From e169837eed54a03bbd39cbab829e3c2cf26bc48f Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Wed, 13 Mar 2024 13:04:45 +0400 Subject: [PATCH 1/8] feat: improved random clifford --- src/qibo/quantum_info/random_ensembles.py | 63 +++++++++++++++++++---- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 94159cf1b2..01b468bd4d 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -1,6 +1,7 @@ """Module with functions that create random quantum and classical objects.""" import warnings +from functools import cache from typing import Optional, Union import numpy as np @@ -1087,6 +1088,46 @@ def _sample_from_quantum_mallows_distribution(nqubits: int, local_state): return hadamards, permutations +@cache +def _create_S(q): + return gates.S(q) + + +def _create_S_layer(init_args, queue): + # for q in init_args: + # l.put(_create_S(q)) + # print("S: ", l.qsize()) + queue.put_nowait([_create_S(q) for q in init_args]) + + +@cache +def _create_CZ(cq, tq): + return gates.CZ(cq, tq) + + +def _create_CZ_layer(init_args, queue): + # for cq, tq in init_args: + # l.put(_create_CZ(cq, tq)) + # print("CZ: ",l.qsize()) + queue.put_nowait([_create_CZ(cq, tq) for cq, tq in init_args]) + + +@cache +def _create_CNOT(cq, tq): + return gates.CNOT(cq, tq) + + +def _create_CNOT_layer(init_args, queue): + # for cq, tq in init_args: + # l.put(_create_CNOT(cq, tq)) + # print("CNOT: ", l.qsize()) + queue.put_nowait([_create_CNOT(cq, tq) for cq, tq in init_args]) + + +def _create_layer(func, init_args): + return func(init_args) + + def _operator_from_hadamard_free_group( gamma_matrix, delta_matrix, density_matrix: bool = False, pauli_operator=None ): @@ -1124,19 +1165,19 @@ def _operator_from_hadamard_free_group( if pauli_operator is not None: circuit += pauli_operator - for qubit, gamma in enumerate(np.diag(gamma_matrix)): - if gamma == 1: - circuit.add(gates.S(qubit)) + idx = np.tril_indices(nqubits, k=-1) + gamma_ones = gamma_matrix[idx].nonzero()[0] + delta_ones = delta_matrix[idx].nonzero()[0] - for j in range(nqubits): - for k in range(j + 1, nqubits): - if gamma_matrix[k, j] == 1: - circuit.add(gates.CZ(j, k)) + S_gates = [_create_S(q) for q in np.diag(gamma_matrix).nonzero()[0]] + CZ_gates = [ + _create_CZ(cq, tq) for cq, tq in zip(idx[1][gamma_ones], idx[0][gamma_ones]) + ] + CNOT_gates = [ + _create_CNOT(cq, tq) for cq, tq in zip(idx[1][delta_ones], idx[0][delta_ones]) + ] - for j in range(nqubits): - for k in range(j + 1, nqubits): - if delta_matrix[k, j] == 1: - circuit.add(gates.CNOT(j, k)) + circuit.add(S_gates + CZ_gates + CNOT_gates) return circuit From 69d0cc761a88e293c28166f327a804085053eb7d Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Wed, 13 Mar 2024 13:06:57 +0400 Subject: [PATCH 2/8] feat: improved random clifford --- src/qibo/quantum_info/random_ensembles.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index 01b468bd4d..ab58618e05 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -1093,41 +1093,18 @@ def _create_S(q): return gates.S(q) -def _create_S_layer(init_args, queue): - # for q in init_args: - # l.put(_create_S(q)) - # print("S: ", l.qsize()) - queue.put_nowait([_create_S(q) for q in init_args]) - @cache def _create_CZ(cq, tq): return gates.CZ(cq, tq) -def _create_CZ_layer(init_args, queue): - # for cq, tq in init_args: - # l.put(_create_CZ(cq, tq)) - # print("CZ: ",l.qsize()) - queue.put_nowait([_create_CZ(cq, tq) for cq, tq in init_args]) - @cache def _create_CNOT(cq, tq): return gates.CNOT(cq, tq) -def _create_CNOT_layer(init_args, queue): - # for cq, tq in init_args: - # l.put(_create_CNOT(cq, tq)) - # print("CNOT: ", l.qsize()) - queue.put_nowait([_create_CNOT(cq, tq) for cq, tq in init_args]) - - -def _create_layer(func, init_args): - return func(init_args) - - def _operator_from_hadamard_free_group( gamma_matrix, delta_matrix, density_matrix: bool = False, pauli_operator=None ): From cdc4a2f12e925eb1589739bf015dbb2d94466a7d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 13 Mar 2024 09:07:32 +0000 Subject: [PATCH 3/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/quantum_info/random_ensembles.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/qibo/quantum_info/random_ensembles.py b/src/qibo/quantum_info/random_ensembles.py index ab58618e05..418be3960b 100644 --- a/src/qibo/quantum_info/random_ensembles.py +++ b/src/qibo/quantum_info/random_ensembles.py @@ -1093,13 +1093,11 @@ def _create_S(q): return gates.S(q) - @cache def _create_CZ(cq, tq): return gates.CZ(cq, tq) - @cache def _create_CNOT(cq, tq): return gates.CNOT(cq, tq) From d8abe417c5d40976e268fb5d6b7e1aa9fe1b8542 Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Wed, 13 Mar 2024 16:26:00 +0400 Subject: [PATCH 4/8] fix: minor optimization --- src/qibo/gates/abstract.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/qibo/gates/abstract.py b/src/qibo/gates/abstract.py index 2cc99fa4b5..c81ed138b9 100644 --- a/src/qibo/gates/abstract.py +++ b/src/qibo/gates/abstract.py @@ -48,9 +48,9 @@ def __init__(self): self.clifford = False self.unitary = False - self._target_qubits = tuple() - self._control_qubits = set() - self._parameters = tuple() + self._target_qubits = () + self._control_qubits = () + self._parameters = () config.ALLOW_SWITCHERS = False self.symbolic_parameters = {} @@ -158,7 +158,7 @@ def _set_target_qubits(self, qubits: Sequence[int]): def _set_control_qubits(self, qubits: Sequence[int]): """Helper method for setting control qubits.""" - self._control_qubits = set(qubits) + self._control_qubits = qubits if len(self._control_qubits) != len(qubits): repeated = self._find_repeated(qubits) raise_error( @@ -204,7 +204,7 @@ def _find_repeated(qubits: Sequence[int]) -> int: def _check_control_target_overlap(self): """Checks that there are no qubits that are both target and controls.""" - common = set(self._target_qubits) & self._control_qubits + common = set(self._target_qubits) & set(self._control_qubits) if common: raise_error( ValueError, From 4bae1f1715f41198fdeee83728a59f74bcfe7e35 Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Thu, 14 Mar 2024 10:55:33 +0400 Subject: [PATCH 5/8] fix: fix to set and check control qubits --- src/qibo/gates/abstract.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/qibo/gates/abstract.py b/src/qibo/gates/abstract.py index c81ed138b9..1328f9edcc 100644 --- a/src/qibo/gates/abstract.py +++ b/src/qibo/gates/abstract.py @@ -158,13 +158,13 @@ def _set_target_qubits(self, qubits: Sequence[int]): def _set_control_qubits(self, qubits: Sequence[int]): """Helper method for setting control qubits.""" - self._control_qubits = qubits - if len(self._control_qubits) != len(qubits): + if len(set(qubits)) != len(qubits): repeated = self._find_repeated(qubits) raise_error( ValueError, f"Control qubit {repeated} was given twice for gate {self.__class__.__name__}.", ) + self._control_qubits = qubits @target_qubits.setter def target_qubits(self, qubits: Sequence[int]): @@ -204,7 +204,8 @@ def _find_repeated(qubits: Sequence[int]) -> int: def _check_control_target_overlap(self): """Checks that there are no qubits that are both target and controls.""" - common = set(self._target_qubits) & set(self._control_qubits) + control_target = self._target_qubits + self._control_qubits + common = len(set(control_target)) != len(control_target) if common: raise_error( ValueError, From 51a2f957cbf80cd85c16b5058414a02bfdc59680 Mon Sep 17 00:00:00 2001 From: BrunoLiegiBastonLiegi <45011234+BrunoLiegiBastonLiegi@users.noreply.github.com> Date: Tue, 19 Mar 2024 11:37:51 +0400 Subject: [PATCH 6/8] Update src/qibo/gates/abstract.py Co-authored-by: Renato Mello --- src/qibo/gates/abstract.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/qibo/gates/abstract.py b/src/qibo/gates/abstract.py index 1328f9edcc..6405b10dc3 100644 --- a/src/qibo/gates/abstract.py +++ b/src/qibo/gates/abstract.py @@ -204,8 +204,8 @@ def _find_repeated(qubits: Sequence[int]) -> int: def _check_control_target_overlap(self): """Checks that there are no qubits that are both target and controls.""" - control_target = self._target_qubits + self._control_qubits - common = len(set(control_target)) != len(control_target) + control_and_target = self._control_qubits + self._target_qubits + common = len(set(control_and_target)) != len(control_and_target) if common: raise_error( ValueError, From ac3e6f40c83f9509583197b0840eb47ecbb1776f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 07:38:10 +0000 Subject: [PATCH 7/8] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/qibo/gates/abstract.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/gates/abstract.py b/src/qibo/gates/abstract.py index 6405b10dc3..6a59ade86c 100644 --- a/src/qibo/gates/abstract.py +++ b/src/qibo/gates/abstract.py @@ -204,7 +204,7 @@ def _find_repeated(qubits: Sequence[int]) -> int: def _check_control_target_overlap(self): """Checks that there are no qubits that are both target and controls.""" - control_and_target = self._control_qubits + self._target_qubits + control_and_target = self._control_qubits + self._target_qubits common = len(set(control_and_target)) != len(control_and_target) if common: raise_error( From 5552d06c3df7d10b3483dbe1290bc4afda681b31 Mon Sep 17 00:00:00 2001 From: Andrea Papaluca Date: Tue, 19 Mar 2024 12:02:56 +0400 Subject: [PATCH 8/8] fix: updated err string for check_control_target_overlap --- src/qibo/gates/abstract.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qibo/gates/abstract.py b/src/qibo/gates/abstract.py index 6a59ade86c..6476883d69 100644 --- a/src/qibo/gates/abstract.py +++ b/src/qibo/gates/abstract.py @@ -209,7 +209,7 @@ def _check_control_target_overlap(self): if common: raise_error( ValueError, - f"{common} qubits are both targets and controls " + f"{set(self._target_qubits) & set(self._control_qubits)} qubits are both targets and controls " + f"for gate {self.__class__.__name__}.", )