From 70f13ced3393cea570970b24d3d932d112183b9a Mon Sep 17 00:00:00 2001
From: Nikolaj Bjorner <nbjorner@microsoft.com>
Date: Sat, 5 Mar 2016 10:14:15 -0800
Subject: [PATCH] make proto-model evaluation use model_evaluator instead of
 legacy evaluator

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
---
 src/ast/ast.cpp                       |   1 +
 src/ast/ast_smt2_pp.cpp               |   2 +-
 src/ast/fpa/fpa2bv_rewriter.cpp       | 270 ++++++++++++++++++++++++++
 src/ast/fpa/fpa2bv_rewriter.h         | 238 +----------------------
 src/ast/rewriter/arith_rewriter.cpp   |   6 +-
 src/ast/rewriter/bool_rewriter.cpp    |  72 ++++---
 src/ast/rewriter/rewriter.cpp         |   2 +
 src/ast/rewriter/rewriter.h           |   7 +-
 src/ast/rewriter/rewriter_def.h       |  96 ++++++---
 src/ast/rewriter/seq_rewriter.cpp     |   2 +-
 src/model/model_core.cpp              |   1 -
 src/model/model_evaluator.cpp         |  15 +-
 src/model/model_params.pyg            |   1 +
 src/smt/proto_model/proto_model.cpp   |  17 +-
 src/smt/proto_model/proto_model.h     |   3 +
 src/smt/smt_model_checker.cpp         |  16 +-
 src/smt/theory_arith_core.h           |   2 +-
 src/smt/theory_seq.cpp                |   1 -
 src/tactic/bv/bvarray2uf_rewriter.cpp |   3 +
 src/tactic/bv/bvarray2uf_rewriter.h   |   3 +-
 src/test/main.cpp                     |   1 +
 src/test/model_evaluator.cpp          |  66 +++++++
 22 files changed, 528 insertions(+), 297 deletions(-)
 create mode 100644 src/ast/fpa/fpa2bv_rewriter.cpp
 create mode 100644 src/test/model_evaluator.cpp

diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp
index 2cf33941e..6d139a5bd 100644
--- a/src/ast/ast.cpp
+++ b/src/ast/ast.cpp
@@ -2095,6 +2095,7 @@ inline app * ast_manager::mk_app_core(func_decl * decl, expr * arg1, expr * arg2
 }
 
 app * ast_manager::mk_app(func_decl * decl, unsigned num_args, expr * const * args) {
+
     bool type_error = 
         decl->get_arity() != num_args && !decl->is_right_associative() && 
         !decl->is_left_associative() && !decl->is_chainable();
diff --git a/src/ast/ast_smt2_pp.cpp b/src/ast/ast_smt2_pp.cpp
index e31e5aab6..7d5248b30 100644
--- a/src/ast/ast_smt2_pp.cpp
+++ b/src/ast/ast_smt2_pp.cpp
@@ -1075,7 +1075,7 @@ public:
         if (strcmp(var_prefix, ALIAS_PREFIX) == 0) {
             var_prefix = "_a";
         }
-        unsigned idx = 1;
+        unsigned idx = 0;
         for (unsigned i = 0; i < num; i++) {
             symbol name = next_name(var_prefix, idx);
             name = ensure_quote_sym(name);
diff --git a/src/ast/fpa/fpa2bv_rewriter.cpp b/src/ast/fpa/fpa2bv_rewriter.cpp
new file mode 100644
index 000000000..45a87087c
--- /dev/null
+++ b/src/ast/fpa/fpa2bv_rewriter.cpp
@@ -0,0 +1,270 @@
+/*++
+Copyright (c) 2012 Microsoft Corporation
+
+Module Name:
+
+    fpa2bv_rewriter.cpp
+
+Abstract:
+
+    Rewriter for converting FPA to BV
+
+Author:
+
+    Christoph (cwinter) 2012-02-09
+
+Notes:
+
+--*/
+
+
+#include"rewriter_def.h"
+#include"fpa2bv_rewriter.h"
+#include"cooperate.h"
+#include"fpa2bv_rewriter_params.hpp"
+
+
+fpa2bv_rewriter_cfg::fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p) :
+    m_manager(m),
+    m_out(m),
+    m_conv(c),
+    m_bindings(m) 
+{
+    updt_params(p);
+    // We need to make sure that the mananger has the BV plugin loaded.
+    symbol s_bv("bv");
+    if (!m_manager.has_plugin(s_bv))
+        m_manager.register_plugin(s_bv, alloc(bv_decl_plugin));
+}
+
+void fpa2bv_rewriter_cfg::updt_local_params(params_ref const & _p) {
+    fpa2bv_rewriter_params p(_p);
+    bool v = p.hi_fp_unspecified();
+    m_conv.set_unspecified_fp_hi(v);
+}
+
+void fpa2bv_rewriter_cfg::updt_params(params_ref const & p) {
+    m_max_memory        = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
+    m_max_steps         = p.get_uint("max_steps", UINT_MAX);
+    updt_local_params(p);
+}
+
+bool fpa2bv_rewriter_cfg::max_steps_exceeded(unsigned num_steps) const { 
+    cooperate("fpa2bv");
+    return num_steps > m_max_steps;
+}
+
+
+br_status fpa2bv_rewriter_cfg::reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
+    TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; );
+    
+    if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_float(f->get_range())) {
+        m_conv.mk_const(f, result);
+        return BR_DONE;
+    }
+    
+    if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_rm(f->get_range())) {
+        m_conv.mk_rm_const(f, result);
+        return BR_DONE;
+        }
+    
+    if (m().is_eq(f)) {
+        SASSERT(num == 2);
+        TRACE("fpa2bv_rw", tout << "(= " << mk_ismt2_pp(args[0], m()) << " " << 
+              mk_ismt2_pp(args[1], m()) << ")" << std::endl;);
+        SASSERT(m().get_sort(args[0]) == m().get_sort(args[1]));            
+        sort * ds = f->get_domain()[0];
+        if (m_conv.is_float(ds)) {
+            m_conv.mk_eq(args[0], args[1], result);
+            return BR_DONE;
+        }
+        else if (m_conv.is_rm(ds)) {
+            result = m().mk_eq(args[0], args[1]);
+            return BR_DONE;
+        }
+        return BR_FAILED;
+    }
+    else if (m().is_ite(f)) {
+        SASSERT(num == 3);
+        if (m_conv.is_float(args[1])) {
+            m_conv.mk_ite(args[0], args[1], args[2], result);
+            return BR_DONE;
+        }
+        return BR_FAILED;
+    }
+    else if (m().is_distinct(f)) {
+        sort * ds = f->get_domain()[0];
+        if (m_conv.is_float(ds) || m_conv.is_rm(ds)) {
+            m_conv.mk_distinct(f, num, args, result);
+            return BR_DONE;
+        }
+        return BR_FAILED;
+    }
+    
+    if (m_conv.is_float_family(f)) {
+        switch (f->get_decl_kind()) {
+        case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
+        case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
+        case OP_FPA_RM_TOWARD_NEGATIVE:
+        case OP_FPA_RM_TOWARD_POSITIVE:
+        case OP_FPA_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE;
+        case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE;                             
+        case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE;
+        case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE;
+        case OP_FPA_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE;
+        case OP_FPA_MINUS_ZERO: m_conv.mk_nzero(f, result); return BR_DONE;
+        case OP_FPA_NAN: m_conv.mk_nan(f, result); return BR_DONE;
+        case OP_FPA_ADD: m_conv.mk_add(f, num, args, result); return BR_DONE;
+        case OP_FPA_SUB: m_conv.mk_sub(f, num, args, result); return BR_DONE;
+        case OP_FPA_NEG: m_conv.mk_neg(f, num, args, result); return BR_DONE;
+        case OP_FPA_MUL: m_conv.mk_mul(f, num, args, result); return BR_DONE;
+        case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
+        case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE;
+        case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;            
+        case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE;
+        case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
+        case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
+        case OP_FPA_EQ: m_conv.mk_float_eq(f, num, args, result); return BR_DONE;
+        case OP_FPA_LT: m_conv.mk_float_lt(f, num, args, result); return BR_DONE;
+        case OP_FPA_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE;
+        case OP_FPA_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE;
+        case OP_FPA_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE;
+        case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;            
+        case OP_FPA_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE;
+        case OP_FPA_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE;
+        case OP_FPA_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE;
+        case OP_FPA_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE;
+        case OP_FPA_IS_POSITIVE: m_conv.mk_is_positive(f, num, args, result); return BR_DONE;
+        case OP_FPA_IS_NEGATIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE;
+        case OP_FPA_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE;
+        case OP_FPA_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(f, num, args, result); return BR_DONE;
+        case OP_FPA_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE;
+        case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE;
+        case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE;
+        case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
+        case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
+            
+        case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL;
+        case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL;
+            
+        case OP_FPA_INTERNAL_MIN_UNSPECIFIED: result = m_conv.mk_min_unspecified(f, args[0], args[1]); return BR_DONE;
+        case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_max_unspecified(f, args[0], args[1]); return BR_DONE;
+        case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE;
+        case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE;
+            
+        case OP_FPA_INTERNAL_RM:
+        case OP_FPA_INTERNAL_BVWRAP: 
+        case OP_FPA_INTERNAL_BVUNWRAP:                
+        case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
+        case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: 
+        case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: return BR_FAILED;
+        default:
+            TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n";
+                  for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
+            NOT_IMPLEMENTED_YET();
+        }
+    }
+    else {
+        SASSERT(!m_conv.is_float_family(f));
+        bool is_float_uf = m_conv.is_float(f->get_range()) || m_conv.is_rm(f->get_range());
+        
+        for (unsigned i = 0; i < f->get_arity(); i++) {
+            sort * di = f->get_domain()[i];
+            is_float_uf |= m_conv.is_float(di) || m_conv.is_rm(di);
+        }
+        
+        if (is_float_uf) {
+            m_conv.mk_uninterpreted_function(f, num, args, result);
+            return BR_DONE;
+        }
+    }
+    
+    return BR_FAILED;
+}
+
+bool fpa2bv_rewriter_cfg::pre_visit(expr * t)
+{
+    TRACE("fpa2bv", tout << "pre_visit: " << mk_ismt2_pp(t, m()) << std::endl;);
+    
+    if (is_quantifier(t)) {            
+        quantifier * q = to_quantifier(t);            
+        TRACE("fpa2bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;);
+        sort_ref_vector new_bindings(m_manager);
+        for (unsigned i = 0 ; i < q->get_num_decls(); i++)
+                new_bindings.push_back(q->get_decl_sort(i));
+        SASSERT(new_bindings.size() == q->get_num_decls());
+        m_bindings.append(new_bindings);
+    }
+    return true;
+}
+
+
+bool fpa2bv_rewriter_cfg::reduce_quantifier(quantifier * old_q, 
+                           expr * new_body, 
+                           expr * const * new_patterns, 
+                           expr * const * new_no_patterns,
+                           expr_ref & result,
+                           proof_ref & result_pr) {
+    unsigned curr_sz   = m_bindings.size();
+    SASSERT(old_q->get_num_decls() <= curr_sz);
+    unsigned num_decls = old_q->get_num_decls();
+    unsigned old_sz    = curr_sz - num_decls;
+    string_buffer<> name_buffer;
+    ptr_buffer<sort> new_decl_sorts;
+    sbuffer<symbol>  new_decl_names;
+    for (unsigned i = 0; i < num_decls; i++) {
+        symbol const & n = old_q->get_decl_name(i);
+        sort * s         = old_q->get_decl_sort(i);
+        if (m_conv.is_float(s)) {
+            unsigned ebits = m_conv.fu().get_ebits(s);
+            unsigned sbits = m_conv.fu().get_sbits(s);
+            name_buffer.reset();
+            name_buffer << n << ".bv";
+            new_decl_names.push_back(symbol(name_buffer.c_str()));
+            new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits+ebits)); 
+        }
+        else {
+            new_decl_sorts.push_back(s);
+            new_decl_names.push_back(n);
+        }
+    }
+    result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
+                               new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
+                               old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
+    result_pr = 0;
+    m_bindings.shrink(old_sz);        
+    TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " << 
+          mk_ismt2_pp(old_q->get_expr(), m()) << std::endl <<
+          " new body: " << mk_ismt2_pp(new_body, m()) << std::endl;
+          tout << "result = " << mk_ismt2_pp(result, m()) << std::endl;);                
+    return true;
+}
+
+bool fpa2bv_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { 
+    if (t->get_idx() >= m_bindings.size())
+        return false;
+    // unsigned inx = m_bindings.size() - t->get_idx() - 1;        
+    
+    expr_ref new_exp(m());
+    sort * s = t->get_sort();
+    if (m_conv.is_float(s))
+        {
+            expr_ref new_var(m());
+            unsigned ebits = m_conv.fu().get_ebits(s);
+            unsigned sbits = m_conv.fu().get_sbits(s);
+            new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits));
+            m_conv.mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var),
+                         m_conv.bu().mk_extract(ebits - 1, 0, new_var),
+                         m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),                         
+                         new_exp);
+        }
+    else
+        new_exp = m().mk_var(t->get_idx(), s);
+    
+    result = new_exp;
+    result_pr = 0;        
+    TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;);
+    return true;
+}
+
+template class rewriter_tpl<fpa2bv_rewriter_cfg>;
diff --git a/src/ast/fpa/fpa2bv_rewriter.h b/src/ast/fpa/fpa2bv_rewriter.h
index c3720421c..7bfc60be4 100644
--- a/src/ast/fpa/fpa2bv_rewriter.h
+++ b/src/ast/fpa/fpa2bv_rewriter.h
@@ -20,11 +20,9 @@ Notes:
 #ifndef FPA2BV_REWRITER_H_
 #define FPA2BV_REWRITER_H_
 
-#include"cooperate.h"
-#include"rewriter_def.h"
+#include"rewriter.h"
 #include"bv_decl_plugin.h"
 #include"fpa2bv_converter.h"
-#include"fpa2bv_rewriter_params.hpp"
 
 struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
     ast_manager              & m_manager;    
@@ -37,17 +35,7 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
 
     ast_manager & m() const { return m_manager; }
 
-    fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p) :
-        m_manager(m),
-        m_out(m),
-        m_conv(c),
-        m_bindings(m) {
-        updt_params(p);
-        // We need to make sure that the mananger has the BV plugin loaded.
-        symbol s_bv("bv");
-        if (!m_manager.has_plugin(s_bv))
-            m_manager.register_plugin(s_bv, alloc(bv_decl_plugin));
-    }
+    fpa2bv_rewriter_cfg(ast_manager & m, fpa2bv_converter & c, params_ref const & p);
 
     ~fpa2bv_rewriter_cfg() {        
     }
@@ -59,236 +47,28 @@ struct fpa2bv_rewriter_cfg : public default_rewriter_cfg {
     void reset() {
     }
 
-    void updt_local_params(params_ref const & _p) {
-        fpa2bv_rewriter_params p(_p);
-        bool v = p.hi_fp_unspecified();
-        m_conv.set_unspecified_fp_hi(v);
-    }
+    void updt_local_params(params_ref const & _p);
 
-    void updt_params(params_ref const & p) {
-        m_max_memory        = megabytes_to_bytes(p.get_uint("max_memory", UINT_MAX));
-        m_max_steps         = p.get_uint("max_steps", UINT_MAX);
-        updt_local_params(p);
-    }
+    void updt_params(params_ref const & p);
 
-    bool max_steps_exceeded(unsigned num_steps) const { 
-        cooperate("fpa2bv");
-        return num_steps > m_max_steps;
-    }
+    bool max_steps_exceeded(unsigned num_steps) const;
 
-    br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr) {
-        TRACE("fpa2bv_rw", tout << "APP: " << f->get_name() << std::endl; );
+    br_status reduce_app(func_decl * f, unsigned num, expr * const * args, expr_ref & result, proof_ref & result_pr);
 
-        if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_float(f->get_range())) {
-            m_conv.mk_const(f, result);
-            return BR_DONE;
-        }
 
-        if (num == 0 && f->get_family_id() == null_family_id && m_conv.is_rm(f->get_range())) {
-            m_conv.mk_rm_const(f, result);
-            return BR_DONE;
-        }
-
-        if (m().is_eq(f)) {
-            SASSERT(num == 2);
-            TRACE("fpa2bv_rw", tout << "(= " << mk_ismt2_pp(args[0], m()) << " " << 
-                                                mk_ismt2_pp(args[1], m()) << ")" << std::endl;);
-            SASSERT(m().get_sort(args[0]) == m().get_sort(args[1]));            
-            sort * ds = f->get_domain()[0];
-            if (m_conv.is_float(ds)) {
-                m_conv.mk_eq(args[0], args[1], result);
-                return BR_DONE;
-            }
-            else if (m_conv.is_rm(ds)) {
-                result = m().mk_eq(args[0], args[1]);
-                return BR_DONE;
-            }
-            return BR_FAILED;
-        }
-        else if (m().is_ite(f)) {
-            SASSERT(num == 3);
-            if (m_conv.is_float(args[1])) {
-                m_conv.mk_ite(args[0], args[1], args[2], result);
-                return BR_DONE;
-            }
-            return BR_FAILED;
-        }
-        else if (m().is_distinct(f)) {
-            sort * ds = f->get_domain()[0];
-            if (m_conv.is_float(ds) || m_conv.is_rm(ds)) {
-                m_conv.mk_distinct(f, num, args, result);
-                return BR_DONE;
-            }
-            return BR_FAILED;
-        }
-        
-        if (m_conv.is_float_family(f)) {
-            switch (f->get_decl_kind()) {
-            case OP_FPA_RM_NEAREST_TIES_TO_AWAY:
-            case OP_FPA_RM_NEAREST_TIES_TO_EVEN:
-            case OP_FPA_RM_TOWARD_NEGATIVE:
-            case OP_FPA_RM_TOWARD_POSITIVE:
-            case OP_FPA_RM_TOWARD_ZERO: m_conv.mk_rounding_mode(f, result); return BR_DONE;
-            case OP_FPA_NUM: m_conv.mk_numeral(f, num, args, result); return BR_DONE;                             
-            case OP_FPA_PLUS_INF: m_conv.mk_pinf(f, result); return BR_DONE;
-            case OP_FPA_MINUS_INF: m_conv.mk_ninf(f, result); return BR_DONE;
-            case OP_FPA_PLUS_ZERO: m_conv.mk_pzero(f, result); return BR_DONE;
-            case OP_FPA_MINUS_ZERO: m_conv.mk_nzero(f, result); return BR_DONE;
-            case OP_FPA_NAN: m_conv.mk_nan(f, result); return BR_DONE;
-            case OP_FPA_ADD: m_conv.mk_add(f, num, args, result); return BR_DONE;
-            case OP_FPA_SUB: m_conv.mk_sub(f, num, args, result); return BR_DONE;
-            case OP_FPA_NEG: m_conv.mk_neg(f, num, args, result); return BR_DONE;
-            case OP_FPA_MUL: m_conv.mk_mul(f, num, args, result); return BR_DONE;
-            case OP_FPA_DIV: m_conv.mk_div(f, num, args, result); return BR_DONE;
-            case OP_FPA_REM: m_conv.mk_rem(f, num, args, result); return BR_DONE;
-            case OP_FPA_ABS: m_conv.mk_abs(f, num, args, result); return BR_DONE;            
-            case OP_FPA_FMA: m_conv.mk_fma(f, num, args, result); return BR_DONE;
-            case OP_FPA_SQRT: m_conv.mk_sqrt(f, num, args, result); return BR_DONE;
-            case OP_FPA_ROUND_TO_INTEGRAL: m_conv.mk_round_to_integral(f, num, args, result); return BR_DONE;
-            case OP_FPA_EQ: m_conv.mk_float_eq(f, num, args, result); return BR_DONE;
-            case OP_FPA_LT: m_conv.mk_float_lt(f, num, args, result); return BR_DONE;
-            case OP_FPA_GT: m_conv.mk_float_gt(f, num, args, result); return BR_DONE;
-            case OP_FPA_LE: m_conv.mk_float_le(f, num, args, result); return BR_DONE;
-            case OP_FPA_GE: m_conv.mk_float_ge(f, num, args, result); return BR_DONE;
-            case OP_FPA_IS_ZERO: m_conv.mk_is_zero(f, num, args, result); return BR_DONE;            
-            case OP_FPA_IS_NAN: m_conv.mk_is_nan(f, num, args, result); return BR_DONE;
-            case OP_FPA_IS_INF: m_conv.mk_is_inf(f, num, args, result); return BR_DONE;
-            case OP_FPA_IS_NORMAL: m_conv.mk_is_normal(f, num, args, result); return BR_DONE;
-            case OP_FPA_IS_SUBNORMAL: m_conv.mk_is_subnormal(f, num, args, result); return BR_DONE;
-            case OP_FPA_IS_POSITIVE: m_conv.mk_is_positive(f, num, args, result); return BR_DONE;
-            case OP_FPA_IS_NEGATIVE: m_conv.mk_is_negative(f, num, args, result); return BR_DONE;
-            case OP_FPA_TO_FP: m_conv.mk_to_fp(f, num, args, result); return BR_DONE;
-            case OP_FPA_TO_FP_UNSIGNED: m_conv.mk_to_fp_unsigned(f, num, args, result); return BR_DONE;
-            case OP_FPA_FP: m_conv.mk_fp(f, num, args, result); return BR_DONE;
-            case OP_FPA_TO_UBV: m_conv.mk_to_ubv(f, num, args, result); return BR_DONE;
-            case OP_FPA_TO_SBV: m_conv.mk_to_sbv(f, num, args, result); return BR_DONE;
-            case OP_FPA_TO_REAL: m_conv.mk_to_real(f, num, args, result); return BR_DONE;
-            case OP_FPA_TO_IEEE_BV: m_conv.mk_to_ieee_bv(f, num, args, result); return BR_DONE;
-            
-            case OP_FPA_MIN: m_conv.mk_min(f, num, args, result); return BR_REWRITE_FULL;
-            case OP_FPA_MAX: m_conv.mk_max(f, num, args, result); return BR_REWRITE_FULL;
-
-            case OP_FPA_INTERNAL_MIN_UNSPECIFIED: result = m_conv.mk_min_unspecified(f, args[0], args[1]); return BR_DONE;
-            case OP_FPA_INTERNAL_MAX_UNSPECIFIED: result = m_conv.mk_max_unspecified(f, args[0], args[1]); return BR_DONE;
-            case OP_FPA_INTERNAL_MIN_I: m_conv.mk_min_i(f, num, args, result); return BR_DONE;
-            case OP_FPA_INTERNAL_MAX_I: m_conv.mk_max_i(f, num, args, result); return BR_DONE;
-
-            case OP_FPA_INTERNAL_RM:
-            case OP_FPA_INTERNAL_BVWRAP: 
-            case OP_FPA_INTERNAL_BVUNWRAP:                
-            case OP_FPA_INTERNAL_TO_REAL_UNSPECIFIED:
-            case OP_FPA_INTERNAL_TO_UBV_UNSPECIFIED: 
-            case OP_FPA_INTERNAL_TO_SBV_UNSPECIFIED: return BR_FAILED;
-            default:
-                TRACE("fpa2bv", tout << "unsupported operator: " << f->get_name() << "\n";
-                      for (unsigned i = 0; i < num; i++) tout << mk_ismt2_pp(args[i], m()) << std::endl;);
-                NOT_IMPLEMENTED_YET();
-            }
-        }
-        else {
-            SASSERT(!m_conv.is_float_family(f));
-            bool is_float_uf = m_conv.is_float(f->get_range()) || m_conv.is_rm(f->get_range());
-
-            for (unsigned i = 0; i < f->get_arity(); i++) {
-                sort * di = f->get_domain()[i];
-                is_float_uf |= m_conv.is_float(di) || m_conv.is_rm(di);
-            }
-
-            if (is_float_uf) {
-                m_conv.mk_uninterpreted_function(f, num, args, result);
-                return BR_DONE;
-            }
-        }
-
-        return BR_FAILED;
-    }
-
-    bool pre_visit(expr * t)
-    {
-        TRACE("fpa2bv", tout << "pre_visit: " << mk_ismt2_pp(t, m()) << std::endl;);
-
-        if (is_quantifier(t)) {            
-            quantifier * q = to_quantifier(t);            
-            TRACE("fpa2bv", tout << "pre_visit quantifier [" << q->get_id() << "]: " << mk_ismt2_pp(q->get_expr(), m()) << std::endl;);
-            sort_ref_vector new_bindings(m_manager);
-            for (unsigned i = 0 ; i < q->get_num_decls(); i++)
-                new_bindings.push_back(q->get_decl_sort(i));
-            SASSERT(new_bindings.size() == q->get_num_decls());
-            m_bindings.append(new_bindings);
-        }
-        return true;
-    }
+    bool pre_visit(expr * t);
 
     bool reduce_quantifier(quantifier * old_q, 
                            expr * new_body, 
                            expr * const * new_patterns, 
                            expr * const * new_no_patterns,
                            expr_ref & result,
-                           proof_ref & result_pr) {
-        unsigned curr_sz   = m_bindings.size();
-        SASSERT(old_q->get_num_decls() <= curr_sz);
-        unsigned num_decls = old_q->get_num_decls();
-        unsigned old_sz    = curr_sz - num_decls;
-        string_buffer<> name_buffer;
-        ptr_buffer<sort> new_decl_sorts;
-        sbuffer<symbol>  new_decl_names;
-        for (unsigned i = 0; i < num_decls; i++) {
-            symbol const & n = old_q->get_decl_name(i);
-            sort * s         = old_q->get_decl_sort(i);
-            if (m_conv.is_float(s)) {
-                unsigned ebits = m_conv.fu().get_ebits(s);
-                unsigned sbits = m_conv.fu().get_sbits(s);
-                name_buffer.reset();
-                name_buffer << n << ".bv";
-                new_decl_names.push_back(symbol(name_buffer.c_str()));
-                new_decl_sorts.push_back(m_conv.bu().mk_sort(sbits+ebits)); 
-            }
-            else {
-                new_decl_sorts.push_back(s);
-                new_decl_names.push_back(n);
-            }
-        }
-        result = m().mk_quantifier(old_q->is_forall(), new_decl_sorts.size(), new_decl_sorts.c_ptr(), new_decl_names.c_ptr(),
-                                   new_body, old_q->get_weight(), old_q->get_qid(), old_q->get_skid(),
-                                   old_q->get_num_patterns(), new_patterns, old_q->get_num_no_patterns(), new_no_patterns);
-        result_pr = 0;
-        m_bindings.shrink(old_sz);        
-        TRACE("fpa2bv", tout << "reduce_quantifier[" << old_q->get_depth() << "]: " << 
-                mk_ismt2_pp(old_q->get_expr(), m()) << std::endl <<
-                " new body: " << mk_ismt2_pp(new_body, m()) << std::endl;
-                tout << "result = " << mk_ismt2_pp(result, m()) << std::endl;);                
-        return true;
-    }
+                           proof_ref & result_pr);
 
-    bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr) { 
-        if (t->get_idx() >= m_bindings.size())
-            return false;
-        // unsigned inx = m_bindings.size() - t->get_idx() - 1;        
+    bool reduce_var(var * t, expr_ref & result, proof_ref & result_pr);
 
-        expr_ref new_exp(m());
-        sort * s = t->get_sort();
-        if (m_conv.is_float(s))
-        {
-            expr_ref new_var(m());
-            unsigned ebits = m_conv.fu().get_ebits(s);
-            unsigned sbits = m_conv.fu().get_sbits(s);
-            new_var = m().mk_var(t->get_idx(), m_conv.bu().mk_sort(sbits+ebits));
-            m_conv.mk_fp(m_conv.bu().mk_extract(sbits+ebits-1, sbits+ebits-1, new_var),
-                         m_conv.bu().mk_extract(ebits - 1, 0, new_var),
-                         m_conv.bu().mk_extract(sbits+ebits-2, ebits, new_var),                         
-                         new_exp);
-        }
-        else
-            new_exp = m().mk_var(t->get_idx(), s);
-
-        result = new_exp;
-        result_pr = 0;        
-        TRACE("fpa2bv", tout << "reduce_var: " << mk_ismt2_pp(t, m()) << " -> " << mk_ismt2_pp(result, m()) << std::endl;);
-        return true;
-    }
 };
 
-template class rewriter_tpl<fpa2bv_rewriter_cfg>;
 
 struct fpa2bv_rewriter : public rewriter_tpl<fpa2bv_rewriter_cfg> {
     fpa2bv_rewriter_cfg m_cfg;
diff --git a/src/ast/rewriter/arith_rewriter.cpp b/src/ast/rewriter/arith_rewriter.cpp
index e48a4fd2a..550171ab5 100644
--- a/src/ast/rewriter/arith_rewriter.cpp
+++ b/src/ast/rewriter/arith_rewriter.cpp
@@ -61,8 +61,10 @@ br_status arith_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * c
     case OP_ADD: st = mk_add_core(num_args, args, result); break;
     case OP_MUL: st = mk_mul_core(num_args, args, result); break;
     case OP_SUB: st = mk_sub(num_args, args, result); break;
-    case OP_DIV: SASSERT(num_args == 2); st = mk_div_core(args[0], args[1], result); break;
-    case OP_IDIV: SASSERT(num_args == 2); st = mk_idiv_core(args[0], args[1], result); break;
+    case OP_DIV: if (num_args == 1) { result = args[0]; st = BR_DONE; break; } 
+        SASSERT(num_args == 2); st = mk_div_core(args[0], args[1], result); break;
+    case OP_IDIV: if (num_args == 1) { result = args[0]; st = BR_DONE; break; }
+        SASSERT(num_args == 2); st = mk_idiv_core(args[0], args[1], result); break;
     case OP_MOD: SASSERT(num_args == 2); st = mk_mod_core(args[0], args[1], result); break;
     case OP_REM: SASSERT(num_args == 2); st = mk_rem_core(args[0], args[1], result); break;
     case OP_UMINUS: SASSERT(num_args == 1);  st = mk_uminus(args[0], result); break;
diff --git a/src/ast/rewriter/bool_rewriter.cpp b/src/ast/rewriter/bool_rewriter.cpp
index 0b8a51fb4..48dffdb58 100644
--- a/src/ast/rewriter/bool_rewriter.cpp
+++ b/src/ast/rewriter/bool_rewriter.cpp
@@ -572,35 +572,61 @@ bool bool_rewriter::local_ctx_simp(unsigned num_args, expr * const * args, expr_
 
 */
 br_status bool_rewriter::try_ite_value(app * ite, app * val, expr_ref & result) {
-    SASSERT(m().is_ite(ite));
+    expr* cond, *t, *e;
+    VERIFY(m().is_ite(ite, cond, t, e));
     SASSERT(m().is_value(val));
 
-    expr * t = ite->get_arg(1);
-    expr * e = ite->get_arg(2);
-    if (!m().is_value(t) || !m().is_value(e))
-        return BR_FAILED;
-
-    if (t != val && e != val) {
-        TRACE("try_ite_value", tout << mk_ismt2_pp(t, m()) << " " << mk_ismt2_pp(e, m()) << " " << mk_ismt2_pp(val, m()) << "\n";
-              tout << t << " " << e << " " << val << "\n";);
-        result = m().mk_false();
+    if (m().is_value(t) && m().is_value(e)) {
+        if (t != val && e != val) {
+            TRACE("try_ite_value", tout << mk_ismt2_pp(t, m()) << " " << mk_ismt2_pp(e, m()) << " " << mk_ismt2_pp(val, m()) << "\n";
+                  tout << t << " " << e << " " << val << "\n";);
+            result = m().mk_false();
+        }        
+        else if (t == val && e == val) {
+            result = m().mk_true();
+        }        
+        else if (t == val) {
+            result = cond;
+        }
+        else {
+            SASSERT(e == val);            
+            mk_not(cond, result);
+        }
         return BR_DONE;
     }
-
-    if (t == val && e == val) {
-        result = m().mk_true();
-        return BR_DONE;
+    if (m().is_value(t)) {
+        if (val == t) {
+            result = m().mk_or(cond, m().mk_eq(val, e));
+        }
+        else {
+            mk_not(cond, result);
+            result = m().mk_and(result, m().mk_eq(val, e));
+        }
+        return BR_REWRITE2;
+    }
+    if (m().is_value(e)) {
+        if (val == e) {
+            mk_not(cond, result);
+            result = m().mk_or(result, m().mk_eq(val, t));
+        }
+        else {
+            result = m().mk_and(cond, m().mk_eq(val, t));
+        }
+        return BR_REWRITE2;
+    }
+    expr* cond2, *t2, *e2;
+    if (m().is_ite(t, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
+        try_ite_value(to_app(t), val, result);
+        result = m().mk_ite(cond, result, m().mk_eq(e, val));
+        return BR_REWRITE2;
+    }
+    if (m().is_ite(e, cond2, t2, e2) && m().is_value(t2) && m().is_value(e2)) {
+        try_ite_value(to_app(e), val, result);
+        result = m().mk_ite(cond, m().mk_eq(t, val), result);
+        return BR_REWRITE2;
     }
 
-    if (t == val) {
-        result = ite->get_arg(0);
-        return BR_DONE;
-    }
-
-    SASSERT(e == val);
-
-    mk_not(ite->get_arg(0), result);
-    return BR_DONE;
+    return BR_FAILED;
 }
 
 #if 0
diff --git a/src/ast/rewriter/rewriter.cpp b/src/ast/rewriter/rewriter.cpp
index e9f66f10c..2b5e7e006 100644
--- a/src/ast/rewriter/rewriter.cpp
+++ b/src/ast/rewriter/rewriter.cpp
@@ -51,6 +51,8 @@ void rewriter_core::cache_result(expr * k, expr * v) {
     
     TRACE("rewriter_cache_result", tout << mk_ismt2_pp(k, m()) << "\n--->\n" << mk_ismt2_pp(v, m()) << "\n";);
 
+    SASSERT(m().get_sort(k) == m().get_sort(v));
+
     m_cache->insert(k, v);
 #if 0
     static unsigned num_cached = 0;
diff --git a/src/ast/rewriter/rewriter.h b/src/ast/rewriter/rewriter.h
index 934d186aa..44f436fa8 100644
--- a/src/ast/rewriter/rewriter.h
+++ b/src/ast/rewriter/rewriter.h
@@ -214,10 +214,12 @@ protected:
     unsigned                   m_num_steps;
     ptr_vector<expr>           m_bindings;
     var_shifter                m_shifter;
+    inv_var_shifter            m_inv_shifter;
     expr_ref                   m_r;
     proof_ref                  m_pr;
     proof_ref                  m_pr2;
-    
+    unsigned_vector            m_shifts;
+
     svector<frame> & frame_stack() { return this->m_frame_stack; }
     svector<frame> const & frame_stack() const { return this->m_frame_stack; }
     expr_ref_vector & result_stack() { return this->m_result_stack; }
@@ -225,6 +227,8 @@ protected:
     proof_ref_vector & result_pr_stack() { return this->m_result_pr_stack; }
     proof_ref_vector const & result_pr_stack() const { return this->m_result_pr_stack; }
 
+    void display_bindings(std::ostream& out);
+
     void set_new_child_flag(expr * old_t) {
         SASSERT(frame_stack().empty() || frame_stack().back().m_state != PROCESS_CHILDREN || this->is_child_of_top_frame(old_t));
         if (!frame_stack().empty())
@@ -232,7 +236,6 @@ protected:
     }
     void set_new_child_flag(expr * old_t, expr * new_t) { if (old_t != new_t) set_new_child_flag(old_t); }
 
-
     // cache the result of shared non atomic expressions.
     bool cache_results() const { return m_cfg.cache_results(); }
     // cache all results share and non shared expressions non atomic expressions.
diff --git a/src/ast/rewriter/rewriter_def.h b/src/ast/rewriter/rewriter_def.h
index 9bfe47f46..4837a053f 100644
--- a/src/ast/rewriter/rewriter_def.h
+++ b/src/ast/rewriter/rewriter_def.h
@@ -24,6 +24,7 @@ template<bool ProofGen>
 void rewriter_tpl<Config>::process_var(var * v) {
     if (m_cfg.reduce_var(v, m_r, m_pr)) {
         result_stack().push_back(m_r);
+        SASSERT(v->get_sort() == m().get_sort(m_r));
         if (ProofGen) {
             result_pr_stack().push_back(m_pr);
             m_pr = 0; 
@@ -36,18 +37,21 @@ void rewriter_tpl<Config>::process_var(var * v) {
         // bindings are only used when Proof Generation is not enabled.
         unsigned idx = v->get_idx();
         if (idx < m_bindings.size()) {
-            expr * r = m_bindings[m_bindings.size() - idx - 1];
-            TRACE("process_var", if (r) tout << "idx: " << idx << " --> " << mk_ismt2_pp(r, m()) << "\n";
-                  tout << "bindings:\n";
-                  for (unsigned i = 0; i < m_bindings.size(); i++) if (m_bindings[i]) tout << i << ": " << mk_ismt2_pp(m_bindings[i], m()) << "\n";);
+            unsigned index = m_bindings.size() - idx - 1;
+            expr * r = m_bindings[index];
             if (r != 0) {
-                if (m_num_qvars == 0 || is_ground(r)) {
-                    result_stack().push_back(r);
+                SASSERT(v->get_sort() == m().get_sort(r));
+                if (!is_ground(r) && m_shifts[index] != UINT_MAX) {
+                    
+                    unsigned shift_amount = m_bindings.size() - m_shifts[index];
+                    expr_ref tmp(m());
+                    m_shifter(r, shift_amount, tmp);
+                    result_stack().push_back(tmp);
+                    TRACE("process_var", tout << "shift: " << shift_amount << " idx: " << idx << " --> " << tmp << "\n";
+                          display_bindings(tout););
                 }
                 else {
-                    expr_ref new_term(m());
-                    m_shifter(r, m_num_qvars, new_term);
-                    result_stack().push_back(new_term);
+                    result_stack().push_back(r);
                 }
                 set_new_child_flag(v);
                 return;
@@ -64,6 +68,7 @@ template<bool ProofGen>
 void rewriter_tpl<Config>::process_const(app * t) {
     SASSERT(t->get_num_args() == 0);
     br_status st = m_cfg.reduce_app(t->get_decl(), 0, 0, m_r, m_pr);
+    SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t));
     SASSERT(st == BR_FAILED || st == BR_DONE);
     if (st == BR_DONE) {
         result_stack().push_back(m_r.get());
@@ -100,6 +105,7 @@ bool rewriter_tpl<Config>::visit(expr * t, unsigned max_depth) {
     proof * new_t_pr;
     if (m_cfg.get_subst(t, new_t, new_t_pr)) {
         TRACE("rewriter_subst", tout << "subst\n" << mk_ismt2_pp(t, m()) << "\n---->\n" << mk_ismt2_pp(new_t, m()) << "\n";);
+        SASSERT(m().get_sort(t) == m().get_sort(new_t));
         result_stack().push_back(new_t);
         set_new_child_flag(t, new_t);
         if (ProofGen)
@@ -124,6 +130,7 @@ bool rewriter_tpl<Config>::visit(expr * t, unsigned max_depth) {
 #endif
         expr * r = get_cached(t);
         if (r) {
+            SASSERT(m().get_sort(r) == m().get_sort(t));
             result_stack().push_back(r);
             set_new_child_flag(t, r);
             if (ProofGen) {
@@ -213,6 +220,7 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
             }
         }
         br_status st = m_cfg.reduce_app(f, new_num_args, new_args, m_r, m_pr2);
+        SASSERT(st != BR_DONE || m().get_sort(m_r) == m().get_sort(t));
         TRACE("reduce_app", 
               tout << mk_ismt2_pp(t, m()) << "\n";
               tout << "st: " << st;
@@ -220,6 +228,7 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
               tout << "\n";);
         if (st != BR_FAILED) {
             result_stack().shrink(fr.m_spos);
+            SASSERT(m().get_sort(m_r) == m().get_sort(t));
             result_stack().push_back(m_r);
             if (ProofGen) {
                 result_pr_stack().shrink(fr.m_spos);
@@ -295,6 +304,7 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
         if (get_macro(f, def, def_q, def_pr)) {
             SASSERT(!f->is_associative() || !flat_assoc(f));
             SASSERT(new_num_args == t->get_num_args());
+            SASSERT(m().get_sort(def) == m().get_sort(t));
             if (is_ground(def)) {
                 m_r = def;
                 if (ProofGen) {
@@ -317,16 +327,18 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
                     TRACE("get_macro", tout << "f: " << f->get_name() << ", def: \n" << mk_ismt2_pp(def, m()) << "\n";
                           tout << "Args num: " << num_args << "\n";
                           for (unsigned i = 0; i < num_args; i++) tout << mk_ismt2_pp(new_args[i], m()) << "\n";);
+                    unsigned sz = m_bindings.size();
                     unsigned i = num_args;
                     while (i > 0) {
                         --i;
-                        m_bindings.push_back(new_args[i]);
+                        m_bindings.push_back(new_args[i]); // num_args - i - 1]);                        
+                        m_shifts.push_back(sz);
                     }
                     result_stack().push_back(def);
-                    TRACE("get_macro", tout << "bindings:\n";
-                          for (unsigned j = 0; j < m_bindings.size(); j++) tout << j << ": " << mk_ismt2_pp(m_bindings[j], m()) << "\n";);
+                    TRACE("get_macro", display_bindings(tout););
                     begin_scope();
-                    m_num_qvars = 0;
+                    m_num_qvars += num_args;
+                    //m_num_qvars = 0;
                     m_root      = def;
                     push_frame(def, false, RW_UNBOUNDED_DEPTH);
                     return;
@@ -383,9 +395,17 @@ void rewriter_tpl<Config>::process_app(app * t, frame & fr) {
         SASSERT(fr.m_spos + t->get_num_args() + 2 == result_stack().size());
         SASSERT(t->get_num_args() <= m_bindings.size());
         if (!ProofGen) {
-            m_bindings.shrink(m_bindings.size() - t->get_num_args());
+            expr_ref tmp(m());
+            unsigned num_args = t->get_num_args();
+            m_bindings.shrink(m_bindings.size() - num_args);
+            m_shifts.shrink(m_shifts.size() - num_args);
+            m_num_qvars -= num_args;
             end_scope();
             m_r = result_stack().back();
+            if (!is_ground(m_r)) {
+                m_inv_shifter(m_r, num_args, tmp);
+                m_r = tmp;
+            }
             result_stack().shrink(fr.m_spos);
             result_stack().push_back(m_r);
             cache_result<ProofGen>(t, m_r, m_pr, fr.m_cache_result);
@@ -411,23 +431,26 @@ template<typename Config>
 template<bool ProofGen>
 void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
     SASSERT(fr.m_state == PROCESS_CHILDREN);
+    unsigned num_decls = q->get_num_decls();
     if (fr.m_i == 0) {
         if (!ProofGen) {
             begin_scope();
             m_root       = q->get_expr();
-        }
-        m_num_qvars += q->get_num_decls();
-        if (!ProofGen) {
-            for (unsigned i = 0; i < q->get_num_decls(); i++) 
+            unsigned sz = m_bindings.size();
+            for (unsigned i = 0; i < num_decls; i++) {
                 m_bindings.push_back(0);
+                m_shifts.push_back(sz);
+            }
         }
+        m_num_qvars += num_decls;
     }
     unsigned num_children = rewrite_patterns() ? q->get_num_children() : 1;
     while (fr.m_i < num_children) {
         expr * child = q->get_child(fr.m_i);
         fr.m_i++;
-        if (!visit<ProofGen>(child, fr.m_max_depth))
+        if (!visit<ProofGen>(child, fr.m_max_depth)) {
             return;
+        }
     }
     SASSERT(fr.m_spos + num_children == result_stack().size());
     expr * const * it = result_stack().c_ptr() + fr.m_spos;
@@ -456,6 +479,8 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
         result_pr_stack().push_back(m_pr);
     }
     else {
+        expr_ref tmp(m());
+
         if (!m_cfg.reduce_quantifier(q, new_body, new_pats, new_no_pats, m_r, m_pr)) {
             if (fr.m_new_child) {
                 m_r = m().update_quantifier(q, q->get_num_patterns(), new_pats, q->get_num_no_patterns(), new_no_pats, new_body);
@@ -468,9 +493,11 @@ void rewriter_tpl<Config>::process_quantifier(quantifier * q, frame & fr) {
     }
     result_stack().shrink(fr.m_spos);
     result_stack().push_back(m_r.get());
+    SASSERT(m().is_bool(m_r));
     if (!ProofGen) {
-        SASSERT(q->get_num_decls() <= m_bindings.size());
-        m_bindings.shrink(m_bindings.size() - q->get_num_decls());
+        SASSERT(num_decls <= m_bindings.size());
+        m_bindings.shrink(m_bindings.size() - num_decls);
+        m_shifts.shrink(m_shifts.size() - num_decls);
         end_scope();
         cache_result<ProofGen>(q, m_r, m_pr, fr.m_cache_result);
     }
@@ -496,6 +523,7 @@ rewriter_tpl<Config>::rewriter_tpl(ast_manager & m, bool proof_gen, Config & cfg
     m_cfg(cfg),
     m_num_steps(0),
     m_shifter(m),
+    m_inv_shifter(m),
     m_r(m),
     m_pr(m),
     m_pr2(m) {
@@ -510,7 +538,9 @@ void rewriter_tpl<Config>::reset() {
     m_cfg.reset();
     rewriter_core::reset();
     m_bindings.reset();
+    m_shifts.reset();
     m_shifter.reset();
+    m_inv_shifter.reset();
 }
 
 template<typename Config>
@@ -519,6 +549,17 @@ void rewriter_tpl<Config>::cleanup() {
     rewriter_core::cleanup();
     m_bindings.finalize();
     m_shifter.cleanup();
+    m_shifts.finalize();
+    m_inv_shifter.cleanup();
+}
+
+template<typename Config>
+void rewriter_tpl<Config>::display_bindings(std::ostream& out) {
+    out << "bindings:\n";
+    for (unsigned i = 0; i < m_bindings.size(); i++) {
+        if (m_bindings[i]) 
+            out << i << ": " << mk_ismt2_pp(m_bindings[i], m()) << "\n";
+    }
 }
 
 template<typename Config>
@@ -526,11 +567,14 @@ void rewriter_tpl<Config>::set_bindings(unsigned num_bindings, expr * const * bi
     SASSERT(!m_proof_gen);
     SASSERT(not_rewriting());
     m_bindings.reset();
+    m_shifts.reset();
     unsigned i = num_bindings;
     while (i > 0) {
         --i;
         m_bindings.push_back(bindings[i]);
+        m_shifts.push_back(UINT_MAX);
     }
+    TRACE("rewriter", display_bindings(tout););
 }
 
 template<typename Config>
@@ -538,9 +582,12 @@ void rewriter_tpl<Config>::set_inv_bindings(unsigned num_bindings, expr * const
     SASSERT(!m_proof_gen);
     SASSERT(not_rewriting());
     m_bindings.reset();
+    m_shifts.reset();
     for (unsigned i = 0; i < num_bindings; i++) {
         m_bindings.push_back(bindings[i]);
+        m_shifts.push_back(UINT_MAX);
     }
+    TRACE("rewriter", display_bindings(tout););
 }
 
 template<typename Config>
@@ -562,9 +609,11 @@ void rewriter_tpl<Config>::main_loop(expr * t, expr_ref & result, proof_ref & re
                 result_pr = m().mk_reflexivity(t);
             SASSERT(result_pr_stack().empty());
         }
-        return;
     }
-    resume_core<ProofGen>(result, result_pr);
+    else {
+        resume_core<ProofGen>(result, result_pr);
+    }
+    TRACE("rewriter", tout << mk_ismt2_pp(t, m()) << "\n=>\n" << result << "\n";;);
 }
 
 /**
@@ -587,6 +636,7 @@ void rewriter_tpl<Config>::resume_core(expr_ref & result, proof_ref & result_pr)
         if (first_visit(fr) && fr.m_cache_result) {
             expr * r = get_cached(t);
             if (r) {
+                SASSERT(m().get_sort(r) == m().get_sort(t));
                 result_stack().push_back(r);
                 if (ProofGen) {
                     proof * pr = get_cached_pr(t);
diff --git a/src/ast/rewriter/seq_rewriter.cpp b/src/ast/rewriter/seq_rewriter.cpp
index f04d445e1..75c8266be 100644
--- a/src/ast/rewriter/seq_rewriter.cpp
+++ b/src/ast/rewriter/seq_rewriter.cpp
@@ -579,7 +579,7 @@ br_status seq_rewriter::mk_seq_contains(expr* a, expr* b, expr_ref& result) {
     unsigned lenA = 0, lenB = 0;
     bool lA = min_length(as.size(), as.c_ptr(), lenA);
     if (lA) {
-        bool lB = min_length(bs.size(), bs.c_ptr(), lenB);
+        min_length(bs.size(), bs.c_ptr(), lenB);
         if (lenB > lenA) {
             result = m().mk_false();
             return BR_DONE;
diff --git a/src/model/model_core.cpp b/src/model/model_core.cpp
index 5c2fd81d4..3a3a8a93a 100644
--- a/src/model/model_core.cpp
+++ b/src/model/model_core.cpp
@@ -29,7 +29,6 @@ model_core::~model_core() {
     decl2finterp::iterator it2  = m_finterp.begin();
     decl2finterp::iterator end2 = m_finterp.end();
     for (; it2 != end2; ++it2) {
-        func_decl* d = it2->m_key;
         m_manager.dec_ref(it2->m_key);
         dealloc(it2->m_value);
     }   
diff --git a/src/model/model_evaluator.cpp b/src/model/model_evaluator.cpp
index d417adc1b..486111ae4 100644
--- a/src/model/model_evaluator.cpp
+++ b/src/model/model_evaluator.cpp
@@ -31,8 +31,9 @@ Revision History:
 #include"rewriter_def.h"
 #include"cooperate.h"
 
+
 struct evaluator_cfg : public default_rewriter_cfg {
-    model_core &                         m_model;
+    model_core &                    m_model;
     bool_rewriter                   m_b_rw;
     arith_rewriter                  m_a_rw;
     bv_rewriter                     m_bv_rw;
@@ -59,9 +60,10 @@ struct evaluator_cfg : public default_rewriter_cfg {
         m_pb_rw(m),
         m_f_rw(m),
         m_seq_rw(m) {
-        m_b_rw.set_flat(false);
-        m_a_rw.set_flat(false);
-        m_bv_rw.set_flat(false);
+        bool flat = true;
+        m_b_rw.set_flat(flat);
+        m_a_rw.set_flat(flat);
+        m_bv_rw.set_flat(flat);
         m_bv_rw.set_mkbv2num(true);
         updt_params(p);
     }
@@ -181,10 +183,12 @@ struct evaluator_cfg : public default_rewriter_cfg {
     }
 
     bool get_macro(func_decl * f, expr * & def, quantifier * & q, proof * & def_pr) {
-        TRACE("model_evaluator", tout << "get_macro for " << f->get_name() << " (model completion: " << m_model_completion << ")\n";);
+
+#define TRACE_MACRO TRACE("model_evaluator", tout << "get_macro for " << f->get_name() << " (model completion: " << m_model_completion << ")\n";);
 
         func_interp * fi = m_model.get_func_interp(f);
         if (fi != 0) {
+            TRACE_MACRO;
             if (fi->is_partial()) {
                 if (m_model_completion) {
                     sort * s   = f->get_range();
@@ -204,6 +208,7 @@ struct evaluator_cfg : public default_rewriter_cfg {
             (f->get_family_id() == null_family_id ||
              m().get_plugin(f->get_family_id())->is_considered_uninterpreted(f)))
         {
+            TRACE_MACRO;
             sort * s   = f->get_range();
             expr * val = m_model.get_some_value(s);
             func_interp * new_fi = alloc(func_interp, m(), f->get_arity());
diff --git a/src/model/model_params.pyg b/src/model/model_params.pyg
index 14e83952c..dfa3748bc 100644
--- a/src/model/model_params.pyg
+++ b/src/model/model_params.pyg
@@ -4,5 +4,6 @@ def_module_params('model',
                           ('v1', BOOL, False, 'use Z3 version 1.x pretty printer'),
                           ('v2', BOOL, False, 'use Z3 version 2.x (x <= 16) pretty printer'),
                           ('compact', BOOL, False, 'try to compact function graph (i.e., function interpretations that are lookup tables)'),
+                          ('new_eval', BOOL, True, 'use new evaluator (temporary parameter for testing)'),
                           ))
 
diff --git a/src/smt/proto_model/proto_model.cpp b/src/smt/proto_model/proto_model.cpp
index 485fe1751..cb6b8c68d 100644
--- a/src/smt/proto_model/proto_model.cpp
+++ b/src/smt/proto_model/proto_model.cpp
@@ -30,12 +30,14 @@ Revision History:
 proto_model::proto_model(ast_manager & m, simplifier & s, params_ref const & p):
     model_core(m),
     m_simplifier(s),
-    m_afid(m.mk_family_id(symbol("array"))) {
+    m_afid(m.mk_family_id(symbol("array"))),
+    m_eval(*this) {
     register_factory(alloc(basic_factory, m));
     m_user_sort_factory = alloc(user_sort_factory, m);
     register_factory(m_user_sort_factory);
     
     m_model_partial = model_params(p).partial();
+    m_use_new_eval  = model_params(p).new_eval();
 }
 
 
@@ -157,6 +159,19 @@ bool proto_model::is_select_of_model_value(expr* e) const {
    So, if model_completion == true, the evaluator never fails if it doesn't contain quantifiers.
 */
 bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
+    if (m_use_new_eval) {
+        m_eval.set_model_completion(model_completion);
+        try {
+            m_eval(e, result);
+            return true;
+        }
+        catch (model_evaluator_exception & ex) {
+            (void)ex;
+            TRACE("model_evaluator", tout << ex.msg() << "\n";);
+            return false;
+        }
+    }
+
     bool is_ok = true;
     SASSERT(is_well_sorted(m_manager, e));
     TRACE("model_eval", tout << mk_pp(e, m_manager) << "\n";
diff --git a/src/smt/proto_model/proto_model.h b/src/smt/proto_model/proto_model.h
index 1b63f8b20..2c27ac39a 100644
--- a/src/smt/proto_model/proto_model.h
+++ b/src/smt/proto_model/proto_model.h
@@ -29,6 +29,7 @@ Revision History:
 #define PROTO_MODEL_H_
 
 #include"model_core.h"
+#include"model_evaluator.h"
 #include"value_factory.h"
 #include"plugin_manager.h"
 #include"simplifier.h"
@@ -44,8 +45,10 @@ class proto_model : public model_core {
     family_id                     m_afid;        //!< array family id: hack for displaying models in V1.x style
     func_decl_set                 m_aux_decls;
     ptr_vector<expr>              m_tmp;
+    model_evaluator               m_eval;
 
     bool                          m_model_partial;
+    bool                          m_use_new_eval;
 
     expr * mk_some_interp_for(func_decl * d);
 
diff --git a/src/smt/smt_model_checker.cpp b/src/smt/smt_model_checker.cpp
index e4bfcc806..0d9c361f8 100644
--- a/src/smt/smt_model_checker.cpp
+++ b/src/smt/smt_model_checker.cpp
@@ -95,7 +95,8 @@ namespace smt {
             expr * e = *it;
             eqs.push_back(m.mk_eq(sk, e));
         }
-        m_aux_context->assert_expr(m.mk_or(eqs.size(), eqs.c_ptr()));
+        expr_ref fml(m.mk_or(eqs.size(), eqs.c_ptr()), m);
+        m_aux_context->assert_expr(fml);
     }
 
 #define PP_DEPTH 8
@@ -105,9 +106,13 @@ namespace smt {
 
        The variables are replaced by skolem constants. These constants are stored in sks.
     */
+
     void model_checker::assert_neg_q_m(quantifier * q, expr_ref_vector & sks) {
         expr_ref tmp(m);
-        m_curr_model->eval(q->get_expr(), tmp, true);
+        if (!m_curr_model->eval(q->get_expr(), tmp, true)) {
+            return;
+        }
+        //std::cout << tmp << "\n";
         TRACE("model_checker", tout << "q after applying interpretation:\n" << mk_ismt2_pp(tmp, m) << "\n";);        
         ptr_buffer<expr> subst_args;
         unsigned num_decls = q->get_num_decls();
@@ -261,10 +266,11 @@ namespace smt {
         
         lbool r = m_aux_context->check();
         TRACE("model_checker", tout << "[complete] model-checker result: " << to_sat_str(r) << "\n";);
-        if (r == l_false) {
+        if (r != l_true) {
             m_aux_context->pop(1);
-            return true; // quantifier is satisfied by m_curr_model
+            return r == l_false; // quantifier is satisfied by m_curr_model
         }
+		
         model_ref complete_cex;
         m_aux_context->get_model(complete_cex); 
         
@@ -276,7 +282,7 @@ namespace smt {
         while (true) {
             lbool r = m_aux_context->check();
             TRACE("model_checker", tout << "[restricted] model-checker (" << (num_new_instances+1) << ") result: " << to_sat_str(r) << "\n";);
-            if (r == l_false)
+            if (r != l_true)
                 break; 
             model_ref cex;
             m_aux_context->get_model(cex);
diff --git a/src/smt/theory_arith_core.h b/src/smt/theory_arith_core.h
index 301b5d14d..291a0f0d8 100644
--- a/src/smt/theory_arith_core.h
+++ b/src/smt/theory_arith_core.h
@@ -1619,6 +1619,7 @@ namespace smt {
         m_found_underspecified_op(false),
         m_arith_eq_adapter(*this, params, m_util),
         m_asserted_qhead(0),
+        m_row_vars_top(0),
         m_to_patch(1024),
         m_blands_rule(false),
         m_random(params.m_arith_random_seed),
@@ -1631,7 +1632,6 @@ namespace smt {
         m_liberal_final_check(true),
         m_changed_assignment(false),
         m_assume_eq_head(0),
-        m_row_vars_top(0),
         m_nl_rounds(0),
         m_nl_gb_exhausted(false),
         m_nl_new_exprs(m),
diff --git a/src/smt/theory_seq.cpp b/src/smt/theory_seq.cpp
index 551e80c85..5bd00db5d 100644
--- a/src/smt/theory_seq.cpp
+++ b/src/smt/theory_seq.cpp
@@ -1591,7 +1591,6 @@ bool theory_seq::solve_ne(unsigned idx) {
 }
 
 bool theory_seq::solve_nc(unsigned idx) {
-    context& ctx = get_context();
     nc const& n = m_ncs[idx];
 
     dependency* deps = n.deps();    
diff --git a/src/tactic/bv/bvarray2uf_rewriter.cpp b/src/tactic/bv/bvarray2uf_rewriter.cpp
index f4f7fac16..54c654d54 100644
--- a/src/tactic/bv/bvarray2uf_rewriter.cpp
+++ b/src/tactic/bv/bvarray2uf_rewriter.cpp
@@ -24,6 +24,7 @@ Notes:
 #include"params.h"
 #include"ast_pp.h"
 #include"bvarray2uf_rewriter.h"
+#include"rewriter_def.h"
 
 // [1] C. M. Wintersteiger, Y. Hamadi, and L. de Moura: Efficiently Solving
 //     Quantified Bit-Vector Formulas, in Formal Methods in System Design,
@@ -345,3 +346,5 @@ bool bvarray2uf_rewriter_cfg::reduce_var(var * t, expr_ref & result, proof_ref &
     NOT_IMPLEMENTED_YET();
     return true;
 }
+
+template class rewriter_tpl<bvarray2uf_rewriter_cfg>;
diff --git a/src/tactic/bv/bvarray2uf_rewriter.h b/src/tactic/bv/bvarray2uf_rewriter.h
index e65340cc3..81b53ddd7 100644
--- a/src/tactic/bv/bvarray2uf_rewriter.h
+++ b/src/tactic/bv/bvarray2uf_rewriter.h
@@ -20,7 +20,7 @@ Notes:
 #ifndef BVARRAY2UF_REWRITER_H_
 #define BVARRAY2UF_REWRITER_H_
 
-#include"rewriter_def.h"
+#include"rewriter.h"
 #include"extension_model_converter.h"
 #include"filter_model_converter.h"
 
@@ -71,7 +71,6 @@ protected:
     func_decl_ref mk_uf_for_array(expr * e);
 };
 
-template class rewriter_tpl<bvarray2uf_rewriter_cfg>;
 
 struct bvarray2uf_rewriter : public rewriter_tpl<bvarray2uf_rewriter_cfg> {
     bvarray2uf_rewriter_cfg m_cfg;
diff --git a/src/test/main.cpp b/src/test/main.cpp
index be12286fb..875f7bed0 100644
--- a/src/test/main.cpp
+++ b/src/test/main.cpp
@@ -226,6 +226,7 @@ int main(int argc, char ** argv) {
     TST(sat_user_scope);
     TST(pdr);
     TST_ARGV(ddnf);
+    TST(model_evaluator);
     //TST_ARGV(hs);
 }
 
diff --git a/src/test/model_evaluator.cpp b/src/test/model_evaluator.cpp
new file mode 100644
index 000000000..6e3a1f441
--- /dev/null
+++ b/src/test/model_evaluator.cpp
@@ -0,0 +1,66 @@
+#include "model.h"
+#include "model_evaluator.h"
+#include "model_pp.h"
+#include "arith_decl_plugin.h"
+#include "reg_decl_plugins.h"
+#include "ast_pp.h"
+
+
+void tst_model_evaluator() {
+    ast_manager m;
+    reg_decl_plugins(m);
+    arith_util a(m);
+
+    model mdl(m);
+
+    sort* sI = a.mk_int();
+
+    sort* dom[2] = { sI, m.mk_bool_sort() };
+    func_decl_ref f(m.mk_func_decl(symbol("f"), 2, dom, sI), m);
+    func_decl_ref g(m.mk_func_decl(symbol("g"), 2, dom, sI), m);
+    func_decl_ref h(m.mk_func_decl(symbol("h"), 2, dom, sI), m);
+    func_decl_ref F(m.mk_func_decl(symbol("F"), 2, dom, sI), m);
+    func_decl_ref G(m.mk_func_decl(symbol("G"), 2, dom, sI), m);
+    expr_ref vI0(m.mk_var(0, sI), m);
+    expr_ref vI1(m.mk_var(1, sI), m);
+    expr_ref vB0(m.mk_var(0, m.mk_bool_sort()), m);
+    expr_ref vB1(m.mk_var(1, m.mk_bool_sort()), m);
+    expr_ref vB2(m.mk_var(2, m.mk_bool_sort()), m);
+    expr_ref f01(m.mk_app(f, vI0, vB1), m);
+    expr_ref g01(m.mk_app(g, vI0, vB1), m);
+    expr_ref h01(m.mk_app(h, vI0, vB1), m);
+    func_interp* fi = alloc(func_interp, m, 2);
+    func_interp* gi = alloc(func_interp, m, 2);
+    func_interp* hi = alloc(func_interp, m, 2);
+    hi->set_else(m.mk_ite(vB1, m.mk_app(f, vI0, vB1), m.mk_app(g, vI0, vB1)));
+    mdl.register_decl(h, hi);
+    
+
+    model_evaluator eval(mdl);
+
+    expr_ref e(m), v(m);
+
+    {
+        symbol nI("N");
+        fi->set_else(m.mk_ite(m.mk_exists(1, &sI, &nI, a.mk_le(vI0, m.mk_app(F, vI1, vB2))), vI0, a.mk_int(1)));
+        gi->set_else(m.mk_ite(m.mk_exists(1, &sI, &nI, a.mk_le(vI0, m.mk_app(G, vI1, vB2))), a.mk_int(2), vI0));
+        mdl.register_decl(g, gi);
+        mdl.register_decl(f, fi);
+        model_pp(std::cout, mdl);
+        e = m.mk_app(h, vI0, vB1);
+        eval(e, v);
+        std::cout << e << " " << v << "\n";
+    }
+
+    {
+        fi->set_else(m.mk_app(F, vI0, vB1));
+        gi->set_else(m.mk_app(G, vI0, vB1));
+        mdl.register_decl(g, gi);
+        mdl.register_decl(h, hi);
+        model_pp(std::cout, mdl);
+        e = m.mk_app(h, vI0, vB1);
+        eval(e, v);
+        std::cout << e << " " << v << "\n";
+    }
+    
+}