Skip to content

Commit

Permalink
Fix BasicQubit.__hash__ not satisfying a==b implies hash(a)==hash(b) (#…
Browse files Browse the repository at this point in the history
…44)

* Fix BasicQubit.__hash__ not satisfying a==b implies hash(a)==hash(b)
  • Loading branch information
Strilanc authored and damiansteiger committed Apr 20, 2017
1 parent c4feb98 commit dd34daa
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 12 deletions.
9 changes: 7 additions & 2 deletions projectq/types/_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ def __eq__(self, other):
Args:
other (BasicQubit): BasicQubit to which to compare this one
"""
return (isinstance(other, self.__class__) and self.id == other.id and
if self.id == -1:
return self is other
return (isinstance(other, BasicQubit) and
self.id == other.id and
self.engine == other.engine)

def __ne__(self, other):
Expand All @@ -96,7 +99,9 @@ def __hash__(self):
Hash definition because of custom __eq__.
Enables storing a qubit in, e.g., a set.
"""
return hash((self.id, self.engine, object.__hash__(self)))
if self.id == -1:
return object.__hash__(self)
return hash((self.engine, self.id))


class Qubit(BasicQubit):
Expand Down
26 changes: 16 additions & 10 deletions projectq/types/_qubit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,21 +60,27 @@ def test_basic_qubit_comparison(id0, id1, expected):
assert qubit2 != qubit0
assert qubit2 != qubit1
# Same engines
if expected:
assert qubit0 == qubit1
else:
assert not (qubit0 == qubit1)
assert (qubit0 == qubit1) == expected


def test_basic_qubit_hash():
fake_engine = "Fake"
qubit0 = _qubit.BasicQubit(fake_engine, 0)
qubit1 = _qubit.BasicQubit(fake_engine, 1)
assert hash(qubit0) != hash(qubit1)
qubit0.id = -1
qubit1.id = -1
a = _qubit.BasicQubit(fake_engine, 1)
b = _qubit.BasicQubit(fake_engine, 1)
c = _qubit.WeakQubitRef(fake_engine, 1)
assert a == b and hash(a) == hash(b)
assert a == c and hash(a) == hash(c)

# For performance reasons, low ids should not collide.
assert len(set(hash(_qubit.BasicQubit(fake_engine, e))
for e in range(100))) == 100

# Important that weakref.WeakSet in projectq.cengines._main.py works.
assert hash(qubit0) != hash(qubit1)
# When id is -1, expect reference equality.
x = _qubit.BasicQubit(fake_engine, -1)
y = _qubit.BasicQubit(fake_engine, -1)
# Note hash(x) == hash(y) isn't technically a failure, but it's surprising.
assert x != y and hash(x) != hash(y)


@pytest.fixture
Expand Down

0 comments on commit dd34daa

Please sign in to comment.