def followstrand(f, x0, x1, y0a): """ Return a piecewise linear aproximation of the homotopy continuation of the root y0a from x0 to x1 INPUT: - ``f`` -- a polynomial in two variables - ``x0`` -- a complex value, where the homotopy starts - ``x1`` -- a complex value, where the homotopy ends - ``y0a`` -- an approximate solution of the polynomial $F(y)=f(x_0,y)$ OUTPUT: A list of values (t, ytr, yti) such that: - ``t`` is a real number between zero and one - $f(t\cdot x_1+(1-t)\cdot x_0, y_{tr} + I\cdot y_{ti})$ is zero (or a good enough aproximation) - the piecewise linear path determined by the points has a tubular neighborhood where the actual homotopy continuation path lies, and no other root intersects it. EXAMPLES:: sage: R.<x,y> = QQ[] sage: f = x^2 + y^3 sage: x0 = CC(1, 0) sage: x1 = CC(1, 0.5) sage: followstrand(f, x0, x1, -1.0) # optional [(0.0, -1.0, 0.0), (0.063125, -1.0001106593601545, -0.02104011456212618), (0.12230468750000001, -1.0004151100003031, -0.04075695242737829), (0.17778564453125, -1.0008762007617709, -0.059227299979315154), (0.28181243896484376, -1.0021948141328698, -0.09380038023464156), (0.3728358840942383, -1.0038270754728402, -0.123962953123039), (0.4524813985824585, -1.005613540368227, -0.15026634875747985), (0.5221712237596512, -1.0074443351354077, -0.17320066690539515), (0.5831498207896948, -1.009246118007067, -0.1931978258913501), (0.636506093190983, -1.0109719597443307, -0.21063630045261386), (0.6831928315421101, -1.0125937110987449, -0.2258465242053158), (0.7648946236565826, -1.0156754074572174, -0.2523480191006915), (0.8261709677424369, -1.0181837235093538, -0.2721208327884435), (0.8721282258068277, -1.0201720738092597, -0.2868892148703381), (0.9410641129034139, -1.0233210275568283, -0.3089391941950436), (1.0, -1.026166099551513, -0.3276894025360433)] """ G = f.change_ring(QQbar).change_ring(CIF) (x, y) = G.variables() g = G.subs({x: (1 - x) * CIF(x0) + x * CIF(x1)}) coefs = [] deg = g.total_degree() for d in range(deg + 1): for i in range(d + 1): c = CIF(g.coefficient({x: d - i, y: i})) cr = c.real() ci = c.imag() coefs += list(cr.endpoints()) coefs += list(ci.endpoints()) yr = CC(y0a).real() yi = CC(y0a).imag() points = contpath(deg, coefs, yr, yi) return points
def __getitem__(self, arg): """ Extend this ring by one or several elements to create a polynomial ring, a power series ring, or an algebraic extension. This is a convenience method intended primarily for interactive use. .. SEEALSO:: :func:`~sage.rings.polynomial.polynomial_ring_constructor.PolynomialRing`, :func:`~sage.rings.power_series_ring.PowerSeriesRing`, :meth:`~sage.rings.ring.Ring.extension`, :meth:`sage.rings.integer_ring.IntegerRing_class.__getitem__`, :meth:`sage.rings.matrix_space.MatrixSpace.__getitem__`, :meth:`sage.structure.parent.Parent.__getitem__` EXAMPLES: We create several polynomial rings:: sage: ZZ['x'] Univariate Polynomial Ring in x over Integer Ring sage: QQ['x'] Univariate Polynomial Ring in x over Rational Field sage: GF(17)['abc'] Univariate Polynomial Ring in abc over Finite Field of size 17 sage: GF(17)['a,b,c'] Multivariate Polynomial Ring in a, b, c over Finite Field of size 17 sage: GF(17)['a']['b'] Univariate Polynomial Ring in b over Univariate Polynomial Ring in a over Finite Field of size 17 We can create skew polynomial rings:: sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: k['x',Frob] Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 We can also create power series rings by using double brackets:: sage: QQ[['t']] Power Series Ring in t over Rational Field sage: ZZ[['W']] Power Series Ring in W over Integer Ring sage: ZZ[['x,y,z']] Multivariate Power Series Ring in x, y, z over Integer Ring sage: ZZ[['x','T']] Multivariate Power Series Ring in x, T over Integer Ring Use :func:`~sage.rings.fraction_field.Frac` or :meth:`~sage.rings.ring.CommutativeRing.fraction_field` to obtain the fields of rational functions and Laurent series:: sage: Frac(QQ['t']) Fraction Field of Univariate Polynomial Ring in t over Rational Field sage: Frac(QQ[['t']]) Laurent Series Ring in t over Rational Field sage: QQ[['t']].fraction_field() Laurent Series Ring in t over Rational Field Note that the same syntax can be used to create number fields:: sage: QQ[I] Number Field in I with defining polynomial x^2 + 1 sage: QQ[I].coerce_embedding() Generic morphism: From: Number Field in I with defining polynomial x^2 + 1 To: Complex Lazy Field Defn: I -> 1*I :: sage: QQ[sqrt(2)] Number Field in sqrt2 with defining polynomial x^2 - 2 sage: QQ[sqrt(2)].coerce_embedding() Generic morphism: From: Number Field in sqrt2 with defining polynomial x^2 - 2 To: Real Lazy Field Defn: sqrt2 -> 1.414213562373095? :: sage: QQ[sqrt(2),sqrt(3)] Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field and orders in number fields:: sage: ZZ[I] Order in Number Field in I with defining polynomial x^2 + 1 sage: ZZ[sqrt(5)] Order in Number Field in sqrt5 with defining polynomial x^2 - 5 sage: ZZ[sqrt(2)+sqrt(3)] Order in Number Field in a with defining polynomial x^4 - 10*x^2 + 1 Embeddings are found for simple extensions (when that makes sense):: sage: QQi.<i> = QuadraticField(-1, 'i') sage: QQ[i].coerce_embedding() Generic morphism: From: Number Field in i with defining polynomial x^2 + 1 To: Complex Lazy Field Defn: i -> 1*I TESTS: A few corner cases:: sage: QQ[()] Multivariate Polynomial Ring in no variables over Rational Field sage: QQ[[]] Traceback (most recent call last): ... TypeError: power series rings must have at least one variable These kind of expressions do not work:: sage: QQ['a,b','c'] Traceback (most recent call last): ... ValueError: variable name 'a,b' is not alphanumeric sage: QQ[['a,b','c']] Traceback (most recent call last): ... ValueError: variable name 'a,b' is not alphanumeric sage: QQ[[['x']]] Traceback (most recent call last): ... TypeError: expected R[...] or R[[...]], not R[[[...]]] Extension towers are built as follows and use distinct generator names:: sage: K = QQ[2^(1/3), 2^(1/2), 3^(1/3)] sage: K Number Field in a with defining polynomial x^3 - 2 over its base field sage: K.base_field() Number Field in sqrt2 with defining polynomial x^2 - 2 over its base field sage: K.base_field().base_field() Number Field in b with defining polynomial x^3 - 3 Embeddings:: sage: QQ[I](I.pyobject()) I sage: a = 10^100; expr = (2*a + sqrt(2))/(2*a^2-1) sage: QQ[expr].coerce_embedding() is None False sage: QQ[sqrt(5)].gen() > 0 True sage: expr = sqrt(2) + I*(cos(pi/4, hold=True) - sqrt(2)/2) sage: QQ[expr].coerce_embedding() Generic morphism: From: Number Field in a with defining polynomial x^2 - 2 To: Real Lazy Field Defn: a -> 1.414213562373095? """ def normalize_arg(arg): if isinstance(arg, (tuple, list)): # Allowing arbitrary iterables would create confusion, but we # may want to support a few more. return tuple(arg) elif isinstance(arg, str): return tuple(arg.split(',')) else: return (arg,) # 1. If arg is a list, try to return a power series ring. if isinstance(arg, list): if arg == []: raise TypeError("power series rings must have at least one variable") elif len(arg) == 1: # R[["a,b"]], R[[(a,b)]]... if isinstance(arg[0], list): raise TypeError("expected R[...] or R[[...]], not R[[[...]]]") elts = normalize_arg(arg[0]) else: elts = normalize_arg(arg) from sage.rings.power_series_ring import PowerSeriesRing return PowerSeriesRing(self, elts) if isinstance(arg, tuple): from sage.categories.morphism import Morphism if len(arg) == 2 and isinstance(arg[1], Morphism): from sage.rings.polynomial.skew_polynomial_ring_constructor import SkewPolynomialRing return SkewPolynomialRing(self, arg[1], names=arg[0]) # 2. Otherwise, if all specified elements are algebraic, try to # return an algebraic extension elts = normalize_arg(arg) try: minpolys = [a.minpoly() for a in elts] except (AttributeError, NotImplementedError, ValueError, TypeError): minpolys = None if minpolys: # how to pass in names? names = tuple(_gen_names(elts)) if len(elts) == 1: from sage.rings.all import CIF, CLF, RIF, RLF elt = elts[0] try: iv = CIF(elt) except (TypeError, ValueError): emb = None else: # First try creating an ANRoot manually, because # extension(..., embedding=CLF(expr)) (or # ...QQbar(expr)) would normalize the expression in # QQbar, which currently is VERY slow in many cases. # This may fail when minpoly has close roots or elt is # a complicated symbolic expression. # TODO: Rewrite using #19362 and/or #17886 and/or # #15600 once those issues are solved. from sage.rings.qqbar import AlgebraicNumber, ANRoot try: elt = AlgebraicNumber(ANRoot(minpolys[0], iv)) except ValueError: pass # Force a real embedding when possible, to get the # right ordered ring structure. if (iv.imag().is_zero() or iv.imag().contains_zero() and elt.imag().is_zero()): emb = RLF(elt) else: emb = CLF(elt) return self.extension(minpolys[0], names[0], embedding=emb) try: # Doing the extension all at once is best, if possible... return self.extension(minpolys, names) except (TypeError, ValueError): # ...but we can also construct it iteratively return reduce(lambda R, ext: R.extension(*ext), zip(minpolys, names), self) # 2. Otherwise, try to return a polynomial ring from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing return PolynomialRing(self, elts)
def followstrand(f, x0, x1, y0a): """ Return a piecewise linear aproximation of the homotopy continuation of the root y0a from x0 to x1 INPUT: - ``f`` -- a polynomial in two variables - ``x0`` -- a complex value, where the homotopy starts - ``x1`` -- a complex value, where the homotopy ends - ``y0a`` -- an approximate solution of the polynomial $F(y)=f(x_0,y)$ OUTPUT: A list of values (t, ytr, yti) such that: - ``t`` is a real number between zero and one - $f(t\cdot x_1+(1-t)\cdot x_0, y_{tr} + I\cdot y_{ti})$ is zero (or a good enough aproximation) - the piecewise linear path determined by the points has a tubular neighborhood where the actual homotopy continuation path lies, and no other root intersects it. EXAMPLES:: sage: R.<x,y> = QQ[] sage: f = x^2 + y^3 sage: x0 = CC(1, 0) sage: x1 = CC(1, 0.5) sage: followstrand(f, x0, x1, -1.0) # optional [(0.0, -1.0, 0.0), (0.063125, -1.0001106593601545, -0.02104011456212618), (0.12230468750000001, -1.0004151100003031, -0.04075695242737829), (0.17778564453125, -1.0008762007617709, -0.059227299979315154), (0.28181243896484376, -1.0021948141328698, -0.09380038023464156), (0.3728358840942383, -1.0038270754728402, -0.123962953123039), (0.4524813985824585, -1.005613540368227, -0.15026634875747985), (0.5221712237596512, -1.0074443351354077, -0.17320066690539515), (0.5831498207896948, -1.009246118007067, -0.1931978258913501), (0.636506093190983, -1.0109719597443307, -0.21063630045261386), (0.6831928315421101, -1.0125937110987449, -0.2258465242053158), (0.7648946236565826, -1.0156754074572174, -0.2523480191006915), (0.8261709677424369, -1.0181837235093538, -0.2721208327884435), (0.8721282258068277, -1.0201720738092597, -0.2868892148703381), (0.9410641129034139, -1.0233210275568283, -0.3089391941950436), (1.0, -1.026166099551513, -0.3276894025360433)] """ G = f.change_ring(QQbar).change_ring(CIF) (x, y) = G.variables() g = G.subs({x: (1-x)*CIF(x0) + x*CIF(x1)}) coefs = [] deg = g.total_degree() for d in range(deg + 1): for i in range(d + 1): c = CIF(g.coefficient({x: d-i, y: i})) cr = c.real() ci = c.imag() coefs += list(cr.endpoints()) coefs += list(ci.endpoints()) yr = CC(y0a).real() yi = CC(y0a).imag() points = contpath(deg, coefs, yr, yi) return points