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 +1 -1
- data/lib/symbolic.rb +5 -0
- data/lib/symbolic/core.rb +1 -1
- data/lib/symbolic/expression.rb +2 -1
- data/lib/symbolic/optimizations.rb +8 -62
- data/lib/symbolic/optimizations/addition.rb +15 -0
- data/lib/symbolic/optimizations/base.rb +9 -0
- data/lib/symbolic/optimizations/division.rb +19 -0
- data/lib/symbolic/optimizations/multiplication.rb +17 -0
- data/lib/symbolic/optimizations/subtraction.rb +16 -0
- data/lib/symbolic/unary_minus.rb +5 -0
- data/spec/symbolic_spec.rb +56 -55
- metadata +7 -2
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.
|
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
data/lib/symbolic/expression.rb
CHANGED
@@ -34,7 +34,8 @@ module Symbolic
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def ==(object)
|
37
|
-
object.
|
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(
|
4
|
-
|
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(
|
22
|
-
|
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(
|
40
|
-
|
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(
|
62
|
-
|
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,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
|
data/lib/symbolic/unary_minus.rb
CHANGED
@@ -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
|
data/spec/symbolic_spec.rb
CHANGED
@@ -11,36 +11,36 @@ describe "Symbolic" do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
describe "evaluation (x=1, y=2):" do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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)'
|
55
|
+
'-(-x)' => 'x',
|
56
56
|
|
57
|
-
'0 + x'
|
58
|
-
'x + 0'
|
59
|
-
'x + (-2)'
|
60
|
-
'-2 + x'
|
61
|
-
'-x + 2'
|
62
|
-
'x + (-y)'
|
63
|
-
'-y + x'
|
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'
|
66
|
-
'x - 0'
|
67
|
-
'x - (-2)'
|
68
|
-
'-2 - (-x)'
|
69
|
-
'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'
|
72
|
-
'x * 0'
|
73
|
-
'1 * x'
|
74
|
-
'x * 1'
|
75
|
-
'-1 * x'
|
76
|
-
'x * (-1)'
|
77
|
-
'x * (-3)'
|
78
|
-
'-3 * x'
|
79
|
-
'-3 * (-x)'
|
80
|
-
'x*(-y)'
|
81
|
-
'-x*y'
|
82
|
-
'(-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'
|
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.
|
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-
|
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
|