Sagebrush · Examples · Notebooks

Gröbner bases (Sage)

Multivariate polynomials: products, gcds, factoring and Gröbner bases.

notebook · Sage · research · by Sagebrush · MIT license

polynomialsalgebra

Download (ZIP)Source on GitHub

Preview

Multivariate polynomials and Gröbner bases

All on Sagebrush's own Rust engine (engine/mpoly), in this page: dense-chunk multiplication, Brown's modular gcd, Wang's EEZ factorization over , factorization over , and Faugère's F4 for Gröbner bases over and over (from bases modulo many primes, checked exactly).

The browser runs one thread. Natively (pip install the Python package, or the sagebrush CLI) the bases over use every core: one prime per thread, and the exact check in parallel. katsura-7 over takes about 0.4 s natively on 16 cores and about 3 s here.

# Fateman's benchmark: the product f*(f + 1) for f = (1 + x + y + z + t)^n
R.<x,y,z,t> = QQ[]
f = (1 + x + y + z + t)^12
g = f*(f + 1)
len(g.dict())
20475
# gcd and factorization (Wang's EEZ: leading coefficients distributed, Hensel lifting)
F = g.factor()
[(h.degree(), e) for h, e in F]
[(1, 12), (4, 1), (8, 1)]
R.<x,y,z> = QQ[]
h = (x^2*y + 3*x - z^3)*(2*x*y*z - 7*y^2 + 1)^2*(x - y)
h.factor(), gcd(h, (x - y)^3*(x^2*y + 3*x - z^3))
((-x + y) * (-x^2*y + z^3 - 3*x) * (2*x*y*z - 7*y^2 + 1)^2, x^3*y - x^2*y^2 - x*z^3 + y*z^3 + 3*x^2 - 3*x*y)
# Over a prime field: a bivariate stage with recombination, then Hensel lifting
S.<a,b,c> = GF(7)[]
k = (a^2*b - c + 3)*(b*c^2 + a + 1)
(k^2*(a + b)).factor()
(a + b) * (-a^2*b + c - 3)^2 * (b*c^2 + a + 1)^2
# The standard benchmark families (sage.rings.ideal.Cyclic, Katsura)
P = PolynomialRing(QQ, 'x', 4)
sage.rings.ideal.Cyclic(P), sage.rings.ideal.Katsura(P)
(Ideal (x0 + x1 + x2 + x3, x0*x1 + x1*x2 + x0*x3 + x2*x3, x0*x1*x2 + x0*x1*x3 + x0*x2*x3 + x1*x2*x3, x0*x1*x2*x3 - 1) of Multivariate Polynomial Ring in x0, x1, x2, x3 over Rational Field, Ideal (x0 + 2*x1 + 2*x2 + 2*x3 - 1, x0^2 + 2*x1^2 + 2*x2^2 + 2*x3^2 - x0, 2*x0*x1 + 2*x1*x2 + 2*x2*x3 - x1, x1^2 + 2*x0*x2 + 2*x1*x3 - x2) of Multivariate Polynomial Ring in x0, x1, x2, x3 over Rational Field)
# Gröbner bases by F4 over GF(32003): the number of elements of each reduced basis
def basis_size(I):
    return len(I.groebner_basis())
for n in [5, 6, 7]:
    print('cyclic-%d' % n, basis_size(sage.rings.ideal.Cyclic(PolynomialRing(GF(32003), 'x', n))))
for n in [6, 7]:
    print('katsura-%d' % n, basis_size(sage.rings.ideal.Katsura(PolynomialRing(GF(32003), 'x', n + 1))))
cyclic-5 20
cyclic-6 45
cyclic-7 209
katsura-6 41
katsura-7 74
# Over QQ: one F4 run over QQ, each matrix reduced modulo primes < 2^31 and
# reconstructed (CRT, rational reconstruction); then, Sage's proof.polynomial()
# being on, a proof that all S-pairs reduce to 0 (a certificate from more
# eliminations modulo primes and a size bound; natively on all cores)
for n in [5, 6]:
    print('cyclic-%d' % n, basis_size(sage.rings.ideal.Cyclic(PolynomialRing(QQ, 'x', n))))
for n in [5, 6, 7]:
    print('katsura-%d' % n, basis_size(sage.rings.ideal.Katsura(PolynomialRing(QQ, 'x', n + 1))))
cyclic-5 20
cyclic-6 45
katsura-5 22
katsura-6 41
katsura-7 74
# proof.polynomial(False) skips the exact check (as Magma does): the basis is then
# wrong only if a reconstruction was accepted too early (each has two primes to spare)
with proof.WithProof('polynomial', False):
    print('cyclic-7', basis_size(sage.rings.ideal.Cyclic(PolynomialRing(QQ, 'x', 7))))
    print('katsura-7', basis_size(sage.rings.ideal.Katsura(PolynomialRing(QQ, 'x', 8))))
cyclic-7 209
katsura-7 74
# Lex bases of zero-dimensional ideals: the degrevlex basis by F4, then FGLM
# (linear algebra in the quotient); katsura-8's eliminant has degree 2^8
for n, K in [(8, GF(32003)), (5, QQ)]:
    B = sage.rings.ideal.Katsura(PolynomialRing(K, 'x', n + 1, order='lex')).groebner_basis()
    print('katsura-%d over %s:' % (n, K), len(B), 'elements, eliminant of degree', B[-1].degree())
katsura-8 over Finite Field of size 32003: 9 elements, eliminant of degree 256
katsura-5 over Rational Field: 6 elements, eliminant of degree 32
# A lexicographic basis and the points
T.<x,y,z> = PolynomialRing(QQ, order='lex')
J = T.ideal(x^2 + y*z - 2, y^2 - x*z + 1, z^2 - x*y - 3)
J.groebner_basis()[-1]
z^8 - 15/2*z^6 + 83/4*z^4 - 113/4*z^2 + 121/8
U.<u,v> = QQ[]
U.ideal((u - 2)*(u + 3)*(u - 5), v*(v - 1)).variety()
[{v: 1, u: 5}, {v: 1, u: 2}, {v: 1, u: -3}, {v: 0, u: 5}, {v: 0, u: 2}, {v: 0, u: -3}]

Files

Open the ZIP's notebook in Sagebrush (File, Open) to run and change it.