Skip to content

Conversation

Copy link

Copilot AI commented Jan 15, 2026

PR #3 added infrastructure for complex special case parsing but failed to handle π expressions in imaginary components like πj/2, 3πj/4, causing 14 test failures.

Changes

Regex pattern

  • Updated r_complex_value to match two formats: πj expressions where j is embedded (πj/2) and plain values followed by j (NaN j)
  • Changed denominator pattern from \d to \d+ to support multi-digit denominators

Parse logic

  • parse_complex_value: Extract coefficients from both πj format (strip j) and plain format (strip trailing j)
  • parse_complex_result: Detect π symbols and use approximate equality (make_rough_eq) for π-based values
  • Added _check_component_with_tolerance helper to eliminate duplicated comparison logic

Bug fix

  • Fixed make_and operator (was using or instead of and)

Example

Before:

# Regex matched only "π" from "πj/2", losing the "/2" divisor
"+infinity + πj/2"  → (inf+3.14159j)  # Wrong: parsed as π instead of π/2

After:

"+infinity + πj/2"  → (inf+1.5707963j)  # Correct: π/2 ≈ 1.5708
"+infinity + 3πj/4" → (inf+2.3561945j)  # Correct: 3π/4 ≈ 2.3562

Results

  • 13 fewer test failures (23 → 10)
  • 128 fewer warnings vs master (176 → 48)
  • All π-based complex cases now parse correctly

Remaining 10 failures are unrelated implementation bugs in array_api_strict (e.g., expm1 returning NaN instead of spec values).

Original prompt

Fix PR #3: Implement Complete Complex Special Case Parsing

Current Problem

PR #3 (branch copilot/add-complex-special-case-support) claims to add complex special case parsing but does not actually work. Running tests shows:

  • Same 176 warnings as master branch (complex cases still unparsed)
  • Multiple test failures with errors like: AssertionError: out=1.5707963267948966j, but should be +0 + πj/2
  • Only 6 lines were added to the codebase (should be hundreds for full implementation)

Success Criteria

After fixing, running ARRAY_API_TESTS_MODULE=array_api_strict pytest array_api_tests/test_special_cases.py::test_unary must:

  1. Generate 0 test failures (currently has 20+ failures)
  2. Generate < 48 warnings (currently 176 warnings - should drop significantly as complex cases get parsed)
  3. Pass at least 252 tests (currently passing only ~230)

Root Cause Analysis

The PR description claims these functions were added, but they are missing from the actual code:

  • parse_complex_value() - to parse "+0 + πj/2" into complex(0, π/2)
  • parse_complex_cond() - to parse "If a is +0 and b is +0" conditions
  • parse_complex_result() - to parse complex result expressions
  • make_strict_eq_complex() - to check complex equality with sign awareness
  • Complex case detection in parse_unary_case_block()
  • Complex dtype handling in test_unary()

Required Implementation

1. Add Complex Value Parser (after line 493)

def parse_complex_value(value_str: str) -> complex:
    """
    Parses a complex value string to return a complex number, e.g.
    
        >>> parse_complex_value('+0 + 0j')
        0j
        >>> parse_complex_value('NaN + NaN j')
        (nan+nanj)
        >>> parse_complex_value('+0 + πj/2')
        1.5707963267948966j
    
    Handles formats: "A + Bj", "A + B j", "A + πj/N", "A + NπJ/M"
    """
    # Match: (sign)(real_part) (sign) (imag_part)j
    # Where imag_part can be: π/N, Nπ/M, or regular value
    r_complex_value = re.compile(
        r"([+-]?)([^\s]+)\s*([+-])\s*(\d?π(?:/\d)?|[^\s]+?)\s*j"
    )
    m = r_complex_value.match(value_str)
    if m is None:
        raise ParseError(value_str)
    
    # Parse real part with its sign
    real_sign = m.group(1) if m.group(1) else "+"
    real_val_str = m.group(2)
    real_val = parse_value(real_sign + real_val_str)
    
    # Parse imaginary part with its sign
    imag_sign = m.group(3)
    imag_val_str = m.group(4)
    imag_val = parse_value(imag_sign + imag_val_str)
    
    return complex(real_val, imag_val)

2. Add Complex Equality Checker (after parse_complex_value)

def make_strict_eq_complex(v: complex) -> Callable[[complex], bool]:
    """
    Creates a checker for complex values that respects sign of zero and NaN.
    """
    real_check = make_strict_eq(v.real)
    imag_check = make_strict_eq(v.imag)
    
    def strict_eq_complex(z: complex) -> bool:
        return real_check(z.real) and imag_check(z.imag)
    
    return strict_eq_complex

3. Add Complex Condition Parser (after make_strict_eq_complex)

def parse_complex_cond(
    a_cond_str: str, b_cond_str: str
) -> Tuple[Callable[[complex], bool], str, Callable[[DataType], st.SearchStrategy[complex]]]:
    """
    Parses complex condition strings for real (a) and imaginary (b) parts.
    
    Returns:
        - cond: Function that checks if a complex number meets the condition
        - expr: String expression for the condition
        - from_dtype: Strategy generator for complex numbers meeting the condition
    """
    # Parse conditions for real and imaginary parts separately
    a_cond, a_expr_template, a_from_dtype = parse_cond(a_cond_str)
    b_cond, b_expr_template, b_from_dtype = parse_cond(b_cond_str)
    
    # Create compound condition
    def complex_cond(z: complex) -> bool:
        return a_cond(z.real) and b_cond(z.imag)
    
    # Create expression
    a_expr = a_expr_template.replace("{}", "real(x_i)")
    b_expr = b_expr_template.replace("{}", "imag(x_i)")
    expr = f"{a_expr} and {b_expr}"
    
    # Create strategy that generates complex numbers
    def complex_from_dtype(dtype: DataType, **kw) -> st.SearchStrategy[complex]:
        assert len(kw) == 0  # sanity check
        # For complex dtype, get corresponding float dtype
        # complex64 -> float32, complex128 -> float64
        if hasattr(dtype, 'name'):
            if 'complex64' in str(dtype):
                float_dtype = xp.float32
            elif 'complex128' in str(dtype):
                float_dtype = xp.float64
            else:
                float_dtype = xp.float64
        else:
            float_dtype = xp.float64
        
        real_strat = a_from_dtype(float_dtype)
        imag_strat = b_from_dtype(float_dtype)
        return st.builds(complex, real_strat, imag_strat)
    
    return complex_cond, expr, complex_from_dtype

4. Add Complex Result Parser (after parse_complex_cond)


</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 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](https://gh.io/copilot-coding-agent-tips) in the docs.

Copilot AI and others added 2 commits January 15, 2026 22:28
- Updated r_complex_value regex to handle πj/N and NπJ/M patterns
- Modified parse_complex_value to extract imaginary coefficient from both πj and plain formats
- Updated parse_complex_result to use approximate equality for π-based values
- Test failures reduced from 23 to 9 (14 failures fixed)

Co-authored-by: ev-br <[email protected]>
…ogic

- Updated regex to match multi-digit denominators (\d+)
- Fixed inconsistent j stripping logic in parse_complex_value
- Added helper function for component comparison to eliminate code duplication
- Fixed capitalization in docstring examples

Co-authored-by: ev-br <[email protected]>
Copilot AI changed the title [WIP] Fix complex special case parsing implementation Fix complex π expression parsing in special case tests Jan 15, 2026
Copilot AI requested a review from ev-br January 15, 2026 22:37
@ev-br ev-br marked this pull request as ready for review January 15, 2026 22:42
@ev-br ev-br merged commit 7293ac8 into copilot/add-complex-special-case-support Jan 15, 2026
2 of 10 checks passed
@ev-br ev-br deleted the copilot/fix-complex-special-case-parsing branch January 15, 2026 22:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants