Skip to content

Commit b0c3450

Browse files
author
Norman_Tran
committed
Corrected handling of solution_loader. Implemented bounded constraint and writing to gms.
1 parent 89f80e0 commit b0c3450

File tree

3 files changed

+63
-27
lines changed

3 files changed

+63
-27
lines changed

pyomo/contrib/solver/solvers/gams.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,13 @@ def solve(self, model, **kwds):
594594
results.gams_termination_condition
595595
]
596596
obj = list(model.component_data_objects(Objective, active=True))
597-
assert len(obj) == 1, 'Only one objective is allowed.'
597+
598+
# NOTE: How should gams handle when no objective is provided
599+
# NOTE: pyomo/contrib/solver/tests/solvers/test_solvers.py::TestSolvers::test_no_objective
600+
# NOTE: results.incumbent_objective = None
601+
# NOTE: results.objective_bound = None
602+
# assert len(obj) == 1, 'Only one objective is allowed.'
603+
598604
if results.solution_status in {
599605
SolutionStatus.feasible,
600606
SolutionStatus.optimal,
@@ -605,7 +611,10 @@ def solve(self, model, **kwds):
605611

606612
if config.load_solutions:
607613
results.solution_loader.load_vars()
608-
results.incumbent_objective = stat_vars["OBJVAL"]
614+
if len(obj) == 1:
615+
results.incumbent_objective = stat_vars["OBJVAL"]
616+
else:
617+
results.incumbent_objective = None
609618
if (
610619
hasattr(model, 'dual')
611620
and isinstance(model.dual, Suffix)

pyomo/contrib/solver/solvers/gms_sol_reader.py

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,11 @@ def get_primals(
8181
if vars_to_load is None:
8282
vars_to_load = self._gms_info.var_symbol_map.bySymbol.items()
8383

84-
for sym, obj in vars_to_load:
85-
res[obj] = val_map[id(obj)]
84+
for sym, obj in vars_to_load:
85+
res[obj] = val_map[id(obj)]
86+
else:
87+
for obj in vars_to_load:
88+
res[obj] = val_map[id(obj)]
8689

8790
return res
8891

@@ -100,14 +103,22 @@ def get_duals(
100103
'check results.termination_condition and/or results.solution_status.'
101104
)
102105

103-
res = ComponentMap()
106+
con_map = {}
107+
if self._gdx_data is None:
108+
assert len(self._gms_info.con_symbol_map.bySymbol) == 0
109+
else:
110+
for sym, obj in self._gms_info.con_symbol_map.bySymbol.items():
111+
con_map[id(obj)] = self._gdx_data[sym][1]
104112

113+
res = ComponentMap()
105114
if cons_to_load is None:
106-
cons_to_load = set(self._gms_info.con_symbol_map.bySymbol.keys())
115+
cons_to_load = self._gms_info.con_symbol_map.bySymbol.items()
107116

108-
for sym, con in self._gms_info.con_symbol_map.bySymbol.items():
109-
if sym in cons_to_load and con.parent_component().ctype is not Objective:
110-
res[con] = self._gdx_data[sym][1]
117+
for sym, obj in cons_to_load:
118+
res[obj] = con_map[id(obj)]
119+
else:
120+
for obj in cons_to_load:
121+
res[obj] = con_map[id(obj)]
111122

112123
return res
113124

@@ -123,11 +134,21 @@ def get_reduced_costs(self, vars_to_load=None):
123134
'check results.termination_condition and/or results.solution_status.'
124135
)
125136

137+
var_map = {}
138+
if self._gdx_data is None:
139+
assert len(self._gms_info.var_symbol_map.bySymbol) == 0
140+
else:
141+
for sym, obj in self._gms_info.var_symbol_map.bySymbol.items():
142+
var_map[id(obj)] = self._gdx_data[sym][1]
143+
126144
res = ComponentMap()
127145
if vars_to_load is None:
128146
vars_to_load = self._gms_info.var_symbol_map.bySymbol.items()
129147

130-
for sym, obj in vars_to_load:
131-
res[obj] = self._gdx_data[sym][1]
148+
for sym, obj in vars_to_load:
149+
res[obj] = var_map[id(obj)]
150+
else:
151+
for obj in vars_to_load:
152+
res[obj] = var_map[id(obj)]
132153

133154
return res

pyomo/repn/plugins/gams_writer_v2.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,21 @@
3030
Param,
3131
Expression,
3232
SOSConstraint,
33-
SortComponents,
3433
Suffix,
3534
SymbolMap,
3635
minimize,
3736
ShortNameLabeler,
3837
)
39-
from pyomo.core.base.component import ActiveComponent
4038
from pyomo.core.base.label import NumericLabeler
4139
from pyomo.opt import WriterFactory
4240
from pyomo.repn.util import ftoa
4341

44-
# from pyomo.repn.quadratic import QuadraticRepnVisitor
4542
from pyomo.repn.linear import LinearRepnVisitor
4643
from pyomo.repn.util import (
4744
FileDeterminism,
4845
FileDeterminism_to_SortComponents,
4946
OrderedVarRecorder,
5047
categorize_valid_components,
51-
initialize_var_map_from_column_order,
52-
int_float,
5348
ordered_active_constraints,
5449
)
5550

@@ -444,7 +439,6 @@ def write(self, model):
444439

445440
con_symbol = con_labeler(con)
446441
declaration, definition, bounds = None, None, None
447-
448442
if lb is not None:
449443
if ub is None:
450444
label = f'{con_symbol}_lo'
@@ -463,10 +457,23 @@ def write(self, model):
463457
bounds = f' =E= {(lb - offset)!s};'
464458
con_list[label] = declaration + definition + bounds
465459
else:
466-
raise NotImplementedError(
467-
"Bounded constraints within the same expression is not supported"
468-
)
469-
460+
# We will need the constraint body twice.
461+
# Procedure is taken from lp_writer.py
462+
label = f'{con_symbol}_lo'
463+
self.con_symbol_map.addSymbol(con, label)
464+
self.var_symbol_map.addSymbol(con, label)
465+
declaration = f'\n{label}.. '
466+
definition = self.write_expression(ostream, repn)
467+
bounds = f' =G= {(lb - offset)!s};'
468+
con_list[label] = declaration + definition + bounds
469+
#
470+
label = f'{con_symbol}_hi'
471+
self.con_symbol_map.alias(con, label)
472+
self.var_symbol_map.alias(con, label)
473+
declaration = f'\n{label}.. '
474+
definition = self.write_expression(ostream, repn)
475+
bounds = f' =L= {(ub - offset)!s};'
476+
con_list[label] = declaration + definition + bounds
470477
elif ub is not None:
471478
label = f'{con_symbol}_hi'
472479
self.con_symbol_map.addSymbol(con, label)
@@ -549,14 +556,13 @@ def write(self, model):
549556
# Writing out the equations/constraints
550557
#
551558
ostream.write("EQUATIONS \n")
552-
for id, cid in enumerate(self.con_symbol_map.byObject.keys()):
553-
c = self.con_symbol_map.byObject[cid]
554-
if id != len(self.con_symbol_map.byObject.keys()) - 1:
555-
ostream.write(f"\t{c}\n")
559+
for count, (sym, con) in enumerate(con_list.items()):
560+
if count != len(con_list.keys()) - 1:
561+
ostream.write(f"\t{sym}\n")
556562
else:
557-
ostream.write(f"\t{c};\n\n")
563+
ostream.write(f"\t{sym};\n\n")
558564

559-
for con_label, con in con_list.items():
565+
for _, con in con_list.items():
560566
ostream.write(con)
561567

562568
#

0 commit comments

Comments
 (0)