DomainCheck.java
1package com.gams.examples.domain;
2 
3 import java.io.File;
4 import java.util.Arrays;
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Vector;
9 
10 import com.gams.api.GAMSDatabase;
12 import com.gams.api.GAMSException;
13 import com.gams.api.GAMSJob;
14 import com.gams.api.GAMSParameter;
15 import com.gams.api.GAMSSet;
16 import com.gams.api.GAMSSetRecord;
18 import com.gams.api.GAMSWorkspace;
20 
36 public class DomainCheck {
37 
38  public static void main(String[] args) {
39  // check workspace info from command line arguments
40  GAMSWorkspaceInfo wsInfo = new GAMSWorkspaceInfo();
41  if (args.length > 0)
42  wsInfo.setSystemDirectory( args[0] );
43  // create a directory
44  File workingDirectory = new File(System.getProperty("user.dir"), "DomainCheck");
45  workingDirectory.mkdir();
46  wsInfo.setWorkingDirectory(workingDirectory.getAbsolutePath());
47  // create a workspace
48  GAMSWorkspace ws = new GAMSWorkspace( wsInfo );
49 
50  // define some data by using C# data structures
51  List<String> plants = Arrays.asList("Seattle", "San-Diego");
52  List<String> markets = Arrays.asList("New-York", "Chicago", "Topeka");
53  Map<String, Double> capacity = new HashMap<String, Double>();
54  {
55  capacity.put("Seattle", Double.valueOf(350.0));
56  capacity.put("San-Diego", Double.valueOf(600.0));
57  }
58  Map<String, Double> demand = new HashMap<String, Double>();
59  {
60  demand.put("New-York", Double.valueOf(325.0));
61  demand.put("Chicago", Double.valueOf(300.0));
62  demand.put("Topeka", Double.valueOf(275.0));
63  }
64 
65  Map<Vector<String>, Double> distance = new HashMap<Vector<String>, Double>();
66  {
67  distance.put( new Vector<String>( Arrays.asList(new String[]{"Seattle", "New-York"}) ), Double.valueOf(2.5));
68  distance.put( new Vector<String>( Arrays.asList(new String[]{"Seattle", "Chicago"}) ), Double.valueOf(1.7));
69  distance.put( new Vector<String>( Arrays.asList(new String[]{"Seattle", "Topeka"}) ), Double.valueOf(1.8));
70  distance.put( new Vector<String>( Arrays.asList(new String[]{"San-Diego", "New-York"}) ), Double.valueOf(2.5));
71  distance.put( new Vector<String>( Arrays.asList(new String[]{"San-Diego", "Chicago"}) ), Double.valueOf(1.8));
72  distance.put( new Vector<String>( Arrays.asList(new String[]{"San-Diego", "Topeka"}) ), Double.valueOf(1.4));
73  }
74 
75  // prepare a GAMSDatabase with data from the C# data structures
76  GAMSDatabase db = ws.addDatabase();
77 
78  // add two sets to the GAMSDatabase
79  GAMSSet i = db.addSet("i", "");
80  for(String p : plants)
81  i.addRecord(p);
82  GAMSSet j = db.addSet("j", "");
83  for(String m : markets)
84  j.addRecord(m);
85 
86  // add a parameter with domain information
87  GAMSParameter a = db.addParameter("a", "capacity at plant", i);
88  for(String p : plants)
89  a.addRecord(p).setValue( capacity.get(p).doubleValue() );
90  // if we see a domain violation something went wrong
91  if (!a.checkDomains())
92  {
93  System.out.println("***ABORT*** Unexpected domain violation in a");
94  System.exit(1);
95  }
96  // add a parameter with relaxed domain information
97  GAMSParameter b = db.addParameter("b", "demand at market j in cases", "j");
98  for(String m : markets)
99  b.addRecord(m).setValue( demand.get(m).doubleValue() );
100 
101  // if we see a domain violation something went wrong
102  if (!b.checkDomains()) {
103  System.out.println("***ABORT*** Unexpected domain violation in b");
104  System.exit(1);
105  }
106 
107  // add a 2-dim parameter with domain information
108  Object[] domains = new Object[] { i, j };
109  GAMSParameter d = db.addParameter("d", "distance in thousands of miles", domains);
110  for(Vector<String> t : distance.keySet()) {
111  String[] keys = new String[t.size()];
112  t.toArray(keys);
113  d.addRecord( keys ).setValue( distance.get(t).doubleValue() ) ;
114  }
115 
116  // if we see a domain violation something went wrong
117  if (!d.checkDomains()) {
118  System.out.println("***ABORT*** Unexpected domain violation in d");
119  System.exit(1);
120  }
121 
122  // if we see a domain violation in the database something went wrong
123  if (!db.checkDomains()) {
124  System.out.println("***ABORT*** Unexpected domain violation in db");
125  System.exit(1);
126  }
127 
128  // create some "wrong" entries
129  d.addRecord( new String[] { "Seattle", "aa" } ).setValue( 1 );
130  d.addRecord( new String[] { "bb", "Seattle"} ).setValue( 1 );
131 
132  a.addRecord( "aa" ).setValue( 1 );
133  a.addRecord( "bb" ).setValue( 1 );
134  b.addRecord( "aa" ).setValue( 1 );
135  b.addRecord( "bb" ).setValue( 1 );
136 
137  // now the GAMSdatabase as well as the symbols a and d should have domain violations
138  if (db.checkDomains()) {
139  System.out.println("***ABORT*** Domain violation for db not recognized");
140  System.exit(1);
141  }
142  if (a.checkDomains()) {
143  System.out.println("***ABORT*** Domain violation for a not recognized");
144  System.exit(1);
145  }
146 
147  if (d.checkDomains()) {
148  System.out.println("***ABORT*** Domain violation for d not recognized");
149  System.exit(1);
150  }
151 
152  // b in contrast was defined with relaxed domain info only, therefore we should never see a domain violation
153  if (!b.checkDomains()) {
154  System.out.println("***ABORT*** Unexpected domain violation in b");
155  System.exit(1);
156  }
157 
158  // for a, we should see 2 domain violations ("aa" and "bb")
159  int dvCnt = 0;
160  System.out.println("Symbol Domain Violations of a:");
162  System.out.print(" > [");
163  for(boolean item1 : item.getViolationArray())
164  System.out.print(item1 + " ");
165  System.out.print("] <> ");
166  for(String item2 : item.getRecord().getKeys())
167  System.out.print(item2 + " ");
168  System.out.println("<<");
169  dvCnt++;
170  }
171  if (dvCnt != 2) {
172  System.out.print("***ABORT*** Expected 3 domain violation records of a, but found [" + dvCnt+"]");
173  System.exit(1);
174  }
175 
176  // for d, we should see 3 domain violations ("Seattle", *"aa"*; *"bb"*, *"Seattle"*)
177  dvCnt = 0;
178  System.out.println("Symbol Domain Violations of d:");
180  System.out.print(" > [");
181  for(boolean item1 : item.getViolationArray()) {
182  System.out.print(item1 + " ");
183  if (item1)
184  dvCnt++;
185  }
186  System.out.print("] <> ");
187  for(String item2 : item.getRecord().getKeys())
188  System.out.print(item2 + " ");
189  System.out.println("<<");
190  }
191  if (dvCnt != 3) {
192  System.out.println("***ABORT*** Expected 3 domain violation records of d, but found [" + dvCnt+"]");
193  System.exit(1);
194  }
195 
196  // for db, we should see 5 domain violations (all the ones from a and d)
197  dvCnt = 0;
198  System.out.println("Database Domain Violations of db without maximum limit of record numbers :");
200  for(GAMSSymbolDomainViolation info : item.getSymbolDomainViolations()) {
201  System.out.print(" > " + item.getSymbol().getName() + ": [");
202  for(boolean element : info.getViolationArray()) {
203  System.out.print(element + " ");
204  if (element)
205  dvCnt++;
206  }
207  System.out.print("] <> ");
208  for(String key : info.getRecord().getKeys())
209  System.out.print(key + " ");
210  System.out.println(" <<");
211  }
212  }
213  if (dvCnt != 5) {
214  System.out.println("***ABORT*** Expected 5 domain violation records of db, but found [" + dvCnt+"]");
215  System.exit(1);
216  }
217 
218  // now we limit the amount of violated records reported to a total of 3
219  dvCnt = 0;
220  System.out.println("Database Domain Violations of db with no more than 3 violation records :");
222  for(GAMSSymbolDomainViolation info : item.getSymbolDomainViolations()) {
223  System.out.print(" > " + item.getSymbol().getName() + ": [");
224  for(boolean element : info.getViolationArray()) {
225  System.out.print(element + " ");
226  if (element)
227  dvCnt++;
228  }
229  System.out.print("] <> ");
230  for(String key : info.getRecord().getKeys())
231  System.out.print(key + " ");
232  System.out.println(" <<");
233  }
234  }
235  if (dvCnt != 3) {
236  System.out.println("***ABORT*** Expected 3 domain violation records of db, but found [" + dvCnt+"]");
237  System.exit(1);
238  }
239 
240  // now we limit the amount of violated records reported to 1 per symbol
241  dvCnt = 0;
242  System.out.println("Database Domain Violations of db with no more than 1 violation record per 1 symbol :");
244  for(GAMSSymbolDomainViolation info : item.getSymbolDomainViolations()) {
245  System.out.print(" > " + item.getSymbol().getName() + ": [");
246  for(boolean element : info.getViolationArray()) {
247  System.out.print(element + " ");
248  }
249  System.out.print("] <> ");
250  for(String key : info.getRecord().getKeys())
251  System.out.print(key + " ");
252  System.out.println(" <<");
253  }
254  dvCnt++;
255  }
256  if (dvCnt != 2) {
257  System.out.println("***ABORT*** Expected 2 domain violation records of a, but found [" + dvCnt+"]");
258  System.exit(1);
259  }
260 
261  // by default we should get an exception when exporting a GAMSDatabase with domain violations
262  boolean sawException = false;
263  try {
264  db.export("test.gdx");
265  } catch(Exception e) {
266  sawException = true;
268  db.export("test.gdx");
269  }
270  if(!sawException) {
271  System.out.println("***ABORT*** It should not be possible to export a GAMSDatabase containing domain violations by default");
272  System.exit(1);
273  }
274 
275  // read a parameter with domain info from gdx
276  GAMSDatabase db2 = ws.addDatabaseFromGDX("test.gdx");
277  GAMSParameter d2 = db2.getParameter("d");
278 
279  // the domain of the parameter should be GAMSSet i and GAMSSet j
280  for(Object item : d2.getDomains()) {
281  if (item instanceof GAMSSet) {
282  if (((GAMSSet)item).getName().equals("i")) {
283  for(GAMSSetRecord uel : (GAMSSet)item)
284  if (!plants.contains(uel.getKey(0))) {
285  System.out.println("***ABORT*** Unexpected uel " + uel.getKey(0) + " found in domain i");
286  System.exit(1);
287  }
288  }
289  else if (((GAMSSet)item).getName().equals("j")) {
290  for(GAMSSetRecord uel : (GAMSSet)item)
291  if (!markets.contains(uel.getKey(0))) {
292  System.out.println("***ABORT*** Unexpected uel " + uel.getKey(0) + " found in domain j");
293  System.exit(1);
294  }
295  }
296  else
297  {
298  System.out.println("***ABORT*** Expected GAMSSet i and j but found " + ((GAMSSet)item).getName());
299  System.exit(1);
300  }
301  }
302  else
303  {
304  System.out.println("***ABORT*** Expected GAMSSet as domain but found relaxed domain " + (String)item);
305  System.exit(1);
306  }
307  }
308 
309  /* *************************************************************** *
310  * This next section is acutally not about domain checking, but we *
311  * make sure that certain things are working as expected. *
312  * *************************************************************** */
313 
314  // Try reading an Alias as Set
315  GAMSJob aliasJob = ws.addJobFromString(aliasData);
316  aliasJob.run();
317  GAMSSet ii = aliasJob.OutDB().getSet("ii");
318  System.out.println("Elements of aliased Set:");
319  for(GAMSSetRecord item : ii)
320  System.out.println(" > " + item.getKey(0));
321 
322  GAMSDatabase testDB = ws.addDatabase();
323  GAMSSet testSet = testDB.addSet("test", 1);
324 
325  // Try adding empty UEL
326  testSet.addRecord("");
327  System.out.println("Elements of test Set after adding empty UEL:");
328  System.out.println(" > " + testSet.getNumberOfRecords());
329 
330  // GAMS strips pending blanks while leading blanks are relevant
331  testSet.addRecord(" a ").setText("a");
332  System.out.println("Record ' a ' should be the same as ' a':");
333  System.out.println(" > " + testSet.findRecord(" a").getText());
334 
335  // GAMS cannot handle UELs with more than 63 characters
336  // This should be OK ...
337  testSet.addRecord("123456789012345678901234567890123456789012345678901234567890123 ").setText("OK");
338  // ... but not this
339  try {
340  testSet.addRecord("1234567890123456789012345678901234567890123456789012345678901234").setText("not OK");
341  System.out.println("*** It should not be possible to add a record with more than 63 characters");
342  System.exit(1);
343  } catch(GAMSException e) { }
344 
345  // GAMS cannot handle explanatory texts with more than 255 characters
346  testDB.addSet("textOK", "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345");
347  try {
348  testDB.addSet("textNotOK", "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456");
349  System.out.println("*** It should not be possible to add an explanatory text with more than 255 characters");
350  System.exit(1);
351  } catch(GAMSException e) { }
352 
353  testSet.addRecord("OK").setText("123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345");
354  try {
355  testSet.addRecord("notOK").setText("1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456");
356  System.out.println("*** It should not be possible to add an explanatory text with more than 255 characters");
357  System.exit(1);
358  } catch(GAMSException e) { }
359 
360  // GAMS can handle UELs containing single and double quotes but not at the same time
361  testSet.addRecord("quote'");
362  testSet.addRecord("quote\"");
363  try {
364  testSet.addRecord("quote'\"");
365  System.out.println("*** It should not be possible to add a record single AND double quote");
366  System.exit(1);
367  } catch(GAMSException e) { }
368 
369  testDB.export("test.gdx");
370 
371  System.out.println("successfully terminated!");
372  System.exit(0);
373  }
374 
375  static String aliasData =
376  "Sets \n"+
377  " i canning plants / seattle, san-diego /; \n"+
378  " \n"+
379  "Alias (i,ii); \n";
380 
381 }
void suppressAutoDomainChecking(boolean value)
GAMSParameter getParameter(String identifier)
The example enforces referential integrity also known in the GAMS lingo as domain checking.
void setSystemDirectory(String directory)
GAMSDatabase addDatabaseFromGDX(String gdxFileName)
GAMSParameter addParameter(String identifier, int dimension)
GAMSSet addSet(String identifier, int dimension)
GAMSSet getSet(String identifier)
GAMSJob addJobFromString(String source)
List< GAMSSymbolDomainViolation > getSymbolDomainViolations(int maxNoViolation)
void setWorkingDirectory(String directory)
GAMSDatabase OutDB()
T addRecord(Vector< String > keys)
T findRecord(String ... keys)
List< GAMSDatabaseDomainViolation > getDatabaseDomainViolations(int maxViolation, int maxViolationPerSymbol)