1818
1919from cvxpy .expressions .constants import Constant
2020from cvxpy .expressions .variable import Variable
21+ from cvxpy .expressions .constants import Constant
22+ import numpy as np
23+ from cvxpy .atoms .elementwise .exp import exp
24+
25+ def collect_constant_and_variable (expr , constants , variable ):
26+ if isinstance (expr , Constant ):
27+ constants .append (expr )
28+ elif isinstance (expr , Variable ):
29+ variable .append (expr )
30+ elif hasattr (expr , "args" ):
31+ for subexpr in expr .args :
32+ collect_constant_and_variable (subexpr , constants , variable )
2133
34+ assert (len (variable ) <= 1 )
35+
36+ # DCED: Without this lower bound the stress test for ML Gaussian non-zero mean fails.
37+ # Perhaps this should be a parameter exposed to the user?
38+ LOWER_BOUND = 1e-5
2239
2340def collect_constant_and_variable (expr , constants , variable ):
2441 if isinstance (expr , Constant ):
@@ -36,7 +53,7 @@ def collect_constant_and_variable(expr, constants, variable):
3653LOWER_BOUND = 1e-5
3754
3855def log_canon (expr , args ):
39- t = Variable (args [0 ].size , bounds = [LOWER_BOUND , None ], name = 't' )
56+ t = Variable (args [0 ].size , bounds = [LOWER_BOUND , None ])
4057
4158 # DCED: if args[0] is a * x for a constant scalar or vector 'a'
4259 # and a vector variable 'x', we want to add bounds to x if x
@@ -71,3 +88,15 @@ def log_canon(expr, args):
7188 t .value = args [0 ].value
7289
7390 return expr .copy ([t ]), [t == args [0 ]]
91+
92+ # TODO (DCED): On some problems this canonicalization seems to work better.
93+ # We should investigate this further when we have more benchmarks
94+ # involving log.
95+ #def log_canon(expr, args):
96+ # t = Variable(args[0].size)
97+ # if args[0].value is not None and np.all(args[0].value > 0):
98+ # t.value = np.log(args[0].value)
99+ # else:
100+ # t.value = expr.point_in_domain()
101+
102+ # return t, [exp(t) == args[0]]
0 commit comments