@@ -851,52 +851,49 @@ def coefficient_matrix(self, sparse=True):
851851 A , v = self .coefficients_monomials (sparse = sparse )
852852 return A , matrix (R ,len (v ),1 ,v )
853853
854- def macaulay_matrix (self , degree , remove_zero = False , homogeneous = False , set_variables = None , long_output = False ) :
854+ def macaulay_matrix (self , degree ,
855+ homogeneous = False ,
856+ variables = None ,
857+ return_indices = False ,
858+ remove_zero = False ):
855859 r"""
856860 Return the Macaulay matrix of degree ``degree`` of this sequence
857861 of polynomials.
858862
859863 INPUT:
860864
861865 - ``remove_zero`` -- boolean (default: ``False``);
862- when ``False``, the columns of
863- the Macaulay matrix are all the monomials of the polynomial
864- ring up to degree ``degree``,
865- when ``True``, the columns of the Macaulay matrix are only
866- the monomials that appears effectively in the sequence of
867- polynomials equations
866+ when ``False``, the columns of the Macaulay matrix are all the
867+ monomials of the polynomial ring up to degree ``degree``, when
868+ ``True``, the columns of the Macaulay matrix are only the monomials
869+ that effectively appear in the sequence of polynomials
868870
869871 - ``homogeneous`` -- boolean (default: ``False``);
870- when ``False``, the sequence of equations is not supposed to be
871- homogeneous and the rows of the Macaulay matrix of degree
872- ``degree`` contain all the equations of this sequence of
873- polynomials and all the products between the element of
874- this sequence and the monomials of the polynomial ring up
875- to degree ``degree``
876- when ``True``, the given systemsequence of equations
877- must be homogeneous, and the rows of the Macaulay matrix
878- are the elements of the input sequence of polynomials
879- multiplied by monomials, such that the product is homogeneous
880- of degree: the sum of ``degree`` and maximum
881- degree in this system.
882-
883- - ``set_variables`` -- boolean (default: ``None``);
884- when ``None`` the Macaulay matrix is constructed
885- using all the variables of the base ring of polynomials.
886- when ``set_variables`` is a list of variables (which must
887- be in the parent of the input sequence of polynomials), it is
888- used instead of all the variables of the base ring of polynomials
889- when multiplying the equations of the given sequence.
890-
891- - ``long_output`` -- boolean (default: ``False``);
892- when ``False``, only return the Macaulay matrix
893- when ``True``, return the Macaulay matrix and two lists,
894- the first one is a list of pairs, each pair is the
895- data of a monomial and one of the input polynomials;
896- the product of the elements of a given tuple is the equation
897- describing each row of the matrix
898- the second one is the list of monomials corresponding
899- to the columns of the matrix
872+ when ``False``, the polynomials in the sequence are not necessarily
873+ homogeneous and the rows of the Macaulay matrix represent all
874+ possible products between a polynomial of this sequence and the
875+ monomials of the polynomial ring up to degree ``degree``;
876+ when ``True``, the polynomials in the sequence must be homogeneous,
877+ and the rows of the Macaulay matrix represent all possible products
878+ between a polynomial of this sequence and a monomial of the
879+ polynomial ring such that the product is homogeneous of degree equal
880+ to the sum of ``degree`` and the maximum degree in the sequence
881+
882+ - ``variables`` -- boolean (default: ``None``);
883+ when ``None``, ``variables`` is interpreted as being the list of
884+ all variables of the ring of the polynomials in the sequence;
885+ otherwise ``variables`` is a list describing a subset of these
886+ variables, and only these variables are used (instead of all ring
887+ variables) when forming monomials to multiply the polynomials of the
888+ sequence
889+
890+ - ``return_indices`` -- boolean (default: ``False``);
891+ when ``False``, only return the Macaulay matrix;
892+ when ``True``, return the Macaulay matrix and two lists: the first
893+ one is a list of pairs, each of them containing a monomial and the
894+ index in the sequence of the input polynomial, whose product
895+ describes the corresponding row of the matrix; the second one is the
896+ list of monomials corresponding to the columns of the matrix
900897
901898 EXAMPLES::
902899
@@ -909,7 +906,7 @@ def macaulay_matrix(self, degree, remove_zero=False, homogeneous=False, set_vari
909906 [2 0 0 0 4 1 0 4 0 3]
910907 [6 0 5 0 4 0 3 0 0 0]
911908
912- Example with the option homogeneous::
909+ Example with a sequence of homogeneous polynomials ::
913910
914911 sage: R.<x,y,z> = PolynomialRing(QQ)
915912 sage: L = Sequence([x*y^2 + y^3 + x*y*z + y*z^2,
@@ -926,13 +923,14 @@ def macaulay_matrix(self, degree, remove_zero=False, homogeneous=False, set_vari
926923 [0 1 0 0 2 0 1 2 0 0 0 0 0 2 0]
927924 [1 0 0 2 0 1 2 0 0 0 0 0 2 0 0]
928925
929- Same example as before but with all options
930- activated excepted the ``set_variables`` option::
926+ Same example for which we now ask to remove monomials that do not
927+ appear in the sequence (``remove_zero=True``), and to return the row
928+ and column indices::
931929
932930 sage: R.<x,y,z> = PolynomialRing(QQ)
933931 sage: L = Sequence([x*y + 2*z^2, y^2 + y*z, x*z])
934- sage: L.macaulay_matrix(1, homogeneous=True, remove_zero=True, long_output =True)
935- [
932+ sage: L.macaulay_matrix(1, homogeneous=True, remove_zero=True, return_indices =True)
933+ (
936934 [0 0 0 0 1 0 0 0 2]
937935 [0 1 0 0 0 0 0 2 0]
938936 [1 0 0 0 0 0 2 0 0]
@@ -942,31 +940,29 @@ def macaulay_matrix(self, degree, remove_zero=False, homogeneous=False, set_vari
942940 [0 0 0 0 0 0 1 0 0]
943941 [0 0 0 0 1 0 0 0 0]
944942 [0 0 0 1 0 0 0 0 0],
945- [(z, x*y + 2*z^2), (y, x*y + 2*z^2), (x, x*y + 2*z^2), (z, y^2 + y*z),
946- (y, y^2 + y*z), (x, y^2 + y*z), (z, x*z), (y, x*z), (x, x*z)],
943+ [(z, 0), (y, 0), (x, 0), (z, 1), (y, 1), (x, 1), (z, 2), (y, 2), (x, 2)],
947944 [x^2*y, x*y^2, y^3, x^2*z, x*y*z, y^2*z, x*z^2, y*z^2, z^3]
948- ]
945+ )
949946
950- Example with the ``set_variables`` option::
947+ Example in which we build rows using monomials that involve only a
948+ subset of the ring variables (``variables=['x']``)::
951949
952950 sage: R.<x,y,z> = PolynomialRing(QQ)
953951 sage: L = Sequence([2*y*z - 2*z^2 - 3*x + z - 3,
954952 ....: -3*y^2 + 3*y*z + 2*z^2 - 2*x - 2*y,
955953 ....: -2*y - z - 3])
956- sage: L.macaulay_matrix(1, set_variables =['x'], remove_zero=True, long_output =True)
957- [
954+ sage: L.macaulay_matrix(1, variables =['x'], remove_zero=True, return_indices =True)
955+ (
958956 [ 0 0 0 0 0 0 0 0 0 2 -2 -3 0 1 -3]
959957 [ 0 0 0 2 -2 -3 0 0 1 0 0 -3 0 0 0]
960958 [ 0 0 0 0 0 0 0 -3 0 3 2 -2 -2 0 0]
961959 [ 0 -3 0 3 2 -2 -2 0 0 0 0 0 0 0 0]
962960 [ 0 0 0 0 0 0 0 0 0 0 0 0 -2 -1 -3]
963961 [ 0 0 0 0 0 0 -2 0 -1 0 0 -3 0 0 0]
964962 [-2 0 -1 0 0 -3 0 0 0 0 0 0 0 0 0],
965- [(1, 2*y*z - 2*z^2 - 3*x + z - 3), (x, 2*y*z - 2*z^2 - 3*x + z - 3),
966- (1, -3*y^2 + 3*y*z + 2*z^2 - 2*x - 2*y), (x, -3*y^2 + 3*y*z + 2*z^2 - 2*x - 2*y),
967- (1, -2*y - z - 3), (x, -2*y - z - 3), (x^2, -2*y - z - 3)],
963+ [(1, 0), (x, 0), (1, 1), (x, 1), (1, 2), (x, 2), (x^2, 2)],
968964 [x^2*y, x*y^2, x^2*z, x*y*z, x*z^2, x^2, x*y, y^2, x*z, y*z, z^2, x, y, z, 1]
969- ]
965+ )
970966
971967 TESTS::
972968
@@ -975,55 +971,99 @@ def macaulay_matrix(self, degree, remove_zero=False, homogeneous=False, set_vari
975971 sage: PolynomialSequence_generic([], R).macaulay_matrix(1)
976972 Traceback (most recent call last):
977973 ...
978- TypeError : the list of polynomials must be non empty
974+ ValueError : the sequence of polynomials must be nonempty
979975
980976 sage: Sequence([x*y, x**2]).macaulay_matrix(-1)
981977 Traceback (most recent call last):
982978 ...
983- ValueError: the degree must be a non negative number
979+ ValueError: the degree must be nonnegative
984980
985981 REFERENCES:
986982
987983 [Mac1902]_, Chapter 1 of [Mac1916]_
988984 """
989985 from sage .matrix .constructor import matrix
990986
991- if len (self ) == 0 :
992- raise TypeError ('the list of polynomials must be non empty' )
987+ m = len (self )
988+
989+ # handle unsuitable input
990+ if m == 0 :
991+ raise ValueError ('the sequence of polynomials must be nonempty' )
993992 if degree < 0 :
994- raise ValueError ('the degree must be a non negative number ' )
993+ raise ValueError ('the degree must be nonnegative ' )
995994
995+ # handle subset of variables
996996 S = self .ring ()
997997 F = S .base_ring ()
998- if set_variables is None :
998+ if variables is None :
999999 R = S
10001000 else :
1001- R = PolynomialRing (F , set_variables )
1002-
1003- degree_system = self .maximal_degree ()
1004-
1005- augmented_system = []
1001+ R = PolynomialRing (F , variables )
1002+
1003+ # maximum degree for monomials appearing in considered polynomial multiples
1004+ target_degree = self .maximal_degree () + degree
1005+
1006+ # precompute `monomials_of_degree(deg)` for the relevant values of `deg`
1007+ # homogeneous:
1008+ # row_indices: we need them for deg = target_degree - self[i].degree(),
1009+ # for all i = 0 ... len(self)-1
1010+ # column_indices: we need them for deg = target_degree
1011+ # non homogeneous:
1012+ # row_indices: we need them for deg = 0 ... target_degree - self[i].degree(),
1013+ # for all i = 0 ... len(self)-1,
1014+ # -> i.e. for deg = 0 ... target_degree - min(self[i].degree() for all i)
1015+ # column_indices: we need them for deg = 0 ... target_degree
1016+ R_monomials_of_degree = {}
1017+ S_monomials_of_degree = {}
1018+ if homogeneous :
1019+ for poly_deg in set ([poly .degree () for poly in self ]):
1020+ deg = target_degree - poly_deg
1021+ R_monomials_of_degree [deg ] = R .monomials_of_degree (deg )
1022+ S_monomials_of_degree [target_degree ] = S .monomials_of_degree (target_degree )
1023+ else :
1024+ max_deg = target_degree - min (poly .degree () for poly in self )
1025+ for deg in range (max_deg + 1 ):
1026+ R_monomials_of_degree [deg ] = R .monomials_of_degree (deg )
1027+ for deg in range (target_degree + 1 ):
1028+ S_monomials_of_degree [deg ] = S .monomials_of_degree (deg )
1029+
1030+ # compute list of extended monomials (ring monomials + polynomial position)
1031+ # that will be used to construct the rows
1032+ row_indices = []
10061033 if homogeneous :
1007- for poly in self :
1008- augmented_system += [(mon , poly ) for mon in R .monomials_of_degree (degree_system - poly .degree () + degree )]
1034+ for i in range (m ):
1035+ deg = target_degree - self [i ].degree ()
1036+ row_indices += [(mon , i ) for mon in R_monomials_of_degree [deg ]]
10091037 else :
1010- for poly in self :
1011- for deg in range (degree_system - poly .degree () + degree + 1 ):
1012- augmented_system += [(mon , poly ) for mon in R . monomials_of_degree ( deg ) ]
1038+ for i in range ( m ) :
1039+ for deg in range (target_degree - self [ i ] .degree () + 1 ):
1040+ row_indices += [(mon , i ) for mon in R_monomials_of_degree [ deg ] ]
10131041
1042+ # compute sorted list of monomials that index the columns
10141043 if remove_zero :
1015- monomials_sys = list (set (sum (((mon * poly ).monomials () for mon , poly in augmented_system ), [])))
1044+ # FIXME clean (and refactor multiplications?)
1045+ column_indices = list (set (sum (((mon * self [i ]).monomials () for mon , i in row_indices ), [])))
10161046 else :
10171047 if homogeneous :
1018- monomials_sys = S . monomials_of_degree ( degree_system + degree )
1048+ column_indices = S_monomials_of_degree [ target_degree ]
10191049 else :
1020- monomials_sys = sum ((S .monomials_of_degree (i ) for i in range (degree_system + degree + 1 )), [])
1021-
1022- monomials_sys = list (monomials_sys )
1023- monomials_sys .sort (reverse = True )
1024- macaulay = matrix (F , [[(mon * poly ).monomial_coefficient (m ) for m in monomials_sys ] for mon , poly in augmented_system ])
1025-
1026- return [macaulay , augmented_system , monomials_sys ] if long_output else macaulay
1050+ column_indices = [mon for deg in range (target_degree + 1 )
1051+ for mon in S_monomials_of_degree [deg ]]
1052+ column_indices .sort (reverse = True )
1053+ dict_columns = {mon .exponents ()[0 ] : j for (j , mon ) in enumerate (column_indices )}
1054+
1055+ # actually build the Macaulay matrix
1056+ macaulay_mat = matrix (F , len (row_indices ), len (column_indices ))
1057+ for (ii , (mrow , i )) in enumerate (row_indices ):
1058+ # in row ii, we put coefficients of the multiple mrow * self[i]
1059+ poly = mrow * self [i ]
1060+ for mon , coeff in poly .iterator_exp_coeff ():
1061+ macaulay_mat [ii , dict_columns [mon ]] = coeff
1062+
1063+ if not return_indices :
1064+ return macaulay_mat
1065+ else :
1066+ return macaulay_mat , row_indices , column_indices
10271067
10281068 def subs (self , * args , ** kwargs ):
10291069 """
0 commit comments