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