automaton 0.0.1
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.
- data/README +11 -0
- data/bin/tex2pdf +9 -0
- data/lib/automaton.rb +243 -0
- data/lib/generate.rb +43 -0
- data/lib/latex.rb +61 -0
- data/lib/layout.rb +116 -0
- data/lib/ruby_extensions.rb +35 -0
- data/lib/tex/FinalStateVar.tex +14 -0
- data/lib/tex/VCPref-main.tex +109 -0
- data/lib/tex/Vaucanson-G.tex +946 -0
- data/lib/tex/multido.sty +27 -0
- data/lib/tex/template.tex +24 -0
- data/lib/tex/vaucanson-g.sty +14 -0
- data/spec/automaton_spec.rb +180 -0
- data/spec/layout_spec.rb +48 -0
- data/spec/spec.opts +0 -0
- data/spec/spec_helper.rb +45 -0
- metadata +78 -0
data/lib/tex/multido.sty
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
%%
|
2
|
+
%% This is file `multido.sty'.
|
3
|
+
%%
|
4
|
+
%% IMPORTANT NOTICE:
|
5
|
+
%%
|
6
|
+
%% multido.sty Copyright (C) 1997 Timothy Van Zandt
|
7
|
+
%% (C) 2004 Herbert Voss <voss@perce.de>
|
8
|
+
%% Rolf Niepraschk <Rolf.Niepraschk@ptb.de>
|
9
|
+
%%
|
10
|
+
%% This package may be distributed under the terms of the LaTeX Project
|
11
|
+
%% Public License, as described in lppl.txt in the base LaTeX distribution.
|
12
|
+
%% Either version 1.0 or, at your option, any later version.
|
13
|
+
%%
|
14
|
+
|
15
|
+
\ProvidesPackage{multido}
|
16
|
+
[2004/05/17 package wrapper for PSTricks `multido.tex', (HV/RN)]
|
17
|
+
|
18
|
+
\@ifundefined{MultidoLoaded}
|
19
|
+
{%
|
20
|
+
\input{multido.tex}
|
21
|
+
\ProvidesFile{multido.tex}
|
22
|
+
[\filedate\space v\fileversion\space `multido' (tvz)]
|
23
|
+
}{}
|
24
|
+
|
25
|
+
\endinput
|
26
|
+
%%
|
27
|
+
%% End of file `multido.sty'.
|
@@ -0,0 +1,24 @@
|
|
1
|
+
\documentclass{report}
|
2
|
+
|
3
|
+
\usepackage{vaucanson-g}
|
4
|
+
|
5
|
+
\begin{document}
|
6
|
+
\begin{VCPicture}{(0,0)(10, 10)}
|
7
|
+
|
8
|
+
% states
|
9
|
+
%\State[p]{(0,0)}{A} \State{(3,0)}{B} \State[r]{(6,0.5)}{C}
|
10
|
+
<%= @states.join("\n")%>
|
11
|
+
|
12
|
+
% initial--final
|
13
|
+
% \Initial{A}
|
14
|
+
<%= @initial %>
|
15
|
+
|
16
|
+
% \Final{C}
|
17
|
+
<%= @finals.join("\n")%>
|
18
|
+
|
19
|
+
% transitions
|
20
|
+
%\EdgeL{B}{A}{a} \EdgeL{B}{C}{b}
|
21
|
+
<%= @transitions.join("\n") %>
|
22
|
+
|
23
|
+
\end{VCPicture}
|
24
|
+
\end{document}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
\ProvidesPackage{vaucanson-g}[2003/05/09 package wrapper for Vaucanson-G]
|
2
|
+
\DeclareOption{slides}{\AtEndOfPackage{\input VCPref-slides.tex}}
|
3
|
+
\ProcessOptions
|
4
|
+
\RequirePackage{ifthen}
|
5
|
+
\RequirePackage[usenames]{pstcol}
|
6
|
+
\RequirePackage{pst-node}
|
7
|
+
\RequirePackage{pst-plot}
|
8
|
+
\RequirePackage{pst-coil}
|
9
|
+
%\RequirePackage{multido}
|
10
|
+
\RequirePackage{pst-3d}
|
11
|
+
\RequirePackage{color}
|
12
|
+
\RequirePackage{calc}
|
13
|
+
\input Vaucanson-G.tex
|
14
|
+
\endinput
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'automaton'
|
3
|
+
|
4
|
+
describe Automaton do
|
5
|
+
|
6
|
+
it "can be pruned" do
|
7
|
+
automata = Automaton.create(:a, :b, {:a => {'1' => [:b], '2' => [:d]}, :c => {'3' => [:b]}})
|
8
|
+
expected = Automaton.create(:a, :b, {:a => {'1' => [:b], '2' => [:d]}})
|
9
|
+
automata.prune.should == expected
|
10
|
+
end
|
11
|
+
|
12
|
+
it "has successors" do
|
13
|
+
automata = Automaton.create(:a, :b, {:a => {'1' => [:b, :c], '2' => [:d]}, :c => {'3' => [:b]}})
|
14
|
+
automata.successors_of(:a).should == Set[:b, :c, :d]
|
15
|
+
automata.successors_of(:b).should == Set.new
|
16
|
+
automata.successors_of(:c).should == Set[:b]
|
17
|
+
end
|
18
|
+
|
19
|
+
it "has start state and final states" do
|
20
|
+
automata = Automaton.create(:a, :b, {:a => {'1' => [:b, :c], '2' => [:d]}, :c => {'3' => [:b]}})
|
21
|
+
automata.start.should == :a
|
22
|
+
automata.finals.should == Set[:b]
|
23
|
+
end
|
24
|
+
|
25
|
+
it "is comparable" do
|
26
|
+
a = Automaton.create(:a, :b, '1' => {:a => :b})
|
27
|
+
b = Automaton.create(:a, :b, '1' => {:a => :b})
|
28
|
+
a.should == b
|
29
|
+
end
|
30
|
+
|
31
|
+
it "is taggable" do
|
32
|
+
automata = Automaton.create(:a, :b, :a => {'1' => [:b, :c]})
|
33
|
+
automata.tag(:left).should == Automaton.create(:a_left, [:b_left], :a_left => {'1' => [:b_left, :c_left]})
|
34
|
+
end
|
35
|
+
|
36
|
+
it "has reachable states" do
|
37
|
+
automata = Automaton.create(:a, :b, {:a => {'1' => [:b, :c], '2' => [:d]}, :x => {'3' => [:a]}})
|
38
|
+
automata.reachable_states.should == Set[:a, :b, :c, :d]
|
39
|
+
end
|
40
|
+
|
41
|
+
#NOTE This is meaningless now that the states are stored as a set
|
42
|
+
it "does not repeat reachable states" do
|
43
|
+
automata = Automaton.create(:a, :a, {:a => {'1' => [:a]}})
|
44
|
+
automata.reachable_states.should == Set[:a]
|
45
|
+
end
|
46
|
+
|
47
|
+
it "can deal with loops on reachable states" do
|
48
|
+
automata = Automaton.create(:a, :x, {:a => {'1' => [:b]}, :b => {'1' => [:a]}})
|
49
|
+
automata.reachable_states.should == Set[:a, :b]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "has an alphabet" do
|
53
|
+
automata = Automaton.create(:a, :b, :a => {'1' => :b, '2' => :x},
|
54
|
+
:b => {'1' => :x, '2' => :c},
|
55
|
+
:x => {'1' => :x, '2' => :x})
|
56
|
+
automata.alphabet.should == Set['1', '2']
|
57
|
+
end
|
58
|
+
|
59
|
+
it "has transitions" do
|
60
|
+
automaton = Automaton.create(:a, :b, :a => {'1' => [:b, :c], '2' => [:d]}, :b => {'3' => [:f]})
|
61
|
+
one = Automaton::Transition.new(:a, Set[:b, :c], '1')
|
62
|
+
two = Automaton::Transition.new(:a, Set[:d], '2')
|
63
|
+
three = Automaton::Transition.new(:b, Set[:f], '3')
|
64
|
+
automaton.transitions.to_set.should == Set[one, two, three]
|
65
|
+
end
|
66
|
+
|
67
|
+
it "may not accept any strings" do
|
68
|
+
Automaton.create(:a, [:b], :a => {'1' => :b}).should be_accepting
|
69
|
+
Automaton.create(:a, [], :a => {'1' => :b}).should_not be_accepting
|
70
|
+
Automaton.create(:a, [:b], :a => {'1' =>:c}).should_not be_accepting
|
71
|
+
end
|
72
|
+
|
73
|
+
it "has a complement" do
|
74
|
+
automata = Automaton.create(:a, :b, {:a => {'1' => [:b, :c], '2' => [:d]}, :c => {'3' => [:b]}})
|
75
|
+
automata.complement.complement.should == automata
|
76
|
+
automata.complement.finals.should == Set[:a,:c,:d]
|
77
|
+
end
|
78
|
+
|
79
|
+
it "has intersection for total DFA" do
|
80
|
+
one = Automaton.create(:a, :b, :a => {'1' => :b, '2' => :a}, :b => {'1' => :b, '2' => :b})
|
81
|
+
two = Automaton.create(:x, [:x, :y], :x => {'1' => :y, '2' => :x}, :y => {'1' => :x, '2' => :y})
|
82
|
+
product = Automaton.create(:a_x, [:b_x, :b_y], :a_x => {'1' => :b_y, '2' => :a_x},
|
83
|
+
:b_x => {'1' => :b_y, '2' => :b_x},
|
84
|
+
:b_y => {'1' => :b_x, '2' => :b_y})
|
85
|
+
one.intersect(two).should == product
|
86
|
+
end
|
87
|
+
|
88
|
+
it "has intersection for NFA" do
|
89
|
+
one = Automaton.create(:a, :b, :a => {'2' => :a}, :b => {'1' => :b, '2' => [:a,:b]})
|
90
|
+
two = Automaton.create(:x, [:x, :y], :x => {'1' => :y, '2' => :x}, :y => {'1' => :x, '2' => :y})
|
91
|
+
product = Automaton.create(:a_x, [:b_x, :b_y], :a_x => {'2' => :a_x},
|
92
|
+
:a_y => {'2' => :a_y},
|
93
|
+
:b_x => {'1' => :b_y, '2' => [:a_x,:b_x]},
|
94
|
+
:b_y => {'1' => :b_x, '2' => [:a_y,:b_y]})
|
95
|
+
one.intersect(two).should == product
|
96
|
+
end
|
97
|
+
|
98
|
+
it "subtracts another automata from itself" do
|
99
|
+
one = Automaton.create(:a, [:b], :a => {'1' => [:b]})
|
100
|
+
one_two = Automaton.create(:a, [:b, :c], {:a => {'1' => :b, '2' => :c}})
|
101
|
+
(one_two - one).should be_accepting
|
102
|
+
(one - one_two).should_not be_accepting
|
103
|
+
(one - one).should_not be_accepting
|
104
|
+
end
|
105
|
+
|
106
|
+
it "can be made total" do
|
107
|
+
input = [:a, :b, {:a => {'1' => [:b,:c]}}]
|
108
|
+
automata = Automaton.create(*input)
|
109
|
+
total_automata = Automaton.create(:a, :b, :a => {'1' => [:b,:c], '2' => :x},
|
110
|
+
:b => {'1' => :x, '2' => :x},
|
111
|
+
:c => {'1' => :x, '2' => :x},
|
112
|
+
:x => {'1' => :x, '2' => :x})
|
113
|
+
automata.to_total(Set['1','2']).should == total_automata
|
114
|
+
automata.to_total(Set['1','2']).to_total(Set['1','2']).should == automata.to_total(Set['1','2'])
|
115
|
+
end
|
116
|
+
|
117
|
+
it "is comparable to other automata" do
|
118
|
+
a = Automaton.create(:a, [:b], :a => {'1' => :b})
|
119
|
+
b = Automaton.create(:a, [:b], :a => {'2' => :b})
|
120
|
+
a.should_not be_accepting_same_language_as(b)
|
121
|
+
a.should be_accepting_same_language_as(a)
|
122
|
+
|
123
|
+
a = Automaton.create(:a, [:b], :a => {'1' => :b})
|
124
|
+
b = Automaton.create(:a, [:b], :a => {'1' => :b})
|
125
|
+
a.should be_accepting_same_language_as(b)
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
it "determines if it accepts a subset of the lanugage of other automata" do
|
130
|
+
small = Automaton.create(:a, [:b], {:a => {'1' => :b}})
|
131
|
+
medium = Automaton.create(:a, [:b, :c], {:a => {'1' => :b}, :b => {'2' => :c}})
|
132
|
+
large = Automaton.create(:a, [:b, :c], {:a => {'1' => :b, '2' => :c}, :b => {'1' => :c}})
|
133
|
+
|
134
|
+
small.subset?(medium).should be_true
|
135
|
+
small.subset?(large).should be_true
|
136
|
+
large.subset?(large).should be_true
|
137
|
+
medium.subset?(small).should be_false
|
138
|
+
large.subset?(medium).should be_false
|
139
|
+
small.subset?(small).should be_true
|
140
|
+
medium.subset?(medium).should be_true
|
141
|
+
large.subset?(large).should be_true
|
142
|
+
end
|
143
|
+
|
144
|
+
it "has a latex representation" do
|
145
|
+
small = Automaton.create(:a, :b, :a => {'1' => :b})
|
146
|
+
latex = Automaton::Latex.new(:a, [:b], [[:a, 0, 0], [:b, 1, 1]], [[:a, :b, '1']])
|
147
|
+
small.to_tex.should == latex
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe Automaton::Graph do
|
152
|
+
|
153
|
+
it "allows a state to have no transitions" do
|
154
|
+
tf = Automaton::Graph.new
|
155
|
+
tf[:a].should == {}
|
156
|
+
tf[:a]='b'
|
157
|
+
tf[:a].should == 'b'
|
158
|
+
hash = {:b => {'2' => Set[:c]}}
|
159
|
+
Automaton::Graph.from_hash(hash)[:a].should_not == hash[:a]
|
160
|
+
Automaton::Graph.from_hash(hash)[:b].should == hash[:b]
|
161
|
+
end
|
162
|
+
|
163
|
+
it "can merge two hashes of transitions" do
|
164
|
+
t1 = {}
|
165
|
+
t2 = {'1' => Set[:a]}
|
166
|
+
Automaton::Graph.merge_transitions(t1,t2).should == t2
|
167
|
+
end
|
168
|
+
|
169
|
+
it "can merge in another transition function" do
|
170
|
+
tf1 = Automaton::Graph.from_hash({:a => {'1' => [:a,:b]}})
|
171
|
+
tf2 = Automaton::Graph.from_hash({:a => {'1' => [:a,:c]}})
|
172
|
+
tf3 = Automaton::Graph.from_hash({:b => {'1' => [:a,:c]}})
|
173
|
+
tf1.merge(tf1).should == tf1.merge(tf1)
|
174
|
+
tf2.merge(tf2).should == tf2.merge(tf2)
|
175
|
+
tf2.merge(tf1).should == tf1.merge(tf2)
|
176
|
+
tf2.merge(tf3).should == Automaton::Graph.from_hash({:b => {'1' => [:a,:c]}, :a => {'1' => [:a,:c]}})
|
177
|
+
tf1.merge(tf2).class.should == Automaton::Graph
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
data/spec/layout_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'layout'
|
3
|
+
|
4
|
+
Node = Automaton::Layout::Node
|
5
|
+
describe Automaton::Layout do
|
6
|
+
before(:all) do
|
7
|
+
@a = Node.new(:a, 0, 0)
|
8
|
+
@b = Node.new(:b, 0, 1)
|
9
|
+
@c = Node.new(:c, 16, 0)
|
10
|
+
@a.connect(@b, @c)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "does force direction" do
|
14
|
+
graph = Automaton::Layout.new(@a, @b, @c)
|
15
|
+
graph.nodes.size.should == 3
|
16
|
+
graph.force_direct
|
17
|
+
graph.normalize
|
18
|
+
graph.nodes.size.should == 3
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Automaton::Layout::Node do
|
22
|
+
|
23
|
+
before(:all) do
|
24
|
+
@a = Node.new(:a, 0, 0)
|
25
|
+
@b = Node.new(:b, 0, 1)
|
26
|
+
@c = Node.new(:c, 4, 0)
|
27
|
+
@a.connect(@b, @c)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "has repulsion" do
|
31
|
+
@a.repulsion(@b).should be_close_to_enum(Vector[0, 0.23], 0.01)
|
32
|
+
@a.repulsion(@c).should == -@c.repulsion(@a)
|
33
|
+
@a.repulsion(@c).should be_close_to_enum(Vector[0.0149, 0], 0.01)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "has attraction" do
|
37
|
+
@a.attraction(@b).should be_close_to_enum(Vector[0, -0.8], 0.01)
|
38
|
+
@a.attraction(@c).should be_close_to_enum(Vector[0.4, 0], 0.01)
|
39
|
+
@a.attraction(@c).should == -@c.attraction(@a)
|
40
|
+
@b.attraction(@c).should be_close_to_enum(Vector[0, 0], 0.01)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "has vector to other node" do
|
44
|
+
@a.vector(@b).should be_close_to_enum(Vector[0.0, 1.0])
|
45
|
+
@a.vector(@c).should be_close_to_enum(Vector[4.0, 0.0])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/spec/spec.opts
ADDED
File without changes
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems'
|
5
|
+
gem 'rspec'
|
6
|
+
require 'spec'
|
7
|
+
end
|
8
|
+
|
9
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
10
|
+
|
11
|
+
|
12
|
+
module EnumerableMatchers #:nodoc:
|
13
|
+
class BeCloseToEnum #:nodoc:
|
14
|
+
def initialize(expected, delta)
|
15
|
+
@expected = expected
|
16
|
+
@delta = delta
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches?(actual)
|
20
|
+
@actual = actual
|
21
|
+
return false if actual.nil?
|
22
|
+
return false unless @actual.size == @expected.size
|
23
|
+
@actual.to_a.zip(@expected.to_a).all? do |actual_item, expected_item|
|
24
|
+
(actual_item - expected_item).abs < @delta
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def failure_message
|
29
|
+
"expected #{@expected} +/- (< #{@delta}), got #{@actual}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def description
|
33
|
+
"be close to #{@expected} (within +- #{@delta})"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def be_close_to_enum(expected, delta = 1.0e-014)
|
39
|
+
BeCloseToEnum.new(expected, delta)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Spec::Runner.configure do |config|
|
44
|
+
config.include(EnumerableMatchers)
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: automaton
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tor Erik Linnerud
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-07-16 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rtex
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 2.0.0
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: tel@jklm.no
|
27
|
+
executables:
|
28
|
+
- tex2pdf
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
files:
|
34
|
+
- lib/layout.rb
|
35
|
+
- lib/latex.rb
|
36
|
+
- lib/automaton.rb
|
37
|
+
- lib/generate.rb
|
38
|
+
- lib/ruby_extensions.rb
|
39
|
+
- lib/tex/template.tex
|
40
|
+
- lib/tex/VCPref-main.tex
|
41
|
+
- lib/tex/multido.sty
|
42
|
+
- lib/tex/FinalStateVar.tex
|
43
|
+
- lib/tex/vaucanson-g.sty
|
44
|
+
- lib/tex/Vaucanson-G.tex
|
45
|
+
- spec/spec.opts
|
46
|
+
- spec/spec_helper.rb
|
47
|
+
- spec/layout_spec.rb
|
48
|
+
- spec/automaton_spec.rb
|
49
|
+
- README
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://www.jklm.no/automation
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
version:
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project: automaton
|
72
|
+
rubygems_version: 1.2.0
|
73
|
+
signing_key:
|
74
|
+
specification_version: 2
|
75
|
+
summary: Implementation of automata, supporting visualization and regular language operations
|
76
|
+
test_files:
|
77
|
+
- spec/layout_spec.rb
|
78
|
+
- spec/automaton_spec.rb
|