Skip to content

Commit

Permalink
sagemathgh-35376: Update Zariski-van Kampen functions
Browse files Browse the repository at this point in the history
    
### 📚 Description

This PR has been cleaned and I think it is ready for review. The main
goal of this PR is to update, create and make faster some functions in
``zariski_vankampen.py``. I describe here the functions created or
modified and the reasons:

- `discrim`: It applies now to a list or tuple of polynomials instead of
a polynomial. Since only the zeroes of $\textrm{disc}_y f$ are needed,
we compute (using `@parallel`) the discriminant of each polynomial and
the pairwise resultants. Moreover the computations are not done in
`QQbar` but in the number field of definition (only the roots are in
`QQbar`). Some other functions are only changed to be applied to tuples
or lists as `roots_interval`, `roots_interval_cached`,
`populate_roots_interval_cache`, `braid_in_segment`.
- `orient_circuit`: If we know that the circuit is convex a much faster
and precise method is used.
- `voronoi_cells`: It is a new function whose input is a *corrected
Voronoi diagram*; the output is the graph of the diagram, the
counterclock-wise boundary, a base point in the boundary, and the dual
graph. It has been isolated for clarity.
- `fieldI`: It is a new function whose function is the ground field `F`
(a subfield of `QQbar`) and the output is the smallest subfield of
`QQbar` containing `F` and `I`. Since the vertices of the Voronoi
diagrams are Gauss rationals, it allows to express everything in a
subfield of `QQbar` where computations are much faster than in `QQbar`.
- `populate_roots_interval_cache`: We add a hack (inspired by the
original `braid_monodromy` function to avoid some random fails when
parallelizing.
- `braid_in_segment`: We replace the complex numbers of the input by
Gauss rational and we add as input a dictionnary `precision` to be
recurrently used in order to increase the precision of the interval
computations and avoid hangs of the original function.
- `geometric_basis`: This function produces a geometric basis of the
free group $\pi_1(\mathbb{C}\setminus\Delta;p)$ where $\Delta$ is the
set of discriminant points; the elements of the basis are meridians
around each point such that its product is the counterclockwise boundary
of a big disk. The input is basically the output of `voronoi_cells`;
there is a new method to produce such a basis since the previous one
gave an error for some diagrams.
- `strand_components`: This function adds a new feature. It applies to
lists or tuples of polynomials and assign each strand of the braids to
the index of the polynomial associated with this strand. It is not a
hard computation and adds usefuel information that can be long (or
impossible) to be retrieved once the braid monodromy is computed
- `braid_monodromy`: The core of this function remains unchanged. The
output includes now a dictionnary associating each strand to an element
of an optional tuple of polynomials in the input.
- `conjugate_positive_form` is an auxiliary function which processes the
special braids appearing in the braid monodromy to make faster he
computation of the fundamental group since the mapping class group
action of the braid group on the free group can be very slow.
- `braid2rels`: this is a separate function to return a minimal set of
relations produced by the action of a braid on a free group.
- `fundamental_group_from_braid_mon`. This function computes the
fundamental group from braid monodromy
- `fundamental_group`: This function admits the optional argument
`puiseux` (`braid2rels` is used to get a smaller set of relations).
- `fundamental_group_arrangement`. The input is a list of polynomials
and, besides the fundamental group a dictionnary is given, associating
to each factor some meridians of these components.
The methods `fundamental_group` and `braid_monodromy` for affine curves
have been adapted. A new class of *arrangements of curves* should be
created to take advantage of the new features.
Actually, in another branch I created a method `fundamental_group` for
hyperplane arrangements which take care of the meridian of each
hyperplane. I encountered some problems since the class of hyperplane
arrangements ordered in a rigid way the meridians and I plan to create a
class of *ordered hyperplane arrangements* to avoid this problem.
What it is called a Puiseux presentation of the $\pi_1$ of the
complement of an affine curve has the same homotopy type as this
complement (as proved by Libgober).
Tests and documentation have been updated (probably not enough).

Fixes sagemath#34415.
### 📝 Checklist

<!-- Put an `x` in all the boxes that apply. It should be `[x]` not `[x
]`. -->

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

### ⌛ Dependencies
    
URL: sagemath#35376
Reported by: Enrique Manuel Artal Bartolo
Reviewer(s): Enrique Manuel Artal Bartolo, Matthias Köppe, miguelmarco
  • Loading branch information
Release Manager committed Aug 23, 2023
2 parents 4d81fde + 4e38e31 commit 2d10476
Show file tree
Hide file tree
Showing 4 changed files with 1,003 additions and 344 deletions.
1 change: 1 addition & 0 deletions src/doc/en/reference/curves/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Curves
sage/schemes/curves/projective_curve
sage/schemes/curves/point
sage/schemes/curves/closed_point
sage/schemes/curves/zariski_vankampen

sage/schemes/jacobians/abstract_jacobian

Expand Down
78 changes: 52 additions & 26 deletions src/sage/schemes/curves/affine_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ class AffineCurve(Curve_generic, AlgebraicScheme_subscheme_affine):
sage: C = Curve([x^2 - z, z - 8*x], A); C # optional - sage.rings.finite_rings
Affine Curve over Finite Field of size 7 defined by x^2 - z, -x + z
"""

def __init__(self, A, X):
r"""
Initialize.
Expand Down Expand Up @@ -271,6 +272,7 @@ class AffinePlaneCurve(AffineCurve):
"""
Affine plane curves.
"""

def __init__(self, A, f):
r"""
Initialize.
Expand Down Expand Up @@ -465,8 +467,8 @@ def plot(self, *args, **kwds):
sage: C.plot()
Graphics object consisting of 1 graphics primitive
"""
I = self.defining_ideal()
return I.plot(*args, **kwds)
Id = self.defining_ideal()
return Id.plot(*args, **kwds)

def is_transverse(self, C, P):
r"""
Expand Down Expand Up @@ -689,7 +691,7 @@ def tangents(self, P, factor=True):
fact.extend([vars[1] - roots[i][0]*vars[0] for i in range(len(roots))])
return [ff(coords) for ff in fact]
else:
return [l[0](coords) for l in T.factor()]
return [ll[0](coords) for ll in T.factor()]

def is_ordinary_singularity(self, P):
r"""
Expand Down Expand Up @@ -1009,10 +1011,10 @@ def projection(self, indices, AS=None):
removecoords.pop(indices[i])
J = self.defining_ideal().elimination_ideal(removecoords)
K = Hom(AA.coordinate_ring(), AA2.coordinate_ring())
l = [0]*(n)
ll = [0]*(n)
for i in range(len(indices)):
l[indices[i]] = AA2.gens()[i]
phi = K(l)
ll[indices[i]] = AA2.gens()[i]
phi = K(ll)
G = [phi(f) for f in J.gens()]
try:
C = AA2.curve(G)
Expand Down Expand Up @@ -1519,6 +1521,7 @@ def resolution_of_singularities(self, extend=False):
working over a number field use extend=True
"""
# helper function for extending the base field (in the case of working over a number field)

def extension(self):
F = self.base_ring()
pts = self.change_ring(F.embeddings(QQbar)[0]).rational_points()
Expand Down Expand Up @@ -1720,11 +1723,11 @@ def tangent_line(self, p):
from sage.schemes.curves.constructor import Curve

# translate to p
I = []
I0 = []
for poly in Tp.defining_polynomials():
I.append(poly.subs({x: x - c for x, c in zip(gens, p)}))
I0.append(poly.subs({x: x - c for x, c in zip(gens, p)}))

return Curve(I, A)
return Curve(I0, A)


class AffinePlaneCurve_field(AffinePlaneCurve, AffineCurve_field):
Expand All @@ -1733,11 +1736,33 @@ class AffinePlaneCurve_field(AffinePlaneCurve, AffineCurve_field):
"""
_point = AffinePlaneCurvePoint_field

def fundamental_group(self):
@cached_method
def fundamental_group(self, simplified=True, puiseux=False):
r"""
Return a presentation of the fundamental group of the complement
of ``self``.
INPUT:
- ``simplified`` -- (default: ``True``) boolean to simplify the presentation.
- ``puiseux`` -- (default: ``False``) boolean to decide if the
presentation is constructed in the classical way or using Puiseux
shortcut. If ``True``, ``simplified`` is set to ``False``.
OUTPUT:
A presentation with generators `x_1, \dots, x_d` and relations. If ``puiseux``
is ``False`` the relations are `(x_j\cdot \tau)\cdot x_j^{-1}` for `1\leq j<d`
and `tau` a braid in the braid monodromy; finally the presentation
is simplified. If ``puiseux`` is ``True``, each
`tau` is decomposed as `\alpha^{-1}\cdot\beta\cdot\alpha`, where `\beta` is
a positive braid; the relations are `((x_j\cdot \beta)\cdot x_j^{-1})\cdot \alpha`
where `j` is an integer of the ``Tietze`` word of `\beta`. This presentation
is not simplified by default since it represents the homotopy type of
the complement of the curve.
.. NOTE::
The curve must be defined over the rationals or a number field
Expand All @@ -1749,6 +1774,12 @@ def fundamental_group(self):
sage: C = A.curve(y^2 - x^3 - x^2)
sage: C.fundamental_group() # optional - sirocco
Finitely presented group < x0 | >
sage: bm = C.braid_monodromy() # optional - sirocco
sage: g = C.fundamental_group(puiseux=True) # optional - sirocco
sage: g # optional - sirocco
Finitely presented group < x0, x1 | x1*x0^-1, x1*x0*x1^-1*x0^-1 >
sage: g.simplified() # optional - sirocco
Finitely presented group < x0 | >
In the case of number fields, they need to have an embedding
to the algebraic field::
Expand All @@ -1766,15 +1797,10 @@ def fundamental_group(self):
This functionality requires the sirocco package to be installed.
"""
from sage.schemes.curves.zariski_vankampen import fundamental_group
F = self.base_ring()
from sage.rings.qqbar import QQbar
if QQbar.coerce_map_from(F) is None:
raise NotImplementedError("the base field must have an embedding"
" to the algebraic field")
f = self.defining_polynomial()
return fundamental_group(f, projective=False)
from sage.schemes.curves.zariski_vankampen import fundamental_group_from_braid_mon
return fundamental_group_from_braid_mon(self.braid_monodromy(), simplified=simplified, puiseux=puiseux)

@cached_method
def braid_monodromy(self):
r"""
Compute the braid monodromy of a projection of the curve.
Expand All @@ -1783,7 +1809,7 @@ def braid_monodromy(self):
A list of braids. The braids correspond to paths based in the same point;
each of this paths is the conjugated of a loop around one of the points
in the discriminant of the projection of `self`.
in the discriminant of the projection of ``self``.
NOTE:
Expand All @@ -1808,7 +1834,7 @@ def braid_monodromy(self):
raise NotImplementedError("the base field must have an embedding"
" to the algebraic field")
f = self.defining_polynomial()
return braid_monodromy(f)
return braid_monodromy(f)[0]

def riemann_surface(self, **kwargs):
r"""
Expand Down Expand Up @@ -2142,18 +2168,18 @@ def _nonsingular_model(self):
from sage.rings.function_field.constructor import FunctionField

k = self.base_ring()
I = self.defining_ideal()
I0 = self.defining_ideal()

# invlex is the lex order with x < y < z for R = k[x,y,z] for instance
R = I.parent().ring().change_ring(order='invlex')
I = I.change_ring(R)
R = I0.parent().ring().change_ring(order='invlex')
I0 = I0.change_ring(R)
n = R.ngens()

names = R.variable_names()

gbasis = I.groebner_basis()
gbasis = I0.groebner_basis()

if not I.is_prime():
if not I0.is_prime():
raise TypeError("the curve is not integral")

# Suppose the generators of the defining ideal I of the curve is
Expand Down Expand Up @@ -2223,7 +2249,7 @@ def _nonsingular_model(self):
lift_to_function_field = hom(R, M, coordinate_functions)

# sanity check
assert all(lift_to_function_field(f).is_zero() for f in I.gens())
assert all(lift_to_function_field(f).is_zero() for f in I0.gens())

return M, lift_to_function_field

Expand Down
5 changes: 4 additions & 1 deletion src/sage/schemes/curves/projective_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ class ProjectiveCurve(Curve_generic, AlgebraicScheme_subscheme_projective):
Projective Curve over Cyclotomic Field of order 11 and degree 10 defined
by -x^2 + (-u)*z^2 + y*w, x*w + (-3*u^2)*z*w
"""

def __init__(self, A, X):
"""
Initialize.
Expand Down Expand Up @@ -603,6 +604,7 @@ class ProjectivePlaneCurve(ProjectiveCurve):
Projective Plane Curve over Finite Field in v of size 5^2
defined by y^2*z - x*z^2 - z^3
"""

def __init__(self, A, f):
"""
Initialize.
Expand Down Expand Up @@ -1436,6 +1438,7 @@ def ordinary_model(self):
+ (-3/16*a - 1/4)*y*z^3 + (1/16*a + 3/32)*z^4)
"""
# helper function for extending the base field

def extension(self):
F = self.base_ring()
pts = self.change_ring(F.embeddings(QQbar)[0]).rational_points()
Expand Down Expand Up @@ -1742,7 +1745,7 @@ def fundamental_group(self):
sage: C = P.curve(z^2*y^3 - z*(33*x*z+2*x^2+8*z^2)*y^2
....: + (21*z^2+21*x*z-x^2)*(z^2+11*x*z-x^2)*y
....: + (x-18*z)*(z^2+11*x*z-x^2)^2)
sage: C.fundamental_group() # optional - sirocco
sage: C.fundamental_group() # random # optional - sirocco
Finitely presented group < x1, x3 | (x3^-1*x1^-1*x3*x1^-1)^2*x3^-1,
x3*(x1^-1*x3^-1)^2*x1^-1*(x3*x1)^2 >
Expand Down
Loading

0 comments on commit 2d10476

Please sign in to comment.