Skip to content

Commit 57eb673

Browse files
Copilotev-br
andcommitted
Add π parsing support for complex values
- Added r_complex_value regex pattern to capture complex numbers with π expressions - Added parse_complex_value() function to parse complex value strings - Regex correctly handles expressions like "+0 + πj/2" by capturing denominator after 'j' - Supports formats: "πj/2", "π/2j", "NaN + NaN j", etc. - All test cases pass including the critical "+0 + πj/2" case Co-authored-by: ev-br <2133832+ev-br@users.noreply.github.com>
1 parent ab78891 commit 57eb673

2 files changed

Lines changed: 110 additions & 0 deletions

File tree

array_api_tests/test_special_cases.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ def abs_cond(i: float) -> bool:
128128
}
129129
r_value = re.compile(r"([+-]?)(.+)")
130130
r_pi = re.compile(r"(\d?)π(?:/(\d))?")
131+
r_complex_value = re.compile(
132+
r"([+-]?)([^\s]+)\s*([+-])\s*([^\s]+)\s*j\s*(?:/(\d+))?"
133+
)
131134

132135

133136
@dataclass
@@ -167,6 +170,38 @@ def parse_value(value_str: str) -> float:
167170
return value
168171

169172

173+
def parse_complex_value(value_str: str) -> complex:
174+
"""
175+
Parses a complex value string to return a complex number, e.g.
176+
177+
>>> parse_complex_value('+0 + 0j')
178+
0j
179+
>>> parse_complex_value('+0 + πj/2')
180+
1.5707963267948966j
181+
>>> parse_complex_value('NaN + NaN j')
182+
(nan+nanj)
183+
184+
"""
185+
m = r_complex_value.match(value_str)
186+
if m is None:
187+
raise ParseError(value_str)
188+
189+
# Parse real part
190+
real_sign = m.group(1) or '+'
191+
real_value_str = real_sign + m.group(2)
192+
real_part = parse_value(real_value_str)
193+
194+
# Parse imaginary part
195+
imag_sign = m.group(3)
196+
imag_value_str = imag_sign + m.group(4)
197+
# Check if there's a denominator (group 5)
198+
if m.group(5):
199+
imag_value_str += '/' + m.group(5)
200+
imag_part = parse_value(imag_value_str)
201+
202+
return complex(real_part, imag_part)
203+
204+
170205
r_code = re.compile(r"``([^\s]+)``")
171206
r_approx_value = re.compile(
172207
rf"an implementation-dependent approximation to {r_code.pattern}"

test_pi_parsing.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Simple test to validate π parsing in complex values
4+
"""
5+
import sys
6+
import math
7+
8+
# Add the array_api_tests module to the path
9+
sys.path.insert(0, '/home/runner/work/array-api-tests/array-api-tests')
10+
11+
from array_api_tests.test_special_cases import parse_complex_value, parse_value
12+
13+
def test_parse_value_pi():
14+
"""Test that parse_value correctly handles π expressions"""
15+
# Test simple π
16+
result = parse_value('π')
17+
assert abs(result - math.pi) < 1e-10, f"Expected {math.pi}, got {result}"
18+
print("✓ parse_value('π') works")
19+
20+
# Test π/2
21+
result = parse_value('π/2')
22+
expected = math.pi / 2
23+
assert abs(result - expected) < 1e-10, f"Expected {expected}, got {result}"
24+
print(f"✓ parse_value('π/2') = {result}")
25+
26+
# Test 3π/4
27+
result = parse_value('3π/4')
28+
expected = 3 * math.pi / 4
29+
assert abs(result - expected) < 1e-10, f"Expected {expected}, got {result}"
30+
print(f"✓ parse_value('3π/4') = {result}")
31+
32+
def test_parse_complex_value():
33+
"""Test that parse_complex_value correctly handles complex values with π"""
34+
# Test +0 + 0j
35+
result = parse_complex_value('+0 + 0j')
36+
expected = complex(0.0, 0.0)
37+
assert result == expected, f"Expected {expected}, got {result}"
38+
print(f"✓ parse_complex_value('+0 + 0j') = {result}")
39+
40+
# Test the critical case: +0 + πj/2
41+
result = parse_complex_value('+0 + πj/2')
42+
expected = complex(0.0, math.pi / 2)
43+
assert abs(result.real - expected.real) < 1e-10, f"Real part mismatch"
44+
assert abs(result.imag - expected.imag) < 1e-10, f"Imaginary part mismatch: expected {expected.imag}, got {result.imag}"
45+
print(f"✓ parse_complex_value('+0 + πj/2') = {result}")
46+
print(f" Real part: {result.real}")
47+
print(f" Imaginary part: {result.imag} (expected {math.pi/2})")
48+
49+
# Test NaN + NaN j
50+
result = parse_complex_value('NaN + NaN j')
51+
assert math.isnan(result.real), f"Expected NaN for real part, got {result.real}"
52+
assert math.isnan(result.imag), f"Expected NaN for imaginary part, got {result.imag}"
53+
print(f"✓ parse_complex_value('NaN + NaN j') = {result}")
54+
55+
# Test -0 - πj/4
56+
result = parse_complex_value('-0 - πj/4')
57+
expected = complex(-0.0, -math.pi / 4)
58+
assert abs(result.imag - expected.imag) < 1e-10, f"Imaginary part mismatch"
59+
print(f"✓ parse_complex_value('-0 - πj/4') = {result}")
60+
61+
if __name__ == '__main__':
62+
print("Testing π parsing in complex values...")
63+
print()
64+
65+
try:
66+
test_parse_value_pi()
67+
print()
68+
test_parse_complex_value()
69+
print()
70+
print("✅ All tests passed!")
71+
except Exception as e:
72+
print(f"\n❌ Test failed: {e}")
73+
import traceback
74+
traceback.print_exc()
75+
sys.exit(1)

0 commit comments

Comments
 (0)