1 /*
2  * This file is part of the Yices SMT Solver.
3  * Copyright (C) 2017 SRI International.
4  *
5  * Yices is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Yices is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Yices.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /*
20  * MATRIX REPRESENTATION FOR LINEAR ARITHMETIC SOLVER
21  */
22 
23 /*
24  * A matrix is represented as an array of rows
25  * - row i is a sparse representation of (a_i1, ..., a_in)
26  *   (where only the non-zero elements are stored)
27  * - for each column j, we keep track of all the rows where
28  *   a_ij is non-zero in a column vector
29  *
30  * Equivalently, each row can be seen as a linear equation
31  *   a_i1 x_1 + ... + a_in x_n == 0
32  * where x_1, ... , x_n are n variables corresponding to the columns.
33  *
34  * Each row is an array of triples (col_idx, c_ptr, a)
35  * - if col_idx < 0, the triple is not used. A list of free elements
36  *   is maintained, links are stored in the c_ptr field.
37  * - if col_idx >= 0, then it's the index k of a variable x_k
38  *   the triple represents a * x_k and and c_ptr is an index in the array
39  *   column[k]
40  *
41  * Each column is an array of pairs (row_idx, r_ptr)
42  * - if row_idx < 0, the pair is not used. It's stored in a free list
43  *   with links stored in r_ptr
44  * - if row_idx >= 0, then it's the index of a row i and r_ptr is
45  *   an index in the array row[i]
46  *
47  * For a non-zero element a_ij in row i, column j, there are two
48  * indices i_ptr and j_ptr such that
49  * - row[i][i_ptr] = (j, j_ptr, a_ij)
50  * - col[j][j_ptr] = (i, i_ptr)
51  */
52 
53 #include <assert.h>
54 #include <stdbool.h>
55 
56 #include "solvers/simplex/matrices.h"
57 #include "utils/memalloc.h"
58 
59 
60 
61 
62 /**************************
63  *  MATRIX CONSTRUCTION   *
64  *************************/
65 
66 /*
67  * COLUMN VECTORS
68  */
69 
70 /*
71  * Allocate and initialize a column vector of capacity n
72  */
new_column(uint32_t n)73 static column_t *new_column(uint32_t n) {
74   column_t *v;
75 
76   if (n >= MAX_MATRIX_COL_SIZE) {
77     out_of_memory();
78   }
79   v = (column_t *) safe_malloc(sizeof(column_t) + n * sizeof(col_elem_t));
80   v->capacity = n;
81   v->size = 0;
82   v->nelems = 0;
83   v->free = -1;
84 
85   return v;
86 }
87 
88 
89 /*
90  * Return a column equal to v but 50% larger
91  */
extend_column(column_t * v)92 static column_t *extend_column(column_t *v) {
93   uint32_t n;
94 
95   n = v->capacity + 1;
96   n += n>>1;
97   if (n >= MAX_MATRIX_COL_SIZE) {
98     out_of_memory();
99   }
100   v = (column_t *) safe_realloc(v, sizeof(column_t) + n * sizeof(col_elem_t));
101   v->capacity = n;
102 
103   return v;
104 }
105 
106 
107 /*
108  * Allocate an element in vector *v
109  * - if *v is null, allocate a fresh vector of default size
110  * - if *v is full, reallocate a larger vector
111  * If any allocation or reallocation happens, *v is updated.
112  * - return the index of the element in v->data
113  */
alloc_column_elem(column_t ** v)114 static uint32_t alloc_column_elem(column_t **v) {
115   column_t *c;
116   int32_t i;
117 
118   c = *v;
119   if (c == NULL) {
120     c = new_column(DEF_MATRIX_COL_SIZE);
121     c->size = 1;
122     *v = c;
123     i = 0;
124   } else {
125     // try the free list
126     i = c->free;
127     if (i >= 0) {
128       c->free = c->data[i].r_ptr;
129     } else {
130       i = c->size;
131       if (i == c->capacity) {
132         c = extend_column(c);
133         *v = c;
134       }
135       assert(i < c->capacity);
136       c->size ++;
137     }
138   }
139   c->nelems ++;
140   return i;
141 }
142 
143 
144 /*
145  * Check whether column element i is valid (not in the free list)
146  */
147 #ifndef NDEBUG
good_column_elem(column_t * v,int32_t i)148 static inline bool good_column_elem(column_t *v, int32_t i) {
149   assert(0 <= i && i < v->size);
150   return v->data[i].r_idx >= 0;
151 }
152 #endif
153 
154 /*
155  * Free element of index i in column v
156  */
free_column_elem(column_t * v,int32_t i)157 static void free_column_elem(column_t *v, int32_t i) {
158   assert(good_column_elem(v, i));
159   v->data[i].r_idx = -1; // mark it as dead
160   v->data[i].r_ptr = v->free;
161   v->free = i;
162   v->nelems --;
163 }
164 
165 
166 /*
167  * Delete column v
168  */
delete_column(column_t * v)169 static inline void delete_column(column_t *v) {
170   safe_free(v);
171 }
172 
173 
174 
175 
176 
177 /*
178  * ROW VECTORS
179  */
180 
181 /*
182  * Allocate and initialize a row of capacity n
183  */
new_row(uint32_t n)184 static row_t *new_row(uint32_t n) {
185   row_t *v;
186 
187   if (n >= MAX_MATRIX_ROW_SIZE) {
188     out_of_memory();
189   }
190   v = (row_t *) safe_malloc(sizeof(row_t) + n * sizeof(row_elem_t));
191   v->capacity = n;
192   v->size = 0;
193   v->nelems = 0;
194   v->free = -1;
195 
196   return v;
197 }
198 
199 
200 
201 /*
202  * Return a column equal to v but 50% larger
203  */
extend_row(row_t * v)204 static row_t *extend_row(row_t *v) {
205   uint32_t n;
206 
207   n = v->capacity + 1;
208   n += n>>1;
209   if (n >= MAX_MATRIX_ROW_SIZE) {
210     out_of_memory();
211   }
212   v = (row_t *) safe_realloc(v, sizeof(row_t) + n * sizeof(row_elem_t));
213   v->capacity = n;
214 
215   return v;
216 }
217 
218 
219 /*
220  * Allocate a row element in vector *v
221  * - if *v is null, allocate a fresh vector of default size
222  * - if *v is full, reallocate a larger vector
223  * If any allocation or reallocation happens, *v is updated.
224  * - return the index of the element in v->data
225  * - initialize v->data[i].coeff if required
226  */
alloc_row_elem(row_t ** v)227 static uint32_t alloc_row_elem(row_t **v) {
228   row_t *r;
229   int32_t i;
230 
231   r = *v;
232   if (r == NULL) {
233     r = new_row(DEF_MATRIX_ROW_SIZE);
234     *v = r;
235     i = 0;
236   } else {
237     // try the free list
238     i = r->free;
239     if (i >= 0) {
240       r->free = r->data[i].c_ptr;
241     } else {
242       i = r->size;
243       if (i == r->capacity) {
244         r = extend_row(r);
245         *v = r;
246       }
247       assert(i < r->capacity);
248       // initialize the rational coefficient
249       q_init(&r->data[i].coeff);
250       r->size ++;
251     }
252   }
253   r->nelems ++;
254   return i;
255 }
256 
257 
258 /*
259  * Check whether row element i is valid (not in the free list)
260  */
261 #ifndef NDEBUG
good_row_elem(row_t * v,int32_t i)262 static inline bool good_row_elem(row_t *v, int32_t i) {
263   assert(0 <= i && i < v->size);
264   return v->data[i].c_idx >= 0;
265 }
266 #endif
267 
268 /*
269  * Free element of index i in row v
270  */
free_row_elem(row_t * v,int32_t i)271 static void free_row_elem(row_t *v, int32_t i) {
272   assert(good_row_elem(v, i));
273   v->data[i].c_idx = -1; // mark it as dead
274   v->data[i].c_ptr = v->free;
275   v->free = i;
276   v->nelems --;
277 }
278 
279 
280 /*
281  * Delete row v
282  */
delete_row(row_t * v)283 static void delete_row(row_t *v) {
284   uint32_t i, n;
285   n = v->size;
286   for (i=0; i<n; i++) {
287     q_clear(&v->data[i].coeff);
288   }
289   safe_free(v);
290 }
291 
292 
293 
294 
295 
296 
297 
298 /*
299  * MATRIX
300  */
301 
302 /*
303  * Initialize matrix:
304  * - n = initial row capacity, m = initial column capacity
305  * - if n == 0 then the default row capacity is used
306  * - if m == 0 then the default column capacity is used
307  */
init_matrix(matrix_t * matrix,uint32_t n,uint32_t m)308 void init_matrix(matrix_t *matrix, uint32_t n, uint32_t m) {
309   if (n == 0) n = DEF_MATRIX_NUM_ROWS;
310   if (m == 0) m = DEF_MATRIX_NUM_COLUMNS;
311 
312   if (n >= MAX_MATRIX_NUM_ROWS || m >= MAX_MATRIX_NUM_COLUMNS) {
313     out_of_memory();
314   }
315 
316   matrix->nrows = 0;
317   matrix->ncolumns = 0;
318   matrix->row_cap = n;
319   matrix->column_cap = m;
320   matrix->row = (row_t **) safe_malloc(n * sizeof(row_t *));
321   matrix->base_var = (int32_t *) safe_malloc(n * sizeof(int32_t));
322 
323   matrix->column = (column_t **) safe_malloc(m * sizeof(column_t *));
324   matrix->base_row = (int32_t *) safe_malloc(m * sizeof(int32_t));
325   matrix->index = (int32_t *) safe_malloc(m * sizeof(int32_t));
326 
327   q_init(&matrix->factor);
328 
329   // marks: one bit per row
330   matrix->marks = allocate_bitvector(n);
331 
332   // constant is not allocated here
333   matrix->constant = NULL;
334 }
335 
336 
337 /*
338  * Delete matrix: free all memory it uses
339  */
delete_matrix(matrix_t * matrix)340 void delete_matrix(matrix_t *matrix) {
341   uint32_t i, n;
342 
343   n = matrix->nrows;
344   for (i=0; i<n; i++) {
345     delete_row(matrix->row[i]);
346   }
347 
348   n = matrix->ncolumns;
349   for (i=0; i<n; i++) {
350     delete_column(matrix->column[i]);
351   }
352 
353   safe_free(matrix->row);
354   safe_free(matrix->column);
355   safe_free(matrix->index);
356   safe_free(matrix->constant);
357   safe_free(matrix->base_var);
358   safe_free(matrix->base_row);
359   delete_bitvector(matrix->marks);
360 
361   q_clear(&matrix->factor);
362 
363   matrix->row = NULL;
364   matrix->column = NULL;
365   matrix->index = NULL;
366   matrix->constant = NULL;
367   matrix->base_var = NULL;
368   matrix->base_row = NULL;
369   matrix->marks = NULL;
370 }
371 
372 
373 /*
374  * Reset matrix to the empty matrix
375  * - delete all rows and columns
376  */
reset_matrix(matrix_t * matrix)377 void reset_matrix(matrix_t *matrix) {
378   uint32_t i, n;
379 
380   n = matrix->nrows;
381   for (i=0; i<n; i++) {
382     delete_row(matrix->row[i]);
383     matrix->row[i] = NULL;  // this is redundant but it helps debugging
384   }
385 
386   n = matrix->ncolumns;
387   for (i=0; i<n; i++) {
388     delete_column(matrix->column[i]);
389     matrix->column[i] = NULL;
390   }
391 
392   q_clear(&matrix->factor);
393 
394   matrix->nrows = 0;
395   matrix->ncolumns = 0;
396 }
397 
398 
399 
400 
401 
402 
403 /*
404  * UTILITIES
405  */
406 
407 /*
408  * Get the index of a new column element for column j
409  */
get_column_elem(matrix_t * matrix,uint32_t j)410 static inline uint32_t get_column_elem(matrix_t *matrix, uint32_t j) {
411   assert(j < matrix->ncolumns);
412   return alloc_column_elem(matrix->column + j);
413 }
414 
415 /*
416  * Pointer to column element k in column j
417  */
column_elem(matrix_t * matrix,uint32_t j,uint32_t k)418 static inline col_elem_t *column_elem(matrix_t *matrix, uint32_t j, uint32_t k) {
419   assert(j < matrix->ncolumns && matrix->column[j] != NULL && k < matrix->column[j]->size);
420   return matrix->column[j]->data + k;
421 }
422 
423 
424 /*
425 #if 0
426 // NOT USED
427 #endif
428 
429  * Pointer to column element k in row i
430  */
row_elem(matrix_t * matrix,uint32_t i,uint32_t k)431 static inline row_elem_t *row_elem(matrix_t *matrix, uint32_t i, uint32_t k) {
432   assert(i < matrix->nrows &&  matrix->row[i] != NULL && k < matrix->row[i]->size);
433   return matrix->row[i]->data + k;
434 }
435 
436 
437 
438 /*
439  * Add a column element in column j, and set it to <r_idx, r_ptr>
440  * - return the index of the element in column j
441  */
add_column_elem(matrix_t * matrix,uint32_t j,uint32_t r_idx,uint32_t r_ptr)442 static uint32_t add_column_elem(matrix_t *matrix, uint32_t j, uint32_t r_idx, uint32_t r_ptr) {
443   uint32_t k;
444   col_elem_t *e;
445 
446   k = get_column_elem(matrix, j);
447   e = column_elem(matrix, j, k);
448   e->r_idx = r_idx;
449   e->r_ptr = r_ptr;
450 
451   return k;
452 }
453 
454 
455 #if 0
456 // Not used
457 /*
458  * Add a row element in row i, and set it to <c_idx, c_ptr, coeff>
459  * - return the element index in row i
460  */
461 static uint32_t add_row_elem(matrix_t *matrix, uint32_t i, uint32_t c_idx, uint32_t c_ptr,
462                              rational_t *coeff) {
463   uint32_t k;
464   row_elem_t *e;
465 
466   k = get_row_elem(matrix, i);
467   e = row_elem(matrix, i, k);
468   e->c_idx = c_idx;
469   e->c_ptr = c_ptr;
470   q_set(&e->coeff, coeff);
471 
472   return k;
473 }
474 
475 #endif
476 
477 /*
478  * Remove element k in row i (when its coefficient is zero)
479  * and update the corresponding column vector
480  */
remove_row_elem(matrix_t * matrix,uint32_t i,uint32_t k)481 static void remove_row_elem(matrix_t *matrix, uint32_t i, uint32_t k) {
482   row_elem_t *e;
483 
484   e = row_elem(matrix, i, k);
485   free_column_elem(matrix->column[e->c_idx], e->c_ptr);
486   free_row_elem(matrix->row[i], k);
487 }
488 
489 
490 #if 0
491 // Not used
492 /*
493  * Create a new a[i, j] for row i and column j with value = a
494  * - this adds a new element in row i and in column j, so there
495  *   mustn't be one already
496  * - return the row index of the new element
497  */
498 static uint32_t add_matrix_elem(matrix_t *matrix, uint32_t i, uint32_t j, rational_t *a) {
499   uint32_t c_ptr, r_ptr;
500   col_elem_t *ce;
501   row_elem_t *re;
502 
503   c_ptr = get_column_elem(matrix, j);
504   r_ptr = get_row_elem(matrix, i);
505   ce = column_elem(matrix, j, c_ptr);
506   ce->r_idx = i;
507   ce->r_ptr = r_ptr;
508   re = row_elem(matrix, i, r_ptr);
509   re->c_idx = j;
510   re->c_ptr = c_ptr;
511   q_set(&re->coeff, a);
512 
513   return r_ptr;
514 }
515 
516 #endif
517 
518 
519 /*
520  * Convert row to a polynomial
521  * - WARNING: the result is not normalized (variables are not in increasing order)
522  */
convert_row_to_poly(row_t * row)523 static polynomial_t *convert_row_to_poly(row_t *row) {
524   uint32_t i, j, n;
525   int32_t x;
526   polynomial_t *p;
527 
528   n = row->nelems;
529   p = (polynomial_t *) safe_malloc(sizeof(polynomial_t) + (n+1) * sizeof(monomial_t));
530   p->nterms = n;
531 
532   n = row->size;
533   j = 0;
534   for (i=0; i<n; i++) {
535     x = row->data[i].c_idx;
536     if (x >= 0) {
537       p->mono[j].var = x;
538       q_init(&p->mono[j].coeff);
539       q_set(&p->mono[j].coeff, &row->data[i].coeff);
540       j ++;
541     }
542   }
543   // add the end marker to p
544   assert(j == row->nelems);
545   p->mono[j].var = max_idx;
546   q_init(&p->mono[j].coeff);
547 
548   return p;
549 }
550 
551 
552 
553 /*
554  * COLUMN ADDITION
555  */
556 
557 /*
558  * Increase the column capacity by 50% or to m,
559  * depending on which is larger
560  * - so after this, there's room for at least m columns
561  */
matrix_increase_column_capacity(matrix_t * matrix,uint32_t m)562 static void matrix_increase_column_capacity(matrix_t *matrix, uint32_t m) {
563   uint32_t n;
564 
565   n = matrix->column_cap + 1;
566   n += n>>1;
567   if (n < m) {
568     n = m;
569   }
570   if (n >= MAX_MATRIX_NUM_COLUMNS) {
571     out_of_memory();
572   }
573   matrix->column_cap = n;
574   matrix->column = (column_t **) safe_realloc(matrix->column, n * sizeof(column_t *));
575   matrix->base_row = (int32_t *) safe_realloc(matrix->base_row, n * sizeof(int32_t));
576   matrix->index = (int32_t *) safe_realloc(matrix->index, n * sizeof(int32_t));
577 }
578 
579 
580 
581 /*
582  * Add a single column to the matrix
583  * - the new column is empty (NULL)
584  * - we also want to maintain the invariant that index[i] == -1 for
585  *   every column i
586  */
matrix_add_column(matrix_t * matrix)587 void matrix_add_column(matrix_t *matrix) {
588   uint32_t i;
589 
590   i = matrix->ncolumns;
591   if (i == matrix->column_cap) {
592     // increase capacity by 50%
593     matrix_increase_column_capacity(matrix, 0);
594   }
595   assert(i < matrix->column_cap);
596 
597   matrix->column[i] = NULL;
598   matrix->base_row[i] = -1;
599   matrix->index[i] = -1;
600   matrix->ncolumns = i + 1;
601 }
602 
603 
604 
605 /*
606  * Add m new columns to the matrix
607  * - all are initialized to NULL and their index[i] is set to -1
608  */
matrix_add_columns(matrix_t * matrix,uint32_t m)609 void matrix_add_columns(matrix_t *matrix, uint32_t m) {
610   uint32_t i, n;
611 
612   n = matrix->ncolumns + m;
613   if (n >= matrix->column_cap) {
614     matrix_increase_column_capacity(matrix, n);
615   }
616   assert(n <= matrix->column_cap);
617 
618   for (i=matrix->ncolumns; i<n; i++) {
619     matrix->column[i] = NULL;
620     matrix->base_row[i] = -1;
621     matrix->index[i] = -1;
622   }
623   matrix->ncolumns = n;
624 }
625 
626 
627 
628 #if 0
629 // not used
630 
631 /*
632  * Remove the empty elements from column c
633  * - update the corresponding row elements
634  */
635 static void matrix_compact_column(matrix_t *matrix, uint32_t c) {
636   column_t *column;
637   uint32_t i, j, n;
638   int32_t r, r_ptr;
639 
640   assert(c < matrix->ncolumns);
641   column = matrix->column[c];
642   if (column == NULL || column->free < 0) return;
643 
644   n = column->size;
645   j = 0;
646   for (i=0; i<n; i++) {
647     r = column->data[i].r_idx;
648     if (r >= 0) {
649       assert(j <= i);
650       if (j < i) {
651         r_ptr = column->data[i].r_ptr;
652         column->data[j] = column->data[i];
653         matrix->row[r]->data[r_ptr].c_ptr = j;
654       }
655       j ++;
656     }
657   }
658   column->size = j;
659   column->free = -1;
660 }
661 
662 #endif
663 
664 
665 
666 /*
667  * ROW ADDITION
668  */
669 
670 /*
671  * Increase the row capacity by 50%
672  */
matrix_increase_row_capacity(matrix_t * matrix)673 static void matrix_increase_row_capacity(matrix_t *matrix) {
674   uint32_t n;
675 
676   n = matrix->row_cap + 1;
677   n += n>>1;
678   if (n >= MAX_MATRIX_NUM_ROWS) {
679     out_of_memory();
680   }
681   matrix->row_cap = n;
682   matrix->row = (row_t **) safe_realloc(matrix->row, n * sizeof(row_t *));
683   matrix->base_var = (int32_t *) safe_realloc(matrix->base_var, n * sizeof(int32_t));
684   matrix->marks = extend_bitvector(matrix->marks, n);
685 }
686 
687 
688 /*
689  * Add a new row of the form p == 0
690  * - p is defined by the array of monomials a
691  * - n = size of that array
692  * - there must be an existing column in the matrix for
693  *   all the variables in p (i.e., a[0].var, ...., a[n-1].var)
694  *   (i.e., a[i].var < matrix->ncolumns for i=0, ..., n-1)
695  * - p must be normalized (all monomials must have different variables,
696  *   and all coefficients must be non zero).
697  */
matrix_add_row(matrix_t * matrix,monomial_t * a,uint32_t n)698 void matrix_add_row(matrix_t *matrix, monomial_t *a, uint32_t n) {
699   row_t *r;
700   col_elem_t *c;
701   uint32_t i, j, row_size;
702   uint32_t c_ptr, r_idx;
703 
704 #ifndef NDEBUG
705   for (i=0; i<n; i++) {
706     assert(q_is_nonzero(&a[i].coeff));
707   }
708 #endif
709 
710   // allocate a row index
711   r_idx = matrix->nrows;
712   if (r_idx == matrix->row_cap) {
713     matrix_increase_row_capacity(matrix);
714   }
715   assert(r_idx < matrix->row_cap);
716   matrix->nrows = r_idx + 1;
717 
718   // allocate a row vector
719   row_size = DEF_MATRIX_ROW_SIZE;
720   if (row_size < n) {
721     row_size = n;
722   }
723   r = new_row(row_size);
724   assert(r->capacity >= n);
725 
726   // copy a[i] into r->data[i]
727   // add the corresponding data to the column vectors
728   for (i=0; i<n; i++) {
729     j = a[i].var;
730     c_ptr = get_column_elem(matrix, j);
731     r->data[i].c_idx = j;
732     r->data[i].c_ptr = c_ptr;
733     q_init(&r->data[i].coeff);
734     q_set(&r->data[i].coeff, &a[i].coeff);
735 
736     c = column_elem(matrix, j, c_ptr);
737     c->r_idx = r_idx;
738     c->r_ptr = i;
739   }
740   r->size = n;
741   r->nelems = n;
742 
743   matrix->row[r_idx] = r;
744   matrix->base_var[r_idx] = -1;
745   clr_bit(matrix->marks, r_idx);
746 }
747 
748 
749 
750 /*
751  * Add a new row of the form x - p == 0
752  * - p is defined by a[0] ... a[n-1]
753  * - p must be normalized
754  * - x must not occur in p
755  */
matrix_add_eq(matrix_t * matrix,int32_t x,monomial_t * a,uint32_t n)756 void matrix_add_eq(matrix_t *matrix, int32_t x, monomial_t *a, uint32_t n) {
757   row_t *r;
758   col_elem_t *c;
759   uint32_t i, j, row_size;
760   uint32_t c_ptr, r_idx;
761 
762 #ifndef NDEBUG
763   for (i=0; i<n; i++) {
764     assert(a[i].var != x && q_is_nonzero(&a[i].coeff));
765   }
766 #endif
767 
768   // allocate a row index
769   r_idx = matrix->nrows;
770   if (r_idx == matrix->row_cap) {
771     matrix_increase_row_capacity(matrix);
772   }
773   assert(r_idx < matrix->row_cap);
774   matrix->nrows = r_idx + 1;
775 
776   // allocate a row vector
777   row_size = DEF_MATRIX_ROW_SIZE;
778   if (row_size < n+1) {
779     row_size = n+1;
780   }
781   r = new_row(row_size);
782   assert(r->capacity >= n+1);
783 
784   // copy -a[i] into r->data[i]
785   // add the corresponding data to the column vectors
786   for (i=0; i<n; i++) {
787     j = a[i].var;
788     c_ptr = get_column_elem(matrix, j);
789     r->data[i].c_idx = j;
790     r->data[i].c_ptr = c_ptr;
791     q_init(&r->data[i].coeff);
792     q_set_neg(&r->data[i].coeff, &a[i].coeff);
793 
794     c = column_elem(matrix, j, c_ptr);
795     c->r_idx = r_idx;
796     c->r_ptr = i;
797   }
798   // add x as last element of the row
799   c_ptr = get_column_elem(matrix, x);
800   r->data[i].c_idx = x;
801   r->data[i].c_ptr = c_ptr;
802   q_init(&r->data[i].coeff);
803   q_set_one(&r->data[i].coeff);
804 
805   c = column_elem(matrix, x, c_ptr);
806   c->r_idx = r_idx;
807   c->r_ptr = i;
808 
809   i++;
810   r->size = i;
811   r->nelems = i;
812 
813   matrix->row[r_idx] = r;
814   matrix->base_var[r_idx] = -1;
815   clr_bit(matrix->marks, r_idx);
816 }
817 
818 
819 #ifndef NDEBUG
820 
821 /*
822  * Check a new tableau row (x - p)
823  */
check_tableau_eq(matrix_t * matrix,int32_t x,monomial_t * a,uint32_t n)824 static void check_tableau_eq(matrix_t *matrix, int32_t x, monomial_t *a, uint32_t n) {
825   uint32_t i;
826   int32_t y;
827 
828   // x must not occur in the tableau
829   assert(0 <= x && x < matrix->ncolumns && matrix->base_row[x] < 0);
830   assert(matrix->column[x] == NULL || matrix->column[x]->nelems == 0);
831 
832   // all variables in a[0] ... a[n-1] must be non-basic
833   for (i=0; i<n; i++) {
834     y = a[i].var;
835     assert(0 <= y && y < matrix->ncolumns && y != x && matrix->base_row[y] < 0);
836   }
837 }
838 
839 #endif
840 
841 
842 /*
843  * Add a new row of the form x - p == 0 and make x the basic variable in the new row
844  * - the matrix must be in tableau form
845  * - p is stored as an array of monomials a[0] ... a[n-1]
846  * - x must be a fresh variable not occurring in any row of the tableau
847  * - x and the existing basic variables must not occur in p
848  * - x and a[0].var, ..., a[n-1].var must be existing columns
849  */
matrix_add_tableau_eq(matrix_t * matrix,int32_t x,monomial_t * a,uint32_t n)850 void matrix_add_tableau_eq(matrix_t *matrix, int32_t x, monomial_t *a, uint32_t n) {
851   uint32_t r_idx; // index of the new row
852 
853 #ifndef NDEBUG
854   check_tableau_eq(matrix, x, a, n);
855 #endif
856 
857   r_idx = matrix->nrows;
858   matrix_add_eq(matrix, x, a, n);
859   assert(matrix->nrows == r_idx+1);
860   matrix->base_var[r_idx] = x;
861   matrix->base_row[x] = r_idx;
862 }
863 
864 
865 /*
866  * Remove the empty elements from row r and update the columns
867  */
matrix_compact_row(matrix_t * matrix,uint32_t r)868 static void matrix_compact_row(matrix_t *matrix, uint32_t r) {
869   row_t *row;
870   uint32_t i, j, n;
871   int32_t c, c_ptr;
872 
873   assert(r < matrix->nrows);
874   row = matrix->row[r];
875   if (row == NULL || row->free < 0) return;
876 
877   n = row->size;
878   j = 0;
879   for (i=0; i<n; i++) {
880     c = row->data[i].c_idx;
881     if (c >= 0) {
882       assert(j <= i);
883       if (j < i) {
884         c_ptr = row->data[i].c_ptr;
885         row->data[j].c_idx = c;
886         row->data[j].c_ptr = c_ptr;
887         q_set(&row->data[j].coeff, &row->data[i].coeff);
888         matrix->column[c]->data[c_ptr].r_ptr = j;
889       }
890       j ++;
891     }
892   }
893   row->size = j;
894   row->free = -1;
895 
896   // free the rationals
897   while (j < n) {
898     q_clear(&row->data[j].coeff);
899     j ++;
900   }
901 }
902 
903 
904 /*
905  * Detach row from the column vectors
906  */
matrix_detach_row(matrix_t * matrix,row_t * row)907 static void matrix_detach_row(matrix_t *matrix, row_t *row) {
908   uint32_t i, n;
909   int32_t c, c_ptr;
910 
911   n = row->size;
912   for (i=0; i<n; i++) {
913     c = row->data[i].c_idx;
914     if (c >= 0) {
915       c_ptr = row->data[i].c_ptr;
916       free_column_elem(matrix->column[c], c_ptr);
917     }
918   }
919 }
920 
921 
922 
923 /*
924  * Change the index of row to r
925  */
matrix_change_row_index(matrix_t * matrix,row_t * row,uint32_t r)926 static void matrix_change_row_index(matrix_t *matrix, row_t *row, uint32_t r) {
927   uint32_t i, n;
928   int32_t c, c_ptr;
929 
930   n = row->size;
931   for (i=0; i<n; i++) {
932     c = row->data[i].c_idx;
933     if (c >= 0) {
934       c_ptr = row->data[i].c_ptr;
935       matrix->column[c]->data[c_ptr].r_idx = r;
936     }
937   }
938 
939 }
940 
941 
942 /*
943  * Remove all NULL or empty rows from the matrix
944  * - renumber the rest
945  */
compact_matrix(matrix_t * matrix)946 static void compact_matrix(matrix_t *matrix) {
947   row_t *row;
948   uint32_t i, j, n;
949   int32_t x;
950 
951   n = matrix->nrows;
952   j = 0;
953   for (i=0; i<n; i++) {
954     row = matrix->row[i];
955     if (row != NULL) {
956       if (row->nelems == 0) {
957         // delete the row
958         delete_row(row);
959       } else {
960         if (j < i) {
961           matrix_change_row_index(matrix, row, j);
962           matrix->row[j] = row;
963           assign_bit(matrix->marks, j, tst_bit(matrix->marks, i));
964 
965           x = matrix->base_var[i];
966           matrix->base_var[j] = x;
967           if (x >= 0) {
968             matrix->base_row[x] = j;
969           }
970         }
971         j ++;
972       }
973     }
974   }
975 
976   matrix->nrows = j;
977 }
978 
979 
980 
981 
982 /*
983  * REMOVAL OF ROWS AND COLUMNS
984  */
985 
986 /*
987  * Remove rows[n ... nrows-1]
988  */
matrix_remove_rows(matrix_t * matrix,uint32_t n)989 static void matrix_remove_rows(matrix_t *matrix, uint32_t n) {
990   uint32_t i, p;
991   row_t *row;
992 
993   assert(n <= matrix->nrows);
994 
995   p = matrix->nrows;
996   for (i=n; i<p; i++) {
997     row = matrix->row[i];
998     matrix_detach_row(matrix, row);
999     delete_row(row);
1000     matrix->row[i] = NULL;
1001   }
1002 
1003   matrix->nrows = n;
1004 }
1005 
1006 
1007 /*
1008  * Remove columns[n ... ncolumns- 1]
1009  */
matrix_remove_columns(matrix_t * matrix,uint32_t n)1010 static void matrix_remove_columns(matrix_t *matrix, uint32_t n) {
1011   uint32_t i, p;
1012   column_t *col;
1013 
1014   assert(n <= matrix->ncolumns);
1015 
1016   p = matrix->ncolumns;
1017   for (i=n; i<p; i++) {
1018     col = matrix->column[i];
1019     if (col != NULL) {
1020       assert(col->nelems == 0);
1021       delete_column(col);
1022       matrix->column[i] = NULL;
1023     }
1024   }
1025 
1026   matrix->ncolumns = n;
1027 }
1028 
1029 
1030 /*
1031  * Reduce the matrix to dimension n x m
1032  * - n = number of rows to keep
1033  * - m = number of columns to keep
1034  */
matrix_shrink(matrix_t * matrix,uint32_t n,uint32_t m)1035 void matrix_shrink(matrix_t *matrix, uint32_t n, uint32_t m) {
1036   assert(good_matrix(matrix));
1037 
1038   matrix_remove_rows(matrix, n);
1039   matrix_remove_columns(matrix, m);
1040 
1041   assert(good_matrix(matrix));
1042 }
1043 
1044 
1045 
1046 /*
1047  * REMOVAL OF FIXED VARIABLES
1048  */
1049 
1050 /*
1051  * Find the index of the constant element in row r
1052  * - return -1 if r has no constant
1053  */
get_constant_in_row(row_t * r)1054 static int32_t get_constant_in_row(row_t *r) {
1055   uint32_t i, n;
1056 
1057   n = r->size;
1058   for (i=0; i<n; i++) {
1059     if (r->data[i].c_idx == const_idx) return i;
1060   }
1061   return -1;
1062 }
1063 
1064 
1065 /*
1066  * Build the constant vector (to prepare for elimination of fixed variables)
1067  */
matrix_collect_constants(matrix_t * matrix)1068 void matrix_collect_constants(matrix_t *matrix) {
1069   uint32_t i, n;
1070   int32_t *tmp;
1071 
1072   assert(matrix->constant == NULL);
1073   n = matrix->nrows;
1074   tmp = (int32_t *) safe_malloc(n * sizeof(int32_t));
1075   matrix->constant = tmp;
1076   for (i=0; i<n; i++) {
1077     tmp[i] = get_constant_in_row(matrix->row[i]);
1078   }
1079 }
1080 
1081 
1082 
1083 /*
1084  * Eliminate fixed variable x (i.e., apply the substitution x := a)
1085  * - x must not be the const_idx
1086  */
matrix_eliminate_fixed_variable(matrix_t * matrix,int32_t x,rational_t * a)1087 void matrix_eliminate_fixed_variable(matrix_t *matrix, int32_t x, rational_t *a) {
1088   column_t *col;
1089   uint32_t i, n;
1090   int32_t j, k, r_ptr, c_ptr;
1091   row_elem_t *e, *cnst;
1092 
1093   assert(0 <= x && x < matrix->ncolumns && x != const_idx);
1094   col = matrix->column[x];
1095   if (col == NULL) return;  // nothing to do
1096 
1097   n = col->size;
1098   if (q_is_zero(a)) {
1099     // if a is zero, we just need to remove the column
1100     for (i=0; i<n; i++) {
1101       j = col->data[i].r_idx;
1102       if (j >= 0) {
1103         r_ptr = col->data[i].r_ptr;
1104         free_row_elem(matrix->row[j], r_ptr);
1105       }
1106     }
1107   } else {
1108     for (i=0; i<n; i++) {
1109       j = col->data[i].r_idx;
1110       if (j >= 0) {
1111         /*
1112          * e --> element c.x in row j = element of index r_ptr
1113          */
1114         r_ptr = col->data[i].r_ptr;
1115         e = row_elem(matrix, j, r_ptr);
1116         assert(e->c_idx == x);
1117         k = matrix->constant[j];
1118         if (k < 0) {
1119           // row j has no constant: attach e to column 0
1120           c_ptr = add_column_elem(matrix, const_idx, j, r_ptr);
1121           e->c_idx = const_idx;
1122           e->c_ptr = c_ptr;
1123           q_mul(&e->coeff, a); // make constant = a.c
1124           matrix->constant[j] = r_ptr;
1125         } else {
1126           // add a.c to element k of row j
1127           cnst = row_elem(matrix, j, k);
1128           q_addmul(&cnst->coeff, &e->coeff, a);
1129           // free e (from row j)
1130           free_row_elem(matrix->row[j], r_ptr);
1131         }
1132       }
1133     }
1134   }
1135 
1136   // remove column x
1137   delete_column(col);
1138   matrix->column[x] = NULL;
1139 }
1140 
1141 
1142 /*
1143  * Cleanup:
1144  * - remove all zero constant elements
1145  * - delete the constant array
1146  */
matrix_cleanup_constants(matrix_t * matrix)1147 void matrix_cleanup_constants(matrix_t *matrix) {
1148   uint32_t i, n;
1149   int32_t r_ptr;
1150   row_elem_t *e;
1151 
1152   assert(matrix->constant != NULL);
1153 
1154   n = matrix->nrows;
1155   for (i=0; i<n; i++) {
1156     r_ptr = matrix->constant[i];
1157     if (r_ptr >= 0) {
1158       e = row_elem(matrix, i, r_ptr);
1159       assert(e->c_idx == const_idx);
1160       if (q_is_zero(&e->coeff)) {
1161         free_column_elem(matrix->column[const_idx], e->c_ptr);
1162         free_row_elem(matrix->row[i], r_ptr);
1163       }
1164     }
1165   }
1166 
1167   safe_free(matrix->constant);
1168   matrix->constant = NULL;
1169 }
1170 
1171 
1172 
1173 
1174 
1175 
1176 
1177 
1178 
1179 
1180 
1181 /*****************************
1182  *   MARKOWITZ'S HEURISTIC   *
1183  ****************************/
1184 
1185 /*
1186  * Markowitz's heuristic is used during Gaussian elimination:
1187  * - select a pivot a_ij/=0 in row i, column j such that
1188  *      (r_count[i] - 1) * (c_count[j] - 1) is minimal
1189  *   where r_count[i] = number of non-zero coefficients in row i
1190  *         c_count[j] = number of non-zero coefficients in column j
1191  *
1192  * To implement this, we keep for a record for each row i:
1193  * - the best column j in that row + the index k of the corresponding element
1194  * - the score (r_count[i] - 1) * (c_count[j] - 1)
1195  * - then we store the rows in a heap
1196  *
1197  * The markowitz_t data structure also contains bitvector that flags
1198  * all variables that can be eliminated. This is used for simplifying the matrix.
1199  */
1200 
1201 /*
1202  * Ordering function for the heap
1203  * - row_cmp(d, x, y) returns true if x has lower score than y
1204  */
row_cmp(markowitz_t * d,int32_t x,int32_t y)1205 static bool row_cmp(markowitz_t *d, int32_t x, int32_t y) {
1206   assert(d->row_rec[x] != NULL && d->row_rec[y] != NULL && x != y);
1207   return d->row_rec[x]->score < d->row_rec[y]->score;
1208 }
1209 
1210 /*
1211  * Compute (a - 1) * (b - 1).
1212  * - if there's an overflow return UINT32_MAX
1213  */
markowitz_score(uint32_t a,uint32_t b)1214 static inline uint32_t markowitz_score(uint32_t a, uint32_t b) {
1215   uint64_t tmp;
1216   tmp = ((uint64_t ) (a - 1)) * (b -1);
1217   return (tmp >= UINT32_MAX) ? UINT32_MAX : tmp;
1218 }
1219 
1220 
1221 /*
1222  * Initialize Markowitz's record for n rows and m columns
1223  * - the row_rec array is allocated but not initialized
1224  * - the elim_flag bitvector is initialized (all zeros)
1225  */
init_markowitz(markowitz_t * d,uint32_t n,uint32_t m)1226 static void init_markowitz(markowitz_t *d, uint32_t n, uint32_t m) {
1227   assert(n < MAX_MATRIX_NUM_ROWS && m < MAX_MATRIX_NUM_COLUMNS);
1228 
1229   d->nrows = n;
1230   d->ncolumns = m;
1231   d->row_rec = (row_record_t **) safe_malloc(n * sizeof(row_record_t *));
1232   d->elim_flag = allocate_bitvector0(m);
1233   init_generic_heap(&d->heap, 0, n, (heap_cmp_fun_t) row_cmp, d);
1234   init_objstore(&d->store, sizeof(row_record_t), MARKOWITZ_RECORDS_PER_BLOCK);
1235 }
1236 
1237 
1238 /*
1239  * Delete the Markovitz's records
1240  */
delete_markowitz(markowitz_t * d)1241 static void delete_markowitz(markowitz_t *d) {
1242   safe_free(d->row_rec);
1243   delete_bitvector(d->elim_flag);
1244   delete_generic_heap(&d->heap);
1245   delete_objstore(&d->store);
1246 }
1247 
1248 
1249 /*
1250  * Mark all columns in array a as elimination candidates
1251  * - n = size of the array
1252  * - the constant const_idx must not be an elimination candidate.
1253  */
markowitz_init_columns(markowitz_t * d,int32_t * a,uint32_t n)1254 static void markowitz_init_columns(markowitz_t *d, int32_t *a, uint32_t n) {
1255   uint32_t i;
1256   int32_t x;
1257 
1258   for (i=0; i<n; i++) {
1259     x = a[i];
1260     assert(0 <= x && x < d->ncolumns && x != const_idx);
1261     set_bit(d->elim_flag, x);
1262   }
1263 }
1264 
1265 
1266 /*
1267  * Mark all columns except const_idx as elimination candidates
1268  */
markowitz_init_all_columns(markowitz_t * d)1269 static void markowitz_init_all_columns(markowitz_t *d) {
1270   set_bitvector(d->elim_flag, d->ncolumns);
1271   clr_bit(d->elim_flag, const_idx);
1272 }
1273 
1274 
1275 /*
1276  * Add record for row r to d->row_rec
1277  */
markowitz_add_record(markowitz_t * d,uint32_t r,uint32_t score,uint32_t c_idx,uint32_t r_ptr)1278 static void markowitz_add_record(markowitz_t *d, uint32_t r, uint32_t score, uint32_t c_idx, uint32_t r_ptr) {
1279   row_record_t *rec;
1280 
1281   rec = (row_record_t *) objstore_alloc(&d->store);
1282   rec->score = score;
1283   rec->c_idx = c_idx;
1284   rec->r_ptr = r_ptr;
1285   d->row_rec[r] = rec; // must be done before adding r to the heap
1286   generic_heap_add(&d->heap, r);
1287 }
1288 
1289 
1290 /*
1291  * Initialize the record for a singleton row r (of the form a.x == 0)
1292  * - row must be equal matrix->row[r]
1293  * - a new record is created
1294  */
markowitz_init_singleton_row(markowitz_t * d,matrix_t * matrix,row_t * row,uint32_t r)1295 static void markowitz_init_singleton_row(markowitz_t *d, matrix_t *matrix, row_t *row, uint32_t r) {
1296   uint32_t i;
1297   int32_t x;
1298 
1299   assert(row->nelems == 1 && row == matrix->row[r]);
1300   i = 0;
1301   x = row->data[i].c_idx;
1302   while (x < 0) {
1303     i ++;
1304     assert(i < row->size);
1305     x = row->data[i].c_idx;
1306   }
1307 
1308   markowitz_add_record(d, r, 0, x, i);
1309 }
1310 
1311 
1312 /*
1313  * Initialize the record for a row r with two monomials
1314  * - row must be equal matrix->row[r]
1315  * - a new record is created if the row is of the form
1316  *   a.x + b == 0 or if it's a.x + b.y == 0
1317  *   and x or y is marked for elimination
1318  */
markowitz_init_simple_row(markowitz_t * d,matrix_t * matrix,row_t * row,uint32_t r)1319 static void markowitz_init_simple_row(markowitz_t *d, matrix_t *matrix, row_t *row, uint32_t r) {
1320   uint32_t i, j, score;
1321   int32_t x, y;
1322 
1323   assert(row->nelems == 2 && row == matrix->row[r]);
1324 
1325   if (row->size == 2) {
1326     i = 0; x = row->data[0].c_idx;
1327     j = 1; y = row->data[1].c_idx;
1328   } else {
1329     // find the two row elements
1330     i = 0;
1331     x = row->data[i].c_idx;
1332     while (x < 0) {
1333       i ++;
1334       assert(i < row->size);
1335       x = row->data[i].c_idx;
1336     }
1337     j = i;
1338     do {
1339       j ++;
1340       assert(j < row->size);
1341       y = row->data[j].c_idx;
1342     } while (y < 0);
1343   }
1344 
1345   assert(x >= 0 && y >= 0 && row->data[i].c_idx == x && row->data[j].c_idx == y);
1346 
1347   if (x == const_idx) {
1348     // eliminate y
1349     score = matrix->column[y]->nelems - 1;
1350     markowitz_add_record(d, r, score, y, j);
1351 
1352   } else if (y == const_idx) {
1353     // eliminate x
1354     score = matrix->column[x]->nelems - 1;
1355     markowitz_add_record(d, r, score, x, i);
1356 
1357   } else if (tst_bit(d->elim_flag, x)) {
1358     // x can be eliminated
1359     score = matrix->column[x]->nelems - 1;
1360     if (tst_bit(d->elim_flag, y) && matrix->column[y]->nelems <= score) {
1361       // y can be eliminated and is better than x
1362       score = matrix->column[y]->nelems - 1;
1363       markowitz_add_record(d, r, score, y, j);
1364     } else {
1365       markowitz_add_record(d, r, score, x, i);
1366     }
1367 
1368   } else if (tst_bit(d->elim_flag, y)) {
1369     // eliminate y
1370     score = matrix->column[y]->nelems - 1;
1371     markowitz_add_record(d, r, score, y, j);
1372 
1373   } else {
1374     // no elimination
1375     d->row_rec[r] = NULL;
1376   }
1377 
1378 }
1379 
1380 
1381 /*
1382  * Initialize the record for a row r (general case: r has at least 3 elements)
1383  * - row must be equal to matrix->row[r]
1384  * - a new record is created if the row contains a variable to eliminate
1385  * - otherwise d->col_rec[r] is NULL
1386  */
markowitz_init_row(markowitz_t * d,matrix_t * matrix,row_t * row,uint32_t r)1387 static void markowitz_init_row(markowitz_t *d, matrix_t *matrix, row_t *row, uint32_t r) {
1388   uint32_t i, n, c;
1389   uint32_t best_i, best_c;
1390   int32_t x, best_x;
1391 
1392   assert(row == matrix->row[r]);
1393 
1394   n = row->size;
1395 
1396   best_x = -1;
1397   best_i = 0;
1398   best_c = UINT32_MAX;
1399 
1400   // find best column for the row
1401   for (i=0; i<n; i++) {
1402     x = row->data[i].c_idx;
1403     if (x >= 0 && tst_bit(d->elim_flag, x)) {
1404       c = matrix->column[x]->nelems;
1405       if (c < best_c) {
1406         best_c = c;
1407         best_x = x;
1408         best_i = i;
1409       }
1410     }
1411   }
1412 
1413   if (best_x >= 0) {
1414     markowitz_add_record(d, r, markowitz_score(best_c, row->nelems), best_x, best_i);
1415   } else {
1416     d->row_rec[r] = NULL;
1417   }
1418 }
1419 
1420 
1421 /*
1422  * Initialize the row record for all rows of matrix
1423  */
markowitz_init_rows(markowitz_t * d,matrix_t * matrix)1424 static void markowitz_init_rows(markowitz_t *d, matrix_t *matrix) {
1425   uint32_t i, n;
1426   row_t *row;
1427 
1428   assert(matrix->nrows == d->nrows);
1429   n = matrix->nrows;
1430   for (i=0; i<n; i++) {
1431     row = matrix->row[i];
1432     switch (row->nelems) {
1433     case 0:
1434       delete_row(row);
1435       matrix->row[i] = NULL;
1436       break;
1437     case 1:
1438       markowitz_init_singleton_row(d, matrix, row, i);
1439       break;
1440     case 2:
1441       markowitz_init_simple_row(d, matrix, row, i);
1442       break;
1443     default:
1444       markowitz_init_row(d, matrix, row, i);
1445       break;
1446     }
1447   }
1448 }
1449 
1450 
1451 
1452 
1453 /*
1454  * Update record for row r
1455  * - score, c_idx, r_ptr are the new record components
1456  */
markowitz_update_record(markowitz_t * d,uint32_t r,uint32_t score,uint32_t c_idx,uint32_t r_ptr)1457 static void markowitz_update_record(markowitz_t *d, uint32_t r, uint32_t score, uint32_t c_idx, uint32_t r_ptr) {
1458   row_record_t *rec;
1459   uint32_t old_score;
1460 
1461   rec = d->row_rec[r];
1462   if (rec != NULL) {
1463     old_score = rec->score;
1464     rec->score = score;
1465     rec->c_idx = c_idx;
1466     rec->r_ptr = r_ptr;
1467     if (score < old_score) {
1468       generic_heap_move_up(&d->heap, r);
1469     } else if (score > old_score) {
1470       generic_heap_move_down(&d->heap, r);
1471     }
1472   } else {
1473     markowitz_add_record(d, r, score, c_idx, r_ptr);
1474   }
1475 }
1476 
1477 
1478 /*
1479  * Remove record for row r
1480  */
markowitz_remove_record(markowitz_t * d,uint32_t r)1481 static void markowitz_remove_record(markowitz_t *d, uint32_t r) {
1482   row_record_t *rec;
1483 
1484   rec = d->row_rec[r];
1485   if (rec != NULL) {
1486     generic_heap_remove(&d->heap, r);
1487     objstore_free(&d->store, rec);
1488     d->row_rec[r] = NULL;
1489   }
1490 }
1491 
1492 
1493 /*
1494  * Update the record for row r after it changes to a singleton row
1495  * - row must be equal matrix->row[r]
1496  */
markowitz_update_singleton_row(markowitz_t * d,matrix_t * matrix,row_t * row,uint32_t r)1497 static void markowitz_update_singleton_row(markowitz_t *d, matrix_t *matrix, row_t *row, uint32_t r) {
1498   uint32_t i;
1499   int32_t x;
1500 
1501   assert(row->nelems == 1 && row == matrix->row[r]);
1502   i = 0;
1503   x = row->data[i].c_idx;
1504   while (x < 0) {
1505     i ++;
1506     assert(i < row->size);
1507     x = row->data[i].c_idx;
1508   }
1509   markowitz_update_record(d, r, 0, x, i);
1510 }
1511 
1512 
1513 /*
1514  * Update the record for a row r with two monomials
1515  * - row must be equal matrix->row[r]
1516  */
markowitz_update_simple_row(markowitz_t * d,matrix_t * matrix,row_t * row,uint32_t r)1517 static void markowitz_update_simple_row(markowitz_t *d, matrix_t *matrix, row_t *row, uint32_t r) {
1518   uint32_t i, j, score;
1519   int32_t x, y;
1520 
1521   assert(row->nelems == 2 && row == matrix->row[r]);
1522 
1523   if (row->size == 2) {
1524     i = 0;
1525     x = row->data[0].c_idx;
1526     j = 1;
1527     y = row->data[1].c_idx;
1528   } else {
1529     // find the two row elements
1530     i = 0;
1531     x = row->data[i].c_idx;
1532     while (x < 0) {
1533       i ++;
1534       assert(i < row->size);
1535       x = row->data[i].c_idx;
1536     }
1537     j = i;
1538     do {
1539       j ++;
1540       assert(j < row->size);
1541       y = row->data[j].c_idx;
1542     } while (y < 0);
1543   }
1544 
1545   assert(x >= 0 && y >= 0 && row->data[i].c_idx == x && row->data[j].c_idx == y);
1546 
1547   if (x == const_idx) {
1548     // eliminate y
1549     score = matrix->column[y]->nelems - 1;
1550     markowitz_update_record(d, r, score, y, j);
1551 
1552   } else if (y == const_idx) {
1553     // eliminate x
1554     score = matrix->column[x]->nelems - 1;
1555     markowitz_update_record(d, r, score, x, i);
1556 
1557   } else if (tst_bit(d->elim_flag, x)) {
1558     // x can be eliminated
1559     score = matrix->column[x]->nelems - 1;
1560     if (tst_bit(d->elim_flag, y) && matrix->column[y]->nelems <= score) {
1561       // y can be eliminated and is better than x
1562       score = matrix->column[y]->nelems - 1;
1563       markowitz_update_record(d, r, score, y, j);
1564     } else {
1565       markowitz_update_record(d, r, score, x, i);
1566     }
1567 
1568   } else if (tst_bit(d->elim_flag, y)) {
1569     // eliminate y
1570     score = matrix->column[y]->nelems - 1;
1571     markowitz_update_record(d, r, score, y, j);
1572 
1573   } else {
1574     // the row can't be eliminated
1575     markowitz_remove_record(d, r);
1576   }
1577 }
1578 
1579 
1580 /*
1581  * Update the record for a row r (general case: r has at least 3 elements)
1582  * - row must be equal to matrix->row[r]
1583  */
markowitz_update_row(markowitz_t * d,matrix_t * matrix,row_t * row,uint32_t r)1584 static void markowitz_update_row(markowitz_t *d, matrix_t *matrix, row_t *row, uint32_t r) {
1585   uint32_t i, n, c;
1586   uint32_t best_i, best_c;
1587   int32_t x, best_x;
1588 
1589   assert(row == matrix->row[r]);
1590 
1591   n = row->size;
1592 
1593   best_x = -1;
1594   best_i = 0;
1595   best_c = UINT32_MAX;
1596 
1597   // find best column for the row
1598   for (i=0; i<n; i++) {
1599     x = row->data[i].c_idx;
1600     if (x >= 0 && tst_bit(d->elim_flag, x)) {
1601       c = matrix->column[x]->nelems;
1602       if (c < best_c) {
1603         best_c = c;
1604         best_x = x;
1605         best_i = i;
1606       }
1607     }
1608   }
1609 
1610   if (best_x >= 0) {
1611     markowitz_update_record(d, r, markowitz_score(best_c, row->nelems), best_x, best_i);
1612   } else {
1613     markowitz_remove_record(d, r);
1614   }
1615 }
1616 
1617 
1618 /*
1619  * Update record after row r has changed
1620  * - if r is non-empty and  does not have a record then a new one is created
1621  *   and added to the heap.
1622  * - during tableau construction, r may be a previously visited row that
1623  *   already has a basic variable. Since r is put back into the heap,
1624  *   it will be revisited again and possibly get simplified more.
1625  */
markowitz_update(markowitz_t * d,matrix_t * matrix,uint32_t r)1626 static void markowitz_update(markowitz_t *d, matrix_t *matrix, uint32_t r) {
1627   row_t *row;
1628 
1629   row = matrix->row[r];
1630   switch (row->nelems) {
1631   case 0:
1632     markowitz_remove_record(d, r);
1633     break;
1634   case 1:
1635     markowitz_update_singleton_row(d, matrix, row, r);
1636     break;
1637   case 2:
1638     markowitz_update_simple_row(d, matrix, row, r);
1639     break;
1640   default:
1641     markowitz_update_row(d, matrix, row, r);
1642     break;
1643   }
1644 }
1645 
1646 
1647 
1648 
1649 
1650 
1651 
1652 
1653 
1654 /*****************
1655  *    PIVOTING   *
1656  ****************/
1657 
1658 /*
1659  * Given a row r and k = index of a row element in r (such that r[k] = <a, x, ..>
1660  * - divide all coefficients in row r by a so that the coefficient of x is 1
1661  */
matrix_scale_row(row_t * r,uint32_t k)1662 void matrix_scale_row(row_t *r, uint32_t k) {
1663   uint32_t i, n;
1664   int32_t c, x;
1665   rational_t *a;
1666 
1667   x = r->data[k].c_idx;
1668   a = &r->data[k].coeff;
1669   assert(x >= 0 && x != const_idx && q_is_nonzero(a));
1670 
1671   if (q_is_one(a)) {
1672     // nothing to do
1673     return;
1674   } else if (q_is_minus_one(a)) {
1675     // negate all coefficients
1676     n = r->size;
1677     for (i=0; i<n; i++) {
1678       if (r->data[i].c_idx >= 0) {
1679         q_neg(&r->data[i].coeff);
1680       }
1681     }
1682     assert(q_is_one(a));
1683 
1684   } else {
1685     // divide all coefficients by a
1686     n = r->size;
1687     for (i=0; i<n; i++) {
1688       c = r->data[i].c_idx;
1689       if (c >= 0 && c != x) {
1690         q_div(&r->data[i].coeff, a);
1691       }
1692     }
1693     q_set_one(a);
1694   }
1695 }
1696 
1697 
1698 /*
1699  * Auxiliary function for variable elimination. This is the common
1700  * part of Gaussian elimination and pivoting.
1701  *
1702  * Input:
1703  * - r = index of the row where variable elimination is done
1704  * - k = index in that row of an element a.x where x is the variable to eliminate
1705  *       (i.e., matrix->row[r]->data[k] is (x, .., a) and a is non-zero
1706  * - row0 = a row where x has coefficient 1 (it must be distinct from row[r])
1707  *
1708  * The function subtract a * row0 from row[r] to eliminate x.
1709  */
matrix_submul_row(matrix_t * matrix,uint32_t r,uint32_t k,row_t * row0)1710 void matrix_submul_row(matrix_t *matrix, uint32_t r, uint32_t k, row_t *row0) {
1711   row_t *row;
1712   row_elem_t *e;
1713   int32_t *index;
1714   uint32_t i, n;
1715   int32_t j, x;
1716   rational_t *a;
1717 
1718   assert(r < matrix->nrows);
1719   row = matrix->row[r];
1720 
1721   // for every variable x, index[x] = element where x occurs in row r or -1
1722   index = matrix->index;
1723   n = row->size;
1724   e = row->data;
1725   for (i=0; i<n; i++) {
1726     x = e[i].c_idx;
1727     if (x >= 0) index[x] = i;
1728   }
1729 
1730   // coefficient: a = row[k].coeff
1731   a = &matrix->factor;
1732   q_set(a, &row->data[k].coeff);
1733 
1734   // update the coefficients in row r
1735   n = row0->size;
1736   e = row0->data;
1737   if (q_is_one(a)) {
1738     /*
1739      * special case a=1: subtract row0 from row
1740      */
1741     for (i=0; i<n; i++) {
1742       x = e[i].c_idx;
1743       if (x >= 0) {
1744         j = index[x];
1745         if (j < 0) {
1746           // x does not occur in row r: create a new element
1747           j = alloc_row_elem(&row);
1748           row->data[j].c_idx = x;
1749           row->data[j].c_ptr = add_column_elem(matrix, x, r, j);
1750           q_set_neg(&row->data[j].coeff, &row0->data[i].coeff);
1751         } else {
1752           // x occurs in row
1753           q_sub(&row->data[j].coeff, &row0->data[i].coeff);
1754         }
1755       }
1756     }
1757 
1758   } else if (q_is_minus_one(a)) {
1759     /*
1760      * special case a=-1: add row0 to row
1761      */
1762     for (i=0; i<n; i++) {
1763       x = e[i].c_idx;
1764       if (x >= 0) {
1765         j = index[x];
1766         if (j < 0) {
1767           // x does not occur in row r
1768           j = alloc_row_elem(&row);
1769           row->data[j].c_idx = x;
1770           row->data[j].c_ptr = add_column_elem(matrix, x, r, j);
1771           q_set(&row->data[j].coeff, &row0->data[i].coeff);
1772         } else {
1773           // x occurs in row
1774           q_add(&row->data[j].coeff, &row0->data[i].coeff);
1775         }
1776       }
1777     }
1778 
1779   } else {
1780     /*
1781      * general case: subtract a * row0 from row
1782      */
1783     for (i=0; i<n; i++) {
1784       x = e[i].c_idx;
1785       if (x >= 0) {
1786         j = index[x];
1787         if (j < 0) {
1788           // x does not occur in row r: create a new element
1789           j = alloc_row_elem(&row);
1790           row->data[j].c_idx = x;
1791           row->data[j].c_ptr = add_column_elem(matrix, x, r, j);
1792           q_set_neg(&row->data[j].coeff, a);
1793           q_mul(&row->data[j].coeff, &row0->data[i].coeff);
1794         } else {
1795           // x occurs in element j of row r
1796           q_submul(&row->data[j].coeff, a, &row0->data[i].coeff);
1797         }
1798       }
1799     }
1800   }
1801 
1802   assert(q_is_zero(&row->data[k].coeff));
1803 
1804   /*
1805    * row must be copied back since alloc_row_elem may change it
1806    */
1807   matrix->row[r] = row;
1808 
1809   /*
1810    * Cleanup: reset the indices to -1
1811    * and remove the zero elements
1812    */
1813   index = matrix->index;
1814   n = row->size;
1815   e = row->data;
1816   for (i=0; i<n; i++) {
1817     x = e[i].c_idx;
1818     if (x >= 0) {
1819       index[x] = -1;
1820       if (q_is_zero(&e[i].coeff)) {
1821         remove_row_elem(matrix, r, i);
1822       }
1823     }
1824   }
1825 
1826   if (row->nelems * 2 < row->size) {
1827     matrix_compact_row(matrix, r);
1828   }
1829 
1830 }
1831 
1832 
1833 
1834 
1835 /*
1836  * Pivoting step: make x basic in r0
1837  * - k identifies the variable: k must be the index of the element where
1838  * x occurs in row r0
1839  */
matrix_pivot(matrix_t * matrix,uint32_t r0,uint32_t k)1840 void matrix_pivot(matrix_t *matrix, uint32_t r0, uint32_t k) {
1841   row_t *row0;
1842   column_t *col;
1843   int32_t x, r, j;
1844   uint32_t i, n;
1845 
1846   assert(r0 < matrix->nrows && matrix->row[r0] != NULL && k < matrix->row[r0]->size);
1847 
1848   row0 = matrix->row[r0];
1849   x = row0->data[k].c_idx; // variable x to make basic
1850 
1851   assert(x >= 0 && x != const_idx);
1852 
1853   // update row0: make coefficient of x equal to 1
1854   matrix_scale_row(row0, k);
1855 
1856   // eliminate x from the other rows
1857   col = matrix->column[x];
1858   n = col->size;
1859   for (i=0; i<n; i++) {
1860     r = col->data[i].r_idx;
1861     if (r >= 0 && r != r0) {
1862       j = col->data[i].r_ptr;
1863       matrix_submul_row(matrix, r, j, row0);
1864       assert(matrix->column[x] == col); // column[x] should not change
1865     }
1866   }
1867 
1868   // reset the column: it contains a single element
1869   if (col->capacity >= MATRIX_SHRINK_COLUMN_THRESHOLD) {
1870     // attempt to save memory: replace column[x] by a smaller column
1871     delete_column(col);
1872     col = new_column(DEF_MATRIX_COL_SIZE);
1873     matrix->column[x] = col;
1874   }
1875   col->free = -1;
1876   col->nelems = 1;
1877   col->size = 1;
1878   col->data[0].r_idx = r0;
1879   col->data[0].r_ptr = k;
1880 
1881   row0->data[k].c_ptr = 0;
1882 
1883   // update base_row and base_var
1884   j = matrix->base_var[r0];
1885   if (j >= 0) {
1886     matrix->base_row[j] = -1; // variable j no longer basic
1887   }
1888   matrix->base_var[r0] = x;
1889   matrix->base_row[x] = r0;
1890 }
1891 
1892 
1893 
1894 
1895 
1896 
1897 /*
1898  * VARIABLE ELIMINATION
1899  */
1900 
1901 
1902 /*
1903  * Eliminate a zero variable: perform the substitution x := 0
1904  * - if d is non-null, the markowitz record of all modified rows is updated
1905  * - the column of x is deleted
1906  */
matrix_eliminate_zero_variable(matrix_t * matrix,markowitz_t * d,int32_t x)1907 static void matrix_eliminate_zero_variable(matrix_t *matrix, markowitz_t *d, int32_t x) {
1908   column_t *col;
1909   row_t *row;
1910   uint32_t i, n;
1911   int32_t r, k;
1912 
1913   assert(0 <= x && x < matrix->ncolumns && matrix->column[x] != NULL);
1914   col = matrix->column[x];
1915   n = col->size;
1916   for (i=0; i<n; i++) {
1917     r = col->data[i].r_idx;
1918     if (r >= 0) {
1919       k = col->data[i].r_ptr;
1920 
1921       // remove x from row r
1922       row = matrix->row[r];
1923       assert(row->data[k].c_idx == x);
1924       q_clear(&row->data[k].coeff);
1925       free_row_elem(row, k);
1926 
1927       // update the heap
1928       if (d != NULL) {
1929         markowitz_update(d, matrix, r);
1930       }
1931     }
1932   }
1933 
1934   // delete column[x]
1935   delete_column(col);
1936   matrix->column[x] = NULL;
1937 }
1938 
1939 
1940 
1941 
1942 
1943 /*
1944  * Special form of submul for variable substitution: replace a variable
1945  * in row r by the monomial - b.y
1946  * - r = row index
1947  * - k = index in row r of an element a.x where x is the variable to eliminate
1948  * - e0 = monomial b.y in a row r0 (distinct from r)
1949  */
matrix_submul_simple_row(matrix_t * matrix,uint32_t r,uint32_t k,row_elem_t * e0)1950 static void matrix_submul_simple_row(matrix_t *matrix, uint32_t r, uint32_t k, row_elem_t *e0) {
1951   row_t *row;
1952   row_elem_t *e;
1953   uint32_t i, n;
1954   int32_t x, y;
1955 
1956   y = e0->c_idx;
1957 
1958   // search for y in row r
1959   row = matrix->row[r];
1960   n = row->size;
1961   e = row->data;
1962   for (i=0; i<n; i++) {
1963     if (e[i].c_idx == y) break;
1964   }
1965 
1966   if (i < n) {
1967     // y is in row r at position i: subtract a.b from its coefficient
1968     q_submul(&e[i].coeff, &e0->coeff, &e[k].coeff);
1969     if (q_is_zero(&e[i].coeff)) {
1970       remove_row_elem(matrix, r, i);
1971     }
1972     // clear coefficient of x
1973     q_clear(&e[k].coeff);
1974     remove_row_elem(matrix, r, k);
1975 
1976   } else {
1977     // recycle row->data[k] (from a.x to -ab.y)
1978     x = e[k].c_idx;
1979     free_column_elem(matrix->column[x], e[k].c_ptr);
1980     e[k].c_idx = y;
1981     e[k].c_ptr = add_column_elem(matrix, y, r, k);
1982     q_neg(&e[k].coeff);
1983     q_mul(&e[k].coeff, &e0->coeff);
1984     assert(q_is_nonzero(&e[k].coeff));
1985   }
1986 
1987 }
1988 
1989 
1990 
1991 /*
1992  * Perform the substitution x := -e = - b.y
1993  * - if d != NULL, the markowitz record of all modified rows is updated
1994  * - e must not occur in the rows that are being modified
1995  *   and the variable in e must be distinct from x
1996  * _ the column of x is removed
1997  */
matrix_substitute_variable(matrix_t * matrix,markowitz_t * d,int32_t x,row_elem_t * e)1998 static void matrix_substitute_variable(matrix_t *matrix, markowitz_t *d, int32_t x, row_elem_t *e) {
1999     column_t *col;
2000   uint32_t i, n;
2001   int32_t r, k;
2002 
2003   assert(0 <= x && x < matrix->ncolumns && matrix->column[x] != NULL && x != e->c_idx);
2004 
2005   col = matrix->column[x];
2006   n = col->size;
2007   for (i=0; i<n; i++) {
2008     r = col->data[i].r_idx;
2009     if (r >= 0) {
2010       k = col->data[i].r_ptr;
2011 
2012       // subtract a.(x + b.y) from row r
2013       matrix_submul_simple_row(matrix, r, k, e);
2014       if (d != NULL) {
2015         markowitz_update(d, matrix, r);
2016       }
2017     }
2018   }
2019 
2020   // delete column[x]
2021   delete_column(col);
2022   matrix->column[x] = NULL;
2023 }
2024 
2025 
2026 
2027 /*
2028  * Pivot and update to markowitz records
2029  * - make a variable x basic in r0
2030  * - k points to a row element r0->data[k] where x occurs
2031  */
matrix_pivot_and_update(matrix_t * matrix,markowitz_t * d,uint32_t r0,uint32_t k)2032 static void matrix_pivot_and_update(matrix_t *matrix, markowitz_t *d, uint32_t r0, uint32_t k) {
2033   row_t *row0;
2034   column_t *col;
2035   int32_t x, r, j;
2036   uint32_t i, n;
2037 
2038   assert(r0 < matrix->nrows && matrix->row[r0] != NULL && k < matrix->row[r0]->size && d != NULL);
2039 
2040   row0 = matrix->row[r0];
2041   x = row0->data[k].c_idx; // variable x to make basic
2042 
2043   assert(x >= 0 && x != const_idx);
2044 
2045   // update row0: make coefficient of x equal to 1
2046   matrix_scale_row(row0, k);
2047 
2048   // eliminate x from the other rows
2049   col = matrix->column[x];
2050   n = col->size;
2051   for (i=0; i<n; i++) {
2052     r = col->data[i].r_idx;
2053     if (r >= 0 && r != r0) {
2054       j = col->data[i].r_ptr;
2055       matrix_submul_row(matrix, r, j, row0);
2056       assert(matrix->column[x] == col); // column[x] should not change
2057 
2058       // update the heap for row r
2059       markowitz_update(d, matrix, r);
2060     }
2061   }
2062 
2063   // reset the column: it contains a single element
2064   col->free = -1;
2065   col->nelems = 1;
2066   col->size = 1;
2067   col->data[0].r_idx = r0;
2068   col->data[0].r_ptr = k;
2069   row0->data[k].c_ptr = 0;
2070 
2071   // update base_row and base_var
2072   j = matrix->base_var[r0];
2073   if (j >= 0) {
2074     matrix->base_row[j] = -1; // variable j no longer basic
2075   }
2076   matrix->base_var[r0] = x;
2077   matrix->base_row[x] = r0;
2078 
2079 }
2080 
2081 
2082 
2083 
2084 
2085 
2086 
2087 
2088 
2089 
2090 /****************************
2091  *   GAUSSIAN ELIMINATION   *
2092  ***************************/
2093 
2094 /*
2095  * Rows that are removed from a matrix during Gaussian elimination are
2096  * stored into two separate data structures:
2097  * - a fixed variable vectors stores variable assignments: x == a.
2098  *   each assignment is the elimination of a singleton row (x == 0) or
2099  *   a simple row (x + a == 0)
2100  * - an elimination matrix stores an upper triangular matrix
2101  *   each row in the matrix is a polynomial a_1 x_1 + ... + a_n x_n ==0
2102  *   with one variable x_i as diagonal element (base_var), with
2103  *   coefficient a_i = 1
2104  */
2105 
2106 
2107 
2108 /*
2109  * ELIMINATION MATRIX
2110  */
2111 
2112 /*
2113  * Initialize an elimination matrix.
2114  * - the initial row_capacity is 0
2115  * - number of rows = 0 too
2116  */
init_elim_matrix(elim_matrix_t * matrix)2117 void init_elim_matrix(elim_matrix_t *matrix) {
2118   matrix->capacity = 0;
2119   matrix->nrows = 0;
2120   matrix->row = NULL;
2121   matrix->base_var = NULL;
2122 }
2123 
2124 
2125 /*
2126  * Delete an elimination matrix
2127  * - also delete all the polynomials it contains
2128  */
delete_elim_matrix(elim_matrix_t * matrix)2129 void delete_elim_matrix(elim_matrix_t *matrix) {
2130   uint32_t i, n;
2131 
2132   n = matrix->nrows;
2133   for (i=0; i<n; i++) {
2134     free_polynomial(matrix->row[i]);
2135   }
2136 
2137   safe_free(matrix->row);
2138   safe_free(matrix->base_var);
2139   matrix->row = NULL;
2140   matrix->base_var = NULL;
2141 }
2142 
2143 
2144 /*
2145  * Empty an elimination matrix
2146  */
reset_elim_matrix(elim_matrix_t * matrix)2147 void reset_elim_matrix(elim_matrix_t *matrix) {
2148   uint32_t i, n;
2149 
2150   n = matrix->nrows;
2151   for (i=0; i<n; i++) {
2152     free_polynomial(matrix->row[i]);
2153   }
2154   matrix->nrows = 0;
2155 }
2156 
2157 
2158 /*
2159  * Allocate a new row in matrix
2160  * - return its index i
2161  * - matrix->row[i] and matrix->base_var[i] are not initialized
2162  */
elim_matrix_alloc_row(elim_matrix_t * matrix)2163 static uint32_t elim_matrix_alloc_row(elim_matrix_t *matrix) {
2164   uint32_t i, n;
2165 
2166   i = matrix->nrows;
2167   n = matrix->capacity;
2168   if (i == n) {
2169     // allocate more rows
2170     if (n == 0) {
2171       n = DEF_ELIM_MATRIX_NUM_ROWS;
2172     } else {
2173       n ++;
2174       n += n>>1;
2175       if (n >= MAX_ELIM_MATRIX_NUM_ROWS) {
2176         out_of_memory();
2177       }
2178     }
2179 
2180     matrix->base_var = (int32_t *) safe_realloc(matrix->base_var, n * sizeof(int32_t));
2181     matrix->row = (polynomial_t **) safe_realloc(matrix->row, n * sizeof(polynomial_t *));
2182     matrix->capacity = n;
2183   }
2184   assert(i < matrix->capacity);
2185   matrix->nrows = i+1;
2186 
2187   return i;
2188 }
2189 
2190 
2191 /*
2192  * Copy the content of row into an elimination matrix:
2193  * - x = base variable for that row
2194  * - convert row to a polynomial
2195  */
elim_matrix_add_row(elim_matrix_t * matrix,int32_t x,row_t * row)2196 static void elim_matrix_add_row(elim_matrix_t *matrix, int32_t x, row_t *row) {
2197   uint32_t i;
2198 
2199   i = elim_matrix_alloc_row(matrix);
2200   matrix->base_var[i] = x;
2201   matrix->row[i] = convert_row_to_poly(row);
2202 }
2203 
2204 
2205 
2206 /*
2207  * FIXED VARIABLE VECTOR
2208  */
2209 
2210 /*
2211  * Initialization: nothing allocated yet
2212  */
init_fvar_vector(fvar_vector_t * v)2213 void init_fvar_vector(fvar_vector_t *v) {
2214   v->nvars = 0;
2215   v->size = 0;
2216   v->fvar = NULL;
2217 }
2218 
2219 
2220 /*
2221  * Deletion: clear all rationals then delete the array
2222  */
delete_fvar_vector(fvar_vector_t * v)2223 void delete_fvar_vector(fvar_vector_t *v) {
2224   uint32_t i, n;
2225 
2226   n = v->nvars;
2227   for (i=0; i<n; i++) {
2228     q_clear(&v->fvar[i].value);
2229   }
2230   safe_free(v->fvar);
2231   v->fvar = NULL;
2232 }
2233 
2234 
2235 /*
2236  * Empty the vector and clear all rationals
2237  */
reset_fvar_vector(fvar_vector_t * v)2238 void reset_fvar_vector(fvar_vector_t *v) {
2239   uint32_t i, n;
2240 
2241   n = v->nvars;
2242   for (i=0; i<n; i++) {
2243     q_clear(&v->fvar[i].value);
2244   }
2245   v->nvars = 0;
2246 }
2247 
2248 
2249 /*
2250  * Allocate a new element in v and initialize its rational value
2251  * - extend the array if necessary
2252  * - return its index
2253  */
fvar_vector_alloc(fvar_vector_t * v)2254 static uint32_t fvar_vector_alloc(fvar_vector_t *v) {
2255   uint32_t i, n;
2256 
2257   i = v->nvars;
2258   n = v->size;
2259   if (i == n) {
2260     if (n == 0) {
2261       n = DEF_FVAR_VECTOR_SIZE;
2262     } else {
2263       n ++;
2264       n += n>>1;
2265       if (n >= MAX_FVAR_VECTOR_SIZE) {
2266         out_of_memory();
2267       }
2268     }
2269     v->fvar = (fvar_rec_t *) safe_realloc(v->fvar, n * sizeof(fvar_rec_t));
2270     v->size = n;
2271   }
2272   assert(i < v->size);
2273   q_init(&v->fvar[i].value);
2274   v->nvars = i + 1;
2275 
2276   return i;
2277 }
2278 
2279 
2280 /*
2281  * Store the pair (x, -a) in v
2282  */
fvar_vector_add_neg(fvar_vector_t * v,int32_t x,rational_t * a)2283 static void fvar_vector_add_neg(fvar_vector_t *v, int32_t x, rational_t *a) {
2284   uint32_t i;
2285 
2286   i = fvar_vector_alloc(v);
2287   v->fvar[i].var = x;
2288   q_set_neg(&v->fvar[i].value, a);
2289  }
2290 
2291 
2292 /*
2293  * Store the pair (x, 0) into v
2294  */
fvar_vector_add0(fvar_vector_t * v,int32_t x)2295 static void fvar_vector_add0(fvar_vector_t *v, int32_t x) {
2296   uint32_t i;
2297 
2298   i = fvar_vector_alloc(v);
2299   v->fvar[i].var = x;
2300   assert(q_is_zero(&v->fvar[i].value));
2301  }
2302 
2303 
2304 
2305 
2306 
2307 
2308 /*
2309  * SIMPLIFICATION
2310  */
2311 
2312 
2313 /*
2314  * Eliminate a simple row (i.e., a row with two monomials)
2315  * - d = markowitz data structure
2316  * - i_flag = bitvector for integer variables
2317  * - row0 = row to eliminate
2318  * - r0 = its index in the matrix
2319  * - k = index of the monomial to eliminate:
2320  *   row0->data[k] = a. x where x is the variable to eliminate
2321  * - elim = elimination matrix (or NULL)
2322  * - fvar = fixed var vector
2323  */
gauss_elim_simple_row(matrix_t * matrix,markowitz_t * d,byte_t * i_flag,row_t * row0,uint32_t r0,uint32_t k,elim_matrix_t * elim,fvar_vector_t * fvars)2324 static void gauss_elim_simple_row(matrix_t *matrix, markowitz_t *d, byte_t *i_flag,
2325                                   row_t *row0, uint32_t r0, uint32_t k,
2326                                   elim_matrix_t *elim, fvar_vector_t *fvars) {
2327   uint32_t i;
2328   int32_t x, y;
2329   bool y_is_int;
2330 
2331   assert(row0 == matrix->row[r0] && row0 != NULL && row0->nelems == 2 && k < row0->size);
2332 
2333   x = row0->data[k].c_idx;   // variable to eliminate
2334   matrix_scale_row(row0, k); // rewrite row0 as x + b.y == 0
2335 
2336   assert(x != const_idx);
2337 
2338   // find the other monomial in row0
2339   i = 0;
2340   for (;;) {
2341     assert(i < row0->size);
2342     y = row0->data[i].c_idx;
2343     if (x != y && y >= 0) break;
2344     i ++;
2345   }
2346 
2347   // row0->data[i] == monomial b.y
2348   if (y == const_idx) {
2349     /*
2350      * Apply the substitution x := -b
2351      * This may be inconsistent if x is integer and b is not, but the simplex
2352      * solver will detect this when scanning the fvar vector.
2353      */
2354     fvar_vector_add_neg(fvars, x, &row0->data[i].coeff);
2355     goto substitute;
2356   }
2357 
2358 
2359   if (tst_bit(i_flag, x)) {
2360     // Check whether the substitution x := -b.y is ok
2361     y_is_int = tst_bit(i_flag, y);
2362     if (y_is_int && q_is_integer(&row0->data[i].coeff)) {
2363       // b.y is an integer
2364       goto save_and_substitute;
2365     }
2366 
2367     /*
2368      * Try the substitution y := -1/b.x if it's allowed
2369      * Old test was:
2370      *  if (tst_bit(d->elim_flag, y) && matrix->column[y]->nelems <= matrix->column[x]->nelems) {
2371      * but replacing y by -1/b x is fine even if y occurs more often than x in the matrix.
2372      */
2373     if (tst_bit(d->elim_flag, y)) {
2374       matrix_scale_row(row0, i); // rewrite row0 as a.x + y == 0
2375       if (!y_is_int || q_is_integer(&row0->data[k].coeff)) {
2376         // we can apply y := -a.x
2377         x = y;
2378         i = k;
2379         goto save_and_substitute;
2380       }
2381     }
2382 
2383     // failed substitution: keep row0
2384     return;
2385   }
2386 
2387  save_and_substitute:
2388   if (elim != NULL) {
2389     elim_matrix_add_row(elim, x, row0);
2390   }
2391 
2392  substitute:
2393   /*
2394    * Perform the substitution x := - b.y where b.y is row0->data[i]
2395    */
2396   matrix_detach_row(matrix, row0);
2397   matrix_substitute_variable(matrix, d, x, row0->data + i);
2398   delete_row(row0);
2399   matrix->row[r0] = NULL;
2400 }
2401 
2402 
2403 
2404 /*
2405  * Check whether all coefficients and variables of row are integer
2406  * - i_flag = integer bit vector
2407  * - return true if for all monomial a.x both a and x are integer
2408  */
all_integer_row(row_t * row,byte_t * i_flag)2409 static bool all_integer_row(row_t *row, byte_t *i_flag) {
2410   uint32_t i, n;
2411   int32_t x;
2412 
2413   n = row->size;
2414   for (i=0; i<n; i++) {
2415     x = row->data[i].c_idx;
2416     if (x >= 0) {
2417       if (! (tst_bit(i_flag, x) && q_is_integer(&row->data[i].coeff))) {
2418         return false;
2419       }
2420     }
2421   }
2422   return true;
2423 }
2424 
2425 
2426 /*
2427  * Eliminate a generic row
2428  * - d = markowitz data structure
2429  * - i_flag = bitvector for integer variables
2430  * - row0 = row to eliminate
2431  * - r0 = its index in the matrix
2432  * - k = index of the monomial to eliminate:
2433  *   row0->data[k] = a. x where x is the variable to eliminate
2434  * - elim = elimination matrix (or NULL)
2435  */
gauss_elim_row(matrix_t * matrix,markowitz_t * d,byte_t * i_flag,row_t * row0,uint32_t r0,uint32_t k,elim_matrix_t * elim)2436 static void gauss_elim_row(matrix_t *matrix, markowitz_t *d, byte_t *i_flag,
2437                            row_t *row0, uint32_t r0, uint32_t k,
2438                            elim_matrix_t *elim) {
2439 
2440   column_t *col;
2441   uint32_t i, n;
2442   int32_t x, r, j;
2443 
2444   assert(row0 == matrix->row[r0] && row0 != NULL && k < row0->size);
2445 
2446   x = row0->data[k].c_idx;    // variable to eliminate
2447   matrix_scale_row(row0, k);  // make coefficient of x equal to 1
2448 
2449   assert(x != const_idx);
2450 
2451   if (tst_bit(i_flag, x) && ! all_integer_row(row0, i_flag)) {
2452     /*
2453      * Can't use the row to eliminate x: just keep the row for now.
2454      * We could also try another variable in the same row?
2455      */
2456     return;
2457   }
2458 
2459   if (elim != NULL) {
2460     elim_matrix_add_row(elim, x, row0);
2461   }
2462   matrix_detach_row(matrix, row0);
2463 
2464   // eliminate x from the other rows
2465   col = matrix->column[x];
2466   n = col->size;
2467   for (i=0; i<n; i++) {
2468     r = col->data[i].r_idx;
2469     if (r >= 0) {
2470       assert(r != r0);
2471       j = col->data[i].r_ptr;
2472       matrix_submul_row(matrix, r, j, row0);
2473       markowitz_update(d, matrix, r);
2474     }
2475   }
2476 
2477   // delete column x and row r0
2478   delete_column(col);
2479   matrix->column[x] = NULL;
2480 
2481   delete_row(row0);
2482   matrix->row[r0] = NULL;
2483 }
2484 
2485 
2486 
2487 
2488 /*
2489  * Eliminate rows in the matrix
2490  * - d = markowitz data structure: must contain the rows to eliminate
2491  * - i_flag = bitvector that indicates which variables are integer
2492  * - fvars = vector to store eliminated fixed variables
2493  * - elim = elimination matrix to store other eliminated rows
2494  *   if elim is NULL, the eliminated rows are not stored anywhere.
2495  */
gaussian_elimination(matrix_t * matrix,markowitz_t * d,byte_t * i_flag,elim_matrix_t * elim,fvar_vector_t * fvars)2496 static void gaussian_elimination(matrix_t *matrix, markowitz_t *d, byte_t *i_flag,
2497                                  elim_matrix_t *elim, fvar_vector_t *fvars) {
2498   row_t *row0;
2499   int32_t r0;
2500   uint32_t x, k;
2501 
2502   for (;;) {
2503     r0 = generic_heap_get_min(&d->heap);
2504     if (r0 < 0) break;
2505 
2506     row0 = matrix->row[r0];
2507     x = d->row_rec[r0]->c_idx;
2508     k = d->row_rec[r0]->r_ptr;
2509 
2510 
2511 #if 0
2512     if (tst_bit(i_flag, x)) {
2513       printf("---> eliminating i!%"PRIu32" and row %"PRId32" (score = %"PRIu32")\n", x, r0, d->row_rec[r0]->score);
2514     } else {
2515       printf("---> eliminating z!%"PRIu32" and row %"PRId32" (score = %"PRIu32")\n", x, r0, d->row_rec[r0]->score);
2516     }
2517 #endif
2518 
2519     /*
2520      * row0 = row[r0] = row to eliminate
2521      * x = variable to eliminate
2522      * k = index of monomial a.x in row0
2523      */
2524     markowitz_remove_record(d, r0);
2525 
2526     switch (row0->nelems) {
2527     case 0: // should never happen
2528       abort();
2529     case 1:
2530       matrix_detach_row(matrix, row0); // must be done before elim_zero_var
2531       delete_row(row0);
2532       matrix->row[r0] = NULL;
2533       fvar_vector_add0(fvars, x); // record the assignment x := 0
2534       matrix_eliminate_zero_variable(matrix, d, x); // remove x
2535       break;
2536     case 2:
2537       gauss_elim_simple_row(matrix, d, i_flag, row0, r0, k, elim, fvars);
2538       break;
2539     default:
2540       gauss_elim_row(matrix, d, i_flag, row0, r0, k, elim);
2541       break;
2542     }
2543 
2544   }
2545 }
2546 
2547 
2548 /*
2549  * Matrix simplification:
2550  * - mark the rows and variables to eliminate then apply Gaussian elimination
2551  * - pivoting steps are applied in the order defined by the Markowitz heuristic
2552  *
2553  * Parameters:
2554  * - matrix = input matrix
2555  * - elim_candidates = array of variables that may be eliminated
2556  *   n = size of that array. There must not be duplicates in the array.
2557  * - i_flag = bitvector that indicates which variables are integer:
2558  *   i_flag[x] = 1 means x is an integer variable,
2559  *   i_flag[x] = 0 means x is not an integer variable
2560  * - elim = elimination matrix where the eliminated rows will be stored
2561  *   (if elim is NULL nothing is stored)
2562  * - fvars = vectors to record the eliminated fixed variables
2563  *
2564  * The result is stored in matrix, elim, and fvars:
2565  * - matrix = simplified matrix
2566  * - fvars = variable assignments of the form x == b where x is a variable id and
2567  *   b is a rational constant (the assignments result from the elimination of
2568  *   singleton or simple rows)
2569  * - elim (if non-NULL) = other eliminated rows/triangular matrix
2570  *
2571  * NOTE: the variable assignments in fvars may be inconsistent
2572  * - there can be two types of inconsistencies:
2573  *   (x == 0) where x = const_idx = 1 if a row a == 0 is generated with a!=0
2574  *   (x == b) where x is an integer variable and b is not an integer
2575  * - the caller must check for this
2576  */
simplify_matrix(matrix_t * matrix,int32_t * elim_candidates,uint32_t n,byte_t * i_flag,elim_matrix_t * elim,fvar_vector_t * fvars)2577 void simplify_matrix(matrix_t *matrix, int32_t *elim_candidates, uint32_t n, byte_t *i_flag,
2578                      elim_matrix_t *elim, fvar_vector_t *fvars) {
2579   markowitz_t d;
2580 
2581   init_markowitz(&d, matrix->nrows, matrix->ncolumns);
2582   markowitz_init_columns(&d, elim_candidates, n);
2583   markowitz_init_rows(&d, matrix);
2584 
2585   gaussian_elimination(matrix, &d, i_flag, elim, fvars);
2586   compact_matrix(matrix);
2587 
2588   delete_markowitz(&d);
2589 }
2590 
2591 
2592 
2593 
2594 
2595 
2596 
2597 /***********************************
2598  *  INITIAL TABLEAU CONSTRUCTION   *
2599  **********************************/
2600 
2601 /*
2602  * Two heuristics can be used to compute basic variables
2603  * - simple heuristic: scan rows from 0 to n-1, pick the best variable in that row
2604  * - Markowitz heuristic: scan the rows in the order defined by their score
2605  *   in the Markowitz data structure
2606  */
2607 
2608 
2609 /*
2610  * Remove a singleton row row0 during tableau construction
2611  * - if d is non-null, update the Markowitz records
2612  * - the row0 must be matrix->row[r0]
2613  * - the eliminated variable is stored in fvars
2614  *
2615  * If row0 is a constant row then the assignment const_idx = 0 is added to fvars.
2616  * This is an invalid assignment and there's no solution to the equations. We add
2617  * the equation anyway so that the caller can check for feasibility by scanning
2618  * the assignments in fvars.
2619  */
tableau_remove_singleton_row(matrix_t * matrix,markowitz_t * d,row_t * row0,uint32_t r0,fvar_vector_t * fvars)2620 static void tableau_remove_singleton_row(matrix_t *matrix, markowitz_t *d,
2621                                          row_t *row0, uint32_t r0, fvar_vector_t *fvars) {
2622   uint32_t i;
2623   int32_t x;
2624 
2625   assert(matrix->row[r0] == row0 && row0->nelems == 1 && row0->size > 0);
2626 
2627   // find the variable in row r0
2628   i = 0;
2629   x = row0->data[i].c_idx;
2630   while (x < 0) {
2631     i ++;
2632     assert(i < row0->size);
2633     x = row0->data[i].c_idx;
2634   }
2635 
2636   assert(0 <= x && x < matrix->ncolumns && matrix->column[x] != NULL);
2637 
2638   // store x := 0 in fvars
2639   fvar_vector_add0(fvars, x);
2640 
2641   // remove row0 from the column vectors and replace x by 0 in other rows
2642   matrix_detach_row(matrix, row0);
2643   matrix_eliminate_zero_variable(matrix, d, x);
2644 
2645   // delete the row
2646   delete_row(row0);
2647   matrix->row[r0] = NULL;
2648 }
2649 
2650 
2651 
2652 
2653 /*
2654  * Eliminate row r0 by replacing x by the constant in element e
2655  * - if d != NULL, update the Markowitz records of all rows modified
2656  * - row0 must be equal to matrix->row[r0]
2657  * - x must have coefficient 1 in the row
2658  * - e->c_idx must be const_idx
2659  * NOTE: e is an element inside row0
2660  *
2661  * The assignment x := - e is saved in fvars even if it's inconsistent.
2662  * This may happen if x is an integer variable and e is not an integer
2663  * constant. The assignments must be checked for feasibility by the callers.
2664  */
tableau_remove_simple_row(matrix_t * matrix,markowitz_t * d,row_t * row0,uint32_t r0,int32_t x,row_elem_t * e,fvar_vector_t * fvars)2665 static void tableau_remove_simple_row(matrix_t *matrix, markowitz_t *d,
2666                                       row_t *row0, uint32_t r0, int32_t x, row_elem_t *e, fvar_vector_t *fvars) {
2667   assert(0 <= x && x < matrix->ncolumns && matrix->column[x] != NULL && matrix->row[r0] == row0 && e->c_idx == const_idx);
2668 
2669   // save the assignment x := - e->coeff
2670   fvar_vector_add_neg(fvars, x, &e->coeff);
2671 
2672   // apply the substitution x := - e  to all rows where x occurs (except row0)
2673   matrix_detach_row(matrix, row0);
2674   matrix_substitute_variable(matrix, d, x, e);
2675 
2676   // remove row0
2677   delete_row(row0);
2678   matrix->row[r0] = NULL;
2679 
2680 }
2681 
2682 
2683 /*
2684  * Check whether a simple row row0 can be eliminated
2685  * - if so, add an assignment x := constant to fvars
2686  * - otherwise, select a basic variable for that row
2687  */
tableau_process_simple_row(matrix_t * matrix,row_t * row0,uint32_t r0,fvar_vector_t * fvars)2688 static void tableau_process_simple_row(matrix_t *matrix, row_t *row0, uint32_t r0, fvar_vector_t *fvars) {
2689   uint32_t i, j;
2690   int32_t x, y;
2691 
2692   assert(row0->nelems == 2 && row0 == matrix->row[r0] && row0->size >= 2);
2693 
2694   if (row0->size == 2) {
2695     i = 0; x = row0->data[0].c_idx;
2696     j = 1; y = row0->data[1].c_idx;
2697   } else {
2698     // find the two row elements
2699     i = 0;
2700     x = row0->data[i].c_idx;
2701     while (x < 0) {
2702       i ++;
2703       assert(i < row0->size);
2704       x = row0->data[i].c_idx;
2705     }
2706     j = i;
2707     do {
2708       j ++;
2709       assert(j < row0->size);
2710       y = row0->data[j].c_idx;
2711     } while (y < 0);
2712   }
2713 
2714   assert(x >= 0 && y >= 0 && row0->data[i].c_idx == x && row0->data[j].c_idx == y);
2715 
2716   if (x == const_idx) {
2717     // substitute y by the constant in row->data[i]
2718     matrix_scale_row(row0, j);  // make coefficient of y == 1
2719     tableau_remove_simple_row(matrix, NULL, row0, r0, y, row0->data + i, fvars);
2720 
2721   } else if (y == const_idx) {
2722     // substitute x by the constant in row->data[j]
2723     matrix_scale_row(row0, i);  // make coefficient of x == 1
2724     tableau_remove_simple_row(matrix, NULL, row0, r0, x, row0->data + j, fvars);
2725 
2726   } else if (matrix->column[y]->nelems < matrix->column[x]->nelems) {
2727     // make y basic in row r0
2728     matrix_pivot(matrix, r0, j);
2729     assert(matrix->base_var[r0] == y);
2730 
2731   } else {
2732     // make x basic in row r0
2733     matrix_pivot(matrix, r0, i);
2734     assert(matrix->base_var[r0] == x);
2735   }
2736 }
2737 
2738 
2739 
2740 /*
2741  * Find a basic variable in row r0
2742  * - matrix->row[r0] must be equal to row0
2743  * - row0 has at least 3 elements
2744  */
tableau_process_row(matrix_t * matrix,row_t * row0,uint32_t r0)2745 static void tableau_process_row(matrix_t *matrix, row_t *row0, uint32_t r0) {
2746   uint32_t i, n, c;
2747   int32_t x;
2748   uint32_t best_i, best_c;
2749 #ifndef NDEBUG
2750   int32_t best_x;
2751 #endif
2752 
2753   assert(matrix->row[r0] == row0);
2754 
2755 #ifndef NDEBUG
2756   best_x = -1;
2757 #endif
2758   best_i = 0;
2759   best_c = UINT32_MAX;
2760 
2761   // find the lower-cost variable to pivot
2762   n = row0->size;
2763   for (i=0; i<n; i++) {
2764     x = row0->data[i].c_idx;;
2765     if (x >= 0 && x != const_idx) {
2766       c = matrix->column[x]->nelems;
2767       if (c < best_c) {
2768         best_c = c;
2769         best_i = i;
2770 #ifndef NDEBUG
2771         best_x = x;
2772 #endif
2773       }
2774     }
2775   }
2776 
2777   // make best_x the basic variable for r0
2778   assert(best_x >= 0);
2779   matrix_pivot(matrix, r0, best_i);
2780   assert(matrix->base_var[r0] == best_x);
2781 }
2782 
2783 
2784 
2785 /*
2786  * Simple tableau construction:
2787  * - scan all rows in index order
2788  * - if a row is of the form a.x == 0 or a.x + b == 0,
2789  *   record the corresponding assignment (x == 0 or x == -b/a) in fvars
2790  *   and remove the row
2791  * - otherwise, pick the variable with smallest column count and make it basic variable
2792  */
simple_tableau_construction(matrix_t * matrix,fvar_vector_t * fvars)2793 void simple_tableau_construction(matrix_t *matrix, fvar_vector_t *fvars) {
2794   uint32_t i, n;
2795   row_t *row;
2796   bool need_compact;
2797 
2798   need_compact = false;
2799   n = matrix->nrows;
2800   for (i=0; i<n; i++) {
2801     row = matrix->row[i];
2802     switch (row->nelems) {
2803     case 0:
2804       delete_row(row);
2805       matrix->row[i] = NULL;
2806       need_compact = true;
2807       break;
2808     case 1:
2809       tableau_remove_singleton_row(matrix, NULL, row, i, fvars);
2810       need_compact = true;
2811       break;
2812     case 2:
2813       tableau_process_simple_row(matrix, row, i, fvars);
2814       need_compact |= (matrix->row[i] == NULL);
2815       break;
2816     default:
2817       tableau_process_row(matrix, row, i);
2818       break;
2819     }
2820   }
2821 
2822   if (need_compact) {
2823     compact_matrix(matrix);
2824   }
2825 }
2826 
2827 
2828 
2829 
2830 
2831 /*
2832  * Check whether simple row row0 can be eliminated
2833  * - if so add the assignment x := constant to fvars
2834  * - otherwise, make variable x basic in that row
2835  * - k = index of monomial where x occurs in row0
2836  */
markowitz_tableau_process_simple_row(matrix_t * matrix,markowitz_t * d,row_t * row0,uint32_t r0,uint32_t k,fvar_vector_t * fvars)2837 static void markowitz_tableau_process_simple_row(matrix_t *matrix, markowitz_t *d,
2838                                                  row_t *row0, uint32_t r0, uint32_t k, fvar_vector_t *fvars) {
2839   uint32_t i;
2840   int32_t x, y;
2841 
2842   assert(row0 == matrix->row[r0] && row0 != NULL && row0->nelems == 2 && k < row0->size);
2843 
2844   x = row0->data[k].c_idx;   // variable to eliminate
2845 
2846   assert(x != const_idx);
2847 
2848   // find the other monomial in row0
2849   i = 0;
2850   for (;;) {
2851     assert(i < row0->size);
2852     y = row0->data[i].c_idx;
2853     if (x != y && y >= 0) break;
2854     i ++;
2855   }
2856 
2857   if (y == const_idx) {
2858     // eliminate x
2859     matrix_scale_row(row0, k); // rewrite row0 as x + b.y == 0
2860     tableau_remove_simple_row(matrix, d, row0, r0, x, row0->data + i, fvars);
2861   } else {
2862     // make x basic in row r0
2863     matrix_pivot_and_update(matrix, d, r0, k);
2864     assert(matrix->base_var[r0] == x);
2865   }
2866 }
2867 
2868 
2869 
2870 
2871 /*
2872  * Reprocess row row0 when it gets reduced to a 2-monomial row
2873  * - x = a variable in that row
2874  * - if row0 is of the form x + constant == 0 then eliminate row0
2875  */
markowitz_tableau_revisit_simple_row(matrix_t * matrix,row_t * row0,uint32_t r0,int32_t x,fvar_vector_t * fvars)2876 static void markowitz_tableau_revisit_simple_row(matrix_t *matrix, row_t *row0, uint32_t r0, int32_t x, fvar_vector_t *fvars) {
2877   uint32_t i;
2878   int32_t y;
2879 
2880   assert(row0 == matrix->row[r0] && row0 != NULL && row0->nelems == 2 && matrix->base_var[r0] >= 0 && x != const_idx);
2881 
2882   // find the other monomial in row0
2883   i = 0;
2884   for (;;) {
2885     assert(i < row0->size);
2886     y = row0->data[i].c_idx;
2887     if (x != y && y >= 0) break;
2888     i ++;
2889   }
2890 
2891   if (y == const_idx) {
2892     /*
2893      * x must be the basic var so the row is of the form x + a == 0
2894      * where a = rational coeff in data[i].
2895      * Since x is basic, it occurs only in r0 so there's no substitution to propagate
2896      */
2897     assert(matrix->base_var[r0] == x && matrix->column[x] != NULL &&
2898            matrix->column[x]->nelems == 1);
2899 
2900     fvar_vector_add_neg(fvars, x, &row0->data[i].coeff);
2901 
2902     free_column_elem(matrix->column[const_idx], row0->data[i].c_ptr);
2903     delete_row(row0);
2904     matrix->row[r0] = NULL;
2905     delete_column(matrix->column[x]);
2906     matrix->column[x] = NULL;
2907     matrix->base_row[x] = -1;
2908   }
2909 
2910 }
2911 
2912 
2913 
2914 
2915 /*
2916  * Tableau construction using the Markowitz heuristic
2917  */
markowitz_tableau_construction(matrix_t * matrix,fvar_vector_t * fvars)2918 void markowitz_tableau_construction(matrix_t *matrix, fvar_vector_t *fvars) {
2919   markowitz_t d;
2920   int32_t r0, x;
2921   row_t *row0;
2922   uint32_t k;
2923 
2924   init_markowitz(&d, matrix->nrows, matrix->ncolumns);
2925   markowitz_init_all_columns(&d);
2926   markowitz_init_rows(&d, matrix);
2927 
2928   for (;;) {
2929     r0 = generic_heap_get_min(&d.heap);
2930     if (r0 < 0) break;
2931 
2932     /*
2933      * See notes in markowitz_update: r0 may be visited several
2934      * times.
2935      */
2936     row0 = matrix->row[r0];
2937     x = d.row_rec[r0]->c_idx;
2938     k = d.row_rec[r0]->r_ptr;
2939     markowitz_remove_record(&d, r0);
2940 
2941     if (matrix->base_var[r0] < 0) {
2942       /*
2943        * First visit of row r0
2944        * Make x basic variable in row r0
2945        * - k = index of the monomial a.x in row0
2946        */
2947       switch (row0->nelems) {
2948       case 0:
2949         abort();
2950       case 1:
2951         tableau_remove_singleton_row(matrix, &d, row0, r0, fvars);
2952         break;
2953       case 2:
2954         markowitz_tableau_process_simple_row(matrix, &d, row0, r0, k, fvars);
2955         break;
2956       default:
2957         matrix_pivot_and_update(matrix, &d, r0, k);
2958         assert(matrix->base_var[r0] == x);
2959         break;
2960       }
2961 
2962     } else {
2963       /*
2964        * r0 already has a basic variable,
2965        * check whether it can be eliminated
2966        */
2967       if (row0->nelems == 1) {
2968         assert(matrix->base_var[r0] == x && matrix->column[x] != NULL &&
2969                matrix->column[x]->nelems == 1);
2970 
2971         // store x := 0 to fvars then delete the row and column
2972         fvar_vector_add0(fvars, x);
2973         delete_row(row0);
2974         matrix->row[r0] = NULL;
2975         delete_column(matrix->column[x]);
2976         matrix->column[x] = NULL;
2977 
2978         // x is no longer basic
2979         matrix->base_row[x] = -1;
2980 
2981       } else if (row0->nelems == 2) {
2982         markowitz_tableau_revisit_simple_row(matrix, row0, r0, x, fvars);
2983       }
2984 
2985     }
2986   }
2987 
2988   compact_matrix(matrix);
2989   delete_markowitz(&d);
2990 }
2991 
2992 
2993 
2994 
2995 
2996 
2997 
2998 #ifndef NDEBUG
2999 
3000 #include <stdio.h>
3001 #include <inttypes.h>
3002 
3003 
3004 /*
3005  * DEBUGGING SUPPORT
3006  */
3007 
3008 /*
3009  * Index of variable x in row r
3010  * - return -1 if x does not occur in r
3011  */
get_var_in_row(row_t * row,int32_t x)3012 static int32_t get_var_in_row(row_t *row, int32_t x) {
3013   uint32_t i, n;
3014 
3015   n = row->size;
3016   for (i=0; i<n; i++) {
3017     if (row->data[i].c_idx == x) return i;
3018   }
3019   return -1;
3020 }
3021 
3022 
3023 /*
3024  * Consistency properties for base_var:
3025  * - base_row[base_var[r]] == r for all rows
3026  * - base_var[r] != const_idx
3027  * - base_var[r] < ncolumns
3028  * - base_var[r] occurs in row r with coefficient 1
3029  */
good_base_var(matrix_t * matrix)3030 static bool good_base_var(matrix_t *matrix) {
3031   uint32_t i, n;
3032   int32_t x, k;
3033   row_t *row;
3034 
3035   n = matrix->nrows;
3036   for (i=0; i<n; i++) {
3037     x = matrix->base_var[i];
3038     if (x >= 0) {
3039       if (x == const_idx || x >= matrix->ncolumns || matrix->base_row[x] != i) {
3040         return false;
3041       }
3042       row = matrix->row[i];
3043       k = get_var_in_row(row, x);
3044       if (k < 0 || ! q_is_one(&row->data[k].coeff)) {
3045         return false;
3046       }
3047     }
3048   }
3049   return true;
3050 }
3051 
3052 
3053 /*
3054  * Consistency properties for base_row
3055  * - base_var[base_row[x]] == x for all basic variables
3056  * - base_var[r] < nrows
3057  */
good_base_row(matrix_t * matrix)3058 static bool good_base_row(matrix_t *matrix) {
3059   uint32_t i, n;
3060   int32_t r;
3061 
3062   n = matrix->ncolumns;
3063   for (i=0; i<n; i++) {
3064     r = matrix->base_row[i];
3065     if (r >= 0) {
3066       if (r >= matrix->nrows || matrix->base_var[r] != i) {
3067         return false;
3068       }
3069     }
3070   }
3071 
3072   return true;
3073 }
3074 
3075 
3076 
3077 /*
3078  * Consistency property for a row r
3079  * - if row->data[i] = (x, k, a) then
3080  *    a /= 0 and 0 <= x < ncolumns and column[x]->data[k] = (x, i)
3081  * - nelems == number of non-zero coefficients
3082  */
good_row(matrix_t * matrix,uint32_t r)3083 static bool good_row(matrix_t *matrix, uint32_t r) {
3084   row_t *row;
3085   col_elem_t *e;
3086   uint32_t j, i, n;
3087   int32_t x, k;
3088 
3089   row = matrix->row[r];
3090   if (row == NULL) return false;
3091 
3092   n = row->size;
3093   j = 0;
3094   for (i=0; i<n; i++) {
3095     x = row->data[i].c_idx;
3096     if (x >= 0) {
3097       if (x >= matrix->ncolumns || q_is_zero(&row->data[i].coeff)) {
3098         return false;
3099       }
3100       k = row->data[i].c_ptr;
3101       if (k < 0 || k >= matrix->column[x]->size) {
3102         return false;
3103       }
3104       e = column_elem(matrix, x, k);
3105       if (e->r_idx != r || e->r_ptr != i) return false;
3106       j ++;
3107     }
3108   }
3109 
3110   if (j != row->nelems) return false;
3111 
3112   return true;
3113 }
3114 
3115 
3116 /*
3117  * Consistency properties for a column c
3118  * - if column->data[i] = (r, k) the row[r]->data[k] = (c, i, ...)
3119  * - nelems = number of elements in column c
3120  */
good_column(matrix_t * matrix,uint32_t c)3121 static bool good_column(matrix_t *matrix, uint32_t c) {
3122   column_t *column;
3123   row_elem_t *e;
3124   uint32_t j, i, n;
3125   int32_t r, k;
3126 
3127   column = matrix->column[c];
3128   if (column != NULL) {
3129     n = column->size;
3130     j = 0;
3131     for (i=0; i<n; i++) {
3132       r = column->data[i].r_idx;
3133       if (r >= 0) {
3134         if (r >= matrix->nrows) return false;
3135         k = column->data[i].r_ptr;
3136         if (k < 0 || k >= matrix->row[r]->size) {
3137           return false;
3138         }
3139         e = row_elem(matrix, r, k);
3140         if (e->c_idx != c || e->c_ptr != i) return false;
3141         j ++;
3142       }
3143     }
3144 
3145     if (j != column->nelems) return false;
3146   }
3147 
3148   return true;
3149 }
3150 
3151 
3152 /*
3153  * Run all consistency checks on matrix
3154  */
good_matrix(matrix_t * matrix)3155 bool good_matrix(matrix_t *matrix) {
3156   uint32_t i, n;
3157 
3158   if (good_base_var(matrix) && good_base_row(matrix)) {
3159     n = matrix->nrows;
3160     for (i=0; i<n; i++) {
3161       if (! good_row(matrix, i)) {
3162         printf("---> Bad row[%"PRIu32"]\n", i);
3163         fflush(stdout);
3164         return false;
3165       }
3166     }
3167 
3168     n = matrix->ncolumns;
3169     for (i=0; i<n; i++) {
3170       if (! good_column(matrix, i)) {
3171         printf("---> Bad column[%"PRIu32"]\n", i);
3172         fflush(stdout);
3173         return false;
3174       }
3175     }
3176 
3177     return true;
3178 
3179   } else {
3180     return false;
3181   }
3182 }
3183 
3184 
3185 #endif
3186