diff --git a/.github/workflows/test_branches.yml b/.github/workflows/test_branches.yml index f1d98bd723e..eab15313df4 100644 --- a/.github/workflows/test_branches.yml +++ b/.github/workflows/test_branches.yml @@ -445,6 +445,8 @@ jobs: echo "DYLD_LIBRARY_PATH=${env:DYLD_LIBRARY_PATH}:$GAMS_DIR" ` Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append $INSTALLER = "${env:DOWNLOAD_DIR}/gams_install.exe" + # We are pinning to 29.1.0 because a license is required for + # versions after this in order to run in demo mode. $URL = "https://d37drm4t2jghv5.cloudfront.net/distributions/29.1.0" if ( "${{matrix.TARGET}}" -eq "win" ) { $URL = "$URL/windows/windows_x64_64.exe" diff --git a/.github/workflows/test_pr_and_main.yml b/.github/workflows/test_pr_and_main.yml index 32c67747aa9..9a8888cef1c 100644 --- a/.github/workflows/test_pr_and_main.yml +++ b/.github/workflows/test_pr_and_main.yml @@ -463,6 +463,8 @@ jobs: echo "DYLD_LIBRARY_PATH=${env:DYLD_LIBRARY_PATH}:$GAMS_DIR" ` Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append $INSTALLER = "${env:DOWNLOAD_DIR}/gams_install.exe" + # We are pinning to 29.1.0 because a license is required for + # versions after this in order to run in demo mode. $URL = "https://d37drm4t2jghv5.cloudfront.net/distributions/29.1.0" if ( "${{matrix.TARGET}}" -eq "win" ) { $URL = "$URL/windows/windows_x64_64.exe" diff --git a/pyomo/repn/plugins/gams_writer.py b/pyomo/repn/plugins/gams_writer.py index d16d65d6c54..7dc827f0aed 100644 --- a/pyomo/repn/plugins/gams_writer.py +++ b/pyomo/repn/plugins/gams_writer.py @@ -308,6 +308,27 @@ def split_long_line(line): return new_lines +class GAMSSymbolMap(SymbolMap): + def __init__(self, var_labeler, var_list): + super().__init__(self.var_label) + self.var_labeler = var_labeler + self.var_list = var_list + + def var_label(self, obj): + # if obj.is_fixed(): + # return str(value(obj)) + return self.getSymbol(obj, self.var_recorder) + + def var_recorder(self, obj): + ans = self.var_labeler(obj) + try: + if obj.is_variable_type(): + self.var_list.append(ans) + except: + pass + return ans + + @WriterFactory.register('gams', 'Generate the corresponding GAMS file') class ProblemWriter_gams(AbstractProblemWriter): def __init__(self): @@ -492,21 +513,7 @@ def __call__(self, model, output_filename, solver_capability, io_options): var_list = [] - def var_recorder(obj): - ans = var_labeler(obj) - try: - if obj.is_variable_type(): - var_list.append(ans) - except: - pass - return ans - - def var_label(obj): - # if obj.is_fixed(): - # return str(value(obj)) - return symbolMap.getSymbol(obj, var_recorder) - - symbolMap = SymbolMap(var_label) + symbolMap = GAMSSymbolMap(var_labeler, var_list) # when sorting, there are a non-trivial number of # temporary objects created. these all yield @@ -527,7 +534,7 @@ def var_label(obj): output_file=output_file, solver_capability=solver_capability, var_list=var_list, - var_label=var_label, + var_label=symbolMap.var_label, symbolMap=symbolMap, con_labeler=con_labeler, sort=sort, diff --git a/pyomo/solvers/tests/checks/test_pickle.py b/pyomo/solvers/tests/checks/test_pickle.py index d8551b34740..567de3dd8d3 100644 --- a/pyomo/solvers/tests/checks/test_pickle.py +++ b/pyomo/solvers/tests/checks/test_pickle.py @@ -169,7 +169,15 @@ def return_test(self): for key, value in generate_scenarios(lambda c: c.test_pickling): model, solver, io = key cls = driver[model] - + # July 19, 2023: There is an issue with certain GAMS cases that is + # causing failures. This is not universal, however, so we cannot add + # the cases directly to testcases.py. + if ( + (solver == 'gams') + and (io in ['gms', 'python']) + and ('.LP_simple_kernel' in str(value.model)) + ): + value.status = 'expected failure' # Symbolic labels test_name = "test_" + solver + "_" + io + "_symbolic_labels" test_method = create_method(model, solver, io, value, True) diff --git a/pyomo/solvers/tests/solvers.py b/pyomo/solvers/tests/solvers.py index 328523a687c..6bbfe08c7c7 100644 --- a/pyomo/solvers/tests/solvers.py +++ b/pyomo/solvers/tests/solvers.py @@ -9,7 +9,7 @@ # This software is distributed under the 3-clause BSD License. # ___________________________________________________________________________ -__all__ = ['test_solver_cases', 'available_solvers'] +__all__ = ['test_solver_cases'] import logging diff --git a/pyomo/solvers/tests/testcases.py b/pyomo/solvers/tests/testcases.py index c7d7c01ce1d..eaebbcd9003 100644 --- a/pyomo/solvers/tests/testcases.py +++ b/pyomo/solvers/tests/testcases.py @@ -108,6 +108,26 @@ # NO EXPECTED FAILURES # +# +# GAMS +# + +ExpectedFailures['gams', 'gms', 'MILP_unbounded'] = ( + lambda v: v <= _trunk_version, + "GAMS requires finite bounds for integer variables. 1.0E100 is as extreme" + "as GAMS will define, and should be enough to appear unbounded. If the" + "solver cannot handle this bound, explicitly set a smaller bound on" + "the pyomo model, or try a different GAMS solver.", +) + +ExpectedFailures['gams', 'python', 'MILP_unbounded'] = ( + lambda v: v <= _trunk_version, + "GAMS requires finite bounds for integer variables. 1.0E100 is as extreme" + "as GAMS will define, and should be enough to appear unbounded. If the" + "solver cannot handle this bound, explicitly set a smaller bound on" + "the pyomo model, or try a different GAMS solver.", +) + # # GLPK # @@ -261,83 +281,6 @@ 'BARON 22.1.19 reports model as optimal', ) -# -# The following were necessary before we started adding the 'WantDual' -# option when a user explicitly defines a 'dual' or 'rc' suffix to -# "force" Baron to run a local solve (if necessary) and always return -# dual nformation. -# - -# # Known to fail through 18.11.15, but was resolved by 19.12.7 -# ExpectedFailures['baron', 'bar', 'MILP_unbounded'] = ( -# lambda v: v <= (18,11,15), -# ['dual'], -# "Baron fails to report a MILP model as unbounded") - -# # Known to work through 18.11.15, and fail in 19.12.7 -# MissingSuffixFailures['baron', 'bar', 'LP_piecewise'] = ( -# lambda v: v <= (15,0,0,0) or v > (18,11,15), -# ['dual'], -# "Baron will not return dual solution when a solution is " -# "found during preprocessing.") - -# # Marking this test suffixes as fragile: Baron 20.4.14 will -# # intermittently return suffixes. -# MissingSuffixFailures['baron', 'bar', 'QP_simple'] = ( -# lambda v: v <= (15,2,0,0) or v > (18,11,15), -# {'dual': (False, {}), 'rc': (False, {})}, -# "Baron will intermittently return dual solution when " -# "a solution is found during preprocessing.") - -# # Known to fail through 17.4.1, but was resolved by 18.5.9 -# MissingSuffixFailures['baron', 'bar', 'QCP_simple'] = ( -# lambda v: v <= (17,4,1) or v > (18,11,15), -# ['dual','rc'], -# "Baron will not return dual solution when a solution is " -# "found during preprocessing.") - -# # Known to work through 18.11.15, and fail in 19.12.7 -# MissingSuffixFailures['baron', 'bar', 'LP_block'] = ( -# lambda v: v > (18,11,15), -# ['dual'], -# "Baron will not return dual solution when a solution is " -# "found during preprocessing.") - -# # Known to work through 18.11.15, and fail in 19.12.7 -# MissingSuffixFailures['baron', 'bar', 'LP_inactive_index'] = ( -# lambda v: v > (18,11,15), -# ['dual'], -# "Baron will not return dual solution when a solution is " -# "found during preprocessing.") - -# # Known to work through 18.11.15, and fail in 19.12.7 -# MissingSuffixFailures['baron', 'bar', 'LP_simple'] = ( -# lambda v: v > (18,11,15), -# ['dual'], -# "Baron will not return dual solution when a solution is " -# "found during preprocessing.") - -# # Known to work through 18.11.15, and fail in 19.12.7 -# MissingSuffixFailures['baron', 'bar', 'LP_trivial_constraints'] = ( -# lambda v: v > (18,11,15), -# ['dual'], -# "Baron will not return dual solution when a solution is " -# "found during preprocessing.") - -# # Known to work through 19.12.7, and fail in 20.4.14 -# MissingSuffixFailures['baron', 'bar', 'LP_duals_minimize'] = ( -# lambda v: v > (19,12,7), -# ['dual','rc'], -# "Baron will not return dual solution when a solution is " -# "found during preprocessing.") - -# # Known to work through 19.12.7, and fail in 20.4.14 -# MissingSuffixFailures['baron', 'bar', 'LP_duals_maximize'] = ( -# lambda v: v > (19,12,7), -# ['dual','rc'], -# "Baron will not return dual solution when a solution is " -# "found during preprocessing.") - # # KNITROAMPL