Source code for qiskit_addon_cutting.qpd.qpd_basis
# This code is a Qiskit project.# (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."""Class containing the basis in which to decompose an operation."""from__future__importannotationsfromcollections.abcimportSequenceimportnumpyasnpfromqiskit.circuitimportInstruction
[docs]classQPDBasis:"""Basis in which to decompose an operation. This class defines a basis in which a quantum operation will be decomposed. The ideal (noise-free) quantum operation will be decomposed into a quasiprobabilistic mixture of noisy circuits. """def__init__(self,maps:Sequence[tuple[Sequence[Instruction],...]],coeffs:Sequence[float],):"""Assign member variables. Args: maps: A sequence of tuples describing the noisy operations probabilistically used to simulate an ideal quantum operation. coeffs: Coefficients for quasiprobability representation. Each coefficient can be any real number. Returns: None """self._set_maps(maps)self.coeffs=coeffs# Note: probabilities and kappa calculated through coeffs@propertydefmaps(self,)->Sequence[tuple[Sequence[Instruction],...]]:"""Get mappings for each qubit in the decomposition."""returnself._mapsdef_set_maps(self,maps:Sequence[tuple[Sequence[Instruction],...]],)->None:iflen(maps)==0:raiseValueError("Number of maps passed to QPDBasis must be nonzero.")num_qubits=len(maps[0])ifnum_qubits>2:raiseValueError("QPDBasis supports at most two qubits.")foriinrange(1,len(maps)):iflen(maps[i])!=num_qubits:raiseValueError(f"All maps passed to QPDBasis must act on the same number of "f"qubits. (Index {i} contains a {len(maps[i])}-tuple but should "f"contain a {num_qubits}-tuple.)")self._maps=maps@propertydefnum_qubits(self)->int:"""Get number of qubits that this decomposition acts on."""returnlen(self._maps[0])@propertydefcoeffs(self)->Sequence[float]:"""Quasiprobability decomposition coefficients."""returnself._coeffs@coeffs.setterdefcoeffs(self,coeffs:Sequence[float])->None:iflen(coeffs)!=len(self.maps):# Note: cross-validationraiseValueError("Coefficients must be same length as maps.")weights=np.abs(coeffs)self._kappa=sum(weights)self._probabilities=weights/self._kappaself._coeffs=coeffs@propertydefprobabilities(self)->Sequence[float]:"""Get the probabilities on which the maps will be sampled."""returnself._probabilities@propertydefkappa(self)->float:"""Get the square root of the sampling overhead. This quantity is the sum of the magnitude of the coefficients. """returnself._kappa@propertydefoverhead(self)->float:"""Get the sampling overhead. The sampling overhead is the square of the sum of the magnitude of the coefficients. """returnself._kappa**2
[docs]@staticmethoddeffrom_instruction(gate:Instruction,/)->QPDBasis:"""Generate a :class:`.QPDBasis` object, given a supported operation. This static method is provided for convenience; it simply calls :func:`~qpd.decompositions.qpdbasis_from_instruction` under the hood. Args: gate: The instruction from which to instantiate a decomposition Returns: The newly-instantiated :class:`QPDBasis` object """# pylint: disable=cyclic-importfrom.decompositionsimportqpdbasis_from_instructionreturnqpdbasis_from_instruction(gate)
def__eq__(self,other):"""Check equivalence for QPDBasis class."""ifother.__class__isnotself.__class__:returnFalseiflen(self.maps)!=len(other.maps)orlen(self.coeffs)!=len(other.coeffs):returnFalseifself.maps!=other.maps:returnFalseifself.coeffs!=other.coeffs:returnFalsereturnTrue