Enable sygusRecFun by default and fixes SyGuS+RecFun+HO issues (#3502)
authorHaniel Barbosa <hanielbbarbosa@gmail.com>
Wed, 27 Nov 2019 20:52:36 +0000 (17:52 -0300)
committerGitHub <noreply@github.com>
Wed, 27 Nov 2019 20:52:36 +0000 (17:52 -0300)
14 files changed:
src/options/quantifiers_options.toml
src/smt/smt_engine.cpp
src/theory/quantifiers/fun_def_evaluator.cpp
src/theory/quantifiers/sygus/synth_conjecture.cpp
src/theory/quantifiers/sygus/synth_engine.cpp
src/theory/quantifiers/sygus/term_database_sygus.cpp
src/theory/quantifiers_engine.cpp
test/regress/CMakeLists.txt
test/regress/regress1/sygus/list_recursor.sy
test/regress/regress1/sygus/rec-fun-swap.sy [new file with mode: 0644]
test/regress/regress1/sygus/rec-fun-sygus.sy
test/regress/regress1/sygus/rec-fun-while-1.sy
test/regress/regress1/sygus/rec-fun-while-2.sy
test/regress/regress1/sygus/rec-fun-while-infinite.sy

index b3c1ffd4d28dfcfed5bca83945a6ce94511b9c91..019b052bc13027c41ab191cfa0071e19c0bde19e 100644 (file)
@@ -1218,14 +1218,14 @@ header = "options/quantifiers_options.h"
   category   = "regular"
   long       = "sygus-rec-fun"
   type       = "bool"
-  default    = "false"
+  default    = "true"
   help       = "enable efficient support for recursive functions in sygus grammars"
 
 [[option]]
   name       = "sygusRecFunEvalLimit"
   category   = "regular"
   long       = "sygus-rec-fun-eval-limit=N"
-  type       = "int"
+  type       = "unsigned"
   default    = "1000"
   help       = "use a hard limit for how many times in a given evaluator call a recursive function can be evaluated (so infinite loops can be avoided)"
 
index 073c2ebc51586e8951e273f53d610ca4bf2ebfcd..dfd3c9fee7863c60bc3f399df0fb4b2980c6697c 100644 (file)
@@ -4861,6 +4861,7 @@ void SmtEngine::checkSynthSolution()
   SmtEngine solChecker(d_exprManager);
   solChecker.setLogic(getLogicInfo());
   setOption("check-synth-sol", SExpr("false"));
+  setOption("sygus-rec-fun", SExpr("false"));
 
   Trace("check-synth-sol") << "Retrieving assertions\n";
   // Build conjecture from original assertions
index ffac9b2c83740418cac4cfd29b506344d3c2c6bc..8eb0ef6866a57bc6c69a8e84b3d48db2cd021057 100644 (file)
@@ -118,7 +118,12 @@ Node FunDefEvaluator::evaluate(Node n) const
           it = visited.find(cur[0]);
           Assert(it != visited.end());
           Assert(!it->second.isNull());
-          Assert(it->second.isConst());
+          if (!it->second.isConst())
+          {
+            Trace("fd-eval") << "FunDefEvaluator: couldn't reduce condition of "
+                                "ITE to const, FAIL\n";
+            return Node::null();
+          }
           // pick child to evaluate depending on condition eval
           unsigned childIdxToEval = it->second.getConst<bool>() ? 1 : 2;
           Trace("fd-eval-debug2")
@@ -134,6 +139,7 @@ Node FunDefEvaluator::evaluate(Node n) const
                                   << cur[childIdxToEval] << "\n";
           continue;
         }
+        unsigned child CVC4_UNUSED = 0;
         for (const Node& cn : cur)
         {
           it = visited.find(cn);
@@ -141,6 +147,8 @@ Node FunDefEvaluator::evaluate(Node n) const
           Assert(!it->second.isNull());
           childChanged = childChanged || cn != it->second;
           children.push_back(it->second);
+          Trace("fd-eval-debug2") << "argument " << child++
+                                  << " eval : " << it->second << std::endl;
         }
         if (cur.getKind() == APPLY_UF)
         {
@@ -197,6 +205,8 @@ Node FunDefEvaluator::evaluate(Node n) const
           // evaluating the body.
           if (!sbody.isConst())
           {
+            Trace("fd-eval-debug2") << "FunDefEvaluator: will map " << cur
+                                    << " from body " << sbody << "\n";
             visit.push_back(cur);
             visit.push_back(sbody);
           }
@@ -208,32 +218,35 @@ Node FunDefEvaluator::evaluate(Node n) const
             ret = nm->mkNode(cur.getKind(), children);
             ret = Rewriter::rewrite(ret);
           }
+          Trace("fd-eval-debug2") << "built from arguments " << ret << "\n";
           visited[cur] = ret;
         }
       }
       else if (cur != curEval && !curEval.isConst())
       {
         Trace("fd-eval-debug") << "from body " << cur << std::endl;
+        Trace("fd-eval-debug") << "and eval  " << curEval << std::endl;
         // we had to evaluate our body, which should have a definition now
         it = visited.find(curEval);
-        Assert(it != visited.end());
-        // our definition is the result of the body
-        visited[cur] = it->second;
+        if (it == visited.end())
+        {
+          Trace("fd-eval-debug2") << "eval without definition\n";
+          // this is the case where curEval was not a constant but it was
+          // irreducible, for example (DT_SYGUS_EVAL e args)
+          visited[cur] = curEval;
+        }
+        else
+        {
+          Trace("fd-eval-debug2")
+              << "eval with definition " << it->second << "\n";
+          visited[cur] = it->second;
       }
     }
+    }
   } while (!visit.empty());
-  Trace("fd-eval") << "FunDefEvaluator: return " << visited[n];
+  Trace("fd-eval") << "FunDefEvaluator: return " << visited[n] << ", SUCCESS\n";
   Assert(visited.find(n) != visited.end());
   Assert(!visited.find(n)->second.isNull());
-  if (!visited.find(n)->second.isConst())
-  {
-    visited[n] = Node::null();
-    Trace("fd-eval") << "\n with NONCONST\n";
-  }
-  else
-  {
-    Trace("fd-eval") << "\n with SUCCESS\n";
-  }
   return visited[n];
 }
 
index 6591e6828cfd9e3785bda324db5e705a26e7d987..da427536567a15ad8c42a56a12aadc20b3bcff78 100644 (file)
@@ -712,7 +712,7 @@ void SynthConjecture::doRefine(std::vector<Node>& lems)
   base_lem = base_lem.substitute(
       sk_vars.begin(), sk_vars.end(), sk_subs.begin(), sk_subs.end());
   Trace("cegqi-refine") << "doRefine : rewrite..." << std::endl;
-  base_lem = Rewriter::rewrite(base_lem);
+  base_lem = d_tds->rewriteNode(base_lem);
   Trace("cegqi-refine") << "doRefine : register refinement lemma " << base_lem
                         << "..." << std::endl;
   d_master->registerRefinementLemma(sk_vars, base_lem, lems);
index cbe907d416478552e91db6a1b598869dad2d9bf2..4a708e66cc8f2b49d6a3143098e60d179cdb69b4 100644 (file)
@@ -276,28 +276,29 @@ void SynthEngine::registerQuantifier(Node q)
 {
   Trace("cegqi-debug") << "SynthEngine: Register quantifier : " << q
                        << std::endl;
-  if (d_quantEngine->getOwner(q) == this)
+  if (d_quantEngine->getOwner(q) != this)
   {
-    Trace("cegqi") << "Register conjecture : " << q << std::endl;
-    if (options::sygusQePreproc())
-    {
-      d_waiting_conj.push_back(q);
-    }
-    else
-    {
-      // assign it now
-      assignConjecture(q);
-    }
+    return;
   }
-  if (options::sygusRecFun())
+  if (d_quantEngine->getQuantAttributes()->isFunDef(q))
   {
-    if (d_quantEngine->getQuantAttributes()->isFunDef(q))
-    {
-      // If it is a recursive function definition, add it to the function
-      // definition evaluator class.
-      FunDefEvaluator* fde = d_tds->getFunDefEvaluator();
-      fde->assertDefinition(q);
-    }
+    Assert(options::sygusRecFun());
+    // If it is a recursive function definition, add it to the function
+    // definition evaluator class.
+    Trace("cegqi") << "Registering function definition : " << q << "\n";
+    FunDefEvaluator* fde = d_tds->getFunDefEvaluator();
+    fde->assertDefinition(q);
+    return;
+  }
+  Trace("cegqi") << "Register conjecture : " << q << std::endl;
+  if (options::sygusQePreproc())
+  {
+    d_waiting_conj.push_back(q);
+  }
+  else
+  {
+    // assign it now
+    assignConjecture(q);
   }
 }
 
index 679d47779ecba889263b240ef8695f4f2beed121..d664a462ddd70ae7eb5879e255e45e12b2f9456a 100644 (file)
@@ -741,9 +741,9 @@ Node TermDbSygus::rewriteNode(Node n) const
       {
         return fres;
       }
-      // It may have failed, in which case there are undefined symbols in res.
-      // In this case, we revert to the result of rewriting in the return
-      // statement below.
+      // It may have failed, in which case there are undefined symbols in res or
+      // we reached the limit of evaluations. In this case, we revert to the
+      // result of rewriting in the return statement below.
     }
   }
   return res;
@@ -1082,4 +1082,3 @@ bool TermDbSygus::isEvaluationPoint(Node n) const
 }/* CVC4::theory::quantifiers namespace */
 }/* CVC4::theory namespace */
 }/* CVC4 namespace */
-
index 8337ba0b072d09747e186261fa423efad97bb494..8730e3a971f4bf12bd575993f712ea8640f8018e 100644 (file)
@@ -407,14 +407,15 @@ void QuantifiersEngine::setOwner(Node q, quantifiers::QAttributes& qa)
     // set rewrite engine as owner
     setOwner(q, d_private->d_rr_engine.get(), 2);
   }
-  if (qa.d_sygus)
+  if (qa.d_sygus || (options::sygusRecFun() && !qa.d_fundef_f.isNull()))
   {
     if (d_private->d_synth_e.get() == nullptr)
     {
       Trace("quant-warn") << "WARNING : synth engine is null, and we have : "
                           << q << std::endl;
     }
-    // set synth engine as owner
+    // set synth engine as owner since this is either a conjecture or a function
+    // definition to be used by sygus
     setOwner(q, d_private->d_synth_e.get(), 2);
   }
 }
index fda31cfdb0a3cb6ae7491941ab9c33b929a5c881..2182beaa8d37ebb6a2ab195dfe36c48bf204dd89 100644 (file)
@@ -1744,6 +1744,7 @@ set(regress_1_tests
   regress1/sygus/qe.sy
   regress1/sygus/qf_abv.smt2
   regress1/sygus/real-grammar.sy
+  regress1/sygus/rec-fun-swap.sy
   regress1/sygus/rec-fun-sygus.sy
   regress1/sygus/rec-fun-while-1.sy
   regress1/sygus/rec-fun-while-2.sy
index 53c55397eaecb7dca88d407ad6842d2b9f14a5b6..2e10a0c71523f3508e190d88c23ac25d640957ae 100644 (file)
@@ -1,5 +1,5 @@
 ; EXPECT: unsat
-; COMMAND-LINE: --sygus-out=status --sygus-rec-fun --lang=sygus2 --uf-ho
+; COMMAND-LINE: --sygus-out=status --lang=sygus2 --uf-ho
 
 (set-logic ALL)
 
diff --git a/test/regress/regress1/sygus/rec-fun-swap.sy b/test/regress/regress1/sygus/rec-fun-swap.sy
new file mode 100644 (file)
index 0000000..056d6a8
--- /dev/null
@@ -0,0 +1,76 @@
+; EXPECT: unsat
+; COMMAND-LINE: --sygus-out=status --lang=sygus2
+
+(set-logic ALL)
+
+; The environment datatypes
+(declare-datatype NVars ((x) (y)))
+
+(declare-datatype Pair ((pair (first NVars) (second Int))))
+
+(declare-datatype Env ((cons (head Pair) (tail Env)) (nil)))
+
+(define-fun-rec envStore ((var NVars) (value Int) (env Env)) Env
+  (ite (is-nil env)
+    (cons (pair var value) env)
+    (ite (= var (first (head env)))
+      (cons (pair var value) (tail env))
+      (cons (head env) (envStore var value (tail env)))
+      )
+    )
+  )
+
+(define-fun-rec envSelect ((var NVars) (env Env)) Int
+  (ite (is-nil env)
+    (- 1)
+    (ite (= var (first (head env)))
+      (second (head env))
+      (envSelect var (tail env))
+      )
+    )
+  )
+
+; Syntax for arithmetic expressions
+(declare-datatype Aexp
+  (
+    (Val (val Int))
+    )
+  )
+
+; Function to evaluate arithmetic expressions
+(define-fun-rec evalA ((env Env) (a Aexp)) Int
+    (val a)
+      )
+
+; Syntax for commands
+(declare-datatype Com
+  (
+    (Skip)
+    (Assign (lhs NVars) (rhs Aexp))
+    (CSeq (cBef Com) (aAft Com))
+    )
+  )
+
+; Function to evaluate statements
+(define-fun-rec evalC ((env Env) (c Com)) Env
+  (ite (is-Skip c)
+    env
+    (ite (is-Assign c)
+      (envStore (lhs c) (evalA env (rhs c)) env)
+      (evalC (evalC env (cBef c)) (aAft c)))
+    )
+  )
+
+(synth-fun prog () Com
+  ((C Com) (V NVars) (A Aexp) (I Int))
+  (
+    (C Com (Skip (Assign V A) (CSeq C C)))
+    (V NVars (x y))
+    (A Aexp ((Val I)))
+    (I Int (0 1))
+    )
+)
+
+(constraint (= (evalC (cons (pair y 0) (cons (pair x 1) nil)) prog) (cons (pair y 1) (cons (pair x 0) nil))))
+
+(check-synth)
index 13d4782d4e83b9317da0d1c64537376743c649d7..769e173de28be63c120bc10dfca08159ec956b5a 100644 (file)
@@ -1,5 +1,5 @@
 ; EXPECT: unsat
-; COMMAND-LINE: --sygus-out=status --sygus-rec-fun --lang=sygus2
+; COMMAND-LINE: --sygus-out=status --lang=sygus2
 
 (set-logic ALL)
 
index c175094ee20542fba9398fb08bf62248ad9e2a4b..e805fdc203b0654aa3248d0b6c6552893bfb34b2 100644 (file)
@@ -1,5 +1,5 @@
 ; EXPECT: unsat
-; COMMAND-LINE: --sygus-out=status --lang=sygus2 --sygus-rec-fun --no-e-matching --no-check-synth-sol
+; COMMAND-LINE: --sygus-out=status --lang=sygus2 --no-check-synth-sol
 
 (set-logic ALL)
 
index 87a4f2a6ea27837c84202b4f3a33f544265e824c..7e32384b38bdc1c9285994fdb21811c2b02d04f8 100644 (file)
@@ -1,5 +1,5 @@
 ; EXPECT: unsat
-; COMMAND-LINE: --sygus-out=status --lang=sygus2 --sygus-rec-fun --no-e-matching --no-check-synth-sol
+; COMMAND-LINE: --sygus-out=status --lang=sygus2 --no-check-synth-sol
 
 (set-logic ALL)
 
index 85f8268c59d798e58b7a77311bd28d4583382b67..b43b3d5e277f40f321c8def056eb6b17438199e9 100644 (file)
@@ -1,5 +1,5 @@
 ; EXPECT: unknown
-; COMMAND-LINE: --sygus-out=status --lang=sygus2 --sygus-rec-fun --no-e-matching --no-check-synth-sol
+; COMMAND-LINE: --sygus-out=status --lang=sygus2 --no-check-synth-sol
 
 (set-logic ALL)