$title Simple Embedded Code ModelInstance Example (EMBMIEX1,SEQ=417) $onText The GAMS Embedded Code facility allows to execute foreign code (e.g. Python) while GAMS runs and to exchange data with GAMS without any disk access (e.g. GDX). In this example we combine the power of the embedded code facility with the GAMS Python OO-API class GAMSModelInstance. An instance of this class provides access to a model instance that can be modified and resolved without regenerating the model over and over. Here we generate the model instance once by using the libinclude pyEmbMI. The arguments to this call provide all necessary information to instantiate an instance of a GAMSModelInstance. In particular we provide the relevant part of the solve statement as well as a list of modifiers. These are the parameters in the model that are subject to change. In addition we can provide some options belonging to a GAMS/Python OO-API class GAMSOptions via the -key=value pairs. See more about the use of GAMSModelInstance and GAMSOptions in the GAMS/Python OO-API at /latest/docs/apis/python/annotated.html A traditional GAMS implemenation of such a scenario loop looks like this: loop(ScenariosToRun, a(i) = newsupply(ScenariosToRun,i); b(j) = newdemand(ScenariosToRun,j); solve transport using lp minimizing z; resultantx(ScenariosToRun,i,j) = x.l(i,j) ); With the embedded code/GAMSModelInstance solution this loop looks as follows: $libInclude pyEmbMI tMI 'transport us lp min z' -all_model_types=cplex a.Zero b.Zero loop(ScenariosToRun, a(i) = newsupply(ScenariosToRun,i); b(j) = newdemand(ScenariosToRun,j); continueEmbeddedCode: gams.db['a'].copy_symbol(tMI.sync_db['a']) gams.db['b'].copy_symbol(tMI.sync_db['b']) tMI.solve() tMI.sync_db['x'].copy_symbol(gams.db['x']) pauseEmbeddedCode x resultantx(ScenariosToRun,i,j) = x.l(i,j); ); With a little helper function this code becomes even more similar: $libInclude pyEmbMI tMI 'transport us lp min z' -all_model_types=cplex a.Zero b.Zero loop(ScenariosToRun, a(i) = newsupply(ScenariosToRun,i); b(j) = newdemand(ScenariosToRun,j); continueEmbeddedCode: solveMI(tMI,['a','b'],['x']) pauseEmbeddedCode x resultantx(ScenariosToRun,i,j) = x.l(i,j); ); In contrast to GUSS/Scenario Solver here we implement the loop logic in GAMS and execute in the loop body the solve method of the GAMSModelInstance class inside the embedded Python code. Rather than using the gams.get|set method of the embedded code facility we use GAMSDatabase.copy_symbol to move data between GAMS (gams.db) and the GAMSModelInstance.sync_db. Even though we don't exercise the ability in this example, the combination of GAMSModelInstance and embedded code provides a way of defining the scenario n+1 based on the result (primal and dual) of the nth scenario. This is not possible in GUSS/Scenario Solver. Keywords: linear programming, GAMS embedded code facility, Python, transportation problem, scheduling $offText $log --- Using Python library %sysEnv.GMSPYTHONLIB% Set i 'canning plants' / seattle, san-diego / j 'markets' / new-york, chicago, topeka /; Parameter a(i) 'capacity of plant i in cases' / seattle 350 san-diego 600 / b(j) 'demand at market j in cases' / new-york 325 chicago 300 topeka 275 /; Table d(i,j) 'distance in thousands of miles' new-york chicago topeka seattle 2.5 1.7 1.8 san-diego 2.5 1.8 1.4; Scalar f 'freight in dollars per case per thousand miles' / 90 /; Parameter c(i,j) 'transport cost in thousands of dollars per case'; c(i,j) = f*d(i,j)/1000; Variable x(i,j) 'shipment quantities in cases' z 'total transportation costs in thousands of dollars'; Positive Variable x; Equation cost 'define objective function' supply(i) 'observe supply limit at plant i' demand(j) 'satisfy demand at market j'; cost.. z =e= sum((i,j), c(i,j)*x(i,j)); supply(i).. sum(j, x(i,j)) =l= a(i); demand(j).. sum(i, x(i,j)) =g= b(j); Model transport / all /; Set s 'scenarios to run' / base, run1, run2 /; Table newsupply(s,i) 'updater for a (capacity)' seattle san-diego base 350 600 run1 300 650 run2 400 550; Table newdemand(s,j) 'updater for b (demand)' new-york chicago topeka base 325 300 275 run1 325 300 275 run2 350 300 250; $set solverlog $if set useSolverLog $set solverlog output=sys.stdout embeddedCode Python: gams.wsWorkingDir = '.' def solveMI(mi, symIn=[], symOut=[]): for sym in symIn: gams.db[sym].copy_symbol(mi.sync_db[sym]) mi.solve(%solverlog%) for sym in symOut: try: gams.db[sym].clear() # Explicitly clear the symbol to ensure setting "writtenTo" flag for sym mi.sync_db[sym].copy_symbol(gams.db[sym]) except: pass pauseEmbeddedCode abort$execerror 'Python error. Check the log'; $set license $if not "%gams.license%" $set license '"-license=%gams.license%"' $libInclude pyEmbMI tMI 'transport us lp min z' -all_model_types=cplex %license% a.Zero b.Zero Parameter repX(s,i,j) 'collector for level of x'; loop(s, a(i) = newsupply(s,i); b(j) = newdemand(s,j); continueEmbeddedCode: solveMI(tMI,['a','b'],['x']) pauseEmbeddedCode x repX(s,i,j) = x.l(i,j); ); option repX:0:1:2; display repX; Set error(s) 'empty solution'; error(s) = sum((i,j), repX(s,i,j)) = 0; abort$card(error) 'Missing solution for some scenarios', error;