source: git/kernel/LinearAlgebra.cc @ 12cca3

spielwiese
Last change on this file since 12cca3 was 12cca3, checked in by Frank Seelisch <seelisch@…>, 14 years ago
new commands ludecomp(mat), and luinverse(mat [, mat, mat]) (see linearAlgebra.h for docu) git-svn-id: file:///usr/local/Singular/svn/trunk@12828 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 8.9 KB
Line 
1/*****************************************************************************\
2 * Computer Algebra System SINGULAR   
3\*****************************************************************************/
4/** @file lineareAlgebra.cc
5 *
6 * This file implements basic linear algebra functionality.
7 *
8 * For more general information, see the documentation in
9 * lineareAlgebra.h.
10 *
11 * @author Frank Seelisch
12 *
13 * @internal @version \$Id$
14 *
15 **/
16/*****************************************************************************/
17
18// include header files
19#include "mod2.h"
20#include "structs.h"
21#include "polys.h"
22#include "ideals.h"
23#include "numbers.h"
24#include "matpol.h"
25#include "linearAlgebra.h"
26
27/**
28 * The returned score is based on the implementation of 'nSize' for
29 * numbers (, see numbers.h): nSize(n) provides a measure for the
30 * complexity of n. Thus, less complex pivot elements will be
31 * prefered, and get therefore a smaller pivot score. Consequently,
32 * we simply return the value of nSize.
33 * An exception to this rule are the ground fields R, long R, and
34 * long C: In these, the result of nSize relates to |n|. And since
35 * a larger modulus of the pivot element ensures a numerically more
36 * stable Gauss elimination, we would like to have a smaller score
37 * for larger values of |n|. Therefore, in R, long R, and long C,
38 * the negative of nSize will be returned.
39 **/
40int pivotScore(number n)
41{
42  int s = nSize(n);
43  if (rField_is_long_C(currRing) ||
44      rField_is_long_R(currRing) ||
45      rField_is_R(currRing))
46    return -s;
47  else
48    return s;
49}
50
51/**
52 * This code computes a score for each non-zero matrix entry in
53 * aMat[r1..r2, c1..c2]. If all entries are zero, false is returned,
54 * otherwise true. In the latter case, the minimum of all scores
55 * is sought, and the row and column indices of the corresponding
56 * matrix entry are stored in bestR and bestC.
57 **/
58bool pivot(const matrix aMat, const int r1, const int r2, const int c1,
59           const int c2, int* bestR, int* bestC)
60{
61  int bestScore; int score; bool foundBestScore = false; poly matEntry;
62
63  for (int c = c1; c <= c2; c++)
64  {
65    for (int r = r1; r <= r2; r++)
66    {
67      matEntry = MATELEM(aMat, r, c);
68      if (matEntry != NULL)
69      {
70        score = pivotScore(pGetCoeff(matEntry));
71        if ((!foundBestScore) || (score < bestScore))
72        {
73          bestScore = score;
74          *bestR = r;
75          *bestC = c;
76        }
77        foundBestScore = true;
78      }
79    }
80  }
81
82  return foundBestScore;
83}
84
85void luDecomp(const matrix aMat, matrix &pMat, matrix &lMat, matrix &uMat)
86{
87  int rr = aMat->rows();
88  int cc = aMat->cols();
89  pMat = mpNew(rr, rr);
90  lMat = mpNew(rr, rr);
91  uMat = mpNew(rr, cc);
92  /* copy aMat into uMat: */
93  for (int r = 1; r <= rr; r++)
94    for (int c = 1; c <= cc; c++)
95      MATELEM(uMat, r, c) = pCopy(aMat->m[c - 1 + (r - 1) * cc]);
96
97  /* we use an int array to store all row permutations;
98     note that we only make use of the entries [1..rr] */
99  int* permut = new int[rr + 1];
100  for (int i = 1; i <= rr; i++) permut[i] = i;
101 
102  /* fill lMat with the (rr x rr) unit matrix */
103  for (int r = 1; r <= rr; r++) MATELEM(lMat, r, r) = pOne();
104
105  int bestR; int bestC; int intSwap; poly pSwap;
106  for (int r = 1; r < rr; r++)
107  {
108    if ((r <= cc) && (pivot(uMat, r, rr, r, r, &bestR, &bestC)))
109    {
110      /* swap rows with indices r and bestR in permut */
111      intSwap = permut[r];
112      permut[r] = permut[bestR];
113      permut[bestR] = intSwap;
114
115      /* swap rows with indices r and bestR in uMat;
116         it is sufficient to do this for columns >= r */
117      for (int c = r; c <= cc; c++)
118      {
119        pSwap = MATELEM(uMat, r, c);
120        MATELEM(uMat, r, c) = MATELEM(uMat, bestR, c);
121        MATELEM(uMat, bestR, c) = pSwap;
122      }
123
124      /* swap rows with indices r and bestR in lMat;
125         we must do this only for columns < r */
126      for (int c = 1; c < r; c++)
127      {
128        pSwap = MATELEM(lMat, r, c);
129        MATELEM(lMat, r, c) = MATELEM(lMat, bestR, c);
130        MATELEM(lMat, bestR, c) = pSwap;
131      }
132
133      /* perform next Gauss elimination step, i.e., below the
134         row with index r;
135         we need to adjust lMat and uMat;
136         we are certain that the matrix entry at [r, r] is non-zero: */
137      number pivotElement = pGetCoeff(MATELEM(uMat, r, r));
138      poly p; number n;
139      for (int rGauss = r + 1; rGauss <= rr; rGauss++)
140      {
141        p = MATELEM(uMat, rGauss, r);
142        if (p != NULL)
143        {
144          n = nDiv(pGetCoeff(p), pivotElement);
145
146          /* filling lMat;
147             old entry was zero, so no need to call pDelete(.) */
148          MATELEM(lMat, rGauss, r) = pNSet(nCopy(n));
149
150          /* adjusting uMat: */
151          MATELEM(uMat, rGauss, r) = NULL; pDelete(&p);
152          n = nNeg(n);
153          for (int cGauss = r + 1; cGauss <= cc; cGauss++)
154            MATELEM(uMat, rGauss, cGauss)
155              = pAdd(MATELEM(uMat, rGauss, cGauss),
156                     ppMult_nn(MATELEM(uMat, r, cGauss), n));
157
158          nDelete(&n); /* clean up n */
159        }
160      }
161    }
162  }
163
164  /* building the permutation matrix from 'permut' */
165  for (int r = 1; r <= rr; r++)
166    MATELEM(pMat, r, permut[r]) = pOne();
167  delete[] permut;
168
169  return;
170}
171
172/**
173 * This code first computes the LU-decomposition of aMat,
174 * and then calls the method for inverting a matrix which
175 * is given by its LU-decomposition.
176 **/
177bool luInverse(const matrix aMat, matrix &iMat)
178{ /* aMat is guaranteed to be an (n x n)-matrix */
179  int d = aMat->rows();
180
181  matrix pMat;
182  matrix lMat;
183  matrix uMat;
184  luDecomp(aMat, pMat, lMat, uMat);
185  bool result = luInverseFromLUDecomp(pMat, lMat, uMat, iMat);
186
187  /* clean-up */
188  idDelete((ideal*)&pMat);
189  idDelete((ideal*)&lMat);
190  idDelete((ideal*)&uMat);
191
192  return result;
193}
194
195bool upperRightTriangleInverse(const matrix uMat, matrix &iMat,
196                               bool diagonalIsOne)
197{
198  int d = uMat->rows();
199  poly p; poly q;
200
201  /* check whether uMat is invertible */
202  bool invertible = diagonalIsOne;
203  if (!invertible)
204  {
205    invertible = true;
206    for (int r = 1; r <= d; r++)
207    {
208      if (MATELEM(uMat, r, r) == NULL)
209      {
210        invertible = false;
211        break;
212      }
213    }
214  }
215
216  if (invertible)
217  {
218    iMat = mpNew(d, d);
219    for (int r = d; r >= 1; r--)
220    {
221      if (diagonalIsOne)
222        MATELEM(iMat, r, r) = pOne();
223      else
224        MATELEM(iMat, r, r) = pNSet(nInvers(pGetCoeff(MATELEM(uMat, r, r))));
225      for (int c = r + 1; c <= d; c++)
226      {
227        p = NULL;
228        for (int k = r + 1; k <= c; k++)
229        {
230          q = ppMult_qq(MATELEM(uMat, r, k), MATELEM(iMat, k, c));
231          p = pAdd(p, q);
232        }
233        p = pNeg(p);
234        p = pMult(p, pCopy(MATELEM(iMat, r, r)));
235        MATELEM(iMat, r, c) = p;
236      }
237    }
238  }
239
240  return invertible;
241}
242
243bool lowerLeftTriangleInverse(const matrix lMat, matrix &iMat,
244                              bool diagonalIsOne)
245{
246  int d = lMat->rows(); poly p; poly q;
247
248  /* check whether lMat is invertible */
249  bool invertible = diagonalIsOne;
250  if (!invertible)
251  {
252    invertible = true;
253    for (int r = 1; r <= d; r++)
254    {
255      if (MATELEM(lMat, r, r) == NULL)
256      {
257        invertible = false;
258        break;
259      }
260    }
261  }
262
263  if (invertible)
264  {
265    iMat = mpNew(d, d);
266    for (int c = d; c >= 1; c--)
267    {
268      if (diagonalIsOne)
269        MATELEM(iMat, c, c) = pOne();
270      else
271        MATELEM(iMat, c, c) = pNSet(nInvers(pGetCoeff(MATELEM(lMat, c, c))));
272      for (int r = c + 1; r <= d; r++)
273      {
274        p = NULL;
275        for (int k = c; k <= r - 1; k++)
276        {
277          q = ppMult_qq(MATELEM(lMat, r, k), MATELEM(iMat, k, c));
278          p = pAdd(p, q);
279        }
280        p = pNeg(p);
281        p = pMult(p, pCopy(MATELEM(iMat, c, c)));
282        MATELEM(iMat, r, c) = p;
283      }
284    }
285  }
286
287  return invertible;
288}
289
290/**
291 * This code computes the inverse by inverting lMat and uMat, and
292 * then performing two matrix multiplications.
293 **/
294bool luInverseFromLUDecomp(const matrix pMat, const matrix lMat,
295                           const matrix uMat, matrix &iMat)
296{ /* uMat is guaranteed to be quadratic */
297  int d = uMat->rows();
298
299  matrix lMatInverse; /* for storing the inverse of lMat;
300                         this inversion will always work                */
301  matrix uMatInverse; /* for storing the inverse of uMat, if invertible */
302
303  bool result = upperRightTriangleInverse(uMat, uMatInverse, false);
304  if (result)
305  {
306    /* next will always work, since lMat is known to have all diagonal
307       entries equal to 1 */
308    lowerLeftTriangleInverse(lMat, lMatInverse, true);
309    iMat = mpMult(mpMult(uMatInverse, lMatInverse), pMat);
310   
311    /* clean-up */
312    idDelete((ideal*)&lMatInverse);
313    idDelete((ideal*)&uMatInverse);
314  }
315
316  return result;
317}
Note: See TracBrowser for help on using the repository browser.