Skip to content

Commit 19c4128

Browse files
committed
[NF] Improve EvalConstants for if-expressions.
- Do branch selection for if-expressions if the condition is a literal value after evaluating constants in it, to avoid having to evaluate constants in branches that would be removed anyway.
1 parent 7dc71fa commit 19c4128

File tree

2 files changed

+51
-41
lines changed

2 files changed

+51
-41
lines changed

OMCompiler/Compiler/NFFrontEnd/NFEvalConstants.mo

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import ExecStat.execStat;
5555
import NFPrefixes.Variability;
5656
import Ceval = NFCeval;
5757
import Package = NFPackage;
58+
import SimplifyExp = NFSimplifyExp;
5859

5960
public
6061
function evaluate
@@ -131,13 +132,13 @@ function evaluateExp
131132
input Variability constVariability;
132133
output Expression outExp;
133134
algorithm
134-
outExp := evaluateExpTraverser(exp, constVariability, false);
135+
outExp := evaluateExpTraverser(exp, constVariability);
135136
end evaluateExp;
136137

137138
function evaluateExpTraverser
138139
input Expression exp;
139140
input Variability constVariability;
140-
input Boolean changed;
141+
input Boolean changed = false;
141142
output Expression outExp;
142143
output Boolean outChanged;
143144
protected
@@ -166,6 +167,12 @@ algorithm
166167
then
167168
outExp;
168169

170+
case Expression.IF()
171+
algorithm
172+
(outExp, outChanged) := evaluateIfExp(exp, constVariability);
173+
then
174+
outExp;
175+
169176
else
170177
algorithm
171178
(outExp, outChanged) := Expression.mapFoldShallow(exp,
@@ -195,6 +202,39 @@ algorithm
195202
end match;
196203
end evaluateDimension;
197204

205+
function evaluateIfExp
206+
input Expression exp;
207+
input Variability constVariability;
208+
output Expression outExp;
209+
output Boolean outChanged;
210+
protected
211+
Expression cond, tb, fb;
212+
Boolean c1, c2;
213+
algorithm
214+
Expression.IF(cond, tb, fb) := exp;
215+
(cond, outChanged) := evaluateExpTraverser(cond, constVariability);
216+
217+
// Simplify the condition in case it can be reduced to a literal value.
218+
cond := SimplifyExp.simplify(cond);
219+
220+
(outExp, outChanged) := match cond
221+
// Only evaluate constants in and return one of the branches if the
222+
// condition is a literal boolean value.
223+
case Expression.BOOLEAN()
224+
then evaluateExpTraverser(if cond.value then tb else fb, constVariability);
225+
226+
// Otherwise evaluate constants in both branches and return the whole
227+
// if-expression.
228+
else
229+
algorithm
230+
(tb, c1) := evaluateExpTraverser(tb, constVariability);
231+
(fb, c2) := evaluateExpTraverser(fb, constVariability);
232+
then
233+
(Expression.IF(cond, tb, fb), outChanged or c1 or c2);
234+
235+
end match;
236+
end evaluateIfExp;
237+
198238
function evaluateEquations
199239
input list<Equation> eql;
200240
input Variability constVariability;

testsuite/flattening/modelica/scodeinst/Ticket5821.mo

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,36 +2198,6 @@ end Test_total;
21982198
// external "C" ModelicaStandardTables_CombiTimeTable_close(externalCombiTimeTable);
21992199
// end Modelica.Blocks.Types.ExternalCombiTimeTable.destructor;
22002200
//
2201-
// function Modelica.Utilities.Strings.Advanced.skipWhiteSpace "Scan white space"
2202-
// input String string;
2203-
// input Integer startIndex(min = 1) = 1;
2204-
// output Integer nextIndex;
2205-
//
2206-
// external "C" nextIndex = ModelicaStrings_skipWhiteSpace(string, startIndex);
2207-
// end Modelica.Utilities.Strings.Advanced.skipWhiteSpace;
2208-
//
2209-
// function Modelica.Utilities.Strings.isEmpty "Return true if a string is empty (has only white space characters)"
2210-
// input String string;
2211-
// output Boolean result "True, if string is empty";
2212-
// protected Integer nextIndex;
2213-
// protected Integer len;
2214-
// algorithm
2215-
// nextIndex := Modelica.Utilities.Strings.Advanced.skipWhiteSpace(string, 1);
2216-
// len := Modelica.Utilities.Strings.length(string);
2217-
// if len < 1 or nextIndex > len then
2218-
// result := true;
2219-
// else
2220-
// result := false;
2221-
// end if;
2222-
// end Modelica.Utilities.Strings.isEmpty;
2223-
//
2224-
// function Modelica.Utilities.Strings.length "Return length of string"
2225-
// input String string;
2226-
// output Integer result "Number of characters of string";
2227-
//
2228-
// external "C" result = ModelicaStrings_length(string);
2229-
// end Modelica.Utilities.Strings.length;
2230-
//
22312201
// function Modelica_StateGraph2.Blocks.BooleanFunctions.anyTrue "Returns true, if at least on element of the Boolean input vector is true ('or')"
22322202
// input Boolean[:] b;
22332203
// output Boolean result;
@@ -2294,7 +2264,7 @@ end Test_total;
22942264
// final parameter Integer booleanTable.combiTimeTable.columns[1] = 2 "Columns of table to be interpolated";
22952265
// final parameter enumeration(LinearSegments, ContinuousDerivative, ConstantSegments, MonotoneContinuousDerivative1, MonotoneContinuousDerivative2) booleanTable.combiTimeTable.smoothness = Modelica.Blocks.Types.Smoothness.ConstantSegments "Smoothness of table interpolation";
22962266
// final parameter enumeration(HoldLastPoint, LastTwoPoints, Periodic, NoExtrapolation) booleanTable.combiTimeTable.extrapolation = Modelica.Blocks.Types.Extrapolation.HoldLastPoint "Extrapolation of data outside the definition range";
2297-
// final parameter Real booleanTable.combiTimeTable.timeScale(quantity = "Time", unit = "s", min = 1e-015) = 1.0 "Time scale of first table column";
2267+
// final parameter Real booleanTable.combiTimeTable.timeScale(quantity = "Time", unit = "s", min = 1e-15) = 1.0 "Time scale of first table column";
22982268
// final parameter Real booleanTable.combiTimeTable.offset[1] = 0.0 "Offsets of output signals";
22992269
// final parameter Real booleanTable.combiTimeTable.startTime(quantity = "Time", unit = "s") = booleanTable.startTime "Output = offset for time < startTime";
23002270
// final parameter Real booleanTable.combiTimeTable.shiftTime(quantity = "Time", unit = "s") = booleanTable.shiftTime "Shift time of first table column";
@@ -2305,7 +2275,7 @@ end Test_total;
23052275
// final parameter Real booleanTable.combiTimeTable.t_minScaled = Modelica.Blocks.Tables.Internal.getTimeTableTmin(booleanTable.combiTimeTable.tableID) "Minimum (scaled) abscissa value defined in table";
23062276
// final parameter Real booleanTable.combiTimeTable.t_maxScaled = Modelica.Blocks.Tables.Internal.getTimeTableTmax(booleanTable.combiTimeTable.tableID) "Maximum (scaled) abscissa value defined in table";
23072277
// protected final parameter Real booleanTable.combiTimeTable.p_offset[1] = 0.0 "Offsets of output signals";
2308-
// protected parameter Modelica.Blocks.Types.ExternalCombiTimeTable booleanTable.combiTimeTable.tableID = Modelica.Blocks.Types.ExternalCombiTimeTable.constructor(if false then booleanTable.combiTimeTable.tableName else "NoName", if false and booleanTable.combiTimeTable.fileName <> "NoName" and not Modelica.Utilities.Strings.isEmpty(booleanTable.combiTimeTable.fileName) then booleanTable.combiTimeTable.fileName else "NoName", booleanTable.combiTimeTable.table, booleanTable.combiTimeTable.startTime / 1.0, {2}, Modelica.Blocks.Types.Smoothness.ConstantSegments, Modelica.Blocks.Types.Extrapolation.HoldLastPoint, booleanTable.combiTimeTable.shiftTime / 1.0, if Modelica.Blocks.Types.Smoothness.ConstantSegments == Modelica.Blocks.Types.Smoothness.LinearSegments then booleanTable.combiTimeTable.timeEvents else if Modelica.Blocks.Types.Smoothness.ConstantSegments == Modelica.Blocks.Types.Smoothness.ConstantSegments then Modelica.Blocks.Types.TimeEvents.Always else Modelica.Blocks.Types.TimeEvents.NoTimeEvents, if false then booleanTable.combiTimeTable.verboseRead else false) "External table object";
2278+
// protected parameter Modelica.Blocks.Types.ExternalCombiTimeTable booleanTable.combiTimeTable.tableID = Modelica.Blocks.Types.ExternalCombiTimeTable.constructor("NoName", "NoName", booleanTable.combiTimeTable.table, booleanTable.combiTimeTable.startTime / 1.0, {2}, Modelica.Blocks.Types.Smoothness.ConstantSegments, Modelica.Blocks.Types.Extrapolation.HoldLastPoint, booleanTable.combiTimeTable.shiftTime / 1.0, Modelica.Blocks.Types.TimeEvents.Always, false) "External table object";
23092279
// protected discrete Real booleanTable.combiTimeTable.nextTimeEvent(quantity = "Time", unit = "s", start = 0.0, fixed = true) "Next time event instant";
23102280
// protected discrete Real booleanTable.combiTimeTable.nextTimeEventScaled(start = 0.0, fixed = true) "Next scaled time event instant";
23112281
// protected Real booleanTable.combiTimeTable.timeScaled "Scaled time";
@@ -2367,7 +2337,7 @@ end Test_total;
23672337
// Boolean logicalDelayStateGraph.T1.conditionPort "Fire condition as Boolean input.";
23682338
// Boolean logicalDelayStateGraph.T1.fire "= true, if transition fires";
23692339
// Boolean logicalDelayStateGraph.T1.enableFire "= true, if firing condition is true";
2370-
// protected constant Real logicalDelayStateGraph.T1.minimumWaitTime(quantity = "Time", unit = "s") = 1e-013;
2340+
// protected constant Real logicalDelayStateGraph.T1.minimumWaitTime(quantity = "Time", unit = "s") = 1e-13;
23712341
// protected Real logicalDelayStateGraph.T1.t_start(quantity = "Time", unit = "s") "Time instant at which the transition would fire, if waitTime would be zero";
23722342
// protected Boolean logicalDelayStateGraph.T1.localCondition;
23732343
// final parameter Integer logicalDelayStateGraph.Y0D0.nIn(min = 0) = 2 "Number of input connections";
@@ -2420,7 +2390,7 @@ end Test_total;
24202390
// Boolean logicalDelayStateGraph.T2.conditionPort "Fire condition as Boolean input.";
24212391
// Boolean logicalDelayStateGraph.T2.fire "= true, if transition fires";
24222392
// Boolean logicalDelayStateGraph.T2.enableFire "= true, if firing condition is true";
2423-
// protected constant Real logicalDelayStateGraph.T2.minimumWaitTime(quantity = "Time", unit = "s") = 1e-013;
2393+
// protected constant Real logicalDelayStateGraph.T2.minimumWaitTime(quantity = "Time", unit = "s") = 1e-13;
24242394
// protected Real logicalDelayStateGraph.T2.t_start(quantity = "Time", unit = "s") "Time instant at which the transition would fire, if waitTime would be zero";
24252395
// protected Boolean logicalDelayStateGraph.T2.localCondition;
24262396
// final parameter Integer logicalDelayStateGraph.Y0D1.nIn(min = 0) = 1 "Number of input connections";
@@ -2464,7 +2434,7 @@ end Test_total;
24642434
// Boolean logicalDelayStateGraph.T3.conditionPort "Fire condition as Boolean input.";
24652435
// Boolean logicalDelayStateGraph.T3.fire "= true, if transition fires";
24662436
// Boolean logicalDelayStateGraph.T3.enableFire "= true, if firing condition is true";
2467-
// protected constant Real logicalDelayStateGraph.T3.minimumWaitTime(quantity = "Time", unit = "s") = 1e-013;
2437+
// protected constant Real logicalDelayStateGraph.T3.minimumWaitTime(quantity = "Time", unit = "s") = 1e-13;
24682438
// protected Real logicalDelayStateGraph.T3.t_start(quantity = "Time", unit = "s") "Time instant at which the transition would fire, if waitTime would be zero";
24692439
// protected Boolean logicalDelayStateGraph.T3.localCondition;
24702440
// final parameter Boolean logicalDelayStateGraph.T4.use_conditionPort = true "= true, if conditionPort enabled";
@@ -2486,7 +2456,7 @@ end Test_total;
24862456
// Boolean logicalDelayStateGraph.T4.conditionPort "Fire condition as Boolean input.";
24872457
// Boolean logicalDelayStateGraph.T4.fire "= true, if transition fires";
24882458
// Boolean logicalDelayStateGraph.T4.enableFire "= true, if firing condition is true";
2489-
// protected constant Real logicalDelayStateGraph.T4.minimumWaitTime(quantity = "Time", unit = "s") = 1e-013;
2459+
// protected constant Real logicalDelayStateGraph.T4.minimumWaitTime(quantity = "Time", unit = "s") = 1e-13;
24902460
// protected Real logicalDelayStateGraph.T4.t_start(quantity = "Time", unit = "s") "Time instant at which the transition would fire, if waitTime would be zero";
24912461
// protected Boolean logicalDelayStateGraph.T4.localCondition;
24922462
// initial equation
@@ -2553,7 +2523,7 @@ end Test_total;
25532523
// booleanTable.combiTimeTable.timeScaled = time;
25542524
// when {time >= pre(booleanTable.combiTimeTable.nextTimeEvent), initial()} then
25552525
// booleanTable.combiTimeTable.nextTimeEventScaled = Modelica.Blocks.Tables.Internal.getNextTimeEvent(booleanTable.combiTimeTable.tableID, booleanTable.combiTimeTable.timeScaled);
2556-
// booleanTable.combiTimeTable.nextTimeEvent = if booleanTable.combiTimeTable.nextTimeEventScaled < 1e+060 then booleanTable.combiTimeTable.nextTimeEventScaled else 1e+060;
2526+
// booleanTable.combiTimeTable.nextTimeEvent = if booleanTable.combiTimeTable.nextTimeEventScaled < 9.999999999999999e+59 then booleanTable.combiTimeTable.nextTimeEventScaled else 9.999999999999999e+59;
25572527
// end when;
25582528
// booleanTable.combiTimeTable.y[1] = booleanTable.combiTimeTable.p_offset[1] + Modelica.Blocks.Tables.Internal.getTimeTableValueNoDer(booleanTable.combiTimeTable.tableID, 1, booleanTable.combiTimeTable.timeScaled, booleanTable.combiTimeTable.nextTimeEventScaled, pre(booleanTable.combiTimeTable.nextTimeEventScaled));
25592529
// booleanTable.realToBoolean.y = booleanTable.realToBoolean.u >= booleanTable.realToBoolean.threshold;
@@ -2612,7 +2582,7 @@ end Test_total;
26122582
// logicalDelayStateGraph.T2.inPort.fire = logicalDelayStateGraph.T2.fire;
26132583
// logicalDelayStateGraph.T2.outPort.fire = logicalDelayStateGraph.T2.fire;
26142584
// logicalDelayStateGraph.T2.outPort.node = logicalDelayStateGraph.T2.inPort.node;
2615-
// assert(logicalDelayStateGraph.T2.waitTime > 1e-013, "Either set delayTransition = false, or set waitTime (= " + String(logicalDelayStateGraph.T2.waitTime, 6, 0, true) + ") > " + String(1e-013, 6, 0, true));
2585+
// assert(logicalDelayStateGraph.T2.waitTime > 1e-13, "Either set delayTransition = false, or set waitTime (= " + String(logicalDelayStateGraph.T2.waitTime, 6, 0, true) + ") > " + String(1e-13, 6, 0, true));
26162586
// logicalDelayStateGraph.Y0D1.inport_fire = Modelica_StateGraph2.Blocks.BooleanFunctions.anyTrue({logicalDelayStateGraph.Y0D1.inPort[1].fire});
26172587
// logicalDelayStateGraph.Y0D1.outport_fire = Modelica_StateGraph2.Blocks.BooleanFunctions.anyTrue({logicalDelayStateGraph.Y0D1.outPort[1].fire});
26182588
// logicalDelayStateGraph.Y0D1.newActive = if logicalDelayStateGraph.Y0D1.node.resume then logicalDelayStateGraph.Y0D1.oldActive else logicalDelayStateGraph.Y0D1.inport_fire or logicalDelayStateGraph.Y0D1.active and not logicalDelayStateGraph.Y0D1.outport_fire and not logicalDelayStateGraph.Y0D1.node.suspend;
@@ -2641,7 +2611,7 @@ end Test_total;
26412611
// logicalDelayStateGraph.T4.inPort.fire = logicalDelayStateGraph.T4.fire;
26422612
// logicalDelayStateGraph.T4.outPort.fire = logicalDelayStateGraph.T4.fire;
26432613
// logicalDelayStateGraph.T4.outPort.node = logicalDelayStateGraph.T4.inPort.node;
2644-
// assert(logicalDelayStateGraph.T4.waitTime > 1e-013, "Either set delayTransition = false, or set waitTime (= " + String(logicalDelayStateGraph.T4.waitTime, 6, 0, true) + ") > " + String(1e-013, 6, 0, true));
2614+
// assert(logicalDelayStateGraph.T4.waitTime > 1e-13, "Either set delayTransition = false, or set waitTime (= " + String(logicalDelayStateGraph.T4.waitTime, 6, 0, true) + ") > " + String(1e-13, 6, 0, true));
26452615
// end Test_total;
26462616
// [flattening/modelica/scodeinst/Ticket5821.mo:39:7-39:47:writable] Warning: The second argument 'logicalDelayStateGraph.Y1D0.node' of Connections.branch must have the form A.R, where A is a connector and R an over-determined type/record.
26472617
// [flattening/modelica/scodeinst/Ticket5821.mo:43:7-49:9:writable] Warning: Usage of non-standard operator (not specified in the Modelica specification): Connections.uniqueRoot. Functionality might be partially supported but is not guaranteed.

0 commit comments

Comments
 (0)