/** \brief Implement one step of the Fu&Malik algorithm. See fu_malik_maxsat function for more details. Input: soft constraints + aux-vars (aka answer literals) Output: done/not-done when not done return updated set of soft-constraints and aux-vars. - if SAT --> terminates - if UNSAT * compute unsat core * add blocking variable to soft-constraints in the core - replace soft-constraint with the one with the blocking variable - we should also add an aux-var - replace aux-var with a new one * add at-most-one constraint with blocking */ int fu_malik_maxsat_step(Z3_context ctx, Z3_solver s, unsigned num_soft_cnstrs, Z3_ast * soft_cnstrs, Z3_ast * aux_vars) { // create assumptions Z3_ast * assumptions = (Z3_ast*) malloc(sizeof(Z3_ast) * num_soft_cnstrs); Z3_lbool is_sat; Z3_ast_vector core; unsigned core_size; unsigned i = 0; unsigned k = 0; Z3_ast * block_vars; for (i = 0; i < num_soft_cnstrs; i++) { // Recall that we asserted (soft_cnstrs[i] \/ aux_vars[i]) // So using (NOT aux_vars[i]) as an assumption we are actually forcing the soft_cnstrs[i] to be considered. assumptions[i] = Z3_mk_not(ctx, aux_vars[i]); } is_sat = Z3_solver_check_assumptions(ctx, s, num_soft_cnstrs, assumptions); if (is_sat != Z3_L_FALSE) { return 1; // done } else { core = Z3_solver_get_unsat_core(ctx, s); Z3_ast_vector_inc_ref(ctx, core); core_size = Z3_ast_vector_size(ctx, core); block_vars = (Z3_ast*) malloc(sizeof(Z3_ast) * core_size); k = 0; // update soft-constraints and aux_vars for (i = 0; i < num_soft_cnstrs; i++) { unsigned j; // check whether assumption[i] is in the core or not for (j = 0; j < core_size; j++) { if (assumptions[i] == Z3_ast_vector_get(ctx, core, j)) break; } if (j < core_size) { // assumption[i] is in the unsat core... so soft_cnstrs[i] is in the unsat core Z3_ast block_var = mk_fresh_bool_var(ctx); Z3_ast new_aux_var = mk_fresh_bool_var(ctx); soft_cnstrs[i] = mk_binary_or(ctx, soft_cnstrs[i], block_var); aux_vars[i] = new_aux_var; block_vars[k] = block_var; k++; // Add new constraint containing the block variable. // Note that we are using the new auxiliary variable to be able to use it as an assumption. Z3_solver_assert(ctx, s, mk_binary_or(ctx, soft_cnstrs[i], new_aux_var)); } } assert_at_most_one(ctx, s, k, block_vars); Z3_ast_vector_dec_ref(ctx, core); return 0; // not done. } }
bool Z3SolverImpl::validateZ3Model(::Z3_solver &theSolver, ::Z3_model &theModel) { bool success = true; ::Z3_ast_vector constraints = Z3_solver_get_assertions(builder->ctx, theSolver); Z3_ast_vector_inc_ref(builder->ctx, constraints); unsigned size = Z3_ast_vector_size(builder->ctx, constraints); for (unsigned index = 0; index < size; ++index) { Z3ASTHandle constraint = Z3ASTHandle( Z3_ast_vector_get(builder->ctx, constraints, index), builder->ctx); ::Z3_ast rawEvaluatedExpr; bool successfulEval = Z3_model_eval(builder->ctx, theModel, constraint, /*model_completion=*/Z3_TRUE, &rawEvaluatedExpr); assert(successfulEval && "Failed to evaluate model"); // Use handle to do ref-counting. Z3ASTHandle evaluatedExpr(rawEvaluatedExpr, builder->ctx); Z3SortHandle sort = Z3SortHandle(Z3_get_sort(builder->ctx, evaluatedExpr), builder->ctx); assert(Z3_get_sort_kind(builder->ctx, sort) == Z3_BOOL_SORT && "Evaluated expression has wrong sort"); Z3_lbool evaluatedValue = Z3_get_bool_value(builder->ctx, evaluatedExpr); if (evaluatedValue != Z3_L_TRUE) { llvm::errs() << "Validating model failed:\n" << "The expression:\n"; constraint.dump(); llvm::errs() << "evaluated to \n"; evaluatedExpr.dump(); llvm::errs() << "But should be true\n"; success = false; } } if (!success) { llvm::errs() << "Solver state:\n" << Z3_solver_to_string(builder->ctx, theSolver) << "\n"; llvm::errs() << "Model:\n" << Z3_model_to_string(builder->ctx, theModel) << "\n"; } Z3_ast_vector_dec_ref(builder->ctx, constraints); return success; }