Add support for get learned literals in the API (#8099)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Fri, 4 Mar 2022 14:37:54 +0000 (08:37 -0600)
committerGitHub <noreply@github.com>
Fri, 4 Mar 2022 14:37:54 +0000 (14:37 +0000)
This command will eventually take a mode; for now it assumes a default implementation. I've opened cvc5/cvc5-wishues#104 to track this.

This is a feature requested by Certora.

27 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/api/python/cvc5.pxd
src/api/python/cvc5.pxi
src/options/smt_options.toml
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/prop/prop_engine.cpp
src/prop/prop_engine.h
src/prop/theory_proxy.cpp
src/prop/theory_proxy.h
src/prop/zero_level_learner.cpp
src/prop/zero_level_learner.h
src/smt/command.cpp
src/smt/command.h
src/smt/solver_engine.cpp
src/smt/solver_engine.h
test/regress/CMakeLists.txt
test/regress/regress1/get-learned-literals.smt2 [new file with mode: 0644]
test/unit/api/cpp/solver_black.cpp
test/unit/api/java/SolverTest.java
test/unit/api/python/test_solver.py

index 51f8b911d5819dfd9215c435d9620371a4c5f3bc..5ffb23e9df81db6da33807ab08d314d23ac1c1bf 100644 (file)
@@ -3013,6 +3013,17 @@ std::vector<Node> Term::termVectorToNodes(const std::vector<Term>& terms)
   return res;
 }
 
+std::vector<Term> Term::nodeVectorToTerms(const Solver* slv,
+                                          const std::vector<Node>& nodes)
+{
+  std::vector<Term> res;
+  for (const Node& n : nodes)
+  {
+    res.push_back(Term(slv, n));
+  }
+  return res;
+}
+
 bool Term::isReal32Value() const
 {
   CVC5_API_TRY_CATCH_BEGIN;
@@ -6997,12 +7008,7 @@ std::vector<Term> Solver::getAssertions(void) const
   /* Can not use
    *   return std::vector<Term>(assertions.begin(), assertions.end());
    * here since constructor is private */
-  std::vector<Term> res;
-  for (const Node& e : assertions)
-  {
-    res.push_back(Term(this, e));
-  }
-  return res;
+  return Term::nodeVectorToTerms(this, assertions);
   ////////
   CVC5_API_TRY_CATCH_END;
 }
@@ -7306,6 +7312,24 @@ std::string Solver::getProof(void) const
   CVC5_API_TRY_CATCH_END;
 }
 
+std::vector<Term> Solver::getLearnedLiterals(void) const
+{
+  CVC5_API_TRY_CATCH_BEGIN;
+  CVC5_API_CHECK(d_slv->getOptions().smt.produceLearnedLiterals)
+      << "Cannot get learned literals unless enabled (try "
+         "--produce-learned-literals)";
+  CVC5_API_RECOVERABLE_CHECK(d_slv->getSmtMode() == SmtMode::UNSAT
+                             || d_slv->getSmtMode() == SmtMode::SAT
+                             || d_slv->getSmtMode() == SmtMode::SAT_UNKNOWN)
+      << "Cannot get learned literals unless after a UNSAT, SAT or UNKNOWN "
+         "response.";
+  //////// all checks before this line
+  std::vector<Node> lits = d_slv->getLearnedLiterals();
+  return Term::nodeVectorToTerms(this, lits);
+  ////////
+  CVC5_API_TRY_CATCH_END;
+}
+
 Term Solver::getValue(const Term& term) const
 {
   CVC5_API_TRY_CATCH_BEGIN;
index e75bef2938777cd4fc5308932a39a443494600be..d3662c832f0ff3e1bd19e7b4cc70a6f2254e7394 100644 (file)
@@ -1585,6 +1585,9 @@ class CVC5_EXPORT Term
  private:
   /** Helper to convert a vector of Terms to internal Nodes. */
   std::vector<Node> static termVectorToNodes(const std::vector<Term>& terms);
+  /** Helper to convert a vector of internal Nodes to Terms. */
+  std::vector<Term> static nodeVectorToTerms(const Solver* slv,
+                                             const std::vector<Node>& nodes);
 
   /** Helper method to collect all elements of a set. */
   static void collectSet(std::set<Term>& set,
@@ -4181,6 +4184,14 @@ class CVC5_EXPORT Solver
    */
   std::string getProof() const;
 
+  /**
+   * Get learned literals
+   *
+   * @return a list of literals that were learned at top-level. In other words,
+   * these are literals that are entailed by the current set of assertions.
+   */
+  std::vector<Term> getLearnedLiterals() const;
+
   /**
    * Get the value of the given term in the current model.
    *
index 43493f784b3150ad1ea572f15d428cbe18bb3c61..f1ad0cea681eaa3b7f27f3e4d8a3f10988e6acb4 100644 (file)
@@ -1760,6 +1760,21 @@ public class Solver implements IPointer, AutoCloseable
    */
   // TODO: void echo(std::ostream& out, String  str)
 
+  /**
+   * Get a list of literals that are entailed by the current set of assertions
+   * SMT-LIB:
+   * {@code
+   * ( get-learned-literals )
+   * }
+   * @return the list of learned literals
+   */
+  public Term[] getLearnedLiterals() {
+    long[] retPointers = getLearnedLiterals(pointer);
+    return Utils.getTerms(this, retPointers);
+  }
+
+  private native long[] getLearnedLiterals(long pointer);
+
   /**
    * Get the list of asserted formulas.
    * SMT-LIB:
index ec54b09b749e0686c5bb594939ebf8c1476d91fb..9af316cbf68ff7cb56867d102bfe9b690ff02f3a 100644 (file)
@@ -1783,6 +1783,22 @@ Java_io_github_cvc5_api_Solver_defineFunsRec(JNIEnv* env,
   CVC5_JAVA_API_TRY_CATCH_END(env);
 }
 
+/*
+ * Class:     io_github_cvc5_api_Solver
+ * Method:    getLearnedLiterals
+ * Signature: (J)[J
+ */
+JNIEXPORT jlongArray JNICALL Java_io_github_cvc5_api_Solver_getLearnedLiterals(
+    JNIEnv* env, jobject, jlong pointer)
+{
+  CVC5_JAVA_API_TRY_CATCH_BEGIN;
+  Solver* solver = reinterpret_cast<Solver*>(pointer);
+  std::vector<Term> assertions = solver->getLearnedLiterals();
+  jlongArray ret = getPointersFromObjects<Term>(env, assertions);
+  return ret;
+  CVC5_JAVA_API_TRY_CATCH_END_RETURN(env, nullptr);
+}
+
 /*
  * Class:     io_github_cvc5_api_Solver
  * Method:    getAssertions
index 357d5d14941dc7464f091327b2f2a4ddf350c2be..0950283655033392408d5a50b694f35939d31a0d 100644 (file)
@@ -273,6 +273,7 @@ cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api":
                           Term term, bint glbl) except +
         Term defineFunsRec(vector[Term]& funs, vector[vector[Term]]& bound_vars,
                            vector[Term]& terms, bint glbl) except +
+        vector[Term] getLearnedLiterals() except +
         vector[Term] getAssertions() except +
         string getInfo(const string& flag) except +
         string getOption(string& option) except +
index 03bb2c9d38deef0bf813468f66f0b59b6eaac89a..d843d55edcf8a721c0e79d42772040ca01d79bbe 100644 (file)
@@ -1944,6 +1944,24 @@ cdef class Solver:
         for t in terms:
             vf.push_back((<Term?> t).cterm)
 
+    def getLearnedLiterals(self):
+        """Get a list of literals that are entailed by the current set of assertions
+
+        SMT-LIB:
+
+        .. code-block:: smtlib
+
+            ( get-learned-literals )
+
+        :return: the list of literals
+        """
+        lits = []
+        for a in self.csolver.getLearnedLiterals():
+            term = Term(self)
+            term.cterm = a
+            lits.append(term)
+        return lits
+
     def getAssertions(self):
         """Get the list of asserted formulas.
 
index e37d84d1ae5adc6095e58e2359b95d0462c4f636..8e961a3bd4b7fbea75f7c26986ec85c35f86c406 100644 (file)
@@ -116,6 +116,14 @@ name   = "SMT Layer"
   name = "values"
   help = "Block models based on the concrete model values for the free variables."
 
+[[option]]
+  name       = "produceLearnedLiterals"
+  category   = "regular"
+  long       = "produce-learned-literals"
+  type       = "bool"
+  default    = "false"
+  help       = "produce learned literals, support get-learned-literals"
+
 [[option]]
   name       = "produceProofs"
   category   = "regular"
index 355a3469e44934b774c1b6f87ac418654c4ebbd7..ae935b7aac272dc38fb369f17f4fcbb6bd2d150c 100644 (file)
@@ -404,6 +404,9 @@ command [std::unique_ptr<cvc5::Command>* cmd]
   | /* get-difficulty */
     GET_DIFFICULTY_TOK { PARSER_STATE->checkThatLogicIsSet(); }
     { cmd->reset(new GetDifficultyCommand); }
+  | /* get-learned-literals */
+    GET_LEARNED_LITERALS_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+    { cmd->reset(new GetLearnedLiteralsCommand); }
   | /* push */
     PUSH_TOK { PARSER_STATE->checkThatLogicIsSet(); }
     ( k=INTEGER_LITERAL
@@ -2204,6 +2207,7 @@ GET_PROOF_TOK : 'get-proof';
 GET_UNSAT_ASSUMPTIONS_TOK : 'get-unsat-assumptions';
 GET_UNSAT_CORE_TOK : 'get-unsat-core';
 GET_DIFFICULTY_TOK : 'get-difficulty';
+GET_LEARNED_LITERALS_TOK : { !PARSER_STATE->strictModeEnabled() }? 'get-learned-literals';
 EXIT_TOK : 'exit';
 RESET_TOK : 'reset';
 RESET_ASSERTIONS_TOK : 'reset-assertions';
index 12b52e284269d0e355cc8ffd715bbbb91722cb05..f3909ae3f689f2def7c2b0934d4830a935c8c6dd 100644 (file)
@@ -445,6 +445,11 @@ void Printer::toStreamCmdGetDifficulty(std::ostream& out) const
   printUnknownCommand(out, "get-difficulty");
 }
 
+void Printer::toStreamCmdGetLearnedLiterals(std::ostream& out) const
+{
+  printUnknownCommand(out, "get-learned-literals");
+}
+
 void Printer::toStreamCmdGetAssertions(std::ostream& out) const
 {
   printUnknownCommand(out, "get-assertions");
index 2a92830010ff7b9d1547c038049c0b5e5433b02e..33824d42deb80f3fa30a43dac83dbe73a2bd47cf 100644 (file)
@@ -226,6 +226,9 @@ class Printer
   /** Print get-difficulty command */
   virtual void toStreamCmdGetDifficulty(std::ostream& out) const;
 
+  /** Print get-learned-literals command */
+  virtual void toStreamCmdGetLearnedLiterals(std::ostream& out) const;
+
   /** Print get-assertions command */
   virtual void toStreamCmdGetAssertions(std::ostream& out) const;
 
index 773d5fd4bb53f6b16bdb64cd7d88d01528d10a57..80bf2b601dd17091cb3cd1efcf6a7ea9f0f72f3e 100644 (file)
@@ -1726,6 +1726,11 @@ void Smt2Printer::toStreamCmdGetDifficulty(std::ostream& out) const
   out << "(get-difficulty)" << std::endl;
 }
 
+void Smt2Printer::toStreamCmdGetLearnedLiterals(std::ostream& out) const
+{
+  out << "(get-learned-literals)" << std::endl;
+}
+
 void Smt2Printer::toStreamCmdSetBenchmarkLogic(std::ostream& out,
                                                const std::string& logic) const
 {
index 4170fe88fdeb0eaa9db6ed7346f8985839d907d0..6f78f96689cca61f5aa18c1b9f14e1e939046b27 100644 (file)
@@ -200,6 +200,9 @@ class Smt2Printer : public cvc5::Printer
   /** Print get-difficulty command */
   void toStreamCmdGetDifficulty(std::ostream& out) const override;
 
+  /** Print get-learned-literals command */
+  void toStreamCmdGetLearnedLiterals(std::ostream& out) const override;
+
   /** Print get-assertions command */
   void toStreamCmdGetAssertions(std::ostream& out) const override;
 
index bf9a80008eb4861ea95758efe398cb49452b282c..734da0b7697f718a6b3a45d24196807bc72aa2a9 100644 (file)
@@ -672,7 +672,7 @@ std::shared_ptr<ProofNode> PropEngine::getRefutation()
   return cdp.getProofFor(fnode);
 }
 
-const std::unordered_set<Node>& PropEngine::getLearnedZeroLevelLiterals() const
+std::vector<Node> PropEngine::getLearnedZeroLevelLiterals() const
 {
   return d_theoryProxy->getLearnedZeroLevelLiterals();
 }
index 96cd2ce1d12e79f2a6b8034a73fdab078dd87d50..fc3c68ca54ae31526a94079c080ed57c0d109997 100644 (file)
@@ -295,7 +295,7 @@ class PropEngine : protected EnvObj
   std::shared_ptr<ProofNode> getRefutation();
 
   /** Get the zero-level assertions */
-  const std::unordered_set<Node>& getLearnedZeroLevelLiterals() const;
+  std::vector<Node> getLearnedZeroLevelLiterals() const;
 
  private:
   /** Dump out the satisfying assignment (after SAT result) */
index 35724872672439c0437ba56079845a9396680137..44bc79d4364b7597daf15e08ba22bff569ccff3b 100644 (file)
@@ -52,7 +52,8 @@ TheoryProxy::TheoryProxy(Env& env,
       d_skdm(skdm),
       d_zll(nullptr)
 {
-  bool trackTopLevelLearned = isOutputOn(OutputTag::LEARNED_LITS);
+  bool trackTopLevelLearned = isOutputOn(OutputTag::LEARNED_LITS)
+                              || options().smt.produceLearnedLiterals;
   if (trackTopLevelLearned)
   {
     d_zll = std::make_unique<ZeroLevelLearner>(env, propEngine);
@@ -289,10 +290,13 @@ void TheoryProxy::getSkolems(TNode node,
 
 void TheoryProxy::preRegister(Node n) { d_theoryEngine->preRegister(n); }
 
-const std::unordered_set<Node>& TheoryProxy::getLearnedZeroLevelLiterals() const
+std::vector<Node> TheoryProxy::getLearnedZeroLevelLiterals() const
 {
-  Assert(d_zll != nullptr);
-  return d_zll->getLearnedZeroLevelLiterals();
+  if (d_zll != nullptr)
+  {
+    return d_zll->getLearnedZeroLevelLiterals();
+  }
+  return {};
 }
 
 }  // namespace prop
index 85070b4c7e4474411b75b753e2b0a4d9bfe6c798..3e95f4a03e7b32819eb83ff893949e90bb24e38b 100644 (file)
@@ -154,7 +154,7 @@ class TheoryProxy : protected EnvObj, public Registrar
   void preRegister(Node n) override;
 
   /** Get the zero-level assertions */
-  const std::unordered_set<Node>& getLearnedZeroLevelLiterals() const;
+  std::vector<Node> getLearnedZeroLevelLiterals() const;
 
  private:
   /** The prop engine we are using. */
index 3562545b89fcb87e9569ee12f7a866e8241503ee..b5415f7140af792e3bfddc838f559e7b1685f3b6 100644 (file)
@@ -30,7 +30,11 @@ namespace prop {
 ZeroLevelLearner::ZeroLevelLearner(Env& env, PropEngine* propEngine)
     : EnvObj(env),
       d_propEngine(propEngine),
+      d_levelZeroAsserts(userContext()),
+      d_levelZeroAssertsLearned(userContext()),
       d_nonZeroAssert(context(), false),
+      d_ppnAtoms(userContext()),
+      d_pplAtoms(userContext()),
       d_assertNoLearnCount(0)
 {
 }
@@ -39,7 +43,7 @@ ZeroLevelLearner::~ZeroLevelLearner() {}
 
 void ZeroLevelLearner::getAtoms(TNode a,
                                 std::unordered_set<TNode>& visited,
-                                std::unordered_set<TNode>& ppLits)
+                                NodeSet& ppLits)
 {
   std::vector<TNode> visit;
   TNode cur;
@@ -67,7 +71,6 @@ void ZeroLevelLearner::notifyInputFormulas(
     const std::vector<Node>& ppl)
 {
   d_assertNoLearnCount = 0;
-  d_ppnAtoms.clear();
   // Copy the preprocessed assertions and skolem map information directly
   // Also, compute the set of literals in the preprocessed assertions
   std::unordered_set<TNode> visited;
@@ -146,10 +149,14 @@ void ZeroLevelLearner::notifyAsserted(TNode assertion)
   }
 }
 
-const std::unordered_set<Node>& ZeroLevelLearner::getLearnedZeroLevelLiterals()
-    const
+std::vector<Node> ZeroLevelLearner::getLearnedZeroLevelLiterals() const
 {
-  return d_levelZeroAssertsLearned;
+  std::vector<Node> ret;
+  for (const Node& n : d_levelZeroAssertsLearned)
+  {
+    ret.push_back(n);
+  }
+  return ret;
 }
 
 }  // namespace prop
index e9979e723e2c62d200d7f80c4fe5700e66867bf9..c15e04e98153d83ff7ece35462f524ff4c9bdc62 100644 (file)
@@ -58,30 +58,30 @@ class ZeroLevelLearner : protected EnvObj
   void notifyAsserted(TNode assertion);
 
   /** Get the zero-level assertions */
-  const std::unordered_set<Node>& getLearnedZeroLevelLiterals() const;
+  std::vector<Node> getLearnedZeroLevelLiterals() const;
 
  private:
   static void getAtoms(TNode a,
                        std::unordered_set<TNode>& visited,
-                       std::unordered_set<TNode>& ppLits);
+                       NodeSet& ppLits);
 
   /** The prop engine we are using. */
   PropEngine* d_propEngine;
 
   /** Set of literals that hold at level 0 */
-  std::unordered_set<TNode> d_levelZeroAsserts;
+  NodeSet d_levelZeroAsserts;
 
   /** Set of learnable literals that hold at level 0 */
-  std::unordered_set<Node> d_levelZeroAssertsLearned;
+  NodeSet d_levelZeroAssertsLearned;
 
   /** Whether we have seen an assertion level > 0 */
   context::CDO<bool> d_nonZeroAssert;
 
   /** Preprocessed literals that are not learned */
-  std::unordered_set<TNode> d_ppnAtoms;
+  NodeSet d_ppnAtoms;
 
   /** Already learned TEMPORARY */
-  std::unordered_set<TNode> d_pplAtoms;
+  NodeSet d_pplAtoms;
 
   /** Current counter of assertions */
   size_t d_assertNoLearnCount;
index 7a81aa0a0ae2d723896098dea6d13d9f2a4cbe7a..f96488452dd07fbaccafe66dc394a1dcd1920750 100644 (file)
@@ -2549,6 +2549,72 @@ void GetDifficultyCommand::toStream(std::ostream& out,
   Printer::getPrinter(language)->toStreamCmdGetDifficulty(out);
 }
 
+/* -------------------------------------------------------------------------- */
+/* class GetLearnedLiteralsCommand */
+/* -------------------------------------------------------------------------- */
+
+GetLearnedLiteralsCommand::GetLearnedLiteralsCommand() {}
+void GetLearnedLiteralsCommand::invoke(api::Solver* solver, SymbolManager* sm)
+{
+  try
+  {
+    d_result = solver->getLearnedLiterals();
+
+    d_commandStatus = CommandSuccess::instance();
+  }
+  catch (api::CVC5ApiRecoverableException& e)
+  {
+    d_commandStatus = new CommandRecoverableFailure(e.what());
+  }
+  catch (exception& e)
+  {
+    d_commandStatus = new CommandFailure(e.what());
+  }
+}
+
+void GetLearnedLiteralsCommand::printResult(std::ostream& out) const
+{
+  if (!ok())
+  {
+    this->Command::printResult(out);
+  }
+  else
+  {
+    out << "(" << std::endl;
+    for (const api::Term& lit : d_result)
+    {
+      out << lit << std::endl;
+    }
+    out << ")" << std::endl;
+  }
+}
+
+const std::vector<api::Term>& GetLearnedLiteralsCommand::getLearnedLiterals()
+    const
+{
+  return d_result;
+}
+
+Command* GetLearnedLiteralsCommand::clone() const
+{
+  GetLearnedLiteralsCommand* c = new GetLearnedLiteralsCommand;
+  c->d_result = d_result;
+  return c;
+}
+
+std::string GetLearnedLiteralsCommand::getCommandName() const
+{
+  return "get-learned-literals";
+}
+
+void GetLearnedLiteralsCommand::toStream(std::ostream& out,
+                                         int toDepth,
+                                         size_t dag,
+                                         Language language) const
+{
+  Printer::getPrinter(language)->toStreamCmdGetLearnedLiterals(out);
+}
+
 /* -------------------------------------------------------------------------- */
 /* class GetAssertionsCommand                                                 */
 /* -------------------------------------------------------------------------- */
index 9a4b04196181c113408016f229dca981d003f9c6..b250d0b59afa381107d8b34b94de996fcea6af16 100644 (file)
@@ -1254,6 +1254,27 @@ class CVC5_EXPORT GetDifficultyCommand : public Command
   std::map<api::Term, api::Term> d_result;
 };
 
+class CVC5_EXPORT GetLearnedLiteralsCommand : public Command
+{
+ public:
+  GetLearnedLiteralsCommand();
+  const std::vector<api::Term>& getLearnedLiterals() 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 result of the get learned literals call */
+  std::vector<api::Term> d_result;
+};
+
 class CVC5_EXPORT GetAssertionsCommand : public Command
 {
  protected:
index 1223e9875ebc4243fec3457297dd601ab6b5c26c..583eaae7ba9de9c718f13ecc27c09953aae87dde 100644 (file)
@@ -1272,6 +1272,17 @@ Node SolverEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first; }
 
 Node SolverEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second; }
 
+std::vector<Node> SolverEngine::getLearnedLiterals()
+{
+  Trace("smt") << "SMT getLearnedLiterals()" << std::endl;
+  SolverEngineScope smts(this);
+  // note that the default mode for learned literals is via the prop engine,
+  // although other modes could use the preprocessor
+  PropEngine* pe = getPropEngine();
+  Assert(pe != nullptr);
+  return pe->getLearnedZeroLevelLiterals();
+}
+
 void SolverEngine::checkProof()
 {
   Assert(d_env->getOptions().smt.produceProofs);
index fd1057f3ddc40af7ddefa21a78e10ee29e40515f..c6cd77dd753f8ecc99cd8e75f135e889e256ecf8 100644 (file)
@@ -271,6 +271,14 @@ class CVC5_EXPORT SolverEngine
   /** When using separation logic, obtain the expression for nil.  */
   Node getSepNilExpr();
 
+  /**
+   * Get the list of top-level learned literals that are entailed by the current
+   * set of assertions.
+   *
+   * TODO (wishue #104): implement for different modes
+   */
+  std::vector<Node> getLearnedLiterals();
+
   /**
    * Get an aspect of the current SMT execution environment.
    * @throw OptionException
index 0e1e84f1ab74bc9d54b2abac3186aab91f14eff7..94e9d3c41d72bf2c06e616b43bc258c3b1ed70e5 100644 (file)
@@ -1863,6 +1863,7 @@ set(regress_1_tests
   regress1/fmf/sort-inf-int.smt2
   regress1/fmf/with-ind-104-core.smt2
   regress1/gensys_brn001.smt2
+  regress1/get-learned-literals.smt2
   regress1/ho/bug_freeVar_BDD_General_data_270.p
   regress1/ho/bug_freevar_PHI004^4-delta.smt2
   regress1/ho/bound_var_bug.p
diff --git a/test/regress/regress1/get-learned-literals.smt2 b/test/regress/regress1/get-learned-literals.smt2
new file mode 100644 (file)
index 0000000..d52a931
--- /dev/null
@@ -0,0 +1,17 @@
+; SCRUBBER: sed -e 's/(>=.*/learned-ineq/'
+; EXPECT: sat
+; EXPECT: (
+; EXPECT: learned-ineq
+; EXPECT: learned-ineq
+; EXPECT: )
+(set-logic ALL)
+(set-option :produce-learned-literals true)
+(declare-fun x () Int)
+(declare-fun y () Int)
+(declare-fun z () Int)
+
+(assert (> x 5))
+(assert (< y 4))
+(assert (or (< x y) (> z 0)))
+(check-sat)
+(get-learned-literals)
\ No newline at end of file
index ac6e4543ef520966f41a73fd420687e9f40b79ad..fa573f5da2b24a57cafe0e32d258812fffd6bd7c 100644 (file)
@@ -1694,6 +1694,8 @@ TEST_F(TestApiBlackSolver, getDifficulty3)
   Term ten = d_solver.mkInteger(10);
   Term f0 = d_solver.mkTerm(GEQ, x, ten);
   Term f1 = d_solver.mkTerm(GEQ, zero, x);
+  d_solver.assertFormula(f0);
+  d_solver.assertFormula(f1);
   d_solver.checkSat();
   std::map<Term, Term> dmap;
   ASSERT_NO_THROW(dmap = d_solver.getDifficulty());
@@ -1705,6 +1707,32 @@ TEST_F(TestApiBlackSolver, getDifficulty3)
   }
 }
 
+TEST_F(TestApiBlackSolver, getLearnedLiterals)
+{
+  d_solver.setOption("produce-learned-literals", "true");
+  // cannot ask before a check sat
+  ASSERT_THROW(d_solver.getLearnedLiterals(), CVC5ApiException);
+  d_solver.checkSat();
+  ASSERT_NO_THROW(d_solver.getLearnedLiterals());
+}
+
+TEST_F(TestApiBlackSolver, getLearnedLiterals2)
+{
+  d_solver.setOption("produce-learned-literals", "true");
+  Sort intSort = d_solver.getIntegerSort();
+  Term x = d_solver.mkConst(intSort, "x");
+  Term y = d_solver.mkConst(intSort, "y");
+  Term zero = d_solver.mkInteger(0);
+  Term ten = d_solver.mkInteger(10);
+  Term f0 = d_solver.mkTerm(GEQ, x, ten);
+  Term f1 = d_solver.mkTerm(
+      OR, d_solver.mkTerm(GEQ, zero, x), d_solver.mkTerm(GEQ, y, zero));
+  d_solver.assertFormula(f0);
+  d_solver.assertFormula(f1);
+  d_solver.checkSat();
+  ASSERT_NO_THROW(d_solver.getLearnedLiterals());
+}
+
 TEST_F(TestApiBlackSolver, getValue1)
 {
   d_solver.setOption("produce-models", "false");
index 80921481a62eae54fb108b3abee78cdb5ab2c86a..6bcd38e92621579960a61050b88f928d902bf52a 100644 (file)
@@ -1669,6 +1669,8 @@ class SolverTest
     Term ten = d_solver.mkInteger(10);
     Term f0 = d_solver.mkTerm(GEQ, x, ten);
     Term f1 = d_solver.mkTerm(GEQ, zero, x);
+    d_solver.assertFormula(f0);
+    d_solver.assertFormula(f1);
     d_solver.checkSat();
     Map<Term, Term> dmap = d_solver.getDifficulty();
     // difficulty should map assertions to integer values
@@ -1679,6 +1681,32 @@ class SolverTest
     }
   }
 
+  @Test
+  void getLearnedLiterals() {
+    d_solver.setOption("produce-learned-literals", "true");
+    // cannot ask before a check sat
+    assertThrows(CVC5ApiException.class, () -> d_solver.getLearnedLiterals());
+    d_solver.checkSat();
+    assertDoesNotThrow(() -> d_solver.getLearnedLiterals());
+  }
+
+  @Test
+  void getLearnedLiterals2() {
+    d_solver.setOption("produce-learned-literals", "true");
+    Sort intSort = d_solver.getIntegerSort();
+    Term x = d_solver.mkConst(intSort, "x");
+    Term y = d_solver.mkConst(intSort, "y");
+    Term zero = d_solver.mkInteger(0);
+    Term ten = d_solver.mkInteger(10);
+    Term f0 = d_solver.mkTerm(GEQ, x, ten);
+    Term f1 = d_solver.mkTerm(
+        OR, d_solver.mkTerm(GEQ, zero, x), d_solver.mkTerm(GEQ, y, zero));
+    d_solver.assertFormula(f0);
+    d_solver.assertFormula(f1);
+    d_solver.checkSat();
+    assertDoesNotThrow(() -> d_solver.getLearnedLiterals());
+  }
+
   @Test void getValue1()
   {
     d_solver.setOption("produce-models", "false");
index 9b89f71875c6681028d0dae7607b618c0769910c..24f180c7b4ffc2ab87e7b4900e69dc9ac15bfdb7 100644 (file)
@@ -1259,6 +1259,27 @@ def test_get_unsat_core3(solver):
     res = solver.checkSat()
     assert res.isUnsat()
 
+def test_learned_literals(solver):
+    solver.setOption("produce-learned-literals", "true")
+    with pytest.raises(RuntimeError):
+        solver.getLearnedLiterals()
+    solver.checkSat()
+    solver.getLearnedLiterals()
+
+def test_learned_literals2(solver):
+    solver.setOption("produce-learned-literals", "true")
+    intSort = solver.getIntegerSort()
+    x = solver.mkConst(intSort, "x")
+    y = solver.mkConst(intSort, "y")
+    zero = solver.mkInteger(0)
+    ten = solver.mkInteger(10)
+    f0 = solver.mkTerm(Kind.Geq, x, ten)
+    f1 = solver.mkTerm(Kind.Or, solver.mkTerm(Kind.Geq, zero, x), solver.mkTerm(Kind.Geq, y, zero))
+    solver.assertFormula(f0)
+    solver.assertFormula(f1)
+    solver.checkSat()
+    solver.getLearnedLiterals()
+
 
 def test_get_value1(solver):
     solver.setOption("produce-models", "false")