Skip to content

Commit c759ba8

Browse files
committed
tests for matmul chain rule
1 parent 519991f commit c759ba8

5 files changed

Lines changed: 78 additions & 27 deletions

File tree

cvxpy/reductions/dnlp2smooth/canonicalizers/__init__.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@
4545
from cvxpy.reductions.dnlp2smooth.canonicalizers.log_canon import log_canon
4646
from cvxpy.reductions.dnlp2smooth.canonicalizers.smooth_full_domain_canon import (
4747
exp_canon, logistic_canon, sinh_canon, asinh_canon, tanh_canon,
48-
sin_canon, cos_canon, normcdf_canon, prod_canon, quad_form_canon)
49-
from cvxpy.reductions.dnlp2smooth.canonicalizers.multiply_canon import matmul_canon, multiply_canon
48+
sin_canon, cos_canon, normcdf_canon, prod_canon, quad_form_canon, matmul_canon, multiply_canon)
5049
from cvxpy.reductions.dnlp2smooth.canonicalizers.pnorm_canon import pnorm_canon
5150
from cvxpy.reductions.dnlp2smooth.canonicalizers.power_canon import power_canon
5251
from cvxpy.reductions.dnlp2smooth.canonicalizers.entr_canon import entr_canon

cvxpy/reductions/dnlp2smooth/canonicalizers/multiply_canon.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,15 @@
1515
"""
1616

1717

18-
from cvxpy.expressions.variable import Variable
1918

2019

2120
# TODO: (dance858) do we need to copy things? Do we need to canonicalize at all?
2221
# Can we have a common canonicalizer for binary operators with full domain?
23-
def multiply_canon(expr, args):
24-
return expr.copy(args), []
25-
26-
def matmul_canon(expr, args):
27-
t1 = args[0]
28-
t2 = args[1]
29-
constraints = []
30-
31-
# if either is constant, no canonicalization needed
32-
if t1.is_constant() or t2.is_constant():
33-
return expr.copy([t1, t2]), []
34-
35-
if not isinstance(t1, Variable):
36-
t1 = Variable(t1.shape)
37-
constraints += [t1 == args[0]]
38-
t1.value = args[0].value
39-
40-
if not isinstance(t2, Variable):
41-
t2 = Variable(t2.shape)
42-
constraints += [t2 == args[1]]
43-
t2.value = args[1].value
44-
45-
return expr.copy([t1, t2]), constraints
22+
#def multiply_canon(expr, args):
23+
# return expr.copy(args), []
24+
#
25+
#def matmul_canon(expr, args):
26+
# return expr.copy(args), []
4627

4728
# ----------------------------------------------------------------------------------
4829
# Old versions
@@ -67,3 +48,24 @@ def matmul_canon(expr, args):
6748
# t2.value = args[1].value
6849
#
6950
# return expr.copy([t1, t2]), constraints
51+
52+
#def matmul_canon(expr, args):
53+
# t1 = args[0]
54+
# t2 = args[1]
55+
# constraints = []
56+
#
57+
# # if either is constant, no canonicalization needed
58+
# if t1.is_constant() or t2.is_constant():
59+
# return expr.copy([t1, t2]), []
60+
#
61+
# if not isinstance(t1, Variable):
62+
# t1 = Variable(t1.shape)
63+
# constraints += [t1 == args[0]]
64+
# t1.value = args[0].value
65+
#
66+
# if not isinstance(t2, Variable):
67+
# t2 = Variable(t2.shape)
68+
# constraints += [t2 == args[1]]
69+
# t2.value = args[1].value
70+
#
71+
# return expr.copy([t1, t2]), constraints

cvxpy/reductions/dnlp2smooth/canonicalizers/rel_entr_canon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from cvxpy.expressions.variable import Variable
2323
from cvxpy.reductions.dnlp2smooth.canonicalizers.entr_canon import entr_canon
2424
from cvxpy.reductions.dnlp2smooth.canonicalizers.log_canon import log_canon
25-
from cvxpy.reductions.dnlp2smooth.canonicalizers.multiply_canon import multiply_canon
25+
from cvxpy.reductions.dnlp2smooth.canonicalizers.smooth_full_domain_canon import multiply_canon
2626

2727
MIN_INIT = 1e-3
2828

cvxpy/reductions/dnlp2smooth/canonicalizers/smooth_full_domain_canon.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,9 @@ def smooth_full_domain_canon_chain_rule(expr, args):
4343
logistic_canon = smooth_full_domain_canon_chain_rule
4444
normcdf_canon = smooth_full_domain_canon_chain_rule
4545

46+
# bivariate atoms with chain rule implemented in diff engine
47+
multiply_canon = smooth_full_domain_canon_chain_rule
48+
matmul_canon = smooth_full_domain_canon_chain_rule
49+
50+
4651
# TODO: do we even need the smooth full domain canon chain rule canonicalizers?

cvxpy/tests/nlp_tests/stress_tests_diff_engine/test_compositions.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,48 @@ def test_quad_form_composition_two(self):
129129
prob.solve(solver=cp.IPOPT, nlp=True, verbose=True)
130130
checker = DerivativeChecker(prob)
131131
checker.run_and_assert()
132+
133+
def test_matmul_composition_one(self):
134+
np.random.seed(0)
135+
m, n, p = 5, 7, 11
136+
X = cp.Variable((m, n), bounds=[-1, 1], name='X')
137+
Y = cp.Variable((n, p), bounds=[-2, 2], name='Y')
138+
Y.value = np.random.rand(n, p)
139+
obj = cp.sum(cp.matmul(X, cp.cos(Y)))
140+
problem = cp.Problem(cp.Minimize(obj))
141+
problem.solve(solver=cp.IPOPT, nlp=True, verbose=True)
142+
assert(problem.status == cp.OPTIMAL)
143+
checker = DerivativeChecker(problem)
144+
checker.run_and_assert()
145+
146+
def test_matmul_composition_two(self):
147+
np.random.seed(0)
148+
m, n, p = 5, 5, 5
149+
X = cp.Variable((m, n), bounds=[-1, 1])
150+
Y = cp.Variable((n, p), bounds=[-2, 2])
151+
Y.value = np.random.rand(n, p)
152+
X.value = np.random.rand(m, n)
153+
obj = cp.sum(cp.matmul(cp.matmul(X, X), cp.cos(Y) + X))
154+
problem = cp.Problem(cp.Minimize(obj))
155+
checker = DerivativeChecker(problem)
156+
checker.run_and_assert()
157+
problem.solve(solver=cp.IPOPT, nlp=True, verbose=True)
158+
assert(problem.status == cp.OPTIMAL)
159+
checker = DerivativeChecker(problem)
160+
checker.run_and_assert()
161+
162+
def test_matmul_composition_three(self):
163+
np.random.seed(0)
164+
m, n, p = 5, 5, 5
165+
X = cp.Variable((m, n), bounds=[-1, 1], name='X')
166+
Y = cp.Variable((n, p), bounds=[-2, 2], name='Y')
167+
Y.value = np.random.rand(n, p)
168+
X.value = np.random.rand(m, n)
169+
obj = cp.sum(cp.matmul(cp.matmul(X, X.T), (cp.cos(Y) + X).T))
170+
problem = cp.Problem(cp.Minimize(obj))
171+
checker = DerivativeChecker(problem)
172+
checker.run_and_assert()
173+
problem.solve(solver=cp.IPOPT, nlp=True, verbose=True)
174+
assert(problem.status == cp.OPTIMAL)
175+
checker = DerivativeChecker(problem)
176+
checker.run_and_assert()

0 commit comments

Comments
 (0)