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
@@ -0,0 +1,128 @@
|
|
1
|
+
module ArtDecomp class FSM
|
2
|
+
|
3
|
+
def self.from_kiss kiss
|
4
|
+
kiss = File.read kiss unless kiss.index "\n"
|
5
|
+
inputs, outputs, state, next_state = [], [], [], []
|
6
|
+
kiss.lines do |line|
|
7
|
+
next unless line =~ /^\s*[01-]+\s+\S+\s+\S+\s+[01-]+\s*$/
|
8
|
+
ins, st, nxt, outs = line.split
|
9
|
+
inputs << ins.split(//).map(&:to_sym)
|
10
|
+
outputs << outs.split(//).map(&:to_sym)
|
11
|
+
state << (st == '*' ? DontCare : st.to_sym)
|
12
|
+
next_state << (nxt == '*' ? DontCare : nxt.to_sym)
|
13
|
+
end
|
14
|
+
# FIXME: the below hack makes state have all possible values by expanding a don’t-care a bit (if present)
|
15
|
+
(next_state - state - [DontCare]).each do |missing_state|
|
16
|
+
i = state.index DontCare
|
17
|
+
state << missing_state
|
18
|
+
next_state << next_state[i]
|
19
|
+
inputs << inputs[i]
|
20
|
+
outputs << outputs[i]
|
21
|
+
end if state.index DontCare
|
22
|
+
new inputs.transpose, outputs.transpose, state, next_state
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize inputs, outputs, state, next_state
|
26
|
+
@inputs, @outputs, @state, @next_state = inputs.freeze, outputs.freeze, state.freeze, next_state.freeze
|
27
|
+
end
|
28
|
+
|
29
|
+
def == other
|
30
|
+
[@inputs, @outputs, @state, @next_state] == [other.inputs, other.outputs, other.state, other.next_state]
|
31
|
+
end
|
32
|
+
|
33
|
+
def beta_f
|
34
|
+
outs = @outputs.map { |output| Blanket.from_array output }
|
35
|
+
outs.inject(:*) * Blanket.from_array(@next_state)
|
36
|
+
end
|
37
|
+
|
38
|
+
def beta_q
|
39
|
+
Blanket.from_array @state
|
40
|
+
end
|
41
|
+
|
42
|
+
def beta_x ins
|
43
|
+
return Blanket[B[*0...@state.size]] if ins.empty?
|
44
|
+
ins.map { |i| Blanket.from_array @inputs[i] }.inject :*
|
45
|
+
end
|
46
|
+
|
47
|
+
alias eql? ==
|
48
|
+
|
49
|
+
def expand_x ins
|
50
|
+
return self unless ins.any? { |i| @inputs[i].include? DontCare }
|
51
|
+
FSM.from_kiss to_kiss.lines.map { |line| line.dc_expand(ins) }.flatten.sort.join
|
52
|
+
end
|
53
|
+
|
54
|
+
def fsm_cells archs
|
55
|
+
return 0 if @outputs.map { |output| Blanket.from_array output }.inject(:*).size < 2
|
56
|
+
Arch[input_count + beta_q.pins, output_count + beta_q.pins].cells archs
|
57
|
+
end
|
58
|
+
|
59
|
+
def hash
|
60
|
+
@inputs.hash ^ @outputs.hash ^ @state.hash ^ @next_state.hash
|
61
|
+
end
|
62
|
+
|
63
|
+
def implementable_in? archs
|
64
|
+
return true if @outputs.map { |output| Blanket.from_array output }.inject(:*).size < 2
|
65
|
+
input_count + beta_q.pins <= archs.map(&:pins).max
|
66
|
+
end
|
67
|
+
|
68
|
+
def input_count
|
69
|
+
@inputs.size
|
70
|
+
end
|
71
|
+
|
72
|
+
def input_relevance
|
73
|
+
seps = beta_f.seps
|
74
|
+
perpin = (beta_q.seps & seps).size.to_f / beta_q.pins
|
75
|
+
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 }
|
76
|
+
more.map(&:last) + [nil] * beta_q.pins + less.map(&:last)
|
77
|
+
end
|
78
|
+
|
79
|
+
def q_encoding rows
|
80
|
+
# FIXME: consider tr DontCare, '*'
|
81
|
+
encoding @state, rows
|
82
|
+
end
|
83
|
+
|
84
|
+
def output_count
|
85
|
+
@outputs.size
|
86
|
+
end
|
87
|
+
|
88
|
+
def state_rows_of_next_state_of rows
|
89
|
+
state = @next_state[rows.bits.first]
|
90
|
+
B[*(0...@state.size).select { |i| @state[i] == state or @state[i] == DontCare }]
|
91
|
+
end
|
92
|
+
|
93
|
+
def stats
|
94
|
+
"#{@inputs.size}/#{@outputs.size}+#{(@state.uniq - [DontCare]).size}s"
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_kiss
|
98
|
+
st = @state.map { |e| e == DontCare ? '*' : e }
|
99
|
+
nxt = @next_state.map { |e| e == DontCare ? '*' : e }
|
100
|
+
div = Array.new @state.size, ' '
|
101
|
+
cols = @inputs + [div, st, div, nxt, div] + @outputs
|
102
|
+
KISS.new(cols.transpose.map(&:join)).formatted
|
103
|
+
end
|
104
|
+
|
105
|
+
def x_encoding ins, rows
|
106
|
+
ins.map { |i| encoding @inputs[i], rows }.join
|
107
|
+
end
|
108
|
+
|
109
|
+
def y_encoding rows
|
110
|
+
@outputs.map { |output| encoding output, rows }.join
|
111
|
+
end
|
112
|
+
|
113
|
+
protected
|
114
|
+
|
115
|
+
attr_reader :inputs, :outputs, :state, :next_state
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def encoding column, rows
|
120
|
+
encs = rows.bits.map { |row| column[row] }.uniq - [DontCare]
|
121
|
+
case encs.size
|
122
|
+
when 0 then DontCare.to_s
|
123
|
+
when 1 then encs.first.to_s
|
124
|
+
else raise AmbiguousEncodingQuery, "ambiguous encoding query: block #{rows.bits.join ','}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module ArtDecomp class Graph
|
2
|
+
|
3
|
+
attr_reader :edges, :vertices
|
4
|
+
|
5
|
+
def initialize blanket, seps
|
6
|
+
@vertices = blanket.ints.dup
|
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
|
14
|
+
end
|
15
|
+
|
16
|
+
def adjacent *vertices
|
17
|
+
return Set[] if @edges.all? { |edge| (edge & vertices).empty? }
|
18
|
+
@edges.reject { |edge| (edge & vertices).empty? }.inject(:|) - vertices
|
19
|
+
end
|
20
|
+
|
21
|
+
def blanket_from_colouring
|
22
|
+
colours = {}
|
23
|
+
@vertices.sort_by { |vert| [-degree(vert), vert] }.each do |vertex|
|
24
|
+
forbidden = adjacent(vertex).map { |vert| colours[vert] }.to_set
|
25
|
+
# FIXME: consider selecting colours on the least-popular-first basis
|
26
|
+
colour = :a
|
27
|
+
colour = colour.next while forbidden.include? colour
|
28
|
+
colours[vertex] = colour
|
29
|
+
end
|
30
|
+
blocks = Hash.new 0
|
31
|
+
colours.each { |vertex, colour| blocks[colour] |= vertex }
|
32
|
+
Blanket.new blocks.values
|
33
|
+
end
|
34
|
+
|
35
|
+
def complete?
|
36
|
+
2 * @edges.size == @vertices.size * (@vertices.size - 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
def degree vertex
|
40
|
+
@edges.count { |edge| edge.include? vertex }
|
41
|
+
end
|
42
|
+
|
43
|
+
def merge_by_edge_labels!
|
44
|
+
return self if @vertices.size == 1
|
45
|
+
pins = @vertices.size.log2_ceil
|
46
|
+
until @vertices.size.log2_ceil < pins
|
47
|
+
# FIXME: edge labels can/should be cached from previous computations
|
48
|
+
a, b = *@edges.sort_by { |edge| yield *edge }.first
|
49
|
+
merge! a, b
|
50
|
+
end
|
51
|
+
self
|
52
|
+
end
|
53
|
+
|
54
|
+
def merge_by_vertex_degrees!
|
55
|
+
pins = @vertices.size.log2_ceil
|
56
|
+
until @vertices.size.log2_ceil < pins or complete?
|
57
|
+
a, b = *@vertices.sort_by { |v| -degree(v) }.pairs.find { |v1, v2| not @edges.include? Set[v1, v2] }
|
58
|
+
merge! a, b
|
59
|
+
end
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
def merge_until_complete!
|
64
|
+
merge_by_vertex_degrees! until complete?
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def merge! a, b
|
71
|
+
new_edges = adjacent(a, b).map { |vert| Set[a|b, vert] }
|
72
|
+
@vertices.subtract [a, b]
|
73
|
+
@vertices.add a|b
|
74
|
+
@edges.delete_if { |edge| edge.include? a or edge.include? b }
|
75
|
+
@edges.merge new_edges
|
76
|
+
end
|
77
|
+
|
78
|
+
end end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ArtDecomp class KISS
|
2
|
+
|
3
|
+
def initialize lines
|
4
|
+
@lines = lines
|
5
|
+
end
|
6
|
+
|
7
|
+
def formatted
|
8
|
+
@lines.sort!
|
9
|
+
@lines.uniq!
|
10
|
+
drop_overlapping
|
11
|
+
combine_matching
|
12
|
+
@lines.join("\n") + "\n"
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def combine_matching
|
18
|
+
a, b, i = find_matching
|
19
|
+
while a and b and i
|
20
|
+
@lines.delete a
|
21
|
+
@lines.delete b
|
22
|
+
@lines << a[0...i] + DontCare.to_s + a[i+1..-1]
|
23
|
+
a, b, i = find_matching
|
24
|
+
end
|
25
|
+
@lines.sort!
|
26
|
+
end
|
27
|
+
|
28
|
+
def drop_overlapping
|
29
|
+
@lines.reject! do |line|
|
30
|
+
@lines.any? { |l| line != l and line[/\s.*$/] == l[/\s.*$/] and line =~ Regexp.new("^#{l.split.first.tr DontCare.to_s, '.'}\s") }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_matching
|
35
|
+
@lines.pairs.each do |a, b|
|
36
|
+
if a[/\s.*$/] == b[/\s.*$/]
|
37
|
+
a.size.times do |i|
|
38
|
+
if a[0...i] == b[0...i] and a[i+1..-1] == b[i+1..-1]
|
39
|
+
return a, b, i
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
end end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'gazer'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
module ArtDecomp class Logging < Gazer::Aspect::Base
|
7
|
+
|
8
|
+
def self.level
|
9
|
+
@@log.level
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.level= level
|
13
|
+
@@log.level = level
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.log= log
|
17
|
+
@@log = Logger.new log
|
18
|
+
@@log.level = Logger::INFO
|
19
|
+
@@log.formatter = proc { |sev, date, name, msg| "#{date} #{msg}\n" }
|
20
|
+
@@indent = ''
|
21
|
+
apply!
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.off
|
25
|
+
# FIXME: if instances can be unadvised, do that and close @@log
|
26
|
+
@@log = Logger.new '/dev/null'
|
27
|
+
end
|
28
|
+
|
29
|
+
after instances_of(Executable) => :run do |point|
|
30
|
+
@@log.info "final best decomposition: #{point.object.best} cells"
|
31
|
+
end
|
32
|
+
|
33
|
+
before instances_of(Executable) => :decompositions do |point|
|
34
|
+
@@indent = ' ' * (point.object.iters - point.args[1])
|
35
|
+
path = point.args[2][point.object.dir.size+1..-1]
|
36
|
+
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"
|
38
|
+
end
|
39
|
+
|
40
|
+
before instances_of(UVGenerator.constants.map { |c| eval("UVGenerator::#{c}") }) => :uv_pairs do |point|
|
41
|
+
@@log.info "#{@@indent} UV with #{point.object.class.to_s.split('::').last}"
|
42
|
+
end
|
43
|
+
|
44
|
+
before instances_of(QuGenerator.constants.map { |c| eval("QuGenerator::#{c}") }) => :blankets do |point|
|
45
|
+
@@log.info "#{@@indent} U = #{point.args[1].sort.inspect}, V = #{point.args[2].sort.inspect}, Qu with #{point.object.class.to_s.split('::').last}"
|
46
|
+
end
|
47
|
+
|
48
|
+
before instances_of(QvGenerator.constants.map { |c| eval("QvGenerator::#{c}") }) => :blankets do |point|
|
49
|
+
@@log.debug "#{@@indent} |Qu| = #{point.args[3].size}, Qv+G with #{point.object.class.to_s.split('::').last}"
|
50
|
+
end
|
51
|
+
|
52
|
+
end end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ArtDecomp class QuGenerator::BlockTable
|
2
|
+
|
3
|
+
def blankets fsm, u, v
|
4
|
+
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
|
+
fold_matching!
|
10
|
+
yielder.yield Blanket.new @rows
|
11
|
+
while @rows.size > 1
|
12
|
+
fold!
|
13
|
+
yielder.yield Blanket.new @rows
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def fold!
|
21
|
+
pins = @rows.size.log2_ceil
|
22
|
+
until @rows.size.log2_ceil < pins
|
23
|
+
@rows.pairs.each do |a, b|
|
24
|
+
@r_adms[Set[a, b]] ||= @cols.map { |col| @seps.r_adm((a | b) & col) }.max
|
25
|
+
end
|
26
|
+
a, b = *@r_adms.min_by { |key, val| val }.first
|
27
|
+
@r_adms.delete_if { |key, val| key.include? a or key.include? b }
|
28
|
+
@rows.subtract [a, b]
|
29
|
+
@rows.add a|b
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def fold_matching!
|
34
|
+
loop do
|
35
|
+
a, b = *@rows.pairs.find { |r1, r2| @cols.all? { |col| (r1 & col).zero? or (r2 & col).zero? } }
|
36
|
+
break unless a and b
|
37
|
+
@rows.subtract [a, b]
|
38
|
+
@rows.add a|b
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module ArtDecomp class QuGenerator::EdgeLabels
|
2
|
+
|
3
|
+
def blankets fsm, u, v
|
4
|
+
Enumerator.new do |yielder|
|
5
|
+
seps = fsm.beta_f.seps - fsm.beta_x(u).seps
|
6
|
+
@graph = Graph.new fsm.beta_q, seps
|
7
|
+
initial_merge
|
8
|
+
yielder.yield Blanket.new @graph.vertices
|
9
|
+
while @graph.vertices.size > 1
|
10
|
+
@graph.merge_by_edge_labels! do |a, b|
|
11
|
+
[seps.r_adm(a|b), (Blanket[a,b].seps & seps).size]
|
12
|
+
end
|
13
|
+
yielder.yield Blanket.new @graph.vertices
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def initial_merge
|
21
|
+
@graph.merge_until_complete!
|
22
|
+
end
|
23
|
+
|
24
|
+
end end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ArtDecomp class QvGenerator::Bipainting
|
2
|
+
|
3
|
+
def blankets fsm, u, v, beta_qu
|
4
|
+
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
|
+
yielder.yield bipainter.blankets
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ArtDecomp class QvGenerator::GraphColouring
|
2
|
+
|
3
|
+
def blankets fsm, u, v, beta_qu
|
4
|
+
Enumerator.new do |yielder|
|
5
|
+
beta_u = fsm.beta_x u
|
6
|
+
beta_v = fsm.beta_x v
|
7
|
+
beta_g = Graph.new(fsm.beta_q * beta_v, fsm.beta_f.seps - beta_u.seps - beta_qu.seps).blanket_from_colouring
|
8
|
+
beta_qv = Graph.new(fsm.beta_q, beta_g.seps - beta_v.seps).blanket_from_colouring
|
9
|
+
yielder.yield beta_qv, beta_g
|
10
|
+
beta_qv = Graph.new(fsm.beta_q, fsm.beta_f.seps - beta_u.seps - beta_qu.seps - beta_v.seps).blanket_from_colouring
|
11
|
+
beta_g = Graph.new(beta_qv * beta_v, fsm.beta_f.seps - beta_u.seps - beta_qu.seps).blanket_from_colouring
|
12
|
+
yielder.yield beta_qv, beta_g
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ArtDecomp class QvGenerator::GraphMerging
|
2
|
+
|
3
|
+
def blankets fsm, u, v, beta_qu
|
4
|
+
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
|
+
loop do
|
9
|
+
beta_qv = Blanket.new qv_graph.vertices
|
10
|
+
g_graph = Graph.new beta_qv * beta_v, fsm.beta_f.seps - beta_u.seps - beta_qu.seps
|
11
|
+
beta_g = Blanket.new g_graph.merge_until_complete!.vertices
|
12
|
+
yielder.yield [beta_qv, beta_g]
|
13
|
+
break if qv_graph.complete?
|
14
|
+
qv_graph.merge_by_vertex_degrees!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ArtDecomp class UVGenerator::Braindead
|
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
|
10
|
+
Enumerator.new do |yielder|
|
11
|
+
inputs = (0...@input_count).to_a
|
12
|
+
(0...2**@input_count).each do |vector|
|
13
|
+
u, v = Set[], Set[]
|
14
|
+
@input_count.times do |bit|
|
15
|
+
(vector[bit].zero? ? u : v) << inputs[bit]
|
16
|
+
end
|
17
|
+
yielder.yield @fsm.expand_x(v), u, v if v.size <= @max_v_size
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end end
|
@@ -0,0 +1,23 @@
|
|
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
|
data/lib/art-decomp.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
if RUBY_VERSION < '1.9'
|
2
|
+
|
3
|
+
require 'backports/1.9'
|
4
|
+
|
5
|
+
class Array
|
6
|
+
def keys
|
7
|
+
map &:first
|
8
|
+
end
|
9
|
+
def values
|
10
|
+
map &:last
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def Dir.exists? dir
|
15
|
+
File.exists? dir and File.directory? dir
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
module ArtDecomp
|
23
|
+
|
24
|
+
DontCare = :-
|
25
|
+
|
26
|
+
module QuGenerator
|
27
|
+
end
|
28
|
+
|
29
|
+
module QvGenerator
|
30
|
+
end
|
31
|
+
|
32
|
+
module UVGenerator
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
require 'set'
|
40
|
+
|
41
|
+
require_relative 'core/enumerable'
|
42
|
+
require_relative 'core/file'
|
43
|
+
require_relative 'core/integer'
|
44
|
+
require_relative 'core/set'
|
45
|
+
require_relative 'core/string'
|
46
|
+
|
47
|
+
require_relative 'art-decomp/arch'
|
48
|
+
require_relative 'art-decomp/b'
|
49
|
+
require_relative 'art-decomp/bipainter'
|
50
|
+
require_relative 'art-decomp/blanket'
|
51
|
+
require_relative 'art-decomp/decomposer'
|
52
|
+
require_relative 'art-decomp/decomposition'
|
53
|
+
require_relative 'art-decomp/exceptions'
|
54
|
+
require_relative 'art-decomp/executable'
|
55
|
+
require_relative 'art-decomp/fsm'
|
56
|
+
require_relative 'art-decomp/graph'
|
57
|
+
require_relative 'art-decomp/kiss'
|
58
|
+
require_relative 'art-decomp/qu_generator/block_table'
|
59
|
+
require_relative 'art-decomp/qu_generator/edge_labels'
|
60
|
+
require_relative 'art-decomp/qv_generator/bipainting'
|
61
|
+
require_relative 'art-decomp/qv_generator/graph_colouring'
|
62
|
+
require_relative 'art-decomp/qv_generator/graph_merging'
|
63
|
+
require_relative 'art-decomp/sep'
|
64
|
+
require_relative 'art-decomp/uv_generator/braindead'
|
65
|
+
require_relative 'art-decomp/uv_generator/relevance'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Enumerable
|
2
|
+
|
3
|
+
def self.all_combinations source
|
4
|
+
result_count = source.map(&:size).inject :*
|
5
|
+
group_count = 1
|
6
|
+
result = []
|
7
|
+
source.each do |elems|
|
8
|
+
row = []
|
9
|
+
group_count.times do
|
10
|
+
elems.each do |elem|
|
11
|
+
(result_count / group_count / elems.size).times { row << elem }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
group_count *= elems.size
|
15
|
+
result << row
|
16
|
+
end
|
17
|
+
result.transpose
|
18
|
+
end
|
19
|
+
|
20
|
+
def pairs
|
21
|
+
respond_to?(:combination) ? combination(2) : to_a.combination(2)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/core/file.rb
ADDED
data/lib/core/integer.rb
ADDED
data/lib/core/set.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
class Set
|
2
|
+
|
3
|
+
def r_adm int
|
4
|
+
# FIXME: consider an algorithm with lesser complexity
|
5
|
+
seps = select { |sep| int & sep == sep }
|
6
|
+
subblocks = Set[]
|
7
|
+
int.bits.each do |elem|
|
8
|
+
bit = 1 << elem
|
9
|
+
subblock = subblocks.find { |sb| seps.none? { |sep| (sb | bit) & sep == sep } } || 0
|
10
|
+
subblocks.delete subblock
|
11
|
+
subblocks << (subblock | bit)
|
12
|
+
end
|
13
|
+
subblocks.size.log2_ceil
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
data/lib/core/string.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def dc_expand columns = 0...size
|
4
|
+
return [self] unless include? ArtDecomp::DontCare.to_s
|
5
|
+
offsets = columns.sort
|
6
|
+
i = index ArtDecomp::DontCare.to_s, offsets.shift until columns.include? i or offsets.empty?
|
7
|
+
return [self] unless columns.include? i
|
8
|
+
zero, one = dup, dup
|
9
|
+
zero[i], one[i] = '0', '1'
|
10
|
+
[zero.dc_expand(columns), one.dc_expand(columns)].flatten
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ArtDecomp describe Arch do
|
2
|
+
|
3
|
+
it 'should be instantiable Array-style (and compare and hash properly)' do
|
4
|
+
Arch[5,1].should == Arch.new(5, 1)
|
5
|
+
Arch[5,2].should_not == Arch[5,1]
|
6
|
+
Arch[4,1].should_not == Arch[5,1]
|
7
|
+
Arch[5,1].hash.should == Arch[5,1].hash
|
8
|
+
Arch[5,1].should eql Arch[5,1]
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should have a common String representation' do
|
12
|
+
Arch[5,1].to_s.should == '5/1'
|
13
|
+
Arch[4,2].to_s.should == '4/2'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should report how many cells of given Archs it requires' do
|
17
|
+
Arch[4,3].cells(Set[Arch[4,2], Arch[5,1]]).should == 2
|
18
|
+
Arch[4,3].cells(Set[Arch[5,1]]).should == 3
|
19
|
+
Arch[5,3].cells(Set[Arch[4,3]]).should be_nil
|
20
|
+
Arch[5,3].cells(Set[Arch[5,2]]).should == 2
|
21
|
+
end
|
22
|
+
|
23
|
+
end end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module ArtDecomp describe B do
|
4
|
+
|
5
|
+
context 'when representing ‘set bits’ concept' do
|
6
|
+
|
7
|
+
it 'should provide proper representation (also across the Fixnum/Bignum boundary)' do
|
8
|
+
B[].should == 0b0
|
9
|
+
B[0].should == 0b1
|
10
|
+
B[5,8].should == 0b100100000
|
11
|
+
B[30].should == 2**30
|
12
|
+
B[40].should == 2**40
|
13
|
+
B[1,69].should == 2**69 + 0b10
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should uniformly work inside Sets (also across the Fixnum/Bignum boundary)' do
|
17
|
+
B[].hash.should == 0b0.hash
|
18
|
+
B[0].hash.should == 0b1.hash
|
19
|
+
B[5,8].hash.should == 0b100100000.hash
|
20
|
+
B[30].hash.should == (2**30).hash
|
21
|
+
B[40].hash.should == (2**40).hash
|
22
|
+
B[1,69].hash.should == (2**69 + 0b10).hash
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end end
|