Next: Package quantum_computing, Previous: Package pslq [Contents][Index]
Next: Functions in pytranslate, Up: Package pytranslate [Contents][Index]
pytranslate
package provides Maxima to Python translation functionality. The package is experimental, and the specifications of the functions in this package might change. It was written as a Google Summer of Code project by Lakshya A Agrawal (Undergraduate Student, IIIT-Delhi) in 2019. A detailed project report is available as a GitHub Gist.
The package needs to be loaded in a Maxima instance for use, by executing load("pytranslate");
The statements are converted to python3 syntax. The file pytranslate.py must be imported for all translations to run, as shown in example.
Example:
(%i1) load ("pytranslate")$
/* Define an example function to calculate factorial */ (%i2) pytranslate(my_factorial(x) := if (x = 1 or x = 0) then 1 else x * my_factorial(x - 1)); (%o2) def my_factorial(x, v = v): v = Stack({}, v) v.ins({"x" : x}) return((1 if ((v["x"] == 1) or (v["x"] == 0)) \ else (v["x"] * my_factorial((v["x"] + (-1)))))) m["my_factorial"] = my_factorial
(%i3) my_factorial(5); (%o3) 120
>>> from pytranslate import * >>> def my_factorial(x, v = v): ... v = Stack({}, v) ... v.ins({"x" : x}) ... return((1 if ((v["x"] == 1) or (v["x"] == 0)) \ ... else (v["x"] * my_factorial((v["x"] + (-1)))))) ... >>> my_factorial(5) 120
The Maxima to Python Translator works in two stages:
1. Conversion of the internal Maxima representation to a defined Intermediate Representation, henceforth referred as IR(mapping is present in share/pytranslate/maxima-to-ir.html)
2. The conversion of IR to Python.
Supported Maxima forms:
1. Numbers
(including complex numbers)
2. Assignment operators
3. Arithmetic operators
(+, -, *, ^, /, !)
4. Logical operators
(and, or, not)
5. Relational operators
(>
, <
, >=
, <=
, !=
, ==
)
6. Lists
7. Arrays
8. block
9. Function
and function calls
10. if
-else converted to Python conditionals
11. for
loops
12. lambda
form
The tests for pytranslate
are present at share/pytranslate/rtest_pytranslate.mac and can be run by executing batch(rtest_pytranslate, test);
Next: Extending pytranslate, Previous: Introduction to pytranslate, Up: Package pytranslate [Contents][Index]
Translates the expression expr to equivalent python3 statements. Output is printed in the stdout.
Example:
(%i1) load ("pytranslate")$
(%i2) pytranslate('(for i:8 step -1 unless i<3 do (print(i)))); (%o2) v["i"] = 8 while not((v["i"] < 3)): m["print"](v["i"]) v["i"] = (v["i"] + -1) del v["i"]
expr is evaluated, and the return value is used for translation. Hence, for statements like assignment, it might be useful to quote the statement:
(%i1) load ("pytranslate")$
(%i2) pytranslate(x:20); (%o2) 20
(%i3) pytranslate('(x:20)); (%o3) v["x"] = 20
Passing the optional parameter (print-ir) to pytranslate
as t, will print the internal IR representation of expr
and return the translated python3 code.
(%i1) load("pytranslate"); (%o1) pytranslate
(%i2) pytranslate('(plot3d(lambda([x, y], x^2+y^(-1)), [x, 1, 10], [y, 1, 10])), t); (body (funcall (element-array "m" (string "plot3d")) (lambda ((symbol "x") (symbol "y") (op-no-bracket = (symbol "v") (funcall (symbol "stack") (dictionary) (symbol "v")))) (op + (funcall (element-array (symbol "m") (string "pow")) (symbol "x") (num 2 0)) (funcall (element-array (symbol "m") (string "pow")) (symbol "y") (unary-op - (num 1 0))))) (struct-list (string "x") (num 1 0) (num 10 0)) (struct-list (string "y") (num 1 0) (num 10 0)))) (%o2) m["plot3d"](lambda x, y, v = Stack({}, v): (m["pow"](x, 2) + m["\ pow"](y, (-1))), ["x", 1, 10], ["y", 1, 10])
Displays the internal maxima form of expr
(%i4) show_form(a^b); ((mexpt) $a $b) (%o4) a^b
Previous: Functions in pytranslate, Up: Package pytranslate [Contents][Index]
Working of pytranslate:
$pytranslate
defined in share/pytranslate/pytranslate.lisp.
$pytranslate
calls the function maxima-to-ir
with the Maxima expression as an argument(henceforth referred as expr
).
maxima-to-ir
determines if expr
is atomic or non-atomic(lisp cons form). If atomic, atom-to-ir
is called with expr
which returns the IR for the atomic expression.atom-to-ir
in accordance with the IR.
expr
is non-atomic, the function cons-to-ir
is called with expr
as an argument.cons-to-ir
looks for (caar expr)
which specifies the type of expr
, in hash-table *maxima-direct-ir-map* and if the type is found, then appends the retrieved IR with the result of lisp call (mapcar #'maxima-to-ir (cdr expr))
, which applies maxima-to-ir function to all the elements present in the list. Effectively, recursively generate IR for all the elements present in expr
and append them to the IR map for the type.(%i9) show_form(a+b); ((MPLUS) $B $A)
(%i10) pytranslate(a+b, t); (body (op + (element-array (symbol "v") (string "b")) \ (element-array (symbol "v") (string "a")))) (%o10) (v["b"] + v["a"])
Here, operator + with internal maxima representation, (mplus)
is present in *maxima-direct-ir-map* and mapped to (op +)
to which the result of generating IR for all other elements of the list (a b), i.e. (ELEMENT-ARRAY (SYMBOL "v") (STRING "b")) (ELEMENT-ARRAY (SYMBOL "v") (STRING "a"))
is appended.
(caar expr)
is not found in *maxima-direct-ir-map*, then cons-to-ir
looks for the type in *maxima-special-ir-map* which returns the function to handle the translation of the type of expr
. cons-to-ir
then calls the returned function with argument expr
as an argument.(%i11) show_form(g(x) := x^2); ((mdefine simp) (($g) $x) ((mexpt) $x 2))
(%i12) pytranslate(g(x):=x^2, t); (body (body (func-def (symbol "g") ((symbol "x") (op-no-bracket = (symbol "v") (symbol "v"))) (body-indented (op-no-bracket = (symbol "v") (funcall (symbol "stack") \ (dictionary) (symbol "v"))) (obj-funcall (symbol "v") (symbol "ins") (dictionary \ ((string "x") (symbol "x")))) (funcall (symbol "return") (funcall (element-array (symbol "f") (string "pow")) (element-array (symbol "v") (string "x")) (num 2 0))))) (op-no-bracket = (element-array (symbol "f") (string "g")) \ (symbol "g")))) (%o12) def g(x, v = v): v = Stack({}, v) v.ins({"x" : x}) return(f["pow"](v["x"], 2)) f["g"] = g
Here, mdefine
, which is the type of expr
is present in *maxima-special-ir-map* which returns func-def-to-ir
as handler function, which is then called with expr
to generate the IR.
To define/modify translation for a type, add an entry to *maxima-direct-ir-map* if only a part of the IR needs to be generated and the rest can be appended, otherwise, for complete handling of expr
, add an entry to *maxima-special-ir-map* and define a function with the name defined in *maxima-special-ir-map* which returns the IR for the form. The function naming convention for ir generators is (type)-to-ir, where type is the (caar expr)
for expression(mdefine -> func-def-to-ir
). The function must return a valid IR for the specific type.
ir-to-python
is called with the generated ir
as an argument, which performs the codegen in a recursive manner.
ir-to-python
looks for lisp (car ir)
in the hash-table *ir-python-direct-templates*, which maps IR type to function handlers and calls the function returned with ir
as an argument.
Next: Package quantum_computing, Previous: Package pslq [Contents][Index]