r"""
Superelliptic curves
====================

A *superelliptic curve* is a smooth projective curve over a field `K` which
is given generically by an equation of the form

.. MATH::

    Y:\; y^n = f(x),

where `n\geq 2` and `f\in K[x]` is  a polynomial over `K`, of degree at least
`2` (and of degree at least `3` if `n=2`). Let

.. MATH::

    f = c\cdot \prod_i f_i^{m_i}

be the prime factorization of `f` (where `c\in K^\times` and the `f_i` are monic,
irreducible and pairwise distinct). We assume that the gcd of the `m_i` is prime
to `n`. This means that the defining equation is irreducible and the curve
`Y` can be considered as a Kummer cover of `X=\mathbb{P}^1_K` of degree `n`.

In this module we define a class ``SuperellipticCurve`` which is a subclasses
of ``SmoothProjectiveCurve`` and whose objects represent superelliptic curves
as above.


AUTHORS:

- Stefan Wewers (2018-5-18): initial version


EXAMPLES::

    sage: from mclf import *
    sage: R.<x> = QQ[]
    sage: Y = SuperellipticCurve(x^4-1, 3)
    sage: Y
    superelliptic curve y^3 = x^4 - 1 over Rational Field
    sage: Y.genus()
    3
    sage: Y.kummer_gen()
    y
    sage: Y.polynomial()
    x^4 - 1
    sage: Y.covering_degree()
    3

.. TODO::

    - override those methods of ``SmoothProjectiveCurve`` where we have a
      faster algorithm in the superelliptic cases

"""

#*****************************************************************************
#       Copyright (C) 2016-2018 Stefan Wewers <stefan.wewers@uni-ulm.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#                  https://www.gnu.org/licenses/
#*****************************************************************************

from sage.all import ZZ, gcd, FunctionField, PolynomialRing
from mclf.curves.smooth_projective_curves import SmoothProjectiveCurve


class SuperellipticCurve(SmoothProjectiveCurve):
    r"""
    Return the superelliptic curve with equation `y^n=f(x)`.

    INPUT:

    - ``f`` -- a nonconstant polynomial over a field `K`
    - ``n`` -- an integer `\geq 2`
    - ``name`` -- a string (default 'y')

    OUTPUT:

    the smooth projective curve `Y` over `K` given generically by the equation

    .. MATH::

        Y:\; y^n = f(x).

    This means that the function field of `Y` is an extension of the rational
    function field in `x` generated by an element `y` (the Kummer generator)
    satisfying the above equation.

    It is assumed that the gcd of the multiplicities of the irreducible factors
    of `f` is prime to `n`. Thus, the curve `Y` is a cover of `\mathbb{P}^1_K`
    of degree `n`. If this condition is not met, an error is raised. ``name`` is
    the name given to the Kummer generator `y`.

    """

    def __init__(self, f, n, name='y'):

        R = f.parent()
        assert R.variable_name() != name, "variable names must be distinct"
        k = R.base_ring()
        assert k.characteristic() == 0 or ZZ(n).gcd(k.characteristic()) == 1, "the characteristic of the base field must be prime to n"
        ff = f.factor()
        assert gcd([m for g, m in ff]+[n]) == 1, "the equation y^n=f(x) must be absolutely irreducible"
        self._n = n
        self._f = f
        self._ff = ff
        self._name = name
        FX = FunctionField(k, R.variable_name())
        S = PolynomialRing(FX, 'T')
        T = S.gen()
        FY = FX.extension(T**n - FX(f), name)
        self._function_field = FY
        self._constant_base_field = k
        self._extra_extension_degree = ZZ(1)
        self._covering_degree = n
        self._coordinate_functions = self.coordinate_functions()
        self._field_of_constants_degree = ZZ(1)
        self._is_separable = True



    def __repr__(self):
        return "superelliptic curve %s^%s = %s over %s"%(self.kummer_gen(), self.covering_degree(), self.polynomial(), self.constant_base_field())


    def covering_degree(self):
        r""" Return the covering degree.

        If the curve is given by the equation `y^n =f(x)` then the covering degree
        degree is `n`.

        """
        return self._covering_degree


    def polynomial(self):
        r""" Return the polynomial defining this curve.

        If the curve is given by the equation `y^n =f(x)` then `f` is this
        polynomial.

        """
        return self._f


    def kummer_gen(self):
        r""" Return the Kummer generator of this superelliptic curve.

        If the curve is given by the equation `y^n =f(x)` then the Kummer
        generator is the element `y` of the the function field.

        """
        return self.function_field().gen()
