# G.C.D. and something for Euclidian ring (equipping 'divmod' and 'zero?')
#
# by Shin-ichiro Hara
#
# Version 1.01 (2001.03.22)
require "algebra/algebraic-system"
module Algebra
module EuclidianRing
def lcm(b)
self * b / gcd(b)
end
def lcm_all(*a)
t = self
a.each do |x|
t = t.lcm(x)
end
t
end
def gcd3(b)
x, y = self, b
until y.zero?
q, r = x.divmod y
x, y = y, r
end
x
end
def gcd(n)
m = self
while n != 0
m %= n
tmp = m; m = n; n = tmp
end
m
end
def gcd_all(*a)
t = self
a.each do |x|
t = t.gcd(x)
end
t
end
def gcd_ext(g)
h, s = self, g
a, b = self.class.unity, self.class.zero
c, d = self.class.zero, self.class.unity
loop do
q, r = h.divmod s
return [s, c, d] if r.zero?
h, s = s, r # r == h - q * s
a, c = c, a - q * c
b, d = d, b - q * d
end
end
alias gcd_coeff gcd_ext
def gcd_coeff0(b)
if b.zero?
[self, unity, zero]
else
q, r = divmod b
d, x, y = b.gcd_coeff(r)
[d, y, x - y * q]
end
end
def gcd_coeff_all(*a0)
return [self, self] if a0.empty?
t, *a = a0
d, x, y = gcd_ext(t)
r = [x, y]
a.each do |u|
d, x, y = d.gcd_coeff(u)
r = r.collect{|v| x*v} + [y]
end
[d] + r
end
alias gcd_ext_all gcd_coeff_all
def pgcd(b)
x, y = self, b
until y.zero?
q, r = x.pdivmod y
x, y = y, r
end
x
end
def gcd_rec(b)
return self if b.zero?
return b if zero?
if is_a?(Polynomial) && !ground.field?
ac, ap = cont_pp
bc, bp = b.cont_pp
c = ac.gcd_rec(bc)
x, y = ap, bp
until y.zero?
q, r = x.pdivmod y
x, y = y, r
end
x.pp * c
else
x, y = self, b
until y.zero?
q, r = x.pdivmod y
x, y = y, r
end
x
end
end
def cont
t = nil
each do |x|
break if t && t.unit?
t = t ? t.gcd_rec(x) : x
end
t ? t : self
end
def pp; self / cont; end
def cont_pp; [c = cont, self / c]; end
end
end
class Integer < Numeric
include Algebra::EuclidianRing
end
class Rational < Numeric
include Algebra::EuclidianRing
end
if $0 == __FILE__
include Algebra
a, b = 108, 221
d, x, y = a.gcd_coeff(b)
puts "#{x}*#{a} + #{y}*#{b} = #{x * a + y * b} = #{d}"
a, b, c, e = 36, 126, 81, 12
p a.gcd_all(b, c, e)
d, x, y, z, w = a.gcd_coeff_all(b, c, e)
p d == x*a + y*b + z*c + w*e
puts "#{d} == #{x}*#{a} + #{y}*#{b} + #{z}*#{c} + #{w}*#{e}"
require "algebra/polynomial"
require "algebra/residue-class-ring"
Z7 = ResidueClassRing(Integer, 7)
# P = Polynomial(Z7, "x", "y")
P = Polynomial(Integer, "x", "y")
x, y = P.vars
f = 6*(x + 1)*(x + 2)*(y - 1)* (y + 2)
g = 9*(x + 1)*(x - 3)*(y - 1)* (y - 1)
p [f, g, f.gcd_rec(g)]
end
syntax highlighted by Code2HTML, v. 0.9.1