GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
/*1* Normaliz2* Copyright (C) 2007-2014 Winfried Bruns, Bogdan Ichim, Christof Soeger3* This program is free software: you can redistribute it and/or modify4* it under the terms of the GNU General Public License as published by5* the Free Software Foundation, either version 3 of the License, or6* (at your option) any later version.7*8* This program is distributed in the hope that it will be useful,9* but WITHOUT ANY WARRANTY; without even the implied warranty of10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11* GNU General Public License for more details.12*13* You should have received a copy of the GNU General Public License14* along with this program. If not, see <http://www.gnu.org/licenses/>.15*16* As an exception, when this program is distributed through (i) the App Store17* by Apple Inc.; (ii) the Mac App Store by Apple Inc.; or (iii) Google Play18* by Google Inc., then that store may impose any digital rights management,19* device limits and/or redistribution restrictions that are required by its20* terms of service.21*/2223//---------------------------------------------------------------------------2425#include <fstream>26#include <set>27#include <algorithm>28#include <math.h>29#include <iomanip>3031#include "libnormaliz/matrix.h"32#include "libnormaliz/cone.h"33#include "libnormaliz/vector_operations.h"34#include "libnormaliz/normaliz_exception.h"35#include "libnormaliz/sublattice_representation.h"3637//---------------------------------------------------------------------------3839namespace libnormaliz {40using namespace std;4142//---------------------------------------------------------------------------43//Public44//---------------------------------------------------------------------------4546template<typename Integer>47Matrix<Integer>::Matrix(){48nr=0;49nc=0;50}5152//---------------------------------------------------------------------------5354template<typename Integer>55Matrix<Integer>::Matrix(size_t dim){56nr=dim;57nc=dim;58elem = vector< vector<Integer> >(dim, vector<Integer>(dim));59for (size_t i = 0; i < dim; i++) {60elem[i][i]=1;61}62}6364//---------------------------------------------------------------------------6566template<typename Integer>67Matrix<Integer>::Matrix(size_t row, size_t col){68nr=row;69nc=col;70elem = vector< vector<Integer> >(row, vector<Integer>(col));71}7273//---------------------------------------------------------------------------7475template<typename Integer>76Matrix<Integer>::Matrix(size_t row, size_t col, Integer value){77nr=row;78nc=col;79elem = vector< vector<Integer> > (row, vector<Integer>(col,value));80}8182//---------------------------------------------------------------------------8384template<typename Integer>85Matrix<Integer>::Matrix(const vector< vector<Integer> >& new_elem){86nr=new_elem.size();87if (nr>0) {88nc=new_elem[0].size();89elem=new_elem;90//check if all rows have the same length91for (size_t i=1; i<nr; i++) {92if (elem[i].size() != nc) {93throw BadInputException("Inconsistent lengths of rows in matrix!");94}95}96} else {97nc=0;98}99}100101//---------------------------------------------------------------------------102103template<typename Integer>104Matrix<Integer>::Matrix(const list< vector<Integer> >& new_elem){105nr = new_elem.size();106elem = vector< vector<Integer> > (nr);107nc = 0;108size_t i=0;109typename list< vector<Integer> >::const_iterator it=new_elem.begin();110for(; it!=new_elem.end(); ++it, ++i) {111if(i == 0) {112nc = (*it).size();113} else {114if ((*it).size() != nc) {115throw BadInputException("Inconsistent lengths of rows in matrix!");116}117}118elem[i]=(*it);119}120}121122//---------------------------------------------------------------------------123/*124template<typename Integer>125void Matrix<Integer>::write(istream& in){126size_t i,j;127for(i=0; i<nr; i++){128for(j=0; j<nc; j++) {129in >> elem[i][j];130}131}132}133*/134//---------------------------------------------------------------------------135136template<typename Integer>137void Matrix<Integer>::write_column(size_t col, const vector<Integer>& data){138assert(col >= 0);139assert(col < nc);140assert(nr == data.size());141142for (size_t i = 0; i < nr; i++) {143elem[i][col]=data[i];144}145}146147//---------------------------------------------------------------------------148149template<typename Integer>150void Matrix<Integer>::print(const string& name,const string& suffix) const{151string file_name = name+"."+suffix;152const char* file = file_name.c_str();153ofstream out(file);154print(out);155out.close();156}157158//---------------------------------------------------------------------------159160template<typename Integer>161void Matrix<Integer>::print_append(const string& name,const string& suffix) const{162string file_name = name+"."+suffix;163const char* file = file_name.c_str();164ofstream out(file,ios_base::app);165print(out);166out.close();167}168169//---------------------------------------------------------------------------170171template<typename Integer>172void Matrix<Integer>::print(ostream& out, bool with_format) const{173size_t i,j;174if(with_format)175out<<nr<<endl<<nc<<endl;176for (i = 0; i < nr; i++) {177for (j = 0; j < nc; j++) {178out<<elem[i][j]<<" ";179}180out<<endl;181}182}183184//---------------------------------------------------------------------------185186template<typename Integer>187void Matrix<Integer>::pretty_print(ostream& out, bool with_row_nr) const{188if(nr>1000000 && !with_row_nr){189print(out,false);190return;191}192size_t i,j;193vector<size_t> max_length = maximal_decimal_length_columnwise();194size_t max_index_length = decimal_length(nr);195for (i = 0; i < nr; i++) {196if (with_row_nr) {197out << std::setw(max_index_length+1) << i<< ": ";198}199for (j = 0; j < nc; j++) {200out << std::setw(max_length[j]+1) << elem[i][j];201}202out<<endl;203}204}205206//---------------------------------------------------------------------------207208template<typename Integer>209size_t Matrix<Integer>::nr_of_rows () const{210return nr;211}212213//---------------------------------------------------------------------------214215template<typename Integer>216size_t Matrix<Integer>::nr_of_columns () const{217return nc;218}219220//---------------------------------------------------------------------------221222template<typename Integer>223void Matrix<Integer>::set_nr_of_columns(size_t c){224nc=c;225}226227//---------------------------------------------------------------------------228229template<typename Integer>230void Matrix<Integer>::random (int mod) {231size_t i,j;232int k;233for (i = 0; i < nr; i++) {234for (j = 0; j < nc; j++) {235k = rand();236elem[i][j]=k % mod;237}238}239}240//---------------------------------------------------------------------------241242template<typename Integer>243void Matrix<Integer>::set_zero() {244size_t i,j;245for (i = 0; i < nr; i++) {246for (j = 0; j < nc; j++) {247elem[i][j] = 0;248}249}250}251252//---------------------------------------------------------------------------253254template<typename Integer>255void Matrix<Integer>::select_submatrix(const Matrix<Integer>& mother, const vector<key_t>& rows){256257assert(nr>=rows.size());258assert(nc>=mother.nc);259260size_t size=rows.size(), j;261for (size_t i=0; i < size; i++) {262j=rows[i];263for(size_t k=0;k<mother.nc;++k)264elem[i][k]=mother[j][k];265}266}267268//---------------------------------------------------------------------------269270template<typename Integer>271void Matrix<Integer>::select_submatrix_trans(const Matrix<Integer>& mother, const vector<key_t>& rows){272273assert(nc>=rows.size());274assert(nr>=mother.nc);275276size_t size=rows.size(), j;277for (size_t i=0; i < size; i++) {278j=rows[i];279for(size_t k=0;k<mother.nc;++k)280elem[k][i]=mother[j][k];281}282}283284//---------------------------------------------------------------------------285286template<typename Integer>287Matrix<Integer> Matrix<Integer>::submatrix(const vector<key_t>& rows) const{288size_t size=rows.size(), j;289Matrix<Integer> M(size, nc);290for (size_t i=0; i < size; i++) {291j=rows[i];292assert(j >= 0);293assert(j < nr);294M.elem[i]=elem[j];295}296return M;297}298299//---------------------------------------------------------------------------300301template<typename Integer>302Matrix<Integer> Matrix<Integer>::submatrix(const vector<int>& rows) const{303size_t size=rows.size(), j;304Matrix<Integer> M(size, nc);305for (size_t i=0; i < size; i++) {306j=rows[i];307assert(j >= 0);308assert(j < nr);309M.elem[i]=elem[j];310}311return M;312}313314//---------------------------------------------------------------------------315316template<typename Integer>317Matrix<Integer> Matrix<Integer>::submatrix(const vector<bool>& rows) const{318assert(rows.size() == nr);319size_t size=0;320for (size_t i = 0; i <rows.size(); i++) {321if (rows[i]) {322size++;323}324}325Matrix<Integer> M(size, nc);326size_t j = 0;327for (size_t i = 0; i < nr; i++) {328if (rows[i]) {329M.elem[j++] = elem[i];330}331}332return M;333}334335//---------------------------------------------------------------------------336337template<typename Integer>338Matrix<Integer>& Matrix<Integer>::remove_zero_rows() {339size_t from = 0, to = 0; // maintain to <= from340while (from < nr && v_is_zero(elem[from])) from++; //skip zero rows341while (from < nr) { // go over matrix342// now from is a non-zero row343if (to != from) elem[to].swap(elem[from]);344++to; ++from;345while (from < nr && v_is_zero(elem[from])) from++; //skip zero rows346}347nr = to;348elem.resize(nr);349return *this;350}351352//---------------------------------------------------------------------------353354template<typename Integer>355void Matrix<Integer>::swap(Matrix<Integer>& x) {356size_t tmp = nr; nr = x.nr; x.nr = tmp;357tmp = nc; nc = x.nc; x.nc = tmp;358elem.swap(x.elem);359}360361//---------------------------------------------------------------------------362363template<typename Integer>364void Matrix<Integer>::resize(size_t nr_rows, size_t nr_cols) {365nc = nr_cols; //for adding new rows with the right length366resize(nr_rows);367resize_columns(nr_cols);368}369370template<typename Integer>371void Matrix<Integer>::resize(size_t nr_rows) {372if (nr_rows > elem.size()) {373elem.resize(nr_rows, vector<Integer>(nc));374}375nr = nr_rows;376}377378template<typename Integer>379void Matrix<Integer>::resize_columns(size_t nr_cols) {380for (size_t i=0; i<nr; i++) {381elem[i].resize(nr_cols);382}383nc = nr_cols;384}385386//---------------------------------------------------------------------------387388template<typename Integer>389vector<Integer> Matrix<Integer>::diagonal() const{390assert(nr == nc);391vector<Integer> diag(nr);392for(size_t i=0; i<nr;i++){393diag[i]=elem[i][i];394}395return diag;396}397398//---------------------------------------------------------------------------399400template<typename Integer>401size_t Matrix<Integer>::maximal_decimal_length() const{402size_t i,maxim=0;403vector<size_t> maxim_col;404maxim_col=maximal_decimal_length_columnwise();405for (i = 0; i <nr; i++)406maxim=max(maxim,maxim_col[i]);407return maxim;408}409410//---------------------------------------------------------------------------411412template<typename Integer>413vector<size_t> Matrix<Integer>::maximal_decimal_length_columnwise() const{414size_t i,j=0;415vector<size_t> maxim(nc,0);416vector<Integer> pos_max(nc,0), neg_max(nc,0);417for (i = 0; i <nr; i++) {418for (j = 0; j <nc; j++) {419// maxim[j]=max(maxim[j],decimal_length(elem[i][j]));420if(elem[i][j]<0){421if(elem[i][j]<neg_max[j])422neg_max[j]=elem[i][j];423continue;424}425if(elem[i][j]>pos_max[j])426pos_max[j]=elem[i][j];427}428}429for(size_t j=0;j<nc;++j)430maxim[j]=max(decimal_length(neg_max[j]),decimal_length(pos_max[j]));431return maxim;432}433434//---------------------------------------------------------------------------435436template<typename Integer>437void Matrix<Integer>::append(const Matrix<Integer>& M) {438assert (nc == M.nc);439elem.reserve(nr+M.nr);440/* for (size_t i=0; i<M.nr; i++) {441elem.push_back(M.elem[i]);442}*/443elem.insert(elem.end(),M.elem.begin(),M.elem.end());444nr += M.nr;445}446447//---------------------------------------------------------------------------448449template<typename Integer>450void Matrix<Integer>::append(const vector<vector<Integer> >& M) {451if(M.size()==0)452return;453assert (nc == M[0].size());454elem.reserve(nr+M.size());455for (size_t i=0; i<M.size(); i++) {456elem.push_back(M[i]);457}458nr += M.size();459}460461//---------------------------------------------------------------------------462463template<typename Integer>464void Matrix<Integer>::append(const vector<Integer>& V) {465assert (nc == V.size());466elem.push_back(V);467nr++;468}469470//---------------------------------------------------------------------------471472template<typename Integer>473void Matrix<Integer>::append_column(const vector<Integer>& v) {474assert (nr == v.size());475for (size_t i=0; i<nr; i++) {476elem[i].resize(nc+1);477elem[i][nc] = v[i];478}479nc++;480}481482//---------------------------------------------------------------------------483484template<typename Integer>485void Matrix<Integer>::remove_row(const vector<Integer>& row) {486size_t tmp_nr = nr;487for (size_t i = 1; i <= tmp_nr; ++i) {488if (elem[tmp_nr-i] == row) {489elem.erase(elem.begin()+(tmp_nr-i));490nr--;491}492}493}494495//---------------------------------------------------------------------------496497template<typename Integer>498void Matrix<Integer>::remove_row(const size_t index) {499assert(index<nr);500nr--;501elem.erase(elem.begin()+(index));502}503504//---------------------------------------------------------------------------505506template<typename Integer>507vector<size_t> Matrix<Integer>::remove_duplicate_and_zero_rows() {508bool remove_some = false;509vector<bool> key(nr, true);510vector<size_t> original_row;511512set<vector<Integer> > SortedRows;513SortedRows.insert( vector<Integer>(nc,0) );514typename set<vector<Integer> >::iterator found;515for (size_t i = 0; i<nr; i++) {516found = SortedRows.find(elem[i]);517if (found != SortedRows.end()) {518key[i] = false;519remove_some = true;520}521else{522SortedRows.insert(found,elem[i]);523original_row.push_back(i);524}525}526527if (remove_some) {528*this = submatrix(key);529}530return original_row;531}532533//---------------------------------------------------------------------------534535template<typename Integer>536void Matrix<Integer>::remove_duplicate(const Matrix<Integer>& M) {537bool remove_some = false;538vector<bool> key(nr, true);539540// TODO more efficient! sorted rows541for (size_t i = 0; i<nr; i++) {542for (size_t j=0;j<M.nr_of_rows();j++){543if (elem[i]==M[j]){544remove_some=true;545key[i]=false;546break;547}548}549}550551if (remove_some) {552*this = submatrix(key);553}554}555556//---------------------------------------------------------------------------557558template<typename Integer>559Matrix<Integer> Matrix<Integer>::add(const Matrix<Integer>& A) const{560assert (nr == A.nr);561assert (nc == A.nc);562563Matrix<Integer> B(nr,nc);564size_t i,j;565for(i=0; i<nr;i++){566for(j=0; j<nc; j++){567B.elem[i][j]=elem[i][j]+A.elem[i][j];568}569}570return B;571}572573//---------------------------------------------------------------------------574575template<typename Integer>576Matrix<Integer> Matrix<Integer>::multiplication(const Matrix<Integer>& A) const{577assert (nc == A.nr);578579Matrix<Integer> Atrans=A.transpose();580Matrix<Integer> B(nr,A.nc); //initialized with 0581size_t i,j,k;582for(i=0; i<B.nr;i++){583for(j=0; j<B.nc; j++){584for(k=0; k<nc; k++){585B[i][j]=v_scalar_product(elem[i],Atrans[j]);586}587}588}589return B;590}591592//---------------------------------------------------------------------------593594template<typename Integer>595Matrix<Integer> Matrix<Integer>::multiplication(const Matrix<Integer>& A, long m) const{596assert (nc == A.nr);597598Matrix<Integer> B(nr,A.nc,0); //initialized with 0599size_t i,j,k;600for(i=0; i<B.nr;i++){601for(j=0; j<B.nc; j++){602for(k=0; k<nc; k++){603B.elem[i][j]=(B.elem[i][j]+elem[i][k]*A.elem[k][j])%m;604if (B.elem[i][j]<0) {605B.elem[i][j]=B.elem[i][j]+m;606}607}608}609}610return B;611}612613//---------------------------------------------------------------------------614615template<typename Integer>616bool Matrix<Integer>::equal(const Matrix<Integer>& A) const{617if ((nr!=A.nr)||(nc!=A.nc)){ return false; }618size_t i,j;619for (i=0; i < nr; i++) {620for (j = 0; j < nc; j++) {621if (elem[i][j]!=A.elem[i][j]) {622return false;623}624}625}626return true;627}628629//---------------------------------------------------------------------------630631template<typename Integer>632bool Matrix<Integer>::equal(const Matrix<Integer>& A, long m) const{633if ((nr!=A.nr)||(nc!=A.nc)){ return false; }634size_t i,j;635for (i=0; i < nr; i++) {636for (j = 0; j < nc; j++) {637if (((elem[i][j]-A.elem[i][j]) % m)!=0) {638return false;639}640}641}642return true;643}644645//---------------------------------------------------------------------------646647template<typename Integer>648Matrix<Integer> Matrix<Integer>::transpose()const{649Matrix<Integer> B(nc,nr);650size_t i,j;651for(i=0; i<nr;i++){652for(j=0; j<nc; j++){653B.elem[j][i]=elem[i][j];654}655}656return B;657}658659//---------------------------------------------------------------------------660661template<typename Integer>662void Matrix<Integer>::scalar_multiplication(const Integer& scalar){663size_t i,j;664for(i=0; i<nr;i++){665for(j=0; j<nc; j++){666elem[i][j] *= scalar;667}668}669}670671//---------------------------------------------------------------------------672673template<typename Integer>674void Matrix<Integer>::scalar_division(const Integer& scalar){675size_t i,j;676assert(scalar != 0);677for(i=0; i<nr;i++){678for(j=0; j<nc; j++){679assert (elem[i][j]%scalar == 0);680elem[i][j] /= scalar;681}682}683}684685//---------------------------------------------------------------------------686687template<typename Integer>688void Matrix<Integer>::reduction_modulo(const Integer& modulo){689size_t i,j;690for(i=0; i<nr;i++){691for(j=0; j<nc; j++){692elem[i][j] %= modulo;693if (elem[i][j] < 0) {694elem[i][j] += modulo;695}696}697}698}699700//---------------------------------------------------------------------------701702template<typename Integer>703Integer Matrix<Integer>::matrix_gcd() const{704Integer g=0,h;705for (size_t i = 0; i <nr; i++) {706h = v_gcd(elem[i]);707g = libnormaliz::gcd<Integer>(g, h);708if (g==1) return g;709}710return g;711}712713//---------------------------------------------------------------------------714715template<typename Integer>716vector<Integer> Matrix<Integer>::make_prime() {717vector<Integer> g(nr);718for (size_t i = 0; i <nr; i++) {719g[i] = v_make_prime(elem[i]);720}721return g;722}723724//---------------------------------------------------------------------------725726template<typename Integer>727void Matrix<Integer>::make_cols_prime(size_t from_col, size_t to_col) {728729for (size_t k = from_col; k <= to_col; k++) {730Integer g=0;731for (size_t i = 0; i < nr; i++){732g = libnormaliz::gcd(g,elem[i][k]);733if (g==1) {734break;735}736}737for (size_t i = 0; i < nr; i++)738elem[i][k]/=g;739}740}741742//---------------------------------------------------------------------------743744template<typename Integer>745Matrix<Integer> Matrix<Integer>::multiply_rows(const vector<Integer>& m) const{ //row i is multiplied by m[i]746Matrix M = Matrix(nr,nc);747size_t i,j;748for (i = 0; i<nr; i++) {749for (j = 0; j<nc; j++) {750M.elem[i][j] = elem[i][j]*m[i];751}752}753return M;754}755756//---------------------------------------------------------------------------757758template<typename Integer>759void Matrix<Integer>::MxV(vector<Integer>& result, const vector<Integer>& v) const{760assert (nc == v.size());761result.resize(nr);762for(size_t i=0; i<nr;i++){763result[i]=v_scalar_product(elem[i],v);764}765}766767//---------------------------------------------------------------------------768769template<typename Integer>770vector<Integer> Matrix<Integer>::MxV(const vector<Integer>& v) const{771vector<Integer> w(nr);772MxV(w, v);773return w;774}775776//---------------------------------------------------------------------------777778template<typename Integer>779vector<Integer> Matrix<Integer>::VxM(const vector<Integer>& v) const{780assert (nr == v.size());781vector<Integer> w(nc,0);782size_t i,j;783for (i=0; i<nc; i++){784for (j=0; j<nr; j++){785w[i] += v[j]*elem[j][i];786}787if(!check_range(w[i]))788break;789}790if(i==nc)791return w;792Matrix<mpz_class> mpz_this(nr,nc);793mat_to_mpz(*this,mpz_this);794vector<mpz_class> mpz_v(nr);795convert(mpz_v, v);796vector<mpz_class> mpz_w=mpz_this.VxM(mpz_v);797convert(w,mpz_w);798return w;799}800801//---------------------------------------------------------------------------802803template<typename Integer>804vector<Integer> Matrix<Integer>::VxM_div(const vector<Integer>& v, const Integer& divisor, bool& success) const{805assert (nr == v.size());806vector<Integer> w(nc,0);807success=true;808size_t i,j;809for (i=0; i<nc; i++){810for (j=0; j<nr; j++){811w[i] += v[j]*elem[j][i];812}813if(!check_range(w[i])){814success=false;815break;816}817}818819if(success)820v_scalar_division(w,divisor);821822return w;823}824825//---------------------------------------------------------------------------826827template<typename Integer>828bool Matrix<Integer>::is_diagonal() const{829830for(size_t i=0;i<nr;++i)831for(size_t j=0;j<nc;++j)832if(i!=j && elem[i][j]!=0)833return false;834return true;835}836837//---------------------------------------------------------------------------838839template<typename Integer>840vector<long> Matrix<Integer>::pivot(size_t corner){841assert(corner < nc);842assert(corner < nr);843size_t i,j;844Integer help=0;845vector<long> v(2,-1);846847for (i = corner; i < nr; i++) {848for (j = corner; j < nc; j++) {849if (elem[i][j]!=0) {850if ((help==0)||(Iabs(elem[i][j])<help)) {851help=Iabs(elem[i][j]);852v[0]=i;853v[1]=j;854if (help == 1) return v;855}856}857}858}859860return v;861}862863//---------------------------------------------------------------------------864865template<typename Integer>866long Matrix<Integer>::pivot_column(size_t row,size_t col){867assert(col < nc);868assert(row < nr);869size_t i;870long j=-1;871Integer help=0;872873for (i = row; i < nr; i++) {874if (elem[i][col]!=0) {875if ((help==0)||(Iabs(elem[i][col])<help)) {876help=Iabs(elem[i][col]);877j=i;878if (help == 1) return j;879}880}881}882883return j;884}885886//---------------------------------------------------------------------------887888template<typename Integer>889long Matrix<Integer>::pivot_column(size_t col){890return pivot_column(col,col);891}892893//---------------------------------------------------------------------------894895template<typename Integer>896void Matrix<Integer>::exchange_rows(const size_t& row1, const size_t& row2){897if (row1 == row2) return;898assert(row1 < nr);899assert(row2 < nr);900elem[row1].swap(elem[row2]);901}902903//---------------------------------------------------------------------------904905template<typename Integer>906void Matrix<Integer>::exchange_columns(const size_t& col1, const size_t& col2){907if (col1 == col2) return;908assert(col1 < nc);909assert(col2 < nc);910for(size_t i=0; i<nr;i++){911std::swap(elem[i][col1], elem[i][col2]);912}913}914915//---------------------------------------------------------------------------916917template<typename Integer>918bool Matrix<Integer>::reduce_row (size_t row, size_t col) {919assert(col < nc);920assert(row < nr);921size_t i,j;922Integer help;923for (i =row+1; i < nr; i++) {924if (elem[i][col]!=0) {925help=elem[i][col] / elem[row][col];926for (j = col; j < nc; j++) {927elem[i][j] -= help*elem[row][j];928if (!check_range(elem[i][j]) ) {929return false;930}931}932// v_el_trans<Integer>(elem[row],elem[i],-help,col);933}934}935return true;936}937938//---------------------------------------------------------------------------939940template<typename Integer>941bool Matrix<Integer>::reduce_row (size_t corner) {942return reduce_row(corner,corner);943}944945//---------------------------------------------------------------------------946947template<typename Integer>948bool Matrix<Integer>::reduce_rows_upwards () {949// assumes that "this" is in row echelon form950// and reduces eevery column in which the rank jumps951// by its lowest element952953if(nr==0)954return true;955956for(size_t row=0;row<nr;++row){957size_t col;958for(col=0;col<nc;++col)959if(elem[row][col]!=0)960break;961if(col==nc)962continue;963if(elem[row][col]<0)964v_scalar_multiplication<Integer>(elem[row],-1);965966for(long i=row-1;i>=0;--i){967Integer quot, rem;968969minimal_remainder(elem[i][col],elem[row][col],quot,rem);970elem[i][col]=rem;971for(size_t j=col+1;j<nc;++j){972elem[i][j]-=quot* elem[row][j];973if ( !check_range(elem[i][j]) ) {974return false;975}976}977}978}979return true;980}981982//---------------------------------------------------------------------------983984template<typename Integer>985bool Matrix<Integer>::linear_comb_columns(const size_t& col,const size_t& j,986const Integer& u,const Integer& w,const Integer& v,const Integer& z){987988for(size_t i=0;i<nr;++i){989Integer rescue=elem[i][col];990elem[i][col]=u*elem[i][col]+v*elem[i][j];991elem[i][j]=w*rescue+z*elem[i][j];992if ( (!check_range(elem[i][col]) || !check_range(elem[i][j]) )) {993return false;994}995}996return true;997}998999//---------------------------------------------------------------------------10001001template<typename Integer>1002bool Matrix<Integer>::gcd_reduce_column (size_t corner, Matrix<Integer>& Right){1003assert(corner < nc);1004assert(corner < nr);1005Integer d,u,w,z,v;1006for(size_t j=corner+1;j<nc;++j){1007d=ext_gcd(elem[corner][corner],elem[corner][j],u,v);1008w=-elem[corner][j]/d;1009z=elem[corner][corner]/d;1010// Now we multiply the submatrix formed by columns "corner" and "j"1011// and rows corner,...,nr from the right by the 2x2 matrix1012// | u w |1013// | v z |1014if(!linear_comb_columns(corner,j,u,w,v,z))1015return false;1016if(!Right.linear_comb_columns(corner,j,u,w,v,z))1017return false;1018}1019return true;1020}102110221023//---------------------------------------------------------------------------10241025template<typename Integer>1026bool Matrix<Integer>::column_trigonalize(size_t rk, Matrix<Integer>& Right) {1027assert(Right.nr == nc);1028assert(Right.nc == nc);1029vector<long> piv(2,0);1030for(size_t j=0;j<rk;++j){1031piv=pivot(j);1032assert(piv[0]>=0); // protect against wrong rank1033exchange_rows (j,piv[0]);1034exchange_columns (j,piv[1]);1035Right.exchange_columns(j,piv[1]);1036if(!gcd_reduce_column(j, Right))1037return false;1038}1039return true;1040}10411042//---------------------------------------------------------------------------10431044template<typename Integer>1045Integer Matrix<Integer>::compute_vol(bool& success){10461047assert(nr<=nc);10481049Integer det=1;1050for(size_t i=0;i<nr;++i){1051det*=elem[i][i];1052if(!check_range(det)){1053success=false;1054return 0;1055}1056}10571058det=Iabs(det);1059success=true;1060return det;1061}10621063//---------------------------------------------------------------------------10641065template<typename Integer>1066size_t Matrix<Integer>::row_echelon_inner_elem(bool& success){10671068size_t pc=0;1069long piv=0, rk=0;1070success=true;10711072if(nr==0)1073return 0;10741075for (rk = 0; rk < (long) nr; rk++){1076for(;pc<nc;pc++){1077piv=pivot_column(rk,pc);1078if(piv>=0)1079break;1080}1081if(pc==nc)1082break;1083do{1084exchange_rows (rk,piv);1085if(!reduce_row(rk,pc)){1086success=false;1087return rk;1088}1089piv=pivot_column(rk,pc);1090}while (piv>rk);1091}10921093return rk;1094}10951096//---------------------------------------------------------------------------10971098/*1099template<typename Integer>1100size_t Matrix<Integer>::row_echelon_inner_bareiss(bool& success, Integer& det){1101// no overflow checks since this is supposed to be only used with GMP11021103success=true;1104if(nr==0)1105return 0;1106assert(using_GMP<Integer>());11071108size_t pc=0;1109long piv=0, rk=0;1110vector<bool> last_time_mult(nr,false),this_time_mult(nr,false);1111Integer last_div=1,this_div=1;1112size_t this_time_exp=0,last_time_exp=0;1113Integer det_factor=1;11141115for (rk = 0; rk < (long) nr; rk++){11161117for(;pc<nc;pc++){1118piv=pivot_column(rk,pc);1119if(piv>=0)1120break;1121}1122if(pc==nc)1123break;11241125if(!last_time_mult[piv]){1126for(size_t k=rk;k<nr;++k)1127if(elem[k][pc]!=0 && last_time_mult[k]){1128piv=k;1129break;1130}1131}11321133exchange_rows (rk,piv);1134v_bool_entry_swap(last_time_mult,rk,piv);11351136if(!last_time_mult[rk])1137for(size_t i=0;i<nr;++i)1138last_time_mult[i]=false;11391140Integer a=elem[rk][pc];1141this_div=Iabs(a);1142this_time_exp=0;11431144for(size_t i=rk+1;i<nr;++i){1145if(elem[i][pc]==0){1146this_time_mult[i]=false;1147continue;1148}11491150this_time_exp++;1151this_time_mult[i]=true;1152bool divide=last_time_mult[i] && (last_div!=1);1153if(divide)1154last_time_exp--;1155Integer b=elem[i][pc];1156elem[i][pc]=0;1157if(a==1){1158for(size_t j=pc+1;j<nc;++j){1159elem[i][j]=elem[i][j]-b*elem[rk][j];1160if(divide){1161elem[i][j]/=last_div;1162}1163}1164}1165else{1166if(a==-1){1167for(size_t j=pc+1;j<nc;++j){1168elem[i][j]=-elem[i][j]-b*elem[rk][j];1169if(divide){1170elem[i][j]/=last_div;1171}1172}1173}1174else{1175for(size_t j=pc+1;j<nc;++j){1176elem[i][j]=a*elem[i][j]-b*elem[rk][j];1177if(divide){1178elem[i][j]/=last_div;1179}1180}1181}1182}1183}11841185for(size_t i=0;i<last_time_exp;++i)1186det_factor*=last_div;1187last_time_mult=this_time_mult;1188last_div=this_div;1189last_time_exp=this_time_exp;1190}11911192det=0;1193if (nr <= nc && rk == (long) nr) { // must allow nonsquare matrices1194det=1;1195for(size_t i=0;i<nr;++i)1196det*=elem[i][i];1197det=Iabs<Integer>(det/det_factor);1198}11991200return rk;1201}1202*/12031204//---------------------------------------------------------------------------12051206template<typename Integer>1207size_t Matrix<Integer>::row_echelon_reduce(bool& success){12081209size_t rk=row_echelon_inner_elem(success);1210if(success)1211success=reduce_rows_upwards();1212return rk;1213}12141215//---------------------------------------------------------------------------12161217template<typename Integer>1218Integer Matrix<Integer>::full_rank_index(bool& success){12191220size_t rk=row_echelon_inner_elem(success);1221Integer index=1;1222if(success){1223for(size_t i=0;i<rk;++i){1224index*=elem[i][i];1225if(!check_range(index)){1226success=false;1227index=0;1228return index;1229}1230}1231}1232assert(rk==nc); // must have full rank1233index=Iabs(index);1234return index;1235}1236//---------------------------------------------------------------------------12371238template<typename Integer>1239Matrix<Integer> Matrix<Integer>::row_column_trigonalize(size_t& rk, bool& success) {12401241Matrix<Integer> Right(nc);1242rk=row_echelon_reduce(success);1243if(success)1244success=column_trigonalize(rk,Right);1245return Right;1246}12471248//---------------------------------------------------------------------------12491250template<typename Integer>1251size_t Matrix<Integer>::row_echelon(bool& success, bool do_compute_vol, Integer& det){12521253/* if(using_GMP<Integer>()){1254return row_echelon_inner_bareiss(success,det);;1255}1256else{ */1257size_t rk=row_echelon_inner_elem(success);1258if(do_compute_vol)1259det=compute_vol(success);1260return rk;1261// }1262}12631264//---------------------------------------------------------------------------12651266template<typename Integer>1267size_t Matrix<Integer>::row_echelon(bool& success){12681269Integer dummy;1270return row_echelon(success,false,dummy);1271}12721273//---------------------------------------------------------------------------12741275template<typename Integer>1276size_t Matrix<Integer>::row_echelon(bool& success, Integer& det){12771278return row_echelon(success,true,det);1279}1280128112821283//---------------------------------------------------------------------------12841285template<typename Integer>1286size_t Matrix<Integer>::rank_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key){12871288assert(nc>=mother.nc);1289if(nr<key.size()){1290elem.resize(key.size(),vector<Integer>(nc,0));1291nr=key.size();1292}1293size_t save_nr=nr;1294size_t save_nc=nc;1295nr=key.size();1296nc=mother.nc;12971298select_submatrix(mother,key);12991300bool success;1301size_t rk=row_echelon(success);13021303if(!success){1304Matrix<mpz_class> mpz_this(nr,nc);1305mpz_submatrix(mpz_this,mother,key);1306rk=mpz_this.row_echelon(success);1307}13081309nr=save_nr;1310nc=save_nc;1311return rk;1312}13131314//---------------------------------------------------------------------------13151316template<typename Integer>1317size_t Matrix<Integer>::rank_submatrix(const vector<key_t>& key) const{13181319Matrix<Integer> work(key.size(),nc);1320return work.rank_submatrix(*this,key);1321}13221323//---------------------------------------------------------------------------13241325template<typename Integer>1326size_t Matrix<Integer>::rank() const{1327vector<key_t> key(nr);1328for(size_t i=0;i<nr;++i)1329key[i]=i;1330return rank_submatrix(key);1331}13321333//---------------------------------------------------------------------------13341335template<typename Integer>1336Integer Matrix<Integer>::vol_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key){13371338assert(nc>=mother.nc);1339if(nr<key.size()){1340elem.resize(key.size(),vector<Integer>(nc,0));1341nr=key.size();1342}1343size_t save_nr=nr;1344size_t save_nc=nc;1345nr=key.size();1346nc=mother.nc;13471348select_submatrix(mother,key);13491350bool success;1351Integer det;1352row_echelon(success,det);13531354if(!success){1355Matrix<mpz_class> mpz_this(nr,nc);1356mpz_submatrix(mpz_this,mother,key);1357mpz_class mpz_det;1358mpz_this.row_echelon(success,mpz_det);1359convert(det, mpz_det);1360}13611362nr=save_nr;1363nc=save_nc;1364return det;1365}1366//---------------------------------------------------------------------------13671368template<typename Integer>1369Integer Matrix<Integer>::vol_submatrix(const vector<key_t>& key) const{13701371Matrix<Integer> work(key.size(),nc);1372return work.vol_submatrix(*this,key);1373}13741375//---------------------------------------------------------------------------13761377template<typename Integer>1378Integer Matrix<Integer>::vol() const{1379vector<key_t> key(nr);1380for(size_t i=0;i<nr;++i)1381key[i]=i;1382return vol_submatrix(key);1383}13841385//---------------------------------------------------------------------------13861387template<typename Integer>1388vector<key_t> Matrix<Integer>::max_rank_submatrix_lex_inner(bool& success) const{13891390success=true;1391size_t max_rank=min(nr,nc);1392Matrix<Integer> Test(max_rank,nc);1393Test.nr=0;1394vector<key_t> col;1395col.reserve(max_rank);1396vector<key_t> key;1397key.reserve(max_rank);1398size_t rk=0;13991400vector<vector<bool> > col_done(max_rank,vector<bool>(nc,false));14011402vector<Integer> Test_vec(nc);14031404for(size_t i=0;i<nr;++i){1405Test_vec=elem[i];1406for(size_t k=0;k<rk;++k){1407if(Test_vec[col[k]]==0)1408continue;1409Integer a=Test[k][col[k]];1410Integer b=Test_vec[col[k]];1411for(size_t j=0;j<nc;++j)1412if(!col_done[k][j]){1413Test_vec[j]=a*Test_vec[j]-b*Test[k][j];1414if (!check_range(Test_vec[j]) ) {1415success=false;1416return key;1417}1418}1419}14201421size_t j=0;1422for(;j<nc;++j)1423if(Test_vec[j]!=0)1424break;1425if(j==nc) // Test_vec=01426continue;14271428col.push_back(j);1429key.push_back(i);14301431if(rk>0){1432col_done[rk]=col_done[rk-1];1433col_done[rk][col[rk-1]]=true;1434}14351436Test.nr++;1437rk++;1438v_make_prime(Test_vec);1439Test[rk-1]=Test_vec;14401441if(rk==max_rank)1442break;1443}1444return key;1445}14461447//---------------------------------------------------------------------------14481449template<typename Integer>1450vector<key_t> Matrix<Integer>::max_rank_submatrix_lex() const{1451bool success;1452vector<key_t> key=max_rank_submatrix_lex_inner(success);1453if(!success){1454Matrix<mpz_class> mpz_this(nr,nc);1455mat_to_mpz(*this,mpz_this);1456key=mpz_this.max_rank_submatrix_lex_inner(success);1457}1458return key;1459}14601461//---------------------------------------------------------------------------14621463template<typename Integer>1464bool Matrix<Integer>::solve_destructive_inner(bool ZZinvertible,Integer& denom) {14651466assert(nc>=nr);1467size_t dim=nr;1468bool success;14691470size_t rk;14711472if(ZZinvertible){1473rk=row_echelon_inner_elem(success);1474if(!success)1475return false;1476assert(rk==nr);1477denom=compute_vol(success);1478}1479else{1480rk=row_echelon(success,denom);1481if(!success)1482return false;1483}14841485if (denom==0) {1486if(using_GMP<Integer>()){1487errorOutput() << "Cannot solve system (denom=0)!" << endl;1488throw ArithmeticException();1489}1490else1491return false;1492}14931494Integer S;1495size_t i;1496long j;1497size_t k;1498for (i = nr; i < nc; i++) {1499for (j = dim-1; j >= 0; j--) {1500S=denom*elem[j][i];1501for (k = j+1; k < dim; k++) {1502S-=elem[j][k]*elem[k][i];1503}1504if(!check_range(S))1505return false;1506elem[j][i]=S/elem[j][j];1507}1508}1509return true;1510}15111512//---------------------------------------------------------------------------15131514template<typename Integer>1515void Matrix<Integer>::customize_solution(size_t dim, Integer& denom, size_t red_col,1516size_t sign_col, bool make_sol_prime) {15171518assert(!(make_sol_prime && (sign_col>0 || red_col>0)));15191520for(size_t j=0;j<red_col;++j){ // reduce first red_col columns of solution mod denom1521for(size_t k=0;k<dim;++k){1522elem[k][dim+j]%=denom;1523if(elem[k][dim+j]<0)1524elem[k][dim+j]+=Iabs(denom);1525}1526}15271528for(size_t j=0;j<sign_col;++j) // replace entries in the next sign_col columns by their signs1529for(size_t k=0;k<dim;++k){1530if(elem[k][dim+red_col+j]>0){1531elem[k][dim+red_col+j]=1;1532continue;1533}1534if(elem[k][dim+red_col+j]<0){1535elem[k][dim+red_col+j]=-1;1536continue;1537}1538}15391540if(make_sol_prime) // make columns of solution coprime if wanted1541make_cols_prime(dim,nc-1);1542}15431544//---------------------------------------------------------------------------15451546template<typename Integer>1547void Matrix<Integer>::solve_system_submatrix_outer(const Matrix<Integer>& mother, const vector<key_t>& key, const vector<vector<Integer>* >& RS,1548Integer& denom, bool ZZ_invertible, bool transpose, size_t red_col, size_t sign_col,1549bool compute_denom, bool make_sol_prime) {15501551size_t dim=mother.nc;1552assert(key.size()==dim);1553assert(nr==dim);1554assert(dim+RS.size()<=nc);1555size_t save_nc=nc;1556nc=dim+RS.size();15571558if(transpose)1559select_submatrix_trans(mother,key);1560else1561select_submatrix(mother,key);15621563for(size_t i=0;i<dim;++i)1564for(size_t k=0;k<RS.size();++k)1565elem[i][k+dim]= (*RS[k])[i];15661567if(solve_destructive_inner(ZZ_invertible,denom)){1568customize_solution(dim, denom,red_col,sign_col,make_sol_prime);1569}1570else{1571#pragma omp atomic1572GMP_mat++;15731574Matrix<mpz_class> mpz_this(nr,nc);1575mpz_class mpz_denom;1576if(transpose)1577mpz_submatrix_trans(mpz_this,mother,key);1578else1579mpz_submatrix(mpz_this,mother,key);15801581for(size_t i=0;i<dim;++i)1582for(size_t k=0;k<RS.size();++k)1583convert(mpz_this[i][k+dim], (*RS[k])[i]);1584mpz_this.solve_destructive_inner(ZZ_invertible,mpz_denom);1585mpz_this.customize_solution(dim, mpz_denom,red_col,sign_col,make_sol_prime);15861587for(size_t i=0;i<dim;++i) // replace left side by 0, except diagonal if ZZ_invetible1588for(size_t j=0;j<dim;++j){1589if(i!=j || !ZZ_invertible)1590mpz_this[i][j]=0;1591}15921593mat_to_Int(mpz_this,*this);1594if(compute_denom)1595convert(denom, mpz_denom);1596}1597nc=save_nc;1598}15991600//---------------------------------------------------------------------------16011602template<typename Integer>1603void Matrix<Integer>::solve_system_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key, const vector<vector<Integer>* >& RS,1604vector< Integer >& diagonal, Integer& denom, size_t red_col, size_t sign_col) {16051606solve_system_submatrix_outer(mother,key,RS,denom,true,false,red_col,sign_col);1607assert(diagonal.size()==nr);1608for(size_t i=0;i<nr;++i)1609diagonal[i]=elem[i][i];16101611}161216131614//---------------------------------------------------------------------------1615// the same without diagonal1616template<typename Integer>1617void Matrix<Integer>::solve_system_submatrix(const Matrix<Integer>& mother, const vector<key_t>& key, const vector<vector<Integer>* >& RS,1618Integer& denom, size_t red_col, size_t sign_col, bool compute_denom, bool make_sol_prime) {16191620solve_system_submatrix_outer(mother,key,RS,denom,false,false,red_col,sign_col,1621compute_denom, make_sol_prime);1622}16231624//---------------------------------------------------------------------------16251626template<typename Integer>1627void Matrix<Integer>::solve_system_submatrix_trans(const Matrix<Integer>& mother, const vector<key_t>& key, const vector<vector<Integer>* >& RS,1628Integer& denom, size_t red_col, size_t sign_col) {16291630solve_system_submatrix_outer(mother,key,RS,denom,false,true,red_col,sign_col);1631}16321633//---------------------------------------------------------------------------16341635template<typename Integer>1636Matrix<Integer> Matrix<Integer>::extract_solution() const {1637assert(nc>=nr);1638Matrix<Integer> Solution(nr,nc-nr);1639for(size_t i=0;i<nr;++i){1640for(size_t j=0;j<Solution.nc;++j)1641Solution[i][j]=elem[i][j+nr];1642}1643return Solution;1644}16451646//---------------------------------------------------------------------------16471648template<typename Integer>1649vector<vector<Integer>* > Matrix<Integer>::row_pointers(){16501651vector<vector<Integer>* > pointers(nr);1652for(size_t i=0;i<nr;++i)1653pointers[i]=&(elem[i]);1654return pointers;1655}16561657//---------------------------------------------------------------------------16581659template<typename Integer>1660vector<vector<Integer>* > Matrix<Integer>::submatrix_pointers(const vector<key_t>& key){16611662vector<vector<Integer>* > pointers(key.size());1663for(size_t i=0;i<key.size();++i)1664pointers[i]=&(elem[key[i]]);1665return pointers;1666}1667//---------------------------------------------------------------------------16681669template<typename Integer>1670Matrix<Integer> Matrix<Integer>::solve(const Matrix<Integer>& Right_side,vector<Integer>& diagonal,Integer& denom) const {16711672Matrix<Integer> M(nr,nc+Right_side.nc);1673vector<key_t> key=identity_key(nr);1674Matrix<Integer> RS_trans=Right_side.transpose();1675vector<vector<Integer>* > RS=RS_trans.row_pointers();1676M.solve_system_submatrix(*this,key,RS,diagonal,denom,0,0);1677return M.extract_solution();1678}16791680//---------------------------------------------------------------------------16811682template<typename Integer>1683Matrix<Integer> Matrix<Integer>::solve(const Matrix<Integer>& Right_side, Integer& denom) const {16841685Matrix<Integer> M(nr,nc+Right_side.nc);1686vector<key_t> key=identity_key(nr);1687Matrix<Integer> RS_trans=Right_side.transpose();1688vector<vector<Integer>* > RS=RS_trans.row_pointers();1689M.solve_system_submatrix(*this,key,RS,denom,0,0);1690return M.extract_solution();1691}16921693//---------------------------------------------------------------------------16941695template<typename Integer>1696Matrix<Integer> Matrix<Integer>::invert(Integer& denom) const{1697assert(nr == nc);1698Matrix<Integer> Right_side(nr);16991700return solve(Right_side,denom);1701}17021703//---------------------------------------------------------------------------17041705template<typename Integer>1706Matrix<Integer> Matrix<Integer>::bundle_matrices(const Matrix<Integer>& Right_side) const {17071708assert(nr == nc);1709assert(nc == Right_side.nr);1710Matrix<Integer> M(nr,nc+Right_side.nc);1711for(size_t i=0;i<nr;++i){1712for(size_t j=0;j<nc;++j)1713M[i][j]=elem[i][j];1714for(size_t j=nc;j<M.nc;++j)1715M[i][j]=Right_side[i][j-nc];1716}1717return M;1718}1719//---------------------------------------------------------------------------17201721template<typename Integer>1722Matrix<Integer> Matrix<Integer>::invert_unprotected(Integer& denom, bool& success) const{1723assert(nr == nc);1724Matrix<Integer> Right_side(nr);1725Matrix<Integer> M=bundle_matrices(Right_side);1726success=M.solve_destructive_inner(false,denom);1727return M.extract_solution();;1728}17291730//---------------------------------------------------------------------------17311732template<typename Integer>1733void Matrix<Integer>::invert_submatrix(const vector<key_t>& key, Integer& denom, Matrix<Integer>& Inv, bool compute_denom, bool make_sol_prime) const{1734assert(key.size() == nc);1735Matrix<Integer> unit_mat(key.size());1736Matrix<Integer> M(key.size(),2*key.size());1737vector<vector<Integer>* > RS_pointers=unit_mat.row_pointers();1738M.solve_system_submatrix(*this,key,RS_pointers,denom,0,0, compute_denom, make_sol_prime);1739Inv=M.extract_solution();;1740}17411742//---------------------------------------------------------------------------17431744template<typename Integer>1745void Matrix<Integer>::simplex_data(const vector<key_t>& key, Matrix<Integer>& Supp, Integer& vol, bool compute_vol) const{1746assert(key.size() == nc);1747invert_submatrix(key,vol,Supp,compute_vol,true);1748Supp=Supp.transpose();1749// Supp.make_prime(); now done internally1750}1751//---------------------------------------------------------------------------17521753template<typename Integer>1754vector<Integer> Matrix<Integer>::solve_rectangular(const vector<Integer>& v, Integer& denom) const {1755if (nc == 0 || nr == 0) { //return zero-vector as solution1756return vector<Integer>(nc,0);1757}1758size_t i;1759vector<key_t> rows=max_rank_submatrix_lex();1760Matrix<Integer> Left_Side=submatrix(rows);1761assert(nc == Left_Side.nr); //otherwise input hadn't full rank //TODO1762Matrix<Integer> Right_Side(v.size(),1);1763Right_Side.write_column(0,v);1764Right_Side = Right_Side.submatrix(rows);1765Matrix<Integer> Solution=Left_Side.solve(Right_Side, denom);1766vector<Integer> Linear_Form(nc);1767for (i = 0; i <nc; i++) {1768Linear_Form[i] = Solution[i][0]; // the solution vector is called Linear_Form1769}1770vector<Integer> test = MxV(Linear_Form); // we have solved the system by taking a square submatrix1771// now we must test whether the solution satisfies the full system1772for (i = 0; i <nr; i++) {1773if (test[i] != denom * v[i]){1774return vector<Integer>();1775}1776}1777Integer total_gcd = libnormaliz::gcd(denom,v_gcd(Linear_Form)); // extract the gcd of denom and solution1778denom/=total_gcd;1779v_scalar_division(Linear_Form,total_gcd);1780return Linear_Form;1781}1782//---------------------------------------------------------------------------17831784template<typename Integer>1785vector<Integer> Matrix<Integer>::solve_ZZ(const vector<Integer>& v) const {17861787Integer denom;1788vector<Integer> result=solve_rectangular(v,denom);1789if(denom!=1)1790result.clear();1791return result;1792}1793//---------------------------------------------------------------------------17941795template<typename Integer>1796vector<Integer> Matrix<Integer>::find_linear_form() const {17971798Integer denom;1799vector<Integer> result=solve_rectangular(vector<Integer>(nr,1),denom);1800v_make_prime(result);1801return result;1802}18031804//---------------------------------------------------------------------------18051806template<typename Integer>1807vector<Integer> Matrix<Integer>::find_linear_form_low_dim () const{1808size_t rank=(*this).rank();1809if (rank == 0) { //return zero-vector as linear form1810return vector<Integer>(nc,0);1811}1812if (rank == nc) { // basis change not necessary1813return (*this).find_linear_form();1814}18151816Sublattice_Representation<Integer> Basis_Change(*this,true);1817vector<Integer> Linear_Form=Basis_Change.to_sublattice(*this).find_linear_form();1818if(Linear_Form.size()!=0)1819Linear_Form=Basis_Change.from_sublattice_dual(Linear_Form);18201821return Linear_Form;1822}18231824//---------------------------------------------------------------------------18251826template<typename Integer>1827size_t Matrix<Integer>::row_echelon_reduce(){18281829size_t rk;1830Matrix<Integer> Copy(*this);1831bool success;1832rk=row_echelon_reduce(success);1833if(success){1834Shrink_nr_rows(rk);1835return rk;1836}1837Matrix<mpz_class> mpz_Copy(nr,nc);1838mat_to_mpz(Copy,mpz_Copy);1839rk=mpz_Copy.row_echelon_reduce(success);1840mat_to_Int(mpz_Copy,*this);1841Shrink_nr_rows(rk);1842return rk;1843}1844//---------------------------------------------------------------------------18451846template<typename Integer>1847Integer Matrix<Integer>::full_rank_index() const{18481849Matrix<Integer> Copy(*this);1850Integer index;1851bool success;1852index=Copy.full_rank_index(success);1853if(success)1854return index;1855Matrix<mpz_class> mpz_Copy(nr,nc);1856mat_to_mpz(*this,mpz_Copy);1857mpz_class mpz_index=mpz_Copy.full_rank_index(success);1858convert(index, mpz_index);1859return index;1860}18611862//---------------------------------------------------------------------------18631864template<typename Integer>1865size_t Matrix<Integer>::row_echelon(){18661867Matrix<Integer> Copy(*this);1868bool success;1869size_t rk;1870rk=row_echelon(success);1871if(success){1872Shrink_nr_rows(rk);1873return rk;1874}1875Matrix<mpz_class> mpz_Copy(nr,nc);1876mat_to_mpz(Copy,mpz_Copy);1877rk=mpz_Copy.row_echelon_reduce(success); // reduce to make entries small1878mat_to_Int(mpz_Copy,*this);1879Shrink_nr_rows(rk);1880return rk;1881}18821883//-----------------------------------------------------------1884//1885// variants for floating point1886//1887//-----------------------------------------------------------18881889template<>1890long Matrix<nmz_float>::pivot_column(size_t row,size_t col){18911892size_t i;1893long j=-1;1894nmz_float help=0;18951896for (i = row; i < nr; i++) {1897if (Iabs(elem[i][col])>nmz_epsilon) {1898if ((help==0)||(Iabs(elem[i][col])>help)) {1899help=Iabs(elem[i][col]);1900j=i;1901} }1902}19031904return j;1905}19061907template<>1908size_t Matrix<nmz_float>::row_echelon_inner_elem(bool& success){19091910size_t pc=0;1911long piv=0, rk=0;19121913if(nr==0)1914return 0;19151916for (rk = 0; rk < (long) nr; rk++){1917for(;pc<nc;pc++){1918piv=pivot_column(rk,pc);1919if(piv>=0)1920break;1921}1922if(pc==nc)1923break;19241925exchange_rows (rk,piv);1926reduce_row(rk,pc);1927}19281929success=true;1930return rk;1931}193219331934template<>1935size_t Matrix<nmz_float>::row_echelon(){19361937size_t rk;1938bool dummy;1939rk=row_echelon_inner_elem(dummy);1940Shrink_nr_rows(rk);1941return rk;1942}1943//---------------------------------------------------------------------------19441945template<typename Integer>1946Matrix<Integer> Matrix<Integer>::kernel () const{1947// computes a ZZ-basis of the solutions of (*this)x=01948// the basis is formed by the rOWS of the returned matrix19491950size_t dim=nc;1951if(nr==0)1952return(Matrix<Integer>(dim));19531954Matrix<Integer> Copy(*this);1955size_t rank;1956bool success;1957Matrix<Integer> Transf=Copy.row_column_trigonalize(rank,success);1958if(!success){1959Matrix<mpz_class> mpz_Copy(nr,nc);1960mat_to_mpz(*this,mpz_Copy);1961Matrix<mpz_class> mpz_Transf=mpz_Copy.row_column_trigonalize(rank,success);1962mat_to_Int(mpz_Transf,Transf);1963}19641965Matrix<Integer> ker_basis(dim-rank,dim);1966Matrix<Integer> Help =Transf.transpose();1967for (size_t i = rank; i < dim; i++)1968ker_basis[i-rank]=Help[i];1969ker_basis.row_echelon_reduce();1970return(ker_basis);1971}19721973//---------------------------------------------------------------------------1974// Converts "this" into (column almost) Hermite normal form, returns column transformation matrix1975template<typename Integer>1976Matrix<Integer> Matrix<Integer>::AlmostHermite(size_t& rk){19771978Matrix<Integer> Copy=*this;1979Matrix<Integer> Transf;1980bool success;1981Transf=row_column_trigonalize(rk,success);1982if(success)1983return Transf;19841985Matrix<mpz_class> mpz_this(nr,nc);1986mat_to_mpz(Copy,mpz_this);1987Matrix<mpz_class> mpz_Transf=mpz_this.row_column_trigonalize(rk,success);1988mat_to_Int(mpz_this,*this);1989mat_to_Int(mpz_Transf,Transf);1990return Transf;1991}19921993//---------------------------------------------------------------------------19941995template<typename Integer>1996bool Matrix<Integer>::SmithNormalForm_inner(size_t& rk, Matrix<Integer>& Right){19971998bool success=true;19992000// first we diagonalize20012002while(true){2003rk=row_echelon_reduce(success);2004if(!success)2005return false;2006if(rk==0)2007break;20082009if(is_diagonal())2010break;20112012success=column_trigonalize(rk,Right);2013if(!success)2014return false;20152016if(is_diagonal())2017break;2018}20192020// now we change the diagonal so that we have successive divisibilty20212022if(rk<=1)2023return true;20242025while(true){2026size_t i=0;2027for(;i<rk-1;++i)2028if(elem[i+1][i+1]%elem[i][i]!=0)2029break;2030if(i==rk-1)2031break;20322033Integer u,v,w,z, d=ext_gcd(elem[i][i],elem[i+1][i+1],u,v);2034elem[i][i+1]=elem[i+1][i+1];2035w=-elem[i+1][i+1]/d;2036z=elem[i][i]/d;2037// Now we multiply the submatrix formed by columns "corner" and "j"2038// and rows corner,...,nr from the right by the 2x2 matrix2039// | u w |2040// | v z |2041if(!linear_comb_columns(i,i+1,u,w,v,z))2042return false;2043if(!Right.linear_comb_columns(i,i+1,u,w,v,z))2044return false;2045elem[i+1][i]=0;2046}20472048return true;2049}20502051// Converts "this" into Smith normal form, returns column transformation matrix2052template<typename Integer>2053Matrix<Integer> Matrix<Integer>::SmithNormalForm(size_t& rk){20542055size_t dim=nc;2056Matrix<Integer> Transf(dim);2057if(dim==0)2058return Transf;20592060Matrix<Integer> Copy=*this;2061bool success=SmithNormalForm_inner(rk,Transf);2062if(success)2063return Transf;20642065Matrix<mpz_class> mpz_this(nr,dim);2066mat_to_mpz(Copy,mpz_this);2067Matrix<mpz_class> mpz_Transf(dim);2068mpz_this.SmithNormalForm_inner(rk,mpz_Transf);2069mat_to_Int(mpz_this,*this);2070mat_to_Int(mpz_Transf,Transf);2071return Transf;2072}20732074//---------------------------------------------------------------------------2075// Classless conversion routines2076//---------------------------------------------------------------------------20772078template<typename ToType, typename FromType>2079void convert(Matrix<ToType>& to_mat, const Matrix<FromType>& from_mat){2080size_t nrows = from_mat.nr_of_rows();2081size_t ncols = from_mat.nr_of_columns();2082to_mat.resize(nrows, ncols);2083for(size_t i=0; i<nrows; ++i)2084for(size_t j=0; j<ncols; ++j)2085convert(to_mat[i][j], from_mat[i][j]);2086}20872088//---------------------------------------------------------------------------208920902091template<typename Integer>2092void mat_to_mpz(const Matrix<Integer>& mat, Matrix<mpz_class>& mpz_mat){2093//convert(mpz_mat, mat);2094// we allow the matrices to have different sizes2095size_t nrows = min(mat.nr_of_rows(), mpz_mat.nr_of_rows());2096size_t ncols = min(mat.nr_of_columns(),mpz_mat.nr_of_columns());2097for(size_t i=0; i<nrows; ++i)2098for(size_t j=0; j<ncols; ++j)2099convert(mpz_mat[i][j], mat[i][j]);2100#pragma omp atomic2101GMP_mat++;2102}21032104//---------------------------------------------------------------------------21052106template<typename Integer>2107void mat_to_Int(const Matrix<mpz_class>& mpz_mat, Matrix<Integer>& mat){2108//convert(mat, mpz_mat);2109// we allow the matrices to have different sizes2110size_t nrows = min(mpz_mat.nr_of_rows(), mat.nr_of_rows());2111size_t ncols = min(mpz_mat.nr_of_columns(),mat.nr_of_columns());2112for(size_t i=0; i<nrows; ++i)2113for(size_t j=0; j<ncols; ++j)2114convert(mat[i][j], mpz_mat[i][j]);2115}21162117//---------------------------------------------------------------------------21182119template<typename Integer>2120void mpz_submatrix(Matrix<mpz_class>& sub, const Matrix<Integer>& mother, const vector<key_t>& selection){21212122assert(sub.nr_of_columns()>=mother.nr_of_columns());2123assert(sub.nr_of_rows()>=selection.size());2124for(size_t i=0;i<selection.size();++i)2125for(size_t j=0;j<mother.nr_of_columns();++j)2126convert(sub[i][j], mother[selection[i]][j]);2127}21282129//---------------------------------------------------------------------------21302131template<typename Integer>2132void mpz_submatrix_trans(Matrix<mpz_class>& sub, const Matrix<Integer>& mother, const vector<key_t>& selection){21332134assert(sub.nr_of_columns()>=selection.size());2135assert(sub.nr_of_rows()>=mother.nr_of_columns());2136for(size_t i=0;i<selection.size();++i)2137for(size_t j=0;j<mother.nr_of_columns();++j)2138convert(sub[j][i], mother[selection[i]][j]);2139}21402141//---------------------------------------------------------------------------21422143/* sorts rows of a matrix by a degree function and returns the permuation2144* does not change matrix (yet)2145*/2146template<typename Integer>2147vector<key_t> Matrix<Integer>::perm_sort_by_degree(const vector<key_t>& key, const vector<Integer>& grading, bool computed) const{21482149list<vector<Integer>> rowList;2150vector<Integer> v;21512152v.resize(nc+2);2153unsigned long i,j;21542155for (i=0;i<key.size();i++){2156if (computed){2157v[0]=v_scalar_product((*this).elem[key[i]],grading);2158} else{2159v[0]=0;2160for (j=0;j<nc;j++) v[0]+=Iabs((*this).elem[key[i]][j]);2161}2162for (j=0;j<nc;j++){2163v[j+1] = (*this).elem[key[i]][j];2164}2165v[nc+1] = key[i]; // position of row2166rowList.push_back(v);2167}2168rowList.sort();2169vector<key_t> perm;2170perm.resize(key.size());2171i=0;2172for (typename list< vector<Integer> >::const_iterator it = rowList.begin();it!=rowList.end();++it){2173perm[i]=convertTo<long>((*it)[nc+1]);2174i++;2175}2176return perm;2177}21782179//---------------------------------------------------------------------------218021812182template<typename Integer>2183bool weight_lex(const order_helper<Integer>& a, const order_helper<Integer>& b){21842185if(a.weight < b.weight)2186return true;2187if(a.weight==b.weight)2188if(*(a.v)< *(b.v))2189return true;2190return false;2191}21922193//---------------------------------------------------------------------------21942195template<typename Integer>2196void Matrix<Integer>::order_rows_by_perm(const vector<key_t>& perm){2197order_by_perm(elem,perm);2198}21992200template<typename Integer>2201Matrix<Integer>& Matrix<Integer>::sort_by_weights(const Matrix<Integer>& Weights, vector<bool> absolute){2202if(nr<=1)2203return *this;2204vector<key_t> perm=perm_by_weights(Weights,absolute);2205order_by_perm(elem,perm);2206return *this;2207}22082209template<typename Integer>2210Matrix<Integer>& Matrix<Integer>::sort_lex(){2211if(nr<=1)2212return *this;2213vector<key_t> perm=perm_by_weights(Matrix<Integer>(0,nc),vector<bool>(0));2214order_by_perm(elem,perm);2215return *this;2216}22172218template<typename Integer>2219vector<key_t> Matrix<Integer>::perm_by_weights(const Matrix<Integer>& Weights, vector<bool> absolute){2220// the smallest entry is the row with index perm[0], then perm[1] etc.22212222assert(Weights.nc==nc);2223assert(absolute.size()==Weights.nr);22242225list<order_helper<Integer> > order;2226order_helper<Integer> entry;2227entry.weight.resize(Weights.nr);22282229for(key_t i=0;i<nr; ++i){2230for(size_t j=0;j<Weights.nr;++j){2231if(absolute[j])2232entry.weight[j]=v_scalar_product(Weights[j],v_abs_value(elem[i]));2233else2234entry.weight[j]=v_scalar_product(Weights[j],elem[i]);2235}2236entry.index=i;2237entry.v=&(elem[i]);2238order.push_back(entry);2239}2240order.sort(weight_lex<Integer>);2241vector<key_t> perm(nr);2242typename list<order_helper<Integer> >::const_iterator ord=order.begin();2243for(key_t i=0;i<nr;++i, ++ord)2244perm[i]=ord->index;22452246return perm;2247}22482249//---------------------------------------------------22502251template<typename Integer>2252Matrix<Integer> Matrix<Integer>::solve_congruences(bool& zero_modulus) const{225322542255zero_modulus=false;2256size_t i,j;2257size_t nr_cong=nr, dim=nc-1;2258if(nr_cong==0)2259return Matrix<Integer>(dim); // give back unit matrix22602261//add slack variables to convert congruences into equaitions2262Matrix<Integer> Cong_Slack(nr_cong, dim+nr_cong);2263for (i = 0; i < nr_cong; i++) {2264for (j = 0; j < dim; j++) {2265Cong_Slack[i][j]=elem[i][j];2266}2267Cong_Slack[i][dim+i]=elem[i][dim];2268if(elem[i][dim]==0){2269zero_modulus=true;2270return Matrix<Integer>(0,dim);2271}2272}22732274//compute kernel22752276Matrix<Integer> Help=Cong_Slack.kernel(); // gives the solutions to the the system with slack variables2277Matrix<Integer> Ker_Basis(dim,dim); // must now project to first dim coordinates to get rid of them2278for(size_t i=0;i<dim;++i)2279for(size_t j=0;j<dim;++j)2280Ker_Basis[i][j]=Help[i][j];2281return Ker_Basis;22822283}22842285//---------------------------------------------------22862287template<typename Integer>2288void Matrix<Integer>::saturate(){22892290*this=kernel().kernel();2291}22922293//---------------------------------------------------22942295template<typename Integer>2296vector<key_t> Matrix<Integer>::max_and_min(const vector<Integer>& L, const vector<Integer>& norm) const{22972298vector<key_t> result(2,0);2299if(nr==0)2300return result;2301key_t maxind=0,minind=0;2302Integer maxval=v_scalar_product(L,elem[0]);2303Integer maxnorm=1,minnorm=1;2304if(norm.size()>0){2305maxnorm=v_scalar_product(norm,elem[0]);2306minnorm=maxnorm;2307}2308Integer minval=maxval;2309for(key_t i=0;i<nr;++i){2310Integer val=v_scalar_product(L,elem[i]);2311if(norm.size()==0){2312if(val>maxval){2313maxind=i;2314maxval=val;2315}2316if(val<minval){2317minind=i;2318minval=val;2319}2320}2321else{2322Integer nm=v_scalar_product(norm,elem[i]);2323if(maxnorm*val>nm*maxval){2324maxind=i;2325maxval=val;2326}2327if(minnorm*val<nm*minval){2328minind=i;2329minval=val;2330}2331}2332}2333result[0]=maxind;2334result[1]=minind;2335return result;2336}23372338template<typename Integer>2339size_t Matrix<Integer>::extreme_points_first(const vector<Integer> norm){23402341if(nr==0)2342return 1;23432344vector<long long> norm_copy;23452346size_t nr_extr=0;2347Matrix<long long> HelpMat(nr,nc);2348try{2349convert(HelpMat,*this);2350convert(norm_copy,norm);2351}2352catch(ArithmeticException){2353return nr_extr;2354}23552356HelpMat.sort_lex();23572358vector<bool> marked(nr,false);2359size_t no_success=0;2360// size_t nr_attempt=0;2361while(true){23622363INTERRUPT_COMPUTATION_BY_EXCEPTION23642365// nr_attempt++; cout << nr_attempt << endl;2366vector<long long> L=v_random<long long>(nc,10);2367vector<key_t> max_min_ind;2368max_min_ind=HelpMat.max_and_min(L,norm_copy);23692370if(marked[max_min_ind[0]] && marked[max_min_ind[1]])2371no_success++;2372else2373no_success=0;2374if(no_success > 1000)2375break;2376marked[max_min_ind[0]]=true;2377marked[max_min_ind[1]]=true;2378}2379Matrix<long long> Extr(nr_extr,nc); // the recognized extreme rays2380Matrix<long long> NonExtr(nr_extr,nc); // the other generators2381size_t j=0;2382vector<key_t> perm(nr);2383for(size_t i=0;i<nr;++i) {2384if(marked[i]){2385perm[j]=i;;2386j++;2387}2388}2389nr_extr=j;2390for(size_t i=0;i<nr;++i) {2391if(!marked[i]){2392perm[j]=i;;2393j++;2394}2395}2396order_rows_by_perm(perm);2397// cout << nr_extr << "extreme points found" << endl;2398return nr_extr;2399// exit(0);2400}24012402template<typename Integer>2403vector<Integer> Matrix<Integer>::find_inner_point(){2404vector<key_t> simplex=max_rank_submatrix_lex();2405vector<Integer> point(nc);2406for(size_t i=0;i<simplex.size();++i)2407point=v_add(point,elem[simplex[i]]);2408return point;2409}24102411template<typename Integer>2412void Matrix<Integer>::Shrink_nr_rows(size_t new_nr_rows){24132414if(new_nr_rows>=nr)2415return;2416nr=new_nr_rows;2417elem.resize(nr);2418}24192420template<typename Integer>2421Matrix<Integer> readMatrix(const string project){2422// reads one matrix from file with name project2423// format: nr of rows, nr of colimns, entries2424// all separated by white space24252426string name_in=project;2427const char* file_in=name_in.c_str();2428ifstream in;2429in.open(file_in,ifstream::in);2430if (in.is_open()==false){2431cerr << "Cannot find input file" << endl;2432exit(1);2433}24342435int nrows,ncols;2436in >> nrows;2437in >> ncols;24382439if(nrows==0 || ncols==0){2440cerr << "Matrix empty" << endl;2441exit(1);2442}244324442445int i,j,entry;2446Matrix<Integer> result(nrows,ncols);24472448for(i=0;i<nrows;++i)2449for(j=0;j<ncols;++j){2450in >> entry;2451result[i][j]=entry;2452}2453return result;2454}24552456//---------------------------------------------------------------------------2457// version with full number of points2458// and search for optimal point24592460template<typename Integer>2461vector<Integer> Matrix<Integer>::optimal_subdivision_point() const{24622463return optimal_subdivision_point_inner();2464}24652466// In mpz_class we first try machine integer2467template<>2468vector<mpz_class> Matrix<mpz_class>::optimal_subdivision_point() const{24692470try {2471Matrix<MachineInteger> GensMI;2472convert(GensMI,*this);2473vector<MachineInteger> PMI=GensMI.optimal_subdivision_point_inner();2474vector<mpz_class> P;2475convert(P,PMI);2476return P;2477} catch(const ArithmeticException& e) {2478return optimal_subdivision_point_inner();2479}2480}24812482// version with a single point, only top of the search polytope2483// After 2 attempts without improvement, g raised to opt_value-12484template<typename Integer>2485vector<Integer> Matrix<Integer>::optimal_subdivision_point_inner() const{2486// returns empty vector if simplex cannot be subdivided with smaller detsum24872488// cout << "==================" << endl;24892490assert(nr>0);2491assert(nr==nc);24922493vector<Integer> opt_point;24942495vector<Integer> N = find_linear_form();2496assert(N.size()==nr);2497Integer G=v_scalar_product(N,elem[0]);2498if(G<=1)2499return opt_point;2500Matrix<Integer> Supp;2501Integer V;2502vector<key_t> dummy(nr);2503for(size_t i=0;i<nr;++i)2504dummy[i]=i;2505simplex_data(dummy, Supp,V,true);2506Integer MinusOne=-1;2507vector<Integer> MinusN(N);2508v_scalar_multiplication(MinusN,MinusOne);2509Supp.append(MinusN);2510Supp.resize_columns(nr+1);2511Supp.exchange_columns(0,nc); // grading to the front!25122513Integer opt_value=G;2514Integer empty_value=0;2515Integer g=G-1;25162517Integer den=2;25182519vector<Integer> Zero(nr+1); // the excluded vector2520Zero[0]=1;25212522// Incidence matrix for projectand lift2523vector<boost::dynamic_bitset<> > Ind(nr+1);2524for(size_t i=0;i<nr+1;++i){2525Ind[i].resize(nc+1);2526for(size_t j=0;j<nc+1;++j)2527Ind[i][j]=true;2528Ind[i][i]=false;2529}25302531// cout << "==============================" << endl;25322533size_t nothing_found=0;2534while(true){2535vector<Integer> SubDiv;2536// cout << "Opt " << opt_value << " test " << g << " empty " << empty_value << " nothing " << nothing_found << endl;2537Supp[nr][0]=g; // the degree at which we cut the simplex1;2538ProjectAndLift<Integer,Integer> PL(Supp,Ind,nr+1);2539PL.set_excluded_point(Zero);2540PL.set_verbose(false);2541PL.compute(false); // only a single point2542PL.put_single_point_into(SubDiv);2543if(SubDiv.size()==0){ // no point found2544nothing_found++;2545if(g==opt_value-1)2546return opt_point; // optimal point found (or nothing found)2547empty_value=g;2548if(nothing_found<1) // can't be true if "1" is not raised to a higher value2549g=empty_value+1+(den-1)*(opt_value-empty_value-2)/den;2550else2551g=opt_value-1;2552den*=2; // not used in the present setting (see above)2553}2554else{ // point found2555nothing_found=0;2556den=2; // back to start value2557opt_point=SubDiv;2558std::swap(opt_point[0],opt_point[nc]);2559opt_point.resize(nc);2560if(opt_value==empty_value+1)2561return opt_point;2562opt_value=v_scalar_product(opt_point,N);2563g=empty_value+1+(opt_value-empty_value-2)/2;2564}2565}2566}25672568#ifndef NMZ_MIC_OFFLOAD //offload with long is not supported2569template Matrix<long> readMatrix(const string project);2570#endif // NMZ_MIC_OFFLOAD2571template Matrix<long long> readMatrix(const string project);2572template Matrix<mpz_class> readMatrix(const string project);25732574} // namespace257525762577