summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTravis Scrimshaw <tscrimsh at umn.edu>2016-05-07 09:53:06 -0500
committerTravis Scrimshaw <tscrimsh at umn.edu>2016-05-08 13:05:13 -0500
commitcfecb18d666ae132043fafe1d942762550bdbaa9 (patch)
tree795d04e7b95643414e91427947d1f08e9c94a4ed
parentMerge branch 'public/manifolds/top_manif_morphisms' of trac.sagemath.org:sage... (diff)
Reviewer changes and tweaks for continuous maps ticket.
-rw-r--r--src/sage/manifolds/chart.py250
-rw-r--r--src/sage/manifolds/continuous_map.py655
-rw-r--r--src/sage/manifolds/coord_func_symb.py3
-rw-r--r--src/sage/manifolds/manifold.py194
-rw-r--r--src/sage/manifolds/manifold_homset.py131
-rw-r--r--src/sage/manifolds/point.py96
-rw-r--r--src/sage/manifolds/scalarfield.py3
-rw-r--r--src/sage/manifolds/utilities.py47
8 files changed, 716 insertions, 663 deletions
diff --git a/src/sage/manifolds/chart.py b/src/sage/manifolds/chart.py
index bc081ab..3925e60 100644
--- a/src/sage/manifolds/chart.py
+++ b/src/sage/manifolds/chart.py
@@ -42,7 +42,7 @@ from sage.structure.unique_representation import UniqueRepresentation
from sage.symbolic.ring import SR
from sage.rings.infinity import Infinity
from sage.misc.latex import latex
-from sage.manifolds.coord_func_symb import CoordFunctionSymb
+from sage.misc.decorators import options
class Chart(UniqueRepresentation, SageObject):
r"""
@@ -313,7 +313,6 @@ class Chart(UniqueRepresentation, SageObject):
# subsets of self._domain, with the
# subsets as keys
# The null and one functions of the coordinates:
- base_field_type = self._domain.base_field_type()
# Expression in self of the zero and one scalar fields of open sets
# containing the domain of self:
for dom in self._domain._supersets:
@@ -547,10 +546,10 @@ class Chart(UniqueRepresentation, SageObject):
restrictions = [x > y, (x != 0, y != 0), z^2 < x]
- means (``x > y``) and ((``x != 0``) or (``y != 0``)) and
- (``z^2 < x``). If the list ``restrictions`` contains only one
- item, this item can be passed as such, i.e. writing ``x > y``
- instead of the single element list ``[x > y]``.
+ means ``(x > y) and ((x != 0) or (y != 0)) and (z^2 < x)``.
+ If the list ``restrictions`` contains only one item, this
+ item can be passed as such, i.e. writing ``x > y`` instead
+ of the single element list ``[x > y]``.
EXAMPLES::
@@ -570,7 +569,7 @@ class Chart(UniqueRepresentation, SageObject):
def restrict(self, subset, restrictions=None):
r"""
- Return the restriction of the chart to some open subset of its domain.
+ Return the restriction of ``self`` to some open subset of its domain.
If the current chart is `(U,\varphi)`, a *restriction* (or *subchart*)
is a chart `(V,\psi)` such that `V\subset U` and `\psi = \varphi |_V`.
@@ -596,14 +595,14 @@ class Chart(UniqueRepresentation, SageObject):
restrictions = [x > y, (x != 0, y != 0), z^2 < x]
- means (``x > y``) and ((``x != 0``) or (``y != 0``)) and
- (``z^2 < x``). If the list ``restrictions`` contains only one
- item, this item can be passed as such, i.e. writing ``x > y``
- instead of the single element list ``[x > y]``.
+ means ``(x > y) and ((x != 0) or (y != 0)) and (z^2 < x)``.
+ If the list ``restrictions`` contains only one item, this
+ item can be passed as such, i.e. writing ``x > y`` instead
+ of the single element list ``[x > y]``.
OUTPUT:
- - chart `(V,\psi)`, as an instance of :class:`Chart`.
+ - chart `(V, \psi)` as a :class:`Chart`
EXAMPLES:
@@ -756,15 +755,15 @@ class Chart(UniqueRepresentation, SageObject):
restrictions = [x > y, (x != 0, y != 0), z^2 < x]
- means (``x > y``) and ((``x != 0``) or (``y != 0``)) and
- (``z^2 < x``). If the list ``restrictions`` contains only one
- item, this item can be passed as such, i.e. writing ``x > y``
- instead of the single element list ``[x > y]``.
+ means ``(x > y) and ((x != 0) or (y != 0)) and (z^2 < x)``.
+ If the list ``restrictions`` contains only one item, this
+ item can be passed as such, i.e. writing ``x > y`` instead
+ of the single element list ``[x > y]``.
OUTPUT:
- the transition map `\psi \circ \varphi^{-1}` defined on
- `U \cap V`, as an instance of :class:`CoordChange`
+ `U \cap V` as a :class:`CoordChange`
EXAMPLES:
@@ -867,7 +866,7 @@ class Chart(UniqueRepresentation, SageObject):
& (x^1,\ldots, x^n) & \longmapsto & f(x^1,\ldots, x^n),
\end{array}
- where `V` is the chart codomain and `(x^1,\ldots, x^n)` are the
+ where `V` is the chart codomain and `(x^1, \ldots, x^n)` are the
chart coordinates.
The coordinate function can be either a symbolic one or a numerical
@@ -934,13 +933,13 @@ class Chart(UniqueRepresentation, SageObject):
where `V` is the chart codomain.
- See class :class:`~sage.manifolds.coord_func_symb.CoorFunctionSymb`
+ See class :class:`~sage.manifolds.coord_func_symb.CoordFunctionSymb`
for a complete documentation.
+
OUTPUT:
- - instance of class
- :class:`~sage.manifolds.coord_func_symb.CoorFunctionSymb`
- representing the zero coordinate function `f`.
+ - a :class:`~sage.manifolds.coord_func_symb.CoordFunctionSymb`
+ representing the zero coordinate function `f`
EXAMPLES::
@@ -988,13 +987,13 @@ class Chart(UniqueRepresentation, SageObject):
where `V` is the chart codomain.
- See class :class:`~sage.manifolds.coord_func_symb.CoorFunctionSymb`
+ See class :class:`~sage.manifolds.coord_func_symb.CoordFunctionSymb`
for a complete documentation.
+
OUTPUT:
- - instance of class
- :class:`~sage.manifolds.coord_func_symb.CoorFunctionSymb`
- representing the one coordinate function `f`.
+ - a :class:`~sage.manifolds.coord_func_symb.CoordFunctionSymb`
+ representing the one coordinate function `f`
EXAMPLES::
@@ -1046,7 +1045,7 @@ class Chart(UniqueRepresentation, SageObject):
where `V` is the codomain of `\varphi`. In other words, `f` is a
`K^m`-valued function of the coordinates associated to the chart
- `(U,\varphi)`.
+ `(U, \varphi)`.
See :class:`~sage.manifolds.coord_func.MultiCoordFunction` for a
complete documentation.
@@ -1583,10 +1582,10 @@ class RealChart(Chart):
restrictions = [x > y, (x != 0, y != 0), z^2 < x]
- means (``x > y``) and ((``x != 0``) or (``y != 0``)) and
- (``z^2 < x``). If the list ``restrictions`` contains only one
- item, this item can be passed as such, i.e. writing ``x > y``
- instead of the single element list ``[x > y]``.
+ means ``(x > y) and ((x != 0) or (y != 0)) and (z^2 < x)``.
+ If the list ``restrictions`` contains only one item, this
+ item can be passed as such, i.e. writing ``x > y`` instead
+ of the single element list ``[x > y]``.
EXAMPLES:
@@ -1681,8 +1680,8 @@ class RealChart(Chart):
r"""
Return the restriction of the chart to some open subset of its domain.
- If the current chart is `(U,\varphi)`, a *restriction* (or *subchart*)
- is a chart `(V,\psi)` such that `V\subset U` and `\psi = \varphi |_V`.
+ If the current chart is `(U, \varphi)`, a *restriction* (or *subchart*)
+ is a chart `(V, \psi)` such that `V \subset U` and `\psi = \varphi|_V`.
If such subchart has not been defined yet, it is constructed here.
@@ -1705,14 +1704,14 @@ class RealChart(Chart):
restrictions = [x > y, (x != 0, y != 0), z^2 < x]
- means (``x > y``) and ((``x != 0``) or (``y != 0``)) and
- (``z^2 < x``). If the list ``restrictions`` contains only one
- item, this item can be passed as such, i.e. writing ``x > y``
- instead of the single element list ``[x > y]``.
+ means ``(x > y) and ((x != 0) or (y != 0)) and (z^2 < x)``.
+ If the list ``restrictions`` contains only one item, this
+ item can be passed as such, i.e. writing ``x > y`` instead
+ of the single element list ``[x > y]``.
OUTPUT:
- - chart `(V,\psi)`, as an instance of :class:`RealChart`.
+ - the chart `(V, \psi)` as a :class:`RealChart`
EXAMPLES:
@@ -1730,7 +1729,7 @@ class RealChart(Chart):
sage: q in D
False
- Cartesian coordinates on the annulus `1 < \sqrt{x^2+y^2} < 2`::
+ Cartesian coordinates on the annulus `1 < \sqrt{x^2 + y^2} < 2`::
sage: A = M.open_subset('A')
sage: c_cart_A = c_cart.restrict(A, [x^2+y^2>1, x^2+y^2<4])
@@ -1864,22 +1863,22 @@ class RealChart(Chart):
# All tests have been passed:
return True
+ @options(color='red', style='-', thickness=1, plot_points=75, label_axes=True)
def plot(self, chart=None, ambient_coords=None, mapping=None,
fixed_coords=None, ranges=None, max_range=8, nb_values=None,
- steps=None, parameters=None, color='red', style='-', thickness=1,
- plot_points=75, label_axes=True):
+ steps=None, parameters=None, **kwds):
r"""
- Plot the current chart as a "grid" in a Cartesian graph
- based on the coordinates of some ambient chart.
+ Plot ``self`` as a grid in a Cartesian graph based on
+ the coordinates of some ambient chart.
- The "grid" is formed by curves along which a chart coordinate
- varies, the other coordinates being kept fixed; it is drawn in terms of
- two (2D graphics) or three (3D graphics) coordinates of another chart,
- called hereafter the *ambient chart*.
+ The grid is formed by curves along which a chart coordinate
+ varies, the other coordinates being kept fixed. It is drawn in
+ terms of two (2D graphics) or three (3D graphics) coordinates
+ of another chart, called hereafter the *ambient chart*.
The ambient chart is related to the current chart either by
- a transition map if both charts are defined on the same manifold, or by
- the coordinate expression of some continuous map (typically an
+ a transition map if both charts are defined on the same manifold,
+ or by the coordinate expression of some continuous map (typically an
immersion). In the latter case, the two charts may be defined on two
different manifolds.
@@ -1887,31 +1886,32 @@ class RealChart(Chart):
- ``chart`` -- (default: ``None``) the ambient chart (see above); if
``None``, the ambient chart is set to the current chart
- - ``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``) continuous manifold map (instance
- of :class:`~sage.manifolds.continuous_map.ContinuousMap`)
- providing the link between the current chart and the ambient chart
- (cf. above); if ``None``, both charts are supposed to be defined on
- the same manifold and related by some transition map (see
- :meth:`~sage.manifolds.chart.Chart.transition_map`)
+ - ``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 providing the link between the current chart and the
+ ambient chart (cf. above); if ``None``, both charts are supposed
+ to be defined on the same manifold and related by some transition
+ map (see :meth:`~sage.manifolds.chart.Chart.transition_map`)
- ``fixed_coords`` -- (default: ``None``) dictionary with keys the
chart coordinates that are not drawn and with values the fixed
value of these coordinates; if ``None``, all the coordinates of the
current chart are drawn
- - ``ranges`` -- (default: ``None``) dictionary with keys the coordinates
- to be drawn and values tuples ``(x_min,x_max)`` specifying the
- coordinate range for the plot; if ``None``, the entire coordinate
- range declared during the chart construction is considered (with
- -Infinity replaced by ``-max_range`` and +Infinity by ``max_range``)
+ - ``ranges`` -- (default: ``None``) dictionary with keys the
+ coordinates to be drawn and values tuples ``(x_min, x_max)``
+ specifying the coordinate range for the plot; if ``None``, the
+ entire coordinate range declared during the chart construction
+ is considered (with ``-Infinity`` replaced by ``-max_range``
+ and ``+Infinity`` by ``max_range``)
- ``max_range`` -- (default: 8) numerical value substituted to
+Infinity if the latter is the upper bound of the range of a
coordinate for which the plot is performed over the entire coordinate
range (i.e. for which no specific plot range has been set in
``ranges``); similarly ``-max_range`` is the numerical valued
- substituted for -Infinity
+ substituted for ``-Infinity``
- ``nb_values`` -- (default: ``None``) either an integer or a dictionary
with keys the coordinates to be drawn and values the number of
constant values of the coordinate to be considered; if ``nb_values``
@@ -1927,16 +1927,17 @@ class RealChart(Chart):
- ``parameters`` -- (default: ``None``) dictionary giving the numerical
values of the parameters that may appear in the relation between
the two coordinate systems
- - ``color`` -- (default: 'red') either a single color or a dictionary
- of colors, with keys the coordinates to be drawn, representing the
- colors of the lines along which the coordinate varies, the other
- being kept constant; if ``color`` is a single color, it is used for
- all coordinate lines
- - ``style`` -- (default: '-') either a single line style or a dictionary
- of line styles, with keys the coordinates to be drawn, representing
- the style of the lines along which the coordinate varies, the other
- being kept constant; if ``style`` is a single style, it is used for
- all coordinate lines; NB: ``style`` is effective only for 2D plots
+ - ``color`` -- (default: ``'red'``) either a single color or a
+ dictionary of colors, with keys the coordinates to be drawn,
+ representing the colors of the lines along which the coordinate
+ varies, the other being kept constant; if ``color`` is a single
+ color, it is used for all coordinate lines
+ - ``style`` -- (default: ``'-'``) either a single line style or
+ a dictionary of line styles, with keys the coordinates to be
+ drawn, representing the style of the lines along which the
+ coordinate varies, the other being kept constant; if ``style``
+ is a single style, it is used for all coordinate lines;
+ NB: ``style`` is effective only for 2D plots
- ``thickness`` -- (default: 1) either a single line thickness or a
dictionary of line thicknesses, with keys the coordinates to be drawn,
representing the thickness of the lines along which the coordinate
@@ -1949,16 +1950,15 @@ class RealChart(Chart):
is a single integer, it is used for all coordinate lines
- ``label_axes`` -- (default: ``True``) boolean determining whether the
labels of the ambient coordinate axes shall be added to the graph;
- can be set to False if the graph is 3D and must be superposed with
- another graph.
+ can be set to ``False`` if the graph is 3D and must be superposed
+ with another graph
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)
+ - a graphic object, either a :class:`~sage.plot.graphics.Graphics`
+ for a 2D plot (i.e. based on 2 coordinates of the ambient chart)
+ or a :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot
+ (i.e. based on 3 coordinates of the ambient chart)
EXAMPLES:
@@ -1971,9 +1971,8 @@ class RealChart(Chart):
sage: c_pol.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') # polar coordinates on U
sage: pol_to_cart = c_pol.transition_map(c_cart, [r*cos(ph), r*sin(ph)])
sage: g = c_pol.plot(c_cart)
- sage: type(g)
- <class 'sage.plot.graphics.Graphics'>
- sage: show(g) # graphical display
+ sage: g
+ Graphics object consisting of 18 graphics primitives
.. PLOT::
@@ -2033,7 +2032,8 @@ class RealChart(Chart):
grid::
sage: g = c_cart.plot() # equivalent to c_cart.plot(c_cart)
- sage: show(g) # a rectangular grid
+ sage: g # a rectangular grid
+ Graphics object consisting of 18 graphics primitives
.. PLOT::
@@ -2063,29 +2063,31 @@ class RealChart(Chart):
....: 2*v/(1+u^2+v^2), (1-u^2-v^2)/(1+u^2+v^2)]},
....: name='Phi', latex_name=r'\Phi') # Embedding of S^2 in R^3
sage: g = c_xy.plot(c_cart, mapping=Phi)
- sage: show(g) # 3D graphic display
+ sage: g
+ Graphics3d Object
sage: type(g)
<class 'sage.plot.plot3d.base.Graphics3dGroup'>
- The same plot without the (X,Y,Z) axes labels::
+ The same plot without the ``(X,Y,Z)`` axes labels::
sage: g = c_xy.plot(c_cart, mapping=Phi, label_axes=False)
The North and South stereographic charts on the same plot::
sage: g2 = c_uv.plot(c_cart, mapping=Phi, color='green')
- sage: show(g+g2)
+ sage: g + g2
+ Graphics3d Object
South stereographic chart drawned in terms of the North one (we split
- the plot in four parts to avoid the singularity at (u,v)=(0,0))::
+ the plot in four parts to avoid the singularity at `(u,v)=(0,0)`)::
sage: W = U.intersection(V) # the subset common to both charts
sage: c_uvW = c_uv.restrict(W) # chart (W,(u,v))
- sage: gSN1 = c_uvW.plot(c_xy, ranges={u:[-6.,-0.02], v:[-6.,-0.02]})
- sage: gSN2 = c_uvW.plot(c_xy, ranges={u:[-6.,-0.02], v:[0.02,6.]})
- sage: gSN3 = c_uvW.plot(c_xy, ranges={u:[0.02,6.], v:[-6.,-0.02]})
- sage: gSN4 = c_uvW.plot(c_xy, ranges={u:[0.02,6.], v:[0.02,6.]})
- sage: show(gSN1+gSN2+gSN3+gSN4, xmin=-1.5, xmax=1.5, ymin=-1.5, ymax=1.5)
+ sage: gSN1 = c_uvW.plot(c_xy, ranges={u:[-6.,-0.02], v:[-6.,-0.02]}) # long time
+ sage: gSN2 = c_uvW.plot(c_xy, ranges={u:[-6.,-0.02], v:[0.02,6.]}) # long time
+ sage: gSN3 = c_uvW.plot(c_xy, ranges={u:[0.02,6.], v:[-6.,-0.02]}) # long time
+ sage: gSN4 = c_uvW.plot(c_xy, ranges={u:[0.02,6.], v:[0.02,6.]}) # long time
+ sage: show(gSN1+gSN2+gSN3+gSN4, xmin=-1.5, xmax=1.5, ymin=-1.5, ymax=1.5) # long time
.. PLOT::
@@ -2105,12 +2107,13 @@ class RealChart(Chart):
g = gSN1+gSN2+gSN3+gSN4; g.set_axes_range(-1.5, 1.5, -1.5, 1.5)
sphinx_plot(g)
- The coordinate line u=1 (red) and the coordinate line v=1 (green) on
- the same plot::
+ The coordinate line `u = 1` (red) and the coordinate line `v = 1`
+ (green) on the same plot::
- sage: gu1 = c_uvW.plot(c_xy, fixed_coords={u: 1}, max_range=20, plot_points=300)
- sage: gv1 = c_uvW.plot(c_xy, fixed_coords={v: 1}, max_range=20, plot_points=300, color='green')
- sage: show(gu1+gv1)
+ sage: gu1 = c_uvW.plot(c_xy, fixed_coords={u: 1}, max_range=20, plot_points=300) # long time
+ sage: gv1 = c_uvW.plot(c_xy, fixed_coords={v: 1}, max_range=20, plot_points=300, color='green') # long time
+ sage: gu1 + gv1 # long time
+ Graphics object consisting of 2 graphics primitives
.. PLOT::
@@ -2127,15 +2130,16 @@ class RealChart(Chart):
gv1 = c_uvW.plot(c_xy, fixed_coords={v: 1}, max_range=20, plot_points=300, color='green')
sphinx_plot(gu1+gv1)
- Note that we have set ``max_range=20`` to have a wider range for the
- coordinates u and v, i.e. to have [-20,20] instead of the default
- [-8,8].
+ Note that we have set ``max_range=20`` to have a wider range for
+ the coordinates `u` and `v`, i.e. to have `[-20, 20]` instead of
+ the default `[-8, 8]`.
A 3-dimensional chart plotted in terms of itself results in a 3D
rectangular grid::
- sage: g = c_cart.plot() # equivalent to c_cart.plot(c_cart)
- sage: show(g) # a 3D mesh cube
+ sage: g = c_cart.plot() # equivalent to c_cart.plot(c_cart) # long time
+ sage: g # a 3D mesh cube # long time
+ Graphics3d Object
A 4-dimensional chart plotted in terms of itself (the plot is
performed for at most 3 coordinates, which must be specified via
@@ -2143,10 +2147,12 @@ class RealChart(Chart):
sage: M = Manifold(4, 'M', structure='topological')
sage: X.<t,x,y,z> = M.chart()
- sage: g = X.plot(ambient_coords=(t,x,y)) # the coordinate z is not depicted
- sage: show(g) # a 3D mesh cube
+ sage: g = X.plot(ambient_coords=(t,x,y)) # the coordinate z is not depicted # long time
+ sage: g # a 3D mesh cube # long time
+ Graphics3d Object
sage: g = X.plot(ambient_coords=(t,y)) # the coordinates x and z are not depicted
- sage: show(g) # a 2D mesh square
+ sage: g # a 2D mesh square
+ Graphics object consisting of 18 graphics primitives
.. PLOT::
@@ -2162,6 +2168,13 @@ class RealChart(Chart):
from sage.manifolds.continuous_map import ContinuousMap
from utilities import set_axes_labels
+ # Extract the kwds options
+ color = kwds['color']
+ style = kwds['style']
+ thickness = kwds['thickness']
+ plot_points = kwds['plot_points']
+ label_axes = kwds['label_axes']
+
def _plot_xx_list(xx_list, rem_coords, ranges, steps, nb_values):
r"""
Helper function to plot the coordinate grid.
@@ -2196,8 +2209,7 @@ class RealChart(Chart):
transf = self.multifunction(*(self._xx))
if nc > 3:
if ambient_coords is None:
- raise TypeError("the argument 'ambient_coords' must be " +
- "provided")
+ raise TypeError("the argument 'ambient_coords' must be provided")
if len(ambient_coords) > 3:
raise ValueError("too many ambient coordinates")
fixed_coords = {}
@@ -2224,7 +2236,7 @@ class RealChart(Chart):
transf = coord_changes[chart_pair]._transf
else:
if not isinstance(mapping, ContinuousMap):
- raise TypeError("the argument 'mapping' must be a " +
+ raise TypeError("the argument 'mapping' must be a "
"continuous manifold map")
if not self._domain.is_subset(mapping._domain):
raise ValueError("the domain of {} is not ".format(self) +
@@ -2296,11 +2308,12 @@ class RealChart(Chart):
steps = {}
for coord in coords:
if coord not in steps:
- steps[coord] = (ranges[coord][1] - ranges[coord][0])/ \
- (nb_values[coord]-1)
+ steps[coord] = ((ranges[coord][1] - ranges[coord][0])
+ / (nb_values[coord]-1))
else:
- nb_values[coord] = 1 + int(
- (ranges[coord][1] - ranges[coord][0])/ steps[coord])
+ from sage.functions.other import floor
+ nb_values[coord] = 1 + floor((ranges[coord][1] - ranges[coord][0])
+ / steps[coord])
if not isinstance(color, dict):
color0 = {}
for coord in coords:
@@ -2377,9 +2390,8 @@ class RealChart(Chart):
if self.valid_coordinates(*xp, tolerance=1e-13,
parameters=parameters):
yp = transf(*xp, simplify=False)
- curve.append(
- [numerical_approx( yp[j].substitute(parameters) )
- for j in ind_a] )
+ curve.append([numerical_approx(yp[j].substitute(parameters))
+ for j in ind_a])
first_invalid = True # next invalid point will be
# the first one
else:
@@ -2398,7 +2410,7 @@ class RealChart(Chart):
resu += line(curve, color=color_c,
linestyle=style_c,
thickness=thickness_c)
- if nca==2: # 2D graphic
+ if nca == 2: # 2D graphic
resu.set_aspect_ratio(1)
if label_axes:
# We update the dictionary _extra_kwds (options to be passed
diff --git a/src/sage/manifolds/continuous_map.py b/src/sage/manifolds/continuous_map.py
index 149041f..dcb5992 100644
--- a/src/sage/manifolds/continuous_map.py
+++ b/src/sage/manifolds/continuous_map.py
@@ -1,9 +1,9 @@
r"""
-Continuous Maps between Topological Manifolds
+Continuous Maps Between Topological Manifolds
-The class :class:`ContinuousMap` implements continuous maps from a topological
-manifold `M` to some topological manifold `N` over the same topological field
-`K` as `M`.
+:class:`ContinuousMap` implements continuous maps from a topological
+manifold `M` to some topological manifold `N` over the same topological
+field `K` as `M`.
AUTHORS:
@@ -22,9 +22,10 @@ REFERENCES:
# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
#
-# 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.
+# 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/
#*****************************************************************************
@@ -39,46 +40,46 @@ class ContinuousMap(Morphism):
.. MATH::
- \Phi: M \longrightarrow N
+ \Phi: M \longrightarrow N,
- where `M` and `N` are topological manifolds over the same topological
- field `K`.
+ where `M` and `N` are topological manifolds over the same
+ topological field `K`.
- Continuous maps are the *morphisms* of the *category* of topological
- manifolds. The set of all continuous maps from `M` to `N` is therefore the
- homset between `M` and `N`, which is denoted by `\mathrm{Hom}(M,N)`.
+ Continuous maps are the morphisms of the category of topological
+ manifolds. The set of all continuous maps from `M` to `N` is
+ therefore the homset between `M` and `N`, which is denoted
+ by `\mathrm{Hom}(M,N)`.
- The class :class:`ContinuousMap` is a Sage *element* class, whose *parent*
- class is :class:`~sage.manifolds.manifold_homset.TopologicalManifoldHomset`.
+ The class :class:`ContinuousMap` is a Sage *element* class,
+ whose *parent* class is
+ :class:`~sage.manifolds.manifold_homset.TopologicalManifoldHomset`.
INPUT:
- ``parent`` -- homset `\mathrm{Hom}(M,N)` to which the continuous
map belongs
- - ``coord_functions`` -- (default: ``None``) if not ``None``, must be
- a dictionary of the coordinate expressions (as lists (or tuples) of the
- coordinates of the image expressed in terms of the coordinates of
- the considered point) with the pairs of charts (chart1, chart2)
- as keys (chart1 being a chart on `M` and chart2 a chart on `N`).
- If the dimension of the map's codomain is 1, a single coordinate
- expression can be passed instead of a tuple with a single element
- - ``name`` -- (default: ``None``) name given to the continuous map
+ - ``coord_functions`` -- a dictionary of the coordinate expressions
+ (as lists or tuples of the coordinates of the image expressed in
+ terms of the coordinates of the considered point) with the pairs
+ of charts ``(chart1, chart2)`` as keys (``chart1`` being a chart
+ on `M` and ``chart2`` a chart on `N`)
+ - ``name`` -- (default: ``None``) name given to ``self``
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
continuous map; if ``None``, the LaTeX symbol is set to
``name``
- ``is_isomorphism`` -- (default: ``False``) determines whether the
constructed object is a isomorphism (i.e. a homeomorphism); if set to
- ``True``, then the manifolds `M` and `N` must have the same dimension.
+ ``True``, then the manifolds `M` and `N` must have the same dimension
- ``is_identity`` -- (default: ``False``) determines whether the
constructed object is the identity map; if set to ``True``,
- then `N` must be `M` and the entry ``coord_functions`` is not used.
+ then `N` must be `M` and the entry ``coord_functions`` is not used
.. NOTE::
- If the information passed by means of the argument ``coord_functions``
- is not sufficient to fully specify the continuous map,
- further coordinate expressions, in other charts, can be subsequently
- added by means of the method :meth:`add_expr`
+ If the information passed by means of the argument
+ ``coord_functions`` is not sufficient to fully specify the
+ continuous map, further coordinate expressions, in other charts,
+ can be subsequently added by means of the method :meth:`add_expr`.
EXAMPLES:
@@ -91,22 +92,23 @@ class ContinuousMap(Morphism):
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)
+ ....: intersection_name='W',
+ ....: restrictions1=x^2+y^2!=0,
+ ....: restrictions2=u^2+v^2!=0)
sage: uv_to_xy = xy_to_uv.inverse()
sage: N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological') # R^3
sage: c_cart.<X,Y,Z> = N.chart() # Cartesian coordinates on R^3
sage: Phi = M.continuous_map(N,
- ....: {(c_xy, c_cart): [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)],
- ....: (c_uv, c_cart): [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2), (1-u^2-v^2)/(1+u^2+v^2)]},
- ....: name='Phi', latex_name=r'\Phi')
+ ....: {(c_xy, c_cart): [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)],
+ ....: (c_uv, c_cart): [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2), (1-u^2-v^2)/(1+u^2+v^2)]},
+ ....: name='Phi', latex_name=r'\Phi')
sage: Phi
- Continuous map Phi from the 2-dimensional topological manifold S^2 to
- the 3-dimensional topological manifold R^3
+ Continuous map Phi from the 2-dimensional topological manifold S^2
+ to the 3-dimensional topological manifold R^3
sage: Phi.parent()
- Set of Morphisms from 2-dimensional topological manifold S^2 to
- 3-dimensional topological manifold R^3 in Category of manifolds over
- Real Field with 53 bits of precision
+ Set of Morphisms from 2-dimensional topological manifold S^2
+ to 3-dimensional topological manifold R^3
+ in Category of manifolds over Real Field with 53 bits of precision
sage: Phi.parent() is Hom(M, N)
True
sage: type(Phi)
@@ -116,31 +118,32 @@ class ContinuousMap(Morphism):
on U: (x, y) |--> (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1), (x^2 + y^2 - 1)/(x^2 + y^2 + 1))
on V: (u, v) |--> (X, Y, Z) = (2*u/(u^2 + v^2 + 1), 2*v/(u^2 + v^2 + 1), -(u^2 + v^2 - 1)/(u^2 + v^2 + 1))
- It is possible to create the map via the method
+ It is possible to create the map using
:meth:`~sage.manifolds.manifold.TopologicalManifold.continuous_map`
- only in a single pair of charts: the argument ``coord_functions`` is then
- a mere list of coordinate expressions (and not a dictionary) and the
- arguments ``chart1`` and ``chart2`` have to be provided if the charts
- differ from the default ones on the domain and/or the codomain::
+ with only in a single pair of charts. The argument ``coord_functions``
+ is then a mere list of coordinate expressions (and not a dictionary)
+ and the arguments ``chart1`` and ``chart2`` have to be provided if
+ the charts differ from the default ones on the domain and/or codomain::
- sage: Phi1 = M.continuous_map(N, [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)], \
- ....: chart1=c_xy, chart2=c_cart, name='Phi', latex_name=r'\Phi')
+ sage: Phi1 = M.continuous_map(N, [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)],
+ ....: chart1=c_xy, chart2=c_cart,
+ ....: name='Phi', latex_name=r'\Phi')
- Since c_xy and c_cart are the default charts on respectively ``M`` and
- ``N``, they can be omitted, so that the above declaration is equivalent
- to::
+ Since ``c_xy`` and ``c_cart`` are the default charts on respectively
+ ``M`` and ``N``, they can be omitted, so that the above declaration
+ is equivalent to::
- sage: Phi1 = M.continuous_map(N, [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)], \
- ....: name='Phi', latex_name=r'\Phi')
+ sage: Phi1 = M.continuous_map(N, [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)],
+ ....: name='Phi', latex_name=r'\Phi')
- With such a declaration, the continuous map is only partially defined
- on the manifold `S^2`, being known in only one chart::
+ With such a declaration, the continuous map ``Phi1`` is only partially
+ defined on the manifold `S^2` as it is known in only one chart::
sage: Phi1.display()
Phi: S^2 --> R^3
on U: (x, y) |--> (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1), (x^2 + y^2 - 1)/(x^2 + y^2 + 1))
- The definition can be completed by means of the method :meth:`add_expr`::
+ The definition can be completed by using :meth:`add_expr`::
sage: Phi1.add_expr(c_uv, c_cart, [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2), (1-u^2-v^2)/(1+u^2+v^2)])
sage: Phi1.display()
@@ -153,44 +156,44 @@ class ContinuousMap(Morphism):
sage: Phi1 == Phi
True
- The test suite is passed::
-
- sage: TestSuite(Phi).run()
- sage: TestSuite(Phi1).run()
-
The map acts on points::
sage: np = M.point((0,0), chart=c_uv) # the North pole
sage: Phi(np)
Point on the 3-dimensional topological manifold R^3
- sage: Phi(np).coord() # Cartesian coordinates
+ sage: Phi(np).coord() # Cartesian coordinates
(0, 0, 1)
sage: sp = M.point((0,0), chart=c_xy) # the South pole
- sage: Phi(sp).coord() # Cartesian coordinates
+ sage: Phi(sp).coord() # Cartesian coordinates
(0, 0, -1)
- Continuous maps can be composed by means of the operator ``*``: let
- us introduce the map `\RR^3\rightarrow \RR^2` corresponding to
- the projection from the point `(X,Y,Z)=(0,0,1)` onto the equatorial plane
- `Z=0`::
+ The test suite is passed::
+
+ sage: TestSuite(Phi).run()
+ sage: TestSuite(Phi1).run()
+
+ Continuous maps can be composed by means of the operator ``*``.
+ Let us introduce the map `\RR^3 \to \RR^2` corresponding to
+ the projection from the point `(X, Y, Z) = (0, 0, 1)` onto the
+ equatorial plane `Z = 0`::
sage: P = Manifold(2, 'R^2', latex_name=r'\RR^2', structure='topological') # R^2 (equatorial plane)
sage: cP.<xP, yP> = P.chart()
sage: Psi = N.continuous_map(P, (X/(1-Z), Y/(1-Z)), name='Psi',
....: latex_name=r'\Psi')
sage: Psi
- Continuous map Psi from the 3-dimensional topological manifold R^3 to
- the 2-dimensional topological manifold R^2
+ Continuous map Psi from the 3-dimensional topological manifold R^3
+ to the 2-dimensional topological manifold R^2
sage: Psi.display()
Psi: R^3 --> R^2
(X, Y, Z) |--> (xP, yP) = (-X/(Z - 1), -Y/(Z - 1))
Then we compose ``Psi`` with ``Phi``, thereby getting a map
- `S^2\rightarrow \RR^2`::
+ `S^2 \to \RR^2`::
- sage: ster = Psi*Phi ; ster
- Continuous map from the 2-dimensional topological manifold S^2 to the
- 2-dimensional topological manifold R^2
+ sage: ster = Psi * Phi ; ster
+ Continuous map from the 2-dimensional topological manifold S^2
+ to the 2-dimensional topological manifold R^2
Let us test on the South pole (``sp``) that ``ster`` is indeed the
composite of ``Psi`` and ``Phi``::
@@ -198,44 +201,49 @@ class ContinuousMap(Morphism):
sage: ster(sp) == Psi(Phi(sp))
True
- Actually ``ster`` is the stereographic projection from the North pole, as
- its coordinate expression reveals::
+ Actually ``ster`` is the stereographic projection from the North pole,
+ as its coordinate expression reveals::
sage: ster.display()
S^2 --> R^2
on U: (x, y) |--> (xP, yP) = (x, y)
on V: (u, v) |--> (xP, yP) = (u/(u^2 + v^2), v/(u^2 + v^2))
- If its codomain is 1-dimensional, a continuous map must be
- defined by a single symbolic expression for each pair of charts, and not
- by a list/tuple with a single element::
+ If the codomain of a continuous map is 1-dimensional, the map can
+ be defined by a single symbolic expression for each pair of charts
+ and not by a list/tuple with a single element::
sage: N = Manifold(1, 'N', structure='topological')
sage: c_N = N.chart('X')
- sage: Phi = M.continuous_map(N, {(c_xy, c_N): x^2+y^2, \
- ....: (c_uv, c_N): 1/(u^2+v^2)}) # not ...[1/(u^2+v^2)] or (1/(u^2+v^2),)
+ sage: Phi = M.continuous_map(N, {(c_xy, c_N): x^2+y^2,
+ ....: (c_uv, c_N): 1/(u^2+v^2)})
- An example of continuous map `\RR \rightarrow \RR^2`::
+ sage: Psi = M.continuous_map(N, {(c_xy, c_N): [x^2+y^2],
+ ....: (c_uv, c_N): [1/(u^2+v^2)]})
+ sage: Phi == Psi
+ True
+
+ Next we construct an example of continuous map `\RR \to \RR^2`::
sage: R = Manifold(1, 'R', structure='topological') # field R
sage: T.<t> = R.chart() # canonical chart on R
sage: R2 = Manifold(2, 'R^2', structure='topological') # R^2
sage: c_xy.<x,y> = R2.chart() # Cartesian coordinates on R^2
- sage: Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi') ; Phi
- Continuous map Phi from the 1-dimensional topological manifold R to
- the 2-dimensional topological manifold R^2
+ sage: Phi = R.continuous_map(R2, [cos(t), sin(t)], name='Phi'); Phi
+ Continuous map Phi from the 1-dimensional topological manifold R
+ to the 2-dimensional topological manifold R^2
sage: Phi.parent()
- Set of Morphisms from 1-dimensional topological manifold R to
- 2-dimensional topological manifold R^2 in Category of manifolds over
- Real Field with 53 bits of precision
+ Set of Morphisms from 1-dimensional topological manifold R
+ to 2-dimensional topological manifold R^2
+ in Category of manifolds over Real Field with 53 bits of precision
sage: Phi.parent() is Hom(R, R2)
True
sage: Phi.display()
Phi: R --> R^2
t |--> (x, y) = (cos(t), sin(t))
- An example of homeomorphism between the unit open disk and the Euclidean
- plane `\RR^2`::
+ An example of homeomorphism between the unit open disk and the
+ Euclidean plane `\RR^2`::
sage: D = R2.open_subset('D', coord_def={c_xy: x^2+y^2<1}) # the open unit disk
sage: Phi = D.homeomorphism(R2, [x/sqrt(1-x^2-y^2), y/sqrt(1-x^2-y^2)],
@@ -262,8 +270,7 @@ class ContinuousMap(Morphism):
sage: q.coord()
(1/3*sqrt(3), 0)
- The inverse homeomorphism is computed by means of the method
- :meth:`inverse`::
+ The inverse homeomorphism is computed by :meth:`inverse`::
sage: Phi.inverse()
Homeomorphism Phi^(-1) from the 2-dimensional topological manifold R^2
@@ -272,8 +279,8 @@ class ContinuousMap(Morphism):
Phi^(-1): R^2 --> D
(x, y) |--> (x, y) = (x/sqrt(x^2 + y^2 + 1), y/sqrt(x^2 + y^2 + 1))
- Equivalently, one may use the notations ``^(-1)`` or ``~`` to get the
- inverse::
+ Equivalently, one may use the notations ``^(-1)`` or ``~`` to
+ get the inverse::
sage: Phi^(-1) is Phi.inverse()
True
@@ -338,7 +345,7 @@ class ContinuousMap(Morphism):
def __init__(self, parent, coord_functions=None, name=None, latex_name=None,
is_isomorphism=False, is_identity=False):
r"""
- Construct a continuous map.
+ Initialize ``self``.
TESTS::
@@ -347,8 +354,8 @@ class ContinuousMap(Morphism):
sage: N = Manifold(3, 'N', structure='topological')
sage: Y.<u,v,w> = N.chart()
sage: f = Hom(M,N)({(X,Y): (x+y, x*y, x-y)}, name='f') ; f
- Continuous map f from the 2-dimensional topological manifold M to
- the 3-dimensional topological manifold N
+ Continuous map f from the 2-dimensional topological manifold M
+ to the 3-dimensional topological manifold N
sage: f.display()
f: M --> N
(x, y) |--> (u, v, w) = (x + y, x*y, x - y)
@@ -380,8 +387,8 @@ class ContinuousMap(Morphism):
self._is_identity = True
self._is_isomorphism = True
if domain != codomain:
- raise ValueError("the domain and codomain must coincide " + \
- "for the identity map")
+ raise ValueError("the domain and codomain must coincide"
+ " for the identity map")
if name is None:
name = 'Id_' + domain._name
if latex_name is None:
@@ -397,23 +404,22 @@ class ContinuousMap(Morphism):
if is_isomorphism:
self._is_isomorphism = True
if domain.dim() != codomain.dim():
- raise ValueError("for an isomorphism, the source " +
- "manifold and target manifold must " +
- "have the same dimension")
+ raise ValueError("for an isomorphism, the source"
+ " manifold and target manifold must"
+ " have the same dimension")
if coord_functions is not None:
n2 = self._codomain.dim()
for chart_pair, expression in coord_functions.iteritems():
if chart_pair[0] not in self._domain.atlas():
raise ValueError("{} is not a chart ".format(
chart_pair[0]) +
- "defined on the {}".format(self._domain))
+ "defined on the {}".format(self._domain))
if chart_pair[1] not in self._codomain.atlas():
raise ValueError("{} is not a chart ".format(
chart_pair[1]) +
- "defined on the {}".format(self._codomain))
+ "defined on the {}".format(self._codomain))
if n2 == 1:
- # a single expression entry is allowed (instead of a
- # tuple)
+ # a single expression entry is allowed
if not isinstance(expression, (tuple, list)):
expression = (expression,)
if len(expression) != n2:
@@ -434,7 +440,7 @@ class ContinuousMap(Morphism):
def _repr_(self):
r"""
- String representation of the object.
+ Return a string representation of ``self``.
TESTS::
@@ -443,28 +449,27 @@ class ContinuousMap(Morphism):
sage: N = Manifold(2, 'N', structure='topological')
sage: Y.<u,v> = N.chart()
sage: f = Hom(M,N)({(X,Y): (x+y,x*y)})
- sage: f._repr_()
- 'Continuous map from the 2-dimensional topological manifold M to
- the 2-dimensional topological manifold N'
+ sage: f
+ Continuous map from the 2-dimensional topological manifold M
+ to the 2-dimensional topological manifold N
sage: f = Hom(M,N)({(X,Y): (x+y,x*y)}, name='f')
- sage: f._repr_()
- 'Continuous map f from the 2-dimensional topological manifold M to
- the 2-dimensional topological manifold N'
+ sage: f
+ Continuous map f from the 2-dimensional topological manifold M
+ to the 2-dimensional topological manifold N
sage: f = Hom(M,N)({(X,Y): (x+y,x-y)}, name='f', is_isomorphism=True)
- sage: f._repr_()
- 'Homeomorphism f from the 2-dimensional topological manifold M to
- the 2-dimensional topological manifold N'
+ sage: f
+ Homeomorphism f from the 2-dimensional topological manifold M
+ to the 2-dimensional topological manifold N
sage: f = Hom(M,M)({(X,X): (x+y,x-y)}, name='f', is_isomorphism=True)
- sage: f._repr_()
- 'Homeomorphism f of the 2-dimensional topological manifold M'
+ sage: f
+ Homeomorphism f of the 2-dimensional topological manifold M
sage: f = Hom(M,M)({}, name='f', is_identity=True)
- sage: f._repr_()
- 'Identity map f of the 2-dimensional topological manifold M'
+ sage: f
+ Identity map f of the 2-dimensional topological manifold M
"""
if self._is_identity:
- return "Identity map " + self._name + \
- " of the {}".format(self._domain)
+ return "Identity map {} of the {}".format(self._name, self._domain)
if self._is_isomorphism:
description = "Homeomorphism"
else:
@@ -483,18 +488,18 @@ class ContinuousMap(Morphism):
def _latex_(self):
r"""
- LaTeX representation of the object.
+ LaTeX representation of ``self``.
TESTS::
sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
sage: f = Hom(M,M)({(X,X): (x+y,x*y)}, name='f')
- sage: f._latex_()
- 'f'
+ sage: latex(f)
+ f
sage: f = Hom(M,M)({(X,X): (x+y,x*y)}, name='f', latex_name=r'\Phi')
- sage: f._latex_()
- '\\Phi'
+ sage: latex(f)
+ \Phi
"""
if self._latex_name is None:
@@ -508,12 +513,11 @@ class ContinuousMap(Morphism):
INPUT:
- - ``other`` -- another instance of :class:`ContinuousMap` to compare
- with
+ - ``other`` -- a :class:`ContinuousMap`
OUTPUT:
- - True if ``self`` is equal to ``other``, or False otherwise
+ - ``True`` if ``self`` is equal to ``other`` and ``False`` otherwise
TESTS::
@@ -554,12 +558,12 @@ class ContinuousMap(Morphism):
INPUT:
- - ``other`` -- another instance of :class:`ContinuousMap` to compare
- with
+ - ``other`` -- a :class:`ContinuousMap`
OUTPUT:
- - True if ``self`` is different from ``other``, or False otherwise
+ - ``True`` if ``self`` is different from ``other`` and
+ ``False`` otherwise
TESTS::
@@ -578,49 +582,22 @@ class ContinuousMap(Morphism):
"""
return not (self == other)
- def __cmp__(self, other):
- r"""
- Old-style (Python 2) comparison operator.
-
- This is provisory, until migration to Python 3 is achieved.
-
- TESTS::
-
- sage: M = Manifold(3, 'M', structure='topological')
- sage: X.<x,y,z> = M.chart()
- sage: N = Manifold(2, 'N', structure='topological')
- sage: Y.<u,v> = N.chart()
- sage: f = M.continuous_map(N, {(X,Y): [x+y+z, 2*x*y*z]}, name='f')
- sage: g = M.continuous_map(N, {(X,Y): [x+y+z, 2*x*y*z]}, name='g')
- sage: f.__cmp__(g)
- 0
- sage: g = M.continuous_map(N, {(X,Y): [x+y+z, 1]}, name='g')
- sage: f.__cmp__(g)
- -1
-
- """
- if self == other:
- return 0
- else:
- return -1
-
#
# Map methods
#
def _call_(self, point):
r"""
- Compute the image of a point by the continous map.
+ Compute the image of a point by ``self``.
INPUT:
- - ``point`` -- point in the domain of ``self``, as an instance of
- :class:`~sage.manifolds.point.TopologicalManifoldPoint`
+ - ``point`` -- :class:`~sage.manifolds.point.TopologicalManifoldPoint`;
+ point in the domain of ``self``
OUTPUT:
- - image of the point by ``self`` (instance of
- :class:`~sage.manifolds.point.TopologicalManifoldPoint`)
+ - image of the point by ``self``
EXAMPLES:
@@ -660,7 +637,6 @@ class ContinuousMap(Morphism):
# repeated here.
if self._is_identity:
return point
- dom = self._domain
chart1, chart2 = None, None
for chart in point._coordinates:
for chart_pair in self._coord_expression:
@@ -682,7 +658,7 @@ class ContinuousMap(Morphism):
break
else:
raise ValueError("no pair of charts has been found to " +
- "compute the action of the {} on the {}".format(self, point))
+ "compute the action of the {} on the {}".format(self, point))
coord_map = self._coord_expression[(chart1, chart2)]
y = coord_map(*(point._coordinates[chart1]))
if point._name is None or self._name is None:
@@ -692,8 +668,8 @@ class ContinuousMap(Morphism):
if point._latex_name is None or self._latex_name is None:
res_latex_name = None
else:
- res_latex_name = self._latex_name + r'\left(' + \
- point._latex_name + r'\right)'
+ res_latex_name = (self._latex_name + r'\left(' +
+ point._latex_name + r'\right)')
# The image point is created as an element of the domain of chart2:
dom2 = chart2.domain()
return dom2.element_class(dom2, coords=y, chart=chart2,
@@ -705,7 +681,7 @@ class ContinuousMap(Morphism):
def is_identity(self):
r"""
- Check whether the continuous map is an identity map.
+ Check whether ``self`` is an identity map.
EXAMPLES:
@@ -756,11 +732,11 @@ class ContinuousMap(Morphism):
Composition of ``self`` with another morphism.
The composition is performed on the right, i.e. the returned
- morphism is ``self*other``.
+ morphism is ``self * other``.
INPUT:
- - ``other`` -- a continuous map, whose codomain is the domain
+ - ``other`` -- a continuous map whose codomain is the domain
of ``self``
- ``homset`` -- the homset of the continuous map ``self*other``;
this argument is required to follow the prototype of
@@ -770,8 +746,8 @@ class ContinuousMap(Morphism):
OUTPUT:
- - the composite map ``self*other``, as an instance of
- :class:`~sage.manifolds.continuous_map.ContinuousMap`
+ - :class:`~sage.manifolds.continuous_map.ContinuousMap` that is
+ the composite map ``self * other``
TESTS::
@@ -784,7 +760,8 @@ class ContinuousMap(Morphism):
sage: f = N.continuous_map(Q, [u+v, u*v, 1+u, 2-v])
sage: g = M.continuous_map(N, [x+y+z, x*y*z])
sage: s = f._composition_(g, Hom(M,Q)); s
- Continuous map from the 3-dimensional topological manifold M to the 4-dimensional topological manifold Q
+ Continuous map from the 3-dimensional topological manifold M
+ to the 4-dimensional topological manifold Q
sage: s.display()
M --> Q
(x, y, z) |--> (a, b, c, d) = ((x*y + 1)*z + x + y, x*y*z^2 + (x^2*y + x*y^2)*z, x + y + z + 1, -x*y*z + 2)
@@ -806,9 +783,8 @@ class ContinuousMap(Morphism):
for chart3 in self._codomain._top_charts:
try:
self23 = self.coord_functions(chart2, chart3)
- resu_funct[(chart1, chart3)] = \
- self23(*(other.expr(chart1, chart2)),
- simplify=True)
+ resu_funct[(chart1, chart3)] = self23(*other.expr(chart1, chart2),
+ simplify=True)
except ValueError:
pass
return homset(resu_funct)
@@ -823,17 +799,17 @@ class ContinuousMap(Morphism):
This applies only when the parent of ``self`` is a monoid, i.e. when
``self`` is an endomorphism of the category of topological manifolds,
- i.e. a continuous map M --> M, where M is a topological manifold.
+ i.e. a continuous map `M \to M`, where `M` is a topological manifold.
INPUT:
- - ``other`` -- a continuous map, whose codomain is the domain
+ - ``other`` -- a continuous map whose codomain is the domain
of ``self``
OUTPUT:
- - the composite map ``self*other``, as an instance of
- :class:`~sage.manifolds.continuous_map.ContinuousMap`
+ - :class:`~sage.manifolds.continuous_map.ContinuousMap` that
+ is the composite map ``self * other``
TESTS::
@@ -842,8 +818,8 @@ class ContinuousMap(Morphism):
sage: f = M.continuous_map(M, [x+y, x*y], name='f')
sage: g = M.continuous_map(M, [1-y, 2+x], name='g')
sage: s = f._mul_(g); s
- Continuous map from the 2-dimensional topological manifold M to
- itself
+ Continuous map from the 2-dimensional topological manifold M
+ to itself
sage: s.display()
M --> M
(x, y) |--> (x - y + 3, -(x + 2)*y + x + 2)
@@ -855,7 +831,6 @@ class ContinuousMap(Morphism):
True
"""
- from sage.categories.homset import Hom
dom = self._domain
return self._composition_(other, Hom(dom, dom))
@@ -865,9 +840,9 @@ class ContinuousMap(Morphism):
def _init_derived(self):
r"""
- Initialize the derived quantities
+ Initialize the derived quantities of ``self``.
- TEST::
+ TESTS::
sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
@@ -887,7 +862,7 @@ class ContinuousMap(Morphism):
def _del_derived(self):
r"""
- Delete the derived quantities
+ Delete the derived quantities of ``self``.
TEST::
@@ -908,22 +883,21 @@ class ContinuousMap(Morphism):
def display(self, chart1=None, chart2=None):
r"""
- Display the expression of the continuous map in one or more
- pair of charts.
+ Display the expression of ``self`` in one or more pair of charts.
If the expression is not known already, it is computed from some
expression in other charts by means of change-of-coordinate formulas.
INPUT:
- - ``chart1`` -- (default: ``None``) chart on the map's domain; if
- ``None``, the display is performed on all the charts on the domain
- in which the map is known or computable via some change of
- coordinates
- - ``chart2`` -- (default: ``None``) chart on the map's codomain; if
- ``None``, the display is performed on all the charts on the codomain
- in which the map is known or computable via some change of
- coordinates
+ - ``chart1`` -- (default: ``None``) chart on the domain of ``self``;
+ if ``None``, the display is performed on all the charts on the
+ domain in which the map is known or computable via some change
+ of coordinates
+ - ``chart2`` -- (default: ``None``) chart on the codomain of ``self``;
+ if ``None``, the display is performed on all the charts on the
+ codomain in which the map is known or computable via some change
+ of coordinates
The output is either text-formatted (console mode) or LaTeX-formatted
(notebook mode).
@@ -940,10 +914,10 @@ class ContinuousMap(Morphism):
sage: M.declare_union(U,V) # S^2 is the union of U and V
sage: N = Manifold(3, 'R^3', latex_name=r'\RR^3', structure='topological') # R^3
sage: c_cart.<X,Y,Z> = N.chart() # Cartesian coordinates on R^3
- sage: Phi = M.continuous_map(N, \
- ....: {(c_xy, c_cart): [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)],
- ....: (c_uv, c_cart): [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2), (1-u^2-v^2)/(1+u^2+v^2)]},
- ....: name='Phi', latex_name=r'\Phi')
+ sage: Phi = M.continuous_map(N,
+ ....: {(c_xy, c_cart): [2*x/(1+x^2+y^2), 2*y/(1+x^2+y^2), (x^2+y^2-1)/(1+x^2+y^2)],
+ ....: (c_uv, c_cart): [2*u/(1+u^2+v^2), 2*v/(1+u^2+v^2), (1-u^2-v^2)/(1+u^2+v^2)]},
+ ....: name='Phi', latex_name=r'\Phi')
sage: Phi.display(c_xy, c_cart)
Phi: S^2 --> R^3
on U: (x, y) |--> (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1), (x^2 + y^2 - 1)/(x^2 + y^2 + 1))
@@ -954,19 +928,24 @@ class ContinuousMap(Morphism):
The LaTeX output::
sage: latex(Phi.display(c_xy, c_cart))
- \begin{array}{llcl} \Phi:& S^2 & \longrightarrow & \RR^3 \\ \mbox{on}\ U : & \left(x, y\right) & \longmapsto & \left(X, Y, Z\right) = \left(\frac{2 \, x}{x^{2} + y^{2} + 1}, \frac{2 \, y}{x^{2} + y^{2} + 1}, \frac{x^{2} + y^{2} - 1}{x^{2} + y^{2} + 1}\right) \end{array}
+ \begin{array}{llcl} \Phi:& S^2 & \longrightarrow & \RR^3
+ \\ \mbox{on}\ U : & \left(x, y\right) & \longmapsto
+ & \left(X, Y, Z\right) = \left(\frac{2 \, x}{x^{2} + y^{2} + 1},
+ \frac{2 \, y}{x^{2} + y^{2} + 1},
+ \frac{x^{2} + y^{2} - 1}{x^{2} + y^{2} + 1}\right)
+ \end{array}
If the argument ``chart2`` is not specified, the display is performed
on all the charts on the codomain in which the map is known
or computable via some change of coordinates (here only one chart:
- c_cart)::
+ ``c_cart``)::
sage: Phi.display(c_xy)
Phi: S^2 --> R^3
on U: (x, y) |--> (X, Y, Z) = (2*x/(x^2 + y^2 + 1), 2*y/(x^2 + y^2 + 1), (x^2 + y^2 - 1)/(x^2 + y^2 + 1))
Similarly, if the argument ``chart1`` is omitted, the display is
- performed on all the charts on the map's domain in which the
+ performed on all the charts on the domain of ``Phi`` in which the
map is known or computable via some change of coordinates::
sage: Phi.display(chart2=c_cart)
@@ -975,7 +954,7 @@ class ContinuousMap(Morphism):
on V: (u, v) |--> (X, Y, Z) = (2*u/(u^2 + v^2 + 1), 2*v/(u^2 + v^2 + 1), -(u^2 + v^2 - 1)/(u^2 + v^2 + 1))
If neither ``chart1`` nor ``chart2`` is specified, the display is
- performed on all the pair of charts in which the map is known or
+ performed on all the pair of charts in which ``Phi`` is known or
computable via some change of coordinates::
sage: Phi.display()
@@ -1080,23 +1059,22 @@ class ContinuousMap(Morphism):
def coord_functions(self, chart1=None, chart2=None):
r"""
- Return the functions of the coordinates representing the continuous
- map in a given pair of charts.
+ Return the functions of the coordinates representing ``self``
+ in a given pair of charts.
- If these functions are not already known, they are computed from known
- ones by means of change-of-chart formulas.
+ If these functions are not already known, they are computed from
+ known ones by means of change-of-chart formulas.
INPUT:
- - ``chart1`` -- (default: ``None``) chart on the map's domain;
- if ``None``, the domain's default chart is assumed
- - ``chart2`` -- (default: ``None``) chart on the map's codomain;
+ - ``chart1`` -- (default: ``None``) chart on the domain of ``self``;
+ if ``None``, the domain's default chart is assumed
+ - ``chart2`` -- (default: ``None``) chart on the codomain of ``self``;
if ``None``, the codomain's default chart is assumed
OUTPUT:
- - instance of class
- :class:`~sage.manifolds.coord_func.MultiCoordFunction`
+ - a :class:`~sage.manifolds.coord_func.MultiCoordFunction`
representing the continuous map in the above two charts
EXAMPLES:
@@ -1145,13 +1123,14 @@ class ContinuousMap(Morphism):
1/4*(U^3 - (U - 4)*V^2 + V^3 - (U^2 + 4*U + 8)*V - 8*U)/(U - V))
on the Chart (M, (U, V))
- Coordinate representation w.r.t. a subchart in the domain::
+ Coordinate representation with respect to a subchart in the domain::
sage: A = M.open_subset('A', coord_def={c_uv: u>0})
sage: Phi.coord_functions(c_uv.restrict(A), c_xyz)
Coordinate functions (u*v, u/v, u + v) on the Chart (A, (u, v))
- Coordinate representation w.r.t. a superchart in the codomain::
+ Coordinate representation with respect to a superchart
+ in the codomain::
sage: B = N.open_subset('B', coord_def={c_xyz: x<0})
sage: c_xyz_B = c_xyz.restrict(B)
@@ -1161,7 +1140,8 @@ class ContinuousMap(Morphism):
sage: Phi1.coord_functions(c_uv, c_xyz) # c_xyz = superchart of c_xyz_B
Coordinate functions (u*v, u/v, u + v) on the Chart (M, (u, v))
- Coordinate representation w.r.t. a pair (subchart, superchart)::
+ Coordinate representation with respect to a pair
+ ``(subchart, superchart)``::
sage: Phi1.coord_functions(c_uv.restrict(A), c_xyz)
Coordinate functions (u*v, u/v, u + v) on the Chart (A, (u, v))
@@ -1177,10 +1157,8 @@ class ContinuousMap(Morphism):
# Check whether (chart1, chart2) are (subchart, superchart) of
# a pair of charts where the expression of self is known:
for (ochart1, ochart2) in self._coord_expression:
- if chart1 in ochart1._subcharts and \
- ochart2 in chart2._subcharts:
- coord_functions = \
- self._coord_expression[(ochart1, ochart2)].expr()
+ if chart1 in ochart1._subcharts and ochart2 in chart2._subcharts:
+ coord_functions = self._coord_expression[(ochart1, ochart2)].expr()
self._coord_expression[(chart1, chart2)] = \
chart1.multifunction(*coord_functions)
return self._coord_expression[(chart1, chart2)]
@@ -1200,8 +1178,8 @@ class ContinuousMap(Morphism):
# 1/ Trying to make a change of chart only on the codomain:
# the codomain's default chart is privileged:
sel_chart2 = None # selected chart2
- if def_chart2 in change_arrival \
- and (def_chart2, chart2) in dom2._coord_changes:
+ if (def_chart2 in change_arrival
+ and (def_chart2, chart2) in dom2._coord_changes):
sel_chart2 = def_chart2
else:
for ochart2 in change_arrival:
@@ -1212,14 +1190,14 @@ class ContinuousMap(Morphism):
oexpr = self._coord_expression[(chart1, sel_chart2)]
chg2 = dom2._coord_changes[(sel_chart2, chart2)]
self._coord_expression[(chart1, chart2)] = \
- chart1.multifunction(*(chg2(*(oexpr.expr()))))
+ chart1.multifunction( *chg2(*oexpr.expr()) )
return self._coord_expression[(chart1, chart2)]
# 2/ Trying to make a change of chart only on the start domain:
# the domain's default chart is privileged:
sel_chart1 = None # selected chart1
- if def_chart1 in change_start \
- and (chart1, def_chart1) in dom1._coord_changes:
+ if (def_chart1 in change_start
+ and (chart1, def_chart1) in dom1._coord_changes):
sel_chart1 = def_chart1
else:
for ochart1 in change_start:
@@ -1230,31 +1208,30 @@ class ContinuousMap(Morphism):
oexpr = self._coord_expression[(sel_chart1, chart2)]
chg1 = dom1._coord_changes[(chart1, sel_chart1)]
self._coord_expression[(chart1, chart2)] = \
- chart1.multifunction(*(oexpr( *(chg1._transf.expr()) )))
+ chart1.multifunction( *oexpr(*chg1._transf.expr()) )
return self._coord_expression[(chart1, chart2)]
# 3/ If this point is reached, it is necessary to perform some
# coordinate change both on the start domain and the arrival one
# the default charts are privileged:
- if (def_chart1, def_chart2) in self._coord_expression \
- and (chart1, def_chart1) in dom1._coord_changes \
- and (def_chart2, chart2) in dom2._coord_changes:
+ if ((def_chart1, def_chart2) in self._coord_expression
+ and (chart1, def_chart1) in dom1._coord_changes
+ and (def_chart2, chart2) in dom2._coord_changes):
sel_chart1 = def_chart1
sel_chart2 = def_chart2
else:
for (ochart1, ochart2) in self._coord_expression:
- if (chart1, ochart1) in dom1._coord_changes \
- and (ochart2, chart2) in dom2._coord_changes:
+ if ((chart1, ochart1) in dom1._coord_changes
+ and (ochart2, chart2) in dom2._coord_changes):
sel_chart1 = ochart1
sel_chart2 = ochart2
break
- if (sel_chart1 is not None) and (sel_chart2 is not None):
+ if sel_chart1 is not None and sel_chart2 is not None:
oexpr = self._coord_expression[(sel_chart1, sel_chart2)]
chg1 = dom1._coord_changes[(chart1, sel_chart1)]
chg2 = dom2._coord_changes[(sel_chart2, chart2)]
- self._coord_expression[(chart1, chart2)] = \
- chart1.multifunction(
- *(chg2( *(oexpr(*(chg1._transf.expr()))) )) )
+ self._coord_expression[(chart1, chart2)] = chart1.multifunction(
+ *chg2( *oexpr(*chg1._transf.expr()) ) )
return self._coord_expression[(chart1, chart2)]
# 4/ If this point is reached, the demanded value cannot be
@@ -1267,11 +1244,11 @@ class ContinuousMap(Morphism):
def expr(self, chart1=None, chart2=None):
r"""
- Return the expression of the continuous map in terms of
+ Return the expression of ``self`` in terms of
specified coordinates.
- If the expression is not already known, it is computed from some known
- expression by means of change-of-chart formulas.
+ If the expression is not already known, it is computed from some
+ known expression by means of change-of-chart formulas.
INPUT:
@@ -1287,8 +1264,8 @@ class ContinuousMap(Morphism):
EXAMPLES:
- Continuous map from a 2-dimensional manifold to a 3-dimensional
- one::
+ Continuous map from a 2-dimensional manifold to a
+ 3-dimensional one::
sage: M = Manifold(2, 'M', structure='topological')
sage: N = Manifold(3, 'N', structure='topological')
@@ -1353,22 +1330,25 @@ class ContinuousMap(Morphism):
"""
return self.coord_functions(chart1, chart2).expr()
+ expression = expr
+
def set_expr(self, chart1, chart2, coord_functions):
r"""
- Set a new coordinate representation of the continuous map.
+ Set a new coordinate representation of ``self``.
The expressions with respect to other charts are deleted, in order to
avoid any inconsistency. To keep them, use :meth:`add_expr` instead.
INPUT:
- - ``chart1`` -- chart for the coordinates on the map's domain
- - ``chart2`` -- chart for the coordinates on the map's codomain
+ - ``chart1`` -- chart for the coordinates on the domain of ``self``
+ - ``chart2`` -- chart for the coordinates on the codomain of ``self``
- ``coord_functions`` -- the coordinate symbolic expression of the
map in the above charts: list (or tuple) of the coordinates of
the image expressed in terms of the coordinates of the considered
- point; if the dimension of the codomain is 1, a single
- expression is expected (not a list with a single element)
+ point; if the dimension of the arrival manifold is 1, a single
+ coordinate expression can be passed instead of a tuple with a
+ single element
EXAMPLES:
@@ -1382,7 +1362,7 @@ class ContinuousMap(Morphism):
sage: c_spher.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') # spherical coordinates on U
sage: # Links between spherical coordinates and Cartesian ones:
sage: ch_cart_spher = c_cart.transition_map(c_spher,
- ....: [sqrt(x*x+y*y), atan2(y,x)])
+ ....: [sqrt(x*x+y*y), atan2(y,x)])
sage: ch_cart_spher.set_inverse(r*cos(ph), r*sin(ph), verbose=True)
Check of the inverse coordinate transformation:
x == x
@@ -1425,16 +1405,35 @@ class ContinuousMap(Morphism):
Chart (U, (r, ph))): Coordinate functions (r, 1/3*pi + ph)
on the Chart (U, (r, ph))}
+ TESTS:
+
+ We check that this does not change the equality nor the hash value::
+
+ sage: M = Manifold(2, 'R^2', latex_name=r'\RR^2', structure='topological')
+ sage: c_xy.<x,y> = M.chart()
+ sage: U = M.open_subset('U', coord_def={c_xy: (y!=0, x<0)})
+ sage: c_cart = c_xy.restrict(U)
+ sage: c_spher.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi')
+ sage: ch_cart_spher = c_cart.transition_map(c_spher,
+ ....: [sqrt(x*x+y*y), atan2(y,x)])
+ sage: ch_cart_spher.set_inverse(r*cos(ph), r*sin(ph))
+ sage: rot = U.continuous_map(U, ((x - sqrt(3)*y)/2, (sqrt(3)*x + y)/2),
+ ....: name='R')
+ sage: rot2 = copy(rot)
+ sage: rot == rot2 and hash(rot) == hash(rot2)
+ True
+ sage: rot.set_expr(c_spher, c_spher, (r, ph+pi/3))
+ sage: rot == rot2 and hash(rot) == hash(rot2)
+ True
"""
if self._is_identity:
- raise NotImplementedError("set_expr() must not be used for the " +
- "identity map")
+ raise NotImplementedError("set_expr() must not be used for the identity map")
if chart1 not in self._domain.atlas():
raise ValueError("the {}".format(chart1) +
- " has not been defined on the {}".format(self._domain))
+ " has not been defined on the {}".format(self._domain))
if chart2 not in self._codomain.atlas():
raise ValueError("the {}".format(chart2) +
- " has not been defined on the {}".format(self._codomain))
+ " has not been defined on the {}".format(self._codomain))
self._coord_expression.clear()
self._del_derived()
n2 = self._codomain.dim()
@@ -1445,12 +1444,16 @@ class ContinuousMap(Morphism):
self._coord_expression[(chart1, chart2)] = \
chart1.multifunction(*coord_functions)
else:
+ if isinstance(coord_functions, (list, tuple)):
+ coord_functions = coord_functions[0]
self._coord_expression[(chart1, chart2)] = \
chart1.multifunction(coord_functions)
+ set_expression = set_expr
+
def add_expr(self, chart1, chart2, coord_functions):
r"""
- Set a new coordinate representation of the continuous map.
+ Set a new coordinate representation of ``self``.
The previous expressions with respect to other charts are kept. To
clear them, use :meth:`set_expr` instead.
@@ -1462,8 +1465,9 @@ class ContinuousMap(Morphism):
- ``coord_functions`` -- the coordinate symbolic expression of the
map in the above charts: list (or tuple) of the coordinates of
the image expressed in terms of the coordinates of the considered
- point; if the dimension of the codomain is 1, a single
- expression is expected (not a list with a single element)
+ point; if the dimension of the arrival manifold is 1, a single
+ coordinate expression can be passed instead of a tuple with a
+ single element
.. WARNING::
@@ -1481,7 +1485,10 @@ class ContinuousMap(Morphism):
sage: U = M.open_subset('U', coord_def={c_xy: (y!=0, x<0)}) # the complement of the segment y=0 and x>0
sage: c_cart = c_xy.restrict(U) # Cartesian coordinates on U
sage: c_spher.<r,ph> = U.chart(r'r:(0,+oo) ph:(0,2*pi):\phi') # spherical coordinates on U
- sage: # Links between spherical coordinates and Cartesian ones:
+
+ We construct the links between spherical coordinates and
+ Cartesian ones::
+
sage: ch_cart_spher = c_cart.transition_map(c_spher, [sqrt(x*x+y*y), atan2(y,x)])
sage: ch_cart_spher.set_inverse(r*cos(ph), r*sin(ph), verbose=True)
Check of the inverse coordinate transformation:
@@ -1495,9 +1502,9 @@ class ContinuousMap(Morphism):
R: U --> U
(x, y) |--> (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)
- If we make Sage calculate the expression in terms of spherical
- coordinates, via the method :meth:`display`, we notice some difficulties
- in arctan2 simplifications::
+ If we calculate the expression in terms of spherical coordinates,
+ via the method :meth:`display`, we notice some difficulties
+ in ``arctan2`` simplifications::
sage: rot.display(c_spher, c_spher)
R: U --> U
@@ -1513,43 +1520,40 @@ class ContinuousMap(Morphism):
The call to :meth:`add_expr` has not deleted the expression in
terms of Cartesian coordinates, as we can check by printing the
- dictionary :attr:`_coord_expression`, which stores the various internal
- representations of the continuous map::
+ internal dictionary ``_coord_expression``, which stores the
+ various internal representations of the continuous map::
sage: rot._coord_expression # random (dictionary output)
- {(Chart (U, (x, y)),
- Chart (U, (x, y))): Coordinate functions (-1/2*sqrt(3)*y + 1/2*x,
- 1/2*sqrt(3)*x + 1/2*y) on the Chart (U, (x, y)),
- (Chart (U, (r, ph)),
- Chart (U, (r, ph))): Coordinate functions (r, 1/3*pi + ph)
- on the Chart (U, (r, ph))}
+ {(Chart (U, (x, y)), Chart (U, (x, y))):
+ Coordinate functions (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)
+ on the Chart (U, (x, y)),
+ (Chart (U, (r, ph)), Chart (U, (r, ph))):
+ Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}
If, on the contrary, we use :meth:`set_expr`, the expression in
Cartesian coordinates is lost::
sage: rot.set_expr(c_spher, c_spher, (r, ph+pi/3))
sage: rot._coord_expression
- {(Chart (U, (r, ph)),
- Chart (U, (r, ph))): Coordinate functions (r, 1/3*pi + ph)
- on the Chart (U, (r, ph))}
+ {(Chart (U, (r, ph)), Chart (U, (r, ph))):
+ Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}
- It is recovered (thanks to the known change of coordinates) by a call
- to :meth:`display`::
+ It is recovered (thanks to the known change of coordinates) by
+ a call to :meth:`display`::
sage: rot.display(c_cart, c_cart)
R: U --> U
(x, y) |--> (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)
sage: rot._coord_expression # random (dictionary output)
- {(Chart (U, (x, y)),
- Chart (U, (x, y))): Coordinate functions (-1/2*sqrt(3)*y + 1/2*x,
- 1/2*sqrt(3)*x + 1/2*y) on the Chart (U, (x, y)),
- (Chart (U, (r, ph)),
- Chart (U, (r, ph))): Coordinate functions (r, 1/3*pi + ph)
- on the Chart (U, (r, ph))}
+ {(Chart (U, (x, y)), Chart (U, (x, y))):
+ Coordinate functions (-1/2*sqrt(3)*y + 1/2*x, 1/2*sqrt(3)*x + 1/2*y)
+ on the Chart (U, (x, y)),
+ (Chart (U, (r, ph)), Chart (U, (r, ph))):
+ Coordinate functions (r, 1/3*pi + ph) on the Chart (U, (r, ph))}
- The rotation can be applied to a point by means of either coordinate
- system::
+ The rotation can be applied to a point by means of either
+ coordinate system::
sage: p = M.point((1,2)) # p defined by its Cartesian coord.
sage: q = rot(p) # q is computed by means of Cartesian coord.
@@ -1560,47 +1564,44 @@ class ContinuousMap(Morphism):
"""
if self._is_identity:
- raise NotImplementedError("add_expr() must not be used for the " +
- "identity map")
+ raise NotImplementedError("add_expr() must not be used for the identity map")
if chart1 not in self._domain.atlas():
raise ValueError("the {}".format(chart1) +
- " has not been defined on the {}".format(self._domain))
+ " has not been defined on the {}".format(self._domain))
if chart2 not in self._codomain.atlas():
raise ValueError("the {}".format(chart2) +
- " has not been defined on the {}".format(self._codomain))
+ " has not been defined on the {}".format(self._codomain))
self._del_derived()
n2 = self._codomain.dim()
if n2 > 1:
if len(coord_functions) != n2:
- raise ValueError("{} coordinate functions must ".format(n2) +
- "be provided")
- self._coord_expression[(chart1, chart2)] = \
- chart1.multifunction(*coord_functions)
+ raise ValueError("{} coordinate functions must be provided".format(n2))
+ self._coord_expression[(chart1, chart2)] = chart1.multifunction(*coord_functions)
else:
- self._coord_expression[(chart1, chart2)] = \
- chart1.multifunction(coord_functions)
+ if isinstance(coord_functions, (list, tuple)):
+ coord_functions = coord_functions[0]
+ self._coord_expression[(chart1, chart2)] = chart1.multifunction(coord_functions)
+
+ add_expression = add_expr
def restrict(self, subdomain, subcodomain=None):
r"""
- Restriction of the continuous map to some open subset of its
+ Restriction of ``self`` to some open subset of its
domain of definition.
INPUT:
- - ``subdomain`` -- an open subset of the domain of the continuous map
- (must be an instance of
- :class:`~sage.manifolds.manifold.TopologicalManifold`)
+ - ``subdomain`` -- :class:`~sage.manifolds.manifold.TopologicalManifold`;
+ an open subset of the domain of ``self``
- ``subcodomain`` -- (default: ``None``) an open subset of the codomain
- of the continuous map (must be an instance of
- :class:`~sage.manifolds.manifold.TopologicalManifold`); if ``None``,
- the codomain of the continuous map is assumed.
+ of ``self``; if ``None``, the codomain of ``self`` is assumed
OUTPUT:
- - the restriction of the continuous map to ``subdomain``, as an
- instance of class :class:`ContinuousMap`
+ - a :class:`ContinuousMap` that is the restriction
+ of ``self`` to ``subdomain``
- EXAMPLE:
+ EXAMPLES:
Restriction to an annulus of a homeomorphism between the open unit
disk and `\RR^2`::
@@ -1616,14 +1617,15 @@ class ContinuousMap(Morphism):
sage: c_xy_D = c_xy.restrict(D)
sage: U = D.open_subset('U', coord_def={c_xy_D: x^2+y^2>1/2}) # the annulus 1/2 < r < 1
sage: Phi.restrict(U)
- Continuous map Phi from the Open subset U of the 2-dimensional
- topological manifold R^2 to the 2-dimensional topological
- manifold R^2
+ Continuous map Phi
+ from the Open subset U of the 2-dimensional topological manifold R^2
+ to the 2-dimensional topological manifold R^2
sage: Phi.restrict(U).parent()
- Set of Morphisms from Open subset U of the 2-dimensional
- topological manifold R^2 to 2-dimensional topological manifold R^2
- in Join of Category of subobjects of sets and Category of
- manifolds over Real Field with 53 bits of precision
+ Set of Morphisms
+ from Open subset U of the 2-dimensional topological manifold R^2
+ to 2-dimensional topological manifold R^2
+ in Join of Category of subobjects of sets
+ and Category of manifolds over Real Field with 53 bits of precision
sage: Phi.domain()
Open subset D of the 2-dimensional topological manifold R^2
sage: Phi.restrict(U).domain()
@@ -1652,14 +1654,14 @@ class ContinuousMap(Morphism):
sage: Phi = D.continuous_map(M, [x/sqrt(1+x^2+y^2), y/sqrt(1+x^2+y^2)])
sage: Phi
- Continuous map from the Open subset D of the 2-dimensional
- topological manifold R^2 to the 2-dimensional topological manifold R^2
+ Continuous map from
+ the Open subset D of the 2-dimensional topological manifold R^2
+ to the 2-dimensional topological manifold R^2
sage: Phi.restrict(D, subcodomain=D)
Continuous map from the Open subset D of the 2-dimensional
topological manifold R^2 to itself
"""
- from sage.categories.homset import Hom
if subcodomain is None:
if self._is_identity:
subcodomain = subdomain
@@ -1669,16 +1671,15 @@ class ContinuousMap(Morphism):
return self
if (subdomain, subcodomain) not in self._restrictions:
if not subdomain.is_subset(self._domain):
- raise ValueError("the specified domain is not a subset " +
- "of the domain of definition of the " +
- "continuous map")
+ raise ValueError("the specified domain is not a subset"
+ " of the domain of definition of the"
+ " continuous map")
if not subcodomain.is_subset(self._codomain):
- raise ValueError("the specified codomain is not a subset " +
- "of the codomain of the continuous map")
+ raise ValueError("the specified codomain is not a subset"
+ " of the codomain of the continuous map")
# Special case of the identity map:
if self._is_identity:
- self._restrictions[(subdomain, subcodomain)] = \
- subdomain.identity_map()
+ self._restrictions[(subdomain, subcodomain)] = subdomain.identity_map()
return self._restrictions[(subdomain, subcodomain)]
# Generic case:
homset = Hom(subdomain, subcodomain)
@@ -1695,19 +1696,16 @@ class ContinuousMap(Morphism):
else:
for sch2 in ch2._subcharts:
if (ch1, sch2) in resu._coord_expression:
- del resu._coord_expression[(ch1,
- sch2)]
- coord_functions = \
- self._coord_expression[charts].expr()
+ del resu._coord_expression[(ch1, sch2)]
+ coord_functions = self._coord_expression[charts].expr()
resu._coord_expression[(ch1, ch2)] = \
ch1.multifunction(*coord_functions)
self._restrictions[(subdomain, subcodomain)] = resu
return self._restrictions[(subdomain, subcodomain)]
-
def __invert__(self):
r"""
- Return the inverse of the map whenever it is an isomorphism.
+ Return the inverse of ``self`` if it is an isomorphism.
OUTPUT:
@@ -1760,8 +1758,9 @@ class ContinuousMap(Morphism):
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)
+ ....: intersection_name='W',
+ ....: restrictions1=x^2+y^2!=0,
+ ....: restrictions2=u^2+v^2!=0)
sage: uv_to_xy = xy_to_uv.inverse()
sage: s = M.homeomorphism(M, {(c_xy, c_uv): [x, y], (c_uv, c_xy): [u, v]},
....: name='s')
@@ -1795,17 +1794,18 @@ class ContinuousMap(Morphism):
n2 = len(chart2._xx)
# New symbolic variables (different from chart2._xx to allow for a
# correct solution even when chart2 = chart1):
- x2 = [ SR.var('xxxx' + str(i)) for i in range(n2) ]
- equations = [ x2[i] == coord_map._functions[i]._express
- for i in range(n2) ]
+ x2 = [SR.var('xxxx' + str(i)) for i in range(n2)]
+ equations = [x2[i] == coord_map._functions[i]._express
+ for i in range(n2)]
solutions = solve(equations, chart1._xx, solution_dict=True)
- if len(solutions) == 0:
+ if not solutions:
raise ValueError("no solution found")
if len(solutions) > 1:
raise ValueError("non-unique solution found")
substitutions = dict(zip(x2, chart2._xx))
- inv_functions = [solutions[0][chart1._xx[i]].subs(substitutions)
- for i in range(n1)]
+ sol = solutions[0]
+ inv_functions = [sol[chart1._xx[i]].subs(substitutions)
+ for i in range(n1)]
for i in range(n1):
x = inv_functions[i]
try:
@@ -1828,3 +1828,4 @@ class ContinuousMap(Morphism):
return self._inverse
inverse = __invert__
+
diff --git a/src/sage/manifolds/coord_func_symb.py b/src/sage/manifolds/coord_func_symb.py
index 551dda8..032fca7 100644
--- a/src/sage/manifolds/coord_func_symb.py
+++ b/src/sage/manifolds/coord_func_symb.py
@@ -41,11 +41,10 @@ AUTHORS:
from sage.misc.cachefunc import cached_method
from sage.symbolic.ring import SR
-from sage.structure.element import RingElement
from sage.structure.parent import Parent
from sage.structure.unique_representation import UniqueRepresentation
from sage.categories.commutative_algebras import CommutativeAlgebras
-from sage.manifolds.coord_func import CoordFunction, MultiCoordFunction
+from sage.manifolds.coord_func import CoordFunction
from sage.manifolds.utilities import (ExpressionNice, simplify_chain_real,
simplify_chain_generic)
diff --git a/src/sage/manifolds/manifold.py b/src/sage/manifolds/manifold.py
index 0693557..b88b7e5 100644
--- a/src/sage/manifolds/manifold.py
+++ b/src/sage/manifolds/manifold.py
@@ -335,6 +335,7 @@ from sage.rings.all import CC
from sage.rings.real_mpfr import RR, RealField_class
from sage.rings.complex_field import ComplexField_class
from sage.misc.prandom import getrandbits
+from sage.misc.cachefunc import cached_method
from sage.rings.integer import Integer
from sage.structure.global_options import GlobalOptions
from sage.manifolds.subset import ManifoldSubset
@@ -644,10 +645,6 @@ class TopologicalManifold(ManifoldSubset):
self._zero_scalar_field = self._scalar_field_algebra.zero()
# The unit scalar field:
self._one_scalar_field = self._scalar_field_algebra.one()
- # Dictionary of sets of morphisms to over manifolds (keys: codomains):
- self._homsets = {} # to be populated by self._Hom_
- # The identity map on self:
- self._identity_map = Hom(self, self).one()
def _repr_(self):
r"""
@@ -1781,14 +1778,14 @@ class TopologicalManifold(ManifoldSubset):
def zero_scalar_field(self):
r"""
- Return the zero scalar field defined on the manifold.
+ Return the zero scalar field defined on ``self``.
OUTPUT:
- - instance of :class:`~sage.manifolds.scalarfield.ScalarField`
- representing the constant scalar field with value 0
+ - a :class:`~sage.manifolds.scalarfield.ScalarField`
+ representing the constant scalar field with value `0`
- EXAMPLE::
+ EXAMPLES::
sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
@@ -1807,16 +1804,16 @@ class TopologicalManifold(ManifoldSubset):
def one_scalar_field(self):
r"""
- Return the constant scalar field with value the unit element of the
- manifold's base field.
+ Return the constant scalar field with value the unit element
+ of the base field of ``self``.
OUTPUT:
- - instance of :class:`~sage.manifolds.scalarfield.ScalarField`
- representing the constant scalar field with value the unit element
- of the manifold's base field
+ - a :class:`~sage.manifolds.scalarfield.ScalarField` representing
+ the constant scalar field with value the unit element
+ of the base field of ``self``
- EXAMPLE::
+ EXAMPLES::
sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
@@ -1838,7 +1835,7 @@ class TopologicalManifold(ManifoldSubset):
def _Hom_(self, other, category=None):
r"""
Construct the set of morphisms (i.e. continuous maps)
- ``self`` --> ``other``.
+ ``self`` to ``other``.
INPUT:
@@ -1849,13 +1846,15 @@ class TopologicalManifold(ManifoldSubset):
OUTPUT:
- - the homset Hom(U,V), where U is ``self`` and V is ``other``
+ - the homset `\mathrm{Hom}(U,V)`, where `U` is ``self``
+ and `V` is ``other``
+
+ .. SEEALSO::
- See class
- :class:`~sage.manifolds.manifold_homset.TopologicalManifoldHomset`
- for more documentation.
+ For more documentation, see
+ :class:`~sage.manifolds.manifold_homset.TopologicalManifoldHomset`.
- TESTS::
+ EXAMPLES::
sage: M = Manifold(2, 'M', structure='topological')
sage: N = Manifold(3, 'N', structure='topological')
@@ -1870,55 +1869,45 @@ class TopologicalManifold(ManifoldSubset):
True
"""
- if other not in self._homsets:
- self._homsets[other] = self._structure.homset(self, other)
- return self._homsets[other]
+ return self._structure.homset(self, other)
def continuous_map(self, codomain, coord_functions=None, chart1=None,
chart2=None, name=None, latex_name=None):
r"""
- Define a continuous map between the current topological manifold
- and another topological manifold over the same topological field.
-
- See :class:`~sage.manifolds.continuous_map.ContinuousMap` for a
- complete documentation.
+ Define a continuous map from ``self`` to ``codomain``.
INPUT:
- - ``codomain`` -- the map's codomain (must be an instance
- of :class:`TopologicalManifold`)
- - ``coord_functions`` -- (default: ``None``) if not ``None``, must be
- either
-
- - (i) a dictionary of
- the coordinate expressions (as lists (or tuples) of the
- coordinates of the image expressed in terms of the coordinates of
- the considered point) with the pairs of charts (chart1, chart2)
- as keys (chart1 being a chart on ``self`` and chart2 a chart on
- ``codomain``)
+ - ``codomain`` -- :class:`TopologicalManifold`; the map's codomain
+ - ``coord_functions`` -- (default: ``None``) if not ``None``,
+ must be either
+
+ - (i) a dictionary of the coordinate expressions (as lists
+ (or tuples) of the coordinates of the image expressed in
+ terms of the coordinates of the considered point) with the
+ pairs of charts ``(chart1, chart2)`` as keys (``chart1`` being
+ a chart on ``self`` and ``chart2`` a chart on ``codomain``);
- (ii) a single coordinate expression in a given pair of charts, the
- latter being provided by the arguments ``chart1`` and ``chart2``
-
- In both cases, if the dimension of the codomain is 1, a single
- coordinate expression can be passed instead of a tuple with a single
- element
- - ``chart1`` -- (default: ``None``; used only in case (ii) above) chart
- on the current manifold defining the start coordinates involved in
- ``coord_functions`` for case (ii); if none is provided, the
- coordinates are assumed to refer to the manifold's default chart
- - ``chart2`` -- (default: ``None``; used only in case (ii) above) chart
- on ``codomain`` defining the target coordinates involved in
- ``coord_functions`` for case (ii); if none is provided, the
- coordinates are assumed to refer to the default chart of ``codomain``
- - ``name`` -- (default: ``None``) name given to the continuous
- map
+ latter being provided by the arguments ``chart1`` and ``chart2``;
+
+ in both cases, if the dimension of the codomain is `1`, a single
+ coordinate expression can be passed instead of a tuple with
+ a single element
+ - ``chart1`` -- (default: ``None``; used only in case (ii) above)
+ chart on ``self`` defining the start coordinates involved in
+ ``coord_functions`` for case (ii); if ``None``, the coordinates
+ are assumed to refer to the default chart of ``self``
+ - ``chart2`` -- (default: ``None``; used only in case (ii) above)
+ chart on ``codomain`` defining the target coordinates involved in
+ ``coord_functions`` for case (ii); if ``None``, the coordinates
+ are assumed to refer to the default chart of ``codomain``
+ - ``name`` -- (default: ``None``) name given to the continuous map
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
- continuous map; if none is provided, the LaTeX symbol is set to
- ``name``
+ continuous map; if ``None``, the LaTeX symbol is set to ``name``
OUTPUT:
- - the continuous map, as an instance of
+ - the continuous map as an instance of
:class:`~sage.manifolds.continuous_map.ContinuousMap`
EXAMPLES:
@@ -1956,11 +1945,29 @@ class TopologicalManifold(ManifoldSubset):
sage: Phi1(p) == Phi(p)
True
- See the documentation of class
- :class:`~sage.manifolds.continuous_map.ContinuousMap` for more
- examples.
+ TESTS::
+
+ sage: M = Manifold(2, 'M', structure='topological')
+ sage: M.continuous_map(ZZ)
+ Traceback (most recent call last):
+ ...
+ ValueError: Integer Ring is not a manifold
+ over Real Field with 53 bits of precision
+
+ .. SEEALSO::
+
+ See :class:`~sage.manifolds.continuous_map.ContinuousMap`
+ for the complete documentation and more examples.
+
+ .. TODO::
+
+ Allow the construction of continuous maps from ``self`` to the
+ base field (considered as a trivial 1-dimensional manifold).
"""
+ if (not isinstance(codomain, TopologicalManifold)
+ or codomain.base_field() != self.base_field()):
+ raise ValueError("{} is not a manifold over {}".format(codomain, self.base_field()))
homset = Hom(self, codomain)
if coord_functions is None:
coord_functions = {}
@@ -1989,42 +1996,40 @@ class TopologicalManifold(ManifoldSubset):
INPUT:
- - ``codomain`` -- codomain of the homeomorphism (must be an instance
- of :class:`TopologicalManifold`)
- - ``coord_functions`` -- (default: ``None``) if not ``None``, must be
- either
-
- - (i) a dictionary of
- the coordinate expressions (as lists (or tuples) of the
- coordinates of the image expressed in terms of the coordinates of
- the considered point) with the pairs of charts (chart1, chart2)
- as keys (chart1 being a chart on ``self`` and chart2 a chart on
- ``codomain``)
+ - ``codomain`` -- :class:`TopologicalManifold`; codomain of
+ the homeomorphism
+ - ``coord_functions`` -- (default: ``None``) if not ``None``,
+ must be either
+
+ - (i) a dictionary of the coordinate expressions (as lists
+ (or tuples) of the coordinates of the image expressed in
+ terms of the coordinates of the considered point) with the
+ pairs of charts ``(chart1, chart2)`` as keys (``chart1`` being
+ a chart on ``self`` and ``chart2`` a chart on ``codomain``);
- (ii) a single coordinate expression in a given pair of charts, the
- latter being provided by the arguments ``chart1`` and ``chart2``
+ latter being provided by the arguments ``chart1`` and ``chart2``;
- In both cases, if the dimension of the codomain is 1, a single
+ in both cases, if the dimension of the codomain is `1`, a single
coordinate expression can be passed instead of a tuple with
a single element
- - ``chart1`` -- (default: ``None``; used only in case (ii) above) chart
- on the current manifold defining the start coordinates involved in
- ``coord_functions`` for case (ii); if none is provided, the
- coordinates are assumed to refer to the manifold's default chart
- - ``chart2`` -- (default: ``None``; used only in case (ii) above) chart
- on ``codomain`` defining the target coordinates involved in
- ``coord_functions`` for case (ii); if none is provided, the
- coordinates are assumed to refer to the default chart of ``codomain``
+ - ``chart1`` -- (default: ``None``; used only in case (ii) above)
+ chart on ``self`` defining the start coordinates involved in
+ ``coord_functions`` for case (ii); if ``None``, the coordinates
+ are assumed to refer to the default chart of ``self``
+ - ``chart2`` -- (default: ``None``; used only in case (ii) above)
+ chart on ``codomain`` defining the target coordinates involved in
+ ``coord_functions`` for case (ii); if ``None``, the coordinates
+ are assumed to refer to the default chart of ``codomain``
- ``name`` -- (default: ``None``) name given to the homeomorphism
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
- homeomorphism; if none is provided, the LaTeX symbol is set to
- ``name``
+ homeomorphism; if ``None``, the LaTeX symbol is set to ``name``
OUTPUT:
- the homeomorphism, as an instance of
:class:`~sage.manifolds.continuous_map.ContinuousMap`
- EXAMPLE:
+ EXAMPLES:
Homeomorphism between the open unit disk in `\RR^2` and `\RR^2`::
@@ -2052,7 +2057,7 @@ class TopologicalManifold(ManifoldSubset):
Phi^(-1): N --> M
(X, Y) |--> (x, y) = (X/sqrt(X^2 + Y^2 + 1), Y/sqrt(X^2 + Y^2 + 1))
- See the documentation of class
+ See the documentation of
:class:`~sage.manifolds.continuous_map.ContinuousMap` for more
examples.
@@ -2076,12 +2081,13 @@ class TopologicalManifold(ManifoldSubset):
return homset(coord_functions, name=name, latex_name=latex_name,
is_isomorphism=True)
+ @cached_method
def identity_map(self):
r"""
- Identity map of the manifold.
+ Identity map of ``self``.
The identity map of a topological manifold `M` is the trivial
- homeomorphism
+ homeomorphism:
.. MATH::
@@ -2090,15 +2096,12 @@ class TopologicalManifold(ManifoldSubset):
& p & \longmapsto & p
\end{array}
- See :class:`~sage.manifolds.continuous_map.ContinuousMap` for a
- complete documentation.
-
OUTPUT:
- - the identity map, as an instance of
+ - the identity map as an instance of
:class:`~sage.manifolds.continuous_map.ContinuousMap`
- EXAMPLE:
+ EXAMPLES:
Identity map of a complex manifold::
@@ -2123,8 +2126,13 @@ class TopologicalManifold(ManifoldSubset):
sage: id(p) == p
True
+ .. SEEALSO::
+
+ See :class:`~sage.manifolds.continuous_map.ContinuousMap`
+ for the complete documentation.
+
"""
- return self._identity_map
+ return Hom(self, self).one()
##############################################################################
## Constructor function
diff --git a/src/sage/manifolds/manifold_homset.py b/src/sage/manifolds/manifold_homset.py
index 51f8c1d..d49edf3 100644
--- a/src/sage/manifolds/manifold_homset.py
+++ b/src/sage/manifolds/manifold_homset.py
@@ -1,9 +1,10 @@
r"""
Sets of Morphisms between Topological Manifolds
-The class :class:`TopologicalManifoldHomset` implements sets of morphisms between
-two topological manifolds over the same topological field `K`, a morphism
-being a *continuous map* for the category of topological manifolds.
+The class :class:`TopologicalManifoldHomset` implements sets of
+morphisms between two topological manifolds over the same topological
+field `K`, a morphism being a *continuous map* for the category of
+topological manifolds.
AUTHORS:
@@ -20,16 +21,18 @@ REFERENCES:
#******************************************************************************
# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
#
-# 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.
+# 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/
-#******************************************************************************
+#*****************************************************************************
from sage.categories.homset import Homset
from sage.structure.parent import Parent
from sage.structure.unique_representation import UniqueRepresentation
from sage.manifolds.continuous_map import ContinuousMap
+from sage.misc.cachefunc import cached_method
class TopologicalManifoldHomset(UniqueRepresentation, Homset):
r"""
@@ -37,23 +40,21 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
Given two topological manifolds `M` and `N` over a topological field `K`,
the class :class:`TopologicalManifoldHomset` implements the set
- `\mathrm{Hom}(M,N)` of morphisms (i.e. continuous maps) `M\rightarrow N`.
+ `\mathrm{Hom}(M, N)` of morphisms (i.e. continuous maps) `M \to N`.
This is a Sage *parent* class, whose *element* class is
:class:`~sage.manifolds.continuous_map.ContinuousMap`.
INPUT:
- - ``domain`` -- topological manifold `M` (domain of the morphisms belonging
- to the homset), as an instance of
- :class:`~sage.manifolds.manifold.TopologicalManifold`
- - ``codomain`` -- topological manifold `N` (codomain of the morphisms
- belonging to the homset), as an instance of
- :class:`~sage.manifolds.manifold.TopologicalManifold`
- - ``name`` -- (default: ``None``) string; name given to the homset; if
- ``None``, Hom(M,N) will be used
- - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the
- homset; if ``None``, `\mathrm{Hom}(M,N)` will be used
+ - ``domain`` -- :class:`~sage.manifolds.manifold.TopologicalManifold`;
+ the domain topological manifold `M` of the morphisms
+ - ``codomain`` -- :class:`~sage.manifolds.manifold.TopologicalManifold`;
+ the codomain topological manifold `N` of the morphisms
+ - ``name`` -- (default: ``None``) string; the name of ``self``;
+ if ``None``, ``Hom(M,N)`` will be used
+ - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote
+ ``self``; if ``None``, `\mathrm{Hom}(M,N)` will be used
EXAMPLES:
@@ -141,6 +142,8 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
def __init__(self, domain, codomain, name=None, latex_name=None):
r"""
+ Initialize ``self``.
+
TESTS::
sage: M = Manifold(2, 'M', structure='topological')
@@ -171,21 +174,18 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
"instance of TopologicalManifold")
Homset.__init__(self, domain, codomain)
if name is None:
- self._name = "Hom(" + domain._name + "," + codomain._name + ")"
+ self._name = "Hom({},{})".format(domain._name, codomain._name)
else:
self._name = name
if latex_name is None:
- self._latex_name = \
- r"\mathrm{Hom}\left(" + domain._latex_name + "," + \
- codomain._latex_name + r"\right)"
+ self._latex_name = r"\mathrm{{Hom}}\left({},{}\right)".format(
+ domain._latex_name, codomain._latex_name)
else:
self._latex_name = latex_name
- self._one = None # to be set by self.one() if self is a set of
- # endomorphisms (codomain = domain)
def _latex_(self):
r"""
- LaTeX representation of the object.
+ LaTeX representation of ``self``.
EXAMPLE::
@@ -193,9 +193,8 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
sage: X.<x,y> = M.chart()
sage: N = Manifold(3, 'N', structure='topological')
sage: H = Hom(M, N)
- sage: H._latex_()
- '\\mathrm{Hom}\\left(M,N\\right)'
-
+ sage: latex(H)
+ \mathrm{Hom}\left(M,N\right)
"""
if self._latex_name is None:
return r'\mbox{' + str(self) + r'}'
@@ -207,27 +206,27 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
def _element_constructor_(self, coord_functions, name=None, latex_name=None,
is_isomorphism=False, is_identity=False):
r"""
- Construct an element of the homset, i.e. a continuous map
- M --> N, where M is the domain of the homset and N its codomain.
+ Construct an element of the homset, i.e. a continuous map `M \to N`,
+ where `M` is the domain of the homset and `N` its codomain.
INPUT:
- ``coord_functions`` -- a dictionary of the coordinate expressions
- (as lists (or tuples) of the coordinates of the image expressed in
- terms of the coordinates of the considered point) with the pairs of
- charts (chart1, chart2) as keys (chart1 being a chart on `M` and
- chart2 a chart on `N`). If the dimension of the arrival manifold
- is 1, a single coordinate expression can be passed instead of a tuple
- with a single element
+ (as lists or tuples of the coordinates of the image expressed in
+ terms of the coordinates of the considered point) with the pairs
+ of charts ``(chart1, chart2)`` as keys (``chart1`` being a chart
+ on `M` and ``chart2`` a chart on `N`); if the dimension of the
+ arrival manifold is 1, a single coordinate expression can be
+ passed instead of a tuple with a single element
- ``name`` -- (default: ``None``) name given to the continuous map
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
continuous map; if ``None``, the LaTeX symbol is set to ``name``
- ``is_isomorphism`` -- (default: ``False``) determines whether the
constructed object is a isomorphism (i.e. a homeomorphism); if set to
- ``True``, then the manifolds `M` and `N` must have the same dimension.
+ ``True``, then the manifolds `M` and `N` must have the same dimension
- ``is_identity`` -- (default: ``False``) determines whether the
constructed object is the identity map; if set to ``True``,
- then `N` must be `M` and the entry ``coord_functions`` is not used.
+ then `N` must be `M` and the entry ``coord_functions`` is not used
.. NOTE::
@@ -238,8 +237,7 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
OUTPUT:
- - instance of
- :class:`~sage.manifolds.continuous_map.ContinuousMap`
+ - a :class:`~sage.manifolds.continuous_map.ContinuousMap`
EXAMPLES::
@@ -270,12 +268,11 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
def _an_element_(self):
r"""
- Construct some element.
+ Construct some element of ``self``.
OUTPUT:
- - instance of
- :class:`~sage.manifolds.continuous_map.ContinuousMap`
+ - a :class:`~sage.manifolds.continuous_map.ContinuousMap`
EXAMPLE::
@@ -312,9 +309,9 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
def _coerce_map_from_(self, other):
r"""
- Determine whether coercion to self exists from other parent.
+ Determine whether coercion to ``self`` exists from parent ``other``.
- EXAMPLE::
+ EXAMPLES::
sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
@@ -327,17 +324,21 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
False
sage: H._coerce_map_from_(N)
False
+ sage: H._coerce_map_from_(H)
+ True
"""
- #!# for the time being:
+ if isinstance(other, TopologicalManifoldHomset):
+ return (other.domain().has_coerce_map_from(self.domain())
+ and self.codomain().has_coerce_map_from(other.codomain()))
return False
#!# check
def __call__(self, *args, **kwds):
r"""
- To bypass Homset.__call__, enforcing Parent.__call__ instead.
+ Construct an element of ``self`` from the input.
- EXAMPLE::
+ EXAMPLES::
sage: M = Manifold(2, 'M', structure='topological')
sage: X.<x,y> = M.chart()
@@ -351,17 +352,29 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
f: M --> N
(x, y) |--> (u, v, w) = (x + y, x - y, x*y)
+ There is also the following shortcut for :meth:`one`::
+
+ sage: M = Manifold(2, 'M', structure='topological')
+ sage: H = Hom(M, M)
+ sage: H(1)
+ Identity map Id_M of the 2-dimensional topological manifold M
"""
+ if len(args) == 1:
+ if self.domain() == self.codomain() and args[0] == 1:
+ return self.one()
+ if isinstance(args[0], ContinuousMap):
+ return Homset.__call__(self, args[0])
return Parent.__call__(self, *args, **kwds)
#### End of parent methods ####
#### Monoid methods (case of an endomorphism set) ####
+ @cached_method
def one(self):
r"""
- Return the identity element of the homset considered as a monoid (case
- of a set of endomorphisms).
+ Return the identity element of ``self`` considered as a monoid
+ (case of a set of endomorphisms).
This applies only when the codomain of the homset is equal to its
domain, i.e. when the homset is of the type `\mathrm{Hom}(M,M)`.
@@ -407,16 +420,16 @@ class TopologicalManifoldHomset(UniqueRepresentation, Homset):
sage: Hom(M, N).one()
Traceback (most recent call last):
...
- TypeError: the Set of Morphisms from 2-dimensional topological
- manifold M to 3-dimensional topological manifold N in Category of
- manifolds over Real Field with 53 bits of precision is not a
- monoid
+ TypeError: Set of Morphisms
+ from 2-dimensional topological manifold M
+ to 3-dimensional topological manifold N
+ in Category of manifolds over Real Field with 53 bits of precision
+ is not a monoid
"""
- if self._one is None:
- if self.codomain() != self.domain():
- raise TypeError("the {} is not a monoid".format(self))
- self._one = self.element_class(self, is_identity=True)
- return self._one
+ if self.codomain() != self.domain():
+ raise TypeError("{} is not a monoid".format(self))
+ return self.element_class(self, is_identity=True)
#### End of monoid methods ####
+
diff --git a/src/sage/manifolds/point.py b/src/sage/manifolds/point.py
index 152d2bd..aa9fabc 100644
--- a/src/sage/manifolds/point.py
+++ b/src/sage/manifolds/point.py
@@ -75,6 +75,7 @@ Points can be compared::
#*****************************************************************************
from sage.structure.element import Element
+from sage.misc.decorators import options
class ManifoldPoint(Element):
r"""
@@ -682,11 +683,11 @@ class ManifoldPoint(Element):
"""
return hash(self.parent().manifold())
- def plot(self, chart=None, ambient_coords=None, mapping=None, size=10,
- color='black', label=None, label_color=None, fontsize=10,
- label_offset=0.1, parameters=None):
+ @options(size=10, color='black', label_color=None, fontsize=10, label_offset=0.1)
+ def plot(self, chart=None, ambient_coords=None, mapping=None,
+ label=None, parameters=None, **kwds):
r"""
- For real manifolds, plot the current point in a Cartesian graph based
+ 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)
@@ -699,28 +700,28 @@ class ManifoldPoint(Element):
- ``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``) continuous manifold map `\Phi`
- (instance of :class:`~sage.manifolds.continuous_map.ContinuousMap`)
- 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
+ - ``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`` -- (default: ``None``) label printed next to the point;
- if ``None``, the point's name is used.
+ - ``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
- - ``parameters`` -- (default: ``None``) dictionary giving the numerical
- values of the parameters that may appear in the point coordinates
OUTPUT:
@@ -741,7 +742,8 @@ class ManifoldPoint(Element):
sage: print(g)
Graphics object consisting of 2 graphics primitives
sage: gX = X.plot(max_range=4) # plot of the coordinate grid
- sage: show(g+gX) # display of the point atop the coordinate grid
+ sage: g + gX # display of the point atop the coordinate grid
+ Graphics object consisting of 20 graphics primitives
.. PLOT::
@@ -757,13 +759,15 @@ class ManifoldPoint(Element):
``plot``::
sage: g = p.plot()
- sage: show(g+gX)
+ 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: show(g+gX)
+ sage: g + gX
+ Graphics object consisting of 20 graphics primitives
.. PLOT::
@@ -781,7 +785,8 @@ class ManifoldPoint(Element):
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: show(g+gX+gq)
+ sage: g + gX + gq
+ Graphics object consisting of 22 graphics primitives
.. PLOT::
@@ -810,13 +815,15 @@ class ManifoldPoint(Element):
sage: print(g)
Graphics3d Object
sage: gX = X.plot(nb_values=5) # coordinate mesh cube
- sage: show(g+gX) # display of the point atop the coordinate mesh
+ 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: show(g+gX)
+ 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``::
@@ -832,7 +839,8 @@ class ManifoldPoint(Element):
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, nb_values=9)
- sage: show(g+gS2)
+ sage: g + gS2
+ Graphics3d Object
Use of the option ``ambient_coords`` for plots on a 4-dimensional
manifold::
@@ -841,14 +849,17 @@ class ManifoldPoint(Element):
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), nb_values=5)
- sage: show(g+gX) # 3D plot
+ sage: gX = X.plot(X, ambient_coords=(t,x,y), nb_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), nb_values=5)
- sage: show(g+gX) # 3D plot
+ sage: gX = X.plot(X, ambient_coords=(t,y,z), nb_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: show(g+gX) # 2D plot
+ sage: g + gX # 2D plot
+ Graphics object consisting of 20 graphics primitives
.. PLOT::
@@ -866,8 +877,8 @@ class ManifoldPoint(Element):
from sage.plot.plot3d.shapes2 import point3d, text3d
from sage.manifolds.chart import Chart
if self._manifold.base_field_type() != 'real':
- raise NotImplementedError('plot of points on manifolds over ' +
- 'fields different from R is not implemented')
+ raise NotImplementedError('plot of points on manifolds over fields different'
+ ' from the real field is not implemented')
# The ambient chart:
if chart is None:
chart = self.parent().default_chart()
@@ -884,8 +895,16 @@ class ManifoldPoint(Element):
elif not isinstance(ambient_coords, tuple):
ambient_coords = tuple(ambient_coords)
nca = len(ambient_coords)
- if nca != 2 and nca !=3:
- raise TypeError("bad number of ambient coordinates: {}".format(nca))
+ if nca != 2 and nca != 3:
+ raise TypeError("invalid number of ambient coordinates: {}".format(nca))
+
+ # Extract the kwds options
+ size = kwds['size']
+ color = kwds['color']
+ label_color = kwds['label_color']
+ fontsize = kwds['fontsize']
+ label_offset = kwds['label_offset']
+
# The point coordinates:
coords = eff_point.coord(chart)
xx = chart[:]
@@ -900,11 +919,12 @@ class ManifoldPoint(Element):
if nca == 2:
if label is None:
label = r'$' + self._latex_name + r'$'
- resu += point2d(xp, color=color, size=size) + \
- text(label, xlab, fontsize=fontsize, color=label_color)
+ resu += (point2d(xp, color=color, size=size) +
+ text(label, xlab, fontsize=fontsize, color=label_color))
else:
if label is None:
label = self._name
- resu += point3d(xp, color=color, size=size) + \
- text3d(label, xlab, fontsize=fontsize, color=label_color)
+ resu += (point3d(xp, color=color, size=size) +
+ text3d(label, xlab, fontsize=fontsize, color=label_color))
return resu
+
diff --git a/src/sage/manifolds/scalarfield.py b/src/sage/manifolds/scalarfield.py
index cb67373..2b3111d 100644
--- a/src/sage/manifolds/scalarfield.py
+++ b/src/sage/manifolds/scalarfield.py
@@ -37,7 +37,6 @@ REFERENCES:
#******************************************************************************
from sage.structure.element import CommutativeAlgebraElement
-from sage.rings.integer import Integer
from sage.symbolic.expression import Expression
from sage.manifolds.coord_func import CoordFunction
@@ -1572,8 +1571,6 @@ class ScalarField(CommutativeAlgebraElement):
"""
if not isinstance(other, ScalarField):
raise TypeError("the second argument must be a scalar field")
- dom1 = self._domain
- dom2 = other._domain
coord_changes = self._manifold._coord_changes
resu = []
#
diff --git a/src/sage/manifolds/utilities.py b/src/sage/manifolds/utilities.py
index 2c3c023..690412a 100644
--- a/src/sage/manifolds/utilities.py
+++ b/src/sage/manifolds/utilities.py
@@ -18,11 +18,14 @@ AUTHORS:
# Copyright (C) 2015 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
# Copyright (C) 2016 Travis Scrimshaw <tscrimsh@umn.edu>
#
-# 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.
+# 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/
-#******************************************************************************
+#*****************************************************************************
+
+from __future__ import division
from sage.symbolic.expression import Expression
@@ -79,7 +82,6 @@ def simplify_sqrt_real(expr):
"""
from sage.symbolic.ring import SR
- from sage.calculus.calculus import maxima
from sage.functions.other import sqrt
# 1/ Search for the sqrt's in expr
sexpr = str(expr)
@@ -318,11 +320,11 @@ def simplify_chain_real(expr):
Other simplifications::
sage: s = abs(sin(pi*x))
- sage: simplify_chain_real(s) # correct output since x in (0,1) # known bug - #20475
+ sage: simplify_chain_real(s) # correct output since x in (0,1)
sin(pi*x)
- sage: s.simplify_real() # unsimplified output # known bug - #20475
+ sage: s.simplify_real() # unsimplified output
abs(sin(pi*x))
- sage: s.simplify_full() # unsimplified output # known bug - #20475
+ sage: s.simplify_full() # unsimplified output
abs(sin(pi*x))
::
@@ -839,16 +841,17 @@ def _list_functions(ex, list_f):
def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds):
r"""
- Set axes labels for a 3D graphics object.
+ Set axes labels for a 3D graphics object ``graph``.
- This is a workaround for the lack of axes labels in Sage 3D plots; it
- sets the labels as text3d objects at locations determined from the
- bounding box of the graphic object ``graph``.
+ This is a workaround for the lack of axes labels in 3D plots.
+ This sets the labels as :func:`~sage.plot.plot3d.shapes2.text3d`
+ objects at locations determined from the bounding box of the
+ graphic object ``graph``.
INPUT:
- - ``graph`` -- a 3D graphic object, as an instance of
- :class:`~sage.plot.plot3d.base.Graphics3d`
+ - ``graph`` -- :class:`~sage.plot.plot3d.base.Graphics3d`;
+ a 3D graphic object
- ``xlabel`` -- string for the x-axis label
- ``ylabel`` -- string for the y-axis label
- ``zlabel`` -- string for the z-axis label
@@ -856,19 +859,18 @@ def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds):
OUTPUT:
- - the 3D graphic object with text3d labels added.
+ - the 3D graphic object with text3d labels added
- EXAMPLE::
+ EXAMPLES::
sage: g = sphere()
- sage: print(g)
- Graphics3d Object
- sage: show(g) # no axes labels
+ sage: g.all
+ [Graphics3d Object]
sage: from sage.manifolds.utilities import set_axes_labels
sage: ga = set_axes_labels(g, 'X', 'Y', 'Z', color='red')
- sage: print(ga)
- Graphics3d Object
- sage: show(ga) # the 3D frame has now axes labels
+ sage: ga.all # the 3D frame has now axes labels
+ [Graphics3d Object, Graphics3d Object,
+ Graphics3d Object, Graphics3d Object]
"""
from sage.plot.plot3d.shapes2 import text3d
@@ -888,3 +890,4 @@ def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds):
graph += text3d(' ' + ylabel, (xmax1, y1, zmin1), **kwds)
graph += text3d(' ' + zlabel, (xmin1, ymin1, z1), **kwds)
return graph
+