DomainChecking.cs
1using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using GAMS;
6 
7 namespace DomainChecking
8 {
28  {
29  static int Main(string[] args)
30  {
31  GAMSWorkspace ws;
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 }
string Key(int index)
new GAMSSetRecord AddRecord(params string[] keys)
new GAMSParameterRecord AddRecord(params string[] keys)
GAMSDatabase OutDB
GAMSParameter GetParameter(string parameterIdentifier)
GAMSSet GetSet(string setIdentifier)
List< GAMSSymbolDomainViolation > ViolRecs
void Export(string filePath=null)
new GAMSSetRecord FindRecord(params string[] keys)
void Run(GAMSOptions gamsOptions=null, GAMSCheckpoint checkpoint=null, TextWriter output=null, Boolean createOutDB=true)
GAMSDatabase AddDatabase(string databaseName=null, string inModelName=null)
GAMSSet AddSet(string identifier, int dimension, string explanatoryText="", SetType setType=SetType.multi)