Skip to content

Commit

Permalink
mv, rename
Browse files Browse the repository at this point in the history
  • Loading branch information
JerryChen97 committed Nov 28, 2024
1 parent e2fc91e commit 7dac47a
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 59 deletions.
44 changes: 44 additions & 0 deletions tests/devices/qubit_mixed/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Copyright 2018-2024 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Pytest configuration file for PennyLane qubit mixed state test suite."""
import numpy as np
import pytest
from scipy.stats import unitary_group


def get_random_mixed_state(num_qubits):
"""
Generates a random mixed state for testing purposes.
Args:
num_qubits (int): The number of qubits in the mixed state.
Returns:
np.ndarray: A tensor representing the random mixed state.
"""
dim = 2**num_qubits

rng = np.random.default_rng(seed=4774)
basis = unitary_group(dim=dim, seed=584545).rvs()
schmidt_weights = rng.dirichlet(np.ones(dim), size=1).astype(complex)[0]
mixed_state = np.zeros((dim, dim)).astype(complex)
for i in range(dim):
mixed_state += schmidt_weights[i] * np.outer(np.conj(basis[i]), basis[i])

return mixed_state.reshape([2] * (2 * num_qubits))


@pytest.fixture(scope="package")
def random_mixed_state():
return get_random_mixed_state
102 changes: 43 additions & 59 deletions tests/devices/qubit_mixed/test_qubit_mixed_apply_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
from scipy.stats import unitary_group

import pennylane as qml
import pennylane.math as math
from pennylane import (
CNOT,
ISWAP,
Expand All @@ -30,6 +29,7 @@
PauliError,
PauliX,
ResetError,
math,
)
from pennylane.devices.qubit_mixed import apply_operation
from pennylane.devices.qubit_mixed.apply_operation import (
Expand Down Expand Up @@ -100,28 +100,6 @@ def root_state(nr_wires):
special_state_generator = [base0, base1, cat_state, hadamard_state, max_mixed_state, root_state]


def get_random_mixed_state(num_qubits):
"""
Generates a random mixed state for testing purposes.
Args:
num_qubits (int): The number of qubits in the mixed state.
Returns:
np.ndarray: A tensor representing the random mixed state.
"""
dim = 2**num_qubits

rng = np.random.default_rng(seed=4774)
basis = unitary_group(dim=dim, seed=584545).rvs()
schmidt_weights = rng.dirichlet(np.ones(dim), size=1).astype(complex)[0]
mixed_state = np.zeros((dim, dim)).astype(complex)
for i in range(dim):
mixed_state += schmidt_weights[i] * np.outer(np.conj(basis[i]), basis[i])

return mixed_state.reshape([2] * (2 * num_qubits))


def get_expected_state(expanded_operator, state, num_q):
"""Finds expected state after applying operator"""
# Convert the state into numpy
Expand Down Expand Up @@ -196,15 +174,15 @@ def circuit():

@pytest.mark.parametrize("op", unbroadcasted_ops)
@pytest.mark.parametrize("num_q", num_qubits)
def test_no_broadcasting(self, op, num_q, ml_framework):
def test_no_broadcasting(self, op, num_q, ml_framework, random_mixed_state):
"""
Tests that unbatched operations are applied correctly to an unbatched state.
Args:
op (Operation): Quantum operation to apply.
ml_framework (str): The machine learning framework in use (numpy, autograd, etc.).
"""
state = math.asarray(get_random_mixed_state(num_q), like=ml_framework)
state = math.asarray(random_mixed_state(num_q), like=ml_framework)
res = apply_operation(op, state)
res_tensordot = apply_operation_tensordot(op, state)
res_einsum = apply_operation_einsum(op, state)
Expand All @@ -220,15 +198,15 @@ def test_no_broadcasting(self, op, num_q, ml_framework):

@pytest.mark.parametrize("op", diagonal_ops)
@pytest.mark.parametrize("num_q", num_qubits)
def test_diagonal(self, op, num_q, ml_framework):
def test_diagonal(self, op, num_q, ml_framework, random_mixed_state):
"""
Tests that diagonal operations are applied correctly to an unbatched state.
Args:
op (Operation): Quantum operation to apply.
ml_framework (str): The machine learning framework in use (numpy, autograd, etc.).
"""
state_np = get_random_mixed_state(num_q)
state_np = random_mixed_state(num_q)
state = math.asarray(state_np, like=ml_framework)
res = apply_operation(op, state)

Expand All @@ -238,19 +216,19 @@ def test_diagonal(self, op, num_q, ml_framework):
assert math.allclose(res, expected), f"Operation {op} failed. {res} != {expected}"

@pytest.mark.parametrize("num_q", num_qubits)
def test_identity(self, num_q, ml_framework):
def test_identity(self, num_q, ml_framework, random_mixed_state):
"""Tests that the identity operation is applied correctly to an unbatched state."""
state_np = get_random_mixed_state(num_q)
state_np = random_mixed_state(num_q)
state = math.asarray(state_np, like=ml_framework)
op = qml.Identity(wires=0)
res = apply_operation(op, state)

assert math.allclose(res, state), f"Operation {op} failed. {res} != {state}"

@pytest.mark.parametrize("num_q", num_qubits)
def test_globalphase(self, num_q, ml_framework):
def test_globalphase(self, num_q, ml_framework, random_mixed_state):
"""Tests that the identity operation is applied correctly to an unbatched state."""
state_np = get_random_mixed_state(num_q)
state_np = random_mixed_state(num_q)
state = math.asarray(state_np, like=ml_framework)
op = qml.GlobalPhase(np.pi / 7, wires=0)
res = apply_operation(op, state)
Expand All @@ -259,10 +237,10 @@ def test_globalphase(self, num_q, ml_framework):

@pytest.mark.parametrize("op", unbroadcasted_ops)
@pytest.mark.parametrize("num_q", num_qubits)
def test_unbroadcasted_ops_batched(self, op, num_q, ml_framework):
def test_unbroadcasted_ops_batched(self, op, num_q, ml_framework, random_mixed_state):
"""Test that unbroadcasted operations are applied correctly to batched states."""
batch_size = self.num_batched
state = np.array([get_random_mixed_state(num_q) for _ in range(batch_size)])
state = np.array([random_mixed_state(num_q) for _ in range(batch_size)])
state = math.asarray(state, like=ml_framework)
res = apply_operation(op, state, is_state_batched=True)

Expand All @@ -286,10 +264,10 @@ def test_unbroadcasted_ops_batched(self, op, num_q, ml_framework):

@pytest.mark.parametrize("op", diagonal_ops)
@pytest.mark.parametrize("num_q", num_qubits)
def test_diagonal_ops_batched(self, op, num_q, ml_framework):
def test_diagonal_ops_batched(self, op, num_q, ml_framework, random_mixed_state):
"""Test that diagonal operations are applied correctly to batched states."""
batch_size = self.num_batched
state = np.array([get_random_mixed_state(num_q) for _ in range(batch_size)])
state = np.array([random_mixed_state(num_q) for _ in range(batch_size)])
state = math.asarray(state, like=ml_framework)
res = apply_operation(op, state, is_state_batched=True)

Expand Down Expand Up @@ -325,9 +303,9 @@ class TestApplyGroverOperator:
(9, "custom"),
],
)
def test_dispatch_method(self, num_wires, expected_method, mocker):
def test_dispatch_method(self, num_wires, expected_method, mocker, random_mixed_state):
"""Test that the correct dispatch method is used based on the number of wires."""
state = get_random_mixed_state(num_wires)
state = random_mixed_state(num_wires)

op = qml.GroverOperator(wires=range(num_wires))

Expand All @@ -348,9 +326,9 @@ def test_dispatch_method(self, num_wires, expected_method, mocker):
# assert not spy_tensordot.called

@pytest.mark.parametrize("num_wires", [2, 3, 7, 8, 9])
def test_correctness(self, num_wires):
def test_correctness(self, num_wires, random_mixed_state):
"""Test that the GroverOperator is applied correctly for various wire numbers."""
state = get_random_mixed_state(num_wires)
state = random_mixed_state(num_wires)

op = qml.GroverOperator(wires=range(num_wires))
op_mat = op.matrix()
Expand All @@ -364,10 +342,10 @@ def test_correctness(self, num_wires):
assert np.allclose(result.reshape(flat_shape), expected)

@pytest.mark.parametrize("num_wires", [2, 3, 7, 8, 9])
def test_batched_state(self, num_wires):
def test_batched_state(self, num_wires, random_mixed_state):
"""Test that the GroverOperator works correctly with batched states."""
batch_size = 3
state = np.array([get_random_mixed_state(num_wires) for _ in range(batch_size)])
state = np.array([random_mixed_state(num_wires) for _ in range(batch_size)])

op = qml.GroverOperator(wires=range(num_wires))
op_mat = op.matrix()
Expand All @@ -382,10 +360,10 @@ def test_batched_state(self, num_wires):
assert np.allclose(result.reshape(flat_shape), expected)

@pytest.mark.parametrize("interface", ml_frameworks_list)
def test_interface_compatibility(self, interface):
def test_interface_compatibility(self, interface, random_mixed_state):
"""Test that the GroverOperator works with different interfaces."""
num_wires = 5
state = get_random_mixed_state(num_wires)
state = random_mixed_state(num_wires)
state = math.asarray(state, like=interface)

op = qml.GroverOperator(wires=range(num_wires))
Expand All @@ -403,6 +381,7 @@ def test_interface_compatibility(self, interface):
class TestApplyMultiControlledX:
"""Test that MultiControlledX is applied correctly to mixed states."""

# pylint: disable=too-many-arguments, too-many-positional-arguments
@pytest.mark.parametrize(
"num_wires, interface, expected_method",
[
Expand All @@ -414,10 +393,12 @@ class TestApplyMultiControlledX:
(9, "autograd", "custom"),
],
)
def test_dispatch_method(self, num_wires, expected_method, interface, mocker):
def test_dispatch_method(
self, num_wires, expected_method, interface, mocker, random_mixed_state
):
"""Test that the correct dispatch method is used based on the number of wires
for numpy and autograd."""
state = get_random_mixed_state(num_wires)
state = random_mixed_state(num_wires)
# Convert to interface
state = math.asarray(state, like=interface)

Expand All @@ -438,6 +419,7 @@ def test_dispatch_method(self, num_wires, expected_method, interface, mocker):
assert not spy_einsum.called
assert not spy_tensordot.called

# pylint: disable=too-many-arguments, too-many-positional-arguments
@pytest.mark.parametrize("interface", ml_frameworks_list[2:])
@pytest.mark.parametrize(
"num_wires, expected_method",
Expand All @@ -448,10 +430,12 @@ def test_dispatch_method(self, num_wires, expected_method, interface, mocker):
(9, "custom"),
],
)
def test_dispatch_method_interfaces(self, num_wires, expected_method, interface, mocker):
def test_dispatch_method_interfaces(
self, num_wires, expected_method, interface, mocker, random_mixed_state
):
"""Test that the correct dispatch method is used based on the number of wires
for torch, tensorflow, and jax."""
state = get_random_mixed_state(num_wires)
state = random_mixed_state(num_wires)
# Convert to interface
state = math.asarray(state, like=interface)

Expand All @@ -473,9 +457,9 @@ def test_dispatch_method_interfaces(self, num_wires, expected_method, interface,
assert not spy_tensordot.called

@pytest.mark.parametrize("num_wires", [2, 3, 7, 8, 9])
def test_correctness(self, num_wires):
def test_correctness(self, num_wires, random_mixed_state):
"""Test that the MultiControlledX is applied correctly for various wire numbers."""
state = get_random_mixed_state(num_wires)
state = random_mixed_state(num_wires)

op = qml.MultiControlledX(wires=range(num_wires))
op_mat = op.matrix()
Expand All @@ -489,10 +473,10 @@ def test_correctness(self, num_wires):
assert np.allclose(result.reshape(flat_shape), expected)

@pytest.mark.parametrize("num_wires", [2, 3, 7, 8, 9])
def test_batched_state(self, num_wires):
def test_batched_state(self, num_wires, random_mixed_state):
"""Test that the MultiControlledX works correctly with batched states."""
batch_size = 3
state = np.array([get_random_mixed_state(num_wires) for _ in range(batch_size)])
state = np.array([random_mixed_state(num_wires) for _ in range(batch_size)])

op = qml.MultiControlledX(wires=range(num_wires))
op_mat = op.matrix()
Expand All @@ -507,10 +491,10 @@ def test_batched_state(self, num_wires):
assert np.allclose(result.reshape(flat_shape), expected)

@pytest.mark.parametrize("interface", ml_frameworks_list)
def test_interface_compatibility(self, interface):
def test_interface_compatibility(self, interface, random_mixed_state):
"""Test that the MultiControlledX works with different interfaces."""
num_wires = 5
state = get_random_mixed_state(num_wires)
state = random_mixed_state(num_wires)
state = math.asarray(state, like=interface)

op = qml.MultiControlledX(wires=range(num_wires))
Expand Down Expand Up @@ -651,10 +635,10 @@ class TestBroadcasting: # pylint: disable=too-few-public-methods
]

@pytest.mark.parametrize("op", broadcasted_ops)
def test_broadcasted_op(self, op, ml_framework):
def test_broadcasted_op(self, op, ml_framework, random_mixed_state):
"""Tests that batched operations are applied correctly to an unbatched state."""
num_q = 3
state = math.asarray(get_random_mixed_state(num_q), like=ml_framework)
state = math.asarray(random_mixed_state(num_q), like=ml_framework)

res = apply_operation(op, state)

Expand All @@ -665,10 +649,10 @@ def test_broadcasted_op(self, op, ml_framework):
assert math.allclose(res, expected)

@pytest.mark.parametrize("op", unbroadcasted_ops)
def test_broadcasted_state(self, op, ml_framework):
def test_broadcasted_state(self, op, ml_framework, random_mixed_state):
"""Tests that batched operations are applied correctly to an unbatched state."""
num_q = 3
state = [math.asarray(get_random_mixed_state(num_q), like=ml_framework) for _ in range(3)]
state = [math.asarray(random_mixed_state(num_q), like=ml_framework) for _ in range(3)]
state = math.stack(state)

res = apply_operation(op, state, is_state_batched=True)
Expand All @@ -680,10 +664,10 @@ def test_broadcasted_state(self, op, ml_framework):
assert math.allclose(res, expected)

@pytest.mark.parametrize("op", broadcasted_ops)
def test_broadcasted_op_broadcasted_state(self, op, ml_framework):
def test_broadcasted_op_broadcasted_state(self, op, ml_framework, random_mixed_state):
"""Tests that batched operations are applied correctly to batched state."""
num_q = 3
state = [math.asarray(get_random_mixed_state(num_q), like=ml_framework) for _ in range(3)]
state = [math.asarray(random_mixed_state(num_q), like=ml_framework) for _ in range(3)]
state = math.stack(state)

res = apply_operation(op, state, is_state_batched=True)
Expand Down

0 comments on commit 7dac47a

Please sign in to comment.