/* * Merge the exists and forall variables of constraint i * - store the variables in solver->all_vars * - store their values in solver->all_values */ static void ef_build_full_map(ef_solver_t *solver, uint32_t i) { ef_cnstr_t *cnstr; ivector_t *v; uint32_t n; assert(i < ef_prob_num_constraints(solver->prob)); cnstr = solver->prob->cnstr + i; // collect all variables of cnstr in solver->all_vars v = &solver->all_vars; ivector_reset(v); n = ef_constraint_num_evars(cnstr); ivector_add(v, cnstr->evars, n); n = ef_constraint_num_uvars(cnstr); ivector_add(v, cnstr->uvars, n); // project the evalues onto the exists variable of constraint i // store the results in all_values v = &solver->all_values; n = ef_constraint_num_evars(cnstr); resize_ivector(v, n); v->size = n; ef_project_exists_model(solver->prob, solver->evalue, cnstr->evars, v->data, n); // copy the uvalues for constraint i (from uvalue_aux to v) n = ef_constraint_num_uvars(cnstr); assert(n == solver->uvalue_aux.size); ivector_add(v, solver->uvalue_aux.data, n); #if EF_VERBOSE printf("Full map\n"); print_full_map(stdout, solver); fflush(stdout); #endif }
/* * Option 2: generalize by substitution * - return (prob->cnstr[i].guarantee with y := value) */ static term_t ef_generalize2(ef_prob_t *prob, uint32_t i, term_t *value) { ef_cnstr_t *cnstr; uint32_t n; term_t g; assert(i < ef_prob_num_constraints(prob)); cnstr = prob->cnstr + i; n = ef_constraint_num_uvars(cnstr); g = ef_substitution(prob, cnstr->uvars, value, n, cnstr->guarantee); return g; }
/* * Show witness found for constraint i */ void print_forall_witness(FILE *f, ef_solver_t *solver, uint32_t i) { ef_prob_t *prob; ef_cnstr_t *cnstr; uint32_t j, n; prob = solver->prob; assert(i < ef_prob_num_constraints(prob)); cnstr = prob->cnstr + i; n = ef_constraint_num_uvars(cnstr); for (j=0; j<n; j++) { fprintf(f, "%s := ", yices_get_term_name(cnstr->uvars[j])); yices_pp_term(f, solver->uvalue_aux.data[j], 100, 1, 10); } }
/* * Sampling for the i-th constraint in solver->prob * - search for at most max_samples y's that satisfy the assumption of constraint i in prob * - for each such y, add a new constraint to the exist context ctx * - max_samples = bound on the number of samples to take (must be positive) * * Constraint i is of the form * (FORALL Y_i: B_i(Y_i) => C(X_i, Y_i)) * - every sample is a model y_i that satisfies B_i. * - for each sample, we learn that any good candidate X_i must satisfy C(X_i, y_i). * So we add the constraint C(X_i, y_i) to ctx. * * Update the solver->status to * - EF_STATUS_UNSAT if the exits context is trivially unsat * - EF_STATUS_..._ERRORif something goes wrong * - EF_STATUS_INTERRUPTED if a call to check/recheck context is interrupted * keep it unchanged otherwise (should be EF_STATUS_SEARCHING). */ static void ef_sample_constraint(ef_solver_t *solver, uint32_t i) { context_t *sampling_ctx; ef_cnstr_t *cnstr; term_t *value; uint32_t nvars, samples; int32_t ucode, ecode; smt_status_t status; term_t cnd; assert(i < ef_prob_num_constraints(solver->prob) && solver->max_samples > 0); cnstr = solver->prob->cnstr + i; /* * make uvalue_aux large enough * its size = number of universal variables in constraint i */ nvars = ef_constraint_num_uvars(cnstr); resize_ivector(&solver->uvalue_aux, nvars); solver->uvalue_aux.size = nvars; value = solver->uvalue_aux.data; samples = solver->max_samples; /* * assert the assumption in the forall context */ sampling_ctx = get_forall_context(solver); ucode = assert_formula(sampling_ctx, cnstr->assumption); while (ucode == CTX_NO_ERROR) { status = satisfy_context(sampling_ctx, solver->parameters, cnstr->uvars, nvars, value, NULL); switch (status) { case STATUS_SAT: case STATUS_UNKNOWN: // learned condition on X: cnd = ef_substitution(solver->prob, cnstr->uvars, value, nvars, cnstr->guarantee); if (cnd < 0) { solver->status = EF_STATUS_SUBST_ERROR; solver->error_code = cnd; goto done; } ecode = update_exists_context(solver, cnd); if (ecode < 0) { solver->status = EF_STATUS_ASSERT_ERROR; solver->error_code = ecode; goto done; } if (ecode == TRIVIALLY_UNSAT) { solver->status = EF_STATUS_UNSAT; goto done; } break; case STATUS_UNSAT: // no more samples for this constraints goto done; case STATUS_INTERRUPTED: solver->status = EF_STATUS_INTERRUPTED; goto done; default: solver->status = EF_STATUS_CHECK_ERROR; solver->error_code = status; goto done; } samples --; if (samples == 0) goto done; ucode = assert_blocking_clause(sampling_ctx); } /* * if ucode < 0, something went wrong in assert_formula * or in assert_blocking_clause */ if (ucode < 0) { solver->status = EF_STATUS_ASSERT_ERROR; solver->error_code = ucode; } done: clear_forall_context(solver, true); }
/* * 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; }
/* * 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); }