UltraScan III
us_matrix.cpp
Go to the documentation of this file.
1 
3 #include "us_matrix.h"
4 #include "us_math2.h"
5 
6 #include <QtCore>
7 
8 bool US_Matrix::lsfit( double* c, double* x, double* y,
9  int N, int order )
10 {
11  bool status = true;
12 
13  QVector< double* > vecA;
14  QVector< double > datA;
15  QVector< double > datb( order );
16 
17  double** A = construct( vecA, datA, order, order );
18  double* b = datb.data();
19 
20  /* To calculate the matrix, calculate the product M'M, where M is the matrix
21  constructed as follows:
22 
23 
24  x1^0 x1^1 x1^2 ... x1^order
25  x2^0 x2^1 x2^2 ... x2^order
26  x3^0 x3^1 x3^2 ... x3^order
27 
28  M = . . .
29  . . . ...
30  . . .
31 
32  xn^0 xn^1 xn^2 ... xn^order
33 
34  A = M'M, and A is positive - definite, and can be decomposed by the
35  Cholesky method. Evaluate A by filling in the lower triangular of the A
36  matrix. NOTE: Instead of polynomials evaluated at each point xi, other
37  linearly independent basis function sets can be used for a fit.
38 
39  */
40 
41  A[ 0 ][ 0 ] = (double) N;
42 
43  for ( int i = 1; i < order; i++ )
44  {
45  for ( int j = 0; j <= i; j++ )
46  {
47  A[ i ][ j ] = 0;
48 
49  for ( int k = 0; k < N; k++ )
50  A[ i ][ j ] += pow( x[ k ], i ) * pow( x[ k ], j );
51  }
52  }
53 
54  // Only the lower triangular matrix is filled now, which is sufficient for
55  // solution by Cholesky decomposition.
56 
57  // Evaluate b:
58 
59  for ( int i = 0; i < order; i++ )
60  {
61  b[ i ] = 0;
62 
63  for ( int k = 0; k < N; k++ )
64  b[ i ] += y[ k ] * pow( x[ k ], i );
65  }
66 
67 
68  // Solve the system Ax=b using Cholesky decomposition:
69 
70  // Ax=b, A=LL', L(L'x)=b, L'x=y, Ly=b (solve for y), now L'x=y (solve for x)
71  //print_matrix( A, order, order);
72  //print_vector( b, order );
73  if( Cholesky_Decomposition( A, order ) )
74  {
75  Cholesky_SolveSystem ( A, b, order );
76  for ( int i = 0; i < order; i++ ) c[ i ] = b[ i ];
77  }
78  else
79  status = false;
80 
81  //print_matrix( A, order, order);
82  //print_vector( b, order );
83  //print_matrix( A, order, order);
84  //print_vector( b, order );
85 
86  return status;
87 }
88 
89 /* This method factors the n by n symmetric positive definite matrix A as LL(T)
90  where L is a lower triangular matrix. The method assumes that at least the
91  lower triangle of A is filled on entry. On exit, the lower triangle of A has
92  been replaced by L.
93 */
94 
95 bool US_Matrix::Cholesky_Decomposition( double** a, int n )
96 {
97  double sum;
98  double diff;
99 
100  for ( int i = 0; i < n; i++ )
101  {
102  sum = 0.0;
103 
104  for ( int j = 0; j < i; j++ )
105  {
106  sum += sq( a[ i ][ j ] );
107  }
108 
109  diff = a[ i ][ i ] - sum;
110 
111  if ( diff <= 0.0 )// not positive definite...
112  {
113  qDebug() << "Cholesky_Decomposition not positive definite.";
114  return false;
115  }
116 
117  a[ i ][ i ] = sqrt( diff );
118 
119  for ( int k = i + 1; k < n; k++ )
120  {
121  sum = 0.0;
122 
123  for ( int j = 0; j < i; j++ )
124  sum += a[ k ][ j ] * a[ i ][ j ];
125 
126  a[ k ][ i ] = ( a[ k ][ i ] - sum ) / a[ i ][ i ];
127  }
128  }
129 
130  // Zero the upper triangular portion
131  for ( int i = 0; i < n - 1; i++ )
132  {
133  for ( int j = i + 1; j < n; j++ )
134  a[ i ][ j ] = 0.0;
135  }
136 
137  return true;
138 }
139 
140 /* Cholesky_SolveSystem expects a Cholesky-decomposed L-matrix (n x n) with the
141  lower diagonal filled, and the right hand side "b". Using forward and
142  backward substitution, the right hand side "b" is replaced by the solution
143  vector "x"
144 */
145 bool US_Matrix::Cholesky_SolveSystem( double** L, double* b, int n )
146 {
147 QString t;
148  // Forward substitution:
149  for ( int i = 0; i < n; i++ )
150  {
151  int j;
152  for ( j = 0; j < i; j++ )
153  {
154  b[ i ] -= L[ i ][ j ] * b[ j ];
155  }
156 
157  b[ i ] /= L[ i ][ i ];
158  }
159 
160  // Backward substitution:
161  for ( int i = n - 1; i >= 0; i-- )
162  {
163  for ( int j = n - 1; j > i; j-- )
164  {
165  b[ i ] -= L[ j ][ i ] * b[ j ];
166  }
167 
168  b[i] /= L[ i ][ i ];
169 
170  }
171 
172  return true;
173 }
174 
175 // Solve the system Ax=b using Cholesky decomposition:
176 // A * A(-1) = I ; A = LL' ; L (L' * A(-1) ) = I ;
177 // L * y = I (solve for y) , now L' * A(-1) = y (solve for A(-1))
178 bool US_Matrix::Cholesky_Invert( double** AA, double** AI, int nn )
179 {
180  QVector< double > workvec( nn );
181  double* work = workvec.data();
182 
183  // Decompose A:
184 
185  if ( ! US_Matrix::Cholesky_Decomposition( AA, nn ) )
186  return false;
187 
188  for ( int jj = 0; jj < nn; jj++ )
189  {
190  // Set up A-inverse to contain the Identity matrix:
191  workvec.fill( 0.0, nn );
192  workvec[ jj ] = 1.0;
193  work = workvec.data();
194 
195  // Solve for each column j:
196  US_Matrix::Cholesky_SolveSystem( AA, work, nn );
197 
198  // Assign the solution to the appropriate column of A-inverse:
199  for ( int ii = 0; ii < nn; ii++ )
200  AI[ ii ][ jj ] = work[ ii ];
201 
202  }
203 
204  return true;
205 }
206 
207 // Construct and initialize a matrix, using a pair of QVectors.
208 // One QVector holds all data values (doubles); the other holds
209 // pointers to columns-sized segments of that data array.
210 double** US_Matrix::construct( QVector< double* >& QVm,
211  QVector< double >& QVd, int rows, int columns )
212 {
213  QVm.fill( 0, rows ); // Initialize the pointers vector
214  QVd.fill( 0., rows * columns ); // Initialize the data elements vector
215  double* vd = QVd.data(); // Point to the beginning of data
216 
217  for ( int ii = 0; ii < rows; ii++ )
218  { // Construct the rows of the matrix
219  QVm[ ii ] = vd; // Store a row pointer
220  vd += columns; // Bump the pointer to the next row
221  }
222 
223  return QVm.data(); // Return the pointer to the pointers array
224 }
225 
226 // Compute the columns x columns square matrix product of
227 // a matrix-transpose and the matrix.
228 // Only the lower triangle of the product is filled,
229 // since that is all that is required in Cholesky decomposition.
230 void US_Matrix::tmm( double** AA, double** CC, int rows, int columns )
231 {
232  QVector< double > ATvec( rows );
233  double* ATrow = ATvec.data(); // Array for a transpose row
234 
235  for ( int ii = 0; ii < columns; ii++ )
236  { // Loop for A' rows, A columns and P columns
237  double dotp = 0.0;
238 
239  // Dot product of the A' row with itself (output diagonal point)
240  // Also, save this A' row for use below
241  for ( int kk = 0; kk < rows; kk++ )
242  {
243  double aval = AA[ kk ][ ii ];
244  dotp += sq( aval );
245  ATrow[ kk ] = aval;
246  }
247 
248  CC[ ii ][ ii ] = dotp; // Store product on diagonal
249 
250  for ( int jj = 0; jj < ii; jj++ )
251  { // Loop for P rows (lower triangle)
252  dotp = 0.0;
253 
254  // Accumulate dot product of columns (A' row, A column)
255  for ( int kk = 0; kk < rows; kk++ )
256  dotp += ( ATrow[ kk ] * AA[ kk ][ jj ] );
257 
258  CC[ ii ][ jj ] = dotp; // Store product for column of row
259  }
260  }
261 }
262 
263 // Compute product of a matrix-transpose and the matrix, with optional full fill
264 void US_Matrix::tmm( double** AA, double** CC, int rows, int columns,
265  bool fill )
266 {
267  // Calculate A-transpose times A, computing just the lower triangle
268  tmm( AA, CC, rows, columns );
269 
270  if ( fill )
271  { // Duplicate values into the upper triangle
272  for ( int ii = 0; ii < columns - 1; ii++ )
273  for ( int jj = ii + 1; jj < columns; jj++ )
274  CC[ ii ][ jj ] = CC[ jj ][ ii ];
275  }
276 }
277 
278 // Compute the vector product of a matrix and a vector
279 void US_Matrix::mvv( double** AA, double* bb, double* cc,
280  int rows, int columns )
281 {
282  for ( int ii = 0; ii < rows; ii++ )
283  {
284  double dotp = 0.0;
285 
286  for ( int jj = 0; jj < columns; jj++ )
287  dotp += ( AA[ ii ][ jj ] * bb[ jj ] );
288 
289  cc[ ii ] = dotp;
290  }
291 }
292 
293 // Compute the vector product of a matrix-transpose and a vector
294 void US_Matrix::tvv( double** AA, double* bb, double* cc,
295  int rows, int columns )
296 {
297  for ( int jj = 0; jj < columns; jj++ )
298  {
299  double dotp = 0.0;
300 
301  for ( int ii = 0; ii < rows; ii++ )
302  dotp += ( AA[ ii ][ jj ] * bb[ ii ] );
303 
304  cc[ jj ] = dotp;
305  }
306 }
307 
308 // Compute a matrix product of two matrices
309 void US_Matrix::mmm( double** AA, double** BB, double** CC,
310  int rows, int size, int columns )
311 {
312  for ( int ii = 0; ii < rows; ii++ )
313  {
314  for ( int jj = 0; jj < columns; jj++ )
315  {
316  double dotp = 0.0;
317 
318  for ( int kk = 0; kk < size; kk++ )
319  dotp += ( AA[ ii ][ kk ] * BB[ kk ][ jj ] );
320 
321  CC[ ii ][ jj ] = dotp;
322  }
323  }
324 }
325 
326 // Calculate the matrix sum of two matrices of the same dimensions
327 void US_Matrix::msum( double** AA, double** BB, double** CC,
328  int rows, int columns )
329 {
330  for ( int ii = 0; ii < rows; ii++ )
331  for ( int jj = 0; jj < columns; jj++ )
332  CC[ ii ][ jj ] = AA[ ii ][ jj ] + BB[ ii ][ jj ];
333 }
334 
335 // Calculate the vector sum of two vectors of the same size
336 void US_Matrix::vsum( double* aa, double* bb, double* cc, int size )
337 {
338  for ( int ii = 0; ii < size; ii++ )
339  cc[ ii ] = aa[ ii ] + bb[ ii ];
340 }
341 
342 // Fill a square matrix to make it an identity matrix
343 void US_Matrix::mident( double** CC, int size )
344 {
345  for ( int ii = 0; ii < size; ii++ )
346  for ( int jj = 0; jj < size; jj++ )
347  CC[ ii ][ jj ] = ( ii != jj ? 0.0 : 1.0 );
348 }
349 
350 // Copy contents from one matrix to another matrix of the same dimensions
351 void US_Matrix::mcopy( double** AA, double** CC, int rows, int columns )
352 {
353  for ( int ii = 0; ii < rows; ii++ )
354  for ( int jj = 0; jj < columns; jj++ )
355  CC[ ii ][ jj ] = AA[ ii ][ jj ];
356 }
357 
358 // Copy contents from one vector to another vector of the same size
359 void US_Matrix::vcopy( double* aa, double* cc, int size )
360 {
361  for ( int ii = 0; ii < size; ii++ )
362  cc[ ii ] = aa[ ii ];
363 }
364 
365 // Add a scalar value to the diagonal of a square matrix
366 void US_Matrix::add_diag( double** CC, double ss, int size )
367 {
368  for ( int ii = 0; ii < size; ii++ )
369  CC[ ii ][ ii ] += ss;
370 }
371 
372 // Add a scalar value to all the elements of a matrix
373 void US_Matrix::add( double** CC, double ss, int rows, int columns )
374 {
375  for ( int ii = 0; ii < rows; ii++ )
376  for ( int jj = 0; jj < columns; jj++ )
377  CC[ ii ][ jj ] += ss;
378 }
379 
380 // Scale all the elements of a matrix by a scalar value
381 void US_Matrix::scale( double** CC, double ss, int rows, int columns )
382 {
383  for ( int ii = 0; ii < rows; ii++ )
384  for ( int jj = 0; jj < columns; jj++ )
385  CC[ ii ][ jj ] *= ss;
386 }
387 
388 // Compute the dot product of two vectors
389 double US_Matrix::dotproduct( double* aa, double* bb, int size )
390 {
391  double dotp = 0.0;
392 
393  for ( int ii = 0; ii < size; ii++ )
394  dotp += ( aa[ ii ] * bb[ ii ] );
395 
396  return dotp;
397 }
398 
399 // Compute the dot product of a vector with itself
400 double US_Matrix::dotproduct( double* aa, int size )
401 {
402  double dotp = 0.0;
403 
404  for ( int ii = 0; ii < size; ii++ )
405  dotp += sq( aa[ ii ] );
406 
407  return dotp;
408 }
409 
410 // Print a vector
411 void US_Matrix::print_vector( double* v, int n )
412 {
413  QString s;
414  QString t;
415  for ( int i = 0; i < n; i++ ) s += t.sprintf( "%.15f ", v[ i ] );
416 
417  qDebug() << s;
418 }
419 
420 // Print a matrix
421 void US_Matrix::print_matrix( double** A, int rows, int columns )
422 {
423  for ( int i = 0; i < rows; i++ ) print_vector( A[ i ], columns );
424  qDebug() << "\n";
425 }
426 
427 /* luDecomposition performs LU Decomposition on a matrix. This routine
428  must be given an array to mark the row permutations and a flag to mark
429  whether the number of permutations was even or odd. Reference: Numerical
430  Recipes in C.
431 */
432 
433 void US_Matrix::LU_Decomposition( double** matrix, int* index, bool parity, int n )
434 {
435  // imax is position of largest element in the row.
436  int imax = 0;
437 
438  // amax is value of largest element in the row.
439  // dum is a temporary variable.
440 
441  double amax;
442  double dum = 0;
443 
444  // scaling factor for each row is stored here
445  QVector< double > vscaling( n );
446  double* scaling = vscaling.data();
447 
448  // a small number != zero
449  double tiny = 1.0E-20;
450 
451  // Is the number of pivots even?
452  parity = true;
453 
454  // Loop over rows to get the scaling information
455  // The largest element in the row is the inverse of the scaling factor.
456  for ( int i = 0; i < n; i++ )
457  {
458  amax = 0;
459 
460  for ( int j = 0; j < n; j++ )
461  {
462  if ( fabs( matrix[ i ][ j ]) > amax ) amax = matrix[ i ][ j ];
463  }
464 
465  if ( amax == 0 )
466  {
467  qDebug() << "Singular Matrix";
468  }
469 
470  // Save the scaling
471  scaling[ i ] = 1.0 / amax;
472  }
473 
474  // Loop over columns using Crout's Method.
475  for ( int j = 0; j < n; j++ )
476  {
477  // lower left corner
478  for ( int i = 0; i < j; i++ )
479  {
480  dum = matrix[ i ][ j ];
481 
482  for ( int k = 0; k < i; k++ )
483  dum -= matrix[ i ][ k ] * matrix[ k ][ j ];
484 
485  matrix[ i ][ j ] = dum;
486  }
487 
488  // Initialize search for largest element
489  amax = 0.0;
490 
491  // upper right corner
492  for ( int i = j; i < n; i++ )
493  {
494  dum = matrix[ i ][ j ];
495 
496  for ( int k = 0; k < j; k++ )
497  dum -= matrix[ i ][ k ] * matrix[ k ][ j ];
498 
499  matrix[ i ][ j ] = dum;
500 
501  if ( scaling[ i ] * fabs( dum ) > amax )
502  {
503  amax = scaling[ i ]* fabs( dum );
504  imax = i;
505  }
506  }
507 
508  // Change rows if it is necessary
509  if ( j != imax)
510  {
511  for ( int k = 0; k < n; k++ )
512  {
513  dum = matrix[ imax ][ k ];
514  matrix[ imax ][ k ] = matrix[ j ][ k ];
515  matrix[ j ][ k ] = dum;
516  }
517 
518  // Change parity
519  parity = ! parity;
520  scaling[ imax ] = scaling[ j ];
521  }
522 
523  // Mark the column with the pivot row.
524  index[ j ] = imax;
525 
526  // replace zeroes on the diagonal with a small number.
527  if ( matrix[ j ][ j ] == 0.0 ) matrix[ j ][ j ] = tiny;
528 
529  // Divide by the pivot element
530  if ( j != n )
531  {
532  dum = 1.0 / matrix[ j ][ j ];
533  for ( int i = j + 1; i < n; i++ ) matrix[ i ][ j ] *= dum;
534  }
535  }
536 
537 }
538 
539 /* Do the backsubstitution on matrix a which is the LU decomposition
540  of the original matrix. b is the right hand side vector which is NX1. b is
541  replaced by the solution. index is the array that marks the row
542  permutations.
543 */
544 
545 void US_Matrix::LU_BackSubstitute( double** A, double*& b, int* index, int n )
546 {
547  int ip;
548  int ii = -1;
549 
550  double sum;
551 
552  for ( int i = 0; i < n; i++ )
553  {
554  ip = index[ i ];
555  sum = b[ ip ];
556  b[ ip ] = b[ i ];
557 
558  if ( ii != -1 )
559  {
560  for ( int j = ii; j < i; j++ ) sum -= A[ i ][ j ] * b[ j ];
561  }
562  else
563  if ( sum != 0 ) ii = i;
564 
565  b[ i ] = sum;
566  }
567 
568  for ( int i = n - 1; i >= 0; i-- )
569  {
570  sum = b[ i ];
571 
572  for ( int j = i + 1; j < n; j++ ) sum -= A[ i ][ j ] * b[ j ];
573 
574  b[ i ] = sum / A[ i ][ i ];
575  }
576 }
577 
578 /* Solve a set of linear equations. a is a square matrix of coefficients.
579  b is the right hand side. b is replaced by solution. Target is replaced by
580  its LU decomposition.
581 */
582 
583 void US_Matrix::LU_SolveSystem( double** A, double*& b, int n )
584 {
585  bool parity = true;
586  QVector< int > vindex( n );
587  int* index = vindex.data();
588 
589  LU_Decomposition ( A, index, parity, n );
590  LU_BackSubstitute( A, b, index, n );
591 }
592