Skip to content

Commit

Permalink
Added support for timeInState()
Browse files Browse the repository at this point in the history
  • Loading branch information
bernhard-thiele authored and OpenModelica-Hudson committed Sep 13, 2015
1 parent 4597a3a commit edba84e
Showing 1 changed file with 163 additions and 33 deletions.
196 changes: 163 additions & 33 deletions Compiler/FrontEnd/StateMachineFlatten.mo
Expand Up @@ -134,8 +134,10 @@ algorithm
if (not listEmpty(flatSmLst)) then
// FIXME HACK2 traverse dae expressions for making substitutions previous(x) -> pre(x) (as long as clocked features are not fully supported)
(outDAElist, _, (_,nOfSubstitutions)) := DAEUtil.traverseDAE(outDAElist, FCore.getFunctionTree(cache), Expression.traverseSubexpressionsHelper, (traversingSubsPreForPrevious, 0));
// FIXME HACK3 traverse dae expressions for making substitutions sample(x, _) -> x (as long as clocked features are not fully supported)
(outDAElist, _, (_,nOfSubstitutions)) := DAEUtil.traverseDAE(outDAElist, FCore.getFunctionTree(cache), Expression.traverseSubexpressionsHelper, (traversingSubsXForSampleX, 0));
end if;
// print("StateMachineFlatten.stateMachineToDataFlow: outDAElist:\n" + DAEDump.dumpStr(outDAElist,FCore.getFunctionTree(cache)));
//print("StateMachineFlatten.stateMachineToDataFlow: outDAElist:\n" + DAEDump.dumpStr(outDAElist,FCore.getFunctionTree(cache)));
end stateMachineToDataFlow;

protected function traversingSubsActiveState "
Expand Down Expand Up @@ -220,7 +222,7 @@ Author: BTH
protected
Integer i;
Boolean found;
DAE.Exp c2, c3, conditionNew, substExp;
DAE.Exp c2, c3, c4, conditionNew, substTickExp, substTimeExp;
DAE.ComponentRef stateRef;
Transition t2;
list<Transition> tElab = {} "Elaborated transitions";
Expand Down Expand Up @@ -255,35 +257,52 @@ algorithm
(t2, c2) := tc;
TRANSITION(from, to, condition, immediate, reset, synchronize, priority) := t2;

// == Search whether condition contains a subexpression 'ticksInState()', if so, substitute them by 'smComps[from].$ticksInState' ==
// Need to access decorations attached to 'from' state
DAE.SM_COMP(componentRef=stateRef) := arrayGet(smComps, from);
substExp := DAE.CREF(qCref("$ticksInState", DAE.T_INTEGER_DEFAULT, {}, stateRef), DAE.T_INTEGER_DEFAULT);
(c3, (_, found)) := Expression.traverseExpTopDown(c2, traversingSubsTicksInState, (substExp, false));

// == Search whether condition contains a subexpression 'ticksInState()', if so, substitute them by 'smComps[from].$ticksInState' ==
substTickExp := DAE.CREF(qCref("$ticksInState", DAE.T_INTEGER_DEFAULT, {}, stateRef), DAE.T_INTEGER_DEFAULT);
(c3, (_, _, found)) := Expression.traverseExpTopDown(c2, traversingSubsXInState, ("ticksInState", substTickExp, false));
if found and isSome(inEnclosingStateCrefOption) then
// MLS 3.3 17.1: "can only be used in transition conditions of state machines not present in states of hierarchical state machines" violated
Error.addCompilerError("Found 'ticksInState()' within a state of an hierarchical state machine.");
fail();
end if;
// if a transition was updated we also need to update the semantic equation containing that transition's logic
smeqsElab := if found then List.map4(smeqs, smeqsSubsTicksInState, arrayGet(smComps, 1), i, listLength(t), substExp) else smeqs;
smeqs := smeqsElab; // use updated smeqs for next iteration
smeqsElab := if found then List.map5(smeqs, smeqsSubsXInState, arrayGet(smComps, 1), i, listLength(t), substTickExp, "ticksInState") else smeqs;
smeqs := smeqsElab; // use updated smeqs

// == Search whether condition contains a subexpression 'timeInState()', if so, substitute them by 'smComps[from].$timeInState' ==
substTimeExp := DAE.CREF(qCref("$timeInState", DAE.T_REAL_DEFAULT, {}, stateRef), DAE.T_REAL_DEFAULT);
(c4, (_, _, found)) := Expression.traverseExpTopDown(c2, traversingSubsXInState, ("timeInState", substTimeExp, false));
if found and isSome(inEnclosingStateCrefOption) then
// MLS 3.3 17.1: "can only be used in transition conditions of state machines not present in states of hierarchical state machines" violated
Error.addCompilerError("Found 'timeInState()' within a state of an hierarchical state machine.");
fail();
end if;
// if a transition was updated we also need to update the semantic equation containing that transition's logic
smeqsElab := if found then List.map5(smeqs, smeqsSubsXInState, arrayGet(smComps, 1), i, listLength(t), substTimeExp, "timeInState") else smeqs;
smeqs := smeqsElab; // use updated smeqs

tElab := TRANSITION(from, to, c3, immediate, reset, synchronize, priority) :: tElab;
cElab := c3 :: cElab;
tElab := TRANSITION(from, to, c4, immediate, reset, synchronize, priority) :: tElab;
cElab := c4 :: cElab;
end for;

outFlatSmSemantics := FLAT_SM_SEMANTICS(ident, smComps, listReverse(tElab), listReverse(cElab), smvars, smknowns, smeqsElab, pvars, peqs, enclosingStateOption);
end elabXInStateOps;

protected function smeqsSubsTicksInState "
protected function smeqsSubsXInState "
Author: BTH
Replace 'ticksInState()' operators in semantic equations for the transition condition specified by the remaining function arguments.
Helper function to elabXInStateOps.
Replace 'xInState()' in RHS of semantic equations by 'substExp', but only within the transition
condition specified by the remaining function arguments.
"
input DAE.Element inSmeqs "SMS equation";
input DAE.Element initialStateComp "Initial state component of governing flat state machine";
input Integer i "Index of transition";
input Integer nTransitions;
input DAE.Exp substExp;
input String xInState "Name of function that is to be replaced, e.g., 'timeInState', or 'tickInState'";
output DAE.Element outSmeqs "SMS equation";
protected
DAE.ComponentRef preRef, cref, lhsRef, crefInitialState;
Expand All @@ -299,37 +318,39 @@ algorithm
cref := qCref("cImmediate", tArrayBool, {DAE.INDEX(DAE.ICONST(i))}, preRef);
DAE.EQUATION(lhsExp, rhsExp, elemSource) := inSmeqs;
DAE.CREF(lhsRef, ty) := lhsExp;
// print("StateMachineFlatten.smeqsSubsTicksInState: cref: " + ComponentReference.printComponentRefStr(cref) + "\n");
// print("StateMachineFlatten.smeqsSubsTicksInState: lhsRef: " + ComponentReference.printComponentRefStr(lhsRef) + "\n");
// print("StateMachineFlatten.smeqsSubsXInState: cref: " + ComponentReference.printComponentRefStr(cref) + "\n");
// print("StateMachineFlatten.smeqsSubsXInState: lhsRef: " + ComponentReference.printComponentRefStr(lhsRef) + "\n");
if ComponentReference.crefEqual(cref, lhsRef) then
// print("StateMachineFlatten.smeqsSubsTicksInState: rhsExp: " + ExpressionDump.printExpStr(rhsExp) + "\n");
(rhsExp2, _) := Expression.traverseExpTopDown(rhsExp, traversingSubsTicksInState, (substExp, false));
// print("StateMachineFlatten.smeqsSubsTicksInState: rhsExp2: " + ExpressionDump.printExpStr(rhsExp2) + "\n");
// print("StateMachineFlatten.smeqsSubsXInState: rhsExp: " + ExpressionDump.printExpStr(rhsExp) + "\n");
(rhsExp2, _) := Expression.traverseExpTopDown(rhsExp, traversingSubsXInState, (xInState, substExp, false));
// print("StateMachineFlatten.smeqsSubsXInState: rhsExp2: " + ExpressionDump.printExpStr(rhsExp2) + "\n");
else
rhsExp2 := rhsExp;
end if;
outSmeqs := DAE.EQUATION(lhsExp, rhsExp2, elemSource);
end smeqsSubsTicksInState;
end smeqsSubsXInState;

protected function traversingSubsTicksInState "
protected function traversingSubsXInState "
Author: BTH
Replace 'ticksInState()' operators by expression given in first element of inSubstHit tuple.
Helper function to elabXInStateOps and smeqsSubsXInState.
Replace 'XInState()' operators (first element of inXSubstHit) by expression given in second element of inXSubstHit tuple.
"
input DAE.Exp inExp;
input tuple<DAE.Exp, Boolean> inSubstHit;
input tuple<String, DAE.Exp, Boolean> inXSubstHit;
output DAE.Exp outExp;
output Boolean cont = true;
output tuple<DAE.Exp, Boolean> outSubstHit;
output tuple<String, DAE.Exp, Boolean> outXSubstHit;
algorithm
(outExp, outSubstHit) := match (inExp, inSubstHit)
(outExp, outXSubstHit) := match (inExp, inXSubstHit)
local
DAE.Exp subsExp;
Boolean hit;
case (DAE.CALL(path=Absyn.IDENT("ticksInState")), (subsExp, hit))
then (subsExp, (subsExp, true));
else then (inExp, inSubstHit);
String xInState, name;
case (DAE.CALL(path=Absyn.IDENT(name)), (xInState, subsExp, hit)) guard name == xInState
then (subsExp, (xInState, subsExp, true));
else then (inExp, inXSubstHit);
end match;
end traversingSubsTicksInState;
end traversingSubsXInState;

protected function smCompToDataFlow "
Author: BTH
Expand Down Expand Up @@ -603,8 +624,8 @@ Add activation and reset propagation related equation and variables to flat stat
output FlatSmSemantics outFlatSmSemantics;
protected
DAE.ComponentRef preRef, initStateRef, initRef, resetRef, activeRef, stateRef, activePlotIndicatorRef;
DAE.Element initVar, activePlotIndicatorVar, ticksInStateVar;
DAE.Element activePlotIndicatorEqn, ticksInStateEqn;
DAE.Element initVar, activePlotIndicatorVar, ticksInStateVar, timeEnteredStateVar, timeInStateVar;
DAE.Element activePlotIndicatorEqn, ticksInStateEqn, timeEnteredStateEqn, timeInStateEqn;
DAE.Exp rhs, andExp, eqExp, activeResetStateRefExp, activeStateRefExp, activeResetRefExp;
DAE.Type tArrayBool, tArrayInteger;

Expand Down Expand Up @@ -691,26 +712,111 @@ algorithm

// Decorate state with additional information
for i in 1:arrayLength(smComps) loop
// Add indication for plotting whether a state is active or not
// Add indication for plotting whether a state is active or not (stateRef.active)
DAE.SM_COMP(componentRef=stateRef) := arrayGet(smComps, i);
(activePlotIndicatorVar, activePlotIndicatorEqn) := createActiveIndicator(stateRef, preRef, i);
(activePlotIndicatorVar, activePlotIndicatorEqn) := createActiveIndicator(stateRef, preRef, i);
pvars := activePlotIndicatorVar :: pvars;
peqs := activePlotIndicatorEqn :: peqs;

// Add ticksInState counter
// Add ticksInState counter (stateRef.$ticksInState = if stateRef.active then previous(stateRef.$ticksInState) + 1 else 0)
DAE.VAR(componentRef=activePlotIndicatorRef) := activePlotIndicatorVar;
(ticksInStateVar, ticksInStateEqn) := createTicksInStateIndicator(stateRef, activePlotIndicatorRef);
pvars := ticksInStateVar :: pvars;
peqs := ticksInStateEqn :: peqs;

// TODO Add timeInState counter
// == Add timeInState Indicator (stateRef.$timeInState(start=0)) ==
// Auxiliary variable holding time when state was entred (stateRef.$timeEnteredState(start=0)
// stateRef.$timeEnteredState = if previous(stateRef.active) == false and stateRef.active == true then sample(time) else previous(stateRef.$timeEnteredState)
(timeEnteredStateVar, timeEnteredStateEqn) := createTimeEnteredStateIndicator(stateRef, activePlotIndicatorRef);
// stateRef.$timeInState = if stateRef.active then sample(time) - stateRef.$timeEnteredState else 0
(timeInStateVar, timeInStateEqn) := createTimeInStateIndicator(stateRef, activePlotIndicatorRef, timeEnteredStateVar);
pvars := timeEnteredStateVar :: timeInStateVar :: pvars;
peqs := timeEnteredStateEqn :: timeInStateEqn :: peqs;
end for;


outFlatSmSemantics := FLAT_SM_SEMANTICS(ident, smComps, t, c, smvars, smknowns, smeqs, pvars, peqs, inEnclosingStateCrefOption);

end addPropagationEquations;

protected function createTimeInStateIndicator "
Author: BTH
Helper function to addPropagationEquations.
Create variable that indicates the time duration since a transition was made to the currently active state"
input DAE.ComponentRef stateRef "cref of state to which timeInState variable shall be added";
input DAE.ComponentRef stateActiveRef "cref of active indicator corresponding to stateRef";
input DAE.Element timeEnteredStateVar "Auxiliary variable generated in createTimeEnteredStateIndicator(..)";
output DAE.Element timeInStateVar;
output DAE.Element timeInStateEqn;
protected
DAE.ComponentRef timeInStateRef, timeEnteredStateRef;
DAE.Type ty;
DAE.Exp timeInStateExp, timeEnteredStateExp, stateActiveExp, expCond, expSampleTime, expThen, expElse;
algorithm
// Create Variable stateRef.$timeEnteredState
timeInStateRef := qCref("$timeInState", DAE.T_REAL_DEFAULT, {}, stateRef);
timeInStateVar := createVarWithDefaults(timeInStateRef, DAE.DISCRETE(), DAE.T_REAL_DEFAULT);
timeInStateVar := setVarFixedStartValue(timeInStateVar, DAE.RCONST(0));
timeInStateExp := DAE.CREF(timeInStateRef, DAE.T_REAL_DEFAULT);

DAE.VAR(componentRef=timeEnteredStateRef, ty=ty) := timeEnteredStateVar;
timeEnteredStateExp := DAE.CREF(timeEnteredStateRef, ty);

stateActiveExp := Expression.crefExp(stateActiveRef);

// == $timeInState = if active then sample(time) - $timeEnteredState else 0; ==
// active
expCond := Expression.crefExp(stateActiveRef);
// sample(time)
expSampleTime := DAE.CALL(Absyn.IDENT("sample"),
{ DAE.CREF(DAE.CREF_IDENT("time", DAE.T_REAL_DEFAULT, {}), DAE.T_REAL_DEFAULT),
DAE.CLKCONST(DAE.INFERRED_CLOCK())},
DAE.callAttrBuiltinImpureReal);
// sample(time) - $timeEnteredState
expThen := DAE.BINARY(expSampleTime, DAE.SUB(DAE.T_REAL_DEFAULT), timeEnteredStateExp);
// 0
expElse := DAE.RCONST(0);
// $timeInState = if active then sample(time) - $timeEnteredState else 0;
timeInStateEqn := DAE.EQUATION(timeInStateExp, DAE.IFEXP(expCond, expThen, expElse), DAE.emptyElementSource);
end createTimeInStateIndicator;

protected function createTimeEnteredStateIndicator "
Author: BTH
Helper function to addPropagationEquations.
Create auxiliary variable that remembers the time in which a state is entered"
input DAE.ComponentRef stateRef "cref of state to which timeEnteredState variable shall be added";
input DAE.ComponentRef stateActiveRef "cref of active indicator corresponding to stateRef";
output DAE.Element timeEnteredStateVar;
output DAE.Element timeEnteredStateEqn;
protected
DAE.ComponentRef timeEnteredStateRef;
DAE.Exp timeEnteredStateExp, stateActiveExp, expCond, expThen, expElse;
algorithm
// Create Variable stateRef.$timeEnteredState
timeEnteredStateRef := qCref("$timeEnteredState", DAE.T_REAL_DEFAULT, {}, stateRef);
timeEnteredStateVar := createVarWithDefaults(timeEnteredStateRef, DAE.DISCRETE(), DAE.T_REAL_DEFAULT);
timeEnteredStateVar := setVarFixedStartValue(timeEnteredStateVar, DAE.RCONST(0));
timeEnteredStateExp := DAE.CREF(timeEnteredStateRef, DAE.T_REAL_DEFAULT);

stateActiveExp := Expression.crefExp(stateActiveRef);

// == $timeEnteredState = if previous(active) == false and active == true then sample(time) else previous($timeEnteredState); ==
// previous(active) == false and active == true
expCond := DAE.LBINARY(
DAE.RELATION( DAE.CALL(Absyn.IDENT("previous"), {stateActiveExp}, DAE.callAttrBuiltinImpureBool), DAE.EQUAL(DAE.T_BOOL_DEFAULT), DAE.BCONST(false), -1, NONE()), // previous(active) == false
DAE.AND(DAE.T_BOOL_DEFAULT), // and
DAE.RELATION( stateActiveExp, DAE.EQUAL(DAE.T_BOOL_DEFAULT), DAE.BCONST(true), -1, NONE()) // active == true
);
// sample(time)
expThen := DAE.CALL(Absyn.IDENT("sample"),
{ DAE.CREF(DAE.CREF_IDENT("time", DAE.T_REAL_DEFAULT, {}), DAE.T_REAL_DEFAULT),
DAE.CLKCONST(DAE.INFERRED_CLOCK())},
DAE.callAttrBuiltinImpureReal);
// previous($timeEnteredState)
expElse := DAE.CALL(Absyn.IDENT("previous"), {timeEnteredStateExp}, DAE.callAttrBuiltinImpureReal);
// $timeEnteredState = if previous(active) == false and active == true then sample(time) else previous($timeEnteredState);
timeEnteredStateEqn := DAE.EQUATION(timeEnteredStateExp, DAE.IFEXP(expCond, expThen, expElse), DAE.emptyElementSource);
end createTimeEnteredStateIndicator;

protected function createTicksInStateIndicator "
Author: BTH
Helper function to addPropagationEquations.
Expand All @@ -726,6 +832,7 @@ algorithm
// Create Variable stateRef.$ticksInState
ticksInStateRef := qCref("$ticksInState", DAE.T_INTEGER_DEFAULT, {}, stateRef);
ticksInStateVar := createVarWithDefaults(ticksInStateRef, DAE.DISCRETE(), DAE.T_INTEGER_DEFAULT);
ticksInStateVar := setVarFixedStartValue(ticksInStateVar, DAE.ICONST(0));

// $ticksInState = if active then previous($ticksInState) + 1 else 0;
ticksInStateExp := DAE.CREF(ticksInStateRef, DAE.T_INTEGER_DEFAULT);
Expand Down Expand Up @@ -1430,5 +1537,28 @@ algorithm
end match;
end traversingSubsPreForPrevious;

protected function traversingSubsXForSampleX "
Author: BTH
Helper function to traverse subexpressions
Substitutes 'sample(x, _)' by 'x' "
input DAE.Exp inExp;
input Integer inHitCount;
output DAE.Exp outExp;
output Integer outHitCount;
algorithm
(outExp,outHitCount) := match inExp
local
DAE.ComponentRef componentRef;
DAE.Exp expX;
DAE.CallAttributes attr;
case DAE.CALL(Absyn.IDENT("sample"),
{ expX,
DAE.CLKCONST(DAE.INFERRED_CLOCK())},
attr)
then (expX, inHitCount + 1);
else (inExp,inHitCount);
end match;
end traversingSubsXForSampleX;

annotation(__OpenModelica_Interface="frontend");
end StateMachineFlatten;

0 comments on commit edba84e

Please sign in to comment.