Пример #1
0
/**
  \brief Finds the maximal number of assumptions that can be satisfied.
  An assumption is any formula preceded with the :assumption keyword.
  "Hard" constraints can be supported by using the :formula keyword.
  
  Input: file in SMT-LIB format, and MaxSAT algorithm to be used: 0 - Naive, 1 - Fu&Malik's algo.
  Output: the maximum number of assumptions that can be satisfied.
*/
int smtlib_maxsat(char * file_name, int approach) 
{
    Z3_context ctx;
    Z3_solver s;
    unsigned i;
    Z3_optimize opt;
    unsigned num_hard_cnstrs, num_soft_cnstrs;
    Z3_ast * hard_cnstrs, * soft_cnstrs;
    Z3_ast_vector  hard, objs;
    Z3_app soft;
    unsigned result = 0;
    ctx = mk_context();
    s = mk_solver(ctx);
    opt = Z3_mk_optimize(ctx);
    Z3_optimize_inc_ref(ctx, opt);
    Z3_optimize_from_file(ctx, opt, file_name);
    hard = Z3_optimize_get_assertions(ctx, opt);
    Z3_ast_vector_inc_ref(ctx, hard);
    num_hard_cnstrs = Z3_ast_vector_size(ctx, hard);
    hard_cnstrs = (Z3_ast *) malloc(sizeof(Z3_ast) * (num_hard_cnstrs));
    for (i = 0; i < num_hard_cnstrs; i++) {
        hard_cnstrs[i] = Z3_ast_vector_get(ctx, hard, i);
    }
    objs = Z3_optimize_get_objectives(ctx, opt);
    Z3_ast_vector_inc_ref(ctx, objs);

    // soft constraints are stored in a single objective which is a sum 
    // of if-then-else expressions.
    soft = Z3_to_app(ctx, Z3_ast_vector_get(ctx, objs, 0));
    num_soft_cnstrs = Z3_get_app_num_args(ctx, soft);
    soft_cnstrs = (Z3_ast *) malloc(sizeof(Z3_ast) * (num_soft_cnstrs));
    for (i = 0; i < num_soft_cnstrs; ++i) {
        soft_cnstrs[i] = Z3_get_app_arg(ctx, Z3_to_app(ctx, Z3_get_app_arg(ctx, soft, i)), 0);
    }
    
    switch (approach) {
    case NAIVE_MAXSAT: 
        result = naive_maxsat(ctx, s, num_hard_cnstrs, hard_cnstrs, num_soft_cnstrs, soft_cnstrs);
        break;
    case FU_MALIK_MAXSAT:
        result = fu_malik_maxsat(ctx, s, num_hard_cnstrs, hard_cnstrs, num_soft_cnstrs, soft_cnstrs);
        break;
    default:
        /* Exercise: implement your own MaxSAT algorithm.*/
        error("Not implemented yet.");
        break;
    }
    free_cnstr_array(hard_cnstrs);
    free_cnstr_array(soft_cnstrs);
    Z3_solver_dec_ref(ctx, s);
    Z3_optimize_dec_ref(ctx, opt);
    return result;
}
Пример #2
0
/**
  \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.
    }
}
Пример #3
0
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;
}
Пример #4
0
 void Z3_API Z3_solver_get_levels(Z3_context c, Z3_solver s, Z3_ast_vector literals, unsigned sz, unsigned levels[]) {
     Z3_TRY;
     LOG_Z3_solver_get_levels(c, s, literals, sz, levels);
     RESET_ERROR_CODE();
     init_solver(c, s);
     if (sz != Z3_ast_vector_size(c, literals)) {
         SET_ERROR_CODE(Z3_IOB, nullptr);
         return;
     }
     ptr_vector<expr> _vars;
     for (unsigned i = 0; i < sz; ++i) {
         expr* e = to_expr(Z3_ast_vector_get(c, literals, i));
         mk_c(c)->m().is_not(e, e);
         _vars.push_back(e);
     }
     unsigned_vector _levels(sz);
     to_solver_ref(s)->get_levels(_vars, _levels);
     for (unsigned i = 0; i < sz; ++i) {
         levels[i] = _levels[i];
     }
     Z3_CATCH;
 }