def herm_signature(self):
        from sage.all import exp, vector, matrix
        from sage.misc.functional import numerical_approx

        n = self._dimension

        alpha_exp = [
            numerical_approx(exp(2 * 1j * pi * self._alpha[i]), 30)
            for i in xrange(self._dimension)
        ]
        beta_exp = [
            numerical_approx(exp(2 * 1j * pi * self._beta[i]), 30)
            for i in xrange(self._dimension)
        ]
        v = vector([1] * n) * matrix(
            n, n, lambda i, j: 1 / (alpha_exp[j] + beta_exp[i])).inverse()
        d_val = [
            1 / (-beta_exp[i] / v[i]).real_part()
            for i in xrange(self._dimension)
        ]
        d_val.sort()

        k = 0
        while (k < n) and (d_val[k] < 0):
            k += 1

        return (k, n - k)
    def herm_signature(self):
        from sage.all import exp, vector, matrix
        from sage.misc.functional import numerical_approx

        n = self._dimension

        alpha_exp = [numerical_approx(exp(2*1j*pi*self._alpha[i]),30) for i in xrange(self._dimension)]
        beta_exp = [numerical_approx(exp(2*1j*pi*self._beta[i]),30) for i in xrange(self._dimension)]
        v = vector([1]*n)*matrix(n,n, lambda i, j: 1/(alpha_exp[j] + beta_exp[i])).inverse()
        d_val = [1/(-beta_exp[i]/v[i]).real_part() for i in xrange(self._dimension)]
        d_val.sort()

        k = 0
        while (k < n) and (d_val[k] < 0):
            k += 1

        return(k, n-k)
Exemple #3
0
    def show(self, boundary=True, **options):
        r"""
        Plot ``self``.

        EXAMPLES::

            sage: HyperbolicPlane().PD().get_point(0).show()
            Graphics object consisting of 2 graphics primitives
            sage: HyperbolicPlane().KM().get_point((0,0)).show()
            Graphics object consisting of 2 graphics primitives
            sage: HyperbolicPlane().HM().get_point((0,0,1)).show()
            Graphics3d Object
        """
        p = self.coordinates()
        if p == infinity:
            raise NotImplementedError("can't draw the point infinity")

        opts = {'axes': False, 'aspect_ratio': 1}
        opts.update(self.graphics_options())
        opts.update(options)

        from sage.plot.point import point
        from sage.misc.functional import numerical_approx

        if self._bdry:  # It is a boundary point
            p = numerical_approx(p)
            pic = point((p, 0), **opts)
            if boundary:
                bd_pic = self._model.get_background_graphic(bd_min=p - 1,
                                                            bd_max=p + 1)
                pic = bd_pic + pic
        else:  # It is an interior point
            if p in RR:
                p = CC(p)
            elif hasattr(p, 'iteritems') or hasattr(p, '__iter__'):
                p = [numerical_approx(k) for k in p]
            else:
                p = numerical_approx(p)
            pic = point(p, **opts)
            if boundary:
                bd_pic = self.parent().get_background_graphic()
                pic = bd_pic + pic
        return pic
Exemple #4
0
    def show(self, boundary=True, **options):
        r"""
        Plot ``self``.

        EXAMPLES::

            sage: HyperbolicPlane().PD().get_point(0).show()
            Graphics object consisting of 2 graphics primitives
            sage: HyperbolicPlane().KM().get_point((0,0)).show()
            Graphics object consisting of 2 graphics primitives
            sage: HyperbolicPlane().HM().get_point((0,0,1)).show()
            Graphics3d Object
        """
        p = self.coordinates()
        if p == infinity:
            raise NotImplementedError("can't draw the point infinity")

        opts = {'axes': False, 'aspect_ratio': 1}
        opts.update(self.graphics_options())
        opts.update(options)

        from sage.plot.point import point
        from sage.misc.functional import numerical_approx

        if self._bdry:  # It is a boundary point
            p = numerical_approx(p)
            pic = point((p, 0), **opts)
            if boundary:
                bd_pic = self._model.get_background_graphic(bd_min=p - 1,
                                                            bd_max=p + 1)
                pic = bd_pic + pic
        else:  # It is an interior point
            if p in RR:
                p = CC(p)
            elif hasattr(p, 'items') or hasattr(p, '__iter__'):
                p = [numerical_approx(k) for k in p]
            else:
                p = numerical_approx(p)
            pic = point(p, **opts)
            if boundary:
                bd_pic = self.parent().get_background_graphic()
                pic = bd_pic + pic
        return pic
Exemple #5
0
 def __cmp__(self, other):
     """
     Compare two coefficient lists of the same height.
     """
     if other is not None:
         assert self.height == other.height, "comparing unequal heights"
     if self.height == 0:
         if other is None:
             val = Integer(0)
         else:
             val = other.val
         d = SR(self.val - val)
         if d.is_constant():
             d = numerical_approx(d)
             if isinstance(d, ComplexNumber):
                 p = (d.real_part(), d.imag_part())
             else:
                 p = (d, 0)
             if p > (0, 0):
                 return 1
             elif p < (0, 0):
                 return -1
         elif checkPos(self.val - val):
             return 1
         elif checkPos(val - self.val):
             return -1
         return 0
     if other is None:
         keys = set()
     else:
         keys = set(six.iterkeys(other.val))
     for k in sorted(keys.union(six.iterkeys(self.val)), reverse=True):
         if k not in keys:
             c = self.val[k].__cmp__(None)
         elif k not in self.val:
             c = -other.val[k].__cmp__(None)
         else:
             c = self.val[k].__cmp__(other.val[k])
         if c != 0:
             return c
     return 0
Exemple #6
0
    def show(self, boundary=True, **options):
        r"""
        Plot ``self``.

        EXAMPLES::

            sage: HyperbolicPlane().UHP().get_point(I).show()
            Graphics object consisting of 2 graphics primitives
            sage: HyperbolicPlane().UHP().get_point(0).show()
            Graphics object consisting of 2 graphics primitives
            sage: HyperbolicPlane().UHP().get_point(infinity).show()
            Traceback (most recent call last):
            ...
            NotImplementedError: can't draw the point infinity
        """
        p = self.coordinates()
        if p == infinity:
            raise NotImplementedError("can't draw the point infinity")
        opts = {'axes': False, 'aspect_ratio': 1}
        opts.update(self.graphics_options())
        opts.update(options)
        from sage.misc.functional import numerical_approx
        p = numerical_approx(p + 0 * I)
        from sage.plot.point import point
        if self._bdry:
            pic = point((p, 0), **opts)
            if boundary:
                bd_pic = self.parent().get_background_graphic(bd_min=p - 1,
                                                              bd_max=p + 1)
                pic = bd_pic + pic
        else:
            pic = point(p, **opts)
            if boundary:
                cent = real(p)
                bd_pic = self.parent().get_background_graphic(bd_min=cent - 1,
                                                              bd_max=cent + 1)
                pic = bd_pic + pic
        return pic
Exemple #7
0
    def show(self, boundary=True, **options):
        r"""
        Plot ``self``.

        EXAMPLES::

            sage: HyperbolicPlane().UHP().get_point(I).show()
            Graphics object consisting of 2 graphics primitives
            sage: HyperbolicPlane().UHP().get_point(0).show()
            Graphics object consisting of 2 graphics primitives
            sage: HyperbolicPlane().UHP().get_point(infinity).show()
            Traceback (most recent call last):
            ...
            NotImplementedError: can't draw the point infinity
        """
        p = self.coordinates()
        if p == infinity:
            raise NotImplementedError("can't draw the point infinity")
        opts = {'axes': False, 'aspect_ratio': 1}
        opts.update(self.graphics_options())
        opts.update(options)
        from sage.misc.functional import numerical_approx
        p = numerical_approx(p + 0 * I)
        from sage.plot.point import point
        if self._bdry:
            pic = point((p, 0), **opts)
            if boundary:
                bd_pic = self.parent().get_background_graphic(bd_min=p - 1,
                                                              bd_max=p + 1)
                pic = bd_pic + pic
        else:
            pic = point(p, **opts)
            if boundary:
                cent = real(p)
                bd_pic = self.parent().get_background_graphic(bd_min=cent - 1,
                                                              bd_max=cent + 1)
                pic = bd_pic + pic
        return pic
Exemple #8
0
    def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None,
             include_end_point=(True, True), end_point_offset=(0.001, 0.001),
             parameters=None, color='red', style='-', label_axes=True, **kwds):
        r"""
        Plot the current curve in a Cartesian graph based on the
        coordinates of some ambient chart.

        The curve is drawn in terms of two (2D graphics) or three (3D graphics)
        coordinates of a given chart, called hereafter the *ambient chart*.
        The ambient chart's domain must overlap with the curve's codomain or
        with the codomain of the composite curve `\Phi\circ c`, where `c` is
        the current curve and `\Phi` some manifold differential map (argument
        ``mapping`` below).

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above);
          if ``None``, the default chart of the codomain of the curve (or of
          the curve composed with `\Phi`) is used

        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2
          or 3 coordinates of the ambient chart in terms of which the plot
          is performed; if ``None``, all the coordinates of the ambient chart
          are considered

        - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi`
          (instance of
          :class:`~sage.manifolds.differentiable.diff_map.DiffMap`)
          providing the link between the curve and the ambient chart ``chart``
          (cf. above); if ``None``, the ambient chart is supposed to be defined
          on the codomain of the curve.

        - ``prange`` -- (default: ``None``) range of the curve parameter for
          the plot; if ``None``, the entire parameter range declared during the
          curve construction is considered (with -Infinity
          replaced by ``-max_range`` and +Infinity by ``max_range``)

        - ``include_end_point`` -- (default: ``(True, True)``) determines
          whether the end points of ``prange`` are included in the plot

        - ``end_point_offset`` -- (default: ``(0.001, 0.001)``) offsets from
          the end points when they are not included in the plot: if
          ``include_end_point[0] == False``, the minimal value of the curve
          parameter used for the plot is ``prange[0] + end_point_offset[0]``,
          while if ``include_end_point[1] == False``, the maximal value is
          ``prange[1] - end_point_offset[1]``.

        - ``max_range`` -- (default: 8) numerical value substituted to
          +Infinity if the latter is the upper bound of the parameter range;
          similarly ``-max_range`` is the numerical valued substituted for
          -Infinity

        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of the curve

        - ``color`` -- (default: 'red') color of the drawn curve

        - ``style`` -- (default: '-') color of the drawn curve; NB: ``style``
          is effective only for 2D plots

        - ``thickness`` -- (default: 1) thickness of the drawn curve

        - ``plot_points`` -- (default: 75) number of points to plot the curve

        - ``label_axes`` -- (default: ``True``) boolean determining whether the
          labels of the coordinate axes of ``chart`` shall be added to the
          graph; can be set to ``False`` if the graph is 3D and must be
          superposed with another graph.

        - ``aspect_ratio`` -- (default: ``'automatic'``) aspect ratio of the
          plot; the default value (``'automatic'``) applies only for 2D plots;
          for 3D plots, the default value is ``1`` instead

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Plot of the lemniscate of Gerono::

            sage: R2 = Manifold(2, 'R^2')
            sage: X.<x,y> = R2.chart()
            sage: R.<t> = RealLine()
            sage: c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            sage: c.plot()  # 2D plot
            Graphics object consisting of 1 graphics primitive

        .. PLOT::

            R2 = Manifold(2, 'R^2')
            X = R2.chart('x y')
            t = RealLine().canonical_coordinate()
            c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            g = c.plot()
            sphinx_plot(g)

        Plot for a subinterval of the curve's domain::

            sage: c.plot(prange=(0,pi))
            Graphics object consisting of 1 graphics primitive

        .. PLOT::

            R2 = Manifold(2, 'R^2')
            X = R2.chart('x y')
            t = RealLine().canonical_coordinate()
            c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            g = c.plot(prange=(0,pi))
            sphinx_plot(g)

        Plot with various options::

            sage: c.plot(color='green', style=':', thickness=3, aspect_ratio=1)
            Graphics object consisting of 1 graphics primitive

        .. PLOT::

            R2 = Manifold(2, 'R^2')
            X = R2.chart('x y')
            t = RealLine().canonical_coordinate()
            c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            g = c.plot(color='green', style=':', thickness=3, aspect_ratio=1)
            sphinx_plot(g)

        Plot via a mapping to another manifold: loxodrome of a sphere viewed
        in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U')
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                      sin(th)*sin(ph), cos(th)]}, name='F')
            sage: F.display()
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c')
            sage: graph_c = c.plot(mapping=F, max_range=40,
            ....:                  plot_points=200, thickness=2, label_axes=False)  # 3D plot
            sage: graph_S2 = XS.plot(X3, mapping=F, number_values=11, color='black') # plot of the sphere
            sage: show(graph_c + graph_S2) # the loxodrome + the sphere

        .. PLOT::

            S2 = Manifold(2, 'S^2')
            U = S2.open_subset('U')
            XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            th, ph = XS[:]
            R3 = Manifold(3, 'R^3')
            X3 = R3.chart('x y z')
            F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
                                            cos(th)]}, name='F')
            t = RealLine().canonical_coordinate()
            c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c')
            graph_c = c.plot(mapping=F, max_range=40, plot_points=200,
                             thickness=2, label_axes=False)
            graph_S2 = XS.plot(X3, mapping=F, number_values=11, color='black')
            sphinx_plot(graph_c + graph_S2)

        Example of use of the argument ``parameters``: we define a curve with
        some symbolic parameters ``a`` and ``b``::

            sage: a, b = var('a b')
            sage: c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c')

        To make a plot, we set specific values for ``a`` and ``b`` by means
        of the Python dictionary ``parameters``::

            sage: c.plot(parameters={a: 2, b: -3}, aspect_ratio=1)
            Graphics object consisting of 1 graphics primitive

        .. PLOT::

            R2 = Manifold(2, 'R^2')
            X = R2.chart('x y')
            t = RealLine().canonical_coordinate()
            a, b = var('a b')
            c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c')
            g = c.plot(parameters={a: 2, b: -3}, aspect_ratio=1)
            sphinx_plot(g)

        """
        from sage.rings.infinity import Infinity
        from sage.misc.functional import numerical_approx
        from sage.manifolds.chart import RealChart

        #
        # Get the @options from kwds
        #
        thickness = kwds.pop('thickness')
        plot_points = kwds.pop('plot_points')
        max_range = kwds.pop('max_range')
        aspect_ratio = kwds.pop('aspect_ratio')
        #
        # The "effective" curve to be plotted
        #
        if mapping is None:
            eff_curve = self
        else:
            eff_curve = mapping.restrict(self.codomain()) * self
        #
        # The chart w.r.t. which the curve is plotted
        #
        if chart is None:
            chart = eff_curve._codomain.default_chart()
        elif not isinstance(chart, RealChart):
            raise TypeError("{} is not a real chart".format(chart))
        #
        # Coordinates of the above chart w.r.t. which the curve is plotted
        #
        if ambient_coords is None:
            ambient_coords = chart[:]  # all chart coordinates are used
        n_pc = len(ambient_coords)
        if n_pc != 2 and n_pc !=3:
            raise ValueError("the number of coordinates involved in the " +
                             "plot must be either 2 or 3, not {}".format(n_pc))
        # indices of plot coordinates
        ind_pc = [chart[:].index(pc) for pc in ambient_coords]
        #
        # Parameter range for the plot
        #
        if prange is None:
            prange = (self._domain.lower_bound(), self._domain.upper_bound())
        elif not isinstance(prange, (tuple, list)):
            raise TypeError("{} is neither a tuple nor a list".format(prange))
        elif len(prange) != 2:
            raise ValueError("the argument prange must be a tuple/list " +
                             "of 2 elements")
        tmin = prange[0]
        tmax = prange[1]
        if tmin == -Infinity:
            tmin = -max_range
        elif not include_end_point[0]:
            tmin = tmin + end_point_offset[0]
        if tmax == Infinity:
            tmax = max_range
        elif not include_end_point[1]:
            tmax = tmax - end_point_offset[1]
        tmin = numerical_approx(tmin)
        tmax = numerical_approx(tmax)
        #
        # The coordinate expression of the effective curve
        #
        canon_chart = self._domain.canonical_chart()
        transf = None
        for chart_pair in eff_curve._coord_expression:
            if chart_pair == (canon_chart, chart):
                transf = eff_curve._coord_expression[chart_pair]
                break
        else:
            # Search for a subchart
            for chart_pair in eff_curve._coord_expression:
                for schart in chart._subcharts:
                    if chart_pair == (canon_chart, schart):
                        transf = eff_curve._coord_expression[chart_pair]
        if transf is None:
            raise ValueError("No expression has been found for " +
                              "{} in terms of {}".format(self, chart))
        #
        # List of points for the plot curve
        #
        plot_curve = []
        dt = (tmax - tmin) / (plot_points - 1)
        t = tmin
        if parameters is None:
            for i in range(plot_points):
                x = transf(t, simplify=False)
                plot_curve.append( [numerical_approx(x[j]) for j in ind_pc] )
                t += dt
        else:
             for i in range(plot_points):
                x = transf(t, simplify=False)
                plot_curve.append(
                               [numerical_approx( x[j].substitute(parameters) )
                                for j in ind_pc] )
                t += dt

        return self._graphics(plot_curve, ambient_coords,
                              thickness=thickness,
                              aspect_ratio=aspect_ratio, color= color,
                              style=style, label_axes=label_axes)
def lyap_exp_CY(beta1,
                beta2,
                nb_vectors=None,
                nb_experiments=10,
                nb_iterations=10**4,
                verbose=False,
                output_file=None,
                return_error=False):
    r"""
        Compute the Lyapunov exponents of the geodesic flow in the hypergeometric function
        space.

        The input parameters yield the eigenvalues around infinity,
        $e^{2i\pi\beta_1}, e^{2i\pi\beta_2}, e^{-2i\pi\beta_1}, e^{-2i\pi\beta_1}$.
        We compute the coefficient of the characteristic polynomial of such a matrix.
        And call the C function which associate to these coefficient the companion matrices
        of the polynomial. We use Levelt theorem for computing monodromy matrices.
        See Theorem 3.2.3 in [Beu].

        INPUT:

        - ``beta1``, ``beta2`` -- parameters of the eigenvalues

        - ``nb_vectors`` -- the number of vectors to use

        - ``nb_experiments`` -- number of experimets

        - ``nb_iterations`` -- the number of iterations of the induction to perform

        - ``output_file`` -- place where we print the results

        - ``verbose`` -- do we print the result with an extensive number of information or not

        OUTPUT:

        A list of nb_vectors lyapunov exponents by default.

        If return_error is True, a 4-tuple consisting of :

        1. a list of nb_vectors lyapunov exponents
        2. a list of nb_vectors of their statistical error
        3. an integer of their sum
        4. an integer of the statistical error of their sum
        """
    from sage.all import exp
    from sage.misc.functional import numerical_approx

    import time
    import lyapunov_exponents  # the cython bindings
    from math import sqrt

    if output_file is None:
        from sys import stdout
        output_file = stdout
        closed = True
    elif isinstance(output_file, str):
        output_file = open(output_file, "w")
        closed = False

    beta1 = numerical_approx(beta1)
    beta2 = numerical_approx(beta2)
    b1 = numerical_approx(exp(2 * 1j * pi * beta1))
    b2 = numerical_approx(exp(2 * 1j * pi * beta2))
    a = (b1**2 * b2 + b1 * b2**2 + b1 + b2) / (b1 * b2)
    b = (-b1**2 * b2**2 - b1**2 - 2 * b1 * b2 - b2**2 - 1) / (b1 * b2)

    if nb_vectors <> None and nb_vectors <= 0:
        raise ValueError("the number of vectors must be positive")
    if nb_experiments <= 0:
        raise ValueError("the number of experiments must be positive")
    if nb_iterations <= 0:
        raise ValueError("the number of iterations must be positive")

    #recall that the lyapunov exponents are symmetric
    if nb_vectors == None:
        nb_vectors = 2

    t0 = time.time()
    res = lyapunov_exponents.lyapunov_exponents([0] * 4, [0] * 4, 4,
                                                nb_vectors, nb_experiments,
                                                nb_iterations, [a, b])
    t1 = time.time()

    res_final = []
    std_final = []
    s_m, s_d = 0, 0

    if verbose:
        from math import floor, log
        output_file.write("sample of %d experiments\n" % nb_experiments)
        output_file.write("%d iterations (~2**%d)\n" %
                          (nb_iterations, floor(log(nb_iterations) / log(2))))
        output_file.write("ellapsed time %s\n" %
                          time.strftime("%H:%M:%S", time.gmtime(t1 - t0)))
    for i in xrange(nb_vectors):
        m, d = mean_and_std_dev(res[i])
        s_m += m
        s_d += d**2
        if verbose:
            output_file.write(
                "theta%d           : %f (std. dev. = %f, conf. rad. 0.01 = %f)\n"
                % (i, m, d, 2.576 * d / sqrt(nb_experiments)))
        res_final.append(m)
        std_final.append(2.576 * d / sqrt(nb_experiments))

    s_d = sqrt(s_d)
    s_d_final = 2.576 * s_d / sqrt(nb_experiments)
    if verbose:
        output_file.write(
            "sum_theta        : %f (std. dev. = %f, conf. rad. 0.01 = %f)\n\n"
            % (s_m, s_d, 2.576 * s_d / sqrt(nb_experiments)))

    if not closed:
        output_file.close()
        print "file closed"

    if return_error:
        return (res_final, std_final, s_m, s_d_final)
    else:
        return res_final
Exemple #10
0
def compute_percolation_probability(range_p, d, n, stop):
    r"""
    EXAMPLES::

        sage: from slabbe.bond_percolation import compute_percolation_probability
        sage: compute_percolation_probability(srange(0,0.8,0.1), d=2, n=5, stop=100) # random
        d = 2, n = number of samples = 5
        stop counting at = 100
        p=0.0000, Theta=0.000, if |C|< 100 then max|C|=1
        p=0.1000, Theta=0.000, if |C|< 100 then max|C|=1
        p=0.2000, Theta=0.000, if |C|< 100 then max|C|=5
        p=0.3000, Theta=0.000, if |C|< 100 then max|C|=6
        p=0.4000, Theta=0.000, if |C|< 100 then max|C|=31
        p=0.5000, Theta=1.00, if |C|< 100 then max|C|=-Infinity
        p=0.6000, Theta=1.00, if |C|< 100 then max|C|=-Infinity
        p=0.7000, Theta=1.00, if |C|< 100 then max|C|=-Infinity

    ::

        sage: range_p = srange(0,0.8,0.1)
        sage: compute_percolation_probability(range_p, d=2, n=5, stop=100) # not tested
        d = 2, n = number of samples = 5
        stop counting at = 100
        p=0.0000, Theta=0.000, if |C|< 100 then max|C|=1
        p=0.1000, Theta=0.000, if |C|< 100 then max|C|=1
        p=0.2000, Theta=0.000, if |C|< 100 then max|C|=5
        p=0.3000, Theta=0.000, if |C|< 100 then max|C|=6
        p=0.4000, Theta=0.000, if |C|< 100 then max|C|=31
        p=0.5000, Theta=1.00, if |C|< 100 then max|C|=-Infinity
        p=0.6000, Theta=1.00, if |C|< 100 then max|C|=-Infinity
        p=0.7000, Theta=1.00, if |C|< 100 then max|C|=-Infinity

    ::

        sage: range_p = srange(0.45,0.55,0.01)
        sage: compute_percolation_probability(range_p, d=2, n=10, stop=1000) # not tested
        d = 2, n = number of samples = 10
        stop counting at = 1000
        p=0.4500, Theta=0.000, if |C|< 1000 then max|C|=378
        p=0.4600, Theta=0.000, if |C|< 1000 then max|C|=475
        p=0.4700, Theta=0.000, if |C|< 1000 then max|C|=514
        p=0.4800, Theta=0.100, if |C|< 1000 then max|C|=655
        p=0.4900, Theta=0.700, if |C|< 1000 then max|C|=274
        p=0.5000, Theta=0.700, if |C|< 1000 then max|C|=975
        p=0.5100, Theta=0.700, if |C|< 1000 then max|C|=16
        p=0.5200, Theta=0.700, if |C|< 1000 then max|C|=125
        p=0.5300, Theta=0.900, if |C|< 1000 then max|C|=4
        p=0.5400, Theta=0.700, if |C|< 1000 then max|C|=6

    ::

        sage: range_p = srange(0.475,0.485,0.001)
        sage: compute_percolation_probability(range_p, d=2, n=10, stop=1000) # not tested
        d = 2, n = number of samples = 10
        stop counting at = 1000
        p=0.4750, Theta=0.200, if |C|< 1000 then max|C|=718
        p=0.4760, Theta=0.200, if |C|< 1000 then max|C|=844
        p=0.4770, Theta=0.200, if |C|< 1000 then max|C|=566
        p=0.4780, Theta=0.500, if |C|< 1000 then max|C|=257
        p=0.4790, Theta=0.200, if |C|< 1000 then max|C|=566
        p=0.4800, Theta=0.300, if |C|< 1000 then max|C|=544
        p=0.4810, Theta=0.300, if |C|< 1000 then max|C|=778
        p=0.4820, Theta=0.500, if |C|< 1000 then max|C|=983
        p=0.4830, Theta=0.300, if |C|< 1000 then max|C|=473
        p=0.4840, Theta=0.500, if |C|< 1000 then max|C|=411

    ::

        sage: range_p = srange(0.47,0.48,0.001)
        sage: compute_percolation_probability(range_p, d=2, n=20, stop=2000)  # not tested
        d = 2, n = number of samples = 20
        stop counting at = 2000
        p=0.4700, Theta=0.0500, if |C|< 2000 then max|C|=1666
        p=0.4710, Theta=0.100, if |C|< 2000 then max|C|=1665
        p=0.4720, Theta=0.000, if |C|< 2000 then max|C|=1798
        p=0.4730, Theta=0.0500, if |C|< 2000 then max|C|=1717
        p=0.4740, Theta=0.150, if |C|< 2000 then max|C|=1924
        p=0.4750, Theta=0.150, if |C|< 2000 then max|C|=1893
        p=0.4760, Theta=0.150, if |C|< 2000 then max|C|=1458
        p=0.4770, Theta=0.150, if |C|< 2000 then max|C|=1573
        p=0.4780, Theta=0.200, if |C|< 2000 then max|C|=1762
        p=0.4790, Theta=0.250, if |C|< 2000 then max|C|=951
    """
    print "d = %s, n = number of samples = %s" % (d, n)
    print "stop counting at = %s" % stop
    for p in range_p:
        p = numerical_approx(p, digits=4)
        S = BondPercolationSamples(p, d, n)
        L = [a for a in S.cluster_cardinality(stop) if not isinstance(a, str)]
        Y = max(L) if L else -Infinity
        theta = S.percolation_probability(stop)
        print "p=%s, Theta=%s, if |C|< %s then max|C|=%s" % (p, theta, stop, Y)
Exemple #11
0
    def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None,
             include_end_point=(True, True), end_point_offset=(0.001, 0.001),
             max_value=8, parameters=None, color='red',  style='-',
             thickness=1, plot_points=75, label_axes=True,
             aspect_ratio='automatic'):
        r"""
        Plot the current curve (``self``) in a Cartesian graph based on the
        coordinates of some ambient chart.

        The curve is drawn in terms of two (2D graphics) or three (3D graphics)
        coordinates of a given chart, called hereafter the *ambient chart*.
        The ambient chart's domain must overlap with the curve's codomain or
        with the codomain of the composite curve `\Phi\circ c`, where `c` is
        ``self`` and `\Phi` some manifold differential mapping (argument
        ``mapping`` below).

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above);
          if ``None``, the default chart of the codomain of the curve (or of
          the curve composed with `\Phi`) is used
        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3
          coordinates of the ambient chart in terms of which the plot is
          performed; if ``None``, all the coordinates of the ambient chart are
          considered
        - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi`
          (instance of
          :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`)
          providing the link between ``self`` and the ambient chart ``chart``
          (cf. above); if ``None``, the ambient chart is supposed to be defined
          on the codomain of the curve ``self``.
        - ``prange`` -- (default: ``None``) range of the curve parameter for
          the plot; if ``None``, the entire parameter range declared during the
          curve construction is considered (with -Infinity
          replaced by ``-max_value`` and +Infinity by ``max_value``)
        - ``include_end_point`` -- (default: ``(True, True)``) determines
          whether the end points of ``prange`` are included in the plot
        - ``end_point_offset`` -- (default: ``(0.001, 0.001)``) offsets from
          the end points when they are not included in the plot: if
          ``include_end_point[0] == False``, the minimal value of the curve
          parameter used for the plot is ``prange[0] + end_point_offset[0]``,
          while if ``include_end_point[1] == False``, the maximal value is
          ``prange[1] - end_point_offset[1]``.
        - ``max_value`` -- (default: 8) numerical value substituted to
          +Infinity if the latter is the upper bound of the parameter range;
          similarly ``-max_value`` is the numerical valued substituted for
          -Infinity
        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of ``self``
        - ``color`` -- (default: 'red') color of the drawn curve
        - ``style`` -- (default: '-') color of the drawn curve; NB: ``style``
          is effective only for 2D plots
        - ``thickness`` -- (default: 1) thickness of the drawn curve
        - ``plot_points`` -- (default: 75) number of points to plot the curve
        - ``label_axes`` -- (default: ``True``) boolean determining whether the
          labels of the coordinate axes of ``chart`` shall be added to the
          graph; can be set to ``False`` if the graph is 3D and must be
          superposed with another graph.
        - ``aspect_ratio`` -- (default: 'automatic') aspect ratio of the plot;
          the default value ('automatic') applies only for 2D plots; for
          3D plots, the default value is ``1`` instead.

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Plot of the lemniscate of Gerono::

            sage: R2 = Manifold(2, 'R^2')
            sage: X.<x,y> = R2.chart()
            sage: R.<t> = RealLine()
            sage: c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c')
            sage: c.plot()  # 2D plot
            Graphics object consisting of 1 graphics primitive

        Plot for a subinterval of the curve's domain::

            sage: c.plot(prange=(0,pi))
            Graphics object consisting of 1 graphics primitive

        Plot with various options::

            sage: c.plot(color='green', style=':', thickness=3, aspect_ratio=1)
            Graphics object consisting of 1 graphics primitive

        Plot via a mapping to another manifold: loxodrome of a sphere viewed
        in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U')
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_mapping(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                     sin(th)*sin(ph), cos(th)]}, name='F')
            sage: F.display()
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c')
            sage: graph_c = c.plot(mapping=F, max_value=40,
            ....:                  plot_points=200, thickness=2, label_axes=False)  # 3D plot
            sage: graph_S2 = XS.plot(X3, mapping=F, nb_values=11, color='black') # plot of the sphere
            sage: show(graph_c + graph_S2) # the loxodrome + the sphere

        Example of use of the argument ``parameters``: we define a curve with
        some symbolic parameters ``a`` and ``b``::

            sage: a, b = var('a b')
            sage: c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c')

        To make a plot, we set spectific values for ``a`` and ``b`` by means
        of the Python dictionary ``parameters``::

            sage: c.plot(parameters={a: 2, b: -3}, aspect_ratio=1)
            Graphics object consisting of 1 graphics primitive

        """
        from sage.rings.infinity import Infinity
        from sage.misc.functional import numerical_approx
        from sage.plot.graphics import Graphics
        from sage.plot.line import line
        from sage.geometry.manifolds.chart import Chart
        from sage.geometry.manifolds.utilities import set_axes_labels
        #
        # The "effective" curve to be plotted
        #
        if mapping is None:
            eff_curve = self
        else:
            eff_curve = mapping.restrict(self.codomain()) * self
        #
        # The chart w.r.t. which the curve is plotted
        #
        if chart is None:
            chart = eff_curve._codomain.default_chart()
        elif not isinstance(chart, Chart):
            raise TypeError("{} is not a chart".format(chart))
        #
        # Coordinates of the above chart w.r.t. which the curve is plotted
        #
        if ambient_coords is None:
            ambient_coords = chart[:]  # all chart coordinates are used
        n_pc = len(ambient_coords)
        if n_pc != 2 and n_pc !=3:
            raise ValueError("The number of coordinates involved in the " +
                             "plot must be either 2 or 3, not {}".format(n_pc))
        ind_pc = [chart[:].index(pc) for pc in ambient_coords] # indices of plot
                                                            # coordinates
        #
        # Parameter range for the plot
        #
        if prange is None:
            prange = (self._domain.lower_bound(), self._domain.upper_bound())
        elif not isinstance(prange, (tuple, list)):
            raise TypeError("{} is neither a tuple nor a list".format(prange))
        elif len(prange) != 2:
            raise ValueError("the argument prange must be a tuple/list " +
                             "of 2 elements")
        tmin = prange[0]
        tmax = prange[1]
        if tmin == -Infinity:
            tmin = -max_value
        elif not include_end_point[0]:
            tmin = tmin + end_point_offset[0]
        if tmax == Infinity:
            tmax = max_value
        elif not include_end_point[1]:
            tmax = tmax - end_point_offset[1]
        tmin = numerical_approx(tmin)
        tmax = numerical_approx(tmax)
        #
        # The coordinate expression of the effective curve
        #
        canon_chart = self._domain.canonical_chart()
        transf = None
        for chart_pair in eff_curve._coord_expression:
            if chart_pair == (canon_chart, chart):
                transf = eff_curve._coord_expression[chart_pair]
                break
        else:
            # Search for a subchart
            for chart_pair in eff_curve._coord_expression:
                for schart in chart._subcharts:
                    if chart_pair == (canon_chart, schart):
                        transf = eff_curve._coord_expression[chart_pair]
        if transf is None:
            raise ValueError("No expression has been found for " +
                              "{} in terms of {}".format(self, format))
        #
        # List of points for the plot curve
        #
        plot_curve = []
        dt = (tmax - tmin) / (plot_points - 1)
        t = tmin
        if parameters is None:
            for i in range(plot_points):
                x = transf(t, simplify=False)
                plot_curve.append( [numerical_approx(x[j]) for j in ind_pc] )
                t += dt
        else:
             for i in range(plot_points):
                x = transf(t, simplify=False)
                plot_curve.append(
                               [numerical_approx( x[j].substitute(parameters) )
                                for j in ind_pc] )
                t += dt
        #
        # The plot
        #
        resu = Graphics()
        resu += line(plot_curve, color=color, linestyle=style,
                     thickness=thickness)
        if n_pc==2:  # 2D graphic
            resu.set_aspect_ratio(aspect_ratio)
            if label_axes:
                # We update the dictionary _extra_kwds (options to be passed
                # to show()), instead of using the method
                # Graphics.axes_labels() since the latter is not robust w.r.t.
                # graph addition
                resu._extra_kwds['axes_labels'] = [r'$'+latex(pc)+r'$'
                                                   for pc in ambient_coords]
        else: # 3D graphic
            if aspect_ratio == 'automatic':
                aspect_ratio = 1
            resu.aspect_ratio(aspect_ratio)
            if label_axes:
                labels = [str(pc) for pc in ambient_coords]
                resu = set_axes_labels(resu, *labels)
        return resu
Exemple #12
0
    def plot(self,
             chart=None,
             ambient_coords=None,
             mapping=None,
             chart_domain=None,
             fixed_coords=None,
             ranges=None,
             max_value=8,
             nb_values=None,
             steps=None,
             scale=1,
             color='blue',
             parameters=None,
             label_axes=True,
             **extra_options):
        r"""
        Plot the vector field in a Cartesian graph based on the coordinates
        of some ambient chart.

        The vector field is drawn in terms of two (2D graphics) or three
        (3D graphics) coordinates of a given chart, called hereafter the
        *ambient chart*.
        The vector field's base points `p` (or their images `\Phi(p)` by some
        differentiable mapping `\Phi`) must lie in the ambient chart's domain.

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above); if
          ``None``, the default chart of the vector field's domain is used
        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3
          coordinates of the ambient chart in terms of which the plot is
          performed; if ``None``, all the coordinates of the ambient chart are
          considered
        - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi`
          (instance of
          :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`)
          providing the link between the vector field's domain and
          the ambient chart ``chart``; if ``None``, the identity mapping is
          assumed
        - ``chart_domain`` -- (default: ``None``) chart on the vector
          field's domain to define the points at which vector arrows are to be
          plotted; if ``None``, the default chart of the vector field's domain
          is used
        - ``fixed_coords`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` that are kept fixed and with values
          the value of these coordinates; if ``None``, all the coordinates of
          ``chart_domain`` are used
        - ``ranges`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` to be used and values
          tuples ``(x_min,x_max)`` specifying the
          coordinate range for the plot; if ``None``, the entire coordinate
          range declared during the construction of ``chart_domain`` is
          considered (with ``-Infinity`` replaced by ``-max_value`` and
          ``+Infinity`` by ``max_value``)
        - ``max_value`` -- (default: 8) numerical value substituted to
          ``+Infinity`` if the latter is the upper bound of the range of a
          coordinate for which the plot is performed over the entire coordinate
          range (i.e. for which no specific plot range has been set in
          ``ranges``); similarly ``-max_value`` is the numerical valued
          substituted for ``-Infinity``
        - ``nb_values`` -- (default: ``None``) either an integer or a dictionary
          with keys the coordinates of ``chart_domain`` to be used and values
          the number of values of the coordinate for sampling
          the part of the vector field's domain involved in the plot ; if
          ``nb_values`` is a single integer, it represents the number of
          values for all coordinates; if ``nb_values`` is ``None``, it is set
          to 9 for a 2D plot and to 5 for a 3D plot
        - ``steps`` -- (default: ``None``) dictionary with keys the coordinates
          of ``chart_domain`` to be used and values the step between each
          constant value of the coordinate; if ``None``, the step is computed
          from the coordinate range (specified in ``ranges``) and ``nb_values``.
          On the contrary, if the step is provided for some coordinate, the
          corresponding number of values is deduced from it and the coordinate
          range.
        - ``scale`` -- (default: 1) value by which the lengths of the arrows
          representing the vectors is multiplied
        - ``color`` -- (default: 'blue') color of the arrows representing the
          vectors
        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of the vector field (see example below)
        - ``label_axes`` -- (default: ``True``) boolean determining whether the
          labels of the coordinate axes of ``chart`` shall be added to the
          graph; can be set to ``False`` if the graph is 3D and must be
          superposed with another graph.
        - ``**extra_options`` -- extra options for the arrow plot, like
          ``linestyle``, ``width`` or ``arrowsize`` (see
          :func:`~sage.plot.arrow.arrow2d` and
          :func:`~sage.plot.plot3d.shapes.arrow3d` for details)

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Plot of a vector field on a 2-dimensional manifold::

            sage: Manifold._clear_cache_() # for doctests only
            sage: M = Manifold(2, 'M')
            sage: X.<x,y> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = -y, x ; v.display()
            v = -y d/dx + x d/dy
            sage: v.plot()
            Graphics object consisting of 80 graphics primitives

        Plot with various options::

            sage: v.plot(scale=0.5, color='green', linestyle='--', width=1, arrowsize=6)
            Graphics object consisting of 80 graphics primitives
            sage: v.plot(max_value=4, nb_values=5, scale=0.5)
            Graphics object consisting of 24 graphics primitives

        Plots along a line of fixed coordinate::

            sage: v.plot(fixed_coords={x: -2})
            Graphics object consisting of 9 graphics primitives
            sage: v.plot(fixed_coords={y: 1})
            Graphics object consisting of 9 graphics primitives

        Let us now consider a vector field on a 4-dimensional manifold::

            sage: Manifold._clear_cache_() # for doctests only
            sage: M = Manifold(4, 'M')
            sage: X.<t,x,y,z> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = (t/8)^2, -t*y/4, t*x/4, t*z/4 ; v.display()
            v = 1/64*t^2 d/dt - 1/4*t*y d/dx + 1/4*t*x d/dy + 1/4*t*z d/dz

        We cannot make a 4D plot directly::

            sage: v.plot()
            Traceback (most recent call last):
            ...
            ValueError: the number of ambient coordinates must be either 2 or 3, not 4

        Rather, we have to select some coordinates for the plot, via
        the argument ``ambient_coords``. For instance, for a 3D plot::

            sage: v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1})
            Graphics3d Object
            sage: v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},
            ....:        ranges={x: (-2,2), y: (-2,2), t: (-1, 4)}, nb_values=4)
            Graphics3d Object

        or, for a 2D plot::

            sage: v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})
            Graphics object consisting of 80 graphics primitives
            sage: v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})
            Graphics object consisting of 72 graphics primitives

        An example of plot via a differential mapping: plot of a vector field
        tangent to a 2-sphere viewed in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U') # the open set covered by spherical coord.
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_mapping(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                     sin(th)*sin(ph), cos(th)]}, name='F')
            sage: F.display() # the standard embedding of S^2 into R^3
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: v = XS.frame()[1] ; v
            vector field 'd/dph' on the open subset 'U' of the 2-dimensional manifold 'S^2'
            sage: graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
            sage: graph_S2 = XS.plot(chart=X3, mapping=F, nb_values=9)
            sage: show(graph_v + graph_S2)

        """
        from sage.rings.infinity import Infinity
        from sage.misc.functional import numerical_approx
        from sage.misc.latex import latex
        from sage.plot.graphics import Graphics
        from sage.geometry.manifolds.chart import Chart
        from sage.geometry.manifolds.utilities import set_axes_labels
        #
        # 1/ Treatment of input parameters
        #    -----------------------------
        if chart is None:
            chart = self._domain.default_chart()
        elif not isinstance(chart, Chart):
            raise TypeError("{} is not a chart".format(chart))
        if chart_domain is None:
            chart_domain = self._domain.default_chart()
        elif not isinstance(chart_domain, Chart):
            raise TypeError("{} is not a chart".format(chart_domain))
        elif not chart_domain.domain().is_subset(self._domain):
            raise ValueError("The domain of {} is not ".format(chart_domain) +
                             "included in the domain of {}".format(self))
        if fixed_coords is None:
            coords = chart_domain._xx
        else:
            fixed_coord_list = fixed_coords.keys()
            coords = []
            for coord in chart_domain._xx:
                if coord not in fixed_coord_list:
                    coords.append(coord)
            coords = tuple(coords)
        if ambient_coords is None:
            ambient_coords = chart[:]
        elif not isinstance(ambient_coords, tuple):
            ambient_coords = tuple(ambient_coords)
        nca = len(ambient_coords)
        if nca != 2 and nca != 3:
            raise ValueError("the number of ambient coordinates must be " +
                             "either 2 or 3, not {}".format(nca))
        if ranges is None:
            ranges = {}
        ranges0 = {}
        for coord in coords:
            if coord in ranges:
                ranges0[coord] = (numerical_approx(ranges[coord][0]),
                                  numerical_approx(ranges[coord][1]))
            else:
                bounds = chart_domain._bounds[chart_domain[:].index(coord)]
                if bounds[0][0] == -Infinity:
                    xmin = numerical_approx(-max_value)
                elif bounds[0][1]:
                    xmin = numerical_approx(bounds[0][0])
                else:
                    xmin = numerical_approx(bounds[0][0] + 1.e-3)
                if bounds[1][0] == Infinity:
                    xmax = numerical_approx(max_value)
                elif bounds[1][1]:
                    xmax = numerical_approx(bounds[1][0])
                else:
                    xmax = numerical_approx(bounds[1][0] - 1.e-3)
                ranges0[coord] = (xmin, xmax)
        ranges = ranges0
        if nb_values is None:
            if nca == 2:  # 2D plot
                nb_values = 9
            else:  # 3D plot
                nb_values = 5
        if not isinstance(nb_values, dict):
            nb_values0 = {}
            for coord in coords:
                nb_values0[coord] = nb_values
            nb_values = nb_values0
        if steps is None:
            steps = {}
        for coord in coords:
            if coord not in steps:
                steps[coord] = (ranges[coord][1] - ranges[coord][0])/ \
                               (nb_values[coord]-1)
            else:
                nb_values[coord] = 1 + int(
                    (ranges[coord][1] - ranges[coord][0]) / steps[coord])
        #
        # 2/ Plots
        #    -----
        dom = chart_domain.domain()
        nc = len(chart_domain[:])
        ncp = len(coords)
        xx = [0] * nc
        if fixed_coords is not None:
            if len(fixed_coords) != nc - ncp:
                raise ValueError("Bad number of fixed coordinates.")
            for fc, val in fixed_coords.iteritems():
                xx[chart_domain[:].index(fc)] = val
        index_p = [chart_domain[:].index(cd) for cd in coords]
        resu = Graphics()
        ind = [0] * ncp
        ind_max = [0] * ncp
        ind_max[0] = nb_values[coords[0]]
        xmin = [ranges[cd][0] for cd in coords]
        step_tab = [steps[cd] for cd in coords]
        while ind != ind_max:
            for i in range(ncp):
                xx[index_p[i]] = xmin[i] + ind[i] * step_tab[i]
            if chart_domain.valid_coordinates(*xx,
                                              tolerance=1e-13,
                                              parameters=parameters):
                point = dom(xx, chart=chart_domain)
                resu += self.at(point).plot(chart=chart,
                                            ambient_coords=ambient_coords,
                                            mapping=mapping,
                                            scale=scale,
                                            color=color,
                                            print_label=False,
                                            parameters=parameters,
                                            **extra_options)
            # Next index:
            ret = 1
            for pos in range(ncp - 1, -1, -1):
                imax = nb_values[coords[pos]] - 1
                if ind[pos] != imax:
                    ind[pos] += ret
                    ret = 0
                elif ret == 1:
                    if pos == 0:
                        ind[pos] = imax + 1  # end point reached
                    else:
                        ind[pos] = 0
                        ret = 1
        if label_axes:
            if nca == 2:  # 2D graphic
                # We update the dictionary _extra_kwds (options to be passed
                # to show()), instead of using the method
                # Graphics.axes_labels() since the latter is not robust w.r.t.
                # graph addition
                resu._extra_kwds['axes_labels'] = [
                    r'$' + latex(ac) + r'$' for ac in ambient_coords
                ]
            else:  # 3D graphic
                labels = [str(ac) for ac in ambient_coords]
                resu = set_axes_labels(resu, *labels)
        return resu
Exemple #13
0
    def isogeny_degree4k_strategy(self, Q, k, method, stop=0):
        '''
        INPUT:
        * self the point defining the kernel of the isogeny, of degree 4**k
        * Q a point that we want to evaluate
        * k such that the isogeny is of degree 4**k
        * method a string defining the method to use : withKernel4, withKernel4k or withoutKernel
        OUTPUT:
        * phiQ the image of Q
        * phiQ4k a point generating the dual isogeny kernel   (if method = 'kernel4k')
        * listOfCurves the list of 4-isogenous curvesq        (if method = 'kernel4')
        REMARKS:
        * self needs to be such that [4**(k-1)] self  has x-coordinate != +/- 1.
        '''

        l = k
        phiP4k = self
        curve_prime = copy(self.curve)
        image_points = [Q] + [self]

        listOfCurves_a = []

        if method == 'kernel4k':
            Q4k = self.dual_kernel_point(k)
            #evaluate Q4k give the kernel of the dual isogeny
            image_points += [Q4k]
        Queue1 = deque()
        Queue1.append([k, self])

        PRINTCOUNTER = 0
        DEC = 0

        i = 0
        F = self.curve
        list1 = copy(image_points)
        while len(Queue1) != 0 and l > stop:
            [h, P] = Queue1.pop()
            if h == 1:
                Queue2 = deque()
                while len(Queue1) != 0:
                    [h, Q] = Queue1.popleft()
                    [Q] = P.isogeny_degree4([Q])
                    Queue2.append([h - 1, Q])
                Queue1 = Queue2
                list1 = P.isogeny_degree4(list1)
                PRINTCOUNTER += 1
                if numerical_approx(100 * PRINTCOUNTER / k) > DEC:
                    DEC += 10
                    if k > 50:
                        print('%d\% of the (big) step' %
                              floor(100 * PRINTCOUNTER / k))
                F = list1[0].curve
                if method == 'kernel4':
                    listOfCurves_a.append(F)
                l -= 1
            elif self.curve.strategy[i] > 0 and self.curve.strategy[i] < h:
                Queue1.append([h, P])
                P = 4**(self.curve.strategy[i]) * P
                Queue1.append([h - self.curve.strategy[i], P])
                i += 1
            else:
                return false
        #output
        phiQ = list1[0]

        if method == 'kernel4k':
            # the point defining the dual is the 3rd one of image_points evaluated by the 4-isogenies
            phiQ4k = list1[2]
        else:
            phiQ4k = None

        if method != 'kernel4':
            listOfCurves_a = None
        return [phiQ, phiQ4k, listOfCurves_a]
Exemple #14
0
    def plot(self,
             chart=None,
             ambient_coords=None,
             mapping=None,
             chart_domain=None,
             fixed_coords=None,
             ranges=None,
             number_values=None,
             steps=None,
             parameters=None,
             label_axes=True,
             **extra_options):
        r"""
        Plot the vector field in a Cartesian graph based on the coordinates
        of some ambient chart.

        The vector field is drawn in terms of two (2D graphics) or three
        (3D graphics) coordinates of a given chart, called hereafter the
        *ambient chart*.
        The vector field's base points `p` (or their images `\Phi(p)` by some
        differentiable mapping `\Phi`) must lie in the ambient chart's domain.

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above); if
          ``None``, the default chart of the vector field's domain is used

        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2
          or 3 coordinates of the ambient chart in terms of which the plot
          is performed; if ``None``, all the coordinates of the ambient
          chart are considered

        - ``mapping`` -- :class:`~sage.manifolds.differentiable.diff_map.DiffMap`
          (default: ``None``); differentiable map `\Phi` providing the link
          between the vector field's domain and the ambient chart ``chart``;
          if ``None``, the identity map is assumed

        - ``chart_domain`` -- (default: ``None``) chart on the vector field's
          domain to define the points at which vector arrows are to be plotted;
          if ``None``, the default chart of the vector field's domain is used

        - ``fixed_coords`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` that are kept fixed and with values
          the value of these coordinates; if ``None``, all the coordinates of
          ``chart_domain`` are used

        - ``ranges`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` to be used and values tuples
          ``(x_min, x_max)`` specifying the coordinate range for the plot;
          if ``None``, the entire coordinate range declared during the
          construction of ``chart_domain`` is considered (with ``-Infinity``
          replaced by ``-max_range`` and ``+Infinity`` by ``max_range``)

        - ``number_values`` -- (default: ``None``) either an integer or a
          dictionary with keys the coordinates of ``chart_domain`` to be
          used and values the number of values of the coordinate for sampling
          the part of the vector field's domain involved in the plot ; if
          ``number_values`` is a single integer, it represents the number of
          values for all coordinates; if ``number_values`` is ``None``, it is
          set to 9 for a 2D plot and to 5 for a 3D plot

        - ``steps`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` to be used and values the step
          between each constant value of the coordinate; if ``None``, the
          step is computed from the coordinate range (specified in ``ranges``)
          and ``number_values``; on the contrary, if the step is provided
          for some coordinate, the corresponding number of values is deduced
          from it and the coordinate range

        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of the vector field (see example below)

        - ``label_axes`` -- (default: ``True``) boolean determining whether
          the labels of the coordinate axes of ``chart`` shall be added to
          the graph; can be set to ``False`` if the graph is 3D and must be
          superposed with another graph

        - ``color`` -- (default: 'blue') color of the arrows representing
          the vectors

        - ``max_range`` -- (default: 8) numerical value substituted to
          ``+Infinity`` if the latter is the upper bound of the range of a
          coordinate for which the plot is performed over the entire coordinate
          range (i.e. for which no specific plot range has been set in
          ``ranges``); similarly ``-max_range`` is the numerical valued
          substituted for ``-Infinity``

        - ``scale`` -- (default: 1) value by which the lengths of the arrows
          representing the vectors is multiplied

        - ``**extra_options`` -- extra options for the arrow plot, like
          ``linestyle``, ``width`` or ``arrowsize`` (see
          :func:`~sage.plot.arrow.arrow2d` and
          :func:`~sage.plot.plot3d.shapes.arrow3d` for details)

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Plot of a vector field on a 2-dimensional manifold::

            sage: M = Manifold(2, 'M')
            sage: X.<x,y> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = -y, x ; v.display()
            v = -y d/dx + x d/dy
            sage: v.plot()
            Graphics object consisting of 80 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot()
            sphinx_plot(g)

        Plot with various options::

            sage: v.plot(scale=0.5, color='green', linestyle='--', width=1,
            ....:        arrowsize=6)
            Graphics object consisting of 80 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(scale=0.5, color='green', linestyle='--', width=1, arrowsize=6)
            sphinx_plot(g)

        ::

            sage: v.plot(max_range=4, number_values=5, scale=0.5)
            Graphics object consisting of 24 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(max_range=4, number_values=5, scale=0.5)
            sphinx_plot(g)

        Plot using parallel computation::

            sage: Parallelism().set(nproc=2)
            sage: v.plot(scale=0.5,  number_values=10, linestyle='--', width=1,
            ....:        arrowsize=6)
            Graphics object consisting of 100 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(scale=0.5,  number_values=10, linestyle='--', width=1, arrowsize=6)
            sphinx_plot(g)

        ::

            sage: Parallelism().set(nproc=1)  # switch off parallelization

        Plots along a line of fixed coordinate::

            sage: v.plot(fixed_coords={x: -2})
            Graphics object consisting of 9 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(fixed_coords={x: -2})
            sphinx_plot(g)

        ::

            sage: v.plot(fixed_coords={y: 1})
            Graphics object consisting of 9 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(fixed_coords={y: 1})
            sphinx_plot(g)

        Let us now consider a vector field on a 4-dimensional manifold::

            sage: M = Manifold(4, 'M')
            sage: X.<t,x,y,z> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = (t/8)^2, -t*y/4, t*x/4, t*z/4 ; v.display()
            v = 1/64*t^2 d/dt - 1/4*t*y d/dx + 1/4*t*x d/dy + 1/4*t*z d/dz

        We cannot make a 4D plot directly::

            sage: v.plot()
            Traceback (most recent call last):
            ...
            ValueError: the number of ambient coordinates must be either 2 or 3, not 4

        Rather, we have to select some coordinates for the plot, via
        the argument ``ambient_coords``. For instance, for a 3D plot::

            sage: v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1},  # long time
            ....:        number_values=4)
            Graphics3d Object

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z') ; t,x,y,z = X[:]
            v = M.vector_field(name='v')
            v[:] = (t/8)**2, -t*y/4, t*x/4, t*z/4
            sphinx_plot(v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1},
                               number_values=4))

        ::

            sage: v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},  # long time
            ....:        ranges={x: (-2,2), y: (-2,2), t: (-1, 4)},
            ....:        number_values=4)
            Graphics3d Object

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            v = M.vector_field(name='v')
            v[:] = (t/8)**2, -t*y/4, t*x/4, t*z/4
            sphinx_plot(v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},
                               ranges={x: (-2,2), y: (-2,2), t: (-1, 4)},
                               number_values=4))

        or, for a 2D plot::

            sage: v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})  # long time
            Graphics object consisting of 80 graphics primitives

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            v = M.vector_field(name='v')
            v[:] = (t/8)**2, -t*y/4, t*x/4, t*z/4
            g = v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})
            sphinx_plot(g)

        ::

            sage: v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})  # long time
            Graphics object consisting of 72 graphics primitives

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            v = M.vector_field(name='v')
            v[:] = v[:] = (t/8)**2, -t*y/4, t*x/4, t*z/4
            g = v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})
            sphinx_plot(g)

        An example of plot via a differential mapping: plot of a vector field
        tangent to a 2-sphere viewed in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U') # the open set covered by spherical coord.
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                       sin(th)*sin(ph), cos(th)]}, name='F')
            sage: F.display() # the standard embedding of S^2 into R^3
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: v = XS.frame()[1] ; v  # the coordinate vector d/dphi
            Vector field d/dph on the Open subset U of the 2-dimensional
             differentiable manifold S^2
            sage: graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
            sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
            sage: graph_v + graph_S2
            Graphics3d Object

        .. PLOT::

            S2 = Manifold(2, 'S^2')
            U = S2.open_subset('U')
            XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            th, ph = XS[:]
            R3 = Manifold(3, 'R^3')
            X3 = R3.chart('x y z')
            F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
                                            cos(th)]}, name='F')
            v = XS.frame()[1]
            graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
            graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
            sphinx_plot(graph_v + graph_S2)

        Note that the default values of some arguments of the method ``plot``
        are stored in the dictionary ``plot.options``::

            sage: v.plot.options  # random (dictionary output)
            {'color': 'blue', 'max_range': 8, 'scale': 1}

        so that they can be adjusted by the user::

            sage: v.plot.options['color'] = 'red'

        From now on, all plots of vector fields will use red as the default
        color. To restore the original default options, it suffices to type::

            sage: v.plot.reset()

        """
        from sage.rings.infinity import Infinity
        from sage.misc.functional import numerical_approx
        from sage.misc.latex import latex
        from sage.plot.graphics import Graphics
        from sage.manifolds.chart import RealChart
        from sage.manifolds.utilities import set_axes_labels
        from sage.parallel.decorate import parallel
        from sage.parallel.parallelism import Parallelism

        #
        # 1/ Treatment of input parameters
        #    -----------------------------
        max_range = extra_options.pop("max_range")
        scale = extra_options.pop("scale")
        color = extra_options.pop("color")
        if chart is None:
            chart = self._domain.default_chart()
        elif not isinstance(chart, RealChart):
            raise TypeError("{} is not a chart on a real ".format(chart) +
                            "manifold")
        if chart_domain is None:
            chart_domain = self._domain.default_chart()
        elif not isinstance(chart_domain, RealChart):
            raise TypeError("{} is not a chart on a ".format(chart_domain) +
                            "real manifold")
        elif not chart_domain.domain().is_subset(self._domain):
            raise ValueError("the domain of {} is not ".format(chart_domain) +
                             "included in the domain of {}".format(self))
        coords_full = tuple(chart_domain[:])  # all coordinates of chart_domain
        if fixed_coords is None:
            coords = coords_full
        else:
            fixed_coord_list = fixed_coords.keys()
            coords = []
            for coord in coords_full:
                if coord not in fixed_coord_list:
                    coords.append(coord)
            coords = tuple(coords)
        if ambient_coords is None:
            ambient_coords = chart[:]
        elif not isinstance(ambient_coords, tuple):
            ambient_coords = tuple(ambient_coords)
        nca = len(ambient_coords)
        if nca != 2 and nca != 3:
            raise ValueError("the number of ambient coordinates must be " +
                             "either 2 or 3, not {}".format(nca))
        if ranges is None:
            ranges = {}
        ranges0 = {}
        for coord in coords:
            if coord in ranges:
                ranges0[coord] = (numerical_approx(ranges[coord][0]),
                                  numerical_approx(ranges[coord][1]))
            else:
                bounds = chart_domain._bounds[coords_full.index(coord)]
                xmin0 = bounds[0][0]
                xmax0 = bounds[1][0]
                if xmin0 == -Infinity:
                    xmin = numerical_approx(-max_range)
                elif bounds[0][1]:
                    xmin = numerical_approx(xmin0)
                else:
                    xmin = numerical_approx(xmin0 + 1.e-3)
                if xmax0 == Infinity:
                    xmax = numerical_approx(max_range)
                elif bounds[1][1]:
                    xmax = numerical_approx(xmax0)
                else:
                    xmax = numerical_approx(xmax0 - 1.e-3)
                ranges0[coord] = (xmin, xmax)
        ranges = ranges0
        if number_values is None:
            if nca == 2:  # 2D plot
                number_values = 9
            else:  # 3D plot
                number_values = 5
        if not isinstance(number_values, dict):
            number_values0 = {}
            for coord in coords:
                number_values0[coord] = number_values
            number_values = number_values0
        if steps is None:
            steps = {}
        for coord in coords:
            if coord not in steps:
                steps[coord] = (ranges[coord][1] - ranges[coord][0])/ \
                               (number_values[coord]-1)
            else:
                number_values[coord] = 1 + int(
                    (ranges[coord][1] - ranges[coord][0]) / steps[coord])
        #
        # 2/ Plots
        #    -----
        dom = chart_domain.domain()
        vector = self.restrict(dom)
        if vector.parent().destination_map() is dom.identity_map():
            if mapping is not None:
                vector = mapping.pushforward(vector)
                mapping = None
        nc = len(coords_full)
        ncp = len(coords)
        xx = [0] * nc
        if fixed_coords is not None:
            if len(fixed_coords) != nc - ncp:
                raise ValueError("bad number of fixed coordinates")
            for fc, val in fixed_coords.items():
                xx[coords_full.index(fc)] = val
        ind_coord = []
        for coord in coords:
            ind_coord.append(coords_full.index(coord))

        resu = Graphics()
        ind = [0] * ncp
        ind_max = [0] * ncp
        ind_max[0] = number_values[coords[0]]
        xmin = [ranges[cd][0] for cd in coords]
        step_tab = [steps[cd] for cd in coords]

        nproc = Parallelism().get('tensor')
        if nproc != 1 and nca == 2:
            # parallel plot construct : Only for 2D plot (at  moment) !

            # creation of the list of parameters
            list_xx = []

            while ind != ind_max:
                for i in range(ncp):
                    xx[ind_coord[i]] = xmin[i] + ind[i] * step_tab[i]

                if chart_domain.valid_coordinates(*xx,
                                                  tolerance=1e-13,
                                                  parameters=parameters):

                    # needed a xx*1 to copy the list by value
                    list_xx.append(xx * 1)

                # Next index:
                ret = 1
                for pos in range(ncp - 1, -1, -1):
                    imax = number_values[coords[pos]] - 1
                    if ind[pos] != imax:
                        ind[pos] += ret
                        ret = 0
                    elif ret == 1:
                        if pos == 0:
                            ind[pos] = imax + 1  # end point reached
                        else:
                            ind[pos] = 0
                            ret = 1

            lol = lambda lst, sz: [
                lst[i:i + sz] for i in range(0, len(lst), sz)
            ]
            ind_step = max(1, int(len(list_xx) / nproc / 2))
            local_list = lol(list_xx, ind_step)

            # definition of the list of input parameters
            listParalInput = [
                (vector, dom, ind_part, chart_domain, chart, ambient_coords,
                 mapping, scale, color, parameters, extra_options)
                for ind_part in local_list
            ]

            # definition of the parallel function
            @parallel(p_iter='multiprocessing', ncpus=nproc)
            def add_point_plot(vector, dom, xx_list, chart_domain, chart,
                               ambient_coords, mapping, scale, color,
                               parameters, extra_options):
                count = 0
                for xx in xx_list:
                    point = dom(xx, chart=chart_domain)
                    part = vector.at(point).plot(chart=chart,
                                                 ambient_coords=ambient_coords,
                                                 mapping=mapping,
                                                 scale=scale,
                                                 color=color,
                                                 print_label=False,
                                                 parameters=parameters,
                                                 **extra_options)
                    if count == 0:
                        local_resu = part
                    else:
                        local_resu += part
                    count += 1
                return local_resu

            # parallel execution and reconstruction of the plot
            for ii, val in add_point_plot(listParalInput):
                resu += val

        else:
            # sequential plot
            while ind != ind_max:
                for i in range(ncp):
                    xx[ind_coord[i]] = xmin[i] + ind[i] * step_tab[i]
                if chart_domain.valid_coordinates(*xx,
                                                  tolerance=1e-13,
                                                  parameters=parameters):
                    point = dom(xx, chart=chart_domain)
                    resu += vector.at(point).plot(
                        chart=chart,
                        ambient_coords=ambient_coords,
                        mapping=mapping,
                        scale=scale,
                        color=color,
                        print_label=False,
                        parameters=parameters,
                        **extra_options)
                # Next index:
                ret = 1
                for pos in range(ncp - 1, -1, -1):
                    imax = number_values[coords[pos]] - 1
                    if ind[pos] != imax:
                        ind[pos] += ret
                        ret = 0
                    elif ret == 1:
                        if pos == 0:
                            ind[pos] = imax + 1  # end point reached
                        else:
                            ind[pos] = 0
                            ret = 1

        if label_axes:
            if nca == 2:  # 2D graphic
                # We update the dictionary _extra_kwds (options to be passed
                # to show()), instead of using the method
                # Graphics.axes_labels() since the latter is not robust w.r.t.
                # graph addition
                resu._extra_kwds['axes_labels'] = [
                    r'$' + latex(ac) + r'$' for ac in ambient_coords
                ]
            else:  # 3D graphic
                labels = [str(ac) for ac in ambient_coords]
                resu = set_axes_labels(resu, *labels)
        return resu
Exemple #15
0
    def plot(self,
             chart=None,
             ambient_coords=None,
             mapping=None,
             color='blue',
             print_label=True,
             label=None,
             label_color=None,
             fontsize=10,
             label_offset=0.1,
             parameters=None,
             **extra_options):
        r"""
        Plot the vector in a Cartesian graph based on the coordinates of some
        ambient chart.

        The vector is drawn in terms of two (2D graphics) or three (3D graphics)
        coordinates of a given chart, called hereafter the *ambient chart*.
        The vector's base point `p` (or its image `\Phi(p)` by some
        differentiable mapping `\Phi`) must lie in the ambient chart's domain.
        If `\Phi` is different from the identity mapping, the vector
        actually depicted is `\mathrm{d}\Phi_p(v)`, where `v` is the current
        vector (``self``) (see the example of a vector tangent to the
        2-sphere below, where `\Phi: S^2 \to \RR^3`).

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above); if
          ``None``, it is set to the default chart of the open set containing
          the point at which the vector (or the vector image via the
          differential `\mathrm{d}\Phi_p` of ``mapping``) is defined

        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2
          or 3 coordinates of the ambient chart in terms of which the plot
          is performed; if ``None``, all the coordinates of the ambient
          chart are considered

        - ``mapping`` -- (default: ``None``)
          :class:`~sage.manifolds.differentiable.diff_map.DiffMap`;
          differentiable mapping `\Phi` providing the link between the
          point `p` at which the vector is defined and the ambient chart
          ``chart``: the domain of ``chart`` must contain `\Phi(p)`;
          if ``None``, the identity mapping is assumed

        - ``scale`` -- (default: 1) value by which the length of the arrow
          representing the vector is multiplied

        - ``color`` -- (default: 'blue') color of the arrow representing the
          vector

        - ``print_label`` -- (boolean; default: ``True``) determines whether a
          label is printed next to the arrow representing the vector

        - ``label`` -- (string; default: ``None``) label printed next to the
          arrow representing the vector; if ``None``, the vector's symbol is
          used, if any

        - ``label_color`` -- (default: ``None``) color to print the label;
          if ``None``, the value of ``color`` is used

        - ``fontsize`` -- (default: 10) size of the font used to print the
          label

        - ``label_offset`` -- (default: 0.1) determines the separation between
          the vector arrow and the label

        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of ``self`` (see example below)

        - ``**extra_options`` -- extra options for the arrow plot, like
          ``linestyle``, ``width`` or ``arrowsize`` (see
          :func:`~sage.plot.arrow.arrow2d` and
          :func:`~sage.plot.plot3d.shapes.arrow3d` for details)

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Vector tangent to a 2-dimensional manifold::

            sage: M = Manifold(2, 'M')
            sage: X.<x,y> = M.chart()
            sage: p = M((2,2), name='p')
            sage: Tp = M.tangent_space(p)
            sage: v = Tp((2, 1), name='v') ; v
            Tangent vector v at Point p on the 2-dimensional differentiable
             manifold M

        Plot of the vector alone (arrow + label)::

            sage: v.plot()
            Graphics object consisting of 2 graphics primitives

        Plot atop of the chart grid::

            sage: X.plot() + v.plot()
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot()
            sphinx_plot(g)

        Plots with various options::

            sage: X.plot() + v.plot(color='green', scale=2, label='V')
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(color='green', scale=2, label='V')
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(print_label=False)
            Graphics object consisting of 19 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(print_label=False)
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(color='green', label_color='black',
            ....:                   fontsize=20, label_offset=0.2)
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(color='green', label_color='black', fontsize=20, label_offset=0.2)
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(linestyle=':', width=4, arrowsize=8,
            ....:                   fontsize=20)
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(linestyle=':', width=4, arrowsize=8, fontsize=20)
            sphinx_plot(g)

        Plot with specific values of some free parameters::

            sage: var('a b')
            (a, b)
            sage: v = Tp((1+a, -b^2), name='v') ; v.display()
            v = (a + 1) d/dx - b^2 d/dy
            sage: X.plot() + v.plot(parameters={a: -2, b: 3})
            Graphics object consisting of 20 graphics primitives

        Special case of the zero vector::

            sage: v = Tp.zero() ; v
            Tangent vector zero at Point p on the 2-dimensional differentiable
             manifold M
            sage: X.plot() + v.plot()
            Graphics object consisting of 19 graphics primitives

        Vector tangent to a 4-dimensional manifold::

            sage: M = Manifold(4, 'M')
            sage: X.<t,x,y,z> = M.chart()
            sage: p = M((0,1,2,3), name='p')
            sage: Tp = M.tangent_space(p)
            sage: v = Tp((5,4,3,2), name='v') ; v
            Tangent vector v at Point p on the 4-dimensional differentiable
             manifold M

        We cannot make a 4D plot directly::

            sage: v.plot()
            Traceback (most recent call last):
            ...
            ValueError: the number of coordinates involved in the plot must
             be either 2 or 3, not 4

        Rather, we have to select some chart coordinates for the plot, via
        the argument ``ambient_coords``. For instance, for a 2-dimensional
        plot in terms of the coordinates `(x, y)`::

            sage: v.plot(ambient_coords=(x,y))
            Graphics object consisting of 2 graphics primitives

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p)
            v = Tp((5,4,3,2), name='v')
            g = X.plot(ambient_coords=(x,y)) + v.plot(ambient_coords=(x,y))
            sphinx_plot(g)

        This plot involves only the components `v^x` and `v^y` of `v`.
        Similarly, for a 3-dimensional plot in terms of the coordinates
        `(t, x, y)`::

            sage: g = v.plot(ambient_coords=(t,x,z))
            sage: print(g)
            Graphics3d Object

        This plot involves only the components `v^t`,  `v^x` and `v^z` of `v`.
        A nice 3D view atop the coordinate grid is obtained via::

            sage: (X.plot(ambient_coords=(t,x,z))  # long time
            ....:  + v.plot(ambient_coords=(t,x,z),
            ....:           label_offset=0.5, width=6))
            Graphics3d Object

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p)
            v = Tp((5,4,3,2), name='v')
            g = X.plot(ambient_coords=(t,x,z)) + v.plot(ambient_coords=(t,x,z),
                       label_offset=0.5, width=6)
            sphinx_plot(g)

        An example of plot via a differential mapping: plot of a vector tangent
        to a 2-sphere viewed in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U') # the open set covered by spherical coord.
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                                 sin(th)*sin(ph),
            ....:                                 cos(th)]}, name='F')
            sage: F.display() # the standard embedding of S^2 into R^3
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: p = U.point((pi/4, 7*pi/4), name='p')
            sage: v = XS.frame()[1].at(p) ; v  # the coordinate vector d/dphi at p
            Tangent vector d/dph at Point p on the 2-dimensional differentiable
             manifold S^2
            sage: graph_v = v.plot(mapping=F)
            sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)  # long time
            sage: graph_v + graph_S2  # long time
            Graphics3d Object

        .. PLOT::

            S2 = Manifold(2, 'S^2')
            U = S2.open_subset('U')
            XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            th, ph = XS[:]
            R3 = Manifold(3, 'R^3')
            X3 = R3.chart('x y z')
            F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
                                            cos(th)]}, name='F')
            p = U.point((pi/4, 7*pi/4), name='p')
            v = XS.frame()[1].at(p)
            graph_v = v.plot(mapping=F)
            graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
            sphinx_plot(graph_v + graph_S2)

        """
        from sage.plot.arrow import arrow2d
        from sage.plot.text import text
        from sage.plot.graphics import Graphics
        from sage.plot.plot3d.shapes import arrow3d
        from sage.plot.plot3d.shapes2 import text3d
        from sage.misc.functional import numerical_approx
        from sage.manifolds.differentiable.chart import DiffChart

        scale = extra_options.pop("scale")

        #
        # The "effective" vector to be plotted
        #
        if mapping is None:
            eff_vector = self
            base_point = self._point
        else:
            #!# check
            # For efficiency, the method FiniteRankFreeModuleMorphism._call_()
            # is called instead of FiniteRankFreeModuleMorphism.__call__()
            eff_vector = mapping.differential(self._point)._call_(self)
            base_point = mapping(self._point)
        #
        # The chart w.r.t. which the vector is plotted
        #
        if chart is None:
            chart = base_point.parent().default_chart()
        elif not isinstance(chart, DiffChart):
            raise TypeError("{} is not a chart".format(chart))
        #
        # Coordinates of the above chart w.r.t. which the vector is plotted
        #
        if ambient_coords is None:
            ambient_coords = chart[:]  # all chart coordinates are used
        n_pc = len(ambient_coords)
        if n_pc != 2 and n_pc != 3:
            raise ValueError("the number of coordinates involved in the " +
                             "plot must be either 2 or 3, not {}".format(n_pc))
        # indices coordinates involved in the plot:
        ind_pc = [chart[:].index(pc) for pc in ambient_coords]
        #
        # Components of the vector w.r.t. the chart frame
        #
        basis = chart.frame().at(base_point)
        vcomp = eff_vector.comp(basis=basis)[:]
        xp = base_point.coord(chart=chart)
        #
        # The arrow
        #
        resu = Graphics()
        if parameters is None:
            coord_tail = [numerical_approx(xp[i]) for i in ind_pc]
            coord_head = [
                numerical_approx(xp[i] + scale * vcomp[i]) for i in ind_pc
            ]
        else:
            coord_tail = [
                numerical_approx(xp[i].substitute(parameters)) for i in ind_pc
            ]
            coord_head = [
                numerical_approx(
                    (xp[i] + scale * vcomp[i]).substitute(parameters))
                for i in ind_pc
            ]
        if coord_head != coord_tail:
            if n_pc == 2:
                resu += arrow2d(tailpoint=coord_tail,
                                headpoint=coord_head,
                                color=color,
                                **extra_options)
            else:
                resu += arrow3d(coord_tail,
                                coord_head,
                                color=color,
                                **extra_options)
        #
        # The label
        #
        if print_label:
            if label is None:
                if n_pc == 2 and self._latex_name is not None:
                    label = r'$' + self._latex_name + r'$'
                if n_pc == 3 and self._name is not None:
                    label = self._name
            if label is not None:
                xlab = [xh + label_offset for xh in coord_head]
                if label_color is None:
                    label_color = color
                if n_pc == 2:
                    resu += text(label,
                                 xlab,
                                 fontsize=fontsize,
                                 color=label_color)
                else:
                    resu += text3d(label,
                                   xlab,
                                   fontsize=fontsize,
                                   color=label_color)
        return resu
Exemple #16
0
def compute_percolation_probability(range_p, d, n, stop):
    r"""
    EXAMPLES::

        sage: from slabbe.bond_percolation import compute_percolation_probability
        sage: compute_percolation_probability(srange(0,0.8,0.1), d=2, n=5, stop=100) # random
        d = 2, n = number of samples = 5
        stop counting at = 100
        p=0.0000, Theta=0.000, if |C|< 100 then max|C|=1
        p=0.1000, Theta=0.000, if |C|< 100 then max|C|=1
        p=0.2000, Theta=0.000, if |C|< 100 then max|C|=5
        p=0.3000, Theta=0.000, if |C|< 100 then max|C|=6
        p=0.4000, Theta=0.000, if |C|< 100 then max|C|=31
        p=0.5000, Theta=1.00, if |C|< 100 then max|C|=-Infinity
        p=0.6000, Theta=1.00, if |C|< 100 then max|C|=-Infinity
        p=0.7000, Theta=1.00, if |C|< 100 then max|C|=-Infinity

    ::

        sage: range_p = srange(0,0.8,0.1)
        sage: compute_percolation_probability(range_p, d=2, n=5, stop=100) # not tested
        d = 2, n = number of samples = 5
        stop counting at = 100
        p=0.0000, Theta=0.000, if |C|< 100 then max|C|=1
        p=0.1000, Theta=0.000, if |C|< 100 then max|C|=1
        p=0.2000, Theta=0.000, if |C|< 100 then max|C|=5
        p=0.3000, Theta=0.000, if |C|< 100 then max|C|=6
        p=0.4000, Theta=0.000, if |C|< 100 then max|C|=31
        p=0.5000, Theta=1.00, if |C|< 100 then max|C|=-Infinity
        p=0.6000, Theta=1.00, if |C|< 100 then max|C|=-Infinity
        p=0.7000, Theta=1.00, if |C|< 100 then max|C|=-Infinity

    ::

        sage: range_p = srange(0.45,0.55,0.01)
        sage: compute_percolation_probability(range_p, d=2, n=10, stop=1000) # not tested
        d = 2, n = number of samples = 10
        stop counting at = 1000
        p=0.4500, Theta=0.000, if |C|< 1000 then max|C|=378
        p=0.4600, Theta=0.000, if |C|< 1000 then max|C|=475
        p=0.4700, Theta=0.000, if |C|< 1000 then max|C|=514
        p=0.4800, Theta=0.100, if |C|< 1000 then max|C|=655
        p=0.4900, Theta=0.700, if |C|< 1000 then max|C|=274
        p=0.5000, Theta=0.700, if |C|< 1000 then max|C|=975
        p=0.5100, Theta=0.700, if |C|< 1000 then max|C|=16
        p=0.5200, Theta=0.700, if |C|< 1000 then max|C|=125
        p=0.5300, Theta=0.900, if |C|< 1000 then max|C|=4
        p=0.5400, Theta=0.700, if |C|< 1000 then max|C|=6

    ::

        sage: range_p = srange(0.475,0.485,0.001)
        sage: compute_percolation_probability(range_p, d=2, n=10, stop=1000) # not tested
        d = 2, n = number of samples = 10
        stop counting at = 1000
        p=0.4750, Theta=0.200, if |C|< 1000 then max|C|=718
        p=0.4760, Theta=0.200, if |C|< 1000 then max|C|=844
        p=0.4770, Theta=0.200, if |C|< 1000 then max|C|=566
        p=0.4780, Theta=0.500, if |C|< 1000 then max|C|=257
        p=0.4790, Theta=0.200, if |C|< 1000 then max|C|=566
        p=0.4800, Theta=0.300, if |C|< 1000 then max|C|=544
        p=0.4810, Theta=0.300, if |C|< 1000 then max|C|=778
        p=0.4820, Theta=0.500, if |C|< 1000 then max|C|=983
        p=0.4830, Theta=0.300, if |C|< 1000 then max|C|=473
        p=0.4840, Theta=0.500, if |C|< 1000 then max|C|=411

    ::

        sage: range_p = srange(0.47,0.48,0.001)
        sage: compute_percolation_probability(range_p, d=2, n=20, stop=2000)  # not tested
        d = 2, n = number of samples = 20
        stop counting at = 2000
        p=0.4700, Theta=0.0500, if |C|< 2000 then max|C|=1666
        p=0.4710, Theta=0.100, if |C|< 2000 then max|C|=1665
        p=0.4720, Theta=0.000, if |C|< 2000 then max|C|=1798
        p=0.4730, Theta=0.0500, if |C|< 2000 then max|C|=1717
        p=0.4740, Theta=0.150, if |C|< 2000 then max|C|=1924
        p=0.4750, Theta=0.150, if |C|< 2000 then max|C|=1893
        p=0.4760, Theta=0.150, if |C|< 2000 then max|C|=1458
        p=0.4770, Theta=0.150, if |C|< 2000 then max|C|=1573
        p=0.4780, Theta=0.200, if |C|< 2000 then max|C|=1762
        p=0.4790, Theta=0.250, if |C|< 2000 then max|C|=951
    """
    print("d = %s, n = number of samples = %s" % (d, n))
    print("stop counting at = %s" % stop)
    for p in range_p:
        p = numerical_approx(p, digits=4)
        S = BondPercolationSamples(p,d,n)
        L = [a for a in S.cluster_cardinality(stop) if not isinstance(a, str)]
        Y = max(L) if L else -Infinity
        theta = S.percolation_probability(stop)
        print("p=%s, Theta=%s, if |C|< %s then max|C|=%s" % (p, theta, stop, Y))
def lyap_exp_CY(beta1, beta2, nb_vectors=None, nb_experiments=10, nb_iterations=10**4, verbose=False, output_file=None, return_error=False):
        r"""
        Compute the Lyapunov exponents of the geodesic flow in the hypergeometric function
        space.

        The input parameters yield the eigenvalues around infinity,
        $e^{2i\pi\beta_1}, e^{2i\pi\beta_2}, e^{-2i\pi\beta_1}, e^{-2i\pi\beta_1}$.
        We compute the coefficient of the characteristic polynomial of such a matrix.
        And call the C function which associate to these coefficient the companion matrices
        of the polynomial. We use Levelt theorem for computing monodromy matrices.
        See Theorem 3.2.3 in [Beu].

        INPUT:

        - ``beta1``, ``beta2`` -- parameters of the eigenvalues

        - ``nb_vectors`` -- the number of vectors to use

        - ``nb_experiments`` -- number of experimets

        - ``nb_iterations`` -- the number of iterations of the induction to perform

        - ``output_file`` -- place where we print the results

        - ``verbose`` -- do we print the result with an extensive number of information or not

        OUTPUT:

        A list of nb_vectors lyapunov exponents by default.

        If return_error is True, a 4-tuple consisting of :

        1. a list of nb_vectors lyapunov exponents
        2. a list of nb_vectors of their statistical error
        3. an integer of their sum
        4. an integer of the statistical error of their sum
        """
        from sage.all import exp
        from sage.misc.functional import numerical_approx

        import time
        import lyapunov_exponents    # the cython bindings
        from math import sqrt

        if output_file is None:
            from sys import stdout
            output_file = stdout
            closed = True
        elif isinstance(output_file, str):
            output_file = open(output_file, "w")
            closed = False

        beta1 = numerical_approx(beta1)
        beta2 = numerical_approx(beta2)
        b1 = numerical_approx(exp(2*1j*pi*beta1))
        b2 = numerical_approx(exp(2*1j*pi*beta2))
        a = (b1**2*b2 + b1*b2**2 + b1 + b2)/(b1*b2)
        b = (-b1**2*b2**2 - b1**2 - 2*b1*b2 - b2**2 - 1)/(b1*b2)

        if nb_vectors <> None and nb_vectors <= 0:
            raise ValueError("the number of vectors must be positive")
        if nb_experiments <= 0:
            raise ValueError("the number of experiments must be positive")
        if nb_iterations <= 0:
            raise ValueError("the number of iterations must be positive")

        #recall that the lyapunov exponents are symmetric
        if nb_vectors == None:
            nb_vectors = 2

        t0 = time.time()
        res = lyapunov_exponents.lyapunov_exponents([0]*4, [0]*4, 4, nb_vectors, nb_experiments, nb_iterations, [a, b])
        t1 = time.time()

        res_final = []
        std_final = []
        s_m, s_d = 0, 0

        if verbose:
            from math import floor, log
            output_file.write("sample of %d experiments\n"%nb_experiments)
            output_file.write("%d iterations (~2**%d)\n"%(nb_iterations, floor(log(nb_iterations) / log(2))))
            output_file.write("ellapsed time %s\n"%time.strftime("%H:%M:%S",time.gmtime(t1-t0)))
        for i in xrange(nb_vectors):
            m,d = mean_and_std_dev(res[i])
            s_m += m
            s_d += d**2
            if verbose:
                output_file.write("theta%d           : %f (std. dev. = %f, conf. rad. 0.01 = %f)\n"%(
                    i,m,d, 2.576*d/sqrt(nb_experiments)))
            res_final.append(m)
            std_final.append(2.576*d/sqrt(nb_experiments))

        s_d = sqrt(s_d)
        s_d_final = 2.576*s_d/sqrt(nb_experiments)
        if verbose:
            output_file.write("sum_theta        : %f (std. dev. = %f, conf. rad. 0.01 = %f)\n\n"%(
                s_m,s_d, 2.576*s_d/sqrt(nb_experiments)))

        if not closed :
            output_file.close()
            print "file closed"

        if return_error:
            return (res_final, std_final, s_m, s_d_final)
        else:
            return res_final
Exemple #18
0
    def plot(self, chart=None, ambient_coords=None, mapping=None,
             chart_domain=None, fixed_coords=None, ranges=None, max_value=8,
             nb_values=None, steps=None,scale=1, color='blue', parameters=None,
             label_axes=True, **extra_options):
        r"""
        Plot the vector field in a Cartesian graph based on the coordinates
        of some ambient chart.

        The vector field is drawn in terms of two (2D graphics) or three
        (3D graphics) coordinates of a given chart, called hereafter the
        *ambient chart*.
        The vector field's base points `p` (or their images `\Phi(p)` by some
        differentiable mapping `\Phi`) must lie in the ambient chart's domain.

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above); if
          ``None``, the default chart of the vector field's domain is used
        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3
          coordinates of the ambient chart in terms of which the plot is
          performed; if ``None``, all the coordinates of the ambient chart are
          considered
        - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi`
          (instance of
          :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`)
          providing the link between the vector field's domain and
          the ambient chart ``chart``; if ``None``, the identity mapping is
          assumed
        - ``chart_domain`` -- (default: ``None``) chart on the vector
          field's domain to define the points at which vector arrows are to be
          plotted; if ``None``, the default chart of the vector field's domain
          is used
        - ``fixed_coords`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` that are kept fixed and with values
          the value of these coordinates; if ``None``, all the coordinates of
          ``chart_domain`` are used
        - ``ranges`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` to be used and values
          tuples ``(x_min,x_max)`` specifying the
          coordinate range for the plot; if ``None``, the entire coordinate
          range declared during the construction of ``chart_domain`` is
          considered (with ``-Infinity`` replaced by ``-max_value`` and
          ``+Infinity`` by ``max_value``)
        - ``max_value`` -- (default: 8) numerical value substituted to
          ``+Infinity`` if the latter is the upper bound of the range of a
          coordinate for which the plot is performed over the entire coordinate
          range (i.e. for which no specific plot range has been set in
          ``ranges``); similarly ``-max_value`` is the numerical valued
          substituted for ``-Infinity``
        - ``nb_values`` -- (default: ``None``) either an integer or a dictionary
          with keys the coordinates of ``chart_domain`` to be used and values
          the number of values of the coordinate for sampling
          the part of the vector field's domain involved in the plot ; if
          ``nb_values`` is a single integer, it represents the number of
          values for all coordinates; if ``nb_values`` is ``None``, it is set
          to 9 for a 2D plot and to 5 for a 3D plot
        - ``steps`` -- (default: ``None``) dictionary with keys the coordinates
          of ``chart_domain`` to be used and values the step between each
          constant value of the coordinate; if ``None``, the step is computed
          from the coordinate range (specified in ``ranges``) and ``nb_values``.
          On the contrary, if the step is provided for some coordinate, the
          corresponding number of values is deduced from it and the coordinate
          range.
        - ``scale`` -- (default: 1) value by which the lengths of the arrows
          representing the vectors is multiplied
        - ``color`` -- (default: 'blue') color of the arrows representing the
          vectors
        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of the vector field (see example below)
        - ``label_axes`` -- (default: ``True``) boolean determining whether the
          labels of the coordinate axes of ``chart`` shall be added to the
          graph; can be set to ``False`` if the graph is 3D and must be
          superposed with another graph.
        - ``**extra_options`` -- extra options for the arrow plot, like
          ``linestyle``, ``width`` or ``arrowsize`` (see
          :func:`~sage.plot.arrow.arrow2d` and
          :func:`~sage.plot.plot3d.shapes.arrow3d` for details)

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Plot of a vector field on a 2-dimensional manifold::

            sage: Manifold._clear_cache_() # for doctests only
            sage: M = Manifold(2, 'M')
            sage: X.<x,y> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = -y, x ; v.display()
            v = -y d/dx + x d/dy
            sage: v.plot()
            Graphics object consisting of 80 graphics primitives

        Plot with various options::

            sage: v.plot(scale=0.5, color='green', linestyle='--', width=1, arrowsize=6)
            Graphics object consisting of 80 graphics primitives
            sage: v.plot(max_value=4, nb_values=5, scale=0.5)
            Graphics object consisting of 24 graphics primitives

        Plots along a line of fixed coordinate::

            sage: v.plot(fixed_coords={x: -2})
            Graphics object consisting of 9 graphics primitives
            sage: v.plot(fixed_coords={y: 1})
            Graphics object consisting of 9 graphics primitives

        Let us now consider a vector field on a 4-dimensional manifold::

            sage: Manifold._clear_cache_() # for doctests only
            sage: M = Manifold(4, 'M')
            sage: X.<t,x,y,z> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = (t/8)^2, -t*y/4, t*x/4, t*z/4 ; v.display()
            v = 1/64*t^2 d/dt - 1/4*t*y d/dx + 1/4*t*x d/dy + 1/4*t*z d/dz

        We cannot make a 4D plot directly::

            sage: v.plot()
            Traceback (most recent call last):
            ...
            ValueError: the number of ambient coordinates must be either 2 or 3, not 4

        Rather, we have to select some coordinates for the plot, via
        the argument ``ambient_coords``. For instance, for a 3D plot::

            sage: v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1})
            Graphics3d Object
            sage: v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},
            ....:        ranges={x: (-2,2), y: (-2,2), t: (-1, 4)}, nb_values=4)
            Graphics3d Object

        or, for a 2D plot::

            sage: v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})
            Graphics object consisting of 80 graphics primitives
            sage: v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})
            Graphics object consisting of 72 graphics primitives

        An example of plot via a differential mapping: plot of a vector field
        tangent to a 2-sphere viewed in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U') # the open set covered by spherical coord.
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_mapping(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                     sin(th)*sin(ph), cos(th)]}, name='F')
            sage: F.display() # the standard embedding of S^2 into R^3
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: v = XS.frame()[1] ; v
            vector field 'd/dph' on the open subset 'U' of the 2-dimensional manifold 'S^2'
            sage: graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
            sage: graph_S2 = XS.plot(chart=X3, mapping=F, nb_values=9)
            sage: show(graph_v + graph_S2)

        """
        from sage.rings.infinity import Infinity
        from sage.misc.functional import numerical_approx
        from sage.misc.latex import latex
        from sage.plot.graphics import Graphics
        from sage.geometry.manifolds.chart import Chart
        from sage.geometry.manifolds.utilities import set_axes_labels
        #
        # 1/ Treatment of input parameters
        #    -----------------------------
        if chart is None:
            chart = self._domain.default_chart()
        elif not isinstance(chart, Chart):
            raise TypeError("{} is not a chart".format(chart))
        if chart_domain is None:
            chart_domain = self._domain.default_chart()
        elif not isinstance(chart_domain, Chart):
            raise TypeError("{} is not a chart".format(chart_domain))
        elif not chart_domain.domain().is_subset(self._domain):
            raise ValueError("The domain of {} is not ".format(chart_domain) +
                             "included in the domain of {}".format(self))
        if fixed_coords is None:
            coords = chart_domain._xx
        else:
            fixed_coord_list = fixed_coords.keys()
            coords = []
            for coord in chart_domain._xx:
                if coord not in fixed_coord_list:
                    coords.append(coord)
            coords = tuple(coords)
        if ambient_coords is None:
            ambient_coords = chart[:]
        elif not isinstance(ambient_coords, tuple):
            ambient_coords = tuple(ambient_coords)
        nca = len(ambient_coords)
        if nca != 2 and nca !=3:
            raise ValueError("the number of ambient coordinates must be " +
                             "either 2 or 3, not {}".format(nca))
        if ranges is None:
            ranges = {}
        ranges0 = {}
        for coord in coords:
            if coord in ranges:
                ranges0[coord] = (numerical_approx(ranges[coord][0]),
                                  numerical_approx(ranges[coord][1]))
            else:
                bounds = chart_domain._bounds[chart_domain[:].index(coord)]
                if bounds[0][0] == -Infinity:
                    xmin = numerical_approx(-max_value)
                elif bounds[0][1]:
                    xmin = numerical_approx(bounds[0][0])
                else:
                    xmin = numerical_approx(bounds[0][0] + 1.e-3)
                if bounds[1][0] == Infinity:
                    xmax = numerical_approx(max_value)
                elif bounds[1][1]:
                    xmax = numerical_approx(bounds[1][0])
                else:
                    xmax = numerical_approx(bounds[1][0] - 1.e-3)
                ranges0[coord] = (xmin, xmax)
        ranges = ranges0
        if nb_values is None:
            if nca == 2: # 2D plot
                nb_values = 9
            else:   # 3D plot
                nb_values = 5
        if not isinstance(nb_values, dict):
            nb_values0 = {}
            for coord in coords:
                nb_values0[coord] = nb_values
            nb_values = nb_values0
        if steps is None:
            steps = {}
        for coord in coords:
            if coord not in steps:
                steps[coord] = (ranges[coord][1] - ranges[coord][0])/ \
                               (nb_values[coord]-1)
            else:
                nb_values[coord] = 1 + int(
                           (ranges[coord][1] - ranges[coord][0])/ steps[coord])
        #
        # 2/ Plots
        #    -----
        dom = chart_domain.domain()
        nc = len(chart_domain[:])
        ncp = len(coords)
        xx = [0] * nc
        if fixed_coords is not None:
            if len(fixed_coords) != nc - ncp:
                raise ValueError("Bad number of fixed coordinates.")
            for fc, val in fixed_coords.iteritems():
                xx[chart_domain[:].index(fc)] = val
        index_p = [chart_domain[:].index(cd) for cd in coords]
        resu = Graphics()
        ind = [0] * ncp
        ind_max = [0] * ncp
        ind_max[0] = nb_values[coords[0]]
        xmin = [ranges[cd][0] for cd in coords]
        step_tab = [steps[cd] for cd in coords]
        while ind != ind_max:
            for i in range(ncp):
                xx[index_p[i]] = xmin[i] + ind[i]*step_tab[i]
            if chart_domain.valid_coordinates(*xx, tolerance=1e-13,
                                              parameters=parameters):
                point = dom(xx, chart=chart_domain)
                resu += self.at(point).plot(chart=chart,
                                 ambient_coords=ambient_coords, mapping=mapping,
                                 scale=scale, color=color, print_label=False,
                                 parameters=parameters,
                                 **extra_options)
            # Next index:
            ret = 1
            for pos in range(ncp-1,-1,-1):
                imax = nb_values[coords[pos]] - 1
                if ind[pos] != imax:
                    ind[pos] += ret
                    ret = 0
                elif ret == 1:
                    if pos == 0:
                        ind[pos] = imax + 1 # end point reached
                    else:
                        ind[pos] = 0
                        ret = 1
        if label_axes:
            if nca==2:  # 2D graphic
                # We update the dictionary _extra_kwds (options to be passed
                # to show()), instead of using the method
                # Graphics.axes_labels() since the latter is not robust w.r.t.
                # graph addition
                resu._extra_kwds['axes_labels'] = [r'$'+latex(ac)+r'$'
                                                   for ac in ambient_coords]
            else: # 3D graphic
                labels = [str(ac) for ac in ambient_coords]
                resu = set_axes_labels(resu, *labels)
        return resu
Exemple #19
0
    def plot(self, chart=None, ambient_coords=None, mapping=None,
             chart_domain=None, fixed_coords=None, ranges=None,
             number_values=None, steps=None,
             parameters=None, label_axes=True, **extra_options):
        r"""
        Plot the vector field in a Cartesian graph based on the coordinates
        of some ambient chart.

        The vector field is drawn in terms of two (2D graphics) or three
        (3D graphics) coordinates of a given chart, called hereafter the
        *ambient chart*.
        The vector field's base points `p` (or their images `\Phi(p)` by some
        differentiable mapping `\Phi`) must lie in the ambient chart's domain.

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above); if
          ``None``, the default chart of the vector field's domain is used

        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2
          or 3 coordinates of the ambient chart in terms of which the plot
          is performed; if ``None``, all the coordinates of the ambient
          chart are considered

        - ``mapping`` -- :class:`~sage.manifolds.differentiable.diff_map.DiffMap`
          (default: ``None``); differentiable map `\Phi` providing the link
          between the vector field's domain and the ambient chart ``chart``;
          if ``None``, the identity map is assumed

        - ``chart_domain`` -- (default: ``None``) chart on the vector field's
          domain to define the points at which vector arrows are to be plotted;
          if ``None``, the default chart of the vector field's domain is used

        - ``fixed_coords`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` that are kept fixed and with values
          the value of these coordinates; if ``None``, all the coordinates of
          ``chart_domain`` are used

        - ``ranges`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` to be used and values tuples
          ``(x_min, x_max)`` specifying the coordinate range for the plot;
          if ``None``, the entire coordinate range declared during the
          construction of ``chart_domain`` is considered (with ``-Infinity``
          replaced by ``-max_range`` and ``+Infinity`` by ``max_range``)

        - ``number_values`` -- (default: ``None``) either an integer or a
          dictionary with keys the coordinates of ``chart_domain`` to be
          used and values the number of values of the coordinate for sampling
          the part of the vector field's domain involved in the plot ; if
          ``number_values`` is a single integer, it represents the number of
          values for all coordinates; if ``number_values`` is ``None``, it is
          set to 9 for a 2D plot and to 5 for a 3D plot

        - ``steps`` -- (default: ``None``) dictionary with keys the
          coordinates of ``chart_domain`` to be used and values the step
          between each constant value of the coordinate; if ``None``, the
          step is computed from the coordinate range (specified in ``ranges``)
          and ``number_values``; on the contrary, if the step is provided
          for some coordinate, the corresponding number of values is deduced
          from it and the coordinate range

        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of the vector field (see example below)

        - ``label_axes`` -- (default: ``True``) boolean determining whether
          the labels of the coordinate axes of ``chart`` shall be added to
          the graph; can be set to ``False`` if the graph is 3D and must be
          superposed with another graph

        - ``color`` -- (default: 'blue') color of the arrows representing
          the vectors

        - ``max_range`` -- (default: 8) numerical value substituted to
          ``+Infinity`` if the latter is the upper bound of the range of a
          coordinate for which the plot is performed over the entire coordinate
          range (i.e. for which no specific plot range has been set in
          ``ranges``); similarly ``-max_range`` is the numerical valued
          substituted for ``-Infinity``

        - ``scale`` -- (default: 1) value by which the lengths of the arrows
          representing the vectors is multiplied

        - ``**extra_options`` -- extra options for the arrow plot, like
          ``linestyle``, ``width`` or ``arrowsize`` (see
          :func:`~sage.plot.arrow.arrow2d` and
          :func:`~sage.plot.plot3d.shapes.arrow3d` for details)

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Plot of a vector field on a 2-dimensional manifold::

            sage: M = Manifold(2, 'M')
            sage: X.<x,y> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = -y, x ; v.display()
            v = -y d/dx + x d/dy
            sage: v.plot()
            Graphics object consisting of 80 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot()
            sphinx_plot(g)

        Plot with various options::

            sage: v.plot(scale=0.5, color='green', linestyle='--', width=1,
            ....:        arrowsize=6)
            Graphics object consisting of 80 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(scale=0.5, color='green', linestyle='--', width=1, arrowsize=6)
            sphinx_plot(g)

        ::

            sage: v.plot(max_range=4, number_values=5, scale=0.5)
            Graphics object consisting of 24 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(max_range=4, number_values=5, scale=0.5)
            sphinx_plot(g)

        Plot using parallel computation::

            sage: Parallelism().set(nproc=2)
            sage: v.plot(scale=0.5,  number_values=10, linestyle='--', width=1,
            ....:        arrowsize=6)
            Graphics object consisting of 100 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(scale=0.5,  number_values=10, linestyle='--', width=1, arrowsize=6)
            sphinx_plot(g)

        ::

            sage: Parallelism().set(nproc=1)  # switch off parallelization

        Plots along a line of fixed coordinate::

            sage: v.plot(fixed_coords={x: -2})
            Graphics object consisting of 9 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(fixed_coords={x: -2})
            sphinx_plot(g)

        ::

            sage: v.plot(fixed_coords={y: 1})
            Graphics object consisting of 9 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            v = M.vector_field(name='v'); v[:] = -y, x
            g = v.plot(fixed_coords={y: 1})
            sphinx_plot(g)

        Let us now consider a vector field on a 4-dimensional manifold::

            sage: M = Manifold(4, 'M')
            sage: X.<t,x,y,z> = M.chart()
            sage: v = M.vector_field(name='v')
            sage: v[:] = (t/8)^2, -t*y/4, t*x/4, t*z/4 ; v.display()
            v = 1/64*t^2 d/dt - 1/4*t*y d/dx + 1/4*t*x d/dy + 1/4*t*z d/dz

        We cannot make a 4D plot directly::

            sage: v.plot()
            Traceback (most recent call last):
            ...
            ValueError: the number of ambient coordinates must be either 2 or 3, not 4

        Rather, we have to select some coordinates for the plot, via
        the argument ``ambient_coords``. For instance, for a 3D plot::

            sage: v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1},  # long time
            ....:        number_values=4)
            Graphics3d Object

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z') ; t,x,y,z = X[:]
            v = M.vector_field(name='v')
            v[:] = (t/8)**2, -t*y/4, t*x/4, t*z/4
            sphinx_plot(v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1},
                               number_values=4))

        ::

            sage: v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},  # long time
            ....:        ranges={x: (-2,2), y: (-2,2), t: (-1, 4)},
            ....:        number_values=4)
            Graphics3d Object

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            v = M.vector_field(name='v')
            v[:] = (t/8)**2, -t*y/4, t*x/4, t*z/4
            sphinx_plot(v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},
                               ranges={x: (-2,2), y: (-2,2), t: (-1, 4)},
                               number_values=4))

        or, for a 2D plot::

            sage: v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})  # long time
            Graphics object consisting of 80 graphics primitives

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            v = M.vector_field(name='v')
            v[:] = (t/8)**2, -t*y/4, t*x/4, t*z/4
            g = v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})
            sphinx_plot(g)

        ::

            sage: v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})  # long time
            Graphics object consisting of 72 graphics primitives

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            v = M.vector_field(name='v')
            v[:] = v[:] = (t/8)**2, -t*y/4, t*x/4, t*z/4
            g = v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})
            sphinx_plot(g)

        An example of plot via a differential mapping: plot of a vector field
        tangent to a 2-sphere viewed in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U') # the open set covered by spherical coord.
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                       sin(th)*sin(ph), cos(th)]}, name='F')
            sage: F.display() # the standard embedding of S^2 into R^3
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: v = XS.frame()[1] ; v  # the coordinate vector d/dphi
            Vector field d/dph on the Open subset U of the 2-dimensional
             differentiable manifold S^2
            sage: graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
            sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
            sage: graph_v + graph_S2
            Graphics3d Object

        .. PLOT::

            S2 = Manifold(2, 'S^2')
            U = S2.open_subset('U')
            XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            th, ph = XS[:]
            R3 = Manifold(3, 'R^3')
            X3 = R3.chart('x y z')
            F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
                                            cos(th)]}, name='F')
            v = XS.frame()[1]
            graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
            graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
            sphinx_plot(graph_v + graph_S2)

        Note that the default values of some arguments of the method ``plot``
        are stored in the dictionary ``plot.options``::

            sage: v.plot.options  # random (dictionary output)
            {'color': 'blue', 'max_range': 8, 'scale': 1}

        so that they can be adjusted by the user::

            sage: v.plot.options['color'] = 'red'

        From now on, all plots of vector fields will use red as the default
        color. To restore the original default options, it suffices to type::

            sage: v.plot.reset()

        """
        from sage.rings.infinity import Infinity
        from sage.misc.functional import numerical_approx
        from sage.misc.latex import latex
        from sage.plot.graphics import Graphics
        from sage.manifolds.chart import RealChart
        from sage.manifolds.utilities import set_axes_labels
        from sage.parallel.decorate import parallel
        from sage.parallel.parallelism import Parallelism

        #
        # 1/ Treatment of input parameters
        #    -----------------------------
        max_range = extra_options.pop("max_range")
        scale = extra_options.pop("scale")
        color = extra_options.pop("color")
        if chart is None:
            chart = self._domain.default_chart()
        elif not isinstance(chart, RealChart):
            raise TypeError("{} is not a chart on a real ".format(chart) +
                            "manifold")
        if chart_domain is None:
            chart_domain = self._domain.default_chart()
        elif not isinstance(chart_domain, RealChart):
            raise TypeError("{} is not a chart on a ".format(chart_domain) +
                            "real manifold")
        elif not chart_domain.domain().is_subset(self._domain):
            raise ValueError("the domain of {} is not ".format(chart_domain) +
                             "included in the domain of {}".format(self))
        coords_full = tuple(chart_domain[:]) # all coordinates of chart_domain
        if fixed_coords is None:
            coords = coords_full
        else:
            fixed_coord_list = fixed_coords.keys()
            coords = []
            for coord in coords_full:
                if coord not in fixed_coord_list:
                    coords.append(coord)
            coords = tuple(coords)
        if ambient_coords is None:
            ambient_coords = chart[:]
        elif not isinstance(ambient_coords, tuple):
            ambient_coords = tuple(ambient_coords)
        nca = len(ambient_coords)
        if nca != 2 and nca !=3:
            raise ValueError("the number of ambient coordinates must be " +
                             "either 2 or 3, not {}".format(nca))
        if ranges is None:
            ranges = {}
        ranges0 = {}
        for coord in coords:
            if coord in ranges:
                ranges0[coord] = (numerical_approx(ranges[coord][0]),
                                  numerical_approx(ranges[coord][1]))
            else:
                bounds = chart_domain._bounds[coords_full.index(coord)]
                xmin0 = bounds[0][0]
                xmax0 = bounds[1][0]
                if xmin0 == -Infinity:
                    xmin = numerical_approx(-max_range)
                elif bounds[0][1]:
                    xmin = numerical_approx(xmin0)
                else:
                    xmin = numerical_approx(xmin0 + 1.e-3)
                if xmax0 == Infinity:
                    xmax = numerical_approx(max_range)
                elif bounds[1][1]:
                    xmax = numerical_approx(xmax0)
                else:
                    xmax = numerical_approx(xmax0 - 1.e-3)
                ranges0[coord] = (xmin, xmax)
        ranges = ranges0
        if number_values is None:
            if nca == 2: # 2D plot
                number_values = 9
            else:   # 3D plot
                number_values = 5
        if not isinstance(number_values, dict):
            number_values0 = {}
            for coord in coords:
                number_values0[coord] = number_values
            number_values = number_values0
        if steps is None:
            steps = {}
        for coord in coords:
            if coord not in steps:
                steps[coord] = (ranges[coord][1] - ranges[coord][0])/ \
                               (number_values[coord]-1)
            else:
                number_values[coord] = 1 + int(
                           (ranges[coord][1] - ranges[coord][0])/ steps[coord])
        #
        # 2/ Plots
        #    -----
        dom = chart_domain.domain()
        vector = self.restrict(dom)
        if vector.parent().destination_map() is dom.identity_map():
            if mapping is not None:
                vector = mapping.pushforward(vector)
                mapping = None
        nc = len(coords_full)
        ncp = len(coords)
        xx = [0] * nc
        if fixed_coords is not None:
            if len(fixed_coords) != nc - ncp:
                raise ValueError("bad number of fixed coordinates")
            for fc, val in fixed_coords.items():
                xx[coords_full.index(fc)] = val
        ind_coord = []
        for coord in coords:
            ind_coord.append(coords_full.index(coord))

        resu = Graphics()
        ind = [0] * ncp
        ind_max = [0] * ncp
        ind_max[0] = number_values[coords[0]]
        xmin = [ranges[cd][0] for cd in coords]
        step_tab = [steps[cd] for cd in coords]

        nproc = Parallelism().get('tensor')
        if nproc != 1 and nca == 2:
            # parallel plot construct : Only for 2D plot (at  moment) !

            # creation of the list of parameters
            list_xx = []

            while ind != ind_max:
                for i in  range(ncp):
                    xx[ind_coord[i]] = xmin[i] + ind[i]*step_tab[i]

                if chart_domain.valid_coordinates(*xx, tolerance=1e-13,
                                                  parameters=parameters):

                    # needed a xx*1 to copy the list by value
                    list_xx.append(xx*1)

                # Next index:
                ret = 1
                for pos in range(ncp-1,-1,-1):
                    imax = number_values[coords[pos]] - 1
                    if ind[pos] != imax:
                        ind[pos] += ret
                        ret = 0
                    elif ret == 1:
                        if pos == 0:
                            ind[pos] = imax + 1 # end point reached
                        else:
                            ind[pos] = 0
                            ret = 1

            lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]
            ind_step = max(1, int(len(list_xx)/nproc/2))
            local_list = lol(list_xx,ind_step)

            # definition of the list of input parameters
            listParalInput = [(vector, dom, ind_part,
                               chart_domain, chart,
                               ambient_coords, mapping,
                               scale, color, parameters,
                               extra_options)
                              for ind_part in local_list]


            # definition of the parallel function
            @parallel(p_iter='multiprocessing', ncpus=nproc)
            def add_point_plot(vector, dom, xx_list, chart_domain, chart,
                               ambient_coords, mapping, scale, color,
                               parameters, extra_options):
                count = 0
                for xx in xx_list:
                    point = dom(xx, chart=chart_domain)
                    part = vector.at(point).plot(chart=chart,
                                                 ambient_coords=ambient_coords,
                                                 mapping=mapping,scale=scale,
                                                 color=color, print_label=False,
                                                 parameters=parameters,
                                                 **extra_options)
                    if count == 0:
                        local_resu = part
                    else:
                        local_resu += part
                    count += 1
                return local_resu

            # parallel execution and reconstruction of the plot
            for ii, val in add_point_plot(listParalInput):
                resu += val

        else:
            # sequential plot
            while ind != ind_max:
                for i in range(ncp):
                    xx[ind_coord[i]] = xmin[i] + ind[i]*step_tab[i]
                if chart_domain.valid_coordinates(*xx, tolerance=1e-13,
                                                  parameters=parameters):
                    point = dom(xx, chart=chart_domain)
                    resu += vector.at(point).plot(chart=chart,
                                                  ambient_coords=ambient_coords,
                                                  mapping=mapping, scale=scale,
                                                  color=color, print_label=False,
                                                  parameters=parameters,
                                                  **extra_options)
                # Next index:
                ret = 1
                for pos in range(ncp-1, -1, -1):
                    imax = number_values[coords[pos]] - 1
                    if ind[pos] != imax:
                        ind[pos] += ret
                        ret = 0
                    elif ret == 1:
                        if pos == 0:
                            ind[pos] = imax + 1 # end point reached
                        else:
                            ind[pos] = 0
                            ret = 1

        if label_axes:
            if nca == 2:  # 2D graphic
                # We update the dictionary _extra_kwds (options to be passed
                # to show()), instead of using the method
                # Graphics.axes_labels() since the latter is not robust w.r.t.
                # graph addition
                resu._extra_kwds['axes_labels'] = [r'$'+latex(ac)+r'$'
                                                   for ac in ambient_coords]
            else: # 3D graphic
                labels = [str(ac) for ac in ambient_coords]
                resu = set_axes_labels(resu, *labels)
        return resu
Exemple #20
0
 def my_rounded(number, s):
     m = my_log(number)
     return numerical_approx(number, digits=m - s + 1)
Exemple #21
0
 def percolation_probability(self, stop):
     return numerical_approx(self.ntimes_over_size(stop) / self._n,
                             digits=3)
Exemple #22
0
 def my_rounded(number, s):
     m = floor_log(number)
     return numerical_approx(number, digits=m-s+1)
Exemple #23
0
 def percolation_probability(self, stop):
     return numerical_approx(self.ntimes_over_size(stop) / self._n, digits=3)
Exemple #24
0
    def plot(self, chart=None, ambient_coords=None, mapping=None,
             color='blue', print_label=True, label=None, label_color=None,
             fontsize=10, label_offset=0.1, parameters=None, **extra_options):
        r"""
        Plot the vector in a Cartesian graph based on the coordinates of some
        ambient chart.

        The vector is drawn in terms of two (2D graphics) or three (3D graphics)
        coordinates of a given chart, called hereafter the *ambient chart*.
        The vector's base point `p` (or its image `\Phi(p)` by some
        differentiable mapping `\Phi`) must lie in the ambient chart's domain.
        If `\Phi` is different from the identity mapping, the vector
        actually depicted is `\mathrm{d}\Phi_p(v)`, where `v` is the current
        vector (``self``) (see the example of a vector tangent to the
        2-sphere below, where `\Phi: S^2 \to \RR^3`).

        INPUT:

        - ``chart`` -- (default: ``None``) the ambient chart (see above); if
          ``None``, it is set to the default chart of the open set containing
          the point at which the vector (or the vector image via the
          differential `\mathrm{d}\Phi_p` of ``mapping``) is defined

        - ``ambient_coords`` -- (default: ``None``) tuple containing the 2
          or 3 coordinates of the ambient chart in terms of which the plot
          is performed; if ``None``, all the coordinates of the ambient
          chart are considered

        - ``mapping`` -- (default: ``None``)
          :class:`~sage.manifolds.differentiable.diff_map.DiffMap`;
          differentiable mapping `\Phi` providing the link between the
          point `p` at which the vector is defined and the ambient chart
          ``chart``: the domain of ``chart`` must contain `\Phi(p)`;
          if ``None``, the identity mapping is assumed

        - ``scale`` -- (default: 1) value by which the length of the arrow
          representing the vector is multiplied

        - ``color`` -- (default: 'blue') color of the arrow representing the
          vector

        - ``print_label`` -- (boolean; default: ``True``) determines whether a
          label is printed next to the arrow representing the vector

        - ``label`` -- (string; default: ``None``) label printed next to the
          arrow representing the vector; if ``None``, the vector's symbol is
          used, if any

        - ``label_color`` -- (default: ``None``) color to print the label;
          if ``None``, the value of ``color`` is used

        - ``fontsize`` -- (default: 10) size of the font used to print the
          label

        - ``label_offset`` -- (default: 0.1) determines the separation between
          the vector arrow and the label

        - ``parameters`` -- (default: ``None``) dictionary giving the numerical
          values of the parameters that may appear in the coordinate expression
          of ``self`` (see example below)

        - ``**extra_options`` -- extra options for the arrow plot, like
          ``linestyle``, ``width`` or ``arrowsize`` (see
          :func:`~sage.plot.arrow.arrow2d` and
          :func:`~sage.plot.plot3d.shapes.arrow3d` for details)

        OUTPUT:

        - a graphic object, either an instance of
          :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
          2 coordinates of ``chart``) or an instance of
          :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
          based on 3 coordinates of ``chart``)

        EXAMPLES:

        Vector tangent to a 2-dimensional manifold::

            sage: M = Manifold(2, 'M')
            sage: X.<x,y> = M.chart()
            sage: p = M((2,2), name='p')
            sage: Tp = M.tangent_space(p)
            sage: v = Tp((2, 1), name='v') ; v
            Tangent vector v at Point p on the 2-dimensional differentiable
             manifold M

        Plot of the vector alone (arrow + label)::

            sage: v.plot()
            Graphics object consisting of 2 graphics primitives

        Plot atop of the chart grid::

            sage: X.plot() + v.plot()
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot()
            sphinx_plot(g)

        Plots with various options::

            sage: X.plot() + v.plot(color='green', scale=2, label='V')
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(color='green', scale=2, label='V')
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(print_label=False)
            Graphics object consisting of 19 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(print_label=False)
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(color='green', label_color='black',
            ....:                   fontsize=20, label_offset=0.2)
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(color='green', label_color='black', fontsize=20, label_offset=0.2)
            sphinx_plot(g)

        ::

            sage: X.plot() + v.plot(linestyle=':', width=4, arrowsize=8,
            ....:                   fontsize=20)
            Graphics object consisting of 20 graphics primitives

        .. PLOT::

            M = Manifold(2, 'M')
            X = M.chart('x y'); x, y = X[:]
            p = M((2,2), name='p'); Tp = M.tangent_space(p)
            v = Tp((2, 1), name='v')
            g = X.plot() + v.plot(linestyle=':', width=4, arrowsize=8, fontsize=20)
            sphinx_plot(g)

        Plot with specific values of some free parameters::

            sage: var('a b')
            (a, b)
            sage: v = Tp((1+a, -b^2), name='v') ; v.display()
            v = (a + 1) d/dx - b^2 d/dy
            sage: X.plot() + v.plot(parameters={a: -2, b: 3})
            Graphics object consisting of 20 graphics primitives

        Special case of the zero vector::

            sage: v = Tp.zero() ; v
            Tangent vector zero at Point p on the 2-dimensional differentiable
             manifold M
            sage: X.plot() + v.plot()
            Graphics object consisting of 19 graphics primitives

        Vector tangent to a 4-dimensional manifold::

            sage: M = Manifold(4, 'M')
            sage: X.<t,x,y,z> = M.chart()
            sage: p = M((0,1,2,3), name='p')
            sage: Tp = M.tangent_space(p)
            sage: v = Tp((5,4,3,2), name='v') ; v
            Tangent vector v at Point p on the 4-dimensional differentiable
             manifold M

        We cannot make a 4D plot directly::

            sage: v.plot()
            Traceback (most recent call last):
            ...
            ValueError: the number of coordinates involved in the plot must
             be either 2 or 3, not 4

        Rather, we have to select some chart coordinates for the plot, via
        the argument ``ambient_coords``. For instance, for a 2-dimensional
        plot in terms of the coordinates `(x, y)`::

            sage: v.plot(ambient_coords=(x,y))
            Graphics object consisting of 2 graphics primitives

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p)
            v = Tp((5,4,3,2), name='v')
            g = X.plot(ambient_coords=(x,y)) + v.plot(ambient_coords=(x,y))
            sphinx_plot(g)

        This plot involves only the components `v^x` and `v^y` of `v`.
        Similarly, for a 3-dimensional plot in terms of the coordinates
        `(t, x, y)`::

            sage: g = v.plot(ambient_coords=(t,x,z))
            sage: print(g)
            Graphics3d Object

        This plot involves only the components `v^t`,  `v^x` and `v^z` of `v`.
        A nice 3D view atop the coordinate grid is obtained via::

            sage: (X.plot(ambient_coords=(t,x,z))  # long time
            ....:  + v.plot(ambient_coords=(t,x,z),
            ....:           label_offset=0.5, width=6))
            Graphics3d Object

        .. PLOT::

            M = Manifold(4, 'M')
            X = M.chart('t x y z'); t,x,y,z = X[:]
            p = M((0,1,2,3), name='p'); Tp = M.tangent_space(p)
            v = Tp((5,4,3,2), name='v')
            g = X.plot(ambient_coords=(t,x,z)) + v.plot(ambient_coords=(t,x,z),
                       label_offset=0.5, width=6)
            sphinx_plot(g)

        An example of plot via a differential mapping: plot of a vector tangent
        to a 2-sphere viewed in `\RR^3`::

            sage: S2 = Manifold(2, 'S^2')
            sage: U = S2.open_subset('U') # the open set covered by spherical coord.
            sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: R3 = Manifold(3, 'R^3')
            sage: X3.<x,y,z> = R3.chart()
            sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
            ....:                                 sin(th)*sin(ph),
            ....:                                 cos(th)]}, name='F')
            sage: F.display() # the standard embedding of S^2 into R^3
            F: S^2 --> R^3
            on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
            sage: p = U.point((pi/4, 7*pi/4), name='p')
            sage: v = XS.frame()[1].at(p) ; v  # the coordinate vector d/dphi at p
            Tangent vector d/dph at Point p on the 2-dimensional differentiable
             manifold S^2
            sage: graph_v = v.plot(mapping=F)
            sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)  # long time
            sage: graph_v + graph_S2  # long time
            Graphics3d Object

        .. PLOT::

            S2 = Manifold(2, 'S^2')
            U = S2.open_subset('U')
            XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
            th, ph = XS[:]
            R3 = Manifold(3, 'R^3')
            X3 = R3.chart('x y z')
            F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
                                            cos(th)]}, name='F')
            p = U.point((pi/4, 7*pi/4), name='p')
            v = XS.frame()[1].at(p)
            graph_v = v.plot(mapping=F)
            graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
            sphinx_plot(graph_v + graph_S2)

        """
        from sage.plot.arrow import arrow2d
        from sage.plot.text import text
        from sage.plot.graphics import Graphics
        from sage.plot.plot3d.shapes import arrow3d
        from sage.plot.plot3d.shapes2 import text3d
        from sage.misc.functional import numerical_approx
        from sage.manifolds.differentiable.chart import DiffChart

        scale = extra_options.pop("scale")

        #
        # The "effective" vector to be plotted
        #
        if mapping is None:
            eff_vector = self
            base_point = self._point
        else:
            #!# check
            # For efficiency, the method FiniteRankFreeModuleMorphism._call_()
            # is called instead of FiniteRankFreeModuleMorphism.__call__()
            eff_vector = mapping.differential(self._point)._call_(self)
            base_point = mapping(self._point)
        #
        # The chart w.r.t. which the vector is plotted
        #
        if chart is None:
            chart = base_point.parent().default_chart()
        elif not isinstance(chart, DiffChart):
            raise TypeError("{} is not a chart".format(chart))
        #
        # Coordinates of the above chart w.r.t. which the vector is plotted
        #
        if ambient_coords is None:
            ambient_coords = chart[:]  # all chart coordinates are used
        n_pc = len(ambient_coords)
        if n_pc != 2 and n_pc !=3:
            raise ValueError("the number of coordinates involved in the " +
                             "plot must be either 2 or 3, not {}".format(n_pc))
        # indices coordinates involved in the plot:
        ind_pc = [chart[:].index(pc) for pc in ambient_coords]
        #
        # Components of the vector w.r.t. the chart frame
        #
        basis = chart.frame().at(base_point)
        vcomp = eff_vector.comp(basis=basis)[:]
        xp = base_point.coord(chart=chart)
        #
        # The arrow
        #
        resu = Graphics()
        if parameters is None:
            coord_tail = [numerical_approx(xp[i]) for i in ind_pc]
            coord_head = [numerical_approx(xp[i] + scale*vcomp[i])
                          for i in ind_pc]
        else:
            coord_tail = [numerical_approx(xp[i].substitute(parameters))
                          for i in ind_pc]
            coord_head = [numerical_approx(
                           (xp[i] + scale*vcomp[i]).substitute(parameters))
                          for i in ind_pc]
        if coord_head != coord_tail:
            if n_pc == 2:
                resu += arrow2d(tailpoint=coord_tail, headpoint=coord_head,
                                color=color, **extra_options)
            else:
                resu += arrow3d(coord_tail, coord_head, color=color,
                                **extra_options)
        #
        # The label
        #
        if print_label:
            if label is None:
                if n_pc == 2 and self._latex_name is not None:
                    label = r'$' + self._latex_name + r'$'
                if n_pc == 3 and self._name is not None:
                    label = self._name
            if label is not None:
                xlab = [xh + label_offset for xh in coord_head]
                if label_color is None:
                    label_color = color
                if n_pc == 2:
                    resu += text(label, xlab, fontsize=fontsize,
                                 color=label_color)
                else:
                    resu += text3d(label, xlab, fontsize=fontsize,
                                   color=label_color)
        return resu