# Expression of Divisors
#
# by Shin-ichiro Hara
#
# Version 1.1 (2001.08.12)
module Algebra
class Factors
include Enumerable
def self.[](*a)
fact = new
a.each do |x|
fact.multiply(x)
end
fact
end
def self.mk(*a)
k = 0
b = []
while k < a.size
f = a[k]; k += 1
i = a[k]; k += 1
raise "parameter error (#{i})" unless i.is_a? Integer
b.push [f, i]
end
new(b)
end
def self.seki(a)
k = a.first
a[1..-1].each do |m|
k *= m
end
k
end
def initialize(array = [])
@bone = array
end
def dup; self.class.new(@bone.collect{|f, i| [f, i]}); end
def to_a; @bone; end
alias to_ary to_a
def each(&b); @bone.each(&b); end
def size; @bone.size; end
def shift; @bone.shift; end
def fact_size;
n = 0
each do |f, i|; n += i; end
n
end
def fact(i); @bone[i].first; end
def empty?; @bone.empty?; end
def head; @bone.first; end
def tail; self.class.new(@bone[1..-1]); end
def push(other); @bone.push other; self; end
def unshift(other); @bone.unshift(other); self; end
def collect(&b); self.class.new(@bone.collect(&b)); end
def map(&b); self.class.new(@bone.collect{|f, i| [yield(f), i]}); end
def collect!(&b); @bone.collect!(&b); self; end
def map!(&b); @bone.collect!{|f, i| [yield(f), i]}; self; end
def normalize!
c = nil
@bone.delete_if do |fact|
f, i = fact
if f.respond_to?(:constant?) and f.constant?
c and c *= f**i or c = f**i
true
end
end
if c
unless c.respond_to?(:unity?) && c.unity? && @bone.size > 0
@bone.unshift [c, 1]
end
end
self
end
def multiply(other, n = 1)
flag = false
@bone.each do |fact|
f, i = fact
if f == other
fact[1] = fact[1]+ 1
flag = true
break
end
end
@bone.push [other, n] unless flag
normalize!
self
end
def gcd(other)
bone = []
@bone.each do |f, n|
i = n
until i == 0 || (other % [f ** i]).zero?
i -= 1
end
bone.push [f, i]
end
self.class.new(bone)
end
def concat(facts)
facts.each do |f, i|
multiply f, i
end
self
end
def *(o)
case o
when self.class
dup.concat(o)
else
#self.class.new(dup.multiply(o).to_a)
dup.multiply(o)
end
end
alias << multiply
def **(n)
fac = self.class.new
n.times do
fac *= self
end
fac
end
def pi
x = 1
@bone.each do |f_i|
f, i = f_i
if i
x *= f**i
else
x *= f
end
end
x
end
def ==(fact)
if pi == fact.pi
flag = false
@bone.each do |f, i|
fact.each do |g, j|
if f == g || f == -g # this will be improved.
unless i == j
return false
end
end
end
end
true
else
false
end
end
def to_s
return "1" if @bone.empty?
a, b = @bone.size == 1 && @bone.first.last == 1? ["", ""] : ["(", ")"]
@bone.collect{|x|
"#{a}#{x.first}#{b}" + (x.last > 1 ? "^#{x.last}" : "")
}.join("")
end
alias inspect to_s
def each_product0 #create non trivial powers
if size > 0
fact0, e0 = head
yield fact0
tail.each_product do |fact, e|
yield fact
end
tail.each_product do |fact, e|
yield fact0*fact # e is ignored
end
end
end
def each_product #create non trivial powers
idx0 = (0...size).to_a
indices = []
idx0.each do |i|
break if i >= size
indices.push [idx0[i...size], [i], fact(i)]
end
avoid = []
until indices.empty?
idx, rdx, f = indices.shift
i = idx.first
next if avoid.find{|x| !(rdx & x).empty? }
#print rdx.inspect + " : "
r = yield(f)
if r
avoid.push rdx
next
end
idx.each_index do |k|
if k > 0 and k < idx.size
idx1 = idx[k..-1]
rdx1 = rdx + [idx[k]]
next if avoid.find{|x| !(rdx1 & x).empty?}
f1 = f * fact(idx[k])
indices.push [idx1, rdx1, f1]
end
end
end
end
def fact_all(f)
facts = self.class.new
each do |g, e|
next if e <= 0
i = 0
loop do
q, r = f.divmod_ED g
if r.zero?
f = q
i += 1
else
facts.push [g, i]
break
end
end
end
facts
end
def fact_all_u(f)
facts = self.class.new
each do |g, e|
next if e <= 0
next if g.constant?
i = 0
loop do
q, r = f.divmod g
if r.zero?
f = q.first
i += 1
else
facts.push [g, i]
break
end
end
end
facts
end
def correct_lc!(f)
k = f.ground.unity
each_with_index do |(g, i), j|
glc = g.lc
if glc != glc.unity && glc.unit?
@bone[j] = [g/glc, i]
else
k *= glc ** i
end
end
m = f.lc / k
unless m == f.ground.unity
unshift([m*f.unity, 1])
end
self
end
def mcorrect_lc!(f, an)
# k = f.ground.unity
k = f.unity
each_with_index do |(g, i), j|
glc = g.lc_at(an)
if glc.unit? && glc != glc.unity
@bone[j] = [g/glc, i]
else
k *= glc ** i
end
end
m = f.lc_at(an).divmod(k).first.first
unless m == f.ground.unity
concat yield(m)
end
self
end
end
end
if $0 == __FILE__
include Algebra
p Factors.new([[2, 2], [3, 2], [5, 2]]).pi == (2*3*5)**2
facts = Factors.new
facts << 2 << 3 << 5 << 7 << 11 << 13
k = 0
facts.each_product do |x|
k += 1
p x
x == 21
end
p k
end
syntax highlighted by Code2HTML, v. 0.9.1