1 /*
2 * Normaliz
3 * Copyright (C) 2007-2019 Winfried Bruns, Bogdan Ichim, Christof Soeger
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * As an exception, when this program is distributed through (i) the App Store
18 * by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play
19 * by Google Inc., then that store may impose any digital rights management,
20 * device limits and/or redistribution restrictions that are required by its
21 * terms of service.
22 */
23
24 //---------------------------------------------------------------------------
25
26 #include <fstream>
27 #include <set>
28 #include <algorithm>
29 #include <cmath>
30 #include <iomanip>
31
32 #include "libnormaliz/matrix.h"
33 #include "libnormaliz/cone.h"
34 #include "libnormaliz/sublattice_representation.h"
35 #include "libnormaliz/project_and_lift.h"
36 #include "libnormaliz/dynamic_bitset.h"
37
38 #ifdef NMZ_FLINT
39 #include "flint/flint.h"
40 #include "flint/fmpz.h"
41 #include "flint/fmpz_mat.h"
42 #endif
43
44 //---------------------------------------------------------------------------
45
46 namespace libnormaliz {
47 using namespace std;
48
49 //---------------------------------------------------------------------------
50 // Public
51 //---------------------------------------------------------------------------
52
53 // the templated version is only usable where numbers of larger absolute
54 // value have longer decomal representations
55 // slight efficiency advantage compared to specialized version below
56 template <typename Integer>
maximal_decimal_length_columnwise() const57 vector<size_t> Matrix<Integer>::maximal_decimal_length_columnwise() const {
58 size_t i, j = 0;
59 vector<size_t> maxim(nc, 0);
60 vector<Integer> pos_max(nc, 0), neg_max(nc, 0);
61 for (i = 0; i < nr; i++) {
62 for (j = 0; j < nc; j++) {
63 // maxim[j]=max(maxim[j],decimal_length(elem[i][j]));
64 if (elem[i][j] < 0) {
65 if (elem[i][j] < neg_max[j])
66 neg_max[j] = elem[i][j];
67 continue;
68 }
69 if (elem[i][j] > pos_max[j])
70 pos_max[j] = elem[i][j];
71 }
72 }
73 for (size_t j = 0; j < nc; ++j)
74 maxim[j] = max(decimal_length(neg_max[j]), decimal_length(pos_max[j]));
75 return maxim;
76 }
77
78 //---------------------------------------------------------------------------
79
80 #ifdef ENFNORMALIZ
81 template <>
maximal_decimal_length_columnwise() const82 vector<size_t> Matrix<renf_elem_class>::maximal_decimal_length_columnwise() const {
83 size_t i, j = 0;
84 vector<size_t> maxim(nc, 0);
85 for (i = 0; i < nr; i++) {
86 for (j = 0; j < nc; j++) {
87 maxim[j] = max(maxim[j], decimal_length(elem[i][j]));
88 }
89 }
90 return maxim;
91 }
92 #endif
93
94 template <typename Integer>
Matrix()95 Matrix<Integer>::Matrix() {
96 nr = 0;
97 nc = 0;
98 }
99
100 //---------------------------------------------------------------------------
101
102 template <typename Integer>
Matrix(size_t dim)103 Matrix<Integer>::Matrix(size_t dim) {
104 nr = dim;
105 nc = dim;
106 elem = vector<vector<Integer> >(dim, vector<Integer>(dim));
107 for (size_t i = 0; i < dim; i++) {
108 elem[i][i] = 1;
109 }
110 }
111
112 //---------------------------------------------------------------------------
113
114 template <typename Integer>
Matrix(size_t row,size_t col)115 Matrix<Integer>::Matrix(size_t row, size_t col) {
116 nr = row;
117 nc = col;
118 elem = vector<vector<Integer> >(row, vector<Integer>(col));
119 }
120
121 //---------------------------------------------------------------------------
122
123 template <typename Integer>
Matrix(size_t row,size_t col,Integer value)124 Matrix<Integer>::Matrix(size_t row, size_t col, Integer value) {
125 nr = row;
126 nc = col;
127 elem = vector<vector<Integer> >(row, vector<Integer>(col, value));
128 }
129
130 //---------------------------------------------------------------------------
131
132 template <typename Integer>
Matrix(const vector<vector<Integer>> & new_elem)133 Matrix<Integer>::Matrix(const vector<vector<Integer> >& new_elem) {
134 nr = new_elem.size();
135 if (nr > 0) {
136 nc = new_elem[0].size();
137 elem = new_elem;
138 // check if all rows have the same length
139 for (size_t i = 1; i < nr; i++) {
140 if (elem[i].size() != nc) {
141 throw BadInputException("Inconsistent lengths of rows in matrix!");
142 }
143 }
144 }
145 else {
146 nc = 0;
147 }
148 }
149
150 //---------------------------------------------------------------------------
151
152 template <typename Integer>
Matrix(const list<vector<Integer>> & new_elem)153 Matrix<Integer>::Matrix(const list<vector<Integer> >& new_elem) {
154 nr = new_elem.size();
155 elem = vector<vector<Integer> >(nr);
156 nc = 0;
157 size_t i = 0;
158 for (const auto& it : new_elem) {
159 if (i == 0) {
160 nc = it.size();
161 }
162 else {
163 if (it.size() != nc) {
164 throw BadInputException("Inconsistent lengths of rows in matrix!");
165 }
166 }
167 elem[i++] = it;
168 }
169 }
170
171 //---------------------------------------------------------------------------
172
173 template <typename Integer>
Matrix(const vector<Integer> & row)174 Matrix<Integer>::Matrix(const vector<Integer>& row) {
175 nr = 1;
176 nc = row.size();
177 elem.push_back(row);
178 }
179
180 //---------------------------------------------------------------------------
181 /*
182 template<typename Integer>
183 void Matrix<Integer>::write(istream& in){
184 size_t i,j;
185 for(i=0; i<nr; i++){
186 for(j=0; j<nc; j++) {
187 in >> elem[i][j];
188 }
189 }
190 }
191 */
192 //---------------------------------------------------------------------------
193
194 template <typename Integer>
write_column(size_t col,const vector<Integer> & data)195 void Matrix<Integer>::write_column(size_t col, const vector<Integer>& data) {
196 assert(col >= 0);
197 assert(col < nc);
198 assert(nr == data.size());
199
200 for (size_t i = 0; i < nr; i++) {
201 elem[i][col] = data[i];
202 }
203 }
204
205 //---------------------------------------------------------------------------
206
207 template <typename Integer>
print(const string & name,const string & suffix) const208 void Matrix<Integer>::print(const string& name, const string& suffix) const {
209 string file_name = name + "." + suffix;
210 const char* file = file_name.c_str();
211 ofstream out(file);
212 print(out);
213 out.close();
214 }
215
216 //---------------------------------------------------------------------------
217
218 /*
219 template <typename Integer>
220 void Matrix<Integer>::print_append(const string& name, const string& suffix) const {
221 string file_name = name + "." + suffix;
222 const char* file = file_name.c_str();
223 ofstream out(file, ios_base::app);
224 print(out);
225 out.close();
226 }
227 */
228
229 //---------------------------------------------------------------------------
230
231 template <typename Integer>
print(ostream & out,bool with_format) const232 void Matrix<Integer>::print(ostream& out, bool with_format) const {
233 size_t i, j;
234 if (with_format)
235 out << nr << endl << nc << endl;
236 for (i = 0; i < nr; i++) {
237 for (j = 0; j < nc; j++) {
238 out << elem[i][j] << " ";
239 }
240 out << endl;
241 }
242 }
243
244 //---------------------------------------------------------------------------
245
246 template <typename Integer>
pretty_print(ostream & out,bool with_row_nr,bool count_from_one) const247 void Matrix<Integer>::pretty_print(ostream& out, bool with_row_nr, bool count_from_one) const {
248 if (nr > 1000000 && !with_row_nr) {
249 print(out, false);
250 return;
251 }
252 size_t i, j;
253 vector<size_t> max_length = maximal_decimal_length_columnwise();
254 size_t max_index_length = decimal_length(nr);
255 if(count_from_one)
256 max_index_length = decimal_length(nr+1);
257 for (i = 0; i < nr; i++) {
258 if (with_row_nr) {
259 size_t j = i;
260 if(count_from_one)
261 j++;
262 out << std::setw(max_index_length + 1) << std::setprecision(6) << j << ": ";
263 }
264 for (j = 0; j < nc; j++) {
265 out << std::setw(max_length[j] + 1) << std::setprecision(6) << elem[i][j];
266 }
267 out << endl;
268 }
269 }
270
271 #ifdef ENFNORMALIZ
272 template <>
pretty_print(ostream & out,bool with_row_nr,bool count_from_one) const273 void Matrix<renf_elem_class>::pretty_print(ostream& out, bool with_row_nr, bool count_from_one) const {
274 if (nr > 1000000 && !with_row_nr) {
275 print(out);
276 return;
277 }
278 size_t i, j, k;
279 vector<size_t> max_length = maximal_decimal_length_columnwise();
280 size_t max_index_length = decimal_length(nr);
281 if(count_from_one)
282 max_index_length = decimal_length(nr+1);
283 for (i = 0; i < nr; i++) {
284 if (with_row_nr) {
285 size_t j = i;
286 if(count_from_one)
287 j++;
288 for (k = 0; k <= max_index_length - decimal_length(j); k++) {
289 out << " ";
290 }
291 out << j << ": ";
292 }
293 for (j = 0; j < nc; j++) {
294 ostringstream to_print;
295 to_print << elem[i][j];
296 for (k = 0; k <= max_length[j] - to_print.str().size(); k++) {
297 out << " ";
298 }
299 out << to_print.str();
300 }
301 out << endl;
302 }
303 }
304 #endif
305
306 //---------------------------------------------------------------------------
307
308 template <>
pretty_print(ostream & out,bool with_row_nr,bool count_from_one) const309 void Matrix<nmz_float>::pretty_print(ostream& out, bool with_row_nr, bool count_from_one) const {
310 for (size_t i = 0; i < nr; ++i) {
311 if (with_row_nr){
312 size_t j = i;
313 if(count_from_one)
314 j++;
315 out << std::setw(7) << j << ": ";
316 }
317 for (size_t j = 0; j < nc; ++j) {
318 out << std::setw(10) << elem[i][j] << " ";
319 }
320 out << endl;
321 }
322 }
323 //---------------------------------------------------------------------------
324
325 template <typename Integer>
nr_of_rows() const326 size_t Matrix<Integer>::nr_of_rows() const {
327 return nr;
328 }
329
330 //---------------------------------------------------------------------------
331
332 template <typename Integer>
nr_of_columns() const333 size_t Matrix<Integer>::nr_of_columns() const {
334 return nc;
335 }
336
337 //---------------------------------------------------
338
339 template <typename Integer>
Shrink_nr_rows(size_t new_nr_rows)340 void Matrix<Integer>::Shrink_nr_rows(size_t new_nr_rows) {
341 if (new_nr_rows >= nr)
342 return;
343 nr = new_nr_rows;
344 elem.resize(nr);
345 }
346
347 //---------------------------------------------------------------------------
348
349 template <typename Integer>
set_nr_of_columns(size_t c)350 void Matrix<Integer>::set_nr_of_columns(size_t c) {
351 nc = c;
352 }
353
354 //---------------------------------------------------------------------------
355
356 template <typename Integer>
check_projection(vector<key_t> & projection_key)357 bool Matrix<Integer>::check_projection(vector<key_t>& projection_key) {
358 // coordinate proection_key[i] is mapped to coordinate i
359 // we do not check whether the matrix has full rank
360
361 /*cout << "----" << endl;
362 pretty_print(cout);
363 cout << "****" << endl;*/
364
365 vector<key_t> tentative_key;
366 for (size_t j = 0; j < nc; ++j) {
367 size_t i = 0;
368 for (; i < nr; ++i) {
369 if (elem[i][j] != 0) {
370 if (elem[i][j] == 1)
371 break;
372 else {
373 return false;
374 }
375 }
376 }
377 if (i == nr) { // column is zero
378 return false;
379 }
380 tentative_key.push_back(i);
381 i++;
382 for (; i < nr; i++) {
383 if (elem[i][j] != 0) {
384 return false;
385 }
386 }
387 }
388
389 projection_key = tentative_key;
390 // cout << "~~~~~~~~~ " << projection_key;
391 return true;
392 }
393
394 //---------------------------------------------------------------------------
395
396 template <typename Integer>
select_coordinates(const vector<key_t> & projection_key) const397 Matrix<Integer> Matrix<Integer>::select_coordinates(const vector<key_t>& projection_key) const {
398 Matrix<Integer> N(nr, projection_key.size());
399 for (size_t i = 0; i < nr; ++i)
400 N[i] = v_select_coordinates(elem[i], projection_key);
401 return N;
402 }
403
404 //---------------------------------------------------------------------------
405
406 template <typename Integer>
insert_coordinates(const vector<key_t> & projection_key,const size_t nr_cols) const407 Matrix<Integer> Matrix<Integer>::insert_coordinates(const vector<key_t>& projection_key, const size_t nr_cols) const {
408 Matrix<Integer> N(nr, nr_cols);
409 for (size_t i = 0; i < nr; ++i)
410 N[i] = v_insert_coordinates(elem[i], projection_key, nr_cols);
411 return N;
412 }
413
414 //---------------------------------------------------------------------------
415
416 /*
417 template <typename Integer>
418 void Matrix<Integer>::random(int mod) {
419 size_t i, j;
420 int k;
421 for (i = 0; i < nr; i++) {
422 for (j = 0; j < nc; j++) {
423 k = rand();
424 elem[i][j] = k % mod;
425 }
426 }
427 }
428 */
429 //---------------------------------------------------------------------------
430
431 template <typename Integer>
set_zero()432 void Matrix<Integer>::set_zero() {
433 size_t i, j;
434 for (i = 0; i < nr; i++) {
435 for (j = 0; j < nc; j++) {
436 elem[i][j] = 0;
437 }
438 }
439 }
440
441 //---------------------------------------------------------------------------
442
443 template <typename Integer>
select_submatrix(const Matrix<Integer> & mother,const vector<key_t> & rows)444 void Matrix<Integer>::select_submatrix(const Matrix<Integer>& mother, const vector<key_t>& rows) {
445 assert(nr >= rows.size());
446 assert(nc >= mother.nc);
447
448 size_t size = rows.size(), j;
449 for (size_t i = 0; i < size; i++) {
450 j = rows[i];
451 for (size_t k = 0; k < mother.nc; ++k)
452 elem[i][k] = mother[j][k];
453 }
454 }
455
456 //---------------------------------------------------------------------------
457
458 template <typename Integer>
select_submatrix_trans(const Matrix<Integer> & mother,const vector<key_t> & rows)459 void Matrix<Integer>::select_submatrix_trans(const Matrix<Integer>& mother, const vector<key_t>& rows) {
460 assert(nc >= rows.size());
461 assert(nr >= mother.nc);
462
463 size_t size = rows.size(), j;
464 for (size_t i = 0; i < size; i++) {
465 j = rows[i];
466 for (size_t k = 0; k < mother.nc; ++k)
467 elem[k][i] = mother[j][k];
468 }
469 }
470
471 //---------------------------------------------------------------------------
472
473 template <typename Integer>
submatrix(const vector<key_t> & rows) const474 Matrix<Integer> Matrix<Integer>::submatrix(const vector<key_t>& rows) const {
475 size_t size = rows.size(), j;
476 Matrix<Integer> M(size, nc);
477 for (size_t i = 0; i < size; i++) {
478 j = rows[i];
479 assert(j >= 0);
480 assert(j < nr);
481 M.elem[i] = elem[j];
482 }
483 return M;
484 }
485
486 //---------------------------------------------------------------------------
487
488 /*
489 template <typename Integer>
490 Matrix<Integer> Matrix<Integer>::submatrix(const vector<int>& rows) const {
491 size_t size = rows.size(), j;
492 Matrix<Integer> M(size, nc);
493 for (size_t i = 0; i < size; i++) {
494 j = rows[i];
495 assert(j >= 0);
496 assert(j < nr);
497 M.elem[i] = elem[j];
498 }
499 return M;
500 }
501 */
502
503 //---------------------------------------------------------------------------
504
505 template <typename Integer>
submatrix(const vector<bool> & rows) const506 Matrix<Integer> Matrix<Integer>::submatrix(const vector<bool>& rows) const {
507 assert(rows.size() == nr);
508 size_t size = 0;
509 for (const auto& row : rows) {
510 if (row) {
511 size++;
512 }
513 }
514 Matrix<Integer> M(size, nc);
515 size_t j = 0;
516 for (size_t i = 0; i < nr; i++) {
517 if (rows[i]) {
518 M.elem[j++] = elem[i];
519 }
520 }
521 return M;
522 }
523
524 /*//---------------------------------------------------------------------------
525
526 template<typename Integer>
527 Matrix<Integer> Matrix<Integer>::submatrix(const dynamic_bitset& rows) const{
528 assert(rows.size() == nr);
529 size_t size=0;
530 for (size_t i = 0; i <rows.size(); i++) {
531 if (rows[i]) {
532 size++;
533 }
534 }
535 Matrix<Integer> M(size, nc);
536 size_t j = 0;
537 for (size_t i = 0; i < nr; i++) {
538 if (rows[i]) {
539 M.elem[j++] = elem[i];
540 }
541 }
542 return M;
543 }*/
544
545 //---------------------------------------------------------------------------
546
547 template <typename Integer>
select_columns(const vector<bool> & cols) const548 Matrix<Integer> Matrix<Integer>::select_columns(const vector<bool>& cols) const {
549 return transpose().submatrix(cols).transpose();
550 }
551
552 //---------------------------------------------------------------------------
553
554 template <typename Integer>
selected_columns_first(const vector<bool> & cols) const555 Matrix<Integer> Matrix<Integer>::selected_columns_first(const vector<bool>& cols) const {
556 assert(cols.size() == nc);
557 Matrix<Integer> M(nr, nc);
558 for (size_t i = 0; i < nr; ++i) {
559 size_t j = 0;
560 for (size_t k = 0; k < nc; ++k)
561 if (cols[k]) {
562 M[i][j] = elem[i][k];
563 j++;
564 }
565 for (size_t k = 0; k < nc; ++k)
566 if (!cols[k]) {
567 M[i][j] = elem[i][k];
568 j++;
569 }
570 }
571 return M;
572 }
573
574 //---------------------------------------------------------------------------
575
576 /*
577 template <typename Integer>
578 Matrix<Integer>& Matrix<Integer>::remove_zero_rows() {
579 size_t from = 0, to = 0; // maintain to <= from
580 while (from < nr && v_is_zero(elem[from]))
581 from++; // skip zero rows
582 while (from < nr) { // go over matrix
583 // now from is a non-zero row
584 if (to != from)
585 elem[to].swap(elem[from]);
586 ++to;
587 ++from;
588 while (from < nr && v_is_zero(elem[from]))
589 from++; // skip zero rows
590 }
591 nr = to;
592 elem.resize(nr);
593 return *this;
594 }
595 */
596
597 //---------------------------------------------------------------------------
598
599 template <typename Integer>
nmz_float_without_first_column() const600 Matrix<nmz_float> Matrix<Integer>::nmz_float_without_first_column() const {
601 Matrix<nmz_float> Ret(nr, nc - 1);
602 for (size_t i = 0; i < nr; ++i) // without first column
603 for (size_t j = 1; j < nc; ++j)
604 convert(Ret[i][j - 1], elem[i][j]);
605
606 // We scale the inequalities for LLL so that right hand side has absolute value 1
607 // If RHS is zero, we divide by absolute value of first non-zero element
608 for (size_t i = 0; i < nr; ++i) {
609 nmz_float denom = Iabs(convertTo<nmz_float>(elem[i][0]));
610 if (denom == 0) {
611 denom = 1; // auxiliary choice if vector is 0 everywhere
612 for (size_t j = 0; j < Ret.nc; ++j)
613 if (Ret[i][j] != 0)
614 denom = Iabs(Ret[i][j]);
615 }
616 v_scalar_division(Ret[i], denom);
617 }
618
619 return Ret;
620 }
621
622 template <>
nmz_float_without_first_column() const623 Matrix<nmz_float> Matrix<mpq_class>::nmz_float_without_first_column() const {
624 assert(false);
625 return Matrix<nmz_float>(0, 0);
626 }
627
628 #ifdef ENFNORMALIZ
629 template <>
nmz_float_without_first_column() const630 Matrix<nmz_float> Matrix<renf_elem_class>::nmz_float_without_first_column() const {
631 assert(false);
632 return Matrix<nmz_float>(0, 0);
633 }
634 #endif
635
636 //---------------------------------------------------------------------------
637
638 template <typename Integer>
swap(Matrix<Integer> & x)639 void Matrix<Integer>::swap(Matrix<Integer>& x) {
640 size_t tmp = nr;
641 nr = x.nr;
642 x.nr = tmp;
643 tmp = nc;
644 nc = x.nc;
645 x.nc = tmp;
646 elem.swap(x.elem);
647 }
648
649 //---------------------------------------------------------------------------
650
651 template <typename Integer>
resize(size_t nr_rows,size_t nr_cols)652 void Matrix<Integer>::resize(size_t nr_rows, size_t nr_cols) {
653 nc = nr_cols; // for adding new rows with the right length
654 resize(nr_rows);
655 resize_columns(nr_cols);
656 }
657
658 template <typename Integer>
resize(size_t nr_rows)659 void Matrix<Integer>::resize(size_t nr_rows) {
660 if (nr_rows > elem.size()) {
661 elem.resize(nr_rows, vector<Integer>(nc));
662 }
663 if (nr_rows < elem.size())
664 elem.resize(nr_rows);
665 nr = nr_rows;
666 }
667
668 template <typename Integer>
resize_columns(size_t nr_cols)669 void Matrix<Integer>::resize_columns(size_t nr_cols) {
670 for (size_t i = 0; i < nr; i++) {
671 elem[i].resize(nr_cols);
672 }
673 nc = nr_cols;
674 }
675
676 //---------------------------------------------------------------------------
677
678 /*
679 template <typename Integer>
680 vector<Integer> Matrix<Integer>::diagonal() const {
681 assert(nr == nc);
682 vector<Integer> diag(nr);
683 for (size_t i = 0; i < nr; i++) {
684 diag[i] = elem[i][i];
685 }
686 return diag;
687 }
688 */
689
690 //---------------------------------------------------------------------------
691
692 /*
693 template <typename Integer>
694 size_t Matrix<Integer>::maximal_decimal_length() const {
695 size_t i, maxim = 0;
696 vector<size_t> maxim_col;
697 maxim_col = maximal_decimal_length_columnwise();
698 for (i = 0; i < nr; i++)
699 maxim = max(maxim, maxim_col[i]);
700 return maxim;
701 }
702 */
703
704 //---------------------------------------------------------------------------
705
706 template <typename Integer>
append(const Matrix<Integer> & M)707 void Matrix<Integer>::append(const Matrix<Integer>& M) {
708 assert(nc == M.nc);
709 elem.resize(nr);
710 /* for (size_t i=0; i<M.nr; i++) {
711 elem.push_back(M.elem[i]);
712 }*/
713 elem.insert(elem.end(), M.elem.begin(), M.elem.end());
714 nr += M.nr;
715 }
716
717 //---------------------------------------------------------------------------
718
719 template <typename Integer>
append(const vector<vector<Integer>> & M)720 void Matrix<Integer>::append(const vector<vector<Integer> >& M) {
721 if (M.size() == 0)
722 return;
723 assert(nc == M[0].size());
724 elem.resize(nr);
725 for (size_t i = 0; i < M.size(); i++) {
726 elem.push_back(M[i]);
727 }
728 nr += M.size();
729 }
730
731 //---------------------------------------------------------------------------
732
733 template <typename Integer>
append(const vector<Integer> & V)734 void Matrix<Integer>::append(const vector<Integer>& V) {
735 assert(nc == V.size());
736 elem.resize(nr);
737 elem.push_back(V);
738 nr++;
739 }
740
741 //---------------------------------------------------------------------------
742
743 template <typename Integer>
append_column(const vector<Integer> & v)744 void Matrix<Integer>::append_column(const vector<Integer>& v) {
745 assert(nr == v.size());
746 for (size_t i = 0; i < nr; i++) {
747 elem[i].resize(nc + 1);
748 elem[i][nc] = v[i];
749 }
750 nc++;
751 }
752
753 //---------------------------------------------------------------------------
754
755 template <typename Integer>
insert_column(const size_t pos,const vector<Integer> & v)756 void Matrix<Integer>::insert_column(const size_t pos, const vector<Integer>& v) {
757 assert(nr == v.size());
758 for (size_t i = 0; i < nr; i++) {
759 elem[i].resize(nc + 1);
760 for (long j = nc - 1; j >= (long)pos; --j)
761 elem[i][j + 1] = elem[i][j];
762 elem[i][pos] = v[i];
763 }
764 nc++;
765 }
766
767 //-----------------------------------------------------
768
769 template <typename Integer>
insert_column(const size_t pos,const Integer & val)770 void Matrix<Integer>::insert_column(const size_t pos, const Integer& val) {
771 for (size_t i = 0; i < nr; i++) {
772 elem[i].resize(nc + 1);
773 for (long j = nc - 1; j >= (long)pos; --j)
774 elem[i][j + 1] = elem[i][j];
775 elem[i][pos] = val;
776 }
777 nc++;
778 }
779
780 //---------------------------------------------------------------------------
781
782 template <typename Integer>
remove_row(const vector<Integer> & row)783 void Matrix<Integer>::remove_row(const vector<Integer>& row) {
784 size_t tmp_nr = nr;
785 for (size_t i = 1; i <= tmp_nr; ++i) {
786 if (elem[tmp_nr - i] == row) {
787 elem.erase(elem.begin() + (tmp_nr - i));
788 nr--;
789 }
790 }
791 }
792
793 //---------------------------------------------------------------------------
794
795 template <typename Integer>
remove_row(const size_t index)796 void Matrix<Integer>::remove_row(const size_t index) {
797 assert(index < nr);
798 nr--;
799 elem.erase(elem.begin() + (index));
800 }
801
802 //---------------------------------------------------------------------------
803
804 template <typename Integer>
remove_duplicate_and_zero_rows()805 vector<size_t> Matrix<Integer>::remove_duplicate_and_zero_rows() {
806 bool remove_some = false;
807 vector<bool> key(nr, true);
808 vector<size_t> original_row;
809
810 set<vector<Integer> > SortedRows;
811 SortedRows.insert(vector<Integer>(nc, 0));
812 for (size_t i = 0; i < nr; i++) {
813 auto found = SortedRows.find(elem[i]);
814 if (found != SortedRows.end()) {
815 key[i] = false;
816 remove_some = true;
817 }
818 else {
819 SortedRows.insert(found, elem[i]);
820 original_row.push_back(i);
821 }
822 }
823
824 if (remove_some) {
825 *this = submatrix(key);
826 }
827 return original_row;
828 }
829
830 //---------------------------------------------------------------------------
831
832 /*
833 template <typename Integer>
834 void Matrix<Integer>::remove_duplicate(const Matrix<Integer>& M) {
835 bool remove_some = false;
836 vector<bool> key(nr, true);
837
838 // TODO more efficient! sorted rows
839 for (size_t i = 0; i < nr; i++) {
840 for (size_t j = 0; j < M.nr_of_rows(); j++) {
841 if (elem[i] == M[j]) {
842 remove_some = true;
843 key[i] = false;
844 break;
845 }
846 }
847 }
848
849 if (remove_some) {
850 *this = submatrix(key);
851 }
852 }
853 */
854
855 //---------------------------------------------------------------------------
856
857 /*
858 template <typename Integer>
859 Matrix<Integer> Matrix<Integer>::add(const Matrix<Integer>& A) const {
860 assert(nr == A.nr);
861 assert(nc == A.nc);
862
863 Matrix<Integer> B(nr, nc);
864 size_t i, j;
865 for (i = 0; i < nr; i++) {
866 for (j = 0; j < nc; j++) {
867 B.elem[i][j] = elem[i][j] + A.elem[i][j];
868 }
869 }
870 return B;
871 }
872 */
873 //---------------------------------------------------------------------------
874
875 // B = (*this)*A.transpose()
876 template <typename Integer>
multiplication_trans(Matrix<Integer> & B,const Matrix<Integer> & A) const877 void Matrix<Integer>::multiplication_trans(Matrix<Integer>& B, const Matrix<Integer>& A) const {
878 assert(nc == A.nc);
879 assert(B.nr == nr);
880 assert(B.nc == A.nr);
881
882 bool skip_remaining = false;
883 std::exception_ptr tmp_exception;
884
885 #pragma omp parallel for
886 for (size_t i = 0; i < B.nr; i++) {
887 if (skip_remaining)
888 continue;
889 try {
890 INTERRUPT_COMPUTATION_BY_EXCEPTION
891
892 for (size_t j = 0; j < B.nc; j++) {
893 B[i][j] = v_scalar_product(elem[i], A[j]);
894 }
895 } catch (const std::exception&) {
896 tmp_exception = std::current_exception();
897 skip_remaining = true;
898 #pragma omp flush(skip_remaining)
899 }
900 } // end for i
901
902 if (!(tmp_exception == 0))
903 std::rethrow_exception(tmp_exception);
904 }
905
906 //---------------------------------------------------------------------------
907
908 // B = (*this)*A
909 template <typename Integer>
multiplication(Matrix<Integer> & B,const Matrix<Integer> & A) const910 void Matrix<Integer>::multiplication(Matrix<Integer>& B, const Matrix<Integer>& A) const {
911 multiplication_trans(B, A.transpose());
912 }
913 //---------------------------------------------------------------------------
914
915 template <typename Integer>
multiplication(const Matrix<Integer> & A) const916 Matrix<Integer> Matrix<Integer>::multiplication(const Matrix<Integer>& A) const {
917 Matrix<Integer> B(nr, A.nc);
918 multiplication(B, A);
919 return B;
920 }
921
922 //---------------------------------------------------------------------------
923
924 template <typename Integer>
multiplication_trans(const Matrix<Integer> & A) const925 Matrix<Integer> Matrix<Integer>::multiplication_trans(const Matrix<Integer>& A) const {
926 Matrix<Integer> B(nr, A.nr);
927 multiplication_trans(B, A);
928 return B;
929 }
930
931 //---------------------------------------------------------------------------
932
933 /*
934 template <typename Integer>
935 Matrix<Integer> Matrix<Integer>::multiplication(const Matrix<Integer>& A, long m) const {
936 assert(nc == A.nr);
937
938 Matrix<Integer> B(nr, A.nc, 0); // initialized with 0
939 size_t i, j, k;
940 for (i = 0; i < B.nr; i++) {
941 for (j = 0; j < B.nc; j++) {
942 for (k = 0; k < nc; k++) {
943 B.elem[i][j] = (B.elem[i][j] + elem[i][k] * A.elem[k][j]) % m;
944 if (B.elem[i][j] < 0) {
945 B.elem[i][j] = B.elem[i][j] + m;
946 }
947 }
948 }
949 }
950 return B;
951 }
952
953 template <>
954 Matrix<nmz_float> Matrix<nmz_float>::multiplication(const Matrix<nmz_float>& A, long m) const {
955 assert(false);
956 return A;
957 }
958
959 template <>
960 Matrix<mpq_class> Matrix<mpq_class>::multiplication(const Matrix<mpq_class>& A, long m) const {
961 assert(false);
962 return A;
963 }
964
965 #ifdef ENFNORMALIZ
966 template <>
967 Matrix<renf_elem_class> Matrix<renf_elem_class>::multiplication(const Matrix<renf_elem_class>& A, long m) const {
968 assert(false);
969 return A;
970 }
971 #endif
972 */
973 //---------------------------------------------------------------------------
974
975 template <typename Integer>
equal(const Matrix<Integer> & A) const976 bool Matrix<Integer>::equal(const Matrix<Integer>& A) const {
977 if ((nr != A.nr) || (nc != A.nc)) {
978 return false;
979 }
980 size_t i, j;
981 for (i = 0; i < nr; i++) {
982 for (j = 0; j < nc; j++) {
983 if (elem[i][j] != A.elem[i][j]) {
984 return false;
985 }
986 }
987 }
988 return true;
989 }
990
991 //---------------------------------------------------------------------------
992 /*
993 template<typename Integer>
994 bool Matrix<Integer>::equal(const Matrix<Integer>& A, long m) const{
995 if ((nr!=A.nr)||(nc!=A.nc)){ return false; }
996 size_t i,j;
997 for (i=0; i < nr; i++) {
998 for (j = 0; j < nc; j++) {
999 if (((elem[i][j]-A.elem[i][j]) % m)!=0) {
1000 return false;
1001 }
1002 }
1003 }
1004 return true;
1005 }
1006 */
1007 //---------------------------------------------------------------------------
1008
1009 template <typename Integer>
transpose() const1010 Matrix<Integer> Matrix<Integer>::transpose() const {
1011 Matrix<Integer> B(nc, nr);
1012 size_t i, j;
1013 for (i = 0; i < nr; i++) {
1014 for (j = 0; j < nc; j++) {
1015 B.elem[j][i] = elem[i][j];
1016 }
1017 }
1018 return B;
1019 }
1020
1021 //---------------------------------------------------------------------------
1022
1023 template <typename Integer>
transpose_in_place()1024 void Matrix<Integer>::transpose_in_place() {
1025 assert(nr == nc);
1026 size_t i, j;
1027 Integer help;
1028 for (i = 0; i < nr; i++) {
1029 for (j = i + 1; j < nc; j++) {
1030 help = elem[i][j];
1031 elem[i][j] = elem[j][i];
1032 elem[j][i] = help;
1033 }
1034 }
1035 }
1036 //---------------------------------------------------------------------------
1037
1038 template <typename Integer>
scalar_multiplication(const Integer & scalar)1039 void Matrix<Integer>::scalar_multiplication(const Integer& scalar) {
1040 size_t i, j;
1041 for (i = 0; i < nr; i++) {
1042 for (j = 0; j < nc; j++) {
1043 elem[i][j] *= scalar;
1044 }
1045 }
1046 }
1047
1048 //---------------------------------------------------------------------------
1049
1050 template <typename Integer>
scalar_division(const Integer & scalar)1051 void Matrix<Integer>::scalar_division(const Integer& scalar) {
1052 size_t i, j;
1053 assert(scalar != 0);
1054 if (scalar == 1)
1055 return;
1056 for (i = 0; i < nr; i++) {
1057 for (j = 0; j < nc; j++) {
1058 assert(elem[i][j] % scalar == 0);
1059 elem[i][j] /= scalar;
1060 }
1061 }
1062 }
1063
1064 template <>
scalar_division(const nmz_float & scalar)1065 void Matrix<nmz_float>::scalar_division(const nmz_float& scalar) {
1066
1067 assert(false);
1068 }
1069 /* body
1070 size_t i, j;
1071 assert(scalar != 0);
1072 for (i = 0; i < nr; i++) {
1073 for (j = 0; j < nc; j++) {
1074 elem[i][j] /= scalar;
1075 }
1076 }
1077 }
1078 */
1079
1080 template <>
scalar_division(const mpq_class & scalar)1081 void Matrix<mpq_class>::scalar_division(const mpq_class& scalar) {
1082 assert(false);
1083 }
1084 /*
1085 size_t i, j;
1086 assert(scalar != 0);
1087 for (i = 0; i < nr; i++) {
1088 for (j = 0; j < nc; j++) {
1089 elem[i][j] /= scalar;
1090 }
1091 }
1092 }*/
1093
1094 #ifdef ENFNORMALIZ
1095 template <>
scalar_division(const renf_elem_class & scalar)1096 void Matrix<renf_elem_class>::scalar_division(const renf_elem_class& scalar) {
1097 size_t i, j;
1098 assert(scalar != 0);
1099 if (scalar == 1)
1100 return;
1101 for (i = 0; i < nr; i++) {
1102 for (j = 0; j < nc; j++) {
1103 elem[i][j] /= scalar;
1104 }
1105 }
1106 }
1107 #endif
1108 //---------------------------------------------------------------------------
1109
1110 /*
1111 template <typename Integer>
1112 void Matrix<Integer>::reduction_modulo(const Integer& modulo) {
1113 size_t i, j;
1114 for (i = 0; i < nr; i++) {
1115 for (j = 0; j < nc; j++) {
1116 elem[i][j] %= modulo;
1117 if (elem[i][j] < 0) {
1118 elem[i][j] += modulo;
1119 }
1120 }
1121 }
1122 }
1123
1124 template <>
1125 void Matrix<nmz_float>::reduction_modulo(const nmz_float& modulo) {
1126 assert(false);
1127 }
1128
1129 template <>
1130 void Matrix<mpq_class>::reduction_modulo(const mpq_class& modulo) {
1131 assert(false);
1132 }
1133
1134 #ifdef ENFNORMALIZ
1135 template <>
1136 void Matrix<renf_elem_class>::reduction_modulo(const renf_elem_class& modulo) {
1137 assert(false);
1138 }
1139 #endif
1140 */
1141
1142 //---------------------------------------------------------------------------
1143
1144 template <typename Integer>
matrix_gcd() const1145 Integer Matrix<Integer>::matrix_gcd() const {
1146 Integer g = 0, h;
1147 for (size_t i = 0; i < nr; i++) {
1148 h = v_gcd(elem[i]);
1149 g = libnormaliz::gcd<Integer>(g, h);
1150 if (g == 1)
1151 return g;
1152 }
1153 return g;
1154 }
1155
1156 template <>
matrix_gcd() const1157 mpq_class Matrix<mpq_class>::matrix_gcd() const {
1158 assert(false);
1159 return 1;
1160 }
1161
1162 #ifdef ENFNORMALIZ
1163 template <>
matrix_gcd() const1164 renf_elem_class Matrix<renf_elem_class>::matrix_gcd() const {
1165 assert(false);
1166 return 1;
1167 }
1168
1169 #endif
1170
1171 //---------------------------------------------------------------------------
1172
1173 template <typename Integer>
make_prime()1174 vector<Integer> Matrix<Integer>::make_prime() {
1175 vector<Integer> g(nr);
1176 for (size_t i = 0; i < nr; i++) {
1177 g[i] = v_make_prime(elem[i]);
1178 }
1179 return g;
1180 }
1181
1182 //---------------------------------------------------------------------------
1183
1184 template <typename Integer>
make_cols_prime(size_t from_col,size_t to_col)1185 void Matrix<Integer>::make_cols_prime(size_t from_col, size_t to_col) {
1186 for (size_t k = from_col; k <= to_col; k++) {
1187 Integer g = 0;
1188 for (size_t i = 0; i < nr; i++) {
1189 g = libnormaliz::gcd(g, elem[i][k]);
1190 if (g == 1) {
1191 break;
1192 }
1193 }
1194 for (size_t i = 0; i < nr; i++)
1195 elem[i][k] /= g;
1196 }
1197 }
1198
1199 template <>
make_cols_prime(size_t from_col,size_t to_col)1200 void Matrix<mpq_class>::make_cols_prime(size_t from_col, size_t to_col) {
1201 assert(false);
1202 }
1203
1204 #ifdef ENFNORMALIZ
1205 template <>
make_cols_prime(size_t from_col,size_t to_col)1206 void Matrix<renf_elem_class>::make_cols_prime(size_t from_col, size_t to_col) {
1207 assert(false);
1208 }
1209 #endif
1210 //---------------------------------------------------------------------------
1211
1212 /*
1213 template <typename Integer>
1214 Matrix<Integer> Matrix<Integer>::multiply_rows(const vector<Integer>& m) const { // row i is multiplied by m[i]
1215 Matrix M = Matrix(nr, nc);
1216 size_t i, j;
1217 for (i = 0; i < nr; i++) {
1218 for (j = 0; j < nc; j++) {
1219 M.elem[i][j] = elem[i][j] * m[i];
1220 }
1221 }
1222 return M;
1223 }*/
1224
1225 template <typename Integer>
standardize_basis()1226 void Matrix<Integer>::standardize_basis() {
1227 row_echelon_reduce();
1228 #ifdef ENFNORMALIZ
1229 if (using_renf<Integer>())
1230 make_first_element_1_in_rows();
1231 #endif
1232 }
1233
1234 template <typename Integer>
standardize_rows(const vector<Integer> & Norm)1235 bool Matrix<Integer>::standardize_rows(const vector<Integer>& Norm) {
1236 assert(false);
1237 return {};
1238 }
1239
1240 template <typename Integer>
standardize_rows()1241 bool Matrix<Integer>::standardize_rows() {
1242 assert(false);
1243 return {};
1244 }
1245
1246 template <>
standardize_rows(const vector<nmz_float> & Norm)1247 bool Matrix<nmz_float>::standardize_rows(const vector<nmz_float>& Norm) {
1248 nmz_float val;
1249 bool non_zero = true;
1250 for (size_t i = 0; i < nr; i++) {
1251 val = v_standardize(elem[i], Norm);
1252 if (val == 0)
1253 non_zero = false;
1254 }
1255 return non_zero;
1256 }
1257
1258 template <>
standardize_rows()1259 bool Matrix<nmz_float>::standardize_rows() {
1260 vector<nmz_float> dummy(0);
1261 for (size_t i = 0; i < nr; i++) {
1262 v_standardize(elem[i], dummy);
1263 }
1264 return true;
1265 }
1266
1267 //---------------------------------------------------------------------------
1268
1269 #ifdef ENFNORMALIZ
1270 template <>
standardize_rows(const vector<renf_elem_class> & Norm)1271 bool Matrix<renf_elem_class>::standardize_rows(const vector<renf_elem_class>& Norm) {
1272 renf_elem_class val;
1273 bool non_zero = true;
1274 for (size_t i = 0; i < nr; i++) {
1275 val = v_standardize(elem[i], Norm);
1276 if (val == 0)
1277 non_zero = false;
1278 }
1279 return non_zero;
1280 }
1281
1282 template <>
standardize_rows()1283 bool Matrix<renf_elem_class>::standardize_rows() {
1284 vector<renf_elem_class> dummy(0);
1285 for (size_t i = 0; i < nr; i++) {
1286 v_standardize(elem[i], dummy);
1287 }
1288 return true;
1289 }
1290 #endif
1291
1292 //---------------------------------------------------------------------------
1293
1294 template <typename Integer>
MxV(vector<Integer> & result,const vector<Integer> & v) const1295 void Matrix<Integer>::MxV(vector<Integer>& result, const vector<Integer>& v) const {
1296 assert(nc == v.size());
1297 result.resize(nr);
1298 for (size_t i = 0; i < nr; i++) {
1299 result[i] = v_scalar_product(elem[i], v);
1300 }
1301 }
1302
1303 //---------------------------------------------------------------------------
1304
1305 template <typename Integer>
MxV(const vector<Integer> & v) const1306 vector<Integer> Matrix<Integer>::MxV(const vector<Integer>& v) const {
1307 vector<Integer> w(nr);
1308 MxV(w, v);
1309 return w;
1310 }
1311
1312 //---------------------------------------------------------------------------
1313
1314 template <typename Integer>
VxM(const vector<Integer> & v) const1315 vector<Integer> Matrix<Integer>::VxM(const vector<Integer>& v) const {
1316 assert(nr == v.size());
1317 vector<Integer> w(nc, 0);
1318 size_t i, j;
1319 for (i = 0; i < nc; i++) {
1320 for (j = 0; j < nr; j++) {
1321 w[i] += v[j] * elem[j][i];
1322 }
1323 if (!check_range(w[i]))
1324 break;
1325 }
1326 if (i == nc)
1327 return w;
1328 Matrix<mpz_class> mpz_this(nr, nc);
1329 mat_to_mpz(*this, mpz_this);
1330 vector<mpz_class> mpz_v(nr);
1331 convert(mpz_v, v);
1332 vector<mpz_class> mpz_w = mpz_this.VxM(mpz_v);
1333 convert(w, mpz_w);
1334 return w;
1335 }
1336
1337 template <>
VxM(const vector<mpq_class> & v) const1338 vector<mpq_class> Matrix<mpq_class>::VxM(const vector<mpq_class>& v) const {
1339
1340 assert(false);
1341 return {};
1342 }
1343 /* body
1344 assert(nr == v.size());
1345 vector<mpq_class> w(nc, 0);
1346 size_t i, j;
1347 for (i = 0; i < nc; i++) {
1348 for (j = 0; j < nr; j++) {
1349 w[i] += v[j] * elem[j][i];
1350 }
1351 }
1352 return w;
1353 }
1354 */
1355
1356 //---------------------------------------------------------------------------
1357
1358 template <typename Integer>
VxM_div(const vector<Integer> & v,const Integer & divisor,bool & success) const1359 vector<Integer> Matrix<Integer>::VxM_div(const vector<Integer>& v, const Integer& divisor, bool& success) const {
1360 assert(nr == v.size());
1361 vector<Integer> w(nc, 0);
1362 success = true;
1363 size_t i, j;
1364 for (i = 0; i < nc; i++) {
1365 for (j = 0; j < nr; j++) {
1366 w[i] += v[j] * elem[j][i];
1367 }
1368 if (!check_range(w[i])) {
1369 success = false;
1370 break;
1371 }
1372 }
1373
1374 if (success)
1375 v_scalar_division(w, divisor);
1376
1377 return w;
1378 }
1379
1380 template <>
VxM_div(const vector<nmz_float> & v,const nmz_float & divisor,bool & success) const1381 vector<nmz_float> Matrix<nmz_float>::VxM_div(const vector<nmz_float>& v, const nmz_float& divisor, bool& success) const {
1382 assert(false);
1383 return {};
1384 }
1385
1386 //---------------------------------------------------------------------------
1387
1388 template <typename Integer>
check_congruences(const vector<Integer> & v) const1389 bool Matrix<Integer>::check_congruences(const vector<Integer>& v) const {
1390 // if(nr==0)
1391 // return true;
1392
1393 assert(nc == v.size() + 1);
1394
1395 for (size_t k = 0; k < nr; ++k) {
1396 if (v_scalar_product_vectors_unequal_lungth(v, elem[k]) % elem[k][nc - 1] != 0) { // congruence not satisfied
1397 return false;
1398 }
1399 }
1400 return true;
1401 }
1402
1403 template <>
check_congruences(const vector<nmz_float> & v) const1404 bool Matrix<nmz_float>::check_congruences(const vector<nmz_float>& v) const {
1405 assert(false);
1406 return false;
1407 }
1408
1409 template <>
check_congruences(const vector<mpq_class> & v) const1410 bool Matrix<mpq_class>::check_congruences(const vector<mpq_class>& v) const {
1411 assert(false);
1412 return false;
1413 }
1414
1415 #ifdef ENFNORMALIZ
1416 template <>
check_congruences(const vector<renf_elem_class> & v) const1417 bool Matrix<renf_elem_class>::check_congruences(const vector<renf_elem_class>& v) const {
1418 assert(false);
1419 return false;
1420 }
1421 #endif
1422
1423 //---------------------------------------------------------------------------
1424
1425 template <typename Integer>
is_diagonal() const1426 bool Matrix<Integer>::is_diagonal() const {
1427 for (size_t i = 0; i < nr; ++i)
1428 for (size_t j = 0; j < nc; ++j)
1429 if (i != j && elem[i][j] != 0)
1430 return false;
1431 return true;
1432 }
1433
1434 //---------------------------------------------------------------------------
1435
1436 template <typename Integer>
pivot(size_t corner)1437 vector<long> Matrix<Integer>::pivot(size_t corner) {
1438 assert(corner < nc);
1439 assert(corner < nr);
1440 size_t i, j;
1441 Integer help = 0;
1442 vector<long> v(2, -1);
1443
1444 for (i = corner; i < nr; i++) {
1445 for (j = corner; j < nc; j++) {
1446 if (elem[i][j] != 0) {
1447 if ((help == 0) || (Iabs(elem[i][j]) < help)) {
1448 help = Iabs(elem[i][j]);
1449 v[0] = i;
1450 v[1] = j;
1451 if (help == 1)
1452 return v;
1453 }
1454 }
1455 }
1456 }
1457
1458 return v;
1459 }
1460
1461 //---------------------------------------------------------------------------
1462
1463 template <typename Integer>
pivot_in_column(size_t row,size_t col)1464 long Matrix<Integer>::pivot_in_column(size_t row, size_t col) {
1465 assert(col < nc);
1466 assert(row < nr);
1467 size_t i;
1468 long j = -1;
1469 Integer help = 0;
1470
1471 for (i = row; i < nr; i++) {
1472 if (elem[i][col] != 0) {
1473 if ((help == 0) || (Iabs(elem[i][col]) < help)) {
1474 help = Iabs(elem[i][col]);
1475 j = i;
1476 if (help == 1)
1477 return j;
1478 }
1479 }
1480 }
1481
1482 return j;
1483 }
1484
1485 //---------------------------------------------------------------------------
1486
1487 template <typename Integer>
pivot_in_column(size_t col)1488 long Matrix<Integer>::pivot_in_column(size_t col) {
1489 return pivot_in_column(col, col);
1490 }
1491
1492 //---------------------------------------------------------------------------
1493
1494 template <typename Integer>
exchange_rows(const size_t & row1,const size_t & row2)1495 void Matrix<Integer>::exchange_rows(const size_t& row1, const size_t& row2) {
1496 if (row1 == row2)
1497 return;
1498 assert(row1 < nr);
1499 assert(row2 < nr);
1500 elem[row1].swap(elem[row2]);
1501 }
1502
1503 //---------------------------------------------------------------------------
1504
1505 template <typename Integer>
exchange_columns(const size_t & col1,const size_t & col2)1506 void Matrix<Integer>::exchange_columns(const size_t& col1, const size_t& col2) {
1507 if (col1 == col2)
1508 return;
1509 assert(col1 < nc);
1510 assert(col2 < nc);
1511 for (size_t i = 0; i < nr; i++) {
1512 std::swap(elem[i][col1], elem[i][col2]);
1513 }
1514 }
1515
1516 //---------------------------------------------------------------------------
1517
1518 template <typename Integer>
reduce_row(size_t row,size_t col)1519 bool Matrix<Integer>::reduce_row(size_t row, size_t col) {
1520 assert(col < nc);
1521 assert(row < nr);
1522 size_t i, j;
1523 Integer help;
1524 if (using_renf<Integer>()) {
1525 for (i = row + 1; i < nr; i++) {
1526 if (elem[i][col] != 0) {
1527 elem[i][col] /= elem[row][col];
1528 for (j = col + 1; j < nc; j++) {
1529 if (elem[row][j] != 0) {
1530 help = elem[i][col];
1531 help *= elem[row][j];
1532 elem[i][j] -= help;
1533 }
1534 }
1535 elem[i][col] = 0;
1536 }
1537 }
1538 } else {
1539 Integer help1;
1540 for (i = row + 1; i < nr; i++) {
1541 if (elem[i][col] != 0) {
1542 help = elem[i][col];
1543 help /= elem[row][col];
1544 for (j = col; j < nc; j++) {
1545 help1 = help;
1546 help1 *= elem[row][j];
1547 elem[i][j] -= help1;
1548 if (!check_range(elem[i][j])) {
1549 return false;
1550 }
1551 }
1552 if (using_float<Integer>())
1553 elem[i][col] = 0;
1554 }
1555 }
1556 }
1557 return true;
1558 }
1559
1560 //---------------------------------------------------------------------------
1561
1562 template <typename Integer>
reduce_row(size_t corner)1563 bool Matrix<Integer>::reduce_row(size_t corner) {
1564 return reduce_row(corner, corner);
1565 }
1566
1567 //---------------------------------------------------------------------------
1568
1569 template <typename Integer>
reduce_rows_upwards()1570 bool Matrix<Integer>::reduce_rows_upwards() {
1571 // assumes that "this" is in row echelon form
1572 // and reduces eevery column in which the rank jumps
1573 // by its lowest element
1574
1575 if (nr == 0)
1576 return true;
1577
1578 for (size_t row = 0; row < nr; ++row) {
1579 size_t col;
1580 for (col = 0; col < nc; ++col)
1581 if (elem[row][col] != 0)
1582 break;
1583 if (col == nc)
1584 continue;
1585 if (elem[row][col] < 0)
1586 v_scalar_multiplication<Integer>(elem[row], -1);
1587
1588 for (long i = row - 1; i >= 0; --i) {
1589 Integer quot, rem;
1590
1591 minimal_remainder(elem[i][col], elem[row][col], quot, rem);
1592 elem[i][col] = rem;
1593 for (size_t j = col + 1; j < nc; ++j) {
1594 elem[i][j] -= quot * elem[row][j];
1595 if (!check_range(elem[i][j])) {
1596 return false;
1597 }
1598 }
1599 }
1600 }
1601 return true;
1602 }
1603
1604 template <>
reduce_rows_upwards()1605 bool Matrix<nmz_float>::reduce_rows_upwards() {
1606 assert(false); // for the time being
1607 return true;
1608 }
1609
1610 #ifdef ENFNORMALIZ
1611 template <>
reduce_rows_upwards()1612 bool Matrix<renf_elem_class>::reduce_rows_upwards() {
1613 // assumes that "this" is in row echelon form
1614 // and reduces eevery column in which the rank jumps
1615 // by its lowest element
1616 //
1617 if (nr == 0)
1618 return true;
1619
1620 for (size_t row = 0; row < nr; ++row) {
1621 size_t col;
1622 for (col = 0; col < nc; ++col)
1623 if (elem[row][col] != 0)
1624 break;
1625 if (col == nc) // zero row
1626 continue;
1627 if (elem[row][col] < 0)
1628 v_scalar_multiplication<renf_elem_class>(elem[row], -1); // make corner posizive
1629
1630 for (long i = row - 1; i >= 0; --i) {
1631 renf_elem_class quot;
1632 // minimal_remainder(elem[i][col],elem[row][col],quot,rem);
1633 quot = elem[i][col] / elem[row][col];
1634 elem[i][col] = 0; // rem
1635 for (size_t j = col + 1; j < nc; ++j) {
1636 elem[i][j] -= quot * elem[row][j];
1637 }
1638 }
1639 }
1640
1641 return true;
1642 }
1643 #endif
1644
1645 //---------------------------------------------------------------------------
1646
1647 template <typename Integer>
linear_comb_columns(const size_t & col,const size_t & j,const Integer & u,const Integer & w,const Integer & v,const Integer & z)1648 bool Matrix<Integer>::linear_comb_columns(
1649 const size_t& col, const size_t& j, const Integer& u, const Integer& w, const Integer& v, const Integer& z) {
1650 for (size_t i = 0; i < nr; ++i) {
1651 Integer rescue = elem[i][col];
1652 elem[i][col] = u * elem[i][col] + v * elem[i][j];
1653 elem[i][j] = w * rescue + z * elem[i][j];
1654 if ((!check_range(elem[i][col]) || !check_range(elem[i][j]))) {
1655 return false;
1656 }
1657 }
1658 return true;
1659 }
1660
1661 //---------------------------------------------------------------------------
1662
1663 template <typename Integer>
gcd_reduce_column(size_t corner,Matrix<Integer> & Right)1664 bool Matrix<Integer>::gcd_reduce_column(size_t corner, Matrix<Integer>& Right) {
1665 assert(corner < nc);
1666 assert(corner < nr);
1667 Integer d, u, w, z, v;
1668 for (size_t j = corner + 1; j < nc; ++j) {
1669 d = ext_gcd(elem[corner][corner], elem[corner][j], u, v);
1670 w = -elem[corner][j] / d;
1671 z = elem[corner][corner] / d;
1672 // Now we multiply the submatrix formed by columns "corner" and "j"
1673 // and rows corner,...,nr from the right by the 2x2 matrix
1674 // | u w |
1675 // | v z |
1676 if (!linear_comb_columns(corner, j, u, w, v, z))
1677 return false;
1678 if (!Right.linear_comb_columns(corner, j, u, w, v, z))
1679 return false;
1680 }
1681 return true;
1682 }
1683
1684 #ifdef ENFNORMALIZ
1685 template <>
gcd_reduce_column(size_t corner,Matrix<renf_elem_class> & Right)1686 bool Matrix<renf_elem_class>::gcd_reduce_column(size_t corner, Matrix<renf_elem_class>& Right) {
1687 assert(corner < nc);
1688 assert(corner < nr);
1689 renf_elem_class d, u, w, z, v;
1690 for (size_t j = corner + 1; j < nc; ++j) {
1691 d = elem[corner][corner], elem[corner]; // ext_gcd(elem[corner][corner],elem[corner][j],u,v);
1692 u = 1;
1693 v = 0;
1694 w = -elem[corner][j] / d;
1695 z = elem[corner][corner] / d;
1696 // Now we multiply the submatrix formed by columns "corner" and "j"
1697 // and rows corner,...,nr from the right by the 2x2 matrix
1698 // | u w |
1699 // | v z |
1700 if (!linear_comb_columns(corner, j, u, w, v, z))
1701 return false;
1702 if (!Right.linear_comb_columns(corner, j, u, w, v, z))
1703 return false;
1704 }
1705 return true;
1706 }
1707 #endif
1708
1709 template <>
gcd_reduce_column(size_t corner,Matrix<nmz_float> & Right)1710 bool Matrix<nmz_float>::gcd_reduce_column(size_t corner, Matrix<nmz_float>& Right) {
1711 assert(false);
1712 return true;
1713 }
1714
1715 template <>
gcd_reduce_column(size_t corner,Matrix<mpq_class> & Right)1716 bool Matrix<mpq_class>::gcd_reduce_column(size_t corner, Matrix<mpq_class>& Right) {
1717 assert(false);
1718 return true;
1719 }
1720
1721 //---------------------------------------------------------------------------
1722
1723 template <typename Integer>
column_trigonalize(size_t rk,Matrix<Integer> & Right)1724 bool Matrix<Integer>::column_trigonalize(size_t rk, Matrix<Integer>& Right) {
1725 assert(Right.nr == nc);
1726 assert(Right.nc == nc);
1727 vector<long> piv(2, 0);
1728 for (size_t j = 0; j < rk; ++j) {
1729 piv = pivot(j);
1730 assert(piv[0] >= 0); // protect against wrong rank
1731 exchange_rows(j, piv[0]);
1732 exchange_columns(j, piv[1]);
1733 Right.exchange_columns(j, piv[1]);
1734 if (!gcd_reduce_column(j, Right))
1735 return false;
1736 }
1737 return true;
1738 }
1739
1740 //---------------------------------------------------------------------------
1741
1742 template <typename Integer>
compute_vol(bool & success)1743 Integer Matrix<Integer>::compute_vol(bool& success) {
1744 assert(nr <= nc);
1745
1746 Integer det = 1;
1747 for (size_t i = 0; i < nr; ++i) {
1748 det *= elem[i][i];
1749 if (!check_range(det)) {
1750 success = false;
1751 return 0;
1752 }
1753 }
1754
1755 det = Iabs(det);
1756 success = true;
1757 return det;
1758 }
1759
1760 //---------------------------------------------------------------------------
1761
1762 template <typename Integer>
row_echelon_inner_elem(bool & success)1763 size_t Matrix<Integer>::row_echelon_inner_elem(bool& success) {
1764 size_t pc = 0;
1765 long piv = 0, rk = 0;
1766 success = true;
1767
1768 if (nr == 0)
1769 return 0;
1770
1771 for (rk = 0; rk < (long)nr; rk++) {
1772 for (; pc < nc; pc++) {
1773 piv = pivot_in_column(rk, pc);
1774 if (piv >= 0)
1775 break;
1776 }
1777 if (pc == nc)
1778 break;
1779 do {
1780 exchange_rows(rk, piv);
1781 if (!reduce_row(rk, pc)) {
1782 success = false;
1783 return rk;
1784 }
1785 piv = pivot_in_column(rk, pc);
1786 } while (piv > rk);
1787 }
1788
1789 return rk;
1790 }
1791
1792 /*
1793 template <typename Integer>
1794 void Matrix<Integer>::make_first_element_1_in_rows() {
1795 assert(false);
1796 }
1797
1798 template <>
1799 long Matrix<mpq_class>::pivot_in_column(size_t row, size_t col) {
1800 size_t i;
1801 long j = -1;
1802 mpq_class help = 0;
1803
1804 for (i = row; i < nr; i++) {
1805 if (elem[i][col] != 0) {
1806 j = i;
1807 break;
1808 }
1809 }
1810
1811 return j;
1812 }
1813 */
1814 template <>
row_echelon_inner_elem(bool & success)1815 size_t Matrix<mpq_class>::row_echelon_inner_elem(bool& success) {
1816
1817 assert(false);
1818 return 0;
1819 }
1820
1821 /* body
1822 success = true;
1823
1824 size_t pc = 0;
1825 long piv = 0, rk = 0;
1826
1827 if (nr == 0)
1828 return 0;
1829
1830 for (rk = 0; rk < (long)nr; rk++) {
1831 for (; pc < nc; pc++) {
1832 piv = pivot_in_column(rk, pc);
1833 if (piv >= 0)
1834 break;
1835 }
1836 if (pc == nc)
1837 break;
1838
1839 exchange_rows(rk, piv);
1840 reduce_row(rk, pc);
1841 }
1842
1843 return rk;
1844 }
1845
1846
1847 template <>
1848 void Matrix<mpq_class>::make_first_element_1_in_rows() {
1849 for (size_t i = 0; i < nr; ++i) {
1850 for (size_t j = 0; j < nc; ++j) {
1851 if (elem[i][j] != 0) {
1852 mpq_class pivot = elem[i][j];
1853 v_scalar_division(elem[i], pivot);
1854 break;
1855 }
1856 }
1857 }
1858 }
1859 */
1860
1861 template <>
row_echelon()1862 size_t Matrix<mpq_class>::row_echelon() {
1863 size_t rk;
1864 bool dummy;
1865 rk = row_echelon_inner_elem(dummy);
1866 Shrink_nr_rows(rk);
1867 return rk;
1868 }
1869
1870 //-----------------------------------------------------------
1871 //
1872 // variants for numberfield
1873 //
1874 //-----------------------------------------------------------
1875
1876 #ifdef ENFNORMALIZ
1877 template <>
pivot_in_column(size_t row,size_t col)1878 long Matrix<renf_elem_class>::pivot_in_column(size_t row, size_t col) {
1879 size_t i;
1880 long j = -1;
1881
1882 for (i = row; i < nr; i++) {
1883 if (elem[i][col] != 0) {
1884 j = i;
1885 break;
1886 }
1887 }
1888
1889 return j;
1890 }
1891
1892 template <>
row_echelon_inner_elem(bool & success)1893 size_t Matrix<renf_elem_class>::row_echelon_inner_elem(bool& success) {
1894 success = true;
1895
1896 size_t pc = 0;
1897 long piv = 0, rk = 0;
1898
1899 if (nr == 0)
1900 return 0;
1901
1902 for (rk = 0; rk < (long)nr; rk++) {
1903 for (; pc < nc; pc++) {
1904 piv = pivot_in_column(rk, pc);
1905 if (piv >= 0)
1906 break;
1907 }
1908 if (pc == nc)
1909 break;
1910
1911 exchange_rows(rk, piv);
1912 reduce_row(rk, pc);
1913 }
1914
1915 return rk;
1916 }
1917
1918 template <>
make_first_element_1_in_rows()1919 void Matrix<renf_elem_class>::make_first_element_1_in_rows() {
1920 for (size_t i = 0; i < nr; ++i) {
1921 for (size_t j = 0; j < nc; ++j) {
1922 if (elem[i][j] != 0) {
1923 renf_elem_class pivot = elem[i][j];
1924 v_scalar_division(elem[i], pivot);
1925 break;
1926 }
1927 }
1928 }
1929 }
1930
1931 template <>
row_echelon()1932 size_t Matrix<renf_elem_class>::row_echelon() {
1933 size_t rk;
1934 bool dummy;
1935 rk = row_echelon_inner_elem(dummy);
1936 Shrink_nr_rows(rk);
1937 return rk;
1938 }
1939 #endif
1940
1941 //---------------------------------------------------------------------------
1942
1943 /*
1944 template<typename Integer>
1945 size_t Matrix<Integer>::row_echelon_inner_bareiss(bool& success, Integer& det){
1946 // no overflow checks since this is supposed to be only used with GMP
1947
1948 success=true;
1949 if(nr==0)
1950 return 0;
1951 assert(using_GMP<Integer>());
1952
1953 size_t pc=0;
1954 long piv=0, rk=0;
1955 vector<bool> last_time_mult(nr,false),this_time_mult(nr,false);
1956 Integer last_div=1,this_div=1;
1957 size_t this_time_exp=0,last_time_exp=0;
1958 Integer det_factor=1;
1959
1960 for (rk = 0; rk < (long) nr; rk++){
1961
1962 for(;pc<nc;pc++){
1963 piv=pivot_in_column(rk,pc);
1964 if(piv>=0)
1965 break;
1966 }
1967 if(pc==nc)
1968 break;
1969
1970 if(!last_time_mult[piv]){
1971 for(size_t k=rk;k<nr;++k)
1972 if(elem[k][pc]!=0 && last_time_mult[k]){
1973 piv=k;
1974 break;
1975 }
1976 }
1977
1978 exchange_rows (rk,piv);
1979 v_bool_entry_swap(last_time_mult,rk,piv);
1980
1981 if(!last_time_mult[rk])
1982 for(size_t i=0;i<nr;++i)
1983 last_time_mult[i]=false;
1984
1985 Integer a=elem[rk][pc];
1986 this_div=Iabs(a);
1987 this_time_exp=0;
1988
1989 for(size_t i=rk+1;i<nr;++i){
1990 if(elem[i][pc]==0){
1991 this_time_mult[i]=false;
1992 continue;
1993 }
1994
1995 this_time_exp++;
1996 this_time_mult[i]=true;
1997 bool divide=last_time_mult[i] && (last_div!=1);
1998 if(divide)
1999 last_time_exp--;
2000 Integer b=elem[i][pc];
2001 elem[i][pc]=0;
2002 if(a==1){
2003 for(size_t j=pc+1;j<nc;++j){
2004 elem[i][j]=elem[i][j]-b*elem[rk][j];
2005 if(divide){
2006 elem[i][j]/=last_div;
2007 }
2008 }
2009 }
2010 else{
2011 if(a==-1){
2012 for(size_t j=pc+1;j<nc;++j){
2013 elem[i][j]=-elem[i][j]-b*elem[rk][j];
2014 if(divide){
2015 elem[i][j]/=last_div;
2016 }
2017 }
2018 }
2019 else{
2020 for(size_t j=pc+1;j<nc;++j){
2021 elem[i][j]=a*elem[i][j]-b*elem[rk][j];
2022 if(divide){
2023 elem[i][j]/=last_div;
2024 }
2025 }
2026 }
2027 }
2028 }
2029
2030 for(size_t i=0;i<last_time_exp;++i)
2031 det_factor*=last_div;
2032 last_time_mult=this_time_mult;
2033 last_div=this_div;
2034 last_time_exp=this_time_exp;
2035 }
2036
2037 det=0;
2038 if (nr <= nc && rk == (long) nr) { // must allow nonsquare matrices
2039 det=1;
2040 for(size_t i=0;i<nr;++i)
2041 det*=elem[i][i];
2042 det=Iabs<Integer>(det/det_factor);
2043 }
2044
2045 return rk;
2046 }
2047 */
2048
2049 //---------------------------------------------------------------------------
2050
2051 template <typename Integer>
row_echelon_reduce(bool & success)2052 size_t Matrix<Integer>::row_echelon_reduce(bool& success) {
2053 size_t rk = row_echelon_inner_elem(success);
2054 if (success)
2055 success = reduce_rows_upwards();
2056 return rk;
2057 }
2058
2059 //---------------------------------------------------------------------------
2060
2061 template <typename Integer>
full_rank_index(bool & success)2062 Integer Matrix<Integer>::full_rank_index(bool& success) {
2063 size_t rk = row_echelon_inner_elem(success);
2064 if(!success)
2065 return 0;
2066 Integer index = 1;
2067 if (success) {
2068 for (size_t i = 0; i < rk; ++i) {
2069 index *= elem[i][i];
2070 if (!check_range(index)) {
2071 success = false;
2072 index = 0;
2073 return index;
2074 }
2075 }
2076 }
2077 assert(rk == nc); // must have full rank
2078 index = Iabs(index);
2079 return index;
2080 }
2081
2082 #ifdef ENFNORMALIZ
2083 template <>
full_rank_index(bool & success)2084 renf_elem_class Matrix<renf_elem_class>::full_rank_index(bool& success) {
2085
2086 assert(false);
2087 return 0;
2088 }
2089 /* body
2090 size_t rk = row_echelon_inner_elem(success);
2091 renf_elem_class index = 1;
2092 if (success) {
2093 for (size_t i = 0; i < rk; ++i) {
2094 index *= elem[i][i];
2095 if (!check_range(index)) {
2096 success = false;
2097 index = 0;
2098 return index;
2099 }
2100 }
2101 }
2102 assert(rk == nc); // must have full rank
2103 index = Iabs(index);
2104 return index;
2105 }
2106 */
2107 #endif
2108 //---------------------------------------------------------------------------
2109
2110 template <typename Integer>
row_column_trigonalize(size_t & rk,bool & success)2111 Matrix<Integer> Matrix<Integer>::row_column_trigonalize(size_t& rk, bool& success) {
2112 Matrix<Integer> Right(nc);
2113 rk = row_echelon_reduce(success);
2114 if (success)
2115 success = column_trigonalize(rk, Right);
2116 return Right;
2117 }
2118
2119 //---------------------------------------------------------------------------
2120
2121 template <typename Integer>
row_echelon(bool & success,bool do_compute_vol,Integer & det)2122 size_t Matrix<Integer>::row_echelon(bool& success, bool do_compute_vol, Integer& det) {
2123 /* if(using_GMP<Integer>()){
2124 return row_echelon_inner_bareiss(success,det);;
2125 }
2126 else{ */
2127 size_t rk = row_echelon_inner_elem(success);
2128 if (do_compute_vol)
2129 det = compute_vol(success);
2130 return rk;
2131 // }
2132 }
2133
2134 //---------------------------------------------------------------------------
2135
2136 template <typename Integer>
row_echelon(bool & success)2137 size_t Matrix<Integer>::row_echelon(bool& success) {
2138 static Integer dummy;
2139 return row_echelon(success, false, dummy);
2140 }
2141
2142 //---------------------------------------------------------------------------
2143
2144 template <typename Integer>
row_echelon(bool & success,Integer & det)2145 size_t Matrix<Integer>::row_echelon(bool& success, Integer& det) {
2146 return row_echelon(success, true, det);
2147 }
2148
2149 //---------------------------------------------------------------------------
2150
2151 template <typename Integer>
rank_submatrix(const Matrix<Integer> & mother,const vector<key_t> & key)2152 size_t Matrix<Integer>::rank_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key) {
2153
2154 assert(nc >= mother.nc);
2155 if (nr < key.size()) {
2156 elem.resize(key.size(), vector<Integer>(nc, 0));
2157 nr = key.size();
2158 }
2159 size_t save_nr = nr;
2160 size_t save_nc = nc;
2161 nr = key.size();
2162 nc = mother.nc;
2163
2164 select_submatrix(mother, key);
2165
2166 bool success;
2167 size_t rk = row_echelon(success);
2168
2169 if (!success) {
2170 Matrix<mpz_class> mpz_this(nr, nc);
2171 mpz_submatrix(mpz_this, mother, key);
2172 rk = mpz_this.row_echelon(success);
2173 }
2174
2175 nr = save_nr;
2176 nc = save_nc;
2177 return rk;
2178 }
2179
2180
2181 template <>
rank_submatrix(const Matrix<mpq_class> & mother,const vector<key_t> & key)2182 size_t Matrix<mpq_class>::rank_submatrix(const Matrix<mpq_class>& mother, const vector<key_t>& key) {
2183
2184 assert(false);
2185 return 0;
2186 }
2187 /* body
2188 assert(nc >= mother.nc);
2189 if (nr < key.size()) {
2190 elem.resize(key.size(), vector<mpq_class>(nc, 0));
2191 nr = key.size();
2192 }
2193 size_t save_nr = nr;
2194 size_t save_nc = nc;
2195 nr = key.size();
2196 nc = mother.nc;
2197
2198 select_submatrix(mother, key);
2199
2200 bool success;
2201 size_t rk = row_echelon(success);
2202
2203 nr = save_nr;
2204 nc = save_nc;
2205 return rk;
2206 }
2207 */
2208
2209 /*
2210 void flint_mat_select(fmpz_mat_t fmat, const Matrix<mpz_class>& nmz_mat,const vector<key_t>& key ){
2211
2212 for(size_t i=0;i<key.size();++i)
2213 for(size_t j=0;j<nmz_mat.nr_of_columns();++j)
2214 fmpz_set_mpz(fmpz_mat_entry(fmat, (slong) i, (slong) j),nmz_mat[key[i]][j].get_mpz_t());
2215 }
2216
2217 void flint_mat(fmpz_mat_t fmat, const Matrix<mpz_class>& nmz_mat){
2218
2219 for(size_t i=0;i<nmz_mat.nr_of_rows();++i)
2220 for(size_t j=0;j<nmz_mat.nr_of_columns();++j)
2221 fmpz_set_mpz(fmpz_mat_entry(fmat, (slong) i, (slong)j),nmz_mat[i][j].get_mpz_t());
2222 }
2223
2224
2225 void nmz_mat(Matrix<mpz_class>& nmz_mat, const fmpz_mat_t fmat){
2226
2227 size_t r=fmpz_mat_nrows(fmat);
2228 size_t c=fmpz_mat_ncols(fmat);
2229 nmz_mat.resize(r,c);
2230 mpz_t t;
2231 mpz_init(t);
2232 for(size_t i=0;i<r;++i)
2233 for(size_t j=0;j<c;++j){
2234 fmpz_get_mpz(t,fmpz_mat_entry(fmat, (slong) i, (slong)j));
2235 nmz_mat[i][j]=mpz_class(t);
2236 }
2237 mpz_clear(t);
2238 }
2239
2240 */
2241 /*
2242 * fmpz_get_mpz(t,f)
2243 * fmpz_set_mpz(f,t)
2244 */
2245 //---------------------------------------------------------------------------
2246
2247 /*
2248 template<>
2249 size_t Matrix<mpz_class>::rank_submatrix(const Matrix<mpz_class>& mother, const vector<key_t>& key){
2250
2251 assert(nc>=mother.nc);
2252 if(nr<key.size()){
2253 elem.resize(key.size(),vector<mpz_class>(nc,0));
2254 nr=key.size();
2255 }
2256 size_t save_nr=nr;
2257 size_t save_nc=nc;
2258 nr=key.size();
2259 nc=mother.nc;
2260
2261 fmpz_mat_t fmat;
2262 fmpz_mat_init(fmat, (slong) nr, (slong) nc);
2263 flint_mat_select(fmat,mother,key);
2264 // flint_mat_select(fmat,*this);
2265 size_t rk= (size_t) fmpz_mat_rank(fmat);
2266 fmpz_mat_clear(fmat);
2267
2268
2269 nr=save_nr;
2270 nc=save_nc;
2271 return rk;
2272 } */
2273
2274 //---------------------------------------------------------------------------
2275
2276 template <typename Integer>
rank_submatrix(const vector<key_t> & key) const2277 size_t Matrix<Integer>::rank_submatrix(const vector<key_t>& key) const {
2278 Matrix<Integer> work(key.size(), nc);
2279 return work.rank_submatrix(*this, key);
2280 }
2281
2282 //---------------------------------------------------------------------------
2283
2284 template <typename Integer>
rank() const2285 size_t Matrix<Integer>::rank() const {
2286 vector<key_t> key(nr);
2287 for (size_t i = 0; i < nr; ++i)
2288 key[i] = i;
2289 return rank_submatrix(key);
2290 }
2291
2292 //---------------------------------------------------------------------------
2293
2294 template <typename Integer>
vol_submatrix(const Matrix<Integer> & mother,const vector<key_t> & key)2295 Integer Matrix<Integer>::vol_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key) {
2296 assert(nc >= mother.nc);
2297 if (nr < key.size()) {
2298 elem.resize(key.size(), vector<Integer>(nc, 0));
2299 nr = key.size();
2300 }
2301 size_t save_nr = nr;
2302 size_t save_nc = nc;
2303 nr = key.size();
2304 nc = mother.nc;
2305
2306 select_submatrix(mother, key);
2307
2308 bool success;
2309 Integer det;
2310 row_echelon(success, det);
2311
2312 if (!success) {
2313 Matrix<mpz_class> mpz_this(nr, nc);
2314 mpz_submatrix(mpz_this, mother, key);
2315 mpz_class mpz_det;
2316 mpz_this.row_echelon(success, mpz_det);
2317 convert(det, mpz_det);
2318 }
2319
2320 nr = save_nr;
2321 nc = save_nc;
2322 return det;
2323 }
2324
2325 template <>
vol_submatrix(const Matrix<mpq_class> & mother,const vector<key_t> & key)2326 mpq_class Matrix<mpq_class>::vol_submatrix(const Matrix<mpq_class>& mother, const vector<key_t>& key) {
2327
2328 assert(false);
2329 return {};
2330 }
2331 /* body
2332 assert(nc >= mother.nc);
2333 if (nr < key.size()) {
2334 elem.resize(key.size(), vector<mpq_class>(nc, 0));
2335 nr = key.size();
2336 }
2337 size_t save_nr = nr;
2338 size_t save_nc = nc;
2339 nr = key.size();
2340 nc = mother.nc;
2341
2342 select_submatrix(mother, key);
2343
2344 bool success;
2345 mpq_class det;
2346 row_echelon(success, det);
2347
2348 nr = save_nr;
2349 nc = save_nc;
2350 return det;
2351 }
2352 */
2353
2354 #ifdef ENFNORMALIZ
2355 template <>
vol_submatrix(const Matrix<renf_elem_class> & mother,const vector<key_t> & key)2356 renf_elem_class Matrix<renf_elem_class>::vol_submatrix(const Matrix<renf_elem_class>& mother, const vector<key_t>& key) {
2357
2358 assert(nc >= mother.nc);
2359 if (nr < key.size()) {
2360 elem.resize(key.size(), vector<renf_elem_class>(nc, 0));
2361 nr = key.size();
2362 }
2363 size_t save_nr = nr;
2364 size_t save_nc = nc;
2365 nr = key.size();
2366 nc = mother.nc;
2367
2368 select_submatrix(mother, key);
2369
2370 bool success;
2371 renf_elem_class det;
2372 row_echelon(success, det);
2373
2374 nr = save_nr;
2375 nc = save_nc;
2376 return det;
2377 }
2378 #endif
2379
2380 //---------------------------------------------------------------------------
2381
2382 template <typename Integer>
vol_submatrix(const vector<key_t> & key) const2383 Integer Matrix<Integer>::vol_submatrix(const vector<key_t>& key) const {
2384 Matrix<Integer> work(key.size(), nc);
2385 return work.vol_submatrix(*this, key);
2386 }
2387
2388 //---------------------------------------------------------------------------
2389
2390 template <typename Integer>
vol() const2391 Integer Matrix<Integer>::vol() const {
2392 vector<key_t> key(nr);
2393 for (size_t i = 0; i < nr; ++i)
2394 key[i] = i;
2395 return vol_submatrix(key);
2396 }
2397
2398 //---------------------------------------------------------------------------
2399
2400 template <typename Integer>
max_rank_submatrix_lex_inner(bool & success,vector<key_t> perm) const2401 vector<key_t> Matrix<Integer>::max_rank_submatrix_lex_inner(bool& success, vector<key_t> perm) const {
2402 success = true;
2403 size_t max_rank = min(nr, nc);
2404 Matrix<Integer> Test(max_rank, nc);
2405 Test.nr = 0;
2406 vector<key_t> col;
2407 col.reserve(max_rank);
2408 vector<key_t> key;
2409 key.reserve(max_rank);
2410 size_t rk = 0;
2411
2412 bool perm_set = false;
2413 if (perm.size() > 0)
2414 perm_set = true;
2415
2416 vector<vector<bool> > col_done(max_rank, vector<bool>(nc, false));
2417
2418 vector<Integer> Test_vec(nc);
2419
2420 for (size_t i = 0; i < nr; ++i) {
2421 if (perm_set)
2422 Test_vec = elem[perm[i]];
2423 else
2424 Test_vec = elem[i];
2425 for (size_t k = 0; k < rk; ++k) {
2426 if (Test_vec[col[k]] == 0)
2427 continue;
2428 Integer a = Test[k][col[k]];
2429 Integer b = Test_vec[col[k]];
2430 for (size_t j = 0; j < nc; ++j)
2431 if (!col_done[k][j]) {
2432 Test_vec[j] = a * Test_vec[j] - b * Test[k][j];
2433 if (!check_range(Test_vec[j])) {
2434 success = false;
2435 return key;
2436 }
2437 }
2438 }
2439
2440 size_t j = 0;
2441 for (; j < nc; ++j)
2442 if (Test_vec[j] != 0)
2443 break;
2444 if (j == nc) // Test_vec=0
2445 continue;
2446
2447 col.push_back(j);
2448 if (perm_set)
2449 key.push_back(perm[i]);
2450 else
2451 key.push_back(i);
2452
2453 if (rk > 0) {
2454 col_done[rk] = col_done[rk - 1];
2455 col_done[rk][col[rk - 1]] = true;
2456 }
2457
2458 Test.nr++;
2459 rk++;
2460 v_make_prime(Test_vec);
2461 Test[rk - 1] = Test_vec;
2462
2463 if (rk == max_rank)
2464 break;
2465 }
2466 return key;
2467 }
2468
2469 //---------------------------------------------------------------------------
2470 // perm allows a reordering of the matrix
2471 // vectors are inserted into the test according to the order given by perm
2472 template <typename Integer>
max_rank_submatrix_lex(vector<key_t> perm) const2473 vector<key_t> Matrix<Integer>::max_rank_submatrix_lex(vector<key_t> perm) const {
2474 bool success;
2475 vector<key_t> key = max_rank_submatrix_lex_inner(success);
2476 if (!success) {
2477 Matrix<mpz_class> mpz_this(nr, nc);
2478 mat_to_mpz(*this, mpz_this);
2479 key = mpz_this.max_rank_submatrix_lex_inner(success);
2480 }
2481 return key;
2482 }
2483
2484 //---------------------------------------------------------------------------
2485
2486 template <typename Integer>
solve_destructive_inner(bool ZZinvertible,Integer & denom)2487 bool Matrix<Integer>::solve_destructive_inner(bool ZZinvertible, Integer& denom) {
2488 assert(nc >= nr);
2489 bool success = true; // to make gcc happy
2490
2491 size_t rk;
2492
2493 if (ZZinvertible) {
2494 rk = row_echelon_inner_elem(success);
2495 if (!success)
2496 return false;
2497 assert(rk == nr);
2498 denom = compute_vol(success);
2499 }
2500 else {
2501 rk = row_echelon(success, denom);
2502 if (!success)
2503 return false;
2504 }
2505
2506 if (denom == 0) {
2507 if (using_GMP<Integer>() || using_renf<Integer>()) {
2508 errorOutput() << "Cannot solve system (denom=0)!" << endl;
2509 throw ArithmeticException();
2510 }
2511 else
2512 return false;
2513 }
2514
2515 if (!using_renf<Integer>()) {
2516 for (int i = nr - 1; i >= 0; --i) {
2517 for (size_t j = nr; j < nc; ++j) {
2518 elem[i][j] *= denom;
2519 if (!check_range(elem[i][j]))
2520 return false;
2521 }
2522 for (int k = i + 1; k < (int)nr; ++k) {
2523 for (size_t j = nr; j < nc; ++j) {
2524 elem[i][j] -= elem[i][k] * elem[k][j];
2525 if (!check_range(elem[i][j]))
2526 return false;
2527 }
2528 }
2529 for (size_t j = nr; j < nc; ++j)
2530 elem[i][j] /= elem[i][i];
2531 }
2532 }
2533 else { // we can divide in this case, somewhat faster
2534
2535 // make pivot elemnst 1 and multiply RHS by denom as in the case with
2536 // integer types for uniform behavior
2537 Integer fact, help;
2538 for (int i = nr - 1; i >= 0; --i) {
2539 fact = 1 / elem[i][i];
2540 Integer fact_times_denom = fact * denom;
2541 for (size_t j = i; j < nr; ++j)
2542 if (elem[i][j] != 0) elem[i][j] *= fact;
2543 for (size_t j = nr; j < nc; ++j)
2544 if (elem[i][j] != 0) elem[i][j] *= fact_times_denom;
2545 }
2546 for (int i = nr - 1; i >= 0; --i) {
2547 for (int k = i - 1; k >= 0; --k) {
2548 if (elem[k][i] != 0) {
2549 fact = elem[k][i];
2550 for (size_t j = i; j < nc; ++j){
2551 if (elem[i][j] != 0) {
2552 help = elem[i][j];
2553 help *= fact;
2554 elem[k][j] -= help;
2555 }
2556 }
2557 }
2558 }
2559 }
2560 }
2561
2562 return true;
2563 }
2564
2565 //---------------------------------------------------------------------------
2566
2567 template <typename Integer>
customize_solution(size_t dim,Integer & denom,size_t red_col,size_t sign_col,bool make_sol_prime)2568 void Matrix<Integer>::customize_solution(size_t dim, Integer& denom, size_t red_col, size_t sign_col, bool make_sol_prime) {
2569 assert(!(make_sol_prime && (sign_col > 0 || red_col > 0)));
2570
2571 for (size_t j = 0; j < red_col; ++j) { // reduce first red_col columns of solution mod denom
2572 for (size_t k = 0; k < dim; ++k) {
2573 elem[k][dim + j] %= denom;
2574 if (elem[k][dim + j] < 0)
2575 elem[k][dim + j] += Iabs(denom);
2576 }
2577 }
2578
2579 for (size_t j = 0; j < sign_col; ++j) // replace entries in the next sign_col columns by their signs
2580 for (size_t k = 0; k < dim; ++k) {
2581 if (elem[k][dim + red_col + j] > 0) {
2582 elem[k][dim + red_col + j] = 1;
2583 continue;
2584 }
2585 if (elem[k][dim + red_col + j] < 0) {
2586 elem[k][dim + red_col + j] = -1;
2587 continue;
2588 }
2589 }
2590
2591 if (make_sol_prime) // make columns of solution coprime if wanted
2592 make_cols_prime(dim, nc - 1);
2593 }
2594
2595 #ifdef ENFNORMALIZ
2596 template <>
customize_solution(size_t dim,renf_elem_class & denom,size_t red_col,size_t sign_col,bool make_sol_prime)2597 void Matrix<renf_elem_class>::customize_solution(
2598 size_t dim, renf_elem_class& denom, size_t red_col, size_t sign_col, bool make_sol_prime) {
2599 return;
2600 }
2601 #endif
2602
2603 template <>
customize_solution(size_t dim,mpq_class & denom,size_t red_col,size_t sign_col,bool make_sol_prime)2604 void Matrix<mpq_class>::customize_solution(size_t dim, mpq_class& denom, size_t red_col, size_t sign_col, bool make_sol_prime) {
2605 return;
2606 }
2607
2608 //---------------------------------------------------------------------------
2609
2610 template <>
customize_solution(size_t dim,nmz_float & denom,size_t red_col,size_t sign_col,bool make_sol_prime)2611 void Matrix<nmz_float>::customize_solution(size_t dim, nmz_float& denom, size_t red_col, size_t sign_col, bool make_sol_prime) {
2612 assert(false);
2613 }
2614
2615 //---------------------------------------------------------------------------
2616
2617 template <typename Integer>
solve_system_submatrix_outer(const Matrix<Integer> & mother,const vector<key_t> & key,const vector<vector<Integer> * > & RS,Integer & denom,bool ZZ_invertible,bool transpose,size_t red_col,size_t sign_col,bool compute_denom,bool make_sol_prime)2618 void Matrix<Integer>::solve_system_submatrix_outer(const Matrix<Integer>& mother,
2619 const vector<key_t>& key,
2620 const vector<vector<Integer>*>& RS,
2621 Integer& denom,
2622 bool ZZ_invertible,
2623 bool transpose,
2624 size_t red_col,
2625 size_t sign_col,
2626 bool compute_denom,
2627 bool make_sol_prime) {
2628 size_t dim = mother.nc;
2629 assert(key.size() == dim);
2630 assert(nr == dim);
2631 assert(dim + RS.size() <= nc);
2632 size_t save_nc = nc;
2633 nc = dim + RS.size();
2634
2635 if (transpose)
2636 select_submatrix_trans(mother, key);
2637 else
2638 select_submatrix(mother, key);
2639
2640 for (size_t i = 0; i < dim; ++i)
2641 for (size_t k = 0; k < RS.size(); ++k)
2642 elem[i][k + dim] = (*RS[k])[i];
2643
2644 if (solve_destructive_inner(ZZ_invertible, denom)) {
2645 customize_solution(dim, denom, red_col, sign_col, make_sol_prime);
2646 }
2647 else {
2648 #pragma omp atomic
2649 GMP_mat++;
2650
2651 Matrix<mpz_class> mpz_this(nr, nc);
2652 mpz_class mpz_denom;
2653 if (transpose)
2654 mpz_submatrix_trans(mpz_this, mother, key);
2655 else
2656 mpz_submatrix(mpz_this, mother, key);
2657
2658 for (size_t i = 0; i < dim; ++i)
2659 for (size_t k = 0; k < RS.size(); ++k)
2660 convert(mpz_this[i][k + dim], (*RS[k])[i]);
2661 mpz_this.solve_destructive_inner(ZZ_invertible, mpz_denom);
2662 mpz_this.customize_solution(dim, mpz_denom, red_col, sign_col, make_sol_prime);
2663
2664 for (size_t i = 0; i < dim; ++i) // replace left side by 0, except diagonal if ZZ_invetible
2665 for (size_t j = 0; j < dim; ++j) {
2666 if (i != j || !ZZ_invertible)
2667 mpz_this[i][j] = 0;
2668 }
2669
2670 mat_to_Int(mpz_this, *this);
2671 if (compute_denom)
2672 convert(denom, mpz_denom);
2673 }
2674 nc = save_nc;
2675 }
2676
2677 template <>
solve_system_submatrix_outer(const Matrix<mpq_class> & mother,const vector<key_t> & key,const vector<vector<mpq_class> * > & RS,mpq_class & denom,bool ZZ_invertible,bool transpose,size_t red_col,size_t sign_col,bool compute_denom,bool make_sol_prime)2678 void Matrix<mpq_class>::solve_system_submatrix_outer(const Matrix<mpq_class>& mother,
2679 const vector<key_t>& key,
2680 const vector<vector<mpq_class>*>& RS,
2681 mpq_class& denom,
2682 bool ZZ_invertible,
2683 bool transpose,
2684 size_t red_col,
2685 size_t sign_col,
2686 bool compute_denom,
2687 bool make_sol_prime) {
2688 assert(false);
2689 }
2690
2691 #ifdef ENFNORMALIZ
2692 template <>
solve_system_submatrix_outer(const Matrix<renf_elem_class> & mother,const vector<key_t> & key,const vector<vector<renf_elem_class> * > & RS,renf_elem_class & denom,bool ZZ_invertible,bool transpose,size_t red_col,size_t sign_col,bool compute_denom,bool make_sol_prime)2693 void Matrix<renf_elem_class>::solve_system_submatrix_outer(const Matrix<renf_elem_class>& mother,
2694 const vector<key_t>& key,
2695 const vector<vector<renf_elem_class>*>& RS,
2696 renf_elem_class& denom,
2697 bool ZZ_invertible,
2698 bool transpose,
2699 size_t red_col,
2700 size_t sign_col,
2701 bool compute_denom,
2702 bool make_sol_prime) {
2703 size_t dim = mother.nc;
2704 assert(key.size() == dim);
2705 assert(nr == dim);
2706 assert(dim + RS.size() <= nc);
2707 size_t save_nc = nc;
2708 nc = dim + RS.size();
2709
2710 if (transpose)
2711 select_submatrix_trans(mother, key);
2712 else
2713 select_submatrix(mother, key);
2714
2715 for (size_t i = 0; i < dim; ++i)
2716 for (size_t k = 0; k < RS.size(); ++k)
2717 elem[i][k + dim] = (*RS[k])[i];
2718
2719 if (solve_destructive_inner(ZZ_invertible, denom)) {
2720 customize_solution(dim, denom, red_col, sign_col, make_sol_prime);
2721 }
2722 nc = save_nc;
2723 }
2724 #endif
2725
2726 //---------------------------------------------------------------------------
2727
2728 template <typename Integer>
solve_system_submatrix(const Matrix<Integer> & mother,const vector<key_t> & key,const vector<vector<Integer> * > & RS,vector<Integer> & diagonal,Integer & denom,size_t red_col,size_t sign_col)2729 void Matrix<Integer>::solve_system_submatrix(const Matrix<Integer>& mother,
2730 const vector<key_t>& key,
2731 const vector<vector<Integer>*>& RS,
2732 vector<Integer>& diagonal,
2733 Integer& denom,
2734 size_t red_col,
2735 size_t sign_col) {
2736 solve_system_submatrix_outer(mother, key, RS, denom, true, false, red_col, sign_col);
2737 assert(diagonal.size() == nr);
2738 for (size_t i = 0; i < nr; ++i)
2739 diagonal[i] = elem[i][i];
2740 }
2741
2742 //---------------------------------------------------------------------------
2743 // the same without diagonal
2744 template <typename Integer>
solve_system_submatrix(const Matrix<Integer> & mother,const vector<key_t> & key,const vector<vector<Integer> * > & RS,Integer & denom,size_t red_col,size_t sign_col,bool compute_denom,bool make_sol_prime)2745 void Matrix<Integer>::solve_system_submatrix(const Matrix<Integer>& mother,
2746 const vector<key_t>& key,
2747 const vector<vector<Integer>*>& RS,
2748 Integer& denom,
2749 size_t red_col,
2750 size_t sign_col,
2751 bool compute_denom,
2752 bool make_sol_prime) {
2753 solve_system_submatrix_outer(mother, key, RS, denom, false, false, red_col, sign_col, compute_denom, make_sol_prime);
2754 }
2755
2756 //---------------------------------------------------------------------------
2757
2758 template <typename Integer>
solve_system_submatrix_trans(const Matrix<Integer> & mother,const vector<key_t> & key,const vector<vector<Integer> * > & RS,Integer & denom,size_t red_col,size_t sign_col)2759 void Matrix<Integer>::solve_system_submatrix_trans(const Matrix<Integer>& mother,
2760 const vector<key_t>& key,
2761 const vector<vector<Integer>*>& RS,
2762 Integer& denom,
2763 size_t red_col,
2764 size_t sign_col) {
2765 solve_system_submatrix_outer(mother, key, RS, denom, false, true, red_col, sign_col);
2766 }
2767
2768 //---------------------------------------------------------------------------
2769
2770 template <typename Integer>
extract_solution() const2771 Matrix<Integer> Matrix<Integer>::extract_solution() const {
2772 assert(nc >= nr);
2773 Matrix<Integer> Solution(nr, nc - nr);
2774 for (size_t i = 0; i < nr; ++i) {
2775 for (size_t j = 0; j < Solution.nc; ++j)
2776 Solution[i][j] = elem[i][j + nr];
2777 }
2778 return Solution;
2779 }
2780
2781 //---------------------------------------------------------------------------
2782
2783 template <typename Integer>
row_pointers()2784 vector<vector<Integer>*> Matrix<Integer>::row_pointers() {
2785 vector<vector<Integer>*> pointers(nr);
2786 for (size_t i = 0; i < nr; ++i)
2787 pointers[i] = &(elem[i]);
2788 return pointers;
2789 }
2790
2791 //---------------------------------------------------------------------------
2792
2793 template <typename Integer>
submatrix_pointers(const vector<key_t> & key)2794 vector<vector<Integer>*> Matrix<Integer>::submatrix_pointers(const vector<key_t>& key) {
2795 vector<vector<Integer>*> pointers(key.size());
2796 for (size_t i = 0; i < key.size(); ++i)
2797 pointers[i] = &(elem[key[i]]);
2798 return pointers;
2799 }
2800 //---------------------------------------------------------------------------
2801
2802 /* not used at present
2803 template <typename Integer>
2804 Matrix<Integer> Matrix<Integer>::solve(const Matrix<Integer>& Right_side, vector<Integer>& diagonal, Integer& denom) const {
2805 Matrix<Integer> M(nr, nc + Right_side.nc);
2806 vector<key_t> key = identity_key(nr);
2807 Matrix<Integer> RS_trans = Right_side.transpose();
2808 vector<vector<Integer>*> RS = RS_trans.row_pointers();
2809 M.solve_system_submatrix(*this, key, RS, diagonal, denom, 0, 0);
2810 return M.extract_solution();
2811 }
2812 */
2813
2814 //---------------------------------------------------------------------------
2815
2816 template <typename Integer>
solve(const Matrix<Integer> & Right_side,Integer & denom) const2817 Matrix<Integer> Matrix<Integer>::solve(const Matrix<Integer>& Right_side, Integer& denom) const {
2818 Matrix<Integer> M(nr, nc + Right_side.nc);
2819 vector<key_t> key = identity_key(nr);
2820 Matrix<Integer> RS_trans = Right_side.transpose();
2821 vector<vector<Integer>*> RS = RS_trans.row_pointers();
2822 M.solve_system_submatrix(*this, key, RS, denom, 0, 0);
2823 return M.extract_solution();
2824 }
2825
2826 //---------------------------------------------------------------------------
2827
2828 template <typename Integer>
invert(Integer & denom) const2829 Matrix<Integer> Matrix<Integer>::invert(Integer& denom) const {
2830 assert(nr == nc);
2831 Matrix<Integer> Right_side(nr);
2832
2833 return solve(Right_side, denom);
2834 }
2835
2836 //---------------------------------------------------------------------------
2837
2838 template <typename Integer>
bundle_matrices(const Matrix<Integer> & Right_side) const2839 Matrix<Integer> Matrix<Integer>::bundle_matrices(const Matrix<Integer>& Right_side) const {
2840 assert(nr == nc);
2841 assert(nc == Right_side.nr);
2842 Matrix<Integer> M(nr, nc + Right_side.nc);
2843 for (size_t i = 0; i < nr; ++i) {
2844 for (size_t j = 0; j < nc; ++j)
2845 M[i][j] = elem[i][j];
2846 for (size_t j = nc; j < M.nc; ++j)
2847 M[i][j] = Right_side[i][j - nc];
2848 }
2849 return M;
2850 }
2851 //---------------------------------------------------------------------------
2852
2853 template <typename Integer>
invert_unprotected(Integer & denom,bool & success) const2854 Matrix<Integer> Matrix<Integer>::invert_unprotected(Integer& denom, bool& success) const {
2855 assert(nr == nc);
2856 Matrix<Integer> Right_side(nr);
2857 Matrix<Integer> M = bundle_matrices(Right_side);
2858 success = M.solve_destructive_inner(false, denom);
2859 return M.extract_solution();
2860 ;
2861 }
2862
2863 //---------------------------------------------------------------------------
2864
2865 template <typename Integer>
invert_submatrix(const vector<key_t> & key,Integer & denom,Matrix<Integer> & Inv,bool compute_denom,bool make_sol_prime) const2866 void Matrix<Integer>::invert_submatrix(
2867 const vector<key_t>& key, Integer& denom, Matrix<Integer>& Inv, bool compute_denom, bool make_sol_prime) const {
2868 assert(key.size() == nc);
2869 Matrix<Integer> unit_mat(key.size());
2870 Matrix<Integer> M(key.size(), 2 * key.size());
2871 vector<vector<Integer>*> RS_pointers = unit_mat.row_pointers();
2872 M.solve_system_submatrix(*this, key, RS_pointers, denom, 0, 0, compute_denom, make_sol_prime);
2873 Inv = M.extract_solution();
2874 }
2875
2876 template <typename Integer>
invert_submatrix(const vector<key_t> & key,Integer & denom,Matrix<Integer> & Inv,Matrix<Integer> & Work,Matrix<Integer> & UnitMat,bool compute_denom,bool make_sol_prime) const2877 void Matrix<Integer>::invert_submatrix(
2878 const vector<key_t>& key, Integer& denom, Matrix<Integer>& Inv, Matrix<Integer>& Work,
2879 Matrix<Integer>& UnitMat, bool compute_denom, bool make_sol_prime) const {
2880 assert(key.size() == nc);
2881 // cout << "WWWWWWWWWWW " << key.size() << " -- " << Work.nr << " " << Work.nc << endl;
2882 assert(Work.nr == key.size());
2883 assert(Work.nc == 2*key.size());
2884 assert(UnitMat.nc == key.size());
2885
2886 vector<vector<Integer>*> RS_pointers = UnitMat.row_pointers();
2887 Work.solve_system_submatrix(*this, key, RS_pointers, denom, 0, 0, compute_denom, make_sol_prime);
2888 Inv = Work.extract_solution();
2889 }
2890
2891 //---------------------------------------------------------------------------
2892
2893 template <typename Integer>
simplex_data(const vector<key_t> & key,Matrix<Integer> & Supp,Integer & vol,bool compute_vol) const2894 void Matrix<Integer>::simplex_data(const vector<key_t>& key, Matrix<Integer>& Supp, Integer& vol, bool compute_vol) const {
2895 assert(key.size() == nc);
2896 invert_submatrix(key, vol, Supp, compute_vol, true);
2897 // Supp=Supp.transpose();
2898 Supp.transpose_in_place();
2899 // Supp.make_prime(); now done internally
2900 }
2901
2902 template <typename Integer>
simplex_data(const vector<key_t> & key,Matrix<Integer> & Supp,Integer & vol,Matrix<Integer> & Work,Matrix<Integer> & UnitMat,bool compute_vol) const2903 void Matrix<Integer>::simplex_data(const vector<key_t>& key, Matrix<Integer>& Supp, Integer& vol,
2904 Matrix<Integer>& Work, Matrix<Integer>& UnitMat, bool compute_vol) const {
2905 assert(key.size() == nc);
2906 // cout << "WWWWWWWWWWW " << key.size() << " -- " << Work.nr << " " << Work.nc << endl;
2907 invert_submatrix(key, vol, Supp, Work, UnitMat,compute_vol, true);
2908 // Supp=Supp.transpose();
2909 Supp.transpose_in_place();
2910 // Supp.make_prime(); now done internally
2911 }
2912 //---------------------------------------------------------------------------
2913
2914 template <typename Integer>
solve_rectangular(const vector<Integer> & v,Integer & denom) const2915 vector<Integer> Matrix<Integer>::solve_rectangular(const vector<Integer>& v, Integer& denom) const {
2916 if (nc == 0 || nr == 0) { // return zero-vector as solution
2917 return vector<Integer>(nc, 0);
2918 }
2919 size_t i;
2920 vector<key_t> rows = max_rank_submatrix_lex();
2921 Matrix<Integer> Left_Side = submatrix(rows);
2922 assert(nc == Left_Side.nr); // otherwise input hadn't full rank //TODO
2923 Matrix<Integer> Right_Side(v.size(), 1);
2924 Right_Side.write_column(0, v);
2925 Right_Side = Right_Side.submatrix(rows);
2926 Matrix<Integer> Solution = Left_Side.solve(Right_Side, denom);
2927 vector<Integer> Linear_Form(nc);
2928 for (i = 0; i < nc; i++) {
2929 Linear_Form[i] = Solution[i][0]; // the solution vector is called Linear_Form
2930 }
2931 vector<Integer> test = MxV(Linear_Form); // we have solved the system by taking a square submatrix
2932 // now we must test whether the solution satisfies the full system
2933 for (i = 0; i < nr; i++) {
2934 if (test[i] != denom * v[i]) {
2935 return vector<Integer>();
2936 }
2937 }
2938 Integer total_gcd = libnormaliz::gcd(denom, v_gcd(Linear_Form)); // extract the gcd of denom and solution
2939 denom /= total_gcd;
2940 v_scalar_division(Linear_Form, total_gcd);
2941 return Linear_Form;
2942 }
2943
2944 template <>
solve_rectangular(const vector<mpq_class> & v,mpq_class & denom) const2945 vector<mpq_class> Matrix<mpq_class>::solve_rectangular(const vector<mpq_class>& v, mpq_class& denom) const {
2946
2947 assert(false);
2948 return {};
2949 }
2950
2951 /* body
2952 if (nc == 0 || nr == 0) { // return zero-vector as solution
2953 return vector<mpq_class>(nc, 0);
2954 }
2955 size_t i;
2956 vector<key_t> rows = max_rank_submatrix_lex();
2957 Matrix<mpq_class> Left_Side = submatrix(rows);
2958 assert(nc == Left_Side.nr); // otherwise input hadn't full rank //TODO
2959 Matrix<mpq_class> Right_Side(v.size(), 1);
2960 Right_Side.write_column(0, v);
2961 Right_Side = Right_Side.submatrix(rows);
2962 Matrix<mpq_class> Solution = Left_Side.solve(Right_Side, denom);
2963 vector<mpq_class> Linear_Form(nc);
2964 for (i = 0; i < nc; i++) {
2965 Linear_Form[i] = Solution[i][0]; // the solution vector is called Linear_Form
2966 }
2967 vector<mpq_class> test = MxV(Linear_Form); // we have solved the system by taking a square submatrix
2968 // now we must test whether the solution satisfies the full system
2969 for (i = 0; i < nr; i++) {
2970 if (test[i] != denom * v[i]) {
2971 return vector<mpq_class>();
2972 }
2973 }
2974 mpq_class total_gcd = 1; // libnormaliz::gcd(denom,v_gcd(Linear_Form)); // extract the gcd of denom and solution
2975 denom /= total_gcd;
2976 v_scalar_division(Linear_Form, total_gcd);
2977 return Linear_Form;
2978 }
2979 */
2980
2981 #ifdef ENFNORMALIZ
2982 template <>
solve_rectangular(const vector<renf_elem_class> & v,renf_elem_class & denom) const2983 vector<renf_elem_class> Matrix<renf_elem_class>::solve_rectangular(const vector<renf_elem_class>& v,
2984 renf_elem_class& denom) const {
2985 if (nc == 0 || nr == 0) { // return zero-vector as solution
2986 return vector<renf_elem_class>(nc, 0);
2987 }
2988 size_t i;
2989 vector<key_t> rows = max_rank_submatrix_lex();
2990 Matrix<renf_elem_class> Left_Side = submatrix(rows);
2991 assert(nc == Left_Side.nr); // otherwise input hadn't full rank //TODO
2992 Matrix<renf_elem_class> Right_Side(v.size(), 1);
2993 Right_Side.write_column(0, v);
2994 Right_Side = Right_Side.submatrix(rows);
2995 Matrix<renf_elem_class> Solution = Left_Side.solve(Right_Side, denom);
2996 vector<renf_elem_class> Linear_Form(nc);
2997 for (i = 0; i < nc; i++) {
2998 Linear_Form[i] = Solution[i][0]; // the solution vector is called Linear_Form
2999 }
3000 vector<renf_elem_class> test = MxV(Linear_Form); // we have solved the system by taking a square submatrix
3001 // now we must test whether the solution satisfies the full system
3002 for (i = 0; i < nr; i++) {
3003 if (test[i] != denom * v[i]) {
3004 return vector<renf_elem_class>();
3005 }
3006 }
3007 renf_elem_class total_gcd = 1; // libnormaliz::gcd(denom,v_gcd(Linear_Form)); // extract the gcd of denom and solution
3008 denom /= total_gcd;
3009 v_scalar_division(Linear_Form, total_gcd);
3010 return Linear_Form;
3011 }
3012 #endif
3013
3014 //---------------------------------------------------------------------------
3015
3016 template <typename Integer>
solve_ZZ(const vector<Integer> & v) const3017 vector<Integer> Matrix<Integer>::solve_ZZ(const vector<Integer>& v) const {
3018 Integer denom;
3019 vector<Integer> result = solve_rectangular(v, denom);
3020 if (denom != 1)
3021 result.clear();
3022 return result;
3023 }
3024 //---------------------------------------------------------------------------
3025
3026 template <typename Integer>
find_linear_form() const3027 vector<Integer> Matrix<Integer>::find_linear_form() const {
3028 Integer denom;
3029 vector<Integer> result = solve_rectangular(vector<Integer>(nr, 1), denom);
3030 v_make_prime(result);
3031 return result;
3032 }
3033
3034 //---------------------------------------------------------------------------
3035
3036 /*
3037 template <typename Integer>
3038 vector<Integer> Matrix<Integer>::find_linear_form_low_dim() const {
3039 size_t rank = (*this).rank();
3040 if (rank == 0) { // return zero-vector as linear form
3041 return vector<Integer>(nc, 0);
3042 }
3043 if (rank == nc) { // basis change not necessary
3044 return (*this).find_linear_form();
3045 }
3046
3047 Sublattice_Representation<Integer> Basis_Change(*this, true);
3048 vector<Integer> Linear_Form = Basis_Change.to_sublattice(*this).find_linear_form();
3049 if (Linear_Form.size() != 0)
3050 Linear_Form = Basis_Change.from_sublattice_dual(Linear_Form);
3051
3052 return Linear_Form;
3053 }
3054
3055 template <>
3056 vector<mpq_class> Matrix<mpq_class>::find_linear_form_low_dim() const {
3057 assert(false);
3058 return vector<mpq_class>(0);
3059 }
3060
3061 #ifdef ENFNORMALIZ
3062 template <>
3063 vector<renf_elem_class> Matrix<renf_elem_class>::find_linear_form_low_dim() const {
3064 assert(false);
3065 return vector<renf_elem_class>(0);
3066 }
3067 #endif
3068
3069 */
3070
3071 //---------------------------------------------------------------------------
3072
3073 template <typename Integer>
row_echelon_reduce()3074 size_t Matrix<Integer>::row_echelon_reduce() {
3075 size_t rk;
3076 Matrix<Integer> Copy(*this);
3077 bool success;
3078 rk = row_echelon_reduce(success);
3079 if (success) {
3080 Shrink_nr_rows(rk);
3081 return rk;
3082 }
3083 Matrix<mpz_class> mpz_Copy(nr, nc);
3084 mat_to_mpz(Copy, mpz_Copy);
3085 rk = mpz_Copy.row_echelon_reduce(success);
3086 mat_to_Int(mpz_Copy, *this);
3087 Shrink_nr_rows(rk);
3088 return rk;
3089 }
3090
3091 template <>
row_echelon_reduce()3092 size_t Matrix<mpq_class>::row_echelon_reduce() {
3093
3094 assert(false);
3095 return 0;
3096 }
3097 /* body
3098 size_t rk;
3099 Matrix<mpq_class> Copy(*this);
3100 bool success;
3101 rk = row_echelon_reduce(success);
3102 if (success) {
3103 Shrink_nr_rows(rk);
3104 return rk;
3105 }
3106 return rk;
3107 }
3108 */
3109 //---------------------------------------------------------------------------
3110
3111 template <typename Integer>
full_rank_index() const3112 Integer Matrix<Integer>::full_rank_index() const {
3113 Matrix<Integer> Copy(*this);
3114 Integer index;
3115 bool success;
3116 index = Copy.full_rank_index(success);
3117 if (success)
3118 return index;
3119 Matrix<mpz_class> mpz_Copy(nr, nc);
3120 mat_to_mpz(*this, mpz_Copy);
3121 mpz_class mpz_index = mpz_Copy.full_rank_index(success);
3122 convert(index, mpz_index);
3123 return index;
3124 }
3125
3126 template <>
full_rank_index() const3127 mpq_class Matrix<mpq_class>::full_rank_index() const {
3128
3129 assert(false);
3130 return{};
3131 }
3132 /* body
3133 Matrix<mpq_class> Copy(*this);
3134 mpq_class index;
3135 bool success;
3136 index = Copy.full_rank_index(success);
3137
3138 return index;
3139 }
3140 */
3141
3142 #ifdef ENFNORMALIZ
3143 template <>
full_rank_index() const3144 renf_elem_class Matrix<renf_elem_class>::full_rank_index() const {
3145
3146 assert(false);
3147 return{};
3148 }
3149 /* body
3150 Matrix<renf_elem_class> Copy(*this);
3151 renf_elem_class index;
3152 bool success;
3153 index = Copy.full_rank_index(success);
3154
3155 return index;
3156 }
3157 */
3158 #endif
3159
3160 //---------------------------------------------------------------------------
3161
3162 template <typename Integer>
row_echelon()3163 size_t Matrix<Integer>::row_echelon() {
3164 Matrix<Integer> Copy(*this);
3165 bool success;
3166 size_t rk;
3167 rk = row_echelon(success);
3168 if (success) {
3169 Shrink_nr_rows(rk);
3170 return rk;
3171 }
3172 Matrix<mpz_class> mpz_Copy(nr, nc);
3173 mat_to_mpz(Copy, mpz_Copy);
3174 rk = mpz_Copy.row_echelon_reduce(success); // reduce to make entries small
3175 mat_to_Int(mpz_Copy, *this);
3176 Shrink_nr_rows(rk);
3177 return rk;
3178 }
3179
3180 //-----------------------------------------------------------
3181 //
3182 // variants for floating point
3183 //
3184 //-----------------------------------------------------------
3185
3186 template <>
pivot_in_column(size_t row,size_t col)3187 long Matrix<nmz_float>::pivot_in_column(size_t row, size_t col) {
3188 size_t i;
3189 long j = -1;
3190 nmz_float help = 0;
3191
3192 for (i = row; i < nr; i++) {
3193 if (Iabs(elem[i][col]) > nmz_epsilon) {
3194 if ((help == 0) || (Iabs(elem[i][col]) > help)) {
3195 help = Iabs(elem[i][col]);
3196 j = i;
3197 }
3198 }
3199 }
3200
3201 return j;
3202 }
3203
3204 template <>
row_echelon_inner_elem(bool & success)3205 size_t Matrix<nmz_float>::row_echelon_inner_elem(bool& success) {
3206 success = true;
3207
3208 size_t pc = 0;
3209 long piv = 0, rk = 0;
3210
3211 if (nr == 0)
3212 return 0;
3213
3214 for (rk = 0; rk < (long)nr; rk++) {
3215 for (; pc < nc; pc++) {
3216 piv = pivot_in_column(rk, pc);
3217 if (piv >= 0)
3218 break;
3219 }
3220 if (pc == nc)
3221 break;
3222
3223 exchange_rows(rk, piv);
3224 reduce_row(rk, pc);
3225 }
3226
3227 return rk;
3228 }
3229
3230 template <>
row_echelon()3231 size_t Matrix<nmz_float>::row_echelon() {
3232
3233 assert(false);
3234 return 0;
3235 }
3236 /* body
3237 size_t rk;
3238 bool dummy;
3239 rk = row_echelon_inner_elem(dummy);
3240 Shrink_nr_rows(rk);
3241 return rk;
3242 }
3243 */
3244 //---------------------------------------------------------------------------
3245
3246 template <typename Integer>
kernel(bool use_LLL) const3247 Matrix<Integer> Matrix<Integer>::kernel(bool use_LLL) const {
3248 // computes a ZZ-basis of the solutions of (*this)x=0
3249 // the basis is formed by the rOWS of the returned matrix
3250
3251 size_t dim = nc;
3252 if (nr == 0)
3253 return (Matrix<Integer>(dim));
3254
3255 Matrix<Integer> Copy(*this);
3256 size_t rank;
3257 bool success;
3258 Matrix<Integer> Transf = Copy.row_column_trigonalize(rank, success);
3259 if (!success) {
3260 Matrix<mpz_class> mpz_Copy(nr, nc);
3261 mat_to_mpz(*this, mpz_Copy);
3262 Matrix<mpz_class> mpz_Transf = mpz_Copy.row_column_trigonalize(rank, success);
3263 mat_to_Int(mpz_Transf, Transf);
3264 }
3265
3266 Matrix<Integer> ker_basis(dim - rank, dim);
3267 Matrix<Integer> Help = Transf.transpose();
3268 for (size_t i = rank; i < dim; i++)
3269 ker_basis[i - rank] = Help[i];
3270
3271 if (use_LLL)
3272 return ker_basis.LLL();
3273 else {
3274 ker_basis.standardize_basis();
3275 return (ker_basis);
3276 }
3277 }
3278
3279 template <>
kernel(bool use_LLL) const3280 Matrix<mpq_class> Matrix<mpq_class>::kernel(bool use_LLL) const {
3281
3282
3283 assert(false);
3284 return{};
3285 }
3286 /* body
3287 // computes a ZZ-basis of the solutions of (*this)x=0
3288 // the basis is formed by the rOWS of the returned matrix
3289
3290 size_t dim = nc;
3291 if (nr == 0)
3292 return (Matrix<mpq_class>(dim));
3293
3294 Matrix<mpq_class> Copy(*this);
3295 size_t rank;
3296 bool success;
3297 Matrix<mpq_class> Transf = Copy.row_column_trigonalize(rank, success);
3298
3299 Matrix<mpq_class> ker_basis(dim - rank, dim);
3300 Matrix<mpq_class> Help = Transf.transpose();
3301 for (size_t i = rank; i < dim; i++)
3302 ker_basis[i - rank] = Help[i];
3303
3304 ker_basis.standardize_basis();
3305 return (ker_basis);
3306 }*/
3307
3308 //---------------------------------------------------------------------------
3309 // Converts "this" into (column almost) Hermite normal form, returns column transformation matrix
3310 template <typename Integer>
AlmostHermite(size_t & rk)3311 Matrix<Integer> Matrix<Integer>::AlmostHermite(size_t& rk) {
3312 Matrix<Integer> Copy = *this;
3313 Matrix<Integer> Transf;
3314 bool success;
3315 Transf = row_column_trigonalize(rk, success);
3316 if (success)
3317 return Transf;
3318
3319 Matrix<mpz_class> mpz_this(nr, nc);
3320 mat_to_mpz(Copy, mpz_this);
3321 Matrix<mpz_class> mpz_Transf = mpz_this.row_column_trigonalize(rk, success);
3322 mat_to_Int(mpz_this, *this);
3323 mat_to_Int(mpz_Transf, Transf);
3324 return Transf;
3325 }
3326
3327 template <>
AlmostHermite(size_t & rk)3328 Matrix<mpq_class> Matrix<mpq_class>::AlmostHermite(size_t& rk) {
3329 assert(false);
3330 return Matrix<mpq_class>(0, 0);
3331 }
3332
3333 #ifdef ENFNORMALIZ
3334 template <>
AlmostHermite(size_t & rk)3335 Matrix<renf_elem_class> Matrix<renf_elem_class>::AlmostHermite(size_t& rk) {
3336 assert(false);
3337 return Matrix<renf_elem_class>(0, 0);
3338 }
3339 #endif
3340
3341 //---------------------------------------------------------------------------
3342
3343 template <typename Integer>
SmithNormalForm_inner(size_t & rk,Matrix<Integer> & Right)3344 bool Matrix<Integer>::SmithNormalForm_inner(size_t& rk, Matrix<Integer>& Right) {
3345 bool success = true;
3346
3347 // first we diagonalize
3348
3349 while (true) {
3350 rk = row_echelon_reduce(success);
3351 if (!success)
3352 return false;
3353 if (rk == 0)
3354 break;
3355
3356 if (is_diagonal())
3357 break;
3358
3359 success = column_trigonalize(rk, Right);
3360 if (!success)
3361 return false;
3362
3363 if (is_diagonal())
3364 break;
3365 }
3366
3367 // now we change the diagonal so that we have successive divisibilty
3368
3369 if (rk <= 1)
3370 return true;
3371
3372 while (true) {
3373 size_t i = 0;
3374 for (; i < rk - 1; ++i)
3375 if (elem[i + 1][i + 1] % elem[i][i] != 0)
3376 break;
3377 if (i == rk - 1)
3378 break;
3379
3380 Integer u, v, w, z, d = ext_gcd(elem[i][i], elem[i + 1][i + 1], u, v);
3381 elem[i][i + 1] = elem[i + 1][i + 1];
3382 w = -elem[i + 1][i + 1] / d;
3383 z = elem[i][i] / d;
3384 // Now we multiply the submatrix formed by columns "corner" and "j"
3385 // and rows corner,...,nr from the right by the 2x2 matrix
3386 // | u w |
3387 // | v z |
3388 if (!linear_comb_columns(i, i + 1, u, w, v, z))
3389 return false;
3390 if (!Right.linear_comb_columns(i, i + 1, u, w, v, z))
3391 return false;
3392 elem[i + 1][i] = 0;
3393 }
3394
3395 return true;
3396 }
3397
3398 template <>
SmithNormalForm_inner(size_t & rk,Matrix<nmz_float> & Right)3399 bool Matrix<nmz_float>::SmithNormalForm_inner(size_t& rk, Matrix<nmz_float>& Right) {
3400 assert(false);
3401 return {};
3402 }
3403
3404 template <>
SmithNormalForm_inner(size_t & rk,Matrix<mpq_class> & Right)3405 bool Matrix<mpq_class>::SmithNormalForm_inner(size_t& rk, Matrix<mpq_class>& Right) {
3406 assert(false);
3407 return {};
3408 }
3409
3410 #ifdef ENFNORMALIZ
3411 template <>
SmithNormalForm_inner(size_t & rk,Matrix<renf_elem_class> & Right)3412 bool Matrix<renf_elem_class>::SmithNormalForm_inner(size_t& rk, Matrix<renf_elem_class>& Right) {
3413 assert(false);
3414 return {};
3415 }
3416 #endif
3417
3418 // Converts "this" into Smith normal form, returns column transformation matrix
3419 template <typename Integer>
SmithNormalForm(size_t & rk)3420 Matrix<Integer> Matrix<Integer>::SmithNormalForm(size_t& rk) {
3421 size_t dim = nc;
3422 Matrix<Integer> Transf(dim);
3423 if (dim == 0)
3424 return Transf;
3425
3426 Matrix<Integer> Copy = *this;
3427 bool success = SmithNormalForm_inner(rk, Transf);
3428 if (success)
3429 return Transf;
3430
3431 Matrix<mpz_class> mpz_this(nr, dim);
3432 mat_to_mpz(Copy, mpz_this);
3433 Matrix<mpz_class> mpz_Transf(dim);
3434 mpz_this.SmithNormalForm_inner(rk, mpz_Transf);
3435 mat_to_Int(mpz_this, *this);
3436 mat_to_Int(mpz_Transf, Transf);
3437 return Transf;
3438 }
3439
3440 template <>
SmithNormalForm(size_t & rk)3441 Matrix<nmz_float> Matrix<nmz_float>::SmithNormalForm(size_t& rk) {
3442 assert(false);
3443 return *this;
3444 }
3445
3446 template <>
SmithNormalForm(size_t & rk)3447 Matrix<mpq_class> Matrix<mpq_class>::SmithNormalForm(size_t& rk) {
3448 assert(false);
3449 return *this;
3450 }
3451
3452 #ifdef ENFNORMALIZ
3453 template <>
SmithNormalForm(size_t & rk)3454 Matrix<renf_elem_class> Matrix<renf_elem_class>::SmithNormalForm(size_t& rk) {
3455 assert(false);
3456 return *this;
3457 }
3458 #endif
3459
3460 //---------------------------------------------------------------------------
3461 // Classless conversion routines
3462 //---------------------------------------------------------------------------
3463
3464 template <typename Integer>
mat_to_mpz(const Matrix<Integer> & mat,Matrix<mpz_class> & mpz_mat)3465 void mat_to_mpz(const Matrix<Integer>& mat, Matrix<mpz_class>& mpz_mat) {
3466 // convert(mpz_mat, mat);
3467 // we allow the matrices to have different sizes
3468 size_t nrows = min(mat.nr_of_rows(), mpz_mat.nr_of_rows());
3469 size_t ncols = min(mat.nr_of_columns(), mpz_mat.nr_of_columns());
3470 for (size_t i = 0; i < nrows; ++i)
3471 for (size_t j = 0; j < ncols; ++j)
3472 convert(mpz_mat[i][j], mat[i][j]);
3473 #pragma omp atomic
3474 GMP_mat++;
3475 }
3476
3477 template <>
mat_to_mpz(const Matrix<mpq_class> & mat,Matrix<mpz_class> & mpz_mat)3478 void mat_to_mpz(const Matrix<mpq_class>& mat, Matrix<mpz_class>& mpz_mat) {
3479 assert(false);
3480 // convert(mpz_mat, mat);
3481 // we allow the matrices to have different sizes
3482 /* size_t nrows = min(mat.nr_of_rows(), mpz_mat.nr_of_rows());
3483 size_t ncols = min(mat.nr_of_columns(),mpz_mat.nr_of_columns());
3484 for(size_t i=0; i<nrows; ++i)
3485 for(size_t j=0; j<ncols; ++j)
3486 convert(mpz_mat[i][j], mat[i][j]);
3487 #pragma omp atomic
3488 GMP_mat++;
3489 */
3490 }
3491
3492 #ifdef ENFNORMALIZ
3493 template <>
mat_to_mpz(const Matrix<renf_elem_class> & mat,Matrix<mpz_class> & mpz_mat)3494 void mat_to_mpz(const Matrix<renf_elem_class>& mat, Matrix<mpz_class>& mpz_mat) {
3495 assert(false);
3496 // convert(mpz_mat, mat);
3497 // we allow the matrices to have different sizes
3498 /* size_t nrows = min(mat.nr_of_rows(), mpz_mat.nr_of_rows());
3499 size_t ncols = min(mat.nr_of_columns(),mpz_mat.nr_of_columns());
3500 for(size_t i=0; i<nrows; ++i)
3501 for(size_t j=0; j<ncols; ++j)
3502 convert(mpz_mat[i][j], mat[i][j]);
3503 #pragma omp atomic
3504 GMP_mat++;
3505 */
3506 }
3507 #endif
3508
3509 template void mat_to_mpz<long>(const Matrix<long>&, Matrix<mpz_class>&);
3510 template void mat_to_mpz<long long>(const Matrix<long long>&, Matrix<mpz_class>&);
3511 template void mat_to_mpz<mpz_class>(const Matrix<mpz_class>&, Matrix<mpz_class>&);
3512
3513 //---------------------------------------------------------------------------
3514
3515 template <typename Integer>
mat_to_Int(const Matrix<mpz_class> & mpz_mat,Matrix<Integer> & mat)3516 void mat_to_Int(const Matrix<mpz_class>& mpz_mat, Matrix<Integer>& mat) {
3517 // convert(mat, mpz_mat);
3518 // we allow the matrices to have different sizes
3519 size_t nrows = min(mpz_mat.nr_of_rows(), mat.nr_of_rows());
3520 size_t ncols = min(mpz_mat.nr_of_columns(), mat.nr_of_columns());
3521 for (size_t i = 0; i < nrows; ++i)
3522 for (size_t j = 0; j < ncols; ++j)
3523 convert(mat[i][j], mpz_mat[i][j]);
3524 }
3525
3526 template void mat_to_Int<long>(const Matrix<mpz_class>&, Matrix<long>&);
3527 template void mat_to_Int<long long>(const Matrix<mpz_class>&, Matrix<long long>&);
3528 template void mat_to_Int<mpz_class>(const Matrix<mpz_class>&, Matrix<mpz_class>&);
3529
3530 //---------------------------------------------------------------------------
3531
3532 template <typename Integer>
mpz_submatrix(Matrix<mpz_class> & sub,const Matrix<Integer> & mother,const vector<key_t> & selection)3533 void mpz_submatrix(Matrix<mpz_class>& sub, const Matrix<Integer>& mother, const vector<key_t>& selection) {
3534 assert(sub.nr_of_columns() >= mother.nr_of_columns());
3535 assert(sub.nr_of_rows() >= selection.size());
3536 for (size_t i = 0; i < selection.size(); ++i)
3537 for (size_t j = 0; j < mother.nr_of_columns(); ++j)
3538 convert(sub[i][j], mother[selection[i]][j]);
3539 }
3540
3541 //---------------------------------------------------------------------------
3542
3543 template <typename Integer>
mpz_submatrix_trans(Matrix<mpz_class> & sub,const Matrix<Integer> & mother,const vector<key_t> & selection)3544 void mpz_submatrix_trans(Matrix<mpz_class>& sub, const Matrix<Integer>& mother, const vector<key_t>& selection) {
3545 assert(sub.nr_of_columns() >= selection.size());
3546 assert(sub.nr_of_rows() >= mother.nr_of_columns());
3547 for (size_t i = 0; i < selection.size(); ++i)
3548 for (size_t j = 0; j < mother.nr_of_columns(); ++j)
3549 convert(sub[j][i], mother[selection[i]][j]);
3550 }
3551
3552 //---------------------------------------------------
3553
3554 template <typename Integer>
saturate()3555 void Matrix<Integer>::saturate() {
3556 *this = kernel().kernel();
3557 }
3558
3559 //---------------------------------------------------------------------------
3560
3561 /* sorts rows of a matrix by a degree function and returns the permuation
3562 * does not change matrix (yet)
3563 */
3564
3565 /*
3566 template <typename Integer>
3567 vector<key_t> Matrix<Integer>::perm_sort_by_degree(const vector<key_t>& key,
3568 const vector<Integer>& grading,
3569 bool computed) const {
3570 list<vector<Integer> > rowList;
3571 vector<Integer> v;
3572
3573 v.resize(nc + 2);
3574 unsigned long i, j;
3575
3576 for (i = 0; i < key.size(); i++) {
3577 if (computed) {
3578 v[0] = v_scalar_product((*this).elem[key[i]], grading);
3579 }
3580 else {
3581 v[0] = 0;
3582 for (j = 0; j < nc; j++)
3583 v[0] += Iabs((*this).elem[key[i]][j]);
3584 }
3585 for (j = 0; j < nc; j++) {
3586 v[j + 1] = (*this).elem[key[i]][j];
3587 }
3588 v[nc + 1] = key[i]; // position of row
3589 rowList.push_back(v);
3590 }
3591 rowList.sort();
3592 vector<key_t> perm;
3593 perm.resize(key.size());
3594 i = 0;
3595 for (const auto& it : rowList) {
3596 perm[i] = convertToLong(it[nc + 1]);
3597 i++;
3598 }
3599 return perm;
3600 }
3601
3602 template <>
3603 vector<key_t> Matrix<mpq_class>::perm_sort_by_degree(const vector<key_t>& key,
3604 const vector<mpq_class>& grading,
3605 bool computed) const {
3606 assert(false);
3607 return vector<key_t>(0);
3608 }
3609
3610 #ifdef ENFNORMALIZ
3611 template <>
3612 vector<key_t> Matrix<renf_elem_class>::perm_sort_by_degree(const vector<key_t>& key,
3613 const vector<renf_elem_class>& grading,
3614 bool computed) const {
3615 assert(false);
3616 return vector<key_t>(0);
3617 }
3618 #endif
3619 */
3620
3621 //---------------------------------------------------------------------------
3622 // sorting routines
3623
3624 template <typename Integer>
weight_lex(const order_helper<Integer> & a,const order_helper<Integer> & b)3625 bool weight_lex(const order_helper<Integer>& a, const order_helper<Integer>& b) {
3626 if (a.weight < b.weight)
3627 return true;
3628 if (a.weight == b.weight)
3629 if (*(a.v) < *(b.v))
3630 return true;
3631 return false;
3632 }
3633
3634 //---------------------------------------------------------------------------
3635 // orders the rows of matrix:
3636 // such that row perm[0] is the new 0th row, row perm[1] the new 1st row etc.
3637
3638 template <typename Integer>
order_rows_by_perm(const vector<key_t> & perm)3639 void Matrix<Integer>::order_rows_by_perm(const vector<key_t>& perm) {
3640 order_by_perm(elem, perm);
3641 }
3642
3643 // sorts the rows accoring to the weight matrix (taking the absolute values of selected rows first)
3644 template <typename Integer>
sort_by_weights(const Matrix<Integer> & Weights,vector<bool> absolute)3645 Matrix<Integer>& Matrix<Integer>::sort_by_weights(const Matrix<Integer>& Weights, vector<bool> absolute) {
3646 if (nr <= 1)
3647 return *this;
3648 vector<key_t> perm = perm_by_weights(Weights, absolute);
3649 order_by_perm(elem, perm);
3650 return *this;
3651 }
3652
3653 template <typename Integer>
sort_lex()3654 Matrix<Integer>& Matrix<Integer>::sort_lex() {
3655 if (nr <= 1)
3656 return *this;
3657 vector<key_t> perm = perm_by_weights(Matrix<Integer>(0, nc), vector<bool>(0));
3658 order_by_perm(elem, perm);
3659 return *this;
3660 }
3661
3662 /* not used at present
3663 template <typename Integer>
3664 // sortes rows by descending number or zeroes
3665 Matrix<Integer>& Matrix<Integer>::sort_by_nr_of_zeroes() {
3666 if (nr <= 1)
3667 return *this;
3668 vector<key_t> perm = perm_by_nr_zeroes();
3669 order_by_perm(elem, perm);
3670 return *this;
3671 }
3672
3673 template <typename Integer>
3674 vector<key_t> Matrix<Integer>::perm_by_lex() {
3675 return perm_by_weights(Matrix<Integer>(0, nc), vector<bool>(0));
3676 }
3677
3678 template <typename Integer>
3679 vector<key_t> Matrix<Integer>::perm_by_nr_zeroes() { //
3680 // the row with index perm[0] has the maximum number of zeoes, then perm[1] etc.
3681
3682 vector<vector<key_t> > order(nr, vector<key_t>(2, 0));
3683
3684 for (key_t i = 0; i < nr; ++i) {
3685 order[i][1] = i;
3686 for (size_t j = 0; j < nc; ++j) {
3687 if (elem[i][j] == 0)
3688 order[i][0]++;
3689 }
3690 }
3691
3692 sort(order.rbegin(), order.rend());
3693 vector<key_t> perm(nr);
3694 for (size_t i = 0; i < nr; ++i)
3695 perm[i] = order[i][1];
3696 return perm;
3697 }
3698 */
3699
3700 template <typename Integer>
perm_by_weights(const Matrix<Integer> & Weights,vector<bool> absolute)3701 vector<key_t> Matrix<Integer>::perm_by_weights(const Matrix<Integer>& Weights, vector<bool> absolute) {
3702 // the smallest entry is the row with index perm[0], then perm[1] etc.
3703 // Computes only perm, matrix unchanged
3704
3705 assert(Weights.nc == nc);
3706 assert(absolute.size() == Weights.nr);
3707
3708 list<order_helper<Integer> > order;
3709 order_helper<Integer> entry;
3710 entry.weight.resize(Weights.nr);
3711
3712 for (key_t i = 0; i < nr; ++i) {
3713 for (size_t j = 0; j < Weights.nr; ++j) {
3714 if (absolute[j])
3715 entry.weight[j] = v_scalar_product(Weights[j], v_abs_value(elem[i]));
3716 else
3717 entry.weight[j] = v_scalar_product(Weights[j], elem[i]);
3718 }
3719 entry.index = i;
3720 entry.v = &(elem[i]);
3721 order.push_back(entry);
3722 }
3723 order.sort(weight_lex<Integer>);
3724 vector<key_t> perm(nr);
3725 typename list<order_helper<Integer> >::const_iterator ord = order.begin();
3726 for (key_t i = 0; i < nr; ++i, ++ord)
3727 perm[i] = ord->index;
3728
3729 return perm;
3730 }
3731
3732 //==========================================================
3733
3734 template <typename Integer>
solve_congruences(bool & zero_modulus) const3735 Matrix<Integer> Matrix<Integer>::solve_congruences(bool& zero_modulus) const {
3736 zero_modulus = false;
3737 size_t i, j;
3738 size_t nr_cong = nr, dim = nc - 1;
3739 if (nr_cong == 0)
3740 return Matrix<Integer>(dim); // give back unit matrix
3741
3742 // add slack variables to convert congruences into equaitions
3743 Matrix<Integer> Cong_Slack(nr_cong, dim + nr_cong);
3744 for (i = 0; i < nr_cong; i++) {
3745 for (j = 0; j < dim; j++) {
3746 Cong_Slack[i][j] = elem[i][j];
3747 }
3748 Cong_Slack[i][dim + i] = elem[i][dim];
3749 if (elem[i][dim] == 0) {
3750 zero_modulus = true;
3751 return Matrix<Integer>(0, dim);
3752 }
3753 }
3754
3755 // compute kernel
3756
3757 Matrix<Integer> Help = Cong_Slack.kernel(); // gives the solutions to the the system with slack variables
3758 Matrix<Integer> Ker_Basis(dim, dim); // must now project to first dim coordinates to get rid of them
3759 for (size_t i = 0; i < dim; ++i)
3760 for (size_t j = 0; j < dim; ++j)
3761 Ker_Basis[i][j] = Help[i][j];
3762 return Ker_Basis;
3763 }
3764
3765 #ifdef ENFNORMALIZ
3766 template <>
solve_congruences(bool & zero_modulus) const3767 Matrix<renf_elem_class> Matrix<renf_elem_class>::solve_congruences(bool& zero_modulus) const {
3768 assert(false);
3769 return Matrix<renf_elem_class>(0, 0);
3770 }
3771 #endif
3772
3773 //---------------------------------------------------
3774
3775 template <typename Integer>
max_and_min(const vector<Integer> & L,const vector<Integer> & norm) const3776 vector<key_t> Matrix<Integer>::max_and_min(const vector<Integer>& L, const vector<Integer>& norm) const {
3777 vector<key_t> result(2, 0);
3778 if (nr == 0)
3779 return result;
3780 key_t maxind = 0, minind = 0;
3781 Integer maxval = v_scalar_product(L, elem[0]);
3782 Integer maxnorm = 1, minnorm = 1;
3783 if (norm.size() > 0) {
3784 maxnorm = v_scalar_product(norm, elem[0]);
3785 minnorm = maxnorm;
3786 }
3787 Integer minval = maxval;
3788 for (key_t i = 0; i < nr; ++i) {
3789 Integer val = v_scalar_product(L, elem[i]);
3790 if (norm.size() == 0) {
3791 if (val > maxval) {
3792 maxind = i;
3793 maxval = val;
3794 }
3795 if (val < minval) {
3796 minind = i;
3797 minval = val;
3798 }
3799 }
3800 else {
3801 Integer nm = v_scalar_product(norm, elem[i]);
3802 if (maxnorm * val > nm * maxval) {
3803 maxind = i;
3804 maxval = val;
3805 }
3806 if (minnorm * val < nm * minval) {
3807 minind = i;
3808 minval = val;
3809 }
3810 }
3811 }
3812 result[0] = maxind;
3813 result[1] = minind;
3814 return result;
3815 }
3816
3817 template <typename Integer>
extreme_points_first(bool verbose,const vector<Integer> norm)3818 size_t Matrix<Integer>::extreme_points_first(bool verbose, const vector<Integer> norm) {
3819 //
3820
3821 if (nr == 0)
3822 return 1;
3823
3824 if(verbose)
3825 verboseOutput() << "Trying to find extreme points" << endl;
3826 vector<long long> norm_copy;
3827
3828 size_t nr_extr = 0;
3829 Matrix<long long> HelpMat(nr, nc);
3830 try {
3831 convert(HelpMat, *this);
3832 convert(norm_copy, norm);
3833 } catch (const ArithmeticException&) {
3834 return nr_extr;
3835 }
3836
3837 HelpMat.sort_lex();
3838
3839 vector<bool> marked(nr, false);
3840 size_t no_success = 0;
3841 // size_t nr_attempt=0;
3842
3843 size_t counter_100=0;
3844 while (true) {
3845 INTERRUPT_COMPUTATION_BY_EXCEPTION
3846
3847 // nr_attempt++; cout << nr_attempt << endl;
3848
3849 vector< vector<key_t> > max_min_ind(10*nc);
3850 #pragma omp parallel for
3851 for(size_t j=0; j < 10*nc; ++j){
3852 vector<long long> L = v_random<long long>(nc, 5*nc);
3853 max_min_ind[j] = HelpMat.max_and_min(L, norm_copy);
3854 }
3855
3856 size_t new_hits=0;
3857
3858 for(size_t j=0; j < 10*nc; ++j){
3859 if(!marked[max_min_ind[j][0]])
3860 new_hits++;
3861 if(!marked[max_min_ind[j][0]])
3862 new_hits++;
3863 marked[max_min_ind[j][0]] = true;
3864 marked[max_min_ind[j][1]] = true;
3865 }
3866
3867 counter_100+=new_hits;
3868
3869 if (new_hits==0)
3870 no_success++;
3871 else{
3872 no_success = 0;
3873 nr_extr+=new_hits;
3874 if(verbose && counter_100 >= 100){
3875 verboseOutput() << "Extreme points " << nr_extr << endl;
3876 counter_100=0;
3877 }
3878 }
3879 if (no_success > 20*nc)
3880 break;
3881 }
3882 Matrix<long long> Extr(nr_extr, nc); // the recognized extreme rays
3883 Matrix<long long> NonExtr(nr_extr, nc); // the other generators
3884 size_t j = 0;
3885 vector<key_t> perm(nr);
3886 for (size_t i = 0; i < nr; ++i) {
3887 if (marked[i]) {
3888 perm[j] = i;
3889 ;
3890 j++;
3891 }
3892 }
3893 nr_extr = j;
3894 for (size_t i = 0; i < nr; ++i) {
3895 if (!marked[i]) {
3896 perm[j] = i;
3897 ;
3898 j++;
3899 }
3900 }
3901 order_rows_by_perm(perm);
3902 // cout << nr_extr << "extreme points found" << endl;
3903 return nr_extr;
3904 }
3905
3906 //---------------------------------------------------
3907
3908 template <>
extreme_points_first(bool verbose,const vector<mpq_class> norm)3909 size_t Matrix<mpq_class>::extreme_points_first(bool verbose, const vector<mpq_class> norm) {
3910 assert(false);
3911 return 0;
3912 }
3913
3914 //---------------------------------------------------
3915
3916 template <typename Integer>
find_inner_point()3917 vector<Integer> Matrix<Integer>::find_inner_point() {
3918 vector<key_t> simplex = max_rank_submatrix_lex();
3919 vector<Integer> point(nc);
3920 for (unsigned int& i : simplex)
3921 point = v_add(point, elem[i]);
3922 return point;
3923 }
3924
3925 //---------------------------------------------------
3926
3927 template <typename Integer>
zero_product_with_transpose_of(const Matrix & B)3928 bool Matrix<Integer>::zero_product_with_transpose_of(const Matrix& B){
3929
3930 if(nr == 0 || B.nr == 0)
3931 return true;
3932
3933 assert(nc == B.nc);
3934 for(size_t i = 0; i < nr; ++i)
3935 for(size_t j= 0; j < B.nr; ++j)
3936 if(v_scalar_product(elem[i],B[j]) != 0)
3937 return false;
3938 return true;
3939 }
3940
3941 //---------------------------------------------------
3942
3943 template <typename Integer>
readMatrix(const string project)3944 Matrix<Integer> readMatrix(const string project) {
3945 // reads one matrix from file with name project
3946 // format: nr of rows, nr of colimns, entries
3947 // all separated by white space
3948
3949 string name_in = project;
3950 const char* file_in = name_in.c_str();
3951 ifstream in;
3952 in.open(file_in, ifstream::in);
3953 if (in.is_open() == false)
3954 throw BadInputException("readMatrix cannot find file");
3955 int nrows, ncols;
3956 in >> nrows;
3957 in >> ncols;
3958
3959 if (nrows == 0 || ncols == 0)
3960 throw BadInputException("readMatrix finds matrix empty");
3961
3962 int i, j;
3963 Matrix<Integer> result(nrows, ncols);
3964
3965 for (i = 0; i < nrows; ++i)
3966 for (j = 0; j < ncols; ++j) {
3967 read_number(in, result[i][j]);
3968 if (in.fail())
3969 throw BadInputException("readMatrix finds matrix corrupted");
3970 }
3971 return result;
3972 }
3973
3974 //---------------------------------------------------------------------------
3975 // version with full number of points
3976 // and search for optimal point
3977
3978 template <typename Integer>
optimal_subdivision_point() const3979 vector<Integer> Matrix<Integer>::optimal_subdivision_point() const {
3980 return optimal_subdivision_point_inner();
3981 }
3982
3983 // In mpz_class we first try machine integer
3984 template <>
optimal_subdivision_point() const3985 vector<mpz_class> Matrix<mpz_class>::optimal_subdivision_point() const {
3986 try {
3987 Matrix<MachineInteger> GensMI;
3988 convert(GensMI, *this);
3989 vector<MachineInteger> PMI = GensMI.optimal_subdivision_point_inner();
3990 vector<mpz_class> P;
3991 convert(P, PMI);
3992 return P;
3993 } catch (const ArithmeticException& e) {
3994 return optimal_subdivision_point_inner();
3995 }
3996 }
3997
3998 /*
3999 * Version with LL for every matrix --- seems to be the best choice
4000 */
4001 // version with a single point, only top of the search polytope
4002 // After 2 attempts without improvement, g raised to opt_value-1
4003
4004 template <typename Integer>
optimal_subdivision_point_inner() const4005 vector<Integer> Matrix<Integer>::optimal_subdivision_point_inner() const {
4006 // returns empty vector if simplex cannot be subdivided with smaller detsum
4007
4008 // cout << "***************" << endl;
4009
4010 assert(nr > 0);
4011 assert(nr == nc);
4012
4013 Sublattice_Representation<Integer> NewCoord = LLL_coordinates<Integer, Integer>(*this);
4014 Matrix<Integer> Gred = NewCoord.to_sublattice(*this);
4015
4016 vector<Integer> opt_point;
4017
4018 vector<Integer> N = Gred.find_linear_form();
4019 assert(N.size() == nr);
4020 Integer G = v_scalar_product(N, Gred[0]);
4021 if (G <= 1)
4022 return opt_point;
4023 Matrix<Integer> Supp;
4024 Integer V;
4025 vector<key_t> dummy(nr);
4026 for (size_t i = 0; i < nr; ++i)
4027 dummy[i] = i;
4028 Gred.simplex_data(dummy, Supp, V, true);
4029 Integer MinusOne = -1;
4030 vector<Integer> MinusN(N);
4031 v_scalar_multiplication(MinusN, MinusOne);
4032 Supp.append(MinusN);
4033 Supp.resize_columns(nr + 1);
4034 Supp.exchange_columns(0, nc); // grading to the front!
4035
4036 Integer opt_value = G;
4037 Integer empty_value = 0;
4038 Integer g = G - 1;
4039
4040 Integer den = 2;
4041
4042 vector<Integer> Zero(nr + 1); // the excluded vector
4043 Zero[0] = 1;
4044
4045 // Incidence matrix for projectand lift
4046 vector<dynamic_bitset> Ind(nr + 1);
4047 for (size_t i = 0; i < nr + 1; ++i) {
4048 Ind[i].resize(nc + 1);
4049 for (size_t j = 0; j < nc + 1; ++j)
4050 Ind[i][j] = true;
4051 Ind[i][i] = false;
4052 }
4053
4054 size_t nothing_found = 0;
4055 while (true) {
4056 vector<Integer> SubDiv;
4057 // cout << "Opt " << opt_value << " test " << g << " empty " << empty_value << " nothing " << nothing_found << endl;
4058 Supp[nr][0] = g; // the degree at which we cut the simplex1;
4059 ProjectAndLift<Integer, Integer> PL(Supp, Ind, nr + 1);
4060 PL.set_excluded_point(Zero);
4061 PL.set_verbose(false);
4062 PL.compute(false); // only a single point
4063 PL.put_single_point_into(SubDiv);
4064 if (SubDiv.size() == 0) { // no point found
4065 nothing_found++;
4066 if (g == opt_value - 1) {
4067 if (opt_point.size() == 0)
4068 return opt_point;
4069 return NewCoord.from_sublattice(opt_point); // optimal point found (or nothing found)
4070 }
4071 empty_value = g;
4072 if (nothing_found < 1) // can't be true if "1" is not raised to a higher value
4073 g = empty_value + 1 + (den - 1) * (opt_value - empty_value - 2) / den;
4074 else
4075 g = opt_value - 1;
4076 den *= 2; // not used in the present setting (see above)
4077 }
4078 else { // point found
4079 nothing_found = 0;
4080 den = 2; // back to start value
4081 opt_point = SubDiv;
4082 std::swap(opt_point[0], opt_point[nc]);
4083 opt_point.resize(nc);
4084 if (opt_value == empty_value + 1) {
4085 if (opt_point.size() == 0)
4086 return opt_point;
4087 return NewCoord.from_sublattice(opt_point);
4088 }
4089 opt_value = v_scalar_product(opt_point, N);
4090 g = empty_value + 1 + (opt_value - empty_value - 2) / 2;
4091 }
4092 }
4093 }
4094
4095 template <>
optimal_subdivision_point_inner() const4096 vector<mpq_class> Matrix<mpq_class>::optimal_subdivision_point_inner() const {
4097 assert(false);
4098 return {};
4099 }
4100
4101 template <>
optimal_subdivision_point_inner() const4102 vector<nmz_float> Matrix<nmz_float>::optimal_subdivision_point_inner() const {
4103 assert(false);
4104 return {};
4105 }
4106
4107 #ifdef ENFNORMALIZ
4108 template <>
optimal_subdivision_point_inner() const4109 vector<renf_elem_class> Matrix<renf_elem_class>::optimal_subdivision_point_inner() const {
4110 assert(false);
4111 return {};
4112 }
4113 #endif
4114
4115 //---------------------------------------------------------------------------
4116
4117 // incremental Gram-Schmidt on rows r, from <= r < to (ATTENTION <)
4118 // The orthogonal matrix is B
4119 // Coefficients in M
4120 template <typename Integer>
GramSchmidt(Matrix<nmz_float> & B,Matrix<nmz_float> & M,int from,int to)4121 void Matrix<Integer>::GramSchmidt(Matrix<nmz_float>& B, Matrix<nmz_float>& M, int from, int to) {
4122 // from=0;
4123 // to= (int) nr_of_rows();
4124 assert(to <= (int)nr_of_rows());
4125 size_t dim = nr_of_columns();
4126 for (int i = from; i < to; ++i) {
4127 convert(B[i], elem[i]);
4128 // cout << B[i];
4129 for (int j = 0; j < i; ++j) {
4130 nmz_float sp = 0;
4131 for (size_t k = 0; k < dim; ++k) {
4132 nmz_float fact;
4133 convert(fact, elem[i][k]);
4134 sp += fact * B[j][k];
4135 }
4136 M[i][j] = sp / v_scalar_product(B[j], B[j]);
4137 // cout << "GS " << i << " " << j << " " << sp << " " << v_scalar_product(B[j],B[j]) << " " << M[i][j] << endl;
4138 for (size_t k = 0; k < dim; ++k)
4139 B[i][k] -= M[i][j] * B[j][k];
4140 }
4141 }
4142 }
4143
4144 template <>
GramSchmidt(Matrix<nmz_float> & B,Matrix<nmz_float> & M,int from,int to)4145 void Matrix<mpq_class>::GramSchmidt(Matrix<nmz_float>& B, Matrix<nmz_float>& M, int from, int to) {
4146 assert(false);
4147
4148 /*
4149 // from=0;
4150 // to= (int) nr_of_rows();
4151 assert(to <= (int) nr_of_rows());
4152 size_t dim=nr_of_columns();
4153 for(int i=from;i<to;++i){
4154 convert(B[i],elem[i]);
4155 // cout << B[i];
4156 for(int j=0;j<i;++j){
4157 nmz_float sp=0;
4158 for(size_t k=0;k<dim;++k){
4159 nmz_float fact;
4160 convert(fact,elem[i][k]);
4161 sp+=fact*B[j][k];
4162 }
4163 M[i][j]=sp/v_scalar_product(B[j],B[j]);
4164 // cout << "GS " << i << " " << j << " " << sp << " " << v_scalar_product(B[j],B[j]) << " " << M[i][j] << endl;
4165 for(size_t k=0;k<dim;++k)
4166 B[i][k]-=M[i][j]*B[j][k];
4167 }
4168 }*/
4169 }
4170
4171 #ifdef ENFNORMALIZ
4172 template <>
GramSchmidt(Matrix<nmz_float> & B,Matrix<nmz_float> & M,int from,int to)4173 void Matrix<renf_elem_class>::GramSchmidt(Matrix<nmz_float>& B, Matrix<nmz_float>& M, int from, int to) {
4174 assert(false);
4175
4176 /*
4177 // from=0;
4178 // to= (int) nr_of_rows();
4179 assert(to <= (int) nr_of_rows());
4180 size_t dim=nr_of_columns();
4181 for(int i=from;i<to;++i){
4182 convert(B[i],elem[i]);
4183 // cout << B[i];
4184 for(int j=0;j<i;++j){
4185 nmz_float sp=0;
4186 for(size_t k=0;k<dim;++k){
4187 nmz_float fact;
4188 convert(fact,elem[i][k]);
4189 sp+=fact*B[j][k];
4190 }
4191 M[i][j]=sp/v_scalar_product(B[j],B[j]);
4192 // cout << "GS " << i << " " << j << " " << sp << " " << v_scalar_product(B[j],B[j]) << " " << M[i][j] << endl;
4193 for(size_t k=0;k<dim;++k)
4194 B[i][k]-=M[i][j]*B[j][k];
4195 }
4196 }*/
4197 }
4198 #endif
4199
4200 /*
4201 template<typename Integer>
4202 Matrix<Integer> Matrix<Integer>::LLL_red(Matrix<Integer>& T, Matrix<Integer>& Tinv) const{
4203 // returns Lred =LLL_reduced(L) (sublattice generated by the rows!)
4204 // Lred=T*this, Tinv=inverse(T)
4205 // We follow Gerhard and von zur Gathen; also see Cohen, p.89 (5)
4206
4207 T=Tinv=Matrix<Integer>(nr);
4208
4209 Matrix<Integer> Lred=*this;
4210 size_t dim=nr_of_columns();
4211 int n=nr_of_rows();
4212 // pretty_print(cout);
4213 assert((int) rank()==n);
4214 if(n<=1)
4215 return Lred;
4216
4217 Matrix<nmz_float> G(n,dim);
4218 Matrix<nmz_float> M(n,n);
4219
4220 Lred.GramSchmidt(G,M,0,2);
4221
4222 int i=1;
4223 while(true){
4224
4225 for(int j=i-1;j>=0;--j){
4226 Integer fact;
4227 cout << "MMMMM " << i << " " << j << " " << M[i][j] << endl;
4228 cout << i << "---" << G[i];
4229 cout << j << "---" << G[j];
4230 convert(fact,round(M[i][j]));
4231 v_el_trans<Integer>(Lred[j],Lred[i],-fact,0);
4232 v_el_trans<Integer>(T[j],T[i],-fact,0);
4233 v_el_trans<Integer>(Tinv[i],Tinv[j],fact,0);
4234 Lred.GramSchmidt(G,M,i,i+1);
4235 }
4236 if(i==0){
4237 i=1;
4238 Lred.GramSchmidt(G,M,0,2);
4239 continue;
4240 }
4241 nmz_float t1=v_scalar_product(G[i-1],G[i-1]);
4242 nmz_float t2=v_scalar_product(G[i],G[i]);
4243 if(t1> 2*t2){
4244 std::swap(Lred[i],Lred[i-1]);
4245 std::swap(T[i],T[i-1]);
4246 std::swap(Tinv[i],Tinv[i-1]);
4247 Lred.GramSchmidt(G,M,i-1,i); // i-1,i+1);
4248 // cout << i-1 << "---" << G[i-1];
4249 i--;
4250 }
4251 else{
4252 i++;
4253 if(i>=n)
4254 break;
4255 Lred.GramSchmidt(G,M,i,i+1);
4256 }
4257 }
4258
4259 Tinv=Tinv.transpose();
4260
4261 return Lred;
4262 }*/
4263
4264 /*
4265 #ifdef ENFNORMALIZ
4266 template<>
4267 Matrix<renf_elem_class> Matrix<renf_elem_class>::LLL_red(Matrix<renf_elem_class>& T, Matrix<renf_elem_class>& Tinv) const{
4268
4269 assert(false);
4270 return Matrix<renf_elem_class(0,0);
4271
4272 #endif
4273 */
4274
4275 template <typename Integer>
LLL() const4276 Matrix<Integer> Matrix<Integer>::LLL() const {
4277 Matrix<Integer> Dummy1, Dummy2;
4278 return LLL_red(*this, Dummy1, Dummy2);
4279 }
4280
4281 template <>
LLL() const4282 Matrix<mpq_class> Matrix<mpq_class>::LLL() const {
4283 assert(false);
4284 return {};
4285 }
4286
4287 template <typename Integer>
LLL_transpose() const4288 Matrix<Integer> Matrix<Integer>::LLL_transpose() const {
4289 return transpose().LLL().transpose();
4290 }
4291
4292 #ifndef NMZ_MIC_OFFLOAD // offload with long is not supported
4293 template Matrix<long> readMatrix(const string project);
4294 #endif // NMZ_MIC_OFFLOAD
4295 template Matrix<long long> readMatrix(const string project);
4296 template Matrix<mpz_class> readMatrix(const string project);
4297
4298 template class Matrix<long>;
4299 template class Matrix<long long>;
4300 template class Matrix<mpz_class>;
4301 template class Matrix<mpq_class>;
4302 template class Matrix<nmz_float>;
4303 #ifdef ENFNORMALIZ
4304 template class Matrix<renf_elem_class>;
4305 #endif
4306
4307 //---------------------------------------------------
4308 // routines for binary matrices
4309
4310 // insert binary expansion of val at "planar" coordinates (i,j)
4311 template <typename Integer>
insert(long val,key_t i,key_t j)4312 void BinaryMatrix<Integer>::insert(long val, key_t i, key_t j) {
4313 assert(i < nr_rows);
4314 assert(j < nr_columns);
4315
4316 vector<bool> bin_exp= binary_expansion(val);
4317 /*
4318 while (val != 0) { // binary expansion of val
4319 Integer bin_digit = val % 2;
4320 if (bin_digit == 1)
4321 bin_exp.push_back(true);
4322 else
4323 bin_exp.push_back(false);
4324 val /= 2;
4325 }*/
4326
4327 long add_layers = bin_exp.size() - get_nr_layers();
4328 if (add_layers > 0) {
4329 for (long k = 0; k < add_layers; ++k)
4330 Layers.push_back(vector<dynamic_bitset>(nr_rows, dynamic_bitset(nr_columns)));
4331 }
4332 else {
4333 for (size_t k = bin_exp.size(); k < get_nr_layers(); ++k) // to be on the safe side
4334 Layers[k][i][j] = false; // in case this object was used before
4335 }
4336
4337 for (size_t k = 0; k < bin_exp.size(); ++k) {
4338 Layers[k][i][j] = bin_exp[k];
4339 }
4340 }
4341
4342
4343 // put rows and columns into the order determined by row_order and col:order
4344 template <typename Integer>
reordered(const vector<key_t> & row_order,const vector<key_t> & col_order) const4345 BinaryMatrix<Integer> BinaryMatrix<Integer>::reordered(const vector<key_t>& row_order, const vector<key_t>& col_order) const {
4346 assert(nr_rows == row_order.size());
4347 assert(nr_columns == col_order.size());
4348 size_t ll = get_nr_layers();
4349 BinaryMatrix<Integer> MatReordered(nr_rows, nr_columns, ll);
4350 for (size_t i = 0; i < nr_rows; ++i) {
4351 for (size_t j = 0; j < nr_columns; ++j) {
4352 for (size_t k = 0; k < ll; ++k) {
4353 MatReordered.Layers[k][i][j] = Layers[k][row_order[i]][col_order[j]];
4354 }
4355 }
4356 }
4357 MatReordered.values=values;
4358 MatReordered.mpz_values=mpz_values;
4359 return MatReordered;
4360 }
4361
4362 // constructors
4363 template <typename Integer>
BinaryMatrix()4364 BinaryMatrix<Integer>::BinaryMatrix() {
4365 nr_rows = 0;
4366 nr_columns = 0;
4367 }
4368
4369 template <typename Integer>
BinaryMatrix(size_t m,size_t n)4370 BinaryMatrix<Integer>::BinaryMatrix(size_t m, size_t n) {
4371 nr_rows = m;
4372 nr_columns = n;
4373 // we need at least one layer -- in case only the value 0 is inserted
4374 Layers.push_back(vector<dynamic_bitset>(nr_rows, dynamic_bitset(nr_columns)));
4375 }
4376
4377 template <typename Integer>
BinaryMatrix(size_t m,size_t n,size_t height)4378 BinaryMatrix<Integer>::BinaryMatrix(size_t m, size_t n, size_t height) {
4379 nr_rows = m;
4380 nr_columns = n;
4381 for (size_t k = 0; k < height; ++k)
4382 Layers.push_back(vector<dynamic_bitset>(nr_rows, dynamic_bitset(nr_columns)));
4383 }
4384
4385 // data access & equality
4386
4387 // test bit k in binary expansion at "planar" coordiantes (i,j)
4388 template <typename Integer>
test(key_t i,key_t j,key_t k) const4389 bool BinaryMatrix<Integer>::test(key_t i, key_t j, key_t k) const {
4390 assert(i < nr_rows);
4391 assert(j < nr_columns);
4392 assert(k < Layers.size());
4393 return Layers[k][i].test(j);
4394 }
4395
4396 template <typename Integer>
get_nr_layers() const4397 size_t BinaryMatrix<Integer>::get_nr_layers() const {
4398 return Layers.size();
4399 }
4400
4401 template <typename Integer>
get_nr_rows() const4402 size_t BinaryMatrix<Integer>::get_nr_rows() const {
4403 return nr_rows;
4404 }
4405
4406 template <typename Integer>
get_nr_columns() const4407 size_t BinaryMatrix<Integer>::get_nr_columns() const {
4408 return nr_columns;
4409 }
4410
4411 template <typename Integer>
equal(const BinaryMatrix & Comp) const4412 bool BinaryMatrix<Integer>::equal(const BinaryMatrix& Comp) const {
4413 if (nr_rows != Comp.nr_rows || nr_columns != Comp.nr_columns || get_nr_layers() != Comp.get_nr_layers())
4414 return false;
4415 for (size_t i = 0; i < get_nr_layers(); ++i)
4416 if (Layers[i] != Comp.Layers[i])
4417 return false;
4418 return true;
4419 }
4420
4421 template <typename Integer>
set_values(const vector<Integer> & V)4422 void BinaryMatrix<Integer>::set_values(const vector<Integer>& V) {
4423 values=V;
4424 }
4425
4426 template <typename Integer>
get_data_mpz(BinaryMatrix<mpz_class> & BM_mpz)4427 void BinaryMatrix<Integer>::get_data_mpz(BinaryMatrix<mpz_class>& BM_mpz) {
4428
4429 swap(Layers, BM_mpz.Layers);
4430 swap(mpz_values,BM_mpz.values);
4431 values.resize(0);
4432 }
4433
4434 template <typename Integer>
get_layers() const4435 const vector<vector<dynamic_bitset> >& BinaryMatrix<Integer>::get_layers() const{
4436 return Layers;
4437 }
4438
4439 template <typename Integer>
get_values() const4440 const vector<Integer>& BinaryMatrix<Integer>::get_values() const{
4441 return values;
4442 }
4443
4444 template <typename Integer>
get_mpz_values() const4445 const vector<mpz_class>& BinaryMatrix<Integer>::get_mpz_values() const{
4446 return mpz_values;
4447 }
4448
4449 template <typename Integer>
val_entry(size_t i,size_t j) const4450 long BinaryMatrix<Integer>::val_entry(size_t i, size_t j) const {
4451
4452 assert(i < nr_rows);
4453 assert(j < nr_columns);
4454
4455 long v=0, p2=1;
4456
4457 for(size_t k=0;k < get_nr_layers(); ++k){
4458 long n=0;
4459 if(test(i,j,k))
4460 n=1;
4461 v+=p2*n;
4462 p2*=2;
4463 }
4464 return v;
4465 }
4466
4467
4468 template <typename Integer>
get_value_mat() const4469 Matrix<Integer> BinaryMatrix<Integer>::get_value_mat() const {
4470
4471 Matrix<Integer> VM(nr_rows,nr_columns);
4472 for(size_t i = 0;i < nr_rows; ++i){
4473 for(size_t j = 0; j < nr_columns; ++j){
4474 cout << "EEEEEE " << val_entry(i,j) << endl;
4475 VM[i][j]=values[val_entry(i,j)];
4476 }
4477 }
4478 return VM;
4479 }
4480
4481 template <typename Integer>
get_mpz_value_mat() const4482 Matrix<mpz_class> BinaryMatrix<Integer>::get_mpz_value_mat() const {
4483
4484 Matrix<mpz_class> VM(nr_rows,nr_columns);
4485 for(size_t i = 0;i < nr_rows; ++i){
4486 for(size_t j = 0; j < nr_columns; ++j){
4487 VM[i][j]=mpz_values[val_entry(i,j)];
4488 }
4489 }
4490 return VM;
4491 }
4492
4493
4494 template <typename Integer>
pretty_print(std::ostream & out,bool with_row_nr) const4495 void BinaryMatrix<Integer>::pretty_print(std::ostream& out, bool with_row_nr) const{
4496
4497 if(values.size() > 0) {
4498 Matrix<Integer> PM=get_value_mat();
4499 PM.pretty_print(out,with_row_nr);
4500 }
4501 else if(mpz_values.size() > 0){
4502 Matrix<mpz_class> PM=get_mpz_value_mat();
4503 PM.pretty_print(out,with_row_nr);
4504 }
4505 }
4506
4507 template class BinaryMatrix<long>;
4508 template class BinaryMatrix<long long>;
4509 template class BinaryMatrix<mpz_class>;
4510 #ifdef ENFNORMALIZ
4511 template class BinaryMatrix<renf_elem_class>;
4512 #endif
4513
4514 //-----------------------------------------------------------------------
4515
4516 // determines the maximal subsets in a vector of subsets given by their indicator vectors
4517 // result returned in is_max_subset
4518 // if is_max_subset has size 0, it is fully set in this routine
4519 // otherwise it is supposed to be pre-information: the entry false means:
4520 // already known not to be not maximal (or irrelevant)
4521 // if a set occurs more than once, only the last instance is recognized as maximal
4522 template <typename IncidenceVector>
maximal_subsets(const vector<IncidenceVector> & ind,IncidenceVector & is_max_subset)4523 void maximal_subsets(const vector<IncidenceVector>& ind, IncidenceVector& is_max_subset) {
4524 if (ind.size() == 0)
4525 return;
4526
4527 if(is_max_subset.size() == 0){
4528 is_max_subset.resize(ind.size());
4529 for(size_t i=0; i<is_max_subset.size();++i)
4530 is_max_subset[i] = true;
4531 }
4532
4533 assert(is_max_subset.size() == ind.size());
4534
4535 size_t nr_sets = ind.size();
4536 size_t card = ind[0].size();
4537 vector<key_t> elem(card);
4538
4539 for (size_t i = 0; i < nr_sets; i++) {
4540 if (!is_max_subset[i]) // already known to be non-maximal
4541 continue;
4542
4543 size_t k = 0; // counts the number of elements in set with index i
4544 for (size_t j = 0; j < card; j++) {
4545 if (ind[i][j]) {
4546 elem[k] = j;
4547 k++;
4548 }
4549 }
4550
4551 for (size_t j = 0; j < nr_sets; j++) {
4552 if (i == j || !is_max_subset[j]) // don't compare with itself or something known not to be maximal
4553 continue;
4554 size_t t;
4555 for (t = 0; t < k; t++) {
4556 if (!ind[j][elem[t]])
4557 break; // not a superset
4558 }
4559 if (t == k) { // found a superset
4560 is_max_subset[i] = false;
4561 break; // the loop over j
4562 }
4563 }
4564 }
4565 }
4566
4567 template <>
maximal_subsets(const vector<dynamic_bitset> & ind,dynamic_bitset & is_max_subset)4568 void maximal_subsets(const vector<dynamic_bitset>& ind, dynamic_bitset& is_max_subset) {
4569 if (ind.size() == 0)
4570 return;
4571
4572 if(is_max_subset.size() == 0){
4573 is_max_subset.resize(ind.size());
4574 is_max_subset.set();
4575 }
4576
4577 assert(is_max_subset.size() == ind.size());
4578
4579 size_t nr_sets = ind.size();
4580 for(size_t i=0; i< nr_sets; ++i){
4581 if(!is_max_subset[i])
4582 continue;
4583 for(size_t j=0; j < nr_sets; ++j){
4584 if(i==j || !is_max_subset[j]) // don't compare to itself or something known not to be maximal
4585 continue;
4586 if(ind[i].is_subset_of(ind[j])){
4587 is_max_subset[i] = false;
4588 break;
4589 }
4590 }
4591 }
4592 }
4593
4594 template void maximal_subsets(const vector<vector<bool> >&, vector<bool>&);
4595 template void maximal_subsets(const vector<dynamic_bitset>&, dynamic_bitset&);
4596
4597 template <typename Integer>
makeIncidenceMatrix(vector<dynamic_bitset> & IncidenceMatrix,const Matrix<Integer> & Gens,const Matrix<Integer> & LinForms)4598 void makeIncidenceMatrix(vector<dynamic_bitset>& IncidenceMatrix, const Matrix<Integer>& Gens, const Matrix<Integer>& LinForms){
4599
4600 IncidenceMatrix = vector<dynamic_bitset>(LinForms.nr_of_rows(), dynamic_bitset(Gens.nr_of_rows()) );
4601
4602 std::exception_ptr tmp_exception;
4603 bool skip_remaining = false;
4604
4605 #pragma omp parallel for
4606 for (size_t i = 0; i < LinForms.nr_of_rows(); ++i) {
4607
4608 if(skip_remaining)
4609 continue;
4610
4611 try {
4612
4613 INTERRUPT_COMPUTATION_BY_EXCEPTION
4614
4615 for (size_t j = 0; j < Gens.nr_of_rows(); ++j) {
4616 if (v_scalar_product(LinForms[i], Gens[j]) == 0)
4617 IncidenceMatrix[i][j] = 1;
4618 }
4619
4620 } catch (const std::exception&) {
4621 tmp_exception = std::current_exception();
4622 skip_remaining = true;
4623 #pragma omp flush(skip_remaining)
4624 }
4625
4626 }
4627 if (!(tmp_exception == 0))
4628 std::rethrow_exception(tmp_exception);
4629 }
4630
4631 template void makeIncidenceMatrix(vector<dynamic_bitset> &, const Matrix<long>&, const Matrix<long>&);
4632 template void makeIncidenceMatrix(vector<dynamic_bitset> &, const Matrix<long long>&, const Matrix<long long>&);
4633 template void makeIncidenceMatrix(vector<dynamic_bitset> &, const Matrix<mpz_class>&, const Matrix<mpz_class>&);
4634 #ifdef ENFNORMALIZ
4635 template void makeIncidenceMatrix(vector<dynamic_bitset> &, const Matrix<renf_elem_class>&, const Matrix<renf_elem_class>&);
4636 #endif
4637
4638 } // namespace libnormaliz
4639