예제 #1
0
def brackets_to_table(L):
    r"""
    Return a html table enumerating all Lie brackets.

    INPUT:

    - ``L`` -- a Lie algebra
    """
    # if the base ring is QQbar, display coefficients as radicals
    disp = QQbar.options('display_format')
    QQbar.options(display_format="radical")

    rows = []
    for X, Y in combinations(L.basis(), 2):
        Z = X.bracket(Y)
        if Z:
            rows.append((X, Y, Z))
    if not rows:
        return ""

    htmlstr = '<table class="brackets">\n'
    for (X, Y, Z) in rows:
        htmlstr += '<tr>'
        htmlstr += '<td class="brkt">[%s, %s]</td>' % (X, Y)
        htmlstr += '<td class="eq">=</td>'
        htmlstr += '<td class="res">%s</td>' % Z
        htmlstr += '</tr>\n'
    htmlstr += '</table>'
    return htmlstr
    def __cmp__(self, other):
        r"""
        Comparison (using the complex embedding).

        TESTS::

            sage: UCF = UniversalCyclotomicField()
            sage: l = [UCF.gen(3), UCF.gen(3)+1, UCF.gen(5), UCF.gen(5,2),
            ....:      UCF.gen(4), 2*UCF.gen(4), UCF.gen(5)-22/3]
            sage: lQQbar = map(QQbar,l)
            sage: lQQbar.sort()
            sage: l.sort()
            sage: lQQbar == map(QQbar,l)
            True

            sage: for i in range(len(l)):
            ....:     assert l[i] >= l[i] and l[i] <= l[i]
            ....:     for j in range(i):
            ....:         assert l[i] > l[j] and l[j] < l[i]
        """
        if self._obj == other._obj:
            return 0
        else:
            from sage.rings.qqbar import QQbar
            return cmp(QQbar(self), QQbar(other))
예제 #3
0
    def regular_ngon(n):
        r"""
        Return a regular n-gon.

        EXAMPLES::

            sage: from flatsurf.geometry.polygon import polygons

            sage: p = polygons.regular_ngon(17)
            sage: p
            Polygon: (0, 0), (1, 0), ..., (-1/2*a^14 + 15/2*a^12 - 45*a^10 + 275/2*a^8 - 225*a^6 + 189*a^4 - 70*a^2 + 15/2, 1/2*a)
        """
        # The code below crashes for n=4!
        if n==4:
            return polygons.square(QQ(1))
        
        from sage.rings.qqbar import QQbar

        c = QQbar.zeta(n).real()
        s = QQbar.zeta(n).imag()

        field, (c,s) = number_field_elements_from_algebraics((c,s))

        cn = field.one()
        sn = field.zero()
        edges = [(cn,sn)]
        for _ in range(n-1):
            cn,sn = c*cn - s*sn, c*sn + s*cn
            edges.append((cn,sn))

        return Polygons(field)(edges=edges)
예제 #4
0
def segments(points):
    """
    Return the bounded segments of the Voronoi diagram of the given points.

    INPUT:

    - ``points`` -- a list of complex points

    OUTPUT:

    A list of pairs ``(p1, p2)``, where ``p1`` and ``p2`` are the
    endpoints of the segments in the Voronoi diagram.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import discrim, segments
        sage: R.<x,y> = QQ[]
        sage: f = y^3 + x^3 - 1
        sage: disc = discrim(f)
        sage: sorted(segments(disc))
        [(-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316,
          -192951821525958031/90044183378780414),
         (-192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316,
          -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326),
         (192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316,
          144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326),
         (-192951821525958031/90044183378780414,
          192951821525958031/67764026159052316*I - 192951821525958031/67764026159052316),
         (-192951821525958031/90044183378780414, 1/38590364305191606),
         (1/38590364305191606,
          -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326),
         (1/38590364305191606,
          144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326),
         (-5/2*I + 5/2,
          -144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326),
         (-5/2*I + 5/2, 5/2*I + 5/2),
         (5/2*I + 5/2,
          144713866144468523/66040650000519163*I + 167101179147960739/132081300001038326)]

    """
    V = corrected_voronoi_diagram(tuple(points))
    res = set([])
    for region in V.regions().values():
        if region.rays():
            continue
        segments = region.facets()
        for s in segments:
            t = tuple((tuple(v.vector()) for v in s.vertices()))
            if t not in res and not tuple(reversed(t)) in res:
                res.add(t)
    return [(r[0] + QQbar.gen() * r[1], s[0] + QQbar.gen() * s[1])
            for (r, s) in res]
예제 #5
0
    def xseries(self, all_conjugates=True):
        r"""Returns the corresponding x-series.

        Parameters
        ----------
        all_conjugates : bool
            (default: True) If ``True``, returns all conjugates
            x-representations of this Puiseux t-series. If ``False``,
            only returns one representative.

        Returns
        -------
        list
            List of PuiseuxXSeries representations of this PuiseuxTSeries.

        """
        # obtain relevant rings:
        #   o R = parent ring of curve
        #   o L = parent ring of T-series
        #   o S = temporary polynomial ring over base ring of T-series
        #   o P = Puiseux series ring
        L = self.ypart.parent()
        t = L.gen()
        S = L.base_ring()['z']
        z = S.gen()

        R = self.f.parent()
        x,y = R.gens()
        P = PuiseuxSeriesRing(L.base_ring(), str(x))
        x = P.gen()

        # given x = alpha + lambda*t^e solve for t. this involves finding an
        # e-th root of either (1/lambda) or of lambda, depending on e's sign
        ## (A sign on a ramification index ? hm)
        e = self.ramification_index
        abse = abs(e)
        lamb = S(self.xcoefficient)
        order = self.order
        if e > 0:
            phi = lamb*z**e - 1
        else:
            phi = z**abse - lamb
        mu = phi.roots(QQbar, multiplicities=False)[0]

        if all_conjugates:
            zeta_e=QQbar.zeta(abse)
            conjugates = [mu*zeta_e**k for k in range(abse)]
        else:
            conjugates = [mu]
        map(lambda x: x.exactify(), conjugates)

        # determine the resulting x-series
        xseries = []
        for c in conjugates:
            t = self.ypart.parent().gen()
            fconj = self.ypart(c*t)
            p = P(fconj(x**(QQ(1)/e)))
            p = p.add_bigoh(QQ(order+1)/abse)
            xseries.append(p)
        return xseries
예제 #6
0
    def xseries(self, all_conjugates=True):
        r"""Returns the corresponding x-series.

        Parameters
        ----------
        all_conjugates : bool
            (default: True) If ``True``, returns all conjugates
            x-representations of this Puiseux t-series. If ``False``,
            only returns one representative.

        Returns
        -------
        list
            List of PuiseuxXSeries representations of this PuiseuxTSeries.

        """
        # obtain relevant rings:
        #   o R = parent ring of curve
        #   o L = parent ring of T-series
        #   o S = temporary polynomial ring over base ring of T-series
        #   o P = Puiseux series ring
        L = self.ypart.parent()
        t = L.gen()
        S = L.base_ring()['z']
        z = S.gen()

        R = self.f.parent()
        x,y = R.gens()
        P = PuiseuxSeriesRing(L.base_ring(), str(x))
        x = P.gen()

        # given x = alpha + lambda*t^e solve for t. this involves finding an
        # e-th root of either (1/lambda) or of lambda, depending on e's sign
        ## (A sign on a ramification index ? hm)
        e = self.ramification_index
        abse = abs(e)
        lamb = S(self.xcoefficient)
        order = self.order
        if e > 0:
            phi = lamb*z**e - 1
        else:
            phi = z**abse - lamb
        mu = phi.roots(QQbar, multiplicities=False)[0]

        if all_conjugates:
            zeta_e=QQbar.zeta(abse)
            conjugates = [mu*zeta_e**k for k in range(abse)]
        else:
            conjugates = [mu]
        map(lambda x: x.exactify(), conjugates)

        # determine the resulting x-series
        xseries = []
        for c in conjugates:
            t = self.ypart.parent().gen()
            fconj = self.ypart(c*t)
            p = P(fconj(x**(QQ(1)/e)))
            p = p.add_bigoh(QQ(order+1)/abse)
            xseries.append(p)
        return xseries
예제 #7
0
def braid_in_segment(f, x0, x1):
    """
    Return the braid formed by the `y` roots of ``f`` when `x` moves
    from ``x0`` to ``x1``.

    INPUT:

    - ``f`` -- a polynomial in two variables
    - ``x0`` -- a complex number
    - ``x1`` -- a complex number

    OUTPUT:

    A braid.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import braid_in_segment # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: x0 = CC(1,0)
        sage: x1 = CC(1, 0.5)
        sage: braid_in_segment(f, x0, x1) # optional - sirocco
        s1
    """
    CC = ComplexField(64)
    (x, y) = f.variables()
    I = QQbar.gen()
    X0 = QQ(x0.real()) + I*QQ(x0.imag())
    X1 = QQ(x1.real()) + I*QQ(x1.imag())
    F0 = QQbar[y](f(X0, y))
    y0s = F0.roots(multiplicities=False)
    strands = [followstrand(f, x0, x1, CC(a)) for a in y0s]
    complexstrands = [[(a[0], CC(a[1], a[2])) for a in b] for b in strands]
    centralbraid = braid_from_piecewise(complexstrands)
    initialstrands = []
    y0aps = [c[0][1] for c in complexstrands]
    used = []
    for y0ap in y0aps:
        distances = [((y0ap - y0).norm(), y0) for y0 in y0s]
        y0 = sorted(distances)[0][1]
        if y0 in used:
            raise ValueError("different roots are too close")
        used.append(y0)
        initialstrands.append([(0, CC(y0)), (1, y0ap)])
    initialbraid = braid_from_piecewise(initialstrands)
    F1 = QQbar[y](f(X1,y))
    y1s = F1.roots(multiplicities=False)
    finalstrands = []
    y1aps = [c[-1][1] for c in complexstrands]
    used = []
    for y1ap in y1aps:
        distances = [((y1ap - y1).norm(), y1) for y1 in y1s]
        y1 = sorted(distances)[0][1]
        if y1 in used:
            raise ValueError("different roots are too close")
        used.append(y1)
        finalstrands.append([(0, y1ap), (1, CC(y1))])
    finallbraid = braid_from_piecewise(finalstrands)
    return initialbraid * centralbraid * finallbraid
예제 #8
0
def braid_in_segment(f, x0, x1):
    """
    Return the braid formed by the `y` roots of ``f`` when `x` moves
    from ``x0`` to ``x1``.

    INPUT:

    - ``f`` -- a polynomial in two variables
    - ``x0`` -- a complex number
    - ``x1`` -- a complex number

    OUTPUT:

    A braid.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import braid_in_segment # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: x0 = CC(1,0)
        sage: x1 = CC(1, 0.5)
        sage: braid_in_segment(f, x0, x1) # optional - sirocco
        s1
    """
    CC = ComplexField(64)
    (x, y) = f.variables()
    I = QQbar.gen()
    X0 = QQ(x0.real()) + I*QQ(x0.imag())
    X1 = QQ(x1.real()) + I*QQ(x1.imag())
    F0 = QQbar[y](f(X0, y))
    y0s = F0.roots(multiplicities=False)
    strands = [followstrand(f, x0, x1, CC(a)) for a in y0s]
    complexstrands = [[(a[0], CC(a[1], a[2])) for a in b] for b in strands]
    centralbraid = braid_from_piecewise(complexstrands)
    initialstrands = []
    y0aps = [c[0][1] for c in complexstrands]
    used = []
    for y0ap in y0aps:
        distances = [((y0ap - y0).norm(), y0) for y0 in y0s]
        y0 = sorted(distances)[0][1]
        if y0 in used:
            raise ValueError("different roots are too close")
        used.append(y0)
        initialstrands.append([(0, CC(y0)), (1, y0ap)])
    initialbraid = braid_from_piecewise(initialstrands)
    F1 = QQbar[y](f(X1,y))
    y1s = F1.roots(multiplicities=False)
    finalstrands = []
    y1aps = [c[-1][1] for c in complexstrands]
    used = []
    for y1ap in y1aps:
        distances = [((y1ap - y1).norm(), y1) for y1 in y1s]
        y1 = sorted(distances)[0][1]
        if y1 in used:
            raise ValueError("different roots are too close")
        used.append(y1)
        finalstrands.append([(0, y1ap), (1, CC(y1))])
    finallbraid = braid_from_piecewise(finalstrands)
    return initialbraid * centralbraid * finallbraid
예제 #9
0
def generalized_series_term_valuation(z, i, j, iota=None):
    r"""
    Given z, i, j, return the valuation of the term x^(z+i) log(x)^j
    """
    try:
        z = QQbar(z)
    except ValueError:
        # FIXME: It would be great if we could show the warning once per
        # relevant field
        warn(
            "Choosing an arbitrary complex embedding for {}.\n"
            "To avoid it, extend the coefficients of the base ring.".format(
                z.parent()), RuntimeWarning)
        z = z.parent().embeddings(QQbar)[0](z)
    if iota is None:
        iota = generalized_series_default_iota
    return ZZ(z + i - iota(z, j))
    def _call_(self, x):
        r"""
        TESTS::

            sage: UCF = UniversalCyclotomicField()
            sage: UCFtoQQbar = UCF.coerce_embedding()
            sage: UCFtoQQbar(UCF.gen(3))  # indirect doctest
            -0.500000000000000? + 0.866025403784439?*I
        """
        obj = x._obj
        QQbar = self.codomain()
        if obj.IsRat():
            return QQbar(obj.sage())
        k = obj.Conductor().sage()
        coeffs = obj.CoeffsCyc(k).sage()
        zeta = QQbar.zeta(k)
        return QQbar(sum(coeffs[a] * zeta**a for a in range(1, k)))
예제 #11
0
def brackets_to_txt(L):
    r"""
    Return a text string enumerating all Lie brackets.

    INPUT:

    - ``L`` -- a Lie algebra
    """
    # if the base ring is QQbar, display coefficients as radicals
    disp = QQbar.options('display_format')
    QQbar.options(display_format="radical")

    bracketstr = ""
    for X, Y in combinations(L.basis(), 2):
        Z = X.bracket(Y)
        if Z:
            bracketstr += "  [%s, %s] = %s\n" % (X, Y, Z)
    QQbar.options(display_format=disp)
    return bracketstr
예제 #12
0
def dim_Joli( k, L, h):
    """
    Return the dimension of the space $J_{k,L}(\varepsilon^h)$.

    INPUT
       k -- a half integer
       L -- an instance of Lattice_class
       h -- an integer
    """
    h = Integer(h)
    g = k - h/2
    try:
        g = Integer(g)
    except:
        return Integer(0)

    # preparations
    o_inv = L.o_invariant()
    V = L.shadow_vectors()
    V2 = L.shadow_vectors_of_order_2()
    n = L.rank()

    if k < n/2:
        return Integer(0)
    if n/2 <= k and k < 2+n/2:
        raise NotImplementedError( 'special weight %s: not yet implemented'%k)

    # scalar term
    scal = (L.det() + len(V2) * (-1)**(g+o_inv)) * (k-n/2-1)/24

    # elliptic S-term
    ell_S = (L.chi(2) * QQbar.zeta(4)**g).real()/4 + Rational(Integer(12).kronecker(2*g+2*n+1))/6

    # elliptic R-term
    ell_R = (L.chi(-3) * QQbar.zeta(24)**(n+2) * QQbar.zeta(6)**g).real() * (-1)**g/QQbar(27).sqrt()
    
    # parabolic term
    B = lambda t: t - t.floor() - Rational(1)/2
    par = -sum( B(h/24-L.beta(x)) for x in V)/2
    par -= (-1)**(g+o_inv) * sum(B(h/24-L.beta(x)) for x in V2)/2

    return Integer(scal + ell_S + ell_R + par)
예제 #13
0
def isom_class_to_html_tablerow(label, ic, mathjax):
    r"""
    Return a html table row describing a labelled isomorphism class of gradings.

    INPUT:

    - ``label`` -- a string identifier
    - ``ic`` -- a :class:`GradingIsomorphismClass`
    - ``mathjax`` -- a boolean; whether to output the table as mathjax or not
    """
    # if the base ring is QQbar, display coefficients as radicals
    disp = QQbar.options('display_format')
    QQbar.options(display_format="radical")

    indent = " " * 4
    classname = "grading"
    # test if stratification or positivisable
    L = ic.representative().lie_algebra()
    try:
        st = stratification(L)
        strat = True
    except ValueError:
        strat = False
    if strat and st in ic:
        classname += " stratification positive"
    else:
        if ic.representative().has_positive_realization():
            classname += " positive"
        else:
            classname += " nonpositive"

    tablerow = '<tr class="%s">\n' % classname
    tablerow += indent + '<td class="label">%s</td>\n' % label
    if mathjax:
        icstr = "\\(%s\\)" % grading_to_array(ic.representative(), amp="&amp;")
    else:
        icstr = grading_to_html_table(ic.representative())
    tablerow += indent + '<td>%s</td>\n' % icstr
    tablerow += "</tr>"
    QQbar.options(display_format=disp)
    return tablerow
예제 #14
0
    def sqrt(self):
        """
        Return a square root of ``self`` as an algebraic number.

        EXAMPLES::

            sage: f = E(33)
            sage: f.sqrt()
            0.9954719225730846? + 0.0950560433041827?*I
            sage: f.sqrt()**2 == f
            True
        """
        return QQbar(self).sqrt()
예제 #15
0
def brackets_to_align(L, amp="&amp;"):
    r"""
    Return a latex align* environment enumerating all Lie brackets.

    INPUT:

    - ``L`` -- a Lie algebra
    - ``amp`` -- a string to use as the ampersand symbol in the output
    """
    rows = []
    for X, Y in combinations(L.basis(), 2):
        Z = X.bracket(Y)
        if Z:
            row = "[%s, %s] %s = %s" % (latex(X), latex(Y), amp, latex(Z))
            rows.append(row)
    if not rows:
        return ""
    latexstr = "\\begin{align*}\n"
    latexstr += "\\\\\n".join(rows)
    latexstr += "\\end{align*}"
    QQbar.options(display_format=disp)
    return latexstr
    def _mpfr_(self, R):
        r"""
        TESTS::

            sage: RR(E(7) + E(7,6))
            1.24697960371747
            sage: 2*cos(2*pi/7).n()
            1.24697960371747
        """
        if not self.is_real():
            raise TypeError("self is not real")

        from sage.rings.qqbar import QQbar, AA
        return AA(QQbar(self))._mpfr_(R)
예제 #17
0
    def _algebraic_(self, R):
        r"""
        TESTS::

            sage: UCF = UniversalCyclotomicField()
            sage: AA(UCF.gen(5) + UCF.gen(5,4))
            0.618033988749895?
            sage: AA(UCF.gen(5))
            Traceback (most recent call last):
            ...
            ValueError: Cannot coerce algebraic number with non-zero imaginary
            part to algebraic real
        """
        return R(QQbar(self))
예제 #18
0
def family_two(n, backend=None):
    r"""
    Return the vector configuration of the simplicial arrangement
    `A(n,1)` from the family `\mathcal R(1)` in Grunbaum's list [Gru]_.

    The arrangement will have an ``n`` hyperplanes, with ``n`` even, consisting
    of the edges of the regular `n/2`-gon and the `n/2` lines of 
    mirror symmetry.

    INPUT:

    - ``n`` -- integer. ``n`` `\geq 6`. The number of lines in the arrangement.
    
    - ``backend`` -- string (default = ``None``). The backend to use.

    OUTPUT:

    A vector configuration.

    EXAMPLES::

        sage: from cn_hyperarr.infinite_families import *
        sage: pf = family_two(8,'normaliz'); pf   # optional - pynormaliz
        Vector configuration of 8 vectors in dimension 3

    The number of lines must be even::

        sage: pf3 = family_two(3,'normaliz');     # optional - pynormaliz
        Traceback (most recent call last):
        ...
        AssertionError: n must be even

    The number of lines must be at least 6::

        sage: pf4 = family_two(4,'normaliz')      # optional - pynormaliz
        Traceback (most recent call last):
        ...
        ValueError: n (=2) must be an integer greater than 2
    """
    assert n % 2 == 0, "n must be even"
    reg_poly = polytopes.regular_polygon(n / QQ(2), backend='normaliz')
    reg_cone = Polyhedron(
        rays=[list(v.vector()) + [1] for v in reg_poly.vertices()],
        backend=backend)
    vecs = [h.A() for h in reg_cone.Hrepresentation()]

    z = QQbar.zeta(n)
    vecs += [[(z**k).real(), (z**k).imag(), 0] for k in range(n / QQ(2))]
    return VectorConfiguration(vecs, backend=backend)
예제 #19
0
 def chi( self, t):
     """
     Return the value of the Gauss sum
     $\sum_{x\in L^\bullet/L} e(tG[x]/2)/\sqrt D$,
     where $D = |L^\bullet/L|$.
     """
     t = Integer(t)%self.shadow_level()
     if self.__chi.has_key(t):
         return self.__chi[t]
     l = self.shadow_level()
     z = QQbar.zeta(l)
     w = QQbar(self.det().sqrt())
     V = self.values()
     self.__chi[t] = sum(len(V[a])*z**(t*a) for a in V)/w
     return self.__chi[t]
    def _call_(self, x):
        r"""
        TESTS::

            sage: UCF = UniversalCyclotomicField()
            sage: UCFtoQQbar = UCF.coerce_embedding()
            sage: UCFtoQQbar(UCF.gen(3))  # indirect doctest
            -0.500000000000000? + 0.866025403784439?*I
        """
        obj = x._obj
        QQbar = self.codomain()
        if obj.IsRat():
            return QQbar(obj.sage())
        k = obj.Conductor().sage()
        coeffs = obj.CoeffsCyc(k).sage()
        zeta = QQbar.zeta(k)
        return QQbar(sum(coeffs[a] * zeta**a for a in range(1,k)))
예제 #21
0
def near_pencil_family(n, backend=None):
    r"""
    Return the vector configuration of the near pencil with ``n`` lines.

    All lines except for one share a common intersection point.

    INPUT:

    - ``n`` -- integer. ``n`` `\geq 3`. The number of lines in the near pencil.
    
    - ``backend`` -- string (default = ``None``). The backend to use.

    OUTPUT:

    A vector configuration.

    EXAMPLES:

    The near pencil with three hyperplanes::

        sage: from cn_hyperarr.infinite_families import *
        sage: np = near_pencil_family(3,'normaliz'); np         # optional - pynormaliz
        Vector configuration of 3 vectors in dimension 3

    The near pencil arrangements are always congruence normal. Note, this test
    just shows there exists a region such that they are CN::

        sage: near_pencils = [near_pencil_family(n,'normaliz') for n in range(3,6)] # optional - pynormaliz
        sage: [ np.is_congruence_normal() for np in near_pencils] # optional - pynormaliz
        [True, True, True]

    TESTS:

    Test that the backend is normaliz::

        sage: np = near_pencil_family(3,'normaliz');            # optional - pynormaliz
        sage: np.backend()                                        # optional - pynormaliz
        'normaliz'
    """
    z = QQbar.zeta(2 * n)
    vecs = [[(z**k).real(), (z**k).imag(), 0] for k in range(1, n)]
    vecs += [vector([0, -1, 1])]
    return VectorConfiguration(vecs, backend=backend)
예제 #22
0
    def right_triangle(angle,leg0=None, leg1=None, hypotenuse=None):
        r"""
        Return a right triangle in a numberfield with an angle of pi*m/n.
        You can specify the length of the first leg (leg0), the second leg (leg1),
        or the hypotenuse.
        """
        from sage.rings.qqbar import QQbar
        z=QQbar.zeta(2*angle.denom())**angle.numer()
        c = z.real()
        s = z.imag()

        if not leg0 is None:
            c,s = leg0*c/c,leg0*s/c
        elif not leg1 is None:
            c,s = leg1*c/s,leg1*s/s
        elif not hypotenuse is None:
            c,s = hypotenuse*c, hypotenuse*s
        
        field, (c,s) = number_field_elements_from_algebraics((c,s))
        return Polygons(field)(edges=[(c,field.zero()),(field.zero(),s),(-c,-s)])
예제 #23
0
def braid_in_segment(g, x0, x1):
    """
    Return the braid formed by the `y` roots of ``f`` when `x` moves
    from ``x0`` to ``x1``.

    INPUT:

    - ``g`` -- a polynomial factorization in two variables
    - ``x0`` -- a complex number
    - ``x1`` -- a complex number

    OUTPUT:

    A braid.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import braid_in_segment # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: x0 = CC(1,0)
        sage: x1 = CC(1, 0.5)
        sage: braid_in_segment(f.factor(), x0, x1) # optional - sirocco
        s1

    TESTS:

    Check that :trac:`26503` is fixed::

        sage: wp = QQ['t']([1, 1, 1]).roots(QQbar)[0][0]
        sage: Kw.<wp> = NumberField(wp.minpoly(), embedding=wp)
        sage: R.<x, y> = Kw[]
        sage: z = -wp - 1
        sage: f = y*(y + z)*x*(x - 1)*(x - y)*(x + z*y - 1)*(x + z*y + wp)
        sage: from sage.schemes.curves import zariski_vankampen as zvk
        sage: g = f.subs({x: x + 2*y})
        sage: p1 = QQbar(sqrt(-1/3))
        sage: p2 = QQbar(1/2+sqrt(-1/3)/2)
        sage: B = zvk.braid_in_segment(g.factor(),CC(p1),CC(p2)) # optional - sirocco
        sage: B  # optional - sirocco
        s5*s3^-1

    """
    (x, y) = g.value().parent().gens()
    I = QQbar.gen()
    X0 = QQ(x0.real()) + I * QQ(x0.imag())
    X1 = QQ(x1.real()) + I * QQ(x1.imag())
    intervals = {}
    precision = {}
    y0s = []
    for (f, naux) in g:
        if f.variables() == (y, ):
            F0 = QQbar[y](f.base_ring()[y](f))
        else:
            F0 = QQbar[y](f(X0, y))
        y0sf = F0.roots(multiplicities=False)
        y0s += list(y0sf)
        precision[f] = 53
        while True:
            CIFp = ComplexIntervalField(precision[f])
            intervals[f] = [r.interval(CIFp) for r in y0sf]
            if not any(
                    a.overlaps(b)
                    for a, b in itertools.combinations(intervals[f], 2)):
                break
            precision[f] *= 2
    strands = [
        followstrand(f[0], [p[0] for p in g if p[0] != f[0]], x0, x1,
                     i.center(), precision[f[0]]) for f in g
        for i in intervals[f[0]]
    ]
    complexstrands = [[(QQ(a[0]), QQ(a[1]), QQ(a[2])) for a in b]
                      for b in strands]
    centralbraid = braid_from_piecewise(complexstrands)
    initialstrands = []
    finalstrands = []
    initialintervals = roots_interval_cached(g.value(), X0)
    finalintervals = roots_interval_cached(g.value(), X1)
    for cs in complexstrands:
        ip = cs[0][1] + I * cs[0][2]
        fp = cs[-1][1] + I * cs[-1][2]
        matched = 0
        for center, interval in initialintervals.items():
            if ip in interval:
                initialstrands.append([(0, center.real(), center.imag()),
                                       (1, cs[0][1], cs[0][2])])
                matched += 1
        if matched == 0:
            raise ValueError("unable to match braid endpoint with root")
        if matched > 1:
            raise ValueError("braid endpoint mathes more than one root")
        matched = 0
        for center, interval in finalintervals.items():
            if fp in interval:
                finalstrands.append([(0, cs[-1][1], cs[-1][2]),
                                     (1, center.real(), center.imag())])
                matched += 1
        if matched == 0:
            raise ValueError("unable to match braid endpoint with root")
        if matched > 1:
            raise ValueError("braid endpoint mathes more than one root")
    initialbraid = braid_from_piecewise(initialstrands)
    finalbraid = braid_from_piecewise(finalstrands)

    return initialbraid * centralbraid * finalbraid
예제 #24
0
    def closed_form(self, n='n'):
        r"""
        Return a symbolic expression in ``n``, which equals the n-th term of
        the sequence.

        It is a well-known property of C-finite sequences ``a_n`` that they
        have a closed form of the type:

        .. MATH::

            a_n = \sum_{i=1}^d c_i(n) \cdot r_i^n,

        where ``r_i`` are the roots of the characteristic equation and
        ``c_i(n)`` is a polynomial (whose degree equals the multiplicity of
        ``r_i`` minus one).  This is a natural generalization of Binet's
        formula for Fibonacci numbers.  See, for instance, [KP2011, Theorem 4.1].

        Note that if the o.g.f. has a polynomial part, that is, if the
        numerator degree is not strictly less than the denominator degree,
        then this closed form holds only when ``n`` exceeds the degree of that
        polynomial part.  In that case, the returned expression will differ
        from the sequence for small ``n``.

        EXAMPLES::

            sage: CFiniteSequence(1/(1-x)).closed_form()
            1
            sage: CFiniteSequence(x^2/(1-x)).closed_form()
            1
            sage: CFiniteSequence(1/(1-x^2)).closed_form()
            1/2*(-1)^n + 1/2
            sage: CFiniteSequence(1/(1+x^3)).closed_form()
            1/3*(-1)^n + 1/3*(1/2*I*sqrt(3) + 1/2)^n + 1/3*(-1/2*I*sqrt(3) + 1/2)^n
            sage: CFiniteSequence(1/(1-x)/(1-2*x)/(1-3*x)).closed_form()
            9/2*3^n - 4*2^n + 1/2

        Binet's formula for the Fibonacci numbers::

            sage: CFiniteSequence(x/(1-x-x^2)).closed_form()
            sqrt(1/5)*(1/2*sqrt(5) + 1/2)^n - sqrt(1/5)*(-1/2*sqrt(5) + 1/2)^n
            sage: [_.subs(n=k).full_simplify() for k in range(6)]
            [0, 1, 1, 2, 3, 5]

            sage: CFiniteSequence((4*x+3)/(1-2*x-5*x^2)).closed_form()
            1/2*(sqrt(6) + 1)^n*(7*sqrt(1/6) + 3) - 1/2*(-sqrt(6) + 1)^n*(7*sqrt(1/6) - 3)

        Examples with multiple roots::

            sage: CFiniteSequence(x*(x^2+4*x+1)/(1-x)^5).closed_form()
            1/4*n^4 + 1/2*n^3 + 1/4*n^2
            sage: CFiniteSequence((1+2*x-x^2)/(1-x)^4/(1+x)^2).closed_form()
            1/12*n^3 - 1/8*(-1)^n*(n + 1) + 3/4*n^2 + 43/24*n + 9/8
            sage: CFiniteSequence(1/(1-x)^3/(1-2*x)^4).closed_form()
            4/3*(n^3 - 3*n^2 + 20*n - 36)*2^n + 1/2*n^2 + 19/2*n + 49
            sage: CFiniteSequence((x/(1-x-x^2))^2).closed_form()
            1/5*(n - sqrt(1/5))*(1/2*sqrt(5) + 1/2)^n + 1/5*(n + sqrt(1/5))*(-1/2*sqrt(5) + 1/2)^n
        """
        from sage.arith.all import binomial
        from sage.rings.qqbar import QQbar

        from sage.symbolic.ring import SR
        n = SR(n)
        expr = SR.zero()

        R = FractionField(PolynomialRing(QQbar, self.parent().variable_name()))
        ogf = R(self.ogf())

        __, parts = ogf.partial_fraction_decomposition(decompose_powers=False)
        for part in parts:
            denom = part.denominator().factor()
            denom_base, denom_exp = denom[0]

            # denominator is of the form (x+b)^{m+1}
            m = denom_exp - 1
            b = denom_base.constant_coefficient()
            # check that the partial fraction decomposition was indeed done correctly
            # (that is, there is only one factor, of degree 1, and monic)
            assert len(denom) == 1 and len(denom_base.list(
            )) == 2 and denom_base[1] == 1 and denom.unit() == 1

            r = SR((-1 / b).radical_expression())
            c = SR.zero()
            for k, a in enumerate(part.numerator()):
                a = -QQbar(a) if k % 2 else QQbar(a)
                bino = binomial(n + m - k, m)
                c += bino * SR((a * b**(k - m - 1)).radical_expression())

            expr += c.expand() * r**n

        return expr
예제 #25
0
def complex_roots(p, skip_squarefree=False, retval='interval', min_prec=0):
    """
    Compute the complex roots of a given polynomial with exact
    coefficients (integer, rational, Gaussian rational, and algebraic
    coefficients are supported).  Returns a list of pairs of a root
    and its multiplicity.

    Roots are returned as a ComplexIntervalFieldElement; each interval
    includes exactly one root, and the intervals are disjoint.

    By default, the algorithm will do a squarefree decomposition
    to get squarefree polynomials.  The skip_squarefree parameter
    lets you skip this step.  (If this step is skipped, and the polynomial
    has a repeated root, then the algorithm will loop forever!)

    You can specify retval='interval' (the default) to get roots as
    complex intervals.  The other options are retval='algebraic' to
    get elements of QQbar, or retval='algebraic_real' to get only
    the real roots, and to get them as elements of AA.

    EXAMPLES::

        sage: from sage.rings.polynomial.complex_roots import complex_roots
        sage: x = polygen(ZZ)
        sage: complex_roots(x^5 - x - 1)
        [(1.167303978261419?, 1), (-0.764884433600585? - 0.352471546031727?*I, 1), (-0.764884433600585? + 0.352471546031727?*I, 1), (0.181232444469876? - 1.083954101317711?*I, 1), (0.181232444469876? + 1.083954101317711?*I, 1)]
        sage: v=complex_roots(x^2 + 27*x + 181)

    Unfortunately due to numerical noise there can be a small imaginary part to each
    root depending on CPU, compiler, etc, and that affects the printing order. So we
    verify the real part of each root and check that the imaginary part is small in
    both cases::

        sage: v # random
        [(-14.61803398874990?..., 1), (-12.3819660112501...? + 0.?e-27*I, 1)]
        sage: sorted((v[0][0].real(),v[1][0].real()))
        [-14.61803398874989?, -12.3819660112501...?]
        sage: v[0][0].imag() < 1e25
        True
        sage: v[1][0].imag() < 1e25
        True

        sage: K.<im> = NumberField(x^2 + 1)
        sage: eps = 1/2^100
        sage: x = polygen(K)
        sage: p = (x-1)*(x-1-eps)*(x-1+eps)*(x-1-eps*im)*(x-1+eps*im)

    This polynomial actually has all-real coefficients, and is very, very
    close to (x-1)^5::

        sage: [RR(QQ(a)) for a in list(p - (x-1)^5)]
        [3.87259191484932e-121, -3.87259191484932e-121]
        sage: rts = complex_roots(p)
        sage: [ComplexIntervalField(10)(rt[0] - 1) for rt in rts]
        [-7.8887?e-31, 0, 7.8887?e-31, -7.8887?e-31*I, 7.8887?e-31*I]

    We can get roots either as intervals, or as elements of QQbar or AA.

    ::

        sage: p = (x^2 + x - 1)
        sage: p = p * p(x*im)
        sage: p
        -x^4 + (im - 1)*x^3 + im*x^2 + (-im - 1)*x + 1

    Two of the roots have a zero real component; two have a zero
    imaginary component.  These zero components will be found slightly
    inaccurately, and the exact values returned are very sensitive to
    the (non-portable) results of NumPy.  So we post-process the roots
    for printing, to get predictable doctest results.

    ::

        sage: def tiny(x):
        ....:     return x.contains_zero() and x.absolute_diameter() <  1e-14
        sage: def smash(x):
        ....:     x = CIF(x[0]) # discard multiplicity
        ....:     if tiny(x.imag()): return x.real()
        ....:     if tiny(x.real()): return CIF(0, x.imag())
        sage: rts = complex_roots(p); type(rts[0][0]), sorted(map(smash, rts))
        (<type 'sage.rings.complex_interval.ComplexIntervalFieldElement'>, [-1.618033988749895?, -0.618033988749895?*I, 1.618033988749895?*I, 0.618033988749895?])
        sage: rts = complex_roots(p, retval='algebraic'); type(rts[0][0]), sorted(map(smash, rts))
        (<class 'sage.rings.qqbar.AlgebraicNumber'>, [-1.618033988749895?, -0.618033988749895?*I, 1.618033988749895?*I, 0.618033988749895?])
        sage: rts = complex_roots(p, retval='algebraic_real'); type(rts[0][0]), rts
        (<class 'sage.rings.qqbar.AlgebraicReal'>, [(-1.618033988749895?, 1), (0.618033988749895?, 1)])

    TESTS:

    Verify that :trac:`12026` is fixed::

        sage: f = matrix(QQ, 8, lambda i, j: 1/(i + j + 1)).charpoly()
        sage: from sage.rings.polynomial.complex_roots import complex_roots
        sage: len(complex_roots(f))
        8
    """

    if skip_squarefree:
        factors = [(p, 1)]
    else:
        factors = p.squarefree_decomposition()

    prec = 53
    while True:
        CC = ComplexField(prec)
        CCX = CC['x']

        all_rts = []
        ok = True

        for (factor, exp) in factors:
            cfac = CCX(factor)
            rts = cfac.roots(multiplicities=False)
            # Make sure the number of roots we found is the degree. If
            # we don't find that many roots, it's because the
            # precision isn't big enough and though the (possibly
            # exact) polynomial "factor" is squarefree, it is not
            # squarefree as an element of CCX.
            if len(rts) < factor.degree():
                ok = False
                break
            irts = interval_roots(factor, rts, max(prec, min_prec))
            if irts is None:
                ok = False
                break
            if retval != 'interval':
                factor = QQbar.common_polynomial(factor)
            for irt in irts:
                all_rts.append((irt, factor, exp))

        if ok and intervals_disjoint([rt for (rt, fac, mult) in all_rts]):
            all_rts = sort_complex_numbers_for_display(all_rts)
            if retval == 'interval':
                return [(rt, mult) for (rt, fac, mult) in all_rts]
            elif retval == 'algebraic':
                return [(QQbar.polynomial_root(fac, rt), mult) for (rt, fac, mult) in all_rts]
            elif retval == 'algebraic_real':
                rts = []
                for (rt, fac, mult) in all_rts:
                    qqbar_rt = QQbar.polynomial_root(fac, rt)
                    if qqbar_rt.imag().is_zero():
                        rts.append((AA(qqbar_rt), mult))
                return rts

        prec = prec * 2
예제 #26
0
def complex_roots(p, skip_squarefree=False, retval='interval', min_prec=0):
    """
    Compute the complex roots of a given polynomial with exact
    coefficients (integer, rational, Gaussian rational, and algebraic
    coefficients are supported).  Returns a list of pairs of a root
    and its multiplicity.

    Roots are returned as a ComplexIntervalFieldElement; each interval
    includes exactly one root, and the intervals are disjoint.

    By default, the algorithm will do a squarefree decomposition
    to get squarefree polynomials.  The skip_squarefree parameter
    lets you skip this step.  (If this step is skipped, and the polynomial
    has a repeated root, then the algorithm will loop forever!)

    You can specify retval='interval' (the default) to get roots as
    complex intervals.  The other options are retval='algebraic' to
    get elements of QQbar, or retval='algebraic_real' to get only
    the real roots, and to get them as elements of AA.

    EXAMPLES::

        sage: from sage.rings.polynomial.complex_roots import complex_roots
        sage: x = polygen(ZZ)
        sage: complex_roots(x^5 - x - 1)
        [(1.167303978261419?, 1), (-0.764884433600585? - 0.352471546031727?*I, 1), (-0.764884433600585? + 0.352471546031727?*I, 1), (0.181232444469876? - 1.083954101317711?*I, 1), (0.181232444469876? + 1.083954101317711?*I, 1)]
        sage: v=complex_roots(x^2 + 27*x + 181)

    Unfortunately due to numerical noise there can be a small imaginary part to each
    root depending on CPU, compiler, etc, and that affects the printing order. So we
    verify the real part of each root and check that the imaginary part is small in
    both cases::

        sage: v # random
        [(-14.61803398874990?..., 1), (-12.3819660112501...? + 0.?e-27*I, 1)]
        sage: sorted((v[0][0].real(),v[1][0].real()))
        [-14.61803398874989?, -12.3819660112501...?]
        sage: v[0][0].imag() < 1e25
        True
        sage: v[1][0].imag() < 1e25
        True

        sage: K.<im> = NumberField(x^2 + 1)
        sage: eps = 1/2^100
        sage: x = polygen(K)
        sage: p = (x-1)*(x-1-eps)*(x-1+eps)*(x-1-eps*im)*(x-1+eps*im)

    This polynomial actually has all-real coefficients, and is very, very
    close to (x-1)^5::

        sage: [RR(QQ(a)) for a in list(p - (x-1)^5)]
        [3.87259191484932e-121, -3.87259191484932e-121]
        sage: rts = complex_roots(p)
        sage: [ComplexIntervalField(10)(rt[0] - 1) for rt in rts]
        [-7.8887?e-31, 0, 7.8887?e-31, -7.8887?e-31*I, 7.8887?e-31*I]

    We can get roots either as intervals, or as elements of QQbar or AA.

    ::

        sage: p = (x^2 + x - 1)
        sage: p = p * p(x*im)
        sage: p
        -x^4 + (im - 1)*x^3 + im*x^2 + (-im - 1)*x + 1

    Two of the roots have a zero real component; two have a zero
    imaginary component.  These zero components will be found slightly
    inaccurately, and the exact values returned are very sensitive to
    the (non-portable) results of NumPy.  So we post-process the roots
    for printing, to get predictable doctest results.

    ::

        sage: def tiny(x):
        ...       return x.contains_zero() and x.absolute_diameter() <  1e-14
        sage: def smash(x):
        ...       x = CIF(x[0]) # discard multiplicity
        ...       if tiny(x.imag()): return x.real()
        ...       if tiny(x.real()): return CIF(0, x.imag())
        sage: rts = complex_roots(p); type(rts[0][0]), sorted(map(smash, rts))
        (<type 'sage.rings.complex_interval.ComplexIntervalFieldElement'>, [-1.618033988749895?, -0.618033988749895?*I, 1.618033988749895?*I, 0.618033988749895?])
        sage: rts = complex_roots(p, retval='algebraic'); type(rts[0][0]), sorted(map(smash, rts))
        (<class 'sage.rings.qqbar.AlgebraicNumber'>, [-1.618033988749895?, -0.618033988749895?*I, 1.618033988749895?*I, 0.618033988749895?])
        sage: rts = complex_roots(p, retval='algebraic_real'); type(rts[0][0]), rts
        (<class 'sage.rings.qqbar.AlgebraicReal'>, [(-1.618033988749895?, 1), (0.618033988749895?, 1)])

    TESTS:

    Verify that trac 12026 is fixed::

        sage: f = matrix(QQ, 8, lambda i, j: 1/(i + j + 1)).charpoly()
        sage: from sage.rings.polynomial.complex_roots import complex_roots
        sage: len(complex_roots(f))
        8
    """

    if skip_squarefree:
        factors = [(p, 1)]
    else:
        factors = p.squarefree_decomposition()

    prec = 53
    while True:
        CC = ComplexField(prec)
        CCX = CC['x']

        all_rts = []
        ok = True

        for (factor, exp) in factors:
            cfac = CCX(factor)
            rts = cfac.roots(multiplicities=False)
            # Make sure the number of roots we found is the degree. If
            # we don't find that many roots, it's because the
            # precision isn't big enough and though the (possibly
            # exact) polynomial "factor" is squarefree, it is not
            # squarefree as an element of CCX.
            if len(rts) < factor.degree():
                ok = False
                break
            irts = interval_roots(factor, rts, max(prec, min_prec))
            if irts is None:
                ok = False
                break
            if retval != 'interval':
                factor = QQbar.common_polynomial(factor)
            for irt in irts:
                all_rts.append((irt, factor, exp))

        if ok and intervals_disjoint([rt for (rt, fac, mult) in all_rts]):
            all_rts = sort_complex_numbers_for_display(all_rts)
            if retval == 'interval':
                return [(rt, mult) for (rt, fac, mult) in all_rts]
            elif retval == 'algebraic':
                return [(QQbar.polynomial_root(fac, rt), mult) for (rt, fac, mult) in all_rts]
            elif retval == 'algebraic_real':
                rts = []
                for (rt, fac, mult) in all_rts:
                    qqbar_rt = QQbar.polynomial_root(fac, rt)
                    if qqbar_rt.imag().is_zero():
                        rts.append((AA(qqbar_rt), mult))
                return rts

        prec = prec * 2
예제 #27
0
def braid_in_segment(f, x0, x1):
    """
    Return the braid formed by the `y` roots of ``f`` when `x` moves
    from ``x0`` to ``x1``.

    INPUT:

    - ``f`` -- a polynomial in two variables
    - ``x0`` -- a complex number
    - ``x1`` -- a complex number

    OUTPUT:

    A braid.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import braid_in_segment # optional - sirocco
        sage: R.<x,y> = QQ[]
        sage: f = x^2 + y^3
        sage: x0 = CC(1,0)
        sage: x1 = CC(1, 0.5)
        sage: braid_in_segment(f, x0, x1) # optional - sirocco
        s1

    TESTS:

    Check that :trac:`26503` is fixed::

        sage: wp = QQ['t']([1, 1, 1]).roots(QQbar)[0][0]
        sage: Kw.<wp> = NumberField(wp.minpoly(), embedding=wp)
        sage: R.<x, y> = Kw[]
        sage: z = -wp - 1
        sage: f = y*(y + z)*x*(x - 1)*(x - y)*(x + z*y - 1)*(x + z*y + wp)
        sage: from sage.schemes.curves import zariski_vankampen as zvk
        sage: g = f.subs({x: x + 2*y})
        sage: p1 = QQbar(sqrt(-1/3))
        sage: p2 = QQbar(1/2+sqrt(-1/3)/2)
        sage: B = zvk.braid_in_segment(g,CC(p1),CC(p2)) # optional - sirocco
        sage: B.left_normal_form()  # optional - sirocco
        (1, s5)
    """
    CC = ComplexField(64)
    (x, y) = f.variables()
    I = QQbar.gen()
    X0 = QQ(x0.real()) + I * QQ(x0.imag())
    X1 = QQ(x1.real()) + I * QQ(x1.imag())
    F0 = QQbar[y](f(X0, y))
    y0s = F0.roots(multiplicities=False)
    strands = [followstrand(f, x0, x1, CC(a)) for a in y0s]
    complexstrands = [[(a[0], CC(a[1], a[2])) for a in b] for b in strands]
    centralbraid = braid_from_piecewise(complexstrands)
    initialstrands = []
    y0aps = [c[0][1] for c in complexstrands]
    used = []
    for y0ap in y0aps:
        distances = [((y0ap - y0).norm(), y0) for y0 in y0s]
        y0 = sorted(distances)[0][1]
        if y0 in used:
            raise ValueError("different roots are too close")
        used.append(y0)
        initialstrands.append([(0, y0), (1, y0ap)])
    initialbraid = braid_from_piecewise(initialstrands)
    F1 = QQbar[y](f(X1, y))
    y1s = F1.roots(multiplicities=False)
    finalstrands = []
    y1aps = [c[-1][1] for c in complexstrands]
    used = []
    for y1ap in y1aps:
        distances = [((y1ap - y1).norm(), y1) for y1 in y1s]
        y1 = sorted(distances)[0][1]
        if y1 in used:
            raise ValueError("different roots are too close")
        used.append(y1)
        finalstrands.append([(0, y1ap), (1, y1)])
    finallbraid = braid_from_piecewise(finalstrands)
    return initialbraid * centralbraid * finallbraid
예제 #28
0
def braid_monodromy(f):
    r"""
    Compute the braid monodromy of a projection of the curve defined by a polynomial

    INPUT:

    - ``f`` -- a polynomial with two variables, over a number field with an embedding
      in the complex numbers.

    OUTPUT:

    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 ``f``.

    .. NOTE::

        The projection over the `x` axis is used if there are no vertical asymptotes.
        Otherwise, a linear change of variables is done to fall into the previous case.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import braid_monodromy
        sage: R.<x,y> = QQ[]
        sage: f = (x^2-y^3)*(x+3*y-5)
        sage: braid_monodromy(f)  # optional - sirocco
        [s1*s0*(s1*s2)^2*s0*s2^2*s0^-1*(s2^-1*s1^-1)^2*s0^-1*s1^-1,
         s1*s0*(s1*s2)^2*(s0*s2^-1*s1*s2*s1*s2^-1)^2*(s2^-1*s1^-1)^2*s0^-1*s1^-1,
         s1*s0*(s1*s2)^2*s2*s1^-1*s2^-1*s1^-1*s0^-1*s1^-1,
         s1*s0*s2*s0^-1*s2*s1^-1]

    """
    global roots_interval_cache
    (x, y) = f.parent().gens()
    F = f.base_ring()
    g = f.radical()
    d = g.degree(y)
    while not g.coefficient(y**d) in F:
        g = g.subs({x: x + y})
        d = g.degree(y)
    disc = discrim(g)
    V = corrected_voronoi_diagram(tuple(disc))
    G = Graph()
    for reg in V.regions().values():
        G = G.union(reg.vertex_graph())
    E = Graph()
    for reg in V.regions().values():
        if reg.rays() or reg.lines():
            E = E.union(reg.vertex_graph())
    p = next(E.vertex_iterator())
    geombasis = geometric_basis(G, E, p)
    segs = set([])
    for p in geombasis:
        for s in zip(p[:-1], p[1:]):
            if (s[1], s[0]) not in segs:
                segs.add((s[0], s[1]))
    I = QQbar.gen()
    segs = [(a[0] + I * a[1], b[0] + I * b[1]) for (a, b) in segs]
    vertices = list(set(flatten(segs)))
    tocacheverts = [(g, v) for v in vertices]
    populate_roots_interval_cache(tocacheverts)
    gfac = g.factor()
    try:
        braidscomputed = list(
            braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]))
    except ChildProcessError:  # hack to deal with random fails first time
        braidscomputed = list(
            braid_in_segment([(gfac, seg[0], seg[1]) for seg in segs]))
    segsbraids = dict()
    for braidcomputed in braidscomputed:
        seg = (braidcomputed[0][0][1], braidcomputed[0][0][2])
        beginseg = (QQ(seg[0].real()), QQ(seg[0].imag()))
        endseg = (QQ(seg[1].real()), QQ(seg[1].imag()))
        b = braidcomputed[1]
        segsbraids[(beginseg, endseg)] = b
        segsbraids[(endseg, beginseg)] = b.inverse()
    B = b.parent()
    result = []
    for path in geombasis:
        braidpath = B.one()
        for i in range(len(path) - 1):
            x0 = tuple(path[i].vector())
            x1 = tuple(path[i + 1].vector())
            braidpath = braidpath * segsbraids[(x0, x1)]
        result.append(braidpath)
    return result
예제 #29
0
def lie_algebra_isomorphism_classes(F, dim):
    r"""
    Return a list of isomorphism classes of Lie algebras.

    INPUT:

    - ``F`` -- the base field of the Lie algebras
    - ``dim`` -- the dimension of Lie algebras to list

    The full listing is implemented for the fields of rationals ``QQ``
    and algebraic numbers ``QQbar`` up to dimension 6.

    For dimension 7, the returned list is incomplete due to existence
    of one parameter families of Lie algebras, but contains at least one
    representative from each family.
    """
    if F not in [QQ, QQbar]:
        return NotImplemented

    if dim == 1:
        return [L1_1(F)]
    if dim == 2:
        return [L2_1(F)]
    if dim == 3:
        return [L3_1(F), L3_2(F)]
    if dim == 4:
        return [L4_1(F), L4_2(F), L4_3(F)]
    if dim == 5:
        return [L5_1(F), L5_2(F), L5_3(F), L5_4(F), L5_5(F),
                L5_6(F), L5_7(F), L5_8(F), L5_9(F)]
    if dim == 6:
        l = [L6_1(F), L6_2(F), L6_3(F), L6_4(F), L6_5(F), L6_6(F), L6_7(F),
             L6_8(F), L6_9(F), L6_10(F), L6_11(F), L6_12(F), L6_13(F),
             L6_14(F), L6_15(F), L6_16(F), L6_17(F), L6_18(F), L6_19(F, -1)]
        if F == QQ:
            l += [L6_19(F, 1)]
        l += [L6_20(F), L6_21(F, -1)]
        if F == QQ:
            l += [L6_21(F, 1)]
        l += [L6_22(F, 0), L6_22(F, 1)]
        if F == QQ:
            l += [L6_22(F, -1)]
        l += [L6_23(F)]
        l += [L6_24(F, 0), L6_24(F, 1)]
        if F == QQ:
            l += [L6_24(F, -1)]
        l += [L6_25(F), L6_26(F), L6_27(F), L6_28(F)]
        return l

    if dim == 7:
        if F == QQ:
            return NotImplemented

        i = QQbar.gens()[0]

        l = [L37A(F), L37B(F), L37C(F), L37D(F)]
        l += [L357A(F), L357B(F), L357C(F)]
        l += [L27A(F), L27B(F)]
        l += [L257A(F), L257B(F), L257C(F), L257D(F), L257E(F), L257F(F),
              L257G(F), L257H(F), L257I(F), L257J(F), L257K(F), L257L(F)]
        l += [L247A(F), L247B(F), L247C(F), L247D(F), L247E(F), L247F(F),
              L247G(F), L247H(F), L247I(F), L247J(F), L247K(F), L247L(F),
              L247M(F), L247N(F), L247O(F), L247P(F), L247Q(F), L247R(F)]
        l += [L2457A(F), L2457B(F), L2457C(F), L2457D(F), L2457E(F),
              L2457F(F), L2457G(F), L2457H(F), L2457I(F),
              L2457J(F), L2457K(F), L2457L(F), L2457M(F)]
        l += [L2357A(F), L2357B(F), L2357C(F), L2357D(F)]
        l += [L23457A(F), L23457B(F), L23457C(F), L23457D(F),
              L23457E(F), L23457F(F), L23457G(F)]
        l += [L17(F)]
        l += [L157(F)]

        # 147 has a family
        # 147C = 147E(0) = 147E(1) = 247P
        l += [L147A(F), L147B(F), L147D(F)]
        l += [L147E(F, 2)]  # singular value 147E(2)=147E(1/2)=147E(-1)
        # complex singular value same as 1/2-sqrt(3)/2*i
        l += [L147E(F, QQbar(1) / 2 + QQbar(sqrt(3)) / 2 * i)]
        # non-singular value
        # 147E(3)=147E(1/3)=147E(2/3)=147E(3/2)= 147E(-1/2)=147E(-2)
        l += [L147E(F, 3)]
        # non-singular value
        # 147E(5)=147E(1/5)=147E(4/5)=147E(5/4)= 147E(-1/4)=147E(-4)
        l += [L147E(F, 5)]

        l += [L1457A(F), L1457B(F)]
        l += [L137A(F), L137B(F), L137C(F), L137D(F)]

        # 1357 has a family
        l += [L1357A(F), L1357B(F), L1357C(F), L1357D(F), L1357E(F), L1357F(F),
              L1357G(F), L1357H(F), L1357I(F), L1357J(F), L1357K(F), L1357L(F)]
        # 1357M(a)=1357M(a') iff a=a'
        # 1357M(0)=2357B
        l += [L1357M(F, 1)]  # singular value
        l += [L1357M(F, 2)]  # singular value
        l += [L1357M(F, -1)]  # singular value
        # l += [L1357M(F, QQbar(1) / 2)]  # singular value, same as 1357K
        l += [L1357M(F, -QQbar(1) / 3)]  # singular value
        # complex singular value
        l += [L1357M(F, QQbar(1) / 2 - QQbar(sqrt(3)) / 2 * i)]
        # complex singular value
        l += [L1357M(F, QQbar(1) / 2 + QQbar(sqrt(3)) / 2 * i)]
        l += [L1357M(F, 3)]  # non singular value
        l += [L1357M(F, 5)]  # non singular value
        # 1357N(a)=1357N(a') iff a=a'
        l += [L1357N(F, 0)]  # singular value
        l += [L1357N(F, 1)]  # singular value
        l += [L1357N(F, 3)]  # non singular value
        l += [L1357N(F, 5)]  # non singular value
        l += [L1357O(F), L1357P(F), L1357Q(F), L1357R(F)]
        # 1357S(a)=1357S(a') iff a*a'=1
        # 1357S(1)=2357D
        l += [L1357S(F, 0)]  # singular value
        l += [L1357S(F, QQbar(1) / 2)]  # singular value
        l += [L1357S(F, -1)]  # singular value
        # complex singular value
        l += [L1357S(F, QQbar(1) / 2 - QQbar(sqrt(3)) / 2 * i)]
        # complex singular value
        l += [L1357S(F, QQbar(1) / 2 + QQbar(sqrt(3)) / 2 * i)]
        l += [L1357S(F, 3)]  # non singular value
        l += [L1357S(F, 5)]  # non singular value

        # 13457
        # 13457H in Seeley is not a Lie algebra
        l += [L13457A(F), L13457B(F), L13457C(F), L13457D(F),
              L13457E(F), L13457F(F), L13457G(F), L13457I(F)]

        # 12457 has a family
        l += [L12457A(F), L12457B(F), L12457C(F), L12457D(F), L12457E(F),
              L12457F(F), L12457G(F), L12457H(F), L12457I(F),
              L12457J(F), L12457K(F), L12457L(F), L12457M(F)]
        # 12457N(a)=12457N(a') iff a=a' or a=-a'
        # l += [L12457N(F, 0)]  # singular value, same as 12457M
        l += [L12457N(F, 1)]  # non singular value
        l += [L12457N(F, 3)]  # non singular value
        l += [L12457N(F, 5)]  # non singular value

        l += [L12357A(F), L12357B(F), L12357C(F)]

        # 123457 has a family
        l += [L123457A(F), L123457B(F), L123457C(F), L123457D(F),
              L123457E(F), L123457F(F), L123457G(F), L123457H(F)]
        # 123457I(a)=123457I(a') iff a=a'
        l += [L123457I(F, 0)]  # non singular value
        #l += [L123457I(F, 1)]  # singular value, same as 123457G
        l += [L123457I(F, 2)]  # singular value
        l += [L123457I(F, 3)]  # singular value
        l += [L123457I(F, -1)]  # singular value
        # complex singular value
        l += [L123457I(F, QQbar(1) / 2 - QQbar(sqrt(3)) / 2 * i)]
        # complex singular value
        l += [L123457I(F, QQbar(1) / 2 + QQbar(sqrt(3)) / 2 * i)]
        return l

    return NotImplemented
예제 #30
0
    def sqrt(self, extend=True, all=False):
        """
        Return a square root of ``self``.

        With default options, the output is an element of the universal
        cyclotomic field when this element is expressed via a single root
        of unity (including rational numbers). Otherwise, return an algebraic
        number.

        INPUT:

        -  ``extend`` -- bool (default: ``True``); if ``True``, might return a
           square root in the algebraic closure of the rationals. If false,
           return a square root in the universal cyclotomic field or raises
           an error.

        -  ``all`` -- bool (default: ``False``); if ``True``, return a
           list of all square roots.

        EXAMPLES::

            sage: UCF = UniversalCyclotomicField()
            sage: UCF(3).sqrt()
            E(12)^7 - E(12)^11
            sage: (UCF(3).sqrt())**2
            3

            sage: r = UCF(-1400 / 143).sqrt()
            sage: r**2
            -1400/143

            sage: E(33).sqrt()
            -E(33)^17
            sage: E(33).sqrt() ** 2
            E(33)

            sage: (3 * E(5)).sqrt()
            -E(60)^11 + E(60)^31
            sage: (3 * E(5)).sqrt() ** 2
            3*E(5)

        Setting ``all=True`` you obtain the two square roots in a list::

            sage: UCF(3).sqrt(all=True)
            [E(12)^7 - E(12)^11, -E(12)^7 + E(12)^11]
            sage: (1 + UCF.zeta(5)).sqrt(all=True)
            [1.209762576525833? + 0.3930756888787117?*I,
             -1.209762576525833? - 0.3930756888787117?*I]

        In the following situation, Sage is not (yet) able to compute a
        square root within the universal cyclotomic field::

            sage: (E(5) + E(5, 2)).sqrt()
            0.7476743906106103? + 1.029085513635746?*I
            sage: (E(5) + E(5, 2)).sqrt(extend=False)
            Traceback (most recent call last):
            ...
            NotImplementedError: sqrt() not fully implemented for elements of Universal Cyclotomic Field
        """
        if all:
            s = self.sqrt(all=False)
            return [s, -s]

        UCF = self.parent()

        # rational case
        if self._obj.IsRat():
            D = self._obj.sage()

            if self._obj.IsInt():
                return UCF_sqrt_int(D, UCF)
            else:
                return UCF_sqrt_int(D.numerator(), UCF) / \
                       UCF_sqrt_int(D.denominator(), UCF)

        # root of unity
        k = self._obj.Conductor()
        coeffs = self._obj.CoeffsCyc(k).sage()
        if sum(bool(x) for x in coeffs) == 1:
            for i, x in enumerate(coeffs):
                if x:
                    break
            return UCF(x).sqrt() * UCF.zeta(2 * k, i)

        # no method to construct square roots yet...
        if extend:
            return QQbar(self).sqrt()
        else:
            raise NotImplementedError(
                "sqrt() not fully implemented for elements of Universal Cyclotomic Field"
            )
예제 #31
0
def roots_interval(f, x0):
    """
    Find disjoint intervals that isolate the roots of a polynomial for a fixed
    value of the first variable.

    INPUT:

    - ``f`` -- a bivariate squarefree polynomial
    - ``x0`` -- a value where the first coordinate will be fixed

    The intervals are taken as big as possible to be able to detect when two
    approximate roots of `f(x_0, y)` correspond to the same exact root.

    The result is given as a dictionary, where the keys are approximations to the roots
    with rational real and imaginary parts, and the values are intervals containing them.

    EXAMPLES::

        sage: from sage.schemes.curves.zariski_vankampen import roots_interval
        sage: R.<x,y> = QQ[]
        sage: f = y^3 - x^2
        sage: ri = roots_interval(f, 1)
        sage: ri
        {-138907099/160396102*I - 1/2: -1.? - 1.?*I,
         138907099/160396102*I - 1/2: -1.? + 1.?*I,
         1: 1.? + 0.?*I}
        sage: [r.endpoints() for r in ri.values()]
        [(0.566987298107781 - 0.433012701892219*I,
          1.43301270189222 + 0.433012701892219*I,
          0.566987298107781 + 0.433012701892219*I,
          1.43301270189222 - 0.433012701892219*I),
         (-0.933012701892219 - 1.29903810567666*I,
          -0.0669872981077806 - 0.433012701892219*I,
          -0.933012701892219 - 0.433012701892219*I,
          -0.0669872981077806 - 1.29903810567666*I),
         (-0.933012701892219 + 0.433012701892219*I,
          -0.0669872981077806 + 1.29903810567666*I,
          -0.933012701892219 + 1.29903810567666*I,
          -0.0669872981077806 + 0.433012701892219*I)]

    """
    x, y = f.parent().gens()
    I = QQbar.gen()
    fx = QQbar[y](f.subs({x: QQ(x0.real()) + I * QQ(x0.imag())}))
    roots = fx.roots(QQbar, multiplicities=False)
    result = {}
    for i in range(len(roots)):
        r = roots[i]
        prec = 53
        IF = ComplexIntervalField(prec)
        CF = ComplexField(prec)
        divisor = 4
        diam = min((CF(r) - CF(r0)).abs()
                   for r0 in roots[:i] + roots[i + 1:]) / divisor
        envelop = IF(diam) * IF((-1, 1), (-1, 1))
        while not newton(fx, r, r + envelop) in r + envelop:
            prec += 53
            IF = ComplexIntervalField(prec)
            CF = ComplexField(prec)
            divisor *= 2
            diam = min([(CF(r) - CF(r0)).abs()
                        for r0 in roots[:i] + roots[i + 1:]]) / divisor
            envelop = IF(diam) * IF((-1, 1), (-1, 1))
        qapr = QQ(CF(r).real()) + QQbar.gen() * QQ(CF(r).imag())
        if qapr not in r + envelop:
            raise ValueError("Could not approximate roots with exact values")
        result[qapr] = r + envelop
    return result