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

Include density_matrix flag in random_clifford and random_pauli #1024

Merged
merged 5 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 25 additions & 5 deletions src/qibo/quantum_info/random_ensembles.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,7 @@ def random_density_matrix(
def random_clifford(
nqubits: int,
return_circuit: bool = True,
density_matrix: bool = False,
seed=None,
backend=None,
):
Expand All @@ -567,6 +568,8 @@ def random_clifford(
nqubits (int): number of qubits.
return_circuit (bool, optional): if ``True``, returns a :class:`qibo.models.Circuit`
object. If ``False``, returns an ``ndarray`` object. Defaults to ``False``.
density_matrix (bool, optional): used when ``return_circuit=True``. If `True`,
the circuit would evolve density matrices. Defaults to ``False``.
seed (int or :class:`numpy.random.Generator`, optional): Either a generator of
random numbers or a fixed seed to initialize a generator. If ``None``,
initializes a generator with a random seed. Defaults to ``None``.
Expand Down Expand Up @@ -672,7 +675,9 @@ def random_clifford(
delta_matrix[k, j] = b

# get first element of the Borel group
clifford_circuit = _operator_from_hadamard_free_group(gamma_matrix, delta_matrix)
clifford_circuit = _operator_from_hadamard_free_group(
gamma_matrix, delta_matrix, density_matrix
)

# Apply permutated Hadamard layer
for qubit, had in enumerate(hadamards):
Expand All @@ -683,7 +688,15 @@ def random_clifford(
clifford_circuit += _operator_from_hadamard_free_group(
gamma_matrix_prime,
delta_matrix_prime,
random_pauli(nqubits, depth=1, return_circuit=True, seed=seed, backend=backend),
density_matrix,
random_pauli(
nqubits,
depth=1,
return_circuit=True,
density_matrix=density_matrix,
seed=seed,
backend=backend,
),
)

if return_circuit is False:
Expand All @@ -698,6 +711,7 @@ def random_pauli(
max_qubits: Optional[int] = None,
subset: Optional[list] = None,
return_circuit: bool = True,
density_matrix: bool = False,
seed=None,
backend=None,
):
Expand All @@ -720,6 +734,8 @@ def random_pauli(
return_circuit (bool, optional): if ``True``, returns a :class:`qibo.models.Circuit`
object. If ``False``, returns an ``ndarray`` with shape (qubits, depth, 2, 2)
that contains all Pauli matrices that were sampled. Defaults to ``True``.
density_matrix (bool, optional): used when ``return_circuit=True``. If `True`,
the circuit would evolve density matrices. Defaults to ``False``.
seed (int or :class:`numpy.random.Generator`, optional): Either a generator of
random numbers or a fixed seed to initialize a generator. If ``None``,
initializes a generator with a random seed. Defaults to ``None``.
Expand Down Expand Up @@ -819,7 +835,7 @@ def random_pauli(
indexes = [[keys[item] for item in row] for row in indexes]

if return_circuit:
gate_grid = Circuit(max_qubits)
gate_grid = Circuit(max_qubits, density_matrix=density_matrix)
for qubit, row in zip(qubits, indexes):
for column_item in row:
if subset[column_item] != gates.I:
Expand Down Expand Up @@ -1100,14 +1116,18 @@ def _sample_from_quantum_mallows_distribution(nqubits: int, local_state):
return hadamards, permutations


def _operator_from_hadamard_free_group(gamma_matrix, delta_matrix, pauli_operator=None):
def _operator_from_hadamard_free_group(
gamma_matrix, delta_matrix, density_matrix: bool = False, pauli_operator=None
):
"""Calculates an element :math:`F` of the Hadamard-free group :math:`\\mathcal{F}_{n}`,
where :math:`n` is the number of qubits ``nqubits``. For more details,
see Reference [1].

Args:
gamma_matrix (ndarray): :math:`\\, n \\times n \\,` binary matrix.
delta_matrix (ndarray): :math:`\\, n \\times n \\,` binary matrix.
density_matrix (bool, optional): used when ``return_circuit=True``. If `True`,
the circuit would evolve density matrices. Defaults to ``False``.
pauli_operator (:class:`qibo.models.Circuit`, optional): a :math:`n`-qubit
Pauli operator. If ``None``, it is assumed to be the Identity.
Defaults to ``None``.
Expand All @@ -1128,7 +1148,7 @@ def _operator_from_hadamard_free_group(gamma_matrix, delta_matrix, pauli_operato
)

nqubits = len(gamma_matrix)
circuit = Circuit(nqubits)
circuit = Circuit(nqubits, density_matrix=density_matrix)

if pauli_operator is not None:
circuit += pauli_operator
Expand Down
16 changes: 12 additions & 4 deletions tests/test_quantum_info_random.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,10 @@ def test_random_density_matrix(backend, dims, pure, metric, basis, normalize):


@pytest.mark.parametrize("seed", [10])
@pytest.mark.parametrize("density_matrix", [False, True])
@pytest.mark.parametrize("return_circuit", [True, False])
@pytest.mark.parametrize("nqubits", [1, 2])
def test_random_clifford(backend, nqubits, return_circuit, seed):
def test_random_clifford(backend, nqubits, return_circuit, density_matrix, seed):
with pytest.raises(TypeError):
test = random_clifford(
nqubits="1", return_circuit=return_circuit, backend=backend
Expand All @@ -301,7 +302,11 @@ def test_random_clifford(backend, nqubits, return_circuit, seed):
result = backend.cast(result, dtype=result.dtype)

matrix = random_clifford(
nqubits, return_circuit=return_circuit, seed=seed, backend=backend
nqubits,
return_circuit=return_circuit,
density_matrix=density_matrix,
seed=seed,
backend=backend,
)

if return_circuit:
Expand Down Expand Up @@ -374,8 +379,11 @@ def test_pauli_single(backend):
@pytest.mark.parametrize("max_qubits", [None])
@pytest.mark.parametrize("subset", [None, ["I", "X"]])
@pytest.mark.parametrize("return_circuit", [True, False])
@pytest.mark.parametrize("density_matrix", [False, True])
@pytest.mark.parametrize("seed", [10])
def test_random_pauli(backend, qubits, depth, max_qubits, subset, return_circuit, seed):
def test_random_pauli(
backend, qubits, depth, max_qubits, subset, return_circuit, density_matrix, seed
):
result_complete_set = np.array(
[
[0.0 + 0.0j, 1.0 + 0.0j, 0.0 + 0.0j, 0.0 + 0.0j],
Expand All @@ -390,7 +398,7 @@ def test_random_pauli(backend, qubits, depth, max_qubits, subset, return_circuit
result_subset = backend.identity_density_matrix(2, normalize=False)

matrix = random_pauli(
qubits, depth, max_qubits, subset, return_circuit, seed, backend
qubits, depth, max_qubits, subset, return_circuit, density_matrix, seed, backend
)

if return_circuit:
Expand Down