Add support for incremental + interpolants (#7853)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Wed, 22 Dec 2021 16:56:51 +0000 (10:56 -0600)
committerGitHub <noreply@github.com>
Wed, 22 Dec 2021 16:56:51 +0000 (10:56 -0600)
Adds support for incrementality + get-interpol, including the get-interpol-next command.

22 files changed:
src/api/cpp/cvc5.cpp
src/api/cpp/cvc5.h
src/api/java/io/github/cvc5/api/Solver.java
src/api/java/jni/solver.cpp
src/parser/smt2/Smt2.g
src/printer/printer.cpp
src/printer/printer.h
src/printer/smt2/smt2_printer.cpp
src/printer/smt2/smt2_printer.h
src/smt/command.cpp
src/smt/command.h
src/smt/interpolation_solver.cpp
src/smt/interpolation_solver.h
src/smt/solver_engine.cpp
src/smt/solver_engine.h
src/theory/quantifiers/sygus/sygus_interpol.cpp
src/theory/quantifiers/sygus/sygus_interpol.h
test/regress/CMakeLists.txt
test/regress/regress1/sygus/interpol1-push-pop.smt2 [new file with mode: 0644]
test/regress/regress1/sygus/interpol3-next.smt2 [new file with mode: 0644]
test/unit/api/cpp/solver_black.cpp
test/unit/api/java/SolverTest.java

index 4c43dbd5b343bc196d32a0ea2253d855973a8897..be5f1017dd181e3a20de5398a5dc8c3836265eff 100644 (file)
@@ -7579,9 +7579,14 @@ bool Solver::getInterpolant(const Term& conj, Term& output) const
 {
   CVC5_API_TRY_CATCH_BEGIN;
   CVC5_API_SOLVER_CHECK_TERM(conj);
+  CVC5_API_CHECK(d_slv->getOptions().smt.produceInterpols
+                 != options::ProduceInterpols::NONE)
+      << "Cannot get interpolant unless interpolants are enabled (try "
+         "--produce-interpols=mode)";
   //////// all checks before this line
   Node result;
-  bool success = d_slv->getInterpol(*conj.d_node, result);
+  TypeNode nullType;
+  bool success = d_slv->getInterpolant(*conj.d_node, nullType, result);
   if (success)
   {
     output = Term(this, result);
@@ -7597,10 +7602,36 @@ bool Solver::getInterpolant(const Term& conj,
 {
   CVC5_API_TRY_CATCH_BEGIN;
   CVC5_API_SOLVER_CHECK_TERM(conj);
+  CVC5_API_CHECK(d_slv->getOptions().smt.produceInterpols
+                 != options::ProduceInterpols::NONE)
+      << "Cannot get interpolant unless interpolants are enabled (try "
+         "--produce-interpols=mode)";
   //////// all checks before this line
   Node result;
   bool success =
-      d_slv->getInterpol(*conj.d_node, *grammar.resolve().d_type, result);
+      d_slv->getInterpolant(*conj.d_node, *grammar.resolve().d_type, result);
+  if (success)
+  {
+    output = Term(this, result);
+  }
+  return success;
+  ////////
+  CVC5_API_TRY_CATCH_END;
+}
+
+bool Solver::getInterpolantNext(Term& output) const
+{
+  CVC5_API_TRY_CATCH_BEGIN;
+  CVC5_API_CHECK(d_slv->getOptions().smt.produceInterpols
+                 != options::ProduceInterpols::NONE)
+      << "Cannot get interpolant unless interpolants are enabled (try "
+         "--produce-interpols=mode)";
+  CVC5_API_CHECK(d_slv->getOptions().base.incrementalSolving)
+      << "Cannot get next interpolant when not solving incrementally (try "
+         "--incremental)";
+  //////// all checks before this line
+  Node result;
+  bool success = d_slv->getInterpolantNext(result);
   if (success)
   {
     output = Term(this, result);
index 7e4dc3cc8c7fc91e127a7a576f978af81cf96a55..21f51a9c8aa8c45a95b14b328c5903094b97f1d5 100644 (file)
@@ -4427,8 +4427,9 @@ class CVC5_EXPORT Solver
    *
    *     (get-interpol <conj>)
    *
-   * Requires to enable option
-   * :ref:`produce-interpols <lbl-option-produce-interpols>`.
+   * Requires option
+   * :ref:`produce-interpols <lbl-option-produce-interpols>` to be set to a
+   * mode different from `none`.
    * \endverbatim
    *
    * @param conj the conjecture term
@@ -4448,8 +4449,9 @@ class CVC5_EXPORT Solver
    *
    *     (get-interpol <conj> <grammar>)
    *
-   * Requires to enable option
-   * :ref:`produce-interpols <lbl-option-produce-interpols>`.
+   * Requires option
+   * :ref:`produce-interpols <lbl-option-produce-interpols>` to be set to a
+   * mode different from `none`.
    * \endverbatim
    *
    * @param conj the conjecture term
@@ -4460,6 +4462,31 @@ class CVC5_EXPORT Solver
    */
   bool getInterpolant(const Term& conj, Grammar& grammar, Term& output) const;
 
+  /**
+   * Get the next interpolant. Can only be called immediately after a successful
+   * call to get-interpol or get-interpol-next. Is guaranteed to produce a
+   * syntactically different interpolant wrt the last returned interpolant if
+   * successful.
+   *
+   * SMT-LIB:
+   *
+   * \verbatim embed:rst:leading-asterisk
+   * .. code:: smtlib
+   *
+   *     (get-interpol-next)
+   *
+   * Requires to enable incremental mode, and option
+   * :ref:`produce-interpols <lbl-option-produce-interpols>` to be set to a
+   * mode different from `none`.
+   * \endverbatim
+   *
+   * @param output a Term I such that A->I and I->B are valid, where A is the
+   *        current set of assertions and B is given in the input by conj
+   *        on the last call to getInterpolant.
+   * @return true if it gets interpolant @f$C@f$ successfully, false otherwise
+   */
+  bool getInterpolantNext(Term& output) const;
+
   /**
    * Get an abduct.
    *
index 32ddf069166edddb0dfacc757aef2efb8b6d3fdc..5e2ac097292c0e39d8ded36a91eb72cfb2e2d878 100644 (file)
@@ -2183,7 +2183,7 @@ public class Solver implements IPointer, AutoCloseable
    * {@code
    * ( get-interpol <conj> )
    * }
-   * Requires to enable option 'produce-interpols'.
+   * Requires 'produce-interpols' to be set to a mode different from 'none'.
    * @param conj the conjecture term
    * @param output a Term I such that {@code A->I} and {@code I->B} are valid, where A is the
    *        current set of assertions and B is given in the input by conj.
@@ -2202,7 +2202,7 @@ public class Solver implements IPointer, AutoCloseable
    * {@code
    * ( get-interpol <conj> <g> )
    * }
-   * Requires to enable option 'produce-interpols'.
+   * Requires 'produce-interpols' to be set to a mode different from 'none'.
    * @param conj the conjecture term
    * @param grammar the grammar for the interpolant I
    * @param output a Term I such that {@code A->I} and {@code I->B} are valid, where A is the
@@ -2217,6 +2217,35 @@ public class Solver implements IPointer, AutoCloseable
   private native boolean getInterpolant(
       long pointer, long conjPointer, long grammarPointer, long outputPointer);
 
+  /**
+   * Get the next interpolant. Can only be called immediately after a successful
+   * call to get-interpol or get-interpol-next. Is guaranteed to produce a
+   * syntactically different interpolant wrt the last returned interpolant if
+   * successful.
+   *
+   * SMT-LIB:
+   *
+   * \verbatim embed:rst:leading-asterisk
+   * .. code:: smtlib
+   *
+   *     (get-interpol-next)
+   *
+   * Requires to enable incremental mode, and option 'produce-interpols' to be
+   * set to a mode different from 'none'.
+   * \endverbatim
+   *
+   * @param output a Term I such that {@code A->I} and {@code I->B} are valid,
+   *        where A is the current set of assertions and B is given in the input
+   *        by conj on the last call to getInterpolant.
+   * @return true if it gets interpolant @f$C@f$ successfully, false otherwise
+   */
+  public boolean getInterpolantNext(Term output)
+  {
+    return getInterpolantNext(pointer, output.getPointer());
+  }
+
+  private native boolean getInterpolantNext(long pointer, long outputPointer);
+
   /**
    * Get an abduct.
    * SMT-LIB:
index 524c527964f0ad80c016840fd45dd30708aecff3..705803c12b29ef3003b077f4369c12a18c935647 100644 (file)
@@ -2243,6 +2243,21 @@ Java_io_github_cvc5_api_Solver_getInterpolant__JJJJ(JNIEnv* env,
   CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0);
 }
 
+/*
+ * Class:     io_github_cvc5_api_Solver
+ * Method:    getInterpolantNext
+ * Signature: (JJ)Z
+ */
+JNIEXPORT jboolean JNICALL Java_io_github_cvc5_api_Solver_getInterpolantNext(
+    JNIEnv* env, jobject, jlong pointer, jlong outputPointer)
+{
+  CVC5_JAVA_API_TRY_CATCH_BEGIN;
+  Solver* solver = reinterpret_cast<Solver*>(pointer);
+  Term* output = reinterpret_cast<Term*>(outputPointer);
+  return (jboolean)solver->getInterpolantNext(*output);
+  CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, 0);
+}
+
 /*
  * Class:     io_github_cvc5_api_Solver
  * Method:    getAbduct
index 31171b2788ee025008ff788fbc673a8a316281f9..fafda041a4012b8afa95d1abe8cf5b916b16a757 100644 (file)
@@ -1022,6 +1022,10 @@ extendedCommand[std::unique_ptr<cvc5::Command>* cmd]
     {
       cmd->reset(new GetInterpolCommand(name, e, g));
     }
+  | GET_INTERPOL_NEXT_TOK {
+      PARSER_STATE->checkThatLogicIsSet();
+      cmd->reset(new GetInterpolNextCommand);
+    }
   | DECLARE_HEAP LPAREN_TOK
     sortSymbol[t, CHECK_DECLARED]
     sortSymbol[s, CHECK_DECLARED]
@@ -2244,6 +2248,7 @@ GET_QE_DISJUNCT_TOK : 'get-qe-disjunct';
 GET_ABDUCT_TOK : 'get-abduct';
 GET_ABDUCT_NEXT_TOK : 'get-abduct-next';
 GET_INTERPOL_TOK : 'get-interpol';
+GET_INTERPOL_NEXT_TOK : 'get-interpol-next';
 DECLARE_HEAP : 'declare-heap';
 DECLARE_POOL : 'declare-pool';
 
index a4ff10014640e6899f1415a8b3e5fffe0deeddc5..12b52e284269d0e355cc8ffd715bbbb91722cb05 100644 (file)
@@ -405,6 +405,11 @@ void Printer::toStreamCmdGetInterpol(std::ostream& out,
   printUnknownCommand(out, "get-interpol");
 }
 
+void Printer::toStreamCmdGetInterpolNext(std::ostream& out) const
+{
+  printUnknownCommand(out, "get-interpol-next");
+}
+
 void Printer::toStreamCmdGetAbduct(std::ostream& out,
                                    const std::string& name,
                                    Node conj,
index 74eb8970b1c6e333e87aa44600eb711e9fc511e7..2a92830010ff7b9d1547c038049c0b5e5433b02e 100644 (file)
@@ -200,6 +200,9 @@ class Printer
                                       Node conj,
                                       TypeNode sygusType) const;
 
+  /** Print get-interpol-next command */
+  virtual void toStreamCmdGetInterpolNext(std::ostream& out) const;
+
   /** Print get-abduct command */
   virtual void toStreamCmdGetAbduct(std::ostream& out,
                                     const std::string& name,
index e6c99c7070e8fd4fa32ffd419ffc65ec1a497edd..69da5d03d85b4b545581a78ed449bbc40832389d 100644 (file)
@@ -1917,6 +1917,11 @@ void Smt2Printer::toStreamCmdGetInterpol(std::ostream& out,
   out << ')' << std::endl;
 }
 
+void Smt2Printer::toStreamCmdGetInterpolNext(std::ostream& out) const
+{
+  out << "(get-interpol-next)" << std::endl;
+}
+
 void Smt2Printer::toStreamCmdGetAbduct(std::ostream& out,
                                        const std::string& name,
                                        Node conj,
index aad3948feb552b721de3eec6869497919cb8f97d..bf6c20d40699e4bbd8bf6cd8e26b156cb804ef4b 100644 (file)
@@ -174,6 +174,9 @@ class Smt2Printer : public cvc5::Printer
                               Node conj,
                               TypeNode sygusType) const override;
 
+  /** Print get-interpol-next command */
+  void toStreamCmdGetInterpolNext(std::ostream& out) const override;
+
   /** Print get-abduct command */
   void toStreamCmdGetAbduct(std::ostream& out,
                             const std::string& name,
index 8161dfb49acb9539cca8868c97d0215b7ceae7fd..e22c39d0e60e581ce529a39cf9a39d46ee793ca2 100644 (file)
@@ -2007,6 +2007,9 @@ void GetInterpolCommand::invoke(api::Solver* solver, SymbolManager* sm)
 {
   try
   {
+    // we must remember the name of the interpolant, in case get-interpol-next
+    // is called later.
+    sm->setLastSynthName(d_name);
     if (d_sygus_grammar == nullptr)
     {
       d_resultStatus = solver->getInterpolant(d_conj, d_result);
@@ -2069,6 +2072,72 @@ void GetInterpolCommand::toStream(std::ostream& out,
       out, d_name, termToNode(d_conj), grammarToTypeNode(d_sygus_grammar));
 }
 
+/* -------------------------------------------------------------------------- */
+/* class GetInterpolNextCommand */
+/* -------------------------------------------------------------------------- */
+
+GetInterpolNextCommand::GetInterpolNextCommand() : d_resultStatus(false) {}
+
+api::Term GetInterpolNextCommand::getResult() const { return d_result; }
+
+void GetInterpolNextCommand::invoke(api::Solver* solver, SymbolManager* sm)
+{
+  try
+  {
+    // Get the name of the interpolant from the symbol manager
+    d_name = sm->getLastSynthName();
+    d_resultStatus = solver->getInterpolantNext(d_result);
+    d_commandStatus = CommandSuccess::instance();
+  }
+  catch (exception& e)
+  {
+    d_commandStatus = new CommandFailure(e.what());
+  }
+}
+
+void GetInterpolNextCommand::printResult(std::ostream& out) const
+{
+  if (!ok())
+  {
+    this->Command::printResult(out);
+  }
+  else
+  {
+    options::ioutils::Scope scope(out);
+    options::ioutils::applyDagThresh(out, 0);
+    if (d_resultStatus)
+    {
+      out << "(define-fun " << d_name << " () Bool " << d_result << ")"
+          << std::endl;
+    }
+    else
+    {
+      out << "none" << std::endl;
+    }
+  }
+}
+
+Command* GetInterpolNextCommand::clone() const
+{
+  GetInterpolNextCommand* c = new GetInterpolNextCommand;
+  c->d_result = d_result;
+  c->d_resultStatus = d_resultStatus;
+  return c;
+}
+
+std::string GetInterpolNextCommand::getCommandName() const
+{
+  return "get-interpol-next";
+}
+
+void GetInterpolNextCommand::toStream(std::ostream& out,
+                                      int toDepth,
+                                      size_t dag,
+                                      Language language) const
+{
+  Printer::getPrinter(language)->toStreamCmdGetInterpolNext(out);
+}
+
 /* -------------------------------------------------------------------------- */
 /* class GetAbductCommand                                                     */
 /* -------------------------------------------------------------------------- */
index 68ff7ffab21eb968af477e00c44d0ac9be30e74e..9a4b04196181c113408016f229dca981d003f9c6 100644 (file)
@@ -1058,6 +1058,35 @@ class CVC5_EXPORT GetInterpolCommand : public Command
   api::Term d_result;
 }; /* class GetInterpolCommand */
 
+/** The command (get-interpol-next) */
+class CVC5_EXPORT GetInterpolNextCommand : public Command
+{
+ public:
+  GetInterpolNextCommand();
+  /**
+   * Get the result of the query, which is the solution to the interpolation
+   * query.
+   */
+  api::Term getResult() const;
+
+  void invoke(api::Solver* solver, SymbolManager* sm) override;
+  void printResult(std::ostream& out) const override;
+  Command* clone() const override;
+  std::string getCommandName() const override;
+  void toStream(std::ostream& out,
+                int toDepth = -1,
+                size_t dag = 1,
+                Language language = Language::LANG_AUTO) const override;
+
+ protected:
+  /** The name of the interpolation predicate */
+  std::string d_name;
+  /** the return status of the command */
+  bool d_resultStatus;
+  /** the return expression of the command */
+  api::Term d_result;
+};
+
 /** The command (get-abduct s B (G)?)
  *
  * This command asks for an abduct from the current set of assertions and
@@ -1134,7 +1163,7 @@ class CVC5_EXPORT GetAbductNextCommand : public Command
   bool d_resultStatus;
   /** the return expression of the command */
   api::Term d_result;
-}; /* class GetAbductCommand */
+};
 
 class CVC5_EXPORT GetQuantifierEliminationCommand : public Command
 {
index 20be53e85c16a3f0aaba48fe4a5129060fd1d6ea..97d3a4224a968139b054223e0b49e32c189863a7 100644 (file)
@@ -36,10 +36,10 @@ InterpolationSolver::InterpolationSolver(Env& env) : EnvObj(env) {}
 
 InterpolationSolver::~InterpolationSolver() {}
 
-bool InterpolationSolver::getInterpol(const std::vector<Node>& axioms,
-                                      const Node& conj,
-                                      const TypeNode& grammarType,
-                                      Node& interpol)
+bool InterpolationSolver::getInterpolant(const std::vector<Node>& axioms,
+                                         const Node& conj,
+                                         const TypeNode& grammarType,
+                                         Node& interpol)
 {
   if (options().smt.produceInterpols == options::ProduceInterpols::NONE)
   {
@@ -54,8 +54,8 @@ bool InterpolationSolver::getInterpol(const std::vector<Node>& axioms,
   conjn = rewrite(conjn);
   std::string name("__internal_interpol");
 
-  quantifiers::SygusInterpol interpolSolver(d_env);
-  if (interpolSolver.solveInterpolation(
+  d_subsolver = std::make_unique<quantifiers::SygusInterpol>(d_env);
+  if (d_subsolver->solveInterpolation(
           name, axioms, conjn, grammarType, interpol))
   {
     if (options().smt.checkInterpols)
@@ -67,12 +67,12 @@ bool InterpolationSolver::getInterpol(const std::vector<Node>& axioms,
   return false;
 }
 
-bool InterpolationSolver::getInterpol(const std::vector<Node>& axioms,
-                                      const Node& conj,
-                                      Node& interpol)
+bool InterpolationSolver::getInterpolantNext(Node& interpol)
 {
-  TypeNode grammarType;
-  return getInterpol(axioms, conj, grammarType, interpol);
+  // should already have initialized a subsolver, since we are immediately
+  // preceeded by a successful call to get-interpol(-next).
+  Assert(d_subsolver != nullptr);
+  return d_subsolver->solveInterpolationNext(interpol);
 }
 
 void InterpolationSolver::checkInterpol(Node interpol,
index 39a241816a9ebf883d7055ca54889ce6878d1857..d1f1c7fd885bff70b8da249eecbb61bfb4fb8a89 100644 (file)
 #include "smt/env_obj.h"
 
 namespace cvc5 {
+
+namespace theory {
+namespace quantifiers {
+class SygusInterpol;
+}
+}  // namespace theory
+
 namespace smt {
 
 /**
@@ -55,19 +62,24 @@ class InterpolationSolver : protected EnvObj
    * This method invokes a separate copy of the SMT engine for solving the
    * corresponding sygus problem for generating such a solution.
    */
-  bool getInterpol(const std::vector<Node>& axioms,
-                   const Node& conj,
-                   const TypeNode& grammarType,
-                   Node& interpol);
+  bool getInterpolant(const std::vector<Node>& axioms,
+                      const Node& conj,
+                      const TypeNode& grammarType,
+                      Node& interpol);
 
   /**
-   * Same as above, but without user-provided grammar restrictions. A default
-   * grammar is chosen internally using the sygus grammar constructor utility.
+   * Get next interpolant. This can only be called immediately after a
+   * successful call to getInterpolant or getInterpolantNext.
+   *
+   * Returns true if an interpolant was found, and sets interpol to the
+   * interpolant.
+   *
+   * This method reuses the subsolver initialized by the last call to
+   * getInterpolant.
    */
-  bool getInterpol(const std::vector<Node>& axioms,
-                   const Node& conj,
-                   Node& interpol);
+  bool getInterpolantNext(Node& interpol);
 
+ private:
   /**
    * Check that a solution to an interpolation problem is indeed a solution.
    *
@@ -78,6 +90,9 @@ class InterpolationSolver : protected EnvObj
   void checkInterpol(Node interpol,
                      const std::vector<Node>& easserts,
                      const Node& conj);
+
+  /** The subsolver */
+  std::unique_ptr<theory::quantifiers::SygusInterpol> d_subsolver;
 };
 
 }  // namespace smt
index 2df3eafa1b20f001e6fb92dceb96cd6969a01945..e7f2e2069a73b9f4ca701d5b5c13003746bc29cd 100644 (file)
@@ -1632,25 +1632,35 @@ Node SolverEngine::getQuantifierElimination(Node q, bool doFull, bool strict)
       *d_asserts, q, doFull, d_isInternalSubsolver);
 }
 
-bool SolverEngine::getInterpol(const Node& conj,
-                               const TypeNode& grammarType,
-                               Node& interpol)
+bool SolverEngine::getInterpolant(const Node& conj,
+                                  const TypeNode& grammarType,
+                                  Node& interpol)
 {
   SolverEngineScope smts(this);
   finishInit();
   std::vector<Node> axioms = getExpandedAssertions();
   bool success =
-      d_interpolSolver->getInterpol(axioms, conj, grammarType, interpol);
+      d_interpolSolver->getInterpolant(axioms, conj, grammarType, interpol);
   // notify the state of whether the get-interpol call was successfuly, which
   // impacts the SMT mode.
   d_state->notifyGetInterpol(success);
   return success;
 }
 
-bool SolverEngine::getInterpol(const Node& conj, Node& interpol)
+bool SolverEngine::getInterpolantNext(Node& interpol)
 {
-  TypeNode grammarType;
-  return getInterpol(conj, grammarType, interpol);
+  SolverEngineScope smts(this);
+  finishInit();
+  if (d_state->getMode() != SmtMode::INTERPOL)
+  {
+    throw RecoverableModalException(
+        "Cannot get-interpol-next unless immediately preceded by a successful "
+        "call to get-interpol(-next).");
+  }
+  bool success = d_interpolSolver->getInterpolantNext(interpol);
+  // notify the state of whether the get-interpolant-next call was successful
+  d_state->notifyGetInterpol(success);
+  return success;
 }
 
 bool SolverEngine::getAbduct(const Node& conj,
index 165424594814b9397f6cd4d1a5b57d8cadcc804a..99d2502b912d2f44ba7114eda96748e524173841 100644 (file)
@@ -637,12 +637,18 @@ class CVC5_EXPORT SolverEngine
    * This method invokes a separate copy of the SMT engine for solving the
    * corresponding sygus problem for generating such a solution.
    */
-  bool getInterpol(const Node& conj,
-                   const TypeNode& grammarType,
-                   Node& interpol);
+  bool getInterpolant(const Node& conj,
+                      const TypeNode& grammarType,
+                      Node& interpol);
 
-  /** Same as above, but without user-provided grammar restrictions */
-  bool getInterpol(const Node& conj, Node& interpol);
+  /**
+   * Get next interpolant. This can only be called immediately after a
+   * successful call to getInterpolant or getInterpolantNext.
+   *
+   * Returns true if an interpolant was found, and sets interpol to the
+   * interpolant.
+   */
+  bool getInterpolantNext(Node& interpol);
 
   /**
    * This method asks this SMT engine to find an abduct with respect to the
index 3e1a5b34c145da4b957628d2243a9ec9f81a5fc4..eb9bed3dcc9b6b5873f29e0f335fb6eb0a3073ff 100644 (file)
@@ -323,36 +323,50 @@ bool SygusInterpol::solveInterpolation(const std::string& name,
   createVariables(itpGType.isNull());
   TypeNode grammarType = setSynthGrammar(itpGType, axioms, conj);
 
-  Node itp = mkPredicate(name);
-  mkSygusConjecture(itp, axioms, conj);
+  d_itp = mkPredicate(name);
+  mkSygusConjecture(d_itp, axioms, conj);
 
-  std::unique_ptr<SolverEngine> subSolver;
-  initializeSubsolver(subSolver, d_env);
+  initializeSubsolver(d_subSolver, d_env);
   // get the logic
-  LogicInfo l = subSolver->getLogicInfo().getUnlockedCopy();
+  LogicInfo l = d_subSolver->getLogicInfo().getUnlockedCopy();
   // enable everything needed for sygus
   l.enableSygus();
-  subSolver->setLogic(l);
+  d_subSolver->setLogic(l);
 
   for (const Node& var : d_vars)
   {
-    subSolver->declareSygusVar(var);
+    d_subSolver->declareSygusVar(var);
   }
   std::vector<Node> vars_empty;
-  subSolver->declareSynthFun(itp, grammarType, false, vars_empty);
-  Trace("sygus-interpol") << "SolverEngine::getInterpol: made conjecture : "
-                          << d_sygusConj << ", solving for "
-                          << d_sygusConj[0][0] << std::endl;
-  subSolver->assertSygusConstraint(d_sygusConj);
+  d_subSolver->declareSynthFun(d_itp, grammarType, false, vars_empty);
+  Trace("sygus-interpol")
+      << "SygusInterpol::solveInterpolation: made conjecture : " << d_sygusConj
+      << ", solving for " << d_sygusConj[0][0] << std::endl;
+  d_subSolver->assertSygusConstraint(d_sygusConj);
 
-  Trace("sygus-interpol") << "  SolverEngine::getInterpol check sat..."
-                          << std::endl;
-  Result r = subSolver->checkSynth();
-  Trace("sygus-interpol") << "  SolverEngine::getInterpol result: " << r
+  Trace("sygus-interpol")
+      << "  SygusInterpol::solveInterpolation check synth..." << std::endl;
+  Result r = d_subSolver->checkSynth();
+  Trace("sygus-interpol") << "  SygusInterpol::solveInterpolation result: " << r
                           << std::endl;
   if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
   {
-    return findInterpol(subSolver.get(), interpol, itp);
+    return findInterpol(d_subSolver.get(), interpol, d_itp);
+  }
+  return false;
+}
+
+bool SygusInterpol::solveInterpolationNext(Node& interpol)
+{
+  Trace("sygus-interpol")
+      << "  SygusInterpol::solveInterpolationNext check synth..." << std::endl;
+  // invoke the check-synth with isNext = true.
+  Result r = d_subSolver->checkSynth(true);
+  Trace("sygus-interpol") << "  SygusInterpol::solveInterpolationNext result: "
+                          << r << std::endl;
+  if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
+  {
+    return findInterpol(d_subSolver.get(), interpol, d_itp);
   }
   return false;
 }
index 4d3ae0219d00366fe2b20f72a99778c259329cd7..604e7435fa31a468b79fee427d8990d152fdc8e5 100644 (file)
@@ -84,6 +84,21 @@ class SygusInterpol : protected EnvObj
                           const TypeNode& itpGType,
                           Node& interpol);
 
+  /**
+   * Returns the sygus conjecture in interpol corresponding to the interpolation
+   * problem for input problem (F above) given by axioms (Fa above), and conj
+   * (Fc above). And solve the interpolation by sygus. Note that axioms is
+   * expected to be a subset of assertions in SMT-LIB.
+   *
+   * @param name the name for the interpol-to-synthesize.
+   * @param axioms the assertions (Fa above)
+   * @param conj the conjecture (Fc above)
+   * @param itpGType (if non-null) a sygus datatype type that encodes the
+   * grammar that should be used for solutions of the interpolation conjecture.
+   * @interpol the solution to the sygus conjecture.
+   */
+  bool solveInterpolationNext(Node& interpol);
+
  private:
   /**
    * Collects symbols from axioms (axioms) and conjecture (conj), which are
@@ -212,6 +227,13 @@ class SygusInterpol : protected EnvObj
    * the sygus conjecture to synthesis for interpolation problem
    */
   Node d_sygusConj;
+  /**
+   * The predicate for interpolation in the subsolver, which we pass to
+   * findInterpol above when the solving is successful.
+   */
+  Node d_itp;
+  /** The subsolver to initialize */
+  std::unique_ptr<SolverEngine> d_subSolver;
 };
 
 }  // namespace quantifiers
index 5c4cdcd4a078409e3cd5e2f8b76df989e318f3b8..e19ef2f7eef9386121dd1a090a978456f1628b50 100644 (file)
@@ -2476,7 +2476,9 @@ set(regress_1_tests
   regress1/sygus/inv-missed-sol-true.sy
   regress1/sygus/inv-unused.sy
   regress1/sygus/interpol1.smt2
+  regress1/sygus/interpol1-push-pop.smt2 
   regress1/sygus/interpol3.smt2
+  regress1/sygus/interpol3-next.smt2
   regress1/sygus/interpol_arr1.smt2
   regress1/sygus/interpol_arr2.smt2
   regress1/sygus/interpol_cosa_1.smt2
diff --git a/test/regress/regress1/sygus/interpol1-push-pop.smt2 b/test/regress/regress1/sygus/interpol1-push-pop.smt2
new file mode 100644 (file)
index 0000000..5ea6d85
--- /dev/null
@@ -0,0 +1,31 @@
+; COMMAND-LINE: --produce-interpols=default --sygus-active-gen=enum --check-interpols -i
+; SCRUBBER: grep -v -E '(\(define-fun)'
+; EXIT: 0
+(set-logic NIA)
+(declare-fun x ( ) Int)
+(declare-fun y ( ) Int)
+(declare-fun z ( ) Int)
+(push)
+(assert (= (* 2 x) y))
+(get-interpol A (distinct (+ (* 2 z) 1) y)
+
+; the grammar for the interpol-to-synthesize
+((Start Bool) (StartInt Int))
+(
+(Start Bool ((< StartInt StartInt)))
+(StartInt Int 
+(y (+ StartInt StartInt) (div StartInt StartInt) (mod StartInt StartInt) 0 1 2))
+)
+)
+(pop)
+
+(assert (= (* 2 y) x))
+(get-interpol A (distinct (+ (* 2 z) 1) x)
+; the grammar for the interpol-to-synthesize
+((Start Bool) (StartInt Int))
+(
+(Start Bool ((< StartInt StartInt)))
+(StartInt Int 
+(x (+ StartInt StartInt) (div StartInt StartInt) (mod StartInt StartInt) 0 1 2))
+)
+)
diff --git a/test/regress/regress1/sygus/interpol3-next.smt2 b/test/regress/regress1/sygus/interpol3-next.smt2
new file mode 100644 (file)
index 0000000..b92a425
--- /dev/null
@@ -0,0 +1,8 @@
+; COMMAND-LINE: --produce-interpols=default --check-interpols -i
+; SCRUBBER: grep -v -E '(\(define-fun)'
+; EXIT: 0
+(set-logic LIA)
+(declare-fun a () Int)
+(assert (> a 1))
+(get-interpol A (> a 0))
+(get-interpol-next)
index 934e0da0da8d8d090ba0743698bb7418b1d51f2e..bdd8201bc504b2e6e3a6841f2737204a28a9d3ea 100644 (file)
@@ -1448,6 +1448,35 @@ TEST_F(TestApiBlackSolver, getInterpolant)
   ASSERT_TRUE(output.getSort().isBoolean());
 }
 
+TEST_F(TestApiBlackSolver, getInterpolantNext)
+{
+  d_solver.setLogic("QF_LIA");
+  d_solver.setOption("produce-interpols", "default");
+  d_solver.setOption("incremental", "true");
+
+  Sort intSort = d_solver.getIntegerSort();
+  Term zero = d_solver.mkInteger(0);
+  Term x = d_solver.mkConst(intSort, "x");
+  Term y = d_solver.mkConst(intSort, "y");
+  Term z = d_solver.mkConst(intSort, "z");
+  // Assumptions for interpolation: x + y > 0 /\ x < 0
+  d_solver.assertFormula(
+      d_solver.mkTerm(GT, d_solver.mkTerm(PLUS, x, y), zero));
+  d_solver.assertFormula(d_solver.mkTerm(LT, x, zero));
+  // Conjecture for interpolation: y + z > 0 \/ z < 0
+  Term conj =
+      d_solver.mkTerm(OR,
+                      d_solver.mkTerm(GT, d_solver.mkTerm(PLUS, y, z), zero),
+                      d_solver.mkTerm(LT, z, zero));
+  Term output;
+  d_solver.getInterpolant(conj, output);
+  Term output2;
+  d_solver.getInterpolantNext(output2);
+
+  // We expect the next output to be distinct
+  ASSERT_TRUE(output != output2);
+}
+
 TEST_F(TestApiBlackSolver, declarePool)
 {
   Sort intSort = d_solver.getIntegerSort();
index 3fb9ca50eb2b4a30b1fa76376dc2bdce2b281d0e..7313405be2dfb61d90e8d6b467b87505dcb1ccf9 100644 (file)
@@ -1439,6 +1439,31 @@ class SolverTest
     assertTrue(output.getSort().isBoolean());
   }
 
+  @Test void getInterpolantNext() throws CVC5ApiException
+  {
+    d_solver.setLogic("QF_LIA");
+    d_solver.setOption("produce-interpols", "default");
+    d_solver.setOption("incremental", "true");
+
+    Sort intSort = d_solver.getIntegerSort();
+    Term zero = d_solver.mkInteger(0);
+    Term x = d_solver.mkConst(intSort, "x");
+    Term y = d_solver.mkConst(intSort, "y");
+    Term z = d_solver.mkConst(intSort, "z");
+
+    d_solver.assertFormula(d_solver.mkTerm(GT, d_solver.mkTerm(PLUS, x, y), zero));
+    d_solver.assertFormula(d_solver.mkTerm(LT, x, zero));
+    Term conj = d_solver.mkTerm(
+        OR, d_solver.mkTerm(GT, d_solver.mkTerm(PLUS, y, z), zero), d_solver.mkTerm(LT, z, zero));
+    Term output = d_solver.getNullTerm();
+    d_solver.getInterpolant(conj, output);
+    Term output2 = d_solver.getNullTerm();
+    d_solver.getInterpolantNext(output2);
+
+    // We expect the next output to be distinct
+    assertNotEquals(output, output2);
+  }
+
   @Test void getOp() throws CVC5ApiException
   {
     Sort bv32 = d_solver.mkBitVectorSort(32);