Mr.CAS 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- 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,192 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module CAS
|
4
|
+
# ___ _
|
5
|
+
# | __|_ ___ __ ___ _ _ ___ _ _| |_
|
6
|
+
# | _|\ \ / '_ \/ _ \ ' \/ -_) ' \ _|
|
7
|
+
# |___/_\_\ .__/\___/_||_\___|_||_\__|
|
8
|
+
# |_|
|
9
|
+
|
10
|
+
##
|
11
|
+
# Representation for the `e^x` function. It is implemented
|
12
|
+
# as a `CAS::Op`
|
13
|
+
class Exp < CAS::Op
|
14
|
+
# Return the derivative of the `sin(x)` function using the chain
|
15
|
+
# rule. The input is a `CAS::Op` because it can handle derivatives
|
16
|
+
# with respect to functions.
|
17
|
+
#
|
18
|
+
# ```
|
19
|
+
# d
|
20
|
+
# -- exp(f(x)) = f'(x) exp(f(x))
|
21
|
+
# dx
|
22
|
+
# ```
|
23
|
+
#
|
24
|
+
# * **argument**: `CAS::Op` object of the derivative
|
25
|
+
# * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
|
26
|
+
def diff(v)
|
27
|
+
if @x.depend? v
|
28
|
+
return @x.diff(v) * CAS.exp(@x)
|
29
|
+
else
|
30
|
+
return CAS::Zero
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
35
|
+
# or `Float` (depends upon promotions).
|
36
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
37
|
+
# as keys, and a `Numeric` as a value
|
38
|
+
#
|
39
|
+
# * **argument**: `Hash` with feed dictionary
|
40
|
+
# * **returns**: `Numeric`
|
41
|
+
def call(f)
|
42
|
+
CAS::Help.assert(f, Hash)
|
43
|
+
Math::exp(@x.call(f))
|
44
|
+
end
|
45
|
+
|
46
|
+
# Convert expression to string
|
47
|
+
#
|
48
|
+
# * **returns**: `String` to print on screen
|
49
|
+
def to_s
|
50
|
+
"exp(#{@x})"
|
51
|
+
end
|
52
|
+
|
53
|
+
# Simplification callback. It simplify the subgraph of each node
|
54
|
+
# until all possible simplification are performed (thus the execution
|
55
|
+
# time is not deterministic).
|
56
|
+
#
|
57
|
+
# * **returns**: `CAS::Op` simplified version
|
58
|
+
def simplify
|
59
|
+
super
|
60
|
+
return @x.x if @x.is_a? CAS::Ln
|
61
|
+
return self.simplify_dictionary
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.init_simplify_dict
|
65
|
+
@simplify_dict = {
|
66
|
+
CAS::Zero => CAS::One,
|
67
|
+
CAS::One => CAS::E,
|
68
|
+
CAS::Infinity => CAS::Infinity
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
73
|
+
#
|
74
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
75
|
+
def to_code
|
76
|
+
"Math::exp(#{@x.to_code})"
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns the latex representation of the current Op.
|
80
|
+
#
|
81
|
+
# * **returns**: `String`
|
82
|
+
def to_latex
|
83
|
+
"e^{#{@x.to_latex}}"
|
84
|
+
end
|
85
|
+
end # Exp
|
86
|
+
CAS::Exp.init_simplify_dict
|
87
|
+
|
88
|
+
# Shortcut for `CAS::Exp#new`
|
89
|
+
#
|
90
|
+
# * **argument**: `CAS::Op` argument of the function
|
91
|
+
# * **returns**: `CAS::Exp` operation
|
92
|
+
def self.exp(x)
|
93
|
+
CAS::Exp.new x
|
94
|
+
end
|
95
|
+
|
96
|
+
# _ _ _ _
|
97
|
+
# | | ___ __ _ __ _ _ _(_) |_| |_ _ __
|
98
|
+
# | |__/ _ \/ _` / _` | '_| | _| ' \| ' \
|
99
|
+
# |____\___/\__, \__,_|_| |_|\__|_||_|_|_|_|
|
100
|
+
# |___/
|
101
|
+
|
102
|
+
##
|
103
|
+
# Representation for the `log(x)` function. It is implemented
|
104
|
+
# as a `CAS::Op`
|
105
|
+
class Ln < CAS::Op
|
106
|
+
# Return the derivative of the `log(x)` function using the chain
|
107
|
+
# rule. The input is a `CAS::Op` because it can handle derivatives
|
108
|
+
# with respect to functions.
|
109
|
+
#
|
110
|
+
# ```
|
111
|
+
# d f'(x)
|
112
|
+
# -- log(f(x)) = -------
|
113
|
+
# dx f(x)
|
114
|
+
# ```
|
115
|
+
#
|
116
|
+
# * **argument**: `CAS::Op` object of the derivative
|
117
|
+
# * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
|
118
|
+
def diff(v)
|
119
|
+
if @x.depend? v
|
120
|
+
return CAS::One / @x
|
121
|
+
else
|
122
|
+
return CAS::Zero
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
127
|
+
# or `Float` (depends upon promotions).
|
128
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
129
|
+
# as keys, and a `Numeric` as a value
|
130
|
+
#
|
131
|
+
# * **argument**: `Hash` with feed dictionary
|
132
|
+
# * **returns**: `Numeric`
|
133
|
+
def call(f)
|
134
|
+
# I'm leaving to Math the honor
|
135
|
+
# of handling negative values...
|
136
|
+
CAS::Help.assert(f, Hash)
|
137
|
+
Math::log(@x.call(f))
|
138
|
+
end
|
139
|
+
|
140
|
+
# Convert expression to string
|
141
|
+
#
|
142
|
+
# * **returns**: `String` to print on screen
|
143
|
+
def to_s
|
144
|
+
"log(#{@x})"
|
145
|
+
end
|
146
|
+
|
147
|
+
# Simplification callback. It simplify the subgraph of each node
|
148
|
+
# until all possible simplification are performed (thus the execution
|
149
|
+
# time is not deterministic).
|
150
|
+
#
|
151
|
+
# * **returns**: `CAS::Op` simplified version
|
152
|
+
def simplify
|
153
|
+
super
|
154
|
+
return @x.x if @x.is_a? CAS::Exp
|
155
|
+
return self.simplify_dictionary
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.init_simplify_dict
|
159
|
+
@simplify_dict = {
|
160
|
+
CAS::Zero => CAS.invert(CAS::Infinity),
|
161
|
+
CAS::One => CAS::Zero,
|
162
|
+
CAS::E => CAS::One
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
167
|
+
#
|
168
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
169
|
+
def to_code
|
170
|
+
"Math::log(#{@x.to_code})"
|
171
|
+
end
|
172
|
+
|
173
|
+
# Returns the latex representation of the current Op.
|
174
|
+
#
|
175
|
+
# * **returns**: `String`
|
176
|
+
def to_latex
|
177
|
+
"\\log\\left( #{@x.to_latex} \\right)"
|
178
|
+
end
|
179
|
+
end # Ln
|
180
|
+
CAS::Ln.init_simplify_dict
|
181
|
+
|
182
|
+
class << self
|
183
|
+
# Shortcut for `CAS::Ln#new`
|
184
|
+
#
|
185
|
+
# * **argument**: `CAS::Op` argument of the function
|
186
|
+
# * **returns**: `CAS::Ln` operation
|
187
|
+
def ln(x)
|
188
|
+
CAS::Ln.new x
|
189
|
+
end
|
190
|
+
alias :log :ln
|
191
|
+
end
|
192
|
+
end
|
@@ -0,0 +1,350 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module CAS
|
4
|
+
# ___ _ _
|
5
|
+
# / __|___ _ _ __| |_ __ _ _ _| |_
|
6
|
+
# | (__/ _ \ ' \(_-< _/ _` | ' \ _|
|
7
|
+
# \___\___/_||_/__/\__\__,_|_||_\__|
|
8
|
+
|
9
|
+
##
|
10
|
+
# Constant is a `CAS::Op` container for a `Numeric` value, that is
|
11
|
+
# not a `CAS::Variable`, thus its derivative it is always zero
|
12
|
+
class Constant < CAS::Op
|
13
|
+
def initialize(x)
|
14
|
+
@x = x
|
15
|
+
end
|
16
|
+
|
17
|
+
# Evaluates the derivative of a constant. The derivative is
|
18
|
+
# always a `CAS::Zero`
|
19
|
+
#
|
20
|
+
# ```
|
21
|
+
# d
|
22
|
+
# -- c = 0
|
23
|
+
# dx
|
24
|
+
# ```
|
25
|
+
def diff(_v)
|
26
|
+
CAS::Zero
|
27
|
+
end
|
28
|
+
|
29
|
+
# Calling a constant will return the value of the constant
|
30
|
+
# itself.
|
31
|
+
#
|
32
|
+
# * **argument**: Unused argument
|
33
|
+
# * **returns**: `Numeric` value of the constant
|
34
|
+
def call(_f)
|
35
|
+
@x
|
36
|
+
end
|
37
|
+
|
38
|
+
# There is no dependency in a constant, thus this method will
|
39
|
+
# always return false
|
40
|
+
#
|
41
|
+
# * **argument**: Unused argument
|
42
|
+
# * **returns**: `FalseClass`
|
43
|
+
def depend?(_v)
|
44
|
+
false
|
45
|
+
end
|
46
|
+
|
47
|
+
# The string representation of a constant is the value
|
48
|
+
# of the constant
|
49
|
+
#
|
50
|
+
# * **returns**: `String`
|
51
|
+
def to_s
|
52
|
+
"#{@x}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Subs for a constant is a dummy method that returns always `self`
|
56
|
+
#
|
57
|
+
# * **argument**: Unused argument
|
58
|
+
# * **returns**: `CAS::Constant` that represent `self`
|
59
|
+
def subs(_dt)
|
60
|
+
return self
|
61
|
+
end
|
62
|
+
|
63
|
+
# Simplification callback. It simplify the subgraph of each node
|
64
|
+
# until all possible simplification are performed (thus the execution
|
65
|
+
# time is not deterministic).
|
66
|
+
#
|
67
|
+
# * **returns**: `CAS::Op` simplified version
|
68
|
+
def simplify
|
69
|
+
return self
|
70
|
+
end
|
71
|
+
@@simplify_dict = { }
|
72
|
+
|
73
|
+
# Args of a constant is an empty `Array`
|
74
|
+
#
|
75
|
+
# * **returns**: `Array` empty
|
76
|
+
def args
|
77
|
+
[]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Check if a constant is equal to another `CAS::Op` object
|
81
|
+
#
|
82
|
+
# * **argument**: `CAs::Op`
|
83
|
+
# * **returns**: `TrueClass` or `FalseClass`
|
84
|
+
def ==(op)
|
85
|
+
if op.is_a? CAS::Constant
|
86
|
+
return @x == op.x
|
87
|
+
else
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Inspection for `CAS::Constant` class
|
93
|
+
#
|
94
|
+
# * **returns**: `String`
|
95
|
+
def inspect
|
96
|
+
"Const(#{self})"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Allows to define a series of new constants.
|
101
|
+
#
|
102
|
+
# ``` ruby
|
103
|
+
# a, b = CAS::const 1.0, 100
|
104
|
+
# ```
|
105
|
+
#
|
106
|
+
# * **argument**: `Array` of Numeric
|
107
|
+
# * **returns**: `Array` of `CAS::Contant`
|
108
|
+
def self.const(*val)
|
109
|
+
#(val = [val]) if val.size == 1
|
110
|
+
ret = []
|
111
|
+
val.each do |n|
|
112
|
+
ret << (NumericToConst[n] ? NumericToConst[n] : CAS::Constant.new(n))
|
113
|
+
end
|
114
|
+
return (ret.size == 1 ? ret[0] : ret)
|
115
|
+
end
|
116
|
+
|
117
|
+
# _______ ___ ___
|
118
|
+
# |_ / __| _ \/ _ \
|
119
|
+
# / /| _|| / (_) |
|
120
|
+
# /___|___|_|_\\___/
|
121
|
+
|
122
|
+
##
|
123
|
+
# Class that represents the constant Zero (0)
|
124
|
+
class ZERO_CONSTANT < CAS::Constant
|
125
|
+
# Initializer for the zero constant
|
126
|
+
#
|
127
|
+
# * **returns**: `CAS::ZERO_CONSTANT` new instance
|
128
|
+
def initialize
|
129
|
+
@x = 0.0
|
130
|
+
end
|
131
|
+
|
132
|
+
# String representation for the constant
|
133
|
+
#
|
134
|
+
# * **returns**: `String`
|
135
|
+
def to_s
|
136
|
+
"0"
|
137
|
+
end
|
138
|
+
end # Zero
|
139
|
+
|
140
|
+
# Zero (0) constant representation
|
141
|
+
Zero = CAS::ZERO_CONSTANT.new
|
142
|
+
|
143
|
+
# ___
|
144
|
+
# / _ \ _ _ ___
|
145
|
+
# | (_) | ' \/ -_)
|
146
|
+
# \___/|_||_\___|
|
147
|
+
|
148
|
+
##
|
149
|
+
# Class that represents the constant One (1)
|
150
|
+
class ONE_CONSTANT < CAS::Constant
|
151
|
+
# Initializer for the one constant
|
152
|
+
#
|
153
|
+
# * **returns**: `CAS::ONE_CONSTANT` new instance
|
154
|
+
def initialize
|
155
|
+
@x = 1.0
|
156
|
+
end
|
157
|
+
|
158
|
+
# String representation for the constant
|
159
|
+
#
|
160
|
+
# * **returns**: `String`
|
161
|
+
def to_s
|
162
|
+
"1"
|
163
|
+
end
|
164
|
+
end # Zero
|
165
|
+
|
166
|
+
# One (1) constant representation
|
167
|
+
One = CAS::ONE_CONSTANT.new
|
168
|
+
|
169
|
+
# _____
|
170
|
+
# |_ _|_ __ _____
|
171
|
+
# | | \ V V / _ \
|
172
|
+
# |_| \_/\_/\___/
|
173
|
+
|
174
|
+
##
|
175
|
+
# Class that represents the constant Two (2)
|
176
|
+
class TWO_CONSTANT < CAS::Constant
|
177
|
+
# Initializer for the two constant
|
178
|
+
#
|
179
|
+
# * **returns**: `CAS::TWO_CONSTANT` new instance
|
180
|
+
def initialize
|
181
|
+
@x = 2.0
|
182
|
+
end
|
183
|
+
|
184
|
+
# String representation for the constant
|
185
|
+
#
|
186
|
+
# * **returns**: `String`
|
187
|
+
def to_s
|
188
|
+
"2"
|
189
|
+
end
|
190
|
+
end # Zero
|
191
|
+
|
192
|
+
# Two (2) constant representation
|
193
|
+
Two = CAS::TWO_CONSTANT.new
|
194
|
+
|
195
|
+
# ___ ___
|
196
|
+
# | _ \_ _|
|
197
|
+
# | _/| |
|
198
|
+
# |_| |___|
|
199
|
+
|
200
|
+
##
|
201
|
+
# Class that represents the constant Pi (π)
|
202
|
+
class PI_CONSTANT < CAS::Constant
|
203
|
+
# Initializer for the pi constant
|
204
|
+
#
|
205
|
+
# * **returns**: `CAS::PI_CONSTANT` new instance
|
206
|
+
def initialize
|
207
|
+
@x = Math::PI
|
208
|
+
end
|
209
|
+
|
210
|
+
# String representation for the constant
|
211
|
+
#
|
212
|
+
# * **returns**: `String`
|
213
|
+
def to_s
|
214
|
+
"π"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Pi (3.14...) constant representation
|
219
|
+
Pi = CAS::PI_CONSTANT.new
|
220
|
+
|
221
|
+
# ___
|
222
|
+
# | __|
|
223
|
+
# | _|
|
224
|
+
# |___|
|
225
|
+
|
226
|
+
##
|
227
|
+
# Class that represents the constant E (e)
|
228
|
+
class E_CONSTANT < CAS::Constant
|
229
|
+
# Initializer for the E constant
|
230
|
+
#
|
231
|
+
# * **returns**: `CAS::E_CONSTANT` new instance
|
232
|
+
def initialize
|
233
|
+
@x = Math::E
|
234
|
+
end
|
235
|
+
|
236
|
+
# String representation for the constant
|
237
|
+
#
|
238
|
+
# * **returns**: `String`
|
239
|
+
def to_s
|
240
|
+
"e"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# E (2.57...) constant representation
|
245
|
+
E = CAS::E_CONSTANT.new
|
246
|
+
|
247
|
+
# ___ __ _ _ _
|
248
|
+
# |_ _|_ _ / _(_)_ _ (_) |_ _ _
|
249
|
+
# | || ' \| _| | ' \| | _| || |
|
250
|
+
# |___|_||_|_| |_|_||_|_|\__|\_, |
|
251
|
+
# |__/
|
252
|
+
|
253
|
+
##
|
254
|
+
# Class that represents the constant Infinity (∞)
|
255
|
+
class INFINITY_CONSTANT < CAS::Constant
|
256
|
+
# Initializer for the infinity constant
|
257
|
+
#
|
258
|
+
# * **returns**: `CAS::INFINITY_CONSTANT` new instance
|
259
|
+
def initialize
|
260
|
+
@x = (1.0/0.0)
|
261
|
+
end
|
262
|
+
|
263
|
+
# String representation for the constant
|
264
|
+
#
|
265
|
+
# * **returns**: `String`
|
266
|
+
def to_s
|
267
|
+
"∞"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# Infinity constant representation
|
272
|
+
Infinity = CAS::INFINITY_CONSTANT.new
|
273
|
+
|
274
|
+
# _ _ ___ __ _ _ _
|
275
|
+
# | \| |___ __ _|_ _|_ _ / _(_)_ _ (_) |_ _ _
|
276
|
+
# | .` / -_) _` || || ' \| _| | ' \| | _| || |
|
277
|
+
# |_|\_\___\__, |___|_||_|_| |_|_||_|_|\__|\_, |
|
278
|
+
# |___/ |__/
|
279
|
+
|
280
|
+
##
|
281
|
+
# Class that represents the constant Negative Infinity (-∞)
|
282
|
+
class NEG_INFINITY_CONSTANT < CAS::Constant
|
283
|
+
# Initializer for the negative infinity constant
|
284
|
+
#
|
285
|
+
# * **returns**: `CAS::NEG_INFINITY_CONSTANT` new instance
|
286
|
+
def initialize
|
287
|
+
@x = -(1.0/0.0)
|
288
|
+
end
|
289
|
+
|
290
|
+
# String representation for the constant
|
291
|
+
#
|
292
|
+
# * **returns**: `String`
|
293
|
+
def to_s
|
294
|
+
"-∞"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# Negative Infinity constant representation
|
299
|
+
NegInfinity = CAS::NEG_INFINITY_CONSTANT.new
|
300
|
+
|
301
|
+
# _
|
302
|
+
# ___/ |
|
303
|
+
# |___| |
|
304
|
+
# |_|
|
305
|
+
|
306
|
+
##
|
307
|
+
# Class that represents the constant Minus One (-1)
|
308
|
+
class MINUS_ONE_CONSTANT < CAS::Constant
|
309
|
+
# Initializer for the minus one constant
|
310
|
+
#
|
311
|
+
# * **returns**: `CAS::MINUS_ONE_CONSTANT` new instance
|
312
|
+
def initialize
|
313
|
+
@x = -1.0
|
314
|
+
end
|
315
|
+
|
316
|
+
# String representation for the constant
|
317
|
+
#
|
318
|
+
# * **returns**: `String`
|
319
|
+
def to_s
|
320
|
+
"-1"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Minus One (-1) constant representation
|
325
|
+
MinusOne = CAS::MINUS_ONE_CONSTANT.new
|
326
|
+
|
327
|
+
# Series of useful numeric constant, Based upon
|
328
|
+
# `Numeric` keys, with `CAs::Constant` value
|
329
|
+
NumericToConst = {
|
330
|
+
0 => CAS::Zero,
|
331
|
+
0.0 => CAS::Zero,
|
332
|
+
1 => CAS::One,
|
333
|
+
1.0 => CAS::One,
|
334
|
+
2 => CAS::Two,
|
335
|
+
2.0 => CAS::Two,
|
336
|
+
Math::PI => CAS::Pi,
|
337
|
+
Math::E => CAS::E,
|
338
|
+
(1.0/0.0) => CAS::Infinity,
|
339
|
+
}
|
340
|
+
|
341
|
+
class Constant
|
342
|
+
@@simplify_dict = {
|
343
|
+
0 => CAS::Zero,
|
344
|
+
1 => CAS::One,
|
345
|
+
Math::PI => CAS::Pi,
|
346
|
+
Math::E => CAS::E,
|
347
|
+
(1.0/0.0) => CAS::Infinity
|
348
|
+
}
|
349
|
+
end
|
350
|
+
end
|