@@ -89,6 +89,7 @@ from sage.structure.element cimport have_same_parent
89
89
from sage.misc.verbose import verbose
90
90
from sage.categories.fields import Fields
91
91
from sage.categories.integral_domains import IntegralDomains
92
+ from sage.categories.principal_ideal_domains import PrincipalIdealDomains
92
93
from sage.rings.ring import is_Ring
93
94
from sage.rings.number_field.number_field_base import NumberField
94
95
from sage.rings.integer_ring import ZZ, is_IntegerRing
@@ -102,6 +103,8 @@ from . import berlekamp_massey
102
103
from sage.modules.free_module_element import is_FreeModuleElement
103
104
from sage.matrix.matrix_misc import permanental_minor_polynomial
104
105
106
+ from sage.misc.misc_c import prod
107
+
105
108
# used to deprecate only adjoint method
106
109
from sage.misc.superseded import deprecated_function_alias
107
110
@@ -15902,6 +15905,135 @@ cdef class Matrix(Matrix1):
15902
15905
else:
15903
15906
return dp
15904
15907
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
+
15905
16037
def _hermite_form_euclidean(self, transformation=False, normalization=None):
15906
16038
"""
15907
16039
Transform the matrix in place to hermite normal form and optionally
0 commit comments