source: git/Singular/minpoly.cc @ 33b509

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