Canonical divisor help

127 views
Skip to first unread message

John H Palmieri

unread,
Oct 27, 2023, 6:14:00 PM10/27/23
to sage-support
If anyone here knows anything about canonical divisors and their implementation in Sage, please see https://ask.sagemath.org/question/74034/converting-algebraic-geometry-magmas-code-to-sage/. The setup:

sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2)
sage: f = 2*x^5 - 4*x^3*y*z + x^2*y*z^2 + 2*x*y^3*z + 2*x*y^2*z^2+ y^5
sage: C = P2.curve(f)

How do you get the canonical divisor for C?

(I encourage you to post answers directly to ask.sagemath.org, if you're willing.)

--
John

Nils Bruin

unread,
Oct 27, 2023, 6:42:24 PM10/27/23
to sage-support
A canonical divisor is the divisor of any differential on C so the following does the trick:

sage: kC=C.function_field()
sage: kC(kC.base_field().gen(0)).differential().divisor()

It doesn't look like we quite have computation of Riemann-Roch spaces natively in sage yet, so finding effective representatives requires a little more work. In the RiemannSurface code this is done using singular's adjoint ideal code (or by Baker's theorem in cases where it applies). For this curve the canonical class is of degree -2, so there are no effective representatives in this case.

Dima Pasechnik

unread,
Oct 27, 2023, 6:51:10 PM10/27/23
to sage-s...@googlegroups.com
By the way, the docstring of divisor() misses an example, it's

def divisor(self, v, base_ring=None, check=True, reduce=True):
r"""
Return the divisor specified by ``v``.

.. WARNING::

The coefficients of the divisor must be in the base ring
and the terms must be reduced. If you set ``check=False``
and/or ``reduce=False`` it is your responsibility to pass
a valid object ``v``.

EXAMPLES::

sage: x,y,z = PolynomialRing(QQ, 3, names='x,y,z').gens()
sage: C = Curve(y^2*z - x^3 - 17*x*z^2 + y*z^2)

"""

Is there an issue for this?
> --
> You received this message because you are subscribed to the Google Groups "sage-support" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sage-support...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sage-support/91b14570-b83e-4dbf-8bca-0a2eff538a50n%40googlegroups.com.

John H Palmieri

unread,
Oct 27, 2023, 7:02:35 PM10/27/23
to sage-support
Hi Dima,

Yes, I noticed that, too. It also fails to provide any information about what ``v`` should be (beyond saying that it should be a "valid object"): there is no INPUT block.

Nils Bruin

unread,
Oct 27, 2023, 7:12:18 PM10/27/23
to sage-support
On Friday, 27 October 2023 at 15:42:24 UTC-7 Nils Bruin wrote:
It doesn't look like we quite have computation of Riemann-Roch spaces natively in sage yet

Correction, that DOES seem to be implemented as well:

sage: kC=C.function_field()
sage: D=kC(kC.base_field().gen(0)).differential().divisor()
sage: (-D).function_space()

That's actually a great gain in functionality! That code really deserves to be exercised and, inevitably, debugged from bugs that would be uncovered by extensive testing.

Dima Pasechnik

unread,
Oct 27, 2023, 7:27:07 PM10/27/23
to sage-s...@googlegroups.com
On Sat, Oct 28, 2023 at 1:02 AM John H Palmieri <jhpalm...@gmail.com> wrote:

> Yes, I noticed that, too. It also fails to provide any information about what ``v`` should be (beyond saying that it should be a "valid object"): there is no INPUT block.

I've left a comment here:
https://github.com/sagemath/sage/commit/977ace651af9b99689f7b6507f91f8b4e2588ae9#r131117132

fortunately, the author, @kwankyu is active

I can't locate the ticket, but it was merged in 9.0.beta9
> To view this discussion on the web visit https://groups.google.com/d/msgid/sage-support/391d8ee7-0329-4a15-bc88-4b84973389abn%40googlegroups.com.

Kwankyu

unread,
Oct 28, 2023, 8:39:26 AM10/28/23
to sage-support
Hi,

I replied to Dima's comment in https://github.com/sagemath/sage/commit/977ace651af9b99689f7b6507f91f8b4e2588ae9#r131138149

Note that the "divisor" method of a curve had existed long before I added function field machinery and attached function fields to curves. Hence actually there are two systems of "divisors" of curves in Sage.

The old system was implemented by William Stein, David Kohel, and Volker Braun. In the old system, a divisor is a formal sum of rational points with multiplicities. It is mainly implemented in `src/sage/schemes/generic/divisor.py`. Overall it is very rudimentary. Dima and John is attempting to use this system.

The new system was implemented by me. Here a divisor is a formal sum of places of a function field with multiplicities. This system is available via the function field attached to a curve. This is much more powerful than the old system. You can compute the Riemann-Roch space of a divisor. Nils is using this system.

I never attempted to combine the two systems, being afraid of breaking the old system (or just being lazy :-) There are similarly two systems in Magma too. But in Magma, the two systems are integrated tightly and seamlessly. I did some integration in Sage too but far from complete compared with Magma.

I looked the Magma code in ask.sagemath. There's no problem in computing a canonical divisor for the curve (through the attached function field). Computing a basis of the Riemann-Roch space is no problem as well. Actually the hard part is to construct the morphism from C to P2 from the basis. Magma does this seamlessly. But Sage lacks this functionality (perhaps because I did not implement it). I think, the gist of the matter is to convert an element of the function field to a rational function of the coordinate ring of P2. I have no idea how to do this now... Once you construct the morphism, Sage can also compute the image of the morphism (perhaps I implemented this). Hence unfortunately the Magma code cannot be line by line converted to Sage code at present.

Kwankyu

unread,
Oct 28, 2023, 8:59:58 AM10/28/23
to sage-support
Let me mention also the related PR 


which implements Jacobian groups of curves (again via function field), referencing Nils' old code. The PR is long sleeping in draft state. If anyone finds it useful, I may wake it up. 

Kwankyu

unread,
Oct 28, 2023, 9:19:48 AM10/28/23
to sage-support
To answer John's question:

sage: P2.<x,y,z> = ProjectiveSpace(QQ, 2)
sage: f = 2*x^5 - 4*x^3*y*z + x^2*y*z^2 + 2*x*y^3*z + 2*x*y^2*z^2+ y^5
sage: C = P2.curve(f)
sage: F = C.function_field()
sage: z, = F.gens()
sage: K = z.differential().divisor()  # canonical divisor
sage: (-K).dimension()
3
sage: f1, f2, f3 = (-K).basis_function_space()
sage: phi = C.hom(P2, [f1,f2,f3]). <--------------- does not work
sage: phi.image()  # will work

John H Palmieri

unread,
Oct 28, 2023, 12:59:35 PM10/28/23
to sage-support
Thanks for all of your posts, Kwankyu. Helpful and informative.

  John

Nils Bruin

unread,
Oct 28, 2023, 2:16:39 PM10/28/23
to sage-support
On Saturday, 28 October 2023 at 05:39:26 UTC-7 Kwankyu wrote:
I looked the Magma code in ask.sagemath. There's no problem in computing a canonical divisor for the curve (through the attached function field). Computing a basis of the Riemann-Roch space is no problem as well. Actually the hard part is to construct the morphism from C to P2 from the basis. Magma does this seamlessly. But Sage lacks this functionality (perhaps because I did not implement it). I think, the gist of the matter is to convert an element of the function field to a rational function of the coordinate ring of P2.

That's actually trivially simple: if [f1,f2,f3] is the basis of your Riemann-Roch space, you just consider the map defined by [f1:f2:f3]. So you lift f1,f2,f3 to rational functions on the affine space that contains your curve: you just take the rational function representation and forget the algebraic relations between the variables. You now have rational functions in a rational function field, so you can clear denominators there. Now you have a rational map (described by polynomials) A^2->P^r under which the rational image of your curve C in A^2 is the corresponding projective image. Computing that image is the usual groebner-basis operation for finding images of rational maps, so that's potentially quite expensive.

In practice, you know something about the denominators of the representations of f1,f2,f3, so you can probably do a little better.

At its core, that is what the magma code does too, although perhaps it has some smart tricks here and there to try and keep degrees in check a bit.

John H Palmieri

unread,
Oct 28, 2023, 4:08:17 PM10/28/23
to sage-support
Nils, thanks to you, too, for your responses.

Kwankyu

unread,
Oct 28, 2023, 6:26:35 PM10/28/23
to sage-support
That's actually trivially simple: if [f1,f2,f3] is the basis of your Riemann-Roch space, you just consider the map defined by [f1:f2:f3]. So you lift f1,f2,f3 to rational functions on the affine space that contains your curve: you just take the rational function representation and forget the algebraic relations between the variables. 

f1, f2, f3 are univariate polynomials (say in y) over rational function field (say in x). Then x and y are not always the variables X and Y of the coordinate ring of the affine plane. Things are more complicated if the curve is in space (of dim > 2).

 

Nils Bruin

unread,
Oct 28, 2023, 9:50:12 PM10/28/23
to sage-support
On Saturday, 28 October 2023 at 15:26:35 UTC-7 Kwankyu wrote:

f1, f2, f3 are univariate polynomials (say in y) over rational function field (say in x). Then x and y are not always the variables X and Y of the coordinate ring of the affine plane. Things are more complicated if the curve is in space (of dim > 2).
 
Sure. But you did get x,y somehow from the model with which C was given. Most likely, the A2 on which x,y are coordinates is obtained via projection from whatever model C was given by? Even if it is not a linear map, there are still expressions through which you can pull back x,y to the original model. You're right that the representations may get rather bad, but I'm not sure there's really something you can do about that.

Nils Bruin

unread,
Oct 28, 2023, 10:18:06 PM10/28/23
to sage-support
The most pressing problem in sage at the moment seems to be that presently there only seem to be morphisms between schemes. You need rational maps for this (especially from a singular model, the map to a canonical model might only be a rational map).

So I think we'd first need a bit of a push to get some infrastructure for rational maps. In fact "maps" between schemes in magma are just rational maps. So presently there is really a difference in functionality.

There are some conceptual problems with the main "map" type between schemes being a rational map. But it is very convenient and certainly for curves a much better fit than maps that are clearly morphisms.

I might be overlooking something ... currently sage allows for the construction of a rational map P2 -> P2, but then asking for the image of a curve C in P2 leads to

TypeError: map must be a morphism

(which should probably be a ValueError). Perhaps the code is just unnecessarily picky?

Kwankyu

unread,
Oct 29, 2023, 7:19:47 AM10/29/23
to sage-support
The most pressing problem in sage at the moment seems to be that presently there only seem to be morphisms between schemes. You need rational maps for this (especially from a singular model, the map to a canonical model might only be a rational map).

"SchemeMorphism" in Sage is a map defined by rational functions between schemes. It does not check the domain of definition. Hence it represent mathematically rational maps rather than morphisms. I guess that the "morphism" in "SchemeMorphism" was intended to mean morphism in category theory rather than morphisms in scheme theory.
 
I might be overlooking something ... currently sage allows for the construction of a rational map P2 -> P2, but then asking for the image of a curve C in P2 leads to

TypeError: map must be a morphism

(which should probably be a ValueError). Perhaps the code is just unnecessarily picky?

What is your code? 

Nils Bruin

unread,
Oct 29, 2023, 4:45:27 PM10/29/23
to sage-support


On Monday, 30 October 2023 at 00:19:47 UTC+13 Kwankyu wrote:
What is your code? 
P2.<x,y,z> = ProjectiveSpace(QQ, 2)
f = 2*x^5 - 4*x^3*y*z + x^2*y*z^2 + 2*x*y^3*z + 2*x*y^2*z^2+ y^5
C = Curve(f)
kC = C.function_field()
D = kC(kC.base_field().gen(0)).differential().divisor()
L,m,s = (-D).function_space()
#the routine below is a bit of a shortcut based on how the affine patch for kC
#is chosen. In more general code this would need to be a little more sophisticated
def liftkC(u):
    return sum([(m.numerator()(y/x))/(m.denominator()(y/x))*(z/x)^i for i,m in enumerate(u.list())])
liftedbasis = [liftkC(m(b)) for b in L.basis()]
den = lcm([b.denominator() for b in liftedbasis])
liftedbasis = [parent(x)(b*den) for b in liftedbasis]
phi = P2.hom(liftedbasis,P2)
phi(C) # this fails
C._forward_image(phi,check=False) #this seems to work!
 
Of course, one could also do some linear algebra with (-D).function_space() and (-2*D).function_space() to figure out this image.

Kwankyu

unread,
Oct 29, 2023, 7:11:05 PM10/29/23
to sage-support
This is simpler

sage: psi = C.hom(liftedbasis, P2)
sage: psi.image()
Closed subscheme of Projective Space of dimension 2 over Rational Field defined by:
  x^2 + x*y + 2*y*z

Kwankyu

unread,
Oct 30, 2023, 10:27:58 AM10/30/23
to sage-support
Now with (draft) PR


the ask.sagemath problem is solved by

P2.<x,y,z> = ProjectiveSpace(QQ, 2)
f = 2*x^5 - 4*x^3*y*z + x^2*y*z^2 + 2*x*y^3*z + 2*x*y^2*z^2+ y^5
C = Curve(f)
kC = C.function_field()
K = kC.gen().differential().divisor()  # canonical divisor
basis = (-K).basis_function_space()
Basis = [C._pull_from_function_field(f) for f in basis]
phi = C.hom(Basis, P2)
D = phi.image()  # conic
assert D.degree() == 2
D

Reply all
Reply to author
Forward
0 new messages