mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-04 06:07:00 +08:00
615 lines
20 KiB
C++
615 lines
20 KiB
C++
/* $NoKeywords: $ */
|
|
/*
|
|
//
|
|
// Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
#if !defined(ON_MATRIX_INC_)
|
|
#define ON_MATRIX_INC_
|
|
|
|
class ON_Xform;
|
|
|
|
class ON_CLASS ON_Matrix
|
|
{
|
|
public:
|
|
ON_Matrix();
|
|
ON_Matrix(
|
|
int row_count,
|
|
int col_count
|
|
);
|
|
ON_Matrix( // see ON_Matrix::Create(int,int,int,int) for details
|
|
int, // first valid row index
|
|
int, // last valid row index
|
|
int, // first valid column index
|
|
int // last valid column index
|
|
);
|
|
ON_Matrix( const ON_Xform& );
|
|
ON_Matrix( const ON_Matrix& );
|
|
|
|
#if defined(ON_HAS_RVALUEREF)
|
|
// rvalue copy constructor
|
|
ON_Matrix(ON_Matrix&&) ON_NOEXCEPT;
|
|
|
|
// The rvalue assignment operator calls ON_Object::operator=(ON_Object&&)
|
|
// which could throw exceptions. See the implementation of
|
|
// ON_Object::operator=(ON_Object&&) for details.
|
|
ON_Matrix& operator=(ON_Matrix&&);
|
|
#endif
|
|
|
|
/*
|
|
Description:
|
|
This constructor is for experts who have storage for a matrix
|
|
and need to use it in ON_Matrix form.
|
|
Parameters:
|
|
row_count - [in]
|
|
col_count - [in]
|
|
M - [in]
|
|
bDestructorFreeM - [in]
|
|
If true, ~ON_Matrix will call onfree(M).
|
|
If false, caller is managing M's memory.
|
|
Remarks:
|
|
ON_Matrix functions that increase the value of row_count or col_count
|
|
will fail on a matrix created with this constructor.
|
|
*/
|
|
ON_Matrix(
|
|
int row_count,
|
|
int col_count,
|
|
double** M,
|
|
bool bDestructorFreeM
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
A row_count X col_count martix on the heap that can be
|
|
deleted by calling ON_Matrix::Deallocate().
|
|
*/
|
|
static double** Allocate(
|
|
unsigned int row_count,
|
|
unsigned int col_count
|
|
);
|
|
|
|
static void Deallocate(
|
|
double** M
|
|
);
|
|
|
|
virtual ~ON_Matrix();
|
|
void EmergencyDestroy(); // call if memory pool used matrix by becomes invalid
|
|
|
|
// ON_Matrix[i][j] = value at row i and column j
|
|
// 0 <= i < RowCount()
|
|
// 0 <= j < ColCount()
|
|
double* operator[](int);
|
|
const double* operator[](int) const;
|
|
|
|
ON_Matrix& operator=(const ON_Matrix&);
|
|
ON_Matrix& operator=(const ON_Xform&);
|
|
|
|
bool IsValid() const;
|
|
int IsSquare() const; // returns 0 for no and m_row_count (= m_col_count) for yes
|
|
|
|
int RowCount() const;
|
|
int ColCount() const;
|
|
int MinCount() const; // smallest of row and column count
|
|
int MaxCount() const; // largest of row and column count
|
|
|
|
unsigned int UnsignedRowCount() const;
|
|
unsigned int UnsignedColCount() const;
|
|
unsigned int UnsignedMinCount() const; // smallest of row and column count
|
|
unsigned int UnsignedMaxCount() const; // largest of row and column count
|
|
|
|
void RowScale(int,double);
|
|
void ColScale(int,double);
|
|
void RowOp(int,double,int);
|
|
void ColOp(int,double,int);
|
|
|
|
bool Create(
|
|
int, // number of rows
|
|
int // number of columns
|
|
);
|
|
|
|
bool Create( // E.g., Create(1,5,1,7) creates a 5x7 sized matrix that with
|
|
// "top" row = m[1][1],...,m[1][7] and "bottom" row
|
|
// = m[5][1],...,m[5][7]. The result of Create(0,m,0,n) is
|
|
// identical to the result of Create(m+1,n+1).
|
|
int, // first valid row index
|
|
int, // last valid row index
|
|
int, // first valid column index
|
|
int // last valid column index
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
This constructor is for experts who have storage for a matrix
|
|
and need to use it in ON_Matrix form.
|
|
Parameters:
|
|
row_count - [in]
|
|
col_count - [in]
|
|
M - [in]
|
|
bDestructorFreeM - [in]
|
|
If true, ~ON_Matrix will call onfree(M).
|
|
If false, caller is managing M's memory.
|
|
Remarks:
|
|
ON_Matrix functions that increase the value of row_count or col_count
|
|
will fail on a matrix created with this constructor.
|
|
*/
|
|
bool Create(
|
|
int row_count,
|
|
int col_count,
|
|
double** M,
|
|
bool bDestructorFreeM
|
|
);
|
|
|
|
|
|
void Destroy();
|
|
|
|
void Zero();
|
|
|
|
void SetDiagonal(double); // sets diagonal value and zeros off diagonal values
|
|
void SetDiagonal(const double*); // sets diagonal values and zeros off diagonal values
|
|
void SetDiagonal(int, const double*); // sets size to count x count and diagonal values and zeros off diagonal values
|
|
void SetDiagonal(const ON_SimpleArray<double>&); // sets size to length X lengthdiagonal values and zeros off diagonal values
|
|
|
|
bool Transpose();
|
|
|
|
bool SwapRows( int, int ); // ints are row indices to swap
|
|
bool SwapCols( int, int ); // ints are col indices to swap
|
|
bool Invert(
|
|
double // zero tolerance
|
|
);
|
|
|
|
/*
|
|
Description:
|
|
Set this = A*B.
|
|
Parameters:
|
|
A - [in]
|
|
(Can be this)
|
|
B - [in]
|
|
(Can be this)
|
|
Returns:
|
|
True when A is an mXk matrix and B is a k X n matrix; in which case
|
|
"this" will be an mXn matrix = A*B.
|
|
False when A.ColCount() != B.RowCount().
|
|
*/
|
|
bool Multiply( const ON_Matrix& A, const ON_Matrix& B );
|
|
|
|
/*
|
|
Description:
|
|
Set this = A+B.
|
|
Parameters:
|
|
A - [in]
|
|
(Can be this)
|
|
B - [in]
|
|
(Can be this)
|
|
Returns:
|
|
True when A and B are mXn matrices; in which case
|
|
"this" will be an mXn matrix = A+B.
|
|
False when A and B have different sizes.
|
|
*/
|
|
bool Add( const ON_Matrix& A, const ON_Matrix& B );
|
|
|
|
|
|
/*
|
|
Description:
|
|
Set this = s*this.
|
|
Parameters:
|
|
s - [in]
|
|
Returns:
|
|
True when A and s are valid.
|
|
*/
|
|
bool Scale( double s );
|
|
|
|
|
|
// Description:
|
|
// Row reduce a matrix to calculate rank and determinant.
|
|
// Parameters:
|
|
// zero_tolerance - [in] (>=0.0) zero tolerance for pivot test
|
|
// If the absolute value of a pivot is <= zero_tolerance,
|
|
// then the pivot is assumed to be zero.
|
|
// determinant - [out] value of determinant is returned here.
|
|
// pivot - [out] value of the smallest pivot is returned here
|
|
// Returns:
|
|
// Rank of the matrix.
|
|
// Remarks:
|
|
// The matrix itself is row reduced so that the result is
|
|
// an upper triangular matrix with 1's on the diagonal.
|
|
int RowReduce( // returns rank
|
|
double, // zero_tolerance
|
|
double&, // determinant
|
|
double& // pivot
|
|
);
|
|
|
|
// Description:
|
|
// Row reduce a matrix as the first step in solving M*X=B where
|
|
// B is a column of values.
|
|
// Parameters:
|
|
// zero_tolerance - [in] (>=0.0) zero tolerance for pivot test
|
|
// If the absolute value of a pivot is <= zero_tolerance,
|
|
// then the pivot is assumed to be zero.
|
|
// B - [in/out] an array of m_row_count values that is row reduced
|
|
// with the matrix.
|
|
// determinant - [out] value of determinant is returned here.
|
|
// pivot - [out] If not nullptr, then the value of the smallest
|
|
// pivot is returned here
|
|
// Returns:
|
|
// Rank of the matrix.
|
|
// Remarks:
|
|
// The matrix itself is row reduced so that the result is
|
|
// an upper triangular matrix with 1's on the diagonal.
|
|
// Example:
|
|
// Solve M*X=B;
|
|
// double B[m] = ...;
|
|
// double B[n] = ...;
|
|
// ON_Matrix M(m,n) = ...;
|
|
// M.RowReduce(ON_ZERO_TOLERANCE,B); // modifies M and B
|
|
// M.BackSolve(m,B,X); // solution is in X
|
|
// See Also:
|
|
// ON_Matrix::BackSolve
|
|
int RowReduce(
|
|
double, // zero_tolerance
|
|
double*, // B
|
|
double* = nullptr // pivot
|
|
);
|
|
|
|
// Description:
|
|
// Row reduce a matrix as the first step in solving M*X=B where
|
|
// B is a column of 3d points
|
|
// Parameters:
|
|
// zero_tolerance - [in] (>=0.0) zero tolerance for pivot test
|
|
// If the absolute value of a pivot is <= zero_tolerance,
|
|
// then the pivot is assumed to be zero.
|
|
// B - [in/out] an array of m_row_count 3d points that is
|
|
// row reduced with the matrix.
|
|
// determinant - [out] value of determinant is returned here.
|
|
// pivot - [out] If not nullptr, then the value of the smallest
|
|
// pivot is returned here
|
|
// Returns:
|
|
// Rank of the matrix.
|
|
// Remarks:
|
|
// The matrix itself is row reduced so that the result is
|
|
// an upper triangular matrix with 1's on the diagonal.
|
|
// See Also:
|
|
// ON_Matrix::BackSolve
|
|
int RowReduce(
|
|
double, // zero_tolerance
|
|
ON_3dPoint*, // B
|
|
double* = nullptr // pivot
|
|
);
|
|
|
|
// Description:
|
|
// Row reduce a matrix as the first step in solving M*X=B where
|
|
// B is a column arbitrary dimension points.
|
|
// Parameters:
|
|
// zero_tolerance - [in] (>=0.0) zero tolerance for pivot test
|
|
// If a the absolute value of a pivot is <= zero_tolerance,
|
|
// then the pivoit is assumed to be zero.
|
|
// pt_dim - [in] dimension of points
|
|
// pt_stride - [in] stride between points (>=pt_dim)
|
|
// pt - [in/out] array of m_row_count*pt_stride values.
|
|
// The i-th point is
|
|
// (pt[i*pt_stride],...,pt[i*pt_stride+pt_dim-1]).
|
|
// This array of points is row reduced along with the
|
|
// matrix.
|
|
// pivot - [out] If not nullptr, then the value of the smallest
|
|
// pivot is returned here
|
|
// Returns:
|
|
// Rank of the matrix.
|
|
// Remarks:
|
|
// The matrix itself is row reduced so that the result is
|
|
// an upper triangular matrix with 1's on the diagonal.
|
|
// See Also:
|
|
// ON_Matrix::BackSolve
|
|
int RowReduce( // returns rank
|
|
double, // zero_tolerance
|
|
int, // pt_dim
|
|
int, // pt_stride
|
|
double*, // pt
|
|
double* = nullptr // pivot
|
|
);
|
|
|
|
// Description:
|
|
// Solve M*X=B where M is upper triangular with a unit diagonal and
|
|
// B is a column of values.
|
|
// Parameters:
|
|
// zero_tolerance - [in] (>=0.0) used to test for "zero" values in B
|
|
// in under determined systems of equations.
|
|
// Bsize - [in] (>=m_row_count) length of B. The values in
|
|
// B[m_row_count],...,B[Bsize-1] are tested to make sure they are
|
|
// "zero".
|
|
// B - [in] array of length Bsize.
|
|
// X - [out] array of length m_col_count. Solutions returned here.
|
|
// Remarks:
|
|
// Actual values M[i][j] with i <= j are ignored.
|
|
// M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero.
|
|
// For square M, B and X can point to the same memory.
|
|
// See Also:
|
|
// ON_Matrix::RowReduce
|
|
bool BackSolve(
|
|
double, // zero_tolerance
|
|
int, // Bsize
|
|
const double*, // B
|
|
double* // X
|
|
) const;
|
|
|
|
// Description:
|
|
// Solve M*X=B where M is upper triangular with a unit diagonal and
|
|
// B is a column of 3d points.
|
|
// Parameters:
|
|
// zero_tolerance - [in] (>=0.0) used to test for "zero" values in B
|
|
// in under determined systems of equations.
|
|
// Bsize - [in] (>=m_row_count) length of B. The values in
|
|
// B[m_row_count],...,B[Bsize-1] are tested to make sure they are
|
|
// "zero".
|
|
// B - [in] array of length Bsize.
|
|
// X - [out] array of length m_col_count. Solutions returned here.
|
|
// Remarks:
|
|
// Actual values M[i][j] with i <= j are ignored.
|
|
// M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero.
|
|
// For square M, B and X can point to the same memory.
|
|
// See Also:
|
|
// ON_Matrix::RowReduce
|
|
bool BackSolve(
|
|
double, // zero_tolerance
|
|
int, // Bsize
|
|
const ON_3dPoint*, // B
|
|
ON_3dPoint* // X
|
|
) const;
|
|
|
|
// Description:
|
|
// Solve M*X=B where M is upper triangular with a unit diagonal and
|
|
// B is a column of points
|
|
// Parameters:
|
|
// zero_tolerance - [in] (>=0.0) used to test for "zero" values in B
|
|
// in under determined systems of equations.
|
|
// pt_dim - [in] dimension of points
|
|
// Bsize - [in] (>=m_row_count) number of points in B[]. The points
|
|
// correspoinding to indices m_row_count, ..., (Bsize-1)
|
|
// are tested to make sure they are "zero".
|
|
// Bpt_stride - [in] stride between B points (>=pt_dim)
|
|
// Bpt - [in/out] array of m_row_count*Bpt_stride values.
|
|
// The i-th B point is
|
|
// (Bpt[i*Bpt_stride],...,Bpt[i*Bpt_stride+pt_dim-1]).
|
|
// Xpt_stride - [in] stride between X points (>=pt_dim)
|
|
// Xpt - [out] array of m_col_count*Xpt_stride values.
|
|
// The i-th X point is
|
|
// (Xpt[i*Xpt_stride],...,Xpt[i*Xpt_stride+pt_dim-1]).
|
|
// Remarks:
|
|
// Actual values M[i][j] with i <= j are ignored.
|
|
// M[i][i] is assumed to be one and M[i][j] i<j is assumed to be zero.
|
|
// For square M, B and X can point to the same memory.
|
|
// See Also:
|
|
// ON_Matrix::RowReduce
|
|
bool BackSolve(
|
|
double, // zero_tolerance
|
|
int, // pt_dim
|
|
int, // Bsize
|
|
int, // Bpt_stride
|
|
const double*,// Bpt
|
|
int, // Xpt_stride
|
|
double* // Xpt
|
|
) const;
|
|
|
|
bool IsRowOrthoganal() const;
|
|
bool IsRowOrthoNormal() const;
|
|
|
|
bool IsColOrthoganal() const;
|
|
bool IsColOrthoNormal() const;
|
|
|
|
|
|
double** m = nullptr; // m[i][j] = value at row i and column j
|
|
// 0 <= i < RowCount()
|
|
// 0 <= j < ColCount()
|
|
private:
|
|
int m_row_count = 0;
|
|
int m_col_count = 0;
|
|
// m_rowmem[i][j] = row i+m_row_offset and column j+m_col_offset.
|
|
ON_SimpleArray<double*> m_rowmem;
|
|
double** m_Mmem = nullptr; // used by Create(row_count,col_count,user_memory,true);
|
|
int m_row_offset = 0; // = ri0 when sub-matrix constructor is used
|
|
int m_col_offset = 0; // = ci0 when sub-matrix constructor is used
|
|
void* m_cmem = nullptr;
|
|
// returns 0 based arrays, even in submatrix case.
|
|
double const * const * ThisM() const;
|
|
double * * ThisM();
|
|
};
|
|
|
|
|
|
/*
|
|
Description:
|
|
Perform simple row reduction on a matrix. If A is square, positive
|
|
definite, and really really nice, then the returned B is the inverse
|
|
of A. If A is not positive definite and really really nice, then it
|
|
is probably a waste of time to call this function.
|
|
Parameters:
|
|
row_count - [in]
|
|
col_count - [in]
|
|
zero_pivot - [in]
|
|
absolute values <= zero_pivot are considered to be zero
|
|
A - [in/out]
|
|
A row_count X col_count matrix. Input is the matrix to be
|
|
row reduced. The calculation destroys A, so output A is garbage.
|
|
B - [out]
|
|
A a row_count X row_count matrix. That records the row reduction.
|
|
pivots - [out]
|
|
minimum and maximum absolute values of pivots.
|
|
Returns:
|
|
Rank of A. If the returned value < min(row_count,col_count),
|
|
then a zero pivot was encountered.
|
|
If C = input value of A, then B*C = (I,*)
|
|
*/
|
|
ON_DECL
|
|
int ON_RowReduce(
|
|
int row_count,
|
|
int col_count,
|
|
double zero_pivot,
|
|
double** A,
|
|
double** B,
|
|
double pivots[2]
|
|
);
|
|
|
|
|
|
/*
|
|
Description:
|
|
Calculate a row reduction matrix so that R*M = upper triangular matrixPerform simple row reduction on a matrix. If A is square, positive
|
|
definite, and really really nice, then the returned B is the inverse
|
|
of A. If A is not positive definite and really really nice, then it
|
|
is probably a waste of time to call this function.
|
|
Parameters:
|
|
row_count - [in]
|
|
col_count - [in]
|
|
zero_pivot - [in]
|
|
absolute values <= zero_pivot_tolerance are considered to be zero
|
|
constA - [in]
|
|
nullptr or a row_count x col_count matrix.
|
|
bInitializeB - [in]
|
|
If true, then B is set to the rox_count x row_count identity
|
|
before the calculation begins.
|
|
bInitializeColumnPermutation - [in]
|
|
If true and nullptr != column_permutation, then
|
|
column_permutation[] is initialized to (0, 1, ..., col_count-1)
|
|
before the calculation begins.
|
|
A - [in/out]
|
|
A row_count X col_count matrix.
|
|
If constA is not null, then A can be null or is the workspace used
|
|
to row reduce.
|
|
If constA is null, then the input A must not be null and must be initialized.
|
|
In all cases, the calculation destroys the contents of A and
|
|
output A contains garbage.
|
|
B - [in/out]
|
|
A a row_count X row_count matrix
|
|
The row operations applied to A are also applied to B.
|
|
If the input B is the identity, then R*(input A) would have zeros below the diagonal.
|
|
column_permutation - [in/out]
|
|
The permutation applied to the columns of A is also applied to
|
|
the column_permutation[] array.
|
|
pivots - [out]
|
|
pivots[0] = maximum nonzero pivot
|
|
pivots[1] = minimum nonzero pivot
|
|
pivots[2] = largest pivot that was treated as zero
|
|
Returns:
|
|
Rank of A. If the returned value < min(row_count,col_count),
|
|
then a zero pivot was encountered.
|
|
If C = input value of A, then B*C = (I,*)
|
|
*/
|
|
ON_DECL
|
|
unsigned int ON_RowReduce(
|
|
unsigned int row_count,
|
|
unsigned col_count,
|
|
double zero_pivot_tolerance,
|
|
const double*const* constA,
|
|
bool bInitializeB,
|
|
bool bInitializeColumnPermutation,
|
|
double** A,
|
|
double** B,
|
|
unsigned int* column_permutation,
|
|
double pivots[3]
|
|
);
|
|
|
|
/*
|
|
Parameters:
|
|
N - [in] >= 1
|
|
M - [in]
|
|
M is an NxN matrix
|
|
|
|
bTransposeM - [in]
|
|
If true, the eigenvectors of the transpose of M are calculated.
|
|
Put another way, if bTransposeM is false, then the "right"
|
|
eigenvectors are calculated; if bTransposeM is true, then the "left"
|
|
eigenvectors are calculated.
|
|
|
|
lambda - [in]
|
|
known eigenvalue of M
|
|
|
|
lambda_multiplicity - [in]
|
|
> 0: known algebraic multiplicity of lambda
|
|
0: algebraic multiplicity is unknown.
|
|
|
|
termination_tolerances - [in]
|
|
An array of three tolerances that control when the calculation
|
|
will stop searching for eigenvectors.
|
|
If you do not understand what pivot values are, then pass nullptr
|
|
and the values (1.0e-12, 1.0e-3, 1.0e4) will be used.
|
|
If termination_tolerances[0] is not strictly positive, then 1.0e-12 is used.
|
|
If termination_tolerances[1] is not strictly positive, then 1.0e-3 is used.
|
|
If termination_tolerances[2] is not strictly positive, then 1.0e4 is used.
|
|
|
|
The search for eigenvectors will continue if condition 1,
|
|
and condition 2, and condition 3a or 3b is true.
|
|
|
|
1) The number of found eigenvectors is < lambda_multiplicity.
|
|
2) eigenpivots[0] >= eigenpivots[1] > eigenpivots[2] >= 0.
|
|
3a) eigenpivots[1]/eigenpivots[0] < termination_tolerance[0].
|
|
3b) eigenpivots[1]/eigenpivots[0] > termination_tolerance[1]
|
|
or
|
|
eigenpivots[0] - eigenpivots[1] <= termination_tolerance[2]*eigenpivots[1].
|
|
|
|
eigenvectors - [out]
|
|
eigenvectors[0,...,eigendim-1][0,...,N-1]
|
|
a basis for the lambda eigenspace. The eigenvectors are generally
|
|
neither normalized nor orthoganal.
|
|
|
|
eigenprecision - [out]
|
|
eigenprecision[i] = maximum value of fabs(lambda*E[j] = E[j])/length(E) 0 <= j < N,
|
|
where E = eigenvectors[i].
|
|
If eigenprecision[i] is not "small" compared to nonzero coefficients in M and E,
|
|
then E is not precise.
|
|
|
|
eigenpivots - [out]
|
|
eigenpivots[0] = maximum nonzero pivot
|
|
eigenpivots[1] = minimum nonzero pivot
|
|
eigenpivots[2] = maximum "zero" pivot
|
|
When eigenpivots[2] s not "small" compared to eigenpivots[1],
|
|
the answer is suspect.
|
|
|
|
Returns:
|
|
Number of eigenvectors found. In stable cases, this is the geometric
|
|
multiplicity of the eigenvalue.
|
|
*/
|
|
ON_DECL
|
|
unsigned int ON_GetEigenvectors(
|
|
const unsigned int N,
|
|
const double*const* M,
|
|
bool bTransposeM,
|
|
double lambda,
|
|
unsigned int lambda_multiplicity,
|
|
const double* termination_tolerances,
|
|
double** eigenvectors,
|
|
double* eigenprecision,
|
|
double* eigenpivots
|
|
);
|
|
|
|
ON_DECL
|
|
double ON_EigenvectorPrecision(
|
|
const unsigned int N,
|
|
const double*const* M,
|
|
bool bTransposeM,
|
|
double lambda,
|
|
const double* eigenvector
|
|
);
|
|
|
|
/*
|
|
Returns:
|
|
Maximum of fabs( ((M-lambda*I)*X)[i] - B[i] ) for 0 <= i < N
|
|
Pass lambda = 0.0 if you're not testing some type of generalized eigenvalue.
|
|
*/
|
|
ON_DECL
|
|
double ON_MatrixSolutionPrecision(
|
|
const unsigned int N,
|
|
const double*const* M,
|
|
bool bTransposeM,
|
|
double lambda,
|
|
const double* X,
|
|
const double* B
|
|
);
|
|
|
|
#endif
|