Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add then method for composing two Clifford tableaux #4096

Merged
merged 23 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d680b29
Move `import DensePauliString` under CliffordTableau into runtime
BichengYing May 6, 2021
70283c4
Add merged_with method of two clifford tableau
BichengYing May 9, 2021
701f0df
Fix lint and coverage error
BichengYing May 9, 2021
e086c41
Varying the seed in the loop
BichengYing May 10, 2021
ae82bcd
Merge branch 'master' into single_clifford
BichengYing May 10, 2021
733c738
Address the comments and rename the function to `then`
BichengYing May 12, 2021
c7877e4
Ignore the pylint warning
BichengYing May 13, 2021
3e341c5
Minor update for more comments
BichengYing May 14, 2021
4d84529
Merge branch 'master' into single_clifford
BichengYing May 14, 2021
6a19c8b
Update cirq-core/cirq/qis/clifford_tableau.py
BichengYing May 15, 2021
356b1ed
Add dimension and type check and corresponding test.
BichengYing May 15, 2021
ddc3ca7
Update cirq-core/cirq/qis/clifford_tableau.py
BichengYing May 17, 2021
ca17267
Update cirq-core/cirq/qis/clifford_tableau.py
BichengYing May 17, 2021
4acbcaf
Add more comments
BichengYing May 18, 2021
75207e5
Compute num_ys in advance
BichengYing May 18, 2021
de6c419
Fix the lint error
BichengYing May 18, 2021
9db74eb
Format file
BichengYing May 18, 2021
7c6eeac
Using the vectorization methods to compute the phases
BichengYing May 18, 2021
17f09f2
Update clifford_tableau.py
BichengYing May 18, 2021
bfa08ca
Update the comments
BichengYing May 18, 2021
464f912
Using @ and add more comments
BichengYing May 19, 2021
f044cc1
Merge branch 'master' into single_clifford
BichengYing May 20, 2021
b11caf7
Merge branch 'master' into single_clifford
CirqBot May 20, 2021
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
16 changes: 11 additions & 5 deletions cirq-core/cirq/qis/clifford_tableau.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ def rs(self, new_rs: np.array) -> None:
self._rs[:-1] = np.array(new_rs).astype(bool)

def matrix(self) -> np.array:
BichengYing marked this conversation as resolved.
Show resolved Hide resolved
"""Returns a 2n * 2n matrix of Clifford table."""
BichengYing marked this conversation as resolved.
Show resolved Hide resolved
return np.concatenate([self.xs, self.zs], axis=1)

def _json_dict_(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -178,12 +179,12 @@ def _str_full_(self) -> str:

return string

def merged_with(self, second: 'CliffordTableau') -> 'CliffordTableau':
"""Returns a merged CliffordTableau of self tableau and second tableau.
def then(self, second: 'CliffordTableau') -> 'CliffordTableau':
balopat marked this conversation as resolved.
Show resolved Hide resolved
"""Returns a composed CliffordTableau of this tableau and the second tableau.

The meaning of merge two clifford tableau is the corresponding unitary operation
of merged clifford tableau is equal to (up to global phase) the composed unitary
operation of self tableau and the one of second tableau.
Then composed tableau is equal to (up to global phase) the composed
unitary operation of the two tableaux, i.e. equivalent to applying the unitary operation
this CliffordTableau then applying the second one.
BichengYing marked this conversation as resolved.
Show resolved Hide resolved
"""
m1 = self.matrix().astype(int)
m2 = second.matrix().astype(int)
BichengYing marked this conversation as resolved.
Show resolved Hide resolved
Expand Down Expand Up @@ -215,6 +216,11 @@ def merged_with(self, second: 'CliffordTableau') -> 'CliffordTableau':
merged_tableau.rs = phase
return merged_tableau

def __matmul__(self, second: 'CliffordTableau'):
if not isinstance(second, CliffordTableau):
return NotImplemented
return second.then(self)

def _rowsum(self, q1, q2):
"""Implements the "rowsum" routine defined by
Aaronson and Gottesman.
Expand Down
72 changes: 48 additions & 24 deletions cirq-core/cirq/qis/clifford_tableau_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,54 +324,60 @@ def test_deprecated_clifford_location():
CliffordTableau(num_qubits=1)


def test_merge_tableau():
def three_identical_table(num_qubits):
t1 = cirq.CliffordTableau(num_qubits)
t2 = cirq.CliffordTableau(num_qubits)
t3 = cirq.CliffordTableau(num_qubits)
return t1, t2, t3
def _three_identical_table(num_qubits):
t1 = cirq.CliffordTableau(num_qubits)
t2 = cirq.CliffordTableau(num_qubits)
t3 = cirq.CliffordTableau(num_qubits)
return t1, t2, t3

t1, t2, expected_t = three_identical_table(1)
assert expected_t == t1.merged_with(t2)

t1, t2, expected_t = three_identical_table(1)
def test_tableau_then():

t1, t2, expected_t = _three_identical_table(1)
assert expected_t == t1.then(t2)

t1, t2, expected_t = _three_identical_table(1)
_ = [_H(t, 0) for t in (t1, expected_t)]
_ = [_H(t, 0) for t in (t2, expected_t)]
assert expected_t == t1.merged_with(t2)
assert expected_t == t1.then(t2)

t1, t2, expected_t = three_identical_table(1)
t1, t2, expected_t = _three_identical_table(1)
_ = [_X(t, 0) for t in (t1, expected_t)]
_ = [_S(t, 0) for t in (t2, expected_t)]
assert expected_t == t1.merged_with(t2)
assert expected_t == t1.then(t2)
assert expected_t != t2.then(t1)

t1, t2, expected_t = three_identical_table(1)
t1, t2, expected_t = _three_identical_table(1)
_ = [_X(t, 0) for t in (t1, expected_t)]
_ = [_H(t, 0) for t in (t1, expected_t)]
_ = [_Z(t, 0) for t in (t1, expected_t)]
_ = [_S(t, 0) for t in (t2, expected_t)]
_ = [_H(t, 0) for t in (t2, expected_t)]
assert expected_t == t1.merged_with(t2)
assert expected_t == t1.then(t2)
assert expected_t != t2.then(t1)

t1, t2, expected_t = three_identical_table(2)
t1, t2, expected_t = _three_identical_table(2)
_ = [_H(t, 0) for t in (t1, expected_t)]
_ = [_H(t, 1) for t in (t1, expected_t)]
_ = [_H(t, 0) for t in (t2, expected_t)]
_ = [_H(t, 1) for t in (t2, expected_t)]
assert expected_t == t1.merged_with(t2)
assert expected_t == t1.then(t2)

t1, t2, expected_t = three_identical_table(2)
t1, t2, expected_t = _three_identical_table(2)
_ = [_H(t, 0) for t in (t1, expected_t)]
_ = [_CNOT(t, 0, 1) for t in (t1, expected_t)]
_ = [_S(t, 0) for t in (t2, expected_t)]
_ = [_X(t, 1) for t in (t2, expected_t)]
assert expected_t == t1.merged_with(t2)
assert expected_t == t1.then(t2)
assert expected_t != t2.then(t1)

t1, t2, expected_t = three_identical_table(2)
t1, t2, expected_t = _three_identical_table(2)
_ = [_H(t, 0) for t in (t1, expected_t)]
_ = [_CNOT(t, 0, 1) for t in (t1, expected_t)]
_ = [_S(t, 1) for t in (t2, expected_t)]
_ = [_CNOT(t, 1, 0) for t in (t2, expected_t)]
assert expected_t == t1.merged_with(t2)
assert expected_t == t1.then(t2)
assert expected_t != t2.then(t1)

def random_circuit(num_ops, num_qubits, seed=12345):
prng = np.random.RandomState(seed)
Expand All @@ -391,22 +397,40 @@ def random_circuit(num_ops, num_qubits, seed=12345):

# Do small random circuits test 100 times.
for seed in range(100):
t1, t2, expected_t = three_identical_table(8)
t1, t2, expected_t = _three_identical_table(8)
seq_op = random_circuit(num_ops=20, num_qubits=8, seed=seed)
for i, (op, args) in enumerate(seq_op):
if i < 7:
_ = [op(t, *args) for t in (t1, expected_t)]
else:
_ = [op(t, *args) for t in (t2, expected_t)]
assert expected_t == t1.merged_with(t2)
assert expected_t == t1.then(t2)

# Since merging Clifford Tableau operation is O(n^3),
# running 100 qubits case is still fast.
t1, t2, expected_t = three_identical_table(100)
t1, t2, expected_t = _three_identical_table(100)
seq_op = random_circuit(num_ops=1000, num_qubits=100)
for i, (op, args) in enumerate(seq_op):
if i < 350:
_ = [op(t, *args) for t in (t1, expected_t)]
else:
_ = [op(t, *args) for t in (t2, expected_t)]
assert expected_t == t1.merged_with(t2)
assert expected_t == t1.then(t2)


def test_tableau_matmul():
t1, t2, expected_t = _three_identical_table(1)
_ = [_H(t, 0) for t in (t1, expected_t)]
_ = [_H(t, 0) for t in (t2, expected_t)]
assert expected_t == t2 @ t1

t1, t2, expected_t = _three_identical_table(1)
_ = [_X(t, 0) for t in (t1, expected_t)]
_ = [_S(t, 0) for t in (t2, expected_t)]
assert expected_t == t2 @ t1
assert expected_t != t1 @ t2

with pytest.raises(TypeError):
# pylint: disable=pointless-statement
t1 @ 21
# pylint: enable=pointless-statement