# 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 zero? || other.zero? return Term.new(coeff * other, variables) unless other.is_a? Term 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 != 1 ? @coeff.to_s : '' unless @variables.empty? first = true @variables.each do |var, power| if first unless power == 1 result += "#{var}^#{power}" else result += "#{var}" end else unless power == 1 result += " * #{var}^#{power}" else result += " * #{var}" end 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