art-decomp 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/LICENCE +661 -0
- data/README +9 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/bin/ad-compare +22 -0
- data/bin/ad-console +11 -0
- data/bin/ad-inputs +24 -0
- data/bin/ad-validate +9 -0
- data/bin/art-decomp +8 -0
- data/lib/art-decomp/arch.rb +32 -0
- data/lib/art-decomp/b.rb +7 -0
- data/lib/art-decomp/bipainter.rb +142 -0
- data/lib/art-decomp/blanket.rb +82 -0
- data/lib/art-decomp/decomposer.rb +75 -0
- data/lib/art-decomp/decomposition.rb +91 -0
- data/lib/art-decomp/exceptions.rb +9 -0
- data/lib/art-decomp/executable.rb +94 -0
- data/lib/art-decomp/fsm.rb +128 -0
- data/lib/art-decomp/graph.rb +78 -0
- data/lib/art-decomp/kiss.rb +47 -0
- data/lib/art-decomp/logging.rb +52 -0
- data/lib/art-decomp/qu_generator/block_table.rb +42 -0
- data/lib/art-decomp/qu_generator/edge_labels.rb +24 -0
- data/lib/art-decomp/qv_generator/bipainting.rb +12 -0
- data/lib/art-decomp/qv_generator/graph_colouring.rb +16 -0
- data/lib/art-decomp/qv_generator/graph_merging.rb +19 -0
- data/lib/art-decomp/sep.rb +7 -0
- data/lib/art-decomp/uv_generator/braindead.rb +22 -0
- data/lib/art-decomp/uv_generator/relevance.rb +23 -0
- data/lib/art-decomp.rb +65 -0
- data/lib/core/enumerable.rb +24 -0
- data/lib/core/file.rb +11 -0
- data/lib/core/integer.rb +13 -0
- data/lib/core/set.rb +16 -0
- data/lib/core/string.rb +13 -0
- data/spec/art-decomp/arch_spec.rb +23 -0
- data/spec/art-decomp/b_spec.rb +27 -0
- data/spec/art-decomp/bipainter_spec.rb +22 -0
- data/spec/art-decomp/blanket_spec.rb +77 -0
- data/spec/art-decomp/decomposer_spec.rb +106 -0
- data/spec/art-decomp/decomposition_spec.rb +119 -0
- data/spec/art-decomp/executable_spec.rb +161 -0
- data/spec/art-decomp/fsm_spec.rb +146 -0
- data/spec/art-decomp/graph_spec.rb +69 -0
- data/spec/art-decomp/kiss_spec.rb +30 -0
- data/spec/art-decomp/logging_spec.rb +62 -0
- data/spec/art-decomp/qu_generator/block_table_spec.rb +37 -0
- data/spec/art-decomp/qu_generator/edge_labels_spec.rb +35 -0
- data/spec/art-decomp/qv_generator/bipainting_spec.rb +28 -0
- data/spec/art-decomp/qv_generator/graph_colouring_spec.rb +31 -0
- data/spec/art-decomp/qv_generator/graph_merging_spec.rb +30 -0
- data/spec/art-decomp/sep_spec.rb +13 -0
- data/spec/art-decomp/uv_generator/braindead_spec.rb +33 -0
- data/spec/art-decomp/uv_generator/relevance_spec.rb +61 -0
- data/spec/core/enumerable_spec.rb +20 -0
- data/spec/core/file_spec.rb +15 -0
- data/spec/core/integer_spec.rb +16 -0
- data/spec/core/set_spec.rb +26 -0
- data/spec/core/string_spec.rb +17 -0
- data/spec/fixtures/ex5 +36 -0
- data/spec/fixtures/fsm +24 -0
- data/spec/fixtures/fsm.exp +40 -0
- data/spec/fixtures/fsm.f +20 -0
- data/spec/fixtures/fsm.g +4 -0
- data/spec/fixtures/fsm.h +19 -0
- data/spec/fixtures/fsm.partially-exp +31 -0
- data/spec/fixtures/fsm.q +10 -0
- data/spec/fixtures/lion +15 -0
- data/spec/fixtures/lion.exp +15 -0
- data/spec/fixtures/lion.h +10 -0
- data/spec/fixtures/lion.to_kiss +11 -0
- data/spec/fixtures/mark1 +26 -0
- data/spec/fixtures/mc +14 -0
- data/spec/fixtures/mc.to_kiss +10 -0
- data/spec/fixtures/opus +26 -0
- data/spec/fixtures/opus.amb.h +22 -0
- data/spec/fixtures/opus.h +21 -0
- data/spec/fixtures/opus.to_kiss +22 -0
- data/spec/fixtures/s420 +142 -0
- data/spec/fixtures/s8 +24 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +8 -0
- metadata +224 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module ArtDecomp describe Bipainter do
|
2
|
+
|
3
|
+
context 'when used for generating the Qv and G blankets' do
|
4
|
+
|
5
|
+
# FIXME: add more specs, targeting non-trivial cases
|
6
|
+
|
7
|
+
it 'should colour the two incompatibility graphs properly and return the resulting blankets' do
|
8
|
+
beta_q = Blanket[B[1,2], B[3,4], B[5,6]]
|
9
|
+
beta_v = Blanket[B[1,3,5], B[2,4,6]]
|
10
|
+
seps = Set[Sep[1,2], Sep[1,3], Sep[1,6], Sep[2,6], Sep[3,4], Sep[3,6], Sep[4,5], Sep[5,6]]
|
11
|
+
|
12
|
+
bipainter = Bipainter.new beta_q, beta_v, seps
|
13
|
+
bipainter.blankets.should == [Blanket[B[1,2], B[3,4,5,6]], Blanket[B[1], B[2,3,5], B[4,6]]]
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should raise a RuntimeError on non-disjoint beta_v' do
|
17
|
+
lambda { Bipainter.new Blanket[], Blanket[B[0,1], B[0,2]], Set[] }.should raise_error(RuntimeError, 'non-disjoint beta_v')
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
end end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module ArtDecomp describe Blanket do
|
4
|
+
|
5
|
+
it 'should be easily instantiable, properly comparable and usable as a Set element' do
|
6
|
+
Blanket[B[], B[0], B[1,2]].should == Blanket.new([B[1,2], B[0]])
|
7
|
+
Blanket[B[], B[0], B[1,2]].hash.should == Blanket.new([B[1,2], B[0]]).hash
|
8
|
+
Blanket[B[], B[0], B[1,2]].should eql Blanket.new([B[1,2], B[0]])
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should expose its internal ints variable and it should be immutable' do
|
12
|
+
Blanket[B[1,2], B[3,4]].ints.should == Set[B[3,4], B[1,2]]
|
13
|
+
Blanket[B[1,2], B[3,4]].ints.should be_frozen
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should be properly instantiable from an Array' do
|
17
|
+
blanket = Blanket.from_array [:b, DontCare, :a, :c, :b, :a, :c]
|
18
|
+
blanket.should == Blanket[B[0,1,4], B[1,2,5], B[1,3,6]]
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should be inspectable and return a self-instanting form' do
|
22
|
+
Blanket[B[]].inspect.should == 'Blanket[]'
|
23
|
+
Blanket[B[1,2], B[0]].inspect.should == 'Blanket[B[0], B[1,2]]'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should be multipliable by other Blankets' do
|
27
|
+
b1 = Blanket[B[1,2,3], B[4,5,6]]
|
28
|
+
b2 = Blanket[B[1,2], B[3,4], B[5,6]]
|
29
|
+
(b1 * b2).should == Blanket[B[1,2], B[3], B[4], B[5,6]]
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should properly expose the separations it provides/requires' do
|
33
|
+
Blanket[].seps.should == Set[]
|
34
|
+
Blanket[B[1]].seps.should == Set[]
|
35
|
+
Blanket[B[1], B[2], B[]].seps.should == Set[Sep[1,2]]
|
36
|
+
Blanket[B[1,2], B[3,4]].seps.should == Set[Sep[1,3], Sep[1,4], Sep[2,3], Sep[2,4]]
|
37
|
+
Blanket[B[1,2,3], B[2,3,4]].seps.should == Set[Sep[1,4]]
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should properly report its size' do
|
41
|
+
Blanket[].size.should == 0
|
42
|
+
Blanket[B[1]].size.should == 1
|
43
|
+
Blanket[B[1], B[2], B[]].size.should == 2
|
44
|
+
Blanket[B[1,2,3], B[2,3,4]].size.should == 2
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should return the Blanket’s ‘natural’ encoding, based on the provided subblock' do
|
48
|
+
blanket = Blanket[B[0,1,2], B[1,2,3], B[2,3,4]]
|
49
|
+
blanket.encoding(B[0,1,2]).should == '00'
|
50
|
+
blanket.encoding(B[1,2,3]).should == '01'
|
51
|
+
blanket.encoding(B[2,3,4]).should == '10'
|
52
|
+
blanket.encoding(B[2]).should == '--'
|
53
|
+
lambda { blanket.encoding(B[1,2]) }.should raise_error(AmbiguousEncodingQuery, 'ambiguous encoding query: block 1,2')
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should return the Blanket’s ‘natural’ encodings in an Array if so asked' do
|
57
|
+
blanket = Blanket[B[0,1,2], B[1,2,3], B[2,3,4]]
|
58
|
+
blanket.encodings(B[0,1,2]).should == ['00']
|
59
|
+
blanket.encodings(B[1,2,3]).should == ['01']
|
60
|
+
blanket.encodings(B[2,3,4]).should == ['10']
|
61
|
+
blanket.encodings(B[2]).should == ['--']
|
62
|
+
blanket.encodings(B[1,2]).should == ['00', '01']
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should report how many physical pins it uses' do
|
66
|
+
Blanket[B[]].pins.should == 0
|
67
|
+
Blanket[B[1]].pins.should == 0
|
68
|
+
Blanket[B[1,2]].pins.should == 0
|
69
|
+
Blanket[B[1],B[2]].pins.should == 1
|
70
|
+
Blanket[B[1],B[2],B[3]].pins.should == 2
|
71
|
+
Blanket[B[1,2],B[3,4],B[5,6],B[7]].pins.should == 2
|
72
|
+
Blanket[B[1],B[2],B[3],B[4],B[5]].pins.should == 3
|
73
|
+
Blanket[B[1],B[2],B[3],B[4],B[5],B[6],B[7],B[8]].pins.should == 3
|
74
|
+
Blanket[B[1],B[2],B[3],B[4],B[5],B[6],B[7],B[8],B[9]].pins.should == 4
|
75
|
+
end
|
76
|
+
|
77
|
+
end end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module ArtDecomp describe Decomposer do
|
2
|
+
|
3
|
+
it 'should instantiate itself and its components properly' do
|
4
|
+
fsm = mock FSM
|
5
|
+
archs = Set[Arch[5,1], Arch[4,2]]
|
6
|
+
uv1, uv2 = mock('UVGenerator class'), mock('UVGenerator class')
|
7
|
+
qu1, qu2 = mock('QuGenerator class'), mock('QuGenerator class')
|
8
|
+
qv1, qv2 = mock('QvGenerator class'), mock('QvGenerator class')
|
9
|
+
[uv1, uv2].each { |gen| gen.should_receive(:new).with fsm, archs }
|
10
|
+
[qu1, qu2, qv1, qv2].each { |gen| gen.should_receive(:new).with no_args }
|
11
|
+
Decomposer.new :fsm => fsm, :archs => archs, :uv_gens => [uv1, uv2], :qu_gens => [qu1, qu2], :qv_gens => [qv1, qv2]
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'given that the three generators are working properly' do
|
15
|
+
|
16
|
+
class StubGenerator
|
17
|
+
def initialize sequences
|
18
|
+
@sequences = sequences
|
19
|
+
end
|
20
|
+
def elems *key, &block
|
21
|
+
@sequences[key].each &block
|
22
|
+
end
|
23
|
+
alias uv_pairs elems
|
24
|
+
alias blankets elems
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should poll the generators and yield the resulting decompositions one by one' do
|
28
|
+
fsm = mock FSM, :beta_q => mock(Blanket, :pins => 3, :size => 5), :input_count => 4
|
29
|
+
|
30
|
+
u_a, v_a = Set[0,1], Set[2] # for this U/V pair: two Qu generating one Qv/G pair each
|
31
|
+
qu_a1, qv_a1, g_a1 = mock(Blanket, :pins => 2, :size => 4), mock(Blanket, :pins => 3, :size => 5), mock(Blanket, :pins => 2)
|
32
|
+
qu_a2, qv_a2, g_a2 = mock(Blanket, :pins => 2, :size => 4), mock(Blanket, :pins => 3, :size => 5), mock(Blanket, :pins => 2)
|
33
|
+
|
34
|
+
u_b, v_b = Set[0], Set[1,2] # for this U/V pair: one Qu generating two Qv/G pairs
|
35
|
+
qu_b = mock Blanket, :pins => 2, :size => 4
|
36
|
+
qv_bA, g_bA = mock(Blanket, :pins => 3, :size => 5), mock(Blanket, :pins => 2)
|
37
|
+
qv_bB, g_bB = mock(Blanket, :pins => 3, :size => 5), mock(Blanket, :pins => 2)
|
38
|
+
|
39
|
+
uv_gen = mock UVGenerator, :new => StubGenerator.new({[] => [[fsm, u_a, v_a], [fsm, u_b, v_b]]})
|
40
|
+
qu_gen = mock QuGenerator, :new => StubGenerator.new({[fsm, u_a, v_a] => [qu_a1, qu_a2],
|
41
|
+
[fsm, u_b, v_b] => [qu_b]})
|
42
|
+
qv_gen = mock QvGenerator, :new => StubGenerator.new({[fsm, u_a, v_a, qu_a1] => [[qv_a1, g_a1]],
|
43
|
+
[fsm, u_a, v_a, qu_a2] => [[qv_a2, g_a2]],
|
44
|
+
[fsm, u_b, v_b, qu_b] => [[qv_bA, g_bA], [qv_bB, g_bB]]})
|
45
|
+
|
46
|
+
decomposer = Decomposer.new :archs => Set[Arch[5,1]], :fsm => fsm, :uv_gens => [uv_gen], :qu_gens => [qu_gen], :qv_gens => [qv_gen]
|
47
|
+
results = decomposer.decompositions.to_a
|
48
|
+
results.size.should == 4
|
49
|
+
results.first.should == Decomposition.new(fsm, u_a, v_a, qu_a1, qv_a1, g_a1)
|
50
|
+
results.last.should == Decomposition.new(fsm, u_b, v_b, qu_b, qv_bB, g_bB)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should yield only sensible decompositions' do
|
54
|
+
fsm = mock FSM
|
55
|
+
uv_gen = mock UVGenerator, :uv_pairs => [[fsm, Set[0], Set[1]]]
|
56
|
+
qu_gen = mock QuGenerator, :blankets => [mock(Blanket)]
|
57
|
+
qv_gen = mock QvGenerator, :blankets => [[mock(Blanket), mock(Blanket)], [mock(Blanket), mock(Blanket)]]
|
58
|
+
dec1 = mock Decomposition, :sensible? => true
|
59
|
+
dec2 = mock Decomposition, :sensible? => false
|
60
|
+
Decomposition.should_receive(:new).exactly(2).times.and_return dec1, dec2
|
61
|
+
decomposer = Decomposer.new :fsm => fsm, :uv_gens => [mock('UVG', :new => uv_gen)], :qu_gens => [mock('QuG', :new => qu_gen)], :qv_gens => [mock('QvG', :new => qv_gen)]
|
62
|
+
decomposer.decompositions.to_a.should == [dec1]
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should skip re-computing elements it already computed once (unless told not to)' do
|
66
|
+
qu1, qu2, qv, g1, g2 = mock(Blanket), mock(Blanket), mock(Blanket), mock(Blanket), mock(Blanket)
|
67
|
+
fsm = mock FSM
|
68
|
+
uv_gen = mock UVGenerator, :uv_pairs => [[fsm, Set[0], Set[1]], [fsm, Set[0], Set[1]], [fsm, Set[1], Set[0]]]
|
69
|
+
qu_gen = mock QuGenerator, :blankets => [qu1, qu1, qu2]
|
70
|
+
qv_gen = mock QvGenerator, :blankets => [[qv, g1], [qv, g1], [qv, g2]]
|
71
|
+
dec = mock Decomposition, :sensible? => true
|
72
|
+
Decomposition.should_receive(:new).exactly(8).times.and_return dec
|
73
|
+
decomposer = Decomposer.new :fsm => fsm, :uv_gens => [mock('UVG', :new => uv_gen)], :qu_gens => [mock('QuG', :new => qu_gen)], :qv_gens => [mock('QvG', :new => qv_gen)]
|
74
|
+
decomposer.decompositions.to_a.size.should == 8
|
75
|
+
Decomposition.should_receive(:new).exactly(27).times.and_return dec
|
76
|
+
decomposer = Decomposer.new :fsm => fsm, :uv_gens => [mock('UVG', :new => uv_gen)], :qu_gens => [mock('QuG', :new => qu_gen)], :qv_gens => [mock('QvG', :new => qv_gen)]
|
77
|
+
decomposer.decompositions(:keep_seen => true).to_a.size.should == 27
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should compute shallow ((u & v).size == 1) non-disjoint decompositions (if told to)' do
|
81
|
+
qu, qv, g1, g2 = mock(Blanket), mock(Blanket), mock(Blanket, :pins => 1), mock(Blanket, :pins => 2)
|
82
|
+
fsm = mock FSM
|
83
|
+
uv_gen = mock UVGenerator, :uv_pairs => [[fsm, Set[0,1], Set[2,3]]]
|
84
|
+
qu_gen = mock QuGenerator, :blankets => [qu]
|
85
|
+
qv_gen = mock QvGenerator, :blankets => [[qv, g2], [qv, g1]]
|
86
|
+
dec = mock Decomposition, :sensible? => true
|
87
|
+
Decomposition.should_receive(:new).exactly(6).times.and_return dec
|
88
|
+
decomposer = Decomposer.new :fsm => fsm, :uv_gens => [mock('UVG', :new => uv_gen)], :qu_gens => [mock('QuG', :new => qu_gen)], :qv_gens => [mock('QvG', :new => qv_gen)]
|
89
|
+
decomposer.decompositions(:non_disjoint => true).to_a.size.should == 4
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should compute deep ((u & v).size > 1) non-disjoint decompositions (if told to)' do
|
93
|
+
qu, qv, g1, g2 = mock(Blanket), mock(Blanket), mock(Blanket, :pins => 1), mock(Blanket, :pins => 2)
|
94
|
+
fsm = mock FSM
|
95
|
+
uv_gen = mock UVGenerator, :uv_pairs => [[fsm, Set[0,1], Set[2,3]]]
|
96
|
+
qu_gen = mock QuGenerator, :blankets => [qu]
|
97
|
+
qv_gen = mock QvGenerator, :blankets => [[qv, g2], [qv, g1]]
|
98
|
+
dec = mock Decomposition, :sensible? => true
|
99
|
+
Decomposition.should_receive(:new).exactly(8).times.and_return dec
|
100
|
+
decomposer = Decomposer.new :fsm => fsm, :uv_gens => [mock('UVG', :new => uv_gen)], :qu_gens => [mock('QuG', :new => qu_gen)], :qv_gens => [mock('QvG', :new => qv_gen)]
|
101
|
+
decomposer.decompositions(:non_disjoint => true, :deep_ndj => true).to_a.size.should == 4
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module ArtDecomp describe Decomposition do
|
4
|
+
|
5
|
+
it 'should instantiate, compare and hash properly' do
|
6
|
+
fsm = mock FSM
|
7
|
+
u, v = Set[0,1], Set[2]
|
8
|
+
qu, qv, g = mock(Blanket), mock(Blanket), mock(Blanket)
|
9
|
+
dec = Decomposition.new fsm, u, v, qu, qv, g
|
10
|
+
dec.should == Decomposition.new(fsm, u, v, qu, qv, g)
|
11
|
+
dec.should_not == Decomposition.new(fsm, v, u, qu, qv, g)
|
12
|
+
dec.should_not == Decomposition.new(fsm, u, v, qv, qu, g)
|
13
|
+
dec.hash.should == Decomposition.new(fsm, u, v, qu, qv, g).hash
|
14
|
+
dec.should eql Decomposition.new(fsm, u, v, qu, qv, g)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should create its F, Q, G and H blocks’ KISS representations properly' do
|
18
|
+
fsm = FSM.from_kiss 'spec/fixtures/fsm'
|
19
|
+
qu = Blanket[B[0,4,5], B[1,2,3,13,14], B[6,7,8,9,10,11,12], B[15,16,17,18,19]]
|
20
|
+
qv = Blanket[B[0,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,19], B[1,2,18]]
|
21
|
+
g = Blanket[B[0,2,5,6,7,9,11,15,16,17,18,19], B[1,3,4,8,10,12,13,14]]
|
22
|
+
decomposition = Decomposition.new fsm, Set[0,1,3], Set[2], qu, qv, g
|
23
|
+
decomposition.f_kiss.should == File.read('spec/fixtures/fsm.f')
|
24
|
+
decomposition.q_kiss.should == File.read('spec/fixtures/fsm.q')
|
25
|
+
decomposition.g_kiss.should == File.read('spec/fixtures/fsm.g')
|
26
|
+
decomposition.h_kiss.should == File.read('spec/fixtures/fsm.h')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should create the H block properly, even if the G blanket seems ambiguous' do
|
30
|
+
fsm = FSM.from_kiss 'spec/fixtures/opus'
|
31
|
+
qu = Blanket[B[0,1,11,14,15,16,17,18,19,20,30,33,34,35,36,37], B[2,5,7,14,21,24,26,33], B[3,4,10,13,14,22,23,29,32,33], B[6,8,9,12,14,25,27,28,31,33]]
|
32
|
+
qv = Blanket[B[0,2,6,8,10,13,14,15,19,21,25,27,29,32,33,34], B[1,3,4,5,7,9,12,14,20,22,23,24,26,28,31,33], B[11,14,16,17,18,30,33,35,36,37]]
|
33
|
+
g = Blanket[B[0,2,6,8,10,13,14,15,19,21,25,27,29,32,33,34], B[1,3,4,5,7,9,12,14,20,22,23,24,26,28,31,33], B[11,14,16,17,18], B[30,33,35,36,37]]
|
34
|
+
decomposition = Decomposition.new fsm.expand_x(Set[0]), Set[1,2,3,4], Set[0], qu, qv, g
|
35
|
+
decomposition.h_kiss.should == File.read('spec/fixtures/opus.amb.h')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should properly recode don’t-care states to *' do
|
39
|
+
fsm = FSM.from_kiss 'spec/fixtures/opus'
|
40
|
+
qu = Blanket[B[0,1,2,3,4,20,21], B[0,5,6,7], B[0,8,9,10,11,12,13,14,15,16], B[0,17,18,19]]
|
41
|
+
qv = Blanket[B[0,1,2,6,7,15,16,17,18], B[0,3,4,5,8,9,10,11,12,13,14,19], B[0,20,21]]
|
42
|
+
g = Blanket[B[0,1], B[2,6,7,15,16,17,18], B[3,4,5,8,9,10,11,12,13,14,19], B[20,21]]
|
43
|
+
decomposition = Decomposition.new fsm, Set[0,1,3,4], Set[2], qu, qv, g
|
44
|
+
decomposition.h_kiss.should == File.read('spec/fixtures/opus.h')
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should properly report whether it’s valid' do
|
48
|
+
fsm = FSM.from_kiss 'spec/fixtures/fsm'
|
49
|
+
qu = Blanket[B[0,1,2,3,4,5,17], B[6,7,8,9,10,11,12,13,14,15,16,18,19]]
|
50
|
+
qv = Blanket[B[0,1,2,17,19], B[3,6,7,8,9,10,11,12], B[4,5,18], B[13,14,15,16]]
|
51
|
+
g = Blanket[B[0,1,4,6,17,18,19], B[2,7,9,11], B[3,5,8,10,12], B[13,14,15,16]]
|
52
|
+
Decomposition.new(fsm, Set[1,3], Set[0,2], qu, qv, g).should be_valid
|
53
|
+
Decomposition.new(fsm, Set[1,3], Set[0,2], qv, qu, g).should_not be_valid
|
54
|
+
Decomposition.new(fsm, Set[1,3], Set[0,2], qv, qv, g).should_not be_valid
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should report whether it’s disjoint' do
|
58
|
+
fsm = mock FSM
|
59
|
+
b = mock Blanket
|
60
|
+
Decomposition.new(fsm, Set[0], Set[1], b, b, b).should be_disjoint
|
61
|
+
Decomposition.new(fsm, Set[0,1], Set[1], b, b, b).should_not be_disjoint
|
62
|
+
Decomposition.new(fsm, Set[1], Set[0,1], b, b, b).should_not be_disjoint
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when assesing whether it’s usable in the future' do
|
66
|
+
|
67
|
+
before do
|
68
|
+
@fsm = mock FSM, :beta_q => mock(Blanket, :pins => 3), :input_count => 3, :output_count => 2
|
69
|
+
@b = mock Blanket
|
70
|
+
@b1 = mock Blanket, :pins => 1, :size => 2
|
71
|
+
@b2 = mock Blanket, :pins => 2, :size => 4
|
72
|
+
@b3 = mock Blanket, :pins => 3
|
73
|
+
@b4 = mock Blanket, :pins => 4
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should properly report whether it’s decomposable further' do
|
77
|
+
Decomposition.new(@fsm, Set[0], Set[1], @b1, @b, @b).should_not be_decomposable
|
78
|
+
Decomposition.new(@fsm, Set[0], Set[1], @b2, @b, @b).should be_decomposable
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should properly report whether it’s sensible, based on the target Archs and G and H blocks’ architectures' do
|
82
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b2, @b2, @b2).should_not be_sensible Set[Arch[3,2]]
|
83
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b2, @b2, @b2).should be_sensible Set[Arch[4,1]]
|
84
|
+
Decomposition.new(@fsm, Set[], Set[0,1,2], @b2, @b2, @b2).should_not be_sensible Set[Arch[4,1]]
|
85
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b2, @b3, @b2).should_not be_sensible Set[Arch[4,1]]
|
86
|
+
Decomposition.new(@fsm, Set[0,1], Set[1,2], @b2, @b2, @b2).should_not be_sensible Set[Arch[4,1]]
|
87
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b3, @b2, @b2).should_not be_sensible Set[Arch[4,1]]
|
88
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b2, @b2, @b3).should_not be_sensible Set[Arch[4,1]]
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should properly report whether it’s final based on a Set of Archs' do
|
92
|
+
Decomposition.new(@fsm, Set[0], Set[1], @b1, @b3, @b3).should be_final Set[Arch[5,1]]
|
93
|
+
Decomposition.new(@fsm, Set[0], Set[1], @b1, @b3, @b3).should_not be_final Set[Arch[4,2]]
|
94
|
+
Decomposition.new(@fsm, Set[], Set[1], @b1, @b3, @b3).should be_final Set[Arch[4,2]]
|
95
|
+
Decomposition.new(@fsm, Set[], Set[1,2], @b1, @b3, @b3).should_not be_final Set[Arch[4,2]]
|
96
|
+
Decomposition.new(@fsm, Set[], Set[1], @b1, @b4, @b3).should_not be_final Set[Arch[4,2]]
|
97
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b1, @b3, @b3).should be_final Set[Arch[5,1]]
|
98
|
+
Decomposition.new(@fsm, Set[0,1], Set[2], @b1, @b3, @b3).should_not be_final Set[Arch[5,1]]
|
99
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b2, @b3, @b3).should_not be_final Set[Arch[5,1]]
|
100
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b1, @b3, @b4).should_not be_final Set[Arch[5,1]]
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should properly report G cell count (if G fits the provided Archs)' do
|
104
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b, @b2, @b2).g_cells(Set[Arch[5,1]]).should == 2
|
105
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b, @b2, @b2).g_cells(Set[Arch[4,2]]).should == 1
|
106
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b, @b2, @b2).g_cells(Set[Arch[3,2]]).should be_nil
|
107
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b, @b2, @b3).g_cells(Set[Arch[4,2]]).should == 2
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'should properly report H cell count (if G fits the provided Archs)' do
|
111
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b1, @b1, @b2).h_cells(Set[Arch[5,1]]).should == 4
|
112
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b1, @b1, @b2).h_cells(Set[Arch[4,2]]).should == 2
|
113
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b1, @b1, @b2).h_cells(Set[Arch[3,1]]).should be_nil
|
114
|
+
Decomposition.new(@fsm, Set[0], Set[1,2], @b1, @b2, @b2).h_cells(Set[Arch[4,2]]).should == 3
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module ArtDecomp describe Executable do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@orig_stderr = $stderr
|
7
|
+
$stderr = StringIO.new
|
8
|
+
@fsm = 'spec/fixtures/fsm'
|
9
|
+
@dir = "#{Dir.tmpdir}/#{rand.to_s}"
|
10
|
+
@args = ['--archs', '5/1', '--outdir', @dir, @fsm]
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
$stderr = @orig_stderr
|
15
|
+
FileUtils.rmtree @dir if Dir.exists? @dir
|
16
|
+
end
|
17
|
+
|
18
|
+
def stderr
|
19
|
+
$stderr.rewind
|
20
|
+
$stderr.read
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should require an FSM' do
|
24
|
+
lambda { Executable.new([]) }.should raise_error SystemExit
|
25
|
+
stderr.should =~ rex('no FSM given')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should require that the FSM exists' do
|
29
|
+
lambda { Executable.new(['bogus']) }.should raise_error SystemExit
|
30
|
+
stderr.should =~ rex('FSM does not exist')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should require at least one target Arch' do
|
34
|
+
lambda { Executable.new([@fsm]) }.should raise_error SystemExit
|
35
|
+
stderr.should =~ rex('no architecture given')
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should require that all architectures are parsable' do
|
39
|
+
args = ['--archs', '5/1', 'a/b', '--outdir', @dir, @fsm]
|
40
|
+
lambda { Executable.new(args) }.should raise_error SystemExit
|
41
|
+
stderr.should =~ rex('archs not in the form of inputs/outputs')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should require output directory' do
|
45
|
+
lambda { Executable.new(['--archs', '5/1', '--', @fsm]) }.should raise_error SystemExit
|
46
|
+
stderr.should =~ rex('no output directory given')
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should require that the output directory does not exist' do
|
50
|
+
lambda { Executable.new(['--archs', '5/1', '--outdir', Dir.tmpdir, @fsm]) }.should raise_error SystemExit
|
51
|
+
stderr.should =~ rex('output directory exists')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should require that the output directory is creatable' do
|
55
|
+
Dir.mkdir @dir, 0400
|
56
|
+
subdir = "#{@dir}/#{rand.to_s}"
|
57
|
+
lambda { Executable.new(['--archs', '5/1', '--outdir', subdir, @fsm]) }.should raise_error SystemExit
|
58
|
+
stderr.should =~ rex('output directory cannot be created')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should create the output directory' do
|
62
|
+
Dir.exists?(@dir).should be_false
|
63
|
+
Executable.new @args
|
64
|
+
Dir.exists?(@dir).should be_true
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should validate that the specified UV generator exists' do
|
68
|
+
lambda { Executable.new(@args + ['--uv', 'bogus']) }.should raise_error SystemExit
|
69
|
+
stderr.should =~ rex('no such UV generator')
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should validate that the specified Qu generator exists' do
|
73
|
+
lambda { Executable.new(@args + ['--qu', 'bogus']) }.should raise_error SystemExit
|
74
|
+
stderr.should =~ rex('no such Qu generator')
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should validate that the specified Qv generator exists' do
|
78
|
+
lambda { Executable.new(@args + ['--qv', 'bogus']) }.should raise_error SystemExit
|
79
|
+
stderr.should =~ rex('no such Qv generator')
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should dump the resulting decompositions into a file' do
|
83
|
+
fsm = FSM.from_kiss 'spec/fixtures/fsm'
|
84
|
+
dec = Decomposition.new fsm, Set[0], Set[1], Blanket[B[0],B[1],B[2]], Blanket[], Blanket[]
|
85
|
+
|
86
|
+
decomposer = mock Decomposer, :decompositions => [dec, dec].each
|
87
|
+
Decomposer.should_receive(:new).with(:fsm => fsm, :archs => an_instance_of(Set), :uv_gens => [UVGenerator::Relevance], :qu_gens => [QuGenerator::EdgeLabels], :qv_gens => [QvGenerator::GraphColouring]).and_return decomposer
|
88
|
+
|
89
|
+
Executable.new(@args).run false
|
90
|
+
Marshal.load(File.read("#{@dir}/decompositions")).should == [dec, dec]
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should create files holding the resulting Decomposition objects and keep track of the best decomposition' do
|
94
|
+
dec0 = Decomposition.new FSM.from_kiss('spec/fixtures/fsm'), Set[0], Set[1], Blanket[B[0],B[1],B[2]], Blanket[], Blanket[]
|
95
|
+
dec1 = Decomposition.new FSM.from_kiss('spec/fixtures/fsm'), Set[1], Set[0], Blanket[B[0],B[1],B[2]], Blanket[], Blanket[]
|
96
|
+
Decomposer.should_receive(:new).and_return mock(Decomposer, :decompositions => [dec0, dec1].each)
|
97
|
+
ex = Executable.new @args
|
98
|
+
ex.best.should be_nil
|
99
|
+
ex.run
|
100
|
+
ex.best.should == 4
|
101
|
+
Marshal.load(File.read("#{@dir}/0.dec")).should == dec0
|
102
|
+
Marshal.load(File.read("#{@dir}/1.dec")).should == dec1
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should pass all of the requested generators and architectures to the Decomposer, and report on what it’s using when asked' do
|
106
|
+
fsm = mock FSM, :fsm_cells => nil, :implementable_in? => false, :stats => ''
|
107
|
+
FSM.should_receive(:from_kiss).with(@fsm).and_return fsm
|
108
|
+
|
109
|
+
decomposer = mock Decomposer, :decompositions => [].each
|
110
|
+
Decomposer.should_receive(:new).with(:fsm => fsm, :archs => Set[Arch[4,2], Arch[5,1]], :uv_gens => [UVGenerator::Braindead, UVGenerator::Braindead], :qu_gens => [QuGenerator::BlockTable, QuGenerator::EdgeLabels], :qv_gens => [QvGenerator::GraphMerging, QvGenerator::Bipainting]).and_return decomposer
|
111
|
+
|
112
|
+
args = ['--archs', '5/1', '4/2', '--uv', 'Braindead', 'Braindead', '--qu', 'BlockTable', 'EdgeLabels', '--qv', 'GraphMerging', 'Bipainting', '--outdir', @dir, @fsm]
|
113
|
+
ex = Executable.new args
|
114
|
+
ex.gens.should == 'Braindead+Braindead, BlockTable+EdgeLabels, GraphMerging+Bipainting'
|
115
|
+
ex.run
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should allow setting any of the generators to ‘all’' do
|
119
|
+
fsm = mock FSM, :fsm_cells => nil, :implementable_in? => false, :stats => ''
|
120
|
+
FSM.should_receive(:from_kiss).with(@fsm).and_return fsm
|
121
|
+
|
122
|
+
decomposer = mock Decomposer, :decompositions => [].each
|
123
|
+
Decomposer.should_receive(:new).with(:fsm => fsm, :archs => Set[Arch[5,1]], :uv_gens => [UVGenerator::Braindead, UVGenerator::Relevance], :qu_gens => [QuGenerator::BlockTable, QuGenerator::EdgeLabels], :qv_gens => [QvGenerator::Bipainting, QvGenerator::GraphColouring,QvGenerator::GraphMerging]).and_return decomposer
|
124
|
+
|
125
|
+
args = ['--archs', '5/1', '--uv', 'all', '--qu', 'all', '--qv', 'all', '--outdir', @dir, @fsm]
|
126
|
+
Executable.new(args).run
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should decompose iteratively according to the number of iterations and expose this number (along with archs and dir)' do
|
130
|
+
args = ['--archs', '2/1', '--iters', '2', '--outdir', @dir, 'spec/fixtures/lion']
|
131
|
+
dec = Decomposition.new FSM.from_kiss('spec/fixtures/lion'), Set[0], Set[1], Blanket[B[0],B[1],B[2]], Blanket[], Blanket[]
|
132
|
+
Decomposer.stub!(:new).and_return mock(Decomposer, :decompositions => [dec].each)
|
133
|
+
ex = Executable.new args
|
134
|
+
ex.archs.should == Set[Arch[2,1]]
|
135
|
+
ex.iters.should == 2
|
136
|
+
ex.dir.should == @dir
|
137
|
+
ex.run
|
138
|
+
File.exists?("#{@dir}/0.dec").should be_true
|
139
|
+
File.exists?("#{@dir}/0/0.dec").should be_true
|
140
|
+
File.exists?("#{@dir}/0/0/0.dec").should be_false
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should allow logging to the specified file/stream' do
|
144
|
+
log = Tempfile.new rand
|
145
|
+
Decomposer.should_receive(:new).and_return mock(Decomposer, :decompositions => [].each)
|
146
|
+
Executable.new(['--archs', '5/1', '4/2', '--debug', '--log', log.path, '--outdir', @dir, @fsm]).run
|
147
|
+
Logging.level.should == Logger::DEBUG
|
148
|
+
Logging.off
|
149
|
+
File.read(log.path).should =~ rex('FSM 4/2+10s → 5/1+4/2')
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'should handle the s8 edge case with grace' do
|
153
|
+
log = Tempfile.new rand
|
154
|
+
Executable.new(['--archs', '2/1', '--log', log.path, '--outdir', @dir, 'spec/fixtures/s8']).run
|
155
|
+
Logging.off
|
156
|
+
File.read(log.path).should =~ rex('final best decomposition: 0 cells')
|
157
|
+
end
|
158
|
+
|
159
|
+
# FIXME: add specs for --non-disjoint and --deep-ndj
|
160
|
+
|
161
|
+
end end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module ArtDecomp describe FSM do
|
4
|
+
|
5
|
+
context 'parsed from an example KISS file' do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@fsm = FSM.from_kiss 'spec/fixtures/fsm'
|
9
|
+
@lion = FSM.from_kiss 'spec/fixtures/lion'
|
10
|
+
@mark1 = FSM.from_kiss 'spec/fixtures/mark1'
|
11
|
+
@mc = FSM.from_kiss 'spec/fixtures/mc'
|
12
|
+
@opus = FSM.from_kiss 'spec/fixtures/opus'
|
13
|
+
@s8 = FSM.from_kiss 'spec/fixtures/s8'
|
14
|
+
@s420 = FSM.from_kiss 'spec/fixtures/s420'
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should parse both KISS files and strings' do
|
18
|
+
@mc.should == FSM.from_kiss(File.read 'spec/fixtures/mc')
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should handle edge cases, like KISS files with arbitrary next-states' do
|
22
|
+
lambda { FSM.from_kiss 'spec/fixtures/ex5' }.should_not raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should properly report the number of inputs' do
|
26
|
+
@opus.input_count.should == 5
|
27
|
+
@lion.input_count.should == 2
|
28
|
+
@mc.input_count.should == 3
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should properly report the number of outputs' do
|
32
|
+
@opus.output_count.should == 6
|
33
|
+
@lion.output_count.should == 1
|
34
|
+
@mc.output_count.should == 5
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should properly generate the Q Blanket' do
|
38
|
+
@opus.beta_q.should == Blanket[B[0,1,2], B[0,3,4], B[0,5], B[0,6,7], B[0,8,9,10,11,12,13,14], B[0,15,16], B[0,17,18], B[0,19], B[0,20], B[0,21]]
|
39
|
+
@lion.beta_q.should == Blanket[B[0,1,2], B[3,4,5], B[6,7,8], B[9,10]]
|
40
|
+
@mc.beta_q.should == Blanket[B[0,1,2], B[3,4], B[5,6,7], B[8,9]]
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should properly generate the F Blanket' do
|
44
|
+
@opus.beta_f.should == Blanket[B[0,1], B[2,3,9], B[4,14], B[5,6], B[7,8,20,21], B[10,16], B[11,18], B[12,15], B[13,17], B[19]]
|
45
|
+
@lion.beta_f.should == Blanket[B[0,1,4], B[2], B[2,3,7], B[5,6,10], B[8,9]]
|
46
|
+
@mc.beta_f.should == Blanket[B[0,1], B[2], B[3], B[4], B[5], B[6,7], B[8], B[9]]
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should properly generate selected inputs Blankets' do
|
50
|
+
@mc.beta_x(Set[0]).should == Blanket[B[0,1,3,4,6,7,8,9], B[1,2,3,4,5,7,8,9]]
|
51
|
+
@mc.beta_x(Set[1,2]).should == Blanket[B[0,1,3,5,6,8], B[0,1,4,5,6,9], B[0,2,3,6,7,8], B[0,2,4,6,7,9]]
|
52
|
+
@mc.beta_x(Set[]).should == Blanket[B[0,1,2,3,4,5,6,7,8,9]]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should properly generate its KISS representation' do
|
56
|
+
@opus.to_kiss.should == File.read('spec/fixtures/opus.to_kiss')
|
57
|
+
@lion.to_kiss.should == File.read('spec/fixtures/lion.to_kiss')
|
58
|
+
@mc.to_kiss.should == File.read('spec/fixtures/mc.to_kiss')
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should return given inputs’ encoding for the given row(s)' do
|
62
|
+
@opus.x_encoding(Set[2], B[0]).should == '1'
|
63
|
+
@opus.x_encoding(Set[0], B[0]).should == '-'
|
64
|
+
@opus.x_encoding(Set[0], B[7,8]).should == '0'
|
65
|
+
lambda { @opus.x_encoding Set[0], B[8,9] }.should raise_error(AmbiguousEncodingQuery, 'ambiguous encoding query: block 8,9')
|
66
|
+
@opus.x_encoding(Set[0,2], B[0]).should == '-1'
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should return output encoding for the given row(s)' do
|
70
|
+
@opus.y_encoding(B[0]).should == '110000'
|
71
|
+
@opus.y_encoding(B[0,1,2,3]).should == '110000'
|
72
|
+
lambda { @opus.y_encoding B[3,4] }.should raise_error(AmbiguousEncodingQuery, 'ambiguous encoding query: block 3,4')
|
73
|
+
@lion.y_encoding(B[2,3]).should == '1'
|
74
|
+
@mark1.y_encoding(B[0]).should == '-11---1-00------'
|
75
|
+
@mark1.y_encoding(B[0,16]).should == '-11---1-00100000'
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should return state encoding for the given row(s)' do
|
79
|
+
@opus.q_encoding(B[1]).should == 'init0'
|
80
|
+
@opus.q_encoding(B[1,2]).should == 'init0'
|
81
|
+
@opus.q_encoding(B[0,1,2]).should == 'init0'
|
82
|
+
@opus.q_encoding(B[0]).should == '-'
|
83
|
+
lambda { @opus.q_encoding B[2,3] }.should raise_error(AmbiguousEncodingQuery, 'ambiguous encoding query: block 2,3')
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should return the row(s) of a state matching next-state of given row(s)' do
|
87
|
+
@opus.state_rows_of_next_state_of(B[20,21]).should == B[0,8,9,10,11,12,13,14]
|
88
|
+
@mark1.state_rows_of_next_state_of(B[2]).should == B[0,22]
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should equal/not-equal other FSMs and hash properly' do
|
92
|
+
@lion.should_not == FSM.from_kiss('spec/fixtures/opus')
|
93
|
+
@lion.should == FSM.from_kiss('spec/fixtures/lion')
|
94
|
+
@lion.hash.should == FSM.from_kiss('spec/fixtures/lion').hash
|
95
|
+
@lion.should eql FSM.from_kiss('spec/fixtures/lion')
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should expand selected input columns and return a new FSM instance' do
|
99
|
+
@lion.expand_x(Set[0,1]).should == FSM.from_kiss('spec/fixtures/lion.exp')
|
100
|
+
@fsm.expand_x(Set[0,1,2,3]).should == FSM.from_kiss('spec/fixtures/fsm.exp')
|
101
|
+
@fsm.expand_x(Set[0,3]).should == FSM.from_kiss('spec/fixtures/fsm.partially-exp')
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should return self if asked to expand columns lacking don’t-cares' do
|
105
|
+
opus = FSM.from_kiss 'spec/fixtures/opus.to_kiss'
|
106
|
+
opus.expand_x(Set[2]).should equal opus
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should report its input/output/state counts' do
|
110
|
+
@fsm.stats.should == '4/2+10s'
|
111
|
+
@lion.stats.should == '2/1+4s'
|
112
|
+
@mark1.stats.should == '5/16+15s'
|
113
|
+
@mc.stats.should == '3/5+4s'
|
114
|
+
@opus.stats.should == '5/6+10s'
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should report whether its directly implementable in a given Set of Archs' do
|
118
|
+
@lion.should be_implementable_in Set[Arch[4,2]]
|
119
|
+
@mc.should_not be_implementable_in Set[Arch[4,2]]
|
120
|
+
@mc.should be_implementable_in Set[Arch[5,1]]
|
121
|
+
@s8.should be_implementable_in Set[Arch[2,1]]
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should report the cell count for a given Set of Archs (if it’s implementable in it)' do
|
125
|
+
@lion.fsm_cells(Set[Arch[4,1]]).should == 3
|
126
|
+
@lion.fsm_cells(Set[Arch[4,2]]).should == 2
|
127
|
+
@mc.fsm_cells(Set[Arch[4,2]]).should be_nil
|
128
|
+
@mc.fsm_cells(Set[Arch[5,1]]).should == 7
|
129
|
+
@s8.fsm_cells(Set[Arch[2,1]]).should == 0
|
130
|
+
@s8.fsm_cells(Set[Arch[3,2]]).should == 0
|
131
|
+
@s8.fsm_cells(Set[Arch[4,1]]).should == 0
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should report its input relevance, and drop irrelevant inputs' do
|
135
|
+
@fsm.input_relevance.should == [2, 1, 3, 0, nil, nil, nil, nil]
|
136
|
+
@lion.input_relevance.should == [0, nil, nil, 1]
|
137
|
+
@mark1.input_relevance.should == [nil, nil, nil, nil, 0, 3, 2, 4, 1]
|
138
|
+
@mc.input_relevance.should == [nil, nil, 2, 1, 0]
|
139
|
+
@opus.input_relevance.should == [nil, nil, nil, nil, 2, 3, 4, 0, 1]
|
140
|
+
@s8.input_relevance.should == [3, 2, 1, 0, nil, nil, nil]
|
141
|
+
@s420.input_relevance.should == [1, 0, 18, nil, nil, nil, nil, nil, 17, 16, 15, 14, 13]
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end end
|