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