lm 0.1.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 +7 -0
- data/Gemfile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/lm/bin_func.rb +48 -0
- data/lib/lm/implicant_chart.rb +90 -0
- data/lib/lm/minimizer.rb +53 -0
- data/lib/lm/output_string.rb +29 -0
- data/lib/lm/petrick.rb +73 -0
- data/lib/lm/pos.rb +79 -0
- data/lib/lm/product.rb +24 -0
- data/lib/lm/quine_mc_cluskey.rb +20 -0
- data/lib/lm/string_122_result_selector.rb +37 -0
- data/lib/lm/sum.rb +43 -0
- data/lib/lm/sum_of_products.rb +33 -0
- data/lib/lm/variable.rb +68 -0
- data/lib/lm/version.rb +5 -0
- data/lib/lm.rb +21 -0
- data/lm.gemspec +34 -0
- data/spec/lm_spec.rb +40 -0
- data/spec/spec_helper.rb +15 -0
- metadata +69 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 82e0500fd99881105260a6367a282628a4c9bf5365ddc717c219fe39e1df0f19
|
|
4
|
+
data.tar.gz: f69499c220e4a27a2a435a6820a708d458491bf0cde568d9fb9c4ddd277f13ed
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: af2de852aeaf14c17783868468dd34405ccde647db085cc2fd3c1999b91c6b4aac5ec608ed9a15116049840c436979e799f7c3894608c8dd798b727e61940ba1
|
|
7
|
+
data.tar.gz: e57c6b4f50c406ca6c1861fa9f530da28706619c3c92d1e1c9fe64e170fa195d3aec9179bfc55331afe238734d857b41a7fab8545a60a3c0cb7e24dc76307f61
|
data/Gemfile
ADDED
data/bin/console
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "bundler/setup"
|
|
5
|
+
require "lm"
|
|
6
|
+
|
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
|
9
|
+
|
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
|
11
|
+
# require "pry"
|
|
12
|
+
# Pry.start
|
|
13
|
+
|
|
14
|
+
require "irb"
|
|
15
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/lm/bin_func.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class BinFunc
|
|
5
|
+
def initialize(products)
|
|
6
|
+
@products = products.arr
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def inputlen
|
|
10
|
+
@products.first.vars.count
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def max
|
|
14
|
+
(1 << inputlen) - 1
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def apply(product, bitstr)
|
|
18
|
+
raise "len mismatch" if bitstr.length != product.vars.length
|
|
19
|
+
|
|
20
|
+
result = 1
|
|
21
|
+
|
|
22
|
+
inputlen.times do |x|
|
|
23
|
+
next if product.vars[x].invalid?
|
|
24
|
+
|
|
25
|
+
val = bitstr[x].to_i
|
|
26
|
+
|
|
27
|
+
val = ~val if product.vars[x].value == "0"
|
|
28
|
+
|
|
29
|
+
result &= val
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
result
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def evaluate(num)
|
|
36
|
+
raise "number too large" if num > max
|
|
37
|
+
|
|
38
|
+
bitstr = num.to_s(2).rjust(inputlen, "0")
|
|
39
|
+
|
|
40
|
+
result = 0
|
|
41
|
+
@products.each do |product|
|
|
42
|
+
result |= apply(product, bitstr)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
result
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class ImplicantChart
|
|
5
|
+
def initialize(chart, length:, step: 0)
|
|
6
|
+
@chart = chart
|
|
7
|
+
@step = step
|
|
8
|
+
@length = length
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def buckets
|
|
12
|
+
@buckets ||= begin
|
|
13
|
+
rr = {}
|
|
14
|
+
@chart.each do |k, v|
|
|
15
|
+
ones = v.count("1")
|
|
16
|
+
rr[ones] ||= {}
|
|
17
|
+
rr[ones][k] = v
|
|
18
|
+
end
|
|
19
|
+
# p rr
|
|
20
|
+
rr
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def keys
|
|
25
|
+
Set.new(@chart.keys)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def reduced
|
|
29
|
+
rr = {}
|
|
30
|
+
touched = Set.new
|
|
31
|
+
@length.times do |x|
|
|
32
|
+
next if buckets[x].nil?
|
|
33
|
+
next if buckets[x + 1].nil?
|
|
34
|
+
|
|
35
|
+
buckets[x].each do |num, pattern|
|
|
36
|
+
buckets[x + 1].each do |num2, pattern2|
|
|
37
|
+
diffcount = 0
|
|
38
|
+
last = 0
|
|
39
|
+
@length.times do |col|
|
|
40
|
+
if pattern[col] == "-" && pattern2[col] != "-" ||
|
|
41
|
+
pattern2[col] == "-" && pattern[col] != "-"
|
|
42
|
+
diffcount += 2
|
|
43
|
+
last = col
|
|
44
|
+
end
|
|
45
|
+
next unless pattern[col] == "1" && pattern2[col] == "0" ||
|
|
46
|
+
pattern2[col] == "1" && pattern[col] == "0"
|
|
47
|
+
|
|
48
|
+
diffcount += 1
|
|
49
|
+
last = col
|
|
50
|
+
end
|
|
51
|
+
next unless diffcount == 1
|
|
52
|
+
|
|
53
|
+
str = pattern.dup
|
|
54
|
+
str[last] = "-"
|
|
55
|
+
rr["#{num},#{num2}".split(",").sort.join(",").to_str] = str
|
|
56
|
+
touched << num.to_s
|
|
57
|
+
touched << num2.to_s
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
@chart.each do |k, v|
|
|
63
|
+
next if touched.include? k
|
|
64
|
+
|
|
65
|
+
rr[k] = v
|
|
66
|
+
end
|
|
67
|
+
ImplicantChart.new(rr, step: @step + 1, length: @length)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def soplist
|
|
71
|
+
rr = {}
|
|
72
|
+
@chart.each do |k, v|
|
|
73
|
+
rr[k] = Product.new(v)
|
|
74
|
+
end
|
|
75
|
+
rr
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def variables
|
|
79
|
+
@variables ||= begin
|
|
80
|
+
vars = Set.new
|
|
81
|
+
@chart.each_key do |x|
|
|
82
|
+
x.split(",").each do |name|
|
|
83
|
+
vars << name
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
vars
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/lib/lm/minimizer.rb
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class Minimizer
|
|
5
|
+
def initialize(output_str)
|
|
6
|
+
@output_str = output_str
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def output_string
|
|
10
|
+
OutputString.new(@output_str)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def canonical
|
|
14
|
+
output_string.sop
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def qcm
|
|
18
|
+
QuineMcCluskey.new(canonical.implicants)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def implicants
|
|
22
|
+
qcm.prime_implicants
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def pm
|
|
26
|
+
Petrick.new(implicants)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def pos
|
|
30
|
+
POS.new(pm.string122)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def reduced_sum
|
|
34
|
+
pos.expand.reduce
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def calculator
|
|
38
|
+
String122ResultSelector.new(implicants, reduced_sum)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def shortest
|
|
42
|
+
calculator.shortest
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def evaluate(input)
|
|
46
|
+
BinFunc.new(shortest).evaluate(input)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def canonical_evaluate(input)
|
|
50
|
+
BinFunc.new(output_string.sop).evaluate(input)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class OutputString
|
|
5
|
+
def initialize(str)
|
|
6
|
+
@str = str
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def bitcount
|
|
10
|
+
Math.log(@str.length, 2).ceil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def sop
|
|
14
|
+
res = SumOfProducts.new
|
|
15
|
+
@str.length.times do |x|
|
|
16
|
+
bitbreak = x.to_s(2).rjust(bitcount, "0")
|
|
17
|
+
next if @str[x] == "0"
|
|
18
|
+
|
|
19
|
+
prod = Product.new(bitbreak)
|
|
20
|
+
res << prod
|
|
21
|
+
end
|
|
22
|
+
res
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_s(v = nil)
|
|
26
|
+
sop.to_s(v)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/lm/petrick.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class Petrick
|
|
5
|
+
def initialize(chart)
|
|
6
|
+
@chart = chart
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def grouplist
|
|
10
|
+
@grouplist ||= @chart.keys
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# factors from the petrick table
|
|
14
|
+
def factors
|
|
15
|
+
factorlist = []
|
|
16
|
+
uncovered_columns.each do |var|
|
|
17
|
+
factor = []
|
|
18
|
+
grouplist.each_with_index do |group, idx|
|
|
19
|
+
vlist = Set.new(group.split(","))
|
|
20
|
+
factor << [idx] if vlist.include?(var)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
factorlist << factor
|
|
24
|
+
end
|
|
25
|
+
factorlist + essential_rows.map { |x| [[x]] }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def essential_columns
|
|
29
|
+
@essential_columns ||= begin
|
|
30
|
+
varcounts = {}
|
|
31
|
+
grouplist.each_with_index do |group, _idx|
|
|
32
|
+
group.split(",").each do |v|
|
|
33
|
+
varcounts[v] ||= 0
|
|
34
|
+
varcounts[v] += 1
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
varcounts.select { |_k, v| v == 1 }.to_h.keys
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def essential_rows
|
|
42
|
+
@essential_rows ||= begin
|
|
43
|
+
rows = []
|
|
44
|
+
|
|
45
|
+
essential_columns.each do |x|
|
|
46
|
+
grouplist.each_with_index do |group, idx|
|
|
47
|
+
vars = Set.new(group.split(","))
|
|
48
|
+
if vars.include?(x)
|
|
49
|
+
rows << idx
|
|
50
|
+
break
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
rows
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def uncovered_columns
|
|
59
|
+
@uncovered_columns ||= begin
|
|
60
|
+
touched = Set.new
|
|
61
|
+
essential_rows.each do |idx|
|
|
62
|
+
touched += grouplist.to_a[idx].split(",")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@chart.variables - touched
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def string122
|
|
70
|
+
factors.map { |sums| sums.map { |prducts| prducts.map { |x| (x.ord + 48).chr }.join("") }.join("+") }.join(",")
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/lm/pos.rb
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
# definitions
|
|
5
|
+
# A = factor
|
|
6
|
+
# AB = term
|
|
7
|
+
# AB+C = sum
|
|
8
|
+
# (AB + C)(D + E) = product of sums
|
|
9
|
+
# AB+C,D+E
|
|
10
|
+
|
|
11
|
+
class POS
|
|
12
|
+
def initialize(str)
|
|
13
|
+
@str = str
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def sum_array
|
|
17
|
+
@sum_array ||= @str.split(",")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def termhash
|
|
21
|
+
@termhash ||= begin
|
|
22
|
+
res = {}
|
|
23
|
+
sum_array.each do |sum|
|
|
24
|
+
terms = sum.split("+")
|
|
25
|
+
terms.each do |term|
|
|
26
|
+
res[term] ||= Set.new
|
|
27
|
+
terms.each do |x|
|
|
28
|
+
next if x == term
|
|
29
|
+
|
|
30
|
+
res[term] << x
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
res
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def apply_factorize
|
|
39
|
+
newarray = []
|
|
40
|
+
seenkeys = Set.new
|
|
41
|
+
|
|
42
|
+
termhash.each do |key, value|
|
|
43
|
+
next if seenkeys.include? key
|
|
44
|
+
|
|
45
|
+
seenkeys << key
|
|
46
|
+
value.each do |factor|
|
|
47
|
+
seenkeys << factor
|
|
48
|
+
end
|
|
49
|
+
newarray << "#{key}+#{value.to_a.join("")}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
POS.new(newarray.join(","))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# return SOP
|
|
56
|
+
def expand
|
|
57
|
+
# puts "EXPAND"
|
|
58
|
+
arr = sum_array
|
|
59
|
+
|
|
60
|
+
loop do
|
|
61
|
+
break if arr.length == 1
|
|
62
|
+
|
|
63
|
+
aterms = arr[0].split("+")
|
|
64
|
+
bterms = arr[1].split("+")
|
|
65
|
+
|
|
66
|
+
newterms = aterms.product(bterms).map do |x|
|
|
67
|
+
x.join("").split("").uniq.join("")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
newsum = newterms.join("+")
|
|
71
|
+
|
|
72
|
+
arr = [newsum] + arr[2..]
|
|
73
|
+
# p arr
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
Sum.new(arr.first)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
data/lib/lm/product.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class Product
|
|
5
|
+
attr_reader :str
|
|
6
|
+
|
|
7
|
+
def initialize(str)
|
|
8
|
+
@str = str
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def vars
|
|
12
|
+
@str.split("").each_with_index.map do |x, i|
|
|
13
|
+
Variable.new(x, i)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def to_s(v = nil)
|
|
18
|
+
joiner = ""
|
|
19
|
+
|
|
20
|
+
joiner = " & " if v == :verilog || (v.is_a?(Hash) && v[:verilog])
|
|
21
|
+
vars.map { |x| x.to_s(v) }.compact.join(joiner)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class QuineMcCluskey
|
|
5
|
+
def initialize(chart)
|
|
6
|
+
@chart = chart
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def prime_implicants
|
|
10
|
+
curchart = @chart
|
|
11
|
+
loop do
|
|
12
|
+
newchart = curchart.reduced
|
|
13
|
+
break if newchart.keys == curchart.keys
|
|
14
|
+
|
|
15
|
+
curchart = newchart
|
|
16
|
+
end
|
|
17
|
+
curchart
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class String122ResultSelector
|
|
5
|
+
def initialize(pm, sum)
|
|
6
|
+
@pm = pm
|
|
7
|
+
@sum = sum
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def chart
|
|
11
|
+
@chart ||= @pm.soplist.map do |k, v|
|
|
12
|
+
{
|
|
13
|
+
columns: k,
|
|
14
|
+
product: v
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def sum_list
|
|
20
|
+
@sum.str.split("+").map do |term|
|
|
21
|
+
term.split("").map do |str122|
|
|
22
|
+
idx = str122.ord - 48
|
|
23
|
+
chart[idx][:product]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def sum_strings
|
|
29
|
+
sum_list.each_with_index.map { |x, i| { str: x.join("+"), idx: i } }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def shortest
|
|
33
|
+
idx = sum_strings.min_by { |x| x[:str].length }[:idx]
|
|
34
|
+
SumOfProducts.new(sum_list[idx])
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/lm/sum.rb
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class Sum
|
|
5
|
+
attr_reader :str
|
|
6
|
+
|
|
7
|
+
def initialize(str)
|
|
8
|
+
@str = str
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def product_list
|
|
12
|
+
@str.split("+").map { |x| Set.new(x.split("")) }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def by_length
|
|
16
|
+
product_list.sort(&:length)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def reduce
|
|
20
|
+
res = []
|
|
21
|
+
arr = by_length
|
|
22
|
+
|
|
23
|
+
loop do
|
|
24
|
+
cur = arr.shift
|
|
25
|
+
|
|
26
|
+
newarr = []
|
|
27
|
+
arr.each do |x|
|
|
28
|
+
# remove supersets (X + XY = X)
|
|
29
|
+
next if cur.subset?(x)
|
|
30
|
+
|
|
31
|
+
newarr << x
|
|
32
|
+
end
|
|
33
|
+
res << cur
|
|
34
|
+
arr = newarr
|
|
35
|
+
|
|
36
|
+
break if arr.length.zero?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
res
|
|
40
|
+
Sum.new(res.map { |x| x.to_a.join("") }.join("+"))
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class SumOfProducts
|
|
5
|
+
attr_reader :arr
|
|
6
|
+
|
|
7
|
+
def initialize(arr = [])
|
|
8
|
+
@arr = arr
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def <<(value)
|
|
12
|
+
insert(value)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def insert(product)
|
|
16
|
+
@arr << product
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def implicants
|
|
20
|
+
result = {}
|
|
21
|
+
@arr.each do |x|
|
|
22
|
+
result[x.str.to_i(2).to_s] = x.str
|
|
23
|
+
end
|
|
24
|
+
ImplicantChart.new(result, length: @arr.first.str.length)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_s(v = nil)
|
|
28
|
+
joiner = "+"
|
|
29
|
+
joiner = " | " if v == :verilog || (v.is_a?(Hash) && v[:verilog])
|
|
30
|
+
@arr.map { |x| x.to_s(v) }.join(joiner)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
data/lib/lm/variable.rb
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lm
|
|
4
|
+
class Variable
|
|
5
|
+
attr_reader :value
|
|
6
|
+
|
|
7
|
+
def initialize(value, pos)
|
|
8
|
+
@value = value
|
|
9
|
+
@pos = pos
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def invalid?
|
|
13
|
+
@value != "1" && @value != "0"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def notop
|
|
17
|
+
@value == "0" ? "~" : ""
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def bar
|
|
21
|
+
@value == "0" ? "\u0305" : ""
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def subscript
|
|
25
|
+
result = ""
|
|
26
|
+
|
|
27
|
+
@pos.to_s.split("").each do |digit|
|
|
28
|
+
result += (0x2080 + digit.to_i).chr("UTF-8")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
LETTERS = %(ABCDEFGHJKLMNPQRSTUVWXYZ)
|
|
35
|
+
|
|
36
|
+
def to_abc(letters = LETTERS)
|
|
37
|
+
return to_x if @pos >= letters.length
|
|
38
|
+
return "" if invalid?
|
|
39
|
+
|
|
40
|
+
letters[@pos] + bar
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def to_x(input = "X")
|
|
44
|
+
return "" if invalid?
|
|
45
|
+
|
|
46
|
+
input.to_s + bar + subscript
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_verilog(letter)
|
|
50
|
+
return nil if invalid?
|
|
51
|
+
|
|
52
|
+
"#{notop}#{letter}[#{@pos}]"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_s(input = nil)
|
|
56
|
+
input ||= LETTERS
|
|
57
|
+
if input.is_a?(String) && input.end_with?("#")
|
|
58
|
+
to_x(input[0])
|
|
59
|
+
elsif input == :verilog
|
|
60
|
+
to_verilog(x)
|
|
61
|
+
elsif input.is_a?(Hash) && input[:verilog]
|
|
62
|
+
to_verilog(input[:verilog])
|
|
63
|
+
else
|
|
64
|
+
to_abc(input)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/lib/lm/version.rb
ADDED
data/lib/lm.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "set"
|
|
4
|
+
|
|
5
|
+
module Lm
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
require_relative "lm/version"
|
|
10
|
+
require_relative "lm/variable"
|
|
11
|
+
require_relative "lm/product"
|
|
12
|
+
require_relative "lm/implicant_chart"
|
|
13
|
+
require_relative "lm/quine_mc_cluskey"
|
|
14
|
+
require_relative "lm/sum_of_products"
|
|
15
|
+
require_relative "lm/petrick"
|
|
16
|
+
require_relative "lm/output_string"
|
|
17
|
+
require_relative "lm/pos"
|
|
18
|
+
require_relative "lm/sum"
|
|
19
|
+
require_relative "lm/string_122_result_selector"
|
|
20
|
+
require_relative "lm/bin_func"
|
|
21
|
+
require_relative "lm/minimizer"
|
data/lm.gemspec
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/lm/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "lm"
|
|
7
|
+
spec.version = Lm::VERSION
|
|
8
|
+
spec.authors = ["David Siaw"]
|
|
9
|
+
spec.email = ["davidsiaw@gmail.com"]
|
|
10
|
+
|
|
11
|
+
spec.summary = "Logic Minimizer"
|
|
12
|
+
spec.description = "Logic Minimizer Library"
|
|
13
|
+
spec.homepage = "https://github.com/davidsiaw/lm"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
|
18
|
+
|
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
20
|
+
spec.metadata["source_code_uri"] = "https://github.com/davidsiaw/lm"
|
|
21
|
+
spec.metadata["changelog_uri"] = "https://github.com/davidsiaw/lm"
|
|
22
|
+
|
|
23
|
+
spec.files = Dir["{data,exe,lib,bin}/**/*"] + %w[Gemfile lm.gemspec]
|
|
24
|
+
spec.test_files = Dir["spec/**/*"]
|
|
25
|
+
spec.bindir = "exe"
|
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
27
|
+
spec.require_paths = ["lib"]
|
|
28
|
+
|
|
29
|
+
# Uncomment to register a new dependency of your gem
|
|
30
|
+
# spec.add_dependency "example-gem", "~> 1.0"
|
|
31
|
+
|
|
32
|
+
# For more information and examples about making a new gem, check out our
|
|
33
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
|
34
|
+
end
|
data/spec/lm_spec.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Lm do
|
|
4
|
+
it "has a version number" do
|
|
5
|
+
expect(Lm::VERSION).not_to be nil
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "returns expected xor" do
|
|
9
|
+
min = Lm::Minimizer.new("0110")
|
|
10
|
+
expect(min.evaluate(0)).to eq 0
|
|
11
|
+
expect(min.evaluate(1)).to eq 1
|
|
12
|
+
expect(min.evaluate(2)).to eq 1
|
|
13
|
+
expect(min.evaluate(3)).to eq 0
|
|
14
|
+
expect(min.shortest.to_s(verilog: "a")).to eq "~a[0] & a[1] | a[0] & ~a[1]"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "returns expected and" do
|
|
18
|
+
min = Lm::Minimizer.new("0001")
|
|
19
|
+
expect(min.evaluate(0)).to eq 0
|
|
20
|
+
expect(min.evaluate(1)).to eq 0
|
|
21
|
+
expect(min.evaluate(2)).to eq 0
|
|
22
|
+
expect(min.evaluate(3)).to eq 1
|
|
23
|
+
expect(min.shortest.to_s(verilog: "a")).to eq "a[0] & a[1]"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "returns expected or" do
|
|
27
|
+
min = Lm::Minimizer.new("0111")
|
|
28
|
+
expect(min.shortest.to_s(verilog: "a")).to eq "a[1] | a[0]"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "returns expected nand" do
|
|
32
|
+
min = Lm::Minimizer.new("1110")
|
|
33
|
+
expect(min.shortest.to_s(verilog: "a")).to eq "~a[0] | ~a[1]"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "return canonical" do
|
|
37
|
+
min = Lm::Minimizer.new("1110")
|
|
38
|
+
expect(min.canonical.to_s(verilog: "a")).to eq "~a[0] & ~a[1] | ~a[0] & a[1] | a[0] & ~a[1]"
|
|
39
|
+
end
|
|
40
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lm"
|
|
4
|
+
|
|
5
|
+
RSpec.configure do |config|
|
|
6
|
+
# Enable flags like --only-failures and --next-failure
|
|
7
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
|
8
|
+
|
|
9
|
+
# Disable RSpec exposing methods globally on `Module` and `main`
|
|
10
|
+
config.disable_monkey_patching!
|
|
11
|
+
|
|
12
|
+
config.expect_with :rspec do |c|
|
|
13
|
+
c.syntax = :expect
|
|
14
|
+
end
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lm
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- David Siaw
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2022-12-23 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Logic Minimizer Library
|
|
14
|
+
email:
|
|
15
|
+
- davidsiaw@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- Gemfile
|
|
21
|
+
- bin/console
|
|
22
|
+
- bin/setup
|
|
23
|
+
- lib/lm.rb
|
|
24
|
+
- lib/lm/bin_func.rb
|
|
25
|
+
- lib/lm/implicant_chart.rb
|
|
26
|
+
- lib/lm/minimizer.rb
|
|
27
|
+
- lib/lm/output_string.rb
|
|
28
|
+
- lib/lm/petrick.rb
|
|
29
|
+
- lib/lm/pos.rb
|
|
30
|
+
- lib/lm/product.rb
|
|
31
|
+
- lib/lm/quine_mc_cluskey.rb
|
|
32
|
+
- lib/lm/string_122_result_selector.rb
|
|
33
|
+
- lib/lm/sum.rb
|
|
34
|
+
- lib/lm/sum_of_products.rb
|
|
35
|
+
- lib/lm/variable.rb
|
|
36
|
+
- lib/lm/version.rb
|
|
37
|
+
- lm.gemspec
|
|
38
|
+
- spec/lm_spec.rb
|
|
39
|
+
- spec/spec_helper.rb
|
|
40
|
+
homepage: https://github.com/davidsiaw/lm
|
|
41
|
+
licenses:
|
|
42
|
+
- MIT
|
|
43
|
+
metadata:
|
|
44
|
+
allowed_push_host: https://rubygems.org
|
|
45
|
+
homepage_uri: https://github.com/davidsiaw/lm
|
|
46
|
+
source_code_uri: https://github.com/davidsiaw/lm
|
|
47
|
+
changelog_uri: https://github.com/davidsiaw/lm
|
|
48
|
+
post_install_message:
|
|
49
|
+
rdoc_options: []
|
|
50
|
+
require_paths:
|
|
51
|
+
- lib
|
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: 2.6.0
|
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
requirements: []
|
|
63
|
+
rubygems_version: 3.2.3
|
|
64
|
+
signing_key:
|
|
65
|
+
specification_version: 4
|
|
66
|
+
summary: Logic Minimizer
|
|
67
|
+
test_files:
|
|
68
|
+
- spec/lm_spec.rb
|
|
69
|
+
- spec/spec_helper.rb
|