dace icon indicating copy to clipboard operation
dace copied to clipboard

Better array indexing support in `pystr_to_symbolic` using SymPy ArraySymbols

Open Copilot opened this issue 8 months ago • 0 comments

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:

  1. Array Detection: Added _detect_array_accesses() function that parses expressions using AST analysis to identify array names and their dimensions
  2. Symbol Extraction: Added _extract_symbols() function that intelligently extracts symbol names while filtering out built-in mathematical functions
  3. Smart ArraySymbol Integration: Creates appropriate ArraySymbol instances and provides them to sympy.sympify() for proper array expression parsing
  4. 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, cos from 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.

Copilot avatar Jun 17 '25 14:06 Copilot