Browse Source

Math/Algorithms: improve SVD docs, add a test for xform decomposition.

pull/268/head
Vladimír Vondruš 8 years ago
parent
commit
44b059bbc5
  1. 21
      src/Magnum/Math/Algorithms/Svd.h
  2. 29
      src/Magnum/Math/Algorithms/Test/SvdTest.cpp

21
src/Magnum/Math/Algorithms/Svd.h

@ -60,20 +60,25 @@ template<> constexpr Double smallestDelta<Double>() { return 1.0e-64; }
Performs [Thin SVD](https://en.wikipedia.org/wiki/Singular-value_decomposition#Thin_SVD)
on given matrix where @p rows >= `cols`: @f[
M = U \Sigma V^*
\boldsymbol{M} = \boldsymbol{U} \boldsymbol{\Sigma} \boldsymbol{V}^*
@f]
Returns first @p cols column vectors of @f$ U @f$, diagonal of @f$ \Sigma @f$
and non-transposed @f$ V @f$. If the solution doesn't converge, returns
zero matrices.
Returns first @p cols column vectors of @f$ \boldsymbol{U} @f$, diagonal of
@f$ \boldsymbol{\Sigma} @f$ and non-transposed @f$ \boldsymbol{V} @f$. If the
solution doesn't converge, returns zero matrices.
Full @f$ U @f$, @f$ \Sigma @f$ matrices and original @f$ M @f$ matrix can be
reconstructed from the values as following:
Full @f$ \boldsymbol{U} @f$, @f$ \boldsymbol{\Sigma} @f$ matrices and original
@f$ \boldsymbol{M} @f$ matrix can be reconstructed from the values as
following:
@snippet MagnumMathAlgorithms.cpp svd
Implementation based on *Golub, G. H.; Reinsch, C. (1970). "Singular value
decomposition and least squares solutions"*.
One possible use is to decompose a transformation matrix into separate rotation
and scaling parts. Note, however, that the decomposition is not unique. See the
[associated test case](https://github.com/mosra/magnum/blob/master/src/Magnum/Math/Algorithms/Test/SvdTest.cpp)
for an example. Implementation based on *Golub, G. H.; Reinsch, C. (1970).
"Singular value decomposition and least squares solutions"*.
@see @ref qr(), @ref Matrix3::rotationShear(), @ref Matrix4::rotationShear()
*/
/* The matrix is passed by value because it is changed inside */
template<std::size_t cols, std::size_t rows, class T> std::tuple<RectangularMatrix<cols, rows, T>, Vector<cols, T>, Matrix<cols, T>> svd(RectangularMatrix<cols, rows, T> m) {

29
src/Magnum/Math/Algorithms/Test/SvdTest.cpp

@ -25,6 +25,7 @@
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Math/Matrix4.h"
#include "Magnum/Math/Algorithms/Svd.h"
namespace Magnum { namespace Math { namespace Algorithms { namespace Test {
@ -33,6 +34,7 @@ struct SvdTest: Corrade::TestSuite::Tester {
explicit SvdTest();
template<class T> void test();
void decomposeRotationShear();
};
template<class T> using Matrix5x8 = RectangularMatrix<5, 8, T>;
@ -42,8 +44,9 @@ template<class T> using Vector8 = Vector<8, T>;
template<class T> using Vector5 = Vector<5, T>;
SvdTest::SvdTest() {
addTests<SvdTest>({&SvdTest::test<Float>,
&SvdTest::test<Double>});
addTests({&SvdTest::test<Float>,
&SvdTest::test<Double>,
&SvdTest::decomposeRotationShear});
}
template<class T> void SvdTest::test() {
@ -91,6 +94,28 @@ template<class T> void SvdTest::test() {
}
}
void SvdTest::decomposeRotationShear() {
typedef Math::Matrix4<Float> Matrix4;
typedef Math::Matrix3x3<Float> Matrix3x3;
typedef Math::Vector3<Float> Vector3;
using namespace Math::Literals;
Matrix4 a = Matrix4::scaling({1.5f, 2.0f, 1.0f})*Matrix4::rotationZ(35.0_degf);
Matrix3x3 u{NoInit};
Vector3 w{NoInit};
Matrix3x3 v{NoInit};
std::tie(u, w, v) = Algorithms::svd(a.rotationScaling());
CORRADE_COMPARE(u*Matrix3x3::fromDiagonal(w)*v.transposed(), a.rotationScaling());
/* U contains a flipped sign for Z, use it to remove the sign from the
transposed rotation matrix V */
CORRADE_COMPARE(w, (Vector3{1.5f, 2.0f, 1.0f}));
CORRADE_COMPARE(Matrix4::from(u*v.transposed(), {}), Matrix4::rotationZ(35.0_degf));
}
}}}}
CORRADE_TEST_MAIN(Magnum::Math::Algorithms::Test::SvdTest)

Loading…
Cancel
Save