Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Laurent polynomials, Fitting ideals and characteristic varieties #36368

Merged
merged 58 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
27c60d7
add is_noetherian and divides, for univariate
enriqueartal Sep 20, 2023
e4e3ced
.
enriqueartal Sep 20, 2023
df7ed6f
divides
enriqueartal Sep 20, 2023
28530fb
avoid non integral domains
enriqueartal Sep 21, 2023
fe8dbac
typo in __contains__
enriqueartal Sep 22, 2023
e798529
reduction of matrices of Laurent polynomials
enriqueartal Sep 22, 2023
97bd76c
import identity
enriqueartal Sep 22, 2023
2888c7b
doctests
enriqueartal Sep 22, 2023
9817b91
homogeneize __reduce__ for uni- and multi-variate Laurent polynomials
enriqueartal Sep 23, 2023
5591d6c
style
enriqueartal Sep 23, 2023
040d9ec
change __reduce__ again to avoid further errors
enriqueartal Sep 23, 2023
c68a651
merge
enriqueartal Sep 25, 2023
fdcfe1c
merge
enriqueartal Sep 25, 2023
04f314a
merge
enriqueartal Sep 25, 2023
0f631cd
Merge branch 'laurent' of github.com:enriqueartal/sage into laurent
enriqueartal Sep 26, 2023
da769a9
Merge branch 'sagemath:develop' into laurent
enriqueartal Sep 28, 2023
905d042
class of matrices of Laurent mpolynomials
enriqueartal Sep 28, 2023
df401b2
use fitting_ideals for characteristic varieties
enriqueartal Sep 28, 2023
68a94e5
adding xgcd, etc, for laurent polynomials in one variable
enriqueartal Sep 28, 2023
8da8781
cut characteristic varieties when the total ideal is reached
enriqueartal Sep 28, 2023
1153822
trailing spaces
enriqueartal Sep 28, 2023
cbcc182
redefine gens_reduced and more doctests
enriqueartal Sep 29, 2023
fbb77c4
sum of ideals
enriqueartal Sep 29, 2023
5673481
change hint definition
enriqueartal Sep 30, 2023
9e9185c
undo format changes for finitely_presented.py
enriqueartal Oct 1, 2023
b498b59
undo format changes for matrix2.pyx
enriqueartal Oct 1, 2023
d22015c
undo format changes for matrix_mpolynomial_dense.pyx
enriqueartal Oct 1, 2023
53c99d2
undo format changes for matrix_mpolynomial_dense.pyx and laurent_poly…
enriqueartal Oct 1, 2023
e5664d7
undo format changes for laurent_polynomial_ideal.py
enriqueartal Oct 1, 2023
7285ecc
undo format changes for laurent_polynomial_mpair.pyx
enriqueartal Oct 1, 2023
61ea6e8
undo format changes for laurent_polynomial_ring.py
enriqueartal Oct 1, 2023
16ce3c7
undo format changes for laurent_polynomial_ring_base.py
enriqueartal Oct 1, 2023
7bfdabf
undo format changes for polynomial_element.pyx
enriqueartal Oct 1, 2023
5f215be
undo format changes for matrix_space.py
enriqueartal Oct 1, 2023
be6667e
Merge branch 'sagemath:develop' into laurent
enriqueartal Oct 8, 2023
2a24465
after first review
enriqueartal Oct 10, 2023
cc813a0
changes in divides
enriqueartal Oct 10, 2023
d68f6a5
trick to solve the hint issue
enriqueartal Oct 13, 2023
9913cdb
Merge branch 'sagemath:develop' into laurent
enriqueartal Oct 15, 2023
fe045a2
descripion of Laurent matrix class
enriqueartal Oct 16, 2023
59e7c09
tests polynomial ideal
enriqueartal Oct 17, 2023
d89c451
Merge branch 'sagemath:develop' into laurent
enriqueartal Oct 21, 2023
01977ca
changes from revision october 23rd
enriqueartal Oct 23, 2023
314c4bb
change position of conditional in divides
enriqueartal Oct 23, 2023
72a36de
revision october 24th
enriqueartal Oct 24, 2023
146508e
forgot to push polynomial_element.pyx
enriqueartal Oct 24, 2023
c0d70fd
Merge branch 'sagemath:develop' into laurent
enriqueartal Oct 31, 2023
d1e90b9
more doctests
enriqueartal Nov 2, 2023
4ef2883
doctests for change_ring in ideal_py and __contains_ in laurent_polyn…
enriqueartal Nov 2, 2023
7030a05
change in monomial_reduction
enriqueartal Nov 2, 2023
650e060
some cases missing in characteristic varieties
enriqueartal Nov 3, 2023
d6a44f7
Merge branch 'sagemath:develop' into laurent
enriqueartal Nov 6, 2023
d3767f0
corrections from review
enriqueartal Nov 7, 2023
b69e449
Merge branch 'sagemath:develop' into laurent
enriqueartal Nov 10, 2023
488fdc0
Merge branch 'sagemath:develop' into laurent
enriqueartal Nov 12, 2023
942ef1d
Merge branch 'sagemath:develop' into laurent
enriqueartal Nov 15, 2023
ebdf776
Merge branch 'sagemath:develop' into laurent
enriqueartal Nov 18, 2023
e14d69a
Merge branch 'sagemath:develop' into laurent
enriqueartal Dec 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 94 additions & 42 deletions src/sage/groups/finitely_presented.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@
from sage.sets.set import Set
from sage.structure.unique_representation import UniqueRepresentation


class GroupMorphismWithGensImages(SetMorphism):
r"""
Class used for morphisms from finitely presented groups to
Expand Down Expand Up @@ -1702,12 +1703,18 @@ def abelian_alexander_matrix(self, ring=QQ, simplified=True):
sage: g = FreeGroup(1) / []
sage: g.abelian_alexander_matrix()
([], [])
sage: g.abelian_alexander_matrix()[0].base_ring()
Univariate Laurent Polynomial Ring in f1 over Rational Field
sage: g = FreeGroup(0) / []
sage: g.abelian_alexander_matrix()
([], [])
sage: A, ideal = g.abelian_alexander_matrix(); A
[]
sage: A.base_ring()
Rational Field
"""
ab, R, ideal, images = self.abelianization_to_algebra(ring=ring)
A = self.alexander_matrix(im_gens=images)
if A.base_ring() != R:
A = A.change_ring(R)
if simplified:
n, m = A.dimensions()
if n == 0 or m == 0:
Expand Down Expand Up @@ -1761,66 +1768,111 @@ def characteristic_varieties(self, ring=QQ, matrix_ideal=None, groebner=False):

OUTPUT:

If ``groebner`` is ``False`` a list of ideals defining the characteristic varieties.
If it is ``True``, a list of lists for Gröbner bases for each ideal.
A dictionary with keys the indices of the varieties. If ``groebner`` is ``False``
the values are the ideals defining the characteristic varieties.
If it is ``True``, lists for Gröbner bases for the ideal of each irreducible
component, stopping when the first time a characteristic variety is empty.

EXAMPLES::

sage: L = [2*(i, j) + 2* (-i, -j) for i, j in ((1, 2), (2, 3), (3, 1))]
sage: G = FreeGroup(3) / L
sage: G.characteristic_varieties(groebner=True)
[[(f1 - 1, f2 - 1, f3 - 1),
(f1 + 1, f2 - 1, f3 - 1),
(f1 - 1, f2 - 1, f3 + 1),
(f3^2 + 1, f1 - f3, f2 - f3),
(f1 - 1, f2 + 1, f3 - 1)],
[(f1 - 1, f2 - 1, f3 - 1),
(f1*f3 + 1, f2 - 1),
(f1*f2 + 1, f3 - 1),
(f2*f3 + 1, f1 - 1),
(f2*f3 + 1, f1 - f2),
(f2*f3 + 1, f1 - f3),
(f1*f3 + 1, f2 - f3)]]
{0: [(0,)],
1: [(f1 - 1, f2 - 1, f3 - 1), (f1*f3 + 1, f2 - 1), (f1*f2 + 1, f3 - 1), (f2*f3 + 1, f1 - 1),
(f2*f3 + 1, f1 - f2), (f2*f3 + 1, f1 - f3), (f1*f3 + 1, f2 - f3)],
2: [(f1 - 1, f2 - 1, f3 - 1), (f1 + 1, f2 - 1, f3 - 1), (f1 - 1, f2 - 1, f3 + 1),
(f3^2 + 1, f1 - f3, f2 - f3), (f1 - 1, f2 + 1, f3 - 1)],
3: [(f1 - 1, f2 - 1, f3 - 1)],
4: []}
sage: G = FreeGroup(2)/[2*(1,2,-1,-2)]
sage: G.characteristic_varieties()
[Ideal (-2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field]
{0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
1: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field,
3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Rational Field}
sage: G.characteristic_varieties(ring=ZZ)
[Ideal (-2*f2 + 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring]
{0: Ideal (0) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
1: Ideal (2*f2 - 2, 2*f1 - 2) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
2: Ideal (f2 - 1, f1 - 1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring,
3: Ideal (1) of Multivariate Laurent Polynomial Ring in f1, f2 over Integer Ring}
sage: G = FreeGroup(2)/[(1,2,1,-2,-1,-2)]
sage: G.characteristic_varieties()
[Ideal (1 - f2 + f2^2, -1 + f2 - f2^2) of Univariate Laurent Polynomial Ring in f2 over Rational Field]
{0: Ideal (0) of Univariate Laurent Polynomial Ring in f2 over Rational Field,
1: Ideal (-1 + 2*f2 - 2*f2^2 + f2^3) of Univariate Laurent Polynomial Ring in f2 over Rational Field,
2: Ideal (1) of Univariate Laurent Polynomial Ring in f2 over Rational Field}
sage: G.characteristic_varieties(groebner=True)
{0: [0], 1: [-1 + f2, 1 - f2 + f2^2], 2: []}
sage: G = FreeGroup(2)/[3 * (1, ), 2 * (2, )]
sage: G.characteristic_varieties(groebner=True)
[[1 - f2 + f2^2]]
{0: [-1 + F1, 1 + F1, 1 - F1 + F1^2, 1 + F1 + F1^2], 1: [1 - F1 + F1^2], 2: []}
sage: G = FreeGroup(2)/[2 * (2, )]
sage: G.characteristic_varieties(groebner=True)
{0: [(f1 + 1,), (f1 - 1,)], 1: [(f1 + 1,), (f1 - 1, f2 - 1)], 2: []}
sage: G = (FreeGroup(0) / [])
sage: G.characteristic_varieties()
{0: Principal ideal (0) of Rational Field,
1: Principal ideal (1) of Rational Field}
sage: G.characteristic_varieties(groebner=True)
{0: [(0,)], 1: [(1,)]}
"""
A, ideal = self.abelian_alexander_matrix(ring=ring, simplified=True)
if self.ngens() == 0:
if groebner:
return {j: [(ring(j),)] for j in (0, 1)}
return {j: ring.ideal(j) for j in (0, 1)}
A, rels = self.abelian_alexander_matrix(ring=ring, simplified=True)
R = A.base_ring()
res = []
eval_1 = {x: ring(1) for x in R.gens()}
A_scalar = A.apply_map(lambda p: p.subs(eval_1))
n = A.ncols()
n1 = n - A_scalar.rank()
ideal_1 = R.ideal([x - 1 for x in R.gens()])
S = R.polynomial_ring()
ideal = [S(elt) for elt in ideal]
for j in range(1, A.ncols()):
L = [p.monomial_reduction()[0] for p in A.minors(j)]
J = R.ideal(L + ideal)
res.append(J)
if not groebner or not R.base_ring().is_field():
K = R.base_ring()
id_rels = R.ideal(rels)
res = dict()
bound = n + 1
for j in range(bound + 1):
J = id_rels + A.fitting_ideal(j)
# J = R.ideal(id_rels.gens() + A.fitting_ideal(j).gens())
if j <= n1:
J1 = K.ideal([K(p.subs(eval_1)) for p in J.gens()])
if J1:
J *= ideal_1
res[j] = R.ideal(J.gens_reduced())
if R(1) in res[j].gens():
bound = j
break
if not groebner or not ring.is_field():
return res
if R.ngens() == 1:
res0 = [gcd(S(p) for p in J.gens()) for J in res]
res1 = []
for p in res0:
if p == 0:
res1.append([R(0)])
res = {j: gcd(S(p) for p in res[j].gens()) for j in range(bound + 1)}
char_var = dict()
strict = True
j = 0
while strict and j <= bound:
if res[j] == 0:
char_var[j] = [R(0)]
else:
fct = [q[0] for q in R(p).factor()]
fct = [q[0] for q in R(res[j]).factor()]
if fct:
res1.append(fct)
return res1
res1 = []
for J in res:
LJ = J.minimal_associated_primes()
char_var[j] = fct
else:
char_var[j] = []
strict = False
j += 1
return char_var
char_var = dict()
strict = True
j = 0
while strict and j <= bound:
LJ = res[j].minimal_associated_primes()
fct = [id.groebner_basis() for id in LJ]
if fct != [(S.one(),)]:
res1.append(fct)
return res1
char_var[j] = fct
if not fct:
strict = False
j += 1
return char_var

def rewriting_system(self):
"""
Expand Down
4 changes: 4 additions & 0 deletions src/sage/matrix/matrix_laurent_mpolynomial_dense.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from sage.matrix.matrix_generic_dense cimport Matrix_generic_dense

cdef class Matrix_Laurent_mpolynomial_dense(Matrix_generic_dense):
pass
114 changes: 114 additions & 0 deletions src/sage/matrix/matrix_laurent_mpolynomial_dense.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""
Dense matrices over multivariate polynomials over fields.

AUTHOR:

- Enrique Artal (2023-??): initial version
"""

# *****************************************************************************
# Copyright (C) 2023 Enrique Artal <artal@unizar.es>
#
# Distributed under the terms of the GNU General Public License (GPL)
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# https://www.gnu.org/licenses/
# *****************************************************************************
from sage.matrix.constructor import identity_matrix
from sage.rings.polynomial.laurent_polynomial_ring_base import LaurentPolynomialRing_generic

cdef class Matrix_laurent_mpolynomial_dense(Matrix_generic_dense):
enriqueartal marked this conversation as resolved.
Show resolved Hide resolved
"""
Dense matrix over a Laurent multivariate polynomial ring over a field.
"""
def laurent_matrix_reduction(self):
"""
From a matrix `self` of Laurent polynomials, apply elementary operations
to obtain a matrix `P` of polynomials such that the variables do not divide
no column and no row.

OUTPUT:

Three matrices `L`, `P`, `R` such that ``self` equals `L P R`, where `L` and
`R` are diagonal with monomial entries.

EXAMPLES:

sage: R.<x, y> = LaurentPolynomialRing(QQ)
sage: L = [1/3*x^-1*y - 6*x^-2*y^2 - 1/2*x^-2*y, 1/5*x + 1/2*y + 1/6]
sage: L += [1/2 - 5*x^-1*y - 2*x^-1, -1/3*y^-2 - 4*x^-1*y^-1 + 11*x^-1*y^-2]
sage: A = matrix(R, 2, L)
sage: lf, P, rg = A.laurent_matrix_reduction()
sage: lf
[ x^-2 0]
[ 0 x^-1*y^-2]
sage: P
[ 1/3*x - 6*y - 1/2 1/5*x^3 + 1/2*x^2*y + 1/6*x^2]
[ 1/2*x*y - 5*y^2 - 2*y -1/3*x - 4*y + 11]
sage: rg
[y 0]
[0 1]
"""
R = self.base_ring()
n_rows, n_cols = self.dimensions()
mat_l = identity_matrix(R, n_rows)
mat_r = identity_matrix(R, n_cols)
res = self.__copy__()
for j, rw in enumerate(res.rows()):
for t in R.gens():
n = min(mon.degree(t) for a in rw for cf, mon in a)
res.rescale_row(j, t ** -n)
mat_l.rescale_col(j, t ** n)
for j, cl in enumerate(res.columns()):
for t in R.gens():
n = min(mon.degree(t) for a in cl for cf, mon in a)
res.rescale_col(j, t ** -n)
mat_r.rescale_row(j, t ** n)
res = res.change_ring(R.polynomial_ring())
return mat_l, res, mat_r

def _fitting_ideal(self, i):
r"""
Return the `i`-th Fitting ideal of the matrix. This is the ideal generated
by the `n - i` minors, where `n` is the number of columns.

INPUT:

``i`` -- an integer

OUTPUT:

An ideal on the base ring.

EXAMPLES::

sage: R.<x,y,z> = LaurentPolynomialRing(QQ)
sage: M = matrix(R, [[2*x^-1-z, 0, y-z^-2, 0], [0, z - y^-1, z - x, 0],[z - y, x^-2 - y, 0, z]])
sage: M
[-z + 2*x^-1 0 y - z^-2 0]
[ 0 z - y^-1 -x + z 0]
[ -y + z -y + x^-2 0 z]
sage: M.fitting_ideal(0)
Ideal (0) of Multivariate Laurent Polynomial Ring in x, y, z over Rational Field
sage: M.fitting_ideal(1) == M._fitting_ideal(1)
True
sage: M.fitting_ideal(1).groebner_basis()
(x^4 - 2*x^3*y - x*z^3 - 4*x^2*y + 8*x*y^2 + 4*x*y*z + 2*z^2 - 8*y,
x*y*z^2 - x*z - 2*y*z + 2,
x^2*z - x*z^2 - 2*x + 2*z,
y^2*z + 1/4*x^2 - 1/2*x*y - 1/4*x*z - y + 1/2)
sage: M.fitting_ideal(2).groebner_basis()
(1,)
sage: M.fitting_ideal(3).groebner_basis()
(1,)
sage: M.fitting_ideal(4).groebner_basis()
(1,)
sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)]
[True, True, True, True, True]

"""
R = self.base_ring()
S = R.polynomial_ring()
A = self.laurent_matrix_reduction()[1].change_ring(S)
J = A._fitting_ideal(i)
return J.change_ring(R)
7 changes: 7 additions & 0 deletions src/sage/matrix/matrix_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,13 @@
pass
else:
return matrix_mpolynomial_dense.Matrix_mpolynomial_dense
elif isinstance(R, sage.rings.polynomial.laurent_polynomial_ring.LaurentPolynomialRing_mpair) and R.base_ring() in _Fields:
try:
from . import matrix_laurent_mpolynomial_dense
except ImportError:
pass

Check warning on line 313 in src/sage/matrix/matrix_space.py

View check run for this annotation

Codecov / codecov/patch

src/sage/matrix/matrix_space.py#L312-L313

Added lines #L312 - L313 were not covered by tests
else:
return matrix_laurent_mpolynomial_dense.Matrix_laurent_mpolynomial_dense

# The fallback
from sage.matrix.matrix_generic_dense import Matrix_generic_dense
Expand Down
13 changes: 13 additions & 0 deletions src/sage/rings/polynomial/ideal.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,16 @@ def groebner_basis(self, algorithm=None):
gb = self.gens_reduced()
from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence_generic
return PolynomialSequence_generic([gb], self.ring(), immutable=True)

def change_ring(self, R):
"""
Coerce an ideal into a new ring.

EXAMPLES::

sage: R.<q> = QQ[]
sage: I = R.ideal([q^2+q-1])
sage: I.change_ring(RR['q'])
Principal ideal (q^2 + q - 1.00000000000000) of Univariate Polynomial Ring in q over Real Field with 53 bits of precision
"""
return R.ideal(self.gens())
Loading
Loading