def __do_check(v): """ This is used internally by the sanity check code. """ for i,a in enumerate(v): global sanity sanity = a print i, sys.stdout.flush() if check_using_magma: if magma(hnf(a)[0]) != magma(a).EchelonForm(): print "bug computing hnf of a matrix" print 'a = matrix(ZZ, %s, %s, %s)'%(a.nrows(), a.ncols(), a.list()) return else: if hnf(a)[0] != a.echelon_form(algorithm = 'pari'): print "bug computing hnf of a matrix" print 'a = matrix(ZZ, %s, %s, %s)'%(a.nrows(), a.ncols(), a.list()) return print " (done)"
def __do_check(v): """ This is used internally by the sanity check code. """ for i,a in enumerate(v): global sanity sanity = a print i, sys.stdout.flush() if check_using_magma: if magma(hnf(a)[0]) != magma(a).EchelonForm(): print "bug computing hnf of a matrix" print 'a = matrix(ZZ, %s, %s, %s)'%(a.nrows(), a.ncols(), a.list()) return else: if hnf(a)[0] != a.echelon_form('pari'): print "bug computing hnf of a matrix" print 'a = matrix(ZZ, %s, %s, %s)'%(a.nrows(), a.ncols(), a.list()) return print " (done)"
def __do_check(v): """ This is used internally by the sanity check code. """ for i, a in enumerate(v): global sanity sanity = a print(i, end=" ") if check_using_magma: if magma(hnf(a)[0]) != magma(a).EchelonForm(): print("bug computing hnf of a matrix") print('a = matrix(ZZ, %s, %s, %s)' % (a.nrows(), a.ncols(), a.list())) return else: if hnf(a)[0] != a.echelon_form(algorithm='pari'): print("bug computing hnf of a matrix") print('a = matrix(ZZ, %s, %s, %s)' % (a.nrows(), a.ncols(), a.list())) return print(" (done)")
def benchmark_magma_hnf(nrange, bits=4): """ EXAMPLES: sage: import sage.matrix.matrix_integer_dense_hnf as hnf sage: hnf.benchmark_magma_hnf([50,100],32) # optional - magma ('magma', 50, 32, ...), ('magma', 100, 32, ...), """ from sage.interfaces.all import magma b = 2**bits for n in nrange: a = magma('MatrixAlgebra(IntegerRing(),%s)![Random(%s,%s) : i in [1..%s]]'%(n,-b,b,n**2)) t = magma.cputime() h = a.EchelonForm() tm = magma.cputime(t) print '%s,'%(('magma', n, bits, tm),)
def matrix_multiply_QQ(n=100, bnd=2, system='sage', times=1): """ Given an n x n matrix A over QQ with random entries whose numerators and denominators are bounded by bnd, compute A * (A+1). INPUT: - ``n`` - matrix dimension (default: ``300``) - ``bnd`` - numerator and denominator bound (default: ``bnd``) - ``system`` - either 'sage' or 'magma' (default: 'sage') - ``times`` - number of experiments (default: ``1``) EXAMPLES:: sage: import sage.matrix.benchmark as b sage: ts = b.matrix_multiply_QQ(100) sage: tm = b.matrix_multiply_QQ(100, system='magma') # optional - magma """ if system == 'sage': A = random_matrix(QQ, n, n, num_bound=bnd, den_bound=bnd) B = A + 1 t = cputime() for z in range(times): v = A * B return cputime(t)/times elif system == 'magma': A = magma(random_matrix(QQ, n, n, num_bound=bnd, den_bound=bnd)) code = """ n := %s; A := %s; B := A + 1; t := Cputime(); for z in [1..%s] do K := A * B; end for; s := Cputime(t); """%(n, A.name(), times) if verbose: print(code) magma.eval(code) return float(magma.eval('s'))/times else: raise ValueError('unknown system "%s"'%system)
def matrix_multiply_QQ(n=100, bnd=2, system='sage', times=1): """ Given an n x n matrix A over QQ with random entries whose numerators and denominators are bounded by bnd, compute A * (A+1). INPUT: - ``n`` - matrix dimension (default: ``300``) - ``bnd`` - numerator and denominator bound (default: ``bnd``) - ``system`` - either 'sage' or 'magma' (default: 'sage') - ``times`` - number of experiments (default: ``1``) EXAMPLES:: sage: import sage.matrix.benchmark as b sage: ts = b.matrix_multiply_QQ(100) sage: tm = b.matrix_multiply_QQ(100, system='magma') # optional - magma """ if system == 'sage': A = random_matrix(QQ, n, n, num_bound=bnd, den_bound=bnd) B = A + 1 t = cputime() for z in range(times): v = A * B return cputime(t)/times elif system == 'magma': A = magma(random_matrix(QQ, n, n, num_bound=bnd, den_bound=bnd)) code = """ n := %s; A := %s; B := A + 1; t := Cputime(); for z in [1..%s] do K := A * B; end for; s := Cputime(t); """%(n, A.name(), times) if verbose: print code magma.eval(code) return float(magma.eval('s'))/times else: raise ValueError('unknown system "%s"'%system)
def dokchitser(self, prec=53, max_imaginary_part=0, max_asymp_coeffs=40, algorithm='gp'): r""" Return interface to Tim Dokchitser's program for computing with the `L`-series of this elliptic curve; this provides a way to compute Taylor expansions and higher derivatives of `L`-series. INPUT: - ``prec`` -- integer (bits precision) - ``max_imaginary_part`` -- real number - ``max_asymp_coeffs`` -- integer - ``algorithm`` -- string: 'gp' or 'magma' .. note:: If algorithm='magma', then the precision is in digits rather than bits and the object returned is a Magma L-series, which has different functionality from the Sage L-series. EXAMPLES:: sage: E = EllipticCurve('37a') sage: L = E.lseries().dokchitser() sage: L(2) 0.381575408260711 sage: L = E.lseries().dokchitser(algorithm='magma') # optional - magma sage: L.Evaluate(2) # optional - magma 0.38157540826071121129371040958008663667709753398892116 If the curve has too large a conductor, it isn't possible to compute with the `L`-series using this command. Instead a ``RuntimeError`` is raised:: sage: e = EllipticCurve([1,1,0,-63900,-1964465932632]) sage: L = e.lseries().dokchitser(15) Traceback (most recent call last): ... RuntimeError: Unable to create L-series, due to precision or other limits in PARI. """ if algorithm == 'magma': from sage.interfaces.all import magma return magma(self.__E).LSeries(Precision=prec) from sage.lfunctions.all import Dokchitser key = (prec, max_imaginary_part, max_asymp_coeffs) try: return self.__dokchitser[key] except KeyError: pass except AttributeError: self.__dokchitser = {} L = Dokchitser(conductor=self.__E.conductor(), gammaV=[0, 1], weight=2, eps=self.__E.root_number(), poles=[], prec=prec) gp = L.gp() s = 'e = ellinit(%s);' % list(self.__E.minimal_model().a_invariants()) s += 'a(k) = ellak(e, k);' L.init_coeffs('a(k)', 1, pari_precode=s, max_imaginary_part=max_imaginary_part, max_asymp_coeffs=max_asymp_coeffs) L.rename('Dokchitser L-function associated to %s' % self.__E) self.__dokchitser[key] = L return L
def dokchitser(self, prec=53, max_imaginary_part=0, max_asymp_coeffs=40, algorithm='gp'): r""" Return interface to Tim Dokchitser's program for computing with the L-series of this elliptic curve; this provides a way to compute Taylor expansions and higher derivatives of $L$-series. INPUT: prec -- integer (bits precision) max_imaginary_part -- real number max_asymp_coeffs -- integer algorithm -- string: 'gp' or 'magma' \note{If algorithm='magma', then the precision is in digits rather than bits and the object returned is a Magma L-series, which has different functionality from the Sage L-series.} EXAMPLES:: sage: E = EllipticCurve('37a') sage: L = E.lseries().dokchitser() sage: L(2) 0.381575408260711 sage: L = E.lseries().dokchitser(algorithm='magma') # optional - magma sage: L.Evaluate(2) # optional - magma 0.38157540826071121129371040958008663667709753398892116 If the curve has too large a conductor, it isn't possible to compute with the L-series using this command. Instead a RuntimeError is raised:: sage: e = EllipticCurve([1,1,0,-63900,-1964465932632]) sage: L = e.lseries().dokchitser(15) Traceback (most recent call last): ... RuntimeError: Unable to create L-series, due to precision or other limits in PARI. """ if algorithm == 'magma': from sage.interfaces.all import magma return magma(self.__E).LSeries(Precision = prec) from sage.lfunctions.all import Dokchitser key = (prec, max_imaginary_part, max_asymp_coeffs) try: return self.__dokchitser[key] except KeyError: pass except AttributeError: self.__dokchitser = {} L = Dokchitser(conductor = self.__E.conductor(), gammaV = [0,1], weight = 2, eps = self.__E.root_number(), poles = [], prec = prec) gp = L.gp() s = 'e = ellinit(%s);'%list(self.__E.minimal_model().a_invariants()) s += 'a(k) = ellak(e, k);' L.init_coeffs('a(k)', 1, pari_precode = s, max_imaginary_part=max_imaginary_part, max_asymp_coeffs=max_asymp_coeffs) L.rename('Dokchitser L-function associated to %s'%self.__E) self.__dokchitser[key] = L return L
def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, algorithm='default'): r""" Returns a hyperelliptic curve with the given Igusa-Clebsch invariants up to scaling. The output is a curve over the field in which the Igusa-Clebsch invariants are given. The output curve is unique up to isomorphism over the algebraic closure. If no such curve exists over the given field, then raise a ValueError. INPUT: - ``i`` - list or tuple of length 4 containing the four Igusa-Clebsch invariants: I2,I4,I6,I10. - ``reduced`` - Boolean (default = True) If True, tries to reduce the polynomial defining the hyperelliptic curve using the function :func:`reduce_polynomial` (see the :func:`reduce_polynomial` documentation for more details). - ``precision`` - integer (default = None) Which precision for real and complex numbers should the reduction use. This only affects the reduction, not the correctness. If None, the algorithm uses the default 53 bit precision. - ``algorithm`` - ``'default'`` or ``'magma'``. If set to ``'magma'``, uses Magma to parameterize Mestre's conic (needs Magma to be installed). OUTPUT: A hyperelliptic curve object. EXAMPLE: Examples over the rationals:: sage: HyperellipticCurve_from_invariants([3840,414720,491028480,2437709561856]) Traceback (most recent call last): ... NotImplementedError: Reduction of hyperelliptic curves not yet implemented. See trac #14755 and #14756. sage: HyperellipticCurve_from_invariants([3840,414720,491028480,2437709561856],reduced = False) Hyperelliptic Curve over Rational Field defined by y^2 = -x^6 + 4410*x^5 - 540*x^4 + 4320*x^3 - 19440*x^2 + 46656*x - 46656 sage: HyperellipticCurve_from_invariants([21, 225/64, 22941/512, 1]) Traceback (most recent call last): ... NotImplementedError: Reduction of hyperelliptic curves not yet implemented. See trac #14755 and #14756. An example over a finite field:: sage: HyperellipticCurve_from_invariants([GF(13)(1),3,7,5]) Hyperelliptic Curve over Finite Field of size 13 defined by y^2 = 8*x^5 + 5*x^4 + 5*x^2 + 9*x + 3 An example over a number field:: sage: K = QuadraticField(353, 'a') sage: H = HyperellipticCurve_from_invariants([21, 225/64, 22941/512, 1], reduced = false) sage: f = K['x'](H.hyperelliptic_polynomials()[0]) If the Mestre Conic defined by the Igusa-Clebsch invariants has no rational points, then there exists no hyperelliptic curve over the base field with the given invariants.:: sage: HyperellipticCurve_from_invariants([1,2,3,4]) Traceback (most recent call last): ... ValueError: No such curve exists over Rational Field as there are no rational points on Projective Conic Curve over Rational Field defined by -2572155000*u^2 - 317736000*u*v + 1250755459200*v^2 + 2501510918400*u*w + 39276887040*v*w + 2736219686912*w^2 Mestre's algorithm only works for generic curves of genus two, so another algorithm is needed for those curves with extra automorphism. See also :trac:`12199`:: sage: P.<x> = QQ[] sage: C = HyperellipticCurve(x^6+1) sage: i = C.igusa_clebsch_invariants() sage: HyperellipticCurve_from_invariants(i) Traceback (most recent call last): ... TypeError: F (=0) must have degree 2 Igusa-Clebsch invariants also only work over fields of charateristic different from 2, 3, and 5, so another algorithm will be needed for fields of those characteristics. See also :trac:`12200`:: sage: P.<x> = GF(3)[] sage: HyperellipticCurve(x^6+x+1).igusa_clebsch_invariants() Traceback (most recent call last): ... NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves not implemented in characteristics 2, 3, and 5 sage: HyperellipticCurve_from_invariants([GF(5)(1),1,0,1]) Traceback (most recent call last): ... ZeroDivisionError: Inverse does not exist. ALGORITHM: This is Mestre's algorithm [M1991]_. Our implementation is based on the formulae on page 957 of [LY2001]_, cross-referenced with [W1999]_ to correct typos. First construct Mestre's conic using the :func:`Mestre_conic` function. Parametrize the conic if possible. Let `f_1, f_2, f_3` be the three coordinates of the parametrization of the conic by the projective line, and change them into one variable by letting `F_i = f_i(t, 1)`. Note that each `F_i` has degree at most 2. Then construct a sextic polynomial `f = \sum_{0<=i,j,k<=3}{c_{ijk}*F_i*F_j*F_k}`, where `c_{ijk}` are defined as rational functions in the invariants (see the source code for detailed formulae for `c_{ijk}`). The output is the hyperelliptic curve `y^2 = f`. REFERENCES: .. [LY2001] K. Lauter and T. Yang, "Computing genus 2 curves from invariants on the Hilbert moduli space", Journal of Number Theory 131 (2011), pages 936 - 958 .. [M1991] J.-F. Mestre, "Construction de courbes de genre 2 a partir de leurs modules", in Effective methods in algebraic geometry (Castiglioncello, 1990), volume 94 of Progr. Math., pages 313 - 334 .. [W1999] P. van Wamelen, Pari-GP code, section "thecubic" https://www.math.lsu.edu/~wamelen/Genus2/FindCurve/igusa2curve.gp """ from sage.structure.sequence import Sequence i = Sequence(i) k = i.universe() try: k = k.fraction_field() except (TypeError, AttributeError, NotImplementedError): pass MConic, x, y, z = Mestre_conic(i, xyz=True) if k.is_finite(): reduced = False t = k['t'].gen() if algorithm == 'magma': from sage.interfaces.all import magma from sage.misc.sage_eval import sage_eval if MConic.has_rational_point(algorithm='magma'): parametrization = [l.replace('$.1', 't').replace('$.2', 'u') \ for l in str(magma(MConic).Parametrization()).splitlines()[4:7]] [F1, F2, F3] = [sage_eval(p, locals={'t':t,'u':1,'a':k.gen()}) \ for p in parametrization] else: raise ValueError("No such curve exists over %s as there are no " \ "rational points on %s" % (k, MConic)) else: if MConic.has_rational_point(): parametrization = MConic.parametrization(morphism=False)[0] [F1, F2, F3] = [p(t, 1) for p in parametrization] else: raise ValueError("No such curve exists over %s as there are no " \ "rational points on %s" % (k, MConic)) # setting the cijk from Mestre's algorithm c111 = 12*x*y - 2*y/3 - 4*z c112 = -18*x**3 - 12*x*y - 36*y**2 - 2*z c113 = -9*x**3 - 36*x**2*y -4*x*y - 6*x*z - 18*y**2 c122 = c113 c123 = -54*x**4 - 36*x**2*y - 36*x*y**2 - 6*x*z - 4*y**2 - 24*y*z c133 = -27*x**4/2 - 72*x**3*y - 6*x**2*y - 9*x**2*z - 39*x*y**2 - \ 36*y**3 - 2*y*z c222 = -27*x**4 - 18*x**2*y - 6*x*y**2 - 8*y**2/3 + 2*y*z c223 = 9*x**3*y - 27*x**2*z + 6*x*y**2 + 18*y**3 - 8*y*z c233 = -81*x**5/2 - 27*x**3*y - 9*x**2*y**2 - 4*x*y**2 + 3*x*y*z - 6*z**2 c333 = 27*x**4*y/2 - 27*x**3*z/2 + 9*x**2*y**2 + 3*x*y**3 - 6*x*y*z + \ 4*y**3/3 - 10*y**2*z # writing out the hyperelliptic curve polynomial f = c111*F1**3 + c112*F1**2*F2 + c113*F1**2*F3 + c122*F1*F2**2 + \ c123*F1*F2*F3 + c133*F1*F3**2 + c222*F2**3 + c223*F2**2*F3 + \ c233*F2*F3**2 + c333*F3**3 try: f = f*f.denominator() # clear the denominator except (AttributeError, TypeError): pass if reduced: raise NotImplementedError("Reduction of hyperelliptic curves not " \ "yet implemented. " \ "See trac #14755 and #14756.") return HyperellipticCurve(f)
def HyperellipticCurve_from_invariants(i, reduced=True, precision=None, algorithm='default'): r""" Returns a hyperelliptic curve with the given Igusa-Clebsch invariants up to scaling. The output is a curve over the field in which the Igusa-Clebsch invariants are given. The output curve is unique up to isomorphism over the algebraic closure. If no such curve exists over the given field, then raise a ValueError. INPUT: - ``i`` - list or tuple of length 4 containing the four Igusa-Clebsch invariants: I2,I4,I6,I10. - ``reduced`` - Boolean (default = True) If True, tries to reduce the polynomial defining the hyperelliptic curve using the function :func:`reduce_polynomial` (see the :func:`reduce_polynomial` documentation for more details). - ``precision`` - integer (default = None) Which precision for real and complex numbers should the reduction use. This only affects the reduction, not the correctness. If None, the algorithm uses the default 53 bit precision. - ``algorithm`` - ``'default'`` or ``'magma'``. If set to ``'magma'``, uses Magma to parameterize Mestre's conic (needs Magma to be installed). OUTPUT: A hyperelliptic curve object. EXAMPLES: Examples over the rationals:: sage: HyperellipticCurve_from_invariants([3840,414720,491028480,2437709561856]) Traceback (most recent call last): ... NotImplementedError: Reduction of hyperelliptic curves not yet implemented. See trac #14755 and #14756. sage: HyperellipticCurve_from_invariants([3840,414720,491028480,2437709561856],reduced = False) Hyperelliptic Curve over Rational Field defined by y^2 = -46656*x^6 + 46656*x^5 - 19440*x^4 + 4320*x^3 - 540*x^2 + 4410*x - 1 sage: HyperellipticCurve_from_invariants([21, 225/64, 22941/512, 1]) Traceback (most recent call last): ... NotImplementedError: Reduction of hyperelliptic curves not yet implemented. See trac #14755 and #14756. An example over a finite field:: sage: HyperellipticCurve_from_invariants([GF(13)(1),3,7,5]) Hyperelliptic Curve over Finite Field of size 13 defined by y^2 = 8*x^5 + 5*x^4 + 5*x^2 + 9*x + 3 An example over a number field:: sage: K = QuadraticField(353, 'a') sage: H = HyperellipticCurve_from_invariants([21, 225/64, 22941/512, 1], reduced = false) sage: f = K['x'](H.hyperelliptic_polynomials()[0]) If the Mestre Conic defined by the Igusa-Clebsch invariants has no rational points, then there exists no hyperelliptic curve over the base field with the given invariants.:: sage: HyperellipticCurve_from_invariants([1,2,3,4]) Traceback (most recent call last): ... ValueError: No such curve exists over Rational Field as there are no rational points on Projective Conic Curve over Rational Field defined by -2572155000*u^2 - 317736000*u*v + 1250755459200*v^2 + 2501510918400*u*w + 39276887040*v*w + 2736219686912*w^2 Mestre's algorithm only works for generic curves of genus two, so another algorithm is needed for those curves with extra automorphism. See also :trac:`12199`:: sage: P.<x> = QQ[] sage: C = HyperellipticCurve(x^6+1) sage: i = C.igusa_clebsch_invariants() sage: HyperellipticCurve_from_invariants(i) Traceback (most recent call last): ... TypeError: F (=0) must have degree 2 Igusa-Clebsch invariants also only work over fields of characteristic different from 2, 3, and 5, so another algorithm will be needed for fields of those characteristics. See also :trac:`12200`:: sage: P.<x> = GF(3)[] sage: HyperellipticCurve(x^6+x+1).igusa_clebsch_invariants() Traceback (most recent call last): ... NotImplementedError: Invariants of binary sextics/genus 2 hyperelliptic curves not implemented in characteristics 2, 3, and 5 sage: HyperellipticCurve_from_invariants([GF(5)(1),1,0,1]) Traceback (most recent call last): ... ZeroDivisionError: Inverse does not exist. ALGORITHM: This is Mestre's algorithm [M1991]_. Our implementation is based on the formulae on page 957 of [LY2001]_, cross-referenced with [W1999]_ to correct typos. First construct Mestre's conic using the :func:`Mestre_conic` function. Parametrize the conic if possible. Let `f_1, f_2, f_3` be the three coordinates of the parametrization of the conic by the projective line, and change them into one variable by letting `F_i = f_i(t, 1)`. Note that each `F_i` has degree at most 2. Then construct a sextic polynomial `f = \sum_{0<=i,j,k<=3}{c_{ijk}*F_i*F_j*F_k}`, where `c_{ijk}` are defined as rational functions in the invariants (see the source code for detailed formulae for `c_{ijk}`). The output is the hyperelliptic curve `y^2 = f`. REFERENCES: .. [LY2001] \K. Lauter and T. Yang, "Computing genus 2 curves from invariants on the Hilbert moduli space", Journal of Number Theory 131 (2011), pages 936 - 958 .. [M1991] \J.-F. Mestre, "Construction de courbes de genre 2 a partir de leurs modules", in Effective methods in algebraic geometry (Castiglioncello, 1990), volume 94 of Progr. Math., pages 313 - 334 .. [W1999] \P. van Wamelen, Pari-GP code, section "thecubic" https://www.math.lsu.edu/~wamelen/Genus2/FindCurve/igusa2curve.gp """ from sage.structure.sequence import Sequence i = Sequence(i) k = i.universe() try: k = k.fraction_field() except (TypeError, AttributeError, NotImplementedError): pass MConic, x, y, z = Mestre_conic(i, xyz=True) if k.is_finite(): reduced = False t = k['t'].gen() if algorithm == 'magma': from sage.interfaces.all import magma from sage.misc.sage_eval import sage_eval if MConic.has_rational_point(algorithm='magma'): parametrization = [l.replace('$.1', 't').replace('$.2', 'u') \ for l in str(magma(MConic).Parametrization()).splitlines()[4:7]] [F1, F2, F3] = [sage_eval(p, locals={'t':t,'u':1,'a':k.gen()}) \ for p in parametrization] else: raise ValueError("No such curve exists over %s as there are no " \ "rational points on %s" % (k, MConic)) else: if MConic.has_rational_point(): parametrization = MConic.parametrization(morphism=False)[0] [F1, F2, F3] = [p(t, 1) for p in parametrization] else: raise ValueError("No such curve exists over %s as there are no " \ "rational points on %s" % (k, MConic)) # setting the cijk from Mestre's algorithm c111 = 12 * x * y - 2 * y / 3 - 4 * z c112 = -18 * x**3 - 12 * x * y - 36 * y**2 - 2 * z c113 = -9 * x**3 - 36 * x**2 * y - 4 * x * y - 6 * x * z - 18 * y**2 c122 = c113 c123 = -54 * x**4 - 36 * x**2 * y - 36 * x * y**2 - 6 * x * z - 4 * y**2 - 24 * y * z c133 = -27*x**4/2 - 72*x**3*y - 6*x**2*y - 9*x**2*z - 39*x*y**2 - \ 36*y**3 - 2*y*z c222 = -27 * x**4 - 18 * x**2 * y - 6 * x * y**2 - 8 * y**2 / 3 + 2 * y * z c223 = 9 * x**3 * y - 27 * x**2 * z + 6 * x * y**2 + 18 * y**3 - 8 * y * z c233 = -81 * x**5 / 2 - 27 * x**3 * y - 9 * x**2 * y**2 - 4 * x * y**2 + 3 * x * y * z - 6 * z**2 c333 = 27*x**4*y/2 - 27*x**3*z/2 + 9*x**2*y**2 + 3*x*y**3 - 6*x*y*z + \ 4*y**3/3 - 10*y**2*z # writing out the hyperelliptic curve polynomial f = c111*F1**3 + c112*F1**2*F2 + c113*F1**2*F3 + c122*F1*F2**2 + \ c123*F1*F2*F3 + c133*F1*F3**2 + c222*F2**3 + c223*F2**2*F3 + \ c233*F2*F3**2 + c333*F3**3 try: f = f * f.denominator() # clear the denominator except (AttributeError, TypeError): pass if reduced: raise NotImplementedError("Reduction of hyperelliptic curves not " \ "yet implemented. " \ "See trac #14755 and #14756.") return HyperellipticCurve(f)