Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

563624 views
1
/*
2
* Normaliz
3
* Copyright (C) 2007-2014 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 <math.h>
30
#include <iomanip>
31
32
#include "libnormaliz/matrix.h"
33
#include "libnormaliz/cone.h"
34
#include "libnormaliz/vector_operations.h"
35
#include "libnormaliz/normaliz_exception.h"
36
#include "libnormaliz/sublattice_representation.h"
37
38
//---------------------------------------------------------------------------
39
40
namespace libnormaliz {
41
using namespace std;
42
43
//---------------------------------------------------------------------------
44
//Public
45
//---------------------------------------------------------------------------
46
47
template<typename Integer>
48
Matrix<Integer>::Matrix(){
49
nr=0;
50
nc=0;
51
}
52
53
//---------------------------------------------------------------------------
54
55
template<typename Integer>
56
Matrix<Integer>::Matrix(size_t dim){
57
nr=dim;
58
nc=dim;
59
elem = vector< vector<Integer> >(dim, vector<Integer>(dim));
60
for (size_t i = 0; i < dim; i++) {
61
elem[i][i]=1;
62
}
63
}
64
65
//---------------------------------------------------------------------------
66
67
template<typename Integer>
68
Matrix<Integer>::Matrix(size_t row, size_t col){
69
nr=row;
70
nc=col;
71
elem = vector< vector<Integer> >(row, vector<Integer>(col));
72
}
73
74
//---------------------------------------------------------------------------
75
76
template<typename Integer>
77
Matrix<Integer>::Matrix(size_t row, size_t col, Integer value){
78
nr=row;
79
nc=col;
80
elem = vector< vector<Integer> > (row, vector<Integer>(col,value));
81
}
82
83
//---------------------------------------------------------------------------
84
85
template<typename Integer>
86
Matrix<Integer>::Matrix(const vector< vector<Integer> >& new_elem){
87
nr=new_elem.size();
88
if (nr>0) {
89
nc=new_elem[0].size();
90
elem=new_elem;
91
//check if all rows have the same length
92
for (size_t i=1; i<nr; i++) {
93
if (elem[i].size() != nc) {
94
throw BadInputException("Inconsistent lengths of rows in matrix!");
95
}
96
}
97
} else {
98
nc=0;
99
}
100
}
101
102
//---------------------------------------------------------------------------
103
104
template<typename Integer>
105
Matrix<Integer>::Matrix(const list< vector<Integer> >& new_elem){
106
nr = new_elem.size();
107
elem = vector< vector<Integer> > (nr);
108
nc = 0;
109
size_t i=0;
110
typename list< vector<Integer> >::const_iterator it=new_elem.begin();
111
for(; it!=new_elem.end(); ++it, ++i) {
112
if(i == 0) {
113
nc = (*it).size();
114
} else {
115
if ((*it).size() != nc) {
116
throw BadInputException("Inconsistent lengths of rows in matrix!");
117
}
118
}
119
elem[i]=(*it);
120
}
121
}
122
123
//---------------------------------------------------------------------------
124
/*
125
template<typename Integer>
126
void Matrix<Integer>::write(istream& in){
127
size_t i,j;
128
for(i=0; i<nr; i++){
129
for(j=0; j<nc; j++) {
130
in >> elem[i][j];
131
}
132
}
133
}
134
*/
135
//---------------------------------------------------------------------------
136
137
template<typename Integer>
138
void Matrix<Integer>::write_column(size_t col, const vector<Integer>& data){
139
assert(col >= 0);
140
assert(col < nc);
141
assert(nr == data.size());
142
143
for (size_t i = 0; i < nr; i++) {
144
elem[i][col]=data[i];
145
}
146
}
147
148
//---------------------------------------------------------------------------
149
150
template<typename Integer>
151
void Matrix<Integer>::print(const string& name,const string& suffix) const{
152
string file_name = name+"."+suffix;
153
const char* file = file_name.c_str();
154
ofstream out(file);
155
print(out);
156
out.close();
157
}
158
159
//---------------------------------------------------------------------------
160
161
template<typename Integer>
162
void Matrix<Integer>::print_append(const string& name,const string& suffix) const{
163
string file_name = name+"."+suffix;
164
const char* file = file_name.c_str();
165
ofstream out(file,ios_base::app);
166
print(out);
167
out.close();
168
}
169
170
//---------------------------------------------------------------------------
171
172
template<typename Integer>
173
void Matrix<Integer>::print(ostream& out, bool with_format) const{
174
size_t i,j;
175
if(with_format)
176
out<<nr<<endl<<nc<<endl;
177
for (i = 0; i < nr; i++) {
178
for (j = 0; j < nc; j++) {
179
out<<elem[i][j]<<" ";
180
}
181
out<<endl;
182
}
183
}
184
185
//---------------------------------------------------------------------------
186
187
template<typename Integer>
188
void Matrix<Integer>::pretty_print(ostream& out, bool with_row_nr) const{
189
if(nr>1000000 && !with_row_nr){
190
print(out,false);
191
return;
192
}
193
size_t i,j;
194
vector<size_t> max_length = maximal_decimal_length_columnwise();
195
size_t max_index_length = decimal_length(nr);
196
for (i = 0; i < nr; i++) {
197
if (with_row_nr) {
198
out << std::setw(max_index_length+1) << i<< ": ";
199
}
200
for (j = 0; j < nc; j++) {
201
out << std::setw(max_length[j]+1) << elem[i][j];
202
}
203
out<<endl;
204
}
205
}
206
207
//---------------------------------------------------------------------------
208
209
template<typename Integer>
210
size_t Matrix<Integer>::nr_of_rows () const{
211
return nr;
212
}
213
214
//---------------------------------------------------------------------------
215
216
template<typename Integer>
217
size_t Matrix<Integer>::nr_of_columns () const{
218
return nc;
219
}
220
221
//---------------------------------------------------------------------------
222
223
template<typename Integer>
224
void Matrix<Integer>::set_nr_of_columns(size_t c){
225
nc=c;
226
}
227
228
//---------------------------------------------------------------------------
229
230
template<typename Integer>
231
void Matrix<Integer>::random (int mod) {
232
size_t i,j;
233
int k;
234
for (i = 0; i < nr; i++) {
235
for (j = 0; j < nc; j++) {
236
k = rand();
237
elem[i][j]=k % mod;
238
}
239
}
240
}
241
//---------------------------------------------------------------------------
242
243
template<typename Integer>
244
void Matrix<Integer>::set_zero() {
245
size_t i,j;
246
for (i = 0; i < nr; i++) {
247
for (j = 0; j < nc; j++) {
248
elem[i][j] = 0;
249
}
250
}
251
}
252
253
//---------------------------------------------------------------------------
254
255
template<typename Integer>
256
void Matrix<Integer>::select_submatrix(const Matrix<Integer>& mother, const vector<key_t>& rows){
257
258
assert(nr>=rows.size());
259
assert(nc>=mother.nc);
260
261
size_t size=rows.size(), j;
262
for (size_t i=0; i < size; i++) {
263
j=rows[i];
264
for(size_t k=0;k<mother.nc;++k)
265
elem[i][k]=mother[j][k];
266
}
267
}
268
269
//---------------------------------------------------------------------------
270
271
template<typename Integer>
272
void Matrix<Integer>::select_submatrix_trans(const Matrix<Integer>& mother, const vector<key_t>& rows){
273
274
assert(nc>=rows.size());
275
assert(nr>=mother.nc);
276
277
size_t size=rows.size(), j;
278
for (size_t i=0; i < size; i++) {
279
j=rows[i];
280
for(size_t k=0;k<mother.nc;++k)
281
elem[k][i]=mother[j][k];
282
}
283
}
284
285
//---------------------------------------------------------------------------
286
287
template<typename Integer>
288
Matrix<Integer> Matrix<Integer>::submatrix(const vector<key_t>& rows) const{
289
size_t size=rows.size(), j;
290
Matrix<Integer> M(size, nc);
291
for (size_t i=0; i < size; i++) {
292
j=rows[i];
293
assert(j >= 0);
294
assert(j < nr);
295
M.elem[i]=elem[j];
296
}
297
return M;
298
}
299
300
//---------------------------------------------------------------------------
301
302
template<typename Integer>
303
Matrix<Integer> Matrix<Integer>::submatrix(const vector<int>& rows) const{
304
size_t size=rows.size(), j;
305
Matrix<Integer> M(size, nc);
306
for (size_t i=0; i < size; i++) {
307
j=rows[i];
308
assert(j >= 0);
309
assert(j < nr);
310
M.elem[i]=elem[j];
311
}
312
return M;
313
}
314
315
//---------------------------------------------------------------------------
316
317
template<typename Integer>
318
Matrix<Integer> Matrix<Integer>::submatrix(const vector<bool>& rows) const{
319
assert(rows.size() == nr);
320
size_t size=0;
321
for (size_t i = 0; i <rows.size(); i++) {
322
if (rows[i]) {
323
size++;
324
}
325
}
326
Matrix<Integer> M(size, nc);
327
size_t j = 0;
328
for (size_t i = 0; i < nr; i++) {
329
if (rows[i]) {
330
M.elem[j++] = elem[i];
331
}
332
}
333
return M;
334
}
335
336
//---------------------------------------------------------------------------
337
338
template<typename Integer>
339
Matrix<Integer>& Matrix<Integer>::remove_zero_rows() {
340
size_t from = 0, to = 0; // maintain to <= from
341
while (from < nr && v_is_zero(elem[from])) from++; //skip zero rows
342
while (from < nr) { // go over matrix
343
// now from is a non-zero row
344
if (to != from) elem[to].swap(elem[from]);
345
++to; ++from;
346
while (from < nr && v_is_zero(elem[from])) from++; //skip zero rows
347
}
348
nr = to;
349
elem.resize(nr);
350
return *this;
351
}
352
353
//---------------------------------------------------------------------------
354
355
template<typename Integer>
356
void Matrix<Integer>::swap(Matrix<Integer>& x) {
357
size_t tmp = nr; nr = x.nr; x.nr = tmp;
358
tmp = nc; nc = x.nc; x.nc = tmp;
359
elem.swap(x.elem);
360
}
361
362
//---------------------------------------------------------------------------
363
364
template<typename Integer>
365
void Matrix<Integer>::resize(size_t nr_rows, size_t nr_cols) {
366
nc = nr_cols; //for adding new rows with the right length
367
resize(nr_rows);
368
resize_columns(nr_cols);
369
}
370
371
template<typename Integer>
372
void Matrix<Integer>::resize(size_t nr_rows) {
373
if (nr_rows > elem.size()) {
374
elem.resize(nr_rows, vector<Integer>(nc));
375
}
376
nr = nr_rows;
377
}
378
379
template<typename Integer>
380
void Matrix<Integer>::resize_columns(size_t nr_cols) {
381
for (size_t i=0; i<nr; i++) {
382
elem[i].resize(nr_cols);
383
}
384
nc = nr_cols;
385
}
386
387
//---------------------------------------------------------------------------
388
389
template<typename Integer>
390
vector<Integer> Matrix<Integer>::diagonal() const{
391
assert(nr == nc);
392
vector<Integer> diag(nr);
393
for(size_t i=0; i<nr;i++){
394
diag[i]=elem[i][i];
395
}
396
return diag;
397
}
398
399
//---------------------------------------------------------------------------
400
401
template<typename Integer>
402
size_t Matrix<Integer>::maximal_decimal_length() const{
403
size_t i,maxim=0;
404
vector<size_t> maxim_col;
405
maxim_col=maximal_decimal_length_columnwise();
406
for (i = 0; i <nr; i++)
407
maxim=max(maxim,maxim_col[i]);
408
return maxim;
409
}
410
411
//---------------------------------------------------------------------------
412
413
template<typename Integer>
414
vector<size_t> Matrix<Integer>::maximal_decimal_length_columnwise() const{
415
size_t i,j=0;
416
vector<size_t> maxim(nc,0);
417
vector<Integer> pos_max(nc,0), neg_max(nc,0);
418
for (i = 0; i <nr; i++) {
419
for (j = 0; j <nc; j++) {
420
// maxim[j]=max(maxim[j],decimal_length(elem[i][j]));
421
if(elem[i][j]<0){
422
if(elem[i][j]<neg_max[j])
423
neg_max[j]=elem[i][j];
424
continue;
425
}
426
if(elem[i][j]>pos_max[j])
427
pos_max[j]=elem[i][j];
428
}
429
}
430
for(size_t j=0;j<nc;++j)
431
maxim[j]=max(decimal_length(neg_max[j]),decimal_length(pos_max[j]));
432
return maxim;
433
}
434
435
//---------------------------------------------------------------------------
436
437
template<typename Integer>
438
void Matrix<Integer>::append(const Matrix<Integer>& M) {
439
assert (nc == M.nc);
440
elem.reserve(nr+M.nr);
441
/* for (size_t i=0; i<M.nr; i++) {
442
elem.push_back(M.elem[i]);
443
}*/
444
elem.insert(elem.end(),M.elem.begin(),M.elem.end());
445
nr += M.nr;
446
}
447
448
//---------------------------------------------------------------------------
449
450
template<typename Integer>
451
void Matrix<Integer>::append(const vector<vector<Integer> >& M) {
452
if(M.size()==0)
453
return;
454
assert (nc == M[0].size());
455
elem.reserve(nr+M.size());
456
for (size_t i=0; i<M.size(); i++) {
457
elem.push_back(M[i]);
458
}
459
nr += M.size();
460
}
461
462
//---------------------------------------------------------------------------
463
464
template<typename Integer>
465
void Matrix<Integer>::append(const vector<Integer>& V) {
466
assert (nc == V.size());
467
elem.push_back(V);
468
nr++;
469
}
470
471
//---------------------------------------------------------------------------
472
473
template<typename Integer>
474
void Matrix<Integer>::append_column(const vector<Integer>& v) {
475
assert (nr == v.size());
476
for (size_t i=0; i<nr; i++) {
477
elem[i].resize(nc+1);
478
elem[i][nc] = v[i];
479
}
480
nc++;
481
}
482
483
//---------------------------------------------------------------------------
484
485
template<typename Integer>
486
void Matrix<Integer>::remove_row(const vector<Integer>& row) {
487
size_t tmp_nr = nr;
488
for (size_t i = 1; i <= tmp_nr; ++i) {
489
if (elem[tmp_nr-i] == row) {
490
elem.erase(elem.begin()+(tmp_nr-i));
491
nr--;
492
}
493
}
494
}
495
496
//---------------------------------------------------------------------------
497
498
template<typename Integer>
499
void Matrix<Integer>::remove_row(const size_t index) {
500
assert(index<nr);
501
nr--;
502
elem.erase(elem.begin()+(index));
503
}
504
505
//---------------------------------------------------------------------------
506
507
template<typename Integer>
508
vector<size_t> Matrix<Integer>::remove_duplicate_and_zero_rows() {
509
bool remove_some = false;
510
vector<bool> key(nr, true);
511
vector<size_t> original_row;
512
513
set<vector<Integer> > SortedRows;
514
SortedRows.insert( vector<Integer>(nc,0) );
515
typename set<vector<Integer> >::iterator found;
516
for (size_t i = 0; i<nr; i++) {
517
found = SortedRows.find(elem[i]);
518
if (found != SortedRows.end()) {
519
key[i] = false;
520
remove_some = true;
521
}
522
else{
523
SortedRows.insert(found,elem[i]);
524
original_row.push_back(i);
525
}
526
}
527
528
if (remove_some) {
529
*this = submatrix(key);
530
}
531
return original_row;
532
}
533
534
//---------------------------------------------------------------------------
535
536
template<typename Integer>
537
void Matrix<Integer>::remove_duplicate(const Matrix<Integer>& M) {
538
bool remove_some = false;
539
vector<bool> key(nr, true);
540
541
// TODO more efficient! sorted rows
542
for (size_t i = 0; i<nr; i++) {
543
for (size_t j=0;j<M.nr_of_rows();j++){
544
if (elem[i]==M[j]){
545
remove_some=true;
546
key[i]=false;
547
break;
548
}
549
}
550
}
551
552
if (remove_some) {
553
*this = submatrix(key);
554
}
555
}
556
557
//---------------------------------------------------------------------------
558
559
template<typename Integer>
560
Matrix<Integer> Matrix<Integer>::add(const Matrix<Integer>& A) const{
561
assert (nr == A.nr);
562
assert (nc == A.nc);
563
564
Matrix<Integer> B(nr,nc);
565
size_t i,j;
566
for(i=0; i<nr;i++){
567
for(j=0; j<nc; j++){
568
B.elem[i][j]=elem[i][j]+A.elem[i][j];
569
}
570
}
571
return B;
572
}
573
574
//---------------------------------------------------------------------------
575
576
template<typename Integer>
577
Matrix<Integer> Matrix<Integer>::multiplication(const Matrix<Integer>& A) const{
578
assert (nc == A.nr);
579
580
Matrix<Integer> Atrans=A.transpose();
581
Matrix<Integer> B(nr,A.nc); //initialized with 0
582
size_t i,j,k;
583
for(i=0; i<B.nr;i++){
584
for(j=0; j<B.nc; j++){
585
for(k=0; k<nc; k++){
586
B[i][j]=v_scalar_product(elem[i],Atrans[j]);
587
}
588
}
589
}
590
return B;
591
}
592
593
//---------------------------------------------------------------------------
594
595
template<typename Integer>
596
Matrix<Integer> Matrix<Integer>::multiplication(const Matrix<Integer>& A, long m) const{
597
assert (nc == A.nr);
598
599
Matrix<Integer> B(nr,A.nc,0); //initialized with 0
600
size_t i,j,k;
601
for(i=0; i<B.nr;i++){
602
for(j=0; j<B.nc; j++){
603
for(k=0; k<nc; k++){
604
B.elem[i][j]=(B.elem[i][j]+elem[i][k]*A.elem[k][j])%m;
605
if (B.elem[i][j]<0) {
606
B.elem[i][j]=B.elem[i][j]+m;
607
}
608
}
609
}
610
}
611
return B;
612
}
613
614
//---------------------------------------------------------------------------
615
616
template<typename Integer>
617
bool Matrix<Integer>::equal(const Matrix<Integer>& A) const{
618
if ((nr!=A.nr)||(nc!=A.nc)){ return false; }
619
size_t i,j;
620
for (i=0; i < nr; i++) {
621
for (j = 0; j < nc; j++) {
622
if (elem[i][j]!=A.elem[i][j]) {
623
return false;
624
}
625
}
626
}
627
return true;
628
}
629
630
//---------------------------------------------------------------------------
631
632
template<typename Integer>
633
bool Matrix<Integer>::equal(const Matrix<Integer>& A, long m) const{
634
if ((nr!=A.nr)||(nc!=A.nc)){ return false; }
635
size_t i,j;
636
for (i=0; i < nr; i++) {
637
for (j = 0; j < nc; j++) {
638
if (((elem[i][j]-A.elem[i][j]) % m)!=0) {
639
return false;
640
}
641
}
642
}
643
return true;
644
}
645
646
//---------------------------------------------------------------------------
647
648
template<typename Integer>
649
Matrix<Integer> Matrix<Integer>::transpose()const{
650
Matrix<Integer> B(nc,nr);
651
size_t i,j;
652
for(i=0; i<nr;i++){
653
for(j=0; j<nc; j++){
654
B.elem[j][i]=elem[i][j];
655
}
656
}
657
return B;
658
}
659
660
//---------------------------------------------------------------------------
661
662
template<typename Integer>
663
void Matrix<Integer>::scalar_multiplication(const Integer& scalar){
664
size_t i,j;
665
for(i=0; i<nr;i++){
666
for(j=0; j<nc; j++){
667
elem[i][j] *= scalar;
668
}
669
}
670
}
671
672
//---------------------------------------------------------------------------
673
674
template<typename Integer>
675
void Matrix<Integer>::scalar_division(const Integer& scalar){
676
size_t i,j;
677
assert(scalar != 0);
678
for(i=0; i<nr;i++){
679
for(j=0; j<nc; j++){
680
assert (elem[i][j]%scalar == 0);
681
elem[i][j] /= scalar;
682
}
683
}
684
}
685
686
//---------------------------------------------------------------------------
687
688
template<typename Integer>
689
void Matrix<Integer>::reduction_modulo(const Integer& modulo){
690
size_t i,j;
691
for(i=0; i<nr;i++){
692
for(j=0; j<nc; j++){
693
elem[i][j] %= modulo;
694
if (elem[i][j] < 0) {
695
elem[i][j] += modulo;
696
}
697
}
698
}
699
}
700
701
//---------------------------------------------------------------------------
702
703
template<typename Integer>
704
Integer Matrix<Integer>::matrix_gcd() const{
705
Integer g=0,h;
706
for (size_t i = 0; i <nr; i++) {
707
h = v_gcd(elem[i]);
708
g = libnormaliz::gcd<Integer>(g, h);
709
if (g==1) return g;
710
}
711
return g;
712
}
713
714
//---------------------------------------------------------------------------
715
716
template<typename Integer>
717
vector<Integer> Matrix<Integer>::make_prime() {
718
vector<Integer> g(nr);
719
for (size_t i = 0; i <nr; i++) {
720
g[i] = v_make_prime(elem[i]);
721
}
722
return g;
723
}
724
725
//---------------------------------------------------------------------------
726
727
template<typename Integer>
728
void Matrix<Integer>::make_cols_prime(size_t from_col, size_t to_col) {
729
730
for (size_t k = from_col; k <= to_col; k++) {
731
Integer g=0;
732
for (size_t i = 0; i < nr; i++){
733
g = libnormaliz::gcd(g,elem[i][k]);
734
if (g==1) {
735
break;
736
}
737
}
738
for (size_t i = 0; i < nr; i++)
739
elem[i][k]/=g;
740
}
741
}
742
743
//---------------------------------------------------------------------------
744
745
template<typename Integer>
746
Matrix<Integer> Matrix<Integer>::multiply_rows(const vector<Integer>& m) const{ //row i is multiplied by m[i]
747
Matrix M = Matrix(nr,nc);
748
size_t i,j;
749
for (i = 0; i<nr; i++) {
750
for (j = 0; j<nc; j++) {
751
M.elem[i][j] = elem[i][j]*m[i];
752
}
753
}
754
return M;
755
}
756
757
//---------------------------------------------------------------------------
758
759
template<typename Integer>
760
void Matrix<Integer>::MxV(vector<Integer>& result, const vector<Integer>& v) const{
761
assert (nc == v.size());
762
result.resize(nr);
763
for(size_t i=0; i<nr;i++){
764
result[i]=v_scalar_product(elem[i],v);
765
}
766
}
767
768
//---------------------------------------------------------------------------
769
770
template<typename Integer>
771
vector<Integer> Matrix<Integer>::MxV(const vector<Integer>& v) const{
772
vector<Integer> w(nr);
773
MxV(w, v);
774
return w;
775
}
776
777
//---------------------------------------------------------------------------
778
779
template<typename Integer>
780
vector<Integer> Matrix<Integer>::VxM(const vector<Integer>& v) const{
781
assert (nr == v.size());
782
vector<Integer> w(nc,0);
783
size_t i,j;
784
for (i=0; i<nc; i++){
785
for (j=0; j<nr; j++){
786
w[i] += v[j]*elem[j][i];
787
}
788
if(!check_range(w[i]))
789
break;
790
}
791
if(i==nc)
792
return w;
793
Matrix<mpz_class> mpz_this(nr,nc);
794
mat_to_mpz(*this,mpz_this);
795
vector<mpz_class> mpz_v(nr);
796
convert(mpz_v, v);
797
vector<mpz_class> mpz_w=mpz_this.VxM(mpz_v);
798
convert(w,mpz_w);
799
return w;
800
}
801
802
//---------------------------------------------------------------------------
803
804
template<typename Integer>
805
vector<Integer> Matrix<Integer>::VxM_div(const vector<Integer>& v, const Integer& divisor, bool& success) const{
806
assert (nr == v.size());
807
vector<Integer> w(nc,0);
808
success=true;
809
size_t i,j;
810
for (i=0; i<nc; i++){
811
for (j=0; j<nr; j++){
812
w[i] += v[j]*elem[j][i];
813
}
814
if(!check_range(w[i])){
815
success=false;
816
break;
817
}
818
}
819
820
if(success)
821
v_scalar_division(w,divisor);
822
823
return w;
824
}
825
826
//---------------------------------------------------------------------------
827
828
template<typename Integer>
829
bool Matrix<Integer>::is_diagonal() const{
830
831
for(size_t i=0;i<nr;++i)
832
for(size_t j=0;j<nc;++j)
833
if(i!=j && elem[i][j]!=0)
834
return false;
835
return true;
836
}
837
838
//---------------------------------------------------------------------------
839
840
template<typename Integer>
841
vector<long> Matrix<Integer>::pivot(size_t corner){
842
assert(corner < nc);
843
assert(corner < nr);
844
size_t i,j;
845
Integer help=0;
846
vector<long> v(2,-1);
847
848
for (i = corner; i < nr; i++) {
849
for (j = corner; j < nc; j++) {
850
if (elem[i][j]!=0) {
851
if ((help==0)||(Iabs(elem[i][j])<help)) {
852
help=Iabs(elem[i][j]);
853
v[0]=i;
854
v[1]=j;
855
if (help == 1) return v;
856
}
857
}
858
}
859
}
860
861
return v;
862
}
863
864
//---------------------------------------------------------------------------
865
866
template<typename Integer>
867
long Matrix<Integer>::pivot_column(size_t row,size_t col){
868
assert(col < nc);
869
assert(row < nr);
870
size_t i;
871
long j=-1;
872
Integer help=0;
873
874
for (i = row; i < nr; i++) {
875
if (elem[i][col]!=0) {
876
if ((help==0)||(Iabs(elem[i][col])<help)) {
877
help=Iabs(elem[i][col]);
878
j=i;
879
if (help == 1) return j;
880
}
881
}
882
}
883
884
return j;
885
}
886
887
//---------------------------------------------------------------------------
888
889
template<typename Integer>
890
long Matrix<Integer>::pivot_column(size_t col){
891
return pivot_column(col,col);
892
}
893
894
//---------------------------------------------------------------------------
895
896
template<typename Integer>
897
void Matrix<Integer>::exchange_rows(const size_t& row1, const size_t& row2){
898
if (row1 == row2) return;
899
assert(row1 < nr);
900
assert(row2 < nr);
901
elem[row1].swap(elem[row2]);
902
}
903
904
//---------------------------------------------------------------------------
905
906
template<typename Integer>
907
void Matrix<Integer>::exchange_columns(const size_t& col1, const size_t& col2){
908
if (col1 == col2) return;
909
assert(col1 < nc);
910
assert(col2 < nc);
911
for(size_t i=0; i<nr;i++){
912
std::swap(elem[i][col1], elem[i][col2]);
913
}
914
}
915
916
//---------------------------------------------------------------------------
917
918
template<typename Integer>
919
bool Matrix<Integer>::reduce_row (size_t row, size_t col) {
920
assert(col < nc);
921
assert(row < nr);
922
size_t i,j;
923
Integer help;
924
for (i =row+1; i < nr; i++) {
925
if (elem[i][col]!=0) {
926
help=elem[i][col] / elem[row][col];
927
for (j = col; j < nc; j++) {
928
elem[i][j] -= help*elem[row][j];
929
if (!check_range(elem[i][j]) ) {
930
return false;
931
}
932
}
933
// v_el_trans<Integer>(elem[row],elem[i],-help,col);
934
}
935
}
936
return true;
937
}
938
939
//---------------------------------------------------------------------------
940
941
template<typename Integer>
942
bool Matrix<Integer>::reduce_row (size_t corner) {
943
return reduce_row(corner,corner);
944
}
945
946
//---------------------------------------------------------------------------
947
948
template<typename Integer>
949
bool Matrix<Integer>::reduce_rows_upwards () {
950
// assumes that "this" is in row echelon form
951
// and reduces eevery column in which the rank jumps
952
// by its lowest element
953
954
if(nr==0)
955
return true;
956
957
for(size_t row=0;row<nr;++row){
958
size_t col;
959
for(col=0;col<nc;++col)
960
if(elem[row][col]!=0)
961
break;
962
if(col==nc)
963
continue;
964
if(elem[row][col]<0)
965
v_scalar_multiplication<Integer>(elem[row],-1);
966
967
for(long i=row-1;i>=0;--i){
968
Integer quot, rem;
969
970
minimal_remainder(elem[i][col],elem[row][col],quot,rem);
971
elem[i][col]=rem;
972
for(size_t j=col+1;j<nc;++j){
973
elem[i][j]-=quot* elem[row][j];
974
if ( !check_range(elem[i][j]) ) {
975
return false;
976
}
977
}
978
}
979
}
980
return true;
981
}
982
983
//---------------------------------------------------------------------------
984
985
template<typename Integer>
986
bool Matrix<Integer>::linear_comb_columns(const size_t& col,const size_t& j,
987
const Integer& u,const Integer& w,const Integer& v,const Integer& z){
988
989
for(size_t i=0;i<nr;++i){
990
Integer rescue=elem[i][col];
991
elem[i][col]=u*elem[i][col]+v*elem[i][j];
992
elem[i][j]=w*rescue+z*elem[i][j];
993
if ( (!check_range(elem[i][col]) || !check_range(elem[i][j]) )) {
994
return false;
995
}
996
}
997
return true;
998
}
999
1000
//---------------------------------------------------------------------------
1001
1002
template<typename Integer>
1003
bool Matrix<Integer>::gcd_reduce_column (size_t corner, Matrix<Integer>& Right){
1004
assert(corner < nc);
1005
assert(corner < nr);
1006
Integer d,u,w,z,v;
1007
for(size_t j=corner+1;j<nc;++j){
1008
d=ext_gcd(elem[corner][corner],elem[corner][j],u,v);
1009
w=-elem[corner][j]/d;
1010
z=elem[corner][corner]/d;
1011
// Now we multiply the submatrix formed by columns "corner" and "j"
1012
// and rows corner,...,nr from the right by the 2x2 matrix
1013
// | u w |
1014
// | v z |
1015
if(!linear_comb_columns(corner,j,u,w,v,z))
1016
return false;
1017
if(!Right.linear_comb_columns(corner,j,u,w,v,z))
1018
return false;
1019
}
1020
return true;
1021
}
1022
1023
1024
//---------------------------------------------------------------------------
1025
1026
template<typename Integer>
1027
bool Matrix<Integer>::column_trigonalize(size_t rk, Matrix<Integer>& Right) {
1028
assert(Right.nr == nc);
1029
assert(Right.nc == nc);
1030
vector<long> piv(2,0);
1031
for(size_t j=0;j<rk;++j){
1032
piv=pivot(j);
1033
assert(piv[0]>=0); // protect against wrong rank
1034
exchange_rows (j,piv[0]);
1035
exchange_columns (j,piv[1]);
1036
Right.exchange_columns(j,piv[1]);
1037
if(!gcd_reduce_column(j, Right))
1038
return false;
1039
}
1040
return true;
1041
}
1042
1043
//---------------------------------------------------------------------------
1044
1045
template<typename Integer>
1046
Integer Matrix<Integer>::compute_vol(bool& success){
1047
1048
assert(nr<=nc);
1049
1050
Integer det=1;
1051
for(size_t i=0;i<nr;++i){
1052
det*=elem[i][i];
1053
if(!check_range(det)){
1054
success=false;
1055
return 0;
1056
}
1057
}
1058
1059
det=Iabs(det);
1060
success=true;
1061
return det;
1062
}
1063
1064
//---------------------------------------------------------------------------
1065
1066
template<typename Integer>
1067
size_t Matrix<Integer>::row_echelon_inner_elem(bool& success){
1068
1069
size_t pc=0;
1070
long piv=0, rk=0;
1071
success=true;
1072
1073
if(nr==0)
1074
return 0;
1075
1076
for (rk = 0; rk < (long) nr; rk++){
1077
for(;pc<nc;pc++){
1078
piv=pivot_column(rk,pc);
1079
if(piv>=0)
1080
break;
1081
}
1082
if(pc==nc)
1083
break;
1084
do{
1085
exchange_rows (rk,piv);
1086
if(!reduce_row(rk,pc)){
1087
success=false;
1088
return rk;
1089
}
1090
piv=pivot_column(rk,pc);
1091
}while (piv>rk);
1092
}
1093
1094
return rk;
1095
}
1096
1097
//---------------------------------------------------------------------------
1098
1099
/*
1100
template<typename Integer>
1101
size_t Matrix<Integer>::row_echelon_inner_bareiss(bool& success, Integer& det){
1102
// no overflow checks since this is supposed to be only used with GMP
1103
1104
success=true;
1105
if(nr==0)
1106
return 0;
1107
assert(using_GMP<Integer>());
1108
1109
size_t pc=0;
1110
long piv=0, rk=0;
1111
vector<bool> last_time_mult(nr,false),this_time_mult(nr,false);
1112
Integer last_div=1,this_div=1;
1113
size_t this_time_exp=0,last_time_exp=0;
1114
Integer det_factor=1;
1115
1116
for (rk = 0; rk < (long) nr; rk++){
1117
1118
for(;pc<nc;pc++){
1119
piv=pivot_column(rk,pc);
1120
if(piv>=0)
1121
break;
1122
}
1123
if(pc==nc)
1124
break;
1125
1126
if(!last_time_mult[piv]){
1127
for(size_t k=rk;k<nr;++k)
1128
if(elem[k][pc]!=0 && last_time_mult[k]){
1129
piv=k;
1130
break;
1131
}
1132
}
1133
1134
exchange_rows (rk,piv);
1135
v_bool_entry_swap(last_time_mult,rk,piv);
1136
1137
if(!last_time_mult[rk])
1138
for(size_t i=0;i<nr;++i)
1139
last_time_mult[i]=false;
1140
1141
Integer a=elem[rk][pc];
1142
this_div=Iabs(a);
1143
this_time_exp=0;
1144
1145
for(size_t i=rk+1;i<nr;++i){
1146
if(elem[i][pc]==0){
1147
this_time_mult[i]=false;
1148
continue;
1149
}
1150
1151
this_time_exp++;
1152
this_time_mult[i]=true;
1153
bool divide=last_time_mult[i] && (last_div!=1);
1154
if(divide)
1155
last_time_exp--;
1156
Integer b=elem[i][pc];
1157
elem[i][pc]=0;
1158
if(a==1){
1159
for(size_t j=pc+1;j<nc;++j){
1160
elem[i][j]=elem[i][j]-b*elem[rk][j];
1161
if(divide){
1162
elem[i][j]/=last_div;
1163
}
1164
}
1165
}
1166
else{
1167
if(a==-1){
1168
for(size_t j=pc+1;j<nc;++j){
1169
elem[i][j]=-elem[i][j]-b*elem[rk][j];
1170
if(divide){
1171
elem[i][j]/=last_div;
1172
}
1173
}
1174
}
1175
else{
1176
for(size_t j=pc+1;j<nc;++j){
1177
elem[i][j]=a*elem[i][j]-b*elem[rk][j];
1178
if(divide){
1179
elem[i][j]/=last_div;
1180
}
1181
}
1182
}
1183
}
1184
}
1185
1186
for(size_t i=0;i<last_time_exp;++i)
1187
det_factor*=last_div;
1188
last_time_mult=this_time_mult;
1189
last_div=this_div;
1190
last_time_exp=this_time_exp;
1191
}
1192
1193
det=0;
1194
if (nr <= nc && rk == (long) nr) { // must allow nonsquare matrices
1195
det=1;
1196
for(size_t i=0;i<nr;++i)
1197
det*=elem[i][i];
1198
det=Iabs<Integer>(det/det_factor);
1199
}
1200
1201
return rk;
1202
}
1203
*/
1204
1205
//---------------------------------------------------------------------------
1206
1207
template<typename Integer>
1208
size_t Matrix<Integer>::row_echelon_reduce(bool& success){
1209
1210
size_t rk=row_echelon_inner_elem(success);
1211
if(success)
1212
success=reduce_rows_upwards();
1213
return rk;
1214
}
1215
1216
//---------------------------------------------------------------------------
1217
1218
template<typename Integer>
1219
Integer Matrix<Integer>::full_rank_index(bool& success){
1220
1221
size_t rk=row_echelon_inner_elem(success);
1222
Integer index=1;
1223
if(success){
1224
for(size_t i=0;i<rk;++i){
1225
index*=elem[i][i];
1226
if(!check_range(index)){
1227
success=false;
1228
index=0;
1229
return index;
1230
}
1231
}
1232
}
1233
assert(rk==nc); // must have full rank
1234
index=Iabs(index);
1235
return index;
1236
}
1237
//---------------------------------------------------------------------------
1238
1239
template<typename Integer>
1240
Matrix<Integer> Matrix<Integer>::row_column_trigonalize(size_t& rk, bool& success) {
1241
1242
Matrix<Integer> Right(nc);
1243
rk=row_echelon_reduce(success);
1244
if(success)
1245
success=column_trigonalize(rk,Right);
1246
return Right;
1247
}
1248
1249
//---------------------------------------------------------------------------
1250
1251
template<typename Integer>
1252
size_t Matrix<Integer>::row_echelon(bool& success, bool do_compute_vol, Integer& det){
1253
1254
/* if(using_GMP<Integer>()){
1255
return row_echelon_inner_bareiss(success,det);;
1256
}
1257
else{ */
1258
size_t rk=row_echelon_inner_elem(success);
1259
if(do_compute_vol)
1260
det=compute_vol(success);
1261
return rk;
1262
// }
1263
}
1264
1265
//---------------------------------------------------------------------------
1266
1267
template<typename Integer>
1268
size_t Matrix<Integer>::row_echelon(bool& success){
1269
1270
Integer dummy;
1271
return row_echelon(success,false,dummy);
1272
}
1273
1274
//---------------------------------------------------------------------------
1275
1276
template<typename Integer>
1277
size_t Matrix<Integer>::row_echelon(bool& success, Integer& det){
1278
1279
return row_echelon(success,true,det);
1280
}
1281
1282
1283
1284
//---------------------------------------------------------------------------
1285
1286
template<typename Integer>
1287
size_t Matrix<Integer>::rank_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key){
1288
1289
assert(nc>=mother.nc);
1290
if(nr<key.size()){
1291
elem.resize(key.size(),vector<Integer>(nc,0));
1292
nr=key.size();
1293
}
1294
size_t save_nr=nr;
1295
size_t save_nc=nc;
1296
nr=key.size();
1297
nc=mother.nc;
1298
1299
select_submatrix(mother,key);
1300
1301
bool success;
1302
size_t rk=row_echelon(success);
1303
1304
if(!success){
1305
Matrix<mpz_class> mpz_this(nr,nc);
1306
mpz_submatrix(mpz_this,mother,key);
1307
rk=mpz_this.row_echelon(success);
1308
}
1309
1310
nr=save_nr;
1311
nc=save_nc;
1312
return rk;
1313
}
1314
1315
//---------------------------------------------------------------------------
1316
1317
template<typename Integer>
1318
size_t Matrix<Integer>::rank_submatrix(const vector<key_t>& key) const{
1319
1320
Matrix<Integer> work(key.size(),nc);
1321
return work.rank_submatrix(*this,key);
1322
}
1323
1324
//---------------------------------------------------------------------------
1325
1326
template<typename Integer>
1327
size_t Matrix<Integer>::rank() const{
1328
vector<key_t> key(nr);
1329
for(size_t i=0;i<nr;++i)
1330
key[i]=i;
1331
return rank_submatrix(key);
1332
}
1333
1334
//---------------------------------------------------------------------------
1335
1336
template<typename Integer>
1337
Integer Matrix<Integer>::vol_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key){
1338
1339
assert(nc>=mother.nc);
1340
if(nr<key.size()){
1341
elem.resize(key.size(),vector<Integer>(nc,0));
1342
nr=key.size();
1343
}
1344
size_t save_nr=nr;
1345
size_t save_nc=nc;
1346
nr=key.size();
1347
nc=mother.nc;
1348
1349
select_submatrix(mother,key);
1350
1351
bool success;
1352
Integer det;
1353
row_echelon(success,det);
1354
1355
if(!success){
1356
Matrix<mpz_class> mpz_this(nr,nc);
1357
mpz_submatrix(mpz_this,mother,key);
1358
mpz_class mpz_det;
1359
mpz_this.row_echelon(success,mpz_det);
1360
convert(det, mpz_det);
1361
}
1362
1363
nr=save_nr;
1364
nc=save_nc;
1365
return det;
1366
}
1367
//---------------------------------------------------------------------------
1368
1369
template<typename Integer>
1370
Integer Matrix<Integer>::vol_submatrix(const vector<key_t>& key) const{
1371
1372
Matrix<Integer> work(key.size(),nc);
1373
return work.vol_submatrix(*this,key);
1374
}
1375
1376
//---------------------------------------------------------------------------
1377
1378
template<typename Integer>
1379
Integer Matrix<Integer>::vol() const{
1380
vector<key_t> key(nr);
1381
for(size_t i=0;i<nr;++i)
1382
key[i]=i;
1383
return vol_submatrix(key);
1384
}
1385
1386
//---------------------------------------------------------------------------
1387
1388
template<typename Integer>
1389
vector<key_t> Matrix<Integer>::max_rank_submatrix_lex_inner(bool& success) const{
1390
1391
success=true;
1392
size_t max_rank=min(nr,nc);
1393
Matrix<Integer> Test(max_rank,nc);
1394
Test.nr=0;
1395
vector<key_t> col;
1396
col.reserve(max_rank);
1397
vector<key_t> key;
1398
key.reserve(max_rank);
1399
size_t rk=0;
1400
1401
vector<vector<bool> > col_done(max_rank,vector<bool>(nc,false));
1402
1403
vector<Integer> Test_vec(nc);
1404
1405
for(size_t i=0;i<nr;++i){
1406
Test_vec=elem[i];
1407
for(size_t k=0;k<rk;++k){
1408
if(Test_vec[col[k]]==0)
1409
continue;
1410
Integer a=Test[k][col[k]];
1411
Integer b=Test_vec[col[k]];
1412
for(size_t j=0;j<nc;++j)
1413
if(!col_done[k][j]){
1414
Test_vec[j]=a*Test_vec[j]-b*Test[k][j];
1415
if (!check_range(Test_vec[j]) ) {
1416
success=false;
1417
return key;
1418
}
1419
}
1420
}
1421
1422
size_t j=0;
1423
for(;j<nc;++j)
1424
if(Test_vec[j]!=0)
1425
break;
1426
if(j==nc) // Test_vec=0
1427
continue;
1428
1429
col.push_back(j);
1430
key.push_back(i);
1431
1432
if(rk>0){
1433
col_done[rk]=col_done[rk-1];
1434
col_done[rk][col[rk-1]]=true;
1435
}
1436
1437
Test.nr++;
1438
rk++;
1439
v_make_prime(Test_vec);
1440
Test[rk-1]=Test_vec;
1441
1442
if(rk==max_rank)
1443
break;
1444
}
1445
return key;
1446
}
1447
1448
//---------------------------------------------------------------------------
1449
1450
template<typename Integer>
1451
vector<key_t> Matrix<Integer>::max_rank_submatrix_lex() const{
1452
bool success;
1453
vector<key_t> key=max_rank_submatrix_lex_inner(success);
1454
if(!success){
1455
Matrix<mpz_class> mpz_this(nr,nc);
1456
mat_to_mpz(*this,mpz_this);
1457
key=mpz_this.max_rank_submatrix_lex_inner(success);
1458
}
1459
return key;
1460
}
1461
1462
//---------------------------------------------------------------------------
1463
1464
template<typename Integer>
1465
bool Matrix<Integer>::solve_destructive_inner(bool ZZinvertible,Integer& denom) {
1466
1467
assert(nc>=nr);
1468
size_t dim=nr;
1469
bool success;
1470
1471
size_t rk;
1472
1473
if(ZZinvertible){
1474
rk=row_echelon_inner_elem(success);
1475
if(!success)
1476
return false;
1477
assert(rk==nr);
1478
denom=compute_vol(success);
1479
}
1480
else{
1481
rk=row_echelon(success,denom);
1482
if(!success)
1483
return false;
1484
}
1485
1486
if (denom==0) {
1487
if(using_GMP<Integer>()){
1488
errorOutput() << "Cannot solve system (denom=0)!" << endl;
1489
throw ArithmeticException();
1490
}
1491
else
1492
return false;
1493
}
1494
1495
Integer S;
1496
size_t i;
1497
long j;
1498
size_t k;
1499
for (i = nr; i < nc; i++) {
1500
for (j = dim-1; j >= 0; j--) {
1501
S=denom*elem[j][i];
1502
for (k = j+1; k < dim; k++) {
1503
S-=elem[j][k]*elem[k][i];
1504
}
1505
if(!check_range(S))
1506
return false;
1507
elem[j][i]=S/elem[j][j];
1508
}
1509
}
1510
return true;
1511
}
1512
1513
//---------------------------------------------------------------------------
1514
1515
template<typename Integer>
1516
void Matrix<Integer>::customize_solution(size_t dim, Integer& denom, size_t red_col,
1517
size_t sign_col, bool make_sol_prime) {
1518
1519
assert(!(make_sol_prime && (sign_col>0 || red_col>0)));
1520
1521
for(size_t j=0;j<red_col;++j){ // reduce first red_col columns of solution mod denom
1522
for(size_t k=0;k<dim;++k){
1523
elem[k][dim+j]%=denom;
1524
if(elem[k][dim+j]<0)
1525
elem[k][dim+j]+=Iabs(denom);
1526
}
1527
}
1528
1529
for(size_t j=0;j<sign_col;++j) // replace entries in the next sign_col columns by their signs
1530
for(size_t k=0;k<dim;++k){
1531
if(elem[k][dim+red_col+j]>0){
1532
elem[k][dim+red_col+j]=1;
1533
continue;
1534
}
1535
if(elem[k][dim+red_col+j]<0){
1536
elem[k][dim+red_col+j]=-1;
1537
continue;
1538
}
1539
}
1540
1541
if(make_sol_prime) // make columns of solution coprime if wanted
1542
make_cols_prime(dim,nc-1);
1543
}
1544
1545
//---------------------------------------------------------------------------
1546
1547
template<typename Integer>
1548
void Matrix<Integer>::solve_system_submatrix_outer(const Matrix<Integer>& mother, const vector<key_t>& key, const vector<vector<Integer>* >& RS,
1549
Integer& denom, bool ZZ_invertible, bool transpose, size_t red_col, size_t sign_col,
1550
bool compute_denom, bool make_sol_prime) {
1551
1552
size_t dim=mother.nc;
1553
assert(key.size()==dim);
1554
assert(nr==dim);
1555
assert(dim+RS.size()<=nc);
1556
size_t save_nc=nc;
1557
nc=dim+RS.size();
1558
1559
if(transpose)
1560
select_submatrix_trans(mother,key);
1561
else
1562
select_submatrix(mother,key);
1563
1564
for(size_t i=0;i<dim;++i)
1565
for(size_t k=0;k<RS.size();++k)
1566
elem[i][k+dim]= (*RS[k])[i];
1567
1568
if(solve_destructive_inner(ZZ_invertible,denom)){
1569
customize_solution(dim, denom,red_col,sign_col,make_sol_prime);
1570
}
1571
else{
1572
#pragma omp atomic
1573
GMP_mat++;
1574
1575
Matrix<mpz_class> mpz_this(nr,nc);
1576
mpz_class mpz_denom;
1577
if(transpose)
1578
mpz_submatrix_trans(mpz_this,mother,key);
1579
else
1580
mpz_submatrix(mpz_this,mother,key);
1581
1582
for(size_t i=0;i<dim;++i)
1583
for(size_t k=0;k<RS.size();++k)
1584
convert(mpz_this[i][k+dim], (*RS[k])[i]);
1585
mpz_this.solve_destructive_inner(ZZ_invertible,mpz_denom);
1586
mpz_this.customize_solution(dim, mpz_denom,red_col,sign_col,make_sol_prime);
1587
1588
for(size_t i=0;i<dim;++i) // replace left side by 0, except diagonal if ZZ_invetible
1589
for(size_t j=0;j<dim;++j){
1590
if(i!=j || !ZZ_invertible)
1591
mpz_this[i][j]=0;
1592
}
1593
1594
mat_to_Int(mpz_this,*this);
1595
if(compute_denom)
1596
convert(denom, mpz_denom);
1597
}
1598
nc=save_nc;
1599
}
1600
1601
//---------------------------------------------------------------------------
1602
1603
template<typename Integer>
1604
void Matrix<Integer>::solve_system_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key, const vector<vector<Integer>* >& RS,
1605
vector< Integer >& diagonal, Integer& denom, size_t red_col, size_t sign_col) {
1606
1607
solve_system_submatrix_outer(mother,key,RS,denom,true,false,red_col,sign_col);
1608
assert(diagonal.size()==nr);
1609
for(size_t i=0;i<nr;++i)
1610
diagonal[i]=elem[i][i];
1611
1612
}
1613
1614
1615
//---------------------------------------------------------------------------
1616
// the same without diagonal
1617
template<typename Integer>
1618
void Matrix<Integer>::solve_system_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key, const vector<vector<Integer>* >& RS,
1619
Integer& denom, size_t red_col, size_t sign_col, bool compute_denom, bool make_sol_prime) {
1620
1621
solve_system_submatrix_outer(mother,key,RS,denom,false,false,red_col,sign_col,
1622
compute_denom, make_sol_prime);
1623
}
1624
1625
//---------------------------------------------------------------------------
1626
1627
template<typename Integer>
1628
void Matrix<Integer>::solve_system_submatrix_trans(const Matrix<Integer>& mother, const vector<key_t>& key, const vector<vector<Integer>* >& RS,
1629
Integer& denom, size_t red_col, size_t sign_col) {
1630
1631
solve_system_submatrix_outer(mother,key,RS,denom,false,true,red_col,sign_col);
1632
}
1633
1634
//---------------------------------------------------------------------------
1635
1636
template<typename Integer>
1637
Matrix<Integer> Matrix<Integer>::extract_solution() const {
1638
assert(nc>=nr);
1639
Matrix<Integer> Solution(nr,nc-nr);
1640
for(size_t i=0;i<nr;++i){
1641
for(size_t j=0;j<Solution.nc;++j)
1642
Solution[i][j]=elem[i][j+nr];
1643
}
1644
return Solution;
1645
}
1646
1647
//---------------------------------------------------------------------------
1648
1649
template<typename Integer>
1650
vector<vector<Integer>* > Matrix<Integer>::row_pointers(){
1651
1652
vector<vector<Integer>* > pointers(nr);
1653
for(size_t i=0;i<nr;++i)
1654
pointers[i]=&(elem[i]);
1655
return pointers;
1656
}
1657
1658
//---------------------------------------------------------------------------
1659
1660
template<typename Integer>
1661
vector<vector<Integer>* > Matrix<Integer>::submatrix_pointers(const vector<key_t>& key){
1662
1663
vector<vector<Integer>* > pointers(key.size());
1664
for(size_t i=0;i<key.size();++i)
1665
pointers[i]=&(elem[key[i]]);
1666
return pointers;
1667
}
1668
//---------------------------------------------------------------------------
1669
1670
template<typename Integer>
1671
Matrix<Integer> Matrix<Integer>::solve(const Matrix<Integer>& Right_side,vector<Integer>& diagonal,Integer& denom) const {
1672
1673
Matrix<Integer> M(nr,nc+Right_side.nc);
1674
vector<key_t> key=identity_key(nr);
1675
Matrix<Integer> RS_trans=Right_side.transpose();
1676
vector<vector<Integer>* > RS=RS_trans.row_pointers();
1677
M.solve_system_submatrix(*this,key,RS,diagonal,denom,0,0);
1678
return M.extract_solution();
1679
}
1680
1681
//---------------------------------------------------------------------------
1682
1683
template<typename Integer>
1684
Matrix<Integer> Matrix<Integer>::solve(const Matrix<Integer>& Right_side, Integer& denom) const {
1685
1686
Matrix<Integer> M(nr,nc+Right_side.nc);
1687
vector<key_t> key=identity_key(nr);
1688
Matrix<Integer> RS_trans=Right_side.transpose();
1689
vector<vector<Integer>* > RS=RS_trans.row_pointers();
1690
M.solve_system_submatrix(*this,key,RS,denom,0,0);
1691
return M.extract_solution();
1692
}
1693
1694
//---------------------------------------------------------------------------
1695
1696
template<typename Integer>
1697
Matrix<Integer> Matrix<Integer>::invert(Integer& denom) const{
1698
assert(nr == nc);
1699
Matrix<Integer> Right_side(nr);
1700
1701
return solve(Right_side,denom);
1702
}
1703
1704
//---------------------------------------------------------------------------
1705
1706
template<typename Integer>
1707
Matrix<Integer> Matrix<Integer>::bundle_matrices(const Matrix<Integer>& Right_side) const {
1708
1709
assert(nr == nc);
1710
assert(nc == Right_side.nr);
1711
Matrix<Integer> M(nr,nc+Right_side.nc);
1712
for(size_t i=0;i<nr;++i){
1713
for(size_t j=0;j<nc;++j)
1714
M[i][j]=elem[i][j];
1715
for(size_t j=nc;j<M.nc;++j)
1716
M[i][j]=Right_side[i][j-nc];
1717
}
1718
return M;
1719
}
1720
//---------------------------------------------------------------------------
1721
1722
template<typename Integer>
1723
Matrix<Integer> Matrix<Integer>::invert_unprotected(Integer& denom, bool& success) const{
1724
assert(nr == nc);
1725
Matrix<Integer> Right_side(nr);
1726
Matrix<Integer> M=bundle_matrices(Right_side);
1727
success=M.solve_destructive_inner(false,denom);
1728
return M.extract_solution();;
1729
}
1730
1731
//---------------------------------------------------------------------------
1732
1733
template<typename Integer>
1734
void Matrix<Integer>::invert_submatrix(const vector<key_t>& key, Integer& denom, Matrix<Integer>& Inv, bool compute_denom, bool make_sol_prime) const{
1735
assert(key.size() == nc);
1736
Matrix<Integer> unit_mat(key.size());
1737
Matrix<Integer> M(key.size(),2*key.size());
1738
vector<vector<Integer>* > RS_pointers=unit_mat.row_pointers();
1739
M.solve_system_submatrix(*this,key,RS_pointers,denom,0,0, compute_denom, make_sol_prime);
1740
Inv=M.extract_solution();;
1741
}
1742
1743
//---------------------------------------------------------------------------
1744
1745
template<typename Integer>
1746
void Matrix<Integer>::simplex_data(const vector<key_t>& key, Matrix<Integer>& Supp, Integer& vol, bool compute_vol) const{
1747
assert(key.size() == nc);
1748
invert_submatrix(key,vol,Supp,compute_vol,true);
1749
Supp=Supp.transpose();
1750
// Supp.make_prime(); now done internally
1751
}
1752
//---------------------------------------------------------------------------
1753
1754
template<typename Integer>
1755
vector<Integer> Matrix<Integer>::solve_rectangular(const vector<Integer>& v, Integer& denom) const {
1756
if (nc == 0 || nr == 0) { //return zero-vector as solution
1757
return vector<Integer>(nc,0);
1758
}
1759
size_t i;
1760
vector<key_t> rows=max_rank_submatrix_lex();
1761
Matrix<Integer> Left_Side=submatrix(rows);
1762
assert(nc == Left_Side.nr); //otherwise input hadn't full rank //TODO
1763
Matrix<Integer> Right_Side(v.size(),1);
1764
Right_Side.write_column(0,v);
1765
Right_Side = Right_Side.submatrix(rows);
1766
Matrix<Integer> Solution=Left_Side.solve(Right_Side, denom);
1767
vector<Integer> Linear_Form(nc);
1768
for (i = 0; i <nc; i++) {
1769
Linear_Form[i] = Solution[i][0]; // the solution vector is called Linear_Form
1770
}
1771
vector<Integer> test = MxV(Linear_Form); // we have solved the system by taking a square submatrix
1772
// now we must test whether the solution satisfies the full system
1773
for (i = 0; i <nr; i++) {
1774
if (test[i] != denom * v[i]){
1775
return vector<Integer>();
1776
}
1777
}
1778
Integer total_gcd = libnormaliz::gcd(denom,v_gcd(Linear_Form)); // extract the gcd of denom and solution
1779
denom/=total_gcd;
1780
v_scalar_division(Linear_Form,total_gcd);
1781
return Linear_Form;
1782
}
1783
//---------------------------------------------------------------------------
1784
1785
template<typename Integer>
1786
vector<Integer> Matrix<Integer>::solve_ZZ(const vector<Integer>& v) const {
1787
1788
Integer denom;
1789
vector<Integer> result=solve_rectangular(v,denom);
1790
if(denom!=1)
1791
result.clear();
1792
return result;
1793
}
1794
//---------------------------------------------------------------------------
1795
1796
template<typename Integer>
1797
vector<Integer> Matrix<Integer>::find_linear_form() const {
1798
1799
Integer denom;
1800
vector<Integer> result=solve_rectangular(vector<Integer>(nr,1),denom);
1801
v_make_prime(result);
1802
return result;
1803
}
1804
1805
//---------------------------------------------------------------------------
1806
1807
template<typename Integer>
1808
vector<Integer> Matrix<Integer>::find_linear_form_low_dim () const{
1809
size_t rank=(*this).rank();
1810
if (rank == 0) { //return zero-vector as linear form
1811
return vector<Integer>(nc,0);
1812
}
1813
if (rank == nc) { // basis change not necessary
1814
return (*this).find_linear_form();
1815
}
1816
1817
Sublattice_Representation<Integer> Basis_Change(*this,true);
1818
vector<Integer> Linear_Form=Basis_Change.to_sublattice(*this).find_linear_form();
1819
if(Linear_Form.size()!=0)
1820
Linear_Form=Basis_Change.from_sublattice_dual(Linear_Form);
1821
1822
return Linear_Form;
1823
}
1824
1825
//---------------------------------------------------------------------------
1826
1827
template<typename Integer>
1828
size_t Matrix<Integer>::row_echelon_reduce(){
1829
1830
size_t rk;
1831
Matrix<Integer> Copy(*this);
1832
bool success;
1833
rk=row_echelon_reduce(success);
1834
if(success){
1835
Shrink_nr_rows(rk);
1836
return rk;
1837
}
1838
Matrix<mpz_class> mpz_Copy(nr,nc);
1839
mat_to_mpz(Copy,mpz_Copy);
1840
rk=mpz_Copy.row_echelon_reduce(success);
1841
mat_to_Int(mpz_Copy,*this);
1842
Shrink_nr_rows(rk);
1843
return rk;
1844
}
1845
//---------------------------------------------------------------------------
1846
1847
template<typename Integer>
1848
Integer Matrix<Integer>::full_rank_index() const{
1849
1850
Matrix<Integer> Copy(*this);
1851
Integer index;
1852
bool success;
1853
index=Copy.full_rank_index(success);
1854
if(success)
1855
return index;
1856
Matrix<mpz_class> mpz_Copy(nr,nc);
1857
mat_to_mpz(*this,mpz_Copy);
1858
mpz_class mpz_index=mpz_Copy.full_rank_index(success);
1859
convert(index, mpz_index);
1860
return index;
1861
}
1862
1863
//---------------------------------------------------------------------------
1864
1865
template<typename Integer>
1866
size_t Matrix<Integer>::row_echelon(){
1867
1868
Matrix<Integer> Copy(*this);
1869
bool success;
1870
size_t rk;
1871
rk=row_echelon(success);
1872
if(success){
1873
Shrink_nr_rows(rk);
1874
return rk;
1875
}
1876
Matrix<mpz_class> mpz_Copy(nr,nc);
1877
mat_to_mpz(Copy,mpz_Copy);
1878
rk=mpz_Copy.row_echelon_reduce(success); // reduce to make entries small
1879
mat_to_Int(mpz_Copy,*this);
1880
Shrink_nr_rows(rk);
1881
return rk;
1882
}
1883
1884
//-----------------------------------------------------------
1885
//
1886
// variants for floating point
1887
//
1888
//-----------------------------------------------------------
1889
1890
template<>
1891
long Matrix<nmz_float>::pivot_column(size_t row,size_t col){
1892
1893
size_t i;
1894
long j=-1;
1895
nmz_float help=0;
1896
1897
for (i = row; i < nr; i++) {
1898
if (Iabs(elem[i][col])>nmz_epsilon) {
1899
if ((help==0)||(Iabs(elem[i][col])>help)) {
1900
help=Iabs(elem[i][col]);
1901
j=i;
1902
} }
1903
}
1904
1905
return j;
1906
}
1907
1908
template<>
1909
size_t Matrix<nmz_float>::row_echelon_inner_elem(bool& success){
1910
1911
size_t pc=0;
1912
long piv=0, rk=0;
1913
1914
if(nr==0)
1915
return 0;
1916
1917
for (rk = 0; rk < (long) nr; rk++){
1918
for(;pc<nc;pc++){
1919
piv=pivot_column(rk,pc);
1920
if(piv>=0)
1921
break;
1922
}
1923
if(pc==nc)
1924
break;
1925
1926
exchange_rows (rk,piv);
1927
reduce_row(rk,pc);
1928
}
1929
1930
success=true;
1931
return rk;
1932
}
1933
1934
1935
template<>
1936
size_t Matrix<nmz_float>::row_echelon(){
1937
1938
size_t rk;
1939
bool dummy;
1940
rk=row_echelon_inner_elem(dummy);
1941
Shrink_nr_rows(rk);
1942
return rk;
1943
}
1944
//---------------------------------------------------------------------------
1945
1946
template<typename Integer>
1947
Matrix<Integer> Matrix<Integer>::kernel () const{
1948
// computes a ZZ-basis of the solutions of (*this)x=0
1949
// the basis is formed by the rOWS of the returned matrix
1950
1951
size_t dim=nc;
1952
if(nr==0)
1953
return(Matrix<Integer>(dim));
1954
1955
Matrix<Integer> Copy(*this);
1956
size_t rank;
1957
bool success;
1958
Matrix<Integer> Transf=Copy.row_column_trigonalize(rank,success);
1959
if(!success){
1960
Matrix<mpz_class> mpz_Copy(nr,nc);
1961
mat_to_mpz(*this,mpz_Copy);
1962
Matrix<mpz_class> mpz_Transf=mpz_Copy.row_column_trigonalize(rank,success);
1963
mat_to_Int(mpz_Transf,Transf);
1964
}
1965
1966
Matrix<Integer> ker_basis(dim-rank,dim);
1967
Matrix<Integer> Help =Transf.transpose();
1968
for (size_t i = rank; i < dim; i++)
1969
ker_basis[i-rank]=Help[i];
1970
ker_basis.row_echelon_reduce();
1971
return(ker_basis);
1972
}
1973
1974
//---------------------------------------------------------------------------
1975
// Converts "this" into (column almost) Hermite normal form, returns column transformation matrix
1976
template<typename Integer>
1977
Matrix<Integer> Matrix<Integer>::AlmostHermite(size_t& rk){
1978
1979
Matrix<Integer> Copy=*this;
1980
Matrix<Integer> Transf;
1981
bool success;
1982
Transf=row_column_trigonalize(rk,success);
1983
if(success)
1984
return Transf;
1985
1986
Matrix<mpz_class> mpz_this(nr,nc);
1987
mat_to_mpz(Copy,mpz_this);
1988
Matrix<mpz_class> mpz_Transf=mpz_this.row_column_trigonalize(rk,success);
1989
mat_to_Int(mpz_this,*this);
1990
mat_to_Int(mpz_Transf,Transf);
1991
return Transf;
1992
}
1993
1994
//---------------------------------------------------------------------------
1995
1996
template<typename Integer>
1997
bool Matrix<Integer>::SmithNormalForm_inner(size_t& rk, Matrix<Integer>& Right){
1998
1999
bool success=true;
2000
2001
// first we diagonalize
2002
2003
while(true){
2004
rk=row_echelon_reduce(success);
2005
if(!success)
2006
return false;
2007
if(rk==0)
2008
break;
2009
2010
if(is_diagonal())
2011
break;
2012
2013
success=column_trigonalize(rk,Right);
2014
if(!success)
2015
return false;
2016
2017
if(is_diagonal())
2018
break;
2019
}
2020
2021
// now we change the diagonal so that we have successive divisibilty
2022
2023
if(rk<=1)
2024
return true;
2025
2026
while(true){
2027
size_t i=0;
2028
for(;i<rk-1;++i)
2029
if(elem[i+1][i+1]%elem[i][i]!=0)
2030
break;
2031
if(i==rk-1)
2032
break;
2033
2034
Integer u,v,w,z, d=ext_gcd(elem[i][i],elem[i+1][i+1],u,v);
2035
elem[i][i+1]=elem[i+1][i+1];
2036
w=-elem[i+1][i+1]/d;
2037
z=elem[i][i]/d;
2038
// Now we multiply the submatrix formed by columns "corner" and "j"
2039
// and rows corner,...,nr from the right by the 2x2 matrix
2040
// | u w |
2041
// | v z |
2042
if(!linear_comb_columns(i,i+1,u,w,v,z))
2043
return false;
2044
if(!Right.linear_comb_columns(i,i+1,u,w,v,z))
2045
return false;
2046
elem[i+1][i]=0;
2047
}
2048
2049
return true;
2050
}
2051
2052
// Converts "this" into Smith normal form, returns column transformation matrix
2053
template<typename Integer>
2054
Matrix<Integer> Matrix<Integer>::SmithNormalForm(size_t& rk){
2055
2056
size_t dim=nc;
2057
Matrix<Integer> Transf(dim);
2058
if(dim==0)
2059
return Transf;
2060
2061
Matrix<Integer> Copy=*this;
2062
bool success=SmithNormalForm_inner(rk,Transf);
2063
if(success)
2064
return Transf;
2065
2066
Matrix<mpz_class> mpz_this(nr,dim);
2067
mat_to_mpz(Copy,mpz_this);
2068
Matrix<mpz_class> mpz_Transf(dim);
2069
mpz_this.SmithNormalForm_inner(rk,mpz_Transf);
2070
mat_to_Int(mpz_this,*this);
2071
mat_to_Int(mpz_Transf,Transf);
2072
return Transf;
2073
}
2074
2075
//---------------------------------------------------------------------------
2076
// Classless conversion routines
2077
//---------------------------------------------------------------------------
2078
2079
template<typename ToType, typename FromType>
2080
void convert(Matrix<ToType>& to_mat, const Matrix<FromType>& from_mat){
2081
size_t nrows = from_mat.nr_of_rows();
2082
size_t ncols = from_mat.nr_of_columns();
2083
to_mat.resize(nrows, ncols);
2084
for(size_t i=0; i<nrows; ++i)
2085
for(size_t j=0; j<ncols; ++j)
2086
convert(to_mat[i][j], from_mat[i][j]);
2087
}
2088
2089
//---------------------------------------------------------------------------
2090
2091
2092
template<typename Integer>
2093
void mat_to_mpz(const Matrix<Integer>& mat, Matrix<mpz_class>& mpz_mat){
2094
//convert(mpz_mat, mat);
2095
// we allow the matrices to have different sizes
2096
size_t nrows = min(mat.nr_of_rows(), mpz_mat.nr_of_rows());
2097
size_t ncols = min(mat.nr_of_columns(),mpz_mat.nr_of_columns());
2098
for(size_t i=0; i<nrows; ++i)
2099
for(size_t j=0; j<ncols; ++j)
2100
convert(mpz_mat[i][j], mat[i][j]);
2101
#pragma omp atomic
2102
GMP_mat++;
2103
}
2104
2105
//---------------------------------------------------------------------------
2106
2107
template<typename Integer>
2108
void mat_to_Int(const Matrix<mpz_class>& mpz_mat, Matrix<Integer>& mat){
2109
//convert(mat, mpz_mat);
2110
// we allow the matrices to have different sizes
2111
size_t nrows = min(mpz_mat.nr_of_rows(), mat.nr_of_rows());
2112
size_t ncols = min(mpz_mat.nr_of_columns(),mat.nr_of_columns());
2113
for(size_t i=0; i<nrows; ++i)
2114
for(size_t j=0; j<ncols; ++j)
2115
convert(mat[i][j], mpz_mat[i][j]);
2116
}
2117
2118
//---------------------------------------------------------------------------
2119
2120
template<typename Integer>
2121
void mpz_submatrix(Matrix<mpz_class>& sub, const Matrix<Integer>& mother, const vector<key_t>& selection){
2122
2123
assert(sub.nr_of_columns()>=mother.nr_of_columns());
2124
assert(sub.nr_of_rows()>=selection.size());
2125
for(size_t i=0;i<selection.size();++i)
2126
for(size_t j=0;j<mother.nr_of_columns();++j)
2127
convert(sub[i][j], mother[selection[i]][j]);
2128
}
2129
2130
//---------------------------------------------------------------------------
2131
2132
template<typename Integer>
2133
void mpz_submatrix_trans(Matrix<mpz_class>& sub, const Matrix<Integer>& mother, const vector<key_t>& selection){
2134
2135
assert(sub.nr_of_columns()>=selection.size());
2136
assert(sub.nr_of_rows()>=mother.nr_of_columns());
2137
for(size_t i=0;i<selection.size();++i)
2138
for(size_t j=0;j<mother.nr_of_columns();++j)
2139
convert(sub[j][i], mother[selection[i]][j]);
2140
}
2141
2142
//---------------------------------------------------------------------------
2143
2144
/* sorts rows of a matrix by a degree function and returns the permuation
2145
* does not change matrix (yet)
2146
*/
2147
template<typename Integer>
2148
vector<key_t> Matrix<Integer>::perm_sort_by_degree(const vector<key_t>& key, const vector<Integer>& grading, bool computed) const{
2149
2150
list<vector<Integer>> rowList;
2151
vector<Integer> v;
2152
2153
v.resize(nc+2);
2154
unsigned long i,j;
2155
2156
for (i=0;i<key.size();i++){
2157
if (computed){
2158
v[0]=v_scalar_product((*this).elem[key[i]],grading);
2159
} else{
2160
v[0]=0;
2161
for (j=0;j<nc;j++) v[0]+=Iabs((*this).elem[key[i]][j]);
2162
}
2163
for (j=0;j<nc;j++){
2164
v[j+1] = (*this).elem[key[i]][j];
2165
}
2166
v[nc+1] = key[i]; // position of row
2167
rowList.push_back(v);
2168
}
2169
rowList.sort();
2170
vector<key_t> perm;
2171
perm.resize(key.size());
2172
i=0;
2173
for (typename list< vector<Integer> >::const_iterator it = rowList.begin();it!=rowList.end();++it){
2174
perm[i]=convertTo<long>((*it)[nc+1]);
2175
i++;
2176
}
2177
return perm;
2178
}
2179
2180
//---------------------------------------------------------------------------
2181
2182
2183
template<typename Integer>
2184
bool weight_lex(const order_helper<Integer>& a, const order_helper<Integer>& b){
2185
2186
if(a.weight < b.weight)
2187
return true;
2188
if(a.weight==b.weight)
2189
if(*(a.v)< *(b.v))
2190
return true;
2191
return false;
2192
}
2193
2194
//---------------------------------------------------------------------------
2195
2196
template<typename Integer>
2197
void Matrix<Integer>::order_rows_by_perm(const vector<key_t>& perm){
2198
order_by_perm(elem,perm);
2199
}
2200
2201
template<typename Integer>
2202
Matrix<Integer>& Matrix<Integer>::sort_by_weights(const Matrix<Integer>& Weights, vector<bool> absolute){
2203
if(nr<=1)
2204
return *this;
2205
vector<key_t> perm=perm_by_weights(Weights,absolute);
2206
order_by_perm(elem,perm);
2207
return *this;
2208
}
2209
2210
template<typename Integer>
2211
Matrix<Integer>& Matrix<Integer>::sort_lex(){
2212
if(nr<=1)
2213
return *this;
2214
vector<key_t> perm=perm_by_weights(Matrix<Integer>(0,nc),vector<bool>(0));
2215
order_by_perm(elem,perm);
2216
return *this;
2217
}
2218
2219
template<typename Integer>
2220
vector<key_t> Matrix<Integer>::perm_by_weights(const Matrix<Integer>& Weights, vector<bool> absolute){
2221
// the smallest entry is the row with index perm[0], then perm[1] etc.
2222
2223
assert(Weights.nc==nc);
2224
assert(absolute.size()==Weights.nr);
2225
2226
list<order_helper<Integer> > order;
2227
order_helper<Integer> entry;
2228
entry.weight.resize(Weights.nr);
2229
2230
for(key_t i=0;i<nr; ++i){
2231
for(size_t j=0;j<Weights.nr;++j){
2232
if(absolute[j])
2233
entry.weight[j]=v_scalar_product(Weights[j],v_abs_value(elem[i]));
2234
else
2235
entry.weight[j]=v_scalar_product(Weights[j],elem[i]);
2236
}
2237
entry.index=i;
2238
entry.v=&(elem[i]);
2239
order.push_back(entry);
2240
}
2241
order.sort(weight_lex<Integer>);
2242
vector<key_t> perm(nr);
2243
typename list<order_helper<Integer> >::const_iterator ord=order.begin();
2244
for(key_t i=0;i<nr;++i, ++ord)
2245
perm[i]=ord->index;
2246
2247
return perm;
2248
}
2249
2250
//---------------------------------------------------
2251
2252
template<typename Integer>
2253
Matrix<Integer> Matrix<Integer>::solve_congruences(bool& zero_modulus) const{
2254
2255
2256
zero_modulus=false;
2257
size_t i,j;
2258
size_t nr_cong=nr, dim=nc-1;
2259
if(nr_cong==0)
2260
return Matrix<Integer>(dim); // give back unit matrix
2261
2262
//add slack variables to convert congruences into equaitions
2263
Matrix<Integer> Cong_Slack(nr_cong, dim+nr_cong);
2264
for (i = 0; i < nr_cong; i++) {
2265
for (j = 0; j < dim; j++) {
2266
Cong_Slack[i][j]=elem[i][j];
2267
}
2268
Cong_Slack[i][dim+i]=elem[i][dim];
2269
if(elem[i][dim]==0){
2270
zero_modulus=true;
2271
return Matrix<Integer>(0,dim);
2272
}
2273
}
2274
2275
//compute kernel
2276
2277
Matrix<Integer> Help=Cong_Slack.kernel(); // gives the solutions to the the system with slack variables
2278
Matrix<Integer> Ker_Basis(dim,dim); // must now project to first dim coordinates to get rid of them
2279
for(size_t i=0;i<dim;++i)
2280
for(size_t j=0;j<dim;++j)
2281
Ker_Basis[i][j]=Help[i][j];
2282
return Ker_Basis;
2283
2284
}
2285
2286
//---------------------------------------------------
2287
2288
template<typename Integer>
2289
void Matrix<Integer>::saturate(){
2290
2291
*this=kernel().kernel();
2292
}
2293
2294
//---------------------------------------------------
2295
2296
template<typename Integer>
2297
vector<key_t> Matrix<Integer>::max_and_min(const vector<Integer>& L, const vector<Integer>& norm) const{
2298
2299
vector<key_t> result(2,0);
2300
if(nr==0)
2301
return result;
2302
key_t maxind=0,minind=0;
2303
Integer maxval=v_scalar_product(L,elem[0]);
2304
Integer maxnorm=1,minnorm=1;
2305
if(norm.size()>0){
2306
maxnorm=v_scalar_product(norm,elem[0]);
2307
minnorm=maxnorm;
2308
}
2309
Integer minval=maxval;
2310
for(key_t i=0;i<nr;++i){
2311
Integer val=v_scalar_product(L,elem[i]);
2312
if(norm.size()==0){
2313
if(val>maxval){
2314
maxind=i;
2315
maxval=val;
2316
}
2317
if(val<minval){
2318
minind=i;
2319
minval=val;
2320
}
2321
}
2322
else{
2323
Integer nm=v_scalar_product(norm,elem[i]);
2324
if(maxnorm*val>nm*maxval){
2325
maxind=i;
2326
maxval=val;
2327
}
2328
if(minnorm*val<nm*minval){
2329
minind=i;
2330
minval=val;
2331
}
2332
}
2333
}
2334
result[0]=maxind;
2335
result[1]=minind;
2336
return result;
2337
}
2338
2339
template<typename Integer>
2340
size_t Matrix<Integer>::extreme_points_first(const vector<Integer> norm){
2341
2342
if(nr==0)
2343
return 1;
2344
2345
vector<long long> norm_copy;
2346
2347
size_t nr_extr=0;
2348
Matrix<long long> HelpMat(nr,nc);
2349
try{
2350
convert(HelpMat,*this);
2351
convert(norm_copy,norm);
2352
}
2353
catch(ArithmeticException){
2354
return nr_extr;
2355
}
2356
2357
HelpMat.sort_lex();
2358
2359
vector<bool> marked(nr,false);
2360
size_t no_success=0;
2361
// size_t nr_attempt=0;
2362
while(true){
2363
2364
INTERRUPT_COMPUTATION_BY_EXCEPTION
2365
2366
// nr_attempt++; cout << nr_attempt << endl;
2367
vector<long long> L=v_random<long long>(nc,10);
2368
vector<key_t> max_min_ind;
2369
max_min_ind=HelpMat.max_and_min(L,norm_copy);
2370
2371
if(marked[max_min_ind[0]] && marked[max_min_ind[1]])
2372
no_success++;
2373
else
2374
no_success=0;
2375
if(no_success > 1000)
2376
break;
2377
marked[max_min_ind[0]]=true;
2378
marked[max_min_ind[1]]=true;
2379
}
2380
Matrix<long long> Extr(nr_extr,nc); // the recognized extreme rays
2381
Matrix<long long> NonExtr(nr_extr,nc); // the other generators
2382
size_t j=0;
2383
vector<key_t> perm(nr);
2384
for(size_t i=0;i<nr;++i) {
2385
if(marked[i]){
2386
perm[j]=i;;
2387
j++;
2388
}
2389
}
2390
nr_extr=j;
2391
for(size_t i=0;i<nr;++i) {
2392
if(!marked[i]){
2393
perm[j]=i;;
2394
j++;
2395
}
2396
}
2397
order_rows_by_perm(perm);
2398
// cout << nr_extr << "extreme points found" << endl;
2399
return nr_extr;
2400
// exit(0);
2401
}
2402
2403
template<typename Integer>
2404
vector<Integer> Matrix<Integer>::find_inner_point(){
2405
vector<key_t> simplex=max_rank_submatrix_lex();
2406
vector<Integer> point(nc);
2407
for(size_t i=0;i<simplex.size();++i)
2408
point=v_add(point,elem[simplex[i]]);
2409
return point;
2410
}
2411
2412
template<typename Integer>
2413
void Matrix<Integer>::Shrink_nr_rows(size_t new_nr_rows){
2414
2415
if(new_nr_rows>=nr)
2416
return;
2417
nr=new_nr_rows;
2418
elem.resize(nr);
2419
}
2420
2421
template<typename Integer>
2422
Matrix<Integer> readMatrix(const string project){
2423
// reads one matrix from file with name project
2424
// format: nr of rows, nr of colimns, entries
2425
// all separated by white space
2426
2427
string name_in=project;
2428
const char* file_in=name_in.c_str();
2429
ifstream in;
2430
in.open(file_in,ifstream::in);
2431
if (in.is_open()==false){
2432
cerr << "Cannot find input file" << endl;
2433
exit(1);
2434
}
2435
2436
int nrows,ncols;
2437
in >> nrows;
2438
in >> ncols;
2439
2440
if(nrows==0 || ncols==0){
2441
cerr << "Matrix empty" << endl;
2442
exit(1);
2443
}
2444
2445
2446
int i,j,entry;
2447
Matrix<Integer> result(nrows,ncols);
2448
2449
for(i=0;i<nrows;++i)
2450
for(j=0;j<ncols;++j){
2451
in >> entry;
2452
result[i][j]=entry;
2453
}
2454
return result;
2455
}
2456
2457
//---------------------------------------------------------------------------
2458
// version with full number of points
2459
// and search for optimal point
2460
2461
template<typename Integer>
2462
vector<Integer> Matrix<Integer>::optimal_subdivision_point() const{
2463
2464
return optimal_subdivision_point_inner();
2465
}
2466
2467
// In mpz_class we first try machine integer
2468
template<>
2469
vector<mpz_class> Matrix<mpz_class>::optimal_subdivision_point() const{
2470
2471
try {
2472
Matrix<MachineInteger> GensMI;
2473
convert(GensMI,*this);
2474
vector<MachineInteger> PMI=GensMI.optimal_subdivision_point_inner();
2475
vector<mpz_class> P;
2476
convert(P,PMI);
2477
return P;
2478
} catch(const ArithmeticException& e) {
2479
return optimal_subdivision_point_inner();
2480
}
2481
}
2482
2483
// version with a single point, only top of the search polytope
2484
// After 2 attempts without improvement, g raised to opt_value-1
2485
template<typename Integer>
2486
vector<Integer> Matrix<Integer>::optimal_subdivision_point_inner() const{
2487
// returns empty vector if simplex cannot be subdivided with smaller detsum
2488
2489
// cout << "==================" << endl;
2490
2491
assert(nr>0);
2492
assert(nr==nc);
2493
2494
vector<Integer> opt_point;
2495
2496
vector<Integer> N = find_linear_form();
2497
assert(N.size()==nr);
2498
Integer G=v_scalar_product(N,elem[0]);
2499
if(G<=1)
2500
return opt_point;
2501
Matrix<Integer> Supp;
2502
Integer V;
2503
vector<key_t> dummy(nr);
2504
for(size_t i=0;i<nr;++i)
2505
dummy[i]=i;
2506
simplex_data(dummy, Supp,V,true);
2507
Integer MinusOne=-1;
2508
vector<Integer> MinusN(N);
2509
v_scalar_multiplication(MinusN,MinusOne);
2510
Supp.append(MinusN);
2511
Supp.resize_columns(nr+1);
2512
Supp.exchange_columns(0,nc); // grading to the front!
2513
2514
Integer opt_value=G;
2515
Integer empty_value=0;
2516
Integer g=G-1;
2517
2518
Integer den=2;
2519
2520
vector<Integer> Zero(nr+1); // the excluded vector
2521
Zero[0]=1;
2522
2523
// Incidence matrix for projectand lift
2524
vector<boost::dynamic_bitset<> > Ind(nr+1);
2525
for(size_t i=0;i<nr+1;++i){
2526
Ind[i].resize(nc+1);
2527
for(size_t j=0;j<nc+1;++j)
2528
Ind[i][j]=true;
2529
Ind[i][i]=false;
2530
}
2531
2532
// cout << "==============================" << endl;
2533
2534
size_t nothing_found=0;
2535
while(true){
2536
vector<Integer> SubDiv;
2537
// cout << "Opt " << opt_value << " test " << g << " empty " << empty_value << " nothing " << nothing_found << endl;
2538
Supp[nr][0]=g; // the degree at which we cut the simplex1;
2539
ProjectAndLift<Integer,Integer> PL(Supp,Ind,nr+1);
2540
PL.set_excluded_point(Zero);
2541
PL.set_verbose(false);
2542
PL.compute(false); // only a single point
2543
PL.put_single_point_into(SubDiv);
2544
if(SubDiv.size()==0){ // no point found
2545
nothing_found++;
2546
if(g==opt_value-1)
2547
return opt_point; // optimal point found (or nothing found)
2548
empty_value=g;
2549
if(nothing_found<1) // can't be true if "1" is not raised to a higher value
2550
g=empty_value+1+(den-1)*(opt_value-empty_value-2)/den;
2551
else
2552
g=opt_value-1;
2553
den*=2; // not used in the present setting (see above)
2554
}
2555
else{ // point found
2556
nothing_found=0;
2557
den=2; // back to start value
2558
opt_point=SubDiv;
2559
std::swap(opt_point[0],opt_point[nc]);
2560
opt_point.resize(nc);
2561
if(opt_value==empty_value+1)
2562
return opt_point;
2563
opt_value=v_scalar_product(opt_point,N);
2564
g=empty_value+1+(opt_value-empty_value-2)/2;
2565
}
2566
}
2567
}
2568
2569
#ifndef NMZ_MIC_OFFLOAD //offload with long is not supported
2570
template Matrix<long> readMatrix(const string project);
2571
#endif // NMZ_MIC_OFFLOAD
2572
template Matrix<long long> readMatrix(const string project);
2573
template Matrix<mpz_class> readMatrix(const string project);
2574
2575
} // namespace
2576
2577