I'm trying to define an equation on a manifold using SymPy, and SymPy's diffgeom package. Since this equation is input by a user, it's sent into the program as a string and is therefore defined prior to the manifold definition in the code. To perform meaningful calculations, I'm trying to replace the "sympified" symbols with symbols defined on the manifold.
Here's a function, supplied by the user.
H = sympify('m*a - f')
Coordinates for the manifold are also supplied by the user as strings.
# Variables defined as symbols (non-diffgeom)
a = Symbol('a')
f = Symbol('f')
And everything afterwards is automated.
from sympy.diffgeom import Manifold, Patch, CoordSystem
from sympy import sympify, Symbol
# Standard manifold definitions
M = Manifold(name='Temp', dim=2)
P = Patch('P', M)
R = CoordSystem('R', P, ['a','f'])
coords = R.coord_functions()
Dx = R.base_vectors()
print(H.diff(a)) # Returns 'm' as expected
print(Differential(H)(Dx[0])) # Returns '0' as expected
The first substitution works great. I can take derivatives as expected using Differential().
H = H.subs(a,coords[0])
print(H.diff(a)) # Returns '0' as expected
print(Differential(H)(Dx[0])) # Returns 'm' as expected
print(Differential(H)(Dx[1])) # Returns '0' as expected
The second substitution is where things get strange. The ().diff() command works fine and returns 0, since the new coordinates are defined on the manifold and not as standard symbols, but I can no longer take derivatives using Differential().
H = H.subs(f,coords[1])
print(H.diff(f)) # Returns '0' as expected
print(Differential(H)(Dx[0])) # Crashes code
print(Differential(H)(Dx[1])) # Also crashes code
It appears as if diffgeom is trying to perform a transformation to calculate the derivatives, but there shouldn't really be any transforming going on since this is all in the same coordinate system. Am I fundamentally missing something here? Or is there an easier method to parse strings as expressions on manifolds?
Here's the full error thrown. I really can't make much out of it other than SymPy is attempting to transform coordinates when I wouldn't expect it.
Traceback (most recent call last):
File "/Users/msparapa/Documents/Python/gprops/examples/test.py", line 37, in <module>
print(Differential(H)(Dx[0])) # Crashes code
File "/Users/msparapa/anaconda/lib/python3.5/site-packages/sympy/diffgeom/diffgeom.py", line 765, in __call__
return vector_fields[0].rcall(self._form_field)
File "/Users/msparapa/anaconda/lib/python3.5/site-packages/sympy/core/basic.py", line 538, in rcall
return Basic._recursive_call(self, args)
File "/Users/msparapa/anaconda/lib/python3.5/site-packages/sympy/core/basic.py", line 552, in _recursive_call
return expr_to_call(*on_args)
File "/Users/msparapa/anaconda/lib/python3.5/site-packages/sympy/diffgeom/diffgeom.py", line 592, in __call__
jac = self._coord_sys.jacobian(b._coord_sys, coords)
File "/Users/msparapa/anaconda/lib/python3.5/site-packages/sympy/diffgeom/diffgeom.py", line 277, in jacobian
to_sys, self._dummies).jacobian(self._dummies)
File "/Users/msparapa/anaconda/lib/python3.5/site-packages/sympy/diffgeom/diffgeom.py", line 270, in coord_tuple_transform_to
transf = self.transforms[to_sys]
KeyError: CoordSystem(R, Patch(P, Manifold(Temp, 2)), (a, f))
After further investigation, the cause was having Symbols of the same name. The fix is to essentially substitute using methods described here, or to use different naming conventions altogether.
To perform the substitution, I needed to swap all of the variables at once. This was done with the following block of code.
set = dict(zip([a,f],coords))
H = H.subs(set, simultaneous=True)
Where "a" and "f" are basic symbols, and "coords" is the list of symbols on the manifold. Substitutions not performed simultaneously, but rather sequentially, such as
set = dict(zip([a,f],coords))
H = H.subs(set)
throw the same error. I believe this is due to the fact that both "a" and "f" are buried within each manifold coordinate. To see where this exactly comes up, we can look at the Repr output of coords[0].
BaseScalarField(CoordSystem(Symbol('R'), Patch(Symbol('P'), Manifold(Symbol('M'), Integer(2))), Tuple(Symbol('f'), Symbol('a'))), Integer(0))
Both Symbol('f') and Symbol('a') show up under the coordinate system. What happens here is that when I substituted the second variable, f, in my expression, SymPy was looking at my manifold variable, a, and seeing a variable of the same name. Thus it attempted to not only substitute the basic symbol, f, but also the symbol f buried within my CoordSystem definition, probably then prompting a coordinate system transformation.