Apply sygus repair constant techniques restricted to refinement lemmas (#3386)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Mon, 14 Oct 2019 19:23:38 +0000 (14:23 -0500)
committerGitHub <noreply@github.com>
Mon, 14 Oct 2019 19:23:38 +0000 (14:23 -0500)
src/smt/smt_engine.cpp
src/theory/quantifiers/sygus/cegis.cpp
src/theory/quantifiers/sygus/cegis.h
src/theory/quantifiers/sygus/sygus_repair_const.cpp
src/theory/quantifiers/sygus/sygus_repair_const.h
test/regress/CMakeLists.txt
test/regress/regress1/sygus/coeff-solve-inv.sy [new file with mode: 0644]
test/regress/regress1/sygus/repair-const-rl.sy [new file with mode: 0644]

index 62b4dc121e2f4c334761d42a4327c6e462c75039..29c3f9092779e614be2520b576ead5e482cfa8b6 100644 (file)
@@ -510,8 +510,6 @@ class SmtEnginePrivate : public NodeManagerListener {
    * universally quantified in the constraints.
    */
   std::vector<Node> d_sygusVars;
-  /** types of sygus primed variables (for debugging) */
-  std::vector<Type> d_sygusPrimedVarTypes;
   /** sygus constraints */
   std::vector<Node> d_sygusConstraints;
   /** functions-to-synthesize */
@@ -3925,9 +3923,7 @@ void SmtEngine::declareSygusVar(const std::string& id, Expr var, Type type)
 
 void SmtEngine::declareSygusPrimedVar(const std::string& id, Type type)
 {
-#ifdef CVC4_ASSERTIONS
-  d_private->d_sygusPrimedVarTypes.push_back(type);
-#endif
+  // do nothing (the command is spurious)
   Trace("smt") << "SmtEngine::declareSygusPrimedVar: " << id << "\n";
   // don't need to set that the conjecture is stale
 }
@@ -4010,27 +4006,6 @@ void SmtEngine::assertSygusInvConstraint(const Expr& inv,
     ss << vars.back() << "'";
     primed_vars.push_back(d_nodeManager->mkBoundVar(ss.str(), tn));
     d_private->d_sygusVars.push_back(primed_vars.back());
-#ifdef CVC4_ASSERTIONS
-    bool find_new_declared_var = false;
-    for (const Type& t : d_private->d_sygusPrimedVarTypes)
-    {
-      if (t == ti)
-      {
-        d_private->d_sygusPrimedVarTypes.erase(
-            std::find(d_private->d_sygusPrimedVarTypes.begin(),
-                      d_private->d_sygusPrimedVarTypes.end(),
-                      t));
-        find_new_declared_var = true;
-        break;
-      }
-    }
-    if (!find_new_declared_var)
-    {
-      Warning()
-          << "warning: declared primed variables do not match invariant's "
-             "type\n";
-    }
-#endif
   }
 
   // make relevant terms; 0 -> Inv, 1 -> Pre, 2 -> Trans, 3 -> Post
index 96f3478908328b1a2dd40378a7f5ca22e9f0524b..3a1ddc73ce7714ad70ee9182238abae8e79516a6 100644 (file)
@@ -198,6 +198,30 @@ bool Cegis::addEvalLemmas(const std::vector<Node>& candidates,
   return addedEvalLemmas;
 }
 
+Node Cegis::getRefinementLemmaFormula()
+{
+  std::vector<Node> conj;
+  conj.insert(
+      conj.end(), d_refinement_lemmas.begin(), d_refinement_lemmas.end());
+  // get the propagated values
+  for (unsigned i = 0, nprops = d_rl_eval_hds.size(); i < nprops; i++)
+  {
+    conj.push_back(d_rl_eval_hds[i].eqNode(d_rl_vals[i]));
+  }
+  // make the formula
+  NodeManager* nm = NodeManager::currentNM();
+  Node ret;
+  if (conj.empty())
+  {
+    ret = nm->mkConst(true);
+  }
+  else
+  {
+    ret = conj.size() == 1 ? conj[0] : nm->mkNode(AND, conj);
+  }
+  return ret;
+}
+
 bool Cegis::constructCandidates(const std::vector<Node>& enums,
                                 const std::vector<Node>& enum_values,
                                 const std::vector<Node>& candidates,
@@ -235,11 +259,18 @@ bool Cegis::constructCandidates(const std::vector<Node>& enums,
     {
       std::vector<Node> fail_cvs = enum_values;
       Assert(candidates.size() == fail_cvs.size());
+      // try to solve entire problem?
       if (src->repairSolution(candidates, fail_cvs, candidate_values))
       {
         return true;
       }
-      // repair solution didn't work, exclude this solution
+      Node rl = getRefinementLemmaFormula();
+      // try to solve for the refinement lemmas only
+      bool ret =
+          src->repairSolution(rl, candidates, fail_cvs, candidate_values);
+      // Even if ret is true, we will exclude the skeleton as well; this means
+      // that we have one chance to repair each skeleton. It is possible however
+      // that we might want to repair the same skeleton multiple times.
       std::vector<Node> exp;
       for (unsigned i = 0, size = enums.size(); i < size; i++)
       {
@@ -252,7 +283,7 @@ bool Cegis::constructCandidates(const std::vector<Node>& enums,
       // must guard it
       expn = nm->mkNode(OR, d_parent->getGuard().negate(), expn.negate());
       lems.push_back(expn);
-      return false;
+      return ret;
     }
   }
 
index 8913799926cd623313de9e75222a0f52a7896715..08cf98c993e9bdb1b0a155394cd8434ba1190c71 100644 (file)
@@ -168,6 +168,8 @@ class Cegis : public SygusModule
   bool addEvalLemmas(const std::vector<Node>& candidates,
                      const std::vector<Node>& candidate_values,
                      std::vector<Node>& lems);
+  /** Get the node corresponding to the conjunction of all refinement lemmas. */
+  Node getRefinementLemmaFormula();
   //-----------------------------------end refinement lemmas
 
   /** Get refinement evaluation lemmas
index 4c5baa4bb257e21921721b4823fc06d78b42f31f..39506b59349d5991a85abfd73d56d3cb57f84465 100644 (file)
@@ -148,6 +148,19 @@ bool SygusRepairConst::repairSolution(const std::vector<Node>& candidates,
                                       const std::vector<Node>& candidate_values,
                                       std::vector<Node>& repair_cv,
                                       bool useConstantsAsHoles)
+{
+  return repairSolution(d_base_inst,
+                        candidates,
+                        candidate_values,
+                        repair_cv,
+                        useConstantsAsHoles);
+}
+
+bool SygusRepairConst::repairSolution(Node sygusBody,
+                                      const std::vector<Node>& candidates,
+                                      const std::vector<Node>& candidate_values,
+                                      std::vector<Node>& repair_cv,
+                                      bool useConstantsAsHoles)
 {
   Assert(candidates.size() == candidate_values.size());
 
@@ -209,7 +222,8 @@ bool SygusRepairConst::repairSolution(const std::vector<Node>& candidates,
 
   NodeManager* nm = NodeManager::currentNM();
   Trace("sygus-repair-const") << "Get first-order query..." << std::endl;
-  Node fo_body = getFoQuery(candidates, candidate_skeletons, sk_vars);
+  Node fo_body =
+      getFoQuery(sygusBody, candidates, candidate_skeletons, sk_vars);
 
   Trace("sygus-repair-const-debug") << "...got : " << fo_body << std::endl;
 
@@ -225,7 +239,8 @@ bool SygusRepairConst::repairSolution(const std::vector<Node>& candidates,
   LogicInfo logic = smt::currentSmtEngine()->getLogicInfo();
   if (logic.isTheoryEnabled(THEORY_ARITH) && logic.isLinear())
   {
-    fo_body = fitToLogic(logic,
+    fo_body = fitToLogic(sygusBody,
+                         logic,
                          fo_body,
                          candidates,
                          candidate_skeletons,
@@ -460,12 +475,12 @@ Node SygusRepairConst::getSkeleton(Node n,
   return visited[n];
 }
 
-Node SygusRepairConst::getFoQuery(const std::vector<Node>& candidates,
+Node SygusRepairConst::getFoQuery(Node body,
+                                  const std::vector<Node>& candidates,
                                   const std::vector<Node>& candidate_skeletons,
                                   const std::vector<Node>& sk_vars)
 {
   NodeManager* nm = NodeManager::currentNM();
-  Node body = d_base_inst;
   Trace("sygus-repair-const") << "  Substitute skeletons..." << std::endl;
   body = body.substitute(candidates.begin(),
                          candidates.end(),
@@ -558,7 +573,8 @@ Node SygusRepairConst::getFoQuery(const std::vector<Node>& candidates,
   return fo_body;
 }
 
-Node SygusRepairConst::fitToLogic(LogicInfo& logic,
+Node SygusRepairConst::fitToLogic(Node body,
+                                  LogicInfo& logic,
                                   Node n,
                                   const std::vector<Node>& candidates,
                                   std::vector<Node>& candidate_skeletons,
@@ -590,7 +606,7 @@ Node SygusRepairConst::fitToLogic(LogicInfo& logic,
     Assert(it != sk_vars.end());
     sk_vars.erase(it);
     // reconstruct the query
-    n = getFoQuery(candidates, candidate_skeletons, sk_vars);
+    n = getFoQuery(body, candidates, candidate_skeletons, sk_vars);
     // reset the exclusion variable
     exc_var = Node::null();
   }
index 26b7234a9602af3986485037096fba8995b77db3..6be5ce5e6d762d2e5cb88f3dbc4bf9fcc129fe7a 100644 (file)
@@ -53,9 +53,9 @@ class SygusRepairConst
   ~SygusRepairConst() {}
   /** initialize
    *
-   * Initialize this class with the base instantiation of the sygus conjecture
-   * (see CegConjecture::d_base_inst) and its candidate variables (see
-   * CegConjecture::d_candidates).
+   * Initialize this class with the base instantiation (body) of the sygus
+   * conjecture (see SynthConjecture::d_base_inst) and its candidate variables
+   * (see SynthConjecture::d_candidates).
    */
   void initialize(Node base_inst, const std::vector<Node>& candidates);
   /** repair solution
@@ -75,6 +75,17 @@ class SygusRepairConst
    * candidate_values to be repairable. In addition, if the flag
    * useConstantsAsHoles is true, we consider all constants whose (sygus) type
    * admit alls constants to be repairable.
+   * The repaired solution has the property that it satisfies the synthesis
+   * conjecture whose body is given by sygusBody.
+   */
+  bool repairSolution(Node sygusBody,
+                      const std::vector<Node>& candidates,
+                      const std::vector<Node>& candidate_values,
+                      std::vector<Node>& repair_cv,
+                      bool useConstantsAsHoles = false);
+  /**
+   * Same as above, but where sygusBody is the body (base_inst) provided to the
+   * call to initialize of this class.
    */
   bool repairSolution(const std::vector<Node>& candidates,
                       const std::vector<Node>& candidate_values,
@@ -148,12 +159,14 @@ class SygusRepairConst
   /** get first-order query
    *
    * This function returns a formula that is equivalent to the negation of the
-   * synthesis conjecture, where candidates are replaced by candidate_skeletons,
+   * synthesis conjecture whose body is given in the first argument, where
+   * candidates are replaced by candidate_skeletons,
    * whose free variables are in the set sk_vars. The returned formula
    * is a first-order (quantified) formula in the background logic, without UF,
    * of the form [***] above.
    */
-  Node getFoQuery(const std::vector<Node>& candidates,
+  Node getFoQuery(Node body,
+                  const std::vector<Node>& candidates,
                   const std::vector<Node>& candidate_skeletons,
                   const std::vector<Node>& sk_vars);
   /** fit to logic
@@ -164,6 +177,9 @@ class SygusRepairConst
    * not enabled, we must undo some of the variables we introduced when
    * inferring candidate skeletons.
    *
+   * body is the (sygus) form of the original synthesis conjecture we are
+   * considering in this call.
+   *
    * This function may remove variables from sk_vars and the map
    * sk_vars_to_subs. The skeletons candidate_skeletons are obtained by
    * getSkeleton(...) on the resulting vectors. If this function returns a
@@ -174,7 +190,8 @@ class SygusRepairConst
    * It uses the function below to choose which variables to remove from
    * sk_vars.
    */
-  Node fitToLogic(LogicInfo& logic,
+  Node fitToLogic(Node body,
+                  LogicInfo& logic,
                   Node n,
                   const std::vector<Node>& candidates,
                   std::vector<Node>& candidate_skeletons,
index cbe5f2e35dbf71937d9bf6ec3f3f5f78bda28d77..8dba70f91bb91f8cab7324fa2e6e84b8998bf603 100644 (file)
@@ -1669,6 +1669,7 @@ set(regress_1_tests
   regress1/sygus/cegisunif-depth1.sy
   regress1/sygus/cggmp.sy
   regress1/sygus/clock-inc-tuple.sy
+  regress1/sygus/coeff-solve-inv.sy
   regress1/sygus/commutative-stream.sy
   regress1/sygus/commutative.sy
   regress1/sygus/concat_extract_example.sy
@@ -1726,6 +1727,7 @@ set(regress_1_tests
   regress1/sygus/qe.sy
   regress1/sygus/qf_abv.smt2
   regress1/sygus/real-grammar.sy
+  regress1/sygus/repair-const-rl.sy
   regress1/sygus/repair-const-unk.sy
   regress1/sygus/simple-regexp.sy
   regress1/sygus/stopwatch-bt.sy
diff --git a/test/regress/regress1/sygus/coeff-solve-inv.sy b/test/regress/regress1/sygus/coeff-solve-inv.sy
new file mode 100644 (file)
index 0000000..edfcd60
--- /dev/null
@@ -0,0 +1,29 @@
+; EXPECT: unsat
+; COMMAND-LINE: --sygus-out=status --sygus-repair-const --lang=sygus2
+(set-logic LIA)
+
+(synth-inv inv-f ((x Int) (y Int)) )
+
+
+(define-fun pre-f ((x Int) (y Int)) Bool
+  (and 
+    (= x 0)
+    (= y 100)
+  )
+)
+
+(define-fun trans-f ((x Int) (y Int) (x! Int) (y! Int)) Bool
+  (and
+    (< x 100)
+    (= x! (+ x 1))
+    (= y! (+ y 1))
+  )
+)
+
+(define-fun post-f ((x Int) (y Int)) Bool 
+  (=> (>= x 100) (>= y 200))
+)
+
+(inv-constraint inv-f pre-f trans-f post-f)
+
+(check-synth)
diff --git a/test/regress/regress1/sygus/repair-const-rl.sy b/test/regress/regress1/sygus/repair-const-rl.sy
new file mode 100644 (file)
index 0000000..6477de3
--- /dev/null
@@ -0,0 +1,24 @@
+; EXPECT: unsat
+; COMMAND-LINE: --sygus-out=status --cegqi-si=none --sygus-repair-const --lang=sygus2
+(set-logic LIA)
+
+(synth-fun f ((x Int) (y Int)) Int
+  ((Start Int) (CInt Int))
+  (
+    (Start Int ((+ (* CInt x) (* CInt y) CInt)))
+    (CInt Int ((Constant Int)))
+  )
+)
+
+(declare-var x Int)
+(declare-var y Int)
+
+(constraint (= (f 0 0) 100))
+
+(constraint (= (f 1 1) 110))
+
+(constraint (= (f 2 1) 117))
+
+(constraint (>= (- (* 3 (f x y)) (f (* 2 x) (+ y 1))) (+ (* 7 x) (* 6 y))))
+
+(check-synth)