Skip to content

Commit c7931be

Browse files
committed
Generic implementation of fitting ideal, and specific _fitting_ideal for MPolynomialRing
1 parent 4103129 commit c7931be

File tree

2 files changed

+197
-1
lines changed

2 files changed

+197
-1
lines changed

src/sage/matrix/matrix2.pyx

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ from sage.structure.element cimport have_same_parent
8989
from sage.misc.verbose import verbose
9090
from sage.categories.fields import Fields
9191
from sage.categories.integral_domains import IntegralDomains
92+
from sage.categories.principal_ideal_domains import PrincipalIdealDomains
9293
from sage.rings.ring import is_Ring
9394
from sage.rings.number_field.number_field_base import NumberField
9495
from sage.rings.integer_ring import ZZ, is_IntegerRing
@@ -102,6 +103,8 @@ from . import berlekamp_massey
102103
from sage.modules.free_module_element import is_FreeModuleElement
103104
from sage.matrix.matrix_misc import permanental_minor_polynomial
104105

106+
from sage.misc.misc_c import prod
107+
105108
# used to deprecate only adjoint method
106109
from sage.misc.superseded import deprecated_function_alias
107110

@@ -15902,6 +15905,135 @@ cdef class Matrix(Matrix1):
1590215905
else:
1590315906
return dp
1590415907

15908+
def fitting_ideal(self, i):
15909+
r"""
15910+
Return the `i`-th Fitting ideal of the matrix. This is the ideal generated
15911+
by the `n - i` minors, where `n` is the number of columns.
15912+
15913+
INPUT:
15914+
15915+
``i`` -- an integer
15916+
15917+
OUTPUT:
15918+
15919+
An ideal on the base ring.
15920+
15921+
EXAMPLES::
15922+
15923+
sage: R.<x,y,z> = QQ[]
15924+
sage: M = matrix(R, [[2*x-z, 0, y-z^2, 1], [0, z - y, z - x, 0],[z - y, x^2 - y, 0, 0]])
15925+
sage: M
15926+
[ 2*x - z 0 -z^2 + y 1]
15927+
[ 0 -y + z -x + z 0]
15928+
[ -y + z x^2 - y 0 0]
15929+
sage: [R.ideal(M.minors(i)) == M.fitting_ideal(4-i) for i in range(5)]
15930+
[True, True, True, True, True]
15931+
sage: M.fitting_ideal(0)
15932+
Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field
15933+
sage: M.fitting_ideal(1)
15934+
Ideal (2*x^4 - 3*x^3*z + x^2*z^2 + y^2*z^2 - 2*y*z^3 + z^4 - 2*x^2*y - y^3 + 3*x*y*z + 2*y^2*z - 2*y*z^2, -x^3 + x^2*z + x*y - y*z, y^2 - 2*y*z + z^2, x*y - x*z - y*z + z^2) of Multivariate Polynomial Ring in x, y, z over Rational Field
15935+
sage: M.fitting_ideal(3)
15936+
Ideal (2*x - z, -z^2 + y, 1, -y + z, -x + z, -y + z, x^2 - y) of Multivariate Polynomial Ring in x, y, z over Rational Field
15937+
sage: M.fitting_ideal(4)
15938+
Ideal (1) of Multivariate Polynomial Ring in x, y, z over Rational Field
15939+
15940+
15941+
If the base ring is a field, the Fitting ideals are zero under the corank::
15942+
15943+
sage: M = matrix(QQ, [[2,1,3,5],[4,2,6,6],[0,3,2,0]])
15944+
sage: M
15945+
[2 1 3 5]
15946+
[4 2 6 6]
15947+
[0 3 2 0]
15948+
sage: M.fitting_ideal(0)
15949+
Principal ideal (0) of Rational Field
15950+
sage: M.fitting_ideal(1)
15951+
Principal ideal (1) of Rational Field
15952+
sage: M.fitting_ideal(2)
15953+
Principal ideal (1) of Rational Field
15954+
sage: M.fitting_ideal(3)
15955+
Principal ideal (1) of Rational Field
15956+
sage: M.fitting_ideal(4)
15957+
Principal ideal (1) of Rational Field
15958+
15959+
15960+
In the case of principal ideal domains, it is given by the elementary
15961+
divisors::
15962+
15963+
sage: M = matrix([[2,1,3,5],[4,2,6,6],[0,3,2,0]])
15964+
sage: M
15965+
[2 1 3 5]
15966+
[4 2 6 6]
15967+
[0 3 2 0]
15968+
sage: M.fitting_ideal(0)
15969+
Principal ideal (0) of Integer Ring
15970+
sage: M.fitting_ideal(1)
15971+
Principal ideal (4) of Integer Ring
15972+
sage: M.fitting_ideal(2)
15973+
Principal ideal (1) of Integer Ring
15974+
sage: M.fitting_ideal(3)
15975+
Principal ideal (1) of Integer Ring
15976+
sage: M.fitting_ideal(4)
15977+
Principal ideal (1) of Integer Ring
15978+
sage: M.elementary_divisors()
15979+
[1, 1, 4]
15980+
15981+
"""
15982+
R = self.base_ring()
15983+
if not R.is_exact():
15984+
raise NotImplementedError("Fitting ideals over non-exact rings not implemented at present")
15985+
n = self.ncols()
15986+
rank = n - i
15987+
if rank > self.nrows():
15988+
return R.ideal([R.zero()])
15989+
elif rank <= 0:
15990+
return R.ideal([R.one()])
15991+
elif rank == 1:
15992+
return R.ideal(self.coefficients())
15993+
if R in _Fields:
15994+
if self.rank() >= rank:
15995+
return R.ideal([1])
15996+
else:
15997+
return R.ideal([0])
15998+
try:
15999+
elemdiv = self.elementary_divisors()
16000+
if rank > len(elemdiv):
16001+
return R.ideal([0])
16002+
return R.ideal(prod(elemdiv[:rank]))
16003+
except (TypeError, NotImplementedError, ArithmeticError):
16004+
pass
16005+
for (nr,r) in enumerate(self.rows()):
16006+
nz = [e for e in enumerate(r) if e[1]]
16007+
if len(nz) == 0:
16008+
N = self.delete_rows([nr])
16009+
return N.fitting_ideal(i)
16010+
elif len(nz) == 1:
16011+
N = self.delete_rows([nr])
16012+
F1 = N.fitting_ideal(i)
16013+
N = N.delete_columns([nz[0][0]])
16014+
F2 = N.fitting_ideal(i)
16015+
return F1 + nz[0][1]*F2
16016+
for (nc,c) in enumerate(self.columns()):
16017+
nz = [e for e in enumerate(c) if e[1]]
16018+
if len(nz) == 0:
16019+
N = self.delete_columns([nc])
16020+
return N._fitting_ideal(i - 1)
16021+
elif len(nz) == 1:
16022+
N = self.delete_columns([nc])
16023+
F1 = N.fitting_ideal(i-1)
16024+
N = N.delete_rows([nz[0][0]])
16025+
F2 = N.fitting_ideal(i)
16026+
return F1 + nz[0][1]*F2
16027+
if hasattr(self, '_fitting_ideal'):
16028+
try:
16029+
return self._fitting_ideal(i)
16030+
except NotImplementedError:
16031+
pass
16032+
else:
16033+
return R.ideal(self.minors(rank))
16034+
16035+
16036+
1590516037
def _hermite_form_euclidean(self, transformation=False, normalization=None):
1590616038
"""
1590716039
Transform the matrix in place to hermite normal form and optionally

src/sage/matrix/matrix_mpolynomial_dense.pyx

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ from sage.matrix.matrix2 cimport Matrix
2323
from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomialRing_libsingular
2424
from sage.rings.polynomial.polynomial_singular_interface import can_convert_to_singular
2525

26-
from sage.libs.singular.function import singular_function
26+
from sage.libs.singular.function import singular_function, lib
27+
28+
from cysignals.signals cimport sig_on, sig_off
2729

2830

2931
cdef class Matrix_mpolynomial_dense(Matrix_generic_dense):
@@ -451,6 +453,68 @@ cdef class Matrix_mpolynomial_dense(Matrix_generic_dense):
451453
"""
452454
return self.fetch('swapped_columns')
453455

456+
def _fitting_ideal(self, i):
457+
r"""
458+
Return the `i`-th Fitting ideal of the matrix. This is the ideal generated
459+
by the `n - i` minors, where `n` is the number of columns.
460+
461+
INPUT:
462+
463+
``i`` -- an integer
464+
465+
OUTPUT:
466+
467+
An ideal on the base ring.
468+
469+
EXAMPLES::
470+
471+
sage: R.<x,y,z> = QQ[]
472+
sage: M = matrix(R, [[2*x-z, 0, y-z^2, 0], [0, z - y, z - x, 0],[z - y, x^2 - y, 0, z]])
473+
sage: M
474+
[ 2*x - z 0 -z^2 + y 0]
475+
[ 0 -y + z -x + z 0]
476+
[ -y + z x^2 - y 0 z]
477+
sage: M.fitting_ideal(0)
478+
Ideal (0) of Multivariate Polynomial Ring in x, y, z over Rational Field
479+
sage: M.fitting_ideal(1)
480+
Ideal (2*x^4 - 3*x^3*z + x^2*z^2 + y^2*z^2 - 2*y*z^3 + z^4 - 2*x^2*y - y^3 + 3*x*y*z + 2*y^2*z - 2*y*z^2, y*z^3 - z^4 - y^2*z + y*z^2, -2*x*y*z + 2*x*z^2 + y*z^2 - z^3, -2*x^2*z + 3*x*z^2 - z^3) of Multivariate Polynomial Ring in x, y, z over Rational Field
481+
sage: M.fitting_ideal(2)
482+
Ideal (-x^3 + x^2*z + x*y - y*z, -y^2 + 2*y*z - z^2, -x^2*z^2 + x^2*y + y*z^2 - y^2, 2*x^3 - x^2*z - 2*x*y + y*z, -x*y + x*z + y*z - z^2, -y*z^2 + z^3 + y^2 - y*z, -2*x*y + 2*x*z + y*z - z^2, y*z^2 - z^3 - y^2 + y*z, 2*x^2 - 3*x*z + z^2, 2*x*z - z^2, -z^3 + y*z, -y*z + z^2, -x*z + z^2) of Multivariate Polynomial Ring in x, y, z over Rational Field
483+
sage: M.fitting_ideal(3)
484+
Ideal (2*x - z, -z^2 + y, -y + z, -x + z, -y + z, x^2 - y, z) of Multivariate Polynomial Ring in x, y, z over Rational Field
485+
sage: M.fitting_ideal(4)
486+
Ideal (1) of Multivariate Polynomial Ring in x, y, z over Rational Field
487+
sage: [R.ideal(M.minors(i)) == M._fitting_ideal(4 - i) for i in range(5)]
488+
[True, True, True, True, True]
489+
490+
"""
491+
minor = singular_function("minor")
492+
R = self.base_ring()
493+
for (nrow, row) in enumerate(self.rows()):
494+
if not row:
495+
N = self.delete_rows([nrow])
496+
return N._fitting_ideal(i)
497+
for (ncoef, coef) in enumerate(row):
498+
if all(coef.divides(f) for f in row):
499+
N = self.__copy__()
500+
for j in range(self.ncols()):
501+
if j != ncoef:
502+
N.add_multiple_of_column(j, ncoef, -R(self[nrow,j] / coef))
503+
return N.fitting_ideal(i)
504+
for (ncolumn, column) in enumerate(self.columns()):
505+
if not column:
506+
N = self.delete_columns([ncolumn])
507+
return N._fitting_ideal(i-1)
508+
for (ncoef, coef) in enumerate(column):
509+
if all(coef.divides(f) for f in column):
510+
N = self.__copy__()
511+
for j in range(self.nrows()):
512+
if j != ncoef:
513+
N.add_multiple_of_row(j, ncoef, -R(self[j, ncolumn] / coef))
514+
return N.fitting_ideal(i)
515+
rank = self.ncols() - i
516+
return R.ideal(minor(self, rank))
517+
454518
def determinant(self, algorithm=None):
455519
"""
456520
Return the determinant of this matrix

0 commit comments

Comments
 (0)