Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 0.0% 0 / 0 / 196
Functions: -% 0 / 1 / 1
Branches: 0.0% 0 / 0 / 66

OMCompiler/Compiler/FrontEnd/UnitChecker.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package UnitChecker
37 "
38 file: UnitChecker.mo
39 package: UnitChecker
40 description: Physical unit checking.
41
42 This package is used for checking if an equation system is consistent, inconsistent or unknown (not enough information to determine).
43 "
44
45 public import UnitAbsyn;
46 public import MMath;
47 public import UnitAbsynBuilder;
48
49 protected import Debug;
50 protected import Error;
51 protected import Flags;
52 protected import HashTable;
53
54 public function check "Check if a list of unit terms are consistent"
55 input UnitAbsyn.UnitTerms tms;
56 input UnitAbsyn.InstStore ist;
57 output UnitAbsyn.InstStore outSt;
58 algorithm
59 outSt := matchcontinue(tms,ist)
60 local
61 UnitAbsyn.Store st1,st2;
62 UnitAbsyn.UnitTerms rest1;
63 UnitAbsyn.UnitTerm tm1;
64 UnitAbsyn.SpecUnit su1,su2;
65 String s1,s2,s3;
66 HashTable.HashTable ht;
67 UnitAbsyn.InstStore st;
68
69 case (_,st)
70 algorithm
71 // phi: very old unit checking
72 /*
73 false = Flags.getConfigBool(Flags.UNIT_CHECKING);
74 */
75 then (st);
76
77 // No more terms?
78 case ({},UnitAbsyn.INSTSTORE(st1,ht,_))
79 ✗ then UnitAbsyn.INSTSTORE(st1,ht,SOME(UnitAbsyn.CONSISTENT()));
80
81 // Is consistent?
82 case (tm1::rest1,UnitAbsyn.INSTSTORE(st1,ht,_))
83 algorithm
84 ✗ (UnitAbsyn.CONSISTENT(),_,st2) := checkTerm(tm1,st1);
85 ✗ st := check(rest1,UnitAbsyn.INSTSTORE(st2,ht,SOME(UnitAbsyn.CONSISTENT())));
86 then(st);
87
88 // Is inconsistent?
89 case (tm1::_,UnitAbsyn.INSTSTORE(st1,ht,_))
90 algorithm
91 ✗ (UnitAbsyn.INCONSISTENT(su1,su2),_,_) := checkTerm(tm1,st1);
92 ✗ s1 := UnitAbsynBuilder.printTermsStr({tm1});
93 ✗ s2 := UnitAbsynBuilder.unit2str(UnitAbsyn.SPECIFIED(su1));
94 ✗ s3 := UnitAbsynBuilder.unit2str(UnitAbsyn.SPECIFIED(su2));
95 ✗ Error.addMessage(Error.INCONSISTENT_UNITS,{s1,s2,s3});
96 ✗ then
97 UnitAbsyn.INSTSTORE(st1,ht,SOME(UnitAbsyn.INCONSISTENT(su1,su2)));
98
99 // failtrace
100 else
101 algorithm
102 ✗ true := Flags.isSet(Flags.FAILTRACE);
103 ✗ Debug.trace("UnitChecker::check() failed\n");
104 ✗ print("check failed\n");
105 ✗ then
106 fail();
107 end matchcontinue;
108 end check;
109
110 public function isComplete "returns true if the store is complete, else false"
111 input UnitAbsyn.Store st;
112 output Boolean complete;
113 output UnitAbsyn.Store stout;
114 algorithm
115 (complete,stout) := match st
116 local
117 array<Option<UnitAbsyn.Unit>> vector; Integer indx;
118 list<Option<UnitAbsyn.Unit>> lst;
119 Boolean comp;
120 UnitAbsyn.Store st2;
121
122 case UnitAbsyn.STORE(vector,indx)
123 algorithm
124 ✗ lst := arrayList(vector);
125 ✗ (comp,st2) := completeCheck(lst,1,UnitAbsyn.STORE(vector,indx));
126 then
127 (comp,st2);
128 end match;
129 end isComplete;
130
131 protected function completeCheck "help function to isComplete"
132 input list<Option<UnitAbsyn.Unit>> ilst;
133 input Integer indx;
134 input UnitAbsyn.Store st;
135 output Boolean isComplete;
136 output UnitAbsyn.Store stout;
137 algorithm
138 (isComplete,stout) := matchcontinue(ilst, st)
139 local
140 UnitAbsyn.Unit u2;
141 Boolean comp1;
142 UnitAbsyn.Store st2,st3;
143 list<Option<UnitAbsyn.Unit>> lst;
144
145 case ({}, st2) then (true,st2);
146
147 case (SOME(_)::lst, st2)
148 algorithm
149 ✗ (u2,st3) := normalize(indx,st2);
150 ✗ false := unitHasUnknown(u2);
151 ✗ (comp1,_) := completeCheck(lst,indx+1,st3);
152 ✗ then
153 (comp1,st3);
154
155 case (SOME(_)::_, st2)
156 algorithm
157 ✗ (u2,_) := normalize(indx,st2);
158 ✗ true := unitHasUnknown(u2);
159 then
160 (false,st2);
161
162 case(NONE()::_, st2) then (true,st2);
163 end matchcontinue;
164 end completeCheck;
165
166 public function checkTerm "check if one term is ok"
167 input UnitAbsyn.UnitTerm tm;
168 input UnitAbsyn.Store st;
169 output UnitAbsyn.UnitCheckResult result;
170 output UnitAbsyn.SpecUnit outUnit;
171 output UnitAbsyn.Store outSt;
172 algorithm
173 (result,outUnit,outSt) := matchcontinue(tm,st)
174 local
175 UnitAbsyn.Store st1,st2,st3,st4;
176 UnitAbsyn.UnitCheckResult res1,res2,res3,res4;
177 UnitAbsyn.UnitTerm ut1,ut2;
178 UnitAbsyn.SpecUnit su1,su2,su3;
179 MMath.Rational expo1;
180 Integer loc;
181
182 case (UnitAbsyn.ADD(ut1,ut2,_),st1)
183 algorithm
184 ✗ (res1,su1,st2) := checkTerm(ut1,st1);
185 ✗ (res2,su2,st3) := checkTerm(ut2,st2);
186 ✗ (res3,st4) := unify(su1,su2,st3);
187 ✗ res4 := chooseResult(res1,res2,res3);
188 ✗ then (res4,su1,st4);
189
190 case (UnitAbsyn.SUB(ut1,ut2,_),st1)
191 algorithm
192 ✗ (res1,su1,st2) := checkTerm(ut1,st1);
193 ✗ (res2,su2,st3) := checkTerm(ut2,st2);
194 ✗ (res3,st4) := unify(su1,su2,st3);
195 ✗ res4 := chooseResult(res1,res2,res3);
196 ✗ then (res4,su1,st4);
197
198 case (UnitAbsyn.MUL(ut1,ut2,_),st1)
199 algorithm
200 ✗ (res1,su1,st2) := checkTerm(ut1,st1);
201 ✗ (res2,su2,st3) := checkTerm(ut2,st2);
202 ✗ su3 := mulSpecUnit(su1,su2);
203 ✗ res4 := chooseResult(res1,res2,UnitAbsyn.CONSISTENT());
204 ✗ then(res4,su3,st3);
205
206 case (UnitAbsyn.DIV(ut1,ut2,_),st1)
207 algorithm
208 ✗ (res1,su1,st2) := checkTerm(ut1,st1);
209 ✗ (res2,su2,st3) := checkTerm(ut2,st2);
210 ✗ su3 := divSpecUnit(su1,su2);
211 ✗ res4 := chooseResult(res1,res2,UnitAbsyn.CONSISTENT());
212 ✗ then(res4,su3,st3);
213
214 case (UnitAbsyn.EQN(ut1,ut2,_),st1)
215 algorithm
216 ✗ (res1,su1,st2) := checkTerm(ut1,st1);
217 ✗ (res2,su2,st3) := checkTerm(ut2,st2);
218 ✗ (res3,st4) := unify(su1,su2,st3);
219 ✗ res4 := chooseResult(res1,res2,res3);
220 ✗ then(res4,su1,st4);
221
222 case (UnitAbsyn.LOC(loc,_),st1)
223 algorithm
224 ✗ UnitAbsyn.UNSPECIFIED() := UnitAbsynBuilder.find(loc,st1);
225 ✗ then(UnitAbsyn.CONSISTENT(),UnitAbsyn.SPECUNIT((MMath.RATIONAL(1,1),UnitAbsyn.TYPEPARAMETER("",loc))::{},{}),st1);
226
227 case (UnitAbsyn.LOC(loc,_),st1)
228 algorithm
229 ✗ UnitAbsyn.SPECIFIED(su1) := UnitAbsynBuilder.find(loc,st1);
230 then(UnitAbsyn.CONSISTENT(),su1,st1);
231
232 case (UnitAbsyn.POW(ut1,expo1,_),st1)
233 algorithm
234 ✗ (res1,su1,st2) := checkTerm(ut1,st1);
235 ✗ su2 := powSpecUnit(su1,expo1);
236 ✗ then(res1,su2,st2);
237
238 else
239 algorithm
240 ✗ true := Flags.isSet(Flags.FAILTRACE);
241 ✗ Debug.trace("UnitChecker::checkTerm() failed\n");
242 ✗ then fail();
243 end matchcontinue;
244 end checkTerm;
245
246 protected function chooseResult "Returns the first result that is UnitAbsyn.INCONSISTENT. If not, CONISTENT will be returned"
247 input UnitAbsyn.UnitCheckResult res1;
248 input UnitAbsyn.UnitCheckResult res2;
249 input UnitAbsyn.UnitCheckResult res3;
250 output UnitAbsyn.UnitCheckResult resout;
251 protected
252 UnitAbsyn.UnitCheckResult incon;
253 algorithm
254 resout := match(res1,res2,res3)
255 case(UnitAbsyn.CONSISTENT(),UnitAbsyn.CONSISTENT(),UnitAbsyn.CONSISTENT()) then UnitAbsyn.CONSISTENT();
256 case(UnitAbsyn.CONSISTENT(),UnitAbsyn.CONSISTENT(),incon) then incon;
257 case(UnitAbsyn.CONSISTENT(),incon,_) then incon;
258 case(incon,_,_) then incon;
259 else
260 algorithm
261 ✗ true := Flags.isSet(Flags.FAILTRACE);
262 ✗ Debug.trace("UnitChecker::chooseResult() failed\n");
263 ✗ then fail();
264 end match;
265 end chooseResult;
266
267 protected function unify
268 input UnitAbsyn.SpecUnit insu1;
269 input UnitAbsyn.SpecUnit insu2;
270 input UnitAbsyn.Store st;
271 output UnitAbsyn.UnitCheckResult outresult;
272 output UnitAbsyn.Store outSt;
273 protected
274 UnitAbsyn.SpecUnit su1,su2;
275 UnitAbsyn.Store st1,st2;
276 algorithm
277 ✗ (UnitAbsyn.SPECIFIED(su1),st1) := normalizeOnUnit(UnitAbsyn.SPECIFIED(insu1),st);
278 ✗ (UnitAbsyn.SPECIFIED(su2),st2) := normalizeOnUnit(UnitAbsyn.SPECIFIED(insu2),st1);
279 ✗ (outresult,outSt) := unifyunits(su1,su2,st2);
280 end unify;
281
282 protected function isSpecUnitEq "checks if twp spec units are equal (presupposed that they have no unknowns"
283 input UnitAbsyn.SpecUnit insu1;
284 input UnitAbsyn.SpecUnit insu2;
285 output Boolean res;
286 algorithm
287 res := match(insu1,insu2)
288 local
289 Boolean r1;
290 Integer i1a,i1b,i2a,i2b;
291 list<MMath.Rational> rest1,rest2;
292
293 case(UnitAbsyn.SPECUNIT(_,{}),UnitAbsyn.SPECUNIT(_,{}))
294 then true;
295
296 case(UnitAbsyn.SPECUNIT(_,{}),UnitAbsyn.SPECUNIT(_,MMath.RATIONAL(0,_)::rest1))
297 algorithm
298 ✗ r1 := isSpecUnitEq(UnitAbsyn.SPECUNIT({},{}), UnitAbsyn.SPECUNIT({},rest1));
299 then r1;
300
301 case(UnitAbsyn.SPECUNIT(_,MMath.RATIONAL(0,_)::rest1),UnitAbsyn.SPECUNIT(_,{}))
302 algorithm
303 ✗ r1 := isSpecUnitEq(UnitAbsyn.SPECUNIT({},rest1),UnitAbsyn.SPECUNIT({},{}));
304 then r1;
305
306 case(UnitAbsyn.SPECUNIT(_,MMath.RATIONAL(i1a,i1b)::rest1), UnitAbsyn.SPECUNIT(_,MMath.RATIONAL(i2a,i2b)::rest2)) guard intEq(i1a, i2a) and intEq(i1b, i2b)
307 algorithm
308 ✗ r1 := isSpecUnitEq(UnitAbsyn.SPECUNIT({},rest1),UnitAbsyn.SPECUNIT({},rest2));
309 then r1;
310
311 else
312 then false;
313 end match;
314 end isSpecUnitEq;
315
316 protected function unifyunits
317 input UnitAbsyn.SpecUnit insu1;
318 input UnitAbsyn.SpecUnit insu2;
319 input UnitAbsyn.Store st;
320 output UnitAbsyn.UnitCheckResult outresult;
321 output UnitAbsyn.Store outSt;
322 algorithm
323 (outresult,outSt) := matchcontinue(insu1,insu2,st)
324 local
325 UnitAbsyn.SpecUnit su1,su2,su3,su4;
326 UnitAbsyn.Store st1,st2;
327 Integer loc1;
328
329 // No unknown and the same on both sides
330 case(su1,su2,st1)
331 algorithm
332 ✗ false := hasUnknown(su1);
333 ✗ false := hasUnknown(su2);
334 ✗ true := isSpecUnitEq(su1,su2);
335 then
336 (UnitAbsyn.CONSISTENT(),st1);
337
338 // No unknown, but different on the sides
339 case(su1,su2,st1)
340 algorithm
341 ✗ false := hasUnknown(su1);
342 ✗ false := hasUnknown(su2);
343 ✗ then
344 (UnitAbsyn.INCONSISTENT(su1,su2),st1);
345
346 // Move the unknown to left side and substitute
347 case(su1,su2,st1)
348 algorithm
349 ✗ su3 := divSpecUnit(su2,su1);
350 ✗ (loc1,su4) := getUnknown(su3);
351 ✗ st2 := UnitAbsynBuilder.update(UnitAbsyn.SPECIFIED(su4),loc1,st1);
352 then
353 (UnitAbsyn.CONSISTENT(),st2);
354
355 // Unknowns are cancelling each other out
356 case(_,_,st1)
357 then(UnitAbsyn.CONSISTENT(),st1);
358 end matchcontinue;
359 end unifyunits;
360
361 public function newDimlessSpecUnit "creates a new dimensionless unit"
362 output UnitAbsyn.SpecUnit su;
363 algorithm
364 ✗ UnitAbsyn.SPECIFIED(su) := UnitAbsynBuilder.str2unit("1",NONE());
365 end newDimlessSpecUnit;
366
367 public function getUnknown "gets the first unknown in a specified unit"
368 input UnitAbsyn.SpecUnit suin;
369 output Integer loc;
370 output UnitAbsyn.SpecUnit suout;
371 algorithm
372 (loc,suout) := matchcontinue suin
373 local
374 UnitAbsyn.SpecUnit su1,su2;
375 MMath.Rational expo1,expo2;
376 Integer loc1;
377 list<MMath.Rational> unitvec1;
378 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> rest1;
379
380 case UnitAbsyn.SPECUNIT((expo1,UnitAbsyn.TYPEPARAMETER(_,loc1))::rest1,unitvec1)
381 algorithm
382 ✗ su1 := divSpecUnit(newDimlessSpecUnit(),UnitAbsyn.SPECUNIT(rest1,unitvec1));
383 ✗ expo2 := MMath.divRational(MMath.RATIONAL(1,1), expo1);
384 ✗ su2 := powSpecUnit(su1,expo2);
385 then (loc1,su2);
386
387 else
388 algorithm
389 ✗ true := Flags.isSet(Flags.FAILTRACE);
390 ✗ Debug.trace("UnitChecker::getUnknown() failed\n");
391 ✗ then
392 fail();
393 end matchcontinue;
394 end getUnknown;
395
396 public function hasUnknown
397 input UnitAbsyn.SpecUnit su;
398 output Boolean res;
399 algorithm
400 res := match su
401 case UnitAbsyn.SPECUNIT({},_) then false;
402 case UnitAbsyn.SPECUNIT(_,_) then true;
403 else
404 algorithm
405 ✗ true := Flags.isSet(Flags.FAILTRACE);
406 ✗ Debug.trace("UnitChecker::hasUnknown() failed\n");
407 ✗ then fail();
408 end match;
409 end hasUnknown;
410
411 public function unitHasUnknown
412 input UnitAbsyn.Unit u;
413 output Boolean res;
414 algorithm
415 res := match u
416 local
417 UnitAbsyn.SpecUnit su;
418 Boolean unk;
419 case UnitAbsyn.SPECIFIED(su)
420 algorithm
421 ✗ unk := hasUnknown(su);
422 then unk;
423 else true;
424 end match;
425 end unitHasUnknown;
426
427 public function mulSpecUnit "Multiplying two units corresponds to adding the units and joining the typeParameter list."
428 input UnitAbsyn.SpecUnit u1;
429 input UnitAbsyn.SpecUnit u2;
430 output UnitAbsyn.SpecUnit u;
431 algorithm
432 u := matchcontinue(u1,u2)
433 local
434 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> tparams1,tparams2,tparams3,tparams4;
435 list<MMath.Rational> units,units1,units2;
436
437 case (UnitAbsyn.SPECUNIT(tparams1,units1),UnitAbsyn.SPECUNIT(tparams2,units2))
438 algorithm
439 ✗ tparams3 := listAppend(tparams1,tparams2);
440 ✗ tparams4 := normalizeParamsExponents(tparams3);
441 ✗ units := mulUnitVec(units1,units2);
442 ✗ then
443 UnitAbsyn.SPECUNIT(tparams4,units);
444
445 else
446 algorithm
447 ✗ true := Flags.isSet(Flags.FAILTRACE);
448 ✗ Debug.trace("UnitChecker::mulSpecUnit() failed\n");
449 ✗ then
450 fail();
451 end matchcontinue;
452 end mulSpecUnit;
453
454 public function mulUnitVec "multiplication of two unit vector"
455 input list<MMath.Rational> inunitvec1;
456 input list<MMath.Rational> inunitvec2;
457 output list<MMath.Rational> outunitvec;
458 algorithm
459 outunitvec := matchcontinue(inunitvec1,inunitvec2)
460 local
461 MMath.Rational expo1,expo2,expo3;
462 list<MMath.Rational> rest1,rest2,rest3;
463
464 // empty list
465 case ({},{}) then {};
466
467 case(expo1::rest1,expo2::rest2)
468 algorithm
469 ✗ expo3 := MMath.addRational(expo1,expo2);
470 ✗ rest3 := mulUnitVec(rest1,rest2);
471 then
472 (expo3::rest3);
473
474 case(expo1::rest1,{})
475 algorithm
476 ✗ rest3 := mulUnitVec(rest1,{});
477 then
478 (expo1::rest3);
479
480 case({},expo1::rest1)
481 algorithm
482 ✗ rest3 := mulUnitVec({},rest1);
483 then (expo1::rest3);
484
485 else
486 algorithm
487 ✗ true := Flags.isSet(Flags.FAILTRACE);
488 ✗ Debug.trace("UnitChecker::powUnitVec() failed\n");
489 ✗ then fail();
490 end matchcontinue;
491 end mulUnitVec;
492
493 public function divSpecUnit "Divide two specified units"
494 input UnitAbsyn.SpecUnit u1;
495 input UnitAbsyn.SpecUnit u2;
496 output UnitAbsyn.SpecUnit u;
497 algorithm
498 u := matchcontinue(u1,u2)
499 local
500 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> tparams1,tparams2,tparams3,tparams4,tparams5;
501 list<MMath.Rational> units,units1,units2;
502
503 case(UnitAbsyn.SPECUNIT(tparams1,units1),UnitAbsyn.SPECUNIT(tparams2,units2))
504 algorithm
505 ✗ tparams3 := negParamList(tparams2,{});
506 ✗ tparams4 := listAppend(tparams1,tparams3);
507 ✗ tparams5 := normalizeParamsExponents(tparams4);
508 ✗ units := divUnitVec(units1,units2);
509 ✗ then
510 UnitAbsyn.SPECUNIT(tparams5,units);
511
512 else
513 algorithm
514 ✗ true := Flags.isSet(Flags.FAILTRACE);
515 ✗ Debug.trace("UnitChecker::divSpecUnit() failed\n");
516 ✗ then fail();
517 end matchcontinue;
518 end divSpecUnit;
519
520 public function divUnitVec "division of two unit vectors"
521 input list<MMath.Rational> inunitvec1;
522 input list<MMath.Rational> inunitvec2;
523 output list<MMath.Rational> outunitvec;
524 algorithm
525 outunitvec := matchcontinue(inunitvec1,inunitvec2)
526 local
527 MMath.Rational expo1,expo2,expo3;
528 list<MMath.Rational> rest1,rest2,rest3;
529
530 case ({},{}) then {};
531
532 case(expo1::rest1,expo2::rest2)
533 algorithm
534 ✗ expo3 := MMath.subRational(expo1,expo2);
535 ✗ rest3 := divUnitVec(rest1,rest2);
536 then
537 (expo3::rest3);
538
539 case(expo1::rest1,{})
540 algorithm
541 ✗ rest3 := divUnitVec(rest1,{});
542 then
543 (expo1::rest3);
544
545 case({},expo1::rest1)
546 algorithm
547 ✗ expo2 := MMath.subRational(MMath.RATIONAL(0,1),expo1);
548 ✗ rest3 := divUnitVec({},rest1);
549 then
550 (expo2::rest3);
551
552 else
553 algorithm
554 ✗ true := Flags.isSet(Flags.FAILTRACE);
555 ✗ Debug.trace("UnitChecker::powUnitVec() failed\n");
556 ✗ then fail();
557 end matchcontinue;
558 end divUnitVec;
559
560 public function powSpecUnit "Power of a specified unit"
561 input UnitAbsyn.SpecUnit suin;
562 input MMath.Rational expo;
563 output UnitAbsyn.SpecUnit uout;
564 algorithm
565 uout := matchcontinue suin
566 local
567 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> params1,params2;
568 list<MMath.Rational> unitvec1,unitvec2;
569
570 case UnitAbsyn.SPECUNIT(params1,unitvec1)
571 algorithm
572 ✗ params2 := powUnitParams(params1,expo);
573 ✗ unitvec2 := powUnitVec(unitvec1,expo);
574 ✗ then
575 UnitAbsyn.SPECUNIT(params2,unitvec2);
576
577 else
578 algorithm
579 ✗ true := Flags.isSet(Flags.FAILTRACE);
580 ✗ Debug.trace("UnitChecker::powSpecUnit() failed\n");
581 ✗ then
582 fail();
583 end matchcontinue;
584 end powSpecUnit;
585
586 public function powUnitParams "exponent power of the unit type parameters"
587 input list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> inparams;
588 input MMath.Rational expo;
589 output list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> outparams;
590 algorithm
591 outparams := matchcontinue(inparams,expo)
592 local
593 MMath.Rational expo1,expo2,expo3;
594 UnitAbsyn.TypeParameter param;
595 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> rest1,rest2;
596
597 case ({},_) then {};
598
599 case((expo1,param)::rest1,expo2)
600 algorithm
601 ✗ expo3 := MMath.multRational(expo1,expo2);
602 ✗ rest2 := powUnitParams(rest1,expo2);
603 ✗ then
604 ((expo3,param)::rest2);
605
606 else
607 algorithm
608 ✗ true := Flags.isSet(Flags.FAILTRACE);
609 ✗ Debug.trace("UnitChecker::powUnitParams() failed\n");
610 ✗ then fail();
611 end matchcontinue;
612 end powUnitParams;
613
614 public function powUnitVec "exponent power of the unit vector"
615 input list<MMath.Rational> inunitvec;
616 input MMath.Rational expo;
617 output list<MMath.Rational> outunitvec;
618 algorithm
619 outunitvec := matchcontinue(inunitvec,expo)
620 local
621 MMath.Rational expo1,expo2,expo3;
622 list<MMath.Rational> rest1,rest2;
623
624 case ({},_) then {};
625
626 case(expo1::rest1,expo2)
627 algorithm
628 ✗ expo3 := MMath.multRational(expo1,expo2);
629 ✗ rest2 := powUnitVec(rest1,expo2);
630 then
631 (expo3::rest2);
632
633 else
634 algorithm
635 ✗ true := Flags.isSet(Flags.FAILTRACE);
636 ✗ Debug.trace("UnitChecker::powUnitVec() failed\n");
637 ✗ then fail();
638 end matchcontinue;
639 end powUnitVec;
640
641 protected function negParamList
642 input list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> ine;
643 input list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> ac;
644 output list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> oute;
645 algorithm
646 oute := matchcontinue(ine,ac)
647 local
648 MMath.Rational qr;
649 Integer i1,i2,indx;
650 String name;
651 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> rest,pres,ac2;
652
653 case ({},ac2) then ac2;
654
655 case ((MMath.RATIONAL(i1,i2),UnitAbsyn.TYPEPARAMETER(name,indx))::rest,ac2)
656 algorithm
657 ✗ qr := MMath.multRational(MMath.RATIONAL(-1,1),MMath.RATIONAL(i1,i2));
658 ✗ pres := negParamList(rest,(qr,UnitAbsyn.TYPEPARAMETER(name,indx))::ac2);
659 then pres;
660
661 else
662 algorithm
663 ✗ true := Flags.isSet(Flags.FAILTRACE);
664 ✗ Debug.trace("UnitChecker::negParamList() failed\n");
665 ✗ then fail();
666 end matchcontinue;
667 end negParamList;
668
669 public function normalize "normalizes the unit pointed by 'loc'. Returns the normalized unit."
670 input Integer loc;
671 input UnitAbsyn.Store st;
672 output UnitAbsyn.Unit unit;
673 output UnitAbsyn.Store outSt;
674 protected
675 UnitAbsyn.Unit u1,u2;
676 UnitAbsyn.Store st2;
677 algorithm
678 ✗ u1 := UnitAbsynBuilder.find(loc,st);
679 ✗ (u2,st2) := normalizeOnUnit(u1,st);
680 ✗ outSt := UnitAbsynBuilder.update(u2,loc,st2);
681 unit := u2;
682 end normalize;
683
684 public function normalizeOnUnit "switch on each kind of unit"
685 input UnitAbsyn.Unit u;
686 input UnitAbsyn.Store st;
687 output UnitAbsyn.Unit unit;
688 output UnitAbsyn.Store outSt;
689 algorithm
690 (unit,outSt) := matchcontinue u
691 local
692 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> params1,params2,params3;
693 list<MMath.Rational> unitvec1,unitvec2;
694 UnitAbsyn.Store st2;
695
696 case UnitAbsyn.UNSPECIFIED()
697 then (UnitAbsyn.UNSPECIFIED(),st);
698
699 case UnitAbsyn.SPECIFIED(UnitAbsyn.SPECUNIT(params1,unitvec1))
700 algorithm
701 ✗ (UnitAbsyn.SPECUNIT(params2,unitvec2),st2) := normalizeParamsValues(params1,UnitAbsyn.SPECUNIT({},unitvec1),st);
702 ✗ params3 := normalizeParamsExponents(params2);
703 ✗ then
704 (UnitAbsyn.SPECIFIED(UnitAbsyn.SPECUNIT(params3,unitvec2)),st2);
705
706 else
707 algorithm
708 ✗ true := Flags.isSet(Flags.FAILTRACE);
709 ✗ Debug.trace("UnitChecker::normalizeOnUnit() failed\n");
710 ✗ then fail();
711 end matchcontinue;
712 end normalizeOnUnit;
713
714 protected function normalizeParamsExponents "normalize the exponents of a parameter list"
715 input list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> inparams;
716 output list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> outparams;
717 algorithm
718 outparams := matchcontinue inparams
719 local
720 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> rest1,rest2,rest3;
721 String name;
722 Integer loc1;
723 MMath.Rational expo1,expo2,expo3;
724 tuple<MMath.Rational,UnitAbsyn.TypeParameter> param;
725
726 // Case: No more elements in list
727 case {} then {};
728
729 // Case: Found duplicate parameter in list
730 case (expo1,UnitAbsyn.TYPEPARAMETER(name,loc1))::rest1
731 algorithm
732 ✗ (true,expo2,rest2) := getParam(rest1,loc1);
733 ✗ expo3 := MMath.addRational(expo1,expo2);
734 ✗ rest3 := normalizeParamsExponents((expo3,UnitAbsyn.TYPEPARAMETER(name,loc1))::rest2);
735 then
736 rest3;
737
738 // Case: No duplicates in list and exponent IS zero
739 case (MMath.RATIONAL(0,1),_)::rest1
740 algorithm
741 ✗ rest2 := normalizeParamsExponents(rest1);
742 then
743 rest2;
744
745 // Case: No duplicates in list and exponent is not zero
746 case param::rest1
747 algorithm
748 ✗ rest2 := normalizeParamsExponents(rest1);
749 then
750 (param::rest2);
751
752 else
753 algorithm
754 ✗ true := Flags.isSet(Flags.FAILTRACE);
755 ✗ Debug.trace("UnitChecker::normalizeParamsExponents() failed\n");
756 ✗ then
757 fail();
758 end matchcontinue;
759 end normalizeParamsExponents;
760
761 protected function getParam "returns the next param in list and removes it from the list. 'found'=true if an location existed"
762 input list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> inparams;
763 input Integer loc;
764 output Boolean found;
765 output MMath.Rational outexpo;
766 output list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> outparams;
767 algorithm
768 (found,outexpo,outparams) := match inparams
769 local
770 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> rest,rest2;
771 Integer loc2;
772 MMath.Rational expo;
773 Boolean found2;
774 tuple<MMath.Rational,UnitAbsyn.TypeParameter> param;
775
776 case {} then (false,MMath.RATIONAL(1,1),{});
777
778 case (expo,UnitAbsyn.TYPEPARAMETER(_,loc2))::rest guard intEq(loc2, loc)
779 then
780 (true,expo,rest);
781
782 case param::rest
783 algorithm
784 ✗ (found2,expo,rest2) := getParam(rest,loc);
785 ✗ then
786 (found2,expo,param::rest2);
787
788 else
789 algorithm
790 ✗ true := Flags.isSet(Flags.FAILTRACE);
791 ✗ Debug.trace("UnitChecker::getParam() failed\n");
792 ✗ then fail();
793 end match;
794 end getParam;
795
796 protected function normalizeParamsValues "normalize the values that the the list of unit parameters points at"
797 input list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> inparams;
798 input UnitAbsyn.SpecUnit suin;
799 input UnitAbsyn.Store st;
800 output UnitAbsyn.SpecUnit uout;
801 output UnitAbsyn.Store outSt;
802 algorithm
803 (uout,outSt) := matchcontinue inparams
804 local
805 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> rest;
806 UnitAbsyn.Store st2,st3;
807 UnitAbsyn.Unit u2;
808 UnitAbsyn.SpecUnit su2,su3;
809 String name;
810 Integer loc;
811 MMath.Rational expo;
812
813 ✗ case {} then (suin,st);
814
815 case (expo,UnitAbsyn.TYPEPARAMETER(name,loc))::rest
816 algorithm
817 ✗ (u2,st2) := normalize(loc,st);
818 ✗ su2 := mulSpecUnitWithNorm(suin,u2,name,loc,expo);
819 ✗ (su3,st3) := normalizeParamsValues(rest,su2,st2);
820 then
821 (su3,st3);
822
823 else
824 algorithm
825 ✗ true := Flags.isSet(Flags.FAILTRACE);
826 ✗ Debug.trace("UnitChecker::normalizeParamsValues() failed\n");
827 ✗ then fail();
828 end matchcontinue;
829 end normalizeParamsValues;
830
831 protected function mulSpecUnitWithNorm
832 input UnitAbsyn.SpecUnit suin;
833 input UnitAbsyn.Unit normunit;
834 input String name;
835 input Integer loc;
836 input MMath.Rational expo;
837 output UnitAbsyn.SpecUnit suout;
838 algorithm
839 suout := matchcontinue(suin, normunit)
840 local
841 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> params;
842 list<MMath.Rational> unitvec;
843 UnitAbsyn.SpecUnit su2,sunorm,su3,su4;
844
845 case (UnitAbsyn.SPECUNIT(params,unitvec), UnitAbsyn.UNSPECIFIED())
846 ✗ then (UnitAbsyn.SPECUNIT((expo,UnitAbsyn.TYPEPARAMETER(name,loc))::params,unitvec));
847
848 case (su2, UnitAbsyn.SPECIFIED(sunorm))
849 algorithm
850 ✗ su3 := powSpecUnit(sunorm,expo);
851 ✗ su4 := mulSpecUnit(su2,su3);
852 then
853 su4;
854
855 else
856 algorithm
857 ✗ true := Flags.isSet(Flags.FAILTRACE);
858 ✗ Debug.trace("UnitChecker::mulSpecUnitWithNorm() failed\n");
859 ✗ then fail();
860 end matchcontinue;
861 end mulSpecUnitWithNorm;
862
863 public function printSpecUnit
864 input String text;
865 input UnitAbsyn.SpecUnit su;
866 algorithm
867 () := match(text,su)
868 local
869 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> params;
870 String str;
871
872 case(str,UnitAbsyn.SPECUNIT(params,_))
873 algorithm
874 ✗ print(str);
875 ✗ print(" \"");
876 ✗ print(UnitAbsynBuilder.unit2str(UnitAbsyn.SPECIFIED(su)));
877 ✗ print("\" {");
878 ✗ printSpecUnitParams(params);
879 ✗ print("}\n");
880 then ();
881 end match;
882 end printSpecUnit;
883
884 public function printSpecUnitParams
885 input list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> params;
886 algorithm
887 () := match params
888 local
889 String name;
890 Integer i1,i2,loc;
891 list<tuple<MMath.Rational,UnitAbsyn.TypeParameter>> rest;
892
893 case {} then ();
894
895 case (MMath.RATIONAL(i1,i2),UnitAbsyn.TYPEPARAMETER(name,loc))::rest
896 algorithm
897 ✗ print("(\"");
898 ✗ print(name);
899 ✗ print("\",");
900 ✗ print(intString(loc));
901 ✗ print(")^(");
902 ✗ print(intString(i1));
903 ✗ print("/");
904 ✗ print(intString(i2));
905 ✗ print("),");
906 ✗ printSpecUnitParams(rest);
907 then ();
908 end match;
909 end printSpecUnitParams;
910
911 public function testUnitOp "Test unit operations"
912 protected
913 algorithm
914 ✗ print("test");
915 end testUnitOp;
916
917 public function printResult "Print out the result from the unit check"
918 input UnitAbsyn.UnitCheckResult res;
919 algorithm
920 () := match res
921 local
922 UnitAbsyn.SpecUnit u1,u2;
923 String str1,str2;
924
925 case UnitAbsyn.CONSISTENT()
926 algorithm
927 ✗ print("\n---\nThe system of units is consistent.\n---\n");
928 then ();
929
930 case UnitAbsyn.INCONSISTENT(u1,u2)
931 algorithm
932 ✗ print("\n---\nThe system of units is inconsistent. \"");
933 ✗ str1 := UnitAbsynBuilder.unit2str(UnitAbsyn.SPECIFIED(u1));
934 ✗ print(str1);
935 ✗ print("\" != \"");
936 ✗ str2 := UnitAbsynBuilder.unit2str(UnitAbsyn.SPECIFIED(u2));
937 ✗ print(str2);
938 ✗ print("\"\n---\n");
939 then ();
940 end match;
941 end printResult;
942
943 annotation(__OpenModelica_Interface="frontend");
944 end UnitChecker;
945