source: git/IntegerProgramming/matrix.cc @ f07fec

spielwiese
Last change on this file since f07fec was f07fec, checked in by Max Horn <max@…>, 10 years ago
Silence compiler warnings about ambiguous looking 'else'
  • Property mode set to 100644
File size: 17.0 KB
RevLine 
[6ba162]1// matrix.cc
2
3// implementation of class matrix
4
5#ifndef MATRIX_CC
6#define MATRIX_CC
7
8#include "matrix.h"
9
10////////////// constructors and destructor //////////////////////////////////
[36f8d9]11typedef Integer* IntegerP;
12typedef BigInt* BigIntP;
[6ba162]13
[194c2e7]14matrix::matrix(const int& row_number, const int& column_number)
[6ba162]15    :rows(row_number),columns(column_number)
16{
17  _kernel_dimension=-2;
18  // LLL-algorithm not yet performed
19
20  // argument check
21  if((rows<=0)||(columns<=0))
22    // bad input, set "error flag"
23  {
[194c2e7]24    cerr<<"\nWARNING: matrix::matrix(const int&, const int&):\n"
[6ba162]25      "argument out of range"<<endl;
26    columns=-1;
27    return;
28  }
29
30  // memory allocation and initialization
31
[36f8d9]32  coefficients=new IntegerP[rows];
[194c2e7]33  for(int i=0;i<rows;i++)
[6ba162]34    coefficients[i]=new Integer[columns];
[194c2e7]35  for(int i=0;i<rows;i++)
36    for(int j=0;j<columns;j++)
[6ba162]37      coefficients[i][j]=0;
38}
39
[194c2e7]40matrix::matrix(const int& row_number, const int& column_number,
[6ba162]41               Integer** entries)
42    :rows(row_number),columns(column_number)
43{
44  _kernel_dimension=-2;
45  // LLL-algorithm not yet performed
46
47  // argument check
48  if((rows<=0)||(columns<=0))
49    // bad input, set "error flag"
50  {
[194c2e7]51    cerr<<"\nWARNING: matrix::matrix(const int&, const int&, Integr**):\n"
[6ba162]52      "argument out of range"<<endl;
53    columns=-1;
54    return;
55  }
56
57  // memory allocation and initialization
58
[36f8d9]59  coefficients=new IntegerP[rows];
[194c2e7]60  for(int i=0;i<rows;i++)
[6ba162]61    coefficients[i]=new Integer[columns];
[194c2e7]62  for(int i=0;i<rows;i++)
63    for(int j=0;j<columns;j++)
[6ba162]64      coefficients[i][j]=entries[i][j];
65  // coefficients[i] is the i-th row vector
66}
67
68
69
70
71matrix::matrix(ifstream& input)
72{
73  _kernel_dimension=-2;
74  // LLL-algorithm not yet performed
75
76  input>>rows;
77  if(!input)
78    // input failure, set "error flag"
79  {
80    cerr<<"\nWARNING: matrix::matrix(ifstream&): input failure"<<endl;
81    columns=-2;
82    return;
83  }
84
85  input>>columns;
86  if(!input)
87    // input failure, set "error flag"
88  {
89    cerr<<"\nWARNING: matrix::matrix(ifstream&): input failure"<<endl;
90    columns=-2;
91    return;
92  }
93
94  if((rows<=0)||(columns<=0))
95    // bad input, set "error flag"
96  {
97    cerr<<"\nWARNING: matrix::matrix(ifstream&): bad input"<<endl;
98    columns=-1;
99    return;
100  }
101
[36f8d9]102  coefficients=new IntegerP[rows];
[194c2e7]103  for(int i=0;i<rows;i++)
[6ba162]104    coefficients[i]=new Integer[columns];
[194c2e7]105  for(int i=0;i<rows;i++)
106    for(int j=0;j<columns;j++)
[6ba162]107    {
108      input>>coefficients[i][j];
109      if(!input)
110        // bad input, set error flag
111      {
112        cerr<<"\nWARNING: matrix::matrix(ifstream&): input failure"<<endl;
113        columns=-2;
114        return;
115      }
116    }
117}
118
119
120
121
[194c2e7]122matrix::matrix(const int& m, const int& n, ifstream& input)
[6ba162]123{
124  _kernel_dimension=-2;
125  // LLL-algorithm not yet performed
126
127  // argument check
128  if((m<=0) || (n<=0))
129    // bad input, set "error flag"
130  {
[194c2e7]131    cerr<<"\nWARNING: matrix::matrix(const int&, const int&, ifstream&):\n"
[6ba162]132      "argument out of range"<<endl;
133    columns=-1;
134    return;
135  }
136
137  rows=m;
138  columns=n;
139
140  // memory allocation and initialization
141
[36f8d9]142  coefficients=new IntegerP[rows];
[194c2e7]143  for(int i=0;i<rows;i++)
[6ba162]144    coefficients[i]=new Integer[columns];
[194c2e7]145  for(int i=0;i<rows;i++)
146    for(int j=0;j<columns;j++)
[6ba162]147    {
148      input>>coefficients[i][j];
149      if(!input)
150        // bad input, set error flag
151      {
152        columns=-2;
153        return;
154      }
155    }
156}
157
158
159
160
161matrix::matrix(const matrix& A)
162    :rows(A.rows),columns(A.columns),_kernel_dimension(A._kernel_dimension)
163{
164
165  if(columns<0)
166  {
167    cerr<<"\nWARNING: matrix::matrix(const matrix&):\n"
168      "Building a matrix from a corrupt one"<<endl;
169    return;
170  }
171
172  // memory allocation and initialization (also for H)
173
[36f8d9]174  coefficients=new IntegerP[rows];
[194c2e7]175  for(int i=0;i<rows;i++)
[6ba162]176    coefficients[i]=new Integer[columns];
[194c2e7]177  for(int i=0;i<rows;i++)
178    for(int j=0;j<columns;j++)
[6ba162]179      coefficients[i][j]=A.coefficients[i][j];
180
181  if(_kernel_dimension>0)
182  {
[36f8d9]183    H=new BigIntP[_kernel_dimension];
[194c2e7]184    for(int k=0;k<_kernel_dimension;k++)
[ae9ccf]185      H[k]=new BigInt[columns];
[194c2e7]186    for(int k=0;k<_kernel_dimension;k++)
187      for(int j=0;j<columns;j++)
[6ba162]188        H[k][j]=(A.H)[k][j];
189  }
190}
191
192
193
194
195matrix::~matrix()
196{
[194c2e7]197  for(int i=0;i<rows;i++)
[6ba162]198    delete[] coefficients[i];
199  delete[] coefficients;
200
201  if(_kernel_dimension>0)
202    // LLL-algorithm performed
203  {
[194c2e7]204    for(int i=0;i<_kernel_dimension;i++)
[6ba162]205      delete[] H[i];
206    delete[] H;
207  }
208}
209
210
211
212
213//////////////////// object properties //////////////////////////////////////
214
215
216
217
218BOOLEAN matrix::is_nonnegative() const
219{
[194c2e7]220  for(int i=0;i<rows;i++)
221    for(int j=0;j<columns;j++)
[6ba162]222      if(coefficients[i][j]<0)
223        return FALSE;
224  return TRUE;
225}
226
227
228
[194c2e7]229int matrix::error_status() const
[6ba162]230{
231  if(columns<0)
232    return columns;
233  else
234    return 0;
235}
236
237
238
[194c2e7]239int matrix::row_number() const
[6ba162]240{
241  return rows;
242}
243
244
245
[194c2e7]246int matrix::column_number() const
[6ba162]247{
248  return columns;
249}
250
251
252
253
254////////// special routines for the IP-algorithms /////////////////////////
255
256
257
258
[194c2e7]259int matrix::LLL_kernel_basis()
[6ba162]260{
261
262  // copy the column vectors of the actual matrix
263  // (They are modified by the LLL-algorithm!)
[36f8d9]264  BigInt** b=new BigIntP[columns];
[194c2e7]265  for(int n=0;n<columns;n++)
[6ba162]266    b[n]=new BigInt[rows];
[194c2e7]267  for(int n=0;n<columns;n++)
268    for(int m=0;m<rows;m++)
[6ba162]269      b[n][m]=coefficients[m][n];
270
271  // compute a LLL-reduced basis of the relations of b[0],...,b[columns-1]
272  _kernel_dimension=relations(b,columns,rows,H);
273
274  // The kernel lattice basis is now stored in the member H (vectors
275  // H[0],...,H[_kernel_dimension-1]).
276
277  // delete auxiliary vectors
[194c2e7]278  for(int n=0;n<columns;n++)
[6ba162]279    delete[] b[n];
280  delete[] b;
281
282  return _kernel_dimension;
283}
284
285
286
287
[194c2e7]288int matrix::compute_nonzero_kernel_vector()
[6ba162]289{
290
291  if(_kernel_dimension==-2)
292    // lattice basis not yet computed
293    LLL_kernel_basis();
294
295  if(_kernel_dimension==-1)
296  {
[194c2e7]297    cerr<<"\nWARNING: int matrix::compute_non_zero_kernel_vector(BigInt*&):"
[6ba162]298      "\nerror in kernel basis, cannot compute the desired vector"<<endl;
299    return 0;
300  }
301
302  if(_kernel_dimension==0)
303  {
[194c2e7]304    cerr<<"\nWARNING: int matrix::compute_non_zero_kernel_vector(BigInt*&): "
[6ba162]305      "\nkernel dimension is zero"<<endl;
306    return 0;
307  }
308
309  // Now, the kernel dimension is positive.
310
311  BigInt *M=new BigInt[_kernel_dimension];
312  // M stores a number by which the algorithm decides which vector to
313  // take next.
314
315
316// STEP 1: Determine the vector with the least zero components (if it is not
317// unique, choose the smallest).
318
319  // determine number of zero components
[194c2e7]320  for(int i=0;i<_kernel_dimension;i++)
[6ba162]321  {
322    M[i]=0;
[194c2e7]323    for(int j=0;j<columns;j++)
[4dcfb4f]324      if(H[i][j]==BigInt(0))
[6ba162]325        M[i]++;
326  }
327
328  // determine minimal number of zero components
329  BigInt min=columns;
330  // columns is an upper bound (not reached because the kernel basis cannot
331  // contain the zero vector)
[194c2e7]332  for(int i=0;i<_kernel_dimension;i++)
[6ba162]333    if(M[i]<min)
334      min=M[i];
335
336  // add the square of the norm to the vectors with the least zero components
337  // and discard the others (the norm computation is why we have chosen the
338  // M[i] to be BigInts)
[194c2e7]339  for(int i=0;i<_kernel_dimension;i++)
[6ba162]340    if(M[i]!=min)
341      M[i]=-1;
342    else
[194c2e7]343      for(int j=0;j<columns;j++)
[6ba162]344        M[i]+=H[i][j]*H[i][j];
345  // As the lattice basis does not contain the zero vector, at least one M[i]
346  // is positive!
347
348  // determine the start vector, i.e. the one with least zero components, but
349  // smallest possible (euclidian) norm
[194c2e7]350  int min_index=-1;
351  for(int i=0;i<_kernel_dimension;i++)
[4dcfb4f]352    if(M[i]>BigInt(0))
[f07fec]353    {
[6ba162]354      if(min_index==-1)
355        min_index=i;
[f07fec]356      else if(M[i]<M[min_index])
357        min_index=i;
358    }
[6ba162]359
360  // Now, H[min_index] is the vector to be transformed into a nonnegative one.
361  // For a better overview, it is swapped with the first vector
362  // (only pointers).
363
364  if(min_index!=0)
365  {
366    BigInt* swap=H[min_index];
367    H[min_index]=H[0];
368    H[0]=swap;
369  }
370
371
372// Now construct the desired vector.
373// This is done by adding a linear combination of
374// H[1],...,H[_kernel_dimension-1] to H[0]. It is important that the final
375// result, written as a linear combination of
376// H[0],...,H[_kernel_dimension-1], has coefficient 1 or -1 at H[0]
377// (to make sure that it is together with H[1],...,H[_kernel_dimension]
378// still a  l a t t i c e   basis).
379
[194c2e7]380  for(int current_position=1;current_position<columns;current_position++)
[6ba162]381    // in fact, this loop will terminate before the condition in the
382    // for-statement is satisfied...
383  {
384
385
386// STEP 2: Nonnegative vector already found?
387
388    BOOLEAN found=TRUE;
[194c2e7]389    for(int j=0;j<columns;j++)
[4dcfb4f]390      if(H[0][j]==BigInt(0))
[6ba162]391        found=FALSE;
392
393    if(found==TRUE)
394      // H[0] has only positive entries,
395      return 1;
396    // else there are further zero components
397
398
399// STEP 3: Can a furhter zero component be "eliminated"?
400// If this is the case, find a basis vector that can do this.
401
402    // determine number of components in each remaining vector that are zero
403    // in the vector itself as well as in the already constructed vector
[194c2e7]404    for(int i=current_position;i<_kernel_dimension;i++)
[6ba162]405      M[i]=0;
406
[194c2e7]407    int remaining_zero_components=0;
[6ba162]408
[194c2e7]409    for(int j=0;j<columns;j++)
[4dcfb4f]410      if(H[0][j]==BigInt(0))
[6ba162]411      {
412        remaining_zero_components++;
[194c2e7]413        for(int i=current_position;i<_kernel_dimension;i++)
[4dcfb4f]414          if(H[i][j]==BigInt(0))
[6ba162]415            M[i]++;
416      }
417
418    // determine minimal number of such components
419    min=remaining_zero_components;
420    // this is the number of zero components in H[0] and an upper bound
421    // for the M[i]
[194c2e7]422    for(int i=current_position;i<_kernel_dimension;i++)
[6ba162]423      if(M[i]<min)
424        min=M[i];
425
[d96b79]426    if(min==(const BigInt&)remaining_zero_components)
[6ba162]427      // all zero components in H[0] are zero in each remaining vector
428      // => desired vector does not exist
429      return 0;
430
431    // add the square of the norm to the vectors with the least common zero
432    // components
433    // discard the others
[194c2e7]434    for(int i=current_position;i<_kernel_dimension;i++)
[6ba162]435      if(M[i]!=min)
436        M[i]=-1;
437      else
[194c2e7]438        for(int j=0;j<columns;j++)
[6ba162]439          M[i]+=H[i][j]*H[i][j];
440    //  Again, at least one M[i] is positive!
441
442    // determine vector to proceed with
443    // This is the vector with the least common zero components with respect
444    // to H[0], but the smallest possible norm.
[194c2e7]445    int min_index=0;
446    for(int i=current_position;i<_kernel_dimension;i++)
[4dcfb4f]447      if(M[i]>BigInt(0))
[f07fec]448      {
[6ba162]449        if(min_index==0)
450          min_index=i;
[f07fec]451        else if(M[i]<M[min_index])
452          min_index=i;
453      }
[6ba162]454
455    // Now, a multiple of H[min_index] will be added to the already constructed
456    // vector H[0].
457    // For a better handling, it is swapped with the vector at current_position
458    // (only pointers).
459
460    if(min_index!=current_position)
461    {
462      BigInt* swap=H[min_index];
463      H[min_index]=H[current_position];
464      H[current_position]=swap;
465    }
466
467
468// STEP 4: Choose a convenient multiple of H[current_position] to add to H[0].
469// The number of factors "mult" that have to be tested is bounded by the
470// number of nonzero components in H[0] (for each such components, there is at
471// most one such factor that will eliminate it in the linear combination
472// H[0] + mult*H[current_position].
473
474    found=FALSE;
475
[194c2e7]476    for(int mult=1;found==FALSE;mult++)
[6ba162]477    {
478      found=TRUE;
479
480      // check if any component !=0 of H[0] becomes zero by adding
481      // mult*H[current_position]
[194c2e7]482      for(int j=0;j<columns;j++)
[4dcfb4f]483        if(H[0][j]!=BigInt(0))
[d96b79]484          if(H[0][j]+(const BigInt&)mult*H[current_position][j]
[4dcfb4f]485            ==BigInt(0))
[6ba162]486            found=FALSE;
487
488      if(found==TRUE)
[194c2e7]489        for(int j=0;j<columns;j++)
[d96b79]490          H[0][j]+=(const BigInt&)mult*H[current_position][j];
[6ba162]491      else
492        // try -mult
493      {
494
495        found=TRUE;
496
497        // check if any component !=0 of H[0] becomes zero by subtracting
498        // mult*H[current_position]
[194c2e7]499        for(int j=0;j<columns;j++)
[4dcfb4f]500          if(H[0][j]!=BigInt(0))
[d96b79]501            if(H[0][j]-(const BigInt&)mult*H[current_position][j]
[4dcfb4f]502              ==BigInt(0))
[6ba162]503              found=FALSE;
504
505        if(found==TRUE)
[194c2e7]506          for(int j=0;j<columns;j++)
[d96b79]507            H[0][j]-=(const BigInt&)mult*H[current_position][j];
[6ba162]508      }
509    }
510  }
511
512// When reaching this line, an error must have occurred.
[194c2e7]513  cerr<<"FATAL ERROR in int matrix::compute_nonnegative_vector()"<<endl;
[6ba162]514  abort();
515}
516
[194c2e7]517int matrix::compute_flip_variables(int*& F)
[6ba162]518{
519  // first compute nonzero vector
520  int okay=compute_nonzero_kernel_vector();
521
522  if(!okay)
523  {
[194c2e7]524    cout<<"\nWARNING: int matrix::compute_flip_variables(int*&):\n"
[6ba162]525      "kernel of the matrix contains no vector with nonzero components,\n"
526      "no flip variables computed"<<endl;
527    return -1;
528  }
529
530  // compute variables to flip; these might either be those corresponding
531  // to the positive components of the kernel vector without zero components
532  // or those corresponding to the negative ones
533
[194c2e7]534  int r=0;
[6ba162]535  // number of flip variables
536
[194c2e7]537  for(int j=0;j<columns;j++)
[4dcfb4f]538    if(H[0][j]<BigInt(0))
[6ba162]539      r++;
540  // remember that all components of H[0] are !=0
541
542  if(r==0)
543    // no flip variables
544    return 0;
545
546  if(2*r>columns)
547    // more negative than positive components in H[0]
548    // all variables corresponding to positive components will be flipped
549  {
550    r=columns-r;
[194c2e7]551    F=new int[r];
552    memset(F,0,r*sizeof(int));
553    int counter=0;
554    for(int j=0;j<columns;j++)
[4dcfb4f]555      if(H[0][j]> BigInt(0))
[6ba162]556      {
557        F[counter]=j;
558        counter++;
559      }
560  }
561  else
562    // more (or as many) positive than negative components in v
563    // all variables corresponding to negative components will be flipped
564  {
[194c2e7]565    F=new int[r];
566    memset(F,0,r*sizeof(int));
567    int counter=0;
568    for(int j=0;j<columns;j++)
[4dcfb4f]569      if(H[0][j]< BigInt(0))
[6ba162]570      {
571        F[counter]=j;
572        counter++;
573      }
574  }
575
576  return r;
577}
578
579
580
581
[194c2e7]582int matrix::hosten_shapiro(int*& sat_var)
[6ba162]583{
584
585  if(_kernel_dimension==-2)
586    // lattice basis not yet computed
587    LLL_kernel_basis();
588
589  if(_kernel_dimension==-1)
590  {
[194c2e7]591    cerr<<"\nWARNING: int matrix::hosten_shapiro(int*&):\n"
[6ba162]592      "error in kernel basis, cannot compute the saturation variables"<<endl;
593    return 0;
594  }
595
596  if(_kernel_dimension==0)
597    // the toric ideal corresponding to the kernel lattice is the zero ideal,
598    // no saturation variables necessary
599    return 0;
600
601  // Now, the kernel dimension is positive.
602
603  if(columns==1)
604    // matrix consists of one zero column, kernel is generated by the vector
605    // (1) corresponding to the toric ideal <x-1> which is already staurated
606    return 0;
607
[194c2e7]608  int number_of_sat_var=0;
609  sat_var=new int[columns/2];
610  memset(sat_var,0,sizeof(int)*(columns/2));
[6ba162]611
612  BOOLEAN* ideal_saturated_by_var=new BOOLEAN[columns];
613  // auxiliary array used to remember by which variables the ideal has still to
614  // be saturated
[194c2e7]615  for(int j=0;j<columns;j++)
[6ba162]616    ideal_saturated_by_var[j]=FALSE;
617
[194c2e7]618  for(int k=0;k<_kernel_dimension;k++)
[6ba162]619  {
620    // determine number of positive and negative components in H[k]
621    // corresponding to variables by which the ideal has still to be saturated
[194c2e7]622    int pos_sat_var=0;
623    int neg_sat_var=0;
[6ba162]624
[194c2e7]625    for(int j=0;j<columns;j++)
[6ba162]626    {
627      if(ideal_saturated_by_var[j]==FALSE)
628      {
[4dcfb4f]629        if(H[k][j]> BigInt(0))
[6ba162]630          pos_sat_var++;
631        else
[4dcfb4f]632          if(H[k][j]< BigInt(0))
[6ba162]633            neg_sat_var++;
634      }
635    }
636
637
638    // now add the smaller set to the saturation variables
639    if(pos_sat_var<=neg_sat_var)
640    {
[194c2e7]641      for(int j=0;j<columns;j++)
[6ba162]642        if(ideal_saturated_by_var[j]==FALSE)
[f07fec]643        {
[4dcfb4f]644          if(H[k][j]> BigInt(0))
[6ba162]645            // ideal has to be saturated by the variables corresponding
646            // to positive components
647          {
648            sat_var[number_of_sat_var]=j;
649            ideal_saturated_by_var[j]=TRUE;
650            number_of_sat_var++;
651          }
[f07fec]652          else if(H[k][j]< BigInt(0))
[6ba162]653              // then the ideal is automatically saturated by the variables
654              // corresponding to negative components
655              ideal_saturated_by_var[j]=TRUE;
[f07fec]656        }
[6ba162]657    }
658    else
659    {
[194c2e7]660      for(int j=0;j<columns;j++)
[6ba162]661        if(ideal_saturated_by_var[j]==FALSE)
[f07fec]662        {
[4dcfb4f]663          if(H[k][j]< BigInt(0))
[6ba162]664            // ideal has to be saturated by the variables corresponding
665            // to negative components
666          {
667            sat_var[number_of_sat_var]=j;
668            ideal_saturated_by_var[j]=TRUE;
669            number_of_sat_var++;
670          }
[f07fec]671          else if(H[k][j]> BigInt(0))
[6ba162]672              // then the ideal is automatically saturated by the variables
673              // corresponding to positive components
674              ideal_saturated_by_var[j]=TRUE;
[f07fec]675        }
[6ba162]676    }
677  }
678
679  // clean up memory
680  delete[] ideal_saturated_by_var;
681
682  return number_of_sat_var;
683}
684
685
686
687
688//////////////////// output ///////////////////////////////////////////////
689
690
691
692
693void matrix::print() const
694{
695  printf("\n%3d x %3d\n",rows,columns);
696
[194c2e7]697  for(int i=0;i<rows;i++)
[6ba162]698  {
[194c2e7]699    for(int j=0;j<columns;j++)
[6ba162]700      printf("%6d",coefficients[i][j]);
701    printf("\n");
702  }
703}
704
705
706void matrix::print(FILE *output) const
707{
708  fprintf(output,"\n%3d x %3d\n",rows,columns);
709
[194c2e7]710  for(int i=0;i<rows;i++)
[6ba162]711  {
[194c2e7]712    for(int j=0;j<columns;j++)
[6ba162]713      fprintf(output,"%6d",coefficients[i][j]);
714    fprintf(output,"\n");
715  }
716}
717
718
719void matrix::print(ofstream& output) const
720{
721  output<<endl<<setw(3)<<rows<<" x "<<setw(3)<<columns<<endl;
722
[194c2e7]723  for(int i=0;i<rows;i++)
[6ba162]724  {
[194c2e7]725    for(int j=0;j<columns;j++)
[6ba162]726      output<<setw(6)<<coefficients[i][j];
727    output<<endl;
728  }
729}
730#endif  // matrix.cc
Note: See TracBrowser for help on using the repository browser.