source: git/Singular/minpoly.cc @ 47a616d

spielwiese
Last change on this file since 47a616d was 47a616d, checked in by Hans Schoenemann <hannes@…>, 13 years ago
fix ssi:tcp close bug git-svn-id: file:///usr/local/Singular/svn/trunk@14352 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 12.7 KB
RevLine 
[2024f6a]1/***********************************************
2 * Copyright (C) 2011 Sebastian Jambor         *
3 * sebastian@momo.math.rwth-aachen.de          *
4 ***********************************************/
5
6
7#include<cmath>
[5b2745]8#include<Singular/mod2.h>
[2024f6a]9
10#include "minpoly.h"
11
12// TODO: avoid code copying, use subclassing instead!
13
[5b2745]14LinearDependencyMatrix::LinearDependencyMatrix (unsigned n, unsigned long p)
15{
16  this->n = n;
17  this->p = p;
18
19  matrix = new unsigned long *[n];
[47a616d]20  for(int i = 0; i < n; i++)
[5b2745]21  {
22    matrix[i] = new unsigned long[2 * n + 1];
23  }
24  pivots = new unsigned[n];
25  tmprow = new unsigned long[2 * n + 1];
26  rows = 0;
[2024f6a]27}
28
[5b2745]29LinearDependencyMatrix::~LinearDependencyMatrix ()
30{
31  delete[]tmprow;
32  delete[]pivots;
[2024f6a]33
[47a616d]34  for(int i = 0; i < n; i++)
[5b2745]35  {
36    delete[](matrix[i]);
37  }
38  delete[]matrix;
[2024f6a]39}
40
[5b2745]41void LinearDependencyMatrix::resetMatrix ()
42{
43  rows = 0;
[2024f6a]44}
45
[5b2745]46int LinearDependencyMatrix::firstNonzeroEntry (unsigned long *row)
47{
[47a616d]48  for(int i = 0; i < n; i++)
[5b2745]49    if(row[i] != 0)
50      return i;
[2024f6a]51
[5b2745]52  return -1;
[2024f6a]53}
54
[5b2745]55void LinearDependencyMatrix::reduceTmpRow ()
56{
[47a616d]57  for(int i = 0; i < rows; i++)
[5b2745]58  {
59    unsigned piv = pivots[i];
60    unsigned long x = tmprow[piv] % p;
61    // if the corresponding entry in the row is zero, there is nothing to do
62    if(x != 0)
63    {
64      // subtract tmprow[i] times the i-th row
[47a616d]65      for(int j = piv; j < n + rows + 1; j++)
[5b2745]66      {
67        unsigned long tmp = matrix[i][j] * x % p;
68        tmp = p - tmp;
69        tmprow[j] += tmp;
70        // We don't normalize here, so remember to do it after all reductions.
71        // tmprow[j] %= p;
72      }
73    }
74  }
75
76  // normalize the entries of tmprow.
[47a616d]77  for(int i = 0; i < n + rows + 1; i++)
[5b2745]78  {
79    tmprow[i] %= p;
80  }
[2024f6a]81}
82
83
[5b2745]84void LinearDependencyMatrix::normalizeTmp (unsigned i)
85{
86  unsigned long inv = modularInverse (tmprow[i], p);
87  tmprow[i] = 1;
[47a616d]88  for(int j = i + 1; j < 2 * n + 1; j++)
[5b2745]89    tmprow[j] = (tmprow[j] * inv) % p;
[2024f6a]90}
[ec9db9]91
[5b2745]92bool LinearDependencyMatrix::findLinearDependency (unsigned long *newRow,
93                                                   unsigned long *dep)
94{
95  // Copy newRow to tmprow (we need to add RHS)
[47a616d]96  for(int i = 0; i < n; i++)
[5b2745]97  {
98    tmprow[i] = newRow[i];
99    tmprow[n + i] = 0;
100  }
101  tmprow[2 * n] = 0;
102  tmprow[n + rows] = 1;
103
104  reduceTmpRow ();
105
106  // Is tmprow reduced to zero? Then we have found a linear dependence.
107  // Otherwise, we just add tmprow to the matrix.
[47a616d]108  unsigned newpivot = firstNonzeroEntry (tmprow);
[5b2745]109  if(newpivot == -1)
110  {
[47a616d]111    for(int i = 0; i <= n; i++)
[5b2745]112    {
113      dep[i] = tmprow[n + i];
114    }
115
116    return true;
117  }
118  else
119  {
120    normalizeTmp (newpivot);
121
[47a616d]122    for(int i = 0; i < 2 * n + 1; i++)
[5b2745]123    {
124      matrix[rows][i] = tmprow[i];
125    }
126
127    pivots[rows] = newpivot;
128    rows++;
129
130    return false;
131  }
[2024f6a]132}
133
[ec9db9]134#if 0
[5b2745]135std::ostream & operator<< (std::ostream & out,
136                           const LinearDependencyMatrix & mat)
137{
138  int width = ((int) log10 (mat.p)) + 1;
[2024f6a]139
[47a616d]140  out << "Pivots: " << std::endl;
141  for(int j = 0; j < mat.n; j++)
142  {
143    out << std::setw (width) << mat.pivots[j] << " ";
144  }
145  out << std::endl;
146  out << "matrix:" << std::endl;
[5b2745]147  for(int i = 0; i < mat.rows; i++)
148  {
149    for(int j = 0; j < mat.n; j++)
150    {
151      out << std::setw (width) << mat.matrix[i][j] << " ";
[2024f6a]152    }
153    out << "| ";
[5b2745]154    for(int j = mat.n; j <= 2 * mat.n; j++)
155    {
156      out << std::setw (width) << mat.matrix[i][j] << " ";
[2024f6a]157    }
158    out << std::endl;
[5b2745]159  }
[47a616d]160  out << "tmprow: " << std::endl;
[5b2745]161  for(int j = 0; j < mat.n; j++)
162  {
163    out << std::setw (width) << mat.tmprow[j] << " ";
164  }
165  out << "| ";
166  for(int j = mat.n; j <= 2 * mat.n; j++)
167  {
168    out << std::setw (width) << mat.tmprow[j] << " ";
169  }
170  out << std::endl;
171
172  return out;
[2024f6a]173}
[ec9db9]174#endif
[2024f6a]175
176
[5b2745]177NewVectorMatrix::NewVectorMatrix (unsigned n, unsigned long p)
178{
179  this->n = n;
180  this->p = p;
[2024f6a]181
[5b2745]182  matrix = new unsigned long *[n];
[47a616d]183  for(int i = 0; i < n; i++)
[5b2745]184  {
185    matrix[i] = new unsigned long[n];
186  }
[2024f6a]187
[5b2745]188  pivots = new unsigned[n];
189  rows = 0;
[2024f6a]190}
191
[5b2745]192NewVectorMatrix::~NewVectorMatrix ()
193{
194  delete pivots;
[2024f6a]195
[47a616d]196  for(int i = 0; i < n; i++)
[5b2745]197  {
198    delete[]matrix[i];
199  }
200  delete matrix;
[2024f6a]201}
202
[5b2745]203int NewVectorMatrix::firstNonzeroEntry (unsigned long *row)
204{
[47a616d]205  for(int i = 0; i < n; i++)
[5b2745]206    if(row[i] != 0)
207      return i;
[2024f6a]208
[5b2745]209  return -1;
[2024f6a]210}
211
212//void NewVectorMatrix::subtractIthRow(unsigned long* row, unsigned i) {
213//    unsigned piv = pivots[i];
214//    unsigned long x = row[piv];
215//    for (int j = piv; j < n; j++) {
216//        unsigned tmp = matrix[i][j]*x % p;
217//        tmp = p - tmp;
218//        row[j] += tmp;
219//        row[j] %= p;
220//    }
221//}
222//
[5b2745]223void NewVectorMatrix::normalizeRow (unsigned long *row, unsigned i)
224{
225  unsigned long inv = modularInverse (row[i], p);
226  row[i] = 1;
227
[47a616d]228  for(int j = i + 1; j < n; j++)
[5b2745]229  {
230    row[j] = (row[j] * inv) % p;
231  }
[2024f6a]232}
233
[5b2745]234void NewVectorMatrix::insertRow (unsigned long *row)
235{
[47a616d]236  for(int i = 0; i < rows; i++)
[5b2745]237  {
238    unsigned piv = pivots[i];
239    unsigned long x = row[piv] % p;
240    // if the corresponding entry in the row is zero, there is nothing to do
241    if(x != 0)
242    {
243      // subtract row[i] times the i-th row
[47a616d]244      for(int j = piv; j < n; j++)
[5b2745]245      {
246        unsigned long tmp = matrix[i][j] * x % p;
247        tmp = p - tmp;
248        row[j] += tmp;
249        // We don't normalize here, so remember to do it after all reductions.
250        // row[j] %= p;
251      }
252    }
253  }
254
255  // normalize the entries of row.
[47a616d]256  for(int i = 0; i < n + rows + 1; i++)
[5b2745]257  {
258    row[i] %= p;
259  }
260
[47a616d]261  unsigned piv = firstNonzeroEntry (row);
[5b2745]262
263  if(piv != -1)
264  {
265    // normalize and insert row into the matrix
266    normalizeRow (row, piv);
[47a616d]267    for(int i = 0; i < n; i++)
[5b2745]268    {
269      matrix[rows][i] = row[i];
270    }
271
272    pivots[rows] = piv;
273    rows++;
274  }
[2024f6a]275}
276
277
[5b2745]278void NewVectorMatrix::insertMatrix (LinearDependencyMatrix & mat)
279{
280  // The matrix in LinearDependencyMatrix is already in reduced form.
281  // Thus, if the current matrix is empty, we can simply copy the other matrix.
282  if(rows == 0)
283  {
[47a616d]284    for(int i = 0; i < mat.rows; i++)
[5b2745]285    {
[47a616d]286      for(int j = 0; j < n; j++)
[5b2745]287      {
288        matrix[i][j] = mat.matrix[i][j];
289
290        rows = mat.rows;
[47a616d]291        for(int i = 0; i < rows; i++)
[5b2745]292        {
[47a616d]293          pivots[i] = mat.pivots[i];
[2024f6a]294        }
[5b2745]295      }
[2024f6a]296    }
[5b2745]297  }
298  else
299  {
[47a616d]300    for(int i = 0; i < mat.rows; i++)
[5b2745]301    {
302      insertRow (mat.matrix[i]);
303    }
304  }
[2024f6a]305}
306
[5b2745]307int NewVectorMatrix::findSmallestNonpivot ()
308{
309  // This method isn't very efficient, but it is called at most a few times, so efficiency is not important.
310  if(rows == n)
311    return -1;
[2024f6a]312
[47a616d]313  for(int i = 0; i < n; i++)
[5b2745]314  {
315    bool isPivot = false;
[47a616d]316    for(int j = 0; j < rows; j++)
[5b2745]317    {
318      if(pivots[j] == i)
319      {
320        isPivot = true;
321        break;
322      }
323    }
324
325    if(!isPivot)
326    {
327      return i;
328    }
329  }
330  assume(0);
331  return -1; // to make the compiler happy
[47a616d]332
[2024f6a]333}
334
335
[5b2745]336void vectorMatrixMult (unsigned long *vec, unsigned long **mat,
337                       unsigned long *result, unsigned n, unsigned long p)
338{
339  unsigned long tmp;
[47a616d]340  for(int i = 0; i < n; i++)
[5b2745]341  {
342    result[i] = 0;
[47a616d]343    for(int j = 0; j < n; j++)
[5b2745]344    {
345      tmp = vec[j] * mat[j][i] % p;
346      result[i] += tmp;
347    }
348    // We can afford to reduce mod p only after all additions, since p < 2^31, but an unsigned long can store 2^64.
349    // Thus the only possibility for an overflow would occurr for matrices with about 2^31 rows.
350    result[i] %= p;
351  }
[2024f6a]352}
353
[ec9db9]354#if 0
[5b2745]355void printVec (unsigned long *vec, int n)
356{
357  for(int i = 0; i < n; i++)
358  {
359    std::cout << vec[i] << ", ";
360  }
361
362  std::cout << std::endl;
[2024f6a]363}
[ec9db9]364#endif
365
[5b2745]366unsigned long *computeMinimalPolynomial (unsigned long **matrix, unsigned n,
367                                         unsigned long p)
368{
369  LinearDependencyMatrix lindepmat (n, p);
370  NewVectorMatrix newvectormat (n, p);
[2024f6a]371
[5b2745]372  unsigned long *result = new unsigned long[n + 1];
373  unsigned long *mpvec = new unsigned long[n + 1];
374  unsigned long *tmp = new unsigned long[n + 1];
[2024f6a]375
[47a616d]376  // initialize result = 1
377  for(int i = 0; i <= n; i++)
[5b2745]378  {
379    result[i] = 0;
380  }
381  result[0] = 1;
[2024f6a]382
[5b2745]383  int degresult = 0;
[2024f6a]384
385
[5b2745]386  int i = 0;
[2024f6a]387
[5b2745]388  unsigned long *vec = new unsigned long[n];
389  unsigned long *vecnew = new unsigned long[n];
[ec9db9]390
[5b2745]391  while(i != -1)
392  {
[47a616d]393    for(int j = 0; j < n; j++)
[5b2745]394    {
395      vec[j] = 0;
[2024f6a]396    }
[5b2745]397    vec[i] = 1;
[2024f6a]398
[5b2745]399    lindepmat.resetMatrix ();
[2024f6a]400
[5b2745]401    while(true)
402    {
403      bool ld = lindepmat.findLinearDependency (vec, mpvec);
[2024f6a]404
[5b2745]405      if(ld)
406      {
407        break;
408      }
[2024f6a]409
[5b2745]410      vectorMatrixMult (vec, matrix, vecnew, n, p);
411      unsigned long *swap = vec;
412      vec = vecnew;
413      vecnew = swap;
414    }
[2024f6a]415
416
[5b2745]417    unsigned degmpvec = n;
418    while(mpvec[degmpvec] == 0)
419    {
420      degmpvec--;
[2024f6a]421    }
422
[47a616d]423    // if the dimension is already maximal, i.e., the minimal polynomial of vec has the highest possible degree,
[5b2745]424    // then we are done.
425    if(degmpvec == n)
426    {
427      unsigned long *swap = result;
428      result = mpvec;
429      mpvec = swap;
430      i = -1;
431    }
432    else
433    {
434      // otherwise, we have to compute the lcm of mpvec and prior result
[2024f6a]435
[5b2745]436      // tmp = zeropol
[47a616d]437      for(int j = 0; j <= n; j++)
[5b2745]438      {
439        tmp[j] = 0;
440      }
441      degresult = lcm (tmp, result, mpvec, p, degresult, degmpvec);
442      unsigned long *swap = result;
443      result = tmp;
444      tmp = swap;
[2024f6a]445
[5b2745]446      if(degresult == n)
447      {
448        // minimal polynomial has highest possible degree, so we are done.
449        i = -1;
450      }
451      else
452      {
453        newvectormat.insertMatrix (lindepmat);
454        i = newvectormat.findSmallestNonpivot ();
455      }
[2024f6a]456    }
[5b2745]457  }
[2024f6a]458
[5b2745]459  // TODO: take lcms of the different monomials!
[2024f6a]460
[5b2745]461  delete[]vecnew;
462  delete[]vec;
463  delete[]tmp;
464  delete[]mpvec;
[2024f6a]465
[5b2745]466  return result;
[2024f6a]467}
468
469
[5b2745]470void rem (unsigned long *a, unsigned long *q, unsigned long p, int &dega,
471          int degq)
472{
473  while(degq <= dega)
474  {
475    unsigned d = dega - degq;
476    long factor = a[dega] * modularInverse (q[degq], p) % p;
477    for(int i = degq; i >= 0; i--)
478    {
479      long tmp = p - (factor * q[i] % p);
480      a[d + i] += tmp;
481      a[d + i] %= p;
482    }
[2024f6a]483
[5b2745]484    while(a[dega] == 0 && dega >= 0)
485    {
486      dega--;
[2024f6a]487    }
[5b2745]488  }
[2024f6a]489}
490
491
[5b2745]492void quo (unsigned long *a, unsigned long *q, unsigned long p, int &dega,
493          int degq)
494{
495  unsigned degres = dega - degq;
496  unsigned long *result = new unsigned long[degres + 1];
497
498  while(degq <= dega)
499  {
500    unsigned d = dega - degq;
501    long inv = modularInverse (q[degq], p);
502    result[d] = a[dega] * inv % p;
[47a616d]503    for(int i = degq; i >= 0; i--)
[5b2745]504    {
505      long tmp = p - (result[d] * q[i] % p);
506      a[d + i] += tmp;
507      a[d + i] %= p;
508    }
509
510    while(a[dega] == 0 && dega >= 0)
511    {
512      dega--;
513    }
514  }
515
516  // copy result into a
[47a616d]517  for(int i = 0; i <= degres; i++)
[5b2745]518  {
519    a[i] = result[i];
520  }
521  // set all following entries of a to zero
[47a616d]522  for(int i = degres + 1; i <= degq + degres; i++)
[5b2745]523  {
524    a[i] = 0;
525  }
526
527  dega = degres;
528
529  delete[]result;
530}
[2024f6a]531
532
[5b2745]533void mult (unsigned long *result, unsigned long *a, unsigned long *b,
534           unsigned long p, int dega, int degb)
535{
536  // NOTE: we assume that every entry in result is preinitialized to zero!
[2024f6a]537
[5b2745]538  for(int i = 0; i <= dega; i++)
539  {
540    for(int j = 0; j <= degb; j++)
541    {
542      result[i + j] += (a[i] * b[j] % p);
543      result[i + j] %= p;
[2024f6a]544    }
[5b2745]545  }
[2024f6a]546}
547
548
[5b2745]549int gcd (unsigned long *g, unsigned long *a, unsigned long *b,
550         unsigned long p, int dega, int degb)
551{
552  unsigned long *tmp1 = new unsigned long[dega + 1];
553  unsigned long *tmp2 = new unsigned long[degb + 1];
554  for(int i = 0; i <= dega; i++)
555  {
556    tmp1[i] = a[i];
557  }
558  for(int i = 0; i <= degb; i++)
559  {
560    tmp2[i] = b[i];
561  }
562  int degtmp1 = dega;
563  int degtmp2 = degb;
564
565  unsigned long *swappol;
566  int swapdeg;
567
568  while(degtmp2 >= 0)
569  {
570    rem (tmp1, tmp2, p, degtmp1, degtmp2);
571    swappol = tmp1;
572    tmp1 = tmp2;
573    tmp2 = swappol;
574
575    swapdeg = degtmp1;
576    degtmp1 = degtmp2;
577    degtmp2 = swapdeg;
578  }
579
580  for(int i = 0; i <= degtmp1; i++)
581  {
582    g[i] = tmp1[i];
583  }
584
585  delete[]tmp1;
586  delete[]tmp2;
587
588  return degtmp1;
589}
[2024f6a]590
591
[5b2745]592int lcm (unsigned long *l, unsigned long *a, unsigned long *b,
593         unsigned long p, int dega, int degb)
594{
595  unsigned long *g = new unsigned long[dega + 1];
596  // initialize entries of g to zero
597  for(int i = 0; i <= dega; i++)
598  {
599    g[i] = 0;
600  }
601
602  int degg = gcd (g, a, b, p, dega, degb);
603
604  if(degg > 0)
605  {
606    // non-trivial gcd, so compute a = (a/g)
607    quo (a, g, p, dega, degg);
608  }
609  mult (l, a, b, p, dega, degb);
610
611  // normalize
612  if(l[dega + degb + 1] != 1)
613  {
614    unsigned long inv = modularInverse (l[dega + degb], p);
615    for(int i = 0; i <= dega + degb; i++)
616    {
617      l[i] *= inv;
618      l[i] %= p;
619    }
620  }
621
622  return dega + degb;
[2024f6a]623}
624
625
[47a616d]626// computes the gcd and the cofactors of u and v
627// gcd(u,v) = u3 = u*u1 + v*u2
[5b2745]628long modularInverse (long x, long p)
629{
630  long u1 = 1;
631  long u2 = 0;
632  long u3 = x;
633  long v1 = 0;
634  long v2 = 1;
635  long v3 = p;
636
637  long q, t1, t2, t3;
638  while(v3 != 0)
639  {
640    q = u3 / v3;
641    t1 = u1 - q * v1;
642    t2 = u2 - q * v2;
643    t3 = u3 - q * v3;
644    u1 = v1;
645    u2 = v2;
646    u3 = v3;
647    v1 = t1;
648    v2 = t2;
649    v3 = t3;
650  }
651
652  if(u1 < 0)
653  {
654    u1 += p;
655  }
656
657  return u1;
[2024f6a]658}
Note: See TracBrowser for help on using the repository browser.