art-decomp 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/LICENCE +661 -0
- data/README +9 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/bin/ad-compare +22 -0
- data/bin/ad-console +11 -0
- data/bin/ad-inputs +24 -0
- data/bin/ad-validate +9 -0
- data/bin/art-decomp +8 -0
- data/lib/art-decomp/arch.rb +32 -0
- data/lib/art-decomp/b.rb +7 -0
- data/lib/art-decomp/bipainter.rb +142 -0
- data/lib/art-decomp/blanket.rb +82 -0
- data/lib/art-decomp/decomposer.rb +75 -0
- data/lib/art-decomp/decomposition.rb +91 -0
- data/lib/art-decomp/exceptions.rb +9 -0
- data/lib/art-decomp/executable.rb +94 -0
- data/lib/art-decomp/fsm.rb +128 -0
- data/lib/art-decomp/graph.rb +78 -0
- data/lib/art-decomp/kiss.rb +47 -0
- data/lib/art-decomp/logging.rb +52 -0
- data/lib/art-decomp/qu_generator/block_table.rb +42 -0
- data/lib/art-decomp/qu_generator/edge_labels.rb +24 -0
- data/lib/art-decomp/qv_generator/bipainting.rb +12 -0
- data/lib/art-decomp/qv_generator/graph_colouring.rb +16 -0
- data/lib/art-decomp/qv_generator/graph_merging.rb +19 -0
- data/lib/art-decomp/sep.rb +7 -0
- data/lib/art-decomp/uv_generator/braindead.rb +22 -0
- data/lib/art-decomp/uv_generator/relevance.rb +23 -0
- data/lib/art-decomp.rb +65 -0
- data/lib/core/enumerable.rb +24 -0
- data/lib/core/file.rb +11 -0
- data/lib/core/integer.rb +13 -0
- data/lib/core/set.rb +16 -0
- data/lib/core/string.rb +13 -0
- data/spec/art-decomp/arch_spec.rb +23 -0
- data/spec/art-decomp/b_spec.rb +27 -0
- data/spec/art-decomp/bipainter_spec.rb +22 -0
- data/spec/art-decomp/blanket_spec.rb +77 -0
- data/spec/art-decomp/decomposer_spec.rb +106 -0
- data/spec/art-decomp/decomposition_spec.rb +119 -0
- data/spec/art-decomp/executable_spec.rb +161 -0
- data/spec/art-decomp/fsm_spec.rb +146 -0
- data/spec/art-decomp/graph_spec.rb +69 -0
- data/spec/art-decomp/kiss_spec.rb +30 -0
- data/spec/art-decomp/logging_spec.rb +62 -0
- data/spec/art-decomp/qu_generator/block_table_spec.rb +37 -0
- data/spec/art-decomp/qu_generator/edge_labels_spec.rb +35 -0
- data/spec/art-decomp/qv_generator/bipainting_spec.rb +28 -0
- data/spec/art-decomp/qv_generator/graph_colouring_spec.rb +31 -0
- data/spec/art-decomp/qv_generator/graph_merging_spec.rb +30 -0
- data/spec/art-decomp/sep_spec.rb +13 -0
- data/spec/art-decomp/uv_generator/braindead_spec.rb +33 -0
- data/spec/art-decomp/uv_generator/relevance_spec.rb +61 -0
- data/spec/core/enumerable_spec.rb +20 -0
- data/spec/core/file_spec.rb +15 -0
- data/spec/core/integer_spec.rb +16 -0
- data/spec/core/set_spec.rb +26 -0
- data/spec/core/string_spec.rb +17 -0
- data/spec/fixtures/ex5 +36 -0
- data/spec/fixtures/fsm +24 -0
- data/spec/fixtures/fsm.exp +40 -0
- data/spec/fixtures/fsm.f +20 -0
- data/spec/fixtures/fsm.g +4 -0
- data/spec/fixtures/fsm.h +19 -0
- data/spec/fixtures/fsm.partially-exp +31 -0
- data/spec/fixtures/fsm.q +10 -0
- data/spec/fixtures/lion +15 -0
- data/spec/fixtures/lion.exp +15 -0
- data/spec/fixtures/lion.h +10 -0
- data/spec/fixtures/lion.to_kiss +11 -0
- data/spec/fixtures/mark1 +26 -0
- data/spec/fixtures/mc +14 -0
- data/spec/fixtures/mc.to_kiss +10 -0
- data/spec/fixtures/opus +26 -0
- data/spec/fixtures/opus.amb.h +22 -0
- data/spec/fixtures/opus.h +21 -0
- data/spec/fixtures/opus.to_kiss +22 -0
- data/spec/fixtures/s420 +142 -0
- data/spec/fixtures/s8 +24 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +8 -0
- metadata +224 -0
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
|