Add -o learned-lits to output learned literals (#7934)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Wed, 12 Jan 2022 23:28:02 +0000 (17:28 -0600)
committerGitHub <noreply@github.com>
Wed, 12 Jan 2022 23:28:02 +0000 (23:28 +0000)
Prints both literals learned during preprocessing, and during search.

This feature was recently requested by Cetora.

14 files changed:
src/CMakeLists.txt
src/options/base_options.toml
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 [new file with mode: 0644]
src/prop/zero_level_learner.h [new file with mode: 0644]
src/smt/preprocessor.cpp
src/smt/preprocessor.h
src/smt/smt_solver.cpp
src/theory/substitutions.h
test/regress/CMakeLists.txt
test/regress/regress0/printer/learned-lit-output.smt2 [new file with mode: 0644]

index 830c70ca9855cee69b101ec91c078e10a1574b51..b17f82ac6d9593b8685dd76fdccda6a0e6d7ce95 100644 (file)
@@ -277,6 +277,8 @@ libcvc5_add_sources(
   prop/skolem_def_manager.h
   prop/theory_proxy.cpp
   prop/theory_proxy.h
+  prop/zero_level_learner.cpp
+  prop/zero_level_learner.h
   smt/abduction_solver.cpp
   smt/abduction_solver.h
   smt/abstract_values.cpp
index 415dbf9f39ad4c57bd6fc20b2747ac9083bb709e..86ce22c6f542b4787c979d6fde7e74fd84dd57b7 100644 (file)
@@ -186,8 +186,13 @@ name   = "Base"
 [[option.mode.RAW_BENCHMARK]]
   name = "raw-benchmark"
   help = "print the benchmark back on the output verbatim as it is processed"
-  description = "With ``-o raw_benchmark``, cvc5 prints the benchmark back just as it has been parsed."
+  description = "With ``-o raw-benchmark``, cvc5 prints the benchmark back just as it has been parsed."
   example-file = "regress0/datatypes/datatype-dump.cvc.smt2"
+[[option.mode.LEARNED_LITS]]
+  name = "learned-lits"
+  help = "print input literals that hold globally"
+  description = "With ``-o learned-lits``, cvc5 prints input literals that it has learned to hold globally."
+  example-file = "regress0/printer/learned-lit-output.smt2"
 
 # Stores then enabled output tags.
 [[option]]
index df18f9a851dac4c5300b4b5d91638fbdecd7361c..b2b4327235dd222e92238980afc0c4875ba2b6a1 100644 (file)
@@ -175,28 +175,11 @@ TrustNode PropEngine::removeItes(TNode node,
 
 void PropEngine::assertInputFormulas(
     const std::vector<Node>& assertions,
-    std::unordered_map<size_t, Node>& skolemMap)
+    std::unordered_map<size_t, Node>& skolemMap,
+    const std::vector<Node>& ppl)
 {
   Assert(!d_inCheckSat) << "Sat solver in solve()!";
-  // notify the theory engine of preprocessed assertions
-  d_theoryEngine->notifyPreprocessedAssertions(assertions);
-  // Now, notify the theory proxy of the assertions and skolem definitions.
-  // Notice we do this before asserting the formulas to the CNF stream below,
-  // since (preregistration) lemmas may occur during calls to assertInternal.
-  // These lemmas we want to be notified about after the theory proxy has
-  // been notified about all input assertions.
-  std::unordered_map<size_t, Node>::iterator it;
-  for (size_t i = 0, asize = assertions.size(); i < asize; i++)
-  {
-    // is the assertion a skolem definition?
-    it = skolemMap.find(i);
-    Node skolem;
-    if (it != skolemMap.end())
-    {
-      skolem = it->second;
-    }
-    d_theoryProxy->notifyAssertion(assertions[i], skolem, false);
-  }
+  d_theoryProxy->notifyInputFormulas(assertions, skolemMap, ppl);
   for (const Node& node : assertions)
   {
     Debug("prop") << "assertFormula(" << node << ")" << std::endl;
@@ -418,7 +401,8 @@ Result PropEngine::checkSat() {
   }
 
   Debug("prop") << "PropEngine::checkSat() => " << result << std::endl;
-  if(result == SAT_VALUE_TRUE && d_theoryEngine->isIncomplete()) {
+  if (result == SAT_VALUE_TRUE && d_theoryProxy->isIncomplete())
+  {
     return Result(Result::SAT_UNKNOWN, Result::INCOMPLETE);
   }
   return Result(result == SAT_VALUE_TRUE ? Result::SAT : Result::UNSAT);
@@ -691,5 +675,10 @@ std::shared_ptr<ProofNode> PropEngine::getRefutation()
   return cdp.getProofFor(fnode);
 }
 
+const std::unordered_set<Node>& PropEngine::getLearnedZeroLevelLiterals() const
+{
+  return d_theoryProxy->getLearnedZeroLevelLiterals();
+}
+
 }  // namespace prop
 }  // namespace cvc5
index 53062ad92b10a9a4a9a2a83e54fa4958fb484275..0497c6738268bca3d224c46bb7407a7f2d1c4991 100644 (file)
@@ -31,7 +31,6 @@
 
 namespace cvc5 {
 
-class Env;
 class ResourceManager;
 class ProofNodeManager;
 class TheoryEngine;
@@ -109,9 +108,11 @@ class PropEngine : protected EnvObj
    * @param skolemMap a map which says which skolem (if any) each assertion
    * corresponds to. For example, if (ite C (= k a) (= k b)) is the i^th
    * assertion, then skolemMap may contain the entry { i -> k }.
+   * @param ppl the list of preprocessed learned literals
    */
   void assertInputFormulas(const std::vector<Node>& assertions,
-                           std::unordered_map<size_t, Node>& skolemMap);
+                           std::unordered_map<size_t, Node>& skolemMap,
+                           const std::vector<Node>& ppl);
 
   /**
    * Converts the given formula to CNF and assert the CNF to the SAT solver.
@@ -293,6 +294,9 @@ class PropEngine : protected EnvObj
   /** Return the prop engine proof for assumption-based unsat cores. */
   std::shared_ptr<ProofNode> getRefutation();
 
+  /** Get the zero-level assertions */
+  const std::unordered_set<Node>& getLearnedZeroLevelLiterals() const;
+
  private:
   /** Dump out the satisfying assignment (after SAT result) */
   void printSatisfyingAssignment();
index 269921da274638d1771781226095fb75b1bd22d8..58a7fb6669f07d830b78cd93a18c266324ff52ea 100644 (file)
 
 #include "context/context.h"
 #include "decision/decision_engine.h"
+#include "expr/node_algorithm.h"
+#include "options/base_options.h"
 #include "options/decision_options.h"
 #include "options/smt_options.h"
 #include "prop/cnf_stream.h"
 #include "prop/prop_engine.h"
 #include "prop/skolem_def_manager.h"
+#include "prop/zero_level_learner.h"
 #include "smt/env.h"
 #include "smt/smt_statistics_registry.h"
 #include "theory/rewriter.h"
@@ -44,10 +47,16 @@ TheoryProxy::TheoryProxy(Env& env,
       d_decisionEngine(decisionEngine),
       d_dmNeedsActiveDefs(d_decisionEngine->needsActiveSkolemDefs()),
       d_theoryEngine(theoryEngine),
-      d_queue(env.getContext()),
+      d_queue(context()),
       d_tpp(env, *theoryEngine),
-      d_skdm(skdm)
+      d_skdm(skdm),
+      d_zll(nullptr)
 {
+  bool trackTopLevelLearned = isOutputOn(OutputTag::LEARNED_LITS);
+  if (trackTopLevelLearned)
+  {
+    d_zll = std::make_unique<ZeroLevelLearner>(env, propEngine);
+  }
 }
 
 TheoryProxy::~TheoryProxy() {
@@ -62,6 +71,39 @@ void TheoryProxy::presolve()
   d_theoryEngine->presolve();
 }
 
+void TheoryProxy::notifyInputFormulas(
+    const std::vector<Node>& assertions,
+    std::unordered_map<size_t, Node>& skolemMap,
+    const std::vector<Node>& ppl)
+{
+  // notify the theory engine of preprocessed assertions
+  d_theoryEngine->notifyPreprocessedAssertions(assertions);
+  // Now, notify the theory proxy of the assertions and skolem definitions.
+  // Notice we do this before asserting the formulas to the CNF stream below,
+  // since (preregistration) lemmas may occur during calls to assertInternal.
+  // These lemmas we want to be notified about after the theory proxy has
+  // been notified about all input assertions.
+  std::unordered_map<size_t, Node>::iterator it;
+  for (size_t i = 0, asize = assertions.size(); i < asize; i++)
+  {
+    // is the assertion a skolem definition?
+    it = skolemMap.find(i);
+    Node skolem;
+    if (it != skolemMap.end())
+    {
+      skolem = it->second;
+    }
+    notifyAssertion(assertions[i], skolem, false);
+  }
+
+  // the zero-level learner needs to be notified of the input assertions, to
+  // determine what is learnable
+  if (d_zll != nullptr)
+  {
+    d_zll->notifyInputFormulas(assertions, skolemMap, ppl);
+  }
+}
+
 void TheoryProxy::notifyAssertion(Node a, TNode skolem, bool isLemma)
 {
   if (skolem.isNull())
@@ -83,6 +125,11 @@ void TheoryProxy::theoryCheck(theory::Theory::Effort effort) {
   while (!d_queue.empty()) {
     TNode assertion = d_queue.front();
     d_queue.pop();
+    if (d_zll != nullptr)
+    {
+      // check if this corresponds to a zero-level asserted literal
+      d_zll->notifyAsserted(assertion);
+    }
     // now, assert to theory engine
     d_theoryEngine->assertFact(assertion);
     if (d_dmNeedsActiveDefs)
@@ -177,6 +224,11 @@ bool TheoryProxy::theoryNeedCheck() const {
   return d_theoryEngine->needCheck();
 }
 
+bool TheoryProxy::isIncomplete() const
+{
+  return d_theoryEngine->isIncomplete();
+}
+
 TNode TheoryProxy::getNode(SatLiteral lit) {
   return d_cnfStream->getNode(lit);
 }
@@ -237,5 +289,11 @@ void TheoryProxy::getSkolems(TNode node,
 
 void TheoryProxy::preRegister(Node n) { d_theoryEngine->preRegister(n); }
 
+const std::unordered_set<Node>& TheoryProxy::getLearnedZeroLevelLiterals() const
+{
+  Assert(d_zll != nullptr);
+  return d_zll->getLearnedZeroLevelLiterals();
+}
+
 }  // namespace prop
 }  // namespace cvc5
index 8e998583d06a9a733855e4e867da5ea44469ab68..85070b4c7e4474411b75b753e2b0a4d9bfe6c798 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <unordered_set>
 
+#include "context/cdhashset.h"
 #include "context/cdqueue.h"
 #include "expr/node.h"
 #include "proof/trust_node.h"
@@ -44,12 +45,15 @@ namespace prop {
 class PropEngine;
 class CnfStream;
 class SkolemDefManager;
+class ZeroLevelLearner;
 
 /**
  * The proxy class that allows the SatSolver to communicate with the theories
  */
 class TheoryProxy : protected EnvObj, public Registrar
 {
+  using NodeSet = context::CDHashSet<Node>;
+
  public:
   TheoryProxy(Env& env,
               PropEngine* propEngine,
@@ -65,6 +69,17 @@ class TheoryProxy : protected EnvObj, public Registrar
   /** Presolve, which calls presolve for the modules managed by this class */
   void presolve();
 
+  /**
+   * Notifies this module of the input assertions.
+   * @param assertion The preprocessed input assertions,
+   * @param skolemMap Map from indices in assertion to the Skolem they are
+   * the definition for
+   * @param ppl The preprocessed learned literals, that is, the literals that
+   * hold at top-level, as computed by the circuit propagator.
+   */
+  void notifyInputFormulas(const std::vector<Node>& assertions,
+                           std::unordered_map<size_t, Node>& skolemMap,
+                           const std::vector<Node>& ppl);
   /**
    * Notify a lemma or input assertion, possibly corresponding to a skolem
    * definition.
@@ -87,6 +102,9 @@ class TheoryProxy : protected EnvObj, public Registrar
 
   bool theoryNeedCheck() const;
 
+  /** Is incomplete */
+  bool isIncomplete() const;
+
   /**
    * Notifies of a new variable at a decision level.
    */
@@ -135,6 +153,9 @@ class TheoryProxy : protected EnvObj, public Registrar
   /** Preregister term */
   void preRegister(Node n) override;
 
+  /** Get the zero-level assertions */
+  const std::unordered_set<Node>& getLearnedZeroLevelLiterals() const;
+
  private:
   /** The prop engine we are using. */
   PropEngine* d_propEngine;
@@ -168,10 +189,13 @@ class TheoryProxy : protected EnvObj, public Registrar
 
   /** The skolem definition manager */
   SkolemDefManager* d_skdm;
+
+  /** The zero level learner */
+  std::unique_ptr<ZeroLevelLearner> d_zll;
+
 }; /* class TheoryProxy */
 
 }  // namespace prop
-
 }  // namespace cvc5
 
-#endif /* CVC5__PROP__SAT_H */
+#endif
diff --git a/src/prop/zero_level_learner.cpp b/src/prop/zero_level_learner.cpp
new file mode 100644 (file)
index 0000000..1b11662
--- /dev/null
@@ -0,0 +1,155 @@
+/******************************************************************************
+ * Top contributors (to current version):
+ *   Andrew Reynolds
+ *
+ * This file is part of the cvc5 project.
+ *
+ * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
+ * in the top-level source directory and their institutional affiliations.
+ * All rights reserved.  See the file COPYING in the top-level source
+ * directory for licensing information.
+ * ****************************************************************************
+ *
+ * Learner for literals asserted at level zero.
+ */
+#include "prop/zero_level_learner.h"
+
+#include "context/context.h"
+#include "expr/node_algorithm.h"
+#include "expr/skolem_manager.h"
+#include "options/base_options.h"
+#include "options/smt_options.h"
+#include "prop/prop_engine.h"
+#include "smt/env.h"
+#include "smt/smt_statistics_registry.h"
+#include "theory/trust_substitutions.h"
+
+namespace cvc5 {
+namespace prop {
+
+ZeroLevelLearner::ZeroLevelLearner(Env& env, PropEngine* propEngine)
+    : EnvObj(env),
+      d_propEngine(propEngine),
+      d_nonZeroAssert(context(), false),
+      d_assertNoLearnCount(0)
+{
+}
+
+ZeroLevelLearner::~ZeroLevelLearner() {}
+
+void ZeroLevelLearner::getAtoms(TNode a,
+                                std::unordered_set<TNode>& visited,
+                                std::unordered_set<TNode>& ppLits)
+{
+  std::vector<TNode> visit;
+  TNode cur;
+  visit.push_back(a);
+  do
+  {
+    cur = visit.back();
+    visit.pop_back();
+    if (visited.find(cur) == visited.end())
+    {
+      visited.insert(cur);
+      if (expr::isBooleanConnective(cur))
+      {
+        visit.insert(visit.end(), cur.begin(), cur.end());
+        continue;
+      }
+      ppLits.insert(cur);
+    }
+  } while (!visit.empty());
+}
+
+void ZeroLevelLearner::notifyInputFormulas(
+    const std::vector<Node>& assertions,
+    std::unordered_map<size_t, Node>& skolemMap,
+    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;
+  // learned literals and d_ppnAtoms are disjoint
+  for (const Node& lit : ppl)
+  {
+    TNode atom = lit.getKind() == kind::NOT ? lit[0] : lit;
+    visited.insert(atom);
+    d_pplAtoms.insert(atom);
+  }
+  if (isOutputOn(OutputTag::LEARNED_LITS))
+  {
+    // output learned literals from preprocessing
+    for (const Node& lit : ppl)
+    {
+      output(OutputTag::LEARNED_LITS)
+          << "(learned-lit " << lit << " :preprocess)" << std::endl;
+    }
+  }
+  for (const Node& a : assertions)
+  {
+    getAtoms(a, visited, d_ppnAtoms);
+  }
+
+  Trace("level-zero") << "Preprocess status:" << std::endl;
+  Trace("level-zero") << "#Non-learned lits = " << d_ppnAtoms.size()
+                      << std::endl;
+  Trace("level-zero") << "#Learned lits = " << ppl.size() << std::endl;
+  Trace("level-zero") << "#Top level subs = "
+                      << d_env.getTopLevelSubstitutions().get().size()
+                      << std::endl;
+}
+
+void ZeroLevelLearner::notifyAsserted(TNode assertion)
+{
+  // check if at level zero
+  if (d_nonZeroAssert.get())
+  {
+    d_assertNoLearnCount++;
+  }
+  else if (d_levelZeroAsserts.find(assertion) == d_levelZeroAsserts.end())
+  {
+    int32_t alevel = d_propEngine->getDecisionLevel(assertion);
+    if (alevel == 0)
+    {
+      TNode aatom = assertion.getKind() == kind::NOT ? assertion[0] : assertion;
+      bool learnable = d_ppnAtoms.find(aatom) != d_ppnAtoms.end();
+      Trace("level-zero-assert")
+          << "Level zero assert: " << assertion << ", learnable=" << learnable
+          << ", already learned="
+          << (d_pplAtoms.find(aatom) != d_pplAtoms.end()) << std::endl;
+      d_levelZeroAsserts.insert(assertion);
+      if (learnable)
+      {
+        d_assertNoLearnCount = 0;
+        d_levelZeroAssertsLearned.insert(assertion);
+        Trace("level-zero-assert")
+            << "#learned now " << d_levelZeroAssertsLearned.size() << std::endl;
+        if (isOutputOn(OutputTag::LEARNED_LITS))
+        {
+          // get the original form so that internally generated variables
+          // are mapped back to their original form
+          output(OutputTag::LEARNED_LITS)
+              << "(learned-lit " << SkolemManager::getOriginalForm(assertion)
+              << ")" << std::endl;
+        }
+        return;
+      }
+    }
+    else
+    {
+      d_nonZeroAssert = true;
+    }
+    d_assertNoLearnCount++;
+  }
+}
+
+const std::unordered_set<Node>& ZeroLevelLearner::getLearnedZeroLevelLiterals()
+    const
+{
+  return d_levelZeroAssertsLearned;
+}
+
+}  // namespace prop
+}  // namespace cvc5
diff --git a/src/prop/zero_level_learner.h b/src/prop/zero_level_learner.h
new file mode 100644 (file)
index 0000000..e9979e7
--- /dev/null
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Top contributors (to current version):
+ *   Andrew Reynolds
+ *
+ * This file is part of the cvc5 project.
+ *
+ * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
+ * in the top-level source directory and their institutional affiliations.
+ * All rights reserved.  See the file COPYING in the top-level source
+ * directory for licensing information.
+ * ****************************************************************************
+ *
+ * Learner for literals asserted at level zero.
+ */
+
+#include "cvc5_private.h"
+
+#ifndef CVC5__PROP__ZERO_LEVEL_LEARNER_H
+#define CVC5__PROP__ZERO_LEVEL_LEARNER_H
+
+#include <unordered_set>
+
+#include "context/cdhashset.h"
+#include "context/cdo.h"
+#include "expr/node.h"
+#include "smt/env_obj.h"
+
+namespace cvc5 {
+namespace prop {
+
+class PropEngine;
+
+/**
+ * The module for processing literals that are learned at decision level zero.
+ *
+ * This tracks the literals that are asserted at decision level zero. It
+ * computes which literals are "learnable", which currently is limited to those
+ * that are over atoms that appear in the input assertions.
+ *
+ * The module can be queried for the set of learned literals, and also is
+ * responsible for printing the literals it learns.
+ */
+class ZeroLevelLearner : protected EnvObj
+{
+  using NodeSet = context::CDHashSet<Node>;
+
+ public:
+  ZeroLevelLearner(Env& env, PropEngine* propEngine);
+
+  ~ZeroLevelLearner();
+
+  void notifyInputFormulas(const std::vector<Node>& assertions,
+                           std::unordered_map<size_t, Node>& skolemMap,
+                           const std::vector<Node>& ppl);
+  /**
+   * Notify the given literal was asserted
+   */
+  void notifyAsserted(TNode assertion);
+
+  /** Get the zero-level assertions */
+  const std::unordered_set<Node>& getLearnedZeroLevelLiterals() const;
+
+ private:
+  static void getAtoms(TNode a,
+                       std::unordered_set<TNode>& visited,
+                       std::unordered_set<TNode>& ppLits);
+
+  /** The prop engine we are using. */
+  PropEngine* d_propEngine;
+
+  /** Set of literals that hold at level 0 */
+  std::unordered_set<TNode> d_levelZeroAsserts;
+
+  /** Set of learnable literals that hold at level 0 */
+  std::unordered_set<Node> 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;
+
+  /** Already learned TEMPORARY */
+  std::unordered_set<TNode> d_pplAtoms;
+
+  /** Current counter of assertions */
+  size_t d_assertNoLearnCount;
+}; /* class ZeroLevelLearner */
+
+}  // namespace prop
+}  // namespace cvc5
+
+#endif
index 985e811abfcf4ad3f054619977e5ae815c474331..249037a1840f1ff22041c7abe593d55bf226aedc 100644 (file)
@@ -99,6 +99,15 @@ void Preprocessor::clearLearnedLiterals()
   d_propagator.getLearnedLiterals().clear();
 }
 
+std::vector<Node> Preprocessor::getLearnedLiterals() const
+{
+  if (d_ppContext == nullptr)
+  {
+    return {};
+  }
+  return d_ppContext->getLearnedLiterals();
+}
+
 void Preprocessor::cleanup() { d_processor.cleanup(); }
 
 Node Preprocessor::expandDefinitions(const Node& n)
index c91d106f5a38e643511dbc0f09485970ac7d1df7..92be021d51184d76459d3e96ef294baef793fe6d 100644 (file)
@@ -70,6 +70,8 @@ class Preprocessor : protected EnvObj
    * Clear learned literals from the Boolean propagator.
    */
   void clearLearnedLiterals();
+  /** Get learned literals */
+  std::vector<Node> getLearnedLiterals() const;
   /**
    * Cleanup, which deletes the processing passes owned by this module. This
    * is required to be done explicitly so that passes are deleted before the
index c1608a80b2fe2429502865a72863be7e9939b59f..07d260c7ee34f2234a8e0ff830d66873e7ff8232 100644 (file)
@@ -220,11 +220,12 @@ void SmtSolver::processAssertions(Assertions& as)
   {
     d_env.verbose(2) << "converting to CNF..." << endl;
     const std::vector<Node>& assertions = ap.ref();
+    const std::vector<Node>& ppl = d_pp.getLearnedLiterals();
     // It is important to distinguish the input assertions from the skolem
     // definitions, as the decision justification heuristic treates the latter
     // specially.
     preprocessing::IteSkolemMap& ism = ap.getIteSkolemMap();
-    d_propEngine->assertInputFormulas(assertions, ism);
+    d_propEngine->assertInputFormulas(assertions, ism, ppl);
   }
 
   // clear the current assertions
index 2154c7fd53403506112e80a95bc6ffcdb9c087f6..f93a1b892d059829d0b04ed9d6d04ae62f53c6fb 100644 (file)
@@ -103,6 +103,8 @@ class SubstitutionMap
    */
   void addSubstitutions(SubstitutionMap& subMap, bool invalidateCache = true);
 
+  /** Size of the substitutions */
+  size_t size() const { return d_substitutions.size(); }
   /**
    * Returns true iff x is in the substitution map
    */
index 3bc432e5c982cf39fa83a8cec60750433ac2da4f..19db389b47ec40b77fd1602fe59c1b628490c3af 100644 (file)
@@ -877,6 +877,7 @@ set(regress_0_tests
   regress0/printer/bv_consts_dec.smt2
   regress0/printer/empty_sort.smt2
   regress0/printer/empty_symbol_name.smt2
+  regress0/printer/learned-lit-output.smt2
   regress0/printer/let_shadowing.smt2
   regress0/printer/symbol_starting_w_digit.smt2
   regress0/printer/tuples_and_records.cvc.smt2
diff --git a/test/regress/regress0/printer/learned-lit-output.smt2 b/test/regress/regress0/printer/learned-lit-output.smt2
new file mode 100644 (file)
index 0000000..b653b85
--- /dev/null
@@ -0,0 +1,12 @@
+; COMMAND-LINE: -o learned-lits
+; SCRUBBER: sed -e 's/(learned-lit.*/learned-lit/'
+; EXPECT: learned-lit
+; EXPECT: learned-lit
+; EXPECT: learned-lit
+; EXPECT: sat
+(set-logic ALL)
+(declare-fun x () Int)
+(declare-fun y () Int)
+(assert (> x 10))
+(assert (or (< x 5) (> y 0)))
+(check-sat)