Class: CAS::NaryOp
- Defined in:
- lib/operators/nary-op.rb,
lib/Mr.CAS/graphviz.rb
Overview
This is an attempt to build some sort of node in the graph that has arbitrary number of childs node. It should help implement more easily some sort of better simplifications engine
This is an incredibly experimental feature.
Instance Attribute Summary collapse
-
#x ⇒ Object
readonly
List of arguments of the operation.
Instance Method Summary collapse
-
#==(op) ⇒ Object
Equality operator, the standard operator is overloaded :warning: this operates on the graph, not on the math See ‘CAS::equal`, etc.
-
#__reduce_constants(xs) ⇒ Object
Collects all the constants and tries to reduce them to a single constant.
-
#__reduce_multeplicity(xs) ⇒ Object
Reduce multeplicity will scan for elements that are equal in the definition of the sum and will reduce their multeplicity.
-
#args ⇒ Object
Returns a list of all ‘CAS::Variable`s of the current tree.
-
#call(fd) ⇒ Object
Call resolves the operation tree in a ‘Numeric` (if `Fixnum`) or `Float` depends upon promotions).
-
#depend?(v) ⇒ Boolean
Returns the dependencies of the operation.
-
#diff(v) ⇒ Object
Return a list of derivative using the chain rule.
-
#dot_graph ⇒ Object
Return the local Graphviz node of the tree.
-
#initialize(*xs) ⇒ NaryOp
constructor
Initialize a new empty N-elements operation container.
-
#inspect ⇒ Object
Inspector for the current object.
-
#simplify ⇒ Object
Simplification callback.
-
#subs(dt) ⇒ Object
Perform substitution of a part of the graph using a data table:.
-
#to_code ⇒ Object
Convert expression to code (internal, for ‘CAS::Op#to_proc` method).
-
#to_s ⇒ Object
Convert expression to string.
Methods inherited from Op
#!=, #*, #**, #+, #-, #-@, #/, #as_proc, #equal, #greater, #greater_equal, init_simplify_dict, #limit, numeric_to_const, simplify_dict, #simplify_dictionary, #smaller, #smaller_equal, #to_c_lib
Constructor Details
#initialize(*xs) ⇒ NaryOp
Initialize a new empty N-elements operation container. This is a virtual class, and other must inherit from this basical container
* **argument**: `Numeric` to be converted in `CAS::Constant` or `CAS::Op` child operations
* **returns**: `CAS::NaryOp` instance
41 42 43 44 45 46 47 48 49 50 |
# File 'lib/operators/nary-op.rb', line 41 def initialize(*xs) @x = [] xs.flatten.each do |x| if x.is_a? Numeric x = Op.numeric_to_const x end CAS::Help.assert(x, CAS::Op) @x << x end end |
Instance Attribute Details
#x ⇒ Object (readonly)
List of arguments of the operation
34 35 36 |
# File 'lib/operators/nary-op.rb', line 34 def x @x end |
Instance Method Details
#==(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
180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/operators/nary-op.rb', line 180 def ==(op) # CAS::Help.assert(op, CAS::Op) if op.is_a? CAS::NaryOp return false if @x.size != op.x.size 0.upto(@x.size - 1) do |i| return false if @x[i] != op.x[i] end return true end false end |
#__reduce_constants(xs) ⇒ Object
Collects all the constants and tries to reduce them to a single constant. Requires a block to understand what it should do with the constants
-
requires: input ‘Array` of `CAS::Op`
-
returns: new ‘Array` of `CAS::Op`
-
block: yields an ‘Array` of `CAS::Constant` and an `Array` of others `CAS::Op`, requires an `Array` back
247 248 249 250 251 252 253 254 255 |
# File 'lib/operators/nary-op.rb', line 247 def __reduce_constants(xs) const = [] xs.each { |x| const << x if x.is_a? CAS::Constant } if const.size > 0 yield const, (xs - const) else xs end end |
#__reduce_multeplicity(xs) ⇒ Object
Reduce multeplicity will scan for elements that are equal in the definition of the sum and will reduce their multeplicity. A block can be used to do something different. For example in nary-product we use it like this:
“‘ ruby end “`
In general it works like that:
“‘
a + a + b + c => 2 * a + b + c
a * a * b * a => (a ** b) * b
“‘ But operates only on Array level! This is an internal function and should never be used
* **requires**: An `Array`
* **returns**: An `Array` with multeplicity reduced
* **block**: yields the count and the op. Get the value to insert in a new
`Array` that is the returned `Array`
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/operators/nary-op.rb', line 224 def __reduce_multeplicity(xs) count = Hash.new(0) xs.each do |x| e = x count.keys.each { |d| e = d if x == d } count[e] += 1 end count.map do |k, v| if block_given? yield(k, v) else v > 1 ? CAS.const(v) * k : k end end end |
#args ⇒ Object
Returns a list of all ‘CAS::Variable`s of the current tree
* **returns**: `Array` of `CAS::Variable`s
195 196 197 198 199 |
# File 'lib/operators/nary-op.rb', line 195 def args r = [] @x.each { |x| r += x.args } return r.uniq end |
#call(fd) ⇒ 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**: `Array` of `Numeric`
103 104 105 106 |
# File 'lib/operators/nary-op.rb', line 103 def call(fd) CAS::Help.assert(fd, Hash) return @x.map { |x| x.call(fd) } end |
#depend?(v) ⇒ Boolean
Returns the dependencies of the operation. Require a ‘CAS::Variable` and it is one of the recursive method (implicit tree resolution)
* **argument**: `CAS::Variable` instance
* **returns**: `TrueClass` or `FalseClass`
57 58 59 60 61 62 63 64 |
# File 'lib/operators/nary-op.rb', line 57 def depend?(v) CAS::Help.assert(v, CAS::Op) ret = false @x.each do |y| ret |= y.depend?(v) end return ret end |
#diff(v) ⇒ Object
Return a list of derivative using the chain rule. The input is a operation:
“‘
f(x) = g(x) + h(x) + l(x) + m(x)
d f(x)
------ = g'(x) + h'(x) + l'(x) + m'(x)
dx
d f(x)
------ = 1
d g(x)
“‘
* **argument**: `CAS::Op` object of the derivative
* **returns**: `CAS::NaryOp` of derivative
82 83 84 85 86 87 88 |
# File 'lib/operators/nary-op.rb', line 82 def diff(v) CAS::Help.assert(v, CAS::Op) if self.depend?(v) return @x.map { |x| x.diff(v) } end return CAS::Zero end |
#dot_graph ⇒ Object
Return the local Graphviz node of the tree
* **returns**: `String` of local Graphiz node
62 63 64 65 66 67 68 69 |
# File 'lib/Mr.CAS/graphviz.rb', line 62 def dot_graph cls = "#{self.class.to_s.gsub("CAS::", "")}_#{self.object_id}" ret = "" @x.each do |x| ret += "#{cls} -> #{x.dot_graph}\n" end return ret end |
#inspect ⇒ Object
Inspector for the current object
* **returns**: `String`
170 171 172 |
# File 'lib/operators/nary-op.rb', line 170 def inspect "#{self.class}(#{@x.map(&:inspect).join(", ")})" 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
158 159 160 161 162 163 164 165 |
# File 'lib/operators/nary-op.rb', line 158 def simplify hash = self.to_s @x = @x.map { |x| x.simplify } while self.to_s != hash hash = self.to_s @x = @x.map { |x| x.simplify } end 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::NaryOp` (`self`) with substitution performed
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/operators/nary-op.rb', line 121 def subs(dt) CAS::Help.assert(dt, Hash) @x = @x.map { |z| z.subs(dt) || z } @x.each_with_index do |x, k| sub = dt.keys.select { |e| e == x }[0] if sub if dt[sub].is_a? CAS::Op @x[k] = dt[sub] elsif dt[sub].is_a? Numeric @x[k] = CAS::const dt[sub] else raise CAS::CASError, "Impossible subs. Received a #{dt[sub].class} = #{dt[sub]}" end end end return self 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`
149 150 151 |
# File 'lib/operators/nary-op.rb', line 149 def to_code return "(#{@x.map(&:to_code).join(", ")})" end |
#to_s ⇒ Object
Convert expression to string
* **returns**: `String` to print on screen
142 143 144 |
# File 'lib/operators/nary-op.rb', line 142 def to_s return "(#{@x.map(&:to_s).join(", ")})" end |