6
6
from poly_matrix import PolyMatrix
7
7
8
8
from cert_tools import HomQCQP
9
+ from cert_tools .linalg_tools import smat , svec
9
10
from cert_tools .problems .rot_synch import RotSynchLoopProblem
10
- from cert_tools .sparse_solvers import solve_dsdp
11
+ from cert_tools .sdp_solvers import solve_sdp_homqcqp
12
+ from cert_tools .sparse_solvers import solve_clarabel , solve_dsdp
11
13
12
14
13
15
def get_chain_rot_prob (N = 10 ):
@@ -20,33 +22,32 @@ def get_loop_rot_prob():
20
22
21
23
class TestHomQCQP (unittest .TestCase ):
22
24
23
- def test_solve ():
25
+ def test_solve (self ):
24
26
# Create chain of rotations problem:
25
27
problem = get_chain_rot_prob ()
26
28
assert isinstance (problem , HomQCQP ), TypeError (
27
29
"Problem should be homogenized qcqp object"
28
30
)
29
31
# Solve SDP via standard method
30
- X , info , time = problem . solve_sdp ( verbose = True )
32
+ X , info , time = solve_sdp_homqcqp ( problem , verbose = True )
31
33
# Convert solution
32
34
R = problem .convert_sdp_to_rot (X )
33
35
34
- def test_get_asg (plot = False ):
35
- """Test retreival of aggregate sparsity graph"""
36
+ def test_get_asg (self , plot = False ):
37
+ """Test retrieval of aggregate sparsity graph"""
36
38
# Test on chain graph
37
39
problem = get_chain_rot_prob ()
38
- problem .get_asg (rm_homog = True ) # Get Graph
39
- problem .triangulate_graph () # Triangulate graph
40
+ problem .clique_decomposition ()
40
41
# No fill in expected
41
- assert any ( problem .asg . es [ "fill_edge" ]) is False
42
+ assert problem .symb . fill [ 0 ] == 0 , ValueError ( "Expected no fill in" )
42
43
if plot :
43
44
problem .plot_asg ()
44
45
45
46
# Test on loop graph
46
47
problem = get_loop_rot_prob ()
47
- problem .get_asg (rm_homog = True )
48
- problem .triangulate_graph ()
49
- assert any ( problem .asg . es [ "fill_edge" ]) is True
48
+ problem .get_asg (rm_homog = False )
49
+ problem .clique_decomposition ()
50
+ assert problem .symb . fill [ 0 ] > 0 , ValueError ( "Expected fill in" )
50
51
if plot :
51
52
problem .plot_asg ()
52
53
@@ -77,8 +78,8 @@ def test_clique_decomp(self, rm_homog=False, plot=False):
77
78
parent = problem .cliques [clique .parent ]
78
79
79
80
vertices = list (parent .var_sizes .keys ()) + list (clique .var_sizes .keys ())
80
- assert set (clique .seperator ).issubset (vertices ), ValueError (
81
- "seperator set should be in set of involved clique vertices"
81
+ assert set (clique .separator ).issubset (vertices ), ValueError (
82
+ "separator set should be in set of involved clique vertices"
82
83
)
83
84
84
85
# Check that mapping from variables to cliques is correct
@@ -98,7 +99,6 @@ def test_consistency_constraints(self):
98
99
# Test chain topology
99
100
nvars = 5
100
101
problem = get_chain_rot_prob (N = nvars )
101
- problem .get_asg (rm_homog = False ) # Get Graph
102
102
problem .clique_decomposition () # Run clique decomposition
103
103
eq_list = problem .get_consistency_constraints ()
104
104
@@ -115,11 +115,11 @@ def test_consistency_constraints(self):
115
115
x_list , info = solve_dsdp (problem , verbose = True , tol = 1e-8 )
116
116
# Verify that the clique variables are equal on overlaps
117
117
for l , clique_l in enumerate (problem .cliques ):
118
- # seperator
119
- sepset = clique_l .seperator
118
+ # separator
119
+ sepset = clique_l .separator
120
120
if len (sepset ) == 0 : # skip the root clique
121
121
continue
122
- # fet parent clique and seperator set
122
+ # fet parent clique and separator set
123
123
k = clique_l .parent
124
124
clique_k = problem .cliques [k ]
125
125
@@ -135,7 +135,6 @@ def test_decompose_matrix(self):
135
135
# setup
136
136
nvars = 5
137
137
problem = get_chain_rot_prob (N = nvars )
138
- problem .get_asg (rm_homog = False ) # Get Graph
139
138
problem .clique_decomposition () # get clique decomposition
140
139
C = problem .C
141
140
@@ -173,10 +172,9 @@ def test_solve_dsdp(self):
173
172
# Test chain topology
174
173
nvars = 5
175
174
problem = get_chain_rot_prob (N = nvars )
176
- problem .get_asg (rm_homog = False ) # Get agg sparse graph
177
175
problem .clique_decomposition () # get cliques
178
176
# Solve non-decomposed problem
179
- X , info , time = problem . solve_sdp ( verbose = True )
177
+ X , info , time = solve_sdp_homqcqp ( problem , verbose = True )
180
178
# get cliques from non-decomposed solution
181
179
c_list_nd = problem .get_cliques_from_psd_mat (X )
182
180
# Solve decomposed problem (Interior Point Version)
@@ -208,12 +206,52 @@ def test_solve_dsdp(self):
208
206
err_msg = "Completed and non-decomposed solutions differ" ,
209
207
)
210
208
209
+ def test_standard_form (self ):
210
+ """Test that the standard form problem definition is correct"""
211
+ nvars = 2
212
+ problem = get_chain_rot_prob (N = nvars )
213
+ problem .get_asg ()
214
+ P , q , A , b = problem .get_standard_form ()
215
+
216
+ # get solution from MOSEK
217
+ X , info , time = solve_sdp_homqcqp (problem , verbose = True )
218
+ x = svec (X )
219
+
220
+ # Check cost matrix
221
+ cost = np .dot (b , x )
222
+ np .testing .assert_allclose (
223
+ cost , info ["cost" ], atol = 1e-12 , err_msg = "Cost incorrect"
224
+ )
225
+ # Check constraints
226
+ for i , vec in enumerate (A .T ):
227
+ a = vec .toarray ().squeeze (0 )
228
+ value = np .dot (a , x )
229
+ np .testing .assert_allclose (
230
+ value , - q [i ], atol = 1e-10 , err_msg = f"Constraint { i } has violation"
231
+ )
232
+
233
+ def test_clarabel (self ):
234
+ nvars = 2
235
+ problem = get_chain_rot_prob (N = nvars )
236
+ problem .get_asg ()
237
+ X_clarabel = solve_clarabel (problem )
238
+ X , info , time = solve_sdp_homqcqp (problem , verbose = True )
239
+
240
+ np .testing .assert_allclose (
241
+ X_clarabel ,
242
+ X ,
243
+ atol = 1e-9 ,
244
+ err_msg = "Clarabel and MOSEK solutions differ" ,
245
+ )
246
+
211
247
212
248
if __name__ == "__main__" :
213
249
test = TestHomQCQP ()
214
250
# test.test_solve()
215
251
# test.test_get_asg(plot=True)
216
252
# test.test_clique_decomp(plot=False)
217
- # test.test_consistency_constraints()
253
+ test .test_consistency_constraints ()
218
254
# test.test_decompose_matrix()
219
- test .test_solve_dsdp ()
255
+ # test.test_solve_dsdp()
256
+ # test.test_standard_form()
257
+ # test.test_clarabel()
0 commit comments