1 /*++
2 Copyright (c) 2017 Microsoft Corporation
3 
4 Author:
5 
6     Lev Nachmanson (levnach)
7 
8 --*/
9 
10 #pragma once
11 #include "util/vector.h"
12 #include <set>
13 #include <unordered_map>
14 #include <utility>
15 #include "math/lp/sparse_vector.h"
16 #include "math/lp/indexed_vector.h"
17 #include "math/lp/permutation_matrix.h"
18 #include <stack>
19 namespace lp {
20 
21 template <typename T>
22 class row_cell {
23     unsigned m_j;         // points to the column
24     unsigned m_offset;    // offset in column
25     T        m_coeff;     // coefficient
26 public:
row_cell(unsigned j,unsigned offset,T const & val)27     row_cell(unsigned j, unsigned offset, T const & val) : m_j(j), m_offset(offset), m_coeff(val) {
28     }
row_cell(unsigned j,unsigned offset)29     row_cell(unsigned j, unsigned offset) : m_j(j), m_offset(offset) {
30     }
coeff()31     inline const T & coeff() const { return m_coeff; }
coeff()32     inline T & coeff() { return m_coeff; }
var()33     inline unsigned var() const { return m_j; }
var()34     inline unsigned & var() { return m_j; }
offset()35     inline unsigned offset() const { return m_offset; }
offset()36     inline unsigned & offset() { return m_offset; }
37 };
38 
39 template <typename T>
40 std::ostream& operator<<(std::ostream& out, const row_cell<T>& rc) {
41     return out << "(j=" << rc.var() << ", offset= " << rc.offset() << ", coeff=" << rc.coeff() << ")";
42 }
43 struct empty_struct {};
44 typedef row_cell<empty_struct> column_cell;
45 typedef vector<column_cell> column_strip;
46 
47 template <typename T>
48 using row_strip = vector<row_cell<T>>;
49 template <typename T>
50 std::ostream& operator<<(std::ostream& out, const row_strip<T>& r) {
51     for (auto const& c : r)
52         out << c << " ";
53     return out << "\n";
54 }
55 
56 // each assignment for this matrix should be issued only once!!!
57 template <typename T, typename X>
58 class static_matrix
59 #ifdef Z3DEBUG
60     : public matrix<T, X>
61 #endif
62 {
63     struct dim {
64         unsigned m_m;
65         unsigned m_n;
dimdim66         dim(unsigned m, unsigned n) :m_m(m), m_n(n) {}
67     };
68     std::stack<dim> m_stack;
69 public:
70     vector<int> m_vector_of_row_offsets;
71     indexed_vector<T> m_work_vector;
72     vector<row_strip<T>> m_rows;
73     vector<column_strip> m_columns;
74     // starting inner classes
75     class ref {
76         static_matrix & m_matrix;
77         unsigned m_row;
78         unsigned m_col;
79     public:
ref(static_matrix & m,unsigned row,unsigned col)80         ref(static_matrix & m, unsigned row, unsigned col):m_matrix(m), m_row(row), m_col(col) {}
81         ref & operator=(T const & v) { m_matrix.set( m_row, m_col, v); return *this; }
82 
83         ref operator=(ref & v) { m_matrix.set(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; }
84 
T()85         operator T () const { return m_matrix.get_elem(m_row, m_col); }
86     };
87 
88     class ref_row {
89         const static_matrix & m_matrix;
90         unsigned        m_row;
91     public:
ref_row(const static_matrix & m,unsigned row)92         ref_row(const static_matrix & m, unsigned row): m_matrix(m), m_row(row) {}
93         T operator[](unsigned col) const { return m_matrix.get_elem(m_row, col); }
94     };
95 
96 public:
97 
get_val(const column_cell & c)98     const T & get_val(const column_cell & c) const {
99         return m_rows[c.var()][c.offset()].coeff();
100     }
101 
get_column_cell(const row_cell<T> & rc)102     column_cell & get_column_cell(const row_cell<T> &rc) {
103         return m_columns[rc.var()][rc.offset()];
104     }
105 
106     void init_row_columns(unsigned m, unsigned n);
107 
108         // constructor with no parameters
static_matrix()109     static_matrix() {}
110 
111     // constructor
static_matrix(unsigned m,unsigned n)112     static_matrix(unsigned m, unsigned n): m_vector_of_row_offsets(n, -1)  {
113         init_row_columns(m, n);
114     }
115     // constructor that copies columns of the basis from A
116     static_matrix(static_matrix const &A, unsigned * basis);
117 
118     void clear();
119 
120     void init_vector_of_row_offsets();
121 
122     void init_empty_matrix(unsigned m, unsigned n);
123 
row_count()124     unsigned row_count() const { return static_cast<unsigned>(m_rows.size()); }
125 
column_count()126     unsigned column_count() const { return static_cast<unsigned>(m_columns.size()); }
127 
128     unsigned lowest_row_in_column(unsigned col);
129 
130     void add_columns_at_the_end(unsigned delta);
131     void add_new_element(unsigned i, unsigned j, const T & v);
132 
add_row()133     void add_row() {m_rows.push_back(row_strip<T>());}
add_column()134     void add_column() {
135         m_columns.push_back(column_strip());
136         m_vector_of_row_offsets.push_back(-1);
137     }
138 
139     void forget_last_columns(unsigned how_many_to_forget);
140 
141     void remove_last_column(unsigned j);
142 
143     void remove_element(vector<row_cell<T>> & row, row_cell<T> & elem_to_remove);
144 
multiply_column(unsigned column,T const & alpha)145     void multiply_column(unsigned column, T const & alpha) {
146         for (auto & t : m_columns[column]) {
147             auto & r = m_rows[t.var()][t.offset()];
148             r.coeff() *= alpha;
149         }
150     }
151 
152 
153 #ifdef Z3DEBUG
154     void regen_domain();
155 #endif
156 
157     // offs - offset in columns
make_row_cell(unsigned row,unsigned offs,T const & val)158     row_cell<T> make_row_cell(unsigned row, unsigned offs, T const & val) {
159         return row_cell<T>(row, offs, val);
160     }
161 
make_column_cell(unsigned column,unsigned offset)162     column_cell make_column_cell(unsigned column, unsigned offset) {
163         return column_cell(column, offset);
164     }
165 
166     void set(unsigned row, unsigned col, T const & val);
167 
operator()168     ref operator()(unsigned row, unsigned col) { return ref(*this, row, col); }
169 
170     std::set<std::pair<unsigned, unsigned>>  get_domain();
171 
172     void copy_column_to_indexed_vector(unsigned j, indexed_vector<T> & v) const;
173 
174     T get_max_abs_in_row(unsigned row) const;
add_column_to_vector(const T & a,unsigned j,T * v)175     void add_column_to_vector (const T & a, unsigned j, T * v) const {
176         for (const auto & it : m_columns[j]) {
177             v[it.var()] += a * get_val(it);
178         }
179     }
180 
181     T get_min_abs_in_row(unsigned row) const;
182     T get_max_abs_in_column(unsigned column) const;
183 
184     T get_min_abs_in_column(unsigned column) const;
185 
186 #ifdef Z3DEBUG
187     void check_consistency();
188 #endif
189 
190 
191     void cross_out_row(unsigned k);
192 
193     //
194     void fix_row_indices_in_each_column_for_crossed_row(unsigned k);
195 
196     void cross_out_row_from_columns(unsigned k, row_strip<T> & row);
197 
198     void cross_out_row_from_column(unsigned col, unsigned k);
199 
200     T get_elem(unsigned i, unsigned j) const;
201 
202 
number_of_non_zeroes_in_column(unsigned j)203     unsigned number_of_non_zeroes_in_column(unsigned j) const { return m_columns[j].size(); }
204 
number_of_non_zeroes_in_row(unsigned i)205     unsigned number_of_non_zeroes_in_row(unsigned i) const { return m_rows[i].size(); }
206 
number_of_non_zeroes()207     unsigned number_of_non_zeroes() const {
208         unsigned ret = 0;
209         for (unsigned i = 0; i < row_count(); i++)
210             ret += number_of_non_zeroes_in_row(i);
211         return ret;
212     }
213 
214     void scan_row_to_work_vector(unsigned i);
215 
216     void clean_row_work_vector(unsigned i);
217 
218 
219 #ifdef Z3DEBUG
get_number_of_rows()220     unsigned get_number_of_rows() const { return row_count(); }
get_number_of_columns()221     unsigned get_number_of_columns() const { return column_count(); }
set_number_of_rows(unsigned)222     virtual void set_number_of_rows(unsigned /*m*/) { }
set_number_of_columns(unsigned)223     virtual void set_number_of_columns(unsigned /*n*/) { }
224 #endif
225 
get_max_val_in_row(unsigned)226     T get_max_val_in_row(unsigned /* i */) const { lp_unreachable();   }
227 
228     T get_balance() const;
229 
230     T get_row_balance(unsigned row) const;
231 
232     bool is_correct() const;
push()233     void push() {
234         dim d(row_count(), column_count());
235         m_stack.push(d);
236     }
237 
pop_row_columns(const vector<row_cell<T>> & row)238     void pop_row_columns(const vector<row_cell<T>> & row) {
239         for (auto & c : row) {
240             unsigned j = c.var();
241             auto & col = m_columns[j];
242             lp_assert(col[col.size() - 1].var() == m_rows.size() -1 ); // todo : start here!!!!
243             col.pop_back();
244         }
245     }
246 
247 
248 
pop(unsigned k)249     void pop(unsigned k) {
250 #ifdef Z3DEBUG
251         std::set<std::pair<unsigned, unsigned>> pairs_to_remove_from_domain;
252 #endif
253 
254 
255         while (k-- > 0) {
256             if (m_stack.empty()) break;
257             unsigned m = m_stack.top().m_m;
258             while (m < row_count()) {
259                 unsigned i = m_rows.size() -1 ;
260                 auto & row = m_rows[i];
261                 pop_row_columns(row);
262                 m_rows.pop_back(); // delete the last row
263             }
264             unsigned n = m_stack.top().m_n;
265             while (n < column_count())
266                 m_columns.pop_back(); // delete the last column
267             m_stack.pop();
268         }
269         lp_assert(is_correct());
270     }
271 
multiply_row(unsigned row,T const & alpha)272     void multiply_row(unsigned row, T const & alpha) {
273         for (auto & t : m_rows[row]) {
274             t.coeff() *= alpha;
275         }
276     }
277 
divide_row(unsigned row,T const & alpha)278     void divide_row(unsigned row, T const & alpha) {
279         for (auto & t : m_rows[row]) {
280             t.coeff() /= alpha;
281         }
282     }
283 
dot_product_with_column(const vector<T> & y,unsigned j)284     T dot_product_with_column(const vector<T> & y, unsigned j) const {
285         lp_assert(j < column_count());
286         T ret = numeric_traits<T>::zero();
287         for (auto & it : m_columns[j]) {
288             ret += y[it.var()] * get_val(it); // get_value_of_column_cell(it);
289         }
290         return ret;
291     }
292 
293     // pivot row i to row ii
294     bool pivot_row_to_row_given_cell(unsigned i, column_cell& c, unsigned);
295     void scan_row_ii_to_offset_vector(const row_strip<T> & rvals);
296 
transpose_rows(unsigned i,unsigned ii)297     void transpose_rows(unsigned i, unsigned ii) {
298         auto t = m_rows[i];
299         m_rows[i] = m_rows[ii];
300         m_rows[ii] = t;
301         // now fix the columns
302         for (auto & rc : m_rows[i]) {
303             column_cell & cc = m_columns[rc.var()][rc.offset()];
304             lp_assert(cc.var() == ii);
305             cc.var() = i;
306         }
307         for (auto & rc : m_rows[ii]) {
308             column_cell & cc = m_columns[rc.var()][rc.offset()];
309             lp_assert(cc.var() == i);
310             cc.var() = ii;
311         }
312 
313     }
fill_last_row_with_pivoting_loop_block(unsigned j,const vector<int> & basis_heading)314     void fill_last_row_with_pivoting_loop_block(unsigned j, const vector<int> & basis_heading) {
315         int row_index = basis_heading[j];
316         if (row_index < 0)
317             return;
318         T & alpha = m_work_vector[j]; // the pivot alpha
319         if (is_zero(alpha))
320             return;
321 
322         for (const auto & c : m_rows[row_index]) {
323             if (c.var() == j) {
324                 continue;
325             }
326             T & wv = m_work_vector.m_data[c.var()];
327             bool was_zero = is_zero(wv);
328             wv -= alpha * c.coeff();
329             if (was_zero)
330                 m_work_vector.m_index.push_back(c.var());
331             else {
332                 if (is_zero(wv)) {
333                     m_work_vector.erase_from_index(c.var());
334                 }
335             }
336         }
337         alpha = zero_of_type<T>();
338         m_work_vector.erase_from_index(j);
339     }
340 
341 
342 
343     template <typename term>
fill_last_row_with_pivoting(const term & row,unsigned bj,const vector<int> & basis_heading)344     void fill_last_row_with_pivoting(const term& row,
345                                      unsigned bj, // the index of the basis column
346                                      const vector<int> & basis_heading) {
347         lp_assert(numeric_traits<T>::precise());
348         lp_assert(row_count() > 0);
349         m_work_vector.resize(column_count());
350         T a;
351          // we use the form -it + 1 = 0
352         m_work_vector.set_value(one_of_type<T>(), bj);
353         for (auto p : row) {
354             m_work_vector.set_value(-p.coeff(), p.column().index());
355             // but take care of the basis 1 later
356         }
357 
358         // now iterate with pivoting
359         fill_last_row_with_pivoting_loop_block(bj, basis_heading);
360         for (auto p : row) {
361             fill_last_row_with_pivoting_loop_block(p.column().index(), basis_heading);
362         }
363         lp_assert(m_work_vector.is_OK());
364         unsigned last_row = row_count() - 1;
365 
366         for (unsigned j : m_work_vector.m_index) {
367             set (last_row, j, m_work_vector.m_data[j]);
368         }
369         lp_assert(column_count() > 0);
370         set(last_row, column_count() - 1, one_of_type<T>());
371     }
372 
copy_column_to_vector(unsigned j,vector<T> & v)373     void copy_column_to_vector (unsigned j, vector<T> & v) const {
374         v.resize(row_count(), numeric_traits<T>::zero());
375         for (auto & it : m_columns[j]) {
376             const T& val = get_val(it);
377             if (!is_zero(val))
378                 v[it.var()] = val;
379         }
380     }
381 
382     template <typename L>
dot_product_with_row(unsigned row,const vector<L> & w)383     L dot_product_with_row(unsigned row, const vector<L> & w) const {
384         L ret = zero_of_type<L>();
385         lp_assert(row < m_rows.size());
386         for (auto & it : m_rows[row]) {
387             ret += w[it.var()] * it.coeff();
388         }
389         return ret;
390     }
391 
392     struct column_cell_plus {
393         const column_cell & m_c;
394         const static_matrix& m_A;
395         // constructor
column_cell_pluscolumn_cell_plus396         column_cell_plus(const column_cell & c, const static_matrix& A) :
397             m_c(c), m_A(A) {}
varcolumn_cell_plus398         unsigned var() const { return m_c.var(); }
coeffcolumn_cell_plus399         const T & coeff() const { return m_A.m_rows[var()][m_c.offset()].coeff(); }
400 
401     };
402 
403     struct column_container {
404         unsigned              m_j; // the column index
405         const static_matrix & m_A;
column_containercolumn_container406         column_container(unsigned j, const static_matrix& A) : m_j(j), m_A(A) {
407         }
408         struct const_iterator {
409             // fields
410             const column_cell *m_c;
411             const static_matrix& m_A;
412 
413             //typedefs
414 
415 
416             typedef const_iterator self_type;
417             typedef column_cell_plus value_type;
418             typedef const column_cell_plus reference;
419             //            typedef const column_cell* pointer;
420             typedef int difference_type;
421             typedef std::forward_iterator_tag iterator_category;
422 
423             reference operator*() const {
424                 return column_cell_plus(*m_c, m_A);
425             }
426             self_type operator++() {  self_type i = *this; m_c++; return i;  }
427             self_type operator++(int) { m_c++; return *this; }
428 
const_iteratorcolumn_container::const_iterator429             const_iterator(const column_cell* it, const static_matrix& A) :
430                 m_c(it),
431                 m_A(A)
432             {}
433             bool operator==(const self_type &other) const {
434                 return m_c == other.m_c;
435             }
436             bool operator!=(const self_type &other) const { return !(*this == other); }
437         };
438 
begincolumn_container439         const_iterator begin() const {
440             return const_iterator(m_A.m_columns[m_j].begin(), m_A);
441         }
442 
endcolumn_container443         const_iterator end() const {
444             return const_iterator(m_A.m_columns[m_j].end(), m_A);
445         }
446     };
447 
column(unsigned j)448     column_container column(unsigned j) const {
449         return column_container(j, *this);
450     }
451 
452     ref_row operator[](unsigned i) const { return ref_row(*this, i);}
453     typedef T coefftype;
454     typedef X argtype;
455 };
456 
457 }
458