Fix bag.map upwards inferences (#8232)
authormudathirmahgoub <mudathirmahgoub@gmail.com>
Fri, 4 Mar 2022 23:33:47 +0000 (17:33 -0600)
committerGitHub <noreply@github.com>
Fri, 4 Mar 2022 23:33:47 +0000 (23:33 +0000)
src/expr/skolem_manager.cpp
src/expr/skolem_manager.h
src/theory/bags/bag_solver.cpp
src/theory/bags/bag_solver.h
src/theory/bags/infer_info.cpp
src/theory/bags/inference_generator.cpp
src/theory/bags/inference_generator.h
src/theory/bags/solver_state.cpp
src/theory/inference_id.cpp
src/theory/inference_id.h

index 4bda69bcbca3d1d76c6ce2c19207c80f81a5653f..ba1f0b0ea00d3a354f3c3490e306fea5c691a62d 100644 (file)
@@ -86,6 +86,7 @@ const char* toString(SkolemFunId id)
     case SkolemFunId::BAGS_FOLD_ELEMENTS: return "BAGS_FOLD_ELEMENTS";
     case SkolemFunId::BAGS_FOLD_UNION_DISJOINT: return "BAGS_FOLD_UNION_DISJOINT";
     case SkolemFunId::BAGS_MAP_PREIMAGE: return "BAGS_MAP_PREIMAGE";
+    case SkolemFunId::BAGS_MAP_PREIMAGE_INDEX: return "BAGS_MAP_PREIMAGE_INDEX";
     case SkolemFunId::BAGS_MAP_SUM: return "BAGS_MAP_SUM";
     case SkolemFunId::HO_TYPE_MATCH_PRED: return "HO_TYPE_MATCH_PRED";
     default: return "?";
index 2c696d23f5d5821dd4c3064a90059d093b01d674..733fbabdcff86b716a7d488afd008651e4976401 100644 (file)
@@ -147,6 +147,12 @@ enum class SkolemFunId
    * where uf: Int -> E is a skolem function, and E is the type of elements of A
    */
   BAGS_MAP_PREIMAGE,
+  /**
+   * A skolem variable for the index that is unique per terms
+   * (map f A), y, preImageSize, y, e which might be an element in A.
+   * (see the documentation for BAGS_MAP_PREIMAGE)
+   */
+  BAGS_MAP_PREIMAGE_INDEX,
   /** An uninterpreted function for bag.map operator:
    * If the preimage of {y} in A is {uf(1), ..., uf(n)} (see BAGS_MAP_PREIMAGE},
    * then the multiplicity of an element y in a bag (map f A) is sum(n),
index dbd2bbc2911ce26196bbc3aefe5ca7e39bdea55c..219e3187db9c370b7cfd3865f294e12bd8fa0cbc 100644 (file)
@@ -261,24 +261,31 @@ void BagSolver::checkMap(Node n)
   for (const Node& z : downwards)
   {
     Node y = d_state.getRepresentative(z);
-    if (d_mapCache.count(n) && d_mapCache[n].get()->contains(y))
+    if (!d_mapCache.count(n))
     {
-      continue;
+      std::shared_ptr<context::CDHashMap<Node, std::pair<Node, Node>>> nMap =
+          std::make_shared<context::CDHashMap<Node, std::pair<Node, Node>>>(
+              userContext());
+      d_mapCache[n] = nMap;
     }
-    auto [downInference, uf, preImageSize] = d_ig.mapDownwards(n, y);
-    d_im.lemmaTheoryInference(&downInference);
-    for (const Node& x : upwards)
+    if (!d_mapCache[n].get()->count(y))
     {
-      InferInfo upInference = d_ig.mapUpwards(n, uf, preImageSize, y, x);
-      d_im.lemmaTheoryInference(&upInference);
+      auto [downInference, uf, preImageSize] = d_ig.mapDown(n, y);
+      d_im.lemmaTheoryInference(&downInference);
+      std::pair<Node, Node> yPair = std::make_pair(uf, preImageSize);
+      d_mapCache[n].get()->insert(y, yPair);
     }
-    if (!d_mapCache.count(n))
+
+    context::CDHashMap<Node, std::pair<Node, Node>>::iterator it =
+        d_mapCache[n].get()->find(y);
+
+    auto [uf, preImageSize] = it->second;
+
+    for (const Node& x : upwards)
     {
-      std::shared_ptr<context::CDHashSet<Node> > set =
-          std::make_shared<context::CDHashSet<Node> >(userContext());
-      d_mapCache.insert(n, set);
+      InferInfo upInference = d_ig.mapUp(n, uf, preImageSize, y, x);
+      d_im.lemmaTheoryInference(&upInference);
     }
-    d_mapCache[n].get()->insert(y);
   }
 }
 
index eb578aafd7b527f7f06b0975cd355a1634b3914f..e5dba3896aacb22b25e700f619463d0127e7b61e 100644 (file)
@@ -110,11 +110,19 @@ class BagSolver : protected EnvObj
   /** Reference to the term registry of theory of bags */
   TermRegistry& d_termReg;
 
-  /** a cache that stores bags of kind BAG_MAP and those element representatives
-   * which we generated their inferences.
+  /**
+   * a map where the keys are nodes of the form (bag.map f A)
+   * where f is a function (-> E T), A a bag of type (Bag E),
+   * and values are maps where keys are elements y's of (bag.map f A)
+   * and values are pairs <uf, preImageSize> such that
+   * uf is an uninterpreted function Int -> E represents the and
+   * preImageSize is the cardinality of the distinct elements in A that are
+   * mapped to each y
+   *
    */
-  using BagElementsMap =
-      context::CDHashMap<Node, std::shared_ptr<context::CDHashSet<Node> > >;
+  using BagElementsMap = context::CDHashMap<
+      Node,
+      std::shared_ptr<context::CDHashMap<Node, std::pair<Node, Node> > > >;
   BagElementsMap d_mapCache;
 
   /** Commonly used constants */
index 9080f29e9df385ec846c44e237be3a68b8e3fa02..187cbff99992f5c7cd7255e4e5754fd2e09db4aa 100644 (file)
@@ -67,13 +67,13 @@ bool InferInfo::isFact() const
 
 std::ostream& operator<<(std::ostream& out, const InferInfo& ii)
 {
-  out << "(infer :id " << ii.getId() << std::endl;
-  out << ":conclusion " << ii.d_conclusion << std::endl;
+  out << "(infer ;id " << std::endl << ii.getId() << std::endl;
+  out << ";conclusion " << std::endl << ii.d_conclusion << std::endl;
   if (!ii.d_premises.empty())
   {
-    out << " :premise (" << ii.d_premises << ")" << std::endl;
+    out << " ;premise" << std::endl << ii.d_premises << std::endl;
   }
-  out << ":skolems " << ii.d_skolems << std::endl;
+  out << ";skolems " << ii.d_skolems << std::endl;
   out << ")";
   return out;
 }
index aa5bf74d8cccefd984b6353b5d32f5dbf550d11e..b87296f32fdf5a3f4b2a9700bedbd8d1c732f22a 100644 (file)
@@ -393,15 +393,14 @@ Node InferenceGenerator::getMultiplicityTerm(Node element, Node bag)
   return count;
 }
 
-std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDownwards(Node n,
-                                                                   Node e)
+std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDown(Node n, Node e)
 {
   Assert(n.getKind() == BAG_MAP && n[1].getType().isBag());
   Assert(n[0].getType().isFunction()
          && n[0].getType().getArgTypes().size() == 1);
   Assert(e.getType() == n[0].getType().getRangeType());
 
-  InferInfo inferInfo(d_im, InferenceId::BAGS_MAP);
+  InferInfo inferInfo(d_im, InferenceId::BAGS_MAP_DOWN);
 
   Node f = n[0];
   Node A = n[1];
@@ -488,19 +487,19 @@ std::tuple<InferInfo, Node, Node> InferenceGenerator::mapDownwards(Node n,
 
   std::map<Node, Node> m;
   m[e] = conclusion;
-  Trace("bags::InferenceGenerator::mapDownwards")
+  Trace("bags::InferenceGenerator::mapDown")
       << "conclusion: " << inferInfo.d_conclusion << std::endl;
   return std::tuple(inferInfo, uf, preImageSize);
 }
 
-InferInfo InferenceGenerator::mapUpwards(
+InferInfo InferenceGenerator::mapUp(
     Node n, Node uf, Node preImageSize, Node y, Node x)
 {
   Assert(n.getKind() == BAG_MAP && n[1].getType().isBag());
   Assert(n[0].getType().isFunction()
          && n[0].getType().getArgTypes().size() == 1);
 
-  InferInfo inferInfo(d_im, InferenceId::BAGS_MAP);
+  InferInfo inferInfo(d_im, InferenceId::BAGS_MAP_UP);
   Node f = n[0];
   Node A = n[1];
 
@@ -508,7 +507,9 @@ InferInfo InferenceGenerator::mapUpwards(
   Node xInA = d_nm->mkNode(GEQ, countA, d_one);
   Node notEqual = d_nm->mkNode(EQUAL, d_nm->mkNode(APPLY_UF, f, x), y).negate();
 
-  Node k = d_sm->mkDummySkolem("k", d_nm->integerType());
+  Node k = d_sm->mkSkolemFunction(SkolemFunId::BAGS_MAP_PREIMAGE_INDEX,
+                                  d_nm->integerType(),
+                                  {n, uf, preImageSize, y, x});
   Node inRange = d_nm->mkNode(
       AND, d_nm->mkNode(GEQ, k, d_one), d_nm->mkNode(LEQ, k, preImageSize));
   Node equal = d_nm->mkNode(EQUAL, d_nm->mkNode(APPLY_UF, uf, k), x);
index ed6122356fa7f4d77e9066e3ffe7cae499113df0..ed6f856e2bd1a033a2f7fec58ade74a053f671fe 100644 (file)
@@ -239,7 +239,7 @@ class InferenceGenerator
    * preimage of e,
    * and skolem is a fresh variable equals (bag.map f A))
    */
-  std::tuple<InferInfo, Node, Node> mapDownwards(Node n, Node e);
+  std::tuple<InferInfo, Node, Node> mapDown(Node n, Node e);
 
   /**
    * @param n is (bag.map f A) where f is a function (-> E T), A a bag of type
@@ -251,7 +251,7 @@ class InferenceGenerator
    * @param e is an element of type E
    * @return an inference that represents the following implication
    * (=>
-   *   (>= (bag.count x A) 1)
+   *   (bag.member x A)
    *   (or
    *     (not (= (f x) y)
    *     (and
@@ -260,7 +260,7 @@ class InferenceGenerator
    *       (= (uf skolem) x)))))
    * where skolem is a fresh variable
    */
-  InferInfo mapUpwards(Node n, Node uf, Node preImageSize, Node y, Node x);
+  InferInfo mapUp(Node n, Node uf, Node preImageSize, Node y, Node x);
 
   /**
    * @param n is (bag.filter p A) where p is a function (-> E Bool),
index 575dcf577bceee39eecb4108d93f190f098d3480..604c05cb4d584496d352cc167866e50c9f507500 100644 (file)
@@ -135,7 +135,7 @@ std::vector<Node> SolverState::collectBagsAndCountTerms()
   while (!repIt.isFinished())
   {
     Node eqc = (*repIt);
-    Trace("bags-eqc") << "Eqc [ " << eqc << " ] = { ";
+    Trace("bags-eqc") << "(eqc " << eqc << std::endl << "";
 
     if (eqc.getType().isBag())
     {
@@ -173,11 +173,11 @@ std::vector<Node> SolverState::collectBagsAndCountTerms()
       }
       ++it;
     }
-    Trace("bags-eqc") << " } " << std::endl;
+    Trace("bags-eqc") << std::endl << " ) " << std::endl;
     ++repIt;
   }
 
-  Trace("bags-eqc") << "bag representatives: " << d_bags << endl;
+  Trace("bags-eqc") << "(bagRepresentatives " << d_bags << ")" << std::endl;
   return lemmas;
 }
 
@@ -189,7 +189,7 @@ void SolverState::collectDisequalBagTerms()
     Node n = (*it);
     if (n.getKind() == EQUAL && n[0].getType().isBag())
     {
-      Trace("bags-eqc") << "Disequal terms: " << n << std::endl;
+      Trace("bags-eqc") << "(disequalTerms " << n << " )" << std::endl;
       d_deq.insert(n);
     }
     ++it;
index b5980d781a6da6956f1af42107bc25ad35cf6e5c..20d758b2147a094d0fe2817495691c7a5ac57421 100644 (file)
@@ -129,7 +129,8 @@ const char* toString(InferenceId i)
       return "BAGS_DIFFERENCE_SUBTRACT";
     case InferenceId::BAGS_DIFFERENCE_REMOVE: return "BAGS_DIFFERENCE_REMOVE";
     case InferenceId::BAGS_DUPLICATE_REMOVAL: return "BAGS_DUPLICATE_REMOVAL";
-    case InferenceId::BAGS_MAP: return "BAGS_MAP";
+    case InferenceId::BAGS_MAP_DOWN: return "BAGS_MAP_DOWN";
+    case InferenceId::BAGS_MAP_UP: return "BAGS_MAP_UP";
     case InferenceId::BAGS_FILTER_DOWN: return "BAGS_FILTER_DOWN";
     case InferenceId::BAGS_FILTER_UP: return "BAGS_FILTER_UP";
     case InferenceId::BAGS_FOLD: return "BAGS_FOLD";
index 4734e0d607336d196573ea4f4e278cd1f82b7e57..f5699540c2b85db273156485d8a052f4c7668f44 100644 (file)
@@ -195,7 +195,8 @@ enum class InferenceId
   BAGS_DIFFERENCE_SUBTRACT,
   BAGS_DIFFERENCE_REMOVE,
   BAGS_DUPLICATE_REMOVAL,
-  BAGS_MAP,
+  BAGS_MAP_DOWN,
+  BAGS_MAP_UP,
   BAGS_FILTER_DOWN,
   BAGS_FILTER_UP,
   BAGS_FOLD,