/** \brief Fu & Malik procedure for MaxSAT. This procedure is based on unsat core extraction and the at-most-one constraint. Return the number of soft-constraints that can be satisfied. Return -1 if the hard-constraints cannot be satisfied. That is, the formula cannot be satisfied even if all soft-constraints are ignored. For more information on the Fu & Malik procedure: Z. Fu and S. Malik, On solving the partial MAX-SAT problem, in International Conference on Theory and Applications of Satisfiability Testing, 2006. */ int fu_malik_maxsat(Z3_context ctx, Z3_solver s, unsigned num_hard_cnstrs, Z3_ast * hard_cnstrs, unsigned num_soft_cnstrs, Z3_ast * soft_cnstrs) { Z3_ast * aux_vars; Z3_lbool is_sat; unsigned k; assert_hard_constraints(ctx, s, num_hard_cnstrs, hard_cnstrs); printf("checking whether hard constraints are satisfiable...\n"); is_sat = Z3_solver_check(ctx, s); if (is_sat == Z3_L_FALSE) { // It is not possible to make the formula satisfiable even when ignoring all soft constraints. return -1; } if (num_soft_cnstrs == 0) return 0; // nothing to be done... /* Fu&Malik algorithm is based on UNSAT-core extraction. We accomplish that using auxiliary variables (aka answer literals). */ aux_vars = assert_soft_constraints(ctx, s, num_soft_cnstrs, soft_cnstrs); k = 0; for (;;) { printf("iteration %d\n", k); if (fu_malik_maxsat_step(ctx, s, num_soft_cnstrs, soft_cnstrs, aux_vars)) { return num_soft_cnstrs - k; } k++; } }
bool Z3SolverImpl::internalRunSolver( const Query &query, const std::vector<const Array *> *objects, std::vector<std::vector<unsigned char> > *values, bool &hasSolution) { TimerStatIncrementer t(stats::queryTime); // TODO: Does making a new solver for each query have a performance // impact vs making one global solver and using push and pop? // TODO: is the "simple_solver" the right solver to use for // best performance? Z3_solver theSolver = Z3_mk_simple_solver(builder->ctx); Z3_solver_inc_ref(builder->ctx, theSolver); Z3_solver_set_params(builder->ctx, theSolver, solverParameters); runStatusCode = SOLVER_RUN_STATUS_FAILURE; for (ConstraintManager::const_iterator it = query.constraints.begin(), ie = query.constraints.end(); it != ie; ++it) { Z3_solver_assert(builder->ctx, theSolver, builder->construct(*it)); } ++stats::queries; if (objects) ++stats::queryCounterexamples; Z3ASTHandle z3QueryExpr = Z3ASTHandle(builder->construct(query.expr), builder->ctx); // KLEE Queries are validity queries i.e. // ∀ X Constraints(X) → query(X) // but Z3 works in terms of satisfiability so instead we ask the // negation of the equivalent i.e. // ∃ X Constraints(X) ∧ ¬ query(X) Z3_solver_assert( builder->ctx, theSolver, Z3ASTHandle(Z3_mk_not(builder->ctx, z3QueryExpr), builder->ctx)); ::Z3_lbool satisfiable = Z3_solver_check(builder->ctx, theSolver); runStatusCode = handleSolverResponse(theSolver, satisfiable, objects, values, hasSolution); Z3_solver_dec_ref(builder->ctx, theSolver); // Clear the builder's cache to prevent memory usage exploding. // By using ``autoClearConstructCache=false`` and clearning now // we allow Z3_ast expressions to be shared from an entire // ``Query`` rather than only sharing within a single call to // ``builder->construct()``. builder->clearConstructCache(); if (runStatusCode == SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE || runStatusCode == SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE) { if (hasSolution) { ++stats::queriesInvalid; } else { ++stats::queriesValid; } return true; // success } return false; // failed }
/** \brief Naive maxsat procedure based on linear search and at-most-k constraint. Return the number of soft-constraints that can be satisfied. Return -1 if the hard-constraints cannot be satisfied. That is, the formula cannot be satisfied even if all soft-constraints are ignored. Exercise: use binary search to implement MaxSAT. Hint: you will need to use an answer literal to retract the at-most-k constraint. */ int naive_maxsat(Z3_context ctx, Z3_solver s, unsigned num_hard_cnstrs, Z3_ast * hard_cnstrs, unsigned num_soft_cnstrs, Z3_ast * soft_cnstrs) { Z3_ast * aux_vars; Z3_lbool is_sat; unsigned r, k; assert_hard_constraints(ctx, s, num_hard_cnstrs, hard_cnstrs); printf("checking whether hard constraints are satisfiable...\n"); is_sat = Z3_solver_check(ctx, s); if (is_sat == Z3_L_FALSE) { // It is not possible to make the formula satisfiable even when ignoring all soft constraints. return -1; } if (num_soft_cnstrs == 0) return 0; // nothing to be done... aux_vars = assert_soft_constraints(ctx, s, num_soft_cnstrs, soft_cnstrs); // Perform linear search. r = 0; k = num_soft_cnstrs - 1; for (;;) { Z3_model m; unsigned num_disabled; // at most k soft-constraints can be ignored. printf("checking whether at-most %d soft-constraints can be ignored.\n", k); assert_at_most_k(ctx, s, num_soft_cnstrs, aux_vars, k); is_sat = Z3_solver_check(ctx, s); if (is_sat == Z3_L_FALSE) { printf("unsat\n"); return num_soft_cnstrs - k - 1; } m = Z3_solver_get_model(ctx, s); Z3_model_inc_ref(ctx, m); num_disabled = get_num_disabled_soft_constraints(ctx, m, num_soft_cnstrs, aux_vars); Z3_model_dec_ref(ctx, m); if (num_disabled > k) { error("BUG"); } printf("sat\n"); k = num_disabled; if (k == 0) { // it was possible to satisfy all soft-constraints. return num_soft_cnstrs; } k--; } }
int main(){ Z3_context context; Z3_solver solver; Z3_sort bvsort1; Z3_sort bvsort4; Z3_sort memsort; Z3_ast x_ast,y_ast,z_ast,u_ast,v_ast,w_ast,test_ast; Z3_model model; Z3_config config = Z3_mk_config(); Z3_set_param_value(config,"model","true"); context = Z3_mk_context_rc(config); Z3_set_error_handler(context,error_handler); solver = Z3_mk_solver(context); Z3_solver_inc_ref(context,solver); bvsort1 = Z3_mk_bv_sort(context,8); bvsort4 = Z3_mk_bv_sort(context,32); memsort = Z3_mk_array_sort(context,bvsort4,bvsort1); y_ast = Z3_mk_const(context,Z3_mk_string_symbol(context,"mem"),memsort); Z3_inc_ref(context,y_ast); u_ast = Z3_mk_unsigned_int64(context,13,bvsort4); Z3_inc_ref(context,u_ast); v_ast = Z3_mk_select(context,y_ast,u_ast); Z3_inc_ref(context,v_ast); z_ast = Z3_mk_unsigned_int64(context,7,bvsort1); Z3_inc_ref(context,z_ast); test_ast = Z3_mk_eq(context,v_ast,z_ast); Z3_inc_ref(context,test_ast); Z3_solver_assert(context,solver,test_ast); w_ast = Z3_mk_const(context,Z3_mk_string_symbol(context,"w"),bvsort1); y_ast = Z3_mk_store(context,y_ast,u_ast,w_ast); Z3_inc_ref(context,y_ast); v_ast = Z3_mk_select(context,y_ast,u_ast); Z3_inc_ref(context,v_ast); z_ast = Z3_mk_unsigned_int64(context,2,bvsort1); Z3_inc_ref(context,z_ast); test_ast = Z3_mk_eq(context,v_ast,z_ast); Z3_inc_ref(context,test_ast); Z3_solver_assert(context,solver,test_ast); Z3_solver_check(context,solver); model = Z3_solver_get_model(context,solver); fprintf(stderr,"%s\n",Z3_model_to_string(context,model)); fprintf(stderr,"%s\n",Z3_simplify_get_help(context)); return 0; }
/** \brief Small test for the at-most-one constraint. */ void tst_at_most_one() { Z3_context ctx = mk_context(); Z3_solver s = mk_solver(ctx); Z3_ast k1 = mk_bool_var(ctx, "k1"); Z3_ast k2 = mk_bool_var(ctx, "k2"); Z3_ast k3 = mk_bool_var(ctx, "k3"); Z3_ast k4 = mk_bool_var(ctx, "k4"); Z3_ast k5 = mk_bool_var(ctx, "k5"); Z3_ast k6 = mk_bool_var(ctx, "k6"); Z3_ast args1[5] = { k1, k2, k3, k4, k5 }; Z3_ast args2[3] = { k4, k5, k6 }; Z3_model m = 0; Z3_lbool result; printf("testing at-most-one constraint\n"); assert_at_most_one(ctx, s, 5, args1); assert_at_most_one(ctx, s, 3, args2); printf("it must be sat...\n"); result = Z3_solver_check(ctx, s); if (result != Z3_L_TRUE) error("BUG"); m = Z3_solver_get_model(ctx, s); Z3_model_inc_ref(ctx, m); printf("model:\n%s\n", Z3_model_to_string(ctx, m)); Z3_model_dec_ref(ctx, m); Z3_solver_assert(ctx, s, mk_binary_or(ctx, k2, k3)); Z3_solver_assert(ctx, s, mk_binary_or(ctx, k1, k6)); printf("it must be sat...\n"); result = Z3_solver_check(ctx, s); if (result != Z3_L_TRUE) error("BUG"); m = Z3_solver_get_model(ctx, s); Z3_model_inc_ref(ctx, m); printf("model:\n%s\n", Z3_model_to_string(ctx, m)); Z3_solver_assert(ctx, s, mk_binary_or(ctx, k4, k5)); printf("it must be unsat...\n"); result = Z3_solver_check(ctx, s); if (result != Z3_L_FALSE) error("BUG"); Z3_model_dec_ref(ctx, m); Z3_solver_dec_ref(ctx, s); Z3_del_context(ctx); }
Z3_lbool z3_find_one_discr_function(const clone *clone1_basis, const clone *clone1, const clone *clone2, uint32_t fun_arity, fun *fun) { z3_wrapper z3; z3_wrapper_init(&z3); gen_assert_discr_fun_two_clones(&z3, clone1_basis, clone1, clone2, fun_arity); Z3_lbool rc = Z3_solver_check(z3.ctx, z3.solver); if(rc == Z3_L_TRUE) { get_function(&z3, z3.fun, fun_arity, fun); } z3_wrapper_free(&z3); return rc; }
bool Z3SolverImpl::internalRunSolver( const Query &query, const std::vector<const Array *> *objects, std::vector<std::vector<unsigned char> > *values, bool &hasSolution) { TimerStatIncrementer t(stats::queryTime); // NOTE: Z3 will switch to using a slower solver internally if push/pop are // used so for now it is likely that creating a new solver each time is the // right way to go until Z3 changes its behaviour. // // TODO: Investigate using a custom tactic as described in // https://github.com/klee/klee/issues/653 Z3_solver theSolver = Z3_mk_solver(builder->ctx); Z3_solver_inc_ref(builder->ctx, theSolver); Z3_solver_set_params(builder->ctx, theSolver, solverParameters); runStatusCode = SOLVER_RUN_STATUS_FAILURE; for (ConstraintManager::const_iterator it = query.constraints.begin(), ie = query.constraints.end(); it != ie; ++it) { Z3_solver_assert(builder->ctx, theSolver, builder->construct(*it)); } ++stats::queries; if (objects) ++stats::queryCounterexamples; Z3ASTHandle z3QueryExpr = Z3ASTHandle(builder->construct(query.expr), builder->ctx); // KLEE Queries are validity queries i.e. // ∀ X Constraints(X) → query(X) // but Z3 works in terms of satisfiability so instead we ask the // negation of the equivalent i.e. // ∃ X Constraints(X) ∧ ¬ query(X) Z3_solver_assert( builder->ctx, theSolver, Z3ASTHandle(Z3_mk_not(builder->ctx, z3QueryExpr), builder->ctx)); if (dumpedQueriesFile) { *dumpedQueriesFile << "; start Z3 query\n"; *dumpedQueriesFile << Z3_solver_to_string(builder->ctx, theSolver); *dumpedQueriesFile << "(check-sat)\n"; *dumpedQueriesFile << "(reset)\n"; *dumpedQueriesFile << "; end Z3 query\n\n"; dumpedQueriesFile->flush(); } ::Z3_lbool satisfiable = Z3_solver_check(builder->ctx, theSolver); runStatusCode = handleSolverResponse(theSolver, satisfiable, objects, values, hasSolution); Z3_solver_dec_ref(builder->ctx, theSolver); // Clear the builder's cache to prevent memory usage exploding. // By using ``autoClearConstructCache=false`` and clearning now // we allow Z3_ast expressions to be shared from an entire // ``Query`` rather than only sharing within a single call to // ``builder->construct()``. builder->clearConstructCache(); if (runStatusCode == SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE || runStatusCode == SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE) { if (hasSolution) { ++stats::queriesInvalid; } else { ++stats::queriesValid; } return true; // success } return false; // failed }