def testExpandGate2toNSwap(self): """ gates: expand 2 to N (using swap) """ a, b = np.random.rand(), np.random.rand() k1 = (a * basis(2, 0) + b * basis(2, 1)).unit() c, d = np.random.rand(), np.random.rand() k2 = (c * basis(2, 0) + d * basis(2, 1)).unit() N = 6 kets = [rand_ket(2) for k in range(N)] for m in range(N): for n in set(range(N)) - {m}: psi_in = tensor([k1 if k == m else k2 if k == n else kets[k] for k in range(N)]) psi_out = tensor([k2 if k == m else k1 if k == n else kets[k] for k in range(N)]) targets = [m, n] G = swap(N, targets) psi_out = G * psi_in assert_((psi_out - G * psi_in).norm() < 1e-12)
def test_QobjPermute(): "Qobj permute" A = basis(5, 0) B = basis(5, 4) C = basis(5, 2) psi = tensor(A, B, C) psi2 = psi.permute([2, 0, 1]) assert_(psi2 == tensor(C, A, B)) A = fock_dm(5, 0) B = fock_dm(5, 4) C = fock_dm(5, 2) rho = tensor(A, B, C) rho2 = rho.permute([2, 0, 1]) assert_(rho2 == tensor(C, A, B)) for ii in range(3): A = rand_ket(5) B = rand_ket(5) C = rand_ket(5) psi = tensor(A, B, C) psi2 = psi.permute([1, 0, 2]) assert_(psi2 == tensor(B, A, C)) for ii in range(3): A = rand_dm(5) B = rand_dm(5) C = rand_dm(5) rho = tensor(A, B, C) rho2 = rho.permute([1, 0, 2]) assert_(rho2 == tensor(B, A, C))
def choi_to_stinespring(q_oper, thresh=1e-10): # TODO: document! kU, kV = _generalized_kraus(q_oper, thresh=thresh) assert(len(kU) == len(kV)) dK = len(kU) dL = kU[0].shape[0] dR = kV[0].shape[1] # Also remember the dims breakout. out_dims, in_dims = q_oper.dims out_left, out_right = out_dims in_left, in_right = in_dims A = Qobj(zeros((dK * dL, dL)), dims=[out_left + [dK], out_right + [1]]) B = Qobj(zeros((dK * dR, dR)), dims=[in_left + [dK], in_right + [1]]) for idx_kraus, (KL, KR) in enumerate(zip(kU, kV)): A += tensor(KL, basis(dK, idx_kraus)) B += tensor(KR, basis(dK, idx_kraus)) # There is no input (right) Kraus index, so strip that off. del A.dims[1][-1] del B.dims[1][-1] return A, B
def phasegate(theta): """ Returns quantum object representing the phase shift gate. Parameters ---------- theta : float Phase rotation angle. Returns ------- phase_gate : qobj Quantum object representation of phase shift gate. Examples -------- >>> phasegate(pi/4) Quantum object: dims = [[2], [2]], \ shape = [2, 2], type = oper, isHerm = False Qobj data = [[ 1.00000000+0.j 0.00000000+0.j ] [ 0.00000000+0.j 0.70710678+0.70710678j]] """ u = basis(2) d = basis(2,1) Q = u * u.dag() + (exp(1.0j * theta) * d * d.dag()) return Qobj(Q)
def testExpandGate1toN(self): """ gates: expand 1 to N """ N = 7 for g in [rx, ry, rz, phasegate]: theta = np.random.rand() * 2 * 3.1415 a, b = np.random.rand(), np.random.rand() psi1 = (a * basis(2, 0) + b * basis(2, 1)).unit() psi2 = g(theta) * psi1 psi_rand_list = [rand_ket(2) for k in range(N)] for m in range(N): psi_in = tensor([psi1 if k == m else psi_rand_list[k] for k in range(N)]) psi_out = tensor([psi2 if k == m else psi_rand_list[k] for k in range(N)]) G = g(theta, N, m) psi_res = G * psi_in assert_((psi_out - psi_res).norm() < 1e-12)
def qubit_states(N=1, states=[0]): """ Function to define initial state of the qubits. Parameters ---------- N : Integer Number of qubits in the register. states : List Initial state of each qubit. Returns ---------- qstates : Qobj List of qubits. """ state_list = [] for i in range(N): if N > len(states) and i >= len(states): state_list.append(0) else: state_list.append(states[i]) return tensor([alpha * basis(2, 1) + sqrt(1 - alpha**2) * basis(2, 0) for alpha in state_list])
def snot(N=None, target=None): """Quantum object representing the SNOT (2-qubit Hadamard) gate. Returns ------- snot_gate : qobj Quantum object representation of SNOT gate. Examples -------- >>> snot() Quantum object: dims = [[2], [2]], \ shape = [2, 2], type = oper, isHerm = True Qobj data = [[ 0.70710678+0.j 0.70710678+0.j] [ 0.70710678+0.j -0.70710678+0.j]] """ if not N is None and not target is None: return gate_expand_1toN(snot(), N, target) else: u = basis(2, 0) d = basis(2, 1) Q = 1.0 / sqrt(2.0) * (sigmax() + sigmaz()) return Q
def test_CheckMulType(): "Qobj multiplication type" # ket-bra and bra-ket multiplication psi = basis(5) dm = psi * psi.dag() assert_(dm.isoper) assert_(dm.isherm) nrm = psi.dag() * psi assert_equal(np.prod(nrm.shape), 1) assert_((abs(nrm) == 1)[0, 0]) # operator-operator multiplication H1 = rand_herm(3) H2 = rand_herm(3) out = H1 * H2 assert_(out.isoper) out = H1 * H1 assert_(out.isoper) assert_(out.isherm) out = H2 * H2 assert_(out.isoper) assert_(out.isherm) U = rand_unitary(5) out = U.dag() * U assert_(out.isoper) assert_(out.isherm) N = num(5) out = N * N assert_(out.isoper) assert_(out.isherm) # operator-ket and bra-operator multiplication op = sigmax() ket1 = basis(2) ket2 = op * ket1 assert_(ket2.isket) bra1 = basis(2).dag() bra2 = bra1 * op assert_(bra2.isbra) assert_(bra2.dag() == ket2) # superoperator-operket and operbra-superoperator multiplication sop = to_super(sigmax()) opket1 = operator_to_vector(fock_dm(2)) opket2 = sop * opket1 assert(opket2.isoperket) opbra1 = operator_to_vector(fock_dm(2)).dag() opbra2 = opbra1 * sop assert(opbra2.isoperbra) assert_(opbra2.dag() == opket2)
def test_unit(): """ Test Qobj: unit """ psi = 10*np.random.randn()*basis(2,0)-10*np.random.randn()*1j*basis(2,1) psi2 = psi.unit() psi.unit(inplace=True) assert_(psi == psi2) assert_almost_equal(np.linalg.norm(psi.full()), 1.0)
def test_QobjPermute(): "Qobj permute" A = basis(3, 0) B = basis(5, 4) C = basis(4, 2) psi = tensor(A, B, C) psi2 = psi.permute([2, 0, 1]) assert_(psi2 == tensor(C, A, B)) psi_bra = psi.dag() psi2_bra = psi_bra.permute([2, 0, 1]) assert_(psi2_bra == tensor(C, A, B).dag()) A = fock_dm(3, 0) B = fock_dm(5, 4) C = fock_dm(4, 2) rho = tensor(A, B, C) rho2 = rho.permute([2, 0, 1]) assert_(rho2 == tensor(C, A, B)) for ii in range(3): A = rand_ket(3) B = rand_ket(4) C = rand_ket(5) psi = tensor(A, B, C) psi2 = psi.permute([1, 0, 2]) assert_(psi2 == tensor(B, A, C)) psi_bra = psi.dag() psi2_bra = psi_bra.permute([1, 0, 2]) assert_(psi2_bra == tensor(B, A, C).dag()) for ii in range(3): A = rand_dm(3) B = rand_dm(4) C = rand_dm(5) rho = tensor(A, B, C) rho2 = rho.permute([1, 0, 2]) assert_(rho2 == tensor(B, A, C)) rho_vec = operator_to_vector(rho) rho2_vec = rho_vec.permute([[1, 0, 2],[4,3,5]]) assert_(rho2_vec == operator_to_vector(tensor(B, A, C))) rho_vec_bra = operator_to_vector(rho).dag() rho2_vec_bra = rho_vec_bra.permute([[1, 0, 2],[4,3,5]]) assert_(rho2_vec_bra == operator_to_vector(tensor(B, A, C)).dag()) for ii in range(3): super_dims = [3, 5, 4] U = rand_unitary(np.prod(super_dims), density=0.02, dims=[super_dims, super_dims]) Unew = U.permute([2,1,0]) S_tens = to_super(U) S_tens_new = to_super(Unew) assert_(S_tens_new == S_tens.permute([[2,1,0],[5,4,3]]))
def bell_state10(): """ Returns the B10 Bell state: |B10>=1/sqrt(2)*[|0>|1>+|1>|0>] Returns ------- B10 : qobj B10 Bell state """ B=tensor(basis(2),basis(2,1))+tensor(basis(2,1),basis(2)) return B.unit()
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 bell_state11(): """ Returns the B11 Bell state: |B11>=1/sqrt(2)*[|0>|1>-|1>|0>] Returns ------- B11 : qobj B11 Bell state """ B=tensor(basis(2),basis(2,1))-tensor(basis(2,1),basis(2)) return B.unit()
def cnot(): """ Quantum object representing the CNOT gate. Returns ------- cnot_gate : qobj Quantum object representation of CNOT gate Examples -------- >>> cnot() Quantum object: dims = [[2, 2], [2, 2]], \ shape = [4, 4], type = oper, isHerm = True Qobj data = [[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 0.+0.j 1.+0.j] [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j]] """ uu = tensor(basis(2),basis(2)) ud = tensor(basis(2),basis(2,1)) du = tensor(basis(2,1),basis(2)) dd = tensor(basis(2,1),basis(2,1)) Q = uu * uu.dag() + ud * ud.dag() + dd * du.dag() + du * dd.dag() return Qobj(Q)
def cnot(N=None, control=None, target=None): """ Quantum object representing the CNOT gate. Returns ------- cnot_gate : qobj Quantum object representation of CNOT gate Examples -------- >>> cnot() Quantum object: dims = [[2, 2], [2, 2]], \ shape = [4, 4], type = oper, isHerm = True Qobj data = [[ 1.+0.j 0.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j] [ 0.+0.j 0.+0.j 0.+0.j 1.+0.j] [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j]] """ if not N is None and not control is None and not target is None: return gate_expand_2toN(cnot(), N, control, target) else: uu = tensor(basis(2), basis(2)) ud = tensor(basis(2), basis(2, 1)) du = tensor(basis(2, 1), basis(2)) dd = tensor(basis(2, 1), basis(2, 1)) Q = uu * uu.dag() + ud * ud.dag() + dd * du.dag() + du * dd.dag() return Qobj(Q)
def testQubitStates(self): """ Tests the qubit_states function. """ psi0_a = basis(2, 0) psi0_b = qubit_states() assert_(psi0_a == psi0_b) psi1_a = basis(2, 1) psi1_b = qubit_states(states=[1]) assert_(psi1_a == psi1_b) psi01_a = tensor(psi0_a, psi1_a) psi01_b = qubit_states(N=2, states=[0, 1]) assert_(psi01_a == psi01_b)
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_BraType(): "Qobj bra type" psi = basis(2, 1).dag() assert_equal(psi.isket, False) assert_equal(psi.isbra, True) assert_equal(psi.isoper, False) assert_equal(psi.issuper, False) psi = tensor(basis(2, 1).dag(), basis(2, 0).dag()) assert_equal(psi.isket, False) assert_equal(psi.isbra, True) assert_equal(psi.isoper, False) assert_equal(psi.issuper, False)
def rand_ket_haar(N=2, dims=None): """ Returns a Haar random pure state of dimension ``dim`` by applying a Haar random unitary to a fixed pure state. Parameters ---------- N : int Dimension of the state vector to be returned. dims : list of ints, or None Left-dimensions of the resultant quantum object. If None, [N] is used. Returns ------- psi : Qobj A random state vector drawn from the Haar measure. """ if dims: _check_ket_dims(dims, N) else: dims = [N] psi = rand_unitary_haar(N) * basis(N, 0) psi.dims = [dims, [1]] return psi
def test_KetType(): "Qobj ket type" psi = basis(2, 1) assert_(psi.isket) assert_(not psi.isbra) assert_(not psi.isoper) assert_(not psi.issuper) psi = tensor(basis(2, 1), basis(2, 0)) assert_(psi.isket) assert_(not psi.isbra) assert_(not psi.isoper) assert_(not psi.issuper)
def ghz_state(N=3): """ Returns the N-qubit GHZ-state. Parameters ---------- N : int (default=3) Number of qubits in state Returns ------- G : qobj N-qubit GHZ-state """ state=tensor([basis(2) for k in range(N)])+tensor([basis(2,1) for k in range(N)]) return state/np.sqrt(2)
def testSwapGate(self): """ gates: swap gate """ a, b = np.random.rand(), np.random.rand() psi1 = (a * basis(2, 0) + b * basis(2, 1)).unit() c, d = np.random.rand(), np.random.rand() psi2 = (c * basis(2, 0) + d * basis(2, 1)).unit() psi_in = tensor(psi1, psi2) psi_out = tensor(psi2, psi1) psi_res = swap() * psi_in assert_((psi_out - psi_res).norm() < 1e-12) psi_res = swap() * swap() * psi_in assert_((psi_in - psi_res).norm() < 1e-12)
def testExpandGate2toN(self): """ gates: expand 2 to N (using cnot, iswap, sqrtswap) """ a, b = np.random.rand(), np.random.rand() k1 = (a * basis(2, 0) + b * basis(2, 1)).unit() c, d = np.random.rand(), np.random.rand() k2 = (c * basis(2, 0) + d * basis(2, 1)).unit() psi_ref_in = tensor(k1, k2) N = 6 psi_rand_list = [rand_ket(2) for k in range(N)] for g in [cnot, iswap, sqrtswap]: psi_ref_out = g() * psi_ref_in rho_ref_out = ket2dm(psi_ref_out) for m in range(N): for n in set(range(N)) - {m}: psi_list = [psi_rand_list[k] for k in range(N)] psi_list[m] = k1 psi_list[n] = k2 psi_in = tensor(psi_list) if g == cnot: G = g(N, m, n) else: G = g(N, [m, n]) psi_out = G * psi_in o1 = psi_out.overlap(psi_in) o2 = psi_ref_out.overlap(psi_ref_in) assert_(abs(o1 - o2) < 1e-12) p = [0, 1] if m < n else [1, 0] rho_out = psi_out.ptrace([m, n]).permute(p) assert_((rho_ref_out - rho_out).norm() < 1e-12)
def test_OperType(): "Qobj operator type" psi = basis(2, 1) rho = psi * psi.dag() assert_equal(rho.isket, False) assert_equal(rho.isbra, False) assert_equal(rho.isoper, True) assert_equal(rho.issuper, False)
def qstate(string): """Creates a tensor product for a set of qubits in either the 'up' :math:`|0>` or 'down' :math:`|1>` state. Parameters ---------- string : str String containing 'u' or 'd' for each qubit (ex. 'ududd') Returns ------- qstate : qobj Qobj for tensor product corresponding to input string. Examples -------- >>> qstate('udu') Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = [8, 1], type = ket Qobj data = [[ 0.] [ 0.] [ 0.] [ 0.] [ 0.] [ 1.] [ 0.] [ 0.]] """ n=len(string) if n!=(string.count('u')+string.count('d')): raise TypeError('String input to QSTATE must consist of "u" and "d" elements only') else: up=basis(2,1) dn=basis(2,0) lst=[] for k in range(n): if string[k]=='u': lst.append(up) else: lst.append(dn) return tensor(lst)
def test_QobjEigenStates(): "Qobj eigenstates" data = np.eye(5) A = Qobj(data) b, c = A.eigenstates() assert_(np.all(b - np.ones(5) == 0)) kets = [basis(5, k) for k in range(5)] for k in range(5): assert_(c[k] == kets[k])
def test_fidelity_known_cases(): """ Metrics: Checks fidelity against known cases. """ ket0 = basis(2, 0) ket1 = basis(2, 1) ketp = (ket0 + ket1).unit() # A state that almost overlaps with |+> should serve as # a nice test case, especially since we can analytically # calculate its overlap with |+>. ketpy = (ket0 + np.exp(1j * np.pi / 4) * ket1).unit() mms = qeye(2).unit() assert_almost_equal(fidelity(ket0, ketp), 1 / np.sqrt(2)) assert_almost_equal(fidelity(ket0, ket1), 0) assert_almost_equal(fidelity(ket0, mms), 1 / np.sqrt(2)) assert_almost_equal(fidelity(ketp, ketpy), np.sqrt( (1 / 8) + (1 / 2 + 1 / (2 * np.sqrt(2))) ** 2 ) )
def snot(): """Quantum object representing the SNOT (Hadamard) gate. Returns ------- snot_gate : qobj Quantum object representation of SNOT (Hadamard) gate. Examples -------- >>> snot() Quantum object: dims = [[2], [2]], \ shape = [2, 2], type = oper, isHerm = True Qobj data = [[ 0.70710678+0.j 0.70710678+0.j] [ 0.70710678+0.j -0.70710678+0.j]] """ u = basis(2,0) d = basis(2,1) Q = 1.0 / sqrt(2.0) * (sigmax()+sigmaz()) return Q
def w_state(N=3): """ Returns the N-qubit W-state. Parameters ---------- N : int (default=3) Number of qubits in state Returns ------- W : qobj N-qubit W-state """ inds=np.zeros(N,dtype=int) inds[0]=1 state=tensor([basis(2,x) for x in inds]) for kk in range(1,N): perm_inds=np.roll(inds,kk) state+=tensor([basis(2,x) for x in perm_inds]) return state.unit()
def testExpandGate3toN(self): """ gates: expand 3 to N (using toffoli, fredkin, and random 3 qubit gate) """ a, b = np.random.rand(), np.random.rand() psi1 = (a * basis(2, 0) + b * basis(2, 1)).unit() c, d = np.random.rand(), np.random.rand() psi2 = (c * basis(2, 0) + d * basis(2, 1)).unit() e, f = np.random.rand(), np.random.rand() psi3 = (e * basis(2, 0) + f * basis(2, 1)).unit() N = 4 psi_rand_list = [rand_ket(2) for k in range(N)] _rand_gate_U = tensor([rand_herm(2, density=1) for k in range(3)]) def _rand_3qubit_gate(N=None, controls=None, k=None): if N is None: return _rand_gate_U else: return gate_expand_3toN(_rand_gate_U, N, controls, k) for g in [fredkin, toffoli, _rand_3qubit_gate]: psi_ref_in = tensor(psi1, psi2, psi3) psi_ref_out = g() * psi_ref_in for m in range(N): for n in set(range(N)) - {m}: for k in set(range(N)) - {m, n}: psi_list = [psi_rand_list[p] for p in range(N)] psi_list[m] = psi1 psi_list[n] = psi2 psi_list[k] = psi3 psi_in = tensor(psi_list) if g == fredkin: targets = [n, k] G = g(N, control=m, targets=targets) else: controls = [m, n] G = g(N, controls, k) psi_out = G * psi_in o1 = psi_out.overlap(psi_in) o2 = psi_ref_out.overlap(psi_ref_in) assert_(abs(o1 - o2) < 1e-12)
def test_SuperType(): "Qobj superoperator type" psi = basis(2, 1) rho = psi * psi.dag() sop = spre(rho) assert not sop.isket assert not sop.isbra assert not sop.isoper assert sop.issuper sop = spost(rho) assert not sop.isket assert not sop.isbra assert not sop.isoper assert sop.issuper
def kets(s): """Generates a list of column vectors that corresponds to the states in Hilbert space. Parameters ---------- s : States array States in Hilbert space. Returns ------- state : array of qobj column_vectors column_vector representing the requested number state ``|n>``. """ N = len(s) kets = [] for n in range(N): kets.append(basis(N,n)) return np.array(kets)
def test_SuperType(): "Qobj superoperator type" psi = basis(2, 1) rho = psi * psi.dag() sop = spre(rho) assert_equal(sop.isket, False) assert_equal(sop.isbra, False) assert_equal(sop.isoper, False) assert_equal(sop.issuper, True) sop = spost(rho) assert_equal(sop.isket, False) assert_equal(sop.isbra, False) assert_equal(sop.isoper, False) assert_equal(sop.issuper, True)
def testWaveguideSplit(self): """ Checks that a trivial splitting of a waveguide collapse operator like [sm] -> [sm/sqrt2, sm/sqrt2] doesn't affect the normalization or result """ gamma = 1.0 sm = np.sqrt(gamma) * destroy(2) pulseArea = np.pi pulseLength = 0.2 / gamma RabiFreq = pulseArea / (2 * pulseLength) psi0 = basis(2, 0) tlist = np.geomspace(gamma, 10 * gamma, 40) - gamma # Define TLS Hamiltonian with rotating frame transformation Htls = [[sm.dag() + sm, lambda t, args: RabiFreq * (t < pulseLength)]] # Run the test c_ops = [sm] c_ops_split = [sm / np.sqrt(2), sm / np.sqrt(2)] P1 = scattering_probability(Htls, psi0, 1, c_ops, tlist) P1_split = scattering_probability(Htls, psi0, 1, c_ops_split, tlist) tolerance = 1e-7 assert_(1 - tolerance < P1 / P1_split < 1 + tolerance)
def rand_ket_haar(N=None, dims=None, seed=None): """ Returns a Haar random pure state of dimension ``dim`` by applying a Haar random unitary to a fixed pure state. Parameters ---------- N : int Dimension of the state vector to be returned. If None, N is deduced from dims. dims : list of ints, or None Dimensions of the resultant quantum object. If None, [[N],[1]] is used. Returns ------- psi : Qobj A random state vector drawn from the Haar measure. Raises ------- ValueError If neither `N` or `dims` are specified. """ if N is None and dims is None: raise ValueError('Specify either the number of rows of state vector' '(N) or dimensions of quantum object (dims)') if N and dims: _check_dims(dims, N, 1) elif dims: N = np.prod(dims[0]) _check_dims(dims, N, 1) else: dims = [[N], [1]] psi = rand_unitary_haar(N, seed=seed) * basis(N, 0) psi.dims = dims return psi
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ############################################################################### import numpy as np from numpy.testing import assert_, assert_equal, run_module_suite from qutip.states import basis from qutip.three_level_atom import * three_states = three_level_basis() three_check = np.array([basis(3), basis(3, 1), basis(3, 2)], dtype=object) three_ops = three_level_ops() def testThreeStates(): "Three-level atom: States" assert_equal(np.all(three_states == three_check), True) def testThreeOps(): "Three-level atom: Operators" assert_equal((three_ops[0] * three_states[0]).full(), three_check[0].full()) assert_equal((three_ops[1] * three_states[1]).full(), three_check[1].full()) assert_equal((three_ops[2] * three_states[2]).full(),
def tens(i,j,k): return tensor(basis(2,i),basis(2,j),basis(2,k))
def propagator(H, t, c_op_list=[], args={}, options=None, parallel=False, progress_bar=None, **kwargs): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. parallel : bool {False, True} Run the propagator in parallel mode. progress_bar: BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. By default no progress bar is used, and if set to True a TextProgressBar will be used. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ kw = _default_kwargs() if 'num_cpus' in kwargs: num_cpus = kwargs['num_cpus'] else: num_cpus = kw['num_cpus'] if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t td_type = _td_format_check(H, c_op_list, solver='me')[2] if td_type > 0: rhs_generate(H, c_op_list, args=args, options=options) if isinstance( H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_sesolve, range(N), task_args=(N, H, tlist, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N): for k, t in enumerate(tlist): u[:, n, k] = output[n].states[k].full().T else: progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T progress_bar.finished() # todo: evolving a batch of wave functions: # psi_0_list = [basis(N, n) for n in range(N)] # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options) # for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] sqrt_N = int(np.sqrt(N)) dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve, range(N * N), task_args=(sqrt_N, H, tlist, c_op_list, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N) for n in range(0, N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n, (sqrt_N, sqrt_N)) rho0 = Qobj( sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(sqrt_N, sqrt_N), dtype=complex)) output = mesolve(H, rho0, tlist, [], [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve, range(N * N), task_args=(N, H, tlist, c_op_list, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n, (N, N)) rho0 = Qobj( sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(N, N), dtype=complex)) output = mesolve(H, rho0, tlist, c_op_list, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return np.array( [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))], dtype=object)
def create_circuit(num_nodes, paths, current_path_index, paths_list, bran_size_list, qc, best_path, highest_fidelity, noise_dict, qubit_set, iterations): #print(paths[current_path_index]) for i, p in enumerate(map(nx.utils.pairwise, paths[current_path_index])): if current_path_index == 0: qubit_set = set() other_set = set() if current_path_index > 0: other_set = set(paths[current_path_index][i]) if len(qubit_set.intersection( other_set)) == 1 or current_path_index == 0: #print(list(p)) cp = list(p) bran_size_list[current_path_index] = len(cp) #print(bran_size_list) current_paths_list = paths_list + cp #print(current_paths_list) if (current_path_index + 1) == len(paths): iterations += 1 qubits = set() for k in range(len(current_paths_list)): qubits.add(current_paths_list[k][0]) qubits.add(current_paths_list[k][1]) if len(qubits) == num_nodes: break #print(qubits) num_qubits = len(qubits) #mapping = {list(qubits)[m]:m for m in range(num_qubits)} #hardware_qubits_mapped_qubit_dict = {k:k for k in range(num_qubits)} q1 = QubitCircuit(num_qubits) q2 = QubitCircuit(num_qubits) q1.user_gates = { "NU": mg.user_cnot, "CSWAP": mg.cnot_swap, "USWAP": mg.user_swap } q2.user_gates = { "NU": mg.user_cnot, "CSWAP": mg.cnot_swap, "USWAP": mg.user_swap } q1.add_gate("SNOT", 0) q2.add_gate("SNOT", 0) starting_place = 0 ending = 0 #print(bran_size_list) l = 0 for size in bran_size_list: ending = ending + size #print(current_paths_list[starting_place:ending]) for edge in current_paths_list[starting_place:ending]: # if len(current_paths_list) == 1: # q1.add_gate("NU", targets = [mapping[edge[0]],mapping[edge[1]]], arg_value = 1) # q2.add_gate("NU", targets = [mapping[edge[0]],mapping[edge[1]]], arg_value = noise_dict_index_keys[edge]) if l == (ending - 1): q1.add_gate("NU", targets=[l, l + 1], arg_value=1) q2.add_gate("NU", targets=[l, l + 1], arg_value=noise_dict[edge]) elif l < (ending - 1): q1.add_gate("USWAP", targets=[l, l + 1], arg_value=1) q2.add_gate("USWAP", targets=[l, l + 1], arg_value=noise_dict[edge]) #hardware_qubits_mapped_qubit_dict[mapping[edge[0]]], hardware_qubits_mapped_qubit_dict[mapping[edge[1]]] = hardware_qubits_mapped_qubit_dict[mapping[edge[1]]], hardware_qubits_mapped_qubit_dict[mapping[edge[0]]] l = l + 1 #print(current_paths_list[starting_place:ending]) starting_place = starting_place + size y = gate_sequence_product(q1.propagators()) * tensor( [basis(2, 0)] * num_qubits) y2 = gate_sequence_product(q2.propagators()) * tensor( [basis(2, 0)] * num_qubits) fidel = fidelity(y, y2) #print(fidel) if fidel > highest_fidelity: qc = q2 best_path = current_paths_list highest_fidelity = fidel #highest fidelity print(highest_fidelity) print(qc.gates) print(best_path) if (i + 1) == len(paths[current_path_index]) and (current_path_index + 1) == len(paths): return qc, best_path, highest_fidelity, iterations j = current_path_index current_set = qubit_set if ((current_path_index + 1) < len(paths) and len(current_set.intersection(other_set)) == 1) or (len(paths) > 1 and current_path_index == 0): current_set.update(paths[current_path_index][i]) j += 1 qc, best_path, highest_fidelity, iterations = create_circuit( num_nodes, paths, j, current_paths_list, bran_size_list, qc, best_path, highest_fidelity, noise_dict, current_set, iterations) return qc, best_path, highest_fidelity, iterations
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()) case(S, True, True, False) # A single off-diagonal element should not be CP, # nor even HP. S = sprepost(a, a) case(S, False, False, False) # Check that unitaries are CPTP and HP. case(identity(2), True, True, True) case(sigmax(), True, True, True) # Check that unitaries on bipartite systems are CPTP and HP. case(tensor(sigmax(), identity(2)), True, True, True) # Check that a linear combination of bipartitie unitaries is CPTP and HP. S = (to_super(tensor(sigmax(), identity(2))) + to_super(tensor(identity(2), sigmay()))) / 2 case(S, 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') 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') case(subnorm_map, True, True, False) # Check that things which aren't even operators aren't identified as # CPTP. case(basis(2), False, False, False)
''' Created on May 2, 2019 @author: leonardo ''' from numpy import pi from qutip import tensor from qutip.operators import sigmax, identity from qutip.qip.circuit import QubitCircuit from qutip.qip.gates import hadamard_transform, cnot, snot, swap, \ gate_sequence_product from qutip.qip.qubits import qubit_states from qutip.states import basis, fock print(basis(N=4, n=0)) print("\n") print(fock(N=4, n=0)) print("\n") print(qubit_states(N=2, states=[0, 0])) print("\n") x = sigmax() print(x) print("\n") ket_zero = qubit_states(N=1, states=[0]) print(ket_zero) print("\n")
from qutip.states import basis from qutip import tensor from qutip.metrics import fidelity eps = 0.7 Re = eps # reeward ratio P = 1./eps # punishment ratio t_e = uniform(0,pi) # random theta angle p_e = uniform(0,2*pi) # random phi angle N = 200 # number of iterations # operators X = qip.sigmax() # x-Pauli operator Z = qip.sigmaz() # z-Pauli operator P_0 = basis(2,0)*basis(2,0).dag() # projector onto eigenspace spanned by |0> P_0 = gate_expand_1toN(P_0,2,0) I = qip.qeye(2) # identity operator Ucnot = cnot(control=1, target=0) # cnot gate # initial conditions Delta = 4*pi # exploration range U = I u = I # initial states A = basis(2,0) # agent in the state |0> E = basis(2,0)*cos(t_e/2) + basis(2,1)*sin(t_e/2)*exp(1j*p_e) # environment state F_hist = [fidelity(E,A)] # list to store fidelities D_hist = [Delta/pi] # list to store deltas
def propagator(H, t, c_op_list, H_args=None, opt=None): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj Hamiltonian t : float Time. c_op_list : list List of qobj collapse operators. Other Parameters ---------------- H_args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ if opt == None: opt = Odeoptions() opt.rhs_reuse = True if len(c_op_list) == 0: # calculate propagator for the wave function if isinstance(H, FunctionType): H0 = H(0.0, H_args) N = H0.shape[0] elif isinstance(H, list): if isinstance(H[0], list): H0 = H[0][0] N = H0.shape[0] else: H0 = H[0] N = H0.shape[0] else: N = H.shape[0] u = zeros([N, N], dtype=complex) for n in range(0, N): psi0 = basis(N, n) output = mesolve(H, psi0, [0, t], [], [], H_args, opt) u[:, n] = output.states[1].full().T # todo: evolving a batch of wave functions: #psi_0_list = [basis(N, n) for n in range(N)] #psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], H_args, opt) #for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T else: # calculate the propagator for the vector representation of the # density matrix if isinstance(H, FunctionType): H0 = H(0.0, H_args) N = H0.shape[0] elif isinstance(H, list): if isinstance(H[0], list): H0 = H[0][0] N = H0.shape[0] else: H0 = H[0] N = H0.shape[0] else: N = H.shape[0] u = zeros([N * N, N * N], dtype=complex) for n in range(0, N * N): psi0 = basis(N * N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, [0, t], c_op_list, [], H_args, opt) u[:, n] = mat2vec(output.states[1].full()).T return Qobj(u)
def _parallel_sesolve(n, N, H, tlist, args, options): psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options, _safe_mode=False) if config.tdname: _cython_build_cleanup(config.tdname) return output
from pylab import * from qutip.tensor import tensor from qutip.states import basis #many definitions sx = sigmax() sy = sigmay() sz = sigmaz() sm = destroy(2) sz1 = tensor(sz,qeye(2),qeye(2)) sz2 = tensor(qeye(2),sz,qeye(2)) sz3 = tensor(qeye(2),qeye(2),sz) psiplus = 1/sqrt(2)*(tensor(basis(2,1),basis(2,1))+tensor(basis(2,0),basis(2,0))); pp = tensor(psiplus * psiplus.dag(),qeye(2)) psiminus = 1/sqrt(2)*(tensor(basis(2,1),basis(2,1))-tensor(basis(2,0),basis(2,0))); mm = tensor(psiminus * psiminus.dag(),qeye(2)) zz = tensor(qeye(2),qeye(2),basis(2,0)*basis(2,0).dag()) onon = tensor(qeye(2),qeye(2),basis(2,1)*basis(2,1).dag()) up = tensor(psiminus,basis(2,0)) down = tensor(psiplus,basis(2,1)) p0 = tensor(psiplus,basis(2,0)) p1 = tensor(psiminus,basis(2,1)) pp0 = tensor(psiplus,basis(2,0)) pm1 = tensor(psiminus,basis(2,1)) # For Error Correction X = tensor(sx,qeye(2),qeye(2))
def propagator(H, t, c_op_list=[], args={}, options=None, unitary_mode='batch', parallel=False, progress_bar=None, _safe_mode=True, **kwargs): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. unitary_mode = str ('batch', 'single') Solve all basis vectors simulaneously ('batch') or individually ('single'). parallel : bool {False, True} Run the propagator in parallel mode. This will override the unitary_mode settings if set to True. progress_bar: BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. By default no progress bar is used, and if set to True a TextProgressBar will be used. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ kw = _default_kwargs() if 'num_cpus' in kwargs: num_cpus = kwargs['num_cpus'] else: num_cpus = kw['num_cpus'] if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t if _safe_mode: _solver_safety_check(H, None, c_ops=c_op_list, e_ops=[], args=args) td_type = _td_format_check(H, c_op_list, solver='me') if isinstance( H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims if parallel: unitary_mode = 'single' u = np.zeros([N, N, len(tlist)], dtype=complex) output = parallel_map(_parallel_sesolve, range(N), task_args=(N, H, tlist, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N): for k, t in enumerate(tlist): u[:, n, k] = output[n].states[k].full().T else: if unitary_mode == 'single': u = np.zeros([N, N, len(tlist)], dtype=complex) progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T progress_bar.finished() elif unitary_mode == 'batch': u = np.zeros(len(tlist), dtype=object) _rows = np.array([(N + 1) * m for m in range(N)]) _cols = np.zeros_like(_rows) _data = np.ones_like(_rows, dtype=complex) psi0 = Qobj(sp.coo_matrix((_data, (_rows, _cols))).tocsr()) if td_type[1] > 0 or td_type[2] > 0: H2 = [] for k in range(len(H)): if isinstance(H[k], list): H2.append([tensor(qeye(N), H[k][0]), H[k][1]]) else: H2.append(tensor(qeye(N), H[k])) else: H2 = tensor(qeye(N), H) options.normalize_output = False output = sesolve(H2, psi0, tlist, [], args=args, options=options, _safe_mode=False) for k, t in enumerate(tlist): u[k] = sp_reshape(output.states[k].data, (N, N)) unit_row_norm(u[k].data, u[k].indptr, u[k].shape[0]) u[k] = u[k].T.tocsr() else: raise Exception('Invalid unitary mode.') elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) unitary_mode = 'single' N = H0.shape[0] sqrt_N = int(np.sqrt(N)) dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve, range(N * N), task_args=(sqrt_N, H, tlist, c_op_list, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N) for n in range(0, N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n, (sqrt_N, sqrt_N)) rho0 = Qobj( sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(sqrt_N, sqrt_N), dtype=complex)) output = mesolve(H, rho0, tlist, [], [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) unitary_mode = 'single' N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if parallel: output = parallel_map(_parallel_mesolve, range(N * N), task_args=(N, H, tlist, c_op_list, args, options), progress_bar=progress_bar, num_cpus=num_cpus) for n in range(N * N): for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output[n].states[k].full()).T else: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) col_idx, row_idx = np.unravel_index(n, (N, N)) rho0 = Qobj( sp.csr_matrix(([1], ([row_idx], [col_idx])), shape=(N, N), dtype=complex)) output = mesolve(H, rho0, tlist, c_op_list, [], args, options, _safe_mode=False) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() if len(tlist) == 2: if unitary_mode == 'batch': return Qobj(u[-1], dims=dims) else: return Qobj(u[:, :, 1], dims=dims) else: if unitary_mode == 'batch': return np.array([Qobj(u[k], dims=dims) for k in range(len(tlist))], dtype=object) else: return np.array( [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))], dtype=object)
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ############################################################################### import numpy as np from numpy.testing import assert_, assert_equal, run_module_suite from qutip.states import basis from qutip.three_level_atom import * three_states = three_level_basis() three_check = np.empty((3, ), dtype=object) three_check[:] = [basis(3, 0), basis(3, 1), basis(3, 2)] three_ops = three_level_ops() def testThreeStates(): "Three-level atom: States" assert_equal(np.all(three_states == three_check), True) def testThreeOps(): "Three-level atom: Operators" assert_equal((three_ops[0] * three_states[0]).full(), three_check[0].full()) assert_equal((three_ops[1] * three_states[1]).full(), three_check[1].full()) assert_equal((three_ops[2] * three_states[2]).full(),
def test_CheckMulType(): "Qobj multiplication type" # ket-bra and bra-ket multiplication psi = basis(5) dm = psi * psi.dag() assert dm.isoper assert dm.isherm nrm = psi.dag() * psi assert np.prod(nrm.shape) == 1 assert abs(nrm)[0, 0] == 1 # operator-operator multiplication H1 = rand_herm(3) H2 = rand_herm(3) out = H1 * H2 assert out.isoper out = H1 * H1 assert out.isoper assert out.isherm out = H2 * H2 assert out.isoper assert out.isherm U = rand_unitary(5) out = U.dag() * U assert out.isoper assert out.isherm N = num(5) out = N * N assert out.isoper assert out.isherm # operator-ket and bra-operator multiplication op = sigmax() ket1 = basis(2) ket2 = op * ket1 assert ket2.isket bra1 = basis(2).dag() bra2 = bra1 * op assert bra2.isbra assert bra2.dag() == ket2 # bra and ket multiplication with different dims zero = basis(2, 0) zero_log = tensor(zero, zero, zero) op1 = zero_log * zero.dag() op2 = zero * zero_log.dag() assert op1 == op2.dag() # superoperator-operket and operbra-superoperator multiplication sop = to_super(sigmax()) opket1 = operator_to_vector(fock_dm(2)) opket2 = sop * opket1 assert opket2.isoperket opbra1 = operator_to_vector(fock_dm(2)).dag() opbra2 = opbra1 * sop assert opbra2.isoperbra assert opbra2.dag() == opket2
def propagator(H, t, c_op_list, args=None, options=None, sparse=False, progress_bar=None): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Options` with options for the ODE solver. progress_bar: BaseProgressBar Optional instance of BaseProgressBar, or a subclass thereof, for showing the progress of the simulation. By default no progress bar is used, and if set to True a TextProgressBar will be used. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ if progress_bar is None: progress_bar = BaseProgressBar() elif progress_bar is True: progress_bar = TextProgressBar() if options is None: options = Options() options.rhs_reuse = True rhs_clear() if isinstance(t, (int, float, np.integer, np.floating)): tlist = [0, t] else: tlist = t if isinstance( H, (types.FunctionType, types.BuiltinFunctionType, functools.partial)): H0 = H(0.0, args) elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] else: H0 = H if len(c_op_list) == 0 and H0.isoper: # calculate propagator for the wave function N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T progress_bar.finished() # todo: evolving a batch of wave functions: # psi_0_list = [basis(N, n) for n in range(N)] # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options) # for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T elif len(c_op_list) == 0 and H0.issuper: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = H0.dims u = np.zeros([N, N, len(tlist)], dtype=complex) progress_bar.start(N) for n in range(0, N): progress_bar.update(n) psi0 = basis(N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, [], [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) N = H0.shape[0] dims = [H0.dims, H0.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) if sparse: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) psi0 = basis(N * N, n) psi0.dims = [dims[0], 1] rho0 = vector_to_operator(psi0) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = operator_to_vector( output.states[k]).full(squeeze=True) progress_bar.finished() else: progress_bar.start(N * N) for n in range(N * N): progress_bar.update(n) psi0 = basis(N * N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T progress_bar.finished() if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
def test_QobjPowerScalar(): """Check that scalars obtained from bra*ket can be exponentiated. (#1691) """ ket = basis(2, 0) assert (ket.dag()*ket)**2 == Qobj(1)
class TestSuperopReps: """ A test class for the QuTiP function for applying superoperators to subsystems. """ def test_SuperChoiSuper(self, superoperator): """ Superoperator: Converting superoperator to Choi matrix and back. """ choi_matrix = to_choi(superoperator) test_supe = to_super(choi_matrix) # Assert both that the result is close to expected, and has the right # type. assert (test_supe - superoperator).norm() < tol assert choi_matrix.type == "super" and choi_matrix.superrep == "choi" assert test_supe.type == "super" and test_supe.superrep == "super" @pytest.mark.parametrize('dimension', [2, 4]) def test_SuperChoiChiSuper(self, dimension): """ Superoperator: Converting two-qubit superoperator through Choi and chi representations goes back to right superoperator. """ superoperator = super_tensor( rand_super(dimension), rand_super(dimension), ) choi_matrix = to_choi(superoperator) chi_matrix = to_chi(choi_matrix) test_supe = to_super(chi_matrix) # Assert both that the result is close to expected, and has the right # type. assert (test_supe - superoperator).norm() < tol assert choi_matrix.type == "super" and choi_matrix.superrep == "choi" assert chi_matrix.type == "super" and chi_matrix.superrep == "chi" assert test_supe.type == "super" and test_supe.superrep == "super" def test_ChoiKrausChoi(self, superoperator): """ Superoperator: Convert superoperator to Choi matrix and back. """ choi_matrix = to_choi(superoperator) kraus_ops = to_kraus(choi_matrix) test_choi = kraus_to_choi(kraus_ops) # Assert both that the result is close to expected, and has the right # type. assert (test_choi - choi_matrix).norm() < tol assert choi_matrix.type == "super" and choi_matrix.superrep == "choi" assert test_choi.type == "super" and test_choi.superrep == "choi" def test_NonSquareKrausSuperChoi(self): """ Superoperator: Convert non-square Kraus operator to Super + Choi matrix and back. """ zero = asarray([[1], [0]], dtype=complex) one = asarray([[0], [1]], dtype=complex) zero_log = kron(kron(zero, zero), zero) one_log = kron(kron(one, one), one) # non-square Kraus operator (isometry) kraus = Qobj(zero_log @ zero.T + one_log @ one.T) super = sprepost(kraus, kraus.dag()) choi = to_choi(super) op1 = to_kraus(super) op2 = to_kraus(choi) op3 = to_super(choi) assert choi.type == "super" and choi.superrep == "choi" assert super.type == "super" and super.superrep == "super" assert (op1[0] - kraus).norm() < tol assert (op2[0] - kraus).norm() < tol assert (op3 - super).norm() < tol def test_NeglectSmallKraus(self): """ Superoperator: Convert Kraus to Choi matrix and back. Neglect tiny Kraus operators. """ zero = asarray([[1], [0]], dtype=complex) one = asarray([[0], [1]], dtype=complex) zero_log = kron(kron(zero, zero), zero) one_log = kron(kron(one, one), one) # non-square Kraus operator (isometry) kraus = Qobj(zero_log @ zero.T + one_log @ one.T) super = sprepost(kraus, kraus.dag()) # 1 non-zero Kraus operator the rest are zero sixteen_kraus_ops = to_kraus(super, tol=0.0) # default is tol=1e-9 one_kraus_op = to_kraus(super) assert len(sixteen_kraus_ops) == 16 and len(one_kraus_op) == 1 assert (one_kraus_op[0] - kraus).norm() < tol def test_SuperPreservesSelf(self, superoperator): """ Superoperator: to_super(q) returns q if q is already a supermatrix. """ assert superoperator is to_super(superoperator) def test_ChoiPreservesSelf(self, superoperator): """ Superoperator: to_choi(q) returns q if q is already Choi. """ choi = to_choi(superoperator) assert choi is to_choi(choi) def test_random_iscptp(self, superoperator): """ Superoperator: Randomly generated superoperators are correctly reported as CPTP and HP. """ assert superoperator.iscptp assert superoperator.ishp # Conjugation by a creation operator a = create(2).dag() S = sprepost(a, a.dag()) # A single off-diagonal element S_ = sprepost(a, a) # Check that a linear combination of bipartite unitaries is CPTP and HP. S_U = (to_super(tensor(sigmax(), identity(2))) + to_super(tensor(identity(2), sigmay()))) / 2 # The partial transpose map, whose Choi matrix is SWAP ptr_swap = Qobj(swap(), type='super', superrep='choi') # Subnormalized maps (representing erasure channels, for instance) subnorm_map = Qobj(identity(4) * 0.9, type='super', superrep='super') @pytest.mark.parametrize(['qobj', 'shouldhp', 'shouldcp', 'shouldtp'], [ pytest.param(S, True, True, False, id="conjugatio by create op"), pytest.param(S_, False, False, False, id="single off-diag"), pytest.param(identity(2), True, True, True, id="Identity"), pytest.param(sigmax(), True, True, True, id="Pauli X"), pytest.param( tensor(sigmax(), identity(2)), True, True, True, id="bipartite system", ), pytest.param( S_U, True, True, True, id="linear combination of bip. unitaries", ), pytest.param(ptr_swap, True, False, True, id="partial transpose map"), pytest.param(subnorm_map, True, True, False, id="subnorm map"), pytest.param(basis(2), False, False, False, id="not an operator"), ]) def test_known_iscptp(self, qobj, shouldhp, shouldcp, shouldtp): """ Superoperator: ishp, iscp, istp and iscptp known cases. """ assert qobj.ishp == shouldhp assert qobj.iscp == shouldcp assert qobj.istp == shouldtp assert qobj.iscptp == (shouldcp and shouldtp) def test_choi_tr(self, dimension): """ Superoperator: Trace returned by to_choi matches docstring. """ assert abs(to_choi(identity(dimension)).tr() - dimension) <= tol def test_stinespring_cp(self, dimension): """ Stinespring: A and B match for CP maps. """ superop = rand_super_bcsz(dimension) A, B = to_stinespring(superop) assert norm(A - B) < tol @pytest.mark.repeat(3) def test_stinespring_agrees(self, dimension): """ Stinespring: Partial Tr over pair agrees w/ supermatrix. """ map = rand_super_bcsz(dimension) state = rand_dm_ginibre(dimension) S = to_super(map) A, B = to_stinespring(map) q1 = vector_to_operator(S * operator_to_vector(state)) # FIXME: problem if Kraus index is implicitly # ptraced! q2 = (A * state * B.dag()).ptrace((0, )) assert (q1 - q2).norm('tr') <= tol def test_stinespring_dims(self, dimension): """ Stinespring: Check that dims of channels are preserved. """ chan = super_tensor(to_super(sigmax()), to_super(qeye(dimension))) A, B = to_stinespring(chan) assert A.dims == [[2, dimension, 1], [2, dimension]] assert B.dims == [[2, dimension, 1], [2, dimension]] @pytest.mark.parametrize('dimension', [2, 4, 8]) def test_chi_choi_roundtrip(self, dimension): superop = rand_super_bcsz(dimension) superop = to_chi(superop) rt_superop = to_chi(to_choi(superop)) dif = norm(rt_superop - superop) assert dif == pytest.approx(0, abs=1e-7) assert rt_superop.type == superop.type assert rt_superop.dims == superop.dims chi_sigmax = [[0, 0, 0, 0], [0, 4, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] chi_diag2 = [[4, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] rotX_pi_4 = (-1j * sigmax() * pi / 4).expm() chi_rotX_pi_4 = [[2, 2j, 0, 0], [-2j, 2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]] @pytest.mark.parametrize(['superop', 'chi_expected'], [ pytest.param(sigmax(), chi_sigmax), pytest.param(to_super(sigmax()), chi_sigmax), pytest.param(qeye(2), chi_diag2), pytest.param(rotX_pi_4, chi_rotX_pi_4) ]) def test_chi_known(self, superop, chi_expected): """ Superoperator: Chi-matrix for known cases is correct. """ chi_actual = to_chi(superop) chiq = Qobj( chi_expected, dims=[[[2], [2]], [[2], [2]]], superrep='chi', ) assert (chi_actual - chiq).norm() < tol
def propagator(H, t, c_op_list, args=None, options=None): """ Calculate the propagator U(t) for the density matrix or wave function such that :math:`\psi(t) = U(t)\psi(0)` or :math:`\\rho_{\mathrm vec}(t) = U(t) \\rho_{\mathrm vec}(0)` where :math:`\\rho_{\mathrm vec}` is the vector representation of the density matrix. Parameters ---------- H : qobj or list Hamiltonian as a Qobj instance of a nested list of Qobjs and coefficients in the list-string or list-function format for time-dependent Hamiltonians (see description in :func:`qutip.mesolve`). t : float or array-like Time or list of times for which to evaluate the propagator. c_op_list : list List of qobj collapse operators. args : list/array/dictionary Parameters to callback functions for time-dependent Hamiltonians and collapse operators. options : :class:`qutip.Odeoptions` with options for the ODE solver. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ if options is None: options = Odeoptions() options.rhs_reuse = True rhs_clear() elif options.rhs_reuse: msg = ("propagator is using previously defined rhs " + "function (options.rhs_reuse = True)") warnings.warn(msg) tlist = [0, t] if isinstance(t, (int, float, np.int64, np.float64)) else t if len(c_op_list) == 0: # calculate propagator for the wave function if isinstance(H, types.FunctionType): H0 = H(0.0, args) N = H0.shape[0] dims = H0.dims elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] N = H0.shape[0] dims = H0.dims else: N = H.shape[0] dims = H.dims u = np.zeros([N, N, len(tlist)], dtype=complex) for n in range(0, N): psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = output.states[k].full().T # todo: evolving a batch of wave functions: # psi_0_list = [basis(N, n) for n in range(N)] # psi_t_list = mesolve(H, psi_0_list, [0, t], [], [], args, options) # for n in range(0, N): # u[:,n] = psi_t_list[n][1].full().T else: # calculate the propagator for the vector representation of the # density matrix (a superoperator propagator) if isinstance(H, types.FunctionType): H0 = H(0.0, args) N = H0.shape[0] dims = [H0.dims, H0.dims] elif isinstance(H, list): H0 = H[0][0] if isinstance(H[0], list) else H[0] N = H0.shape[0] dims = [H0.dims, H0.dims] else: N = H.shape[0] dims = [H.dims, H.dims] u = np.zeros([N * N, N * N, len(tlist)], dtype=complex) for n in range(0, N * N): psi0 = basis(N * N, n) rho0 = Qobj(vec2mat(psi0.full())) output = mesolve(H, rho0, tlist, c_op_list, [], args, options) for k, t in enumerate(tlist): u[:, n, k] = mat2vec(output.states[k].full()).T if len(tlist) == 2: return Qobj(u[:, :, 1], dims=dims) else: return [Qobj(u[:, :, k], dims=dims) for k in range(len(tlist))]
""" T2 Relaxation ============= Simulating the T2 relaxation of a single qubit with :class:`qutip.qip.device.Processor`. The single qubit is driven by a rotation around z axis. We measure the population of the plus state as a function of time to see the Ramsey signal. """ import numpy as np import matplotlib.pyplot as plt from qutip.qip.device import Processor from qutip.operators import sigmaz, destroy from qutip.qip import snot from qutip.states import basis a = destroy(2) Hadamard = snot() plus_state = (basis(2, 1) + basis(2, 0)).unit() tlist = np.arange(0.00, 20.2, 0.2) T2 = 5 processor = Processor(1, t2=T2) processor.add_ctrl(sigmaz()) processor.tlist = tlist processor.coeffs = np.ones((1, len(processor.tlist))) result = processor.run_state( rho0=plus_state, e_ops=[a.dag() * a, Hadamard * a.dag() * a * Hadamard]) fig, ax = plt.subplots() # detail about length of tlist needs to be fixed ax.plot(tlist[:-1], result.expect[1][:-1], '.', label="simulation") ax.plot(tlist[:-1], np.exp(-1. / T2 * tlist[:-1]) * 0.5 + 0.5, label="theory") ax.set_xlabel("t")
def _parallel_sesolve(n, N, H, tlist, args, options): psi0 = basis(N, n) output = sesolve(H, psi0, tlist, [], args, options, _safe_mode=False) return output