From efd22c8b066083a0e62c57a3a5c94dbd606d98e5 Mon Sep 17 00:00:00 2001 From: migueltorrescosta Date: Wed, 1 May 2024 02:11:46 +0200 Subject: [PATCH 1/7] Support binary exponentiation --- cirq-core/cirq/ops/clifford_gate.py | 39 ++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index c3021bf9bbc..6621b05bfa1 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -400,7 +400,10 @@ def _has_stabilizer_effect_(self) -> Optional[bool]: # By definition, Clifford Gate should always return True. return True - def __pow__(self, exponent) -> 'CliffordGate': + def __pow__(self, exponent: int) -> 'CliffordGate': + if exponent != int(exponent): + return NotImplemented + if exponent == -1: return CliffordGate.from_clifford_tableau(self.clifford_tableau.inverse()) if exponent == 0: @@ -409,18 +412,30 @@ def __pow__(self, exponent) -> 'CliffordGate': ) if exponent == 1: return self - if exponent > 0 and int(exponent) == exponent: - base_tableau = self.clifford_tableau.copy() - for _ in range(int(exponent) - 1): - base_tableau = base_tableau.then(self.clifford_tableau) - return CliffordGate.from_clifford_tableau(base_tableau) - if exponent < 0 and int(exponent) == exponent: - base_tableau = self.clifford_tableau.copy() - for _ in range(int(-exponent) - 1): - base_tableau = base_tableau.then(self.clifford_tableau) - return CliffordGate.from_clifford_tableau(base_tableau.inverse()) + base_tableau = self.clifford_tableau.copy() + if exponent < 0: + base_tableau = base_tableau.inverse() + exponent = int(abs(exponent)) + + # https://cp-algorithms.com/algebra/binary-exp.html + operation_order: List[bool] = list() + while exponent > 1: + if exponent % 2 == 0: + exponent /= 2 + operation_order.append(True) # Represents multiplication by 2 + else: + exponent -= 1 + operation_order.append(False) # Represents addition of 1 + operation_order = operation_order[::-1] + + result_tableau = base_tableau.copy() + for multiply_by_two in operation_order: + if multiply_by_two: + result_tableau.then(result_tableau) + else: + result_tableau.then(base_tableau) - return NotImplemented + return CliffordGate.from_clifford_tableau(result_tableau) def __repr__(self) -> str: return f"Clifford Gate with Tableau:\n {self.clifford_tableau._str_full_()}" From 16935e690de92508f1690acafc76e21c929800d2 Mon Sep 17 00:00:00 2001 From: migueltorrescosta Date: Wed, 1 May 2024 20:18:15 +0200 Subject: [PATCH 2/7] Fix docstring --- cirq-core/cirq/qis/clifford_tableau.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cirq-core/cirq/qis/clifford_tableau.py b/cirq-core/cirq/qis/clifford_tableau.py index e652c669043..15cc13234b8 100644 --- a/cirq-core/cirq/qis/clifford_tableau.py +++ b/cirq-core/cirq/qis/clifford_tableau.py @@ -129,7 +129,8 @@ def apply_global_phase(self, coefficient: linear_dict.Scalar): class CliffordTableau(StabilizerState): """Tableau representation of a stabilizer state - (based on Aaronson and Gottesman 2006). + (based on Aaronson and Gottesman 2004). + # https://arxiv.org/pdf/quant-ph/0406196 The tableau stores the stabilizer generators of the state using three binary arrays: xs, zs, and rs. From b066508f7226c252980b08906fef0f28edcca0f2 Mon Sep 17 00:00:00 2001 From: migueltorrescosta Date: Wed, 1 May 2024 20:31:07 +0200 Subject: [PATCH 3/7] Apply suggested solution --- cirq-core/cirq/ops/clifford_gate.py | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index 6621b05bfa1..908e681ba9c 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -412,30 +412,21 @@ def __pow__(self, exponent: int) -> 'CliffordGate': ) if exponent == 1: return self + base_tableau = self.clifford_tableau.copy() if exponent < 0: base_tableau = base_tableau.inverse() exponent = int(abs(exponent)) # https://cp-algorithms.com/algebra/binary-exp.html - operation_order: List[bool] = list() + aux = qis.CliffordTableau(num_qubits=self.clifford_tableau.n) # this tableau collects the odd terms while exponent > 1: - if exponent % 2 == 0: - exponent /= 2 - operation_order.append(True) # Represents multiplication by 2 - else: - exponent -= 1 - operation_order.append(False) # Represents addition of 1 - operation_order = operation_order[::-1] - - result_tableau = base_tableau.copy() - for multiply_by_two in operation_order: - if multiply_by_two: - result_tableau.then(result_tableau) - else: - result_tableau.then(base_tableau) + if exponent & 1: aux = aux.then(base_tableau) + base_tableau = base_tableau.then(base_tableau) + exponent >>= 1 - return CliffordGate.from_clifford_tableau(result_tableau) + base_tableau = base_tableau.then(aux) + return CliffordGate.from_clifford_tableau(base_tableau) def __repr__(self) -> str: return f"Clifford Gate with Tableau:\n {self.clifford_tableau._str_full_()}" From 112207f3a62cb28887c291c2300ee6522eee20b8 Mon Sep 17 00:00:00 2001 From: migueltorrescosta Date: Thu, 2 May 2024 11:39:56 +0200 Subject: [PATCH 4/7] Linting --- cirq-core/cirq/ops/clifford_gate.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index 908e681ba9c..82dabf8269e 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -419,9 +419,12 @@ def __pow__(self, exponent: int) -> 'CliffordGate': exponent = int(abs(exponent)) # https://cp-algorithms.com/algebra/binary-exp.html - aux = qis.CliffordTableau(num_qubits=self.clifford_tableau.n) # this tableau collects the odd terms + aux = qis.CliffordTableau( + num_qubits=self.clifford_tableau.n + ) # this tableau collects the odd terms while exponent > 1: - if exponent & 1: aux = aux.then(base_tableau) + if exponent & 1: + aux = aux.then(base_tableau) base_tableau = base_tableau.then(base_tableau) exponent >>= 1 From 4fcd55040cfb82db1f9153f4427a5097d2ab11bc Mon Sep 17 00:00:00 2001 From: migueltorrescosta Date: Thu, 2 May 2024 11:42:02 +0200 Subject: [PATCH 5/7] Apply PR suggestions --- cirq-core/cirq/ops/clifford_gate.py | 2 +- cirq-core/cirq/qis/clifford_tableau.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index 82dabf8269e..ef905b18dde 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -416,7 +416,7 @@ def __pow__(self, exponent: int) -> 'CliffordGate': base_tableau = self.clifford_tableau.copy() if exponent < 0: base_tableau = base_tableau.inverse() - exponent = int(abs(exponent)) + exponent = abs(exponent) # https://cp-algorithms.com/algebra/binary-exp.html aux = qis.CliffordTableau( diff --git a/cirq-core/cirq/qis/clifford_tableau.py b/cirq-core/cirq/qis/clifford_tableau.py index 15cc13234b8..b5f3c977448 100644 --- a/cirq-core/cirq/qis/clifford_tableau.py +++ b/cirq-core/cirq/qis/clifford_tableau.py @@ -129,8 +129,9 @@ def apply_global_phase(self, coefficient: linear_dict.Scalar): class CliffordTableau(StabilizerState): """Tableau representation of a stabilizer state - (based on Aaronson and Gottesman 2004). - # https://arxiv.org/pdf/quant-ph/0406196 + + References: + - [Aaronson and Gottesman](https://arxiv.org/pdf/quant-ph/0406196) The tableau stores the stabilizer generators of the state using three binary arrays: xs, zs, and rs. From 0137b937554a37fb1cceead4a176a07250ef0abf Mon Sep 17 00:00:00 2001 From: Miguel Costa Date: Sat, 4 May 2024 00:40:16 +0200 Subject: [PATCH 6/7] Fix type signature --- cirq-core/cirq/ops/clifford_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index ef905b18dde..d087c5dbcda 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -400,7 +400,7 @@ def _has_stabilizer_effect_(self) -> Optional[bool]: # By definition, Clifford Gate should always return True. return True - def __pow__(self, exponent: int) -> 'CliffordGate': + def __pow__(self, exponent: Union[float, int]) -> 'CliffordGate': if exponent != int(exponent): return NotImplemented From 3bfae657e5677198a8cdd9c5d5710c1ff10084ef Mon Sep 17 00:00:00 2001 From: Miguel Costa Date: Sat, 4 May 2024 13:21:04 +0200 Subject: [PATCH 7/7] Fix link to use /abs/ rather than /pdf/, and fix mypy types --- cirq-core/cirq/ops/clifford_gate.py | 3 ++- cirq-core/cirq/qis/clifford_tableau.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cirq-core/cirq/ops/clifford_gate.py b/cirq-core/cirq/ops/clifford_gate.py index d087c5dbcda..82ce7ebe42e 100644 --- a/cirq-core/cirq/ops/clifford_gate.py +++ b/cirq-core/cirq/ops/clifford_gate.py @@ -400,9 +400,10 @@ def _has_stabilizer_effect_(self) -> Optional[bool]: # By definition, Clifford Gate should always return True. return True - def __pow__(self, exponent: Union[float, int]) -> 'CliffordGate': + def __pow__(self, exponent: float) -> 'CliffordGate': if exponent != int(exponent): return NotImplemented + exponent = int(exponent) if exponent == -1: return CliffordGate.from_clifford_tableau(self.clifford_tableau.inverse()) diff --git a/cirq-core/cirq/qis/clifford_tableau.py b/cirq-core/cirq/qis/clifford_tableau.py index b5f3c977448..4130436509b 100644 --- a/cirq-core/cirq/qis/clifford_tableau.py +++ b/cirq-core/cirq/qis/clifford_tableau.py @@ -131,7 +131,7 @@ class CliffordTableau(StabilizerState): """Tableau representation of a stabilizer state References: - - [Aaronson and Gottesman](https://arxiv.org/pdf/quant-ph/0406196) + - [Aaronson and Gottesman](https://arxiv.org/abs/quant-ph/0406196) The tableau stores the stabilizer generators of the state using three binary arrays: xs, zs, and rs.