passagemath-symbolics 10.6.40__cp314-cp314t-macosx_13_0_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-symbolics might be problematic. Click here for more details.
- passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.40.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.40.dist-info/RECORD +172 -0
- passagemath_symbolics-10.6.40.dist-info/WHEEL +6 -0
- passagemath_symbolics-10.6.40.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2826 -0
- sage/calculus/desolvers.py +1866 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-314t-darwin.so +0 -0
- sage/calculus/var.pyx +401 -0
- sage/dynamics/all__sagemath_symbolics.py +6 -0
- sage/dynamics/complex_dynamics/all.py +5 -0
- sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-darwin.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
- sage/ext/all__sagemath_symbolics.py +1 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/magma/latex/latex.m +1021 -0
- sage/ext_data/magma/latex/latex.spec +1 -0
- sage/ext_data/magma/sage/basic.m +356 -0
- sage/ext_data/magma/sage/sage.spec +1 -0
- sage/ext_data/magma/spec +9 -0
- sage/geometry/all__sagemath_symbolics.py +8 -0
- sage/geometry/hyperbolic_space/all.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
- sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
- sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
- sage/geometry/riemannian_manifolds/all.py +7 -0
- sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
- sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
- sage/interfaces/all__sagemath_symbolics.py +1 -0
- sage/interfaces/magma.py +3017 -0
- sage/interfaces/magma_free.py +92 -0
- sage/interfaces/maple.py +1397 -0
- sage/interfaces/mathematica.py +1345 -0
- sage/interfaces/mathics.py +1312 -0
- sage/interfaces/sympy.py +1398 -0
- sage/interfaces/sympy_wrapper.py +197 -0
- sage/interfaces/tides.py +938 -0
- sage/libs/all__sagemath_symbolics.py +6 -0
- sage/manifolds/all.py +7 -0
- sage/manifolds/calculus_method.py +555 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4019 -0
- sage/manifolds/chart_func.py +3419 -0
- sage/manifolds/continuous_map.py +2183 -0
- sage/manifolds/continuous_map_image.py +155 -0
- sage/manifolds/differentiable/affine_connection.py +2475 -0
- sage/manifolds/differentiable/all.py +1 -0
- sage/manifolds/differentiable/automorphismfield.py +1383 -0
- sage/manifolds/differentiable/automorphismfield_group.py +604 -0
- sage/manifolds/differentiable/bundle_connection.py +1445 -0
- sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
- sage/manifolds/differentiable/chart.py +1241 -0
- sage/manifolds/differentiable/curve.py +1028 -0
- sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
- sage/manifolds/differentiable/degenerate.py +559 -0
- sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
- sage/manifolds/differentiable/diff_form.py +1658 -0
- sage/manifolds/differentiable/diff_form_module.py +1062 -0
- sage/manifolds/differentiable/diff_map.py +1315 -0
- sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
- sage/manifolds/differentiable/examples/all.py +1 -0
- sage/manifolds/differentiable/examples/euclidean.py +2517 -0
- sage/manifolds/differentiable/examples/real_line.py +897 -0
- sage/manifolds/differentiable/examples/sphere.py +1186 -0
- sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
- sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
- sage/manifolds/differentiable/integrated_curve.py +4035 -0
- sage/manifolds/differentiable/levi_civita_connection.py +841 -0
- sage/manifolds/differentiable/manifold.py +4254 -0
- sage/manifolds/differentiable/manifold_homset.py +1826 -0
- sage/manifolds/differentiable/metric.py +3032 -0
- sage/manifolds/differentiable/mixed_form.py +1507 -0
- sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
- sage/manifolds/differentiable/multivector_module.py +800 -0
- sage/manifolds/differentiable/multivectorfield.py +1520 -0
- sage/manifolds/differentiable/poisson_tensor.py +268 -0
- sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
- sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
- sage/manifolds/differentiable/scalarfield.py +1343 -0
- sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
- sage/manifolds/differentiable/symplectic_form.py +910 -0
- sage/manifolds/differentiable/symplectic_form_test.py +220 -0
- sage/manifolds/differentiable/tangent_space.py +412 -0
- sage/manifolds/differentiable/tangent_vector.py +616 -0
- sage/manifolds/differentiable/tensorfield.py +4665 -0
- sage/manifolds/differentiable/tensorfield_module.py +963 -0
- sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
- sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
- sage/manifolds/differentiable/vector_bundle.py +1728 -0
- sage/manifolds/differentiable/vectorfield.py +1717 -0
- sage/manifolds/differentiable/vectorfield_module.py +2445 -0
- sage/manifolds/differentiable/vectorframe.py +1832 -0
- sage/manifolds/family.py +270 -0
- sage/manifolds/local_frame.py +1490 -0
- sage/manifolds/manifold.py +3090 -0
- sage/manifolds/manifold_homset.py +452 -0
- sage/manifolds/operators.py +359 -0
- sage/manifolds/point.py +994 -0
- sage/manifolds/scalarfield.py +3718 -0
- sage/manifolds/scalarfield_algebra.py +629 -0
- sage/manifolds/section.py +3111 -0
- sage/manifolds/section_module.py +831 -0
- sage/manifolds/structure.py +229 -0
- sage/manifolds/subset.py +2764 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +885 -0
- sage/manifolds/topological_submanifold.py +891 -0
- sage/manifolds/trivialization.py +733 -0
- sage/manifolds/utilities.py +1348 -0
- sage/manifolds/vector_bundle.py +1342 -0
- sage/manifolds/vector_bundle_fiber.py +332 -0
- sage/manifolds/vector_bundle_fiber_element.py +111 -0
- sage/matrix/all__sagemath_symbolics.py +1 -0
- sage/matrix/matrix_symbolic_dense.cpython-314t-darwin.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1022 -0
- sage/matrix/matrix_symbolic_sparse.cpython-314t-darwin.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
- sage/modules/all__sagemath_symbolics.py +1 -0
- sage/modules/vector_callable_symbolic_dense.py +105 -0
- sage/modules/vector_symbolic_dense.py +116 -0
- sage/modules/vector_symbolic_sparse.py +118 -0
- sage/rings/all__sagemath_symbolics.py +4 -0
- sage/rings/asymptotic/all.py +6 -0
- sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
- sage/rings/asymptotic/asymptotic_ring.py +4858 -0
- sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5237 -0
- sage/rings/function_field/all__sagemath_symbolics.py +2 -0
- sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
- sage/symbolic/all.py +15 -0
- sage/symbolic/assumptions.py +985 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +459 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1287 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1713 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +270 -0
- sage/symbolic/integration/integral.py +1115 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/random_tests.py +462 -0
- sage/symbolic/relation.py +1907 -0
- sage/symbolic/ring.cpython-314t-darwin.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyx +1396 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1470 -0
|
@@ -0,0 +1,3419 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Chart Functions
|
|
4
|
+
|
|
5
|
+
In the context of a topological manifold `M` over a topological field
|
|
6
|
+
`K`, a *chart function* is a function from a chart codomain
|
|
7
|
+
to `K`.
|
|
8
|
+
In other words, a chart function is a `K`-valued function of the coordinates
|
|
9
|
+
associated to some chart. The internal coordinate expressions of chart
|
|
10
|
+
functions and calculus on them are taken in charge by different calculus
|
|
11
|
+
methods, at the choice of the user:
|
|
12
|
+
|
|
13
|
+
- Sage's default symbolic engine (Pynac + Maxima), implemented via the
|
|
14
|
+
Symbolic Ring (``SR``)
|
|
15
|
+
- SymPy engine, denoted ``sympy`` hereafter
|
|
16
|
+
|
|
17
|
+
See :class:`~sage.manifolds.calculus_method.CalculusMethod` for details.
|
|
18
|
+
|
|
19
|
+
AUTHORS:
|
|
20
|
+
|
|
21
|
+
- Marco Mancini (2017) : initial version
|
|
22
|
+
- Eric Gourgoulhon (2015) : for a previous class implementing only SR
|
|
23
|
+
calculus (CoordFunctionSymb)
|
|
24
|
+
- Florentin Jaffredo (2018) : series expansion with respect to a given
|
|
25
|
+
parameter
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
# ****************************************************************************
|
|
29
|
+
# Copyright (C) 2017 Marco Mancini <marco.mancini@obspm.fr>
|
|
30
|
+
# Copyright (C) 2018 Florentin Jaffredo <florentin.jaffredo@polytechnique.edu>
|
|
31
|
+
#
|
|
32
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
33
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
34
|
+
# the License, or (at your option) any later version.
|
|
35
|
+
# https://www.gnu.org/licenses/
|
|
36
|
+
# ****************************************************************************
|
|
37
|
+
try:
|
|
38
|
+
from typing import Self # type: ignore (Python >= 3.11)
|
|
39
|
+
except ImportError:
|
|
40
|
+
from typing_extensions import Self # type: ignore (Python 3.10)
|
|
41
|
+
|
|
42
|
+
from sage.categories.commutative_algebras import CommutativeAlgebras
|
|
43
|
+
from sage.manifolds.utilities import ExpressionNice
|
|
44
|
+
from sage.misc.cachefunc import cached_method
|
|
45
|
+
from sage.structure.element import AlgebraElement, ModuleElementWithMutability
|
|
46
|
+
from sage.structure.mutability import Mutability
|
|
47
|
+
from sage.structure.parent import Parent
|
|
48
|
+
from sage.structure.sage_object import SageObject
|
|
49
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
|
50
|
+
from sage.symbolic.ring import SR
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
import sympy
|
|
54
|
+
except ImportError:
|
|
55
|
+
pass
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class ChartFunction(AlgebraElement, ModuleElementWithMutability):
|
|
59
|
+
r"""
|
|
60
|
+
Function of coordinates of a given chart.
|
|
61
|
+
|
|
62
|
+
If `(U, \varphi)` is a chart on a topological manifold `M` of
|
|
63
|
+
dimension `n` over a topological field `K`, a *chart function*
|
|
64
|
+
associated to `(U, \varphi)` is a map
|
|
65
|
+
|
|
66
|
+
.. MATH::
|
|
67
|
+
|
|
68
|
+
\begin{array}{llcl}
|
|
69
|
+
f:& V \subset K^n & \longrightarrow & K \\
|
|
70
|
+
& (x^1, \ldots, x^n) & \longmapsto & f(x^1, \ldots, x^n),
|
|
71
|
+
\end{array}
|
|
72
|
+
|
|
73
|
+
where `V` is the codomain of `\varphi`. In other words, `f` is a
|
|
74
|
+
`K`-valued function of the coordinates associated to the chart
|
|
75
|
+
`(U, \varphi)`.
|
|
76
|
+
|
|
77
|
+
The chart function `f` can be represented by expressions pertaining to
|
|
78
|
+
different calculus methods; the currently implemented ones are
|
|
79
|
+
|
|
80
|
+
- ``SR`` (Sage's Symbolic Ring)
|
|
81
|
+
- ``SymPy``
|
|
82
|
+
|
|
83
|
+
See :meth:`~sage.manifolds.chart_func.ChartFunction.expr` for details.
|
|
84
|
+
|
|
85
|
+
INPUT:
|
|
86
|
+
|
|
87
|
+
- ``parent`` -- the algebra of chart functions on the chart
|
|
88
|
+
`(U, \varphi)`
|
|
89
|
+
|
|
90
|
+
- ``expression`` -- (default: ``None``) a symbolic expression representing
|
|
91
|
+
`f(x^1, \ldots, x^n)`, where `(x^1, \ldots, x^n)` are the
|
|
92
|
+
coordinates of the chart `(U, \varphi)`
|
|
93
|
+
|
|
94
|
+
- ``calc_method`` -- string (default: ``None``); the calculus method with
|
|
95
|
+
respect to which the internal expression of ``self`` must be initialized
|
|
96
|
+
from ``expression``. One of
|
|
97
|
+
|
|
98
|
+
- ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
|
|
99
|
+
- ``'sympy'``: SymPy
|
|
100
|
+
- ``None``: the chart current calculus method is assumed
|
|
101
|
+
|
|
102
|
+
- ``expansion_symbol`` -- (default: ``None``) symbolic variable (the "small
|
|
103
|
+
parameter") with respect to which the coordinate expression is expanded
|
|
104
|
+
in power series (around the zero value of this variable)
|
|
105
|
+
|
|
106
|
+
- ``order`` -- integer (default: ``None``); the order of the expansion
|
|
107
|
+
if ``expansion_symbol`` is not ``None``; the *order* is defined as the
|
|
108
|
+
degree of the polynomial representing the truncated power series in
|
|
109
|
+
``expansion_symbol``
|
|
110
|
+
|
|
111
|
+
.. WARNING::
|
|
112
|
+
|
|
113
|
+
The value of ``order`` is `n-1`, where `n` is the order of the
|
|
114
|
+
big `O` in the power series expansion
|
|
115
|
+
|
|
116
|
+
EXAMPLES:
|
|
117
|
+
|
|
118
|
+
A symbolic chart function on a 2-dimensional manifold::
|
|
119
|
+
|
|
120
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
121
|
+
sage: X.<x,y> = M.chart()
|
|
122
|
+
sage: f = X.function(x^2+3*y+1)
|
|
123
|
+
sage: type(f)
|
|
124
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
125
|
+
sage: f.display()
|
|
126
|
+
(x, y) ↦ x^2 + 3*y + 1
|
|
127
|
+
sage: f(x,y)
|
|
128
|
+
x^2 + 3*y + 1
|
|
129
|
+
|
|
130
|
+
The symbolic expression is returned when asking for the direct display of
|
|
131
|
+
the function::
|
|
132
|
+
|
|
133
|
+
sage: f
|
|
134
|
+
x^2 + 3*y + 1
|
|
135
|
+
sage: latex(f)
|
|
136
|
+
x^{2} + 3 \, y + 1
|
|
137
|
+
|
|
138
|
+
A similar output is obtained by means of the method :meth:`expr`::
|
|
139
|
+
|
|
140
|
+
sage: f.expr()
|
|
141
|
+
x^2 + 3*y + 1
|
|
142
|
+
|
|
143
|
+
The expression returned by :meth:`expr` is by default a Sage symbolic
|
|
144
|
+
expression::
|
|
145
|
+
|
|
146
|
+
sage: type(f.expr())
|
|
147
|
+
<class 'sage.symbolic.expression.Expression'>
|
|
148
|
+
|
|
149
|
+
A SymPy expression can also be asked for::
|
|
150
|
+
|
|
151
|
+
sage: f.expr('sympy')
|
|
152
|
+
x**2 + 3*y + 1
|
|
153
|
+
sage: type(f.expr('sympy'))
|
|
154
|
+
<class 'sympy.core.add.Add'>
|
|
155
|
+
|
|
156
|
+
The value of the function at specified coordinates is obtained by means
|
|
157
|
+
of the standard parentheses notation::
|
|
158
|
+
|
|
159
|
+
sage: f(2,-1)
|
|
160
|
+
2
|
|
161
|
+
sage: var('a b')
|
|
162
|
+
(a, b)
|
|
163
|
+
sage: f(a,b)
|
|
164
|
+
a^2 + 3*b + 1
|
|
165
|
+
|
|
166
|
+
An unspecified chart function::
|
|
167
|
+
|
|
168
|
+
sage: g = X.function(function('G')(x, y))
|
|
169
|
+
sage: g
|
|
170
|
+
G(x, y)
|
|
171
|
+
sage: g.display()
|
|
172
|
+
(x, y) ↦ G(x, y)
|
|
173
|
+
sage: g.expr()
|
|
174
|
+
G(x, y)
|
|
175
|
+
sage: g(2,3)
|
|
176
|
+
G(2, 3)
|
|
177
|
+
|
|
178
|
+
Coordinate functions can be compared to other values::
|
|
179
|
+
|
|
180
|
+
sage: f = X.function(x^2+3*y+1)
|
|
181
|
+
sage: f == 2
|
|
182
|
+
False
|
|
183
|
+
sage: f == x^2 + 3*y + 1
|
|
184
|
+
True
|
|
185
|
+
sage: g = X.function(x*y)
|
|
186
|
+
sage: f == g
|
|
187
|
+
False
|
|
188
|
+
sage: h = X.function(x^2+3*y+1)
|
|
189
|
+
sage: f == h
|
|
190
|
+
True
|
|
191
|
+
|
|
192
|
+
A coercion by means of the restriction is implemented::
|
|
193
|
+
|
|
194
|
+
sage: D = M.open_subset('D')
|
|
195
|
+
sage: X_D = X.restrict(D, x^2+y^2<1) # open disk
|
|
196
|
+
sage: c = X_D.function(x^2)
|
|
197
|
+
sage: c + f
|
|
198
|
+
2*x^2 + 3*y + 1
|
|
199
|
+
|
|
200
|
+
Expansion to a given order with respect to a small parameter::
|
|
201
|
+
|
|
202
|
+
sage: t = var('t') # the small parameter
|
|
203
|
+
sage: f = X.function(cos(t)*x*y, expansion_symbol=t, order=2)
|
|
204
|
+
|
|
205
|
+
The expansion is triggered by the call to :meth:`simplify`::
|
|
206
|
+
|
|
207
|
+
sage: f
|
|
208
|
+
x*y*cos(t)
|
|
209
|
+
sage: f.simplify()
|
|
210
|
+
-1/2*t^2*x*y + x*y
|
|
211
|
+
|
|
212
|
+
.. RUBRIC:: Differences between ``ChartFunction`` and callable
|
|
213
|
+
symbolic expressions
|
|
214
|
+
|
|
215
|
+
Callable symbolic expressions are defined directly from symbolic
|
|
216
|
+
expressions of the coordinates::
|
|
217
|
+
|
|
218
|
+
sage: f0(x,y) = x^2 + 3*y + 1
|
|
219
|
+
sage: type(f0)
|
|
220
|
+
<class 'sage.symbolic.expression.Expression'>
|
|
221
|
+
sage: f0
|
|
222
|
+
(x, y) |--> x^2 + 3*y + 1
|
|
223
|
+
sage: f0(x,y)
|
|
224
|
+
x^2 + 3*y + 1
|
|
225
|
+
|
|
226
|
+
To get an output similar to that of ``f0`` for a chart function, we must
|
|
227
|
+
use the method :meth:`display`::
|
|
228
|
+
|
|
229
|
+
sage: f = X.function(x^2+3*y+1)
|
|
230
|
+
sage: f
|
|
231
|
+
x^2 + 3*y + 1
|
|
232
|
+
sage: f.display()
|
|
233
|
+
(x, y) ↦ x^2 + 3*y + 1
|
|
234
|
+
sage: f(x,y)
|
|
235
|
+
x^2 + 3*y + 1
|
|
236
|
+
|
|
237
|
+
More importantly, instances of :class:`ChartFunction` differ from
|
|
238
|
+
callable symbolic expression by the automatic simplifications in all
|
|
239
|
+
operations. For instance, adding the two callable symbolic expressions::
|
|
240
|
+
|
|
241
|
+
sage: f0(x,y,z) = cos(x)^2 ; g0(x,y,z) = sin(x)^2
|
|
242
|
+
|
|
243
|
+
results in::
|
|
244
|
+
|
|
245
|
+
sage: f0 + g0
|
|
246
|
+
(x, y, z) |--> cos(x)^2 + sin(x)^2
|
|
247
|
+
|
|
248
|
+
To get `1`, one has to call
|
|
249
|
+
:meth:`~sage.symbolic.expression.Expression.simplify_trig`::
|
|
250
|
+
|
|
251
|
+
sage: (f0 + g0).simplify_trig()
|
|
252
|
+
(x, y, z) |--> 1
|
|
253
|
+
|
|
254
|
+
On the contrary, the sum of the corresponding :class:`ChartFunction`
|
|
255
|
+
instances is automatically simplified (see
|
|
256
|
+
:func:`~sage.manifolds.utilities.simplify_chain_real` and
|
|
257
|
+
:func:`~sage.manifolds.utilities.simplify_chain_generic` for details)::
|
|
258
|
+
|
|
259
|
+
sage: f = X.function(cos(x)^2) ; g = X.function(sin(x)^2)
|
|
260
|
+
sage: f + g
|
|
261
|
+
1
|
|
262
|
+
|
|
263
|
+
Another difference regards the display of partial derivatives:
|
|
264
|
+
for callable symbolic functions, it involves ``diff``::
|
|
265
|
+
|
|
266
|
+
sage: g = function('g')(x, y)
|
|
267
|
+
sage: f0(x,y) = diff(g, x) + diff(g, y)
|
|
268
|
+
sage: f0
|
|
269
|
+
(x, y) |--> diff(g(x, y), x) + diff(g(x, y), y)
|
|
270
|
+
|
|
271
|
+
while for chart functions, the display is more "textbook" like::
|
|
272
|
+
|
|
273
|
+
sage: f = X.function(diff(g, x) + diff(g, y))
|
|
274
|
+
sage: f
|
|
275
|
+
d(g)/dx + d(g)/dy
|
|
276
|
+
|
|
277
|
+
The difference is even more dramatic on LaTeX outputs::
|
|
278
|
+
|
|
279
|
+
sage: latex(f0)
|
|
280
|
+
\left( x, y \right) \ {\mapsto} \ \frac{\partial}{\partial x}g\left(x, y\right) + \frac{\partial}{\partial y}g\left(x, y\right)
|
|
281
|
+
sage: latex(f)
|
|
282
|
+
\frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}
|
|
283
|
+
|
|
284
|
+
Note that this regards only the display of coordinate functions:
|
|
285
|
+
internally, the ``diff`` notation is still used, as we can check by asking
|
|
286
|
+
for the symbolic expression stored in ``f``::
|
|
287
|
+
|
|
288
|
+
sage: f.expr()
|
|
289
|
+
diff(g(x, y), x) + diff(g(x, y), y)
|
|
290
|
+
|
|
291
|
+
One can switch to Pynac notation by changing the options::
|
|
292
|
+
|
|
293
|
+
sage: Manifold.options.textbook_output=False
|
|
294
|
+
sage: latex(f)
|
|
295
|
+
\frac{\partial}{\partial x}g\left(x, y\right) + \frac{\partial}{\partial y}g\left(x, y\right)
|
|
296
|
+
sage: Manifold.options._reset()
|
|
297
|
+
sage: latex(f)
|
|
298
|
+
\frac{\partial\,g}{\partial x} + \frac{\partial\,g}{\partial y}
|
|
299
|
+
|
|
300
|
+
Another difference between :class:`ChartFunction` and
|
|
301
|
+
callable symbolic expression is the possibility to switch off the display
|
|
302
|
+
of the arguments of unspecified functions. Consider for instance::
|
|
303
|
+
|
|
304
|
+
sage: f = X.function(function('u')(x, y) * function('v')(x, y))
|
|
305
|
+
sage: f
|
|
306
|
+
u(x, y)*v(x, y)
|
|
307
|
+
sage: f0(x,y) = function('u')(x, y) * function('v')(x, y)
|
|
308
|
+
sage: f0
|
|
309
|
+
(x, y) |--> u(x, y)*v(x, y)
|
|
310
|
+
|
|
311
|
+
If there is a clear understanding that `u` and `v` are functions of
|
|
312
|
+
`(x,y)`, the explicit mention of the latter can be cumbersome in lengthy
|
|
313
|
+
tensor expressions. We can switch it off by::
|
|
314
|
+
|
|
315
|
+
sage: Manifold.options.omit_function_arguments=True
|
|
316
|
+
sage: f
|
|
317
|
+
u*v
|
|
318
|
+
|
|
319
|
+
Note that neither the callable symbolic expression ``f0`` nor the internal
|
|
320
|
+
expression of ``f`` is affected by the above command::
|
|
321
|
+
|
|
322
|
+
sage: f0
|
|
323
|
+
(x, y) |--> u(x, y)*v(x, y)
|
|
324
|
+
sage: f.expr()
|
|
325
|
+
u(x, y)*v(x, y)
|
|
326
|
+
|
|
327
|
+
We revert to the default behavior by::
|
|
328
|
+
|
|
329
|
+
sage: Manifold.options._reset()
|
|
330
|
+
sage: f
|
|
331
|
+
u(x, y)*v(x, y)
|
|
332
|
+
|
|
333
|
+
.. automethod:: __call__
|
|
334
|
+
"""
|
|
335
|
+
|
|
336
|
+
def __init__(
|
|
337
|
+
self,
|
|
338
|
+
parent,
|
|
339
|
+
expression=None,
|
|
340
|
+
calc_method=None,
|
|
341
|
+
expansion_symbol=None,
|
|
342
|
+
order=None,
|
|
343
|
+
):
|
|
344
|
+
r"""
|
|
345
|
+
Initialize ``self``.
|
|
346
|
+
|
|
347
|
+
TESTS:
|
|
348
|
+
|
|
349
|
+
Chart function on a real manifold::
|
|
350
|
+
|
|
351
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
352
|
+
sage: X.<x,y> = M.chart()
|
|
353
|
+
sage: f = X.function(x^3+y); f
|
|
354
|
+
x^3 + y
|
|
355
|
+
sage: type(f)
|
|
356
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
357
|
+
sage: TestSuite(f).run()
|
|
358
|
+
|
|
359
|
+
Using SymPy::
|
|
360
|
+
|
|
361
|
+
sage: X.calculus_method().set('sympy')
|
|
362
|
+
sage: f = X.function(x^3+y)
|
|
363
|
+
sage: f
|
|
364
|
+
x**3 + y
|
|
365
|
+
sage: TestSuite(f).run()
|
|
366
|
+
|
|
367
|
+
Chart function on a complex manifold::
|
|
368
|
+
|
|
369
|
+
sage: N = Manifold(2, 'N', structure='topological', field='complex')
|
|
370
|
+
sage: Y.<z,w> = N.chart()
|
|
371
|
+
sage: g = Y.function(i*z + 2*w); g
|
|
372
|
+
2*w + I*z
|
|
373
|
+
sage: TestSuite(g).run()
|
|
374
|
+
"""
|
|
375
|
+
ModuleElementWithMutability.__init__(self, parent)
|
|
376
|
+
self._chart = parent._chart
|
|
377
|
+
self._nc = len(self._chart[:])
|
|
378
|
+
self._express = {}
|
|
379
|
+
# set the calculation method managing
|
|
380
|
+
self._calc_method = self._chart._calc_method
|
|
381
|
+
if expression is not None:
|
|
382
|
+
if calc_method is None:
|
|
383
|
+
calc_method = self._calc_method._current
|
|
384
|
+
self._express[calc_method] = self._calc_method._tranf[calc_method](
|
|
385
|
+
expression
|
|
386
|
+
)
|
|
387
|
+
# Derived quantities:
|
|
388
|
+
self._der = None # list of partial derivatives (to be set by diff()
|
|
389
|
+
# and unset by del_derived())
|
|
390
|
+
self._expansion_symbol = expansion_symbol
|
|
391
|
+
self._order = order
|
|
392
|
+
|
|
393
|
+
def _simplify(self, expr):
|
|
394
|
+
"""
|
|
395
|
+
Simplify the expression `expr` using `self._calc_method.simplify`.
|
|
396
|
+
|
|
397
|
+
If needed, truncate the expression to the predefined order in the
|
|
398
|
+
power series with respect to a small parameter.
|
|
399
|
+
|
|
400
|
+
INPUT:
|
|
401
|
+
|
|
402
|
+
- ``expr`` -- expression to simplify
|
|
403
|
+
|
|
404
|
+
OUTPUT: simplified expression
|
|
405
|
+
|
|
406
|
+
EXAMPLES:
|
|
407
|
+
|
|
408
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
409
|
+
sage: c_xy.<x,y> = M.chart()
|
|
410
|
+
sage: fc = c_xy.function(x+2*y^3)
|
|
411
|
+
sage: fc._simplify(x+x)
|
|
412
|
+
2*x
|
|
413
|
+
"""
|
|
414
|
+
res = self._calc_method.simplify(expr)
|
|
415
|
+
if self._expansion_symbol is not None and self._calc_method._current == 'SR':
|
|
416
|
+
res = res.series(self._expansion_symbol, self._order + 1).truncate()
|
|
417
|
+
return res
|
|
418
|
+
|
|
419
|
+
def chart(self):
|
|
420
|
+
r"""
|
|
421
|
+
Return the chart with respect to which ``self`` is defined.
|
|
422
|
+
|
|
423
|
+
OUTPUT: a :class:`~sage.manifolds.chart.Chart`
|
|
424
|
+
|
|
425
|
+
EXAMPLES::
|
|
426
|
+
|
|
427
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
428
|
+
sage: X.<x,y> = M.chart()
|
|
429
|
+
sage: f = X.function(1+x+y^2)
|
|
430
|
+
sage: f.chart()
|
|
431
|
+
Chart (M, (x, y))
|
|
432
|
+
sage: f.chart() is X
|
|
433
|
+
True
|
|
434
|
+
"""
|
|
435
|
+
return self._chart
|
|
436
|
+
|
|
437
|
+
def scalar_field(self, name=None, latex_name=None):
|
|
438
|
+
r"""
|
|
439
|
+
Construct the scalar field that has ``self`` as coordinate expression.
|
|
440
|
+
|
|
441
|
+
The domain of the scalar field is the open subset covered by the
|
|
442
|
+
chart on which ``self`` is defined.
|
|
443
|
+
|
|
444
|
+
INPUT:
|
|
445
|
+
|
|
446
|
+
- ``name`` -- (default: ``None``) name given to the scalar field
|
|
447
|
+
|
|
448
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the
|
|
449
|
+
scalar field; if ``None``, the LaTeX symbol is set to ``name``
|
|
450
|
+
|
|
451
|
+
OUTPUT: a :class:`~sage.manifolds.scalarfield.ScalarField`
|
|
452
|
+
|
|
453
|
+
EXAMPLES:
|
|
454
|
+
|
|
455
|
+
Construction of a scalar field on a 2-dimensional manifold::
|
|
456
|
+
|
|
457
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
458
|
+
sage: c_xy.<x,y> = M.chart()
|
|
459
|
+
sage: fc = c_xy.function(x+2*y^3)
|
|
460
|
+
sage: f = fc.scalar_field() ; f
|
|
461
|
+
Scalar field on the 2-dimensional topological manifold M
|
|
462
|
+
sage: f.display()
|
|
463
|
+
M → ℝ
|
|
464
|
+
(x, y) ↦ 2*y^3 + x
|
|
465
|
+
sage: f.coord_function(c_xy) is fc
|
|
466
|
+
True
|
|
467
|
+
"""
|
|
468
|
+
alg = self._chart.domain().scalar_field_algebra()
|
|
469
|
+
return alg.element_class(
|
|
470
|
+
alg, coord_expression={self._chart: self}, name=name, latex_name=latex_name
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
def expr(self, method=None):
|
|
474
|
+
r"""
|
|
475
|
+
Return the symbolic expression of ``self`` in terms of the chart
|
|
476
|
+
coordinates, as an object of a specified calculus method.
|
|
477
|
+
|
|
478
|
+
INPUT:
|
|
479
|
+
|
|
480
|
+
- ``method`` -- string (default: ``None``); the calculus method which
|
|
481
|
+
the returned expression belongs to. One of
|
|
482
|
+
|
|
483
|
+
- ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
|
|
484
|
+
- ``'sympy'``: SymPy
|
|
485
|
+
- ``None``: the chart current calculus method is assumed
|
|
486
|
+
|
|
487
|
+
OUTPUT:
|
|
488
|
+
|
|
489
|
+
- a :class:`Sage symbolic expression <sage.symbolic.expression.Expression>`
|
|
490
|
+
if ``method`` is ``'SR'``
|
|
491
|
+
- a SymPy object if ``method`` is ``'sympy'``
|
|
492
|
+
|
|
493
|
+
EXAMPLES:
|
|
494
|
+
|
|
495
|
+
Chart function on a 2-dimensional manifold::
|
|
496
|
+
|
|
497
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
498
|
+
sage: X.<x,y> = M.chart()
|
|
499
|
+
sage: f = X.function(x^2+y)
|
|
500
|
+
sage: f.expr()
|
|
501
|
+
x^2 + y
|
|
502
|
+
sage: type(f.expr())
|
|
503
|
+
<class 'sage.symbolic.expression.Expression'>
|
|
504
|
+
|
|
505
|
+
Asking for the SymPy expression::
|
|
506
|
+
|
|
507
|
+
sage: f.expr('sympy')
|
|
508
|
+
x**2 + y
|
|
509
|
+
sage: type(f.expr('sympy'))
|
|
510
|
+
<class 'sympy.core.add.Add'>
|
|
511
|
+
|
|
512
|
+
The default corresponds to the current calculus method, here the one
|
|
513
|
+
based on the Symbolic Ring ``SR``::
|
|
514
|
+
|
|
515
|
+
sage: f.expr() is f.expr('SR')
|
|
516
|
+
True
|
|
517
|
+
|
|
518
|
+
If we change the current calculus method on chart ``X``, we change the
|
|
519
|
+
default::
|
|
520
|
+
|
|
521
|
+
sage: X.calculus_method().set('sympy')
|
|
522
|
+
sage: f.expr()
|
|
523
|
+
x**2 + y
|
|
524
|
+
sage: f.expr() is f.expr('sympy')
|
|
525
|
+
True
|
|
526
|
+
sage: X.calculus_method().set('SR') # revert back to SR
|
|
527
|
+
|
|
528
|
+
Internally, the expressions corresponding to various calculus methods
|
|
529
|
+
are stored in the dictionary ``_express``::
|
|
530
|
+
|
|
531
|
+
sage: for method in sorted(f._express):
|
|
532
|
+
....: print("'{}': {}".format(method, f._express[method]))
|
|
533
|
+
....:
|
|
534
|
+
'SR': x^2 + y
|
|
535
|
+
'sympy': x**2 + y
|
|
536
|
+
|
|
537
|
+
The method :meth:`expr` is useful for accessing to all the
|
|
538
|
+
symbolic expression functionalities in Sage; for instance::
|
|
539
|
+
|
|
540
|
+
sage: var('a')
|
|
541
|
+
a
|
|
542
|
+
sage: f = X.function(a*x*y); f.display()
|
|
543
|
+
(x, y) ↦ a*x*y
|
|
544
|
+
sage: f.expr()
|
|
545
|
+
a*x*y
|
|
546
|
+
sage: f.expr().subs(a=2)
|
|
547
|
+
2*x*y
|
|
548
|
+
|
|
549
|
+
Note that for substituting the value of a coordinate, the function
|
|
550
|
+
call can be used as well::
|
|
551
|
+
|
|
552
|
+
sage: f(x,3)
|
|
553
|
+
3*a*x
|
|
554
|
+
sage: bool( f(x,3) == f.expr().subs(y=3) )
|
|
555
|
+
True
|
|
556
|
+
"""
|
|
557
|
+
if method is None:
|
|
558
|
+
method = self._calc_method._current
|
|
559
|
+
if method in self._express:
|
|
560
|
+
return self._express[method]
|
|
561
|
+
else:
|
|
562
|
+
for vv in self._express.values():
|
|
563
|
+
try:
|
|
564
|
+
self._express[method] = self._calc_method._tranf[method](vv)
|
|
565
|
+
return self._express[method]
|
|
566
|
+
except (KeyError, ValueError):
|
|
567
|
+
pass
|
|
568
|
+
raise ValueError("no expression found for converting to {}".format(method))
|
|
569
|
+
|
|
570
|
+
def set_expr(self, calc_method, expression):
|
|
571
|
+
r"""
|
|
572
|
+
Add an expression in a particular calculus method ``self``.
|
|
573
|
+
Some control is done to verify the consistency between the
|
|
574
|
+
different representations of the same expression.
|
|
575
|
+
|
|
576
|
+
INPUT:
|
|
577
|
+
|
|
578
|
+
- ``calc_method`` -- calculus method
|
|
579
|
+
|
|
580
|
+
- ``expression`` -- symbolic expression
|
|
581
|
+
|
|
582
|
+
EXAMPLES::
|
|
583
|
+
|
|
584
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
585
|
+
sage: X.<x,y> = M.chart()
|
|
586
|
+
sage: f = X.function(1+x^2)
|
|
587
|
+
sage: f._repr_()
|
|
588
|
+
'x^2 + 1'
|
|
589
|
+
sage: f.set_expr('sympy','x**2+1')
|
|
590
|
+
sage: f # indirect doctest
|
|
591
|
+
x^2 + 1
|
|
592
|
+
|
|
593
|
+
sage: g = X.function(1+x^3)
|
|
594
|
+
sage: g._repr_()
|
|
595
|
+
'x^3 + 1'
|
|
596
|
+
sage: g.set_expr('sympy','x**2+y')
|
|
597
|
+
Traceback (most recent call last):
|
|
598
|
+
...
|
|
599
|
+
ValueError: Expressions are not equal
|
|
600
|
+
"""
|
|
601
|
+
if self.is_immutable():
|
|
602
|
+
raise ValueError(
|
|
603
|
+
"the expressions of an immutable element cannot be changed"
|
|
604
|
+
)
|
|
605
|
+
for vv in self._express.values():
|
|
606
|
+
if not bool(
|
|
607
|
+
self._calc_method._tranf[calc_method](expression)
|
|
608
|
+
== self._calc_method._tranf[calc_method](vv)
|
|
609
|
+
):
|
|
610
|
+
raise ValueError("Expressions are not equal")
|
|
611
|
+
self._express[calc_method] = expression
|
|
612
|
+
|
|
613
|
+
def _repr_(self):
|
|
614
|
+
r"""
|
|
615
|
+
String representation of ``self``.
|
|
616
|
+
|
|
617
|
+
TESTS::
|
|
618
|
+
|
|
619
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
620
|
+
sage: X.<x,y> = M.chart()
|
|
621
|
+
sage: f = X.function(1+x*y)
|
|
622
|
+
sage: f._repr_()
|
|
623
|
+
'x*y + 1'
|
|
624
|
+
sage: repr(f) # indirect doctest
|
|
625
|
+
'x*y + 1'
|
|
626
|
+
sage: f # indirect doctest
|
|
627
|
+
x*y + 1
|
|
628
|
+
"""
|
|
629
|
+
curr = self._calc_method._current
|
|
630
|
+
if curr == 'SR' and self._chart.manifold().options.textbook_output:
|
|
631
|
+
return str(ExpressionNice(self.expr(curr)))
|
|
632
|
+
else:
|
|
633
|
+
return str(self.expr(curr))
|
|
634
|
+
|
|
635
|
+
def _latex_(self):
|
|
636
|
+
r"""
|
|
637
|
+
LaTeX representation of ``self``.
|
|
638
|
+
|
|
639
|
+
TESTS::
|
|
640
|
+
|
|
641
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
642
|
+
sage: X.<x,y> = M.chart()
|
|
643
|
+
sage: f = X.function(cos(x*y/2))
|
|
644
|
+
sage: f._latex_()
|
|
645
|
+
\cos\left(\frac{1}{2} \, x y\right)
|
|
646
|
+
sage: latex(f) # indirect doctest
|
|
647
|
+
\cos\left(\frac{1}{2} \, x y\right)
|
|
648
|
+
"""
|
|
649
|
+
curr = self._calc_method._current
|
|
650
|
+
if curr == 'SR' and self._chart.manifold().options.textbook_output:
|
|
651
|
+
out_expr = ExpressionNice(self._express[curr])
|
|
652
|
+
else:
|
|
653
|
+
out_expr = self._express[curr]
|
|
654
|
+
return self._calc_method._latex_dict[curr](out_expr)
|
|
655
|
+
|
|
656
|
+
def display(self):
|
|
657
|
+
r"""
|
|
658
|
+
Display ``self`` in arrow notation.
|
|
659
|
+
For display the standard ``SR`` representation is used.
|
|
660
|
+
|
|
661
|
+
The output is either text-formatted (console mode) or
|
|
662
|
+
LaTeX-formatted (notebook mode).
|
|
663
|
+
|
|
664
|
+
EXAMPLES:
|
|
665
|
+
|
|
666
|
+
Coordinate function on a 2-dimensional manifold::
|
|
667
|
+
|
|
668
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
669
|
+
sage: X.<x,y> = M.chart()
|
|
670
|
+
sage: f = X.function(cos(x*y/2))
|
|
671
|
+
sage: f.display()
|
|
672
|
+
(x, y) ↦ cos(1/2*x*y)
|
|
673
|
+
sage: latex(f.display())
|
|
674
|
+
\left(x, y\right) \mapsto \cos\left(\frac{1}{2} \, x y\right)
|
|
675
|
+
|
|
676
|
+
A shortcut is ``disp()``::
|
|
677
|
+
|
|
678
|
+
sage: f.disp()
|
|
679
|
+
(x, y) ↦ cos(1/2*x*y)
|
|
680
|
+
|
|
681
|
+
Display of the zero function::
|
|
682
|
+
|
|
683
|
+
sage: X.zero_function().display()
|
|
684
|
+
(x, y) ↦ 0
|
|
685
|
+
"""
|
|
686
|
+
from sage.tensor.modules.format_utilities import FormattedExpansion
|
|
687
|
+
from sage.typeset.unicode_characters import unicode_mapsto
|
|
688
|
+
|
|
689
|
+
curr = self._calc_method._current
|
|
690
|
+
expr = self.expr(curr)
|
|
691
|
+
if curr == 'SR' and self._chart.manifold().options.textbook_output:
|
|
692
|
+
expr = ExpressionNice(expr)
|
|
693
|
+
latex_func = self._calc_method._latex_dict[curr]
|
|
694
|
+
resu_txt = str(self._chart[:]) + ' ' + unicode_mapsto + ' ' + str(expr)
|
|
695
|
+
resu_latex = latex_func(self._chart[:]) + r' \mapsto ' + latex_func(expr)
|
|
696
|
+
return FormattedExpansion(resu_txt, resu_latex)
|
|
697
|
+
|
|
698
|
+
disp = display
|
|
699
|
+
|
|
700
|
+
def __call__(self, *coords, **options):
|
|
701
|
+
r"""
|
|
702
|
+
Compute the value of the function at specified coordinates.
|
|
703
|
+
|
|
704
|
+
INPUT:
|
|
705
|
+
|
|
706
|
+
- ``*coords`` -- list of coordinates `(x^1, \ldots, x^n)`,
|
|
707
|
+
where the function `f` is to be evaluated
|
|
708
|
+
- ``**options`` -- allows to pass ``simplify=False`` to disable the
|
|
709
|
+
call of the simplification chain on the result
|
|
710
|
+
|
|
711
|
+
OUTPUT:
|
|
712
|
+
|
|
713
|
+
- the value `f(x^1, \ldots, x^n)`, where `f` is the current
|
|
714
|
+
chart function
|
|
715
|
+
|
|
716
|
+
EXAMPLES::
|
|
717
|
+
|
|
718
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
719
|
+
sage: X.<x,y> = M.chart()
|
|
720
|
+
sage: f = X.function(sin(x*y))
|
|
721
|
+
sage: f.__call__(-2, 3)
|
|
722
|
+
-sin(6)
|
|
723
|
+
sage: f(-2, 3)
|
|
724
|
+
-sin(6)
|
|
725
|
+
sage: var('a b')
|
|
726
|
+
(a, b)
|
|
727
|
+
sage: f.__call__(a, b)
|
|
728
|
+
sin(a*b)
|
|
729
|
+
sage: f(a,b)
|
|
730
|
+
sin(a*b)
|
|
731
|
+
sage: f.__call__(pi, 1)
|
|
732
|
+
0
|
|
733
|
+
sage: f.__call__(pi, 1/2)
|
|
734
|
+
1
|
|
735
|
+
|
|
736
|
+
With SymPy::
|
|
737
|
+
|
|
738
|
+
sage: X.calculus_method().set('sympy')
|
|
739
|
+
sage: f(-2,3)
|
|
740
|
+
-sin(6)
|
|
741
|
+
sage: type(f(-2,3))
|
|
742
|
+
<class 'sympy.core.mul.Mul'>
|
|
743
|
+
sage: f(a,b)
|
|
744
|
+
sin(a*b)
|
|
745
|
+
sage: type(f(a,b))
|
|
746
|
+
sin
|
|
747
|
+
sage: type(f(pi,1))
|
|
748
|
+
<class 'sympy.core.numbers.Zero'>
|
|
749
|
+
sage: f(pi, 1/2)
|
|
750
|
+
1
|
|
751
|
+
sage: type(f(pi, 1/2))
|
|
752
|
+
<class 'sympy.core.numbers.One'>
|
|
753
|
+
"""
|
|
754
|
+
if len(coords) != self._nc:
|
|
755
|
+
raise ValueError("bad number of coordinates")
|
|
756
|
+
calc = self._calc_method
|
|
757
|
+
curr = calc._current
|
|
758
|
+
if curr == 'SR':
|
|
759
|
+
xx = self._chart._xx
|
|
760
|
+
co = [calc._tranf['SR'](c) for c in coords]
|
|
761
|
+
elif curr == 'sympy':
|
|
762
|
+
xx = [x._sympy_() for x in self._chart._xx]
|
|
763
|
+
co = [calc._tranf['sympy'](c) for c in coords]
|
|
764
|
+
substitutions = dict(zip(xx, co))
|
|
765
|
+
resu = self.expr(curr).subs(substitutions)
|
|
766
|
+
if 'simplify' in options:
|
|
767
|
+
if options['simplify']:
|
|
768
|
+
return calc.simplify(resu, method=curr)
|
|
769
|
+
else:
|
|
770
|
+
return resu
|
|
771
|
+
else:
|
|
772
|
+
return calc.simplify(resu, method=curr)
|
|
773
|
+
|
|
774
|
+
def __bool__(self):
|
|
775
|
+
r"""
|
|
776
|
+
Return ``True`` if ``self`` is nonzero and ``False`` otherwise.
|
|
777
|
+
|
|
778
|
+
This method is called by :meth:`~sage.structure.element.Element.is_zero()`.
|
|
779
|
+
|
|
780
|
+
EXAMPLES:
|
|
781
|
+
|
|
782
|
+
Coordinate functions associated to a 2-dimensional chart::
|
|
783
|
+
|
|
784
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
785
|
+
sage: X.<x,y> = M.chart()
|
|
786
|
+
sage: f = X.function(x^2+3*y+1)
|
|
787
|
+
sage: bool(f)
|
|
788
|
+
True
|
|
789
|
+
sage: f.is_zero()
|
|
790
|
+
False
|
|
791
|
+
sage: f == 0
|
|
792
|
+
False
|
|
793
|
+
sage: g = X.function(0)
|
|
794
|
+
sage: bool(g)
|
|
795
|
+
False
|
|
796
|
+
sage: g.is_zero()
|
|
797
|
+
True
|
|
798
|
+
sage: X.calculus_method().set('sympy')
|
|
799
|
+
sage: g.is_zero()
|
|
800
|
+
True
|
|
801
|
+
sage: g == 0
|
|
802
|
+
True
|
|
803
|
+
sage: X.zero_function().is_zero()
|
|
804
|
+
True
|
|
805
|
+
sage: X.zero_function() == 0
|
|
806
|
+
True
|
|
807
|
+
"""
|
|
808
|
+
curr = self._calc_method._current
|
|
809
|
+
if curr == 'SR':
|
|
810
|
+
val = self.expr(curr).is_zero()
|
|
811
|
+
elif curr == 'sympy':
|
|
812
|
+
val = self.expr(curr).is_zero
|
|
813
|
+
return not val
|
|
814
|
+
|
|
815
|
+
def is_trivial_zero(self):
|
|
816
|
+
r"""
|
|
817
|
+
Check if ``self`` is trivially equal to zero without any
|
|
818
|
+
simplification.
|
|
819
|
+
|
|
820
|
+
This method is supposed to be fast as compared with
|
|
821
|
+
``self.is_zero()`` or ``self == 0`` and is intended to be
|
|
822
|
+
used in library code where trying to obtain a mathematically
|
|
823
|
+
correct result by applying potentially expensive rewrite rules
|
|
824
|
+
is not desirable.
|
|
825
|
+
|
|
826
|
+
EXAMPLES::
|
|
827
|
+
|
|
828
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
829
|
+
sage: X.<x,y> = M.chart()
|
|
830
|
+
sage: f = X.function(0)
|
|
831
|
+
sage: f.is_trivial_zero()
|
|
832
|
+
True
|
|
833
|
+
sage: f = X.function(float(0.0))
|
|
834
|
+
sage: f.is_trivial_zero()
|
|
835
|
+
True
|
|
836
|
+
sage: f = X.function(x-x)
|
|
837
|
+
sage: f.is_trivial_zero()
|
|
838
|
+
True
|
|
839
|
+
sage: X.zero_function().is_trivial_zero()
|
|
840
|
+
True
|
|
841
|
+
|
|
842
|
+
No simplification is attempted, so that ``False`` is returned for
|
|
843
|
+
non-trivial cases::
|
|
844
|
+
|
|
845
|
+
sage: f = X.function(cos(x)^2 + sin(x)^2 - 1)
|
|
846
|
+
sage: f.is_trivial_zero()
|
|
847
|
+
False
|
|
848
|
+
|
|
849
|
+
On the contrary, the method
|
|
850
|
+
:meth:`~sage.structure.element.Element.is_zero` and the direct
|
|
851
|
+
comparison to zero involve some simplification algorithms and
|
|
852
|
+
return ``True``::
|
|
853
|
+
|
|
854
|
+
sage: f.is_zero()
|
|
855
|
+
True
|
|
856
|
+
sage: f == 0
|
|
857
|
+
True
|
|
858
|
+
"""
|
|
859
|
+
curr = self._calc_method._current
|
|
860
|
+
return self._calc_method.is_trivial_zero(self.expr(curr))
|
|
861
|
+
|
|
862
|
+
def is_trivial_one(self):
|
|
863
|
+
r"""
|
|
864
|
+
Check if ``self`` is trivially equal to one without any
|
|
865
|
+
simplification.
|
|
866
|
+
|
|
867
|
+
This method is supposed to be fast as compared with
|
|
868
|
+
``self == 1`` and is intended to be used in library code where
|
|
869
|
+
trying to obtain a mathematically correct result by applying
|
|
870
|
+
potentially expensive rewrite rules is not desirable.
|
|
871
|
+
|
|
872
|
+
EXAMPLES::
|
|
873
|
+
|
|
874
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
875
|
+
sage: X.<x,y> = M.chart()
|
|
876
|
+
sage: f = X.function(1)
|
|
877
|
+
sage: f.is_trivial_one()
|
|
878
|
+
True
|
|
879
|
+
sage: f = X.function(float(1.0))
|
|
880
|
+
sage: f.is_trivial_one()
|
|
881
|
+
True
|
|
882
|
+
sage: f = X.function(x-x+1)
|
|
883
|
+
sage: f.is_trivial_one()
|
|
884
|
+
True
|
|
885
|
+
sage: X.one_function().is_trivial_one()
|
|
886
|
+
True
|
|
887
|
+
|
|
888
|
+
No simplification is attempted, so that ``False`` is returned for
|
|
889
|
+
non-trivial cases::
|
|
890
|
+
|
|
891
|
+
sage: f = X.function(cos(x)^2 + sin(x)^2)
|
|
892
|
+
sage: f.is_trivial_one()
|
|
893
|
+
False
|
|
894
|
+
|
|
895
|
+
On the contrary, the method
|
|
896
|
+
:meth:`~sage.structure.element.Element.is_zero` and the direct
|
|
897
|
+
comparison to one involve some simplification algorithms and
|
|
898
|
+
return ``True``::
|
|
899
|
+
|
|
900
|
+
sage: (f - 1).is_zero()
|
|
901
|
+
True
|
|
902
|
+
sage: f == 1
|
|
903
|
+
True
|
|
904
|
+
"""
|
|
905
|
+
curr = self._calc_method._current
|
|
906
|
+
return self._calc_method.is_trivial_zero(self.expr(curr) - SR.one())
|
|
907
|
+
|
|
908
|
+
# TODO: Remove this method as soon as issue #28629 is solved?
|
|
909
|
+
def is_unit(self):
|
|
910
|
+
r"""
|
|
911
|
+
Return ``True`` iff ``self`` is not trivially zero since most chart
|
|
912
|
+
functions are invertible and an actual computation would take too much
|
|
913
|
+
time.
|
|
914
|
+
|
|
915
|
+
EXAMPLES::
|
|
916
|
+
|
|
917
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
918
|
+
sage: X.<x,y> = M.chart()
|
|
919
|
+
sage: f = X.function(x^2+3*y+1)
|
|
920
|
+
sage: f.is_unit()
|
|
921
|
+
True
|
|
922
|
+
sage: zero = X.function(0)
|
|
923
|
+
sage: zero.is_unit()
|
|
924
|
+
False
|
|
925
|
+
"""
|
|
926
|
+
return not self.is_trivial_zero()
|
|
927
|
+
|
|
928
|
+
def copy(self):
|
|
929
|
+
r"""
|
|
930
|
+
Return an exact copy of the object.
|
|
931
|
+
|
|
932
|
+
OUTPUT: a :class:`ChartFunctionSymb`
|
|
933
|
+
|
|
934
|
+
EXAMPLES::
|
|
935
|
+
|
|
936
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
937
|
+
sage: X.<x,y> = M.chart()
|
|
938
|
+
sage: f = X.function(x+y^2)
|
|
939
|
+
sage: g = f.copy(); g
|
|
940
|
+
y^2 + x
|
|
941
|
+
|
|
942
|
+
By construction, ``g`` is identical to ``f``::
|
|
943
|
+
|
|
944
|
+
sage: type(g) == type(f)
|
|
945
|
+
True
|
|
946
|
+
sage: g == f
|
|
947
|
+
True
|
|
948
|
+
|
|
949
|
+
but it is not the same object::
|
|
950
|
+
|
|
951
|
+
sage: g is f
|
|
952
|
+
False
|
|
953
|
+
"""
|
|
954
|
+
resu = type(self)(self.parent())
|
|
955
|
+
for kk, vv in self._express.items():
|
|
956
|
+
resu._express[kk] = vv
|
|
957
|
+
resu._expansion_symbol = self._expansion_symbol
|
|
958
|
+
resu._order = self._order
|
|
959
|
+
return resu
|
|
960
|
+
|
|
961
|
+
def derivative(self, coord):
|
|
962
|
+
r"""
|
|
963
|
+
Partial derivative with respect to a coordinate.
|
|
964
|
+
|
|
965
|
+
INPUT:
|
|
966
|
+
|
|
967
|
+
- ``coord`` -- either the coordinate `x^i` with respect
|
|
968
|
+
to which the derivative of the chart function `f` is to be
|
|
969
|
+
taken, or the index `i` labelling this coordinate (with the
|
|
970
|
+
index convention defined on the chart domain via the parameter
|
|
971
|
+
``start_index``)
|
|
972
|
+
|
|
973
|
+
OUTPUT:
|
|
974
|
+
|
|
975
|
+
- a :class:`ChartFunction` representing the partial
|
|
976
|
+
derivative `\frac{\partial f}{\partial x^i}`
|
|
977
|
+
|
|
978
|
+
EXAMPLES:
|
|
979
|
+
|
|
980
|
+
Partial derivatives of a 2-dimensional chart function::
|
|
981
|
+
|
|
982
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
983
|
+
sage: X.<x,y> = M.chart(calc_method='SR')
|
|
984
|
+
sage: f = X.function(x^2+3*y+1); f
|
|
985
|
+
x^2 + 3*y + 1
|
|
986
|
+
sage: f.derivative(x)
|
|
987
|
+
2*x
|
|
988
|
+
sage: f.derivative(y)
|
|
989
|
+
3
|
|
990
|
+
|
|
991
|
+
An alias is ``diff``::
|
|
992
|
+
|
|
993
|
+
sage: f.diff(x)
|
|
994
|
+
2*x
|
|
995
|
+
|
|
996
|
+
Each partial derivative is itself a chart function::
|
|
997
|
+
|
|
998
|
+
sage: type(f.diff(x))
|
|
999
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1000
|
+
|
|
1001
|
+
The same result is returned by the function ``diff``::
|
|
1002
|
+
|
|
1003
|
+
sage: diff(f, x)
|
|
1004
|
+
2*x
|
|
1005
|
+
|
|
1006
|
+
An index can be used instead of the coordinate symbol::
|
|
1007
|
+
|
|
1008
|
+
sage: f.diff(0)
|
|
1009
|
+
2*x
|
|
1010
|
+
sage: diff(f, 1)
|
|
1011
|
+
3
|
|
1012
|
+
|
|
1013
|
+
The index range depends on the convention used on the chart's domain::
|
|
1014
|
+
|
|
1015
|
+
sage: M = Manifold(2, 'M', structure='topological', start_index=1)
|
|
1016
|
+
sage: X.<x,y> = M.chart()
|
|
1017
|
+
sage: f = X.function(x^2+3*y+1)
|
|
1018
|
+
sage: f.diff(0)
|
|
1019
|
+
Traceback (most recent call last):
|
|
1020
|
+
...
|
|
1021
|
+
ValueError: coordinate index out of range
|
|
1022
|
+
sage: f.diff(1)
|
|
1023
|
+
2*x
|
|
1024
|
+
sage: f.diff(2)
|
|
1025
|
+
3
|
|
1026
|
+
|
|
1027
|
+
The same test with SymPy::
|
|
1028
|
+
|
|
1029
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1030
|
+
sage: X.<x,y> = M.chart(calc_method='sympy')
|
|
1031
|
+
sage: f = X.function(x^2+3*y+1); f
|
|
1032
|
+
x**2 + 3*y + 1
|
|
1033
|
+
sage: f.diff(x)
|
|
1034
|
+
2*x
|
|
1035
|
+
sage: f.diff(y)
|
|
1036
|
+
3
|
|
1037
|
+
"""
|
|
1038
|
+
from sage.calculus.functional import diff
|
|
1039
|
+
from sage.rings.integer import Integer
|
|
1040
|
+
|
|
1041
|
+
if self._der is None:
|
|
1042
|
+
# the list of partial derivatives has to be updated
|
|
1043
|
+
curr = self._calc_method._current
|
|
1044
|
+
if curr == 'SR':
|
|
1045
|
+
self._der = [
|
|
1046
|
+
type(self)(
|
|
1047
|
+
self.parent(),
|
|
1048
|
+
self._simplify(diff(self.expr(), xx)),
|
|
1049
|
+
expansion_symbol=self._expansion_symbol,
|
|
1050
|
+
order=self._order,
|
|
1051
|
+
)
|
|
1052
|
+
for xx in self._chart[:]
|
|
1053
|
+
]
|
|
1054
|
+
elif curr == 'sympy':
|
|
1055
|
+
self._der = [
|
|
1056
|
+
type(self)(
|
|
1057
|
+
self.parent(),
|
|
1058
|
+
self._simplify(sympy.diff(self.expr(), xx._sympy_())),
|
|
1059
|
+
)
|
|
1060
|
+
for xx in self._chart[:]
|
|
1061
|
+
]
|
|
1062
|
+
if isinstance(coord, (int, Integer)):
|
|
1063
|
+
# NB: for efficiency, we access directly to the "private" attributes
|
|
1064
|
+
# of other classes. A more conventional OOP writing would be
|
|
1065
|
+
# coordsi = coord - self._chart.domain().start_index()
|
|
1066
|
+
coordsi = coord - self._chart.domain()._sindex
|
|
1067
|
+
if coordsi < 0 or coordsi >= self._nc:
|
|
1068
|
+
raise ValueError("coordinate index out of range")
|
|
1069
|
+
return self._der[coordsi]
|
|
1070
|
+
else:
|
|
1071
|
+
return self._der[self._chart[:].index(coord)]
|
|
1072
|
+
|
|
1073
|
+
diff = derivative
|
|
1074
|
+
|
|
1075
|
+
def __eq__(self, other):
|
|
1076
|
+
r"""
|
|
1077
|
+
Comparison (equality) operator.
|
|
1078
|
+
|
|
1079
|
+
INPUT:
|
|
1080
|
+
|
|
1081
|
+
- ``other`` -- a :class:`ChartFunction` or a value
|
|
1082
|
+
|
|
1083
|
+
OUTPUT: ``True`` if ``self`` is equal to ``other``, or ``False`` otherwise
|
|
1084
|
+
|
|
1085
|
+
TESTS:
|
|
1086
|
+
|
|
1087
|
+
Coordinate functions associated to a 2-dimensional chart::
|
|
1088
|
+
|
|
1089
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1090
|
+
sage: X.<x,y> = M.chart()
|
|
1091
|
+
sage: f = X.function(x+y^2)
|
|
1092
|
+
sage: g = X.function(x+y^2)
|
|
1093
|
+
sage: f == g
|
|
1094
|
+
True
|
|
1095
|
+
sage: f = X.function(x+y^2)
|
|
1096
|
+
sage: g = X.function(x+y**2,'sympy')
|
|
1097
|
+
sage: f._express; g._express
|
|
1098
|
+
{'SR': y^2 + x}
|
|
1099
|
+
{'sympy': x + y**2}
|
|
1100
|
+
sage: f == g
|
|
1101
|
+
True
|
|
1102
|
+
sage: f == 1
|
|
1103
|
+
False
|
|
1104
|
+
sage: h = X.function(1)
|
|
1105
|
+
sage: h == 1
|
|
1106
|
+
True
|
|
1107
|
+
sage: h == f
|
|
1108
|
+
False
|
|
1109
|
+
sage: h == 0
|
|
1110
|
+
False
|
|
1111
|
+
sage: X.function(0) == 0
|
|
1112
|
+
True
|
|
1113
|
+
sage: X.zero_function() == 0
|
|
1114
|
+
True
|
|
1115
|
+
"""
|
|
1116
|
+
if other is self:
|
|
1117
|
+
return True
|
|
1118
|
+
if isinstance(other, ChartFunction):
|
|
1119
|
+
if other.parent() != self.parent():
|
|
1120
|
+
return False
|
|
1121
|
+
else:
|
|
1122
|
+
if self._calc_method._current in self._express:
|
|
1123
|
+
method = self._calc_method._current
|
|
1124
|
+
else:
|
|
1125
|
+
method = list(self._express)[0] # pick a random method
|
|
1126
|
+
# other.expr(method)
|
|
1127
|
+
if method == 'sympy':
|
|
1128
|
+
return bool(
|
|
1129
|
+
sympy.simplify(other.expr(method) - self.expr(method)) == 0
|
|
1130
|
+
)
|
|
1131
|
+
return bool(other.expr(method) == self.expr(method))
|
|
1132
|
+
else:
|
|
1133
|
+
return bool(self.expr(self._calc_method._current) == other)
|
|
1134
|
+
|
|
1135
|
+
def __ne__(self, other):
|
|
1136
|
+
r"""
|
|
1137
|
+
Inequality operator.
|
|
1138
|
+
|
|
1139
|
+
INPUT:
|
|
1140
|
+
|
|
1141
|
+
- ``other`` -- a :class:`ChartFunction`
|
|
1142
|
+
|
|
1143
|
+
OUTPUT:
|
|
1144
|
+
|
|
1145
|
+
- ``True`` if ``self`` is different from ``other``, ``False``
|
|
1146
|
+
otherwise
|
|
1147
|
+
|
|
1148
|
+
TESTS::
|
|
1149
|
+
|
|
1150
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1151
|
+
sage: X.<x,y> = M.chart()
|
|
1152
|
+
sage: f = X.function(x-y)
|
|
1153
|
+
sage: f != X.function(x*y)
|
|
1154
|
+
True
|
|
1155
|
+
sage: f != X.function(x)
|
|
1156
|
+
True
|
|
1157
|
+
sage: f != X.function(x-y)
|
|
1158
|
+
False
|
|
1159
|
+
"""
|
|
1160
|
+
return not (self == other)
|
|
1161
|
+
|
|
1162
|
+
def __neg__(self):
|
|
1163
|
+
r"""
|
|
1164
|
+
Unary minus operator.
|
|
1165
|
+
|
|
1166
|
+
OUTPUT: the opposite of ``self``
|
|
1167
|
+
|
|
1168
|
+
TESTS:
|
|
1169
|
+
|
|
1170
|
+
Coordinate functions associated to a 2-dimensional chart::
|
|
1171
|
+
|
|
1172
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1173
|
+
sage: X.<x,y> = M.chart(calc_method='sympy')
|
|
1174
|
+
sage: f = X.function(x+y^2)
|
|
1175
|
+
sage: g = -f; g
|
|
1176
|
+
-x - y**2
|
|
1177
|
+
sage: type(g)
|
|
1178
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1179
|
+
sage: -g == f
|
|
1180
|
+
True
|
|
1181
|
+
"""
|
|
1182
|
+
curr = self._calc_method._current
|
|
1183
|
+
resu = type(self)(self.parent())
|
|
1184
|
+
resu._express[curr] = self._simplify(-self.expr())
|
|
1185
|
+
resu._order = self._order
|
|
1186
|
+
resu._expansion_symbol = self._expansion_symbol
|
|
1187
|
+
return resu
|
|
1188
|
+
|
|
1189
|
+
def __invert__(self):
|
|
1190
|
+
r"""
|
|
1191
|
+
Inverse operator.
|
|
1192
|
+
|
|
1193
|
+
If `f` denotes the current chart function and `K` the topological
|
|
1194
|
+
field over which the manifold is defined, the *inverse* of `f` is the
|
|
1195
|
+
chart function `1/f`, where `1` of the multiplicative identity
|
|
1196
|
+
of `K`.
|
|
1197
|
+
|
|
1198
|
+
OUTPUT: the inverse of ``self``
|
|
1199
|
+
|
|
1200
|
+
TESTS:
|
|
1201
|
+
|
|
1202
|
+
Coordinate functions associated to a 2-dimensional chart::
|
|
1203
|
+
|
|
1204
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1205
|
+
sage: X.<x,y> = M.chart()
|
|
1206
|
+
sage: f = X.function(1+x^2+y^2)
|
|
1207
|
+
sage: g = f.__invert__(); g
|
|
1208
|
+
1/(x^2 + y^2 + 1)
|
|
1209
|
+
sage: type(g)
|
|
1210
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1211
|
+
sage: g == ~f
|
|
1212
|
+
True
|
|
1213
|
+
sage: g.__invert__() == f
|
|
1214
|
+
True
|
|
1215
|
+
|
|
1216
|
+
The same test with SymPy::
|
|
1217
|
+
|
|
1218
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1219
|
+
sage: X.<x,y> = M.chart(calc_method='sympy')
|
|
1220
|
+
sage: f = X.function(1+x^2+y^2)
|
|
1221
|
+
sage: g = f.__invert__(); g
|
|
1222
|
+
1/(x**2 + y**2 + 1)
|
|
1223
|
+
sage: type(g)
|
|
1224
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1225
|
+
sage: g == ~f
|
|
1226
|
+
True
|
|
1227
|
+
sage: g.__invert__() == f
|
|
1228
|
+
True
|
|
1229
|
+
"""
|
|
1230
|
+
curr = self._calc_method._current
|
|
1231
|
+
if curr == 'SR':
|
|
1232
|
+
return type(self)(
|
|
1233
|
+
self.parent(),
|
|
1234
|
+
calc_method='SR',
|
|
1235
|
+
expression=self._simplify(SR.one() / self.expr()),
|
|
1236
|
+
)
|
|
1237
|
+
# NB: self._express.__invert__() would return 1/self._express
|
|
1238
|
+
# (cf. the code of __invert__ in src/sage/symbolic/expression.pyx)
|
|
1239
|
+
# Here we prefer SR(1)/self._express
|
|
1240
|
+
return type(self)(
|
|
1241
|
+
self.parent(),
|
|
1242
|
+
calc_method=curr,
|
|
1243
|
+
expression=self._simplify(1 / self.expr()),
|
|
1244
|
+
expansion_symbol=self._expansion_symbol,
|
|
1245
|
+
order=self._order,
|
|
1246
|
+
)
|
|
1247
|
+
|
|
1248
|
+
def _add_(self, other):
|
|
1249
|
+
r"""
|
|
1250
|
+
Addition operator.
|
|
1251
|
+
|
|
1252
|
+
INPUT:
|
|
1253
|
+
|
|
1254
|
+
- ``other`` -- a :class:`ChartFunction` or a value
|
|
1255
|
+
|
|
1256
|
+
OUTPUT:
|
|
1257
|
+
|
|
1258
|
+
- chart function resulting from the addition of ``self``
|
|
1259
|
+
and ``other``
|
|
1260
|
+
|
|
1261
|
+
TESTS::
|
|
1262
|
+
|
|
1263
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1264
|
+
sage: X.<x,y> = M.chart(calc_method='SR')
|
|
1265
|
+
|
|
1266
|
+
sage: f = X.function(x+y^2)
|
|
1267
|
+
sage: g = X.function(x+1)
|
|
1268
|
+
sage: s = f + g; s.display()
|
|
1269
|
+
(x, y) ↦ y^2 + 2*x + 1
|
|
1270
|
+
sage: type(s)
|
|
1271
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1272
|
+
sage: (f + 0).display()
|
|
1273
|
+
(x, y) ↦ y^2 + x
|
|
1274
|
+
sage: (f + X.zero_function()).display()
|
|
1275
|
+
(x, y) ↦ y^2 + x
|
|
1276
|
+
sage: (f + 1).display()
|
|
1277
|
+
(x, y) ↦ y^2 + x + 1
|
|
1278
|
+
sage: (f + pi).display()
|
|
1279
|
+
(x, y) ↦ pi + y^2 + x
|
|
1280
|
+
sage: (f + x).display()
|
|
1281
|
+
(x, y) ↦ y^2 + 2*x
|
|
1282
|
+
sage: (f + -f).display()
|
|
1283
|
+
(x, y) ↦ 0
|
|
1284
|
+
|
|
1285
|
+
The same test with SymPy::
|
|
1286
|
+
|
|
1287
|
+
sage: X.calculus_method().set('sympy')
|
|
1288
|
+
sage: f = X.function(x+y^2)
|
|
1289
|
+
sage: g = X.function(x+1)
|
|
1290
|
+
sage: s = f + g; s.display()
|
|
1291
|
+
(x, y) ↦ 2*x + y**2 + 1
|
|
1292
|
+
sage: (f + 0).display()
|
|
1293
|
+
(x, y) ↦ x + y**2
|
|
1294
|
+
sage: (f + X.zero_function()).display()
|
|
1295
|
+
(x, y) ↦ x + y**2
|
|
1296
|
+
sage: (f + 1).display()
|
|
1297
|
+
(x, y) ↦ x + y**2 + 1
|
|
1298
|
+
sage: (f + pi).display()
|
|
1299
|
+
(x, y) ↦ x + y**2 + pi
|
|
1300
|
+
sage: (f + x).display()
|
|
1301
|
+
(x, y) ↦ 2*x + y**2
|
|
1302
|
+
sage: (f + -f).display()
|
|
1303
|
+
(x, y) ↦ 0
|
|
1304
|
+
"""
|
|
1305
|
+
curr = self._calc_method._current
|
|
1306
|
+
if other._expansion_symbol is not None:
|
|
1307
|
+
res = other._simplify(self.expr() + other.expr())
|
|
1308
|
+
else:
|
|
1309
|
+
res = self._simplify(self.expr() + other.expr())
|
|
1310
|
+
if curr == 'SR' and res.is_trivial_zero():
|
|
1311
|
+
# NB: "if res == 0" would be too expensive (cf. #22859)
|
|
1312
|
+
return self.parent().zero()
|
|
1313
|
+
if other._expansion_symbol is not None:
|
|
1314
|
+
return type(self)(
|
|
1315
|
+
self.parent(),
|
|
1316
|
+
res,
|
|
1317
|
+
expansion_symbol=other._expansion_symbol,
|
|
1318
|
+
order=other._order,
|
|
1319
|
+
)
|
|
1320
|
+
else:
|
|
1321
|
+
return type(self)(
|
|
1322
|
+
self.parent(),
|
|
1323
|
+
res,
|
|
1324
|
+
expansion_symbol=self._expansion_symbol,
|
|
1325
|
+
order=self._order,
|
|
1326
|
+
)
|
|
1327
|
+
|
|
1328
|
+
def _sub_(self, other):
|
|
1329
|
+
r"""
|
|
1330
|
+
Subtraction operator.
|
|
1331
|
+
|
|
1332
|
+
INPUT:
|
|
1333
|
+
|
|
1334
|
+
- ``other`` -- a :class:`ChartFunction` or a value
|
|
1335
|
+
|
|
1336
|
+
OUTPUT:
|
|
1337
|
+
|
|
1338
|
+
- chart function resulting from the subtraction of ``other``
|
|
1339
|
+
from ``self``
|
|
1340
|
+
|
|
1341
|
+
TESTS::
|
|
1342
|
+
|
|
1343
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1344
|
+
sage: X.<x,y> = M.chart()
|
|
1345
|
+
sage: f = X.function(x+y^2)
|
|
1346
|
+
sage: g = X.function(x+1)
|
|
1347
|
+
sage: s = f - g; s.display()
|
|
1348
|
+
(x, y) ↦ y^2 - 1
|
|
1349
|
+
sage: type(s)
|
|
1350
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1351
|
+
sage: (f - 0).display()
|
|
1352
|
+
(x, y) ↦ y^2 + x
|
|
1353
|
+
sage: (f - X.zero_function()).display()
|
|
1354
|
+
(x, y) ↦ y^2 + x
|
|
1355
|
+
sage: (f - 1).display()
|
|
1356
|
+
(x, y) ↦ y^2 + x - 1
|
|
1357
|
+
sage: (f - x).display()
|
|
1358
|
+
(x, y) ↦ y^2
|
|
1359
|
+
sage: (f - pi).display()
|
|
1360
|
+
(x, y) ↦ -pi + y^2 + x
|
|
1361
|
+
sage: (f - f).display()
|
|
1362
|
+
(x, y) ↦ 0
|
|
1363
|
+
sage: (f - g) == -(g - f)
|
|
1364
|
+
True
|
|
1365
|
+
|
|
1366
|
+
Tests with SymPy::
|
|
1367
|
+
|
|
1368
|
+
sage: X.calculus_method().set('sympy')
|
|
1369
|
+
sage: h = X.function(2*(x+y^2))
|
|
1370
|
+
sage: s = h - f
|
|
1371
|
+
sage: s.display()
|
|
1372
|
+
(x, y) ↦ x + y**2
|
|
1373
|
+
sage: s.expr()
|
|
1374
|
+
x + y**2
|
|
1375
|
+
"""
|
|
1376
|
+
curr = self._calc_method._current
|
|
1377
|
+
if other._expansion_symbol is not None:
|
|
1378
|
+
res = other._simplify(self.expr() - other.expr())
|
|
1379
|
+
else:
|
|
1380
|
+
res = self._simplify(self.expr() - other.expr())
|
|
1381
|
+
if curr == 'SR' and res.is_trivial_zero():
|
|
1382
|
+
# NB: "if res == 0" would be too expensive (cf. #22859)
|
|
1383
|
+
return self.parent().zero()
|
|
1384
|
+
if other._expansion_symbol is not None:
|
|
1385
|
+
return type(self)(
|
|
1386
|
+
self.parent(),
|
|
1387
|
+
res,
|
|
1388
|
+
expansion_symbol=other._expansion_symbol,
|
|
1389
|
+
order=other._order,
|
|
1390
|
+
)
|
|
1391
|
+
else:
|
|
1392
|
+
return type(self)(
|
|
1393
|
+
self.parent(),
|
|
1394
|
+
res,
|
|
1395
|
+
expansion_symbol=self._expansion_symbol,
|
|
1396
|
+
order=self._order,
|
|
1397
|
+
)
|
|
1398
|
+
|
|
1399
|
+
def _mul_(self, other):
|
|
1400
|
+
r"""
|
|
1401
|
+
Multiplication operator.
|
|
1402
|
+
|
|
1403
|
+
INPUT:
|
|
1404
|
+
|
|
1405
|
+
- ``other`` -- a :class:`ChartFunction` or a value
|
|
1406
|
+
|
|
1407
|
+
OUTPUT:
|
|
1408
|
+
|
|
1409
|
+
- chart function resulting from the multiplication of ``self``
|
|
1410
|
+
by ``other``
|
|
1411
|
+
|
|
1412
|
+
TESTS::
|
|
1413
|
+
|
|
1414
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1415
|
+
sage: X.<x,y> = M.chart()
|
|
1416
|
+
sage: f = X.function(x+y)
|
|
1417
|
+
sage: g = X.function(x-y)
|
|
1418
|
+
sage: s = f._mul_(g); s.display()
|
|
1419
|
+
(x, y) ↦ x^2 - y^2
|
|
1420
|
+
sage: type(s)
|
|
1421
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1422
|
+
sage: (f * 0).display()
|
|
1423
|
+
(x, y) ↦ 0
|
|
1424
|
+
sage: (f * X.zero_function()).display()
|
|
1425
|
+
(x, y) ↦ 0
|
|
1426
|
+
sage: (f * (1/f)).display()
|
|
1427
|
+
(x, y) ↦ 1
|
|
1428
|
+
|
|
1429
|
+
The same test with SymPy::
|
|
1430
|
+
|
|
1431
|
+
sage: X.calculus_method().set('sympy')
|
|
1432
|
+
sage: f = X.function(x+y)
|
|
1433
|
+
sage: g = X.function(x-y)
|
|
1434
|
+
sage: s = f._mul_(g); s.expr()
|
|
1435
|
+
x**2 - y**2
|
|
1436
|
+
sage: (f * 0).expr()
|
|
1437
|
+
0
|
|
1438
|
+
sage: (f * X.zero_function()).expr()
|
|
1439
|
+
0
|
|
1440
|
+
sage: (f * (1/f)).expr()
|
|
1441
|
+
1
|
|
1442
|
+
"""
|
|
1443
|
+
curr = self._calc_method._current
|
|
1444
|
+
if other._expansion_symbol is not None:
|
|
1445
|
+
res = other._simplify(self.expr() * other.expr())
|
|
1446
|
+
else:
|
|
1447
|
+
res = self._simplify(self.expr() * other.expr())
|
|
1448
|
+
if curr == 'SR' and res.is_trivial_zero():
|
|
1449
|
+
# NB: "if res == 0" would be too expensive (cf. #22859)
|
|
1450
|
+
return self.parent().zero()
|
|
1451
|
+
if other._expansion_symbol is not None:
|
|
1452
|
+
return type(self)(
|
|
1453
|
+
self.parent(),
|
|
1454
|
+
res,
|
|
1455
|
+
expansion_symbol=other._expansion_symbol,
|
|
1456
|
+
order=other._order,
|
|
1457
|
+
)
|
|
1458
|
+
else:
|
|
1459
|
+
return type(self)(
|
|
1460
|
+
self.parent(),
|
|
1461
|
+
res,
|
|
1462
|
+
expansion_symbol=self._expansion_symbol,
|
|
1463
|
+
order=self._order,
|
|
1464
|
+
)
|
|
1465
|
+
|
|
1466
|
+
def _rmul_(self, other):
|
|
1467
|
+
"""
|
|
1468
|
+
Return ``other * self``.
|
|
1469
|
+
|
|
1470
|
+
EXAMPLES::
|
|
1471
|
+
|
|
1472
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1473
|
+
sage: X.<x,y> = M.chart()
|
|
1474
|
+
sage: one = X.function_ring().one()
|
|
1475
|
+
sage: 2 * one
|
|
1476
|
+
2
|
|
1477
|
+
sage: f = X.function(x+y)
|
|
1478
|
+
sage: (f * pi).display()
|
|
1479
|
+
(x, y) ↦ pi*(x + y)
|
|
1480
|
+
sage: (x * f).display()
|
|
1481
|
+
(x, y) ↦ (x + y)*x
|
|
1482
|
+
|
|
1483
|
+
The same test with SymPy::
|
|
1484
|
+
|
|
1485
|
+
sage: X.calculus_method().set('sympy')
|
|
1486
|
+
sage: f = X.function(x+y)
|
|
1487
|
+
sage: (f * pi).expr()
|
|
1488
|
+
pi*(x + y)
|
|
1489
|
+
sage: (x * f).expr()
|
|
1490
|
+
x*(x + y)
|
|
1491
|
+
"""
|
|
1492
|
+
curr = self._calc_method._current
|
|
1493
|
+
try:
|
|
1494
|
+
other = self._calc_method._tranf[curr](other)
|
|
1495
|
+
except (TypeError, ValueError):
|
|
1496
|
+
return
|
|
1497
|
+
return type(self)(
|
|
1498
|
+
self.parent(),
|
|
1499
|
+
other * self.expr(),
|
|
1500
|
+
expansion_symbol=self._expansion_symbol,
|
|
1501
|
+
order=self._order,
|
|
1502
|
+
)
|
|
1503
|
+
|
|
1504
|
+
def _lmul_(self, other):
|
|
1505
|
+
"""
|
|
1506
|
+
Return ``self * other``.
|
|
1507
|
+
|
|
1508
|
+
EXAMPLES::
|
|
1509
|
+
|
|
1510
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1511
|
+
sage: X.<x,y> = M.chart()
|
|
1512
|
+
sage: one = X.function_ring().one()
|
|
1513
|
+
sage: one * 2
|
|
1514
|
+
2
|
|
1515
|
+
sage: f = X.function(x+y)
|
|
1516
|
+
sage: (f * 2).display()
|
|
1517
|
+
(x, y) ↦ 2*x + 2*y
|
|
1518
|
+
sage: (f * pi).display()
|
|
1519
|
+
(x, y) ↦ pi*(x + y)
|
|
1520
|
+
|
|
1521
|
+
The same test with SymPy::
|
|
1522
|
+
|
|
1523
|
+
sage: X.calculus_method().set('sympy')
|
|
1524
|
+
sage: f = X.function(x+y)
|
|
1525
|
+
sage: (f * 2).display()
|
|
1526
|
+
(x, y) ↦ 2*x + 2*y
|
|
1527
|
+
sage: (f * pi).display()
|
|
1528
|
+
(x, y) ↦ pi*(x + y)
|
|
1529
|
+
"""
|
|
1530
|
+
curr = self._calc_method._current
|
|
1531
|
+
try:
|
|
1532
|
+
other = self._calc_method._tranf[curr](other)
|
|
1533
|
+
except (TypeError, ValueError):
|
|
1534
|
+
return
|
|
1535
|
+
return type(self)(
|
|
1536
|
+
self.parent(),
|
|
1537
|
+
self.expr() * other,
|
|
1538
|
+
expansion_symbol=self._expansion_symbol,
|
|
1539
|
+
order=self._order,
|
|
1540
|
+
)
|
|
1541
|
+
|
|
1542
|
+
def _div_(self, other):
|
|
1543
|
+
r"""
|
|
1544
|
+
Division operator.
|
|
1545
|
+
|
|
1546
|
+
INPUT:
|
|
1547
|
+
|
|
1548
|
+
- ``other`` -- a :class:`ChartFunction` or a value
|
|
1549
|
+
|
|
1550
|
+
OUTPUT:
|
|
1551
|
+
|
|
1552
|
+
- chart function resulting from the division of ``self``
|
|
1553
|
+
by ``other``
|
|
1554
|
+
|
|
1555
|
+
TESTS::
|
|
1556
|
+
|
|
1557
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1558
|
+
sage: X.<x,y> = M.chart()
|
|
1559
|
+
sage: f = X.function(x+y)
|
|
1560
|
+
sage: g = X.function(1+x^2+y^2)
|
|
1561
|
+
sage: s = f._div_(g); s.display()
|
|
1562
|
+
(x, y) ↦ (x + y)/(x^2 + y^2 + 1)
|
|
1563
|
+
sage: type(s)
|
|
1564
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
1565
|
+
sage: f / X.zero_function()
|
|
1566
|
+
Traceback (most recent call last):
|
|
1567
|
+
...
|
|
1568
|
+
ZeroDivisionError: division of a chart function by zero
|
|
1569
|
+
sage: (f / 1).display()
|
|
1570
|
+
(x, y) ↦ x + y
|
|
1571
|
+
sage: (f / 2).display()
|
|
1572
|
+
(x, y) ↦ 1/2*x + 1/2*y
|
|
1573
|
+
sage: (f / pi).display()
|
|
1574
|
+
(x, y) ↦ (x + y)/pi
|
|
1575
|
+
sage: (f / (1+x^2)).display()
|
|
1576
|
+
(x, y) ↦ (x + y)/(x^2 + 1)
|
|
1577
|
+
sage: (f / (1+x^2)).display()
|
|
1578
|
+
(x, y) ↦ (x + y)/(x^2 + 1)
|
|
1579
|
+
sage: (f / g) == ~(g / f)
|
|
1580
|
+
True
|
|
1581
|
+
|
|
1582
|
+
The same test with SymPy::
|
|
1583
|
+
|
|
1584
|
+
sage: X.calculus_method().set('sympy')
|
|
1585
|
+
sage: f = X.function(x+y)
|
|
1586
|
+
sage: g = X.function(1+x**2+y**2)
|
|
1587
|
+
sage: s = f._div_(g); s.display()
|
|
1588
|
+
(x, y) ↦ (x + y)/(x**2 + y**2 + 1)
|
|
1589
|
+
sage: (f / g) == ~(g / f)
|
|
1590
|
+
True
|
|
1591
|
+
"""
|
|
1592
|
+
if other.is_zero():
|
|
1593
|
+
raise ZeroDivisionError("division of a chart function by zero")
|
|
1594
|
+
curr = self._calc_method._current
|
|
1595
|
+
res = self._simplify(self.expr() / other.expr())
|
|
1596
|
+
if curr == 'SR' and res.is_trivial_zero():
|
|
1597
|
+
# NB: "if res == 0" would be too expensive (cf. #22859)
|
|
1598
|
+
return self.parent().zero()
|
|
1599
|
+
return type(self)(
|
|
1600
|
+
self.parent(),
|
|
1601
|
+
res,
|
|
1602
|
+
expansion_symbol=self._expansion_symbol,
|
|
1603
|
+
order=self._order,
|
|
1604
|
+
)
|
|
1605
|
+
|
|
1606
|
+
def exp(self):
|
|
1607
|
+
r"""
|
|
1608
|
+
Exponential of ``self``.
|
|
1609
|
+
|
|
1610
|
+
OUTPUT:
|
|
1611
|
+
|
|
1612
|
+
- chart function `\exp(f)`, where `f` is the current
|
|
1613
|
+
chart function
|
|
1614
|
+
|
|
1615
|
+
EXAMPLES::
|
|
1616
|
+
|
|
1617
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1618
|
+
sage: X.<x,y> = M.chart()
|
|
1619
|
+
sage: f = X.function(x+y)
|
|
1620
|
+
sage: f.exp()
|
|
1621
|
+
e^(x + y)
|
|
1622
|
+
sage: exp(f) # equivalent to f.exp()
|
|
1623
|
+
e^(x + y)
|
|
1624
|
+
sage: exp(f).display()
|
|
1625
|
+
(x, y) ↦ e^(x + y)
|
|
1626
|
+
sage: exp(X.zero_function())
|
|
1627
|
+
1
|
|
1628
|
+
|
|
1629
|
+
The same test with SymPy::
|
|
1630
|
+
|
|
1631
|
+
sage: X.calculus_method().set('sympy')
|
|
1632
|
+
sage: f = X.function(x+y)
|
|
1633
|
+
sage: f.exp()
|
|
1634
|
+
exp(x + y)
|
|
1635
|
+
sage: exp(f) # equivalent to f.exp()
|
|
1636
|
+
exp(x + y)
|
|
1637
|
+
sage: exp(f).display()
|
|
1638
|
+
(x, y) ↦ exp(x + y)
|
|
1639
|
+
sage: exp(X.zero_function())
|
|
1640
|
+
1
|
|
1641
|
+
"""
|
|
1642
|
+
curr = self._calc_method._current
|
|
1643
|
+
if curr == 'SR':
|
|
1644
|
+
val = self.expr().exp()
|
|
1645
|
+
elif curr == 'sympy':
|
|
1646
|
+
val = sympy.exp(self.expr())
|
|
1647
|
+
return type(self)(
|
|
1648
|
+
self.parent(),
|
|
1649
|
+
self._simplify(val),
|
|
1650
|
+
expansion_symbol=self._expansion_symbol,
|
|
1651
|
+
order=self._order,
|
|
1652
|
+
)
|
|
1653
|
+
|
|
1654
|
+
def log(self, base=None):
|
|
1655
|
+
r"""
|
|
1656
|
+
Logarithm of ``self``.
|
|
1657
|
+
|
|
1658
|
+
INPUT:
|
|
1659
|
+
|
|
1660
|
+
- ``base`` -- (default: ``None``) base of the logarithm; if ``None``,
|
|
1661
|
+
the natural logarithm (i.e. logarithm to base `e`) is returned
|
|
1662
|
+
|
|
1663
|
+
OUTPUT:
|
|
1664
|
+
|
|
1665
|
+
- chart function `\log_a(f)`, where `f` is the current chart
|
|
1666
|
+
function and `a` is the base
|
|
1667
|
+
|
|
1668
|
+
EXAMPLES::
|
|
1669
|
+
|
|
1670
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1671
|
+
sage: X.<x,y> = M.chart()
|
|
1672
|
+
sage: f = X.function(x+y)
|
|
1673
|
+
sage: f.log()
|
|
1674
|
+
log(x + y)
|
|
1675
|
+
sage: log(f) # equivalent to f.log()
|
|
1676
|
+
log(x + y)
|
|
1677
|
+
sage: log(f).display()
|
|
1678
|
+
(x, y) ↦ log(x + y)
|
|
1679
|
+
sage: f.log(2)
|
|
1680
|
+
log(x + y)/log(2)
|
|
1681
|
+
sage: log(f, 2)
|
|
1682
|
+
log(x + y)/log(2)
|
|
1683
|
+
|
|
1684
|
+
The same test with SymPy::
|
|
1685
|
+
|
|
1686
|
+
sage: X.calculus_method().set('sympy')
|
|
1687
|
+
sage: f = X.function(x+y)
|
|
1688
|
+
sage: f.log()
|
|
1689
|
+
log(x + y)
|
|
1690
|
+
sage: log(f) # equivalent to f.log()
|
|
1691
|
+
log(x + y)
|
|
1692
|
+
sage: log(f).display()
|
|
1693
|
+
(x, y) ↦ log(x + y)
|
|
1694
|
+
sage: f.log(2)
|
|
1695
|
+
log(x + y)/log(2)
|
|
1696
|
+
sage: log(f, 2)
|
|
1697
|
+
log(x + y)/log(2)
|
|
1698
|
+
"""
|
|
1699
|
+
curr = self._calc_method._current
|
|
1700
|
+
if curr == 'SR':
|
|
1701
|
+
val = self.expr().log(base)
|
|
1702
|
+
elif curr == 'sympy':
|
|
1703
|
+
val = (
|
|
1704
|
+
sympy.log(self.expr()) if base is None else sympy.log(self.expr(), base)
|
|
1705
|
+
)
|
|
1706
|
+
return type(self)(
|
|
1707
|
+
self.parent(),
|
|
1708
|
+
self._simplify(val),
|
|
1709
|
+
expansion_symbol=self._expansion_symbol,
|
|
1710
|
+
order=self._order,
|
|
1711
|
+
)
|
|
1712
|
+
|
|
1713
|
+
def __pow__(self, exponent):
|
|
1714
|
+
r"""
|
|
1715
|
+
Power of ``self``.
|
|
1716
|
+
|
|
1717
|
+
INPUT:
|
|
1718
|
+
|
|
1719
|
+
- ``exponent`` -- the exponent
|
|
1720
|
+
|
|
1721
|
+
OUTPUT:
|
|
1722
|
+
|
|
1723
|
+
- chart function `f^a`, where `f` is the current chart
|
|
1724
|
+
function and `a` is the exponent
|
|
1725
|
+
|
|
1726
|
+
EXAMPLES::
|
|
1727
|
+
|
|
1728
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1729
|
+
sage: X.<x,y> = M.chart()
|
|
1730
|
+
sage: f = X.function(x+y)
|
|
1731
|
+
sage: f.__pow__(3)
|
|
1732
|
+
x^3 + 3*x^2*y + 3*x*y^2 + y^3
|
|
1733
|
+
sage: f^3 # equivalent to f.__pow__(3)
|
|
1734
|
+
x^3 + 3*x^2*y + 3*x*y^2 + y^3
|
|
1735
|
+
sage: f.__pow__(3).display()
|
|
1736
|
+
(x, y) ↦ x^3 + 3*x^2*y + 3*x*y^2 + y^3
|
|
1737
|
+
sage: pow(f,3).display()
|
|
1738
|
+
(x, y) ↦ x^3 + 3*x^2*y + 3*x*y^2 + y^3
|
|
1739
|
+
sage: (f^3).display()
|
|
1740
|
+
(x, y) ↦ x^3 + 3*x^2*y + 3*x*y^2 + y^3
|
|
1741
|
+
sage: pow(X.zero_function(), 3).display()
|
|
1742
|
+
(x, y) ↦ 0
|
|
1743
|
+
|
|
1744
|
+
The same test with SymPy::
|
|
1745
|
+
|
|
1746
|
+
sage: X.calculus_method().set('sympy')
|
|
1747
|
+
sage: f = X.function(x+y)
|
|
1748
|
+
sage: f.__pow__(3)
|
|
1749
|
+
x**3 + 3*x**2*y + 3*x*y**2 + y**3
|
|
1750
|
+
sage: f^3 # equivalent to f.__pow__(3)
|
|
1751
|
+
x**3 + 3*x**2*y + 3*x*y**2 + y**3
|
|
1752
|
+
sage: f.__pow__(3).display()
|
|
1753
|
+
(x, y) ↦ x**3 + 3*x**2*y + 3*x*y**2 + y**3
|
|
1754
|
+
sage: pow(f,3).display()
|
|
1755
|
+
(x, y) ↦ x**3 + 3*x**2*y + 3*x*y**2 + y**3
|
|
1756
|
+
sage: (f^3).display()
|
|
1757
|
+
(x, y) ↦ x**3 + 3*x**2*y + 3*x*y**2 + y**3
|
|
1758
|
+
sage: pow(X.zero_function(), 3).display()
|
|
1759
|
+
(x, y) ↦ 0
|
|
1760
|
+
"""
|
|
1761
|
+
curr = self._calc_method._current
|
|
1762
|
+
if curr == 'SR':
|
|
1763
|
+
val = pow(self.expr(), exponent)
|
|
1764
|
+
elif curr == 'sympy':
|
|
1765
|
+
val = self.expr() ** exponent
|
|
1766
|
+
return type(self)(
|
|
1767
|
+
self.parent(),
|
|
1768
|
+
self._simplify(val),
|
|
1769
|
+
expansion_symbol=self._expansion_symbol,
|
|
1770
|
+
order=self._order,
|
|
1771
|
+
)
|
|
1772
|
+
|
|
1773
|
+
def sqrt(self):
|
|
1774
|
+
r"""
|
|
1775
|
+
Square root of ``self``.
|
|
1776
|
+
|
|
1777
|
+
OUTPUT:
|
|
1778
|
+
|
|
1779
|
+
- chart function `\sqrt{f}`, where `f` is the current
|
|
1780
|
+
chart function
|
|
1781
|
+
|
|
1782
|
+
EXAMPLES::
|
|
1783
|
+
|
|
1784
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1785
|
+
sage: X.<x,y> = M.chart()
|
|
1786
|
+
sage: f = X.function(x+y)
|
|
1787
|
+
sage: f.sqrt()
|
|
1788
|
+
sqrt(x + y)
|
|
1789
|
+
sage: sqrt(f) # equivalent to f.sqrt()
|
|
1790
|
+
sqrt(x + y)
|
|
1791
|
+
sage: sqrt(f).display()
|
|
1792
|
+
(x, y) ↦ sqrt(x + y)
|
|
1793
|
+
sage: sqrt(X.zero_function()).display()
|
|
1794
|
+
(x, y) ↦ 0
|
|
1795
|
+
"""
|
|
1796
|
+
curr = self._calc_method._current
|
|
1797
|
+
if curr == 'SR':
|
|
1798
|
+
val = self.expr().sqrt()
|
|
1799
|
+
elif curr == 'sympy':
|
|
1800
|
+
val = sympy.sqrt(self.expr())
|
|
1801
|
+
return type(self)(
|
|
1802
|
+
self.parent(),
|
|
1803
|
+
self._simplify(val),
|
|
1804
|
+
expansion_symbol=self._expansion_symbol,
|
|
1805
|
+
order=self._order,
|
|
1806
|
+
)
|
|
1807
|
+
|
|
1808
|
+
def cos(self):
|
|
1809
|
+
r"""
|
|
1810
|
+
Cosine of ``self``.
|
|
1811
|
+
|
|
1812
|
+
OUTPUT:
|
|
1813
|
+
|
|
1814
|
+
- chart function `\cos(f)`, where `f` is the current
|
|
1815
|
+
chart function
|
|
1816
|
+
|
|
1817
|
+
EXAMPLES::
|
|
1818
|
+
|
|
1819
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1820
|
+
sage: X.<x,y> = M.chart()
|
|
1821
|
+
sage: f = X.function(x*y)
|
|
1822
|
+
sage: f.cos()
|
|
1823
|
+
cos(x*y)
|
|
1824
|
+
sage: cos(f) # equivalent to f.cos()
|
|
1825
|
+
cos(x*y)
|
|
1826
|
+
sage: cos(f).display()
|
|
1827
|
+
(x, y) ↦ cos(x*y)
|
|
1828
|
+
sage: cos(X.zero_function()).display()
|
|
1829
|
+
(x, y) ↦ 1
|
|
1830
|
+
|
|
1831
|
+
The same tests with SymPy::
|
|
1832
|
+
|
|
1833
|
+
sage: X.calculus_method().set('sympy')
|
|
1834
|
+
sage: f.cos()
|
|
1835
|
+
cos(x*y)
|
|
1836
|
+
sage: cos(f) # equivalent to f.cos()
|
|
1837
|
+
cos(x*y)
|
|
1838
|
+
"""
|
|
1839
|
+
curr = self._calc_method._current
|
|
1840
|
+
if curr == 'SR':
|
|
1841
|
+
val = self.expr().cos()
|
|
1842
|
+
elif curr == 'sympy':
|
|
1843
|
+
val = sympy.cos(self.expr())
|
|
1844
|
+
return type(self)(
|
|
1845
|
+
self.parent(),
|
|
1846
|
+
self._simplify(val),
|
|
1847
|
+
expansion_symbol=self._expansion_symbol,
|
|
1848
|
+
order=self._order,
|
|
1849
|
+
)
|
|
1850
|
+
|
|
1851
|
+
def sin(self):
|
|
1852
|
+
r"""
|
|
1853
|
+
Sine of ``self``.
|
|
1854
|
+
|
|
1855
|
+
OUTPUT:
|
|
1856
|
+
|
|
1857
|
+
- chart function `\sin(f)`, where `f` is the current
|
|
1858
|
+
chart function
|
|
1859
|
+
|
|
1860
|
+
EXAMPLES::
|
|
1861
|
+
|
|
1862
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1863
|
+
sage: X.<x,y> = M.chart()
|
|
1864
|
+
sage: f = X.function(x*y)
|
|
1865
|
+
sage: f.sin()
|
|
1866
|
+
sin(x*y)
|
|
1867
|
+
sage: sin(f) # equivalent to f.sin()
|
|
1868
|
+
sin(x*y)
|
|
1869
|
+
sage: sin(f).display()
|
|
1870
|
+
(x, y) ↦ sin(x*y)
|
|
1871
|
+
sage: sin(X.zero_function()) == X.zero_function()
|
|
1872
|
+
True
|
|
1873
|
+
sage: f = X.function(2-cos(x)^2+y)
|
|
1874
|
+
sage: g = X.function(-sin(x)^2+y)
|
|
1875
|
+
sage: (f+g).simplify()
|
|
1876
|
+
2*y + 1
|
|
1877
|
+
|
|
1878
|
+
The same tests with SymPy::
|
|
1879
|
+
|
|
1880
|
+
sage: X.calculus_method().set('sympy')
|
|
1881
|
+
sage: f = X.function(x*y)
|
|
1882
|
+
sage: f.sin()
|
|
1883
|
+
sin(x*y)
|
|
1884
|
+
sage: sin(f) # equivalent to f.sin()
|
|
1885
|
+
sin(x*y)
|
|
1886
|
+
"""
|
|
1887
|
+
curr = self._calc_method._current
|
|
1888
|
+
if curr == 'SR':
|
|
1889
|
+
val = self.expr().sin()
|
|
1890
|
+
elif curr == 'sympy':
|
|
1891
|
+
val = sympy.sin(self.expr())
|
|
1892
|
+
return type(self)(
|
|
1893
|
+
self.parent(),
|
|
1894
|
+
self._simplify(val),
|
|
1895
|
+
expansion_symbol=self._expansion_symbol,
|
|
1896
|
+
order=self._order,
|
|
1897
|
+
)
|
|
1898
|
+
|
|
1899
|
+
def tan(self):
|
|
1900
|
+
r"""
|
|
1901
|
+
Tangent of ``self``.
|
|
1902
|
+
|
|
1903
|
+
OUTPUT:
|
|
1904
|
+
|
|
1905
|
+
- chart function `\tan(f)`, where `f` is the current
|
|
1906
|
+
chart function
|
|
1907
|
+
|
|
1908
|
+
EXAMPLES::
|
|
1909
|
+
|
|
1910
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1911
|
+
sage: X.<x,y> = M.chart()
|
|
1912
|
+
sage: f = X.function(x*y)
|
|
1913
|
+
sage: f.tan()
|
|
1914
|
+
sin(x*y)/cos(x*y)
|
|
1915
|
+
sage: tan(f) # equivalent to f.tan()
|
|
1916
|
+
sin(x*y)/cos(x*y)
|
|
1917
|
+
sage: tan(f).display()
|
|
1918
|
+
(x, y) ↦ sin(x*y)/cos(x*y)
|
|
1919
|
+
sage: tan(X.zero_function()) == X.zero_function()
|
|
1920
|
+
True
|
|
1921
|
+
|
|
1922
|
+
The same test with SymPy::
|
|
1923
|
+
|
|
1924
|
+
sage: M.set_calculus_method('sympy')
|
|
1925
|
+
sage: g = X.function(x*y)
|
|
1926
|
+
sage: g.tan()
|
|
1927
|
+
tan(x*y)
|
|
1928
|
+
sage: tan(g) # equivalent to g.tan()
|
|
1929
|
+
tan(x*y)
|
|
1930
|
+
sage: tan(g).display()
|
|
1931
|
+
(x, y) ↦ tan(x*y)
|
|
1932
|
+
"""
|
|
1933
|
+
curr = self._calc_method._current
|
|
1934
|
+
if curr == 'SR':
|
|
1935
|
+
val = self.expr().tan()
|
|
1936
|
+
elif curr == 'sympy':
|
|
1937
|
+
val = sympy.tan(self.expr())
|
|
1938
|
+
return type(self)(
|
|
1939
|
+
self.parent(),
|
|
1940
|
+
self._simplify(val),
|
|
1941
|
+
expansion_symbol=self._expansion_symbol,
|
|
1942
|
+
order=self._order,
|
|
1943
|
+
)
|
|
1944
|
+
|
|
1945
|
+
def arccos(self):
|
|
1946
|
+
r"""
|
|
1947
|
+
Arc cosine of ``self``.
|
|
1948
|
+
|
|
1949
|
+
OUTPUT:
|
|
1950
|
+
|
|
1951
|
+
- chart function `\arccos(f)`, where `f` is the current
|
|
1952
|
+
chart function
|
|
1953
|
+
|
|
1954
|
+
EXAMPLES::
|
|
1955
|
+
|
|
1956
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
1957
|
+
sage: X.<x,y> = M.chart()
|
|
1958
|
+
sage: f = X.function(x*y)
|
|
1959
|
+
sage: f.arccos()
|
|
1960
|
+
arccos(x*y)
|
|
1961
|
+
sage: arccos(f) # equivalent to f.arccos()
|
|
1962
|
+
arccos(x*y)
|
|
1963
|
+
sage: acos(f) # equivalent to f.arccos()
|
|
1964
|
+
arccos(x*y)
|
|
1965
|
+
sage: arccos(f).display()
|
|
1966
|
+
(x, y) ↦ arccos(x*y)
|
|
1967
|
+
sage: arccos(X.zero_function()).display()
|
|
1968
|
+
(x, y) ↦ 1/2*pi
|
|
1969
|
+
|
|
1970
|
+
The same test with SymPy::
|
|
1971
|
+
|
|
1972
|
+
sage: M.set_calculus_method('sympy')
|
|
1973
|
+
sage: f = X.function(x*y)
|
|
1974
|
+
sage: f.arccos()
|
|
1975
|
+
acos(x*y)
|
|
1976
|
+
sage: arccos(f) # equivalent to f.arccos()
|
|
1977
|
+
acos(x*y)
|
|
1978
|
+
sage: acos(f) # equivalent to f.arccos()
|
|
1979
|
+
acos(x*y)
|
|
1980
|
+
sage: arccos(f).display()
|
|
1981
|
+
(x, y) ↦ acos(x*y)
|
|
1982
|
+
"""
|
|
1983
|
+
curr = self._calc_method._current
|
|
1984
|
+
if curr == 'SR':
|
|
1985
|
+
val = self.expr().arccos()
|
|
1986
|
+
elif curr == 'sympy':
|
|
1987
|
+
val = sympy.acos(self.expr())
|
|
1988
|
+
return type(self)(
|
|
1989
|
+
self.parent(),
|
|
1990
|
+
self._simplify(val),
|
|
1991
|
+
expansion_symbol=self._expansion_symbol,
|
|
1992
|
+
order=self._order,
|
|
1993
|
+
)
|
|
1994
|
+
|
|
1995
|
+
def arcsin(self):
|
|
1996
|
+
r"""
|
|
1997
|
+
Arc sine of ``self``.
|
|
1998
|
+
|
|
1999
|
+
OUTPUT:
|
|
2000
|
+
|
|
2001
|
+
- chart function `\arcsin(f)`, where `f` is the current
|
|
2002
|
+
chart function
|
|
2003
|
+
|
|
2004
|
+
EXAMPLES::
|
|
2005
|
+
|
|
2006
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2007
|
+
sage: X.<x,y> = M.chart()
|
|
2008
|
+
sage: f = X.function(x*y)
|
|
2009
|
+
sage: f.arcsin()
|
|
2010
|
+
arcsin(x*y)
|
|
2011
|
+
sage: arcsin(f) # equivalent to f.arcsin()
|
|
2012
|
+
arcsin(x*y)
|
|
2013
|
+
sage: asin(f) # equivalent to f.arcsin()
|
|
2014
|
+
arcsin(x*y)
|
|
2015
|
+
sage: arcsin(f).display()
|
|
2016
|
+
(x, y) ↦ arcsin(x*y)
|
|
2017
|
+
sage: arcsin(X.zero_function()) == X.zero_function()
|
|
2018
|
+
True
|
|
2019
|
+
|
|
2020
|
+
The same tests with SymPy::
|
|
2021
|
+
|
|
2022
|
+
sage: X.calculus_method().set('sympy')
|
|
2023
|
+
sage: f.arcsin()
|
|
2024
|
+
asin(x*y)
|
|
2025
|
+
sage: arcsin(f) # equivalent to f.arcsin()
|
|
2026
|
+
asin(x*y)
|
|
2027
|
+
sage: asin(f) # equivalent to f.arcsin()
|
|
2028
|
+
asin(x*y)
|
|
2029
|
+
"""
|
|
2030
|
+
curr = self._calc_method._current
|
|
2031
|
+
if curr == 'SR':
|
|
2032
|
+
val = self.expr().arcsin()
|
|
2033
|
+
elif curr == 'sympy':
|
|
2034
|
+
val = sympy.asin(self.expr())
|
|
2035
|
+
return type(self)(
|
|
2036
|
+
self.parent(),
|
|
2037
|
+
self._simplify(val),
|
|
2038
|
+
expansion_symbol=self._expansion_symbol,
|
|
2039
|
+
order=self._order,
|
|
2040
|
+
)
|
|
2041
|
+
|
|
2042
|
+
def arctan(self):
|
|
2043
|
+
r"""
|
|
2044
|
+
Arc tangent of ``self``.
|
|
2045
|
+
|
|
2046
|
+
OUTPUT:
|
|
2047
|
+
|
|
2048
|
+
- chart function `\arctan(f)`, where `f` is the current
|
|
2049
|
+
chart function
|
|
2050
|
+
|
|
2051
|
+
EXAMPLES::
|
|
2052
|
+
|
|
2053
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2054
|
+
sage: X.<x,y> = M.chart()
|
|
2055
|
+
sage: f = X.function(x*y)
|
|
2056
|
+
sage: f.arctan()
|
|
2057
|
+
arctan(x*y)
|
|
2058
|
+
sage: arctan(f) # equivalent to f.arctan()
|
|
2059
|
+
arctan(x*y)
|
|
2060
|
+
sage: atan(f) # equivalent to f.arctan()
|
|
2061
|
+
arctan(x*y)
|
|
2062
|
+
sage: arctan(f).display()
|
|
2063
|
+
(x, y) ↦ arctan(x*y)
|
|
2064
|
+
sage: arctan(X.zero_function()) == X.zero_function()
|
|
2065
|
+
True
|
|
2066
|
+
|
|
2067
|
+
The same tests with SymPy::
|
|
2068
|
+
|
|
2069
|
+
sage: X.calculus_method().set('sympy')
|
|
2070
|
+
sage: f.arctan()
|
|
2071
|
+
atan(x*y)
|
|
2072
|
+
sage: arctan(f) # equivalent to f.arctan()
|
|
2073
|
+
atan(x*y)
|
|
2074
|
+
sage: atan(f) # equivalent to f.arctan()
|
|
2075
|
+
atan(x*y)
|
|
2076
|
+
"""
|
|
2077
|
+
curr = self._calc_method._current
|
|
2078
|
+
if curr == 'SR':
|
|
2079
|
+
val = self.expr().arctan()
|
|
2080
|
+
elif curr == 'sympy':
|
|
2081
|
+
val = sympy.atan(self.expr())
|
|
2082
|
+
return type(self)(
|
|
2083
|
+
self.parent(),
|
|
2084
|
+
self._simplify(val),
|
|
2085
|
+
expansion_symbol=self._expansion_symbol,
|
|
2086
|
+
order=self._order,
|
|
2087
|
+
)
|
|
2088
|
+
|
|
2089
|
+
def cosh(self):
|
|
2090
|
+
r"""
|
|
2091
|
+
Hyperbolic cosine of ``self``.
|
|
2092
|
+
|
|
2093
|
+
OUTPUT:
|
|
2094
|
+
|
|
2095
|
+
- chart function `\cosh(f)`, where `f` is the current
|
|
2096
|
+
chart function
|
|
2097
|
+
|
|
2098
|
+
EXAMPLES::
|
|
2099
|
+
|
|
2100
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2101
|
+
sage: X.<x,y> = M.chart()
|
|
2102
|
+
sage: f = X.function(x*y)
|
|
2103
|
+
sage: f.cosh()
|
|
2104
|
+
cosh(x*y)
|
|
2105
|
+
sage: cosh(f) # equivalent to f.cosh()
|
|
2106
|
+
cosh(x*y)
|
|
2107
|
+
sage: cosh(f).display()
|
|
2108
|
+
(x, y) ↦ cosh(x*y)
|
|
2109
|
+
sage: cosh(X.zero_function()).display()
|
|
2110
|
+
(x, y) ↦ 1
|
|
2111
|
+
|
|
2112
|
+
The same tests with SymPy::
|
|
2113
|
+
|
|
2114
|
+
sage: X.calculus_method().set('sympy')
|
|
2115
|
+
sage: f.cosh()
|
|
2116
|
+
cosh(x*y)
|
|
2117
|
+
sage: cosh(f) # equivalent to f.cosh()
|
|
2118
|
+
cosh(x*y)
|
|
2119
|
+
"""
|
|
2120
|
+
curr = self._calc_method._current
|
|
2121
|
+
if curr == 'SR':
|
|
2122
|
+
val = self.expr().cosh()
|
|
2123
|
+
elif curr == 'sympy':
|
|
2124
|
+
val = sympy.cosh(self.expr())
|
|
2125
|
+
return type(self)(
|
|
2126
|
+
self.parent(),
|
|
2127
|
+
self._simplify(val),
|
|
2128
|
+
expansion_symbol=self._expansion_symbol,
|
|
2129
|
+
order=self._order,
|
|
2130
|
+
)
|
|
2131
|
+
|
|
2132
|
+
def sinh(self):
|
|
2133
|
+
r"""
|
|
2134
|
+
Hyperbolic sine of ``self``.
|
|
2135
|
+
|
|
2136
|
+
OUTPUT:
|
|
2137
|
+
|
|
2138
|
+
- chart function `\sinh(f)`, where `f` is the current
|
|
2139
|
+
chart function
|
|
2140
|
+
|
|
2141
|
+
EXAMPLES::
|
|
2142
|
+
|
|
2143
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2144
|
+
sage: X.<x,y> = M.chart()
|
|
2145
|
+
sage: f = X.function(x*y)
|
|
2146
|
+
sage: f.sinh()
|
|
2147
|
+
sinh(x*y)
|
|
2148
|
+
sage: sinh(f) # equivalent to f.sinh()
|
|
2149
|
+
sinh(x*y)
|
|
2150
|
+
sage: sinh(f).display()
|
|
2151
|
+
(x, y) ↦ sinh(x*y)
|
|
2152
|
+
sage: sinh(X.zero_function()) == X.zero_function()
|
|
2153
|
+
True
|
|
2154
|
+
|
|
2155
|
+
The same tests with SymPy::
|
|
2156
|
+
|
|
2157
|
+
sage: X.calculus_method().set('sympy')
|
|
2158
|
+
sage: f.sinh()
|
|
2159
|
+
sinh(x*y)
|
|
2160
|
+
sage: sinh(f) # equivalent to f.sinh()
|
|
2161
|
+
sinh(x*y)
|
|
2162
|
+
"""
|
|
2163
|
+
curr = self._calc_method._current
|
|
2164
|
+
if curr == 'SR':
|
|
2165
|
+
val = self.expr().sinh()
|
|
2166
|
+
elif curr == 'sympy':
|
|
2167
|
+
val = sympy.sinh(self.expr())
|
|
2168
|
+
return type(self)(
|
|
2169
|
+
self.parent(),
|
|
2170
|
+
self._simplify(val),
|
|
2171
|
+
expansion_symbol=self._expansion_symbol,
|
|
2172
|
+
order=self._order,
|
|
2173
|
+
)
|
|
2174
|
+
|
|
2175
|
+
def tanh(self):
|
|
2176
|
+
r"""
|
|
2177
|
+
Hyperbolic tangent of ``self``.
|
|
2178
|
+
|
|
2179
|
+
OUTPUT:
|
|
2180
|
+
|
|
2181
|
+
- chart function `\tanh(f)`, where `f` is the current
|
|
2182
|
+
chart function
|
|
2183
|
+
|
|
2184
|
+
EXAMPLES::
|
|
2185
|
+
|
|
2186
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2187
|
+
sage: X.<x,y> = M.chart()
|
|
2188
|
+
sage: f = X.function(x*y)
|
|
2189
|
+
sage: f.tanh()
|
|
2190
|
+
sinh(x*y)/cosh(x*y)
|
|
2191
|
+
sage: tanh(f) # equivalent to f.tanh()
|
|
2192
|
+
sinh(x*y)/cosh(x*y)
|
|
2193
|
+
sage: tanh(f).display()
|
|
2194
|
+
(x, y) ↦ sinh(x*y)/cosh(x*y)
|
|
2195
|
+
sage: tanh(X.zero_function()) == X.zero_function()
|
|
2196
|
+
True
|
|
2197
|
+
|
|
2198
|
+
The same tests with SymPy::
|
|
2199
|
+
|
|
2200
|
+
sage: X.calculus_method().set('sympy')
|
|
2201
|
+
sage: f.tanh()
|
|
2202
|
+
tanh(x*y)
|
|
2203
|
+
sage: tanh(f) # equivalent to f.tanh()
|
|
2204
|
+
tanh(x*y)
|
|
2205
|
+
"""
|
|
2206
|
+
curr = self._calc_method._current
|
|
2207
|
+
if curr == 'SR':
|
|
2208
|
+
val = self.expr().tanh()
|
|
2209
|
+
elif curr == 'sympy':
|
|
2210
|
+
val = sympy.tanh(self.expr())
|
|
2211
|
+
return type(self)(
|
|
2212
|
+
self.parent(),
|
|
2213
|
+
self._simplify(val),
|
|
2214
|
+
expansion_symbol=self._expansion_symbol,
|
|
2215
|
+
order=self._order,
|
|
2216
|
+
)
|
|
2217
|
+
|
|
2218
|
+
def arccosh(self):
|
|
2219
|
+
r"""
|
|
2220
|
+
Inverse hyperbolic cosine of ``self``.
|
|
2221
|
+
|
|
2222
|
+
OUTPUT:
|
|
2223
|
+
|
|
2224
|
+
- chart function `\mathrm{arccosh}(f)`, where `f` is the current
|
|
2225
|
+
chart function
|
|
2226
|
+
|
|
2227
|
+
EXAMPLES::
|
|
2228
|
+
|
|
2229
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2230
|
+
sage: X.<x,y> = M.chart()
|
|
2231
|
+
sage: f = X.function(x*y)
|
|
2232
|
+
sage: f.arccosh()
|
|
2233
|
+
arccosh(x*y)
|
|
2234
|
+
sage: arccosh(f) # equivalent to f.arccosh()
|
|
2235
|
+
arccosh(x*y)
|
|
2236
|
+
sage: acosh(f) # equivalent to f.arccosh()
|
|
2237
|
+
arccosh(x*y)
|
|
2238
|
+
sage: arccosh(f).display()
|
|
2239
|
+
(x, y) ↦ arccosh(x*y)
|
|
2240
|
+
sage: arccosh(X.function(1)) == X.zero_function()
|
|
2241
|
+
True
|
|
2242
|
+
|
|
2243
|
+
The same tests with SymPy::
|
|
2244
|
+
|
|
2245
|
+
sage: X.calculus_method().set('sympy')
|
|
2246
|
+
sage: f.arccosh()
|
|
2247
|
+
acosh(x*y)
|
|
2248
|
+
sage: arccosh(f) # equivalent to f.arccosh()
|
|
2249
|
+
acosh(x*y)
|
|
2250
|
+
sage: acosh(f) # equivalent to f.arccosh()
|
|
2251
|
+
acosh(x*y)
|
|
2252
|
+
"""
|
|
2253
|
+
curr = self._calc_method._current
|
|
2254
|
+
if curr == 'SR':
|
|
2255
|
+
val = self.expr().arccosh()
|
|
2256
|
+
elif curr == 'sympy':
|
|
2257
|
+
val = sympy.acosh(self.expr())
|
|
2258
|
+
return type(self)(
|
|
2259
|
+
self.parent(),
|
|
2260
|
+
self._simplify(val),
|
|
2261
|
+
expansion_symbol=self._expansion_symbol,
|
|
2262
|
+
order=self._order,
|
|
2263
|
+
)
|
|
2264
|
+
|
|
2265
|
+
def arcsinh(self):
|
|
2266
|
+
r"""
|
|
2267
|
+
Inverse hyperbolic sine of ``self``.
|
|
2268
|
+
|
|
2269
|
+
OUTPUT:
|
|
2270
|
+
|
|
2271
|
+
- chart function `\mathrm{arcsinh}(f)`, where `f` is the current
|
|
2272
|
+
chart function
|
|
2273
|
+
|
|
2274
|
+
EXAMPLES::
|
|
2275
|
+
|
|
2276
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2277
|
+
sage: X.<x,y> = M.chart()
|
|
2278
|
+
sage: f = X.function(x*y)
|
|
2279
|
+
sage: f.arcsinh()
|
|
2280
|
+
arcsinh(x*y)
|
|
2281
|
+
sage: arcsinh(f) # equivalent to f.arcsinh()
|
|
2282
|
+
arcsinh(x*y)
|
|
2283
|
+
sage: asinh(f) # equivalent to f.arcsinh()
|
|
2284
|
+
arcsinh(x*y)
|
|
2285
|
+
sage: arcsinh(f).display()
|
|
2286
|
+
(x, y) ↦ arcsinh(x*y)
|
|
2287
|
+
sage: arcsinh(X.zero_function()) == X.zero_function()
|
|
2288
|
+
True
|
|
2289
|
+
|
|
2290
|
+
The same tests with SymPy::
|
|
2291
|
+
|
|
2292
|
+
sage: X.calculus_method().set('sympy')
|
|
2293
|
+
sage: f.arcsinh()
|
|
2294
|
+
asinh(x*y)
|
|
2295
|
+
sage: arcsinh(f) # equivalent to f.arcsinh()
|
|
2296
|
+
asinh(x*y)
|
|
2297
|
+
sage: asinh(f) # equivalent to f.arcsinh()
|
|
2298
|
+
asinh(x*y)
|
|
2299
|
+
"""
|
|
2300
|
+
curr = self._calc_method._current
|
|
2301
|
+
if curr == 'SR':
|
|
2302
|
+
val = self.expr().arcsinh()
|
|
2303
|
+
elif curr == 'sympy':
|
|
2304
|
+
val = sympy.asinh(self.expr())
|
|
2305
|
+
return type(self)(
|
|
2306
|
+
self.parent(),
|
|
2307
|
+
self._simplify(val),
|
|
2308
|
+
expansion_symbol=self._expansion_symbol,
|
|
2309
|
+
order=self._order,
|
|
2310
|
+
)
|
|
2311
|
+
|
|
2312
|
+
def arctanh(self):
|
|
2313
|
+
r"""
|
|
2314
|
+
Inverse hyperbolic tangent of ``self``.
|
|
2315
|
+
|
|
2316
|
+
OUTPUT:
|
|
2317
|
+
|
|
2318
|
+
- chart function `\mathrm{arctanh}(f)`, where `f` is the
|
|
2319
|
+
current chart function
|
|
2320
|
+
|
|
2321
|
+
EXAMPLES::
|
|
2322
|
+
|
|
2323
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2324
|
+
sage: X.<x,y> = M.chart()
|
|
2325
|
+
sage: f = X.function(x*y)
|
|
2326
|
+
sage: f.arctanh()
|
|
2327
|
+
arctanh(x*y)
|
|
2328
|
+
sage: arctanh(f) # equivalent to f.arctanh()
|
|
2329
|
+
arctanh(x*y)
|
|
2330
|
+
sage: atanh(f) # equivalent to f.arctanh()
|
|
2331
|
+
arctanh(x*y)
|
|
2332
|
+
sage: arctanh(f).display()
|
|
2333
|
+
(x, y) ↦ arctanh(x*y)
|
|
2334
|
+
sage: arctanh(X.zero_function()) == X.zero_function()
|
|
2335
|
+
True
|
|
2336
|
+
|
|
2337
|
+
The same tests with SymPy::
|
|
2338
|
+
|
|
2339
|
+
sage: X.calculus_method().set('sympy')
|
|
2340
|
+
sage: f.arctanh()
|
|
2341
|
+
atanh(x*y)
|
|
2342
|
+
sage: arctanh(f) # equivalent to f.arctanh()
|
|
2343
|
+
atanh(x*y)
|
|
2344
|
+
sage: atanh(f) # equivalent to f.arctanh()
|
|
2345
|
+
atanh(x*y)
|
|
2346
|
+
"""
|
|
2347
|
+
curr = self._calc_method._current
|
|
2348
|
+
if curr == 'SR':
|
|
2349
|
+
val = self.expr().arctanh()
|
|
2350
|
+
elif curr == 'sympy':
|
|
2351
|
+
val = sympy.atanh(self.expr())
|
|
2352
|
+
return type(self)(
|
|
2353
|
+
self.parent(),
|
|
2354
|
+
self._simplify(val),
|
|
2355
|
+
expansion_symbol=self._expansion_symbol,
|
|
2356
|
+
order=self._order,
|
|
2357
|
+
)
|
|
2358
|
+
|
|
2359
|
+
def __abs__(self):
|
|
2360
|
+
r"""
|
|
2361
|
+
Absolute value of ``self``.
|
|
2362
|
+
|
|
2363
|
+
OUTPUT:
|
|
2364
|
+
|
|
2365
|
+
- chart function `\mathrm{abs}(f)`, where `f` is the
|
|
2366
|
+
current chart function
|
|
2367
|
+
|
|
2368
|
+
EXAMPLES::
|
|
2369
|
+
|
|
2370
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2371
|
+
sage: X.<x,y> = M.chart()
|
|
2372
|
+
sage: f = X.function(x*y)
|
|
2373
|
+
sage: f.abs()
|
|
2374
|
+
abs(x)*abs(y)
|
|
2375
|
+
sage: abs(f) # equivalent to f.abs()
|
|
2376
|
+
abs(x)*abs(y)
|
|
2377
|
+
sage: abs(f).display()
|
|
2378
|
+
(x, y) ↦ abs(x)*abs(y)
|
|
2379
|
+
sage: abs(X.zero_function()) == X.zero_function()
|
|
2380
|
+
True
|
|
2381
|
+
|
|
2382
|
+
The same tests with SymPy::
|
|
2383
|
+
|
|
2384
|
+
sage: X.calculus_method().set('sympy')
|
|
2385
|
+
sage: f.abs()
|
|
2386
|
+
Abs(x*y)
|
|
2387
|
+
sage: abs(f) # equivalent to f.abs()
|
|
2388
|
+
Abs(x*y)
|
|
2389
|
+
"""
|
|
2390
|
+
curr = self._calc_method._current
|
|
2391
|
+
if curr == 'SR':
|
|
2392
|
+
val = self.expr().abs()
|
|
2393
|
+
elif curr == 'sympy':
|
|
2394
|
+
val = abs(self.expr())
|
|
2395
|
+
return type(self)(
|
|
2396
|
+
self.parent(),
|
|
2397
|
+
self._simplify(val),
|
|
2398
|
+
expansion_symbol=self._expansion_symbol,
|
|
2399
|
+
order=self._order,
|
|
2400
|
+
)
|
|
2401
|
+
|
|
2402
|
+
def _del_derived(self):
|
|
2403
|
+
r"""
|
|
2404
|
+
Delete the derived quantities.
|
|
2405
|
+
|
|
2406
|
+
TESTS::
|
|
2407
|
+
|
|
2408
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2409
|
+
sage: X.<x,y> = M.chart()
|
|
2410
|
+
sage: f = X.function(cos(x*y))
|
|
2411
|
+
sage: f._der
|
|
2412
|
+
sage: f.diff(x)
|
|
2413
|
+
-y*sin(x*y)
|
|
2414
|
+
sage: f._der
|
|
2415
|
+
[-y*sin(x*y), -x*sin(x*y)]
|
|
2416
|
+
sage: f._del_derived()
|
|
2417
|
+
sage: f._der
|
|
2418
|
+
|
|
2419
|
+
The same tests with SymPy::
|
|
2420
|
+
|
|
2421
|
+
sage: X.calculus_method().set('sympy')
|
|
2422
|
+
sage: f = X.function(cos(x*y))
|
|
2423
|
+
sage: f._der
|
|
2424
|
+
sage: f.diff(x)
|
|
2425
|
+
-y*sin(x*y)
|
|
2426
|
+
sage: f._der
|
|
2427
|
+
[-y*sin(x*y), -x*sin(x*y)]
|
|
2428
|
+
sage: type(f._der[0]._express['sympy'])
|
|
2429
|
+
<class 'sympy.core.mul.Mul'>
|
|
2430
|
+
sage: f._del_derived()
|
|
2431
|
+
sage: f._der
|
|
2432
|
+
"""
|
|
2433
|
+
self._der = None # reset of the partial derivatives
|
|
2434
|
+
|
|
2435
|
+
def simplify(self) -> Self:
|
|
2436
|
+
r"""
|
|
2437
|
+
Simplify the coordinate expression of ``self``.
|
|
2438
|
+
|
|
2439
|
+
For details about the employed chain of simplifications for the ``SR``
|
|
2440
|
+
calculus method, see
|
|
2441
|
+
:func:`~sage.manifolds.utilities.simplify_chain_real` for chart
|
|
2442
|
+
functions on real manifolds and
|
|
2443
|
+
:func:`~sage.manifolds.utilities.simplify_chain_generic` for the
|
|
2444
|
+
generic case.
|
|
2445
|
+
|
|
2446
|
+
If ``self`` has been defined with the small parameter
|
|
2447
|
+
``expansion_symbol`` and some truncation order, the coordinate
|
|
2448
|
+
expression of ``self`` will be expanded in power series of that
|
|
2449
|
+
parameter and truncated to the given order.
|
|
2450
|
+
|
|
2451
|
+
OUTPUT: ``self`` with its coordinate expression simplified
|
|
2452
|
+
|
|
2453
|
+
EXAMPLES:
|
|
2454
|
+
|
|
2455
|
+
Simplification of a chart function on a 2-dimensional manifold::
|
|
2456
|
+
|
|
2457
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2458
|
+
sage: X.<x,y> = M.chart()
|
|
2459
|
+
sage: f = X.function(cos(x)^2 + sin(x)^2 + sqrt(x^2))
|
|
2460
|
+
sage: f.display()
|
|
2461
|
+
(x, y) ↦ cos(x)^2 + sin(x)^2 + abs(x)
|
|
2462
|
+
sage: f.simplify()
|
|
2463
|
+
abs(x) + 1
|
|
2464
|
+
|
|
2465
|
+
The method ``simplify()`` has changed the expression of ``f``::
|
|
2466
|
+
|
|
2467
|
+
sage: f.display()
|
|
2468
|
+
(x, y) ↦ abs(x) + 1
|
|
2469
|
+
|
|
2470
|
+
Another example::
|
|
2471
|
+
|
|
2472
|
+
sage: f = X.function((x^2-1)/(x+1)); f
|
|
2473
|
+
(x^2 - 1)/(x + 1)
|
|
2474
|
+
sage: f.simplify()
|
|
2475
|
+
x - 1
|
|
2476
|
+
|
|
2477
|
+
Examples taking into account the declared range of a coordinate::
|
|
2478
|
+
|
|
2479
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2480
|
+
sage: X.<x,y> = M.chart('x:(1,+oo) y')
|
|
2481
|
+
sage: f = X.function(sqrt(x^2-2*x+1)); f
|
|
2482
|
+
sqrt(x^2 - 2*x + 1)
|
|
2483
|
+
sage: f.simplify()
|
|
2484
|
+
x - 1
|
|
2485
|
+
|
|
2486
|
+
::
|
|
2487
|
+
|
|
2488
|
+
sage: forget() # to clear the previous assumption on x
|
|
2489
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2490
|
+
sage: X.<x,y> = M.chart('x:(-oo,0) y')
|
|
2491
|
+
sage: f = X.function(sqrt(x^2-2*x+1)); f
|
|
2492
|
+
sqrt(x^2 - 2*x + 1)
|
|
2493
|
+
sage: f.simplify()
|
|
2494
|
+
-x + 1
|
|
2495
|
+
|
|
2496
|
+
The same tests with SymPy::
|
|
2497
|
+
|
|
2498
|
+
sage: forget() # to clear the previous assumption on x
|
|
2499
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2500
|
+
sage: X.<x,y> = M.chart(calc_method='sympy')
|
|
2501
|
+
sage: f = X.function(cos(x)^2 + sin(x)^2 + sqrt(x^2)); f
|
|
2502
|
+
sin(x)**2 + cos(x)**2 + Abs(x)
|
|
2503
|
+
sage: f.simplify()
|
|
2504
|
+
Abs(x) + 1
|
|
2505
|
+
|
|
2506
|
+
::
|
|
2507
|
+
|
|
2508
|
+
sage: f = X.function((x^2-1)/(x+1)); f
|
|
2509
|
+
(x**2 - 1)/(x + 1)
|
|
2510
|
+
sage: f.simplify()
|
|
2511
|
+
x - 1
|
|
2512
|
+
|
|
2513
|
+
::
|
|
2514
|
+
|
|
2515
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2516
|
+
sage: X.<x,y> = M.chart('x:(1,+oo) y', calc_method='sympy')
|
|
2517
|
+
sage: f = X.function(sqrt(x^2-2*x+1)); f
|
|
2518
|
+
sqrt(x**2 - 2*x + 1)
|
|
2519
|
+
sage: f.simplify()
|
|
2520
|
+
x - 1
|
|
2521
|
+
|
|
2522
|
+
::
|
|
2523
|
+
|
|
2524
|
+
sage: forget() # to clear the previous assumption on x
|
|
2525
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2526
|
+
sage: X.<x,y> = M.chart('x:(-oo,0) y', calc_method='sympy')
|
|
2527
|
+
sage: f = X.function(sqrt(x^2-2*x+1)); f
|
|
2528
|
+
sqrt(x**2 - 2*x + 1)
|
|
2529
|
+
sage: f.simplify()
|
|
2530
|
+
1 - x
|
|
2531
|
+
|
|
2532
|
+
Power series expansion with respect to a small parameter `t` (at
|
|
2533
|
+
the moment, this is implemented only for the ``SR`` calculus backend,
|
|
2534
|
+
hence the first line below)::
|
|
2535
|
+
|
|
2536
|
+
sage: X.calculus_method().set('SR')
|
|
2537
|
+
sage: t = var('t')
|
|
2538
|
+
sage: f = X.function(exp(t*x), expansion_symbol=t, order=3)
|
|
2539
|
+
|
|
2540
|
+
At this stage, `f` is not expanded in power series::
|
|
2541
|
+
|
|
2542
|
+
sage: f
|
|
2543
|
+
e^(t*x)
|
|
2544
|
+
|
|
2545
|
+
Invoking ``simplify()`` triggers the expansion to the given order::
|
|
2546
|
+
|
|
2547
|
+
sage: f.simplify()
|
|
2548
|
+
1/6*t^3*x^3 + 1/2*t^2*x^2 + t*x + 1
|
|
2549
|
+
sage: f.display()
|
|
2550
|
+
(x, y) ↦ 1/6*t^3*x^3 + 1/2*t^2*x^2 + t*x + 1
|
|
2551
|
+
"""
|
|
2552
|
+
curr = self._calc_method._current
|
|
2553
|
+
self._express[curr] = self._simplify(self.expr(curr))
|
|
2554
|
+
self._del_derived()
|
|
2555
|
+
return self
|
|
2556
|
+
|
|
2557
|
+
def factor(self) -> Self:
|
|
2558
|
+
r"""
|
|
2559
|
+
Factorize the coordinate expression of ``self``.
|
|
2560
|
+
|
|
2561
|
+
OUTPUT: ``self`` with its expression factorized
|
|
2562
|
+
|
|
2563
|
+
EXAMPLES:
|
|
2564
|
+
|
|
2565
|
+
Factorization of a 2-dimensional chart function::
|
|
2566
|
+
|
|
2567
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2568
|
+
sage: X.<x,y> = M.chart()
|
|
2569
|
+
sage: f = X.function(x^2 + 2*x*y + y^2)
|
|
2570
|
+
sage: f.display()
|
|
2571
|
+
(x, y) ↦ x^2 + 2*x*y + y^2
|
|
2572
|
+
sage: f.factor()
|
|
2573
|
+
(x + y)^2
|
|
2574
|
+
|
|
2575
|
+
The method ``factor()`` has changed the expression of ``f``::
|
|
2576
|
+
|
|
2577
|
+
sage: f.display()
|
|
2578
|
+
(x, y) ↦ (x + y)^2
|
|
2579
|
+
|
|
2580
|
+
The same test with SymPy ::
|
|
2581
|
+
|
|
2582
|
+
sage: X.calculus_method().set('sympy')
|
|
2583
|
+
sage: g = X.function(x^2 + 2*x*y + y^2)
|
|
2584
|
+
sage: g.display()
|
|
2585
|
+
(x, y) ↦ x**2 + 2*x*y + y**2
|
|
2586
|
+
sage: g.factor()
|
|
2587
|
+
(x + y)**2
|
|
2588
|
+
"""
|
|
2589
|
+
curr = self._calc_method._current
|
|
2590
|
+
self._express[curr] = self.expr().factor()
|
|
2591
|
+
self._del_derived()
|
|
2592
|
+
return self
|
|
2593
|
+
|
|
2594
|
+
def expand(self) -> Self:
|
|
2595
|
+
r"""
|
|
2596
|
+
Expand the coordinate expression of ``self``.
|
|
2597
|
+
|
|
2598
|
+
OUTPUT: ``self`` with its expression expanded
|
|
2599
|
+
|
|
2600
|
+
EXAMPLES:
|
|
2601
|
+
|
|
2602
|
+
Expanding a 2-dimensional chart function::
|
|
2603
|
+
|
|
2604
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2605
|
+
sage: X.<x,y> = M.chart()
|
|
2606
|
+
sage: f = X.function((x - y)^2)
|
|
2607
|
+
sage: f.display()
|
|
2608
|
+
(x, y) ↦ (x - y)^2
|
|
2609
|
+
sage: f.expand()
|
|
2610
|
+
x^2 - 2*x*y + y^2
|
|
2611
|
+
|
|
2612
|
+
The method ``expand()`` has changed the expression of ``f``::
|
|
2613
|
+
|
|
2614
|
+
sage: f.display()
|
|
2615
|
+
(x, y) ↦ x^2 - 2*x*y + y^2
|
|
2616
|
+
|
|
2617
|
+
The same test with SymPy ::
|
|
2618
|
+
|
|
2619
|
+
sage: X.calculus_method().set('sympy')
|
|
2620
|
+
sage: g = X.function((x - y)^2)
|
|
2621
|
+
sage: g.expand()
|
|
2622
|
+
x**2 - 2*x*y + y**2
|
|
2623
|
+
"""
|
|
2624
|
+
curr = self._calc_method._current
|
|
2625
|
+
self._express[curr] = self.expr().expand()
|
|
2626
|
+
self._del_derived()
|
|
2627
|
+
return self
|
|
2628
|
+
|
|
2629
|
+
def collect(self, s) -> Self:
|
|
2630
|
+
r"""
|
|
2631
|
+
Collect the coefficients of `s` in the expression of ``self``
|
|
2632
|
+
into a group.
|
|
2633
|
+
|
|
2634
|
+
INPUT:
|
|
2635
|
+
|
|
2636
|
+
- ``s`` -- the symbol whose coefficients will be collected
|
|
2637
|
+
|
|
2638
|
+
OUTPUT:
|
|
2639
|
+
|
|
2640
|
+
- ``self`` with the coefficients of ``s`` grouped in
|
|
2641
|
+
its expression
|
|
2642
|
+
|
|
2643
|
+
EXAMPLES:
|
|
2644
|
+
|
|
2645
|
+
Action on a 2-dimensional chart function::
|
|
2646
|
+
|
|
2647
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2648
|
+
sage: X.<x,y> = M.chart()
|
|
2649
|
+
sage: f = X.function(x^2*y + x*y + (x*y)^2)
|
|
2650
|
+
sage: f.display()
|
|
2651
|
+
(x, y) ↦ x^2*y^2 + x^2*y + x*y
|
|
2652
|
+
sage: f.collect(y)
|
|
2653
|
+
x^2*y^2 + (x^2 + x)*y
|
|
2654
|
+
|
|
2655
|
+
The method ``collect()`` has changed the expression of ``f``::
|
|
2656
|
+
|
|
2657
|
+
sage: f.display()
|
|
2658
|
+
(x, y) ↦ x^2*y^2 + (x^2 + x)*y
|
|
2659
|
+
|
|
2660
|
+
The same test with SymPy ::
|
|
2661
|
+
|
|
2662
|
+
sage: X.calculus_method().set('sympy')
|
|
2663
|
+
sage: f = X.function(x^2*y + x*y + (x*y)^2)
|
|
2664
|
+
sage: f.display()
|
|
2665
|
+
(x, y) ↦ x**2*y**2 + x**2*y + x*y
|
|
2666
|
+
sage: f.collect(y)
|
|
2667
|
+
x**2*y**2 + y*(x**2 + x)
|
|
2668
|
+
"""
|
|
2669
|
+
curr = self._calc_method._current
|
|
2670
|
+
self._express[curr] = self.expr().collect(s)
|
|
2671
|
+
self._del_derived()
|
|
2672
|
+
return self
|
|
2673
|
+
|
|
2674
|
+
def collect_common_factors(self) -> Self:
|
|
2675
|
+
r"""
|
|
2676
|
+
Collect common factors in the expression of ``self``.
|
|
2677
|
+
|
|
2678
|
+
This method does not perform a full factorization but only looks
|
|
2679
|
+
for factors which are already explicitly present.
|
|
2680
|
+
|
|
2681
|
+
OUTPUT:
|
|
2682
|
+
|
|
2683
|
+
- ``self`` with the common factors collected in
|
|
2684
|
+
its expression
|
|
2685
|
+
|
|
2686
|
+
EXAMPLES:
|
|
2687
|
+
|
|
2688
|
+
Action on a 2-dimensional chart function::
|
|
2689
|
+
|
|
2690
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2691
|
+
sage: X.<x,y> = M.chart()
|
|
2692
|
+
sage: f = X.function(x/(x^2*y + x*y))
|
|
2693
|
+
sage: f.display()
|
|
2694
|
+
(x, y) ↦ x/(x^2*y + x*y)
|
|
2695
|
+
sage: f.collect_common_factors()
|
|
2696
|
+
1/((x + 1)*y)
|
|
2697
|
+
|
|
2698
|
+
The method ``collect_common_factors()`` has changed the expression
|
|
2699
|
+
of ``f``::
|
|
2700
|
+
|
|
2701
|
+
sage: f.display()
|
|
2702
|
+
(x, y) ↦ 1/((x + 1)*y)
|
|
2703
|
+
|
|
2704
|
+
The same test with SymPy::
|
|
2705
|
+
|
|
2706
|
+
sage: X.calculus_method().set('sympy')
|
|
2707
|
+
sage: g = X.function(x/(x^2*y + x*y))
|
|
2708
|
+
sage: g.display()
|
|
2709
|
+
(x, y) ↦ x/(x**2*y + x*y)
|
|
2710
|
+
sage: g.collect_common_factors()
|
|
2711
|
+
1/(y*(x + 1))
|
|
2712
|
+
"""
|
|
2713
|
+
curr = self._calc_method._current
|
|
2714
|
+
if curr == 'sympy':
|
|
2715
|
+
self._express[curr] = self.expr().simplify()
|
|
2716
|
+
else:
|
|
2717
|
+
self._express[curr] = self.expr().collect_common_factors()
|
|
2718
|
+
self._del_derived()
|
|
2719
|
+
return self
|
|
2720
|
+
|
|
2721
|
+
|
|
2722
|
+
class ChartFunctionRing(Parent, UniqueRepresentation):
|
|
2723
|
+
"""
|
|
2724
|
+
Ring of all chart functions on a chart.
|
|
2725
|
+
|
|
2726
|
+
INPUT:
|
|
2727
|
+
|
|
2728
|
+
- ``chart`` -- a coordinate chart, as an instance of class
|
|
2729
|
+
:class:`~sage.manifolds.chart.Chart`
|
|
2730
|
+
|
|
2731
|
+
EXAMPLES:
|
|
2732
|
+
|
|
2733
|
+
The ring of all chart functions w.r.t. to a chart::
|
|
2734
|
+
|
|
2735
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2736
|
+
sage: X.<x,y> = M.chart()
|
|
2737
|
+
sage: FR = X.function_ring(); FR
|
|
2738
|
+
Ring of chart functions on Chart (M, (x, y))
|
|
2739
|
+
sage: type(FR)
|
|
2740
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category'>
|
|
2741
|
+
sage: FR.category()
|
|
2742
|
+
Category of commutative algebras over Symbolic Ring
|
|
2743
|
+
|
|
2744
|
+
Coercions by means of restrictions are implemented::
|
|
2745
|
+
|
|
2746
|
+
sage: FR_X = X.function_ring()
|
|
2747
|
+
sage: D = M.open_subset('D')
|
|
2748
|
+
sage: X_D = X.restrict(D, x^2+y^2<1) # open disk
|
|
2749
|
+
sage: FR_X_D = X_D.function_ring()
|
|
2750
|
+
sage: FR_X_D.has_coerce_map_from(FR_X)
|
|
2751
|
+
True
|
|
2752
|
+
|
|
2753
|
+
But only if the charts are compatible::
|
|
2754
|
+
|
|
2755
|
+
sage: Y.<t,z> = D.chart()
|
|
2756
|
+
sage: FR_Y = Y.function_ring()
|
|
2757
|
+
sage: FR_Y.has_coerce_map_from(FR_X)
|
|
2758
|
+
False
|
|
2759
|
+
"""
|
|
2760
|
+
|
|
2761
|
+
Element = ChartFunction
|
|
2762
|
+
|
|
2763
|
+
def __init__(self, chart):
|
|
2764
|
+
"""
|
|
2765
|
+
Initialize ``self``.
|
|
2766
|
+
|
|
2767
|
+
EXAMPLES::
|
|
2768
|
+
|
|
2769
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2770
|
+
sage: X.<x,y> = M.chart()
|
|
2771
|
+
sage: FR = X.function_ring()
|
|
2772
|
+
sage: TestSuite(FR).run()
|
|
2773
|
+
"""
|
|
2774
|
+
self._chart = chart
|
|
2775
|
+
Parent.__init__(self, base=SR, category=CommutativeAlgebras(SR))
|
|
2776
|
+
|
|
2777
|
+
def _element_constructor_(self, expression, calc_method=None):
|
|
2778
|
+
r"""
|
|
2779
|
+
Construct a chart function.
|
|
2780
|
+
|
|
2781
|
+
INPUT:
|
|
2782
|
+
|
|
2783
|
+
- ``expression`` -- Expression
|
|
2784
|
+
- ``calc_method`` -- Calculation method (default: ``None``)
|
|
2785
|
+
|
|
2786
|
+
TESTS::
|
|
2787
|
+
|
|
2788
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2789
|
+
sage: X.<x,y> = M.chart()
|
|
2790
|
+
sage: FR = X.function_ring()
|
|
2791
|
+
sage: f = FR._element_constructor_(sin(x*y))
|
|
2792
|
+
sage: f
|
|
2793
|
+
sin(x*y)
|
|
2794
|
+
sage: f.parent() is FR
|
|
2795
|
+
True
|
|
2796
|
+
sage: D = M.open_subset('D')
|
|
2797
|
+
sage: X_D = X.restrict(D, x^2+y^2<1)
|
|
2798
|
+
sage: FR_D = X_D.function_ring()
|
|
2799
|
+
sage: FR_D(f)
|
|
2800
|
+
sin(x*y)
|
|
2801
|
+
"""
|
|
2802
|
+
if isinstance(expression, ChartFunction):
|
|
2803
|
+
if self._chart in expression._chart._subcharts:
|
|
2804
|
+
expression = expression.expr(method=calc_method)
|
|
2805
|
+
return self.element_class(self, expression, calc_method=calc_method)
|
|
2806
|
+
|
|
2807
|
+
def _coerce_map_from_(self, other):
|
|
2808
|
+
r"""
|
|
2809
|
+
Determine whether coercion to ``self`` exists from ``other``.
|
|
2810
|
+
|
|
2811
|
+
TESTS::
|
|
2812
|
+
|
|
2813
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2814
|
+
sage: X.<x,y> = M.chart()
|
|
2815
|
+
sage: FR = X.function_ring()
|
|
2816
|
+
sage: FR.has_coerce_map_from(RR)
|
|
2817
|
+
True
|
|
2818
|
+
sage: D = M.open_subset('D')
|
|
2819
|
+
sage: X_D = X.restrict(D, x^2+y^2<1)
|
|
2820
|
+
sage: FR_D = X_D.function_ring()
|
|
2821
|
+
sage: FR_D.has_coerce_map_from(FR)
|
|
2822
|
+
True
|
|
2823
|
+
"""
|
|
2824
|
+
if SR.has_coerce_map_from(other):
|
|
2825
|
+
return True
|
|
2826
|
+
if isinstance(other, ChartFunctionRing):
|
|
2827
|
+
if self._chart in other._chart._subcharts:
|
|
2828
|
+
return True
|
|
2829
|
+
return False
|
|
2830
|
+
|
|
2831
|
+
def _repr_(self):
|
|
2832
|
+
r"""
|
|
2833
|
+
Return a string representation of ``self``.
|
|
2834
|
+
|
|
2835
|
+
EXAMPLES::
|
|
2836
|
+
|
|
2837
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2838
|
+
sage: X.<x,y> = M.chart()
|
|
2839
|
+
sage: X.function_ring()
|
|
2840
|
+
Ring of chart functions on Chart (M, (x, y))
|
|
2841
|
+
"""
|
|
2842
|
+
return "Ring of chart functions on {}".format(self._chart)
|
|
2843
|
+
|
|
2844
|
+
def is_integral_domain(self, proof=True):
|
|
2845
|
+
"""
|
|
2846
|
+
Return ``False`` as ``self`` is not an integral domain.
|
|
2847
|
+
|
|
2848
|
+
EXAMPLES::
|
|
2849
|
+
|
|
2850
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2851
|
+
sage: X.<x,y> = M.chart()
|
|
2852
|
+
sage: FR = X.function_ring()
|
|
2853
|
+
sage: FR.is_integral_domain()
|
|
2854
|
+
False
|
|
2855
|
+
sage: FR.is_field()
|
|
2856
|
+
False
|
|
2857
|
+
"""
|
|
2858
|
+
return False
|
|
2859
|
+
|
|
2860
|
+
@cached_method
|
|
2861
|
+
def zero(self):
|
|
2862
|
+
"""
|
|
2863
|
+
Return the constant function `0` in ``self``.
|
|
2864
|
+
|
|
2865
|
+
EXAMPLES::
|
|
2866
|
+
|
|
2867
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2868
|
+
sage: X.<x,y> = M.chart()
|
|
2869
|
+
sage: FR = X.function_ring()
|
|
2870
|
+
sage: FR.zero()
|
|
2871
|
+
0
|
|
2872
|
+
|
|
2873
|
+
sage: # needs sage.rings.padics
|
|
2874
|
+
sage: M = Manifold(2, 'M', structure='topological', field=Qp(5))
|
|
2875
|
+
sage: X.<x,y> = M.chart()
|
|
2876
|
+
sage: X.function_ring().zero()
|
|
2877
|
+
0
|
|
2878
|
+
"""
|
|
2879
|
+
if self._chart.manifold().base_field_type() in ['real', 'complex']:
|
|
2880
|
+
elt = SR.zero()
|
|
2881
|
+
else:
|
|
2882
|
+
elt = self._chart.manifold().base_field().zero()
|
|
2883
|
+
res = self.element_class(self, elt)
|
|
2884
|
+
res.set_immutable()
|
|
2885
|
+
return res
|
|
2886
|
+
|
|
2887
|
+
@cached_method
|
|
2888
|
+
def one(self):
|
|
2889
|
+
"""
|
|
2890
|
+
Return the constant function `1` in ``self``.
|
|
2891
|
+
|
|
2892
|
+
EXAMPLES::
|
|
2893
|
+
|
|
2894
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2895
|
+
sage: X.<x,y> = M.chart()
|
|
2896
|
+
sage: FR = X.function_ring()
|
|
2897
|
+
sage: FR.one()
|
|
2898
|
+
1
|
|
2899
|
+
|
|
2900
|
+
sage: # needs sage.rings.padics
|
|
2901
|
+
sage: M = Manifold(2, 'M', structure='topological', field=Qp(5))
|
|
2902
|
+
sage: X.<x,y> = M.chart()
|
|
2903
|
+
sage: X.function_ring().one()
|
|
2904
|
+
1 + O(5^20)
|
|
2905
|
+
"""
|
|
2906
|
+
if self._chart.manifold().base_field_type() in ['real', 'complex']:
|
|
2907
|
+
elt = SR.one()
|
|
2908
|
+
else:
|
|
2909
|
+
elt = self._chart.manifold().base_field().one()
|
|
2910
|
+
res = self.element_class(self, elt)
|
|
2911
|
+
res.set_immutable()
|
|
2912
|
+
return res
|
|
2913
|
+
|
|
2914
|
+
is_field = is_integral_domain
|
|
2915
|
+
|
|
2916
|
+
|
|
2917
|
+
class MultiCoordFunction(SageObject, Mutability):
|
|
2918
|
+
r"""
|
|
2919
|
+
Coordinate function to some Cartesian power of the base field.
|
|
2920
|
+
|
|
2921
|
+
If `n` and `m` are two positive integers and `(U, \varphi)` is a chart on
|
|
2922
|
+
a topological manifold `M` of dimension `n` over a topological field `K`,
|
|
2923
|
+
a *multi-coordinate function* associated to `(U, \varphi)` is a map
|
|
2924
|
+
|
|
2925
|
+
.. MATH::
|
|
2926
|
+
|
|
2927
|
+
\begin{array}{llcl}
|
|
2928
|
+
f:& V \subset K^n & \longrightarrow & K^m \\
|
|
2929
|
+
& (x^1, \ldots, x^n) & \longmapsto & (f_1(x^1, \ldots, x^n),
|
|
2930
|
+
\ldots, f_m(x^1, \ldots, x^n)),
|
|
2931
|
+
\end{array}
|
|
2932
|
+
|
|
2933
|
+
where `V` is the codomain of `\varphi`. In other words, `f` is a
|
|
2934
|
+
`K^m`-valued function of the coordinates associated to the chart
|
|
2935
|
+
`(U, \varphi)`. Each component `f_i` (`1 \leq i \leq m`) is a coordinate
|
|
2936
|
+
function and is therefore stored as a
|
|
2937
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`.
|
|
2938
|
+
|
|
2939
|
+
INPUT:
|
|
2940
|
+
|
|
2941
|
+
- ``chart`` -- the chart `(U, \varphi)`
|
|
2942
|
+
- ``expressions`` -- list (or tuple) of length `m` of elements to
|
|
2943
|
+
construct the coordinate functions `f_i` (`1 \leq i \leq m`); for
|
|
2944
|
+
symbolic coordinate functions, this must be symbolic expressions
|
|
2945
|
+
involving the chart coordinates, while for numerical coordinate
|
|
2946
|
+
functions, this must be data file names
|
|
2947
|
+
|
|
2948
|
+
EXAMPLES:
|
|
2949
|
+
|
|
2950
|
+
A function `f: V \subset \RR^2 \longrightarrow \RR^3`::
|
|
2951
|
+
|
|
2952
|
+
sage: forget() # to clear the previous assumption on x
|
|
2953
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
2954
|
+
sage: X.<x,y> = M.chart()
|
|
2955
|
+
sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y)); f
|
|
2956
|
+
Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y))
|
|
2957
|
+
sage: type(f)
|
|
2958
|
+
<class 'sage.manifolds.chart_func.MultiCoordFunction'>
|
|
2959
|
+
sage: f(x,y)
|
|
2960
|
+
(x - y, x*y, cos(x)*e^y)
|
|
2961
|
+
sage: latex(f)
|
|
2962
|
+
\left(x - y, x y, \cos\left(x\right) e^{y}\right)
|
|
2963
|
+
|
|
2964
|
+
Each real-valued function `f_i` (`1 \leq i \leq m`) composing `f` can
|
|
2965
|
+
be accessed via the square-bracket operator, by providing `i-1` as an
|
|
2966
|
+
argument::
|
|
2967
|
+
|
|
2968
|
+
sage: f[0]
|
|
2969
|
+
x - y
|
|
2970
|
+
sage: f[1]
|
|
2971
|
+
x*y
|
|
2972
|
+
sage: f[2]
|
|
2973
|
+
cos(x)*e^y
|
|
2974
|
+
|
|
2975
|
+
We can give a more verbose explanation of each function::
|
|
2976
|
+
|
|
2977
|
+
sage: f[0].display()
|
|
2978
|
+
(x, y) ↦ x - y
|
|
2979
|
+
|
|
2980
|
+
Each ``f[i-1]`` is an instance of
|
|
2981
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`::
|
|
2982
|
+
|
|
2983
|
+
sage: isinstance(f[0], sage.manifolds.chart_func.ChartFunction)
|
|
2984
|
+
True
|
|
2985
|
+
|
|
2986
|
+
A class :class:`MultiCoordFunction` can represent a
|
|
2987
|
+
real-valued function (case `m = 1`), although one should
|
|
2988
|
+
rather employ the class :class:`~sage.manifolds.chart_func.ChartFunction`
|
|
2989
|
+
for this purpose::
|
|
2990
|
+
|
|
2991
|
+
sage: g = X.multifunction(x*y^2)
|
|
2992
|
+
sage: g(x,y)
|
|
2993
|
+
(x*y^2,)
|
|
2994
|
+
|
|
2995
|
+
Evaluating the functions at specified coordinates::
|
|
2996
|
+
|
|
2997
|
+
sage: f(1,2)
|
|
2998
|
+
(-1, 2, cos(1)*e^2)
|
|
2999
|
+
sage: var('a b')
|
|
3000
|
+
(a, b)
|
|
3001
|
+
sage: f(a,b)
|
|
3002
|
+
(a - b, a*b, cos(a)*e^b)
|
|
3003
|
+
sage: g(1,2)
|
|
3004
|
+
(4,)
|
|
3005
|
+
"""
|
|
3006
|
+
|
|
3007
|
+
def __init__(self, chart, expressions):
|
|
3008
|
+
r"""
|
|
3009
|
+
Initialize ``self``.
|
|
3010
|
+
|
|
3011
|
+
TESTS::
|
|
3012
|
+
|
|
3013
|
+
sage: M = Manifold(3, 'M', structure='topological')
|
|
3014
|
+
sage: X.<x,y,z> = M.chart()
|
|
3015
|
+
sage: f = X.multifunction(x+y+z, x*y*z); f
|
|
3016
|
+
Coordinate functions (x + y + z, x*y*z) on the Chart (M, (x, y, z))
|
|
3017
|
+
sage: type(f)
|
|
3018
|
+
<class 'sage.manifolds.chart_func.MultiCoordFunction'>
|
|
3019
|
+
sage: TestSuite(f).run()
|
|
3020
|
+
"""
|
|
3021
|
+
self._chart = chart
|
|
3022
|
+
self._nc = len(self._chart._xx) # number of coordinates
|
|
3023
|
+
self._nf = len(expressions) # number of functions
|
|
3024
|
+
self._functions = tuple(chart.function(express) for express in expressions)
|
|
3025
|
+
Mutability.__init__(self)
|
|
3026
|
+
|
|
3027
|
+
def _repr_(self):
|
|
3028
|
+
r"""
|
|
3029
|
+
String representation of ``self``.
|
|
3030
|
+
|
|
3031
|
+
TESTS::
|
|
3032
|
+
|
|
3033
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3034
|
+
sage: X.<x,y> = M.chart()
|
|
3035
|
+
sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
|
|
3036
|
+
sage: f._repr_()
|
|
3037
|
+
'Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y))'
|
|
3038
|
+
sage: f
|
|
3039
|
+
Coordinate functions (x - y, x*y, cos(x)*e^y) on the Chart (M, (x, y))
|
|
3040
|
+
"""
|
|
3041
|
+
return "Coordinate functions {} on the {}".format(self._functions, self._chart)
|
|
3042
|
+
|
|
3043
|
+
def _latex_(self):
|
|
3044
|
+
r"""
|
|
3045
|
+
LaTeX representation of the object.
|
|
3046
|
+
|
|
3047
|
+
TESTS::
|
|
3048
|
+
|
|
3049
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3050
|
+
sage: X.<x,y> = M.chart()
|
|
3051
|
+
sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
|
|
3052
|
+
sage: f._latex_()
|
|
3053
|
+
\left(x - y, x y, \cos\left(x\right) e^{y}\right)
|
|
3054
|
+
sage: latex(f)
|
|
3055
|
+
\left(x - y, x y, \cos\left(x\right) e^{y}\right)
|
|
3056
|
+
"""
|
|
3057
|
+
from sage.misc.latex import latex
|
|
3058
|
+
|
|
3059
|
+
return latex(self._functions)
|
|
3060
|
+
|
|
3061
|
+
def expr(self, method=None):
|
|
3062
|
+
r"""
|
|
3063
|
+
Return a tuple of data, the item no. `i` being sufficient to
|
|
3064
|
+
reconstruct the coordinate function no. `i`.
|
|
3065
|
+
|
|
3066
|
+
In other words, if ``f`` is a multi-coordinate function, then
|
|
3067
|
+
``f.chart().multifunction(*(f.expr()))`` results in a
|
|
3068
|
+
multi-coordinate function identical to ``f``.
|
|
3069
|
+
|
|
3070
|
+
INPUT:
|
|
3071
|
+
|
|
3072
|
+
- ``method`` -- string (default: ``None``); the calculus method which
|
|
3073
|
+
the returned expressions belong to. One of
|
|
3074
|
+
|
|
3075
|
+
- ``'SR'``: Sage's default symbolic engine (Symbolic Ring)
|
|
3076
|
+
- ``'sympy'``: SymPy
|
|
3077
|
+
- ``None``: the chart current calculus method is assumed
|
|
3078
|
+
|
|
3079
|
+
OUTPUT:
|
|
3080
|
+
|
|
3081
|
+
- a tuple of the symbolic expressions of the chart functions
|
|
3082
|
+
composing ``self``
|
|
3083
|
+
|
|
3084
|
+
EXAMPLES::
|
|
3085
|
+
|
|
3086
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3087
|
+
sage: X.<x,y> = M.chart()
|
|
3088
|
+
sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
|
|
3089
|
+
sage: f.expr()
|
|
3090
|
+
(x - y, x*y, cos(x)*e^y)
|
|
3091
|
+
sage: type(f.expr()[0])
|
|
3092
|
+
<class 'sage.symbolic.expression.Expression'>
|
|
3093
|
+
|
|
3094
|
+
A SymPy output::
|
|
3095
|
+
|
|
3096
|
+
sage: f.expr('sympy')
|
|
3097
|
+
(x - y, x*y, exp(y)*cos(x))
|
|
3098
|
+
sage: type(f.expr('sympy')[0])
|
|
3099
|
+
<class 'sympy.core.add.Add'>
|
|
3100
|
+
|
|
3101
|
+
One shall always have::
|
|
3102
|
+
|
|
3103
|
+
sage: f.chart().multifunction(*(f.expr())) == f
|
|
3104
|
+
True
|
|
3105
|
+
"""
|
|
3106
|
+
return tuple(func.expr(method=method) for func in self._functions)
|
|
3107
|
+
|
|
3108
|
+
def chart(self):
|
|
3109
|
+
r"""
|
|
3110
|
+
Return the chart with respect to which ``self`` is defined.
|
|
3111
|
+
|
|
3112
|
+
OUTPUT: a :class:`~sage.manifolds.chart.Chart`
|
|
3113
|
+
|
|
3114
|
+
EXAMPLES::
|
|
3115
|
+
|
|
3116
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3117
|
+
sage: X.<x,y> = M.chart()
|
|
3118
|
+
sage: f = X.multifunction(x-y, x*y, cos(x)*exp(y))
|
|
3119
|
+
sage: f.chart()
|
|
3120
|
+
Chart (M, (x, y))
|
|
3121
|
+
sage: f.chart() is X
|
|
3122
|
+
True
|
|
3123
|
+
"""
|
|
3124
|
+
return self._chart
|
|
3125
|
+
|
|
3126
|
+
def __eq__(self, other):
|
|
3127
|
+
r"""
|
|
3128
|
+
Comparison (equality) operator.
|
|
3129
|
+
|
|
3130
|
+
INPUT:
|
|
3131
|
+
|
|
3132
|
+
- ``other`` -- a :class:`MultiCoordFunction`
|
|
3133
|
+
|
|
3134
|
+
OUTPUT: ``True`` if ``self`` is equal to ``other``, ``False`` otherwise
|
|
3135
|
+
|
|
3136
|
+
TESTS::
|
|
3137
|
+
|
|
3138
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3139
|
+
sage: X.<x,y> = M.chart()
|
|
3140
|
+
sage: f = X.multifunction(x-y, x*y, cos(x*y))
|
|
3141
|
+
sage: f == X.multifunction(x-y, x*y)
|
|
3142
|
+
False
|
|
3143
|
+
sage: f == X.multifunction(x-y, x*y, 2)
|
|
3144
|
+
False
|
|
3145
|
+
sage: f == X.multifunction(x-y, x*y, cos(y*x))
|
|
3146
|
+
True
|
|
3147
|
+
sage: Y.<u,v> = M.chart()
|
|
3148
|
+
sage: f == Y.multifunction(u-v, u*v, cos(u*v))
|
|
3149
|
+
False
|
|
3150
|
+
"""
|
|
3151
|
+
if other is self:
|
|
3152
|
+
return True
|
|
3153
|
+
if not isinstance(other, MultiCoordFunction):
|
|
3154
|
+
return False
|
|
3155
|
+
if other._chart != self._chart:
|
|
3156
|
+
return False
|
|
3157
|
+
if other._nf != self._nf:
|
|
3158
|
+
return False
|
|
3159
|
+
return all(other._functions[i] == self._functions[i] for i in range(self._nf))
|
|
3160
|
+
|
|
3161
|
+
def __ne__(self, other):
|
|
3162
|
+
r"""
|
|
3163
|
+
Inequality operator.
|
|
3164
|
+
|
|
3165
|
+
INPUT:
|
|
3166
|
+
|
|
3167
|
+
- ``other`` -- a :class:`MultiCoordFunction`
|
|
3168
|
+
|
|
3169
|
+
OUTPUT:
|
|
3170
|
+
|
|
3171
|
+
- ``True`` if ``self`` is different from ``other``, ``False``
|
|
3172
|
+
otherwise
|
|
3173
|
+
|
|
3174
|
+
TESTS::
|
|
3175
|
+
|
|
3176
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3177
|
+
sage: X.<x,y> = M.chart()
|
|
3178
|
+
sage: f = X.multifunction(x-y, x*y, cos(x*y))
|
|
3179
|
+
sage: f != X.multifunction(x-y, x*y)
|
|
3180
|
+
True
|
|
3181
|
+
sage: f != X.multifunction(x, y, 2)
|
|
3182
|
+
True
|
|
3183
|
+
sage: f != X.multifunction(x-y, x*y, cos(x*y))
|
|
3184
|
+
False
|
|
3185
|
+
"""
|
|
3186
|
+
return not (self == other)
|
|
3187
|
+
|
|
3188
|
+
def __getitem__(self, index):
|
|
3189
|
+
r"""
|
|
3190
|
+
Return a specified function of the set represented by ``self``.
|
|
3191
|
+
|
|
3192
|
+
INPUT:
|
|
3193
|
+
|
|
3194
|
+
- ``index`` -- index `i` of the function (`0 \leq i \leq m-1`)
|
|
3195
|
+
|
|
3196
|
+
OUTPUT:
|
|
3197
|
+
|
|
3198
|
+
-- a :class:`ChartFunction` representing the function
|
|
3199
|
+
|
|
3200
|
+
TESTS::
|
|
3201
|
+
|
|
3202
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3203
|
+
sage: X.<x,y> = M.chart()
|
|
3204
|
+
sage: f = X.multifunction(x-y, x*y, cos(x*y))
|
|
3205
|
+
sage: f.__getitem__(0)
|
|
3206
|
+
x - y
|
|
3207
|
+
sage: f.__getitem__(1)
|
|
3208
|
+
x*y
|
|
3209
|
+
sage: f.__getitem__(2)
|
|
3210
|
+
cos(x*y)
|
|
3211
|
+
sage: f[0], f[1], f[2]
|
|
3212
|
+
(x - y, x*y, cos(x*y))
|
|
3213
|
+
"""
|
|
3214
|
+
return self._functions[index]
|
|
3215
|
+
|
|
3216
|
+
def __call__(self, *coords, **options):
|
|
3217
|
+
r"""
|
|
3218
|
+
Compute the values of the functions at specified coordinates.
|
|
3219
|
+
|
|
3220
|
+
INPUT:
|
|
3221
|
+
|
|
3222
|
+
- ``*coords`` -- list of coordinates where the functions are
|
|
3223
|
+
to be evaluated
|
|
3224
|
+
- ``**options`` -- allows to pass some options, e.g.,
|
|
3225
|
+
``simplify=False`` to disable simplification for symbolic
|
|
3226
|
+
coordinate functions
|
|
3227
|
+
|
|
3228
|
+
OUTPUT: tuple containing the values of the `m` functions
|
|
3229
|
+
|
|
3230
|
+
TESTS::
|
|
3231
|
+
|
|
3232
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3233
|
+
sage: X.<x,y> = M.chart()
|
|
3234
|
+
sage: f = X.multifunction(x-y, x*y, cos(x*y))
|
|
3235
|
+
sage: f.__call__(2,3)
|
|
3236
|
+
(-1, 6, cos(6))
|
|
3237
|
+
sage: f(2,3)
|
|
3238
|
+
(-1, 6, cos(6))
|
|
3239
|
+
sage: f.__call__(x,y)
|
|
3240
|
+
(x - y, x*y, cos(x*y))
|
|
3241
|
+
"""
|
|
3242
|
+
return tuple(func(*coords, **options) for func in self._functions)
|
|
3243
|
+
|
|
3244
|
+
@cached_method
|
|
3245
|
+
def jacobian(self):
|
|
3246
|
+
r"""
|
|
3247
|
+
Return the Jacobian matrix of the system of coordinate functions.
|
|
3248
|
+
|
|
3249
|
+
``jacobian()`` is a 2-dimensional array of size `m \times n`,
|
|
3250
|
+
where `m` is the number of functions and `n` the number of
|
|
3251
|
+
coordinates, the generic element being
|
|
3252
|
+
`J_{ij} = \frac{\partial f_i}{\partial x^j}` with `1 \leq i \leq m`
|
|
3253
|
+
(row index) and `1 \leq j \leq n` (column index).
|
|
3254
|
+
|
|
3255
|
+
OUTPUT:
|
|
3256
|
+
|
|
3257
|
+
- Jacobian matrix as a 2-dimensional array ``J`` of
|
|
3258
|
+
coordinate functions with ``J[i-1][j-1]`` being
|
|
3259
|
+
`J_{ij} = \frac{\partial f_i}{\partial x^j}`
|
|
3260
|
+
for `1 \leq i \leq m` and `1 \leq j \leq n`
|
|
3261
|
+
|
|
3262
|
+
EXAMPLES:
|
|
3263
|
+
|
|
3264
|
+
Jacobian of a set of 3 functions of 2 coordinates::
|
|
3265
|
+
|
|
3266
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3267
|
+
sage: X.<x,y> = M.chart()
|
|
3268
|
+
sage: f = X.multifunction(x-y, x*y, y^3*cos(x))
|
|
3269
|
+
sage: f.jacobian()
|
|
3270
|
+
[ 1 -1]
|
|
3271
|
+
[ y x]
|
|
3272
|
+
[ -y^3*sin(x) 3*y^2*cos(x)]
|
|
3273
|
+
|
|
3274
|
+
Each element of the result is a
|
|
3275
|
+
:class:`chart function <ChartFunction>`::
|
|
3276
|
+
|
|
3277
|
+
sage: type(f.jacobian()[2,0])
|
|
3278
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
3279
|
+
sage: f.jacobian()[2,0].display()
|
|
3280
|
+
(x, y) ↦ -y^3*sin(x)
|
|
3281
|
+
|
|
3282
|
+
Test of the computation::
|
|
3283
|
+
|
|
3284
|
+
sage: [[f.jacobian()[i,j] == f[i].diff(j) for j in range(2)] for i in range(3)]
|
|
3285
|
+
[[True, True], [True, True], [True, True]]
|
|
3286
|
+
|
|
3287
|
+
Test with ``start_index = 1``::
|
|
3288
|
+
|
|
3289
|
+
sage: M = Manifold(2, 'M', structure='topological', start_index=1)
|
|
3290
|
+
sage: X.<x,y> = M.chart()
|
|
3291
|
+
sage: f = X.multifunction(x-y, x*y, y^3*cos(x))
|
|
3292
|
+
sage: f.jacobian()
|
|
3293
|
+
[ 1 -1]
|
|
3294
|
+
[ y x]
|
|
3295
|
+
[ -y^3*sin(x) 3*y^2*cos(x)]
|
|
3296
|
+
sage: [[f.jacobian()[i,j] == f[i].diff(j+1) for j in range(2)] # note the j+1
|
|
3297
|
+
....: for i in range(3)]
|
|
3298
|
+
[[True, True], [True, True], [True, True]]
|
|
3299
|
+
"""
|
|
3300
|
+
from sage.matrix.constructor import matrix
|
|
3301
|
+
|
|
3302
|
+
mat = matrix(
|
|
3303
|
+
[[func.diff(coord) for coord in self._chart[:]] for func in self._functions]
|
|
3304
|
+
)
|
|
3305
|
+
mat.set_immutable()
|
|
3306
|
+
return mat
|
|
3307
|
+
|
|
3308
|
+
@cached_method
|
|
3309
|
+
def jacobian_det(self):
|
|
3310
|
+
r"""
|
|
3311
|
+
Return the Jacobian determinant of the system of functions.
|
|
3312
|
+
|
|
3313
|
+
The number `m` of coordinate functions must equal the number `n`
|
|
3314
|
+
of coordinates.
|
|
3315
|
+
|
|
3316
|
+
OUTPUT: a :class:`ChartFunction` representing the determinant
|
|
3317
|
+
|
|
3318
|
+
EXAMPLES:
|
|
3319
|
+
|
|
3320
|
+
Jacobian determinant of a set of 2 functions of 2 coordinates::
|
|
3321
|
+
|
|
3322
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
3323
|
+
sage: X.<x,y> = M.chart()
|
|
3324
|
+
sage: f = X.multifunction(x-y, x*y)
|
|
3325
|
+
sage: f.jacobian_det()
|
|
3326
|
+
x + y
|
|
3327
|
+
|
|
3328
|
+
The output of :meth:`jacobian_det` is an instance of
|
|
3329
|
+
:class:`ChartFunction` and can therefore be called on specific
|
|
3330
|
+
values of the coordinates, e.g. `(x,y) = (1,2)`::
|
|
3331
|
+
|
|
3332
|
+
sage: type(f.jacobian_det())
|
|
3333
|
+
<class 'sage.manifolds.chart_func.ChartFunctionRing_with_category.element_class'>
|
|
3334
|
+
sage: f.jacobian_det().display()
|
|
3335
|
+
(x, y) ↦ x + y
|
|
3336
|
+
sage: f.jacobian_det()(1,2)
|
|
3337
|
+
3
|
|
3338
|
+
|
|
3339
|
+
The result is cached::
|
|
3340
|
+
|
|
3341
|
+
sage: f.jacobian_det() is f.jacobian_det()
|
|
3342
|
+
True
|
|
3343
|
+
|
|
3344
|
+
We verify the determinant of the Jacobian::
|
|
3345
|
+
|
|
3346
|
+
sage: f.jacobian_det() == det(matrix([[f[i].diff(j).expr() for j in range(2)]
|
|
3347
|
+
....: for i in range(2)]))
|
|
3348
|
+
True
|
|
3349
|
+
|
|
3350
|
+
An example using SymPy::
|
|
3351
|
+
|
|
3352
|
+
sage: M.set_calculus_method('sympy')
|
|
3353
|
+
sage: g = X.multifunction(x*y^3, e^x)
|
|
3354
|
+
sage: g.jacobian_det()
|
|
3355
|
+
-3*x*y**2*exp(x)
|
|
3356
|
+
sage: type(g.jacobian_det().expr())
|
|
3357
|
+
<class 'sympy.core.mul.Mul'>
|
|
3358
|
+
|
|
3359
|
+
Jacobian determinant of a set of 3 functions of 3 coordinates::
|
|
3360
|
+
|
|
3361
|
+
sage: M = Manifold(3, 'M', structure='topological')
|
|
3362
|
+
sage: X.<x,y,z> = M.chart()
|
|
3363
|
+
sage: f = X.multifunction(x*y+z^2, z^2*x+y^2*z, (x*y*z)^3)
|
|
3364
|
+
sage: f.jacobian_det().display()
|
|
3365
|
+
(x, y, z) ↦ 6*x^3*y^5*z^3 - 3*x^4*y^3*z^4 - 12*x^2*y^4*z^5 + 6*x^3*y^2*z^6
|
|
3366
|
+
|
|
3367
|
+
We verify the determinant of the Jacobian::
|
|
3368
|
+
|
|
3369
|
+
sage: f.jacobian_det() == det(matrix([[f[i].diff(j).expr() for j in range(3)]
|
|
3370
|
+
....: for i in range(3)]))
|
|
3371
|
+
True
|
|
3372
|
+
"""
|
|
3373
|
+
from sage.matrix.constructor import matrix
|
|
3374
|
+
|
|
3375
|
+
if self._nf != self._nc:
|
|
3376
|
+
raise ValueError("the Jacobian matrix is not a square matrix")
|
|
3377
|
+
mat = self.jacobian()
|
|
3378
|
+
# TODO: do the computation without the 'SR' enforcement
|
|
3379
|
+
mat_expr = matrix(
|
|
3380
|
+
[
|
|
3381
|
+
[mat[i, j].expr(method='SR') for i in range(self._nc)]
|
|
3382
|
+
for j in range(self._nc)
|
|
3383
|
+
]
|
|
3384
|
+
)
|
|
3385
|
+
det = mat_expr.det() # the unsimplified determinant
|
|
3386
|
+
func = self._functions[0]
|
|
3387
|
+
return type(func)(
|
|
3388
|
+
func.parent(),
|
|
3389
|
+
func._calc_method.simplify(det, method='SR'),
|
|
3390
|
+
calc_method=self._chart._calc_method._current,
|
|
3391
|
+
)
|
|
3392
|
+
|
|
3393
|
+
def set_immutable(self):
|
|
3394
|
+
r"""
|
|
3395
|
+
Set ``self`` and all chart functions of ``self`` immutable.
|
|
3396
|
+
|
|
3397
|
+
EXAMPLES:
|
|
3398
|
+
|
|
3399
|
+
Declare a coordinate function immutable::
|
|
3400
|
+
|
|
3401
|
+
sage: M = Manifold(3, 'M', structure='topological')
|
|
3402
|
+
sage: X.<x,y,z> = M.chart()
|
|
3403
|
+
sage: f = X.multifunction(x+y+z, x*y*z)
|
|
3404
|
+
sage: f.is_immutable()
|
|
3405
|
+
False
|
|
3406
|
+
sage: f.set_immutable()
|
|
3407
|
+
sage: f.is_immutable()
|
|
3408
|
+
True
|
|
3409
|
+
|
|
3410
|
+
The chart functions are now immutable, too::
|
|
3411
|
+
|
|
3412
|
+
sage: f[0].parent()
|
|
3413
|
+
Ring of chart functions on Chart (M, (x, y, z))
|
|
3414
|
+
sage: f[0].is_immutable()
|
|
3415
|
+
True
|
|
3416
|
+
"""
|
|
3417
|
+
for func in self._functions:
|
|
3418
|
+
func.set_immutable()
|
|
3419
|
+
Mutability.set_immutable(self)
|