boolean_simplifier 1.0.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.
- data/README.md +36 -0
- data/lib/boolean_simplifier.rb +20 -0
- data/lib/boolean_simplifier/base.rb +12 -0
- data/lib/boolean_simplifier/expression.rb +22 -0
- data/lib/boolean_simplifier/expression/conjunction.rb +14 -0
- data/lib/boolean_simplifier/expression/disjunction.rb +11 -0
- data/lib/boolean_simplifier/expression/negation.rb +12 -0
- data/lib/boolean_simplifier/expression_parser.rb +16 -0
- data/lib/boolean_simplifier/expression_simplifier.rb +39 -0
- data/lib/boolean_simplifier/grammar/boolean_expression.treetop +71 -0
- data/lib/boolean_simplifier/rule.rb +7 -0
- data/lib/boolean_simplifier/rule/absorbtion.rb +28 -0
- data/lib/boolean_simplifier/rule/annihilator.rb +25 -0
- data/lib/boolean_simplifier/rule/complementation.rb +25 -0
- data/lib/boolean_simplifier/rule/de_morgans.rb +31 -0
- data/lib/boolean_simplifier/rule/distributivity.rb +31 -0
- data/lib/boolean_simplifier/rule/double_negation.rb +17 -0
- data/lib/boolean_simplifier/rule/idempotence.rb +12 -0
- data/lib/boolean_simplifier/rule/identity.rb +25 -0
- metadata +111 -0
    
        data/README.md
    ADDED
    
    | @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            ## Boolean Simplifier
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            A hobbyist's attempt to simplify boolean expressions using a recursive, object-oriented strategy.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Usage
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ```ruby
         | 
| 8 | 
            +
            puts BooleanSimplifier.simplify("a && a || !!b")
         | 
| 9 | 
            +
            # a || b
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            puts BooleanSimplifier.simplify("a && !a")
         | 
| 12 | 
            +
            # false
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            puts BooleanSimplifier.simplify("!a || !b && (true || false)")
         | 
| 15 | 
            +
            # !(a && b)
         | 
| 16 | 
            +
            ```
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            ## How it works
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            The boolean expression is parsed and an object graph is constructed. This graph consists of instances of Negation, Conjunction, Disjunction. It also contains literal strings.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            A set of boolean simplification rules is applied to the expression and recursively to its subexpressions. These rules take an arbitrary expression as input and return a new expression if the rule applies. If not, the original expression is returned.
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            The base case for this recursive algorithm is when no improvement is made to the given expression after iterating through all simplification rules.
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ## Limitations
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            Ruby does not implement tail recursion. Therefore, you may run into a SystemStackError when simplifying large expressions.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            I haven't figured out every simplification rule, or the most efficient way to apply them. Therefore, you may find that some expressions are only partially simplified.
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            ## Contribution
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Open an issue, or send a pull request. I'd appreciate all feedback.
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            [Twitter](https://twitter.com/cpatuzzo)
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require "treetop"
         | 
| 2 | 
            +
            require "polyglot"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require "boolean_simplifier/base"
         | 
| 5 | 
            +
            require "boolean_simplifier/expression"
         | 
| 6 | 
            +
            require "boolean_simplifier/expression/conjunction"
         | 
| 7 | 
            +
            require "boolean_simplifier/expression/disjunction"
         | 
| 8 | 
            +
            require "boolean_simplifier/expression/negation"
         | 
| 9 | 
            +
            require "boolean_simplifier/expression_parser"
         | 
| 10 | 
            +
            require "boolean_simplifier/expression_simplifier"
         | 
| 11 | 
            +
            require "boolean_simplifier/grammar/boolean_expression"
         | 
| 12 | 
            +
            require "boolean_simplifier/rule"
         | 
| 13 | 
            +
            require "boolean_simplifier/rule/absorbtion"
         | 
| 14 | 
            +
            require "boolean_simplifier/rule/annihilator"
         | 
| 15 | 
            +
            require "boolean_simplifier/rule/complementation"
         | 
| 16 | 
            +
            require "boolean_simplifier/rule/de_morgans"
         | 
| 17 | 
            +
            require "boolean_simplifier/rule/distributivity"
         | 
| 18 | 
            +
            require "boolean_simplifier/rule/double_negation"
         | 
| 19 | 
            +
            require "boolean_simplifier/rule/idempotence"
         | 
| 20 | 
            +
            require "boolean_simplifier/rule/identity"
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            class Expression
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              attr_accessor :parts
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def ==(other)
         | 
| 6 | 
            +
                to_s == other.to_s
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def to_s
         | 
| 10 | 
            +
                raise NotImplementedError
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              private
         | 
| 14 | 
            +
              def bracket(expression, *classes)
         | 
| 15 | 
            +
                if classes.include?(expression.class)
         | 
| 16 | 
            +
                  "(#{expression})"
         | 
| 17 | 
            +
                else
         | 
| 18 | 
            +
                  expression
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            module ExpressionParser
         | 
| 2 | 
            +
              def parse(string)
         | 
| 3 | 
            +
                parser = BooleanExpressionParser.new
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                ast = parser.parse(string)
         | 
| 6 | 
            +
                if ast.nil?
         | 
| 7 | 
            +
                  raise ParseError, parser.failure_reason
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                ast.to_expression
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              class ::ParseError < StandardError; end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              extend self
         | 
| 16 | 
            +
            end
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            module ExpressionSimplifier
         | 
| 2 | 
            +
              def simplify(expression)
         | 
| 3 | 
            +
                until_no_improvement(expression) do
         | 
| 4 | 
            +
                  simplify_parts(expression)
         | 
| 5 | 
            +
                  simplify_root(expression)
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              private
         | 
| 10 | 
            +
              def until_no_improvement(expression, &block)
         | 
| 11 | 
            +
                begin
         | 
| 12 | 
            +
                  break if trivial?(expression)
         | 
| 13 | 
            +
                  previous = expression.dup
         | 
| 14 | 
            +
                  expression = yield
         | 
| 15 | 
            +
                end until previous == expression
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                expression
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def simplify_parts(expression)
         | 
| 21 | 
            +
                expression.parts.each.with_index do |part, index|
         | 
| 22 | 
            +
                  expression.parts[index] = simplify(part)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              def simplify_root(expression)
         | 
| 27 | 
            +
                Rule.collection.each do |rule|
         | 
| 28 | 
            +
                  expression = rule.simplify(expression)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                expression
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def trivial?(expression)
         | 
| 35 | 
            +
                !expression.respond_to?(:parts)
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              extend self
         | 
| 39 | 
            +
            end
         | 
| @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            grammar BooleanExpression
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              rule expression
         | 
| 4 | 
            +
                space disjunctive space {
         | 
| 5 | 
            +
                  def to_expression
         | 
| 6 | 
            +
                    disjunctive.to_expression
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
                }
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              rule disjunctive
         | 
| 12 | 
            +
                a:conjunctive space "||" space b:disjunctive {
         | 
| 13 | 
            +
                  def to_expression
         | 
| 14 | 
            +
                    Disjunction.new(a.to_expression, b.to_expression)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                } /
         | 
| 17 | 
            +
                conjunctive
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              rule conjunctive
         | 
| 21 | 
            +
                a:negative space "&&" space b:conjunctive {
         | 
| 22 | 
            +
                  def to_expression
         | 
| 23 | 
            +
                    Conjunction.new(a.to_expression, b.to_expression)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                } /
         | 
| 26 | 
            +
                negative
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              rule negative
         | 
| 30 | 
            +
                "!" negative {
         | 
| 31 | 
            +
                  def to_expression
         | 
| 32 | 
            +
                    Negation.new(negative.to_expression)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                } /
         | 
| 35 | 
            +
                primary
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              rule primary
         | 
| 39 | 
            +
                boolean / variable / "(" expression ")" {
         | 
| 40 | 
            +
                  def to_expression
         | 
| 41 | 
            +
                    expression.to_expression
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                }
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              rule boolean
         | 
| 47 | 
            +
                "true" {
         | 
| 48 | 
            +
                  def to_expression
         | 
| 49 | 
            +
                    true
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                } /
         | 
| 52 | 
            +
                "false" {
         | 
| 53 | 
            +
                  def to_expression
         | 
| 54 | 
            +
                    false
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                }
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              rule variable
         | 
| 60 | 
            +
                [a-zA-Z0-9_]+ {
         | 
| 61 | 
            +
                  def to_expression
         | 
| 62 | 
            +
                    text_value
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                }
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              rule space
         | 
| 68 | 
            +
                " "*
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            module Absorbtion
         | 
| 2 | 
            +
              def simplify(expr)
         | 
| 3 | 
            +
                if expr.class == Conjunction
         | 
| 4 | 
            +
                  absorb_for_class(expr, Disjunction)
         | 
| 5 | 
            +
                elsif expr.class == Disjunction
         | 
| 6 | 
            +
                  absorb_for_class(expr, Conjunction)
         | 
| 7 | 
            +
                else
         | 
| 8 | 
            +
                  expr
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              private
         | 
| 13 | 
            +
              def absorb_for_class(expr, klass)
         | 
| 14 | 
            +
                [[0, 1], [1, 0]].each do |a, b|
         | 
| 15 | 
            +
                  if expr.parts[a].class == klass && contains?(expr.parts[a], expr.parts[b])
         | 
| 16 | 
            +
                    return expr.parts[b]
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
                expr
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              def contains?(a, b)
         | 
| 23 | 
            +
                a.parts[0] == b || a.parts[1] == b
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              extend self
         | 
| 27 | 
            +
              Rule.collection << self
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module Annihilator
         | 
| 2 | 
            +
              def simplify(expr)
         | 
| 3 | 
            +
                if expr.class == Conjunction
         | 
| 4 | 
            +
                  return_x_if_contains_x(expr, false)
         | 
| 5 | 
            +
                elsif expr.class == Disjunction
         | 
| 6 | 
            +
                  return_x_if_contains_x(expr, true)
         | 
| 7 | 
            +
                else
         | 
| 8 | 
            +
                  expr
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              private
         | 
| 13 | 
            +
              def return_x_if_contains_x(expr, x)
         | 
| 14 | 
            +
                if expr.parts[0] == x
         | 
| 15 | 
            +
                  x
         | 
| 16 | 
            +
                elsif expr.parts[1] == x
         | 
| 17 | 
            +
                  x
         | 
| 18 | 
            +
                else
         | 
| 19 | 
            +
                  expr
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              extend self
         | 
| 24 | 
            +
              Rule.collection << self
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module Complementation
         | 
| 2 | 
            +
              def simplify(expr)
         | 
| 3 | 
            +
                if expr.class == Conjunction
         | 
| 4 | 
            +
                  return_x_if_complementary(expr, false)
         | 
| 5 | 
            +
                elsif expr.class == Disjunction
         | 
| 6 | 
            +
                  return_x_if_complementary(expr, true)
         | 
| 7 | 
            +
                else
         | 
| 8 | 
            +
                  expr
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              private
         | 
| 13 | 
            +
              def return_x_if_complementary(expr, x)
         | 
| 14 | 
            +
                complementary_expressions?(expr) ? x : expr
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def complementary_expressions?(expr)
         | 
| 18 | 
            +
                [[0, 1], [1, 0]].any? do |a, b|
         | 
| 19 | 
            +
                  expr.parts[a] == Negation.new(expr.parts[b])
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              extend self
         | 
| 24 | 
            +
              Rule.collection << self
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            module DeMorgans
         | 
| 2 | 
            +
              def simplify(expr)
         | 
| 3 | 
            +
                if expr.class == Conjunction
         | 
| 4 | 
            +
                  apply_de_morgans(expr, Disjunction)
         | 
| 5 | 
            +
                elsif expr.class == Disjunction
         | 
| 6 | 
            +
                  apply_de_morgans(expr, Conjunction)
         | 
| 7 | 
            +
                else
         | 
| 8 | 
            +
                  expr
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              private
         | 
| 13 | 
            +
              def apply_de_morgans(expr, inner_class)
         | 
| 14 | 
            +
                if both_negation?(expr)
         | 
| 15 | 
            +
                  Negation.new(
         | 
| 16 | 
            +
                    inner_class.new(
         | 
| 17 | 
            +
                      expr.parts[0].parts[0],
         | 
| 18 | 
            +
                      expr.parts[1].parts[0])
         | 
| 19 | 
            +
                  )
         | 
| 20 | 
            +
                else
         | 
| 21 | 
            +
                  expr
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def both_negation?(expr)
         | 
| 26 | 
            +
                [0, 1].all? { |i| expr.parts[i].class == Negation }
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              extend self
         | 
| 30 | 
            +
              Rule.collection << self
         | 
| 31 | 
            +
            end
         | 
| @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            module Distributivity
         | 
| 2 | 
            +
              def simplify(expr)
         | 
| 3 | 
            +
                if expr.class == Conjunction
         | 
| 4 | 
            +
                  distribute(expr, Conjunction, Disjunction)
         | 
| 5 | 
            +
                elsif expr.class == Disjunction
         | 
| 6 | 
            +
                  distribute(expr, Disjunction, Conjunction)
         | 
| 7 | 
            +
                else
         | 
| 8 | 
            +
                  expr
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              private
         | 
| 13 | 
            +
              def distribute(expr, inner, outer)
         | 
| 14 | 
            +
                [[0, 1], [1, 0]].each do |a, b|
         | 
| 15 | 
            +
                  if expr.parts[a].class == outer && trivial?(expr.parts[b])
         | 
| 16 | 
            +
                    return outer.new(
         | 
| 17 | 
            +
                      inner.new(expr.parts[b], expr.parts[a].parts[0]),
         | 
| 18 | 
            +
                      inner.new(expr.parts[b], expr.parts[a].parts[1])
         | 
| 19 | 
            +
                    )
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                expr
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def trivial?(expr)
         | 
| 26 | 
            +
                !expr.respond_to?(:parts)
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              extend self
         | 
| 30 | 
            +
              Rule.collection << self
         | 
| 31 | 
            +
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            module DoubleNegation
         | 
| 2 | 
            +
              def simplify(expr)
         | 
| 3 | 
            +
                if negation?(expr) && negation?(expr.parts[0])
         | 
| 4 | 
            +
                  expr.parts[0].parts[0]
         | 
| 5 | 
            +
                else
         | 
| 6 | 
            +
                  expr
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              private
         | 
| 11 | 
            +
              def negation?(expr)
         | 
| 12 | 
            +
                expr.class == Negation
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              extend self
         | 
| 16 | 
            +
              Rule.collection << self
         | 
| 17 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module Identity
         | 
| 2 | 
            +
              def simplify(expr)
         | 
| 3 | 
            +
                if expr.class == Conjunction
         | 
| 4 | 
            +
                  return_part_if_contains_x(expr, true)
         | 
| 5 | 
            +
                elsif expr.class == Disjunction
         | 
| 6 | 
            +
                  return_part_if_contains_x(expr, false)
         | 
| 7 | 
            +
                else
         | 
| 8 | 
            +
                  expr
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              private
         | 
| 13 | 
            +
              def return_part_if_contains_x(expr, x)
         | 
| 14 | 
            +
                if expr.parts[0] == x
         | 
| 15 | 
            +
                  expr.parts[1]
         | 
| 16 | 
            +
                elsif expr.parts[1] == x
         | 
| 17 | 
            +
                  expr.parts[0]
         | 
| 18 | 
            +
                else
         | 
| 19 | 
            +
                  expr
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              extend self
         | 
| 24 | 
            +
              Rule.collection << self
         | 
| 25 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,111 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification
         | 
| 2 | 
            +
            name: boolean_simplifier
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            +
              version: 1.0.0
         | 
| 5 | 
            +
              prerelease: 
         | 
| 6 | 
            +
            platform: ruby
         | 
| 7 | 
            +
            authors:
         | 
| 8 | 
            +
            - Chris Patuzzo
         | 
| 9 | 
            +
            autorequire: 
         | 
| 10 | 
            +
            bindir: bin
         | 
| 11 | 
            +
            cert_chain: []
         | 
| 12 | 
            +
            date: 2013-11-17 00:00:00.000000000 Z
         | 
| 13 | 
            +
            dependencies:
         | 
| 14 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 15 | 
            +
              name: treetop
         | 
| 16 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 17 | 
            +
                none: false
         | 
| 18 | 
            +
                requirements:
         | 
| 19 | 
            +
                - - ! '>='
         | 
| 20 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            +
                    version: '0'
         | 
| 22 | 
            +
              type: :runtime
         | 
| 23 | 
            +
              prerelease: false
         | 
| 24 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 25 | 
            +
                none: false
         | 
| 26 | 
            +
                requirements:
         | 
| 27 | 
            +
                - - ! '>='
         | 
| 28 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 29 | 
            +
                    version: '0'
         | 
| 30 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 31 | 
            +
              name: polyglot
         | 
| 32 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 33 | 
            +
                none: false
         | 
| 34 | 
            +
                requirements:
         | 
| 35 | 
            +
                - - ! '>='
         | 
| 36 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 37 | 
            +
                    version: '0'
         | 
| 38 | 
            +
              type: :runtime
         | 
| 39 | 
            +
              prerelease: false
         | 
| 40 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 41 | 
            +
                none: false
         | 
| 42 | 
            +
                requirements:
         | 
| 43 | 
            +
                - - ! '>='
         | 
| 44 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 45 | 
            +
                    version: '0'
         | 
| 46 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 47 | 
            +
              name: rspec
         | 
| 48 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 49 | 
            +
                none: false
         | 
| 50 | 
            +
                requirements:
         | 
| 51 | 
            +
                - - ! '>='
         | 
| 52 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 53 | 
            +
                    version: '0'
         | 
| 54 | 
            +
              type: :development
         | 
| 55 | 
            +
              prerelease: false
         | 
| 56 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 57 | 
            +
                none: false
         | 
| 58 | 
            +
                requirements:
         | 
| 59 | 
            +
                - - ! '>='
         | 
| 60 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            +
                    version: '0'
         | 
| 62 | 
            +
            description: Simplify boolean expressions
         | 
| 63 | 
            +
            email: chris@patuzzo.co.uk
         | 
| 64 | 
            +
            executables: []
         | 
| 65 | 
            +
            extensions: []
         | 
| 66 | 
            +
            extra_rdoc_files: []
         | 
| 67 | 
            +
            files:
         | 
| 68 | 
            +
            - README.md
         | 
| 69 | 
            +
            - lib/boolean_simplifier/base.rb
         | 
| 70 | 
            +
            - lib/boolean_simplifier/expression/conjunction.rb
         | 
| 71 | 
            +
            - lib/boolean_simplifier/expression/disjunction.rb
         | 
| 72 | 
            +
            - lib/boolean_simplifier/expression/negation.rb
         | 
| 73 | 
            +
            - lib/boolean_simplifier/expression.rb
         | 
| 74 | 
            +
            - lib/boolean_simplifier/expression_parser.rb
         | 
| 75 | 
            +
            - lib/boolean_simplifier/expression_simplifier.rb
         | 
| 76 | 
            +
            - lib/boolean_simplifier/grammar/boolean_expression.treetop
         | 
| 77 | 
            +
            - lib/boolean_simplifier/rule/absorbtion.rb
         | 
| 78 | 
            +
            - lib/boolean_simplifier/rule/annihilator.rb
         | 
| 79 | 
            +
            - lib/boolean_simplifier/rule/complementation.rb
         | 
| 80 | 
            +
            - lib/boolean_simplifier/rule/de_morgans.rb
         | 
| 81 | 
            +
            - lib/boolean_simplifier/rule/distributivity.rb
         | 
| 82 | 
            +
            - lib/boolean_simplifier/rule/double_negation.rb
         | 
| 83 | 
            +
            - lib/boolean_simplifier/rule/idempotence.rb
         | 
| 84 | 
            +
            - lib/boolean_simplifier/rule/identity.rb
         | 
| 85 | 
            +
            - lib/boolean_simplifier/rule.rb
         | 
| 86 | 
            +
            - lib/boolean_simplifier.rb
         | 
| 87 | 
            +
            homepage: https://github.com/tuzz/boolean_simplifier
         | 
| 88 | 
            +
            licenses: []
         | 
| 89 | 
            +
            post_install_message: 
         | 
| 90 | 
            +
            rdoc_options: []
         | 
| 91 | 
            +
            require_paths:
         | 
| 92 | 
            +
            - lib
         | 
| 93 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 94 | 
            +
              none: false
         | 
| 95 | 
            +
              requirements:
         | 
| 96 | 
            +
              - - ! '>='
         | 
| 97 | 
            +
                - !ruby/object:Gem::Version
         | 
| 98 | 
            +
                  version: '0'
         | 
| 99 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 100 | 
            +
              none: false
         | 
| 101 | 
            +
              requirements:
         | 
| 102 | 
            +
              - - ! '>='
         | 
| 103 | 
            +
                - !ruby/object:Gem::Version
         | 
| 104 | 
            +
                  version: '0'
         | 
| 105 | 
            +
            requirements: []
         | 
| 106 | 
            +
            rubyforge_project: 
         | 
| 107 | 
            +
            rubygems_version: 1.8.23
         | 
| 108 | 
            +
            signing_key: 
         | 
| 109 | 
            +
            specification_version: 3
         | 
| 110 | 
            +
            summary: Boolean Simplifier
         | 
| 111 | 
            +
            test_files: []
         |