コード例 #1
0
 def _new_comp(self, frame_name):
     r"""
     Create some components in the given frame. 
             
     """
     from component import Components, CompFullyAntiSym
     if self.rank == 1:
         return Components(self.manifold, 1, frame_name)
     else:
         return CompFullyAntiSym(self.manifold, self.rank, frame_name)
コード例 #2
0
 def _new_comp(self, frame):
     r"""
     Create some components in the given frame. 
             
     """
     from component import Components, CompFullyAntiSym
     if self.rank == 1:
         return Components(frame, 1)
     else:
         return CompFullyAntiSym(frame, self.rank)
コード例 #3
0
    def pushforward(self, tensor):
        r""" 
        Pushforward operator associated with the embedding.

        INPUT:
        
        - ``tensor`` -- instance of :class:`TensorField` representing a fully 
          contravariant tensor field `T` on the submanifold, i.e. a tensor 
          field of type (k,0), with k a positive integer. The case k=0 
          corresponds to a scalar field.
          
        OUTPUT:
        
        - instance of :class:`TensorField` representing a field of fully 
          contravariant tensors of the ambient manifold, field defined on 
          the domain occupied by the submanifold. 
          
        EXAMPLES:

        Pushforward of a vector field defined on `S^2`, submanifold of `\RR^3`::
        
            sage: M = Manifold(3, 'R^3', r'\RR^3', start_index=1)
            sage: c_cart.<x,y,z> = M.chart('x y z') # Cartesian coordinates on R^3
            sage: S = Submanifold(M, 2, 'S^2', start_index=1)
            sage: U = S.open_domain('U') # U = S minus two poles
            sage: c_spher.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') # spherical coordinates on U
            sage: S.def_embedding( DiffMapping(S, M, [sin(th)*cos(ph), sin(th)*sin(ph), cos(th)], name='i', latex_name=r'\iota') )
            sage: v = VectorField(S, 'v') 
            sage: v[2] = 1 ; v.view()  # azimuthal vector field on S^2
            v = d/dph
            sage: iv = S.pushforward(v) ; iv
            vector field 'i_*(v)' on the domain 'S^2' on the 3-dimensional manifold 'R^3'
            sage: iv.view(c_cart.frame, c_spher) # the pushforward expanded on the Cartesian frame, with components expressed in terms of (th,ph) coordinates
            i_*(v) = -sin(ph)*sin(th) d/dx + cos(ph)*sin(th) d/dy
            
        The components of the pushforward vector are scalar fields on the submanifold::
        
            sage: iv.comp(c_cart.frame)[[1]]
            scalar field on the open domain 'U' on the 2-dimensional submanifold 'S^2' of the 3-dimensional manifold 'R^3'

        Pushforward of a tangent vector to a helix, submanifold of `\RR^3`::
        
            sage: H = Submanifold(M, 1, 'H')
            sage: c_t.<t> = H.chart('t')
            sage: H.def_embedding( DiffMapping(H, M, [cos(t), sin(t), t], name='iH') )
            sage: u = VectorField(H, 'u')
            sage: u[0] = 1 ; u.view() # tangent vector to the helix
            u = d/dt
            sage: iu = H.pushforward(u) ; iu
            vector field 'iH_*(u)' on the domain 'H' on the 3-dimensional manifold 'R^3'
            sage: iu.view(c_cart.frame, c_t)
            iH_*(u) = -sin(t) d/dx + cos(t) d/dy + d/dz

        """
        from component import Components, CompWithSym, CompFullySym, \
                              CompFullyAntiSym
        if tensor.manifold != self:
            raise TypeError("The tensor field is not defined on the " +
                            "submanifold.")
        (ncon, ncov) = tensor.tensor_type
        if ncov != 0:
            raise TypeError("The pushforward cannot be taken on a tensor " +
                            "with some covariant part.")
        dom1 = tensor.domain
        embed = self.embedding
        resu_name = None
        resu_latex_name = None
        if embed.name is not None and tensor.name is not None:
            resu_name = embed.name + '_*(' + tensor.name + ')'
        if embed.latex_name is not None and tensor.latex_name is not None:
            resu_latex_name = embed.latex_name + '_*' + tensor.latex_name
        if ncon == 0:
            raise NotImplementedError("The case of a scalar field is not " +
                                      "implemented yet.")
        # A pair of charts (chart1, chart2) where the computation
        # is feasable is searched, privileging the default chart of the
        # start domain for chart1
        chart1 = None
        chart2 = None
        def_chart1 = dom1.def_chart
        def_chart2 = self.ambient_manifold.def_chart
        if def_chart1.frame in tensor.components and \
               (def_chart1, def_chart2) in embed.coord_expression:
            chart1 = def_chart1
            chart2 = def_chart2
        else:
            for (chart1n, chart2n) in embed.coord_expression:
                if chart2n == def_chart2 and \
                                    chart1n.frame in tensor.components:
                    chart1 = chart1n
                    chart2 = def_chart2
                    break
        if chart2 is None:
            # It is not possible to have def_chart2 as chart for
            # expressing the result; any other chart is then looked for:
            for (chart1n, chart2n) in self.coord_expression:
                if chart1n.frame in tensor.components:
                    chart1 = chart1n
                    chart2 = chart2n
                    break
        if chart1 is None:
            raise ValueError("No common chart could be find to compute " +
                             "the pushforward of the tensor field.")
        frame1 = chart1.frame
        frame2 = chart2.frame
        # Computation at the component level:
        tcomp = tensor.components[frame1]
        # Construction of the pushforward components (ptcomp):
        if isinstance(tcomp, CompFullySym):
            ptcomp = CompFullySym(frame2, ncon)
        elif isinstance(tcomp, CompFullyAntiSym):
            ptcomp = CompFullyAntiSym(frame2, ncon)
        elif isinstance(tcomp, CompWithSym):
            ptcomp = CompWithSym(frame2,
                                 ncon,
                                 sym=tcomp.sym,
                                 antisym=tcomp.antisym)
        else:
            ptcomp = Components(frame2, ncon)
        phi = embed.coord_expression[(chart1, chart2)]
        jacob = phi.jacobian()
        # X2 coordinates expressed in terms of X1 ones via the mapping:
        # coord2_1 = phi(*(chart1.xx))
        si1 = self.sindex
        si2 = self.ambient_manifold.sindex
        for ind_new in ptcomp.non_redundant_index_generator():
            res = 0
            for ind_old in self.index_generator(ncon):
                t = tcomp[[ind_old]].function_chart(chart1)
                for i in range(ncon):
                    t *= jacob[ind_new[i] - si2][ind_old[i] - si1]
                res += t
            ptcomp[ind_new] = res
        resu = ptcomp.tensor_field((ncon, 0),
                                   name=resu_name,
                                   latex_name=resu_latex_name)
        resu.domain = self.domain_amb  # the domain is resctrited to the submanifold
        return resu
コード例 #4
0
    def exterior_der(self, chart_name=None):
        r"""
        Compute the exterior derivative of the differential form. 
        
        INPUT:
        
        - ``chart_name`` -- (default: None): name of the chart used for the
          computation; if none is provided, the computation is performed in a
          coordinate basis where the components are known, or computable by 
          a component transformation, privileging the domain's default chart.
        
        OUTPUT:
        
        - the exterior derivative of ``self``. 
        
        EXAMPLE:
        
        Exterior derivative of a 1-form on a 4-dimensional manifold::
        
            sage: m = Manifold(4, 'M')
            sage: c_txyz.<t,x,y,z> = m.chart('t x y z', 'coord_txyz')           
            sage: a = OneForm(m, 'A')
            sage: a[:] = (t*x*y*z, z*y**2, x*z**2, x**2 + y**2)
            sage: da = a.exterior_der() ; da
            2-form 'dA' on the 4-dimensional manifold 'M'
            sage: da.view()
            dA = -t*y*z dt/\dx - t*x*z dt/\dy - t*x*y dt/\dz + (-2*y*z + z^2) dx/\dy + (-y^2 + 2*x) dx/\dz + (-2*x*z + 2*y) dy/\dz
            sage: latex(da)
            \mathrm{d}A
            
        The exterior derivative is nilpotent::
        
            sage: dda = da.exterior_der() ; dda
            3-form 'ddA' on the 4-dimensional manifold 'M'
            sage: dda.view()
            ddA = 0
            sage: dda == 0
            True

        """
        from sage.calculus.functional import diff
        from utilities import format_unop_txt, format_unop_latex
        if self._exterior_derivative is None:
            # A new computation is necessary:
            if chart_name is None:
                frame_name = self.pick_a_coord_basis()
                if frame_name is None:
                    raise ValueError("No coordinate basis could be found for " +
                                     "the differential form components.")
                chart_name = frame_name[:-2]
                chart = self.domain.atlas[chart_name]
            else:
                chart = self.domain.atlas[chart_name]
                frame_name = chart.frame.name
                if frame_name not in self.components:
                    raise ValueError("Components in the frame " + frame_name + 
                                     " have not been defined.")
            n = self.manifold.dim
            si = self.manifold.sindex
            sc = self.components[frame_name]
            dc = CompFullyAntiSym(self.domain.frames[frame_name], self.rank+1)
            for ind, val in sc._comp.items():
                for i in range(n):
                    ind_d = (i+si,) + ind
                    if len(ind_d) == len(set(ind_d)): # all indices are different
                          dc[[ind_d]] += val.function_chart(chart_name).diff(chart.xx[i])
            dc._del_zeros()
            # Name and LaTeX name of the result (rname and rlname):
            rname = format_unop_txt('d', self.name)
            rlname = format_unop_latex(r'\mathrm{d}', self.latex_name)
            # Final result
            self._exterior_derivative = DiffForm(self.domain, self.rank+1, 
                                                 rname, rlname)
            self._exterior_derivative.components[frame_name] = dc
        return self._exterior_derivative
コード例 #5
0
    def pullback(self, tensor):
        r""" 
        Pullback operator associated with the differentiable mapping. 
        
        INPUT:
        
        - ``tensor`` -- instance of :class:`TensorField` representing a fully 
          covariant tensor field `T` on the *arrival* domain, i.e. a tensor 
          field of type (0,p), with p a positive or zero integer. The case p=0 
          corresponds to a scalar field.
          
        OUTPUT:
        
        - instance of :class:`TensorField` representing a fully 
          covariant tensor field on the *start* domain that is the 
          pullback of `T` given by ``self``. 
          
        EXAMPLES:
        
        Pullback on `S^2` of a scalar field defined on `R^3`::
        
            sage: m = Manifold(2, 'S^2', start_index=1)
            sage: c_spher.<th,ph> = m.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') # spherical coord. on S^2
            sage: n = Manifold(3, 'R^3', r'\RR^3', start_index=1)
            sage: c_cart.<x,y,z> = n.chart('x y z') # Cartesian coord. on R^3
            sage: Phi = DiffMapping(m, n, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)), name='Phi', latex_name=r'\Phi')
            sage: f = ScalarField(n, x*y*z, name='f') ; f
            scalar field 'f' on the 3-dimensional manifold 'R^3'
            sage: f.view()
            f: (x, y, z) |--> x*y*z
            sage: pf = Phi.pullback(f) ; pf
            scalar field 'Phi_*(f)' on the 2-dimensional manifold 'S^2'
            sage: pf.view()
            Phi_*(f): (th, ph) |--> cos(ph)*cos(th)*sin(ph)*sin(th)^2
            
        Pullback on `S^2` of the standard Euclidean metric on `R^3`::
                
            sage: g = SymBilinFormField(n, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
            sage: g.view()
            g = dx*dx + dy*dy + dz*dz
            sage: pg = Phi.pullback(g) ; pg
            field of symmetric bilinear forms 'Phi_*(g)' on the 2-dimensional manifold 'S^2'
            sage: pg.view()
            Phi_*(g) = dth*dth + sin(th)^2 dph*dph

        Pullback on `S^2` of a 3-form on `R^3`::
                
            sage: a = DiffForm(n, 3, 'A')
            sage: a[1,2,3] = f 
            sage: a.view()
            A = x*y*z dx/\dy/\dz
            sage: pa = Phi.pullback(a) ; pa
            3-form 'Phi_*(A)' on the 2-dimensional manifold 'S^2'
            sage: pa.view() # should be zero (as any 3-form on a 2-dimensional manifold)
            Phi_*(A) = 0

        """
        from scalarfield import ScalarField
        from vectorframe import CoordFrame
        from rank2field import SymBilinFormField
        from diffform import DiffForm, OneForm

        if not isinstance(tensor, TensorField):
            raise TypeError("The argument 'tensor' must be a tensor field.")
        dom1 = self.domain1
        dom2 = self.domain2
        if not tensor.domain.is_subdomain(dom2):
            raise TypeError("The tensor field is not defined on the mapping " +
                            "arrival domain.")
        (ncon, ncov) = tensor.tensor_type
        if ncon != 0:
            raise TypeError("The pullback cannot be taken on a tensor " + 
                            "with some contravariant part.")
        resu_name = None ; resu_latex_name = None
        if self.name is not None and tensor.name is not None:
            resu_name = self.name + '_*(' + tensor.name + ')'
        if self.latex_name is not None and tensor.latex_name is not None:
            resu_latex_name = self.latex_name + '_*' + tensor.latex_name                
        if ncov == 0:
            # Case of a scalar field
            # ----------------------
            resu = ScalarField(dom1, name=resu_name, 
                               latex_name=resu_latex_name)
            for chart2 in tensor.express:
                for chart1 in dom1.atlas:
                    if (chart1, chart2) in self.coord_expression:
                        phi = self.coord_expression[(chart1, chart2)]
                        coord1 = chart1.xx
                        ff = tensor.express[chart2]
                        resu.add_expr( ff(*(phi(*coord1))), chart1)
            return resu
        else:
            # Case of tensor field of rank >= 1
            # ---------------------------------
            if isinstance(tensor, OneForm):
                resu = OneForm(dom1, name=resu_name, 
                               latex_name=resu_latex_name)
            elif isinstance(tensor, DiffForm):
                resu = DiffForm(dom1, ncov, name=resu_name, 
                                latex_name=resu_latex_name)
            elif isinstance(tensor, SymBilinFormField):
                resu = SymBilinFormField(dom1, name=resu_name, 
                                         latex_name=resu_latex_name)                
            else:
                resu = TensorField(dom1, 0, ncov, name=resu_name, 
                                   latex_name=resu_latex_name, sym=tensor.sym,
                                   antisym=tensor.antisym)
            for frame2 in tensor.components:
                if isinstance(frame2, CoordFrame):
                    chart2 = frame2.chart
                    for chart1 in dom1.atlas:
                        if (chart1, chart2) in self.coord_expression:
                            # Computation at the component level:
                            frame1 = chart1.frame
                            tcomp = tensor.components[frame2]
                            if isinstance(tcomp, CompFullySym):
                                ptcomp = CompFullySym(frame1, ncov)
                            elif isinstance(tcomp, CompFullyAntiSym):
                                ptcomp = CompFullyAntiSym(frame1, ncov)
                            elif isinstance(tcomp, CompWithSym):
                                ptcomp = CompWithSym(frame1, ncov, sym=tcomp.sym, 
                                                     antisym=tcomp.antisym)
                            else:
                                ptcomp = Components(frame1, ncov)
                            phi = self.coord_expression[(chart1, chart2)]
                            jacob = phi.jacobian()
                            # X2 coordinates expressed in terms of X1 ones via the mapping:
                            coord2_1 = phi(*(chart1.xx)) 
                            si1 = dom1.manifold.sindex
                            si2 = dom2.manifold.sindex
                            for ind_new in ptcomp.non_redundant_index_generator(): 
                                res = 0 
                                for ind_old in dom2.manifold.index_generator(ncov): 
                                    ff = tcomp[[ind_old]].function_chart(chart2)
                                    t = FunctionChart(chart1, ff(*coord2_1))
                                    for i in range(ncov):
                                        t *= jacob[ind_old[i]-si2][ind_new[i]-si1]
                                    res += t
                                ptcomp[ind_new] = res
                            resu.components[frame1] = ptcomp
            return resu
コード例 #6
0
    def wedge(self, other):
        r"""
        Compute the exterior product with another differential form. 
        
        INPUT:
        
        - ``other``: another differential form
        
        OUTPUT:
        
        - the exterior product self/\\other. 
        
        EXAMPLES:
        
        Exterior product of two 1-forms on a 3-dimensional manifold::
        
            sage: m = Manifold(3, 'M')
            sage: c_xyz = Chart(m, 'x y z', 'coord_xyz')
            sage: a = OneForm(m, 'A')
            sage: a[:] = (x, y, z)
            sage: b = OneForm(m, 'B')
            sage: b[2] = z^2
            sage: a.show() ; b.show()
            A = x dx + y dy + z dz
            B = z^2 dz
            sage: h = a.wedge(b) ; h
            2-form 'A/\B' on the 3-dimensional manifold 'M'
            sage: h.show()
            A/\B = x*z^2 dx/\dz + y*z^2 dy/\dz
            sage: latex(h)
            A\wedge B
            sage: latex(h.show())
            A\wedge B = x z^{2} \mathrm{d} x\wedge\mathrm{d} z + y z^{2} \mathrm{d} y\wedge\mathrm{d} z

        The exterior product of two 1-forms is antisymmetric::
        
            sage: (b.wedge(a)).show()
            B/\A = -x*z^2 dx/\dz - y*z^2 dy/\dz
            sage: a.wedge(b) == - b.wedge(a)  
            True
            sage: (a.wedge(b) + b.wedge(a))[:]  # for the skeptical mind
            [0 0 0]
            [0 0 0]
            [0 0 0]
            sage: a.wedge(a) == 0
            True

        The exterior product of a 2-form by a 1-form::
        
            sage: c = OneForm(m, 'C')
            sage: c[1] = y^3 ; c.show()
            C = y^3 dy
            sage: g = h.wedge(c) ; g
            3-form 'A/\B/\C' on the 3-dimensional manifold 'M'
            sage: g.show()
            A/\B/\C = -x*y^3*z^2 dx/\dy/\dz
            sage: g[:]
            [[[0, 0, 0], [0, 0, -x*y^3*z^2], [0, x*y^3*z^2, 0]], [[0, 0, x*y^3*z^2], [0, 0, 0], [-x*y^3*z^2, 0, 0]], [[0, -x*y^3*z^2, 0], [x*y^3*z^2, 0, 0], [0, 0, 0]]]

        The exterior product of a 2-form by a 1-form is symmetric::
        
            sage: h.wedge(c) == c.wedge(h)
            True

        """
        from utilities import is_atomic
        if not isinstance(other, DiffForm):
            raise TypeError("The second argument for the exterior product " +
                            "must be a differential form.")
        if other.rank == 0:
            return other * self
        if self.rank == 0:
            return self * other
        frame_name = self.common_frame(other)
        if frame_name is None:
            raise ValueError("No common frame for the exterior product.")
        rank_r = self.rank + other.rank
        cmp_s = self.components[frame_name]
        cmp_o = other.components[frame_name]
        cmp_r = CompFullyAntiSym(self.manifold, rank_r, frame_name)
        for ind_s, val_s in cmp_s._comp.items():
            for ind_o, val_o in cmp_o._comp.items():
                ind_r = ind_s + ind_o
                if len(ind_r) == len(set(ind_r)):  # all indices are different
                    cmp_r[ind_r] += val_s * val_o
        result = DiffForm(self.manifold, rank_r)
        result.components[frame_name] = cmp_r
        if self.name is not None and other.name is not None:
            sname = self.name
            oname = other.name
            if not is_atomic(sname):
                sname = '(' + sname + ')'
            if not is_atomic(oname):
                oname = '(' + oname + ')'
            result.name = sname + '/\\' + oname
        if self.latex_name is not None and other.latex_name is not None:
            slname = self.latex_name
            olname = other.latex_name
            if not is_atomic(slname):
                slname = '(' + slname + ')'
            if not is_atomic(olname):
                olname = '(' + olname + ')'
            result.latex_name = slname + r'\wedge ' + olname
        return result
コード例 #7
0
    def exterior_der(self, chart_name=None):
        r"""
        Compute the exterior derivative of the differential form. 
        
        INPUT:
        
        - ``chart_name`` -- (default: None): name of the chart used for the
          computation; if none is provided, the computation is performed in a
          coordinate basis where the components are known, or computable by 
          a component transformation, privileging the manifold's default chart.
        
        OUTPUT:
        
        - the exterior derivative of ``self``. 
        
        EXAMPLE:
        
        Exterior derivative of a 1-form on a 4-dimensional manifold::
        
            sage: m = Manifold(4, 'M')
            sage: c_txyz = Chart(m, 't x y z', 'coord_txyz')           
            sage: a = OneForm(m, 'A')
            sage: a[:] = (t*x*y*z, z*y**2, x*z**2, x**2 + y**2)
            sage: da = a.exterior_der() ; da
            2-form 'dA' on the 4-dimensional manifold 'M'
            sage: da.show()
            dA = -t*y*z dt/\dx - t*x*z dt/\dy - t*x*y dt/\dz + (-2*y*z + z^2) dx/\dy + (-y^2 + 2*x) dx/\dz + (-2*x*z + 2*y) dy/\dz
            sage: latex(da)
            \mathrm{d}A
            
        The exterior derivative is nilpotent::
        
            sage: dda = da.exterior_der() ; dda
            3-form 'ddA' on the 4-dimensional manifold 'M'
            sage: dda.show()
            ddA = 0
            sage: dda == 0
            True

        """
        from sage.calculus.functional import diff
        from utilities import format_unop_txt, format_unop_latex
        if self._exterior_derivative is None:
            # A new computation is necessary:
            if chart_name is None:
                frame_name = self.pick_a_coord_basis()
                if frame_name is None:
                    raise ValueError(
                        "No coordinate basis could be found for " +
                        "the differential form components.")
                chart_name = frame_name[:-2]
                chart = self.manifold.atlas[chart_name]
            else:
                chart = self.manifold.atlas[chart_name]
                frame_name = chart.frame.name
                if frame_name not in self.components:
                    raise ValueError("Components in the frame " + frame_name +
                                     " have not been defined.")
            n = self.manifold.dim
            si = self.manifold.sindex
            sc = self.components[frame_name]
            dc = CompFullyAntiSym(self.manifold, self.rank + 1, frame_name)
            for ind, val in sc._comp.items():
                for i in range(n):
                    ind_d = (i + si, ) + ind
                    if len(ind_d) == len(
                            set(ind_d)):  # all indices are different
                        dc[[ind_d]] += val.function_chart(chart_name).diff(
                            chart.xx[i])
            dc._del_zeros()
            # Name and LaTeX name of the result (rname and rlname):
            rname = format_unop_txt('d', self.name)
            rlname = format_unop_latex(r'\mathrm{d}', self.latex_name)
            # Final result
            self._exterior_derivative = DiffForm(self.manifold, self.rank + 1,
                                                 rname, rlname)
            self._exterior_derivative.components[frame_name] = dc
        return self._exterior_derivative
コード例 #8
0
ファイル: diffmapping.py プロジェクト: embray/SageManifolds
    def pullback(self, tensor):
        r""" 
        Pullback operator associated with the differentiable mapping. 
        
        INPUT:
        
        - ``tensor`` -- instance of :class:`TensorField` representing a fully 
          covariant tensor field `T` on the *arrival* manifold, i.e. a tensor 
          field of type (0,p), with p a positive or zero integer. The case p=0 
          corresponds to a scalar field.
          
        OUTPUT:
        
        - instance of :class:`TensorField` representing a fully 
          covariant tensor field on the *start* manifold that is the 
          pullback of `T` given by ``self``. 
          
        EXAMPLES:
        
        Pullback on `S^2` of a scalar field defined on `R^3`::
        
            sage: m = Manifold(2, 'S^2', start_index=1)
            sage: c_spher = Chart(m, r'th:[0,pi]:\theta ph:[0,2*pi):\phi', 'spher') # spherical coord. on S^2
            sage: n = Manifold(3, 'R^3', r'\RR^3', start_index=1)
            sage: c_cart = Chart(n, 'x y z', 'cart') # Cartesian coord. on R^3
            sage: Phi = DiffMapping(m, n, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)), name='Phi', latex_name=r'\Phi')
            sage: f = ScalarField(n, x*y*z, name='f') ; f
            scalar field 'f' on the 3-dimensional manifold 'R^3'
            sage: f.show()
            f: (x, y, z) |--> x*y*z
            sage: pf = Phi.pullback(f) ; pf
            scalar field 'Phi_*(f)' on the 2-dimensional manifold 'S^2'
            sage: pf.show()
            Phi_*(f): (th, ph) |--> cos(ph)*cos(th)*sin(ph)*sin(th)^2
            
        Pullback on `S^2` of the standard Euclidean metric on `R^3`::
                
            sage: g = SymBilinFormField(n, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
            sage: g.show()
            g = dx*dx + dy*dy + dz*dz
            sage: pg = Phi.pullback(g) ; pg
            field of symmetric bilinear forms 'Phi_*(g)' on the 2-dimensional manifold 'S^2'
            sage: pg.show()
            Phi_*(g) = dth*dth + sin(th)^2 dph*dph

        Pullback on `S^2` of a 3-form on `R^3`::
                
            sage: a = DiffForm(n, 3, 'A')
            sage: a[1,2,3] = f 
            sage: a.show()
            A = x*y*z dx/\dy/\dz
            sage: pa = Phi.pullback(a) ; pa
            3-form 'Phi_*(A)' on the 2-dimensional manifold 'S^2'
            sage: pa.show() # should be zero (as any 3-form on a 2-dimensional manifold)
            Phi_*(A) = 0

        """
        from scalarfield import ScalarField
        if not isinstance(tensor, TensorField):
            raise TypeError("The argument 'tensor' must be a tensor field.")
        manif1 = self.manifold1
        manif2 = self.manifold2
        if tensor.manifold != manif2:
            raise TypeError("The tensor field is not defined on the mapping " +
                            "arrival manifold.")
        (ncon, ncov) = tensor.tensor_type
        if ncon != 0:
            raise TypeError("The pullback cannot be taken on a tensor " +
                            "with some contravariant part.")
        resu_name = None
        resu_latex_name = None
        if self.name is not None and tensor.name is not None:
            resu_name = self.name + '_*(' + tensor.name + ')'
        if self.latex_name is not None and tensor.latex_name is not None:
            resu_latex_name = self.latex_name + '_*' + tensor.latex_name
        chart1_name = None
        chart2_name = None
        def_chart1 = manif1.def_chart
        def_chart1_name = def_chart1.name
        def_chart2 = manif2.def_chart
        def_chart2_name = def_chart2.name
        if ncov == 0:
            # Case of a scalar field
            # ----------------------
            # A pair of chart (chart1_name, chart2_name) where the computation
            # is feasable is searched, privileging the default chart of the
            # start manifold for chart1_name
            if def_chart2_name in tensor.express and \
                   (def_chart1_name, def_chart2_name) in self.coord_expression:
                chart1_name = def_chart1_name
                chart2_name = def_chart2_name
            else:
                for (chart1n, chart2n) in self.coord_expression:
                    if chart1n == def_chart1_name and chart2n in tensor.express:
                        chart1_name = def_chart1_name
                        chart2_name = chart2n
                        break
            if chart1_name is None:
                # It is not possible to have def_chart1 as chart for
                # expressing the result; any other chart is then looked for:
                for (chart1n, chart2n) in self.coord_expression:
                    if chart2n in tensor.express:
                        chart1_name = chart1n
                        chart2_name = chart2n
                        break
            if chart1_name is None:
                raise ValueError("No common chart could be find to compute " +
                                 "the pullback of the scalar field.")
            phi = self.coord_expression[(chart1_name, chart2_name)]
            coord1 = manif1.atlas[chart1_name].xx
            ff = tensor.express[chart2_name]
            return ScalarField(manif1, ff(*(phi(*coord1))), chart1_name,
                               resu_name, resu_latex_name)
        else:
            # Case of tensor field of rank >= 1
            # ---------------------------------
            # A pair of chart (chart1_name, chart2_name) where the computation
            # is feasable is searched, privileging the default chart of the
            # start manifold for chart1_name
            if def_chart2.frame.name in tensor.components and \
                   (def_chart1_name, def_chart2_name) in self.coord_expression:
                chart1_name = def_chart1_name
                chart2_name = def_chart2_name
            else:
                for (chart1n, chart2n) in self.coord_expression:
                    if chart1n == def_chart1_name and \
                         manif2.atlas[chart2n].frame.name in tensor.components:
                        chart1_name = def_chart1_name
                        chart2_name = chart2n
                        break
            if chart1_name is None:
                # It is not possible to have def_chart1 as chart for
                # expressing the result; any other chart is then looked for:
                for (chart1n, chart2n) in self.coord_expression:
                    if manif2.atlas[chart2n].frame.name in tensor.components:
                        chart1_name = chart1n
                        chart2_name = chart2n
                        break
            if chart1_name is None:
                raise ValueError("No common chart could be find to compute " +
                                 "the pullback of the tensor field.")
            chart1 = manif1.atlas[chart1_name]
            chart2 = manif2.atlas[chart2_name]
            frame1_name = chart1.frame.name
            frame2_name = chart2.frame.name
            # Computation at the component level:
            tcomp = tensor.components[frame2_name]
            if isinstance(tcomp, CompFullySym):
                ptcomp = CompFullySym(manif1, ncov, frame1_name)
            elif isinstance(tcomp, CompFullyAntiSym):
                ptcomp = CompFullyAntiSym(manif1, ncov, frame1_name)
            elif isinstance(tcomp, CompWithSym):
                ptcomp = CompWithSym(manif1,
                                     ncov,
                                     frame1_name,
                                     sym=tcomp.sym,
                                     antisym=tcomp.antisym)
            else:
                ptcomp = Components(manif1, ncov, frame1_name)
            phi = self.coord_expression[(chart1_name, chart2_name)]
            jacob = phi.jacobian()
            # X2 coordinates expressed in terms of X1 ones via the mapping:
            coord2_1 = phi(*(chart1.xx))
            si1 = manif1.sindex
            si2 = manif2.sindex
            for ind_new in ptcomp.non_redundant_index_generator():
                res = 0
                for ind_old in manif2.index_generator(ncov):
                    ff = tcomp[[ind_old]].function_chart(chart2_name)
                    t = FunctionChart(chart1, ff(*coord2_1))
                    for i in range(ncov):
                        t *= jacob[ind_old[i] - si2][ind_new[i] - si1]
                    res += t
                ptcomp[ind_new] = res
            resu = tensor_field_from_comp(ptcomp, (0, ncov))
            resu.set_name(resu_name, resu_latex_name)
            return resu