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]
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
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