Skip to content

Commit 624f5f5

Browse files
committed
adds new folder for tests
1 parent d7a3a02 commit 624f5f5

1 file changed

Lines changed: 358 additions & 0 deletions

File tree

python/tests/convert_tests.py

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
import cvxpy as cp
2+
import numpy as np
3+
import DNLP_diff_engine as diffengine
4+
from convert import convert_problem, get_jacobian
5+
6+
7+
def test_sum_log():
8+
"""Test sum(log(x)) forward and jacobian."""
9+
x = cp.Variable(4)
10+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(x))))
11+
c_obj, _ = convert_problem(problem)
12+
13+
test_values = np.array([1.0, 2.0, 3.0, 4.0])
14+
15+
# Forward
16+
result = diffengine.forward(c_obj, test_values)
17+
expected = np.sum(np.log(test_values))
18+
assert np.allclose(result, expected)
19+
20+
# Jacobian: d/dx sum(log(x)) = [1/x_1, 1/x_2, ...]
21+
jac = get_jacobian(c_obj, test_values)
22+
expected_jac = (1.0 / test_values).reshape(1, -1)
23+
assert np.allclose(jac.toarray(), expected_jac)
24+
25+
26+
def test_sum_exp():
27+
"""Test sum(exp(x)) forward and jacobian."""
28+
x = cp.Variable(3)
29+
problem = cp.Problem(cp.Minimize(cp.sum(cp.exp(x))))
30+
c_obj, _ = convert_problem(problem)
31+
32+
test_values = np.array([0.0, 1.0, 2.0])
33+
34+
# Forward
35+
result = diffengine.forward(c_obj, test_values)
36+
expected = np.sum(np.exp(test_values))
37+
assert np.allclose(result, expected)
38+
39+
# Jacobian: d/dx sum(exp(x)) = [exp(x_1), exp(x_2), ...]
40+
jac = get_jacobian(c_obj, test_values)
41+
expected_jac = np.exp(test_values).reshape(1, -1)
42+
assert np.allclose(jac.toarray(), expected_jac)
43+
44+
45+
def test_two_variables_elementwise_add():
46+
"""Test sum(log(x + y)) - elementwise after add."""
47+
x = cp.Variable(2)
48+
y = cp.Variable(2)
49+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(x + y))))
50+
c_obj, _ = convert_problem(problem)
51+
52+
test_values = np.array([1.0, 2.0, 3.0, 4.0])
53+
54+
# Forward
55+
result = diffengine.forward(c_obj, test_values)
56+
expected = np.sum(np.log(np.array([1+3, 2+4])))
57+
assert np.allclose(result, expected)
58+
59+
# TODO: Jacobian for elementwise(add(...)) patterns not yet supported
60+
61+
62+
def test_variable_reuse():
63+
"""Test sum(log(x) + exp(x)) - same variable used twice."""
64+
x = cp.Variable(2)
65+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(x) + cp.exp(x))))
66+
c_obj, _ = convert_problem(problem)
67+
68+
test_values = np.array([1.0, 2.0])
69+
70+
# Forward
71+
result = diffengine.forward(c_obj, test_values)
72+
expected = np.sum(np.log(test_values) + np.exp(test_values))
73+
assert np.allclose(result, expected)
74+
75+
# Jacobian: d/dx_i = 1/x_i + exp(x_i)
76+
jac = get_jacobian(c_obj, test_values)
77+
expected_jac = (1.0 / test_values + np.exp(test_values)).reshape(1, -1)
78+
assert np.allclose(jac.toarray(), expected_jac)
79+
80+
81+
def test_four_variables_elementwise_add():
82+
"""Test sum(log(a + b) + exp(c + d)) - elementwise after add."""
83+
a = cp.Variable(3)
84+
b = cp.Variable(3)
85+
c = cp.Variable(3)
86+
d = cp.Variable(3)
87+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(a + b) + cp.exp(c + d))))
88+
c_obj, _ = convert_problem(problem)
89+
90+
a_vals = np.array([1.0, 2.0, 3.0])
91+
b_vals = np.array([0.5, 1.0, 1.5])
92+
c_vals = np.array([0.1, 0.2, 0.3])
93+
d_vals = np.array([0.1, 0.1, 0.1])
94+
test_values = np.concatenate([a_vals, b_vals, c_vals, d_vals])
95+
96+
# Forward
97+
result = diffengine.forward(c_obj, test_values)
98+
expected = np.sum(np.log(a_vals + b_vals) + np.exp(c_vals + d_vals))
99+
assert np.allclose(result, expected)
100+
101+
# TODO: Jacobian for elementwise(add(...)) patterns not yet supported
102+
103+
104+
def test_deep_nesting():
105+
"""Test sum(log(exp(log(exp(x))))) - deeply nested elementwise."""
106+
x = cp.Variable(4)
107+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(cp.exp(cp.log(cp.exp(x)))))))
108+
c_obj, _ = convert_problem(problem)
109+
110+
test_values = np.array([0.5, 1.0, 1.5, 2.0])
111+
112+
# Forward
113+
result = diffengine.forward(c_obj, test_values)
114+
expected = np.sum(np.log(np.exp(np.log(np.exp(test_values)))))
115+
assert np.allclose(result, expected)
116+
117+
# TODO: Jacobian for nested elementwise compositions not yet supported
118+
119+
120+
def test_chained_additions():
121+
"""Test sum(x + y + z + w) - chained additions."""
122+
x = cp.Variable(2)
123+
y = cp.Variable(2)
124+
z = cp.Variable(2)
125+
w = cp.Variable(2)
126+
problem = cp.Problem(cp.Minimize(cp.sum(x + y + z + w)))
127+
c_obj, _ = convert_problem(problem)
128+
129+
x_vals = np.array([1.0, 2.0])
130+
y_vals = np.array([3.0, 4.0])
131+
z_vals = np.array([5.0, 6.0])
132+
w_vals = np.array([7.0, 8.0])
133+
test_values = np.concatenate([x_vals, y_vals, z_vals, w_vals])
134+
135+
# Forward
136+
result = diffengine.forward(c_obj, test_values)
137+
expected = np.sum(x_vals + y_vals + z_vals + w_vals)
138+
assert np.allclose(result, expected)
139+
140+
# TODO: Jacobian for sum(add(...)) patterns not yet supported
141+
142+
143+
def test_variable_used_multiple_times():
144+
"""Test sum(log(x) + exp(x) + x) - variable used 3+ times."""
145+
x = cp.Variable(3)
146+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(x) + cp.exp(x) + x)))
147+
c_obj, _ = convert_problem(problem)
148+
149+
test_values = np.array([1.0, 2.0, 3.0])
150+
151+
# Forward
152+
result = diffengine.forward(c_obj, test_values)
153+
expected = np.sum(np.log(test_values) + np.exp(test_values) + test_values)
154+
assert np.allclose(result, expected)
155+
156+
# TODO: Jacobian for expressions with sum(variable) not yet supported
157+
158+
159+
def test_larger_variable():
160+
"""Test sum(log(x)) with larger variable (100 elements)."""
161+
x = cp.Variable(100)
162+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(x))))
163+
c_obj, _ = convert_problem(problem)
164+
165+
test_values = np.linspace(1.0, 10.0, 100)
166+
167+
# Forward
168+
result = diffengine.forward(c_obj, test_values)
169+
expected = np.sum(np.log(test_values))
170+
assert np.allclose(result, expected)
171+
172+
# Jacobian
173+
jac = get_jacobian(c_obj, test_values)
174+
expected_jac = (1.0 / test_values).reshape(1, -1)
175+
assert np.allclose(jac.toarray(), expected_jac)
176+
177+
178+
def test_matrix_variable():
179+
"""Test sum(log(X)) with 2D matrix variable (3x4)."""
180+
X = cp.Variable((3, 4))
181+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(X))))
182+
c_obj, _ = convert_problem(problem)
183+
184+
test_values = np.arange(1.0, 13.0) # 12 elements
185+
186+
# Forward
187+
result = diffengine.forward(c_obj, test_values)
188+
expected = np.sum(np.log(test_values))
189+
assert np.allclose(result, expected)
190+
191+
# Jacobian
192+
jac = get_jacobian(c_obj, test_values)
193+
expected_jac = (1.0 / test_values).reshape(1, -1)
194+
assert np.allclose(jac.toarray(), expected_jac)
195+
196+
197+
def test_mixed_sizes():
198+
"""Test sum(log(a)) + sum(log(b)) + sum(log(c)) with different sized variables."""
199+
a = cp.Variable(2)
200+
b = cp.Variable(5)
201+
c = cp.Variable(3)
202+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(a)) + cp.sum(cp.log(b)) + cp.sum(cp.log(c))))
203+
c_obj, _ = convert_problem(problem)
204+
205+
a_vals = np.array([1.0, 2.0])
206+
b_vals = np.array([1.0, 2.0, 3.0, 4.0, 5.0])
207+
c_vals = np.array([1.0, 2.0, 3.0])
208+
test_values = np.concatenate([a_vals, b_vals, c_vals])
209+
210+
# Forward
211+
result = diffengine.forward(c_obj, test_values)
212+
expected = np.sum(np.log(a_vals)) + np.sum(np.log(b_vals)) + np.sum(np.log(c_vals))
213+
assert np.allclose(result, expected)
214+
215+
# Jacobian
216+
jac = get_jacobian(c_obj, test_values)
217+
expected_jac = (1.0 / test_values).reshape(1, -1)
218+
assert np.allclose(jac.toarray(), expected_jac)
219+
220+
221+
def test_multiple_variables_log_exp():
222+
"""Test sum(log(a)) + sum(log(b)) + sum(exp(c)) + sum(exp(d))."""
223+
a = cp.Variable(2)
224+
b = cp.Variable(2)
225+
c = cp.Variable(2)
226+
d = cp.Variable(2)
227+
obj = cp.sum(cp.log(a)) + cp.sum(cp.log(b)) + cp.sum(cp.exp(c)) + cp.sum(cp.exp(d))
228+
problem = cp.Problem(cp.Minimize(obj))
229+
c_obj, _ = convert_problem(problem)
230+
231+
a_vals = np.array([1.0, 2.0])
232+
b_vals = np.array([0.5, 1.0])
233+
c_vals = np.array([0.1, 0.2])
234+
d_vals = np.array([0.1, 0.1])
235+
test_values = np.concatenate([a_vals, b_vals, c_vals, d_vals])
236+
237+
# Forward
238+
result = diffengine.forward(c_obj, test_values)
239+
expected = (np.sum(np.log(a_vals)) + np.sum(np.log(b_vals)) +
240+
np.sum(np.exp(c_vals)) + np.sum(np.exp(d_vals)))
241+
assert np.allclose(result, expected)
242+
243+
# Jacobian
244+
jac = get_jacobian(c_obj, test_values)
245+
df_da = 1.0 / a_vals
246+
df_db = 1.0 / b_vals
247+
df_dc = np.exp(c_vals)
248+
df_dd = np.exp(d_vals)
249+
expected_jac = np.concatenate([df_da, df_db, df_dc, df_dd]).reshape(1, -1)
250+
assert np.allclose(jac.toarray(), expected_jac)
251+
252+
253+
def test_two_variables_separate_sums():
254+
"""Test sum(log(x) + log(y)) - two variables with separate elementwise ops."""
255+
x = cp.Variable(2)
256+
y = cp.Variable(2)
257+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(x) + cp.log(y))))
258+
c_obj, _ = convert_problem(problem)
259+
260+
test_values = np.array([1.0, 2.0, 3.0, 4.0])
261+
262+
# Forward
263+
result = diffengine.forward(c_obj, test_values)
264+
expected = np.sum(np.log(test_values[:2]) + np.log(test_values[2:]))
265+
assert np.allclose(result, expected)
266+
267+
# Jacobian
268+
jac = get_jacobian(c_obj, test_values)
269+
expected_jac = np.array([[1/1, 1/2, 1/3, 1/4]])
270+
assert np.allclose(jac.toarray(), expected_jac)
271+
272+
273+
def test_complex_objective_elementwise_add():
274+
"""Test sum(log(x + y)) + sum(exp(y + z)) + sum(log(z + x)) - elementwise after add."""
275+
x = cp.Variable(3)
276+
y = cp.Variable(3)
277+
z = cp.Variable(3)
278+
obj = cp.sum(cp.log(x + y)) + cp.sum(cp.exp(y + z)) + cp.sum(cp.log(z + x))
279+
problem = cp.Problem(cp.Minimize(obj))
280+
c_obj, _ = convert_problem(problem)
281+
282+
x_vals = np.array([1.0, 2.0, 3.0])
283+
y_vals = np.array([0.5, 1.0, 1.5])
284+
z_vals = np.array([0.2, 0.3, 0.4])
285+
test_values = np.concatenate([x_vals, y_vals, z_vals])
286+
287+
# Forward
288+
result = diffengine.forward(c_obj, test_values)
289+
expected = (np.sum(np.log(x_vals + y_vals)) +
290+
np.sum(np.exp(y_vals + z_vals)) +
291+
np.sum(np.log(z_vals + x_vals)))
292+
assert np.allclose(result, expected)
293+
294+
# TODO: Jacobian for elementwise(add(...)) patterns not yet supported
295+
296+
297+
def test_complex_objective_no_add():
298+
"""Test sum(log(x) + exp(y) + log(z)) - multiple elementwise ops without add composition."""
299+
x = cp.Variable(2)
300+
y = cp.Variable(2)
301+
z = cp.Variable(2)
302+
obj = cp.sum(cp.log(x) + cp.exp(y) + cp.log(z))
303+
problem = cp.Problem(cp.Minimize(obj))
304+
c_obj, _ = convert_problem(problem)
305+
306+
x_vals = np.array([1.0, 2.0])
307+
y_vals = np.array([0.5, 1.0])
308+
z_vals = np.array([0.2, 0.3])
309+
test_values = np.concatenate([x_vals, y_vals, z_vals])
310+
311+
# Forward
312+
result = diffengine.forward(c_obj, test_values)
313+
expected = np.sum(np.log(x_vals) + np.exp(y_vals) + np.log(z_vals))
314+
assert np.allclose(result, expected)
315+
316+
# Jacobian
317+
jac = get_jacobian(c_obj, test_values)
318+
df_dx = 1.0 / x_vals
319+
df_dy = np.exp(y_vals)
320+
df_dz = 1.0 / z_vals
321+
expected_jac = np.concatenate([df_dx, df_dy, df_dz]).reshape(1, -1)
322+
assert np.allclose(jac.toarray(), expected_jac)
323+
324+
325+
def test_log_exp_identity():
326+
"""Test sum(log(exp(x))) = sum(x) identity - nested elementwise."""
327+
x = cp.Variable(5)
328+
problem = cp.Problem(cp.Minimize(cp.sum(cp.log(cp.exp(x)))))
329+
c_obj, _ = convert_problem(problem)
330+
331+
test_values = np.array([-1.0, 0.0, 1.0, 2.0, 3.0])
332+
333+
# Forward
334+
result = diffengine.forward(c_obj, test_values)
335+
expected = np.sum(test_values) # log(exp(x)) = x
336+
assert np.allclose(result, expected)
337+
338+
# TODO: Jacobian for nested elementwise compositions not yet supported
339+
340+
341+
if __name__ == "__main__":
342+
test_sum_log()
343+
test_sum_exp()
344+
test_two_variables_elementwise_add()
345+
test_variable_reuse()
346+
test_four_variables_elementwise_add()
347+
test_deep_nesting()
348+
test_chained_additions()
349+
test_variable_used_multiple_times()
350+
test_larger_variable()
351+
test_matrix_variable()
352+
test_mixed_sizes()
353+
test_multiple_variables_log_exp()
354+
test_two_variables_separate_sums()
355+
test_complex_objective_elementwise_add()
356+
test_complex_objective_no_add()
357+
test_log_exp_identity()
358+
print("All tests passed!")

0 commit comments

Comments
 (0)