def hodge_star(self, metric): r""" Compute the Hodge dual of the differential form. If ``self`` is a `p`-form `A`, its Hodge dual is the `(n-p)`-form `*A` defined by (`n` being the manifold's dimension) .. MATH:: *A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A_{k_1\ldots k_p} \epsilon^{k_1\ldots k_p}_{\qquad\ i_1\ldots i_{n-p}} where `\epsilon` is the volume form associated with some pseudo-Riemannian metric `g` on the manifold, and the indices `k_1,\ldots, k_p` are raised with `g`. INPUT: - ``metric``: the pseudo-Riemannian metric `g` defining the Hodge dual, via the volume form `\epsilon`; must be an instance of :class:`~sage.geometry.manifolds.metric.Metric` OUTPUT: - the `(n-p)`-form `*A` EXAMPLES: """ from sage.functions.other import factorial from sage.tensor.modules.format_utilities import format_unop_txt, \ format_unop_latex p = self._tensor_rank eps = metric.volume_form(p) args = range(p) + [eps] + range(p) resu = self.contract(*args) if p > 1: resu = resu / factorial(p) resu.set_name(name=format_unop_txt('*', self._name), latex_name=format_unop_latex(r'\star ', self._latex_name)) return resu
def exterior_der(self): r""" Compute the exterior derivative of the differential form. OUTPUT: - the exterior derivative of ``self``. EXAMPLE: """ from sage.tensor.modules.format_utilities import format_unop_txt, \ format_unop_latex if self._exterior_derivative is None: vmodule = self._vmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) resu = vmodule.alternating_form(self._tensor_rank + 1, name=rname, latex_name=rlname) for dom, rst in self._restrictions.iteritems(): resu._restrictions[dom] = rst.exterior_der() self._exterior_derivative = resu return self._exterior_derivative
def differential(self): r""" Return the differential of ``self``. OUTPUT: - a :class:`~sage.manifolds.differentiable.diff_form.DiffForm` (or of :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal` if the scalar field's domain is parallelizable) representing the 1-form that is the differential of the scalar field EXAMPLES: Differential of a scalar field on a 3-dimensional differentiable manifold:: sage: M = Manifold(3, 'M') sage: c_xyz.<x,y,z> = M.chart() sage: f = M.scalar_field(cos(x)*z^3 + exp(y)*z^2, name='f') sage: df = f.differential() ; df 1-form df on the 3-dimensional differentiable manifold M sage: df.display() df = -z^3*sin(x) dx + z^2*e^y dy + (3*z^2*cos(x) + 2*z*e^y) dz sage: latex(df) \mathrm{d}f sage: df.parent() Free module /\^1(M) of 1-forms on the 3-dimensional differentiable manifold M The result is cached, i.e. is not recomputed unless ``f`` is changed:: sage: f.differential() is df True Since the exterior derivative of a scalar field (considered a 0-form) is nothing but its differential, ``exterior_derivative()`` is an alias of ``differential()``:: sage: df = f.exterior_derivative() ; df 1-form df on the 3-dimensional differentiable manifold M sage: df.display() df = -z^3*sin(x) dx + z^2*e^y dy + (3*z^2*cos(x) + 2*z*e^y) dz sage: latex(df) \mathrm{d}f One may also use the global function :func:`~sage.manifolds.utilities.exterior_derivative` or its alias :func:`~sage.manifolds.utilities.xder` instead of the method ``exterior_derivative()``:: sage: from sage.manifolds.utilities import xder sage: xder(f) is f.exterior_derivative() True Differential computed on a chart that is not the default one:: sage: c_uvw.<u,v,w> = M.chart() sage: g = M.scalar_field(u*v^2*w^3, c_uvw, name='g') sage: dg = g.differential() ; dg 1-form dg on the 3-dimensional differentiable manifold M sage: dg._components {Coordinate frame (M, (d/du,d/dv,d/dw)): 1-index components w.r.t. Coordinate frame (M, (d/du,d/dv,d/dw))} sage: dg.comp(c_uvw.frame())[:, c_uvw] [v^2*w^3, 2*u*v*w^3, 3*u*v^2*w^2] sage: dg.display(c_uvw.frame(), c_uvw) dg = v^2*w^3 du + 2*u*v*w^3 dv + 3*u*v^2*w^2 dw The exterior derivative is nilpotent:: sage: ddf = df.exterior_derivative() ; ddf 2-form ddf on the 3-dimensional differentiable manifold M sage: ddf == 0 True sage: ddf[:] # for the incredule [0 0 0] [0 0 0] [0 0 0] sage: ddg = dg.exterior_derivative() ; ddg 2-form ddg on the 3-dimensional differentiable manifold M sage: ddg == 0 True """ from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) if self._differential is None: # A new computation is necessary: rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) self._differential = self._domain.one_form(name=rname, latex_name=rlname) if self._is_zero: for chart in self._domain._atlas: self._differential.add_comp(chart._frame) # since a newly # created set of components is zero else: for chart, func in self._express.items(): diff_func = self._differential.add_comp(chart._frame) for i in self._manifold.irange(): diff_func[i, chart] = func.diff(i) return self._differential
def differential(self): r""" Return the differential of ``self``. OUTPUT: - a :class:`~sage.manifolds.differentiable.diff_form.DiffForm` (or of :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal` if the scalar field's domain is parallelizable) representing the 1-form that is the differential of the scalar field EXAMPLES: Differential of a scalar field on a 3-dimensional differentiable manifold:: sage: M = Manifold(3, 'M') sage: c_xyz.<x,y,z> = M.chart() sage: f = M.scalar_field(cos(x)*z^3 + exp(y)*z^2, name='f') sage: df = f.differential() ; df 1-form df on the 3-dimensional differentiable manifold M sage: df.display() df = -z^3*sin(x) dx + z^2*e^y dy + (3*z^2*cos(x) + 2*z*e^y) dz sage: latex(df) \mathrm{d}f sage: df.parent() Free module Omega^1(M) of 1-forms on the 3-dimensional differentiable manifold M The result is cached, i.e. is not recomputed unless ``f`` is changed:: sage: f.differential() is df True Since the exterior derivative of a scalar field (considered a 0-form) is nothing but its differential, ``exterior_derivative()`` is an alias of ``differential()``:: sage: df = f.exterior_derivative() ; df 1-form df on the 3-dimensional differentiable manifold M sage: df.display() df = -z^3*sin(x) dx + z^2*e^y dy + (3*z^2*cos(x) + 2*z*e^y) dz sage: latex(df) \mathrm{d}f One may also use the function :func:`~sage.manifolds.utilities.exterior_derivative` or its alias :func:`~sage.manifolds.utilities.xder` instead of the method ``exterior_derivative()``:: sage: from sage.manifolds.utilities import xder sage: xder(f) is f.exterior_derivative() True Differential computed on a chart that is not the default one:: sage: c_uvw.<u,v,w> = M.chart() sage: g = M.scalar_field(u*v^2*w^3, c_uvw, name='g') sage: dg = g.differential() ; dg 1-form dg on the 3-dimensional differentiable manifold M sage: dg._components {Coordinate frame (M, (d/du,d/dv,d/dw)): 1-index components w.r.t. Coordinate frame (M, (d/du,d/dv,d/dw))} sage: dg.comp(c_uvw.frame())[:, c_uvw] [v^2*w^3, 2*u*v*w^3, 3*u*v^2*w^2] sage: dg.display(c_uvw.frame(), c_uvw) dg = v^2*w^3 du + 2*u*v*w^3 dv + 3*u*v^2*w^2 dw The exterior derivative is nilpotent:: sage: ddf = df.exterior_derivative() ; ddf 2-form ddf on the 3-dimensional differentiable manifold M sage: ddf == 0 True sage: ddf[:] # for the incredule [0 0 0] [0 0 0] [0 0 0] sage: ddg = dg.exterior_derivative() ; ddg 2-form ddg on the 3-dimensional differentiable manifold M sage: ddg == 0 True """ from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) if self._differential is None: # A new computation is necessary: rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) self._differential = self._domain.one_form(name=rname, latex_name=rlname) if self._is_zero: for chart in self._domain._atlas: self._differential.add_comp(chart._frame) # since a newly # created set of components is zero else: for chart, func in self._express.items(): diff_func = self._differential.add_comp(chart._frame) for i in self._manifold.irange(): diff_func[i, chart] = func.diff(i) return self._differential
def exterior_derivative(self): r""" Compute the exterior derivative of ``self``. OUTPUT: - instance of :class:`DiffForm` representing the exterior derivative of the differential form EXAMPLES: Exterior derivative of a 1-form on the 2-sphere:: sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole sage: V = M.open_subset('V') # complement of the South pole sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: xy_to_uv = c_xy.transition_map(c_uv, (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: uv_to_xy = xy_to_uv.inverse() sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() The 1-form:: sage: a = M.diff_form(1, name='a') sage: a[e_xy,:] = -y^2, x^2 sage: a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: a.display(e_xy) a = -y^2 dx + x^2 dy sage: a.display(e_uv) a = -(2*u^3*v - u^2*v^2 + v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du + (u^4 - u^2*v^2 + 2*u*v^3)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv Its exterior derivative:: sage: da = a.exterior_derivative(); da 2-form da on the 2-dimensional differentiable manifold M sage: da.display(e_xy) da = (2*x + 2*y) dx/\dy sage: da.display(e_uv) da = -2*(u + v)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) du/\dv The result is cached, i.e. is not recomputed unless ``a`` is changed:: sage: a.exterior_derivative() is da True Instead of invoking the method :meth:`exterior_derivative`, one may use the global function :func:`~sage.manifolds.utilities.exterior_derivative` or its alias :func:`~sage.manifolds.utilities.xder`:: sage: from sage.manifolds.utilities import xder sage: xder(a) is a.exterior_derivative() True Let us check Cartan's identity:: sage: v = M.vector_field(name='v') sage: v[e_xy, :] = -y, x sage: v.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: a.lie_der(v) == v.contract(xder(a)) + xder(a(v)) # long time True """ from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) vmodule = self._vmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) resu = vmodule.alternating_form(self._tensor_rank + 1, name=rname, latex_name=rlname) for dom, rst in self._restrictions.items(): resu._restrictions[dom] = rst.exterior_derivative() return resu
def exterior_derivative(self): r""" Compute the exterior derivative of ``self``. OUTPUT: - a :class:`DiffFormParal` representing the exterior derivative of the differential form EXAMPLES: Exterior derivative of a 1-form on a 4-dimensional manifold:: sage: M = Manifold(4, 'M') sage: c_txyz.<t,x,y,z> = M.chart() sage: a = M.one_form('A') sage: a[:] = (t*x*y*z, z*y**2, x*z**2, x**2 + y**2) sage: da = a.exterior_derivative() ; da 2-form dA on the 4-dimensional differentiable manifold M sage: da.display() dA = -t*y*z dt/\dx - t*x*z dt/\dy - t*x*y dt/\dz + (-2*y*z + z^2) dx/\dy + (-y^2 + 2*x) dx/\dz + (-2*x*z + 2*y) dy/\dz sage: latex(da) \mathrm{d}A The result is cached, i.e. is not recomputed unless ``a`` is changed:: sage: a.exterior_derivative() is da True Instead of invoking the method :meth:`exterior_derivative`, one may use the global function :func:`~sage.manifolds.utilities.exterior_derivative` or its alias :func:`~sage.manifolds.utilities.xder`:: sage: from sage.manifolds.utilities import xder sage: xder(a) is a.exterior_derivative() True The exterior derivative is nilpotent:: sage: dda = da.exterior_derivative() ; dda 3-form ddA on the 4-dimensional differentiable manifold M sage: dda.display() ddA = 0 sage: dda == 0 True Let us check Cartan's identity:: sage: v = M.vector_field(name='v') sage: v[:] = -y, x, t, z sage: a.lie_der(v) == v.contract(xder(a)) + xder(a(v)) # long time True """ from sage.calculus.functional import diff from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) from sage.tensor.modules.comp import CompFullyAntiSym from sage.manifolds.differentiable.vectorframe import CoordFrame fmodule = self._fmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) resu = fmodule.alternating_form(self._tensor_rank + 1, name=rname, latex_name=rlname) # 1/ List of all coordinate frames in which the components of self # are known coord_frames = [] for frame in self._components: if isinstance(frame, CoordFrame): coord_frames.append(frame) if not coord_frames: # A coordinate frame is searched, at the price of a change of # frame, privileging the frame of the domain's default chart dom = self._domain def_coordf = dom._def_chart._frame for frame in self._components: if (frame, def_coordf) in dom._frame_changes: self.comp(def_coordf, from_basis=frame) coord_frames = [def_coordf] break if not coord_frames: for chart in dom._atlas: if chart != dom._def_chart: # the case def_chart is # treated above coordf = chart._frame for frame in self._components: if (frame, coordf) in dom._frame_changes: self.comp(coordf, from_basis=frame) coord_frames[coordf] break if coord_frames: break # 2/ The computation: for frame in coord_frames: chart = frame._chart sc = self._components[frame] dc = CompFullyAntiSym(fmodule._ring, frame, self._tensor_rank + 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) for ind, val in sc._comp.items(): for i in fmodule.irange(): ind_d = (i, ) + ind if len(ind_d) == len(set(ind_d)): # all indices are different dc[[ind_d]] += \ val.coord_function(chart).diff(i).scalar_field() resu._components[frame] = dc return resu
def exterior_derivative(self): r""" Compute the exterior derivative of ``self``. OUTPUT: - instance of :class:`DiffForm` representing the exterior derivative of the differential form EXAMPLES: Exterior derivative of a 1-form on the 2-sphere:: sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2 sage: U = M.open_subset('U') # complement of the North pole sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole sage: V = M.open_subset('V') # complement of the South pole sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole sage: M.declare_union(U,V) # S^2 is the union of U and V sage: xy_to_uv = c_xy.transition_map(c_uv, (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: uv_to_xy = xy_to_uv.inverse() sage: e_xy = c_xy.frame(); e_uv = c_uv.frame() The 1-form:: sage: a = M.diff_form(1, name='a') sage: a[e_xy,:] = -y^2, x^2 sage: a.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: a.display(e_xy) a = -y^2 dx + x^2 dy sage: a.display(e_uv) a = -(2*u^3*v - u^2*v^2 + v^4)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) du + (u^4 - u^2*v^2 + 2*u*v^3)/(u^8 + 4*u^6*v^2 + 6*u^4*v^4 + 4*u^2*v^6 + v^8) dv Its exterior derivative:: sage: da = a.exterior_derivative(); da 2-form da on the 2-dimensional differentiable manifold M sage: da.display(e_xy) da = (2*x + 2*y) dx/\dy sage: da.display(e_uv) da = -2*(u + v)/(u^6 + 3*u^4*v^2 + 3*u^2*v^4 + v^6) du/\dv The result is cached, i.e. is not recomputed unless ``a`` is changed:: sage: a.exterior_derivative() is da True Instead of invoking the method :meth:`exterior_derivative`, one may use the global function :func:`~sage.manifolds.utilities.exterior_derivative` or its alias :func:`~sage.manifolds.utilities.xder`:: sage: from sage.manifolds.utilities import xder sage: xder(a) is a.exterior_derivative() True Let us check Cartan's identity:: sage: v = M.vector_field(name='v') sage: v[e_xy, :] = -y, x sage: v.add_comp_by_continuation(e_uv, U.intersection(V), c_uv) sage: a.lie_der(v) == v.contract(xder(a)) + xder(a(v)) # long time True """ from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) vmodule = self._vmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) resu = vmodule.alternating_form(self._tensor_rank+1, name=rname, latex_name=rlname) for dom, rst in self._restrictions.items(): resu._restrictions[dom] = rst.exterior_derivative() return resu
def exterior_derivative(self): r""" Compute the exterior derivative of ``self``. OUTPUT: - a :class:`DiffFormParal` representing the exterior derivative of the differential form EXAMPLES: Exterior derivative of a 1-form on a 4-dimensional manifold:: sage: M = Manifold(4, 'M') sage: c_txyz.<t,x,y,z> = M.chart() sage: a = M.one_form('A') sage: a[:] = (t*x*y*z, z*y**2, x*z**2, x**2 + y**2) sage: da = a.exterior_derivative() ; da 2-form dA on the 4-dimensional differentiable manifold M sage: da.display() dA = -t*y*z dt/\dx - t*x*z dt/\dy - t*x*y dt/\dz + (-2*y*z + z^2) dx/\dy + (-y^2 + 2*x) dx/\dz + (-2*x*z + 2*y) dy/\dz sage: latex(da) \mathrm{d}A The result is cached, i.e. is not recomputed unless ``a`` is changed:: sage: a.exterior_derivative() is da True Instead of invoking the method :meth:`exterior_derivative`, one may use the global function :func:`~sage.manifolds.utilities.exterior_derivative` or its alias :func:`~sage.manifolds.utilities.xder`:: sage: from sage.manifolds.utilities import xder sage: xder(a) is a.exterior_derivative() True The exterior derivative is nilpotent:: sage: dda = da.exterior_derivative() ; dda 3-form ddA on the 4-dimensional differentiable manifold M sage: dda.display() ddA = 0 sage: dda == 0 True Let us check Cartan's identity:: sage: v = M.vector_field(name='v') sage: v[:] = -y, x, t, z sage: a.lie_der(v) == v.contract(xder(a)) + xder(a(v)) # long time True """ from sage.calculus.functional import diff from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) from sage.tensor.modules.comp import CompFullyAntiSym from sage.manifolds.differentiable.vectorframe import CoordFrame fmodule = self._fmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) resu = fmodule.alternating_form(self._tensor_rank + 1, name=rname, latex_name=rlname) # 1/ List of all coordinate frames in which the components of self # are known coord_frames = [] for frame in self._components: if isinstance(frame, CoordFrame): coord_frames.append(frame) if not coord_frames: # A coordinate frame is searched, at the price of a change of # frame, privileging the frame of the domain's default chart dom = self._domain def_coordf = dom._def_chart._frame for frame in self._components: if (frame, def_coordf) in dom._frame_changes: self.comp(def_coordf, from_basis=frame) coord_frames = [def_coordf] break if not coord_frames: for chart in dom._atlas: if chart != dom._def_chart: # the case def_chart is # treated above coordf = chart._frame for frame in self._components: if (frame, coordf) in dom._frame_changes: self.comp(coordf, from_basis=frame) coord_frames[coordf] break if coord_frames: break # 2/ The computation: for frame in coord_frames: chart = frame._chart sc = self._components[frame] dc = CompFullyAntiSym(fmodule._ring, frame, self._tensor_rank+1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) for ind, val in sc._comp.items(): for i in fmodule.irange(): ind_d = (i,) + ind if len(ind_d) == len(set(ind_d)): # all indices are different dc[[ind_d]] += \ val.coord_function(chart).diff(i).scalar_field() resu._components[frame] = dc return resu
def exterior_derivative(self): r""" Compute the exterior derivative of ``self``. More precisely, the *exterior derivative* on `\Omega^k(M,\varphi)` is a linear map .. MATH:: \mathrm{d}_{k} : \Omega^k(M,\varphi) \to \Omega^{k+1}(M,\varphi), where `\Omega^k(M,\varphi)` denotes the space of differential forms of degree `k` along `\varphi` (see :meth:`~sage.manifolds.differentiable.diff_form.DiffForm.exterior_derivative` for further information). By linear extension, this induces a map on `\Omega^*(M,\varphi)`: .. MATH:: \mathrm{d}: \Omega^*(M,\varphi) \to \Omega^*(M,\varphi). OUTPUT: - a :class:`MixedForm` representing the exterior derivative of the mixed form EXAMPLES: Exterior derivative of a mixed form on a 3-dimensional manifold:: sage: M = Manifold(3, 'M', start_index=1) sage: c_xyz.<x,y,z> = M.chart() sage: f = M.scalar_field(z^2, name='f') sage: f.disp() f: M --> R (x, y, z) |--> z^2 sage: a = M.diff_form(2, 'a') sage: a[1,2], a[1,3], a[2,3] = z+y^2, z+x, x^2 sage: a.disp() a = (y^2 + z) dx/\dy + (x + z) dx/\dz + x^2 dy/\dz sage: F = M.mixed_form(name='F', comp=[f, 0, a, 0]); F.disp() F = f + zero + a + zero sage: dF = F.exterior_derivative() sage: dF.disp() dF = zero + df + dzero + da sage: dF = F.exterior_derivative() sage: dF.disp(c_xyz.frame()) dF = [0] + [2*z dz] + [0] + [(2*x + 1) dx/\dy/\dz] Due to long calculation times, the result is cached, i.e. is not recomputed unless ``F`` is changed:: sage: F.exterior_derivative() is dF True """ resu_comp = list() resu_comp.append(self._domain.scalar_field_algebra().zero()) resu_comp.append(self[0].differential()) resu_comp.extend( [self[j].exterior_derivative() for j in range(1, self._max_deg)]) resu = type(self)(self.parent(), comp=resu_comp) # Compose name: from sage.tensor.modules.format_utilities import (format_unop_txt, format_unop_latex) resu._name = format_unop_txt('d', self._name) resu._latex_name = format_unop_latex(r'\mathrm{d}', self._latex_name) return resu
def hodge_star(self, metric): r""" Compute the Hodge dual of the differential form. If ``self`` is a `p`-form `A`, its Hodge dual is the `(n-p)`-form `*A` defined by (`n` being the manifold's dimension) .. MATH:: *A_{i_1\ldots i_{n-p}} = \frac{1}{p!} A_{k_1\ldots k_p} \epsilon^{k_1\ldots k_p}_{\qquad\ i_1\ldots i_{n-p}} where `\epsilon` is the volume form associated with some pseudo-Riemannian metric `g` on the manifold, and the indices `k_1,\ldots, k_p` are raised with `g`. INPUT: - ``metric``: the pseudo-Riemannian metric `g` defining the Hodge dual, via the volume form `\epsilon`; must be an instance of :class:`~sage.geometry.manifolds.metric.Metric` OUTPUT: - the `(n-p)`-form `*A` EXAMPLES: Hodge star of a 1-form in the Euclidean space `R^3`:: sage: M = Manifold(3, 'M', start_index=1) sage: X.<x,y,z> = M.chart() sage: g = M.metric('g') sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1 sage: a = M.one_form('A') sage: var('Ax Ay Az') (Ax, Ay, Az) sage: a[:] = (Ax, Ay, Az) sage: sa = a.hodge_star(g) ; sa 2-form '*A' on the 3-dimensional manifold 'M' sage: sa.display() *A = Az dx/\dy - Ay dx/\dz + Ax dy/\dz sage: ssa = sa.hodge_star(g) ; ssa 1-form '**A' on the 3-dimensional manifold 'M' sage: ssa.display() **A = Ax dx + Ay dy + Az dz sage: ssa == a # must hold for a Riemannian metric in dimension 3 True Hodge star of a 0-form (scalar field) in `R^3`:: sage: f = M.scalar_field(function('F',x,y,z), name='f') sage: sf = f.hodge_star(g) ; sf 3-form '*f' on the 3-dimensional manifold 'M' sage: sf.display() *f = F(x, y, z) dx/\dy/\dz sage: ssf = sf.hodge_star(g) ; ssf scalar field '**f' on the 3-dimensional manifold 'M' sage: ssf.display() **f: M --> R (x, y, z) |--> F(x, y, z) sage: ssf == f # must hold for a Riemannian metric True Hodge star of a 0-form in Minkowksi spacetime:: sage: M = Manifold(4, 'M') sage: X.<t,x,y,z> = M.chart() sage: g = M.metric('g', signature=2) sage: g[0,0], g[1,1], g[2,2], g[3,3] = -1, 1, 1, 1 sage: g.display() # Minkowski metric g = -dt*dt + dx*dx + dy*dy + dz*dz sage: var('f0') f0 sage: f = M.scalar_field(f0, name='f') sage: sf = f.hodge_star(g) ; sf 4-form '*f' on the 4-dimensional manifold 'M' sage: sf.display() *f = f0 dt/\dx/\dy/\dz sage: ssf = sf.hodge_star(g) ; ssf scalar field '**f' on the 4-dimensional manifold 'M' sage: ssf.display() **f: M --> R (t, x, y, z) |--> -f0 sage: ssf == -f # must hold for a Lorentzian metric True Hodge star of a 1-form in Minkowksi spacetime:: sage: a = M.one_form('A') sage: var('At Ax Ay Az') (At, Ax, Ay, Az) sage: a[:] = (At, Ax, Ay, Az) sage: a.display() A = At dt + Ax dx + Ay dy + Az dz sage: sa = a.hodge_star(g) ; sa 3-form '*A' on the 4-dimensional manifold 'M' sage: sa.display() *A = -Az dt/\dx/\dy + Ay dt/\dx/\dz - Ax dt/\dy/\dz - At dx/\dy/\dz sage: ssa = sa.hodge_star(g) ; ssa 1-form '**A' on the 4-dimensional manifold 'M' sage: ssa.display() **A = At dt + Ax dx + Ay dy + Az dz sage: ssa == a # must hold for a Lorentzian metric in dimension 4 True Hodge star of a 2-form in Minkowksi spacetime:: sage: F = M.diff_form(2, 'F') sage: var('Ex Ey Ez Bx By Bz') (Ex, Ey, Ez, Bx, By, Bz) sage: F[0,1], F[0,2], F[0,3] = -Ex, -Ey, -Ez sage: F[1,2], F[1,3], F[2,3] = Bz, -By, Bx sage: F[:] [ 0 -Ex -Ey -Ez] [ Ex 0 Bz -By] [ Ey -Bz 0 Bx] [ Ez By -Bx 0] sage: sF = F.hodge_star(g) ; sF 2-form '*F' on the 4-dimensional manifold 'M' sage: sF[:] [ 0 Bx By Bz] [-Bx 0 Ez -Ey] [-By -Ez 0 Ex] [-Bz Ey -Ex 0] sage: ssF = sF.hodge_star(g) ; ssF 2-form '**F' on the 4-dimensional manifold 'M' sage: ssF[:] [ 0 Ex Ey Ez] [-Ex 0 -Bz By] [-Ey Bz 0 -Bx] [-Ez -By Bx 0] sage: ssF.display() **F = Ex dt/\dx + Ey dt/\dy + Ez dt/\dz - Bz dx/\dy + By dx/\dz - Bx dy/\dz sage: F.display() F = -Ex dt/\dx - Ey dt/\dy - Ez dt/\dz + Bz dx/\dy - By dx/\dz + Bx dy/\dz sage: ssF == -F # must hold for a Lorentzian metric in dimension 4 True Test of the standard identity .. MATH:: *(A\wedge B) = \epsilon(A^\sharp, B^\sharp, ., .) where `A` and `B` are any 1-forms and `A^\sharp` and `B^\sharp` the vectors associated to them by the metric `g` (index raising):: sage: b = M.one_form('B') sage: var('Bt Bx By Bz') (Bt, Bx, By, Bz) sage: b[:] = (Bt, Bx, By, Bz) ; b.display() B = Bt dt + Bx dx + By dy + Bz dz sage: epsilon = g.volume_form() sage: (a.wedge(b)).hodge_star(g) == epsilon.contract(0,a.up(g)).contract(0,b.up(g)) True """ from sage.functions.other import factorial from sage.tensor.modules.format_utilities import format_unop_txt, \ format_unop_latex p = self._tensor_rank eps = metric.volume_form(p) resu = self.contract(0, eps, 0) for j in range(1, p): resu = resu.trace(0, p - j) if p > 1: resu = resu / factorial(p) resu.set_name(name=format_unop_txt('*', self._name), latex_name=format_unop_latex(r'\star ', self._latex_name)) return resu
def exterior_der(self): r""" Compute the exterior derivative of the differential form. OUTPUT: - the exterior derivative of ``self``. EXAMPLE: Exterior derivative of a 1-form on a 4-dimensional manifold:: sage: M = Manifold(4, 'M') sage: c_txyz.<t,x,y,z> = M.chart() sage: a = M.one_form('A') sage: a[:] = (t*x*y*z, z*y**2, x*z**2, x**2 + y**2) sage: da = a.exterior_der() ; da 2-form 'dA' on the 4-dimensional manifold 'M' sage: da.display() dA = -t*y*z dt/\dx - t*x*z dt/\dy - t*x*y dt/\dz + (-2*y*z + z^2) dx/\dy + (-y^2 + 2*x) dx/\dz + (-2*x*z + 2*y) dy/\dz sage: latex(da) \mathrm{d}A The exterior derivative is nilpotent:: sage: dda = da.exterior_der() ; dda 3-form 'ddA' on the 4-dimensional manifold 'M' sage: dda.display() ddA = 0 sage: dda == 0 True """ from sage.calculus.functional import diff from sage.tensor.modules.format_utilities import format_unop_txt, \ format_unop_latex from sage.tensor.modules.comp import CompFullyAntiSym from vectorframe import CoordFrame if self._exterior_derivative is None: # A new computation is necessary: fmodule = self._fmodule # shortcut rname = format_unop_txt('d', self._name) rlname = format_unop_latex(r'\mathrm{d}', self._latex_name) self._exterior_derivative = fmodule.alternating_form( self._tensor_rank + 1, name=rname, latex_name=rlname) # 1/ List of all coordinate frames in which the components of self # are known coord_frames = [] for frame in self._components: if isinstance(frame, CoordFrame): coord_frames.append(frame) if coord_frames == []: # A coordinate frame is searched, at the price of a change of # frame, priveleging the frame of the domain's default chart dom = self._domain def_coordf = dom._def_chart._frame for frame in self._components: if (frame, def_coordf) in dom._frame_changes: self.comp(def_coordf, from_basis=frame) coord_frames = [def_coordf] break if coord_frames == []: for chart in dom._atlas: if chart != dom._def_chart: # the case def_chart is treated above coordf = chart._frame for frame in self._components: if (frame, coordf) in dom._frame_changes: self.comp(coordf, from_basis=frame) coord_frames[coordf] break if coord_frames != []: break # 2/ The computation: for frame in coord_frames: chart = frame._chart sc = self._components[frame] dc = CompFullyAntiSym( fmodule._ring, frame, self._tensor_rank + 1, start_index=fmodule._sindex, output_formatter=fmodule._output_formatter) for ind, val in sc._comp.iteritems(): for i in fmodule.irange(): ind_d = (i, ) + ind if len(ind_d) == len(set(ind_d)): # all indices are different dc[[ind_d]] += \ val.function_chart(chart).diff(i).scalar_field() self._exterior_derivative._components[frame] = dc return self._exterior_derivative