symbolic 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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 = (4 - 2*(-x) + y*(-1.0))*x - 0*y + 0 - 2
16
- puts f # => (4+2*x-y)*x-2
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.detailed_operations # => {"+"=>1, "-"=>2, "*"=>2}
19
- p f.operations # => 5
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 # => 6
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.2.5'
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"
@@ -5,23 +5,23 @@ module Symbolic
5
5
  end
6
6
 
7
7
  def +(numeric)
8
- Operation::Binary::Addition.for numeric, @symbolic
8
+ Summand.add numeric, @symbolic
9
9
  end
10
10
 
11
11
  def -(numeric)
12
- Operation::Binary::Subtraction.for numeric, @symbolic
12
+ Summand.subtract numeric, @symbolic
13
13
  end
14
14
 
15
15
  def *(numeric)
16
- Operation::Binary::Multiplication.for numeric, @symbolic
16
+ Factor.multiply numeric, @symbolic
17
17
  end
18
18
 
19
19
  def /(numeric)
20
- Operation::Binary::Division.for numeric, @symbolic
20
+ Factor.divide numeric, @symbolic
21
21
  end
22
22
 
23
23
  def **(numeric)
24
- Operation::Binary::Exponentiation.for numeric, @symbolic
24
+ Factor.exponent numeric, @symbolic
25
25
  end
26
26
  end
27
27
  end
File without changes
File without changes
@@ -2,8 +2,4 @@ class Numeric
2
2
  def value
3
3
  self
4
4
  end
5
-
6
- def variables
7
- []
8
- end
9
5
  end
@@ -0,0 +1,13 @@
1
+ # Fix for rational on 1.8.7
2
+ [Fixnum,Bignum].each do |klass|
3
+ klass.class_eval do
4
+ def rpower(other)
5
+ if other.is_a?(Numeric) && other < 0
6
+ Rational.new!(self, 1)**other
7
+ else
8
+ self.power!(other)
9
+ end
10
+ end
11
+ alias ** rpower
12
+ end
13
+ end
@@ -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
- def self.cos(argument)
3
- Symbolic::Function.new argument, :cos
4
- end
5
-
6
- def self.sin(argument)
7
- Symbolic::Function.new argument, :sin
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
- Operation::Unary::Minus.for self
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
- Operation::Binary::Addition.for self, var
26
+ Summand.add self, var
33
27
  end
34
28
 
35
29
  def -(var)
36
- Operation::Binary::Subtraction.for self, var
30
+ Summand.subtract self, var
37
31
  end
38
32
 
39
33
  def *(var)
40
- Operation::Binary::Multiplication.for self, var
34
+ Factor.multiply self, var
41
35
  end
42
36
 
43
37
  def /(var)
44
- Operation::Binary::Division.for self, var
38
+ Factor.divide self, var
45
39
  end
46
40
 
47
41
  def **(var)
48
- Operation::Binary::Exponentiation.for self, var
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 operations
56
- detailed_operations.values.inject(0) {|sum,it| sum + it }
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
@@ -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
- '(-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'
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
- '(-(2+x))/(-(-y))' => '(-2-x)/y',
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.2.5
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-11 00:00:00 +03:00
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/operation.rb
45
- - lib/symbolic/operation/binary.rb
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,15 +0,0 @@
1
- class Symbolic::Operation::Binary::Addition < Symbolic::Operation::Binary
2
- symmetric
3
-
4
- def self.simplify_first_arg(var1, var2)
5
- if var1 == 0
6
- var2
7
- elsif negative?(var1)
8
- var2 - var1.abs
9
- end
10
- end
11
-
12
- def sign
13
- '+'
14
- end
15
- end
@@ -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
@@ -1,13 +0,0 @@
1
- class Symbolic::Operation::Unary < Symbolic::Operation
2
- def initialize(expression)
3
- @expression = expression
4
- end
5
-
6
- def variables
7
- @expression.variables
8
- end
9
-
10
- def undefined_variables
11
- @expression.undefined_variables
12
- end
13
- end
@@ -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