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,1348 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Utilities for Calculus
|
|
4
|
+
|
|
5
|
+
This module defines helper functions which are used for simplifications
|
|
6
|
+
and display of symbolic expressions.
|
|
7
|
+
|
|
8
|
+
AUTHORS:
|
|
9
|
+
|
|
10
|
+
- Michal Bejger (2015) : class :class:`ExpressionNice`
|
|
11
|
+
- Eric Gourgoulhon (2015, 2017) : simplification functions
|
|
12
|
+
- Travis Scrimshaw (2016): review tweaks
|
|
13
|
+
- Marius Gerbershagen (2022) : skip simplification of expressions with a single
|
|
14
|
+
number or symbolic variable
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
# *****************************************************************************
|
|
18
|
+
#
|
|
19
|
+
# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
|
|
20
|
+
# Copyright (C) 2015, 2017 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
21
|
+
# Copyright (C) 2016 Travis Scrimshaw <tscrimsh@umn.edu>
|
|
22
|
+
#
|
|
23
|
+
# This program is free software: you can redistribute it and/or modify
|
|
24
|
+
# it under the terms of the GNU General Public License as published by
|
|
25
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
26
|
+
# (at your option) any later version.
|
|
27
|
+
# https://www.gnu.org/licenses/
|
|
28
|
+
# ****************************************************************************
|
|
29
|
+
|
|
30
|
+
from operator import pow as _pow
|
|
31
|
+
|
|
32
|
+
from sage.functions.other import abs_symbolic
|
|
33
|
+
from sage.functions.trig import cos, sin
|
|
34
|
+
from sage.misc.functional import sqrt
|
|
35
|
+
from sage.rings.rational import Rational
|
|
36
|
+
from sage.symbolic.constants import pi
|
|
37
|
+
from sage.symbolic.expression import Expression
|
|
38
|
+
from sage.symbolic.expression_conversions import ExpressionTreeWalker
|
|
39
|
+
from sage.symbolic.ring import SR
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class SimplifySqrtReal(ExpressionTreeWalker):
|
|
43
|
+
r"""
|
|
44
|
+
Class for simplifying square roots in the real domain, by walking the
|
|
45
|
+
expression tree.
|
|
46
|
+
|
|
47
|
+
The end user interface is the function :func:`simplify_sqrt_real`.
|
|
48
|
+
|
|
49
|
+
INPUT:
|
|
50
|
+
|
|
51
|
+
- ``ex`` -- a symbolic expression
|
|
52
|
+
|
|
53
|
+
EXAMPLES:
|
|
54
|
+
|
|
55
|
+
Let us consider the square root of an exact square under some assumption::
|
|
56
|
+
|
|
57
|
+
sage: assume(x<1)
|
|
58
|
+
sage: a = sqrt(x^2-2*x+1)
|
|
59
|
+
|
|
60
|
+
The method :meth:`~sage.symbolic.expression.Expression.simplify_full()`
|
|
61
|
+
is ineffective on such an expression::
|
|
62
|
+
|
|
63
|
+
sage: a.simplify_full()
|
|
64
|
+
sqrt(x^2 - 2*x + 1)
|
|
65
|
+
|
|
66
|
+
and the more aggressive method :meth:`~sage.symbolic.expression.Expression.canonicalize_radical()`
|
|
67
|
+
yields a wrong result, given that `x<1`::
|
|
68
|
+
|
|
69
|
+
sage: a.canonicalize_radical() # wrong output!
|
|
70
|
+
x - 1
|
|
71
|
+
|
|
72
|
+
We construct a :class:`SimplifySqrtReal` object ``s`` from the symbolic
|
|
73
|
+
expression ``a``::
|
|
74
|
+
|
|
75
|
+
sage: from sage.manifolds.utilities import SimplifySqrtReal
|
|
76
|
+
sage: s = SimplifySqrtReal(a)
|
|
77
|
+
|
|
78
|
+
We use the ``__call__`` method to walk the expression tree and produce a
|
|
79
|
+
correctly simplified expression::
|
|
80
|
+
|
|
81
|
+
sage: s()
|
|
82
|
+
-x + 1
|
|
83
|
+
|
|
84
|
+
Calling the simplifier ``s`` with an expression actually simplifies this
|
|
85
|
+
expression::
|
|
86
|
+
|
|
87
|
+
sage: s(a) # same as s() since s is built from a
|
|
88
|
+
-x + 1
|
|
89
|
+
sage: s(sqrt(x^2))
|
|
90
|
+
abs(x)
|
|
91
|
+
sage: s(sqrt(1+sqrt(x^2-2*x+1))) # nested sqrt's
|
|
92
|
+
sqrt(-x + 2)
|
|
93
|
+
|
|
94
|
+
Another example where both
|
|
95
|
+
:meth:`~sage.symbolic.expression.Expression.simplify_full()` and
|
|
96
|
+
:meth:`~sage.symbolic.expression.Expression.canonicalize_radical()`
|
|
97
|
+
fail::
|
|
98
|
+
|
|
99
|
+
sage: b = sqrt((x-1)/(x-2))*sqrt(1-x)
|
|
100
|
+
sage: b.simplify_full() # does not simplify
|
|
101
|
+
sqrt(-x + 1)*sqrt((x - 1)/(x - 2))
|
|
102
|
+
sage: b.canonicalize_radical() # wrong output, given that x<1
|
|
103
|
+
(I*x - I)/sqrt(x - 2)
|
|
104
|
+
sage: SimplifySqrtReal(b)() # OK, given that x<1
|
|
105
|
+
-(x - 1)/sqrt(-x + 2)
|
|
106
|
+
|
|
107
|
+
TESTS:
|
|
108
|
+
|
|
109
|
+
We check that the inverse of a square root is well simplified; this is a
|
|
110
|
+
a non-trivial test since ``1/sqrt(x)`` is represented by ``pow(x,-1/2)``
|
|
111
|
+
in the expression tree::
|
|
112
|
+
|
|
113
|
+
sage: SimplifySqrtReal(1/sqrt(x^2-4*x+4))()
|
|
114
|
+
-1/(x - 2)
|
|
115
|
+
sage: SimplifySqrtReal(sqrt((x-2)/((x-3)*(x^2-2*x+1))))()
|
|
116
|
+
-sqrt(-x + 2)/((x - 1)*sqrt(-x + 3))
|
|
117
|
+
sage: forget() # for doctests below
|
|
118
|
+
|
|
119
|
+
.. SEEALSO::
|
|
120
|
+
|
|
121
|
+
:func:`simplify_sqrt_real` for more examples with
|
|
122
|
+
:class:`SimplifySqrtReal` at work.
|
|
123
|
+
"""
|
|
124
|
+
def arithmetic(self, ex, operator):
|
|
125
|
+
r"""
|
|
126
|
+
This is the only method of the base class
|
|
127
|
+
:class:`~sage.symbolic.expression_conversions.ExpressionTreeWalker`
|
|
128
|
+
that is reimplemented, since square roots are considered as
|
|
129
|
+
arithmetic operations with ``operator`` = ``pow`` and
|
|
130
|
+
``ex.operands()[1]`` = ``1/2`` or ``-1/2``.
|
|
131
|
+
|
|
132
|
+
INPUT:
|
|
133
|
+
|
|
134
|
+
- ``ex`` -- a symbolic expression
|
|
135
|
+
- ``operator`` -- an arithmetic operator
|
|
136
|
+
|
|
137
|
+
OUTPUT:
|
|
138
|
+
|
|
139
|
+
- a symbolic expression, equivalent to ``ex`` with square roots
|
|
140
|
+
simplified
|
|
141
|
+
|
|
142
|
+
EXAMPLES::
|
|
143
|
+
|
|
144
|
+
sage: from sage.manifolds.utilities import SimplifySqrtReal
|
|
145
|
+
sage: a = sqrt(x^2+2*x+1)
|
|
146
|
+
sage: s = SimplifySqrtReal(a)
|
|
147
|
+
sage: a.operator()
|
|
148
|
+
<built-in function pow>
|
|
149
|
+
sage: s.arithmetic(a, a.operator())
|
|
150
|
+
abs(x + 1)
|
|
151
|
+
|
|
152
|
+
::
|
|
153
|
+
|
|
154
|
+
sage: a = x + 1 # no square root
|
|
155
|
+
sage: s.arithmetic(a, a.operator())
|
|
156
|
+
x + 1
|
|
157
|
+
|
|
158
|
+
::
|
|
159
|
+
|
|
160
|
+
sage: a = x + 1 + sqrt(function('f')(x)^2)
|
|
161
|
+
sage: s.arithmetic(a, a.operator())
|
|
162
|
+
x + abs(f(x)) + 1
|
|
163
|
+
"""
|
|
164
|
+
if operator is _pow:
|
|
165
|
+
operands = ex.operands()
|
|
166
|
+
power = operands[1]
|
|
167
|
+
one_half = Rational((1,2))
|
|
168
|
+
minus_one_half = -one_half
|
|
169
|
+
if (power == one_half) or (power == minus_one_half):
|
|
170
|
+
# This is a square root or the inverse of a square root
|
|
171
|
+
w0 = SR.wild(0)
|
|
172
|
+
w1 = SR.wild(1)
|
|
173
|
+
sqrt_pattern = w0**one_half
|
|
174
|
+
inv_sqrt_pattern = w0**minus_one_half
|
|
175
|
+
sqrt_ratio_pattern1 = w0**one_half * w1**minus_one_half
|
|
176
|
+
sqrt_ratio_pattern2 = w0**minus_one_half * w1**one_half
|
|
177
|
+
argum = operands[0] # the argument of sqrt
|
|
178
|
+
if argum.has(sqrt_pattern) or argum.has(inv_sqrt_pattern):
|
|
179
|
+
argum = self(argum) # treatment of nested sqrt's
|
|
180
|
+
den = argum.denominator()
|
|
181
|
+
if not (den == 1): # the argument of sqrt is a fraction
|
|
182
|
+
# NB: after #19312 (integrated in Sage 6.10.beta7), the
|
|
183
|
+
# above test cannot be written as "if den != 1:"
|
|
184
|
+
num = argum.numerator()
|
|
185
|
+
if num < 0 or den < 0:
|
|
186
|
+
ex = sqrt(-num) / sqrt(-den)
|
|
187
|
+
else:
|
|
188
|
+
ex = sqrt(argum)
|
|
189
|
+
else:
|
|
190
|
+
ex = sqrt(argum)
|
|
191
|
+
simpl = SR(ex._maxima_().radcan())
|
|
192
|
+
if (not simpl.match(sqrt_pattern) and
|
|
193
|
+
not simpl.match(inv_sqrt_pattern) and
|
|
194
|
+
not simpl.match(sqrt_ratio_pattern1) and
|
|
195
|
+
not simpl.match(sqrt_ratio_pattern2)):
|
|
196
|
+
# radcan transformed substantially the expression,
|
|
197
|
+
# possibly getting rid of some sqrt; in order to ensure a
|
|
198
|
+
# positive result, the absolute value of radcan's output
|
|
199
|
+
# is taken, the call to simplify() taking care of possible
|
|
200
|
+
# assumptions regarding signs of subexpression of simpl:
|
|
201
|
+
simpl = abs(simpl).simplify()
|
|
202
|
+
if power == minus_one_half:
|
|
203
|
+
simpl = SR(1)/simpl
|
|
204
|
+
return simpl
|
|
205
|
+
# If operator is not a square root, we default to ExpressionTreeWalker:
|
|
206
|
+
return super().arithmetic(ex, operator)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class SimplifyAbsTrig(ExpressionTreeWalker):
|
|
210
|
+
r"""
|
|
211
|
+
Class for simplifying absolute values of cosines or sines (in the real
|
|
212
|
+
domain), by walking the expression tree.
|
|
213
|
+
|
|
214
|
+
The end user interface is the function :func:`simplify_abs_trig`.
|
|
215
|
+
|
|
216
|
+
INPUT:
|
|
217
|
+
|
|
218
|
+
- ``ex`` -- a symbolic expression
|
|
219
|
+
|
|
220
|
+
EXAMPLES:
|
|
221
|
+
|
|
222
|
+
Let us consider the following symbolic expression with some assumption
|
|
223
|
+
on the range of the variable `x`::
|
|
224
|
+
|
|
225
|
+
sage: assume(pi/2<x, x<pi)
|
|
226
|
+
sage: a = abs(cos(x)) + abs(sin(x))
|
|
227
|
+
|
|
228
|
+
The method :meth:`~sage.symbolic.expression.Expression.simplify_full()`
|
|
229
|
+
is ineffective on such an expression::
|
|
230
|
+
|
|
231
|
+
sage: a.simplify_full()
|
|
232
|
+
abs(cos(x)) + abs(sin(x))
|
|
233
|
+
|
|
234
|
+
We construct a :class:`SimplifyAbsTrig` object ``s`` from the symbolic
|
|
235
|
+
expression ``a``::
|
|
236
|
+
|
|
237
|
+
sage: from sage.manifolds.utilities import SimplifyAbsTrig
|
|
238
|
+
sage: s = SimplifyAbsTrig(a)
|
|
239
|
+
|
|
240
|
+
We use the ``__call__`` method to walk the expression tree and produce a
|
|
241
|
+
correctly simplified expression, given that `x\in(\pi/2, \pi)`::
|
|
242
|
+
|
|
243
|
+
sage: s()
|
|
244
|
+
-cos(x) + sin(x)
|
|
245
|
+
|
|
246
|
+
Calling the simplifier ``s`` with an expression actually simplifies this
|
|
247
|
+
expression::
|
|
248
|
+
|
|
249
|
+
sage: s(a) # same as s() since s is built from a
|
|
250
|
+
-cos(x) + sin(x)
|
|
251
|
+
sage: s(abs(cos(x/2)) + abs(sin(x/2))) # pi/4 < x/2 < pi/2
|
|
252
|
+
cos(1/2*x) + sin(1/2*x)
|
|
253
|
+
sage: s(abs(cos(2*x)) + abs(sin(2*x))) # pi < 2 x < 2*pi
|
|
254
|
+
abs(cos(2*x)) - sin(2*x)
|
|
255
|
+
sage: s(abs(sin(2+abs(cos(x))))) # nested abs(sin_or_cos(...))
|
|
256
|
+
sin(-cos(x) + 2)
|
|
257
|
+
|
|
258
|
+
TESTS::
|
|
259
|
+
|
|
260
|
+
sage: forget() # for doctests below
|
|
261
|
+
|
|
262
|
+
.. SEEALSO::
|
|
263
|
+
|
|
264
|
+
:func:`simplify_abs_trig` for more examples with
|
|
265
|
+
:class:`SimplifyAbsTrig` at work.
|
|
266
|
+
"""
|
|
267
|
+
def composition(self, ex, operator):
|
|
268
|
+
r"""
|
|
269
|
+
This is the only method of the base class
|
|
270
|
+
:class:`~sage.symbolic.expression_conversions.ExpressionTreeWalker`
|
|
271
|
+
that is reimplemented, since it manages the composition of
|
|
272
|
+
``abs`` with ``cos`` or ``sin``.
|
|
273
|
+
|
|
274
|
+
INPUT:
|
|
275
|
+
|
|
276
|
+
- ``ex`` -- a symbolic expression
|
|
277
|
+
- ``operator`` -- an operator
|
|
278
|
+
|
|
279
|
+
OUTPUT:
|
|
280
|
+
|
|
281
|
+
- a symbolic expression, equivalent to ``ex`` with ``abs(cos(...))``
|
|
282
|
+
and ``abs(sin(...))`` simplified, according to the range of their
|
|
283
|
+
argument.
|
|
284
|
+
|
|
285
|
+
EXAMPLES::
|
|
286
|
+
|
|
287
|
+
sage: from sage.manifolds.utilities import SimplifyAbsTrig
|
|
288
|
+
sage: assume(-pi/2 < x, x<0)
|
|
289
|
+
sage: a = abs(sin(x))
|
|
290
|
+
sage: s = SimplifyAbsTrig(a)
|
|
291
|
+
sage: a.operator()
|
|
292
|
+
abs
|
|
293
|
+
sage: s.composition(a, a.operator())
|
|
294
|
+
sin(-x)
|
|
295
|
+
|
|
296
|
+
::
|
|
297
|
+
|
|
298
|
+
sage: a = exp(function('f')(x)) # no abs(sin_or_cos(...))
|
|
299
|
+
sage: a.operator()
|
|
300
|
+
exp
|
|
301
|
+
sage: s.composition(a, a.operator())
|
|
302
|
+
e^f(x)
|
|
303
|
+
|
|
304
|
+
::
|
|
305
|
+
|
|
306
|
+
sage: forget() # no longer any assumption on x
|
|
307
|
+
sage: a = abs(cos(sin(x))) # simplifiable since -1 <= sin(x) <= 1
|
|
308
|
+
sage: s.composition(a, a.operator())
|
|
309
|
+
cos(sin(x))
|
|
310
|
+
sage: a = abs(sin(cos(x))) # not simplifiable
|
|
311
|
+
sage: s.composition(a, a.operator())
|
|
312
|
+
abs(sin(cos(x)))
|
|
313
|
+
"""
|
|
314
|
+
if operator is abs_symbolic:
|
|
315
|
+
argum = ex.operands()[0] # argument of abs
|
|
316
|
+
if argum.operator() is sin:
|
|
317
|
+
# Case of abs(sin(...))
|
|
318
|
+
x = argum.operands()[0] # argument of sin
|
|
319
|
+
w0 = SR.wild()
|
|
320
|
+
if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic(cos(w0))):
|
|
321
|
+
x = self(x) # treatment of nested abs(sin_or_cos(...))
|
|
322
|
+
# Simplifications for values of x in the range [-pi, 2*pi]:
|
|
323
|
+
if x >= 0 and x <= pi:
|
|
324
|
+
ex = sin(x)
|
|
325
|
+
elif (x > pi and x <= 2*pi) or (x >= -pi and x < 0):
|
|
326
|
+
ex = -sin(x)
|
|
327
|
+
return ex
|
|
328
|
+
if argum.operator() is cos:
|
|
329
|
+
# Case of abs(cos(...))
|
|
330
|
+
x = argum.operands()[0] # argument of cos
|
|
331
|
+
w0 = SR.wild()
|
|
332
|
+
if x.has(abs_symbolic(sin(w0))) or x.has(abs_symbolic(cos(w0))):
|
|
333
|
+
x = self(x) # treatment of nested abs(sin_or_cos(...))
|
|
334
|
+
# Simplifications for values of x in the range [-pi, 2*pi]:
|
|
335
|
+
if (x >= -pi/2 and x <= pi/2) or (x >= 3*pi/2 and x <= 2*pi):
|
|
336
|
+
ex = cos(x)
|
|
337
|
+
elif (x > pi/2 and x <= 3*pi/2) or (x >= -pi and x < -pi/2):
|
|
338
|
+
ex = -cos(x)
|
|
339
|
+
return ex
|
|
340
|
+
# If no pattern is found, we default to ExpressionTreeWalker:
|
|
341
|
+
return super().composition(ex, operator)
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def simplify_sqrt_real(expr):
|
|
345
|
+
r"""
|
|
346
|
+
Simplify ``sqrt`` in symbolic expressions in the real domain.
|
|
347
|
+
|
|
348
|
+
EXAMPLES:
|
|
349
|
+
|
|
350
|
+
Simplifications of basic expressions::
|
|
351
|
+
|
|
352
|
+
sage: from sage.manifolds.utilities import simplify_sqrt_real
|
|
353
|
+
sage: simplify_sqrt_real( sqrt(x^2) )
|
|
354
|
+
abs(x)
|
|
355
|
+
sage: assume(x<0)
|
|
356
|
+
sage: simplify_sqrt_real( sqrt(x^2) )
|
|
357
|
+
-x
|
|
358
|
+
sage: simplify_sqrt_real( sqrt(x^2-2*x+1) )
|
|
359
|
+
-x + 1
|
|
360
|
+
sage: simplify_sqrt_real( sqrt(x^2) + sqrt(x^2-2*x+1) )
|
|
361
|
+
-2*x + 1
|
|
362
|
+
|
|
363
|
+
This improves over
|
|
364
|
+
:meth:`~sage.symbolic.expression.Expression.canonicalize_radical`,
|
|
365
|
+
which yields incorrect results when ``x < 0``::
|
|
366
|
+
|
|
367
|
+
sage: forget() # removes the assumption x<0
|
|
368
|
+
sage: sqrt(x^2).canonicalize_radical()
|
|
369
|
+
x
|
|
370
|
+
sage: assume(x<0)
|
|
371
|
+
sage: sqrt(x^2).canonicalize_radical()
|
|
372
|
+
-x
|
|
373
|
+
sage: sqrt(x^2-2*x+1).canonicalize_radical() # wrong output
|
|
374
|
+
x - 1
|
|
375
|
+
sage: ( sqrt(x^2) + sqrt(x^2-2*x+1) ).canonicalize_radical() # wrong output
|
|
376
|
+
-1
|
|
377
|
+
|
|
378
|
+
Simplification of nested ``sqrt``'s::
|
|
379
|
+
|
|
380
|
+
sage: forget() # removes the assumption x<0
|
|
381
|
+
sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) )
|
|
382
|
+
sqrt(abs(x) + 1)
|
|
383
|
+
sage: assume(x<0)
|
|
384
|
+
sage: simplify_sqrt_real( sqrt(1 + sqrt(x^2)) )
|
|
385
|
+
sqrt(-x + 1)
|
|
386
|
+
sage: simplify_sqrt_real( sqrt(x^2 + sqrt(4*x^2) + 1) )
|
|
387
|
+
-x + 1
|
|
388
|
+
|
|
389
|
+
Again, :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`
|
|
390
|
+
fails on the last one::
|
|
391
|
+
|
|
392
|
+
sage: (sqrt(x^2 + sqrt(4*x^2) + 1)).canonicalize_radical()
|
|
393
|
+
x - 1
|
|
394
|
+
|
|
395
|
+
TESTS:
|
|
396
|
+
|
|
397
|
+
Simplification of expressions involving some symbolic derivatives::
|
|
398
|
+
|
|
399
|
+
sage: f = function('f')
|
|
400
|
+
sage: simplify_sqrt_real( diff(f(x), x)/sqrt(x^2-2*x+1) ) # x<0 => x-1<0
|
|
401
|
+
-diff(f(x), x)/(x - 1)
|
|
402
|
+
sage: g = function('g')
|
|
403
|
+
sage: simplify_sqrt_real( sqrt(x^3*diff(f(g(x)), x)^2) ) # x<0
|
|
404
|
+
(-x)^(3/2)*abs(D[0](f)(g(x)))*abs(diff(g(x), x))
|
|
405
|
+
sage: forget() # for doctests below
|
|
406
|
+
"""
|
|
407
|
+
w0 = SR.wild()
|
|
408
|
+
one_half = Rational((1,2))
|
|
409
|
+
if expr.has(w0**one_half) or expr.has(w0**(-one_half)):
|
|
410
|
+
return SimplifySqrtReal(expr)()
|
|
411
|
+
return expr
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
def simplify_abs_trig(expr):
|
|
415
|
+
r"""
|
|
416
|
+
Simplify ``abs(sin(...))`` and ``abs(cos(...))`` in symbolic expressions.
|
|
417
|
+
|
|
418
|
+
EXAMPLES::
|
|
419
|
+
|
|
420
|
+
sage: M = Manifold(3, 'M', structure='topological')
|
|
421
|
+
sage: X.<x,y,z> = M.chart(r'x y:(0,pi) z:(-pi/3,0)')
|
|
422
|
+
sage: X.coord_range()
|
|
423
|
+
x: (-oo, +oo); y: (0, pi); z: (-1/3*pi, 0)
|
|
424
|
+
|
|
425
|
+
Since `x` spans all `\RR`, no simplification of ``abs(sin(x))``
|
|
426
|
+
occurs, while ``abs(sin(y))`` and ``abs(sin(3*z))`` are correctly
|
|
427
|
+
simplified, given that `y \in (0,\pi)` and `z \in (-\pi/3,0)`::
|
|
428
|
+
|
|
429
|
+
sage: from sage.manifolds.utilities import simplify_abs_trig
|
|
430
|
+
sage: simplify_abs_trig( abs(sin(x)) + abs(sin(y)) + abs(sin(3*z)) )
|
|
431
|
+
abs(sin(x)) + sin(y) + sin(-3*z)
|
|
432
|
+
|
|
433
|
+
Note that neither
|
|
434
|
+
:meth:`~sage.symbolic.expression.Expression.simplify_trig` nor
|
|
435
|
+
:meth:`~sage.symbolic.expression.Expression.simplify_full`
|
|
436
|
+
works in this case::
|
|
437
|
+
|
|
438
|
+
sage: s = abs(sin(x)) + abs(sin(y)) + abs(sin(3*z))
|
|
439
|
+
sage: s.simplify_trig()
|
|
440
|
+
abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))
|
|
441
|
+
sage: s.simplify_full()
|
|
442
|
+
abs(4*cos(-z)^2 - 1)*abs(sin(-z)) + abs(sin(x)) + abs(sin(y))
|
|
443
|
+
|
|
444
|
+
despite the following assumptions hold::
|
|
445
|
+
|
|
446
|
+
sage: assumptions()
|
|
447
|
+
[x is real, y is real, y > 0, y < pi, z is real, z > -1/3*pi, z < 0]
|
|
448
|
+
|
|
449
|
+
Additional checks are::
|
|
450
|
+
|
|
451
|
+
sage: simplify_abs_trig( abs(sin(y/2)) ) # shall simplify
|
|
452
|
+
sin(1/2*y)
|
|
453
|
+
sage: simplify_abs_trig( abs(sin(2*y)) ) # must not simplify
|
|
454
|
+
abs(sin(2*y))
|
|
455
|
+
sage: simplify_abs_trig( abs(sin(z/2)) ) # shall simplify
|
|
456
|
+
sin(-1/2*z)
|
|
457
|
+
sage: simplify_abs_trig( abs(sin(4*z)) ) # must not simplify
|
|
458
|
+
abs(sin(-4*z))
|
|
459
|
+
|
|
460
|
+
Simplification of ``abs(cos(...))``::
|
|
461
|
+
|
|
462
|
+
sage: forget()
|
|
463
|
+
sage: M = Manifold(3, 'M', structure='topological')
|
|
464
|
+
sage: X.<x,y,z> = M.chart(r'x y:(0,pi/2) z:(pi/4,3*pi/4)')
|
|
465
|
+
sage: X.coord_range()
|
|
466
|
+
x: (-oo, +oo); y: (0, 1/2*pi); z: (1/4*pi, 3/4*pi)
|
|
467
|
+
sage: simplify_abs_trig( abs(cos(x)) + abs(cos(y)) + abs(cos(2*z)) )
|
|
468
|
+
abs(cos(x)) + cos(y) - cos(2*z)
|
|
469
|
+
|
|
470
|
+
Additional tests::
|
|
471
|
+
|
|
472
|
+
sage: simplify_abs_trig(abs(cos(y-pi/2))) # shall simplify
|
|
473
|
+
cos(-1/2*pi + y)
|
|
474
|
+
sage: simplify_abs_trig(abs(cos(y+pi/2))) # shall simplify
|
|
475
|
+
-cos(1/2*pi + y)
|
|
476
|
+
sage: simplify_abs_trig(abs(cos(y-pi))) # shall simplify
|
|
477
|
+
-cos(-pi + y)
|
|
478
|
+
sage: simplify_abs_trig(abs(cos(2*y))) # must not simplify
|
|
479
|
+
abs(cos(2*y))
|
|
480
|
+
sage: simplify_abs_trig(abs(cos(y/2)) * abs(sin(z))) # shall simplify
|
|
481
|
+
cos(1/2*y)*sin(z)
|
|
482
|
+
|
|
483
|
+
TESTS:
|
|
484
|
+
|
|
485
|
+
Simplification of expressions involving some symbolic derivatives::
|
|
486
|
+
|
|
487
|
+
sage: f = function('f')
|
|
488
|
+
sage: s = abs(cos(x)) + abs(cos(y))*diff(f(x),x) + abs(cos(2*z))
|
|
489
|
+
sage: simplify_abs_trig(s)
|
|
490
|
+
cos(y)*diff(f(x), x) + abs(cos(x)) - cos(2*z)
|
|
491
|
+
sage: s = abs(sin(x))*diff(f(x),x).subs(x=y^2) + abs(cos(y))
|
|
492
|
+
sage: simplify_abs_trig(s)
|
|
493
|
+
abs(sin(x))*D[0](f)(y^2) + cos(y)
|
|
494
|
+
sage: forget() # for doctests below
|
|
495
|
+
"""
|
|
496
|
+
w0 = SR.wild()
|
|
497
|
+
if expr.has(abs_symbolic(sin(w0))) or expr.has(abs_symbolic(cos(w0))):
|
|
498
|
+
return SimplifyAbsTrig(expr)()
|
|
499
|
+
return expr
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def simplify_chain_real(expr):
|
|
503
|
+
r"""
|
|
504
|
+
Apply a chain of simplifications to a symbolic expression, assuming the
|
|
505
|
+
real domain.
|
|
506
|
+
|
|
507
|
+
This is the simplification chain used in calculus involving coordinate
|
|
508
|
+
functions on real manifolds, as implemented in
|
|
509
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`.
|
|
510
|
+
|
|
511
|
+
The chain is formed by the following functions, called
|
|
512
|
+
successively:
|
|
513
|
+
|
|
514
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_factorial`
|
|
515
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_trig`
|
|
516
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_rational`
|
|
517
|
+
#. :func:`simplify_sqrt_real`
|
|
518
|
+
#. :func:`simplify_abs_trig`
|
|
519
|
+
#. :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`
|
|
520
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_log`
|
|
521
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_rational`
|
|
522
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_trig`
|
|
523
|
+
|
|
524
|
+
EXAMPLES:
|
|
525
|
+
|
|
526
|
+
We consider variables that are coordinates of a chart on a real manifold::
|
|
527
|
+
|
|
528
|
+
sage: M = Manifold(2, 'M', structure='topological')
|
|
529
|
+
sage: X.<x,y> = M.chart('x:(0,1) y')
|
|
530
|
+
|
|
531
|
+
The following assumptions then hold::
|
|
532
|
+
|
|
533
|
+
sage: assumptions()
|
|
534
|
+
[x is real, x > 0, x < 1, y is real]
|
|
535
|
+
|
|
536
|
+
and we have::
|
|
537
|
+
|
|
538
|
+
sage: from sage.manifolds.utilities import simplify_chain_real
|
|
539
|
+
sage: s = sqrt(y^2)
|
|
540
|
+
sage: simplify_chain_real(s)
|
|
541
|
+
abs(y)
|
|
542
|
+
|
|
543
|
+
The above result is correct since ``y`` is real. It is obtained by
|
|
544
|
+
:meth:`~sage.symbolic.expression.Expression.simplify_real` as well::
|
|
545
|
+
|
|
546
|
+
sage: s.simplify_real()
|
|
547
|
+
abs(y)
|
|
548
|
+
sage: s.simplify_full()
|
|
549
|
+
abs(y)
|
|
550
|
+
|
|
551
|
+
Furthermore, we have::
|
|
552
|
+
|
|
553
|
+
sage: s = sqrt(x^2-2*x+1)
|
|
554
|
+
sage: simplify_chain_real(s)
|
|
555
|
+
-x + 1
|
|
556
|
+
|
|
557
|
+
which is correct since `x \in (0,1)`. On this example, neither
|
|
558
|
+
:meth:`~sage.symbolic.expression.Expression.simplify_real`
|
|
559
|
+
nor :meth:`~sage.symbolic.expression.Expression.simplify_full`,
|
|
560
|
+
nor :meth:`~sage.symbolic.expression.Expression.canonicalize_radical`
|
|
561
|
+
give satisfactory results::
|
|
562
|
+
|
|
563
|
+
sage: s.simplify_real() # unsimplified output
|
|
564
|
+
sqrt(x^2 - 2*x + 1)
|
|
565
|
+
sage: s.simplify_full() # unsimplified output
|
|
566
|
+
sqrt(x^2 - 2*x + 1)
|
|
567
|
+
sage: s.canonicalize_radical() # wrong output since x in (0,1)
|
|
568
|
+
x - 1
|
|
569
|
+
|
|
570
|
+
Other simplifications::
|
|
571
|
+
|
|
572
|
+
sage: s = abs(sin(pi*x))
|
|
573
|
+
sage: simplify_chain_real(s) # correct output since x in (0,1)
|
|
574
|
+
sin(pi*x)
|
|
575
|
+
sage: s.simplify_real() # unsimplified output
|
|
576
|
+
abs(sin(pi*x))
|
|
577
|
+
sage: s.simplify_full() # unsimplified output
|
|
578
|
+
abs(sin(pi*x))
|
|
579
|
+
|
|
580
|
+
::
|
|
581
|
+
|
|
582
|
+
sage: s = cos(y)^2 + sin(y)^2
|
|
583
|
+
sage: simplify_chain_real(s)
|
|
584
|
+
1
|
|
585
|
+
sage: s.simplify_real() # unsimplified output
|
|
586
|
+
cos(y)^2 + sin(y)^2
|
|
587
|
+
sage: s.simplify_full() # OK
|
|
588
|
+
1
|
|
589
|
+
|
|
590
|
+
TESTS::
|
|
591
|
+
|
|
592
|
+
sage: forget() # for doctests below
|
|
593
|
+
"""
|
|
594
|
+
if expr.number_of_operands() == 0:
|
|
595
|
+
return expr
|
|
596
|
+
expr = expr.simplify_factorial()
|
|
597
|
+
expr = expr.simplify_trig()
|
|
598
|
+
expr = expr.simplify_rational()
|
|
599
|
+
expr = simplify_sqrt_real(expr)
|
|
600
|
+
expr = simplify_abs_trig(expr)
|
|
601
|
+
expr = expr.canonicalize_radical()
|
|
602
|
+
expr = expr.simplify_log('one')
|
|
603
|
+
expr = expr.simplify_rational()
|
|
604
|
+
expr = expr.simplify_trig()
|
|
605
|
+
return expr
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def simplify_chain_generic(expr):
|
|
609
|
+
r"""
|
|
610
|
+
Apply a chain of simplifications to a symbolic expression.
|
|
611
|
+
|
|
612
|
+
This is the simplification chain used in calculus involving coordinate
|
|
613
|
+
functions on manifolds over fields different from `\RR`, as implemented in
|
|
614
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`.
|
|
615
|
+
|
|
616
|
+
The chain is formed by the following functions, called
|
|
617
|
+
successively:
|
|
618
|
+
|
|
619
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_factorial`
|
|
620
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_rectform`
|
|
621
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_trig`
|
|
622
|
+
#. :meth:`~sage.symbolic.expression.Expression.simplify_rational`
|
|
623
|
+
#. :meth:`~sage.symbolic.expression.Expression.expand_sum`
|
|
624
|
+
|
|
625
|
+
NB: for the time being, this is identical to
|
|
626
|
+
:meth:`~sage.symbolic.expression.Expression.simplify_full`.
|
|
627
|
+
|
|
628
|
+
EXAMPLES:
|
|
629
|
+
|
|
630
|
+
We consider variables that are coordinates of a chart on a complex
|
|
631
|
+
manifold::
|
|
632
|
+
|
|
633
|
+
sage: M = Manifold(2, 'M', structure='topological', field='complex')
|
|
634
|
+
sage: X.<x,y> = M.chart()
|
|
635
|
+
|
|
636
|
+
Then neither ``x`` nor ``y`` is assumed to be real::
|
|
637
|
+
|
|
638
|
+
sage: assumptions()
|
|
639
|
+
[]
|
|
640
|
+
|
|
641
|
+
Accordingly, ``simplify_chain_generic`` does not simplify
|
|
642
|
+
``sqrt(x^2)`` to ``abs(x)``::
|
|
643
|
+
|
|
644
|
+
sage: from sage.manifolds.utilities import simplify_chain_generic
|
|
645
|
+
sage: s = sqrt(x^2)
|
|
646
|
+
sage: simplify_chain_generic(s)
|
|
647
|
+
sqrt(x^2)
|
|
648
|
+
|
|
649
|
+
This contrasts with the behavior of
|
|
650
|
+
:func:`~sage.manifolds.utilities.simplify_chain_real`.
|
|
651
|
+
|
|
652
|
+
Other simplifications::
|
|
653
|
+
|
|
654
|
+
sage: s = (x+y)^2 - x^2 -2*x*y - y^2
|
|
655
|
+
sage: simplify_chain_generic(s)
|
|
656
|
+
0
|
|
657
|
+
sage: s = (x^2 - 2*x + 1) / (x^2 -1)
|
|
658
|
+
sage: simplify_chain_generic(s)
|
|
659
|
+
(x - 1)/(x + 1)
|
|
660
|
+
sage: s = cos(2*x) - 2*cos(x)^2 + 1
|
|
661
|
+
sage: simplify_chain_generic(s)
|
|
662
|
+
0
|
|
663
|
+
|
|
664
|
+
TESTS::
|
|
665
|
+
|
|
666
|
+
sage: forget() # for doctests below
|
|
667
|
+
"""
|
|
668
|
+
if expr.number_of_operands() == 0:
|
|
669
|
+
return expr
|
|
670
|
+
expr = expr.simplify_factorial()
|
|
671
|
+
expr = expr.simplify_rectform()
|
|
672
|
+
expr = expr.simplify_trig()
|
|
673
|
+
expr = expr.simplify_rational()
|
|
674
|
+
expr = expr.expand_sum()
|
|
675
|
+
return expr
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
def simplify_chain_generic_sympy(expr):
|
|
679
|
+
r"""
|
|
680
|
+
Apply a chain of simplifications to a sympy expression.
|
|
681
|
+
|
|
682
|
+
This is the simplification chain used in calculus involving coordinate
|
|
683
|
+
functions on manifolds over fields different from `\RR`, as implemented in
|
|
684
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`.
|
|
685
|
+
|
|
686
|
+
The chain is formed by the following functions, called
|
|
687
|
+
successively:
|
|
688
|
+
|
|
689
|
+
#. :meth:`~sympy.simplify.combsimp`
|
|
690
|
+
#. :meth:`~sympy.simplify.trigsimp`
|
|
691
|
+
#. :meth:`~sympy.core.expand`
|
|
692
|
+
#. :meth:`~sympy.simplify.simplify`
|
|
693
|
+
|
|
694
|
+
EXAMPLES:
|
|
695
|
+
|
|
696
|
+
We consider variables that are coordinates of a chart on a complex
|
|
697
|
+
manifold::
|
|
698
|
+
|
|
699
|
+
sage: forget() # for doctest only
|
|
700
|
+
sage: M = Manifold(2, 'M', structure='topological', field='complex', calc_method='sympy')
|
|
701
|
+
sage: X.<x,y> = M.chart()
|
|
702
|
+
|
|
703
|
+
Then neither ``x`` nor ``y`` is assumed to be real::
|
|
704
|
+
|
|
705
|
+
sage: assumptions()
|
|
706
|
+
[]
|
|
707
|
+
|
|
708
|
+
Accordingly, ``simplify_chain_generic_sympy`` does not simplify
|
|
709
|
+
``sqrt(x^2)`` to ``abs(x)``::
|
|
710
|
+
|
|
711
|
+
sage: from sage.manifolds.utilities import simplify_chain_generic_sympy
|
|
712
|
+
sage: s = (sqrt(x^2))._sympy_()
|
|
713
|
+
sage: simplify_chain_generic_sympy(s)
|
|
714
|
+
sqrt(x**2)
|
|
715
|
+
|
|
716
|
+
This contrasts with the behavior of
|
|
717
|
+
:func:`~sage.manifolds.utilities.simplify_chain_real_sympy`.
|
|
718
|
+
|
|
719
|
+
Other simplifications::
|
|
720
|
+
|
|
721
|
+
sage: s = ((x+y)^2 - x^2 -2*x*y - y^2)._sympy_()
|
|
722
|
+
sage: simplify_chain_generic_sympy(s)
|
|
723
|
+
0
|
|
724
|
+
sage: s = ((x^2 - 2*x + 1) / (x^2 -1))._sympy_()
|
|
725
|
+
sage: simplify_chain_generic_sympy(s)
|
|
726
|
+
(x - 1)/(x + 1)
|
|
727
|
+
sage: s = (cos(2*x) - 2*cos(x)^2 + 1)._sympy_()
|
|
728
|
+
sage: simplify_chain_generic_sympy(s)
|
|
729
|
+
0
|
|
730
|
+
"""
|
|
731
|
+
expr = expr.combsimp()
|
|
732
|
+
expr = expr.trigsimp()
|
|
733
|
+
expr = expr.expand()
|
|
734
|
+
expr = expr.simplify()
|
|
735
|
+
return expr
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
def simplify_chain_real_sympy(expr):
|
|
739
|
+
r"""
|
|
740
|
+
Apply a chain of simplifications to a sympy expression, assuming the
|
|
741
|
+
real domain.
|
|
742
|
+
|
|
743
|
+
This is the simplification chain used in calculus involving coordinate
|
|
744
|
+
functions on real manifolds, as implemented in
|
|
745
|
+
:class:`~sage.manifolds.chart_func.ChartFunction`.
|
|
746
|
+
|
|
747
|
+
The chain is formed by the following functions, called
|
|
748
|
+
successively:
|
|
749
|
+
|
|
750
|
+
#. :meth:`~sympy.simplify.combsimp`
|
|
751
|
+
#. :meth:`~sympy.simplify.trigsimp`
|
|
752
|
+
#. :func:`simplify_sqrt_real`
|
|
753
|
+
#. :func:`simplify_abs_trig`
|
|
754
|
+
#. :meth:`~sympy.core.expand`
|
|
755
|
+
#. :meth:`~sympy.simplify.simplify`
|
|
756
|
+
|
|
757
|
+
EXAMPLES:
|
|
758
|
+
|
|
759
|
+
We consider variables that are coordinates of a chart on a real manifold::
|
|
760
|
+
|
|
761
|
+
sage: forget() # for doctest only
|
|
762
|
+
sage: M = Manifold(2, 'M', structure='topological',calc_method='sympy')
|
|
763
|
+
sage: X.<x,y> = M.chart('x:(0,1) y')
|
|
764
|
+
|
|
765
|
+
The following assumptions then hold::
|
|
766
|
+
|
|
767
|
+
sage: assumptions()
|
|
768
|
+
[x is real, x > 0, x < 1, y is real]
|
|
769
|
+
|
|
770
|
+
and we have::
|
|
771
|
+
|
|
772
|
+
sage: from sage.manifolds.utilities import simplify_chain_real_sympy
|
|
773
|
+
sage: s = (sqrt(y^2))._sympy_()
|
|
774
|
+
sage: simplify_chain_real_sympy(s)
|
|
775
|
+
Abs(y)
|
|
776
|
+
|
|
777
|
+
Furthermore, we have::
|
|
778
|
+
|
|
779
|
+
sage: s = (sqrt(x^2-2*x+1))._sympy_()
|
|
780
|
+
sage: simplify_chain_real_sympy(s)
|
|
781
|
+
1 - x
|
|
782
|
+
|
|
783
|
+
Other simplifications::
|
|
784
|
+
|
|
785
|
+
sage: s = (abs(sin(pi*x)))._sympy_()
|
|
786
|
+
sage: simplify_chain_real_sympy(s) # correct output since x in (0,1)
|
|
787
|
+
sin(pi*x)
|
|
788
|
+
|
|
789
|
+
::
|
|
790
|
+
|
|
791
|
+
sage: s = (cos(y)^2 + sin(y)^2)._sympy_()
|
|
792
|
+
sage: simplify_chain_real_sympy(s)
|
|
793
|
+
1
|
|
794
|
+
"""
|
|
795
|
+
# TODO: introduce pure SymPy functions instead of simplify_sqrt_real and
|
|
796
|
+
# simplify_abs_trig
|
|
797
|
+
if 'sqrt(' in str(expr):
|
|
798
|
+
expr = simplify_sqrt_real(expr._sage_())._sympy_()
|
|
799
|
+
expr = expr.combsimp()
|
|
800
|
+
expr = expr.trigsimp()
|
|
801
|
+
if 'sqrt(' in str(expr):
|
|
802
|
+
expr = simplify_sqrt_real(expr._sage_())._sympy_()
|
|
803
|
+
if 'Abs(sin(' in str(expr):
|
|
804
|
+
expr = simplify_abs_trig(expr._sage_())._sympy_()
|
|
805
|
+
expr = expr.expand()
|
|
806
|
+
expr = expr.simplify()
|
|
807
|
+
return expr
|
|
808
|
+
|
|
809
|
+
#******************************************************************************
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
class ExpressionNice(Expression):
|
|
813
|
+
r"""
|
|
814
|
+
Subclass of :class:`~sage.symbolic.expression.Expression` for a
|
|
815
|
+
"human-friendly" display of partial derivatives and the possibility to
|
|
816
|
+
shorten the display by skipping the arguments of symbolic functions.
|
|
817
|
+
|
|
818
|
+
INPUT:
|
|
819
|
+
|
|
820
|
+
- ``ex`` -- symbolic expression
|
|
821
|
+
|
|
822
|
+
EXAMPLES:
|
|
823
|
+
|
|
824
|
+
An expression formed with callable symbolic expressions::
|
|
825
|
+
|
|
826
|
+
sage: var('x y z')
|
|
827
|
+
(x, y, z)
|
|
828
|
+
sage: f = function('f')(x, y)
|
|
829
|
+
sage: g = f.diff(y).diff(x)
|
|
830
|
+
sage: h = function('h')(y, z)
|
|
831
|
+
sage: k = h.diff(z)
|
|
832
|
+
sage: fun = x*g + y*(k-z)^2
|
|
833
|
+
|
|
834
|
+
The standard Pynac display of partial derivatives::
|
|
835
|
+
|
|
836
|
+
sage: fun
|
|
837
|
+
y*(z - diff(h(y, z), z))^2 + x*diff(f(x, y), x, y)
|
|
838
|
+
sage: latex(fun)
|
|
839
|
+
y {\left(z - \frac{\partial}{\partial z}h\left(y, z\right)\right)}^{2} + x \frac{\partial^{2}}{\partial x\partial y}f\left(x, y\right)
|
|
840
|
+
|
|
841
|
+
With :class:`ExpressionNice`, the Pynac notation ``D[...]`` is replaced
|
|
842
|
+
by textbook-like notation::
|
|
843
|
+
|
|
844
|
+
sage: from sage.manifolds.utilities import ExpressionNice
|
|
845
|
+
sage: ExpressionNice(fun)
|
|
846
|
+
y*(z - d(h)/dz)^2 + x*d^2(f)/dxdy
|
|
847
|
+
sage: latex(ExpressionNice(fun))
|
|
848
|
+
y {\left(z - \frac{\partial\,h}{\partial z}\right)}^{2}
|
|
849
|
+
+ x \frac{\partial^2\,f}{\partial x\partial y}
|
|
850
|
+
|
|
851
|
+
An example when function variables are themselves functions::
|
|
852
|
+
|
|
853
|
+
sage: f = function('f')(x, y)
|
|
854
|
+
sage: g = function('g')(x, f) # the second variable is the function f
|
|
855
|
+
sage: fun = (g.diff(x))*x - x^2*f.diff(x,y)
|
|
856
|
+
sage: fun
|
|
857
|
+
-x^2*diff(f(x, y), x, y) + (diff(f(x, y), x)*D[1](g)(x, f(x, y)) + D[0](g)(x, f(x, y)))*x
|
|
858
|
+
sage: ExpressionNice(fun)
|
|
859
|
+
-x^2*d^2(f)/dxdy + (d(f)/dx*d(g)/d(f(x, y)) + d(g)/dx)*x
|
|
860
|
+
sage: latex(ExpressionNice(fun))
|
|
861
|
+
-x^{2} \frac{\partial^2\,f}{\partial x\partial y}
|
|
862
|
+
+ {\left(\frac{\partial\,f}{\partial x}
|
|
863
|
+
\frac{\partial\,g}{\partial \left( f\left(x, y\right) \right)}
|
|
864
|
+
+ \frac{\partial\,g}{\partial x}\right)} x
|
|
865
|
+
|
|
866
|
+
Note that ``D[1](g)(x, f(x,y))`` is rendered as ``d(g)/d(f(x, y))``.
|
|
867
|
+
|
|
868
|
+
An example with multiple differentiations::
|
|
869
|
+
|
|
870
|
+
sage: fun = f.diff(x,x,y,y,x)*x
|
|
871
|
+
sage: fun
|
|
872
|
+
x*diff(f(x, y), x, x, x, y, y)
|
|
873
|
+
sage: ExpressionNice(fun)
|
|
874
|
+
x*d^5(f)/dx^3dy^2
|
|
875
|
+
sage: latex(ExpressionNice(fun))
|
|
876
|
+
x \frac{\partial^5\,f}{\partial x ^ 3\partial y ^ 2}
|
|
877
|
+
|
|
878
|
+
Parentheses are added around powers of partial derivatives to avoid any
|
|
879
|
+
confusion::
|
|
880
|
+
|
|
881
|
+
sage: fun = f.diff(y)^2
|
|
882
|
+
sage: fun
|
|
883
|
+
diff(f(x, y), y)^2
|
|
884
|
+
sage: ExpressionNice(fun)
|
|
885
|
+
(d(f)/dy)^2
|
|
886
|
+
sage: latex(ExpressionNice(fun))
|
|
887
|
+
\left(\frac{\partial\,f}{\partial y}\right)^{2}
|
|
888
|
+
|
|
889
|
+
The explicit mention of function arguments can be omitted for the sake of
|
|
890
|
+
brevity::
|
|
891
|
+
|
|
892
|
+
sage: fun = fun*f
|
|
893
|
+
sage: ExpressionNice(fun)
|
|
894
|
+
f(x, y)*(d(f)/dy)^2
|
|
895
|
+
sage: Manifold.options.omit_function_arguments=True
|
|
896
|
+
sage: ExpressionNice(fun)
|
|
897
|
+
f*(d(f)/dy)^2
|
|
898
|
+
sage: latex(ExpressionNice(fun))
|
|
899
|
+
f \left(\frac{\partial\,f}{\partial y}\right)^{2}
|
|
900
|
+
sage: Manifold.options._reset()
|
|
901
|
+
sage: ExpressionNice(fun)
|
|
902
|
+
f(x, y)*(d(f)/dy)^2
|
|
903
|
+
sage: latex(ExpressionNice(fun))
|
|
904
|
+
f\left(x, y\right) \left(\frac{\partial\,f}{\partial y}\right)^{2}
|
|
905
|
+
"""
|
|
906
|
+
def __init__(self, ex):
|
|
907
|
+
r"""
|
|
908
|
+
Initialize ``self``.
|
|
909
|
+
|
|
910
|
+
TESTS::
|
|
911
|
+
|
|
912
|
+
sage: f = function('f')(x)
|
|
913
|
+
sage: df = f.diff(x)
|
|
914
|
+
sage: df
|
|
915
|
+
diff(f(x), x)
|
|
916
|
+
sage: from sage.manifolds.utilities import ExpressionNice
|
|
917
|
+
sage: df_nice = ExpressionNice(df)
|
|
918
|
+
sage: df_nice
|
|
919
|
+
d(f)/dx
|
|
920
|
+
"""
|
|
921
|
+
from sage.symbolic.ring import SR
|
|
922
|
+
self._parent = SR
|
|
923
|
+
Expression.__init__(self, SR, x=ex)
|
|
924
|
+
|
|
925
|
+
def _repr_(self):
|
|
926
|
+
r"""
|
|
927
|
+
String representation of the object.
|
|
928
|
+
|
|
929
|
+
EXAMPLES::
|
|
930
|
+
|
|
931
|
+
sage: var('x y z')
|
|
932
|
+
(x, y, z)
|
|
933
|
+
sage: f = function('f')(x, y)
|
|
934
|
+
sage: g = f.diff(y).diff(x)
|
|
935
|
+
sage: h = function('h')(y, z)
|
|
936
|
+
sage: k = h.diff(z)
|
|
937
|
+
sage: fun = x*g + y*(k-z)^2
|
|
938
|
+
sage: fun
|
|
939
|
+
y*(z - diff(h(y, z), z))^2 + x*diff(f(x, y), x, y)
|
|
940
|
+
sage: from sage.manifolds.utilities import ExpressionNice
|
|
941
|
+
sage: ExpressionNice(fun)
|
|
942
|
+
y*(z - d(h)/dz)^2 + x*d^2(f)/dxdy
|
|
943
|
+
|
|
944
|
+
Check that :issue:`33399` is fixed::
|
|
945
|
+
|
|
946
|
+
sage: ExpressionNice(function('f')(x+y, x-y).diff(y))
|
|
947
|
+
d(f)/d(x + y) - d(f)/d(x - y)
|
|
948
|
+
"""
|
|
949
|
+
d = self._parent._repr_element_(self)
|
|
950
|
+
|
|
951
|
+
# find all occurrences of diff
|
|
952
|
+
list_d = []
|
|
953
|
+
_list_derivatives(self, list_d)
|
|
954
|
+
|
|
955
|
+
# process the list
|
|
956
|
+
for m in list_d:
|
|
957
|
+
funcname = m[1]
|
|
958
|
+
diffargs = m[3]
|
|
959
|
+
numargs = len(diffargs)
|
|
960
|
+
|
|
961
|
+
if numargs > 1:
|
|
962
|
+
numargs = "^" + str(numargs)
|
|
963
|
+
else:
|
|
964
|
+
numargs = ""
|
|
965
|
+
|
|
966
|
+
variables = m[4]
|
|
967
|
+
strv = [str(v) for v in variables]
|
|
968
|
+
|
|
969
|
+
# checking if the variable is composite
|
|
970
|
+
comp_chars = ['+', '-', '*', '/', '^', '(']
|
|
971
|
+
for i, sv in enumerate(strv):
|
|
972
|
+
if any(c in sv for c in comp_chars):
|
|
973
|
+
strv[i] = "(" + sv + ")"
|
|
974
|
+
|
|
975
|
+
# dictionary to group multiple occurrences of differentiation: d/dxdx -> d/dx^2 etc.
|
|
976
|
+
occ = {i: strv[i] + "^" + str(D) if (D := diffargs.count(i)) > 1
|
|
977
|
+
else strv[i] for i in diffargs}
|
|
978
|
+
|
|
979
|
+
res = f"d{numargs}({funcname})/d" + "d".join(occ.values())
|
|
980
|
+
|
|
981
|
+
# str representation of the operator
|
|
982
|
+
s = self._parent._repr_element_(m[0])
|
|
983
|
+
|
|
984
|
+
# if diff operator is raised to some power (m[5]), put brackets around
|
|
985
|
+
if m[5]:
|
|
986
|
+
res = "(" + res + ")^" + str(m[5])
|
|
987
|
+
o = s + "^" + str(m[5])
|
|
988
|
+
else:
|
|
989
|
+
o = s
|
|
990
|
+
|
|
991
|
+
d = d.replace(o, res)
|
|
992
|
+
|
|
993
|
+
import re
|
|
994
|
+
|
|
995
|
+
from sage.manifolds.manifold import TopologicalManifold
|
|
996
|
+
if TopologicalManifold.options.omit_function_arguments:
|
|
997
|
+
list_f = []
|
|
998
|
+
_list_functions(self, list_f)
|
|
999
|
+
|
|
1000
|
+
for m in list_f:
|
|
1001
|
+
d = re.sub(m[1] + r'\([^)]+\)', m[1], d)
|
|
1002
|
+
|
|
1003
|
+
return d
|
|
1004
|
+
|
|
1005
|
+
def _latex_(self):
|
|
1006
|
+
r"""
|
|
1007
|
+
LaTeX representation of the object.
|
|
1008
|
+
|
|
1009
|
+
EXAMPLES::
|
|
1010
|
+
|
|
1011
|
+
sage: var('x y z')
|
|
1012
|
+
(x, y, z)
|
|
1013
|
+
sage: f = function('f')(x, y)
|
|
1014
|
+
sage: g = f.diff(y).diff(x)
|
|
1015
|
+
sage: h = function('h')(y, z)
|
|
1016
|
+
sage: k = h.diff(z)
|
|
1017
|
+
sage: fun = x*g + y*(k-z)^2
|
|
1018
|
+
sage: fun
|
|
1019
|
+
y*(z - diff(h(y, z), z))^2 + x*diff(f(x, y), x, y)
|
|
1020
|
+
sage: from sage.manifolds.utilities import ExpressionNice
|
|
1021
|
+
sage: ExpressionNice(fun)
|
|
1022
|
+
y*(z - d(h)/dz)^2 + x*d^2(f)/dxdy
|
|
1023
|
+
sage: latex(ExpressionNice(fun))
|
|
1024
|
+
y {\left(z - \frac{\partial\,h}{\partial z}\right)}^{2} + x \frac{\partial^2\,f}{\partial x\partial y}
|
|
1025
|
+
|
|
1026
|
+
Testing the behavior if no latex_name of the function is given::
|
|
1027
|
+
|
|
1028
|
+
sage: f = function('f_x')(x, y)
|
|
1029
|
+
sage: fun = f.diff(y)
|
|
1030
|
+
sage: latex(ExpressionNice(fun))
|
|
1031
|
+
\frac{\partial\,f_{x}}{\partial y}
|
|
1032
|
+
|
|
1033
|
+
If latex_name, it should be used in LaTeX output::
|
|
1034
|
+
|
|
1035
|
+
sage: f = function('f_x', latex_name=r"{\cal F}")(x,y)
|
|
1036
|
+
sage: fun = f.diff(y)
|
|
1037
|
+
sage: latex(ExpressionNice(fun))
|
|
1038
|
+
\frac{\partial\,{\cal F}}{\partial y}
|
|
1039
|
+
|
|
1040
|
+
Check that :issue:`33399` is fixed::
|
|
1041
|
+
|
|
1042
|
+
sage: latex(ExpressionNice(function('f')(x+y, x-y).diff(y)))
|
|
1043
|
+
\frac{\partial\,f}{\partial \left( x + y \right)}
|
|
1044
|
+
- \frac{\partial\,f}{\partial \left( x - y \right)}
|
|
1045
|
+
"""
|
|
1046
|
+
from sage.misc.latex import latex
|
|
1047
|
+
|
|
1048
|
+
d = self._parent._latex_element_(self)
|
|
1049
|
+
|
|
1050
|
+
# find all occurrences of diff
|
|
1051
|
+
list_d = []
|
|
1052
|
+
_list_derivatives(self, list_d)
|
|
1053
|
+
|
|
1054
|
+
for m in list_d:
|
|
1055
|
+
if str(m[1]) == str(m[2]):
|
|
1056
|
+
funcname = str(m[1])
|
|
1057
|
+
else:
|
|
1058
|
+
funcname = str(m[2])
|
|
1059
|
+
|
|
1060
|
+
diffargs = m[3]
|
|
1061
|
+
numargs = len(diffargs)
|
|
1062
|
+
|
|
1063
|
+
if numargs > 1:
|
|
1064
|
+
numargs = "^" + str(numargs)
|
|
1065
|
+
else:
|
|
1066
|
+
numargs = ""
|
|
1067
|
+
|
|
1068
|
+
variables = m[4]
|
|
1069
|
+
|
|
1070
|
+
strv = [str(v) for v in variables]
|
|
1071
|
+
latv = [latex(v) for v in variables]
|
|
1072
|
+
|
|
1073
|
+
# checking if the variable is composite
|
|
1074
|
+
comp_chars = ['+', '-', '*', '/', '^', '(']
|
|
1075
|
+
for i, sv in enumerate(strv):
|
|
1076
|
+
if any(c in sv for c in comp_chars):
|
|
1077
|
+
latv[i] = r"\left(" + latv[i] + r"\right)"
|
|
1078
|
+
|
|
1079
|
+
# dictionary to group multiple occurrences of differentiation: d/dxdx -> d/dx^2 etc.
|
|
1080
|
+
occ = {i: (latv[i] + "^" + latex(diffargs.count(i))
|
|
1081
|
+
if diffargs.count(i) > 1 else latv[i])
|
|
1082
|
+
for i in diffargs}
|
|
1083
|
+
|
|
1084
|
+
res = r"\frac{\partial" + numargs + r"\," + funcname + \
|
|
1085
|
+
r"}{\partial " + r"\partial ".join(i for i in occ.values()) + "}"
|
|
1086
|
+
|
|
1087
|
+
# representation of the operator
|
|
1088
|
+
s = self._parent._latex_element_(m[0])
|
|
1089
|
+
|
|
1090
|
+
# if diff operator is raised to some power (m[5]), put brackets around
|
|
1091
|
+
if m[5]:
|
|
1092
|
+
res = r"\left(" + res + r"\right)^{" + str(m[5]) + "}"
|
|
1093
|
+
o = s + "^{" + str(m[5]) + "}"
|
|
1094
|
+
else:
|
|
1095
|
+
o = s
|
|
1096
|
+
|
|
1097
|
+
d = d.replace(o, res)
|
|
1098
|
+
|
|
1099
|
+
from sage.manifolds.manifold import TopologicalManifold
|
|
1100
|
+
if TopologicalManifold.options.omit_function_arguments:
|
|
1101
|
+
list_f = []
|
|
1102
|
+
_list_functions(self, list_f)
|
|
1103
|
+
|
|
1104
|
+
for m in list_f:
|
|
1105
|
+
d = d.replace(str(m[3]) + str(m[4]), str(m[3]))
|
|
1106
|
+
|
|
1107
|
+
return d
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
def _list_derivatives(ex, list_d, exponent=0):
|
|
1111
|
+
r"""
|
|
1112
|
+
Function to find the occurrences of ``FDerivativeOperator`` in a symbolic
|
|
1113
|
+
expression; inspired by
|
|
1114
|
+
http://ask.sagemath.org/question/10256/how-can-extract-different-terms-from-a-symbolic-expression/?answer=26136#post-id-26136
|
|
1115
|
+
|
|
1116
|
+
INPUT:
|
|
1117
|
+
|
|
1118
|
+
- ``ex`` -- symbolic expression to be analyzed
|
|
1119
|
+
- ``exponent`` -- (optional) exponent of ``FDerivativeOperator``,
|
|
1120
|
+
passed to a next level in the expression tree
|
|
1121
|
+
|
|
1122
|
+
OUTPUT:
|
|
1123
|
+
|
|
1124
|
+
- ``list_d`` -- tuple containing the details of ``FDerivativeOperator``
|
|
1125
|
+
found, in the following order:
|
|
1126
|
+
|
|
1127
|
+
1. operator
|
|
1128
|
+
2. function name
|
|
1129
|
+
3. LaTeX function name
|
|
1130
|
+
4. parameter set
|
|
1131
|
+
5. operands
|
|
1132
|
+
6. exponent (if found, else 0)
|
|
1133
|
+
|
|
1134
|
+
TESTS::
|
|
1135
|
+
|
|
1136
|
+
sage: f = function('f_x', latex_name=r"{\cal F}")(x)
|
|
1137
|
+
sage: df = f.diff(x)^2
|
|
1138
|
+
sage: from sage.manifolds.utilities import _list_derivatives
|
|
1139
|
+
sage: list_d = []
|
|
1140
|
+
sage: _list_derivatives(df, list_d)
|
|
1141
|
+
sage: list_d
|
|
1142
|
+
[(diff(f_x(x), x), 'f_x', {\cal F}, [0], [x], 2)]
|
|
1143
|
+
"""
|
|
1144
|
+
op = ex.operator()
|
|
1145
|
+
operands = ex.operands()
|
|
1146
|
+
|
|
1147
|
+
import operator
|
|
1148
|
+
|
|
1149
|
+
from sage.misc.latex import latex, latex_variable_name
|
|
1150
|
+
from sage.symbolic.operators import FDerivativeOperator
|
|
1151
|
+
|
|
1152
|
+
if op:
|
|
1153
|
+
if op is operator.pow:
|
|
1154
|
+
if isinstance(operands[0].operator(), FDerivativeOperator):
|
|
1155
|
+
exponent = operands[1]
|
|
1156
|
+
|
|
1157
|
+
if isinstance(op, FDerivativeOperator):
|
|
1158
|
+
parameter_set = op.parameter_set()
|
|
1159
|
+
function = repr(op.function())
|
|
1160
|
+
latex_function = latex(op.function())
|
|
1161
|
+
|
|
1162
|
+
# case when no latex_name given
|
|
1163
|
+
if function == latex_function:
|
|
1164
|
+
latex_function = latex_variable_name(str(op.function()))
|
|
1165
|
+
|
|
1166
|
+
list_d.append((ex, function, latex_function, parameter_set,
|
|
1167
|
+
operands, exponent))
|
|
1168
|
+
|
|
1169
|
+
for operand in operands:
|
|
1170
|
+
_list_derivatives(operand, list_d, exponent)
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
def _list_functions(ex, list_f):
|
|
1174
|
+
r"""
|
|
1175
|
+
Function to find the occurrences of symbolic functions in a symbolic
|
|
1176
|
+
expression.
|
|
1177
|
+
|
|
1178
|
+
INPUT:
|
|
1179
|
+
|
|
1180
|
+
- ``ex`` -- symbolic expression to be analyzed
|
|
1181
|
+
|
|
1182
|
+
OUTPUT:
|
|
1183
|
+
|
|
1184
|
+
- ``list_f`` -- tuple containing the details of a symbolic function found,
|
|
1185
|
+
in the following order:
|
|
1186
|
+
|
|
1187
|
+
1. operator
|
|
1188
|
+
2. function name
|
|
1189
|
+
3. arguments
|
|
1190
|
+
4. LaTeX version of function name
|
|
1191
|
+
5. LaTeX version of arguments
|
|
1192
|
+
|
|
1193
|
+
TESTS::
|
|
1194
|
+
|
|
1195
|
+
sage: var('x y z')
|
|
1196
|
+
(x, y, z)
|
|
1197
|
+
sage: f = function('f', latex_name=r"{\cal F}")(x, y)
|
|
1198
|
+
sage: g = function('g_x')(x, y)
|
|
1199
|
+
sage: d = sin(x)*g.diff(x)*x*f - x^2*f.diff(x,y)/g
|
|
1200
|
+
sage: from sage.manifolds.utilities import _list_functions
|
|
1201
|
+
sage: list_f = []
|
|
1202
|
+
sage: _list_functions(d, list_f)
|
|
1203
|
+
sage: list_f
|
|
1204
|
+
[(f, 'f', '(x, y)', {\cal F}, \left(x, y\right)),
|
|
1205
|
+
(g_x, 'g_x', '(x, y)', 'g_{x}', \left(x, y\right))]
|
|
1206
|
+
"""
|
|
1207
|
+
op = ex.operator()
|
|
1208
|
+
operands = ex.operands()
|
|
1209
|
+
|
|
1210
|
+
from sage.misc.latex import latex, latex_variable_name
|
|
1211
|
+
|
|
1212
|
+
if op:
|
|
1213
|
+
# FIXME: This hack is needed because the NewSymbolicFunction is
|
|
1214
|
+
# a class defined inside of the *function* function_factory().
|
|
1215
|
+
if "NewSymbolicFunction" in str(type(op)):
|
|
1216
|
+
repr_function = repr(op)
|
|
1217
|
+
latex_function = latex(op)
|
|
1218
|
+
|
|
1219
|
+
# case when no latex_name given
|
|
1220
|
+
if repr_function == latex_function:
|
|
1221
|
+
latex_function = latex_variable_name(str(op))
|
|
1222
|
+
|
|
1223
|
+
repr_args = repr(ex.arguments())
|
|
1224
|
+
# remove comma in case of singleton
|
|
1225
|
+
if len(ex.arguments()) == 1:
|
|
1226
|
+
repr_args = repr_args.replace(",","")
|
|
1227
|
+
|
|
1228
|
+
latex_args = latex(ex.arguments())
|
|
1229
|
+
|
|
1230
|
+
list_f.append((op, repr_function, repr_args, latex_function, latex_args))
|
|
1231
|
+
|
|
1232
|
+
for operand in operands:
|
|
1233
|
+
_list_functions(operand, list_f)
|
|
1234
|
+
|
|
1235
|
+
#******************************************************************************
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
def set_axes_labels(graph, xlabel, ylabel, zlabel, **kwds):
|
|
1239
|
+
r"""
|
|
1240
|
+
Set axes labels for a 3D graphics object ``graph``.
|
|
1241
|
+
|
|
1242
|
+
This is a workaround for the lack of axes labels in 3D plots.
|
|
1243
|
+
This sets the labels as :func:`~sage.plot.plot3d.shapes2.text3d`
|
|
1244
|
+
objects at locations determined from the bounding box of the
|
|
1245
|
+
graphic object ``graph``.
|
|
1246
|
+
|
|
1247
|
+
INPUT:
|
|
1248
|
+
|
|
1249
|
+
- ``graph`` -- :class:`~sage.plot.plot3d.base.Graphics3d`;
|
|
1250
|
+
a 3D graphic object
|
|
1251
|
+
- ``xlabel`` -- string for the x-axis label
|
|
1252
|
+
- ``ylabel`` -- string for the y-axis label
|
|
1253
|
+
- ``zlabel`` -- string for the z-axis label
|
|
1254
|
+
- ``**kwds`` -- options (e.g. color) for text3d
|
|
1255
|
+
|
|
1256
|
+
OUTPUT: the 3D graphic object with text3d labels added
|
|
1257
|
+
|
|
1258
|
+
EXAMPLES::
|
|
1259
|
+
|
|
1260
|
+
sage: # needs sage.plot
|
|
1261
|
+
sage: g = sphere()
|
|
1262
|
+
sage: g.all
|
|
1263
|
+
[Graphics3d Object]
|
|
1264
|
+
sage: from sage.manifolds.utilities import set_axes_labels
|
|
1265
|
+
sage: ga = set_axes_labels(g, 'X', 'Y', 'Z', color='red')
|
|
1266
|
+
sage: ga.all # the 3D frame has now axes labels
|
|
1267
|
+
[Graphics3d Object, Graphics3d Object,
|
|
1268
|
+
Graphics3d Object, Graphics3d Object]
|
|
1269
|
+
"""
|
|
1270
|
+
from sage.plot.plot3d.shapes2 import text3d
|
|
1271
|
+
xmin, ymin, zmin = graph.bounding_box()[0]
|
|
1272
|
+
xmax, ymax, zmax = graph.bounding_box()[1]
|
|
1273
|
+
dx = xmax - xmin
|
|
1274
|
+
dy = ymax - ymin
|
|
1275
|
+
dz = zmax - zmin
|
|
1276
|
+
x1 = xmin + dx / 2
|
|
1277
|
+
y1 = ymin + dy / 2
|
|
1278
|
+
z1 = zmin + dz / 2
|
|
1279
|
+
xmin1 = xmin - dx / 20
|
|
1280
|
+
ymin1 = ymin - dy / 20
|
|
1281
|
+
zmin1 = zmin - dz / 20
|
|
1282
|
+
graph += text3d(' ' + xlabel, (x1, ymin1, zmin1), **kwds)
|
|
1283
|
+
graph += text3d(' ' + ylabel, (xmin1, y1, zmin1), **kwds)
|
|
1284
|
+
graph += text3d(' ' + zlabel, (xmin1, ymin1, z1), **kwds)
|
|
1285
|
+
return graph
|
|
1286
|
+
|
|
1287
|
+
|
|
1288
|
+
def exterior_derivative(form):
|
|
1289
|
+
r"""
|
|
1290
|
+
Exterior derivative of a differential form.
|
|
1291
|
+
|
|
1292
|
+
INPUT:
|
|
1293
|
+
|
|
1294
|
+
- ``form`` -- a differential form; this must an instance of either
|
|
1295
|
+
|
|
1296
|
+
* :class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
|
|
1297
|
+
for a 0-form (scalar field)
|
|
1298
|
+
* :class:`~sage.manifolds.differentiable.diff_form.DiffFormParal` for
|
|
1299
|
+
a `p`-form (`p\geq 1`) on a parallelizable manifold
|
|
1300
|
+
* :class:`~sage.manifolds.differentiable.diff_form.DiffForm` for a
|
|
1301
|
+
a `p`-form (`p\geq 1`) on a non-parallelizable manifold
|
|
1302
|
+
|
|
1303
|
+
OUTPUT:
|
|
1304
|
+
|
|
1305
|
+
- the `(p+1)`-form that is the exterior derivative of ``form``
|
|
1306
|
+
|
|
1307
|
+
EXAMPLES:
|
|
1308
|
+
|
|
1309
|
+
Exterior derivative of a scalar field (0-form)::
|
|
1310
|
+
|
|
1311
|
+
sage: from sage.manifolds.utilities import exterior_derivative
|
|
1312
|
+
sage: M = Manifold(3, 'M')
|
|
1313
|
+
sage: X.<x,y,z> = M.chart()
|
|
1314
|
+
sage: f = M.scalar_field({X: x+y^2+z^3}, name='f')
|
|
1315
|
+
sage: df = exterior_derivative(f); df
|
|
1316
|
+
1-form df on the 3-dimensional differentiable manifold M
|
|
1317
|
+
sage: df.display()
|
|
1318
|
+
df = dx + 2*y dy + 3*z^2 dz
|
|
1319
|
+
|
|
1320
|
+
An alias is ``xder``::
|
|
1321
|
+
|
|
1322
|
+
sage: from sage.manifolds.utilities import xder
|
|
1323
|
+
sage: df == xder(f)
|
|
1324
|
+
True
|
|
1325
|
+
|
|
1326
|
+
Exterior derivative of a 1-form::
|
|
1327
|
+
|
|
1328
|
+
sage: a = M.one_form(name='a')
|
|
1329
|
+
sage: a[:] = [x+y*z, x-y*z, x*y*z]
|
|
1330
|
+
sage: da = xder(a); da
|
|
1331
|
+
2-form da on the 3-dimensional differentiable manifold M
|
|
1332
|
+
sage: da.display()
|
|
1333
|
+
da = (-z + 1) dx∧dy + (y*z - y) dx∧dz + (x*z + y) dy∧dz
|
|
1334
|
+
sage: dda = xder(da); dda
|
|
1335
|
+
3-form dda on the 3-dimensional differentiable manifold M
|
|
1336
|
+
sage: dda.display()
|
|
1337
|
+
dda = 0
|
|
1338
|
+
|
|
1339
|
+
.. SEEALSO::
|
|
1340
|
+
|
|
1341
|
+
:class:`sage.manifolds.differentiable.diff_form.DiffFormParal.exterior_derivative`
|
|
1342
|
+
or :class:`sage.manifolds.differentiable.diff_form.DiffForm.exterior_derivative`
|
|
1343
|
+
for more examples.
|
|
1344
|
+
"""
|
|
1345
|
+
return form.exterior_derivative()
|
|
1346
|
+
|
|
1347
|
+
|
|
1348
|
+
xder = exterior_derivative
|