示例#1
0
    def __init__(self,
                 vector_field_module,
                 degree,
                 name=None,
                 latex_name=None):
        r"""
        Construct a differential form.

        TEST::

            sage: M = Manifold(2, 'M')
            sage: U = M.open_subset('U') ; V = M.open_subset('V')
            sage: M.declare_union(U,V)   # M is the union of U and V
            sage: c_xy.<x,y> = U.chart() ; c_uv.<u,v> = V.chart()
            sage: transf = c_xy.transition_map(c_uv, (x+y, x-y),
            ....:  intersection_name='W', restrictions1= x>0,
            ....:  restrictions2= u+v>0)
            sage: inv = transf.inverse()
            sage: W = U.intersection(V)
            sage: eU = c_xy.frame() ; eV = c_uv.frame()
            sage: a = M.diff_form(2, name='a') ; a
            2-form 'a' on the 2-dimensional manifold 'M'
            sage: a[eU,0,1] = x*y^2 + 2*x
            sage: a.add_comp_by_continuation(eV, W, c_uv)

        """
        TensorField.__init__(
            self,
            vector_field_module, (0, degree),
            name=name,
            latex_name=latex_name,
            antisym=range(degree),
            parent=vector_field_module.dual_exterior_power(degree))
        self._init_derived()  # initialization of derived quantities
示例#2
0
 def __init__(self, manifold, name, signature=None, latex_name=None):
     SymBilinFormField.__init__(self, manifold, name, latex_name)
     # signature:
     ndim = self.manifold.dim
     if signature is None:
         signature = ndim
     else:
         if not isinstance(signature, (int, Integer)):
             raise TypeError("The metric signature must be an integer.")
         if (signature < -ndim) or (signature > ndim):
             raise ValueError("Metric signature out of range.")
         if (signature + ndim) % 2 == 1:
             if ndim % 2 == 0:
                 raise ValueError("The metric signature must be even.")
             else:
                 raise ValueError("The metric signature must be odd.")
     self._signature = signature
     # the pair (n_+, n_-):
     self._signature_pm = ((ndim + signature) / 2, (ndim - signature) / 2)
     self._indic_signat = 1 - 2 * (self._signature_pm[1] % 2)  # (-1)^n_-
     # inverse metric:
     inv_name = 'inv_' + self.name
     inv_latex_name = self.latex_name + r'^{-1}'
     self._inverse = TensorField(self.manifold,
                                 2,
                                 0,
                                 inv_name,
                                 inv_latex_name,
                                 sym=(0, 1))
     self._connection = None  # Levi-Civita connection (not set yet)
     self._weyl = None  # Weyl tensor (not set yet)
     self._determinants = {}  # determinants in various frames
     self._sqrt_abs_dets = {}  # sqrt(abs(det g)) in various frames
     self._vol_forms = []  # volume form and associated tensors
示例#3
0
 def __init__(self, vector_field_module, name=None, latex_name=None):
     TensorField.__init__(self, vector_field_module, (1,0), name=name,
                          latex_name=latex_name)
     # Initialization of derived quantities:
     TensorField._init_derived(self)
     # Initialization of list of quantities depending on self:
     self._init_dependencies()
示例#4
0
 def __init__(self,
              vector_field_module,
              name=None,
              latex_name=None,
              is_identity=False):
     if is_identity:
         if name is None:
             name = 'Id'
         if latex_name is None and name == 'Id':
             latex_name = r'\mathrm{Id}'
     TensorField.__init__(self,
                          vector_field_module, (1, 1),
                          name=name,
                          latex_name=latex_name,
                          parent=vector_field_module.general_linear_group())
     self._is_identity = is_identity
     self._init_derived()  # initialization of derived quantities
     # Specific initializations for the field of identity maps:
     if self._is_identity:
         self._inverse = self
         for dom in self._domain._subsets:
             if dom.is_manifestly_parallelizable():
                 fmodule = dom.vector_field_module()
                 self._restrictions[dom] = fmodule.identity_map(
                     name=name, latex_name=latex_name)
示例#5
0
 def _del_derived(self):
     r"""
     Delete the derived quantities.
     """
     # First delete the derived quantities pertaining to the mother class:
     TensorField._del_derived(self)
     # then deletes the inverse automorphism:
     self._inverse = None
示例#6
0
 def _del_derived(self):
     r"""
     Delete the derived quantities.
     """
     # First delete the derived quantities pertaining to the mother class:
     TensorField._del_derived(self)
     # then deletes the inverse automorphism:
     self._inverse = None
示例#7
0
 def __init__(self, vector_field_module, name=None, latex_name=None):
     TensorField.__init__(self,
                          vector_field_module, (1, 0),
                          name=name,
                          latex_name=latex_name)
     # Initialization of derived quantities:
     TensorField._init_derived(self)
     # Initialization of list of quantities depending on self:
     self._init_dependencies()
示例#8
0
 def __init__(self, manifold, p, name=None, latex_name=None):
     TensorField.__init__(self,
                          manifold,
                          0,
                          p,
                          name,
                          latex_name,
                          antisym=range(p))
     self._init_derived()  # initialization of derived quantities
示例#9
0
 def __init__(self, domain, p, name=None, latex_name=None):
     TensorField.__init__(self,
                          domain,
                          0,
                          p,
                          name,
                          latex_name,
                          antisym=range(p))
     DiffForm._init_derived(self)  # initialization of derived quantities
示例#10
0
 def __call__(self, *arg):
     r"""
     Redefinition of :meth:`TensorField.__call__` to allow for a single 
     vector argument. 
     """
     if len(arg) > 1:
         # the endomorphism acting as a type (1,1) tensor on a pair
         # (1-form, vector), returning a scalar:
         return TensorField.__call__(self, *arg)
     # the endomorphism acting as such, on a vector, returning a vector:
     vector = arg[0]
     if not isinstance(vector, VectorField):
         raise TypeError("The argument must be a vector field.")
     frame = self.common_frame(vector)
     t = self.components[frame]
     v = vector.components[frame]
     manif = self.manifold
     result = VectorField(self.domain)
     n = manif.dim
     si = manif.sindex
     for i in range(si, si + n):
         res = 0
         for j in range(si, si + n):
             res += t[[i, j]] * v[[j]]
         result.set_comp(frame)[i] = res
     # Name of the output:
     result.name = None
     if self.name is not None and vector.name is not None:
         result.name = self.name + "(" + vector.name + ")"
     # LaTeX symbol for the output:
     result.latex_name = None
     if self.latex_name is not None and vector.latex_name is not None:
         result.latex_name = self.latex_name + r"\left(" + \
                           vector.latex_name + r"\right)"
     return result
示例#11
0
 def __call__(self, *arg):
     r"""
     Redefinition of :meth:`TensorField.__call__` to allow for a single 
     vector argument. 
     """
     if len(arg) > 1:
         # the endomorphism acting as a type (1,1) tensor on a pair 
         # (1-form, vector), returning a scalar:
         return TensorField.__call__(self, *arg) 
     # the endomorphism acting as such, on a vector, returning a vector:
     vector = arg[0]
     if not isinstance(vector, VectorField):
         raise TypeError("The argument must be a vector field.")
     frame_name = self.common_frame(vector)
     t = self.components[frame_name]
     v = vector.components[frame_name]
     manif = self.manifold
     result = VectorField(self.domain)
     n = manif.dim
     si = manif.sindex
     for i in range(si, si+n):
         res = 0
         for j in range(si, si+n):
             res += t[[i,j]]*v[[j]]
         result.set_comp(frame_name)[i] = res
     # Name of the output:
     result.name = None
     if self.name is not None and vector.name is not None:
         result.name = self.name + "(" + vector.name + ")"
     # LaTeX symbol for the output:
     result.latex_name = None
     if self.latex_name is not None and vector.latex_name is not None:
         result.latex_name = self.latex_name + r"\left(" + \
                           vector.latex_name + r"\right)"
     return result
示例#12
0
 def __call__(self, *arg):
     r"""
     Redefinition of
     :meth:`~sage.geometry.manifolds.tensorfield.TensorField.__call__`
     to allow for a proper
     treatment of the identity map and of the call with a single argument
     """
     if self._is_identity:
         if len(arg) == 1:
             # The identity map acting as such, on a vector field:
             vector = arg[0]
             if vector._tensor_type != (1,0):
                 raise TypeError("the argument must be a vector field")
             dom = self._domain.intersection(vector._domain)
             return vector.restrict(dom)
         elif len(arg) == 2:
             # self acting as a type-(1,1) tensor on a pair
             # (1-form, vector field), returning a scalar field:
             oneform = arg[0]
             vector = arg[1]
             dom = self._domain.intersection(
                               oneform._domain).intersection(vector._domain)
             return oneform.restrict(dom)(vector.restrict(dom))
         else:
             raise TypeError("wrong number of arguments")
     # Generic case
     if len(arg) == 1:
         raise NotImplementedError("__call__  with 1 arg not implemented yet")
     return TensorField.__call__(self, *arg)
示例#13
0
 def _init_derived(self):
     r"""
     Initialize the derived quantities
     """
     # Initialization of quantities pertaining to the mother class:
     SymBilinFormField._init_derived(self) 
     # inverse metric:
     inv_name = 'inv_' + self.name
     inv_latex_name = self.latex_name + r'^{-1}'
     self._inverse = TensorField(self.domain, 2, 0, inv_name, 
                                 inv_latex_name, sym=(0,1))   
     self._connection = None  # Levi-Civita connection (not set yet)
     self._weyl = None # Weyl tensor (not set yet)
     self._determinants = {} # determinants in various frames
     self._sqrt_abs_dets = {} # sqrt(abs(det g)) in various frames
     self._vol_forms = [] # volume form and associated tensors
示例#14
0
 def __call__(self, *arg):
     r"""
     Redefinition of
     :meth:`~sage.geometry.manifolds.tensorfield.TensorField.__call__`
     to allow for a proper
     treatment of the identity map and of the call with a single argument
     """
     if self._is_identity:
         if len(arg) == 1:
             # The identity map acting as such, on a vector field:
             vector = arg[0]
             if vector._tensor_type != (1, 0):
                 raise TypeError("the argument must be a vector field")
             dom = self._domain.intersection(vector._domain)
             return vector.restrict(dom)
         elif len(arg) == 2:
             # self acting as a type-(1,1) tensor on a pair
             # (1-form, vector field), returning a scalar field:
             oneform = arg[0]
             vector = arg[1]
             dom = self._domain.intersection(oneform._domain).intersection(
                 vector._domain)
             return oneform.restrict(dom)(vector.restrict(dom))
         else:
             raise TypeError("wrong number of arguments")
     # Generic case
     if len(arg) == 1:
         raise NotImplementedError(
             "__call__  with 1 arg not implemented yet")
     return TensorField.__call__(self, *arg)
示例#15
0
 def __init__(self, vector_field_module, name=None, latex_name=None,
              is_identity=False):
     if is_identity:
         if name is None:
             name = 'Id'
         if latex_name is None and name == 'Id':
             latex_name = r'\mathrm{Id}'
     TensorField.__init__(self, vector_field_module, (1,1), name=name,
                          latex_name=latex_name,
                          parent=vector_field_module.general_linear_group())
     self._is_identity = is_identity
     self._init_derived() # initialization of derived quantities
     # Specific initializations for the field of identity maps:
     if self._is_identity:
         self._inverse = self
         for dom in self._domain._subsets:
             if dom.is_manifestly_parallelizable():
                 fmodule = dom.vector_field_module()
                 self._restrictions[dom] = fmodule.identity_map(name=name,
                                                      latex_name=latex_name)
示例#16
0
    def __mul__(self, other):
        r"""
        Redefinition of
        :meth:`~sage.geometry.manifolds.tensorfield.TensorField.__mul__`
        so that * dispatches either to automorphism composition or to the
        tensor product.

        EXAMPLES:


        """
        if isinstance(other, AutomorphismField):
            return self._mul_(other)  # general linear group law
        else:
            return TensorField.__mul__(self, other)  # tensor product
示例#17
0
    def __mul__(self, other):
        r"""
        Redefinition of
        :meth:`~sage.geometry.manifolds.tensorfield.TensorField.__mul__`
        so that * dispatches either to automorphism composition or to the
        tensor product.

        EXAMPLES:


        """
        if isinstance(other, AutomorphismField):
            return self._mul_(other)  # general linear group law
        else:
            return TensorField.__mul__(self, other)  # tensor product
示例#18
0
 def _init_derived(self):
     r"""
     Initialize the derived quantities
     """
     # Initialization of quantities pertaining to the mother class:
     SymBilinFormField._init_derived(self) 
     # inverse metric:
     inv_name = 'inv_' + self.name
     inv_latex_name = self.latex_name + r'^{-1}'
     self._inverse = TensorField(self.domain, 2, 0, inv_name, 
                                 inv_latex_name, sym=(0,1))   
     self._connection = None  # Levi-Civita connection (not set yet)
     self._weyl = None # Weyl tensor (not set yet)
     self._determinants = {} # determinants in various frames
     self._sqrt_abs_dets = {} # sqrt(abs(det g)) in various frames
     self._vol_forms = [] # volume form and associated tensors
示例#19
0
 def __init__(self, domain, p, name=None, latex_name=None):
     TensorField.__init__(self, domain, 0, p, name, latex_name, 
                          antisym=range(p))
     DiffForm._init_derived(self) # initialization of derived quantities
示例#20
0
    def restrict(self, subdomain, dest_map=None):
        r"""
        Return the restriction of ``self`` to some subdomain.

        This is a redefinition of
        :meth:`sage.geometry.manifolds.tensorfield.TensorField.restrict`
        to take into account the identity map.

        INPUT:

        - ``subdomain`` -- open subset `U` of ``self._domain`` (must be an
          instance of :class:`~sage.geometry.manifolds.domain.ManifoldOpenSubset`)
        - ``dest_map`` -- (default: ``None``) destination map
          `\Phi:\ U \rightarrow V`, where `V` is a subdomain of
          ``self._codomain``
          (type: :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`)
          If None, the restriction of ``self._vmodule._dest_map`` to `U` is
          used.

        OUTPUT:

        - instance of :class:`AutomorphismField` representing the restriction.

        EXAMPLES:

        Restrictions of an automorphism field on the 2-sphere::

            sage: M = Manifold(2, 'S^2', start_index=1)
            sage: U = M.open_subset('U') # the complement of the North pole
            sage: stereoN.<x,y> = U.chart()  # stereographic coordinates from the North pole
            sage: eN = stereoN.frame() # the associated vector frame
            sage: V =  M.open_subset('V') # the complement of the South pole
            sage: stereoS.<u,v> = V.chart()  # stereographic coordinates from the South pole
            sage: eS = stereoS.frame() # the associated vector frame
            sage: transf = stereoN.transition_map(stereoS, (x/(x^2+y^2), y/(x^2+y^2)), intersection_name='W', \
                                                  restrictions1= x^2+y^2!=0, restrictions2= u^2+v^2!=0)
            sage: inv = transf.inverse() # transformation from stereoS to stereoN
            sage: W = U.intersection(V) # the complement of the North and South poles
            sage: stereoN_W = W.atlas()[0]  # restriction of stereographic coord. from North pole to W
            sage: stereoS_W = W.atlas()[1]  # restriction of stereographic coord. from South pole to W
            sage: eN_W = stereoN_W.frame() ; eS_W = stereoS_W.frame()
            sage: a = M.automorphism_field(name='a') ; a
            field of tangent-space automorphisms 'a' on the 2-dimensional manifold 'S^2'
            sage: a[eN,:] = [[1, atan(x^2+y^2)], [0,3]]
            sage: a.add_comp_by_continuation(eS, W, chart=stereoS)
            sage: a.restrict(U)
            field of tangent-space automorphisms 'a' on the open subset 'U' of
             the 2-dimensional manifold 'S^2'
            sage: a.restrict(U)[eN,:]
            [                1 arctan(x^2 + y^2)]
            [                0                 3]
            sage: a.restrict(V)
            field of tangent-space automorphisms 'a' on the open subset 'V' of the 2-dimensional manifold 'S^2'
            sage: a.restrict(V)[eS,:]
            [   (u^4 + 10*u^2*v^2 + v^4 + 2*(u^3*v - u*v^3)*arctan(1/(u^2 + v^2)))/(u^4 + 2*u^2*v^2 + v^4)  -(4*u^3*v - 4*u*v^3 + (u^4 - 2*u^2*v^2 + v^4)*arctan(1/(u^2 + v^2)))/(u^4 + 2*u^2*v^2 + v^4)]
            [                    4*(u^2*v^2*arctan(1/(u^2 + v^2)) - u^3*v + u*v^3)/(u^4 + 2*u^2*v^2 + v^4) (3*u^4 - 2*u^2*v^2 + 3*v^4 - 2*(u^3*v - u*v^3)*arctan(1/(u^2 + v^2)))/(u^4 + 2*u^2*v^2 + v^4)]
            sage: a.restrict(W)
            field of tangent-space automorphisms 'a' on the open subset 'W' of the 2-dimensional manifold 'S^2'
            sage: a.restrict(W)[eN_W,:]
            [                1 arctan(x^2 + y^2)]
            [                0                 3]

        Restrictions of the field of tangent-space identity maps::

            sage: id = M.tangent_identity_field() ; id
            field of tangent-space identity maps on the 2-dimensional manifold 'S^2'
            sage: id.restrict(U)
            field of tangent-space identity maps on the open subset 'U' of the 2-dimensional manifold 'S^2'
            sage: id.restrict(U)[eN,:]
            [1 0]
            [0 1]
            sage: id.restrict(V)
            field of tangent-space identity maps on the open subset 'V' of the 2-dimensional manifold 'S^2'
            sage: id.restrict(V)[eS,:]
            [1 0]
            [0 1]
            sage: id.restrict(W)[eN_W,:]
            [1 0]
            [0 1]
            sage: id.restrict(W)[eS_W,:]
            [1 0]
            [0 1]

        """
        if subdomain == self._domain:
            return self
        if subdomain not in self._restrictions:
            if not self._is_identity:
                return TensorField.restrict(self, subdomain, dest_map=dest_map)
            # Special case of the identity map:
            if not subdomain.is_subset(self._domain):
                raise ValueError("The provided domain is not a subset of " +
                                 "the field's domain.")
            if dest_map is None:
                dest_map = self._vmodule._dest_map.restrict(subdomain)
            elif not dest_map._codomain.is_subset(self._ambient_domain):
                raise ValueError("Argument dest_map not compatible with " +
                                 "self._ambient_domain")
            smodule = subdomain.vector_field_module(dest_map=dest_map)
            self._restrictions[subdomain] = smodule.identity_map()
        return self._restrictions[subdomain]
示例#21
0
class Metric(SymBilinFormField):
    r"""
    Base class for pseudo-Riemannian metrics on a differentiable manifold.

    INPUT:
    
    - ``manifold`` -- the manifold on which the metric is defined
    - ``name`` -- name given to the metric
    - ``signature`` -- (default: None) signature `S` of the metric as a single 
      integer: `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the number of 
      positive terms (resp. number of negative terms) in any diagonal writing 
      of the metric components; if ``signature`` is not provided, `S` is set to 
      the manifold's dimension (Riemannian signature)
    - ``latex_name`` -- (default: None) LaTeX symbol to denote the metric; if
      none, it is formed from ``name``      

    EXAMPLES:
    
    Metric on a 2-dimensional manifold::
    
        sage: m = Manifold(2, 'M', start_index=1)
        sage: c_xy = Chart(m, 'x y', 'xy')
        sage: g = Metric(m, 'g') ; g
        pseudo-Riemannian metric 'g' on the 2-dimensional manifold 'M'
        sage: latex(g)
        g
   
    A metric is a special kind of tensor field and therefore inheritates all the
    properties from class :class:`TensorField`::

        sage: isinstance(g, TensorField)
        True
        sage: g.tensor_type
        (0, 2)
        sage: g.symmetries()  # g is symmetric:
        symmetry: (0, 1);  no antisymmetry
        sage: isinstance(g, SymBilinFormField)  # a metric is actually a field of symmetric bilinear forms:
        True
       
    Setting the metric components in the manifold's default frame::
    
        sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x 
        sage: g[:]
        [ x + 1    x*y]
        [   x*y -x + 1]
        sage: g.show()
        g = (x + 1) dx*dx + x*y dx*dy + x*y dy*dx + (-x + 1) dy*dy

    Metric components in a frame different from the manifold's default one::
    
        sage: c_uv = Chart(m, 'u v', 'uv')  # new chart on M
        sage: xy_to_uv = CoordChange(c_xy, c_uv, x+y, x-y) ; xy_to_uv
        coordinate change from chart 'xy' (x, y) to chart 'uv' (u, v)
        sage: uv_to_xy = xy_to_uv.inverse() ; uv_to_xy
        coordinate change from chart 'uv' (u, v) to chart 'xy' (x, y)
        sage: m.get_atlas()
        {'xy': chart 'xy' (x, y), 'uv': chart 'uv' (u, v)}
        sage: m.frames
        {'xy_b': coordinate basis 'xy_b' (d/dx,d/dy), 'uv_b': coordinate basis 'uv_b' (d/du,d/dv)}
        sage: g.comp('uv_b')[:]  # metric components in frame 'uv_b' expressed in M's default chart (x,y)
        [ 1/2*x*y + 1/2          1/2*x]
        [         1/2*x -1/2*x*y + 1/2]
        sage: g.show('uv_b')
        g = (1/2*x*y + 1/2) du*du + 1/2*x du*dv + 1/2*x dv*du + (-1/2*x*y + 1/2) dv*dv
        sage: g.comp('uv_b')[:, 'uv']   # metric components in frame 'uv_b' expressed in chart (u,v)
        [ 1/8*u^2 - 1/8*v^2 + 1/2            1/4*u + 1/4*v]
        [           1/4*u + 1/4*v -1/8*u^2 + 1/8*v^2 + 1/2]
        sage: g.show('uv_b', 'uv')
        g = (1/8*u^2 - 1/8*v^2 + 1/2) du*du + (1/4*u + 1/4*v) du*dv + (1/4*u + 1/4*v) dv*du + (-1/8*u^2 + 1/8*v^2 + 1/2) dv*dv


    The inverse metric is obtained via :meth:`inverse`::
    
        sage: ig = g.inverse() ; ig
        tensor field 'inv_g' of type (2,0) on the 2-dimensional manifold 'M'
        sage: ig[:]
        [ (x - 1)/(x^2*y^2 + x^2 - 1)      x*y/(x^2*y^2 + x^2 - 1)]
        [     x*y/(x^2*y^2 + x^2 - 1) -(x + 1)/(x^2*y^2 + x^2 - 1)]
        sage: ig.show()
        inv_g = (x - 1)/(x^2*y^2 + x^2 - 1) d/dx*d/dx + x*y/(x^2*y^2 + x^2 - 1) d/dx*d/dy + x*y/(x^2*y^2 + x^2 - 1) d/dy*d/dx - (x + 1)/(x^2*y^2 + x^2 - 1) d/dy*d/dy

    """
    def __init__(self, manifold, name, signature=None, latex_name=None):
        SymBilinFormField.__init__(self, manifold, name, latex_name)
        # signature:
        ndim = self.manifold.dim
        if signature is None:
            signature = ndim
        else:
            if not isinstance(signature, (int, Integer)):
                raise TypeError("The metric signature must be an integer.")
            if (signature < -ndim) or (signature > ndim):
                raise ValueError("Metric signature out of range.")
            if (signature + ndim) % 2 == 1:
                if ndim % 2 == 0:
                    raise ValueError("The metric signature must be even.")
                else:
                    raise ValueError("The metric signature must be odd.")
        self._signature = signature
        # the pair (n_+, n_-):
        self._signature_pm = ((ndim + signature) / 2, (ndim - signature) / 2)
        self._indic_signat = 1 - 2 * (self._signature_pm[1] % 2)  # (-1)^n_-
        # inverse metric:
        inv_name = 'inv_' + self.name
        inv_latex_name = self.latex_name + r'^{-1}'
        self._inverse = TensorField(self.manifold,
                                    2,
                                    0,
                                    inv_name,
                                    inv_latex_name,
                                    sym=(0, 1))
        self._connection = None  # Levi-Civita connection (not set yet)
        self._weyl = None  # Weyl tensor (not set yet)
        self._determinants = {}  # determinants in various frames
        self._sqrt_abs_dets = {}  # sqrt(abs(det g)) in various frames
        self._vol_forms = []  # volume form and associated tensors

    def _repr_(self):
        r"""
        Special Sage function for the string representation of the object.
        """
        description = "pseudo-Riemannian metric '%s'" % self.name
        description += " on the " + str(self.manifold)
        return description

    def _new_instance(self):
        r"""
        Create a :class:`Metric` instance with the same signature.
        
        """
        return Metric(self.manifold, 'unnamed', signature=self._signature)

    def _del_derived(self):
        r"""
        Delete the derived quantities
        """
        # First the derived quantities from the mother class are deleted:
        SymBilinFormField._del_derived(self)
        # The inverse metric is cleared:
        self._inverse.components.clear()
        self._inverse._del_derived()
        # The connection and Weyl tensor are reset to None:
        self._connection = None
        self._weyl = None
        # The dictionary of determinants over the various frames is cleared:
        self._determinants.clear()
        self._sqrt_abs_dets.clear()
        # The volume form and the associated tensors is deleted:
        del self._vol_forms[:]

    def signature(self):
        r"""
        Signature of the metric. 
        
        OUTPUT:

        - signature `S` of the metric, defined as the integer 
          `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the number of 
          positive terms (resp. number of negative terms) in any diagonal 
          writing of the metric components
        
        EXAMPLES:
        
        Signatures on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M')
            sage: g = Metric(M, 'g') # if not specified, the signature is Riemannian
            sage: g.signature() 
            2
            sage: h = Metric(M, 'h', signature=0)
            sage: h.signature()
            0

        """
        return self._signature

    def inverse(self):
        r"""
        Return the inverse metric.
        
        EXAMPLES:
        
        Inverse metric on a 2-dimensional manifold::
    
            sage: m = Manifold(2, 'M', start_index=1)
            sage: c_xy = Chart(m, 'x y', 'xy')
            sage: g = Metric(m, 'g') 
            sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x 
            sage: g[:]  # components in the manifold's default frame
            [ x + 1    x*y]
            [   x*y -x + 1]
            sage: ig = g.inverse() ; ig
            tensor field 'inv_g' of type (2,0) on the 2-dimensional manifold 'M'
            sage: ig[:]
            [ (x - 1)/(x^2*y^2 + x^2 - 1)      x*y/(x^2*y^2 + x^2 - 1)]
            [     x*y/(x^2*y^2 + x^2 - 1) -(x + 1)/(x^2*y^2 + x^2 - 1)]

        If the metric is modified, the inverse metric is automatically updated::
        
            sage: g[1,2] = 0 ; g[:]
            [ x + 1      0]
            [     0 -x + 1]
            sage: g.inverse()[:]
            [ 1/(x + 1)          0]
            [         0 -1/(x - 1)]

        """
        from sage.matrix.constructor import matrix
        from component import CompFullySym
        from utilities import simplify_chain
        # Is the inverse metric up to date ?
        for frame_name in self.components:
            if frame_name not in self._inverse.components:
                # the computation is necessary
                manif = self.manifold
                if frame_name[-2:] == '_b':
                    # coordinate basis
                    chart_name = frame_name[:-2]
                else:
                    chart_name = manif.def_chart.name
                si = manif.sindex
                nsi = manif.dim + si
                try:
                    gmat = matrix([[
                        self.comp(frame_name)[i, j, chart_name].express
                        for j in range(si, nsi)
                    ] for i in range(si, nsi)])
                except KeyError:
                    continue
                gmat_inv = gmat.inverse()
                cinv = CompFullySym(manif, 2, frame_name)
                for i in range(si, nsi):
                    for j in range(i, nsi):  # symmetry taken into account
                        cinv[i, j,
                             chart_name] = simplify_chain(gmat_inv[i - si,
                                                                   j - si])
                self._inverse.components[frame_name] = cinv
        return self._inverse

    def connection(self, name=None, latex_name=None):
        r"""
        Return the unique torsion-free affine connection compatible with 
        ``self``.
        
        This is the so-called Levi-Civita connection.
        
        INPUT:
        
        - ``name`` -- (default: None) name given to the Levi-Civita connection; 
          if none, it is formed from the metric name
        - ``latex_name`` -- (default: None) LaTeX symbol to denote the 
          Levi-Civita connection; if none, it is formed from the symbol 
          `\nabla` and the metric symbol
          
        OUTPUT:
        
        - the Levi-Civita connection, as an instance of 
          :class:`LeviCivitaConnection`. 
          
        EXAMPLES:
        
        Levi-Civitation connection associated with the Euclidean metric on 
        `\RR^3`::
        
            sage: m = Manifold(3, 'R^3', start_index=1)
            sage: # Let us use spherical coordinates on R^3:
            sage: c_spher = Chart(m, r'r:positive, th:positive:\theta, ph:\phi', 'spher')
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2 , (r*sin(th))^2  # the Euclidean metric
            sage: g.connection()
            Levi-Civita connection 'nabla_g' associated with the pseudo-Riemannian metric 'g' on the 3-dimensional manifold 'R^3'
            sage: g.connection()[:]  # Christoffel symbols in spherical coordinates
            [[[0, 0, 0], [0, -r, 0], [0, 0, -r*sin(th)^2]],
            [[0, 1/r, 0], [1/r, 0, 0], [0, 0, -sin(th)*cos(th)]],
            [[0, 0, 1/r], [0, 0, cos(th)/sin(th)], [1/r, cos(th)/sin(th), 0]]]

        Test of compatibility with the metric::
        
            sage: Dg = g.connection()(g) ; Dg
            tensor field 'nabla_g g' of type (0,3) on the 3-dimensional manifold 'R^3'
            sage: Dg == 0
            True
            sage: Dig = g.connection()(g.inverse()) ; Dig
            tensor field 'nabla_g inv_g' of type (2,1) on the 3-dimensional manifold 'R^3'
            sage: Dig == 0
            True
        
        """
        if self._connection is None:
            if name is None:
                name = 'nabla_' + self.name
            if latex_name is None:
                latex_name = r'\nabla_{' + self.latex_name + '}'
            self._connection = LeviCivitaConnection(self, name, latex_name)
        return self._connection

    def christoffel(self, chart_name=None):
        r"""
        Christoffel symbols of ``self`` with respect to a chart.
        
        INPUT:
        
        - ``chart_name`` -- (default: None) name of the chart; if none is 
          provided, the manifold's default chart is assumed.
          
        OUTPUT:
        
        - the set of Christoffel symbols in the given chart, as an instance of
          :class:`CompWithSym`
          
        EXAMPLES:
        
        Christoffel symbols of the flat metric on `\RR^3` with respect to 
        spherical coordinates::
        
            sage: m = Manifold(3, 'R3', r'\RR^3', start_index=1)
            sage: X = Chart(m, r'r:positive th:\theta  ph:\phi','spher')
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, r^2*sin(th)^2
            sage: g.show()  # the standard flat metric expressed in spherical coordinates
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: Gam = g.christoffel() ; Gam
            3-indices components w.r.t. the coordinate basis 'spher_b' (d/dr,d/dth,d/dph), with symmetry on the index positions (1, 2)
            sage: print type(Gam)
            <class 'sage.geometry.manifolds.component.CompWithSym'>
            sage: Gam[:]
            [[[0, 0, 0], [0, -r, 0], [0, 0, -r*sin(th)^2]],
             [[0, 1/r, 0], [1/r, 0, 0], [0, 0, -sin(th)*cos(th)]],
             [[0, 0, 1/r], [0, 0, cos(th)/sin(th)], [1/r, cos(th)/sin(th), 0]]]
            sage: Gam[1,2,2]
            -r
            sage: Gam[2,1,2]
            1/r
            sage: Gam[3,1,3]
            1/r
            sage: Gam[3,2,3]
            cos(th)/sin(th)
            sage: Gam[2,3,3]
            -sin(th)*cos(th)

        
        """
        if chart_name is None:
            frame_name = self.manifold.def_chart.frame.name
        else:
            frame_name = self.manifold.atlas[chart_name].frame.name
        return self.connection().coef(frame_name)

    def riemann(self, frame_name=None, name=None, latex_name=None):
        r""" 
        Return the Riemann curvature tensor associated with the metric.

        This method is actually a shortcut for ``self.connection().riemann()``
        
        The Riemann curvature tensor is the tensor field `R` of type (1,3) 
        defined by

        .. MATH::
            
            R(\omega, u, v, w) = \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:
        
        - ``frame_name`` -- (default: None) string containing the name of the 
          vector frame in which the computation must be performed; if none is 
          provided, the computation is performed in a frame for which the 
          metric components are known, privileging the manifold's default 
          frame.
        - ``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:`TensorField`
        
        EXAMPLES:

        Riemann tensor of the standard metric on the 2-sphere::
        
            sage: m = Manifold(2, 'S^2', start_index=1)
            sage: c_spher = Chart(m, r'th:\theta, ph:\phi', 'spher')
            sage: a = var('a') # the sphere radius 
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
            sage: g.show() # standard metric on the 2-sphere of radius a:
            g = a^2 dth*dth + a^2*sin(th)^2 dph*dph
            sage: g.riemann()
            tensor field 'Riem(g)' of type (1,3) on the 2-dimensional manifold 'S^2'
            sage: g.riemann()[:]
            [[[[0, 0], [0, 0]], [[0, sin(th)^2], [-sin(th)^2, 0]]],
             [[[0, (cos(th)^2 - 1)/sin(th)^2], [1, 0]], [[0, 0], [0, 0]]]]
             
        In dimension 2, the Riemann tensor can be expressed entirely in terms of
        the Ricci scalar `r`:

        .. MATH::
            
            R^i_{\ \, jlk} = \frac{r}{2} \left( \delta^i_{\ \, k} g_{jl}
                - \delta^i_{\ \, l} g_{jk} \right)
        
        This formula can be checked here, with the r.h.s. rewritten as 
        `-r g_{j[k} \delta^i_{\ \, l]}`::
        
            sage: g.riemann() == -g.ricci_scalar()*(g*IdentityMap(m)).antisymmetrize([2,3])
            True
        
        """
        return self.connection().riemann(frame_name, name, latex_name)

    def ricci(self, frame_name=None, name=None, latex_name=None):
        r""" 
        Return the Ricci tensor associated with the metric.
        
        This method is actually a shortcut for ``self.connection().ricci()``
                
        The Ricci tensor is the tensor field `Ric` of type (0,2) 
        defined from the Riemann curvature tensor `R` by 

        .. MATH::
            
            Ric(u, v) = R(e^i, u, e_i, v)
        
        for any vector fields `u` and `v`, `(e_i)` being any vector frame and
        `(e^i)` the dual coframe. 

        INPUT:
        
        - ``frame_name`` -- (default: None) string containing the name of the 
          vector frame in which the computation must be performed; if none is 
          provided, the computation is performed in a frame for which the 
          metric components are known, privileging the manifold's default 
          frame.
        - ``name`` -- (default: None) name given to the Ricci tensor; 
          if none, it is set to "Ric(g)", where "g" is the metric's name
        - ``latex_name`` -- (default: None) LaTeX symbol to denote the 
          Ricci tensor; if none, it is set to "\\mathrm{Ric}(g)", where "g" 
          is the metric's name
          
        OUTPUT:
        
        - the Ricci tensor `Ric`, as an instance of :class:`SymBilinFormField`
        
        EXAMPLES:
        
        Ricci tensor of the standard metric on the 2-sphere::
        
            sage: m = Manifold(2, 'S^2', start_index=1)
            sage: c_spher = Chart(m, r'th:\theta, ph:\phi', 'spher')
            sage: a = var('a') # the sphere radius 
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
            sage: g.show() # standard metric on the 2-sphere of radius a:
            g = a^2 dth*dth + a^2*sin(th)^2 dph*dph
            sage: g.ricci()
            field of symmetric bilinear forms 'Ric(g)' on the 2-dimensional manifold 'S^2'
            sage: g.ricci()[:]
            [        1         0]
            [        0 sin(th)^2]
            sage: g.ricci() == a^(-2) * g
            True

        """
        return self.connection().ricci(frame_name, name, latex_name)

    def ricci_scalar(self, frame_name=None, name=None, latex_name=None):
        r""" 
        Return the Ricci scalar associated with the metric.
        
        The Ricci scalar is the scalar field `r` defined from the Ricci tensor 
        `Ric` and the metric tensor `g` by 

        .. MATH::
            
            r = g^{ij} Ric_{ij}
        

        INPUT:
        
        - ``frame_name`` -- (default: None) string containing the name of the 
          vector frame in which the computation must be performed; if none is 
          provided, the computation is performed in a frame for which the 
          metric components are known, privileging the manifold's default 
          frame.
        - ``name`` -- (default: None) name given to the Ricci scalar; 
          if none, it is set to "r(g)", where "g" is the metric's name
        - ``latex_name`` -- (default: None) LaTeX symbol to denote the 
          Ricci scalar; if none, it is set to "\\mathrm{r}(g)", where "g" 
          is the metric's name

        OUTPUT:
        
        - the Ricci scalar `r`, as an instance of :class:`ScalarField`

        EXAMPLES:
        
        Ricci scalar of the standard metric on the 2-sphere::
        
            sage: m = Manifold(2, 'S^2', start_index=1)
            sage: c_spher = Chart(m, r'th:\theta, ph:\phi', 'spher')
            sage: a = var('a') # the sphere radius 
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
            sage: g.show() # standard metric on the 2-sphere of radius a:
            g = a^2 dth*dth + a^2*sin(th)^2 dph*dph
            sage: g.ricci_scalar()
            scalar field 'r(g)' on the 2-dimensional manifold 'S^2'
            sage: g.ricci_scalar().expr()
            2/a^2

        """
        return self.connection().ricci_scalar(frame_name, name, latex_name)

    def weyl(self, name=None, latex_name=None):
        r""" 
        Return the Weyl conformal tensor associated with the metric.
                        
        The Weyl conformal tensor is the tensor field `C` of type (1,3) 
        defined as the trace-free part of the Riemann curvature tensor `R`

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

        OUTPUT:
        
        - the Weyl conformal tensor `C`, as an instance of :class:`TensorField`
        
        EXAMPLES:
        
        Checking that the Weyl tensor identically vanishes on a 3-dimensional 
        manifold, for instance the hyperbolic space `H^3`::
        
            sage: m = Manifold(3, 'H^3', start_index=1)
            sage: X = Chart(m, r'rh:positive:\rho th:\theta  ph:\phi', 'rtp-coord')
            sage: g = Metric(m, 'g')
            sage: b = var('b')                                                        
            sage: g[1,1], g[2,2], g[3,3] = b^2, (b*sinh(rh))^2, (b*sinh(rh)*sin(th))^2
            sage: g.show()  # standard metric on H^3:
            g = b^2 drh*drh + b^2*sinh(rh)^2 dth*dth + b^2*sin(th)^2*sinh(rh)^2 dph*dph
            sage: C = g.weyl() ; C
            tensor field 'C(g)' of type (1,3) on the 3-dimensional manifold 'H^3'
            sage: C == 0 
            True

        """
        from rank2field import IdentityMap
        if self._weyl is None:
            n = self.manifold.dim
            if n < 3:
                raise ValueError("The Weyl tensor is not defined for a " +
                                 "manifold of dimension n <= 2.")
            delta = IdentityMap(self.manifold)
            riem = self.riemann()
            ric = self.ricci()
            rscal = self.ricci_scalar()
            # First index of the Ricci tensor raised with the metric
            ricup = ric.up(self, 0)
            # The identity map is expressed in a frame in which the Riemann
            # tensor is known
            delta.comp(riem.pick_a_frame())
            aux = self * ricup + ric * delta - rscal / (n - 1) * self * delta
            self._weyl = riem + 2 / (n - 2) * aux.antisymmetrize([2, 3])
            if name is None:
                self._weyl.name = "C(" + self.name + ")"
            else:
                self._weyl.name = name
            if latex_name is None:
                self._weyl.latex_name = r"\mathrm{C}\left(" + self.latex_name + r"\right)"
            else:
                self._weyl.latex_name = latex_name
        return self._weyl

    def determinant(self, frame_name=None):
        r"""
        Determinant of the metric components in the specified frame.
        
        INPUT:
        
        - ``frame_name`` -- (default: None) name of the vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the manifold's default frame is used. If a chart name is 
          provided, the associated coordinate basis is used
          
        OUTPUT:
        
        - the determinant `\det (g_{ij})`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X = Chart(M, 'x y', 'xy')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.determinant()  # determinant in M's default frame
            sage: s.expr()
            -x^2*y^2 - (x + 1)*y + x + 1

        Determinant in a frame different from the default's one::
            
            sage: Y = Chart(M, 'u v', 'uv')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()                    
            coordinate change from chart 'uv' (u, v) to chart 'xy' (x, y)
            sage: g.comp('uv_b')[:, 'uv']
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.determinant('uv_b').expr()
            -1/4*x^2*y^2 - 1/4*(x + 1)*y + 1/4*x + 1/4
            sage: g.determinant('uv_b').expr('uv')
            -1/64*u^4 - 1/16*u^2 - 1/64*v^4 + 1/32*(u^2 + 2)*v^2 + 1/4*v + 1/4

        The name of a chart can be passed instead of the name of a frame::
        
            sage: g.determinant('xy') is g.determinant('xy_b')
            True
            sage: g.determinant('uv') is g.determinant('uv_b')
            True

        The metric determinant depends on the frame::
        
            sage: g.determinant('xy_b') == g.determinant('uv_b')
            False
        
        """
        from sage.matrix.constructor import matrix
        from scalarfield import ScalarField
        from utilities import simple_determinant, simplify_chain
        manif = self.manifold
        if frame_name is None:
            frame_name = manif.def_frame.name
        if frame_name in manif.atlas:
            # frame_name is actually the name of a chart and is changed to the
            # name of the associated coordinate basis:
            frame_name = manif.atlas[frame_name].frame.name
        if frame_name not in self._determinants:
            # a new computation is necessary
            resu = ScalarField(manif)
            gg = self.comp(frame_name)
            i1 = manif.sindex
            for chart_name in gg[[i1, i1]].express:
                gm = matrix(
                    [[gg[i, j, chart_name].express for j in manif.irange()]
                     for i in manif.irange()])
                detgm = simplify_chain(simple_determinant(gm))
                resu.set_expr(detgm,
                              chart_name=chart_name,
                              delete_others=False)
            self._determinants[frame_name] = resu
        return self._determinants[frame_name]

    def sqrt_abs_det(self, frame_name=None):
        r"""
        Square root of the absolute value of the determinant of the metric 
        components in the specified frame.
        
        INPUT:
        
        - ``frame_name`` -- (default: None) name of the vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the manifold's default frame is used. If a chart name is 
          provided, the associated coordinate basis is used
          
        OUTPUT:
        
        -  `\sqrt{|\det (g_{ij})|}`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Standard metric in the Euclidean space `\RR^3` with spherical 
        coordinates::
        
            sage: m = Manifold(3, 'M', start_index=1)
            sage: c_spher = Chart(m, r'r:positive th:positive:\theta ph:\phi', 'spher')
            sage: assume(th>=0); assume(th<=pi)
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
            sage: g.show()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: g.sqrt_abs_det().expr()
            r^2*sin(th)
            
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X = Chart(M, 'x y', 'xy')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.sqrt_abs_det() ; s
            scalar field on the 2-dimensional manifold 'M'
            sage: s.expr()
            sqrt(-x^2*y^2 - (x + 1)*y + x + 1)

        Determinant in a frame different from the default's one::
            
            sage: Y = Chart(M, 'u v', 'uv')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()                    
            coordinate change from chart 'uv' (u, v) to chart 'xy' (x, y)
            sage: g.comp('uv_b')[:, 'uv']
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.sqrt_abs_det('uv_b').expr()
            1/2*sqrt(-x^2*y^2 - (x + 1)*y + x + 1)
            sage: g.sqrt_abs_det('uv_b').expr('uv')
            1/8*sqrt(-u^4 - 4*u^2 - v^4 + 2*(u^2 + 2)*v^2 + 16*v + 16)

        The name of a chart can be passed instead of the name of a frame::
        
            sage: g.sqrt_abs_det('uv') is g.sqrt_abs_det('uv_b')
            True

        The metric determinant depends on the frame::
        
            sage: g.sqrt_abs_det('xy_b') == g.sqrt_abs_det('uv_b') 
            False

        """
        from sage.functions.other import sqrt
        from scalarfield import ScalarField
        from utilities import simplify_chain
        manif = self.manifold
        if frame_name is None:
            frame_name = manif.def_frame.name
        if frame_name in manif.atlas:
            # frame_name is actually the name of a chart and is changed to the
            # name of the associated coordinate basis:
            frame_name = manif.atlas[frame_name].frame.name
        if frame_name not in self._sqrt_abs_dets:
            # a new computation is necessary
            detg = self.determinant(frame_name)
            resu = ScalarField(manif)
            for chart_name in detg.express:
                x = self._indic_signat * detg.express[chart_name].express  # |g|
                x = simplify_chain(sqrt(x))
                resu.set_expr(x, chart_name=chart_name, delete_others=False)
            self._sqrt_abs_dets[frame_name] = resu
        return self._sqrt_abs_dets[frame_name]

    def volume_form(self, contra=0):
        r"""
        Volume form (Levi-Civita tensor) `\epsilon` associated with the metric.
        
        This assumes that the manifold is orientable. 
        
        The volume form `\epsilon` is a `n`-form (`n` being the manifold's 
        dimension) such that for any vector basis `(e_i)` that is orthonormal
        with respect to the metric, 
        
        .. MATH::
            
            \epsilon(e_1,\ldots,e_n) = \pm 1 

        There are only two such `n`-forms, which are opposite of each other. 
        The volume form `\epsilon` is selected such that the manifold's default 
        frame is right-handed with respect to it. 
        
        INPUT:
        
        - ``contra`` -- (default: 0) number of contravariant indices of the
          returned tensor
        
        OUTPUT:
        
        - if ``contra = 0`` (default value): the volume `n`-form `\epsilon`, as 
          an instance of :class:`DiffForm`
        - if ``contra = k``, with `1\leq k \leq n`, the tensor field of type 
          (k,n-k) formed from `\epsilon` by raising the first k indices with the 
          metric (see method :meth:`TensorField.up`); the output is then an
          instance of :class:`TensorField`, with the appropriate antisymmetries
       
        EXAMPLES:
        
        Volume form on `\RR^3` with spherical coordinates::
        
            sage: m = Manifold(3, 'M', start_index=1)
            sage: c_spher = Chart(m, r'r:positive th:positive:\theta ph:\phi', 'spher')
            sage: assume(th>=0); assume(th<=pi)
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
            sage: g.show()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: eps = g.volume_form() ; eps
            3-form 'eps_g' on the 3-dimensional manifold 'M'
            sage: eps.show()
            eps_g = r^2*sin(th) dr/\dth/\dph
            sage: eps[[1,2,3]] == g.sqrt_abs_det()
            True
            sage: latex(eps)
            \epsilon_{g}
            
            
        The tensor field of components `\epsilon^i_{\ \, jk}` (``contra=1``)::
        
            sage: eps1 = g.volume_form(1) ; eps1
            tensor field of type (1,2) on the 3-dimensional manifold 'M'
            sage: eps1.symmetries()
            no symmetry;  antisymmetry: (1, 2)
            sage: eps1[:]
            [[[0, 0, 0], [0, 0, r^2*sin(th)], [0, -r^2*sin(th), 0]],
             [[0, 0, -sin(th)], [0, 0, 0], [sin(th), 0, 0]],
             [[0, 1/sin(th), 0], [-1/sin(th), 0, 0], [0, 0, 0]]]
            
        The tensor field of components `\epsilon^{ij}_{\ \ k}` (``contra=2``)::
        
            sage: eps2 = g.volume_form(2) ; eps2
            tensor field of type (2,1) on the 3-dimensional manifold 'M'
            sage: eps2.symmetries()
            no symmetry;  antisymmetry: (0, 1)
            sage: eps2[:]
            [[[0, 0, 0], [0, 0, sin(th)], [0, -1/sin(th), 0]],
             [[0, 0, -sin(th)], [0, 0, 0], [1/(r^2*sin(th)), 0, 0]],
             [[0, 1/sin(th), 0], [-1/(r^2*sin(th)), 0, 0], [0, 0, 0]]]
            
        The tensor field of components `\epsilon^{ijk}` (``contra=3``)::
        
            sage: eps3 = g.volume_form(3) ; eps3
            tensor field of type (3,0) on the 3-dimensional manifold 'M'
            sage: eps3.symmetries()
            no symmetry;  antisymmetry: (0, 1, 2)
            sage: eps3[:]
            [[[0, 0, 0], [0, 0, 1/(r^2*sin(th))], [0, -1/(r^2*sin(th)), 0]],
             [[0, 0, -1/(r^2*sin(th))], [0, 0, 0], [1/(r^2*sin(th)), 0, 0]],
             [[0, 1/(r^2*sin(th)), 0], [-1/(r^2*sin(th)), 0, 0], [0, 0, 0]]]
            sage: eps3[1,2,3]
            1/(r^2*sin(th))
            sage: eps3[[1,2,3]] * g.sqrt_abs_det() == 1
            True
        
        """
        if self._vol_forms == []:
            # a new computation is necessary
            manif = self.manifold
            ndim = manif.dim
            eps = DiffForm(manif,
                           ndim,
                           name='eps_' + self.name,
                           latex_name=r'\epsilon_{' + self.latex_name + r'}')
            ind = tuple(range(manif.sindex, manif.sindex + ndim))
            eps[[ind]] = self.sqrt_abs_det(manif.def_frame.name)
            self._vol_forms.append(eps)  # Levi-Civita tensor constructed
            # Tensors related to the Levi-Civita one by index rising:
            for k in range(1, ndim + 1):
                epskm1 = self._vol_forms[k - 1]
                epsk = epskm1.up(self, k - 1)
                if k > 1:
                    # restoring the antisymmetry after the up operation:
                    epsk = epsk.antisymmetrize(range(k))
                self._vol_forms.append(epsk)
        return self._vol_forms[contra]
示例#22
0
 def _init_derived(self):
     r"""
     Initialises the derived quantities
     """
     TensorField._init_derived(self)
     self._exterior_derivative = None
示例#23
0
 def _del_derived(self):
     r"""
     Delete the derived quantities
     """
     TensorField._del_derived(self)
     self._exterior_derivative = None
示例#24
0
 def _del_derived(self):
     r"""
     Delete the derived quantities
     """
     TensorField._del_derived(self)
     self._del_dependencies()
示例#25
0
    def restrict(self, subdomain, dest_map=None):
        r"""
        Return the restriction of ``self`` to some subdomain.

        This is a redefinition of
        :meth:`sage.geometry.manifolds.tensorfield.TensorField.restrict`
        to take into account the identity map.

        INPUT:

        - ``subdomain`` -- open subset `U` of ``self._domain`` (must be an
          instance of :class:`~sage.geometry.manifolds.domain.ManifoldOpenSubset`)
        - ``dest_map`` -- (default: ``None``) destination map
          `\Phi:\ U \rightarrow V`, where `V` is a subdomain of
          ``self._codomain``
          (type: :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`)
          If None, the restriction of ``self._vmodule._dest_map`` to `U` is
          used.

        OUTPUT:

        - instance of :class:`AutomorphismField` representing the restriction.

        EXAMPLES:

        Restrictions of an automorphism field on the 2-sphere::

            sage: M = Manifold(2, 'S^2', start_index=1)
            sage: U = M.open_subset('U') # the complement of the North pole
            sage: stereoN.<x,y> = U.chart()  # stereographic coordinates from the North pole
            sage: eN = stereoN.frame() # the associated vector frame
            sage: V =  M.open_subset('V') # the complement of the South pole
            sage: stereoS.<u,v> = V.chart()  # stereographic coordinates from the South pole
            sage: eS = stereoS.frame() # the associated vector frame
            sage: transf = stereoN.transition_map(stereoS, (x/(x^2+y^2), y/(x^2+y^2)), intersection_name='W', \
                                                  restrictions1= x^2+y^2!=0, restrictions2= u^2+v^2!=0)
            sage: inv = transf.inverse() # transformation from stereoS to stereoN
            sage: W = U.intersection(V) # the complement of the North and South poles
            sage: stereoN_W = W.atlas()[0]  # restriction of stereographic coord. from North pole to W
            sage: stereoS_W = W.atlas()[1]  # restriction of stereographic coord. from South pole to W
            sage: eN_W = stereoN_W.frame() ; eS_W = stereoS_W.frame()
            sage: a = M.automorphism_field(name='a') ; a
            field of tangent-space automorphisms 'a' on the 2-dimensional manifold 'S^2'
            sage: a[eN,:] = [[1, atan(x^2+y^2)], [0,3]]
            sage: a.add_comp_by_continuation(eS, W, chart=stereoS)
            sage: a.restrict(U)
            field of tangent-space automorphisms 'a' on the open subset 'U' of
             the 2-dimensional manifold 'S^2'
            sage: a.restrict(U)[eN,:]
            [                1 arctan(x^2 + y^2)]
            [                0                 3]
            sage: a.restrict(V)
            field of tangent-space automorphisms 'a' on the open subset 'V' of the 2-dimensional manifold 'S^2'
            sage: a.restrict(V)[eS,:]
            [   (u^4 + 10*u^2*v^2 + v^4 + 2*(u^3*v - u*v^3)*arctan(1/(u^2 + v^2)))/(u^4 + 2*u^2*v^2 + v^4)  -(4*u^3*v - 4*u*v^3 + (u^4 - 2*u^2*v^2 + v^4)*arctan(1/(u^2 + v^2)))/(u^4 + 2*u^2*v^2 + v^4)]
            [                    4*(u^2*v^2*arctan(1/(u^2 + v^2)) - u^3*v + u*v^3)/(u^4 + 2*u^2*v^2 + v^4) (3*u^4 - 2*u^2*v^2 + 3*v^4 - 2*(u^3*v - u*v^3)*arctan(1/(u^2 + v^2)))/(u^4 + 2*u^2*v^2 + v^4)]
            sage: a.restrict(W)
            field of tangent-space automorphisms 'a' on the open subset 'W' of the 2-dimensional manifold 'S^2'
            sage: a.restrict(W)[eN_W,:]
            [                1 arctan(x^2 + y^2)]
            [                0                 3]

        Restrictions of the field of tangent-space identity maps::

            sage: id = M.tangent_identity_field() ; id
            field of tangent-space identity maps on the 2-dimensional manifold 'S^2'
            sage: id.restrict(U)
            field of tangent-space identity maps on the open subset 'U' of the 2-dimensional manifold 'S^2'
            sage: id.restrict(U)[eN,:]
            [1 0]
            [0 1]
            sage: id.restrict(V)
            field of tangent-space identity maps on the open subset 'V' of the 2-dimensional manifold 'S^2'
            sage: id.restrict(V)[eS,:]
            [1 0]
            [0 1]
            sage: id.restrict(W)[eN_W,:]
            [1 0]
            [0 1]
            sage: id.restrict(W)[eS_W,:]
            [1 0]
            [0 1]

        """
        if subdomain == self._domain:
            return self
        if subdomain not in self._restrictions:
            if not self._is_identity:
                return TensorField.restrict(self, subdomain, dest_map=dest_map)
            # Special case of the identity map:
            if not subdomain.is_subset(self._domain):
                raise ValueError("The provided domain is not a subset of " +
                                 "the field's domain.")
            if dest_map is None:
                dest_map = self._vmodule._dest_map.restrict(subdomain)
            elif not dest_map._codomain.is_subset(self._ambient_domain):
                raise ValueError("Argument dest_map not compatible with " +
                                 "self._ambient_domain")
            smodule = subdomain.vector_field_module(dest_map=dest_map)
            self._restrictions[subdomain] = smodule.identity_map()
        return self._restrictions[subdomain]
示例#26
0
 def __init__(self, manifold, p, name=None, latex_name=None):
     TensorField.__init__(self, manifold, 0, p, name, latex_name, 
                          antisym=range(p))
     self._init_derived() # initialization of derived quantities
示例#27
0
 def __init__(self, manifold, name=None, latex_name=None):
     TensorField.__init__(self, manifold, 1, 1, name, latex_name)
示例#28
0
 def __init__(self, domain, name=None, latex_name=None):
     TensorField.__init__(self, domain, 1, 1, name, latex_name)
示例#29
0
class Metric(SymBilinFormField):
    r"""
    Base class for pseudo-Riemannian metrics on a differentiable manifold.

    INPUT:
    
    - ``domain`` -- the manifold domain on which the metric is defined
      (must be an instance of class :class:`Domain`)
    - ``name`` -- name given to the metric
    - ``signature`` -- (default: None) signature `S` of the metric as a single 
      integer: `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the number of 
      positive terms (resp. number of negative terms) in any diagonal writing 
      of the metric components; if ``signature`` is not provided, `S` is set to 
      the manifold's dimension (Riemannian signature)
    - ``latex_name`` -- (default: None) LaTeX symbol to denote the metric; if
      none, it is formed from ``name``      

    EXAMPLES:
    
    Metric on a 2-dimensional manifold::
    
        sage: m = Manifold(2, 'M', start_index=1)
        sage: c_xy.<x,y> = m.chart('x y')
        sage: g = Metric(m, 'g') ; g
        pseudo-Riemannian metric 'g' on the 2-dimensional manifold 'M'
        sage: latex(g)
        g
   
    A metric is a special kind of tensor field and therefore inheritates all the
    properties from class :class:`TensorField`::

        sage: isinstance(g, TensorField)
        True
        sage: g.tensor_type
        (0, 2)
        sage: g.symmetries()  # g is symmetric:
        symmetry: (0, 1);  no antisymmetry
        sage: isinstance(g, SymBilinFormField)  # a metric is actually a field of symmetric bilinear forms:
        True
       
    Setting the metric components in the manifold's default frame::
    
        sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x 
        sage: g[:]
        [ x + 1    x*y]
        [   x*y -x + 1]
        sage: g.view()
        g = (x + 1) dx*dx + x*y dx*dy + x*y dy*dx + (-x + 1) dy*dy

    Metric components in a frame different from the manifold's default one::
    
        sage: c_uv.<u,v> = m.chart('u v')  # new chart on M
        sage: xy_to_uv = CoordChange(c_xy, c_uv, x+y, x-y) ; xy_to_uv
        coordinate change from chart (M, (x, y)) to chart (M, (u, v))
        sage: uv_to_xy = xy_to_uv.inverse() ; uv_to_xy
        coordinate change from chart (M, (u, v)) to chart (M, (x, y))
        sage: m.atlas
        [chart (M, (x, y)), chart (M, (u, v))]
        sage: m.frames
        [coordinate frame (M, (d/dx,d/dy)), coordinate frame (M, (d/du,d/dv))]
        sage: g.comp(c_uv.frame)[:]  # metric components in frame c_uv.frame expressed in M's default chart (x,y)
        [ 1/2*x*y + 1/2          1/2*x]
        [         1/2*x -1/2*x*y + 1/2]
        sage: g.view(c_uv.frame)
        g = (1/2*x*y + 1/2) du*du + 1/2*x du*dv + 1/2*x dv*du + (-1/2*x*y + 1/2) dv*dv
        sage: g.comp(c_uv.frame)[:, c_uv]   # metric components in frame c_uv.frame expressed in chart (u,v)
        [ 1/8*u^2 - 1/8*v^2 + 1/2            1/4*u + 1/4*v]
        [           1/4*u + 1/4*v -1/8*u^2 + 1/8*v^2 + 1/2]
        sage: g.view(c_uv.frame, c_uv)
        g = (1/8*u^2 - 1/8*v^2 + 1/2) du*du + (1/4*u + 1/4*v) du*dv + (1/4*u + 1/4*v) dv*du + (-1/8*u^2 + 1/8*v^2 + 1/2) dv*dv


    The inverse metric is obtained via :meth:`inverse`::
    
        sage: ig = g.inverse() ; ig
        tensor field 'inv_g' of type (2,0) on the 2-dimensional manifold 'M'
        sage: ig[:]
        [ (x - 1)/(x^2*y^2 + x^2 - 1)      x*y/(x^2*y^2 + x^2 - 1)]
        [     x*y/(x^2*y^2 + x^2 - 1) -(x + 1)/(x^2*y^2 + x^2 - 1)]
        sage: ig.view()
        inv_g = (x - 1)/(x^2*y^2 + x^2 - 1) d/dx*d/dx + x*y/(x^2*y^2 + x^2 - 1) d/dx*d/dy + x*y/(x^2*y^2 + x^2 - 1) d/dy*d/dx - (x + 1)/(x^2*y^2 + x^2 - 1) d/dy*d/dy

    """
    def __init__(self, domain, name, signature=None, latex_name=None):
        SymBilinFormField.__init__(self, domain, name, latex_name)
        # signature:
        ndim = self.manifold.dim
        if signature is None:
            signature = ndim
        else:
            if not isinstance(signature, (int, Integer)):
                raise TypeError("The metric signature must be an integer.")
            if (signature < - ndim) or (signature > ndim):
                raise ValueError("Metric signature out of range.")
            if (signature+ndim)%2 == 1:
                if ndim%2 == 0:
                    raise ValueError("The metric signature must be even.")
                else:
                    raise ValueError("The metric signature must be odd.")
        self._signature = signature
        # the pair (n_+, n_-):
        self._signature_pm = ((ndim+signature)/2, (ndim-signature)/2)
        self._indic_signat = 1 - 2*(self._signature_pm[1]%2)  # (-1)^n_-
        Metric._init_derived(self)
        
    def _repr_(self):
        r"""
        Special Sage function for the string representation of the object.
        """
        description = "pseudo-Riemannian metric '%s'" % self.name
        description += " on the " + str(self.domain)
        return description

    def _new_instance(self):
        r"""
        Create a :class:`Metric` instance with the same signature.
        
        """
        return Metric(self.domain, 'unnamed', signature=self._signature)

    def _init_derived(self):
        r"""
        Initialize the derived quantities
        """
        # Initialization of quantities pertaining to the mother class:
        SymBilinFormField._init_derived(self) 
        # inverse metric:
        inv_name = 'inv_' + self.name
        inv_latex_name = self.latex_name + r'^{-1}'
        self._inverse = TensorField(self.domain, 2, 0, inv_name, 
                                    inv_latex_name, sym=(0,1))   
        self._connection = None  # Levi-Civita connection (not set yet)
        self._weyl = None # Weyl tensor (not set yet)
        self._determinants = {} # determinants in various frames
        self._sqrt_abs_dets = {} # sqrt(abs(det g)) in various frames
        self._vol_forms = [] # volume form and associated tensors

    def _del_derived(self):
        r"""
        Delete the derived quantities
        """
        # First the derived quantities from the mother class are deleted:
        SymBilinFormField._del_derived(self)
        # The inverse metric is cleared: 
        self._inverse.components.clear()
        self._inverse._del_derived()
        # The connection and Weyl tensor are reset to None:
        self._connection = None
        self._weyl = None
        # The dictionary of determinants over the various frames is cleared:
        self._determinants.clear()
        self._sqrt_abs_dets.clear()
        # The volume form and the associated tensors is deleted:
        del self._vol_forms[:]

    def signature(self):
        r"""
        Signature of the metric. 
        
        OUTPUT:

        - signature `S` of the metric, defined as the integer 
          `S = n_+ - n_-`, where `n_+` (resp. `n_-`) is the number of 
          positive terms (resp. number of negative terms) in any diagonal 
          writing of the metric components
        
        EXAMPLES:
        
        Signatures on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M')
            sage: g = Metric(M, 'g') # if not specified, the signature is Riemannian
            sage: g.signature() 
            2
            sage: h = Metric(M, 'h', signature=0)
            sage: h.signature()
            0

        """
        return self._signature

    def set(self, symbiform):
        r"""
        Defines the metric from a field of symmetric bilinear forms
        
        INPUT:
    
        - ``symbiform`` -- field of symmetric bilinear forms

        """
        if not isinstance(symbiform, SymBilinFormField):
            raise TypeError("The argument must be a symmetric bilinear form.")
        if symbiform.manifold != self.manifold:
            raise TypeError("The manifold of the symmetric bilinear form " + 
                            "differs from that of the metric.")
        self.domain = symbiform.domain
        self._init_derived()
        self.components.clear()
        for frame in symbiform.components:
            self.components[frame] = symbiform.components[frame].copy()
        
    def inverse(self):
        r"""
        Return the inverse metric.
        
        EXAMPLES:
        
        Inverse metric on a 2-dimensional manifold::
    
            sage: m = Manifold(2, 'M', start_index=1)
            sage: c_xy.<x,y> = m.chart('x y')
            sage: g = Metric(m, 'g') 
            sage: g[1,1], g[1,2], g[2,2] = 1+x, x*y, 1-x 
            sage: g[:]  # components in the manifold's default frame
            [ x + 1    x*y]
            [   x*y -x + 1]
            sage: ig = g.inverse() ; ig
            tensor field 'inv_g' of type (2,0) on the 2-dimensional manifold 'M'
            sage: ig[:]
            [ (x - 1)/(x^2*y^2 + x^2 - 1)      x*y/(x^2*y^2 + x^2 - 1)]
            [     x*y/(x^2*y^2 + x^2 - 1) -(x + 1)/(x^2*y^2 + x^2 - 1)]

        If the metric is modified, the inverse metric is automatically updated::
        
            sage: g[1,2] = 0 ; g[:]
            [ x + 1      0]
            [     0 -x + 1]
            sage: g.inverse()[:]
            [ 1/(x + 1)          0]
            [         0 -1/(x - 1)]

        """
        from sage.matrix.constructor import matrix
        from component import CompFullySym
        from vectorframe import CoordFrame
        from utilities import simplify_chain
        # Is the inverse metric up to date ?
        for frame in self.components:
            if frame not in self._inverse.components:
                # the computation is necessary
                manif = self.manifold
                dom = self.domain
                if isinstance(frame, CoordFrame):
                    chart = frame.chart
                else:
                    chart = dom.def_chart
                si = manif.sindex
                nsi = manif.dim + si
                try:    
                    gmat = matrix(
                              [[self.comp(frame)[i, j, chart].express 
                              for j in range(si, nsi)] for i in range(si, nsi)])
                except (KeyError, ValueError):
                    continue
                gmat_inv = gmat.inverse()
                cinv = CompFullySym(frame, 2)
                for i in range(si, nsi):
                    for j in range(i, nsi):   # symmetry taken into account
                        cinv[i, j, chart] = simplify_chain(
                                                        gmat_inv[i-si,j-si])
                self._inverse.components[frame] = cinv
        return self._inverse
        
    def connection(self, name=None, latex_name=None):
        r"""
        Return the unique torsion-free affine connection compatible with 
        ``self``.
        
        This is the so-called Levi-Civita connection.
        
        INPUT:
        
        - ``name`` -- (default: None) name given to the Levi-Civita connection; 
          if none, it is formed from the metric name
        - ``latex_name`` -- (default: None) LaTeX symbol to denote the 
          Levi-Civita connection; if none, it is formed from the symbol 
          `\nabla` and the metric symbol
          
        OUTPUT:
        
        - the Levi-Civita connection, as an instance of 
          :class:`LeviCivitaConnection`. 
          
        EXAMPLES:
        
        Levi-Civitation connection associated with the Euclidean metric on 
        `\RR^3`::
        
            sage: m = Manifold(3, 'R^3', start_index=1)
            sage: # Let us use spherical coordinates on R^3:
            sage: c_spher.<r,th,ph> = m.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi')
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2 , (r*sin(th))^2  # the Euclidean metric
            sage: g.connection()
            Levi-Civita connection 'nabla_g' associated with the pseudo-Riemannian metric 'g' on the 3-dimensional manifold 'R^3'
            sage: g.connection()[:]  # Christoffel symbols in spherical coordinates
            [[[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]]]

        Test of compatibility with the metric::
        
            sage: Dg = g.connection()(g) ; Dg
            tensor field 'nabla_g g' of type (0,3) on the 3-dimensional manifold 'R^3'
            sage: Dg == 0
            True
            sage: Dig = g.connection()(g.inverse()) ; Dig
            tensor field 'nabla_g inv_g' of type (2,1) on the 3-dimensional manifold 'R^3'
            sage: Dig == 0
            True
        
        """
        if self._connection is None:
            if name is None:
                name = 'nabla_' + self.name
            if latex_name is None:
                latex_name = r'\nabla_{' + self.latex_name + '}'
            self._connection = LeviCivitaConnection(self, name, latex_name)
        return self._connection

        
    def christoffel(self, chart=None):
        r"""
        Christoffel symbols of ``self`` with respect to a chart.
        
        INPUT:
        
        - ``chart`` -- (default: None) chart with respect to which the 
          Christoffel symbolds are required; if none is provided, the 
          manifold's default chart is assumed.
          
        OUTPUT:
        
        - the set of Christoffel symbols in the given chart, as an instance of
          :class:`CompWithSym`
          
        EXAMPLES:
        
        Christoffel symbols of the flat metric on `\RR^3` with respect to 
        spherical coordinates::
        
            sage: m = Manifold(3, 'R3', r'\RR^3', start_index=1)
            sage: X.<r,th,ph> = m.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi')
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, r^2*sin(th)^2
            sage: g.view()  # the standard flat metric expressed in spherical coordinates
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: Gam = g.christoffel() ; Gam
            3-indices components w.r.t. the coordinate frame (R3, (d/dr,d/dth,d/dph)), with symmetry on the index positions (1, 2)
            sage: print type(Gam)
            <class 'sage.geometry.manifolds.component.CompWithSym'>
            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: Gam[1,2,2]
            -r
            sage: Gam[2,1,2]
            1/r
            sage: Gam[3,1,3]
            1/r
            sage: Gam[3,2,3]
            cos(th)/sin(th)
            sage: Gam[2,3,3]
            -cos(th)*sin(th)

        
        """
        if chart is None:
            frame = self.domain.def_chart.frame
        else:
            frame = chart.frame
        return self.connection().coef(frame)
          
    def riemann(self, frame=None, name=None, latex_name=None):
        r""" 
        Return the Riemann curvature tensor associated with the metric.

        This method is actually a shortcut for ``self.connection().riemann()``
        
        The Riemann curvature tensor is the tensor field `R` of type (1,3) 
        defined by

        .. MATH::
            
            R(\omega, u, v, w) = \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:
        
        - ``frame`` -- (default: None) vector frame in which the computation 
          must be performed; if none is provided, the computation is performed 
          in a frame in which the metric components are known, privileging the 
          domain's default frame.
        - ``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:`TensorField`
        
        EXAMPLES:

        Riemann tensor of the standard metric on the 2-sphere::
        
            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')
            sage: a = var('a') # the sphere radius 
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
            sage: g.view() # standard metric on the 2-sphere of radius a:
            g = a^2 dth*dth + a^2*sin(th)^2 dph*dph
            sage: g.riemann()
            tensor field 'Riem(g)' of type (1,3) on the 2-dimensional manifold 'S^2'
            sage: g.riemann()[:]
            [[[[0, 0], [0, 0]], [[0, sin(th)^2], [-sin(th)^2, 0]]],
             [[[0, (cos(th)^2 - 1)/sin(th)^2], [1, 0]], [[0, 0], [0, 0]]]]
             
        In dimension 2, the Riemann tensor can be expressed entirely in terms of
        the Ricci scalar `r`:

        .. MATH::
            
            R^i_{\ \, jlk} = \frac{r}{2} \left( \delta^i_{\ \, k} g_{jl}
                - \delta^i_{\ \, l} g_{jk} \right)
        
        This formula can be checked here, with the r.h.s. rewritten as 
        `-r g_{j[k} \delta^i_{\ \, l]}`::
        
            sage: g.riemann() == -g.ricci_scalar()*(g*IdentityMap(m)).antisymmetrize([2,3])
            True
        
        """
        return self.connection().riemann(frame, name, latex_name)

        
    def ricci(self, frame=None, name=None, latex_name=None):
        r""" 
        Return the Ricci tensor associated with the metric.
        
        This method is actually a shortcut for ``self.connection().ricci()``
                
        The Ricci tensor is the tensor field `Ric` of type (0,2) 
        defined from the Riemann curvature tensor `R` by 

        .. MATH::
            
            Ric(u, v) = R(e^i, u, e_i, v)
        
        for any vector fields `u` and `v`, `(e_i)` being any vector frame and
        `(e^i)` the dual coframe. 

        INPUT:
        
        - ``frame`` -- (default: None) vector frame in which the computation 
          must be performed; if none is provided, the computation is performed 
          in a frame in which the metric components are known, privileging the 
          domain's default frame.
        - ``name`` -- (default: None) name given to the Ricci tensor; 
          if none, it is set to "Ric(g)", where "g" is the metric's name
        - ``latex_name`` -- (default: None) LaTeX symbol to denote the 
          Ricci tensor; if none, it is set to "\\mathrm{Ric}(g)", where "g" 
          is the metric's name
          
        OUTPUT:
        
        - the Ricci tensor `Ric`, as an instance of :class:`SymBilinFormField`
        
        EXAMPLES:
        
        Ricci tensor of the standard metric on the 2-sphere::
        
            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')
            sage: a = var('a') # the sphere radius 
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
            sage: g.view() # standard metric on the 2-sphere of radius a:
            g = a^2 dth*dth + a^2*sin(th)^2 dph*dph
            sage: g.ricci()
            field of symmetric bilinear forms 'Ric(g)' on the 2-dimensional manifold 'S^2'
            sage: g.ricci()[:]
            [        1         0]
            [        0 sin(th)^2]
            sage: g.ricci() == a^(-2) * g
            True

        """
        return self.connection().ricci(frame, name, latex_name)
    
        
    def ricci_scalar(self, frame=None, name=None, latex_name=None):
        r""" 
        Return the Ricci scalar associated with the metric.
        
        The Ricci scalar is the scalar field `r` defined from the Ricci tensor 
        `Ric` and the metric tensor `g` by 

        .. MATH::
            
            r = g^{ij} Ric_{ij}
        

        INPUT:
        
        - ``frame`` -- (default: None) vector frame in which the computation 
          must be performed; if none is provided, the computation is performed 
          in a frame in which the metric components are known, privileging 
          the domain's default frame.
        - ``name`` -- (default: None) name given to the Ricci scalar; 
          if none, it is set to "r(g)", where "g" is the metric's name
        - ``latex_name`` -- (default: None) LaTeX symbol to denote the 
          Ricci scalar; if none, it is set to "\\mathrm{r}(g)", where "g" 
          is the metric's name

        OUTPUT:
        
        - the Ricci scalar `r`, as an instance of :class:`ScalarField`

        EXAMPLES:
        
        Ricci scalar of the standard metric on the 2-sphere::
        
            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')
            sage: a = var('a') # the sphere radius 
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2] = a^2, a^2*sin(th)^2
            sage: g.view() # standard metric on the 2-sphere of radius a:
            g = a^2 dth*dth + a^2*sin(th)^2 dph*dph
            sage: g.ricci_scalar()
            scalar field 'r(g)' on the 2-dimensional manifold 'S^2'
            sage: g.ricci_scalar().expr()
            2/a^2

        """
        return self.connection().ricci_scalar(frame, name, latex_name)


    def weyl(self, name=None, latex_name=None):
        r""" 
        Return the Weyl conformal tensor associated with the metric.
                        
        The Weyl conformal tensor is the tensor field `C` of type (1,3) 
        defined as the trace-free part of the Riemann curvature tensor `R`

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

        OUTPUT:
        
        - the Weyl conformal tensor `C`, as an instance of :class:`TensorField`
        
        EXAMPLES:
        
        Checking that the Weyl tensor identically vanishes on a 3-dimensional 
        manifold, for instance the hyperbolic space `H^3`::
        
            sage: m = Manifold(3, 'H^3', start_index=1)
            sage: X.<rh,th,ph> = m.chart(r'rh:[0,+oo):\rho th:[0,pi]:\theta  ph:[0,2*pi):\phi')
            sage: g = Metric(m, 'g')
            sage: b = var('b')                                                        
            sage: g[1,1], g[2,2], g[3,3] = b^2, (b*sinh(rh))^2, (b*sinh(rh)*sin(th))^2
            sage: g.view()  # standard metric on H^3:
            g = b^2 drh*drh + b^2*sinh(rh)^2 dth*dth + b^2*sin(th)^2*sinh(rh)^2 dph*dph
            sage: C = g.weyl() ; C
            tensor field 'C(g)' of type (1,3) on the 3-dimensional manifold 'H^3'
            sage: C == 0 
            True

        """
        from rank2field import IdentityMap
        if self._weyl is None:
            n = self.manifold.dim
            if n < 3:
                raise ValueError("The Weyl tensor is not defined for a " + 
                                 "manifold of dimension n <= 2.")
            delta = IdentityMap(self.domain)
            riem = self.riemann()
            ric = self.ricci()
            rscal = self.ricci_scalar()
            # First index of the Ricci tensor raised with the metric
            ricup = ric.up(self, 0) 
            # The identity map is expressed in a frame in which the Riemann 
            # tensor is known
            delta.comp(riem.pick_a_frame())
            aux = self*ricup + ric*delta - rscal/(n-1)* self*delta
            self._weyl = riem + 2/(n-2)* aux.antisymmetrize([2,3]) 
            if name is None:
                self._weyl.name = "C(" + self.name + ")"
            else:
                self._weyl.name = name
            if latex_name is None:
                self._weyl.latex_name = r"\mathrm{C}\left(" + self.latex_name \
                                        + r"\right)"
            else:
                self._weyl.latex_name = latex_name
        return self._weyl
            
    def determinant(self, frame=None):
        r"""
        Determinant of the metric components in the specified frame.
        
        INPUT:
        
        - ``frame`` -- (default: None) vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the domain's default frame is used. If a chart is 
          provided, the associated coordinate frame is used
          
        OUTPUT:
        
        - the determinant `\det (g_{ij})`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X.<x,y> = M.chart('x y')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.determinant()  # determinant in M's default frame
            sage: s.expr()
            -x^2*y^2 - (x + 1)*y + x + 1

        Determinant in a frame different from the default's one::
            
            sage: Y.<u,v> = M.chart('u v')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()
            coordinate change from chart (M, (u, v)) to chart (M, (x, y))                 
            sage: g.comp(Y.frame)[:, Y]
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.determinant(Y.frame).expr()
            -1/4*x^2*y^2 - 1/4*(x + 1)*y + 1/4*x + 1/4
            sage: g.determinant(Y.frame).expr(Y)
            -1/64*u^4 - 1/64*v^4 + 1/32*(u^2 + 2)*v^2 - 1/16*u^2 + 1/4*v + 1/4

        A chart can be passed instead of a frame::
        
            sage: g.determinant(X) is g.determinant(X.frame)
            True
            sage: g.determinant(Y) is g.determinant(Y.frame)
            True

        The metric determinant depends on the frame::
        
            sage: g.determinant(X.frame) == g.determinant(Y.frame)
            False
        
        """
        from sage.matrix.constructor import matrix
        from scalarfield import ScalarField
        from utilities import simple_determinant, simplify_chain
        manif = self.manifold
        dom = self.domain
        if frame is None:
            frame = dom.def_frame
        if frame in dom.atlas:   
            # frame is actually a chart and is changed to the associated 
            # coordinate frame:
            frame = frame.frame
        if frame not in self._determinants:
            # a new computation is necessary
            resu = ScalarField(dom)
            gg = self.comp(frame)
            i1 = manif.sindex
            for chart in gg[[i1, i1]].express:
                gm = matrix( [[ gg[i, j, chart].express 
                            for j in manif.irange()] for i in manif.irange()] )
                detgm = simplify_chain(simple_determinant(gm))
                resu.add_expr(detgm, chart=chart)
            self._determinants[frame] = resu
        return self._determinants[frame]

    def sqrt_abs_det(self, frame=None):
        r"""
        Square root of the absolute value of the determinant of the metric 
        components in the specified frame.
        
        INPUT:
        
        - ``frame`` -- (default: None) vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the domain's default frame is used. If a chart is 
          provided, the associated coordinate frame is used
          
        OUTPUT:
        
        -  `\sqrt{|\det (g_{ij})|}`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Standard metric in the Euclidean space `\RR^3` with spherical 
        coordinates::
        
            sage: m = Manifold(3, 'M', 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 = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
            sage: g.view()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: g.sqrt_abs_det().expr()
            r^2*sin(th)
            
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X.<x,y> = M.chart('x y')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.sqrt_abs_det() ; s
            scalar field on the 2-dimensional manifold 'M'
            sage: s.expr()
            sqrt(-x^2*y^2 - (x + 1)*y + x + 1)

        Determinant in a frame different from the default's one::
            
            sage: Y.<u,v> = M.chart('u v')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()
            coordinate change from chart (M, (u, v)) to chart (M, (x, y))                    
            sage: g.comp(Y.frame)[:, Y]
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.sqrt_abs_det(Y.frame).expr()
            1/2*sqrt(-x^2*y^2 - (x + 1)*y + x + 1)
            sage: g.sqrt_abs_det(Y.frame).expr(Y)
            1/8*sqrt(-u^4 - v^4 + 2*(u^2 + 2)*v^2 - 4*u^2 + 16*v + 16)

        A chart can be passed instead of a frame::
        
            sage: g.sqrt_abs_det(Y) is g.sqrt_abs_det(Y.frame)
            True

        The metric determinant depends on the frame::
        
            sage: g.sqrt_abs_det(X.frame) == g.sqrt_abs_det(Y.frame) 
            False

        """
        from sage.functions.other import sqrt
        from scalarfield import ScalarField
        from utilities import simplify_chain
        manif = self.manifold
        dom = self.domain
        if frame is None:
            frame = dom.def_frame
        if frame in dom.atlas:   
            # frame is actually a chart and is changed to the associated 
            # coordinate frame:
            frame = frame.frame
        if frame not in self._sqrt_abs_dets:
            # a new computation is necessary
            detg = self.determinant(frame)
            resu = ScalarField(dom)
            for chart in detg.express:
                x = self._indic_signat * detg.express[chart].express # |g|
                x = simplify_chain(sqrt(x))
                resu.add_expr(x, chart=chart)
            self._sqrt_abs_dets[frame] = resu
        return self._sqrt_abs_dets[frame]


    def volume_form(self, contra=0):
        r"""
        Volume form (Levi-Civita tensor) `\epsilon` associated with the metric.
        
        This assumes that the manifold is orientable. 
        
        The volume form `\epsilon` is a `n`-form (`n` being the manifold's 
        dimension) such that for any vector basis `(e_i)` that is orthonormal
        with respect to the metric, 
        
        .. MATH::
            
            \epsilon(e_1,\ldots,e_n) = \pm 1 

        There are only two such `n`-forms, which are opposite of each other. 
        The volume form `\epsilon` is selected such that the domain's default 
        frame is right-handed with respect to it. 
        
        INPUT:
        
        - ``contra`` -- (default: 0) number of contravariant indices of the
          returned tensor
        
        OUTPUT:
        
        - if ``contra = 0`` (default value): the volume `n`-form `\epsilon`, as 
          an instance of :class:`DiffForm`
        - if ``contra = k``, with `1\leq k \leq n`, the tensor field of type 
          (k,n-k) formed from `\epsilon` by raising the first k indices with the 
          metric (see method :meth:`TensorField.up`); the output is then an
          instance of :class:`TensorField`, with the appropriate antisymmetries
       
        EXAMPLES:
        
        Volume form on `\RR^3` with spherical coordinates::
        
            sage: m = Manifold(3, 'M', 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 = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
            sage: g.view()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: eps = g.volume_form() ; eps
            3-form 'eps_g' on the 3-dimensional manifold 'M'
            sage: eps.view()
            eps_g = r^2*sin(th) dr/\dth/\dph
            sage: eps[[1,2,3]] == g.sqrt_abs_det()
            True
            sage: latex(eps)
            \epsilon_{g}
            
            
        The tensor field of components `\epsilon^i_{\ \, jk}` (``contra=1``)::
        
            sage: eps1 = g.volume_form(1) ; eps1
            tensor field of type (1,2) on the 3-dimensional manifold 'M'
            sage: eps1.symmetries()
            no symmetry;  antisymmetry: (1, 2)
            sage: eps1[:]
            [[[0, 0, 0], [0, 0, r^2*sin(th)], [0, -r^2*sin(th), 0]],
             [[0, 0, -sin(th)], [0, 0, 0], [sin(th), 0, 0]],
             [[0, 1/sin(th), 0], [-1/sin(th), 0, 0], [0, 0, 0]]]
            
        The tensor field of components `\epsilon^{ij}_{\ \ k}` (``contra=2``)::
        
            sage: eps2 = g.volume_form(2) ; eps2
            tensor field of type (2,1) on the 3-dimensional manifold 'M'
            sage: eps2.symmetries()
            no symmetry;  antisymmetry: (0, 1)
            sage: eps2[:]
            [[[0, 0, 0], [0, 0, sin(th)], [0, -1/sin(th), 0]],
             [[0, 0, -sin(th)], [0, 0, 0], [1/(r^2*sin(th)), 0, 0]],
             [[0, 1/sin(th), 0], [-1/(r^2*sin(th)), 0, 0], [0, 0, 0]]]
            
        The tensor field of components `\epsilon^{ijk}` (``contra=3``)::
        
            sage: eps3 = g.volume_form(3) ; eps3
            tensor field of type (3,0) on the 3-dimensional manifold 'M'
            sage: eps3.symmetries()
            no symmetry;  antisymmetry: (0, 1, 2)
            sage: eps3[:]
            [[[0, 0, 0], [0, 0, 1/(r^2*sin(th))], [0, -1/(r^2*sin(th)), 0]],
             [[0, 0, -1/(r^2*sin(th))], [0, 0, 0], [1/(r^2*sin(th)), 0, 0]],
             [[0, 1/(r^2*sin(th)), 0], [-1/(r^2*sin(th)), 0, 0], [0, 0, 0]]]
            sage: eps3[1,2,3]
            1/(r^2*sin(th))
            sage: eps3[[1,2,3]] * g.sqrt_abs_det() == 1
            True
        
        """
        if self._vol_forms == []:
            # a new computation is necessary
            manif = self.manifold
            dom = self.domain
            ndim = manif.dim
            eps = DiffForm(dom, ndim, name='eps_'+self.name, 
                           latex_name=r'\epsilon_{'+self.latex_name+r'}')
            ind = tuple(range(manif.sindex, manif.sindex+ndim))
            eps[[ind]] = self.sqrt_abs_det(dom.def_frame)
            self._vol_forms.append(eps)  # Levi-Civita tensor constructed
            # Tensors related to the Levi-Civita one by index rising:
            for k in range(1, ndim+1):
                epskm1 = self._vol_forms[k-1]
                epsk = epskm1.up(self, k-1)
                if k > 1:
                    # restoring the antisymmetry after the up operation: 
                    epsk = epsk.antisymmetrize(range(k)) 
                self._vol_forms.append(epsk)
        return self._vol_forms[contra]
示例#30
0
 def __init__(self, domain, name=None, latex_name=None):
     TensorField.__init__(self, domain, 1, 1, name, latex_name)
示例#31
0
 def __init__(self, domain, name=None, latex_name=None):
     TensorField.__init__(self, domain, 0, 2, name, latex_name, sym=(0,1))
示例#32
0
 def __init__(self, manifold, name=None, latex_name=None):
     TensorField.__init__(self, manifold, 1, 0, name, latex_name)
     self._init_dependencies()
示例#33
0
 def __init__(self, domain, name=None, latex_name=None):
     TensorField.__init__(self, domain, 0, 2, name, latex_name, sym=(0, 1))
示例#34
0
 def _del_derived(self):
     r"""
     Delete the derived quantities
     """
     TensorField._del_derived(self)
     self._exterior_derivative = None
示例#35
0
 def _init_derived(self):
     r"""
     Initialize the derived quantities
     """
     TensorField._init_derived(self)
     self._inverse = None  # inverse not set yet
示例#36
0
 def _init_derived(self):
     r"""
     Initialize the derived quantities
     """
     TensorField._init_derived(self)
     self._inverse = None  # inverse not set yet
示例#37
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
示例#38
0
 def __init__(self, domain, name=None, latex_name=None) :
     TensorField.__init__(self, domain, 1, 0, name, latex_name)
     self._init_dependencies()
示例#39
0
 def _init_derived(self):
     r"""
     Initialize the derived quantities
     """
     TensorField._init_derived(self)  
     self._exterior_derivative = None
示例#40
0
 def _del_derived(self):
     r"""
     Delete the derived quantities
     """
     TensorField._del_derived(self)
     self._del_dependencies()
示例#41
0
 def __init__(self, manifold, name=None, latex_name=None) :
     TensorField.__init__(self, manifold, 1, 0, name, latex_name)
     self._init_dependencies()
示例#42
0
 def __init__(self, manifold, name=None, latex_name=None):
     TensorField.__init__(self, manifold, 0, 2, name, latex_name, sym=(0,1))