Skip to content

Commit bad8c82

Browse files
First steps towards continuous-time state machines
1 parent fd06aab commit bad8c82

File tree

5 files changed

+569
-42
lines changed

5 files changed

+569
-42
lines changed

Compiler/FrontEnd/Expression.mo

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6459,6 +6459,58 @@ algorithm
64596459
end match;
64606460
end traversingexpHasDer;
64616461

6462+
public function expHasPre "
6463+
Returns true if the expression contains the operator pre"
6464+
input DAE.Exp inExp;
6465+
output Boolean hasPre;
6466+
algorithm
6467+
(_, hasPre) := traverseExpTopDown(inExp, traversingexpHasPre, false);
6468+
end expHasPre;
6469+
6470+
protected function traversingexpHasPre "
6471+
Returns true if the exp is pre(..)"
6472+
input DAE.Exp inExp;
6473+
input Boolean inHasIt;
6474+
output DAE.Exp outExp;
6475+
output Boolean cont;
6476+
output Boolean outHasIt;
6477+
algorithm
6478+
(outExp,cont,outHasIt) := match(inExp,inHasIt)
6479+
local
6480+
Boolean b;
6481+
ComponentRef cr;
6482+
case (DAE.CALL(path= Absyn.IDENT("pre")), false)
6483+
then (inExp,false,true);
6484+
case (_,b) then (inExp, not b, inHasIt);
6485+
end match;
6486+
end traversingexpHasPre;
6487+
6488+
public function expHasPrevious "
6489+
Returns true if the expression contains the operator previous"
6490+
input DAE.Exp inExp;
6491+
output Boolean hasPre;
6492+
algorithm
6493+
(_, hasPre) := traverseExpTopDown(inExp, traversingexpHasPrevious, false);
6494+
end expHasPrevious;
6495+
6496+
protected function traversingexpHasPrevious "
6497+
Returns true if the exp is pre(..)"
6498+
input DAE.Exp inExp;
6499+
input Boolean inHasIt;
6500+
output DAE.Exp outExp;
6501+
output Boolean cont;
6502+
output Boolean outHasIt;
6503+
algorithm
6504+
(outExp,cont,outHasIt) := match(inExp,inHasIt)
6505+
local
6506+
Boolean b;
6507+
ComponentRef cr;
6508+
case (DAE.CALL(path= Absyn.IDENT("previous")), false)
6509+
then (inExp,false,true);
6510+
case (_,b) then (inExp, not b, inHasIt);
6511+
end match;
6512+
end traversingexpHasPrevious;
6513+
64626514

64636515
public function expHasCrefNoPreorDer "
64646516
@author: Frenkel TUD 2011-04

Compiler/FrontEnd/Inst.mo

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,13 @@ algorithm
14471447

14481448
case(_,_,_,_,_,expectedTp,DAE.PROP(bindTp,c))
14491449
equation
1450-
false = valueEq(c,DAE.C_VAR());
1450+
if Flags.getConfigBool(Flags.CT_STATE_MACHINES) then
1451+
// BTH Hack to allow variable modification of "start" attribute for ct SM re-initialization
1452+
// This is is forbidden in standard Modelica! Standard Modelica is the "else" branch!
1453+
true = valueEq(c,DAE.C_VAR());
1454+
else
1455+
false = valueEq(c,DAE.C_VAR());
1456+
end if;
14511457
(bind1,t_1) = Types.matchType(bind,bindTp,expectedTp,true);
14521458
then DAE.TYPES_VAR(id,DAE.dummyAttrParam,t_1,
14531459
DAE.EQBOUND(bind1,NONE(),DAE.C_PARAM(),DAE.BINDING_FROM_DEFAULT_VALUE()),NONE());

Compiler/FrontEnd/InstStateMachineUtil.mo

Lines changed: 168 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,15 @@ protected
194194
HashTableCG.HashTable outerOutputCrefToSMCompCref "Table to map outer outputs to corresponding state";
195195
HashTableCG.HashTable outerOutputCrefToInnerCref "Table to map outer output to corresponding inners";
196196
HashTable3.HashTable innerCrefToOuterOutputCrefs "Kind of \"inverse\" of outerOutputCrefToInnerCref";
197-
List<tuple<DAE.ComponentRef, DAE.ComponentRef>> hashEntries;
198-
List<DAE.ComponentRef> uniqueHashValues;
197+
List<tuple<DAE.ComponentRef, DAE.ComponentRef>> hashEntries_outerOutputCrefToInnerCref;
198+
List<tuple<DAE.ComponentRef, list<DAE.ComponentRef>>> innerCrefToOuterOutputCrefs_der = {} "Extracted part in which at least one of the output crefs appears in a der(..)";
199+
List<tuple<DAE.ComponentRef, list<DAE.ComponentRef>>> innerCrefToOuterOutputCrefs_nonDer = {} "The non-der(..) rest";
200+
List<DAE.ComponentRef> uniqueHashValues, crefs, derCrefsAcc = {}, outerOutputCrefs;
201+
HashSet.HashSet derCrefsSet;
199202
DAE.FunctionTree emptyTree;
200-
list<DAE.Element> dAElistNew, mergeEqns;
203+
list<DAE.Element> dAElistNew, mergeEqns, mergeEqns_der, aliasEqns_der;
204+
Integer nOfHits;
205+
Boolean hasDer;
201206
// FLAT_SM
202207
DAE.Ident ident;
203208
list<DAE.Element> dAElist "The states/modes within the the flat state machine";
@@ -206,49 +211,195 @@ algorithm
206211

207212
// Create table that maps outer outputs to corresponding state
208213
outerOutputCrefToSMCompCref := List.fold(dAElist, collectOuterOutputs, HashTableCG.emptyHashTable());
209-
//print("InstStateMachineUtil.mergeVariableDefinitions OuterToSTATE:\n"); BaseHashTable.dumpHashTable(outerOutputCrefToSMCompCref);
214+
// print("InstStateMachineUtil.mergeVariableDefinitions OuterToSTATE:\n"); BaseHashTable.dumpHashTable(outerOutputCrefToSMCompCref);
210215

211216
// Create table that maps outer outputs crefs to corresponding inner crefs
212217
outerOutputCrefToInnerCref := List.fold1(BaseHashTable.hashTableKeyList(outerOutputCrefToSMCompCref), matchOuterWithInner, inIH, HashTableCG.emptyHashTable());
213-
//print("InstStateMachineUtil.mergeVariableDefinitions OuterToINNER:\n"); BaseHashTable.dumpHashTable(outerOutputCrefToInnerCref);
218+
// print("InstStateMachineUtil.mergeVariableDefinitions OuterToINNER:\n"); BaseHashTable.dumpHashTable(outerOutputCrefToInnerCref);
214219

215220
// Create table that maps inner crefs from above to a list of corresponding outer crefs
216-
hashEntries := BaseHashTable.hashTableList(outerOutputCrefToInnerCref);
221+
hashEntries_outerOutputCrefToInnerCref := BaseHashTable.hashTableList(outerOutputCrefToInnerCref);
217222
uniqueHashValues := List.unique(BaseHashTable.hashTableValueList(outerOutputCrefToInnerCref));
218-
//print("InstStateMachineUtil.mergeVariableDefinitions uniqueHashValues: (" + stringDelimitList(List.map(uniqueHashValues, ComponentReference.crefStr), ",") + ")\n");
219-
innerCrefToOuterOutputCrefs := List.fold1(uniqueHashValues, collectCorrespondingKeys, hashEntries, HashTable3.emptyHashTable());
220-
//print("InstStateMachineUtil.mergeVariableDefinitions: innerCrefToOuterOutputCrefs:\n"); BaseHashTable.dumpHashTable(innerCrefToOuterOutputCrefs);
223+
// print("InstStateMachineUtil.mergeVariableDefinitions uniqueHashValues: (" + stringDelimitList(List.map(uniqueHashValues, ComponentReference.crefStr), ",") + ")\n");
224+
innerCrefToOuterOutputCrefs := List.fold1(uniqueHashValues, collectCorrespondingKeys, hashEntries_outerOutputCrefToInnerCref, HashTable3.emptyHashTable());
225+
// print("InstStateMachineUtil.mergeVariableDefinitions: innerCrefToOuterOutputCrefs:\n"); BaseHashTable.dumpHashTable(innerCrefToOuterOutputCrefs);
221226

222227
// Substitute occurrences of previous(outerCref) by previous(innerCref)
223228
emptyTree := DAE.AvlTreePathFunction.Tree.EMPTY();
224229
(DAE.DAE(dAElist), _, _) := DAEUtil.traverseDAE(DAE.DAE(dAElist), emptyTree, traverserHelperSubsOuterByInnerExp, outerOutputCrefToInnerCref);
225230

226-
// FIXME add support for outers that don't have "inner outer" or "inner" at closest instance level (requires to introduce a fresh intermediate variable)
227-
mergeEqns := List.map1(BaseHashTable.hashTableKeyList(innerCrefToOuterOutputCrefs), freshMergingEqn, innerCrefToOuterOutputCrefs);
231+
if Flags.getConfigBool(Flags.CT_STATE_MACHINES) then
232+
// == HACK Let's deal with continuous-time ==
233+
crefs := BaseHashTable.hashTableKeyList(outerOutputCrefToSMCompCref);
234+
for cref in crefs loop
235+
nOfHits := 0;
236+
// traverse dae expressions and search for der(cref) occurances
237+
(_, _, (_,(_, nOfHits))) := DAEUtil.traverseDAE(DAE.DAE(dAElist), emptyTree, Expression.traverseSubexpressionsHelper, (traversingCountDer, (cref, 0)));
238+
if nOfHits > 0 then
239+
derCrefsAcc := cref :: derCrefsAcc;
240+
end if;
241+
end for;
242+
// print("InstStateMachineUtil.mergeVariableDefinitions derCrefsAcc:\n" + stringDelimitList(List.map(derCrefsAcc, ComponentReference.crefStr), ", ") + "\n");
243+
derCrefsSet := HashSet.emptyHashSetSized(listLength(derCrefsAcc));
244+
derCrefsSet := List.fold(derCrefsAcc, BaseHashSet.add, derCrefsSet);
245+
// Split the mapping from inner crefs to outer output crefs in a "continuous" part and the rest
246+
for hashEntry in BaseHashTable.hashTableList(innerCrefToOuterOutputCrefs) loop
247+
(_, outerOutputCrefs) := hashEntry;
248+
hasDer := List.exist(outerOutputCrefs, function BaseHashSet.has(hashSet=derCrefsSet));
249+
if hasDer then
250+
innerCrefToOuterOutputCrefs_der := hashEntry :: innerCrefToOuterOutputCrefs_der;
251+
else
252+
innerCrefToOuterOutputCrefs_nonDer := hashEntry :: innerCrefToOuterOutputCrefs_nonDer;
253+
end if;
254+
end for;
255+
// Create aliases between inner and outer of 'der' entries, e.g., a tuple (x -> {a.x, b.x}) will be transformed to alias equations {x = a.x, x = b.x}
256+
aliasEqns_der := List.flatten( List.map(innerCrefToOuterOutputCrefs_der, freshAliasEqn_der) );
257+
// Create merging equations for 'der' entries
258+
mergeEqns_der := listAppend(List.map(innerCrefToOuterOutputCrefs_der, freshMergingEqn_der), aliasEqns_der);
259+
// Create merging equations for 'nonDer' entries
260+
mergeEqns := listAppend(List.map(innerCrefToOuterOutputCrefs_nonDer, freshMergingEqn), mergeEqns_der);
261+
else
262+
// FIXME add support for outers that don't have "inner outer" or "inner" at closest instance level (requires to introduce a fresh intermediate variable)
263+
mergeEqns := List.map(BaseHashTable.hashTableList(innerCrefToOuterOutputCrefs), freshMergingEqn);
264+
end if;
228265

229266
// add processed flat state machine and corresponding merging equations to the dae element list
230267
//outElementLst := listAppend(outElementLst, {DAE.FLAT_SM(ident=ident, dAElist=listAppend(dAElist, mergeEqns))}); // put merge equations in FLAT_SM element
231268
outElementLst := listAppend(inStartElementLst, DAE.FLAT_SM(ident=ident, dAElist=dAElist) :: mergeEqns); // put equations after FLAT_SM element
232269
end mergeVariableDefinitions;
233270

271+
protected function freshAliasEqn_der "
272+
Author: BTH
273+
Helper function to mergeVariableDefinition.
274+
Create a fresh alias equation between inners and their corresponding outer output variable defintions
275+
"
276+
input tuple<DAE.ComponentRef, list<DAE.ComponentRef>> inInnerCrefToOuterOutputCrefs "tuple relating the inner cref to respective outer crefs";
277+
output list<DAE.Element> outEqns;
278+
protected
279+
DAE.ComponentRef innerCref;
280+
List<DAE.ComponentRef> outerCrefs;
281+
DAE.Type ty;
282+
algorithm
283+
(innerCref, outerCrefs) := inInnerCrefToOuterOutputCrefs;
284+
// FIXME use instead 'ty := ComponentReference.crefTypeConsiderSubs(innerCref);'?
285+
ty := ComponentReference.crefLastType(innerCref);
286+
// Alias equations
287+
outEqns := list(DAE.EQUATION(DAE.CREF(innerCref, ty), DAE.CREF(outerCref, ty), DAE.emptyElementSource) for outerCref in outerCrefs);
288+
end freshAliasEqn_der;
289+
290+
protected function freshMergingEqn_der "
291+
Author: BTH
292+
Helper function to mergeVariableDefinition.
293+
Create a fresh equation for merging outer output variable defintions of equations involving der(..)
294+
"
295+
input tuple<DAE.ComponentRef, list<DAE.ComponentRef>> inInnerCrefToOuterOutputCrefs "tuple relating the inner cref to respective outer crefs";
296+
output DAE.Element outEqn;
297+
protected
298+
DAE.ComponentRef innerCref;
299+
List<DAE.ComponentRef> outerCrefs, outerCrefsStripped, outerCrefDers;
300+
DAE.Type ty;
301+
DAE.Exp exp;
302+
algorithm
303+
(innerCref, outerCrefs) := inInnerCrefToOuterOutputCrefs;
304+
305+
// FIXME use instead 'ty := ComponentReference.crefTypeConsiderSubs(innerCref);'?
306+
ty := ComponentReference.crefLastType(innerCref);
307+
outerCrefsStripped := List.map(outerCrefs, ComponentReference.crefStripLastIdent);
308+
309+
// FIXME this variables are generated in StateMachineFlatten.addStateActivationAndReset(..) which is UGLY
310+
outerCrefDers := List.map(outerCrefs, function ComponentReference.appendStringLastIdent(inString = "_der$"));
311+
312+
// der(x)
313+
exp := DAE.CALL(Absyn.IDENT("der"), {DAE.CREF(innerCref, ty)}, DAE.callAttrBuiltinReal);
314+
// der(x) = ...
315+
outEqn := DAE.EQUATION(exp, mergingRhs_der(outerCrefDers, innerCref, ty), DAE.emptyElementSource);
316+
end freshMergingEqn_der;
317+
318+
protected function mergingRhs_der "
319+
Author: BTH
320+
Helper function to freshMergingEqn_der.
321+
Create RHS expression of merging equation.
322+
"
323+
input List<DAE.ComponentRef> inOuterCrefs "List of the crefs of the outer variables";
324+
input DAE.ComponentRef inInnerCref;
325+
input DAE.Type ty "type of inner cref (inner cref type expected to the same as outer crefs type)";
326+
output DAE.Exp res;
327+
protected
328+
DAE.CallAttributes callAttributes = DAE.CALL_ATTR(ty,false,true,false,false,DAE.NO_INLINE(),DAE.NO_TAIL());
329+
algorithm
330+
res := match (inOuterCrefs)
331+
local
332+
DAE.ComponentRef outerCref, crefState;
333+
List<DAE.ComponentRef> rest;
334+
DAE.Exp outerCrefExp, innerCrefExp, crefStateExp, ifExp, expCond, expElse;
335+
case (outerCref::{})
336+
equation
337+
outerCrefExp = DAE.CREF(outerCref, ty);
338+
innerCrefExp = DAE.CREF(inInnerCref, ty);
339+
crefState = ComponentReference.crefStripLastIdent(outerCref);
340+
crefStateExp = DAE.CREF(crefState, ty);
341+
expCond = DAE.CALL(Absyn.IDENT("activeState"), {crefStateExp}, callAttributes);
342+
expElse = DAE.RCONST(0);
343+
ifExp = DAE.IFEXP(expCond, outerCrefExp, expElse);
344+
then ifExp;
345+
case (outerCref::rest)
346+
equation
347+
outerCrefExp = DAE.CREF(outerCref, ty);
348+
crefState = ComponentReference.crefStripLastIdent(outerCref);
349+
crefStateExp = DAE.CREF(crefState, ty);
350+
expCond = DAE.CALL(Absyn.IDENT("activeState"), {crefStateExp}, callAttributes);
351+
expElse = mergingRhs_der(rest, inInnerCref, ty);
352+
ifExp = DAE.IFEXP(expCond, outerCrefExp, expElse);
353+
then ifExp;
354+
end match;
355+
356+
end mergingRhs_der;
357+
358+
protected function traversingCountDer "
359+
Author: BTH
360+
Helper function to traverse subexpressions
361+
Counts occurances of 'der(cref)'
362+
"
363+
input DAE.Exp inExp;
364+
input tuple<DAE.ComponentRef, Integer> inCref_HitCount "tuple of x and counter for hits of der(x)";
365+
output DAE.Exp outExp;
366+
output tuple<DAE.ComponentRef, Integer> outCref_HitCount;
367+
protected
368+
DAE.ComponentRef cref;
369+
Integer hitCount;
370+
algorithm
371+
(cref, hitCount) := inCref_HitCount;
372+
(outExp,outCref_HitCount) := match inExp
373+
local
374+
DAE.ComponentRef componentRef;
375+
list<DAE.Exp> expLst;
376+
DAE.CallAttributes attr;
377+
case DAE.CALL(path=Absyn.IDENT("der"), expLst={DAE.CREF(componentRef=componentRef)})
378+
guard ComponentReference.crefEqual(componentRef, cref)
379+
then (inExp, (cref, hitCount + 1));
380+
else (inExp,inCref_HitCount);
381+
end match;
382+
end traversingCountDer;
383+
234384
protected function freshMergingEqn "
235385
Author: BTH
236386
Helper function to mergeVariableDefinition.
237387
Create a fresh equation for merging outer output variable defintions
238388
"
239-
input DAE.ComponentRef inInnerCref;
240-
input HashTable3.HashTable inInnerCrefToOuterOutputCrefs;
389+
input tuple<DAE.ComponentRef, list<DAE.ComponentRef>> inInnerCrefToOuterOutputCrefs "tuple relating the inner cref to respective outer crefs";
241390
output DAE.Element outEqn;
242391
protected
392+
DAE.ComponentRef innerCref;
243393
List<DAE.ComponentRef> outerCrefs, outerCrefsStripped;
244394
DAE.Type ty;
245395
algorithm
246-
ty := ComponentReference.crefLastType(inInnerCref);
247-
// FIXME use instead 'ty := ComponentReference.crefTypeConsiderSubs(inInnerCref);'?
248-
outerCrefs := BaseHashTable.get(inInnerCref, inInnerCrefToOuterOutputCrefs);
396+
(innerCref, outerCrefs) := inInnerCrefToOuterOutputCrefs;
397+
398+
// FIXME BTH use instead 'ty := ComponentReference.crefTypeConsiderSubs(innerCref);'?
399+
ty := ComponentReference.crefLastType(innerCref);
249400
outerCrefsStripped := List.map(outerCrefs, ComponentReference.crefStripLastIdent);
250401

251-
outEqn := DAE.EQUATION(DAE.CREF(inInnerCref, ty), mergingRhs(outerCrefs, inInnerCref, ty), DAE.emptyElementSource);
402+
outEqn := DAE.EQUATION(DAE.CREF(innerCref, ty), mergingRhs(outerCrefs, innerCref, ty), DAE.emptyElementSource);
252403
end freshMergingEqn;
253404

254405
protected function mergingRhs "

0 commit comments

Comments
 (0)