art-decomp 0.0.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/.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
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
|
5
|
+
Spec::Rake::SpecTask.new :cov do |t|
|
6
|
+
t.rcov = true
|
7
|
+
t.rcov_opts = ['--exclude', 'spec']
|
8
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
9
|
+
end
|
10
|
+
|
11
|
+
Spec::Rake::SpecTask.new :spec do |t|
|
12
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
13
|
+
end
|
14
|
+
|
15
|
+
namespace :spec do
|
16
|
+
FileList['spec/**/*_spec.rb'].each do |file|
|
17
|
+
spec = file.split('/').last[0...-8]
|
18
|
+
desc "Run the #{spec} spec"
|
19
|
+
Spec::Rake::SpecTask.new spec do |t|
|
20
|
+
t.spec_files = [file]
|
21
|
+
t.spec_opts = ['--options', 'spec/spec.opts']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'jeweler'
|
27
|
+
|
28
|
+
Jeweler::Tasks.new do |gem|
|
29
|
+
gem.authors = ['Piotr Szotkowski']
|
30
|
+
gem.email = 'p.szotkowski@tele.pw.edu.pl'
|
31
|
+
gem.homepage = 'http://github.com/chastell/art-decomp'
|
32
|
+
gem.name = 'art-decomp'
|
33
|
+
gem.summary = 'art décomp: an FSM → FPGA decomposer'
|
34
|
+
|
35
|
+
gem.files.exclude 'kiss/**/*'
|
36
|
+
|
37
|
+
gem.add_dependency 'teejayvanslyke-gazer'
|
38
|
+
gem.add_dependency 'trollop'
|
39
|
+
|
40
|
+
gem.add_development_dependency 'diff-lcs'
|
41
|
+
gem.add_development_dependency 'jeweler'
|
42
|
+
gem.add_development_dependency 'rcov'
|
43
|
+
gem.add_development_dependency 'rspec'
|
44
|
+
end
|
45
|
+
|
46
|
+
Jeweler::GemcutterTasks.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/bin/ad-compare
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require_relative '../lib/art-decomp'
|
5
|
+
|
6
|
+
input_limit = ARGV.first.to_i.zero? ? 0 : ARGV.shift.to_i
|
7
|
+
|
8
|
+
ARGV.each do |fsm_file|
|
9
|
+
fsm = ArtDecomp::FSM.from_kiss fsm_file
|
10
|
+
seps = fsm.beta_f.seps
|
11
|
+
input_seps = (0...fsm.input_count).map { |i| fsm.beta_x(Set[i]).seps & seps }
|
12
|
+
|
13
|
+
puts
|
14
|
+
puts fsm_file
|
15
|
+
puts "X seps: #{input_seps.map(&:size).inspect}"
|
16
|
+
|
17
|
+
(0...input_seps.size).pairs.to_a.each do |a, b|
|
18
|
+
puts "#{a} ⊂ #{b}" if input_seps[a].proper_subset? input_seps[b]
|
19
|
+
puts "#{a} = #{b}" if input_seps[a] == input_seps[b]
|
20
|
+
puts "#{a} ⊃ #{b}" if input_seps[a].proper_superset? input_seps[b]
|
21
|
+
end
|
22
|
+
end
|
data/bin/ad-console
ADDED
data/bin/ad-inputs
ADDED
@@ -0,0 +1,24 @@
|
|
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
|
+
ARGV.each do |fsm_file|
|
12
|
+
fsm = ArtDecomp::FSM.from_kiss fsm_file
|
13
|
+
next if fsm.input_count < input_limit
|
14
|
+
seps = fsm.beta_f.seps
|
15
|
+
rel_q = (fsm.beta_q.seps & seps).size
|
16
|
+
puts
|
17
|
+
puts fsm_file
|
18
|
+
puts "inputs: #{fsm.input_count}"
|
19
|
+
puts "βf sep: #{seps.size}"
|
20
|
+
puts "βq sep: #{rel_q}"
|
21
|
+
puts "βq.pin: #{fsm.beta_q.pins}"
|
22
|
+
puts "perpin: #{rel_q.to_f / fsm.beta_q.pins}"
|
23
|
+
puts "X seps: #{(0...fsm.input_count).map { |i| (fsm.beta_x(Set[i]).seps & seps).size }.sort.reverse.inspect}"
|
24
|
+
end
|
data/bin/ad-validate
ADDED
data/bin/art-decomp
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module ArtDecomp class Arch
|
2
|
+
|
3
|
+
attr_reader :pins, :pons
|
4
|
+
|
5
|
+
def self.[] pins, pons
|
6
|
+
new pins, pons
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize pins, pons
|
10
|
+
@pins, @pons = pins, pons
|
11
|
+
end
|
12
|
+
|
13
|
+
def == other
|
14
|
+
[@pins, @pons] == [other.pins, other.pons]
|
15
|
+
end
|
16
|
+
|
17
|
+
def cells archs
|
18
|
+
pons = archs.select { |a| a.pins >= @pins }.map(&:pons).max
|
19
|
+
(@pons % pons).zero? ? @pons / pons : @pons / pons + 1 rescue nil
|
20
|
+
end
|
21
|
+
|
22
|
+
alias eql? ==
|
23
|
+
|
24
|
+
def hash
|
25
|
+
@pins.hash ^ @pons.hash
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"#{pins}/#{pons}"
|
30
|
+
end
|
31
|
+
|
32
|
+
end end
|
data/lib/art-decomp/b.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
module ArtDecomp class Bipainter
|
2
|
+
|
3
|
+
def initialize beta_q, beta_v, seps
|
4
|
+
raise 'non-disjoint beta_v' if beta_v.ints.pairs.any? { |a, b| a & b != 0 }
|
5
|
+
@beta_v = beta_v
|
6
|
+
@qv_colours = {}
|
7
|
+
@g_colours = {}
|
8
|
+
@qv_forbidden = Hash.new { |h, k| h[k] = Set[] }
|
9
|
+
@g_forbidden = Hash.new { |h, k| h[k] = Set[] }
|
10
|
+
@qv_graph = Graph.new beta_q, seps - beta_v.seps
|
11
|
+
@g_graph = Graph.new beta_q * beta_v, seps
|
12
|
+
end
|
13
|
+
|
14
|
+
def blankets
|
15
|
+
colour_next_vertex! until painted?
|
16
|
+
qv_blocks = Hash.new 0
|
17
|
+
g_blocks = Hash.new 0
|
18
|
+
@qv_colours.each { |vertex, colour| qv_blocks[colour] |= vertex }
|
19
|
+
@g_colours.each { |vertex, colour| g_blocks[colour] |= vertex }
|
20
|
+
[Blanket.new(qv_blocks.values), Blanket.new(g_blocks.values)]
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def backup!
|
26
|
+
@g_forbidden.default = nil
|
27
|
+
@qv_forbidden.default = nil
|
28
|
+
@backup = {
|
29
|
+
:g_colours => Marshal.dump(@g_colours),
|
30
|
+
:g_forbidden => Marshal.dump(@g_forbidden),
|
31
|
+
:qv_colours => Marshal.dump(@qv_colours),
|
32
|
+
:qv_forbidden => Marshal.dump(@qv_forbidden),
|
33
|
+
}
|
34
|
+
@g_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
|
35
|
+
@qv_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
|
36
|
+
end
|
37
|
+
|
38
|
+
def restore!
|
39
|
+
@g_colours = Marshal.load @backup[:g_colours]
|
40
|
+
@g_forbidden = Marshal.load @backup[:g_forbidden]
|
41
|
+
@qv_colours = Marshal.load @backup[:qv_colours]
|
42
|
+
@qv_forbidden = Marshal.load @backup[:qv_forbidden]
|
43
|
+
@g_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
|
44
|
+
@qv_forbidden.default_proc = proc { |h, k| h[k] = Set[] }
|
45
|
+
end
|
46
|
+
|
47
|
+
def colour_g_vertex! g_vertex
|
48
|
+
begin
|
49
|
+
backup!
|
50
|
+
colour = :a
|
51
|
+
colour = colour.next while @g_forbidden[g_vertex].include? colour
|
52
|
+
colour_g! g_vertex, colour
|
53
|
+
rescue PaintingError
|
54
|
+
restore!
|
55
|
+
forbid_g! g_vertex, colour
|
56
|
+
retry
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def colour_next_vertex!
|
61
|
+
# FIXME: consider colouring G graph’s vertex first
|
62
|
+
# FIXME: consider other vertex selection algorithms
|
63
|
+
qv_vertex = (@qv_graph.vertices - @qv_colours.keys).sort_by { |v| [-@qv_forbidden[v].size, -@qv_graph.degree(v)] }.first
|
64
|
+
colour_qv_vertex! qv_vertex if qv_vertex
|
65
|
+
g_vertex = (@g_graph.vertices - @g_colours.keys).sort_by { |v| [-@g_forbidden[v].size, -@g_graph.degree(v)] }.first
|
66
|
+
colour_g_vertex! g_vertex if g_vertex
|
67
|
+
end
|
68
|
+
|
69
|
+
def colour_qv_vertex! qv_vertex
|
70
|
+
begin
|
71
|
+
backup!
|
72
|
+
colour = :a
|
73
|
+
colour = colour.next while @qv_forbidden[qv_vertex].include? colour
|
74
|
+
colour_qv! qv_vertex, colour
|
75
|
+
rescue PaintingError
|
76
|
+
restore!
|
77
|
+
forbid_qv! qv_vertex, colour
|
78
|
+
retry
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def forbid_g! g_vertex, colour
|
83
|
+
return if @g_forbidden[g_vertex].include? colour
|
84
|
+
raise PaintingError if colour == @g_colours[g_vertex]
|
85
|
+
@g_forbidden[g_vertex] << colour
|
86
|
+
siblings_of(g_vertex).each { |sibling| forbid_g! sibling, colour }
|
87
|
+
end
|
88
|
+
|
89
|
+
def forbid_qv! qv_vertex, colour
|
90
|
+
return if @qv_forbidden[qv_vertex].include? colour
|
91
|
+
raise PaintingError if colour == @qv_colours[qv_vertex]
|
92
|
+
@qv_forbidden[qv_vertex] << colour
|
93
|
+
end
|
94
|
+
|
95
|
+
def colour_g! g_vertex, colour
|
96
|
+
return if @g_colours[g_vertex] == colour
|
97
|
+
raise PaintingError if @g_colours[g_vertex] and @g_colours[g_vertex] != colour
|
98
|
+
raise PaintingError if @g_forbidden[g_vertex].include? colour
|
99
|
+
@g_colours[g_vertex] = colour
|
100
|
+
@g_graph.adjacent(g_vertex).each { |adjacent| forbid_g! adjacent, colour }
|
101
|
+
siblings_of(g_vertex).each { |sibling| colour_g! sibling, colour }
|
102
|
+
end
|
103
|
+
|
104
|
+
def colour_qv! qv_vertex, colour
|
105
|
+
return if @qv_colours[qv_vertex] == colour
|
106
|
+
raise PaintingError if @qv_colours[qv_vertex] and @qv_colours[qv_vertex] != colour
|
107
|
+
raise PaintingError if @qv_forbidden[qv_vertex].include? colour
|
108
|
+
@qv_colours[qv_vertex] = colour
|
109
|
+
@qv_graph.adjacent(qv_vertex).each { |adjacent| forbid_qv! adjacent, colour }
|
110
|
+
if @qv_colours.any? { |q, col| q != qv_vertex and col == colour }
|
111
|
+
@g_graph.vertices.select { |g| g & qv_vertex == g }.each do |g_vertex|
|
112
|
+
v_parent = @beta_v.ints.find { |v| v & g_vertex == g_vertex }
|
113
|
+
@g_graph.adjacent(g_vertex).select { |g| v_parent & g == g and qv_vertex & g != g }.each do |neighbour|
|
114
|
+
@qv_graph.vertices.select { |q| q & neighbour == neighbour }.each do |q_parent|
|
115
|
+
forbid_qv! q_parent, colour
|
116
|
+
end
|
117
|
+
end
|
118
|
+
siblings_of(g_vertex).each { |sibling| sync_colours g_vertex, sibling }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def siblings_of g_vertex
|
124
|
+
v_parent = @beta_v.ints.find { |v| v & g_vertex == g_vertex }
|
125
|
+
colours = @qv_colours.select { |q, col| g_vertex & q == g_vertex }.values
|
126
|
+
similar = @qv_colours.select { |q, col| colours.include? col }.keys
|
127
|
+
(similar.map { |q| q & v_parent }.to_set & @g_graph.vertices).delete g_vertex
|
128
|
+
end
|
129
|
+
|
130
|
+
def sync_colours v1, v2
|
131
|
+
(@g_forbidden[v1] - @g_forbidden[v2]).each { |col| forbid_g! v2, col }
|
132
|
+
(@g_forbidden[v2] - @g_forbidden[v1]).each { |col| forbid_g! v1, col }
|
133
|
+
if @g_colours[v1] then colour_g! v2, @g_colours[v1]
|
134
|
+
elsif @g_colours[v2] then colour_g! v1, @g_colours[v2]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def painted?
|
139
|
+
@qv_graph.vertices == @qv_colours.keys.to_set and @g_graph.vertices == @g_colours.keys.to_set
|
140
|
+
end
|
141
|
+
|
142
|
+
end end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module ArtDecomp class Blanket
|
2
|
+
|
3
|
+
attr_reader :ints
|
4
|
+
|
5
|
+
def self.[] *ints
|
6
|
+
new ints
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.from_array array
|
10
|
+
ints = Hash.new 0
|
11
|
+
array.each_with_index do |enc, i|
|
12
|
+
ints[enc] |= 1 << i
|
13
|
+
end
|
14
|
+
ints.each_key do |key|
|
15
|
+
ints[key] |= ints[DontCare]
|
16
|
+
end unless ints[DontCare].zero?
|
17
|
+
ints.delete DontCare unless ints.size <= 1
|
18
|
+
new ints.values
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize ints
|
22
|
+
@ints = ints.to_set.delete(0).freeze
|
23
|
+
end
|
24
|
+
|
25
|
+
def * other
|
26
|
+
ints = []
|
27
|
+
@ints.each do |this_int|
|
28
|
+
other.ints.each do |other_int|
|
29
|
+
ints << (this_int & other_int)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
Blanket.new ints
|
33
|
+
end
|
34
|
+
|
35
|
+
def == other
|
36
|
+
@ints == other.ints
|
37
|
+
end
|
38
|
+
|
39
|
+
def encoding bits
|
40
|
+
encs = encodings bits
|
41
|
+
encs.size == 1 ? encs.first : raise(AmbiguousEncodingQuery, "ambiguous encoding query: block #{bits.bits.join ','}")
|
42
|
+
end
|
43
|
+
|
44
|
+
def encodings bits
|
45
|
+
sorted = @ints.sort
|
46
|
+
width = sorted.size.log2_ceil
|
47
|
+
encs = @ints.select { |int| int & bits == bits }.map { |int| sorted.index(int) }.map { |i| i.to_s(2).rjust width, '0' }
|
48
|
+
encs.size == 0 or encs.size == @ints.size ? [DontCare.to_s * width] : encs
|
49
|
+
end
|
50
|
+
|
51
|
+
alias eql? ==
|
52
|
+
|
53
|
+
def hash
|
54
|
+
@ints.hash
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
blocks = @ints.map(&:bits).sort.map { |bl| "B[#{bl.join ','}]" }
|
59
|
+
"Blanket[#{blocks.join ', '}]"
|
60
|
+
end
|
61
|
+
|
62
|
+
def pins
|
63
|
+
@ints.size.log2_ceil
|
64
|
+
end
|
65
|
+
|
66
|
+
def seps
|
67
|
+
# FIXME: consider an algorithm with lesser complexity
|
68
|
+
seps = Set[]
|
69
|
+
singles = 0
|
70
|
+
@ints.pairs.each { |int1, int2| singles |= int1 ^ int2 }
|
71
|
+
singles.bits.pairs.each do |elem1, elem2|
|
72
|
+
sep = Sep[elem1, elem2]
|
73
|
+
seps << sep unless @ints.any? { |int| int & sep == sep }
|
74
|
+
end
|
75
|
+
seps
|
76
|
+
end
|
77
|
+
|
78
|
+
def size
|
79
|
+
@ints.size
|
80
|
+
end
|
81
|
+
|
82
|
+
end end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module ArtDecomp class Decomposer
|
2
|
+
|
3
|
+
def initialize params
|
4
|
+
@archs = params[:archs]
|
5
|
+
@uv_gens = params[:uv_gens].map { |gen| gen.new params[:fsm], params[:archs] }
|
6
|
+
@qu_gens = params[:qu_gens].map &:new
|
7
|
+
@qv_gens = params[:qv_gens].map &:new
|
8
|
+
end
|
9
|
+
|
10
|
+
def decompositions opts = {}
|
11
|
+
@seen = Set[]
|
12
|
+
Enumerator.new do |yielder|
|
13
|
+
@uv_gens.each do |uv_gen|
|
14
|
+
uv_gen.uv_pairs.each do |fsm, u, v|
|
15
|
+
unless @seen.include? [fsm, u, v]
|
16
|
+
@qu_gens.each do |qu_gen|
|
17
|
+
qu_gen.blankets(fsm, u, v).each do |qu|
|
18
|
+
unless @seen.include? [fsm, u, v, qu]
|
19
|
+
@qv_gens.each do |qv_gen|
|
20
|
+
qv_gen.blankets(fsm, u, v, qu).each do |qv, g|
|
21
|
+
unless @seen.include? [fsm, u, v, qu, qv, g]
|
22
|
+
dec = Decomposition.new fsm, u, v, qu, qv, g
|
23
|
+
if dec.sensible? @archs
|
24
|
+
if opts[:non_disjoint]
|
25
|
+
non_disjoint(fsm, u, v, qu, qv, g, opts).each do |ndj|
|
26
|
+
yielder.yield ndj
|
27
|
+
end
|
28
|
+
end
|
29
|
+
yielder.yield dec
|
30
|
+
end
|
31
|
+
@seen << [fsm, u, v, qu, qv, g] unless opts[:keep_seen]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
@seen << [fsm, u, v, qu] unless opts[:keep_seen]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@seen << [fsm, u, v] unless opts[:keep_seen]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def non_disjoint fsm, u_dj, v, qu, qv_dj, g_dj, opts
|
49
|
+
Enumerator.new do |yielder|
|
50
|
+
(v - u_dj).each do |v_input|
|
51
|
+
u = u_dj + [v_input]
|
52
|
+
unless @seen.include? [fsm, u, v, qu]
|
53
|
+
@qv_gens.each do |qv_gen|
|
54
|
+
qv_gen.blankets(fsm, u, v, qu).each do |qv, g|
|
55
|
+
unless @seen.include? [fsm, u, v, qu, qv, g]
|
56
|
+
dec = Decomposition.new fsm, u, v, qu, qv, g
|
57
|
+
if dec.sensible? @archs and g.pins < g_dj.pins
|
58
|
+
if opts[:deep_ndj]
|
59
|
+
non_disjoint(fsm, u, v, qu, qv, g, opts).each do |ndj|
|
60
|
+
yielder.yield ndj
|
61
|
+
end
|
62
|
+
end
|
63
|
+
yielder.yield dec
|
64
|
+
end
|
65
|
+
@seen << [fsm, u, v, qu, qv, g] unless opts[:keep_seen]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
@seen << [fsm, u, v, qu] unless opts[:keep_seen]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module ArtDecomp class Decomposition
|
2
|
+
|
3
|
+
def initialize fsm, u, v, qu, qv, g, opts = {}
|
4
|
+
@fsm, @u, @v, @qu, @qv, @g = fsm, u, v, qu, qv, g
|
5
|
+
end
|
6
|
+
|
7
|
+
def == other
|
8
|
+
[@fsm, @u, @v, @qu, @qv, @g] == [other.fsm, other.u, other.v, other.qu, other.qv, other.g]
|
9
|
+
end
|
10
|
+
|
11
|
+
def decomposable?
|
12
|
+
@qu.size > 2
|
13
|
+
end
|
14
|
+
|
15
|
+
def disjoint?
|
16
|
+
(@u & @v).empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
alias eql? ==
|
20
|
+
|
21
|
+
def f_kiss
|
22
|
+
@fsm.to_kiss
|
23
|
+
end
|
24
|
+
|
25
|
+
def final? archs
|
26
|
+
pins = archs.map(&:pins).max
|
27
|
+
@v.size + @qv.pins <= pins and @u.size + @qu.pins + @g.pins <= pins
|
28
|
+
end
|
29
|
+
|
30
|
+
def g_cells archs
|
31
|
+
Arch[@v.size + @qv.pins, @g.pins].cells archs
|
32
|
+
end
|
33
|
+
|
34
|
+
def g_kiss
|
35
|
+
lines = (@fsm.beta_x(@v) * @qv).ints.map do |row|
|
36
|
+
v = @fsm.x_encoding @v, row
|
37
|
+
qv = @qv.encoding row
|
38
|
+
g = @g.encoding row
|
39
|
+
"#{v}#{qv} #{g}"
|
40
|
+
end
|
41
|
+
KISS.new(lines).formatted
|
42
|
+
end
|
43
|
+
|
44
|
+
def h_cells archs
|
45
|
+
Arch[@u.size + @qu.pins + @g.pins, @fsm.output_count + @qu.pins + @qv.pins].cells archs
|
46
|
+
end
|
47
|
+
|
48
|
+
def h_kiss
|
49
|
+
lines = (@fsm.beta_x(@u) * @g * @qu).ints.map do |row|
|
50
|
+
u = @fsm.x_encoding @u, row
|
51
|
+
qu = @qu.encoding row
|
52
|
+
qup = @qu.encoding @fsm.state_rows_of_next_state_of(row)
|
53
|
+
qvp = @qv.encoding @fsm.state_rows_of_next_state_of(row)
|
54
|
+
y = @fsm.y_encoding row
|
55
|
+
qu = '*' if qu =~ /^-+$/
|
56
|
+
qup = '*' if qup =~ /^-+$/
|
57
|
+
# FIXME: use only the encoding(s) really mapped from this row
|
58
|
+
@g.encodings(row).map do |g|
|
59
|
+
"#{u}#{g} #{qu} #{qup} #{qvp}#{y}"
|
60
|
+
end
|
61
|
+
end.flatten
|
62
|
+
KISS.new(lines).formatted
|
63
|
+
end
|
64
|
+
|
65
|
+
def hash
|
66
|
+
@fsm.hash ^ @u.hash ^ @v.hash ^ @qu.hash ^ @qv.hash ^ @g.hash
|
67
|
+
end
|
68
|
+
|
69
|
+
def q_kiss
|
70
|
+
lines = @fsm.beta_q.ints.map do |row|
|
71
|
+
qu = @qu.encoding row
|
72
|
+
qv = @qv.encoding row
|
73
|
+
q = @fsm.q_encoding row
|
74
|
+
"#{qu} #{qv} #{q}"
|
75
|
+
end
|
76
|
+
KISS.new(lines).formatted
|
77
|
+
end
|
78
|
+
|
79
|
+
def sensible? archs
|
80
|
+
@v.size + @qv.pins <= archs.map(&:pins).max and @u.size + @qu.pins + @g.pins < @fsm.input_count + @fsm.beta_q.pins
|
81
|
+
end
|
82
|
+
|
83
|
+
def valid?
|
84
|
+
@g.seps.subset?((@fsm.beta_x(@v) * @qv).seps) and @fsm.beta_f.seps.subset?((@fsm.beta_x(@u) * @qu * @g).seps)
|
85
|
+
end
|
86
|
+
|
87
|
+
protected
|
88
|
+
|
89
|
+
attr_reader :fsm, :u, :v, :qu, :qv, :g
|
90
|
+
|
91
|
+
end end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
|
3
|
+
module ArtDecomp class Executable
|
4
|
+
|
5
|
+
attr_reader :archs, :best, :iters, :dir
|
6
|
+
|
7
|
+
def initialize args = ARGV
|
8
|
+
opts = Trollop.options(args) do
|
9
|
+
opt :archs, 'Target architecture(s)', :type => :strings
|
10
|
+
opt :outdir, 'Output directory', :type => :string
|
11
|
+
opt :iters, 'Number of iterations, 0 for infinite', :default => 1
|
12
|
+
opt :uv, 'UV generator(s)', :default => ['Relevance']
|
13
|
+
opt :qu, 'Qu generator(s)', :default => ['EdgeLabels']
|
14
|
+
opt :qv, 'Qv generator(s)', :default => ['GraphColouring']
|
15
|
+
opt :non_disjoint, 'Compute non-disjoint decompositions', :default => false
|
16
|
+
opt :deep_ndj, 'Compute deep non-dj decompositions', :default => false
|
17
|
+
opt :log, 'Logging target', :type => :string
|
18
|
+
opt :debug, 'Log debug-level activities', :default => false
|
19
|
+
end
|
20
|
+
|
21
|
+
opts[:uv] = UVGenerator.constants.map(&:to_s).sort if opts[:uv] == ['all']
|
22
|
+
opts[:qu] = QuGenerator.constants.map(&:to_s).sort if opts[:qu] == ['all']
|
23
|
+
opts[:qv] = QvGenerator.constants.map(&:to_s).sort if opts[:qv] == ['all']
|
24
|
+
|
25
|
+
Trollop.die 'no FSM given' if args.empty?
|
26
|
+
Trollop.die 'FSM does not exist' unless File.exists? args.first
|
27
|
+
Trollop.die 'no architecture given' unless opts[:archs_given]
|
28
|
+
Trollop.die 'no output directory given' unless opts[:outdir_given]
|
29
|
+
Trollop.die :archs, 'not in the form of inputs/outputs' unless opts[:archs].all? { |s| s =~ /^\d+\/\d+$/ }
|
30
|
+
Trollop.die :outdir, 'output directory exists' if File.exists? opts[:outdir]
|
31
|
+
Trollop.die :uv, 'no such UV generator' unless (opts[:uv] - UVGenerator.constants.map(&:to_s)).empty?
|
32
|
+
Trollop.die :qu, 'no such Qu generator' unless (opts[:qu] - QuGenerator.constants.map(&:to_s)).empty?
|
33
|
+
Trollop.die :qv, 'no such Qv generator' unless (opts[:qv] - QvGenerator.constants.map(&:to_s)).empty?
|
34
|
+
|
35
|
+
Dir.mkdir opts[:outdir] rescue Trollop.die :outdir, 'output directory cannot be created'
|
36
|
+
|
37
|
+
@dir = opts[:outdir]
|
38
|
+
@fsm = FSM.from_kiss args.first
|
39
|
+
@archs = opts[:archs].map { |s| Arch[*s.split('/').map(&:to_i)] }.to_set
|
40
|
+
@iters = opts[:iters]
|
41
|
+
@non_disjoint = opts[:non_disjoint]
|
42
|
+
@deep_ndj = opts[:deep_ndj]
|
43
|
+
|
44
|
+
@uv_gens = opts[:uv].map { |gen| eval "UVGenerator::#{gen}" }
|
45
|
+
@qu_gens = opts[:qu].map { |gen| eval "QuGenerator::#{gen}" }
|
46
|
+
@qv_gens = opts[:qv].map { |gen| eval "QvGenerator::#{gen}" }
|
47
|
+
|
48
|
+
if opts[:log_given]
|
49
|
+
require_relative 'logging'
|
50
|
+
Logging.log = opts[:log] == '-' ? $stdout : opts[:log]
|
51
|
+
Logging.level = Logger::DEBUG if opts[:debug]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def gens
|
56
|
+
[@uv_gens, @qu_gens, @qv_gens].map do |gens|
|
57
|
+
gens.map { |gen| gen.to_s.split('::').last }.join '+'
|
58
|
+
end.join ', '
|
59
|
+
end
|
60
|
+
|
61
|
+
def run dump_decs = true
|
62
|
+
@best = @fsm.fsm_cells @archs
|
63
|
+
dumps = Hash.new { |h, k| h[k] = [] }
|
64
|
+
decompositions(@fsm, @iters, @dir, 0).each do |dec, dir, i|
|
65
|
+
dumps[dir] << dec
|
66
|
+
File.dump_object dec, "#{dir}/#{i}.dec" if dump_decs
|
67
|
+
end unless @fsm.implementable_in? @archs
|
68
|
+
dumps.each do |dir, decs|
|
69
|
+
File.dump_object decs, "#{dir}/decompositions"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def decompositions fsm, iters, dir, cells
|
76
|
+
decomposer = Decomposer.new :fsm => fsm, :archs => @archs, :uv_gens => @uv_gens, :qu_gens => @qu_gens, :qv_gens => @qv_gens
|
77
|
+
Enumerator.new do |yielder|
|
78
|
+
decomposer.decompositions(:non_disjoint => @non_disjoint, :deep_ndj => @deep_ndj).with_index do |dec, i|
|
79
|
+
yielder.yield dec, dir, i
|
80
|
+
if dec.final? @archs
|
81
|
+
this = cells + dec.g_cells(@archs) + dec.h_cells(@archs)
|
82
|
+
@best = this if @best.nil? or this < @best
|
83
|
+
elsif iters != 1 and dec.decomposable? and (@best.nil? or cells < @best)
|
84
|
+
in_dir = "#{dir}/#{i}"
|
85
|
+
Dir.mkdir in_dir
|
86
|
+
decompositions(FSM.from_kiss(dec.h_kiss), iters - 1, in_dir, cells + dec.g_cells(@archs)).each do |in_dec, in_dir, in_i|
|
87
|
+
yielder.yield in_dec, in_dir, in_i
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end end
|