polynomials

This commit is contained in:
2026-03-31 04:03:44 +03:00
parent 6b719a37e3
commit afb81b475a
3 changed files with 272 additions and 10 deletions

View File

@@ -1,8 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "ruby_algebra/version" require_relative 'ruby_algebra/version'
require_relative "ruby_algebra/expression" require_relative 'ruby_algebra/expression'
require_relative "ruby_algebra/parser" require_relative 'ruby_algebra/polynomial'
require_relative 'ruby_algebra/parser'
module RubyAlgebra module RubyAlgebra
end end

View File

@@ -17,12 +17,15 @@ module RubyAlgebra
def op_assoc_type def op_assoc_type
raise NotImplementedError raise NotImplementedError
end end
def diff(v) def diff(v)
raise NotImplementedError, "#{self.class}#diff not implemented" raise NotImplementedError, "#{self.class}#diff not implemented"
end end
def evaluate def evaluate
raise NotImplementedError, "#{self.class}#evaluate not implemented" raise NotImplementedError, "#{self.class}#evaluate not implemented"
end end
def constant? def constant?
raise NotImplementedError, "#{self.class}#constant? not implemented" raise NotImplementedError, "#{self.class}#constant? not implemented"
end end
@@ -33,6 +36,7 @@ module RubyAlgebra
def initialize(lhs, rhs) def initialize(lhs, rhs)
raise ArgumentError unless lhs.is_a?(Expression) && rhs.is_a?(Expression) raise ArgumentError unless lhs.is_a?(Expression) && rhs.is_a?(Expression)
@lhs = lhs @lhs = lhs
@rhs = rhs @rhs = rhs
end end
@@ -59,18 +63,22 @@ module RubyAlgebra
def ==(other) def ==(other)
return false if other.type != type return false if other.type != type
lhs == other.lhs && rhs == other.rhs lhs == other.lhs && rhs == other.rhs
end end
def diff(v) def diff(v)
Addition.new(@lhs.diff(v), @rhs.diff(v)) Addition.new(@lhs.diff(v), @rhs.diff(v))
end end
def evaluate def evaluate
lhs_val = @lhs.evaluate lhs_val = @lhs.evaluate
rhs_val = @rhs.evaluate rhs_val = @rhs.evaluate
return nil if lhs_val.nil? || rhs_val.nil? return nil if lhs_val.nil? || rhs_val.nil?
lhs_val + rhs_val lhs_val + rhs_val
end end
def constant? def constant?
@lhs.constant? && @rhs.constant? @lhs.constant? && @rhs.constant?
end end
@@ -94,12 +102,15 @@ module RubyAlgebra
def diff(v) def diff(v)
Subtraction.new(@lhs.diff(v), @rhs.diff(v)) Subtraction.new(@lhs.diff(v), @rhs.diff(v))
end end
def evaluate def evaluate
lhs_val = @lhs.evaluate lhs_val = @lhs.evaluate
rhs_val = @rhs.evaluate rhs_val = @rhs.evaluate
return nil if lhs_val.nil? || rhs_val.nil? return nil if lhs_val.nil? || rhs_val.nil?
lhs_val - rhs_val lhs_val - rhs_val
end end
def constant? def constant?
@lhs.constant? && @rhs.constant? @lhs.constant? && @rhs.constant?
end end
@@ -110,6 +121,7 @@ module RubyAlgebra
def initialize(lhs, rhs) def initialize(lhs, rhs)
raise ArgumentError unless lhs.is_a?(Expression) && rhs.is_a?(Expression) raise ArgumentError unless lhs.is_a?(Expression) && rhs.is_a?(Expression)
@lhs = lhs @lhs = lhs
@rhs = rhs @rhs = rhs
end end
@@ -121,12 +133,10 @@ module RubyAlgebra
if lhs.type == :constant && lhs.value == 1 if lhs.type == :constant && lhs.value == 1
need_parentheses_right ? "(#{rhs})" : rhs.to_s need_parentheses_right ? "(#{rhs})" : rhs.to_s
elsif lhs.type == :constant && lhs.value == -1 elsif lhs.type == :constant && lhs.value == -1
need_parentheses_right ? "-(#{rhs})" : "-#{rhs.to_s}" need_parentheses_right ? "-(#{rhs})" : "-#{rhs}"
elsif (need_parentheses_right || rhs.type == :variable) && (need_parentheses_left || lhs.type == :mult || lhs.type == :constant) elsif (need_parentheses_right || rhs.type == :variable) && (need_parentheses_left || lhs.type == :mult || lhs.type == :constant)
result = need_parentheses_left ? "(#{lhs})" : lhs.to_s result = need_parentheses_left ? "(#{lhs})" : lhs.to_s
if lhs.type == :variable && rhs.type == :variable && lhs.single_letter? && rhs.single_letter? result += ' ' if lhs.type == :variable && rhs.type == :variable && lhs.single_letter? && rhs.single_letter?
result += " "
end
result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s) result + (need_parentheses_right ? "(#{rhs})" : rhs.to_s)
else else
result = need_parentheses_left ? "(#{lhs}) * " : "#{lhs} * " result = need_parentheses_left ? "(#{lhs}) * " : "#{lhs} * "
@@ -148,6 +158,7 @@ module RubyAlgebra
def ==(other) def ==(other)
return false if other.type != type return false if other.type != type
lhs == other.lhs && rhs == other.rhs lhs == other.lhs && rhs == other.rhs
end end
@@ -158,12 +169,15 @@ module RubyAlgebra
term2 = Multiplication.new(@lhs, v_prime) term2 = Multiplication.new(@lhs, v_prime)
Addition.new(term1, term2) Addition.new(term1, term2)
end end
def evaluate def evaluate
lhs_val = @lhs.evaluate lhs_val = @lhs.evaluate
rhs_val = @rhs.evaluate rhs_val = @rhs.evaluate
return nil if lhs_val.nil? || rhs_val.nil? return nil if lhs_val.nil? || rhs_val.nil?
lhs_val * rhs_val lhs_val * rhs_val
end end
def constant? def constant?
@lhs.constant? && @rhs.constant? @lhs.constant? && @rhs.constant?
end end
@@ -181,6 +195,7 @@ module RubyAlgebra
def type def type
:div :div
end end
def diff(v) def diff(v)
u_prime = @lhs.diff(v) u_prime = @lhs.diff(v)
v_prime = @rhs.diff(v) v_prime = @rhs.diff(v)
@@ -192,13 +207,16 @@ module RubyAlgebra
denominator = Power.new(@rhs, Constant.new(2)) denominator = Power.new(@rhs, Constant.new(2))
Division.new(numerator, denominator) Division.new(numerator, denominator)
end end
def evaluate def evaluate
lhs_val = @lhs.evaluate lhs_val = @lhs.evaluate
rhs_val = @rhs.evaluate rhs_val = @rhs.evaluate
return nil if lhs_val.nil? || rhs_val.nil? return nil if lhs_val.nil? || rhs_val.nil?
return nil if rhs_val == 0 return nil if rhs_val == 0
lhs_val / rhs_val
lhs_val.to_f / rhs_val
end end
def constant? def constant?
@lhs.constant? && @rhs.constant? @lhs.constant? && @rhs.constant?
end end
@@ -209,6 +227,7 @@ module RubyAlgebra
def initialize(base, exponent) def initialize(base, exponent)
raise ArgumentError unless base.is_a?(Expression) && exponent.is_a?(Expression) raise ArgumentError unless base.is_a?(Expression) && exponent.is_a?(Expression)
@base = base @base = base
@exponent = exponent @exponent = exponent
end end
@@ -235,12 +254,13 @@ module RubyAlgebra
def ==(other) def ==(other)
return false if other.type != type return false if other.type != type
base == other.base && exponent == other.exponent base == other.base && exponent == other.exponent
end end
def diff(v) def diff(v)
unless @exponent.is_a?(Constant) unless @exponent.is_a?(Constant)
raise NotImplementedError, "Дифференцирование степени с неконстантным показателем не реализовано" raise NotImplementedError, 'Дифференцирование степени с неконстантным показателем не реализовано'
end end
n = @exponent.value n = @exponent.value
@@ -250,12 +270,15 @@ module RubyAlgebra
coeff = Constant.new(n) coeff = Constant.new(n)
Multiplication.new(coeff, Multiplication.new(new_power, base_diff)) Multiplication.new(coeff, Multiplication.new(new_power, base_diff))
end end
def evaluate def evaluate
base_val = @base.evaluate base_val = @base.evaluate
exp_val = @exponent.evaluate exp_val = @exponent.evaluate
return nil if base_val.nil? || exp_val.nil? return nil if base_val.nil? || exp_val.nil?
base_val ** exp_val
base_val**exp_val
end end
def constant? def constant?
@base.constant? && @exponent.constant? @base.constant? && @exponent.constant?
end end
@@ -286,15 +309,18 @@ module RubyAlgebra
def ==(other) def ==(other)
return false if other.type != type return false if other.type != type
value == other.value value == other.value
end end
def diff(v) def diff(v)
Constant.new(0) Constant.new(0)
end end
def evaluate def evaluate
@value @value
end end
def constant? def constant?
true true
end end
@@ -330,15 +356,18 @@ module RubyAlgebra
def ==(other) def ==(other)
return false if other.type != type return false if other.type != type
symbol == other.symbol symbol == other.symbol
end end
def diff(v) def diff(v)
@symbol == v ? Constant.new(1) : Constant.new(0) @symbol == v ? Constant.new(1) : Constant.new(0)
end end
def evaluate def evaluate
nil nil
end end
def constant? def constant?
false false
end end

View File

@@ -0,0 +1,232 @@
# 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