blob: cb4c073e941895b9e72f6d39cdb8ae70f707598e [file] [log] [blame]
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +00001// This file is part of Eigen, a lightweight C++ template library
Benoit Jacob6347b1d2009-05-22 20:25:33 +02002// for linear algebra.
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +00003//
Gael Guennebaud28e64b02010-06-24 23:21:58 +02004// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
Benoit Jacob00f89a82008-11-24 13:40:43 +00005// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +00006//
Benoit Jacob69124cf2012-07-13 14:42:47 -04007// 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/.
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000010
Benoit Jacob1d52bd42009-01-08 15:20:21 +000011// discard stack allocation as that too bypasses malloc
Benoit Jacobd6712052008-12-31 00:25:31 +000012#define EIGEN_STACK_ALLOCATION_LIMIT 0
Christoph Hertzberg6af6cf02015-02-21 19:43:56 +010013// heap allocation will raise an assert if enabled at runtime
Christoph Hertzberg12d59462014-09-30 14:57:54 +020014#define EIGEN_RUNTIME_NO_MALLOC
Benoit Jacobd6712052008-12-31 00:25:31 +000015
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000016#include "main.h"
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +010017#include <Eigen/Cholesky>
18#include <Eigen/Eigenvalues>
19#include <Eigen/LU>
20#include <Eigen/QR>
21#include <Eigen/SVD>
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000022
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000023template<typename MatrixType> void nomalloc(const MatrixType& m)
24{
25 /* this test check no dynamic memory allocation are issued with fixed-size matrices
26 */
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000027 typedef typename MatrixType::Scalar Scalar;
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000028
Hauke Heibelf1679c72010-06-20 17:37:56 +020029 Index rows = m.rows();
30 Index cols = m.cols();
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000031
Gael Guennebaudc10f0692008-07-21 00:34:46 +000032 MatrixType m1 = MatrixType::Random(rows, cols),
33 m2 = MatrixType::Random(rows, cols),
Benoit Jacob0609dbe2011-10-31 00:51:36 -040034 m3(rows, cols);
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000035
Benoit Jacob47160402010-10-25 10:15:22 -040036 Scalar s1 = internal::random<Scalar>();
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000037
Benoit Jacob47160402010-10-25 10:15:22 -040038 Index r = internal::random<Index>(0, rows-1),
39 c = internal::random<Index>(0, cols-1);
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000040
41 VERIFY_IS_APPROX((m1+m2)*s1, s1*m1+s1*m2);
42 VERIFY_IS_APPROX((m1+m2)(r,c), (m1(r,c))+(m2(r,c)));
Gael Guennebaud71a171c2010-01-04 19:13:08 +010043 VERIFY_IS_APPROX(m1.cwiseProduct(m1.block(0,0,rows,cols)), (m1.array()*m1.array()).matrix());
Gael Guennebaud3d8e1792011-01-27 18:02:49 +010044 VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2));
Gael Guennebaudc60818f2011-02-01 11:38:46 +010045
Gael Guennebaudf46ace62011-01-31 21:30:27 +010046 m2.col(0).noalias() = m1 * m1.col(0);
47 m2.col(0).noalias() -= m1.adjoint() * m1.col(0);
48 m2.col(0).noalias() -= m1 * m1.row(0).adjoint();
49 m2.col(0).noalias() -= m1.adjoint() * m1.row(0).adjoint();
50
51 m2.row(0).noalias() = m1.row(0) * m1;
52 m2.row(0).noalias() -= m1.row(0) * m1.adjoint();
53 m2.row(0).noalias() -= m1.col(0).adjoint() * m1;
54 m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint();
Gael Guennebaudc60818f2011-02-01 11:38:46 +010055 VERIFY_IS_APPROX(m2,m2);
56
57 m2.col(0).noalias() = m1.template triangularView<Upper>() * m1.col(0);
58 m2.col(0).noalias() -= m1.adjoint().template triangularView<Upper>() * m1.col(0);
59 m2.col(0).noalias() -= m1.template triangularView<Upper>() * m1.row(0).adjoint();
60 m2.col(0).noalias() -= m1.adjoint().template triangularView<Upper>() * m1.row(0).adjoint();
61
62 m2.row(0).noalias() = m1.row(0) * m1.template triangularView<Upper>();
63 m2.row(0).noalias() -= m1.row(0) * m1.adjoint().template triangularView<Upper>();
64 m2.row(0).noalias() -= m1.col(0).adjoint() * m1.template triangularView<Upper>();
65 m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint().template triangularView<Upper>();
66 VERIFY_IS_APPROX(m2,m2);
67
68 m2.col(0).noalias() = m1.template selfadjointView<Upper>() * m1.col(0);
69 m2.col(0).noalias() -= m1.adjoint().template selfadjointView<Upper>() * m1.col(0);
70 m2.col(0).noalias() -= m1.template selfadjointView<Upper>() * m1.row(0).adjoint();
71 m2.col(0).noalias() -= m1.adjoint().template selfadjointView<Upper>() * m1.row(0).adjoint();
72
73 m2.row(0).noalias() = m1.row(0) * m1.template selfadjointView<Upper>();
74 m2.row(0).noalias() -= m1.row(0) * m1.adjoint().template selfadjointView<Upper>();
75 m2.row(0).noalias() -= m1.col(0).adjoint() * m1.template selfadjointView<Upper>();
76 m2.row(0).noalias() -= m1.col(0).adjoint() * m1.adjoint().template selfadjointView<Upper>();
77 VERIFY_IS_APPROX(m2,m2);
Gael Guennebaud59af20b2011-02-01 16:46:35 +010078
79 m2.template selfadjointView<Lower>().rankUpdate(m1.col(0),-1);
Gael Guennebaud6da5d872016-01-27 17:26:48 +010080 m2.template selfadjointView<Upper>().rankUpdate(m1.row(0),-1);
81 m2.template selfadjointView<Lower>().rankUpdate(m1.col(0), m1.col(0)); // rank-2
Gael Guennebaudc60818f2011-02-01 11:38:46 +010082
83 // The following fancy matrix-matrix products are not safe yet regarding static allocation
Gael Guennebaude58827d2016-01-25 17:16:33 +010084 m2.template selfadjointView<Lower>().rankUpdate(m1);
85 m2 += m2.template triangularView<Upper>() * m1;
86 m2.template triangularView<Upper>() = m2 * m2;
Gael Guennebaud8328caa2016-01-25 22:06:42 +010087 m1 += m1.template selfadjointView<Lower>() * m2;
Gael Guennebaude58827d2016-01-25 17:16:33 +010088 VERIFY_IS_APPROX(m2,m2);
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +000089}
90
Gael Guennebaud8a380472010-07-04 15:35:21 +020091template<typename Scalar>
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +010092void ctms_decompositions()
93{
94 const int maxSize = 16;
95 const int size = 12;
96
Gael Guennebaud8a380472010-07-04 15:35:21 +020097 typedef Eigen::Matrix<Scalar,
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +010098 Eigen::Dynamic, Eigen::Dynamic,
Benoit Jacobb81351c2010-03-08 21:30:06 -050099 0,
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100100 maxSize, maxSize> Matrix;
101
Gael Guennebaud8a380472010-07-04 15:35:21 +0200102 typedef Eigen::Matrix<Scalar,
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100103 Eigen::Dynamic, 1,
Benoit Jacobb81351c2010-03-08 21:30:06 -0500104 0,
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100105 maxSize, 1> Vector;
106
Gael Guennebaud8a380472010-07-04 15:35:21 +0200107 typedef Eigen::Matrix<std::complex<Scalar>,
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100108 Eigen::Dynamic, Eigen::Dynamic,
Benoit Jacobb81351c2010-03-08 21:30:06 -0500109 0,
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100110 maxSize, maxSize> ComplexMatrix;
111
Gael Guennebaud88e05102012-06-12 13:12:47 +0200112 const Matrix A(Matrix::Random(size, size)), B(Matrix::Random(size, size));
113 Matrix X(size,size);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100114 const ComplexMatrix complexA(ComplexMatrix::Random(size, size));
Gael Guennebaud56686742010-06-24 21:44:24 +0200115 const Matrix saA = A.adjoint() * A;
Gael Guennebaud88e05102012-06-12 13:12:47 +0200116 const Vector b(Vector::Random(size));
117 Vector x(size);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100118
119 // Cholesky module
120 Eigen::LLT<Matrix> LLT; LLT.compute(A);
Gael Guennebaud88e05102012-06-12 13:12:47 +0200121 X = LLT.solve(B);
122 x = LLT.solve(b);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100123 Eigen::LDLT<Matrix> LDLT; LDLT.compute(A);
Gael Guennebaud88e05102012-06-12 13:12:47 +0200124 X = LDLT.solve(B);
125 x = LDLT.solve(b);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100126
127 // Eigenvalues module
128 Eigen::HessenbergDecomposition<ComplexMatrix> hessDecomp; hessDecomp.compute(complexA);
129 Eigen::ComplexSchur<ComplexMatrix> cSchur(size); cSchur.compute(complexA);
Gael Guennebaud3d8e1792011-01-27 18:02:49 +0100130 Eigen::ComplexEigenSolver<ComplexMatrix> cEigSolver; cEigSolver.compute(complexA);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100131 Eigen::EigenSolver<Matrix> eigSolver; eigSolver.compute(A);
132 Eigen::SelfAdjointEigenSolver<Matrix> saEigSolver(size); saEigSolver.compute(saA);
133 Eigen::Tridiagonalization<Matrix> tridiag; tridiag.compute(saA);
134
135 // LU module
136 Eigen::PartialPivLU<Matrix> ppLU; ppLU.compute(A);
Gael Guennebaud88e05102012-06-12 13:12:47 +0200137 X = ppLU.solve(B);
138 x = ppLU.solve(b);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100139 Eigen::FullPivLU<Matrix> fpLU; fpLU.compute(A);
Gael Guennebaud88e05102012-06-12 13:12:47 +0200140 X = fpLU.solve(B);
141 x = fpLU.solve(b);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100142
143 // QR module
144 Eigen::HouseholderQR<Matrix> hQR; hQR.compute(A);
Gael Guennebaud88e05102012-06-12 13:12:47 +0200145 X = hQR.solve(B);
146 x = hQR.solve(b);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100147 Eigen::ColPivHouseholderQR<Matrix> cpQR; cpQR.compute(A);
Gael Guennebaud57b58042012-06-26 17:45:01 +0200148 X = cpQR.solve(B);
Gael Guennebaud88e05102012-06-12 13:12:47 +0200149 x = cpQR.solve(b);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100150 Eigen::FullPivHouseholderQR<Matrix> fpQR; fpQR.compute(A);
Gael Guennebaud882912b2012-06-20 08:58:26 +0200151 // FIXME X = fpQR.solve(B);
Gael Guennebaud88e05102012-06-12 13:12:47 +0200152 x = fpQR.solve(b);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100153
154 // SVD module
Rasmus Munk Larsen085c2fc2021-11-30 18:45:54 +0000155 Eigen::JacobiSVD<Matrix> jSVD; jSVD.compute(A, ComputeFullU | ComputeFullV);
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100156}
157
Christoph Hertzberg4ba8aa12014-09-25 16:05:17 +0200158void test_zerosized() {
159 // default constructors:
160 Eigen::MatrixXd A;
161 Eigen::VectorXd v;
162 // explicit zero-sized:
163 Eigen::ArrayXXd A0(0,0);
164 Eigen::ArrayXd v0(0);
165
166 // assigning empty objects to each other:
167 A=A0;
168 v=v0;
169}
170
171template<typename MatrixType> void test_reference(const MatrixType& m) {
172 typedef typename MatrixType::Scalar Scalar;
173 enum { Flag = MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor};
174 enum { TransposeFlag = !MatrixType::IsRowMajor ? Eigen::RowMajor : Eigen::ColMajor};
Gael Guennebaud12e1ebb2018-07-12 17:16:40 +0200175 Index rows = m.rows(), cols=m.cols();
Christoph Hertzberg12d59462014-09-30 14:57:54 +0200176 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, Flag > MatrixX;
177 typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic, TransposeFlag> MatrixXT;
Christoph Hertzberg4ba8aa12014-09-25 16:05:17 +0200178 // Dynamic reference:
Christoph Hertzberg12d59462014-09-30 14:57:54 +0200179 typedef Eigen::Ref<const MatrixX > Ref;
180 typedef Eigen::Ref<const MatrixXT > RefT;
Christoph Hertzberg4ba8aa12014-09-25 16:05:17 +0200181
182 Ref r1(m);
183 Ref r2(m.block(rows/3, cols/4, rows/2, cols/2));
184 RefT r3(m.transpose());
185 RefT r4(m.topLeftCorner(rows/2, cols/2).transpose());
186
187 VERIFY_RAISES_ASSERT(RefT r5(m));
188 VERIFY_RAISES_ASSERT(Ref r6(m.transpose()));
189 VERIFY_RAISES_ASSERT(Ref r7(Scalar(2) * m));
Christoph Hertzberg12d59462014-09-30 14:57:54 +0200190
191 // Copy constructors shall also never malloc
192 Ref r8 = r1;
193 RefT r9 = r3;
194
195 // Initializing from a compatible Ref shall also never malloc
196 Eigen::Ref<const MatrixX, Unaligned, Stride<Dynamic, Dynamic> > r10=r8, r11=m;
197
198 // Initializing from an incompatible Ref will malloc:
199 typedef Eigen::Ref<const MatrixX, Aligned> RefAligned;
200 VERIFY_RAISES_ASSERT(RefAligned r12=r10);
201 VERIFY_RAISES_ASSERT(Ref r13=r10); // r10 has more dynamic strides
202
Christoph Hertzberg4ba8aa12014-09-25 16:05:17 +0200203}
204
Gael Guennebaud82f0ce22018-07-17 14:46:15 +0200205EIGEN_DECLARE_TEST(nomalloc)
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +0000206{
Christoph Hertzberg12d59462014-09-30 14:57:54 +0200207 // create some dynamic objects
208 Eigen::MatrixXd M1 = MatrixXd::Random(3,3);
209 Ref<const MatrixXd> R1 = 2.0*M1; // Ref requires temporary
210
211 // from here on prohibit malloc:
212 Eigen::internal::set_is_malloc_allowed(false);
213
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +0000214 // check that our operator new is indeed called:
Benoit Jacobaaaade42010-05-30 16:00:58 -0400215 VERIFY_RAISES_ASSERT(MatrixXd dummy(MatrixXd::Random(3,3)));
Benoit Jacobb81351c2010-03-08 21:30:06 -0500216 CALL_SUBTEST_1(nomalloc(Matrix<float, 1, 1>()) );
217 CALL_SUBTEST_2(nomalloc(Matrix4d()) );
218 CALL_SUBTEST_3(nomalloc(Matrix<float,32,32>()) );
Adolfo Rodriguez Tsouroukdissian5a36f4a2010-03-08 19:31:27 +0100219
220 // Check decomposition modules with dynamic matrices that have a known compile-time max size (ctms)
Gael Guennebaud8a380472010-07-04 15:35:21 +0200221 CALL_SUBTEST_4(ctms_decompositions<float>());
Christoph Hertzberg12d59462014-09-30 14:57:54 +0200222
Christoph Hertzberg4ba8aa12014-09-25 16:05:17 +0200223 CALL_SUBTEST_5(test_zerosized());
Christoph Hertzberg12d59462014-09-30 14:57:54 +0200224
Christoph Hertzberg4ba8aa12014-09-25 16:05:17 +0200225 CALL_SUBTEST_6(test_reference(Matrix<float,32,32>()));
Christoph Hertzberg12d59462014-09-30 14:57:54 +0200226 CALL_SUBTEST_7(test_reference(R1));
227 CALL_SUBTEST_8(Ref<MatrixXd> R2 = M1.topRows<2>(); test_reference(R2));
Gael Guennebaudf2ebbee2008-06-02 14:54:52 +0000228}