/* * 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); }