class CAS::NaryOp

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.

Attributes

x[R]

List of arguments of the operation

Public Class Methods

new(*xs) click to toggle source

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

Public Instance Methods

==(op) click to toggle source

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
# 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) { |const, (xs - const)| ... } click to toggle source

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

# 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) { |k, v| ... } click to toggle source

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 @x = self.__reduce_multeplicity(@x) do |count, op|

count > 1 ? (op ** count) : op

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`
# 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() click to toggle source

Returns a list of all `CAS::Variable`s of the current tree

* **returns**: `Array` of `CAS::Variable`s
# File lib/operators/nary-op.rb, line 168
def args
  r = []
  @x.each { |x| r += x.args }
  return r.uniq
end
call(fd) click to toggle source

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({x => 1, y => 2}) # => 2 “`

* **argument**: `Hash` with feed dictionary
* **returns**: `Array` of `Numeric`
# 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) click to toggle source

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`
# File lib/operators/nary-op.rb, line 34
def depend?(v)
  CAS::Help.assert(v, CAS::Op)
  @x.include? v
end
diff(v) click to toggle source

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
# 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() click to toggle source

Return the local Graphviz node of the tree

* **returns**: `String` of local Graphiz node
# 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() click to toggle source

Inspector for the current object

* **returns**: `String`
# File lib/operators/nary-op.rb, line 143
def inspect
  "#{self.class}(#{@x.map(&:inspect).join(", ")})"
end
simplify() click to toggle source

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
# 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) click to toggle source

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({x => CAS::ln(y)}) # => (ln(y)^2) + (y^2) “`

* **argument**: `Hash` with substitution table
* **returns**: `CAS::NaryOp` (`self`) with substitution performed
# 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() click to toggle source

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`
# File lib/operators/nary-op.rb, line 122
def to_code
  return "(#{@x.map(&:to_code).join(", ")})"
end
to_s() click to toggle source

Convert expression to string

* **returns**: `String` to print on screen
# File lib/operators/nary-op.rb, line 115
def to_s
  return "(#{@x.map(&:to_s).join(", ")})"
end