1
+ import cvxpy as cp
2
+ import numpy as np
3
+
4
+ import diffcp .cone_program as cone_prog
5
+ import diffcp .utils as utils
6
+
7
+
8
+ def test_solve_and_derivative ():
9
+ np .random .seed (0 )
10
+ m = 20
11
+ n = 10
12
+
13
+ A , b , c , cone_dims = utils .least_squares_eq_scs_data (m , n )
14
+ for mode in ["lsqr" , "dense" ]:
15
+ x , y , s , derivative , adjoint_derivative = cone_prog .solve_and_derivative (
16
+ A , b , c , cone_dims , mode = mode , solve_method = "Clarabel" )
17
+
18
+ dA = utils .get_random_like (
19
+ A , lambda n : np .random .normal (0 , 1e-6 , size = n ))
20
+ db = np .random .normal (0 , 1e-6 , size = b .size )
21
+ dc = np .random .normal (0 , 1e-6 , size = c .size )
22
+
23
+ dx , dy , ds = derivative (dA , db , dc )
24
+
25
+ x_pert , y_pert , s_pert , _ , _ = cone_prog .solve_and_derivative (
26
+ A + dA , b + db , c + dc , cone_dims , solve_method = "Clarabel" )
27
+
28
+ np .testing .assert_allclose (x_pert - x , dx , atol = 1e-8 )
29
+ np .testing .assert_allclose (y_pert - y , dy , atol = 1e-8 )
30
+ np .testing .assert_allclose (s_pert - s , ds , atol = 1e-8 )
31
+
32
+ objective = c .T @ x
33
+ dA , db , dc = adjoint_derivative (
34
+ c , np .zeros (y .size ), np .zeros (s .size ))
35
+
36
+ x_pert , _ , _ , _ , _ = cone_prog .solve_and_derivative (
37
+ A + 1e-6 * dA , b + 1e-6 * db , c + 1e-6 * dc , cone_dims , solve_method = "Clarabel" )
38
+ objective_pert = c .T @ x_pert
39
+
40
+ np .testing .assert_allclose (
41
+ objective_pert - objective ,
42
+ 1e-6 * dA .multiply (dA ).sum () + 1e-6 * db @ db + 1e-6 * dc @ dc , atol = 1e-8 )
43
+
44
+
45
+ def test_warm_start ():
46
+ np .random .seed (0 )
47
+ m = 20
48
+ n = 10
49
+ A , b , c , cone_dims = utils .least_squares_eq_scs_data (m , n )
50
+ x , y , s , _ , _ = cone_prog .solve_and_derivative (
51
+ A , b , c , cone_dims , solve_method = "Clarabel" )
52
+ x_p , y_p , s_p , _ , _ = cone_prog .solve_and_derivative (
53
+ A , b , c , cone_dims , warm_start = (x , y , s ), max_iters = 1 , solve_method = "Clarabel" )
54
+
55
+ np .testing .assert_allclose (x , x_p , atol = 1e-7 )
56
+ np .testing .assert_allclose (y , y_p , atol = 1e-7 )
57
+ np .testing .assert_allclose (s , s_p , atol = 1e-7 )
58
+
59
+
60
+ def test_threading ():
61
+ np .random .seed (0 )
62
+ test_rtol = 1e-3
63
+ test_atol = 1e-8
64
+ m = 20
65
+ n = 10
66
+ As , bs , cs , cone_dicts = [], [], [], []
67
+ results = []
68
+
69
+ for _ in range (50 ):
70
+ A , b , c , cone_dims = utils .least_squares_eq_scs_data (m , n )
71
+ As += [A ]
72
+ bs += [b ]
73
+ cs += [c ]
74
+ cone_dicts += [cone_dims ]
75
+ results .append (cone_prog .solve_and_derivative (A , b , c , cone_dims ))
76
+
77
+ for n_jobs in [1 , - 1 ]:
78
+ xs , ys , ss , _ , DT_batch = cone_prog .solve_and_derivative_batch (
79
+ As , bs , cs , cone_dicts , n_jobs_forward = n_jobs , n_jobs_backward = n_jobs )
80
+
81
+ for i in range (50 ):
82
+ np .testing .assert_allclose (results [i ][0 ], xs [i ], rtol = test_rtol , atol = test_atol )
83
+ np .testing .assert_allclose (results [i ][1 ], ys [i ], rtol = test_rtol , atol = test_atol )
84
+ np .testing .assert_allclose (results [i ][2 ], ss [i ], rtol = test_rtol , atol = test_atol )
85
+
86
+ dAs , dbs , dcs = DT_batch (xs , ys , ss )
87
+ for i in range (50 ):
88
+ dA , db , dc = results [
89
+ i ][- 1 ](results [i ][0 ], results [i ][1 ], results [i ][2 ])
90
+ np .testing .assert_allclose (dA .todense (), dAs [i ].todense (), rtol = test_rtol , atol = test_atol )
91
+ np .testing .assert_allclose (dbs [i ], db , rtol = test_rtol , atol = test_atol )
92
+ np .testing .assert_allclose (dcs [i ], dc , rtol = test_rtol , atol = test_atol )
93
+
94
+
95
+ def test_expcone ():
96
+ np .random .seed (0 )
97
+ n = 10
98
+ y = cp .Variable (n )
99
+ obj = cp .Minimize (- cp .sum (cp .entr (y )))
100
+ const = [cp .sum (y ) == 1 ]
101
+ prob = cp .Problem (obj , const )
102
+ A , b , c , cone_dims = utils .scs_data_from_cvxpy_problem (prob )
103
+ for mode in ["lsqr" , "lsmr" , "dense" ]:
104
+ x , y , s , D , DT = cone_prog .solve_and_derivative (
105
+ A ,
106
+ b ,
107
+ c ,
108
+ cone_dims ,
109
+ solve_method = "Clarabel" ,
110
+ mode = mode ,
111
+ tol_gap_abs = 1e-10 ,
112
+ tol_gap_rel = 1e-10 ,
113
+ tol_feas = 1e-10 ,
114
+ tol_infeas_abs = 1e-10 ,
115
+ tol_infeas_rel = 1e-10 ,
116
+ tol_ktratio = 1e-10 ,
117
+ )
118
+ dA = utils .get_random_like (A , lambda n : np .random .normal (0 , 1e-6 , size = n ))
119
+ db = np .random .normal (0 , 1e-6 , size = b .size )
120
+ dc = np .random .normal (0 , 1e-6 , size = c .size )
121
+ dx , dy , ds = D (dA , db , dc )
122
+ x_pert , y_pert , s_pert , _ , _ = cone_prog .solve_and_derivative (
123
+ A + dA ,
124
+ b + db ,
125
+ c + dc ,
126
+ cone_dims ,
127
+ solve_method = "Clarabel" ,
128
+ mode = mode ,
129
+ tol_gap_abs = 1e-10 ,
130
+ tol_gap_rel = 1e-10 ,
131
+ tol_feas = 1e-10 ,
132
+ tol_infeas_abs = 1e-10 ,
133
+ tol_infeas_rel = 1e-10 ,
134
+ tol_ktratio = 1e-10
135
+ )
136
+
137
+ import IPython as ipy
138
+ ipy .embed ()
139
+
140
+ np .testing .assert_allclose (x_pert - x , dx , atol = 1e-8 )
141
+ np .testing .assert_allclose (y_pert - y , dy , atol = 1e-8 )
142
+ np .testing .assert_allclose (s_pert - s , ds , atol = 1e-8 )
143
+
144
+
145
+ if __name__ == "__main__" :
146
+ test_expcone ()
0 commit comments