def countstat_current(L, c_ops=None, rhoss=None, J_ops=None): """ Calculate the current corresponding a system Liouvillian `L` and a list of current collapse operators `c_ops` or current superoperators `J_ops` (either must be specified). Optionally the steadystate density matrix `rhoss` and a list of current superoperators `J_ops` can be specified. If either of these are omitted they are computed internally. Parameters ---------- L : :class:`qutip.Qobj` Qobj representing the system Liouvillian. c_ops : array / list (optional) List of current collapse operators. rhoss : :class:`qutip.Qobj` (optional) The steadystate density matrix corresponding the system Liouvillian `L`. J_ops : array / list (optional) List of current superoperators. Returns -------- I : array The currents `I` corresponding to each current collapse operator `c_ops` (or, equivalently, each current superopeator `J_ops`). """ if J_ops is None: if c_ops is None: raise ValueError("c_ops must be given if J_ops is not") J_ops = [sprepost(c, c.dag()) for c in c_ops] if rhoss is None: if c_ops is None: raise ValueError("c_ops must be given if rhoss is not") rhoss = steadystate(L, c_ops) rhoss_vec = mat2vec(rhoss.full()).ravel() N = len(J_ops) I = np.zeros(N) for i, Ji in enumerate(J_ops): I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) return I
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 to_super(q_oper): """ Converts a Qobj representing a quantum map to the supermatrix (Liouville) representation. Parameters ---------- q_oper : Qobj Superoperator to be converted to supermatrix representation. If ``q_oper`` is ``type="oper"``, then it is taken to act by conjugation, such that ``to_super(A) == sprepost(A, A.dag())``. Returns ------- superop : Qobj A quantum object representing the same map as ``q_oper``, such that ``superop.superrep == "super"``. Raises ------ TypeError If the given quantum object is not a map, or cannot be converted to supermatrix representation. """ if q_oper.type == 'super': # Case 1: Already done. if q_oper.superrep == "super": return q_oper # Case 2: Can directly convert. elif q_oper.superrep == 'choi': return choi_to_super(q_oper) # Case 3: Need to go through Choi. elif q_oper.superrep == 'chi': return to_super(to_choi(q_oper)) # Case 4: Something went wrong. else: raise ValueError( "Unrecognized superrep '{}'.".format(q_oper.superrep)) elif q_oper.type == 'oper': # Assume unitary return sprepost(q_oper, q_oper.dag()) else: raise TypeError( "Conversion of Qobj with type = {0.type} " "and superrep = {0.superrep} to supermatrix not " "supported.".format(q_oper) )
def to_chi(q_oper): """ Converts a Qobj representing a quantum map to a representation as a chi (process) matrix in the Pauli basis, such that the trace of the returned operator is equal to the dimension of the system. Parameters ---------- q_oper : Qobj Superoperator to be converted to Chi representation. If ``q_oper`` is ``type="oper"``, then it is taken to act by conjugation, such that ``to_chi(A) == to_chi(sprepost(A, A.dag()))``. Returns ------- chi : Qobj A quantum object representing the same map as ``q_oper``, such that ``chi.superrep == "chi"``. Raises ------ TypeError: if the given quantum object is not a map, or cannot be converted to Chi representation. """ if q_oper.type == 'super': # Case 1: Already done. if q_oper.superrep == 'chi': return q_oper # Case 2: Can directly convert. elif q_oper.superrep == 'choi': return choi_to_chi(q_oper) # Case 3: Need to go through Choi. elif q_oper.superrep == 'super': return to_chi(to_choi(q_oper)) else: raise TypeError(q_oper.superrep) elif q_oper.type == 'oper': return to_chi(sprepost(q_oper, q_oper.dag())) else: raise TypeError( "Conversion of Qobj with type = {0.type} " "and superrep = {0.choi} to Choi not supported.".format(q_oper) )
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() < 1e-8) assert_((op2[0] - kraus).norm() < 1e-8) assert_((op3 - super).norm() < 1e-8)
def to_choi(q_oper): """ Converts a Qobj representing a quantum map to the Choi representation, such that the trace of the returned operator is equal to the dimension of the system. Parameters ---------- q_oper : Qobj Superoperator to be converted to Choi representation. If ``q_oper`` is ``type="oper"``, then it is taken to act by conjugation, such that ``to_choi(A) == to_choi(sprepost(A, A.dag()))``. Returns ------- choi : Qobj A quantum object representing the same map as ``q_oper``, such that ``choi.superrep == "choi"``. Raises ------ TypeError: if the given quantum object is not a map, or cannot be converted to Choi representation. """ if q_oper.type == 'super': if q_oper.superrep == 'choi': return q_oper if q_oper.superrep == 'super': return super_to_choi(q_oper) if q_oper.superrep == 'chi': return chi_to_choi(q_oper) else: raise TypeError(q_oper.superrep) elif q_oper.type == 'oper': return super_to_choi(sprepost(q_oper, q_oper.dag())) else: raise TypeError( "Conversion of Qobj with type = {0.type} " "and superrep = {0.choi} to Choi not supported.".format(q_oper) )
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)
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 countstat_current_noise(L, c_ops, wlist=None, rhoss=None, J_ops=None, sparse=True, method='direct'): """ Compute the cross-current noise spectrum for a list of collapse operators `c_ops` corresponding to monitored currents, given the system Liouvillian `L`. The current collapse operators `c_ops` should be part of the dissipative processes in `L`, but the `c_ops` given here does not necessarily need to be all collapse operators contributing to dissipation in the Liouvillian. Optionally, the steadystate density matrix `rhoss` and the current operators `J_ops` correpsonding to the current collapse operators `c_ops` can also be specified. If either of `rhoss` and `J_ops` are omitted, they will be computed internally. 'wlist' is an optional list of frequencies at which to evaluate the noise spectrum. Note: The default method is a direct solution using dense matrices, as sparse matrix methods fail for some examples of small systems. For larger systems it is reccomended to use the sparse solver with the direct method, as it avoids explicit calculation of the pseudo-inverse, as described in page 67 of "Electrons in nanostructures" C. Flindt, PhD Thesis, available online: http://orbit.dtu.dk/fedora/objects/orbit:82314/datastreams/file_4732600/content Parameters ---------- L : :class:`qutip.Qobj` Qobj representing the system Liouvillian. c_ops : array / list List of current collapse operators. rhoss : :class:`qutip.Qobj` (optional) The steadystate density matrix corresponding the system Liouvillian `L`. wlist : array / list (optional) List of frequencies at which to evaluate (if none are given, evaluates at zero frequency) J_ops : array / list (optional) List of current superoperators. sparse : bool Flag that indicates whether to use sparse or dense matrix methods when computing the pseudo inverse. Default is false, as sparse solvers can fail for small systems. For larger systems the sparse solvers are reccomended. Returns -------- I, S : tuple of arrays The currents `I` corresponding to each current collapse operator `c_ops` (or, equivalently, each current superopeator `J_ops`) and the zero-frequency cross-current correlation `S`. """ if rhoss is None: rhoss = steadystate(L, c_ops) if J_ops is None: J_ops = [sprepost(c, c.dag()) for c in c_ops] N = len(J_ops) I = np.zeros(N) if wlist is None: S = np.zeros((N, N, 1)) wlist = [0.] else: S = np.zeros((N, N, len(wlist))) if sparse == False: rhoss_vec = mat2vec(rhoss.full()).ravel() for k, w in enumerate(wlist): R = pseudo_inverse(L, rhoss=rhoss, w=w, sparse=sparse, method=method) for i, Ji in enumerate(J_ops): for j, Jj in enumerate(J_ops): if i == j: I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) S[i, j, k] = I[i] S[i, j, k] -= expect_rho_vec( (Ji * R * Jj + Jj * R * Ji).data, rhoss_vec, 1) else: if method == "direct": N = np.prod(L.dims[0][0]) rhoss_vec = operator_to_vector(rhoss) tr_op = tensor([identity(n) for n in L.dims[0][0]]) tr_op_vec = operator_to_vector(tr_op) Pop = sp.kron(rhoss_vec.data, tr_op_vec.data.T, format='csr') Iop = sp.eye(N * N, N * N, format='csr') Q = Iop - Pop for k, w in enumerate(wlist): if w != 0.0: L_temp = 1.0j * w * spre(tr_op) + L else: #At zero frequency some solvers fail for small systems. #Adding a small finite frequency of order 1e-15 #helps prevent the solvers from throwing an exception. L_temp = 1.0j * (1e-15) * spre(tr_op) + L if not settings.has_mkl: A = L_temp.data.tocsc() else: A = L_temp.data.tocsr() A.sort_indices() rhoss_vec = mat2vec(rhoss.full()).ravel() for j, Jj in enumerate(J_ops): Qj = Q.dot(Jj.data.dot(rhoss_vec)) try: if settings.has_mkl: X_rho_vec_j = mkl_spsolve(A, Qj) else: X_rho_vec_j = sp.linalg.splu( A, permc_spec='COLAMD').solve(Qj) except: X_rho_vec_j = sp.linalg.lsqr(A, Qj)[0] for i, Ji in enumerate(J_ops): Qi = Q.dot(Ji.data.dot(rhoss_vec)) try: if settings.has_mkl: X_rho_vec_i = mkl_spsolve(A, Qi) else: X_rho_vec_i = sp.linalg.splu( A, permc_spec='COLAMD').solve(Qi) except: X_rho_vec_i = sp.linalg.lsqr(A, Qi)[0] if i == j: I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) S[j, i, k] = I[i] S[j, i, k] -= (expect_rho_vec(Jj.data * Q, X_rho_vec_i, 1) + expect_rho_vec(Ji.data * Q, X_rho_vec_j, 1)) else: rhoss_vec = mat2vec(rhoss.full()).ravel() for k, w in enumerate(wlist): R = pseudo_inverse(L, rhoss=rhoss, w=w, sparse=sparse, method=method) for i, Ji in enumerate(J_ops): for j, Jj in enumerate(J_ops): if i == j: I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) S[i, j, k] = I[i] S[i, j, k] -= expect_rho_vec( (Ji * R * Jj + Jj * R * Ji).data, rhoss_vec, 1) return I, S
def countstat_current_noise(L, c_ops, wlist=None, rhoss=None, J_ops=None, sparse=True, method='direct'): """ Compute the cross-current noise spectrum for a list of collapse operators `c_ops` corresponding to monitored currents, given the system Liouvillian `L`. The current collapse operators `c_ops` should be part of the dissipative processes in `L`, but the `c_ops` given here does not necessarily need to be all collapse operators contributing to dissipation in the Liouvillian. Optionally, the steadystate density matrix `rhoss` and the current operators `J_ops` correpsonding to the current collapse operators `c_ops` can also be specified. If either of `rhoss` and `J_ops` are omitted, they will be computed internally. 'wlist' is an optional list of frequencies at which to evaluate the noise spectrum. Note: The default method is a direct solution using dense matrices, as sparse matrix methods fail for some examples of small systems. For larger systems it is reccomended to use the sparse solver with the direct method, as it avoids explicit calculation of the pseudo-inverse, as described in page 67 of "Electrons in nanostructures" C. Flindt, PhD Thesis, available online: http://orbit.dtu.dk/fedora/objects/orbit:82314/datastreams/file_4732600/content Parameters ---------- L : :class:`qutip.Qobj` Qobj representing the system Liouvillian. c_ops : array / list List of current collapse operators. rhoss : :class:`qutip.Qobj` (optional) The steadystate density matrix corresponding the system Liouvillian `L`. wlist : array / list (optional) List of frequencies at which to evaluate (if none are given, evaluates at zero frequency) J_ops : array / list (optional) List of current superoperators. sparse : bool Flag that indicates whether to use sparse or dense matrix methods when computing the pseudo inverse. Default is false, as sparse solvers can fail for small systems. For larger systems the sparse solvers are reccomended. Returns -------- I, S : tuple of arrays The currents `I` corresponding to each current collapse operator `c_ops` (or, equivalently, each current superopeator `J_ops`) and the zero-frequency cross-current correlation `S`. """ if rhoss is None: rhoss = steadystate(L, c_ops) if J_ops is None: J_ops = [sprepost(c, c.dag()) for c in c_ops] N = len(J_ops) I = np.zeros(N) if wlist is None: S = np.zeros((N, N,1)) wlist=[0.] else: S = np.zeros((N, N,len(wlist))) if sparse == False: rhoss_vec = mat2vec(rhoss.full()).ravel() for k,w in enumerate(wlist): R = pseudo_inverse(L, rhoss=rhoss, w= w, sparse = sparse, method=method) for i, Ji in enumerate(J_ops): for j, Jj in enumerate(J_ops): if i == j: I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) S[i, j,k] = I[i] S[i, j,k] -= expect_rho_vec((Ji * R * Jj + Jj * R * Ji).data, rhoss_vec, 1) else: if method == "direct": N = np.prod(L.dims[0][0]) rhoss_vec = operator_to_vector(rhoss) tr_op = tensor([identity(n) for n in L.dims[0][0]]) tr_op_vec = operator_to_vector(tr_op) Pop = sp.kron(rhoss_vec.data, tr_op_vec.data.T, format='csr') Iop = sp.eye(N*N, N*N, format='csr') Q = Iop - Pop for k,w in enumerate(wlist): if w != 0.0: L_temp = 1.0j*w*spre(tr_op) + L else: #At zero frequency some solvers fail for small systems. #Adding a small finite frequency of order 1e-15 #helps prevent the solvers from throwing an exception. L_temp = 1.0j*(1e-15)*spre(tr_op) + L if not settings.has_mkl: A = L_temp.data.tocsc() else: A = L_temp.data.tocsr() A.sort_indices() rhoss_vec = mat2vec(rhoss.full()).ravel() for j, Jj in enumerate(J_ops): Qj = Q.dot( Jj.data.dot( rhoss_vec)) try: if settings.has_mkl: X_rho_vec_j = mkl_spsolve(A,Qj) else: X_rho_vec_j = sp.linalg.splu(A, permc_spec ='COLAMD').solve(Qj) except: X_rho_vec_j = sp.linalg.lsqr(A,Qj)[0] for i, Ji in enumerate(J_ops): Qi = Q.dot( Ji.data.dot(rhoss_vec)) try: if settings.has_mkl: X_rho_vec_i = mkl_spsolve(A,Qi) else: X_rho_vec_i = sp.linalg.splu(A, permc_spec ='COLAMD').solve(Qi) except: X_rho_vec_i = sp.linalg.lsqr(A,Qi)[0] if i == j: I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) S[j, i, k] = I[i] S[j, i, k] -= (expect_rho_vec(Jj.data * Q, X_rho_vec_i, 1) + expect_rho_vec(Ji.data * Q, X_rho_vec_j, 1)) else: rhoss_vec = mat2vec(rhoss.full()).ravel() for k,w in enumerate(wlist): R = pseudo_inverse(L,rhoss=rhoss, w= w, sparse = sparse, method=method) for i, Ji in enumerate(J_ops): for j, Jj in enumerate(J_ops): if i == j: I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) S[i, j, k] = I[i] S[i, j, k] -= expect_rho_vec((Ji * R * Jj + Jj * R * Ji).data, rhoss_vec, 1) return I, S
def countstat_current_noise(L, c_ops, rhoss=None, J_ops=None, R=False): """ Compute the cross-current noise spectrum for a list of collapse operators `c_ops` corresponding to monitored currents, given the system Liouvillian `L`. The current collapse operators `c_ops` should be part of the dissipative processes in `L`, but the `c_ops` given here does not necessarily need to be all collapse operators contributing to dissipation in the Liouvillian. Optionally, the steadystate density matrix `rhoss` and/or the pseudo inverse `R` of the Liouvillian `L`, and the current operators `J_ops` correpsonding to the current collapse operators `c_ops` can also be specified. If `R` is not given, the cross-current correlations will be computed directly without computing `R` explicitly. If either of `rhoss` and `J_ops` are omitted, they will be computed internally. Parameters ---------- L : :class:`qutip.Qobj` Qobj representing the system Liouvillian. c_ops : array / list List of current collapse operators. rhoss : :class:`qutip.Qobj` (optional) The steadystate density matrix corresponding the system Liouvillian `L`. J_ops : array / list (optional) List of current superoperators. R : :class:`qutip.Qobj` (optional) Qobj representing the pseudo inverse of the system Liouvillian `L`. Returns -------- I, S : tuple of arrays The currents `I` corresponding to each current collapse operator `c_ops` (or, equivalently, each current superopeator `J_ops`) and the zero-frequency cross-current correlation `S`. """ if rhoss is None: rhoss = steadystate(L, c_ops) if J_ops is None: J_ops = [sprepost(c, c.dag()) for c in c_ops] rhoss_vec = mat2vec(rhoss.full()).ravel() N = len(J_ops) I = np.zeros(N) S = np.zeros((N, N)) if R: if R is True: R = pseudo_inverse(L, rhoss) for i, Ji in enumerate(J_ops): for j, Jj in enumerate(J_ops): if i == j: I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) S[i, j] = I[i] S[i, j] -= expect_rho_vec((Ji * R * Jj + Jj * R * Ji).data, rhoss_vec, 1) else: N = np.prod(L.dims[0][0]) rhoss_vec = operator_to_vector(rhoss) tr_op = tensor([identity(n) for n in L.dims[0][0]]) tr_op_vec = operator_to_vector(tr_op) Pop = sp.kron(rhoss_vec.data, tr_op_vec.data.T, format='csc') Iop = sp.eye(N*N, N*N, format='csc') Q = Iop - Pop A = L.data.tocsc() rhoss_vec = mat2vec(rhoss.full()).ravel() for j, Jj in enumerate(J_ops): Qj = Q * Jj.data * rhoss_vec X_rho_vec = sp.linalg.splu(A, permc_spec='COLAMD').solve(Qj) for i, Ji in enumerate(J_ops): if i == j: S[i, i] = I[i] = expect_rho_vec(Ji.data, rhoss_vec, 1) S[i, j] -= expect_rho_vec(Ji.data * Q, X_rho_vec, 1) return I, S
LC_iy = liouvillian(Hc[1]) LC_iz = liouvillian(Hc[2]) #LC_zi = liouvillian(Hc[4]) #LC_zy = liouvillian(Hc[5]) #LC_zz = liouvillian(Hc[6]) drift = L0 #ctrls = [LC_ix,LC_xi,LC_xx,LC_yy]#,LC_yi] ctrls = [LC_ix,LC_iy,LC_iz,LC_zx]#,LC_ix,LC_iy,LC_iz,LC_zi,LC_zy,LC_zz] #ctrls = [LC_zx,LC_ix,LC_iy,LC_yi] #ctrls = [LC_zx,LC_ix,LC_iy,LC_yi] nctrl = len(ctrls) E0 = sprepost(U0,U0) #E_targ = sprepost(cnot_gate,cnot_gate) E_targ = sprepost(U_targ,U_targ) # Fidelity error target fid_err_targ = 1e-3 # Maximum iterations for the optisation algorithm max_iter = 3500 # Maximum (elapsed) time allowed in seconds max_wall_time = 1600 # Minimum gradient (sum of gradients squared) # as this tends to 0 -> local minima has been found min_grad = 1e-20 p_type = 'CUSTOM' for evo_time in evo_times: n_ts = int(float(evo_time/0.222))
#Amplitude damping# #Damping rate: gamma = 0.3 # qutip column vectorisation L0 = liouvillian(H0, [np.sqrt(gamma) * Sm]) #sigma X control LC_x = liouvillian(Sx) #sigma Y control LC_y = liouvillian(Sy) #sigma Z control LC_z = liouvillian(Sz) E0 = sprepost(Si, Si) # target map 1 # E_targ = sprepost(had_gate, had_gate) # target map 2 E_targ = sprepost(Sx, Sx) psi0 = basis(2, 1) # ground state #psi0 = basis(2, 0) # excited state rho0 = ket2dm(psi0) print("rho0:\n{}\n".format(rho0)) rho0_vec = operator_to_vector(rho0) print("rho0_vec:\n{}\n".format(rho0_vec)) # target state 1 # psi_targ = (basis(2, 0) + basis(2, 1)).unit() # target state 2
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
E0 = tensor(Si, Si) E_targ = tensor(had_gate, had_gate) elif vectorization == 'column': # qutip column vectorisation L0 = liouvillian(H0, [np.sqrt(gamma) * Sm]) #sigma X control LC_x = liouvillian(Sx) #sigma Y control LC_y = liouvillian(Sy) #sigma Z control LC_z = liouvillian(Sz) E0 = sprepost(Si, Si) E_targ = sprepost(had_gate, had_gate) else: raise RuntimeError("No option for vectorization={}".format(vectorization)) print("L0:\n{}\n".format(L0)) print("LC_x:\n{}\n".format(LC_x)) print("LC_y:\n{}\n".format(LC_y)) print("LC_z:\n{}\n".format(LC_z)) #Drift drift = L0 #Controls ctrls = [LC_x, LC_z]