Better array indexing support in `pystr_to_symbolic` using SymPy ArraySymbols
Summary
This PR enhances pystr_to_symbolic to properly handle array indexing expressions by leveraging SymPy's ArraySymbol functionality, addressing limitations with the current bracket-to-parentheses fallback approach.
Problem
The current implementation of pystr_to_symbolic uses a simple hack when encountering array subscripts: it replaces [ with ( and ] with ), treating arrays as function calls. While this works for basic cases, it fails with complex expressions, especially when array subscripts are nested inside comparisons or other operations.
For example, this expression from interstate edges or conditional blocks would fail to parse correctly:
pystr_to_symbolic('ztp1[tmp_index_224, tmp_index_225] - v_ydcst_var_1_rtt > 0.0')
Solution
This PR implements a more robust approach using SymPy's ArraySymbol from sympy.tensor.array.expressions:
-
Array Detection: Added
_detect_array_accesses()function that parses expressions using AST analysis to identify array names and their dimensions -
Symbol Extraction: Added
_extract_symbols()function that intelligently extracts symbol names while filtering out built-in mathematical functions -
Smart ArraySymbol Integration: Creates appropriate
ArraySymbolinstances and provides them tosympy.sympify()for proper array expression parsing - Maintains Backward Compatibility: Falls back to the original approach when needed
Key Improvements
Before:
# Simple case works but uses function call representation
pystr_to_symbolic('A[i, j]') # Returns function call A(i, j)
# Complex expressions could fail
pystr_to_symbolic('ztp1[tmp_index_224, tmp_index_225] - v_ydcst_var_1_rtt > 0.0') # Error prone
After:
# Proper ArrayElement representation
pystr_to_symbolic('A[i, j]') # Returns ArrayElement A[i, j]
# Complex expressions work correctly
pystr_to_symbolic('ztp1[tmp_index_224, tmp_index_225] - v_ydcst_var_1_rtt > 0.0') # ✓ Works
# Mathematical operations with arrays
pystr_to_symbolic('sqrt(A[i, j] ** 2 + B[i, j] ** 2)') # ✓ Proper ArrayElements
# Mixed array/scalar expressions
pystr_to_symbolic('matrix[row, col] * factor + offset') # ✓ Works
Implementation Details
- Conditional ArraySymbol Usage: Only applies ArraySymbol approach when expressions won't be processed by the AST transformer (e.g., for comparisons)
-
Function Name Filtering: Prevents built-in functions like
sqrt,sin,cosfrom being treated as symbols - Graceful Fallback: Maintains the original bracket-to-parentheses approach as a fallback for edge cases
- Comprehensive Testing: Added 9 test cases covering simple arrays, complex expressions, nested access, and backward compatibility
Backward Compatibility
✅ All existing functionality preserved - non-array expressions work exactly as before
✅ Existing interstate edge and conditional block expressions continue to work
✅ Performance impact minimal - only processes expressions with detected arrays
Fixes #2052.
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.