26using namespace Qt::StringLiterals;
29#define GSL_RANGE_CHECK_OFF
32#include <gsl/gsl_matrix.h>
33#include <gsl/gsl_vector.h>
34#include <gsl/gsl_linalg.h>
35#include <gsl/gsl_errno.h>
42 gsl_matrix *maxMatrix =
nullptr;
43 gsl_vector *maxVectorB =
nullptr;
44 gsl_vector *maxVectorX =
nullptr;
47 std::vector<gsl_permutation *> permutations;
49 gsl_matrix *matrixA_Copy =
nullptr;
50 gsl_matrix *matrixV =
nullptr;
51 gsl_vector *vectorS =
nullptr;
52 gsl_vector *workSvd =
nullptr;
66 : mData( std::make_unique<
GslData>() )
76 static std::once_flag sGslErrorHandlerFlag;
77 std::call_once( sGslErrorHandlerFlag, []() { gsl_set_error_handler_off(); } );
92 mData->permutations[i] = gsl_permutation_alloc( i );
100 if ( mData->maxMatrix )
102 gsl_matrix_free( mData->maxMatrix );
104 if ( mData->maxVectorB )
106 gsl_vector_free( mData->maxVectorB );
108 if ( mData->maxVectorX )
110 gsl_vector_free( mData->maxVectorX );
112 if ( mData->matrixA_Copy )
114 gsl_matrix_free( mData->matrixA_Copy );
116 if ( mData->matrixV )
118 gsl_matrix_free( mData->matrixV );
120 if ( mData->vectorS )
122 gsl_vector_free( mData->vectorS );
124 if ( mData->workSvd )
126 gsl_vector_free( mData->workSvd );
129 for (
auto *p : mData->permutations )
133 gsl_permutation_free( p );
141 return mData->maximumDimension;
147 gsl_matrix_set( mData->maxMatrix, row, column, value );
159 gsl_vector_set( mData->maxVectorB, row, value );
169 if ( dimension <= 0 )
173 if ( dimension > mData->maximumDimension )
180 return solveLu( dimension, result,
false );
183 return solveSvd( dimension, result,
false );
187 if ( solveLu( dimension, result,
true ) )
191 return solveSvd( dimension, result,
false );
198bool QgsMatrixSolver::solveLu(
int dimension, QVector<double> &result,
bool retainOriginalMatrices )
202 gsl_matrix_view A_view = gsl_matrix_submatrix( mData->maxMatrix, 0, 0, dimension, dimension );
203 gsl_matrix_view A_copy = gsl_matrix_submatrix( mData->matrixA_Copy, 0, 0, dimension, dimension );
205 gsl_vector_view B_view = gsl_vector_subvector( mData->maxVectorB, 0, dimension );
206 gsl_vector_view X_view = gsl_vector_subvector( mData->maxVectorX, 0, dimension );
208 gsl_matrix *A = &A_view.matrix;
209 if ( retainOriginalMatrices )
211 gsl_matrix_memcpy( &A_copy.matrix, &A_view.matrix );
215 gsl_permutation *p = mData->permutations[dimension];
217 gsl_linalg_LU_decomp( A, p, &signum );
218 if ( gsl_linalg_LU_solve( A, p, &B_view.vector, &X_view.vector ) != 0 )
223 result.resize( dimension );
224 for (
int i = 0; i < dimension; ++i )
226 result[i] = gsl_vector_get( &X_view.vector, i );
233 throw QgsNotSupportedException( u
"QgsMatrixSolver requires a QGIS build with GSL support enabled"_s );
237bool QgsMatrixSolver::solveSvd(
int dimension, QVector<double> &result,
bool retainOriginalMatrices )
240 gsl_matrix_view A_view = gsl_matrix_submatrix( mData->maxMatrix, 0, 0, dimension, dimension );
241 gsl_matrix_view A_copy = gsl_matrix_submatrix( mData->matrixA_Copy, 0, 0, dimension, dimension );
242 gsl_matrix_view V = gsl_matrix_submatrix( mData->matrixV, 0, 0, dimension, dimension );
243 gsl_vector_view S = gsl_vector_subvector( mData->vectorS, 0, dimension );
244 gsl_vector_view b = gsl_vector_subvector( mData->maxVectorB, 0, dimension );
245 gsl_vector_view x = gsl_vector_subvector( mData->maxVectorX, 0, dimension );
246 gsl_vector_view work = gsl_vector_subvector( mData->workSvd, 0, dimension );
248 gsl_matrix *A = &A_view.matrix;
249 if ( retainOriginalMatrices )
251 gsl_matrix_memcpy( &A_copy.matrix, &A_view.matrix );
256 if ( gsl_linalg_SV_decomp( A, &V.matrix, &S.vector, &work.vector ) != 0 )
263 if ( gsl_linalg_SV_solve( A, &V.matrix, &S.vector, &b.vector, &x.vector ) != 0 )
268 result.resize( dimension );
269 for (
int i = 0; i < dimension; ++i )
271 result[i] = gsl_vector_get( &x.vector, i );
278 throw QgsNotSupportedException( u
"QgsMatrixSolver requires a QGIS build with GSL support enabled"_s );
LinearMatrixMethod
Mathematical methods to use for solving linear matrix equations.
@ Lu
Fast lower-upper (LU) decomposition (fails on singular/collinear matrices).
@ LuWithSvdFallback
Try LU first; fallback to SVD on singularity.
@ Svd
Singular Value Decomposition (handles collinearity and rank deficiency).
Custom exception class when argument are invalid.
void setRightHandSide(int row, double value)
Sets a value in the preallocated right-hand-side vector b.
QgsMatrixSolver(int maximumDimension)
Constructor for QgsMatrixSolver, pre-allocated to solve matrices with the specified maximumDimension.
bool solve(int dimension, QVector< double > &result, Qgis::LinearMatrixMethod method=Qgis::LinearMatrixMethod::Lu)
Solves the system Ax = b for a specific active dimension.
void setValue(int row, int column, double value)
Sets the value for row, column in the preallocated matrix A.
int maximumDimension() const
Returns the maximum dimension supported by this solver.
static bool isAvailable()
Returns true if the matrix solver functionality is available on the current system.
Custom exception class which is raised when an operation is not supported.