source: git/Singular/minpoly.cc @ 667ba1

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