Class: Multivariate
- Inherits:
-
Polynomial
- Object
- Polynomial
- Multivariate
- Defined in:
- lib/polynomial/multivariate.rb
Overview
TODO: consider building an writer for @terms which sorts the value
prior to actually setting it.
Constant Summary collapse
- Unity =
new([1,0,0])
- Zero =
new([0,0,0])
Constants inherited from Polynomial
Polynomial::FromStringDefaults, Polynomial::ToSDefaults
Instance Attribute Summary collapse
-
#terms ⇒ Object
readonly
Returns the value of attribute terms.
-
#vars ⇒ Object
readonly
Returns the value of attribute vars.
Attributes inherited from Polynomial
Class Method Summary collapse
-
.reduce_terms(terms) ⇒ Object
Group same powered terms.
Instance Method Summary collapse
- #*(other) ⇒ Object
-
#**(n) ⇒ Object
FIXME: implement efficiently, i.e., O(m) where m is the number of terms.
- #==(other) ⇒ Object
- #coerce(other) ⇒ Object
- #degree(index) ⇒ Object
-
#initialize(*terms) ⇒ Multivariate
constructor
Creates a new multivariate polynomial from supplied string representation, basically delegating to Multivariate.from_string.
-
#substitute(*xs) ⇒ Object
Evaluates Multivariate polynomial – FIXME: replace current straightforward but slow implementation by some efficient Horner’s rule inspired algorithm.
Methods inherited from Polynomial
#%, #+, #-, #-@, #<=>, #derivative, #derivatives, #div, #divmod, #dup, #equal_in_delta, from_string, #integral, #quo, #quomod, #to_f, #to_i, #to_num, #to_s, #unity?, #zero?
Constructor Details
#initialize(*terms) ⇒ Multivariate
Creates a new multivariate polynomial from supplied string representation, basically delegating to Multivariate.from_string.
Examples:
Polynomial::Multivariate[[1,1,0],[2,0,1]].to_s #=> "x + 2*y"
–
Polynomial::Multivariate['x+y'].to_s #=> "x + y"
Polynomial::Multivariate['xy+y^3', :power_symbol=>'^'].to_s #=> "x*y + y**3"
++
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/polynomial/multivariate.rb', line 25 def initialize(*terms) !terms.empty? or raise ArgumentError, 'at least one coefficient should be supplied' arg = terms[0] case arg when Array terms.flatten.all? {|a| a.is_a? Numeric } or raise TypeError, 'coefficient-power should be Numeric' sz = arg.size sz > 2 or raise ArgumentError, 'coefficient-power tuplets should have length > 2' terms.all? {|ary| ary.size == sz } or raise ArgumentError, 'inconsistent data' when String raise NotImplementedError # coefs = self.class.coefs_from_string(coefs[0], coefs[1] || {}) else raise TypeError, 'coefficient-power should be Numeric' end @vars = sz - 1 @terms = self.class.reduce_terms(terms).sort end |
Instance Attribute Details
#terms ⇒ Object (readonly)
Returns the value of attribute terms.
9 10 11 |
# File 'lib/polynomial/multivariate.rb', line 9 def terms @terms end |
#vars ⇒ Object (readonly)
Returns the value of attribute vars.
9 10 11 |
# File 'lib/polynomial/multivariate.rb', line 9 def vars @vars end |
Class Method Details
.reduce_terms(terms) ⇒ Object
Group same powered terms.
The result is always non-empty, the base case being [[0,..,0]]
128 129 130 131 132 133 134 135 136 |
# File 'lib/polynomial/multivariate.rb', line 128 def self.reduce_terms(terms) new_terms = [] terms.group_by {|a,*powers| powers }.each_pair do |powers, terms| new_coef = 0 terms.each {|coef, *rest| new_coef += coef } new_terms << [new_coef, *powers] unless new_coef.zero? end new_terms.empty? ? [terms[0].map { 0 }] : new_terms end |
Instance Method Details
#*(other) ⇒ Object
62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/polynomial/multivariate.rb', line 62 def *(other) @vars == other.vars or raise ArgumentError, "number of variables must be the same for both multiplicands" new_terms = [] @terms.each do |my_term| other.terms.each do |other_term| new_coef = my_term[0] * other_term[0] new_powers = my_term[1..-1].zip(other_term[1..-1]).map {|a,b| a + b } new_term = [new_coef] + new_powers new_terms << new_term end end self.class.new(*new_terms.sort) end |
#**(n) ⇒ Object
FIXME: implement efficiently, i.e., O(m) where m is the number of terms
77 78 79 80 81 |
# File 'lib/polynomial/multivariate.rb', line 77 def **(n) n >= 0 or raise RangeError, "negative argument" n.is_a?(Integer) or raise TypeError, "non-integer argument" ([self]*n).inject(Unity) {|s,k| s*k } end |
#==(other) ⇒ Object
83 84 85 86 87 |
# File 'lib/polynomial/multivariate.rb', line 83 def ==(other) self.instance_variables.all? do |var_name| self.instance_variable_get(var_name) == other.instance_variable_get(var_name) end end |
#coerce(other) ⇒ Object
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/polynomial/multivariate.rb', line 99 def coerce(other) case other when Numeric [self.class.new([other]), self] when Polynomial [other, self] else raise TypeError, "#{other.class} can't be coerced into Polynomial" end end |
#degree(index) ⇒ Object
89 90 91 92 93 94 95 96 97 |
# File 'lib/polynomial/multivariate.rb', line 89 def degree(index) if index == 0 0 elsif index > 0 && index <= @vars @terms.map {|cp| cp[index] }.max else raise RangeError, 'invalid variable index' end end |
#substitute(*xs) ⇒ Object
Evaluates Multivariate polynomial – FIXME: replace current straightforward but slow implementation
by some efficient Horner's rule inspired algorithm.
++
49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/polynomial/multivariate.rb', line 49 def substitute(*xs) xs.size == @vars or raise ArgumentError, "wrong number of arguments (#{xs.size} for #{@vars})" total = 0 @terms.each do |coef, *powers| result = coef for i in 0 ... @vars result *= xs[i] ** powers[i] end total += result end total end |