Skip to content

Commit d16d664

Browse files
committed
decompositions: Tridiagonalization: Completed tests
1 parent fb331f2 commit d16d664

File tree

3 files changed

+102
-5
lines changed

3 files changed

+102
-5
lines changed

include/nanoeigenpy/decompositions/hessenberg-decomposition.hpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ void exposeHessenbergDecomposition(nb::module_ m, const char *name) {
4040
"Returns the internal representation of the decomposition.",
4141
nb::rv_policy::reference_internal)
4242

43-
// TODO: Expose so that the return type are convertible to np arrays
44-
// matrixQ
4543
.def(
4644
"matrixQ", [](const Solver &c) -> MatrixType { return c.matrixQ(); },
4745
"Reconstructs the orthogonal matrix Q in the decomposition.")

include/nanoeigenpy/decompositions/tridiagonalization.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,13 @@ void exposeTridiagonalization(nb::module_ m, const char *name) {
3939
"Returns the internal representation of the decomposition.",
4040
nb::rv_policy::reference_internal)
4141

42-
// TODO: Expose so that the return type are convertible to np arrays
43-
// matrixQ()
44-
// matrixT()
42+
.def(
43+
"matrixQ", [](const Solver &c) -> MatrixType { return c.matrixQ(); },
44+
"Returns the unitary matrix Q in the decomposition.")
45+
.def(
46+
"matrixT", [](Solver &c) -> MatrixType { return c.matrixT(); },
47+
"Returns an expression of the tridiagonal matrix T in the "
48+
"decomposition.")
4549

4650
.def("diagonal", &Solver::diagonal,
4751
"Returns the diagonal of the tridiagonal matrix T in the "

tests/test_tridiagonalization.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,100 @@
44
dim = 100
55
rng = np.random.default_rng()
66
A = rng.random((dim, dim))
7+
A = (A + A.T) * 0.5
78

89
tri = nanoeigenpy.Tridiagonalization(A)
10+
11+
Q = tri.matrixQ()
12+
T = tri.matrixT()
13+
14+
assert nanoeigenpy.is_approx(A, Q @ T @ Q.T, 1e-10)
15+
assert nanoeigenpy.is_approx(Q @ Q.T, np.eye(dim), 1e-10)
16+
17+
for i in range(dim):
18+
for j in range(dim):
19+
if abs(i - j) > 1:
20+
assert abs(T[i, j]) < 1e-12
21+
22+
assert nanoeigenpy.is_approx(T, T.T, 1e-12)
23+
24+
diag = tri.diagonal()
25+
sub_diag = tri.subDiagonal()
26+
27+
for i in range(dim):
28+
assert abs(diag[i] - T[i, i]) < 1e-12
29+
30+
for i in range(dim - 1):
31+
assert abs(sub_diag[i] - T[i + 1, i]) < 1e-12
32+
33+
A_test = rng.random((dim, dim))
34+
A_test = (A_test + A_test.T) * 0.5
35+
36+
tri1 = nanoeigenpy.Tridiagonalization(dim)
37+
tri1.compute(A_test)
38+
tri2 = nanoeigenpy.Tridiagonalization(A_test)
39+
40+
Q1 = tri1.matrixQ()
41+
T1 = tri1.matrixT()
42+
Q2 = tri2.matrixQ()
43+
T2 = tri2.matrixT()
44+
45+
assert nanoeigenpy.is_approx(Q1, Q2, 1e-12)
46+
assert nanoeigenpy.is_approx(T1, T2, 1e-12)
47+
48+
h_coeffs = tri.householderCoefficients()
49+
packed = tri.packedMatrix()
50+
51+
assert h_coeffs.shape == (dim - 1,)
52+
assert packed.shape == (dim, dim)
53+
54+
for i in range(dim):
55+
for j in range(i + 1, dim):
56+
assert abs(packed[i, j] - A[i, j]) < 1e-12
57+
58+
for i in range(dim):
59+
assert abs(packed[i, i] - T[i, i]) < 1e-12
60+
if i < dim - 1:
61+
assert abs(packed[i + 1, i] - T[i + 1, i]) < 1e-12
62+
63+
A_diag = np.diag(rng.random(dim))
64+
tri_diag = nanoeigenpy.Tridiagonalization(A_diag)
65+
Q_diag = tri_diag.matrixQ()
66+
T_diag = tri_diag.matrixT()
67+
68+
assert nanoeigenpy.is_approx(A_diag, Q_diag @ T_diag @ Q_diag.T, 1e-10)
69+
for i in range(dim):
70+
for j in range(dim):
71+
if i != j:
72+
assert abs(T_diag[i, j]) < 1e-10
73+
74+
A_tridiag = np.zeros((dim, dim))
75+
for i in range(dim):
76+
A_tridiag[i, i] = rng.random()
77+
if i < dim - 1:
78+
val = rng.random()
79+
A_tridiag[i, i + 1] = val
80+
A_tridiag[i + 1, i] = val
81+
82+
tri_tridiag = nanoeigenpy.Tridiagonalization(A_tridiag)
83+
Q_tridiag = tri_tridiag.matrixQ()
84+
T_tridiag = tri_tridiag.matrixT()
85+
86+
assert nanoeigenpy.is_approx(A_tridiag, Q_tridiag @ T_tridiag @ Q_tridiag.T, 1e-10)
87+
88+
89+
tri1_id = nanoeigenpy.Tridiagonalization(dim)
90+
tri2_id = nanoeigenpy.Tridiagonalization(dim)
91+
id1 = tri1_id.id()
92+
id2 = tri2_id.id()
93+
assert id1 != id2
94+
assert id1 == tri1_id.id()
95+
assert id2 == tri2_id.id()
96+
97+
tri3_id = nanoeigenpy.Tridiagonalization(A)
98+
tri4_id = nanoeigenpy.Tridiagonalization(A)
99+
id3 = tri3_id.id()
100+
id4 = tri4_id.id()
101+
assert id3 != id4
102+
assert id3 == tri3_id.id()
103+
assert id4 == tri4_id.id()

0 commit comments

Comments
 (0)