From 080dbb13b0adaf9620273f1e29ad7892c79f7b25 Mon Sep 17 00:00:00 2001
From: Nikolaj Bjorner <nbjorner@microsoft.com>
Date: Sun, 5 Apr 2020 03:35:19 -0700
Subject: [PATCH] tv alignment, code review comments

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
---
 src/math/lp/gomory.cpp     |  3 +++
 src/math/lp/hnf_cutter.cpp |  8 ++++----
 src/math/lp/hnf_cutter.h   |  2 +-
 src/math/lp/int_branch.cpp |  2 +-
 src/math/lp/int_cube.cpp   |  2 +-
 src/math/lp/lar_solver.cpp | 22 +++++++++++-----------
 src/math/lp/lar_solver.h   | 17 +++++++++++------
 7 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/src/math/lp/gomory.cpp b/src/math/lp/gomory.cpp
index 37b201497..62bd4ba7e 100644
--- a/src/math/lp/gomory.cpp
+++ b/src/math/lp/gomory.cpp
@@ -346,6 +346,9 @@ public:
             adjust_term_and_k_for_some_ints_case_gomory();
         TRACE("gomory_cut_detail", dump_cut_and_constraints_as_smt_lemma(tout););
         lp_assert(lia.current_solution_is_inf_on_cut());
+        // NSB code review: this is also used in nla_core.
+        // but it isn't consistent: when theory_lra accesses lar_solver::get_term, the term that is returned uses
+        // column indices, not terms.
         lia.lra.subs_term_columns(m_t);
         TRACE("gomory_cut", print_linear_combination_of_column_indices_only(m_t.coeffs_as_vector(), tout << "gomory cut:"); tout << " <= " << m_k << std::endl;);
         return lia_move::cut;
diff --git a/src/math/lp/hnf_cutter.cpp b/src/math/lp/hnf_cutter.cpp
index 7c8dd42d7..cbc5eb4f8 100644
--- a/src/math/lp/hnf_cutter.cpp
+++ b/src/math/lp/hnf_cutter.cpp
@@ -201,13 +201,13 @@ namespace lp  {
 
     svector<unsigned> hnf_cutter::vars() const { return m_var_register.vars(); }
 
-    void hnf_cutter::try_add_term_to_A_for_hnf(unsigned i) {
+    void hnf_cutter::try_add_term_to_A_for_hnf(tv const &i) {
         mpq rs;
-        const lar_term* t = lra.terms()[i];
+        const lar_term& t = lra.get_term(i);
         constraint_index ci;
         bool upper_bound;
         if (!is_full() && lra.get_equality_and_right_side_for_term_on_current_x(i, rs, ci, upper_bound)) {
-            add_term(t, rs, ci, upper_bound);
+            add_term(&t, rs, ci, upper_bound);
         }
     }
 
@@ -221,7 +221,7 @@ namespace lp  {
     bool hnf_cutter::init_terms_for_hnf_cut() {
         clear();
         for (unsigned i = 0; i < lra.terms().size() && !is_full(); i++) {
-            try_add_term_to_A_for_hnf(i);
+            try_add_term_to_A_for_hnf(tv::term(i));
         }
         return hnf_has_var_with_non_integral_value();
     }
diff --git a/src/math/lp/hnf_cutter.h b/src/math/lp/hnf_cutter.h
index 027f2c7b1..dd0f7b093 100644
--- a/src/math/lp/hnf_cutter.h
+++ b/src/math/lp/hnf_cutter.h
@@ -49,7 +49,7 @@ public:
 private:
     bool init_terms_for_hnf_cut();
     bool hnf_has_var_with_non_integral_value() const;
-    void try_add_term_to_A_for_hnf(unsigned i);
+    void try_add_term_to_A_for_hnf(tv const& i);
 
     unsigned terms_count() const { return m_terms.size();  }
     const mpq & abs_max() const { return m_abs_max; }
diff --git a/src/math/lp/int_branch.cpp b/src/math/lp/int_branch.cpp
index d840888e5..c9ab221eb 100644
--- a/src/math/lp/int_branch.cpp
+++ b/src/math/lp/int_branch.cpp
@@ -10,8 +10,8 @@ Abstract:
     Branch heuristic
 
 Author:
-    Nikolaj Bjorner (nbjorner)
     Lev Nachmanson (levnach)
+    Nikolaj Bjorner (nbjorner)
 
 Revision History:
 --*/
diff --git a/src/math/lp/int_cube.cpp b/src/math/lp/int_cube.cpp
index 1f918bc7c..24609ec25 100644
--- a/src/math/lp/int_cube.cpp
+++ b/src/math/lp/int_cube.cpp
@@ -64,7 +64,7 @@ namespace lp {
         TRACE("cube", lra.print_term_as_indices(*t, tout); tout << ", delta = " << delta;);
         if (is_zero(delta))
             return true;
-        return lra.tighten_term_bounds_by_delta(i, delta);
+        return lra.tighten_term_bounds_by_delta(tv::term(i), delta);
     }
     
     bool int_cube::tighten_terms_for_cube() {
diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp
index f7a1c1a19..99c79f5e3 100644
--- a/src/math/lp/lar_solver.cpp
+++ b/src/math/lp/lar_solver.cpp
@@ -113,7 +113,7 @@ bool lar_solver::implied_bound_is_correctly_explained(implied_bound const & be,
         }
         rs_of_evidence /= ratio;
     } else {
-        lar_term & t = *m_terms[tv::unmask_term(be.m_j)];
+        lar_term const& t = get_term(be.m_j);
         auto first_coeff = t.begin();
         unsigned j = (*first_coeff).var().index();
         auto it = coeff_map.find(j);
@@ -182,7 +182,7 @@ void lar_solver::substitute_basis_var_in_terms_for_row(unsigned i) {
 }
     
 void lar_solver::calculate_implied_bounds_for_row(unsigned i, lp_bound_propagator & bp) {
-    if(use_tableau()) {
+    if (use_tableau()) {
         analyze_new_bounds_on_row_tableau(i, bp);
     } else {
         m_mpq_lar_core_solver.calculate_pivot_row(i);
@@ -2192,9 +2192,9 @@ var_index lar_solver::to_column(unsigned ext_j) const {
     return m_var_register.external_to_local(ext_j);
 }
 
-bool lar_solver::tighten_term_bounds_by_delta(unsigned term_index, const impq& delta) {
-    SASSERT(!tv::is_term(term_index));
-    unsigned tj = tv::mask_term(term_index);
+bool lar_solver::tighten_term_bounds_by_delta(tv const& t, const impq& delta) {
+    SASSERT(t.is_term());
+    unsigned tj = t.index();
     unsigned j;
     if (m_var_register.external_is_used(tj, j) == false)
         return true; // the term is not a column so it has no bounds
@@ -2282,21 +2282,21 @@ bool lar_solver::sum_first_coords(const lar_term& t, mpq & val) const {
     return true;
 }
 
-bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term_index, mpq & rs, constraint_index& ci, bool &upper_bound) const {
-    unsigned tj = tv::mask_term(term_index);
+bool lar_solver::get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq & rs, constraint_index& ci, bool &upper_bound) const {
+    lp_assert(t.is_term())
     unsigned j;
     bool is_int;
-    if (m_var_register.external_is_used(tj, j, is_int) == false)
+    if (m_var_register.external_is_used(t.index(), j, is_int) == false)
         return false; // the term does not have a bound because it does not correspond to a column
     if (!is_int) // todo - allow for the next version of hnf
         return false;
     bool rs_is_calculated = false;
     mpq b;
     bool is_strict;
-    const lar_term& t = *terms()[term_index];
+    const lar_term& term = get_term(t);
     if (has_upper_bound(j, ci, b, is_strict) && !is_strict) {
         lp_assert(b.is_int());
-        if (!sum_first_coords(t, rs))
+        if (!sum_first_coords(term, rs))
             return false;
         rs_is_calculated = true;
         if (rs == b) {
@@ -2306,7 +2306,7 @@ bool lar_solver::get_equality_and_right_side_for_term_on_current_x(unsigned term
     }
     if (has_lower_bound(j, ci, b, is_strict) && !is_strict) {
         if (!rs_is_calculated){
-            if (!sum_first_coords(t, rs))
+            if (!sum_first_coords(term, rs))
                 return false;
         }
         lp_assert(b.is_int());
diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h
index f4270eddd..e28737a7a 100644
--- a/src/math/lp/lar_solver.h
+++ b/src/math/lp/lar_solver.h
@@ -583,6 +583,11 @@ public:
         return m_columns_to_ul_pairs()[j].lower_bound_witness();
     }
 
+    // NSB code review - seems superfluous to translate back and forth because
+    // get_term(..) that is exposed over API does not ensure that columns that
+    // are based on terms are translated back to term indices.
+    // would be better to have consistent typing, either lar_term uses cv (and not tv)
+    // or they are created to use tv consistently.
     void subs_term_columns(lar_term& t) {
         svector<std::pair<unsigned,unsigned>> columns_to_subs;
         for (const auto & m : t) {
@@ -594,15 +599,15 @@ public:
             t.subst_index(p.first, p.second);            
         }
     }
+
     
     std::ostream& print_column_info(unsigned j, std::ostream& out) const {
         m_mpq_lar_core_solver.m_r_solver.print_column_info(j, out);
         if (tv::is_term(j)) {
-            const lar_term& t = * m_terms[tv::unmask_term(j)];
-            print_term_as_indices(t, out) << "\n";
+            print_term_as_indices(get_term(j), out) << "\n";
             
-        } else if(column_corresponds_to_term(j)) { 
-            const lar_term& t = * m_terms[tv::unmask_term(m_var_register.local_to_external(j))];
+        } else if (column_corresponds_to_term(j)) { 
+            const lar_term& t = get_term(m_var_register.local_to_external(j));
             print_term_as_indices(t, out) << "\n";
         }
         return out;
@@ -630,7 +635,7 @@ public:
     bool column_corresponds_to_term(unsigned) const;
     void catch_up_in_updating_int_solver();
     var_index to_column(unsigned ext_j) const;
-    bool tighten_term_bounds_by_delta(unsigned, const impq&);
+    bool tighten_term_bounds_by_delta(tv const& t, const impq&);
     void round_to_integer_solution();
     void fix_terms_with_rounded_columns();
     void update_delta_for_terms(const impq & delta, unsigned j, const vector<unsigned>&);
@@ -639,7 +644,7 @@ public:
     unsigned row_count() const { return A_r().row_count(); }
     const vector<unsigned> & r_basis() const { return m_mpq_lar_core_solver.r_basis(); }
     const vector<unsigned> & r_nbasis() const { return m_mpq_lar_core_solver.r_nbasis(); }
-    bool get_equality_and_right_side_for_term_on_current_x(unsigned i, mpq &rs, constraint_index& ci, bool &upper_bound) const;
+    bool get_equality_and_right_side_for_term_on_current_x(tv const& t, mpq &rs, constraint_index& ci, bool &upper_bound) const;
     bool remove_from_basis(unsigned);
     lar_term get_term_to_maximize(unsigned ext_j) const;
     void set_cut_strategy(unsigned cut_frequency);