transport12.cpp
Go to the documentation of this file.
1/*
2 * GAMS - General Algebraic Modeling System C++ API
3 *
4 * Copyright (c) 2017-2018 GAMS Software GmbH <support@gams.com>
5 * Copyright (c) 2017-2018 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
30using namespace gams;
31using namespace std;
32
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
84string toLower(const string &str)
85{
86 string lstr(str);
87 transform(lstr.begin(), lstr.end(), lstr.begin(), ::tolower);
88 return lstr;
89}
90
92void 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 {
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
253int 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);
263
264 // initialize a GAMSCheckpoint by running a GAMSJob
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}
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:92
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:34
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:84
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)