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 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