Skip to content

Commit

Permalink
Improve / simplify GridQubit hash implementation to be the same as a …
Browse files Browse the repository at this point in the history
…complex number.
  • Loading branch information
daxfohl committed Jan 11, 2025
1 parent ac5a752 commit e89ddb3
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 39 deletions.
42 changes: 7 additions & 35 deletions cirq-core/cirq/devices/grid_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import abc
import functools
import sys
import weakref
from typing import Any, Dict, Iterable, List, Optional, Tuple, Set, TYPE_CHECKING, Union
from typing_extensions import Self
Expand All @@ -38,41 +39,12 @@ class _BaseGridQid(ops.Qid):

def __hash__(self) -> int:
if self._hash is None:
# This approach seems to perform better than traditional "random" hash in `Set`
# operations for typical circuits, as it reduces bucket collisions. Caveat: it does not
# include dimension, so sets with qudits of different dimensions but same location will
# have degenerate performance.
# Indexes the plane by concentric squares around the origin.
# | -2 -1 0 1 2
# ---+---------------
# -2 | 9 10 11 12 13
# -1 | 24 1 2 3 14
# 0 | 23 8 0 4 15
# 1 | 22 7 6 5 16
# 2 | 21 20 19 18 17
row = self._row
col = self._col

# The index of the square containing this point
n = max(abs(row), abs(col))
if n == 0:
self._hash = 0
return 0

# Determine the area of the inner square
start = (2 * n - 1) ** 2

# Determine the offset within the outer square
if row == -n: # Top edge
offset = n + col
elif col == n: # Right edge
offset = 3 * n + row
elif row == n: # Bottom edge
offset = 5 * n - col
else: # Left edge
offset = 7 * n - row

self._hash = hash(start + offset)
# Use the same hash algorithm as complex numbers, which performs better than a tuple
# hash. Note this does not include dimension, so sets with qubits at the same grid
# position but different dimensions will have poor performance, but such use cases are
# not anticipated. (Similarly, sets with grid qubits and raw complex numbers will
# perform poorly, but are not anticipated.)
self._hash = hash(self._row + self._col * sys.hash_info.imag)
return self._hash

def __eq__(self, other) -> bool:
Expand Down
9 changes: 5 additions & 4 deletions cirq-core/cirq/devices/line_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ class _BaseLineQid(ops.Qid):
_hash: Optional[int] = None

def __hash__(self) -> int:
# This approach seems to perform better than traditional "random" hash in `Set`
# operations for typical circuits, as it reduces bucket collisions. Caveat: it does not
# include dimension, so sets with qudits of different dimensions but same location will
# have degenerate performance.
if self._hash is None:
# Use the line index integer itself as the hash. This performs better than a tuple
# hash. Note this does not include dimension, so sets with qubits at the same line
# index but different dimensions will have poor performance, but such use cases are
# not anticipated. (Similarly, sets with line qubits and raw integers will perform
# poorly, but are not anticipated.)
self._hash = hash(self._x) # hash(i) returns i except for huge numbers
return self._hash

Expand Down

0 comments on commit e89ddb3

Please sign in to comment.