Mr.CAS 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 +7 -0
- checksums.yaml.gz.sig +1 -0
- data.tar.gz.sig +2 -0
- data/lib/Mr.CAS.rb +73 -0
- 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/Mr.CAS/graphviz.rb +132 -0
- data/lib/Mr.CAS/latex.rb +68 -0
- data/lib/Mr.CAS/matlab.rb +81 -0
- data/lib/functions/fnc-base.rb +515 -0
- data/lib/functions/fnc-box-conditions.rb +319 -0
- data/lib/functions/fnc-conditions.rb +365 -0
- data/lib/functions/fnc-piecewise.rb +186 -0
- data/lib/functions/fnc-prod.rb +102 -0
- data/lib/functions/fnc-sum.rb +151 -0
- data/lib/functions/fnc-trig.rb +489 -0
- data/lib/functions/fnc-trsc.rb +192 -0
- data/lib/numbers/constants.rb +350 -0
- data/lib/numbers/functions.rb +194 -0
- data/lib/numbers/variables.rb +202 -0
- data/lib/operators/bary-op.rb +186 -0
- data/lib/operators/nary-op.rb +232 -0
- data/lib/operators/op.rb +285 -0
- data/lib/overloading/fixnum.rb +61 -0
- data/lib/overloading/float.rb +61 -0
- data/lib/version.rb +12 -0
- metadata +88 -0
- metadata.gz.sig +2 -0
@@ -0,0 +1,232 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module CAS
|
4
|
+
# This is an attempt to build some sort of node in the graph that
|
5
|
+
# has arbitrary number of childs node. It should help implement more easily
|
6
|
+
# some sort of better simplifications engine
|
7
|
+
#
|
8
|
+
# This is an incredibly experimental feature.
|
9
|
+
class NaryOp < CAS::Op
|
10
|
+
# List of arguments of the operation
|
11
|
+
attr_reader :x
|
12
|
+
|
13
|
+
# Initialize a new empty N-elements operation container. This is
|
14
|
+
# a virtual class, and other must inherit from this basical container
|
15
|
+
#
|
16
|
+
# * **argument**: `Numeric` to be converted in `CAS::Constant` or `CAS::Op` child operations
|
17
|
+
# * **returns**: `CAS::NaryOp` instance
|
18
|
+
def initialize(*xs)
|
19
|
+
@x = []
|
20
|
+
xs.flatten.each do |x|
|
21
|
+
if x.is_a? Numeric
|
22
|
+
x = Op.numeric_to_const x
|
23
|
+
end
|
24
|
+
CAS::Help.assert(x, CAS::Op)
|
25
|
+
@x << x
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the dependencies of the operation. Require a `CAS::Variable`
|
30
|
+
# and it is one of the recursive method (implicit tree resolution)
|
31
|
+
#
|
32
|
+
# * **argument**: `CAS::Variable` instance
|
33
|
+
# * **returns**: `TrueClass` or `FalseClass`
|
34
|
+
def depend?(v)
|
35
|
+
CAS::Help.assert(v, CAS::Op)
|
36
|
+
@x.include? v
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return a list of derivative using the chain rule. The input is a
|
40
|
+
# operation:
|
41
|
+
#
|
42
|
+
# ```
|
43
|
+
# f(x) = g(x) + h(x) + l(x) + m(x)
|
44
|
+
#
|
45
|
+
# d f(x)
|
46
|
+
# ------ = g'(x) + h'(x) + l'(x) + m'(x)
|
47
|
+
# dx
|
48
|
+
#
|
49
|
+
# d f(x)
|
50
|
+
# ------ = 1
|
51
|
+
# d g(x)
|
52
|
+
# ```
|
53
|
+
# * **argument**: `CAS::Op` object of the derivative
|
54
|
+
# * **returns**: `CAS::NaryOp` of derivative
|
55
|
+
def diff(v)
|
56
|
+
CAS::Help.assert(v, CAS::Op)
|
57
|
+
if self.depend?(v)
|
58
|
+
return @x.map { |x| x.diff(v) }
|
59
|
+
end
|
60
|
+
return CAS::Zero
|
61
|
+
end
|
62
|
+
|
63
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
64
|
+
# or `Float` depends upon promotions).
|
65
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
66
|
+
# as keys, and a `Numeric` as a value
|
67
|
+
#
|
68
|
+
# ``` ruby
|
69
|
+
# x, y = CAS::vars :x, :y
|
70
|
+
# f = (x ** 2) + (y ** 2)
|
71
|
+
# f.call({x => 1, y => 2})
|
72
|
+
# # => 2
|
73
|
+
# ```
|
74
|
+
# * **argument**: `Hash` with feed dictionary
|
75
|
+
# * **returns**: `Array` of `Numeric`
|
76
|
+
def call(fd)
|
77
|
+
CAS::Help.assert(fd, Hash)
|
78
|
+
return @x.map { |x| x.call(fd) }
|
79
|
+
end
|
80
|
+
|
81
|
+
# Perform substitution of a part of the graph using a data table:
|
82
|
+
#
|
83
|
+
# ``` ruby
|
84
|
+
# x, y = CAS::vars :x, :y
|
85
|
+
# f = (x ** 2) + (y ** 2)
|
86
|
+
# puts f
|
87
|
+
# # => (x^2) + (y^2)
|
88
|
+
# puts f.subs({x => CAS::ln(y)})
|
89
|
+
# # => (ln(y)^2) + (y^2)
|
90
|
+
# ```
|
91
|
+
#
|
92
|
+
# * **argument**: `Hash` with substitution table
|
93
|
+
# * **returns**: `CAS::NaryOp` (`self`) with substitution performed
|
94
|
+
def subs(dt)
|
95
|
+
CAS::Help.assert(dt, Hash)
|
96
|
+
@x = @x.map { |z| z.subs(dt) || z }
|
97
|
+
@x.each_with_index do |x, k|
|
98
|
+
sub = dt.keys.select { |e| e == x }[0]
|
99
|
+
if sub
|
100
|
+
if dt[sub].is_a? CAS::Op
|
101
|
+
@x[k] = dt[sub]
|
102
|
+
elsif dt[sub].is_a? Numeric
|
103
|
+
@x[k] = CAS::const dt[sub]
|
104
|
+
else
|
105
|
+
raise CAS::CASError, "Impossible subs. Received a #{dt[sub].class} = #{dt[sub]}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
return self
|
110
|
+
end
|
111
|
+
|
112
|
+
# Convert expression to string
|
113
|
+
#
|
114
|
+
# * **returns**: `String` to print on screen
|
115
|
+
def to_s
|
116
|
+
return "(#{@x.map(&:to_s).join(", ")})"
|
117
|
+
end
|
118
|
+
|
119
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
120
|
+
#
|
121
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
122
|
+
def to_code
|
123
|
+
return "(#{@x.map(&:to_code).join(", ")})"
|
124
|
+
end
|
125
|
+
|
126
|
+
# Simplification callback. It simplify the subgraph of each node
|
127
|
+
# until all possible simplification are performed (thus the execution
|
128
|
+
# time is not deterministic).
|
129
|
+
#
|
130
|
+
# * **returns**: `CAS::Op` simplified
|
131
|
+
def simplify
|
132
|
+
hash = self.to_s
|
133
|
+
@x = @x.map { |x| x.simplify }
|
134
|
+
while self.to_s != hash
|
135
|
+
hash = self.to_s
|
136
|
+
@x = @x.map { |x| x.simplify }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Inspector for the current object
|
141
|
+
#
|
142
|
+
# * **returns**: `String`
|
143
|
+
def inspect
|
144
|
+
"#{self.class}(#{@x.map(&:inspect).join(", ")})"
|
145
|
+
end
|
146
|
+
|
147
|
+
# Equality operator, the standard operator is overloaded
|
148
|
+
# :warning: this operates on the graph, not on the math
|
149
|
+
# See `CAS::equal`, etc.
|
150
|
+
#
|
151
|
+
# * **argument**: `CAS::Op` to be tested against
|
152
|
+
# * **returns**: `TrueClass` if equal, `FalseClass` if differs
|
153
|
+
def ==(op)
|
154
|
+
# CAS::Help.assert(op, CAS::Op)
|
155
|
+
if op.is_a? CAS::NaryOp
|
156
|
+
return false if @x.size != op.x.size
|
157
|
+
0.upto(@x.size - 1) do |i|
|
158
|
+
return false if @x[i] != op.x[i]
|
159
|
+
end
|
160
|
+
return true
|
161
|
+
end
|
162
|
+
false
|
163
|
+
end
|
164
|
+
|
165
|
+
# Returns a list of all `CAS::Variable`s of the current tree
|
166
|
+
#
|
167
|
+
# * **returns**: `Array` of `CAS::Variable`s
|
168
|
+
def args
|
169
|
+
r = []
|
170
|
+
@x.each { |x| r += x.args }
|
171
|
+
return r.uniq
|
172
|
+
end
|
173
|
+
|
174
|
+
# Reduce multeplicity will scan for elements that are equal in the definition
|
175
|
+
# of the sum and will reduce their multeplicity. A block can be used to do something
|
176
|
+
# different. For example in nary-product we use it like this:
|
177
|
+
#
|
178
|
+
# ``` ruby
|
179
|
+
# @x = self.__reduce_multeplicity(@x) do |count, op|
|
180
|
+
# count > 1 ? (op ** count) : op
|
181
|
+
# end
|
182
|
+
# ```
|
183
|
+
#
|
184
|
+
# In general it works like that:
|
185
|
+
#
|
186
|
+
# ```
|
187
|
+
# a + a + b + c => 2 * a + b + c
|
188
|
+
# a * a * b * a => (a ** b) * b
|
189
|
+
# ```
|
190
|
+
# But operates only on Array level! This is an internal function
|
191
|
+
# and should never be used
|
192
|
+
#
|
193
|
+
# * **requires**: An `Array`
|
194
|
+
# * **returns**: An `Array` with multeplicity reduced
|
195
|
+
# * **block**: yields the count and the op. Get the value to insert in a new
|
196
|
+
# `Array` that is the returned `Array`
|
197
|
+
def __reduce_multeplicity(xs)
|
198
|
+
count = Hash.new(0)
|
199
|
+
xs.each do |x|
|
200
|
+
e = x
|
201
|
+
count.keys.each { |d| e = d if x == d }
|
202
|
+
count[e] += 1
|
203
|
+
end
|
204
|
+
count.map do |k, v|
|
205
|
+
if block_given?
|
206
|
+
yield(k, v)
|
207
|
+
else
|
208
|
+
v > 1 ? CAS.const(v) * k : k
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Collects all the constants and tries to reduce them to a single constant.
|
214
|
+
# Requires a block to understand what it should do with the constants
|
215
|
+
#
|
216
|
+
# * **requires**: input `Array` of `CAS::Op`
|
217
|
+
# * **returns**: new `Array` of `CAS::Op`
|
218
|
+
# * **block**: yields an `Array` of `CAS::Constant` and an `Array` of others `CAS::Op`,
|
219
|
+
# requires an `Array` back
|
220
|
+
def __reduce_constants(xs)
|
221
|
+
const = []
|
222
|
+
xs.each { |x| const << x if x.is_a? CAS::Constant }
|
223
|
+
if const.size > 0
|
224
|
+
yield const, (xs - const)
|
225
|
+
else
|
226
|
+
xs
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end # NaryOp
|
231
|
+
CAS::NaryOp.init_simplify_dict
|
232
|
+
end
|
data/lib/operators/op.rb
ADDED
@@ -0,0 +1,285 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module CAS
|
4
|
+
class CASError < RuntimeError; end
|
5
|
+
|
6
|
+
# ___
|
7
|
+
# / _ \ _ __
|
8
|
+
# | (_) | '_ \
|
9
|
+
# \___/| .__/
|
10
|
+
# |_|
|
11
|
+
class Op
|
12
|
+
# Argument of the operation
|
13
|
+
attr_reader :x
|
14
|
+
|
15
|
+
# Initialize a new empty operation container. This is a virtual
|
16
|
+
# class and the other must inherit from this basic container.
|
17
|
+
# Some methods raise a `CAS::CASError` if called.
|
18
|
+
# The input element is a Numric, to create a constant.
|
19
|
+
# `CAS::Op` specifies operations with a single variable
|
20
|
+
#
|
21
|
+
# * **argument**: `Numeric` to be converted in `CAS::Constant` or `CAS::Op` child operation
|
22
|
+
# * **returns**: `CAS::Op` instance
|
23
|
+
def initialize(x)
|
24
|
+
if x.is_a? Numeric
|
25
|
+
x = Op.numeric_to_const x
|
26
|
+
end
|
27
|
+
CAS::Help.assert(x, CAS::Op)
|
28
|
+
|
29
|
+
@x = x
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.numeric_to_const(x)
|
33
|
+
if CAS::NumericToConst[x]
|
34
|
+
return CAS::NumericToConst[x]
|
35
|
+
else
|
36
|
+
return CAS::const x
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return the dependencies of the operation. Requires a `CAS::Variable`
|
41
|
+
# and it is one of the recursve method (implicit tree resolution)
|
42
|
+
#
|
43
|
+
# * **argument**: `CAS::Variable` instance
|
44
|
+
# * **returns**: `TrueClass` if depends, `FalseClass` if not
|
45
|
+
def depend?(v)
|
46
|
+
CAS::Help.assert(v, CAS::Op)
|
47
|
+
|
48
|
+
@x.depend? v
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return the derivative of the operation using the chain rule
|
52
|
+
# The input is a `CAS::Op` because it can handle derivatives
|
53
|
+
# with respect to functions. E.g.:
|
54
|
+
#
|
55
|
+
# ```
|
56
|
+
# f(x) = (ln(x))**2
|
57
|
+
# g(x) = ln(x)
|
58
|
+
#
|
59
|
+
# d f(x)
|
60
|
+
# ------ = 2 ln(x)
|
61
|
+
# d g(x)
|
62
|
+
# ```
|
63
|
+
#
|
64
|
+
# * **argument**: `CAS::Op` object of the derivative
|
65
|
+
# * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
|
66
|
+
def diff(v)
|
67
|
+
CAS::Help.assert(v, CAS::Op)
|
68
|
+
|
69
|
+
if @x.depend? v
|
70
|
+
return @x.diff(v)
|
71
|
+
end
|
72
|
+
CAS::Zero
|
73
|
+
end
|
74
|
+
|
75
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
76
|
+
# or `Float` (depends upon promotions).
|
77
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
78
|
+
# as keys, and a `Numeric` as a value
|
79
|
+
#
|
80
|
+
# ``` ruby
|
81
|
+
# x, y = CAS::vars :x, :y
|
82
|
+
# f = (x ** 2) + (y ** 2)
|
83
|
+
# f.call({x => 1, y => 2})
|
84
|
+
# # => 2
|
85
|
+
# ```
|
86
|
+
#
|
87
|
+
# * **argument**: `Hash` with feed dictionary
|
88
|
+
# * **returns**: `Numeric`
|
89
|
+
def call(f)
|
90
|
+
CAS::Help.assert(f, Hash)
|
91
|
+
|
92
|
+
@x.call(f)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Perform substitution of a part of the graph using a data table:
|
96
|
+
#
|
97
|
+
# ``` ruby
|
98
|
+
# x, y = CAS::vars :x, :y
|
99
|
+
# f = (x ** 2) + (y ** 2)
|
100
|
+
# puts f
|
101
|
+
# # => (x^2) + (y^2)
|
102
|
+
# puts f.subs({x => CAS::ln(y)})
|
103
|
+
# # => (ln(y)^2) + (y^2)
|
104
|
+
# ```
|
105
|
+
#
|
106
|
+
# * **argument**: `Hash` with substitution table
|
107
|
+
# * **returns**: `CAS::Op` (`self`) with substitution performed
|
108
|
+
def subs(dt)
|
109
|
+
CAS::Help.assert(dt, Hash)
|
110
|
+
sub = dt.keys.select { |e| e == @x }[0]
|
111
|
+
if sub
|
112
|
+
if dt[sub].is_a? CAS::Op
|
113
|
+
@x = dt[sub]
|
114
|
+
elsif dt[sub].is_a? Numeric
|
115
|
+
@x = CAS::const dt[sub]
|
116
|
+
else
|
117
|
+
raise CAS::CASError, "Impossible subs. Received a #{dt[@x].class} = #{dt[@x]}"
|
118
|
+
end
|
119
|
+
else
|
120
|
+
@x.subs(dt)
|
121
|
+
end
|
122
|
+
return self
|
123
|
+
end
|
124
|
+
|
125
|
+
# Convert expression to string
|
126
|
+
#
|
127
|
+
# * **returns**: `String` to print on screen
|
128
|
+
def to_s
|
129
|
+
"#{@x}"
|
130
|
+
end
|
131
|
+
|
132
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
133
|
+
#
|
134
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
135
|
+
def to_code
|
136
|
+
"#{@x}"
|
137
|
+
end
|
138
|
+
|
139
|
+
# Returns a sum of two `CAS::Op`s
|
140
|
+
#
|
141
|
+
# * **argument**: `CAS::Op` tree
|
142
|
+
# * **returns**: `CAS::Op` new object
|
143
|
+
def +(op)
|
144
|
+
CAS::Sum.new [self, op]
|
145
|
+
end
|
146
|
+
|
147
|
+
# Returns a difference of two `CAS::Op`s
|
148
|
+
#
|
149
|
+
# * **argument**: `CAS::Op` tree
|
150
|
+
# * **returns**: `CAS::Op` new object
|
151
|
+
def -(op)
|
152
|
+
CAS::Diff.new self, op
|
153
|
+
end
|
154
|
+
|
155
|
+
# Returns a product of two `CAS::Op`s
|
156
|
+
#
|
157
|
+
# * **argument**: `CAS::Op` tree
|
158
|
+
# * **returns**: `CAS::Op` new object
|
159
|
+
def *(op)
|
160
|
+
CAS::Prod.new [self, op]
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns a division of two `CAS::Op`s
|
164
|
+
#
|
165
|
+
# * **argument**: `CAS::Op` tree
|
166
|
+
# * **returns**: `CAS::Op` new object
|
167
|
+
def /(op)
|
168
|
+
CAS::Div.new self, op
|
169
|
+
end
|
170
|
+
|
171
|
+
# Returns the power of two `CAS::Op`s
|
172
|
+
#
|
173
|
+
# * **argument**: `CAS::Op` tree
|
174
|
+
# * **returns**: `CAS::Op` new object
|
175
|
+
def **(op)
|
176
|
+
CAS.pow(self, op)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Unary operator for inversion of a `CAS::Op`
|
180
|
+
#
|
181
|
+
# * **returns**: `CAS::Op` new object
|
182
|
+
def -@
|
183
|
+
CAS.invert(self)
|
184
|
+
end
|
185
|
+
|
186
|
+
# Simplification callback. It simplify the subgraph of each node
|
187
|
+
# until all possible simplification are performed (thus the execution
|
188
|
+
# time is not deterministic).
|
189
|
+
#
|
190
|
+
# * **returns**: `CAS::Op` simplified version
|
191
|
+
def simplify
|
192
|
+
hash = @x.to_s
|
193
|
+
@x = @x.simplify
|
194
|
+
while @x.to_s != hash
|
195
|
+
hash = @x.to_s
|
196
|
+
@x = @x.simplify
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Simplify dictionary performs a dictionary simplification
|
201
|
+
# that is the class variable `@@simplify_dict`
|
202
|
+
#
|
203
|
+
# * **returns**: `CAS::Op` self
|
204
|
+
def simplify_dictionary
|
205
|
+
self.class.simplify_dict(@x) || self
|
206
|
+
end
|
207
|
+
|
208
|
+
# Initializes the simplification dictionary (one for each class)
|
209
|
+
#
|
210
|
+
# * **returns**: `Hash` with simplification dictionary
|
211
|
+
def self.init_simplify_dict
|
212
|
+
@simplify_dict = { }
|
213
|
+
end
|
214
|
+
|
215
|
+
# Returns an element of a
|
216
|
+
def self.simplify_dict(k)
|
217
|
+
@simplify_dict.keys.each do |op|
|
218
|
+
return @simplify_dict[op] if op.simplify == k.simplify
|
219
|
+
end
|
220
|
+
return nil
|
221
|
+
end
|
222
|
+
|
223
|
+
# Inspector for the current object
|
224
|
+
#
|
225
|
+
# * **returns**: `String`
|
226
|
+
def inspect
|
227
|
+
"#{self.class}(#{@x.inspect})"
|
228
|
+
end
|
229
|
+
|
230
|
+
# Equality operator, the standard operator is overloaded
|
231
|
+
# :warning: this operates on the graph, not on the math
|
232
|
+
# See `CAS::equal`, etc.
|
233
|
+
#
|
234
|
+
# * **argument**: `CAS::Op` to be tested against
|
235
|
+
# * **returns**: `TrueClass` if equal, `FalseClass` if differs
|
236
|
+
def ==(op)
|
237
|
+
# CAS::Help.assert(op, CAS::Op)
|
238
|
+
if op.is_a? CAS::Op
|
239
|
+
return false if op.is_a? CAS::BinaryOp
|
240
|
+
return (self.class == op.class and @x == op.x)
|
241
|
+
end
|
242
|
+
false
|
243
|
+
end
|
244
|
+
|
245
|
+
# Disequality operator, the standard operator is overloaded
|
246
|
+
# :warning: this operates on the graph, not on the math
|
247
|
+
# See `CAS::equal`, etc.
|
248
|
+
#
|
249
|
+
# * **argument**: `CAS::Op` to be tested against
|
250
|
+
# * **returns**: `FalseClass` if equal, `TrueClass` if differs
|
251
|
+
def !=(op)
|
252
|
+
not self.==(op)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Evaluates the proc against a given context. It is like having a
|
256
|
+
# snapshot of the tree transformed in a callable object.
|
257
|
+
# Obviously **if the tree changes, the generated proc does notchanges**.
|
258
|
+
# The proc takes as input a feed dictionary in which each variable
|
259
|
+
# is identified through the `CAS::Variable#name` key.
|
260
|
+
#
|
261
|
+
# The proc is evaluated in the context devined by the input `Binding` object
|
262
|
+
# If `nil` is passed, the `eval` will run in this local context
|
263
|
+
#
|
264
|
+
# * **argument**: `Binding` or `NilClass` that is the context of the Ruby VM
|
265
|
+
# * **returns**: `Proc` object with a single argument as an `Hash`
|
266
|
+
def as_proc(bind=nil)
|
267
|
+
args_ext = self.args.map { |e| "#{e} = fd[\"#{e}\"];" }
|
268
|
+
code = "Proc.new do |fd|; #{args_ext.join " "} #{self.to_code}; end"
|
269
|
+
if bind # All objects have eval value, we bind when not nil
|
270
|
+
# CAS::Help.assert(bind, Binding)
|
271
|
+
bind.eval(code)
|
272
|
+
else
|
273
|
+
eval(code)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# Returns a list of all `CAS::Variable`s of the current tree
|
278
|
+
#
|
279
|
+
# * **returns**: `Array` of `CAS::Variable`s
|
280
|
+
def args
|
281
|
+
@x.args.uniq
|
282
|
+
end
|
283
|
+
end # Op
|
284
|
+
CAS::Op.init_simplify_dict
|
285
|
+
end
|