array-api-shape-check 1.0.0__py3-none-any.whl → 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- array_api_shape_check/_main.py +35 -16
- {array_api_shape_check-1.0.0.dist-info → array_api_shape_check-1.0.1.dist-info}/METADATA +1 -1
- array_api_shape_check-1.0.1.dist-info/RECORD +8 -0
- array_api_shape_check-1.0.0.dist-info/RECORD +0 -8
- {array_api_shape_check-1.0.0.dist-info → array_api_shape_check-1.0.1.dist-info}/WHEEL +0 -0
- {array_api_shape_check-1.0.0.dist-info → array_api_shape_check-1.0.1.dist-info}/licenses/LICENSE +0 -0
- {array_api_shape_check-1.0.0.dist-info → array_api_shape_check-1.0.1.dist-info}/top_level.txt +0 -0
array_api_shape_check/_main.py
CHANGED
|
@@ -39,36 +39,46 @@ class SubscriptInfoFromShapeItemUnchecked(SubscriptInfoFromSubcriptItem):
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
@attrs.frozen(kw_only=True)
|
|
42
|
-
class SubscriptInfoFromShapeItemUnique(
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
class SubscriptInfoFromShapeItemUnique[BroadcastShape: tuple[int, ...] | None](
|
|
43
|
+
SubscriptInfoFromSubcriptItem
|
|
44
|
+
):
|
|
45
|
+
shape_broadcasted: BroadcastShape
|
|
46
|
+
"""The broadcast shape, or None for an inconsistent subscript."""
|
|
45
47
|
|
|
46
48
|
def __repr__(self) -> str:
|
|
47
49
|
if self.is_variable:
|
|
48
50
|
return f"*{self.name}:{self.shape_broadcasted}"
|
|
49
|
-
|
|
51
|
+
if self.shape_broadcasted is None:
|
|
52
|
+
return f"{self.name}:None"
|
|
53
|
+
return f"{self.name}:{cast('tuple[int, ...]', self.shape_broadcasted)[0]}"
|
|
50
54
|
|
|
51
55
|
|
|
52
56
|
@attrs.frozen(kw_only=True)
|
|
53
|
-
class SubscriptInfoFromShapeItem(
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
class SubscriptInfoFromShapeItem[BroadcastShape: tuple[int, ...] | None](
|
|
58
|
+
SubscriptInfoFromShapeItemUnchecked
|
|
59
|
+
):
|
|
60
|
+
shape_broadcasted: BroadcastShape
|
|
61
|
+
"""The broadcast shape, or None for an inconsistent subscript."""
|
|
56
62
|
|
|
57
63
|
def __repr__(self) -> str:
|
|
64
|
+
if self.shape_broadcasted is None:
|
|
65
|
+
current = self.shape_current if self.is_variable else self.shape_current[0]
|
|
66
|
+
return f"{'*' if self.is_variable else ''}{self.name}:{current}->None"
|
|
58
67
|
if self.is_variable:
|
|
59
68
|
if self.shape_current != self.shape_broadcasted:
|
|
60
69
|
return f"*{self.name}:{self.shape_current}->{self.shape_broadcasted}"
|
|
61
70
|
return f"*{self.name}:{self.shape_current}"
|
|
62
71
|
if self.shape_current != self.shape_broadcasted:
|
|
63
|
-
|
|
72
|
+
broadcasted = cast("tuple[int, ...]", self.shape_broadcasted)
|
|
73
|
+
return f"{self.name}:{self.shape_current[0]}->{broadcasted[0]}"
|
|
64
74
|
return f"{self.name}:{self.shape_current[0]}"
|
|
65
75
|
|
|
66
76
|
|
|
67
77
|
@attrs.frozen(kw_only=True)
|
|
68
|
-
class SubscriptInfoFromShape:
|
|
69
|
-
all: tuple[tuple[SubscriptInfoFromShapeItem, ...], ...]
|
|
78
|
+
class SubscriptInfoFromShape[BroadcastShape: tuple[int, ...] | None]:
|
|
79
|
+
all: tuple[tuple[SubscriptInfoFromShapeItem[BroadcastShape], ...], ...]
|
|
70
80
|
"""The subscript info grouped by order, then by operand"""
|
|
71
|
-
unique: dict[str, SubscriptInfoFromShapeItemUnique]
|
|
81
|
+
unique: dict[str, SubscriptInfoFromShapeItemUnique[BroadcastShape]]
|
|
72
82
|
"""The unique subscripts,
|
|
73
83
|
ignoring order and shapes not broadcasted,
|
|
74
84
|
sorted lexicographically by name"""
|
|
@@ -111,9 +121,14 @@ class InconsistentNdimErrorNoSolutions(InconsistentNdimError): # noqa: N818
|
|
|
111
121
|
|
|
112
122
|
|
|
113
123
|
class InconsistentShapeError(ValueError):
|
|
114
|
-
subscript_info: SubscriptInfoFromShape
|
|
124
|
+
subscript_info: SubscriptInfoFromShape[tuple[int, ...] | None]
|
|
115
125
|
|
|
116
|
-
def __init__(
|
|
126
|
+
def __init__(
|
|
127
|
+
self,
|
|
128
|
+
subscript_info: SubscriptInfoFromShape[tuple[int, ...] | None],
|
|
129
|
+
reason: str,
|
|
130
|
+
*args: object,
|
|
131
|
+
) -> None:
|
|
117
132
|
super().__init__("Inconsistent shapes: " + str(subscript_info.all) + f"\n {reason}", *args)
|
|
118
133
|
self.subscript_info = subscript_info
|
|
119
134
|
|
|
@@ -344,7 +359,7 @@ def _parse_shapes(
|
|
|
344
359
|
|
|
345
360
|
def check_shapes(
|
|
346
361
|
subscripts: str, /, *operands: Array | tuple[int | None, ...], names: str | None = None
|
|
347
|
-
) -> SubscriptInfoFromShape:
|
|
362
|
+
) -> SubscriptInfoFromShape[tuple[int, ...]]:
|
|
348
363
|
"""
|
|
349
364
|
Parse variable subscript ndims by solving linear equations.
|
|
350
365
|
|
|
@@ -435,12 +450,15 @@ def check_shapes(
|
|
|
435
450
|
info_flatten_keyed = [(i, item) for i, info_array in enumerate(info_all) for item in info_array]
|
|
436
451
|
errors = []
|
|
437
452
|
shape_broadcasted = {}
|
|
438
|
-
for key, group in groupby(
|
|
453
|
+
for key, group in groupby(
|
|
454
|
+
sorted(info_flatten_keyed, key=lambda x: x[1].name), key=lambda x: x[1].name
|
|
455
|
+
):
|
|
439
456
|
group_list = list(group)
|
|
440
457
|
shapes = [item.shape_current for _, item in group_list]
|
|
441
458
|
try:
|
|
442
459
|
shape_broadcasted[key] = np.broadcast_shapes(*shapes)
|
|
443
460
|
except ValueError:
|
|
461
|
+
shape_broadcasted[key] = None
|
|
444
462
|
inner_text = ", ".join([f"{shape} ({names_[i]})" for i, shape in group_list])
|
|
445
463
|
errors.append(f"Key {key}: shapes {inner_text} are not broadcastable")
|
|
446
464
|
|
|
@@ -475,4 +493,5 @@ def check_shapes(
|
|
|
475
493
|
if errors:
|
|
476
494
|
raise InconsistentShapeError(result, "\n".join(errors))
|
|
477
495
|
|
|
478
|
-
|
|
496
|
+
# No broadcast shape can be None unless an inconsistency was recorded.
|
|
497
|
+
return cast("SubscriptInfoFromShape[tuple[int, ...]]", result)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
array_api_shape_check/__init__.py,sha256=8i9ZV_x6HXtVd0g7N3ec190lQ1LUC2s93A9p-J3C9WI,940
|
|
2
|
+
array_api_shape_check/_main.py,sha256=jKI3eDWql14v2oXesGXeZE9_114hfp5D8TUaqKbMAY4,17808
|
|
3
|
+
array_api_shape_check/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
array_api_shape_check-1.0.1.dist-info/licenses/LICENSE,sha256=Otwb96xcK4QBqXXVdBKpLZVnc4mJuFTa8rsMUEpphMM,1061
|
|
5
|
+
array_api_shape_check-1.0.1.dist-info/METADATA,sha256=0DwyMEHAVpY908iaOjNLGR8uFSxDLLRfebEFnm0I89I,6179
|
|
6
|
+
array_api_shape_check-1.0.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
7
|
+
array_api_shape_check-1.0.1.dist-info/top_level.txt,sha256=pirw2DeaWnDU_rSg3CZ1MsE-tJWEvndYSQG0illDMkI,22
|
|
8
|
+
array_api_shape_check-1.0.1.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
array_api_shape_check/__init__.py,sha256=8i9ZV_x6HXtVd0g7N3ec190lQ1LUC2s93A9p-J3C9WI,940
|
|
2
|
-
array_api_shape_check/_main.py,sha256=VXDxm8ds6mjq9qiJ4BFNWJWXxjBZKMXZ7WafYvuICt4,16965
|
|
3
|
-
array_api_shape_check/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
array_api_shape_check-1.0.0.dist-info/licenses/LICENSE,sha256=Otwb96xcK4QBqXXVdBKpLZVnc4mJuFTa8rsMUEpphMM,1061
|
|
5
|
-
array_api_shape_check-1.0.0.dist-info/METADATA,sha256=6cj-qjtOx_MV44WBn5-mLIY2XnChx71cQNG8V_74jQY,6179
|
|
6
|
-
array_api_shape_check-1.0.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
7
|
-
array_api_shape_check-1.0.0.dist-info/top_level.txt,sha256=pirw2DeaWnDU_rSg3CZ1MsE-tJWEvndYSQG0illDMkI,22
|
|
8
|
-
array_api_shape_check-1.0.0.dist-info/RECORD,,
|
|
File without changes
|
{array_api_shape_check-1.0.0.dist-info → array_api_shape_check-1.0.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{array_api_shape_check-1.0.0.dist-info → array_api_shape_check-1.0.1.dist-info}/top_level.txt
RENAMED
|
File without changes
|