From 207c1c509f4cc8ae854830d34c2ab60723ce5f91 Mon Sep 17 00:00:00 2001
From: Lev Nachmanson <levnach@hotmail.com>
Date: Tue, 6 Aug 2019 11:41:37 -0700
Subject: [PATCH] fixes in horner's heuristic

Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
---
 src/math/lp/horner.cpp     | 10 ++++++----
 src/math/lp/lar_solver.cpp | 18 +++++++++++++----
 src/math/lp/lar_term.h     | 40 +++++++++++++++++++++++++++++++++++---
 src/math/lp/lp_utils.h     |  4 +---
 src/math/lp/nla_core.cpp   |  2 +-
 src/math/lp/nla_expr.h     |  7 +++++--
 6 files changed, 64 insertions(+), 17 deletions(-)

diff --git a/src/math/lp/horner.cpp b/src/math/lp/horner.cpp
index 6fa6e2f06..3bb84f9c7 100644
--- a/src/math/lp/horner.cpp
+++ b/src/math/lp/horner.cpp
@@ -241,7 +241,7 @@ void horner::add_linear_to_vector(const nex& e, vector<std::pair<rational, lpvar
         SASSERT(false);
     }
 }
-// e = a * can_t + b, but we do not calculate the offset here
+// e = a * can_t + b
 lp::lar_term horner::expression_to_normalized_term(nex& e, rational& a, rational& b) {
     TRACE("nla_horner_details", tout << e << "\n";);
     lpvar smallest_j;
@@ -253,12 +253,13 @@ lp::lar_term horner::expression_to_normalized_term(nex& e, rational& a, rational
             b += c.value();
         } else {
             add_linear_to_vector(c, v);
-            if (v.size() == 1 || smallest_j <  v.back().second) {
+            if (v.size() == 1 || smallest_j > v.back().second) {
                 smallest_j = v.back().second;
                 a_index = v.size() - 1;
             }
         }
     }
+    TRACE("nla_horner_details", tout << "a_index = " << a_index << ", v="; print_vector(v, tout) << "\n";);
     a = v[a_index].first;
     lp::lar_term t;
 
@@ -277,7 +278,8 @@ lp::lar_term horner::expression_to_normalized_term(nex& e, rational& a, rational
         }
     }
     TRACE("nla_horner_details", tout << a << "* (";
-          lp::lar_solver::print_term_as_indices(t, tout) << ") + " << b << std::endl;); 
+          lp::lar_solver::print_term_as_indices(t, tout) << ") + " << b << std::endl;);
+    SASSERT(t.is_normalized());
     return t;
 }
 
@@ -346,7 +348,7 @@ interv horner::interval_of_sum(const nex& e) {
     TRACE("nla_horner_details", tout << "e=" << e << "\n";);
     SASSERT(e.is_sum());
     interv i_e = interval_of_sum_no_terms(e);
-    if (e.sum_is_linear()) {
+    if (e.sum_is_a_linear_term()) {
         interv i_from_term ;
         if (interval_from_term(e, i_from_term)
             &&
diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp
index 182bd3fb3..c489aed15 100644
--- a/src/math/lp/lar_solver.cpp
+++ b/src/math/lp/lar_solver.cpp
@@ -2376,13 +2376,17 @@ void lar_solver::register_normalized_term(const lar_term& t, lpvar j) {
     lar_term normalized_t = t.get_normalized_by_min_var();
     TRACE("lar_solver_terms", tout << "t="; print_term_as_indices(t, tout);
           tout << ", normalized_t="; print_term_as_indices(normalized_t, tout) << "\n";);
-    lp_assert(m_normalized_terms_to_columns.find(normalized_t) == m_normalized_terms_to_columns.end());
-    m_normalized_terms_to_columns[normalized_t] = j;            
+    if (m_normalized_terms_to_columns.find(normalized_t) == m_normalized_terms_to_columns.end()) {
+        m_normalized_terms_to_columns[normalized_t] = j;
+    } else {
+        TRACE("lar_solver_terms", tout << "the term has been seen already\n";);        
+    }
 }
 
 void lar_solver::deregister_normalized_term(const lar_term& t) {
+    TRACE("lar_solver_terms", tout << "deregister term ";
+          print_term_as_indices(t, tout) << "\n";);
     lar_term normalized_t = t.get_normalized_by_min_var();
-    lp_assert(m_normalized_terms_to_columns.find(normalized_t) != m_normalized_terms_to_columns.end());
     m_normalized_terms_to_columns.erase(normalized_t);
 }
 
@@ -2395,9 +2399,15 @@ void lar_solver::register_existing_terms() {
 }
 
 unsigned lar_solver::fetch_normalized_term_column(const lar_term& c) const {
+    TRACE("lar_solver_terms", tout << "looking for term ";
+          print_term_as_indices(c, tout) << "\n";);
+    lp_assert(c.is_normalized());
     auto it = m_normalized_terms_to_columns.find(c);
-    if (it != m_normalized_terms_to_columns.end())
+    if (it != m_normalized_terms_to_columns.end()) {
+        TRACE("lar_solver_terms", tout << "got " << it->second << "\n" ;);
         return it->second;
+    }
+    TRACE("lar_solver_terms", tout << "have not found\n";);
     return -1;
 }
 } // namespace lp
diff --git a/src/math/lp/lar_term.h b/src/math/lp/lar_term.h
index 469e34f22..108325045 100644
--- a/src/math/lp/lar_term.h
+++ b/src/math/lp/lar_term.h
@@ -23,6 +23,7 @@
 namespace lp {
 class lar_term {
     // the term evaluates to sum of m_coeffs 
+    typedef unsigned lpvar;
     u_map<mpq> m_coeffs;
 public:
     lar_term() {}
@@ -149,8 +150,41 @@ public:
         bool operator!=(const self_type &other) const { return !(*this == other); }
     };
 
-    
-    const_iterator begin() const { return m_coeffs.begin();}
-    const_iterator end() const { return m_coeffs.end(); }
+    bool is_normalized() const {
+        lpvar min_var = -1;
+        mpq c;
+        for (const auto & p : *this) {
+            if (p.var() < min_var) {
+                min_var = p.var();
+            }
+        }
+        lar_term r;
+        for (const auto & p : *this) {
+            if (p.var() == min_var) {
+                return p.coeff().is_one();
+            }
+        }
+        lp_unreachable();
+        return false;        
+    }
+
+    // a is the coefficient by which we diveded the term to normalize it
+    lar_term get_normalized_by_min_var(mpq& a) const {
+        a = m_coeffs.begin()->second;
+        if (a.is_one()) {
+            return *this;
+        }
+        lar_term r;
+        auto it = m_coeffs.begin();
+        r.add_var(it->first);
+        it++;
+        for(;it != m_coeffs.end(); it++) {
+            r.add_coeff_var(it->second / a, it->first);
+        }
+        return r;        
+    }
+    const_iterator begin() const { return const_iterator(m_coeffs.begin());}
+    const_iterator end() const { return const_iterator(m_coeffs.end()); }
+
 };
 }
diff --git a/src/math/lp/lp_utils.h b/src/math/lp/lp_utils.h
index cef119168..9a8dc3fd3 100644
--- a/src/math/lp/lp_utils.h
+++ b/src/math/lp/lp_utils.h
@@ -102,9 +102,7 @@ std::ostream& print_linear_combination_customized(const vector<std::pair<T, unsi
                 val = -val;
             }
         }
-        if (val == 1)
-            out << " ";
-        else {
+        if (val != 1) {
             out << T_to_string(val);
         }
         out << var_str(it.second);
diff --git a/src/math/lp/nla_core.cpp b/src/math/lp/nla_core.cpp
index 9150e7aa2..cff739a99 100644
--- a/src/math/lp/nla_core.cpp
+++ b/src/math/lp/nla_core.cpp
@@ -955,7 +955,7 @@ void core::init_search() {
 }
 
 void core::init_to_refine() {
-    TRACE("nla_solver", tout << "emons:" << pp_emons(*this, m_emons););
+    TRACE("nla_solver_details", tout << "emons:" << pp_emons(*this, m_emons););
     m_to_refine.clear();
     m_to_refine.resize(m_lar_solver.number_of_vars());
     unsigned r = random(), sz = m_emons.number_of_monomials();
diff --git a/src/math/lp/nla_expr.h b/src/math/lp/nla_expr.h
index e48073af5..f1e00d266 100644
--- a/src/math/lp/nla_expr.h
+++ b/src/math/lp/nla_expr.h
@@ -376,17 +376,20 @@ public:
         return *this;
     }
 
-    bool sum_is_linear() const {
+    bool sum_is_a_linear_term() const {
         SASSERT(is_sum());
         int degree = 0;
+        unsigned number_of_non_scalars = 0;
         for (auto & e : children()) {
             int d = e.get_degree();
             if (d > 1)
                 return false;
             if (d > degree)
                 degree = d;
+            if (!e.is_scalar())
+                number_of_non_scalars++;
         }
-        return degree == 1;
+        return degree == 1 && number_of_non_scalars > 1;
     }
 
     int get_degree() const {