# Path: abelfunctions/puiseux.py
# def puiseux(f, alpha, beta=None, order=None, parametric=True):
#     r"""Singular parts of the Puiseux series above :math:`x=\alpha`.
# 
#     Parameters
#     ----------
#     f : polynomial
#         A plane algebraic curve in `x` and `y`.
#     alpha : complex
#         The x-point over which to compute the Puiseux series of `f`.
#     t : variable
#         Variable used in the Puiseux series expansions.
#     beta : complex
#         (Optional) The y-point at which to compute the Puiseux series.
#     order : int
#         (Default: `None`) If provided, returns Puiseux series expansions
#         up the the specified order.
# 
#     Returns
#     -------
#     list of PuiseuxTSeries
# 
#     """
#     R = f.parent()
#     x,y = R.gens()
# 
#     # recenter the curve at x=alpha
#     if alpha in [infinity,'oo']:
#         alpha = infinity
#         d = f.degree(x)
#         F = f(1/x,y)*x**d
#         n,d = F.numerator(), F.denominator()
#         falpha,_ = n.polynomial(x).quo_rem(d.univariate_polynomial())
#         falpha = falpha(x).numerator()
#     else:
#         falpha = f(x+alpha,y)
# 
#     # determine the points on the curve lying above x=alpha
#     R = falpha.parent()
#     x,y = R.gens()
#     g, transform = almost_monicize(falpha)
#     galpha = R(g(0,y)).univariate_polynomial()
#     betas = galpha.roots(ring=QQbar, multiplicities=False)
# 
#     # filter for requested value of beta. raise error if not found
#     if not beta is None:
#         betas = [b for b in betas if b == beta]
#         if not betas:
#             raise ValueError('The point ({0}, {1}) is not on the '
#                              'curve {2}.'.format(alpha, beta, f))
# 
#     # for each (alpha, beta) determine the corresponding singular parts of the
#     # Puiseux series expansions. note that there may be multiple, distinct
#     # places above the same point.
#     singular_parts = []
#     for beta in betas:
#         H = g(x,y+beta)
#         singular_part_ab = puiseux_rational(H)
# 
#         # recenter the result back to (alpha, beta) from (0,0)
#         for G,P,Q in singular_part_ab:
#             Q += beta
#             Q = Q/transform.univariate_polynomial()(P)
#             if alpha == infinity:
#                 P = 1/P
#             else:
#                 P += alpha
# 
#             # append to list of singular data
#             singular_parts.append((G,P,Q))
# 
#     # instantiate PuiseuxTSeries from the singular data
#     series = [PuiseuxTSeries(f, alpha, singular_data, order=order)
#               for singular_data in singular_parts]
#     return series
# 
# Path: abelfunctions/puiseux_series_ring.py
# def PuiseuxSeriesRing(base_ring, name=None, names=None, default_prec=None, sparse=False):
#     if names is not None:
#         name = names
#     if name is None:
#         raise TypeError('You must specify the name of the indeterminate of the Puiseux series ring.')
# 
#     if default_prec is None:
#         from sage.misc.defaults import series_precision
#         default_prec = series_precision()
# 
#     global puiseux_series
#     key = (base_ring, name, default_prec, sparse)
#     if key in puiseux_series:
#         x = puiseux_series[key]()
#         if x is not None: return x
# 
#     if isinstance(base_ring, Field):
#         R = PuiseuxSeriesRing_field(base_ring, name, default_prec, sparse)
#     elif isinstance(base_ring, IntegralDomain):
#         R = PuiseuxSeriesRing_domain(base_ring, name, default_prec, sparse)
#     elif isinstance(base_ring, CommutativeRing):
#         R = PuiseuxSeriesRing_generic(base_ring, name, default_prec, sparse)
#     else:
#         raise TypeError("base_ring must be a commutative ring")
#     puiseux_series[key] = weakref.ref(R)
#     return R


from abelfunctions.puiseux import puiseux
from abelfunctions.puiseux_series_ring import PuiseuxSeriesRing
from sage.all import cached_function
from sage.functions.other import ceil
from sage.matrix.constructor import Matrix
from sage.rings.polynomial.all import PolynomialRing
from sage.rings.rational_field import QQ
from sage.rings.qqbar import QQbar
    from sage.all import singular
import warnings
r"""Integral Basis :mod:`abelfunctions.integralbasis`
=================================================

A module for computing integral bases of algebraic function fields of the form
:math:`O(X) = \mathbb{C}[x,y] / (f(x,y))` where :math:`X : f(x,y) = 0`.

For polynomials over :math:`\mathbb{Q}[x,y]` we use Singular's very fast
implementation.

The slow / general-purpose algorithm is based off of the paper "An Algorithm
for Computing an Integral Basis in an Algebraic Function Field" by Mark van
Hoeij [vHoeij]_.

An integral basis for :math:`O(X)` is a set of :math:`\beta_i \in
\mathbb{C}(x,y)` such that

.. math::

    \overline{O(X)} = \beta_1\mathbb{C}[x,y] + \cdots + \beta_g\mathbb{C}[x,y].

This data is necessary for computing a basis for the space of holomorphic

# Path: abelfunctions/puiseux.py
# def puiseux(f, alpha, beta=None, order=None, parametric=True):
#     r"""Singular parts of the Puiseux series above :math:`x=\alpha`.
# 
#     Parameters
#     ----------
#     f : polynomial
#         A plane algebraic curve in `x` and `y`.
#     alpha : complex
#         The x-point over which to compute the Puiseux series of `f`.
#     t : variable
#         Variable used in the Puiseux series expansions.
#     beta : complex
#         (Optional) The y-point at which to compute the Puiseux series.
#     order : int
#         (Default: `None`) If provided, returns Puiseux series expansions
#         up the the specified order.
# 
#     Returns
#     -------
#     list of PuiseuxTSeries
# 
#     """
#     R = f.parent()
#     x,y = R.gens()
# 
#     # recenter the curve at x=alpha
#     if alpha in [infinity,'oo']:
#         alpha = infinity
#         d = f.degree(x)
#         F = f(1/x,y)*x**d
#         n,d = F.numerator(), F.denominator()
#         falpha,_ = n.polynomial(x).quo_rem(d.univariate_polynomial())
#         falpha = falpha(x).numerator()
#     else:
#         falpha = f(x+alpha,y)
# 
#     # determine the points on the curve lying above x=alpha
#     R = falpha.parent()
#     x,y = R.gens()
#     g, transform = almost_monicize(falpha)
#     galpha = R(g(0,y)).univariate_polynomial()
#     betas = galpha.roots(ring=QQbar, multiplicities=False)
# 
#     # filter for requested value of beta. raise error if not found
#     if not beta is None:
#         betas = [b for b in betas if b == beta]
#         if not betas:
#             raise ValueError('The point ({0}, {1}) is not on the '
#                              'curve {2}.'.format(alpha, beta, f))
# 
#     # for each (alpha, beta) determine the corresponding singular parts of the
#     # Puiseux series expansions. note that there may be multiple, distinct
#     # places above the same point.
#     singular_parts = []
#     for beta in betas:
#         H = g(x,y+beta)
#         singular_part_ab = puiseux_rational(H)
# 
#         # recenter the result back to (alpha, beta) from (0,0)
#         for G,P,Q in singular_part_ab:
#             Q += beta
#             Q = Q/transform.univariate_polynomial()(P)
#             if alpha == infinity:
#                 P = 1/P
#             else:
#                 P += alpha
# 
#             # append to list of singular data
#             singular_parts.append((G,P,Q))
# 
#     # instantiate PuiseuxTSeries from the singular data
#     series = [PuiseuxTSeries(f, alpha, singular_data, order=order)
#               for singular_data in singular_parts]
#     return series
# 
# Path: abelfunctions/puiseux_series_ring.py
# def PuiseuxSeriesRing(base_ring, name=None, names=None, default_prec=None, sparse=False):
#     if names is not None:
#         name = names
#     if name is None:
#         raise TypeError('You must specify the name of the indeterminate of the Puiseux series ring.')
# 
#     if default_prec is None:
#         from sage.misc.defaults import series_precision
#         default_prec = series_precision()
# 
#     global puiseux_series
#     key = (base_ring, name, default_prec, sparse)
#     if key in puiseux_series:
#         x = puiseux_series[key]()
#         if x is not None: return x
# 
#     if isinstance(base_ring, Field):
#         R = PuiseuxSeriesRing_field(base_ring, name, default_prec, sparse)
#     elif isinstance(base_ring, IntegralDomain):
#         R = PuiseuxSeriesRing_domain(base_ring, name, default_prec, sparse)
#     elif isinstance(base_ring, CommutativeRing):
#         R = PuiseuxSeriesRing_generic(base_ring, name, default_prec, sparse)
#     else:
#         raise TypeError("base_ring must be a commutative ring")
#     puiseux_series[key] = weakref.ref(R)
#     return R


# Path: abelfunctions/integralbasis.py
from abelfunctions.puiseux import puiseux
from abelfunctions.puiseux_series_ring import PuiseuxSeriesRing
from sage.all import cached_function
from sage.functions.other import ceil
from sage.matrix.constructor import Matrix
from sage.rings.polynomial.all import PolynomialRing
from sage.rings.rational_field import QQ
from sage.rings.qqbar import QQbar
    from sage.all import singular
import warnings

r"""Integral Basis :mod:`abelfunctions.integralbasis`
=================================================

A module for computing integral bases of algebraic function fields of the form
:math:`O(X) = \mathbb{C}[x,y] / (f(x,y))` where :math:`X : f(x,y) = 0`.

For polynomials over :math:`\mathbb{Q}[x,y]` we use Singular's very fast
implementation.

The slow / general-purpose algorithm is based off of the paper "An Algorithm
for Computing an Integral Basis in an Algebraic Function Field" by Mark van
Hoeij [vHoeij]_.

An integral basis for :math:`O(X)` is a set of :math:`\beta_i \in
\mathbb{C}(x,y)` such that

.. math::

    \overline{O(X)} = \beta_1\mathbb{C}[x,y] + \cdots + \beta_g\mathbb{C}[x,y].

This data is necessary for computing a basis for the space of holomorphic

differentials :math:`\Omega_X^1` defined on the Riemann surface :math:`X` which