source: git/Singular/minpoly.cc @ ba5e9e

spielwiese
Last change on this file since ba5e9e was ba5e9e, checked in by Oleksandr Motsak <motsak@…>, 11 years ago
Changed configure-scripts to generate individual public config files for each package: resources, libpolys, singular (main) fix: sources should include correct corresponding config headers.
  • Property mode set to 100644
File size: 15.0 KB
Line 
1/*************************************************
2 * Author: Sebastian Jambor, 2011                *
3 * GPL (e-mail from June 6, 2012, 17:00:31 MESZ) *
4 * sebastian@momo.math.rwth-aachen.de            *
5 ************************************************/
6
7
8#include<cmath>
9#include <cstdlib>
10#ifdef HAVE_CONFIG_H
11#include "singularconfig.h"
12#endif /* HAVE_CONFIG_H */
13#include<kernel/mod2.h>
14
15//#include<iomanip>
16
17#include "minpoly.h"
18
19// TODO: avoid code copying, use subclassing instead!
20
21LinearDependencyMatrix::LinearDependencyMatrix (unsigned n, unsigned long p)
22{
23  this->n = n;
24  this->p = p;
25
26  matrix = new unsigned long *[n];
27  for(int i = 0; i < n; i++)
28  {
29    matrix[i] = new unsigned long[2 * n + 1];
30  }
31  pivots = new unsigned[n];
32  tmprow = new unsigned long[2 * n + 1];
33  rows = 0;
34}
35
36LinearDependencyMatrix::~LinearDependencyMatrix ()
37{
38  delete[]tmprow;
39  delete[]pivots;
40
41  for(int i = 0; i < n; i++)
42  {
43    delete[](matrix[i]);
44  }
45  delete[]matrix;
46}
47
48void LinearDependencyMatrix::resetMatrix ()
49{
50  rows = 0;
51}
52
53int LinearDependencyMatrix::firstNonzeroEntry (unsigned long *row)
54{
55  for(int i = 0; i < n; i++)
56    if(row[i] != 0)
57      return i;
58
59  return -1;
60}
61
62void LinearDependencyMatrix::reduceTmpRow ()
63{
64  for(int i = 0; i < rows; i++)
65  {
66    unsigned piv = pivots[i];
67    unsigned x = tmprow[piv];
68    // if the corresponding entry in the row is zero, there is nothing to do
69    if(x != 0)
70    {
71      // subtract tmprow[i] times the i-th row
72      for(int j = piv; j < n + rows + 1; j++)
73      {
74        if (matrix[i][j] != 0)
75        {
76          unsigned long tmp = multMod (matrix[i][j], x, p);
77          tmp = p - tmp;
78          tmprow[j] += tmp;
79          if (tmprow[j] >= p)
80          {
81            tmprow[j] -= p;
82          }
83        }
84      }
85    }
86  }
87}
88
89
90void LinearDependencyMatrix::normalizeTmp (unsigned i)
91{
92  unsigned long inv = modularInverse (tmprow[i], p);
93  tmprow[i] = 1;
94  for(int j = i + 1; j < 2 * n + 1; j++)
95    tmprow[j] = multMod (tmprow[j], inv, p);
96}
97
98bool LinearDependencyMatrix::findLinearDependency (unsigned long *newRow,
99                                                   unsigned long *dep)
100{
101  // Copy newRow to tmprow (we need to add RHS)
102  for(int i = 0; i < n; i++)
103  {
104    tmprow[i] = newRow[i];
105    tmprow[n + i] = 0;
106  }
107  tmprow[2 * n] = 0;
108  tmprow[n + rows] = 1;
109
110  reduceTmpRow ();
111
112  // Is tmprow reduced to zero? Then we have found a linear dependence.
113  // Otherwise, we just add tmprow to the matrix.
114  unsigned newpivot = firstNonzeroEntry (tmprow);
115  if(newpivot == -1)
116  {
117    for(int i = 0; i <= n; i++)
118    {
119      dep[i] = tmprow[n + i];
120    }
121
122    return true;
123  }
124  else
125  {
126    normalizeTmp (newpivot);
127
128    for(int i = 0; i < 2 * n + 1; i++)
129    {
130      matrix[rows][i] = tmprow[i];
131    }
132
133    pivots[rows] = newpivot;
134    rows++;
135
136    return false;
137  }
138}
139
140#if 0
141std::ostream & operator<< (std::ostream & out,
142                           const LinearDependencyMatrix & mat)
143{
144  int width = ((int) log10 (mat.p)) + 1;
145
146  out << "Pivots: " << std::endl;
147  for(int j = 0; j < mat.n; j++)
148  {
149    out << std::setw (width) << mat.pivots[j] << " ";
150  }
151  out << std::endl;
152  out << "matrix:" << std::endl;
153  for(int i = 0; i < mat.rows; i++)
154  {
155    for(int j = 0; j < mat.n; j++)
156    {
157      out << std::setw (width) << mat.matrix[i][j] << " ";
158    }
159    out << "| ";
160    for(int j = mat.n; j <= 2 * mat.n; j++)
161    {
162      out << std::setw (width) << mat.matrix[i][j] << " ";
163    }
164    out << std::endl;
165  }
166  out << "tmprow: " << std::endl;
167  for(int j = 0; j < mat.n; j++)
168  {
169    out << std::setw (width) << mat.tmprow[j] << " ";
170  }
171  out << "| ";
172  for(int j = mat.n; j <= 2 * mat.n; j++)
173  {
174    out << std::setw (width) << mat.tmprow[j] << " ";
175  }
176  out << std::endl;
177
178  return out;
179}
180#endif
181
182
183NewVectorMatrix::NewVectorMatrix (unsigned n, unsigned long p)
184{
185  this->n = n;
186  this->p = p;
187
188  matrix = new unsigned long *[n];
189  for(int i = 0; i < n; i++)
190  {
191    matrix[i] = new unsigned long[n];
192  }
193
194  pivots = new unsigned[n];
195
196  nonPivots = new unsigned[n];
197
198  for (int i = 0; i < n; i++)
199  {
200     nonPivots[i] = i;
201  }
202
203  rows = 0;
204}
205
206NewVectorMatrix::~NewVectorMatrix ()
207{
208  delete nonPivots;
209  delete pivots;
210
211  for(int i = 0; i < n; i++)
212  {
213    delete[]matrix[i];
214  }
215  delete matrix;
216}
217
218int NewVectorMatrix::firstNonzeroEntry (unsigned long *row)
219{
220  for(int i = 0; i < n; i++)
221    if(row[i] != 0)
222      return i;
223
224  return -1;
225}
226
227void NewVectorMatrix::normalizeRow (unsigned long *row, unsigned i)
228{
229  unsigned long inv = modularInverse (row[i], p);
230  row[i] = 1;
231
232  for(int j = i + 1; j < n; j++)
233  {
234    row[j] = multMod (row[j], inv, p);
235  }
236}
237
238void NewVectorMatrix::insertRow (unsigned long *row)
239{
240  for(int i = 0; i < rows; i++)
241  {
242    unsigned piv = pivots[i];
243    unsigned x = row[piv];
244    // if the corresponding entry in the row is zero, there is nothing to do
245    if(x != 0)
246    {
247      // subtract row[i] times the i-th row
248      // only the non-pivot entries have to be considered
249      // (and also the first entry)
250      row[piv] = 0;
251
252      int smallestNonPivIndex = 0;
253      while (nonPivots[smallestNonPivIndex] < piv)
254      {
255        smallestNonPivIndex++;
256      }
257
258      for (int j = smallestNonPivIndex; j < n-rows; j++)
259      {
260        unsigned ind = nonPivots[j];
261        if (matrix[i][ind] != 0)
262        {
263          unsigned long tmp = multMod (matrix[i][ind], x, p);
264          tmp = p - tmp;
265          row[ind] += tmp;
266          if (row[ind] >= p)
267          {
268            row[ind] -= p;
269          }
270        }
271      }
272    }
273  }
274
275  unsigned piv = firstNonzeroEntry (row);
276
277  if(piv != -1)
278  {
279    // Normalize and insert row into the matrix.
280    // Then reduce upwards.
281    normalizeRow (row, piv);
282    for(int i = 0; i < n; i++)
283    {
284      matrix[rows][i] = row[i];
285    }
286
287
288    for (int i = 0; i < rows; i++)
289    {
290      unsigned x = matrix[i][piv];
291      // if the corresponding entry in the matrix is zero,
292      // there is nothing to do
293      if (x != 0)
294      {
295        for (int j = piv; j < n; j++)
296        {
297          if (row[j] != 0)
298          {
299            unsigned long tmp = multMod(row[j], x, p);
300            tmp = p - tmp;
301            matrix[i][j] += tmp;
302            if (matrix[i][j] >= p)
303            {
304              matrix[i][j] -= p;
305            }
306          }
307        }
308      }
309    }
310
311    pivots[rows] = piv;
312
313    // update nonPivots
314    for (int i = 0; i < n-rows; i++)
315    {
316      if (nonPivots[i] == piv)
317      {
318        // shift everything one position to the left
319        for (int j = i; j < n-rows-1; j++)
320        {
321          nonPivots[j] = nonPivots[j+1];
322        }
323
324        break;
325      }
326    }
327
328    rows++;
329  }
330}
331
332
333void NewVectorMatrix::insertMatrix (LinearDependencyMatrix & mat)
334{
335  for(int i = 0; i < mat.rows; i++)
336  {
337    insertRow (mat.matrix[i]);
338  }
339}
340
341int NewVectorMatrix::findSmallestNonpivot ()
342{
343  // This method isn't very efficient, but it is called at most a few times,
344  // so efficiency is not important.
345  if(rows == n)
346    return -1;
347
348  for(int i = 0; i < n; i++)
349  {
350    bool isPivot = false;
351    for(int j = 0; j < rows; j++)
352    {
353      if(pivots[j] == i)
354      {
355        isPivot = true;
356        break;
357      }
358    }
359
360    if(!isPivot)
361    {
362      return i;
363    }
364  }
365}
366
367int NewVectorMatrix::findLargestNonpivot ()
368{
369  // This method isn't very efficient, but it is called at most a few times, so efficiency is not important.
370  if(rows == n)
371    return -1;
372
373  for(int i = n-1; i >= 0; i--)
374  {
375    bool isPivot = false;
376    for(int j = 0; j < rows; j++)
377    {
378      if(pivots[j] == i)
379      {
380        isPivot = true;
381        break;
382      }
383    }
384
385    if(!isPivot)
386    {
387      return i;
388    }
389  }
390  abort();
391}
392
393
394void vectorMatrixMult (unsigned long *vec, unsigned long **mat,
395                       unsigned **nonzeroIndices, unsigned *nonzeroCounts,
396                       unsigned long *result, unsigned n, unsigned long p)
397{
398  unsigned long tmp;
399
400  for(int i = 0; i < n; i++)
401  {
402    result[i] = 0;
403    for(int j = 0; j < nonzeroCounts[i]; j++)
404    {
405      tmp = multMod (vec[nonzeroIndices[i][j]], mat[nonzeroIndices[i][j]][i], p);
406      result[i] += tmp;
407      if (result[i] >= p)
408      {
409        result[i] -= p;
410      }
411    }
412  }
413}
414
415
416#if 0
417void printVec (unsigned long *vec, int n)
418{
419  for(int i = 0; i < n; i++)
420  {
421    std::cout << vec[i] << ", ";
422  }
423
424  std::cout << std::endl;
425}
426#endif
427
428
429unsigned long *computeMinimalPolynomial (unsigned long **matrix, unsigned n,
430                                         unsigned long p)
431{
432  LinearDependencyMatrix lindepmat (n, p);
433  NewVectorMatrix newvectormat (n, p);
434
435  unsigned long *result = new unsigned long[n + 1];
436  unsigned long *mpvec = new unsigned long[n + 1];
437  unsigned long *tmp = new unsigned long[n + 1];
438
439  // initialize result = 1
440  for(int i = 0; i <= n; i++)
441  {
442    result[i] = 0;
443  }
444  result[0] = 1;
445
446  int degresult = 0;
447
448
449  // Store the indices where the matrix has non-zero entries.
450  // This has a huge impact on spares matrices.
451  unsigned* nonzeroCounts = new unsigned[n];
452  unsigned** nonzeroIndices = new unsigned*[n];
453  for (int i = 0; i < n; i++)
454  {
455    nonzeroIndices[i] = new unsigned[n];
456    nonzeroCounts[i] = 0;
457    for (int j = 0; j < n; j++)
458    {
459      if (matrix[j][i] != 0)
460      {
461        nonzeroIndices[i][nonzeroCounts[i]] = j;
462        nonzeroCounts[i]++;
463      }
464    }
465  }
466
467  int i = n-1;
468
469  unsigned long *vec = new unsigned long[n];
470  unsigned long *vecnew = new unsigned long[n];
471
472  unsigned loopsEven = true;
473  while(i != -1)
474  {
475    for(int j = 0; j < n; j++)
476    {
477      vec[j] = 0;
478    }
479    vec[i] = 1;
480
481    lindepmat.resetMatrix ();
482
483    while(true)
484    {
485      bool ld = lindepmat.findLinearDependency (vec, mpvec);
486
487      if(ld)
488      {
489        break;
490      }
491
492      vectorMatrixMult (vec, matrix, nonzeroIndices, nonzeroCounts, vecnew, n, p);
493      unsigned long *swap = vec;
494      vec = vecnew;
495      vecnew = swap;
496    }
497
498
499    unsigned degmpvec = n;
500    while(mpvec[degmpvec] == 0)
501    {
502      degmpvec--;
503    }
504
505    // if the dimension is already maximal, i.e., the minimal polynomial of vec has the highest possible degree,
506    // then we are done.
507    if(degmpvec == n)
508    {
509      unsigned long *swap = result;
510      result = mpvec;
511      mpvec = swap;
512      i = -1;
513    }
514    else
515    {
516      // otherwise, we have to compute the lcm of mpvec and prior result
517
518      // tmp = zeropol
519      for(int j = 0; j <= n; j++)
520      {
521        tmp[j] = 0;
522      }
523      degresult = lcm (tmp, result, mpvec, p, degresult, degmpvec);
524      unsigned long *swap = result;
525      result = tmp;
526      tmp = swap;
527
528      if(degresult == n)
529      {
530        // minimal polynomial has highest possible degree, so we are done.
531        i = -1;
532      }
533      else
534      {
535        newvectormat.insertMatrix (lindepmat);
536
537        // choose new unit vector from the front or the end, alternating
538        // for each round. If the matrix is the companion matrix for x^n,
539        // then taking vectors from the end is best. If it is the transpose,
540        // taking vectors from the front is best.
541        // This tries to take the middle way
542        if (loopsEven)
543        {
544          i = newvectormat.findSmallestNonpivot ();
545        }
546        else
547        {
548          i = newvectormat.findLargestNonpivot ();
549        }
550      }
551    }
552
553    loopsEven = !loopsEven;
554  }
555
556  for (int i = 0; i < n; i++)
557  {
558    delete[] nonzeroIndices[i];
559  }
560  delete[] nonzeroIndices;
561  delete[] nonzeroCounts;
562
563
564  delete[]vecnew;
565  delete[]vec;
566  delete[]tmp;
567  delete[]mpvec;
568
569  return result;
570}
571
572
573void rem (unsigned long *a, unsigned long *q, unsigned long p, int &dega,
574          int degq)
575{
576  while(degq <= dega)
577  {
578    unsigned d = dega - degq;
579    long factor = multMod (a[dega], modularInverse (q[degq], p), p);
580    for(int i = degq; i >= 0; i--)
581    {
582      long tmp = p - multMod (factor, q[i], p);
583      a[d + i] += tmp;
584      if (a[d + i] >= p)
585      {
586        a[d + i] -= p;
587      }
588    }
589
590    while(dega >= 0 && a[dega] == 0)
591    {
592      dega--;
593    }
594  }
595}
596
597
598void quo (unsigned long *a, unsigned long *q, unsigned long p, int &dega,
599          int degq)
600{
601  unsigned degres = dega - degq;
602  unsigned long *result = new unsigned long[degres + 1];
603
604  // initialize to zero
605  for (int i = 0; i <= degres; i++)
606  {
607    result[i] = 0;
608  }
609
610  while(degq <= dega)
611  {
612    unsigned d = dega - degq;
613    unsigned long inv = modularInverse (q[degq], p);
614    result[d] = multMod (a[dega], inv, p);
615    for(int i = degq; i >= 0; i--)
616    {
617      unsigned long tmp = p - multMod (result[d], q[i], p);
618      a[d + i] += tmp;
619      if (a[d + i] >= p)
620      {
621        a[d + i] -= p;
622      }
623    }
624
625    while(dega >= 0 && a[dega] == 0)
626    {
627      dega--;
628    }
629  }
630
631  // copy result into a
632  for(int i = 0; i <= degres; i++)
633  {
634    a[i] = result[i];
635  }
636  // set all following entries of a to zero
637  for(int i = degres + 1; i <= degq + degres; i++)
638  {
639    a[i] = 0;
640  }
641
642  dega = degres;
643
644  delete[]result;
645}
646
647
648void mult (unsigned long *result, unsigned long *a, unsigned long *b,
649           unsigned long p, int dega, int degb)
650{
651  // NOTE: we assume that every entry in result is preinitialized to zero!
652
653  for(int i = 0; i <= dega; i++)
654  {
655    for(int j = 0; j <= degb; j++)
656    {
657      result[i + j] += multMod (a[i], b[j], p);
658      if (result[i + j] >= p)
659      {
660        result[i + j] -= p;
661      }
662    }
663  }
664}
665
666
667int gcd (unsigned long *g, unsigned long *a, unsigned long *b,
668         unsigned long p, int dega, int degb)
669{
670  unsigned long *tmp1 = new unsigned long[dega + 1];
671  unsigned long *tmp2 = new unsigned long[degb + 1];
672  for(int i = 0; i <= dega; i++)
673  {
674    tmp1[i] = a[i];
675  }
676  for(int i = 0; i <= degb; i++)
677  {
678    tmp2[i] = b[i];
679  }
680  int degtmp1 = dega;
681  int degtmp2 = degb;
682
683  unsigned long *swappol;
684  int swapdeg;
685
686  while(degtmp2 >= 0)
687  {
688    rem (tmp1, tmp2, p, degtmp1, degtmp2);
689    swappol = tmp1;
690    tmp1 = tmp2;
691    tmp2 = swappol;
692
693    swapdeg = degtmp1;
694    degtmp1 = degtmp2;
695    degtmp2 = swapdeg;
696  }
697
698  for(int i = 0; i <= degtmp1; i++)
699  {
700    g[i] = tmp1[i];
701  }
702
703  delete[]tmp1;
704  delete[]tmp2;
705
706  return degtmp1;
707}
708
709
710int lcm (unsigned long *l, unsigned long *a, unsigned long *b,
711         unsigned long p, int dega, int degb)
712{
713  unsigned long *g = new unsigned long[dega + 1];
714  // initialize entries of g to zero
715  for(int i = 0; i <= dega; i++)
716  {
717    g[i] = 0;
718  }
719
720  int degg = gcd (g, a, b, p, dega, degb);
721
722  if(degg > 0)
723  {
724    // non-trivial gcd, so compute a = (a/g)
725    quo (a, g, p, dega, degg);
726  }
727  mult (l, a, b, p, dega, degb);
728
729  // normalize
730  if(l[dega + degb + 1] != 1)
731  {
732    unsigned long inv = modularInverse (l[dega + degb], p);
733    for(int i = 0; i <= dega + degb; i++)
734    {
735      l[i] = multMod (l[i], inv, p);
736    }
737  }
738
739  return dega + degb;
740}
741
742
743// computes the gcd and the cofactors of u and v
744// gcd(u,v) = u3 = u*u1 + v*u2
745unsigned long modularInverse (long long x, long long p)
746{
747  long long u1 = 1;
748  long long u2 = 0;
749  long long u3 = x;
750  long long v1 = 0;
751  long long v2 = 1;
752  long long v3 = p;
753
754  long long q, t1, t2, t3;
755  while(v3 != 0)
756  {
757    q = u3 / v3;
758    t1 = u1 - q * v1;
759    t2 = u2 - q * v2;
760    t3 = u3 - q * v3;
761    u1 = v1;
762    u2 = v2;
763    u3 = v3;
764    v1 = t1;
765    v2 = t2;
766    v3 = t3;
767  }
768
769  if(u1 < 0)
770  {
771    u1 += p;
772  }
773
774  return (unsigned long) u1;
775}
776
Note: See TracBrowser for help on using the repository browser.