Skip to content

Commit

Permalink
Trac #30362: Add symplectic structures
Browse files Browse the repository at this point in the history
This ticket implements the basics of symplectic structures,
like Poisson brackets and Hamiltonian vector fields.

TODO (as follow-up tickets):
- Extract general coordinate stuff from `EuclideanSpace`
  to new class `VectorSpace`, and let `SymplecticVectorSpace`
  derive from `VectorSpace`

URL: https://trac.sagemath.org/30362
Reported by: gh-tobiasdiez
Ticket author(s): Tobias Diez
Reviewer(s): Eric Gourgoulhon, Michael Jung, Matthias Koeppe, Travis
Scrimshaw
  • Loading branch information
Release Manager committed Jan 30, 2022
2 parents 25080fa + b78d8a2 commit 464f81e
Show file tree
Hide file tree
Showing 18 changed files with 1,839 additions and 73 deletions.
2 changes: 2 additions & 0 deletions src/doc/en/reference/manifolds/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ More documentation (in particular example worksheets) can be found

riem_manifold

poisson_manifold

sage/manifolds/utilities

sage/manifolds/catalog
Expand Down
11 changes: 11 additions & 0 deletions src/doc/en/reference/manifolds/poisson_manifold.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Poisson Manifolds
=================

.. toctree::
:maxdepth: 3

sage/manifolds/differentiable/poisson_tensor

sage/manifolds/differentiable/symplectic_form

sage/manifolds/differentiable/examples/symplectic_space
6 changes: 6 additions & 0 deletions src/doc/en/reference/references/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ REFERENCES:
.. [AM1969] \M. F. Atiyah and I. G. Macdonald, "Introduction to commutative
algebra", Addison-Wesley, 1969.
.. [AM1990] \R. Abraham and J. E. Marsden, "Foundations of Mechanics",
Addison-Wesley, 1980.
.. [AM1974] \J. F. Adams and H. R. Margolis, "Sub-Hopf-algebras of the
Steenrod algebra," Proc. Cambridge Philos. Soc. 76 (1974),
45-52.
Expand Down Expand Up @@ -4949,6 +4952,9 @@ REFERENCES:
.. [RSS] :wikipedia:`Residual_sum_of_squares`, accessed 13th
October 2009.
.. [RS2012] G. Rudolph and M. Schmidt, "Differential Geometry and Mathematical Physics.
Part I. Manifolds, Lie Groups and Hamiltonian Systems", Springer, 2012.
.. [RSW2011] Victor Reiner, Franco Saliola, Volkmar Welker.
*Spectra of Symmetrized Shuffling Operators*.
:arxiv:`1102.2460v2`.
Expand Down
4 changes: 4 additions & 0 deletions src/sage/manifolds/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
_lazy_import('sage.manifolds.differentiable.examples.real_line', 'RealLine')
_lazy_import('sage.manifolds.differentiable.examples.euclidean', 'EuclideanSpace')
_lazy_import('sage.manifolds.differentiable.examples.sphere', 'Sphere')
_lazy_import(
"sage.manifolds.differentiable.examples.symplectic_space", "StandardSymplecticSpace"
)


def Minkowski(positive_spacelike=True, names=None):
"""
Expand Down
80 changes: 64 additions & 16 deletions src/sage/manifolds/differentiable/diff_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,17 @@
# https://www.gnu.org/licenses/
# *****************************************************************************

from __future__ import annotations
from typing import Union, TYPE_CHECKING
from sage.misc.cachefunc import cached_method
from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm
from sage.manifolds.differentiable.tensorfield import TensorField
from sage.manifolds.differentiable.tensorfield_paral import TensorFieldParal

if TYPE_CHECKING:
from sage.manifolds.differentiable.metric import PseudoRiemannianMetric
from sage.manifolds.differentiable.symplectic_form import SymplecticForm


class DiffForm(TensorField):
r"""
Expand Down Expand Up @@ -441,21 +447,25 @@ def exterior_derivative(self):
True
"""
from sage.tensor.modules.format_utilities import (format_unop_txt,
format_unop_latex)
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)
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

derivative = exterior_derivative # allows one to use functional notation,
# e.g. diff(a) for a.exterior_derivative()

def wedge(self, other):
def wedge(self, other: DiffForm) -> DiffForm:
r"""
Exterior product with another differential form.
Expand Down Expand Up @@ -603,13 +613,16 @@ def degree(self):
"""
return self._tensor_rank

def hodge_dual(self, metric=None):
def hodge_dual(
self,
nondegenerate_tensor: Union[PseudoRiemannianMetric, SymplecticForm, None] = None,
) -> DiffForm:
r"""
Compute the Hodge dual of the differential form with respect to some
metric.
Compute the Hodge dual of the differential form with respect to some non-degenerate
bilinear form (Riemannian metric or symplectic form).
If the differential form is a `p`-form `A`, its *Hodge dual* with
respect to a pseudo-Riemannian metric `g` is the
respect to the non-degenerate form `g` is the
`(n-p)`-form `*A` defined by
.. MATH::
Expand All @@ -624,9 +637,10 @@ def hodge_dual(self, metric=None):
INPUT:
- ``metric``: a pseudo-Riemannian metric defined on the same manifold
- ``nondegenerate_tensor``: a non-degenerate bilinear form defined on the same manifold
as the current differential form; must be an instance of
:class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric`.
:class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric` or
:class:`~sage.manifolds.differentiable.symplectic_form.SymplecticForm`.
If none is provided, the ambient domain of ``self`` is supposed to be endowed
with a default metric and this metric is then used.
Expand Down Expand Up @@ -731,10 +745,43 @@ def hodge_dual(self, metric=None):
See the documentation of
:meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.hodge_star`
for more examples.
TESTS:
Fall back to use (ambient) metric::
sage: M = Manifold(3, 'M', start_index=1, structure='Riemannian')
sage: X.<x,y,z> = M.chart()
sage: g = M.metric()
sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
sage: var('Ax Ay Az')
(Ax, Ay, Az)
sage: a = M.one_form(Ax, Ay, Az, name='A')
sage: a.hodge_dual().display()
*A = Az dx∧dy - Ay dx∧dz + Ax dy∧dz
"""
if metric is None:
metric = self._vmodule._ambient_domain.metric()
return metric.hodge_star(self)
from sage.functions.other import factorial
from sage.tensor.modules.format_utilities import (
format_unop_txt,
format_unop_latex,
)

if nondegenerate_tensor is None:
nondegenerate_tensor = self._vmodule._ambient_domain.metric()

p = self.tensor_type()[1]
eps = nondegenerate_tensor.volume_form(p)
if p == 0:
common_domain = nondegenerate_tensor.domain().intersection(self.domain())
result = self.restrict(common_domain) * eps.restrict(common_domain)
else:
result = self.contract(*range(p), eps, *range(p))
if p > 1:
result = result / factorial(p)
result.set_name(
name=format_unop_txt("*", self._name),
latex_name=format_unop_latex(r"\star ", self._latex_name),
)
return result

def interior_product(self, qvect):
r"""
Expand Down Expand Up @@ -1506,6 +1553,7 @@ def wedge(self, other):
other_r = other.restrict(dom_resu)
return FreeModuleAltForm.wedge(self_r, other_r)


def interior_product(self, qvect):
r"""
Interior product with a multivector field.
Expand Down
163 changes: 163 additions & 0 deletions src/sage/manifolds/differentiable/examples/symplectic_space.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
r"""
Symplectic vector spaces
AUTHORS:
- Tobias Diez (2021): initial version
"""

# *****************************************************************************
# Copyright (C) 2020 Tobias Diez
#
# Distributed under the terms of the GNU General Public License (GPL)
# as published by the Free Software Foundation; either version 2 of
# the License, or (at your option) any later version.
# https://www.gnu.org/licenses/
# *****************************************************************************
from __future__ import annotations

from typing import Optional, Tuple

from sage.categories.manifolds import Manifolds
from sage.manifolds.differentiable.examples.euclidean import EuclideanSpace
from sage.manifolds.differentiable.symplectic_form import (SymplecticForm,
SymplecticFormParal)
from sage.rings.real_mpfr import RR


class StandardSymplecticSpace(EuclideanSpace):
r"""
The vector space `\RR^{2n}` equipped with its standard symplectic form.
"""

_symplectic_form: SymplecticForm

def __init__(
self,
dimension: int,
name: Optional[str] = None,
latex_name: Optional[str] = None,
coordinates: str = "Cartesian",
symbols: Optional[str] = None,
symplectic_name: Optional[str] = "omega",
symplectic_latex_name: Optional[str] = None,
start_index: int = 1,
base_manifold: Optional[StandardSymplecticSpace] = None,
names: Optional[Tuple[str]] = None,
):
r"""
INPUT:
- ``dimension`` -- dimension of the space over the real field (has to be even)
- ``name`` -- name (symbol) given to the underlying vector space;
if ``None``, the name will be set to ``'Rn'``, where ``n`` is the ``dimension``
- ``latex_name`` -- LaTeX symbol to denote the underlying vector space; if ``None``, it is set to ``name``
- ``coordinates`` -- (default: ``'Cartesian'``) the
type of coordinates to be initialized at the Euclidean space
creation; allowed values are
- ``'Cartesian'`` (canonical coordinates on `\RR^{2n}`)
- ``'polar'`` for ``dimension=2`` only (see
:meth:`~sage.manifolds.differentiable.examples.euclidean.EuclideanPlane.polar_coordinates`)
- ``symbols`` -- the coordinate text symbols and LaTeX symbols, with the same conventions as the
argument ``coordinates`` in :class:`~sage.manifolds.differentiable.chart.RealDiffChart`, namely
``symbols`` is a string of coordinate fields separated by a blank
space, where each field contains the coordinate's text symbol and
possibly the coordinate's LaTeX symbol (when the latter is different
from the text symbol), both symbols being separated by a colon
(``:``); if ``None``, the symbols will be automatically generated
according to the value of ``coordinates``
- ``symplectic_name`` -- name (symbol) given to the symplectic form
- ``symplectic_latex_name`` -- LaTeX symbol to denote the symplectic form;
if none is provided, it is set to ``symplectic_name``
- ``start_index`` -- lower value of the range of
indices used for "indexed objects" in the vector space, e.g.
coordinates of a chart
- ``base_manifold`` -- if not ``None``, the created object is then an open subset
of ``base_manifold``
- ``names`` -- (default: ``None``) unused argument, except if
``symbols`` is not provided; it must then be a tuple containing
the coordinate symbols (this is guaranteed if the shortcut operator
``<,>`` is used)
If ``names`` is specified, then ``dimension`` does not have to be specified.
EXAMPLES:
Standard symplectic form on `\RR^2`::
sage: M.<q, p> = manifolds.StandardSymplecticSpace(2, symplectic_name='omega')
sage: omega = M.symplectic_form()
sage: omega.display()
omega = -dq∧dp
"""
# Check that manifold is even dimensional
if dimension % 2 == 1:
raise ValueError(
f"the dimension of the manifold must be even but it is {dimension}"
)
dim_half = dimension // 2

if names is not None and symbols is None:
symbols = " ".join(names)

if symbols is None:
if dim_half == 1:
symbols = r"q:q p:p"
else:
symbols_list = [
f"q{i}:q^{i} p{i}:p_{i}" for i in range(1, dim_half + 1)
]
symbols = " ".join(symbols_list)

if name is None:
name = f"R{dimension}"

category = Manifolds(RR).Smooth()

EuclideanSpace.__init__(
self,
dimension,
name,
latex_name=latex_name,
coordinates=coordinates,
symbols=symbols,
start_index=start_index,
base_manifold=base_manifold,
category=category,
init_coord_methods=None,
)

self._symplectic_form = SymplecticFormParal(
self, symplectic_name, symplectic_latex_name
)
for i in range(0, dim_half):
q_index = 2 * i + 1
self._symplectic_form.set_comp()[q_index, q_index + 1] = -1

def _repr_(self):
r"""
Return a string representation of ``self``.
EXAMPLES::
sage: V.<q, p> = manifolds.StandardSymplecticSpace(2, symplectic_name='omega'); V
Standard symplectic space R2
"""
return f"Standard symplectic space {self._name}"

def symplectic_form(self) -> SymplecticForm:
r"""
Return the symplectic form.
EXAMPLES:
Standard symplectic form on `\RR^2`::
sage: M.<q, p> = manifolds.StandardSymplecticSpace(2, symplectic_name='omega')
sage: omega = M.symplectic_form()
sage: omega.display()
omega = -dq∧dp
"""
return self._symplectic_form
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import sage.all
from sage.manifolds.differentiable.symplectic_form import SymplecticForm
from sage.manifolds.differentiable.examples.symplectic_space import (
StandardSymplecticSpace,
)
import pytest


class TestR2VectorSpace:
@pytest.fixture
def M(self):
return StandardSymplecticSpace(2, "R2", symplectic_name="omega")

@pytest.fixture
def omega(self, M: StandardSymplecticSpace):
return M.symplectic_form()

def test_repr(self, M: StandardSymplecticSpace):
assert str(M) == "Standard symplectic space R2"

def test_display(self, omega: SymplecticForm):
assert str(omega.display()) == r"omega = -dq∧dp"


class TestR4VectorSpace:
@pytest.fixture
def M(self):
return StandardSymplecticSpace(4, "R4", symplectic_name="omega")

@pytest.fixture
def omega(self, M: StandardSymplecticSpace):
return M.symplectic_form()

def test_repr(self, M: StandardSymplecticSpace):
assert str(M) == "Standard symplectic space R4"

def test_display(self, omega: SymplecticForm):
assert str(omega.display()) == r"omega = -dq1∧dp1 - dq2∧dp2"
Loading

0 comments on commit 464f81e

Please sign in to comment.