Dimensionality using SymPy in the Physics Derivation Graph

navigation / documentation overview / Dimensionality

The commands here can be reproduced using

docker run -it --rm -v `pwd`:/scratch --workdir /scratch sympyonubuntu python3

using the Dockerfile https://github.com/allofphysicsgraph/ui_v8_website_flask_neo4j/blob/gh-pages/webserver_for_pdg/Dockerfile which provides SymPy 1.14.0 and antlr4-python3-runtime==4.11

How to convert Latex to SymPy with symbol IDs, then check dimensionality.

A Latex expression can serve as input for SymPy:

>>> from sympy.parsing.latex import parse_latex
>>> my_expr = parse_latex("x = r")
>>> my_expr
Eq(x, r)

Also, SymPy can print to Latex. A round-trip example:

>>> import sympy
>>> print(sympy.__version__)
1.12
>>> from sympy.parsing.latex import parse_latex
>>> print(sympy.latex(parse_latex("x = y")))
x = y

_Goal_: replace symbols like `r` with something like `pdg123`. Substituting in the Latex string doesn't work:

>>> from sympy.parsing.latex import parse_latex
>>> parse_latex("x = pdg123")
Eq(x, p*(dg*123))

That's not what we were seeking.

From the page substitution of variables is available in SymPy:

>>> import sympy
>>> x, y, z = sympy.symbols("x y z")
>>> expr = sympy.cos(x) + 1
>>> expr.subs(x, y)
cos(y) + 1

Use SymPy's substitution, but with arbitrary strings for replacement.

First, observe that the symbols can be extracted:

>>> from sympy.parsing.latex import parse_latex
>>> expr = parse_latex('x = y a')
>>> expr.atoms()
{x, a, y}

At this point `x, a, y` aren't SymPy symbols yet:

>>> from sympy.parsing.latex import parse_latex
>>> expr = parse_latex('x = y a')
>>> expr.atoms()
{x, a, y}
>>> a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

Declare the symbols using dynamic execution ([Pythons' `exec`](https://docs.python.org/3/library/functions.html#exec)):

>>> import sympy
>>> from sympy.parsing.latex import parse_latex
>>> expr = parse_latex('x = y a')
>>> for this_symb in expr.atoms():
    my_str = str(this_symb)+" = sympy.Symbol('"+str(this_symb)+"')"
    exec(my_str)

>>> type(x)
<class 'sympy.core.symbol.Symbol'>

>>> revised_expr = expr.subs(x, sympy.Symbol('pdg12')).subs(a, sympy.Symbol('pdg99')).subs(y, sympy.Symbol('pdg00'))
>>> revised_expr
Eq(pdg12, pdg00*pdg99)

That's what we wanted. We are now treating `pdg12` as a symbol registered with SymPy.

# _Goal_: consistent dimensionality of symbols in an expression

>>> from sympy.parsing.latex import parse_latex
>>> from sympy.physics.units import mass, length, time, temperature, luminous_intensity, amount_of_substance, charge
>>> from sympy.physics.units.systems.si import dimsys_SI  # type: ignore

>>> expr = parse_latex('x = y a')
>>> for this_symb in expr.atoms():
    my_str = str(this_symb)+" = sympy.Symbol('"+str(this_symb)+"')"
    exec(my_str)

>>> revised_expr = expr.subs(x, sympy.Symbol('pdg12')).subs(a, sympy.Symbol('pdg99')).subs(y, sympy.Symbol('pdg00'))

>>> pdg12 = (mass**2)*(time**3)
>>> pdg00 = (mass**2)
>>> pdg99 = (time**3)

Now that the variables have dimensions, we can check for consistency:

>>> dimsys_SI.equivalent_dims(pdg12, pdg00*pdg99)
True

For reasons I don't understand, `equivalent_dims` doesn't seem to unpack `revised_expr`

>>> dimsys_SI.equivalent_dims(revised_expr.lhs, revised_expr.rhs)
False

even though we can confirm they are comprised of these symbols

>>> revised_expr.lhs
pdg12
>>> revised_expr.rhs
pdg00*pdg99

Here's the ugly hack to check dimensions:

>>> dimsys_SI.equivalent_dims(eval(str(revised_expr.lhs)), eval(str(revised_expr.rhs)))
True