symbolic 0.1.0 → 0.1.1
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/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
|