Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions parity_tensor/parity_tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,19 @@ class ParityTensor:
Each dimension of the tensor is composed of an even and an odd part, represented as a pair of integers.
"""

_arrow: tuple[bool, ...]

Copilot AI Jul 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The _arrow attribute is declared without a default value, but other attributes like _parity and _mask have default values of None. This inconsistency could cause initialization issues if arrow is not provided during object creation.

Suggested change
_arrow: tuple[bool, ...]
_arrow: tuple[bool, ...] = ()

Copilot uses AI. Check for mistakes.
_edges: tuple[tuple[int, int], ...]
_tensor: torch.Tensor
_parity: tuple[torch.Tensor, ...] | None = None
_mask: torch.Tensor | None = None

@property
def arrow(self) -> tuple[bool, ...]:
"""
The arrow of the tensor, represented as a tuple of booleans indicating the order of the fermion operators.
"""
return self._arrow

@property
def edges(self) -> tuple[tuple[int, int], ...]:
"""
Expand Down Expand Up @@ -80,6 +88,7 @@ def permute(self, before_by_after: tuple[int, ...]) -> ParityTensor:
"""
assert set(before_by_after) == set(range(self.tensor.dim())), "Permutation indices must cover all dimensions."

arrow = tuple(self.arrow[i] for i in before_by_after)
edges = tuple(self.edges[i] for i in before_by_after)
tensor = self.tensor.permute(before_by_after)
parity = tuple(self.parity[i] for i in before_by_after)
Expand All @@ -98,13 +107,15 @@ def permute(self, before_by_after: tuple[int, ...]) -> ParityTensor:

return dataclasses.replace(
self,
_arrow=arrow,
_edges=edges,
_tensor=tensor,
_parity=parity,
_mask=mask,
)

def __post_init__(self) -> None:
assert len(self._arrow) == self._tensor.dim(), f"Arrow length ({len(self._arrow)}) must match tensor dimensions ({self._tensor.dim()})."
assert len(self._edges) == self._tensor.dim(), f"Edges length ({len(self._edges)}) must match tensor dimensions ({self._tensor.dim()})."
for dim, (even, odd) in zip(self._tensor.shape, self._edges):
assert even >= 0 and odd >= 0 and dim == even + odd, f"Dimension {dim} must equal sum of even ({even}) and odd ({odd}) parts, and both must be non-negative."
Expand All @@ -126,6 +137,7 @@ def _validate_edge_compatibility(self, other: ParityTensor) -> None:
"""
Validate that the edges of two ParityTensor instances are compatible for arithmetic operations.
"""
assert self._arrow == other.arrow, f"Arrows must match for arithmetic operations. Got {self._arrow} and {other.arrow}."

Copilot AI Jul 31, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The assertion accesses other.arrow (property) while comparing to self._arrow (private attribute). For consistency, either use other._arrow or self.arrow to maintain symmetry in the comparison.

Suggested change
assert self._arrow == other.arrow, f"Arrows must match for arithmetic operations. Got {self._arrow} and {other.arrow}."
assert self.arrow == other.arrow, f"Arrows must match for arithmetic operations. Got {self.arrow} and {other.arrow}."

Copilot uses AI. Check for mistakes.
assert self._edges == other.edges, f"Edges must match for arithmetic operations. Got {self._edges} and {other.edges}."

def __pos__(self) -> ParityTensor:
Expand Down