22import numpy as np
33import pytest
44
5- full_u = nanoeigenpy .DecompositionOptions .ComputeFullU .value
6- full_v = nanoeigenpy .DecompositionOptions .ComputeFullV .value
7- thin_u = nanoeigenpy .DecompositionOptions .ComputeThinU .value
8- thin_v = nanoeigenpy .DecompositionOptions .ComputeThinV .value
9-
105_options = [
116 0 ,
12- thin_u ,
13- thin_v ,
14- full_u ,
15- full_v ,
16- thin_u | thin_v ,
17- full_u | full_v ,
18- thin_u | full_v ,
19- full_u | thin_v ,
7+ nanoeigenpy .DecompositionOptions .ComputeThinU .value ,
8+ nanoeigenpy .DecompositionOptions .ComputeThinV .value ,
9+ nanoeigenpy .DecompositionOptions .ComputeFullU .value ,
10+ nanoeigenpy .DecompositionOptions .ComputeFullV .value ,
11+ nanoeigenpy .DecompositionOptions .ComputeThinU .value
12+ | nanoeigenpy .DecompositionOptions .ComputeThinV .value ,
13+ nanoeigenpy .DecompositionOptions .ComputeFullU .value
14+ | nanoeigenpy .DecompositionOptions .ComputeFullV .value ,
15+ nanoeigenpy .DecompositionOptions .ComputeThinU .value
16+ | nanoeigenpy .DecompositionOptions .ComputeFullV .value ,
17+ nanoeigenpy .DecompositionOptions .ComputeFullU .value
18+ | nanoeigenpy .DecompositionOptions .ComputeThinV .value ,
2019]
2120
2221_classes = [
@@ -35,94 +34,119 @@ def test_jacobi(cls, options):
3534 A = rng .random ((dim , dim ))
3635 A = (A + A .T ) * 0.5 + np .diag (10.0 + rng .random (dim ))
3736
38- skip_case = (
39- cls == nanoeigenpy .FullPivHhJacobiSVD
40- and options != 0
41- and not (options & (full_u | full_v ))
37+ if cls == nanoeigenpy .FullPivHhJacobiSVD :
38+ if options != 0 and not (
39+ options
40+ & (
41+ nanoeigenpy .DecompositionOptions .ComputeFullU .value
42+ | nanoeigenpy .DecompositionOptions .ComputeFullV .value
43+ )
44+ ):
45+ return
46+
47+ jacobisvd = cls (A , options )
48+ assert jacobisvd .info () == nanoeigenpy .ComputationInfo .Success
49+
50+ if options & (
51+ nanoeigenpy .DecompositionOptions .ComputeThinU .value
52+ | nanoeigenpy .DecompositionOptions .ComputeFullU .value
53+ ) and options & (
54+ nanoeigenpy .DecompositionOptions .ComputeThinV .value
55+ | nanoeigenpy .DecompositionOptions .ComputeFullV .value
56+ ):
57+ X = rng .random ((dim , 20 ))
58+ B = A @ X
59+ X_est = jacobisvd .solve (B )
60+ assert nanoeigenpy .is_approx (X , X_est )
61+ assert nanoeigenpy .is_approx (A @ X_est , B )
62+
63+ x = rng .random (dim )
64+ b = A @ x
65+ x_est = jacobisvd .solve (b )
66+ assert nanoeigenpy .is_approx (x , x_est )
67+ assert nanoeigenpy .is_approx (A @ x_est , b )
68+
69+ rows = jacobisvd .rows ()
70+ cols = jacobisvd .cols ()
71+ assert cols == dim
72+ assert rows == dim
73+
74+ _jacobisvd_compute = jacobisvd .compute (A )
75+ _jacobisvd_compute_options = jacobisvd .compute (A , options )
76+
77+ rank = jacobisvd .rank ()
78+ singularvalues = jacobisvd .singularValues ()
79+ nonzerosingularvalues = jacobisvd .nonzeroSingularValues ()
80+ assert rank == nonzerosingularvalues
81+ assert len (singularvalues ) == dim
82+ assert all (
83+ singularvalues [i ] >= singularvalues [i + 1 ]
84+ for i in range (len (singularvalues ) - 1 )
4285 )
4386
44- if not skip_case :
45- jacobisvd = cls (A , options )
46- assert jacobisvd .info () == nanoeigenpy .ComputationInfo .Success
47-
48- if options & (thin_u | full_u ) and options & (thin_v | full_v ):
49- X = rng .random ((dim , 20 ))
50- B = A @ X
51- X_est = jacobisvd .solve (B )
52- assert nanoeigenpy .is_approx (X , X_est )
53- assert nanoeigenpy .is_approx (A @ X_est , B )
54-
55- x = rng .random (dim )
56- b = A @ x
57- x_est = jacobisvd .solve (b )
58- assert nanoeigenpy .is_approx (x , x_est )
59- assert nanoeigenpy .is_approx (A @ x_est , b )
60-
61- rows = jacobisvd .rows ()
62- cols = jacobisvd .cols ()
63- assert cols == dim
64- assert rows == dim
65-
66- _jacobisvd_compute = jacobisvd .compute (A )
67- _jacobisvd_compute_options = jacobisvd .compute (A , options )
68-
69- rank = jacobisvd .rank ()
70- singularvalues = jacobisvd .singularValues ()
71- nonzerosingularvalues = jacobisvd .nonzeroSingularValues ()
72- assert rank == nonzerosingularvalues
73- assert len (singularvalues ) == dim
74-
75- compute_u = jacobisvd .computeU ()
76- compute_v = jacobisvd .computeV ()
77- expected_compute_u = bool (options & (thin_u | full_u ))
78- expected_compute_v = bool (options & (thin_v | full_v ))
79- assert compute_u == expected_compute_u
80- assert compute_v == expected_compute_v
81-
82- if compute_u :
83- matrixU = jacobisvd .matrixU ()
84- if options & full_u :
85- assert matrixU .shape == (dim , dim )
86- elif options & thin_u :
87- assert matrixU .shape == (dim , dim )
88- assert nanoeigenpy .is_approx (matrixU .T @ matrixU , np .eye (matrixU .shape [1 ]))
89-
90- if compute_v :
91- matrixV = jacobisvd .matrixV ()
92- if options & full_v :
93- assert matrixV .shape == (dim , dim )
94- elif options & thin_v :
95- assert matrixV .shape == (dim , dim )
96- assert nanoeigenpy .is_approx (matrixV .T @ matrixV , np .eye (matrixV .shape [1 ]))
97-
98- if compute_u and compute_v :
99- U = jacobisvd .matrixU ()
100- V = jacobisvd .matrixV ()
101- S = jacobisvd .singularValues ()
102- S_matrix = np .diag (S )
103- A_reconstructed = U @ S_matrix @ V .T
104- assert nanoeigenpy .is_approx (A , A_reconstructed )
105-
106- jacobisvd .setThreshold ()
107- _default_threshold = jacobisvd .threshold ()
108- jacobisvd .setThreshold (1e-8 )
109- assert jacobisvd .threshold () == 1e-8
110-
111- decomp1 = cls ()
112- decomp2 = cls ()
113- id1 = decomp1 .id ()
114- id2 = decomp2 .id ()
115- assert id1 != id2
116- assert id1 == decomp1 .id ()
117- assert id2 == decomp2 .id ()
118-
119- decomp3 = cls (dim , dim , options )
120- decomp4 = cls (dim , dim , options )
121- id3 = decomp3 .id ()
122- id4 = decomp4 .id ()
123- assert id3 != id4
124- assert id3 == decomp3 .id ()
125- assert id4 == decomp4 .id ()
87+ compute_u = jacobisvd .computeU ()
88+ compute_v = jacobisvd .computeV ()
89+ expected_compute_u = bool (
90+ options
91+ & (
92+ nanoeigenpy .DecompositionOptions .ComputeThinU .value
93+ | nanoeigenpy .DecompositionOptions .ComputeFullU .value
94+ )
95+ )
96+ expected_compute_v = bool (
97+ options
98+ & (
99+ nanoeigenpy .DecompositionOptions .ComputeThinV .value
100+ | nanoeigenpy .DecompositionOptions .ComputeFullV .value
101+ )
102+ )
103+ assert compute_u == expected_compute_u
104+ assert compute_v == expected_compute_v
105+
106+ if compute_u :
107+ matrixU = jacobisvd .matrixU ()
108+ if options & nanoeigenpy .DecompositionOptions .ComputeFullU .value :
109+ assert matrixU .shape == (dim , dim )
110+ elif options & nanoeigenpy .DecompositionOptions .ComputeThinU .value :
111+ assert matrixU .shape == (dim , dim )
112+ assert nanoeigenpy .is_approx (matrixU .T @ matrixU , np .eye (matrixU .shape [1 ]))
113+
114+ if compute_v :
115+ matrixV = jacobisvd .matrixV ()
116+ if options & nanoeigenpy .DecompositionOptions .ComputeFullV .value :
117+ assert matrixV .shape == (dim , dim )
118+ elif options & nanoeigenpy .DecompositionOptions .ComputeThinV .value :
119+ assert matrixV .shape == (dim , dim )
120+ assert nanoeigenpy .is_approx (matrixV .T @ matrixV , np .eye (matrixV .shape [1 ]))
121+
122+ if compute_u and compute_v :
123+ U = jacobisvd .matrixU ()
124+ V = jacobisvd .matrixV ()
125+ S = jacobisvd .singularValues ()
126+ S_matrix = np .diag (S )
127+ A_reconstructed = U @ S_matrix @ V .T
128+ assert nanoeigenpy .is_approx (A , A_reconstructed )
129+
130+ jacobisvd .setThreshold ()
131+ _default_threshold = jacobisvd .threshold ()
132+ jacobisvd .setThreshold (1e-8 )
133+ assert jacobisvd .threshold () == 1e-8
134+
135+ decomp1 = cls ()
136+ decomp2 = cls ()
137+ id1 = decomp1 .id ()
138+ id2 = decomp2 .id ()
139+ assert id1 != id2
140+ assert id1 == decomp1 .id ()
141+ assert id2 == decomp2 .id ()
142+
143+ decomp3 = cls (dim , dim , options )
144+ decomp4 = cls (dim , dim , options )
145+ id3 = decomp3 .id ()
146+ id4 = decomp4 .id ()
147+ assert id3 != id4
148+ assert id3 == decomp3 .id ()
149+ assert id4 == decomp4 .id ()
126150
127151
128152if __name__ == "__main__" :
0 commit comments