/* * Delete the whole thing */ void delete_ef_solver(ef_solver_t *solver) { if (solver->exists_context != NULL) { delete_context(solver->exists_context); safe_free(solver->exists_context); solver->exists_context = NULL; } if (solver->forall_context != NULL) { delete_context(solver->forall_context); safe_free(solver->forall_context); solver->forall_context = NULL; } if (solver->exists_model != NULL) { yices_free_model(solver->exists_model); solver->exists_model = NULL; } safe_free(solver->evalue); safe_free(solver->uvalue); solver->evalue = NULL; solver->uvalue = NULL; if (solver->full_model != NULL) { yices_free_model(solver->full_model); solver->full_model = NULL; } yices_delete_term_vector(&solver->implicant); delete_ivector(&solver->evalue_aux); delete_ivector(&solver->uvalue_aux); delete_ivector(&solver->all_vars); delete_ivector(&solver->all_values); }
/* * Check satisfiability and get a model * - ctx = the context * - parameters = heuristic settings (if parameters is NULL, the defaults are used) * - var = array of n uninterpreted terms * - n = size of array evar and value * Output parameters; * - value = array of n terms (to receive the value of each var) * - model = to export the model (if model is NULL, nothing is exported) * * The return code is as in check_context: * 1) if code = STATUS_SAT then the context is satisfiable * and a model is stored in value[0 ... n-1] * - value[i] = a constant term mapped to evar[i] in the model * 2) code = STATUS_UNSAT: not satisfiable * * 3) other codes report an error of some kind or STATUS_INTTERRUPT */ static smt_status_t satisfy_context(context_t *ctx, const param_t *parameters, term_t *var, uint32_t n, term_t *value, model_t **model) { smt_status_t stat; model_t *mdl; int32_t code; assert(context_status(ctx) == STATUS_IDLE); stat = check_context(ctx, parameters); switch (stat) { case STATUS_SAT: case STATUS_UNKNOWN: mdl = yices_get_model(ctx, true); code = yices_term_array_value(mdl, n, var, value); if (model != NULL) { *model = mdl; } else { yices_free_model(mdl); } if (code < 0) { // can't convert the model to constant terms stat = STATUS_ERROR; } break; default: // can't build a model break; } return stat; }
/* * Check satisfiability of the exists_context * - first free the exists_model if non-NULL * - if SAT build a model (in solver->evalue) and store the exists_model */ static smt_status_t ef_solver_check_exists(ef_solver_t *solver) { term_t *evar; uint32_t n; if (solver->exists_model != NULL) { yices_free_model(solver->exists_model); solver->exists_model = NULL; } evar = solver->prob->all_evars; n = iv_len(evar); return satisfy_context(solver->exists_context, solver->parameters, evar, n, solver->evalue, &solver->exists_model); }
/* * Compute an implicant for constraint i * - we must have an assignment for the exists variable in solver->evalue * and an assignment for the universal variables of constraints i in * solver->uvalue_aux. * - this builds and store the full model for constraint i in solver->full_model * then construct and store the implicant in solver->implicant * * Error codes: set solver->status to EF_STATUS_ERROR * - this may happen if yices_model_from_map or yices_implicant_for_fomuulas fail */ static void ef_build_implicant(ef_solver_t *solver, uint32_t i) { model_t *mdl; ef_cnstr_t *cnstr; term_vector_t *v; term_t a[2]; uint32_t n; int32_t code; assert(i < ef_prob_num_constraints(solver->prob)); // free the current full model if any if (solver->full_model != NULL) { yices_free_model(solver->full_model); solver->full_model = NULL; } // build the full_map and the correspongin model. ef_build_full_map(solver, i); n = solver->all_vars.size; assert(n == solver->all_values.size); mdl = yices_model_from_map(n, solver->all_vars.data, solver->all_values.data); if (mdl == NULL) { // error in the model construction solver->status = EF_STATUS_ERROR; // TODO: add another code solver->error_code = yices_error_code(); return; } solver->full_model = mdl; cnstr = solver->prob->cnstr + i; a[0] = cnstr->assumption; a[1] = opposite_term(cnstr->guarantee); v = &solver->implicant; v->size = 0; code = yices_implicant_for_formulas(mdl, 2, a, v); if (code < 0) { solver->status = EF_STATUS_ERROR; solver->error_code = yices_error_code(); } #if 1 printf("Implicant\n"); yices_pp_term_array(stdout, v->size, v->data, 120, UINT32_MAX, 0, 0); printf("(%"PRIu32" literals)\n", v->size); #endif }
int example2_main(void) { type_t real; term_t t, a; int32_t code; context_t *ctx; model_t *mdl; /* * Global initialization: this must called first. */ yices_init(); /* * Create an uninterpreted term of type real and call it "x" */ real = yices_real_type(); t = yices_new_uninterpreted_term(real); code = yices_set_term_name(t, "x"); /* * If code is negative, something went wrong */ if (code < 0) { printf("Error in yices_set_term\n"); yices_print_error(stdout); fflush(stdout); goto done; } /* * Create the atom (x > 0) */ a = yices_arith_gt0_atom(t); /* * Print the atom: */ printf("Atom: "); yices_pp_term(stdout, a, 120, 2, 6); /* * Check that (x > 0) is satisfiable and get a model * - create a context * - assert atom 'a' in this context * - check that the context is satisfiable */ ctx = yices_new_context(NULL); // NULL means use the default configuration code = yices_assert_formula(ctx, a); if (code < 0) { printf("Assert failed: "); yices_print_error(stdout); fflush(stdout); goto done; } switch (yices_check_context(ctx, NULL)) { // NULL means default heuristics case STATUS_SAT: // build the model and print it printf("Satisfiable\n"); mdl = yices_get_model(ctx, true); code = yices_pp_model(stdout, mdl, 120, 100, 0); if (code < 0) { printf("Print model failed: "); yices_print_error(stdout); fflush(stdout); goto done; } // cleanup: delete the model yices_free_model(mdl); break; case STATUS_UNSAT: printf("Unsatisfiable\n"); break; case STATUS_UNKNOWN: printf("Status is unknown\n"); break; case STATUS_IDLE: case STATUS_SEARCHING: case STATUS_INTERRUPTED: case STATUS_ERROR: // these codes should not be returned printf("Bug: unexpected status returned\n"); break; } /* * Delete the context: this is optional since yices_exit * would do it anyway. */ yices_free_context(ctx); done: /* * Global cleanup: free all memory used by Yices */ yices_exit(); return 0; }
/* * Sample exists models * - stop when we find one that's not refuted by the forall constraints * - or when we reach the iteration bound * * Result: * - solver->status = EF_STATUS_ERROR if something goes wrong * - solver->status = EF_STATUS_INTERRUPTED if one of the calls to * check_context is interrupted * - solver->status = EF_STATUS_UNSAT if all efmodels have been tried and none * of them worked * - solver->status = EF_STATUS_UNKNOWN if the iteration limit is reached * - solver->status = EF_STATUS_SAT if a good model is found * * In the later case, * - the model is stored in solver->exists_model * - also it's available as a mapping form solver->prob->evars to solver->evalues * * Also solver->iters stores the number of iterations used. */ static void ef_solver_search(ef_solver_t *solver) { smt_status_t stat; uint32_t i, max; max = solver->max_iters; i = 0; assert(max > 0); #if 0 printf("\nEF search: %"PRIu32" constraints, %"PRIu32" exists vars, %"PRIu32" forall vars\n", ef_prob_num_constraints(solver->prob), ef_prob_num_evars(solver->prob), ef_prob_num_uvars(solver->prob)); // printf("\nConditions on the exists variables:\n"); // yices_pp_term_array(stdout, ef_prob_num_conditions(solver->prob), solver->prob->conditions, 120, UINT32_MAX, 0, 0); #endif ef_solver_start(solver); while (solver->status == EF_STATUS_SEARCHING && i < max) { #if 0 printf("\n--- Iteration %"PRIu32" (scan_idx = %"PRIu32") ---\n", i, solver->scan_idx); #endif stat = ef_solver_check_exists(solver); switch (stat) { case STATUS_SAT: case STATUS_UNKNOWN: // we have a candidate exists model // check it and learn what we can #if 0 // FOR DEBUGGING printf("Candidate exists model:\n"); print_ef_solution(stdout, solver); printf("\n"); #endif ef_solver_check_exists_model(solver); break; case STATUS_UNSAT: solver->status = EF_STATUS_UNSAT; break; case STATUS_INTERRUPTED: solver->status = EF_STATUS_INTERRUPTED; break; default: solver->status = EF_STATUS_CHECK_ERROR; solver->error_code = stat; break; } i ++; } /* * Cleanup and set status if i == max */ if (solver->status != EF_STATUS_SAT && solver->exists_model != NULL) { yices_free_model(solver->exists_model); solver->exists_model = NULL; if (solver->status == EF_STATUS_SEARCHING) { assert(i == max); solver->status = EF_STATUS_UNKNOWN; } } solver->iters = i; }
/* * Option 3: generalize by computing an implicant then * applying projection. */ static term_t ef_generalize3(ef_solver_t *solver, uint32_t i) { model_t *mdl; ef_cnstr_t *cnstr; ivector_t *v, *w; term_t a[2]; uint32_t n; int32_t code; proj_flag_t pflag; term_t result; assert(i < ef_prob_num_constraints(solver->prob)); // free the current full model if any if (solver->full_model != NULL) { yices_free_model(solver->full_model); solver->full_model = NULL; } // build the full_map and the corresponding model. ef_build_full_map(solver, i); n = solver->all_vars.size; assert(n == solver->all_values.size); mdl = yices_model_from_map(n, solver->all_vars.data, solver->all_values.data); if (mdl == NULL) { // error in the model construction solver->status = EF_STATUS_MDL_ERROR; solver->error_code = yices_error_code(); return NULL_TERM; } solver->full_model = mdl; // Constraint cnstr = solver->prob->cnstr + i; a[0] = cnstr->assumption; // B(y) a[1] = opposite_term(cnstr->guarantee); // not C(x, y) #if EF_VERBOSE printf("Constraint:\n"); yices_pp_term_array(stdout, 2, a, 120, UINT32_MAX, 0, 0); printf("(%"PRIu32" literals)\n", 2); #endif // Compute the implicant v = &solver->implicant; ivector_reset(v); code = get_implicant(mdl, solver->prob->manager, LIT_COLLECTOR_ALL_OPTIONS, 2, a, v); if (code < 0) { solver->status = EF_STATUS_IMPLICANT_ERROR; solver->error_code = code; return NULL_TERM; } #if EF_VERBOSE printf("Implicant:\n"); yices_pp_term_array(stdout, v->size, v->data, 120, UINT32_MAX, 0, 0); printf("(%"PRIu32" literals)\n", v->size); #endif // Projection w = &solver->projection; ivector_reset(w); n = ef_constraint_num_uvars(cnstr); #if EF_VERBOSE printf("(%"PRIu32" universals)\n", n); yices_pp_term_array(stdout, n, cnstr->uvars, 120, UINT32_MAX, 0, 0); #endif pflag = project_literals(mdl, solver->prob->manager, v->size, v->data, n, cnstr->uvars, w); if (pflag != PROJ_NO_ERROR) { solver->status = EF_STATUS_PROJECTION_ERROR; solver->error_code = pflag; return NULL_TERM; } #if EF_VERBOSE printf("Projection:\n"); yices_pp_term_array(stdout, w->size, w->data, 120, UINT32_MAX, 0, 0); printf("(%"PRIu32" literals)\n", w->size); #endif switch (w->size) { case 0: result = true_term; break; case 1: result = w->data[0]; break; default: result = mk_and(solver->prob->manager, w->size, w->data); break; } return opposite_term(result); }