0
$\begingroup$

I have an enormous algebraic expression in Mathematica that I want to export to Python. The expression per se is not complicated, more like a polynomial, but it contains some special functions defined from a Mathematical package (Package X, used in HEP calculations).

Here is an excerpt of the function:

1/Kallen[a^2, b^2, c^2 + d^2] k21 y21 DiscB[a^2, M1, mH1]

If I try to export a function such as Kallen[a^2, b^2, c^2 + d^2] as follows:

ResourceFunction["ToPythonFunction"][Function[{a, b, c}, Kallen[a, b, c]]]

the output is

lambda x1,x2,x3: ``.function(wolframclient.language.wlexpr('Function[{a, b, c}, Kallen[a, b, c]]'))(x1,x2,x3)

I would like Mathematica to export just an expression of the form:

Kallen(a, b, c)

when finding such a function in the general expression to be Python-exported; this would be great, because then I can define "by hand" the function Kallen (and all the other special functions as well) directly in the Python file later. In summary, I would like an output of the form:

lambda a, b, c, k21, y21, M1, mH1: pow(Kallen(pow(a, 2), pow(b, 2), pow(c, 2) + pow(d, 2)), -1) * k21 * y21 * DiscB(pow(a, 2), M1, mH1)

Is there a way to do this? Or maybe a better way to do the export?

$\endgroup$
1
  • 1
    $\begingroup$ ToString[InputForm[Kallen[a^2, b^2, c^2 + d^2]]] will turn that into a string and I think do pretty much everything except [] to () to be ready for Python. Then you can Print or do anything else with an ordinary string to put it into a file. Changing InputForm to TraditionalForm LOOKS like it does more of what you want BUT that is only for looking at while inside MMA and that is not what you want. $\endgroup$
    – Bill
    Commented Apr 8 at 17:57

1 Answer 1

0
$\begingroup$

Here is the pipeline that worked for me: Let us suppose you have an expression like the following:

-(1/Sqrt[Kallenλ[x, y, z]]) DiLog[(a^2 x + b^2)/(a^2 y - b^2 y), -x] Log[a c^2 x y]

where Log is the (natural) logarithm function defined in Mathematica, but the functions Kallenλ and DiLog are "not functions inherent to Mathematica", in the sense that they are given by a Mathematica package. The aim is to turn such an expression into a Python-readable one:

As suggested by @Bill, the idea is to turn our expression into a string:

expression = -(1/Sqrt[Kallen\[Lambda][x, y, z]]) DiLog[(a^2 x + b^2)/(a^2 y - b^2 y), -x] Log[a c^2 x y];
tostring = ToString[InputForm[expression]];
Export["/your/path/mathematica_expression.txt", tostring]

If you open the .txt file, the expression will look like as follows:

-((DiLog[(b^2 + a^2*x)/(a^2*y - b^2*y), -x]*Log[a*c^2*x*y])/Sqrt[Kallenλ[x, y, z]])

Parentheses have been set to guarantee the correct order of evaluation of the operations; additionally, a * symbol has been placed wherever a product applies. However, expressions like b^2 should be b**2; we need to change [] by (), and some special characters, such as λ, must be removed. Next, we continue working exclusively in Python:

The special characters can be removed as follows:

def search_and_replace(file_path, search_word, replace_word):
   with open(file_path, 'r') as file:
      file_contents = file.read()

      updated_contents = file_contents.replace(search_word, replace_word)

   with open(file_path, 'w') as file:
      file.write(updated_contents)

and so

search_and_replace("/your/path/mathematica_expression.txt", "Kallenλ", "Kallen")

will replace the instances of Kallenλ with Kallen. You can use the same function to remove other special characters. Please note that you have overwritten the .txt file.

Now, we use sympy's method parse_mathematica. The full documentation is here. By doing

from sympy.parsing.mathematica import parse_mathematica

with open("/your/path/mathematica_expression.txt", 'r') as file:
    file_name = file.read()

parsed_expression = parse_mathematica(file_name)

you will replace [] with (), and lowercase some functions such as Sin to sin. Finally, probably you would like to use Python libraries such as cmath, numpy, etc. Then, for example, we would like to replace every instance of sin with np.sin. I did this with the RegEx Python module:

import re
import numpy as np

patterns = [
(r'Conjugate\((.*?)\)', r'np.conjugate(\1)'),
(r'sin\((.*?)\)', r'np.sin(\1)'),
(r'cos\((.*?)\)', r'np.cos(\1)'),
(r'log\((.*?)\)', r'cmath.log(\1)'),
(r'sqrt\((.*?)\)', r'cmath.sqrt(\1)'),
(r're\((.*?)\)', r'np.real(\1)'),
(r'im\((.*?)\)', r'np.imag(\1)'),
(r'pi', r'np.pi')
]

# Apply replacements using regular expression substitution
def replacepatterns(input_string):
   for pattern, replacement in patterns:
      input_string = re.sub(pattern, replacement, input_string)
   return input_string

python_expression = replacepatterns(str(parsed_expression))

After this, your python_expression will look like:

DiLog((a**2*x + a**2*y - a**2*z + b**2*x - b**2*y + b**2*z - 2*c**2*x - x**2 + x*y + x*z + (-a**2 + b**2 - x)*cmath.sqrt(Kallen(x, y, z)))/(a**2*x + a**2*y - a**2*z + b**2*x - b**2*y + b**2*z - 2*c**2*x - x**2 + x*y + x*z - cmath.sqrt(Kallen(a**2, b**2, x))*cmath.sqrt(Kallen(x, y, z))), -x*(a**2*(-x - y + z + cmath.sqrt(Kallen(x, y, z))) - b**2*(x - y + z + cmath.sqrt(Kallen(x, y, z))) + x*(2*c**2 + x - y - z + cmath.sqrt(Kallen(x, y, z)))))

Of course, you can save this expression in a .py file and call it later or do whatever you want. To define a function from this expression, we can do:

from sympy import var

variables = var(
['x', 'y', 'z', 'a', 'b', 'c'])

x, y, z, a, b, c = variables

def our_function(a, b, c, x, y, z):
   return eval(python_expression)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.