Cegis-specific infrastructure (#1933)
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>
Thu, 17 May 2018 19:09:46 +0000 (14:09 -0500)
committerHaniel Barbosa <hanielbbarbosa@gmail.com>
Thu, 17 May 2018 19:09:46 +0000 (14:09 -0500)
src/options/quantifiers_options.toml
src/theory/quantifiers/sygus/ce_guided_instantiation.cpp
src/theory/quantifiers/sygus/cegis.cpp
src/theory/quantifiers/sygus/cegis.h
src/theory/quantifiers/sygus/cegis_unif.cpp
src/theory/quantifiers/sygus/cegis_unif.h
src/theory/quantifiers/sygus/term_database_sygus.cpp
test/regress/Makefile.tests
test/regress/regress1/sygus/VC22_a.sy
test/regress/regress1/sygus/find_sc_bvult_bvnot.sy [new file with mode: 0644]

index 715b0c28688903620071a98f9646464551746ff0..691b2fef4cf8717221c103bf8be824c51dbf0346 100644 (file)
@@ -1058,41 +1058,32 @@ header = "options/quantifiers_options.h"
   help       = "enable approach which unifies conditional solutions, specialized for programming-by-examples (pbe) conjectures"
 
 [[option]]
-  name       = "sygusDirectEval"
+  name       = "sygusEvalUnfold"
   category   = "regular"
-  long       = "sygus-direct-eval"
+  long       = "sygus-eval-unfold"
   type       = "bool"
   default    = "true"
   read_only  = true
-  help       = "direct unfolding of evaluation functions"
+  help       = "do unfolding of sygus evaluation functions"
 
 [[option]]
-  name       = "sygusUnfoldBool"
+  name       = "sygusEvalUnfoldBool"
   category   = "regular"
-  long       = "sygus-unfold-bool"
+  long       = "sygus-eval-unfold-bool"
   type       = "bool"
   default    = "true"
   read_only  = true
   help       = "do unfolding of Boolean evaluation functions that appear in refinement lemmas"
 
 [[option]]
-  name       = "sygusCRefEval"
+  name       = "sygusRefEval"
   category   = "regular"
-  long       = "sygus-cref-eval"
+  long       = "sygus-ref-eval"
   type       = "bool"
   default    = "true"
   read_only  = true
   help       = "direct evaluation of refinement lemmas for conflict analysis"
 
-[[option]]
-  name       = "sygusCRefEvalMinExp"
-  category   = "regular"
-  long       = "sygus-cref-eval-min-exp"
-  type       = "bool"
-  default    = "true"
-  read_only  = true
-  help       = "use min explain for direct evaluation of refinement lemmas for conflict analysis"
-
 [[option]]
   name       = "sygusStream"
   category   = "regular"
index 0aebbe11a1b24c5e7085d93cc978e5c56a7a1ab2..031507c1145f9c9426656f2f2360dbba4304ac85 100644 (file)
@@ -138,11 +138,8 @@ void CegInstantiation::checkCegConjecture( CegConjecture * conj ) {
           addedLemma = true;
         }else{
           //this may happen if we eagerly unfold, simplify to true
-          if( !options::sygusDirectEval() ){
-            Trace("cegqi-warn") << "  ...FAILED to add candidate!" << std::endl;
-          }else{
-            Trace("cegqi-engine-debug") << "  ...FAILED to add candidate!" << std::endl;
-          }
+          Trace("cegqi-engine-debug")
+              << "  ...FAILED to add candidate!" << std::endl;
         }
       }
       if( addedLemma ){
index 47053080af7221ce157944fae8295defb85ec540..ec17294f9eb7520ea50a604094130f7efee92f4a 100644 (file)
@@ -13,7 +13,9 @@
  **/
 
 #include "theory/quantifiers/sygus/cegis.h"
+#include "options/base_options.h"
 #include "options/quantifiers_options.h"
+#include "printer/printer.h"
 #include "theory/quantifiers/sygus/ce_guided_conjecture.h"
 #include "theory/quantifiers/sygus/term_database_sygus.h"
 #include "theory/theory_engine.h"
@@ -27,6 +29,7 @@ namespace theory {
 namespace quantifiers {
 
 Cegis::Cegis(QuantifiersEngine* qe, CegConjecture* p) : SygusModule(qe, p) {}
+
 bool Cegis::initialize(Node n,
                        const std::vector<Node>& candidates,
                        std::vector<Node>& lemmas)
@@ -49,7 +52,13 @@ bool Cegis::initialize(Node n,
     TypeNode bt = d_base_body.getType();
     d_cegis_sampler.initialize(bt, d_base_vars, options::sygusSamples());
   }
+  return processInitialize(n, candidates, lemmas);
+}
 
+bool Cegis::processInitialize(Node n,
+                              const std::vector<Node>& candidates,
+                              std::vector<Node>& lemmas)
+{
   // initialize an enumerator for each candidate
   for (unsigned i = 0; i < candidates.size(); i++)
   {
@@ -69,9 +78,9 @@ bool Cegis::addEvalLemmas(const std::vector<Node>& candidates,
 {
   NodeManager* nm = NodeManager::currentNM();
   bool addedEvalLemmas = false;
-  if (options::sygusCRefEval())
+  if (options::sygusRefEval())
   {
-    Trace("cegqi-engine") << "  *** Do conjecture refinement evaluation..."
+    Trace("cegqi-engine") << "  *** Do refinement lemma evaluation..."
                           << std::endl;
     // see if any refinement lemma is refuted by evaluation
     std::vector<Node> cre_lems;
@@ -82,8 +91,8 @@ bool Cegis::addEvalLemmas(const std::vector<Node>& candidates,
       {
         if (d_qe->addLemma(lem))
         {
-          Trace("cegqi-lemma") << "Cegqi::Lemma : cref evaluation : " << lem
-                               << std::endl;
+          Trace("cegqi-lemma")
+              << "Cegqi::Lemma : ref evaluation : " << lem << std::endl;
           addedEvalLemmas = true;
         }
       }
@@ -91,61 +100,107 @@ bool Cegis::addEvalLemmas(const std::vector<Node>& candidates,
          add the lemmas below as well, in parallel. */
     }
   }
-  if (!options::sygusDirectEval())
-  {
-    return addedEvalLemmas;
-  }
-  Trace("cegqi-engine") << "  *** Do direct evaluation..." << std::endl;
-  std::vector<Node> eager_terms, eager_vals, eager_exps;
-  for (unsigned i = 0, size = candidates.size(); i < size; ++i)
+  if (options::sygusEvalUnfold())
   {
-    Trace("cegqi-debug") << "  register " << candidates[i] << " -> "
-                         << candidate_values[i] << std::endl;
-    d_tds->registerModelValue(candidates[i],
-                              candidate_values[i],
-                              eager_terms,
-                              eager_vals,
-                              eager_exps);
-  }
-  Trace("cegqi-debug") << "...produced " << eager_terms.size()
-                       << " eager evaluation lemmas.\n";
-  for (unsigned i = 0, size = eager_terms.size(); i < size; ++i)
-  {
-    Node lem = nm->mkNode(
-        OR, eager_exps[i].negate(), eager_terms[i].eqNode(eager_vals[i]));
-    if (d_qe->addLemma(lem))
+    Trace("cegqi-engine") << "  *** Do evaluation unfolding..." << std::endl;
+    std::vector<Node> eager_terms, eager_vals, eager_exps;
+    for (unsigned i = 0, size = candidates.size(); i < size; ++i)
     {
-      Trace("cegqi-lemma") << "Cegqi::Lemma : evaluation : " << lem
-                           << std::endl;
-      addedEvalLemmas = true;
+      Trace("cegqi-debug") << "  register " << candidates[i] << " -> "
+                           << candidate_values[i] << std::endl;
+      d_tds->registerModelValue(candidates[i],
+                                candidate_values[i],
+                                eager_terms,
+                                eager_vals,
+                                eager_exps);
+    }
+    Trace("cegqi-debug") << "...produced " << eager_terms.size()
+                         << " evaluation unfold lemmas.\n";
+    for (unsigned i = 0, size = eager_terms.size(); i < size; ++i)
+    {
+      Node lem = nm->mkNode(
+          OR, eager_exps[i].negate(), eager_terms[i].eqNode(eager_vals[i]));
+      if (d_qe->addLemma(lem))
+      {
+        Trace("cegqi-lemma")
+            << "Cegqi::Lemma : evaluation unfold : " << lem << std::endl;
+        addedEvalLemmas = true;
+      }
     }
   }
   return addedEvalLemmas;
 }
 
-/** construct candidate */
 bool Cegis::constructCandidates(const std::vector<Node>& enums,
                                 const std::vector<Node>& enum_values,
                                 const std::vector<Node>& candidates,
                                 std::vector<Node>& candidate_values,
                                 std::vector<Node>& lems)
 {
-  if (addEvalLemmas(enums, enum_values))
+  if (Trace.isOn("cegis"))
   {
-    // it may be repairable
-    SygusRepairConst* src = d_parent->getRepairConst();
-    std::vector<Node> fail_cvs = enum_values;
-    if (src->repairSolution(candidates, fail_cvs, candidate_values))
+    Trace("cegis") << "  Enumerators :\n";
+    for (unsigned i = 0, size = enums.size(); i < size; ++i)
     {
-      return true;
+      Trace("cegis") << "    " << enums[i] << " -> ";
+      std::stringstream ss;
+      Printer::getPrinter(options::outputLanguage())
+          ->toStreamSygus(ss, enum_values[i]);
+      Trace("cegis") << ss.str() << std::endl;
     }
+  }
+  // evaluate on refinement lemmas
+  bool addedEvalLemmas = addEvalLemmas(enums, enum_values);
+
+  // try to construct candidates
+  if (!processConstructCandidates(enums,
+                                  enum_values,
+                                  candidates,
+                                  candidate_values,
+                                  !addedEvalLemmas,
+                                  lems))
+  {
     return false;
   }
-  candidate_values.insert(
-      candidate_values.end(), enum_values.begin(), enum_values.end());
+
+  if (options::cegisSample() != CEGIS_SAMPLE_NONE && lems.empty())
+  {
+    // if we didn't add a lemma, trying sampling to add a refinement lemma
+    // that immediately refutes the candidate we just constructed
+    if (sampleAddRefinementLemma(enums, enum_values, lems))
+    {
+      // restart (should be guaranteed to add evaluation lemmas on this call)
+      return constructCandidates(
+          enums, enum_values, candidates, candidate_values, lems);
+    }
+  }
   return true;
 }
 
+bool Cegis::processConstructCandidates(const std::vector<Node>& enums,
+                                       const std::vector<Node>& enum_values,
+                                       const std::vector<Node>& candidates,
+                                       std::vector<Node>& candidate_values,
+                                       bool satisfiedRl,
+                                       std::vector<Node>& lems)
+{
+  if (satisfiedRl)
+  {
+    candidate_values.insert(
+        candidate_values.end(), enum_values.begin(), enum_values.end());
+    return true;
+  }
+  SygusRepairConst* src = d_parent->getRepairConst();
+  if (src != nullptr)
+  {
+    // it may be repairable
+    std::vector<Node> fail_cvs = enum_values;
+    Assert(candidates.size() == fail_cvs.size());
+    return src->repairSolution(candidates, fail_cvs, candidate_values);
+  }
+  return false;
+}
+
 void Cegis::addRefinementLemma(Node lem)
 {
   d_refinement_lemmas.push_back(lem);
@@ -371,21 +426,13 @@ void Cegis::getRefinementEvalLemmas(const std::vector<Node>& vs,
       break;
     }
   }
-  // if we didn't add a lemma, trying sampling to add one
-  if (options::cegisSample() != CEGIS_SAMPLE_NONE && lems.empty())
-  {
-    if (sampleAddRefinementLemma(vs, ms, lems))
-    {
-      // restart (should be guaranteed to add evaluation lemmas
-      getRefinementEvalLemmas(vs, ms, lems);
-    }
-  }
 }
 
 bool Cegis::sampleAddRefinementLemma(const std::vector<Node>& candidates,
                                      const std::vector<Node>& vals,
                                      std::vector<Node>& lems)
 {
+  Trace("cegqi-engine") << "  *** Do sample add refinement..." << std::endl;
   if (Trace.isOn("cegis-sample"))
   {
     Trace("cegis-sample") << "Check sampling for candidate solution"
index cbd563e07970df03cca509f6e1afed4accbb2238..e5ee6bc5680102035883b2ac28b142855d379214 100644 (file)
@@ -72,6 +72,23 @@ class Cegis : public SygusModule
    * formula P( CegConjecture::d_candidates, y ).
    */
   Node d_base_body;
+  //----------------------------------cegis-implementation-specific
+  /** do cegis-implementation-specific intialization for this class */
+  virtual bool processInitialize(Node n,
+                                 const std::vector<Node>& candidates,
+                                 std::vector<Node>& lemmas);
+  /** do cegis-implementation-specific construct candidate
+   *
+   * satisfiedRl is whether all refinement lemmas are satisfied under the
+   * substitution { enums -> enum_values }.
+   */
+  virtual bool processConstructCandidates(const std::vector<Node>& enums,
+                                          const std::vector<Node>& enum_values,
+                                          const std::vector<Node>& candidates,
+                                          std::vector<Node>& candidate_values,
+                                          bool satisfiedRl,
+                                          std::vector<Node>& lems);
+  //----------------------------------end cegis-implementation-specific
 
   //-----------------------------------refinement lemmas
   /** refinement lemmas */
index 20f0627226342e8bd93fc60e147ae02d6758f292..9ae598f8357de28d212087a188d08337edcc2948 100644 (file)
@@ -33,9 +33,9 @@ CegisUnif::CegisUnif(QuantifiersEngine* qe, CegConjecture* p)
 }
 
 CegisUnif::~CegisUnif() {}
-bool CegisUnif::initialize(Node n,
-                           const std::vector<Node>& candidates,
-                           std::vector<Node>& lemmas)
+bool CegisUnif::processInitialize(Node n,
+                                  const std::vector<Node>& candidates,
+                                  std::vector<Node>& lemmas)
 {
   Trace("cegis-unif") << "Initialize CegisUnif : " << n << std::endl;
   // list of strategy points for unification candidates
@@ -99,27 +99,16 @@ void CegisUnif::getTermList(const std::vector<Node>& candidates,
   }
 }
 
-bool CegisUnif::constructCandidates(const std::vector<Node>& enums,
-                                    const std::vector<Node>& enum_values,
-                                    const std::vector<Node>& candidates,
-                                    std::vector<Node>& candidate_values,
-                                    std::vector<Node>& lems)
+bool CegisUnif::processConstructCandidates(const std::vector<Node>& enums,
+                                           const std::vector<Node>& enum_values,
+                                           const std::vector<Node>& candidates,
+                                           std::vector<Node>& candidate_values,
+                                           bool satisfiedRl,
+                                           std::vector<Node>& lems)
 {
-  if (Trace.isOn("cegis-unif-enum"))
-  {
-    Trace("cegis-unif-enum") << "  Evaluation heads :\n";
-    for (unsigned i = 0, size = enums.size(); i < size; ++i)
-    {
-      Trace("cegis-unif-enum") << "    " << enums[i] << " -> ";
-      std::stringstream ss;
-      Printer::getPrinter(options::outputLanguage())
-          ->toStreamSygus(ss, enum_values[i]);
-      Trace("cegis-unif-enum") << ss.str() << std::endl;
-    }
-  }
-  // evaluate on refinement lemmas
-  if (addEvalLemmas(enums, enum_values))
+  if (!satisfiedRl)
   {
+    // if we didn't satisfy the specification, there is no way to repair
     return false;
   }
   // the unification enumerators (return values, conditions) and their model
@@ -137,9 +126,8 @@ bool CegisUnif::constructCandidates(const std::vector<Node>& enums,
     {
       for (unsigned index = 0; index < 2; index++)
       {
-        Trace("cegis-unif-enum")
-            << "  " << (index == 0 ? "Return values" : "Conditions") << " for "
-            << e << ":\n";
+        Trace("cegis") << "  " << (index == 0 ? "Return values" : "Conditions")
+                       << " for " << e << ":\n";
         // get the current unification enumerators
         d_u_enum_manager.getEnumeratorsForStrategyPt(
             e, unif_enums[index][e], index);
@@ -147,13 +135,13 @@ bool CegisUnif::constructCandidates(const std::vector<Node>& enums,
         for (const Node& eu : unif_enums[index][e])
         {
           Node m_eu = d_parent->getModelValue(eu);
-          if (Trace.isOn("cegis-unif-enum"))
+          if (Trace.isOn("cegis"))
           {
-            Trace("cegis-unif-enum") << "    " << eu << " -> ";
+            Trace("cegis") << "    " << eu << " -> ";
             std::stringstream ss;
             Printer::getPrinter(options::outputLanguage())
                 ->toStreamSygus(ss, m_eu);
-            Trace("cegis-unif-enum") << ss.str() << std::endl;
+            Trace("cegis") << ss.str() << std::endl;
           }
           unif_values[index][e].push_back(m_eu);
         }
index ecaec4129a84e8e9ac8d9ef48af68e603759e751..5c2c11e4df77c1c8ac1b2cd0d1ff5674eef9a598 100644 (file)
@@ -183,10 +183,6 @@ class CegisUnif : public Cegis
  public:
   CegisUnif(QuantifiersEngine* qe, CegConjecture* p);
   ~CegisUnif();
-  /** initialize this class */
-  bool initialize(Node n,
-                  const std::vector<Node>& candidates,
-                  std::vector<Node>& lemmas) override;
   /** Retrieves enumerators for constructing solutions
    *
    * Non-unification candidates have themselves as enumerators, while for
@@ -195,33 +191,6 @@ class CegisUnif : public Cegis
    */
   void getTermList(const std::vector<Node>& candidates,
                    std::vector<Node>& enums) override;
-  /** Tries to build new candidate solutions with new enumerated expressions
-   *
-   * This function relies on a data-driven unification-based approach for
-   * constructing solutions for the functions-to-synthesize. See SygusUnifRl for
-   * more details.
-   *
-   * Calls to this function are such that terms is the list of active
-   * enumerators (returned by getTermList), and term_values are their current
-   * model values. This function registers { terms -> terms_values } in
-   * the database of values that have been enumerated, which are in turn used
-   * for constructing candidate solutions when possible.
-   *
-   * This function also excludes models where (terms = terms_values) by adding
-   * blocking clauses to lems. For example, for grammar:
-   *   A -> A+A | x | 1 | 0
-   * and a call where terms = { d } and term_values = { +( x, 1 ) }, it adds:
-   *   ~G V ~is_+( d ) V ~is_x( d.1 ) V ~is_1( d.2 )
-   * to lems, where G is active guard of the enumerator d (see
-   * TermDatabaseSygus::getActiveGuardForEnumerator). This blocking clause
-   * indicates that d should not be given the model value +( x, 1 ) anymore,
-   * since { d -> +( x, 1 ) } has now been added to the database of this class.
-   */
-  bool constructCandidates(const std::vector<Node>& enums,
-                           const std::vector<Node>& enum_values,
-                           const std::vector<Node>& candidates,
-                           std::vector<Node>& candidate_values,
-                           std::vector<Node>& lems) override;
 
   /** Communicates refinement lemma to unification utility and external modules
    *
@@ -249,6 +218,38 @@ class CegisUnif : public Cegis
   Node getNextDecisionRequest(unsigned& priority) override;
 
  private:
+  /** do cegis-implementation-specific intialization for this class */
+  bool processInitialize(Node n,
+                         const std::vector<Node>& candidates,
+                         std::vector<Node>& lemmas) override;
+  /** Tries to build new candidate solutions with new enumerated expressions
+   *
+   * This function relies on a data-driven unification-based approach for
+   * constructing solutions for the functions-to-synthesize. See SygusUnifRl for
+   * more details.
+   *
+   * Calls to this function are such that terms is the list of active
+   * enumerators (returned by getTermList), and term_values are their current
+   * model values. This function registers { terms -> terms_values } in
+   * the database of values that have been enumerated, which are in turn used
+   * for constructing candidate solutions when possible.
+   *
+   * This function also excludes models where (terms = terms_values) by adding
+   * blocking clauses to lems. For example, for grammar:
+   *   A -> A+A | x | 1 | 0
+   * and a call where terms = { d } and term_values = { +( x, 1 ) }, it adds:
+   *   ~G V ~is_+( d ) V ~is_x( d.1 ) V ~is_1( d.2 )
+   * to lems, where G is active guard of the enumerator d (see
+   * TermDatabaseSygus::getActiveGuardForEnumerator). This blocking clause
+   * indicates that d should not be given the model value +( x, 1 ) anymore,
+   * since { d -> +( x, 1 ) } has now been added to the database of this class.
+   */
+  bool processConstructCandidates(const std::vector<Node>& enums,
+                                  const std::vector<Node>& enum_values,
+                                  const std::vector<Node>& candidates,
+                                  std::vector<Node>& candidate_values,
+                                  bool satisfiedRl,
+                                  std::vector<Node>& lems) override;
   /**
    * Sygus unif utility. This class implements the core algorithm (e.g. decision
    * tree learning) that this module relies upon.
index 0b7841170a08ef8eef060978dffa8fbb25561c79..b530edeaad88adb2a28cda51957e3028b1293488 100644 (file)
@@ -1261,7 +1261,8 @@ unsigned TermDbSygus::getAnchorDepth( Node n ) {
 
 
 void TermDbSygus::registerEvalTerm( Node n ) {
-  if( options::sygusDirectEval() ){
+  if (options::sygusEvalUnfold())
+  {
     if( n.getKind()==APPLY_UF && !n.getType().isBoolean() ){
       TypeNode tn = n[0].getType();
       if( tn.isDatatype() ){
@@ -1344,7 +1345,8 @@ void TermDbSygus::registerModelValue( Node a, Node v, std::vector< Node >& terms
           Node expn;
           // unfold?
           bool do_unfold = false;
-          if( options::sygusUnfoldBool() ){
+          if (options::sygusEvalUnfoldBool())
+          {
             if( bTerm.getKind()==ITE || bTerm.getType().isBoolean() ){
               do_unfold = true;
             }
index c0f1cf315b531184a09568215937cfbfb15bbd57..f8fdd4a18846ddef9d5f247a5a9695a2f3acf1ee 100644 (file)
@@ -1480,6 +1480,7 @@ REG1_TESTS = \
        regress1/sygus/dt-test-ns.sy \
        regress1/sygus/dup-op.sy \
        regress1/sygus/fg_polynomial3.sy \
+       regress1/sygus/find_sc_bvult_bvnot.sy \
        regress1/sygus/hd-01-d1-prog.sy \
        regress1/sygus/hd-19-d1-prog-dup-op.sy \
        regress1/sygus/hd-sdiv.sy \
index 32e4723aa060e80265768d762db3347a83b4b866..ce437bc34f81568517c6342777970a11670830a0 100644 (file)
@@ -1,5 +1,6 @@
 ; EXPECT: unsat
 ; COMMAND-LINE: --sygus-out=status
+; COMMAND-LINE: --sygus-out=status --cegis-sample=use
 (set-logic LIA)
 
 (synth-fun f ((x1 Int) (x2 Int)) Int
diff --git a/test/regress/regress1/sygus/find_sc_bvult_bvnot.sy b/test/regress/regress1/sygus/find_sc_bvult_bvnot.sy
new file mode 100644 (file)
index 0000000..e994c2a
--- /dev/null
@@ -0,0 +1,74 @@
+; EXPECT: unsat
+; COMMAND-LINE: --sygus-out=status
+; COMMAND-LINE: --sygus-out=status --cegis-sample=trust
+(set-logic BV)
+
+; we test --cegis-sample=trust since we can exhaustively sample BV4
+
+(synth-fun SC ((s (BitVec 4)) (t (BitVec 4))) Bool
+  ((Start Bool (
+     true
+     false
+     (not Start)
+     (and Start Start)
+     (or Start Start)
+;     (=> Start Start)
+     (= StartBv StartBv)
+     (bvult StartBv StartBv)
+     (bvslt StartBv StartBv)
+     (bvuge StartBv StartBv)
+     (bvsge StartBv StartBv)
+   ))
+   (StartBv (BitVec 4) (
+     s
+     t
+     #x0
+     #x8 ; min_val
+     #x7 ; max_val
+     (bvneg  StartBv)
+     (bvnot  StartBv)
+     (bvadd  StartBv StartBv)
+     (bvsub  StartBv StartBv)
+     (bvand  StartBv StartBv)
+     (bvlshr StartBv StartBv)
+     (bvor   StartBv StartBv)
+     (bvshl  StartBv StartBv)
+   ))
+))
+
+(declare-var s (BitVec 4))
+(declare-var t (BitVec 4))
+(define-fun udivtotal ((a (_ BitVec 4)) (b (_ BitVec 4))) (_ BitVec 4)
+  (ite (= b #x0) #xF (bvudiv a b))
+)
+(define-fun uremtotal ((a (_ BitVec 4)) (b (_ BitVec 4))) (_ BitVec 4)
+  (ite (= b #x0) a (bvurem a b))
+)
+(define-fun case ((x (BitVec 4)) (s (BitVec 4)) (t (BitVec 4))) Bool
+(bvult (bvnot x) t)
+)
+(constraint
+  (=
+   (or
+    (case #x0 s t)
+    (case #x1 s t)
+    (case #x2 s t)
+    (case #x3 s t)
+    (case #x4 s t)
+    (case #x5 s t)
+    (case #x6 s t)
+    (case #x7 s t)
+    (case #x8 s t)
+    (case #x9 s t)
+    (case #xA s t)
+    (case #xB s t)
+    (case #xC s t)
+    (case #xD s t)
+    (case #xE s t)
+    (case #xF s t)
+   )
+   (SC s t)
+  )
+)
+
+(check-synth)