mirror of https://github.com/Qiskit/qiskit.git
Fix a corner case of `SparsePauliOp.apply_layout` (#12375)
* fix a corner case of `SparsePauliOp.apply_layout` * Add zero-qubit tests of Pauli.apply_layout * use combine and apply isort * Update releasenotes/notes/fix-sparse-pauli-op-apply-layout-zero-43b9e70f0d1536a6.yaml --------- Co-authored-by: Matthew Treinish <mtreinish@kortar.org>
This commit is contained in:
parent
fe69594699
commit
cea93a0516
|
@ -1165,6 +1165,8 @@ class SparsePauliOp(LinearOp):
|
|||
raise QiskitError("Provided layout contains indices outside the number of qubits.")
|
||||
if len(set(layout)) != len(layout):
|
||||
raise QiskitError("Provided layout contains duplicate indices.")
|
||||
if self.num_qubits == 0:
|
||||
return type(self)(["I" * n_qubits] * self.size, self.coeffs)
|
||||
new_op = type(self)("I" * n_qubits)
|
||||
return new_op.compose(self, qargs=layout)
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
fixes:
|
||||
- |
|
||||
Fixed :meth:`.SparsePauliOp.apply_layout` to work correctly with zero-qubit operators.
|
||||
For example, if you previously created a 0 qubit and applied a layout like::
|
||||
|
||||
op = SparsePauliOp("")
|
||||
op.apply_layout(None, 3)
|
||||
|
||||
this would have previously raised an error. Now this will correctly return an operator of the form:
|
||||
``SparsePauliOp(['III'], coeffs=[1.+0.j])``
|
|
@ -14,42 +14,41 @@
|
|||
|
||||
"""Tests for Pauli operator class."""
|
||||
|
||||
import itertools as it
|
||||
import re
|
||||
import unittest
|
||||
import itertools as it
|
||||
from functools import lru_cache
|
||||
from test import QiskitTestCase, combine
|
||||
|
||||
import numpy as np
|
||||
from ddt import ddt, data, unpack
|
||||
from ddt import data, ddt, unpack
|
||||
|
||||
from qiskit import QuantumCircuit
|
||||
from qiskit.circuit import Qubit
|
||||
from qiskit.exceptions import QiskitError
|
||||
from qiskit.circuit.library import (
|
||||
CXGate,
|
||||
CYGate,
|
||||
CZGate,
|
||||
ECRGate,
|
||||
EfficientSU2,
|
||||
HGate,
|
||||
IGate,
|
||||
SdgGate,
|
||||
SGate,
|
||||
SwapGate,
|
||||
XGate,
|
||||
YGate,
|
||||
ZGate,
|
||||
HGate,
|
||||
SGate,
|
||||
SdgGate,
|
||||
CXGate,
|
||||
CZGate,
|
||||
CYGate,
|
||||
SwapGate,
|
||||
ECRGate,
|
||||
EfficientSU2,
|
||||
)
|
||||
from qiskit.circuit.library.generalized_gates import PauliGate
|
||||
from qiskit.compiler.transpiler import transpile
|
||||
from qiskit.providers.fake_provider import GenericBackendV2
|
||||
from qiskit.exceptions import QiskitError
|
||||
from qiskit.primitives import BackendEstimator
|
||||
from qiskit.providers.fake_provider import GenericBackendV2
|
||||
from qiskit.quantum_info.operators import Operator, Pauli, SparsePauliOp
|
||||
from qiskit.quantum_info.random import random_clifford, random_pauli
|
||||
from qiskit.quantum_info.operators import Pauli, Operator, SparsePauliOp
|
||||
from qiskit.utils import optionals
|
||||
|
||||
from test import QiskitTestCase # pylint: disable=wrong-import-order
|
||||
|
||||
|
||||
LABEL_REGEX = re.compile(r"(?P<coeff>[+-]?1?[ij]?)(?P<pauli>[IXYZ]*)")
|
||||
PHASE_MAP = {"": 0, "-i": 1, "-": 2, "i": 3}
|
||||
|
||||
|
@ -618,6 +617,13 @@ class TestPauli(QiskitTestCase):
|
|||
with self.assertRaises(QiskitError):
|
||||
op.apply_layout(layout=[0, 0], num_qubits=3)
|
||||
|
||||
@combine(phase=["", "-i", "-", "i"], layout=[None, []])
|
||||
def test_apply_layout_zero_qubit(self, phase, layout):
|
||||
"""Test apply_layout with a zero-qubit operator"""
|
||||
op = Pauli(phase)
|
||||
res = op.apply_layout(layout=layout, num_qubits=5)
|
||||
self.assertEqual(Pauli(phase + "IIIII"), res)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
|
@ -14,23 +14,22 @@
|
|||
|
||||
import itertools as it
|
||||
import unittest
|
||||
from test import QiskitTestCase, combine
|
||||
|
||||
import numpy as np
|
||||
import scipy.sparse
|
||||
import rustworkx as rx
|
||||
import scipy.sparse
|
||||
from ddt import ddt
|
||||
|
||||
|
||||
from qiskit import QiskitError
|
||||
from qiskit.circuit import ParameterExpression, Parameter, ParameterVector
|
||||
from qiskit.circuit.parametertable import ParameterView
|
||||
from qiskit.quantum_info.operators import Operator, Pauli, PauliList, SparsePauliOp
|
||||
from qiskit.circuit import Parameter, ParameterExpression, ParameterVector
|
||||
from qiskit.circuit.library import EfficientSU2
|
||||
from qiskit.circuit.parametertable import ParameterView
|
||||
from qiskit.compiler.transpiler import transpile
|
||||
from qiskit.primitives import BackendEstimator
|
||||
from qiskit.providers.fake_provider import GenericBackendV2
|
||||
from qiskit.compiler.transpiler import transpile
|
||||
from qiskit.quantum_info.operators import Operator, Pauli, PauliList, SparsePauliOp
|
||||
from qiskit.utils import optionals
|
||||
from test import QiskitTestCase # pylint: disable=wrong-import-order
|
||||
from test import combine # pylint: disable=wrong-import-order
|
||||
|
||||
|
||||
def pauli_mat(label):
|
||||
|
@ -1191,6 +1190,22 @@ class TestSparsePauliOpMethods(QiskitTestCase):
|
|||
with self.assertRaises(QiskitError):
|
||||
op.apply_layout(layout=[0, 0], num_qubits=3)
|
||||
|
||||
@combine(layout=[None, []])
|
||||
def test_apply_layout_zero_qubit(self, layout):
|
||||
"""Test apply_layout with a zero-qubit operator"""
|
||||
with self.subTest("default"):
|
||||
op = SparsePauliOp("")
|
||||
res = op.apply_layout(layout=layout, num_qubits=5)
|
||||
self.assertEqual(SparsePauliOp("IIIII"), res)
|
||||
with self.subTest("coeff"):
|
||||
op = SparsePauliOp("", 2)
|
||||
res = op.apply_layout(layout=layout, num_qubits=5)
|
||||
self.assertEqual(SparsePauliOp("IIIII", 2), res)
|
||||
with self.subTest("multiple ops"):
|
||||
op = SparsePauliOp.from_list([("", 1), ("", 2)])
|
||||
res = op.apply_layout(layout=layout, num_qubits=5)
|
||||
self.assertEqual(SparsePauliOp.from_list([("IIIII", 1), ("IIIII", 2)]), res)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
Loading…
Reference in New Issue