Loading...
Searching...
No Matches
domain_check.m
1function domain_check(varargin)
2
3 % check workspace info from arguments
4 if nargin > 0
5 wsInfo = gams.control.WorkspaceInfo();
6 wsInfo.systemDirectory = varargin{1};
7 ws = gams.control.Workspace(wsInfo);
8 else
9 ws = gams.control.Workspace();
10 end
11
12 % prepare input data
13 plants = {'Seattle', 'San-Diego'};
14 markets = {'New-York', 'Chicago', 'Topeka'};
15 capacity = [350, 600];
16 demand = [325, 300, 275];
17 distance = [2.5, 1.7, 1.8; 2.5, 1.8, 1.4];
18
19 % prepare a Database with the data above
20 db = ws.addDatabase();
21
22 % add two sets to the Database
23 i = db.addSet('i', 1, 'canning plants');
24 for k = 1:numel(plants)
25 i.addRecord(plants{k});
26 end
27 j = db.addSet('j', 1, 'markets');
28 for k = 1:numel(markets)
29 j.addRecord(markets{k});
30 end
31
32 % add a parameter with domain information
33 a = db.addParameter('a', 'capacity of plant i in cases', i);
34 for k = 1:numel(plants)
35 rec = a.addRecord(plants{k});
36 rec.value = capacity(k);
37 end
38 % if we see a domain violation something went wrong
39 if ~a.checkDomains()
40 error('Unexpected domain violation in a');
41 end
42
43 % add a parameter with relaxed domain information
44 b = db.addParameter('b', 'demand at market j in cases', 'j');
45 for k = 1:numel(markets)
46 rec = b.addRecord(markets{k});
47 rec.value = demand(k);
48 end
49 if ~b.checkDomains()
50 error('Unexpected domain violation in b');
51 end
52
53 % add a 2-dim parameter with domain information
54 domains = {i, j};
55 d = db.addParameter('d', 'distance in thousands of miles', domains);
56 for k1 = 1:numel(plants)
57 for k2 = 1:numel(markets)
58 keys = {plants{k1}, markets{k2}};
59 rec = d.addRecord(keys);
60 rec.value = distance(k1,k2);
61 end
62 end
63 if ~d.checkDomains()
64 error('Unexpected domain violation in d');
65 end
66
67 if ~db.checkDomains()
68 error('Unexpected domain violation in db');
69 end
70
71 % create some 'wrong' entries
72 rec = d.addRecord({'Seattle', 'aa'});
73 rec.value = 1;
74 rec = d.addRecord({'bb', 'Seattle'});
75 rec.value = 1;
76
77 rec = a.addRecord('aa');
78 rec.value = 1;
79 rec = a.addRecord('bb');
80 rec.value = 1;
81 rec = b.addRecord('aa');
82 rec.value = 1;
83 rec = b.addRecord('bb');
84 rec.value = 1;
85
86 % now the database as well as the symbols a and d should have domain violations
87 if db.checkDomains()
88 error('Domain violation for db not recognized');
89 end
90 if a.checkDomains()
91 error('Domain violation for a not recognized');
92 end
93 if d.checkDomains()
94 error('Domain violation for d not recognized');
95 end
96
97 % b in contrast was defined with relaxed domain info only, therefore we should never see a domain violation
98 if ~b.checkDomains()
99 error('Unexpected domain violation in b');
100 end
101
102 % for a, we should see 2 domain violations ('aa' and 'bb')
103 fprintf('Symbol Domain Violations of a:\n');
104 dvCnt = list_domain_violations('', a.getSymbolDomainViolations(0), 0);
105 if dvCnt ~= 2
106 error('Expected 2 domain violation records of a, but found [%d]', dvCnt);
107 end
108
109 % for d, we should see 3 domain violations ('Seattle', *'aa'*; *'bb'*, *'Seattle'*)
110 fprintf('Symbol Domain Violations of d:\n');
111 dvCnt = list_domain_violations('', d.getSymbolDomainViolations(0), 0);
112 if dvCnt ~= 3
113 error('Expected 3 domain violation records of d, but found [%d]', dvCnt);
114 end
115
116 % for db, we should see 5 domain violations (all the ones from a and d)
117 dvCnt = 0;
118 fprintf('Database Domain Violations of db without maximum limit of record numbers:\n');
119 dbDomViolations = db.getDatabaseDomainViolations(0,0);
120 for i = 1:numel(dbDomViolations)
121 name = dbDomViolations{i}.symbol.name;
122 dvCnt = list_domain_violations(name, dbDomViolations{i}.symbolDomainViolations, dvCnt);
123 end
124 if dvCnt ~= 5
125 error('Expected 5 domain violation records of db, but found [%d]', dvCnt);
126 end
127
128 % now we limit the amount of violated records reported to a total of 3
129 dvCnt = 0;
130 fprintf('Database Domain Violations of db with no more than 3 violation records:\n');
131 dbDomViolations = db.getDatabaseDomainViolations(3,0);
132 for i = 1:numel(dbDomViolations)
133 name = dbDomViolations{i}.symbol.name;
134 dvCnt = list_domain_violations(name, dbDomViolations{i}.symbolDomainViolations, dvCnt);
135 end
136 if dvCnt ~= 3
137 error('Expected 3 domain violation records of db, but found [%d]', dvCnt);
138 end
139
140 % now we limit the amount of violated records reported to 1 per symbol
141 dvCnt = 0;
142 fprintf('Database Domain Violations of db with no more than 1 violation record per 1 symbol:\n');
143 dbDomViolations = db.getDatabaseDomainViolations(0,1);
144 for i = 1:numel(dbDomViolations)
145 name = dbDomViolations{i}.symbol.name;
146 dvCnt = list_domain_violations(name, dbDomViolations{i}.symbolDomainViolations, dvCnt);
147 end
148 if dvCnt ~= 2
149 error('Expected 2 domain violation records of db, but found [%d]', dvCnt);
150 end
151
152 % by default we should get an exception when exporting a Database with domain violations
153 sawException = false;
154 try
155 db.export('test.gdx');
156 catch
157 sawException = true;
158 db.suppressAutoDomainChecking = true;
159 db.export('test.gdx');
160 end
161 if ~sawException
162 error('It should not be possible to export a Database containing domain violations by default');
163 end
164
165 % read a parameter with domain info from gdx
166 db2 = ws.addDatabaseFromGDX('test.gdx');
167 d2 = db2.getParameter('d');
168
169 % the domain of the parameter should be Set i and Set j
170 domains = d2.domains;
171 for i = 1:numel(domains)
172 if ~isa(domains{i}, 'gams.control.Set')
173 error('Expected Set as domain but found relaxed domain %s', item);
174 end
175 if strcmp(domains{i}.name, 'i')
176 if ~check_uel(domains{i}, plants)
177 error('Unexpected uel found in domain i');
178 end
179 elseif strcmp(domains{i}.name, 'j')
180 if ~check_uel(domains{i}, markets)
181 error('Unexpected uel found in domain j');
182 end
183 else
184 error('Expected Set i and j but found %s', domains{i}.name);
185 end
186 end
187
188 % *************************************************************** %
189 % This next section is acutally not about domain checking, but we %
190 % make sure that certain things are working as expected. %
191 % *************************************************************** %
192
193 aliasData = {
194 'Sets '
195 ' i canning plants / seattle, san-diego /; '
196 ' '
197 'Alias (i,ii); '};
198 aliasData = sprintf('%s\n', aliasData{:});
199
200 % Try reading an Alias as Set
201 aliasJob = ws.addJobFromString(aliasData);
202 aliasJob.run();
203 ii = aliasJob.outDB.getSet('ii');
204 fprintf('Elements of aliased Set:');
205 for rec = ii.records
206 fprintf(' > %s\n', rec{1}.key(1));
207 end
208
209 testDB = ws.addDatabase();
210 testSet = testDB.addSet('test', 1);
211
212 % Try adding empty UEL
213 testSet.addRecord('');
214 fprintf('Elements of test Set after adding empty UEL:\n');
215 fprintf(' > %d\n', testSet.numberOfRecords);
216
217 % GAMS strips pending blanks while leading blanks are relevant
218 rec = testSet.addRecord(' a ');
219 rec.text = 'a';
220 fprintf('Record '' a '' should be the same as '' a'':\n');
221 fprintf(' > %s\n', testSet.findRecord(' a').text);
222
223 % GAMS cannot handle UELs with more than 63 characters
224 % This should be OK ...
225 rec = testSet.addRecord('123456789012345678901234567890123456789012345678901234567890123 ');
226 rec.text = 'OK';
227 % ... but not this
228 try
229 error_thrown = true;
230 rec = testSet.addRecord('1234567890123456789012345678901234567890123456789012345678901234');
231 rec.text = 'not OK';
232 error_thrown = false;
233 catch
234 end
235 if ~error_thrown
236 error('It should not be possible to add a record with more than 63 characters');
237 end
238
239 % GAMS cannot handle explanatory texts with more than 255 characters
240 testDB.addSet('textOK', '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345');
241 try
242 error_thrown = true;
243 testDB.addSet('textNotOK', '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456');
244 error_thrown = false;
245 catch
246 end
247 if ~error_thrown
248 error('It should not be possible to add an explanatory text with more than 255 characters');
249 end
250
251 rec = testSet.addRecord('OK');
252 rec.text = '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345';
253 try
254 error_thrown = true;
255 rec = testSet.addRecord('notOK');
256 rec.text = '1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456';
257 error_thrown = false;
258 catch
259 end
260 if ~error_thrown
261 error('It should not be possible to add an explanatory text with more than 255 characters');
262 end
263
264 % GAMS can handle UELs containing single and double quotes but not at the same time
265 testSet.addRecord('quote''');
266 testSet.addRecord('quote"');
267 try
268 error_thrown = true;
269 testSet.addRecord('quote''"');
270 error_thrown = false;
271 catch
272 end
273 if ~error_thrown
274 error('It should not be possible to add a record single AND double quote');
275 end
276
277 testDB.export('test.gdx');
278
279 fprintf('successfully terminated!\n');
280
281end
282
283function dvCnt = list_domain_violations(symbolName, domViolations, dvCnt)
284 for j = 1:numel(domViolations)
285 fprintf(' > %s [', symbolName);
286 item1 = domViolations{j}.violationArray;
287 for k = 1:numel(item1)
288 if item1(k)
289 fprintf('true ');
290 dvCnt = dvCnt + 1;
291 else
292 fprintf('false ');
293 end
294 end
295 fprintf('] <> ');
296 item2 = domViolations{j}.record.keys;
297 for k = 1:numel(item2)
298 fprintf('%s ', item2{k});
299 end
300 fprintf('<<\n');
301 end
302end
303
304function ret = check_uel(symbol, uels)
305 ret = true;
306 for rec = symbol.records
307 key = rec{1}.key(1);
308 is_contained = false;
309 for i = 1:numel(uels)
310 if strcmp(key, uels{i})
311 is_contained = true;
312 break;
313 end
314 end
315 if ~is_contained
316 ret = false;
317 return
318 end
319 end
320 return
321end