passagemath-symbolics 10.8.1a1__cp314-cp314t-musllinux_1_2_aarch64.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.
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
- passagemath_symbolics-10.8.1a1.dist-info/RECORD +181 -0
- passagemath_symbolics-10.8.1a1.dist-info/WHEEL +5 -0
- passagemath_symbolics-10.8.1a1.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2838 -0
- sage/calculus/desolvers.py +1864 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/calculus/var.pyx +401 -0
- sage/dynamics/all__sagemath_symbolics.py +6 -0
- sage/dynamics/complex_dynamics/all.py +5 -0
- sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1034 -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 +755 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2419 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1083 -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 +2991 -0
- sage/interfaces/magma_free.py +90 -0
- sage/interfaces/maple.py +1402 -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 +553 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4010 -0
- sage/manifolds/chart_func.py +3416 -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 +1668 -0
- sage/manifolds/differentiable/diff_form.py +1660 -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 +1522 -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 +912 -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 +1725 -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 +2721 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +883 -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 +1347 -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-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1030 -0
- sage/matrix/matrix_symbolic_sparse.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1038 -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 +4106 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5205 -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 +987 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +456 -0
- sage/symbolic/callable.pyi +66 -0
- sage/symbolic/comparison_impl.pyi +38 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1286 -0
- sage/symbolic/constants_c_impl.pyi +10 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1727 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/function_factory.pyi +41 -0
- sage/symbolic/getitem_impl.pyi +24 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +271 -0
- sage/symbolic/integration/integral.py +1075 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/operators.pyi +61 -0
- sage/symbolic/pynac_constant_impl.pyi +13 -0
- sage/symbolic/pynac_function_impl.pyi +8 -0
- sage/symbolic/random_tests.py +461 -0
- sage/symbolic/relation.py +2062 -0
- sage/symbolic/ring.cpython-314t-aarch64-linux-musl.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyi +110 -0
- sage/symbolic/ring.pyx +1393 -0
- sage/symbolic/series_impl.pyi +10 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1468 -0
|
@@ -0,0 +1,1345 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Interface to Mathematica
|
|
4
|
+
|
|
5
|
+
The Mathematica interface will only work if Mathematica is installed on your
|
|
6
|
+
computer with a command line interface that runs when you give the ``math``
|
|
7
|
+
command. The interface lets you send certain Sage objects to Mathematica,
|
|
8
|
+
run Mathematica functions, import certain Mathematica expressions to Sage,
|
|
9
|
+
or any combination of the above.
|
|
10
|
+
The Sage command::
|
|
11
|
+
|
|
12
|
+
sage: print(mathematica._install_hints())
|
|
13
|
+
...
|
|
14
|
+
|
|
15
|
+
prints more information on Mathematica installation.
|
|
16
|
+
|
|
17
|
+
To send a Sage object ``sobj`` to Mathematica, call ``mathematica(sobj)``.
|
|
18
|
+
This exports the Sage object to Mathematica and returns a new Sage object
|
|
19
|
+
wrapping the Mathematica expression/variable, so that you can use the
|
|
20
|
+
Mathematica variable from within Sage. You can then call Mathematica
|
|
21
|
+
functions on the new object; for example::
|
|
22
|
+
|
|
23
|
+
sage: mobj = mathematica(x^2-1) # optional - mathematica
|
|
24
|
+
sage: mobj.Factor() # optional - mathematica
|
|
25
|
+
(-1 + x)*(1 + x)
|
|
26
|
+
|
|
27
|
+
In the above example the factorization is done using Mathematica's
|
|
28
|
+
``Factor[]`` function.
|
|
29
|
+
|
|
30
|
+
To see Mathematica's output you can simply print the Mathematica wrapper
|
|
31
|
+
object. However if you want to import Mathematica's output back to Sage,
|
|
32
|
+
call the Mathematica wrapper object's ``sage()`` method. This method returns
|
|
33
|
+
a native Sage object::
|
|
34
|
+
|
|
35
|
+
sage: # optional - mathematica
|
|
36
|
+
sage: mobj = mathematica(x^2-1)
|
|
37
|
+
sage: mobj2 = mobj.Factor(); mobj2
|
|
38
|
+
(-1 + x)*(1 + x)
|
|
39
|
+
sage: mobj2.parent()
|
|
40
|
+
Mathematica
|
|
41
|
+
sage: sobj = mobj2.sage(); sobj
|
|
42
|
+
(x + 1)*(x - 1)
|
|
43
|
+
sage: sobj.parent()
|
|
44
|
+
Symbolic Ring
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
If you want to run a Mathematica function and don't already have the input
|
|
48
|
+
in the form of a Sage object, then it might be simpler to input a string to
|
|
49
|
+
``mathematica(expr)``. This string will be evaluated as if you had typed it
|
|
50
|
+
into Mathematica::
|
|
51
|
+
|
|
52
|
+
sage: mathematica('Factor[x^2-1]') # optional - mathematica
|
|
53
|
+
(-1 + x)*(1 + x)
|
|
54
|
+
sage: mathematica('Range[3]') # optional - mathematica
|
|
55
|
+
{1, 2, 3}
|
|
56
|
+
|
|
57
|
+
If you don't want Sage to go to the trouble of creating a wrapper for the
|
|
58
|
+
Mathematica expression, then you can call ``mathematica.eval(expr)``, which
|
|
59
|
+
returns the result as a Mathematica AsciiArtString formatted string. If you
|
|
60
|
+
want the result to be a string formatted like Mathematica's InputForm, call
|
|
61
|
+
``repr(mobj)`` on the wrapper object ``mobj``. If you want a string
|
|
62
|
+
formatted in Sage style, call ``mobj._sage_repr()``::
|
|
63
|
+
|
|
64
|
+
sage: mathematica.eval('x^2 - 1') # optional - mathematica
|
|
65
|
+
2
|
|
66
|
+
-1 + x
|
|
67
|
+
sage: repr(mathematica('Range[3]')) # optional - mathematica
|
|
68
|
+
'{1, 2, 3}'
|
|
69
|
+
sage: mathematica('Range[3]')._sage_repr() # optional - mathematica
|
|
70
|
+
'[1, 2, 3]'
|
|
71
|
+
|
|
72
|
+
Finally, if you just want to use a Mathematica command line from within
|
|
73
|
+
Sage, the function ``mathematica_console()`` dumps you into an interactive
|
|
74
|
+
command-line Mathematica session. This is an enhanced version of the usual
|
|
75
|
+
Mathematica command-line, in that it provides readline editing and history
|
|
76
|
+
(the usual one doesn't!)
|
|
77
|
+
|
|
78
|
+
Tutorial
|
|
79
|
+
--------
|
|
80
|
+
|
|
81
|
+
We follow some of the tutorial from
|
|
82
|
+
http://library.wolfram.com/conferences/devconf99/withoff/Basic1.html/.
|
|
83
|
+
|
|
84
|
+
For any of this to work you must buy and install the Mathematica
|
|
85
|
+
program, and it must be available as the command
|
|
86
|
+
``math`` in your PATH.
|
|
87
|
+
|
|
88
|
+
Syntax
|
|
89
|
+
~~~~~~
|
|
90
|
+
|
|
91
|
+
Now make 1 and add it to itself. The result is a Mathematica
|
|
92
|
+
object.
|
|
93
|
+
|
|
94
|
+
::
|
|
95
|
+
|
|
96
|
+
sage: m = mathematica
|
|
97
|
+
sage: a = m(1) + m(1); a # optional - mathematica
|
|
98
|
+
2
|
|
99
|
+
sage: a.parent() # optional - mathematica
|
|
100
|
+
Mathematica
|
|
101
|
+
sage: m('1+1') # optional - mathematica
|
|
102
|
+
2
|
|
103
|
+
sage: m(3)**m(50) # optional - mathematica
|
|
104
|
+
717897987691852588770249
|
|
105
|
+
|
|
106
|
+
The following is equivalent to ``Plus[2, 3]`` in
|
|
107
|
+
Mathematica::
|
|
108
|
+
|
|
109
|
+
sage: m = mathematica
|
|
110
|
+
sage: m(2).Plus(m(3)) # optional - mathematica
|
|
111
|
+
5
|
|
112
|
+
|
|
113
|
+
We can also compute `7(2+3)`.
|
|
114
|
+
|
|
115
|
+
::
|
|
116
|
+
|
|
117
|
+
sage: m(7).Times(m(2).Plus(m(3))) # optional - mathematica
|
|
118
|
+
35
|
|
119
|
+
sage: m('7(2+3)') # optional - mathematica
|
|
120
|
+
35
|
|
121
|
+
|
|
122
|
+
Some typical input
|
|
123
|
+
~~~~~~~~~~~~~~~~~~
|
|
124
|
+
|
|
125
|
+
We solve an equation and a system of two equations::
|
|
126
|
+
|
|
127
|
+
sage: # optional - mathematica
|
|
128
|
+
sage: eqn = mathematica('3x + 5 == 14')
|
|
129
|
+
sage: eqn
|
|
130
|
+
5 + 3*x == 14
|
|
131
|
+
sage: eqn.Solve('x')
|
|
132
|
+
{{x -> 3}}
|
|
133
|
+
sage: sys = mathematica('{x^2 - 3y == 3, 2x - y == 1}')
|
|
134
|
+
sage: print(sys)
|
|
135
|
+
2
|
|
136
|
+
{x - 3 y == 3, 2 x - y == 1}
|
|
137
|
+
sage: sys.Solve('{x, y}')
|
|
138
|
+
{{x -> 0, y -> -1}, {x -> 6, y -> 11}}
|
|
139
|
+
|
|
140
|
+
Assignments and definitions
|
|
141
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
142
|
+
|
|
143
|
+
If you assign the mathematica `5` to a variable `c`
|
|
144
|
+
in Sage, this does not affect the `c` in Mathematica.
|
|
145
|
+
|
|
146
|
+
::
|
|
147
|
+
|
|
148
|
+
sage: c = m(5) # optional - mathematica
|
|
149
|
+
sage: print(m('b + c x')) # optional - mathematica
|
|
150
|
+
b + c x
|
|
151
|
+
sage: print(m('b') + c*m('x')) # optional - mathematica
|
|
152
|
+
b + 5 x
|
|
153
|
+
|
|
154
|
+
The Sage interfaces changes Sage lists into Mathematica lists::
|
|
155
|
+
|
|
156
|
+
sage: m = mathematica
|
|
157
|
+
sage: eq1 = m('x^2 - 3y == 3') # optional - mathematica
|
|
158
|
+
sage: eq2 = m('2x - y == 1') # optional - mathematica
|
|
159
|
+
sage: v = m([eq1, eq2]); v # optional - mathematica
|
|
160
|
+
{x^2 - 3*y == 3, 2*x - y == 1}
|
|
161
|
+
sage: v.Solve(['x', 'y']) # optional - mathematica
|
|
162
|
+
{{x -> 0, y -> -1}, {x -> 6, y -> 11}}
|
|
163
|
+
|
|
164
|
+
Function definitions
|
|
165
|
+
~~~~~~~~~~~~~~~~~~~~
|
|
166
|
+
|
|
167
|
+
Define mathematica functions by simply sending the definition to
|
|
168
|
+
the interpreter.
|
|
169
|
+
|
|
170
|
+
::
|
|
171
|
+
|
|
172
|
+
sage: m = mathematica
|
|
173
|
+
sage: _ = mathematica('f[p_] = p^2'); # optional - mathematica
|
|
174
|
+
sage: m('f[9]') # optional - mathematica
|
|
175
|
+
81
|
|
176
|
+
|
|
177
|
+
Numerical Calculations
|
|
178
|
+
~~~~~~~~~~~~~~~~~~~~~~
|
|
179
|
+
|
|
180
|
+
We find the `x` such that `e^x - 3x = 0`.
|
|
181
|
+
|
|
182
|
+
::
|
|
183
|
+
|
|
184
|
+
sage: eqn = mathematica('Exp[x] - 3x == 0') # optional - mathematica
|
|
185
|
+
sage: eqn.FindRoot(['x', 2]) # optional - mathematica
|
|
186
|
+
{x -> 1.512134551657842}
|
|
187
|
+
|
|
188
|
+
Note that this agrees with what the PARI interpreter gp produces::
|
|
189
|
+
|
|
190
|
+
sage: gp('solve(x=1,2,exp(x)-3*x)') # needs sage.libs.pari
|
|
191
|
+
1.5121345516578424738967396780720387046
|
|
192
|
+
|
|
193
|
+
Next we find the minimum of a polynomial using the two different
|
|
194
|
+
ways of accessing Mathematica::
|
|
195
|
+
|
|
196
|
+
sage: mathematica('FindMinimum[x^3 - 6x^2 + 11x - 5, {x,3}]') # optional - mathematica
|
|
197
|
+
{0.6150998205402516, {x -> 2.5773502699629733}}
|
|
198
|
+
sage: f = mathematica('x^3 - 6x^2 + 11x - 5') # optional - mathematica
|
|
199
|
+
sage: f.FindMinimum(['x', 3]) # optional - mathematica
|
|
200
|
+
{0.6150998205402516, {x -> 2.5773502699629733}}
|
|
201
|
+
|
|
202
|
+
Polynomial and Integer Factorization
|
|
203
|
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
204
|
+
|
|
205
|
+
We factor a polynomial of degree 200 over the integers.
|
|
206
|
+
|
|
207
|
+
::
|
|
208
|
+
|
|
209
|
+
sage: R.<x> = PolynomialRing(ZZ)
|
|
210
|
+
sage: f = (x**100+17*x+5)*(x**100-5*x+20)
|
|
211
|
+
sage: f
|
|
212
|
+
x^200 + 12*x^101 + 25*x^100 - 85*x^2 + 315*x + 100
|
|
213
|
+
sage: g = mathematica(str(f)) # optional - mathematica
|
|
214
|
+
sage: print(g) # optional - mathematica
|
|
215
|
+
2 100 101 200
|
|
216
|
+
100 + 315 x - 85 x + 25 x + 12 x + x
|
|
217
|
+
sage: g # optional - mathematica
|
|
218
|
+
100 + 315*x - 85*x^2 + 25*x^100 + 12*x^101 + x^200
|
|
219
|
+
sage: print(g.Factor()) # optional - mathematica
|
|
220
|
+
100 100
|
|
221
|
+
(20 - 5 x + x ) (5 + 17 x + x )
|
|
222
|
+
|
|
223
|
+
We can also factor a multivariate polynomial::
|
|
224
|
+
|
|
225
|
+
sage: f = mathematica('x^6 + (-y - 2)*x^5 + (y^3 + 2*y)*x^4 - y^4*x^3') # optional - mathematica
|
|
226
|
+
sage: print(f.Factor()) # optional - mathematica
|
|
227
|
+
3 2 3
|
|
228
|
+
x (x - y) (-2 x + x + y )
|
|
229
|
+
|
|
230
|
+
We factor an integer::
|
|
231
|
+
|
|
232
|
+
sage: # optional - mathematica
|
|
233
|
+
sage: n = mathematica(2434500)
|
|
234
|
+
sage: n.FactorInteger()
|
|
235
|
+
{{2, 2}, {3, 2}, {5, 3}, {541, 1}}
|
|
236
|
+
sage: n = mathematica(2434500)
|
|
237
|
+
sage: F = n.FactorInteger(); F
|
|
238
|
+
{{2, 2}, {3, 2}, {5, 3}, {541, 1}}
|
|
239
|
+
sage: F[1]
|
|
240
|
+
{2, 2}
|
|
241
|
+
sage: F[4]
|
|
242
|
+
{541, 1}
|
|
243
|
+
|
|
244
|
+
Mathematica's ECM package is no longer available.
|
|
245
|
+
|
|
246
|
+
Long Input
|
|
247
|
+
----------
|
|
248
|
+
|
|
249
|
+
The Mathematica interface reads in even very long input (using
|
|
250
|
+
files) in a robust manner.
|
|
251
|
+
|
|
252
|
+
::
|
|
253
|
+
|
|
254
|
+
sage: t = '"%s"'%10^10000 # ten thousand character string.
|
|
255
|
+
sage: a = mathematica(t) # optional - mathematica
|
|
256
|
+
sage: a = mathematica.eval(t) # optional - mathematica
|
|
257
|
+
|
|
258
|
+
Loading and saving
|
|
259
|
+
------------------
|
|
260
|
+
|
|
261
|
+
Mathematica has an excellent ``InputForm`` function,
|
|
262
|
+
which makes saving and loading Mathematica objects possible. The
|
|
263
|
+
first examples test saving and loading to strings.
|
|
264
|
+
|
|
265
|
+
::
|
|
266
|
+
|
|
267
|
+
sage: # optional - mathematica
|
|
268
|
+
sage: x = mathematica(pi/2)
|
|
269
|
+
sage: print(x)
|
|
270
|
+
Pi
|
|
271
|
+
--
|
|
272
|
+
2
|
|
273
|
+
sage: loads(dumps(x)) == x
|
|
274
|
+
True
|
|
275
|
+
sage: n = x.N(50)
|
|
276
|
+
sage: print(n)
|
|
277
|
+
1.5707963267948966192313216916397514420985846996876
|
|
278
|
+
sage: loads(dumps(n)) == n
|
|
279
|
+
True
|
|
280
|
+
|
|
281
|
+
Complicated translations
|
|
282
|
+
------------------------
|
|
283
|
+
|
|
284
|
+
The ``mobj.sage()`` method tries to convert a Mathematica object to a Sage
|
|
285
|
+
object. In many cases, it will just work. In particular, it should be able to
|
|
286
|
+
convert expressions entirely consisting of:
|
|
287
|
+
|
|
288
|
+
- numbers, i.e. integers, floats, complex numbers;
|
|
289
|
+
- functions and named constants also present in Sage, where:
|
|
290
|
+
|
|
291
|
+
- Sage knows how to translate the function or constant's name from
|
|
292
|
+
Mathematica's, or
|
|
293
|
+
- the Sage name for the function or constant is trivially related to
|
|
294
|
+
Mathematica's;
|
|
295
|
+
|
|
296
|
+
- symbolic variables whose names don't pathologically overlap with
|
|
297
|
+
objects already defined in Sage.
|
|
298
|
+
|
|
299
|
+
This method will not work when Mathematica's output includes:
|
|
300
|
+
|
|
301
|
+
- strings;
|
|
302
|
+
- functions unknown to Sage;
|
|
303
|
+
- Mathematica functions with different parameters/parameter order to
|
|
304
|
+
the Sage equivalent.
|
|
305
|
+
|
|
306
|
+
If you want to convert more complicated Mathematica expressions, you can
|
|
307
|
+
instead call ``mobj._sage_()`` and supply a translation dictionary::
|
|
308
|
+
|
|
309
|
+
sage: m = mathematica('NewFn[x]') # optional - mathematica
|
|
310
|
+
sage: m._sage_(locals={('NewFn', 1): sin}) # optional - mathematica
|
|
311
|
+
sin(x)
|
|
312
|
+
|
|
313
|
+
For more details, see the documentation for ``._sage_()``.
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
OTHER Examples::
|
|
317
|
+
|
|
318
|
+
sage: def math_bessel_K(nu, x):
|
|
319
|
+
....: return mathematica(nu).BesselK(x).N(20)
|
|
320
|
+
sage: math_bessel_K(2,I) # optional - mathematica
|
|
321
|
+
-2.59288617549119697817 + 0.18048997206696202663*I
|
|
322
|
+
|
|
323
|
+
::
|
|
324
|
+
|
|
325
|
+
sage: slist = [[1, 2], 3., 4 + I]
|
|
326
|
+
sage: mlist = mathematica(slist); mlist # optional - mathematica
|
|
327
|
+
{{1, 2}, 3., 4 + I}
|
|
328
|
+
sage: slist2 = list(mlist); slist2 # optional - mathematica
|
|
329
|
+
[{1, 2}, 3., 4 + I]
|
|
330
|
+
sage: slist2[0] # optional - mathematica
|
|
331
|
+
{1, 2}
|
|
332
|
+
sage: slist2[0].parent() # optional - mathematica
|
|
333
|
+
Mathematica
|
|
334
|
+
sage: slist3 = mlist.sage(); slist3 # optional - mathematica
|
|
335
|
+
[[1, 2], 3.00000000000000, I + 4]
|
|
336
|
+
|
|
337
|
+
::
|
|
338
|
+
|
|
339
|
+
sage: mathematica('10.^80') # optional - mathematica
|
|
340
|
+
1.*^80
|
|
341
|
+
sage: mathematica('10.^80').sage() # optional - mathematica
|
|
342
|
+
1.00000000000000e80
|
|
343
|
+
|
|
344
|
+
AUTHORS:
|
|
345
|
+
|
|
346
|
+
- William Stein (2005): first version
|
|
347
|
+
|
|
348
|
+
- Doug Cutrell (2006-03-01): Instructions for use under Cygwin/Windows.
|
|
349
|
+
|
|
350
|
+
- Felix Lawrence (2009-08-21): Added support for importing Mathematica lists
|
|
351
|
+
and floats with exponents.
|
|
352
|
+
|
|
353
|
+
TESTS:
|
|
354
|
+
|
|
355
|
+
Check that numerical approximations via Mathematica's `N[]` function work
|
|
356
|
+
correctly (:issue:`18888`, :issue:`28907`)::
|
|
357
|
+
|
|
358
|
+
sage: # optional - mathematica
|
|
359
|
+
sage: mathematica('Pi/2').N(10)
|
|
360
|
+
1.5707963268
|
|
361
|
+
sage: mathematica('Pi').N(10)
|
|
362
|
+
3.1415926536
|
|
363
|
+
sage: mathematica('Pi').N(50)
|
|
364
|
+
3.14159265358979323846264338327950288419716939937511
|
|
365
|
+
sage: str(mathematica('Pi*x^2-1/2').N())
|
|
366
|
+
2
|
|
367
|
+
-0.5 + 3.14159 x
|
|
368
|
+
|
|
369
|
+
Check that Mathematica's `E` exponential symbol is correctly backtranslated
|
|
370
|
+
as Sage's `e` (:issue:`29833`)::
|
|
371
|
+
|
|
372
|
+
sage: x = var('x')
|
|
373
|
+
sage: (e^x)._mathematica_().sage() # optional -- mathematica
|
|
374
|
+
e^x
|
|
375
|
+
sage: exp(x)._mathematica_().sage() # optional -- mathematica
|
|
376
|
+
e^x
|
|
377
|
+
|
|
378
|
+
Check that all trig/hyperbolic functions and their reciprocals are correctly
|
|
379
|
+
translated to Mathematica (:issue:`34087`)::
|
|
380
|
+
|
|
381
|
+
sage: # optional - mathematica
|
|
382
|
+
sage: x=var('x')
|
|
383
|
+
sage: FL=[sin, cos, tan, csc, sec, cot,
|
|
384
|
+
....: sinh, cosh, tanh, csch, sech, coth]
|
|
385
|
+
sage: IFL=[arcsin, arccos, arctan, arccsc,
|
|
386
|
+
....: arcsec, arccot, arcsinh, arccosh,
|
|
387
|
+
....: arctanh, arccsch, arcsech, arccoth]
|
|
388
|
+
sage: [mathematica.TrigToExp(u(x)).sage()
|
|
389
|
+
....: for u in FL]
|
|
390
|
+
[-1/2*I*e^(I*x) + 1/2*I*e^(-I*x),
|
|
391
|
+
1/2*e^(I*x) + 1/2*e^(-I*x),
|
|
392
|
+
(-I*e^(I*x) + I*e^(-I*x))/(e^(I*x) + e^(-I*x)),
|
|
393
|
+
2*I/(e^(I*x) - e^(-I*x)),
|
|
394
|
+
2/(e^(I*x) + e^(-I*x)),
|
|
395
|
+
-(-I*e^(I*x) - I*e^(-I*x))/(e^(I*x) - e^(-I*x)),
|
|
396
|
+
-1/2*e^(-x) + 1/2*e^x,
|
|
397
|
+
1/2*e^(-x) + 1/2*e^x,
|
|
398
|
+
-e^(-x)/(e^(-x) + e^x) + e^x/(e^(-x) + e^x),
|
|
399
|
+
-2/(e^(-x) - e^x),
|
|
400
|
+
2/(e^(-x) + e^x),
|
|
401
|
+
-(e^(-x) + e^x)/(e^(-x) - e^x)]
|
|
402
|
+
sage: [mathematica.TrigToExp(u(x)).sage()
|
|
403
|
+
....: for u in IFL]
|
|
404
|
+
[-I*log(I*x + sqrt(-x^2 + 1)),
|
|
405
|
+
1/2*pi + I*log(I*x + sqrt(-x^2 + 1)),
|
|
406
|
+
-1/2*I*log(I*x + 1) + 1/2*I*log(-I*x + 1),
|
|
407
|
+
-I*log(sqrt(-1/x^2 + 1) + I/x),
|
|
408
|
+
1/2*pi + I*log(sqrt(-1/x^2 + 1) + I/x),
|
|
409
|
+
-1/2*I*log(I/x + 1) + 1/2*I*log(-I/x + 1),
|
|
410
|
+
log(x + sqrt(x^2 + 1)),
|
|
411
|
+
log(sqrt(x + 1)*sqrt(x - 1) + x),
|
|
412
|
+
1/2*log(x + 1) - 1/2*log(-x + 1),
|
|
413
|
+
log(sqrt(1/x^2 + 1) + 1/x),
|
|
414
|
+
log(sqrt(1/x + 1)*sqrt(1/x - 1) + 1/x),
|
|
415
|
+
1/2*log(1/x + 1) - 1/2*log(-1/x + 1)]
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
# ****************************************************************************
|
|
419
|
+
# Copyright (C) 2005 William Stein <wstein@gmail.com>
|
|
420
|
+
#
|
|
421
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
422
|
+
#
|
|
423
|
+
# This code is distributed in the hope that it will be useful,
|
|
424
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
425
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
426
|
+
# General Public License for more details.
|
|
427
|
+
#
|
|
428
|
+
# The full text of the GPL is available at:
|
|
429
|
+
#
|
|
430
|
+
# https://www.gnu.org/licenses/
|
|
431
|
+
# ****************************************************************************
|
|
432
|
+
|
|
433
|
+
import os
|
|
434
|
+
import re
|
|
435
|
+
|
|
436
|
+
from sage.misc.cachefunc import cached_method
|
|
437
|
+
from sage.interfaces.expect import (Expect, ExpectElement, ExpectFunction,
|
|
438
|
+
FunctionElement)
|
|
439
|
+
from sage.interfaces.interface import AsciiArtString
|
|
440
|
+
from sage.interfaces.tab_completion import ExtraTabCompletion
|
|
441
|
+
from sage.misc.instancedoc import instancedoc
|
|
442
|
+
from sage.structure.richcmp import rich_to_bool
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def clean_output(s):
|
|
446
|
+
if s is None:
|
|
447
|
+
return ''
|
|
448
|
+
i = s.find('Out[')
|
|
449
|
+
j = i + s[i:].find('=')
|
|
450
|
+
s = s[:i] + ' ' * (j + 1 - i) + s[j + 1:]
|
|
451
|
+
s = s.replace('\\\n', '')
|
|
452
|
+
return s.strip('\n')
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def _un_camel(name):
|
|
456
|
+
"""
|
|
457
|
+
Convert ``CamelCase`` to ``camel_case``.
|
|
458
|
+
|
|
459
|
+
EXAMPLES::
|
|
460
|
+
|
|
461
|
+
sage: sage.interfaces.mathematica._un_camel('CamelCase')
|
|
462
|
+
'camel_case'
|
|
463
|
+
sage: sage.interfaces.mathematica._un_camel('EllipticE')
|
|
464
|
+
'elliptic_e'
|
|
465
|
+
sage: sage.interfaces.mathematica._un_camel('FindRoot')
|
|
466
|
+
'find_root'
|
|
467
|
+
sage: sage.interfaces.mathematica._un_camel('GCD')
|
|
468
|
+
'gcd'
|
|
469
|
+
"""
|
|
470
|
+
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name)
|
|
471
|
+
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
class Mathematica(ExtraTabCompletion, Expect):
|
|
475
|
+
"""
|
|
476
|
+
Interface to the Mathematica interpreter.
|
|
477
|
+
"""
|
|
478
|
+
def __init__(self, maxread=None, script_subdirectory=None, logfile=None, server=None,
|
|
479
|
+
server_tmpdir=None, command=None, verbose_start=False):
|
|
480
|
+
r"""
|
|
481
|
+
TESTS:
|
|
482
|
+
|
|
483
|
+
Test that :issue:`28075` is fixed::
|
|
484
|
+
|
|
485
|
+
sage: repr(mathematica.eval("Print[1]; Print[2]; Print[3]")) # optional - mathematica
|
|
486
|
+
'1\n2\n3'
|
|
487
|
+
"""
|
|
488
|
+
# We use -rawterm to get a raw text interface in Mathematica 9 or later.
|
|
489
|
+
# This works around the following issues of Mathematica 9 or later
|
|
490
|
+
# (tested with Mathematica 11.0.1 for Mac OS X x86 (64-bit))
|
|
491
|
+
#
|
|
492
|
+
# 1) If TERM is unset and input is a pseudoterminal, Mathematica shows no
|
|
493
|
+
# prompts, so pexpect will not work.
|
|
494
|
+
#
|
|
495
|
+
# 2) If TERM is set (to dumb, lpr, vt100, or xterm), there will be
|
|
496
|
+
# prompts; but there is bizarre echoing behavior by Mathematica (not
|
|
497
|
+
# the terminal driver). For example, with TERM=dumb, many spaces and
|
|
498
|
+
# \r's are echoed. With TERM=vt100 or better, in addition, many escape
|
|
499
|
+
# sequences are printed.
|
|
500
|
+
#
|
|
501
|
+
if command is None:
|
|
502
|
+
command = os.getenv('SAGE_MATHEMATICA_COMMAND') or 'math -rawterm'
|
|
503
|
+
eval_using_file_cutoff = 1024
|
|
504
|
+
# Removing terminal echo using "stty -echo" is not essential but it slightly
|
|
505
|
+
# improves performance (system time) and eliminates races of the terminal echo
|
|
506
|
+
# as a possible source of error.
|
|
507
|
+
if server:
|
|
508
|
+
command = 'stty -echo; {}'.format(command)
|
|
509
|
+
else:
|
|
510
|
+
command = 'sh -c "stty -echo; {}"'.format(command)
|
|
511
|
+
Expect.__init__(self,
|
|
512
|
+
name='mathematica',
|
|
513
|
+
terminal_echo=False,
|
|
514
|
+
command=command,
|
|
515
|
+
prompt=r'In\[[0-9]+\]:= ',
|
|
516
|
+
server=server,
|
|
517
|
+
server_tmpdir=server_tmpdir,
|
|
518
|
+
script_subdirectory=script_subdirectory,
|
|
519
|
+
verbose_start=verbose_start,
|
|
520
|
+
logfile=logfile,
|
|
521
|
+
eval_using_file_cutoff=eval_using_file_cutoff)
|
|
522
|
+
|
|
523
|
+
def _read_in_file_command(self, filename):
|
|
524
|
+
return '<<"%s"' % filename
|
|
525
|
+
|
|
526
|
+
def _keyboard_interrupt(self):
|
|
527
|
+
print("Interrupting %s..." % self)
|
|
528
|
+
e = self._expect
|
|
529
|
+
e.sendline(chr(3)) # send ctrl-c
|
|
530
|
+
e.expect('Interrupt> ')
|
|
531
|
+
e.sendline("a") # a -- abort
|
|
532
|
+
e.expect(self._prompt)
|
|
533
|
+
return e.before
|
|
534
|
+
|
|
535
|
+
def _install_hints(self):
|
|
536
|
+
"""
|
|
537
|
+
Hints for installing mathematica on your computer.
|
|
538
|
+
|
|
539
|
+
AUTHORS:
|
|
540
|
+
|
|
541
|
+
- William Stein and Justin Walker (2006-02-12)
|
|
542
|
+
"""
|
|
543
|
+
return """
|
|
544
|
+
In order to use the Mathematica interface you need to have Mathematica
|
|
545
|
+
installed and have a script in your PATH called "math" that runs the
|
|
546
|
+
command-line version of Mathematica. Alternatively, you could use a
|
|
547
|
+
remote connection to a server running Mathematica -- for hints, type
|
|
548
|
+
print(mathematica._install_hints_ssh())
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
(1) You might have to buy Mathematica (https://www.wolfram.com/), or
|
|
552
|
+
install a currently (Feb 2022) free for personal use Wolfram Engine
|
|
553
|
+
(https://www.wolfram.com/engine/).
|
|
554
|
+
|
|
555
|
+
(2) * LINUX: The math script usually comes standard with your Mathematica install.
|
|
556
|
+
However, on some systems it may be called wolfram,
|
|
557
|
+
or, in case of Wolfram Engine, wolframengine, while math is absent.
|
|
558
|
+
In this case, assuming wolfram, respectively, wolframengine,
|
|
559
|
+
is in your PATH,
|
|
560
|
+
(a) create a file called math (in your PATH):
|
|
561
|
+
#!/bin/sh
|
|
562
|
+
/usr/bin/env wolfram $@
|
|
563
|
+
|
|
564
|
+
respectively,
|
|
565
|
+
(a') create a file called math (in your PATH):
|
|
566
|
+
#!/bin/sh
|
|
567
|
+
/usr/bin/env wolframengine $@
|
|
568
|
+
|
|
569
|
+
(b) Make the file executable.
|
|
570
|
+
chmod +x math
|
|
571
|
+
|
|
572
|
+
* Apple macOS: for Mathematica,
|
|
573
|
+
(a) create a file called math (in your PATH):
|
|
574
|
+
#!/bin/sh
|
|
575
|
+
/Applications/Mathematica.app/Contents/MacOS/MathKernel $@
|
|
576
|
+
|
|
577
|
+
(a') for Wolfram Engine, follow the Linux step (a') above.
|
|
578
|
+
|
|
579
|
+
The path in the above script must be modified if you installed
|
|
580
|
+
Mathematica elsewhere or installed an old version of
|
|
581
|
+
Mathematica that has the version in the .app name.
|
|
582
|
+
|
|
583
|
+
(b) Make the file executable.
|
|
584
|
+
chmod +x math
|
|
585
|
+
|
|
586
|
+
* WINDOWS:
|
|
587
|
+
|
|
588
|
+
Install Mathematica for Linux into the VMware virtual machine, or in
|
|
589
|
+
a WSL/WSL2 Linux installation with Sage installed there (sorry,
|
|
590
|
+
that's the only ways at present).
|
|
591
|
+
"""
|
|
592
|
+
|
|
593
|
+
def eval(self, code, strip=True, **kwds):
|
|
594
|
+
s = Expect.eval(self, code, **kwds)
|
|
595
|
+
if strip:
|
|
596
|
+
return AsciiArtString(clean_output(s))
|
|
597
|
+
else:
|
|
598
|
+
return AsciiArtString(s)
|
|
599
|
+
|
|
600
|
+
def set(self, var, value):
|
|
601
|
+
"""
|
|
602
|
+
Set the variable var to the given value.
|
|
603
|
+
"""
|
|
604
|
+
cmd = '%s=%s;' % (var, value)
|
|
605
|
+
out = self._eval_line(cmd, allow_use_file=True)
|
|
606
|
+
if len(out) > 8:
|
|
607
|
+
raise TypeError("Error executing code in Mathematica\nCODE:\n\t%s\nMathematica ERROR:\n\t%s" % (cmd, out))
|
|
608
|
+
|
|
609
|
+
def get(self, var, ascii_art=False):
|
|
610
|
+
"""
|
|
611
|
+
Get the value of the variable var.
|
|
612
|
+
|
|
613
|
+
AUTHORS:
|
|
614
|
+
|
|
615
|
+
- William Stein
|
|
616
|
+
|
|
617
|
+
- Kiran Kedlaya (2006-02-04): suggested using InputForm
|
|
618
|
+
"""
|
|
619
|
+
if ascii_art:
|
|
620
|
+
return self.eval(var, strip=True)
|
|
621
|
+
return self.eval('InputForm[%s, NumberMarks->False]' % var, strip=True)
|
|
622
|
+
|
|
623
|
+
def _eval_line(self, line, allow_use_file=True, wait_for_prompt=True, restart_if_needed=False):
|
|
624
|
+
s = Expect._eval_line(self, line,
|
|
625
|
+
allow_use_file=allow_use_file, wait_for_prompt=wait_for_prompt)
|
|
626
|
+
return str(s).strip('\n')
|
|
627
|
+
|
|
628
|
+
def _function_call_string(self, function, args, kwds):
|
|
629
|
+
"""
|
|
630
|
+
Return the string used to make function calls.
|
|
631
|
+
|
|
632
|
+
EXAMPLES::
|
|
633
|
+
|
|
634
|
+
sage: mathematica._function_call_string('Sin', ['x'], [])
|
|
635
|
+
'Sin[x]'
|
|
636
|
+
"""
|
|
637
|
+
return "%s[%s]" % (function, ",".join(args))
|
|
638
|
+
|
|
639
|
+
def _left_list_delim(self):
|
|
640
|
+
return "{"
|
|
641
|
+
|
|
642
|
+
def _right_list_delim(self):
|
|
643
|
+
return "}"
|
|
644
|
+
|
|
645
|
+
def _left_func_delim(self):
|
|
646
|
+
return "["
|
|
647
|
+
|
|
648
|
+
def _right_func_delim(self):
|
|
649
|
+
return "]"
|
|
650
|
+
|
|
651
|
+
###########################################
|
|
652
|
+
# System -- change directory, etc.
|
|
653
|
+
###########################################
|
|
654
|
+
def chdir(self, dir):
|
|
655
|
+
"""
|
|
656
|
+
Change Mathematica's current working directory.
|
|
657
|
+
|
|
658
|
+
EXAMPLES::
|
|
659
|
+
|
|
660
|
+
sage: mathematica.chdir('/') # optional - mathematica
|
|
661
|
+
sage: mathematica('Directory[]') # optional - mathematica
|
|
662
|
+
"/"
|
|
663
|
+
"""
|
|
664
|
+
self.eval('SetDirectory["%s"]' % dir)
|
|
665
|
+
|
|
666
|
+
def _true_symbol(self):
|
|
667
|
+
return 'True'
|
|
668
|
+
|
|
669
|
+
def _false_symbol(self):
|
|
670
|
+
return 'False'
|
|
671
|
+
|
|
672
|
+
def _equality_symbol(self):
|
|
673
|
+
return '=='
|
|
674
|
+
|
|
675
|
+
def _assign_symbol(self):
|
|
676
|
+
return ":="
|
|
677
|
+
|
|
678
|
+
def _exponent_symbol(self):
|
|
679
|
+
"""
|
|
680
|
+
Return the symbol used to denote the exponent of a number in
|
|
681
|
+
Mathematica.
|
|
682
|
+
|
|
683
|
+
EXAMPLES::
|
|
684
|
+
|
|
685
|
+
sage: mathematica._exponent_symbol() # optional - mathematica
|
|
686
|
+
'*^'
|
|
687
|
+
|
|
688
|
+
::
|
|
689
|
+
|
|
690
|
+
sage: bignum = mathematica('10.^80') # optional - mathematica
|
|
691
|
+
sage: repr(bignum) # optional - mathematica
|
|
692
|
+
'1.*^80'
|
|
693
|
+
sage: repr(bignum).replace(mathematica._exponent_symbol(), 'e').strip() # optional - mathematica
|
|
694
|
+
'1.e80'
|
|
695
|
+
"""
|
|
696
|
+
return "*^"
|
|
697
|
+
|
|
698
|
+
def _object_class(self):
|
|
699
|
+
return MathematicaElement
|
|
700
|
+
|
|
701
|
+
def console(self, readline=True):
|
|
702
|
+
mathematica_console(readline=readline)
|
|
703
|
+
|
|
704
|
+
def _tab_completion(self):
|
|
705
|
+
a = self.eval('Names["*"]')
|
|
706
|
+
return a.replace('$', '').replace('\n \n>', '').replace(',', '').replace('}', '').replace('{', '').split()
|
|
707
|
+
|
|
708
|
+
def help(self, cmd):
|
|
709
|
+
return self.eval('? %s' % cmd)
|
|
710
|
+
|
|
711
|
+
def __getattr__(self, attrname):
|
|
712
|
+
if attrname[:1] == "_":
|
|
713
|
+
raise AttributeError
|
|
714
|
+
return MathematicaFunction(self, attrname)
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
@instancedoc
|
|
718
|
+
class MathematicaElement(ExpectElement):
|
|
719
|
+
def __getitem__(self, n):
|
|
720
|
+
return self.parent().new('%s[[%s]]' % (self._name, n))
|
|
721
|
+
|
|
722
|
+
def __getattr__(self, attrname):
|
|
723
|
+
self._check_valid()
|
|
724
|
+
if attrname[:1] == "_":
|
|
725
|
+
raise AttributeError
|
|
726
|
+
return MathematicaFunctionElement(self, attrname)
|
|
727
|
+
|
|
728
|
+
def __float__(self, precision=16):
|
|
729
|
+
P = self.parent()
|
|
730
|
+
return float(P.eval('N[%s,%s]' % (self.name(), precision)))
|
|
731
|
+
|
|
732
|
+
def _reduce(self):
|
|
733
|
+
return self.parent().eval('InputForm[%s]' % self.name()).strip()
|
|
734
|
+
|
|
735
|
+
def __reduce__(self):
|
|
736
|
+
return reduce_load, (self._reduce(), )
|
|
737
|
+
|
|
738
|
+
def _latex_(self):
|
|
739
|
+
z = self.parent().eval('TeXForm[%s]' % self.name())
|
|
740
|
+
i = z.find('=')
|
|
741
|
+
return z[i + 1:].strip()
|
|
742
|
+
|
|
743
|
+
def _repr_(self):
|
|
744
|
+
P = self.parent()
|
|
745
|
+
return P.get(self._name, ascii_art=False).strip()
|
|
746
|
+
|
|
747
|
+
def _sage_(self, locals={}):
|
|
748
|
+
r"""
|
|
749
|
+
Attempt to return a Sage version of this object.
|
|
750
|
+
|
|
751
|
+
This method works successfully when Mathematica returns a result
|
|
752
|
+
or list of results that consist only of:
|
|
753
|
+
|
|
754
|
+
- numbers, i.e. integers, floats, complex numbers;
|
|
755
|
+
- functions and named constants also present in Sage, where:
|
|
756
|
+
- Sage knows how to translate the function or constant's name
|
|
757
|
+
from Mathematica's naming scheme, or
|
|
758
|
+
- you provide a translation dictionary `locals`, or
|
|
759
|
+
- the Sage name for the function or constant is simply the
|
|
760
|
+
Mathematica name in lower case;
|
|
761
|
+
|
|
762
|
+
- symbolic variables whose names do not pathologically overlap with
|
|
763
|
+
objects already defined in Sage.
|
|
764
|
+
|
|
765
|
+
This method will not work when Mathematica's output includes:
|
|
766
|
+
|
|
767
|
+
- strings;
|
|
768
|
+
- functions unknown to Sage that are not specified in `locals`;
|
|
769
|
+
- Mathematica functions with different parameters/parameter order to
|
|
770
|
+
the Sage equivalent. In this case, define a function to do the
|
|
771
|
+
parameter conversion, and pass it in via the locals dictionary.
|
|
772
|
+
|
|
773
|
+
EXAMPLES:
|
|
774
|
+
|
|
775
|
+
Mathematica lists of numbers/constants become Sage lists of
|
|
776
|
+
numbers/constants::
|
|
777
|
+
|
|
778
|
+
sage: # optional - mathematica
|
|
779
|
+
sage: m = mathematica('{{1., 4}, Pi, 3.2e100, I}')
|
|
780
|
+
sage: s = m.sage(); s
|
|
781
|
+
[[1.00000000000000, 4], pi, 3.20000000000000*e100, I]
|
|
782
|
+
sage: s[1].n()
|
|
783
|
+
3.14159265358979
|
|
784
|
+
sage: s[3]^2
|
|
785
|
+
-1
|
|
786
|
+
|
|
787
|
+
::
|
|
788
|
+
|
|
789
|
+
sage: m = mathematica('x^2 + 5*y') # optional - mathematica
|
|
790
|
+
sage: m.sage() # optional - mathematica
|
|
791
|
+
x^2 + 5*y
|
|
792
|
+
|
|
793
|
+
::
|
|
794
|
+
|
|
795
|
+
sage: m = mathematica('Sin[Sqrt[1-x^2]] * (1 - Cos[1/x])^2') # optional - mathematica
|
|
796
|
+
sage: m.sage() # optional - mathematica
|
|
797
|
+
(cos(1/x) - 1)^2*sin(sqrt(-x^2 + 1))
|
|
798
|
+
|
|
799
|
+
::
|
|
800
|
+
|
|
801
|
+
sage: m = mathematica('NewFn[x]') # optional - mathematica
|
|
802
|
+
sage: m._sage_(locals={('NewFn', 1): sin}) # optional - mathematica
|
|
803
|
+
sin(x)
|
|
804
|
+
|
|
805
|
+
::
|
|
806
|
+
|
|
807
|
+
sage: var('bla') # optional - mathematica
|
|
808
|
+
bla
|
|
809
|
+
sage: m = mathematica('bla^2') # optional - mathematica
|
|
810
|
+
sage: bla^2 - m.sage() # optional - mathematica
|
|
811
|
+
0
|
|
812
|
+
|
|
813
|
+
::
|
|
814
|
+
|
|
815
|
+
sage: # optional - mathematica
|
|
816
|
+
sage: m = mathematica('bla^2')
|
|
817
|
+
sage: mb = m.sage()
|
|
818
|
+
sage: var('bla')
|
|
819
|
+
bla
|
|
820
|
+
sage: bla^2 - mb
|
|
821
|
+
0
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
AUTHORS:
|
|
825
|
+
|
|
826
|
+
- Felix Lawrence (2010-11-03): Major rewrite to use ._sage_repr() and
|
|
827
|
+
sage.calculus.calculus.symbolic_expression_from_string() for greater
|
|
828
|
+
compatibility, while still supporting conversion of symbolic
|
|
829
|
+
expressions.
|
|
830
|
+
|
|
831
|
+
TESTS:
|
|
832
|
+
|
|
833
|
+
Check that :issue:`28814` is fixed::
|
|
834
|
+
|
|
835
|
+
sage: mathematica('Exp[1000.0]').sage() # optional - mathematica
|
|
836
|
+
1.97007111401700e434
|
|
837
|
+
sage: mathematica('1/Exp[1000.0]').sage() # optional - mathematica
|
|
838
|
+
5.07595889754950e-435
|
|
839
|
+
sage: mathematica(RealField(100)(1/3)).sage() # optional - mathematica
|
|
840
|
+
0.3333333333333333333333333333335
|
|
841
|
+
"""
|
|
842
|
+
from sage.symbolic.expression import symbol_table
|
|
843
|
+
from sage.symbolic.constants import constants_name_table as constants
|
|
844
|
+
from sage.calculus.calculus import symbolic_expression_from_string
|
|
845
|
+
from sage.calculus.calculus import _find_func as find_func
|
|
846
|
+
|
|
847
|
+
# Get Mathematica's output and perform preliminary formatting
|
|
848
|
+
res = self._sage_repr()
|
|
849
|
+
if '"' in res:
|
|
850
|
+
raise NotImplementedError("String conversion from Mathematica \
|
|
851
|
+
does not work. Mathematica's output was: %s" % res)
|
|
852
|
+
|
|
853
|
+
# Find all the mathematica functions, constants and symbolic variables
|
|
854
|
+
# present in `res`. Convert MMA functions and constants to their
|
|
855
|
+
# Sage equivalents (if possible), using `locals` and
|
|
856
|
+
# `sage.symbolic.pynac.symbol_table['mathematica']` as translation
|
|
857
|
+
# dictionaries. If a MMA function or constant is not in either
|
|
858
|
+
# dictionary, then we use a variety of tactics listed in `autotrans`.
|
|
859
|
+
# If a MMA variable is not in any dictionary, then create an
|
|
860
|
+
# identically named Sage equivalent.
|
|
861
|
+
|
|
862
|
+
# Merge the user-specified locals dictionary and the symbol_table
|
|
863
|
+
# (locals takes priority)
|
|
864
|
+
lsymbols = symbol_table['mathematica'].copy()
|
|
865
|
+
lsymbols.update(locals)
|
|
866
|
+
|
|
867
|
+
# Strategies for translating unknown functions/constants:
|
|
868
|
+
autotrans = [str.lower, # Try it in lower case
|
|
869
|
+
_un_camel, # Convert `CamelCase` to `camel_case`
|
|
870
|
+
lambda x: x] # Try the original name
|
|
871
|
+
|
|
872
|
+
# Find the MMA funcs/vars/constants - they start with a letter.
|
|
873
|
+
# Exclude exponents (e.g. 'e8' from 4.e8)
|
|
874
|
+
p = re.compile(r'(?<!\.)[a-zA-Z]\w*')
|
|
875
|
+
for m in p.finditer(res):
|
|
876
|
+
# If the function, variable or constant is already in the
|
|
877
|
+
# translation dictionary, then just move on.
|
|
878
|
+
if m.group() in lsymbols:
|
|
879
|
+
pass
|
|
880
|
+
# Now try to translate all other functions -- try each strategy
|
|
881
|
+
# in `autotrans` and check if the function exists in Sage
|
|
882
|
+
elif m.end() < len(res) and res[m.end()] == '(':
|
|
883
|
+
for t in autotrans:
|
|
884
|
+
f = find_func(t(m.group()), create_when_missing=False)
|
|
885
|
+
if f is not None:
|
|
886
|
+
lsymbols[m.group()] = f
|
|
887
|
+
break
|
|
888
|
+
else:
|
|
889
|
+
raise NotImplementedError("Don't know a Sage equivalent \
|
|
890
|
+
for Mathematica function '%s'. Please specify one \
|
|
891
|
+
manually using the 'locals' dictionary" % m.group())
|
|
892
|
+
# Check if Sage has an equivalent constant
|
|
893
|
+
else:
|
|
894
|
+
for t in autotrans:
|
|
895
|
+
if t(m.group()) in constants:
|
|
896
|
+
lsymbols[m.group()] = constants[t(m.group())]
|
|
897
|
+
break
|
|
898
|
+
# If Sage has never heard of the variable, then
|
|
899
|
+
# symbolic_expression_from_string will automatically create it
|
|
900
|
+
try:
|
|
901
|
+
return symbolic_expression_from_string(res, lsymbols,
|
|
902
|
+
accept_sequence=True)
|
|
903
|
+
except Exception:
|
|
904
|
+
raise NotImplementedError("Unable to parse Mathematica \
|
|
905
|
+
output: %s" % res)
|
|
906
|
+
|
|
907
|
+
def __str__(self):
|
|
908
|
+
P = self._check_valid()
|
|
909
|
+
return P.get(self._name, ascii_art=True)
|
|
910
|
+
|
|
911
|
+
def __len__(self):
|
|
912
|
+
"""
|
|
913
|
+
Return the object's length, evaluated by mathematica.
|
|
914
|
+
|
|
915
|
+
EXAMPLES::
|
|
916
|
+
|
|
917
|
+
sage: len(mathematica([1,1.,2])) # optional - mathematica
|
|
918
|
+
3
|
|
919
|
+
|
|
920
|
+
AUTHORS:
|
|
921
|
+
- Felix Lawrence (2009-08-21)
|
|
922
|
+
"""
|
|
923
|
+
return int(self.Length())
|
|
924
|
+
|
|
925
|
+
@cached_method
|
|
926
|
+
def _is_graphics(self):
|
|
927
|
+
"""
|
|
928
|
+
Test whether the mathematica expression is graphics.
|
|
929
|
+
|
|
930
|
+
OUTPUT: boolean
|
|
931
|
+
|
|
932
|
+
EXAMPLES::
|
|
933
|
+
|
|
934
|
+
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica
|
|
935
|
+
sage: P._is_graphics() # optional - mathematica
|
|
936
|
+
True
|
|
937
|
+
"""
|
|
938
|
+
P = self._check_valid()
|
|
939
|
+
return P.eval('InputForm[%s]' % self.name()).strip().startswith('Graphics[')
|
|
940
|
+
|
|
941
|
+
def save_image(self, filename, ImageSize=600):
|
|
942
|
+
r"""
|
|
943
|
+
Save a mathematica graphics.
|
|
944
|
+
|
|
945
|
+
INPUT:
|
|
946
|
+
|
|
947
|
+
- ``filename`` -- string; the filename to save as. The
|
|
948
|
+
extension determines the image file format
|
|
949
|
+
|
|
950
|
+
- ``ImageSize`` -- integer; the size of the resulting image
|
|
951
|
+
|
|
952
|
+
EXAMPLES::
|
|
953
|
+
|
|
954
|
+
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica
|
|
955
|
+
sage: filename = tmp_filename() # optional - mathematica
|
|
956
|
+
sage: P.save_image(filename, ImageSize=800) # optional - mathematica
|
|
957
|
+
"""
|
|
958
|
+
P = self._check_valid()
|
|
959
|
+
if not self._is_graphics():
|
|
960
|
+
raise ValueError('mathematica expression is not graphics')
|
|
961
|
+
filename = os.path.abspath(filename)
|
|
962
|
+
s = 'Export["%s", %s, ImageSize->%s]' % (filename, self.name(),
|
|
963
|
+
ImageSize)
|
|
964
|
+
P.eval(s)
|
|
965
|
+
|
|
966
|
+
def _rich_repr_(self, display_manager, **kwds):
|
|
967
|
+
"""
|
|
968
|
+
Rich Output Magic Method.
|
|
969
|
+
|
|
970
|
+
See :mod:`sage.repl.rich_output` for details.
|
|
971
|
+
|
|
972
|
+
EXAMPLES::
|
|
973
|
+
|
|
974
|
+
sage: from sage.repl.rich_output import get_display_manager
|
|
975
|
+
sage: dm = get_display_manager()
|
|
976
|
+
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica
|
|
977
|
+
|
|
978
|
+
The following test requires a working X display on Linux so that the
|
|
979
|
+
Mathematica frontend can do the rendering (:issue:`23112`)::
|
|
980
|
+
|
|
981
|
+
sage: P._rich_repr_(dm) # optional - mathematica mathematicafrontend
|
|
982
|
+
OutputImagePng container
|
|
983
|
+
"""
|
|
984
|
+
if self._is_graphics():
|
|
985
|
+
OutputImagePng = display_manager.types.OutputImagePng
|
|
986
|
+
if display_manager.preferences.graphics == 'disable':
|
|
987
|
+
return
|
|
988
|
+
if OutputImagePng in display_manager.supported_output():
|
|
989
|
+
return display_manager.graphics_from_save(
|
|
990
|
+
self.save_image, kwds, '.png', OutputImagePng)
|
|
991
|
+
else:
|
|
992
|
+
OutputLatex = display_manager.types.OutputLatex
|
|
993
|
+
dmp = display_manager.preferences.text
|
|
994
|
+
if dmp is None or dmp == 'plain':
|
|
995
|
+
return
|
|
996
|
+
if dmp == 'latex' and OutputLatex in display_manager.supported_output():
|
|
997
|
+
return OutputLatex(self._latex_())
|
|
998
|
+
|
|
999
|
+
def show(self, ImageSize=600):
|
|
1000
|
+
r"""
|
|
1001
|
+
Show a mathematica expression immediately.
|
|
1002
|
+
|
|
1003
|
+
This method attempts to display the graphics immediately,
|
|
1004
|
+
without waiting for the currently running code (if any) to
|
|
1005
|
+
return to the command line. Be careful, calling it from within
|
|
1006
|
+
a loop will potentially launch a large number of external
|
|
1007
|
+
viewer programs.
|
|
1008
|
+
|
|
1009
|
+
INPUT:
|
|
1010
|
+
|
|
1011
|
+
- ``ImageSize`` -- integer; the size of the resulting image
|
|
1012
|
+
|
|
1013
|
+
OUTPUT:
|
|
1014
|
+
|
|
1015
|
+
This method does not return anything. Use :meth:`save` if you
|
|
1016
|
+
want to save the figure as an image.
|
|
1017
|
+
|
|
1018
|
+
EXAMPLES::
|
|
1019
|
+
|
|
1020
|
+
sage: Q = mathematica('Sin[x Cos[y]]/Sqrt[1-x^2]') # optional - mathematica
|
|
1021
|
+
sage: show(Q) # optional - mathematica
|
|
1022
|
+
Sin[x*Cos[y]]/Sqrt[1 - x^2]
|
|
1023
|
+
|
|
1024
|
+
The following example starts a Mathematica frontend to do the rendering
|
|
1025
|
+
(:issue:`28819`)::
|
|
1026
|
+
|
|
1027
|
+
sage: P = mathematica('Plot[Sin[x],{x,-2Pi,4Pi}]') # optional - mathematica
|
|
1028
|
+
sage: show(P) # optional - mathematica mathematicafrontend
|
|
1029
|
+
sage: P.show(ImageSize=800) # optional - mathematica mathematicafrontend
|
|
1030
|
+
"""
|
|
1031
|
+
from sage.repl.rich_output import get_display_manager
|
|
1032
|
+
dm = get_display_manager()
|
|
1033
|
+
dm.display_immediately(self, ImageSize=ImageSize)
|
|
1034
|
+
|
|
1035
|
+
def str(self):
|
|
1036
|
+
return str(self)
|
|
1037
|
+
|
|
1038
|
+
def _richcmp_(self, other, op):
|
|
1039
|
+
P = self.parent()
|
|
1040
|
+
if P.eval("%s < %s" % (self.name(), other.name())).strip() == 'True':
|
|
1041
|
+
return rich_to_bool(op, -1)
|
|
1042
|
+
elif P.eval("%s > %s" % (self.name(), other.name())).strip() == 'True':
|
|
1043
|
+
return rich_to_bool(op, 1)
|
|
1044
|
+
elif P.eval("%s == %s" % (self.name(), other.name())).strip() == 'True':
|
|
1045
|
+
return rich_to_bool(op, 0)
|
|
1046
|
+
return NotImplemented
|
|
1047
|
+
|
|
1048
|
+
def __bool__(self):
|
|
1049
|
+
"""
|
|
1050
|
+
Return whether this Mathematica element is not identical to ``False``.
|
|
1051
|
+
|
|
1052
|
+
EXAMPLES::
|
|
1053
|
+
|
|
1054
|
+
sage: bool(mathematica(True)) # optional - mathematica
|
|
1055
|
+
True
|
|
1056
|
+
sage: bool(mathematica(False)) # optional - mathematica
|
|
1057
|
+
False
|
|
1058
|
+
|
|
1059
|
+
In Mathematica, `0` cannot be used to express falsity::
|
|
1060
|
+
|
|
1061
|
+
sage: bool(mathematica(0)) # optional - mathematica
|
|
1062
|
+
True
|
|
1063
|
+
"""
|
|
1064
|
+
P = self._check_valid()
|
|
1065
|
+
cmd = '%s===%s' % (self._name, P._false_symbol())
|
|
1066
|
+
return P.eval(cmd).strip() != P._true_symbol()
|
|
1067
|
+
|
|
1068
|
+
def n(self, *args, **kwargs):
|
|
1069
|
+
r"""
|
|
1070
|
+
Numerical approximation by converting to Sage object first.
|
|
1071
|
+
|
|
1072
|
+
Convert the object into a Sage object and return its numerical
|
|
1073
|
+
approximation. See documentation of the function
|
|
1074
|
+
:func:`sage.misc.functional.n` for details.
|
|
1075
|
+
|
|
1076
|
+
EXAMPLES::
|
|
1077
|
+
|
|
1078
|
+
sage: mathematica('Pi').n(10) # optional -- mathematica
|
|
1079
|
+
3.1
|
|
1080
|
+
sage: mathematica('Pi').n() # optional -- mathematica
|
|
1081
|
+
3.14159265358979
|
|
1082
|
+
sage: mathematica('Pi').n(digits=10) # optional -- mathematica
|
|
1083
|
+
3.141592654
|
|
1084
|
+
"""
|
|
1085
|
+
return self._sage_().n(*args, **kwargs)
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
@instancedoc
|
|
1089
|
+
class MathematicaFunction(ExpectFunction):
|
|
1090
|
+
def _instancedoc_(self):
|
|
1091
|
+
M = self._parent
|
|
1092
|
+
return M.help(self._name)
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
@instancedoc
|
|
1096
|
+
class MathematicaFunctionElement(FunctionElement):
|
|
1097
|
+
def _instancedoc_(self):
|
|
1098
|
+
M = self._obj.parent()
|
|
1099
|
+
return M.help(self._name)
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
# An instance
|
|
1103
|
+
mathematica = Mathematica()
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
def reduce_load(X):
|
|
1107
|
+
return mathematica(X)
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
def mathematica_console(readline=True):
|
|
1111
|
+
from sage.repl.rich_output.display_manager import get_display_manager
|
|
1112
|
+
if not get_display_manager().is_in_terminal():
|
|
1113
|
+
raise RuntimeError('Can use the console only in the terminal. Try %%mathematica magics instead.')
|
|
1114
|
+
if not readline:
|
|
1115
|
+
os.system('math')
|
|
1116
|
+
return
|
|
1117
|
+
else:
|
|
1118
|
+
os.system('math-readline')
|
|
1119
|
+
return
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
# some tools for online interface
|
|
1123
|
+
|
|
1124
|
+
def request_wolfram_alpha(input, verbose=False):
|
|
1125
|
+
r"""
|
|
1126
|
+
Request Wolfram Alpha website.
|
|
1127
|
+
|
|
1128
|
+
INPUT:
|
|
1129
|
+
|
|
1130
|
+
- ``input`` -- string
|
|
1131
|
+
- ``verbose`` -- boolean (default: ``False``)
|
|
1132
|
+
|
|
1133
|
+
OUTPUT: json
|
|
1134
|
+
|
|
1135
|
+
EXAMPLES::
|
|
1136
|
+
|
|
1137
|
+
sage: from sage.interfaces.mathematica import request_wolfram_alpha
|
|
1138
|
+
sage: page_data = request_wolfram_alpha('integrate Sin[x]') # optional internet
|
|
1139
|
+
sage: [str(a) for a in sorted(page_data.keys())] # optional internet
|
|
1140
|
+
['queryresult']
|
|
1141
|
+
sage: [str(a) for a in sorted(page_data['queryresult'].keys())] # optional internet
|
|
1142
|
+
['datatypes',
|
|
1143
|
+
'encryptedEvaluatedExpression',
|
|
1144
|
+
'encryptedParsedExpression',
|
|
1145
|
+
'error',
|
|
1146
|
+
'host',
|
|
1147
|
+
'id',
|
|
1148
|
+
'inputstring',
|
|
1149
|
+
'numpods',
|
|
1150
|
+
'parsetimedout',
|
|
1151
|
+
'parsetiming',
|
|
1152
|
+
'pods',
|
|
1153
|
+
'recalculate',
|
|
1154
|
+
'related',
|
|
1155
|
+
'server',
|
|
1156
|
+
'sponsorCategories',
|
|
1157
|
+
'success',
|
|
1158
|
+
'timedout',
|
|
1159
|
+
'timedoutpods',
|
|
1160
|
+
'timing',
|
|
1161
|
+
'version']
|
|
1162
|
+
"""
|
|
1163
|
+
from urllib.parse import urlencode
|
|
1164
|
+
from urllib.request import Request, build_opener, HTTPCookieProcessor, HTTPSHandler
|
|
1165
|
+
import json
|
|
1166
|
+
from http.cookiejar import CookieJar
|
|
1167
|
+
from ssl import create_default_context as default_context
|
|
1168
|
+
|
|
1169
|
+
# we need cookies for this...
|
|
1170
|
+
cj = CookieJar()
|
|
1171
|
+
opener = build_opener(HTTPCookieProcessor(cj),
|
|
1172
|
+
HTTPSHandler(context=default_context()))
|
|
1173
|
+
# build initial query for code
|
|
1174
|
+
req = Request("https://www.wolframalpha.com/input/api/v1/code")
|
|
1175
|
+
resp = opener.open(req)
|
|
1176
|
+
# the website returns JSON containing the code
|
|
1177
|
+
page_data = json.loads(resp.read().decode("utf-8"))
|
|
1178
|
+
if "code" not in page_data:
|
|
1179
|
+
raise ValueError("Wolfram did not return a code")
|
|
1180
|
+
proxy_code = page_data['code']
|
|
1181
|
+
if verbose:
|
|
1182
|
+
print("Code: {}".format(proxy_code))
|
|
1183
|
+
print("Cookies: {}".format(cj))
|
|
1184
|
+
# now we can make a request
|
|
1185
|
+
# some parameters documented here:
|
|
1186
|
+
# https://products.wolframalpha.com/api/documentation/#parameter-reference
|
|
1187
|
+
# the following are the parameters used by the website
|
|
1188
|
+
params = {
|
|
1189
|
+
'assumptionsversion': '2',
|
|
1190
|
+
'async': 'true',
|
|
1191
|
+
'banners': 'raw',
|
|
1192
|
+
'debuggingdata': 'false',
|
|
1193
|
+
'format': 'image,plaintext,imagemap,sound,minput,moutput',
|
|
1194
|
+
'formattimeout': '8',
|
|
1195
|
+
'input': input,
|
|
1196
|
+
'output': 'JSON',
|
|
1197
|
+
'parsetimeout': '5',
|
|
1198
|
+
'podinfosasync': 'true',
|
|
1199
|
+
'proxycode': proxy_code,
|
|
1200
|
+
'recalcscheme': 'parallel',
|
|
1201
|
+
'sbsdetails': 'true',
|
|
1202
|
+
'scantimeout': '0.5',
|
|
1203
|
+
'sponsorcategories': 'true',
|
|
1204
|
+
'statemethod': 'deploybutton',
|
|
1205
|
+
'storesubpodexprs': 'true'}
|
|
1206
|
+
# # we can also change some parameters
|
|
1207
|
+
# params = {
|
|
1208
|
+
# 'assumptionsversion': '2',
|
|
1209
|
+
# 'banners': 'raw',
|
|
1210
|
+
# 'format': 'minput,moutput',
|
|
1211
|
+
# 'formattimeout': '8',
|
|
1212
|
+
# 'input': input,
|
|
1213
|
+
# 'output': 'JSON',
|
|
1214
|
+
# 'parsetimeout': '5',
|
|
1215
|
+
# 'proxycode': proxy_code,
|
|
1216
|
+
# 'scantimeout': '0.5',
|
|
1217
|
+
# 'storesubpodexprs': 'true'
|
|
1218
|
+
# }
|
|
1219
|
+
params = urlencode(params)
|
|
1220
|
+
url = "https://www.wolframalpha.com/input/json.jsp?%s" % params
|
|
1221
|
+
req = Request(url)
|
|
1222
|
+
req.add_header('Referer', "https://www.wolframalpha.com/input/") # seems important
|
|
1223
|
+
resp = opener.open(req)
|
|
1224
|
+
# the website returns JSON containing the code
|
|
1225
|
+
return json.loads(resp.read().decode("utf-8"))
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
def parse_moutput_from_json(page_data, verbose=False):
|
|
1229
|
+
r"""
|
|
1230
|
+
Return the list of outputs found in the json (with key ``'moutput'``).
|
|
1231
|
+
|
|
1232
|
+
INPUT:
|
|
1233
|
+
|
|
1234
|
+
- ``page_data`` -- json obtained from Wolfram Alpha
|
|
1235
|
+
- ``verbose`` -- boolean (default: ``False``)
|
|
1236
|
+
|
|
1237
|
+
OUTPUT: list of unicode strings
|
|
1238
|
+
|
|
1239
|
+
EXAMPLES::
|
|
1240
|
+
|
|
1241
|
+
sage: from sage.interfaces.mathematica import request_wolfram_alpha
|
|
1242
|
+
sage: from sage.interfaces.mathematica import parse_moutput_from_json
|
|
1243
|
+
sage: page_data = request_wolfram_alpha('integrate Sin[x]') # optional internet
|
|
1244
|
+
sage: parse_moutput_from_json(page_data) # optional internet
|
|
1245
|
+
['-Cos[x]']
|
|
1246
|
+
|
|
1247
|
+
::
|
|
1248
|
+
|
|
1249
|
+
sage: page_data = request_wolfram_alpha('Sin[x]') # optional internet
|
|
1250
|
+
sage: L = parse_moutput_from_json(page_data) # optional internet
|
|
1251
|
+
sage: sorted(L) # optional internet
|
|
1252
|
+
['-Cos[x]', '{x == 0}', '{x == Pi C[1], Element[C[1], Integers]}']
|
|
1253
|
+
|
|
1254
|
+
TESTS::
|
|
1255
|
+
|
|
1256
|
+
sage: page_data = request_wolfram_alpha('Integrate(Sin[z], y)') # optional internet
|
|
1257
|
+
sage: parse_moutput_from_json(page_data) # optional internet
|
|
1258
|
+
Traceback (most recent call last):
|
|
1259
|
+
...
|
|
1260
|
+
ValueError: asking wolframalpha.com was not successful
|
|
1261
|
+
"""
|
|
1262
|
+
queryresult = page_data['queryresult']
|
|
1263
|
+
if not queryresult['success']:
|
|
1264
|
+
raise ValueError('asking wolframalpha.com was not successful')
|
|
1265
|
+
if 'pods' not in queryresult:
|
|
1266
|
+
raise ValueError('json object contains no pods')
|
|
1267
|
+
pods = queryresult['pods']
|
|
1268
|
+
if verbose:
|
|
1269
|
+
print(" Query successful: {}".format(queryresult['success']))
|
|
1270
|
+
print(" Number of results: {}".format(len(pods)))
|
|
1271
|
+
L = []
|
|
1272
|
+
for i, result in enumerate(pods):
|
|
1273
|
+
if verbose:
|
|
1274
|
+
print(" Result #{}".format(i))
|
|
1275
|
+
print(" Title: {}".format(result['title']))
|
|
1276
|
+
if 'subpods' not in result:
|
|
1277
|
+
continue
|
|
1278
|
+
subpods = result['subpods']
|
|
1279
|
+
for j, subpod in enumerate(subpods):
|
|
1280
|
+
if verbose:
|
|
1281
|
+
print(" Subpod #{}".format(j))
|
|
1282
|
+
if 'minput' in subpod.keys():
|
|
1283
|
+
print(" MInput: {}".format(subpod['minput']))
|
|
1284
|
+
if 'moutput' in subpod.keys():
|
|
1285
|
+
print(" MOutput: {}".format(subpod['moutput']))
|
|
1286
|
+
if 'moutput' in subpod.keys():
|
|
1287
|
+
L.append(subpod['moutput'])
|
|
1288
|
+
return L
|
|
1289
|
+
|
|
1290
|
+
|
|
1291
|
+
def symbolic_expression_from_mathematica_string(mexpr):
|
|
1292
|
+
r"""
|
|
1293
|
+
Translate a mathematica string into a symbolic expression.
|
|
1294
|
+
|
|
1295
|
+
INPUT:
|
|
1296
|
+
|
|
1297
|
+
- ``mexpr`` -- string
|
|
1298
|
+
|
|
1299
|
+
OUTPUT: symbolic expression
|
|
1300
|
+
|
|
1301
|
+
EXAMPLES::
|
|
1302
|
+
|
|
1303
|
+
sage: from sage.interfaces.mathematica import symbolic_expression_from_mathematica_string
|
|
1304
|
+
sage: symbolic_expression_from_mathematica_string('-Cos[x]')
|
|
1305
|
+
-cos(x)
|
|
1306
|
+
"""
|
|
1307
|
+
from sage.symbolic.expression import symbol_table
|
|
1308
|
+
from sage.symbolic.constants import constants_name_table as constants
|
|
1309
|
+
from sage.calculus.calculus import symbolic_expression_from_string
|
|
1310
|
+
from sage.calculus.calculus import _find_func as find_func
|
|
1311
|
+
|
|
1312
|
+
expr = mexpr.replace('\n', ' ').replace('\r', '')
|
|
1313
|
+
expr = expr.replace('[', '(').replace(']', ')')
|
|
1314
|
+
expr = expr.replace('{', '[').replace('}', ']')
|
|
1315
|
+
lsymbols = symbol_table['mathematica'].copy()
|
|
1316
|
+
lsymbols_names_only = [s[0] for s in lsymbols]
|
|
1317
|
+
autotrans = [lambda x:x.lower(), # Try it in lower case
|
|
1318
|
+
_un_camel, # Convert `CamelCase` to `camel_case`
|
|
1319
|
+
lambda x: x] # Try the original name
|
|
1320
|
+
# Find the MMA funcs/vars/constants - they start with a letter.
|
|
1321
|
+
# Exclude exponents (e.g. 'e8' from 4.e8)
|
|
1322
|
+
p = re.compile(r'(?<!\.)[a-zA-Z]\w*')
|
|
1323
|
+
|
|
1324
|
+
for m in p.finditer(expr):
|
|
1325
|
+
# If the function, variable or constant is already in the
|
|
1326
|
+
# translation dictionary, then just move on.
|
|
1327
|
+
if m.group() in lsymbols_names_only:
|
|
1328
|
+
pass
|
|
1329
|
+
# Now try to translate all other functions -- try each strategy
|
|
1330
|
+
# in `autotrans` and check if the function exists in Sage
|
|
1331
|
+
elif m.end() < len(expr) and expr[m.end()] == '(':
|
|
1332
|
+
for t in autotrans:
|
|
1333
|
+
f = find_func(t(m.group()), create_when_missing=False)
|
|
1334
|
+
if f is not None:
|
|
1335
|
+
lsymbols[(m.group(), f.number_of_arguments())] = f
|
|
1336
|
+
break
|
|
1337
|
+
else:
|
|
1338
|
+
raise NotImplementedError("Don't know a Sage equivalent for Mathematica function '%s'." % m.group())
|
|
1339
|
+
# Check if Sage has an equivalent constant
|
|
1340
|
+
else:
|
|
1341
|
+
for t in autotrans:
|
|
1342
|
+
if t(m.group()) in constants:
|
|
1343
|
+
lsymbols[(m.group(), 0)] = constants[t(m.group())]
|
|
1344
|
+
break
|
|
1345
|
+
return symbolic_expression_from_string(expr, lsymbols, accept_sequence=True)
|