class TruthTable
truth table and formula generator from Ruby block¶ ↑
The truthtable library generates a truth table from a logical formula written in Ruby. The truth table can be converted to a logical formula.
Author¶ ↑
Tanaka Akira <akr@fsij.org>
Feature¶ ↑
-
generate a truth table from a given block which contains logical formula written in Ruby.
-
generate a formula from the table:
-
minimal one (obtained by Quine-McCluskey algorithm)
-
disjunctive normal form
-
conjunctive normal form
-
Usage¶ ↑
-
require
require 'truthtable'
-
puts, p and pp shows truth table
puts TruthTable.new {|v| v[0] & v[1] } #=> v[0] v[1] | ----------+-- f f | f f t | f t f | f t t | t p TruthTable.new {|v| v[0] & v[1] } #=> #<TruthTable: !v[0]&!v[1]=>false !v[0]&v[1]=>false v[0]&!v[1]=>false v[0]&v[1]=>true> require 'pp' pp TruthTable.new {|v| v[0] & v[1] } #=> #<TruthTable: !v[0]&!v[1]=>false !v[0]& v[1]=>false v[0]&!v[1]=>false v[0]& v[1]=>true>
-
formula generation
p TruthTable.new {|v| v[0] }.formula #=>"v[0]" p TruthTable.new {|v| !v[0] }.formula #=> "!v[0]" p TruthTable.new {|v| true ^ v[0] }.formula #=> "!v[0]" p TruthTable.new {|v| v[0] & v[1] }.formula #=> "v[0]&v[1]" p TruthTable.new {|v| v[0] | v[1] }.formula #=> "v[0] | v[1]" p TruthTable.new {|v| v[0] ^ v[1] }.formula #=> "!v[0]&v[1] | v[0]&!v[1]" p TruthTable.new {|v| v[0] == v[1] }.formula #=> "!v[0]&!v[1] | v[0]&v[1]"
-
shortcuts, && and ||, are also usable but converted to & and |
p TruthTable.new {|v| v[0] && v[1] }.formula #=> "v[0]&v[1]" p TruthTable.new {|v| v[0] || v[1] }.formula #=> "v[0] | v[1]"
-
actually any expression (without side effect)
p TruthTable.new {|v| v[0] ? !v[1] : v[1] }.formula #=> "!v[0]&v[1] | v[0]&!v[1]"
-
any number of inputs
p TruthTable.new {|v| [v[0], v[1], v[2], v[3]].grep(true).length <= 3 }.formula #=> "!v[0] | !v[1] | !v[2] | !v[3]"
truthtable/qm.rb - Quine-McCluskey algorithm
Copyright (C) 2007 Tanaka Akira <akr@fsij.org>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-
The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR “AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Public Class Methods
# File truthtable.rb, line 156 def initialize(&b) table = TruthTable.test(&b) @table = table end
# File truthtable.rb, line 144 def self.test(&b) r = [] o = TruthTableObject.new begin result = !!b.call(o) inputs = o.plan order = o.order r << [inputs, result, order] end while o.next_plan r end
Public Instance Methods
obtains a formula in conjunctive normal form.
# File truthtable.rb, line 275 def cnf r = [] @table.each {|inputs, output| return output.to_s if inputs.empty? next if output term = [] each_input(inputs) {|name, input| if input term << "!#{name}" else term << name end } if term.length == 1 r << term.join('|') else r << "(#{term.join('|')})" end } return "true" if r.empty? r.join(' & ') end
obtains a formula in disjunctive normal form.
# File truthtable.rb, line 255 def dnf r = [] @table.each {|inputs, output| return output.to_s if inputs.empty? next if !output term = [] each_input(inputs) {|name, input| if input term << name else term << "!#{name}" end } r << term.join('&') } return "false" if r.empty? r.join(' | ') end
obtains a minimal formula using Quine-McCluskey algorithm.
# File truthtable.rb, line 299 def formula input_names = all_names input_names_ary = sort_names(input_names.keys) tbl = {} @table.each {|inputs, output| return output.to_s if inputs.empty? inputs2 = [:x] * input_names.length inputs.each {|name, input| inputs2[input_names[name]] = input ? 1 : 0 } tbl[inputs2] = output ? 1 : 0 } qm = QM.qm(tbl) r = [] qm.each {|term| t = [] num_dontcare = 0 term.each_with_index {|v, i| if v == false t << ("!" + input_names_ary[i]) elsif v == true t << input_names_ary[i] else # :x num_dontcare += 1 end } if num_dontcare == term.length r << 'true' else r << t.join('&') end } return "false" if r.empty? r.join(' | ') end
# File truthtable.rb, line 161 def to_s r = '' names = sort_names(all_names.keys) format = '' sep = '' names.each {|name| format << "%-#{name.length}s " sep << '-' * (name.length+1) } format << "| %s\n" sep << "+--\n" r << sprintf(format, *(names + [''])) r << sep @table.each {|inputs, output, order| h = {} each_input(inputs) {|name, input| h[name] = input } args = [] names.each {|name| if h.has_key? name args << (h[name] ? 't' : 'f').center(name.length) else args << '?'.center(name.length) end } args << (output ? 't' : 'f') r << sprintf(format, *args) } r end