Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
r""" Points of Topological Manifolds
The class :class:`ManifoldPoint` implements points of a topological manifold.
A :class:`ManifoldPoint` object can have coordinates in various charts defined on the manifold. Two points are declared equal if they have the same coordinates in the same chart.
AUTHORS:
- Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
REFERENCES:
- [Lee2011]_ - [Lee2013]_
EXAMPLES:
Defining a point in `\RR^3` by its spherical coordinates::
sage: M = Manifold(3, 'R^3', structure='topological') sage: U = M.open_subset('U') # the complement of the half-plane (y=0, x>=0) sage: c_spher.<r,th,ph> = U.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi')
We construct the point in the coordinates in the default chart of ``U`` (``c_spher``)::
sage: p = U((1, pi/2, pi), name='P') sage: p Point P on the 3-dimensional topological manifold R^3 sage: latex(p) P sage: p in U True sage: p.parent() Open subset U of the 3-dimensional topological manifold R^3 sage: c_spher(p) (1, 1/2*pi, pi) sage: p.coordinates(c_spher) # equivalent to above (1, 1/2*pi, pi)
Computing the coordinates of ``p`` in a new chart::
sage: c_cart.<x,y,z> = U.chart() # Cartesian coordinates on U sage: spher_to_cart = c_spher.transition_map(c_cart, ....: [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)]) sage: c_cart(p) # evaluate P's Cartesian coordinates (-1, 0, 0)
Points can be compared::
sage: p1 = U((1, pi/2, pi)) sage: p == p1 True sage: q = U((1,2,3), chart=c_cart, name='Q') # point defined by its Cartesian coordinates sage: p == q False
"""
#***************************************************************************** # Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr> # Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
r""" Point of a topological manifold.
This is a Sage *element* class, the corresponding *parent* class being :class:`~sage.manifolds.manifold.TopologicalManifold` or :class:`~sage.manifolds.subset.ManifoldSubset`.
INPUT:
- ``parent`` -- the manifold subset to which the point belongs - ``coords`` -- (default: ``None``) the point coordinates (as a tuple or a list) in the chart ``chart`` - ``chart`` -- (default: ``None``) chart in which the coordinates are given; if ``None``, the coordinates are assumed to refer to the default chart of ``parent`` - ``name`` -- (default: ``None``) name given to the point - ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the point; if ``None``, the LaTeX symbol is set to ``name`` - ``check_coords`` -- (default: ``True``) determines whether ``coords`` are valid coordinates for the chart ``chart``; for symbolic coordinates, it is recommended to set ``check_coords`` to ``False``
EXAMPLES:
A point on a 2-dimensional manifold::
sage: M = Manifold(2, 'M', structure='topological') sage: c_xy.<x,y> = M.chart() sage: (a, b) = var('a b') # generic coordinates for the point sage: p = M.point((a, b), name='P'); p Point P on the 2-dimensional topological manifold M sage: p.coordinates() # coordinates of P in the subset's default chart (a, b)
Since points are Sage *elements*, the *parent* of which being the subset on which they are defined, it is equivalent to write::
sage: p = M((a, b), name='P'); p Point P on the 2-dimensional topological manifold M
A point is an element of the manifold subset in which it has been defined::
sage: p in M True sage: p.parent() 2-dimensional topological manifold M sage: U = M.open_subset('U', coord_def={c_xy: x>0}) sage: q = U.point((2,1), name='q') sage: q.parent() Open subset U of the 2-dimensional topological manifold M sage: q in U True sage: q in M True
By default, the LaTeX symbol of the point is deduced from its name::
sage: latex(p) P
But it can be set to any value::
sage: p = M.point((a, b), name='P', latex_name=r'\mathcal{P}') sage: latex(p) \mathcal{P}
Points can be drawn in 2D or 3D graphics thanks to the method :meth:`plot`. """ latex_name=None, check_coords=True): r""" Construct a manifold point.
TESTS::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M((2,3), name='p'); p Point p on the 2-dimensional topological manifold M sage: TestSuite(p).run() sage: U = M.open_subset('U', coord_def={X: x<0}) sage: q = U((-1,2), name='q'); q Point q on the 2-dimensional topological manifold M sage: TestSuite(q).run()
""" # charts, with the charts as keys raise ValueError("the number of coordinates must be equal " + "to the manifold's dimension") raise ValueError("the {} has not been".format(chart) + "defined on the {}".format(parent)) " are not valid on the {}".format(chart)) else:
r""" Return a string representation of the point.
TESTS::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M((2,-3)) sage: p._repr_() 'Point on the 2-dimensional topological manifold M' sage: p = M((2,-3), name='p') sage: p._repr_() 'Point p on the 2-dimensional topological manifold M' sage: repr(p) # indirect doctest 'Point p on the 2-dimensional topological manifold M'
"""
r""" Return a LaTeX representation of the point.
TESTS::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M((2,-3)) sage: p._latex_() '\\mbox{Point on the 2-dimensional topological manifold M}' sage: p = M((2,-3), name='p') sage: p._latex_() 'p' sage: p = M((2,-3), name='p', latex_name=r'\mathcal{P}') sage: p._latex_() '\\mathcal{P}' sage: latex(p) # indirect doctest \mathcal{P}
"""
r""" Return the point coordinates in the specified chart.
If these coordinates are not already known, they are computed from known ones by means of change-of-chart formulas.
An equivalent way to get the coordinates of a point is to let the chart acting on the point, i.e. if ``X`` is a chart and ``p`` a point, one has ``p.coordinates(chart=X) == X(p)``.
INPUT:
- ``chart`` -- (default: ``None``) chart in which the coordinates are given; if none are provided, the coordinates are assumed to refer to the subset's default chart - ``old_chart`` -- (default: ``None``) chart from which the coordinates in ``chart`` are to be computed; if ``None``, a chart in which the point's coordinates are already known will be picked, privileging the subset's default chart
EXAMPLES:
Spherical coordinates of a point on `\RR^3`::
sage: M = Manifold(3, 'M', structure='topological') sage: c_spher.<r,th,ph> = M.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi') # spherical coordinates sage: p = M.point((1, pi/2, pi)) sage: p.coordinates() # coordinates in the manifold's default chart (1, 1/2*pi, pi)
Since the default chart of ``M`` is ``c_spher``, it is equivalent to write::
sage: p.coordinates(c_spher) (1, 1/2*pi, pi)
An alternative way to get the coordinates is to let the chart act on the point (from the very definition of a chart)::
sage: c_spher(p) (1, 1/2*pi, pi)
A shortcut for ``coordinates`` is ``coord``::
sage: p.coord() (1, 1/2*pi, pi)
Computing the Cartesian coordinates from the spherical ones::
sage: c_cart.<x,y,z> = M.chart() # Cartesian coordinates sage: c_spher.transition_map(c_cart, [r*sin(th)*cos(ph), ....: r*sin(th)*sin(ph), r*cos(th)]) Change of coordinates from Chart (M, (r, th, ph)) to Chart (M, (x, y, z))
The computation is performed by means of the above change of coordinates::
sage: p.coord(c_cart) (-1, 0, 0) sage: p.coord(c_cart) == c_cart(p) True
Coordinates of a point on a 2-dimensional manifold::
sage: M = Manifold(2, 'M', structure='topological') sage: c_xy.<x,y> = M.chart() sage: (a, b) = var('a b') # generic coordinates for the point sage: P = M.point((a, b), name='P')
Coordinates of ``P`` in the manifold's default chart::
sage: P.coord() (a, b)
Coordinates of ``P`` in a new chart::
sage: c_uv.<u,v> = M.chart() sage: ch_xy_uv = c_xy.transition_map(c_uv, [x-y, x+y]) sage: P.coord(c_uv) (a - b, a + b)
Coordinates of ``P`` in a third chart::
sage: c_wz.<w,z> = M.chart() sage: ch_uv_wz = c_uv.transition_map(c_wz, [u^3, v^3]) sage: P.coord(c_wz, old_chart=c_uv) (a^3 - 3*a^2*b + 3*a*b^2 - b^3, a^3 + 3*a^2*b + 3*a*b^2 + b^3)
Actually, in the present case, it is not necessary to specify ``old_chart='uv'``. Note that the first command erases all the coordinates except those in the chart ``c_uv``::
sage: P.set_coord((a-b, a+b), c_uv) sage: P._coordinates {Chart (M, (u, v)): (a - b, a + b)} sage: P.coord(c_wz) (a^3 - 3*a^2*b + 3*a*b^2 - b^3, a^3 + 3*a^2*b + 3*a*b^2 + b^3) sage: P._coordinates # random (dictionary output) {Chart (M, (u, v)): (a - b, a + b), Chart (M, (w, z)): (a^3 - 3*a^2*b + 3*a*b^2 - b^3, a^3 + 3*a^2*b + 3*a*b^2 + b^3)}
""" else: "of {}".format(chart)) # Check whether chart corresponds to a superchart of a chart # in which the coordinates are known: # If this point is reached, some change of coordinates must be # performed else: # A chart must be found as a starting point of the computation # The domain's default chart is privileged: and (def_chart, chart) in dom._coord_changes): else: # Some search involving the subcharts of chart is # performed: raise ValueError("the coordinates of {}".format(self) + " in the {}".format(chart) + " cannot be computed " + "by means of known changes of charts.") else:
r""" Sets the point coordinates in the specified chart.
Coordinates with respect to other charts are deleted, in order to avoid any inconsistency. To keep them, use the method :meth:`add_coord` instead.
INPUT:
- ``coords`` -- the point coordinates (as a tuple or a list) - ``chart`` -- (default: ``None``) chart in which the coordinates are given; if none are provided, the coordinates are assumed to refer to the subset's default chart
EXAMPLES:
Setting coordinates to a point on a 2-dimensional manifold::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M.point()
We set the coordinates in the manifold's default chart::
sage: p.set_coordinates((2,-3)) sage: p.coordinates() (2, -3) sage: X(p) (2, -3)
A shortcut for ``set_coordinates`` is ``set_coord``::
sage: p.set_coord((2,-3)) sage: p.coord() (2, -3)
Let us introduce a second chart on the manifold::
sage: Y.<u,v> = M.chart() sage: X_to_Y = X.transition_map(Y, [x+y, x-y])
If we set the coordinates of ``p`` in chart ``Y``, those in chart ``X`` are lost::
sage: Y(p) (-1, 5) sage: p.set_coord(Y(p), chart=Y) sage: p._coordinates {Chart (M, (u, v)): (-1, 5)}
"""
r""" Adds some coordinates in the specified chart.
The previous coordinates with respect to other charts are kept. To clear them, use :meth:`set_coord` instead.
INPUT:
- ``coords`` -- the point coordinates (as a tuple or a list) - ``chart`` -- (default: ``None``) chart in which the coordinates are given; if none are provided, the coordinates are assumed to refer to the subset's default chart
.. WARNING::
If the point has already coordinates in other charts, it is the user's responsibility to make sure that the coordinates to be added are consistent with them.
EXAMPLES:
Setting coordinates to a point on a 2-dimensional manifold::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M.point()
We give the point some coordinates in the manifold's default chart::
sage: p.add_coordinates((2,-3)) sage: p.coordinates() (2, -3) sage: X(p) (2, -3)
A shortcut for ``add_coordinates`` is ``add_coord``::
sage: p.add_coord((2,-3)) sage: p.coord() (2, -3)
Let us introduce a second chart on the manifold::
sage: Y.<u,v> = M.chart() sage: X_to_Y = X.transition_map(Y, [x+y, x-y])
If we add coordinates for ``p`` in chart ``Y``, those in chart ``X`` are kept::
sage: p.add_coordinates((-1,5), chart=Y) sage: p._coordinates # random (dictionary output) {Chart (M, (u, v)): (-1, 5), Chart (M, (x, y)): (2, -3)}
On the contrary, with the method :meth:`set_coordinates`, the coordinates in charts different from ``Y`` would be lost::
sage: p.set_coordinates((-1,5), chart=Y) sage: p._coordinates {Chart (M, (u, v)): (-1, 5)}
""" raise ValueError("the number of coordinates must be equal to " + "the manifold's dimension.") else: raise ValueError("the {}".format(chart) + " has not been " + "defined on the {}".format(self.parent()))
r""" Compares the current point with another one.
EXAMPLES:
Comparison with coordinates in the same chart::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M((2,-3), chart=X) sage: q = M((2,-3), chart=X) sage: p == q True sage: q = M((-2,-3), chart=X) sage: p == q False
Comparison with coordinates of other in a subchart::
sage: U = M.open_subset('U', coord_def={X: x>0}) sage: XU = X.restrict(U) sage: q = U((2,-3), chart=XU) sage: p == q and q == p True sage: q = U((1,-3), chart=XU) sage: p == q or q == p False
Comparison requiring a change of chart::
sage: Y.<u,v> = U.chart() sage: XU_to_Y = XU.transition_map(Y, (ln(x), x+y)) sage: XU_to_Y.inverse()(u,v) (e^u, v - e^u) sage: q = U((ln(2),-1), chart=Y) sage: p == q and q == p True sage: q = U((ln(3),1), chart=Y) sage: p == q or q == p False
""" return False # Search for a common chart to compare the coordinates # the subset's default chart is privileged: # FIXME: Make this a better test else: def_chart = self.parent().manifold()._def_chart else: # A commont chart is searched via a coordinate transformation, # privileging the default chart except ValueError: pass # At this stage, a commont chart is searched via a coordinate # transformation from any chart common_chart = chart break else: # Attempt a coordinate transformation in the reverse way: common_chart = chart break #!# Another option would be: # raise ValueError("no common chart has been found to compare " + # "{} and {}".format(self, other)) other._coordinates[common_chart]):
r""" Non-equality operator.
TESTS::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M((2,-3), chart=X) sage: q = M((0,1), chart=X) sage: p != q True sage: p != M((2,-3), chart=X) False
"""
r""" Return the hash of ``self``.
This hash function is set to constant on a given manifold, to fulfill Python's credo::
p == q ==> hash(p) == hash(q)
This is necessary since ``p`` and ``q`` may be created in different coordinate systems and nevertheless be equal.
.. TODO::
Find a better hash function.
TESTS::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M((2,-3), chart=X) sage: hash(p) == hash(M) True
"""
label=None, parameters=None, **kwds): r""" For real manifolds, plot ``self`` in a Cartesian graph based on the coordinates of some ambient chart.
The point is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The domain of the ambient chart must contain the point, or its image by a continuous manifold map `\Phi`.
INPUT:
- ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, the ambient chart is set the default chart of ``self.parent()`` - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) :class:`~sage.manifolds.continuous_map.ContinuousMap`; continuous manifold map `\Phi` providing the link between the current point `p` and the ambient chart ``chart``: the domain of ``chart`` must contain `\Phi(p)`; if ``None``, the identity map is assumed - ``label`` -- (default: ``None``) label printed next to the point; if ``None``, the point's name is used - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the point coordinates - ``size`` -- (default: 10) size of the point once drawn as a small disk or sphere - ``color`` -- (default: ``'black'``) color of the point - ``label_color`` -- (default: ``None``) color to print the label; if ``None``, the value of ``color`` is used - ``fontsize`` -- (default: 10) size of the font used to print the label - ``label_offset`` -- (default: 0.1) determines the separation between the point and its label
OUTPUT:
- a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of the ambient chart) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of the ambient chart)
EXAMPLES:
Drawing a point on a 2-dimensional manifold::
sage: M = Manifold(2, 'M', structure='topological') sage: X.<x,y> = M.chart() sage: p = M.point((1,3), name='p') sage: g = p.plot(X) sage: print(g) Graphics object consisting of 2 graphics primitives sage: gX = X.plot(max_range=4) # plot of the coordinate grid sage: g + gX # display of the point atop the coordinate grid Graphics object consisting of 20 graphics primitives
.. PLOT::
M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(X) gX = X.plot(max_range=4) sphinx_plot(g+gX)
Actually, since ``X`` is the default chart of the open set in which ``p`` has been defined, it can be skipped in the arguments of ``plot``::
sage: g = p.plot() sage: g + gX Graphics object consisting of 20 graphics primitives
Call with some options::
sage: g = p.plot(chart=X, size=40, color='green', label='$P$', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: g + gX Graphics object consisting of 20 graphics primitives
.. PLOT::
M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(chart=X, size=40, color='green', label='$P$', \ label_color='blue', fontsize=20, label_offset=0.3) gX = X.plot(max_range=4) sphinx_plot(g+gX)
Use of the ``parameters`` option to set a numerical value of some symbolic variable::
sage: a = var('a') sage: q = M.point((a,2*a), name='q') sage: gq = q.plot(parameters={a:-2}, label_offset=0.2) sage: g + gX + gq Graphics object consisting of 22 graphics primitives
.. PLOT::
M = Manifold(2, 'M', structure='topological') X = M.chart('x y'); x,y = X[:] p = M.point((1,3), name='p') g = p.plot(chart=X, size=40, color='green', label='$P$', \ label_color='blue', fontsize=20, label_offset=0.3) var('a') q = M.point((a,2*a), name='q') gq = q.plot(parameters={a:-2}, label_offset=0.2) gX = X.plot(max_range=4) sphinx_plot(g+gX+gq)
The numerical value is used only for the plot::
sage: q.coord() (a, 2*a)
Drawing a point on a 3-dimensional manifold::
sage: M = Manifold(3, 'M', structure='topological') sage: X.<x,y,z> = M.chart() sage: p = M.point((2,1,3), name='p') sage: g = p.plot() sage: print(g) Graphics3d Object sage: gX = X.plot(number_values=5) # coordinate mesh cube sage: g + gX # display of the point atop the coordinate mesh Graphics3d Object
Call with some options::
sage: g = p.plot(chart=X, size=40, color='green', label='P_1', ....: label_color='blue', fontsize=20, label_offset=0.3) sage: g + gX Graphics3d Object
An example of plot via a mapping: plot of a point on a 2-sphere viewed in the 3-dimensional space ``M``::
sage: S2 = Manifold(2, 'S^2', structure='topological') sage: U = S2.open_subset('U') # the open set covered by spherical coord. sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: p = U.point((pi/4, pi/8), name='p') sage: F = S2.continuous_map(M, {(XS, X): [sin(th)*cos(ph), ....: sin(th)*sin(ph), cos(th)]}, name='F') sage: F.display() F: S^2 --> M on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: g = p.plot(chart=X, mapping=F) sage: gS2 = XS.plot(chart=X, mapping=F, number_values=9) sage: g + gS2 Graphics3d Object
Use of the option ``ambient_coords`` for plots on a 4-dimensional manifold::
sage: M = Manifold(4, 'M', structure='topological') sage: X.<t,x,y,z> = M.chart() sage: p = M.point((1,2,3,4), name='p') sage: g = p.plot(X, ambient_coords=(t,x,y), label_offset=0.4) # the coordinate z is skipped sage: gX = X.plot(X, ambient_coords=(t,x,y), number_values=5) # long time sage: g + gX # 3D plot # long time Graphics3d Object sage: g = p.plot(X, ambient_coords=(t,y,z), label_offset=0.4) # the coordinate x is skipped sage: gX = X.plot(X, ambient_coords=(t,y,z), number_values=5) # long time sage: g + gX # 3D plot # long time Graphics3d Object sage: g = p.plot(X, ambient_coords=(y,z), label_offset=0.4) # the coordinates t and x are skipped sage: gX = X.plot(X, ambient_coords=(y,z)) sage: g + gX # 2D plot Graphics object consisting of 20 graphics primitives
.. PLOT::
M = Manifold(4, 'M', structure='topological') X = M.chart('t x y z'); t,x,y,z = X[:] p = M.point((1,2,3,4), name='p') g = p.plot(X, ambient_coords=(y,z), label_offset=0.4) gX = X.plot(X, ambient_coords=(y,z)) sphinx_plot(g+gX)
""" raise NotImplementedError('plot of points on manifolds over fields different' ' from the real field is not implemented') # The ambient chart: raise TypeError("the argument 'chart' must be a coordinate chart") # The effective point to be plotted: else: # The coordinates of the ambient chart used for the plot: ambient_coords = tuple(ambient_coords) raise TypeError("invalid number of ambient coordinates: {}".format(nca))
# Extract the kwds options
# The point coordinates: text(label, xlab, fontsize=fontsize, color=label_color)) else: text3d(label, xlab, fontsize=fontsize, color=label_color))
|