Skip to content

Commit d8f4de4

Browse files
Merge pull request #1 from vneiger/macaulay_matrix
Macaulay matrix
2 parents 0bc2513 + 8496a77 commit d8f4de4

File tree

2 files changed

+118
-78
lines changed

2 files changed

+118
-78
lines changed

src/sage/rings/polynomial/multi_polynomial_sequence.py

Lines changed: 117 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -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
"""

src/sage/rings/polynomial/polynomial_ring.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ def monomials_of_degree(self, degree):
630630
degree in this univariate polynomial ring, which is simply the list with one element ``[self.gen()**degree]``.
631631
632632
.. SEEALSO::
633-
633+
634634
:meth:`sage.rings.polynomial.multi_polynomial_ring_base.MPolynomialRing_base.monomials_of_degree`
635635
636636
EXAMPLES::

0 commit comments

Comments
 (0)