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.
@@ -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