blob: d564db404afadc4e349a580b28339d76b2681944 [file] [log] [blame]
Googler45874d82019-08-21 12:06:47 -07001// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
6//
7// This Source Code Form is subject to the terms of the Mozilla
8// Public License v. 2.0. If a copy of the MPL was not distributed
9// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10
11#include "main.h"
12#include <Eigen/LU>
13
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080014template <typename MatrixType>
15void inverse_for_fixed_size(const MatrixType&, std::enable_if_t<MatrixType::SizeAtCompileTime == Dynamic>* = 0) {}
Googler45874d82019-08-21 12:06:47 -070016
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080017template <typename MatrixType>
18void inverse_for_fixed_size(const MatrixType& m1, std::enable_if_t<MatrixType::SizeAtCompileTime != Dynamic>* = 0) {
Googler45874d82019-08-21 12:06:47 -070019 using std::abs;
20
21 MatrixType m2, identity = MatrixType::Identity();
22
23 typedef typename MatrixType::Scalar Scalar;
24 typedef typename NumTraits<Scalar>::Real RealScalar;
25 typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> VectorType;
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080026
27 // computeInverseAndDetWithCheck tests
28 // First: an invertible matrix
Googler45874d82019-08-21 12:06:47 -070029 bool invertible;
30 Scalar det;
31
32 m2.setZero();
33 m1.computeInverseAndDetWithCheck(m2, det, invertible);
34 VERIFY(invertible);
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080035 VERIFY_IS_APPROX(identity, m1 * m2);
Googler45874d82019-08-21 12:06:47 -070036 VERIFY_IS_APPROX(det, m1.determinant());
37
38 m2.setZero();
39 m1.computeInverseWithCheck(m2, invertible);
40 VERIFY(invertible);
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080041 VERIFY_IS_APPROX(identity, m1 * m2);
Googler45874d82019-08-21 12:06:47 -070042
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080043 // Second: a rank one matrix (not invertible, except for 1x1 matrices)
Googler45874d82019-08-21 12:06:47 -070044 VectorType v3 = VectorType::Random();
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080045 MatrixType m3 = v3 * v3.transpose(), m4;
Googler45874d82019-08-21 12:06:47 -070046 m3.computeInverseAndDetWithCheck(m4, det, invertible);
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080047 VERIFY(m1.rows() == 1 ? invertible : !invertible);
48 VERIFY_IS_MUCH_SMALLER_THAN(abs(det - m3.determinant()), RealScalar(1));
Googler45874d82019-08-21 12:06:47 -070049 m3.computeInverseWithCheck(m4, invertible);
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080050 VERIFY(m1.rows() == 1 ? invertible : !invertible);
51
Googler45874d82019-08-21 12:06:47 -070052 // check with submatrices
53 {
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080054 Matrix<Scalar, MatrixType::RowsAtCompileTime + 1, MatrixType::RowsAtCompileTime + 1, MatrixType::Options> m5;
Googler45874d82019-08-21 12:06:47 -070055 m5.setRandom();
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080056 m5.topLeftCorner(m1.rows(), m1.rows()) = m1;
57 m2 = m5.template topLeftCorner<MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime>().inverse();
58 VERIFY_IS_APPROX((m5.template topLeftCorner<MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime>()),
59 m2.inverse());
Googler45874d82019-08-21 12:06:47 -070060 }
61}
62
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080063template <typename MatrixType>
64void inverse(const MatrixType& m) {
Googler45874d82019-08-21 12:06:47 -070065 /* this test covers the following files:
66 Inverse.h
67 */
68 Index rows = m.rows();
69 Index cols = m.cols();
70
71 typedef typename MatrixType::Scalar Scalar;
72
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080073 MatrixType m1(rows, cols), m2(rows, cols), identity = MatrixType::Identity(rows, rows);
74 createRandomPIMatrixOfRank(rows, rows, rows, m1);
Googler45874d82019-08-21 12:06:47 -070075 m2 = m1.inverse();
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080076 VERIFY_IS_APPROX(m1, m2.inverse());
Googler45874d82019-08-21 12:06:47 -070077
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080078 VERIFY_IS_APPROX((Scalar(2) * m2).inverse(), m2.inverse() * Scalar(0.5));
Googler45874d82019-08-21 12:06:47 -070079
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080080 VERIFY_IS_APPROX(identity, m1.inverse() * m1);
81 VERIFY_IS_APPROX(identity, m1 * m1.inverse());
Googler45874d82019-08-21 12:06:47 -070082
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080083 VERIFY_IS_APPROX(m1, m1.inverse().inverse());
Googler45874d82019-08-21 12:06:47 -070084
85 // since for the general case we implement separately row-major and col-major, test that
86 VERIFY_IS_APPROX(MatrixType(m1.transpose().inverse()), MatrixType(m1.inverse().transpose()));
87
88 inverse_for_fixed_size(m1);
89
90 // check in-place inversion
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080091 if (MatrixType::RowsAtCompileTime >= 2 && MatrixType::RowsAtCompileTime <= 4) {
Googler45874d82019-08-21 12:06:47 -070092 // in-place is forbidden
93 VERIFY_RAISES_ASSERT(m1 = m1.inverse());
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080094 } else {
Googler45874d82019-08-21 12:06:47 -070095 m2 = m1.inverse();
96 m1 = m1.inverse();
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -080097 VERIFY_IS_APPROX(m1, m2);
Googler45874d82019-08-21 12:06:47 -070098 }
99}
100
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -0800101template <typename Scalar>
102void inverse_zerosized() {
103 Matrix<Scalar, Dynamic, Dynamic> A(0, 0);
Googler45874d82019-08-21 12:06:47 -0700104 {
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -0800105 Matrix<Scalar, 0, 1> b, x;
Googler45874d82019-08-21 12:06:47 -0700106 x = A.inverse() * b;
107 }
108 {
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -0800109 Matrix<Scalar, Dynamic, Dynamic> b(0, 1), x;
Googler45874d82019-08-21 12:06:47 -0700110 x = A.inverse() * b;
111 VERIFY_IS_EQUAL(x.rows(), 0);
112 VERIFY_IS_EQUAL(x.cols(), 1);
113 }
114}
115
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -0800116EIGEN_DECLARE_TEST(inverse) {
Googler45874d82019-08-21 12:06:47 -0700117 int s = 0;
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -0800118 for (int i = 0; i < g_repeat; i++) {
119 CALL_SUBTEST_1(inverse(Matrix<double, 1, 1>()));
120 CALL_SUBTEST_2(inverse(Matrix2d()));
121 CALL_SUBTEST_3(inverse(Matrix3f()));
122 CALL_SUBTEST_4(inverse(Matrix4f()));
123 CALL_SUBTEST_4(inverse(Matrix<float, 4, 4, DontAlign>()));
Googler45874d82019-08-21 12:06:47 -0700124
Rasmus Munk Larsen2434cfd2023-12-06 12:02:41 -0800125 s = internal::random<int>(50, 320);
126 CALL_SUBTEST_5(inverse(MatrixXf(s, s)));
127 TEST_SET_BUT_UNUSED_VARIABLE(s)
128 CALL_SUBTEST_5(inverse_zerosized<float>());
129 CALL_SUBTEST_5(inverse(MatrixXf(0, 0)));
130 CALL_SUBTEST_5(inverse(MatrixXf(1, 1)));
131
132 s = internal::random<int>(25, 100);
133 CALL_SUBTEST_6(inverse(MatrixXcd(s, s)));
134 TEST_SET_BUT_UNUSED_VARIABLE(s)
135
136 CALL_SUBTEST_7(inverse(Matrix4d()));
137 CALL_SUBTEST_7(inverse(Matrix<double, 4, 4, DontAlign>()));
138
139 CALL_SUBTEST_8(inverse(Matrix4cd()));
Googler45874d82019-08-21 12:06:47 -0700140 }
141}