Re: revised enterStates

I took the liberty of implementing the new algorithms and have a few superficial remarks.

On Feb 13, 2013, at 9:37 PM, Jim Barnett <Jim.Barnett@genesyslab.com<mailto:Jim.Barnett@genesyslab.com>> wrote:

[...]

procedurecomputeEntrySet(transitions, statesToEnter, statesForDefaultEntry)
Compute the complete set of states that will be entered as a result of taking 'transitions'. This value will be returned in 'statesToEnter' (which is modified by this procedure). Also place in 'statesForDefaultEntry' the set of all states whose default initial states were entered. First gather up all the target states in 'transitions'. Then add them and, for all that are not atomic states, add all of their (default) descendents until we reach one or more atomic states. Then add any ancestors that will be entered within the domain of the transition. (Ancestors outside of the domain of the transition will not have been exited.)
procedure computeEntrySet(transitions, statesToEnter, statesForDefaultEntry)
   for t in transitions:
        statesToEnter.union(getTargetStates(t.target))
    for s in statesToEnter:
        addDescendentStatesToEnter(s,statesToEnter,statesForDefaultEntry)

I assume enabledTransitions is transitions? Also getTransitionDomain takes a transition, not a state.

    for t in enabledTransitions:
        ancestor = getTransitionDomain(t.target)
        for s in getTargetStates(t.target)):
            addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry)
procedure addDescendentStatesToEnter(state,statesToEnter,statesForDefaultEntry)
The purpose of this procedure is to add to statesToEnter 'state' and any of its descendents that the state machine will end up entering when it enters 'state'. (N.B. If 'state' is a history pseudo-state, we dereference it and add the history value instead.) Note that this procedure permanently modifies both statesToEnter and statesForDefaultEntry.
First, If state is a history state then add either the history values associated with state or state's default target to statesToEnter. Then (since the history value may not be an immediate descendent of 'state's parent) add any ancestors between the history value and state's parent. Else (if state is not a history state), add state to statesToEnter. Then, if state is a compound state, add state to statesForDefaultEntry and recursively call addStatesToEnter on its default initial state(s). Then, since the default initial states may not be children of 'state', add any ancestors between the default initial states and 'state'. Otherwise, if state is a parallel state, recursively call addStatesToEnter on any of its child states that don't already have a descendent on statesToEnter.
procedure addDescendentStatesToEnter(state,statesToEnter,statesForDefaultEntry):
    if isHistoryState(state):
        if historyValue[state.id]:
            for s in historyValue[state.id]:
                addDescendentStatesToEnter(s,statesToEnter,statesForDefaultEntry)
                addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry)
        else:
            for t in state.transition:
                for s in getTargetStates(t.target):
                    addDescendentStatesToEnter(s,statesToEnter,statesForDefaultEntry)
                    addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry)
    else:
        statesToEnter.add(state)
        if isCompoundState(state):
            statesForDefaultEntry.add(state)

I do not get this part: "state.initial" is supposed to be the initial state with regards to an <initial> element or the initial attribute? But how can there be more than one with a compound state? I was already wondering with the original algorithm.

            for s in getTargetStates(state.initial):
                addDescendentStatesToEnter(s,statesToEnter,statesForDefaultEntry)
                addAncestorStatesToEnter(s, state, statesToEnter, statesForDefaultEntry)

This else is indented somewhat unfortunately.

   else:
        if isParallelState(state):
            for child in getChildStates(state):
                 if not statesToEnter.some(lambda s: isDescendant(s,child)):
                     addDescendentStatesToEnter(child,statesToEnter,statesForDefaultEntry)


I assume this is what's called "addAncestorStatesToEnter" in the rest of the pseudo-code.

procedureaddAncestorsToEnter(state, ancestor, statesToEnter, statesForDefaultEntry)
Add to statesToEnter any ancestors of 'state' up to, but not including, 'ancestor' that must be entered in order to enter 'state'. If any of these ancestor states is a parallel state, we must fill in its descendents as well.
procedure addAncestorsToEnter(state, ancestor, statesToEnter, statesForDefaultEntry)
   for anc in getProperAncestors(state,ancestor):
       statesToEnter.add(anc)
       if isParallelState(anc):
           for child in getChildStates(anc):
               if not statesToEnter.some(lambda s: isDescendant(s,child)):
                   addStatesToEnter(child,statesToEnter,statesForDefaultEntry)


function getTransitionDomain(transition)

Return the compound state such that 1) all states that are exited or entered as a result of taking 'transition' are descendents of it 2) no descendent of it has this property.

function getTransitionDomain(t)

  if not t.target

     return t.source

This elif is placed somewhat unfortunately as well. Also tstates is not defined. I take it, this is what Chris proposed as "getTransitionSubgraph"?


        elif t.type == "internal" and isCompoundState(t.source) and tstates.every(lambda s: isDescendant(s,t.source)):

      return t.source

  else:

      return findLCCA([t.source].append(getTargetStates(t.target)))



Best regards
Stefan

Received on Wednesday, 13 February 2013 23:55:12 UTC