Source code for qc_executor.quantum_operator

"""Concrete quantum operator implementation backed by a Qiskit SparsePauliOp."""

from __future__ import annotations

from typing import Any, List, Optional, cast

from qiskit.quantum_info import SparsePauliOp

from .base import QuantumOperatorBase
from .utils.qiskit_hash_functions import _observable_key


[docs] class QuantumOperator(QuantumOperatorBase): """Quantum operator backed by a Qiskit SparsePauliOp."""
[docs] @classmethod def from_quantum_operator(cls, operator: QuantumOperatorBase) -> QuantumOperatorBase: """Identity conversion for generic operators.""" return operator
def __init__( self, paulis: Optional[List[str]] = None, coeffs: Optional[List[float]] = None, num_qubits: Optional[int] = None, _native_operator: Optional[SparsePauliOp] = None, ): super().__init__(num_qubits=num_qubits, paulis=paulis, coeffs=coeffs) if _native_operator is not None: self._qiskit_operator: SparsePauliOp = _native_operator elif paulis is not None: self._qiskit_operator = SparsePauliOp(paulis, coeffs=cast(Any, coeffs)) elif num_qubits is not None: self._qiskit_operator = SparsePauliOp.from_list([("I" * num_qubits, 0.0)]) else: raise ValueError("Must provide paulis, num_qubits, or _native_operator") @property def qiskit_operator(self) -> SparsePauliOp: """The underlying Qiskit SparsePauliOp.""" return self._qiskit_operator @property def num_qubits(self) -> int: """Return the number of qubits in the circuit.""" return cast(int, self._qiskit_operator.num_qubits) @property def num_paulis(self) -> int: """Return the number of Paulis in the operator.""" return len(self.paulis) @property def paulis(self) -> List[str]: """Return the list of Paulis.""" return list(self._qiskit_operator.paulis.to_labels()) @property def coeffs(self) -> List: """Return the list of coefficients.""" return cast(Any, self._qiskit_operator.coeffs).tolist() @property def is_parametrized(self) -> bool: """Return True if the operator is parametrized.""" return len(self.parameters) > 0 @property def parameters(self) -> list: """ Return the parameters of the operator. Returns: List of parameters. """ return list(self._qiskit_operator.parameters) @property def num_parameters(self) -> int: """ Return the number of parameters in the operator. Returns: Number of parameters. """ return len(self.parameters)
[docs] def copy(self) -> "QuantumOperatorBase": """ Return a copy of the operator. Returns: Copy of the operator. """ return_value = self.__class__(_native_operator=self._qiskit_operator.copy()) return return_value
[docs] def adjoint(self) -> "QuantumOperatorBase": """ Return the adjoint of the operator. Returns: Adjoint of the operator. """ return_value = self.__class__(_native_operator=self._qiskit_operator.adjoint()) return return_value
[docs] def apply_layout(self, layout: List[int]) -> "QuantumOperatorBase": """ Apply a layout to the operator. Args: layout (List[int]): Layout to apply. Returns: Operator with applied layout. """ return_value = self.__class__(_native_operator=self._qiskit_operator.apply_layout(layout)) return return_value
[docs] def compose(self, other: "QuantumOperatorBase") -> "QuantumOperatorBase": """ Compose the operator with another operator. Args: other (QuantumOperatorBase): Operator to compose with. Returns: Composed operator. """ if not isinstance(other, QuantumOperator): raise TypeError("Can only compose with a QuantumOperator instance") self._qiskit_operator = self._qiskit_operator.compose(other.qiskit_operator) return self
[docs] def append(self, pauli: str, coeff=None) -> "QuantumOperatorBase": """ Append a Pauli operator with a coefficient to the operator. Args: pauli (str): Pauli operator to append. coeff (float): Coefficient of the Pauli operator. """ if coeff is None: coeff = 1.0 self._qiskit_operator = SparsePauliOp.from_list( self._qiskit_operator.to_list() + [(pauli, coeff)] ) return self
[docs] def simplify(self) -> "QuantumOperatorBase": """ Simplify the operator. Returns: Simplified operator. """ return_value = self.__class__(_native_operator=self._qiskit_operator.simplify()) return return_value
[docs] def transpose(self) -> "QuantumOperatorBase": """ Return the transpose of the operator. Returns: Transpose of the operator. """ return_value = self.__class__(_native_operator=self._qiskit_operator.transpose()) return return_value
[docs] def conjugate(self) -> "QuantumOperatorBase": """ Return the conjugate of the operator. Returns: Conjugate of the operator. """ return_value = self.__class__(_native_operator=self._qiskit_operator.conjugate()) return return_value
[docs] def group_commuting(self) -> List["QuantumOperatorBase"]: """ Group commuting operators. Returns: List of commuting operators. """ commuting_op = self._qiskit_operator.group_commuting() return [self.__class__(_native_operator=operator) for operator in commuting_op]
@property def is_unitary(self) -> bool: """ Return True if the operator is unitary. Returns: True if the operator is unitary. """ return self._qiskit_operator.is_unitary() @property def is_real(self) -> bool: """ Return True if the operator is real. Returns: True if the operator is real. """ raise NotImplementedError @property def is_imaginary(self) -> bool: """ Return True if the operator is imaginary. Returns: True if the operator is imaginary. """ raise NotImplementedError def __hash__(self): return hash(_observable_key(self._qiskit_operator)) def __eq__(self, other): return ( isinstance(other, QuantumOperator) and self._qiskit_operator == other._qiskit_operator ) def __str__(self): """ Return the string representation of the operator. Returns: String representation of the operator. """ return str(self._qiskit_operator) def __repr__(self): """ Return the string representation of the operator. Returns: String representation of the operator. """ return str(self._qiskit_operator)