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

Add commutator functions to quantum_info #9546

Merged
merged 16 commits into from
Mar 31, 2023
74 changes: 42 additions & 32 deletions qiskit/quantum_info/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@

partial_trace
shannon_entropy
commutator
anti_commutator
double_commutator

Random
======
Expand Down Expand Up @@ -122,48 +125,55 @@
XXDecomposer
"""

from .operators import Operator, ScalarOp, Pauli, Clifford, SparsePauliOp
from .operators import PauliList, PauliTable, StabilizerTable, pauli_basis
from .operators.channel import Choi, SuperOp, Kraus, Stinespring, Chi, PTM
from .operators.measures import process_fidelity, average_gate_fidelity, gate_error, diamond_norm
from .operators.dihedral import CNOTDihedral

from .states import Statevector, DensityMatrix, StabilizerState
from .states import (
partial_trace,
state_fidelity,
purity,
entropy,
concurrence,
entanglement_of_formation,
mutual_information,
shannon_entropy,
from .analysis import hellinger_distance, hellinger_fidelity
from .operators import (
Clifford,
Operator,
Pauli,
PauliList,
PauliTable,
ScalarOp,
SparsePauliOp,
StabilizerTable,
anti_commutator,
commutator,
double_commutator,
pauli_basis,
)

from .operators.channel import PTM, Chi, Choi, Kraus, Stinespring, SuperOp
from .operators.dihedral import CNOTDihedral
from .operators.measures import average_gate_fidelity, diamond_norm, gate_error, process_fidelity
from .random import (
random_quantum_channel,
random_unitary,
random_clifford,
random_cnotdihedral,
random_density_matrix,
random_hermitian,
random_pauli,
random_pauli_table,
random_pauli_list,
random_pauli_table,
random_quantum_channel,
random_stabilizer_table,
random_hermitian,
random_statevector,
random_density_matrix,
random_cnotdihedral,
random_unitary,
)
from .states import (
DensityMatrix,
StabilizerState,
Statevector,
concurrence,
entanglement_of_formation,
entropy,
mutual_information,
partial_trace,
purity,
shannon_entropy,
state_fidelity,
)

from .synthesis import (
OneQubitEulerDecomposer,
TwoQubitBasisDecomposer,
two_qubit_cnot_decompose,
Quaternion,
decompose_clifford,
TwoQubitBasisDecomposer,
XXDecomposer,
)

from .analysis import (
hellinger_distance,
hellinger_fidelity,
decompose_clifford,
two_qubit_cnot_decompose,
)
8 changes: 2 additions & 6 deletions qiskit/quantum_info/operators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,7 @@

from .channel import PTM, Chi, Choi, Kraus, Stinespring, SuperOp
from .dihedral import CNOTDihedral
from .measures import (
average_gate_fidelity,
diamond_norm,
gate_error,
process_fidelity,
)
from .measures import average_gate_fidelity, diamond_norm, gate_error, process_fidelity
from .operator import Operator
from .scalar_op import ScalarOp
from .symplectic import (
Expand All @@ -31,3 +26,4 @@
StabilizerTable,
pauli_basis,
)
from .utils import anti_commutator, commutator, double_commutator
19 changes: 19 additions & 0 deletions qiskit/quantum_info/operators/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
Quantum information utility functions for operators.
"""

from .anti_commutator import anti_commutator
from .commutator import commutator
from .double_commutator import double_commutator
35 changes: 35 additions & 0 deletions qiskit/quantum_info/operators/utils/anti_commutator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Anti commutator function."""

from typing import TypeVar

from qiskit.quantum_info.operators.linear_op import LinearOp

OperatorTypeT = TypeVar("OperatorTypeT", bound=LinearOp)


def anti_commutator(a: OperatorTypeT, b: OperatorTypeT) -> OperatorTypeT:
r"""Compute anti-commutator of a and b.

.. math::

ab + ba.

Args:
a: Operator a.
b: Operator b.
Returns:
The anti-commutator
"""
return a @ b + b @ a
35 changes: 35 additions & 0 deletions qiskit/quantum_info/operators/utils/commutator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Commutator function."""

from typing import TypeVar

from qiskit.quantum_info.operators.linear_op import LinearOp

OperatorTypeT = TypeVar("OperatorTypeT", bound=LinearOp)


def commutator(a: OperatorTypeT, b: OperatorTypeT) -> OperatorTypeT:
r"""Compute commutator of a and b.

.. math::

ab - ba.

Args:
a: Operator a.
b: Operator b.
Returns:
The commutator
"""
return a @ b - b @ a
75 changes: 75 additions & 0 deletions qiskit/quantum_info/operators/utils/double_commutator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Double commutator function."""

from typing import TypeVar

from qiskit.quantum_info.operators.linear_op import LinearOp

OperatorTypeT = TypeVar("OperatorTypeT", bound=LinearOp)


def double_commutator(
a: OperatorTypeT, b: OperatorTypeT, c: OperatorTypeT, *, commutator: bool = True
) -> OperatorTypeT:
r"""Compute symmetric double commutator of a, b and c.

See also Equation (13.6.18) in [1].

If `commutator` is `True`, it returns

.. math::

[[A, B], C]/2 + [A, [B, C]]/2
= (2ABC + 2CBA - BAC - CAB - ACB - BCA)/2.

If `commutator` is `False`, it returns

.. math::
\lbrace[A, B], C\rbrace/2 + \lbrace A, [B, C]\rbrace/2
= (2ABC - 2CBA - BAC + CAB - ACB + BCA)/2.

Args:
a: Operator a.
b: Operator b.
c: Operator c.
commutator: If ``True`` compute the double commutator,
if ``False`` the double anti-commutator.

Returns:
The double commutator

References:

[1]: R. McWeeny.
Methods of Molecular Quantum Mechanics.
2nd Edition, Academic Press, 1992.
ISBN 0-12-486552-6.
"""
sign_num = -1 if commutator else 1

ab = a @ b
ba = b @ a
ac = a @ c
ca = c @ a

abc = ab @ c
cba = c @ ba
bac = ba @ c
cab = c @ ab
acb = ac @ b
bca = b @ ca

res = abc - sign_num * cba + 0.5 * (-bac + sign_num * cab - acb + sign_num * bca)

return res
7 changes: 7 additions & 0 deletions releasenotes/notes/add-commutator-96ef07433e8ca4e7.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
features:
- |
Add utility functions :func:`~qiskit.quantum_info.commutator`,
:func:`~qiskit.quantum_info.anti_commutator`, and
:func:`~qiskit.quantum_info.double_commutator` to compute commutators
for any objects implementing a :class:`.LinearOp`.
58 changes: 58 additions & 0 deletions test/python/quantum_info/operators/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Tests utility functions for operator classes."""

import unittest

from ddt import data, ddt, unpack

from qiskit.quantum_info import SparsePauliOp, anti_commutator, commutator, double_commutator
from qiskit.test import QiskitTestCase

I = SparsePauliOp("I")
X = SparsePauliOp("X")
Y = SparsePauliOp("Y")
Z = SparsePauliOp("Z")
zero = SparsePauliOp("I", 0)


@ddt
class TestOperatorUtils(QiskitTestCase):
ikkoham marked this conversation as resolved.
Show resolved Hide resolved
"""Test utility functions for operator classes."""

@unpack
@data((Z, I, zero), (Z, X, 2j * Y))
def test_commutator(self, a, b, com):
"""Test commutator function on SparsePauliOp."""
self.assertTrue(commutator(a, b).equiv(com))

@unpack
@data((Z, X, zero), (Z, I, 2 * Z))
def test_anti_commutator(self, a, b, com):
"""Test anti_commutator function on SparsePauliOp."""
self.assertTrue(anti_commutator(a, b).equiv(com))

@unpack
@data(
(X, Y, Z, True, zero),
(X, Y, X, True, -4 * Y),
(X, Y, Z, False, 4j * I),
(X, Y, X, False, zero),
)
def test_double_commutator(self, a, b, c, com, expected):
"""Test double_commutator function on SparsePauliOp."""
self.assertTrue(double_commutator(a, b, c, commutator=com).equiv(expected))


if __name__ == "__main__":
unittest.main()