Skip to content

Commit bc3a33e

Browse files
committed
Explicit return types, improved testing
1 parent 2004134 commit bc3a33e

3 files changed

Lines changed: 47 additions & 21 deletions

File tree

stan/math/prim/fun/eigenvalues.hpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ namespace math {
1717
*/
1818
template <typename EigMat, require_eigen_matrix_dynamic_t<EigMat>* = nullptr,
1919
require_not_vt_complex<EigMat>* = nullptr>
20-
inline auto eigenvalues(const EigMat& m) {
20+
inline Eigen::Matrix<complex_return_t<value_type_t<EigMat>>, 1, -1> eigenvalues(
21+
const EigMat& m) {
2122
using PlainMat = plain_type_t<EigMat>;
2223
const PlainMat& m_eval = m;
2324
check_nonzero_size("eigenvalues", "m", m_eval);
@@ -30,15 +31,17 @@ inline auto eigenvalues(const EigMat& m) {
3031
/**
3132
* Return the eigenvalues of a (complex-valued) matrix
3233
*
33-
* @tparam EigMat type of complex matrix argument
34+
* @tparam EigCplxMat type of complex matrix argument
3435
* @param[in] m matrix to find the eigenvectors of. Must be square and have a
3536
* non-zero size.
3637
* @return a complex-valued column vector with entries the eigenvectors of `m`
3738
*/
38-
template <typename EigMat, require_eigen_matrix_dynamic_t<EigMat>* = nullptr,
39-
require_vt_complex<EigMat>* = nullptr>
40-
inline auto eigenvalues(const EigMat& m) {
41-
using PlainMat = Eigen::Matrix<scalar_type_t<EigMat>, -1, -1>;
39+
template <typename EigCplxMat,
40+
require_eigen_matrix_dynamic_t<EigCplxMat>* = nullptr,
41+
require_vt_complex<EigCplxMat>* = nullptr>
42+
inline Eigen::Matrix<complex_return_t<value_type_t<EigCplxMat>>, 1, -1>
43+
eigenvalues(const EigCplxMat& m) {
44+
using PlainMat = Eigen::Matrix<scalar_type_t<EigCplxMat>, -1, -1>;
4245
const PlainMat& m_eval = m;
4346
check_nonzero_size("eigenvalues", "m", m_eval);
4447
check_square("eigenvalues", "m", m_eval);

stan/math/prim/fun/eigenvectors.hpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ namespace math {
1818
*/
1919
template <typename EigMat, require_eigen_matrix_dynamic_t<EigMat>* = nullptr,
2020
require_not_vt_complex<EigMat>* = nullptr>
21-
inline auto eigenvectors(const EigMat& m) {
21+
inline Eigen::Matrix<complex_return_t<value_type_t<EigMat>>, -1, -1>
22+
eigenvectors(const EigMat& m) {
2223
using PlainMat = plain_type_t<EigMat>;
2324
const PlainMat& m_eval = m;
2425
check_nonzero_size("eigenvectors", "m", m_eval);
@@ -31,16 +32,18 @@ inline auto eigenvectors(const EigMat& m) {
3132
/**
3233
* Return the eigenvectors of a (complex-valued) matrix
3334
*
34-
* @tparam EigMat type of complex matrix argument
35+
* @tparam EigCplxMat type of complex matrix argument
3536
* @param[in] m matrix to find the eigenvectors of. Must be square and have a
3637
* non-zero size.
3738
* @return a complex-valued matrix with columns representing the eigenvectors of
3839
* `m`
3940
*/
40-
template <typename EigMat, require_eigen_matrix_dynamic_t<EigMat>* = nullptr,
41-
require_vt_complex<EigMat>* = nullptr>
42-
inline auto eigenvectors(const EigMat& m) {
43-
using PlainMat = Eigen::Matrix<scalar_type_t<EigMat>, -1, -1>;
41+
template <typename EigCplxMat,
42+
require_eigen_matrix_dynamic_t<EigCplxMat>* = nullptr,
43+
require_vt_complex<EigCplxMat>* = nullptr>
44+
inline Eigen::Matrix<complex_return_t<value_type_t<EigCplxMat>>, -1, -1>
45+
eigenvectors(const EigCplxMat& m) {
46+
using PlainMat = Eigen::Matrix<scalar_type_t<EigCplxMat>, -1, -1>;
4447
const PlainMat& m_eval = m;
4548
check_nonzero_size("eigenvectors", "m", m_eval);
4649
check_square("eigenvectors", "m", m_eval);

test/unit/math/mix/fun/eigenvectors_test.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,17 @@ TEST(mathMixFun, eigenvectorsComplex) {
3131

3232
template <typename T>
3333
void expect_identity_matrix(const T& x) {
34-
EXPECT_EQUAL(x.rows(), x.cols());
34+
EXPECT_EQ(x.rows(), x.cols());
3535
for (int j = 0; j < x.cols(); ++j) {
3636
for (int i = 0; i < x.rows(); ++i) {
37-
EXPECT_NEAR(i == j ? 1 : 0, x(i, j), 1e-6);
37+
EXPECT_NEAR(i == j ? 1 : 0, stan::math::value_of_rec(x(i, j)), 1e-6);
3838
}
3939
}
4040
}
4141

4242
template <typename T>
4343
void expectEigenvectorsId() {
44-
for (const auto& m_d : stan::test::square_test_matrices(0, 2)) {
44+
for (const auto& m_d : stan::test::square_test_matrices(1, 2)) {
4545
Eigen::Matrix<T, -1, -1> m(m_d);
4646
auto vecs = eigenvectors(m).eval();
4747
auto vals = eigenvalues(m).eval();
@@ -50,7 +50,21 @@ void expectEigenvectorsId() {
5050
}
5151
}
5252

53-
// THESE TESTS USED TO WORK STANDALONE
53+
template <typename T>
54+
void expectComplexEigenvectorsId() {
55+
Eigen::Matrix<std::complex<T>, -1, -1> c22(2, 2);
56+
c22 << stan::math::to_complex(T(0), T(-1)),
57+
stan::math::to_complex(T(0), T(0)), stan::math::to_complex(T(2), T(0)),
58+
stan::math::to_complex(T(4), T(0));
59+
auto eigenvalues = stan::math::eigenvalues(c22);
60+
auto eigenvectors = stan::math::eigenvectors(c22);
61+
62+
auto I = (eigenvectors.inverse() * c22 * eigenvectors
63+
* eigenvalues.asDiagonal().inverse())
64+
.real();
65+
66+
expect_identity_matrix(I);
67+
}
5468

5569
TEST(mathMixFun, eigenvectorsId) {
5670
using d_t = double;
@@ -60,9 +74,15 @@ TEST(mathMixFun, eigenvectorsId) {
6074
using fv_t = stan::math::fvar<stan::math::var>;
6175
using ffv_t = stan::math::fvar<fv_t>;
6276

63-
// expectEigenvectorsId<v_t>();
64-
// expectEigenvectorsId<fd_t>();
65-
// expectEigenvectorsId<ffd_t>();
66-
// expectEigenvectorsId<fv_t>();
67-
// expectEigenvectorsId<ffv_t>();
77+
expectEigenvectorsId<v_t>();
78+
expectEigenvectorsId<fd_t>();
79+
expectEigenvectorsId<ffd_t>();
80+
expectEigenvectorsId<fv_t>();
81+
expectEigenvectorsId<ffv_t>();
82+
83+
expectComplexEigenvectorsId<v_t>();
84+
expectComplexEigenvectorsId<fd_t>();
85+
expectComplexEigenvectorsId<ffd_t>();
86+
expectComplexEigenvectorsId<fv_t>();
87+
expectComplexEigenvectorsId<ffv_t>();
6888
}

0 commit comments

Comments
 (0)