INCF/nineml-spec

Inactivation of OnEvent transitions

Opened this issue · 1 comments

When attempting to write code to split regimes that contain piecewise expressions (either directly or via aliases) into separate regimes I realised that there isn't a way to specify which regime to transition to based on the current state for OnEvent transitions. For example, it is not possible to split a Dynamics class such as this

<Dynamics name="Foo">
  <Parameter name="a" dimension="dimensionless"/>
  <StateVariable name="x" dimension="dimensionless"/>
  <EventReceivePort name="incomingSpike"/>
  <Regime name="A"/>
    <TimeDerivative variable="x">
      <MathInline>c * x</MathInline>
    </TimeDerivative>
    <OnEvent target="B" port="incomingSpike"/>
  </Regime>
  <Regime name="B"/>
    <TimeDerivative variable="x">
      <MathInline>-a * x ? a &lt; 10 : -2 * a</MathInline>
    </TimeDerivative>
    <OnCondition target="A">
      <Trigger>
        <MathInline>a &lt; 0</MathInline>
      </Trigger>
    </OnCondition>
  </Regime>
</Dynamics>

into

<Dynamics name="FooSplit">
  <Parameter name="a" dimension="dimensionless"/>
  <StateVariable name="x" dimension="dimensionless"/>
  <EventReceivePort name="incomingSpike"/>
  <Regime name="A"/>
    <TimeDerivative variable="x">
      <MathInline>c * x</MathInline>
    </TimeDerivative>
    <OnEvent target="B if x < 10 else C" port="incomingSpike"/>
  </Regime>
  <Regime name="B"/>
    <TimeDerivative variable="x">
      <MathInline>-a * x</MathInline>
    </TimeDerivative>
    <OnCondition target="A">
      <Trigger>
        <MathInline>a &lt; 0</MathInline>
      </Trigger>
    </OnCondition>
  </Regime>
  <Regime name="C"/>
    <TimeDerivative variable="x">
      <MathInline>-2 * a</MathInline>
    </TimeDerivative>
    <OnCondition target="A">
      <Trigger>
        <MathInline>a &lt; 0</MathInline>
      </Trigger>
    </OnCondition>
  </Regime>
</Dynamics>

because the target of the OnEvent transition needs to change based on the value of x.

One way to handle this would be to introduce a conditional statement on the regime target, however, I think this would be a bit messy and wouldn't allow you to update states and chain subsequent events conditionally. Therefore, I would favour adding an optional ActiveWhen (or another name) element to OnEvent transitions, which would allow you to write

<Dynamics name="FooSplit">
  <Parameter name="a" dimension="dimensionless"/>
  <StateVariable name="x" dimension="dimensionless"/>
  <EventReceivePort name="incomingSpike"/>
  <Regime name="A"/>
    <TimeDerivative variable="x">
      <MathInline>c * x</MathInline>
    </TimeDerivative>
    <OnEvent target="B" port="incomingSpike">
      <ActiveWhen>
        <MathInline>x &lt; 10</MathInline>
      </ActiveWhen>
    <OnEvent>
    <OnEvent target="C" port="incomingSpike">
      <ActiveWhen>
        <MathInline>x &gt;= 10</MathInline>
      </ActiveWhen>
    <OnEvent>
  </Regime>
  <Regime name="B"/>
    <TimeDerivative variable="x">
      <MathInline>-a * x</MathInline>
    </TimeDerivative>
    <OnCondition target="A">
      <Trigger>
        <MathInline>a &lt; 0</MathInline>
      </Trigger>
    </OnCondition>
  </Regime>
  <Regime name="C"/>
    <TimeDerivative variable="x">
      <MathInline>-2 * a</MathInline>
    </TimeDerivative>
    <OnCondition target="A">
      <Trigger>
        <MathInline>a &lt; 0</MathInline>
      </Trigger>
    </OnCondition>
  </Regime>
</Dynamics>

The only problem I can see with this is that it would be impossible to check whether two OnEvent transitions that listen to the same port could be active together, which would have to be left to the user to ensure it doesn't happen. However, this problem already occurs with multiple OnCondition transition statements so it is not a new problem.

I will like to work on this issue . Can you please provide more info?