#require "algebra/euclidian-ring"
require "algebra/array-supplement"
module Algebra
module ChineseRemainderTheorem
# return coeffs s.t. coeffs.inner_product(ary) == c
# entries of c and ary must be euclidian ring
def decompose_on_factors(c, ary)
f1, *fs = ary
k, *coeffs = f1.gcd_ext_all(*fs)
q, r = c.divmod(k)
unless r.zero?
print "c = "
p c
print "k = "
p k
print "ary = "
p ary
raise "#{c} is not expressed by parameters"
end
d1, *ds = coeffs.collect{|x| x * q}
[d1]+ds #this is ok
end
def decompose_on_cofactors_modp(c, ary, cofacts)
# c: Polynomial/Zp
# ary: Array of Polynomial/Zp
# cofacts: cofacts of ary
# OutPut: coeff.inner_product(cofacts of ary) == c
pf, prime = c.ground, c.ground.char
coeffs = ary.collect{|f| f.zero}
d1, *ds = decompose_on_factors(c, cofacts)
#normalize
ds_new = []
ds.each_with_index do |d, i|
fq, fr = d.divmod(ary[i+1])
d1 += fq * ary[0]
ds_new << fr
end
coeffs = [d1] + ds_new
# p c == coeffs.inner_product(cofacts)
coeffs
end
def decomp_on_cofactors_over_p_adic_int_first(c, ary, prime, cofacts)
pf = Polynomial.reduction(Integer, prime, "x")
ary_Zp = ary.collect{|f| pf.reduce(f)}
cofacts_Zp = cofacts.collect{|f| pf.reduce(f)}
c_zp = pf.reduce(c)
d1, *ds = decompose_on_factors(c_zp, cofacts_Zp)
#normalize
ds_new = []
ds.each_with_index do |d, i|
fq, fr = d.divmod(ary_Zp[i+1])
d1 += fq * ary_Zp[0]
ds_new << fr
end
coeffs = [d1] + ds_new
ring = c.class
coeffs.collect{|f| lifting(f, ring)}
end
def lifting(f, ring)
f.project(ring){|c, i| c.lift}
end
private :decomp_on_cofactors_over_p_adic_int_first, :lifting
def mk_cofacts(ary)
tot = ary.first.unity
ary.each do |f|; tot *= f; end
cofacts = []
ary.each do |f|; cofacts.push tot / f; end
cofacts
end
def decompose_on_cofactors_p_adic(c, ary, cofacts, prime, k)
# c: Polynomial/Intger
# ary: Array of Polynomial/Integer
# OutPut: coeff.inner_product(cofacts of ary) === c mod prime**k
raise if ary.find{|f| (f.lc % prime).zero?}
# cofacts = mk_cofacts(ary)
coeffs = ary.collect{|f| f.zero}
0.upto k-1 do |j|
e = prime ** j
c1 = (c - coeffs.inner_product(cofacts)) / e
coeffs1 = decomp_on_cofactors_over_p_adic_int_first(c1,
ary, prime, cofacts)
coeffs.each_index do |i|
coeffs[i] += coeffs1[i]*e
end
end
# p c - coeffs.inner_product(cofacts)
coeffs
end
end
end
if $0 == __FILE__
CRT = ChineseRemainderTheorem
include CRT
require "algebra/polynomial"
require "algebra/residue-class-ring"
require "algebra/polynomial-factor"
Zp = ResidueClassRing(Integer, 5)
P = Polynomial(Zp, "x")
x = P.var
a = x + 1
b = x + 2
c = x + 3
# ary = [b*c, c*a, a*b]
ary = [a, b, c]
f = a*b*c
# coeffs = decompose_on_factors(P.unity, ary)
coeffs = decompose_on_cofactors_modp(P.unity, ary, mk_cofacts(ary))
p cofacts = mk_cofacts(ary)
p coeffs
p coeffs.inner_product(cofacts)
exit
PZ = Polynomial(Integer, "x")
x = PZ.var
a = (x + 1)**2
b = (x + 2)**3
c = (x + 3)**1
ary = [a, b, c]
p decompose_on_cofactors_over_p_adic_int(PZ.unity, ary, mk_cofacts(ary),
11, 2)
end
syntax highlighted by Code2HTML, v. 0.9.1