/** \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); }
/** \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--; } }
Z3Model& Z3Model::operator = (const Z3Model& Other) { if(&Other == this) { return *this; } // Do the destructor if(Model != nullptr && Ctx != nullptr) { Z3_model_dec_ref(Ctx, Model); } // Assign Ctx = Other.Ctx; Model = Other.Model; if(Model != nullptr && Ctx != nullptr) { Z3_model_inc_ref(Ctx, Model); } return *this; }
void get_function(z3_wrapper *z3, Z3_func_decl fun, uint32_t fun_arity, struct fun *kfun) { Z3_model m = Z3_solver_get_model(z3->ctx, z3->solver); assert(m); /* printf("------\n%s\n------\n", Z3_model_to_string(z3->ctx, m)); */ Z3_model_inc_ref(z3->ctx, m); fun_init(kfun, fun_arity); for(size_t xs = 0; xs < int_pow(K, fun_arity); ++xs) { /* represent `xs` in the K-ary form, * with digits[0] being the highest digit. */ uint32_t digits[fun_arity]; get_K_digits(digits, fun_arity, xs); Z3_ast args[fun_arity]; for(size_t i = 0; i < fun_arity; ++i) { args[i] = z3->Ek_consts[digits[i]]; } /* eval func on given args */ Z3_ast t = Z3_mk_app(z3->ctx, fun, fun_arity, args); Z3_ast res; assert(Z3_model_eval(z3->ctx, m, t, 1, &res) == Z3_TRUE); /* printf("%s == %s\n", Z3_ast_to_string(z3->ctx, t), Z3_ast_to_string(z3->ctx, res)); */ /* interpret the result of function application */ uint64_t y; sscanf(Z3_ast_to_string(z3->ctx, res), "V%lu", &y); fun_set_val(kfun, xs, y); } Z3_model_dec_ref(z3->ctx, m); }
SolverImpl::SolverRunStatus Z3SolverImpl::handleSolverResponse( ::Z3_solver theSolver, ::Z3_lbool satisfiable, const std::vector<const Array *> *objects, std::vector<std::vector<unsigned char> > *values, bool &hasSolution) { switch (satisfiable) { case Z3_L_TRUE: { hasSolution = true; if (!objects) { // No assignment is needed assert(values == NULL); return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE; } assert(values && "values cannot be nullptr"); ::Z3_model theModel = Z3_solver_get_model(builder->ctx, theSolver); assert(theModel && "Failed to retrieve model"); Z3_model_inc_ref(builder->ctx, theModel); values->reserve(objects->size()); for (std::vector<const Array *>::const_iterator it = objects->begin(), ie = objects->end(); it != ie; ++it) { const Array *array = *it; std::vector<unsigned char> data; data.reserve(array->size); for (unsigned offset = 0; offset < array->size; offset++) { // We can't use Z3ASTHandle here so have to do ref counting manually ::Z3_ast arrayElementExpr; Z3ASTHandle initial_read = builder->getInitialRead(array, offset); bool successfulEval = Z3_model_eval(builder->ctx, theModel, initial_read, /*model_completion=*/Z3_TRUE, &arrayElementExpr); assert(successfulEval && "Failed to evaluate model"); Z3_inc_ref(builder->ctx, arrayElementExpr); assert(Z3_get_ast_kind(builder->ctx, arrayElementExpr) == Z3_NUMERAL_AST && "Evaluated expression has wrong sort"); int arrayElementValue = 0; bool successGet = Z3_get_numeral_int(builder->ctx, arrayElementExpr, &arrayElementValue); assert(successGet && "failed to get value back"); assert(arrayElementValue >= 0 && arrayElementValue <= 255 && "Integer from model is out of range"); data.push_back(arrayElementValue); Z3_dec_ref(builder->ctx, arrayElementExpr); } values->push_back(data); } Z3_model_dec_ref(builder->ctx, theModel); return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_SOLVABLE; } case Z3_L_FALSE: hasSolution = false; return SolverImpl::SOLVER_RUN_STATUS_SUCCESS_UNSOLVABLE; case Z3_L_UNDEF: { ::Z3_string reason = ::Z3_solver_get_reason_unknown(builder->ctx, theSolver); if (strcmp(reason, "timeout") == 0 || strcmp(reason, "canceled") == 0) { return SolverImpl::SOLVER_RUN_STATUS_TIMEOUT; } if (strcmp(reason, "unknown") == 0) { return SolverImpl::SOLVER_RUN_STATUS_FAILURE; } llvm::errs() << "Unexpected solver failure. Reason is \"" << reason << "\"\n"; abort(); } default: llvm_unreachable("unhandled Z3 result"); } }
Z3Model::~Z3Model() { if (Ctx != Z3Ctx::NullPtr && Model != nullptr) { Z3_model_dec_ref(*Ctx, Model); } }
void Z3_API Z3_del_model(Z3_context c, Z3_model m) { Z3_model_dec_ref(c, m); }
Z3Model::~Z3Model() { if(Model != nullptr && Ctx != nullptr) { Z3_model_dec_ref(Ctx, Model); } }