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 +0 -2
- data/Rakefile +1 -1
- data/lib/symbolic/function.rb +20 -21
- data/lib/symbolic/operation.rb +1 -0
- data/lib/symbolic/operation/binary/division.rb +1 -1
- data/lib/symbolic/operation/binary/exponentiation.rb +10 -1
- data/lib/symbolic/operation/binary/multiplication.rb +77 -37
- data/spec/symbolic_spec.rb +10 -3
- metadata +2 -2
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.
|
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"
|
data/lib/symbolic/function.rb
CHANGED
@@ -1,28 +1,27 @@
|
|
1
|
-
|
2
|
-
|
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
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def value
|
13
|
+
Math.send @operation, @variable.value if undefined_variables.empty?
|
14
|
+
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def variables
|
17
|
+
@variable.variables
|
18
|
+
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
20
|
+
def undefined_variables
|
21
|
+
@variable.undefined_variables
|
22
|
+
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
end
|
24
|
+
def detailed_operations
|
25
|
+
@variable.detailed_operations.tap {|it| it[@operation] += 1}
|
27
26
|
end
|
28
27
|
end
|
data/lib/symbolic/operation.rb
CHANGED
@@ -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
|
@@ -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
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
56
|
+
def sign
|
57
|
+
'*'
|
58
|
+
end
|
17
59
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
33
|
-
|
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
|
data/spec/symbolic_spec.rb
CHANGED
@@ -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)
|
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
|
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.
|
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-
|
12
|
+
date: 2009-12-11 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|