quine_mc 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/bin/quine_mc +21 -0
- data/lib/quine_mc.rb +41 -0
- data/lib/quine_mc/.DS_Store +0 -0
- data/lib/quine_mc/cube.rb +39 -0
- data/lib/quine_mc/epi_list.rb +80 -0
- data/lib/quine_mc/pi_list.rb +59 -0
- data/lib/quine_mc/version.rb +3 -0
- data/quine_mc.gemspec +24 -0
- metadata +58 -0
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/quine_mc
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'quine_mc'
|
3
|
+
|
4
|
+
puts "Welcome. This is Erik Formella's Quine McClusky Logic Minimizer."
|
5
|
+
puts
|
6
|
+
puts "Eneter the minterms of your function. Exclude dont cares"
|
7
|
+
|
8
|
+
minterms = gets.chomp
|
9
|
+
m_a = minterms.scan(/\d+/).map {|x| x.to_i}
|
10
|
+
|
11
|
+
puts "Now enter the don't cares please"
|
12
|
+
dont_cares = gets.chomp
|
13
|
+
dc_a = dont_cares.scan(/\d+/).map {|x| x.to_i}
|
14
|
+
|
15
|
+
solution = QuineMc::Quine_McClusky.new(m_a, dc_a)
|
16
|
+
puts
|
17
|
+
puts
|
18
|
+
puts "The solution for:"
|
19
|
+
print "f = m(", minterms, ") + d(", dont_cares, ") is:"
|
20
|
+
puts
|
21
|
+
solution.display_sol
|
data/lib/quine_mc.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require "quine_mc/version"
|
2
|
+
require 'quine_mc/epi_list'
|
3
|
+
|
4
|
+
module QuineMc
|
5
|
+
class Quine_McClusky
|
6
|
+
|
7
|
+
def initialize(m, d)
|
8
|
+
@nl = find_num_lit(m, d)
|
9
|
+
if (m+d) == (0..2**(@nl)-1).to_a or (m+d).empty?
|
10
|
+
@sop = []
|
11
|
+
@pos = []
|
12
|
+
else
|
13
|
+
maxterms = (0...2**@nl).to_a - (m+d)
|
14
|
+
@sop = EPi_List.new(m, d, @nl)
|
15
|
+
@pos = EPi_List.new(maxterms, d, @nl)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_num_lit(m, d)
|
20
|
+
return (m+d).max.to_s(2).size
|
21
|
+
end
|
22
|
+
|
23
|
+
def display_sol
|
24
|
+
if !@sop.empty? and !@pos.empty?
|
25
|
+
print "f = "
|
26
|
+
@sop.each do |t|
|
27
|
+
print (t == @sop.last)? t.to_prod(@nl) : t.to_prod(@nl)+" + "
|
28
|
+
end
|
29
|
+
puts
|
30
|
+
print "f = "
|
31
|
+
@pos.each do |t|
|
32
|
+
print t.to_sum(@nl)
|
33
|
+
end
|
34
|
+
puts
|
35
|
+
else
|
36
|
+
puts "f = 1"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
Binary file
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module QuineMc
|
2
|
+
class Cube < Array
|
3
|
+
|
4
|
+
def num_ones
|
5
|
+
n = inject {|m,o| m & o}
|
6
|
+
count = 0
|
7
|
+
count += n & 1 and n >>= 1 until n == 0
|
8
|
+
return count
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_prod(n_l)
|
12
|
+
ls = (n_l > 26)? (0..n_l).to_a.map {|n| n = "A" << n.to_s} : ('A'..'Z').to_a[0,n_l]
|
13
|
+
p = ""
|
14
|
+
ls.each_with_index do |l, i|
|
15
|
+
if all? {|x| first[n_l-i-1] == x[n_l-i-1]}
|
16
|
+
p << (first[n_l-i-1] == 1 ? l : l+"'")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
return p
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_sum(n_l)
|
23
|
+
ls = (n_l > 26)? (0..n_l).to_a.map {|n| n = "A" << n.to_s} : ('A'..'Z').to_a[0,n_l]
|
24
|
+
s = "("
|
25
|
+
ls.each_with_index do |l, i|
|
26
|
+
if all? {|x| first[n_l-i-1] == x[n_l-i-1]}
|
27
|
+
s << (first[n_l-i-1] == 1 ? l+"'+" : l+"+")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
s[s.size-1] = ")"
|
31
|
+
return s
|
32
|
+
end
|
33
|
+
|
34
|
+
def strict_subset?(b)
|
35
|
+
self & b == self and length < b.length
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'quine_mc/pi_list'
|
2
|
+
|
3
|
+
module QuineMc
|
4
|
+
|
5
|
+
class EPi_List < Array
|
6
|
+
attr_accessor :pi_table, :pi_list
|
7
|
+
|
8
|
+
def initialize(m, d, n_l)
|
9
|
+
@n_l = n_l
|
10
|
+
@pi_list = Pi_List.new(m, d)
|
11
|
+
get_solution(m)
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_solution(m)
|
15
|
+
@pi_table = Hash.new {|h,k| h[k] = @pi_list.reject {|e| !e.include?(k)}}
|
16
|
+
m.each {|i| @pi_table[i]}
|
17
|
+
reduce
|
18
|
+
end
|
19
|
+
|
20
|
+
def reduce
|
21
|
+
(@pi_table.empty?)? (return true) : size = 0
|
22
|
+
|
23
|
+
while size != @pi_table.size
|
24
|
+
size = @pi_table.size
|
25
|
+
@pi_table.each do |k,v|
|
26
|
+
if v.length == 1
|
27
|
+
push(v[0])
|
28
|
+
v[0].each {|i| @pi_table.delete(i)}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
(@pi_table.empty?)? (return true) : dominated_rows
|
34
|
+
end
|
35
|
+
|
36
|
+
def dominated_rows
|
37
|
+
removed = false
|
38
|
+
#puts @pi_table.inspect
|
39
|
+
(@pi_table.values.flatten(1) - self).each do |c1|
|
40
|
+
(@pi_table.values.flatten(1) - self).each do |c2|
|
41
|
+
if QuineMc::Cube.new(c1 & @pi_table.keys).strict_subset?(Cube.new(c2 & @pi_table.keys))
|
42
|
+
@pi_table.each {|k,v| v.delete_if {|i| i == c1}}
|
43
|
+
removed = true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
(removed)? reduce : petrick
|
48
|
+
end
|
49
|
+
|
50
|
+
def petrick
|
51
|
+
cube_i = Hash[@pi_table.values.flatten(1).uniq.zip((0...@pi_table.values.flatten(1).uniq.length).to_a)]
|
52
|
+
product = []
|
53
|
+
@pi_table.each do |k,v|
|
54
|
+
temp = []
|
55
|
+
v.each {|x| temp << cube_i[x]}
|
56
|
+
product << temp
|
57
|
+
end
|
58
|
+
choices = expand_s(product).uniq
|
59
|
+
cube_i = cube_i.invert
|
60
|
+
answer = choices.min {|a,b| cost(a, cube_i) <=> cost(b, cube_i)}
|
61
|
+
answer.each {|i| push(cube_i[i])}
|
62
|
+
end
|
63
|
+
|
64
|
+
def cost(c, h)
|
65
|
+
price = c.size
|
66
|
+
c.each {|i| price += @n_l - Math.log(h[i].length)/Math.log(2)}
|
67
|
+
return price
|
68
|
+
end
|
69
|
+
|
70
|
+
def expand_s (sum)
|
71
|
+
expand_r(sum).each {|x| x.flatten!; x.sort!; x.uniq!}
|
72
|
+
end
|
73
|
+
|
74
|
+
def expand_r(exp)
|
75
|
+
if exp.length == 1 then return [[exp[0][0]],[exp[0][1]]] end
|
76
|
+
exp.length == 2 ? exp[0].product(exp[1]) : exp[0].product(expand_r(exp[1..exp.length]))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'quine_mc/cube'
|
2
|
+
|
3
|
+
module QuineMc
|
4
|
+
class Pi_List < Array
|
5
|
+
|
6
|
+
def initialize(m, d)
|
7
|
+
@cube_table = order_terms((m + d).sort)
|
8
|
+
#puts @cube_table.inspect
|
9
|
+
get_pis()
|
10
|
+
end
|
11
|
+
|
12
|
+
#orders terms by number of set bits
|
13
|
+
def order_terms(uo_terms)
|
14
|
+
h = {}
|
15
|
+
uo_terms.each do |t|
|
16
|
+
t = Cube.new([t])
|
17
|
+
b = t.num_ones
|
18
|
+
h[b] = h[b] || Array.new
|
19
|
+
h[b].push(t)
|
20
|
+
end
|
21
|
+
return h
|
22
|
+
end
|
23
|
+
|
24
|
+
def power_of_2?(x)
|
25
|
+
((x != 0) and (x & (x-1) == 0))
|
26
|
+
end
|
27
|
+
|
28
|
+
def makes_cube?(a, b)
|
29
|
+
a.zip(b).all? { |x,y| power_of_2?(y-x) } and a.all? {|x| b.all? {|y| y>x} }
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def get_pis()
|
34
|
+
next_table = {}
|
35
|
+
while !@cube_table.empty?
|
36
|
+
#puts @cube_table.inspect
|
37
|
+
@cube_table.each do |k,v|
|
38
|
+
if v
|
39
|
+
v.each do |c1|
|
40
|
+
if @cube_table[k+1]
|
41
|
+
@cube_table[k+1].each do |c2|
|
42
|
+
if makes_cube?(c1, c2)
|
43
|
+
if !next_table[k] then next_table[k] = [] end
|
44
|
+
next_table[k].push(Cube.new(c1+c2))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
if c1.any? {|x| !next_table.values.flatten.include?(x)} then push(Cube.new(c1)) end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
@cube_table = next_table
|
53
|
+
next_table = {}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
data/quine_mc.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "quine_mc/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "quine_mc"
|
7
|
+
s.version = QuineMc::VERSION
|
8
|
+
s.authors = ["Erik Formella"]
|
9
|
+
s.email = ["erik.formella@tufts.edu"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Quine-McCluskey algorithm}
|
12
|
+
s.description = %q{Pretty much only for command line use}
|
13
|
+
|
14
|
+
s.rubyforge_project = "quine_mc"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: quine_mc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Erik Formella
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-06 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Pretty much only for command line use
|
15
|
+
email:
|
16
|
+
- erik.formella@tufts.edu
|
17
|
+
executables:
|
18
|
+
- quine_mc
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .DS_Store
|
23
|
+
- .gitignore
|
24
|
+
- Gemfile
|
25
|
+
- Rakefile
|
26
|
+
- bin/quine_mc
|
27
|
+
- lib/quine_mc.rb
|
28
|
+
- lib/quine_mc/.DS_Store
|
29
|
+
- lib/quine_mc/cube.rb
|
30
|
+
- lib/quine_mc/epi_list.rb
|
31
|
+
- lib/quine_mc/pi_list.rb
|
32
|
+
- lib/quine_mc/version.rb
|
33
|
+
- quine_mc.gemspec
|
34
|
+
homepage: ''
|
35
|
+
licenses: []
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project: quine_mc
|
54
|
+
rubygems_version: 1.8.15
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Quine-McCluskey algorithm
|
58
|
+
test_files: []
|