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.
Files changed (84) hide show
  1. data/.gitignore +2 -0
  2. data/LICENCE +661 -0
  3. data/README +9 -0
  4. data/Rakefile +46 -0
  5. data/VERSION +1 -0
  6. data/bin/ad-compare +22 -0
  7. data/bin/ad-console +11 -0
  8. data/bin/ad-inputs +24 -0
  9. data/bin/ad-validate +9 -0
  10. data/bin/art-decomp +8 -0
  11. data/lib/art-decomp/arch.rb +32 -0
  12. data/lib/art-decomp/b.rb +7 -0
  13. data/lib/art-decomp/bipainter.rb +142 -0
  14. data/lib/art-decomp/blanket.rb +82 -0
  15. data/lib/art-decomp/decomposer.rb +75 -0
  16. data/lib/art-decomp/decomposition.rb +91 -0
  17. data/lib/art-decomp/exceptions.rb +9 -0
  18. data/lib/art-decomp/executable.rb +94 -0
  19. data/lib/art-decomp/fsm.rb +128 -0
  20. data/lib/art-decomp/graph.rb +78 -0
  21. data/lib/art-decomp/kiss.rb +47 -0
  22. data/lib/art-decomp/logging.rb +52 -0
  23. data/lib/art-decomp/qu_generator/block_table.rb +42 -0
  24. data/lib/art-decomp/qu_generator/edge_labels.rb +24 -0
  25. data/lib/art-decomp/qv_generator/bipainting.rb +12 -0
  26. data/lib/art-decomp/qv_generator/graph_colouring.rb +16 -0
  27. data/lib/art-decomp/qv_generator/graph_merging.rb +19 -0
  28. data/lib/art-decomp/sep.rb +7 -0
  29. data/lib/art-decomp/uv_generator/braindead.rb +22 -0
  30. data/lib/art-decomp/uv_generator/relevance.rb +23 -0
  31. data/lib/art-decomp.rb +65 -0
  32. data/lib/core/enumerable.rb +24 -0
  33. data/lib/core/file.rb +11 -0
  34. data/lib/core/integer.rb +13 -0
  35. data/lib/core/set.rb +16 -0
  36. data/lib/core/string.rb +13 -0
  37. data/spec/art-decomp/arch_spec.rb +23 -0
  38. data/spec/art-decomp/b_spec.rb +27 -0
  39. data/spec/art-decomp/bipainter_spec.rb +22 -0
  40. data/spec/art-decomp/blanket_spec.rb +77 -0
  41. data/spec/art-decomp/decomposer_spec.rb +106 -0
  42. data/spec/art-decomp/decomposition_spec.rb +119 -0
  43. data/spec/art-decomp/executable_spec.rb +161 -0
  44. data/spec/art-decomp/fsm_spec.rb +146 -0
  45. data/spec/art-decomp/graph_spec.rb +69 -0
  46. data/spec/art-decomp/kiss_spec.rb +30 -0
  47. data/spec/art-decomp/logging_spec.rb +62 -0
  48. data/spec/art-decomp/qu_generator/block_table_spec.rb +37 -0
  49. data/spec/art-decomp/qu_generator/edge_labels_spec.rb +35 -0
  50. data/spec/art-decomp/qv_generator/bipainting_spec.rb +28 -0
  51. data/spec/art-decomp/qv_generator/graph_colouring_spec.rb +31 -0
  52. data/spec/art-decomp/qv_generator/graph_merging_spec.rb +30 -0
  53. data/spec/art-decomp/sep_spec.rb +13 -0
  54. data/spec/art-decomp/uv_generator/braindead_spec.rb +33 -0
  55. data/spec/art-decomp/uv_generator/relevance_spec.rb +61 -0
  56. data/spec/core/enumerable_spec.rb +20 -0
  57. data/spec/core/file_spec.rb +15 -0
  58. data/spec/core/integer_spec.rb +16 -0
  59. data/spec/core/set_spec.rb +26 -0
  60. data/spec/core/string_spec.rb +17 -0
  61. data/spec/fixtures/ex5 +36 -0
  62. data/spec/fixtures/fsm +24 -0
  63. data/spec/fixtures/fsm.exp +40 -0
  64. data/spec/fixtures/fsm.f +20 -0
  65. data/spec/fixtures/fsm.g +4 -0
  66. data/spec/fixtures/fsm.h +19 -0
  67. data/spec/fixtures/fsm.partially-exp +31 -0
  68. data/spec/fixtures/fsm.q +10 -0
  69. data/spec/fixtures/lion +15 -0
  70. data/spec/fixtures/lion.exp +15 -0
  71. data/spec/fixtures/lion.h +10 -0
  72. data/spec/fixtures/lion.to_kiss +11 -0
  73. data/spec/fixtures/mark1 +26 -0
  74. data/spec/fixtures/mc +14 -0
  75. data/spec/fixtures/mc.to_kiss +10 -0
  76. data/spec/fixtures/opus +26 -0
  77. data/spec/fixtures/opus.amb.h +22 -0
  78. data/spec/fixtures/opus.h +21 -0
  79. data/spec/fixtures/opus.to_kiss +22 -0
  80. data/spec/fixtures/s420 +142 -0
  81. data/spec/fixtures/s8 +24 -0
  82. data/spec/spec.opts +3 -0
  83. data/spec/spec_helper.rb +8 -0
  84. 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,7 @@
1
+ module ArtDecomp class Sep
2
+
3
+ def self.[] first, last
4
+ 1 << first | 1 << last
5
+ end
6
+
7
+ 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
@@ -0,0 +1,11 @@
1
+ class File
2
+
3
+ def self.dump_object object, path
4
+ write_data Marshal.dump(object), path
5
+ end
6
+
7
+ def self.write_data data, path
8
+ self.open(path, 'w') { |f| f << data }
9
+ end
10
+
11
+ end
@@ -0,0 +1,13 @@
1
+ class Integer
2
+
3
+ # FIXME: consider right-shifting self and counting ones
4
+ def bits
5
+ (0...to_s(2).size).select { |bit| self[bit] == 1 }
6
+ end
7
+
8
+ def log2_ceil
9
+ return 0 if self == 0 or self == 1
10
+ (self - 1).to_s(2).size
11
+ end
12
+
13
+ end
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
@@ -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