nfa2dfa 1.0.2 → 1.0.4
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.
- checksums.yaml +4 -4
- data/bin/automaton +33 -0
- data/lib/nfa2dfa.rb +0 -1
- data/spec/automaton_spec.rb +134 -0
- data/spec/state_spec.rb +101 -0
- data/spec/transition_spec.rb +28 -0
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0dd869aacabd6004faccc4de1a7f9b35f7ec8b3c
|
4
|
+
data.tar.gz: dfe9e1cb14760e786a2b4ea5b0de62620c53e2ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ecb4a5153853a308678183c024a342d59c1f5a8272398bc03243351656322322959c3acabcdf840c19f62feafb9ec63a74ab087cf881790c222d194364dae20e
|
7
|
+
data.tar.gz: bc6bfa2a48abeac27a93521dfe5184a8ff4f1e7a07a407d5ba019027099acf5195e786d6604e9ab9cde6fab834f64b6112244c80259b8e336a65f55261a85feb
|
data/bin/automaton
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'commander/import'
|
5
|
+
require 'nfa2dfa'
|
6
|
+
program :version, '0.0.1'
|
7
|
+
program :description, 'Controller of automaton'
|
8
|
+
program :name, 'automaton'
|
9
|
+
|
10
|
+
command :create_finite do |c|
|
11
|
+
c.syntax = 'automaton create_finite [options]'
|
12
|
+
c.description = 'Creates determined automaton from file and writes it into "<input_file>.determined"'
|
13
|
+
c.action do |args|
|
14
|
+
args.each do |arg|
|
15
|
+
input_mat = Nfa2Dfa::Automaton.init(arg)
|
16
|
+
output_mat = input_mat.determine
|
17
|
+
data = output_mat.to_str
|
18
|
+
File.open(arg + ".determined", 'w') { |file| file.write(data) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
command :automaton_to_png do |c|
|
24
|
+
c.syntax = 'automaton automaton_to_png [options]'
|
25
|
+
c.description = 'Creates png representation of automaton from input'
|
26
|
+
c.action do |args|
|
27
|
+
args.each do |arg|
|
28
|
+
input_mat = Nfa2Dfa::Automaton.init(arg)
|
29
|
+
data = input_mat.to_graph(arg + ".png")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/lib/nfa2dfa.rb
CHANGED
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'spec_helper'
|
3
|
+
require_relative '../lib/automaton.rb'
|
4
|
+
|
5
|
+
describe Nfa2Dfa::Automaton do
|
6
|
+
before(:each) do
|
7
|
+
@file_path = "#{File.dirname(__FILE__)}/testdata/valid_input.automat"
|
8
|
+
@file_path2 = "#{File.dirname(__FILE__)}/testdata/valid_input2.automat"
|
9
|
+
@file_path3 = "#{File.dirname(__FILE__)}/testdata/valid_input3.automat"
|
10
|
+
end
|
11
|
+
context "initializes as" do
|
12
|
+
it "valid automaton" do
|
13
|
+
mat = Automaton.init(@file_path)
|
14
|
+
mat.should_not eq NIL
|
15
|
+
mat.class.should eq Nfa2Dfa::Automaton
|
16
|
+
end
|
17
|
+
it "invalid automaton, when there is invalid input" do
|
18
|
+
mat = Automaton.init("#{File.dirname(__FILE__)}/testdata/invalid_input.automat")
|
19
|
+
mat.should eq NIL
|
20
|
+
end
|
21
|
+
end
|
22
|
+
it "should be exportable in same format by method 'to_str'" do
|
23
|
+
valid_str = "z f\na b\nz-a-f f-b-f\nz\nf"
|
24
|
+
mat = Automaton.init(@file_path)
|
25
|
+
mat.to_str.should eq valid_str
|
26
|
+
end
|
27
|
+
|
28
|
+
context "accepts method resolves" do
|
29
|
+
subject { Automaton.init(@file_path) }
|
30
|
+
it "valid words" do
|
31
|
+
(subject.accepts? "a b").should eq true
|
32
|
+
(subject.accepts? "a").should eq true
|
33
|
+
(subject.accepts? "a b b b").should eq true
|
34
|
+
(subject.accepts? "a b b").should eq true
|
35
|
+
end
|
36
|
+
|
37
|
+
it "invalid words" do
|
38
|
+
(subject.accepts? "").should eq false
|
39
|
+
(subject.accepts? "a a").should eq false
|
40
|
+
(subject.accepts? "a a ").should eq false
|
41
|
+
(subject.accepts? "a b a").should eq false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should be able to check if automat is deterministic" do
|
46
|
+
Automaton.init(@file_path).deterministic?.should eq true
|
47
|
+
Automaton.init(@file_path2).deterministic?.should eq false
|
48
|
+
end
|
49
|
+
|
50
|
+
context "can create deterministic automaton" do
|
51
|
+
it "returns Automaton class" do
|
52
|
+
mat1 = Automaton.init(@file_path)
|
53
|
+
mat2 = Automaton.init(@file_path2)
|
54
|
+
mat3 = Automaton.init(@file_path3)
|
55
|
+
mat1.determine.class.should eq Nfa2Dfa::Automaton
|
56
|
+
mat2.determine.class.should eq Nfa2Dfa::Automaton
|
57
|
+
mat3.determine.class.should eq Nfa2Dfa::Automaton
|
58
|
+
end
|
59
|
+
it "returns same instance of Automaton when already deterministic" do
|
60
|
+
mat1 = Automaton.init(@file_path)
|
61
|
+
mat1det = mat1.determine
|
62
|
+
mat1.should eq mat1det
|
63
|
+
end
|
64
|
+
it "returns deterministic automaton" do
|
65
|
+
mat2 = Automaton.init(@file_path2)
|
66
|
+
mat2det = mat2.determine
|
67
|
+
mat2det.deterministic?.should eq true
|
68
|
+
end
|
69
|
+
|
70
|
+
it "which can accept same words" do
|
71
|
+
mat2 = Automaton.init(@file_path2)
|
72
|
+
mat2det = mat2.determine
|
73
|
+
word = ""
|
74
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
75
|
+
(mat2.accepts? word).should eq true
|
76
|
+
word = "a a"
|
77
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
78
|
+
(mat2.accepts? word).should eq true
|
79
|
+
word = "a b"
|
80
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
81
|
+
(mat2.accepts? word).should eq true
|
82
|
+
word = "a c"
|
83
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
84
|
+
(mat2.accepts? word).should eq true
|
85
|
+
word = "a c c"
|
86
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
87
|
+
(mat2.accepts? word).should eq true
|
88
|
+
word = "a c c a"
|
89
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
90
|
+
(mat2.accepts? word).should eq true
|
91
|
+
word = "a c c a c a"
|
92
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
93
|
+
(mat2.accepts? word).should eq true
|
94
|
+
word = "a c c a c a a b"
|
95
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
96
|
+
(mat2.accepts? word).should eq true
|
97
|
+
word = "c a b c a b c"
|
98
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
99
|
+
(mat2.accepts? word).should eq true
|
100
|
+
word = "a c c b c"
|
101
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
102
|
+
(mat2.accepts? word).should eq true
|
103
|
+
end
|
104
|
+
|
105
|
+
it "which rejects same words" do
|
106
|
+
mat2 = Automaton.init(@file_path3)
|
107
|
+
mat2det = mat2.determine
|
108
|
+
word = "0"
|
109
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
110
|
+
(mat2.accepts? word).should eq false
|
111
|
+
word = "1"
|
112
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
113
|
+
(mat2.accepts? word).should eq false
|
114
|
+
word = "0 1"
|
115
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
116
|
+
(mat2.accepts? word).should eq false
|
117
|
+
word = "1 0"
|
118
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
119
|
+
(mat2.accepts? word).should eq false
|
120
|
+
word = "1 1 1 1 0"
|
121
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
122
|
+
(mat2.accepts? word).should eq false
|
123
|
+
word = "0 0 0 0 1"
|
124
|
+
(mat2.accepts? word).should eq mat2det.accepts? word
|
125
|
+
(mat2.accepts? word).should eq false
|
126
|
+
end
|
127
|
+
|
128
|
+
it "should have method for exporting as GraphViz 'to_graph'" do
|
129
|
+
mat = Automaton.init(@file_path2)
|
130
|
+
expect(mat.methods.include?(:to_graph)).to be true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
data/spec/state_spec.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'spec_helper'
|
3
|
+
require_relative '../lib/state.rb'
|
4
|
+
|
5
|
+
describe Nfa2Dfa::State do
|
6
|
+
before(:each) do
|
7
|
+
@end_state = State.new("end")
|
8
|
+
@end_state.to_starting_node
|
9
|
+
end
|
10
|
+
context "should keep " do
|
11
|
+
subject { State.new("state") }
|
12
|
+
|
13
|
+
it "basic data" do
|
14
|
+
subject.id.should eq "state"
|
15
|
+
subject.is_final.should eq false
|
16
|
+
end
|
17
|
+
|
18
|
+
it "transitions as private data" do
|
19
|
+
expect { subject.transitions }.to raise_error NoMethodError
|
20
|
+
end
|
21
|
+
|
22
|
+
it "added transitions" do
|
23
|
+
trans = Transition.new(subject, "jump", @end_state)
|
24
|
+
transes = subject.add_transition(trans)
|
25
|
+
transes.size.should eq 1
|
26
|
+
transes[0].should eq trans
|
27
|
+
end
|
28
|
+
|
29
|
+
it "cleared transition array" do
|
30
|
+
subject.clear_transitions.size.should eq 0
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be able to be finalized" do
|
35
|
+
state_a = State.new("a")
|
36
|
+
state_a.is_final.should eq false
|
37
|
+
state_a.finalize
|
38
|
+
state_a.is_final.should eq true
|
39
|
+
state_a.finalize
|
40
|
+
state_a.is_final.should eq true
|
41
|
+
end
|
42
|
+
it "should be able to be starting node" do
|
43
|
+
state_a = State.new("a")
|
44
|
+
state_a.is_starting.should eq false
|
45
|
+
state_a.to_starting_node
|
46
|
+
state_a.is_starting.should eq true
|
47
|
+
state_a.to_starting_node
|
48
|
+
state_a.is_starting.should eq true
|
49
|
+
end
|
50
|
+
|
51
|
+
context "gets correct next state" do
|
52
|
+
trans = []
|
53
|
+
state_a = State.new("a")
|
54
|
+
state_b = State.new("b")
|
55
|
+
state_c = State.new("c")
|
56
|
+
trans[0] = Transition.new(state_a, "0", state_b)
|
57
|
+
trans[1] = Transition.new(state_b, "1", state_a)
|
58
|
+
trans[2] = Transition.new(state_a, "0", state_a)
|
59
|
+
trans[3] = Transition.new(state_c, "1", state_a)
|
60
|
+
trans[4] = Transition.new(state_a, "0", state_c)
|
61
|
+
state_a.add_transition(trans[0])
|
62
|
+
state_a.add_transition(trans[2])
|
63
|
+
state_a.add_transition(trans[4])
|
64
|
+
state_b.add_transition(trans[1])
|
65
|
+
state_c.add_transition(trans[3])
|
66
|
+
|
67
|
+
it "array" do
|
68
|
+
state_a.get_next("0").size.should eq 3
|
69
|
+
state_a.get_next("1").size.should eq 0
|
70
|
+
end
|
71
|
+
|
72
|
+
it "in first step" do
|
73
|
+
state_a.get_next("0")[0].should eq state_b
|
74
|
+
end
|
75
|
+
|
76
|
+
it "in second step" do
|
77
|
+
state_a.get_next("0")[0].get_next("1")[0].should eq state_a
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "while conversion from NFA to DFA" do
|
82
|
+
trans = Array.new
|
83
|
+
state_a = State.new("a")
|
84
|
+
state_b = State.new("b")
|
85
|
+
state_c = State.new("c")
|
86
|
+
trans[0] = Transition.new(state_a, "0", state_b)
|
87
|
+
trans[1] = Transition.new(state_b, "1", state_a)
|
88
|
+
trans[2] = Transition.new(state_a, "0", state_a)
|
89
|
+
trans[3] = Transition.new(state_c, "1", state_a)
|
90
|
+
trans[4] = Transition.new(state_a, "0", state_c)
|
91
|
+
|
92
|
+
subject { State.new("a,b") }
|
93
|
+
it "should find correct transitions" do
|
94
|
+
subject.associate_transitions(trans)
|
95
|
+
subject.get_next("a").size.should eq 0
|
96
|
+
subject.get_next("1").size.should eq 1
|
97
|
+
subject.get_next("0").size.should eq 3
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'spec_helper'
|
3
|
+
require_relative '../lib/transition.rb'
|
4
|
+
|
5
|
+
describe Nfa2Dfa::Transition do
|
6
|
+
context "should keep " do
|
7
|
+
state1 = State.new("1")
|
8
|
+
state2 = State.new("2")
|
9
|
+
state2.finalize
|
10
|
+
subject { Transition.new(state1, "a", state2) }
|
11
|
+
|
12
|
+
it "states" do
|
13
|
+
subject.beginning_state.should eq state1
|
14
|
+
subject.ending_state.should eq state2
|
15
|
+
end
|
16
|
+
|
17
|
+
it "transition alphabet" do
|
18
|
+
subject.alphabet.should eq "a"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "correct types" do
|
22
|
+
subject.beginning_state.class.should eq State
|
23
|
+
subject.ending_state.class.should eq State
|
24
|
+
subject.alphabet.class.should eq String
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nfa2dfa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Zachov
|
@@ -12,7 +12,8 @@ date: 2013-10-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
13
13
|
description: Finite automaton determinizer
|
14
14
|
email: martin.zachov@gmail.com
|
15
|
-
executables:
|
15
|
+
executables:
|
16
|
+
- automaton
|
16
17
|
extensions: []
|
17
18
|
extra_rdoc_files: []
|
18
19
|
files:
|
@@ -20,6 +21,10 @@ files:
|
|
20
21
|
- lib/automaton.rb
|
21
22
|
- lib/transition.rb
|
22
23
|
- lib/nfa2dfa.rb
|
24
|
+
- spec/automaton_spec.rb
|
25
|
+
- spec/state_spec.rb
|
26
|
+
- spec/transition_spec.rb
|
27
|
+
- bin/automaton
|
23
28
|
homepage: http://fit.cvut.cz
|
24
29
|
licenses:
|
25
30
|
- GNU GPL
|
@@ -44,4 +49,7 @@ rubygems_version: 2.0.3
|
|
44
49
|
signing_key:
|
45
50
|
specification_version: 4
|
46
51
|
summary: MI-RUB semestral
|
47
|
-
test_files:
|
52
|
+
test_files:
|
53
|
+
- spec/automaton_spec.rb
|
54
|
+
- spec/state_spec.rb
|
55
|
+
- spec/transition_spec.rb
|