passagemath-symbolics 10.6.43__cp314-cp314t-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-symbolics might be problematic. Click here for more details.
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.43.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.43.dist-info/RECORD +171 -0
- passagemath_symbolics-10.6.43.dist-info/WHEEL +5 -0
- passagemath_symbolics-10.6.43.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2826 -0
- sage/calculus/desolvers.py +1866 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-314t-x86_64-linux-musl.so +0 -0
- sage/calculus/var.pyx +401 -0
- sage/dynamics/all__sagemath_symbolics.py +6 -0
- sage/dynamics/complex_dynamics/all.py +5 -0
- sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-x86_64-linux-musl.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
- sage/ext/all__sagemath_symbolics.py +1 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/magma/latex/latex.m +1021 -0
- sage/ext_data/magma/latex/latex.spec +1 -0
- sage/ext_data/magma/sage/basic.m +356 -0
- sage/ext_data/magma/sage/sage.spec +1 -0
- sage/ext_data/magma/spec +9 -0
- sage/geometry/all__sagemath_symbolics.py +8 -0
- sage/geometry/hyperbolic_space/all.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
- sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
- sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
- sage/geometry/riemannian_manifolds/all.py +7 -0
- sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
- sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
- sage/interfaces/all__sagemath_symbolics.py +1 -0
- sage/interfaces/magma.py +3017 -0
- sage/interfaces/magma_free.py +92 -0
- sage/interfaces/maple.py +1397 -0
- sage/interfaces/mathematica.py +1345 -0
- sage/interfaces/mathics.py +1312 -0
- sage/interfaces/sympy.py +1398 -0
- sage/interfaces/sympy_wrapper.py +197 -0
- sage/interfaces/tides.py +938 -0
- sage/libs/all__sagemath_symbolics.py +6 -0
- sage/manifolds/all.py +7 -0
- sage/manifolds/calculus_method.py +555 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4019 -0
- sage/manifolds/chart_func.py +3419 -0
- sage/manifolds/continuous_map.py +2183 -0
- sage/manifolds/continuous_map_image.py +155 -0
- sage/manifolds/differentiable/affine_connection.py +2475 -0
- sage/manifolds/differentiable/all.py +1 -0
- sage/manifolds/differentiable/automorphismfield.py +1383 -0
- sage/manifolds/differentiable/automorphismfield_group.py +604 -0
- sage/manifolds/differentiable/bundle_connection.py +1445 -0
- sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
- sage/manifolds/differentiable/chart.py +1241 -0
- sage/manifolds/differentiable/curve.py +1028 -0
- sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
- sage/manifolds/differentiable/degenerate.py +559 -0
- sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
- sage/manifolds/differentiable/diff_form.py +1658 -0
- sage/manifolds/differentiable/diff_form_module.py +1062 -0
- sage/manifolds/differentiable/diff_map.py +1315 -0
- sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
- sage/manifolds/differentiable/examples/all.py +1 -0
- sage/manifolds/differentiable/examples/euclidean.py +2517 -0
- sage/manifolds/differentiable/examples/real_line.py +897 -0
- sage/manifolds/differentiable/examples/sphere.py +1186 -0
- sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
- sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
- sage/manifolds/differentiable/integrated_curve.py +4035 -0
- sage/manifolds/differentiable/levi_civita_connection.py +841 -0
- sage/manifolds/differentiable/manifold.py +4254 -0
- sage/manifolds/differentiable/manifold_homset.py +1826 -0
- sage/manifolds/differentiable/metric.py +3032 -0
- sage/manifolds/differentiable/mixed_form.py +1507 -0
- sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
- sage/manifolds/differentiable/multivector_module.py +800 -0
- sage/manifolds/differentiable/multivectorfield.py +1520 -0
- sage/manifolds/differentiable/poisson_tensor.py +268 -0
- sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
- sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
- sage/manifolds/differentiable/scalarfield.py +1343 -0
- sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
- sage/manifolds/differentiable/symplectic_form.py +910 -0
- sage/manifolds/differentiable/symplectic_form_test.py +220 -0
- sage/manifolds/differentiable/tangent_space.py +412 -0
- sage/manifolds/differentiable/tangent_vector.py +616 -0
- sage/manifolds/differentiable/tensorfield.py +4665 -0
- sage/manifolds/differentiable/tensorfield_module.py +963 -0
- sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
- sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
- sage/manifolds/differentiable/vector_bundle.py +1728 -0
- sage/manifolds/differentiable/vectorfield.py +1717 -0
- sage/manifolds/differentiable/vectorfield_module.py +2445 -0
- sage/manifolds/differentiable/vectorframe.py +1832 -0
- sage/manifolds/family.py +270 -0
- sage/manifolds/local_frame.py +1490 -0
- sage/manifolds/manifold.py +3090 -0
- sage/manifolds/manifold_homset.py +452 -0
- sage/manifolds/operators.py +359 -0
- sage/manifolds/point.py +994 -0
- sage/manifolds/scalarfield.py +3718 -0
- sage/manifolds/scalarfield_algebra.py +629 -0
- sage/manifolds/section.py +3111 -0
- sage/manifolds/section_module.py +831 -0
- sage/manifolds/structure.py +229 -0
- sage/manifolds/subset.py +2764 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +885 -0
- sage/manifolds/topological_submanifold.py +891 -0
- sage/manifolds/trivialization.py +733 -0
- sage/manifolds/utilities.py +1348 -0
- sage/manifolds/vector_bundle.py +1342 -0
- sage/manifolds/vector_bundle_fiber.py +332 -0
- sage/manifolds/vector_bundle_fiber_element.py +111 -0
- sage/matrix/all__sagemath_symbolics.py +1 -0
- sage/matrix/matrix_symbolic_dense.cpython-314t-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1022 -0
- sage/matrix/matrix_symbolic_sparse.cpython-314t-x86_64-linux-musl.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
- sage/modules/all__sagemath_symbolics.py +1 -0
- sage/modules/vector_callable_symbolic_dense.py +105 -0
- sage/modules/vector_symbolic_dense.py +116 -0
- sage/modules/vector_symbolic_sparse.py +118 -0
- sage/rings/all__sagemath_symbolics.py +4 -0
- sage/rings/asymptotic/all.py +6 -0
- sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
- sage/rings/asymptotic/asymptotic_ring.py +4858 -0
- sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5237 -0
- sage/rings/function_field/all__sagemath_symbolics.py +2 -0
- sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
- sage/symbolic/all.py +15 -0
- sage/symbolic/assumptions.py +985 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +459 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1287 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1713 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +270 -0
- sage/symbolic/integration/integral.py +1115 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/random_tests.py +462 -0
- sage/symbolic/relation.py +1907 -0
- sage/symbolic/ring.cpython-314t-x86_64-linux-musl.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyx +1396 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1470 -0
sage/manifolds/point.py
ADDED
|
@@ -0,0 +1,994 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Points of Topological Manifolds
|
|
4
|
+
|
|
5
|
+
The class :class:`ManifoldPoint` implements points of a
|
|
6
|
+
topological manifold.
|
|
7
|
+
|
|
8
|
+
A :class:`ManifoldPoint` object can have coordinates in
|
|
9
|
+
various charts defined on the manifold. Two points are declared
|
|
10
|
+
equal if they have the same coordinates in the same chart.
|
|
11
|
+
|
|
12
|
+
AUTHORS:
|
|
13
|
+
|
|
14
|
+
- Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
|
|
15
|
+
|
|
16
|
+
REFERENCES:
|
|
17
|
+
|
|
18
|
+
- [Lee2011]_
|
|
19
|
+
- [Lee2013]_
|
|
20
|
+
|
|
21
|
+
EXAMPLES:
|
|
22
|
+
|
|
23
|
+
Defining a point in `\RR^3` by its spherical coordinates::
|
|
24
|
+
|
|
25
|
+
sage: M = Manifold(3, 'R^3', structure='topological')
|
|
26
|
+
sage: U = M.open_subset('U') # the domain of spherical coordinates
|
|
27
|
+
sage: c_spher.<r,th,ph> = U.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):periodic:\phi')
|
|
28
|
+
|
|
29
|
+
We construct the point in the coordinates in the default chart of ``U``
|
|
30
|
+
(``c_spher``)::
|
|
31
|
+
|
|
32
|
+
sage: p = U((1, pi/2, pi), name='P')
|
|
33
|
+
sage: p
|
|
34
|
+
Point P on the 3-dimensional topological manifold R^3
|
|
35
|
+
sage: latex(p)
|
|
36
|
+
P
|
|
37
|
+
sage: p in U
|
|
38
|
+
True
|
|
39
|
+
sage: p.parent()
|
|
40
|
+
Open subset U of the 3-dimensional topological manifold R^3
|
|
41
|
+
sage: c_spher(p)
|
|
42
|
+
(1, 1/2*pi, pi)
|
|
43
|
+
sage: p.coordinates(c_spher) # equivalent to above
|
|
44
|
+
(1, 1/2*pi, pi)
|
|
45
|
+
|
|
46
|
+
Computing the coordinates of ``p`` in a new chart::
|
|
47
|
+
|
|
48
|
+
sage: c_cart.<x,y,z> = U.chart() # Cartesian coordinates on U
|
|
49
|
+
sage: spher_to_cart = c_spher.transition_map(c_cart,
|
|
50
|
+
....: [r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)])
|
|
51
|
+
sage: c_cart(p) # evaluate P's Cartesian coordinates
|
|
52
|
+
(-1, 0, 0)
|
|
53
|
+
|
|
54
|
+
Points can be compared::
|
|
55
|
+
|
|
56
|
+
sage: p1 = U((1, pi/2, pi))
|
|
57
|
+
sage: p1 == p
|
|
58
|
+
True
|
|
59
|
+
sage: q = U((2, pi/2, pi))
|
|
60
|
+
sage: q == p
|
|
61
|
+
False
|
|
62
|
+
|
|
63
|
+
even if they were initially not defined within the same coordinate chart::
|
|
64
|
+
|
|
65
|
+
sage: p2 = U((-1,0,0), chart=c_cart)
|
|
66
|
+
sage: p2 == p
|
|
67
|
+
True
|
|
68
|
+
|
|
69
|
+
The `2\pi`-periodicity of the `\phi` coordinate is also taken into account
|
|
70
|
+
for the comparison::
|
|
71
|
+
|
|
72
|
+
sage: p3 = U((1, pi/2, 5*pi))
|
|
73
|
+
sage: p3 == p
|
|
74
|
+
True
|
|
75
|
+
sage: p4 = U((1, pi/2, -pi))
|
|
76
|
+
sage: p4 == p
|
|
77
|
+
True
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
#*****************************************************************************
|
|
81
|
+
# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
82
|
+
# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
|
|
83
|
+
#
|
|
84
|
+
# This program is free software: you can redistribute it and/or modify
|
|
85
|
+
# it under the terms of the GNU General Public License as published by
|
|
86
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
87
|
+
# (at your option) any later version.
|
|
88
|
+
# https://www.gnu.org/licenses/
|
|
89
|
+
#*****************************************************************************
|
|
90
|
+
|
|
91
|
+
from sage.misc.decorators import options
|
|
92
|
+
from sage.rings.integer_ring import ZZ
|
|
93
|
+
from sage.structure.element import Element
|
|
94
|
+
from sage.symbolic.expression import Expression
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class ManifoldPoint(Element):
|
|
98
|
+
r"""
|
|
99
|
+
Point of a topological manifold.
|
|
100
|
+
|
|
101
|
+
This is a Sage *element* class, the corresponding *parent* class
|
|
102
|
+
being :class:`~sage.manifolds.manifold.TopologicalManifold`
|
|
103
|
+
or :class:`~sage.manifolds.subset.ManifoldSubset`.
|
|
104
|
+
|
|
105
|
+
INPUT:
|
|
106
|
+
|
|
107
|
+
- ``parent`` -- the manifold subset to which the point belongs
|
|
108
|
+
- ``coords`` -- (default: ``None``) the point coordinates (as a tuple
|
|
109
|
+
or a list) in the chart ``chart``
|
|
110
|
+
- ``chart`` -- (default: ``None``) chart in which the coordinates are
|
|
111
|
+
given; if ``None``, the coordinates are assumed to refer to the
|
|
112
|
+
default chart of ``parent``
|
|
113
|
+
- ``name`` -- (default: ``None``) name given to the point
|
|
114
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the point;
|
|
115
|
+
if ``None``, the LaTeX symbol is set to ``name``
|
|
116
|
+
- ``check_coords`` -- boolean (default: ``True``); determines whether ``coords``
|
|
117
|
+
are valid coordinates for the chart ``chart``. For symbolic
|
|
118
|
+
coordinates, it is recommended to set ``check_coords`` to ``False``.
|
|
119
|
+
|
|
120
|
+
EXAMPLES:
|
|
121
|
+
|
|
122
|
+
A point on a 2-dimensional manifold::
|
|
123
|
+
|
|
124
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
125
|
+
sage: c_xy.<x,y> = M.chart()
|
|
126
|
+
sage: (a, b) = var('a b') # generic coordinates for the point
|
|
127
|
+
sage: p = M.point((a, b), name='P'); p
|
|
128
|
+
Point P on the 2-dimensional topological manifold M
|
|
129
|
+
sage: p.coordinates() # coordinates of P in the subset's default chart
|
|
130
|
+
(a, b)
|
|
131
|
+
|
|
132
|
+
Since points are Sage *elements*, the *parent* of which being the
|
|
133
|
+
subset on which they are defined, it is equivalent to write::
|
|
134
|
+
|
|
135
|
+
sage: p = M((a, b), name='P'); p
|
|
136
|
+
Point P on the 2-dimensional topological manifold M
|
|
137
|
+
|
|
138
|
+
A point is an element of the manifold subset in which it has
|
|
139
|
+
been defined::
|
|
140
|
+
|
|
141
|
+
sage: p in M
|
|
142
|
+
True
|
|
143
|
+
sage: p.parent()
|
|
144
|
+
2-dimensional topological manifold M
|
|
145
|
+
sage: U = M.open_subset('U', coord_def={c_xy: x>0})
|
|
146
|
+
sage: q = U.point((2,1), name='q')
|
|
147
|
+
sage: q.parent()
|
|
148
|
+
Open subset U of the 2-dimensional topological manifold M
|
|
149
|
+
sage: q in U
|
|
150
|
+
True
|
|
151
|
+
sage: q in M
|
|
152
|
+
True
|
|
153
|
+
|
|
154
|
+
By default, the LaTeX symbol of the point is deduced from its name::
|
|
155
|
+
|
|
156
|
+
sage: latex(p)
|
|
157
|
+
P
|
|
158
|
+
|
|
159
|
+
But it can be set to any value::
|
|
160
|
+
|
|
161
|
+
sage: p = M.point((a, b), name='P', latex_name=r'\mathcal{P}')
|
|
162
|
+
sage: latex(p)
|
|
163
|
+
\mathcal{P}
|
|
164
|
+
|
|
165
|
+
Points can be drawn in 2D or 3D graphics thanks to the
|
|
166
|
+
method :meth:`plot`.
|
|
167
|
+
"""
|
|
168
|
+
def __init__(self, parent, coords=None, chart=None, name=None,
|
|
169
|
+
latex_name=None, check_coords=True):
|
|
170
|
+
r"""
|
|
171
|
+
Construct a manifold point.
|
|
172
|
+
|
|
173
|
+
TESTS::
|
|
174
|
+
|
|
175
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
176
|
+
sage: X.<x,y> = M.chart()
|
|
177
|
+
sage: p = M((2,3), name='p'); p
|
|
178
|
+
Point p on the 2-dimensional topological manifold M
|
|
179
|
+
sage: TestSuite(p).run()
|
|
180
|
+
sage: U = M.open_subset('U', coord_def={X: x<0})
|
|
181
|
+
sage: q = U((-1,2), name='q'); q
|
|
182
|
+
Point q on the 2-dimensional topological manifold M
|
|
183
|
+
sage: TestSuite(q).run()
|
|
184
|
+
"""
|
|
185
|
+
if parent.is_empty():
|
|
186
|
+
raise TypeError(f'cannot define a point on the {parent} because it has been declared empty')
|
|
187
|
+
Element.__init__(self, parent)
|
|
188
|
+
parent._has_defined_points = True
|
|
189
|
+
self._manifold = parent.manifold() # a useful shortcut
|
|
190
|
+
self._coordinates = {} # dictionary of the point coordinates in various
|
|
191
|
+
# charts, with the charts as keys
|
|
192
|
+
if coords is not None:
|
|
193
|
+
if len(coords) != parent.manifold().dimension():
|
|
194
|
+
raise ValueError("the number of coordinates must be equal " +
|
|
195
|
+
"to the manifold's dimension")
|
|
196
|
+
from sage.manifolds.manifold import TopologicalManifold
|
|
197
|
+
if chart is None:
|
|
198
|
+
chart = parent._def_chart
|
|
199
|
+
elif isinstance(parent, TopologicalManifold):
|
|
200
|
+
if chart not in parent._atlas:
|
|
201
|
+
raise ValueError("the {} has not been".format(chart) +
|
|
202
|
+
"defined on the {}".format(parent))
|
|
203
|
+
if check_coords:
|
|
204
|
+
if not chart.valid_coordinates(*coords):
|
|
205
|
+
raise ValueError("the coordinates {}".format(coords) +
|
|
206
|
+
" are not valid on the {}".format(chart))
|
|
207
|
+
for schart in chart._supercharts:
|
|
208
|
+
self._coordinates[schart] = tuple(coords)
|
|
209
|
+
for schart in chart._subcharts:
|
|
210
|
+
if schart != chart:
|
|
211
|
+
if schart.valid_coordinates(*coords):
|
|
212
|
+
self._coordinates[schart] = tuple(coords)
|
|
213
|
+
self._name = name
|
|
214
|
+
if latex_name is None:
|
|
215
|
+
self._latex_name = self._name
|
|
216
|
+
else:
|
|
217
|
+
self._latex_name = latex_name
|
|
218
|
+
|
|
219
|
+
def _repr_(self):
|
|
220
|
+
r"""
|
|
221
|
+
Return a string representation of the point.
|
|
222
|
+
|
|
223
|
+
TESTS::
|
|
224
|
+
|
|
225
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
226
|
+
sage: X.<x,y> = M.chart()
|
|
227
|
+
sage: p = M((2,-3))
|
|
228
|
+
sage: p._repr_()
|
|
229
|
+
'Point on the 2-dimensional topological manifold M'
|
|
230
|
+
sage: p = M((2,-3), name='p')
|
|
231
|
+
sage: p._repr_()
|
|
232
|
+
'Point p on the 2-dimensional topological manifold M'
|
|
233
|
+
sage: repr(p) # indirect doctest
|
|
234
|
+
'Point p on the 2-dimensional topological manifold M'
|
|
235
|
+
"""
|
|
236
|
+
description = "Point"
|
|
237
|
+
if self._name is not None:
|
|
238
|
+
description += " " + self._name
|
|
239
|
+
description += " on the {}".format(self._manifold)
|
|
240
|
+
return description
|
|
241
|
+
|
|
242
|
+
def _latex_(self):
|
|
243
|
+
r"""
|
|
244
|
+
Return a LaTeX representation of the point.
|
|
245
|
+
|
|
246
|
+
TESTS::
|
|
247
|
+
|
|
248
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
249
|
+
sage: X.<x,y> = M.chart()
|
|
250
|
+
sage: p = M((2,-3))
|
|
251
|
+
sage: p._latex_()
|
|
252
|
+
'\\text{Point on the 2-dimensional topological manifold M}'
|
|
253
|
+
sage: p = M((2,-3), name='p')
|
|
254
|
+
sage: p._latex_()
|
|
255
|
+
'p'
|
|
256
|
+
sage: p = M((2,-3), name='p', latex_name=r'\mathcal{P}')
|
|
257
|
+
sage: p._latex_()
|
|
258
|
+
'\\mathcal{P}'
|
|
259
|
+
sage: latex(p) # indirect doctest
|
|
260
|
+
\mathcal{P}
|
|
261
|
+
"""
|
|
262
|
+
if self._latex_name is None:
|
|
263
|
+
return r'\text{' + str(self) + r'}'
|
|
264
|
+
return self._latex_name
|
|
265
|
+
|
|
266
|
+
def coordinates(self, chart=None, old_chart=None):
|
|
267
|
+
r"""
|
|
268
|
+
Return the point coordinates in the specified chart.
|
|
269
|
+
|
|
270
|
+
If these coordinates are not already known, they are computed from
|
|
271
|
+
known ones by means of change-of-chart formulas.
|
|
272
|
+
|
|
273
|
+
An equivalent way to get the coordinates of a point is to let the
|
|
274
|
+
chart acting on the point, i.e. if ``X`` is a chart and ``p`` a
|
|
275
|
+
point, one has ``p.coordinates(chart=X) == X(p)``.
|
|
276
|
+
|
|
277
|
+
INPUT:
|
|
278
|
+
|
|
279
|
+
- ``chart`` -- (default: ``None``) chart in which the coordinates
|
|
280
|
+
are given; if none are provided, the coordinates are assumed to
|
|
281
|
+
refer to the subset's default chart
|
|
282
|
+
- ``old_chart`` -- (default: ``None``) chart from which the
|
|
283
|
+
coordinates in ``chart`` are to be computed; if ``None``, a chart
|
|
284
|
+
in which the point's coordinates are already known will be picked,
|
|
285
|
+
privileging the subset's default chart
|
|
286
|
+
|
|
287
|
+
EXAMPLES:
|
|
288
|
+
|
|
289
|
+
Spherical coordinates of a point on `\RR^3`::
|
|
290
|
+
|
|
291
|
+
sage: M = Manifold(3, 'M', structure='topological')
|
|
292
|
+
sage: c_spher.<r,th,ph> = M.chart(r'r:(0,+oo) th:(0,pi):\theta ph:(0,2*pi):\phi') # spherical coordinates
|
|
293
|
+
sage: p = M.point((1, pi/2, pi))
|
|
294
|
+
sage: p.coordinates() # coordinates in the manifold's default chart
|
|
295
|
+
(1, 1/2*pi, pi)
|
|
296
|
+
|
|
297
|
+
Since the default chart of ``M`` is ``c_spher``, it is equivalent to
|
|
298
|
+
write::
|
|
299
|
+
|
|
300
|
+
sage: p.coordinates(c_spher)
|
|
301
|
+
(1, 1/2*pi, pi)
|
|
302
|
+
|
|
303
|
+
An alternative way to get the coordinates is to let the chart act
|
|
304
|
+
on the point (from the very definition of a chart)::
|
|
305
|
+
|
|
306
|
+
sage: c_spher(p)
|
|
307
|
+
(1, 1/2*pi, pi)
|
|
308
|
+
|
|
309
|
+
A shortcut for ``coordinates`` is ``coord``::
|
|
310
|
+
|
|
311
|
+
sage: p.coord()
|
|
312
|
+
(1, 1/2*pi, pi)
|
|
313
|
+
|
|
314
|
+
Computing the Cartesian coordinates from the spherical ones::
|
|
315
|
+
|
|
316
|
+
sage: c_cart.<x,y,z> = M.chart() # Cartesian coordinates
|
|
317
|
+
sage: c_spher.transition_map(c_cart, [r*sin(th)*cos(ph),
|
|
318
|
+
....: r*sin(th)*sin(ph), r*cos(th)])
|
|
319
|
+
Change of coordinates from Chart (M, (r, th, ph)) to Chart (M, (x, y, z))
|
|
320
|
+
|
|
321
|
+
The computation is performed by means of the above change
|
|
322
|
+
of coordinates::
|
|
323
|
+
|
|
324
|
+
sage: p.coord(c_cart)
|
|
325
|
+
(-1, 0, 0)
|
|
326
|
+
sage: p.coord(c_cart) == c_cart(p)
|
|
327
|
+
True
|
|
328
|
+
|
|
329
|
+
Coordinates of a point on a 2-dimensional manifold::
|
|
330
|
+
|
|
331
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
332
|
+
sage: c_xy.<x,y> = M.chart()
|
|
333
|
+
sage: (a, b) = var('a b') # generic coordinates for the point
|
|
334
|
+
sage: P = M.point((a, b), name='P')
|
|
335
|
+
|
|
336
|
+
Coordinates of ``P`` in the manifold's default chart::
|
|
337
|
+
|
|
338
|
+
sage: P.coord()
|
|
339
|
+
(a, b)
|
|
340
|
+
|
|
341
|
+
Coordinates of ``P`` in a new chart::
|
|
342
|
+
|
|
343
|
+
sage: c_uv.<u,v> = M.chart()
|
|
344
|
+
sage: ch_xy_uv = c_xy.transition_map(c_uv, [x-y, x+y])
|
|
345
|
+
sage: P.coord(c_uv)
|
|
346
|
+
(a - b, a + b)
|
|
347
|
+
|
|
348
|
+
Coordinates of ``P`` in a third chart::
|
|
349
|
+
|
|
350
|
+
sage: c_wz.<w,z> = M.chart()
|
|
351
|
+
sage: ch_uv_wz = c_uv.transition_map(c_wz, [u^3, v^3])
|
|
352
|
+
sage: P.coord(c_wz, old_chart=c_uv)
|
|
353
|
+
(a^3 - 3*a^2*b + 3*a*b^2 - b^3, a^3 + 3*a^2*b + 3*a*b^2 + b^3)
|
|
354
|
+
|
|
355
|
+
Actually, in the present case, it is not necessary to specify
|
|
356
|
+
``old_chart='uv'``. Note that the first command erases all
|
|
357
|
+
the coordinates except those in the chart ``c_uv``::
|
|
358
|
+
|
|
359
|
+
sage: P.set_coord((a-b, a+b), c_uv)
|
|
360
|
+
sage: P._coordinates
|
|
361
|
+
{Chart (M, (u, v)): (a - b, a + b)}
|
|
362
|
+
sage: P.coord(c_wz)
|
|
363
|
+
(a^3 - 3*a^2*b + 3*a*b^2 - b^3, a^3 + 3*a^2*b + 3*a*b^2 + b^3)
|
|
364
|
+
sage: P._coordinates # random (dictionary output)
|
|
365
|
+
{Chart (M, (u, v)): (a - b, a + b),
|
|
366
|
+
Chart (M, (w, z)): (a^3 - 3*a^2*b + 3*a*b^2 - b^3,
|
|
367
|
+
a^3 + 3*a^2*b + 3*a*b^2 + b^3)}
|
|
368
|
+
"""
|
|
369
|
+
if chart is None:
|
|
370
|
+
dom = self.parent()
|
|
371
|
+
chart = dom._def_chart
|
|
372
|
+
def_chart = chart
|
|
373
|
+
else:
|
|
374
|
+
dom = chart.domain()
|
|
375
|
+
def_chart = dom._def_chart
|
|
376
|
+
if self not in dom:
|
|
377
|
+
raise ValueError("the point does not belong to the domain " +
|
|
378
|
+
"of {}".format(chart))
|
|
379
|
+
if chart not in self._coordinates:
|
|
380
|
+
# Check whether chart corresponds to a superchart of a chart
|
|
381
|
+
# in which the coordinates are known:
|
|
382
|
+
for ochart in self._coordinates:
|
|
383
|
+
if chart in ochart._supercharts or chart in ochart._subcharts:
|
|
384
|
+
self._coordinates[chart] = self._coordinates[ochart]
|
|
385
|
+
return self._coordinates[chart]
|
|
386
|
+
# If this point is reached, some change of coordinates must be
|
|
387
|
+
# performed
|
|
388
|
+
if old_chart is not None:
|
|
389
|
+
s_old_chart = old_chart
|
|
390
|
+
s_chart = chart
|
|
391
|
+
else:
|
|
392
|
+
# A chart must be found as a starting point of the computation
|
|
393
|
+
# The domain's default chart is privileged:
|
|
394
|
+
if (def_chart in self._coordinates
|
|
395
|
+
and (def_chart, chart) in dom._coord_changes):
|
|
396
|
+
old_chart = def_chart
|
|
397
|
+
s_old_chart = def_chart
|
|
398
|
+
s_chart = chart
|
|
399
|
+
else:
|
|
400
|
+
for ochart in self._coordinates:
|
|
401
|
+
for subchart in ochart._subcharts:
|
|
402
|
+
if (subchart, chart) in dom._coord_changes:
|
|
403
|
+
old_chart = ochart
|
|
404
|
+
s_old_chart = subchart
|
|
405
|
+
s_chart = chart
|
|
406
|
+
break
|
|
407
|
+
if old_chart is not None:
|
|
408
|
+
break
|
|
409
|
+
if old_chart is None:
|
|
410
|
+
# Some search involving the subcharts of chart is
|
|
411
|
+
# performed:
|
|
412
|
+
for schart in chart._subcharts:
|
|
413
|
+
for ochart in self._coordinates:
|
|
414
|
+
for subchart in ochart._subcharts:
|
|
415
|
+
if (subchart, schart) in dom._coord_changes:
|
|
416
|
+
old_chart = ochart
|
|
417
|
+
s_old_chart = subchart
|
|
418
|
+
s_chart = schart
|
|
419
|
+
break
|
|
420
|
+
if old_chart is not None:
|
|
421
|
+
break
|
|
422
|
+
if old_chart is not None:
|
|
423
|
+
break
|
|
424
|
+
if old_chart is None:
|
|
425
|
+
raise ValueError("the coordinates of {}".format(self) +
|
|
426
|
+
" in the {}".format(chart) + " cannot be computed " +
|
|
427
|
+
"by means of known changes of charts.")
|
|
428
|
+
else:
|
|
429
|
+
chcoord = dom._coord_changes[(s_old_chart, s_chart)]
|
|
430
|
+
self._coordinates[chart] = chcoord(*self._coordinates[old_chart])
|
|
431
|
+
return self._coordinates[chart]
|
|
432
|
+
|
|
433
|
+
coord = coordinates
|
|
434
|
+
|
|
435
|
+
def set_coordinates(self, coords, chart=None):
|
|
436
|
+
r"""
|
|
437
|
+
Set the point coordinates in the specified chart.
|
|
438
|
+
|
|
439
|
+
Coordinates with respect to other charts are deleted, in order to
|
|
440
|
+
avoid any inconsistency. To keep them, use the method :meth:`add_coord`
|
|
441
|
+
instead.
|
|
442
|
+
|
|
443
|
+
INPUT:
|
|
444
|
+
|
|
445
|
+
- ``coords`` -- the point coordinates (as a tuple or a list)
|
|
446
|
+
- ``chart`` -- (default: ``None``) chart in which the coordinates
|
|
447
|
+
are given; if none are provided, the coordinates are assumed to
|
|
448
|
+
refer to the subset's default chart
|
|
449
|
+
|
|
450
|
+
EXAMPLES:
|
|
451
|
+
|
|
452
|
+
Setting coordinates to a point on a 2-dimensional manifold::
|
|
453
|
+
|
|
454
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
455
|
+
sage: X.<x,y> = M.chart()
|
|
456
|
+
sage: p = M.point()
|
|
457
|
+
|
|
458
|
+
We set the coordinates in the manifold's default chart::
|
|
459
|
+
|
|
460
|
+
sage: p.set_coordinates((2,-3))
|
|
461
|
+
sage: p.coordinates()
|
|
462
|
+
(2, -3)
|
|
463
|
+
sage: X(p)
|
|
464
|
+
(2, -3)
|
|
465
|
+
|
|
466
|
+
A shortcut for ``set_coordinates`` is ``set_coord``::
|
|
467
|
+
|
|
468
|
+
sage: p.set_coord((2,-3))
|
|
469
|
+
sage: p.coord()
|
|
470
|
+
(2, -3)
|
|
471
|
+
|
|
472
|
+
Let us introduce a second chart on the manifold::
|
|
473
|
+
|
|
474
|
+
sage: Y.<u,v> = M.chart()
|
|
475
|
+
sage: X_to_Y = X.transition_map(Y, [x+y, x-y])
|
|
476
|
+
|
|
477
|
+
If we set the coordinates of ``p`` in chart ``Y``, those in chart ``X``
|
|
478
|
+
are lost::
|
|
479
|
+
|
|
480
|
+
sage: Y(p)
|
|
481
|
+
(-1, 5)
|
|
482
|
+
sage: p.set_coord(Y(p), chart=Y)
|
|
483
|
+
sage: p._coordinates
|
|
484
|
+
{Chart (M, (u, v)): (-1, 5)}
|
|
485
|
+
"""
|
|
486
|
+
self._coordinates.clear()
|
|
487
|
+
self.add_coord(coords, chart)
|
|
488
|
+
|
|
489
|
+
set_coord = set_coordinates
|
|
490
|
+
|
|
491
|
+
def add_coordinates(self, coords, chart=None):
|
|
492
|
+
r"""
|
|
493
|
+
Add some coordinates in the specified chart.
|
|
494
|
+
|
|
495
|
+
The previous coordinates with respect to other charts are kept. To
|
|
496
|
+
clear them, use :meth:`set_coord` instead.
|
|
497
|
+
|
|
498
|
+
INPUT:
|
|
499
|
+
|
|
500
|
+
- ``coords`` -- the point coordinates (as a tuple or a list)
|
|
501
|
+
- ``chart`` -- (default: ``None``) chart in which the coordinates
|
|
502
|
+
are given; if none are provided, the coordinates are assumed to
|
|
503
|
+
refer to the subset's default chart
|
|
504
|
+
|
|
505
|
+
.. WARNING::
|
|
506
|
+
|
|
507
|
+
If the point has already coordinates in other charts, it
|
|
508
|
+
is the user's responsibility to make sure that the coordinates
|
|
509
|
+
to be added are consistent with them.
|
|
510
|
+
|
|
511
|
+
EXAMPLES:
|
|
512
|
+
|
|
513
|
+
Setting coordinates to a point on a 2-dimensional manifold::
|
|
514
|
+
|
|
515
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
516
|
+
sage: X.<x,y> = M.chart()
|
|
517
|
+
sage: p = M.point()
|
|
518
|
+
|
|
519
|
+
We give the point some coordinates in the manifold's default chart::
|
|
520
|
+
|
|
521
|
+
sage: p.add_coordinates((2,-3))
|
|
522
|
+
sage: p.coordinates()
|
|
523
|
+
(2, -3)
|
|
524
|
+
sage: X(p)
|
|
525
|
+
(2, -3)
|
|
526
|
+
|
|
527
|
+
A shortcut for ``add_coordinates`` is ``add_coord``::
|
|
528
|
+
|
|
529
|
+
sage: p.add_coord((2,-3))
|
|
530
|
+
sage: p.coord()
|
|
531
|
+
(2, -3)
|
|
532
|
+
|
|
533
|
+
Let us introduce a second chart on the manifold::
|
|
534
|
+
|
|
535
|
+
sage: Y.<u,v> = M.chart()
|
|
536
|
+
sage: X_to_Y = X.transition_map(Y, [x+y, x-y])
|
|
537
|
+
|
|
538
|
+
If we add coordinates for ``p`` in chart ``Y``, those in chart ``X``
|
|
539
|
+
are kept::
|
|
540
|
+
|
|
541
|
+
sage: p.add_coordinates((-1,5), chart=Y)
|
|
542
|
+
sage: p._coordinates # random (dictionary output)
|
|
543
|
+
{Chart (M, (u, v)): (-1, 5), Chart (M, (x, y)): (2, -3)}
|
|
544
|
+
|
|
545
|
+
On the contrary, with the method :meth:`set_coordinates`, the
|
|
546
|
+
coordinates in charts different from ``Y`` would be lost::
|
|
547
|
+
|
|
548
|
+
sage: p.set_coordinates((-1,5), chart=Y)
|
|
549
|
+
sage: p._coordinates
|
|
550
|
+
{Chart (M, (u, v)): (-1, 5)}
|
|
551
|
+
"""
|
|
552
|
+
if len(coords) != self.parent().manifold()._dim:
|
|
553
|
+
raise ValueError("the number of coordinates must be equal to " +
|
|
554
|
+
"the manifold's dimension.")
|
|
555
|
+
if chart is None:
|
|
556
|
+
chart = self.parent()._def_chart
|
|
557
|
+
else:
|
|
558
|
+
if chart not in self.parent()._atlas:
|
|
559
|
+
raise ValueError("the {}".format(chart) + " has not been " +
|
|
560
|
+
"defined on the {}".format(self.parent()))
|
|
561
|
+
self._coordinates[chart] = coords
|
|
562
|
+
|
|
563
|
+
add_coord = add_coordinates
|
|
564
|
+
|
|
565
|
+
def __eq__(self, other):
|
|
566
|
+
r"""
|
|
567
|
+
Compare the current point with another one.
|
|
568
|
+
|
|
569
|
+
EXAMPLES:
|
|
570
|
+
|
|
571
|
+
Comparison with coordinates in the same chart::
|
|
572
|
+
|
|
573
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
574
|
+
sage: X.<x,y> = M.chart()
|
|
575
|
+
sage: p = M((2,-3), chart=X)
|
|
576
|
+
sage: q = M((2,-3), chart=X)
|
|
577
|
+
sage: p == q
|
|
578
|
+
True
|
|
579
|
+
sage: q = M((-2,-3), chart=X)
|
|
580
|
+
sage: p == q
|
|
581
|
+
False
|
|
582
|
+
|
|
583
|
+
Comparison with coordinates of other in a subchart::
|
|
584
|
+
|
|
585
|
+
sage: U = M.open_subset('U', coord_def={X: x>0})
|
|
586
|
+
sage: XU = X.restrict(U)
|
|
587
|
+
sage: q = U((2,-3), chart=XU)
|
|
588
|
+
sage: p == q and q == p
|
|
589
|
+
True
|
|
590
|
+
sage: q = U((1,-3), chart=XU)
|
|
591
|
+
sage: p == q or q == p
|
|
592
|
+
False
|
|
593
|
+
|
|
594
|
+
Comparison requiring a change of chart::
|
|
595
|
+
|
|
596
|
+
sage: Y.<u,v> = U.chart()
|
|
597
|
+
sage: XU_to_Y = XU.transition_map(Y, (ln(x), x+y))
|
|
598
|
+
sage: XU_to_Y.inverse()(u,v)
|
|
599
|
+
(e^u, v - e^u)
|
|
600
|
+
sage: q = U((ln(2),-1), chart=Y)
|
|
601
|
+
sage: p == q and q == p
|
|
602
|
+
True
|
|
603
|
+
sage: q = U((ln(3),1), chart=Y)
|
|
604
|
+
sage: p == q or q == p
|
|
605
|
+
False
|
|
606
|
+
|
|
607
|
+
Comparison with periodic coordinates::
|
|
608
|
+
|
|
609
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
610
|
+
sage: X.<x,y> = M.chart('x y:period=2')
|
|
611
|
+
sage: p = M((0,1))
|
|
612
|
+
sage: q = M((0,3))
|
|
613
|
+
sage: p == q and q == p
|
|
614
|
+
True
|
|
615
|
+
sage: q = M((0,2))
|
|
616
|
+
sage: p == q or q == p
|
|
617
|
+
False
|
|
618
|
+
sage: Y.<u,v> = M.chart('u:(0,2*pi):periodic v')
|
|
619
|
+
sage: p = M((0,1), chart=Y)
|
|
620
|
+
sage: q = M((-4*pi,1), chart=Y)
|
|
621
|
+
sage: p == q and q == p
|
|
622
|
+
True
|
|
623
|
+
sage: q = M((3*pi,1), chart=Y)
|
|
624
|
+
sage: p == q or q == p
|
|
625
|
+
False
|
|
626
|
+
"""
|
|
627
|
+
if other is self:
|
|
628
|
+
return True
|
|
629
|
+
if not isinstance(other, ManifoldPoint):
|
|
630
|
+
return False
|
|
631
|
+
if other.parent().manifold() != self.parent().manifold():
|
|
632
|
+
return False
|
|
633
|
+
# Search for a common chart to compare the coordinates
|
|
634
|
+
common_chart = None
|
|
635
|
+
# the subset's default chart is privileged:
|
|
636
|
+
# FIXME: Make this a better test
|
|
637
|
+
if hasattr(self.parent(), '_def_chart'): # self.parent() is open
|
|
638
|
+
def_chart = self.parent()._def_chart
|
|
639
|
+
else:
|
|
640
|
+
def_chart = self.parent().manifold()._def_chart
|
|
641
|
+
if def_chart in self._coordinates and def_chart in other._coordinates:
|
|
642
|
+
common_chart = def_chart
|
|
643
|
+
else:
|
|
644
|
+
for chart in self._coordinates:
|
|
645
|
+
if chart in other._coordinates:
|
|
646
|
+
common_chart = chart
|
|
647
|
+
break
|
|
648
|
+
if common_chart is None:
|
|
649
|
+
# A common chart is searched via a coordinate transformation,
|
|
650
|
+
# privileging the default chart
|
|
651
|
+
if def_chart in self._coordinates:
|
|
652
|
+
try:
|
|
653
|
+
other.coordinates(def_chart)
|
|
654
|
+
common_chart = def_chart
|
|
655
|
+
except ValueError:
|
|
656
|
+
pass
|
|
657
|
+
if common_chart is None:
|
|
658
|
+
if def_chart in other._coordinates:
|
|
659
|
+
try:
|
|
660
|
+
self.coordinates(def_chart)
|
|
661
|
+
common_chart = def_chart
|
|
662
|
+
except ValueError:
|
|
663
|
+
pass
|
|
664
|
+
if common_chart is None:
|
|
665
|
+
# At this stage, a common chart is searched via a coordinate
|
|
666
|
+
# transformation from any chart
|
|
667
|
+
for chart in self._coordinates:
|
|
668
|
+
try:
|
|
669
|
+
other.coordinates(chart)
|
|
670
|
+
common_chart = chart
|
|
671
|
+
break
|
|
672
|
+
except ValueError:
|
|
673
|
+
pass
|
|
674
|
+
else:
|
|
675
|
+
# Attempt a coordinate transformation in the reverse way:
|
|
676
|
+
for chart in other._coordinates:
|
|
677
|
+
try:
|
|
678
|
+
self.coordinates(chart)
|
|
679
|
+
common_chart = chart
|
|
680
|
+
break
|
|
681
|
+
except ValueError:
|
|
682
|
+
pass
|
|
683
|
+
if common_chart is None:
|
|
684
|
+
return False
|
|
685
|
+
#!# Another option would be:
|
|
686
|
+
# raise ValueError("no common chart has been found to compare " +
|
|
687
|
+
# "{} and {}".format(self, other))
|
|
688
|
+
periods = common_chart.periods()
|
|
689
|
+
for ind, (xs, xo) in enumerate(zip(self._coordinates[common_chart],
|
|
690
|
+
other._coordinates[common_chart])):
|
|
691
|
+
diff = xs - xo
|
|
692
|
+
period = periods[ind]
|
|
693
|
+
if period is not None:
|
|
694
|
+
if diff/period not in ZZ:
|
|
695
|
+
return False
|
|
696
|
+
else:
|
|
697
|
+
if isinstance(diff, Expression) and not diff.is_trivial_zero():
|
|
698
|
+
return False
|
|
699
|
+
elif not (diff == 0):
|
|
700
|
+
return False
|
|
701
|
+
return True
|
|
702
|
+
|
|
703
|
+
def __ne__(self, other):
|
|
704
|
+
r"""
|
|
705
|
+
Non-equality operator.
|
|
706
|
+
|
|
707
|
+
TESTS::
|
|
708
|
+
|
|
709
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
710
|
+
sage: X.<x,y> = M.chart()
|
|
711
|
+
sage: p = M((2,-3), chart=X)
|
|
712
|
+
sage: q = M((0,1), chart=X)
|
|
713
|
+
sage: p != q
|
|
714
|
+
True
|
|
715
|
+
sage: p != M((2,-3), chart=X)
|
|
716
|
+
False
|
|
717
|
+
"""
|
|
718
|
+
return not (self == other)
|
|
719
|
+
|
|
720
|
+
def __hash__(self):
|
|
721
|
+
r"""
|
|
722
|
+
Return the hash of ``self``.
|
|
723
|
+
|
|
724
|
+
This hash function is set to constant on a given manifold, to fulfill
|
|
725
|
+
Python's credo::
|
|
726
|
+
|
|
727
|
+
p == q ==> hash(p) == hash(q)
|
|
728
|
+
|
|
729
|
+
This is necessary since ``p`` and ``q`` may be created in
|
|
730
|
+
different coordinate systems and nevertheless be equal.
|
|
731
|
+
|
|
732
|
+
.. TODO::
|
|
733
|
+
|
|
734
|
+
Find a better hash function.
|
|
735
|
+
|
|
736
|
+
TESTS::
|
|
737
|
+
|
|
738
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
739
|
+
sage: X.<x,y> = M.chart()
|
|
740
|
+
sage: p = M((2,-3), chart=X)
|
|
741
|
+
sage: hash(p) == hash(M)
|
|
742
|
+
True
|
|
743
|
+
"""
|
|
744
|
+
return hash(self.parent().manifold())
|
|
745
|
+
|
|
746
|
+
@options(size=10, color='black', label_color=None, fontsize=10, label_offset=0.1)
|
|
747
|
+
def plot(self, chart=None, ambient_coords=None, mapping=None,
|
|
748
|
+
label=None, parameters=None, **kwds):
|
|
749
|
+
r"""
|
|
750
|
+
For real manifolds, plot ``self`` in a Cartesian graph based
|
|
751
|
+
on the coordinates of some ambient chart.
|
|
752
|
+
|
|
753
|
+
The point is drawn in terms of two (2D graphics) or three (3D graphics)
|
|
754
|
+
coordinates of a given chart, called hereafter the *ambient chart*.
|
|
755
|
+
The domain of the ambient chart must contain the point, or its image
|
|
756
|
+
by a continuous manifold map `\Phi`.
|
|
757
|
+
|
|
758
|
+
INPUT:
|
|
759
|
+
|
|
760
|
+
- ``chart`` -- (default: ``None``) the ambient chart (see above); if
|
|
761
|
+
``None``, the ambient chart is set the default chart of
|
|
762
|
+
``self.parent()``
|
|
763
|
+
- ``ambient_coords`` -- (default: ``None``) tuple containing the 2
|
|
764
|
+
or 3 coordinates of the ambient chart in terms of which the plot
|
|
765
|
+
is performed; if ``None``, all the coordinates of the ambient
|
|
766
|
+
chart are considered
|
|
767
|
+
- ``mapping`` -- (default: ``None``)
|
|
768
|
+
:class:`~sage.manifolds.continuous_map.ContinuousMap`; continuous
|
|
769
|
+
manifold map `\Phi` providing the link between the current point
|
|
770
|
+
`p` and the ambient chart ``chart``: the domain of ``chart`` must
|
|
771
|
+
contain `\Phi(p)`; if ``None``, the identity map is assumed
|
|
772
|
+
- ``label`` -- (default: ``None``) label printed next to the point;
|
|
773
|
+
if ``None``, the point's name is used
|
|
774
|
+
- ``parameters`` -- (default: ``None``) dictionary giving the numerical
|
|
775
|
+
values of the parameters that may appear in the point coordinates
|
|
776
|
+
- ``size`` -- (default: 10) size of the point once drawn as a small
|
|
777
|
+
disk or sphere
|
|
778
|
+
- ``color`` -- (default: ``'black'``) color of the point
|
|
779
|
+
- ``label_color`` -- (default: ``None``) color to print the label;
|
|
780
|
+
if ``None``, the value of ``color`` is used
|
|
781
|
+
- ``fontsize`` -- (default: 10) size of the font used to print the
|
|
782
|
+
label
|
|
783
|
+
- ``label_offset`` -- (default: 0.1) determines the separation between
|
|
784
|
+
the point and its label
|
|
785
|
+
|
|
786
|
+
OUTPUT:
|
|
787
|
+
|
|
788
|
+
- a graphic object, either an instance of
|
|
789
|
+
:class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
|
|
790
|
+
2 coordinates of the ambient chart) or an instance of
|
|
791
|
+
:class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
|
|
792
|
+
based on 3 coordinates of the ambient chart)
|
|
793
|
+
|
|
794
|
+
EXAMPLES:
|
|
795
|
+
|
|
796
|
+
Drawing a point on a 2-dimensional manifold::
|
|
797
|
+
|
|
798
|
+
sage: # needs sage.plot
|
|
799
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
800
|
+
sage: X.<x,y> = M.chart()
|
|
801
|
+
sage: p = M.point((1,3), name='p')
|
|
802
|
+
sage: g = p.plot(X)
|
|
803
|
+
sage: print(g)
|
|
804
|
+
Graphics object consisting of 2 graphics primitives
|
|
805
|
+
sage: gX = X.plot(max_range=4) # plot of the coordinate grid
|
|
806
|
+
sage: g + gX # display of the point atop the coordinate grid
|
|
807
|
+
Graphics object consisting of 20 graphics primitives
|
|
808
|
+
|
|
809
|
+
.. PLOT::
|
|
810
|
+
|
|
811
|
+
M = Manifold(2, 'M', structure='topological')
|
|
812
|
+
X = M.chart('x y'); x,y = X[:]
|
|
813
|
+
p = M.point((1,3), name='p')
|
|
814
|
+
g = p.plot(X)
|
|
815
|
+
gX = X.plot(max_range=4)
|
|
816
|
+
sphinx_plot(g+gX)
|
|
817
|
+
|
|
818
|
+
Actually, since ``X`` is the default chart of the open set in which
|
|
819
|
+
``p`` has been defined, it can be skipped in the arguments of
|
|
820
|
+
``plot``::
|
|
821
|
+
|
|
822
|
+
sage: # needs sage.plot
|
|
823
|
+
sage: g = p.plot()
|
|
824
|
+
sage: g + gX
|
|
825
|
+
Graphics object consisting of 20 graphics primitives
|
|
826
|
+
|
|
827
|
+
Call with some options::
|
|
828
|
+
|
|
829
|
+
sage: # needs sage.plot
|
|
830
|
+
sage: g = p.plot(chart=X, size=40, color='green', label='$P$',
|
|
831
|
+
....: label_color='blue', fontsize=20, label_offset=0.3)
|
|
832
|
+
sage: g + gX
|
|
833
|
+
Graphics object consisting of 20 graphics primitives
|
|
834
|
+
|
|
835
|
+
.. PLOT::
|
|
836
|
+
|
|
837
|
+
M = Manifold(2, 'M', structure='topological')
|
|
838
|
+
X = M.chart('x y'); x,y = X[:]
|
|
839
|
+
p = M.point((1,3), name='p')
|
|
840
|
+
g = p.plot(chart=X, size=40, color='green', label='$P$', \
|
|
841
|
+
label_color='blue', fontsize=20, label_offset=0.3)
|
|
842
|
+
gX = X.plot(max_range=4)
|
|
843
|
+
sphinx_plot(g+gX)
|
|
844
|
+
|
|
845
|
+
Use of the ``parameters`` option to set a numerical value of some
|
|
846
|
+
symbolic variable::
|
|
847
|
+
|
|
848
|
+
sage: a = var('a')
|
|
849
|
+
sage: q = M.point((a,2*a), name='q') # needs sage.plot
|
|
850
|
+
sage: gq = q.plot(parameters={a:-2}, label_offset=0.2) # needs sage.plot
|
|
851
|
+
sage: g + gX + gq # needs sage.plot
|
|
852
|
+
Graphics object consisting of 22 graphics primitives
|
|
853
|
+
|
|
854
|
+
.. PLOT::
|
|
855
|
+
|
|
856
|
+
M = Manifold(2, 'M', structure='topological')
|
|
857
|
+
X = M.chart('x y'); x,y = X[:]
|
|
858
|
+
p = M.point((1,3), name='p')
|
|
859
|
+
g = p.plot(chart=X, size=40, color='green', label='$P$', \
|
|
860
|
+
label_color='blue', fontsize=20, label_offset=0.3)
|
|
861
|
+
var('a')
|
|
862
|
+
q = M.point((a,2*a), name='q')
|
|
863
|
+
gq = q.plot(parameters={a:-2}, label_offset=0.2)
|
|
864
|
+
gX = X.plot(max_range=4)
|
|
865
|
+
sphinx_plot(g+gX+gq)
|
|
866
|
+
|
|
867
|
+
The numerical value is used only for the plot::
|
|
868
|
+
|
|
869
|
+
sage: q.coord() # needs sage.plot
|
|
870
|
+
(a, 2*a)
|
|
871
|
+
|
|
872
|
+
Drawing a point on a 3-dimensional manifold::
|
|
873
|
+
|
|
874
|
+
sage: # needs sage.plot
|
|
875
|
+
sage: M = Manifold(3, 'M', structure='topological')
|
|
876
|
+
sage: X.<x,y,z> = M.chart()
|
|
877
|
+
sage: p = M.point((2,1,3), name='p')
|
|
878
|
+
sage: g = p.plot()
|
|
879
|
+
sage: print(g)
|
|
880
|
+
Graphics3d Object
|
|
881
|
+
sage: gX = X.plot(number_values=5) # coordinate mesh cube
|
|
882
|
+
sage: g + gX # display of the point atop the coordinate mesh
|
|
883
|
+
Graphics3d Object
|
|
884
|
+
|
|
885
|
+
Call with some options::
|
|
886
|
+
|
|
887
|
+
sage: g = p.plot(chart=X, size=40, color='green', label='P_1', # needs sage.plot
|
|
888
|
+
....: label_color='blue', fontsize=20, label_offset=0.3)
|
|
889
|
+
sage: g + gX # needs sage.plot
|
|
890
|
+
Graphics3d Object
|
|
891
|
+
|
|
892
|
+
An example of plot via a mapping: plot of a point on a 2-sphere viewed
|
|
893
|
+
in the 3-dimensional space ``M``::
|
|
894
|
+
|
|
895
|
+
sage: # needs sage.plot
|
|
896
|
+
sage: S2 = Manifold(2, 'S^2', structure='topological')
|
|
897
|
+
sage: U = S2.open_subset('U') # the open set covered by spherical coord.
|
|
898
|
+
sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
|
|
899
|
+
sage: p = U.point((pi/4, pi/8), name='p')
|
|
900
|
+
sage: F = S2.continuous_map(M, {(XS, X): [sin(th)*cos(ph),
|
|
901
|
+
....: sin(th)*sin(ph), cos(th)]}, name='F')
|
|
902
|
+
sage: F.display()
|
|
903
|
+
F: S^2 → M
|
|
904
|
+
on U: (th, ph) ↦ (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
|
|
905
|
+
sage: g = p.plot(chart=X, mapping=F)
|
|
906
|
+
sage: gS2 = XS.plot(chart=X, mapping=F, number_values=9)
|
|
907
|
+
sage: g + gS2
|
|
908
|
+
Graphics3d Object
|
|
909
|
+
|
|
910
|
+
Use of the option ``ambient_coords`` for plots on a 4-dimensional
|
|
911
|
+
manifold::
|
|
912
|
+
|
|
913
|
+
sage: # needs sage.plot
|
|
914
|
+
sage: M = Manifold(4, 'M', structure='topological')
|
|
915
|
+
sage: X.<t,x,y,z> = M.chart()
|
|
916
|
+
sage: p = M.point((1,2,3,4), name='p')
|
|
917
|
+
sage: g = p.plot(X, ambient_coords=(t,x,y), label_offset=0.4) # the coordinate z is skipped
|
|
918
|
+
sage: gX = X.plot(X, ambient_coords=(t,x,y), number_values=5) # long time
|
|
919
|
+
sage: g + gX # 3D plot # long time
|
|
920
|
+
Graphics3d Object
|
|
921
|
+
sage: g = p.plot(X, ambient_coords=(t,y,z), label_offset=0.4) # the coordinate x is skipped
|
|
922
|
+
sage: gX = X.plot(X, ambient_coords=(t,y,z), number_values=5) # long time
|
|
923
|
+
sage: g + gX # 3D plot # long time
|
|
924
|
+
Graphics3d Object
|
|
925
|
+
sage: g = p.plot(X, ambient_coords=(y,z), label_offset=0.4) # the coordinates t and x are skipped
|
|
926
|
+
sage: gX = X.plot(X, ambient_coords=(y,z))
|
|
927
|
+
sage: g + gX # 2D plot
|
|
928
|
+
Graphics object consisting of 20 graphics primitives
|
|
929
|
+
|
|
930
|
+
.. PLOT::
|
|
931
|
+
|
|
932
|
+
M = Manifold(4, 'M', structure='topological')
|
|
933
|
+
X = M.chart('t x y z'); t,x,y,z = X[:]
|
|
934
|
+
p = M.point((1,2,3,4), name='p')
|
|
935
|
+
g = p.plot(X, ambient_coords=(y,z), label_offset=0.4)
|
|
936
|
+
gX = X.plot(X, ambient_coords=(y,z))
|
|
937
|
+
sphinx_plot(g+gX)
|
|
938
|
+
"""
|
|
939
|
+
from sage.manifolds.chart import Chart
|
|
940
|
+
from sage.plot.graphics import Graphics
|
|
941
|
+
from sage.plot.plot3d.shapes2 import point3d, text3d
|
|
942
|
+
from sage.plot.point import point2d
|
|
943
|
+
from sage.plot.text import text
|
|
944
|
+
if self._manifold.base_field_type() != 'real':
|
|
945
|
+
raise NotImplementedError('plot of points on manifolds over fields different'
|
|
946
|
+
' from the real field is not implemented')
|
|
947
|
+
# The ambient chart:
|
|
948
|
+
if chart is None:
|
|
949
|
+
chart = self.parent().default_chart()
|
|
950
|
+
elif not isinstance(chart, Chart):
|
|
951
|
+
raise TypeError("the argument 'chart' must be a coordinate chart")
|
|
952
|
+
# The effective point to be plotted:
|
|
953
|
+
if mapping is None:
|
|
954
|
+
eff_point = self
|
|
955
|
+
else:
|
|
956
|
+
eff_point = mapping(self)
|
|
957
|
+
# The coordinates of the ambient chart used for the plot:
|
|
958
|
+
if ambient_coords is None:
|
|
959
|
+
ambient_coords = chart[:]
|
|
960
|
+
elif not isinstance(ambient_coords, tuple):
|
|
961
|
+
ambient_coords = tuple(ambient_coords)
|
|
962
|
+
nca = len(ambient_coords)
|
|
963
|
+
if nca != 2 and nca != 3:
|
|
964
|
+
raise TypeError("invalid number of ambient coordinates: {}".format(nca))
|
|
965
|
+
|
|
966
|
+
# Extract the kwds options
|
|
967
|
+
size = kwds['size']
|
|
968
|
+
color = kwds['color']
|
|
969
|
+
label_color = kwds['label_color']
|
|
970
|
+
fontsize = kwds['fontsize']
|
|
971
|
+
label_offset = kwds['label_offset']
|
|
972
|
+
|
|
973
|
+
# The point coordinates:
|
|
974
|
+
coords = eff_point.coord(chart)
|
|
975
|
+
xx = chart[:]
|
|
976
|
+
xp = [coords[xx.index(c)] for c in ambient_coords]
|
|
977
|
+
if parameters is not None:
|
|
978
|
+
xps = [coord.substitute(parameters) for coord in xp]
|
|
979
|
+
xp = xps
|
|
980
|
+
xlab = [coord + label_offset for coord in xp]
|
|
981
|
+
if label_color is None:
|
|
982
|
+
label_color = color
|
|
983
|
+
resu = Graphics()
|
|
984
|
+
if nca == 2:
|
|
985
|
+
if label is None:
|
|
986
|
+
label = r'$' + self._latex_name + r'$'
|
|
987
|
+
resu += (point2d(xp, color=color, size=size) +
|
|
988
|
+
text(label, xlab, fontsize=fontsize, color=label_color))
|
|
989
|
+
else:
|
|
990
|
+
if label is None:
|
|
991
|
+
label = self._name
|
|
992
|
+
resu += (point3d(xp, color=color, size=size) +
|
|
993
|
+
text3d(label, xlab, fontsize=fontsize, color=label_color))
|
|
994
|
+
return resu
|