Update to sygus standard output for check-synth responses (#6521)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Fri, 21 May 2021 17:15:28 +0000 (12:15 -0500)
committerGitHub <noreply@github.com>
Fri, 21 May 2021 17:15:28 +0000 (17:15 +0000)
This PR does two things:
(1) It eliminates the ad-hoc implementation of printSynthSolutions and removes it from the API. Now, printing response to a check-synth command is done in a more standard way, using the API + symbol manager. This is analogous to recent refactoring to get-model.
(2) It updates cvc5's output in response to check-synth to be compliant with the upcoming sygus 2.1 standard. The standard has changed slightly: responses to check-synth are now closed in parentheses, mirroring the smt2 response to get-model.

It also removes the unused command GetSynthSolutionCommand.

22 files changed:
src/api/cpp/cvc5.cpp
src/api/cpp/cvc5.h
src/expr/symbol_manager.cpp
src/expr/symbol_manager.h
src/options/smt_options.toml
src/printer/printer.cpp
src/printer/printer.h
src/smt/command.cpp
src/smt/command.h
src/smt/smt_engine.cpp
src/smt/smt_engine.h
src/smt/sygus_solver.cpp
src/smt/sygus_solver.h
src/theory/quantifiers/sygus/synth_conjecture.cpp
src/theory/quantifiers/sygus/synth_conjecture.h
src/theory/quantifiers/sygus/synth_engine.cpp
src/theory/quantifiers/sygus/synth_engine.h
src/theory/quantifiers_engine.cpp
src/theory/quantifiers_engine.h
test/regress/regress0/sygus/print-debug.sy
test/regress/regress0/sygus/print-define-fun.sy
test/regress/regress1/sygus/no-var-in-sol.sy

index b7923321ce7fdba6924a979d0d8f50ff74a65403..0da42f173d1a8b42757dbcba58011863c111890d 100644 (file)
@@ -7437,15 +7437,6 @@ std::vector<Term> Solver::getSynthSolutions(
   CVC5_API_TRY_CATCH_END;
 }
 
-void Solver::printSynthSolution(std::ostream& out) const
-{
-  CVC5_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  d_smtEngine->printSynthSolution(out);
-  ////////
-  CVC5_API_TRY_CATCH_END;
-}
-
 /*
  * !!! This is only temporarily available until the parser is fully migrated to
  * the new API. !!!
index f77869c2cdf9c6dd629ff926b5a208c57f4a3ea5..e8f7737a6ddf4ecca5f4db0d7a9369156736f942 100644 (file)
@@ -4118,12 +4118,6 @@ class CVC5_EXPORT Solver
    */
   std::vector<Term> getSynthSolutions(const std::vector<Term>& terms) const;
 
-  /**
-   * Print solution for synthesis conjecture to the given output stream.
-   * @param out the output stream
-   */
-  void printSynthSolution(std::ostream& out) const;
-
   // !!! This is only temporarily available until the parser is fully migrated
   // to the new API. !!!
   SmtEngine* getSmtEngine(void) const;
index 8d48709668de6e9c49e4cdede530764d9d22a025..687f4963ff0f75f0fc92ef476489becfed03dc5b 100644 (file)
@@ -40,6 +40,7 @@ class SymbolManager::Implementation
         d_namedAsserts(&d_context),
         d_declareSorts(&d_context),
         d_declareTerms(&d_context),
+        d_funToSynth(&d_context),
         d_hasPushedScope(&d_context, false)
   {
     // use an outermost push, to be able to clear all definitions
@@ -65,10 +66,14 @@ class SymbolManager::Implementation
   std::vector<api::Sort> getModelDeclareSorts() const;
   /** get model declare terms */
   std::vector<api::Term> getModelDeclareTerms() const;
+  /** get functions to synthesize */
+  std::vector<api::Term> getFunctionsToSynthesize() const;
   /** Add declared sort to the list of model declarations. */
   void addModelDeclarationSort(api::Sort s);
   /** Add declared term to the list of model declarations. */
   void addModelDeclarationTerm(api::Term t);
+  /** Add function to the list of functions to synthesize. */
+  void addFunctionToSynthesize(api::Term t);
   /** reset */
   void reset();
   /** reset assertions */
@@ -91,6 +96,8 @@ class SymbolManager::Implementation
   SortList d_declareSorts;
   /** Declared terms (for model printing) */
   TermList d_declareTerms;
+  /** Functions to synthesize (for response to check-synth) */
+  TermList d_funToSynth;
   /**
    * Have we pushed a scope (e.g. a let or quantifier) in the current context?
    */
@@ -192,6 +199,12 @@ std::vector<api::Term> SymbolManager::Implementation::getModelDeclareTerms()
   return declareTerms;
 }
 
+std::vector<api::Term> SymbolManager::Implementation::getFunctionsToSynthesize()
+    const
+{
+  return std::vector<api::Term>(d_funToSynth.begin(), d_funToSynth.end());
+}
+
 void SymbolManager::Implementation::addModelDeclarationSort(api::Sort s)
 {
   Trace("sym-manager") << "SymbolManager: addModelDeclarationSort " << s
@@ -206,6 +219,13 @@ void SymbolManager::Implementation::addModelDeclarationTerm(api::Term t)
   d_declareTerms.push_back(t);
 }
 
+void SymbolManager::Implementation::addFunctionToSynthesize(api::Term f)
+{
+  Trace("sym-manager") << "SymbolManager: addFunctionToSynthesize " << f
+                       << std::endl;
+  d_funToSynth.push_back(f);
+}
+
 void SymbolManager::Implementation::pushScope(bool isUserContext)
 {
   Trace("sym-manager") << "SymbolManager: pushScope, isUserContext = "
@@ -306,6 +326,11 @@ std::vector<api::Term> SymbolManager::getModelDeclareTerms() const
   return d_implementation->getModelDeclareTerms();
 }
 
+std::vector<api::Term> SymbolManager::getFunctionsToSynthesize() const
+{
+  return d_implementation->getFunctionsToSynthesize();
+}
+
 void SymbolManager::addModelDeclarationSort(api::Sort s)
 {
   d_implementation->addModelDeclarationSort(s);
@@ -316,6 +341,11 @@ void SymbolManager::addModelDeclarationTerm(api::Term t)
   d_implementation->addModelDeclarationTerm(t);
 }
 
+void SymbolManager::addFunctionToSynthesize(api::Term f)
+{
+  d_implementation->addFunctionToSynthesize(f);
+}
+
 size_t SymbolManager::scopeLevel() const
 {
   return d_symtabAllocated.getLevel();
index 271825e07d9aa9433ad908a94326e593da55225a..d8b7e23bd47ab7eb225c6a237e0f63e08d485b18 100644 (file)
@@ -112,6 +112,11 @@ class CVC5_EXPORT SymbolManager
    * @return The terms we have declared that should be printed in the model.
    */
   std::vector<api::Term> getModelDeclareTerms() const;
+  /**
+   * @return The functions we have declared that should be printed in a response
+   * to check-synth.
+   */
+  std::vector<api::Term> getFunctionsToSynthesize() const;
   /**
    * Add declared sort to the list of model declarations.
    */
@@ -120,6 +125,11 @@ class CVC5_EXPORT SymbolManager
    * Add declared term to the list of model declarations.
    */
   void addModelDeclarationTerm(api::Term t);
+  /**
+   * Add a function to synthesize. This ensures the solution for f is printed
+   * in a successful response to check-synth.
+   */
+  void addFunctionToSynthesize(api::Term f);
 
   //---------------------------- end named expressions
   /**
index 880bbe0fbb77c7c7715a2ad873b1dc605f00c0e0..d1354f7777a6094167d786314c24708bfbe329e4 100644 (file)
@@ -158,7 +158,7 @@ name   = "SMT Layer"
   category   = "regular"
   long       = "sygus-out=MODE"
   type       = "SygusSolutionOutMode"
-  default    = "STATUS_AND_DEF"
+  default    = "STANDARD"
   help       = "output mode for sygus"
   help_mode  = "Modes for sygus solution output."
 [[option.mode.STATUS]]
index 927fd1d13c03baa06c5cc5c0cf4e5dc85d804133..048f5d06bb5c1d20019ea803637cbbbe98f68ec4 100644 (file)
@@ -333,11 +333,6 @@ void Printer::toStreamCmdGetInstantiations(std::ostream& out) const
   printUnknownCommand(out, "get-instantiations");
 }
 
-void Printer::toStreamCmdGetSynthSolution(std::ostream& out) const
-{
-  printUnknownCommand(out, "get-synth-solution");
-}
-
 void Printer::toStreamCmdGetInterpol(std::ostream& out,
                                      const std::string& name,
                                      Node conj,
index 86f3dbb2b3cd33e32a056420e94e9a32e80d70fd..6c00ebad5bc1edc851690eb7020c32405469a7b6 100644 (file)
@@ -181,9 +181,6 @@ class Printer
   /** Print get-instantiations command */
   void toStreamCmdGetInstantiations(std::ostream& out) const;
 
-  /** Print get-synth-solution command */
-  void toStreamCmdGetSynthSolution(std::ostream& out) const;
-
   /** Print get-interpol command */
   void toStreamCmdGetInterpol(std::ostream& out,
                               const std::string& name,
index 02cea842a109c906895af8201e6d9edb573d9da8..bf7d5ef3df344380d58e93ade15bc5e4086f7116 100644 (file)
@@ -699,6 +699,7 @@ const api::Grammar* SynthFunCommand::getGrammar() const { return d_grammar; }
 
 void SynthFunCommand::invoke(api::Solver* solver, SymbolManager* sm)
 {
+  sm->addFunctionToSynthesize(d_fun);
   d_commandStatus = CommandSuccess::instance();
 }
 
@@ -846,7 +847,7 @@ void CheckSynthCommand::invoke(api::Solver* solver, SymbolManager* sm)
     {
       if (options::sygusOut() == options::SygusSolutionOutMode::STANDARD)
       {
-        d_solution << "(fail)" << endl;
+        d_solution << "fail" << endl;
       }
       else
       {
@@ -857,12 +858,30 @@ void CheckSynthCommand::invoke(api::Solver* solver, SymbolManager* sm)
     if (d_result.isUnsat()
         && options::sygusOut() != options::SygusSolutionOutMode::STATUS)
     {
-      // printing a synthesis solution is a non-constant
-      // method, since it invokes a sophisticated algorithm
-      // (Figure 5 of Reynolds et al. CAV 2015).
-      // Hence, we must call here print solution here,
-      // instead of during printResult.
-      solver->printSynthSolution(d_solution);
+      std::vector<api::Term> synthFuns = sm->getFunctionsToSynthesize();
+      d_solution << "(" << std::endl;
+      Printer* p = Printer::getPrinter(language::output::LANG_SYGUS_V2);
+      for (api::Term& f : synthFuns)
+      {
+        api::Term sol = solver->getSynthSolution(f);
+        std::vector<api::Term> formals;
+        if (sol.getKind() == api::LAMBDA)
+        {
+          formals.insert(formals.end(), sol[0].begin(), sol[0].end());
+          sol = sol[1];
+        }
+        api::Sort rangeSort = f.getSort();
+        if (rangeSort.isFunction())
+        {
+          rangeSort = rangeSort.getFunctionCodomainSort();
+        }
+        p->toStreamCmdDefineFunction(d_solution,
+                                     f.toString(),
+                                     termVectorToNodes(formals),
+                                     sortToTypeNode(rangeSort),
+                                     termToNode(sol));
+      }
+      d_solution << ")" << std::endl;
     }
   }
   catch (exception& e)
@@ -2069,57 +2088,6 @@ void GetInstantiationsCommand::toStream(std::ostream& out,
   Printer::getPrinter(language)->toStreamCmdGetInstantiations(out);
 }
 
-/* -------------------------------------------------------------------------- */
-/* class GetSynthSolutionCommand                                              */
-/* -------------------------------------------------------------------------- */
-
-GetSynthSolutionCommand::GetSynthSolutionCommand() : d_solver(nullptr) {}
-void GetSynthSolutionCommand::invoke(api::Solver* solver, SymbolManager* sm)
-{
-  try
-  {
-    d_solver = solver;
-    d_commandStatus = CommandSuccess::instance();
-  }
-  catch (exception& e)
-  {
-    d_commandStatus = new CommandFailure(e.what());
-  }
-}
-
-void GetSynthSolutionCommand::printResult(std::ostream& out,
-                                          uint32_t verbosity) const
-{
-  if (!ok())
-  {
-    this->Command::printResult(out, verbosity);
-  }
-  else
-  {
-    d_solver->printSynthSolution(out);
-  }
-}
-
-Command* GetSynthSolutionCommand::clone() const
-{
-  GetSynthSolutionCommand* c = new GetSynthSolutionCommand();
-  c->d_solver = d_solver;
-  return c;
-}
-
-std::string GetSynthSolutionCommand::getCommandName() const
-{
-  return "get-synth-solution";
-}
-
-void GetSynthSolutionCommand::toStream(std::ostream& out,
-                                       int toDepth,
-                                       size_t dag,
-                                       OutputLanguage language) const
-{
-  Printer::getPrinter(language)->toStreamCmdGetSynthSolution(out);
-}
-
 /* -------------------------------------------------------------------------- */
 /* class GetInterpolCommand                                                   */
 /* -------------------------------------------------------------------------- */
index 41a3639c96b66686ffc247426beb47f80ece6f9c..21ecd196441f236590a5e22d2cd30eb5f2612251 100644 (file)
@@ -1091,25 +1091,6 @@ class CVC5_EXPORT GetInstantiationsCommand : public Command
   api::Solver* d_solver;
 }; /* class GetInstantiationsCommand */
 
-class CVC5_EXPORT GetSynthSolutionCommand : public Command
-{
- public:
-  GetSynthSolutionCommand();
-
-  void invoke(api::Solver* solver, SymbolManager* sm) override;
-  void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
-  Command* clone() const override;
-  std::string getCommandName() const override;
-  void toStream(
-      std::ostream& out,
-      int toDepth = -1,
-      size_t dag = 1,
-      OutputLanguage language = language::output::LANG_AUTO) const override;
-
- protected:
-  api::Solver* d_solver;
-}; /* class GetSynthSolutionCommand */
-
 /** The command (get-interpol s B (G)?)
  *
  * This command asks for an interpolant from the current set of assertions and
index bd38f630deda2c93d914d3d4b1a0e1ddacc1d78e..6377091f2d6bb4104562d3079b9dd00b790e08fe 100644 (file)
@@ -1629,12 +1629,6 @@ void SmtEngine::getInstantiationTermVectors(
   }
 }
 
-void SmtEngine::printSynthSolution( std::ostream& out ) {
-  SmtScope smts(this);
-  finishInit();
-  d_sygusSolver->printSynthSolution(out);
-}
-
 bool SmtEngine::getSynthSolutions(std::map<Node, Node>& solMap)
 {
   SmtScope smts(this);
index b8cd1c3d782b811d0fc55a4701eb25842a01730f..3128257e6507381d139ce93063b2fb25155e616e 100644 (file)
@@ -543,11 +543,6 @@ class CVC5_EXPORT SmtEngine
    * in the proper format.
    */
   void printProof();
-  /**
-   * Print solution for synthesis conjectures found by counter-example guided
-   * instantiation module.
-   */
-  void printSynthSolution(std::ostream& out);
 
   /**
    * Get synth solution.
index 37d752230016c47c7eab9d96b4f75a032330a204..4e5d6cd8c2bfdf0c2501fcb6473db1c85bf3170e 100644 (file)
@@ -251,18 +251,6 @@ bool SygusSolver::getSynthSolutions(std::map<Node, Node>& sol_map)
   return true;
 }
 
-void SygusSolver::printSynthSolution(std::ostream& out)
-{
-  QuantifiersEngine* qe = d_smtSolver.getQuantifiersEngine();
-  if (qe == nullptr)
-  {
-    InternalError()
-        << "SygusSolver::printSynthSolution(): Cannot print synth solution in "
-           "the current logic, which does not include quantifiers";
-  }
-  qe->printSynthSolution(out);
-}
-
 void SygusSolver::checkSynthSolution(Assertions& as)
 {
   NodeManager* nm = NodeManager::currentNM();
index 5b3bca928eecf35cdda07463f3c44b9ebad6e90e..ff9b7e51306d59b84d80fd7c4e91c60d3e2d9945 100644 (file)
@@ -137,11 +137,6 @@ class SygusSolver
    * is a valid formula.
    */
   bool getSynthSolutions(std::map<Node, Node>& sol_map);
-  /**
-   * Print solution for synthesis conjectures found by counter-example guided
-   * instantiation module.
-   */
-  void printSynthSolution(std::ostream& out);
 
  private:
   /**
index 0eb96e2775aff64f25a90333d168dc8b012b4b33..e4ec40325cc5dea83cf2e144b52fe5b1625d9945 100644 (file)
@@ -995,7 +995,7 @@ void SynthConjecture::printAndContinueStream(const std::vector<Node>& enums,
   // we have generated a solution, print it
   // get the current output stream
   Options& sopts = smt::currentSmtEngine()->getOptions();
-  printSynthSolution(*sopts.getOut());
+  printSynthSolutionInternal(*sopts.getOut());
   excludeCurrentSolution(enums, values);
 }
 
@@ -1041,7 +1041,7 @@ void SynthConjecture::excludeCurrentSolution(const std::vector<Node>& enums,
   }
 }
 
-void SynthConjecture::printSynthSolution(std::ostream& out)
+void SynthConjecture::printSynthSolutionInternal(std::ostream& out)
 {
   Trace("cegqi-sol-debug") << "Printing synth solution..." << std::endl;
   Assert(d_quant[0].getNumChildren() == d_embed_quant[0].getNumChildren());
index a7ecd4eadf9bb31237ff39b75dddea9916aaff21..4329a9c6060e8d4947e5b88b62f20141cfe33e2b 100644 (file)
@@ -134,11 +134,11 @@ class SynthConjecture
   bool doRefine();
   //-------------------------------end for counterexample-guided check/refine
   /**
-   * Prints the synthesis solution to output stream out. This invokes solution
-   * reconstruction if the conjecture is single invocation. Otherwise, it
-   * returns the solution found by sygus enumeration.
+   * Prints the current synthesis solution to output stream out. This is
+   * currently used for printing solutions for sygusStream only. We do not
+   * enclose solutions in parentheses.
    */
-  void printSynthSolution(std::ostream& out);
+  void printSynthSolutionInternal(std::ostream& out);
   /** get synth solutions
    *
    * This method returns true if this class has a solution available to the
index 173f58060d5fb813757cc7c01fe1dd2b631777ba..86c3f62d0e3d14dca6595faa0c1e6a46d41fd5ba 100644 (file)
@@ -246,18 +246,6 @@ bool SynthEngine::checkConjecture(SynthConjecture* conj)
   return conj->doRefine();
 }
 
-void SynthEngine::printSynthSolution(std::ostream& out)
-{
-  Assert(!d_conjs.empty());
-  for (unsigned i = 0, size = d_conjs.size(); i < size; i++)
-  {
-    if (d_conjs[i]->isAssigned())
-    {
-      d_conjs[i]->printSynthSolution(out);
-    }
-  }
-}
-
 bool SynthEngine::getSynthSolutions(
     std::map<Node, std::map<Node, Node> >& sol_map)
 {
index df73c4821a33774505427d340c2eb1662d992944..d37df4e28a706f940ed2b43a9cf1f167dc59ca38 100644 (file)
@@ -57,8 +57,6 @@ class SynthEngine : public QuantifiersModule
   void registerQuantifier(Node q) override;
   /** Identify this module (for debugging, dynamic configuration, etc..) */
   std::string identify() const override { return "SynthEngine"; }
-  /** print solution for synthesis conjectures */
-  void printSynthSolution(std::ostream& out);
   /** get synth solutions
    *
    * This function adds entries to sol_map that map functions-to-synthesize
index 2d1eeab84a93413a3a0166ef1c16dc4befcf6301..40f5b901fd29c6aa081d51881c29dbedb0b631de 100644 (file)
@@ -651,15 +651,6 @@ void QuantifiersEngine::getInstantiations(Node q, std::vector<Node>& insts)
   d_qim.getInstantiate()->getInstantiations(q, insts);
 }
 
-void QuantifiersEngine::printSynthSolution( std::ostream& out ) {
-  if (d_qmodules->d_synth_e)
-  {
-    d_qmodules->d_synth_e->printSynthSolution(out);
-  }else{
-    out << "Internal error : module for synth solution not found." << std::endl;
-  }
-}
-
 void QuantifiersEngine::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs)
 {
   d_qim.getInstantiate()->getInstantiatedQuantifiedFormulas(qs);
index fc29ab8e861714bcfc062aa25f7d5fb9e49dc0d9..482dbfaee8288cab77bd9e1ede429b76d2d8a90c 100644 (file)
@@ -134,8 +134,6 @@ public:
 
 public:
  //----------user interface for instantiations (see quantifiers/instantiate.h)
- /** print solution for synthesis conjectures */
- void printSynthSolution(std::ostream& out);
  /** get list of quantified formulas that were instantiated */
  void getInstantiatedQuantifiedFormulas(std::vector<Node>& qs);
  /** get instantiation term vectors */
index 0de43129457653a8ef5f8bde9ae36720494360b4..aba9c715f2dc70d08bc58a88057b24777d8a3e7b 100644 (file)
@@ -3,8 +3,9 @@
 ; EXPECT: (sygus-candidate (f 0))
 ; EXPECT: (sygus-enum 1)
 ; EXPECT: (sygus-candidate (f 1))
-; EXPECT: unsat
+; EXPECT: (
 ; EXPECT: (define-fun f () Int 1)
+; EXPECT: )
 (set-logic LIA)
 
 (synth-fun f () Int ((Start Int)) ((Start Int (0 1))))
index e6c7e4748d0ff28ff77aa4281faa73293c658d5c..520a03d2ad48bb3a9206f00c746a8d9c7df5d9a3 100644 (file)
@@ -1,6 +1,7 @@
 ; COMMAND-LINE: --lang=sygus2
-; EXPECT: unsat
+; EXPECT: (
 ; EXPECT: (define-fun g ((x Int)) Int (f 0))
+; EXPECT: )
 (set-logic LIA)
 (define-fun f ((x Int)) Int (+ x 1))
 (synth-fun g ((x Int)) Int ((Start Int)) ((Start Int ((f 0)))))
index 333e29d6eadd966f27a8f98d259ec10ed1bcc35d..ff2be7b227c570211490f5c3915b89fe402ae3d2 100644 (file)
@@ -1,7 +1,8 @@
 ; COMMAND-LINE: --sygus-si=all --dag-thresh=0
-; EXPECT: unsat
+; EXPECT: (
 ; EXPECT: (define-fun f1 ((x Bool) (y Bool)) Bool (ite true true false))
 ; EXPECT: (define-fun f2 ((x Bool) (y Bool)) Bool (ite x (ite y false (not false)) (not (ite false false (not false)))))
+; EXPECT: )
 
 ; Test ensures that the solution does not contain a random variable