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

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