/* * Print solution found by the ef solver */ void print_ef_solution(FILE *f, ef_solver_t *solver) { ef_prob_t *prob; uint32_t i, n; prob = solver->prob; n = ef_prob_num_evars(prob); for (i=0; i<n; i++) { fprintf(f, "%s := ", yices_get_term_name(prob->all_evars[i])); yices_pp_term(f, solver->evalue[i], 100, 1, 10); } }
/* * Initialize solver: * - prob = problem descriptor * - logic/arch/parameters = for context initialization and check */ void init_ef_solver(ef_solver_t *solver, ef_prob_t *prob, smt_logic_t logic, context_arch_t arch) { uint32_t n; solver->prob = prob; solver->logic = logic; solver->arch = arch; solver->status = EF_STATUS_IDLE; solver->error_code = 0; solver->parameters = NULL; solver->option = EF_GEN_BY_SUBST_OPTION; solver->max_samples = 0; solver->max_iters = 0; solver->scan_idx = 0; solver->exists_context = NULL; solver->forall_context = NULL; solver->exists_model = NULL; n = ef_prob_num_evars(prob); assert(n <= UINT32_MAX/sizeof(term_t)); solver->evalue = (term_t *) safe_malloc(n * sizeof(term_t)); n = ef_prob_num_uvars(prob); assert(n <= UINT32_MAX/sizeof(term_t)); solver->uvalue = (term_t *) safe_malloc(n * sizeof(term_t)); solver->full_model = NULL; init_ivector(&solver->implicant, 20); init_ivector(&solver->projection, 20); init_ivector(&solver->evalue_aux, 64); init_ivector(&solver->uvalue_aux, 64); init_ivector(&solver->all_vars, 64); init_ivector(&solver->all_values, 64); solver->trace = NULL; }
/* * Test the current exists model using universal constraint i * - i must be a valid index (i.e., 0 <= i < solver->prob->num_cnstr) * - this checks the assertion B_i and not C_i after replacing existential * variables by their values (stored in evalue) * - return code: * if STATUS_SAT (or STATUS_UNKNOWN): a model of (B_i and not C_i) * is found and stored in uvalue_aux * if STATUS_UNSAT: no model found (current exists model is good as * far as constraint i is concerned) * anything else: an error or interruption * * - if we get an error or interruption, solver->status is updated * otherwise, it is kept as is (should be EF_STATUS_SEARCHING) */ static smt_status_t ef_solver_test_exists_model(ef_solver_t *solver, uint32_t i) { context_t *forall_ctx; ef_cnstr_t *cnstr; term_t *value; term_t g; uint32_t n; int32_t code; smt_status_t status; assert(i < ef_prob_num_constraints(solver->prob)); cnstr = solver->prob->cnstr + i; n = ef_prob_num_evars(solver->prob); g = ef_substitution(solver->prob, solver->prob->all_evars, solver->evalue, n, cnstr->guarantee); if (g < 0) { // error in substitution solver->status = EF_STATUS_SUBST_ERROR; solver->error_code = g; return STATUS_ERROR; } /* * make uvalue_aux large enough */ n = ef_constraint_num_uvars(cnstr); resize_ivector(&solver->uvalue_aux, n); solver->uvalue_aux.size = n; value = solver->uvalue_aux.data; forall_ctx = get_forall_context(solver); code = forall_context_assert(solver, cnstr->assumption, g); // assert B_i(Y_i) and not g(Y_i) if (code == CTX_NO_ERROR) { status = satisfy_context(forall_ctx, solver->parameters, cnstr->uvars, n, value, NULL); switch (status) { case STATUS_SAT: case STATUS_UNKNOWN: case STATUS_UNSAT: break; case STATUS_INTERRUPTED: solver->status = EF_STATUS_INTERRUPTED; break; default: solver->status = EF_STATUS_CHECK_ERROR; solver->error_code = status; break; } } else if (code == TRIVIALLY_UNSAT) { assert(context_status(forall_ctx) == STATUS_UNSAT); status = STATUS_UNSAT; } else { // error in assertion solver->status = EF_STATUS_ASSERT_ERROR; solver->error_code = code; status = STATUS_ERROR; } clear_forall_context(solver, true); return status; }
/* * 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; }