symbolic 0.2.0 → 0.2.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/README.rdoc +2 -2
- data/Rakefile +1 -1
- data/lib/symbolic.rb +40 -39
- data/lib/symbolic/coerced.rb +21 -10
- data/lib/symbolic/{method.rb → function.rb} +1 -2
- data/lib/symbolic/math.rb +9 -0
- data/lib/symbolic/operation.rb +48 -0
- data/lib/symbolic/operation/binary.rb +64 -0
- data/lib/symbolic/operation/binary/addition.rb +15 -0
- data/lib/symbolic/operation/binary/division.rb +23 -0
- data/lib/symbolic/operation/binary/exponentiation.rb +24 -0
- data/lib/symbolic/operation/binary/multiplication.rb +42 -0
- data/lib/symbolic/operation/binary/subtraction.rb +17 -0
- data/lib/symbolic/operation/unary.rb +13 -0
- data/lib/symbolic/operation/unary/minus.rb +32 -0
- data/lib/symbolic/variable.rb +0 -1
- data/spec/symbolic_spec.rb +29 -11
- metadata +13 -11
- data/lib/symbolic/expression.rb +0 -66
- data/lib/symbolic/optimization.rb +0 -12
- data/lib/symbolic/optimization/addition.rb +0 -15
- data/lib/symbolic/optimization/base.rb +0 -9
- data/lib/symbolic/optimization/division.rb +0 -19
- data/lib/symbolic/optimization/multiplication.rb +0 -17
- data/lib/symbolic/optimization/subtraction.rb +0 -15
- data/lib/symbolic/unary_minus.rb +0 -46
data/README.rdoc
CHANGED
@@ -14,7 +14,7 @@ Currently I've implemented only naive optimizations to simplify math expressions
|
|
14
14
|
x = var :name => 'x'
|
15
15
|
y = var :name => 'y'
|
16
16
|
|
17
|
-
f =
|
17
|
+
f = (4 - 2*(-x) + y*(-1.0))*x - 0*y + 0 - 2
|
18
18
|
puts f # => (4+2*x-y)*x-2
|
19
19
|
|
20
20
|
p f.detailed_operations # => {"+"=>1, "-"=>2, "*"=>2}
|
@@ -26,7 +26,7 @@ Currently I've implemented only naive optimizations to simplify math expressions
|
|
26
26
|
puts f.value # => 6
|
27
27
|
|
28
28
|
|
29
|
-
g =
|
29
|
+
g = Symbolic::Math.cos(y)
|
30
30
|
puts g # => cos(y)
|
31
31
|
y.value = 0
|
32
32
|
puts g.value # => 1.0
|
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.
|
8
|
+
gem.version = '0.2.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
@@ -1,57 +1,58 @@
|
|
1
|
+
Symbolic = Module.new
|
2
|
+
|
3
|
+
require 'symbolic/operation'
|
4
|
+
require 'symbolic/operation/unary'
|
5
|
+
require 'symbolic/operation/unary/minus'
|
6
|
+
require 'symbolic/operation/binary'
|
7
|
+
require 'symbolic/operation/binary/addition'
|
8
|
+
require 'symbolic/operation/binary/subtraction'
|
9
|
+
require 'symbolic/operation/binary/multiplication'
|
10
|
+
require 'symbolic/operation/binary/division'
|
11
|
+
require 'symbolic/operation/binary/exponentiation'
|
12
|
+
|
13
|
+
require 'symbolic/coerced'
|
14
|
+
require 'symbolic/variable'
|
15
|
+
require 'symbolic/function'
|
16
|
+
require 'symbolic/math'
|
17
|
+
|
18
|
+
require 'extensions/kernel'
|
19
|
+
require 'extensions/numeric'
|
20
|
+
require 'extensions/matrix'
|
21
|
+
|
1
22
|
module Symbolic
|
2
|
-
def
|
3
|
-
|
4
|
-
:+ => :addition,
|
5
|
-
:- => :subtraction,
|
6
|
-
:/ => :division }
|
23
|
+
def -@
|
24
|
+
Operation::Unary::Minus.for self
|
7
25
|
end
|
8
26
|
|
9
|
-
|
10
|
-
|
11
|
-
def #{sign}(value)
|
12
|
-
Optimization.#{name} self, value
|
13
|
-
end
|
14
|
-
CODE
|
15
|
-
class_eval method, __FILE__, __LINE__
|
27
|
+
def +@
|
28
|
+
self
|
16
29
|
end
|
17
30
|
|
18
|
-
def
|
19
|
-
|
31
|
+
def +(var)
|
32
|
+
Operation::Binary::Addition.for self, var
|
20
33
|
end
|
21
34
|
|
22
|
-
def
|
23
|
-
|
35
|
+
def -(var)
|
36
|
+
Operation::Binary::Subtraction.for self, var
|
24
37
|
end
|
25
38
|
|
26
|
-
def
|
27
|
-
self
|
39
|
+
def *(var)
|
40
|
+
Operation::Binary::Multiplication.for self, var
|
28
41
|
end
|
29
42
|
|
30
|
-
def
|
31
|
-
|
43
|
+
def /(var)
|
44
|
+
Operation::Binary::Division.for self, var
|
45
|
+
end
|
46
|
+
|
47
|
+
def **(var)
|
48
|
+
Operation::Binary::Exponentiation.for self, var
|
32
49
|
end
|
33
50
|
|
34
|
-
def
|
35
|
-
|
51
|
+
def coerce(numeric)
|
52
|
+
return Coerced.new(self), numeric
|
36
53
|
end
|
37
54
|
|
38
55
|
def operations
|
39
56
|
detailed_operations.values.inject(0) {|sum,it| sum + it }
|
40
57
|
end
|
41
|
-
end
|
42
|
-
|
43
|
-
require 'symbolic/coerced'
|
44
|
-
require 'symbolic/optimization'
|
45
|
-
require 'symbolic/optimization/base'
|
46
|
-
require 'symbolic/optimization/addition'
|
47
|
-
require 'symbolic/optimization/subtraction'
|
48
|
-
require 'symbolic/optimization/multiplication'
|
49
|
-
require 'symbolic/optimization/division'
|
50
|
-
require 'symbolic/variable'
|
51
|
-
require 'symbolic/expression'
|
52
|
-
require 'symbolic/method'
|
53
|
-
require 'symbolic/unary_minus'
|
54
|
-
|
55
|
-
require 'extensions/kernel'
|
56
|
-
require 'extensions/numeric'
|
57
|
-
require 'extensions/matrix'
|
58
|
+
end
|
data/lib/symbolic/coerced.rb
CHANGED
@@ -4,13 +4,24 @@ module Symbolic
|
|
4
4
|
@symbolic = symbolic
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
7
|
+
def +(numeric)
|
8
|
+
Operation::Binary::Addition.for numeric, @symbolic
|
9
|
+
end
|
10
|
+
|
11
|
+
def -(numeric)
|
12
|
+
Operation::Binary::Subtraction.for numeric, @symbolic
|
13
|
+
end
|
14
|
+
|
15
|
+
def *(numeric)
|
16
|
+
Operation::Binary::Multiplication.for numeric, @symbolic
|
17
|
+
end
|
18
|
+
|
19
|
+
def /(numeric)
|
20
|
+
Operation::Binary::Division.for numeric, @symbolic
|
21
|
+
end
|
22
|
+
|
23
|
+
def **(numeric)
|
24
|
+
Operation::Binary::Exponentiation.for numeric, @symbolic
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Symbolic::Operation
|
2
|
+
include Symbolic
|
3
|
+
|
4
|
+
def self.for(*args)
|
5
|
+
simplify(*args) || new(*args)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.negative?(var)
|
9
|
+
var.is_a?(Unary::Minus) || (var.is_a?(Numeric) && var < 0)
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def operation(expression)
|
15
|
+
case expression
|
16
|
+
when Unary::Minus then :unary_minus
|
17
|
+
when Binary::Addition then :addition
|
18
|
+
when Binary::Subtraction then :subtraction
|
19
|
+
when Binary::Multiplication then :multiplication
|
20
|
+
when Binary::Division then :division
|
21
|
+
when Symbolic::Variable then :variable
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def unary_minus?(expression)
|
26
|
+
operation(expression) == :unary_minus
|
27
|
+
end
|
28
|
+
|
29
|
+
def addition?(expression)
|
30
|
+
operation(expression) == :addition
|
31
|
+
end
|
32
|
+
|
33
|
+
def subtraction?(expression)
|
34
|
+
operation(expression) == :subtraction
|
35
|
+
end
|
36
|
+
|
37
|
+
def multiplication?(expression)
|
38
|
+
operation(expression) == :multiplication
|
39
|
+
end
|
40
|
+
|
41
|
+
def division?(expression)
|
42
|
+
operation(expression) == :division
|
43
|
+
end
|
44
|
+
|
45
|
+
def variable?(expression)
|
46
|
+
operation(expession) == :variable
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Symbolic::Operation::Binary < Symbolic::Operation
|
2
|
+
def self.simplify(var1, var2)
|
3
|
+
simplify_first_arg(var1, var2) || simplify_second_arg(var1, var2)
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.symmetric
|
7
|
+
def self.simplify(var1, var2)
|
8
|
+
simplify_first_arg(var1, var2) || simplify_first_arg(var2, var1)
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(object)
|
12
|
+
(object.class == self.class) &&
|
13
|
+
((object.var1 == @var1 && object.var2 == @var2) || (object.var1 == @var2 && object.var2 == @var1))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.brackets_for(*operations)
|
18
|
+
def brackets(var)
|
19
|
+
operations.include?(operation var) ? "(#{var})" : var.to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(var1, var2)
|
24
|
+
@var1, @var2 = var1, var2
|
25
|
+
end
|
26
|
+
|
27
|
+
def variables
|
28
|
+
@var1.variables | @var2.variables
|
29
|
+
end
|
30
|
+
|
31
|
+
def undefined_variables
|
32
|
+
variables.select {|it| it.value.nil? }
|
33
|
+
end
|
34
|
+
|
35
|
+
def value
|
36
|
+
@var1.value.send sign, @var2.value if undefined_variables.empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
def detailed_operations
|
40
|
+
operations_of(@var1).tap {|it| it.merge!(operations_of @var2)[sign] += 1 }
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
"#{brackets @var1}#{sign}#{brackets @var2}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def ==(object)
|
48
|
+
(object.class == self.class) && (object.var1 == @var1 && object.var2 == @var2)
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
attr_reader :var1, :var2
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def operations_of(var)
|
58
|
+
var.is_a?(Symbolic) ? var.detailed_operations : Hash.new(0)
|
59
|
+
end
|
60
|
+
|
61
|
+
def brackets(var)
|
62
|
+
var.to_s
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Symbolic::Operation::Binary::Division < Symbolic::Operation::Binary
|
2
|
+
brackets_for :unary_minus, :addition, :subtraction
|
3
|
+
|
4
|
+
def self.simplify_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.simplify_second_arg(var1, var2)
|
13
|
+
if var2 == 1
|
14
|
+
var1
|
15
|
+
elsif negative?(var2)
|
16
|
+
-(var1 / var2.abs)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def sign
|
21
|
+
'/'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Symbolic::Operation::Binary::Exponentiation < Symbolic::Operation::Binary
|
2
|
+
brackets_for :unary_minus, :addition, :subtraction, :multiplication, :division
|
3
|
+
|
4
|
+
def self.simplify_first_arg(var1, var2)
|
5
|
+
# add conditional for negative?(var1) and even or odd values of var2
|
6
|
+
if var1 == 0
|
7
|
+
0
|
8
|
+
elsif var1 == 1
|
9
|
+
1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.simplify_second_arg(var1, var2)
|
14
|
+
if var2 == 0
|
15
|
+
1
|
16
|
+
elsif var2 == 1
|
17
|
+
var1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def sign
|
22
|
+
'**'
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Symbolic::Operation::Binary::Multiplication < Symbolic::Operation::Binary
|
2
|
+
symmetric
|
3
|
+
brackets_for :unary_minus, :addition, :subtraction
|
4
|
+
|
5
|
+
def self.simplify_first_arg(var1, var2)
|
6
|
+
if var1 == 0
|
7
|
+
0
|
8
|
+
elsif var1 == 1
|
9
|
+
var2
|
10
|
+
elsif negative?(var1)
|
11
|
+
-(var1.abs * var2)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def sign
|
16
|
+
'*'
|
17
|
+
end
|
18
|
+
|
19
|
+
# def initialize(var1, var2)
|
20
|
+
# super
|
21
|
+
# coef, numerators, denominators = unite_factors factors_of(var1), factors_of(var2)
|
22
|
+
# end
|
23
|
+
|
24
|
+
def unite_factors(factors1, factors2)
|
25
|
+
c1, n1, d1 = factors1
|
26
|
+
c2, n2, d2 = factors2
|
27
|
+
return c1*c2, n1+n2, d1+d2
|
28
|
+
end
|
29
|
+
|
30
|
+
def factors_of(var)
|
31
|
+
case var
|
32
|
+
when Numeric
|
33
|
+
[var, [], []]
|
34
|
+
when Unary::Minus
|
35
|
+
unite_factors [-1, [], []], factors_of(var.abs)
|
36
|
+
when Binary::Multiplication
|
37
|
+
[var.coef, var.nominators, var.denominators]
|
38
|
+
else
|
39
|
+
[[], [var], []]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Symbolic::Operation::Binary::Subtraction < Symbolic::Operation::Binary
|
2
|
+
def self.simplify_first_arg(var1, var2)
|
3
|
+
-var2 if var1 == 0
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.simplify_second_arg(var1, var2)
|
7
|
+
if var2 == 0
|
8
|
+
var1
|
9
|
+
elsif negative?(var2)
|
10
|
+
var1 + var2.abs
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def sign
|
15
|
+
'-'
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Symbolic::Operation
|
2
|
+
class Unary::Minus < Unary
|
3
|
+
def self.simplify(expression)
|
4
|
+
expression.abs if expression.is_a? Unary::Minus
|
5
|
+
end
|
6
|
+
|
7
|
+
def abs
|
8
|
+
# TODO: implement Symbolic#abs
|
9
|
+
@expression
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
if [:variable, :multiplication, :division].include? operation(@expression)
|
14
|
+
"-#{@expression}"
|
15
|
+
else
|
16
|
+
"(-#{@expression})"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def value
|
21
|
+
-@expression.value if undefined_variables.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def ==(object)
|
25
|
+
object.is_a?(Unary::Minus) && object.abs == @expression
|
26
|
+
end
|
27
|
+
|
28
|
+
def detailed_operations
|
29
|
+
@expression.detailed_operations.tap {|it| it['-@'] += 1}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/symbolic/variable.rb
CHANGED
data/spec/symbolic_spec.rb
CHANGED
@@ -7,7 +7,15 @@ describe "Symbolic" do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def expression(string)
|
10
|
-
eval string.gsub(/[
|
10
|
+
eval string.gsub(/[xy]/, '@\0')
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.should_equal(conditions)
|
14
|
+
conditions.each do |non_optimized, optimized|
|
15
|
+
it non_optimized do
|
16
|
+
expression(non_optimized).should == expression(optimized)
|
17
|
+
end
|
18
|
+
end
|
11
19
|
end
|
12
20
|
|
13
21
|
describe "evaluation (x=1, y=2):" do
|
@@ -39,18 +47,13 @@ describe "Symbolic" do
|
|
39
47
|
'y/2' => 1,
|
40
48
|
'x/2.0' => 0.5,
|
41
49
|
'-2/x' => -2,
|
42
|
-
'4/(-y)' => -2
|
50
|
+
'4/(-y)' => -2,
|
51
|
+
'x**2' => 1,
|
52
|
+
'4**y' => 16,
|
53
|
+
'y**x' => 2
|
43
54
|
end
|
44
55
|
|
45
56
|
describe "optimization:" do
|
46
|
-
def self.should_equal(conditions)
|
47
|
-
conditions.each do |non_optimized, optimized|
|
48
|
-
it non_optimized do
|
49
|
-
expression(non_optimized).should == expression(optimized)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
57
|
should_equal \
|
55
58
|
'-(-x)' => 'x',
|
56
59
|
|
@@ -81,7 +84,22 @@ describe "Symbolic" do
|
|
81
84
|
'-x*y' => '-(x*y)',
|
82
85
|
'(-x)*(-y)' => 'x*y',
|
83
86
|
|
84
|
-
'
|
87
|
+
'0 / x' => '0',
|
88
|
+
'x / 1' => 'x',
|
89
|
+
|
90
|
+
'0**x' => '0',
|
91
|
+
'1**x' => '1',
|
92
|
+
'x**0' => '1',
|
93
|
+
'x**1' => 'x'
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'general methods:' do
|
97
|
+
should_equal \
|
98
|
+
'x.variables' => '[x]',
|
99
|
+
'(-(x-y)).variables' => '[x,y]',
|
100
|
+
'(x+y).undefined_variables' => '[]',
|
101
|
+
'(-x-4*y+5-y/x).detailed_operations' =>
|
102
|
+
'{"+" => 1, "-" => 2, "*" => 1, "/" => 1, "-@" => 1}'
|
85
103
|
end
|
86
104
|
|
87
105
|
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.2.
|
4
|
+
version: 0.2.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-12-
|
12
|
+
date: 2009-12-08 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -39,15 +39,17 @@ files:
|
|
39
39
|
- lib/extensions/numeric.rb
|
40
40
|
- lib/symbolic.rb
|
41
41
|
- lib/symbolic/coerced.rb
|
42
|
-
- lib/symbolic/
|
43
|
-
- lib/symbolic/
|
44
|
-
- lib/symbolic/
|
45
|
-
- lib/symbolic/
|
46
|
-
- lib/symbolic/
|
47
|
-
- lib/symbolic/
|
48
|
-
- lib/symbolic/
|
49
|
-
- lib/symbolic/
|
50
|
-
- lib/symbolic/
|
42
|
+
- lib/symbolic/function.rb
|
43
|
+
- lib/symbolic/math.rb
|
44
|
+
- lib/symbolic/operation.rb
|
45
|
+
- lib/symbolic/operation/binary.rb
|
46
|
+
- lib/symbolic/operation/binary/addition.rb
|
47
|
+
- lib/symbolic/operation/binary/division.rb
|
48
|
+
- lib/symbolic/operation/binary/exponentiation.rb
|
49
|
+
- lib/symbolic/operation/binary/multiplication.rb
|
50
|
+
- lib/symbolic/operation/binary/subtraction.rb
|
51
|
+
- lib/symbolic/operation/unary.rb
|
52
|
+
- lib/symbolic/operation/unary/minus.rb
|
51
53
|
- lib/symbolic/variable.rb
|
52
54
|
- spec/spec.opts
|
53
55
|
- spec/spec_helper.rb
|
data/lib/symbolic/expression.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
module Symbolic
|
2
|
-
class Expression
|
3
|
-
include Symbolic
|
4
|
-
|
5
|
-
attr_reader :var1, :var2, :operation
|
6
|
-
|
7
|
-
def initialize(var1, var2, operation)
|
8
|
-
@var1, @var2, @operation = var1, var2, operation
|
9
|
-
end
|
10
|
-
|
11
|
-
def to_s
|
12
|
-
"#{brackets @var1}#{@operation}#{brackets @var2}"
|
13
|
-
end
|
14
|
-
|
15
|
-
def plus?
|
16
|
-
@operation == '+'
|
17
|
-
end
|
18
|
-
|
19
|
-
def minus?
|
20
|
-
@operation == '-'
|
21
|
-
end
|
22
|
-
|
23
|
-
def multiply?
|
24
|
-
@operation == '*'
|
25
|
-
end
|
26
|
-
|
27
|
-
def divide?
|
28
|
-
@operation == '/'
|
29
|
-
end
|
30
|
-
|
31
|
-
def value
|
32
|
-
@var1.value.send @operation, @var2.value if undefined_variables.empty?
|
33
|
-
end
|
34
|
-
|
35
|
-
def variables
|
36
|
-
@var1.variables | @var2.variables
|
37
|
-
end
|
38
|
-
|
39
|
-
def undefined_variables
|
40
|
-
variables.select &:undefined?
|
41
|
-
end
|
42
|
-
|
43
|
-
def ==(object)
|
44
|
-
object.is_a?(Expression) && (object.operation == @operation) &&
|
45
|
-
((object.var1 == @var1 && object.var2 == @var2) || ((plus? || multiply?) && (object.var1 == @var2 && object.var2 == @var1)))
|
46
|
-
end
|
47
|
-
|
48
|
-
def detailed_operations
|
49
|
-
operations_of(@var1).tap {|it| it.merge!(operations_of @var2)[@operation] += 1 }
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def brackets(var)
|
55
|
-
brackets_conditional(var) ? "(#{var})" : var.to_s
|
56
|
-
end
|
57
|
-
|
58
|
-
def brackets_conditional(var)
|
59
|
-
%w(* /).include?(@operation) && (var.is_a?(UnaryMinus) || var.is_a?(Expression) && (var.plus? || var.minus?))
|
60
|
-
end
|
61
|
-
|
62
|
-
def operations_of(var)
|
63
|
-
var.is_a?(Symbolic) ? var.detailed_operations : Hash.new(0)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
module Symbolic
|
2
|
-
module Optimization
|
3
|
-
Symbolic.operations.each do |operation_sign, operation_name|
|
4
|
-
method = <<-CODE
|
5
|
-
def #{operation_name}(var1, var2)
|
6
|
-
#{operation_name.to_s.capitalize}.optimize(var1, var2) || Expression.new(var1, var2, '#{operation_sign}')
|
7
|
-
end
|
8
|
-
CODE
|
9
|
-
instance_eval method, __FILE__, __LINE__
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Symbolic::Optimization::Addition
|
2
|
-
extend Symbolic::Optimization::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
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Symbolic::Optimization::Division
|
2
|
-
extend Symbolic::Optimization::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
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Symbolic::Optimization::Multiplication
|
2
|
-
extend Symbolic::Optimization::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
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Symbolic::Optimization::Subtraction
|
2
|
-
extend Symbolic::Optimization::Base
|
3
|
-
|
4
|
-
def self.optimize_first_arg(var1, var2)
|
5
|
-
-var2 if var1 == 0
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.optimize_second_arg(var1, var2)
|
9
|
-
if var2 == 0
|
10
|
-
var1
|
11
|
-
elsif negative?(var2)
|
12
|
-
var1 + var2.abs
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
data/lib/symbolic/unary_minus.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
module Symbolic
|
2
|
-
class UnaryMinus
|
3
|
-
include Symbolic
|
4
|
-
|
5
|
-
def self.create(var)
|
6
|
-
var.is_a?(UnaryMinus) ? var.abs : new(var)
|
7
|
-
end
|
8
|
-
|
9
|
-
def initialize(variable)
|
10
|
-
@variable = variable
|
11
|
-
end
|
12
|
-
|
13
|
-
def to_s
|
14
|
-
if @variable.is_a? Variable
|
15
|
-
"-#{@variable}"
|
16
|
-
else
|
17
|
-
"(-#{@variable})"
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def abs
|
22
|
-
# TODO: add a common method for Symbolic which will point to an instance of Abs(magnitude) class
|
23
|
-
@variable
|
24
|
-
end
|
25
|
-
|
26
|
-
def value
|
27
|
-
-@variable.value if undefined_variables.empty?
|
28
|
-
end
|
29
|
-
|
30
|
-
def variables
|
31
|
-
@variable.variables
|
32
|
-
end
|
33
|
-
|
34
|
-
def undefined_variables
|
35
|
-
@variable.undefined_variables
|
36
|
-
end
|
37
|
-
|
38
|
-
def ==(object)
|
39
|
-
object.is_a?(UnaryMinus) && object.abs == @variable
|
40
|
-
end
|
41
|
-
|
42
|
-
def detailed_operations
|
43
|
-
@variable.detailed_operations.tap {|it| it['-@'] += 1}
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|