add sat(1) command
This commit is contained in:
parent
d68417bc01
commit
87df80019e
1 changed files with 303 additions and 0 deletions
303
sys/src/cmd/sat.c
Normal file
303
sys/src/cmd/sat.c
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <sat.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
typedef struct Trie Trie;
|
||||||
|
typedef struct Var Var;
|
||||||
|
Biobuf *bin, *bout;
|
||||||
|
|
||||||
|
struct Trie {
|
||||||
|
u64int hash;
|
||||||
|
Trie *c[2];
|
||||||
|
uchar l;
|
||||||
|
};
|
||||||
|
struct Var {
|
||||||
|
Trie trie;
|
||||||
|
char *name;
|
||||||
|
int n;
|
||||||
|
Var *next;
|
||||||
|
};
|
||||||
|
Trie *root;
|
||||||
|
Var *vlist, **vlistp = &vlist;
|
||||||
|
int varctr;
|
||||||
|
|
||||||
|
static void*
|
||||||
|
emalloc(ulong n)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
v = malloc(n);
|
||||||
|
if(v == nil) sysfatal("malloc: %r");
|
||||||
|
setmalloctag(v, getcallerpc(&n));
|
||||||
|
memset(v, 0, n);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64int
|
||||||
|
hash(char *s)
|
||||||
|
{
|
||||||
|
u64int h;
|
||||||
|
|
||||||
|
h = 0xcbf29ce484222325ULL;
|
||||||
|
for(; *s != 0; s++){
|
||||||
|
h ^= *s;
|
||||||
|
h *= 0x100000001b3ULL;
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ctz(u64int d)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
|
||||||
|
d &= -d;
|
||||||
|
r = 0;
|
||||||
|
if((int)d == 0) r += 32, d >>= 32;
|
||||||
|
r += ((d & 0xffff0000) != 0) << 4;
|
||||||
|
r += ((d & 0xff00ff00) != 0) << 3;
|
||||||
|
r += ((d & 0xf0f0f0f0) != 0) << 2;
|
||||||
|
r += ((d & 0xcccccccc) != 0) << 1;
|
||||||
|
r += ((d & 0xaaaaaaaa) != 0);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Trie *
|
||||||
|
trieget(u64int h)
|
||||||
|
{
|
||||||
|
Trie *t, *s, **tp;
|
||||||
|
u64int d;
|
||||||
|
|
||||||
|
tp = &root;
|
||||||
|
for(;;){
|
||||||
|
t = *tp;
|
||||||
|
if(t == nil){
|
||||||
|
t = emalloc(sizeof(Var));
|
||||||
|
t->hash = h;
|
||||||
|
t->l = 64;
|
||||||
|
*tp = t;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
d = (h ^ t->hash) << 64 - t->l >> 64 - t->l;
|
||||||
|
if(d == 0 || t->l == 0){
|
||||||
|
if(t->l == 64)
|
||||||
|
return t;
|
||||||
|
tp = &t->c[h >> t->l & 1];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
s = emalloc(sizeof(Trie));
|
||||||
|
s->hash = h;
|
||||||
|
s->l = ctz(d);
|
||||||
|
s->c[t->hash >> s->l & 1] = t;
|
||||||
|
*tp = s;
|
||||||
|
tp = &s->c[h >> s->l & 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Var *
|
||||||
|
varget(char *n)
|
||||||
|
{
|
||||||
|
Var *v, **vp;
|
||||||
|
|
||||||
|
v = (Var*) trieget(hash(n));
|
||||||
|
if(v->name == nil){
|
||||||
|
gotv:
|
||||||
|
v->name = strdup(n);
|
||||||
|
v->n = ++varctr;
|
||||||
|
*vlistp = v;
|
||||||
|
vlistp = &v->next;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
if(strcmp(v->name, n) == 0)
|
||||||
|
return v;
|
||||||
|
for(vp = (Var**)&v->trie.c[0]; (v = *vp) != nil; vp = (Var**)&v->trie.c[0])
|
||||||
|
if(strcmp(v->name, n) == 0)
|
||||||
|
return v;
|
||||||
|
v = emalloc(sizeof(Var));
|
||||||
|
*vp = v;
|
||||||
|
goto gotv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
isvarchar(int c)
|
||||||
|
{
|
||||||
|
return isalnum(c) || c == '_' || c == '-' || c >= 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
char lexbuf[512];
|
||||||
|
enum { TEOF = -1, TVAR = -2 };
|
||||||
|
int peektok;
|
||||||
|
|
||||||
|
int
|
||||||
|
lex(void)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if(peektok != 0){
|
||||||
|
c = peektok;
|
||||||
|
peektok = 0;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
do
|
||||||
|
c = Bgetc(bin);
|
||||||
|
while(c >= 0 && isspace(c) && c != '\n');
|
||||||
|
if(c == '#'){
|
||||||
|
do
|
||||||
|
c = Bgetc(bin);
|
||||||
|
while(c >= 0 && c != '\n');
|
||||||
|
if(c < 0) return TEOF;
|
||||||
|
c = Bgetc(bin);
|
||||||
|
}
|
||||||
|
if(c < 0) return TEOF;
|
||||||
|
if(isvarchar(c)){
|
||||||
|
p = lexbuf;
|
||||||
|
*p++ = c;
|
||||||
|
while(c = Bgetc(bin), c >= 0 && isvarchar(c))
|
||||||
|
if(p < lexbuf + sizeof(lexbuf) - 1)
|
||||||
|
*p++ = c;
|
||||||
|
*p = 0;
|
||||||
|
Bungetc(bin);
|
||||||
|
return TVAR;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
superman(int t)
|
||||||
|
{
|
||||||
|
peektok = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
clause(SATSolve *s)
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
int n;
|
||||||
|
int not, min, max;
|
||||||
|
char *p;
|
||||||
|
static int *clbuf, nclbuf;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
not = 1;
|
||||||
|
min = -1;
|
||||||
|
max = -1;
|
||||||
|
for(;;)
|
||||||
|
switch(t = lex()){
|
||||||
|
case '[':
|
||||||
|
t = lex();
|
||||||
|
if(t == TVAR){
|
||||||
|
min = strtol(lexbuf, &p, 10);
|
||||||
|
if(p == lexbuf || *p != 0 || min < 0) goto syntax;
|
||||||
|
t = lex();
|
||||||
|
}else
|
||||||
|
min = 0;
|
||||||
|
if(t == ']'){
|
||||||
|
max = min;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(t != ',') goto syntax;
|
||||||
|
t = lex();
|
||||||
|
if(t == TVAR){
|
||||||
|
max = strtol(lexbuf, &p, 10);
|
||||||
|
if(p == lexbuf || *p != 0 || max < 0) goto syntax;
|
||||||
|
t = lex();
|
||||||
|
}else
|
||||||
|
max = -1;
|
||||||
|
if(t != ']') goto syntax;
|
||||||
|
break;
|
||||||
|
case TVAR:
|
||||||
|
if(n == nclbuf){
|
||||||
|
clbuf = realloc(clbuf, (nclbuf + 32) * sizeof(int));
|
||||||
|
nclbuf += 32;
|
||||||
|
}
|
||||||
|
clbuf[n++] = not * varget(lexbuf)->n;
|
||||||
|
not = 1;
|
||||||
|
break;
|
||||||
|
case '!':
|
||||||
|
not *= -1;
|
||||||
|
break;
|
||||||
|
case TEOF:
|
||||||
|
case '\n':
|
||||||
|
case ';':
|
||||||
|
goto out;
|
||||||
|
default:
|
||||||
|
sysfatal("unexpected token %d", t);
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
if(n != 0)
|
||||||
|
if(min >= 0)
|
||||||
|
satrange1(s, clbuf, n, min, max< 0 ? n : max);
|
||||||
|
else
|
||||||
|
satadd1(s, clbuf, n);
|
||||||
|
return t != TEOF;
|
||||||
|
syntax:
|
||||||
|
sysfatal("syntax error");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int oneflag, multiflag;
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: %s [-1m] [file]\n", argv0);
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
SATSolve *s;
|
||||||
|
Var *v;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case '1': oneflag++; break;
|
||||||
|
case 'm': multiflag++; break;
|
||||||
|
default: usage();
|
||||||
|
} ARGEND;
|
||||||
|
|
||||||
|
switch(argc){
|
||||||
|
case 0:
|
||||||
|
bin = Bfdopen(0, OREAD);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
bin = Bopen(argv[0], OREAD);
|
||||||
|
break;
|
||||||
|
default: usage();
|
||||||
|
}
|
||||||
|
if(bin == nil) sysfatal("Bopen: %r");
|
||||||
|
s = satnew();
|
||||||
|
if(s == nil) sysfatal("satnew: %r");
|
||||||
|
while(clause(s))
|
||||||
|
;
|
||||||
|
if(multiflag){
|
||||||
|
bout = Bfdopen(1, OWRITE);
|
||||||
|
while(satmore(s) > 0){
|
||||||
|
for(v = vlist; v != nil; v = v->next)
|
||||||
|
if(satval(s, v->n) > 0)
|
||||||
|
Bprint(bout, "%s ", v->name);
|
||||||
|
Bprint(bout, "\n");
|
||||||
|
Bflush(bout);
|
||||||
|
}
|
||||||
|
}else if(oneflag){
|
||||||
|
if(satsolve(s) == 0)
|
||||||
|
exits("unsat");
|
||||||
|
bout = Bfdopen(1, OWRITE);
|
||||||
|
for(v = vlist; v != nil; v = v->next)
|
||||||
|
if(satval(s, v->n) > 0)
|
||||||
|
Bprint(bout, "%s ", v->name);
|
||||||
|
Bprint(bout, "\n");
|
||||||
|
Bflush(bout);
|
||||||
|
}else{
|
||||||
|
if(satsolve(s) == 0)
|
||||||
|
exits("unsat");
|
||||||
|
bout = Bfdopen(1, OWRITE);
|
||||||
|
for(v = vlist; v != nil; v = v->next)
|
||||||
|
Bprint(bout, "%s %d\n", v->name, satval(s, v->n));
|
||||||
|
Bflush(bout);
|
||||||
|
}
|
||||||
|
exits(nil);
|
||||||
|
}
|
Loading…
Reference in a new issue