transport12.cpp
Go to the documentation of this file.
1/*
2  * GAMS - General Algebraic Modeling System C++ API
3  *
4  * Copyright (c) 2017-2022 GAMS Software GmbH <support@gams.com>
5  * Copyright (c) 2017-2022 GAMS Development Corp. <support@gams.com>
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23  * SOFTWARE.
24  */
25 #include "gams.h"
26 
27 #include <algorithm>
28 #include <iostream>
29 
30 using namespace gams;
31 using namespace std;
32 
34 string getModelText()
35 {
36  return " Sets \n"
37  " i canning plants / seattle, san-diego / \n"
38  " j markets / new-york, chicago, topeka / ; \n"
39  " \n"
40  " Parameters \n"
41  " \n"
42  " a(i) capacity of plant i in cases \n"
43  " / seattle 350 \n"
44  " san-diego 600 / \n"
45  " \n"
46  " b(j) demand at market j in cases \n"
47  " / new-york 325 \n"
48  " chicago 300 \n"
49  " topeka 275 / ; \n"
50  " \n"
51  " Table d(i,j) distance in thousands of miles \n"
52  " new-york chicago topeka \n"
53  " seattle 2.5 1.7 1.8 \n"
54  " san-diego 2.5 1.8 1.4 ; \n"
55  " \n"
56  " Scalar f freight in dollars per case per thousand miles /90/ ; \n"
57  " Scalar bmult demand multiplier /1/; \n"
58  " \n"
59  " Parameter c(i,j) transport cost in thousands of dollars per case ; \n"
60  " \n"
61  " c(i,j) = f * d(i,j) / 1000 ; \n"
62  " \n"
63  " Variables \n"
64  " x(i,j) shipment quantities in cases \n"
65  " z total transportation costs in thousands of dollars ; \n"
66  " \n"
67  " Positive Variable x ; \n"
68  " \n"
69  " Equations \n"
70  " cost define objective function \n"
71  " supply(i) observe supply limit at plant i \n"
72  " demand(j) satisfy demand at market j ; \n"
73  " \n"
74  " cost .. z =e= sum((i,j), c(i,j)*x(i,j)) ; \n"
75  " \n"
76  " supply(i) .. sum(j, x(i,j)) =l= a(i) ; \n"
77  " \n"
78  " demand(j) .. sum(i, x(i,j)) =g= bmult*b(j) ; \n"
79  " \n"
80  " Model transport /all/ ; \n";
81 }
82 
84 string toLower(const string &str)
85 {
86  string lstr(str);
87  transform(lstr.begin(), lstr.end(), lstr.begin(), ::tolower);
88  return lstr;
89 }
90 
92 void GUSSCall(GAMSSet dict, GAMSModelInstance mi, string solveStatement
93  , gams::GAMSOptions* opt = nullptr
95  , std::ostream* output = nullptr)
96 {
97  vector< tuple<GAMSModifier, GAMSParameter> > modifierList;
98 
99  if (dict.dim() != 3)
100  throw GAMSException("Dict needs to be 3-dimensional");
101 
102  vector<string> strs { " ", "scenario", " " };
103  string scenName = dict.firstRecord(strs).key(0);
104  GAMSSet scenSymbol = dict.database().getSet(scenName);
105 
106 
107  for (GAMSSetRecord rec : dict) {
108  if (toLower(rec.key(1)) == "scenario")
109  continue;
110  if (toLower(rec.key(1)) == "param") {
111  int modifierDim = dict.database().getParameter(rec.key(2)).dim() - scenSymbol.dim();
112  if (modifierDim < 0)
113  throw GAMSException("Dimension of " + rec.key(2) + " too small");
114  auto tuple = make_tuple(GAMSModifier(mi.syncDb().addParameter(rec.key(0), modifierDim, "")),
115  dict.database().getParameter(rec.key(2)));
116  modifierList.push_back(tuple);
117 
118  } else if ((rec.key(1) == "lower") || (toLower(rec.key(1)) == "upper") || (toLower(rec.key(1)) == "fixed")) {
119  int modifierDim = dict.database().getParameter(rec.key(2)).dim() - scenSymbol.dim();
120  if (modifierDim < 0)
121  throw GAMSException("Dimension of " + rec.key(2) + " too small");
122 
123  GAMSVariable modifierVar;
124  try {
125  modifierVar = dict.database().getVariable(rec.key(0));
126  } catch (...) {
127  modifierVar = mi.syncDb().addVariable(rec.key(0),modifierDim, GAMSEnum::Free, "");
128  }
129 
130  if (toLower(rec.key(1)) == "lower") {
131  auto tuple = make_tuple(GAMSModifier(modifierVar, GAMSEnum::Lower,
132  mi.syncDb().addParameter(rec.key(2), modifierDim, "")),
133  dict.database().getParameter(rec.key(2)));
134  modifierList.push_back(tuple);
135 
136  } else if (toLower(rec.key(1)) == "upper") {
137  auto tuple = make_tuple(GAMSModifier(modifierVar, GAMSEnum::Upper,
138  mi.syncDb().addParameter(rec.key(2), modifierDim, "")),
139  dict.database().getParameter(rec.key(2)));
140  modifierList.push_back(tuple);
141 
142  } else { // fixed
143  auto tuple = make_tuple(GAMSModifier(modifierVar, GAMSEnum::Fixed,
144  mi.syncDb().addParameter(rec.key(2), modifierDim, "")),
145  dict.database().getParameter(rec.key(2)));
146  modifierList.push_back(tuple);
147  }
148  } else if ((toLower(rec.key(1)) == "level") || (toLower(rec.key(1)) == "marginal")) {
149  // Check that parameter exists in GAMSDatabase, will throw an exception if not
150  dict.database().getParameter(rec.key(2));
151  } else {
152  throw GAMSException("Cannot handle UpdateAction " + rec.key(1));
153  }
154  }
155 
156  vector<GAMSModifier> mL;
157  for (auto tuple : modifierList)
158  mL.push_back(get<0>(tuple));
159  if (opt)
160  mi.instantiate(solveStatement, *opt, mL);
161  else
162  mi.instantiate(solveStatement, mL);
163 
164  vector<tuple<GAMSSymbol, GAMSParameter, string>> outList;
165 
166  for (GAMSSetRecord s : scenSymbol)
167  {
168  for (auto tup : modifierList)
169  {
170  GAMSParameter p;
171  GAMSParameter pscen = get<1>(tup);
172 
173  if (!get<0>(tup).dataSymbol().isValid())
174  p = get<0>(tup).gamsSymbol();
175  else
176  p = get<0>(tup).dataSymbol();
177 
178  // Implemented SymbolUpdateType=BaseCase
179  p.clear();
180 
182  vector<string> filter(pscen.dim());
183  for (int i = 0; i < scenSymbol.dim(); i++)
184  filter[i] = s.key(i);
185  for (int i = scenSymbol.dim(); i < pscen.dim(); i++)
186  filter[i] = " ";
187 
188  try {
189  rec = pscen.firstRecord(filter);
190  } catch (GAMSException&) {
191  continue;
192  }
193 
194  do {
195  vector<string> myKeys(p.dim());
196  for (int i = 0; i < p.dim(); i++)
197  myKeys[i] = rec.key(scenSymbol.dim()+i);
198  p.addRecord(myKeys).setValue(rec.value());
199  } while (rec.moveNext());
200  }
201 
202  mi.solve(GAMSEnum::SymbolUpdateType::BaseCase, *output, miOpt);
203 
204  if (outList.size() == 0)
205  for (GAMSSetRecord rec : dict)
206  if ((toLower(rec.key(1)) == "level") || (toLower(rec.key(1)) == "marginal")) {
207  auto tuple = make_tuple(mi.syncDb().getSymbol(rec.key(0)),
208  dict.database().getParameter(rec.key(2)),
209  toLower(rec.key(1)));
210  outList.push_back(tuple);
211  }
212 
213  for (tuple<GAMSSymbol, GAMSParameter, string> tup : outList) {
214  GAMSSymbol mySym = get<0>(tup);
215  vector<string> myKeys;
216  for (int i = 0; i < scenSymbol.dim(); i++)
217  myKeys.push_back(s.key(i));
218 
219  if ((get<2>(tup) == "level") && (mySym.type() == GAMSEnum::SymTypeVar)) {
220  for (GAMSVariableRecord rec : GAMSVariable(mySym)) {
221  for (int i = 0; i < static_cast<int>(rec.keys().size()); i++)
222  myKeys[scenSymbol.dim() + i] = s.key(i);
223  get<1>(tup).addRecord(myKeys).setValue(rec.level());
224  }
225  } else if ((get<2>(tup) == "level") && (mySym.type() == GAMSEnum::SymTypeEqu)) {
226  for (GAMSEquationRecord rec : GAMSEquation(mySym)) {
227  for (int i = 0; i < static_cast<int>(rec.keys().size()); i++)
228  myKeys[scenSymbol.dim() + i] = s.key(i);
229  get<1>(tup).addRecord(myKeys).setValue(rec.level());
230  }
231  } else if ((get<2>(tup) == "marginal") && (mySym.type() == GAMSEnum::SymTypeVar)) {
232  for (GAMSVariableRecord rec : GAMSVariable(mySym)) {
233  for (int i = 0; i < static_cast<int>(rec.keys().size()); i++)
234  myKeys[scenSymbol.dim() + i] = s.key(i);
235  get<1>(tup).addRecord(myKeys).setValue(rec.marginal());
236  }
237  } else if ((get<2>(tup) == "marginal") && (mySym.type() == GAMSEnum::SymTypeEqu)) {
238  for (GAMSEquationRecord rec : GAMSEquation(mySym)) {
239  for (int i = 0; i < static_cast<int>(rec.keys().size()); i++)
240  myKeys[scenSymbol.dim() + i] = s.key(i);
241  get<1>(tup).addRecord(myKeys).setValue(rec.marginal());
242  }
243  }
244  }
245  }
246 }
247 
253 int main(int argc, char* argv[])
254 {
255  cout << "---------- Transport 12 --------------" << endl;
256 
257  try {
258  GAMSWorkspaceInfo wsInfo;
259  if (argc > 1)
260  wsInfo.setSystemDirectory(argv[1]);
261  GAMSWorkspace ws(wsInfo);
262  GAMSCheckpoint cp = ws.addCheckpoint();
263 
264  // initialize a GAMSCheckpoint by running a GAMSJob
265  GAMSJob t12 = ws.addJobFromString(getModelText());
266  t12.run(cp);
267 
268  // create a GAMSModelInstance and solve it multiple times with different scalar bmult
270 
271  double bmultlist[] { 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3 };
272 
273  GAMSDatabase db = ws.addDatabase();
274 
275  GAMSSet scen = db.addSet("scen", 1, "");
276  GAMSParameter bmult = db.addParameter("bmultlist", "", scen);
277  GAMSParameter zscen = db.addParameter("zscen", "", scen);
278 
279  int i = 0;
280  for (double b : bmultlist) {
281  bmult.addRecord("s" + to_string(i)).setValue(b);
282  scen.addRecord("s" + to_string(i++));
283  }
284 
285  GAMSSet dict = db.addSet("dict",3,"");
286  dict.addRecord(scen.name(), "scenario", "");
287  dict.addRecord("bmult", "param", bmult.name());
288  dict.addRecord("z", "level", zscen.name());
289 
290 
291  GUSSCall(dict, mi, "transport use lp min z");
292 
293  for (GAMSParameterRecord rec : db.getParameter(zscen.name()))
294  cout << rec.key(0) << " obj: " << rec.value() << endl;
295 
297  GAMSDatabase db2 = ws.addDatabase();
298 
299  GAMSSet scen2 = db2.addSet("scen", 1, "");
300  GAMSParameter zscen2 = db2.addParameter("zscen", "", scen2);
301  GAMSParameter xup = db2.addParameter("xup", 3);
302 
303  for (int j = 0; j < 4; j++) {
304  for (GAMSSetRecord irec : t12.outDB().getSet("i"))
305  for (GAMSSetRecord jrec : t12.outDB().getSet("j"))
306  xup.addRecord("s" + to_string(j), irec.key(0), jrec.key(0)).setValue(j+1);
307  scen2.addRecord("s" + to_string(j));
308  }
309 
310  GAMSSet dict2 = db2.addSet("dict", 3, "");
311  dict2.addRecord(scen2.name(), "scenario", "");
312  dict2.addRecord("x", "lower", xup.name());
313  dict2.addRecord("z", "level", zscen2.name());
314 
315  GUSSCall(dict2, mi2, "transport use lp min z");
316 
317  for (GAMSParameterRecord rec : db2.getParameter(zscen2.name()))
318  cout << rec.key(0) << " obj: " << rec.value() << endl;
319 
320  } catch (GAMSException &ex) {
321  cout << "GAMSException occured: " << ex.what() << endl;
322  } catch (exception &ex) {
323  cout << ex.what() << endl;
324  }
325 
326  return 0;
327 }
gams::GAMSDatabase & database() const
GAMSEnum::SymbolType type() const
void setSystemDirectory(std::string systemDir)
GAMSDatabase syncDb()
void instantiate(const std::string &modelDefinition, const gams::GAMSOptions &options, const std::vector< gams::GAMSModifier > &modifiers={ })
void solve(GAMSEnum::SymbolUpdateType updateType, std::ostream &output, GAMSModelInstanceOpt miOpt)
int dim() const
GAMSVariable getVariable(const std::string &name)
std::string & name() const
GAMSSet addSet(const std::string &name, const int dimension, const std::string &explanatoryText="", GAMSEnum::SetType setType=GAMSEnum::SetType::Multi)
GAMSVariable addVariable(const std::string &name, const int dimension, const GAMSEnum::VarType varType, const std::string &explanatoryText="")
GAMSParameterRecord addRecord(const std::vector< std::string > &keys)
void GUSSCall(GAMSSet dict, GAMSModelInstance mi, string solveStatement, gams::GAMSOptions *opt=nullptr, gams::GAMSModelInstanceOpt miOpt=gams::GAMSModelInstanceOpt(), std::ostream *output=nullptr)
Using GUSS to solve the model in different scenarios.
Definition: transport12.cpp:92
GAMSDatabase outDB()
string getModelText()
Get model as string.
Definition: transport12.cpp:34
GAMSSetRecord addRecord(const std::vector< std::string > &keys)
GAMSParameter addParameter(const std::string &name, const int dimension, const std::string &explanatoryText="")
GAMSParameterRecord firstRecord(const std::vector< std::string > &slice)
GAMSSet getSet(const std::string &name)
GAMSModelInstance addModelInstance(const std::string &modelInstanceName="")
void setValue(const double val)
GAMSParameter getParameter(const std::string &name)
GAMSSetRecord firstRecord(const std::vector< std::string > &slice)
string toLower(const string &str)
Convert string to lower case.
Definition: transport12.cpp:84
GAMSSymbol getSymbol(const std::string &name)
std::string key(int index)