bliftax 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3684c7584ac8b0997cf6de140dadf03327bea675
4
- data.tar.gz: 75bcb8953ee6979a0536f557326b7df0987eaa76
3
+ metadata.gz: 785167c0e657e38b987fd032dacacfeb2b31229e
4
+ data.tar.gz: 8144130dde9b34a98b76fb67d940cd81ee861d3d
5
5
  SHA512:
6
- metadata.gz: c4bd813c5b38f9ee2328f0e0bae284971a9ef88c1fe32d19a16c4d29644af8ce8287c576a3fa3e1a667f3f7c46d5ed544f2f7d64a1e934be520eb4dd6e93d2c9
7
- data.tar.gz: 581ec378e22f33b2e0bcaf804f9c3823d0d523094def03fd90f9c9872753ede88487cc45c0c7773a0d98080c433167636f6cfe8bcb813402784eafc4730bcd4c
6
+ metadata.gz: 769d3fea118d3ee1c2bac90fa5c727f7eb49f5c8ee2c68cc3e6ff3ec511491d47b1ede6b40ad4dbb988ac739cd8340dcdd677f1d4668b9b66e41b9e291d8c444
7
+ data.tar.gz: b804198d60ee236c8a3084a879fe6630acf38a319b8d6b9aa7b92563fcc825fe4f13209e20c307e46a316ce46266ccd4541afbd4d82f410e4878ad98df47c4f2
data/.travis.yml CHANGED
@@ -1,4 +1,13 @@
1
1
  language: ruby
2
+
2
3
  rvm:
3
4
  - 2.2.2
5
+
4
6
  before_install: gem install bundler -v 1.10.4
7
+
8
+ script: 'bundle exec rake'
9
+
10
+ notifications:
11
+ email:
12
+ on_failure: change
13
+ on_success: never
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Bliftax
2
2
 
3
+ [![Build Status](https://travis-ci.org/NigoroJr/bliftax.svg)](https://travis-ci.org/NigoroJr/bliftax)
4
+
3
5
  This is a simple library that parses a
4
6
  [BLIF](https://www.ece.cmu.edu/~ee760/760docs/blif.pdf) file and does
5
7
  operations used in logic optimization algorithms described in Chapter 4.10.2
@@ -29,6 +31,10 @@ This gem currently only supports the following declarations for BLIF:
29
31
 
30
32
  Following is the list of main features of this gem:
31
33
 
34
+ * 2-level logic optimization
35
+ - getting the prime implicants
36
+ - getting the essential prime implicants
37
+ - using branch heuristic
32
38
  * star operators
33
39
  * sharp operators
34
40
  * coverage check (b is covered by a)
@@ -37,6 +43,28 @@ Following is the list of main features of this gem:
37
43
 
38
44
  Here is an example usage of this gem.
39
45
 
46
+ ```ruby
47
+ #!/usr/bin/env ruby
48
+
49
+ require 'bliftax'
50
+
51
+ abort "Usage: #{$PROGRAM_NAME} <blif file>" if ARGV.empty?
52
+
53
+ BLIF_FILE = ARGV.first
54
+
55
+ model = Bliftax.new(BLIF_FILE)
56
+ output = model.dup
57
+
58
+ model.gates.each_with_index do |gate, i|
59
+ final_cover = Bliftax::Optimizer.optimize(gate)
60
+ output.gates[i].implicants = final_cover.to_a
61
+ end
62
+
63
+ puts output.to_blif
64
+ ```
65
+
66
+ Some other ways you can use this gem.
67
+
40
68
  ```ruby
41
69
  require 'bliftax'
42
70
 
@@ -98,6 +98,10 @@ class Bliftax
98
98
  # * C = NULL if A_i * B_i = NULL for more than one i
99
99
  # * Otherwise, C_i = A_i * B_i when A_i * B_i != NULL, and C_i = x (don't
100
100
  # care) for the coordinate where A_i * B_i = NULL
101
+ #
102
+ # @param rhs [Implicant] the right hand side of the operation.
103
+ #
104
+ # @return [Implicant] the result of the star operation.
101
105
  def star(rhs)
102
106
  # Sanity check
103
107
  unless @inputs.size == rhs.inputs.size
@@ -141,7 +145,7 @@ class Bliftax
141
145
  # * C = NULL if A_i # B_i = EPSILON for all i
142
146
  # * Otherwise, C = union of A_i = B_i' (negated) if A_i = x and B_i != x
143
147
  #
144
- # @param rhs [Implicant] the right hand side of the operation
148
+ # @param rhs [Implicant] the right hand side of the operation.
145
149
  #
146
150
  # @return [Set<Implicant>] Note that the set size could be 1.
147
151
  def sharp(rhs)
@@ -301,6 +305,23 @@ class Bliftax
301
305
  format '%s %s', @inputs.map(&:bit).join, @output.bit
302
306
  end
303
307
 
308
+ # Creates a dummy implicant with the given inputs.
309
+ # This is useful when checking if an implicant is equal to what is
310
+ # expected. The input labels are labeled from 'a' to 'z' then 'A' to 'Z',
311
+ # and the output label is 'out'.
312
+ #
313
+ # @param inputs [String, Array<String>] the input bits.
314
+ # @param output [String] the output bit.
315
+ #
316
+ # @return [Implicant] an implicant with dummy labels and the bits set to
317
+ # the given bits.
318
+ def self.make_dummy(inputs, output = '1')
319
+ labels = ('a'..'z').to_a + ('A'..'Z').to_a
320
+ in_labels = labels.first(inputs.size)
321
+ input_str = inputs.is_a?(Array) ? inputs.join : inputs
322
+ Implicant.new(in_labels, 'out', format('%s %s', input_str, output))
323
+ end
324
+
304
325
  # Creates a new NULL Implicant.
305
326
  #
306
327
  # @return [Implicant] a null Implicant
@@ -0,0 +1,202 @@
1
+ class Bliftax
2
+ # A module that does 2-level logic optimization
3
+ module Optimizer
4
+ module_function
5
+
6
+ # Does 2-level logic optimization to the given gate (a set of implicants).
7
+ # This is done in the following steps (as described in the book
8
+ # Fundamentals of Digital Logic with Verilog Design.
9
+ #
10
+ # 1. Find all prime implicants by using the star operator until the
11
+ # resulting set of implicants is the same as the previous round.
12
+ # 2. Apply the sharp operation to one of the prime implicants against all
13
+ # other implicants. The operation is cascaded. If the result is not
14
+ # null, it is an essential prime implicant. Do this for all prime
15
+ # implicants.
16
+ # 3. For the non-essential prime implicants, remove the ones that can be
17
+ # covered by some other implicant but with less cost.
18
+ # 4. For the remaining implicants, use the branching heuristic to find the
19
+ # set of prime implicants with the minimum cost.
20
+ #
21
+ # @param gate [Bliftax::Gate, Set<Implicant>, Array<Implicant>] the set of
22
+ # implicants to be optimized.
23
+ #
24
+ # @return [Set<Implicant>] the resulting optimized set of implicants that
25
+ # covers the same minterms.
26
+ def optimize(gate)
27
+ implicants = gate.is_a?(Bliftax::Gate) ? gate.implicants : gate
28
+ primes = get_prime_implicants(implicants)
29
+
30
+ essentials = get_essential_implicants(primes)
31
+
32
+ # Essential implicants will always be essential
33
+ primes -= essentials
34
+
35
+ # Find minterms that still needs to be covered
36
+ need_cover = implicants.map(&:minterms).to_set.flatten
37
+ need_cover -= essentials.map(&:minterms).to_set.flatten
38
+
39
+ # Remove implicants with higher cost
40
+ primes.to_a.permutation(2).each do |a, b|
41
+ # If b has same coverage but cheaper
42
+ if a.cost > b.cost && (a.minterms & need_cover) <= b.minterms
43
+ primes.delete(a)
44
+ end
45
+ end
46
+
47
+ # Branching heuristic
48
+ to_use = branching(need_cover, primes)
49
+
50
+ essentials.union(to_use)
51
+ end
52
+
53
+ # Returns the prime implicants of the given set of implicants.
54
+ # This method successively applies the star operations to the given
55
+ # implicants to find the prime implicants.
56
+ #
57
+ # @param implicants [Set<Implicant>, Array<Implicant>] the original set of
58
+ # implicants.
59
+ #
60
+ # @return [Set<Implicant>] a set of prime implicants.
61
+ def get_prime_implicants(implicants)
62
+ # Use star operator to find prime implicants
63
+ star_set = Set.new(implicants)
64
+ prev_set = Set.new
65
+
66
+ loop do
67
+ prev_set = star_set.dup
68
+ prev_set.to_a.combination(2).each do |a, b|
69
+ result = a * b
70
+ star_set.add(result) unless result.null?
71
+ end
72
+
73
+ # Remove redundant implicants
74
+ union = star_set.union(prev_set)
75
+ union.to_a.permutation(2).each do |a, b|
76
+ star_set.delete(b) if a.covers?(b)
77
+ end
78
+
79
+ break if star_set == prev_set
80
+ end
81
+
82
+ star_set
83
+ end
84
+
85
+ # Finds the essential implicants of the given set of implicants.
86
+ # This method applies the sharp operation to an implicant against each of
87
+ # the other implicants in the set, and adds the tested implicant if and
88
+ # only if the result of the cascaded sharp operation is not null.
89
+ #
90
+ # @param implicants [Set<Implicant>, Array<Implicant>] the original set of
91
+ # implicants.
92
+ #
93
+ # @return [Set<Implicant>] the essential implicants of the given set of
94
+ # implicants.
95
+ def get_essential_implicants(implicants)
96
+ sharp_set = Set.new
97
+
98
+ implicants.each do |a|
99
+ result_set = Set.new([a])
100
+
101
+ implicants.each do |b|
102
+ next if b == a
103
+
104
+ copy = result_set.dup
105
+ result_set.clear
106
+ copy.each do |new_a|
107
+ result_set.add(new_a.sharp(b))
108
+ end
109
+ result_set.flatten!
110
+ result_set.delete_if { |s| s.null? }
111
+ end
112
+
113
+ sharp_set.add(a) unless result_set.empty?
114
+ end
115
+
116
+ sharp_set
117
+ end
118
+
119
+ # Cost heuristic.
120
+ # If an Implicant is given, the cost of that Implicant is returned.
121
+ # Otherwise, the sum of the number of implicants and the cost of each
122
+ # implicant is returned as the cost for that collection.
123
+ #
124
+ # @param what [Implicant, #to_a<#cost>] the thing to be evaluated.
125
+ #
126
+ # @return the evaluated cost
127
+ def cost(what)
128
+ return what.cost if what.is_a?(Bliftax::Implicant)
129
+
130
+ cost_sum = what.size
131
+ cost_sum += what.to_a.reduce(0) { |a, e| a + e.cost }
132
+ cost_sum
133
+ end
134
+
135
+ # Finds the minimum-cost combination to cover the given minterms.
136
+ # This method does recursive DFS to search for the minimum-cost
137
+ # combination, so it may become slow depending on the number of available
138
+ # options.
139
+ #
140
+ # @param to_cover [Set<Integer>] the set of minterms that need to be
141
+ # covered.
142
+ # @param options [Set<Implicant>] the set of implicants to choose from.
143
+ def branching(to_cover, options)
144
+ to_use = Set.new
145
+ options.dup.each do |implicant|
146
+ result = branching_helper(to_cover, options, implicant)
147
+ if result.include?(implicant)
148
+ to_use.add(implicant)
149
+ to_cover -= implicant.minterms
150
+ options.delete(implicant)
151
+ end
152
+ end
153
+ to_use
154
+ end
155
+
156
+ private
157
+
158
+ module_function
159
+
160
+ # A helper method for the recursive DFS for branching heuristic.
161
+ #
162
+ # @param to_cover [Set<Integer>] minterms that need to be covered.
163
+ # @param options [Set<Implicant>] the prime implicants that we can choose
164
+ # from.
165
+ # @param implicant [Implicant] the implicant that's being decided whether
166
+ # to include in the final cover or not.
167
+ # @return the set that results in a better cost when including or not
168
+ # including the implicant.
169
+ def branching_helper(to_cover, options, implicant)
170
+ # Get implicants from options that cover at least one required vertex
171
+ options = options.select do |o|
172
+ !(to_cover & o.minterms).empty?
173
+ end
174
+ options = options.to_set
175
+
176
+ # Base case
177
+ return Set.new if options.empty?
178
+
179
+ # Final cover when using the implicant
180
+ new_options = options - Set.new([implicant])
181
+ using_implicant = branching_helper(to_cover - implicant.minterms,
182
+ new_options,
183
+ new_options.to_a.first)
184
+ # Don't forget to add this implicant
185
+ using_implicant.add(implicant)
186
+ # Final cover when not using the implicant
187
+ not_using_implicant = branching_helper(to_cover,
188
+ new_options,
189
+ new_options.to_a.first)
190
+
191
+ cost_using = cost(using_implicant)
192
+ cost_not_using = cost(not_using_implicant)
193
+
194
+ # Not using this implicant results in as good a coverage but less cost
195
+ minterms_coverage = not_using_implicant.map(&:minterms).to_set.flatten
196
+ if cost_not_using < cost_using && minterms_coverage >= to_cover
197
+ return not_using_implicant
198
+ end
199
+ return using_implicant
200
+ end
201
+ end
202
+ end
@@ -1,3 +1,3 @@
1
1
  class Bliftax
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/bliftax.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'bliftax/gate'
2
2
  require 'bliftax/implicant'
3
+ require 'bliftax/optimizer'
3
4
  require 'bliftax/version'
4
5
 
5
6
  # A class that parses a BLIF file.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bliftax
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naoki Mizuno
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-16 00:00:00.000000000 Z
11
+ date: 2015-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -73,6 +73,7 @@ files:
73
73
  - lib/bliftax/gate.rb
74
74
  - lib/bliftax/implicant.rb
75
75
  - lib/bliftax/implicant/bit.rb
76
+ - lib/bliftax/optimizer.rb
76
77
  - lib/bliftax/version.rb
77
78
  homepage: https://github.com/NigoroJr/bliftax
78
79
  licenses: