# Residue Class Ring
#
# by Shin-ichiro Hara
#
# Version 1.2 (2001.04.08)
require "algebra/euclidian-ring"
require "algebra/algebraic-system"
#require "algebra/algebraic-extension-field.rb"
module Algebra
def ResidueClassRing(klass, mod)
ResidueClassRing.create(klass, mod)
end
=begin
def AlgebraicExtensionField(field, var)
ring = Polynomial(field, var)
k = ResidueClassRing(ring, yield(ring.var))
def k.var; self[ground.var]; end
k
end
module_function :ResidueClassRing, :AlgebraicExtensionField
=end
module_function :ResidueClassRing
class ResidueClassRing
extend AlgebraCreator
include AlgebraBase
attr_reader :x
def lift; @x; end
def self.[](m); new(m); end
def self.indeterminate(obj)
new(ground.indeterminate(obj))
end
def self.**(elem)
#elem: Polynomial, ResidueClassRing
elem.convert_to(self)
end
def initialize(x)
@x = x % modulus
end
def monomial?
!@x.respond_to?(:monomial?) || @x.monomial?
#^^^^^^^^^ numeric ^^^^^^^^^
end
def need_paren_in_coeff?
if @x.respond_to?(:need_paren_in_coeff?)
@x.need_paren_in_coeff?
elsif @x.is_a?(Numeric)
false
else
true
end
end
def evaluate(*a)
#p [333, @x, @x.class, a[0], a[0].class]
#b = a[0].lift
#c = b.evaluate(@x)
#p [c, c.class]
#d = self.class[c]
#p [d, d.class]
#k = @x.evaluate(*a)
#p [444, k, k.class, k.lift, k.lift.class]
self.class[@x.evaluate(*a)]
#d
end
def convert_to(k)
b = lift
c = b.evaluate(k.ground.var)
k[c]
end
def ==(other)
super{ |o|
((@x - o.x) % modulus).zero?
}
end
def +(other)
super{ |o|
self.class[@x + o.x]
}
end
def -(other)
super{ |o|
self.class[@x - o.x]
}
end
def *(other)
super{ |o|
self.class[@x * o.x]
}
end
def inverse
return self.class.inverse(@x) if self.class.respond_to? :inverse
return self.class[@x.inverse] if @x.respond_to? :inverse
d, a, = @x.gcd_coeff(modulus)
self.class.new(a / d)
end
def /(other)
if other.is_a?(self.class)
self * other.inverse
else
super{ |o|
self.class[@x / o.x]
}
end
end
def pdivmod(other); [self / other, zero]; end
# def unit?
# inverse
# end
def to_s
(@x % modulus).to_s
end
alias inspect to_s unless $DEBUG
def modulus; self.class.modulus; end
def modulus=(var); self.class.modulus = var; end
def self.create(ground, mod)
klass = super(ground)
klass.sysvar(:modulus, mod)
if mod.is_a?(Integer) && (ground <= Integer || defined?(Rational) &&
ground <= Rational)
klass.class_eval <<__END_OF_CLASS_DEFINITION__
# @@modulus = #{mod}
@@inverse = [nil] + (1...@@modulus).collect{|x|
d, a, = x.gcd_coeff(@@modulus)
(y = a % @@modulus / d).zero? ? nil : y
}
require "algebra/prime-gen"
def self.field?; Primes.include?(@@modulus); end
def self.char; @@modulus; end
def self.inverse(k); @@inverse[k]; end
def self.to_ary; (0...@@modulus).collect{|x| self[x]}; end
__END_OF_CLASS_DEFINITION__
end
klass
end
end
end
if __FILE__ == $0
include Algebra
Z13 = ResidueClassRing.create(Integer, 13)
a, b, c, d, e, f, g = Z13
p [e + c, e - c, e * c, e * 2001, 3 + c, 1/c, 1/c * c,
d / d, b * 1 / b] #=> [6, 2, 8, 9, 5, 7, 1, 1, 1]
p( (1...13).collect{|i| Z13[i]**12} )
#=> [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
require "algebra/polynomial"
require "algebra/rational"
Px = Polynomial(Rational, "x")
# Px = Polynomial(Z13, "x")
x = Px.var
F = ResidueClassRing(Px, x**2 + x + 1)
x = F[x]
p( (x + 1)**100 ) #=> -x - 1
G = Polynomial(F, "y")
y = G.var
p( (x + y + 1)** 7 )
#=> y^7 + (7x + 7)y^6 + 8xy^5 + 4y^4 + (4x + 4)y^3 + 5xy^2 + 7y + x + 1
H = ResidueClassRing(G, y**5 + x*y + 1)
y = H[y]
p( (x + y + 1)**7 )
#=> 4y^4 + (3x + 4)y^3 + (5x + 6)y^2 + (x + 8)y + 6x + 1
p( 1/(x + y + 1)**7 )
#=> (1798/3x + 1825/9)y^4 + (-74x + 5176/9)y^3 +
# (-6886/9x - 5917/9)y^2 + (1826/3x - 3101/9)y + 2146/9x + 4702/9
require "algebra/polynomial"
# A = Polynomial(Rational, "x")
Z7 = ResidueClassRing.create(Integer, 7)
A = Polynomial(Z7, "x")
x = A.var
B = Polynomial(A, "y")
y = B.var
C = Polynomial(B, "z")
z = C.var
D = Polynomial(C, "w")
w = D.var
p( (x+y+z+w)**7 ) #=> w^7 + z^7 + y^7 + x^7
require "algebra/algebraic-extension-field.rb"
AEF = AlgebraicExtensionField(Rational, "x") {|x| x**2 + x + 1}
x = AEF.var
p( (x-1)** 3 / (x**2 - 1) )
end
syntax highlighted by Code2HTML, v. 0.9.1