DomainChecking.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Text;
5using GAMS;
6
8{
28 {
29 static int Main(string[] args)
30 {
32 if (Environment.GetCommandLineArgs().Length > 1)
33 ws = new GAMSWorkspace(systemDirectory: Environment.GetCommandLineArgs()[1]);
34 else
35 ws = new GAMSWorkspace();
36
37 // define some data by using C# data structures
38 List<string> plants = new List<string>() { "Seattle", "San-Diego" };
39 List<string> markets = new List<string>() { "New-York", "Chicago", "Topeka" };
40 Dictionary<string, double> capacity = new Dictionary<string, double>() { { "Seattle", 350.0 }, { "San-Diego", 600.0 } };
41 Dictionary<string, double> demand = new Dictionary<string, double>() { { "New-York", 325.0 }, { "Chicago", 300.0 }, { "Topeka", 275.0 } };
42 Dictionary<Tuple<string, string>, double> distance = new Dictionary<Tuple<string, string>, double>()
43 {
44 { new Tuple<string,string> ("Seattle", "New-York"), 2.5 },
45 { new Tuple<string,string> ("Seattle", "Chicago"), 1.7 },
46 { new Tuple<string,string> ("Seattle", "Topeka"), 1.8 },
47 { new Tuple<string,string> ("San-Diego", "New-York"), 2.5 },
48 { new Tuple<string,string> ("San-Diego", "Chicago"), 1.8 },
49 { new Tuple<string,string> ("San-Diego", "Topeka"), 1.4 }
50 };
51
52 // prepare a GAMSDatabase with data from the C# data structures
53 GAMSDatabase db = ws.AddDatabase();
54
55 // add two sets to the GAMSDatabase
56 GAMSSet i = db.AddSet("i", "");
57 foreach (string p in plants)
58 i.AddRecord(p);
59 GAMSSet j = db.AddSet("j", "");
60 foreach (string m in markets)
61 j.AddRecord(m);
62
63 // add a parameter with domain information
64 GAMSParameter a = db.AddParameter("a", "capacity at plant", i);
65 foreach (string p in plants)
66 a.AddRecord(p).Value = capacity[p];
67
68 // if we see a domain violation something went wrong
69 if (!a.CheckDomains())
70 {
71 Console.WriteLine("*** Unexpected domain violation in a");
72 return 1;
73 }
74
75 // add a parameter with relaxed domain information
76 GAMSParameter b = db.AddParameter("b", "demand at market j in cases", "j");
77 foreach (string m in markets)
78 b.AddRecord(m).Value = demand[m];
79
80 // if we see a domain violation something went wrong
81 if (!b.CheckDomains())
82 {
83 Console.WriteLine("*** Unexpected domain violation in b");
84 return 1;
85 }
86
87 // add a 2-dim parameter with domain information
88 GAMSParameter d = db.AddParameter("d", "distance in thousands of miles", i, j);
89 foreach (Tuple<string, string> t in distance.Keys)
90 d.AddRecord(t.Item1, t.Item2).Value = distance[t];
91
92 // if we see a domain violation something went wrong
93 if (!d.CheckDomains())
94 {
95 Console.WriteLine("*** Unexpected domain violation in d");
96 return 1;
97 }
98
99 // if we see a domain violation in the database something went wrong
100 if (!db.CheckDomains())
101 {
102 Console.WriteLine("*** Unexpected domain violation in db");
103 return 1;
104 }
105
106 // create some "wrong" entries
107 d.AddRecord("Seattle", "aa").Value = 1;
108 d.AddRecord("bb", "Seattle").Value = 1;
109 a.AddRecord("aa").Value = 1;
110 a.AddRecord("bb").Value = 1;
111 b.AddRecord("aa").Value = 1;
112 b.AddRecord("bb").Value = 1;
113
114 // now the GAMSdatabase as well as the symbols a and d should have domain violations
115 if (db.CheckDomains())
116 {
117 Console.WriteLine("*** Domain violation for db not recognized");
118 return 1;
119 }
120 if (a.CheckDomains())
121 {
122 Console.WriteLine("*** Domain violation for a not recognized");
123 return 1;
124 }
125 if (d.CheckDomains())
126 {
127 Console.WriteLine("*** Domain violation for d not recognized");
128 return 1;
129 }
130
131 // b in contrast was defined with realxed domain info only, therefore we should never see a domain violation
132 if (!b.CheckDomains())
133 {
134 Console.WriteLine("*** Unexpected domain violation in b");
135 return 1;
136 }
137
138 // for a we should see 2 domain violations ("aa" and "bb")
139 int dvCnt = 0;
140 Console.WriteLine("Domain Violations of a:");
141 foreach (GAMSSymbolDomainViolation SDV in a.GetSymbolDVs())
142 {
143 Console.Write(" > ");
144 foreach (bool vi in SDV.ViolInd)
145 Console.Write(vi + " ");
146 Console.Write("<> ");
147 foreach (string k in SDV.ViolRec.Keys)
148 Console.Write(k + " ");
149 Console.WriteLine("<<");
150 dvCnt++;
151 }
152 if (dvCnt != 2)
153 {
154 Console.WriteLine("*** Number of domain violations for a should be 2 but saw " + dvCnt);
155 return 1;
156 }
157
158 // for d we should see 3 domain violations ("Seattle", *"aa"*; *"bb"*, *"Seattle"*)
159 dvCnt = 0;
160 Console.WriteLine("Domain Violations of d:");
161 foreach (GAMSSymbolDomainViolation SDV in d.GetSymbolDVs())
162 {
163 Console.Write(" > ");
164 foreach (bool vi in SDV.ViolInd)
165 {
166 Console.Write(vi + " ");
167 if (vi)
168 dvCnt++;
169 }
170 Console.Write("<> ");
171 foreach (string k in SDV.ViolRec.Keys)
172 Console.Write(k + " ");
173 Console.WriteLine("<<");
174 }
175 if (dvCnt != 3)
176 {
177 Console.WriteLine("*** Number of domain violations for a should be 3 but saw " + dvCnt);
178 return 1;
179 }
180
181 // for db we should see 5 domain violations (all the ones from a and d)
182 dvCnt = 0;
183 Console.WriteLine("Domain Violations of db:");
184 foreach (GAMSDatabaseDomainViolation DDV in db.GetDatabaseDVs())
185 {
186 Console.WriteLine(" > " + DDV.ViolSym.Name + ": ");
187 foreach (GAMSSymbolDomainViolation SDV in DDV.ViolRecs)
188 {
189 Console.Write(" ");
190 foreach (bool vi in SDV.ViolInd)
191 {
192 Console.Write(vi + " ");
193 if (vi)
194 dvCnt++;
195 }
196 Console.Write("<> ");
197 foreach (string k in SDV.ViolRec.Keys)
198 Console.Write(k + " ");
199 Console.WriteLine("<<");
200 }
201 }
202 if (dvCnt != 5)
203 {
204 Console.WriteLine("*** Number of domain violations for db should be 5 but saw " + dvCnt);
205 return 1;
206 }
207
208 // now we limit the amount of violated records reported to a total of 3
209 dvCnt = 0;
210 Console.WriteLine("Domain Violations of db:");
211 foreach (GAMSDatabaseDomainViolation DDV in db.GetDatabaseDVs(3))
212 {
213 Console.WriteLine(" > " + DDV.ViolSym.Name + ": ");
214 foreach (GAMSSymbolDomainViolation SDV in DDV.ViolRecs)
215 {
216 Console.Write(" ");
217 foreach (bool vi in SDV.ViolInd)
218 Console.Write(vi + " ");
219 Console.Write("<> ");
220 foreach (string k in SDV.ViolRec.Keys)
221 Console.Write(k + " ");
222 Console.WriteLine("<<");
223 dvCnt++;
224 }
225 }
226 if (dvCnt != 3)
227 {
228 Console.WriteLine("*** Number of domain violations for db should be 3 but saw " + dvCnt);
229 return 1;
230 }
231 // now we limit the amount of violated records reported to 1 per symbol
232 dvCnt = 0;
233 Console.WriteLine("Domain Violations of db:");
234 foreach (GAMSDatabaseDomainViolation DDV in db.GetDatabaseDVs(0, 1))
235 {
236 Console.WriteLine(" > " + DDV.ViolSym.Name + ": ");
237 foreach (GAMSSymbolDomainViolation SDV in DDV.ViolRecs)
238 {
239 Console.Write(" ");
240 foreach (bool vi in SDV.ViolInd)
241 Console.Write(vi + " ");
242 Console.Write("<> ");
243 foreach (string k in SDV.ViolRec.Keys)
244 Console.Write(k + " ");
245 Console.WriteLine("<<");
246 dvCnt++;
247 }
248 }
249 if (dvCnt != 2)
250 {
251 Console.WriteLine("*** Number of domain violations for db should be 2 but saw " + dvCnt);
252 return 1;
253 }
254
255 // by default we should get an exception when exporting a GAMSDatabase with domain violations
256 bool sawException = false;
257 try
258 {
259 db.Export("test.gdx");
260 }
261 catch
262 {
263 sawException = true;
264 db.SuppressAutoDomainChecking = true;
265 db.Export("test.gdx");
266 }
267 if (!sawException)
268 {
269 Console.WriteLine("*** It should not be possible to export a GAMSDatabase containing domain violations by default");
270 return 1;
271 }
272
273 // read a parameter with domain info from gdx
274 GAMSDatabase db2 = ws.AddDatabaseFromGDX("test.gdx");
275 GAMSParameter d2 = db2.GetParameter("d");
276
277 // the domain of the parameter should be GAMSSet i and GAMSSet j
278 foreach (object item in d2.Domains)
279 {
280 if (item is GAMSSet)
281 {
282 if (((GAMSSet)item).Name == "i")
283 {
284 foreach (GAMSSetRecord uel in (GAMSSet)item)
285 if (!plants.Contains(uel.Key(0)))
286 {
287 Console.WriteLine("*** Unexpected uel " + uel.Key(0) + " found in domain i");
288 return 1;
289 }
290 }
291 else if (((GAMSSet)item).Name == "j")
292 {
293 foreach (GAMSSetRecord uel in (GAMSSet)item)
294 if (!markets.Contains(uel.Key(0)))
295 {
296 Console.WriteLine("*** Unexpected uel " + uel.Key(0) + " found in domain j");
297 return 1;
298 }
299 }
300 else
301 {
302 Console.WriteLine("*** Expected GAMSSet i and j but found " + ((GAMSSet)item).Name);
303 return 1;
304 }
305 }
306 else
307 {
308 Console.WriteLine("*** Expected GAMSSet as domain but found relaxed domain " + (string)item);
309 return 1;
310 }
311 }
312
313 /* *************************************************************** *
314 * This next section is acutally not about domain checking, but we *
315 * make sure that certain things are working as expected. *
316 * *************************************************************** */
317
318 // Try reading an Alias as Set
319 GAMSJob jAlias = ws.AddJobFromString(GetDataText());
320 jAlias.Run();
321 GAMSSet ii = jAlias.OutDB.GetSet("ii");
322 Console.WriteLine("Elements of aliased Set:");
323 foreach (GAMSSetRecord item in ii)
324 Console.WriteLine(" > " + item.Key(0));
325
326 GAMSDatabase testDB = ws.AddDatabase();
327 GAMSSet testSet = testDB.AddSet("test", 1);
328
329 // Try adding empty UEL
330 testSet.AddRecord("");
331 Console.WriteLine("Elements of test Set after adding empty UEL:");
332 Console.WriteLine(" > " + testSet.NumberRecords);
333
334 // GAMS strips pending blanks while leading blanks are relevant
335 testSet.AddRecord(" a ").Text = "a";
336 Console.WriteLine("Record ' a ' should be the same as ' a':");
337 Console.WriteLine(" > " + testSet.FindRecord(" a").Text);
338
339 // GAMS cannot handle UELs with more than 63 characters
340 // This should be OK ...
341 testSet.AddRecord("123456789012345678901234567890123456789012345678901234567890123 ").Text = "OK";
342 // ... but not this
343 sawException = false;
344 try
345 {
346 testSet.AddRecord("1234567890123456789012345678901234567890123456789012345678901234").Text = "not OK";
347 }
348 catch
349 {
350 sawException = true;
351 }
352 if (!sawException)
353 {
354 Console.WriteLine("*** It should not be possible to add a record with more than 63 characters");
355 return 1;
356 }
357
358 // GAMS cannot handle explanatory texts with more than 255 characters
359 testDB.AddSet("textOK", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345");
360 sawException = false;
361 try
362 {
363 testDB.AddSet("textNotOK", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456");
364 }
365 catch
366 {
367 sawException = true;
368 }
369 if (!sawException)
370 {
371 Console.WriteLine("*** It should not be possible to add an explanatory text with more than 255 characters");
372 return 1;
373 }
374
375 testSet.AddRecord("OK").Text = "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345";
376 sawException = false;
377 try
378 {
379 testSet.AddRecord("notOK").Text = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456";
380 }
381 catch
382 {
383 sawException = true;
384 }
385 if (!sawException)
386 {
387 Console.WriteLine("*** It should not be possible to add an explanatory text with more than 255 characters");
388 return 1;
389 }
390
391 // GAMS can handle UELs containing single and double quotes but not at the same time
392 testSet.AddRecord("quote'");
393 testSet.AddRecord("quote\"");
394 sawException = false;
395 try
396 {
397 testSet.AddRecord("quote'\"");
398 }
399 catch
400 {
401 sawException = true;
402 }
403 if (!sawException)
404 {
405 Console.WriteLine("*** It should not be possible to add a record single AND double quote");
406 return 1;
407 }
408
409 testDB.Export("test.gdx");
410
411 return 0;
412 }
413
414 static String GetDataText()
415 {
416 String data = @"
417 Sets
418 i canning plants / seattle, san-diego /;
419
420 Alias (i,ii);";
421 return data;
422 }
423
424 }
425}
void Export(string filePath=null)
string Key(int index)
GAMSParameter GetParameter(string parameterIdentifier)
GAMSDatabase OutDB
void Run(GAMSOptions gamsOptions=null, GAMSCheckpoint checkpoint=null, TextWriter output=null, Boolean createOutDB=true)
GAMSSet GetSet(string setIdentifier)
GAMSDatabase AddDatabase(string databaseName=null, string inModelName=null)
new GAMSSetRecord FindRecord(params string[] keys)
GAMSSet AddSet(string identifier, int dimension, string explanatoryText="")
List< GAMSSymbolDomainViolation > ViolRecs
new GAMSParameterRecord AddRecord(params string[] keys)
new GAMSSetRecord AddRecord(params string[] keys)