1 /*-------------------------------------------------------------------------*/
2 /* Copyright 2010-2014 Armin Biere Johannes Kepler University Linz Austria */
3 /*-------------------------------------------------------------------------*/
17 static LGL * lgl4sigh;
18 static int catchedsig, verbose, ignmissingheader, ignaddcls;
20 static int * targets, sztargets, ntargets, multiple;
22 static void (*sig_int_handler)(int);
23 static void (*sig_segv_handler)(int);
24 static void (*sig_abrt_handler)(int);
25 static void (*sig_term_handler)(int);
26 static void (*sig_bus_handler)(int);
27 static void (*sig_alrm_handler)(int);
29 static void resetsighandlers (void) {
30 (void) signal (SIGINT, sig_int_handler);
31 (void) signal (SIGSEGV, sig_segv_handler);
32 (void) signal (SIGABRT, sig_abrt_handler);
33 (void) signal (SIGTERM, sig_term_handler);
34 (void) signal (SIGBUS, sig_bus_handler);
37 static void caughtsigmsg (int sig) {
38 if (verbose < 0) return;
39 printf ("c\nc CAUGHT SIGNAL %d", sig);
41 case SIGINT: printf (" SIGINT"); break;
42 case SIGSEGV: printf (" SIGSEGV"); break;
43 case SIGABRT: printf (" SIGABRT"); break;
44 case SIGTERM: printf (" SIGTERM"); break;
45 case SIGBUS: printf (" SIGBUS"); break;
46 case SIGALRM: printf (" SIGALRM"); break;
53 static void catchsig (int sig) {
57 fputs ("c s UNKNOWN\n", stdout);
60 lglflushtimers (lgl4sigh);
66 if (!getenv ("LGLNABORT")) raise (sig); else exit (1);
69 static void setsighandlers (void) {
70 sig_int_handler = signal (SIGINT, catchsig);
71 sig_segv_handler = signal (SIGSEGV, catchsig);
72 sig_abrt_handler = signal (SIGABRT, catchsig);
73 sig_term_handler = signal (SIGTERM, catchsig);
74 sig_bus_handler = signal (SIGBUS, catchsig);
77 static int timelimit = -1, caughtalarm = 0;
79 static void catchalrm (int sig) {
80 assert (sig == SIGALRM);
85 printf ("c time limit of %d reached after %.1f seconds\nc\n",
86 timelimit, lglsec (lgl4sigh));
92 static int checkalarm (void * ptr) {
93 assert (ptr == (void*) &caughtalarm);
97 static int next (FILE * in, int *linenoptr) {
99 if (res == '\n') *linenoptr += 1;
103 static char isoptchartab[256];
104 static int isoptchartabinitialized;
106 static int isoptchar (unsigned char uch) {
108 if (!isoptchartabinitialized) {
109 for (i = 'a'; i <= 'z'; i++) isoptchartab[i] = 1;
110 for (i = 'A'; i <= 'Z'; i++) isoptchartab[i] = 1;
111 for (i = '0'; i <= '9'; i++) isoptchartab[i] = 1;
112 isoptchartab['-'] = isoptchartab['_'] = 1;
113 isoptchartabinitialized = 1;
115 return isoptchartab[uch];
118 typedef struct Opt { char * name; int size, count; } Opt;
120 static void pushoptch (Opt * opt, int ch) {
121 if (opt->count + 1 >= opt->size)
122 opt->name = realloc (opt->name, opt->size = opt->size ? 2*opt->size : 2);
124 opt->name[opt->count++] = ch;
125 opt->name[opt->count] = 0;
128 static const char * parse (LGL * lgl, FILE * in, int * lp) {
129 int ch, prev, m, n, v, c, l, lit, sign, val, embedded = 0, header;
131 memset (&opt, 0, sizeof opt);
134 if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') goto SKIP;
138 if (ch == EOF) return "end of file in comment";
141 if (prev != '-') continue;
142 if (ch != '-') continue;
145 while (isoptchar (ch)) {
147 pushoptch (&opt, ch);
151 if (ch != '=') continue;
153 if (ch == '-') sign = -1, ch = next (in, lp); else sign = 1;
154 if (!isdigit (ch)) continue;
156 while (isdigit (ch = next (in, lp)))
157 val = 10 * val + (ch - '0');
159 if (!lglhasopt (lgl, opt.name)) {
161 "*** lingeling warning: "
162 "parsed invalid embedded option '--%s'\n",
169 if (!embedded++ && verbose >= 0)
170 printf ("c\nc embedded options:\nc\n");
171 if (!strcmp (opt.name, "verbose")) verbose = val;
172 if (verbose >= 0) printf ("c --%s=%d\n", opt.name, val);
173 lglsetopt (lgl, opt.name, val);
179 if (embedded) printf ("c\n"); else printf ("c no embedded options\n");
182 header = m = n = v = l = c = 0;
183 if (ignmissingheader) {
185 if (verbose >= 0) printf ("will not read header");
186 while ((ch = next (in, lp)) != '\n' && ch != EOF)
188 } else if (verbose >= 0) printf ("c skipping missing header\n");
191 if (ch != 'p') return "missing 'p ...' header";
192 if (next (in, lp) != ' ') return "invalid header: expected ' ' after 'p'";
193 while ((ch = next (in, lp)) == ' ')
195 if (ch != 'c') return "invalid header: expected 'c' after ' '";
196 if (next (in, lp) != 'n') return "invalid header: expected 'n' after 'c'";
197 if (next (in, lp) != 'f') return "invalid header: expected 'f' after 'n'";
198 if (next (in, lp) != ' ') return "invalid header: expected ' ' after 'f'";
199 while ((ch = next (in, lp)) == ' ')
201 if (!isdigit (ch)) return "invalid header: expected digit after 'p cnf '";
203 while (isdigit (ch = next (in, lp)))
204 m = 10 * m + (ch - '0');
205 if (ch != ' ') return "invalid header: expected ' ' after 'p cnf <m>'";
206 while ((ch = next (in, lp)) == ' ')
209 return "invalid header: expected digit after 'p cnf <m> '";
211 while (isdigit (ch = next (in, lp)))
212 n = 10 * n + (ch - '0');
215 if (ch != '\n') return "invalid header: expected new line after header";
217 printf ("c found 'p cnf %d %d' header\n", m, n), fflush (stdout);
222 if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r') goto BODY;
224 while ((ch = next (in, lp)) != '\n')
225 if (ch == EOF) return "end of file in comment";
229 if (header && c + 1 == n) return "clause missing";
230 if (header && c < n) return "clauses missing";
233 printf ("c read %d variables, %d clauses, %d literals in %.2f seconds\n",
234 v, c, l, lglsec (lgl));
241 if (ch == '0') return "expected positive digit after '-'";
244 if (!isdigit (ch)) return "expected digit";
245 if (header && c == n) return "too many clauses";
247 while (isdigit (ch = next (in, lp)))
248 lit = 10 * lit + (ch - '0');
249 if (header && lit > m) return "maxium variable index exceeded";
250 if (lit > v) v = lit;
255 if (!lit && ignaddcls && c == n) goto DONE;
259 typedef struct OBuf { char line[81]; int pos; } OBuf;
261 static void flushobuf (OBuf * obuf, int simponly, FILE * file) {
262 assert (0 < obuf->pos);
263 assert (obuf->pos < 81);
264 obuf->line[obuf->pos++] = '\n';
265 assert (obuf->pos < 81);
266 obuf->line[obuf->pos++] = 0;
267 if (simponly) fputs ("c ", file);
269 fputs (obuf->line, file);
273 static void print2obuf (OBuf * obuf, int i, int simponly, FILE * file) {
276 sprintf (str, " %d", i);
279 if (obuf->pos + len > 79) flushobuf (obuf, simponly, file);
280 strcpy (obuf->line + obuf->pos, str);
282 assert (obuf->pos <= 79);
285 static FILE * writefile (const char * name, int * clptr) {
286 int len = strlen (name);
289 if (len >= 3 && !strcmp (name + len - 3, ".gz")) {
290 tmp = malloc (len + 20);
292 sprintf (tmp, "gzip -c > %s", name);
293 res = popen (tmp, "w");
297 res = fopen (name, "w");
300 if (!res) fprintf (stderr, "*** lingeling error: can not write %s\n", name);
304 static void closefile (FILE * file, int type) {
305 if (type == 1) fclose (file);
306 if (type == 2) pclose (file);
309 static void lgltravcounter (void * voidptr, int lit) {
310 int * cntptr = voidptr;
311 if (!lit) *cntptr += 1;
314 static void lglpushtarget (int target) {
315 if (ntargets == sztargets)
316 targets = realloc (targets, sizeof *targets *
317 (sztargets = sztargets ? 2*sztargets : 1));
318 targets[ntargets++] = target;
321 static int lglmonotifiy (void * lgl, int target, int val) {
322 printf ("t %d %d after %.3f seconds\n", target, val, lglsec (lgl));
327 static int primes[] = {
328 200000033, 200000039, 200000051, 200000069, 200000081,
331 static int nprimes = sizeof primes / sizeof *primes;
333 int main (int argc, char ** argv) {
334 int res, i, j, clin, clout, val, len, lineno, simponly, count, target;
335 const char * iname, * oname, * pname, * match, * p, * err, * thanks;
336 int maxvar, lit, nopts, simplevel;
337 FILE * in, * out, * pfile;
343 res = clin = clout = simponly = simplevel = 0;
344 iname = oname = pname = thanks = 0;
345 lgl4sigh = lgl = lglinit ();
347 for (i = 1; i < argc; i++) {
348 if (!strcmp (argv[i], "-h") || !strcmp (argv[i], "--help")) {
349 printf ("usage: lingeling [<option> ...][<file>[.gz]]\n");
351 printf ("where <option> is one of the following:\n");
353 printf ("-q be quiet (same as '--verbose=-1')\n");
354 printf ("-s only simplify and print to output file\n");
355 printf ("-O<L> set simplification level to <L>\n");
356 printf ("-o <output> set output file (default 'stdout')\n");
357 printf ("-p <options> read options from file\n");
359 printf ("-t <seconds> set time limit\n");
361 printf ("-a <assumption> use multiple assumptions\n");
362 printf ("-m <objective> use multiple objectives\n");
364 printf ("-h|--help print command line option summary\n");
365 printf ("-f|--force force reading even without header\n");
366 printf ("-i|--ignore ignore additional clauses\n");
367 printf ("-r|--ranges print value ranges of options\n");
368 printf ("-d|--defaults print default values of options\n");
369 printf ("-P|--pcs print (full) PCS file\n");
370 printf ("--pcs-mixed print mixed PCS file\n");
371 printf ("--pcs-reduced print reduced PCS file\n");
372 printf ("-e|--embedded ditto but in an embedded format print\n");
373 printf ("-n|--no-witness do not print solution (see '--witness')\n");
375 printf ("--thanks=<whom> alternative way of specifying the seed\n");
376 printf (" (inspired by Vampire)\n");
379 "The following options can also be used in the form '--<name>=<int>',\n"
380 "just '--<name>' for increment and '--no-<name>' for zero. They\n"
381 "can be embedded into the CNF file, set through the API or capitalized\n"
382 "with prefix 'LGL' instead of '--' through environment variables.\n"
383 "Their default values are displayed in square brackets.\n");
387 } else if (!strcmp (argv[i], "-s")) simponly = 1;
388 else if (argv[i][0] == '-' && argv[i][1] == 'O') {
390 fprintf (stderr, "*** lingeling error: multiple '-O..' options\n");
394 if ((simplevel = atoi (argv[i] + 2)) <= 0) {
396 "*** lingeling error: invalid '%s' option\n", argv[i]);
400 } else if (!strcmp (argv[i], "-q")) lglsetopt (lgl, "verbose", -1);
401 else if (!strcmp (argv[i], "-o")) {
403 fprintf (stderr, "*** lingeling error: argument to '-o' missing\n");
409 "*** lingeling error: "
410 "multiple output files '%s' and '%s'\n",
416 } else if (!strcmp (argv[i], "-p")) {
418 fprintf (stderr, "*** lingeling error: argument to '-p' missing\n");
424 "*** lingeling error: "
425 "multiple option files '%s' and '%s'\n",
431 } else if (!strcmp (argv[i], "-t")) {
433 fprintf (stderr, "*** lingeling error: argument to '-t' missing\n");
437 if (timelimit >= 0) {
438 fprintf (stderr, "*** lingeling error: timit limit set twice\n");
442 for (p = argv[i]; *p && isdigit (*p); p++)
444 if (p == argv[i] || *p || (timelimit = atoi (argv[i])) < 0) {
446 "*** lingeling error: invalid time limit '-t %s'\n", argv[i]);
450 } else if (!strcmp (argv[i], "-a")) {
452 fprintf (stderr, "*** lingeling error: argument to '-a' missing\n");
457 assert (ntargets > 0);
458 fprintf (stderr, "*** lingeling error: unexpectd '-a' after '-m'\n");
462 target = atoi (argv[i]);
465 "*** lingeling error: invalid literal in '-a %d'\n", target);
469 lglpushtarget (target);
470 } else if (!strcmp (argv[i], "-m")) {
472 fprintf (stderr, "*** lingeling error: argument to '-m' missing\n");
476 if (!multiple && ntargets > 0) {
477 fprintf (stderr, "*** lingeling error: unexpectd '-m' after '-a'\n");
481 target = atoi (argv[i]);
484 "*** lingeling error: invalid literal in '-m %d'\n", target);
488 lglpushtarget (target);
490 } else if (!strcmp (argv[i], "-d") || !strcmp (argv[i], "--defaults")) {
491 lglopts (lgl, "", 0);
493 } else if (!strcmp (argv[i], "-e") || !strcmp (argv[i], "--embedded")) {
494 lglopts (lgl, "c ", 1);
496 } else if (!strcmp (argv[i], "-r") || !strcmp (argv[i], "--ranges")) {
499 } else if (!strcmp (argv[i], "-P") || !strcmp (argv[i], "--pcs")) {
500 printf ("# generated by 'lingeling --pcs'\n");
501 printf ("# version %s\n", lglversion ());
504 } else if (!strcmp (argv[i], "--pcs-mixed")) {
505 printf ("# generated by 'lingeling --pcs-mixed'\n");
506 printf ("# version %s\n", lglversion ());
509 } else if (!strcmp (argv[i], "--pcs-reduced")) {
510 printf ("# generated by 'lingeling --pcs-reduced'\n");
511 printf ("# version %s\n", lglversion ());
514 } else if (!strcmp (argv[i], "-f") || !strcmp (argv[i], "--force")) {
515 ignmissingheader = 1;
516 } else if (!strcmp (argv[i], "-i") || !strcmp (argv[i], "--ignore")) {
518 } else if (!strcmp (argv[i], "-n") || !strcmp (argv[i], "no-witness")) {
519 lglsetopt (lgl, "witness", 0);
520 } else if (argv[i][0] == '-') {
521 if (argv[i][1] == '-') {
522 match = strchr (argv[i] + 2, '=');
525 if (*p == '-') p++; // TODO for what is this useful again?
527 if (!strncmp (argv[i], "--write-api-trace=", len)) {
528 // TODO not handled yet ...
530 } else if (!strncmp (argv[i], "--thanks=", len)) {
533 } else if (!isdigit (*p)) {
536 "*** lingeling error: invalid command line option '%s'\n",
541 while (*++p) if (!isdigit (*p)) goto ERR;
542 len = match - argv[i] - 2;
543 tmp = malloc (len + 1);
545 for (p = argv[i] + 2; *p != '='; p++) tmp[j++] = *p;
547 val = atoi (match + 1);
548 } else if (!strncmp (argv[i], "--no-", 5)) {
549 tmp = strdup (argv[i] + 5);
552 tmp = strdup (argv[i] + 2);
553 val = lglgetopt (lgl, tmp) + 1;
555 if (!lglhasopt (lgl, tmp)) { free (tmp); goto ERR; }
556 lglsetopt (lgl, tmp, val);
559 if (argv[i][2]) goto ERR;
560 if (!lglhasopt (lgl, argv[i] + 1)) goto ERR;
561 val = lglgetopt (lgl, argv[i] + 1) + 1;
562 lglsetopt (lgl, argv[i] + 1, val);
565 fprintf (stderr, "*** lingeling error: can not read '%s' and '%s'\n",
569 } else iname = argv[i];
571 verbose = lglgetopt (lgl, "verbose");
573 lglbnr ("Lingeling SAT Solver", "c ", stdout);
574 if (simponly) printf ("c simplifying only\n");
575 if (oname) printf ("c output file %s\n", oname);
576 if (simponly || oname) fflush (stdout);
577 lglsetopt (lgl, "trep", 1);
580 unsigned seed = 0, i = 0, ch;
582 for (p = thanks; (ch = *p); p++) {
583 seed += primes[i++] * ch;
584 if (i == nprimes) i = 0;
586 if (seed >= (unsigned) INT_MAX) seed >>= 1;
587 assert (seed <= (unsigned) INT_MAX);
591 printf ("c will have to thank %s (--seed=%d)\nc\n",
593 lglsetopt (lgl, "seed", iseed);
596 printf ("c\nc options after command line parsing:\nc\n");
597 lglopts (lgl, "c ", 0);
603 len = strlen (iname);
604 if (len >= 3 && !strcmp (iname + len - 3, ".gz")) {
605 if (verbose >= 1) printf ("c piping '%s' through 'gunzip'\n", iname);
606 tmp = malloc (len + 20);
607 sprintf (tmp, "gunzip -c %s", iname);
608 in = popen (tmp, "r");
611 } else if (len >= 5 && !strcmp (iname + len - 5, ".lzma")) {
612 if (verbose >= 1) printf ("c piping '%s' through 'lzcat'\n", iname);
613 tmp = malloc (len + 20);
614 sprintf (tmp, "lzcat %s", iname);
615 in = popen (tmp, "r");
618 } else if (len >= 4 && !strcmp (iname + len - 4, ".bz2")) {
619 if (verbose >= 1) printf ("c piping '%s' through 'bzcat'\n", iname);
620 tmp = malloc (len + 20);
621 sprintf (tmp, "bzcat %s", iname);
622 in = popen (tmp, "r");
625 } else if (len >= 3 && !strcmp (iname + len - 3, ".7z")) {
626 if (verbose >= 1) printf ("c piping '%s' through '7z'\n", iname);
627 tmp = malloc (len + 40);
628 sprintf (tmp, "7z x -so %s 2>/dev/null", iname);
629 in = popen (tmp, "r");
633 in = fopen (iname, "r");
638 "*** lingeling error: can not read input file %s\n", iname);
642 } else iname = "<stdin>", in = stdin;
644 pfile = fopen (pname, "r");
647 "*** lingeling error: can not read option file %s\n", pname);
652 printf ("c reading options file %s\n", pname);
655 nopts = lglreadopts (lgl, pfile);
657 printf ("c read and set %d options\nc\n", nopts), fflush (stdout);
660 if (verbose >= 0) printf ("c reading input file %s\n", iname);
662 if ((err = parse (lgl, in, &lineno))) {
663 fprintf (stderr, "%s:%d: %s\n", iname, lineno, err);
667 closefile (in, clin);
671 if (verbose >= 2) printf ("c final options:\nc\n");
672 lglopts (lgl, "c ", 0);
674 if (timelimit >= 0) {
676 printf ("c\nc setting time limit of %d seconds\n", timelimit);
679 lglseterm (lgl, checkalarm, &caughtalarm);
680 sig_alrm_handler = signal (SIGALRM, catchalrm);
683 if (multiple) lglpushtarget (0), ntargets--;
684 else for (i = 0; i < ntargets; i++) lglassume (lgl, targets[i]);
685 if (multiple) res = lglmosat (lgl, lgl, lglmonotifiy, targets);
689 printf ("c simplifying with simplification level %d\n", simplevel);
692 res = lglsimp (lgl, simplevel);
694 printf ("c simplifying result %d after %.2f seconds\n",
701 if (timelimit >= 0) {
703 (void) signal (SIGALRM, sig_alrm_handler);
706 double start = lglsec (lgl), delta;
707 if (!strcmp (oname, "-")) out = stdout, oname = "<stdout>", clout = 0;
708 else if (!(out = writefile (oname, &clout))) { res = 1; goto DONE; }
711 lglctrav (lgl, &count, lgltravcounter);
712 printf ("c\nc writing 'p cnf %d %d' to '%s'\n",
713 lglmaxvar (lgl), count, oname);
717 closefile (out, clout);
719 delta = lglsec (lgl) - start; if (delta < 0) delta = 0;
720 printf ("c collected garbage and wrote '%s' in %.1f seconds\n",
722 printf ("c\n"), fflush (stdout);
725 if (!simponly || verbose >= 0) {
726 if (simponly) fputs ("c ", stdout);
727 if (res == 10) fputs ("s SATISFIABLE\n", stdout);
728 else if (res == 20) fputs ("s UNSATISFIABLE\n", stdout);
729 else fputs ("c s UNKNOWN\n", stdout);
730 if (thanks) printf ("c\nc Thanks to %s!\nc\n", thanks);
732 if (res == 10 && lglgetopt (lgl, "witness")) {
734 maxvar = lglmaxvar (lgl);
735 for (i = 1; i <= maxvar; i++) {
736 lit = (lglderef (lgl, i) > 0) ? i : -i;
737 print2obuf (&obuf, lit, simponly, stdout);
739 print2obuf (&obuf, 0, simponly, stdout);
740 if (obuf.pos > 0) flushobuf (&obuf, simponly, stdout);
744 if (verbose >= 0) fputs ("c\n", stdout), lglstats (lgl);
746 closefile (in, clin);