/********************* */ /*! \file theory_strings.h ** \verbatim ** Top contributors (to current version): ** Andrew Reynolds, Tianyi Liang, Tim King ** This file is part of the CVC4 project. ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** ** \brief Theory of strings ** ** Theory of strings. **/ #include "cvc4_private.h" #ifndef CVC4__THEORY__STRINGS__THEORY_STRINGS_H #define CVC4__THEORY__STRINGS__THEORY_STRINGS_H #include #include #include "context/cdhashset.h" #include "context/cdlist.h" #include "expr/node_trie.h" #include "theory/strings/base_solver.h" #include "theory/strings/core_solver.h" #include "theory/strings/extf_solver.h" #include "theory/strings/infer_info.h" #include "theory/strings/inference_manager.h" #include "theory/strings/normal_form.h" #include "theory/strings/regexp_elim.h" #include "theory/strings/regexp_operation.h" #include "theory/strings/regexp_solver.h" #include "theory/strings/sequences_stats.h" #include "theory/strings/skolem_cache.h" #include "theory/strings/solver_state.h" #include "theory/strings/strings_fmf.h" #include "theory/strings/strings_rewriter.h" #include "theory/strings/term_registry.h" #include "theory/theory.h" #include "theory/uf/equality_engine.h" namespace CVC4 { namespace theory { namespace strings { /** * Decision procedure for strings. * */ /** inference steps * * Corresponds to a step in the overall strategy of the strings solver. For * details on the individual steps, see documentation on the inference schemas * within TheoryStrings. */ enum InferStep { // indicates that the strategy should break if lemmas or facts are added BREAK, // check initial CHECK_INIT, // check constant equivalence classes CHECK_CONST_EQC, // check extended function evaluation CHECK_EXTF_EVAL, // check cycles CHECK_CYCLES, // check flat forms CHECK_FLAT_FORMS, // check register terms pre-normal forms CHECK_REGISTER_TERMS_PRE_NF, // check normal forms equalities CHECK_NORMAL_FORMS_EQ, // check normal forms disequalities CHECK_NORMAL_FORMS_DEQ, // check codes CHECK_CODES, // check lengths for equivalence classes CHECK_LENGTH_EQC, // check register terms for normal forms CHECK_REGISTER_TERMS_NF, // check extended function reductions CHECK_EXTF_REDUCTION, // check regular expression memberships CHECK_MEMBERSHIP, // check cardinality CHECK_CARDINALITY, }; std::ostream& operator<<(std::ostream& out, Inference i); class TheoryStrings : public Theory { friend class InferenceManager; typedef context::CDList NodeList; typedef context::CDHashMap NodeBoolMap; typedef context::CDHashMap NodeIntMap; typedef context::CDHashMap NodeNodeMap; typedef context::CDHashSet NodeSet; typedef context::CDHashSet TypeNodeSet; public: TheoryStrings(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo); ~TheoryStrings(); TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; } void setMasterEqualityEngine(eq::EqualityEngine* eq) override; std::string identify() const override { return std::string("TheoryStrings"); } public: void propagate(Effort e) override; bool propagate(TNode literal); Node explain(TNode literal) override; eq::EqualityEngine* getEqualityEngine() override { return &d_equalityEngine; } bool getCurrentSubstitution(int effort, std::vector& vars, std::vector& subs, std::map >& exp) override; /** * Get all relevant information in this theory regarding the current * model. Return false if a contradiction is discovered. */ bool collectModelInfo(TheoryModel* m) override; // NotifyClass for equality engine class NotifyClass : public eq::EqualityEngineNotify { public: NotifyClass(TheoryStrings& ts) : d_str(ts), d_state(ts.d_state) {} bool eqNotifyTriggerEquality(TNode equality, bool value) override { Debug("strings") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl; if (value) { return d_str.propagate(equality); } else { // We use only literal triggers so taking not is safe return d_str.propagate(equality.notNode()); } } bool eqNotifyTriggerPredicate(TNode predicate, bool value) override { Debug("strings") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl; if (value) { return d_str.propagate(predicate); } else { return d_str.propagate(predicate.notNode()); } } bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) override { Debug("strings") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl; if (value) { return d_str.propagate(t1.eqNode(t2)); } else { return d_str.propagate(t1.eqNode(t2).notNode()); } } void eqNotifyConstantTermMerge(TNode t1, TNode t2) override { Debug("strings") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl; d_str.conflict(t1, t2); } void eqNotifyNewClass(TNode t) override { Debug("strings") << "NotifyClass::eqNotifyNewClass(" << t << std::endl; d_str.eqNotifyNewClass(t); } void eqNotifyPreMerge(TNode t1, TNode t2) override { Debug("strings") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << std::endl; d_state.eqNotifyPreMerge(t1, t2); } void eqNotifyPostMerge(TNode t1, TNode t2) override { Debug("strings") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << std::endl; } void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override { Debug("strings") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << std::endl; d_state.eqNotifyDisequal(t1, t2, reason); } private: /** The theory of strings object to notify */ TheoryStrings& d_str; /** The solver state of the theory of strings */ SolverState& d_state; };/* class TheoryStrings::NotifyClass */ //--------------------------- helper functions /** get normal string * * This method returns the node that is equivalent to the normal form of x, * and adds the corresponding explanation to nf_exp. * * For example, if x = y ++ z is an assertion in the current context, then * this method returns the term y ++ z and adds x = y ++ z to nf_exp. */ Node getNormalString(Node x, std::vector& nf_exp); //-------------------------- end helper functions private: // Constants Node d_emptyString; Node d_true; Node d_false; Node d_zero; Node d_one; Node d_neg_one; /** the cardinality of the alphabet */ uint32_t d_cardSize; /** The notify class */ NotifyClass d_notify; /** * Statistics for the theory of strings/sequences. All statistics for these * theories is collected in this object. */ SequencesStatistics d_statistics; /** Equaltity engine */ eq::EqualityEngine d_equalityEngine; /** The solver state object */ SolverState d_state; /** The term registry for this theory */ TermRegistry d_termReg; /** The (custom) output channel of the theory of strings */ InferenceManager d_im; std::vector< Node > d_empty_vec; private: std::map< Node, Node > d_eqc_to_len_term; ///////////////////////////////////////////////////////////////////////////// // NOTIFICATIONS ///////////////////////////////////////////////////////////////////////////// public: void presolve() override; void shutdown() override {} ///////////////////////////////////////////////////////////////////////////// // MAIN SOLVER ///////////////////////////////////////////////////////////////////////////// private: void addSharedTerm(TNode n) override; EqualityStatus getEqualityStatus(TNode a, TNode b) override; private: void addCarePairs(TNodeTrie* t1, TNodeTrie* t2, unsigned arity, unsigned depth); public: /** preregister term */ void preRegisterTerm(TNode n) override; /** Expand definition */ Node expandDefinition(Node n) override; /** Check at effort e */ void check(Effort e) override; /** needs check last effort */ bool needsCheckLastEffort() override; /** Conflict when merging two constants */ void conflict(TNode a, TNode b); /** called when a new equivalence class is created */ void eqNotifyNewClass(TNode t); protected: /** compute care graph */ void computeCareGraph() override; /** * Are x and y shared terms that are not equal? This is used for constructing * the care graph in the above function. */ bool areCareDisequal(TNode x, TNode y); /** Collect model info for type tn * * Assigns model values (in m) to all relevant terms of the string-like type * tn in the current context, which are stored in repSet. * * Returns false if a conflict is discovered while doing this assignment. */ bool collectModelInfoType( TypeNode tn, const std::unordered_set& repSet, TheoryModel* m); /** assert pending fact * * This asserts atom with polarity to the equality engine of this class, * where exp is the explanation of why (~) atom holds. * * This call may trigger further initialization steps involving the terms * of atom, including calls to registerTerm. */ void assertPendingFact(Node atom, bool polarity, Node exp); // Symbolic Regular Expression private: /** The theory rewriter for this theory. */ StringsRewriter d_rewriter; /** * The base solver, responsible for reasoning about congruent terms and * inferring constants for equivalence classes. */ BaseSolver d_bsolver; /** * The core solver, responsible for reasoning about string concatenation * with length constraints. */ CoreSolver d_csolver; /** * Extended function solver, responsible for reductions and simplifications * involving extended string functions. */ std::unique_ptr d_esolver; /** regular expression solver module */ std::unique_ptr d_rsolver; /** regular expression elimination module */ RegExpElimination d_regexp_elim; /** Strings finite model finding decision strategy */ StringsFmf d_stringsFmf; public: // ppRewrite Node ppRewrite(TNode atom) override; private: //-----------------------inference steps /** check register terms pre-normal forms * * This calls registerTerm(n,2) on all non-congruent strings in the * equality engine of this class. */ void checkRegisterTermsPreNormalForm(); /** check codes * * This inference schema ensures that constraints between str.code terms * are satisfied by models that correspond to extensions of the current * assignment. In particular, this method ensures that str.code can be * given an interpretation that is injective for string arguments with length * one. It may add lemmas of the form: * str.code(x) == -1 V str.code(x) != str.code(y) V x == y */ void checkCodes(); /** check register terms for normal forms * * This calls registerTerm(str.++(t1, ..., tn ), 3) on the normal forms * (t1, ..., tn) of all string equivalence classes { s1, ..., sm } such that * there does not exist a term of the form str.len(si) in the current context. */ void checkRegisterTermsNormalForms(); //-----------------------end inference steps //-----------------------representation of the strategy /** is strategy initialized */ bool d_strategy_init; /** run the given inference step */ void runInferStep(InferStep s, int effort); /** the strategy */ std::vector d_infer_steps; /** the effort levels */ std::vector d_infer_step_effort; /** the range (begin, end) of steps to run at given efforts */ std::map > d_strat_steps; /** do we have a strategy for effort e? */ bool hasStrategyEffort(Effort e) const; /** initialize the strategy * * This adds (s,effort) as a strategy step to the vectors d_infer_steps and * d_infer_step_effort. This indicates that a call to runInferStep should * be run as the next step in the strategy. If addBreak is true, we add * a BREAK to the strategy following this step. */ void addStrategyStep(InferStep s, int effort = 0, bool addBreak = true); /** initialize the strategy * * This initializes the above information based on the options. This makes * a series of calls to addStrategyStep above. */ void initializeStrategy(); /** run strategy * * This executes the inference steps starting at index sbegin and ending at * index send. We exit if any step in this sequence adds a lemma or infers a * fact. */ void runStrategy(unsigned sbegin, unsigned send); //-----------------------end representation of the strategy };/* class TheoryStrings */ }/* CVC4::theory::strings namespace */ }/* CVC4::theory namespace */ }/* CVC4 namespace */ #endif /* CVC4__THEORY__STRINGS__THEORY_STRINGS_H */