ragni-cas 0.2.5 → 0.2.6
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -2
- data/lib/{ragni-cas.rb → Mr.CAS.rb} +3 -2
- data/lib/Mr.CAS/auto-diff.rb +129 -0
- data/lib/Mr.CAS/c-opt.rb +225 -0
- data/lib/Mr.CAS/c.rb +126 -0
- data/lib/{ragni-cas/plugins → Mr.CAS}/graphviz.rb +0 -0
- data/lib/{ragni-cas/plugins → Mr.CAS}/latex.rb +0 -0
- data/lib/Mr.CAS/matlab.rb +81 -0
- data/lib/functions/fnc-base.rb +1 -157
- data/lib/functions/fnc-prod.rb +102 -0
- data/lib/functions/fnc-sum.rb +151 -0
- data/lib/numbers/functions.rb +27 -18
- data/lib/operators/bary-op.rb +14 -13
- data/lib/operators/nary-op.rb +66 -7
- data/lib/operators/op.rb +8 -7
- data/lib/version.rb +1 -2
- metadata +13 -7
- metadata.gz.sig +0 -0
File without changes
|
File without changes
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# __ __ _ _ _ ___ _ _
|
4
|
+
# | \/ |__ _| |_| |__ _| |__ | _ \ |_ _ __ _(_)_ _
|
5
|
+
# | |\/| / _` | _| / _` | '_ \ | _/ | || / _` | | ' \
|
6
|
+
# |_| |_\__,_|\__|_\__,_|_.__/ |_| |_|\_,_\__, |_|_||_|
|
7
|
+
# |___/
|
8
|
+
|
9
|
+
module CAS
|
10
|
+
{
|
11
|
+
# Terminal nodes
|
12
|
+
CAS::Constant => Proc.new { |_v| "#{x}", nil },
|
13
|
+
CAS::Variable => Proc.new { |_v| "#{name}", nil },
|
14
|
+
CAS::PI_CONSTANT => Proc.new { |_v| "pi", nil },
|
15
|
+
CAS::INFINITY_CONSTANT => Proc.new { |_v| "Inf", nil },
|
16
|
+
CAS::NEG_INFINITY_CONSTANT => Proc.new { |_v| "(-Inf)", nil },
|
17
|
+
CAS::E_CONSTANT => Proc.new { |_v|
|
18
|
+
},
|
19
|
+
# Base functions
|
20
|
+
CAS::Sum => Proc.new { "(#{x.to_c} + #{y.to_c})" },
|
21
|
+
CAS::Diff => Proc.new { "(#{x.to_c} - #{y.to_c})" },
|
22
|
+
CAS::Prod => Proc.new { "(#{x.to_c} * #{y.to_c})" },
|
23
|
+
CAS::Pow => Proc.new { "pow(#{x.to_c}, #{y.to_c})" },
|
24
|
+
CAS::Div => Proc.new { "(#{x.to_c}) / (#{y.to_c} + )" },
|
25
|
+
CAS::Sqrt => Proc.new { "sqrt(#{x.to_c})" },
|
26
|
+
CAS::Invert => Proc.new { "(-#{x.to_c})" },
|
27
|
+
CAS::Abs => Proc.new { "fabs(#{x.to_c})" },
|
28
|
+
|
29
|
+
# Trigonometric functions
|
30
|
+
CAS::Sin => Proc.new { "sin(#{x.to_c})" },
|
31
|
+
CAS::Asin => Proc.new { "asin(#{x.to_c})" },
|
32
|
+
CAS::Cos => Proc.new { "cos(#{x.to_c})" },
|
33
|
+
CAS::Acos => Proc.new { "acos(#{x.to_c})" },
|
34
|
+
CAS::Tan => Proc.new { "tan(#{x.to_c})" },
|
35
|
+
CAS::Atan => Proc.new { "atan(#{x.to_c})" },
|
36
|
+
|
37
|
+
# Trascendent functions
|
38
|
+
CAS::Exp => Proc.new { "exp(#{x.to_c})" },
|
39
|
+
CAS::Ln => Proc.new { "log(#{x.to_c})" },
|
40
|
+
|
41
|
+
# Box Conditions
|
42
|
+
# CAS::BoxConditionOpen => Proc.new {
|
43
|
+
# ["double __t_#{x.object_id} = #{x.to_c};",
|
44
|
+
# "(__t_#{x.object_id} > #{lower.latex} && __t_#{x.object_id} < #{upper.latex})"]
|
45
|
+
# },
|
46
|
+
# CAS::BoxConditionUpperClosed => Proc.new {
|
47
|
+
# ["double __t_#{x.object_id} = #{x.to_c};",
|
48
|
+
# "(__t_#{x.object_id} > #{lower.latex} && __t_#{x.object_id} <= #{upper.latex})"]
|
49
|
+
# },
|
50
|
+
# CAS::BoxConditionLowerClosed => Proc.new {
|
51
|
+
# ["double __t_#{x.object_id} = #{x.to_c};",
|
52
|
+
# "(__t_#{x.object_id} >= #{lower.latex} && __t_#{x.object_id} < #{upper.latex})"]
|
53
|
+
# },
|
54
|
+
# CAS::BoxConditionClosed => Proc.new {
|
55
|
+
# ["double __t_#{x.object_id} = #{x.to_c};",
|
56
|
+
# "(__t_#{x.object_id} >= #{lower.latex} && __t_#{x.object_id} <= #{upper.latex})"]
|
57
|
+
# },
|
58
|
+
|
59
|
+
# Conditions
|
60
|
+
CAS::Equal => Proc.new { "(#{x.to_c} == #{y.to_c})" },
|
61
|
+
CAS::Smaller => Proc.new { "(#{x.to_c} < #{y.to_c})" },
|
62
|
+
CAS::Greater => Proc.new { "(#{x.to_c} > #{y.to_c})" },
|
63
|
+
CAS::SmallerEqual => Proc.new { "(#{x.to_c} <= #{y.to_c})" },
|
64
|
+
CAS::GreaterEqual => Proc.new { "(#{x.to_c} >= #{y.to_c})" },
|
65
|
+
|
66
|
+
# Piecewise
|
67
|
+
CAS::Piecewise => Proc.new { raise CASError, "Not implemented yet" },
|
68
|
+
CAS::Max => Proc.new { raise CASError, "Not implemented yet" },
|
69
|
+
CAS::Min => Proc.new { raise CASError, "Not implemented yet" }
|
70
|
+
}.each do |cls, blk|
|
71
|
+
cls.send(:define_method, "__to_matlab", &blk)
|
72
|
+
end
|
73
|
+
|
74
|
+
class Op
|
75
|
+
def to_c_lib(name)
|
76
|
+
CAS::Help.assert(name, String)
|
77
|
+
[CAS::C_PLUGIN.write_header(self, name), CAS::C_PLUGIN.write_source(self, name)]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
data/lib/functions/fnc-base.rb
CHANGED
@@ -1,85 +1,6 @@
|
|
1
1
|
#!/usr/vin/env ruby
|
2
2
|
|
3
3
|
module CAS
|
4
|
-
# ___
|
5
|
-
# / __|_ _ _ __
|
6
|
-
# \__ \ || | ' \
|
7
|
-
# |___/\_,_|_|_|_|
|
8
|
-
|
9
|
-
##
|
10
|
-
# **Sum basic operation**. As for now it is implemented as a simple
|
11
|
-
# binary operation. It will be implemented as n-ary op.
|
12
|
-
class Sum < CAS::BinaryOp
|
13
|
-
# Performs the sum between two `CAS::Op`
|
14
|
-
#
|
15
|
-
# ```
|
16
|
-
# d
|
17
|
-
# ---- (f(x) + g(x)) = f'(x) + g'(x)
|
18
|
-
# dx
|
19
|
-
# ```
|
20
|
-
#
|
21
|
-
# * **argument**: `CAS::Op` argument of derivative
|
22
|
-
# * **returns**: `CAS::Op` derivative
|
23
|
-
def diff(v)
|
24
|
-
left, right = super v
|
25
|
-
|
26
|
-
return left if right == CAS::Zero
|
27
|
-
return right if left == CAS::Zero
|
28
|
-
left + right
|
29
|
-
end
|
30
|
-
|
31
|
-
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
32
|
-
# or `Float` (depends upon promotions).
|
33
|
-
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
34
|
-
# as keys, and a `Numeric` as a value. In this case it will call
|
35
|
-
# the `Fixnum#overloaded_plus`, that is the old plus function.
|
36
|
-
#
|
37
|
-
# * **argument**: `Hash` with feed dictionary
|
38
|
-
# * **returns**: `Numeric`
|
39
|
-
def call(f)
|
40
|
-
CAS::Help.assert(f, Hash)
|
41
|
-
return @x.call(f).overloaded_plus(@y.call(f))
|
42
|
-
end
|
43
|
-
|
44
|
-
# Convert expression to string
|
45
|
-
#
|
46
|
-
# * **returns**: `String` to print on screen
|
47
|
-
def to_s
|
48
|
-
"(#{@x} + #{@y})"
|
49
|
-
end
|
50
|
-
|
51
|
-
# Same as `CAS::Op`
|
52
|
-
#
|
53
|
-
# Simplifcation engine supports:
|
54
|
-
#
|
55
|
-
# * x + 0 = x
|
56
|
-
# * 0 + y = y
|
57
|
-
# * x + x = 2 x
|
58
|
-
# * x + (-x) = 0
|
59
|
-
# * x + (-y) = x - y
|
60
|
-
# * 1 + 2 = 3 (constants reduction)
|
61
|
-
#
|
62
|
-
# * **returns**: `CAS::Op` simplified version
|
63
|
-
def simplify
|
64
|
-
super
|
65
|
-
return @y if @x == CAS::Zero
|
66
|
-
return @x if @y == CAS::Zero
|
67
|
-
return @x * 2.0 if @x == @y
|
68
|
-
return CAS::Zero if @x == -@y or -@x == @y
|
69
|
-
return (@x - @y.x) if @y.is_a? CAS::Invert
|
70
|
-
return CAS.const(self.call({})) if (@x.is_a? CAS::Constant and @y.is_a? CAS::Constant)
|
71
|
-
return self
|
72
|
-
end
|
73
|
-
|
74
|
-
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
75
|
-
#
|
76
|
-
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
77
|
-
def to_code
|
78
|
-
"(#{@x.to_code} + #{@y.to_code})"
|
79
|
-
end
|
80
|
-
end # Sum
|
81
|
-
CAS::Sum.init_simplify_dict
|
82
|
-
|
83
4
|
# ___ _ __ __
|
84
5
|
# | \(_)/ _|/ _|
|
85
6
|
# | |) | | _| _/
|
@@ -149,83 +70,6 @@ module CAS
|
|
149
70
|
end # Difference
|
150
71
|
CAS::Diff.init_simplify_dict
|
151
72
|
|
152
|
-
# ___ _
|
153
|
-
# | _ \_ _ ___ __| |
|
154
|
-
# | _/ '_/ _ \/ _` |
|
155
|
-
# |_| |_| \___/\__,_|
|
156
|
-
|
157
|
-
##
|
158
|
-
# Product class. Performs the product between two elements.
|
159
|
-
# This class will be soon modified as an n-ary operator.
|
160
|
-
class Prod < CAS::BinaryOp
|
161
|
-
# Performs the product between two `CAS::Op`
|
162
|
-
#
|
163
|
-
# ```
|
164
|
-
# d
|
165
|
-
# ---- (f(x) * g(x)) = f'(x) * g(x) + f(x) * g'(x)
|
166
|
-
# dx
|
167
|
-
# ```
|
168
|
-
#
|
169
|
-
# * **argument**: `CAS::Op` argument of derivative
|
170
|
-
# * **returns**: `CAS::Op` derivative
|
171
|
-
def diff(v)
|
172
|
-
left, right = super v
|
173
|
-
return left * @y if right == CAS::Zero
|
174
|
-
return right * @x if left == CAS::Zero
|
175
|
-
(left * @y) + (right * @x)
|
176
|
-
end
|
177
|
-
|
178
|
-
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
179
|
-
# or `Float` (depends upon promotions).
|
180
|
-
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
181
|
-
# as keys, and a `Numeric` as a value. In this case it will call
|
182
|
-
# the `Fixnum#overloaded_plus`, that is the old plus function.
|
183
|
-
#
|
184
|
-
# * **argument**: `Hash` with feed dictionary
|
185
|
-
# * **returns**: `Numeric`
|
186
|
-
def call(f)
|
187
|
-
CAS::Help.assert(f, Hash)
|
188
|
-
|
189
|
-
return @x.call(f).overloaded_mul(@y.call(f))
|
190
|
-
end
|
191
|
-
|
192
|
-
# Convert expression to string
|
193
|
-
#
|
194
|
-
# * **returns**: `String` to print on screen
|
195
|
-
def to_s
|
196
|
-
"(#{@x} * #{@y})"
|
197
|
-
end
|
198
|
-
|
199
|
-
# Same as `CAS::Op`
|
200
|
-
#
|
201
|
-
# Simplifcation engine supports:
|
202
|
-
#
|
203
|
-
# * x * 0 = x * y = 0
|
204
|
-
# * 1 * y = y
|
205
|
-
# * x * 1 = x
|
206
|
-
# * x * x = x²
|
207
|
-
# * a * b = c (constants reduction)
|
208
|
-
#
|
209
|
-
# * **returns**: `CAS::Op` simplified version
|
210
|
-
def simplify
|
211
|
-
super
|
212
|
-
return CAS::Zero if (@x == CAS::Zero or @y == CAS::Zero)
|
213
|
-
return @y if @x == CAS::One
|
214
|
-
return @x if @y == CAS::One
|
215
|
-
return @x ** 2.0 if @x == @y
|
216
|
-
return CAS.const(self.call({})) if @x.is_a? CAS::Constant and @y.is_a? CAS::Constant
|
217
|
-
return self
|
218
|
-
end
|
219
|
-
|
220
|
-
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
221
|
-
#
|
222
|
-
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
223
|
-
def to_code
|
224
|
-
"(#{@x.to_code} * #{@y.to_code})"
|
225
|
-
end
|
226
|
-
end # Prod
|
227
|
-
CAS::Prod.init_simplify_dict
|
228
|
-
|
229
73
|
# ___
|
230
74
|
# | _ \_____ __ __
|
231
75
|
# | _/ _ \ V V /
|
@@ -300,7 +144,7 @@ module CAS
|
|
300
144
|
return self if (@x == CAS::Infinity and @y == CAS::Infinity)
|
301
145
|
return self if (@x == CAS::Infinity and @y == CAS::Zero)
|
302
146
|
return self if (@x == CAS::Zero and @y == CAS::Infinity)
|
303
|
-
|
147
|
+
|
304
148
|
return CAS::Zero if @x == CAS::Zero
|
305
149
|
return CAS::One if @x == CAS::One
|
306
150
|
return @x if @y == CAS::One
|
@@ -0,0 +1,102 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module CAS
|
4
|
+
|
5
|
+
# ___ _
|
6
|
+
# | _ \_ _ ___ __| |
|
7
|
+
# | _/ '_/ _ \/ _` |
|
8
|
+
# |_| |_| \___/\__,_|
|
9
|
+
|
10
|
+
##
|
11
|
+
# Product class. Performs the product between two elements.
|
12
|
+
# This class will be soon modified as an n-ary operator.
|
13
|
+
class Prod < CAS::NaryOp
|
14
|
+
# The new element of a sum accumulates inside the
|
15
|
+
# vector that holds the elements
|
16
|
+
def *(op)
|
17
|
+
CAS::Help.assert(op, CAS::Op)
|
18
|
+
@x << op
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
# Performs the product between two `CAS::Op`
|
23
|
+
#
|
24
|
+
# ```
|
25
|
+
# d
|
26
|
+
# ---- (f(x) * g(x) * h(x)) = f'(x) * g(x) * h(x) +
|
27
|
+
# dx
|
28
|
+
# + f(x) * g'(x) * h(x) +
|
29
|
+
#
|
30
|
+
# + f(x) * g(x) * h'(x)
|
31
|
+
# ```
|
32
|
+
#
|
33
|
+
# * **argument**: `CAS::Op` argument of derivative
|
34
|
+
# * **returns**: `CAS::Op` derivative
|
35
|
+
def diff(v)
|
36
|
+
xdiff = @x.map { |y| y.diff(v) }
|
37
|
+
|
38
|
+
xdiff.each_with_index { |y, i|
|
39
|
+
xdiff[i] = y * CAS::Prod.new(@x[0...i] + @x[(i + 1)..-1])
|
40
|
+
}
|
41
|
+
|
42
|
+
return CAS::Sum.new(xdiff)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
46
|
+
# or `Float` (depends upon promotions).
|
47
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
48
|
+
# as keys, and a `Numeric` as a value. In this case it will call
|
49
|
+
# the `Fixnum#overloaded_plus`, that is the old plus function.
|
50
|
+
#
|
51
|
+
# * **argument**: `Hash` with feed dictionary
|
52
|
+
# * **returns**: `Numeric`
|
53
|
+
def call(f)
|
54
|
+
CAS::Help.assert(f, Hash)
|
55
|
+
|
56
|
+
return @x.inject { |p, y| p = p.overloaded_mul(y.call(f)) }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Convert expression to string
|
60
|
+
#
|
61
|
+
# * **returns**: `String` to print on screen
|
62
|
+
def to_s
|
63
|
+
"(#{@x.map(&:to_s).join(" * ")})"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Same as `CAS::Op`
|
67
|
+
#
|
68
|
+
# Simplifcation engine supports:
|
69
|
+
#
|
70
|
+
# * x * 0 = x * y = 0
|
71
|
+
# * 1 * y = y
|
72
|
+
# * x * 1 = x
|
73
|
+
# * x * x = x²
|
74
|
+
# * a * b = c (constants reduction)
|
75
|
+
#
|
76
|
+
# * **returns**: `CAS::Op` simplified version
|
77
|
+
def simplify
|
78
|
+
super
|
79
|
+
return CAS::Zero if @x.include? CAS::Zero
|
80
|
+
@x = @x - [CAS::One]
|
81
|
+
return CAS::One if @x.size == 0
|
82
|
+
return @x[0] if @x.size == 1
|
83
|
+
|
84
|
+
@x = self.__reduce_constants(@x) do |cs, xs|
|
85
|
+
[cs.inject { |t, c| t *= c.call({}) }] + xs
|
86
|
+
end
|
87
|
+
|
88
|
+
@x = self.__reduce_multeplicity(@x) do |op, count|
|
89
|
+
count > 1 ? (op ** count) : op
|
90
|
+
end
|
91
|
+
return self
|
92
|
+
end
|
93
|
+
|
94
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
95
|
+
#
|
96
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
97
|
+
def to_code
|
98
|
+
"(#{@x.map(&:to_code).join(" * ")})"
|
99
|
+
end
|
100
|
+
end # Prod
|
101
|
+
CAS::Prod.init_simplify_dict
|
102
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module CAS
|
2
|
+
# ___
|
3
|
+
# / __|_ _ _ __
|
4
|
+
# \__ \ || | ' \
|
5
|
+
# |___/\_,_|_|_|_|
|
6
|
+
|
7
|
+
##
|
8
|
+
# **Sum basic operation**. As for now it is implemented as a simple
|
9
|
+
# binary operation. It will be implemented as n-ary op.
|
10
|
+
class Sum < CAS::NaryOp
|
11
|
+
# Performs the sum between arbitrary number of `CAS::Op`
|
12
|
+
#
|
13
|
+
# ```
|
14
|
+
# d
|
15
|
+
# ---- (f(x) + g(x) + h(x)) = f'(x) + g'(x) + h'(x)
|
16
|
+
# dx
|
17
|
+
# ```
|
18
|
+
#
|
19
|
+
# * **argument**: `CAS::Op` argument of derivative
|
20
|
+
# * **returns**: `CAS::Op` derivative
|
21
|
+
def diff(v)
|
22
|
+
@x.map { |x| x.diff(v) }.inject { |sum_x, dx| sum_x += dx }
|
23
|
+
end
|
24
|
+
|
25
|
+
# The added element of a sum accumulates inside the
|
26
|
+
# vector that holds the elements
|
27
|
+
def +(op)
|
28
|
+
CAS::Help.assert(op, CAS::Op)
|
29
|
+
@x << op
|
30
|
+
self
|
31
|
+
end
|
32
|
+
|
33
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
34
|
+
# or `Float` (depends upon promotions).
|
35
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
36
|
+
# as keys, and a `Numeric` as a value. In this case it will call
|
37
|
+
# the `Fixnum#overloaded_plus`, that is the old plus function.
|
38
|
+
#
|
39
|
+
# * **argument**: `Hash` with feed dictionary
|
40
|
+
# * **returns**: `Numeric`
|
41
|
+
def call(f)
|
42
|
+
CAS::Help.assert(f, Hash)
|
43
|
+
return @x.inject { |val, x_i| val += x_i.call(f) }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Convert expression to string
|
47
|
+
#
|
48
|
+
# * **returns**: `String` to print on screen
|
49
|
+
def to_s
|
50
|
+
"(#{@x.map(&:to_s).join(" + ")})"
|
51
|
+
end
|
52
|
+
|
53
|
+
# Same as `CAS::Op`
|
54
|
+
#
|
55
|
+
# Simplifcation engine supports:
|
56
|
+
#
|
57
|
+
# * x + 0 = x
|
58
|
+
# * 0 + y = y
|
59
|
+
# * x + x = 2 x
|
60
|
+
# * x + (-x) = 0
|
61
|
+
# * x + (-y) = x - y
|
62
|
+
# * 1 + 2 = 3 (constants reduction)
|
63
|
+
#
|
64
|
+
# * **returns**: `CAS::Op` simplified version
|
65
|
+
def simplify
|
66
|
+
super
|
67
|
+
return @x[0] if @x.size == 1
|
68
|
+
|
69
|
+
# return CAS::Zero if @x == -@y or -@x == @y
|
70
|
+
# return (@x - @y.x) if @y.is_a? CAS::Invert
|
71
|
+
# return CAS.const(self.call({})) if (@x.is_a? CAS::Constant and @y.is_a? CAS::Constant)
|
72
|
+
# Removing Zeros
|
73
|
+
@x = @x - [CAS::Zero]
|
74
|
+
return CAS::Zero if @x.size == 0
|
75
|
+
# Reduce constants
|
76
|
+
@x = self.__reduce_constants(@x) do |cs, xs|
|
77
|
+
xs + [cs.inject { |t, c| t += c.call({}) }]
|
78
|
+
end
|
79
|
+
# Multeplicity and associativity executed
|
80
|
+
return self.reduce_associativity
|
81
|
+
end
|
82
|
+
|
83
|
+
# Reduces from an associative point of view, by a segregation
|
84
|
+
# of "negative" and positive elements. Negatives comes from
|
85
|
+
# Diff operations and Invert operations. All the others are considered
|
86
|
+
# positive. This function implements an internal heuristic. Should
|
87
|
+
# not be used outside
|
88
|
+
#
|
89
|
+
# * **returns**: A `CAS::Diff` or a `CAS::Sum`
|
90
|
+
def reduce_associativity
|
91
|
+
pos, neg = [], []
|
92
|
+
|
93
|
+
@x.each do |x_el|
|
94
|
+
case x_el
|
95
|
+
when CAS::Invert
|
96
|
+
neg << x_el.x
|
97
|
+
when CAS::Diff
|
98
|
+
pos << x_el.x
|
99
|
+
neg << x_el.y
|
100
|
+
else
|
101
|
+
pos << x_el
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
pos, neg = self.reduce_associativity_array pos, neg
|
106
|
+
pos = self.__reduce_multeplicity(pos)
|
107
|
+
neg = self.__reduce_multeplicity neg
|
108
|
+
|
109
|
+
# TODO : Add rules for simplifications
|
110
|
+
left, right = nil, nil
|
111
|
+
left = CAS::Sum.new(pos) if pos.size > 1
|
112
|
+
left = pos[0] if pos.size == 1
|
113
|
+
right = CAS::Sum.new(neg) if neg.size > 1
|
114
|
+
right = neg[0] if neg.size == 1
|
115
|
+
|
116
|
+
return CAS::Zero unless left || right
|
117
|
+
return left unless right
|
118
|
+
return -right unless left
|
119
|
+
return left - right
|
120
|
+
end
|
121
|
+
|
122
|
+
# Reduce the positive and the negative associative part of
|
123
|
+
# the sum to perform the symbolic difference. Does not take into account
|
124
|
+
# multeplicity
|
125
|
+
#
|
126
|
+
# * **requires**: positive `Array`
|
127
|
+
# * **requires**: negative `Array`
|
128
|
+
# * **returns**: positive, reduced `Array` and negative `Array`
|
129
|
+
def reduce_associativity_array(p_old, n_old)
|
130
|
+
p_del, n_del = [], []
|
131
|
+
p_old.each do |p|
|
132
|
+
n_old.each do |n|
|
133
|
+
if p == n
|
134
|
+
p_del << p
|
135
|
+
n_del << n
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
return (p_old - p_del), (n_old - n_del)
|
141
|
+
end
|
142
|
+
|
143
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
144
|
+
#
|
145
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
146
|
+
def to_code
|
147
|
+
"(#{@x.map(&:to_code).join(" + ")})"
|
148
|
+
end
|
149
|
+
end # Sum
|
150
|
+
CAS::Sum.init_simplify_dict
|
151
|
+
end
|