diff --git a/.devcontainer.json b/.devcontainer.json index 7c4ad3ec..9fb95e39 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -1,12 +1,3 @@ -////////////////////////////////////////////////////////////// -// -// This file provides configuration options so that a PreTeXt -// project can be edited and built using GitHub's Codespaces. -// It is recommended to keep this in your repository even if you -// do not use this feature, as it will allow other to explore -// your project easily. -// -/////////////////////////////////////////////////////////////// { "name": "PreTeXt-Codespaces", diff --git a/.github/workflows/pretext-cli.yml b/.github/workflows/pretext-cli.yml index 3c73b5c8..c7b2ba08 100644 --- a/.github/workflows/pretext-cli.yml +++ b/.github/workflows/pretext-cli.yml @@ -3,11 +3,9 @@ on: # Runs on pull requests pull_request: branches: ["*"] - # Runs on pushes to main push: branches: ["main"] - # Runs on demand workflow_dispatch: @@ -15,44 +13,17 @@ jobs: build: runs-on: ubuntu-latest container: oscarlevin/pretext:full + steps: - name: Checkout source uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '3.x' - - - name: Install dependencies - run: | - apt-get update - apt-get install -y inkscape - shell: bash - - - name: Verify Inkscape Installation - run: inkscape --version - - name: install deps - run: | - pip install -r requirements.txt - pretext --version - - - name: ensure proper asset type in image references - run: ./update-img-refs.py source/ --to-svg + run: pip install -r requirements.txt - name: build deploy targets - run: | - version="$(pretext --version)" - major="$(echo $version | cut -d '.' -f 1)" - minor="$(echo $version | cut -d '.' -f 2)" - if [ "$major" -ge 2 -a "$minor" -ge 5 ]; then - echo "PreTeXt version is 2.5 or greater; using new build command" - pretext build --deploys - else - echo "PreTeXt version is less than 2.5, using old build command" - pretext build - fi + run: pretext build --deploys + - name: stage deployment run: pretext deploy --stage-only @@ -62,11 +33,6 @@ jobs: name: deploy path: output/stage - - name: ensure proper asset type in image references for pdf output - run: | - make svg-to-pdf - ./update-img-refs.py source/ --to-pdf - - name: Build PDF with PreTeXt run: pretext build print @@ -140,7 +106,7 @@ jobs: - name: Commit changes run: | - git add output/print/discrete-math-with-sage.pdf + git add output/print/main.pdf git commit -m "Update PDF" || echo "No changes to commit" - name: Force push to pdf-update branch diff --git a/.gitignore b/.gitignore index eaad9e29..2cd75baa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,9 @@ # ensure this file is tracked !.gitignore -# don't track unpublished builds or stage (note: Runestone uses `published`) +# don't track unpublished builds or stage output/web output/stage -published # don't track assets generated from source generated-assets @@ -99,16 +98,3 @@ codechat_config.yaml # Don't track local files under /venv (virtual local environment) venv - -# Don't track local temp files and generated files -*.local -*.bak -*.swp -*.old -*.log -*.tmp -assets/*/*.pdf - -# Don't track deprecated workflows -.github/workflows/deploy.yml -.github/workflows/test-build.yml diff --git a/Makefile b/Makefile deleted file mode 100644 index b896d141..00000000 --- a/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# Define the directory containing the SVG files -SVG_DIR := assets - -# Find all SVG files recursively in the assets directory -SVG_FILES := $(shell find $(SVG_DIR) -type f -name '*.svg') - -# Create a list of PDF files by replacing the .svg extension with .pdf -PDF_FILES := $(SVG_FILES:.svg=.pdf) - -# Check if Inkscape is available and print its version -INKSCAPE := $(shell command -v inkscape) -ifeq ($(INKSCAPE),) -$(error "Inkscape is required but is not installed or not on the PATH.") -else -INKSCAPE_VERSION := $(shell inkscape --version) -endif - -## svg-to-pdf: Run the full pipeline: check inkscape, clean generated PDFs, and convert SVGs to PDFs -svg-to-pdf: check-inkscape clean convert - -# Verify Inkscape installation and display its version -check-inkscape: - @echo "Using Inkscape: $(INKSCAPE_VERSION)" - -# Remove all generated PDF files in the assets directory -clean: - @echo "Cleaning up generated PDF files..." - find $(SVG_DIR) -type f -name '*.pdf' -exec rm -f {} + - @echo "Cleanup complete." - -# Convert all SVG files in the assets directory to PDFs -convert: $(PDF_FILES) - -# Pattern rule to convert a single SVG to a PDF -%.pdf: %.svg - @echo "Converting $< to $@..." - $(INKSCAPE) -o $@ $< - -## help: Display this help message -help: - @echo "Makefile for converting SVG files to PDF using Inkscape" - @echo - @echo "Available targets:" - @awk '/^##/ {print substr($$0, 4)}' $(MAKEFILE_LIST) | sort diff --git a/assets/finite-state-machines/first_traffic_light_FSM.png b/assets/finite-state-machines/first_traffic_light_FSM.png new file mode 100644 index 00000000..43d7d0c0 Binary files /dev/null and b/assets/finite-state-machines/first_traffic_light_FSM.png differ diff --git a/assets/finite-state-machines/first_traffic_light_FSM.svg b/assets/finite-state-machines/first_traffic_light_FSM.svg deleted file mode 100644 index 9cda8ba2..00000000 --- a/assets/finite-state-machines/first_traffic_light_FSM.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - diff --git a/assets/finite-state-machines/intersection_2_ways.png b/assets/finite-state-machines/intersection_2_ways.png new file mode 100644 index 00000000..48f9a1c2 Binary files /dev/null and b/assets/finite-state-machines/intersection_2_ways.png differ diff --git a/assets/finite-state-machines/intersection_4_ways.png b/assets/finite-state-machines/intersection_4_ways.png new file mode 100644 index 00000000..055c0e5d Binary files /dev/null and b/assets/finite-state-machines/intersection_4_ways.png differ diff --git a/assets/finite-state-machines/simple_traffic_light.png b/assets/finite-state-machines/simple_traffic_light.png new file mode 100644 index 00000000..1c2e4a76 Binary files /dev/null and b/assets/finite-state-machines/simple_traffic_light.png differ diff --git a/assets/finite-state-machines/simple_traffic_light.svg b/assets/finite-state-machines/simple_traffic_light.svg deleted file mode 100644 index b274affc..00000000 --- a/assets/finite-state-machines/simple_traffic_light.svg +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/project.ptx b/project.ptx index 2489cc80..10faf1f6 100644 --- a/project.ptx +++ b/project.ptx @@ -1,22 +1,8 @@ - + - - + + diff --git a/requirements.txt b/requirements.txt index c60720ca..be2a3ac1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ # -pretext == 2.11.2 +pretext == 2.5.2 \ No newline at end of file diff --git a/source/combinatorics/sec-combinatorics.ptx b/source/combinatorics/sec-combinatorics.ptx index 5397b879..db5da40d 100644 --- a/source/combinatorics/sec-combinatorics.ptx +++ b/source/combinatorics/sec-combinatorics.ptx @@ -4,40 +4,40 @@ Combinatorics - Factorial Function - - factorial - -

The factorial of a non-negative integer n, denoted by n!, is the product - of all positive integers less than or equal to n.

-

Compute the factorial of 5:

+ Factorial Functionfactorial +

+ The factorial of a non-negative integer n, denoted by n!, is the product of all positive integers less than or equal to n. +

+

+ Compute the factorial of 5: +

factorial(5) +
- Combinations - - combination - -

The combination (n, k) is an unordered selection of k objects from a set - of n objects.

+ Combinationscombination +

+ The combination (n, k) is an unordered selection of k objects from a set of n objects. +

-

Calculate the number of ways to choose 3 elements from a set of 5:

+

+ Calculate the number of ways to choose 3 elements from a set of 5: +

Combinations(5, 3).cardinality() +

List the combinations: @@ -46,40 +46,39 @@ Combinations(5, 3).list() + - - binomial - -

The binomial() function provides an alternative method to compute the number of - combinations.

+ binomial +

+ The binomial() function provides an alternative method to compute the number of combinations. +

binomial(5, 3) +
- Permutations - - permutation - -

A permutation (n, k) is an ordered selection of k objects from a set of - n objects.

+ Permutationspermutation +

+ A permutation (n, k) is an ordered selection of k objects from a set of n objects. +

-

To calculate the number of ways to choose 3 elements from a set of 5 when - the order matters, use the Permutations() method.

+

+ To calculate the number of ways to choose 3 elements from a set of 5 when the order matters, use the Permutations() method. +

Permutations(5, 3).cardinality() +

List the permutations: @@ -88,13 +87,19 @@ Permutations(5, 3).list() + -

When n = k, we can calculate permutations of n elements.

-

Calculate the number of permutations of a set with 3 elements:

+

+ When n = k, we can calculate permutations of n elements. +

+

+ Calculate the number of permutations of a set with 3 elements: +

Permutations(3).cardinality() +

List the permutations: @@ -103,6 +108,7 @@ Permutations(3).list() +

The following is an example of permutations of specified elements: @@ -113,14 +119,18 @@ A.list() + -

Choose 2:

+

+ Choose 2: +

A = Permutations(['a', 'b', 'c'], 2) A.list() +
diff --git a/source/finite-state-machines/sec-fsm-in-action.ptx b/source/finite-state-machines/sec-fsm-in-action.ptx index a81ef701..1ed33ef7 100644 --- a/source/finite-state-machines/sec-fsm-in-action.ptx +++ b/source/finite-state-machines/sec-fsm-in-action.ptx @@ -26,7 +26,7 @@ a transition event after a predefined duration.

- + Simple Traffic Light
@@ -88,14 +88,12 @@ - next - + next - output - + output diff --git a/source/finite-state-machines/sec-modeling-finite-state-machines.ptx b/source/finite-state-machines/sec-modeling-finite-state-machines.ptx index c972737e..1814c73b 100644 --- a/source/finite-state-machines/sec-modeling-finite-state-machines.ptx +++ b/source/finite-state-machines/sec-modeling-finite-state-machines.ptx @@ -9,12 +9,12 @@

Although Sage includes a dedicated built-in rich module to handle various types of - state machines, it may not always be sufficient to address certain use cases or - implement specific custom behaviors of the machine. Additionally, the built-in module allows state + state machines, it may not always be sufficient to address certain use cases or implement + specific custom behaviors of the machine. Additionally, the built-in module allows state machines to be defined and constructed in different ways, providing greater flexibility and making it more suitable from a programmer's perspective. However, it may not fully - conform to the precise definition given earlier. This highlights that it is still - possible to model, construct, display, and run relatively simple state machines by utilizing + conform to the precise definition given earlier. This highlights that it is still possible + to model, construct, display, and run relatively simple state machines by utilizing general-purpose tools, such as graphs and transition matrices, to represent and operate on state machines.

-
+ The Elevator State Machine

- Let's design a basic controller to an elevator to show the process of defining states, - creating a state transition graph, visualizing the state machine, and simulating its execution in - Sage.

+ Let's design a basic controller to an elevator to show the process of defining states, creating + a state transition graph, visualizing the state machine, and simulating its execution in Sage.

- Consider a 3-level elevator (floors 1 through 3). The elevator can be at one of the - three floors and moves in the same direction (up or down) until it reaches the top or bottom floor. - It stops at each floor along the way. The elevator has 3 buttons for users to select the - destination floor (only one can be selected at a time). Depending on the current position and the selected - floor, the elevator can go up, go down, or remain on the same floor.

- - - Description of the Elevator FSM -

This elevator system can be modeled and simulated using a finite-state machine with - states S=\{f_1, f_2, f_3\} representing each floor, the user inputs set X=\{b_1, b_2, b_3\} (where b_i - represents the button for i^{th} floor), and the outputs set Z=\{U, D, N\} for 'going up', 'going down', or 'going nowhere'.

- -

- The components of this FSM are transcribed in the following table.

-

- - The Elevator State Machine Definition - - - - - next - - - - output - - - - - current - - - b_1 - - - b_2 - - - b_3 - - - - b_1 - - - b_2 - - - b_3 - - - - - - f_1 - - - - f_1 - - - f_2 - - - f_3 - - - - N - - - U - - - U - - - - - - f_2 - - - - f_1 - - - f_2 - - - f_3 - - - - D - - - N - - - U - - - - - - f_3 - - - - f_1 - - - f_2 - - - f_3 - - - - D - - - D - - - N - - - -
-

- -

The following steps outline the approach to build and test the elevator controller system: -

    -
  1. -

    Define the elements of the Finite State Machine: States, Inputs, Transitions, and Outputs.

    -
  2. -
  3. -

    Construct the State Machine.

    -
  4. -
  5. -

    Run the machine using a sample input set.

    -
  6. -
-

-
- - Elements of the Elevator FSM -

- The first step is to define the states and transitions in the state machine, - which can be represented using lists and dictionaries.

- - - # Define state, input and output sets - states = ['f1', 'f2', 'f3'] - inputs = ['b1', 'b2', 'b3'] - outputs = ['U', 'D', 'N'] - - # Transitions as a dictionary {(current_state, input): next_state} - transitions = { - ('f1', 'b1'): 'f1', - ('f1', 'b2'): 'f2', - ('f1', 'b3'): 'f3', - - ('f2', 'b1'): 'f1', - ('f2', 'b2'): 'f2', - ('f2', 'b3'): 'f3', - - ('f3', 'b1'): 'f1', - ('f3', 'b2'): 'f2', - ('f3', 'b3'): 'f3', - } - - # The machine outputs control how the elevator would move - outputs = { - ('f1', 'b1'): 'N', - ('f1', 'b2'): 'U', - ('f1', 'b3'): 'U', - - ('f2', 'b1'): 'D', - ('f2', 'b2'): 'N', - ('f2', 'b3'): 'U', - - ('f3', 'b1'): 'D', - ('f3', 'b2'): 'D', - ('f3', 'b3'): 'N', - } - - # Display the machine configuration - print('States: ', states) - print('Transitions: ', transitions) - print('Outputs: ', outputs) - - -
- - Graph Model of the Elevator FSM -

- An FSM can be modeled as a graph where vertices represent the states, and the directed - edge between vertices is the relationship between two states (the transition from - one state to the other). The weight of a directed edge between two vertices represents - the pair of input and output associated with the transition between the two states.

- -

In Sage, the DiGraph class can be used to represent the states, transitions, - and outputs of the state machine as a directed graph, leveraging the graph structure - to visualize the state machine representation.

- - - # 'DiGraph' is imported by default. If not, it can be imported as follow - # from sage.graphs.digraph import DiGraph - - # Initialize a directed graph - elevator_fsm = DiGraph(loops=True) - - # Add states as vertices - elevator_fsm.add_vertices(states) - - # Add transitions and outputs as edges - for (_state, _input), next_state in transitions.items(): - _output = outputs[(_state, _input)] - edge_label = f"{_input}, {_output}" - elevator_fsm.add_edge(_state, next_state, label=edge_label) - - # Display the graph (state machine) - elevator_fsm.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, - ) - - -

The show() method renders a graphical representation of the state machine. - Each vertex in the graph represents a state, and each directed edge represents a - transition, labeled as (input, output).

-
- - Run the Elevator State Machine -

- Next, the state machine's behavior can be simulated by defining a function that - processes a list of inputs and transitions through the states accordingly.

- - - # Function to run the state machine - def run_state_machine(start_state, inputs): - current_state = start_state - for _input in inputs: - 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" - f"Output: {current_output}\n" - ) - else: - print( - f"No transition/output available for input {_input} in state {current_state}" - ) - break - - print(f"Last state: {current_state}") - - # Example of running the state machine - start_state = 'f2' - inputs = ['b1', 'b1', 'b3', 'b2'] - - run_state_machine(start_state, inputs) - - -

The run_state_machine() function simulates the state machine by processing a - list of inputs starting from an initial state.

-
+ Consider a 3-level elevator (floors 1 through 3). The elevator has 3 buttons for users to select + the destination floor (only one can be selected at a time). Depending on the current position and + the selected floor, the elevator can go up, go down, or remain on the same floor.

+ + + Description of the Elevator FSM +

+ This elevator system can be modeled and simulated using a finite-state machine with + states S=\{f_1, f_2, f_3\} representing each floor, the user inputs set X=\{b_1, b_2, b_3\} + (where b_i represents the button for i^{th} floor), and the outputs set Z=\{U, D, N\} + for 'going up', 'going down', or 'going nowhere'.

+ +

+ The components of this FSM are transcribed in the following table.

+

+ + The Elevator State Machine Definition + + + + + + next + + + + output + + + + current + + b_1 + b_2 + b_3 + + b_1 + b_2 + b_3 + + + + f_1 + + f_1 + f_2 + f_3 + + N + U + U + + + + f_2 + + f_1 + f_2 + f_3 + + D + N + U + + + + f_3 + + f_1 + f_2 + f_3 + + D + D + N + + +
+

+ +

+ The following steps outline the approach to build and test the elevator controller system: +

    +
  1. +

    Define the elements of the Finite State Machine: States, Inputs, Transitions, and Outputs.

    +
  2. +
  3. +

    Construct the State Machine.

    +
  4. +
  5. +

    Run the machine using a sample input set.

    +
  6. +
+

+
+ + Elements of the Elevator FSM +

+ The first step is to define the states and transitions in the state machine, + which can be represented using lists and dictionaries.

+ + + # Define state, input and output sets + states = ['f1', 'f2', 'f3'] + inputs = ['b1', 'b2', 'b3'] + outputs = ['U', 'D', 'N'] + + # Transitions as a dictionary {(current_state, input): next_state} + transitions = { + ('f1', 'b1'): 'f1', + ('f1', 'b2'): 'f2', + ('f1', 'b3'): 'f3', + + ('f2', 'b1'): 'f1', + ('f2', 'b2'): 'f2', + ('f2', 'b3'): 'f3', + + ('f3', 'b1'): 'f1', + ('f3', 'b2'): 'f2', + ('f3', 'b3'): 'f3', + } + + # The machine outputs control how the elevator would move + outputs = { + ('f1', 'b1'): 'N', + ('f1', 'b2'): 'U', + ('f1', 'b3'): 'U', + + ('f2', 'b1'): 'D', + ('f2', 'b2'): 'N', + ('f2', 'b3'): 'U', + + ('f3', 'b1'): 'D', + ('f3', 'b2'): 'D', + ('f3', 'b3'): 'N', + } + + # Display the machine configuration + print('States: ', states) + print('Transitions: ', transitions) + print('Outputs: ', outputs) + + + +
+ + Graph Model of the Elevator FSM +

+ An FSM can be modeled as a graph where vertices represent the states, and the directed + edge between vertices is the relationship between two states (the transition from one + state to the other). The weight of a directed edge between two vertices represents the + pair of input and output associated with the transition between the two states.

+ +

In Sage, the DiGraph class can be used to represent the states, transitions, and + outputs of the state machine as a directed graph, leveraging the graph structure to + visualize the state machine representation.

+ + + # 'DiGraph' is imported by default. If not, it can be imported as follow + # from sage.graphs.digraph import DiGraph + + # Initialize a directed graph + elevator_fsm = DiGraph(loops=True) + + # Add states as vertices + elevator_fsm.add_vertices(states) + + # Add transitions and outputs as edges + for (_state, _input), next_state in transitions.items(): + _output = outputs[(_state, _input)] + edge_label = f"{_input}, {_output}" + elevator_fsm.add_edge(_state, next_state, label=edge_label) + + # Display the graph (state machine) + elevator_fsm.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, + ) + + + +

The show() method renders a graphical representation of the state machine. + Each vertex in the graph represents a state, and each directed edge represents a + transition, labeled as (input, output).

+
+ + Run the Elevator State Machine +

+ Next, the state machine's behavior can be simulated by defining a function that + processes a list of inputs and transitions through the states accordingly.

+ + + # Function to run the state machine + def run_state_machine(start_state, inputs): + current_state = start_state + for _input in inputs: + 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" + f"Output: {current_output}\n" + ) + else: + print( + f"No transition/output available for input {_input} in state {current_state}" + ) + break + + print(f"Last state: {current_state}") + + # Example of running the state machine + start_state = 'f2' + inputs = ['b1', 'b1', 'b3', 'b2'] + + run_state_machine(start_state, inputs) + + + +

The run_state_machine() function simulates the state machine by processing a list + of inputs starting from an initial state.

+
@@ -321,41 +270,38 @@ Let's design a simple traffic light controller to illustrate alternative methods for defining, visualizing, and executing finite state machines in Sage.

-

Consider a simplified traffic light system controlled by preset timers. This system +

+ Consider a simplified traffic light system controlled by preset timers. This system operates through three phases that represent the flow of road traffic: Free-flowing, Slowing-down, and Halted. These phases correspond to the traffic light signals: green, yellow, and red, controlling the flow of traffic. The system uses three timer settings: - 30 seconds, 20 seconds, and 5 seconds. When a timer expires, it triggers - the transition to the next phase. Initially, the light is green, the traffic is flowing, and: + 30 seconds, 20 seconds, and 5 seconds. When a timer expires, it triggers the transition + to the next phase. Initially, the light is green, the traffic is flowing, and:

Description of the Traffic Light FSM -

In this traffic light system, the three phases representing the flow of road - traffic: Free-flowing (F), Slowing-down (S), and Halted (H) - are the states S=\{F, S, H\} of the FSM. These phases correspond to the - traffic light signals: green (G), yellow (Y), and red (R), which are the outputs set - Z=\{G, Y, R\} of the system. The timers driving the transitions are the inputs set - X=\{t_{5s}, t_{20s}, t_{30s}\} of this traffic light system.

+

+ In this traffic light system, the three phases representing the flow of road traffic: Free-flowing (F), Slowing-down (S), + and Halted (H) are the states S=\{F, S, H\} of the FSM. These phases correspond to the traffic light signals: green (G), + yellow (Y), and red (R), which are the outputs set Z=\{G, Y, R\} of the system. The timers driving the transitions are the inputs + set X=\{t_{5s}, t_{20s}, t_{30s}\} of this traffic light system.

The following table summarize the elements of the traffic light FSM.

@@ -365,147 +311,96 @@ - next + next - output + output current - - t_{5s} - - - t_{20s} - - - t_{30s} - - - - t_{5s} - - - t_{20s} - - - t_{30s} - + t_{5s} + t_{20s} + t_{30s} + + t_{5s} + t_{20s} + t_{30s} - - F - - - - F - - - F - - - S - - - - G - - - G - - - Y - + F + + F + F + S + + G + G + Y - - S - - - - H - - - S - - - S - - - - R - - - Y - - - Y - + S + + H + S + S + + R + Y + Y - - H - - - - H - - - F - - - H - - - - R - - - G - - - R - + H + + H + F + H + + R + G + R

- By applying the same steps and approach as in the previous section, the traffic light - controller system will be built and tested, this time utilizing the Sage built-in module and functions.

+ By applying the same steps and approach as in the previous section, the traffic light controller + system will be built and tested, this time utilizing the Sage built-in module and functions.

Using `FiniteStateMachine' Module -

Sage FiniteStateMachine built-in library provides a powerful tool to model, - construct as well as simulate state machines of various systems. This module will be - leveraged to showcase its capabilities on the given example, and demonstrating how - it can be used to construct and display the FSM, manage its state transitions and outputs.

-

The command FiniteStateMachine() constructs an empty state machine (no states, no transitions).

+

+ Sage FiniteStateMachine built-in library provides a powerful tool to model, construct as + well as simulate state machines of various systems. This module will be leveraged to showcase + its capabilities on the given example, and demonstrating how it can be used to construct and + display the FSM, manage its state transitions and outputs.

+

+ The command FiniteStateMachine() constructs an empty state machine (no states, no transitions).

from sage.combinat.finite_state_machine import FSMState # FSM states, inputs and outputs - states = ['F', 'S', 'H'] # Free-flowing, Slowing-down, Halted + states = ['F', 'S', 'H'] # Free-flowing, Slowing-down, Halted inputs = ['t30s', 't5s', 't20s'] # timer durations before state transitions - outputs = ['G', 'Y', 'R'] # traffic light: Green, Yellow, Red + outputs = ['G', 'Y', 'R'] # traffic light: Green, Yellow, Red # Create an empty state machine object traffic_light_fsm = FiniteStateMachine() traffic_light_fsm + -

The function FSMState() defines a state for a given label. The is_initial - flag can be set to true to set the current state as the initial state of - the finite state machine. The method add_state() appends the created state to - an existing state machine.

+

+ The function FSMState() defines a state for a given label. The is_initial flag can + be set to true to set the current state as the initial state of the finite state machine. + The method add_state() appends the created state to an existing state machine.

# Define a new state then adding it @@ -519,6 +414,7 @@ # the FiniteStateMachine instance traffic_light_fsm +

To check whether or not a finite state machine has a state defined, has_state() method can be used by passing in the state label (case-sensitive).

@@ -526,33 +422,35 @@ traffic_light_fsm.has_state('F') + -

The function states() enumerates the list of all defined states of the state - machine.

+

+ The function states() enumerates the list of all defined states of the state machine.

traffic_light_fsm.states() + -

The method initial_states() lists the defined initial state(s) of the state - machine.

+

+ The method initial_states() lists the defined initial state(s) of the state machine.

traffic_light_fsm.initial_states() + -

To define a new transition between two states (as well as the input triggering the - transition, and the output associated with the state transition), the method - FSMTransition() can be used. The method add_transition() attaches the - defined transition to the state machine, and the function transitions() - enumerates the list of all defined transitions of the state machine.

+

+ To define a new transition between two states (as well as the input triggering the transition, and + the output associated with the state transition), the method FSMTransition() can be used. The + method add_transition() attaches the defined transition to the state machine, and the function + transitions() enumerates the list of all defined transitions of the state machine.

from sage.combinat.finite_state_machine import FSMTransition # defining 3 transitions, and associating them the state machine - # After 30sec, transition from free-flowing to slowing-down, and set traffic - # light to yellow + # After 30sec, transition from free-flowing to slowing-down, and set traffic light to yellow traffic_light_fsm.add_transition( FSMTransition( from_state=free_flowing, @@ -562,19 +460,19 @@ ) ) - # After 5sec, transition from slowing-down to halted and set traffic light to red + # After 5sec, transition from slowing-down to halted, and set traffic light to red traffic_light_fsm.add_transition(FSMTransition(slowing_down, halted, 't5s', 'R')) - # After 30sec, transition from halted back to free-flowing, and set traffic - # light to green + # After 30sec, transition from halted back to free-flowing, and set traffic light to green traffic_light_fsm.add_transition(FSMTransition(halted, free_flowing, 't20s', 'G')) traffic_light_fsm.transitions() + -

An alternative method for defining state transitions in an FSM is by using the - add_transitions_from_function() method. This approach accepts a callable - function that takes two states as arguments: the source state and the target state. +

+ An alternative method for defining state transitions in an FSM is by using the add_transitions_from_function() method. + This approach accepts a callable function that takes two states as arguments: the source state and the target state. The following code demonstrates how this can be implemented.

@@ -600,10 +498,11 @@ traffic_light_fsm.add_transitions_from_function(transit_function) traffic_light_fsm.transitions() +

Once the states and transitions are defined, the state machine can be run using - process() method, which then returns the intermediary outputs during the state - machine run.

+ process() method, which then returns the intermediary outputs during the + state machine run.

# pass in the initial state and the list of inputs @@ -615,8 +514,10 @@ # print out the outputs of the state machine run outputs_history + -

The graph() command displays the graph representation of the state machine.

+

+ The graph() command displays the graph representation of the state machine.

traffic_light_fsm.graph().show( @@ -628,9 +529,10 @@ edge_thickness=1.0 ) + -

The FiniteStateMachine class also offers representation of the - state machine using the latex_options() method.

+

The FiniteStateMachine class also offers representation of the state + machine using the latex_options() method.

# define printout options @@ -642,25 +544,25 @@ print(latex(traffic_light_fsm)) -

Note that the printout may not have all elements displayed. However, it - can still be customized further. The following figure shows a rendering of the above commands.

+

+ Note that the printout may not have all elements displayed. However, it can still be + customized further. The following figure shows a rendering of the above commands.

- - - + FSM graph output.
Using `Transducer' Module -

Sage Transducer is a specialization of the generic FiniteStateMachine - class. The Transducer class creates a finite state machine that support - optional final states, and whose transitions have input and output labels.

+

+ Sage Transducer is a specialization of the generic FiniteStateMachine class. + The Transducer class creates a finite state machine that support optional final states, and + whose transitions have input and output labels.

-

Let's see how to create another state machine using Transducer and for the - same traffic light example.

+

+ Let's see how to create another state machine using Transducer and for the same traffic light example.

# the module allows the instantiation of a state machine by passing @@ -693,44 +595,53 @@ ) traffic_light_transducer + -

The member variable input_alphabet lists the set of the transducer inputs set.

+

+ The member variable input_alphabet lists the set of the transducer inputs set.

traffic_light_transducer.input_alphabet + -

The member variable output_alphabet lists the set of the transducer outputs set.

+

+ The member variable output_alphabet lists the set of the transducer outputs set.

traffic_light_transducer.output_alphabet + -

Since a Transducer is also a FiniteStateMachine , the method - has_state() can still be used to check whether or not a given state exists in - the defined transducer (by passing in the case-sensitive state label).

+

Since a Transducer is also a FiniteStateMachine , the method has_state() can + still be used to check whether or not a given state exists in the defined transducer (by passing + in the case-sensitive state label).

traffic_light_transducer.has_state('F') + -

The function states() enumerates the list of all defined states of the state - machine.

+

+ The function states() enumerates the list of all defined states of the state machine.

traffic_light_transducer.states() + -

The method initial_states() lists the defined initial state(s) of the state - machine.

+

+ The method initial_states() lists the defined initial state(s) of the state machine.

traffic_light_transducer.initial_states() + -

After defining the states and transitions, the transducer can be executed using the - process() method from the parent FiniteStateMachine class. This method - returns the intermediate outputs generated during the execution of the state machine.

+

+ After defining the states and transitions, the transducer can be executed using the process() method + from the parent FiniteStateMachine class. This method returns the intermediate outputs generated + during the execution of the state machine.

# fetching the initial state by its label @@ -744,15 +655,15 @@ outputs_history + -

The graph() command displays the graph representation of the transducer-based - state machine.

- +

+ The graph() command displays the graph representation of the transducer-based state machine.

+ traffic_light_transducer.graph().show( @@ -764,14 +675,15 @@ edge_thickness=1.0 ) +

- The above are basic commands with a typical workflow of defining and running of simple - finite state machines. The general structure of the state machine can be adapted to fit - different use cases. The examples shown can be customized and fine-tuned to reflect more - complex scenarios (more states, different input sequences, etc.)

+ The above are basic commands with a typical workflow of defining and running of simple finite + state machines. The general structure of the state machine can be adapted to fit different use + cases. The examples shown can be customized and fine-tuned to reflect more complex scenarios + (more states, different input sequences, etc.)

diff --git a/source/frontmatter.ptx b/source/frontmatter.ptx index 362ec214..491bc037 100644 --- a/source/frontmatter.ptx +++ b/source/frontmatter.ptx @@ -182,7 +182,7 @@

\textbf{PDF Download}: This book is available for free download in PDF format by clicking - here. + here.

diff --git a/source/functions/sec-functions.ptx b/source/functions/sec-functions.ptx index 6a07653c..43c04e95 100644 --- a/source/functions/sec-functions.ptx +++ b/source/functions/sec-functions.ptx @@ -1,40 +1,39 @@
- Functions - - functions (math) - + Functionsfunctions (math) -

A function from a set A into a set B is a relation from A into B - such that each element of A is related to exactly one element of the set B. - The set A is called the domain of the function, and the set B is called - the co-domain. Functions are fundamental in both mathematics and computer science for - describing mathematical relationships and implementing computational logic.

+

+ A function from a set A into a set B is a relation from A into B such that each element of A is related to exactly one element of the set B. The set A is called the domain of the function, and the set B is called the co-domain. Functions are fundamental in both mathematics and computer science for describing mathematical relationships and implementing computational logic. +

In Sage, functions can be defined using direct definition.

-

For example, defining a function f : \mathbb{R} \rightarrow \mathbb{R} to - calculate the cube of a number, such as 3:

+

+ For example, defining a function f : \mathbb{R} \rightarrow \mathbb{R} to calculate the cube of a number, such as 3: +

f(x) = x^3 show(f) f(3) +
Graphical Representations

- Sage provides powerful tools for visualizing functions, enabling you to explore the - graphical representations of mathematical relationships. + Sage provides powerful tools for visualizing functions, enabling you to explore the graphical representations of mathematical relationships. +

+

+ For example, to plot the function f(x) = x^3 over the interval [-2, 2]:

-

For example, to plot the function f(x) = x^3 over the interval [-2, 2]:

f(x) = x^3 plot(f(x), x, -2, 2) +
diff --git a/source/functions/sec-recursion.ptx b/source/functions/sec-recursion.ptx index 1f1b2322..bfbf07c6 100644 --- a/source/functions/sec-recursion.ptx +++ b/source/functions/sec-recursion.ptx @@ -1,39 +1,25 @@
- Recursion - - recursion - + Recursionrecursion

- Recursion is a method where the solution to a problem depends on solutions to smaller - instances of the same problem. This approach is extensively used in mathematics and - computer science, especially in the computation of binomial coefficients, the evaluation - of polynomials, and the generation of sequences. + Recursion is a method where the solution to a problem depends on solutions to smaller instances of the same problem. This approach is extensively used in mathematics and computer science, especially in the computation of binomial coefficients, the evaluation of polynomials, and the generation of sequences.

- Recursion in Sequences - - sequence - + Recursion in Sequencessequence

- A recursive sequence is defined by one or more base cases and a recursive step that - relates each term to its predecessors. + A recursive sequence is defined by one or more base cases and a recursive step that relates each term to its predecessors.

-

Given a sequence defined by a recursive formula, we can ask Sage to find its closed - form. Here, s is a function representing the sequence defined by recursion. The - equation eqn defines the recursive relation s_n = s_{n-1} + 2\cdot s_{n-2}. - The rsolve() function is then used to find a closed-form solution to this - recurrence, given the initial conditions s_0 = 2 and s_1 = 7. At last, we - use the SR() function to convert from Python notation to mathematical notation.

+

+ Given a sequence defined by a recursive formula, we can ask Sage to find its closed form. Here, s is a function representing the sequence defined by recursion. The equation eqn defines the recursive relation s_n = s_{n-1} + 2\cdot s_{n-2}. The rsolve() function is then used to find a closed-form solution to this recurrence, given the initial conditions s_0 = 2 and s_1 = 7. At last, we use the SR() function to convert from Python notation to mathematical notation. +

from sympy import Function, rsolve @@ -43,16 +29,15 @@ sol = rsolve(eqn, s(n), {s(0): 2, s(1): 7}) show(SR(sol)) + -

We can use the show() function to make the output visually more pleasing; you can - try removing it and see how the output looks.

- - Fibonacci - -

Similarly, the Fibonacci sequence is another example of a recursive sequence, defined by - the base cases F_0 = 0 and F_1 = 1, and the recursive relation F_n = - F_{n-1} + F_{n-2} for n > 1. This sequence is a cornerstone example in the - study of recursion.

+

+ We can use the show() function to make the output visually more pleasing; you can try removing it and see how the output looks. +

+ Fibonacci +

+ Similarly, the Fibonacci sequence is another example of a recursive sequence, defined by the base cases F_0 = 0 and F_1 = 1, and the recursive relation F_n = F_{n-1} + F_{n-2} for n > 1. This sequence is a cornerstone example in the study of recursion. +

from sympy import Function, rsolve @@ -62,33 +47,30 @@ fib_sol = rsolve(fib_eqn, F(n), {F(0): 0, F(1): 1}) show(SR(fib_sol)) + -

The show() function is again used here to present the solution in a more - accessible mathematical notation, illustrating the power of recursive functions to - describe complex sequences with simple rules.

-

We can also write a function fib() to compute the nth Fibonacci number by - iterating and updating the values of two consecutive Fibonacci numbers in the sequence. - Let's calculate the third Fibonacci number.

+

+ The show() function is again used here to present the solution in a more accessible mathematical notation, illustrating the power of recursive functions to describe complex sequences with simple rules. +

+

+ We can also write a function fib() to compute the nth Fibonacci number by iterating and updating the values of two consecutive Fibonacci numbers in the sequence. Let's calculate the third Fibonacci number. +

def fib(n): - # assuming n is always an int - if n < 2: - return n + if n == 0 or n == 1: return n else: - # the initial terms F0 and F1 - U = 0; V = 1 + U = 0; V = 1 # the initial terms F0 and F1 for k in range(2, n+1): - W = U + V; - U = V; V = W + W = U + V; U = V; V = W return V - - # display the first 10 Fibonacci numbers - [fib(i) for i in range(10)] + fib(3) + -

We go back to the previous method where we calculated the closed form fib_sol and - evaluate it now at n = 3.

+

+ We go back to the previous method where we calculated the closed form fib_sol and evaluate it now at n = 3. +

from sympy import Function, rsolve, Symbol, simplify @@ -100,28 +82,27 @@ fib3 = simplify(fib_sol.subs(n, 3)) show(SR(fib3)) + -

As we can see, we obtain the same number either by evaluating the closed form at n = - 3 or by finding the third Fibonacci number directly by iteration.

+

+ As we can see, we obtain the same number either by evaluating the closed form at n = 3 or by finding the third Fibonacci number directly by iteration. +

- Recursion with Binomial Coefficients - - binomial coefficients - -

Binomial coefficients, denoted as \binom{n}{k}, count the number of ways to - choose k elements from an n-element set. They can be defined recursively. - Sage can compute binomial coefficients using the binomial(n, k) function.

+ Recursion with Binomial Coefficientsbinomial coefficients +

+ Binomial coefficients, denoted as \binom{n}{k}, count the number of ways to choose k elements from an n-element set. They can be defined recursively. Sage can compute binomial coefficients using the binomial(n, k) function. +

binomial(5, 3) +

- We can also explore the recursive nature of binomial coefficients by defining a function - ourselves recursively. + We can also explore the recursive nature of binomial coefficients by defining a function ourselves recursively.

@@ -130,11 +111,14 @@ return 1 else: return binomial_recursive(n-1, k-1) + binomial_recursive(n-1, k) + binomial_recursive(5, 3) + -

This function implements the recursive formula \binom{n}{k} = \binom{n-1}{k-1} + - \binom{n-1}{k}, with base cases \binom{n}{0} = \binom{n}{n} = 1.

+

+ This function implements the recursive formula \binom{n}{k} = \binom{n-1}{k-1} + \binom{n-1}{k}, with base cases \binom{n}{0} = \binom{n}{n} = 1. +

diff --git a/source/logic/sec-truth-table.ptx b/source/logic/sec-truth-table.ptx index 1537b861..1f1f88fb 100644 --- a/source/logic/sec-truth-table.ptx +++ b/source/logic/sec-truth-table.ptx @@ -1,45 +1,41 @@
- Truth Tables - - truth table - -

The truthtable() function in Sage generates the truth table for a given logical - expression.

- - - - A = propcalc.formula('p -> q') - A.truthtable() - - -

An alternative way to display the table with better separation and visuals would be to use - SymbolicLogic(), statement(), truthtable() and the print_table() functions.

- - - A = SymbolicLogic() - B = A.statement('p -> q') - C = A.truthtable(B) - A.print_table(C) - -

- The command SymbolicLogic() creates an instance for handling symbolic logic operations, - while statement() defines the given statement. The truthtable() method generates a - truth table for this statement, and print_table() displays it.

-

Expanding on the concept of truth tables, we can analyze logical expressions involving three - variables. This provides a deeper understanding of the interplay between multiple - conditions. The truthtable() function supports expressions with a number of variables - that is practical for computational purposes, if the list of variables becomes too lengthy - (such as extending beyond the width of a LaTeX page), the truth table's columns may run off - the screen. Additionally, the function's performance may degrade with a very large number of - variables, potentially increasing the computation time.

+ Expanding on the concept of truth tables, we can analyze logical expressions involving three variables. This provides a deeper understanding of the interplay between multiple conditions. The truthtable() function supports expressions with a number of variables that is practical for computational purposes, if the list of variables becomes too lengthy (such as extending beyond the width of a LaTeX page), the truth table's columns may run off the screen. Additionally, the function's performance may degrade with a very large number of variables, potentially increasing the computation time. +

B = propcalc.formula('(p & q) -> r') diff --git a/update-img-refs.py b/update-img-refs.py deleted file mode 100755 index d47666d1..00000000 --- a/update-img-refs.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python3 -import re -import argparse -from enum import Enum -from pathlib import Path - -class ImageFormat(Enum): - """supported image asset types""" - SVG = "svg" - PDF = "pdf" - - @classmethod - def default(cls): - """default image format""" - return cls.SVG - -def update_references_in_file(file_path: str, to_format: ImageFormat) -> bool: - """ - Update image references in a single PreTeXt XML (.ptx) file to the specified format. - """ - # Read the input file - with open(file_path, 'r', encoding='utf-8') as file: - content = file.read() - - # Determine the target format - from_format = ImageFormat.PDF if to_format == ImageFormat.SVG else ImageFormat.SVG - - # Check if the content needs updating (only proceed if we need to change references) - updated_content = re.sub( - rf'(