ragni-cas 0.2.2 → 0.2.3
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/lib/functions/fnc-base.rb +660 -0
- data/lib/functions/fnc-box-conditions.rb +316 -0
- data/lib/functions/fnc-conditions.rb +365 -0
- data/lib/functions/fnc-piecewise.rb +186 -0
- data/lib/functions/fnc-trig.rb +487 -0
- data/lib/functions/fnc-trsc.rb +196 -0
- data/lib/numbers/constants.rb +358 -0
- data/lib/numbers/variables.rb +211 -0
- data/lib/operators/bary-op.rb +185 -0
- data/lib/operators/nary-op.rb +175 -0
- data/lib/operators/op.rb +285 -0
- data/lib/overloading/fixnum.rb +61 -0
- data/lib/overloading/float.rb +61 -0
- data/lib/ragni-cas.rb +23 -187
- data/lib/version.rb +7 -1
- data.tar.gz.sig +0 -0
- metadata +15 -8
- metadata.gz.sig +0 -0
- data/lib/fnc-base.rb +0 -560
- data/lib/fnc-branch.rb +0 -388
- data/lib/fnc-trig.rb +0 -336
- data/lib/fnc-trsc.rb +0 -126
- data/lib/numbers.rb +0 -390
- data/lib/op.rb +0 -454
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module CAS
|
4
|
+
# ___ _ _
|
5
|
+
# | _ (_)___ __ _____ __ _(_)___ ___
|
6
|
+
# | _/ / -_) _/ -_) V V / (_-</ -_)
|
7
|
+
# |_| |_\___\__\___|\_/\_/|_/__/\___|
|
8
|
+
|
9
|
+
##
|
10
|
+
# Piecewise function. The function returns when called a result
|
11
|
+
# that dependes upon the evaluation of a condition. In practice:
|
12
|
+
#
|
13
|
+
# ```
|
14
|
+
# /
|
15
|
+
# | f(x) if condition(x) is True
|
16
|
+
# <
|
17
|
+
# | g(x) otherwise
|
18
|
+
# \
|
19
|
+
# ```
|
20
|
+
#
|
21
|
+
# From this class other classes will inherit like `CAS::Max` and `CAS::Min` classes
|
22
|
+
class Piecewise < CAS::BinaryOp
|
23
|
+
attr_reader :condition
|
24
|
+
|
25
|
+
# Initialize a new piecewise function. It requires first the function
|
26
|
+
# that returns when condition is true, than the function when condition is
|
27
|
+
# false, and finally the condition that must be of class `CAS::Condition`
|
28
|
+
#
|
29
|
+
# * **argument**: `CAS::Op` first function
|
30
|
+
# * **argument**: `CAS::Op` second function
|
31
|
+
# * **argument**: `CAS::Condition` evaluated condition
|
32
|
+
# * **returns**: `CAS::Piecewise` new instance
|
33
|
+
def initialize(x, y, condition)
|
34
|
+
CAS::Help.assert(condition, CAS::Condition)
|
35
|
+
|
36
|
+
super(x, y)
|
37
|
+
@condition = condition
|
38
|
+
end
|
39
|
+
|
40
|
+
# Derivative of a function is performed as derivative of the two internal functions
|
41
|
+
# while condition is unchanged
|
42
|
+
#
|
43
|
+
# warning:: Piecewise functions are in general not differentiable. Thus differentiability
|
44
|
+
# is left to the user
|
45
|
+
#
|
46
|
+
# ```
|
47
|
+
# / /
|
48
|
+
# d | f(x) if condition(x) is True | f'(x) if condition(x) is True
|
49
|
+
# -- < = <
|
50
|
+
# dx | g(x) otherwise | g'(x) otherwise
|
51
|
+
# \ \
|
52
|
+
# ```
|
53
|
+
#
|
54
|
+
# * **argument**: `CAS::Op` argument of derivative
|
55
|
+
# * **returns**: `CAS::Piecewise` with derivated functions and unchanged condition
|
56
|
+
def diff(v)
|
57
|
+
CAS::Help.assert(v, CAS::Op)
|
58
|
+
return CAS::Piecewise.new(@x.diff(v).simplify, @y.diff(v).simplify, @condition)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Executes the condition. If it is `true` it returns the first function,
|
62
|
+
# else it returns the value of the second function.
|
63
|
+
#
|
64
|
+
# * **argument**: `Hash` with value tables
|
65
|
+
# * **returns**: `Numeric` the result of the call
|
66
|
+
def call(fd)
|
67
|
+
CAS::Help.assert(fd, Hash)
|
68
|
+
(@condition.call(fd) ? @x.call(fd) : @y.call(fd))
|
69
|
+
end
|
70
|
+
|
71
|
+
# Checks if two `CAS::Piecewise` are equal. Checks equality on all functions+
|
72
|
+
# and conditions
|
73
|
+
#
|
74
|
+
# * **argument**: `CAS::Op` to be checked against
|
75
|
+
# * **returns**: `TrueClass` or `FalseClass`
|
76
|
+
def ==(op)
|
77
|
+
CAS::Help.assert(op, CAS::Op)
|
78
|
+
if self.class != op.class
|
79
|
+
return false
|
80
|
+
else
|
81
|
+
return ((@x == op.x) and (@y == op.y) and (@condition == op.condition))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Convert the piecewise funtion to a String of Ruby code
|
86
|
+
#
|
87
|
+
# * **returns**: `String` of code
|
88
|
+
def to_code
|
89
|
+
"(#{@condition.to_code} ? (#{@x.to_code}) : (#{@y.to_code}))"
|
90
|
+
end
|
91
|
+
|
92
|
+
# Convert the piecewise function into a String
|
93
|
+
#
|
94
|
+
# * **returns**: `String`
|
95
|
+
def to_s
|
96
|
+
"(#{@condition} ? #{@x} : #{@y})"
|
97
|
+
end
|
98
|
+
|
99
|
+
# Convert piecewise function into LaTeX representation
|
100
|
+
#
|
101
|
+
# * **returns**: `String` of LaTeX code
|
102
|
+
def to_latex
|
103
|
+
"\\left\\{ \\begin{array}{lr} #{@x.to_latex} & #{@condition.to_latex} \\\\ #{@y.to_latex} \\end{array} \\right."
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# __ __ _ __ __
|
108
|
+
# | \/ (_)_ _ | \/ |__ ___ __
|
109
|
+
# | |\/| | | ' \| |\/| / _` \ \ /
|
110
|
+
# |_| |_|_|_||_|_| |_\__,_/_\_\
|
111
|
+
|
112
|
+
##
|
113
|
+
# Class MinMax is an intermediate class for Min and Max functions. It contains shared code
|
114
|
+
# and methods
|
115
|
+
class MinMax < CAS::Piecewise
|
116
|
+
# Convert MinMax function into LaTeX representation
|
117
|
+
#
|
118
|
+
# * **returns**: `String` of LaTeX code
|
119
|
+
def to_latex
|
120
|
+
"\\mathrm{#{@type}}\\left( \\begin{array}{c} #{@x.to_latex} \\\\ #{@y.to_latex} \\end{array} \\right)"
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns a string representation for the current operation
|
124
|
+
#
|
125
|
+
# * **returns**: `String`
|
126
|
+
def to_s
|
127
|
+
"#{@type}(#{@x}, #{@y})"
|
128
|
+
end
|
129
|
+
end # MinMax
|
130
|
+
|
131
|
+
# __ __
|
132
|
+
# | \/ |__ ___ __
|
133
|
+
# | |\/| / _` \ \ /
|
134
|
+
# |_| |_\__,_/_\_\
|
135
|
+
|
136
|
+
# Max class represent a piecewise in which the condition is `f(x) ≥ g(x)`. Derivate a `CAS::Max`
|
137
|
+
# will return a `CAS::Piecewise` (since condition will not depend anymore on object functions)
|
138
|
+
class Max < CAS::Piecewise
|
139
|
+
# To initialize `CAS::Max` only the two functions are necessary. The condition is automatically
|
140
|
+
# generated
|
141
|
+
#
|
142
|
+
# * **argument**: `CAS::Op` first function
|
143
|
+
# * **argument**: `CAS::Op` second function
|
144
|
+
def initialize(x, y)
|
145
|
+
super(x, y, CAS::greater_equal(x, y))
|
146
|
+
@type = "max"
|
147
|
+
end
|
148
|
+
end # Max
|
149
|
+
|
150
|
+
# __ __ _
|
151
|
+
# | \/ (_)_ _
|
152
|
+
# | |\/| | | ' \
|
153
|
+
# |_| |_|_|_||_|
|
154
|
+
|
155
|
+
# Min class represent a piecewise in which the condition is `f(x) ≤ g(x)`. Derivate a `CAS::Min`
|
156
|
+
# will return a `CAS::Piecewise` (since condition will not depend anymore on object functions)
|
157
|
+
class Min < CAS::Piecewise
|
158
|
+
# To initialize `CAS::Min` only the two functions are necessary. The condition is automatically
|
159
|
+
# generated
|
160
|
+
#
|
161
|
+
# * **argument**: `CAS::Op` first function
|
162
|
+
# * **argument**: `CAS::Op` second function
|
163
|
+
def initialize(x, y)
|
164
|
+
super(x, y, CAS::smaller_equal(x, y))
|
165
|
+
@type = "min"
|
166
|
+
end
|
167
|
+
end # Min
|
168
|
+
|
169
|
+
# Shortcut for `CAS::Max` initializer
|
170
|
+
#
|
171
|
+
# * **argument**: `CAS::Op` left function
|
172
|
+
# * **argument**: `CAS::Op` right function
|
173
|
+
# * **returns**: `CAS::Max` new instance
|
174
|
+
def self.max(x, y)
|
175
|
+
CAS::Max.new(x, y)
|
176
|
+
end
|
177
|
+
|
178
|
+
# Shortcut for `CAS::Min` initializer
|
179
|
+
#
|
180
|
+
# * **argument**: `CAS::Op` left function
|
181
|
+
# * **argument**: `CAS::Op` right function
|
182
|
+
# * **returns**: `CAS::Min` new instance
|
183
|
+
def self.min(x, y)
|
184
|
+
CAS::Min.new(x, y, CAS::smaller_equal(x, y))
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,487 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module CAS
|
4
|
+
# ___ _
|
5
|
+
# / __(_)_ _
|
6
|
+
# \__ \ | ' \
|
7
|
+
# |___/_|_||_|
|
8
|
+
|
9
|
+
##
|
10
|
+
# Representation for the `sin(x)` function. It is implemented
|
11
|
+
# as a `CAS::Op`
|
12
|
+
class Sin < CAS::Op
|
13
|
+
# Return the derivative of the `sin(x)` function using the chain
|
14
|
+
# rule. The input is a `CAS::Op` because it can handle derivatives
|
15
|
+
# with respect to functions.
|
16
|
+
#
|
17
|
+
# ```
|
18
|
+
# d
|
19
|
+
# -- sin(f(x)) = f'(x) cos(fx)
|
20
|
+
# dx
|
21
|
+
# ```
|
22
|
+
#
|
23
|
+
# * **argument**: `CAS::Op` object of the derivative
|
24
|
+
# * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
|
25
|
+
def diff(v)
|
26
|
+
if @x.depend? v
|
27
|
+
return @x.diff(v) * CAS.cos(@x)
|
28
|
+
else
|
29
|
+
return CAS::Zero
|
30
|
+
end
|
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
|
37
|
+
#
|
38
|
+
# * **argument**: `Hash` with feed dictionary
|
39
|
+
# * **returns**: `Numeric`
|
40
|
+
def call(f)
|
41
|
+
CAS::Help.assert(f, Hash)
|
42
|
+
Math::sin(@x.call(f))
|
43
|
+
end
|
44
|
+
|
45
|
+
# Convert expression to string
|
46
|
+
#
|
47
|
+
# * **returns**: `String` to print on screen
|
48
|
+
def to_s
|
49
|
+
"sin(#{@x})"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Simplification callback. It simplify the subgraph of each node
|
53
|
+
# until all possible simplification are performed (thus the execution
|
54
|
+
# time is not deterministic).
|
55
|
+
#
|
56
|
+
# * **returns**: `CAS::Op` simplified version
|
57
|
+
def simplify
|
58
|
+
super
|
59
|
+
return @x.x if @x.is_a? CAS::Asin
|
60
|
+
return self.simplify_dictionary
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.init_simplify_dict
|
64
|
+
@simplify_dict = {
|
65
|
+
CAS::Zero => CAS::Zero,
|
66
|
+
CAS::Pi => CAS::Zero
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
71
|
+
#
|
72
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
73
|
+
def to_code
|
74
|
+
"Math::sin(#{@x.to_code})"
|
75
|
+
end
|
76
|
+
end # Sin
|
77
|
+
CAS::Sin.init_simplify_dict
|
78
|
+
|
79
|
+
# Shortcut for `CAS::Sin#new`
|
80
|
+
#
|
81
|
+
# * **argument**: `CAS::Op` argument of the function
|
82
|
+
# * **returns**: `CAS::Sin` operation
|
83
|
+
def self.sin(x)
|
84
|
+
CAS::Sin.new x
|
85
|
+
end
|
86
|
+
|
87
|
+
# _ _
|
88
|
+
# /_\ __(_)_ _
|
89
|
+
# / _ \ (_-< | ' \
|
90
|
+
# /_/ \_\/__/_|_||_|
|
91
|
+
|
92
|
+
##
|
93
|
+
# Representation for the `arcsin(x)` function. It is implemented
|
94
|
+
# as a `CAS::Op`. It is the inverse of the `sin(x)` function
|
95
|
+
class Asin < CAS::Op
|
96
|
+
# Return the derivative of the `arcsin(x)` function using the chain
|
97
|
+
# rule. The input is a `CAS::Op`
|
98
|
+
#
|
99
|
+
# * **argument**: `CAS::Op` object of the derivative
|
100
|
+
# * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
|
101
|
+
def diff(v)
|
102
|
+
if @x.depend? v
|
103
|
+
return @x.diff(v) / CAS.sqrt(CAS::One - CAS.pow(@x, CAS::Two))
|
104
|
+
else
|
105
|
+
return CAS::Zero
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
110
|
+
# or `Float` (depends upon promotions).
|
111
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
112
|
+
# as keys, and a `Numeric` as a value
|
113
|
+
#
|
114
|
+
# * **argument**: `Hash` with feed dictionary
|
115
|
+
# * **returns**: `Numeric`
|
116
|
+
def call(f)
|
117
|
+
CAS::Help.assert(f, Hash)
|
118
|
+
Math::acos(@x.call(f))
|
119
|
+
end
|
120
|
+
|
121
|
+
# Convert expression to string
|
122
|
+
#
|
123
|
+
# * **returns**: `String` to print on screen
|
124
|
+
def to_s
|
125
|
+
"asin(#{@x})"
|
126
|
+
end
|
127
|
+
|
128
|
+
# Simplification callback. It simplify the subgraph of each node
|
129
|
+
# until all possible simplification are performed (thus the execution
|
130
|
+
# time is not deterministic).
|
131
|
+
#
|
132
|
+
# * **returns**: `CAS::Op` simplified version
|
133
|
+
def simplify
|
134
|
+
super
|
135
|
+
return @x.x if @x.is_a? CAS::Sin
|
136
|
+
return self.simplify_dictionary
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.init_simplify_dict
|
140
|
+
@simplify_dict = {
|
141
|
+
CAS::Zero => CAS::Zero,
|
142
|
+
CAS::One => (CAS::Pi / 2)
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
147
|
+
#
|
148
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
149
|
+
def to_code
|
150
|
+
"Math::asin(#{@x.to_code})"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
CAS::Asin.init_simplify_dict
|
154
|
+
|
155
|
+
# Shortcut for `CAS::Asin#new`
|
156
|
+
#
|
157
|
+
# * **argument**: `CAS::Op` argument of the function
|
158
|
+
# * **returns**: `CAS::Asin` operation
|
159
|
+
def self.asin(x)
|
160
|
+
CAS::Asin.new x
|
161
|
+
end
|
162
|
+
# alias :arcsin :asin
|
163
|
+
|
164
|
+
# ___
|
165
|
+
# / __|___ ___
|
166
|
+
# | (__/ _ (_-<
|
167
|
+
# \___\___/__/
|
168
|
+
|
169
|
+
##
|
170
|
+
# Representation for the `cos(x)` function. It is implemented
|
171
|
+
# as a `CAS::Op`.
|
172
|
+
class Cos < CAS::Op
|
173
|
+
# Return the derivative of the `cos(x)` function using the chain
|
174
|
+
# rule. The input is a `CAS::Op` because it can handle derivatives
|
175
|
+
# with respect to functions.
|
176
|
+
#
|
177
|
+
# ```
|
178
|
+
# d
|
179
|
+
# -- cos(f(x)) = -f'(x) sin(fx)
|
180
|
+
# dx
|
181
|
+
# ```
|
182
|
+
#
|
183
|
+
# * **argument**: `CAS::Op` object of the derivative
|
184
|
+
# * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
|
185
|
+
def diff(v)
|
186
|
+
if @x.depend? v
|
187
|
+
return CAS.invert(@x.diff(v) * CAS.sin(@x))
|
188
|
+
else
|
189
|
+
return CAS::Zero
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
194
|
+
# or `Float` (depends upon promotions).
|
195
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
196
|
+
# as keys, and a `Numeric` as a value
|
197
|
+
#
|
198
|
+
# * **argument**: `Hash` with feed dictionary
|
199
|
+
# * **returns**: `Numeric`
|
200
|
+
def call(f)
|
201
|
+
CAS::Help.assert(f, Hash)
|
202
|
+
Math::cos(@x.call(f))
|
203
|
+
end
|
204
|
+
|
205
|
+
# Convert expression to string
|
206
|
+
#
|
207
|
+
# * **returns**: `String` to print on screen
|
208
|
+
def to_s
|
209
|
+
"cos(#{@x})"
|
210
|
+
end
|
211
|
+
|
212
|
+
# Simplification callback. It simplify the subgraph of each node
|
213
|
+
# until all possible simplification are performed (thus the execution
|
214
|
+
# time is not deterministic).
|
215
|
+
#
|
216
|
+
# * **returns**: `CAS::Op` simplified version
|
217
|
+
def simplify
|
218
|
+
super
|
219
|
+
return @x.x if @x.is_a? CAS::Acos
|
220
|
+
return self.simplify_dictionary
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.init_simplify_dict
|
224
|
+
@simplify_dict = {
|
225
|
+
CAS::Zero => CAS::One,
|
226
|
+
CAS::Pi => CAS::One
|
227
|
+
}
|
228
|
+
end
|
229
|
+
|
230
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
231
|
+
#
|
232
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
233
|
+
def to_code
|
234
|
+
"Math::cos(#{@x.to_code})"
|
235
|
+
end
|
236
|
+
end
|
237
|
+
CAS::Cos.init_simplify_dict
|
238
|
+
|
239
|
+
# Shortcut for `CAS::Cos#new`
|
240
|
+
#
|
241
|
+
# * **argument**: `CAS::Op` argument of the function
|
242
|
+
# * **returns**: `CAS::Cos` operation
|
243
|
+
def self.cos(x)
|
244
|
+
CAS::Cos.new x
|
245
|
+
end
|
246
|
+
|
247
|
+
# _
|
248
|
+
# /_\ __ ___ ___
|
249
|
+
# / _ \/ _/ _ (_-<
|
250
|
+
# /_/ \_\__\___/__/
|
251
|
+
|
252
|
+
##
|
253
|
+
# Representation for the `arccos(x)` function. It is implemented
|
254
|
+
# as a `CAS::Op`. It is the inverse of the `cos(x)` function
|
255
|
+
class Acos < CAS::Op
|
256
|
+
def diff(v)
|
257
|
+
if @x.depend? v
|
258
|
+
return CAS.invert(@x.diff(v)/CAS.sqrt(CAS::One - CAS.pow(@x, CAS::Two)))
|
259
|
+
else
|
260
|
+
return CAS::Zero
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
265
|
+
# or `Float` (depends upon promotions).
|
266
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
267
|
+
# as keys, and a `Numeric` as a value
|
268
|
+
#
|
269
|
+
# * **argument**: `Hash` with feed dictionary
|
270
|
+
# * **returns**: `Numeric`
|
271
|
+
def call(f)
|
272
|
+
CAS::Help.assert(f, Hash)
|
273
|
+
return Math::acos(@x.call(f))
|
274
|
+
end
|
275
|
+
|
276
|
+
# Convert expression to string
|
277
|
+
#
|
278
|
+
# * **returns**: `String` to print on screen
|
279
|
+
def to_s
|
280
|
+
"acos(#{@x})"
|
281
|
+
end
|
282
|
+
|
283
|
+
# Simplification callback. It simplify the subgraph of each node
|
284
|
+
# until all possible simplification are performed (thus the execution
|
285
|
+
# time is not deterministic).
|
286
|
+
#
|
287
|
+
# * **returns**: `CAS::Op` simplified version
|
288
|
+
def simplify
|
289
|
+
super
|
290
|
+
return @x.x if @x.is_a? CAS::Cos
|
291
|
+
return self.simplify_dictionary
|
292
|
+
end
|
293
|
+
|
294
|
+
def self.init_simplify_dict
|
295
|
+
@simplify_dict = {
|
296
|
+
CAS::Zero => (CAS::Pi / 2),
|
297
|
+
CAS::One => CAS::Zero
|
298
|
+
}
|
299
|
+
end
|
300
|
+
|
301
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
302
|
+
#
|
303
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
304
|
+
def to_code
|
305
|
+
"Math::acos(#{@x.to_code})"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
CAS::Acos.init_simplify_dict
|
309
|
+
|
310
|
+
# Shortcut for `CAS::Acos#new`
|
311
|
+
#
|
312
|
+
# * **argument**: `CAS::Op` argument of the function
|
313
|
+
# * **returns**: `CAS::Acos` operation
|
314
|
+
def self.acos(x)
|
315
|
+
CAS::Acos.new x
|
316
|
+
end
|
317
|
+
# alias :arccos :acos
|
318
|
+
|
319
|
+
# _____
|
320
|
+
# |_ _|_ _ _ _
|
321
|
+
# | |/ _` | ' \
|
322
|
+
# |_|\__,_|_||_|
|
323
|
+
|
324
|
+
##
|
325
|
+
# Representation for the `tan(x)` function. It is implemented
|
326
|
+
# as a `CAS::Op`.
|
327
|
+
class Tan < CAS::Op
|
328
|
+
# Return the derivative of the `tan(x)` function using the chain
|
329
|
+
# rule. The input is a `CAS::Op` because it can handle derivatives
|
330
|
+
# with respect to functions. E.g.:
|
331
|
+
#
|
332
|
+
# ```
|
333
|
+
# d f'(x)
|
334
|
+
# -- sin(f(x)) = -------
|
335
|
+
# dx cos²(x)
|
336
|
+
# ```
|
337
|
+
#
|
338
|
+
# * **argument**: `CAS::Op` object of the derivative
|
339
|
+
# * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
|
340
|
+
def diff(v)
|
341
|
+
if @x.depend? v
|
342
|
+
return @x.diff(v) * CAS.pow(CAS::One/CAS.cos(@x), CAS::Two)
|
343
|
+
else
|
344
|
+
return CAS::Zero
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
349
|
+
# or `Float` (depends upon promotions).
|
350
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
351
|
+
# as keys, and a `Numeric` as a value
|
352
|
+
#
|
353
|
+
# * **argument**: `Hash` with feed dictionary
|
354
|
+
# * **returns**: `Numeric`
|
355
|
+
def call(f)
|
356
|
+
CAS::Help.assert(f, Hash)
|
357
|
+
Math::tan(@x.call(f))
|
358
|
+
end
|
359
|
+
|
360
|
+
# Convert expression to string
|
361
|
+
#
|
362
|
+
# * **returns**: `String` to print on screen
|
363
|
+
def to_s
|
364
|
+
"tan(#{@x})"
|
365
|
+
end
|
366
|
+
|
367
|
+
# Simplification callback. It simplify the subgraph of each node
|
368
|
+
# until all possible simplification are performed (thus the execution
|
369
|
+
# time is not deterministic).
|
370
|
+
#
|
371
|
+
# * **returns**: `CAS::Op` simplified version
|
372
|
+
def simplify
|
373
|
+
super
|
374
|
+
return @x.x if @x.is_a? CAS::Atan
|
375
|
+
return self.simplify_dictionary
|
376
|
+
end
|
377
|
+
|
378
|
+
def self.init_simplify_dict
|
379
|
+
@simplify_dict = {
|
380
|
+
CAS::Zero => CAS::Zero,
|
381
|
+
CAS::Pi => CAS::Zero
|
382
|
+
}
|
383
|
+
end
|
384
|
+
|
385
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
386
|
+
#
|
387
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
388
|
+
def to_code
|
389
|
+
"Math::tan(#{@x.to_code})"
|
390
|
+
end
|
391
|
+
end
|
392
|
+
CAS::Tan.init_simplify_dict
|
393
|
+
|
394
|
+
# Shortcut for `CAS::Tan#new`
|
395
|
+
#
|
396
|
+
# * **argument**: `CAS::Op` argument of the function
|
397
|
+
# * **returns**: `CAS::Tan` operation
|
398
|
+
def self.tan(x)
|
399
|
+
CAS::Tan.new x
|
400
|
+
end
|
401
|
+
|
402
|
+
# _ _
|
403
|
+
# /_\| |_ __ _ _ _
|
404
|
+
# / _ \ _/ _` | ' \
|
405
|
+
# /_/ \_\__\__,_|_||_|
|
406
|
+
|
407
|
+
##
|
408
|
+
# Representation for the `arctan(x)` function. It is implemented
|
409
|
+
# as a `CAS::Op`. It is the inverse of the `tan(x)` function
|
410
|
+
class Atan < CAS::Op
|
411
|
+
# Return the derivative of the `arctan(x)` function using the chain
|
412
|
+
# rule. The input is a `CAS::Op` because it can handle derivatives
|
413
|
+
# with respect to functions.
|
414
|
+
#
|
415
|
+
# * **argument**: `CAS::Op` object of the derivative
|
416
|
+
# * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
|
417
|
+
def diff(v)
|
418
|
+
if @x.depend? v
|
419
|
+
return (@x.diff(v) / (CAS.pow(@x, CAS::Two) + CAS::One))
|
420
|
+
else
|
421
|
+
return CAS::Zero
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
# Call resolves the operation tree in a `Numeric` (if `Fixnum`)
|
426
|
+
# or `Float` (depends upon promotions).
|
427
|
+
# As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
|
428
|
+
# as keys, and a `Numeric` as a value
|
429
|
+
#
|
430
|
+
# * **argument**: `Hash` with feed dictionary
|
431
|
+
# * **returns**: `Numeric`
|
432
|
+
def call(f)
|
433
|
+
CAS::Help.assert(f, Hash)
|
434
|
+
Math::atan(@x.call(f))
|
435
|
+
end
|
436
|
+
|
437
|
+
# Convert expression to string
|
438
|
+
#
|
439
|
+
# * **returns**: `String` to print on screen
|
440
|
+
def to_s
|
441
|
+
"atan(#{@x})"
|
442
|
+
end
|
443
|
+
|
444
|
+
# Simplification callback. It simplify the subgraph of each node
|
445
|
+
# until all possible simplification are performed (thus the execution
|
446
|
+
# time is not deterministic).
|
447
|
+
#
|
448
|
+
# * **returns**: `CAS::Op` simplified version
|
449
|
+
def simplify
|
450
|
+
super
|
451
|
+
return @x.x if @x.is_a? CAS::Tan
|
452
|
+
return self.simplify_dictionary
|
453
|
+
end
|
454
|
+
|
455
|
+
def self.init_simplify_dict
|
456
|
+
@simplify_dict = {
|
457
|
+
CAS::Zero => CAS::Zero,
|
458
|
+
CAS::One => (CAS::Pi/4),
|
459
|
+
CAS::Infinity => (CAS::Pi/2)
|
460
|
+
}
|
461
|
+
end
|
462
|
+
|
463
|
+
# Convert expression to code (internal, for `CAS::Op#to_proc` method)
|
464
|
+
#
|
465
|
+
# * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
|
466
|
+
def to_code
|
467
|
+
"Math::atan(#{@x.to_code})"
|
468
|
+
end
|
469
|
+
|
470
|
+
# Returns the latex representation of the current Op.
|
471
|
+
#
|
472
|
+
# * **returns**: `String`
|
473
|
+
def to_latex
|
474
|
+
"\\arctan\\left( #{@x.to_latex} \\right)"
|
475
|
+
end
|
476
|
+
end
|
477
|
+
CAS::Atan.init_simplify_dict
|
478
|
+
|
479
|
+
# Shortcut for `CAS::Atan#new`
|
480
|
+
#
|
481
|
+
# * **argument**: `CAS::Op` argument of the function
|
482
|
+
# * **returns**: `CAS::Atan` operation
|
483
|
+
def self.atan(x)
|
484
|
+
CAS::Atan.new x
|
485
|
+
end
|
486
|
+
# alias :arctan :atan
|
487
|
+
end
|