/* * This file is part of the Yices SMT Solver. * Copyright (C) 2017 SRI International. * * Yices is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Yices is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Yices. If not, see . */ /* * EF-Solver */ /* * Input problems are stored in an ef_prob structure. * - prob->evars = existential variables (denoted by X) * - prob->uvars = universal variables (denoted by Y) * - prob->conditions = a set of constraints on X: * A1(X) and ... and At(X) * - and a finite list of universal constraints * * Each universal constraint has the form * * (FORALL Y_i: B_i(Y_i) => C_i(X_i, Y_i)) * * where Y_i is a subset of the universal variables * X_i is a subset of the existential variables * B_i is the assumption (on Y_i) * C_i is the guarantee * * * The goal is to solve the exists/forall problem: * * EXISTS X: A1(X) and ... and At(X) * AND (FORALL Y_1: B_1(Y_1) => C_1(X_1, Y_1)) * ... * AND (FORALL Y_k: B_k(Y_k) => C_k(X_k, Y_k)) * * * General procedure * ----------------- * * 1) initialize a context ctx with A1(X) ... At(X) * * 2) iterate the following loop * * a) check whether ctx is satisfiable. * If it's not, we're done. The EF-problem has no solution. * If it is, let x be a model for ctx * * b) check whether x is a solution: * * For each universal constraint, check whether * * B_i(Y_i) AND not C_i(X_i, Y_i) is satisfiable * under the mapping X_i := x_i. * * If it is, then let y_i be a model of this constraint. * * c) If we find no witness in step b: exit. The model x is * a solution to the EF-problem. * * Otherwise, we have a witness y_i that shows why x is not * good. That is, y_i is a counterexample to * * (forall Y_i: B_i(Y_i) => C_i(X_i, Y_i)) with [X := x] * * So y_i eliminates x from the candidate spaces. * We want to generalize y_i: construct a formula Z(X_i) such * that: 1) x satisfies Z(X_i) * 2) no other solution to Z(X_i) is a good candidate. * * Once we have Z(X_i), we add \not Z(X_i) to the ctx and * go back to a). * * * Different options for constructing Z * ------------------------------------ * - Option 1: no generalization: Z(X_i) is (X_i /= x_i) * (just eliminate x_i) * * - Option 2: generalization by substitution: * Z(X_i) is C(X_i, Y_i) with [Y_i := y_i] * (eliminate any x_i for which y_i is a witness). * * - Option 3: quantifier elimination: * rewrite (FORALL Y_i: B_i(Y_i) AND not C_i(X_i, Y_i)) * to Z(X_i) * * - Other options: cheaper forms of quantifier elimination, * driven by the witness y_i. * * Variant for initializing the exist context * ------------------------------------------ * - Given constraint * * (FORALL Y_i: B_i(Y_i) => C_i(X_i, Y_i)) * * we can sample y_s that satisfy B_i(Y_i). For every * such y_i, we get a constraint C_i(X_i, y_i) by substitution. * Then this constraint depends only on the existential * variable, so we can add (C_i(X_i, y_i))) to the * exists context (i.e., any good X_i must satisfy C_i(X_i, y_i)). * * Baseline implementation * ----------------------- * - support Option 1 and 2. */ #ifndef __EFSOLVER_H #define __EFSOLVER_H #include #include #include #include "api/search_parameters.h" #include "api/smt_logic_codes.h" #include "context/context_types.h" #include "exists_forall/ef_problem.h" #include "io/tracer.h" #include "yices_types.h" /* * efsolver: stores a pointer to the ef_prob_t descriptor * + flags for context initialization: logic/arch * + search parameters (for now we use the same parameters for exists and forall) * + generalization option * + presampling setting: if max_samples is 0, no presampling * otherwise, max_samples is used for sampling * * Internal data structures: * - exists_context, forall_context: pointers to contexts, allocated and initialized * when needed * - evalue = array large enough to store the value of all exists variables * - uvalue = array large enough to store the value of all universal variables * - evalue_aux and uvalue_aux = auxiliary vectors (to store value vector of smaller * sizes than evalue/uvalue) * * Flags for diagnostic * - status = status of the last call to check (either in the exists or * the forall context) * - code = result of the last assertion (negative code is an error) */ typedef enum ef_gen_option { EF_NOGEN_OPTION, // option 1 above EF_GEN_BY_SUBST_OPTION, // option 2 above EF_GEN_BY_PROJ_OPTION, // model-based projection (cheap quantifier elimination) EF_GEN_AUTO_OPTION, // select between PROJ or SUBST depending on variables } ef_gen_option_t; /* * Status + error report */ typedef enum ef_status { EF_STATUS_IDLE, // before call to efsolver_check EF_STATUS_SEARCHING, // while in efsolver_check EF_STATUS_UNKNOWN, // max_iters reached EF_STATUS_SAT, // satisfiable EF_STATUS_UNSAT, // unsat EF_STATUS_INTERRUPTED, // timeout EF_STATUS_SUBST_ERROR, // error in a substitution EF_STATUS_TVAL_ERROR, // error when converting model to constant terms EF_STATUS_CHECK_ERROR, // unexpected status in check_context EF_STATUS_ASSERT_ERROR, // error in assert formulas EF_STATUS_MDL_ERROR, // error in model_from_map EF_STATUS_IMPLICANT_ERROR, // error in get_implicant EF_STATUS_PROJECTION_ERROR, // error in projection EF_STATUS_ERROR, // any other internal error } ef_status_t; #define NUM_EF_STATUSES (EF_STATUS_ERROR+1) /* * error_code below can be used for diagnostic * when status is EF_STATUS_..._ERROR: * - status = EF_STATUS_SUBST_ERROR * error_code = negative code from apply_term_subst * - status = EF_STATUS_TVAL_ERROR * error_code = not used (error from yices_term_array_value) * - status = EF_STATUS_CHECK_ERROR: * error_code = the unexpected status * - status = EF_STATUS_ASSERT_ERROR * error_code = exception code from context_assert_formulas */ typedef struct ef_solver_s { // Input problem + logic and architecture codes ef_prob_t *prob; smt_logic_t logic; context_arch_t arch; ef_status_t status; int32_t error_code; // for diagnostic // Parameters used during the search const param_t *parameters; // search parameters ef_gen_option_t option; // generalization mode uint32_t max_samples; // bound on pre-sampling: 0 means no pre-sampling uint32_t max_iters; // bound on outer iterations uint32_t iters; // number of outer iterations uint32_t scan_idx; // first universal constraint to check // Exists and forall contexts + exists model context_t *exists_context; context_t *forall_context; model_t *exists_model; term_t *evalue; term_t *uvalue; // Support for implicant construction and projection model_t *full_model; ivector_t implicant; ivector_t projection; // Auxiliary buffers ivector_t evalue_aux; ivector_t uvalue_aux; ivector_t all_vars; ivector_t all_values; // For verbose output (default = NULL) tracer_t *trace; } ef_solver_t; /* * Initialize solver: * - prob = problem descriptor * - logic/arch = for context initialization * - the logic must be supported by the context (so it must be QF_XXX). */ extern void init_ef_solver(ef_solver_t *solver, ef_prob_t *prob, smt_logic_t logic, context_arch_t arch); /* * Delete the whole thing */ extern void delete_ef_solver(ef_solver_t *solver); /* * Set the trace: * - the current tracer must be NULL. */ extern void ef_solver_set_trace(ef_solver_t *solver, tracer_t *trace); /* * Check satisfiability: * * The result is stored in solver->status: * - EF_STATUS_ERROR if something goes wrong * - EF_STATUS_INTERRUPTED if one of the calls to check_context is interrupted * - EF_STATUS_UNSAT if all exists models have been tried and none of them worked * - EF_STATUS_UNKNOWN if the iteration limit is reached * - 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 required. */ extern void ef_solver_check(ef_solver_t *solver, const param_t *parameters, ef_gen_option_t gen_mode, uint32_t max_samples, uint32_t max_iters); /* * Stop the search */ extern void ef_solver_stop_search(ef_solver_t *solver); /* * Print solution */ extern void print_ef_solution(FILE *f, ef_solver_t *solver); #endif /* __EFSOLVER_H */