Class: CAS::Op
- Inherits:
-
Object
- Object
- CAS::Op
- Defined in:
- lib/operators/op.rb,
lib/Mr.CAS/c.rb,
lib/Mr.CAS/c-opt.rb,
lib/Mr.CAS/graphviz.rb,
lib/functions/fnc-conditions.rb,
lib/functions/fnc-box-conditions.rb
Overview
_ _ _
/ __|___ _ _| |_ __ _(_)_ _ ___ _ _ ___
| (__/ _ \ ‘ \ _/ _` | | ’ / -_) ‘_(_-<
\___\___/_||_\__\__,_|_|_||_\___|_| /__/
Direct Known Subclasses
Abs, Acos, Asin, Atan, BinaryOp, Constant, Cos, Exp, Invert, Ln, NaryOp, Sin, Sqrt, Tan, Variable
Instance Attribute Summary collapse
-
#x ⇒ Object
readonly
Argument of the operation.
Class Method Summary collapse
-
.init_simplify_dict ⇒ Object
Initializes the simplification dictionary (one for each class).
- .numeric_to_const(x) ⇒ Object
-
.simplify_dict(k) ⇒ Object
Returns an element of a.
Instance Method Summary collapse
-
#!=(op) ⇒ Object
Disequality operator, the standard operator is overloaded :warning: this operates on the graph, not on the math See ‘CAS::equal`, etc.
-
#*(op) ⇒ Object
Returns a product of two ‘CAS::Op`s.
-
#**(op) ⇒ Object
Returns the power of two ‘CAS::Op`s.
-
#+(op) ⇒ Object
Returns a sum of two ‘CAS::Op`s.
-
#-(op) ⇒ Object
Returns a difference of two ‘CAS::Op`s.
-
#-@ ⇒ Object
Unary operator for inversion of a ‘CAS::Op`.
-
#/(op) ⇒ Object
Returns a division of two ‘CAS::Op`s.
-
#==(op) ⇒ Object
Equality operator, the standard operator is overloaded :warning: this operates on the graph, not on the math See ‘CAS::equal`, etc.
-
#args ⇒ Object
Returns a list of all ‘CAS::Variable`s of the current tree.
-
#as_proc(bind = nil) ⇒ Object
Evaluates the proc against a given context.
-
#call(f) ⇒ Object
Call resolves the operation tree in a ‘Numeric` (if `Fixnum`) or `Float` (depends upon promotions).
-
#depend?(v) ⇒ Boolean
Return the dependencies of the operation.
-
#diff(v) ⇒ Object
Return the derivative of the operation using the chain rule The input is a ‘CAS::Op` because it can handle derivatives with respect to functions.
-
#dot_graph ⇒ Object
Return the local Graphviz node of the tree.
-
#equal(v) ⇒ Object
Shortcut for creating equality condition.
-
#greater(v) ⇒ Object
Shortcut for creating greater kind condition.
-
#greater_equal(v) ⇒ Object
Shortcut for creating a greater equal kind condition.
-
#initialize(x) ⇒ Op
constructor
Initialize a new empty operation container.
-
#inspect ⇒ Object
Inspector for the current object.
-
#limit(a, b, type = :closed) ⇒ Object
Shortcut for creating a new box condition.
-
#simplify ⇒ Object
Simplification callback.
-
#simplify_dictionary ⇒ Object
Simplify dictionary performs a dictionary simplification that is the class variable ‘@simplify_dict`.
-
#smaller(v) ⇒ Object
Shortcut for creating a smaller kind condition.
-
#smaller_equal(v) ⇒ Object
Shortcut for creating a smaller equal kind condition.
-
#subs(dt) ⇒ Object
Perform substitution of a part of the graph using a data table:.
- #to_c_lib(name) ⇒ Object
-
#to_code ⇒ Object
Convert expression to code (internal, for ‘CAS::Op#to_proc` method).
-
#to_s ⇒ Object
Convert expression to string.
Constructor Details
#initialize(x) ⇒ Op
Initialize a new empty operation container. This is a virtual class and the other must inherit from this basic container. Some methods raise a ‘CAS::CASError` if called. The input element is a Numric, to create a constant. `CAS::Op` specifies operations with a single variable
* **argument**: `Numeric` to be converted in `CAS::Constant` or `CAS::Op` child operation
* **returns**: `CAS::Op` instance
46 47 48 49 50 51 52 53 |
# File 'lib/operators/op.rb', line 46 def initialize(x) if x.is_a? Numeric x = Op.numeric_to_const x end CAS::Help.assert(x, CAS::Op) @x = x end |
Instance Attribute Details
#x ⇒ Object (readonly)
Argument of the operation
36 37 38 |
# File 'lib/operators/op.rb', line 36 def x @x end |
Class Method Details
.init_simplify_dict ⇒ Object
Initializes the simplification dictionary (one for each class)
-
returns: ‘Hash` with simplification dictionary
234 235 236 |
# File 'lib/operators/op.rb', line 234 def self.init_simplify_dict @simplify_dict = { } end |
.numeric_to_const(x) ⇒ Object
55 56 57 58 59 60 61 |
# File 'lib/operators/op.rb', line 55 def self.numeric_to_const(x) if CAS::NumericToConst[x] return CAS::NumericToConst[x] else return CAS::const x end end |
.simplify_dict(k) ⇒ Object
Returns an element of a
239 240 241 242 243 244 |
# File 'lib/operators/op.rb', line 239 def self.simplify_dict(k) @simplify_dict.keys.each do |op| return @simplify_dict[op] if op.simplify == k.simplify end return nil end |
Instance Method Details
#!=(op) ⇒ Object
Disequality operator, the standard operator is overloaded :warning: this operates on the graph, not on the math See ‘CAS::equal`, etc.
* **argument**: `CAS::Op` to be tested against
* **returns**: `FalseClass` if equal, `TrueClass` if differs
274 275 276 |
# File 'lib/operators/op.rb', line 274 def !=(op) not self.==(op) end |
#*(op) ⇒ Object
Returns a product of two ‘CAS::Op`s
* **argument**: `CAS::Op` tree
* **returns**: `CAS::Op` new object
182 183 184 |
# File 'lib/operators/op.rb', line 182 def *(op) CAS::Prod.new [self, op] end |
#**(op) ⇒ Object
Returns the power of two ‘CAS::Op`s
* **argument**: `CAS::Op` tree
* **returns**: `CAS::Op` new object
198 199 200 |
# File 'lib/operators/op.rb', line 198 def **(op) CAS.pow(self, op) end |
#+(op) ⇒ Object
Returns a sum of two ‘CAS::Op`s
* **argument**: `CAS::Op` tree
* **returns**: `CAS::Op` new object
166 167 168 |
# File 'lib/operators/op.rb', line 166 def +(op) CAS::Sum.new [self, op] end |
#-(op) ⇒ Object
Returns a difference of two ‘CAS::Op`s
* **argument**: `CAS::Op` tree
* **returns**: `CAS::Op` new object
174 175 176 |
# File 'lib/operators/op.rb', line 174 def -(op) CAS::Diff.new self, op end |
#-@ ⇒ Object
Unary operator for inversion of a ‘CAS::Op`
* **returns**: `CAS::Op` new object
205 206 207 |
# File 'lib/operators/op.rb', line 205 def -@ CAS.invert(self) end |
#/(op) ⇒ Object
Returns a division of two ‘CAS::Op`s
* **argument**: `CAS::Op` tree
* **returns**: `CAS::Op` new object
190 191 192 |
# File 'lib/operators/op.rb', line 190 def /(op) CAS::Div.new self, op end |
#==(op) ⇒ Object
Equality operator, the standard operator is overloaded :warning: this operates on the graph, not on the math See ‘CAS::equal`, etc.
* **argument**: `CAS::Op` to be tested against
* **returns**: `TrueClass` if equal, `FalseClass` if differs
259 260 261 262 263 264 265 266 |
# File 'lib/operators/op.rb', line 259 def ==(op) # CAS::Help.assert(op, CAS::Op) if op.is_a? CAS::Op return false if op.is_a? CAS::BinaryOp return (self.class == op.class and @x == op.x) end false end |
#args ⇒ Object
Returns a list of all ‘CAS::Variable`s of the current tree
* **returns**: `Array` of `CAS::Variable`s
303 304 305 |
# File 'lib/operators/op.rb', line 303 def args @x.args.uniq end |
#as_proc(bind = nil) ⇒ Object
Evaluates the proc against a given context. It is like having a snapshot of the tree transformed in a callable object. Obviously **if the tree changes, the generated proc does notchanges**. The proc takes as input a feed dictionary in which each variable is identified through the ‘CAS::Variable#name` key.
The proc is evaluated in the context devined by the input ‘Binding` object If `nil` is passed, the `eval` will run in this local context
* **argument**: `Binding` or `NilClass` that is the context of the Ruby VM
* **returns**: `Proc` object with a single argument as an `Hash`
289 290 291 292 293 294 295 296 297 298 |
# File 'lib/operators/op.rb', line 289 def as_proc(bind=nil) args_ext = self.args.map { |e| "#{e} = fd[\"#{e}\"];" } code = "Proc.new do |fd|; #{args_ext.join " "} #{self.to_code}; end" if bind # All objects have eval value, we bind when not nil # CAS::Help.assert(bind, Binding) bind.eval(code) else eval(code) end end |
#call(f) ⇒ Object
Call resolves the operation tree in a ‘Numeric` (if `Fixnum`) or `Float` (depends upon promotions). As input, it requires an hash with `CAS::Variable` or `CAS::Variable#name` as keys, and a `Numeric` as a value
“‘ ruby x, y = CAS::vars :x, :y f = (x ** 2) + (y ** 2) f.call(=> 1, y => 2) # => 2 “`
* **argument**: `Hash` with feed dictionary
* **returns**: `Numeric`
112 113 114 115 116 |
# File 'lib/operators/op.rb', line 112 def call(f) CAS::Help.assert(f, Hash) @x.call(f) end |
#depend?(v) ⇒ Boolean
Return the dependencies of the operation. Requires a ‘CAS::Variable` and it is one of the recursve method (implicit tree resolution)
* **argument**: `CAS::Variable` instance
* **returns**: `TrueClass` if depends, `FalseClass` if not
68 69 70 71 72 |
# File 'lib/operators/op.rb', line 68 def depend?(v) CAS::Help.assert(v, CAS::Op) @x.depend? v end |
#diff(v) ⇒ Object
Return the derivative of the operation using the chain rule The input is a ‘CAS::Op` because it can handle derivatives with respect to functions. E.g.:
“‘
f(x) = (ln(x))**2
g(x) = ln(x)
d f(x)
------ = 2 ln(x)
d g(x)
“‘
* **argument**: `CAS::Op` object of the derivative
* **returns**: `CAS::Op` a derivated object, or `CAS::Zero` for constants
89 90 91 92 93 94 95 96 |
# File 'lib/operators/op.rb', line 89 def diff(v) CAS::Help.assert(v, CAS::Op) if @x.depend? v return @x.diff(v) end CAS::Zero end |
#dot_graph ⇒ Object
Return the local Graphviz node of the tree
* **returns**: `String` of local Graphiz node
42 43 44 45 |
# File 'lib/Mr.CAS/graphviz.rb', line 42 def dot_graph cls = "#{self.class.to_s.gsub("CAS::", "")}_#{self.object_id}" "#{cls} -> #{@x.dot_graph}\n" end |
#equal(v) ⇒ Object
Shortcut for creating equality condition.
* **argument**: `CAS::Op` ther element of the condition
* **returns**: `CAS::Equal` new instance
344 345 346 |
# File 'lib/functions/fnc-conditions.rb', line 344 def equal(v) CAS.equal(self, v) end |
#greater(v) ⇒ Object
Shortcut for creating greater kind condition.
* **argument**: `CAS::Op` ther element of the condition
* **returns**: `CAS::Greater` new instance
352 353 354 |
# File 'lib/functions/fnc-conditions.rb', line 352 def greater(v) CAS.greater(self, v) end |
#greater_equal(v) ⇒ Object
Shortcut for creating a greater equal kind condition.
* **argument**: `CAS::Op` ther element of the condition
* **returns**: `CAS::GreaterEqual` new instance
368 369 370 |
# File 'lib/functions/fnc-conditions.rb', line 368 def greater_equal(v) CAS.greater_equal(self, v) end |
#inspect ⇒ Object
Inspector for the current object
* **returns**: `String`
249 250 251 |
# File 'lib/operators/op.rb', line 249 def inspect "#{self.class}(#{@x.inspect})" end |
#limit(a, b, type = :closed) ⇒ Object
Shortcut for creating a new box condition. It requires limits and type:
* **argument**: `CAS::Constant` lower limit
* **argument**: `CAs::Constant` upper limit
* **argument**: `Symbol` of condition type it can be:
- `:closed` for `CAs::BoxConditionClosed`
- `:open` for `CAs::BoxConditionOpen`
- `:upper_closed` for `CAs::BoxConditionUpperClosed`
- `:lower_closed` for `CAs::BoxConditionLowerClosed`
* **returns**: `CAS::BoxCondition` new instance
338 339 340 |
# File 'lib/functions/fnc-box-conditions.rb', line 338 def limit(a, b, type=:closed) return CAS::box(self, a, b, type) end |
#simplify ⇒ Object
Simplification callback. It simplify the subgraph of each node until all possible simplification are performed (thus the execution time is not deterministic).
* **returns**: `CAS::Op` simplified version
214 215 216 217 218 219 220 221 |
# File 'lib/operators/op.rb', line 214 def simplify hash = @x.to_s @x = @x.simplify while @x.to_s != hash hash = @x.to_s @x = @x.simplify end end |
#simplify_dictionary ⇒ Object
Simplify dictionary performs a dictionary simplification that is the class variable ‘@simplify_dict`
* **returns**: `CAS::Op` self
227 228 229 |
# File 'lib/operators/op.rb', line 227 def simplify_dictionary self.class.simplify_dict(@x) || self end |
#smaller(v) ⇒ Object
Shortcut for creating a smaller kind condition.
* **argument**: `CAS::Op` ther element of the condition
* **returns**: `CAS::Smaller` new instance
360 361 362 |
# File 'lib/functions/fnc-conditions.rb', line 360 def smaller(v) CAS.smaller(self, v) end |
#smaller_equal(v) ⇒ Object
Shortcut for creating a smaller equal kind condition.
* **argument**: `CAS::Op` ther element of the condition
* **returns**: `CAS::SmallerEqual` new instance
376 377 378 |
# File 'lib/functions/fnc-conditions.rb', line 376 def smaller_equal(v) CAS.smaller_equal(self, v) end |
#subs(dt) ⇒ Object
Perform substitution of a part of the graph using a data table:
“‘ ruby x, y = CAS::vars :x, :y f = (x ** 2) + (y ** 2) puts f # => (x^2) + (y^2) puts f.subs(=> CAS::ln(y)) # => (ln(y)^2) + (y^2) “`
* **argument**: `Hash` with substitution table
* **returns**: `CAS::Op` (`self`) with substitution performed
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/operators/op.rb', line 131 def subs(dt) CAS::Help.assert(dt, Hash) sub = dt.keys.select { |e| e == @x }[0] if sub if dt[sub].is_a? CAS::Op @x = dt[sub] elsif dt[sub].is_a? Numeric @x = CAS::const dt[sub] else raise CAS::CASError, "Impossible subs. Received a #{dt[@x].class} = #{dt[@x]}" end else @x.subs(dt) end return self end |
#to_c_lib(name) ⇒ Object
143 144 145 146 |
# File 'lib/Mr.CAS/c.rb', line 143 def to_c_lib(name) CAS::Help.assert(name, String) [CAS::C_PLUGIN.write_header(self, name), CAS::C_PLUGIN.write_source(self, name)] end |
#to_code ⇒ Object
Convert expression to code (internal, for ‘CAS::Op#to_proc` method)
* **returns**: `String` that represent Ruby code to be parsed in `CAS::Op#to_proc`
158 159 160 |
# File 'lib/operators/op.rb', line 158 def to_code "#{@x}" end |
#to_s ⇒ Object
Convert expression to string
* **returns**: `String` to print on screen
151 152 153 |
# File 'lib/operators/op.rb', line 151 def to_s "#{@x}" end |