symbolic 0.2.5 → 0.3.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.rdoc +6 -6
- data/Rakefile +1 -1
- data/lib/symbolic/coerced.rb +5 -5
- data/lib/{extensions → symbolic/extensions}/kernel.rb +0 -0
- data/lib/{extensions → symbolic/extensions}/matrix.rb +0 -0
- data/lib/{extensions → symbolic/extensions}/numeric.rb +0 -4
- data/lib/symbolic/extensions/rational.rb +13 -0
- data/lib/symbolic/factor.rb +129 -0
- data/lib/symbolic/math.rb +10 -6
- data/lib/symbolic/statistics.rb +13 -0
- data/lib/symbolic/summand.rb +86 -0
- data/lib/symbolic.rb +29 -21
- data/spec/symbolic_spec.rb +11 -10
- metadata +9 -14
- data/lib/symbolic/operation/binary/addition.rb +0 -15
- data/lib/symbolic/operation/binary/division.rb +0 -25
- data/lib/symbolic/operation/binary/exponentiation.rb +0 -35
- data/lib/symbolic/operation/binary/multiplication.rb +0 -84
- data/lib/symbolic/operation/binary/subtraction.rb +0 -19
- data/lib/symbolic/operation/binary.rb +0 -54
- data/lib/symbolic/operation/unary/minus.rb +0 -39
- data/lib/symbolic/operation/unary.rb +0 -13
- data/lib/symbolic/operation.rb +0 -61
    
        data/README.rdoc
    CHANGED
    
    | @@ -12,16 +12,16 @@ Symbolic math can be really helpful if you want to simplify some giant equation | |
| 12 12 | 
             
              x = var :name => 'x'
         | 
| 13 13 | 
             
              y = var :name => 'y'
         | 
| 14 14 |  | 
| 15 | 
            -
              f = ( | 
| 16 | 
            -
              puts f # => ( | 
| 15 | 
            +
              f = (-2*(-x) + y*(-1.0) + 6*x/(3*x))*x - 2*y + 2*y - (2**x)**y
         | 
| 16 | 
            +
              puts f # => (2*x-y+2)*x-2**(x*y)
         | 
| 17 17 |  | 
| 18 | 
            -
              p f. | 
| 19 | 
            -
              p f. | 
| 20 | 
            -
              p f.undefined_variables.map &:name # => ["x", "y"]
         | 
| 18 | 
            +
              p f.operations # => {"+"=>1, "-"=>2, "*"=>3, "/"=>0, "**"=>1, "-@"=>0}
         | 
| 19 | 
            +
              p f.variables.map &:name # => ["x", "y"]
         | 
| 21 20 | 
             
              x.value = 2
         | 
| 21 | 
            +
              p f.undefined_variables.map &:name # => ["y"]
         | 
| 22 22 | 
             
              y.value = 4
         | 
| 23 23 |  | 
| 24 | 
            -
              puts f.value # =>  | 
| 24 | 
            +
              puts f.value # => -252.0
         | 
| 25 25 |  | 
| 26 26 |  | 
| 27 27 | 
             
              g = Symbolic::Math.cos(y)
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -5,7 +5,7 @@ begin | |
| 5 5 | 
             
              require 'jeweler'
         | 
| 6 6 | 
             
              Jeweler::Tasks.new do |gem|
         | 
| 7 7 | 
             
                gem.name = "symbolic"
         | 
| 8 | 
            -
                gem.version = '0. | 
| 8 | 
            +
                gem.version = '0.3.0'
         | 
| 9 9 | 
             
                gem.summary = 'Symbolic math for ruby'
         | 
| 10 10 | 
             
                gem.description = %Q{Symbolic math can be really helpful if you want to simplify some giant equation or if you don't want to get a performance hit re-evaluating big math expressions every time when few variables change.}
         | 
| 11 11 | 
             
                gem.email = "ravwar@gmail.com"
         | 
    
        data/lib/symbolic/coerced.rb
    CHANGED
    
    | @@ -5,23 +5,23 @@ module Symbolic | |
| 5 5 | 
             
                end
         | 
| 6 6 |  | 
| 7 7 | 
             
                def +(numeric)
         | 
| 8 | 
            -
                   | 
| 8 | 
            +
                  Summand.add numeric, @symbolic
         | 
| 9 9 | 
             
                end
         | 
| 10 10 |  | 
| 11 11 | 
             
                def -(numeric)
         | 
| 12 | 
            -
                   | 
| 12 | 
            +
                  Summand.subtract numeric, @symbolic
         | 
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 15 | 
             
                def *(numeric)
         | 
| 16 | 
            -
                   | 
| 16 | 
            +
                  Factor.multiply numeric, @symbolic
         | 
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 19 | 
             
                def /(numeric)
         | 
| 20 | 
            -
                   | 
| 20 | 
            +
                  Factor.divide numeric, @symbolic
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
| 23 23 | 
             
                def **(numeric)
         | 
| 24 | 
            -
                   | 
| 24 | 
            +
                  Factor.exponent numeric, @symbolic
         | 
| 25 25 | 
             
                end
         | 
| 26 26 | 
             
              end
         | 
| 27 27 | 
             
            end
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| @@ -0,0 +1,129 @@ | |
| 1 | 
            +
            class Symbolic::Factor
         | 
| 2 | 
            +
              include Symbolic
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              class << self
         | 
| 5 | 
            +
                def exponent(base, exponent)
         | 
| 6 | 
            +
                  simplify_exponents! factors = unite_exponents(base, exponent)
         | 
| 7 | 
            +
                  simplify(*factors) || new(factors)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def multiply(var1, var2)
         | 
| 11 | 
            +
                  simplify_exponents! factors = unite(factors(var1), factors(var2))
         | 
| 12 | 
            +
                  simplify(*factors) || new(factors)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def divide(var1, var2)
         | 
| 16 | 
            +
                  simplify_exponents! factors = unite(factors(var1), reverse(var2))
         | 
| 17 | 
            +
                  simplify(*factors) || new(factors)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def simplify_exponents!(factors)
         | 
| 21 | 
            +
                  factors[1].delete_if {|base, exp| (base == 1) || (exp == 0) }
         | 
| 22 | 
            +
                  factors[0] = 0 if factors[1].any? {|base, exp| base == 0 }
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def simplify(numeric, symbolic)
         | 
| 26 | 
            +
                  if numeric == 0 || symbolic.empty?
         | 
| 27 | 
            +
                    (numeric.round == numeric) ? numeric.to_i : numeric.to_f
         | 
| 28 | 
            +
                  elsif numeric == 1 && symbolic.size == 1 && symbolic.values.first == 1
         | 
| 29 | 
            +
                    symbolic.keys.first
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def reverse(var)
         | 
| 34 | 
            +
                  factors(var).dup.tap do |it|
         | 
| 35 | 
            +
                    it[0] = it[0]**-1
         | 
| 36 | 
            +
                    it[1] = Hash[*it[1].map {|b,e| [b,-e] }.flatten]
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                def factors(var)
         | 
| 41 | 
            +
                  var.is_a?(Symbolic) ? var.send(:factors) : [var, {}]
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def unite(factors1, factors2)
         | 
| 45 | 
            +
                  numeric1, symbolic1 = factors1
         | 
| 46 | 
            +
                  numeric2, symbolic2 = factors2
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  numeric = numeric1 * numeric2
         | 
| 49 | 
            +
                  symbolic = symbolic1.merge(symbolic2) {|base, exp1, exp2| exp1 + exp2 }
         | 
| 50 | 
            +
                  return numeric, symbolic
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def unite_exponents(base, exponent)
         | 
| 54 | 
            +
                  if base.is_a? Symbolic::Factor
         | 
| 55 | 
            +
                    numeric, symbolic = factors(base)
         | 
| 56 | 
            +
                    return numeric**exponent, Hash[*symbolic.map {|base,exp| [base,exp*exponent] }.flatten]
         | 
| 57 | 
            +
                  else
         | 
| 58 | 
            +
                    [1, { base => exponent }]
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              def initialize(factors)
         | 
| 64 | 
            +
                @factors = factors
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              def value
         | 
| 68 | 
            +
                @factors[1].inject(@factors[0]) {|value, (base, exp)| value * base.value ** exp.value }
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              def variables
         | 
| 72 | 
            +
                @factors[1].map {|k,v| [variables_of(k), variables_of(v)] }.flatten.uniq
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def to_s
         | 
| 76 | 
            +
                simplify_output
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              def ==(object)
         | 
| 80 | 
            +
                object.send(:factors) == @factors rescue false
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              private
         | 
| 84 | 
            +
             | 
| 85 | 
            +
              attr_reader :factors
         | 
| 86 | 
            +
             | 
| 87 | 
            +
              def summands
         | 
| 88 | 
            +
                if @factors[0] == 1
         | 
| 89 | 
            +
                  super
         | 
| 90 | 
            +
                else
         | 
| 91 | 
            +
                  [0, {(self/@factors[0]) => @factors[0]}]
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
              def coefficient_to_string(numeric)
         | 
| 96 | 
            +
                "#{'-' if numeric < 0}#{"#{rational_to_string numeric.abs}*" if numeric.abs != 1}"
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              def exponent_to_string(base, exponent)
         | 
| 100 | 
            +
                "#{brackets base}#{"**#{brackets exponent}" if exponent != 1}"
         | 
| 101 | 
            +
              end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
              def brackets(var)
         | 
| 104 | 
            +
                [Numeric, Symbolic::Variable].any? {|klass| var.is_a? klass } ? var : "(#{var})"
         | 
| 105 | 
            +
              end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
              def simplify_output
         | 
| 108 | 
            +
                groups = @factors[1].group_by {|b,e| e.is_a?(Numeric) && e < 0 }
         | 
| 109 | 
            +
                reversed_factors = groups[true] ? [1, Hash[*groups[true].flatten] ] : nil
         | 
| 110 | 
            +
                factors = groups[false] ? [@factors[0], Hash[*groups[false].flatten] ] : nil
         | 
| 111 | 
            +
                output = '' << (factors ? output(factors) : rational_to_string(@factors[0]))
         | 
| 112 | 
            +
                output << "/#{reversed_output reversed_factors}" if reversed_factors
         | 
| 113 | 
            +
                output
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              def output(factors)
         | 
| 117 | 
            +
                coefficient_to_string(factors[0]) <<
         | 
| 118 | 
            +
                factors[1].map {|base,exp| exponent_to_string base,exp }.join('*')
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              def reversed_output(factors)
         | 
| 122 | 
            +
                result = output [factors[0], Hash[*factors[1].map {|b,e| [b,-e] }.flatten]]
         | 
| 123 | 
            +
                (factors[1].length > 1) ? "(#{result})" : result
         | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
              def rational_to_string(numeric)
         | 
| 127 | 
            +
                ((numeric.round == numeric) ? numeric.to_i : numeric.to_f).to_s
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
            end
         | 
    
        data/lib/symbolic/math.rb
    CHANGED
    
    | @@ -1,9 +1,13 @@ | |
| 1 1 | 
             
            module Symbolic::Math
         | 
| 2 | 
            -
               | 
| 3 | 
            -
                 | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 2 | 
            +
              Math.methods(false).each do |method|
         | 
| 3 | 
            +
                instance_eval <<-CODE, __FILE__, __LINE__
         | 
| 4 | 
            +
                  def #{method}(argument)
         | 
| 5 | 
            +
                    unless argument.is_a? Numeric
         | 
| 6 | 
            +
                      Symbolic::Function.new argument, :#{method}
         | 
| 7 | 
            +
                    else
         | 
| 8 | 
            +
                      ::Math.#{method} argument
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                CODE
         | 
| 8 12 | 
             
              end
         | 
| 9 13 | 
             
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            module Symbolic
         | 
| 2 | 
            +
              def operations
         | 
| 3 | 
            +
                formula = to_s
         | 
| 4 | 
            +
                stats = {}
         | 
| 5 | 
            +
                stats['+'] = formula.scan(/\+/).size
         | 
| 6 | 
            +
                stats['-'] = formula.scan(/[^(]-/).size
         | 
| 7 | 
            +
                stats['*'] = formula.scan(/[^*]\*[^*]/).size
         | 
| 8 | 
            +
                stats['/'] = formula.scan(/\//).size
         | 
| 9 | 
            +
                stats['**']= formula.scan(/\*\*/).size
         | 
| 10 | 
            +
                stats['-@']= formula.scan(/\(-/).size + formula.scan(/^-/).size
         | 
| 11 | 
            +
                stats
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| @@ -0,0 +1,86 @@ | |
| 1 | 
            +
            class Symbolic::Summand
         | 
| 2 | 
            +
              include Symbolic
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              class << self
         | 
| 5 | 
            +
                def add(var1, var2)
         | 
| 6 | 
            +
                  simplify_coefficients! summands = unite(summands(var1), summands(var2))
         | 
| 7 | 
            +
                  simplify(*summands) || new(summands)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def subtract(var1, var2)
         | 
| 11 | 
            +
                  simplify_coefficients! summands = unite(summands(var1), reverse(var2))
         | 
| 12 | 
            +
                  simplify(*summands) || new(summands)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def reverse(var)
         | 
| 16 | 
            +
                  summands(var).tap do |it|
         | 
| 17 | 
            +
                    it[0] = -it[0]
         | 
| 18 | 
            +
                    it[1] = Hash[*it[1].map {|b,e| [b,-e] }.flatten]
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def summands(var)
         | 
| 23 | 
            +
                  var.is_a?(Symbolic) ? var.send(:summands) : [var, {}]
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def unite(summands1, summands2)
         | 
| 27 | 
            +
                  numeric1, symbolic1 = summands1
         | 
| 28 | 
            +
                  numeric2, symbolic2 = summands2
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  numeric = numeric1 + numeric2
         | 
| 31 | 
            +
                  symbolic = symbolic1.merge(symbolic2) {|base, coef1, coef2| coef1 + coef2 }
         | 
| 32 | 
            +
                  return numeric, symbolic
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def simplify_coefficients!(summands)
         | 
| 36 | 
            +
                  summands[1].delete_if {|base, coef| coef == 0 }
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                def simplify(numeric, symbolic)
         | 
| 40 | 
            +
                  if symbolic.empty?
         | 
| 41 | 
            +
                    numeric
         | 
| 42 | 
            +
                  elsif numeric == 0 && symbolic.size == 1
         | 
| 43 | 
            +
                    symbolic.values.first * symbolic.keys.first
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def initialize(summands)
         | 
| 49 | 
            +
                @summands = summands
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              def value
         | 
| 53 | 
            +
                @summands[1].inject(@summands[0]) {|value, (base, coef)| value + base.value * coef.value }
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
              def variables
         | 
| 57 | 
            +
                @summands[1].map {|k,v| [variables_of(k), variables_of(v)] }.flatten.uniq
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              def ==(object)
         | 
| 61 | 
            +
                object.send(:summands) == @summands rescue false
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              def to_s
         | 
| 65 | 
            +
                output = @summands[1].map {|base, coef| coef_to_string(coef) + base.to_s }
         | 
| 66 | 
            +
                output << remainder_to_string(@summands[0]) if @summands[0] != 0
         | 
| 67 | 
            +
                output[0] = output.first[1..-1]
         | 
| 68 | 
            +
                output.join
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              private
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              attr_reader :summands
         | 
| 74 | 
            +
             | 
| 75 | 
            +
              def coef_to_string(coef)
         | 
| 76 | 
            +
                "#{(coef > 0) ? '+' : '-' }#{ "#{rational_to_string(coef.abs)}*" if coef.abs != 1}"
         | 
| 77 | 
            +
              end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
              def remainder_to_string(numeric)
         | 
| 80 | 
            +
                "#{'+' if numeric > 0}#{numeric}"
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              def rational_to_string(numeric)
         | 
| 84 | 
            +
                ((numeric.round == numeric) ? numeric.to_i : numeric.to_f).to_s
         | 
| 85 | 
            +
              end
         | 
| 86 | 
            +
            end
         | 
    
        data/lib/symbolic.rb
    CHANGED
    
    | @@ -1,27 +1,21 @@ | |
| 1 1 | 
             
            Symbolic = Module.new
         | 
| 2 2 |  | 
| 3 | 
            -
            require 'symbolic/operation'
         | 
| 4 | 
            -
            require 'symbolic/operation/unary'
         | 
| 5 | 
            -
            require 'symbolic/operation/unary/minus'
         | 
| 6 | 
            -
            require 'symbolic/operation/binary'
         | 
| 7 | 
            -
            require 'symbolic/operation/binary/addition'
         | 
| 8 | 
            -
            require 'symbolic/operation/binary/subtraction'
         | 
| 9 | 
            -
            require 'symbolic/operation/binary/multiplication'
         | 
| 10 | 
            -
            require 'symbolic/operation/binary/division'
         | 
| 11 | 
            -
            require 'symbolic/operation/binary/exponentiation'
         | 
| 12 | 
            -
             | 
| 13 3 | 
             
            require 'symbolic/coerced'
         | 
| 14 4 | 
             
            require 'symbolic/variable'
         | 
| 5 | 
            +
            require 'symbolic/summand'
         | 
| 6 | 
            +
            require 'symbolic/factor'
         | 
| 15 7 | 
             
            require 'symbolic/function'
         | 
| 16 8 | 
             
            require 'symbolic/math'
         | 
| 9 | 
            +
            require 'symbolic/statistics'
         | 
| 17 10 |  | 
| 18 | 
            -
            require 'extensions/kernel'
         | 
| 19 | 
            -
            require 'extensions/numeric'
         | 
| 20 | 
            -
            require 'extensions/matrix'
         | 
| 11 | 
            +
            require 'symbolic/extensions/kernel'
         | 
| 12 | 
            +
            require 'symbolic/extensions/numeric'
         | 
| 13 | 
            +
            require 'symbolic/extensions/matrix' if Object.const_defined? 'Matrix'
         | 
| 14 | 
            +
            require 'symbolic/extensions/rational' if RUBY_VERSION == '1.8.7'
         | 
| 21 15 |  | 
| 22 16 | 
             
            module Symbolic
         | 
| 23 17 | 
             
              def -@
         | 
| 24 | 
            -
                 | 
| 18 | 
            +
                Factor.multiply self, -1
         | 
| 25 19 | 
             
              end
         | 
| 26 20 |  | 
| 27 21 | 
             
              def +@
         | 
| @@ -29,30 +23,44 @@ module Symbolic | |
| 29 23 | 
             
              end
         | 
| 30 24 |  | 
| 31 25 | 
             
              def +(var)
         | 
| 32 | 
            -
                 | 
| 26 | 
            +
                Summand.add self, var
         | 
| 33 27 | 
             
              end
         | 
| 34 28 |  | 
| 35 29 | 
             
              def -(var)
         | 
| 36 | 
            -
                 | 
| 30 | 
            +
                Summand.subtract self, var
         | 
| 37 31 | 
             
              end
         | 
| 38 32 |  | 
| 39 33 | 
             
              def *(var)
         | 
| 40 | 
            -
                 | 
| 34 | 
            +
                Factor.multiply self, var
         | 
| 41 35 | 
             
              end
         | 
| 42 36 |  | 
| 43 37 | 
             
              def /(var)
         | 
| 44 | 
            -
                 | 
| 38 | 
            +
                Factor.divide self, var
         | 
| 45 39 | 
             
              end
         | 
| 46 40 |  | 
| 47 41 | 
             
              def **(var)
         | 
| 48 | 
            -
                 | 
| 42 | 
            +
                Factor.exponent self, var
         | 
| 49 43 | 
             
              end
         | 
| 50 44 |  | 
| 51 45 | 
             
              def coerce(numeric)
         | 
| 52 46 | 
             
                return Coerced.new(self), numeric
         | 
| 53 47 | 
             
              end
         | 
| 54 48 |  | 
| 55 | 
            -
              def  | 
| 56 | 
            -
                 | 
| 49 | 
            +
              def undefined_variables
         | 
| 50 | 
            +
                variables.select {|it| it.value.nil? }
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              private
         | 
| 54 | 
            +
             | 
| 55 | 
            +
              def factors
         | 
| 56 | 
            +
                [1, { self => 1 }]
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              def summands
         | 
| 60 | 
            +
                [0, { self => 1 }]
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              def variables_of(var)
         | 
| 64 | 
            +
                var.variables rescue []
         | 
| 57 65 | 
             
              end
         | 
| 58 66 | 
             
            end
         | 
    
        data/spec/symbolic_spec.rb
    CHANGED
    
    | @@ -43,9 +43,8 @@ describe "Symbolic" do | |
| 43 43 | 
             
                 'x*3'       => 3,
         | 
| 44 44 | 
             
                 '4*y'       => 8,
         | 
| 45 45 | 
             
                 '(+x)*(-y)' => -2,
         | 
| 46 | 
            -
                 'x/2'       => 0,
         | 
| 46 | 
            +
                 'x/2'       => 0.5,
         | 
| 47 47 | 
             
                 'y/2'       => 1,
         | 
| 48 | 
            -
                 'x/2.0'     => 0.5,
         | 
| 49 48 | 
             
                 '-2/x'      => -2,
         | 
| 50 49 | 
             
                 '4/(-y)'    => -2,
         | 
| 51 50 | 
             
                 'x**2'      => 1,
         | 
| @@ -105,9 +104,10 @@ describe "Symbolic" do | |
| 105 104 | 
             
                'x.variables' => '[x]',
         | 
| 106 105 | 
             
                '(-(x+y)).variables' => '[x,y]',
         | 
| 107 106 | 
             
                '(x+y).undefined_variables' => '[]',
         | 
| 108 | 
            -
                '( | 
| 109 | 
            -
                ' | 
| 110 | 
            -
                ' | 
| 107 | 
            +
                '(x*y).undefined_variables' => '[]'#,
         | 
| 108 | 
            +
                # '(-x**y-4*y+5-y/x).detailed_operations' =>
         | 
| 109 | 
            +
                # '{"+" => 1, "-" => 2, "*" => 1, "/" => 1, "-@" => 1, "**" => 1}',
         | 
| 110 | 
            +
                # '(-x**y-4*y+5-y/x).operations' => '7'
         | 
| 111 111 | 
             
              end
         | 
| 112 112 |  | 
| 113 113 | 
             
              describe "to_s:" do
         | 
| @@ -124,16 +124,17 @@ describe "Symbolic" do | |
| 124 124 | 
             
                '-x' => '-x',
         | 
| 125 125 | 
             
                'x+1' => 'x+1',
         | 
| 126 126 | 
             
                'x-4' => 'x-4',
         | 
| 127 | 
            -
                '-(x+y)' => '-x-y',
         | 
| 128 | 
            -
                '-(x-y)' => 'y-x',
         | 
| 127 | 
            +
                # '-(x+y)' => '-x-y',
         | 
| 128 | 
            +
                # '-(x-y)' => 'y-x',
         | 
| 129 129 | 
             
                'x*y' => 'x*y',
         | 
| 130 130 | 
             
                '(-x)*y' => '-x*y',
         | 
| 131 131 | 
             
                '(x+2)*(y+3)*4' => '4*(x+2)*(y+3)',
         | 
| 132 132 | 
             
                '4/x' => '4/x',
         | 
| 133 | 
            -
                ' | 
| 133 | 
            +
                '2*x**(-1)*y**(-1)' => '2/(x*y)',
         | 
| 134 | 
            +
                # '(-(2+x))/(-(-y))' => '(-2-x)/y',
         | 
| 134 135 | 
             
                'x**y' => 'x**y',
         | 
| 135 136 | 
             
                'x**(y-4)' => 'x**(y-4)',
         | 
| 136 | 
            -
                '(x+1)**(y*2)' => '(x+1)**(2*y)' | 
| 137 | 
            -
                '-(x**y -2)+5' => '2-x**y+5'
         | 
| 137 | 
            +
                '(x+1)**(y*2)' => '(x+1)**(2*y)'#,
         | 
| 138 | 
            +
                # '-(x**y -2)+5' => '2-x**y+5'
         | 
| 138 139 | 
             
              end
         | 
| 139 140 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: symbolic
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - brainopia
         | 
| @@ -9,7 +9,7 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 11 |  | 
| 12 | 
            -
            date: 2009-12- | 
| 12 | 
            +
            date: 2009-12-13 00:00:00 +03:00
         | 
| 13 13 | 
             
            default_executable: 
         | 
| 14 14 | 
             
            dependencies: 
         | 
| 15 15 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -34,22 +34,17 @@ files: | |
| 34 34 | 
             
            - .gitignore
         | 
| 35 35 | 
             
            - README.rdoc
         | 
| 36 36 | 
             
            - Rakefile
         | 
| 37 | 
            -
            - lib/extensions/kernel.rb
         | 
| 38 | 
            -
            - lib/extensions/matrix.rb
         | 
| 39 | 
            -
            - lib/extensions/numeric.rb
         | 
| 40 37 | 
             
            - lib/symbolic.rb
         | 
| 41 38 | 
             
            - lib/symbolic/coerced.rb
         | 
| 39 | 
            +
            - lib/symbolic/extensions/kernel.rb
         | 
| 40 | 
            +
            - lib/symbolic/extensions/matrix.rb
         | 
| 41 | 
            +
            - lib/symbolic/extensions/numeric.rb
         | 
| 42 | 
            +
            - lib/symbolic/extensions/rational.rb
         | 
| 43 | 
            +
            - lib/symbolic/factor.rb
         | 
| 42 44 | 
             
            - lib/symbolic/function.rb
         | 
| 43 45 | 
             
            - lib/symbolic/math.rb
         | 
| 44 | 
            -
            - lib/symbolic/ | 
| 45 | 
            -
            - lib/symbolic/ | 
| 46 | 
            -
            - lib/symbolic/operation/binary/addition.rb
         | 
| 47 | 
            -
            - lib/symbolic/operation/binary/division.rb
         | 
| 48 | 
            -
            - lib/symbolic/operation/binary/exponentiation.rb
         | 
| 49 | 
            -
            - lib/symbolic/operation/binary/multiplication.rb
         | 
| 50 | 
            -
            - lib/symbolic/operation/binary/subtraction.rb
         | 
| 51 | 
            -
            - lib/symbolic/operation/unary.rb
         | 
| 52 | 
            -
            - lib/symbolic/operation/unary/minus.rb
         | 
| 46 | 
            +
            - lib/symbolic/statistics.rb
         | 
| 47 | 
            +
            - lib/symbolic/summand.rb
         | 
| 53 48 | 
             
            - lib/symbolic/variable.rb
         | 
| 54 49 | 
             
            - spec/spec.opts
         | 
| 55 50 | 
             
            - spec/spec_helper.rb
         | 
| @@ -1,25 +0,0 @@ | |
| 1 | 
            -
            class Symbolic::Operation::Binary::Division < Symbolic::Operation::Binary
         | 
| 2 | 
            -
              def self.simplify_first_arg(var1, var2)
         | 
| 3 | 
            -
                if var1 == 0
         | 
| 4 | 
            -
                  0
         | 
| 5 | 
            -
                elsif negative?(var1)
         | 
| 6 | 
            -
                  -(var1.abs / var2)
         | 
| 7 | 
            -
                end
         | 
| 8 | 
            -
              end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
              def self.simplify_second_arg(var1, var2)
         | 
| 11 | 
            -
                if var2 == 1
         | 
| 12 | 
            -
                  var1
         | 
| 13 | 
            -
                elsif negative?(var2)
         | 
| 14 | 
            -
                  -(var1 / var2.abs)
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
              end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
              def sign
         | 
| 19 | 
            -
                '/'
         | 
| 20 | 
            -
              end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
              def brackets_for
         | 
| 23 | 
            -
                [:addition, :subtraction]
         | 
| 24 | 
            -
              end
         | 
| 25 | 
            -
            end
         | 
| @@ -1,35 +0,0 @@ | |
| 1 | 
            -
            class Symbolic::Operation::Binary::Exponentiation < Symbolic::Operation::Binary
         | 
| 2 | 
            -
              def self.simplify_first_arg(var1, var2)
         | 
| 3 | 
            -
                if var1 == 0
         | 
| 4 | 
            -
                  0
         | 
| 5 | 
            -
                elsif var1 == 1
         | 
| 6 | 
            -
                  1
         | 
| 7 | 
            -
                elsif negative?(var1) && var2.respond_to?(:even?)
         | 
| 8 | 
            -
                  without_sign = var1.abs ** var2
         | 
| 9 | 
            -
                  var2.even? ? without_sign : -without_sign
         | 
| 10 | 
            -
                elsif operation(var1) == :exponentiation
         | 
| 11 | 
            -
                  var1.send(:base) ** (var1.send(:exponent) * var2)
         | 
| 12 | 
            -
                end
         | 
| 13 | 
            -
              end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
              def self.simplify_second_arg(var1, var2)
         | 
| 16 | 
            -
                if var2 == 0
         | 
| 17 | 
            -
                  1
         | 
| 18 | 
            -
                elsif var2 == 1
         | 
| 19 | 
            -
                  var1
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
              end
         | 
| 22 | 
            -
             | 
| 23 | 
            -
              def brackets_for
         | 
| 24 | 
            -
                [:unary_minus, :addition, :subtraction, :multiplication, :division]
         | 
| 25 | 
            -
              end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
              def sign
         | 
| 28 | 
            -
                '**'
         | 
| 29 | 
            -
              end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
              private
         | 
| 32 | 
            -
             | 
| 33 | 
            -
              alias base var1
         | 
| 34 | 
            -
              alias exponent var2
         | 
| 35 | 
            -
            end
         | 
| @@ -1,84 +0,0 @@ | |
| 1 | 
            -
            class Symbolic::Operation
         | 
| 2 | 
            -
              class Binary::Multiplication < Binary
         | 
| 3 | 
            -
             | 
| 4 | 
            -
                class << self
         | 
| 5 | 
            -
                  def for(var1, var2)
         | 
| 6 | 
            -
                    # TODO: def -@(var); -1 * var; end
         | 
| 7 | 
            -
                    sign1, var1 = sign_and_modulus var1
         | 
| 8 | 
            -
                    sign2, var2 = sign_and_modulus var2
         | 
| 9 | 
            -
                    sign = (sign1 == sign2) ? :+@ : :-@
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                    factors = unite factors(var1), factors(var2)
         | 
| 12 | 
            -
                    (simplify(factors) || new(factors)).send sign
         | 
| 13 | 
            -
                  end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                  def simplify(factors)
         | 
| 16 | 
            -
                    factors.first if factors.length == 1
         | 
| 17 | 
            -
                  end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                  def unite(factors1, factors2)
         | 
| 20 | 
            -
                    numeric = extract_numeric!(factors1) * extract_numeric!(factors2)
         | 
| 21 | 
            -
                    return [0] if numeric == 0
         | 
| 22 | 
            -
                    factors = unite_by_exponent factors1, factors2
         | 
| 23 | 
            -
                    factors.unshift(numeric) if numeric != 1 || factors.empty?
         | 
| 24 | 
            -
                    factors
         | 
| 25 | 
            -
                  end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                  def unite_by_exponent(factors1, factors2)
         | 
| 28 | 
            -
                    exponents(factors1).
         | 
| 29 | 
            -
                      merge(exponents factors2) {|base,exponent1,exponent2| exponent1 + exponent2 }.
         | 
| 30 | 
            -
                      delete_if {|base, exponent| exponent == 0 }.
         | 
| 31 | 
            -
                      map {|base, exponent| base**exponent }
         | 
| 32 | 
            -
                  end
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                  def exponents(factors)
         | 
| 35 | 
            -
                    exponents = factors.map {|it| base_and_exponent it }
         | 
| 36 | 
            -
                    Hash[exponents]
         | 
| 37 | 
            -
                  end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                  def base_and_exponent(var)
         | 
| 40 | 
            -
                    var.is_a?(Binary::Exponentiation) ? [var.send(:base), var.send(:exponent)] : [var, 1]
         | 
| 41 | 
            -
                  end
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                  def extract_numeric!(factors)
         | 
| 44 | 
            -
                    factors.first.is_a?(Numeric) ? factors.shift : 1
         | 
| 45 | 
            -
                  end
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                  def sign_and_modulus(var)
         | 
| 48 | 
            -
                    negative?(var) ? [:-@, var.abs] : [:+@, var]
         | 
| 49 | 
            -
                  end
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                  def factors(var)
         | 
| 52 | 
            -
                    var.respond_to?(:factors) ? var.send(:factors).dup : [var]
         | 
| 53 | 
            -
                  end
         | 
| 54 | 
            -
                end
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                def sign
         | 
| 57 | 
            -
                  '*'
         | 
| 58 | 
            -
                end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                def brackets_for
         | 
| 61 | 
            -
                  [:addition, :subtraction]
         | 
| 62 | 
            -
                end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                def initialize(factors)
         | 
| 65 | 
            -
                  @factors = factors
         | 
| 66 | 
            -
                end
         | 
| 67 | 
            -
             | 
| 68 | 
            -
                def variables
         | 
| 69 | 
            -
                  @factors.map(&:variables).flatten.uniq
         | 
| 70 | 
            -
                end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                def value
         | 
| 73 | 
            -
                  @factors.inject(1) {|product, it| product*it.value } if undefined_variables.empty?
         | 
| 74 | 
            -
                end
         | 
| 75 | 
            -
             | 
| 76 | 
            -
                def to_s
         | 
| 77 | 
            -
                  @factors.map {|it| brackets it }.join '*'
         | 
| 78 | 
            -
                end
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                protected
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                attr_reader :factors
         | 
| 83 | 
            -
              end
         | 
| 84 | 
            -
            end
         | 
| @@ -1,19 +0,0 @@ | |
| 1 | 
            -
            class Symbolic::Operation::Binary::Subtraction < Symbolic::Operation::Binary
         | 
| 2 | 
            -
              def self.simplify_first_arg(var1, var2)
         | 
| 3 | 
            -
                -var2 if var1 == 0
         | 
| 4 | 
            -
              end
         | 
| 5 | 
            -
             | 
| 6 | 
            -
              def self.simplify_second_arg(var1, var2)
         | 
| 7 | 
            -
                if var2 == 0
         | 
| 8 | 
            -
                  var1
         | 
| 9 | 
            -
                elsif negative?(var2)
         | 
| 10 | 
            -
                  var1 + var2.abs
         | 
| 11 | 
            -
                elsif [:addition, :subtraction].include? operation(var2)
         | 
| 12 | 
            -
                  var1 + (-var2)
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
              end
         | 
| 15 | 
            -
             | 
| 16 | 
            -
              def sign
         | 
| 17 | 
            -
                '-'
         | 
| 18 | 
            -
              end
         | 
| 19 | 
            -
            end
         | 
| @@ -1,54 +0,0 @@ | |
| 1 | 
            -
            class Symbolic::Operation::Binary < Symbolic::Operation
         | 
| 2 | 
            -
              def self.simplify(var1, var2)
         | 
| 3 | 
            -
                simplify_first_arg(var1, var2) || simplify_second_arg(var1, var2)
         | 
| 4 | 
            -
              end
         | 
| 5 | 
            -
             | 
| 6 | 
            -
              def self.symmetric
         | 
| 7 | 
            -
                def self.simplify(var1, var2)
         | 
| 8 | 
            -
                  simplify_first_arg(var1, var2) || simplify_first_arg(var2, var1)
         | 
| 9 | 
            -
                end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                def ==(object)
         | 
| 12 | 
            -
                  (object.class == self.class) &&
         | 
| 13 | 
            -
                  ((object.var1 == @var1 && object.var2 == @var2) || (object.var1 == @var2 && object.var2 == @var1))
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
              end
         | 
| 16 | 
            -
             | 
| 17 | 
            -
              def initialize(var1, var2)
         | 
| 18 | 
            -
                @var1, @var2 = var1, var2
         | 
| 19 | 
            -
              end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              def variables
         | 
| 22 | 
            -
                @var1.variables | @var2.variables
         | 
| 23 | 
            -
              end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
              def undefined_variables
         | 
| 26 | 
            -
                variables.select {|it| it.value.nil? }
         | 
| 27 | 
            -
              end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
              def value
         | 
| 30 | 
            -
                @var1.value.send sign, @var2.value if undefined_variables.empty?
         | 
| 31 | 
            -
              end
         | 
| 32 | 
            -
             | 
| 33 | 
            -
              def detailed_operations
         | 
| 34 | 
            -
                operations_of(@var1).tap {|it| it.merge!(operations_of @var2)[sign] += 1 }
         | 
| 35 | 
            -
              end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
              def to_s
         | 
| 38 | 
            -
                "#{brackets @var1}#{sign}#{brackets @var2}"
         | 
| 39 | 
            -
              end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
              def ==(object)
         | 
| 42 | 
            -
                (object.class == self.class) && (object.var1 == @var1 && object.var2 == @var2)
         | 
| 43 | 
            -
              end
         | 
| 44 | 
            -
             | 
| 45 | 
            -
              protected
         | 
| 46 | 
            -
             | 
| 47 | 
            -
              attr_reader :var1, :var2
         | 
| 48 | 
            -
             | 
| 49 | 
            -
              private
         | 
| 50 | 
            -
             | 
| 51 | 
            -
              def operations_of(var)
         | 
| 52 | 
            -
                var.is_a?(Symbolic) ? var.detailed_operations : Hash.new(0)
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
            end
         | 
| @@ -1,39 +0,0 @@ | |
| 1 | 
            -
            class Symbolic::Operation
         | 
| 2 | 
            -
              class Unary::Minus < Unary
         | 
| 3 | 
            -
                def self.simplify(expression)
         | 
| 4 | 
            -
                  case operation(expression)
         | 
| 5 | 
            -
                  when :unary_minus
         | 
| 6 | 
            -
                    expression.abs
         | 
| 7 | 
            -
                  when :addition
         | 
| 8 | 
            -
                    -expression.send(:var1)-expression.send(:var2)
         | 
| 9 | 
            -
                  when :subtraction
         | 
| 10 | 
            -
                    expression.send(:var2) - expression.send(:var1)
         | 
| 11 | 
            -
                  end
         | 
| 12 | 
            -
                end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                def abs
         | 
| 15 | 
            -
                  # TODO: implement Symbolic#abs
         | 
| 16 | 
            -
                  @expression
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                def brackets_for
         | 
| 20 | 
            -
                  [:addition, :subtraction]
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
             | 
| 23 | 
            -
                def value
         | 
| 24 | 
            -
                  -@expression.value if undefined_variables.empty?
         | 
| 25 | 
            -
                end
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                def ==(object)
         | 
| 28 | 
            -
                  object.is_a?(Unary::Minus) && object.abs == @expression
         | 
| 29 | 
            -
                end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                def detailed_operations
         | 
| 32 | 
            -
                  @expression.detailed_operations.tap {|it| it['-@'] += 1}
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                def to_s
         | 
| 36 | 
            -
                  "-#{brackets @expression}"
         | 
| 37 | 
            -
                end
         | 
| 38 | 
            -
              end
         | 
| 39 | 
            -
            end
         | 
    
        data/lib/symbolic/operation.rb
    DELETED
    
    | @@ -1,61 +0,0 @@ | |
| 1 | 
            -
            class Symbolic::Operation
         | 
| 2 | 
            -
              include Symbolic
         | 
| 3 | 
            -
             | 
| 4 | 
            -
              def self.for(*args)
         | 
| 5 | 
            -
                simplify(*args) || new(*args)
         | 
| 6 | 
            -
              end
         | 
| 7 | 
            -
             | 
| 8 | 
            -
              def self.negative?(var)
         | 
| 9 | 
            -
                var.is_a?(Unary::Minus) || (var.is_a?(Numeric) && var < 0)
         | 
| 10 | 
            -
              end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              private
         | 
| 13 | 
            -
             | 
| 14 | 
            -
              def self.operation(expression)
         | 
| 15 | 
            -
                case expression
         | 
| 16 | 
            -
                when Unary::Minus           then :unary_minus
         | 
| 17 | 
            -
                when Binary::Addition       then :addition
         | 
| 18 | 
            -
                when Binary::Subtraction    then :subtraction
         | 
| 19 | 
            -
                when Binary::Multiplication then :multiplication
         | 
| 20 | 
            -
                when Binary::Division       then :division
         | 
| 21 | 
            -
                when Binary::Exponentiation then :exponentiation
         | 
| 22 | 
            -
                when Symbolic::Variable     then :variable
         | 
| 23 | 
            -
                end
         | 
| 24 | 
            -
              end
         | 
| 25 | 
            -
             | 
| 26 | 
            -
              def operation(expression)
         | 
| 27 | 
            -
                self.class.operation expression
         | 
| 28 | 
            -
              end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
              def unary_minus?(expression)
         | 
| 31 | 
            -
                operation(expression) == :unary_minus
         | 
| 32 | 
            -
              end
         | 
| 33 | 
            -
             | 
| 34 | 
            -
              def addition?(expression)
         | 
| 35 | 
            -
                operation(expression) == :addition
         | 
| 36 | 
            -
              end
         | 
| 37 | 
            -
             | 
| 38 | 
            -
              def subtraction?(expression)
         | 
| 39 | 
            -
                operation(expression) == :subtraction
         | 
| 40 | 
            -
              end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
              def multiplication?(expression)
         | 
| 43 | 
            -
                operation(expression) == :multiplication
         | 
| 44 | 
            -
              end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
              def division?(expression)
         | 
| 47 | 
            -
                operation(expression) == :division
         | 
| 48 | 
            -
              end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
              def variable?(expression)
         | 
| 51 | 
            -
                operation(expession) == :variable
         | 
| 52 | 
            -
              end
         | 
| 53 | 
            -
             | 
| 54 | 
            -
              def brackets(var)
         | 
| 55 | 
            -
                brackets_for.include?(operation var) ? "(#{var})" : var.to_s
         | 
| 56 | 
            -
              end
         | 
| 57 | 
            -
             | 
| 58 | 
            -
              def brackets_for
         | 
| 59 | 
            -
                []
         | 
| 60 | 
            -
              end
         | 
| 61 | 
            -
            end
         |