art-decomp 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
data/bin/ad-fsm-info ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require_relative '../lib/art-decomp'
5
+
6
+ $stdout.sync = true
7
+
8
+ ARGV.each do |fsm_file|
9
+ fsm = ArtDecomp::FSM.from_kiss fsm_file
10
+ puts "#{fsm_file}: #{fsm.stats}"
11
+
12
+ f_seps = fsm.beta_f.seps
13
+ i_seps = Hash[(0...fsm.input_count).map { |i| [i, fsm.beta_x(Set[i]).seps & f_seps] }]
14
+ i_seps['Q'] = fsm.beta_q.seps & f_seps
15
+ o_seps = Hash[(0...fsm.output_count).map { |o| [o, fsm.beta_y(Set[o]).seps] }]
16
+ o_seps['Q’'] = fsm.beta_qp.seps
17
+
18
+ u_i_seps = i_seps.map { |i, seps| seps.reject { |s| i_seps.any? { |o, os| o != i and o != 'Q' and os.include? s } } }
19
+
20
+ puts "relevant separation counts: #{i_seps.values.map &:size}"
21
+ puts "unique relevant sep counts: #{u_i_seps.map &:size}"
22
+ puts "relevant separation counts by input: #{i_seps.values.map(&:size).each.with_index.sort.reverse.map &:last}"
23
+ puts "unique relevant sep counts by input: #{u_i_seps.map(&:size).each.with_index.sort.reverse.map &:last}"
24
+ puts "relevant state separations per pin: #{i_seps['Q'].size.to_f / fsm.beta_q.pins}"
25
+ puts "unique relevant state seps per pin: #{u_i_seps.last.size.to_f / fsm.beta_q.pins}"
26
+ puts "unnecessary inputs: #{i_seps.select { |i, sep| sep.empty? }.keys.sort}"
27
+
28
+ i_seps.pairs.each do |(a, sep_a), (b, sep_b)|
29
+ next if sep_a.empty? or sep_b.empty?
30
+ puts "input inclusion: #{a} ⊂ #{b}" if sep_a.proper_subset? sep_b
31
+ puts "input inclusion: #{a} = #{b}" if sep_a == sep_b
32
+ puts "input inclusion: #{a} ⊃ #{b}" if sep_a.proper_superset? sep_b
33
+ end
34
+
35
+ o_seps.each do |o, o_sep|
36
+ required = Set[]
37
+ o_sep.each do |separation|
38
+ required << i_seps.select { |i, s| s.include? separation }.keys.to_set
39
+ end
40
+ required.delete_if do |this|
41
+ required.any? { |other| this != other and this.superset? other }
42
+ end
43
+ puts "sufficient for o#{o}: #{required.map(&:to_a)}"
44
+ end
45
+
46
+ puts
47
+
48
+ end
data/lib/art-decomp.rb CHANGED
@@ -61,5 +61,7 @@ require_relative 'art-decomp/qv_generator/bipainting'
61
61
  require_relative 'art-decomp/qv_generator/graph_colouring'
62
62
  require_relative 'art-decomp/qv_generator/graph_merging'
63
63
  require_relative 'art-decomp/sep'
64
+ require_relative 'art-decomp/uv_relevance_generator'
64
65
  require_relative 'art-decomp/uv_generator/braindead'
65
- require_relative 'art-decomp/uv_generator/relevance'
66
+ require_relative 'art-decomp/uv_generator/general_relevance'
67
+ require_relative 'art-decomp/uv_generator/unique_relevance'
@@ -2,7 +2,8 @@ module ArtDecomp class Decomposer
2
2
 
3
3
  def initialize params
4
4
  @archs = params[:archs]
5
- @uv_gens = params[:uv_gens].map { |gen| gen.new params[:fsm], params[:archs] }
5
+ @fsm = params[:fsm]
6
+ @uv_gens = params[:uv_gens].map &:new
6
7
  @qu_gens = params[:qu_gens].map &:new
7
8
  @qv_gens = params[:qv_gens].map &:new
8
9
  end
@@ -11,7 +12,7 @@ module ArtDecomp class Decomposer
11
12
  @seen = Set[]
12
13
  Enumerator.new do |yielder|
13
14
  @uv_gens.each do |uv_gen|
14
- uv_gen.uv_pairs.each do |fsm, u, v|
15
+ uv_gen.uv_pairs(@fsm, @archs).each do |fsm, u, v|
15
16
  unless @seen.include? [fsm, u, v]
16
17
  @qu_gens.each do |qu_gen|
17
18
  qu_gen.blankets(fsm, u, v).each do |qu|
@@ -9,7 +9,7 @@ module ArtDecomp class Executable
9
9
  opt :archs, 'Target architecture(s)', :type => :strings
10
10
  opt :outdir, 'Output directory', :type => :string
11
11
  opt :iters, 'Number of iterations, 0 for infinite', :default => 1
12
- opt :uv, 'UV generator(s)', :default => ['Relevance']
12
+ opt :uv, 'UV generator(s)', :default => ['GeneralRelevance']
13
13
  opt :qu, 'Qu generator(s)', :default => ['EdgeLabels']
14
14
  opt :qv, 'Qv generator(s)', :default => ['GraphColouring']
15
15
  opt :binary, 'Compute binary decompositions', :default => false
@@ -41,9 +41,16 @@ module ArtDecomp class FSM
41
41
  Blanket.from_array @state
42
42
  end
43
43
 
44
+ def beta_qp
45
+ Blanket.from_array @next_state
46
+ end
47
+
44
48
  def beta_x ins
45
- return Blanket[B[*0...@state.size]] if ins.empty?
46
- ins.map { |i| Blanket.from_array @inputs[i] }.inject :*
49
+ beta @inputs, ins
50
+ end
51
+
52
+ def beta_y ins
53
+ beta @outputs, ins
47
54
  end
48
55
 
49
56
  alias eql? ==
@@ -58,26 +65,22 @@ module ArtDecomp class FSM
58
65
  Arch[input_count + beta_q.pins, output_count + beta_q.pins].cells archs
59
66
  end
60
67
 
68
+ def general_relevance
69
+ relevance false
70
+ end
71
+
61
72
  def hash
62
73
  @inputs.hash ^ @outputs.hash ^ @state.hash ^ @next_state.hash
63
74
  end
64
75
 
65
76
  def implementable_in? archs
66
- return true if @outputs.map { |output| Blanket.from_array output }.inject(:*).size < 2
67
- input_count + beta_q.pins <= archs.map(&:pins).max
77
+ not fsm_cells(archs).nil?
68
78
  end
69
79
 
70
80
  def input_count
71
81
  @inputs.size
72
82
  end
73
83
 
74
- def input_relevance
75
- seps = beta_f.seps
76
- perpin = (beta_q.seps & seps).size.to_f / beta_q.pins
77
- more, less = (0...input_count).map { |i| [(beta_x(Set[i]).seps & seps).size, i] }.sort.reverse.reject { |rel, i| rel.zero? }.partition { |rel, i| rel > perpin }
78
- more.map(&:last) + [nil] * beta_q.pins + less.map(&:last)
79
- end
80
-
81
84
  def q_encoding rows
82
85
  # FIXME: consider tr DontCare, '*'
83
86
  encoding @state, rows
@@ -109,6 +112,10 @@ module ArtDecomp class FSM
109
112
  @state.all? { |s| s == DontCare } and @next_state.all? { |ns| ns == DontCare }
110
113
  end
111
114
 
115
+ def unique_relevance
116
+ relevance true
117
+ end
118
+
112
119
  def x_encoding ins, rows
113
120
  ins.map { |i| encoding @inputs[i], rows }.join
114
121
  end
@@ -123,6 +130,11 @@ module ArtDecomp class FSM
123
130
 
124
131
  private
125
132
 
133
+ def beta column, ins
134
+ return Blanket[B[*0...@state.size]] if ins.empty?
135
+ ins.map { |i| Blanket.from_array column[i] }.inject :*
136
+ end
137
+
126
138
  def encoding column, rows
127
139
  encs = rows.bits.map { |row| column[row] }.uniq - [DontCare]
128
140
  case encs.size
@@ -132,4 +144,15 @@ module ArtDecomp class FSM
132
144
  end
133
145
  end
134
146
 
147
+ def relevance unique
148
+ f_seps = beta_f.seps
149
+ i_seps = Hash[(0...input_count).map { |i| [i, beta_x(Set[i]).seps & f_seps] }]
150
+ q_seps = beta_q.seps & f_seps
151
+ q_seps -= i_seps.values.inject :+ if unique
152
+ perpin = q_seps.size.to_f / beta_q.pins
153
+ i_seps = Hash[i_seps.map { |i, seps| [i, seps - i_seps.reject { |o,| o == i }.values.inject(Set[], :+)] }] if unique
154
+ more, less = i_seps.map { |i, seps| [seps.size, i] }.sort.reverse.reject { |rel,| rel.zero? }.partition { |rel,| rel > perpin }
155
+ more.map(&:last) + [nil] * beta_q.pins + less.map(&:last)
156
+ end
157
+
135
158
  end end
@@ -5,12 +5,10 @@ module ArtDecomp class Graph
5
5
  def initialize blanket, seps
6
6
  @vertices = blanket.ints.dup
7
7
  @vertices.delete_if { |this| @vertices.any? { |other| other != this and other & this == this } }
8
- @edges = Set[]
9
- seps.each do |sep|
10
- @vertices.pairs.each do |a, b|
11
- @edges << Set[a,b] unless (a & sep).zero? or (b & sep).zero? or (a | b) & sep != sep
12
- end
13
- end
8
+ relevant = Hash[@vertices.map { |v| [v, seps.select { |s| v&s != 0 and v&s != s }.to_set] }]
9
+ @edges = @vertices.pairs.select do |a, b|
10
+ (relevant[a] & relevant[b]).any? { |s| a&s != b&s }
11
+ end.map(&:to_set).to_set
14
12
  end
15
13
 
16
14
  def adjacent *vertices
@@ -19,6 +19,7 @@ module ArtDecomp class Logging < Gazer::Aspect::Base
19
19
  @@log.formatter = proc { |sev, date, name, msg| "#{date} #{msg}\n" }
20
20
  @@indent = ''
21
21
  apply!
22
+ @@start = Time.now
22
23
  end
23
24
 
24
25
  def self.off
@@ -27,14 +28,15 @@ module ArtDecomp class Logging < Gazer::Aspect::Base
27
28
  end
28
29
 
29
30
  after instances_of(Executable) => :run do |point|
30
- @@log.info "final best decomposition: #{point.object.best} cells"
31
+ secs = (Time.now - @@start).to_i
32
+ @@log.info "#{point.object.best ? "final best decomposition: #{point.object.best} cells" : 'no final decomposition'}; done in #{secs}s (#{secs / 60 / 60}h #{secs / 60 % 60}m #{secs % 60}s)"
31
33
  end
32
34
 
33
35
  before instances_of(Executable) => :decompositions do |point|
34
36
  @@indent = ' ' * (point.object.iters - point.args[1])
35
37
  path = point.args[2][point.object.dir.size+1..-1]
36
38
  archs = point.object.archs.map(&:to_s).sort.reverse.join '+'
37
- @@log.info "#{@@indent}FSM #{point.args[0].stats} → #{archs} (#{path}) with #{point.object.gens} – best so far: #{point.object.best} cells"
39
+ @@log.info "#{@@indent}FSM #{point.args[0].stats} → #{archs} (#{path}) with #{point.object.gens} – #{point.object.best ? "best so far: #{point.object.best} cells" : 'no decomposition so far'}"
38
40
  end
39
41
 
40
42
  before instances_of(UVGenerator.constants.map { |c| eval("UVGenerator::#{c}") }) => :uv_pairs do |point|
@@ -1,11 +1,11 @@
1
1
  module ArtDecomp class QuGenerator::BlockTable
2
2
 
3
3
  def blankets fsm, u, v
4
+ @seps = fsm.beta_f.seps
5
+ @rows = fsm.beta_q.ints.dup
6
+ @cols = fsm.beta_x(u).ints
7
+ @r_adms = {}
4
8
  Enumerator.new do |yielder|
5
- @seps = fsm.beta_f.seps
6
- @rows = fsm.beta_q.ints.dup
7
- @cols = fsm.beta_x(u).ints
8
- @r_adms = {}
9
9
  fold_matching!
10
10
  yielder.yield Blanket.new @rows
11
11
  while @rows.size > 1
@@ -1,9 +1,9 @@
1
1
  module ArtDecomp class QuGenerator::EdgeLabels
2
2
 
3
3
  def blankets fsm, u, v
4
+ seps = fsm.beta_f.seps - fsm.beta_x(u).seps
5
+ @graph = Graph.new fsm.beta_q, seps
4
6
  Enumerator.new do |yielder|
5
- seps = fsm.beta_f.seps - fsm.beta_x(u).seps
6
- @graph = Graph.new fsm.beta_q, seps
7
7
  initial_merge
8
8
  yielder.yield Blanket.new @graph.vertices
9
9
  while @graph.vertices.size > 1
@@ -1,10 +1,10 @@
1
1
  module ArtDecomp class QvGenerator::Bipainting
2
2
 
3
3
  def blankets fsm, u, v, beta_qu
4
+ beta_u = fsm.beta_x u
5
+ beta_v = fsm.beta_x v
6
+ bipainter = Bipainter.new fsm.beta_q, beta_v, fsm.beta_f.seps - beta_u.seps - beta_qu.seps
4
7
  Enumerator.new do |yielder|
5
- beta_u = fsm.beta_x u
6
- beta_v = fsm.beta_x v
7
- bipainter = Bipainter.new fsm.beta_q, beta_v, fsm.beta_f.seps - beta_u.seps - beta_qu.seps
8
8
  yielder.yield bipainter.blankets
9
9
  end
10
10
  end
@@ -1,9 +1,9 @@
1
1
  module ArtDecomp class QvGenerator::GraphColouring
2
2
 
3
3
  def blankets fsm, u, v, beta_qu
4
+ beta_u = fsm.beta_x u
5
+ beta_v = fsm.beta_x v
4
6
  Enumerator.new do |yielder|
5
- beta_u = fsm.beta_x u
6
- beta_v = fsm.beta_x v
7
7
  beta_g = Graph.new(fsm.beta_q * beta_v, fsm.beta_f.seps - beta_u.seps - beta_qu.seps).blanket_from_colouring
8
8
  beta_qv = Graph.new(fsm.beta_q, beta_g.seps - beta_v.seps).blanket_from_colouring
9
9
  yielder.yield beta_qv, beta_g
@@ -1,10 +1,10 @@
1
1
  module ArtDecomp class QvGenerator::GraphMerging
2
2
 
3
3
  def blankets fsm, u, v, beta_qu
4
+ beta_u = fsm.beta_x u
5
+ beta_v = fsm.beta_x v
6
+ qv_graph = Graph.new fsm.beta_q, fsm.beta_f.seps - beta_u.seps - beta_qu.seps - beta_v.seps
4
7
  Enumerator.new do |yielder|
5
- beta_u = fsm.beta_x u
6
- beta_v = fsm.beta_x v
7
- qv_graph = Graph.new fsm.beta_q, fsm.beta_f.seps - beta_u.seps - beta_qu.seps - beta_v.seps
8
8
  loop do
9
9
  beta_qv = Blanket.new qv_graph.vertices
10
10
  g_graph = Graph.new beta_qv * beta_v, fsm.beta_f.seps - beta_u.seps - beta_qu.seps
@@ -1,20 +1,16 @@
1
1
  module ArtDecomp class UVGenerator::Braindead
2
2
 
3
- def initialize fsm, archs
4
- @fsm = fsm
5
- @input_count = fsm.input_count
6
- @max_v_size = archs.map(&:pins).max
7
- end
8
-
9
- def uv_pairs
3
+ def uv_pairs fsm, archs
4
+ input_count = fsm.input_count
5
+ inputs = (0...input_count).to_a
6
+ max_v_size = archs.map(&:pins).max
10
7
  Enumerator.new do |yielder|
11
- inputs = (0...@input_count).to_a
12
- (0...2**@input_count).each do |vector|
8
+ (0...2**input_count).each do |vector|
13
9
  u, v = Set[], Set[]
14
- @input_count.times do |bit|
10
+ input_count.times do |bit|
15
11
  (vector[bit].zero? ? u : v) << inputs[bit]
16
12
  end
17
- yielder.yield @fsm.expand_x(v), u, v if v.size <= @max_v_size
13
+ yielder.yield fsm.expand_x(v), u, v if v.size <= max_v_size
18
14
  end
19
15
  end
20
16
  end
@@ -0,0 +1,7 @@
1
+ module ArtDecomp class UVGenerator::GeneralRelevance < UVRelevanceGenerator
2
+
3
+ def uv_pairs fsm, archs
4
+ super fsm, archs, :general_relevance
5
+ end
6
+
7
+ end end
@@ -0,0 +1,7 @@
1
+ module ArtDecomp class UVGenerator::UniqueRelevance < UVRelevanceGenerator
2
+
3
+ def uv_pairs fsm, archs
4
+ super fsm, archs, :unique_relevance
5
+ end
6
+
7
+ end end
@@ -0,0 +1,19 @@
1
+ module ArtDecomp class UVRelevanceGenerator
2
+
3
+ def uv_pairs fsm, archs, method
4
+ relevance = fsm.send(method).reverse
5
+ max_v_sizes = archs.map(&:pins).to_set
6
+ cache = Set[]
7
+ Enumerator.new do |yielder|
8
+ (0...2**relevance.size).each do |vector|
9
+ bits = vector.bits
10
+ next unless max_v_sizes.include? bits.size
11
+ v = relevance.values_at(*bits).compact.to_set
12
+ u = (relevance - v.to_a).compact.to_set
13
+ yielder.yield fsm.expand_x(v), u, v unless cache.include? v
14
+ cache << v
15
+ end
16
+ end
17
+ end
18
+
19
+ end end
@@ -6,8 +6,7 @@ module ArtDecomp describe Decomposer do
6
6
  uv1, uv2 = mock('UVGenerator class'), mock('UVGenerator class')
7
7
  qu1, qu2 = mock('QuGenerator class'), mock('QuGenerator class')
8
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 }
9
+ [uv1, uv2, qu1, qu2, qv1, qv2].each { |gen| gen.should_receive(:new).with no_args }
11
10
  Decomposer.new :fsm => fsm, :archs => archs, :uv_gens => [uv1, uv2], :qu_gens => [qu1, qu2], :qv_gens => [qv1, qv2]
12
11
  end
13
12
 
@@ -26,6 +25,7 @@ module ArtDecomp describe Decomposer do
26
25
 
27
26
  it 'should poll the generators and yield the resulting decompositions one by one' do
28
27
  fsm = mock FSM, :beta_q => mock(Blanket, :pins => 3, :size => 5), :input_count => 4
28
+ archs = Set[Arch[5,1]]
29
29
 
30
30
  u_a, v_a = Set[0,1], Set[2] # for this U/V pair: two Qu generating one Qv/G pair each
31
31
  qu_a1, qv_a1, g_a1 = mock(Blanket, :pins => 2, :size => 4), mock(Blanket, :pins => 3, :size => 5), mock(Blanket, :pins => 2)
@@ -36,14 +36,14 @@ module ArtDecomp describe Decomposer do
36
36
  qv_bA, g_bA = mock(Blanket, :pins => 3, :size => 5), mock(Blanket, :pins => 2)
37
37
  qv_bB, g_bB = mock(Blanket, :pins => 3, :size => 5), mock(Blanket, :pins => 2)
38
38
 
39
- uv_gen = mock UVGenerator, :new => StubGenerator.new({[] => [[fsm, u_a, v_a], [fsm, u_b, v_b]]})
39
+ uv_gen = mock UVGenerator, :new => StubGenerator.new({[fsm, archs] => [[fsm, u_a, v_a], [fsm, u_b, v_b]]})
40
40
  qu_gen = mock QuGenerator, :new => StubGenerator.new({[fsm, u_a, v_a] => [qu_a1, qu_a2],
41
41
  [fsm, u_b, v_b] => [qu_b]})
42
42
  qv_gen = mock QvGenerator, :new => StubGenerator.new({[fsm, u_a, v_a, qu_a1] => [[qv_a1, g_a1]],
43
43
  [fsm, u_a, v_a, qu_a2] => [[qv_a2, g_a2]],
44
44
  [fsm, u_b, v_b, qu_b] => [[qv_bA, g_bA], [qv_bB, g_bB]]})
45
45
 
46
- decomposer = Decomposer.new :archs => Set[Arch[5,1]], :fsm => fsm, :uv_gens => [uv_gen], :qu_gens => [qu_gen], :qv_gens => [qv_gen]
46
+ decomposer = Decomposer.new :archs => archs, :fsm => fsm, :uv_gens => [uv_gen], :qu_gens => [qu_gen], :qv_gens => [qv_gen]
47
47
  results = decomposer.decompositions.to_a
48
48
  results.size.should == 4
49
49
  results.first.should == Decomposition.new(fsm, u_a, v_a, qu_a1, qv_a1, g_a1)
@@ -3,7 +3,6 @@
3
3
  module ArtDecomp describe Executable do
4
4
 
5
5
  before do
6
- @orig_stderr = $stderr
7
6
  $stderr = StringIO.new
8
7
  @fsm = 'spec/fixtures/fsm'
9
8
  @dir = "#{Dir.tmpdir}/#{rand.to_s}"
@@ -11,7 +10,7 @@ module ArtDecomp describe Executable do
11
10
  end
12
11
 
13
12
  after do
14
- $stderr = @orig_stderr
13
+ $stderr = STDERR
15
14
  FileUtils.rmtree @dir if Dir.exists? @dir
16
15
  end
17
16
 
@@ -84,7 +83,7 @@ module ArtDecomp describe Executable do
84
83
  dec = Decomposition.new fsm, Set[0], Set[1], Blanket[B[0],B[1],B[2]], Blanket[], Blanket[]
85
84
 
86
85
  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
86
+ Decomposer.should_receive(:new).with(:fsm => fsm, :archs => an_instance_of(Set), :uv_gens => [UVGenerator::GeneralRelevance], :qu_gens => [QuGenerator::EdgeLabels], :qv_gens => [QvGenerator::GraphColouring]).and_return decomposer
88
87
 
89
88
  Executable.new(@args).run false
90
89
  Marshal.load(File.read("#{@dir}/decompositions")).should == [dec, dec]
@@ -120,7 +119,7 @@ module ArtDecomp describe Executable do
120
119
  FSM.should_receive(:from_kiss).with(@fsm).and_return fsm
121
120
 
122
121
  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
122
+ Decomposer.should_receive(:new).with(:fsm => fsm, :archs => Set[Arch[5,1]], :uv_gens => [UVGenerator::Braindead, UVGenerator::GeneralRelevance, UVGenerator::UniqueRelevance], :qu_gens => [QuGenerator::BlockTable, QuGenerator::EdgeLabels], :qv_gens => [QvGenerator::Bipainting, QvGenerator::GraphColouring,QvGenerator::GraphMerging]).and_return decomposer
124
123
 
125
124
  args = ['--archs', '5/1', '--uv', 'all', '--qu', 'all', '--qv', 'all', '--outdir', @dir, @fsm]
126
125
  Executable.new(args).run
@@ -47,6 +47,12 @@ module ArtDecomp describe FSM do
47
47
  @mc.beta_q.should == Blanket[B[0,1,2], B[3,4], B[5,6,7], B[8,9]]
48
48
  end
49
49
 
50
+ it 'should properly generate the Q’ Blanket' do
51
+ @opus.beta_qp.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]]
52
+ @lion.beta_qp.should == Blanket[B[0,1,4], B[2,3,7], B[5,6,10], B[8,9]]
53
+ @mc.beta_qp.should == Blanket[B[0,1,9], B[2,3], B[4,5], B[6,7,8]]
54
+ end
55
+
50
56
  it 'should properly generate the F Blanket' do
51
57
  @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]]
52
58
  @lion.beta_f.should == Blanket[B[0,1,4], B[2], B[2,3,7], B[5,6,10], B[8,9]]
@@ -59,6 +65,12 @@ module ArtDecomp describe FSM do
59
65
  @mc.beta_x(Set[]).should == Blanket[B[0,1,2,3,4,5,6,7,8,9]]
60
66
  end
61
67
 
68
+ it 'should properly generate selected output Blankets' do
69
+ @mc.beta_y(Set[4]).should == Blanket[B[0,1,2,3,4,5,6,7], B[8,9]]
70
+ @mc.beta_y(Set[2,3]).should == Blanket[B[0,1,2], B[3,4], B[5,6,7,8,9]]
71
+ @mc.beta_y(Set[]).should == Blanket[B[0,1,2,3,4,5,6,7,8,9]]
72
+ end
73
+
62
74
  it 'should properly generate its KISS representation' do
63
75
  @opus.to_kiss.should == File.read('spec/fixtures/opus.to_kiss')
64
76
  @lion.to_kiss.should == File.read('spec/fixtures/lion.to_kiss')
@@ -139,15 +151,26 @@ module ArtDecomp describe FSM do
139
151
  @s8.fsm_cells(Set[Arch[4,1]]).should == 0
140
152
  end
141
153
 
142
- it 'should report its input relevance, and drop irrelevant inputs' do
143
- @ex4.input_relevance.should == [nil, nil, nil, nil, 2, 1, 5, 4, 3]
144
- @fsm.input_relevance.should == [2, 1, 3, 0, nil, nil, nil, nil]
145
- @lion.input_relevance.should == [0, nil, nil, 1]
146
- @mark1.input_relevance.should == [nil, nil, nil, nil, 0, 3, 2, 4, 1]
147
- @mc.input_relevance.should == [nil, nil, 2, 1, 0]
148
- @opus.input_relevance.should == [nil, nil, nil, nil, 2, 3, 4, 0, 1]
149
- @s8.input_relevance.should == [3, 2, 1, 0, nil, nil, nil]
150
- @tt.input_relevance.should == [1, 3, 2]
154
+ it 'should report its general input relevance, and drop irrelevant inputs' do
155
+ @ex4.general_relevance.should == [nil, nil, nil, nil, 2, 1, 5, 4, 3]
156
+ @fsm.general_relevance.should == [2, 1, 3, 0, nil, nil, nil, nil]
157
+ @lion.general_relevance.should == [0, nil, nil, 1]
158
+ @mark1.general_relevance.should == [nil, nil, nil, nil, 0, 3, 2, 4, 1]
159
+ @mc.general_relevance.should == [nil, nil, 2, 1, 0]
160
+ @opus.general_relevance.should == [nil, nil, nil, nil, 2, 3, 4, 0, 1]
161
+ @s8.general_relevance.should == [3, 2, 1, 0, nil, nil, nil]
162
+ @tt.general_relevance.should == [1, 3, 2]
163
+ end
164
+
165
+ it 'should report its unique input relevance, and drop irrelevant inputs' do
166
+ @ex4.unique_relevance.should == [nil, nil, nil, nil, 2, 1, 5, 4, 3]
167
+ @fsm.unique_relevance.should == [2, 1, 0, 3, nil, nil, nil, nil]
168
+ @lion.unique_relevance.should == [0, nil, nil, 1]
169
+ @mark1.unique_relevance.should == [nil, nil, nil, nil, 0, 3, 2, 4, 1]
170
+ @mc.unique_relevance.should == [nil, nil, 2, 1, 0]
171
+ @opus.unique_relevance.should == [2, nil, nil, nil, nil, 3, 4, 1, 0]
172
+ @s8.unique_relevance.should == [nil, nil, nil]
173
+ @tt.unique_relevance.should == [1, 3, 2]
151
174
  end
152
175
 
153
176
  it 'should report whether it’s a truth table or a full-blown FSM' do
@@ -66,4 +66,9 @@ module ArtDecomp describe Graph do
66
66
  @graph.adjacent(B[5,6], B[7]).should == Set[B[3,4], B[8,9]]
67
67
  end
68
68
 
69
+ it 'should only create the necessary edges' do
70
+ blanket = Blanket[B[1,2,3], B[1,2,4], B[1,5], B[2,6]]
71
+ Graph.new(blanket, Set[Sep[1,2]]).edges.should == Set[Set[B[1,5], B[2,6]]]
72
+ end
73
+
69
74
  end end
@@ -6,6 +6,7 @@ module ArtDecomp describe Logging do
6
6
 
7
7
  before do
8
8
  @dir = "#{Dir.tmpdir}/#{rand.to_s}"
9
+ @fsm = mock FSM, :beta_f => Blanket[], :beta_q => Blanket[], :beta_x => Blanket[]
9
10
  @log = StringIO.new
10
11
  Logging.log = @log
11
12
  end
@@ -23,27 +24,37 @@ module ArtDecomp describe Logging do
23
24
  it 'should log Executable’s decompositions calls on simple cases' do
24
25
  args = ['-a', '5/1', '4/2', '-o', @dir, 'spec/fixtures/lion']
25
26
  Executable.new(args).run
26
- log.should =~ rex('final best decomposition: 2')
27
+ log.should =~ rex('final best decomposition: 2 cells; done in 0s (0h 0m 0s)')
27
28
  end
28
29
 
29
30
  it 'should log Executable’s decompositions calls on typical cases' do
31
+ Decomposer.should_receive(:new).and_return mock(Decomposer, :decompositions => [].each)
32
+ args = ['-a', '5/1', '4/2', '-o', @dir, 'spec/fixtures/fsm']
33
+ ex = Executable.new(args)
34
+ ex.stub!(:best).and_return 69
35
+ ex.run
36
+ log.should =~ rex('FSM 4/2+10s → 5/1+4/2 () with GeneralRelevance, EdgeLabels, GraphColouring – best so far: 69 cells')
37
+ log.should =~ rex('final best decomposition: 69 cells; done in 0s (0h 0m 0s)')
38
+ end
39
+
40
+ it 'should log Executable’s decompositions calls on problematic cases' do
30
41
  Decomposer.should_receive(:new).and_return mock(Decomposer, :decompositions => [].each)
31
42
  args = ['-a', '5/1', '4/2', '-o', @dir, 'spec/fixtures/fsm']
32
43
  Executable.new(args).run
33
- log.should =~ rex('FSM 4/2+10s → 5/1+4/2 () with Relevance, EdgeLabels, GraphColouring – best so far: ')
34
- log.should =~ rex('final best decomposition: ')
44
+ log.should =~ rex('FSM 4/2+10s → 5/1+4/2 () with GeneralRelevance, EdgeLabels, GraphColouring – no decomposition so far')
45
+ log.should =~ rex('no final decomposition; done in 0s (0h 0m 0s)')
35
46
  end
36
47
 
37
48
  it 'should log UVGenerators’ uv_pairs calls' do
38
- uv = UVGenerator::Braindead.new mock(FSM, :input_count => 2), Set[Arch[5,1]]
39
- uv.uv_pairs
49
+ uv = UVGenerator::Braindead.new
50
+ uv.uv_pairs mock(FSM, :input_count => 2), Set[Arch[5,1]]
40
51
  log.should =~ rex('UV with Braindead')
41
52
  end
42
53
 
43
54
  it 'should log QuGenerators’ blankets calls' do
44
55
  qu = QuGenerator::BlockTable.new
45
56
  [[Set[0], Set[1]], [Set[1], Set[0]]].each do |u, v|
46
- qu.blankets mock(FSM), u, v
57
+ qu.blankets @fsm, u, v
47
58
  end
48
59
  log.should =~ rex('U = [0], V = [1], Qu with BlockTable')
49
60
  log.should =~ rex('U = [1], V = [0], Qu with BlockTable')
@@ -53,7 +64,7 @@ module ArtDecomp describe Logging do
53
64
  Logging.level = Logger::DEBUG
54
65
  qv = QvGenerator::GraphColouring.new
55
66
  [mock(Blanket, :size => 8), mock(Blanket, :size => 4)].each do |qu|
56
- qv.blankets mock(FSM), Set[0], Set[1], qu
67
+ qv.blankets @fsm, Set[0], Set[1], qu
57
68
  end
58
69
  log.should =~ rex('|Qu| = 8, Qv+G with GraphColouring')
59
70
  log.should =~ rex('|Qu| = 4, Qv+G with GraphColouring')
@@ -6,8 +6,8 @@ module ArtDecomp describe UVGenerator::Braindead do
6
6
  fsm = mock FSM, :input_count => 4
7
7
  fsm.stub!(:expand_x).and_return fsm
8
8
  archs = Set[Arch[3,1]]
9
- uv_gen = UVGenerator::Braindead.new fsm, archs
10
- uvs = uv_gen.uv_pairs.to_a
9
+ uv_gen = UVGenerator::Braindead.new
10
+ uvs = uv_gen.uv_pairs(fsm, archs).to_a
11
11
  uvs.size.should == 15
12
12
  uvs.first.should == [fsm, Set[0,1,2,3], Set[]]
13
13
  uvs[7].should == [fsm, Set[3], Set[0,1,2]]
@@ -19,8 +19,8 @@ module ArtDecomp describe UVGenerator::Braindead do
19
19
  fsm0, fsm1, fsm2, fsm3 = mock(FSM), mock(FSM), mock(FSM), mock(FSM)
20
20
  fsm.should_receive(:expand_x).exactly(4).times.and_return(fsm0, fsm1, fsm2, fsm3)
21
21
  archs = Set[Arch[3,1]]
22
- uv_gen = UVGenerator::Braindead.new fsm, archs
23
- uv_gen.uv_pairs.to_a.should == [
22
+ uv_gen = UVGenerator::Braindead.new
23
+ uv_gen.uv_pairs(fsm, archs).to_a.should == [
24
24
  [fsm0, Set[0,1], Set[]],
25
25
  [fsm1, Set[1], Set[0]],
26
26
  [fsm2, Set[0], Set[1]],
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
2
+
3
+ module ArtDecomp describe UVGenerator::GeneralRelevance do
4
+
5
+ it 'should call UVRelevanceGenerator’s uv_pairs method with proper args' do
6
+ fsm = mock FSM
7
+ fsm.should_receive(:general_relevance).and_return []
8
+ UVGenerator::GeneralRelevance.new.uv_pairs fsm, Set[Arch[5,1]]
9
+ end
10
+
11
+ end end
@@ -0,0 +1,11 @@
1
+ # encoding: UTF-8
2
+
3
+ module ArtDecomp describe UVGenerator::UniqueRelevance do
4
+
5
+ it 'should call UVRelevanceGenerator’s uv_pairs method with proper args' do
6
+ fsm = mock FSM
7
+ fsm.should_receive(:unique_relevance).and_return []
8
+ UVGenerator::UniqueRelevance.new.uv_pairs fsm, Set[Arch[5,1]]
9
+ end
10
+
11
+ end end
@@ -1,13 +1,13 @@
1
- module ArtDecomp describe UVGenerator::Relevance do
1
+ module ArtDecomp describe UVRelevanceGenerator do
2
2
 
3
3
  context 'given a certain FSM and a Set of Archs' do
4
4
 
5
5
  it 'should yield U and V combinations in a relevance-based order' do
6
- fsm = mock FSM, :input_count => 6, :input_relevance => [0, 1, 2, nil, nil, nil, 3, 4, 5]
6
+ fsm = mock FSM, :input_count => 6, :common_relevance => [0, 1, 2, nil, nil, nil, 3, 4, 5]
7
7
  fsm.stub!(:expand_x).and_return fsm
8
8
  archs = Set[Arch[3,1]]
9
- uv_gen = UVGenerator::Relevance.new fsm, archs
10
- uvs = uv_gen.uv_pairs.to_a
9
+ uv_gen = UVRelevanceGenerator.new
10
+ uvs = uv_gen.uv_pairs(fsm, archs, :common_relevance).to_a
11
11
  uvs.size.should == 42
12
12
  uvs[0].should == [fsm, Set[0,1,2], Set[3,4,5]]
13
13
  uvs[1].should == [fsm, Set[0,1,2,3], Set[4,5]]
@@ -22,11 +22,11 @@ module ArtDecomp describe UVGenerator::Relevance do
22
22
  end
23
23
 
24
24
  it 'should consider all architecture widths when generating the UV sets' do
25
- fsm = mock FSM, :input_count => 6, :input_relevance => [0, 1, 2, nil, nil, nil, 3, 4, 5]
25
+ fsm = mock FSM, :input_count => 6, :common_relevance => [0, 1, 2, nil, nil, nil, 3, 4, 5]
26
26
  fsm.stub!(:expand_x).and_return fsm
27
27
  archs = Set[Arch[3,1], Arch[2,1]]
28
- uv_gen = UVGenerator::Relevance.new fsm, archs
29
- uvs = uv_gen.uv_pairs.to_a
28
+ uv_gen = UVRelevanceGenerator.new
29
+ uvs = uv_gen.uv_pairs(fsm, archs, :common_relevance).to_a
30
30
  uvs.size.should == 42
31
31
  uvs[0].should == [fsm, Set[0,1,2,3], Set[4,5]]
32
32
  uvs[1].should == [fsm, Set[0,1,2,4], Set[3,5]]
@@ -43,12 +43,12 @@ module ArtDecomp describe UVGenerator::Relevance do
43
43
  end
44
44
 
45
45
  it 'should yield V-expanded FSMs' do
46
- fsm = mock FSM, :input_count => 2, :input_relevance => [1, 0, nil, nil, nil]
46
+ fsm = mock FSM, :input_count => 2, :common_relevance => [1, 0, nil, nil, nil]
47
47
  fsm0, fsm1, fsm2, fsm3 = mock(FSM), mock(FSM), mock(FSM), mock(FSM)
48
48
  fsm.should_receive(:expand_x).exactly(4).times.and_return(fsm0, fsm1, fsm2, fsm3)
49
49
  archs = Set[Arch[3,1]]
50
- uv_gen = UVGenerator::Relevance.new fsm, archs
51
- uv_gen.uv_pairs.to_a.should == [
50
+ uv_gen = UVRelevanceGenerator.new
51
+ uv_gen.uv_pairs(fsm, archs, :common_relevance).to_a.should == [
52
52
  [fsm0, Set[0,1], Set[]],
53
53
  [fsm1, Set[1], Set[0]],
54
54
  [fsm2, Set[0], Set[1]],
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: art-decomp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Szotkowski
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-05 00:00:00 +01:00
12
+ date: 2009-12-13 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -77,8 +77,7 @@ email: p.szotkowski@tele.pw.edu.pl
77
77
  executables:
78
78
  - ad-validate
79
79
  - ad-console
80
- - ad-analyse
81
- - ad-inputs
80
+ - ad-fsm-info
82
81
  - art-decomp
83
82
  extensions: []
84
83
 
@@ -90,9 +89,8 @@ files:
90
89
  - README
91
90
  - Rakefile
92
91
  - VERSION
93
- - bin/ad-analyse
94
92
  - bin/ad-console
95
- - bin/ad-inputs
93
+ - bin/ad-fsm-info
96
94
  - bin/ad-validate
97
95
  - bin/art-decomp
98
96
  - lib/art-decomp.rb
@@ -115,7 +113,9 @@ files:
115
113
  - lib/art-decomp/qv_generator/graph_merging.rb
116
114
  - lib/art-decomp/sep.rb
117
115
  - lib/art-decomp/uv_generator/braindead.rb
118
- - lib/art-decomp/uv_generator/relevance.rb
116
+ - lib/art-decomp/uv_generator/general_relevance.rb
117
+ - lib/art-decomp/uv_generator/unique_relevance.rb
118
+ - lib/art-decomp/uv_relevance_generator.rb
119
119
  - lib/core/enumerable.rb
120
120
  - lib/core/file.rb
121
121
  - lib/core/integer.rb
@@ -139,7 +139,9 @@ files:
139
139
  - spec/art-decomp/qv_generator/graph_merging_spec.rb
140
140
  - spec/art-decomp/sep_spec.rb
141
141
  - spec/art-decomp/uv_generator/braindead_spec.rb
142
- - spec/art-decomp/uv_generator/relevance_spec.rb
142
+ - spec/art-decomp/uv_generator/general_relevance_spec.rb
143
+ - spec/art-decomp/uv_generator/unique_relevance_spec.rb
144
+ - spec/art-decomp/uv_relevance_generator_spec.rb
143
145
  - spec/core/enumerable_spec.rb
144
146
  - spec/core/file_spec.rb
145
147
  - spec/core/integer_spec.rb
@@ -209,6 +211,7 @@ test_files:
209
211
  - spec/art-decomp/fsm_spec.rb
210
212
  - spec/art-decomp/sep_spec.rb
211
213
  - spec/art-decomp/bipainter_spec.rb
214
+ - spec/art-decomp/uv_relevance_generator_spec.rb
212
215
  - spec/art-decomp/blanket_spec.rb
213
216
  - spec/art-decomp/kiss_spec.rb
214
217
  - spec/art-decomp/qv_generator/graph_colouring_spec.rb
@@ -218,7 +221,8 @@ test_files:
218
221
  - spec/art-decomp/decomposer_spec.rb
219
222
  - spec/art-decomp/qu_generator/edge_labels_spec.rb
220
223
  - spec/art-decomp/qu_generator/block_table_spec.rb
221
- - spec/art-decomp/uv_generator/relevance_spec.rb
224
+ - spec/art-decomp/uv_generator/general_relevance_spec.rb
225
+ - spec/art-decomp/uv_generator/unique_relevance_spec.rb
222
226
  - spec/art-decomp/uv_generator/braindead_spec.rb
223
227
  - spec/art-decomp/decomposition_spec.rb
224
228
  - spec/art-decomp/b_spec.rb
data/bin/ad-analyse DELETED
@@ -1,30 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- require 'rubygems' if RUBY_VERSION < '1.9'
5
- require 'backports/1.9' if RUBY_VERSION < '1.9'
6
-
7
- require_relative '../lib/art-decomp'
8
-
9
- input_limit = ARGV.first.to_i.zero? ? 0 : ARGV.shift.to_i
10
-
11
- $stdout.sync = true
12
-
13
- ARGV.each do |fsm_file|
14
- fsm = ArtDecomp::FSM.from_kiss fsm_file
15
- seps = fsm.beta_f.seps
16
- input_seps = (0...fsm.input_count).map { |i| fsm.beta_x(Set[i]).seps & seps }
17
-
18
- puts
19
- puts fsm_file
20
- puts "X seps: #{input_seps.map(&:size).inspect}"
21
-
22
- input_seps.each_with_index { |a, i| puts "#{i} insignificant" if a.empty? }
23
-
24
- (0...input_seps.size).pairs.to_a.each do |a, b|
25
- next if input_seps[a].empty? or input_seps[b].empty?
26
- puts "#{a} ⊂ #{b}" if input_seps[a].proper_subset? input_seps[b]
27
- puts "#{a} = #{b}" if input_seps[a] == input_seps[b]
28
- puts "#{a} ⊃ #{b}" if input_seps[a].proper_superset? input_seps[b]
29
- end
30
- end
data/bin/ad-inputs DELETED
@@ -1,26 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- require 'rubygems' if RUBY_VERSION < '1.9'
5
- require 'backports/1.9' if RUBY_VERSION < '1.9'
6
-
7
- require_relative '../lib/art-decomp'
8
-
9
- input_limit = ARGV.first.to_i.zero? ? 0 : ARGV.shift.to_i
10
-
11
- $stdout.sync = true
12
-
13
- ARGV.each do |fsm_file|
14
- fsm = ArtDecomp::FSM.from_kiss fsm_file
15
- next if fsm.input_count < input_limit
16
- seps = fsm.beta_f.seps
17
- rel_q = (fsm.beta_q.seps & seps).size
18
- puts
19
- puts fsm_file
20
- puts "inputs: #{fsm.input_count}"
21
- puts "βf sep: #{seps.size}"
22
- puts "βq sep: #{rel_q}"
23
- puts "βq.pin: #{fsm.beta_q.pins}"
24
- puts "perpin: #{rel_q.to_f / fsm.beta_q.pins}"
25
- puts "X seps: #{(0...fsm.input_count).map { |i| (fsm.beta_x(Set[i]).seps & seps).size }.sort.reverse.inspect}"
26
- end
@@ -1,23 +0,0 @@
1
- module ArtDecomp class UVGenerator::Relevance
2
-
3
- def initialize fsm, archs
4
- @fsm = fsm
5
- @relevance = fsm.input_relevance.reverse
6
- @max_v_sizes = archs.map(&:pins).to_set
7
- end
8
-
9
- def uv_pairs
10
- @cache = Set[]
11
- Enumerator.new do |yielder|
12
- (0...2**@relevance.size).each do |vector|
13
- bits = vector.bits
14
- next unless @max_v_sizes.include? bits.size
15
- v = @relevance.values_at(*bits).compact.to_set
16
- u = (@relevance - v.to_a).compact.to_set
17
- yielder.yield @fsm.expand_x(v), u, v unless @cache.include? v
18
- @cache << v
19
- end
20
- end
21
- end
22
-
23
- end end