spcl / spcl/dace

Better array indexing support in `pystr_to_symbolic`

Open
#2,052 0 comments 1 reaction 1 assignee Assigned to @Copilot View on GitHub
Dominant language
Python
Stars
593
Forks
163
Avg merge
2d 23h
Merged PRs (30d)
60

Description

When using `sympy.sympify` without context, SymPy considers all names to be scalar symbols. This means that if you try to sympify, e.g., `A[i, j, k]`, the following error will occur: `TypeError: 'Symbol' object is not subscriptable`. However, SymPy has support for array expressions, as described here: https://docs.sympy.org/latest/modules/tensor/array_expressions.html
A minimal example is the following:
```python
import sympy
from sympy.tensor.array.expressions import ArraySymbol

A = ArraySymbol("A", (3, 2, 4))
sym = sympy.sympify("A[i, j, k]", locals={'A': A})
```

In DaCe, a crucial utility method is `dace.symbolic.pystr_to_symbolic`, which converts a Python-compatible string expression to a SymPy-compatible symbolic expression. To enable the parsing of strings that contain array subscripts without special context, we currently utilize the following hack. We replace brackets with parentheses, which makes SymPy think that the array names correspond to functions. Specifically, in `dace/symbolic.py` and line 1327, we do the following:
```python
try:
return sympy_to_dace(sympy.sympify(expr, locals, evaluate=simplify), symbol_map)
except (TypeError, sympy.SympifyError): # Symbol object is not subscriptable
# Replace subscript expressions with function calls
expr = expr.replace('[', '(')
expr = expr.replace(']', ')')
return sympy_to_dace(sympy.sympify(expr, locals, evaluate=simplify), symbol_map)
```
Although this works well for simple expressions, it may fail with indirect accesses or more complicated expressions, e.g., when the array subscript is nested inside a comparison.

To address those issues, we want to update `pystr_to_symbolic` to use SymPy's ArraySymbols. We should amend the method to, when accepting a string as input, detect array subscripts, count the number of dimensions, create appropriate ArraySymbols, and pass the context to `sympy.sympify` through the `locals` dictionary parameter. To ensure that the updated method works properly, we should generate tests where the conditions in InterstateEdges or the branches of ConditionalBlocks are such complicated expressions, e.g., `ztp1[tmp_index_224, tmp_index_225] - v_ydcst_var_1_rtt > 0.0`.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.