@@ -120,6 +120,7 @@ def __init__(self, solver):
120
120
super (MAiNGOResults , self ).__init__ ()
121
121
self .wallclock_time = None
122
122
self .cpu_time = None
123
+ self .globally_optimal = None
123
124
self .solution_loader = MAiNGOSolutionLoader (solver = solver )
124
125
125
126
@@ -228,9 +229,14 @@ def solve(self, model, timer: HierarchicalTimer = None):
228
229
self ._last_results_object .solution_loader .invalidate ()
229
230
if timer is None :
230
231
timer = HierarchicalTimer ()
231
- timer .start ("set_instance" )
232
- self .set_instance (model )
233
- timer .stop ("set_instance" )
232
+ if model is not self ._model :
233
+ timer .start ("set_instance" )
234
+ self .set_instance (model )
235
+ timer .stop ("set_instance" )
236
+ else :
237
+ timer .start ("Update" )
238
+ self .update (timer = timer )
239
+ timer .stop ("Update" )
234
240
res = self ._solve (timer )
235
241
self ._last_results_object = res
236
242
if self .config .report_timing :
@@ -285,7 +291,7 @@ def _process_domain_and_bounds(self, var):
285
291
return lb , ub , vtype
286
292
287
293
def _add_variables (self , variables : List [_GeneralVarData ]):
288
- for ndx , var in enumerate ( variables ) :
294
+ for var in variables :
289
295
varname = self ._symbol_map .getSymbol (var , self ._labeler )
290
296
lb , ub , vtype = self ._process_domain_and_bounds (var )
291
297
self ._maingo_vars .append (
@@ -331,10 +337,11 @@ def set_instance(self, model):
331
337
con_list = self ._cons ,
332
338
objective = self ._objective ,
333
339
idmap = self ._pyomo_var_to_solver_var_id_map ,
340
+ logger = logger ,
334
341
)
335
342
336
343
def _add_constraints (self , cons : List [_GeneralConstraintData ]):
337
- self ._cons = cons
344
+ self ._cons + = cons
338
345
339
346
def _add_sos_constraints (self , cons : List [_SOSConstraintData ]):
340
347
if len (cons ) >= 1 :
@@ -344,7 +351,8 @@ def _add_sos_constraints(self, cons: List[_SOSConstraintData]):
344
351
pass
345
352
346
353
def _remove_constraints (self , cons : List [_GeneralConstraintData ]):
347
- pass
354
+ for con in cons :
355
+ self ._cons .remove (con )
348
356
349
357
def _remove_sos_constraints (self , cons : List [_SOSConstraintData ]):
350
358
if len (cons ) >= 1 :
@@ -354,28 +362,48 @@ def _remove_sos_constraints(self, cons: List[_SOSConstraintData]):
354
362
pass
355
363
356
364
def _remove_variables (self , variables : List [_GeneralVarData ]):
357
- pass
365
+ removed_maingo_vars = []
366
+ for var in variables :
367
+ varname = self ._symbol_map .getSymbol (var , self ._labeler )
368
+ del self ._maingo_vars [self ._pyomo_var_to_solver_var_id_map [id (var )]]
369
+ removed_maingo_vars += [self ._pyomo_var_to_solver_var_id_map [id (var )]]
370
+ del self ._pyomo_var_to_solver_var_id_map [id (var )]
371
+
372
+ for pyomo_var , maingo_var_id in self ._pyomo_var_to_solver_var_id_map .items ():
373
+ # How many variables before current var where removed?
374
+ num_removed = 0
375
+ for removed_var in removed_maingo_vars :
376
+ if removed_var <= maingo_var_id :
377
+ num_removed += 1
378
+ self ._pyomo_var_to_solver_var_id_map [pyomo_var ] = (
379
+ maingo_var_id - num_removed
380
+ )
358
381
359
382
def _remove_params (self , params : List [_ParamData ]):
360
383
pass
361
384
362
385
def _update_variables (self , variables : List [_GeneralVarData ]):
363
- pass
386
+ for var in variables :
387
+ if id (var ) not in self ._pyomo_var_to_solver_var_id_map :
388
+ raise ValueError (
389
+ 'The Var provided to update_var needs to be added first: {0}' .format (
390
+ var
391
+ )
392
+ )
393
+ lb , ub , vtype = self ._process_domain_and_bounds (var )
394
+ self ._maingo_vars [self ._pyomo_var_to_solver_var_id_map [id (var )]] = (
395
+ MaingoVar (name = var .name , type = vtype , lb = lb , ub = ub , init = var .value )
396
+ )
364
397
365
398
def update_params (self ):
366
- pass
399
+ vars = [var [0 ] for var in self ._vars .values ()]
400
+ self ._update_variables (vars )
367
401
368
402
def _set_objective (self , obj ):
369
- if obj is None :
370
- raise NotImplementedError (
371
- "MAiNGO needs a objective. Please set a dummy objective."
372
- )
373
- else :
374
- if not obj .sense in {minimize , maximize }:
375
- raise ValueError (
376
- "Objective sense is not recognized: {0}" .format (obj .sense )
377
- )
378
- self ._objective = obj
403
+
404
+ if not obj .sense in {minimize , maximize }:
405
+ raise ValueError ("Objective sense is not recognized: {0}" .format (obj .sense ))
406
+ self ._objective = obj
379
407
380
408
def _postsolve (self , timer : HierarchicalTimer ):
381
409
config = self .config
@@ -388,7 +416,9 @@ def _postsolve(self, timer: HierarchicalTimer):
388
416
389
417
if status in {maingopy .GLOBALLY_OPTIMAL , maingopy .FEASIBLE_POINT }:
390
418
results .termination_condition = TerminationCondition .optimal
419
+ results .globally_optimal = True
391
420
if status == maingopy .FEASIBLE_POINT :
421
+ results .globally_optimal = False
392
422
logger .warning (
393
423
"MAiNGO did only find a feasible solution but did not prove its global optimality."
394
424
)
@@ -425,8 +455,8 @@ def _postsolve(self, timer: HierarchicalTimer):
425
455
426
456
timer .start ("load solution" )
427
457
if config .load_solution :
428
- if not results .best_feasible_objective is None :
429
- if results .termination_condition != TerminationCondition . optimal :
458
+ if results .termination_condition is TerminationCondition . optimal :
459
+ if not results .globally_optimal :
430
460
logger .warning (
431
461
"Loading a feasible but suboptimal solution. "
432
462
"Please set load_solution=False and check "
@@ -487,6 +517,15 @@ def get_reduced_costs(self, vars_to_load=None):
487
517
def get_duals (self , cons_to_load = None ):
488
518
raise ValueError ("MAiNGO does not support returning Duals" )
489
519
520
+ def update (self , timer : HierarchicalTimer = None ):
521
+ super (MAiNGO , self ).update (timer = timer )
522
+ self ._solver_model = maingo_solvermodel .SolverModel (
523
+ var_list = self ._maingo_vars ,
524
+ con_list = self ._cons ,
525
+ objective = self ._objective ,
526
+ idmap = self ._pyomo_var_to_solver_var_id_map ,
527
+ logger = logger ,
528
+ )
490
529
491
530
def _set_maingo_options (self ):
492
531
pass
0 commit comments