art-decomp 0.1.0 → 0.2.0

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/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