polynomials
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
232
lib/ruby_algebra/polynomial.rb
Normal file
232
lib/ruby_algebra/polynomial.rb
Normal 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
|
||||||
Reference in New Issue
Block a user