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