symbolic 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -8,8 +8,6 @@ gem install symbolic
8
8
 
9
9
  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.
10
10
 
11
- Currently I've implemented only naive optimizations to simplify math expressions, but it's pretty simple to add your own - see Symbolic::Optimization module for examples.
12
-
13
11
  == Examples:
14
12
  x = var :name => 'x'
15
13
  y = var :name => '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.2'
8
+ gem.version = '0.2.3'
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"
@@ -1,28 +1,27 @@
1
- module Symbolic
2
- class Function
3
- include Symbolic
4
- def initialize(variable, operation)
5
- @variable, @operation = variable, operation
6
- end
1
+ class Symbolic::Function
2
+ include Symbolic
7
3
 
8
- def to_s
9
- "#{@operation}(#{@variable})"
10
- end
4
+ def initialize(variable, operation)
5
+ @variable, @operation = variable, operation
6
+ end
7
+
8
+ def to_s
9
+ "#{@operation}(#{@variable})"
10
+ end
11
11
 
12
- def value
13
- Math.send @operation, @variable.value if undefined_variables.empty?
14
- end
12
+ def value
13
+ Math.send @operation, @variable.value if undefined_variables.empty?
14
+ end
15
15
 
16
- def variables
17
- @variable.variables
18
- end
16
+ def variables
17
+ @variable.variables
18
+ end
19
19
 
20
- def undefined_variables
21
- @variable.undefined_variables
22
- end
20
+ def undefined_variables
21
+ @variable.undefined_variables
22
+ end
23
23
 
24
- def detailed_operations
25
- @variable.detailed_operations.tap {|it| it[@operation] += 1}
26
- end
24
+ def detailed_operations
25
+ @variable.detailed_operations.tap {|it| it[@operation] += 1}
27
26
  end
28
27
  end
@@ -18,6 +18,7 @@ class Symbolic::Operation
18
18
  when Binary::Subtraction then :subtraction
19
19
  when Binary::Multiplication then :multiplication
20
20
  when Binary::Division then :division
21
+ when Binary::Exponentiation then :exponentiation
21
22
  when Symbolic::Variable then :variable
22
23
  end
23
24
  end
@@ -20,6 +20,6 @@ class Symbolic::Operation::Binary::Division < Symbolic::Operation::Binary
20
20
  end
21
21
 
22
22
  def brackets_for
23
- [:unary_minus, :addition, :subtraction]
23
+ [:addition, :subtraction]
24
24
  end
25
25
  end
@@ -1,10 +1,14 @@
1
1
  class Symbolic::Operation::Binary::Exponentiation < Symbolic::Operation::Binary
2
2
  def self.simplify_first_arg(var1, var2)
3
- # add conditional for negative?(var1) and even or odd values of var2
4
3
  if var1 == 0
5
4
  0
6
5
  elsif var1 == 1
7
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)
8
12
  end
9
13
  end
10
14
 
@@ -23,4 +27,9 @@ class Symbolic::Operation::Binary::Exponentiation < Symbolic::Operation::Binary
23
27
  def sign
24
28
  '**'
25
29
  end
30
+
31
+ private
32
+
33
+ alias base var1
34
+ alias exponent var2
26
35
  end
@@ -1,44 +1,84 @@
1
- class Symbolic::Operation::Binary::Multiplication < Symbolic::Operation::Binary
2
- symmetric
3
-
4
- def self.simplify_first_arg(var1, var2)
5
- if var1 == 0
6
- 0
7
- elsif var1 == 1
8
- var2
9
- elsif negative?(var1)
10
- -(var1.abs * var2)
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) : [var]
53
+ end
11
54
  end
12
- end
13
55
 
14
- def sign
15
- '*'
16
- end
56
+ def sign
57
+ '*'
58
+ end
17
59
 
18
- def brackets_for
19
- [:unary_minus, :addition, :subtraction]
20
- end
21
- # def initialize(var1, var2)
22
- # super
23
- # coef, numerators, denominators = unite_factors factors_of(var1), factors_of(var2)
24
- # end
25
-
26
- def unite_factors(factors1, factors2)
27
- c1, n1, d1 = factors1
28
- c2, n2, d2 = factors2
29
- return c1*c2, n1+n2, d1+d2
30
- end
60
+ def brackets_for
61
+ [:addition, :subtraction]
62
+ end
63
+
64
+ def initialize(factors)
65
+ @factors = factors
66
+ end
31
67
 
32
- def factors_of(var)
33
- case var
34
- when Numeric
35
- [var, [], []]
36
- when Unary::Minus
37
- unite_factors [-1, [], []], factors_of(var.abs)
38
- when Binary::Multiplication
39
- [var.coef, var.nominators, var.denominators]
40
- else
41
- [[], [var], []]
68
+ def variables
69
+ @factors.map(&:variables).flatten.uniq
42
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
43
83
  end
44
84
  end
@@ -90,7 +90,14 @@ describe "Symbolic" do
90
90
  '0**x' => '0',
91
91
  '1**x' => '1',
92
92
  'x**0' => '1',
93
- 'x**1' => 'x'
93
+ 'x**1' => 'x',
94
+ '(-x)**1' => '-x',
95
+ '(-x)**2' => 'x**2',
96
+ '(x**2)**y' => 'x**(2*y)',
97
+
98
+ 'x*4*x' => '4*x**2',
99
+ 'x*(-1)*x**(-1)' => '-1',
100
+ 'x**2*(-1)*x**(-1)' => '-x'
94
101
  end
95
102
 
96
103
  describe 'general methods:' do
@@ -121,12 +128,12 @@ describe "Symbolic" do
121
128
  '-(x-y)' => 'y-x',
122
129
  'x*y' => 'x*y',
123
130
  '(-x)*y' => '-x*y',
124
- '(x+2)*(y+3)*4' => '(x+2)*(y+3)*4',
131
+ '(x+2)*(y+3)*4' => '4*(x+2)*(y+3)',
125
132
  '4/x' => '4/x',
126
133
  '(-(2+x))/(-(-y))' => '(-2-x)/y',
127
134
  'x**y' => 'x**y',
128
135
  'x**(y-4)' => 'x**(y-4)',
129
- '(x+1)**(y*2)' => '(x+1)**(y*2)',
136
+ '(x+1)**(y*2)' => '(x+1)**(2*y)',
130
137
  '-(x**y -2)+5' => '2-x**y+5'
131
138
  end
132
139
  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.2
4
+ version: 0.2.3
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-09 00:00:00 +03:00
12
+ date: 2009-12-11 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency