Created
October 12, 2018 22:02
-
-
Save coldnebo/0d72096caae07f36a665162eaabfb118 to your computer and use it in GitHub Desktop.
playing around with recomposing predicates.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'csv' | |
class BooleanFunction | |
attr_reader :inputs, :input_values, :output, :output_values | |
BOOLEAN_SET = [true, false] | |
def initialize( inputs:, output: nil ) | |
raise ArgumentError, "inputs must be an Enumerable of symbols" if (!inputs.kind_of?(Enumerable) || !inputs.map{|e| e.is_a?(Symbol) }.reduce(:&)) | |
@output = output | |
@output = :output if output.nil? | |
@inputs = inputs | |
@input_values = BOOLEAN_SET.repeated_permutation(@inputs.count).to_a | |
@output_values = Array.new(@input_values.count) | |
nil | |
end | |
def table | |
input_values.zip(output_values).map{|e| e.flatten } | |
end | |
def output_values=(ary) | |
raise ArgumentError, "output_values must be an Enumerable of booleans" if (!ary.kind_of?(Enumerable) || !ary.map{|e| e.is_a?(TrueClass) || e.is_a?(FalseClass) }.reduce(:&)) | |
raise ArgumentError, "output_values must be the same size as input_values (#{input_values.count})" if ary.count != input_values.count | |
@output_values = ary | |
end | |
def shorthand(ary) | |
ary.map{|e| | |
case | |
when e == true | |
"T" | |
when e == false | |
"F" | |
else | |
"?" | |
end | |
} | |
end | |
def logical(ary, mode:) | |
ary.each_with_index.map{|e, i| | |
v = inputs[i] | |
case mode | |
when :high | |
e ? "#{v}" : "!#{v}" | |
when :low | |
e ? "!#{v}" : "#{v}" | |
end | |
} | |
end | |
def to_csv | |
CSV.generate do |csv| | |
# headers | |
csv << inputs + [output] | |
# values | |
table.each {|r| csv << shorthand(r) } | |
end | |
end | |
def sum_of_products | |
raise ArgumentError, "output_values must be an Enumerable of booleans before using" if (!output_values.kind_of?(Enumerable) || !output_values.map{|e| e.is_a?(TrueClass) || e.is_a?(FalseClass) }.reduce(:&)) | |
hi_outputs = output_values.each_with_index.map{|v, i| logical(input_values[i], mode: :high) if v }.compact | |
conjunctions = hi_outputs.map{|e| "(" + e.join(" && ") + ")" } | |
disjuctions = conjunctions.join(" || ") | |
end | |
def product_of_sums | |
raise ArgumentError, "output_values must be an Enumerable of booleans before using" if (!output_values.kind_of?(Enumerable) || !output_values.map{|e| e.is_a?(TrueClass) || e.is_a?(FalseClass) }.reduce(:&)) | |
lo_outputs = output_values.each_with_index.map{|v, i| logical(input_values[i], mode: :low) if !v }.compact | |
disjuctions = lo_outputs.map{|e| "(" + e.join(" || ") + ")" } | |
conjunctions = disjuctions.join(" && ") | |
end | |
def test(&block) | |
test_outs = input_values.map{|ins| | |
yield(*ins) | |
} | |
end | |
def compare(expected:, actual:, truthy: true) | |
if truthy | |
puts expected.zip(actual).map{|p| (p[0] ? (true == true && p[1]) : (false == false || p[1])) ? "." : "F (expected #{p[0].inspect}, got #{p[1].inspect})"}.join("") | |
else | |
puts expected.zip(actual).map{|p| p[0] == p[1] ? "." : "F (expected #{p[0].inspect}, got #{p[1].inspect})"}.join("") | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
f = BooleanFunction.new(inputs: %i(a b c), output: :d ) | |
f.output_values = [false, false, false, true, false, false, false, false] | |
puts f.product_of_sums | |
# (!a || !b || !c) && (!a || !b || c) && (!a || b || !c) && (a || !b || !c) && (a || !b || c) && (a || b || !c) && (a || b || c) | |
puts f.sum_of_products | |
# (a && !b && !c) | |
touts = f.test{|a,b,c| | |
(a && !b && !c) | |
} | |
f.compare( expected: f.output_values, actual: touts ) | |
# ........ | |
touts = f.test{|a,b,c| | |
if a | |
!b && !c | |
end | |
} | |
f.compare( expected: f.output_values, actual: touts ) | |
# ........ | |
f.compare( expected: f.output_values, actual: touts, truthy: false ) | |
# ....F (expected false, got nil)F (expected false, got nil)F (expected false, got nil)F (expected false, got nil) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment