fas-js 1.3.0 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +674 -674
- package/README.md +165 -164
- package/lib/bundle.js +1 -1
- package/package.json +85 -80
package/README.md
CHANGED
|
@@ -1,164 +1,165 @@
|
|
|
1
|
-
# Finite Automaton Simulator
|
|
2
|
-
|
|
3
|
-
[](https://badge.fury.io/js/fas-js)
|
|
4
|
-
[](https://snyk.io/test/github/jml6m/fas-js)
|
|
6
|
-
[](https://codecov.io/gh/jml6m/fas-js)
|
|
7
|
-
[](https://npmjs.org/package/fas-js)
|
|
8
|
-
[](https://www.jsdelivr.com/package/npm/fas-js)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* For
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
{ from: "
|
|
73
|
-
{ from: "q2", to: "
|
|
74
|
-
{ from: "
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
{ from: "q1", to: "q1
|
|
80
|
-
{ from: "
|
|
81
|
-
{ from: "q2", to: "q3", input: "" },
|
|
82
|
-
{ from: "
|
|
83
|
-
{ from: "
|
|
84
|
-
{ from: "q4", to: "q4", input: "
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
simulateFSA("
|
|
129
|
-
simulateFSA("", dfa); // returns
|
|
130
|
-
simulateFSA("
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
stepOnceFSA("
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
simulateFSA("
|
|
138
|
-
simulateFSA("
|
|
139
|
-
simulateFSA("
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
stepOnceFSA("
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
1
|
+
# Finite Automaton Simulator
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/js/fas-js)
|
|
4
|
+
[](https://libraries.io/npm/fas-js)
|
|
5
|
+
[](https://snyk.io/test/github/jml6m/fas-js)
|
|
6
|
+
[](https://codecov.io/gh/jml6m/fas-js)
|
|
7
|
+
[](https://npmjs.org/package/fas-js)
|
|
8
|
+
[](https://www.jsdelivr.com/package/npm/fas-js)
|
|
9
|
+
[](https://github.com/jml6m/fas-js/network/alerts)
|
|
10
|
+
|
|
11
|
+
Easily create and simulate state machines using this JS library. Import into your own server side or browser based JS application.
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
###### Visualization of an FSA
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
Add the latest version of `fas-js` to your package.json:
|
|
18
|
+
```
|
|
19
|
+
npm install fas-js --save-dev
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Import the ES6 module:
|
|
23
|
+
```
|
|
24
|
+
var fas_js = require('fas-js');
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Import into HTML file
|
|
28
|
+
```
|
|
29
|
+
<script src="https://cdn.jsdelivr.net/npm/fas-js/lib/bundle.js"></script>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Background
|
|
33
|
+
A finite automaton is a formally defined state machine, a concept that can then be expanded on to build more complex and powerful computational machines. I highly recommend the book "Introduction to the Theory of Computation" by Michael Sipser if you want to learn more about FSAs and related concepts.
|
|
34
|
+
|
|
35
|
+
A **Finite State Automaton (FSA)** is defined as a 5-tuple (Q, Σ, δ, q0, F) where:
|
|
36
|
+
|
|
37
|
+
1. Q is a finite set called **states**
|
|
38
|
+
2. Σ is a finite set called **alphabet**
|
|
39
|
+
3. δ: Q x Σ → Q is the **transition function**
|
|
40
|
+
4. q0 ∈ Q is the **start state**
|
|
41
|
+
5. F ⊆ Q is the set of **accept states**
|
|
42
|
+
|
|
43
|
+
An FSA can be conceptualized as a [Directed Graph](https://en.wikipedia.org/wiki/Directed_graph), or more specifically, an [Oriented Graph](https://en.wikipedia.org/wiki/Orientation_(graph_theory)). It's often visualized in this way for teaching and demonstration purposes. It is also important to understand [Sets](https://en.wikipedia.org/wiki/Set_(mathematics)) and their logical operators when working with FSAs.
|
|
44
|
+
|
|
45
|
+
A **Deterministic Finite Automaton (DFA)** has exactly one transition for each symbol on every state. A **Nondeterministic Finite Automaton (NFA)** may have any number of transitions (including no transition) for an input symbol on any given state. NFAs may also include an ε-transition, a transition that occurs without consuming an input symbol. By definition, all DFAs are also NFAs. It also follows that all NFAs can be represented as a DFA.
|
|
46
|
+
|
|
47
|
+
## Creation
|
|
48
|
+
This library offers one method for creating an FSA. The parameters correspond to the definition above:
|
|
49
|
+
|
|
50
|
+
<span style="font-size:20px"><a name="createFSA" href="#createFSA">#</a> <b>createFSA</b>(<i>Q</i>: string[], <i>Σ</i>: string | string[], <i>δ</i>: Object[], <i>q0</i>: string, <i>F</i>: string[]): FSA [<>](https://github.com/jml6m/fas-js/blob/master/src/utils/FSAUtils.js#L125 "Source")</span>
|
|
51
|
+
|
|
52
|
+
### Inputs
|
|
53
|
+
<b>Q</b> cannot be empty, and each state name must be unique
|
|
54
|
+
```javascript
|
|
55
|
+
const states = ["q1", "q2"];
|
|
56
|
+
const states2 = ["q1", "q2", "q3", "q4"];
|
|
57
|
+
```
|
|
58
|
+
<b>Σ</b> cannot be empty, and can be passed in as one string (each character will be interpreted as a separate symbol) or a string array. Cannot contain duplicate symbols. For NFAs, you do not need to specify the empty string, it is implicitly added.
|
|
59
|
+
```javascript
|
|
60
|
+
const alphabet = "01"; // ["0", "1"]
|
|
61
|
+
const alph_array = ["0", "1", "up", "down", "*"];
|
|
62
|
+
```
|
|
63
|
+
<b>δ</b> is an array of objects that define the transitions between states. This object differs for DFAs and NFAs, and createFSA() will determine which to create based on the structure of this input.
|
|
64
|
+
* For DFA: `{from: "origin_state", to: "dest_state", input: "symbol"}`
|
|
65
|
+
* For NFA: `{from: "origin_state", to: "dest_state1,dest_state2,...", input: "symbol"}`
|
|
66
|
+
|
|
67
|
+
Input array for DFAs must contain a transition for each alphabet symbol on each origin state. Thus, the size of δ = size of Σ x size of Q. Σ cannot contain an empty string as a symbol for DFAs.
|
|
68
|
+
|
|
69
|
+
For NFAs, the `to` field can contain one or more destination states, comma separated, no spaces between state names. The `input` field can be `""`, indicating an ε (empty) transition.
|
|
70
|
+
```javascript
|
|
71
|
+
const dfa_tfunc = [
|
|
72
|
+
{ from: "q1", to: "q2", input: "1" },
|
|
73
|
+
{ from: "q2", to: "q1", input: "0" },
|
|
74
|
+
{ from: "q2", to: "q2", input: "1" },
|
|
75
|
+
{ from: "q1", to: "q1", input: "0" }
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
const nfa_tfunc = = [
|
|
79
|
+
{ from: "q1", to: "q1", input: "0" },
|
|
80
|
+
{ from: "q1", to: "q1,q2", input: "1" },
|
|
81
|
+
{ from: "q2", to: "q3", input: "0" },
|
|
82
|
+
{ from: "q2", to: "q3", input: "" },
|
|
83
|
+
{ from: "q3", to: "q4", input: "1" },
|
|
84
|
+
{ from: "q4", to: "q4", input: "0" },
|
|
85
|
+
{ from: "q4", to: "q4", input: "1" }
|
|
86
|
+
];
|
|
87
|
+
```
|
|
88
|
+
<b>q0</b> is the start state of the FSA. The first symbol of the input string is processed on this state. It must be a member of Q.
|
|
89
|
+
```javascript
|
|
90
|
+
const start = "q1";
|
|
91
|
+
```
|
|
92
|
+
<b>F</b> is the set of accept states, which determine whether a given input string is "accepted" by the FSA or "rejected". This determination is made after the last symbol of the input has been read. If any of the final states are in the accepting set, that string is accepted.
|
|
93
|
+
|
|
94
|
+
The set of accept states must be a subset of Q - it can also be an empty set (an FSA that always rejects). For simulation purposes, F is passed in as a string array that cannot contain duplicate states
|
|
95
|
+
```javascript
|
|
96
|
+
const accepts = ["q1"]; // Start state can also be an accept state
|
|
97
|
+
const accepts2 = ["q3", "q4"];
|
|
98
|
+
```
|
|
99
|
+
### Examples
|
|
100
|
+
```javascript
|
|
101
|
+
const dfa = createFSA(states, alphabet, dfa_tfunc, start, accepts);
|
|
102
|
+
const nfa = createFSA(states2, alphabet, nfa_tfunc, start, accepts2);
|
|
103
|
+
```
|
|
104
|
+
<span style="font-size:24px"><a name="FSA" href="#FSA">#</a> <b>FSA</b></span><br />
|
|
105
|
+
`createFSA()` returns an object with custom type. This object has no public properties, but does include helper methods available to the user.
|
|
106
|
+
|
|
107
|
+
<span style="font-size:18px"><b>getType</b>(): string</span> - returns either `"DFA"` or `"NFA"`
|
|
108
|
+
|
|
109
|
+
<span style="font-size:18px"><b>generateDigraph</b>(): string</span> - returns digraph according to [DOT](https://www.graphviz.org/doc/info/lang.html) language to be used for visualization.
|
|
110
|
+
|
|
111
|
+
## Simulation
|
|
112
|
+
There are two simulation options available:<br />
|
|
113
|
+
|
|
114
|
+
<span style="font-size:18px"><a name="simulateFSA" href="#simulateFSA">#</a> <b>simulateFSA</b>(<i>w</i>: string | string[], <i>fsa</i>: FSA, <i>logging</i>: boolean = false, <i>returnEndState</i>: boolean = false) [<>](https://github.com/jml6m/fas-js/blob/master/src/engine/Simulators.js#L10 "Source")</span>
|
|
115
|
+
|
|
116
|
+
Runs the entire input `w` through the `fsa`. `w` must only contain symbols from the alphabet defined in `fsa`. By default, the function returns a boolean signifying whether `w` was accepted by the `fsa`. If `returnEndState` is set to true, the function will instead return the final state (string) or the final array of states (string[]), depending on whether `fsa` is a DFA or NFA.
|
|
117
|
+
|
|
118
|
+
<span style="font-size:18px"><a name="stepOnceFSA" href="#stepOnceFSA">#</a> <b>stepOnceFSA</b>(w: string, qin: string | string[], fsa: FSA, logging: boolean = false) [<>](https://github.com/jml6m/fas-js/blob/master/src/engine/Simulators.js#L23 "Source")</span>
|
|
119
|
+
|
|
120
|
+
Returns the destination state(s), based on input symbol `w` and input state `qin`, as defined by δ of `fsa`. `w` must match a symbol from the alphabet defined in `fsa` (can also be the empty string). `qin` must be a state in Q. Use this function if you'd like to iterate through an input string step-by-step.
|
|
121
|
+
|
|
122
|
+
<sub>Note: In both functions above, a third `logging` parameter is available (defaults to false) which will print useful messages to the console as the simulator processes the input string. This can be used for debugging purposes or server-side logs. It is recommended to leave it defaulted to false for browser applications.
|
|
123
|
+
|
|
124
|
+
### Examples
|
|
125
|
+
Both simulators require an FSA object created with createFSA(). Here we will use the FSAs created in the [Examples](#Examples) above.
|
|
126
|
+
```javascript
|
|
127
|
+
// DFA Simulations
|
|
128
|
+
simulateFSA("0", dfa); // returns true
|
|
129
|
+
simulateFSA("01", dfa); // returns false
|
|
130
|
+
simulateFSA("", dfa); // returns true
|
|
131
|
+
simulateFSA("011", dfa, false, true); // returnEndState enabled, returns "q2"
|
|
132
|
+
|
|
133
|
+
stepOnceFSA("0", "q1", dfa); // returns "q1"
|
|
134
|
+
stepOnceFSA("1", "q1", dfa); // returns "q2"
|
|
135
|
+
|
|
136
|
+
// NFA Simulations
|
|
137
|
+
simulateFSA("0", nfa); // returns false
|
|
138
|
+
simulateFSA("01", nfa); // returns true
|
|
139
|
+
simulateFSA("0100", nfa); // returns false
|
|
140
|
+
simulateFSA("011", nfa, false, true); // returnEndState enabled, returns ["q1", "q2", "q3", "q4"]
|
|
141
|
+
|
|
142
|
+
stepOnceFSA("1", "q1", nfa); // returns ["q1", "q2", "q3"]
|
|
143
|
+
stepOnceFSA("0", ["q1","q2","q3"], nfa); // returns ["q1", "q3"]
|
|
144
|
+
|
|
145
|
+
// Step through an input string w on DFA
|
|
146
|
+
const w = "01101";
|
|
147
|
+
let inputState = start;
|
|
148
|
+
for (const symbol of w) {
|
|
149
|
+
inputState = stepOnceFSA(symbol, inputState, dfa);
|
|
150
|
+
}
|
|
151
|
+
// Now, check for acceptance
|
|
152
|
+
if(accepts.indexOf(inputState) !== -1)
|
|
153
|
+
console.log("Accepted!");
|
|
154
|
+
else
|
|
155
|
+
console.log("Rejected!");
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Demo
|
|
160
|
+
This library provides an engine that creates and simulates an FSA. The demo below provides a UI that utilizes this engine and visualizes the FSA as it's being processed. It's a great way to learn about FSAs and experiment with your own FSA creations! The UI and graph visualizations were built using [preact](https://github.com/developit/preact), [d3.js](https://github.com/d3/d3), and [d3-graphviz](https://github.com/magjac/d3-graphviz).
|
|
161
|
+
|
|
162
|
+
[Demo on ObservableHQ](https://beta.observablehq.com/@jml6m/state-machine-simulator) (Learn more about ObservableHQ [here](https://beta.observablehq.com/collection/@observablehq/introduction))
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
This library is distributed under the GPL 3.0 license found in the [LICENSE](https://github.com/jml6m/fas-js/blob/master/LICENSE) file.
|