def set_up_ops(self, N): """ Generate the Hamiltonians for the spinchain model and save them in the attribute `ctrls`. Parameters ---------- N: int The number of qubits in the system. """ self.pulse_dict = {} index = 0 # sx_ops for m in range(N): self.pulses.append( Pulse(sigmax(), m, spline_kind=self.spline_kind)) self.pulse_dict["sx" + str(m)] = index index += 1 # sz_ops for m in range(N): self.pulses.append( Pulse(sigmaz(), m, spline_kind=self.spline_kind)) self.pulse_dict["sz" + str(m)] = index index += 1 # sxsy_ops operator = tensor([sigmax(), sigmax()]) + tensor([sigmay(), sigmay()]) for n in range(N - 1): self.pulses.append( Pulse(operator, [n, n+1], spline_kind=self.spline_kind)) self.pulse_dict["g" + str(n)] = index index += 1
def set_up_ops(self, N): """ Generate the Hamiltonians for the spinchain model and save them in the attribute `ctrls`. Parameters ---------- N: int The number of qubits in the system. """ # single qubit terms self.a = tensor(destroy(self.num_levels)) self.pulses.append( Pulse(self.a.dag() * self.a, [0], spline_kind=self.spline_kind)) for m in range(N): self.pulses.append( Pulse(sigmax(), [m + 1], spline_kind=self.spline_kind)) for m in range(N): self.pulses.append( Pulse(sigmaz(), [m + 1], spline_kind=self.spline_kind)) # interaction terms a_full = tensor([destroy(self.num_levels)] + [identity(2) for n in range(N)]) for n in range(N): sm = tensor( [identity(self.num_levels)] + [destroy(2) if m == n else identity(2) for m in range(N)]) self.pulses.append( Pulse(a_full.dag() * sm + a_full * sm.dag(), list(range(N + 1)), spline_kind=self.spline_kind)) self.psi_proj = tensor([basis(self.num_levels, 0)] + [identity(2) for n in range(N)])
def add_control(self, qobj, targets=None, cyclic_permutation=False, label=None): """ Add a control Hamiltonian to the processor. It creates a new :class:`qutip.qip.Pulse` object for the device that is turned off (``tlist = None``, ``coeff = None``). To activate the pulse, one can set its `tlist` and `coeff`. Parameters ---------- qobj: :class:`qutip.Qobj` The Hamiltonian for the control pulse.. targets: list, optional The indices of the target qubits (or subquantum system of other dimensions). cyclic_permutation: bool, optional If true, the Hamiltonian will be expanded for all cyclic permutation of the target qubits. label: str, optional The label (name) of the pulse """ # Check validity of ctrl if not isinstance(qobj, Qobj): raise TypeError("The control Hamiltonian must be a qutip.Qobj.") if not qobj.isherm: raise ValueError("The control Hamiltonian must be Hermitian.") num_qubits = len(qobj.dims[0]) if targets is None: targets = list(range(num_qubits)) if not isinstance(targets, list): targets = [targets] if cyclic_permutation: for i in range(self.N): temp_targets = [(t + i) % self.N for t in targets] if label is not None: temp_label = label + "_" + str(temp_targets) temp_label = label self.pulses.append( Pulse(qobj, temp_targets, spline_kind=self.spline_kind, label=temp_label)) else: self.pulses.append( Pulse(qobj, targets, spline_kind=self.spline_kind, label=label))
def test_id_with_T1_T2(self): """ Test for identity evolution with relaxation t1 and t2 """ # setup a = destroy(2) Hadamard = hadamard_transform(1) ex_state = basis(2, 1) mines_state = (basis(2, 1) - basis(2, 0)).unit() end_time = 2. tlist = np.arange(0, end_time + 0.02, 0.02) t1 = 1. t2 = 0.5 # test t1 test = Processor(1, t1=t1) # zero ham evolution test.add_pulse(Pulse(identity(2), 0, tlist, False)) result = test.run_state(ex_state, e_ops=[a.dag() * a]) assert_allclose(result.expect[0][-1], np.exp(-1. / t1 * end_time), rtol=1e-5, err_msg="Error in t1 time simulation") # test t2 test = Processor(1, t2=t2) test.add_pulse(Pulse(identity(2), 0, tlist, False)) result = test.run_state(init_state=mines_state, e_ops=[Hadamard * a.dag() * a * Hadamard]) assert_allclose(result.expect[0][-1], np.exp(-1. / t2 * end_time) * 0.5 + 0.5, rtol=1e-5, err_msg="Error in t2 time simulation") # test t1 and t2 t1 = np.random.rand(1) + 0.5 t2 = np.random.rand(1) * 0.5 + 0.5 test = Processor(1, t1=t1, t2=t2) test.add_pulse(Pulse(identity(2), 0, tlist, False)) result = test.run_state(init_state=mines_state, e_ops=[Hadamard * a.dag() * a * Hadamard]) assert_allclose(result.expect[0][-1], np.exp(-1. / t2 * end_time) * 0.5 + 0.5, rtol=1e-5, err_msg="Error in t1 & t2 simulation, " "with t1={} and t2={}".format(t1, t2))
def TestDrift(self): """ Test for the drift Hamiltonian """ processor = Processor(N=1) processor.add_drift(sigmaz(), 0) tlist = np.array([0., 1., 2.]) processor.add_pulse(Pulse(identity(2), 0, tlist, False)) ideal_qobjevo, _ = processor.get_qobjevo(noisy=True) assert_equal(ideal_qobjevo.cte, sigmaz())
def process_noise(pulses, noise_list, dims, t1=None, t2=None, device_noise=False): """ Apply noise to the input list of pulses. It does not modify the input pulse, but return a new one containing the noise. Parameters ---------- pulses: list of :class:`qutip.qip.Pulse` The input pulses, on which the noise object will be applied. noise_list: list of :class:`qutip.qip.noise` A list of noise objects. dims: int or list Dimension of the system. If int, we assume it is the number of qubits in the system. If list, it is the dimension of the component systems. t1: list or float, optional Characterize the decoherence of amplitude damping for each qubit. A list of size `N` or a float for all qubits. t2: list of float, optional Characterize the decoherence of dephasing for each qubit. A list of size `N` or a float for all qubits. device_noise: bool If pulse independent noise such as relaxation are included. Default is False. Returns ------- noisy_pulses: list of :class:`qutip.qip.Pulse` The noisy pulses, including the system noise. """ noisy_pulses = deepcopy(pulses) systematic_noise = Pulse(None, None, label="systematic_noise") if (t1 is not None) or (t2 is not None): noise_list.append(RelaxationNoise(t1, t2)) for noise in noise_list: if isinstance(noise, (DecoherenceNoise, RelaxationNoise)) \ and not device_noise: pass else: noisy_pulses, systematic_noise = noise._apply_noise( dims=dims, pulses=noisy_pulses, systematic_noise=systematic_noise) if device_noise: return noisy_pulses + [systematic_noise] else: return noisy_pulses
def get_noisy_dynamics(self, dims): """ Return a list of Pulse object with only trivial ideal pulse (H=0) but non-trivial lindblad noise. Parameters ---------- dims: list, optional The dimension of the components system, the default value is [2,2...,2] for qubits system. Returns ------- lindblad_noise: list of :class:`qutip.qip.Pulse` A list of Pulse object with only trivial ideal pulse (H=0) but non-trivial lindblad noise. """ if isinstance(dims, list): N = len(dims) else: N = dims # time-independent if (self.coeff is None) and (self.tlist is None): self.coeff = True lindblad_noise = Pulse(None, None) for c_op in self.c_ops: if self.all_qubits: for targets in range(N): lindblad_noise.add_lindblad_noise(c_op, targets, self.tlist, self.coeff) else: lindblad_noise.add_lindblad_noise(c_op, self.targets, self.tlist, self.coeff) return lindblad_noise
def TestUserNoise(self): """ Test for the user-defined noise object """ dr_noise = DriftNoise(sigmax()) proc = Processor(1) proc.add_noise(dr_noise) tlist = np.array([0, np.pi / 2.]) proc.add_pulse(Pulse(identity(2), 0, tlist, False)) result = proc.run_state(init_state=basis(2, 0)) assert_allclose(fidelity(result.states[-1], basis(2, 1)), 1, rtol=1.0e-6)
def TestControlAmpNoise(self): """ Test for the control amplitude noise """ tlist = np.array([1, 2, 3, 4, 5, 6]) coeff = np.array([1, 1, 1, 1, 1, 1]) # use proc_qobjevo pulses = [Pulse(sigmaz(), 0, tlist, coeff)] connoise = ControlAmpNoise(coeff=coeff, tlist=tlist) noisy_pulses = connoise.get_noisy_dynamics(pulses=pulses) assert_allclose(noisy_pulses[0].coherent_noise[0].qobj, sigmaz()) assert_allclose(noisy_pulses[0].coherent_noise[0].coeff, coeff)
def test_id_evolution(self): """ Test for identity evolution """ N = 1 proc = Processor(N=N) init_state = rand_ket(2) tlist = [0., 1., 2.] proc.add_pulse(Pulse(identity(2), 0, tlist, False)) result = proc.run_state( init_state, options=Options(store_final_state=True)) global_phase = init_state.data[0, 0]/result.final_state.data[0, 0] assert_allclose(global_phase*result.final_state, init_state)
def get_noisy_dynamics(self, dims): """ Return a list of Pulse object with only trivial ideal pulse (H=0) but non-trivial relaxation noise. Parameters ---------- dims: list, optional The dimension of the components system, the default value is [2,2...,2] for qubits system. Returns ------- lindblad_noise: list of :class:`qutip.qip.Pulse` A list of Pulse object with only trivial ideal pulse (H=0) but non-trivial relaxation noise. """ if isinstance(dims, list): for d in dims: if d != 2: raise ValueError( "Relaxation noise is defined only for qubits system") N = len(dims) else: N = 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, " "len(t1)={}, len(t2)={}".format( len(self.t1), len(self.t2))) lindblad_noise = Pulse(None, None) 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(2) lindblad_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( "t1={}, t2={} does not fulfill " "2*t1>t2".format(t1, t2)) T2_eff = 1./(1./t2-1./2./t1) else: T2_eff = t2 op = 1/np.sqrt(2*T2_eff) * sigmaz() lindblad_noise.add_lindblad_noise(op, qu_ind, coeff=True) return lindblad_noise
def test_relaxation_noise(self): """ Test for the relaxation noise """ # only t1 a = destroy(2) dims = [2] * 3 relnoise = RelaxationNoise(t1=[1., 1., 1.], t2=None) systematic_noise = Pulse(None, None, label="system") pulses, systematic_noise = relnoise.get_noisy_dynamics( dims=dims, systematic_noise=systematic_noise) noisy_qu, c_ops = systematic_noise.get_noisy_qobjevo(dims=dims) assert_(len(c_ops) == 3) assert_allclose(c_ops[1].cte, tensor([qeye(2), a, qeye(2)])) # no relaxation dims = [2] * 2 relnoise = RelaxationNoise(t1=None, t2=None) systematic_noise = Pulse(None, None, label="system") pulses, systematic_noise = relnoise.get_noisy_dynamics( dims=dims, systematic_noise=systematic_noise) noisy_qu, c_ops = systematic_noise.get_noisy_qobjevo(dims=dims) assert_(len(c_ops) == 0) # only t2 relnoise = RelaxationNoise(t1=None, t2=[0.2, 0.7]) systematic_noise = Pulse(None, None, label="system") pulses, systematic_noise = relnoise.get_noisy_dynamics( dims=dims, systematic_noise=systematic_noise) noisy_qu, c_ops = systematic_noise.get_noisy_qobjevo(dims=dims) assert_(len(c_ops) == 2) # t1+t2 and systematic_noise = None relnoise = RelaxationNoise(t1=[1., 1.], t2=[0.5, 0.5]) pulses, systematic_noise = relnoise.get_noisy_dynamics(dims=dims) noisy_qu, c_ops = systematic_noise.get_noisy_qobjevo(dims=dims) assert_(len(c_ops) == 4)
def set_up_ops(self, N): """ Generate the Hamiltonians for the spinchain model and save them in the attribute `ctrls`. Parameters ---------- N: int The number of qubits in the system. """ self.pulse_dict = {} index = 0 # single qubit terms for m in range(N): self.pulses.append( Pulse(sigmax(), [m + 1], spline_kind=self.spline_kind)) self.pulse_dict["sx" + str(m)] = index index += 1 for m in range(N): self.pulses.append( Pulse(sigmaz(), [m + 1], spline_kind=self.spline_kind)) self.pulse_dict["sz" + str(m)] = index index += 1 # coupling terms a = tensor([destroy(self.num_levels)] + [identity(2) for n in range(N)]) for n in range(N): sm = tensor( [identity(self.num_levels)] + [destroy(2) if m == n else identity(2) for m in range(N)]) self.pulses.append( Pulse(a.dag() * sm + a * sm.dag(), list(range(N + 1)), spline_kind=self.spline_kind)) self.pulse_dict["g" + str(n)] = index index += 1
def testDrift(self): """ Test for the drift Hamiltonian """ processor = Processor(N=1) processor.add_drift(sigmax() / 2, 0) tlist = np.array([0., np.pi, 2 * np.pi, 3 * np.pi]) processor.add_pulse(Pulse(None, None, tlist, False)) ideal_qobjevo, _ = processor.get_qobjevo(noisy=True) assert_equal(ideal_qobjevo.cte, sigmax() / 2) init_state = basis(2) propagators = processor.run_analytically() analytical_result = init_state for unitary in propagators: analytical_result = unitary * analytical_result fid = fidelity(sigmax() * init_state, analytical_result) assert ((1 - fid) < 1.0e-6)
def test_random_noise(self): """ Test for the white noise """ tlist = np.array([1, 2, 3, 4, 5, 6]) coeff = np.array([1, 1, 1, 1, 1, 1]) dummy_qobjevo = QobjEvo(sigmaz(), tlist=tlist) mean = 0. std = 0.5 pulses = [ Pulse(sigmaz(), 0, tlist, coeff), Pulse(sigmax(), 0, tlist, coeff * 2), Pulse(sigmay(), 0, tlist, coeff * 3) ] # random noise with operators from proc_qobjevo gaussnoise = RandomNoise(dt=0.1, rand_gen=np.random.normal, loc=mean, scale=std) noisy_pulses, systematic_noise = \ gaussnoise.get_noisy_dynamics(pulses=pulses) assert_allclose(noisy_pulses[2].qobj, sigmay()) assert_allclose(noisy_pulses[1].coherent_noise[0].qobj, sigmax()) assert_allclose(len(noisy_pulses[0].coherent_noise[0].tlist), len(noisy_pulses[0].coherent_noise[0].coeff)) # random noise with dt and other random number generator pulses = [ Pulse(sigmaz(), 0, tlist, coeff), Pulse(sigmax(), 0, tlist, coeff * 2), Pulse(sigmay(), 0, tlist, coeff * 3) ] gaussnoise = RandomNoise(lam=0.1, dt=0.2, rand_gen=np.random.poisson) assert_(gaussnoise.rand_gen is np.random.poisson) noisy_pulses, systematic_noise = \ gaussnoise.get_noisy_dynamics(pulses=pulses) assert_allclose(noisy_pulses[0].coherent_noise[0].tlist, np.linspace(1, 6, int(5 / 0.2) + 1)) assert_allclose(noisy_pulses[1].coherent_noise[0].tlist, np.linspace(1, 6, int(5 / 0.2) + 1)) assert_allclose(noisy_pulses[2].coherent_noise[0].tlist, np.linspace(1, 6, int(5 / 0.2) + 1))
def get_noisy_dynamics(self, dims=None, pulses=None, systematic_noise=None): if systematic_noise is None: systematic_noise = Pulse(None, None, label="system") N = len(dims) # time-independent if (self.coeff is None) and (self.tlist is None): self.coeff = True for c_op in self.c_ops: if self.all_qubits: for targets in range(N): systematic_noise.add_lindblad_noise( c_op, targets, self.tlist, self.coeff) else: systematic_noise.add_lindblad_noise(c_op, self.targets, self.tlist, self.coeff) return pulses, systematic_noise
def TestCoherentNoise(): """ Test for pulse genration with coherent noise. """ coeff = np.array([0.1, 0.2, 0.3, 0.4]) tlist = np.array([0., 1., 2., 3.]) ham = sigmaz() pulse1 = Pulse(ham, 1, tlist, coeff) # Add coherent noise with the same tlist pulse1.add_coherent_noise(sigmay(), 0, tlist, coeff) assert_allclose( pulse1.get_ideal_qobjevo(2).ops[0].qobj, tensor(identity(2), sigmaz())) assert_(len(pulse1.coherent_noise) == 1) noise_qu, c_ops = pulse1.get_noisy_qobjevo(2) assert_allclose(c_ops, []) assert_allclose(noise_qu.tlist, np.array([0., 1., 2., 3.])) qobj_list = [ele.qobj for ele in noise_qu.ops] assert_(tensor(identity(2), sigmaz()) in qobj_list) assert_(tensor(sigmay(), identity(2)) in qobj_list) for ele in noise_qu.ops: assert_allclose(ele.coeff, coeff)
def get_noisy_dynamics(self, dims=None, pulses=None, systematic_noise=None): 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, " "len(t1)={}, len(t2)={}".format( len(self.t1), 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("t1={}, t2={} does not fulfill " "2*t1>t2".format(t1, t2)) T2_eff = 1. / (1. / t2 - 1. / 2. / 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
def TestPulseConstructor(): """ Test for creating empty Pulse, Pulse with constant coefficients etc. """ coeff = np.array([0.1, 0.2, 0.3, 0.4]) tlist = np.array([0., 1., 2., 3.]) ham = sigmaz() # Special ways of initializing pulse pulse2 = Pulse(sigmax(), 0, tlist, True) assert_allclose(pulse2.get_ideal_qobjevo(2).ops[0].qobj, tensor(sigmax(), identity(2))) pulse3 = Pulse(sigmay(), 0) assert_allclose(pulse3.get_ideal_qobjevo(2).cte.norm(), 0.) pulse4 = Pulse(None, None) # Dummy empty ham assert_allclose(pulse4.get_ideal_qobjevo(2).cte.norm(), 0.) tlist_noise = np.array([1., 2.5, 3.]) coeff_noise = np.array([0.5, 0.1, 0.5]) tlist_noise2 = np.array([0.5, 2, 3.]) coeff_noise2 = np.array([0.1, 0.2, 0.3]) # Pulse with different dims random_qobj = Qobj(np.random.random((3, 3))) pulse5 = Pulse(sigmaz(), 1, tlist, True) pulse5.add_coherent_noise(sigmay(), 1, tlist_noise, coeff_noise) pulse5.add_lindblad_noise( random_qobj, 0, tlist=tlist_noise2, coeff=coeff_noise2) qu, c_ops = pulse5.get_noisy_qobjevo(dims=[3, 2]) assert_allclose(qu.ops[0].qobj, tensor([identity(3), sigmaz()])) assert_allclose(qu.ops[1].qobj, tensor([identity(3), sigmay()])) assert_allclose(c_ops[0].ops[0].qobj, tensor([random_qobj, identity(2)]))
def get_noisy_dynamics(self, ctrl_pulses, dims=None): dummy = Pulse(None, None) dummy.add_coherent_noise(self.qobj, 0, coeff=True) return ctrl_pulses + [dummy]
def TestBasicPulse(): """ Test for basic pulse generation and attributes. """ coeff = np.array([0.1, 0.2, 0.3, 0.4]) tlist = np.array([0., 1., 2., 3.]) ham = sigmaz() # Basic tests pulse1 = Pulse(ham, 1, tlist, coeff) assert_allclose( pulse1.get_ideal_qobjevo(2).ops[0].qobj, tensor(identity(2), sigmaz())) pulse1.tlist = 2 * tlist assert_allclose(pulse1.tlist, 2 * tlist) pulse1.tlist = tlist pulse1.coeff = 2 * coeff assert_allclose(pulse1.coeff, 2 * coeff) pulse1.coeff = coeff pulse1.qobj = 2 * sigmay() assert_allclose(pulse1.qobj, 2 * sigmay()) pulse1.qobj = ham pulse1.targets = 3 assert_allclose(pulse1.targets, 3) pulse1.targets = 1 assert_allclose(pulse1.get_ideal_qobj(2), tensor(identity(2), sigmaz()))
def set_up_ops(self, N): super(CircularSpinChain, self).set_up_ops(N) operator = tensor([sigmax(), sigmax()]) + tensor([sigmay(), sigmay()]) self.pulses.append( Pulse(operator, [N-1, 0], spline_kind=self.spline_kind)) self.pulse_dict["g" + str(N-1)] = len(self.pulses) - 1
def TestNoisyPulse(): """ Test for lindblad noise and different tlist """ coeff = np.array([0.1, 0.2, 0.3, 0.4]) tlist = np.array([0., 1., 2., 3.]) ham = sigmaz() pulse1 = Pulse(ham, 1, tlist, coeff) # Add coherent noise and lindblad noise with different tlist pulse1.spline_kind = "step_func" tlist_noise = np.array([1., 2.5, 3.]) coeff_noise = np.array([0.5, 0.1, 0.5]) pulse1.add_coherent_noise(sigmay(), 0, tlist_noise, coeff_noise) tlist_noise2 = np.array([0.5, 2, 3.]) coeff_noise2 = np.array([0.1, 0.2, 0.3]) pulse1.add_lindblad_noise(sigmax(), 1, coeff=True) pulse1.add_lindblad_noise( sigmax(), 0, tlist=tlist_noise2, coeff=coeff_noise2) assert_allclose( pulse1.get_ideal_qobjevo(2).ops[0].qobj, tensor(identity(2), sigmaz())) noise_qu, c_ops = pulse1.get_noisy_qobjevo(2) assert_allclose(noise_qu.tlist, np.array([0., 0.5, 1., 2., 2.5, 3.])) for ele in noise_qu.ops: if ele.qobj == tensor(identity(2), sigmaz()): assert_allclose( ele.coeff, np.array([0.1, 0.1, 0.2, 0.3, 0.3, 0.4])) elif ele.qobj == tensor(sigmay(), identity(2)): assert_allclose( ele.coeff, np.array([0., 0., 0.5, 0.5, 0.1, 0.5])) for c_op in c_ops: if len(c_op.ops) == 0: assert_allclose(c_ops[0].cte, tensor(identity(2), sigmax())) else: assert_allclose( c_ops[1].ops[0].qobj, tensor(sigmax(), identity(2))) assert_allclose( c_ops[1].tlist, np.array([0., 0.5, 1., 2., 2.5, 3.])) assert_allclose( c_ops[1].ops[0].coeff, np.array([0., 0.1, 0.1, 0.2, 0.2, 0.3]))