source: git/libpolys/coeffs/bigintmat.cc @ efa704d

spielwiese
Last change on this file since efa704d was efa704d, checked in by Hans Schoenemann <hannes@…>, 10 years ago
compatibility with intmat/intvec
  • Property mode set to 100644
File size: 60.3 KB
Line 
1/*****************************************
2 *  Computer Algebra System SINGULAR      *
3 *****************************************/
4/*
5 *  * ABSTRACT: class bigintmat: matrices of numbers.
6 *   * a few functinos might be limited to bigint or euclidean rings.
7 *    */
8
9
10#include <misc/auxiliary.h>
11
12
13
14#include "bigintmat.h"
15#include <misc/intvec.h>
16#include <coeffs/longrat.h>
17
18
19#include <math.h>
20#include <string.h>
21
22
23//#define BIMATELEM(M,I,J) (M)[ (M).index(I,J) ]
24
25bigintmat * bigintmat::transpose()
26{
27  bigintmat * t = new bigintmat(col, row, basecoeffs());
28  for (int i=1; i<=row; i++)
29  {
30    for (int j=1; j<=col; j++)
31    {
32      t->set(j, i, BIMATELEM(*this,i,j));
33    }
34  }
35  return t;
36}
37
38void bigintmat::inpTranspose()
39{
40  int n = row,
41      m = col,
42      nm = n<m?n : m; // the min, describing the square part of the matrix
43  //CF: this is not optimal, but so far, it seems to work
44
45#define swap(_i, _j)        \
46  int __i = (_i), __j=(_j); \
47  number c = v[__i];        \
48  v[__i] = v[__j];          \
49  v[__j] = c                \
50
51  for (int i=0; i< nm; i++)
52    for (int j=i+1; j< nm; j++) {
53      swap(i*m+j, j*n+i);
54    }
55  if (n<m)
56    for (int i=nm; i<m; i++)
57      for(int j=0; j<n; j++) {
58        swap(j*n+i, i*m+j);
59      }
60  if (n>m)
61    for (int i=nm; i<n; i++)
62      for(int j=0; j<m; j++) {
63        swap(i*m+j, j*n+i);
64      }
65#undef swap
66  row = m;
67  col = n;
68}
69
70
71// Beginnt bei [0]
72void bigintmat::set(int i, number n, const coeffs C)
73{
74  assume (C == NULL || C == basecoeffs());
75
76  rawset(i, n_Copy(n, basecoeffs()), basecoeffs());
77}
78
79// Beginnt bei [1,1]
80void bigintmat::set(int i, int j, number n, const coeffs C)
81{
82  assume (C == NULL || C == basecoeffs());
83  assume (i > 0 && j > 0);
84  assume (i <= rows() && j <= cols());
85  set(index(i, j), n, C);
86}
87
88number bigintmat::get(int i) const
89{
90  assume (i >= 0);
91  assume (i<rows()*cols());
92
93  return n_Copy(v[i], basecoeffs());
94}
95
96number bigintmat::view(int i) const
97{
98  assume (i >= 0);
99  assume (i<rows()*cols());
100
101  return v[i];
102}
103
104number bigintmat::get(int i, int j) const
105{
106  assume (i > 0 && j > 0);
107  assume (i <= rows() && j <= cols());
108
109  return get(index(i, j));
110}
111
112number bigintmat::view(int i, int j) const
113{
114  assume (i >= 0 && j >= 0);
115  assume (i <= rows() && j <= cols());
116
117  return view(index(i, j));
118}
119// Ueberladener *=-Operator (fÃŒr int und bigint)
120// Frage hier: *= verwenden oder lieber = und * einzeln?
121void bigintmat::operator*=(int intop)
122{
123  number iop = n_Init(intop, basecoeffs());
124
125  inpMult(iop, basecoeffs());
126
127  n_Delete(&iop, basecoeffs());
128}
129
130void bigintmat::inpMult(number bintop, const coeffs C)
131{
132  assume (C == NULL || C == basecoeffs());
133
134  const int l = rows() * cols();
135
136  for (int i=0; i < l; i++)
137    n_InpMult(v[i], bintop, basecoeffs());
138}
139
140// Stimmen Parameter?
141// Welche der beiden Methoden?
142// Oder lieber eine comp-Funktion?
143
144bool operator==(const bigintmat & lhr, const bigintmat & rhr)
145{
146  if (&lhr == &rhr) { return true; }
147  if (lhr.cols() != rhr.cols()) { return false; }
148  if (lhr.rows() != rhr.rows()) { return false; }
149  if (lhr.basecoeffs() != rhr.basecoeffs()) { return false; }
150
151  const int l = (lhr.rows())*(lhr.cols());
152
153  for (int i=0; i < l; i++)
154  {
155    if (!n_Equal(lhr[i], rhr[i], lhr.basecoeffs())) { return false; }
156  }
157
158  return true;
159}
160
161bool operator!=(const bigintmat & lhr, const bigintmat & rhr)
162{
163  return !(lhr==rhr);
164}
165
166// Matrix-Add/-Sub/-Mult so oder mit operator+/-/* ?
167bigintmat * bimAdd(bigintmat * a, bigintmat * b)
168{
169  if (a->cols() != b->cols()) return NULL;
170  if (a->rows() != b->rows()) return NULL;
171  if (a->basecoeffs() != b->basecoeffs()) { return NULL; }
172
173  const coeffs basecoeffs = a->basecoeffs();
174
175  int i;
176
177  bigintmat * bim = new bigintmat(a->rows(), a->cols(), basecoeffs);
178
179  for (i=a->rows()*a->cols()-1;i>=0; i--)
180    bim->rawset(i, n_Add((*a)[i], (*b)[i], basecoeffs), basecoeffs);
181
182  return bim;
183}
184bigintmat * bimAdd(bigintmat * a, int b)
185{
186
187  const int mn = a->rows()*a->cols();
188
189  const coeffs basecoeffs = a->basecoeffs();
190  number bb=n_Init(b,basecoeffs);
191
192  int i;
193
194  bigintmat * bim = new bigintmat(a->rows(),a->cols() , basecoeffs);
195
196  for (i=0; i<mn; i++)
197    bim->rawset(i, n_Add((*a)[i], bb, basecoeffs), basecoeffs);
198
199  n_Delete(&bb,basecoeffs);
200  return bim;
201}
202
203bigintmat * bimSub(bigintmat * a, bigintmat * b)
204{
205  if (a->cols() != b->cols()) return NULL;
206  if (a->rows() != b->rows()) return NULL;
207  if (a->basecoeffs() != b->basecoeffs()) { return NULL; }
208
209  const coeffs basecoeffs = a->basecoeffs();
210
211  int i;
212
213  bigintmat * bim = new bigintmat(a->rows(), a->cols(), basecoeffs);
214
215  for (i=a->rows()*a->cols()-1;i>=0; i--)
216    bim->rawset(i, n_Sub((*a)[i], (*b)[i], basecoeffs), basecoeffs);
217
218  return bim;
219}
220
221bigintmat * bimSub(bigintmat * a, int b)
222{
223  const int mn = a->rows()*a->cols();
224
225  const coeffs basecoeffs = a->basecoeffs();
226  number bb=n_Init(b,basecoeffs);
227
228  int i;
229
230  bigintmat * bim = new bigintmat(a->rows(),a->cols() , basecoeffs);
231
232  for (i=0; i<mn; i++)
233    bim->rawset(i, n_Sub((*a)[i], bb, basecoeffs), basecoeffs);
234
235  n_Delete(&bb,basecoeffs);
236  return bim;
237}
238
239//TODO: make special versions for certain rings!
240bigintmat * bimMult(bigintmat * a, bigintmat * b)
241{
242  const int ca = a->cols();
243  const int cb = b->cols();
244
245  const int ra = a->rows();
246  const int rb = b->rows();
247
248  if (ca != rb)
249  {
250#ifndef SING_NDEBUG
251    Werror("wrong bigintmat sizes at multiplication a * b: acols: %d != brows: %d\n", ca, rb);
252#endif
253    return NULL;
254  }
255
256  assume (ca == rb);
257
258  if (a->basecoeffs() != b->basecoeffs()) { return NULL; }
259
260  const coeffs basecoeffs = a->basecoeffs();
261
262  int i, j, k;
263
264  number sum;
265
266  bigintmat * bim = new bigintmat(ra, cb, basecoeffs);
267
268  for (i=1; i<=ra; i++)
269    for (j=1; j<=cb; j++)
270    {
271      sum = n_Init(0, basecoeffs);
272
273      for (k=1; k<=ca; k++)
274      {
275        number prod = n_Mult( BIMATELEM(*a, i, k), BIMATELEM(*b, k, j), basecoeffs);
276
277        number sum2 = n_Add(sum, prod, basecoeffs); // no inplace add :(
278
279        n_Delete(&sum, basecoeffs); n_Delete(&prod, basecoeffs);
280
281        sum = sum2;
282      }
283      bim->rawset(i, j, sum, basecoeffs);
284    }
285  return bim;
286}
287
288bigintmat * bimMult(bigintmat * a, int b)
289{
290
291  const int mn = a->rows()*a->cols();
292
293  const coeffs basecoeffs = a->basecoeffs();
294  number bb=n_Init(b,basecoeffs);
295
296  int i;
297
298  bigintmat * bim = new bigintmat(a->rows(),a->cols() , basecoeffs);
299
300  for (i=0; i<mn; i++)
301    bim->rawset(i, n_Mult((*a)[i], bb, basecoeffs), basecoeffs);
302
303  n_Delete(&bb,basecoeffs);
304  return bim;
305}
306
307bigintmat * bimMult(bigintmat * a, number b, const coeffs cf)
308{
309  if (cf!=a->basecoeffs()) return NULL;
310
311  const int mn = a->rows()*a->cols();
312
313  const coeffs basecoeffs = a->basecoeffs();
314
315  int i;
316
317  bigintmat * bim = new bigintmat(a->rows(),a->cols() , basecoeffs);
318
319  for (i=0; i<mn; i++)
320    bim->rawset(i, n_Mult((*a)[i], b, basecoeffs), basecoeffs);
321
322  return bim;
323}
324
325// ----------------------------------------------------------------- //
326// Korrekt?
327
328intvec * bim2iv(bigintmat * b)
329{
330  intvec * iv = new intvec(b->rows(), b->cols(), 0);
331  for (int i=0; i<(b->rows())*(b->cols()); i++)
332    (*iv)[i] = n_Int((*b)[i], b->basecoeffs()); // Geht das so?
333  return iv;
334}
335
336bigintmat * iv2bim(intvec * b, const coeffs C)
337{
338  const int l = (b->rows())*(b->cols());
339  bigintmat * bim = new bigintmat(b->rows(), b->cols(), C);
340
341  for (int i=0; i < l; i++)
342    bim->rawset(i, n_Init((*b)[i], C), C);
343
344  return bim;
345}
346
347// ----------------------------------------------------------------- //
348
349int bigintmat::compare(const bigintmat* op) const
350{
351  assume (basecoeffs() == op->basecoeffs() );
352
353#ifndef SING_NDEBUG
354  if (basecoeffs() != op->basecoeffs() )
355    WerrorS("wrong bigintmat comparison: different basecoeffs!\n");
356#endif
357
358  if ((col!=1) ||(op->cols()!=1))
359  {
360    if((col!=op->cols())
361       || (row!=op->rows()))
362      return -2;
363  }
364
365  int i;
366  for (i=0; i<si_min(row*col,op->rows()*op->cols()); i++)
367  {
368    if ( n_Greater(v[i], (*op)[i], basecoeffs()) )
369      return 1;
370    else if (! n_Equal(v[i], (*op)[i], basecoeffs()))
371      return -1;
372  }
373
374  for (; i<row; i++)
375  {
376    if ( n_GreaterZero(v[i], basecoeffs()) )
377      return 1;
378    else if (! n_IsZero(v[i], basecoeffs()) )
379      return -1;
380  }
381  for (; i<op->rows(); i++)
382  {
383    if ( n_GreaterZero((*op)[i], basecoeffs()) )
384      return -1;
385    else if (! n_IsZero((*op)[i], basecoeffs()) )
386      return 1;
387  }
388  return 0;
389}
390
391
392bigintmat * bimCopy(const bigintmat * b)
393{
394  if (b == NULL)
395    return NULL;
396
397  return new bigintmat(b);
398}
399
400void bigintmat::Write()
401{
402  int n = cols(), m=rows();
403
404  StringAppendS("[ ");
405  for(int i=1; i<= m; i++) {
406    StringAppendS("[ ");
407    for(int j=1; j< n; j++) {
408      n_Write(v[(i-1)*n+j-1], basecoeffs());
409      StringAppendS(", ");
410    }
411    if (n) n_Write(v[i*n-1], basecoeffs());
412    StringAppendS(" ]");
413    if (i<m) {
414      StringAppendS(", ");
415    }
416  }
417  StringAppendS(" ] ");
418}
419
420char* bigintmat::String()
421{
422  StringSetS("");
423  Write();
424  return StringEndS();
425}
426
427void bigintmat::Print()
428{
429  char * s = String();
430  PrintS(s);
431  omFree(s);
432}
433
434
435char* bigintmat::StringAsPrinted()
436{
437  if ((col==0) || (row==0))
438    return NULL;
439  else
440  {
441    int * colwid = getwid(80);
442    if (colwid == NULL)
443    {
444      WerrorS("not enough space to print bigintmat");
445      WerrorS("try string(...) for a unformatted output");
446      return NULL;
447    }
448    char * ps;
449    int slength = 0;
450    for (int j=0; j<col; j++)
451      slength += colwid[j]*row;
452    slength += col*row+row;
453    ps = (char*) omAlloc0(sizeof(char)*(slength));
454    int pos = 0;
455    for (int i=0; i<col*row; i++)
456    {
457      StringSetS("");
458      n_Write(v[i], basecoeffs());
459      char * ts = StringEndS();
460      const int _nl = strlen(ts);
461      int cj = i%col;
462      if (_nl > colwid[cj])
463      {
464        StringSetS("");
465        int ci = i/col;
466        StringAppend("[%d,%d]", ci+1, cj+1);
467        char * ph = StringEndS();
468        int phl = strlen(ph);
469        if (phl > colwid[cj])
470        {
471          for (int j=0; j<colwid[cj]-1; j++)
472            ps[pos+j] = ' ';
473          ps[pos+colwid[cj]-1] = '*';
474        }
475        else
476        {
477          for (int j=0; j<colwid[cj]-phl; j++)
478            ps[pos+j] = ' ';
479          for (int j=0; j<phl; j++)
480            ps[pos+colwid[cj]-phl+j] = ph[j];
481        }
482        omFree(ph);
483    }
484    else  // Mit Leerzeichen auffÃŒllen und zahl reinschreiben
485    {
486      for (int j=0; j<colwid[cj]-_nl; j++)
487        ps[pos+j] = ' ';
488      for (int j=0; j<_nl; j++)
489        ps[pos+colwid[cj]-_nl+j] = ts[j];
490    }
491    // ", " und (evtl) "\n" einfÃŒgen
492    if ((i+1)%col == 0)
493    {
494      if (i != col*row-1)
495      {
496        ps[pos+colwid[cj]] = ',';
497        ps[pos+colwid[cj]+1] = '\n';
498        pos += colwid[cj]+2;
499      }
500    }
501    else
502    {
503      ps[pos+colwid[cj]] = ',';
504      pos += colwid[cj]+1;
505    }
506
507      omFree(ts);  // Hier ts zerstören
508  }
509  return(ps);
510  // omFree(ps);
511}
512}
513
514static int intArrSum(int * a, int length)
515{
516  int sum = 0;
517  for (int i=0; i<length; i++)
518    sum += a[i];
519  return sum;
520}
521
522static int findLongest(int * a, int length)
523{
524  int l = 0;
525  int index;
526  for (int i=0; i<length; i++)
527  {
528    if (a[i] > l)
529    {
530      l = a[i];
531      index = i;
532    }
533  }
534  return index;
535}
536
537static int getShorter (int * a, int l, int j, int cols, int rows)
538{
539  int sndlong = 0;
540  int min;
541  for (int i=0; i<rows; i++)
542  {
543    int index = cols*i+j;
544    if ((a[index] > sndlong) && (a[index] < l))
545    {
546      min = floor(log10((double)cols))+floor(log10((double)rows))+5;
547      if ((a[index] < min) && (min < l))
548        sndlong = min;
549      else
550        sndlong = a[index];
551    }
552  }
553  if (sndlong == 0)
554  {
555    min = floor(log10((double)cols))+floor(log10((double)rows))+5;
556    if (min < l)
557      sndlong = min;
558    else
559      sndlong = 1;
560  }
561  return sndlong;
562}
563
564
565int * bigintmat::getwid(int maxwid)
566{
567  int const c = /*2**/(col-1)+1;
568  if (col + c > maxwid-1) return NULL;
569  int * wv = (int*)omAlloc(sizeof(int)*col*row);
570  int * cwv = (int*)omAlloc(sizeof(int)*col);
571  for (int j=0; j<col; j++)
572  {
573    cwv[j] = 0;
574    for (int i=0; i<row; i++)
575    {
576      StringSetS("");
577      n_Write(v[col*i+j], basecoeffs());
578      char * tmp = StringEndS();
579      const int _nl = strlen(tmp);
580      wv[col*i+j] = _nl;
581      if (_nl > cwv[j])
582        cwv[j]=_nl;
583        omFree(tmp);
584    }
585  }
586
587  // Groesse verkleinern, bis < maxwid
588  while (intArrSum(cwv, col)+c > maxwid)
589  {
590    int j = findLongest(cwv, col);
591    cwv[j] = getShorter(wv, cwv[j], j, col, row);
592  }
593  omFree(wv);
594return cwv;
595}
596
597void bigintmat::pprint(int maxwid)
598{
599  if ((col==0) || (row==0))
600    PrintS("");
601  else
602  {
603    int * colwid = getwid(maxwid);
604    if (colwid == NULL)
605    {
606      WerrorS("not enough space to print bigintmat");
607      return;
608    }
609    char * ps;
610    int slength = 0;
611    for (int j=0; j<col; j++)
612      slength += colwid[j]*row;
613    slength += col*row+row;
614    ps = (char*) omAlloc0(sizeof(char)*(slength));
615    int pos = 0;
616    for (int i=0; i<col*row; i++)
617    {
618      StringSetS("");
619      n_Write(v[i], basecoeffs());
620      char * ts = StringEndS();
621      const int _nl = strlen(ts);
622      int cj = i%col;
623      if (_nl > colwid[cj])
624      {
625        StringSetS("");
626        int ci = i/col;
627        StringAppend("[%d,%d]", ci+1, cj+1);
628        char * ph = StringEndS();
629        int phl = strlen(ph);
630        if (phl > colwid[cj])
631        {
632          for (int j=0; j<colwid[cj]-1; j++)
633            ps[pos+j] = ' ';
634          ps[pos+colwid[cj]-1] = '*';
635        }
636        else
637        {
638          for (int j=0; j<colwid[cj]-phl; j++)
639            ps[pos+j] = ' ';
640          for (int j=0; j<phl; j++)
641            ps[pos+colwid[cj]-phl+j] = ph[j];
642        }
643          omFree(ph);
644      }
645      else  // Mit Leerzeichen auffÃŒllen und zahl reinschreiben
646      {
647        for (int j=0; j<colwid[cj]-_nl; j++)
648          ps[pos+j] = ' ';
649        for (int j=0; j<_nl; j++)
650          ps[pos+colwid[cj]-_nl+j] = ts[j];
651      }
652      // ", " und (evtl) "\n" einfÃŒgen
653      if ((i+1)%col == 0)
654      {
655        if (i != col*row-1)
656        {
657          ps[pos+colwid[cj]] = ',';
658          ps[pos+colwid[cj]+1] = '\n';
659          pos += colwid[cj]+2;
660        }
661      }
662      else
663      {
664        ps[pos+colwid[cj]] = ',';
665        pos += colwid[cj]+1;
666      }
667
668      omFree(ts);  // Hier ts zerstören
669    }
670    PrintS(ps);
671    omFree(ps);
672  }
673}
674
675
676//swaps columns i and j
677void bigintmat::swap(int i, int j) {
678  if ((i <= col) && (j <= col) && (i>0) && (j>0)) {
679    number tmp;
680    number t;
681    for (int k=1; k<=row; k++) {
682      tmp = get(k, i);
683      t = view(k, j);
684      set(k, i, t);
685      set(k, j, tmp);
686      n_Delete(&tmp, basecoeffs());
687    }
688  } else
689    Werror("Error in swap");
690}
691
692void bigintmat::swaprow(int i, int j) {
693  if ((i <= row) && (j <= row) && (i>0) && (j>0)) {
694    number tmp;
695    number t;
696    for (int k=1; k<=col; k++) {
697      tmp = get(i, k);
698      t = view(j, k);
699      set(i, k, t);
700      set(j, k, tmp);
701      n_Delete(&tmp, basecoeffs());
702    }
703  }
704  else
705    Werror("Error in swaprow");
706}
707
708int bigintmat::findnonzero(int i)
709{
710  for (int j=1; j<=col; j++) {
711    if (!n_IsZero(view(i,j), basecoeffs()))
712    {
713      return j;
714    }
715  }
716  return 0;
717}
718
719int bigintmat::findcolnonzero(int j)
720{
721  for (int i=row; i>=1; i--) {
722    if (!n_IsZero(view(i,j), basecoeffs()))
723    {
724      return i;
725    }
726  }
727  return 0;
728}
729
730void bigintmat::getcol(int j, bigintmat *a)
731{
732  assume((j<=col) && (j>=1));
733  if (((a->rows() != row) || (a->cols() != 1)) && ((a->rows() != 1) || (a->cols() != row))) {
734    assume(0);
735    Werror("Error in getcol. Dimensions must agree!");
736    return;
737  }
738  if (!nCoeffs_are_equal(basecoeffs(), a->basecoeffs())) {
739    nMapFunc f = n_SetMap(basecoeffs(), a->basecoeffs());
740    number t1, t2;
741    for (int i=1; i<=row;i++) {
742    t1 = get(i,j);
743    t2 = f(t1, basecoeffs(), a->basecoeffs());
744    a->set(i-1,t1);
745    n_Delete(&t1, basecoeffs());
746    n_Delete(&t2, a->basecoeffs());
747  }
748    return;
749  }
750  number t1;
751  for (int i=1; i<=row;i++) {
752    t1 = view(i,j);
753    a->set(i-1,t1);
754  }
755}
756
757void bigintmat::getColRange(int j, int no, bigintmat *a)
758{
759  number t1;
760  for(int ii=0; ii< no; ii++) {
761    for (int i=1; i<=row;i++) {
762      t1 = view(i, ii+j);
763      a->set(i, ii+1, t1);
764    }
765  }
766}
767
768void bigintmat::getrow(int i, bigintmat *a)
769{
770  if ((i>row) || (i<1)) {
771    Werror("Error in getrow: Index out of range!");
772    return;
773  }
774  if (((a->rows() != 1) || (a->cols() != col)) && ((a->rows() != col) || (a->cols() != 1))) {
775    Werror("Error in getrow. Dimensions must agree!");
776    return;
777  }
778  if (!nCoeffs_are_equal(basecoeffs(), a->basecoeffs())) {
779    nMapFunc f = n_SetMap(basecoeffs(), a->basecoeffs());
780    number t1, t2;
781    for (int j=1; j<=col;j++) {
782      t1 = get(i,j);
783      t2 = f(t1, basecoeffs(), a->basecoeffs());
784      a->set(j-1,t2);
785      n_Delete(&t1, basecoeffs());
786      n_Delete(&t2, a->basecoeffs());
787    }
788    return;
789  }
790  number t1;
791  for (int j=1; j<=col;j++) {
792    t1 = get(i,j);
793    a->set(j-1,t1);
794    n_Delete(&t1, basecoeffs());
795  }
796}
797
798
799void bigintmat::setcol(int j, bigintmat *m)
800{
801   if ((j>col) || (j<1)) {
802    Werror("Error in setcol: Index out of range!");
803    return;
804  }
805  if (((m->rows() != row) || (m->cols() != 1)) && ((m->rows() != 1) || (m->cols() != row))) {
806    Werror("Error in setcol. Dimensions must agree!");
807    return;
808  }
809  if (!nCoeffs_are_equal(basecoeffs(), m->basecoeffs())) {
810    nMapFunc f = n_SetMap(m->basecoeffs(), basecoeffs());
811    number t1,t2;
812    for (int i=1; i<=row; i++) {
813      t1 = m->get(i-1);
814      t2 = f(t1, m->basecoeffs(),basecoeffs());
815      set(i, j, t2);
816      n_Delete(&t2, basecoeffs());
817      n_Delete(&t1, m->basecoeffs());
818    }
819    return;
820  }
821  number t1;
822  for (int i=1; i<=row; i++) {
823      t1 = m->view(i-1);
824      set(i, j, t1);
825  }
826}
827
828void bigintmat::setrow(int j, bigintmat *m) {
829  if ((j>row) || (j<1)) {
830    Werror("Error in setrow: Index out of range!");
831    return;
832  }
833  if (((m->rows() != 1) || (m->cols() != col)) && ((m->rows() != col) || (m->cols() != 1))) {
834    Werror("Error in setrow. Dimensions must agree!");
835    return;
836  }
837  if (!nCoeffs_are_equal(basecoeffs(), m->basecoeffs())) {
838    nMapFunc f = n_SetMap(m->basecoeffs(), basecoeffs());
839    number tmp1,tmp2;
840  for (int i=1; i<=col; i++) {
841      tmp1 = m->get(i-1);
842      tmp2 = f(tmp1, m->basecoeffs(),basecoeffs());
843      set(j, i, tmp2);
844      n_Delete(&tmp2, basecoeffs());
845      n_Delete(&tmp1, m->basecoeffs());
846  }
847    return;
848  }
849  number tmp;
850  for (int i=1; i<=col; i++) {
851      tmp = m->view(i-1);
852      set(j, i, tmp);
853  }
854
855}
856
857bool bigintmat::add(bigintmat *b)
858{
859  if ((b->rows() != row) || (b->cols() != col)) {
860    Werror("Error in bigintmat::add. Dimensions do not agree!");
861    return false;
862  }
863  if (!nCoeffs_are_equal(basecoeffs(), b->basecoeffs())) {
864    Werror("Error in bigintmat::add. coeffs do not agree!");
865    return false;
866  }
867  for (int i=1; i<=row; i++) {
868    for (int j=1; j<=col; j++) {
869      rawset(i, j, n_Add(b->view(i,j), view(i,j), basecoeffs()));
870    }
871  }
872  return true;
873}
874
875bool bigintmat::sub(bigintmat *b)
876{
877 if ((b->rows() != row) || (b->cols() != col)) {
878    Werror("Error in bigintmat::sub. Dimensions do not agree!");
879    return false;
880  }
881  if (!nCoeffs_are_equal(basecoeffs(), b->basecoeffs())) {
882    Werror("Error in bigintmat::sub. coeffs do not agree!");
883    return false;
884  }
885  for (int i=1; i<=row; i++) {
886    for (int j=1; j<=col; j++) {
887      rawset(i, j, n_Sub(view(i,j), b->view(i,j), basecoeffs()));
888    }
889  }
890  return true;
891}
892
893bool bigintmat::skalmult(number b, coeffs c)
894{
895  if (!nCoeffs_are_equal(c, basecoeffs()))
896  {
897    Werror("Wrong coeffs\n");
898    return false;
899  }
900  number t1, t2;
901  if ( n_IsOne(b,c)) return true;
902  for (int i=1; i<=row; i++)
903  {
904    for (int j=1; j<=col; j++)
905    {
906      t1 = view(i, j);
907      t2 = n_Mult(t1, b, basecoeffs());
908      rawset(i, j, t2);
909    }
910  }
911  return true;
912}
913
914bool bigintmat::addcol(int i, int j, number a, coeffs c)
915{
916  if ((i>col) || (j>col) || (i<1) || (j<1)) {
917    Werror("Error in addcol: Index out of range!");
918    return false;
919  }
920  if (!nCoeffs_are_equal(c, basecoeffs())) {
921    Werror("Error in addcol: coeffs do not agree!");
922    return false;
923  }
924  number t1, t2, t3, t4;
925  for (int k=1; k<=row; k++)
926  {
927    t1 = view(k, j);
928    t2 = view(k, i);
929    t3 = n_Mult(t1, a, basecoeffs());
930    t4 = n_Add(t3, t2, basecoeffs());
931    rawset(k, i, t4);
932    n_Delete(&t3, basecoeffs());
933  }
934  return true;
935}
936
937bool bigintmat::addrow(int i, int j, number a, coeffs c)
938{
939  if ((i>row) || (j>row) || (i<1) || (j<1)) {
940    Werror("Error in addrow: Index out of range!");
941    return false;
942  }
943  if (!nCoeffs_are_equal(c, basecoeffs())) {
944    Werror("Error in addrow: coeffs do not agree!");
945    return false;
946  }
947  number t1, t2, t3, t4;
948  for (int k=1; k<=col; k++)
949  {
950    t1 = view(j, k);
951    t2 = view(i, k);
952    t3 = n_Mult(t1, a, basecoeffs());
953    t4 = n_Add(t3, t2, basecoeffs());
954    rawset(i, k, t4);
955    n_Delete(&t3, basecoeffs());
956  }
957  return true;
958}
959
960void bigintmat::colskalmult(int i, number a, coeffs c) {
961  if ((i>=1) && (i<=col) && (nCoeffs_are_equal(c, basecoeffs()))) {
962    number t, tmult;
963    for (int j=1; j<=row; j++) {
964      t = view(j, i);
965      tmult = n_Mult(a, t, basecoeffs());
966      rawset(j, i, tmult);
967    }
968  }
969  else
970    Werror("Error in colskalmult");
971}
972
973void bigintmat::rowskalmult(int i, number a, coeffs c) {
974  if ((i>=1) && (i<=row) && (nCoeffs_are_equal(c, basecoeffs()))) {
975    number t, tmult;
976    for (int j=1; j<=col; j++) {
977      t = view(i, j);
978      tmult = n_Mult(a, t, basecoeffs());
979      rawset(i, j, tmult);
980    }
981  }
982  else
983    Werror("Error in rowskalmult");
984}
985
986void bigintmat::concatrow(bigintmat *a, bigintmat *b) {
987  int ay = a->cols();
988  int ax = a->rows();
989  int by = b->cols();
990  int bx = b->rows();
991  number tmp;
992  if (!((col == ay) && (col == by) && (ax+bx == row))) {
993    Werror("Error in concatrow. Dimensions must agree!");
994    return;
995  }
996  if (!(nCoeffs_are_equal(a->basecoeffs(), basecoeffs()) && nCoeffs_are_equal(b->basecoeffs(), basecoeffs()))) {
997    Werror("Error in concatrow. coeffs do not agree!");
998    return;
999  }
1000  for (int i=1; i<=ax; i++) {
1001    for (int j=1; j<=ay; j++) {
1002      tmp = a->get(i,j);
1003      set(i, j, tmp);
1004      n_Delete(&tmp, basecoeffs());
1005    }
1006  }
1007  for (int i=1; i<=bx; i++) {
1008    for (int j=1; j<=by; j++) {
1009      tmp = b->get(i,j);
1010      set(i+ax, j, tmp);
1011      n_Delete(&tmp, basecoeffs());
1012    }
1013  }
1014}
1015
1016void bigintmat::extendCols(int i) {
1017  bigintmat * tmp = new bigintmat(rows(), i, basecoeffs());
1018  appendCol(tmp);
1019  delete tmp;
1020}
1021void bigintmat::appendCol (bigintmat *a) {
1022  coeffs R = basecoeffs();
1023  int ay = a->cols();
1024  int ax = a->rows();
1025  assume(row == ax);
1026
1027  assume(nCoeffs_are_equal(a->basecoeffs(), R));
1028
1029  bigintmat * tmp = new bigintmat(rows(), cols() + ay, R);
1030  tmp->concatcol(this, a);
1031  this->swapMatrix(tmp);
1032  delete tmp;
1033}
1034
1035
1036void bigintmat::concatcol (bigintmat *a, bigintmat *b) {
1037  int ay = a->cols();
1038  int ax = a->rows();
1039  int by = b->cols();
1040  int bx = b->rows();
1041  number tmp;
1042
1043  assume(row==ax && row == bx && ay+by ==col);
1044
1045  assume(nCoeffs_are_equal(a->basecoeffs(), basecoeffs()) && nCoeffs_are_equal(b->basecoeffs(), basecoeffs()));
1046
1047  for (int i=1; i<=ax; i++) {
1048    for (int j=1; j<=ay; j++) {
1049      tmp = a->view(i,j);
1050      set(i, j, tmp);
1051    }
1052  }
1053  for (int i=1; i<=bx; i++) {
1054    for (int j=1; j<=by; j++) {
1055      tmp = b->view(i,j);
1056      set(i, j+ay, tmp);
1057    }
1058  }
1059}
1060
1061void bigintmat::splitrow(bigintmat *a, bigintmat *b) {
1062  int ay = a->cols();
1063  int ax = a->rows();
1064  int by = b->cols();
1065  int bx = b->rows();
1066  number tmp;
1067  if (!(ax + bx == row)) {
1068    Werror("Error in splitrow. Dimensions must agree!");
1069  }
1070  else if (!((col == ay) && (col == by))) {
1071    Werror("Error in splitrow. Dimensions must agree!");
1072  }
1073  else if (!(nCoeffs_are_equal(a->basecoeffs(), basecoeffs()) && nCoeffs_are_equal(b->basecoeffs(), basecoeffs()))) {
1074    Werror("Error in splitrow. coeffs do not agree!");
1075  }
1076  else {
1077    for(int i = 1; i<=ax; i++) {
1078      for(int j = 1; j<=ay;j++) {
1079        tmp = get(i,j);
1080        a->set(i,j,tmp);
1081        n_Delete(&tmp, basecoeffs());
1082      }
1083    }
1084    for (int i =1; i<=bx; i++) {
1085      for (int j=1;j<=col;j++) {
1086        tmp = get(i+ax, j);
1087        b->set(i,j,tmp);
1088        n_Delete(&tmp, basecoeffs());
1089      }
1090    }
1091  }
1092}
1093
1094void bigintmat::splitcol(bigintmat *a, bigintmat *b) {
1095  int ay = a->cols();
1096  int ax = a->rows();
1097  int by = b->cols();
1098  int bx = b->rows();
1099  number tmp;
1100  if (!((row == ax) && (row == bx))) {
1101    Werror("Error in splitcol. Dimensions must agree!");
1102  }
1103  else if (!(ay+by == col)) {
1104    Werror("Error in splitcol. Dimensions must agree!");
1105  }
1106  else if (!(nCoeffs_are_equal(a->basecoeffs(), basecoeffs()) && nCoeffs_are_equal(b->basecoeffs(), basecoeffs()))) {
1107    Werror("Error in splitcol. coeffs do not agree!");
1108  }
1109  else {
1110    for (int i=1; i<=ax; i++) {
1111      for (int j=1; j<=ay; j++) {
1112        tmp = view(i,j);
1113        a->set(i,j,tmp);
1114      }
1115    }
1116    for (int i=1; i<=bx; i++) {
1117      for (int j=1; j<=by; j++) {
1118        tmp = view(i,j+ay);
1119        b->set(i,j,tmp);
1120      }
1121    }
1122  }
1123}
1124
1125void bigintmat::splitcol(bigintmat *a, int i) {
1126  number tmp;
1127  if ((a->rows() != row) || (a->cols()+i-1 > col) || (i<1)) {
1128    Werror("Error in splitcol. Dimensions must agree!");
1129    return;
1130  }
1131  if (!(nCoeffs_are_equal(a->basecoeffs(), basecoeffs()))) {
1132    Werror("Error in splitcol. coeffs do not agree!");
1133    return;
1134  }
1135  int width = a->cols();
1136  for (int j=1; j<=width; j++) {
1137    for (int k=1; k<=row; k++) {
1138      tmp = get(k, j+i-1);
1139      a->set(k, j, tmp);
1140      n_Delete(&tmp, basecoeffs());
1141    }
1142  }
1143}
1144
1145void bigintmat::splitrow(bigintmat *a, int i) {
1146  number tmp;
1147  if ((a->cols() != col) || (a->rows()+i-1 > row) || (i<1)) {
1148    Werror("Error in Marco-splitrow");
1149    return;
1150  }
1151
1152  if (!(nCoeffs_are_equal(a->basecoeffs(), basecoeffs()))) {
1153    Werror("Error in splitrow. coeffs do not agree!");
1154    return;
1155  }
1156  int height = a->rows();
1157  for (int j=1; j<=height; j++) {
1158    for (int k=1; k<=col; k++) {
1159      tmp = view(j+i-1, k);
1160      a->set(j, k, tmp);
1161    }
1162  }
1163}
1164
1165bool bigintmat::copy(bigintmat *b)
1166{
1167  if ((b->rows() != row) || (b->cols() != col)) {
1168    Werror("Error in bigintmat::copy. Dimensions do not agree!");
1169    return false;
1170  }
1171  if (!nCoeffs_are_equal(basecoeffs(), b->basecoeffs())) {
1172    Werror("Error in bigintmat::copy. coeffs do not agree!");
1173    return false;
1174  }
1175  number t1;
1176  for (int i=1; i<=row; i++)
1177  {
1178    for (int j=1; j<=col; j++)
1179    {
1180      t1 = b->view(i, j);
1181      set(i, j, t1);
1182    }
1183  }
1184  return true;
1185}
1186
1187// copy the submatrix of b, staring at (a,b) having n rows, m cols into
1188// the given matrix at pos. (c,d)
1189// needs c+n, d+m <= rows, cols
1190//       a+n, b+m <= b.rows(), b.cols()
1191void bigintmat::copySubmatInto(bigintmat *B, int a, int b, int n, int m, int c, int d)
1192{
1193  number t1;
1194  for (int i=1; i<=n; i++)
1195  {
1196    for (int j=1; j<=m; j++)
1197    {
1198      t1 = B->view(a+i-1, b+j-1);
1199      set(c+i-1, d+j-1, t1);
1200    }
1201  }
1202}
1203
1204
1205int bigintmat::isOne() {
1206  coeffs r = basecoeffs();
1207  if (row==col) {
1208    for (int i=1; i<=row; i++) {
1209      for (int j=1; j<=col; j++) {
1210        if (i==j) {
1211          if (!n_IsOne(view(i, j), r))
1212            return 0;
1213        }
1214        else {
1215          if (!n_IsZero(view(i,j), r))
1216            return 0;
1217        }
1218      }
1219    }
1220  }
1221  return 1;
1222}
1223
1224
1225void bigintmat::one() {
1226  if (row==col) {
1227    number one = n_Init(1, basecoeffs()),
1228           zero = n_Init(0, basecoeffs());
1229    for (int i=1; i<=row; i++) {
1230      for (int j=1; j<=col; j++) {
1231        if (i==j) {
1232          set(i, j, one);
1233        } else {
1234          set(i, j, zero);
1235        }
1236      }
1237    }
1238    n_Delete(&one, basecoeffs());
1239    n_Delete(&zero, basecoeffs());
1240  }
1241}
1242
1243void bigintmat::zero() {
1244  number tmp = n_Init(0, basecoeffs());
1245  for (int i=1; i<=row; i++) {
1246    for (int j=1; j<=col; j++) {
1247      set(i, j, tmp);
1248    }
1249  }
1250  n_Delete(&tmp,basecoeffs());
1251}
1252
1253int bigintmat::isZero() {
1254  for (int i=1; i<=row; i++) {
1255    for (int j=1; j<=col; j++) {
1256      if (!n_IsZero(view(i,j), basecoeffs()))
1257        return FALSE;
1258    }
1259  }
1260  return TRUE;
1261}
1262//****************************************************************************
1263//
1264//****************************************************************************
1265
1266//used in the det function. No idea what it does.
1267//looks like it return the submatrix where the i-th row
1268//and j-th column has been removed in the LaPlace generic
1269//determinant algorithm
1270bigintmat *bigintmat::elim(int i, int j)
1271{
1272  if ((i<=0) || (i>row) || (j<=0) || (j>col))
1273    return NULL;
1274  int cx, cy;
1275  cx=1;
1276  cy=1;
1277  number t;
1278  bigintmat *b = new bigintmat(row-1, col-1, basecoeffs());
1279  for (int k=1; k<=row; k++) {
1280    if (k!=i)
1281    {
1282      cy=1;
1283      for (int l=1; l<=col; l++)
1284      {
1285        if (l!=j)
1286        {
1287          t = get(k, l);
1288          b->set(cx, cy, t);
1289          n_Delete(&t, basecoeffs());
1290          cy++;
1291        }
1292      }
1293      cx++;
1294    }
1295  }
1296  return b;
1297}
1298
1299
1300//returns d such that a/d is the inverse of the input
1301//TODO: make work for p not prime using the euc stuff.
1302//long term: rewrite for Z using p-adic lifting
1303//and Dixon. Possibly even the sparse recent Storjohann stuff
1304number bigintmat::pseudoinv(bigintmat *a) {
1305
1306  // Falls Matrix ÃŒber reellen Zahlen nicht invertierbar, breche ab
1307 assume((a->rows() == row) && (a->rows() == a->cols()) && (row == col));
1308
1309 number det = this->det(); //computes the HNF, so should e reused.
1310 if ((n_IsZero(det, basecoeffs())))
1311    return det;
1312
1313 // HÀnge Einheitsmatrix ÃŒber Matrix und wendet HNF an. An Stelle der Einheitsmatrix steht im Ergebnis die Transformationsmatrix dazu
1314  a->one();
1315  bigintmat *m = new bigintmat(2*row, col, basecoeffs());
1316  m->concatrow(a,this);
1317  m->hnf();
1318  // Arbeite weiterhin mit der zusammengehÀngten Matrix
1319  // Laufe durch die Diagonalelemente, und multipliziere jede Spalte rechts davon damit, speichere aber den alten Eintrag der Spalte, temp, der in der Zeile des Diagonalelements liegt, zwischen. Dann addiere das -temp-Fache der Diagonalspalte zur entsprechenenden Spalte rechts davon. Dadurch entsteht ÃŒberall rechts der Diagonalen eine 0
1320  number diag;
1321  number temp, ttemp;
1322  for (int i=1; i<=col; i++) {
1323    diag = m->get(row+i, i);
1324    for (int j=i+1; j<=col; j++) {
1325      temp = m->get(row+i, j);
1326      m->colskalmult(j, diag, basecoeffs());
1327      temp = n_InpNeg(temp, basecoeffs());
1328      m->addcol(j, i, temp, basecoeffs());
1329      n_Delete(&temp, basecoeffs());
1330    }
1331    n_Delete(&diag, basecoeffs());
1332  }
1333  // Falls wir nicht modulo n arbeiten, können wir die Spalten durch den ggT teilen, um die EintrÀge kleiner zu bekommen
1334  // Bei Z/n sparen wir uns das, da es hier sinnlos ist
1335  number g;
1336  number gcd;
1337  for (int j=1; j<=col; j++) {
1338    g = n_Init(0, basecoeffs());
1339    for (int i=1; i<=2*row; i++) {
1340      temp = m->get(i,j);
1341      gcd = n_Gcd(g, temp, basecoeffs());
1342      n_Delete(&g, basecoeffs());
1343      n_Delete(&temp, basecoeffs());
1344      g = n_Copy(gcd, basecoeffs());
1345      n_Delete(&gcd, basecoeffs());
1346    }
1347    if (!(n_IsOne(g, basecoeffs())))
1348      m->colskaldiv(j, g);
1349    n_Delete(&g, basecoeffs());
1350  }
1351
1352  // Nun mÃŒssen die Diagonalelemente durch Spaltenmultiplikation gleich gesett werden. Bei Z können wir mit dem kgV arbeiten, bei Z/n bringen wir jedes Diagonalelement auf 1 (wir arbeiten immer mit n = Primzahl. FÃŒr n != Primzahl muss noch an anderen Stellen etwas geÀndert werden)
1353
1354  g = n_Init(0, basecoeffs());
1355  number prod = n_Init(1, basecoeffs());
1356  for (int i=1; i<=col; i++) {
1357    gcd = n_Gcd(g, m->get(row+i, i), basecoeffs());
1358    n_Delete(&g, basecoeffs());
1359    g = n_Copy(gcd, basecoeffs());
1360    n_Delete(&gcd, basecoeffs());
1361    ttemp = n_Copy(prod, basecoeffs());
1362    temp = m->get(row+i, i);
1363    n_Delete(&prod, basecoeffs());
1364    prod = n_Mult(ttemp, temp, basecoeffs());
1365    n_Delete(&ttemp, basecoeffs());
1366    n_Delete(&temp, basecoeffs());
1367  }
1368  number lcm;
1369  lcm = n_Div(prod, g, basecoeffs());
1370  for (int j=1; j<=col; j++) {
1371    ttemp = m->get(row+j,j);
1372    temp = n_QuotRem(lcm, ttemp, NULL, basecoeffs());
1373    m->colskalmult(j, temp, basecoeffs());
1374    n_Delete(&ttemp, basecoeffs());
1375    n_Delete(&temp, basecoeffs());
1376  }
1377  n_Delete(&lcm, basecoeffs());
1378  n_Delete(&prod, basecoeffs());
1379
1380  number divisor = m->get(row+1, 1);
1381  m->splitrow(a, 1);
1382  delete m;
1383  n_Delete(&det, basecoeffs());
1384  return divisor;
1385}
1386
1387number bigintmat::trace()
1388{
1389  assume (col == row);
1390  number t = get(1,1),
1391         h;
1392  coeffs r = basecoeffs();
1393  for(int i=2; i<= col; i++) {
1394    h = n_Add(t, view(i,i), r);
1395    n_Delete(&t, r);
1396    t = h;
1397  }
1398  return t;
1399}
1400
1401number bigintmat::det()
1402{
1403  assume (row==col);
1404
1405  if (col == 1)
1406    return get(1, 1);
1407  // should work as well in Z/pZ of type n_Zp?
1408  // relies on XExtGcd and the other euc. functinos.
1409  if ( getCoeffType(basecoeffs())== n_Z || getCoeffType(basecoeffs() )== n_Zn) {
1410    return hnfdet();
1411  }
1412  number sum = n_Init(0, basecoeffs());
1413  number t1, t2, t3, t4;
1414  bigintmat *b;
1415  for (int i=1; i<=row; i++) {
1416    b = elim(i, 1);
1417    t1 = get(i, 1);
1418    t2 = b->det();
1419    t3 = n_Mult(t1, t2, basecoeffs());
1420    t4 = n_Copy(sum, basecoeffs());
1421    n_Delete(&sum, basecoeffs());
1422    if ((i+1)>>1<<1==(i+1))
1423      sum = n_Add(t4, t3, basecoeffs());
1424    else
1425      sum = n_Sub(t4, t3, basecoeffs());
1426    n_Delete(&t1, basecoeffs());
1427    n_Delete(&t2, basecoeffs());
1428    n_Delete(&t3, basecoeffs());
1429    n_Delete(&t4, basecoeffs());
1430  }
1431  return sum;
1432}
1433
1434number bigintmat::hnfdet()
1435{
1436  assume (col == row);
1437
1438  if (col == 1)
1439    return get(1, 1);
1440  bigintmat *m = new bigintmat(this);
1441  m->hnf();
1442  number prod = n_Init(1, basecoeffs());
1443  number temp, temp2;
1444  for (int i=1; i<=col; i++) {
1445    temp = m->get(i, i);
1446    temp2 = n_Mult(temp, prod, basecoeffs());
1447    n_Delete(&prod, basecoeffs());
1448    prod = temp2;
1449    n_Delete(&temp, basecoeffs());
1450  }
1451  delete m;
1452  return prod;
1453}
1454
1455void bigintmat::swapMatrix(bigintmat *a)
1456{
1457  int n = rows(), m = cols();
1458  row = a->rows();
1459  col = a->cols();
1460  number * V = v;
1461  v = a->v;
1462  a->v = V;
1463  a->row = n;
1464  a->col = m;
1465}
1466int bigintmat::colIsZero(int j)
1467{
1468  coeffs R = basecoeffs();
1469  for(int i=1; i<=rows(); i++)
1470    if (!n_IsZero(view(i, j), R)) return FALSE;
1471  return TRUE;
1472}
1473
1474void bigintmat::howell()
1475{
1476  coeffs R = basecoeffs();
1477  hnf(); // as a starting point...
1478  if (getCoeffType(R)== n_Z) return; //wrong, need to prune!
1479
1480  int n = cols(), m = rows(), i, j, k;
1481
1482  //make sure, the matrix has enough space. We need no rows+1 columns.
1483  //The resulting Howell form will be pruned to be at most square.
1484  bigintmat * t = new bigintmat(m, m+1, R);
1485  t->copySubmatInto(this, 1, n>m ? n-m+1 : 1, m, n>m ? m : n, 1, n>m ? 2 : m+2-);
1486  swapMatrix(t);
1487  delete t;
1488  for(i=1; i<= cols(); i++) {
1489    if (!colIsZero(i)) break;
1490  }
1491  assume (i>1);
1492  if (i>cols()) {
1493    t = new bigintmat(rows(), 0, R);
1494    swapMatrix(t);
1495    delete t;
1496    return; // zero matrix found, clearly normal.
1497  }
1498
1499  int last_zero_col = i-1;
1500  for (int c = cols(); c>0; c--) {
1501    for(i=rows(); i>0; i--) {
1502      if (!n_IsZero(view(i, c), R)) break;
1503    }
1504    if (i==0) break; // matrix SHOULD be zero from here on
1505    number a = n_Ann(view(i, c), R);
1506    addcol(last_zero_col, c, a, R);
1507    n_Delete(&a, R);
1508    for(j = c-1; j>last_zero_col; j--) {
1509      for(k=rows(); k>0; k--) {
1510        if (!n_IsZero(view(k, j), R)) break;
1511        if (!n_IsZero(view(k, last_zero_col), R)) break;
1512      }
1513      if (k==0) break;
1514      if (!n_IsZero(view(k, last_zero_col), R)) {
1515        number gcd, co1, co2, co3, co4;
1516        gcd = n_XExtGcd(view(k, last_zero_col), view(k, j), &co1, &co2, &co3, &co4, R);
1517        if (n_Equal(gcd, view(k, j), R)) {
1518          number q = n_Div(view(k, last_zero_col), gcd, R);
1519          q = n_InpNeg(q, R);
1520          addcol(last_zero_col, j, q, R);
1521          n_Delete(&q, R);
1522        } else if (n_Equal(gcd, view(k, last_zero_col), R)) {
1523          swap(last_zero_col, k);
1524          number q = n_Div(view(k, last_zero_col), gcd, R);
1525          q = n_InpNeg(q, R);
1526          addcol(last_zero_col, j, q, R);
1527          n_Delete(&q, R);
1528        } else {
1529          coltransform(last_zero_col, j, co3, co4, co1, co2);
1530        }
1531        n_Delete(&gcd, R);
1532        n_Delete(&co1, R);
1533        n_Delete(&co2, R);
1534        n_Delete(&co3, R);
1535        n_Delete(&co4, R);
1536      }
1537    }
1538    for(k=rows(); k>0; k--) {
1539      if (!n_IsZero(view(k, last_zero_col), R)) break;
1540    }
1541    if (k) last_zero_col--;
1542  }
1543  t = new bigintmat(rows(), cols()-last_zero_col, R);
1544  t->copySubmatInto(this, 1, last_zero_col+1, rows(), cols()-last_zero_col, 1, 1);
1545  swapMatrix(t);
1546  delete t;
1547}
1548
1549void bigintmat::hnf()
1550{
1551  // Laufen von unten nach oben und von links nach rechts
1552  // CF: TODO: for n_Z: write a recursive version. This one will
1553  //     have exponential blow-up. Look at Michianchio
1554  //     Alternatively, do p-adic det and modular method
1555
1556#if 0
1557    char * s;
1558    ::Print("mat over Z is \n");
1559    ::Print("%s\n", s = basecoeffs()->cfCoeffString(basecoeffs()));
1560    omFree(s);
1561    Print();
1562    ::Print("\n(%d x %d)\n", rows(), cols());
1563#endif
1564
1565  int i = rows();
1566  int j = cols();
1567  number q = n_Init(0, basecoeffs());
1568  number one = n_Init(1, basecoeffs());
1569  number minusone = n_Init(-1, basecoeffs());
1570  number tmp1 = n_Init(0, basecoeffs());
1571  number tmp2 = n_Init(0, basecoeffs());
1572  number co1, co2, co3, co4;
1573  number ggt = n_Init(0, basecoeffs());
1574
1575  while ((i>0) && (j>0)) {
1576    // Falls erstes Nicht-Null-Element in Zeile i nicht existiert, oder hinter Spalte j vorkommt, gehe in nÀchste Zeile
1577    if ((findnonzero(i)==0) || (findnonzero(i)>j)) {
1578      i--;
1579    } else {
1580      // Laufe von links nach rechts durch die Zeile:
1581      for (int l=1; l<=j-1; l++) {
1582        n_Delete(&tmp1, basecoeffs());
1583        tmp1 = get(i, l);
1584        // Falls Eintrag (im folgenden x genannt) gleich 0, gehe eine Spalte weiter. Ansonsten...
1585        if (!n_IsZero(tmp1, basecoeffs())) {
1586          n_Delete(&tmp2, basecoeffs());
1587          tmp2 = get(i, l+1);
1588          // Falls Eintrag (i.f. y g.) rechts daneben gleich 0, tausche beide Spalten, sonst...
1589          if (!n_IsZero(tmp2, basecoeffs())) {
1590            n_Delete(&ggt, basecoeffs());
1591            ggt = n_XExtGcd(tmp1, tmp2, &co1, &co2, &co3, &co4, basecoeffs());
1592            // Falls x=ggT(x, y), tausche die beiden Spalten und ziehe die (neue) rechte Spalte so hÀufig von der linken ab, dass an der ehemaligen Stelle von x nun eine 0 steht. Dazu:
1593            if (n_Equal(tmp1, ggt, basecoeffs())) {
1594              swap(l, l+1);
1595              n_Delete(&q, basecoeffs());
1596              q = n_Div(tmp2, ggt, basecoeffs());
1597              q = n_InpNeg(q, basecoeffs());
1598              // Dann addiere das -q-fache der (neuen) rechten Spalte zur linken dazu. Damit erhalten wir die gewÃŒnschte 0
1599
1600              addcol(l, l+1, q, basecoeffs());
1601              n_Delete(&q, basecoeffs());
1602            }
1603            else if (n_Equal(tmp1, minusone, basecoeffs())) {
1604              // Falls x=-1, so ist x=-ggt(x, y). Dann gehe wie oben vor, multipliziere aber zuerst die neue rechte Spalte (die mit x) mit -1
1605              // Die Berechnung von q (=y/ggt) entfÀllt, da ggt=1
1606              swap(l, l+1);
1607              colskalmult(l+1, minusone, basecoeffs());
1608              tmp2 = n_InpNeg(tmp2, basecoeffs());
1609              addcol(l, l+1, tmp2, basecoeffs());
1610            }
1611            else {
1612              // CF: use the 2x2 matrix (co1, co2)(co3, co4) to
1613              // get the gcd in position and the 0 in the other:
1614#ifdef CF_DEB
1615              ::Print("applying trafo\n");
1616              StringSetS("");
1617              n_Write(co1, basecoeffs()); StringAppendS("\t");
1618              n_Write(co2, basecoeffs()); StringAppendS("\t");
1619              n_Write(co3, basecoeffs()); StringAppendS("\t");
1620              n_Write(co4, basecoeffs()); StringAppendS("\t");
1621              ::Print("%s\nfor l=%d\n", StringEndS(), l);
1622              {char * s = String();
1623              ::Print("to %s\n", s);omFree(s);};
1624#endif
1625              coltransform(l, l+1, co3, co4, co1, co2);
1626#ifdef CF_DEB
1627              {char * s = String();
1628              ::Print("gives %s\n", s);}
1629#endif
1630            }
1631            n_Delete(&co1, basecoeffs());
1632            n_Delete(&co2, basecoeffs());
1633            n_Delete(&co3, basecoeffs());
1634            n_Delete(&co4, basecoeffs());
1635          }
1636          else {
1637            swap(l, l+1);
1638          }
1639          // Dann betrachte die vormals rechte Spalte als neue linke, und die rechts daneben als neue rechte.
1640        }
1641      }
1642
1643      // normalize by units:
1644      if (!n_IsZero(view(i, j), basecoeffs())) {
1645        number u = n_GetUnit(view(i, j), basecoeffs());
1646        if (!n_IsOne(u, basecoeffs())) {
1647          colskaldiv(j, u);
1648        }
1649        n_Delete(&u, basecoeffs());
1650      }
1651      // Zum Schluss mache alle EintrÀge rechts vom Diagonalelement betragsmÀßig kleiner als dieses
1652      for (int l=j+1; l<=col; l++) {
1653        n_Delete(&q, basecoeffs());
1654        q = n_QuotRem(view(i, l), view(i, j), NULL, basecoeffs());
1655        q = n_InpNeg(q, basecoeffs());
1656        addcol(l, j, q, basecoeffs());
1657      }
1658      i--;
1659      j--;
1660      // Dann betrachte die Zeile darÃŒber und gehe dort wie vorher vor
1661    }
1662  }
1663  n_Delete(&q, basecoeffs());
1664  n_Delete(&tmp1, basecoeffs());
1665  n_Delete(&tmp2, basecoeffs());
1666  n_Delete(&ggt, basecoeffs());
1667  n_Delete(&one, basecoeffs());
1668  n_Delete(&minusone, basecoeffs());
1669
1670#if 0
1671    ::Print("hnf over Z is \n");
1672    Print();
1673    ::Print("\n(%d x %d)\n", rows(), cols());
1674#endif
1675}
1676
1677bigintmat * bimChangeCoeff(bigintmat *a, coeffs cnew)
1678{
1679  coeffs cold = a->basecoeffs();
1680  bigintmat *b = new bigintmat(a->rows(), a->cols(), cnew);
1681  // Erzeugt Karte von alten coeffs nach neuen
1682  nMapFunc f = n_SetMap(cold, cnew);
1683  number t1;
1684  number t2;
1685  // apply map to all entries.
1686  for (int i=1; i<=a->rows(); i++)
1687  {
1688    for (int j=1; j<=a->cols(); j++)
1689    {
1690      t1 = a->get(i, j);
1691      t2 = f(t1, cold, cnew);
1692      b->set(i, j, t2);
1693      n_Delete(&t1, cold);
1694      n_Delete(&t2, cnew);
1695    }
1696  }
1697  return b;
1698}
1699
1700//OK: a HNF of (this | p*I)
1701//so the result will always have FULL rank!!!!
1702//(This is different form a lift of the HNF mod p: consider the matrix (p)
1703//to see the difference. It CAN be computed as HNF mod p^2 usually..)
1704bigintmat * bigintmat::modhnf(number p, coeffs R)
1705{
1706  coeffs Rp = numbercoeffs(p, R); // R/pR
1707  bigintmat *m = bimChangeCoeff(this, Rp);
1708  m->howell();
1709  bigintmat *a = bimChangeCoeff(m, R);
1710  delete m;
1711  bigintmat *C = new bigintmat(rows(), rows(), R);
1712  int piv = rows(), i = a->cols();
1713  while (piv) {
1714    if (!i || n_IsZero(a->view(piv, i), R)) {
1715      C->set(piv, piv, p, R);
1716    } else {
1717      C->copySubmatInto(a, 1, i, rows(), 1, 1, piv);
1718      i--;
1719    }
1720    piv--;
1721  }
1722  delete a;
1723  return C;
1724}
1725
1726
1727//exactly divide matrix by b
1728void bigintmat::skaldiv(number b)
1729{
1730  number tmp1, tmp2;
1731  for (int i=1; i<=row; i++)
1732  {
1733    for (int j=1; j<=col; j++)
1734    {
1735      tmp1 = view(i, j);
1736      tmp2 = n_Div(tmp1, b, basecoeffs());
1737      rawset(i, j, tmp2);
1738    }
1739  }
1740}
1741
1742//exactly divide col j by b
1743void bigintmat::colskaldiv(int j, number b)
1744{
1745  number tmp1, tmp2;
1746  for (int i=1; i<=row; i++)
1747  {
1748    tmp1 = view(i, j);
1749    tmp2 = n_Div(tmp1, b, basecoeffs());
1750    rawset(i, j, tmp2);
1751  }
1752}
1753
1754// col(j, k) <- col(j,k)*matrix((a, c)(b, d))
1755// mostly used internally in the hnf and Howell stuff
1756void bigintmat::coltransform(int j, int k, number a, number b, number c, number d)
1757{
1758  number tmp1, tmp2, tmp3, tmp4;
1759  for (int i=1; i<=row; i++)
1760  {
1761    tmp1 = get(i, j);
1762    tmp2 = get(i, k);
1763    tmp3 = n_Mult(tmp1, a, basecoeffs());
1764    tmp4 = n_Mult(tmp2, b, basecoeffs());
1765    n_InpAdd(tmp3, tmp4, basecoeffs());
1766    n_Delete(&tmp4, basecoeffs());
1767
1768    n_InpMult(tmp1, c, basecoeffs());
1769    n_InpMult(tmp2, d, basecoeffs());
1770    n_InpAdd(tmp1, tmp2, basecoeffs());
1771    n_Delete(&tmp2, basecoeffs());
1772
1773    set(i, j, tmp3);
1774    set(i, k, tmp1);
1775    n_Delete(&tmp1, basecoeffs());
1776    n_Delete(&tmp3, basecoeffs());
1777  }
1778}
1779
1780
1781
1782//reduce all entries mod p. Does NOT change the coeffs type
1783void bigintmat::mod(number p, coeffs c)
1784{
1785  // produce the matrix in Z/pZ
1786  // CF: TODO rewrite using QuotRem and not the map
1787  coeffs coe = numbercoeffs(p, c);
1788  nMapFunc f1 = n_SetMap(basecoeffs(), coe);
1789  nMapFunc f2 = n_SetMap(coe, basecoeffs());
1790  number tmp1, tmp2;
1791  for (int i=1; i<=row; i++)
1792  {
1793    for (int j=1; j<=col; j++)
1794    {
1795      tmp1 = get(i, j);
1796      tmp2 = f1(tmp1, basecoeffs(), coe);
1797      n_Delete(&tmp1, basecoeffs());
1798      tmp1 = f2(tmp2, coe, basecoeffs());
1799      set(i, j, tmp1);
1800      n_Delete(&tmp1, basecoeffs());
1801      n_Delete(&tmp2, coe);
1802    }
1803  }
1804  nKillChar(coe);
1805}
1806
1807void bimMult(bigintmat *a, bigintmat *b, bigintmat *c)
1808{
1809  if (!nCoeffs_are_equal(a->basecoeffs(), b->basecoeffs())) {
1810    Werror("Error in bimMult. Coeffs do not agree!");
1811    return;
1812  }
1813  if ((a->rows() != c->rows()) || (b->cols() != c->cols()) || (a->cols() != b->rows())) {
1814    Werror("Error in bimMult. Dimensions do not agree!");
1815    return;
1816  }
1817  bigintmat *tmp = bimMult(a, b);
1818  c->copy(tmp);
1819
1820  delete tmp;
1821}
1822
1823static void reduce_mod_howell(bigintmat *A, bigintmat *b, bigintmat * eps, bigintmat *x) {
1824  //write b = Ax + eps where eps is "small" in the sense of bounded by the
1825  //pivot entries in H. H does not need to be Howell (or HNF) but need
1826  //to be triagonal in the same direction.
1827  //b can have multiple columns.
1828#if 0
1829  Print("reduce_mod_howell: A:\n");
1830  A->Print();
1831  Print("\nb:\n");
1832  b->Print();
1833#endif
1834
1835  coeffs R = A->basecoeffs();
1836  assume(x->basecoeffs() == R);
1837  assume(b->basecoeffs() == R);
1838  assume(eps->basecoeffs() == R);
1839  if (!A->cols()) {
1840    x->zero();
1841    eps->copy(b);
1842
1843#if 0
1844    Print("\nx:\n");
1845    x->Print();
1846    Print("\neps:\n");
1847    eps->Print();
1848    Print("\n****************************************\n");
1849#endif
1850    return;
1851  }
1852
1853  bigintmat * B = new bigintmat(b->rows(), 1, R);
1854  for(int i=1; i<= b->cols(); i++) {
1855    int A_col = A->cols();
1856    b->getcol(i, B);
1857    for(int j = B->rows(); j>0; j--) {
1858      number Ai = A->view(A->rows() - B->rows() + j, A_col);
1859      if (n_IsZero(Ai, R) &&
1860          n_IsZero(B->view(j, 1), R)) {
1861        continue; //all is fine: 0*x = 0
1862      } else if (n_IsZero(B->view(j, 1), R)) {
1863        x->rawset(x->rows() - B->rows() + j, i, n_Init(0, R));
1864        A_col--;
1865      } else if (n_IsZero(Ai, R)) {
1866        A_col--;
1867      } else {
1868        // "solve" ax=b, possibly enlarging d
1869        number Bj = B->view(j, 1);
1870        number q = n_Div(Bj, Ai, R);
1871        x->rawset(x->rows() - B->rows() + j, i, q);
1872        for(int k=j; k>B->rows() - A->rows(); k--) {
1873          //B[k] = B[k] - x[k]A[k][j]
1874          number s = n_Mult(q, A->view(A->rows() - B->rows() + k, A_col), R);
1875          B->rawset(k, 1, n_Sub(B->view(k, 1), s, R));
1876          n_Delete(&s, R);
1877        }
1878        A_col--;
1879      }
1880      if (!A_col) {
1881        break;
1882      }
1883    }
1884    eps->setcol(i, B);
1885  }
1886  delete B;
1887#if 0
1888  Print("\nx:\n");
1889  x->Print();
1890  Print("\neps:\n");
1891  eps->Print();
1892  Print("\n****************************************\n");
1893#endif
1894}
1895
1896static bigintmat * prependIdentity(bigintmat *A)
1897{
1898  coeffs R = A->basecoeffs();
1899  bigintmat *m = new bigintmat(A->rows()+A->cols(), A->cols(), R);
1900  m->copySubmatInto(A, 1, 1, A->rows(), A->cols(), A->cols()+1, 1);
1901  number one = n_Init(1, R);
1902  for(int i=1; i<= A->cols(); i++)
1903    m->set(i,i,one);
1904  n_Delete(&one, R);
1905  return m;
1906}
1907
1908static number bimFarey(bigintmat *A, number N, bigintmat *L) {
1909  coeffs Z = A->basecoeffs(),
1910         Q = nInitChar(n_Q, 0);
1911  number den = n_Init(1, Z);
1912  nMapFunc f = n_SetMap(Q, Z);
1913
1914  for(int i=1; i<= A->rows(); i++) {
1915    for(int j=1; j<= A->cols(); j++) {
1916      number ad = n_Mult(den, A->view(i, j), Z);
1917      number re = n_IntMod(ad, N, Z);
1918      n_Delete(&ad, Z);
1919      number q = n_Farey(re, N, Z);
1920      n_Delete(&re, Z);
1921      if (!q) {
1922        n_Delete(&ad, Z);
1923        n_Delete(&den, Z);
1924        return NULL;
1925      }
1926
1927      number d = nlGetDenom(q, Q),
1928             n = nlGetNumerator(q, Q);
1929
1930      n_Delete(&q, Q);
1931      n_Delete(&ad, Z);
1932      number dz = f(d, Q, Z),
1933             nz = f(n, Q, Z);
1934      n_Delete(&d, Q);
1935      n_Delete(&n, Q);
1936
1937      if (!n_IsOne(dz, Z)) {
1938        L->skalmult(dz, Z);
1939        n_InpMult(den, dz, Z);
1940#if 0
1941        Print("den increasing to ");
1942        n_Print(den, Z);
1943        Print("\n");
1944#endif
1945      }
1946      n_Delete(&dz, Z);
1947      L->rawset(i, j, nz);
1948    }
1949  }
1950
1951  nKillChar(Q);
1952  Print("bimFarey worked\n");
1953#if 0
1954  L->Print();
1955  Print("\n * 1/");
1956  n_Print(den, Z);
1957  Print("\n");
1958#endif
1959  return den;
1960}
1961
1962static number solveAx_dixon(bigintmat *A, bigintmat *B, bigintmat *x, bigintmat *kern) {
1963  coeffs R = A->basecoeffs();
1964
1965  assume(getCoeffType(R) == n_Z);
1966
1967  number p = n_Init(536870909, R); // PreviousPrime(2^29); not clever
1968  coeffs Rp = numbercoeffs(p, R); // R/pR
1969  bigintmat *Ap = bimChangeCoeff(A, Rp),
1970            *m = prependIdentity(Ap),
1971            *Tp, *Hp;
1972  delete Ap;
1973
1974  m->howell();
1975  Hp = new bigintmat(A->rows(), A->cols(), Rp);
1976  Hp->copySubmatInto(m, A->cols()+1, 1, A->rows(), A->cols(), 1, 1);
1977  Tp = new bigintmat(A->cols(), A->cols(), Rp);
1978  Tp->copySubmatInto(m, 1, 1, A->cols(), A->cols(), 1, 1);
1979
1980  int i, j;
1981
1982  for(i=1; i<= A->cols(); i++) {
1983    for(j=m->rows(); j>A->cols(); j--) {
1984      if (!n_IsZero(m->view(j, i), Rp)) break;
1985    }
1986    if (j>A->cols()) break;
1987  }
1988//  Print("Found nullity (kern dim) of %d\n", i-1);
1989  bigintmat * kp = new bigintmat(A->cols(), i-1, Rp);
1990  kp->copySubmatInto(Tp, 1, 1, A->cols(), i-1, 1, 1);
1991  kp->howell();
1992
1993  delete m;
1994
1995  //Hp is the mod-p howell form
1996  //Tp the transformation, mod p
1997  //kp a basis for the kernel, in howell form, mod p
1998
1999  bigintmat * eps_p = new bigintmat(B->rows(), B->cols(), Rp),
2000            * x_p   = new bigintmat(A->cols(), B->cols(), Rp),
2001            * fps_p = new bigintmat(kp->cols(), B->cols(), Rp);
2002
2003  //initial solution
2004
2005  number zero = n_Init(0, R);
2006  x->skalmult(zero, R);
2007  n_Delete(&zero, R);
2008
2009  bigintmat * b = new bigintmat(B);
2010  number pp = n_Init(1, R);
2011  i = 1;
2012  do {
2013    bigintmat * b_p = bimChangeCoeff(b, Rp), * s;
2014    bigintmat * t1, *t2;
2015    reduce_mod_howell(Hp, b_p, eps_p, x_p);
2016    delete b_p;
2017    if (!eps_p->isZero()) {
2018      Print("no solution, since no modular solution\n");
2019
2020      delete eps_p;
2021      delete x_p;
2022      delete Hp;
2023      delete kp;
2024      delete Tp;
2025      delete b;
2026      n_Delete(&pp, R);
2027      n_Delete(&p, R);
2028      nKillChar(Rp);
2029
2030      return NULL;
2031    }
2032    t1 = bimMult(Tp, x_p);
2033    delete x_p;
2034    x_p = t1;
2035    reduce_mod_howell(kp, x_p, x_p, fps_p);  //we're not all interested in fps_p
2036    s = bimChangeCoeff(x_p, R);
2037    t1 = bimMult(A, s);
2038    t2 = bimSub(b, t1);
2039    t2->skaldiv(p);
2040    delete b;
2041    delete t1;
2042    b = t2;
2043    s->skalmult(pp, R);
2044    t1 = bimAdd(x, s);
2045    delete s;
2046    x->swapMatrix(t1);
2047    delete t1;
2048
2049    if(kern && i==1) {
2050      bigintmat * ker = bimChangeCoeff(kp, R);
2051      t1 = bimMult(A, ker);
2052      t1->skaldiv(p);
2053      t1->skalmult(n_Init(-1, R), R);
2054      b->appendCol(t1);
2055      delete t1;
2056      x->appendCol(ker);
2057      delete ker;
2058      x_p->extendCols(kp->cols());
2059      eps_p->extendCols(kp->cols());
2060      fps_p->extendCols(kp->cols());
2061    }
2062
2063    n_InpMult(pp, p, R);
2064
2065    if (b->isZero()) {
2066      //exact solution found, stop
2067      delete eps_p;
2068      delete fps_p;
2069      delete x_p;
2070      delete Hp;
2071      delete kp;
2072      delete Tp;
2073      delete b;
2074      n_Delete(&pp, R);
2075      n_Delete(&p, R);
2076      nKillChar(Rp);
2077
2078      return n_Init(1, R);
2079    } else {
2080      bigintmat *y = new bigintmat(x->rows(), x->cols(), R);
2081      number d = bimFarey(x, pp, y);
2082      if (d) {
2083        bigintmat *c = bimMult(A, y);
2084        bigintmat *bd = new bigintmat(B);
2085        bd->skalmult(d, R);
2086        if (kern) {
2087          bd->extendCols(kp->cols());
2088        }
2089        if (*c == *bd) {
2090          x->swapMatrix(y);
2091          delete y;
2092          delete c;
2093          if (kern) {
2094            y = new bigintmat(x->rows(), B->cols(), R);
2095            c = new bigintmat(x->rows(), kp->cols(), R);
2096            x->splitcol(y, c);
2097            x->swapMatrix(y);
2098            delete y;
2099            kern->swapMatrix(c);
2100            delete c;
2101          }
2102
2103          delete bd;
2104
2105          delete eps_p;
2106          delete fps_p;
2107          delete x_p;
2108          delete Hp;
2109          delete kp;
2110          delete Tp;
2111          delete b;
2112          n_Delete(&pp, R);
2113          n_Delete(&p, R);
2114          nKillChar(Rp);
2115
2116          return d;
2117        }
2118        delete c;
2119        delete bd;
2120        n_Delete(&d, R);
2121      }
2122      delete y;
2123    }
2124    i++;
2125  } while (1);
2126  delete eps_p;
2127  delete fps_p;
2128  delete x_p;
2129  delete Hp;
2130  delete kp;
2131  delete Tp;
2132  n_Delete(&pp, R);
2133  n_Delete(&p, R);
2134  nKillChar(Rp);
2135  return NULL;
2136}
2137
2138//TODO: re-write using reduce_mod_howell
2139static number solveAx_howell(bigintmat *A, bigintmat *b, bigintmat *x, bigintmat *kern) {
2140  // try to solve Ax=b, more precisely, find
2141  //   number    d
2142  //   bigintmat x
2143  // sth. Ax=db
2144  // where d is small-ish (divides the determinant of A if this makes sense)
2145  // return 0 if there is no solution.
2146  //
2147  // if kern is non-NULL, return a basis for the kernel
2148
2149  //Algo: we do row-howell (triangular matrix). The idea is
2150  //  Ax = b <=>  AT T^-1x = b
2151  //  y := T^-1 x, solve AT y = b
2152  //  and return Ty.
2153  //Howell does not compute the trafo, hence we need to cheat:
2154  //B := (I_n | A^t)^t, then the top part of the Howell form of
2155  //B will give a useful trafo
2156  //Then we can find x by back-substitution and lcm/gcd to find the denominator
2157  //The defining property of Howell makes this work.
2158
2159  coeffs R = A->basecoeffs();
2160  bigintmat *m = prependIdentity(A);
2161  m->howell(); // since m contains the identity, we'll have A->cols()
2162               // many cols.
2163  number den = n_Init(1, R);
2164
2165  bigintmat * B = new bigintmat(A->rows(), 1, R);
2166  for(int i=1; i<= b->cols(); i++) {
2167    int A_col = A->cols();
2168    b->getcol(i, B);
2169    B->skalmult(den, R);
2170    for(int j = B->rows(); j>0; j--) {
2171      number Ai = m->view(m->rows()-B->rows() + j, A_col);
2172      if (n_IsZero(Ai, R) &&
2173          n_IsZero(B->view(j, 1), R)) {
2174        continue; //all is fine: 0*x = 0
2175      } else if (n_IsZero(B->view(j, 1), R)) {
2176        x->rawset(x->rows() - B->rows() + j, i, n_Init(0, R));
2177        A_col--;
2178      } else if (n_IsZero(Ai, R)) {
2179        delete m;
2180        delete B;
2181        n_Delete(&den, R);
2182        return 0;
2183      } else {
2184        // solve ax=db, possibly enlarging d
2185        // so x = db/a
2186        number Bj = B->view(j, 1);
2187        number g = n_Gcd(Bj, Ai, R);
2188        number xi;
2189        if (n_Equal(Ai, g, R)) { //good: den stable!
2190          xi = n_Div(Bj, Ai, R);
2191        } else { //den <- den * (a/g), so old sol. needs to be adjusted
2192          number inc_d = n_Div(Ai, g, R);
2193          n_InpMult(den, inc_d, R);
2194          x->skalmult(inc_d, R);
2195          B->skalmult(inc_d, R);
2196          xi = n_Div(Bj, g, R);
2197          n_Delete(&inc_d, R);
2198        } //now for the back-substitution:
2199        x->rawset(x->rows() - B->rows() + j, i, xi);
2200        for(int k=j; k>0; k--) {
2201          //B[k] = B[k] - x[k]A[k][j]
2202          number s = n_Mult(xi, m->view(m->rows()-B->rows() + k, A_col), R);
2203          B->rawset(k, 1, n_Sub(B->view(k, 1), s, R));
2204          n_Delete(&s, R);
2205        }
2206        n_Delete(&g, R);
2207        A_col--;
2208      }
2209      if (!A_col) {
2210        if (B->isZero()) break;
2211        else {
2212          delete m;
2213          delete B;
2214          n_Delete(&den, R);
2215          return 0;
2216        }
2217      }
2218    }
2219  }
2220  delete B;
2221  bigintmat *T = new bigintmat(A->cols(), A->cols(), R);
2222  T->copySubmatInto(m, 1, 1, A->cols(), A->cols(), 1, 1);
2223  if (kern) {
2224    int i, j;
2225    for(i=1; i<= A->cols(); i++) {
2226      for(j=m->rows(); j>A->cols(); j--) {
2227        if (!n_IsZero(m->view(j, i), R)) break;
2228      }
2229      if (j>A->cols()) break;
2230    }
2231    Print("Found nullity (kern dim) of %d\n", i-1);
2232    bigintmat * ker = new bigintmat(A->rows(), i-1, R);
2233    ker->copySubmatInto(T, 1, 1, A->rows(), i-1, 1, 1);
2234    kern->swapMatrix(ker);
2235    delete ker;
2236  }
2237  delete m;
2238  bigintmat * y = bimMult(T, x);
2239  x->swapMatrix(y);
2240  delete y;
2241  x->simplifyContentDen(&den);
2242#if 0
2243  Print("sol = 1/");
2244  n_Print(den, R);
2245  Print(" *\n");
2246  x->Print();
2247  Print("\n");
2248#endif
2249  return den;
2250}
2251
2252number solveAx(bigintmat *A, bigintmat *b, bigintmat *x) {
2253#if 0
2254  Print("Solve Ax=b for A=\n");
2255  A->Print();
2256  Print("\nb = \n");
2257  b->Print();
2258  Print("\nx = \n");
2259  x->Print();
2260  Print("\n");
2261#endif
2262
2263  coeffs R = A->basecoeffs();
2264  assume (R == b->basecoeffs());
2265  assume (R == x->basecoeffs());
2266  assume ((x->cols() == b->cols()) && (x->rows() == A->cols()) && (A->rows() == b->rows()));
2267
2268  switch (getCoeffType(R)) {
2269    case n_Z:
2270      return solveAx_dixon(A, b, x, NULL);
2271    case n_Zn:
2272    case n_Znm:
2273    case n_Z2m:
2274      return solveAx_howell(A, b, x, NULL);
2275    case n_Zp:
2276    case n_Q:
2277    case n_GF:
2278    case n_algExt:
2279    case n_transExt:
2280      Warn("have field, should use Gauss or better");
2281    default:
2282      if (R->cfXExtGcd && R->cfAnn) { //assume it's Euclidean
2283        return solveAx_howell(A, b, x, NULL);
2284      }
2285      Werror("have no solve algorithm");
2286  }
2287  return NULL;
2288}
2289
2290void diagonalForm(bigintmat *A, bigintmat ** S, bigintmat ** T)
2291{
2292  bigintmat * t, *s, *a=A;
2293  coeffs R = a->basecoeffs();
2294  if (T) {
2295    *T = new bigintmat(a->cols(), a->cols(), R),
2296    (*T)->one();
2297    t = new bigintmat(*T);
2298  } else {
2299    t = *T;
2300  }
2301
2302  if (S) {
2303    *S = new bigintmat(a->rows(), a->rows(), R);
2304    (*S)->one();
2305    s = new bigintmat(*S);
2306  } else {
2307    s = *S;
2308  }
2309
2310  int flip=0;
2311  do {
2312    bigintmat * x, *X;
2313    if (flip) {
2314      x = s;
2315      X = *S;
2316    } else {
2317      x = t;
2318      X = *T;
2319    }
2320
2321    if (x) {
2322      x->one();
2323      bigintmat * r = new bigintmat(a->rows()+a->cols(), a->cols(), R);
2324      bigintmat * rw = new bigintmat(1, a->cols(), R);
2325      for(int i=0; i<a->cols(); i++) {
2326        x->getrow(i+1, rw);
2327        r->setrow(i+1, rw);
2328      }
2329      for (int i=0; i<a->rows(); i++) {
2330        a->getrow(i+1, rw);
2331        r->setrow(i+a->cols()+1, rw);
2332      }
2333      r->hnf();
2334      for(int i=0; i<a->cols(); i++) {
2335        r->getrow(i+1, rw);
2336        x->setrow(i+1, rw);
2337      }
2338      for(int i=0; i<a->rows(); i++) {
2339        r->getrow(i+a->cols()+1, rw);
2340        a->setrow(i+1, rw);
2341      }
2342      delete rw;
2343      delete r;
2344
2345#if 0
2346      Print("X: %ld\n", X);
2347      X->Print();
2348      Print("\nx: %ld\n", x);
2349      x->Print();
2350#endif
2351      bimMult(X, x, X);
2352#if 0
2353      Print("\n2:X: %ld %ld %ld\n", X, *S, *T);
2354      X->Print();
2355      Print("\n2:x: %ld\n", x);
2356      x->Print();
2357      Print("\n");
2358#endif
2359    } else {
2360      a->hnf();
2361    }
2362
2363    int diag = 1;
2364    for(int i=a->rows(); diag && i>0; i--) {
2365      for(int j=a->cols(); j>0; j--) {
2366        if ((a->rows()-i)!=(a->cols()-j) && !n_IsZero(a->view(i, j), R)) {
2367          diag = 0;
2368          break;
2369        }
2370      }
2371    }
2372#if 0
2373    Print("Diag ? %d\n", diag);
2374    a->Print();
2375    Print("\n");
2376#endif
2377    if (diag) break;
2378
2379    a = a->transpose(); // leaks - I need to write inpTranspose
2380    flip = 1-flip;
2381  } while (1);
2382  if (flip)
2383    a = a->transpose();
2384
2385  if (S) *S = (*S)->transpose();
2386  if (s) delete s;
2387  if (t) delete t;
2388  A->copy(a);
2389}
2390
2391//a "q-base" for the kernel of a.
2392//Should be re-done to use Howell rather than smith.
2393//can be done using solveAx now.
2394int kernbase (bigintmat *a, bigintmat *c, number p, coeffs q) {
2395#if 0
2396  Print("Kernel of ");
2397  a->Print();
2398  Print(" modulo ");
2399  n_Print(p, q);
2400  Print("\n");
2401#endif
2402
2403  coeffs coe = numbercoeffs(p, q);
2404  bigintmat *m = bimChangeCoeff(a, coe), *U, *V;
2405  diagonalForm(m, &U, &V);
2406#if 0
2407  Print("\ndiag form: ");
2408  m->Print();
2409  Print("\nU:\n");
2410  U->Print();
2411  Print("\nV:\n");
2412  V->Print();
2413  Print("\n");
2414#endif
2415
2416  int rg = 0;
2417#undef MIN
2418#define MIN(a,b) (a < b ? a : b)
2419  for(rg=0; rg<MIN(m->rows(), m->cols()) && !n_IsZero(m->view(m->rows()-rg,m->cols()-rg), coe); rg++);
2420
2421#undef MAX
2422#define MAX(a,b) (a > b ? a : b)
2423  bigintmat * k = new bigintmat(m->cols(), m->rows(), coe);
2424  for(int i=0; i<rg; i++) {
2425    number A = n_Ann(m->view(m->rows()-i, m->cols()-i), coe);
2426    k->set(m->cols()-i, i+1, A);
2427    n_Delete(&A, coe);
2428  }
2429  for(int i=rg; i<m->cols(); i++) {
2430    k->set(m->cols()-i, i+1-rg, n_Init(1, coe));
2431  }
2432  bimMult(V, k, k);
2433  c->copy(bimChangeCoeff(k, q));
2434  return c->cols();
2435}
2436
2437
2438//create Z/nA of type n_Zn
2439coeffs numbercoeffs(number n, coeffs c) {
2440  mpz_t p;
2441  number2mpz(n, c, p);
2442  ZnmInfo *pp = new ZnmInfo;
2443  pp->base = p;
2444  pp->exp = 1;
2445  coeffs nc = nInitChar(n_Zn, (void*)pp);
2446  mpz_clear(p);
2447  delete pp;
2448  return nc;
2449}
2450
2451bool nCoeffs_are_equal(coeffs r, coeffs s) {
2452  if ((r == NULL) || (s == NULL))
2453    return false;
2454  if ((getCoeffType(r)==n_Z) && (getCoeffType(s)==n_Z))
2455    return true;
2456  if ((getCoeffType(r)==n_Zp) && (getCoeffType(s)==n_Zp)) {
2457    if (r->ch == s->ch)
2458      return true;
2459    else
2460      return false;
2461  }
2462  // n_Zn stimmt wahrscheinlich noch nicht
2463  if ((getCoeffType(r)==n_Zn) && (getCoeffType(s)==n_Zn)) {
2464    if (r->ch == s->ch)
2465      return true;
2466    else
2467      return false;
2468  }
2469  if ((getCoeffType(r)==n_Q) && (getCoeffType(s)==n_Q))
2470    return true;
2471  // FALL n_Zn FEHLT NOCH!
2472    //if ((getCoeffType(r)==n_Zn) && (getCoeffType(s)==n_Zn))
2473  return false;
2474}
2475
2476number bigintmat::content()
2477{
2478  coeffs r = basecoeffs();
2479  number g = get(1,1), h;
2480  int n=rows()*cols();
2481  for(int i=1; i<n && !n_IsOne(g, r); i++) {
2482    h = n_Gcd(g, view(i), r);
2483    n_Delete(&g, r);
2484    g=h;
2485  }
2486  return g;
2487}
2488void bigintmat::simplifyContentDen(number *d)
2489{
2490  coeffs r = basecoeffs();
2491  number g = n_Copy(*d, r), h;
2492  int n=rows()*cols();
2493  for(int i=0; i<n && !n_IsOne(g, r); i++) {
2494    h = n_Gcd(g, view(i), r);
2495    n_Delete(&g, r);
2496    g=h;
2497  }
2498  *d = n_Div(*d, g, r);
2499  if (!n_IsOne(g, r))
2500  skaldiv(g);
2501}
Note: See TracBrowser for help on using the repository browser.