def __init__(self, metric, name, latex_name=None, init_coef=True):
        r"""
        Construct a Levi-Civita connection.

        TESTS:

        Levi-Civita connection of the hyperbolic plane::

            sage: M = Manifold(2, 'M')
            sage: X.<r,ph> = M.chart(r'r:(0,+oo) ph:(0,2*pi)')
            sage: g = M.metric('g')
            sage: g[0,0], g[1,1] = 1/(1+r^2), r^2
            sage: from sage.manifolds.differentiable.levi_civita_connection \
            ....:                                   import LeviCivitaConnection
            sage: nab = LeviCivitaConnection(g, 'nabla', latex_name=r'\nabla')
            sage: nab
            Levi-Civita connection nabla associated with the Riemannian metric
             g on the 2-dimensional differentiable manifold M
            sage: TestSuite(nab).run()

        """
        AffineConnection.__init__(self, metric.domain(), name, latex_name)
        self._metric = metric
        # Initialization of the derived quantities:
        LeviCivitaConnection._init_derived(self)
        if init_coef:
            # Initialization of the Christoffel symbols in the top charts on
            # the domain (i.e. disregarding the subcharts)
            for chart in self._domain.top_charts():
                self.coef(chart._frame)
    def __init__(self, metric, name, latex_name=None, init_coef=True):
        r"""
        Construct a Levi-Civita connection.

        TESTS:

        Levi-Civita connection of the hyperbolic plane::

            sage: M = Manifold(2, 'M')
            sage: X.<r,ph> = M.chart(r'r:(0,+oo) ph:(0,2*pi)')
            sage: g = M.metric('g')
            sage: g[0,0], g[1,1] = 1/(1+r^2), r^2
            sage: from sage.manifolds.differentiable.levi_civita_connection \
            ....:                                   import LeviCivitaConnection
            sage: nab = LeviCivitaConnection(g, 'nabla', latex_name=r'\nabla')
            sage: nab
            Levi-Civita connection nabla associated with the Riemannian metric
             g on the 2-dimensional differentiable manifold M
            sage: TestSuite(nab).run()

        """
        AffineConnection.__init__(self, metric.domain(), name, latex_name)
        self._metric = metric
        # Initialization of the derived quantities:
        LeviCivitaConnection._init_derived(self)
        if init_coef:
            # Initialization of the Christoffel symbols in the top charts on
            # the domain (i.e. disregarding the subcharts)
            for chart in self._domain.top_charts():
                self.coef(chart._frame)
    def _del_derived(self):
        r"""
        Delete the derived quantities.

        TEST::

            sage: M = Manifold(5, 'M')
            sage: g = M.metric('g')
            sage: nab = g.connection()
            sage: nab._del_derived()

        """
        AffineConnection._del_derived(self)
    def _del_derived(self):
        r"""
        Delete the derived quantities.

        TESTS::

            sage: M = Manifold(5, 'M')
            sage: g = M.metric('g')
            sage: nab = g.connection()
            sage: nab._del_derived()

        """
        AffineConnection._del_derived(self)
    def _init_derived(self):
        r"""
        Initialize the derived quantities.

        TESTS::

            sage: M = Manifold(5, 'M')
            sage: g = M.metric('g')
            sage: nab = g.connection()
            sage: nab._init_derived()

        """
        AffineConnection._init_derived(self)
    def riemann(self, name=None, latex_name=None):
        r"""
        Return the Riemann curvature tensor of the connection.

        This method redefines
        :meth:`sage.manifolds.differentiable.affine_connection.AffineConnection.riemann`
        to set some name and the latex_name to the output.

        The Riemann curvature tensor is the tensor field `R` of type (1,3)
        defined by

        .. MATH::

            R(\omega, w, u, v) = \left\langle \omega, \nabla_u \nabla_v w
                - \nabla_v \nabla_u w - \nabla_{[u, v]} w \right\rangle

        for any 1-form  `\omega`  and any vector fields `u`, `v` and `w`.

        INPUT:

        - ``name`` -- (default: ``None``) name given to the Riemann tensor;
          if none, it is set to "Riem(g)", where "g" is the metric's name
        - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
          Riemann tensor; if none, it is set to "\\mathrm{Riem}(g)", where "g"
          is the metric's name

        OUTPUT:

        - the Riemann curvature tensor `R`, as an instance of
          :class:`~sage.manifolds.differentiable.tensorfield.TensorField`

        EXAMPLES:

        Riemann tensor of the Levi-Civita connection associated with the
        metric of the hyperbolic plane (Poincare disk model)::

            sage: M = Manifold(2, 'M', start_index=1)
            sage: X.<x,y> = M.chart('x:(-1,1) y:(-1,1)')  # Cartesian coord. on the Poincare disk
            sage: X.add_restrictions(x^2+y^2<1)
            sage: g = M.metric('g')
            sage: g[1,1], g[2,2] = 4/(1-x^2-y^2)^2, 4/(1-x^2-y^2)^2
            sage: nab = g.connection()
            sage: riem = nab.riemann(); riem
            Tensor field Riem(g) of type (1,3) on the 2-dimensional
             differentiable manifold M
            sage: riem.display_comp()
            Riem(g)^x_yxy = -4/(x^4 + y^4 + 2*(x^2 - 1)*y^2 - 2*x^2 + 1)
            Riem(g)^x_yyx = 4/(x^4 + y^4 + 2*(x^2 - 1)*y^2 - 2*x^2 + 1)
            Riem(g)^y_xxy = 4/(x^4 + y^4 + 2*(x^2 - 1)*y^2 - 2*x^2 + 1)
            Riem(g)^y_xyx = -4/(x^4 + y^4 + 2*(x^2 - 1)*y^2 - 2*x^2 + 1)

        """
        if self._riemann is None:
            AffineConnection.riemann(self)
            if name is None:
                self._riemann._name = "Riem(" + self._metric._name + ")"
            else:
                self._riemann._name = name
            if latex_name is None:
                self._riemann._latex_name = r"\mathrm{Riem}\left(" + \
                                           self._metric._latex_name + r"\right)"
            else:
                self._riemann._latex_name = latex_name
            for rst in self._riemann._restrictions.values():
                rst._name = self._riemann._name
                rst._latex_name = self._riemann._latex_name
        return self._riemann
    def coef(self, frame=None):
        r"""
        Return the connection coefficients relative to the given frame.

        `n` being the manifold's dimension, the connection coefficients
        relative to the vector frame `(e_i)` are the `n^3` scalar fields
        `\Gamma^k_{\ \, ij}` defined by

        .. MATH::

            \nabla_{e_j} e_i = \Gamma^k_{\ \, ij} e_k

        If the connection coefficients are not known already, they are computed

         * as Christoffel symbols if the frame `(e_i)` is a coordinate frame
         * from the above formula otherwise

        INPUT:

        - ``frame`` -- (default: ``None``) vector frame relative to which the
          connection coefficients are required; if none is provided, the
          domain's default frame is assumed

        OUTPUT:

        - connection coefficients relative to the frame ``frame``, as an
          instance of the class :class:`~sage.tensor.modules.comp.Components`
          with 3 indices ordered as `(k,i,j)`; for Christoffel symbols,
          an instance of the subclass
          :class:`~sage.tensor.modules.comp.CompWithSym` is returned.

        EXAMPLES:

        Christoffel symbols of the Levi-Civita connection associated to
        the Euclidean metric on `\RR^3` expressed in spherical coordinates::

            sage: M = Manifold(3, 'R^3', start_index=1)
            sage: c_spher.<r,th,ph> = M.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: g = M.metric('g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2 , (r*sin(th))^2
            sage: g.display()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: nab = g.connection()
            sage: gam = nab.coef() ; gam
            3-indices components w.r.t. Coordinate frame (R^3, (d/dr,d/dth,d/dph)),
             with symmetry on the index positions (1, 2)
            sage: gam[:]
            [[[0, 0, 0], [0, -r, 0], [0, 0, -r*sin(th)^2]],
            [[0, 1/r, 0], [1/r, 0, 0], [0, 0, -cos(th)*sin(th)]],
            [[0, 0, 1/r], [0, 0, cos(th)/sin(th)], [1/r, cos(th)/sin(th), 0]]]
            sage: # The only non-zero Christoffel symbols:
            sage: gam[1,2,2], gam[1,3,3]
            (-r, -r*sin(th)^2)
            sage: gam[2,1,2], gam[2,3,3]
            (1/r, -cos(th)*sin(th))
            sage: gam[3,1,3], gam[3,2,3]
            (1/r, cos(th)/sin(th))

        Connection coefficients of the same connection with respect to the
        orthonormal frame associated to spherical coordinates::

            sage: ch_basis = M.automorphism_field()
            sage: ch_basis[1,1], ch_basis[2,2], ch_basis[3,3] = 1, 1/r, 1/(r*sin(th))
            sage: e = c_spher.frame().new_frame(ch_basis, 'e')
            sage: gam_e = nab.coef(e) ; gam_e
            3-indices components w.r.t. Vector frame (R^3, (e_1,e_2,e_3))
            sage: gam_e[:]
            [[[0, 0, 0], [0, -1/r, 0], [0, 0, -1/r]],
            [[0, 1/r, 0], [0, 0, 0], [0, 0, -cos(th)/(r*sin(th))]],
            [[0, 0, 1/r], [0, 0, cos(th)/(r*sin(th))], [0, 0, 0]]]
            sage: # The only non-zero connection coefficients:
            sage: gam_e[1,2,2], gam_e[2,1,2]
            (-1/r, 1/r)
            sage: gam_e[1,3,3], gam_e[3,1,3]
            (-1/r, 1/r)
            sage: gam_e[2,3,3], gam_e[3,2,3]
            (-cos(th)/(r*sin(th)), cos(th)/(r*sin(th)))

        """
        from sage.manifolds.differentiable.vectorframe import CoordFrame
        if frame is None:
            frame = self._domain._def_frame
        if frame not in self._coefficients:
            # the coefficients must be computed
            #
            # Check whether frame is a subframe of a frame in which the
            # coefficients are already known:
            for oframe in self._coefficients:
                if frame in oframe._subframes:
                    self._coefficients[frame] = self._new_coef(frame)
                    comp_store = self._coefficients[frame]._comp
                    ocomp_store = self._coefficients[oframe]._comp
                    for ind, value in ocomp_store.items():
                        comp_store[ind] = value.restrict(frame._domain)
                    break
            else:
                # If not, the coefficients must be computed from scratch:
                manif = self._domain
                if isinstance(frame, CoordFrame):
                    # Christoffel symbols
                    chart = frame._chart
                    gam = self._new_coef(frame)
                    gg = self._metric.comp(frame)
                    ginv = self._metric.inverse().comp(frame)

                    if Parallelism().get('tensor') != 1:
                        # parallel computation
                        nproc = Parallelism().get('tensor')
                        lol = lambda lst, sz: [
                            lst[i:i + sz] for i in range(0, len(lst), sz)
                        ]

                        ind_list = []
                        for ind in gam.non_redundant_index_generator():
                            i, j, k = ind
                            ind_list.append((i, j, k))
                        ind_step = max(1, int(len(ind_list) / nproc / 2))
                        local_list = lol(ind_list, ind_step)

                        # definition of the list of input parameters
                        listParalInput = []
                        for ind_part in local_list:
                            listParalInput.append(
                                (ind_part, chart, ginv, gg, manif))

                        # definition of the parallel function
                        @parallel(p_iter='multiprocessing', ncpus=nproc)
                        def make_Connect(local_list_ijk, chart, ginv, gg,
                                         manif):
                            partial = []
                            for i, j, k in local_list_ijk:
                                rsum = 0
                                for s in manif.irange():
                                    if ginv[i, s, chart] != 0:
                                        rsum += ginv[i, s, chart] * (
                                            gg[s, k, chart].diff(j) +
                                            gg[j, s, chart].diff(k) -
                                            gg[j, k, chart].diff(s))
                                partial.append([i, j, k, rsum / 2])
                            return partial

                        # Computation and Assignation of values
                        for ii, val in make_Connect(listParalInput):
                            for jj in val:
                                gam[jj[0], jj[1], jj[2], ii[0][1]] = jj[3]

                    else:
                        # sequential
                        for ind in gam.non_redundant_index_generator():
                            i, j, k = ind
                            # The computation is performed at the CoordFunction level:
                            rsum = 0
                            for s in manif.irange():
                                rsum += ginv[i, s, chart] * (
                                    gg[s, k, chart].diff(j) +
                                    gg[j, s, chart].diff(k) -
                                    gg[j, k, chart].diff(s))
                            gam[i, j, k, chart] = rsum / 2

                    # Assignation of results
                    self._coefficients[frame] = gam

                else:
                    # Computation from the formula defining the connection coef.
                    return AffineConnection.coef(self, frame)
        return self._coefficients[frame]
    def riemann(self, name=None, latex_name=None):
        r"""
        Return the Riemann curvature tensor of the connection.

        This method redefines
        :meth:`sage.manifolds.differentiable.affine_connection.AffineConnection.riemann`
        to set some name and the latex_name to the output.

        The Riemann curvature tensor is the tensor field `R` of type (1,3)
        defined by

        .. MATH::

            R(\omega, w, u, v) = \left\langle \omega, \nabla_u \nabla_v w
                - \nabla_v \nabla_u w - \nabla_{[u, v]} w \right\rangle

        for any 1-form  `\omega`  and any vector fields `u`, `v` and `w`.

        INPUT:

        - ``name`` -- (default: ``None``) name given to the Riemann tensor;
          if none, it is set to "Riem(g)", where "g" is the metric's name
        - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
          Riemann tensor; if none, it is set to "\\mathrm{Riem}(g)", where "g"
          is the metric's name

        OUTPUT:

        - the Riemann curvature tensor `R`, as an instance of
          :class:`~sage.manifolds.differentiable.tensorfield.TensorField`

        EXAMPLES:

        Riemann tensor of the Levi-Civita connection associated with the
        metric of the hyperbolic plane (Poincaré disk model)::

            sage: M = Manifold(2, 'M', start_index=1)
            sage: X.<x,y> = M.chart('x:(-1,1) y:(-1,1)')  # Cartesian coord. on the Poincaré disk
            sage: X.add_restrictions(x^2+y^2<1)
            sage: g = M.metric('g')
            sage: g[1,1], g[2,2] = 4/(1-x^2-y^2)^2, 4/(1-x^2-y^2)^2
            sage: nab = g.connection()
            sage: riem = nab.riemann(); riem
            Tensor field Riem(g) of type (1,3) on the 2-dimensional
             differentiable manifold M
            sage: riem.display_comp()
            Riem(g)^x_yxy = -4/(x^4 + y^4 + 2*(x^2 - 1)*y^2 - 2*x^2 + 1)
            Riem(g)^x_yyx = 4/(x^4 + y^4 + 2*(x^2 - 1)*y^2 - 2*x^2 + 1)
            Riem(g)^y_xxy = 4/(x^4 + y^4 + 2*(x^2 - 1)*y^2 - 2*x^2 + 1)
            Riem(g)^y_xyx = -4/(x^4 + y^4 + 2*(x^2 - 1)*y^2 - 2*x^2 + 1)

        """
        if self._riemann is None:
            AffineConnection.riemann(self)
            if name is None:
                self._riemann._name = "Riem(" + self._metric._name + ")"
            else:
                self._riemann._name = name
            if latex_name is None:
                self._riemann._latex_name = r"\mathrm{Riem}\left(" + \
                                           self._metric._latex_name + r"\right)"
            else:
                self._riemann._latex_name = latex_name
            for rst in self._riemann._restrictions.values():
                rst._name = self._riemann._name
                rst._latex_name = self._riemann._latex_name
        return self._riemann
    def coef(self, frame=None):
        r"""
        Return the connection coefficients relative to the given frame.

        `n` being the manifold's dimension, the connection coefficients
        relative to the vector frame `(e_i)` are the `n^3` scalar fields
        `\Gamma^k_{\ \, ij}` defined by

        .. MATH::

            \nabla_{e_j} e_i = \Gamma^k_{\ \, ij} e_k

        If the connection coefficients are not known already, they are computed

         * as Christoffel symbols if the frame `(e_i)` is a coordinate frame
         * from the above formula otherwise

        INPUT:

        - ``frame`` -- (default: ``None``) vector frame relative to which the
          connection coefficients are required; if none is provided, the
          domain's default frame is assumed

        OUTPUT:

        - connection coefficients relative to the frame ``frame``, as an
          instance of the class :class:`~sage.tensor.modules.comp.Components`
          with 3 indices ordered as `(k,i,j)`; for Christoffel symbols,
          an instance of the subclass
          :class:`~sage.tensor.modules.comp.CompWithSym` is returned.

        EXAMPLES:

        Christoffel symbols of the Levi-Civita connection associated to
        the Euclidean metric on `\RR^3` expressed in spherical coordinates::

            sage: M = Manifold(3, 'R^3', start_index=1)
            sage: c_spher.<r,th,ph> = M.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
            sage: g = M.metric('g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2 , (r*sin(th))^2
            sage: g.display()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: nab = g.connection()
            sage: gam = nab.coef() ; gam
            3-indices components w.r.t. Coordinate frame (R^3, (d/dr,d/dth,d/dph)),
             with symmetry on the index positions (1, 2)
            sage: gam[:]
            [[[0, 0, 0], [0, -r, 0], [0, 0, -r*sin(th)^2]],
            [[0, 1/r, 0], [1/r, 0, 0], [0, 0, -cos(th)*sin(th)]],
            [[0, 0, 1/r], [0, 0, cos(th)/sin(th)], [1/r, cos(th)/sin(th), 0]]]
            sage: # The only non-zero Christoffel symbols:
            sage: gam[1,2,2], gam[1,3,3]
            (-r, -r*sin(th)^2)
            sage: gam[2,1,2], gam[2,3,3]
            (1/r, -cos(th)*sin(th))
            sage: gam[3,1,3], gam[3,2,3]
            (1/r, cos(th)/sin(th))

        Connection coefficients of the same connection with respect to the
        orthonormal frame associated to spherical coordinates::

            sage: ch_basis = M.automorphism_field()
            sage: ch_basis[1,1], ch_basis[2,2], ch_basis[3,3] = 1, 1/r, 1/(r*sin(th))
            sage: e = c_spher.frame().new_frame(ch_basis, 'e')
            sage: gam_e = nab.coef(e) ; gam_e
            3-indices components w.r.t. Vector frame (R^3, (e_1,e_2,e_3))
            sage: gam_e[:]
            [[[0, 0, 0], [0, -1/r, 0], [0, 0, -1/r]],
            [[0, 1/r, 0], [0, 0, 0], [0, 0, -cos(th)/(r*sin(th))]],
            [[0, 0, 1/r], [0, 0, cos(th)/(r*sin(th))], [0, 0, 0]]]
            sage: # The only non-zero connection coefficients:
            sage: gam_e[1,2,2], gam_e[2,1,2]
            (-1/r, 1/r)
            sage: gam_e[1,3,3], gam_e[3,1,3]
            (-1/r, 1/r)
            sage: gam_e[2,3,3], gam_e[3,2,3]
            (-cos(th)/(r*sin(th)), cos(th)/(r*sin(th)))

        """
        from sage.manifolds.differentiable.vectorframe import CoordFrame
        if frame is None:
            frame = self._domain._def_frame
        if frame not in self._coefficients:
            # the coefficients must be computed
            #
            # Check whether frame is a subframe of a frame in which the
            # coefficients are already known:
            for oframe in self._coefficients:
                if frame in oframe._subframes:
                    self._coefficients[frame] = self._new_coef(frame)
                    comp_store = self._coefficients[frame]._comp
                    ocomp_store = self._coefficients[oframe]._comp
                    for ind, value in ocomp_store.items():
                        comp_store[ind] = value.restrict(frame._domain)
                    break
            else:
                # If not, the coefficients must be computed from scratch:
                manif = self._domain
                if isinstance(frame, CoordFrame):
                    # Christoffel symbols
                    chart = frame._chart
                    gam = self._new_coef(frame)
                    gg = self._metric.comp(frame)
                    ginv = self._metric.inverse().comp(frame)

                    if Parallelism().get('tensor') != 1:
                        # parallel computation
                        nproc = Parallelism().get('tensor')
                        lol = lambda lst, sz: [lst[i:i+sz] for i in
                                                        range(0, len(lst), sz)]

                        ind_list = []
                        for ind in gam.non_redundant_index_generator():
                            i, j, k = ind
                            ind_list.append((i,j,k))
                        ind_step = max(1,int(len(ind_list)/nproc/2))
                        local_list = lol(ind_list,ind_step)

                        # definition of the list of input parameters
                        listParalInput = []
                        for ind_part in local_list:
                            listParalInput.append((ind_part,chart,ginv,gg,manif))

                        # definition of the parallel function
                        @parallel(p_iter='multiprocessing',ncpus=nproc)
                        def make_Connect(local_list_ijk,chart,ginv,gg,manif):
                            partial = []
                            for i,j,k in local_list_ijk:
                                rsum = 0
                                for s in manif.irange():
                                    if ginv[i,s, chart]!=0:
                                        rsum += ginv[i,s, chart] * (
                                                        gg[s,k, chart].diff(j)
                                                      + gg[j,s, chart].diff(k)
                                                      - gg[j,k, chart].diff(s) )
                                partial.append([i,j,k,rsum / 2])
                            return partial

                        # Computation and Assignation of values
                        for ii, val in make_Connect(listParalInput):
                            for jj in val:
                                gam[jj[0],jj[1],jj[2],ii[0][1]] = jj[3]

                    else:
                        # sequential
                        for ind in gam.non_redundant_index_generator():
                            i, j, k = ind
                            # The computation is performed at the ChartFunction level:
                            rsum = 0
                            for s in manif.irange():
                                rsum += ginv[i,s, chart] * (
                                                    gg[s,k, chart].diff(j)
                                                  + gg[j,s, chart].diff(k)
                                                  - gg[j,k, chart].diff(s) )
                            gam[i,j,k, chart] = rsum / 2

                    # Assignation of results
                    self._coefficients[frame] = gam

                else:
                    # Computation from the formula defining the connection coef.
                    return AffineConnection.coef(self, frame)
        return self._coefficients[frame]