Eliminate static options accesses in sygus (#8943)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Sat, 9 Jul 2022 04:49:19 +0000 (23:49 -0500)
committerGitHub <noreply@github.com>
Sat, 9 Jul 2022 04:49:19 +0000 (04:49 +0000)
Towards eliminating option scopes.

Also simplifies and corrects an issue in default Boolean grammar construction where included/excluded constructors were ignored.

src/theory/quantifiers/sygus/enum_value_manager.cpp
src/theory/quantifiers/sygus/sygus_enumerator.cpp
src/theory/quantifiers/sygus/sygus_enumerator.h
src/theory/quantifiers/sygus/sygus_grammar_cons.cpp
src/theory/quantifiers/sygus/sygus_grammar_cons.h
src/theory/quantifiers/sygus/sygus_interpol.cpp
src/theory/quantifiers/sygus/sygus_unif_rl.cpp
src/theory/quantifiers/sygus/sygus_unif_rl.h
src/theory/quantifiers/sygus_inst.cpp

index 93e29f8b35b7ac74b29dd4a70fb3a24c330335f6..ed8c7589fcfc72c86503259d020a7a084b6015ed 100644 (file)
@@ -125,7 +125,8 @@ Node EnumValueManager::getEnumeratedValue(bool& activeIncomplete)
             d_secd.get(),
             &d_stats,
             false,
-            options().quantifiers.sygusRepairConst);
+            options().quantifiers.sygusRepairConst,
+            options().quantifiers.sygusEnumFastNumConsts);
       }
     }
     Trace("sygus-active-gen")
index bc9146dfdf66d158423799b82406b7ca779431a7..53b8e4adafc4d331f10dffa946d4c3224fb73059 100644 (file)
@@ -38,13 +38,15 @@ SygusEnumerator::SygusEnumerator(Env& env,
                                  SygusEnumeratorCallback* sec,
                                  SygusStatistics* s,
                                  bool enumShapes,
-                                 bool enumAnyConstHoles)
+                                 bool enumAnyConstHoles,
+                                 size_t numConstants)
     : EnumValGenerator(env),
       d_tds(tds),
       d_sec(sec),
       d_stats(s),
       d_enumShapes(enumShapes),
       d_enumAnyConstHoles(enumAnyConstHoles),
+      d_enumNumConsts(numConstants),
       d_tlEnum(nullptr),
       d_abortSize(-1)
 {
@@ -598,7 +600,7 @@ SygusEnumerator::TermEnum* SygusEnumerator::getMasterEnumForType(TypeNode tn)
   }
   initializeTermCache(tn);
   // create the master enumerator
-  d_masterEnumInt[tn].reset(new TermEnumMasterInterp(tn));
+  d_masterEnumInt[tn].reset(new TermEnumMasterInterp(tn, d_enumNumConsts));
   // initialize the master enumerator
   TermEnumMasterInterp* temi = d_masterEnumInt[tn].get();
   bool ret = temi->initialize(this, tn);
@@ -1147,8 +1149,13 @@ Node SygusEnumerator::TermEnumMaster::convertShape(
   return visited[n];
 }
 
-SygusEnumerator::TermEnumMasterInterp::TermEnumMasterInterp(TypeNode tn)
-    : TermEnum(), d_te(tn), d_currNumConsts(0), d_nextIndexEnd(0)
+SygusEnumerator::TermEnumMasterInterp::TermEnumMasterInterp(TypeNode tn,
+                                                            size_t numConstants)
+    : TermEnum(),
+      d_te(tn),
+      d_currNumConsts(0),
+      d_nextIndexEnd(0),
+      d_enumNumConsts(numConstants)
 {
 }
 
@@ -1177,7 +1184,7 @@ bool SygusEnumerator::TermEnumMasterInterp::increment()
   {
     tc.pushEnumSizeIndex();
     d_currSize++;
-    d_currNumConsts = d_currNumConsts * options::sygusEnumFastNumConsts();
+    d_currNumConsts = d_currNumConsts * d_enumNumConsts;
     d_nextIndexEnd = d_nextIndexEnd + d_currNumConsts;
   }
   ++d_te;
index 441c57618b7d8f39223be16bd6bc1ef00d6a0d8c..2626aca5a227b5dadc275f180d3861c79e56fd09 100644 (file)
@@ -70,13 +70,16 @@ class SygusEnumerator : public EnumValGenerator
    * number of free variables
    * @param enumAnyConstHoles If true, this enumerator will generate terms where
    * free variables are the arguments to any-constant constructors.
+   * @param numConstants The number of interpreted constants to consider for
+   * each size
    */
   SygusEnumerator(Env& env,
                   TermDbSygus* tds = nullptr,
                   SygusEnumeratorCallback* sec = nullptr,
                   SygusStatistics* s = nullptr,
                   bool enumShapes = false,
-                  bool enumAnyConstHoles = false);
+                  bool enumAnyConstHoles = false,
+                  size_t numConstants = 5);
   ~SygusEnumerator() {}
   /** initialize this class with enumerator e */
   void initialize(Node e) override;
@@ -103,6 +106,8 @@ class SygusEnumerator : public EnumValGenerator
   /** Whether we are enumerating free variables as arguments to any-constant
    * constructors */
   bool d_enumAnyConstHoles;
+  /** The number of interpreted constants to consider for each size */
+  size_t d_enumNumConsts;
   /** Term cache
    *
    * This stores a list of terms for a given sygus type. The key features of
@@ -456,7 +461,7 @@ class SygusEnumerator : public EnumValGenerator
   class TermEnumMasterInterp : public TermEnum
   {
    public:
-    TermEnumMasterInterp(TypeNode tn);
+    TermEnumMasterInterp(TypeNode tn, size_t numConstants);
     /** initialize this enumerator */
     bool initialize(SygusEnumerator* se, TypeNode tn);
     /** get the current term of the enumerator */
@@ -471,6 +476,8 @@ class SygusEnumerator : public EnumValGenerator
     unsigned d_currNumConsts;
     /** the next end threshold */
     unsigned d_nextIndexEnd;
+    /** The number of interpreted constants to consider for each size */
+    size_t d_enumNumConsts;
   };
   /** a free variable enumerator
    *
index 9d3e9d7faf16fe04cc9fb98a031ec70ebd0c7571..2081ed86dc30b5056b4fe0f0bd61fe495ab1abca 100644 (file)
@@ -22,7 +22,6 @@
 #include "expr/dtype_cons.h"
 #include "expr/node_algorithm.h"
 #include "options/base_options.h"
-#include "options/quantifiers_options.h"
 #include "theory/bv/theory_bv_utils.h"
 #include "theory/datatypes/sygus_datatype_utils.h"
 #include "theory/quantifiers/sygus/sygus_grammar_norm.h"
@@ -169,7 +168,8 @@ Node CegGrammarConstructor::process(Node q,
       }
 
       // make the default grammar
-      tn = mkSygusDefaultType(preGrammarType,
+      tn = mkSygusDefaultType(options(),
+                              preGrammarType,
                               sfvl,
                               ss.str(),
                               extra_cons,
@@ -392,13 +392,9 @@ Node CegGrammarConstructor::convertToEmbedding(Node n)
   return visited[n];
 }
 
-TypeNode CegGrammarConstructor::mkUnresolvedType(const std::string& name,
-                                                 std::set<TypeNode>& unres)
+TypeNode CegGrammarConstructor::mkUnresolvedType(const std::string& name)
 {
-  TypeNode unresolved =
-      NodeManager::currentNM()->mkUnresolvedDatatypeSort(name);
-  unres.insert(unresolved);
-  return unresolved;
+  return NodeManager::currentNM()->mkUnresolvedDatatypeSort(name);
 }
 
 void CegGrammarConstructor::mkSygusConstantsForType(TypeNode type,
@@ -576,7 +572,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
     const std::map<TypeNode, std::unordered_set<Node>>& include_cons,
     std::unordered_set<Node>& term_irrelevant,
     std::vector<SygusDatatypeGenerator>& sdts,
-    std::set<TypeNode>& unres)
+    options::SygusGrammarConsMode sgcm)
 {
   NodeManager* nm = NodeManager::currentNM();
   Trace("sygus-grammar-def") << "Construct default grammar for " << fun << " "
@@ -615,14 +611,19 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
 
   // create placeholder for boolean type (kept apart since not collected)
 
+  // make Boolean type
+  TypeNode bool_type = nm->booleanType();
+  // the index of Bool in types
+  size_t boolIndex = types.size();
+  types.push_back(bool_type);
+
   // create placeholders for collected types
   std::vector<TypeNode> unres_types;
   std::map<TypeNode, TypeNode> type_to_unres;
   std::map<TypeNode, std::unordered_set<Node>>::const_iterator itc;
   // maps types to the index of its "any term" grammar construction
   std::map<TypeNode, std::pair<unsigned, bool>> typeToGAnyTerm;
-  options::SygusGrammarConsMode sgcm = options::sygusGrammarConsMode();
-  for (unsigned i = 0, size = types.size(); i < size; ++i)
+  for (size_t i = 0, size = types.size(); i < size; ++i)
   {
     std::stringstream ss;
     ss << fun << "_" << types[i];
@@ -639,23 +640,12 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
       sdts.back().d_include_cons = itc->second;
     }
     //make unresolved type
-    TypeNode unres_t = mkUnresolvedType(dname, unres);
+    TypeNode unres_t = mkUnresolvedType(dname);
     unres_types.push_back(unres_t);
     type_to_unres[types[i]] = unres_t;
     sygus_to_builtin[unres_t] = types[i];
   }
-  // make Boolean type
-  std::stringstream ssb;
-  ssb << fun << "_Bool";
-  std::string dbname = ssb.str();
-  sdts.push_back(SygusDatatypeGenerator(dbname));
-  unsigned boolIndex = types.size();
-  TypeNode bool_type = nm->booleanType();
-  TypeNode unres_bt = mkUnresolvedType(ssb.str(), unres);
-  types.push_back(bool_type);
-  unres_types.push_back(unres_bt);
-  type_to_unres[bool_type] = unres_bt;
-  sygus_to_builtin[unres_bt] = bool_type;
+  TypeNode unres_bt = type_to_unres[bool_type];
 
   // We ensure an ordering on types such that parametric types are processed
   // before their consitituents. Since parametric types were added before their
@@ -687,7 +677,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
         std::stringstream ssat;
         ssat << sdts[i].d_sdt.getName() << "_any_term";
         sdts.push_back(SygusDatatypeGenerator(ssat.str()));
-        TypeNode unresAnyTerm = mkUnresolvedType(ssat.str(), unres);
+        TypeNode unresAnyTerm = mkUnresolvedType(ssat.str());
         unres_types.push_back(unresAnyTerm);
         // set tracking information for later addition at boolean type.
         std::pair<unsigned, bool> p(sdts.size() - 1, false);
@@ -789,7 +779,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
         ss << fun << "_PosIReal";
         std::string posIRealName = ss.str();
         // make unresolved type
-        TypeNode unresPosIReal = mkUnresolvedType(posIRealName, unres);
+        TypeNode unresPosIReal = mkUnresolvedType(posIRealName);
         unres_types.push_back(unresPosIReal);
         // make data type for positive constant integral reals
         sdts.push_back(SygusDatatypeGenerator(posIRealName));
@@ -1117,7 +1107,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
     std::stringstream ss;
     ss << fun << "_AnyConst";
     // Make sygus datatype for any constant.
-    TypeNode unresAnyConst = mkUnresolvedType(ss.str(), unres);
+    TypeNode unresAnyConst = mkUnresolvedType(ss.str());
     unres_types.push_back(unresAnyConst);
     sdts.push_back(SygusDatatypeGenerator(ss.str()));
     sdts.back().d_sdt.addAnyConstantConstructor(types[i]);
@@ -1460,13 +1450,6 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
     for (unsigned i = 0; i < 4; i++)
     {
       Kind k = i == 0 ? NOT : (i == 1 ? AND : (i == 2 ? OR : ITE));
-      // TODO #1935 ITEs are added to Boolean grammars so that we can infer
-      // unification strategies. We can do away with this if we can infer
-      // unification strategies from and/or/not
-      if (k == ITE && options::sygusUnifPi() == options::SygusUnifPiMode::NONE)
-      {
-        continue;
-      }
       Trace("sygus-grammar-def") << "...add for " << k << std::endl;
       std::vector<TypeNode> cargs;
       cargs.push_back(unres_bt);
@@ -1498,6 +1481,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
 }
 
 TypeNode CegGrammarConstructor::mkSygusDefaultType(
+    const Options& opts,
     TypeNode range,
     Node bvl,
     const std::string& fun,
@@ -1506,6 +1490,7 @@ TypeNode CegGrammarConstructor::mkSygusDefaultType(
     std::map<TypeNode, std::unordered_set<Node>>& include_cons,
     std::unordered_set<Node>& term_irrelevant)
 {
+  NodeManager* nm = NodeManager::currentNM();
   Trace("sygus-grammar-def") << "*** Make sygus default type " << range << ", make datatypes..." << std::endl;
   for (std::map<TypeNode, std::unordered_set<Node>>::iterator it =
            extra_cons.begin();
@@ -1514,7 +1499,15 @@ TypeNode CegGrammarConstructor::mkSygusDefaultType(
   {
     Trace("sygus-grammar-def") << "    ...using " << it->second.size() << " extra constants for " << it->first << std::endl;
   }
-  std::set<TypeNode> unres;
+  // TODO #1935 ITEs are added to Boolean grammars so that we can infer
+  // unification strategies. We can do away with this if we can infer
+  // unification strategies from and/or/not
+  if (opts.quantifiers.sygusUnifPi == options::SygusUnifPiMode::NONE)
+  {
+    TypeNode btype = nm->booleanType();
+    exclude_cons[btype].insert(nm->operatorOf(ITE));
+    Trace("sygus-grammar-def") << "...exclude Boolean ITE" << std::endl;
+  }
   std::vector<SygusDatatypeGenerator> sdts;
   mkSygusDefaultGrammar(range,
                         bvl,
@@ -1524,7 +1517,7 @@ TypeNode CegGrammarConstructor::mkSygusDefaultType(
                         include_cons,
                         term_irrelevant,
                         sdts,
-                        unres);
+                        opts.quantifiers.sygusGrammarConsMode);
   // extract the datatypes from the sygus datatype generator objects
   std::vector<DType> datatypes;
   for (unsigned i = 0, ndts = sdts.size(); i < ndts; i++)
@@ -1533,8 +1526,7 @@ TypeNode CegGrammarConstructor::mkSygusDefaultType(
   }
   Trace("sygus-grammar-def")  << "...made " << datatypes.size() << " datatypes, now make mutual datatype types..." << std::endl;
   Assert(!datatypes.empty());
-  std::vector<TypeNode> types =
-      NodeManager::currentNM()->mkMutualDatatypeTypes(datatypes);
+  std::vector<TypeNode> types = nm->mkMutualDatatypeTypes(datatypes);
   Trace("sygus-grammar-def") << "...finished" << std::endl;
   Assert(types.size() == datatypes.size());
   return types[0];
@@ -1547,7 +1539,6 @@ TypeNode CegGrammarConstructor::mkSygusTemplateTypeRec( Node templ, Node templ_a
     return templ_arg_sygus_type;
   }else{
     tcount++;
-    std::set<TypeNode> unres;
     std::vector<SygusDatatype> sdts;
     std::stringstream ssd;
     ssd << fun << "_templ_" << tcount;
index 4d01ad866652c363391dd18a244b067d2c0bc651..7b9e5a700d90eacc48ae6ca9a7fbb8454b999e5a 100644 (file)
@@ -25,6 +25,7 @@
 #include "expr/attribute.h"
 #include "expr/node.h"
 #include "expr/sygus_datatype.h"
+#include "options/quantifiers_options.h"
 #include "smt/env_obj.h"
 
 namespace cvc5::internal {
@@ -109,6 +110,7 @@ public:
   *     will be included.
   */
  static TypeNode mkSygusDefaultType(
+     const Options& opts,
      TypeNode range,
      Node bvl,
      const std::string& fun,
@@ -120,7 +122,8 @@ public:
  /**
   * Make the default sygus datatype type corresponding to builtin type range.
   */
- static TypeNode mkSygusDefaultType(TypeNode range,
+ static TypeNode mkSygusDefaultType(const Options& opts,
+                                    TypeNode range,
                                     Node bvl,
                                     const std::string& fun)
  {
@@ -128,7 +131,8 @@ public:
    std::map<TypeNode, std::unordered_set<Node>> exclude_cons;
    std::map<TypeNode, std::unordered_set<Node>> include_cons;
    std::unordered_set<Node> term_irrelevant;
-   return mkSygusDefaultType(range,
+   return mkSygusDefaultType(opts,
+                             range,
                              bvl,
                              fun,
                              extra_cons,
@@ -220,15 +224,13 @@ public:
   };
 
   // helper for mkSygusDefaultGrammar (makes unresolved type for mutually recursive datatype construction)
-  static TypeNode mkUnresolvedType(const std::string& name,
-                                   std::set<TypeNode>& unres);
+  static TypeNode mkUnresolvedType(const std::string& name);
   // collect the list of types that depend on type range
   static void collectSygusGrammarTypesFor(TypeNode range,
                                           std::vector<TypeNode>& types);
   /** helper function for function mkSygusDefaultType
   * Collects a set of mutually recursive datatypes "datatypes" corresponding to
   * encoding type "range" to SyGuS.
-  *   unres is used for the resulting call to mkMutualDatatypeTypes
   */
   static void mkSygusDefaultGrammar(
       TypeNode range,
@@ -239,7 +241,7 @@ public:
       const std::map<TypeNode, std::unordered_set<Node>>& include_cons,
       std::unordered_set<Node>& term_irrelevant,
       std::vector<SygusDatatypeGenerator>& sdts,
-      std::set<TypeNode>& unres);
+      options::SygusGrammarConsMode sgcm);
 
   // helper function for mkSygusTemplateType
   static TypeNode mkSygusTemplateTypeRec(Node templ,
index 7230e0ce6507777551e0f72efc073d52c448eccd..df6b237b639ddda59b84884b177a2af39d4b548c 100644 (file)
@@ -192,6 +192,7 @@ TypeNode SygusInterpol::setSynthGrammar(const TypeNode& itpGType,
     getIncludeCons(axioms, conj, include_cons);
     std::unordered_set<Node> terms_irrelevant;
     itpGTypeS = CegGrammarConstructor::mkSygusDefaultType(
+        options(),
         NodeManager::currentNM()->booleanType(),
         d_ibvlShared,
         "interpolation_grammar",
index 8bc1e5a96a7790e03fc960df05c7f06e0fd22029..827e0e360b6271ad6758a15e5673bc676892c962 100644 (file)
@@ -361,7 +361,11 @@ Node SygusUnifRl::constructSol(
     return d_parent->getModelValue(e);
   }
   EnumTypeInfoStrat* etis = snode.d_strats[itd->second.getStrategyIndex()];
-  Node sol = itd->second.buildSol(etis->d_cons, lemmas);
+  Node sol =
+      itd->second.buildSol(etis->d_cons,
+                           lemmas,
+                           options().quantifiers.sygusUnifShuffleCond,
+                           options().quantifiers.sygusUnifCondIndNoRepeatSol);
   Assert(d_useCondPool || !sol.isNull() || !lemmas.empty());
   return sol;
 }
@@ -558,7 +562,9 @@ unsigned SygusUnifRl::DecisionTreeInfo::getStrategyIndex() const
 }
 
 Node SygusUnifRl::DecisionTreeInfo::buildSol(Node cons,
-                                             std::vector<Node>& lemmas)
+                                             std::vector<Node>& lemmas,
+                                             bool shuffleCond,
+                                             bool condIndNoRepeatSol)
 {
   if (!d_template.first.isNull())
   {
@@ -570,12 +576,15 @@ Node SygusUnifRl::DecisionTreeInfo::buildSol(Node cons,
                           << " conditions..." << std::endl;
   // reset the trie
   d_pt_sep.d_trie.clear();
-  return d_unif->usingConditionPool() ? buildSolAllCond(cons, lemmas)
-                                      : buildSolMinCond(cons, lemmas);
+  return d_unif->usingConditionPool()
+             ? buildSolAllCond(cons, lemmas, shuffleCond, condIndNoRepeatSol)
+             : buildSolMinCond(cons, lemmas);
 }
 
 Node SygusUnifRl::DecisionTreeInfo::buildSolAllCond(Node cons,
-                                                    std::vector<Node>& lemmas)
+                                                    std::vector<Node>& lemmas,
+                                                    bool shuffleCond,
+                                                    bool condIndNoRepeatSol)
 {
   // model values for evaluation heads
   std::map<Node, Node> hd_mv;
@@ -589,7 +598,7 @@ Node SygusUnifRl::DecisionTreeInfo::buildSolAllCond(Node cons,
   // bigger, or have no impact) and which conditions will be present in the DT,
   // which influences the "quality" of the solution for cases not covered in the
   // current data points
-  if (options::sygusUnifShuffleCond())
+  if (shuffleCond)
   {
     std::shuffle(d_conds.begin(), d_conds.end(), Random::getRandom());
   }
@@ -624,8 +633,7 @@ Node SygusUnifRl::DecisionTreeInfo::buildSolAllCond(Node cons,
   Trace("sygus-unif-sol") << "...ready to build solution from DT\n";
   Node sol = extractSol(cons, hd_mv);
   // repeated solution
-  if (options::sygusUnifCondIndNoRepeatSol()
-      && d_sols.find(sol) != d_sols.end())
+  if (condIndNoRepeatSol && d_sols.find(sol) != d_sols.end())
   {
     return Node::null();
   }
index e99ec31188c6e26f8d3684a7d22f314e594a5c84..f6655438c1d556fbec2880ba5dff46a8554a98c1 100644 (file)
@@ -224,9 +224,15 @@ class SygusUnifRl : public SygusUnif
      * A solution is possible when all different valued heads can be separated,
      * i.e. the current set of conditions separates them in a decision tree
      */
-    Node buildSol(Node cons, std::vector<Node>& lemmas);
+    Node buildSol(Node cons,
+                  std::vector<Node>& lemmas,
+                  bool shuffleCond,
+                  bool condIndNoRepeatSol);
     /** bulids a solution by considering all condition values ever enumerated */
-    Node buildSolAllCond(Node cons, std::vector<Node>& lemmas);
+    Node buildSolAllCond(Node cons,
+                         std::vector<Node>& lemmas,
+                         bool shuffleCond,
+                         bool condIndNoRepeatSol);
     /** builds a solution by incrementally adding points and conditions to DT
      *
      * Differently from the above method, here a condition is only added to the
index a5f88dc37c1e50e28397cd3421ec6a4e25cd2599..938c5e84875e2e8038ae611de4205e90a048072c 100644 (file)
@@ -446,7 +446,8 @@ void SygusInst::registerQuantifier(Node q)
   for (const Node& var : q[0])
   {
     addSpecialValues(var.getType(), extra_cons);
-    TypeNode tn = CegGrammarConstructor::mkSygusDefaultType(var.getType(),
+    TypeNode tn = CegGrammarConstructor::mkSygusDefaultType(options(),
+                                                            var.getType(),
                                                             Node(),
                                                             var.toString(),
                                                             extra_cons,