From f0604bdabdea49d78d8312615b3722f4566702b4 Mon Sep 17 00:00:00 2001 From: Markus Wageringel Date: Thu, 30 Apr 2020 20:49:45 +0200 Subject: [PATCH] 29625: support weighted term orders in normal_basis --- .../polynomial/multi_polynomial_ideal.py | 49 ++++++++++++++++--- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/sage/rings/polynomial/multi_polynomial_ideal.py b/src/sage/rings/polynomial/multi_polynomial_ideal.py index cc587596dd3..35c2374fbcb 100644 --- a/src/sage/rings/polynomial/multi_polynomial_ideal.py +++ b/src/sage/rings/polynomial/multi_polynomial_ideal.py @@ -2888,7 +2888,7 @@ def hilbert_numerator(self, grading = None, algorithm = 'sage'): raise ValueError("'algorithm' must be one of 'sage' or 'singular'") @require_field - def _normal_basis_libsingular(self, degree): + def _normal_basis_libsingular(self, degree, weights=None): r""" Return the normal basis for a given Groebner basis. @@ -2899,6 +2899,9 @@ def _normal_basis_libsingular(self, degree): - ``degree`` -- ``None`` or integer + - ``weights`` -- tuple of positive integers (default: ``None``); if not + ``None``, compute the degree with respect to these weights + OUTPUT: If ``degree`` is an integer, only the monomials of the given degree in @@ -2913,6 +2916,9 @@ def _normal_basis_libsingular(self, degree): sage: J = R.ideal(x^2-2*x*z+5) sage: J.normal_basis(3) # indirect doctest [z^3, y*z^2, x*z^2, y^2*z, x*y*z, y^3, x*y^2] + sage: [J._normal_basis_libsingular(d, (2, 2, 3)) for d in (0..8)] + [[1], [], [x, y], [z], [x*y, y^2], [x*z, y*z], [x*y^2, y^3, z^2], + [x*y*z, y^2*z], [x*y^3, y^4, x*z^2, y*z^2]] TESTS: @@ -2926,7 +2932,13 @@ def _normal_basis_libsingular(self, degree): from sage.rings.polynomial.multi_polynomial_ideal_libsingular import kbase_libsingular from sage.rings.polynomial.multi_polynomial_sequence import PolynomialSequence gb = self._groebner_basis_libsingular() - res = kbase_libsingular(self.ring().ideal(gb), degree) + J = self.ring().ideal(gb) + if weights is None: + res = kbase_libsingular(J, degree) + else: + from sage.libs.singular.function_factory import ff + res = ff.weightKB(J, -1 if degree is None else degree, + tuple(weights), attributes={J: {'isSB': 1}}) if len(res) == 1 and res[0].is_zero(): res = [] return PolynomialSequence(self.ring(), res, immutable=True) @@ -2943,7 +2955,8 @@ def normal_basis(self, degree=None, algorithm='libsingular', - ``degree`` -- integer (default: ``None``) - ``algorithm`` -- string (default: ``"libsingular"``); if not the - default, this will use the ``kbase()`` command from Singular + default, this will use the ``kbase()`` or ``weightKB()`` command from + Singular - ``singular`` -- the singular interpreter to use when ``algorithm`` is not ``"libsingular"`` (default: the default instance) @@ -2974,11 +2987,21 @@ def normal_basis(self, degree=None, algorithm='libsingular', sage: [J.normal_basis(d, algorithm='singular') for d in (0..3)] [[1], [z, y, x], [z^2, y*z, x*z, x*y], [z^3, y*z^2, x*z^2, x*y*z]] + In case of a polynomial ring with a weighted term order, the degree of + the monomials is taken with respect to the weights. :: + + sage: T = TermOrder('wdegrevlex', (1, 2, 3)) + sage: R. = PolynomialRing(QQ, order=T) + sage: B = R.ideal(x*y^2 + x^5, z*y + x^3*y).normal_basis(9); B + [x^2*y^2*z, x^3*z^2, x*y*z^2, z^3] + sage: all(f.degree() == 9 for f in B) + True + TESTS: Check that this method works over QQbar (:trac:`25351`):: - sage: P. = QQbar[] + sage: R. = QQbar[] sage: I = R.ideal(x^2+y^2+z^2-4, x^2+2*y^2-5, x*z-1) sage: I.normal_basis() [y*z^2, z^2, y*z, z, x*y, y, x, 1] @@ -2986,6 +3009,13 @@ def normal_basis(self, degree=None, algorithm='libsingular', sage: [J.normal_basis(d) for d in (0..3)] [[1], [z, y, x], [z^2, y*z, x*z, x*y], [z^3, y*z^2, x*z^2, x*y*z]] + Check the option ``algorithm="singular"`` with a weighted term order:: + + sage: T = TermOrder('wdegrevlex', (1, 2, 3)) + sage: S. = PolynomialRing(GF(2), order=T) + sage: S.ideal(x^6 + y^3 + z^2).normal_basis(6, algorithm='singular') + [x^4*y, x^2*y^2, y^3, x^3*z, x*y*z, z^2] + Check the deprecation:: sage: R. = PolynomialRing(QQ) @@ -3001,15 +3031,22 @@ def normal_basis(self, degree=None, algorithm='libsingular', algorithm = degree degree = None + weights = tuple(x.degree() for x in self.ring().gens()) + if all(w == 1 for w in weights): + weights = None + if algorithm == 'libsingular': - return self._normal_basis_libsingular(degree) + return self._normal_basis_libsingular(degree, weights=weights) else: gb = self.groebner_basis() R = self.ring() if degree is None: res = singular.kbase(R.ideal(gb)) - else: + elif weights is None: res = singular.kbase(R.ideal(gb), int(degree)) + else: + res = singular.weightKB(R.ideal(gb), int(degree), + singular(weights, type='intvec')) return PolynomialSequence(R, [R(f) for f in res], immutable=True)