Source code for qdk_chemistry.algorithms.circuit_mapper.pauli_sequence_mapper

"""QDK/Chemistry sequence structure evolution circuit mapper."""

# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

from qdk import qsharp

from qdk_chemistry.data import Settings
from qdk_chemistry.data.circuit import Circuit, QsharpFactoryData
from qdk_chemistry.data.unitary_representation.base import UnitaryRepresentation
from qdk_chemistry.data.unitary_representation.containers.pauli_product_formula import (
    PauliProductFormulaContainer,
)
from qdk_chemistry.utils.qsharp import QSHARP_UTILS

from .base import CircuitMapper

__all__: list[str] = ["PauliSequenceMapper", "PauliSequenceMapperSettings"]


[docs] class PauliSequenceMapperSettings(Settings): """Settings for PauliSequenceMapper."""
[docs] def __init__(self): """Initialize PauliSequenceMapperSettings with default values.""" super().__init__()
[docs] class PauliSequenceMapper(CircuitMapper): r"""Circuit mapper using Pauli product formula term sequences. Given a unitary expressed as a Pauli product formula :math:`U \approx \left[ \prod_j e^{-i\theta_j P_j} \right]^{r}`, this mapper constructs a circuit for :math:`U` using the following pattern: 1. Each Pauli operator :math:`P_j` is basis-rotated into the :math:`Z` basis. 2. Qubits involved in :math:`P_j` are entangled into a sequence using CNOT gates. 3. A :math:`R_z` rotation implements :math:`e^{-i\,\theta_j\,P_j} \;\rightarrow\; R_z(2 \theta_j)`. 4. The basis rotations and entangling operations are uncomputed. Notes: * Requires a ``PauliProductFormulaContainer`` for the unitary representation. """
[docs] def __init__(self): """Initialize the PauliSequenceMapper.""" super().__init__() self._settings = PauliSequenceMapperSettings()
[docs] def name(self) -> str: """Return the algorithm name.""" return "pauli_sequence"
[docs] def type_name(self) -> str: """Return circuit_mapper as the algorithm type name.""" return "circuit_mapper"
def _run_impl(self, evolution: UnitaryRepresentation) -> Circuit: r"""Construct a quantum circuit implementing the given unitary. Args: evolution: The unitary representation to map into a circuit. Returns: Circuit: A quantum circuit implementing the unitary. Raises: ValueError: If the unitary container type is not supported. """ unitary_container = evolution.get_container() if not isinstance(unitary_container, PauliProductFormulaContainer): raise ValueError( f"The {evolution.get_container_type()} container type is not supported. " "PauliSequenceMapper only supports PauliProductFormula containers." ) pauli_terms: list[list[qsharp.Pauli]] = [] angles: list[float] = [] for term in unitary_container.step_terms: base_terms = [qsharp.Pauli.I] * unitary_container.num_qubits for index, pauli in term.pauli_term.items(): base_terms[index] = getattr(qsharp.Pauli, pauli) pauli_terms.append(base_terms.copy()) angles.append(term.angle) evo_params = { "pauliExponents": pauli_terms, "pauliCoefficients": angles, "repetitions": unitary_container.step_reps, } target_indices = list(range(unitary_container.num_qubits)) qsc = qsharp.circuit( QSHARP_UTILS.PauliExp.MakeRepPauliExpCircuit, evo_params, target_indices, ) qir = qsharp.compile( QSHARP_UTILS.PauliExp.MakeRepPauliExpCircuit, evo_params, target_indices, ) evolution_op = QSHARP_UTILS.PauliExp.MakeRepPauliExpOp(evo_params) factory = QsharpFactoryData( program=QSHARP_UTILS.PauliExp.MakeRepPauliExpCircuit, parameter={"evo_params": evo_params, "target_indices": target_indices}, ) return Circuit(qsharp=qsc, qir=qir, qsharp_op=evolution_op, qsharp_factory=factory)