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
Line 
1/***********************************************
2 * Copyright (C) 2011 Sebastian Jambor         *
3 * sebastian@momo.math.rwth-aachen.de          *
4 ***********************************************/
5
6
7#include<cmath>
8#include<Singular/mod2.h>
9
10#include "minpoly.h"
11
12// TODO: avoid code copying, use subclassing instead!
13
14LinearDependencyMatrix::LinearDependencyMatrix (unsigned n, unsigned long p)
15{
16  this->n = n;
17  this->p = p;
18
19  matrix = new unsigned long *[n];
20  for(int i = 0; i < n; i++)
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;
27}
28
29LinearDependencyMatrix::~LinearDependencyMatrix ()
30{
31  delete[]tmprow;
32  delete[]pivots;
33
34  for(int i = 0; i < n; i++)
35  {
36    delete[](matrix[i]);
37  }
38  delete[]matrix;
39}
40
41void LinearDependencyMatrix::resetMatrix ()
42{
43  rows = 0;
44}
45
46int LinearDependencyMatrix::firstNonzeroEntry (unsigned long *row)
47{
48  for(int i = 0; i < n; i++)
49    if(row[i] != 0)
50      return i;
51
52  return -1;
53}
54
55void LinearDependencyMatrix::reduceTmpRow ()
56{
57  for(int i = 0; i < rows; i++)
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
65      for(int j = piv; j < n + rows + 1; j++)
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.
77  for(int i = 0; i < n + rows + 1; i++)
78  {
79    tmprow[i] %= p;
80  }
81}
82
83
84void LinearDependencyMatrix::normalizeTmp (unsigned i)
85{
86  unsigned long inv = modularInverse (tmprow[i], p);
87  tmprow[i] = 1;
88  for(int j = i + 1; j < 2 * n + 1; j++)
89    tmprow[j] = (tmprow[j] * inv) % p;
90}
91
92bool LinearDependencyMatrix::findLinearDependency (unsigned long *newRow,
93                                                   unsigned long *dep)
94{
95  // Copy newRow to tmprow (we need to add RHS)
96  for(int i = 0; i < n; i++)
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.
108  unsigned newpivot = firstNonzeroEntry (tmprow);
109  if(newpivot == -1)
110  {
111    for(int i = 0; i <= n; i++)
112    {
113      dep[i] = tmprow[n + i];
114    }
115
116    return true;
117  }
118  else
119  {
120    normalizeTmp (newpivot);
121
122    for(int i = 0; i < 2 * n + 1; i++)
123    {
124      matrix[rows][i] = tmprow[i];
125    }
126
127    pivots[rows] = newpivot;
128    rows++;
129
130    return false;
131  }
132}
133
134#if 0
135std::ostream & operator<< (std::ostream & out,
136                           const LinearDependencyMatrix & mat)
137{
138  int width = ((int) log10 (mat.p)) + 1;
139
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;
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] << " ";
152    }
153    out << "| ";
154    for(int j = mat.n; j <= 2 * mat.n; j++)
155    {
156      out << std::setw (width) << mat.matrix[i][j] << " ";
157    }
158    out << std::endl;
159  }
160  out << "tmprow: " << std::endl;
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;
173}
174#endif
175
176
177NewVectorMatrix::NewVectorMatrix (unsigned n, unsigned long p)
178{
179  this->n = n;
180  this->p = p;
181
182  matrix = new unsigned long *[n];
183  for(int i = 0; i < n; i++)
184  {
185    matrix[i] = new unsigned long[n];
186  }
187
188  pivots = new unsigned[n];
189  rows = 0;
190}
191
192NewVectorMatrix::~NewVectorMatrix ()
193{
194  delete pivots;
195
196  for(int i = 0; i < n; i++)
197  {
198    delete[]matrix[i];
199  }
200  delete matrix;
201}
202
203int NewVectorMatrix::firstNonzeroEntry (unsigned long *row)
204{
205  for(int i = 0; i < n; i++)
206    if(row[i] != 0)
207      return i;
208
209  return -1;
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//
223void NewVectorMatrix::normalizeRow (unsigned long *row, unsigned i)
224{
225  unsigned long inv = modularInverse (row[i], p);
226  row[i] = 1;
227
228  for(int j = i + 1; j < n; j++)
229  {
230    row[j] = (row[j] * inv) % p;
231  }
232}
233
234void NewVectorMatrix::insertRow (unsigned long *row)
235{
236  for(int i = 0; i < rows; i++)
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
244      for(int j = piv; j < n; j++)
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.
256  for(int i = 0; i < n + rows + 1; i++)
257  {
258    row[i] %= p;
259  }
260
261  unsigned piv = firstNonzeroEntry (row);
262
263  if(piv != -1)
264  {
265    // normalize and insert row into the matrix
266    normalizeRow (row, piv);
267    for(int i = 0; i < n; i++)
268    {
269      matrix[rows][i] = row[i];
270    }
271
272    pivots[rows] = piv;
273    rows++;
274  }
275}
276
277
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  {
284    for(int i = 0; i < mat.rows; i++)
285    {
286      for(int j = 0; j < n; j++)
287      {
288        matrix[i][j] = mat.matrix[i][j];
289
290        rows = mat.rows;
291        for(int i = 0; i < rows; i++)
292        {
293          pivots[i] = mat.pivots[i];
294        }
295      }
296    }
297  }
298  else
299  {
300    for(int i = 0; i < mat.rows; i++)
301    {
302      insertRow (mat.matrix[i]);
303    }
304  }
305}
306
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;
312
313  for(int i = 0; i < n; i++)
314  {
315    bool isPivot = false;
316    for(int j = 0; j < rows; j++)
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
332
333}
334
335
336void vectorMatrixMult (unsigned long *vec, unsigned long **mat,
337                       unsigned long *result, unsigned n, unsigned long p)
338{
339  unsigned long tmp;
340  for(int i = 0; i < n; i++)
341  {
342    result[i] = 0;
343    for(int j = 0; j < n; j++)
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  }
352}
353
354#if 0
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;
363}
364#endif
365
366unsigned long *computeMinimalPolynomial (unsigned long **matrix, unsigned n,
367                                         unsigned long p)
368{
369  LinearDependencyMatrix lindepmat (n, p);
370  NewVectorMatrix newvectormat (n, p);
371
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];
375
376  // initialize result = 1
377  for(int i = 0; i <= n; i++)
378  {
379    result[i] = 0;
380  }
381  result[0] = 1;
382
383  int degresult = 0;
384
385
386  int i = 0;
387
388  unsigned long *vec = new unsigned long[n];
389  unsigned long *vecnew = new unsigned long[n];
390
391  while(i != -1)
392  {
393    for(int j = 0; j < n; j++)
394    {
395      vec[j] = 0;
396    }
397    vec[i] = 1;
398
399    lindepmat.resetMatrix ();
400
401    while(true)
402    {
403      bool ld = lindepmat.findLinearDependency (vec, mpvec);
404
405      if(ld)
406      {
407        break;
408      }
409
410      vectorMatrixMult (vec, matrix, vecnew, n, p);
411      unsigned long *swap = vec;
412      vec = vecnew;
413      vecnew = swap;
414    }
415
416
417    unsigned degmpvec = n;
418    while(mpvec[degmpvec] == 0)
419    {
420      degmpvec--;
421    }
422
423    // if the dimension is already maximal, i.e., the minimal polynomial of vec has the highest possible degree,
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
435
436      // tmp = zeropol
437      for(int j = 0; j <= n; j++)
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;
445
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      }
456    }
457  }
458
459  // TODO: take lcms of the different monomials!
460
461  delete[]vecnew;
462  delete[]vec;
463  delete[]tmp;
464  delete[]mpvec;
465
466  return result;
467}
468
469
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    }
483
484    while(a[dega] == 0 && dega >= 0)
485    {
486      dega--;
487    }
488  }
489}
490
491
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;
503    for(int i = degq; i >= 0; i--)
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
517  for(int i = 0; i <= degres; i++)
518  {
519    a[i] = result[i];
520  }
521  // set all following entries of a to zero
522  for(int i = degres + 1; i <= degq + degres; i++)
523  {
524    a[i] = 0;
525  }
526
527  dega = degres;
528
529  delete[]result;
530}
531
532
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!
537
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;
544    }
545  }
546}
547
548
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}
590
591
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;
623}
624
625
626// computes the gcd and the cofactors of u and v
627// gcd(u,v) = u3 = u*u1 + v*u2
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;
658}
Note: See TracBrowser for help on using the repository browser.