Finitomata.Transition (Finitomata v0.34.0)
View SourceThe internal representation of Transition.
It includes from and to states, and the event, all represented as atoms.
Summary
Types
The event in FSM
The kind of event
The state of FSM
The transition is represented by from and to states and the event.
Functions
Returns the list of all the transitions, matching the options.
Returns the list of all the transitions, matching the from state and the event.
Returns true if the transition from → to is allowed, false otherwise.
Returns keyword list of
{Finitomata.Transition.state(), [Finitomata.Transition.event()]} for transitions
which do not have a determined to state.
Returns the continuation from the state given which inevitably lead to other state(s).
Returns keyword list of
{Finitomata.Transition.state(), Finitomata.Transition.event()} tuples
for determined transition from the current state.
Returns {:ok, {event(), state()}} tuple if there is a determined transition
from the current state, :error otherwise.
Returns the state after starting one, so-called entry state.
Returns the kind of event.
Returns the not ordered list of events, including or excluding
the internal starting and ending transitions :__start__ and __end__
according to the second argument.
Returns the states before ending one, so-called exit states.
Returns all the states which inevitably lead to the ending one.
Tries to guess the next state based on current state and event
Returns all the hard transitions which inevitably lead to the next state
(events ending with an exclamation sign,)
which makes the FSM to go to the next state with :continue callback.
Returns all the loops aka internal paths where starting and ending states are the same one.
Returns all the paths from starting to ending state.
Returns true if the state from hsa an outgoing transition with event, false otherwise.
Returns the shortest path from starting to ending state.
Returns the not ordered list of states, including or excluding
the starting and ending states :* according to the second argument.
Returns the minimal number of steps required to get from from state to to state,
including hard transitions
Returns the minimal number of steps required to get from from state to to state,
omitting hard transitions
Returns the straight paths from starting to ending state.
Types
Functions
@spec allowed([t()], from: state(), to: state(), with: event(), as: :states | :transitions ) :: [ {state(), state(), event()} ]
Returns the list of all the transitions, matching the options.
Used internally for the validations.
iex> {:ok, transitions} =
...> Finitomata.Mermaid.parse(
...> "idle --> |to_s1| s1\n" <>
...> "s1 --> |to_s2| s2\n" <>
...> "s1 --> |to_s3| s3\n" <>
...> "s2 --> |to_s3| s3")
...> Finitomata.Transition.allowed(transitions, to: [:idle, :*])
[{:*, :idle, :__start__}, {:s3, :*, :__end__}]
iex> Finitomata.Transition.allowed(transitions, from: :s1)
[{:s1, :s2, :to_s2}, {:s1, :s3, :to_s3}]
iex> Finitomata.Transition.allowed(transitions, from: :s1, to: :s3)
[{:s1, :s3, :to_s3}]
iex> Finitomata.Transition.allowed(transitions, from: :s1, with: :to_s3)
[{:s1, :s3, :to_s3}]
iex> Finitomata.Transition.allowed(transitions, from: :s2, with: :to_s2)
[]
Returns the list of all the transitions, matching the from state and the event.
Used internally for the validations.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.allowed(transitions, :s1, :foo)
[:s2]
...> Finitomata.Transition.allowed(transitions, :s1, :*)
[]
Returns true if the transition from → to is allowed, false otherwise.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.allowed?(transitions, :s1, :s2)
true
...> Finitomata.Transition.allowed?(transitions, :s1, :*)
false
Returns keyword list of
{Finitomata.Transition.state(), [Finitomata.Transition.event()]} for transitions
which do not have a determined to state.
Used internally for the validations.
iex> {:ok, transitions} =
...> Finitomata.Mermaid.parse(
...> "idle --> |to_s1| s1\n" <>
...> "s1 --> |to_s2| s2\n" <>
...> "s1 --> |to_s3| s3\n" <>
...> "s2 --> |to_s1| s3\n" <>
...> "s2 --> |ambiguous| s3\n" <>
...> "s2 --> |ambiguous| s4\n" <>
...> "s3 --> |determined| s3\n" <>
...> "s3 --> |determined| s4\n")
...> Finitomata.Transition.ambiguous(transitions)
[s3: {:determined, [:s3, :s4]}, s2: {:ambiguous, [:s3, :s4]}]
@spec continuation(:states | :transitions, state(), [t()]) :: nil | [Finitomata.Transition.Path.t()] | [t()]
Returns the continuation from the state given which inevitably lead to other state(s).
All the transitions from this state are hard (ending with !,)
which makes the FSM to go through all these states in :continue callbacks.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> entry : start\nentry --> exit : go!\nexit --> done : finish\ndone --> [*] : terminate")
...> Finitomata.Transition.continuation(:entry, Finitomata.Transition.hard(:transitions, transitions))
[%Finitomata.Transition.Path{from: :entry, to: :exit, path: [go!: :exit]}]
@spec count(:states | :transitions, [t()]) :: non_neg_integer()
Returns keyword list of
{Finitomata.Transition.state(), Finitomata.Transition.event()} tuples
for determined transition from the current state.
The transition is determined, if it is the only transition allowed from the state.
Used internally for the validations.
iex> {:ok, transitions} =
...> Finitomata.Mermaid.parse(
...> "idle --> |to_s1| s1\n" <>
...> "s1 --> |to_s2| s2\n" <>
...> "s1 --> |to_s3| s3\n" <>
...> "s2 --> |to_s1| s3\n" <>
...> "s2 --> |ambiguous| s3\n" <>
...> "s2 --> |ambiguous| s4\n" <>
...> "s3 --> |determined| s3\n" <>
...> "s3 --> |determined| s4\n")
...> Finitomata.Transition.determined(transitions)
[s4: :__end__, s3: :determined, idle: :to_s1]
Returns {:ok, {event(), state()}} tuple if there is a determined transition
from the current state, :error otherwise.
The transition is determined, if it is the only transition allowed from the state.
Used internally for the validations.
iex> {:ok, transitions} =
...> Finitomata.Mermaid.parse(
...> "idle --> |to_s1| s1\n" <>
...> "s1 --> |to_s2| s2\n" <>
...> "s1 --> |to_s3| s3\n" <>
...> "s2 --> |to_s3| s3")
...> Finitomata.Transition.determined(transitions, :s1)
:error
iex> Finitomata.Transition.determined(transitions, :s2)
{:ok, {:to_s3, :s3}}
iex> Finitomata.Transition.determined(transitions, :s3)
{:ok, {:__end__, :*}}
Returns the state after starting one, so-called entry state.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> entry : foo\nentry --> exit : go\nexit --> [*] : terminate")
...> Finitomata.Transition.entry(transitions)
:entry
@spec event_kind(event() | t()) :: event_kind()
Returns the kind of event.
If event ends up with an exclamation sign, it’s :hard, meaning the respective
transition would be initiated automatically when the from state of such a transition
is reached.
If event ends up with a question mark, it’s :soft, meaning no error would have
been reported in a case transition fails.
Otherwise the event is :normal.
iex> {:ok, [_, hard, _]} =
...> Finitomata.PlantUML.parse("[*] --> entry : foo\nentry --> exit : go!\nexit --> [*] : terminate")
...> Finitomata.Transition.event_kind(hard)
:hard
Returns the not ordered list of events, including or excluding
the internal starting and ending transitions :__start__ and __end__
according to the second argument.
iex> {:ok, transitions} =
...> Finitomata.Mermaid.parse("s1 --> |ok| s2\ns1 --> |ko| s3")
...> Finitomata.Transition.events(transitions, true)
[:ok, :ko]
...> Finitomata.Transition.events(transitions)
[:__start__, :ok, :ko, :__end__]
Returns the states before ending one, so-called exit states.
iex> {:ok, transitions} =
...> Finitomata.Mermaid.parse(
...> "entry --> |process| processing\nprocessing --> |ok| success\nprocessing --> |ko| error"
...> )
...> Finitomata.Transition.exit(transitions)
[:error, :success]
@spec exiting(:states | :transitions, [t()]) :: Enumerable.t([t()]) | [Finitomata.Transition.Path.t()]
Returns all the states which inevitably lead to the ending one.
All the transitions from these states to the ending one are hard (ending with !,)
which makes the FSM to go through all these states in :continue callbacks.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> entry : start\nentry --> exit : go!\nexit --> [*] : terminate")
...> Finitomata.Transition.exiting(transitions)
[%Finitomata.Transition.Path{from: :entry, to: :*, path: [go!: :exit, terminate: :*]}]
@spec guess_next_state([t()], state(), event(), Finitomata.State.payload()) :: Finitomata.transition_resolution()
Tries to guess the next state based on current state and event
iex> {:ok, transitions} = Finitomata.Mermaid.parse("s1 --> |ok| s2\ns1 --> |ko| s3")
...> Finitomata.Transition.guess_next_state(transitions, :s1, :ok, %{})
{:ok, :s2, %{}}
iex> {:ok, transitions} = Finitomata.Mermaid.parse("s1 --> |ok| s2\ns1 --> |ok| s3")
...> Finitomata.Transition.guess_next_state(transitions, :s1, :ok, %{})
{:error, {:ambiguous_transition, {:s1, :ok}, [:s2, :s3]}}
@spec hard(:states | :transitions, [t()]) :: Enumerable.t(t()) | [Finitomata.Transition.Path.t()]
Returns all the hard transitions which inevitably lead to the next state
(events ending with an exclamation sign,)
which makes the FSM to go to the next state with :continue callback.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> entry : start\nentry --> exit : go!\nexit --> [*] : terminate")
...> Finitomata.Transition.hard(transitions)
[entry: :go!]
...> Finitomata.Transition.hard(:transitions, transitions)
[%Finitomata.Transition{from: :entry, to: :exit, event: :go!}]
@spec loops(:states | :transitions, [t()]) :: Enumerable.t(t()) | [Finitomata.Transition.Path.t()]
Returns all the loops aka internal paths where starting and ending states are the same one.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> s1 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.loops(transitions)
[%Finitomata.Transition.Path{from: :s1, to: :s1, path: [ok: :s2, ok: :s1]},
%Finitomata.Transition.Path{from: :s2, to: :s2, path: [ok: :s1, ok: :s2]}]
@spec paths(:states | :transitions, [t()], state(), state()) :: Enumerable.t(t()) | [Finitomata.Transition.Path.t()]
Returns all the paths from starting to ending state.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns1 --> s3 : ok\ns2 --> [*] : ko\ns3 --> [*] : ko")
...> Finitomata.Transition.paths(transitions)
[%Finitomata.Transition.Path{from: :*, to: :*, path: [foo: :s1, ok: :s2, ko: :*]},
%Finitomata.Transition.Path{from: :*, to: :*, path: [foo: :s1, ok: :s3, ko: :*]}]
Returns true if the state from hsa an outgoing transition with event, false otherwise.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.responds?(transitions, :s1, :ok)
true
...> Finitomata.Transition.responds?(transitions, :s1, :ko)
false
@spec shortest_paths(:states | :transitions, [t()], state(), state(), boolean()) :: Enumerable.t(t()) | [Finitomata.Transition.Path.t()]
Returns the shortest path from starting to ending state.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns1 --> s3 : ok\ns2 --> [*] : ko\ns3 --> s4 : step\ns4 --> [*] : ko")
...> Finitomata.Transition.shortest_paths(transitions)
[%Finitomata.Transition.Path{from: :*, to: :*, path: [foo: :s1, ok: :s2, ko: :*]}]
Returns the not ordered list of states, including or excluding
the starting and ending states :* according to the second argument.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns2 --> [*] : ko")
...> Finitomata.Transition.states(transitions, true)
[:s1, :s2]
...> Finitomata.Transition.states(transitions)
[:*, :s1, :s2]
@spec steps([t()], state(), state()) :: non_neg_integer()
Returns the minimal number of steps required to get from from state to to state,
including hard transitions
@spec steps_handled([t()], state(), state()) :: non_neg_integer()
Returns the minimal number of steps required to get from from state to to state,
omitting hard transitions
@spec straight_paths(:states | :transitions, [t()], state(), state()) :: Enumerable.t(t()) | Finitomata.Transition.Path.t()
Returns the straight paths from starting to ending state.
iex> {:ok, transitions} =
...> Finitomata.PlantUML.parse("[*] --> s1 : foo\ns1 --> s2 : ok\ns1 --> s3 : ok\ns2 --> s2 : loop\ns2 --> [*] : ko\ns3 --> s4 : step\ns4 --> [*] : ko")
...> Finitomata.Transition.straight_paths(transitions)
[%Finitomata.Transition.Path{from: :*, to: :*, path: [foo: :s1, ok: :s2, ko: :*]},
%Finitomata.Transition.Path{from: :*, to: :*, path: [foo: :s1, ok: :s3, step: :s4, ko: :*]}]