symbolic 0.2.2 → 0.2.3

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