Skip to content

Commit f0d395d

Browse files
maffoorht
authored andcommitted
Cache the hash of frozen circuits to avoid recomputing (quantumlib#5738)
This follows what we previously did for GridQubit, but reworked to use `_compat.cached_method` and to compute the hash lazily.
1 parent c8d6166 commit f0d395d

File tree

3 files changed

+25
-15
lines changed

3 files changed

+25
-15
lines changed

cirq-core/cirq/circuits/frozen_circuit.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,20 @@ def __init__(
5555
def moments(self) -> Sequence['cirq.Moment']:
5656
return self._moments
5757

58-
def __hash__(self):
58+
@_compat.cached_method
59+
def __hash__(self) -> int:
60+
# Explicitly cached for performance
5961
return hash((self.moments,))
6062

63+
def __getstate__(self):
64+
# Don't save hash when pickling; see #3777.
65+
state = self.__dict__
66+
hash_cache = _compat._method_cache_name(self.__hash__)
67+
if hash_cache in state:
68+
state = state.copy()
69+
del state[hash_cache]
70+
return state
71+
6172
@_compat.cached_method
6273
def _num_qubits_(self) -> int:
6374
return len(self.all_qubits())

cirq-core/cirq/devices/grid_qubit.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import numpy as np
2121

22-
from cirq import ops, protocols
22+
from cirq import _compat, ops, protocols
2323

2424
if TYPE_CHECKING:
2525
import cirq
@@ -294,23 +294,19 @@ class GridQubit(_BaseGridQid):
294294
cirq.GridQubit(5, 4)
295295
"""
296296

297-
def __init__(self, row: int, col: int):
298-
super().__init__(row, col)
299-
self._hash = super().__hash__()
300-
301297
def __getstate__(self):
302298
# Don't save hash when pickling; see #3777.
303-
state = self.__dict__.copy()
304-
del state['_hash']
299+
state = self.__dict__
300+
hash_key = _compat._method_cache_name(self.__hash__)
301+
if hash_key in state:
302+
state = state.copy()
303+
del state[hash_key]
305304
return state
306305

307-
def __setstate__(self, state):
308-
self.__dict__.update(state)
309-
self._hash = super().__hash__()
310-
311-
def __hash__(self):
306+
@_compat.cached_method
307+
def __hash__(self) -> int:
312308
# Explicitly cached for performance (vs delegating to Qid).
313-
return self._hash
309+
return super().__hash__()
314310

315311
def __eq__(self, other):
316312
# Explicitly implemented for performance (vs delegating to Qid).

cirq-core/cirq/devices/grid_qubit_test.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import pytest
2020

2121
import cirq
22+
from cirq import _compat
2223

2324

2425
def test_init():
@@ -43,7 +44,9 @@ def test_eq():
4344
def test_pickled_hash():
4445
q = cirq.GridQubit(3, 4)
4546
q_bad = cirq.GridQubit(3, 4)
46-
q_bad._hash += 1
47+
_ = hash(q_bad) # compute hash to ensure it is cached.
48+
hash_key = _compat._method_cache_name(cirq.GridQubit.__hash__)
49+
setattr(q_bad, hash_key, getattr(q_bad, hash_key) + 1)
4750
assert q_bad == q
4851
assert hash(q_bad) != hash(q)
4952
data = pickle.dumps(q_bad)

0 commit comments

Comments
 (0)