Skip to content

Commit

Permalink
update to FSM chapter (feedback of 2024-10-14) (#156)
Browse files Browse the repository at this point in the history
* update chapter into

* update FSM definitions

* modeling FSM, raw and using built-in library

---------

Co-authored-by: Zunaid Ahmed <[email protected]>
  • Loading branch information
boughrira and Zune-Ahmed authored Oct 30, 2024
1 parent 613f829 commit 1056597
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 222 deletions.
12 changes: 1 addition & 11 deletions source/finite-state-machines/ch-finite-state-machines.ptx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,8 @@

<introduction>
<p> In this chapter, we explore a powerful abstract model: <em>finite-state machines</em>.
Beyond the theory, we'll see how to use <term>Sage</term> to define, model and build, then
Beyond the theory, we'll see how to use Sage to define, model and build, then
visualize and run a few examples of state machines to solve real-world problems.</p>
<aside>
<title>Notes</title>
<p>
State machines are often associated with tasks in relation with system designs (circuits and
digital computers, algorithms, etc.) However, the vast and rich domain of applications of
state machines extends far beyond simple simulations to full control logic of complex
industrial processes and workflows. These tasks can vary in complexity, be as simple as a
parity check or a complex as managing traffic patterns, a programming language compiler, or
natural language recognition and processing.</p>
</aside>
</introduction>

<!-- include sections -->
Expand Down
213 changes: 125 additions & 88 deletions source/finite-state-machines/sec-modeling-finite-state-machines.ptx
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,31 @@
machines, we can still model, construct, display, and run relatively
simple state machines, leveraging the general-purpose tools, such as graphs and
transition matrices, to represent and work with state machines.</p>
<p>
In this section, we'll explore how to define states, create a state transition graph,
visualize the state machine, and simulate its execution in Sage.</p>

<aside>
<title>Notes</title>
<p> While Sage provides basic tools to represent and simulate state machines,
it may not natively support more complex state machine features such as parallel
states or hierarchical transitions.</p>
</aside>
<p>
In this section, we'll explore how to define states, create a state transition graph,
visualize the state machine, and simulate its execution in Sage.</p>
</introduction>
</introduction>

<subsection>
<title>Example of Application of FSMs</title>
<p>
Let's consider the example of an elevator for 3 floors. Being in a given floor <m>i</m> would represent
a distinct state <m>f_i</m>, so that we can have the subset of states <m>S=\{f_1,\;f_2,\;f_3\}</m>.</p>
<p>
The elevator has 3 buttons as inputs for users to select the destination floor <m>X=\{1,\;2,\;3\}</m>, and
based of which the elevator can either go up, go down, or stay in the same floor.</p>
<p>
Let's have the set of outputs <m>O=\{N,\;U,\;D\}</m> to represent the outputs ,"do nothing", "go up",
"go down" respectively. The following table shows the state machine representation of this elevator.</p>
<table>
<title>State Machine Transitions and Outputs</title>
<title>Elevator State Machine: Transitions and Outputs</title>
<p> Assume there is a 3-levels elevator (floors 1 thru 3). this elevator moves in the
same direction (up or down) until it reaches the last floor while moving up, or
the first floor while moving down. It makes stop at every floor on its way up or
Expand All @@ -44,7 +54,7 @@
<cell>|</cell>

<cell></cell>
<cell>next state</cell>
<cell>next</cell>
<cell></cell>

<cell>|</cell>
Expand All @@ -54,66 +64,66 @@
<cell></cell>
</row>
<row header="yes" bottom="minor">
<cell>from</cell>
<cell>current</cell>
<cell>|</cell>

<cell>push-1</cell>
<cell>push-2</cell>
<cell>push-3</cell>
<cell>(1)</cell>
<cell>(2)</cell>
<cell>(3)</cell>

<cell>|</cell>

<cell>push-1</cell>
<cell>push-2</cell>
<cell>push-3</cell>
<cell>(1)</cell>
<cell>(2)</cell>
<cell>(3)</cell>
</row>

<row>
<cell>fl_1</cell>
<cell><m>f_1</m></cell>

<cell>|</cell>

<cell>fl_1</cell>
<cell>fl_2</cell>
<cell>fl_3</cell>
<cell><m>f_1</m></cell>
<cell><m>f_2</m></cell>
<cell><m>f_3</m></cell>

<cell>|</cell>

<cell>no_change</cell>
<cell>go_up</cell>
<cell>go_up</cell>
<cell><m>N</m></cell>
<cell><m>U</m></cell>
<cell><m>U</m></cell>
</row>

<row>
<cell>fl_2</cell>
<cell><m>f_2</m></cell>

<cell>|</cell>

<cell>fl_1</cell>
<cell>fl_2</cell>
<cell>fl_3</cell>
<cell><m>f_1</m></cell>
<cell><m>f_2</m></cell>
<cell><m>f_3</m></cell>

<cell>|</cell>

<cell>go_down</cell>
<cell>no_change</cell>
<cell>go_up</cell>
<cell><m>D</m></cell>
<cell><m>N</m></cell>
<cell><m>U</m></cell>
</row>

<row>
<cell>fl_3</cell>
<cell><m>f_3</m></cell>

<cell>|</cell>

<cell>fl_1</cell>
<cell>fl_2</cell>
<cell>fl_3</cell>
<cell><m>f_1</m></cell>
<cell><m>f_2</m></cell>
<cell><m>f_3</m></cell>

<cell>|</cell>

<cell>go_down</cell>
<cell>go_down</cell>
<cell>no_change</cell>
<cell><m>D</m></cell>
<cell><m>D</m></cell>
<cell><m>N</m></cell>
</row>

</tabular>
Expand All @@ -128,44 +138,44 @@
<sage>
<input>
# Define state, input and output sets
states = ['fl_1', 'fl_2', 'fl_3']
inputs = ['push-1', 'push-2', 'push-3']
outputs = ['go_up', 'go_down', 'no_change']
states = ['f1', 'f2', 'f3']
inputs = ['1', '2', '3']
outputs = ['U', 'D', 'N']

# transitions are defined as a dictionary {(current_state, input): next_state}
transitions = {
('fl_1', 'push-1'): 'fl_1',
('fl_1', 'push-2'): 'fl_2',
('fl_1', 'push-3'): 'fl_3',
('f1', '1'): 'f1',
('f1', '2'): 'f2',
('f1', '3'): 'f3',

('fl_2', 'push-1'): 'fl_1',
('fl_2', 'push-2'): 'fl_2',
('fl_2', 'push-3'): 'fl_3',
('f2', '1'): 'f1',
('f2', '2'): 'f2',
('f2', '3'): 'f3',

('fl_3', 'push-1'): 'fl_1',
('fl_3', 'push-2'): 'fl_2',
('fl_3', 'push-3'): 'fl_3',
('f3', '1'): 'f1',
('f3', '2'): 'f2',
('f3', '3'): 'f3',
}

# The machine output controls how the elevator would move
outputs = {
('fl_1', 'push-1'): 'no_change',
('fl_1', 'push-2'): 'go_up',
('fl_1', 'push-3'): 'go_up',
('f1', '1'): 'N',
('f1', '2'): 'U',
('f1', '3'): 'U',

('fl_2', 'push-1'): 'go_down',
('fl_2', 'push-2'): 'no_change',
('fl_2', 'push-3'): 'go_up',
('f2', '1'): 'D',
('f2', '2'): 'N',
('f2', '3'): 'U',

('fl_3', 'push-1'): 'go_down',
('fl_3', 'push-2'): 'go_down',
('fl_3', 'push-3'): 'no_change',
('f3', '1'): 'D',
('f3', '2'): 'D',
('f3', '3'): 'N',
}

# Display the machine configuration
print('States: ', states, '\n')
print('Transitions: ', transitions, '\n')
print('Outputs: ', outputs, '\n')
print('States: ', states)
print('Transitions: ', transitions)
print('Outputs: ', outputs)
</input>
<output></output>
</sage>
Expand All @@ -175,7 +185,7 @@
edges between these vertices.</p>
</subsection>
<subsection>
<title>Create and Display the Graph Model of State Machine</title>
<title>Graph Model of a Finite State Machine</title>
<p> In Sage, we can use the <c>DiGraph</c> class to represent the states, transitions and
outputs of the state machine as a directed graph, and use the graph structure to
visualize the state machine representation.</p>
Expand All @@ -197,13 +207,21 @@
SM.add_edge(_state, next_state, label=edge_label)

# Display the graph (state machine)
SM.show(edge_labels=True)
SM.show(
figsize=[5.6, 5.6],
layout='circular',
vertex_size=250,
edge_labels=True,
vertex_labels=True,
edge_color=(.2,.4,1),
edge_thickness=1.0,
)
</input>
<output></output>
</sage>
<p> The <c>SM.show()</c> command renders a graphical representation of the state machine.
Each vertex in the graph represents a state, and each directed edge represents a
transition, labeled with the input.</p>
transition, labeled as (input, output).</p>
</subsection>

<subsection>
Expand All @@ -220,17 +238,23 @@
print(f"Current State: {current_state}, Input: {_input}")

if (current_state, _input) in transitions:
current_output = outputs[(current_state, _input)]
current_state = transitions[(current_state, _input)]
print(f"Transitioned to: {current_state}\n")
print(
f"Transitioned to: {current_state}\n"
f"Output: {current_output}\n"
)
else:
print(f"No transition available for input {_input} in state {current_state}")
print(
f"No transition/output available for input {_input} in state {current_state}"
)
break

print(f"New State: {current_state}")

# Example of running the state machine
start_state = 'fl_2'
inputs = ['push-1', 'push-1', 'push-3', 'push-2']
start_state = 'f2'
inputs = ['1', '1', '3', '2']

run_state_machine(start_state, inputs)
</input>
Expand All @@ -241,12 +265,27 @@
</subsection>

<subsection>
<title>Using Sage built-in 'FiniteStateMachine'</title>
<title>Using Sage built-in `FiniteStateMachine'</title>
<p>
In this section, we'll the Sage built-in library for FSM, to model and run a very basic
traffic light system, controlled only by a preset timer and has 3 traffic lights: (G)reen,
(Y)ellow, and (R)ed.
</p>
<p>
<c>FiniteStateMachine()</c> is used define an <em>empty</em> state machine.</p>
<sage>
<input>
from sage.combinat.finite_state_machine import FSMState

# define the states, inputs and outputs of the FSM that models a simple traffic light
# GO for light being gree, HOLD for light being yellow, and STOP for light being red.
states = ['GO', 'HOLD', 'STOP']

# FSM inputs and outputs
inputs = [30, 5, 30] # timer duration
outputs = ['G', 'Y', 'R'] # light turns Green, Yellow, Red

# Create an empty state machine object
fsm = FiniteStateMachine()
fsm
</input>
Expand Down Expand Up @@ -298,43 +337,34 @@
</sage>
<p>
<c>FSMTransition()</c> defines a new transition between two states, as well as the input
(the transition trigger) and output associated with the new state after teh transition.<c>
add_transition()</c> method attach the defined transition to the state machine. <c>
transitions()</c> method is used to enumerate the list of all defined transitions of the
(the transition trigger) and output associated with the new state after the transition.
<c>add_transition()</c> method attach the defined transition to the state machine.
<c>transitions()</c> method is used to enumerate the list of all defined transitions of the
state machine.</p>
<sage>
<input>
from sage.combinat.finite_state_machine import FSMTransition

# defining 3 transitions, and associating them the state machine
drive = fsm.add_transition(FSMTransition(stop, go, 0,10))
wait = fsm.add_transition(FSMTransition(go, hold, 1,20))
walk = fsm.add_transition(FSMTransition(hold, stop, 2,40))
drive = fsm.add_transition(FSMTransition(stop, go, 30, 'G'))
wait = fsm.add_transition(FSMTransition(go, hold, 5, 'Y'))
walk = fsm.add_transition(FSMTransition(hold, stop, 30, 'R'))

fsm.transitions()
</input>
<output></output>
</sage>
<p> Once the states and transitions as defined, the state machine can be<em>run</em> using <c>
process()</c> method. </p>
<p> Once the states and transitions are defined, the state machine can be run using
<c>process()</c> method, which then returns the intermediary outputs during the
state machine run.</p>
<sage>
<input>
# pass in the initial state and the list of inputs
_, final_state, outputs_history = fsm.process(
initial_state=go,
input_tape=[1, 2, 0],
_1, _2, outputs_history = fsm.process(
initial_state=go,
input_tape=[5, 30, 30],
)

# display final/current state
final_state
</input>
<output></output>
</sage>
<p>
<c>process()</c> method also returned the list of intermediary outputs during the state
machine run.</p>
<sage>
<input>
# print out the outputs of the state machine run
outputs_history
</input>
Expand All @@ -344,7 +374,14 @@
<c>graph()</c> command displays the graph representation of the state machine.</p>
<sage>
<input>
fsm.graph()
fsm.graph().show(
figsize=[6, 6],
vertex_size=800,
edge_labels=True,
vertex_labels=True,
edge_color=(.2,.4,1),
edge_thickness=1.0
)
</input>
<output></output>
</sage>
Expand Down
Loading

0 comments on commit 1056597

Please sign in to comment.