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,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