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]
Beispiel #2
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
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
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
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
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
Beispiel #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

    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