/* * 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 }
/* * Learn a constraint for the exists variable based on the * existing forall witness for constraint i: * - the witness is defined by the uvars of constraint i * and the values stored in uvalue_aux. * * This function adds a constraint to the exists_context that will remove the * current exists model: * - if solver->option is EF_NOGEN_OPTION, the new constraint is * of the form (or (/= var[0] eval[k0]) ... (/= var[k-1] eval[k-1])) * where var[0 ... k-1] are the exist variables of constraint i * - if solver->option is EF_GEN_BY_SUBST_OPTION, we build a new * constraint by substitution (option 2) * * If something goes wrong, then solver->status is updated to EF_STATUS_ERROR. * If the new learned assertion makes the exist context trivially unsat * then context->status is set to EF_STATUS_UNSAT. * Otherwise context->status is kept as is. */ static void ef_solver_learn(ef_solver_t *solver, uint32_t i) { ef_cnstr_t *cnstr; term_t *val; term_t new_constraint; uint32_t n; int32_t code; assert(i < ef_prob_num_constraints(solver->prob)); cnstr = solver->prob->cnstr + i; switch (solver->option) { case EF_NOGEN_OPTION: /* * project solver->evalues on the existential * variables that occur in constraint i. * then build (or (/= evar[0] val[0]) ... (/= evar[n-1] val[n-1])) */ n = ef_constraint_num_evars(cnstr); resize_ivector(&solver->evalue_aux, n); solver->evalue_aux.size = n; val = solver->evalue_aux.data; ef_project_exists_model(solver->prob, solver->evalue, cnstr->evars, val, n); new_constraint = ef_generalize1(solver->prob, cnstr->evars, val, n); break; case EF_GEN_BY_SUBST_OPTION: val = solver->uvalue_aux.data; new_constraint = ef_generalize2(solver->prob, i, val); if (new_constraint < 0) { // error in substitution solver->status = EF_STATUS_SUBST_ERROR; solver->error_code = new_constraint; return; } break; case EF_GEN_BY_PROJ_OPTION: default: // added this to prevent bogus GCC warning new_constraint = ef_generalize3(solver, i); if (new_constraint < 0) { return; } break; } // add the new constraint to the exists context code = update_exists_context(solver, new_constraint); if (code == TRIVIALLY_UNSAT) { solver->status = EF_STATUS_UNSAT; } else if (code < 0) { solver->status = EF_STATUS_ASSERT_ERROR; solver->error_code = code; } }
/* * 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; }