# Groebner basis module
#
# by Shin-ichiro Hara
#
# Version 1.3 (2001.04.03)
#
# Example:
# x, y, z = MPolynomial.vars "xyz"
# require "algebra/mathn"
# p Groebner.basis([x**2 + y**2 + z**2 -1, x**2 + z**2 - y, x - z])
require "algebra/ruby-version"
require "algebra/array-supplement"
require "algebra/groebner-basis-coeff"
#require "algebra/work/old-basis"
module Algebra
module Groebner
def S_pair(other)
x = lm.lcm(other.lm)
x / lt * rt - x / other.lt * other.rt
end
alias | S_pair
def self.basis?(f)
f.each_pair do |x, y|
unless ((x|y) % f).zero?
return false
end
end
true
end
def self.minimal_basis?(f)
return false unless basis?(f)
indexes = (0...f.size).to_a
indexes.each do |i|
others = f.values_at(*(indexes-[i])).collect{|x| x.lt}
if (f[i].lt % others).zero?
return false
end
end
true
end
def self.reduced_basis?(f)
return false unless basis?(f)
indexes = (0...f.size).to_a
indexes.each do |i|
others = f.values_at(*(indexes-[i])).collect{|x| x.lt}
f[i].each_term do |t|
if (t % others).zero?
return false
end
end
end
true
end
def self.basis_132D(f)
gbasis = f.dup
pairs = []
gbasis.each_pair do |x, y|
pairs.push [x, y]
end
while pair = pairs.shift
x, y = pair
s = (x|y) % gbasis
unless s.zero?
gbasis.each do |z| pairs.push([z, s]) end
gbasis.push s
end
end
gbasis
end
def self.basis_159A(f)
gbasis = f.sort # little effort
glm = gbasis.collect{|x| x.lm}
pairs = []
(0...glm.size).to_a.each_pair do |i, j|
pairs.push [i, j]
end
until pairs.empty?
i, j = pairs.first
if !glm[i].prime_to?(glm[j]) && !_ct(glm, pairs, i, j)
s = (gbasis[i]|gbasis[j]) % gbasis
unless s.zero?
0.upto glm.size-1 do |k|
pairs.push [k, glm.size]
end
gbasis.push s
glm.push s.lm
end
end
pairs.shift
end
gbasis
end
def self._ct(fm, b, i, j)
0.upto fm.size-1 do |k|
next if k == i or
k == j or
i < k ? b.include?([i, k]) : b.include?([k, i]) or
j < k ? b.include?([j, k]) : b.include?([k, j])
return true if fm[k].divide_or?(fm[i], fm[j])
end
false
end
def self.minimal_basis(gbasis)
# p [200, gbasis]
glm = gbasis.collect{|x| x.lm}
indexes = (0...gbasis.size).sort{|i, j| glm[j] <=> glm[i]}
indexes.each_with_index do |i, s|
(s+1).upto indexes.size-1 do |k| j = indexes[k]
# p [glm[j], glm[i], glm[j].divide? glm[i]]
if glm[j].divide? glm[i]
indexes[s] = nil
break
end
end
end
indexes.compact!
gbasis.values_at(*indexes)
end
def self.reduced_basis(gbasis)
gbasis.each_with_index do |x, i|
(g = gbasis.dup).delete_at(i)
gbasis[i] = x % g
end
gbasis.collect{|t| t / t.lc}
end
def self.basis(g)
gbasis = nil
# gbasis = basis_132D(g)
gbasis = basis_159A(g)
gbasis = minimal_basis(gbasis)
gbasis = reduced_basis(gbasis)
gbasis.sort!{|x, y| y <=> x}
gbasis
end
end
class MPolynomial
include Algebra::Groebner
end
end
if $0 == __FILE__
require "algebra/m-polynomial"
# include Algebra
def gb(f, sw = false)
f0 = f.first
print "Basis of: "
sw ? puts('', *f) : puts(f.join(", "))
gbase = Algebra::Groebner.reduced_basis(f)
print "Is: "
sw ? puts('', *gbase) : puts(gbase.join(", "))
puts
end
puts "rational"
require "algebra/rational"
x, y, z = Algebra.MPolynomial(Rational).vars "xyz"
f1 = x**2 + y**2 + z**2 -1
f2 = x**2 + z**2 - y
f3 = x - z
gb([f1, f2, f3])
puts "mod 5"
require "algebra/residue-class-ring"
F5 = Algebra.ResidueClassRing(Integer, 5)
x, y, z = Algebra.MPolynomial(F5).vars "xyz"
f1 = x**2 + y**2 + z**2 -1
f2 = x**2 + z**2 - y
f3 = x - z
gb([f1, f2, f3])
puts "require 'algebra/mathn'"
require "algebra/mathn"
x, y, z = Algebra.MPolynomial(Integer).vars "xyz"
f1 = x**2 + y**2 + z**2 -1
f2 = x**2 + z**2 - y
f3 = x - z
gb([f1, f2, f3])
end
syntax highlighted by Code2HTML, v. 0.9.1