Mr.CAS 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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