def sprepost(A, B): """Superoperator formed from pre-multiplication by operator A and post- multiplication of operator B. Parameters ---------- A : Qobj Quantum operator for pre-multiplication. B : Qobj Quantum operator for post-multiplication. Returns -------- super : Qobj Superoperator formed from input quantum objects. """ dims = [[_drop_projected_dims(A.dims[0]), _drop_projected_dims(B.dims[1])], [_drop_projected_dims(A.dims[1]), _drop_projected_dims(B.dims[0])]] data = zcsr_kron(B.data.T.tocsr(), A.data) return Qobj(data, dims=dims, superrep='super')
def spre(A): """Superoperator formed from pre-multiplication by operator A. Parameters ---------- A : qobj Quantum operator for pre-multiplication. Returns -------- super :qobj Superoperator formed from input quantum object. """ if not isinstance(A, Qobj): raise TypeError('Input is not a quantum object') if not A.isoper: raise TypeError('Input is not a quantum operator') S = Qobj(isherm=A.isherm, superrep='super') S.dims = [[A.dims[0], A.dims[1]], [A.dims[0], A.dims[1]]] S.data = zcsr_kron(sp.identity(np.prod(A.shape[1]), dtype=complex, format='csr'), A.data) return S
def _pseudo_inverse_sparse(L, rhoss, w=None, **pseudo_args): """ Internal function for computing the pseudo inverse of an Liouvillian using sparse matrix methods. See pseudo_inverse for details. """ 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) P = zcsr_kron(rhoss_vec.data, tr_op_vec.data.T.tocsr()) I = sp.eye(N*N, N*N, format='csr') Q = I - P if w is None: L = 1.0j*(1e-15)*spre(tr_op) + L else: if w != 0.0: L = 1.0j*w*spre(tr_op) + L else: L = 1.0j*(1e-15)*spre(tr_op) + L if pseudo_args['use_rcm']: perm = reverse_cuthill_mckee(L.data) A = sp_permute(L.data, perm, perm, 'csr') Q = sp_permute(Q, perm, perm, 'csr') else: if not settings.has_mkl: A = L.data.tocsc() A.sort_indices() if pseudo_args['method'] == 'splu': if settings.has_mkl: A = L.data.tocsr() A.sort_indices() LIQ = mkl_spsolve(A,Q.toarray()) else: lu = sp.linalg.splu(A, permc_spec=pseudo_args['permc_spec'], diag_pivot_thresh=pseudo_args['diag_pivot_thresh'], options=dict(ILU_MILU=pseudo_args['ILU_MILU'])) LIQ = lu.solve(Q.toarray()) elif pseudo_args['method'] == 'spilu': lu = sp.linalg.spilu(A, permc_spec=pseudo_args['permc_spec'], fill_factor=pseudo_args['fill_factor'], drop_tol=pseudo_args['drop_tol']) LIQ = lu.solve(Q.toarray()) else: raise ValueError("unsupported method '%s'" % method) R = sp.csr_matrix(Q * LIQ) if pseudo_args['use_rcm']: rev_perm = np.argsort(perm) R = sp_permute(R, rev_perm, rev_perm, 'csr') return Qobj(R, dims=L.dims)
def liouvillian(H, c_ops=[], data_only=False, chi=None): """Assembles the Liouvillian superoperator from a Hamiltonian and a ``list`` of collapse operators. Like liouvillian, but with an experimental implementation which avoids creating extra Qobj instances, which can be advantageous for large systems. Parameters ---------- H : qobj System Hamiltonian. c_ops : array_like A ``list`` or ``array`` of collapse operators. Returns ------- L : qobj Liouvillian superoperator. """ if chi and len(chi) != len(c_ops): raise ValueError('chi must be a list with same length as c_ops') if H is not None: if H.isoper: op_dims = H.dims op_shape = H.shape elif H.issuper: op_dims = H.dims[0] op_shape = [np.prod(op_dims[0]), np.prod(op_dims[0])] else: raise TypeError("Invalid type for Hamiltonian.") else: # no hamiltonian given, pick system size from a collapse operator if isinstance(c_ops, list) and len(c_ops) > 0: c = c_ops[0] if c.isoper: op_dims = c.dims op_shape = c.shape elif c.issuper: op_dims = c.dims[0] op_shape = [np.prod(op_dims[0]), np.prod(op_dims[0])] else: raise TypeError("Invalid type for collapse operator.") else: raise TypeError("Either H or c_ops must be given.") sop_dims = [[op_dims[0], op_dims[0]], [op_dims[1], op_dims[1]]] sop_shape = [np.prod(op_dims), np.prod(op_dims)] spI = sp.identity(op_shape[0], format='csr', dtype=complex) if H: if H.isoper: Ht = H.data.T.tocsr() data = -1j * zcsr_kron(spI, H.data) data += 1j * zcsr_kron(Ht, spI) else: data = H.data else: data = sp.csr_matrix((sop_shape[0], sop_shape[1]), dtype=complex) for idx, c_op in enumerate(c_ops): if c_op.issuper: data = data + c_op.data else: cd = c_op.data.T.conj().tocsr() c = c_op.data # Here we call _csr_kron directly as we can avoid creating # another sparse matrix by passing c.data.conj() if chi: data = data + np.exp(1j * chi[idx]) * \ _csr_kron(c.data.conj(), c.indices, c.indptr, c.shape[0], c.shape[1], c.data, c.indices, c.indptr, c.shape[0], c.shape[1]) else: data = data + _csr_kron(c.data.conj(), c.indices, c.indptr, c.shape[0], c.shape[1], c.data, c.indices, c.indptr, c.shape[0], c.shape[1]) cdc = cd * c cdct = cdc.T.tocsr() data = data - 0.5 * zcsr_kron(spI, cdc) data = data - 0.5 * zcsr_kron(cdct, spI) if data_only: return data else: L = Qobj() L.dims = sop_dims L.data = data L.isherm = False L.superrep = 'super' return L
def tensor(*args): """Calculates the tensor product of input operators. Parameters ---------- args : array_like ``list`` or ``array`` of quantum objects for tensor product. Returns ------- obj : qobj A composite quantum object. Examples -------- >>> tensor([sigmax(), sigmax()]) Quantum object: dims = [[2, 2], [2, 2]], \ shape = [4, 4], type = oper, isHerm = True Qobj data = [[ 0.+0.j 0.+0.j 0.+0.j 1.+0.j] [ 0.+0.j 0.+0.j 1.+0.j 0.+0.j] [ 0.+0.j 1.+0.j 0.+0.j 0.+0.j] [ 1.+0.j 0.+0.j 0.+0.j 0.+0.j]] """ if not args: raise TypeError("Requires at least one input argument") if len(args) == 1 and isinstance(args[0], (list, np.ndarray)): # this is the case when tensor is called on the form: # tensor([q1, q2, q3, ...]) qlist = args[0] elif len(args) == 1 and isinstance(args[0], Qobj): # tensor is called with a single Qobj as an argument, do nothing return args[0] else: # this is the case when tensor is called on the form: # tensor(q1, q2, q3, ...) qlist = args if not all([isinstance(q, Qobj) for q in qlist]): # raise error if one of the inputs is not a quantum object raise TypeError("One of inputs is not a quantum object") out = Qobj() if qlist[0].issuper: out.superrep = qlist[0].superrep if not all([q.superrep == out.superrep for q in qlist]): raise TypeError("In tensor products of superroperators, all must" + "have the same representation") out.isherm = True for n, q in enumerate(qlist): if n == 0: out.data = q.data out.dims = q.dims else: out.data = zcsr_kron(out.data, q.data) out.dims = [out.dims[0] + q.dims[0], out.dims[1] + q.dims[1]] out.isherm = out.isherm and q.isherm if not out.isherm: out._isherm = None return out.tidyup() if qutip.settings.auto_tidyup else out