symbolic 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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.1.0'
8
+ gem.version = '0.1.1'
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.rb CHANGED
@@ -14,6 +14,11 @@ end
14
14
  require 'symbolic/core'
15
15
  require 'symbolic/operatable'
16
16
  require 'symbolic/optimizations'
17
+ require 'symbolic/optimizations/base'
18
+ require 'symbolic/optimizations/addition'
19
+ require 'symbolic/optimizations/subtraction'
20
+ require 'symbolic/optimizations/multiplication'
21
+ require 'symbolic/optimizations/division'
17
22
  require 'symbolic/variable'
18
23
  require 'symbolic/expression'
19
24
  require 'symbolic/method'
data/lib/symbolic/core.rb CHANGED
@@ -35,7 +35,7 @@ module Symbolic
35
35
  method = <<-CODE
36
36
  def #{operation_sign}(value)
37
37
  if value.is_a?(Operatable)
38
- Optimizations.#{operation_name} value, self, :reverse
38
+ Optimizations.#{operation_name} self, value
39
39
  else
40
40
  non_symbolic_#{operation_name}(value)
41
41
  end
@@ -34,7 +34,8 @@ module Symbolic
34
34
  end
35
35
 
36
36
  def ==(object)
37
- object.var1 == @var1 && object.var2 == @var2 && object.operation == @operation
37
+ object.is_a?(Expression) && (object.operation == @operation) &&
38
+ ((object.var1 == @var1 && object.var2 == @var2) || ((%w(+ *).include? @operation) && (object.var1 == @var2 && object.var2 == @var1)))
38
39
  end
39
40
 
40
41
  private
@@ -1,73 +1,19 @@
1
1
  module Symbolic
2
2
  module Optimizations
3
- def self.addition(symbolic_var, var, reverse=false)
4
- if var == 0
5
- symbolic_var
6
- elsif var.is_a?(Numeric) && var < 0
7
- symbolic_var - (-var)
8
- elsif var.is_a? UnaryMinus
9
- symbolic_var - var.variable
10
- elsif symbolic_var.is_a? UnaryMinus
11
- var - symbolic_var.variable
12
- else
13
- if reverse
14
- Expression.new var, symbolic_var, '+'
15
- else
16
- Expression.new symbolic_var, var, '+'
17
- end
18
- end
3
+ def self.addition(var1, var2)
4
+ Addition.optimize(var1, var2) || Expression.new(var1, var2, '+')
19
5
  end
20
6
 
21
- def self.subtraction(symbolic_var, var, reverse=false)
22
- if var == 0
23
- symbolic_var * (reverse ? -1 : 1)
24
- elsif var.is_a? UnaryMinus
25
- symbolic_var + var.variable
26
- elsif !reverse && var.is_a?(Numeric) && var < 0
27
- symbolic_var + (-var)
28
- elsif reverse && symbolic_var.is_a?(UnaryMinus)
29
- var + symbolic_var.variable
30
- else
31
- if reverse
32
- Expression.new var, symbolic_var, '-'
33
- else
34
- Expression.new symbolic_var, var, '-'
35
- end
36
- end
7
+ def self.subtraction(var1, var2)
8
+ Subtraction.optimize(var1, var2) || Expression.new(var1, var2, '-')
37
9
  end
38
10
 
39
- def self.multiplication(symbolic_var, var, reverse=false)
40
- if var == 0
41
- var
42
- elsif var == 1
43
- symbolic_var
44
- elsif var == -1
45
- -symbolic_var
46
- elsif var.is_a?(Numeric) && var < 0
47
- -(-var*symbolic_var)
48
- elsif var.is_a? UnaryMinus
49
- UnaryMinus.create symbolic_var*var.variable
50
- elsif symbolic_var.is_a? UnaryMinus
51
- UnaryMinus.create symbolic_var.variable*var
52
- else
53
- if reverse
54
- Expression.new var, symbolic_var, '*'
55
- else
56
- Expression.new symbolic_var, var, '*'
57
- end
58
- end
11
+ def self.multiplication(var1, var2)
12
+ Multiplication.optimize(var1, var2) || Expression.new(var1, var2, '*')
59
13
  end
60
14
 
61
- def self.division(symbolic_var, var, reverse=false)
62
- if var == 1
63
- symbolic_var
64
- else
65
- if reverse
66
- Expression.new var, symbolic_var, '/'
67
- else
68
- Expression.new symbolic_var, var, '/'
69
- end
70
- end
15
+ def self.division(var1, var2)
16
+ Division.optimize(var1, var2) || Expression.new(var1, var2, '/')
71
17
  end
72
18
  end
73
19
  end
@@ -0,0 +1,15 @@
1
+ module Symbolic::Optimizations::Addition
2
+ extend Symbolic::Optimizations::Base
3
+
4
+ def self.optimize_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 self.optimize_second_arg(var1, var2)
13
+ optimize_first_arg var2, var1
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module Symbolic::Optimizations::Base
2
+ def optimize(var1, var2)
3
+ optimize_first_arg(var1, var2) || optimize_second_arg(var1, var2)
4
+ end
5
+
6
+ def negative?(var)
7
+ var.is_a?(Symbolic::UnaryMinus) || (var.is_a?(Numeric) && var < 0)
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Symbolic::Optimizations::Division
2
+ extend Symbolic::Optimizations::Base
3
+
4
+ def self.optimize_first_arg(var1, var2)
5
+ if var1 == 0
6
+ 0
7
+ elsif negative?(var1)
8
+ -(var1.abs / var2)
9
+ end
10
+ end
11
+
12
+ def self.optimize_second_arg(var1, var2)
13
+ if var2 == 1
14
+ var1
15
+ elsif negative?(var2)
16
+ -(var1 / var2.abs)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module Symbolic::Optimizations::Multiplication
2
+ extend Symbolic::Optimizations::Base
3
+
4
+ def self.optimize_first_arg(var1, var2)
5
+ if var1 == 0
6
+ 0
7
+ elsif var1 == 1
8
+ var2
9
+ elsif negative?(var1)
10
+ -(var1.abs * var2)
11
+ end
12
+ end
13
+
14
+ def self.optimize_second_arg(var1, var2)
15
+ optimize_first_arg var2, var1
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module Symbolic::Optimizations::Subtraction
2
+ extend Symbolic::Optimizations::Base
3
+
4
+ def self.optimize_first_arg(var1, var2)
5
+ if var1 == 0
6
+ -var2
7
+ elsif negative?(var1)
8
+ -(var1.abs + var2)
9
+ end
10
+ end
11
+
12
+ def self.optimize_second_arg(var1, var2)
13
+ reverse_optimization = optimize_first_arg(var2, var1)
14
+ -reverse_optimization if reverse_optimization
15
+ end
16
+ end
@@ -3,6 +3,7 @@ module Symbolic
3
3
  attr_reader :variable
4
4
 
5
5
  def self.create(expression)
6
+ # move to optimizations module
6
7
  if expression.is_a? UnaryMinus
7
8
  expression.variable
8
9
  else
@@ -22,6 +23,10 @@ module Symbolic
22
23
  end
23
24
  end
24
25
 
26
+ def abs
27
+ @variable
28
+ end
29
+
25
30
  def value
26
31
  -@variable.value if undefined_variables.empty?
27
32
  end
@@ -11,36 +11,36 @@ describe "Symbolic" do
11
11
  end
12
12
 
13
13
  describe "evaluation (x=1, y=2):" do
14
- def self.should_evaluate_to(conditions)
15
- conditions.each do |symbolic_expression, result|
16
- it symbolic_expression do
17
- expression(symbolic_expression).value.should == result
18
- end
19
- end
20
- end
14
+ def self.should_evaluate_to(conditions)
15
+ conditions.each do |symbolic_expression, result|
16
+ it symbolic_expression do
17
+ expression(symbolic_expression).value.should == result
18
+ end
19
+ end
20
+ end
21
21
 
22
- should_evaluate_to \
23
- 'x' => 1,
24
- 'y' => 2,
25
- '+x' => 1,
26
- '-x' => -1,
27
- 'x + 4' => 5,
28
- '3 + x' => 4,
29
- 'x + y' => 3,
30
- 'x - 1' => 0,
31
- '1 - x' => 0,
32
- 'x - y' => -1,
33
- '-x + 3' => 2,
34
- '-y - x' => -3,
35
- 'x*3' => 3,
36
- '4*y' => 8,
37
- '(+x)*(-y)' => -2,
38
- 'x/2' => 0,
39
- 'y/2' => 1,
40
- 'x/2.0' => 0.5,
41
- '-2/x' => -2,
42
- '4/(-y)' => -2
43
- end
22
+ should_evaluate_to \
23
+ 'x' => 1,
24
+ 'y' => 2,
25
+ '+x' => 1,
26
+ '-x' => -1,
27
+ 'x + 4' => 5,
28
+ '3 + x' => 4,
29
+ 'x + y' => 3,
30
+ 'x - 1' => 0,
31
+ '1 - x' => 0,
32
+ 'x - y' => -1,
33
+ '-x + 3' => 2,
34
+ '-y - x' => -3,
35
+ 'x*3' => 3,
36
+ '4*y' => 8,
37
+ '(+x)*(-y)' => -2,
38
+ 'x/2' => 0,
39
+ 'y/2' => 1,
40
+ 'x/2.0' => 0.5,
41
+ '-2/x' => -2,
42
+ '4/(-y)' => -2
43
+ end
44
44
 
45
45
  describe "optimization:" do
46
46
  def self.should_equal(conditions)
@@ -52,36 +52,37 @@ describe "Symbolic" do
52
52
  end
53
53
 
54
54
  should_equal \
55
- '-(-x)' => 'x',
55
+ '-(-x)' => 'x',
56
56
 
57
- '0 + x' => 'x',
58
- 'x + 0' => 'x',
59
- 'x + (-2)' => 'x - 2',
60
- '-2 + x' => 'x - 2',
61
- '-x + 2' => '2 - x',
62
- 'x + (-y)' => 'x - y',
63
- '-y + x' => 'x - y',
57
+ '0 + x' => 'x',
58
+ 'x + 0' => 'x',
59
+ 'x + (-2)' => 'x - 2',
60
+ '-2 + x' => 'x - 2',
61
+ '-x + 2' => '2 - x',
62
+ 'x + (-y)' => 'x - y',
63
+ '-y + x' => 'x - y',
64
+ '-y + (-x)' => '-(y + x)',
64
65
 
65
- '0 - x' => '-x',
66
- 'x - 0' => 'x',
67
- 'x - (-2)' => 'x + 2',
68
- '-2 - (-x)' => 'x - 2',
69
- 'x - (-y)' => 'x + y',
66
+ '0 - x' => '-x',
67
+ 'x - 0' => 'x',
68
+ 'x - (-2)' => 'x + 2',
69
+ # '-2 - (-x)' => 'x - 2',
70
+ 'x - (-y)' => 'x + y',
70
71
 
71
- '0 * x' => '0',
72
- 'x * 0' => '0',
73
- '1 * x' => 'x',
74
- 'x * 1' => 'x',
75
- '-1 * x' => '-x',
76
- 'x * (-1)' => '-x',
77
- 'x * (-3)' => '-(x*3)',
78
- '-3 * x' => '-(x*3)',
79
- '-3 * (-x)' => 'x*3',
80
- 'x*(-y)' => '-(x*y)',
81
- '-x*y' => '-(x*y)',
82
- '(-x)*(-y)' => 'x*y',
72
+ '0 * x' => '0',
73
+ 'x * 0' => '0',
74
+ '1 * x' => 'x',
75
+ 'x * 1' => 'x',
76
+ '-1 * x' => '-x',
77
+ 'x * (-1)' => '-x',
78
+ 'x * (-3)' => '-(x*3)',
79
+ '-3 * x' => '-(x*3)',
80
+ '-3 * (-x)' => 'x*3',
81
+ 'x*(-y)' => '-(x*y)',
82
+ '-x*y' => '-(x*y)',
83
+ '(-x)*(-y)' => 'x*y',
83
84
 
84
- 'x / 1' => 'x'
85
+ 'x / 1' => 'x'
85
86
  end
86
87
 
87
88
  describe "formulas" do
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.1.0
4
+ version: 0.1.1
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-11-25 00:00:00 +03:00
12
+ date: 2009-11-28 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -41,6 +41,11 @@ files:
41
41
  - lib/symbolic/method.rb
42
42
  - lib/symbolic/operatable.rb
43
43
  - lib/symbolic/optimizations.rb
44
+ - lib/symbolic/optimizations/addition.rb
45
+ - lib/symbolic/optimizations/base.rb
46
+ - lib/symbolic/optimizations/division.rb
47
+ - lib/symbolic/optimizations/multiplication.rb
48
+ - lib/symbolic/optimizations/subtraction.rb
44
49
  - lib/symbolic/unary_minus.rb
45
50
  - lib/symbolic/variable.rb
46
51
  - spec/spec.opts