def test_known_iscptp(self): """ Superoperator: iscp, istp and iscptp known cases. """ # Check that unitaries are CPTP. assert_(identity(2).iscptp) assert_(sigmax().iscptp) # The partial transpose map, whose Choi matrix is SWAP, is TP but not # CP. W = Qobj(swap(), type='super', superrep='choi') assert_(W.istp) assert_(not W.iscp) assert_(not W.iscptp) # Subnormalized maps (representing erasure channels, for instance) # can be CP but not TP. subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') assert_(subnorm_map.iscp) assert_(not subnorm_map.istp) assert_(not subnorm_map.iscptp) # Check that things which aren't even operators aren't identified as # CPTP. assert_(not (basis(2).iscptp))
def test_user_gate(self): """ User defined gate for QubitCircuit """ def customer_gate1(arg_values): mat = np.zeros((4, 4), dtype=np.complex) mat[0, 0] = mat[1, 1] = 1. mat[2:4, 2:4] = rx(arg_values) return Qobj(mat, dims=[[2, 2], [2, 2]]) def customer_gate2(): mat = np.array([[1., 0], [0., 1.j]]) return Qobj(mat, dims=[[2], [2]]) qc = QubitCircuit(3) qc.user_gates = {"CTRLRX": customer_gate1, "T1": customer_gate2} qc.add_gate("CTRLRX", targets=[1, 2], arg_value=np.pi/2) qc.add_gate("T1", targets=[1]) props = qc.propagators() result1 = tensor(identity(2), customer_gate1(np.pi/2)) assert_allclose(props[0], result1) result2 = tensor(identity(2), customer_gate2(), identity(2)) assert_allclose(props[1], result2)
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 gate_expand_1toN(U, N, target): """ Create a Qobj representing a one-qubit gate that act on a system with N qubits. Parameters ---------- U : Qobj The one-qubit gate N : integer The number of qubits in the target space. target : integer The index of the target qubit. Returns ------- gate : qobj Quantum object representation of N-qubit gate. """ if N < 1: raise ValueError("integer N must be larger or equal to 1") if target >= N: raise ValueError("target must be integer < integer N") return tensor([identity(2)] * (target) + [U] + [identity(2)] * (N - target - 1))
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 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 set_up_ops(self, N): """ Generate the Hamiltonians for the circuitqed model and save them in the attribute `ctrls`. Parameters ---------- N: int The number of qubits in the system. """ # single qubit terms 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)) # 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))
def set_up_ops(self, num_qubits): """ Generate the Hamiltonians for the spinchain model and save them in the attribute `ctrls`. Parameters ---------- num_qubits: int The number of qubits in the system. """ # single qubit terms for m in range(num_qubits): self.add_control(sigmax(), [m + 1], label="sx" + str(m)) for m in range(num_qubits): self.add_control(sigmaz(), [m + 1], label="sz" + str(m)) # coupling terms a = tensor([destroy(self.num_levels)] + [identity(2) for n in range(num_qubits)]) for n in range(num_qubits): sm = tensor([identity(self.num_levels)] + [ destroy(2) if m == n else identity(2) for m in range(num_qubits) ]) self.add_control(a.dag() * sm + a * sm.dag(), list(range(num_qubits + 1)), label="g" + str(n))
def set_up_ops(self, N): super(CircularSpinChain, self).set_up_ops(N) x = [identity(2)] * N x[0] = x[N - 1] = sigmax() y = [identity(2)] * N y[0] = y[N - 1] = sigmay() self.ctrls.append(tensor(x) + tensor(y))
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. """ # sx_ops self.ctrls += [ tensor([sigmax() if m == n else identity(2) for n in range(N)]) for m in range(N) ] # sz_ops self.ctrls += [ tensor([sigmaz() if m == n else identity(2) for n in range(N)]) for m in range(N) ] # sxsy_ops for n in range(N - 1): x = [identity(2)] * N x[n] = x[n + 1] = sigmax() y = [identity(2)] * N y[n] = y[n + 1] = sigmay() self.ctrls.append(tensor(x) + tensor(y))
def test_multi_qubits(self): """ Test for multi-qubits system. """ N = 3 H_d = tensor([sigmaz()] * 3) H_c = [] # test empty ctrls num_tslots = 30 evo_time = 10 test = OptPulseProcessor(N) test.add_drift(H_d, [0, 1, 2]) test.add_control(tensor([sigmax(), sigmax()]), cyclic_permutation=True) # test periodically adding ctrls sx = sigmax() iden = identity(2) # print(test.ctrls) # print(Qobj(tensor([sx, iden, sx]))) assert_(Qobj(tensor([sx, iden, sx])) in test.ctrls) assert_(Qobj(tensor([iden, sx, sx])) in test.ctrls) assert_(Qobj(tensor([sx, sx, iden])) in test.ctrls) test.add_control(sigmax(), cyclic_permutation=True) test.add_control(sigmay(), cyclic_permutation=True) # test pulse genration for cnot gate, with kwargs qc = [tensor([identity(2), cnot()])] test.load_circuit(qc, num_tslots=num_tslots, evo_time=evo_time, min_fid_err=1.0e-6) rho0 = qubit_states(3, [1, 1, 1]) rho1 = qubit_states(3, [1, 1, 0]) result = test.run_state(rho0, options=Options(store_states=True)) assert_(fidelity(result.states[-1], rho1) > 1 - 1.0e-6)
def __init__(self, N, correct_global_phase=True, sx=None, sz=None, sxsy=None): """ Parameters ---------- sx: Integer/List The delta for each of the qubits in the system. sz: Integer/List The epsilon for each of the qubits in the system. sxsy: Integer/List The interaction strength for each of the qubit pair in the system. """ super(SpinChain, self).__init__(N, correct_global_phase) self.sx_ops = [ tensor([sigmax() if m == n else identity(2) for n in range(N)]) for m in range(N) ] self.sz_ops = [ tensor([sigmaz() if m == n else identity(2) for n in range(N)]) for m in range(N) ] self.sxsy_ops = [] for n in range(N - 1): x = [identity(2)] * N x[n] = x[n + 1] = sigmax() y = [identity(2)] * N y[n] = y[n + 1] = sigmay() self.sxsy_ops.append(tensor(x) + tensor(y)) if sx is None: self.sx_coeff = [0.25 * 2 * np.pi] * N elif not isinstance(sx, list): self.sx_coeff = [sx * 2 * np.pi] * N else: self.sx_coeff = sx if sz is None: self.sz_coeff = [1.0 * 2 * np.pi] * N elif not isinstance(sz, list): self.sz_coeff = [sz * 2 * np.pi] * N else: self.sz_coeff = sz if sxsy is None: self.sxsy_coeff = [0.1 * 2 * np.pi] * (N - 1) elif not isinstance(sxsy, list): self.sxsy_coeff = [sxsy * 2 * np.pi] * (N - 1) else: self.sxsy_coeff = sxsy
def test_expand_oper(self): """ gate : expand qubits operator to a N qubits system. """ # random single qubit gate test, integer as target r = rand_unitary(2) assert (expand_oper(r, 3, 0) == tensor([r, identity(2), identity(2)])) assert (expand_oper(r, 3, 1) == tensor([identity(2), r, identity(2)])) assert (expand_oper(r, 3, 2) == tensor([identity(2), identity(2), r])) # random 2qubits gate test, list as target r2 = rand_unitary(4) r2.dims = [[2, 2], [2, 2]] assert (expand_oper(r2, 3, [2, 1]) == tensor( [identity(2), r2.permute([1, 0])])) assert (expand_oper(r2, 3, [0, 1]) == tensor([r2, identity(2)])) assert (expand_oper(r2, 3, [0, 2]) == tensor([r2, identity(2)]).permute([0, 2, 1])) # cnot expantion, qubit 2 control qubit 0 assert (expand_oper(cnot(), 3, [2, 0]) == Qobj([ [1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 0., 1.], [0., 0., 0., 0., 1., 0., 0., 0.], [0., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0., 1., 0.], [0., 0., 0., 1., 0., 0., 0., 0.] ], dims=[[2, 2, 2], [2, 2, 2]]))
def test_qrot(self): """ gate: test for the qubit rotation gate """ assert_allclose(qrot(0, 0), identity(2)) assert_allclose(qrot(np.pi, np.pi / 2), Qobj([[0, -1], [1, 0]]), atol=1e-15) assert_allclose(qrot(np.pi / 4., np.pi / 3., N=2, target=1), tensor([identity(2), qrot(np.pi / 4., np.pi / 3.)]))
def test_tensor_contract_ident(): qobj = identity([2, 3, 4]) ans = 3 * identity([2, 4]) assert_(ans == tensor_contract(qobj, (1, 4))) # Now try for superoperators. # For now, we just ensure the dims are correct. sqobj = to_super(qobj) correct_dims = [[[2, 4], [2, 4]], [[2, 4], [2, 4]]] assert_equal(correct_dims, tensor_contract(sqobj, (1, 4), (7, 10)).dims)
def __init__(self, N, correct_global_phase=True, sx=None, sz=None, sxsy=None): """ Parameters ---------- sx: Integer/List The delta for each of the qubits in the system. sz: Integer/List The epsilon for each of the qubits in the system. sxsy: Integer/List The interaction strength for each of the qubit pair in the system. """ super(SpinChain, self).__init__(N, correct_global_phase) self.sx_ops = [tensor([sigmax() if m == n else identity(2) for n in range(N)]) for m in range(N)] self.sz_ops = [tensor([sigmaz() if m == n else identity(2) for n in range(N)]) for m in range(N)] self.sxsy_ops = [] for n in range(N - 1): x = [identity(2)] * N x[n] = x[n + 1] = sigmax() y = [identity(2)] * N y[n] = y[n + 1] = sigmay() self.sxsy_ops.append(tensor(x) + tensor(y)) if sx is None: self.sx_coeff = [0.25 * 2 * np.pi] * N elif not isinstance(sx, list): self.sx_coeff = [sx * 2 * np.pi] * N else: self.sx_coeff = sx if sz is None: self.sz_coeff = [1.0 * 2 * np.pi] * N elif not isinstance(sz, list): self.sz_coeff = [sz * 2 * np.pi] * N else: self.sz_coeff = sz if sxsy is None: self.sxsy_coeff = [0.1 * 2 * np.pi] * (N - 1) elif not isinstance(sxsy, list): self.sxsy_coeff = [sxsy * 2 * np.pi] * (N - 1) else: self.sxsy_coeff = sxsy
def f(ab, w, ulim, Nt, tmax): # Create time series vector time = np.linspace(0, tmax, Nt) # U = identity(2*2*Nho) # create starting unitary # could this be wrong ? U = tensor(identity(2), identity(2), identity(Nho)) # Initialize g g = 0.0 # half the length of ab vector # used for decomposing it into a and b # possible problems for odd length vectors # no because created by concatenating two vectors of same length # in whatever program that calls it Lab = int(ab.size/2) # at a paticular time t # making g # making H,Ui # and hence U at that time # multiplying it to the product of unitatries at previous times for t in time: for ir in range(Lab): # normalizing the A_k and B_k norm = np.sqrt(ab[ir]**2 + ab[ir+Lab]**2) # numerator built by decomposition of ab just like above numer = ab[ir]*np.sin(w[ir]*t) + ab[ir+Lab]*np.cos(w[ir]*t) # multiplying by ulim and dividing by norm # construction of g_k # adding it to rest of g g += (ulim*numer)/norm # constructing the total hamiltonian H = H0 + g*Hi # constructing U at the time t Ui = (-1j*H*t).expm() # multiplying it with the othe unitaries before U *= Ui # f = hilbert_dist(U.dag(),U_target) # fi = np.float64(hilbert_dist(U.dag(),U_target)) # fif = hilbert_dist(U.dag(),U_target) # fis = str(fif) # fi = float(fis) # stuff inside the trace with normalization uu = ((U.dag())*U_target)/(2*2*Nho) # taking the trace f = uu.tr() # absolute value of the trace fi = abs(f) return fi
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)] + [identity(2) for n in range(N)]) self.ctrls.append(self.a.dag() * self.a) self.ctrls += [ tensor([identity(self.num_levels)] + [sigmax() if m == n else identity(2) for n in range(N)]) for m in range(N) ] self.ctrls += [ tensor([identity(self.num_levels)] + [sigmaz() if m == n else identity(2) for n in range(N)]) for m in range(N) ] # interaction terms 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.ctrls.append(self.a.dag() * sm + self.a * sm.dag()) self.psi_proj = tensor([basis(self.num_levels, 0)] + [identity(2) for n in range(N)])
def get_qobj(self, dims): """ Get the `Qobj` representation of the element. If `qobj` is None, a zero :class:`qutip.Qobj` with the corresponding dimension is returned. Parameters ---------- 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. Returns ------- qobj : :class:`qutip.Qobj` The operator of this element. """ if isinstance(dims, (int, np.integer)): dims = [2] * dims if self.qobj is None: qobj = identity(dims[0]) * 0. targets = 0 else: qobj = self.qobj targets = self.targets return expand_operator(qobj, len(dims), targets, dims)
def test_choi_tr(self): """ Superoperator: Checks that the trace of matrices returned by to_choi matches that asserted by the docstring for that function. """ for dims in range(2, 5): assert_(abs(to_choi(identity(dims)).tr() - dims) <= tol)
def controlled_h(N=2, control=0, target=1, control_value=1): """ Create an N-qubit controlled gate from hadamard gate with the given control and target qubits. Parameters ---------- N : integer The number of qubits in the target space. control : integer The index of the first control qubit. target : integer The index of the target qubit. control_value : integer (1) The state of the control qubit that activates the gate U. Returns ------- result : qobj Quantum object representing the controlled-s gate. """ U = 1 / np.sqrt(2.0) * Qobj([[1, 1], [1, -1]]) if [N, control, target] == [2, 0, 1]: return (tensor(fock_dm(2, control_value), U) + tensor(fock_dm(2, 1 - control_value), identity(2))) else: U2 = controlled_gate(U, control_value=control_value) return gate_expand_2toN(U2, N=N, control=control, target=target)
def eliminate_auxillary_modes(self, U): """ Eliminate the auxillary modes like the cavity modes in cqed. """ psi_proj = tensor([basis(self.num_levels, 0)] + [identity(2) for n in range(self.N)]) return psi_proj.dag() * U * psi_proj
def controlled_gate(U, N=2, control=0, target=1, control_value=1): """ Create an N-qubit controlled gate from a single-qubit gate U with the given control and target qubits. Parameters ---------- U : Qobj Arbitrary single-qubit gate. N : integer The number of qubits in the target space. control : integer The index of the first control qubit. target : integer The index of the target qubit. control_value : integer (1) The state of the control qubit that activates the gate U. Returns ------- result : qobj Quantum object representing the controlled-U gate. """ if [N, control, target] == [2, 0, 1]: return (tensor(fock_dm(2, control_value), U) + tensor(fock_dm(2, 1 - control_value), identity(2))) else: U2 = controlled_gate(U, control_value=control_value) return gate_expand_2toN(U2, N=N, control=control, target=target)
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 _dummy_qobjevo(dims, **kwargs): """ Create a dummy :class":`qutip.QobjEvo` with a constant zero Hamiltonian. This is used since empty QobjEvo is not yet supported. """ dummy = QobjEvo(tensor([identity(d) for d in dims]) * 0., **kwargs) return dummy
def test_average_gate_fidelity(self): """ Metrics: Checks that average gate fidelities are sensible for random maps, and are equal to 1 for identity maps. """ for dims in range(2, 5): assert_(abs(average_gate_fidelity(identity(dims)) - 1) <= 1e-12) assert_(0 <= average_gate_fidelity(self.rand_super()) <= 1)
def test_average_gate_fidelity(): """ Metrics: Check avg gate fidelities for random maps (equal to 1 for id maps). """ for dims in range(2, 5): assert_(abs(average_gate_fidelity(identity(dims)) - 1) <= 1e-12) assert_(0 <= average_gate_fidelity(rand_super()) <= 1)
def controlled_mat3(arg_value): """ A qubit control an operator acting on a 3 level system """ control_value = arg_value dim = mat3.dims[0][0] return (tensor(fock_dm(2, control_value), mat3) + tensor(fock_dm(2, 1 - control_value), identity(dim)))
def gate_expand_2toN(U, N, control=None, target=None, targets=None): """ Create a Qobj representing a two-qubit gate that act on a system with N qubits. Parameters ---------- U : Qobj The two-qubit gate N : integer The number of qubits in the target space. control : integer The index of the control qubit. target : integer The index of the target qubit. targets : list List of target qubits. Returns ------- gate : qobj Quantum object representation of N-qubit gate. """ if targets is not None: control, target = targets if control is None or target is None: raise ValueError("Specify value of control and target") if N < 2: raise ValueError("integer N must be larger or equal to 2") if control >= N or target >= N: raise ValueError("control and not target must be integer < integer N") if control == target: raise ValueError("target and not control cannot be equal") p = list(range(N)) if target == 0 and control == 1: p[control], p[target] = p[target], p[control] elif target == 0: p[1], p[target] = p[target], p[1] p[1], p[control] = p[control], p[1] else: p[1], p[target] = p[target], p[1] p[0], p[control] = p[control], p[0] return tensor([U] + [identity(2)] * (N - 2)).permute(p)
def testExpandGate3toN_permutation(self): """ gates: expand 3 to 3 with permuTation (using toffoli) """ for _p in itertools.permutations([0, 1, 2]): controls, target = [_p[0], _p[1]], _p[2] controls = [1, 2] target = 0 p = [1, 2, 3] p[controls[0]] = 0 p[controls[1]] = 1 p[target] = 2 U = toffoli(N=3, controls=controls, target=target) ops = [basis(2, 0).dag(), basis(2, 0).dag(), identity(2)] P = tensor(ops[p[0]], ops[p[1]], ops[p[2]]) assert_(P * U * P.dag() == identity(2)) ops = [basis(2, 1).dag(), basis(2, 0).dag(), identity(2)] P = tensor(ops[p[0]], ops[p[1]], ops[p[2]]) assert_(P * U * P.dag() == identity(2)) ops = [basis(2, 0).dag(), basis(2, 1).dag(), identity(2)] P = tensor(ops[p[0]], ops[p[1]], ops[p[2]]) assert_(P * U * P.dag() == identity(2)) ops = [basis(2, 1).dag(), basis(2, 1).dag(), identity(2)] P = tensor(ops[p[0]], ops[p[1]], ops[p[2]]) assert_(P * U * P.dag() == sigmax())
def TestDrift(): """ Test for Drift """ drift = Drift() assert_allclose(drift.get_ideal_qobjevo(2).cte.norm(), 0) drift.add_drift(sigmaz(), targets=1) assert_allclose( drift.get_ideal_qobjevo(dims=[3, 2]).cte, tensor(identity(3), sigmaz()))
def case_is_clifford(self, U): paulis = (identity(2), sigmax(), sigmay(), sigmaz()) for P in paulis: U_P = U * P * U.dag() out = (np.any( np.array([self._prop_identity(U_P * Q) for Q in paulis]))) return out
def __init__(self, N, correct_global_phase=True, sx=None, sz=None, sxsy=None): super(CircularSpinChain, self).__init__(N, correct_global_phase, sx, sz, sxsy) x = [identity(2)] * N x[0] = x[N - 1] = sigmax() y = [identity(2)] * N y[0] = y[N - 1] = sigmay() self.sxsy_ops.append(tensor(x) + tensor(y)) if sxsy is None: self.sxsy_coeff = [0.1 * 2 * np.pi] * N elif not isinstance(sxsy, list): self.sxsy_coeff = [sxsy * 2 * np.pi] * N else: self.sxsy_coeff = sxsy
def case_is_clifford(self, U): paulis = (identity(2), sigmax(), sigmay(), sigmaz()) for P in paulis: U_P = U * P * U.dag() assert_(any( self._prop_identity(U_P * Q) for Q in paulis ))
def case_is_clifford(self, U): paulis = (identity(2), sigmax(), sigmay(), sigmaz()) for P in paulis: U_P = U * P * U.dag() out = (np.any( np.array([self._prop_identity(U_P * Q) for Q in paulis]) )) return out
def cphase(theta, N=2, control=0, target=1): """ Returns quantum object representing the phase shift gate. Parameters ---------- theta : float Phase rotation angle. N : integer The number of qubits in the target space. control : integer The index of the control qubit. target : integer The index of the target qubit. Returns ------- U : qobj Quantum object representation of controlled phase gate. """ if N < 1 or target < 0 or control < 0: raise ValueError("Minimum value: N=1, control=0 and target=0") if control >= N or target >= N: raise ValueError("control and target need to be smaller than N") U_list1 = [identity(2)] * N U_list2 = [identity(2)] * N U_list1[control] = fock_dm(2, 1) U_list1[target] = phasegate(theta) U_list2[control] = fock_dm(2, 0) U = tensor(U_list1) + tensor(U_list2) return U
CPTP, expand to arbitrary dimensional systems, etc. """ return Qobj(dims=[[[2], [2]], [[2], [2]]], inpt=array([[1. - pe / 2., 0., 0., 1. - pe], [0., pe / 2., 0., 0.], [0., 0., pe / 2., 0.], [1. - pe, 0., 0., 1. - pe / 2.]]), superrep='choi') # CHANGE OF BASIS FUNCTIONS --------------------------------------------------- # These functions find change of basis matrices, and are useful in converting # between (for instance) Choi and chi matrices. At some point, these should # probably be moved out to another module. _SINGLE_QUBIT_PAULI_BASIS = (identity(2), sigmax(), sigmay(), sigmaz()) def _pauli_basis(nq=1): # NOTE: This is slow as can be. # TODO: Make this sparse. CSR format was causing problems for the [idx, :] # slicing below. B = zeros((4 ** nq, 4 ** nq), dtype=complex) dims = [[[2] * nq] * 2] * 2 for idx, op in enumerate(starmap(tensor, product(_SINGLE_QUBIT_PAULI_BASIS, repeat=nq))): B[:, idx] = operator_to_vector(op).dag().data.todense() return Qobj(B, dims=dims)
def test_known_iscptp(self): """ Superoperator: ishp, iscp, istp and iscptp known cases. """ def case(qobj, shouldhp, shouldcp, shouldtp): hp = qobj.ishp cp = qobj.iscp tp = qobj.istp cptp = qobj.iscptp shouldcptp = shouldcp and shouldtp if ( hp == shouldhp and cp == shouldcp and tp == shouldtp and cptp == shouldcptp ): return fails = [] if hp != shouldhp: fails.append(("ishp", shouldhp, hp)) if tp != shouldtp: fails.append(("istp", shouldtp, tp)) if cp != shouldcp: fails.append(("iscp", shouldcp, cp)) if cptp != shouldcptp: fails.append(("iscptp", shouldcptp, cptp)) raise AssertionError("Expected {}.".format(" and ".join([ "{} == {} (got {})".format(fail, expected, got) for fail, expected, got in fails ]))) # Conjugation by a creation operator should # have be CP (and hence HP), but not TP. a = create(2).dag() S = sprepost(a, a.dag()) yield case, S, True, True, False # A single off-diagonal element should not be CP, # nor even HP. S = sprepost(a, a) yield case, S, False, False, False # Check that unitaries are CPTP and HP. yield case, identity(2), True, True, True yield case, sigmax(), True, True, True # The partial transpose map, whose Choi matrix is SWAP, is TP # and HP but not CP (one negative eigenvalue). W = Qobj(swap(), type='super', superrep='choi') yield case, W, True, False, True # Subnormalized maps (representing erasure channels, for instance) # can be CP but not TP. subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') yield case, subnorm_map, True, True, False # Check that things which aren't even operators aren't identified as # CPTP. yield case, basis(2), False, False, False
def gate_expand_3toN(U, N, controls=[0, 1], target=2): """ Create a Qobj representing a three-qubit gate that act on a system with N qubits. Parameters ---------- U : Qobj The three-qubit gate N : integer The number of qubits in the target space. controls : list The list of the control qubits. target : integer The index of the target qubit. Returns ------- gate : qobj Quantum object representation of N-qubit gate. """ if N < 3: raise ValueError("integer N must be larger or equal to 3") if controls[0] >= N or controls[1] >= N or target >= N: raise ValueError( "control and not target is None must be integer < integer N") if (controls[0] == target or controls[1] == target or controls[0] == controls[1]): raise ValueError( "controls[0], controls[1], and target cannot be equal") p = list(range(N)) p1 = list(range(N)) p2 = list(range(N)) if controls[0] <= 2 and controls[1] <= 2 and target <= 2: p[controls[0]] = 0 p[controls[1]] = 1 p[target] = 2 # # N > 3 cases # elif controls[0] == 0 and controls[1] == 1: p[2], p[target] = p[target], p[2] elif controls[0] == 0 and target == 2: p[1], p[controls[1]] = p[controls[1]], p[1] elif controls[1] == 1 and target == 2: p[0], p[controls[0]] = p[controls[0]], p[0] elif controls[0] == 1 and controls[1] == 0: p[controls[1]], p[controls[0]] = p[controls[0]], p[controls[1]] p2[2], p2[target] = p2[target], p2[2] p = [p2[p[k]] for k in range(N)] elif controls[0] == 2 and target == 0: p[target], p[controls[0]] = p[controls[0]], p[target] p1[1], p1[controls[1]] = p1[controls[1]], p1[1] p = [p1[p[k]] for k in range(N)] elif controls[1] == 2 and target == 1: p[target], p[controls[1]] = p[controls[1]], p[target] p1[0], p1[controls[0]] = p1[controls[0]], p1[0] p = [p1[p[k]] for k in range(N)] elif controls[0] == 1 and controls[1] == 2: # controls[0] -> controls[1] -> target -> outside p[0], p[1] = p[1], p[0] p[0], p[2] = p[2], p[0] p[0], p[target] = p[target], p[0] elif controls[0] == 2 and target == 1: # controls[0] -> target -> controls[1] -> outside p[0], p[2] = p[2], p[0] p[0], p[1] = p[1], p[0] p[0], p[controls[1]] = p[controls[1]], p[0] elif controls[1] == 0 and controls[0] == 2: # controls[1] -> controls[0] -> target -> outside p[1], p[0] = p[0], p[1] p[1], p[2] = p[2], p[1] p[1], p[target] = p[target], p[1] elif controls[1] == 2 and target == 0: # controls[1] -> target -> controls[0] -> outside p[1], p[2] = p[2], p[1] p[1], p[0] = p[0], p[1] p[1], p[controls[0]] = p[controls[0]], p[1] elif target == 1 and controls[1] == 0: # target -> controls[1] -> controls[0] -> outside p[2], p[1] = p[1], p[2] p[2], p[0] = p[0], p[2] p[2], p[controls[0]] = p[controls[0]], p[2] elif target == 0 and controls[0] == 1: # target -> controls[0] -> controls[1] -> outside p[2], p[0] = p[0], p[2] p[2], p[1] = p[1], p[2] p[2], p[controls[1]] = p[controls[1]], p[2] elif controls[0] == 0 and controls[1] == 2: # controls[0] -> self, controls[1] -> target -> outside p[1], p[2] = p[2], p[1] p[1], p[target] = p[target], p[1] elif controls[1] == 1 and controls[0] == 2: # controls[1] -> self, controls[0] -> target -> outside p[0], p[2] = p[2], p[0] p[0], p[target] = p[target], p[0] elif target == 2 and controls[0] == 1: # target -> self, controls[0] -> controls[1] -> outside p[0], p[1] = p[1], p[0] p[0], p[controls[1]] = p[controls[1]], p[0] # # N > 4 cases # elif controls[0] == 1 and controls[1] > 2 and target > 2: # controls[0] -> controls[1] -> outside, target -> outside p[0], p[1] = p[1], p[0] p[0], p[controls[1]] = p[controls[1]], p[0] p[2], p[target] = p[target], p[2] elif controls[0] == 2 and controls[1] > 2 and target > 2: # controls[0] -> target -> outside, controls[1] -> outside p[0], p[2] = p[2], p[0] p[0], p[target] = p[target], p[0] p[1], p[controls[1]] = p[controls[1]], p[1] elif controls[1] == 2 and controls[0] > 2 and target > 2: # controls[1] -> target -> outside, controls[0] -> outside p[1], p[2] = p[2], p[1] p[1], p[target] = p[target], p[1] p[0], p[controls[0]] = p[controls[0]], p[0] else: p[0], p[controls[0]] = p[controls[0]], p[0] p1[1], p1[controls[1]] = p1[controls[1]], p1[1] p2[2], p2[target] = p2[target], p2[2] p = [p[p1[p2[k]]] for k in range(N)] return tensor([U] + [identity(2)] * (N - 3)).permute(p)
def test_choi_tr(self): """ Superoperator: Trace returned by to_choi matches docstring. """ for dims in range(2, 5): assert_(abs(to_choi(identity(dims)).tr() - dims) <= tol)