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
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/operators/nary-op.rb', line 18 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
11 12 13 |
# File 'lib/operators/nary-op.rb', line 11 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
153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/operators/nary-op.rb', line 153 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
220 221 222 223 224 225 226 227 228 |
# File 'lib/operators/nary-op.rb', line 220 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`
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/operators/nary-op.rb', line 197 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
168 169 170 171 172 |
# File 'lib/operators/nary-op.rb', line 168 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`
76 77 78 79 |
# File 'lib/operators/nary-op.rb', line 76 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`
34 35 36 37 |
# File 'lib/operators/nary-op.rb', line 34 def depend?(v) CAS::Help.assert(v, CAS::Op) @x.include? v 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
55 56 57 58 59 60 61 |
# File 'lib/operators/nary-op.rb', line 55 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
39 40 41 42 43 44 45 46 |
# File 'lib/Mr.CAS/graphviz.rb', line 39 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`
143 144 145 |
# File 'lib/operators/nary-op.rb', line 143 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
131 132 133 134 135 136 137 138 |
# File 'lib/operators/nary-op.rb', line 131 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
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/operators/nary-op.rb', line 94 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`
122 123 124 |
# File 'lib/operators/nary-op.rb', line 122 def to_code return "(#{@x.map(&:to_code).join(", ")})" end |
#to_s ⇒ Object
Convert expression to string
* **returns**: `String` to print on screen
115 116 117 |
# File 'lib/operators/nary-op.rb', line 115 def to_s return "(#{@x.map(&:to_s).join(", ")})" end |