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,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,102 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module CAS
4
+
5
+ # ___ _
6
+ # | _ \_ _ ___ __| |
7
+ # | _/ '_/ _ \/ _` |
8
+ # |_| |_| \___/\__,_|
9
+
10
+ ##
11
+ # Product class. Performs the product between two elements.
12
+ # This class will be soon modified as an n-ary operator.
13
+ class Prod < CAS::NaryOp
14
+ # The new element of a sum accumulates inside the
15
+ # vector that holds the elements
16
+ def *(op)
17
+ CAS::Help.assert(op, CAS::Op)
18
+ @x << op
19
+ self
20
+ end
21
+
22
+ # Performs the product between two `CAS::Op`
23
+ #
24
+ # ```
25
+ # d
26
+ # ---- (f(x) * g(x) * h(x)) = f'(x) * g(x) * h(x) +
27
+ # dx
28
+ # + f(x) * g'(x) * h(x) +
29
+ #
30
+ # + f(x) * g(x) * h'(x)
31
+ # ```
32
+ #
33
+ # * **argument**: `CAS::Op` argument of derivative
34
+ # * **returns**: `CAS::Op` derivative
35
+ def diff(v)
36
+ xdiff = @x.map { |y| y.diff(v) }
37
+
38
+ xdiff.each_with_index { |y, i|
39
+ xdiff[i] = y * CAS::Prod.new(@x[0...i] + @x[(i + 1)..-1])
40
+ }
41
+
42
+ return CAS::Sum.new(xdiff)
43
+ end
44
+
45
+ # Call resolves the operation tree in a `Numeric` (if `Fixnum`)
46
+ # or `Float` (depends upon promotions).
47
+ # As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
48
+ # as keys, and a `Numeric` as a value. In this case it will call
49
+ # the `Fixnum#overloaded_plus`, that is the old plus function.
50
+ #
51
+ # * **argument**: `Hash` with feed dictionary
52
+ # * **returns**: `Numeric`
53
+ def call(f)
54
+ CAS::Help.assert(f, Hash)
55
+
56
+ return @x.inject { |p, y| p = p.overloaded_mul(y.call(f)) }
57
+ end
58
+
59
+ # Convert expression to string
60
+ #
61
+ # * **returns**: `String` to print on screen
62
+ def to_s
63
+ "(#{@x.map(&:to_s).join(" * ")})"
64
+ end
65
+
66
+ # Same as `CAS::Op`
67
+ #
68
+ # Simplifcation engine supports:
69
+ #
70
+ # * x * 0 = x * y = 0
71
+ # * 1 * y = y
72
+ # * x * 1 = x
73
+ # * x * x = x²
74
+ # * a * b = c (constants reduction)
75
+ #
76
+ # * **returns**: `CAS::Op` simplified version
77
+ def simplify
78
+ super
79
+ return CAS::Zero if @x.include? CAS::Zero
80
+ @x = @x - [CAS::One]
81
+ return CAS::One if @x.size == 0
82
+ return @x[0] if @x.size == 1
83
+
84
+ @x = self.__reduce_constants(@x) do |cs, xs|
85
+ [cs.inject { |t, c| t *= c.call({}) }] + xs
86
+ end
87
+
88
+ @x = self.__reduce_multeplicity(@x) do |op, count|
89
+ count > 1 ? (op ** count) : op
90
+ end
91
+ return self
92
+ end
93
+
94
+ # Convert expression to code (internal, for `CAS::Op#to_proc` method)
95
+ #
96
+ # * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
97
+ def to_code
98
+ "(#{@x.map(&:to_code).join(" * ")})"
99
+ end
100
+ end # Prod
101
+ CAS::Prod.init_simplify_dict
102
+ end
@@ -0,0 +1,151 @@
1
+ module CAS
2
+ # ___
3
+ # / __|_ _ _ __
4
+ # \__ \ || | ' \
5
+ # |___/\_,_|_|_|_|
6
+
7
+ ##
8
+ # **Sum basic operation**. As for now it is implemented as a simple
9
+ # binary operation. It will be implemented as n-ary op.
10
+ class Sum < CAS::NaryOp
11
+ # Performs the sum between arbitrary number of `CAS::Op`
12
+ #
13
+ # ```
14
+ # d
15
+ # ---- (f(x) + g(x) + h(x)) = f'(x) + g'(x) + h'(x)
16
+ # dx
17
+ # ```
18
+ #
19
+ # * **argument**: `CAS::Op` argument of derivative
20
+ # * **returns**: `CAS::Op` derivative
21
+ def diff(v)
22
+ @x.map { |x| x.diff(v) }.inject { |sum_x, dx| sum_x += dx }
23
+ end
24
+
25
+ # The added element of a sum accumulates inside the
26
+ # vector that holds the elements
27
+ def +(op)
28
+ CAS::Help.assert(op, CAS::Op)
29
+ @x << op
30
+ self
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. In this case it will call
37
+ # the `Fixnum#overloaded_plus`, that is the old plus function.
38
+ #
39
+ # * **argument**: `Hash` with feed dictionary
40
+ # * **returns**: `Numeric`
41
+ def call(f)
42
+ CAS::Help.assert(f, Hash)
43
+ return @x.inject { |val, x_i| val += x_i.call(f) }
44
+ end
45
+
46
+ # Convert expression to string
47
+ #
48
+ # * **returns**: `String` to print on screen
49
+ def to_s
50
+ "(#{@x.map(&:to_s).join(" + ")})"
51
+ end
52
+
53
+ # Same as `CAS::Op`
54
+ #
55
+ # Simplifcation engine supports:
56
+ #
57
+ # * x + 0 = x
58
+ # * 0 + y = y
59
+ # * x + x = 2 x
60
+ # * x + (-x) = 0
61
+ # * x + (-y) = x - y
62
+ # * 1 + 2 = 3 (constants reduction)
63
+ #
64
+ # * **returns**: `CAS::Op` simplified version
65
+ def simplify
66
+ super
67
+ return @x[0] if @x.size == 1
68
+
69
+ # return CAS::Zero if @x == -@y or -@x == @y
70
+ # return (@x - @y.x) if @y.is_a? CAS::Invert
71
+ # return CAS.const(self.call({})) if (@x.is_a? CAS::Constant and @y.is_a? CAS::Constant)
72
+ # Removing Zeros
73
+ @x = @x - [CAS::Zero]
74
+ return CAS::Zero if @x.size == 0
75
+ # Reduce constants
76
+ @x = self.__reduce_constants(@x) do |cs, xs|
77
+ xs + [cs.inject { |t, c| t += c.call({}) }]
78
+ end
79
+ # Multeplicity and associativity executed
80
+ return self.reduce_associativity
81
+ end
82
+
83
+ # Reduces from an associative point of view, by a segregation
84
+ # of "negative" and positive elements. Negatives comes from
85
+ # Diff operations and Invert operations. All the others are considered
86
+ # positive. This function implements an internal heuristic. Should
87
+ # not be used outside
88
+ #
89
+ # * **returns**: A `CAS::Diff` or a `CAS::Sum`
90
+ def reduce_associativity
91
+ pos, neg = [], []
92
+
93
+ @x.each do |x_el|
94
+ case x_el
95
+ when CAS::Invert
96
+ neg << x_el.x
97
+ when CAS::Diff
98
+ pos << x_el.x
99
+ neg << x_el.y
100
+ else
101
+ pos << x_el
102
+ end
103
+ end
104
+
105
+ pos, neg = self.reduce_associativity_array pos, neg
106
+ pos = self.__reduce_multeplicity(pos)
107
+ neg = self.__reduce_multeplicity neg
108
+
109
+ # TODO : Add rules for simplifications
110
+ left, right = nil, nil
111
+ left = CAS::Sum.new(pos) if pos.size > 1
112
+ left = pos[0] if pos.size == 1
113
+ right = CAS::Sum.new(neg) if neg.size > 1
114
+ right = neg[0] if neg.size == 1
115
+
116
+ return CAS::Zero unless left || right
117
+ return left unless right
118
+ return -right unless left
119
+ return left - right
120
+ end
121
+
122
+ # Reduce the positive and the negative associative part of
123
+ # the sum to perform the symbolic difference. Does not take into account
124
+ # multeplicity
125
+ #
126
+ # * **requires**: positive `Array`
127
+ # * **requires**: negative `Array`
128
+ # * **returns**: positive, reduced `Array` and negative `Array`
129
+ def reduce_associativity_array(p_old, n_old)
130
+ p_del, n_del = [], []
131
+ p_old.each do |p|
132
+ n_old.each do |n|
133
+ if p == n
134
+ p_del << p
135
+ n_del << n
136
+ end
137
+ end
138
+ end
139
+
140
+ return (p_old - p_del), (n_old - n_del)
141
+ end
142
+
143
+ # Convert expression to code (internal, for `CAS::Op#to_proc` method)
144
+ #
145
+ # * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
146
+ def to_code
147
+ "(#{@x.map(&:to_code).join(" + ")})"
148
+ end
149
+ end # Sum
150
+ CAS::Sum.init_simplify_dict
151
+ end
@@ -0,0 +1,489 @@
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
+ CAS::Pi/2 => CAS::One
68
+ }
69
+ end
70
+
71
+ # Convert expression to code (internal, for `CAS::Op#to_proc` method)
72
+ #
73
+ # * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
74
+ def to_code
75
+ "Math::sin(#{@x.to_code})"
76
+ end
77
+ end # Sin
78
+ CAS::Sin.init_simplify_dict
79
+
80
+ # Shortcut for `CAS::Sin#new`
81
+ #
82
+ # * **argument**: `CAS::Op` argument of the function
83
+ # * **returns**: `CAS::Sin` operation
84
+ def self.sin(x)
85
+ CAS::Sin.new x
86
+ end
87
+
88
+ # _ _
89
+ # /_\ __(_)_ _
90
+ # / _ \ (_-< | ' \
91
+ # /_/ \_\/__/_|_||_|
92
+
93
+ ##
94
+ # Representation for the `arcsin(x)` function. It is implemented
95
+ # as a `CAS::Op`. It is the inverse of the `sin(x)` function
96
+ class Asin < CAS::Op
97
+ # Return the derivative of the `arcsin(x)` function using the chain
98
+ # rule. The input is a `CAS::Op`
99
+ #
100
+ # * **argument**: `CAS::Op` object of the derivative
101
+ # * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
102
+ def diff(v)
103
+ if @x.depend? v
104
+ return @x.diff(v) / CAS.sqrt(CAS::One - CAS.pow(@x, CAS::Two))
105
+ else
106
+ return CAS::Zero
107
+ end
108
+ end
109
+
110
+ # Call resolves the operation tree in a `Numeric` (if `Fixnum`)
111
+ # or `Float` (depends upon promotions).
112
+ # As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
113
+ # as keys, and a `Numeric` as a value
114
+ #
115
+ # * **argument**: `Hash` with feed dictionary
116
+ # * **returns**: `Numeric`
117
+ def call(f)
118
+ CAS::Help.assert(f, Hash)
119
+ Math::acos(@x.call(f))
120
+ end
121
+
122
+ # Convert expression to string
123
+ #
124
+ # * **returns**: `String` to print on screen
125
+ def to_s
126
+ "asin(#{@x})"
127
+ end
128
+
129
+ # Simplification callback. It simplify the subgraph of each node
130
+ # until all possible simplification are performed (thus the execution
131
+ # time is not deterministic).
132
+ #
133
+ # * **returns**: `CAS::Op` simplified version
134
+ def simplify
135
+ super
136
+ return @x.x if @x.is_a? CAS::Sin
137
+ return self.simplify_dictionary
138
+ end
139
+
140
+ def self.init_simplify_dict
141
+ @simplify_dict = {
142
+ CAS::Zero => CAS::Zero,
143
+ CAS::One => (CAS::Pi / 2)
144
+ }
145
+ end
146
+
147
+ # Convert expression to code (internal, for `CAS::Op#to_proc` method)
148
+ #
149
+ # * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
150
+ def to_code
151
+ "Math::asin(#{@x.to_code})"
152
+ end
153
+ end
154
+ CAS::Asin.init_simplify_dict
155
+
156
+ class << self
157
+ # Shortcuts for `CAS::Asin#new`
158
+ #
159
+ # * **argument**: `CAS::Op` argument of the function
160
+ # * **returns**: `CAS::Asin` operation
161
+ def asin(x)
162
+ CAS::Asin.new x
163
+ end
164
+ alias :arcsin :asin
165
+ end
166
+
167
+ # ___
168
+ # / __|___ ___
169
+ # | (__/ _ (_-<
170
+ # \___\___/__/
171
+
172
+ ##
173
+ # Representation for the `cos(x)` function. It is implemented
174
+ # as a `CAS::Op`.
175
+ class Cos < CAS::Op
176
+ # Return the derivative of the `cos(x)` function using the chain
177
+ # rule. The input is a `CAS::Op` because it can handle derivatives
178
+ # with respect to functions.
179
+ #
180
+ # ```
181
+ # d
182
+ # -- cos(f(x)) = -f'(x) sin(fx)
183
+ # dx
184
+ # ```
185
+ #
186
+ # * **argument**: `CAS::Op` object of the derivative
187
+ # * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
188
+ def diff(v)
189
+ if @x.depend? v
190
+ return CAS.invert(@x.diff(v) * CAS.sin(@x))
191
+ else
192
+ return CAS::Zero
193
+ end
194
+ end
195
+
196
+ # Call resolves the operation tree in a `Numeric` (if `Fixnum`)
197
+ # or `Float` (depends upon promotions).
198
+ # As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
199
+ # as keys, and a `Numeric` as a value
200
+ #
201
+ # * **argument**: `Hash` with feed dictionary
202
+ # * **returns**: `Numeric`
203
+ def call(f)
204
+ CAS::Help.assert(f, Hash)
205
+ Math::cos(@x.call(f))
206
+ end
207
+
208
+ # Convert expression to string
209
+ #
210
+ # * **returns**: `String` to print on screen
211
+ def to_s
212
+ "cos(#{@x})"
213
+ end
214
+
215
+ # Simplification callback. It simplify the subgraph of each node
216
+ # until all possible simplification are performed (thus the execution
217
+ # time is not deterministic).
218
+ #
219
+ # * **returns**: `CAS::Op` simplified version
220
+ def simplify
221
+ super
222
+ return @x.x if @x.is_a? CAS::Acos
223
+ return self.simplify_dictionary
224
+ end
225
+
226
+ def self.init_simplify_dict
227
+ @simplify_dict = {
228
+ CAS::Zero => CAS::One,
229
+ CAS::Pi => CAS::One,
230
+ CAS::Pi/2 => CAS::Zero
231
+ }
232
+ end
233
+
234
+ # Convert expression to code (internal, for `CAS::Op#to_proc` method)
235
+ #
236
+ # * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
237
+ def to_code
238
+ "Math::cos(#{@x.to_code})"
239
+ end
240
+ end
241
+ CAS::Cos.init_simplify_dict
242
+
243
+ # Shortcut for `CAS::Cos#new`
244
+ #
245
+ # * **argument**: `CAS::Op` argument of the function
246
+ # * **returns**: `CAS::Cos` operation
247
+ def self.cos(x)
248
+ CAS::Cos.new x
249
+ end
250
+
251
+ # _
252
+ # /_\ __ ___ ___
253
+ # / _ \/ _/ _ (_-<
254
+ # /_/ \_\__\___/__/
255
+
256
+ ##
257
+ # Representation for the `arccos(x)` function. It is implemented
258
+ # as a `CAS::Op`. It is the inverse of the `cos(x)` function
259
+ class Acos < CAS::Op
260
+ def diff(v)
261
+ if @x.depend? v
262
+ return CAS.invert(@x.diff(v)/CAS.sqrt(CAS::One - CAS.pow(@x, CAS::Two)))
263
+ else
264
+ return CAS::Zero
265
+ end
266
+ end
267
+
268
+ # Call resolves the operation tree in a `Numeric` (if `Fixnum`)
269
+ # or `Float` (depends upon promotions).
270
+ # As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
271
+ # as keys, and a `Numeric` as a value
272
+ #
273
+ # * **argument**: `Hash` with feed dictionary
274
+ # * **returns**: `Numeric`
275
+ def call(f)
276
+ CAS::Help.assert(f, Hash)
277
+ return Math::acos(@x.call(f))
278
+ end
279
+
280
+ # Convert expression to string
281
+ #
282
+ # * **returns**: `String` to print on screen
283
+ def to_s
284
+ "acos(#{@x})"
285
+ end
286
+
287
+ # Simplification callback. It simplify the subgraph of each node
288
+ # until all possible simplification are performed (thus the execution
289
+ # time is not deterministic).
290
+ #
291
+ # * **returns**: `CAS::Op` simplified version
292
+ def simplify
293
+ super
294
+ return @x.x if @x.is_a? CAS::Cos
295
+ return self.simplify_dictionary
296
+ end
297
+
298
+ def self.init_simplify_dict
299
+ @simplify_dict = {
300
+ CAS::Zero => (CAS::Pi / 2),
301
+ CAS::One => CAS::Zero
302
+ }
303
+ end
304
+
305
+ # Convert expression to code (internal, for `CAS::Op#to_proc` method)
306
+ #
307
+ # * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
308
+ def to_code
309
+ "Math::acos(#{@x.to_code})"
310
+ end
311
+ end
312
+ CAS::Acos.init_simplify_dict
313
+
314
+ class << self
315
+ # Shortcut for `CAS::Acos#new`
316
+ #
317
+ # * **argument**: `CAS::Op` argument of the function
318
+ # * **returns**: `CAS::Acos` operation
319
+ def acos(x)
320
+ CAS::Acos.new x
321
+ end
322
+ alias :arccos :acos
323
+ end
324
+
325
+ # _____
326
+ # |_ _|_ _ _ _
327
+ # | |/ _` | ' \
328
+ # |_|\__,_|_||_|
329
+
330
+ ##
331
+ # Representation for the `tan(x)` function. It is implemented
332
+ # as a `CAS::Op`.
333
+ class Tan < CAS::Op
334
+ # Return the derivative of the `tan(x)` function using the chain
335
+ # rule. The input is a `CAS::Op` because it can handle derivatives
336
+ # with respect to functions. E.g.:
337
+ #
338
+ # ```
339
+ # d f'(x)
340
+ # -- sin(f(x)) = -------
341
+ # dx cos²(x)
342
+ # ```
343
+ #
344
+ # * **argument**: `CAS::Op` object of the derivative
345
+ # * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
346
+ def diff(v)
347
+ if @x.depend? v
348
+ return @x.diff(v) * CAS.pow(CAS::One/CAS.cos(@x), CAS::Two)
349
+ else
350
+ return CAS::Zero
351
+ end
352
+ end
353
+
354
+ # Call resolves the operation tree in a `Numeric` (if `Fixnum`)
355
+ # or `Float` (depends upon promotions).
356
+ # As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
357
+ # as keys, and a `Numeric` as a value
358
+ #
359
+ # * **argument**: `Hash` with feed dictionary
360
+ # * **returns**: `Numeric`
361
+ def call(f)
362
+ CAS::Help.assert(f, Hash)
363
+ Math::tan(@x.call(f))
364
+ end
365
+
366
+ # Convert expression to string
367
+ #
368
+ # * **returns**: `String` to print on screen
369
+ def to_s
370
+ "tan(#{@x})"
371
+ end
372
+
373
+ # Simplification callback. It simplify the subgraph of each node
374
+ # until all possible simplification are performed (thus the execution
375
+ # time is not deterministic).
376
+ #
377
+ # * **returns**: `CAS::Op` simplified version
378
+ def simplify
379
+ super
380
+ return @x.x if @x.is_a? CAS::Atan
381
+ return self.simplify_dictionary
382
+ end
383
+
384
+ def self.init_simplify_dict
385
+ @simplify_dict = {
386
+ CAS::Zero => CAS::Zero,
387
+ CAS::Pi => CAS::Zero,
388
+ CAS::Pi/2 => CAS::Infinity
389
+ }
390
+ end
391
+
392
+ # Convert expression to code (internal, for `CAS::Op#to_proc` method)
393
+ #
394
+ # * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
395
+ def to_code
396
+ "Math::tan(#{@x.to_code})"
397
+ end
398
+ end
399
+ CAS::Tan.init_simplify_dict
400
+
401
+ # Shortcut for `CAS::Tan#new`
402
+ #
403
+ # * **argument**: `CAS::Op` argument of the function
404
+ # * **returns**: `CAS::Tan` operation
405
+ def self.tan(x)
406
+ CAS::Tan.new x
407
+ end
408
+
409
+ # _ _
410
+ # /_\| |_ __ _ _ _
411
+ # / _ \ _/ _` | ' \
412
+ # /_/ \_\__\__,_|_||_|
413
+
414
+ ##
415
+ # Representation for the `arctan(x)` function. It is implemented
416
+ # as a `CAS::Op`. It is the inverse of the `tan(x)` function
417
+ class Atan < CAS::Op
418
+ # Return the derivative of the `arctan(x)` function using the chain
419
+ # rule. The input is a `CAS::Op` because it can handle derivatives
420
+ # with respect to functions.
421
+ #
422
+ # * **argument**: `CAS::Op` object of the derivative
423
+ # * **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
424
+ def diff(v)
425
+ if @x.depend? v
426
+ return (@x.diff(v) / (CAS.pow(@x, CAS::Two) + CAS::One))
427
+ else
428
+ return CAS::Zero
429
+ end
430
+ end
431
+
432
+ # Call resolves the operation tree in a `Numeric` (if `Fixnum`)
433
+ # or `Float` (depends upon promotions).
434
+ # As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name`
435
+ # as keys, and a `Numeric` as a value
436
+ #
437
+ # * **argument**: `Hash` with feed dictionary
438
+ # * **returns**: `Numeric`
439
+ def call(f)
440
+ CAS::Help.assert(f, Hash)
441
+ Math::atan(@x.call(f))
442
+ end
443
+
444
+ # Convert expression to string
445
+ #
446
+ # * **returns**: `String` to print on screen
447
+ def to_s
448
+ "atan(#{@x})"
449
+ end
450
+
451
+ # Simplification callback. It simplify the subgraph of each node
452
+ # until all possible simplification are performed (thus the execution
453
+ # time is not deterministic).
454
+ #
455
+ # * **returns**: `CAS::Op` simplified version
456
+ def simplify
457
+ super
458
+ return @x.x if @x.is_a? CAS::Tan
459
+ return self.simplify_dictionary
460
+ end
461
+
462
+ def self.init_simplify_dict
463
+ @simplify_dict = {
464
+ CAS::Zero => CAS::Zero,
465
+ CAS::One => (CAS::Pi/4),
466
+ CAS::Infinity => (CAS::Pi/2)
467
+ }
468
+ end
469
+
470
+ # Convert expression to code (internal, for `CAS::Op#to_proc` method)
471
+ #
472
+ # * **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
473
+ def to_code
474
+ "Math::atan(#{@x.to_code})"
475
+ end
476
+ end
477
+ CAS::Atan.init_simplify_dict
478
+
479
+ class << self
480
+ # Shortcut for `CAS::Atan#new`
481
+ #
482
+ # * **argument**: `CAS::Op` argument of the function
483
+ # * **returns**: `CAS::Atan` operation
484
+ def atan(x)
485
+ CAS::Atan.new x
486
+ end
487
+ alias :arctan :atan
488
+ end
489
+ end