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 transpile_operator function to primitives.utils #9988

Closed
wants to merge 3 commits into from
Closed
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
32 changes: 31 additions & 1 deletion qiskit/primitives/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,18 @@
from __future__ import annotations

from collections.abc import Iterable
from typing import Sequence
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use collections.abc instead of typing here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh... What’s wrong with me


import numpy as np

from qiskit.circuit import Instruction, ParameterExpression, QuantumCircuit
from qiskit.circuit import Instruction, ParameterExpression, QuantumCircuit, Qubit
from qiskit.circuit.bit import Bit
from qiskit.extensions.quantum_initializer.initializer import Initialize
from qiskit.opflow import PauliSumOp
from qiskit.quantum_info import SparsePauliOp, Statevector
from qiskit.quantum_info.operators.base_operator import BaseOperator
from qiskit.quantum_info.operators.symplectic.base_pauli import BasePauli
from qiskit.transpiler.layout import TranspileLayout


def init_circuit(state: QuantumCircuit | Statevector) -> QuantumCircuit:
Expand Down Expand Up @@ -213,3 +215,31 @@ def bound_circuit_to_instruction(circuit: QuantumCircuit) -> Instruction:
)
inst.definition = circuit
return inst


def transpile_operator(
operator: BaseOperator | PauliSumOp | str,
layout: TranspileLayout,
original_qubits: Sequence[Qubit],
) -> SparsePauliOp:
"""Utility function for transpilation of operator.

If skip_transpilation is True, users need to transpile the operator corresponding to the layout
of the transpiled circuit. This function helps the transpilation of operator.

Args:
operator: Operator to be transpiled.
layout: The layout of the transpiled circuit.
original_qubits: Qubits that original circuit has.

Returns:
The operator for the given layout.
"""
operator = init_observable(operator)
virtual_bit_map = layout.initial_layout.get_virtual_bits()
identity = SparsePauliOp("I" * len(virtual_bit_map))
perm_pattern = [virtual_bit_map[v] for v in original_qubits]
if layout.final_layout is not None:
final_mapping = dict(enumerate(layout.final_layout.get_virtual_bits().values()))
perm_pattern = [final_mapping[i] for i in perm_pattern]
return identity.compose(operator, qargs=perm_pattern)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
features:
- |
Add :func:`~primitives.utils.transpile_operator` function.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this will be found as it is, I think it would be safer to either add the full path, or use .transpile_operator only 🙂

Suggested change
Add :func:`~primitives.utils.transpile_operator` function.
Add :func:`~qiskit.primitives.utils.transpile_operator` function.

If skip_transpilation is True, users need to transpile the operator corresponding to the layout
of the transpiled circuit. The function helps the transpilation of operator.
40 changes: 38 additions & 2 deletions test/python/primitives/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,17 @@

"""Tests for utilities of Primitives."""

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
from qiskit.primitives.utils import final_measurement_mapping
from test import combine

from ddt import ddt

from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister, transpile
from qiskit.primitives import BackendEstimator
from qiskit.primitives.utils import final_measurement_mapping, transpile_operator
from qiskit.providers.fake_provider import FakeNairobi, FakeNairobiV2
from qiskit.quantum_info import SparsePauliOp
from qiskit.test import QiskitTestCase
from qiskit.utils import optionals


class TestMapping(QiskitTestCase):
Expand Down Expand Up @@ -83,3 +91,31 @@ def test_mapping_w_delays(self):

maps = final_measurement_mapping(qc)
self.assertDictEqual(maps, {1: 0, 0: 1})


BACKENDS = [FakeNairobi(), FakeNairobiV2()]


@ddt
class TestTranspileOperator(QiskitTestCase):
"""Test transpile_operator utility function."""

@combine(backend=BACKENDS)
def test_tranpile_operator(self, backend):
"""test for transpile_operator"""
backend.set_options(seed_simulator=15)
n = 6
qc = QuantumCircuit(n)
qc.x(n - 1)
qc.h(range(n))
qc.cx(range(n - 1), n - 1)
qc.h(range(n - 1))
trans_qc = transpile(qc, backend, seed_transpiler=15)

op = SparsePauliOp("Z" * n)
trans_op = transpile_operator(op, trans_qc.layout, qc.qubits)
result = BackendEstimator(backend=backend).run(trans_qc, trans_op).result()
if optionals.HAS_AER:
self.assertAlmostEqual(result.values[0], -0.045, places=2)
else:
self.assertAlmostEqual(result.values[0], 0, places=2)
Comment on lines +117 to +121
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add an additional test that checks that trans_op equals the expected operator? Testing that the values are correct is also good, but there are other steps included which could affect the test, so I think it would be good to have a very specific one too 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure.