forked from gwiederhecker/ToPython
-
Notifications
You must be signed in to change notification settings - Fork 2
/
ToPython.wl
179 lines (166 loc) · 8.3 KB
/
ToPython.wl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
(* ::Package:: *)
(*This package provides a function to convert a Mathematica expression to numpy
----------------------------------------------------;
INPUT ARGUMENTS;
expression: your mathematica expression, it can be numbers, literals, complexes or lists;
numpy\[LetterSpace]prefix: string defining your Numpy import prefix, e.g.:
if your used "import numpy as np", your prefix should be the string "np"
if your used "from numpy import *", your prefix should be the empty string ""
;
OUTPUT;
the Numpy python-ready expression (to be copied as a string);
!The formatted expression will be copied ot your clipboard, ready to paste on Python!;
------------------------------------------------------;
Not tested for every possible combination; use at your risk, by Gustavo Wiederhecker with
modifications by David Zwicker
*)
BeginPackage["ToPython`"]
ToPython::usage = "ToPython[expression, NumpyPrefix->\"np\", Copy->False]
converts Mathematica expression to a Numpy compatible expression. Because Numpy can
be imported in several ways, you can specify the name of the numpy module using the
NumpyPrefix option. The additional option Copy allows you to copy the result to the clipboard"
ToPythonEquation::usage = "ToPythonEquation[equation, NumpyPrefix->\"np\", Copy->False]
converts a Mathematica equation to a Numpy compatible expression."
Begin["Private`"]
(* list of function heads that do not need to be enclosed in brackets *)
singleFunctions = {Log, Sin, Cos, Tan, Sinh, Cosh, Tanh};
Options[ToPython] = {NumpyPrefix -> "np", Copy -> False};
ToPython[expression_, OptionsPattern[]] :=
Module[
{numpyprefix = OptionValue[NumpyPrefix], copy = OptionValue[Copy
], result, greekrule, format, PythonForm, np, br, brackets, a, b, l,
m, args}
,
(* determine the correct numpy prefix *)
If[numpyprefix == "",
np = numpyprefix
,
np = numpyprefix <> "."
];
(* general function for formating output *)
format[pattern_String, args__] :=
Module[{s},
s = StringReplace[pattern, "numpy." -> np];
ToString @ StringForm[s, Sequence @@ PythonForm /@ List[
args]]
];
(* helper function deciding when to use brackets *)
br[a_] :=
If[AtomQ[a] || MemberQ[singleFunctions, Head[a]],
a
,
brackets[a]
];
PythonForm[brackets[a_]] := format["(``)", a];
(* special forms that are recognized *)
PythonForm[Times[-1, a_]] := format["-``", br[a]];
PythonForm[Power[a_, Rational[1, 2]]] := format["numpy.sqrt(``)",
a];
PythonForm[Times[a_, Power[b_, -1]]] := format["`` / ``", br[
a], br[b]];
(* special forms that are not supported *)
ToPython::hasDerivative = "Dervatives are not supported";
PythonForm[Derivative[___]] :=
(
Message[ToPython::hasDerivative];
Abort[]
);
(* Simple math *)
PythonForm[Rational[a_, b_]] := ToString[N[a / b, $MachinePrecision
], FortranForm];
PythonForm[a_Rational] := ToString[N[a, $MachinePrecision], FortranForm
];
PythonForm[Complex[a_, b_]] := format["complex(``, ``)", a, b
];
PythonForm[a_ * b__] :=
Module[{fs, bl = {b}},
fs = StringRiffle[ConstantArray["``", 1 + Length @ bl
], " * "];
format[fs, br @ a, Sequence @@ br /@ bl]
];
PythonForm[a_ + b_] := format["`` + ``", a, b];
PythonForm[Power[a_, b_]] := format["`` ** ``", br[a], br[b]]
;
PythonForm[Exp[a_]] := format["numpy.exp(``)", a];
(* Some basic functions *)
PythonForm[Max[a_, b_]] := format["numpy.maximum(`1`, `2`)",
a, b];
PythonForm[Min[a_, b_]] := format["numpy.minimum(`1`, `2`)",
a, b];
(* Some special functions *)
PythonForm[Arg[a_]] := format["numpy.angle(``)", a];
PythonForm[SphericalHarmonicY[l_, m_, a_, b_]] := format["special.sph_harm(``, ``, (``) % (2 * numpy.pi), (``) % numpy.pi)",
m, l, b, a];
PythonForm[Gamma[a_]] := format["special.gamma(``)", a];
PythonForm[Gamma[a_, b_]] := format["special.gamma(`1`) * special.gammaincc(`1`, `2`)",
a, b];
PythonForm[BesselI[0, b_]] := format["special.i0(``)", b];
PythonForm[BesselJ[0, b_]] := format["special.j0(``)", b];
PythonForm[BesselK[0, b_]] := format["special.k0(``)", b];
PythonForm[BesselY[0, b_]] := format["special.y0(``)", b];
PythonForm[BesselI[1, b_]] := format["special.i1(``)", b];
PythonForm[BesselJ[1, b_]] := format["special.j1(``)", b];
PythonForm[BesselK[1, b_]] := format["special.k1(``)", b];
PythonForm[BesselY[1, b_]] := format["special.y1(``)", b];
PythonForm[BesselI[a_, b_]] := format["special.iv(``, ``)", a,
b];
PythonForm[BesselJ[a_, b_]] := format["special.jv(``, ``)", a,
b];
PythonForm[BesselK[a_, b_]] := format["special.kn(``, ``)", a,
b];
PythonForm[BesselY[a_, b_]] := format["special.yn(``, ``)", a,
b];
(* Some functions that are not defined in numpy *)
PythonForm[Csc[a_]] := format["1 / numpy.sin(``)", a];
PythonForm[Sec[a_]] := format["1 / numpy.cos(``)", a];
PythonForm[Cot[a_]] := format["1 / numpy.tan(``)", a];
PythonForm[Csch[a_]] := format["1 / numpy.sinh(``)", a];
PythonForm[Sech[a_]] := format["1 / numpy.cosh(``)", a];
PythonForm[Coth[a_]] := format["1 / numpy.tanh(``)", a];
(* Handling arrays *)
PythonForm[a_NumericArray] := np <> "array(" <> StringReplace[
ToString @ Normal @ a, {"{" -> "[", "}" -> "]"}] <> ")";
PythonForm[List[args__]] := np <> "array([" <> StringRiffle[PythonForm
/@ List[args], ", "] <> "])";
(* Constants *)
PythonForm[\[Pi]] = np <> "pi";
PythonForm[E] = np <> "e";
(* Greek characters *)
greekrule = {"\[Alpha]" -> "alpha", "\[Beta]" -> "beta", "\[Gamma]"
-> "gamma", "\[Delta]" -> "delta", "\[Epsilon]" -> "epsilon", "\[CurlyEpsilon]"
-> "curlyepsilon", "\[Zeta]" -> "zeta", "\[Eta]" -> "eta", "\[Theta]"
-> "theta", "\[Iota]" -> "iota", "\[Kappa]" -> "kappa", "\[Lambda]"
-> "lamb", "\[Mu]" -> "mu", "\[Nu]" -> "nu", "\[Xi]" -> "xi", "\[Omicron]"
-> "omicron", "\[Pi]" -> "pi", "\[Rho]" -> "rho", "\[FinalSigma]" ->
"finalsigma", "\[Sigma]" -> "sigma", "\[Tau]" -> "tau", "\[Upsilon]"
-> "upsilon", "\[CurlyPhi]" -> "curlyphi", "\[Chi]" -> "chi", "\[Phi]"
-> "phi", "\[Psi]" -> "psi", "\[Omega]" -> "omega", "\[CapitalAlpha]"
-> "Alpha", "\[CapitalBeta]" -> "Beta", "\[CapitalGamma]" -> "Gamma",
"\[CapitalDelta]" -> "Delta", "\[CapitalEpsilon]" -> "CurlyEpsilon",
"\[CapitalZeta]" -> "Zeta", "\[CapitalEta]" -> "Eta", "\[CapitalTheta]"
-> "Theta", "\[CapitalIota]" -> "Iota", "\[CapitalKappa]" -> "Kappa",
"\[CapitalLambda]" -> "Lambda", "\[CapitalMu]" -> "Mu", "\[CapitalNu]"
-> "Nu", "\[CapitalXi]" -> "Xi", "\[CapitalOmicron]" -> "Omicron", "\[CapitalPi]"
-> "Pi", "\[CapitalRho]" -> "Rho", "\[CapitalSigma]" -> "Sigma", "\[CapitalTau]"
-> "Tau", "\[CapitalUpsilon]" -> "Upsilon", "\[CapitalPhi]" -> "CurlyPhi",
"\[CapitalChi]" -> "Chi", "\[CapitalPsi]" -> "Psi", "\[CapitalOmega]"
-> "Omega"};
plusminusrule = {"+ -" -> "-"};
(* Everything else *)
PythonForm[h_[args__]] := np <> ToLowerCase[PythonForm[h]] <>
"(" <> PythonForm[args] <> ")";
PythonForm[allOther_] := StringReplace[ToString[allOther, FortranForm
], greekrule];
result = StringReplace[PythonForm[expression], greekrule ~ Join
~ plusminusrule];
(* Copy results to clipboard *)
If[copy,
CopyToClipboard[result]
];
result
]
Options[ToPythonEquation] = {NumpyPrefix -> "np", Copy -> False};
ToPythonEquation[Equal[a_, b_], opts : OptionsPattern[]] :=
ToPython[a - b, opts]
End[]
EndPackage[]