233 lines
4.8 KiB
Ruby
233 lines
4.8 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module RubyAlgebra
|
|
# Многочлен - сумма одночленов
|
|
class Polynomial
|
|
# одночлены
|
|
attr_reader :terms
|
|
|
|
def initialize(terms = [])
|
|
@terms = if terms.is_a? Term
|
|
[terms]
|
|
else
|
|
terms
|
|
end
|
|
simplify!
|
|
end
|
|
|
|
def to_s
|
|
if @terms.empty?
|
|
result = ''
|
|
else
|
|
result = @terms[-1].to_s
|
|
i = @terms.length - 2
|
|
while i >= 0
|
|
result += if @terms[i].coeff > 0
|
|
" + #{@terms[i]}"
|
|
else
|
|
" - #{-@terms[i]}"
|
|
end
|
|
i -= 1
|
|
end
|
|
end
|
|
result
|
|
end
|
|
|
|
def diff
|
|
raise NotImplementedError
|
|
end
|
|
|
|
def evaluate(values)
|
|
result = 0
|
|
@terms.each do |term|
|
|
# ...
|
|
end
|
|
result
|
|
end
|
|
|
|
def +(other)
|
|
if other.is_a? Polynomial
|
|
Polynomial.new(@terms + other.terms).simplify
|
|
elsif other.is_a? Term
|
|
Polynomial.new(@terms + [other]).simplify
|
|
else
|
|
Polynomial.new(@terms + [Term.new(other)]).simplify
|
|
end
|
|
end
|
|
|
|
def *(other)
|
|
if other.is_a? Polynomial
|
|
result = Polynomial.new
|
|
other.terms.each do |term|
|
|
result += self * term
|
|
end
|
|
result
|
|
else
|
|
Polynomial.new(@terms.map { |term| term * other })
|
|
end
|
|
end
|
|
|
|
def **(other)
|
|
result = Polynomial.new([Term.new(1)])
|
|
other.times do
|
|
result *= self
|
|
end
|
|
result
|
|
end
|
|
|
|
def -(other)
|
|
self + -other
|
|
end
|
|
|
|
def +@
|
|
self
|
|
end
|
|
|
|
def -@
|
|
self * -1
|
|
end
|
|
|
|
def ==(other)
|
|
@terms == other.terms
|
|
end
|
|
|
|
def simplify
|
|
i = 0
|
|
new_terms = @terms.filter { |t| !t.zero? }
|
|
while i < new_terms.length
|
|
j = i + 1
|
|
while j < new_terms.length
|
|
if new_terms[i].similar_to?(new_terms[j])
|
|
new_terms[i] += new_terms[j]
|
|
if new_terms[i].zero?
|
|
new_terms.delete_at(i)
|
|
i -= 1
|
|
j -= 1
|
|
end
|
|
new_terms.delete_at(j)
|
|
j -= 1
|
|
end
|
|
j += 1
|
|
end
|
|
i += 1
|
|
end
|
|
Polynomial.new(new_terms.sort_by { |t| t.total_power })
|
|
end
|
|
|
|
def simplify!
|
|
i = 0
|
|
new_terms = @terms.filter { |t| !t.zero? }
|
|
while i < new_terms.length
|
|
j = i + 1
|
|
while j < new_terms.length
|
|
if new_terms[i].similar_to?(new_terms[j])
|
|
new_terms[i] += new_terms[j]
|
|
if new_terms[i].zero?
|
|
new_terms.delete_at(i)
|
|
i -= 1
|
|
j -= 1
|
|
end
|
|
new_terms.delete_at(j)
|
|
j -= 1
|
|
end
|
|
j += 1
|
|
end
|
|
i += 1
|
|
end
|
|
@terms = new_terms.sort_by { |t| t.total_power }
|
|
end
|
|
end
|
|
|
|
# Одночлен в форме a_n * x_1^k_1 * ... * x_n^k_n
|
|
class Term
|
|
attr_reader :coeff, :variables
|
|
|
|
def initialize(coeff = 0, variables = {})
|
|
@coeff = coeff
|
|
@variables = {}
|
|
variables.each do |var, power|
|
|
next if power.zero?
|
|
|
|
if @variables[var].nil?
|
|
@variables[var] = power
|
|
else
|
|
@variables[var] += power
|
|
end
|
|
end
|
|
end
|
|
|
|
def diff(var)
|
|
raise NotImplementedError
|
|
end
|
|
|
|
def evaluate(values)
|
|
raise NotImplementedError
|
|
end
|
|
|
|
def +(other)
|
|
raise NotImplementedError, 'addition of non-similar terms is not implemented' unless similar_to?(other)
|
|
|
|
Term.new(@coeff + other.coeff, @variables)
|
|
end
|
|
|
|
def *(other)
|
|
return Term.new if @coeff.zero? || other.coeff.zero?
|
|
|
|
new_variables = @variables.clone
|
|
other.variables.each do |symbol, power|
|
|
if new_variables[symbol].nil?
|
|
new_variables[symbol] = power
|
|
else
|
|
new_variables[symbol] += power
|
|
end
|
|
end
|
|
Term.new(@coeff * other.coeff, new_variables)
|
|
end
|
|
|
|
def +@
|
|
Term.new(@coeff, @variables)
|
|
end
|
|
|
|
def -@
|
|
Term.new(-@coeff, @variables)
|
|
end
|
|
|
|
def ==(other)
|
|
@coeff == other.coeff && @variables == other.variables
|
|
end
|
|
|
|
def total_power
|
|
@variables.values.sum
|
|
end
|
|
|
|
def to_s
|
|
result = coeff.to_s
|
|
unless @variables.empty?
|
|
first = true
|
|
@variables.each do |var, power|
|
|
result += if first
|
|
"#{var}^#{power}"
|
|
else
|
|
" * #{var}^#{power}"
|
|
end
|
|
first = false
|
|
end
|
|
end
|
|
result
|
|
end
|
|
|
|
def similar_to?(other)
|
|
return false if @variables.length != other.variables.length
|
|
|
|
other.variables.each do |var, power|
|
|
return false if @variables[var] != power
|
|
end
|
|
true
|
|
end
|
|
|
|
def zero?
|
|
@coeff.zero?
|
|
end
|
|
end
|
|
end
|