Skip to content

Commit 476ac8c

Browse files
authored
[NB] Simplify if-equation structure (#12790)
1 parent 56fe5ad commit 476ac8c

File tree

6 files changed

+240
-17
lines changed

6 files changed

+240
-17
lines changed

OMCompiler/Compiler/NBackEnd/Classes/NBEquation.mo

Lines changed: 87 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -701,7 +701,7 @@ public
701701
tupl_recd_str := if Type.isTuple(eq.ty) then "[TUPL] " else "[RECD] ";
702702
then str + tupl_recd_str + s + " " + Expression.toString(eq.lhs) + " = " + Expression.toString(eq.rhs) + EquationAttributes.toString(eq.attr, " ");
703703
case ALGORITHM() then str + "[ALGO] " + s + EquationAttributes.toString(eq.attr, " ") + "\n" + Algorithm.toString(eq.alg, str + "[----] ");
704-
case IF_EQUATION() then str + IfEquationBody.toString(eq.body, str + "[----] ", "[-IF-] " + s + EquationAttributes.toString(eq.attr, " "));
704+
case IF_EQUATION() then str + IfEquationBody.toString(eq.body, str + "[----] ", "[-IF-] " + s + EquationAttributes.toString(eq.attr, " ") + "\n");
705705
case FOR_EQUATION() then str + forEquationToString(eq.iter, eq.body, "", str + "[----] ", "[FOR-] " + s + EquationAttributes.toString(eq.attr, " "));
706706
case WHEN_EQUATION() then str + WhenEquationBody.toString(eq.body, str + "[----] ", "[WHEN] " + s + EquationAttributes.toString(eq.attr, " ") + "\n");
707707
case AUX_EQUATION() then str + "[AUX-] " + s + "Auxiliary equation for " + Variable.toString(Pointer.access(eq.auxiliary));
@@ -1338,6 +1338,7 @@ public
13381338
algorithm
13391339
e := func(e);
13401340
end apply;
1341+
Equation old_eq;
13411342
algorithm
13421343
if Flags.isSet(Flags.DUMP_SIMPLIFY) and not stringEqual(indent, "") then
13431344
print("\n");
@@ -1347,10 +1348,10 @@ public
13471348
eq := map(eq, simplifyExp, mapFunc = apply);
13481349

13491350
// simplify equation structure
1351+
old_eq := eq;
13501352
eq := match eq
13511353
local
13521354
Equation new_eq;
1353-
WhenEquationBody body;
13541355

13551356
case SCALAR_EQUATION() algorithm
13561357
if Expression.isEqual(eq.lhs, eq.rhs) then
@@ -1376,8 +1377,22 @@ public
13761377
case ALGORITHM() algorithm
13771378
eq.alg := SimplifyModel.simplifyAlgorithm(eq.alg);
13781379
then eq;
1380+
13791381
case WHEN_EQUATION() algorithm
13801382
new_eq := match WhenEquationBody.simplify(SOME(eq.body))
1383+
local
1384+
WhenEquationBody body;
1385+
case SOME(body) algorithm
1386+
eq.body := body;
1387+
then eq;
1388+
else Equation.DUMMY_EQUATION();
1389+
end match;
1390+
then new_eq;
1391+
1392+
case IF_EQUATION() algorithm
1393+
new_eq := match IfEquationBody.simplify(SOME(eq.body))
1394+
local
1395+
IfEquationBody body;
13811396
case SOME(body) algorithm
13821397
eq.body := body;
13831398
then eq;
@@ -1387,13 +1402,18 @@ public
13871402

13881403
// ToDo: implement the following correctly:
13891404

1390-
case IF_EQUATION() then eq;
13911405
case FOR_EQUATION() then eq;
13921406
case AUX_EQUATION() then eq;
13931407
else algorithm
13941408
Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed for: " + toString(eq)});
13951409
then fail();
13961410
end match;
1411+
1412+
if Flags.isSet(Flags.DUMP_SIMPLIFY) and not isEqual(old_eq, eq) then
1413+
print(indent + "### dumpSimplify | " + name + " ###\n");
1414+
print(indent + "[BEFORE]\n" + toString(old_eq, indent + " ") + "\n");
1415+
print(indent + "[AFTER ]\n" + toString(eq, indent + " ") + "\n\n");
1416+
end if;
13971417
end simplify;
13981418

13991419
function createName
@@ -2297,20 +2317,21 @@ public
22972317
input String elseStr = "";
22982318
input Boolean selfCall = false;
22992319
output String str;
2300-
protected
2301-
IfEquationBody elseIf;
23022320
algorithm
2321+
str := elseStr;
2322+
if not selfCall then
2323+
str := str + indent;
2324+
end if;
23032325
if not Expression.isEnd(body.condition) then
2304-
str := elseStr + "if " + Expression.toString(body.condition) + " then\n";
2326+
str := str + "if " + Expression.toString(body.condition) + " then\n";
23052327
else
2306-
str := elseStr + "\n";
2328+
str := str + "\n";
23072329
end if;
23082330
for eqn in body.then_eqns loop
23092331
str := str + Equation.toString(Pointer.access(eqn), indent + " ") + "\n";
23102332
end for;
23112333
if isSome(body.else_if) then
2312-
SOME(elseIf) := body.else_if;
2313-
str := str + toString(elseIf, indent, indent + "else", true);
2334+
str := str + toString(Util.getOption(body.else_if), indent, indent + "else", true);
23142335
end if;
23152336
if not selfCall then
23162337
str := str + indent + "end if;";
@@ -2507,6 +2528,60 @@ public
25072528
end for;
25082529
end split;
25092530

2531+
function simplify
2532+
input output Option<IfEquationBody> body;
2533+
input Integer depth = 1;
2534+
input Boolean done = false;
2535+
algorithm
2536+
body := match body
2537+
local
2538+
IfEquationBody b;
2539+
Expression condition;
2540+
list<Expression> conditions;
2541+
2542+
case SOME(b) algorithm
2543+
if done then
2544+
b.condition := Expression.END();
2545+
b.else_if := NONE();
2546+
end if;
2547+
// if the condition is True -> cut later unreachable branches
2548+
if Expression.isTrue(b.condition) then
2549+
// FIXME can't yet handle removing the IF altogether so at least two branches have to remain.
2550+
if depth >= 2 then
2551+
b.condition := Expression.END();
2552+
b.else_if := NONE();
2553+
else
2554+
b.else_if := simplify(b.else_if, depth + 1, true);
2555+
end if;
2556+
else
2557+
b.else_if := simplify(b.else_if, depth + 1);
2558+
end if;
2559+
// if the condition is False -> skip this unreachable branch
2560+
// FIXME can't yet handle removing the IF altogether so at least two branches have to remain.
2561+
if Expression.isFalse(b.condition) and depth - 1 + numberOfBranches(b.else_if) >= 2 then
2562+
body := b.else_if;
2563+
else
2564+
body := SOME(b);
2565+
end if;
2566+
then body;
2567+
2568+
// NONE() stays NONE()
2569+
else body;
2570+
end match;
2571+
end simplify;
2572+
2573+
function numberOfBranches
2574+
input Option<IfEquationBody> body;
2575+
output Integer numBranches;
2576+
algorithm
2577+
numBranches := match body
2578+
local
2579+
IfEquationBody b;
2580+
case SOME(b) then 1 + numberOfBranches(b.else_if);
2581+
else 0;
2582+
end match;
2583+
end numberOfBranches;
2584+
25102585
function isRecordOrTupleEquation
25112586
"only checks first layer body if it returns multiple variables"
25122587
input IfEquationBody body;
@@ -2585,20 +2660,17 @@ public
25852660
input String elseStr = "";
25862661
input Boolean selfCall = false;
25872662
output String str;
2588-
protected
2589-
WhenEquationBody elseWhen;
25902663
algorithm
25912664
str := elseStr;
25922665
if not selfCall then
25932666
str := str + indent;
25942667
end if;
2595-
str := str + "when " + Expression.toString(body.condition) + " then \n";
2668+
str := str + "when " + Expression.toString(body.condition) + " then\n";
25962669
for stmt in body.when_stmts loop
25972670
str := str + WhenStatement.toString(stmt, indent + " ") + "\n";
25982671
end for;
25992672
if isSome(body.else_when) then
2600-
SOME(elseWhen) := body.else_when;
2601-
str := str + toString(elseWhen, indent, indent +"else ", true);
2673+
str := str + toString(Util.getOption(body.else_when), indent, indent + "else", true);
26022674
end if;
26032675
if not selfCall then
26042676
str := str + indent + "end when;";
@@ -2631,7 +2703,7 @@ public
26312703
input WhenEquationBody body2;
26322704
output Boolean b;
26332705
algorithm
2634-
b := List.all(List.zip(body1.when_stmts, body2.when_stmts), WhenStatement.isEqualTpl) and Util.optionEqual(body1.else_when, body2.else_when, isEqual);
2706+
b := Expression.isEqual(body1.condition, body2.condition) and List.all(List.zip(body1.when_stmts, body2.when_stmts), WhenStatement.isEqualTpl) and Util.optionEqual(body1.else_when, body2.else_when, isEqual);
26352707
end isEqual;
26362708

26372709
function getBodyAttributes

OMCompiler/Compiler/NBackEnd/Modules/2_Pre/NBEvents.mo

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,6 +1018,7 @@ protected
10181018
Expression condition;
10191019

10201020
// logical unarys: e.g. not a
1021+
// FIXME this is wrong for `not initial()`
10211022
case Expression.LUNARY() algorithm
10221023
(exp, bucket) := collectEventsCondition(exp, Pointer.access(bucket_ptr), iter, eqn, funcTree, createAux);
10231024
Pointer.update(bucket_ptr, bucket);

testsuite/simulation/modelica/NBackend/event_handling/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ TESTFILES = \
44
compositeEvent.mos \
55
eventSystem.mos \
66
hybridSys.mos \
7-
simplifyWhen.mos\
87

98
# test that currently fail. Move up when fixed.
109
# Run make failingtest
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
TEST = ../../../../rtest -v
2+
3+
TESTFILES = \
4+
simplifyIf.mos\
5+
simplifyWhen.mos\
6+
7+
# test that currently fail. Move up when fixed.
8+
# Run make failingtest
9+
FAILINGTESTFILES = \
10+
11+
# Dependency files that are not .mo .mos or Makefile
12+
# Add them here or they will be cleaned.
13+
DEPENDENCIES = \
14+
*.mo \
15+
*.mos \
16+
Makefile \
17+
18+
CLEAN = `ls | grep -w -v -f deps.tmp`
19+
20+
.PHONY : test clean getdeps failingtest
21+
22+
test:
23+
@echo
24+
@echo Running tests...
25+
@echo
26+
@echo OPENMODELICAHOME=" $(OPENMODELICAHOME) "
27+
@$(TEST) $(TESTFILES)
28+
29+
# Cleans all files that are not listed as dependencies
30+
clean:
31+
@echo $(DEPENDENCIES) | sed 's/ /\\|/g' > deps.tmp
32+
@rm -f $(CLEAN)
33+
34+
# Run this if you want to list out the files (dependencies).
35+
# do it after cleaning and updating the folder
36+
# then you can get a list of file names (which must be dependencies
37+
# since you got them from repository + your own new files)
38+
# then add them to the DEPENDENCIES. You can find the
39+
# list in deps.txt
40+
getdeps:
41+
@echo $(DEPENDENCIES) | sed 's/ /\\|/g' > deps.tmp
42+
@echo $(CLEAN) | sed -r 's/deps.txt|deps.tmp//g' | sed 's/ / \\\n/g' > deps.txt
43+
@echo Dependency list saved in deps.txt.
44+
@echo Copy the list from deps.txt and add it to the Makefile @DEPENDENCIES
45+
46+
failingtest:
47+
@echo
48+
@echo Running failing tests...
49+
@echo
50+
@$(TEST) $(FAILINGTESTFILES)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// name: simplifyIf
2+
// keywords: NewBackend
3+
// status: correct
4+
5+
loadString("
6+
model SimplifyIf
7+
Integer n;
8+
Boolean b = true;
9+
equation
10+
if initial() then
11+
n = 1;
12+
elseif time > 0.5 then
13+
n = 2;
14+
elseif b then
15+
n = 3;
16+
else
17+
n = 4;
18+
end if;
19+
end SimplifyIf;
20+
"); getErrorString();
21+
setCommandLineOptions("--newBackend -d=dumpSimplify"); getErrorString();
22+
buildModel(SimplifyIf); getErrorString();
23+
24+
// Result:
25+
// true
26+
// ""
27+
// true
28+
// ""
29+
// ### dumpSimplify | NBackendDAE.simplify ###
30+
// [BEFORE]
31+
// [-IF-] (1) ($RES_SIM_0)
32+
// [----] if initial() then
33+
// [----] [SCAL] (1) n = 1 ($RES_SIM_1)
34+
// [----] elseif time > 0.5 then
35+
// [----] [SCAL] (1) n = 2 ($RES_SIM_2)
36+
// [----] elseif true then
37+
// [----] [SCAL] (1) n = 3 ($RES_SIM_3)
38+
// [----] else
39+
// [----] [SCAL] (1) n = 4 ($RES_SIM_4)
40+
// [----] end if;
41+
// [AFTER ]
42+
// [-IF-] (1) ($RES_SIM_0)
43+
// [----] if initial() then
44+
// [----] [SCAL] (1) n = 1 ($RES_SIM_1)
45+
// [----] elseif time > 0.5 then
46+
// [----] [SCAL] (1) n = 2 ($RES_SIM_2)
47+
// [----] else
48+
// [----] [SCAL] (1) n = 3 ($RES_SIM_3)
49+
// [----] end if;
50+
//
51+
// ### dumpSimplify | ###
52+
// [BEFORE]
53+
// [-IF-] (1) ($RES_SIM_0)
54+
// [----] if false then
55+
// [----] [SCAL] (1) n = 1 ($RES_SIM_1)
56+
// [----] elseif $TEV_0 then
57+
// [----] [SCAL] (1) n = 2 ($RES_SIM_2)
58+
// [----] else
59+
// [----] [SCAL] (1) n = 3 ($RES_SIM_3)
60+
// [----] end if;
61+
// [AFTER ]
62+
// [-IF-] (1) ($RES_SIM_0)
63+
// [----] if $TEV_0 then
64+
// [----] [SCAL] (1) n = 2 ($RES_SIM_2)
65+
// [----] else
66+
// [----] [SCAL] (1) n = 3 ($RES_SIM_3)
67+
// [----] end if;
68+
//
69+
// ### dumpSimplify | ###
70+
// [BEFORE]
71+
// [-IF-] (1) ($RES_SIM_0)
72+
// [----] if true then
73+
// [----] [SCAL] (1) n = 1 ($RES_SIM_1)
74+
// [----] elseif $TEV_0 then
75+
// [----] [SCAL] (1) n = 2 ($RES_SIM_2)
76+
// [----] else
77+
// [----] [SCAL] (1) n = 3 ($RES_SIM_3)
78+
// [----] end if;
79+
// [AFTER ]
80+
// [-IF-] (1) ($RES_SIM_0)
81+
// [----] if true then
82+
// [----] [SCAL] (1) n = 1 ($RES_SIM_1)
83+
// [----] else
84+
// [----] [SCAL] (1) n = 2 ($RES_SIM_2)
85+
// [----] end if;
86+
//
87+
// {"SimplifyIf","SimplifyIf_init.xml"}
88+
// ""
89+
// endResult

testsuite/simulation/modelica/NBackend/event_handling/simplifyWhen.mos renamed to testsuite/simulation/modelica/NBackend/simplification/simplifyWhen.mos

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,26 @@ equation
1111
end when;
1212
end SimplifyWhen;
1313
"); getErrorString();
14-
setCommandLineOptions("--newBackend"); getErrorString();
14+
setCommandLineOptions("--newBackend -d=dumpSimplify"); getErrorString();
1515
buildModel(SimplifyWhen); getErrorString();
1616

1717
// Result:
1818
// true
1919
// ""
2020
// true
2121
// ""
22+
// ### dumpSimplify | ###
23+
// [BEFORE]
24+
// [WHEN] (1) ($RES_SIM_0)
25+
// [----] when {$TEV_0, false} then
26+
// [----] n := integer(time)
27+
// [----] end when;
28+
// [AFTER ]
29+
// [WHEN] (1) ($RES_SIM_0)
30+
// [----] when $TEV_0 then
31+
// [----] n := integer(time)
32+
// [----] end when;
33+
//
2234
// {"SimplifyWhen","SimplifyWhen_init.xml"}
2335
// ""
2436
// endResult

0 commit comments

Comments
 (0)