\myheading{A poor man’s MaxSMT} First, what is incremental SAT? When a SAT-solver is \textit{warmed up}, and you want only to alter list of clauses slightly by adding one, why to reset it? In my toy SMT solver, I use incremental SAT for model counting, or getting all models: see the \href{\MKURL}{picosat\_get\_all\_models()} function. Also, many SAT solvers supports \textit{assumptions}. That is you supply a list of clauses + \textit{temporary} clauses that will be dropped each time. Now a digression: this is my own binary search implementation: \lstinputlisting[style=customc]{\CURPATH/MaxSMT/binsearch.c} You wouldn't use it, but I wrote it because it's fits so nicely on SAT. To solve an optimization problem, you want to find some \textit{optimum} variable, that is minimized or maximized. Like in my implementation of binary search, I can try bit by bit, but these are added as assumptions. \begin{lstlisting}[style=customc] // poor man's MaxSMT // if we minimize, first try false, then true // if we maximize, do contrariwise bool run_poor_mans_MaxSMT(struct ctx* ctx) { if (verbose>0) printf ("%s() begin\n", __FUNCTION__); assert (ctx->maxsat==true); struct PicoSAT *p=picosat_init (); add_clauses_to_picosat(ctx, p); if (ctx->write_CNF_file) { write_CNF(ctx, "tmp.cnf"); printf ("CNF file written to tmp.cnf\n"); }; int array[ctx->min_max_var->width]; int res; // do this starting at the MSB moving towards the LSB: for (int idx=ctx->min_max_var->width-1; idx>=0; idx--) { // try the first false/true array[idx]=ctx->min_or_max==false ? 0 : 1; if (verbose>0) printf ("idx=%d trying %s\n", idx, ctx->min_or_max==false ? "false" : "true"); picosat_assume (p, (ctx->min_or_max==false ? -1 : 1) * (ctx->min_max_var->SAT_var+idx)); res=picosat_sat (p,-1); if (res==10) { if (verbose>0) printf ("got SAT\n"); if (idx!=0) { // add a newly discovered correct bit as a clause // but do this only if this is not the last bit // if the bit is the last/lowest (idx==0), we want to prevent PicoSAT to be switched out of SAT state // (PicoSAT do this after picosat_add() call) // because we are fetching result sooner afterwards picosat_add (p, (ctx->min_or_max==false ? -1 : 1) * (ctx->min_max_var->SAT_var+idx)); picosat_add (p, 0); } // proceed to the next bit: continue; }; if (verbose>0) printf ("got UNSAT\n"); assert (res==20); // must be in UNSAT state // try the second false/true array[idx]=ctx->min_or_max==false ? 1 : 0; if (verbose>0) printf ("idx=%d trying %s\n", idx, ctx->min_or_max==false ? "true" : "false"); picosat_assume (p, (ctx->min_or_max==false ? 1 : -1) * (ctx->min_max_var->SAT_var+idx)); res=picosat_sat (p,-1); if (res==10) { if (verbose>0) printf ("got SAT\n"); if (idx!=0) { picosat_add (p, (ctx->min_or_max==false ? 1 : -1) * (ctx->min_max_var->SAT_var+idx)); picosat_add (p, 0); }; } else if (res==20) { if (verbose>0) { printf ("got UNSAT\n"); printf ("%s() begin -> false\n", __FUNCTION__); }; // UNSAT for both false and true for this bit at idx, return UNSAT for this instance: return false; } else { assert(0); }; }; // must have a solution at this point fill_variables_from_picosat(ctx, p); // construct a value from array[]: ctx->min_max_var->val=SAT_solution_to_value(array, ctx->min_max_var->width); if (verbose>0) printf ("%s() begin -> true, val=%llu\n", __FUNCTION__, ctx->min_max_var->val); return true; }; \end{lstlisting} ( \url{\MKURL} ) For the popsicle problem (\ref{popsicles}): \begin{lstlisting} idx=15 trying true got UNSAT idx=15 trying false got SAT idx=14 trying true got UNSAT idx=14 trying false got SAT idx=13 trying true got UNSAT idx=13 trying false got SAT idx=12 trying true got UNSAT idx=12 trying false got SAT idx=11 trying true got UNSAT idx=11 trying false got SAT idx=10 trying true got UNSAT idx=10 trying false got SAT idx=9 trying true got UNSAT idx=9 trying false got SAT idx=8 trying true got UNSAT idx=8 trying false got SAT idx=7 trying true got UNSAT idx=7 trying false got SAT idx=6 trying true got UNSAT idx=6 trying false got SAT idx=5 trying true got UNSAT idx=5 trying false got SAT idx=4 trying true got UNSAT idx=4 trying false got SAT idx=3 trying true got SAT idx=2 trying true got SAT idx=1 trying true got UNSAT idx=1 trying false got SAT idx=0 trying true got SAT ... run_poor_mans_MaxSMT() begin -> true, val=13 \end{lstlisting} It works slower than if using Open-WBO, but sometimes even faster than Z3! This is as well: \ref{beer_can}. And this is close to LEXSAT, see exercise and solution from the \ac{TAOCP}, section 7.2.2.2: \begin{figure}[H] \centering \frame{\includegraphics[scale=0.6]{\CURPATH/MaxSMT/exercise.png}} \caption{The exercise} \end{figure} % FIXME: unfull frame... \begin{figure}[H] \centering \frame{\includegraphics[scale=0.6]{\CURPATH/MaxSMT/solution.png}} \caption{The solution} \end{figure}