diff --git a/pyomo/solvers/plugins/solvers/GAMS.py b/pyomo/solvers/plugins/solvers/GAMS.py index 40c40921d72..1a8307c4dbd 100644 --- a/pyomo/solvers/plugins/solvers/GAMS.py +++ b/pyomo/solvers/plugins/solvers/GAMS.py @@ -40,8 +40,27 @@ ) from pyomo.common.dependencies import attempt_import +import struct -gdxcc, gdxcc_available = attempt_import('gdxcc') + +def _gams_importer(): + try: + import gams.core.gdx as gdx + + return gdx + except ImportError: + try: + # fall back to the pre-GAMS-45.0 API + import gdxcc + + return gdxcc + except: + # suppress the error from the old API and reraise the current API import error + pass + raise + + +gdxcc, gdxcc_available = attempt_import('gdxcc', importer=_gams_importer) logger = logging.getLogger('pyomo.solvers') @@ -728,18 +747,6 @@ def _get_version(self): ) return _extract_version(results.stdout) - @staticmethod - def _parse_special_values(value): - if value == 1.0e300 or value == 2.0e300: - return float('nan') - if value == 3.0e300: - return float('inf') - if value == 4.0e300: - return -float('inf') - if value == 5.0e300: - return sys.float_info.epsilon - return value - def _rewrite_path_win8p3(self, path): """ Return the 8.3 short path on Windows; unchanged elsewhere. @@ -1278,6 +1285,18 @@ def _parse_gdx_results(self, results_filename, statresults_filename): if not ret[0]: raise RuntimeError("GAMS GDX failure (gdxOpenRead): %d." % ret[1]) + specVals = gdxcc.doubleArray(gdxcc.GMS_SVIDX_MAX) + rc = gdxcc.gdxGetSpecialValues(pgdx, specVals) + + specVals[gdxcc.GMS_SVIDX_EPS] = sys.float_info.min + specVals[gdxcc.GMS_SVIDX_UNDEF] = float("nan") + specVals[gdxcc.GMS_SVIDX_PINF] = float("inf") + specVals[gdxcc.GMS_SVIDX_MINF] = float("-inf") + specVals[gdxcc.GMS_SVIDX_NA] = struct.unpack( + ">d", bytes.fromhex("fffffffffffffffe") + )[0] + gdxcc.gdxSetSpecialValues(pgdx, specVals) + i = 0 while True: i += 1 @@ -1299,7 +1318,7 @@ def _parse_gdx_results(self, results_filename, statresults_filename): raise RuntimeError("GAMS GDX failure (gdxDataReadRaw).") if stat in ('OBJEST', 'OBJVAL', 'ETSOLVE'): - stat_vars[stat] = self._parse_special_values(ret[2][0]) + stat_vars[stat] = ret[2][0] else: stat_vars[stat] = int(ret[2][0]) @@ -1311,6 +1330,18 @@ def _parse_gdx_results(self, results_filename, statresults_filename): if not ret[0]: raise RuntimeError("GAMS GDX failure (gdxOpenRead): %d." % ret[1]) + specVals = gdxcc.doubleArray(gdxcc.GMS_SVIDX_MAX) + rc = gdxcc.gdxGetSpecialValues(pgdx, specVals) + + specVals[gdxcc.GMS_SVIDX_EPS] = sys.float_info.min + specVals[gdxcc.GMS_SVIDX_UNDEF] = float("nan") + specVals[gdxcc.GMS_SVIDX_PINF] = float("inf") + specVals[gdxcc.GMS_SVIDX_MINF] = float("-inf") + specVals[gdxcc.GMS_SVIDX_NA] = struct.unpack( + ">d", bytes.fromhex("fffffffffffffffe") + )[0] + gdxcc.gdxSetSpecialValues(pgdx, specVals) + i = 0 while True: i += 1 @@ -1321,8 +1352,8 @@ def _parse_gdx_results(self, results_filename, statresults_filename): ret = gdxcc.gdxDataReadRaw(pgdx) if not ret[0] or len(ret[2]) < 2: raise RuntimeError("GAMS GDX failure (gdxDataReadRaw).") - level = self._parse_special_values(ret[2][0]) - dual = self._parse_special_values(ret[2][1]) + level = ret[2][0] + dual = ret[2][1] ret = gdxcc.gdxSymbolInfo(pgdx, i) if not ret[0]: @@ -1335,6 +1366,7 @@ def _parse_gdx_results(self, results_filename, statresults_filename): gdxcc.gdxClose(pgdx) gdxcc.gdxFree(pgdx) + gdxcc.gdxLibraryUnload() return model_soln, stat_vars def _parse_dat_results(self, results_filename, statresults_filename):