|
| 1 | +# This code is part of Qiskit. |
| 2 | +# |
| 3 | +# (C) Copyright IBM 2024. |
| 4 | +# |
| 5 | +# This code is licensed under the Apache License, Version 2.0. You may |
| 6 | +# obtain a copy of this license in the LICENSE.txt file in the root directory |
| 7 | +# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. |
| 8 | +# |
| 9 | +# Any modifications or derivative works of this code must retain this |
| 10 | +# copyright notice, and modified files need to carry a notice indicating |
| 11 | +# that they have been altered from the originals. |
| 12 | + |
| 13 | +"""Test QAOA circuits module.""" |
| 14 | + |
| 15 | + |
| 16 | +from pytest import mark, raises # pylint: disable=import-error |
| 17 | +from qiskit import QuantumCircuit |
| 18 | + |
| 19 | +from quantum_enablement.circuits._qaoa import QAOAPathCircuit |
| 20 | + |
| 21 | + |
| 22 | +def two_qubit_depth_filter(instruction): |
| 23 | + """Filter instructions which do not contribute to two-qubit depth.""" |
| 24 | + num_qubits = instruction.operation.num_qubits |
| 25 | + name = instruction.operation.name |
| 26 | + return num_qubits > 1 and name != "barrier" |
| 27 | + |
| 28 | + |
| 29 | +class TestQAOAPathCircuit: |
| 30 | + """Test suite for the QAOAPathCircuit class.""" |
| 31 | + |
| 32 | + @mark.parametrize("num_qubits", [4, 6]) |
| 33 | + @mark.parametrize("depth", [0, 2, 4]) |
| 34 | + def test_creation(self, num_qubits, depth): |
| 35 | + """Test QAOAPathCircuit creation.""" |
| 36 | + circuit = QAOAPathCircuit(num_qubits, depth, barriers=False, measurements=False) |
| 37 | + op_counts = circuit.count_ops() |
| 38 | + assert isinstance(circuit, QuantumCircuit), "QAOAPathCircuit must be a QuantumCircuit." |
| 39 | + assert circuit.num_qubits == num_qubits, "Wrong number of qubits." |
| 40 | + assert circuit.depth(two_qubit_depth_filter) == depth, "Wrong two-qubit depth." |
| 41 | + assert circuit.num_parameters == depth, "Wrong number of parameters." |
| 42 | + assert op_counts.get("h", 0) == num_qubits, "Wrong number of H gates." |
| 43 | + assert op_counts.get("rzz", 0) == (num_qubits - 1) * ( |
| 44 | + depth // 2 |
| 45 | + ), "Wrong number of RZZ gates." |
| 46 | + assert op_counts.get("rx", 0) == num_qubits * (depth // 2), "Wrong number of RX gates." |
| 47 | + assert op_counts.get("barrier", 0) == 0, "Wrong number of barriers." |
| 48 | + assert op_counts.get("measure", 0) == 0, "Wrong number of measurements." |
| 49 | + |
| 50 | + def test_defaults(self): |
| 51 | + """Test QAOAPathCircuit defaults.""" |
| 52 | + circuit = QAOAPathCircuit(4, 4) # Note: default barriers and measurements are False. |
| 53 | + op_counts = circuit.count_ops() |
| 54 | + assert op_counts.get("barrier", 0) == 0, "By default barriers should not be present." |
| 55 | + assert op_counts.get("measure", 0) == 0, "By default measurements should not be present." |
| 56 | + |
| 57 | + @mark.parametrize("num_qubits", [4, 6]) |
| 58 | + @mark.parametrize("depth", [0, 2, 4]) |
| 59 | + def test_barriers(self, num_qubits, depth): |
| 60 | + """Test QAOAPathCircuit barriers.""" |
| 61 | + circuit = QAOAPathCircuit(num_qubits, depth, barriers=True, measurements=False) |
| 62 | + op_counts = circuit.count_ops() |
| 63 | + assert op_counts.get("barrier", 0) == depth // 2, "Wrong number of barriers." |
| 64 | + # circuit.remove_operations("barrier") |
| 65 | + # assert circuit == QAOAPathCircuit(num_qubits, depth, measurements=False, barriers=False) |
| 66 | + |
| 67 | + @mark.parametrize("num_qubits", [4, 6]) |
| 68 | + @mark.parametrize("depth", [0, 2, 4]) |
| 69 | + def test_measurements(self, num_qubits, depth): |
| 70 | + """Test QAOAPathCircuit measurements.""" |
| 71 | + circuit = QAOAPathCircuit(num_qubits, depth, barriers=False, measurements=True) |
| 72 | + op_counts = circuit.count_ops() |
| 73 | + assert op_counts.get("measure", 0) == num_qubits, "Wrong number of measurements." |
| 74 | + assert op_counts.get("barrier", 0) == 1, "Measurements should be preceded by a barrier." |
| 75 | + # circuit.remove_final_measurements() |
| 76 | + # assert circuit == QAOAPathCircuit(num_qubits, depth, measurements=False, barriers=False) |
| 77 | + |
| 78 | + @mark.parametrize("num_qubits", [4, 6]) |
| 79 | + @mark.parametrize("depth", [0, 2, 4]) |
| 80 | + def test_name(self, num_qubits, depth): |
| 81 | + """Test QAOAPathCircuit name.""" |
| 82 | + circuit = QAOAPathCircuit(num_qubits, depth) |
| 83 | + assert circuit.name == f"QAOAPathCircuit<{num_qubits}, {depth}>", "Wrong circuit name." |
| 84 | + |
| 85 | + def test_invalid_num_qubits(self): |
| 86 | + """Test QAOAPathCircuit with invalid number of qubits.""" |
| 87 | + with raises(ValueError, match=r"Number of qubits \(2\) must be greater than two."): |
| 88 | + QAOAPathCircuit(2, 2) |
| 89 | + |
| 90 | + with raises(ValueError, match=r"Number of qubits \(3\) must be even\."): |
| 91 | + QAOAPathCircuit(3, 2) |
| 92 | + |
| 93 | + with raises(TypeError, match=r"Invalid num\. qubits type .*, expected <int>\."): |
| 94 | + QAOAPathCircuit("4", 2) # type: ignore |
| 95 | + |
| 96 | + def test_invalid_depth(self): |
| 97 | + """Test QAOAPathCircuit with invalid depth.""" |
| 98 | + with raises(ValueError, match=r"Depth \(-1\) must be positive\."): |
| 99 | + QAOAPathCircuit(4, -1) |
| 100 | + |
| 101 | + with raises(ValueError, match=r"Depth \(1\) must be even\."): |
| 102 | + QAOAPathCircuit(4, 1) |
| 103 | + |
| 104 | + with raises(TypeError, match=r"Invalid depth type .*, expected <int>\."): |
| 105 | + QAOAPathCircuit(4, "2") # type: ignore |
0 commit comments