Skip to content

Commit

Permalink
gh-36045: sage.rings.polynomial: Modularization fixes, # needs
Browse files Browse the repository at this point in the history
    
<!-- ^^^^^
Please provide a concise, informative and self-explanatory title.
Don't put issue numbers in there, do this in the PR body below.
For example, instead of "Fixes #1234" use "Introduce new method to
calculate 1+1"
-->
<!-- Describe your changes here in detail -->

<!-- Why is this change required? What problem does it solve? -->
- Part of: #29705
- Cherry-picked from: #35095
<!-- If this PR resolves an open issue, please link to it here. For
example "Fixes #12345". -->
<!-- If your change requires a documentation PR, please link it
appropriately. -->

### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. -->
<!-- If your change requires a documentation PR, please link it
appropriately -->
<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
<!-- Feel free to remove irrelevant items. -->

- [x] The title is concise, informative, and self-explanatory.
- [ ] The description explains in detail what this PR is about.
- [x] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [ ] I have updated the documentation accordingly.

### ⌛ Dependencies

<!-- List all open PRs that this PR logically depends on
- #12345: short description why this is a dependency
- #34567: ...
-->

<!-- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
    
URL: #36045
Reported by: Matthias Köppe
Reviewer(s): David Coudert
  • Loading branch information
Release Manager committed Aug 12, 2023
2 parents a38d129 + fafd930 commit ba7d118
Show file tree
Hide file tree
Showing 51 changed files with 5,222 additions and 4,594 deletions.
61 changes: 35 additions & 26 deletions src/sage/rings/polynomial/cyclotomic.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,34 @@ import sys
from cysignals.memory cimport sig_malloc, check_calloc, sig_free
from cysignals.signals cimport sig_on, sig_off

from sage.structure.element cimport parent

from sage.arith.misc import factor
from sage.rings.integer_ring import ZZ
from sage.misc.misc_c import prod
from sage.combinat.subset import subsets
from sage.libs.pari.all import pari
from sage.misc.misc_c import prod
from sage.rings.integer_ring import ZZ
from sage.structure.element cimport parent

try:
from sage.libs.pari.all import pari
except ImportError:
pass

def cyclotomic_coeffs(nn, sparse=None):
"""
Return the coefficients of the n-th cyclotomic polynomial
Return the coefficients of the `n`-th cyclotomic polynomial
by using the formula
.. MATH::
\\Phi_n(x) = \\prod_{d|n} (1-x^{n/d})^{\\mu(d)}
where `\\mu(d)` is the Möbius function that is 1 if d has an even
number of distinct prime divisors, -1 if it has an odd number of
distinct prime divisors, and 0 if d is not squarefree.
where `\\mu(d)` is the Möbius function that is 1 if `d` has an even
number of distinct prime divisors, `-1` if it has an odd number of
distinct prime divisors, and `0` if `d` is not squarefree.
Multiplications and divisions by polynomials of the
form `1-x^n` can be done very quickly in a single pass.
If sparse is ``True``, the result is returned as a dictionary of
If ``sparse`` is ``True``, the result is returned as a dictionary of
the non-zero entries, otherwise the result is returned as a list
of python ints.
Expand All @@ -72,17 +74,19 @@ def cyclotomic_coeffs(nn, sparse=None):
Check that it has the right degree::
sage: euler_phi(30)
sage: euler_phi(30) # needs sage.libs.pari
8
sage: R(cyclotomic_coeffs(14)).factor()
sage: R(cyclotomic_coeffs(14)).factor() # needs sage.libs.pari
x^6 - x^5 + x^4 - x^3 + x^2 - x + 1
The coefficients are not always +/-1::
sage: cyclotomic_coeffs(105)
[1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1]
[1, 1, 1, 0, 0, -1, -1, -2, -1, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1,
0, -1, 0, -1, 0, -1, 0, -1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, -1, -1, -2,
-1, -1, 0, 0, 1, 1, 1]
In fact the height is not bounded by any polynomial in n (Erdos),
In fact the height is not bounded by any polynomial in `n` (Erdos),
although takes a while just to exceed linear::
sage: v = cyclotomic_coeffs(1181895)
Expand Down Expand Up @@ -200,10 +204,10 @@ def cyclotomic_value(n, x):
INPUT:
- `n` -- an Integer, specifying which cyclotomic polynomial is to be
- ``n`` -- an Integer, specifying which cyclotomic polynomial is to be
evaluated
- `x` -- an element of a ring
- ``x`` -- an element of a ring
OUTPUT:
Expand Down Expand Up @@ -247,9 +251,12 @@ def cyclotomic_value(n, x):
TESTS::
sage: R.<x> = QQ[]
sage: K.<i> = NumberField(x^2 + 1)
sage: for y in [-1, 0, 1, 2, 1/2, Mod(3, 8), Mod(3,11), GF(9,'a').gen(), Zp(3)(54), i, x^2+2]:
sage: elements = [-1, 0, 1, 2, 1/2, Mod(3, 8), Mod(3,11)]
sage: R.<x> = QQ[]; elements += [x^2 + 2]
sage: K.<i> = NumberField(x^2 + 1); elements += [i] # needs sage.rings.number_fields
sage: elements += [GF(9,'a').gen()] # needs sage.rings.finite_rings
sage: elements += [Zp(3)(54)] # needs sage.rings.padics
sage: for y in elements:
....: for n in [1..60]:
....: val1 = cyclotomic_value(n, y)
....: val2 = cyclotomic_polynomial(n)(y)
Expand All @@ -258,29 +265,31 @@ def cyclotomic_value(n, x):
....: if val1.parent() is not val2.parent():
....: print("Wrong parent for cyclotomic_value(%s, %s) in %s"%(n,y,parent(y)))
sage: cyclotomic_value(20, I)
sage: cyclotomic_value(20, I) # needs sage.symbolic
5
sage: a = cyclotomic_value(10, mod(3, 11)); a
6
sage: a.parent()
Ring of integers modulo 11
sage: cyclotomic_value(30, -1.0)
sage: cyclotomic_value(30, -1.0) # needs sage.rings.real_mpfr
1.00000000000000
sage: # needs sage.libs.pari
sage: S.<t> = R.quotient(R.cyclotomic_polynomial(15))
sage: cyclotomic_value(15, t)
0
sage: cyclotomic_value(30, t)
2*t^7 - 2*t^5 - 2*t^3 + 2*t
sage: S.<t> = R.quotient(x^10)
sage: cyclotomic_value(2^128-1, t)
sage: cyclotomic_value(2^128 - 1, t)
-t^7 - t^6 - t^5 + t^2 + t + 1
sage: cyclotomic_value(10,mod(3,4))
sage: cyclotomic_value(10, mod(3,4))
1
Check that the issue with symbolic element in :trac:`14982` is fixed::
sage: a = cyclotomic_value(3, I)
sage: parent(a)
sage: a = cyclotomic_value(3, I) # needs sage.rings.number_fields
sage: parent(a) # needs sage.rings.number_fields
Number Field in I with defining polynomial x^2 + 1 with I = 1*I
"""
n = ZZ(n)
Expand Down Expand Up @@ -387,7 +396,7 @@ def bateman_bound(nn):
EXAMPLES::
sage: from sage.rings.polynomial.cyclotomic import bateman_bound
sage: bateman_bound(2**8*1234567893377)
sage: bateman_bound(2**8 * 1234567893377) # needs sage.libs.pari
66944986927
"""
_, n = nn.val_unit(2)
Expand Down
39 changes: 22 additions & 17 deletions src/sage/rings/polynomial/flatten.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,37 +111,41 @@ def __init__(self, domain):
::
sage: # needs sage.rings.number_field
sage: x = polygen(ZZ, 'x')
sage: K.<v> = NumberField(x^3 - 2) # optional - sage.rings.number_field
sage: R = K['x','y']['a','b'] # optional - sage.rings.number_field
sage: K.<v> = NumberField(x^3 - 2)
sage: R = K['x','y']['a','b']
sage: from sage.rings.polynomial.flatten import FlatteningMorphism
sage: f = FlatteningMorphism(R) # optional - sage.rings.number_field
sage: f(R('v*a*x^2 + b^2 + 1/v*y')) # optional - sage.rings.number_field
sage: f = FlatteningMorphism(R)
sage: f(R('v*a*x^2 + b^2 + 1/v*y'))
v*x^2*a + b^2 + (1/2*v^2)*y
::
sage: R = QQbar['x','y']['a','b'] # optional - sage.rings.number_field
sage: # needs sage.rings.number_field
sage: R = QQbar['x','y']['a','b']
sage: from sage.rings.polynomial.flatten import FlatteningMorphism
sage: f = FlatteningMorphism(R) # optional - sage.rings.number_field
sage: f(R('QQbar(sqrt(2))*a*x^2 + b^2 + QQbar(I)*y')) # optional - sage.rings.number_field
sage: f = FlatteningMorphism(R)
sage: f(R('QQbar(sqrt(2))*a*x^2 + b^2 + QQbar(I)*y')) # needs sage.symbolic
1.414213562373095?*x^2*a + b^2 + I*y
::
sage: R.<z> = PolynomialRing(QQbar, 1) # optional - sage.rings.number_field
sage: # needs sage.rings.number_field
sage: R.<z> = PolynomialRing(QQbar, 1)
sage: from sage.rings.polynomial.flatten import FlatteningMorphism
sage: f = FlatteningMorphism(R) # optional - sage.rings.number_field
sage: f.domain(), f.codomain() # optional - sage.rings.number_field
sage: f = FlatteningMorphism(R)
sage: f.domain(), f.codomain()
(Multivariate Polynomial Ring in z over Algebraic Field,
Multivariate Polynomial Ring in z over Algebraic Field)
::
sage: R.<z> = PolynomialRing(QQbar) # optional - sage.rings.number_field
sage: # needs sage.rings.number_field
sage: R.<z> = PolynomialRing(QQbar)
sage: from sage.rings.polynomial.flatten import FlatteningMorphism
sage: f = FlatteningMorphism(R) # optional - sage.rings.number_field
sage: f.domain(), f.codomain() # optional - sage.rings.number_field
sage: f = FlatteningMorphism(R)
sage: f.domain(), f.codomain()
(Univariate Polynomial Ring in z over Algebraic Field,
Univariate Polynomial Ring in z over Algebraic Field)
Expand Down Expand Up @@ -376,8 +380,8 @@ def _call_(self, p):
sage: from sage.rings.polynomial.flatten import FlatteningMorphism
sage: rings = [ZZ['x']['y']['a,b,c']]
sage: rings += [GF(4)['x','y']['a','b']] # optional - sage.rings.finite_rings
sage: rings += [AA['x']['a','b']['y'], QQbar['a1','a2']['t']['X','Y']] # optional - sage.rings.number_field
sage: rings += [GF(4)['x','y']['a','b']] # needs sage.rings.finite_rings
sage: rings += [AA['x']['a','b']['y'], QQbar['a1','a2']['t']['X','Y']] # needs sage.rings.number_field
sage: for R in rings:
....: f = FlatteningMorphism(R)
....: g = f.section()
Expand Down Expand Up @@ -490,8 +494,9 @@ def __init__(self, domain, D):
sage: P.<z> = AffineSpace(R, 1)
sage: H = End(P)
sage: f = H([z^2 + c])
sage: f.specialization({c:1})
Scheme endomorphism of Affine Space of dimension 1 over Real Field with 53 bits of precision
sage: f.specialization({c:1}) # needs sage.modules
Scheme endomorphism of
Affine Space of dimension 1 over Real Field with 53 bits of precision
Defn: Defined on coordinates by sending (z) to
(z^2 + 1.00000000000000)
"""
Expand Down
26 changes: 13 additions & 13 deletions src/sage/rings/polynomial/groebner_fan.py
Original file line number Diff line number Diff line change
Expand Up @@ -1246,51 +1246,51 @@ def render(self, file=None, larger=False, shift=0, rgbcolor=(0, 0, 0),
INPUT:
- ``file`` - a filename if you prefer the output
- ``file`` -- a filename if you prefer the output
saved to a file. This will be in xfig format.
- ``shift`` - shift the positions of the variables in
- ``shift`` -- shift the positions of the variables in
the drawing. For example, with shift=1, the corners will be b
(right), c (left), and d (top). The shifting is done modulo the
number of variables in the polynomial ring. The default is 0.
- ``larger`` - bool (default: ``False``); if ``True``, make
- ``larger`` -- bool (default: ``False``); if ``True``, make
the triangle larger so that the shape of the Groebner region
appears. Affects the xfig file but probably not the sage graphics
(?)
- ``rgbcolor`` - This will not affect the saved xfig
- ``rgbcolor`` -- This will not affect the saved xfig
file, only the sage graphics produced.
- ``polyfill`` - Whether or not to fill the cones with
- ``polyfill`` -- Whether or not to fill the cones with
a color determined by the highest degree in each reduced Groebner
basis for that cone.
- ``scale_colors`` - if True, this will normalize
- ``scale_colors`` -- if True, this will normalize
color values to try to maximize the range
EXAMPLES::
sage: R.<x,y,z> = PolynomialRing(QQ,3)
sage: G = R.ideal([y^3 - x^2, y^2 - 13*x,z]).groebner_fan()
sage: test_render = G.render()
sage: test_render = G.render() # needs sage.plot
::
sage: R.<x,y,z> = PolynomialRing(QQ,3)
sage: G = R.ideal([x^2*y - z, y^2*z - x, z^2*x - y]).groebner_fan()
sage: test_render = G.render(larger=True)
sage: test_render = G.render(larger=True) # needs sage.plot
TESTS:
Testing the case where the number of generators is < 3. Currently,
this should raise a ``NotImplementedError`` error.
this should raise a :class:`NotImplementedError`.
::
sage: R.<x,y> = PolynomialRing(QQ, 2)
sage: R.ideal([y^3 - x^2, y^2 - 13*x]).groebner_fan().render()
sage: R.ideal([y^3 - x^2, y^2 - 13*x]).groebner_fan().render() # needs sage.plot
Traceback (most recent call last):
...
NotImplementedError
Expand Down Expand Up @@ -1460,17 +1460,17 @@ def render3d(self, verbose=False):
sage: R4.<w,x,y,z> = PolynomialRing(QQ,4)
sage: gf = R4.ideal([w^2-x,x^2-y,y^2-z,z^2-x]).groebner_fan()
sage: three_d = gf.render3d()
sage: three_d = gf.render3d() # needs sage.plot
TESTS:
Now test the case where the number of generators is not 4. Currently,
this should raise a ``NotImplementedError`` error.
this should raise a :class:`NotImplementedError` error.
::
sage: P.<a,b,c> = PolynomialRing(QQ, 3, order="lex")
sage: sage.rings.ideal.Katsura(P, 3).groebner_fan().render3d()
sage: sage.rings.ideal.Katsura(P, 3).groebner_fan().render3d() # needs sage.plot
Traceback (most recent call last):
...
NotImplementedError
Expand Down
5 changes: 3 additions & 2 deletions src/sage/rings/polynomial/hilbert.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ in any example with more than 34 variables.
#
#*****************************************************************************

import sage.interfaces.abc

from sage.rings.polynomial.polydict cimport ETuple
from sage.rings.polynomial.polynomial_integer_dense_flint cimport Polynomial_integer_dense_flint
from sage.interfaces.singular import Singular

from cysignals.memory cimport sig_malloc
from cpython.list cimport PyList_GET_ITEM
Expand Down Expand Up @@ -476,7 +477,7 @@ def first_hilbert_series(I, grading=None, return_grading=False):
cdef Polynomial_integer_dense_flint fhs = Polynomial_integer_dense_flint.__new__(Polynomial_integer_dense_flint)
fhs._parent = PR
fhs._is_gen = 0
if isinstance(I.parent(), Singular):
if isinstance(I, sage.interfaces.abc.SingularElement):
S = I._check_valid()
# First, we need to deal with quotient rings, which also covers the case
# of graded commutative rings that arise as cohomology rings in odd characteristic.
Expand Down
16 changes: 8 additions & 8 deletions src/sage/rings/polynomial/ideal.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ def residue_class_degree(self):
EXAMPLES::
sage: R.<t> = GF(5)[] # optional - sage.rings.finite_rings
sage: P = R.ideal(t^4 + t + 1) # optional - sage.rings.finite_rings
sage: P.residue_class_degree() # optional - sage.rings.finite_rings
sage: R.<t> = GF(5)[]
sage: P = R.ideal(t^4 + t + 1)
sage: P.residue_class_degree()
4
"""
return self.gen().degree()
Expand All @@ -45,8 +45,8 @@ def residue_field(self, names=None, check=True):
EXAMPLES::
sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + 2*t + 9) # optional - sage.rings.finite_rings
sage: k.<a> = P.residue_field(); k # optional - sage.rings.finite_rings
sage: R.<t> = GF(17)[]; P = R.ideal(t^3 + 2*t + 9)
sage: k.<a> = P.residue_field(); k # needs sage.rings.finite_rings
Residue field in a of Principal ideal (t^3 + 2*t + 9) of
Univariate Polynomial Ring in t over Finite Field of size 17
"""
Expand Down Expand Up @@ -75,11 +75,11 @@ def groebner_basis(self, algorithm=None):
sage: R.<x> = QQ[]
sage: I = R.ideal([x^2 - 1, x^3 - 1])
sage: G = I.groebner_basis(); G # optional - sage.libs.singular
sage: G = I.groebner_basis(); G
[x - 1]
sage: type(G) # optional - sage.libs.singular
sage: type(G)
<class 'sage.rings.polynomial.multi_polynomial_sequence.PolynomialSequence_generic'>
sage: list(G) # optional - sage.libs.singular
sage: list(G)
[x - 1]
"""
gb = self.gens_reduced()
Expand Down
Loading

0 comments on commit ba7d118

Please sign in to comment.