source: git/Singular/MinorProcessor.cc @ 7b8818

spielwiese
Last change on this file since 7b8818 was 2e4ec14, checked in by Yue Ren <ren@…>, 11 years ago
fix: -Wunused-parameter warnings
  • Property mode set to 100644
File size: 58.8 KB
Line 
1#include "config.h"
2#include <kernel/mod2.h>
3
4#include "MinorProcessor.h"
5
6#include <polys/kbuckets.h>
7
8#include <kernel/structs.h>
9#include <kernel/polys.h>
10#include <kernel/febase.h>
11#include <kernel/kstd1.h>
12
13#include <kernel/ideals.h>
14
15using namespace std;
16
17#ifdef COUNT_AND_PRINT_OPERATIONS
18long addsPoly        = 0;    /* for the number of additions of two polynomials */
19long multsPoly       = 0;    /* for the number of multiplications of two polynomials */
20long addsPolyForDiv  = 0;    /* for the number of additions of two polynomials for
21                                polynomial division part */
22long multsPolyForDiv = 0;    /* for the number of multiplications of two polynomials
23                                for polynomial division part */
24long multsMon        = 0;    /* for the number of multiplications of two monomials */
25long multsMonForDiv  = 0;    /* for the number of m-m-multiplications for polynomial
26                                division part */
27long savedMultsMFD   = 0;    /* number of m-m-multiplications that could be saved
28                                when polynomial division would be optimal
29                                (if p / t1 = t2 + ..., then t1 * t2 = LT(p), i.e.,
30                                this multiplication need not be performed which
31                                would save one m-m-multiplication) */
32long divsMon         = 0;    /* for the number of divisions of two monomials;
33                                these are all guaranteed to work, i.e., m1/m2 only
34                                when exponentVector(m1) >= exponentVector(m2) */
35void printCounters (char* prefix, bool resetToZero)
36{
37  printf("%s [p+p(div) | p*p(div) | m*m(div, -save) | m/m ]", prefix);
38  printf(" = [%ld(%ld) | %ld(%ld) | %ld(%d, -%ld) | %ld]\n",
39         addsPoly, addsPolyForDiv, multsPoly, multsPolyForDiv,
40         multsMon, multsMonForDiv, savedMultsMFD, divsMon);
41  if (resetToZero)
42  {
43    multsMon = 0; addsPoly = 0; multsPoly = 0; divsMon = 0;
44    savedMultsMFD = 0; multsMonForDiv = 0; addsPolyForDiv = 0;
45    multsPolyForDiv = 0;
46  }
47}
48#endif
49/* COUNT_AND_PRINT_OPERATIONS */
50
51void MinorProcessor::print() const
52{
53  PrintS(this->toString().c_str());
54}
55
56int MinorProcessor::getBestLine (const int k, const MinorKey& mk) const
57{
58  /* This method identifies the row or column with the most zeros.
59     The returned index (bestIndex) is absolute within the pre-
60     defined matrix.
61     If some row has the most zeros, then the absolute (0-based)
62     row index is returned.
63     If, contrariwise, some column has the most zeros, then -1 minus
64     the absolute (0-based) column index is returned. */
65  int numberOfZeros = 0;
66  int bestIndex = 100000;    /* We start with an invalid row/column index. */
67  int maxNumberOfZeros = -1; /* We update this variable whenever we find
68                                a new so-far optimal row or column. */
69  for (int r = 0; r < k; r++)
70  {
71    /* iterate through all k rows of the momentary minor */
72    int absoluteR = mk.getAbsoluteRowIndex(r);
73    numberOfZeros = 0;
74    for (int c = 0; c < k; c++)
75    {
76      int absoluteC = mk.getAbsoluteColumnIndex(c);
77      if (isEntryZero(absoluteR, absoluteC)) numberOfZeros++;
78    }
79    if (numberOfZeros > maxNumberOfZeros)
80    {
81      /* We found a new best line which is a row. */
82      bestIndex = absoluteR;
83      maxNumberOfZeros = numberOfZeros;
84    }
85  };
86  for (int c = 0; c < k; c++)
87  {
88    int absoluteC = mk.getAbsoluteColumnIndex(c);
89    numberOfZeros = 0;
90    for (int r = 0; r < k; r++)
91    {
92      int absoluteR = mk.getAbsoluteRowIndex(r);
93      if (isEntryZero(absoluteR, absoluteC)) numberOfZeros++;
94    }
95    if (numberOfZeros > maxNumberOfZeros)
96    {
97      /* We found a new best line which is a column. So we transform
98         the return value. Note that we can easily retrieve absoluteC
99         from bestLine: absoluteC = - 1 - bestLine. */
100      bestIndex = - absoluteC - 1;
101      maxNumberOfZeros = numberOfZeros;
102    }
103  };
104  return bestIndex;
105}
106
107void MinorProcessor::setMinorSize(const int minorSize)
108{
109  _minorSize = minorSize;
110  _minor.reset();
111}
112
113bool MinorProcessor::hasNextMinor()
114{
115  return setNextKeys(_minorSize);
116}
117
118void MinorProcessor::getCurrentRowIndices(int* const target) const
119{
120  return _minor.getAbsoluteRowIndices(target);
121}
122
123void MinorProcessor::getCurrentColumnIndices(int* const target) const
124{
125  return _minor.getAbsoluteColumnIndices(target);
126}
127
128void MinorProcessor::defineSubMatrix(const int numberOfRows,
129                                     const int* rowIndices,
130                                     const int numberOfColumns,
131                                     const int* columnIndices)
132{
133  /* The method assumes ascending row and column indices in the
134     two argument arrays. These indices are understood to be zero-based.
135     The method will set the two arrays of ints in _container.
136     Example: The indices 0, 2, 3, 7 will be converted to an array with
137     one int representing the binary number 10001101
138     (check bits from right to left). */
139
140  _containerRows = numberOfRows;
141  int highestRowIndex = rowIndices[numberOfRows - 1];
142  int rowBlockCount = (highestRowIndex / 32) + 1;
143  unsigned int *rowBlocks=new unsigned int[rowBlockCount];
144  for (int i = 0; i < rowBlockCount; i++) rowBlocks[i] = 0;
145  for (int i = 0; i < numberOfRows; i++)
146  {
147    int blockIndex = rowIndices[i] / 32;
148    int offset = rowIndices[i] % 32;
149    rowBlocks[blockIndex] += (1 << offset);
150  }
151
152  _containerColumns = numberOfColumns;
153  int highestColumnIndex = columnIndices[numberOfColumns - 1];
154  int columnBlockCount = (highestColumnIndex / 32) + 1;
155  unsigned *columnBlocks=new unsigned[columnBlockCount];
156  for (int i = 0; i < columnBlockCount; i++) columnBlocks[i] = 0;
157  for (int i = 0; i < numberOfColumns; i++)
158  {
159    int blockIndex = columnIndices[i] / 32;
160    int offset = columnIndices[i] % 32;
161    columnBlocks[blockIndex] += (1 << offset);
162  }
163
164  _container.set(rowBlockCount, rowBlocks, columnBlockCount, columnBlocks);
165  delete[] columnBlocks;
166  delete[] rowBlocks;
167}
168
169bool MinorProcessor::setNextKeys(const int k)
170{
171  /* This method moves _minor to the next valid (k x k)-minor within
172     _container. It returns true iff this is successful, i.e. iff
173     _minor did not already encode the terminal (k x k)-minor. */
174  if (_minor.compare(MinorKey(0, 0, 0, 0)) == 0)
175  {
176    /* This means that we haven't started yet. Thus, we are about
177       to compute the first (k x k)-minor. */
178    _minor.selectFirstRows(k, _container);
179    _minor.selectFirstColumns(k, _container);
180    return true;
181  }
182  else if (_minor.selectNextColumns(k, _container))
183  {
184    /* Here we were able to pick a next subset of columns
185       within the same subset of rows. */
186    return true;
187  }
188  else if (_minor.selectNextRows(k, _container))
189  {
190    /* Here we were not able to pick a next subset of columns
191       within the same subset of rows. But we could pick a next
192       subset of rows. We must hence reset the subset of columns: */
193    _minor.selectFirstColumns(k, _container);
194    return true;
195  }
196  else
197  {
198    /* We were neither able to pick a next subset
199       of columns nor of rows. I.e., we have iterated through
200       all sensible choices of subsets of rows and columns. */
201    return false;
202  }
203}
204
205bool MinorProcessor::isEntryZero (const int /*absoluteRowIndex*/,
206                                  const int /*absoluteColumnIndex*/) const
207{
208  assume(false);
209  return false;
210}
211
212string MinorProcessor::toString () const
213{
214  assume(false);
215  return "";
216}
217
218int MinorProcessor::IOverJ(const int i, const int j)
219{
220  /* This is a non-recursive implementation. */
221  assume( (i >= 0) && (j >= 0) && (i >= j));
222  if (j == 0 || i == j) return 1;
223  int result = 1;
224  for (int k = i - j + 1; k <= i; k++) result *= k;
225  /* Now, result = (i - j + 1) * ... * i. */
226  for (int k = 2; k <= j; k++) result /= k;
227  /* Now, result = (i - j + 1) * ... * i / 1 / 2 ...
228     ... / j = i! / j! / (i - j)!. */
229  return result;
230}
231
232int MinorProcessor::Faculty(const int i)
233{
234  /* This is a non-recursive implementation. */
235  assume(i >= 0);
236  int result = 1;
237  for (int j = 1; j <= i; j++) result *= j;
238  // Now, result = 1 * 2 * ... * i = i!
239  return result;
240}
241
242int MinorProcessor::NumberOfRetrievals (const int rows, const int columns,
243                                        const int containerMinorSize,
244                                        const int minorSize,
245                                        const bool multipleMinors)
246{
247  /* This method computes the number of potential retrievals
248     of a single minor when computing all minors of a given size
249     within a matrix of given size. */
250  int result = 0;
251  if (multipleMinors)
252  {
253    /* Here, we would like to compute all minors of size
254       containerMinorSize x containerMinorSize in a matrix
255       of size rows x columns.
256       Then, we need to retrieve any minor of size
257       minorSize x minorSize exactly n times, where n is as
258       follows: */
259    result = IOverJ(rows - minorSize, containerMinorSize - minorSize)
260           * IOverJ(columns - minorSize, containerMinorSize - minorSize)
261           * Faculty(containerMinorSize - minorSize);
262  }
263  else
264  {
265    /* Here, we would like to compute just one minor of size
266       containerMinorSize x containerMinorSize. Then, we need
267       to retrieve any minor of size minorSize x minorSize exactly
268       (containerMinorSize - minorSize)! times: */
269    result = Faculty(containerMinorSize - minorSize);
270  }
271  return result;
272}
273
274MinorProcessor::MinorProcessor ()
275{
276  _container = MinorKey(0, 0, 0, 0);
277  _minor = MinorKey(0, 0, 0, 0);
278  _containerRows = 0;
279  _containerColumns = 0;
280  _minorSize = 0;
281  _rows = 0;
282  _columns = 0;
283}
284
285MinorProcessor::~MinorProcessor () { }
286
287IntMinorProcessor::IntMinorProcessor ()
288{
289  _intMatrix = 0;
290}
291
292string IntMinorProcessor::toString () const
293{
294  char h[32];
295  string t = "";
296  string s = "IntMinorProcessor:";
297  s += "\n   matrix: ";
298  sprintf(h, "%d", _rows); s += h;
299  s += " x ";
300  sprintf(h, "%d", _columns); s += h;
301  for (int r = 0; r < _rows; r++)
302  {
303    s += "\n      ";
304    for (int c = 0; c < _columns; c++)
305    {
306      sprintf(h, "%d", getEntry(r, c)); t = h;
307      for (int k = 0; k < int(4 - strlen(h)); k++) s += " ";
308      s += t;
309    }
310  }
311  int myIndexArray[500];
312  s += "\n   considered submatrix has row indices: ";
313  _container.getAbsoluteRowIndices(myIndexArray);
314  for (int k = 0; k < _containerRows; k++)
315  {
316    if (k != 0) s += ", ";
317    sprintf(h, "%d", myIndexArray[k]); s += h;
318  }
319  s += " (first row of matrix has index 0)";
320  s += "\n   considered submatrix has column indices: ";
321  _container.getAbsoluteColumnIndices(myIndexArray);
322  for (int k = 0; k < _containerColumns; k++)
323  {
324    if (k != 0) s += ", ";
325    sprintf(h, "%d", myIndexArray[k]); s += h;
326  }
327  s += " (first column of matrix has index 0)";
328  s += "\n   size of considered minor(s): ";
329  sprintf(h, "%d", _minorSize); s += h;
330  s += "x";
331  s += h;
332  return s;
333}
334
335IntMinorProcessor::~IntMinorProcessor()
336{
337  /* free memory of _intMatrix */
338  delete [] _intMatrix; _intMatrix = 0;
339}
340
341bool IntMinorProcessor::isEntryZero (const int absoluteRowIndex,
342                                     const int absoluteColumnIndex) const
343{
344  return getEntry(absoluteRowIndex, absoluteColumnIndex) == 0;
345}
346
347void IntMinorProcessor::defineMatrix (const int numberOfRows,
348                                      const int numberOfColumns,
349                                      const int* matrix)
350{
351  /* free memory of _intMatrix */
352  delete [] _intMatrix; _intMatrix = 0;
353
354  _rows = numberOfRows;
355  _columns = numberOfColumns;
356
357  /* allocate memory for new entries in _intMatrix */
358  int n = _rows * _columns;
359  _intMatrix = new int[n];
360
361  /* copying values from one-dimensional method
362     parameter "matrix" */
363  for (int i = 0; i < n; i++)
364    _intMatrix[i] = matrix[i];
365}
366
367IntMinorValue IntMinorProcessor::getMinor(const int dimension,
368                                          const int* rowIndices,
369                                          const int* columnIndices,
370                                          Cache<MinorKey, IntMinorValue>& c,
371                                          const int characteristic,
372                                          const ideal& iSB)
373{
374  defineSubMatrix(dimension, rowIndices, dimension, columnIndices);
375  _minorSize = dimension;
376  /* call a helper method which recursively computes the minor using the
377     cache c: */
378  return getMinorPrivateLaplace(dimension, _container, false, c,
379                                characteristic, iSB);
380}
381
382IntMinorValue IntMinorProcessor::getMinor(const int dimension,
383                                          const int* rowIndices,
384                                          const int* columnIndices,
385                                          const int characteristic,
386                                          const ideal& iSB,
387                                          const char* algorithm)
388{
389  defineSubMatrix(dimension, rowIndices, dimension, columnIndices);
390  _minorSize = dimension;
391
392  /* call a helper method which computes the minor (without a cache): */
393  if (strcmp(algorithm, "Laplace") == 0)
394    return getMinorPrivateLaplace(_minorSize, _container, characteristic,
395                                  iSB);
396  else if (strcmp(algorithm, "Bareiss") == 0)
397    return getMinorPrivateBareiss(_minorSize, _container, characteristic,
398                                  iSB);
399  else assume(false);
400
401  /* The following code is never reached and just there to make the
402     compiler happy: */
403  return IntMinorValue();
404}
405
406IntMinorValue IntMinorProcessor::getNextMinor(const int characteristic,
407                                              const ideal& iSB,
408                                              const char* algorithm)
409{
410  /* call a helper method which computes the minor (without a cache): */
411  if (strcmp(algorithm, "Laplace") == 0)
412    return getMinorPrivateLaplace(_minorSize, _minor, characteristic, iSB);
413  else if (strcmp(algorithm, "Bareiss") == 0)
414    return getMinorPrivateBareiss(_minorSize, _minor, characteristic, iSB);
415  else assume(false);
416 
417  /* The following code is never reached and just there to make the
418     compiler happy: */
419  return IntMinorValue();
420}
421
422IntMinorValue IntMinorProcessor::getNextMinor(Cache<MinorKey,
423                                              IntMinorValue>& c,
424                                              const int characteristic,
425                                              const ideal& iSB)
426{
427    /* computation with cache */
428    return getMinorPrivateLaplace(_minorSize, _minor, true, c, characteristic,
429                                  iSB);
430}
431
432/* computes the reduction of an integer i modulo an ideal
433   which captures a std basis */
434int getReduction (const int i, const ideal& iSB)
435{
436  if (i == 0) return 0;
437  poly f = pISet(i);
438  poly g = kNF(iSB, currRing->qideal, f);
439  int result = 0;
440  if (g != NULL) result = n_Int(pGetCoeff(g), currRing->cf);
441  pDelete(&f);
442  pDelete(&g);
443  return result;
444}
445
446IntMinorValue IntMinorProcessor::getMinorPrivateLaplace(
447     const int k,
448     const MinorKey& mk,
449     const int characteristic,
450     const ideal& iSB)
451{
452  assume(k > 0); /* k is the minor's dimension; the minor must be at least
453                    1x1 */
454  /* The method works by recursion, and using Lapace's Theorem along the
455     row/column with the most zeros. */
456  if (k == 1)
457  {
458    int e = getEntry(mk.getAbsoluteRowIndex(0), mk.getAbsoluteColumnIndex(0));
459    if (characteristic != 0) e = e % characteristic;
460    if (iSB != 0) e = getReduction(e, iSB);
461    return IntMinorValue(e, 0, 0, 0, 0, -1, -1); /* "-1" is to signal that any
462                                                    statistics about the number
463                                                    of retrievals does not make
464                                                    sense, as we do not use a
465                                                    cache. */
466  }
467  else
468  {
469    /* Here, the minor must be 2x2 or larger. */
470    int b = getBestLine(k, mk);                   /* row or column with most
471                                                     zeros */
472    int result = 0;                               /* This will contain the
473                                                     value of the minor. */
474    int s = 0; int m = 0; int as = 0; int am = 0; /* counters for additions and
475                                                     multiplications, ..."a*"
476                                                     for accumulated operation
477                                                     counters */
478    bool hadNonZeroEntry = false;
479    if (b >= 0)
480    {
481      /* This means that the best line is the row with absolute (0-based)
482         index b.
483         Using Laplace, the sign of the contributing minors must be iterating;
484         the initial sign depends on the relative index of b in minorRowKey: */
485      int sign = (mk.getRelativeRowIndex(b) % 2 == 0 ? 1 : -1);
486      for (int c = 0; c < k; c++) /* This iterates over all involved columns. */
487      {
488        int absoluteC = mk.getAbsoluteColumnIndex(c);
489        if (getEntry(b, absoluteC) != 0) /* Only then do we have to consider
490                                            this sub-determinante. */
491        {
492          hadNonZeroEntry = true;
493          /* Next MinorKey is mk with row b and column absoluteC omitted: */
494          MinorKey subMk = mk.getSubMinorKey(b, absoluteC);
495          IntMinorValue mv = getMinorPrivateLaplace(k - 1, subMk,
496                             characteristic, iSB);  /* recursive call */
497          m += mv.getMultiplications();
498          s += mv.getAdditions();
499          am += mv.getAccumulatedMultiplications();
500          as += mv.getAccumulatedAdditions();
501          /* adding sub-determinante times matrix entry
502             times appropriate sign: */
503          result += sign * mv.getResult() * getEntry(b, absoluteC);
504
505          if (characteristic != 0) result = result % characteristic;
506          s++; m++; as++, am++; /* This is for the last addition and
507                                   multiplication. */
508        }
509        sign = - sign; /* alternating the sign */
510      }
511    }
512    else
513    {
514      b = - b - 1;
515      /* This means that the best line is the column with absolute (0-based)
516         index b.
517         Using Laplace, the sign of the contributing minors must be iterating;
518         the initial sign depends on the relative index of b in
519         minorColumnKey: */
520      int sign = (mk.getRelativeColumnIndex(b) % 2 == 0 ? 1 : -1);
521      for (int r = 0; r < k; r++) /* This iterates over all involved rows. */
522      {
523        int absoluteR = mk.getAbsoluteRowIndex(r);
524        if (getEntry(absoluteR, b) != 0) /* Only then do we have to consider
525                                            this sub-determinante. */
526        {
527          hadNonZeroEntry = true;
528          /* Next MinorKey is mk with row absoluteR and column b omitted. */
529          MinorKey subMk = mk.getSubMinorKey(absoluteR, b);
530          IntMinorValue mv = getMinorPrivateLaplace(k - 1, subMk, characteristic, iSB); /* recursive call */
531          m += mv.getMultiplications();
532          s += mv.getAdditions();
533          am += mv.getAccumulatedMultiplications();
534          as += mv.getAccumulatedAdditions();
535          /* adding sub-determinante times matrix entry
536             times appropriate sign: */
537          result += sign * mv.getResult() * getEntry(absoluteR, b);
538          if (characteristic != 0) result = result % characteristic;
539          s++; m++; as++, am++; /* This is for the last addition and
540                                   multiplication. */
541        }
542        sign = - sign; /* alternating the sign */
543      }
544    }
545    if (hadNonZeroEntry)
546    {
547      s--; as--; /* first addition was 0 + ..., so we do not count it */
548    }
549    if (s < 0) s = 0; /* may happen when all subminors are zero and no
550                         addition needs to be performed */
551    if (as < 0) as = 0; /* may happen when all subminors are zero and no
552                           addition needs to be performed */
553    if (iSB != 0) result = getReduction(result, iSB);
554    IntMinorValue newMV(result, m, s, am, as, -1, -1);
555    /* "-1" is to signal that any statistics about the number of retrievals
556       does not make sense, as we do not use a cache. */
557    return newMV;
558  }
559}
560
561/* This method can only be used in the case of coefficients
562   coming from a field or at least from an integral domain. */
563IntMinorValue IntMinorProcessor::getMinorPrivateBareiss(
564     const int k,
565     const MinorKey& mk,
566     const int characteristic,
567     const ideal& iSB)
568{
569  assume(k > 0); /* k is the minor's dimension; the minor must be at least
570                    1x1 */
571  int *theRows=new int[k]; mk.getAbsoluteRowIndices(theRows);
572  int *theColumns=new int[k]; mk.getAbsoluteColumnIndices(theColumns);
573  /* the next line provides the return value for the case k = 1 */
574  int e = getEntry(theRows[0], theColumns[0]);
575  if (characteristic != 0) e = e % characteristic;
576  if (iSB != 0) e = getReduction(e, iSB);
577  IntMinorValue mv(e, 0, 0, 0, 0, -1, -1);
578  if (k > 1)
579  {
580    /* the matrix to perform Bareiss with */
581    long *tempMatrix=new long[k * k];
582    /* copy correct set of entries from _intMatrix to tempMatrix */
583    int i = 0;
584    for (int r = 0; r < k; r++)
585      for (int c = 0; c < k; c++)
586      {
587        e = getEntry(theRows[r], theColumns[c]);
588        if (characteristic != 0) e = e % characteristic;
589        tempMatrix[i++] = e;
590      }
591    /* Bareiss algorithm operating on tempMatrix which is at least 2x2 */
592    int sign = 1;   /* This will store the correct sign resulting
593                       from permuting the rows of tempMatrix. */
594    int *rowPermutation=new int[k];
595                    /* This is for storing the permutation of rows
596                       resulting from searching for a non-zero
597                       pivot element. */
598    for (int i = 0; i < k; i++) rowPermutation[i] = i;
599    int divisor = 1;   /* the Bareiss divisor */
600    for (int r = 0; r <= k - 2; r++)
601    {
602      /* look for a non-zero entry in column r: */
603      int i = r;
604      while ((i < k) && (tempMatrix[rowPermutation[i] * k + r] == 0))
605        i++;
606      if (i == k)
607        /* There is no non-zero entry; hence the minor is zero. */
608        return IntMinorValue(0, 0, 0, 0, 0, -1, -1);
609      if (i != r)
610      {
611        /* We swap the rows with indices r and i: */
612        int j = rowPermutation[i];
613        rowPermutation[i] = rowPermutation[r];
614        rowPermutation[r] = j;
615        /* Now we know that tempMatrix[rowPermutation[r] * k + r] is not zero.
616           But carefull; we have to negate the sign, as there is always an odd
617           number of row transpositions to swap two given rows of a matrix. */
618        sign = -sign;
619      }
620      if (r >= 1) divisor = tempMatrix[rowPermutation[r - 1] * k + r - 1];
621      for (int rr = r + 1; rr < k; rr++)
622        for (int cc = r + 1; cc < k; cc++)
623        {
624          e = rowPermutation[rr] * k + cc;
625          /* Attention: The following may cause an overflow and
626             thus a wrong result: */
627          tempMatrix[e] = tempMatrix[e] * tempMatrix[rowPermutation[r] * k + r]
628                         - tempMatrix[rowPermutation[r] * k + cc]
629                         * tempMatrix[rowPermutation[rr] * k + r];
630          /* The following is, by theory, always a division without
631             remainder: */
632          tempMatrix[e] = tempMatrix[e] / divisor;
633          if (characteristic != 0)
634            tempMatrix[e] = tempMatrix[e] % characteristic;
635        }
636      delete[] rowPermutation;
637      delete[] tempMatrix;
638    }
639    int theValue = sign * tempMatrix[rowPermutation[k - 1] * k + k - 1];
640    if (iSB != 0) theValue = getReduction(theValue, iSB);
641    mv = IntMinorValue(theValue, 0, 0, 0, 0, -1, -1);
642  }
643  delete [] theRows;
644  delete [] theColumns;
645  return mv;
646}
647
648int IntMinorProcessor::getEntry (const int rowIndex,
649                                 const int columnIndex) const
650{
651  return _intMatrix[rowIndex * _columns + columnIndex];
652}
653
654IntMinorValue IntMinorProcessor::getMinorPrivateLaplace(
655     const int k, const MinorKey& mk,
656     const bool multipleMinors,
657     Cache<MinorKey, IntMinorValue>& cch,
658     const int characteristic, const ideal& iSB)
659{
660  assume(k > 0); /* k is the minor's dimension; the minor must be at least
661                    1x1 */
662  /* The method works by recursion, and using Lapace's Theorem along
663     the row/column with the most zeros. */
664  if (k == 1)
665  {
666    int e = getEntry(mk.getAbsoluteRowIndex(0), mk.getAbsoluteColumnIndex(0));
667    if (characteristic != 0) e = e % characteristic;
668    if (iSB != 0) e = getReduction(e, iSB);
669    return IntMinorValue(e, 0, 0, 0, 0, -1, -1);
670    /* we set "-1" as, for k == 1, we do not have any cache retrievals */
671  }
672  else
673  {
674    int b = getBestLine(k, mk);                   /* row or column with
675                                                     most zeros */
676    int result = 0;                               /* This will contain the
677                                                     value of the minor. */
678    int s = 0; int m = 0; int as = 0; int am = 0; /* counters for additions
679                                                     and multiplications,
680                                                     ..."a*" for
681                                                     accumulated operation
682                                                     counters */
683    IntMinorValue mv(0, 0, 0, 0, 0, 0, 0);        /* for storing all
684                                                     intermediate minors */
685    bool hadNonZeroEntry = false;
686    if (b >= 0)
687    {
688      /* This means that the best line is the row with absolute (0-based)
689         index b.
690         Using Laplace, the sign of the contributing minors must be
691         iterating; the initial sign depends on the relative index of b
692         in minorRowKey: */
693      int sign = (mk.getRelativeRowIndex(b) % 2 == 0 ? 1 : -1);
694      for (int c = 0; c < k; c++) /* This iterates over all involved
695                                     columns. */
696      {
697        int absoluteC = mk.getAbsoluteColumnIndex(c);
698        if (getEntry(b, absoluteC) != 0) /* Only then do we have to consider
699                                            this sub-determinante. */
700        {
701          hadNonZeroEntry = true;
702          /* Next MinorKey is mk with row b and column absoluteC omitted. */
703          MinorKey subMk = mk.getSubMinorKey(b, absoluteC);
704          if (cch.hasKey(subMk))
705          { /* trying to find the result in the cache */
706              mv = cch.getValue(subMk);
707              mv.incrementRetrievals(); /* once more, we made use of the cached
708                                           value for key mk */
709              cch.put(subMk, mv); /* We need to do this with "put", as the
710                                     (altered) number of retrievals may have
711                                     an impact on the internal ordering among
712                                     the cached entries. */
713          }
714          else
715          {
716              mv = getMinorPrivateLaplace(k - 1, subMk, multipleMinors, cch,
717                   characteristic, iSB); /* recursive call */
718              /* As this minor was not in the cache, we count the additions
719                 and multiplications that we needed to perform in the
720                 recursive call: */
721              m += mv.getMultiplications();
722              s += mv.getAdditions();
723          }
724          /* In any case, we count all nested operations in the accumulative
725             counters: */
726          am += mv.getAccumulatedMultiplications();
727          as += mv.getAccumulatedAdditions();
728          /* adding sub-determinante times matrix entry times appropriate
729             sign */
730          result += sign * mv.getResult() * getEntry(b, absoluteC);
731          if (characteristic != 0) result = result % characteristic;
732          s++; m++; as++; am++; /* This is for the last addition and
733                                   multiplication. */
734        }
735        sign = - sign; /* alternating the sign */
736      }
737    }
738    else
739    {
740      b = - b - 1;
741      /* This means that the best line is the column with absolute (0-based)
742         index b.
743         Using Laplace, the sign of the contributing minors must be iterating;
744         the initial sign depends on the relative index of b in
745         minorColumnKey: */
746      int sign = (mk.getRelativeColumnIndex(b) % 2 == 0 ? 1 : -1);
747      for (int r = 0; r < k; r++) /* This iterates over all involved rows. */
748      {
749        int absoluteR = mk.getAbsoluteRowIndex(r);
750        if (getEntry(absoluteR, b) != 0) /* Only then do we have to consider
751                                            this sub-determinante. */
752        {
753          hadNonZeroEntry = true;
754          /* Next MinorKey is mk with row absoluteR and column b omitted. */
755          MinorKey subMk = mk.getSubMinorKey(absoluteR, b);
756          if (cch.hasKey(subMk))
757          { /* trying to find the result in the cache */
758            mv = cch.getValue(subMk);
759            mv.incrementRetrievals(); /* once more, we made use of the cached
760                                         value for key mk */
761            cch.put(subMk, mv); /* We need to do this with "put", as the
762                                   (altered) number of retrievals may have an
763                                   impact on the internal ordering among the
764                                   cached entries. */
765          }
766          else
767          {
768            mv = getMinorPrivateLaplace(k - 1, subMk, multipleMinors, cch, characteristic, iSB); /* recursive call */
769            /* As this minor was not in the cache, we count the additions and
770               multiplications that we needed to do in the recursive call: */
771            m += mv.getMultiplications();
772            s += mv.getAdditions();
773          }
774          /* In any case, we count all nested operations in the accumulative
775             counters: */
776          am += mv.getAccumulatedMultiplications();
777          as += mv.getAccumulatedAdditions();
778          /* adding sub-determinante times matrix entry times appropriate
779             sign: */
780          result += sign * mv.getResult() * getEntry(absoluteR, b);
781          if (characteristic != 0) result = result % characteristic;
782          s++; m++; as++; am++; /* This is for the last addition and
783                                   multiplication. */
784        }
785        sign = - sign; /* alternating the sign */
786      }
787    }
788    /* Let's cache the newly computed minor: */
789    int potentialRetrievals = NumberOfRetrievals(_containerRows,
790                                                 _containerColumns,
791                                                 _minorSize, k,
792                                                 multipleMinors);
793    if (hadNonZeroEntry)
794    {
795      s--; as--; /* first addition was 0 + ..., so we do not count it */
796    }
797    if (s < 0) s = 0; /* may happen when all subminors are zero and no
798                         addition needs to be performed */
799    if (as < 0) as = 0; /* may happen when all subminors are zero and no
800                           addition needs to be performed */
801    if (iSB != 0) result = getReduction(result, iSB);
802    IntMinorValue newMV(result, m, s, am, as, 1, potentialRetrievals);
803    cch.put(mk, newMV); /* Here's the actual put inside the cache. */
804    return newMV;
805  }
806}
807
808PolyMinorProcessor::PolyMinorProcessor ()
809{
810  _polyMatrix = 0;
811}
812
813poly PolyMinorProcessor::getEntry (const int rowIndex,
814                                   const int columnIndex) const
815{
816  return _polyMatrix[rowIndex * _columns + columnIndex];
817}
818
819bool PolyMinorProcessor::isEntryZero (const int absoluteRowIndex,
820                                      const int absoluteColumnIndex) const
821{
822  return getEntry(absoluteRowIndex, absoluteColumnIndex) == NULL;
823}
824
825string PolyMinorProcessor::toString () const
826{
827  char h[32];
828  string t = "";
829  string s = "PolyMinorProcessor:";
830  s += "\n   matrix: ";
831  sprintf(h, "%d", _rows); s += h;
832  s += " x ";
833  sprintf(h, "%d", _columns); s += h;
834  int myIndexArray[500];
835  s += "\n   considered submatrix has row indices: ";
836  _container.getAbsoluteRowIndices(myIndexArray);
837  for (int k = 0; k < _containerRows; k++)
838  {
839    if (k != 0) s += ", ";
840    sprintf(h, "%d", myIndexArray[k]); s += h;
841  }
842  s += " (first row of matrix has index 0)";
843  s += "\n   considered submatrix has column indices: ";
844  _container.getAbsoluteColumnIndices(myIndexArray);
845  for (int k = 0; k < _containerColumns; k++)
846  {
847    if (k != 0) s += ", ";
848    sprintf(h, "%d", myIndexArray[k]); s += h;
849  }
850  s += " (first column of matrix has index 0)";
851  s += "\n   size of considered minor(s): ";
852  sprintf(h, "%d", _minorSize); s += h;
853  s += "x";
854  s += h;
855  return s;
856}
857
858PolyMinorProcessor::~PolyMinorProcessor()
859{
860  /* free memory of _polyMatrix */
861  int n = _rows * _columns;
862  for (int i = 0; i < n; i++)
863    p_Delete(&_polyMatrix[i], currRing);
864  delete [] _polyMatrix; _polyMatrix = 0;
865}
866
867void PolyMinorProcessor::defineMatrix (const int numberOfRows,
868                                       const int numberOfColumns,
869                                       const poly* polyMatrix)
870{
871  /* free memory of _polyMatrix */
872  int n = _rows * _columns;
873  for (int i = 0; i < n; i++)
874    p_Delete(&_polyMatrix[i], currRing);
875  delete [] _polyMatrix; _polyMatrix = 0;
876
877  _rows = numberOfRows;
878  _columns = numberOfColumns;
879  n = _rows * _columns;
880
881  /* allocate memory for new entries in _polyMatrix */
882  _polyMatrix = new poly[n];
883
884  /* copying values from one-dimensional method
885     parameter "polyMatrix" */
886  for (int i = 0; i < n; i++)
887    _polyMatrix[i] = pCopy(polyMatrix[i]);
888}
889
890PolyMinorValue PolyMinorProcessor::getMinor(const int dimension,
891                                            const int* rowIndices,
892                                            const int* columnIndices,
893                                            Cache<MinorKey, PolyMinorValue>& c,
894                                            const ideal& iSB)
895{
896  defineSubMatrix(dimension, rowIndices, dimension, columnIndices);
897  _minorSize = dimension;
898  /* call a helper method which recursively computes the minor using the cache
899     c: */
900  return getMinorPrivateLaplace(dimension, _container, false, c, iSB);
901}
902
903PolyMinorValue PolyMinorProcessor::getMinor(const int dimension,
904                                            const int* rowIndices,
905                                            const int* columnIndices,
906                                            const char* algorithm,
907                                            const ideal& iSB)
908{
909  defineSubMatrix(dimension, rowIndices, dimension, columnIndices);
910  _minorSize = dimension;
911  /* call a helper method which computes the minor (without using a cache): */
912  if (strcmp(algorithm, "Laplace") == 0)
913    return getMinorPrivateLaplace(_minorSize, _container, iSB);
914  else if (strcmp(algorithm, "Bareiss") == 0)
915    return getMinorPrivateBareiss(_minorSize, _container, iSB);
916  else assume(false);
917
918  /* The following code is never reached and just there to make the
919     compiler happy: */
920  return PolyMinorValue();
921}
922
923PolyMinorValue PolyMinorProcessor::getNextMinor(const char* algorithm,
924                                                const ideal& iSB)
925{
926  /* call a helper method which computes the minor (without using a
927     cache): */
928  if (strcmp(algorithm, "Laplace") == 0)
929    return getMinorPrivateLaplace(_minorSize, _minor, iSB);
930  else if (strcmp(algorithm, "Bareiss") == 0)
931    return getMinorPrivateBareiss(_minorSize, _minor, iSB);
932  else assume(false);
933   
934  /* The following code is never reached and just there to make the
935     compiler happy: */
936  return PolyMinorValue();
937}
938
939PolyMinorValue PolyMinorProcessor::getNextMinor(Cache<MinorKey,
940                                                PolyMinorValue>& c,
941                                                const ideal& iSB)
942{
943    /* computation with cache */
944    return getMinorPrivateLaplace(_minorSize, _minor, true, c, iSB);
945}
946
947/* assumes that all entries in polyMatrix are already reduced w.r.t. iSB */
948PolyMinorValue PolyMinorProcessor::getMinorPrivateLaplace(const int k,
949                                                          const MinorKey& mk,
950                                                          const ideal& iSB)
951{
952  assume(k > 0); /* k is the minor's dimension; the minor must be at least
953                    1x1 */
954  /* The method works by recursion, and using Lapace's Theorem along the
955     row/column with the most zeros. */
956  if (k == 1)
957  {
958    PolyMinorValue pmv(getEntry(mk.getAbsoluteRowIndex(0),
959                                mk.getAbsoluteColumnIndex(0)),
960                       0, 0, 0, 0, -1, -1);
961    /* "-1" is to signal that any statistics about the number of retrievals
962       does not make sense, as we do not use a cache. */
963    return pmv;
964  }
965  else
966  {
967    /* Here, the minor must be 2x2 or larger. */
968    int b = getBestLine(k, mk);                   /* row or column with most
969                                                     zeros */
970    poly result = NULL;                           /* This will contain the
971                                                     value of the minor. */
972    int s = 0; int m = 0; int as = 0; int am = 0; /* counters for additions
973                                                     and multiplications,
974                                                     ..."a*" for accumulated
975                                                     operation counters */
976    bool hadNonZeroEntry = false;
977    if (b >= 0)
978    {
979      /* This means that the best line is the row with absolute (0-based)
980         index b.
981         Using Laplace, the sign of the contributing minors must be iterating;
982         the initial sign depends on the relative index of b in minorRowKey: */
983      int sign = (mk.getRelativeRowIndex(b) % 2 == 0 ? 1 : -1);
984      poly signPoly = NULL;
985      for (int c = 0; c < k; c++) /* This iterates over all involved columns. */
986      {
987        int absoluteC = mk.getAbsoluteColumnIndex(c);
988        if (!isEntryZero(b, absoluteC)) /* Only then do we have to consider
989                                           this sub-determinante. */
990        {
991          hadNonZeroEntry = true;
992          /* Next MinorKey is mk with row b and column absoluteC omitted. */
993          MinorKey subMk = mk.getSubMinorKey(b, absoluteC);
994          /* recursive call: */
995          PolyMinorValue mv = getMinorPrivateLaplace(k - 1, subMk, iSB);
996          m += mv.getMultiplications();
997          s += mv.getAdditions();
998          am += mv.getAccumulatedMultiplications();
999          as += mv.getAccumulatedAdditions();
1000          pDelete(&signPoly);
1001          signPoly = pISet(sign);
1002          poly temp = pp_Mult_qq(mv.getResult(), getEntry(b, absoluteC),
1003                                 currRing);
1004          temp = p_Mult_q(signPoly, temp, currRing);
1005          result = p_Add_q(result, temp, currRing);
1006#ifdef COUNT_AND_PRINT_OPERATIONS
1007          multsPoly++;
1008          addsPoly++;
1009          multsMon += pLength(mv.getResult()) * pLength(getEntry(b, absoluteC));
1010#endif
1011          signPoly = NULL;
1012          s++; m++; as++, am++; /* This is for the addition and multiplication
1013                                   in the previous lines of code. */
1014        }
1015        sign = - sign; /* alternating the sign */
1016      }
1017    }
1018    else
1019    {
1020      b = - b - 1;
1021      /* This means that the best line is the column with absolute (0-based)
1022         index b.
1023         Using Laplace, the sign of the contributing minors must be iterating;
1024         the initial sign depends on the relative index of b in
1025         minorColumnKey: */
1026      int sign = (mk.getRelativeColumnIndex(b) % 2 == 0 ? 1 : -1);
1027      poly signPoly = NULL;
1028      for (int r = 0; r < k; r++) /* This iterates over all involved rows. */
1029      {
1030        int absoluteR = mk.getAbsoluteRowIndex(r);
1031        if (!isEntryZero(absoluteR, b)) /* Only then do we have to consider
1032                                           this sub-determinante. */
1033        {
1034          hadNonZeroEntry = true;
1035          /* This is mk with row absoluteR and column b omitted. */
1036          MinorKey subMk = mk.getSubMinorKey(absoluteR, b);
1037          /* recursive call: */
1038          PolyMinorValue mv = getMinorPrivateLaplace(k - 1, subMk, iSB);
1039          m += mv.getMultiplications();
1040          s += mv.getAdditions();
1041          am += mv.getAccumulatedMultiplications();
1042          as += mv.getAccumulatedAdditions();
1043          pDelete(&signPoly);
1044          signPoly = pISet(sign);
1045          poly temp = pp_Mult_qq(mv.getResult(), getEntry(absoluteR, b),
1046                                 currRing);
1047          temp = p_Mult_q(signPoly, temp, currRing);
1048          result = p_Add_q(result, temp, currRing);
1049#ifdef COUNT_AND_PRINT_OPERATIONS
1050          multsPoly++;
1051          addsPoly++;
1052          multsMon += pLength(mv.getResult()) * pLength(getEntry(absoluteR, b));
1053#endif
1054          signPoly = NULL;
1055          s++; m++; as++, am++; /* This is for the addition and multiplication
1056                                   in the previous lines of code. */
1057        }
1058        sign = - sign; /* alternating the sign */
1059      }
1060    }
1061    if (hadNonZeroEntry)
1062    {
1063      s--; as--; /* first addition was 0 + ..., so we do not count it */
1064#ifdef COUNT_AND_PRINT_OPERATIONS
1065      addsPoly--;
1066#endif
1067    }
1068    if (s < 0) s = 0; /* may happen when all subminors are zero and no
1069                         addition needs to be performed */
1070    if (as < 0) as = 0; /* may happen when all subminors are zero and no
1071                           addition needs to be performed */
1072    if (iSB != 0) result = kNF(iSB, currRing->qideal, result);
1073    PolyMinorValue newMV(result, m, s, am, as, -1, -1);
1074    /* "-1" is to signal that any statistics about the number of retrievals
1075       does not make sense, as we do not use a cache. */
1076    pDelete(&result);
1077    return newMV;
1078  }
1079}
1080
1081/* assumes that all entries in polyMatrix are already reduced w.r.t. iSB */
1082PolyMinorValue PolyMinorProcessor::getMinorPrivateLaplace(
1083     const int k,
1084     const MinorKey& mk,
1085     const bool multipleMinors,
1086     Cache<MinorKey, PolyMinorValue>& cch,
1087     const ideal& iSB)
1088{
1089  assume(k > 0); /* k is the minor's dimension; the minor must be at least
1090                    1x1 */
1091  /* The method works by recursion, and using Lapace's Theorem along
1092     the row/column with the most zeros. */
1093  if (k == 1)
1094  {
1095    PolyMinorValue pmv(getEntry(mk.getAbsoluteRowIndex(0),
1096                                mk.getAbsoluteColumnIndex(0)),
1097                       0, 0, 0, 0, -1, -1);
1098    /* we set "-1" as, for k == 1, we do not have any cache retrievals */
1099    return pmv;
1100  }
1101  else
1102  {
1103    int b = getBestLine(k, mk);                   /* row or column with most
1104                                                     zeros */
1105    poly result = NULL;                           /* This will contain the
1106                                                     value of the minor. */
1107    int s = 0; int m = 0; int as = 0; int am = 0; /* counters for additions
1108                                                     and multiplications,
1109                                                     ..."a*" for accumulated
1110                                                     operation counters */
1111    bool hadNonZeroEntry = false;
1112    if (b >= 0)
1113    {
1114      /* This means that the best line is the row with absolute (0-based)
1115         index b.
1116         Using Laplace, the sign of the contributing minors must be iterating;
1117         the initial sign depends on the relative index of b in
1118         minorRowKey: */
1119      int sign = (mk.getRelativeRowIndex(b) % 2 == 0 ? 1 : -1);
1120      poly signPoly = NULL;
1121      for (int c = 0; c < k; c++) /* This iterates over all involved columns. */
1122      {
1123        int absoluteC = mk.getAbsoluteColumnIndex(c);
1124        if (!isEntryZero(b, absoluteC)) /* Only then do we have to consider
1125                                           this sub-determinante. */
1126        {
1127          hadNonZeroEntry = true;
1128          PolyMinorValue mv; /* for storing all intermediate minors */
1129          /* Next MinorKey is mk with row b and column absoluteC omitted. */
1130          MinorKey subMk = mk.getSubMinorKey(b, absoluteC);
1131          if (cch.hasKey(subMk))
1132          { /* trying to find the result in the cache */
1133            mv = cch.getValue(subMk);
1134            mv.incrementRetrievals(); /* once more, we made use of the cached
1135                                         value for key mk */
1136            cch.put(subMk, mv); /* We need to do this with "put", as the
1137                                   (altered) number of retrievals may have an
1138                                   impact on the internal ordering among cache
1139                                   entries. */
1140          }
1141          else
1142          {
1143            /* recursive call: */
1144            mv = getMinorPrivateLaplace(k - 1, subMk, multipleMinors, cch,
1145                                        iSB);
1146            /* As this minor was not in the cache, we count the additions and
1147               multiplications that we needed to do in the recursive call: */
1148            m += mv.getMultiplications();
1149            s += mv.getAdditions();
1150          }
1151          /* In any case, we count all nested operations in the accumulative
1152             counters: */
1153          am += mv.getAccumulatedMultiplications();
1154          as += mv.getAccumulatedAdditions();
1155          pDelete(&signPoly);
1156          signPoly = pISet(sign);
1157          poly temp = pp_Mult_qq(mv.getResult(), getEntry(b, absoluteC),
1158                                 currRing);
1159          temp = p_Mult_q(signPoly, temp, currRing);
1160          result = p_Add_q(result, temp, currRing);
1161#ifdef COUNT_AND_PRINT_OPERATIONS
1162          multsPoly++;
1163          addsPoly++;
1164          multsMon += pLength(mv.getResult()) * pLength(getEntry(b, absoluteC));
1165#endif
1166          signPoly = NULL;
1167          s++; m++; as++; am++; /* This is for the addition and multiplication
1168                                   in the previous lines of code. */
1169        }
1170        sign = - sign; /* alternating the sign */
1171      }
1172    }
1173    else
1174    {
1175      b = - b - 1;
1176      /* This means that the best line is the column with absolute (0-based)
1177         index b.
1178         Using Laplace, the sign of the contributing minors must be iterating;
1179         the initial sign depends on the relative index of b in
1180         minorColumnKey: */
1181      int sign = (mk.getRelativeColumnIndex(b) % 2 == 0 ? 1 : -1);
1182      poly signPoly = NULL;
1183      for (int r = 0; r < k; r++) /* This iterates over all involved rows. */
1184      {
1185        int absoluteR = mk.getAbsoluteRowIndex(r);
1186        if (!isEntryZero(absoluteR, b)) /* Only then do we have to consider
1187                                           this sub-determinante. */
1188        {
1189          hadNonZeroEntry = true;
1190          PolyMinorValue mv; /* for storing all intermediate minors */
1191          /* Next MinorKey is mk with row absoluteR and column b omitted. */
1192          MinorKey subMk = mk.getSubMinorKey(absoluteR, b);
1193          if (cch.hasKey(subMk))
1194          { /* trying to find the result in the cache */
1195            mv = cch.getValue(subMk);
1196            mv.incrementRetrievals(); /* once more, we made use of the cached
1197                                         value for key mk */
1198            cch.put(subMk, mv); /* We need to do this with "put", as the
1199                                   (altered) number of retrievals may have an
1200                                   impact on the internal ordering among the
1201                                   cached entries. */
1202          }
1203          else
1204          {
1205            mv = getMinorPrivateLaplace(k - 1, subMk, multipleMinors, cch,
1206                                        iSB); /* recursive call */
1207            /* As this minor was not in the cache, we count the additions and
1208               multiplications that we needed to do in the recursive call: */
1209            m += mv.getMultiplications();
1210            s += mv.getAdditions();
1211          }
1212          /* In any case, we count all nested operations in the accumulative
1213             counters: */
1214          am += mv.getAccumulatedMultiplications();
1215          as += mv.getAccumulatedAdditions();
1216          pDelete(&signPoly);
1217          signPoly = pISet(sign);
1218          poly temp = pp_Mult_qq(mv.getResult(), getEntry(absoluteR, b),
1219                                 currRing);
1220          temp = p_Mult_q(signPoly, temp, currRing);
1221          result = p_Add_q(result, temp, currRing);
1222#ifdef COUNT_AND_PRINT_OPERATIONS
1223          multsPoly++;
1224          addsPoly++;
1225          multsMon += pLength(mv.getResult()) * pLength(getEntry(absoluteR, b));
1226#endif
1227          signPoly = NULL;
1228          s++; m++; as++; am++; /* This is for the addition and multiplication
1229                                   in the previous lines of code. */
1230        }
1231        sign = - sign; /* alternating the sign */
1232      }
1233    }
1234    /* Let's cache the newly computed minor: */
1235    int potentialRetrievals = NumberOfRetrievals(_containerRows,
1236                                                 _containerColumns,
1237                                                 _minorSize,
1238                                                 k,
1239                                                 multipleMinors);
1240    if (hadNonZeroEntry)
1241    {
1242      s--; as--; /* first addition was 0 + ..., so we do not count it */
1243#ifdef COUNT_AND_PRINT_OPERATIONS
1244      addsPoly--;
1245#endif
1246    }
1247    if (s < 0) s = 0; /* may happen when all subminors are zero and no
1248                         addition needs to be performed */
1249    if (as < 0) as = 0; /* may happen when all subminors are zero and no
1250                           addition needs to be performed */
1251    if (iSB != 0) result = kNF(iSB, currRing->qideal, result);
1252    PolyMinorValue newMV(result, m, s, am, as, 1, potentialRetrievals);
1253    pDelete(&result); result = NULL;
1254    cch.put(mk, newMV); /* Here's the actual put inside the cache. */
1255    return newMV;
1256  }
1257}
1258
1259/* This can only be used in the case of coefficients coming from a field
1260   or at least an integral domain. */
1261void addOperationBucket(poly& f1, poly& f2, kBucket_pt& bucket)
1262{
1263  /* fills all terms of f1 * f2 into the bucket */
1264  poly a = f1; poly b = f2;
1265  int aLen = pLength(a); int bLen = pLength(b);
1266  if (aLen > bLen)
1267  {
1268    b = f1; a = f2; bLen = aLen;
1269  }
1270  pNormalize(b);
1271
1272  while (a != NULL)
1273  {
1274    /* The next line actually uses only LT(a): */
1275    kBucket_Plus_mm_Mult_pp(bucket, a, b, bLen);
1276    a = pNext(a);
1277  }
1278}
1279
1280/* computes the polynomial (p1 * p2 - p3 * p4) and puts result into p1;
1281   the method destroys the old value of p1;
1282   p2, p3, and p4 may be pNormalize-d but must, apart from that,
1283   not be changed;
1284   This can only be used in the case of coefficients coming from a field
1285   or at least an integral domain. */
1286void elimOperationBucketNoDiv(poly &p1, poly &p2, poly &p3, poly &p4)
1287{
1288#ifdef COUNT_AND_PRINT_OPERATIONS
1289  if ((pLength(p1) != 0) && (pLength(p2) != 0))
1290  {
1291    multsPoly++;
1292    multsMon += pLength(p1) * pLength(p2);
1293  }
1294  if ((pLength(p3) != 0) && (pLength(p4) != 0))
1295  {
1296    multsPoly++;
1297    multsMon += pLength(p3) * pLength(p4);
1298  }
1299  if ((pLength(p1) != 0) && (pLength(p2) != 0) &&
1300      (pLength(p3) != 0) && (pLength(p4) != 0))
1301    addsPoly++;
1302#endif
1303  kBucket_pt myBucket = kBucketCreate(currRing);
1304  addOperationBucket(p1, p2, myBucket);
1305  poly p3Neg = pNeg(pCopy(p3));
1306  addOperationBucket(p3Neg, p4, myBucket);
1307  pDelete(&p3Neg);
1308  pDelete(&p1);
1309  p1 = kBucketClear(myBucket);
1310  kBucketDestroy(&myBucket);
1311}
1312
1313/* computes the polynomial (p1 * p2 - p3 * p4) / p5 and puts result into p1;
1314   the method destroys the old value of p1;
1315   p2, p3, p4, and p5 may be pNormalize-d but must, apart from that,
1316   not be changed;
1317   c5 is assumed to be the leading coefficient of p5;
1318   p5Len is assumed to be the length of p5;
1319   This can only be used in the case of coefficients coming from a field
1320   or at least an integral domain. */
1321void elimOperationBucket(poly &p1, poly &p2, poly &p3, poly &p4, poly &p5,
1322                         number &c5, int p5Len)
1323{
1324#ifdef COUNT_AND_PRINT_OPERATIONS
1325  if ((pLength(p1) != 0) && (pLength(p2) != 0))
1326  {
1327    multsPoly++;
1328    multsMon += pLength(p1) * pLength(p2);
1329  }
1330  if ((pLength(p3) != 0) && (pLength(p4) != 0))
1331  {
1332    multsPoly++;
1333    multsMon += pLength(p3) * pLength(p4);
1334  }
1335  if ((pLength(p1) != 0) && (pLength(p2) != 0) &&
1336      (pLength(p3) != 0) && (pLength(p4) != 0))
1337    addsPoly++;
1338#endif
1339  kBucket_pt myBucket = kBucketCreate(currRing);
1340  addOperationBucket(p1, p2, myBucket);
1341  poly p3Neg = pNeg(pCopy(p3));
1342  addOperationBucket(p3Neg, p4, myBucket);
1343  pDelete(&p3Neg);
1344
1345  /* Now, myBucket contains all terms of p1 * p2 - p3 * p4.
1346     Now we need to perform the polynomial division myBucket / p5
1347     which is known to work without remainder: */
1348  pDelete(&p1); poly helperPoly = NULL;
1349
1350  poly bucketLm = pCopy(kBucketGetLm(myBucket));
1351  while (bucketLm != NULL)
1352  {
1353    /* divide bucketLm by the leading term of p5 and put result into bucketLm;
1354       we start with the coefficients;
1355       note that bucketLm will always represent a term */
1356    number coeff = nDiv(pGetCoeff(bucketLm), c5);
1357    nNormalize(coeff);
1358    pSetCoeff(bucketLm, coeff);
1359    /* subtract exponent vector of p5 from that of quotient; modifies
1360       quotient */
1361    p_ExpVectorSub(bucketLm, p5, currRing);
1362#ifdef COUNT_AND_PRINT_OPERATIONS
1363    divsMon++;
1364    multsMonForDiv += p5Len;
1365    multsMon += p5Len;
1366    savedMultsMFD++;
1367    multsPoly++;
1368    multsPolyForDiv++;
1369    addsPoly++;
1370    addsPolyForDiv++;
1371#endif
1372    kBucket_Minus_m_Mult_p(myBucket, bucketLm, p5, &p5Len);
1373    /* The following lines make bucketLm the new leading term of p1,
1374       i.e., put bucketLm in front of everything which is already in p1.
1375       Thus, after the while loop, we need to revert p1. */
1376    helperPoly = bucketLm;
1377    helperPoly->next = p1;
1378    p1 = helperPoly;
1379
1380    bucketLm = pCopy(kBucketGetLm(myBucket));
1381  }
1382  p1 = pReverse(p1);
1383  kBucketDestroy(&myBucket);
1384}
1385
1386/* assumes that all entries in polyMatrix are already reduced w.r.t. iSB
1387   This can only be used in the case of coefficients coming from a field!!! */
1388PolyMinorValue PolyMinorProcessor::getMinorPrivateBareiss(const int k,
1389                                                          const MinorKey& mk,
1390                                                          const ideal& iSB)
1391{
1392  assume(k > 0); /* k is the minor's dimension; the minor must be at least
1393                    1x1 */
1394  int *theRows=new int[k]; mk.getAbsoluteRowIndices(theRows);
1395  int *theColumns=new int[k]; mk.getAbsoluteColumnIndices(theColumns);
1396  if (k == 1)
1397  {
1398    PolyMinorValue tmp=PolyMinorValue(getEntry(theRows[0], theColumns[0]),
1399                          0, 0, 0, 0, -1, -1);
1400    delete[] theColumns;
1401    delete[] theRows;
1402    return tmp;
1403  }
1404  else /* k > 0 */
1405  {
1406    /* the matrix to perform Bareiss with */
1407    poly* tempMatrix = (poly*)omAlloc(k * k * sizeof(poly));
1408    /* copy correct set of entries from _polyMatrix to tempMatrix */
1409    int i = 0;
1410    for (int r = 0; r < k; r++)
1411      for (int c = 0; c < k; c++)
1412        tempMatrix[i++] = pCopy(getEntry(theRows[r], theColumns[c]));
1413
1414    /* Bareiss algorithm operating on tempMatrix which is at least 2x2 */
1415    int sign = 1; /* This will store the correct sign resulting from
1416                     permuting the rows of tempMatrix. */
1417    int *rowPermutation=new int[k];   /* This is for storing the permutation of rows
1418                                resulting from searching for a non-zero pivot
1419                                element. */
1420    for (int i = 0; i < k; i++) rowPermutation[i] = i;
1421    poly divisor = NULL;
1422    int divisorLength = 0;
1423    number divisorLC;
1424    for (int r = 0; r <= k - 2; r++)
1425    {
1426      /* look for a non-zero entry in column r, rows = r .. (k - 1)
1427         s.t. the polynomial has least complexity: */
1428      int minComplexity = -1; int complexity = 0; int bestRow = -1;
1429      poly pp = NULL;
1430      for (int i = r; i < k; i++)
1431      {
1432        pp = tempMatrix[rowPermutation[i] * k + r];
1433        if (pp != NULL)
1434        {
1435          if (minComplexity == -1)
1436          {
1437            minComplexity = pSize(pp);
1438            bestRow = i;
1439          }
1440          else
1441          {
1442            complexity = 0;
1443            while ((pp != NULL) && (complexity < minComplexity))
1444            { 
1445              complexity += nSize(pGetCoeff(pp)); pp = pNext(pp);
1446            }
1447            if (complexity < minComplexity)
1448            {
1449              minComplexity = complexity;
1450              bestRow = i;
1451            }
1452          }
1453          if (minComplexity <= 1) break; /* terminate the search */
1454        }
1455      }
1456      if (bestRow == -1)
1457      {
1458        /* There is no non-zero entry; hence the minor is zero. */
1459        for (int i = 0; i < k * k; i++) pDelete(&tempMatrix[i]);
1460        return PolyMinorValue(NULL, 0, 0, 0, 0, -1, -1);
1461      }
1462      pNormalize(tempMatrix[rowPermutation[bestRow] * k + r]);
1463      if (bestRow != r)
1464      {
1465        /* We swap the rows with indices r and i: */
1466        int j = rowPermutation[bestRow];
1467        rowPermutation[bestRow] = rowPermutation[r];
1468        rowPermutation[r] = j;
1469        /* Now we know that tempMatrix[rowPermutation[r] * k + r] is not zero.
1470           But carefull; we have to negate the sign, as there is always an odd
1471           number of row transpositions to swap two given rows of a matrix. */
1472        sign = -sign;
1473      }
1474#if (defined COUNT_AND_PRINT_OPERATIONS) && (COUNT_AND_PRINT_OPERATIONS > 2)
1475      poly w = NULL; int wl = 0;
1476      printf("matrix after %d steps:\n", r);
1477      for (int u = 0; u < k; u++)
1478      {
1479        for (int v = 0; v < k; v++)
1480        {
1481          if ((v < r) && (u > v))
1482            wl = 0;
1483          else
1484          {
1485            w = tempMatrix[rowPermutation[u] * k + v];
1486            wl = pLength(w);
1487          }
1488          printf("%5d  ", wl);
1489        }
1490        printf("\n");
1491      }
1492      printCounters ("", false);
1493#endif
1494      if (r != 0)
1495      {
1496        divisor = tempMatrix[rowPermutation[r - 1] * k + r - 1];
1497        pNormalize(divisor);
1498        divisorLength = pLength(divisor);
1499        divisorLC = pGetCoeff(divisor);
1500      }
1501      for (int rr = r + 1; rr < k; rr++)
1502        for (int cc = r + 1; cc < k; cc++)
1503        {
1504          if (r == 0)
1505            elimOperationBucketNoDiv(tempMatrix[rowPermutation[rr] * k + cc],
1506                                     tempMatrix[rowPermutation[r]  * k + r],
1507                                     tempMatrix[rowPermutation[r]  * k + cc],
1508                                     tempMatrix[rowPermutation[rr] * k + r]);
1509          else
1510            elimOperationBucket(tempMatrix[rowPermutation[rr] * k + cc],
1511                                tempMatrix[rowPermutation[r]  * k + r],
1512                                tempMatrix[rowPermutation[r]  * k + cc],
1513                                tempMatrix[rowPermutation[rr] * k + r],
1514                                divisor, divisorLC, divisorLength);
1515        }
1516    }
1517#if (defined COUNT_AND_PRINT_OPERATIONS) && (COUNT_AND_PRINT_OPERATIONS > 2)
1518    poly w = NULL; int wl = 0;
1519    printf("matrix after %d steps:\n", k - 1);
1520    for (int u = 0; u < k; u++)
1521    {
1522      for (int v = 0; v < k; v++)
1523      {
1524        if ((v < k - 1) && (u > v))
1525          wl = 0;
1526        else
1527        {
1528          w = tempMatrix[rowPermutation[u] * k + v];
1529          wl = pLength(w);
1530        }
1531        printf("%5d  ", wl);
1532      }
1533      printf("\n");
1534    }
1535#endif
1536    poly result = tempMatrix[rowPermutation[k - 1] * k + k - 1];
1537    if (sign == -1) result = pNeg(result);
1538    if (iSB != 0) result = kNF(iSB, currRing->qideal, result);
1539    PolyMinorValue mv(result, 0, 0, 0, 0, -1, -1);
1540    for (int i = 0; i < k * k; i++) pDelete(&tempMatrix[i]);
1541    omFreeSize(tempMatrix, k * k * sizeof(poly));
1542    delete[] rowPermutation;
1543    delete[] theColumns;
1544    delete[] theRows;
1545    return mv;
1546  }
1547}
1548
Note: See TracBrowser for help on using the repository browser.