opennurbs_matrix.h
1 /* $NoKeywords: $ */
2 /*
3 //
4 // Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
5 // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
6 // McNeel & Associates.
7 //
8 // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
9 // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
10 // MERCHANTABILITY ARE HEREBY DISCLAIMED.
11 //
12 // For complete openNURBS copyright information see <http://www.opennurbs.org>.
13 //
14 ////////////////////////////////////////////////////////////////
15 */
16 
17 #if !defined(ON_MATRIX_INC_)
18 #define ON_MATRIX_INC_
19 
20 class ON_Xform;
21 
22 class ON_CLASS ON_Matrix
23 {
24 public:
25  ON_Matrix();
26  ON_Matrix(
27  int row_count,
28  int col_count
29  );
30  ON_Matrix( // see ON_Matrix::Create(int,int,int,int) for details
31  int, // first valid row index
32  int, // last valid row index
33  int, // first valid column index
34  int // last valid column index
35  );
36  ON_Matrix( const ON_Xform& );
37  ON_Matrix( const ON_Matrix& );
38 
39 #if defined(ON_HAS_RVALUEREF)
40  // rvalue copy constructor
41  ON_Matrix(ON_Matrix&&) ON_NOEXCEPT;
42 
43  // The rvalue assignment operator calls ON_Object::operator=(ON_Object&&)
44  // which could throw exceptions. See the implementation of
45  // ON_Object::operator=(ON_Object&&) for details.
46  ON_Matrix& operator=(ON_Matrix&&);
47 #endif
48 
49  /*
50  Description:
51  This constructor is for experts who have storage for a matrix
52  and need to use it in ON_Matrix form.
53  Parameters:
54  row_count - [in]
55  col_count - [in]
56  M - [in]
57  bDestructorFreeM - [in]
58  If true, ~ON_Matrix will call onfree(M).
59  If false, caller is managing M's memory.
60  Remarks:
61  ON_Matrix functions that increase the value of row_count or col_count
62  will fail on a matrix created with this constructor.
63  */
64  ON_Matrix(
65  int row_count,
66  int col_count,
67  double** M,
68  bool bDestructorFreeM
69  );
70 
71  /*
72  Returns:
73  A row_count X col_count martix on the heap that can be
74  deleted by calling ON_Matrix::Deallocate().
75  */
76  static double** Allocate(
77  unsigned int row_count,
78  unsigned int col_count
79  );
80 
81  static void Deallocate(
82  double** M
83  );
84 
85  virtual ~ON_Matrix();
86  void EmergencyDestroy(); // call if memory pool used matrix by becomes invalid
87 
88  // ON_Matrix[i][j] = value at row i and column j
89  // 0 <= i < RowCount()
90  // 0 <= j < ColCount()
91  double* operator[](int);
92  const double* operator[](int) const;
93 
94  ON_Matrix& operator=(const ON_Matrix&);
95  ON_Matrix& operator=(const ON_Xform&);
96 
97  bool IsValid() const;
98  int IsSquare() const; // returns 0 for no and m_row_count (= m_col_count) for yes
99 
100  int RowCount() const;
101  int ColCount() const;
102  int MinCount() const; // smallest of row and column count
103  int MaxCount() const; // largest of row and column count
104 
105  unsigned int UnsignedRowCount() const;
106  unsigned int UnsignedColCount() const;
107  unsigned int UnsignedMinCount() const; // smallest of row and column count
108  unsigned int UnsignedMaxCount() const; // largest of row and column count
109 
110  void RowScale(int,double);
111  void ColScale(int,double);
112  void RowOp(int,double,int);
113  void ColOp(int,double,int);
114 
115  bool Create(
116  int, // number of rows
117  int // number of columns
118  );
119 
120  bool Create( // E.g., Create(1,5,1,7) creates a 5x7 sized matrix that with
121  // "top" row = m[1][1],...,m[1][7] and "bottom" row
122  // = m[5][1],...,m[5][7]. The result of Create(0,m,0,n) is
123  // identical to the result of Create(m+1,n+1).
124  int, // first valid row index
125  int, // last valid row index
126  int, // first valid column index
127  int // last valid column index
128  );
129 
130  /*
131  Description:
132  This constructor is for experts who have storage for a matrix
133  and need to use it in ON_Matrix form.
134  Parameters:
135  row_count - [in]
136  col_count - [in]
137  M - [in]
138  bDestructorFreeM - [in]
139  If true, ~ON_Matrix will call onfree(M).
140  If false, caller is managing M's memory.
141  Remarks:
142  ON_Matrix functions that increase the value of row_count or col_count
143  will fail on a matrix created with this constructor.
144  */
145  bool Create(
146  int row_count,
147  int col_count,
148  double** M,
149  bool bDestructorFreeM
150  );
151 
152 
153  void Destroy();
154 
155  void Zero();
156 
157  void SetDiagonal(double); // sets diagonal value and zeros off diagonal values
158  void SetDiagonal(const double*); // sets diagonal values and zeros off diagonal values
159  void SetDiagonal(int, const double*); // sets size to count x count and diagonal values and zeros off diagonal values
160  void SetDiagonal(const ON_SimpleArray<double>&); // sets size to length X lengthdiagonal values and zeros off diagonal values
161 
162  bool Transpose();
163 
164  bool SwapRows( int, int ); // ints are row indices to swap
165  bool SwapCols( int, int ); // ints are col indices to swap
166  bool Invert(
167  double // zero tolerance
168  );
169 
170  /*
171  Description:
172  Set this = A*B.
173  Parameters:
174  A - [in]
175  (Can be this)
176  B - [in]
177  (Can be this)
178  Returns:
179  True when A is an mXk matrix and B is a k X n matrix; in which case
180  "this" will be an mXn matrix = A*B.
181  False when A.ColCount() != B.RowCount().
182  */
183  bool Multiply( const ON_Matrix& A, const ON_Matrix& B );
184 
185  /*
186  Description:
187  Set this = A+B.
188  Parameters:
189  A - [in]
190  (Can be this)
191  B - [in]
192  (Can be this)
193  Returns:
194  True when A and B are mXn matrices; in which case
195  "this" will be an mXn matrix = A+B.
196  False when A and B have different sizes.
197  */
198  bool Add( const ON_Matrix& A, const ON_Matrix& B );
199 
200 
201  /*
202  Description:
203  Set this = s*this.
204  Parameters:
205  s - [in]
206  Returns:
207  True when A and s are valid.
208  */
209  bool Scale( double s );
210 
211 
212  // Description:
213  // Row reduce a matrix to calculate rank and determinant.
214  // Parameters:
215  // zero_tolerance - [in] (>=0.0) zero tolerance for pivot test
216  // If the absolute value of a pivot is <= zero_tolerance,
217  // then the pivot is assumed to be zero.
218  // determinant - [out] value of determinant is returned here.
219  // pivot - [out] value of the smallest pivot is returned here
220  // Returns:
221  // Rank of the matrix.
222  // Remarks:
223  // The matrix itself is row reduced so that the result is
224  // an upper triangular matrix with 1's on the diagonal.
225  int RowReduce( // returns rank
226  double, // zero_tolerance
227  double&, // determinant
228  double& // pivot
229  );
230 
231  // Description:
232  // Row reduce a matrix as the first step in solving M*X=B where
233  // B is a column of values.
234  // Parameters:
235  // zero_tolerance - [in] (>=0.0) zero tolerance for pivot test
236  // If the absolute value of a pivot is <= zero_tolerance,
237  // then the pivot is assumed to be zero.
238  // B - [in/out] an array of m_row_count values that is row reduced
239  // with the matrix.
240  // determinant - [out] value of determinant is returned here.
241  // pivot - [out] If not nullptr, then the value of the smallest
242  // pivot is returned here
243  // Returns:
244  // Rank of the matrix.
245  // Remarks:
246  // The matrix itself is row reduced so that the result is
247  // an upper triangular matrix with 1's on the diagonal.
248  // Example:
249  // Solve M*X=B;
250  // double B[m] = ...;
251  // double B[n] = ...;
252  // ON_Matrix M(m,n) = ...;
253  // M.RowReduce(ON_ZERO_TOLERANCE,B); // modifies M and B
254  // M.BackSolve(m,B,X); // solution is in X
255  // See Also:
256  // ON_Matrix::BackSolve
257  int RowReduce(
258  double, // zero_tolerance
259  double*, // B
260  double* = nullptr // pivot
261  );
262 
263  // Description:
264  // Row reduce a matrix as the first step in solving M*X=B where
265  // B is a column of 3d points
266  // Parameters:
267  // zero_tolerance - [in] (>=0.0) zero tolerance for pivot test
268  // If the absolute value of a pivot is <= zero_tolerance,
269  // then the pivot is assumed to be zero.
270  // B - [in/out] an array of m_row_count 3d points that is
271  // row reduced with the matrix.
272  // determinant - [out] value of determinant is returned here.
273  // pivot - [out] If not nullptr, then the value of the smallest
274  // pivot is returned here
275  // Returns:
276  // Rank of the matrix.
277  // Remarks:
278  // The matrix itself is row reduced so that the result is
279  // an upper triangular matrix with 1's on the diagonal.
280  // See Also:
281  // ON_Matrix::BackSolve
282  int RowReduce(
283  double, // zero_tolerance
284  ON_3dPoint*, // B
285  double* = nullptr // pivot
286  );
287 
288  // Description:
289  // Row reduce a matrix as the first step in solving M*X=B where
290  // B is a column arbitrary dimension points.
291  // Parameters:
292  // zero_tolerance - [in] (>=0.0) zero tolerance for pivot test
293  // If a the absolute value of a pivot is <= zero_tolerance,
294  // then the pivoit is assumed to be zero.
295  // pt_dim - [in] dimension of points
296  // pt_stride - [in] stride between points (>=pt_dim)
297  // pt - [in/out] array of m_row_count*pt_stride values.
298  // The i-th point is
299  // (pt[i*pt_stride],...,pt[i*pt_stride+pt_dim-1]).
300  // This array of points is row reduced along with the
301  // matrix.
302  // pivot - [out] If not nullptr, then the value of the smallest
303  // pivot is returned here
304  // Returns:
305  // Rank of the matrix.
306  // Remarks:
307  // The matrix itself is row reduced so that the result is
308  // an upper triangular matrix with 1's on the diagonal.
309  // See Also:
310  // ON_Matrix::BackSolve
311  int RowReduce( // returns rank
312  double, // zero_tolerance
313  int, // pt_dim
314  int, // pt_stride
315  double*, // pt
316  double* = nullptr // pivot
317  );
318 
319  // Description:
320  // Solve M*X=B where M is upper triangular with a unit diagonal and
321  // B is a column of values.
322  // Parameters:
323  // zero_tolerance - [in] (>=0.0) used to test for "zero" values in B
324  // in under determined systems of equations.
325  // Bsize - [in] (>=m_row_count) length of B. The values in
326  // B[m_row_count],...,B[Bsize-1] are tested to make sure they are
327  // "zero".
328  // B - [in] array of length Bsize.
329  // X - [out] array of length m_col_count. Solutions returned here.
330  // Remarks:
331  // Actual values M[i][j] with i <= j are ignored.
332  // M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero.
333  // For square M, B and X can point to the same memory.
334  // See Also:
335  // ON_Matrix::RowReduce
336  bool BackSolve(
337  double, // zero_tolerance
338  int, // Bsize
339  const double*, // B
340  double* // X
341  ) const;
342 
343  // Description:
344  // Solve M*X=B where M is upper triangular with a unit diagonal and
345  // B is a column of 3d points.
346  // Parameters:
347  // zero_tolerance - [in] (>=0.0) used to test for "zero" values in B
348  // in under determined systems of equations.
349  // Bsize - [in] (>=m_row_count) length of B. The values in
350  // B[m_row_count],...,B[Bsize-1] are tested to make sure they are
351  // "zero".
352  // B - [in] array of length Bsize.
353  // X - [out] array of length m_col_count. Solutions returned here.
354  // Remarks:
355  // Actual values M[i][j] with i <= j are ignored.
356  // M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero.
357  // For square M, B and X can point to the same memory.
358  // See Also:
359  // ON_Matrix::RowReduce
360  bool BackSolve(
361  double, // zero_tolerance
362  int, // Bsize
363  const ON_3dPoint*, // B
364  ON_3dPoint* // X
365  ) const;
366 
367  // Description:
368  // Solve M*X=B where M is upper triangular with a unit diagonal and
369  // B is a column of points
370  // Parameters:
371  // zero_tolerance - [in] (>=0.0) used to test for "zero" values in B
372  // in under determined systems of equations.
373  // pt_dim - [in] dimension of points
374  // Bsize - [in] (>=m_row_count) number of points in B[]. The points
375  // correspoinding to indices m_row_count, ..., (Bsize-1)
376  // are tested to make sure they are "zero".
377  // Bpt_stride - [in] stride between B points (>=pt_dim)
378  // Bpt - [in/out] array of m_row_count*Bpt_stride values.
379  // The i-th B point is
380  // (Bpt[i*Bpt_stride],...,Bpt[i*Bpt_stride+pt_dim-1]).
381  // Xpt_stride - [in] stride between X points (>=pt_dim)
382  // Xpt - [out] array of m_col_count*Xpt_stride values.
383  // The i-th X point is
384  // (Xpt[i*Xpt_stride],...,Xpt[i*Xpt_stride+pt_dim-1]).
385  // Remarks:
386  // Actual values M[i][j] with i <= j are ignored.
387  // M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero.
388  // For square M, B and X can point to the same memory.
389  // See Also:
390  // ON_Matrix::RowReduce
391  bool BackSolve(
392  double, // zero_tolerance
393  int, // pt_dim
394  int, // Bsize
395  int, // Bpt_stride
396  const double*,// Bpt
397  int, // Xpt_stride
398  double* // Xpt
399  ) const;
400 
401  bool IsRowOrthoganal() const;
402  bool IsRowOrthoNormal() const;
403 
404  bool IsColOrthoganal() const;
405  bool IsColOrthoNormal() const;
406 
407 
408  double** m = nullptr; // m[i][j] = value at row i and column j
409  // 0 <= i < RowCount()
410  // 0 <= j < ColCount()
411 private:
412  int m_row_count = 0;
413  int m_col_count = 0;
414  // m_rowmem[i][j] = row i+m_row_offset and column j+m_col_offset.
415  ON_SimpleArray<double*> m_rowmem;
416  double** m_Mmem = nullptr; // used by Create(row_count,col_count,user_memory,true);
417  int m_row_offset = 0; // = ri0 when sub-matrix constructor is used
418  int m_col_offset = 0; // = ci0 when sub-matrix constructor is used
419  void* m_cmem = nullptr;
420  // returns 0 based arrays, even in submatrix case.
421  double const * const * ThisM() const;
422  double * * ThisM();
423 };
424 
425 
426 /*
427 Description:
428  Perform simple row reduction on a matrix. If A is square, positive
429  definite, and really really nice, then the returned B is the inverse
430  of A. If A is not positive definite and really really nice, then it
431  is probably a waste of time to call this function.
432 Parameters:
433  row_count - [in]
434  col_count - [in]
435  zero_pivot - [in]
436  absolute values <= zero_pivot are considered to be zero
437  A - [in/out]
438  A row_count X col_count matrix. Input is the matrix to be
439  row reduced. The calculation destroys A, so output A is garbage.
440  B - [out]
441  A a row_count X row_count matrix. That records the row reduction.
442  pivots - [out]
443  minimum and maximum absolute values of pivots.
444 Returns:
445  Rank of A. If the returned value < min(row_count,col_count),
446  then a zero pivot was encountered.
447  If C = input value of A, then B*C = (I,*)
448 */
449 ON_DECL
450 int ON_RowReduce(
451  int row_count,
452  int col_count,
453  double zero_pivot,
454  double** A,
455  double** B,
456  double pivots[2]
457  );
458 
459 
460 /*
461 Description:
462  Calculate a row reduction matrix so that R*M = upper triangular matrixPerform simple row reduction on a matrix. If A is square, positive
463  definite, and really really nice, then the returned B is the inverse
464  of A. If A is not positive definite and really really nice, then it
465  is probably a waste of time to call this function.
466 Parameters:
467  row_count - [in]
468  col_count - [in]
469  zero_pivot - [in]
470  absolute values <= zero_pivot_tolerance are considered to be zero
471  constA - [in]
472  nullptr or a row_count x col_count matrix.
473  bInitializeB - [in]
474  If true, then B is set to the rox_count x row_count identity
475  before the calculation begins.
476  bInitializeColumnPermutation - [in]
477  If true and nullptr != column_permutation, then
478  column_permutation[] is initialized to (0, 1, ..., col_count-1)
479  before the calculation begins.
480  A - [in/out]
481  A row_count X col_count matrix.
482  If constA is not null, then A can be null or is the workspace used
483  to row reduce.
484  If constA is null, then the input A must not be null and must be initialized.
485  In all cases, the calculation destroys the contents of A and
486  output A contains garbage.
487  B - [in/out]
488  A a row_count X row_count matrix
489  The row operations applied to A are also applied to B.
490  If the input B is the identity, then R*(input A) would have zeros below the diagonal.
491  column_permutation - [in/out]
492  The permutation applied to the columns of A is also applied to
493  the column_permutation[] array.
494  pivots - [out]
495  pivots[0] = maximum nonzero pivot
496  pivots[1] = minimum nonzero pivot
497  pivots[2] = largest pivot that was treated as zero
498 Returns:
499  Rank of A. If the returned value < min(row_count,col_count),
500  then a zero pivot was encountered.
501  If C = input value of A, then B*C = (I,*)
502 */
503 ON_DECL
504 unsigned int ON_RowReduce(
505  unsigned int row_count,
506  unsigned col_count,
507  double zero_pivot_tolerance,
508  const double*const* constA,
509  bool bInitializeB,
510  bool bInitializeColumnPermutation,
511  double** A,
512  double** B,
513  unsigned int* column_permutation,
514  double pivots[3]
515  );
516 
517 /*
518 Parameters:
519  N - [in] >= 1
520  M - [in]
521  M is an NxN matrix
522 
523  bTransposeM - [in]
524  If true, the eigenvectors of the transpose of M are calculated.
525  Put another way, if bTransposeM is false, then the "right"
526  eigenvectors are calculated; if bTransposeM is true, then the "left"
527  eigenvectors are calculated.
528 
529  lambda - [in]
530  known eigenvalue of M
531 
532  lambda_multiplicity - [in]
533  > 0: known algebraic multiplicity of lambda
534  0: algebraic multiplicity is unknown.
535 
536  termination_tolerances - [in]
537  An array of three tolerances that control when the calculation
538  will stop searching for eigenvectors.
539  If you do not understand what pivot values are, then pass nullptr
540  and the values (1.0e-12, 1.0e-3, 1.0e4) will be used.
541  If termination_tolerances[0] is not strictly positive, then 1.0e-12 is used.
542  If termination_tolerances[1] is not strictly positive, then 1.0e-3 is used.
543  If termination_tolerances[2] is not strictly positive, then 1.0e4 is used.
544 
545  The search for eigenvectors will continue if condition 1,
546  and condition 2, and condition 3a or 3b is true.
547 
548  1) The number of found eigenvectors is < lambda_multiplicity.
549  2) eigenpivots[0] >= eigenpivots[1] > eigenpivots[2] >= 0.
550  3a) eigenpivots[1]/eigenpivots[0] < termination_tolerance[0].
551  3b) eigenpivots[1]/eigenpivots[0] > termination_tolerance[1]
552  or
553  eigenpivots[0] - eigenpivots[1] <= termination_tolerance[2]*eigenpivots[1].
554 
555  eigenvectors - [out]
556  eigenvectors[0,...,eigendim-1][0,...,N-1]
557  a basis for the lambda eigenspace. The eigenvectors are generally
558  neither normalized nor orthoganal.
559 
560  eigenprecision - [out]
561  eigenprecision[i] = maximum value of fabs(lambda*E[j] = E[j])/length(E) 0 <= j < N,
562  where E = eigenvectors[i].
563  If eigenprecision[i] is not "small" compared to nonzero coefficients in M and E,
564  then E is not precise.
565 
566  eigenpivots - [out]
567  eigenpivots[0] = maximum nonzero pivot
568  eigenpivots[1] = minimum nonzero pivot
569  eigenpivots[2] = maximum "zero" pivot
570  When eigenpivots[2] s not "small" compared to eigenpivots[1],
571  the answer is suspect.
572 
573 Returns:
574  Number of eigenvectors found. In stable cases, this is the geometric
575  multiplicity of the eigenvalue.
576 */
577 ON_DECL
578 unsigned int ON_GetEigenvectors(
579  const unsigned int N,
580  const double*const* M,
581  bool bTransposeM,
582  double lambda,
583  unsigned int lambda_multiplicity,
584  const double* termination_tolerances,
585  double** eigenvectors,
586  double* eigenprecision,
587  double* eigenpivots
588  );
589 
590 ON_DECL
591 double ON_EigenvectorPrecision(
592  const unsigned int N,
593  const double*const* M,
594  bool bTransposeM,
595  double lambda,
596  const double* eigenvector
597  );
598 
599 /*
600 Returns:
601  Maximum of fabs( ((M-lambda*I)*X)[i] - B[i] ) for 0 <= i < N
602  Pass lambda = 0.0 if you're not testing some type of generalized eigenvalue.
603 */
604 ON_DECL
605 double ON_MatrixSolutionPrecision(
606  const unsigned int N,
607  const double*const* M,
608  bool bTransposeM,
609  double lambda,
610  const double* X,
611  const double* B
612  );
613 
614 #endif
Definition: opennurbs_xform.h:28
Definition: opennurbs_matrix.h:22
Definition: opennurbs_point.h:460