I am trying to calculate a determinant using the boost c++ libraries. I found the code for the function InvertMatrix() which I have copied below. Every time I calculate this inverse, I want the determinant as well. I have a good idea how to calculate, by multiplying down the diagonal of the U matrix from the LU decomposition. There is one problem, I am able to calculate the determinant properly, except for the sign. Depending on the pivoting I get the sign incorrect half of the time. Does anyone have a suggestion on how to get the sign right every time? Thanks in advance.
template<class T>
bool InvertMatrix(const ublas::matrix<T>& input, ublas::matrix<T>& inverse)
{
using namespace boost::numeric::ublas;
typedef permutation_matrix<std::size_t> pmatrix;
// create a working copy of the input
matrix<T> A(input);
// create a permutation matrix for the LU-factorization
pmatrix pm(A.size1());
// perform LU-factorization
int res = lu_factorize(A,pm);
if( res != 0 ) return false;
Here is where I inserted my best shot at calculating the determinant.
T determinant = 1;
for(int i = 0; i < A.size1(); i++)
{
determinant *= A(i,i);
}
End my portion of the code.
// create identity matrix of "inverse"
inverse.assign(ublas::identity_matrix<T>(A.size1()));
// backsubstitute to get the inverse
lu_substitute(A, pm, inverse);
return true;
}
The permutation matrix pm
contains the information you'll need to determine the sign change: you'll want to multiply your determinant by the determinant of the permutation matrix.
Perusing the source file lu.hpp
we find a function called swap_rows
which tells how to apply a permutation matrix to a matrix. It's easily modified to yield the determinant of the permutation matrix (the sign of the permutation), given that each actual swap contributes a factor of -1:
template <typename size_type, typename A>
int determinant(const permutation_matrix<size_type,A>& pm)
{
int pm_sign=1;
size_type size=pm.size();
for (size_type i = 0; i < size; ++i)
if (i != pm(i))
pm_sign* = -1; // swap_rows would swap a pair of rows here, so we change sign
return pm_sign;
}
Another alternative would be to use the lu_factorize
and lu_substitute
methods which don't do any pivoting (consult the source, but basically drop the pm
in the calls to lu_factorize
and lu_substitute
). That change would make your determinant calculation work as-is. Be careful, however: removing pivoting will make the algorithm less numerically stable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With