Source code for qutip_qip.noise.relaxation

from collections.abc import Iterable
import numpy as np

from qutip import destroy, num
from qutip_qip.noise import Noise
from qutip_qip.pulse import Pulse
from qutip_qip.typing import Int, IntSequence, Real, RealSequence


[docs] class RelaxationNoise(Noise): """ The decoherence on each qubit characterized by two time scales t1 and t2. Parameters ---------- t1: float or list, optional Characterize the decoherence of amplitude damping for each qubit. t2: float or list, optional Characterize the decoherence of dephasing for each qubit. targets: int or list, optional The indices of qubits that are acted on. Default is on all qubits Attributes ---------- t1: float or list Characterize the decoherence of amplitude damping for each qubit. t2: float or list Characterize the decoherence of dephasing for each qubit. targets: int or list The indices of qubits that are acted on. """ def __init__( self, t1: Real | RealSequence | None = None, t2: Real | RealSequence | None = None, targets: Int | IntSequence | None = None, ): self.t1 = t1 self.t2 = t2 self.targets = targets @staticmethod def _T_to_list(T: Real | RealSequence, N: int) -> RealSequence: """ Check if the relaxation time is valid Parameters ---------- T: float or list of float The relaxation time N: int The number of qubits. Returns ------- T: list of float The relaxation time in Python list form """ if (isinstance(T, Real) and T > 0) or T is None: return [T] * N elif isinstance(T, Iterable) and len(T) == N: return T else: raise ValueError( f"Invalid relaxation time T={T}," "either the length is not equal to the number of qubits, " "or T is not a positive number." )
[docs] def get_noisy_pulses( self, dims: IntSequence | None = None, pulses: RealSequence | None = None, systematic_noise: Pulse | None = None, ) -> tuple[list[Pulse], Pulse]: """ Return the input pulses list with noise added and the pulse independent noise in a dummy :class:`.Pulse` object. Parameters ---------- dims: list, optional The dimension of the components system, the default value is [2,2...,2] for qubits system. pulses : list of :class:`.Pulse`, optional The input pulses. The noise will be added to pulses in this list. systematic_noise : :class:`.Pulse`, optional The dummy pulse with no ideal control element. Returns ------- noisy_pulses: list of :class:`.Pulse` Noisy pulses. systematic_noise : :class:`.Pulse` The dummy pulse representing pulse-independent noise. """ if systematic_noise is None: systematic_noise = Pulse(None, None, label="system") N = len(dims) self.t1 = self._T_to_list(self.t1, N) self.t2 = self._T_to_list(self.t2, N) if len(self.t1) != N or len(self.t2) != N: raise ValueError( "Length of t1 or t2 does not match N, " f"len(t1)={len(self.t1)}, len(t2)={len(self.t2)}" ) if self.targets is None: targets = range(N) else: targets = self.targets for qu_ind in targets: t1 = self.t1[qu_ind] t2 = self.t2[qu_ind] if t1 is not None: op = 1 / np.sqrt(t1) * destroy(dims[qu_ind]) systematic_noise.add_lindblad_noise(op, qu_ind, coeff=True) if t2 is not None: # Keep the total dephasing ~ exp(-t/t2) if t1 is not None: if 2 * t1 < t2: raise ValueError(f"t1={t1}, t2={t2} does not fulfill 2*t1>t2") T2_eff = 1.0 / (1.0 / t2 - 1.0 / 2.0 / t1) else: T2_eff = t2 op = 1 / np.sqrt(2 * T2_eff) * 2 * num(dims[qu_ind]) systematic_noise.add_lindblad_noise(op, qu_ind, coeff=True) return pulses, systematic_noise