1616
1717import numpy as np
1818import scipy .sparse as sp
19- from time import time
2019
2120import cvxpy .settings as s
2221from cvxpy .constraints import (
@@ -134,14 +133,7 @@ def solve_via_data(self, data, warm_start: bool, verbose: bool, solver_opts, sol
134133 """
135134 import cyipopt
136135 bounds = self .Bounds (data ["problem" ])
137- initial_values = []
138- for var in bounds .main_var :
139- if var .value is not None :
140- initial_values .append (var .value .flatten (order = 'F' ))
141- else :
142- # If no initial value, use zero
143- initial_values .append (np .zeros (var .size ))
144- x0 = np .concatenate (initial_values , axis = 0 )
136+ x0 = self .construct_initial_point (bounds )
145137 nlp = cyipopt .Problem (
146138 n = len (x0 ),
147139 m = len (bounds .cl ),
@@ -153,9 +145,14 @@ def solve_via_data(self, data, warm_start: bool, verbose: bool, solver_opts, sol
153145 )
154146 nlp .add_option ('mu_strategy' , 'adaptive' )
155147 nlp .add_option ('tol' , 1e-7 )
156- nlp .add_option ('honor_original_bounds' , 'yes' )
148+ #nlp.add_option('honor_original_bounds', 'yes')
149+ nlp .add_option ('bound_relax_factor' , 0.0 )
157150 nlp .add_option ('hessian_approximation' , "limited-memory" )
158151 nlp .add_option ('derivative_test' , 'first-order' )
152+ nlp .add_option ('least_square_init_duals' , 'yes' )
153+ #nlp.add_option('constr_mult_init_max', 1e10)
154+ #nlp.add_option('derivative_test_perturbation', 1e-5)
155+ #nlp.add_option('point_perturbation_radius', 0.1)
159156 _ , info = nlp .solve (x0 )
160157 return info
161158
@@ -168,6 +165,43 @@ def cite(self, data):
168165 Data generated via an apply call.
169166 """
170167 return CITATION_DICT ["IPOPT" ]
168+
169+ # TODO (DCED): Ask WZ where to put this.
170+ def construct_initial_point (self , bounds ):
171+ initial_values = []
172+ offset = 0
173+ lbs = bounds .lb
174+ ubs = bounds .ub
175+ for var in bounds .main_var :
176+ if var .value is not None :
177+ initial_values .append (var .value .flatten (order = 'F' ))
178+ else :
179+ # If no initial value is specified, look at the bounds.
180+ # If both lb and ub are specified, we initialize the
181+ # variables to be their midpoints. If only one of them
182+ # is specified, we initialize the variable one unit
183+ # from the bound. If none of them is specified, we
184+ # initialize it to zero.
185+ lb = lbs [offset :offset + var .size ]
186+ ub = ubs [offset :offset + var .size ]
187+
188+ lb_finite = np .isfinite (lb )
189+ ub_finite = np .isfinite (ub )
190+
191+ # Replace infs with zero for arithmetic
192+ lb0 = np .where (lb_finite , lb , 0.0 )
193+ ub0 = np .where (ub_finite , ub , 0.0 )
194+
195+ # Midpoint if both finite, one from bound if only one finite, zero if none
196+ init = (lb_finite * ub_finite * 0.5 * (lb0 + ub0 ) +
197+ lb_finite * (~ ub_finite ) * (lb0 + 1.0 ) +
198+ (~ lb_finite ) * ub_finite * (ub0 - 1.0 ))
199+
200+ initial_values .append (init )
201+
202+ offset += var .size
203+ x0 = np .concatenate (initial_values , axis = 0 )
204+ return x0
171205
172206 class Oracles ():
173207 def __init__ (self , problem , inital_point ):
@@ -176,7 +210,7 @@ def __init__(self, problem, inital_point):
176210 self .initial_point = inital_point
177211 for var in self .problem .variables ():
178212 self .main_var .append (var )
179-
213+
180214 def objective (self , x ):
181215 """Returns the scalar value of the objective given x."""
182216 # Set the variable value
@@ -190,6 +224,8 @@ def objective(self, x):
190224 return obj_value
191225
192226 def gradient (self , x ):
227+ #import pdb
228+ #pdb.set_trace()
193229 """Returns the gradient of the objective with respect to x."""
194230 # compute the gradient using _grad
195231 offset = 0
@@ -214,6 +250,8 @@ def constraints(self, x):
214250 """Returns the constraint values."""
215251 # Set the variable value
216252 offset = 0
253+ #import pdb
254+ #pdb.set_trace()
217255 for var in self .main_var :
218256 size = var .size
219257 var .value = x [offset :offset + size ].reshape (var .shape , order = 'F' )
@@ -222,12 +260,13 @@ def constraints(self, x):
222260 # Evaluate all constraints
223261 constraint_values = []
224262 for constraint in self .problem .constraints :
225- constraint_values .append (np .asarray (constraint .args [0 ].value ).flatten ())
263+ constraint_values .append (np .asarray (constraint .args [0 ].value ).flatten (order = 'F' ))
226264 return np .concatenate (constraint_values )
227265
228266 def jacobian (self , x ):
229267 """Returns only the non-zero values of the Jacobian."""
230-
268+ #import pdb
269+ #pdb.set_trace()
231270 # Set variable values
232271 offset = 0
233272 for var in self .main_var :
@@ -245,7 +284,10 @@ def jacobian(self, x):
245284 jacobian = grad_dict [var ].T
246285 if sp .issparse (jacobian ):
247286 jacobian = sp .dok_matrix (jacobian )
248- data = np .array ([jacobian .get ((r , c ), 0 ) for r , c in zip (rows , cols )])
287+ data = np .array ([
288+ jacobian .get ((r , c ), 0 )
289+ for r , c in zip (rows , cols )
290+ ])
249291 values .append (np .atleast_1d (data ))
250292 else :
251293 values .append (np .atleast_1d (jacobian ))
@@ -328,12 +370,29 @@ def get_variable_bounds(self):
328370 for var in self .main_var :
329371 size = var .size
330372 if var .bounds :
331- var_lower .extend (var .bounds [0 ].flatten (order = 'F' ))
332- var_upper .extend (var .bounds [1 ].flatten (order = 'F' ))
373+ lb = var .bounds [0 ].flatten (order = 'F' )
374+ ub = var .bounds [1 ].flatten (order = 'F' )
375+
376+ if var .is_nonneg ():
377+ lb = np .maximum (lb , 0 )
378+
379+ if var .is_nonpos ():
380+ ub = np .minimum (ub , 0 )
381+
382+ var_lower .extend (lb )
383+ var_upper .extend (ub )
333384 else :
334- # No bounds specified, use infinite bounds
335- var_lower .extend ([- np .inf ] * size )
336- var_upper .extend ([np .inf ] * size )
385+ # No bounds specified, use infinite bounds or bounds
386+ # set by the nonnegative or nonpositive attribute
387+ if var .is_nonneg ():
388+ var_lower .extend ([0.0 ] * size )
389+ else :
390+ var_lower .extend ([- np .inf ] * size )
391+
392+ if var .is_nonpos ():
393+ var_upper .extend ([0.0 ] * size )
394+ else :
395+ var_upper .extend ([np .inf ] * size )
337396
338397 self .lb = np .array (var_lower )
339398 self .ub = np .array (var_upper )
0 commit comments