diff --git a/.github/workflows/test_pr_and_main.yml b/.github/workflows/test_pr_and_main.yml index 2e96054c3..cd9e75cec 100644 --- a/.github/workflows/test_pr_and_main.yml +++ b/.github/workflows/test_pr_and_main.yml @@ -310,6 +310,34 @@ jobs: python test_pickle_bundle.py + mps: + name: MPS tests + runs-on: ubuntu-latest + needs: [ruff] + + steps: + - uses: actions/checkout@v3 + - uses: conda-incubator/setup-miniconda@v2 + with: + activate-environment: test_env + python-version: 3.11 + auto-activate-base: false + - name: Install dependencies + run: | + conda install mpi4py pandas setuptools + pip install pyomo xpress cplex mip + + - name: setup the program + run: | + pip install -e . + + - name: run MPS tests + timeout-minutes: 2 + run: | + cd mpisppy/tests + python test_mps.py + + confidence-intervals: name: confidence intervals tests runs-on: ubuntu-latest @@ -494,7 +522,7 @@ jobs: timeout-minutes: 10 run: | cd mpisppy/tests - mpiexec -np 2 python -m mpi4py test_with_cylinders.py + mpiexec -np 2 python -m mpi4py test_with_cylinders.py test-agnostic: name: tests on agnostic diff --git a/doc/src/agnostic.rst b/doc/src/agnostic.rst index ea397a7d4..fd0aec27c 100644 --- a/doc/src/agnostic.rst +++ b/doc/src/agnostic.rst @@ -4,7 +4,34 @@ AML Agnosticism The mpi-sppy package provides callouts so that algebraic modeling languages (AMLs) other than Pyomo can be used. A growing number of AMLs are supported as `guest` languages (we refer to mpi-sppy as the `host`). This code is -in an alpha-release state; use with extreme caution. +in an alpha-release state; use with extreme caution. This is referred to +as `tight` integration with the guest. It is also possible to simply read +scenario data from an mps file and the mps file (and the associated json +nonant file) that can be created however you like. + +Loose integration +^^^^^^^^^^^^^^^^^ + +Code for creating a +Pyomo model from an mps file is in ``mpisppy.utils.mps_reader.py``, +but you can also just use ``generic_cylinders.py`` and give +it the module ``mpisppy.utils.mps_module`` (you will need to specify +that path to this module) and the ``--mps-files-directory`` +option. Note +that at the time of this writing, the number of scenarios is obtained +by counting the mps files in the directory given. + +The file ``examples.sizes.mps_demo.bash`` has two commands. The second illustrates +how to instruction ``MPI-SPPY`` to read mps/json file pairs for each scenario from a +directory. The first command illustrates how to use ``MPI-SPPY`` to write +them in the first place (but if ``MPI-SPPY`` can get your scenarios, there +is probably no reason to write them and then read them again!). This +functionality is intended to be used by users of other AMLs or other +scenario-based stochastic programming applications. + + +Tight integration +^^^^^^^^^^^^^^^^^ From the end-user's perspective ------------------------------- diff --git a/doc/src/extensions.rst b/doc/src/extensions.rst index 1c0df836e..a4aae4d47 100644 --- a/doc/src/extensions.rst +++ b/doc/src/extensions.rst @@ -274,11 +274,17 @@ If some variables have zero probability in all scenarios, then you will need to all variable probabilities! So you might want to set this to False to verify that the probabilities sum to one only for the Vars you expect before setting it to True. -Scenario_lpwriter ------------------ - -This extension writes an lp file with the model and json file with (a) list(s) of -scenario tree node names and nonanticaptive variables for each scenario before -the iteration zero solve of PH or APH. Note that for two-stage problems, all -json files will be the same. See ``mpisppy.generic_cylinders.py`` -for an example of use. +Scenario_lp_mps_writer +---------------------- + +This extension writes an lp file and an mps file with the model as well as a +json file with (a) list(s) of scenario tree node names and +nonanticaptive variables for each scenario before the iteration zero +solve of PH or APH. Note that for two-stage problems, all json files +will be the same. See ``mpisppy.generic_cylinders.py`` for an example +of use. In that program it is activated with the +``--scenario-lp-mps-writer`` option. Note that it +writes the files to the current working directory and for each scenario +the base name of the three files written is the scenario name. + +Unless you know exactly why you need this, you probably don't. diff --git a/examples/generic_tester.py b/examples/generic_tester.py index b06866b2d..4329d4e42 100644 --- a/examples/generic_tester.py +++ b/examples/generic_tester.py @@ -177,12 +177,19 @@ def do_one(dirname, modname, np, argstring, xhat_baseline_dir=None, tol=1e-6): #rebaseline_xhat("farmer", "farmer", 3, farmer_rd, "test_data/farmer_rd_baseline") do_one("farmer", "farmer", 3, farmer_rd, xhat_baseline_dir="test_data/farmer_rd_baseline") -# Just a smoke test to make sure sizes_expression still exists and -# that lpfiles still executes. +### combined runs to test mps files #### +# Make sure sizes_expression still exists and lpfiles still executes. sizese = ("--module-name sizes_expression --num-scens 3 --default-rho 1" f" --solver-name {solver_name} --max-iterations 0" - " --scenario-lpfiles") -do_one("sizes", "sizes", 3, sizese, xhat_baseline_dir=None) + " --write-scenario-lp-mps-files") +do_one("sizes", "sizes_expression", 3, sizese, xhat_baseline_dir=None) +# just smoke for now +sizesMPS = ("--module-name ../../mpisppy/utils/mps_module --default-rho 1" + f" --solver-name {solver_name} --max-iterations 0" + " --mps-files-directory=.") # we will be in the sizes dir +do_one("sizes", "../../mpisppy/utils/mps_module", 1, sizesMPS, xhat_baseline_dir=None) + +### end combined mps file runs ### quit() diff --git a/examples/sizes/mps_demo.bash b/examples/sizes/mps_demo.bash new file mode 100644 index 000000000..50dd6fd48 --- /dev/null +++ b/examples/sizes/mps_demo.bash @@ -0,0 +1,23 @@ +#!/bin/bash +# This is mainly to demonstrate what loose agnostic files look like and +# how to use them with agnostic_cylinders.py. +# To do that, we write the files based on a Pyomo model, then +# read them in. +# Note: if you actually have a Pyomo model, you probably don't want to do +# it this way since you would have had to have written most of the +# functions (e.g. scenario_creator) anyway. +# If you are using some other AML, then you migth want to use the second +# command line to read the files you wrote with your AML and +# you can use the first command to write files as an example of the format +# for the json files. + +set -e + +SOLVER=cplex + +# assumes we are in the sizes directory and don't mind polluting it with 6 files +python ../../mpisppy/generic_cylinders.py --module-name sizes_expression --num-scens 3 --default-rho 1 --solver-name ${SOLVER} --max-iterations 0 --scenario-lp-mps-files + +# By specifying the module to be mps_module we will read files for the problem +# from the specified mps-files-directory. +mpiexec -np 3 python -m mpi4py ../../mpisppy/generic_cylinders.py --module-name ../../mpisppy/utils/mps_module --xhatshuffle --lagrangian --default-rho 1 --solver-name ${SOLVER} --max-iterations 10 --mps-files-directory=. diff --git a/mpisppy/extensions/scenario_lpfiles.py b/mpisppy/extensions/scenario_lp_mps_files.py similarity index 63% rename from mpisppy/extensions/scenario_lpfiles.py rename to mpisppy/extensions/scenario_lp_mps_files.py index b1dbf2e89..807e623c1 100644 --- a/mpisppy/extensions/scenario_lpfiles.py +++ b/mpisppy/extensions/scenario_lp_mps_files.py @@ -17,12 +17,11 @@ def lpize(varname): - # convert varname to the string that will appear in the lp file - # return varname.replace("[", "(").replace("]", ")").replace(",", "_").replace(".","_") + # convert varname to the string that will appear in the lp and mps files return pyomo_label.cpxlp_label_from_name(varname) -class Scenario_lpfiles(mpisppy.extensions.extension.Extension): +class Scenario_lp_mps_files(mpisppy.extensions.extension.Extension): def __init__(self, ph): self.ph = ph @@ -30,9 +29,16 @@ def __init__(self, ph): def pre_iter0(self): for k, s in self.ph.local_subproblems.items(): s.write(f"{k}.lp", io_options={'symbolic_solver_labels': True}) - nonants_by_node = {nd.name: [lpize(var.name) for var in nd.nonant_vardata_list] for nd in s._mpisppy_node_list} + s.write(f"{k}.mps", io_options={'symbolic_solver_labels': True}) + scenData = {"name": s.name, "scenProb": s._mpisppy_probability} + scenDict = {"scenarioData": scenData} + treeData = dict() + for nd in s._mpisppy_node_list: + treeData[nd.name] = {"condProb": nd.cond_prob} + treeData[nd.name].update({"nonAnts": [lpize(var.name) for var in nd.nonant_vardata_list]}) + scenDict["treeData"] = treeData with open(f"{k}_nonants.json", "w") as jfile: - json.dump(nonants_by_node, jfile) + json.dump(scenDict, jfile, indent=2) def post_iter0(self): return diff --git a/mpisppy/generic_cylinders.py b/mpisppy/generic_cylinders.py index 91c176a1e..f39199e0c 100644 --- a/mpisppy/generic_cylinders.py +++ b/mpisppy/generic_cylinders.py @@ -29,7 +29,7 @@ from mpisppy.extensions.fixer import Fixer from mpisppy.extensions.mipgapper import Gapper from mpisppy.extensions.gradient_extension import Gradient_extension -from mpisppy.extensions.scenario_lpfiles import Scenario_lpfiles +from mpisppy.extensions.scenario_lp_mps_files import Scenario_lp_mps_files from mpisppy.utils.wxbarwriter import WXBarWriter from mpisppy.utils.wxbarreader import WXBarReader @@ -55,8 +55,8 @@ def _parse_args(m): description="The string used for a directory of ouput along with a csv and an npv file (default None, which means no soltion output)", domain=str, default=None) - cfg.add_to_config(name="scenario_lpfiles", - description="Invokes an extension that writes an model lp file and a nonants json file for each scenario before iteration 0", + cfg.add_to_config(name="write_scenario_lp_mps_files", + description="Invokes an extension that writes an model lp file, mps file and a nonants json file for each scenario before iteration 0", domain=bool, default=False) @@ -64,6 +64,8 @@ def _parse_args(m): # many models, e.g., farmer, need num_scens_required # in which case, it should go in the inparser_adder function # cfg.num_scens_required() + # On the other hand, this program really wants cfg.num_scens somehow so + # maybe it should just require it. cfg.EF_base() # If EF is slected, most other options will be moot # There are some arguments here that will not make sense for all models @@ -120,7 +122,7 @@ def _name_lists(module, cfg, bundle_wrapper=None): "For now, stage2EFsolvern is required for multistage xhat" else: all_nodenames = None - num_scens = cfg.num_scens + num_scens = cfg.get("num_scens") # maybe None is OK # proper bundles should be almost magic if cfg.unpickle_bundles_dir or cfg.scenarios_per_bundle is not None: @@ -230,8 +232,8 @@ def _do_decomp(module, cfg, scenario_creator, scenario_creator_kwargs, scenario_ ext_classes.append(Gradient_extension) hub_dict['opt_kwargs']['options']['gradient_extension_options'] = {'cfg': cfg} - if cfg.scenario_lpfiles: - ext_classes.append(Scenario_lpfiles) + if cfg.write_scenario_lp_mps_files: + ext_classes.append(Scenario_lp_mps_files) if cfg.W_and_xbar_reader: ext_classes.append(WXBarReader) diff --git a/mpisppy/spbase.py b/mpisppy/spbase.py index 11479e824..ba1c328b3 100644 --- a/mpisppy/spbase.py +++ b/mpisppy/spbase.py @@ -105,7 +105,8 @@ def __init__( global_toc("Initializing SPBase") if self.n_proc > len(self.all_scenario_names): - raise RuntimeError("More ranks than scenarios") + raise RuntimeError(f"More ranks ({self.n_proc}) than scenarios" + f" ({len(self.all_scenario_names)})") self._calculate_scenario_ranks() # Put the deprecation message in the init so they should only see it once per rank diff --git a/mpisppy/tests/examples/sizes1.mps b/mpisppy/tests/examples/sizes1.mps new file mode 100644 index 000000000..13f3ebb2a --- /dev/null +++ b/mpisppy/tests/examples/sizes1.mps @@ -0,0 +1,911 @@ +* Source: Pyomo MPS Writer +* Format: Free MPS +* +NAME unknown +OBJSENSE + MIN +ROWS + N Total_Cost_Objective + G c_l_DemandSatisfiedFirstStage(1)_ + G c_l_DemandSatisfiedFirstStage(2)_ + G c_l_DemandSatisfiedFirstStage(3)_ + G c_l_DemandSatisfiedFirstStage(4)_ + G c_l_DemandSatisfiedFirstStage(5)_ + G c_l_DemandSatisfiedFirstStage(6)_ + G c_l_DemandSatisfiedFirstStage(7)_ + G c_l_DemandSatisfiedFirstStage(8)_ + G c_l_DemandSatisfiedFirstStage(9)_ + G c_l_DemandSatisfiedFirstStage(10)_ + G c_l_DemandSatisfiedSecondStage(1)_ + G c_l_DemandSatisfiedSecondStage(2)_ + G c_l_DemandSatisfiedSecondStage(3)_ + G c_l_DemandSatisfiedSecondStage(4)_ + G c_l_DemandSatisfiedSecondStage(5)_ + G c_l_DemandSatisfiedSecondStage(6)_ + G c_l_DemandSatisfiedSecondStage(7)_ + G c_l_DemandSatisfiedSecondStage(8)_ + G c_l_DemandSatisfiedSecondStage(9)_ + G c_l_DemandSatisfiedSecondStage(10)_ + L c_u_EnforceProductionBinaryFirstStage(1)_ + L c_u_EnforceProductionBinaryFirstStage(2)_ + L c_u_EnforceProductionBinaryFirstStage(3)_ + L c_u_EnforceProductionBinaryFirstStage(4)_ + L c_u_EnforceProductionBinaryFirstStage(5)_ + L c_u_EnforceProductionBinaryFirstStage(6)_ + L c_u_EnforceProductionBinaryFirstStage(7)_ + L c_u_EnforceProductionBinaryFirstStage(8)_ + L c_u_EnforceProductionBinaryFirstStage(9)_ + L c_u_EnforceProductionBinaryFirstStage(10)_ + L c_u_EnforceProductionBinarySecondStage(1)_ + L c_u_EnforceProductionBinarySecondStage(2)_ + L c_u_EnforceProductionBinarySecondStage(3)_ + L c_u_EnforceProductionBinarySecondStage(4)_ + L c_u_EnforceProductionBinarySecondStage(5)_ + L c_u_EnforceProductionBinarySecondStage(6)_ + L c_u_EnforceProductionBinarySecondStage(7)_ + L c_u_EnforceProductionBinarySecondStage(8)_ + L c_u_EnforceProductionBinarySecondStage(9)_ + L c_u_EnforceProductionBinarySecondStage(10)_ + L c_u_EnforceCapacityLimitFirstStage_ + L c_u_EnforceCapacityLimitSecondStage_ + L c_u_EnforceInventoryFirstStage(1)_ + L c_u_EnforceInventoryFirstStage(2)_ + L c_u_EnforceInventoryFirstStage(3)_ + L c_u_EnforceInventoryFirstStage(4)_ + L c_u_EnforceInventoryFirstStage(5)_ + L c_u_EnforceInventoryFirstStage(6)_ + L c_u_EnforceInventoryFirstStage(7)_ + L c_u_EnforceInventoryFirstStage(8)_ + L c_u_EnforceInventoryFirstStage(9)_ + L c_u_EnforceInventoryFirstStage(10)_ + L c_u_EnforceInventorySecondStage(1)_ + L c_u_EnforceInventorySecondStage(2)_ + L c_u_EnforceInventorySecondStage(3)_ + L c_u_EnforceInventorySecondStage(4)_ + L c_u_EnforceInventorySecondStage(5)_ + L c_u_EnforceInventorySecondStage(6)_ + L c_u_EnforceInventorySecondStage(7)_ + L c_u_EnforceInventorySecondStage(8)_ + L c_u_EnforceInventorySecondStage(9)_ + L c_u_EnforceInventorySecondStage(10)_ +COLUMNS + ProduceSizeFirstStage(1) Total_Cost_Objective 453 + ProduceSizeFirstStage(1) c_u_EnforceProductionBinaryFirstStage(1)_ -200000 + ProduceSizeFirstStage(2) Total_Cost_Objective 453 + ProduceSizeFirstStage(2) c_u_EnforceProductionBinaryFirstStage(2)_ -200000 + ProduceSizeFirstStage(3) Total_Cost_Objective 453 + ProduceSizeFirstStage(3) c_u_EnforceProductionBinaryFirstStage(3)_ -200000 + ProduceSizeFirstStage(4) Total_Cost_Objective 453 + ProduceSizeFirstStage(4) c_u_EnforceProductionBinaryFirstStage(4)_ -200000 + ProduceSizeFirstStage(5) Total_Cost_Objective 453 + ProduceSizeFirstStage(5) c_u_EnforceProductionBinaryFirstStage(5)_ -200000 + ProduceSizeFirstStage(6) Total_Cost_Objective 453 + ProduceSizeFirstStage(6) c_u_EnforceProductionBinaryFirstStage(6)_ -200000 + ProduceSizeFirstStage(7) Total_Cost_Objective 453 + ProduceSizeFirstStage(7) c_u_EnforceProductionBinaryFirstStage(7)_ -200000 + ProduceSizeFirstStage(8) Total_Cost_Objective 453 + ProduceSizeFirstStage(8) c_u_EnforceProductionBinaryFirstStage(8)_ -200000 + ProduceSizeFirstStage(9) Total_Cost_Objective 453 + ProduceSizeFirstStage(9) c_u_EnforceProductionBinaryFirstStage(9)_ -200000 + ProduceSizeFirstStage(10) Total_Cost_Objective 453 + ProduceSizeFirstStage(10) c_u_EnforceProductionBinaryFirstStage(10)_ -200000 + ProduceSizeSecondStage(1) Total_Cost_Objective 453 + ProduceSizeSecondStage(1) c_u_EnforceProductionBinarySecondStage(1)_ -200000 + ProduceSizeSecondStage(2) Total_Cost_Objective 453 + ProduceSizeSecondStage(2) c_u_EnforceProductionBinarySecondStage(2)_ -200000 + ProduceSizeSecondStage(3) Total_Cost_Objective 453 + ProduceSizeSecondStage(3) c_u_EnforceProductionBinarySecondStage(3)_ -200000 + ProduceSizeSecondStage(4) Total_Cost_Objective 453 + ProduceSizeSecondStage(4) c_u_EnforceProductionBinarySecondStage(4)_ -200000 + ProduceSizeSecondStage(5) Total_Cost_Objective 453 + ProduceSizeSecondStage(5) c_u_EnforceProductionBinarySecondStage(5)_ -200000 + ProduceSizeSecondStage(6) Total_Cost_Objective 453 + ProduceSizeSecondStage(6) c_u_EnforceProductionBinarySecondStage(6)_ -200000 + ProduceSizeSecondStage(7) Total_Cost_Objective 453 + ProduceSizeSecondStage(7) c_u_EnforceProductionBinarySecondStage(7)_ -200000 + ProduceSizeSecondStage(8) Total_Cost_Objective 453 + ProduceSizeSecondStage(8) c_u_EnforceProductionBinarySecondStage(8)_ -200000 + ProduceSizeSecondStage(9) Total_Cost_Objective 453 + ProduceSizeSecondStage(9) c_u_EnforceProductionBinarySecondStage(9)_ -200000 + ProduceSizeSecondStage(10) Total_Cost_Objective 453 + ProduceSizeSecondStage(10) c_u_EnforceProductionBinarySecondStage(10)_ -200000 + NumProducedFirstStage(1) Total_Cost_Objective 0.748 + NumProducedFirstStage(1) c_u_EnforceProductionBinaryFirstStage(1)_ 1 + NumProducedFirstStage(1) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(1) c_u_EnforceInventoryFirstStage(1)_ -1 + NumProducedFirstStage(1) c_u_EnforceInventorySecondStage(1)_ -1 + NumProducedFirstStage(2) Total_Cost_Objective 0.75839999999999996 + NumProducedFirstStage(2) c_u_EnforceProductionBinaryFirstStage(2)_ 1 + NumProducedFirstStage(2) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(2) c_u_EnforceInventoryFirstStage(2)_ -1 + NumProducedFirstStage(2) c_u_EnforceInventorySecondStage(2)_ -1 + NumProducedFirstStage(3) Total_Cost_Objective 0.76880000000000004 + NumProducedFirstStage(3) c_u_EnforceProductionBinaryFirstStage(3)_ 1 + NumProducedFirstStage(3) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(3) c_u_EnforceInventoryFirstStage(3)_ -1 + NumProducedFirstStage(3) c_u_EnforceInventorySecondStage(3)_ -1 + NumProducedFirstStage(4) Total_Cost_Objective 0.7792 + NumProducedFirstStage(4) c_u_EnforceProductionBinaryFirstStage(4)_ 1 + NumProducedFirstStage(4) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(4) c_u_EnforceInventoryFirstStage(4)_ -1 + NumProducedFirstStage(4) c_u_EnforceInventorySecondStage(4)_ -1 + NumProducedFirstStage(5) Total_Cost_Objective 0.78959999999999997 + NumProducedFirstStage(5) c_u_EnforceProductionBinaryFirstStage(5)_ 1 + NumProducedFirstStage(5) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(5) c_u_EnforceInventoryFirstStage(5)_ -1 + NumProducedFirstStage(5) c_u_EnforceInventorySecondStage(5)_ -1 + NumProducedFirstStage(6) Total_Cost_Objective 0.80000000000000004 + NumProducedFirstStage(6) c_u_EnforceProductionBinaryFirstStage(6)_ 1 + NumProducedFirstStage(6) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(6) c_u_EnforceInventoryFirstStage(6)_ -1 + NumProducedFirstStage(6) c_u_EnforceInventorySecondStage(6)_ -1 + NumProducedFirstStage(7) Total_Cost_Objective 0.81040000000000001 + NumProducedFirstStage(7) c_u_EnforceProductionBinaryFirstStage(7)_ 1 + NumProducedFirstStage(7) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(7) c_u_EnforceInventoryFirstStage(7)_ -1 + NumProducedFirstStage(7) c_u_EnforceInventorySecondStage(7)_ -1 + NumProducedFirstStage(8) Total_Cost_Objective 0.82079999999999997 + NumProducedFirstStage(8) c_u_EnforceProductionBinaryFirstStage(8)_ 1 + NumProducedFirstStage(8) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(8) c_u_EnforceInventoryFirstStage(8)_ -1 + NumProducedFirstStage(8) c_u_EnforceInventorySecondStage(8)_ -1 + NumProducedFirstStage(9) Total_Cost_Objective 0.83120000000000005 + NumProducedFirstStage(9) c_u_EnforceProductionBinaryFirstStage(9)_ 1 + NumProducedFirstStage(9) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(9) c_u_EnforceInventoryFirstStage(9)_ -1 + NumProducedFirstStage(9) c_u_EnforceInventorySecondStage(9)_ -1 + NumProducedFirstStage(10) Total_Cost_Objective 0.84160000000000001 + NumProducedFirstStage(10) c_u_EnforceProductionBinaryFirstStage(10)_ 1 + NumProducedFirstStage(10) c_u_EnforceCapacityLimitFirstStage_ 1 + NumProducedFirstStage(10) c_u_EnforceInventoryFirstStage(10)_ -1 + NumProducedFirstStage(10) c_u_EnforceInventorySecondStage(10)_ -1 + NumProducedSecondStage(1) Total_Cost_Objective 0.748 + NumProducedSecondStage(1) c_u_EnforceProductionBinarySecondStage(1)_ 1 + NumProducedSecondStage(1) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(1) c_u_EnforceInventorySecondStage(1)_ -1 + NumProducedSecondStage(2) Total_Cost_Objective 0.75839999999999996 + NumProducedSecondStage(2) c_u_EnforceProductionBinarySecondStage(2)_ 1 + NumProducedSecondStage(2) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(2) c_u_EnforceInventorySecondStage(2)_ -1 + NumProducedSecondStage(3) Total_Cost_Objective 0.76880000000000004 + NumProducedSecondStage(3) c_u_EnforceProductionBinarySecondStage(3)_ 1 + NumProducedSecondStage(3) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(3) c_u_EnforceInventorySecondStage(3)_ -1 + NumProducedSecondStage(4) Total_Cost_Objective 0.7792 + NumProducedSecondStage(4) c_u_EnforceProductionBinarySecondStage(4)_ 1 + NumProducedSecondStage(4) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(4) c_u_EnforceInventorySecondStage(4)_ -1 + NumProducedSecondStage(5) Total_Cost_Objective 0.78959999999999997 + NumProducedSecondStage(5) c_u_EnforceProductionBinarySecondStage(5)_ 1 + NumProducedSecondStage(5) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(5) c_u_EnforceInventorySecondStage(5)_ -1 + NumProducedSecondStage(6) Total_Cost_Objective 0.80000000000000004 + NumProducedSecondStage(6) c_u_EnforceProductionBinarySecondStage(6)_ 1 + NumProducedSecondStage(6) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(6) c_u_EnforceInventorySecondStage(6)_ -1 + NumProducedSecondStage(7) Total_Cost_Objective 0.81040000000000001 + NumProducedSecondStage(7) c_u_EnforceProductionBinarySecondStage(7)_ 1 + NumProducedSecondStage(7) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(7) c_u_EnforceInventorySecondStage(7)_ -1 + NumProducedSecondStage(8) Total_Cost_Objective 0.82079999999999997 + NumProducedSecondStage(8) c_u_EnforceProductionBinarySecondStage(8)_ 1 + NumProducedSecondStage(8) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(8) c_u_EnforceInventorySecondStage(8)_ -1 + NumProducedSecondStage(9) Total_Cost_Objective 0.83120000000000005 + NumProducedSecondStage(9) c_u_EnforceProductionBinarySecondStage(9)_ 1 + NumProducedSecondStage(9) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(9) c_u_EnforceInventorySecondStage(9)_ -1 + NumProducedSecondStage(10) Total_Cost_Objective 0.84160000000000001 + NumProducedSecondStage(10) c_u_EnforceProductionBinarySecondStage(10)_ 1 + NumProducedSecondStage(10) c_u_EnforceCapacityLimitSecondStage_ 1 + NumProducedSecondStage(10) c_u_EnforceInventorySecondStage(10)_ -1 + NumUnitsCutFirstStage(1_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(1_1) c_u_EnforceInventoryFirstStage(1)_ 1 + NumUnitsCutFirstStage(1_1) c_u_EnforceInventorySecondStage(1)_ 1 + NumUnitsCutFirstStage(2_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(2_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(2_1) c_u_EnforceInventoryFirstStage(2)_ 1 + NumUnitsCutFirstStage(2_1) c_u_EnforceInventorySecondStage(2)_ 1 + NumUnitsCutFirstStage(2_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(2_2) c_u_EnforceInventoryFirstStage(2)_ 1 + NumUnitsCutFirstStage(2_2) c_u_EnforceInventorySecondStage(2)_ 1 + NumUnitsCutFirstStage(3_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(3_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(3_1) c_u_EnforceInventoryFirstStage(3)_ 1 + NumUnitsCutFirstStage(3_1) c_u_EnforceInventorySecondStage(3)_ 1 + NumUnitsCutFirstStage(3_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(3_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(3_2) c_u_EnforceInventoryFirstStage(3)_ 1 + NumUnitsCutFirstStage(3_2) c_u_EnforceInventorySecondStage(3)_ 1 + NumUnitsCutFirstStage(3_3) c_l_DemandSatisfiedFirstStage(3)_ 1 + NumUnitsCutFirstStage(3_3) c_u_EnforceInventoryFirstStage(3)_ 1 + NumUnitsCutFirstStage(3_3) c_u_EnforceInventorySecondStage(3)_ 1 + NumUnitsCutFirstStage(4_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(4_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(4_1) c_u_EnforceInventoryFirstStage(4)_ 1 + NumUnitsCutFirstStage(4_1) c_u_EnforceInventorySecondStage(4)_ 1 + NumUnitsCutFirstStage(4_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(4_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(4_2) c_u_EnforceInventoryFirstStage(4)_ 1 + NumUnitsCutFirstStage(4_2) c_u_EnforceInventorySecondStage(4)_ 1 + NumUnitsCutFirstStage(4_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(4_3) c_l_DemandSatisfiedFirstStage(3)_ 1 + NumUnitsCutFirstStage(4_3) c_u_EnforceInventoryFirstStage(4)_ 1 + NumUnitsCutFirstStage(4_3) c_u_EnforceInventorySecondStage(4)_ 1 + NumUnitsCutFirstStage(4_4) c_l_DemandSatisfiedFirstStage(4)_ 1 + NumUnitsCutFirstStage(4_4) c_u_EnforceInventoryFirstStage(4)_ 1 + NumUnitsCutFirstStage(4_4) c_u_EnforceInventorySecondStage(4)_ 1 + NumUnitsCutFirstStage(5_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(5_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(5_1) c_u_EnforceInventoryFirstStage(5)_ 1 + NumUnitsCutFirstStage(5_1) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutFirstStage(5_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(5_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(5_2) c_u_EnforceInventoryFirstStage(5)_ 1 + NumUnitsCutFirstStage(5_2) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutFirstStage(5_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(5_3) c_l_DemandSatisfiedFirstStage(3)_ 1 + NumUnitsCutFirstStage(5_3) c_u_EnforceInventoryFirstStage(5)_ 1 + NumUnitsCutFirstStage(5_3) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutFirstStage(5_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(5_4) c_l_DemandSatisfiedFirstStage(4)_ 1 + NumUnitsCutFirstStage(5_4) c_u_EnforceInventoryFirstStage(5)_ 1 + NumUnitsCutFirstStage(5_4) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutFirstStage(5_5) c_l_DemandSatisfiedFirstStage(5)_ 1 + NumUnitsCutFirstStage(5_5) c_u_EnforceInventoryFirstStage(5)_ 1 + NumUnitsCutFirstStage(5_5) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutFirstStage(6_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(6_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(6_1) c_u_EnforceInventoryFirstStage(6)_ 1 + NumUnitsCutFirstStage(6_1) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutFirstStage(6_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(6_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(6_2) c_u_EnforceInventoryFirstStage(6)_ 1 + NumUnitsCutFirstStage(6_2) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutFirstStage(6_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(6_3) c_l_DemandSatisfiedFirstStage(3)_ 1 + NumUnitsCutFirstStage(6_3) c_u_EnforceInventoryFirstStage(6)_ 1 + NumUnitsCutFirstStage(6_3) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutFirstStage(6_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(6_4) c_l_DemandSatisfiedFirstStage(4)_ 1 + NumUnitsCutFirstStage(6_4) c_u_EnforceInventoryFirstStage(6)_ 1 + NumUnitsCutFirstStage(6_4) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutFirstStage(6_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(6_5) c_l_DemandSatisfiedFirstStage(5)_ 1 + NumUnitsCutFirstStage(6_5) c_u_EnforceInventoryFirstStage(6)_ 1 + NumUnitsCutFirstStage(6_5) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutFirstStage(6_6) c_l_DemandSatisfiedFirstStage(6)_ 1 + NumUnitsCutFirstStage(6_6) c_u_EnforceInventoryFirstStage(6)_ 1 + NumUnitsCutFirstStage(6_6) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutFirstStage(7_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(7_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(7_1) c_u_EnforceInventoryFirstStage(7)_ 1 + NumUnitsCutFirstStage(7_1) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutFirstStage(7_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(7_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(7_2) c_u_EnforceInventoryFirstStage(7)_ 1 + NumUnitsCutFirstStage(7_2) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutFirstStage(7_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(7_3) c_l_DemandSatisfiedFirstStage(3)_ 1 + NumUnitsCutFirstStage(7_3) c_u_EnforceInventoryFirstStage(7)_ 1 + NumUnitsCutFirstStage(7_3) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutFirstStage(7_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(7_4) c_l_DemandSatisfiedFirstStage(4)_ 1 + NumUnitsCutFirstStage(7_4) c_u_EnforceInventoryFirstStage(7)_ 1 + NumUnitsCutFirstStage(7_4) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutFirstStage(7_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(7_5) c_l_DemandSatisfiedFirstStage(5)_ 1 + NumUnitsCutFirstStage(7_5) c_u_EnforceInventoryFirstStage(7)_ 1 + NumUnitsCutFirstStage(7_5) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutFirstStage(7_6) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(7_6) c_l_DemandSatisfiedFirstStage(6)_ 1 + NumUnitsCutFirstStage(7_6) c_u_EnforceInventoryFirstStage(7)_ 1 + NumUnitsCutFirstStage(7_6) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutFirstStage(7_7) c_l_DemandSatisfiedFirstStage(7)_ 1 + NumUnitsCutFirstStage(7_7) c_u_EnforceInventoryFirstStage(7)_ 1 + NumUnitsCutFirstStage(7_7) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutFirstStage(8_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(8_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(8_1) c_u_EnforceInventoryFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_1) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutFirstStage(8_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(8_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(8_2) c_u_EnforceInventoryFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_2) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutFirstStage(8_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(8_3) c_l_DemandSatisfiedFirstStage(3)_ 1 + NumUnitsCutFirstStage(8_3) c_u_EnforceInventoryFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_3) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutFirstStage(8_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(8_4) c_l_DemandSatisfiedFirstStage(4)_ 1 + NumUnitsCutFirstStage(8_4) c_u_EnforceInventoryFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_4) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutFirstStage(8_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(8_5) c_l_DemandSatisfiedFirstStage(5)_ 1 + NumUnitsCutFirstStage(8_5) c_u_EnforceInventoryFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_5) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutFirstStage(8_6) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(8_6) c_l_DemandSatisfiedFirstStage(6)_ 1 + NumUnitsCutFirstStage(8_6) c_u_EnforceInventoryFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_6) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutFirstStage(8_7) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(8_7) c_l_DemandSatisfiedFirstStage(7)_ 1 + NumUnitsCutFirstStage(8_7) c_u_EnforceInventoryFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_7) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutFirstStage(8_8) c_l_DemandSatisfiedFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_8) c_u_EnforceInventoryFirstStage(8)_ 1 + NumUnitsCutFirstStage(8_8) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutFirstStage(9_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(9_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(9_1) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_1) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(9_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(9_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(9_2) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_2) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(9_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(9_3) c_l_DemandSatisfiedFirstStage(3)_ 1 + NumUnitsCutFirstStage(9_3) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_3) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(9_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(9_4) c_l_DemandSatisfiedFirstStage(4)_ 1 + NumUnitsCutFirstStage(9_4) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_4) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(9_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(9_5) c_l_DemandSatisfiedFirstStage(5)_ 1 + NumUnitsCutFirstStage(9_5) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_5) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(9_6) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(9_6) c_l_DemandSatisfiedFirstStage(6)_ 1 + NumUnitsCutFirstStage(9_6) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_6) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(9_7) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(9_7) c_l_DemandSatisfiedFirstStage(7)_ 1 + NumUnitsCutFirstStage(9_7) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_7) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(9_8) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(9_8) c_l_DemandSatisfiedFirstStage(8)_ 1 + NumUnitsCutFirstStage(9_8) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_8) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(9_9) c_l_DemandSatisfiedFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_9) c_u_EnforceInventoryFirstStage(9)_ 1 + NumUnitsCutFirstStage(9_9) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutFirstStage(10_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_1) c_l_DemandSatisfiedFirstStage(1)_ 1 + NumUnitsCutFirstStage(10_1) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_1) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_2) c_l_DemandSatisfiedFirstStage(2)_ 1 + NumUnitsCutFirstStage(10_2) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_2) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_3) c_l_DemandSatisfiedFirstStage(3)_ 1 + NumUnitsCutFirstStage(10_3) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_3) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_4) c_l_DemandSatisfiedFirstStage(4)_ 1 + NumUnitsCutFirstStage(10_4) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_4) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_5) c_l_DemandSatisfiedFirstStage(5)_ 1 + NumUnitsCutFirstStage(10_5) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_5) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_6) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_6) c_l_DemandSatisfiedFirstStage(6)_ 1 + NumUnitsCutFirstStage(10_6) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_6) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_7) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_7) c_l_DemandSatisfiedFirstStage(7)_ 1 + NumUnitsCutFirstStage(10_7) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_7) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_8) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_8) c_l_DemandSatisfiedFirstStage(8)_ 1 + NumUnitsCutFirstStage(10_8) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_8) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_9) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutFirstStage(10_9) c_l_DemandSatisfiedFirstStage(9)_ 1 + NumUnitsCutFirstStage(10_9) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_9) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutFirstStage(10_10) c_l_DemandSatisfiedFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_10) c_u_EnforceInventoryFirstStage(10)_ 1 + NumUnitsCutFirstStage(10_10) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(1_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(1_1) c_u_EnforceInventorySecondStage(1)_ 1 + NumUnitsCutSecondStage(2_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(2_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(2_1) c_u_EnforceInventorySecondStage(2)_ 1 + NumUnitsCutSecondStage(2_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(2_2) c_u_EnforceInventorySecondStage(2)_ 1 + NumUnitsCutSecondStage(3_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(3_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(3_1) c_u_EnforceInventorySecondStage(3)_ 1 + NumUnitsCutSecondStage(3_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(3_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(3_2) c_u_EnforceInventorySecondStage(3)_ 1 + NumUnitsCutSecondStage(3_3) c_l_DemandSatisfiedSecondStage(3)_ 1 + NumUnitsCutSecondStage(3_3) c_u_EnforceInventorySecondStage(3)_ 1 + NumUnitsCutSecondStage(4_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(4_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(4_1) c_u_EnforceInventorySecondStage(4)_ 1 + NumUnitsCutSecondStage(4_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(4_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(4_2) c_u_EnforceInventorySecondStage(4)_ 1 + NumUnitsCutSecondStage(4_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(4_3) c_l_DemandSatisfiedSecondStage(3)_ 1 + NumUnitsCutSecondStage(4_3) c_u_EnforceInventorySecondStage(4)_ 1 + NumUnitsCutSecondStage(4_4) c_l_DemandSatisfiedSecondStage(4)_ 1 + NumUnitsCutSecondStage(4_4) c_u_EnforceInventorySecondStage(4)_ 1 + NumUnitsCutSecondStage(5_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(5_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(5_1) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutSecondStage(5_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(5_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(5_2) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutSecondStage(5_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(5_3) c_l_DemandSatisfiedSecondStage(3)_ 1 + NumUnitsCutSecondStage(5_3) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutSecondStage(5_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(5_4) c_l_DemandSatisfiedSecondStage(4)_ 1 + NumUnitsCutSecondStage(5_4) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutSecondStage(5_5) c_l_DemandSatisfiedSecondStage(5)_ 1 + NumUnitsCutSecondStage(5_5) c_u_EnforceInventorySecondStage(5)_ 1 + NumUnitsCutSecondStage(6_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(6_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(6_1) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutSecondStage(6_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(6_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(6_2) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutSecondStage(6_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(6_3) c_l_DemandSatisfiedSecondStage(3)_ 1 + NumUnitsCutSecondStage(6_3) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutSecondStage(6_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(6_4) c_l_DemandSatisfiedSecondStage(4)_ 1 + NumUnitsCutSecondStage(6_4) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutSecondStage(6_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(6_5) c_l_DemandSatisfiedSecondStage(5)_ 1 + NumUnitsCutSecondStage(6_5) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutSecondStage(6_6) c_l_DemandSatisfiedSecondStage(6)_ 1 + NumUnitsCutSecondStage(6_6) c_u_EnforceInventorySecondStage(6)_ 1 + NumUnitsCutSecondStage(7_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(7_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(7_1) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutSecondStage(7_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(7_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(7_2) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutSecondStage(7_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(7_3) c_l_DemandSatisfiedSecondStage(3)_ 1 + NumUnitsCutSecondStage(7_3) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutSecondStage(7_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(7_4) c_l_DemandSatisfiedSecondStage(4)_ 1 + NumUnitsCutSecondStage(7_4) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutSecondStage(7_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(7_5) c_l_DemandSatisfiedSecondStage(5)_ 1 + NumUnitsCutSecondStage(7_5) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutSecondStage(7_6) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(7_6) c_l_DemandSatisfiedSecondStage(6)_ 1 + NumUnitsCutSecondStage(7_6) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutSecondStage(7_7) c_l_DemandSatisfiedSecondStage(7)_ 1 + NumUnitsCutSecondStage(7_7) c_u_EnforceInventorySecondStage(7)_ 1 + NumUnitsCutSecondStage(8_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(8_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(8_1) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutSecondStage(8_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(8_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(8_2) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutSecondStage(8_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(8_3) c_l_DemandSatisfiedSecondStage(3)_ 1 + NumUnitsCutSecondStage(8_3) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutSecondStage(8_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(8_4) c_l_DemandSatisfiedSecondStage(4)_ 1 + NumUnitsCutSecondStage(8_4) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutSecondStage(8_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(8_5) c_l_DemandSatisfiedSecondStage(5)_ 1 + NumUnitsCutSecondStage(8_5) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutSecondStage(8_6) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(8_6) c_l_DemandSatisfiedSecondStage(6)_ 1 + NumUnitsCutSecondStage(8_6) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutSecondStage(8_7) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(8_7) c_l_DemandSatisfiedSecondStage(7)_ 1 + NumUnitsCutSecondStage(8_7) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutSecondStage(8_8) c_l_DemandSatisfiedSecondStage(8)_ 1 + NumUnitsCutSecondStage(8_8) c_u_EnforceInventorySecondStage(8)_ 1 + NumUnitsCutSecondStage(9_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(9_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(9_1) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(9_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(9_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(9_2) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(9_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(9_3) c_l_DemandSatisfiedSecondStage(3)_ 1 + NumUnitsCutSecondStage(9_3) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(9_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(9_4) c_l_DemandSatisfiedSecondStage(4)_ 1 + NumUnitsCutSecondStage(9_4) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(9_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(9_5) c_l_DemandSatisfiedSecondStage(5)_ 1 + NumUnitsCutSecondStage(9_5) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(9_6) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(9_6) c_l_DemandSatisfiedSecondStage(6)_ 1 + NumUnitsCutSecondStage(9_6) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(9_7) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(9_7) c_l_DemandSatisfiedSecondStage(7)_ 1 + NumUnitsCutSecondStage(9_7) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(9_8) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(9_8) c_l_DemandSatisfiedSecondStage(8)_ 1 + NumUnitsCutSecondStage(9_8) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(9_9) c_l_DemandSatisfiedSecondStage(9)_ 1 + NumUnitsCutSecondStage(9_9) c_u_EnforceInventorySecondStage(9)_ 1 + NumUnitsCutSecondStage(10_1) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_1) c_l_DemandSatisfiedSecondStage(1)_ 1 + NumUnitsCutSecondStage(10_1) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_2) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_2) c_l_DemandSatisfiedSecondStage(2)_ 1 + NumUnitsCutSecondStage(10_2) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_3) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_3) c_l_DemandSatisfiedSecondStage(3)_ 1 + NumUnitsCutSecondStage(10_3) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_4) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_4) c_l_DemandSatisfiedSecondStage(4)_ 1 + NumUnitsCutSecondStage(10_4) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_5) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_5) c_l_DemandSatisfiedSecondStage(5)_ 1 + NumUnitsCutSecondStage(10_5) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_6) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_6) c_l_DemandSatisfiedSecondStage(6)_ 1 + NumUnitsCutSecondStage(10_6) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_7) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_7) c_l_DemandSatisfiedSecondStage(7)_ 1 + NumUnitsCutSecondStage(10_7) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_8) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_8) c_l_DemandSatisfiedSecondStage(8)_ 1 + NumUnitsCutSecondStage(10_8) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_9) Total_Cost_Objective -0.0080000000000000002 + NumUnitsCutSecondStage(10_9) c_l_DemandSatisfiedSecondStage(9)_ 1 + NumUnitsCutSecondStage(10_9) c_u_EnforceInventorySecondStage(10)_ 1 + NumUnitsCutSecondStage(10_10) c_l_DemandSatisfiedSecondStage(10)_ 1 + NumUnitsCutSecondStage(10_10) c_u_EnforceInventorySecondStage(10)_ 1 +RHS + RHS c_l_DemandSatisfiedFirstStage(1)_ 2500 + RHS c_l_DemandSatisfiedFirstStage(2)_ 7500 + RHS c_l_DemandSatisfiedFirstStage(3)_ 12500 + RHS c_l_DemandSatisfiedFirstStage(4)_ 10000 + RHS c_l_DemandSatisfiedFirstStage(5)_ 35000 + RHS c_l_DemandSatisfiedFirstStage(6)_ 25000 + RHS c_l_DemandSatisfiedFirstStage(7)_ 15000 + RHS c_l_DemandSatisfiedFirstStage(8)_ 12500 + RHS c_l_DemandSatisfiedFirstStage(9)_ 12500 + RHS c_l_DemandSatisfiedFirstStage(10)_ 5000 + RHS c_l_DemandSatisfiedSecondStage(1)_ 1750 + RHS c_l_DemandSatisfiedSecondStage(2)_ 5250 + RHS c_l_DemandSatisfiedSecondStage(3)_ 8750 + RHS c_l_DemandSatisfiedSecondStage(4)_ 7000 + RHS c_l_DemandSatisfiedSecondStage(5)_ 24500 + RHS c_l_DemandSatisfiedSecondStage(6)_ 17500 + RHS c_l_DemandSatisfiedSecondStage(7)_ 10500 + RHS c_l_DemandSatisfiedSecondStage(8)_ 8750 + RHS c_l_DemandSatisfiedSecondStage(9)_ 8750 + RHS c_l_DemandSatisfiedSecondStage(10)_ 3500 + RHS c_u_EnforceProductionBinaryFirstStage(1)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(2)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(3)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(4)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(5)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(6)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(7)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(8)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(9)_ 0 + RHS c_u_EnforceProductionBinaryFirstStage(10)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(1)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(2)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(3)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(4)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(5)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(6)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(7)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(8)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(9)_ 0 + RHS c_u_EnforceProductionBinarySecondStage(10)_ 0 + RHS c_u_EnforceCapacityLimitFirstStage_ 200000 + RHS c_u_EnforceCapacityLimitSecondStage_ 200000 + RHS c_u_EnforceInventoryFirstStage(1)_ 0 + RHS c_u_EnforceInventoryFirstStage(2)_ 0 + RHS c_u_EnforceInventoryFirstStage(3)_ 0 + RHS c_u_EnforceInventoryFirstStage(4)_ 0 + RHS c_u_EnforceInventoryFirstStage(5)_ 0 + RHS c_u_EnforceInventoryFirstStage(6)_ 0 + RHS c_u_EnforceInventoryFirstStage(7)_ 0 + RHS c_u_EnforceInventoryFirstStage(8)_ 0 + RHS c_u_EnforceInventoryFirstStage(9)_ 0 + RHS c_u_EnforceInventoryFirstStage(10)_ 0 + RHS c_u_EnforceInventorySecondStage(1)_ 0 + RHS c_u_EnforceInventorySecondStage(2)_ 0 + RHS c_u_EnforceInventorySecondStage(3)_ 0 + RHS c_u_EnforceInventorySecondStage(4)_ 0 + RHS c_u_EnforceInventorySecondStage(5)_ 0 + RHS c_u_EnforceInventorySecondStage(6)_ 0 + RHS c_u_EnforceInventorySecondStage(7)_ 0 + RHS c_u_EnforceInventorySecondStage(8)_ 0 + RHS c_u_EnforceInventorySecondStage(9)_ 0 + RHS c_u_EnforceInventorySecondStage(10)_ 0 +BOUNDS + BV BOUND ProduceSizeFirstStage(1) + BV BOUND ProduceSizeFirstStage(2) + BV BOUND ProduceSizeFirstStage(3) + BV BOUND ProduceSizeFirstStage(4) + BV BOUND ProduceSizeFirstStage(5) + BV BOUND ProduceSizeFirstStage(6) + BV BOUND ProduceSizeFirstStage(7) + BV BOUND ProduceSizeFirstStage(8) + BV BOUND ProduceSizeFirstStage(9) + BV BOUND ProduceSizeFirstStage(10) + BV BOUND ProduceSizeSecondStage(1) + BV BOUND ProduceSizeSecondStage(2) + BV BOUND ProduceSizeSecondStage(3) + BV BOUND ProduceSizeSecondStage(4) + BV BOUND ProduceSizeSecondStage(5) + BV BOUND ProduceSizeSecondStage(6) + BV BOUND ProduceSizeSecondStage(7) + BV BOUND ProduceSizeSecondStage(8) + BV BOUND ProduceSizeSecondStage(9) + BV BOUND ProduceSizeSecondStage(10) + LI BOUND NumProducedFirstStage(1) 0 + UI BOUND NumProducedFirstStage(1) 200000 + LI BOUND NumProducedFirstStage(2) 0 + UI BOUND NumProducedFirstStage(2) 200000 + LI BOUND NumProducedFirstStage(3) 0 + UI BOUND NumProducedFirstStage(3) 200000 + LI BOUND NumProducedFirstStage(4) 0 + UI BOUND NumProducedFirstStage(4) 200000 + LI BOUND NumProducedFirstStage(5) 0 + UI BOUND NumProducedFirstStage(5) 200000 + LI BOUND NumProducedFirstStage(6) 0 + UI BOUND NumProducedFirstStage(6) 200000 + LI BOUND NumProducedFirstStage(7) 0 + UI BOUND NumProducedFirstStage(7) 200000 + LI BOUND NumProducedFirstStage(8) 0 + UI BOUND NumProducedFirstStage(8) 200000 + LI BOUND NumProducedFirstStage(9) 0 + UI BOUND NumProducedFirstStage(9) 200000 + LI BOUND NumProducedFirstStage(10) 0 + UI BOUND NumProducedFirstStage(10) 200000 + LI BOUND NumProducedSecondStage(1) 0 + UI BOUND NumProducedSecondStage(1) 200000 + LI BOUND NumProducedSecondStage(2) 0 + UI BOUND NumProducedSecondStage(2) 200000 + LI BOUND NumProducedSecondStage(3) 0 + UI BOUND NumProducedSecondStage(3) 200000 + LI BOUND NumProducedSecondStage(4) 0 + UI BOUND NumProducedSecondStage(4) 200000 + LI BOUND NumProducedSecondStage(5) 0 + UI BOUND NumProducedSecondStage(5) 200000 + LI BOUND NumProducedSecondStage(6) 0 + UI BOUND NumProducedSecondStage(6) 200000 + LI BOUND NumProducedSecondStage(7) 0 + UI BOUND NumProducedSecondStage(7) 200000 + LI BOUND NumProducedSecondStage(8) 0 + UI BOUND NumProducedSecondStage(8) 200000 + LI BOUND NumProducedSecondStage(9) 0 + UI BOUND NumProducedSecondStage(9) 200000 + LI BOUND NumProducedSecondStage(10) 0 + UI BOUND NumProducedSecondStage(10) 200000 + LI BOUND NumUnitsCutFirstStage(1_1) 0 + UI BOUND NumUnitsCutFirstStage(1_1) 200000 + LI BOUND NumUnitsCutFirstStage(2_1) 0 + UI BOUND NumUnitsCutFirstStage(2_1) 200000 + LI BOUND NumUnitsCutFirstStage(2_2) 0 + UI BOUND NumUnitsCutFirstStage(2_2) 200000 + LI BOUND NumUnitsCutFirstStage(3_1) 0 + UI BOUND NumUnitsCutFirstStage(3_1) 200000 + LI BOUND NumUnitsCutFirstStage(3_2) 0 + UI BOUND NumUnitsCutFirstStage(3_2) 200000 + LI BOUND NumUnitsCutFirstStage(3_3) 0 + UI BOUND NumUnitsCutFirstStage(3_3) 200000 + LI BOUND NumUnitsCutFirstStage(4_1) 0 + UI BOUND NumUnitsCutFirstStage(4_1) 200000 + LI BOUND NumUnitsCutFirstStage(4_2) 0 + UI BOUND NumUnitsCutFirstStage(4_2) 200000 + LI BOUND NumUnitsCutFirstStage(4_3) 0 + UI BOUND NumUnitsCutFirstStage(4_3) 200000 + LI BOUND NumUnitsCutFirstStage(4_4) 0 + UI BOUND NumUnitsCutFirstStage(4_4) 200000 + LI BOUND NumUnitsCutFirstStage(5_1) 0 + UI BOUND NumUnitsCutFirstStage(5_1) 200000 + LI BOUND NumUnitsCutFirstStage(5_2) 0 + UI BOUND NumUnitsCutFirstStage(5_2) 200000 + LI BOUND NumUnitsCutFirstStage(5_3) 0 + UI BOUND NumUnitsCutFirstStage(5_3) 200000 + LI BOUND NumUnitsCutFirstStage(5_4) 0 + UI BOUND NumUnitsCutFirstStage(5_4) 200000 + LI BOUND NumUnitsCutFirstStage(5_5) 0 + UI BOUND NumUnitsCutFirstStage(5_5) 200000 + LI BOUND NumUnitsCutFirstStage(6_1) 0 + UI BOUND NumUnitsCutFirstStage(6_1) 200000 + LI BOUND NumUnitsCutFirstStage(6_2) 0 + UI BOUND NumUnitsCutFirstStage(6_2) 200000 + LI BOUND NumUnitsCutFirstStage(6_3) 0 + UI BOUND NumUnitsCutFirstStage(6_3) 200000 + LI BOUND NumUnitsCutFirstStage(6_4) 0 + UI BOUND NumUnitsCutFirstStage(6_4) 200000 + LI BOUND NumUnitsCutFirstStage(6_5) 0 + UI BOUND NumUnitsCutFirstStage(6_5) 200000 + LI BOUND NumUnitsCutFirstStage(6_6) 0 + UI BOUND NumUnitsCutFirstStage(6_6) 200000 + LI BOUND NumUnitsCutFirstStage(7_1) 0 + UI BOUND NumUnitsCutFirstStage(7_1) 200000 + LI BOUND NumUnitsCutFirstStage(7_2) 0 + UI BOUND NumUnitsCutFirstStage(7_2) 200000 + LI BOUND NumUnitsCutFirstStage(7_3) 0 + UI BOUND NumUnitsCutFirstStage(7_3) 200000 + LI BOUND NumUnitsCutFirstStage(7_4) 0 + UI BOUND NumUnitsCutFirstStage(7_4) 200000 + LI BOUND NumUnitsCutFirstStage(7_5) 0 + UI BOUND NumUnitsCutFirstStage(7_5) 200000 + LI BOUND NumUnitsCutFirstStage(7_6) 0 + UI BOUND NumUnitsCutFirstStage(7_6) 200000 + LI BOUND NumUnitsCutFirstStage(7_7) 0 + UI BOUND NumUnitsCutFirstStage(7_7) 200000 + LI BOUND NumUnitsCutFirstStage(8_1) 0 + UI BOUND NumUnitsCutFirstStage(8_1) 200000 + LI BOUND NumUnitsCutFirstStage(8_2) 0 + UI BOUND NumUnitsCutFirstStage(8_2) 200000 + LI BOUND NumUnitsCutFirstStage(8_3) 0 + UI BOUND NumUnitsCutFirstStage(8_3) 200000 + LI BOUND NumUnitsCutFirstStage(8_4) 0 + UI BOUND NumUnitsCutFirstStage(8_4) 200000 + LI BOUND NumUnitsCutFirstStage(8_5) 0 + UI BOUND NumUnitsCutFirstStage(8_5) 200000 + LI BOUND NumUnitsCutFirstStage(8_6) 0 + UI BOUND NumUnitsCutFirstStage(8_6) 200000 + LI BOUND NumUnitsCutFirstStage(8_7) 0 + UI BOUND NumUnitsCutFirstStage(8_7) 200000 + LI BOUND NumUnitsCutFirstStage(8_8) 0 + UI BOUND NumUnitsCutFirstStage(8_8) 200000 + LI BOUND NumUnitsCutFirstStage(9_1) 0 + UI BOUND NumUnitsCutFirstStage(9_1) 200000 + LI BOUND NumUnitsCutFirstStage(9_2) 0 + UI BOUND NumUnitsCutFirstStage(9_2) 200000 + LI BOUND NumUnitsCutFirstStage(9_3) 0 + UI BOUND NumUnitsCutFirstStage(9_3) 200000 + LI BOUND NumUnitsCutFirstStage(9_4) 0 + UI BOUND NumUnitsCutFirstStage(9_4) 200000 + LI BOUND NumUnitsCutFirstStage(9_5) 0 + UI BOUND NumUnitsCutFirstStage(9_5) 200000 + LI BOUND NumUnitsCutFirstStage(9_6) 0 + UI BOUND NumUnitsCutFirstStage(9_6) 200000 + LI BOUND NumUnitsCutFirstStage(9_7) 0 + UI BOUND NumUnitsCutFirstStage(9_7) 200000 + LI BOUND NumUnitsCutFirstStage(9_8) 0 + UI BOUND NumUnitsCutFirstStage(9_8) 200000 + LI BOUND NumUnitsCutFirstStage(9_9) 0 + UI BOUND NumUnitsCutFirstStage(9_9) 200000 + LI BOUND NumUnitsCutFirstStage(10_1) 0 + UI BOUND NumUnitsCutFirstStage(10_1) 200000 + LI BOUND NumUnitsCutFirstStage(10_2) 0 + UI BOUND NumUnitsCutFirstStage(10_2) 200000 + LI BOUND NumUnitsCutFirstStage(10_3) 0 + UI BOUND NumUnitsCutFirstStage(10_3) 200000 + LI BOUND NumUnitsCutFirstStage(10_4) 0 + UI BOUND NumUnitsCutFirstStage(10_4) 200000 + LI BOUND NumUnitsCutFirstStage(10_5) 0 + UI BOUND NumUnitsCutFirstStage(10_5) 200000 + LI BOUND NumUnitsCutFirstStage(10_6) 0 + UI BOUND NumUnitsCutFirstStage(10_6) 200000 + LI BOUND NumUnitsCutFirstStage(10_7) 0 + UI BOUND NumUnitsCutFirstStage(10_7) 200000 + LI BOUND NumUnitsCutFirstStage(10_8) 0 + UI BOUND NumUnitsCutFirstStage(10_8) 200000 + LI BOUND NumUnitsCutFirstStage(10_9) 0 + UI BOUND NumUnitsCutFirstStage(10_9) 200000 + LI BOUND NumUnitsCutFirstStage(10_10) 0 + UI BOUND NumUnitsCutFirstStage(10_10) 200000 + LI BOUND NumUnitsCutSecondStage(1_1) 0 + UI BOUND NumUnitsCutSecondStage(1_1) 200000 + LI BOUND NumUnitsCutSecondStage(2_1) 0 + UI BOUND NumUnitsCutSecondStage(2_1) 200000 + LI BOUND NumUnitsCutSecondStage(2_2) 0 + UI BOUND NumUnitsCutSecondStage(2_2) 200000 + LI BOUND NumUnitsCutSecondStage(3_1) 0 + UI BOUND NumUnitsCutSecondStage(3_1) 200000 + LI BOUND NumUnitsCutSecondStage(3_2) 0 + UI BOUND NumUnitsCutSecondStage(3_2) 200000 + LI BOUND NumUnitsCutSecondStage(3_3) 0 + UI BOUND NumUnitsCutSecondStage(3_3) 200000 + LI BOUND NumUnitsCutSecondStage(4_1) 0 + UI BOUND NumUnitsCutSecondStage(4_1) 200000 + LI BOUND NumUnitsCutSecondStage(4_2) 0 + UI BOUND NumUnitsCutSecondStage(4_2) 200000 + LI BOUND NumUnitsCutSecondStage(4_3) 0 + UI BOUND NumUnitsCutSecondStage(4_3) 200000 + LI BOUND NumUnitsCutSecondStage(4_4) 0 + UI BOUND NumUnitsCutSecondStage(4_4) 200000 + LI BOUND NumUnitsCutSecondStage(5_1) 0 + UI BOUND NumUnitsCutSecondStage(5_1) 200000 + LI BOUND NumUnitsCutSecondStage(5_2) 0 + UI BOUND NumUnitsCutSecondStage(5_2) 200000 + LI BOUND NumUnitsCutSecondStage(5_3) 0 + UI BOUND NumUnitsCutSecondStage(5_3) 200000 + LI BOUND NumUnitsCutSecondStage(5_4) 0 + UI BOUND NumUnitsCutSecondStage(5_4) 200000 + LI BOUND NumUnitsCutSecondStage(5_5) 0 + UI BOUND NumUnitsCutSecondStage(5_5) 200000 + LI BOUND NumUnitsCutSecondStage(6_1) 0 + UI BOUND NumUnitsCutSecondStage(6_1) 200000 + LI BOUND NumUnitsCutSecondStage(6_2) 0 + UI BOUND NumUnitsCutSecondStage(6_2) 200000 + LI BOUND NumUnitsCutSecondStage(6_3) 0 + UI BOUND NumUnitsCutSecondStage(6_3) 200000 + LI BOUND NumUnitsCutSecondStage(6_4) 0 + UI BOUND NumUnitsCutSecondStage(6_4) 200000 + LI BOUND NumUnitsCutSecondStage(6_5) 0 + UI BOUND NumUnitsCutSecondStage(6_5) 200000 + LI BOUND NumUnitsCutSecondStage(6_6) 0 + UI BOUND NumUnitsCutSecondStage(6_6) 200000 + LI BOUND NumUnitsCutSecondStage(7_1) 0 + UI BOUND NumUnitsCutSecondStage(7_1) 200000 + LI BOUND NumUnitsCutSecondStage(7_2) 0 + UI BOUND NumUnitsCutSecondStage(7_2) 200000 + LI BOUND NumUnitsCutSecondStage(7_3) 0 + UI BOUND NumUnitsCutSecondStage(7_3) 200000 + LI BOUND NumUnitsCutSecondStage(7_4) 0 + UI BOUND NumUnitsCutSecondStage(7_4) 200000 + LI BOUND NumUnitsCutSecondStage(7_5) 0 + UI BOUND NumUnitsCutSecondStage(7_5) 200000 + LI BOUND NumUnitsCutSecondStage(7_6) 0 + UI BOUND NumUnitsCutSecondStage(7_6) 200000 + LI BOUND NumUnitsCutSecondStage(7_7) 0 + UI BOUND NumUnitsCutSecondStage(7_7) 200000 + LI BOUND NumUnitsCutSecondStage(8_1) 0 + UI BOUND NumUnitsCutSecondStage(8_1) 200000 + LI BOUND NumUnitsCutSecondStage(8_2) 0 + UI BOUND NumUnitsCutSecondStage(8_2) 200000 + LI BOUND NumUnitsCutSecondStage(8_3) 0 + UI BOUND NumUnitsCutSecondStage(8_3) 200000 + LI BOUND NumUnitsCutSecondStage(8_4) 0 + UI BOUND NumUnitsCutSecondStage(8_4) 200000 + LI BOUND NumUnitsCutSecondStage(8_5) 0 + UI BOUND NumUnitsCutSecondStage(8_5) 200000 + LI BOUND NumUnitsCutSecondStage(8_6) 0 + UI BOUND NumUnitsCutSecondStage(8_6) 200000 + LI BOUND NumUnitsCutSecondStage(8_7) 0 + UI BOUND NumUnitsCutSecondStage(8_7) 200000 + LI BOUND NumUnitsCutSecondStage(8_8) 0 + UI BOUND NumUnitsCutSecondStage(8_8) 200000 + LI BOUND NumUnitsCutSecondStage(9_1) 0 + UI BOUND NumUnitsCutSecondStage(9_1) 200000 + LI BOUND NumUnitsCutSecondStage(9_2) 0 + UI BOUND NumUnitsCutSecondStage(9_2) 200000 + LI BOUND NumUnitsCutSecondStage(9_3) 0 + UI BOUND NumUnitsCutSecondStage(9_3) 200000 + LI BOUND NumUnitsCutSecondStage(9_4) 0 + UI BOUND NumUnitsCutSecondStage(9_4) 200000 + LI BOUND NumUnitsCutSecondStage(9_5) 0 + UI BOUND NumUnitsCutSecondStage(9_5) 200000 + LI BOUND NumUnitsCutSecondStage(9_6) 0 + UI BOUND NumUnitsCutSecondStage(9_6) 200000 + LI BOUND NumUnitsCutSecondStage(9_7) 0 + UI BOUND NumUnitsCutSecondStage(9_7) 200000 + LI BOUND NumUnitsCutSecondStage(9_8) 0 + UI BOUND NumUnitsCutSecondStage(9_8) 200000 + LI BOUND NumUnitsCutSecondStage(9_9) 0 + UI BOUND NumUnitsCutSecondStage(9_9) 200000 + LI BOUND NumUnitsCutSecondStage(10_1) 0 + UI BOUND NumUnitsCutSecondStage(10_1) 200000 + LI BOUND NumUnitsCutSecondStage(10_2) 0 + UI BOUND NumUnitsCutSecondStage(10_2) 200000 + LI BOUND NumUnitsCutSecondStage(10_3) 0 + UI BOUND NumUnitsCutSecondStage(10_3) 200000 + LI BOUND NumUnitsCutSecondStage(10_4) 0 + UI BOUND NumUnitsCutSecondStage(10_4) 200000 + LI BOUND NumUnitsCutSecondStage(10_5) 0 + UI BOUND NumUnitsCutSecondStage(10_5) 200000 + LI BOUND NumUnitsCutSecondStage(10_6) 0 + UI BOUND NumUnitsCutSecondStage(10_6) 200000 + LI BOUND NumUnitsCutSecondStage(10_7) 0 + UI BOUND NumUnitsCutSecondStage(10_7) 200000 + LI BOUND NumUnitsCutSecondStage(10_8) 0 + UI BOUND NumUnitsCutSecondStage(10_8) 200000 + LI BOUND NumUnitsCutSecondStage(10_9) 0 + UI BOUND NumUnitsCutSecondStage(10_9) 200000 + LI BOUND NumUnitsCutSecondStage(10_10) 0 + UI BOUND NumUnitsCutSecondStage(10_10) 200000 +ENDATA diff --git a/mpisppy/tests/examples/test1.mps b/mpisppy/tests/examples/test1.mps new file mode 100644 index 000000000..c1c4e9f58 --- /dev/null +++ b/mpisppy/tests/examples/test1.mps @@ -0,0 +1,30 @@ +NAME TINYMATCHING +ROWS + N OBJ + E NODEA1 + E NODEA2 + E NODEA3 +COLUMNS + X11 OBJ 1 NODEA1 1 + X12 OBJ 2 NODEA1 1 + X13 OBJ 3 NODEA1 1 + X21 OBJ 2 NODEA2 1 + X22 OBJ 3 NODEA2 1 + X23 OBJ 1 NODEA2 1 + X31 OBJ 3 NODEA3 1 + X32 OBJ 1 NODEA3 1 + X33 OBJ 2 NODEA3 1 +RHS + rhs NODEA1 1 NODEA2 1 + rhs NODEA3 1 +BOUNDS + UP BOUND X11 1 + UP BOUND X12 1 + UP BOUND X13 1 + UP BOUND X21 1 + UP BOUND X22 1 + UP BOUND X23 1 + UP BOUND X31 1 + UP BOUND X32 1 + UP BOUND X33 1 +ENDATA diff --git a/mpisppy/tests/test_admmWrapper.py b/mpisppy/tests/test_admmWrapper.py index 1371f2653..2118effb9 100644 --- a/mpisppy/tests/test_admmWrapper.py +++ b/mpisppy/tests/test_admmWrapper.py @@ -6,6 +6,7 @@ # All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md for # full copyright and license information. ############################################################################### +# TBD: make these tests less fragile import unittest import mpisppy.utils.admmWrapper as admmWrapper import examples.distr as distr @@ -95,7 +96,8 @@ def _extracting_output(self, line): inner_bound = match.group(2) return float(outer_bound), float(inner_bound) else: - raise RuntimeError("The test is probably not correctly adapted: can't match the format of the line") + raise RuntimeError("Cannot find outer and inner bounds in pattern" + f" in this output {line=}") def test_values(self): command_line_pairs = [(f"mpiexec -np 3 python -u -m mpi4py distr_admm_cylinders.py --num-scens 3 --default-rho 10 --solver-name {solver_name} --max-iterations 50 --xhatxbar --lagrangian --rel-gap 0.01 --ensure-xhat-feas" \ @@ -112,11 +114,16 @@ def test_values(self): result = subprocess.run(command, capture_output=True, text=True) if result.stderr: print("Error output:") - print(result.stderr) + raise RuntimeError(result.stderr) + # Check the standard output if result.stdout: result_by_line = result.stdout.strip().split('\n') + else: + print(f"{result.stdout=}, {result.returncode=}") + raise RuntimeError(f"Cannot get output from {command=}") + target_line = "Iter. Best Bound Best Incumbent Rel. Gap Abs. Gap" precedent_line_target = False diff --git a/mpisppy/tests/test_mps.py b/mpisppy/tests/test_mps.py new file mode 100644 index 000000000..7ee7297b2 --- /dev/null +++ b/mpisppy/tests/test_mps.py @@ -0,0 +1,46 @@ +############################################################################### +# mpi-sppy: MPI-based Stochastic Programming in PYthon +# +# Copyright (c) 2024, Lawrence Livermore National Security, LLC, Alliance for +# Sustainable Energy, LLC, The Regents of the University of California, et al. +# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md for +# full copyright and license information. +############################################################################### +# test mps utilities +import unittest +import mpisppy.utils.mps_reader as mps_reader +from mpisppy.tests.utils import get_solver +import pyomo.environ as pyo +import mip # pip install mip (from coin-or) + +solver_available, solver_name, persistent_available, persistent_solver_name= get_solver(persistent_OK=False) + +class TestStochAdmmWrapper(unittest.TestCase): + def setUp(self): + pass + + def tearDown(self): + pass + + def _reader_body(self, fname): + pyomo_model = mps_reader.read_mps_and_create_pyomo_model(fname) + + opt = pyo.SolverFactory(solver_name) + opt.solve(pyomo_model) + pyomo_obj = pyo.value(pyomo_model.objective) + + m = mip.Model(solver_name="CBC") + m.read(fname) + m.optimize() # returns a status, btw + coin_obj = m.objective_value + self.assertAlmostEqual(coin_obj, pyomo_obj, places=3, + delta=None, msg=None) + + def test_mps_reader_test1(self): + self._reader_body("examples/test1.mps") + + def test_mps_reader_sizes1(self): + self._reader_body("examples/sizes1.mps") + +if __name__ == '__main__': + unittest.main() diff --git a/mpisppy/utils/mps_module.py b/mpisppy/utils/mps_module.py new file mode 100644 index 000000000..b7c182d17 --- /dev/null +++ b/mpisppy/utils/mps_module.py @@ -0,0 +1,144 @@ +############################################################################## +# mpi-sppy: MPI-based Stochastic Programming in PYthon +# +# Copyright (c) 2025, Lawrence Livermore National Security, LLC, Alliance for +# Sustainable Energy, LLC, The Regents of the University of California, et al. +# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md for +# full copyright and license information. +############################################################################### +# WARNING: the scenario_creator is very dependent on how the mps_reader works. +# This is designed for use with generic_cylinders.py +"""You pass in a path to a special mps_files_directory in the config and this +module will become a valid mpi-sppy module. +The directory has to have file pairs for each scenario where one file +is the mps file and other is a json file with a scenario tree dictionary +for the scenario. + +Scenario names must have a consistent base (e.g. "scenario" or "scen") and +must end in a serial number (unless you can't, you should start with 0; +otherwise, start with 1). + +Parenthesis in variable names in the json file must become underscores + +note to dlw from dlw: + You could offer the option to split up the objective by stages in the lp file + You should also offer other types of nonants in the json + +""" +import os +import re +import glob +import json +import mpisppy.scenario_tree as scenario_tree +import mpisppy.utils.sputils as sputils +import mpisppy.utils.mps_reader as mps_reader +# assume you can get the path from config, set in kw_creator as a side-effect +mps_files_directory = None + +def scenario_creator(sname, cfg=None): + """ Load the model from an mps file + + Args: + scenario_name (str): + Name of the scenario to construct. + cfg (Pyomo config object): options + """ + + sharedPath = os.path.join(cfg.mps_files_directory, sname) + mpsPath = sharedPath + ".mps" + model = mps_reader.read_mps_and_create_pyomo_model(mpsPath) + + # now read the JSON file and attach the tree information. + jsonPath = sharedPath + "_nonants.json" + with open(jsonPath) as f: + nonantDict = json.load(f) + try: + scenProb = nonantDict["scenarioData"]["scenProb"] + except Exception as e: + raise RuntimeError(f'Error getting scenProb from {jsonPath}: {e}') + assert "ROOT" in nonantDict, f'"ROOT" must be top node in {jsonPath}' + treeNodes = list() + parent_ndn = None # counting on the json file to have ordered nodes + stage = 1 + treeDict = nonantDict["treeData"] + for ndn in treeDict: + cp = treeDict[ndn]["condProb"] + nonants = [model.\ + find_component(var_name.replace('(','_').replace(')','_')) + for var_name in treeDict[ndn]["nonAnts"]] + assert parent_ndn == sputils.parent_ndn(ndn),\ + f"bad node names or parent order in {jsonPath} detected at {ndn}" + treeNodes.append(scenario_tree.\ + ScenarioNode(name=ndn, + cond_prob=cp, + stage=stage, + cost_expression=0.0, + nonant_list=nonants, + scen_model=model, + nonant_ef_suppl_list = None, + parent_name = parent_ndn + ) + ) + parent_ndn = ndn + stage += 1 + + model._mpisppy_probability = scenProb + model._mpisppy_node_list = treeNodes + return model + + +#========= +def scenario_names_creator(num_scens, start=None): + # validate the directory and use it to get names (that have to be numbered) + # IMPORTANT: start is zero-based even if the names are one-based! + mps_files = [os.path.basename(f) + for f in glob.glob(os.path.join(mps_files_directory, "*.mps"))] + mps_files.sort() + if start is None: + start = 0 + if num_scens is None: + num_scens = len(mps_files) - start + first = re.search(r"\d+$",mps_files[0][:-4]) # first scenario number + try: + first = int(first.group()) + except Exception as e: + raise RuntimeError(f'mps files in {mps_files_directory} must end with an integer' + f'found file {mps_files[0]} (error was: {e})') + + print("WARNING: one-based senario names might cause trouble" + f" found {first} for dir {mps_files_directory}") + assert start+num_scens <= len(mps_files),\ + f"Trying to create scenarios names with {start=}, {num_scens=} but {len(mps_files)=}" + retval = [fn[:-4] for fn in mps_files[start:start+num_scens]] + return retval + +#========= +def inparser_adder(cfg): + # verify that that the mps_files_directory is there, or add it + if "mps_files_directory" not in cfg: + cfg.add_to_config("mps_files_directory", + "Directory with mps, json pairs for scenarios", + domain=str, + default=None, + argparse=True) + +#========= +def kw_creator(cfg): + # creates keywords for scenario creator + # SIDE EFFECT: A bit of hack to get the directory path + global mps_files_directory + mps_files_directory = cfg.mps_files_directory + return {"cfg": cfg} + + +# This is only needed for sampling +def sample_tree_scen_creator(sname, stage, sample_branching_factors, seed, + given_scenario=None, **scenario_creator_kwargs): + # assert two stage, then do the usual for two stages? + pass + + +#============================ +def scenario_denouement(rank, scenario_name, scenario): + pass + diff --git a/mpisppy/utils/mps_reader.py b/mpisppy/utils/mps_reader.py new file mode 100644 index 000000000..28c1a2655 --- /dev/null +++ b/mpisppy/utils/mps_reader.py @@ -0,0 +1,111 @@ +############################################################################### +# mpi-sppy: MPI-based Stochastic Programming in PYthon +# +# Copyright (c) 2025, Lawrence Livermore National Security, LLC, Alliance for +# Sustainable Energy, LLC, The Regents of the University of California, et al. +# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md for +# full copyright and license information. +############################################################################### +# IMPORTANT: parens in variable names will become underscore (_) +import mip # from coin-or (pip install mip) +import pyomo.environ as pyo + +def read_mps_and_create_pyomo_model(mps_path): + """ + Reads an MPS file using mip and converts it into a Pyomo ConcreteModel. + + :param mps_path: Path to the MPS file. + :return: Pyomo ConcreteModel. + + aside: Chatgpt was almost negative help with this function... + """ + + def _domain_lookup(v): + # given a mip var, return its Pyomo domain + if v.var_type == 'C': + if v.lb == 0.0: + return pyo.NonNegativeReals + else: + return pyo.Reals + elif v.var_type == 'B': + return pyo.Binary + elif v.var_type == 'I': + return pyo.Integers + else: + raise RuntimeError(f"Unknown type from coin mip {v.var_type=}") + # BTW: I don't know how to query the mip object for SOS sets + # (maybe it transforms them?) + + # Read the MPS file and call the coin-mip model m + m = mip.Model(solver_name="cbc") + m.read(mps_path) + + # Create a Pyomo model + model = pyo.ConcreteModel() + + varDict = dict() # coin mip var to pyomo var + # Add variables to Pyomo model with their bounds and domains + for v in m.vars: + vname = v.name.replace("(","_").replace(")","_") + varDict[v] = pyo.Var(domain=_domain_lookup(v), bounds=(v.lb, v.ub)) + setattr(model, vname, varDict[v]) + #print(f"{dir(v)=}") + + # Add constraints + for c in m.constrs: + # Extract terms correctly from LinExpr + body = sum(coeff * varDict[var] for var, coeff in c.expr.expr.items()) + + if c.expr.sense == "=": + pyomoC = pyo.Constraint(expr=(c.rhs, body, c.rhs)) + elif c.expr.sense == ">": + pyomoC = pyo.Constraint(expr=(c.rhs, body, None)) + elif c.expr.sense == "<": + pyomoC = pyo.Constraint(expr=(None, body, c.rhs)) + elif c.expr.sense == "": + raise RuntimeError(f"Unexpected empty sense for constraint {c.name}" + f" from file {mps_path}") + else: + raise RuntimeError(f"Unexpected sense {c.expr.sense=}" + f" for constraint {c.name} from file {mps_path}") + setattr(model, c.name, pyomoC) + + # objective function + obj_expr = sum(coeff * varDict[v] for v, coeff in m.objective.expr.items()) + if m.sense == mip.MINIMIZE: + model.objective = pyo.Objective(expr=obj_expr, sense=pyo.minimize) + else: + model.objective = pyo.Objective(expr=obj_expr, sense=pyo.maximize) + + return model + + +if __name__ == "__main__": + # for testing + solver_name = "cplex" + fname = "delme.mps" + #fname = "test1.mps" + pyomo_model = read_mps_and_create_pyomo_model(fname) + pyomo_model.pprint() + + opt = pyo.SolverFactory(solver_name) + opt.solve(pyomo_model) + pyomo_obj = pyo.value(pyomo_model.objective) + + m = mip.Model(solver_name=solver_name) + m.read(fname) + coinstatus = m.optimize() + coin_obj = m.objective_value + print(f"{coinstatus=}, {coin_obj=}, {pyomo_obj=}") + + print("\ncoin var values") + for v in m.vars: + print(f"{v.name}: {v.x}") + + print("\npyomo var values") + for v in pyomo_model.component_objects(pyo.Var, active=True): + print(f"Variable: {v.name}") + for index in v: + print(f" Index: {index}, Value: {v[index].value}") + +