def test_QobjMulNonsquareDims(): """ Qobj: multiplication w/ non-square qobj.dims Checks for regression of #331. """ data = np.array([[0, 1], [1, 0]]) q1 = Qobj(data) q1.dims[0].append(1) q2 = Qobj(data) assert_equal((q1 * q2).dims, [[2, 1], [2]]) assert_equal((q2 * q1.dag()).dims, [[2], [2, 1]]) # Note that this is [[2], [2]] instead of [[2, 1], [2, 1]], # as matching dimensions of 1 are implicitly partial traced out. # (See #331.) assert_equal((q1 * q2 * q1.dag()).dims, [[2], [2]]) # Because of the above, we also need to check for extra indices # that aren't of length 1. q1 = Qobj([[ 1.+0.j, 0.+0.j], [ 0.+0.j, 1.+0.j], [ 0.+0.j, 1.+0.j], [ 1.+0.j, 0.+0.j], [ 0.+0.j, 0.-1.j], [ 0.+1.j, 0.+0.j], [ 1.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j] ], dims=[[4, 2], [2]]) assert_equal((q1 * q2 * q1.dag()).dims, [[4, 2], [4, 2]])
def test_QobjMulNonsquareDims(): """ Qobj: multiplication w/ non-square qobj.dims Checks for regression of #331. """ data = np.array([[0, 1], [1, 0]]) q1 = Qobj(data) q1.dims[0].append(1) q2 = Qobj(data) assert_equal((q1 * q2).dims, [[2, 1], [2]]) assert_equal((q2 * q1.dag()).dims, [[2], [2, 1]]) # Note that this is [[2], [2]] instead of [[2, 1], [2, 1]], # as matching dimensions of 1 are implicitly partial traced out. # (See #331.) assert_equal((q1 * q2 * q1.dag()).dims, [[2], [2]]) # Because of the above, we also need to check for extra indices # that aren't of length 1. q1 = Qobj([[ 1.+0.j, 0.+0.j], [ 0.+0.j, 1.+0.j], [ 0.+0.j, 1.+0.j], [ 1.+0.j, 0.+0.j], [ 0.+0.j, 0.-1.j], [ 0.+1.j, 0.+0.j], [ 1.+0.j, 0.+0.j], [ 0.+0.j, -1.+0.j] ], dims=[[4, 2], [2]]) assert_equal((q1 * q2 * q1.dag()).dims, [[4, 2], [4, 2]])
def propagator_steadystate(U): """Find the steady state for successive applications of the propagator :math:`U`. Parameters ---------- U : qobj Operator representing the propagator. Returns ------- a : qobj Instance representing the steady-state density matrix. """ evals, evecs = la.eig(U.full()) ev_min, ev_idx = _get_min_and_index(abs(evals - 1.0)) evecs = evecs.T rho = Qobj(vec2mat(evecs[ev_idx]), dims=U.dims[0]) rho = rho * (1.0 / rho.tr()) rho = 0.5 * (rho + rho.dag()) # make sure rho is herm return rho
def propagator_steadystate(U): """Find the steady state for successive applications of the propagator :math:`U`. Parameters ---------- U : qobj Operator representing the propagator. Returns ------- a : qobj Instance representing the steady-state density matrix. """ evals, evecs = la.eig(U.full()) ev_min, ev_idx = _get_min_and_index(abs(evals - 1.0)) evecs = evecs.T rho = Qobj(vec2mat(evecs[ev_idx]), dims=U.dims[0]) rho = rho * (1.0 / rho.tr()) rho = 0.5 * (rho + rho.dag()) # make sure rho is herm return rho
def test_QobjDagger(): "Qobj adjoint (dagger)" data = _random_not_singular(5) A = Qobj(data) B = A.dag() assert np.all(B.data.todense() - np.matrix(data.conj().T) == 0) assert A.isherm == B.isherm assert A.type == B.type assert A.superrep == B.superrep
def test_QobjDagger(): "Qobj adjoint (dagger)" data = _random_not_singular(5) A = Qobj(data) B = A.dag() assert_(np.all(B.data.todense() - np.matrix(data.conj().T) == 0)) assert_equal(A.isherm, B.isherm) assert_equal(A.type, B.type) assert_equal(A.superrep, B.superrep)
def test_QobjDagger(): "Qobj adjoint (dagger)" data = np.random.random((5, 5)) + 1j * np.random.random((5, 5)) - (0.5 + 0.5j) A = Qobj(data) B = A.dag() assert_(np.all(B.data.todense() - np.matrix(data.conj().T) == 0)) assert_equal(A.isherm, B.isherm) assert_equal(A.type, B.type) assert_equal(A.superrep, B.superrep)
def test_QobjDagger(): "Qobj adjoint (dagger)" data = np.random.random( (5, 5)) + 1j * np.random.random((5, 5)) - (0.5 + 0.5j) A = Qobj(data) B = A.dag() assert_(np.all(B.data.todense() - np.matrix(data.conj().T) == 0)) assert_equal(A.isherm, B.isherm) assert_equal(A.type, B.type) assert_equal(A.superrep, B.superrep)
def steadystate_nonlinear(L_func, rho0, args={}, maxiter=10, random_initial_state=False, tol=1e-6, itertol=1e-5, use_umfpack=True, verbose=False): """ Steady state for the evolution subject to the nonlinear Liouvillian (which depends on the density matrix). .. note:: Experimental. Not at all certain that the inverse power method works for state-dependent Liouvillian operators. """ use_solver(assumeSortedIndices=True, useUmfpack=use_umfpack) if random_initial_state: rhoss = rand_dm(rho0.shape[0], 1.0, dims=rho0.dims) elif isket(rho0): rhoss = ket2dm(rho0) else: rhoss = Qobj(rho0) v = mat2vec(rhoss.full()) n = prod(rhoss.shape) tr_vec = sp.eye(rhoss.shape[0], rhoss.shape[0], format='coo') tr_vec = tr_vec.reshape((1, n)) it = 0 while it < maxiter: L = L_func(rhoss, args) L = L.data.tocsc() - (tol**2) * sp.eye(n, n, format='csc') L.sort_indices() v = spsolve(L, v, use_umfpack=use_umfpack) v = v / la.norm(v, np.inf) data = v / sum(tr_vec.dot(v)) data = reshape(data, (rhoss.shape[0], rhoss.shape[1])).T rhoss.data = sp.csr_matrix(data) it += 1 if la.norm(L * v, np.inf) <= tol: break if it >= maxiter: raise ValueError('Failed to find steady state after ' + str(maxiter) + ' iterations') rhoss = 0.5 * (rhoss + rhoss.dag()) return rhoss.tidyup() if qset.auto_tidyup else rhoss
def rand_herm(N, density=0.75, dims=None): """Creates a random NxN sparse Hermitian quantum object. Uses :math:`H=X+X^{+}` where :math:`X` is a randomly generated quantum operator with a given `density`. Parameters ---------- N : int Shape of output quantum operator. density : float Density between [0,1] of output Hermitian operator. dims : list Dimensions of quantum object. Used for specifying tensor structure. Default is dims=[[N],[N]]. Returns ------- oper : qobj NxN Hermitian quantum operator. """ if dims: _check_dims(dims, N, N) # to get appropriate density of output # Hermitian operator must convert via: herm_density = 2.0 * arcsin(density) / pi X = sp.rand(N, N, herm_density, format='csr') X.data = X.data - 0.5 Y = X.copy() Y.data = 1.0j * np.random.random(len(X.data)) - (0.5 + 0.5j) X = X + Y X.sort_indices() X = Qobj(X) if dims: return Qobj((X + X.dag()) / 2.0, dims=dims, shape=[N, N]) else: return Qobj((X + X.dag()) / 2.0)
def rand_herm(N, density=0.75, dims=None): """Creates a random NxN sparse Hermitian quantum object. Uses :math:`H=X+X^{+}` where :math:`X` is a randomly generated quantum operator with a given `density`. Parameters ---------- N : int Shape of output quantum operator. density : float Density between [0,1] of output Hermitian operator. dims : list Dimensions of quantum object. Used for specifying tensor structure. Default is dims=[[N],[N]]. Returns ------- oper : qobj NxN Hermitian quantum operator. """ if dims: _check_dims(dims, N, N) # to get appropriate density of output # Hermitian operator must convert via: herm_density = 2.0 * arcsin(density) / pi X = sp.rand(N, N, herm_density, format='csr') X.data = X.data - 0.5 Y = X.copy() Y.data = 1.0j * np.random.random(len(X.data)) - (0.5 + 0.5j) X = X + Y X.sort_indices() X = Qobj(X) if dims: return Qobj((X + X.dag()) / 2.0, dims=dims, shape=[N, N]) else: return Qobj((X + X.dag()) / 2.0)
def steadystate_nonlinear(L_func, rho0, args={}, maxiter=10, random_initial_state=False, tol=1e-6, itertol=1e-5, use_umfpack=True, verbose=False): """ Steady state for the evolution subject to the nonlinear Liouvillian (which depends on the density matrix). .. note:: Experimental. Not at all certain that the inverse power method works for state-dependent Liouvillian operators. """ use_solver(assumeSortedIndices=True, useUmfpack=use_umfpack) if random_initial_state: rhoss = rand_dm(rho0.shape[0], 1.0, dims=rho0.dims) elif isket(rho0): rhoss = ket2dm(rho0) else: rhoss = Qobj(rho0) v = mat2vec(rhoss.full()) n = prod(rhoss.shape) tr_vec = sp.eye(rhoss.shape[0], rhoss.shape[0], format='coo') tr_vec = tr_vec.reshape((1, n)) it = 0 while it < maxiter: L = L_func(rhoss, args) L = L.data.tocsc() - (tol ** 2) * sp.eye(n, n, format='csc') L.sort_indices() v = spsolve(L, v, use_umfpack=use_umfpack) v = v / la.norm(v, np.inf) data = v / sum(tr_vec.dot(v)) data = reshape(data, (rhoss.shape[0], rhoss.shape[1])).T rhoss.data = sp.csr_matrix(data) it += 1 if la.norm(L * v, np.inf) <= tol: break if it >= maxiter: raise ValueError('Failed to find steady state after ' + str(maxiter) + ' iterations') rhoss = 0.5 * (rhoss + rhoss.dag()) return rhoss.tidyup() if qset.auto_tidyup else rhoss
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_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)