def test_ComplexSuperApply(self): """ Superoperator: Efficient numerics and reference return same result, acting on non-composite system """ rho_list = list(map(rand_dm, [2, 3, 2, 3, 2])) rho_input = tensor(rho_list) superop = kraus_to_super(rand_kraus_map(3)) analytic_result = rho_list analytic_result[1] = Qobj(vec2mat(superop.data.todense() * mat2vec(analytic_result[1].data.todense()))) analytic_result[3] = Qobj(vec2mat(superop.data.todense() * mat2vec(analytic_result[3].data.todense()))) analytic_result = tensor(analytic_result) naive_result = subsystem_apply(rho_input, superop, [False, True, False, True, False], reference=True) naive_diff = (analytic_result - naive_result).data.todense() assert_(norm(naive_diff) < 1e-12) efficient_result = subsystem_apply(rho_input, superop, [False, True, False, True, False]) efficient_diff = (efficient_result - analytic_result).data.todense() assert_(norm(efficient_diff) < 1e-12)
def _steadystate_svd_dense(L, ss_args): """ Find the steady state(s) of an open quantum system by solving for the nullspace of the Liouvillian. """ atol = 1e-12 rtol = 1e-12 if settings.debug: print('Starting SVD solver...') u, s, vh = svd(L.full(), full_matrices=False) tol = max(atol, rtol * s[0]) nnz = (s >= tol).sum() ns = vh[nnz:].conj().T if ss_args['all_states']: rhoss_list = [] for n in range(ns.shape[1]): rhoss = Qobj(vec2mat(ns[:, n]), dims=L.dims[0]) rhoss_list.append(rhoss / rhoss.tr()) return rhoss_list else: rhoss = Qobj(vec2mat(ns[:, 0]), dims=L.dims[0]) return rhoss / rhoss.tr()
def test_ComplexSuperApply(self): """ Superoperator: Efficient numerics and reference return same result, acting on non-composite system """ tol = 1e-10 rho_list = list(map(rand_dm, [2, 3, 2, 3, 2])) rho_input = tensor(rho_list) superop = kraus_to_super(rand_kraus_map(3)) analytic_result = rho_list analytic_result[1] = Qobj( vec2mat(superop.full() @ mat2vec(analytic_result[1].full()))) analytic_result[3] = Qobj( vec2mat(superop.full() @ mat2vec(analytic_result[3].full()))) analytic_result = tensor(analytic_result) naive_result = subsystem_apply(rho_input, superop, [False, True, False, True, False], reference=True) naive_diff = (analytic_result - naive_result).full() naive_diff_norm = norm(naive_diff) assert_(naive_diff_norm < tol, msg="ComplexSuper: naive_diff_norm {} " "is beyond tolerance {}".format(naive_diff_norm, tol)) efficient_result = subsystem_apply(rho_input, superop, [False, True, False, True, False]) efficient_diff = (efficient_result - analytic_result).full() efficient_diff_norm = norm(efficient_diff) assert_(efficient_diff_norm < tol, msg="ComplexSuper: efficient_diff_norm {} " "is beyond tolerance {}".format(efficient_diff_norm, tol))
def _steadystate_svd_dense(L, ss_args): """ Find the steady state(s) of an open quantum system by solving for the nullspace of the Liouvillian. """ ss_args['info'].pop('weight', None) atol = 1e-12 rtol = 1e-12 if settings.debug: logger.debug('Starting SVD solver.') _svd_start = time.time() u, s, vh = svd(L.full(), full_matrices=False) tol = max(atol, rtol * s[0]) nnz = (s >= tol).sum() ns = vh[nnz:].conj().T _svd_end = time.time() ss_args['info']['solution_time'] = _svd_end - _svd_start if ss_args['all_states']: rhoss_list = [] for n in range(ns.shape[1]): rhoss = Qobj(vec2mat(ns[:, n]), dims=L.dims[0]) rhoss_list.append(rhoss / rhoss.tr()) if ss_args['return_info']: return rhoss_list, ss_args['info'] else: if ss_args['return_info']: return rhoss_list, ss_args['info'] else: return rhoss_list else: rhoss = Qobj(vec2mat(ns[:, 0]), dims=L.dims[0]) return rhoss / rhoss.tr()
def test_ComplexSuperApply(self): """ Superoperator: Efficient numerics and reference return same result, acting on non-composite system """ rho_list = list(map(rand_dm, [2, 3, 2, 3, 2])) rho_input = tensor(rho_list) superop = kraus_to_super(rand_kraus_map(3)) analytic_result = rho_list analytic_result[1] = Qobj( vec2mat(superop.data.todense() * mat2vec(analytic_result[1].data.todense()))) analytic_result[3] = Qobj( vec2mat(superop.data.todense() * mat2vec(analytic_result[3].data.todense()))) analytic_result = tensor(analytic_result) naive_result = subsystem_apply(rho_input, superop, [False, True, False, True, False], reference=True) naive_diff = (analytic_result - naive_result).data.todense() assert_(norm(naive_diff) < 1e-12) efficient_result = subsystem_apply(rho_input, superop, [False, True, False, True, False]) efficient_diff = (efficient_result - analytic_result).data.todense() assert_(norm(efficient_diff) < 1e-12)
def _steadystate_svd_dense(L, ss_args): """ Find the steady state(s) of an open quantum system by solving for the nullspace of the Liouvillian. """ ss_args['info'].pop('weight', None) atol = 1e-12 rtol = 1e-12 if settings.debug: logger.debug('Starting SVD solver.') _svd_start = time.time() u, s, vh = svd(L.full(), full_matrices=False) tol = max(atol, rtol * s[0]) nnz = (s >= tol).sum() ns = vh[nnz:].conj().T _svd_end = time.time() ss_args['info']['solution_time'] = _svd_end-_svd_start if ss_args['all_states']: rhoss_list = [] for n in range(ns.shape[1]): rhoss = Qobj(vec2mat(ns[:, n]), dims=L.dims[0]) rhoss_list.append(rhoss / rhoss.tr()) if ss_args['return_info']: return rhoss_list, ss_args['info'] else: if ss_args['return_info']: return rhoss_list, ss_args['info'] else: return rhoss_list else: rhoss = Qobj(vec2mat(ns[:, 0]), dims=L.dims[0]) return rhoss / rhoss.tr()
def gradient_CFI(self, M): ''' Input: 1) M: TYPE: list of Qobj (matrix) DESCRIPTION: merasurement. It takes the form [M1,M2,...], where M1, M2 ... are matrices and satisfies M1+M2+... = identity matrix. Output: 1) updated values of self.control_coefficients. Notice: To run this function, the function 'propagation_single()' has to run first. ''' num = len(self.times) dH0 = 1.j * Qobj(liouvillian(self.Hamiltonian_derivative[0]).full()) dim = self.freeHamiltonian.dims[0][0] dt = self.times[1] - self.times[0] Hc_coeff = self.control_coefficients D = self.propagator rhoT_vec = self.rho[num-1] drhoT_vec = self.rho_derivative[num-1] rhoT = Qobj(vec2mat(rhoT_vec.full())) drhoT = Qobj(vec2mat(drhoT_vec.full())) L1 = Qobj(np.array([[0. for i in range(0,dim)] for k in range(0,dim)])) L2 = Qobj(np.array([[0. for i in range(0,dim)] for k in range(0,dim)])) for mi in range(0, len(M)): ptemp = (rhoT * M[mi]).tr() dptemp = (drhoT * M[mi]).tr() if ptemp != 0: L1 += (dptemp / ptemp) * M[mi] L2 += ((dptemp / ptemp)**2) * M[mi] for ki in range(0, len(self.control_Hamiltonian)): Hk = 1.j * Qobj(liouvillian(self.control_Hamiltonian[ki]).full()) Hc_ki = Hc_coeff[ki] for ti in range(0,num): Mj1 = 1.j * D[ti+1][num-1] * Hk * self.rho[ti] Mj2 = Qobj(np.zeros((dim*dim, 1))) for ri in range(0, ti+1): Mj2 += D[ti+1][num-1] * Hk * D[ri+1][ti] * dH0 * self.rho[ri] Mj3 = Qobj(np.zeros((dim*dim, 1))) for ri in range(ti+1, num): Mj3 += D[ri+1][num-1] * dH0 * D[ti+1][ri] * Hk * self.rho[ti] Mj1mat = Qobj(vec2mat(Mj1.full())) Mj2mat = Qobj(vec2mat(Mj2.full())) Mj3mat = Qobj(vec2mat(Mj3.full())) term1 = dt * (L2 * Mj1mat).tr() term2 = -2 * (dt * dt) * (L1 * (Mj2mat+Mj3mat)).tr() delta = np.real(term1 + term2) Hc_ki[ti] += Hc_ki[ti] + self.epsilon * delta Hc_coeff[ki] = Hc_ki self.control_coefficients = Hc_coeff
def _steadystate_eigen(L, ss_args): """ Internal function for solving the steady state problem by finding the eigenvector corresponding to the zero eigenvalue of the Liouvillian using ARPACK. """ if settings.debug: print('Starting Eigen solver...') dims = L.dims[0] shape = prod(dims[0]) L = L.data.tocsc() if ss_args['use_rcm']: if settings.debug: old_band = sp_bandwidth(L)[0] print('Original bandwidth:', old_band) perm = reverse_cuthill_mckee(L) rev_perm = np.argsort(perm) L = sp_permute(L, perm, perm, 'csc') if settings.debug: rcm_band = sp_bandwidth(L)[0] print('RCM bandwidth:', rcm_band) print('Bandwidth reduction factor:', round(old_band/rcm_band, 1)) eigval, eigvec = eigs(L, k=1, sigma=1e-15, tol=ss_args['tol'], which='LM', maxiter=ss_args['maxiter']) if ss_args['use_rcm']: eigvec = eigvec[np.ix_(rev_perm,)] data = vec2mat(eigvec) data = 0.5 * (data + data.conj().T) out = Qobj(data, dims=dims, isherm=True) return out/out.tr()
def qpt(U, op_basis_list): """ Calculate the quantum process tomography chi matrix for a given (possibly nonunitary) transformation matrix U, which transforms a density matrix in vector form according to: vec(rho) = U * vec(rho0) or rho = vec2mat(U * mat2vec(rho0)) U can be calculated for an open quantum system using the QuTiP propagator function. """ E_ops = [] # loop over all index permutations for inds in index_permutations([len(op_list) for op_list in op_basis_list]): # loop over all composite systems E_op_list = [op_basis_list[k][inds[k]] for k in range(len(op_basis_list))] E_ops.append(tensor(E_op_list)) EE_ops = [spre(E1) * spost(E2.dag()) for E1 in E_ops for E2 in E_ops] M = hstack([mat2vec(EE.full()) for EE in EE_ops]) Uvec = mat2vec(U.full()) chi_vec = la.solve(M, Uvec) return vec2mat(chi_vec)
def _smepdpsolve_single_trajectory(L, dt, tlist, N_store, N_substeps, rho_t, c_ops, e_ops, data): """ Internal function. """ states_list = [] rho_t = np.copy(rho_t) prng = RandomState() # todo: seed it r_jump, r_op = prng.rand(2) jump_times = [] jump_op_idx = [] for t_idx, t in enumerate(tlist): if e_ops: for e_idx, e in enumerate(e_ops): data.expect[e_idx, t_idx] += expect_rho_vec(e, rho_t) else: states_list.append(Qobj(vec2mat(rho_t))) for j in range(N_substeps): if expect_rho_vec(d_op, sigma_t) < r_jump: # jump occurs p = np.array([rho_expect(c.dag() * c, rho_t) for c in c_ops]) p = np.cumsum(p / np.sum(p)) n = np.where(p >= r_op)[0][0] # apply jump rho_t = c_ops[n] * psi_t * c_ops[n].dag() rho_t /= rho_expect(c.dag() * c, rho_t) rho_t = np.copy(rho_t) # store info about jump jump_times.append(tlist[t_idx] + dt * j) jump_op_idx.append(n) # get new random numbers for next jump r_jump, r_op = prng.rand(2) # deterministic evolution wihtout correction for norm decay dsigma_t = spmv(L.data.data, L.data.indices, L.data.indptr, sigma_t) * dt # deterministic evolution with correction for norm decay drho_t = spmv(L.data.data, L.data.indices, L.data.indptr, rho_t) * dt rho_t += drho_t # increment density matrices sigma_t += dsigma_t rho_t += drho_t return states_list, jump_times, jump_op_idx
def _steadystate_direct_dense(L, ss_args): """ Direct solver that use numpy dense matrices. Suitable for small system, with a few states. """ if settings.debug: logger.debug('Starting direct dense solver.') dims = L.dims[0] n = int(np.sqrt(L.shape[0])) b = np.zeros(n**2) b[0] = ss_args['weight'] L = L.data.todense() L[0, :] = np.diag(ss_args['weight'] * np.ones(n)).reshape((1, n**2)) _dense_start = time.time() v = np.linalg.solve(L, b) _dense_end = time.time() ss_args['info']['solution_time'] = _dense_end - _dense_start if ss_args['return_info']: ss_args['info']['residual_norm'] = la.norm(b - L * v, np.inf) data = vec2mat(v) data = 0.5 * (data + data.conj().T) return Qobj(data, dims=dims, isherm=True)
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 _subsystem_apply_reference(state, channel, mask): if isket(state): state = ket2dm(state) if isoper(channel): full_oper = tensor([channel if mask[j] else qeye(state.dims[0][j]) for j in range(len(state.dims[0]))]) return full_oper * state * full_oper.dag() else: # Go to Choi, then Kraus # chan_mat = array(channel.data.todense()) choi_matrix = super_to_choi(channel) vals, vecs = eig(choi_matrix.full()) vecs = list(map(array, zip(*vecs))) kraus_list = [sqrt(vals[j]) * vec2mat(vecs[j]) for j in range(len(vals))] # Kraus operators to be padded with identities: k_qubit_kraus_list = product(kraus_list, repeat=sum(mask)) rho_out = Qobj(inpt=zeros(state.shape), dims=state.dims) for operator_iter in k_qubit_kraus_list: operator_iter = iter(operator_iter) op_iter_list = [next(operator_iter).conj().T if mask[j] else qeye(state.dims[0][j]) for j in range(len(state.dims[0]))] full_oper = tensor(list(map(Qobj, op_iter_list))) rho_out = rho_out + full_oper * state * full_oper.dag() return Qobj(rho_out)
def _steadystate_direct_dense(L, ss_args): """ Direct solver that use numpy dense matrices. Suitable for small system, with a few states. """ if settings.debug: logger.debug('Starting direct dense solver.') dims = L.dims[0] n = int(np.sqrt(L.shape[0])) b = np.zeros(n ** 2) b[0] = ss_args['weight'] L = L.data.todense() L[0, :] = np.diag(ss_args['weight']*np.ones(n)).reshape((1, n ** 2)) _dense_start = time.time() v = np.linalg.solve(L, b) _dense_end = time.time() ss_args['info']['solution_time'] = _dense_end-_dense_start if ss_args['return_info']: ss_args['info']['residual_norm'] = la.norm(b - L*v, np.inf) data = vec2mat(v) data = 0.5 * (data + data.conj().T) return Qobj(data, dims=dims, isherm=True)
def _subsystem_apply_reference(state, channel, mask): if isket(state): state = ket2dm(state) if isoper(channel): full_oper = tensor([ channel if mask[j] else qeye(state.dims[0][j]) for j in range(len(state.dims[0])) ]) return full_oper * state * full_oper.dag() else: # Go to Choi, then Kraus # chan_mat = array(channel.data.todense()) choi_matrix = super_to_choi(channel) vals, vecs = eig(choi_matrix.full()) vecs = list(map(array, zip(*vecs))) kraus_list = [ sqrt(vals[j]) * vec2mat(vecs[j]) for j in range(len(vals)) ] # Kraus operators to be padded with identities: k_qubit_kraus_list = product(kraus_list, repeat=sum(mask)) rho_out = Qobj(inpt=zeros(state.shape), dims=state.dims) for operator_iter in k_qubit_kraus_list: operator_iter = iter(operator_iter) op_iter_list = [ next(operator_iter) if mask[j] else qeye(state.dims[0][j]) for j in range(len(state.dims[0])) ] full_oper = tensor(list(map(Qobj, op_iter_list))) rho_out = rho_out + full_oper * state * full_oper.dag() return Qobj(rho_out)
def _smesolve_single_trajectory(L, dt, tlist, N_store, N_substeps, rho_t, A_ops, e_ops, data, rhs, d1, d2): """ Internal function. See smesolve. """ dW = np.sqrt(dt) * scipy.randn(len(A_ops), N_store, N_substeps) states_list = [] for t_idx, t in enumerate(tlist): if e_ops: for e_idx, e in enumerate(e_ops): # XXX: need to keep hilbert space structure data.expect[e_idx, t_idx] += expect(e, Qobj(vec2mat(rho_t))) else: states_list.append(Qobj(rho_t)) # dito for j in range(N_substeps): drho_t = spmv( L.data.data, L.data.indices, L.data.indptr, rho_t) * dt for a_idx, A in enumerate(A_ops): drho_t += rhs( L.data, rho_t, A, dt, dW[a_idx, t_idx, j], d1, d2) rho_t += drho_t return states_list
def np_to_kraus(U): from scipy.linalg import eig from qutip.superoperator import vec2mat vals, vecs = eig(U) vecs = [np.array(_) for _ in zip(*vecs)] return [np.sqrt(val) * vec2mat(vec) for val, vec in zip(vals, vecs)]
def _smesolve_single_trajectory(L, dt, tlist, N_store, N_substeps, rho_t, A_ops, e_ops, data, rhs, d1, d2): """ Internal function. See smesolve. """ dW = np.sqrt(dt) * scipy.randn(len(A_ops), N_store, N_substeps) states_list = [] for t_idx, t in enumerate(tlist): if e_ops: for e_idx, e in enumerate(e_ops): # XXX: need to keep hilbert space structure data.expect[e_idx, t_idx] += expect(e, Qobj(vec2mat(rho_t))) else: states_list.append(Qobj(rho_t)) # dito for j in range(N_substeps): drho_t = spmv(L.data.data, L.data.indices, L.data.indptr, rho_t) * dt for a_idx, A in enumerate(A_ops): drho_t += rhs(L.data, rho_t, A, dt, dW[a_idx, t_idx, j], d1, d2) rho_t += drho_t return states_list
def _steadystate_direct_sparse(L, ss_args): """ Direct solver that uses scipy sparse matrices """ if settings.debug: print('Starting direct solver...') dims = L.dims[0] weight = np.abs(L.data.data.max()) n = prod(L.dims[0][0]) b = np.zeros((n ** 2, 1), dtype=complex) b[0, 0] = weight L = L.data + sp.csr_matrix( (weight*np.ones(n), (np.zeros(n), [nn * (n + 1) for nn in range(n)])), shape=(n ** 2, n ** 2)) L.sort_indices() use_solver(assumeSortedIndices=True, useUmfpack=ss_args['use_umfpack']) if ss_args['use_rcm']: perm = symrcm(L) L = sp_permute(L, perm, perm) b = b[np.ix_(perm,)] v = spsolve(L, b) if ss_args['use_rcm']: rev_perm = np.argsort(perm) v = v[np.ix_(rev_perm,)] data = vec2mat(v) data = 0.5 * (data + data.conj().T) return Qobj(data, dims=dims, isherm=True)
def gradient_QFI(self): ''' Output: 1) updated values of self.control_coefficients Notice: To run this function, the function 'propagation_single()' has to run first. ''' num = len(self.times) dH0 = 1.j * Qobj(liouvillian(self.Hamiltonian_derivative[0]).full()) rhomat_final = Qobj(vec2mat(self.rho[num - 1].full())) drhomat_final = Qobj(vec2mat(self.rho_derivative[num - 1].full())) SLD_final = CR.SLD(rhomat_final, drhomat_final) dim = self.freeHamiltonian.dims[0][0] dt = self.times[1] - self.times[0] Hc_coeff = self.control_coefficients D = self.propagator for ki in range(0, len(self.control_Hamiltonian)): Hk = 1.j * Qobj(liouvillian(self.control_Hamiltonian[ki]).full()) Hc_ki = Hc_coeff[ki] for ti in range(0, num): Mj1 = 1.j * D[ti + 1][num - 1] * Hk * self.rho[ti] Mj2 = Qobj(np.zeros((dim * dim, 1))) for ri in range(0, ti + 1): Mj2 += D[ti + 1][num - 1] * Hk * D[ri + 1][ti] * dH0 * self.rho[ri] Mj3 = Qobj(np.zeros((dim * dim, 1))) for ri in range(ti + 1, num): Mj3 += D[ri + 1][num - 1] * dH0 * D[ti + 1][ri] * Hk * self.rho[ti] Mj1mat = Qobj(vec2mat(Mj1.full())) Mj2mat = Qobj(vec2mat(Mj2.full())) Mj3mat = Qobj(vec2mat(Mj3.full())) term1 = dt * (SLD_final * SLD_final * Mj1mat).tr() term2 = -2 * (dt * dt) * (SLD_final * (Mj2mat + Mj3mat)).tr() delta = np.real(term1 + term2) Hc_ki[ti] += self.epsilon * delta Hc_coeff[ki] = Hc_ki self.control_coefficients = Hc_coeff
def choi_to_kraus(q_oper): """ Takes a Choi matrix and returns a list of Kraus operators. TODO: Create a new class structure for quantum channels, perhaps as a strict sub-class of Qobj. """ vals, vecs = eig(q_oper.data.todense()) vecs = [array(_) for _ in zip(*vecs)] return [Qobj(inpt=sqrt(val)*vec2mat(vec)) for val, vec in zip(vals, vecs)]
def __call__(self, H, state, dt, c_ops=None, backwards=False, initialize=False): """Evaluation of a single propagation step Args: H (list): A Liouvillian superoperator in qutip's nested-list format, with a scalar value in the place of a time-dependency. For example, ``[L0, [L1, u]]`` for a drift Liouvillian ``L0``, a control Liouvillian ``H1``, and a scalar value ``u`` that is a time-dependent control evaluated for a particular point in time. If `initialize` is False, only the control values are taken into account; any operators are assumed to be identical to the internally cached values of `H` during initialization. state (qutip.Qobj): The density matrix to propagate. The passed value is ignored unless `initialize` is given as True. Otherwise, it is assumed that `state` matches the (internally stored) state that was the result from the previous propagation step. dt (float): The time step over which to propagate c_ops (list or None): An empty list, or None. Since this propagator assumes a full Liouvillian, it cannot be combined with Lindblad operators. backwards (bool): Whether the propagation is forward in time or backward in time. Since the equation of motion for a Liouvillian and conjugate Liouvillian is the same, this parameter has no effect. Instead, for the backward propagation, the conjugate Liouvillian must be passed for `L`. initialize (bool): Whether to (re-)initialize for a new propagation. This caches `H` (except for the control values) and `state` internally. """ # H is really an L, but it's a very bad idea for a subclass not to # follow the interface of the parent (including argument names). # Internally, however, we'll use L instead of H if initialize or self.reentrant: self._initialize(H, state, dt, c_ops, backwards) else: if self.reentrant: self._initialize_integrator(self._y) # only update the control values for i in self._control_indices: self._L_list[i][1] = H[i][1] self._t += dt self._r.integrate(self._t) self._y = self._r.y return qutip.Qobj( dense2D_to_fastcsr_fmode(vec2mat(self._y), state.shape[0], state.shape[1]), dims=state.dims, isherm=True, )
def _smesolve_single_trajectory(L, dt, tlist, N_store, N_substeps, rho_t, A_ops, e_ops, m_ops, data, rhs, d1, d2, d2_len, homogeneous, distribution, args, store_measurement=False, store_states=False, noise=None): """ Internal function. See smesolve. """ if noise is None: if homogeneous: if distribution == 'normal': dW = np.sqrt(dt) * scipy.randn(len(A_ops), N_store, N_substeps, d2_len) else: raise TypeError('Unsupported increment distribution for homogeneous process.') else: if distribution != 'poisson': raise TypeError('Unsupported increment distribution for inhomogeneous process.') dW = np.zeros((len(A_ops), N_store, N_substeps, d2_len)) else: dW = noise states_list = [] measurements = np.zeros((len(tlist), len(m_ops)), dtype=complex) for t_idx, t in enumerate(tlist): if e_ops: for e_idx, e in enumerate(e_ops): s = expect_rho_vec(e.data, rho_t) data.expect[e_idx, t_idx] += s data.ss[e_idx, t_idx] += s ** 2 if store_states or not e_ops: # XXX: need to keep hilbert space structure states_list.append(Qobj(vec2mat(rho_t))) rho_prev = np.copy(rho_t) for j in range(N_substeps): if noise is None and not homogeneous: for a_idx, A in enumerate(A_ops): dw_expect = np.real(cy_expect_rho_vec(A[4], rho_t)) * dt dW[a_idx, t_idx, j, :] = np.random.poisson(dw_expect, d2_len) rho_t = rhs(L.data, rho_t, t + dt * j, A_ops, dt, dW[:, t_idx, j, :], d1, d2, args) if store_measurement: for m_idx, m in enumerate(m_ops): # TODO: allow using more than one increment measurements[t_idx, m_idx] = cy_expect_rho_vec(m.data, rho_prev) * dt * N_substeps + dW[m_idx, t_idx, :, 0].sum() return states_list, dW, measurements
def _smesolve_single_trajectory(L, dt, tlist, N_store, N_substeps, rho_t, A_ops, e_ops, data, rhs, d1, d2, d2_len, homogeneous, distribution, args, store_measurement=False, store_states=False, noise=None): """ Internal function. See smesolve. """ if noise is None: if homogeneous: if distribution == 'normal': dW = np.sqrt(dt) * scipy.randn(len(A_ops), N_store, N_substeps, d2_len) else: raise TypeError('Unsupported increment distribution for homogeneous process.') else: if distribution != 'poisson': raise TypeError('Unsupported increment distribution for inhomogeneous process.') dW = np.zeros((len(A_ops), N_store, N_substeps, d2_len)) else: dW = noise states_list = [] measurements = np.zeros((len(tlist), len(A_ops)), dtype=complex) for t_idx, t in enumerate(tlist): if e_ops: for e_idx, e in enumerate(e_ops): s = expect_rho_vec(e.data, rho_t) data.expect[e_idx, t_idx] += s data.ss[e_idx, t_idx] += s ** 2 if store_states or not e_ops: # XXX: need to keep hilbert space structure states_list.append(Qobj(vec2mat(rho_t))) rho_prev = np.copy(rho_t) for j in range(N_substeps): if noise is None and not homogeneous: for a_idx, A in enumerate(A_ops): dw_expect = np.real(cy_expect_rho_vec(A[4], rho_t)) * dt dW[a_idx, t_idx, j, :] = np.random.poisson(dw_expect, d2_len) rho_t = rhs(L.data, rho_t, t + dt * j, A_ops, dt, dW[:, t_idx, j, :], d1, d2, args) if store_measurement: for a_idx, A in enumerate(A_ops): measurements[t_idx, a_idx] = cy_expect_rho_vec(A[0], rho_prev) * dt * N_substeps + dW[a_idx, t_idx, :, 0].sum() return states_list, dW, measurements
def choi_to_kraus(q_oper): """ Takes a Choi matrix and returns a list of Kraus operators. TODO: Create a new class structure for quantum channels, perhaps as a strict sub-class of Qobj. """ vals, vecs = eig(q_oper.data.todense()) vecs = [array(_) for _ in zip(*vecs)] return [ Qobj(inpt=sqrt(val) * vec2mat(vec)) for val, vec in zip(vals, vecs) ]
def choi_to_kraus(q_oper): """ Takes a Choi matrix and returns a list of Kraus operators. # TODO Create a new class structure for quantum channels, perhaps as a strict sub-class of Qobj. """ vals, vecs = eig(q_oper.data.todense()) vecs = list(map(array, zip(*vecs))) return list( map(lambda x: Qobj(inpt=x), [sqrt(vals[j]) * vec2mat(vecs[j]) for j in range(len(vals))]))
def choi_to_kraus(q_oper): """ Takes a Choi matrix and returns a list of Kraus operators. TODO: Create a new class structure for quantum channels, perhaps as a strict sub-class of Qobj. """ vals, vecs = eig(q_oper.data.todense()) vecs = list(map(array, zip(*vecs))) return list(map(lambda x: Qobj(inpt=x), [sqrt(vals[j]) * vec2mat(vecs[j]) for j in range(len(vals))]))
def choi_to_kraus(q_oper, tol=1e-9): """ Takes a Choi matrix and returns a list of Kraus operators. TODO: Create a new class structure for quantum channels, perhaps as a strict sub-class of Qobj. """ vals, vecs = eig(q_oper.data.todense()) vecs = [array(_) for _ in zip(*vecs)] shape = [np.prod(q_oper.dims[0][i]) for i in range(2)][::-1] return [Qobj(inpt=sqrt(val)*vec2mat(vec, shape=shape), dims=q_oper.dims[0][::-1]) for val, vec in zip(vals, vecs) if abs(val) >= tol]
def _steadystate_iterative(L, ss_args): """ Iterative steady state solver using the LGMRES algorithm and a sparse incomplete LU preconditioner. """ if settings.debug: print('Starting GMRES solver...') dims = L.dims[0] n = prod(L.dims[0][0]) b = np.zeros(n ** 2) b[0] = 1.0 L = L.data.tocsc() + sp.csc_matrix( (1e-1 * np.ones(n), (np.zeros(n), [nn * (n + 1) for nn in range(n)])), shape=(n ** 2, n ** 2)) if ss_args['use_rcm']: if settings.debug: print('Original bandwidth ', sp_bandwidth(L)) perm = symrcm(L) rev_perm = np.argsort(perm) L = sp_permute(L, perm, perm, 'csc') b = b[np.ix_(perm,)] if settings.debug: print('RCM bandwidth ', sp_bandwidth(L)) L.sort_indices() if ss_args['M'] is None and ss_args['use_precond']: M = _iterative_precondition(L, n, ss_args['drop_tol'], ss_args['diag_pivot_thresh'], ss_args['fill_factor']) v, check = gmres(L, b, tol=ss_args['tol'], M=ss_args['M'], maxiter=ss_args['maxiter']) if check > 0: raise Exception("Steadystate solver did not reach tolerance after " + str(check) + " steps.") elif check < 0: raise Exception( "Steadystate solver failed with fatal error: " + str(check) + ".") if ss_args['use_rcm']: v = v[np.ix_(rev_perm,)] data = vec2mat(v) data = 0.5 * (data + data.conj().T) return Qobj(data, dims=dims, isherm=True)
def _steadystate_eigen(L, ss_args): """ Internal function for solving the steady state problem by finding the eigenvector corresponding to the zero eigenvalue of the Liouvillian using ARPACK. """ ss_args['info'].pop('weight', None) if settings.debug: logger.debug('Starting Eigen solver.') dims = L.dims[0] L = L.data.tocsc() if ss_args['use_rcm']: ss_args['info']['perm'].append('rcm') if settings.debug: old_band = sp_bandwidth(L)[0] logger.debug('Original bandwidth: %i' % old_band) perm = sp.csgraph.reverse_cuthill_mckee(L) rev_perm = np.argsort(perm) L = sp_permute(L, perm, perm, 'csc') if settings.debug: rcm_band = sp_bandwidth(L)[0] logger.debug('RCM bandwidth: %i' % rcm_band) logger.debug('Bandwidth reduction factor: %f' % (old_band / rcm_band)) _eigen_start = time.time() eigval, eigvec = eigs(L, k=1, sigma=1e-15, tol=ss_args['tol'], which='LM', maxiter=ss_args['maxiter']) _eigen_end = time.time() ss_args['info']['solution_time'] = _eigen_end - _eigen_start if ss_args['return_info']: ss_args['info']['residual_norm'] = la.norm(L * eigvec, np.inf) if ss_args['use_rcm']: eigvec = eigvec[np.ix_(rev_perm, )] _temp = vec2mat(eigvec) data = dense2D_to_fastcsr_fmode(_temp, _temp.shape[0], _temp.shape[1]) data = 0.5 * (data + data.H) out = Qobj(data, dims=dims, isherm=True) if ss_args['return_info']: return out / out.tr(), ss_args['info'] else: return out / out.tr()
def test_SimpleSuperApply(self): """ Non-composite system, operator on Liouville space. """ rho_3 = rand_dm(3) superop = kraus_to_super(rand_kraus_map(3)) analytic_result = vec2mat(superop.data.todense() * mat2vec(rho_3.data.todense())) naive_result = subsystem_apply(rho_3, superop, [True], reference=True) naive_diff = (analytic_result - naive_result).data.todense() assert_(norm(naive_diff) < 1e-12) efficient_result = subsystem_apply(rho_3, superop, [True]) efficient_diff = (efficient_result - analytic_result).data.todense() assert_(norm(efficient_diff) < 1e-12)
def _steadystate_eigen(L, ss_args): """ Internal function for solving the steady state problem by finding the eigenvector corresponding to the zero eigenvalue of the Liouvillian using ARPACK. """ ss_args['info'].pop('weight', None) if settings.debug: print('Starting Eigen solver...') dims = L.dims[0] shape = prod(dims[0]) L = L.data.tocsc() if ss_args['use_rcm']: ss_args['info']['perm'].append('rcm') if settings.debug: old_band = sp_bandwidth(L)[0] print('Original bandwidth:', old_band) perm = reverse_cuthill_mckee(L) rev_perm = np.argsort(perm) L = sp_permute(L, perm, perm, 'csc') if settings.debug: rcm_band = sp_bandwidth(L)[0] print('RCM bandwidth:', rcm_band) print('Bandwidth reduction factor:', round(old_band / rcm_band, 1)) _eigen_start = time.time() eigval, eigvec = eigs(L, k=1, sigma=1e-15, tol=ss_args['tol'], which='LM', maxiter=ss_args['maxiter']) _eigen_end = time.time() ss_args['info']['solution_time'] = _eigen_end - _eigen_start if ss_args['use_rcm']: eigvec = eigvec[np.ix_(rev_perm, )] data = vec2mat(eigvec) data = 0.5 * (data + data.conj().T) out = Qobj(data, dims=dims, isherm=True) if ss_args['return_info']: return out / out.tr(), ss_args['info'] else: return out / out.tr()
def _steadystate_eigen(L, ss_args): """ Internal function for solving the steady state problem by finding the eigenvector corresponding to the zero eigenvalue of the Liouvillian using ARPACK. """ ss_args['info'].pop('weight', None) if settings.debug: logger.debug('Starting Eigen solver.') dims = L.dims[0] L = L.data.tocsc() if ss_args['use_rcm']: ss_args['info']['perm'].append('rcm') if settings.debug: old_band = sp_bandwidth(L)[0] logger.debug('Original bandwidth: %i' % old_band) perm = reverse_cuthill_mckee(L) rev_perm = np.argsort(perm) L = sp_permute(L, perm, perm, 'csc') if settings.debug: rcm_band = sp_bandwidth(L)[0] logger.debug('RCM bandwidth: %i' % rcm_band) logger.debug('Bandwidth reduction factor: %f' % (old_band/rcm_band)) _eigen_start = time.time() eigval, eigvec = eigs(L, k=1, sigma=1e-15, tol=ss_args['tol'], which='LM', maxiter=ss_args['maxiter']) _eigen_end = time.time() ss_args['info']['solution_time'] = _eigen_end - _eigen_start if ss_args['return_info']: ss_args['info']['residual_norm'] = la.norm(L*eigvec, np.inf) if ss_args['use_rcm']: eigvec = eigvec[np.ix_(rev_perm,)] _temp = vec2mat(eigvec) data = dense2D_to_fastcsr_fmode(_temp, _temp.shape[0], _temp.shape[1]) data = 0.5 * (data + data.H) out = Qobj(data, dims=dims, isherm=True) if ss_args['return_info']: return out/out.tr(), ss_args['info'] else: return out/out.tr()
def _steadystate_power(L, ss_args): """ Inverse power method for steady state solving. """ if settings.debug: print('Starting iterative power method Solver...') tol=ss_args['tol'] maxiter=ss_args['maxiter'] use_solver(assumeSortedIndices=True) rhoss = Qobj() sflag = issuper(L) if sflag: rhoss.dims = L.dims[0] else: rhoss.dims = [L.dims[0], 1] n = prod(rhoss.shape) L = L.data.tocsc() - (tol ** 2) * sp.eye(n, n, format='csc') L.sort_indices() v = mat2vec(rand_dm(rhoss.shape[0], 0.5 / rhoss.shape[0] + 0.5).full()) it = 0 while (la.norm(L * v, np.inf) > tol) and (it < maxiter): v = spsolve(L, v) v = v / la.norm(v, np.inf) it += 1 if it >= maxiter: raise Exception('Failed to find steady state after ' + str(maxiter) + ' iterations') # normalise according to type of problem if sflag: trow = sp.eye(rhoss.shape[0], rhoss.shape[0], format='coo') trow = sp_reshape(trow, (1, n)) data = v / sum(trow.dot(v)) else: data = data / la.norm(v) data = sp.csr_matrix(vec2mat(data)) rhoss.data = 0.5 * (data + data.conj().T) rhoss.isherm = True return rhoss
def _steadystate_direct_dense(L): """ Direct solver that use numpy dense matrices. Suitable for small system, with a few states. """ if settings.debug: print('Starting direct dense solver...') dims = L.dims[0] n = prod(L.dims[0][0]) b = np.zeros(n ** 2) b[0] = ss_args['weight'] L = L.data.todense() L[0, :] = np.diag(ss_args['weight']*np.ones(n)).reshape((1, n ** 2)) v = np.linalg.solve(L, b) data = vec2mat(v) data = 0.5 * (data + data.conj().T) return Qobj(data, dims=dims, isherm=True)
def test_SimpleSuperApply(self): """ Non-composite system, operator on Liouville space. """ tol = 1e-12 rho_3 = rand_dm(3) superop = kraus_to_super(rand_kraus_map(3)) analytic_result = vec2mat(superop.full() @ mat2vec(rho_3.full())) naive_result = subsystem_apply(rho_3, superop, [True], reference=True) naive_diff = (analytic_result - naive_result).full() naive_diff_norm = norm(naive_diff) assert_(naive_diff_norm < tol, msg="SimpleSuper: naive_diff_norm {} " "is beyond tolerance {}".format(naive_diff_norm, tol)) efficient_result = subsystem_apply(rho_3, superop, [True]) efficient_diff = (efficient_result - analytic_result).full() efficient_diff_norm = norm(efficient_diff) assert_(efficient_diff_norm < tol, msg="SimpleSuper: efficient_diff_norm {} " "is beyond tolerance {}".format(efficient_diff_norm, tol))
def _steadystate_direct_dense(L): """ Direct solver that use numpy dense matrices. Suitable for small system, with a few states. """ if settings.debug: print('Starting direct dense solver...') dims = L.dims[0] n = prod(L.dims[0][0]) b = np.zeros(n**2) b[0] = ss_args['weight'] L = L.data.todense() L[0, :] = np.diag(ss_args['weight'] * np.ones(n)).reshape((1, n**2)) _dense_start = time.time() v = np.linalg.solve(L, b) _dense_end = time.time() ss_args['info']['solution_time'] = _dense_end - _dense_start data = vec2mat(v) data = 0.5 * (data + data.conj().T) return Qobj(data, dims=dims, isherm=True)
def integrate(L,E0,ti,tf,opt=qt.Options()): """ Basic ode integrator """ def _rhs(t,y,L): ym = y.reshape(L.shape) return (L*ym).flatten() from qutip.superoperator import vec2mat r = sp.integrate.ode(_rhs) r.set_f_params(L.data) initial_vector = E0.data.toarray().flatten() r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, nsteps=opt.nsteps, first_step=opt.first_step, min_step=opt.min_step, max_step=opt.max_step) r.set_initial_value(initial_vector, ti) r.integrate(tf) if not r.successful(): raise Exception("ODE integration error: Try to increase " "the allowed number of substeps by increasing " "the nsteps parameter in the Options class.") return qt.Qobj(vec2mat(r.y)).trans()
def test_SimpleSuperApply(self): """ Non-composite system, operator on Liouville space. """ tol = 1e-12 rho_3 = rand_dm(3) superop = kraus_to_super(rand_kraus_map(3)) analytic_result = vec2mat(superop.data.todense() * mat2vec(rho_3.data.todense())) naive_result = subsystem_apply(rho_3, superop, [True], reference=True) naive_diff = (analytic_result - naive_result).data.todense() naive_diff_norm = norm(naive_diff) assert_( naive_diff_norm < tol, msg="SimpleSuper: naive_diff_norm {} " "is beyond tolerance {}".format(naive_diff_norm, tol), ) efficient_result = subsystem_apply(rho_3, superop, [True]) efficient_diff = (efficient_result - analytic_result).data.todense() efficient_diff_norm = norm(efficient_diff) assert_( efficient_diff_norm < tol, msg="SimpleSuper: efficient_diff_norm {} " "is beyond tolerance {}".format(efficient_diff_norm, tol), )
def ode2es(L, rho0): """Creates an exponential series that describes the time evolution for the initial density matrix (or state vector) `rho0`, given the Liouvillian (or Hamiltonian) `L`. .. deprecated:: 4.6.0 :obj:`~ode2es` will be removed in QuTiP 5. Please use :obj:`Qobj.eigenstates` to get the eigenstates and -values, and use :obj:`~QobjEvo` for general time-dependence. Parameters ---------- L : qobj Liouvillian of the system. rho0 : qobj Initial state vector or density matrix. Returns ------- eseries : :class:`qutip.eseries` ``eseries`` represention of the system dynamics. """ if issuper(L): # check initial state if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = rho0 * rho0.dag() # check if state is below error threshold if abs(rho0.full()).sum() < 1e-10 + 1e-24: # enforce zero operator return eseries(qzero(rho0.dims[0])) w, v = L.eigenstates() v = np.hstack([ket.full() for ket in v]) # w[i] = eigenvalue i # v[:,i] = eigenvector i rlen = np.prod(rho0.shape) r0 = mat2vec(rho0.full()) v0 = la.solve(v, r0) vv = v * sp.spdiags(v0.T, 0, rlen, rlen) out = None for i in range(rlen): qo = Qobj(vec2mat(vv[:, i]), dims=rho0.dims, shape=rho0.shape) if out: out += eseries(qo, w[i]) else: out = eseries(qo, w[i]) elif isoper(L): if not isket(rho0): raise TypeError('Second argument must be a ket if first' + 'is a Hamiltonian.') # check if state is below error threshold if abs(rho0.full()).sum() < 1e-5 + 1e-20: # enforce zero operator dims = rho0.dims return eseries( Qobj(sp.csr_matrix((dims[0][0], dims[1][0]), dtype=complex))) w, v = L.eigenstates() v = np.hstack([ket.full() for ket in v]) # w[i] = eigenvalue i # v[:,i] = eigenvector i rlen = np.prod(rho0.shape) r0 = rho0.full() v0 = la.solve(v, r0) vv = v * sp.spdiags(v0.T, 0, rlen, rlen) out = None for i in range(rlen): qo = Qobj(np.array(vv[:, i]).T, dims=rho0.dims, shape=rho0.shape) if out: out += eseries(qo, -1.0j * w[i]) else: out = eseries(qo, -1.0j * w[i]) else: raise TypeError('First argument must be a Hamiltonian or Liouvillian.') return estidy(out)
def _td_brmesolve(H, psi0, tlist, a_ops=[], e_ops=[], c_ops=[], args={}, use_secular=True, sec_cutoff=0.1, tol=qset.atol, options=None, progress_bar=None,_safe_mode=True, verbose=False, _prep_time=0): if isket(psi0): rho0 = ket2dm(psi0) else: rho0 = psi0 nrows = rho0.shape[0] H_terms = [] H_td_terms = [] H_obj = [] A_terms = [] A_td_terms = [] C_terms = [] C_td_terms = [] CA_obj = [] spline_count = [0,0] coupled_ops = [] coupled_lengths = [] coupled_spectra = [] if isinstance(H, Qobj): H_terms.append(H.full('f')) H_td_terms.append('1') else: for kk, h in enumerate(H): if isinstance(h, Qobj): H_terms.append(h.full('f')) H_td_terms.append('1') elif isinstance(h, list): H_terms.append(h[0].full('f')) if isinstance(h[1], Cubic_Spline): H_obj.append(h[1].coeffs) spline_count[0] += 1 H_td_terms.append(h[1]) else: raise Exception('Invalid Hamiltonian specification.') for kk, c in enumerate(c_ops): if isinstance(c, Qobj): C_terms.append(c.full('f')) C_td_terms.append('1') elif isinstance(c, list): C_terms.append(c[0].full('f')) if isinstance(c[1], Cubic_Spline): CA_obj.append(c[1].coeffs) spline_count[0] += 1 C_td_terms.append(c[1]) else: raise Exception('Invalid collapse operator specification.') coupled_offset = 0 for kk, a in enumerate(a_ops): if isinstance(a, list): if isinstance(a[0], Qobj): A_terms.append(a[0].full('f')) A_td_terms.append(a[1]) if isinstance(a[1], tuple): if not len(a[1])==2: raise Exception('Tuple must be len=2.') if isinstance(a[1][0],Cubic_Spline): spline_count[1] += 1 if isinstance(a[1][1],Cubic_Spline): spline_count[1] += 1 elif isinstance(a[0], tuple): if not isinstance(a[1], tuple): raise Exception('Invalid bath-coupling specification.') if (len(a[0])+1) != len(a[1]): raise Exception('BR a_ops tuple lengths not compatible.') coupled_ops.append(kk+coupled_offset) coupled_lengths.append(len(a[0])) coupled_spectra.append(a[1][0]) coupled_offset += len(a[0])-1 if isinstance(a[1][0],Cubic_Spline): spline_count[1] += 1 for nn, _a in enumerate(a[0]): A_terms.append(_a.full('f')) A_td_terms.append(a[1][nn+1]) if isinstance(a[1][nn+1],Cubic_Spline): CA_obj.append(a[1][nn+1].coeffs) spline_count[1] += 1 else: raise Exception('Invalid bath-coupling specification.') string_list = [] for kk,_ in enumerate(H_td_terms): string_list.append("H_terms[{0}]".format(kk)) for kk,_ in enumerate(H_obj): string_list.append("H_obj[{0}]".format(kk)) for kk,_ in enumerate(C_td_terms): string_list.append("C_terms[{0}]".format(kk)) for kk,_ in enumerate(CA_obj): string_list.append("CA_obj[{0}]".format(kk)) for kk,_ in enumerate(A_td_terms): string_list.append("A_terms[{0}]".format(kk)) #Add nrows to parameters string_list.append('nrows') for name, value in args.items(): if isinstance(value, np.ndarray): raise TypeError('NumPy arrays not valid args for BR solver.') else: string_list.append(str(value)) parameter_string = ",".join(string_list) if verbose: print('BR prep time:', time.time()-_prep_time) # # generate and compile new cython code if necessary # if not options.rhs_reuse or config.tdfunc is None: if options.rhs_filename is None: config.tdname = "rhs" + str(os.getpid()) + str(config.cgen_num) else: config.tdname = opt.rhs_filename if verbose: _st = time.time() cgen = BR_Codegen(h_terms=len(H_terms), h_td_terms=H_td_terms, h_obj=H_obj, c_terms=len(C_terms), c_td_terms=C_td_terms, c_obj=CA_obj, a_terms=len(A_terms), a_td_terms=A_td_terms, spline_count=spline_count, coupled_ops = coupled_ops, coupled_lengths = coupled_lengths, coupled_spectra = coupled_spectra, config=config, sparse=False, use_secular = use_secular, sec_cutoff = sec_cutoff, args=args, use_openmp=options.use_openmp, omp_thresh=qset.openmp_thresh if qset.has_openmp else None, omp_threads=options.num_cpus, atol=tol) cgen.generate(config.tdname + ".pyx") code = compile('from ' + config.tdname + ' import cy_td_ode_rhs', '<string>', 'exec') exec(code, globals()) config.tdfunc = cy_td_ode_rhs if verbose: print('BR compile time:', time.time()-_st) initial_vector = mat2vec(rho0.full()).ravel() _ode = scipy.integrate.ode(config.tdfunc) code = compile('_ode.set_f_params(' + parameter_string + ')', '<string>', 'exec') _ode.set_integrator('zvode', method=options.method, order=options.order, atol=options.atol, rtol=options.rtol, nsteps=options.nsteps, first_step=options.first_step, min_step=options.min_step, max_step=options.max_step) _ode.set_initial_value(initial_vector, tlist[0]) exec(code, locals()) # # prepare output array # n_tsteps = len(tlist) e_sops_data = [] output = Result() output.solver = "brmesolve" output.times = tlist if options.store_states: output.states = [] if isinstance(e_ops, types.FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(e_ops, list): n_expt_op = len(e_ops) expt_callback = False if n_expt_op == 0: # fall back on storing states output.states = [] options.store_states = True else: output.expect = [] output.num_expect = n_expt_op for op in e_ops: e_sops_data.append(spre(op).data) if op.isherm: output.expect.append(np.zeros(n_tsteps)) else: output.expect.append(np.zeros(n_tsteps, dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # start evolution # if type(progress_bar)==BaseProgressBar and verbose: _run_time = time.time() progress_bar.start(n_tsteps) rho = Qobj(rho0) dt = np.diff(tlist) for t_idx, t in enumerate(tlist): progress_bar.update(t_idx) if not _ode.successful(): raise Exception("ODE integration error: Try to increase " "the allowed number of substeps by increasing " "the nsteps parameter in the Options class.") if options.store_states or expt_callback: rho.data = dense2D_to_fastcsr_fmode(vec2mat(_ode.y), rho.shape[0], rho.shape[1]) if options.store_states: output.states.append(Qobj(rho, isherm=True)) if expt_callback: # use callback method e_ops(t, rho) for m in range(n_expt_op): if output.expect[m].dtype == complex: output.expect[m][t_idx] = expect_rho_vec(e_sops_data[m], _ode.y, 0) else: output.expect[m][t_idx] = expect_rho_vec(e_sops_data[m], _ode.y, 1) if t_idx < n_tsteps - 1: _ode.integrate(_ode.t + dt[t_idx]) progress_bar.finished() if type(progress_bar)==BaseProgressBar and verbose: print('BR runtime:', time.time()-_run_time) if (not options.rhs_reuse) and (config.tdname is not None): _cython_build_cleanup(config.tdname) if options.store_final_state: rho.data = dense2D_to_fastcsr_fmode(vec2mat(_ode.y), rho.shape[0], rho.shape[1]) output.final_state = Qobj(rho, dims=rho0.dims, isherm=True) return output
def _steadystate_power(L, ss_args): """ Inverse power method for steady state solving. """ ss_args['info'].pop('weight', None) if settings.debug: logger.debug('Starting iterative inverse-power method solver.') tol = ss_args['tol'] mtol = ss_args['mtol'] if mtol is None: mtol = max(0.1 * tol, 1e-15) maxiter = ss_args['maxiter'] use_solver(assumeSortedIndices=True) rhoss = Qobj() sflag = issuper(L) if sflag: rhoss.dims = L.dims[0] else: rhoss.dims = [L.dims[0], 1] n = L.shape[0] # Build Liouvillian if ss_args['solver'] == 'mkl' and ss_args['method'] == 'power': has_mkl = 1 else: has_mkl = 0 L, perm, perm2, rev_perm, ss_args = _steadystate_power_liouvillian( L, ss_args, has_mkl) orig_nnz = L.nnz # start with all ones as RHS v = np.ones(n, dtype=complex) if ss_args['use_rcm']: v = v[np.ix_(perm2, )] # Do preconditioning if ss_args['solver'] == 'scipy': if ss_args['M'] is None and ss_args['use_precond'] and \ ss_args['method'] in ['power-gmres', 'power-lgmres', 'power-bicgstab']: ss_args['M'], ss_args = _iterative_precondition( L, int(np.sqrt(n)), ss_args) if ss_args['M'] is None: warnings.warn("Preconditioning failed. Continuing without.", UserWarning) ss_iters = {'iter': 0} def _iter_count(r): ss_iters['iter'] += 1 return _power_start = time.time() # Get LU factors if ss_args['method'] == 'power': if ss_args['solver'] == 'mkl': lu = mkl_splu(L, max_iter_refine=ss_args['max_iter_refine'], scaling_vectors=ss_args['scaling_vectors'], weighted_matching=ss_args['weighted_matching']) else: lu = splu(L, permc_spec=ss_args['permc_spec'], diag_pivot_thresh=ss_args['diag_pivot_thresh'], options=dict(ILU_MILU=ss_args['ILU_MILU'])) if settings.debug and _scipy_check: L_nnz = lu.L.nnz U_nnz = lu.U.nnz logger.debug('L NNZ: %i ; U NNZ: %i' % (L_nnz, U_nnz)) logger.debug('Fill factor: %f' % ((L_nnz + U_nnz) / orig_nnz)) it = 0 # FIXME: These atol keyword except checks can be removed once scipy 1.1 # is a minimum requirement while (la.norm(L * v, np.inf) > tol) and (it < maxiter): check = 0 if ss_args['method'] == 'power': v = lu.solve(v) elif ss_args['method'] == 'power-gmres': try: v, check = gmres(L, v, tol=mtol, atol=ss_args['matol'], M=ss_args['M'], x0=ss_args['x0'], restart=ss_args['restart'], maxiter=ss_args['maxiter'], callback=_iter_count) except TypeError as e: if "unexpected keyword argument 'atol'" in str(e): v, check = gmres(L, v, tol=mtol, M=ss_args['M'], x0=ss_args['x0'], restart=ss_args['restart'], maxiter=ss_args['maxiter'], callback=_iter_count) elif ss_args['method'] == 'power-lgmres': try: v, check = lgmres(L, v, tol=mtol, atol=ss_args['matol'], M=ss_args['M'], x0=ss_args['x0'], maxiter=ss_args['maxiter'], callback=_iter_count) except TypeError as e: if "unexpected keyword argument 'atol'" in str(e): v, check = lgmres(L, v, tol=mtol, M=ss_args['M'], x0=ss_args['x0'], maxiter=ss_args['maxiter'], callback=_iter_count) elif ss_args['method'] == 'power-bicgstab': try: v, check = bicgstab(L, v, tol=mtol, atol=ss_args['matol'], M=ss_args['M'], x0=ss_args['x0'], maxiter=ss_args['maxiter'], callback=_iter_count) except TypeError as e: if "unexpected keyword argument 'atol'" in str(e): v, check = bicgstab(L, v, tol=mtol, M=ss_args['M'], x0=ss_args['x0'], maxiter=ss_args['maxiter'], callback=_iter_count) else: raise Exception("Invalid iterative solver method.") if check > 0: raise Exception("{} failed to find solution in " "{} iterations.".format(ss_args['method'], check)) if check < 0: raise Exception("Breakdown in {}".format(ss_args['method'])) v = v / la.norm(v, np.inf) it += 1 if ss_args['method'] == 'power' and ss_args['solver'] == 'mkl': lu.delete() if ss_args['return_info']: ss_args['info']['max_iter_refine'] = ss_args['max_iter_refine'] ss_args['info']['scaling_vectors'] = ss_args['scaling_vectors'] ss_args['info']['weighted_matching'] = ss_args['weighted_matching'] if it >= maxiter: raise Exception('Failed to find steady state after ' + str(maxiter) + ' iterations') _power_end = time.time() ss_args['info']['solution_time'] = _power_end - _power_start ss_args['info']['iterations'] = it if ss_args['return_info']: ss_args['info']['residual_norm'] = la.norm(L * v, np.inf) if settings.debug: logger.debug('Number of iterations: %i' % it) if ss_args['use_rcm']: v = v[np.ix_(rev_perm, )] # normalise according to type of problem if sflag: trow = v[::rhoss.shape[0] + 1] data = v / np.sum(trow) else: data = data / la.norm(v) data = dense2D_to_fastcsr_fmode(vec2mat(data), rhoss.shape[0], rhoss.shape[0]) rhoss.data = 0.5 * (data + data.H) rhoss.isherm = True if ss_args['return_info']: return rhoss, ss_args['info'] else: return rhoss
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, f_modes_table=None, options=None, floquet_basis=True): """ Solve the dynamics for the system using the Floquet-Markov master equation. """ if options is None: opt = Options() else: opt = options if opt.tidy: R.tidyup() # # check initial state # if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # prepare output array # n_tsteps = len(tlist) dt = tlist[1] - tlist[0] output = Result() output.solver = "fmmesolve" output.times = tlist if isinstance(e_ops, FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(e_ops, list): n_expt_op = len(e_ops) expt_callback = False if n_expt_op == 0: output.states = [] else: if not f_modes_table: raise TypeError("The Floquet mode table has to be provided " + "when requesting expectation values.") output.expect = [] output.num_expect = n_expt_op for op in e_ops: if op.isherm: output.expect.append(np.zeros(n_tsteps)) else: output.expect.append(np.zeros(n_tsteps, dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # transform the initial density matrix to the eigenbasis: from # computational basis to the floquet basis # if ekets is not None: rho0 = rho0.transform(ekets) # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(cy_ode_rhs) r.set_f_params(R.data.data, R.data.indices, R.data.indptr) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) # # start evolution # rho = Qobj(rho0) t_idx = 0 for t in tlist: if not r.successful(): break rho = Qobj(vec2mat(r.y), rho0.dims, rho0.shape) if expt_callback: # use callback method if floquet_basis: e_ops(t, Qobj(rho)) else: f_modes_table_t, T = f_modes_table f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T) e_ops(t, Qobj(rho).transform(f_modes_t, True)) else: # calculate all the expectation values, or output rho if # no operators if n_expt_op == 0: if floquet_basis: output.states.append(Qobj(rho)) else: f_modes_table_t, T = f_modes_table f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T) output.states.append(Qobj(rho).transform(f_modes_t, True)) else: f_modes_table_t, T = f_modes_table f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T) for m in range(0, n_expt_op): output.expect[m][t_idx] = \ expect(e_ops[m], rho.transform(f_modes_t, False)) r.integrate(r.t + dt) t_idx += 1 return output
def _steadystate_iterative(L, ss_args): """ Iterative steady state solver using the GMRES, LGMRES, or BICGSTAB algorithm and a sparse incomplete LU preconditioner. """ ss_iters = {'iter': 0} def _iter_count(r): ss_iters['iter'] += 1 return if settings.debug: logger.debug('Starting %s solver.' % ss_args['method']) dims = L.dims[0] n = int(np.sqrt(L.shape[0])) b = np.zeros(n**2) b[0] = ss_args['weight'] L, perm, perm2, rev_perm, ss_args = _steadystate_LU_liouvillian(L, ss_args) if np.any(perm): b = b[np.ix_(perm, )] if np.any(perm2): b = b[np.ix_(perm2, )] use_solver(assumeSortedIndices=True) if ss_args['M'] is None and ss_args['use_precond']: ss_args['M'], ss_args = _iterative_precondition(L, n, ss_args) if ss_args['M'] is None: warnings.warn("Preconditioning failed. Continuing without.", UserWarning) # Select iterative solver type _iter_start = time.time() # FIXME: These atol keyword except checks can be removed once scipy 1.1 # is a minimum requirement extra = {"callback_type": 'legacy'} if scipy.__version__ >= "1.4" else {} if ss_args['method'] == 'iterative-gmres': try: v, check = gmres(L, b, tol=ss_args['tol'], atol=ss_args['matol'], M=ss_args['M'], x0=ss_args['x0'], restart=ss_args['restart'], maxiter=ss_args['maxiter'], callback=_iter_count, **extra) except TypeError as e: if "unexpected keyword argument 'atol'" in str(e): v, check = gmres(L, b, tol=ss_args['tol'], M=ss_args['M'], x0=ss_args['x0'], restart=ss_args['restart'], maxiter=ss_args['maxiter'], callback=_iter_count) elif ss_args['method'] == 'iterative-lgmres': try: v, check = lgmres(L, b, tol=ss_args['tol'], atol=ss_args['matol'], M=ss_args['M'], x0=ss_args['x0'], maxiter=ss_args['maxiter'], callback=_iter_count) except TypeError as e: if "unexpected keyword argument 'atol'" in str(e): v, check = lgmres(L, b, tol=ss_args['tol'], M=ss_args['M'], x0=ss_args['x0'], maxiter=ss_args['maxiter'], callback=_iter_count) elif ss_args['method'] == 'iterative-bicgstab': try: v, check = bicgstab(L, b, tol=ss_args['tol'], atol=ss_args['matol'], M=ss_args['M'], x0=ss_args['x0'], maxiter=ss_args['maxiter'], callback=_iter_count) except TypeError as e: if "unexpected keyword argument 'atol'" in str(e): v, check = bicgstab(L, b, tol=ss_args['tol'], M=ss_args['M'], x0=ss_args['x0'], maxiter=ss_args['maxiter'], callback=_iter_count) else: raise Exception("Invalid iterative solver method.") _iter_end = time.time() ss_args['info']['iter_time'] = _iter_end - _iter_start if 'precond_time' in ss_args['info'].keys(): ss_args['info']['solution_time'] = (ss_args['info']['iter_time'] + ss_args['info']['precond_time']) else: ss_args['info']['solution_time'] = ss_args['info']['iter_time'] ss_args['info']['iterations'] = ss_iters['iter'] if ss_args['return_info']: ss_args['info']['residual_norm'] = la.norm(b - L * v, np.inf) if settings.debug: logger.debug('Number of Iterations: %i' % ss_iters['iter']) logger.debug('Iteration. time: %f' % (_iter_end - _iter_start)) if check > 0: raise Exception("Steadystate error: Did not reach tolerance after " + str(ss_args['maxiter']) + " steps." + "\nResidual norm: " + str(ss_args['info']['residual_norm'])) elif check < 0: raise Exception("Steadystate error: Failed with fatal error: " + str(check) + ".") if ss_args['use_rcm']: v = v[np.ix_(rev_perm, )] data = vec2mat(v) data = 0.5 * (data + data.conj().T) if ss_args['return_info']: return Qobj(data, dims=dims, isherm=True), ss_args['info'] else: return Qobj(data, dims=dims, isherm=True)
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 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. 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 is None: opt = Odeoptions() opt.rhs_reuse = True 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, H_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 = mesolve(H, psi0, tlist, [], [], H_args, opt) 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], [], [], 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 (a superoperator propagator) if isinstance(H, types.FunctionType): H0 = H(0.0, H_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, [], H_args, opt) 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))]
def _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar): """ Internal function for solving ME. Solve an ODE which solver parameters already setup (r). Calculate the required expectation values or invoke callback function at each time step. """ # # prepare output array # n_tsteps = len(tlist) e_sops_data = [] output = Result() output.solver = "mesolve" output.times = tlist if opt.store_states: output.states = [] if isinstance(e_ops, types.FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(e_ops, list): n_expt_op = len(e_ops) expt_callback = False if n_expt_op == 0: # fall back on storing states output.states = [] opt.store_states = True else: output.expect = [] output.num_expect = n_expt_op for op in e_ops: e_sops_data.append(spre(op).data) if op.isherm and rho0.isherm: output.expect.append(np.zeros(n_tsteps)) else: output.expect.append(np.zeros(n_tsteps, dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # start evolution # progress_bar.start(n_tsteps) rho = Qobj(rho0) dt = np.diff(tlist) for t_idx, t in enumerate(tlist): progress_bar.update(t_idx) if not r.successful(): raise Exception("ODE integration error: Try to increase " "the allowed number of substeps by increasing " "the nsteps parameter in the Options class.") if opt.store_states or expt_callback: rho.data = dense2D_to_fastcsr_fmode(vec2mat(r.y), rho.shape[0], rho.shape[1]) if opt.store_states: output.states.append(Qobj(rho, isherm=True)) if expt_callback: # use callback method e_ops(t, rho) for m in range(n_expt_op): if output.expect[m].dtype == complex: output.expect[m][t_idx] = expect_rho_vec(e_sops_data[m], r.y, 0) else: output.expect[m][t_idx] = expect_rho_vec(e_sops_data[m], r.y, 1) if t_idx < n_tsteps - 1: r.integrate(r.t + dt[t_idx]) progress_bar.finished() if (not opt.rhs_reuse) and (config.tdname is not None): _cython_build_cleanup(config.tdname) if opt.store_final_state: rho.data = dense2D_to_fastcsr_fmode(vec2mat(r.y), rho.shape[0], rho.shape[1]) output.final_state = Qobj(rho, dims=rho0.dims, isherm=True) return output
def get_curr_state_data(r): return vec2mat(r.y)
def propagator(H, t, c_op_list, args=None, options=None, sparse=False): """ 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. Returns ------- a : qobj Instance representing the propagator :math:`U(t)`. """ 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) 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 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) for n in range(0, 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 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: for n in range(N * 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) else: for n in range(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))]
def _steadystate_direct_sparse(L, ss_args): """ Direct solver that uses scipy sparse matrices """ if settings.debug: logger.debug('Starting direct LU solver.') dims = L.dims[0] n = int(np.sqrt(L.shape[0])) b = np.zeros(n**2, dtype=complex) b[0] = ss_args['weight'] if ss_args['solver'] == 'mkl': has_mkl = 1 else: has_mkl = 0 ss_lu_liouv_list = _steadystate_LU_liouvillian(L, ss_args, has_mkl) L, perm, perm2, rev_perm, ss_args = ss_lu_liouv_list if np.any(perm): b = b[np.ix_(perm, )] if np.any(perm2): b = b[np.ix_(perm2, )] if ss_args['solver'] == 'scipy': ss_args['info']['permc_spec'] = ss_args['permc_spec'] ss_args['info']['drop_tol'] = ss_args['drop_tol'] ss_args['info']['diag_pivot_thresh'] = ss_args['diag_pivot_thresh'] ss_args['info']['fill_factor'] = ss_args['fill_factor'] ss_args['info']['ILU_MILU'] = ss_args['ILU_MILU'] if not ss_args['solver'] == 'mkl': # Use superLU solver orig_nnz = L.nnz _direct_start = time.time() lu = splu(L, permc_spec=ss_args['permc_spec'], diag_pivot_thresh=ss_args['diag_pivot_thresh'], options=dict(ILU_MILU=ss_args['ILU_MILU'])) v = lu.solve(b) _direct_end = time.time() ss_args['info']['solution_time'] = _direct_end - _direct_start if (settings.debug or ss_args['return_info']) and _scipy_check: L_nnz = lu.L.nnz U_nnz = lu.U.nnz ss_args['info']['l_nnz'] = L_nnz ss_args['info']['u_nnz'] = U_nnz ss_args['info']['lu_fill_factor'] = (L_nnz + U_nnz) / L.nnz if settings.debug: logger.debug('L NNZ: %i ; U NNZ: %i' % (L_nnz, U_nnz)) logger.debug('Fill factor: %f' % ((L_nnz + U_nnz) / orig_nnz)) else: # Use MKL solver if len(ss_args['info']['perm']) != 0: in_perm = np.arange(n**2, dtype=np.int32) else: in_perm = None _direct_start = time.time() v = mkl_spsolve(L, b, perm=in_perm, verbose=ss_args['verbose'], max_iter_refine=ss_args['max_iter_refine'], scaling_vectors=ss_args['scaling_vectors'], weighted_matching=ss_args['weighted_matching']) _direct_end = time.time() ss_args['info']['solution_time'] = _direct_end - _direct_start if ss_args['return_info']: ss_args['info']['residual_norm'] = la.norm(b - L * v, np.inf) ss_args['info']['max_iter_refine'] = ss_args['max_iter_refine'] ss_args['info']['scaling_vectors'] = ss_args['scaling_vectors'] ss_args['info']['weighted_matching'] = ss_args['weighted_matching'] if ss_args['use_rcm']: v = v[np.ix_(rev_perm, )] data = dense2D_to_fastcsr_fmode(vec2mat(v), n, n) data = 0.5 * (data + data.H) if ss_args['return_info']: return Qobj(data, dims=dims, isherm=True), ss_args['info'] else: return Qobj(data, dims=dims, isherm=True)
def bloch_redfield_solve(R, ekets, rho0, tlist, e_ops=[], options=None): """ Evolve the ODEs defined by Bloch-Redfield master equation. The Bloch-Redfield tensor can be calculated by the function :func:`bloch_redfield_tensor`. Parameters ---------- R : :class:`qutip.qobj` Bloch-Redfield tensor. ekets : array of :class:`qutip.qobj` Array of kets that make up a basis tranformation for the eigenbasis. rho0 : :class:`qutip.qobj` Initial density matrix. tlist : *list* / *array* List of times for :math:`t`. e_ops : list of :class:`qutip.qobj` / callback function List of operators for which to evaluate expectation values. options : :class:`qutip.Qdeoptions` Options for the ODE solver. Returns ------- output: :class:`qutip.solver` An instance of the class :class:`qutip.solver`, which contains either an *array* of expectation values for the times specified by `tlist`. """ if options is None: options = Options() if options.tidy: R.tidyup() # # check initial state # if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = rho0 * rho0.dag() # # prepare output array # n_tsteps = len(tlist) dt = tlist[1] - tlist[0] result_list = [] # # transform the initial density matrix and the e_ops opterators to the # eigenbasis # rho_eb = rho0.transform(ekets) e_eb_ops = [e.transform(ekets) for e in e_ops] for e_eb in e_eb_ops: result_list.append(np.zeros(n_tsteps, dtype=complex)) # # setup integrator # initial_vector = mat2vec(rho_eb.full()) r = scipy.integrate.ode(cy_ode_rhs) r.set_f_params(R.data.data, R.data.indices, R.data.indptr) r.set_integrator('zvode', method=options.method, order=options.order, atol=options.atol, rtol=options.rtol, nsteps=options.nsteps, first_step=options.first_step, min_step=options.min_step, max_step=options.max_step) r.set_initial_value(initial_vector, tlist[0]) # # start evolution # dt = np.diff(tlist) for t_idx, _ in enumerate(tlist): if not r.successful(): break rho_eb.data = vec2mat(r.y) # calculate all the expectation values, or output rho_eb if no # expectation value operators are given if e_ops: rho_eb_tmp = Qobj(rho_eb) for m, e in enumerate(e_eb_ops): result_list[m][t_idx] = expect(e, rho_eb_tmp) else: result_list.append(rho_eb.transform(ekets, True)) if t_idx < n_tsteps - 1: r.integrate(r.t + dt[t_idx]) return result_list
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 _generic_ode_solve(r, rho0, tlist, e_ops, opt, progress_bar): """ Internal function for solving ME. Solve an ODE which solver parameters already setup (r). Calculate the required expectation values or invoke callback function at each time step. """ # # prepare output array # n_tsteps = len(tlist) e_sops_data = [] output = Result() output.solver = "mesolve" output.times = tlist if opt.store_states: output.states = [] if isinstance(e_ops, types.FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(e_ops, list): n_expt_op = len(e_ops) expt_callback = False if n_expt_op == 0: # fall back on storing states output.states = [] opt.store_states = True else: output.expect = [] output.num_expect = n_expt_op for op in e_ops: e_sops_data.append(spre(op).data) if op.isherm and rho0.isherm: output.expect.append(np.zeros(n_tsteps)) else: output.expect.append(np.zeros(n_tsteps, dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # start evolution # progress_bar.start(n_tsteps) rho = Qobj(rho0) dt = np.diff(tlist) for t_idx, t in enumerate(tlist): progress_bar.update(t_idx) if not r.successful(): break if opt.store_states or expt_callback: rho.data = vec2mat(r.y) if opt.store_states: output.states.append(Qobj(rho)) if expt_callback: # use callback method e_ops(t, rho) for m in range(n_expt_op): if output.expect[m].dtype == complex: output.expect[m][t_idx] = expect_rho_vec(e_sops_data[m], r.y, 0) else: output.expect[m][t_idx] = expect_rho_vec(e_sops_data[m], r.y, 1) if t_idx < n_tsteps - 1: r.integrate(r.t + dt[t_idx]) progress_bar.finished() if not opt.rhs_reuse and config.tdname is not None: try: os.remove(config.tdname + ".pyx") except: pass if opt.store_final_state: rho.data = vec2mat(r.y) output.final_state = Qobj(rho) return output
def ode2es(L, rho0): """Creates an exponential series that describes the time evolution for the initial density matrix (or state vector) `rho0`, given the Liouvillian (or Hamiltonian) `L`. Parameters ---------- L : qobj Liouvillian of the system. rho0 : qobj Initial state vector or density matrix. Returns ------- eseries : :class:`qutip.eseries` ``eseries`` represention of the system dynamics. """ if issuper(L): # check initial state if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = rho0 * rho0.dag() w, v = L.eigenstates() v = np.hstack([ket.full() for ket in v]) # w[i] = eigenvalue i # v[:,i] = eigenvector i rlen = np.prod(rho0.shape) r0 = mat2vec(rho0.full()) v0 = la.solve(v, r0) vv = v * sp.spdiags(v0.T, 0, rlen, rlen) out = None for i in range(rlen): qo = Qobj(vec2mat(vv[:, i]), dims=rho0.dims, shape=rho0.shape) if out: out += eseries(qo, w[i]) else: out = eseries(qo, w[i]) elif isoper(L): if not isket(rho0): raise TypeError("Second argument must be a ket if first" + "is a Hamiltonian.") w, v = L.eigenstates() v = np.hstack([ket.full() for ket in v]) # w[i] = eigenvalue i # v[:,i] = eigenvector i rlen = np.prod(rho0.shape) r0 = rho0.full() v0 = la.solve(v, r0) vv = v * sp.spdiags(v0.T, 0, rlen, rlen) out = None for i in range(rlen): qo = Qobj(np.matrix(vv[:, i]).T, dims=rho0.dims, shape=rho0.shape) if out: out += eseries(qo, -1.0j * w[i]) else: out = eseries(qo, -1.0j * w[i]) else: raise TypeError("First argument must be a Hamiltonian or Liouvillian.") return estidy(out)
def _ode_super_func(t, y, data): ym = vec2mat(y) return (data*ym).ravel('F')
def floquet_markov_mesolve(R, ekets, rho0, tlist, e_ops, f_modes_table=None, options=None, floquet_basis=True): """ Solve the dynamics for the system using the Floquet-Markov master equation. """ if options is None: opt = Options() else: opt = options if opt.tidy: R.tidyup() # # check initial state # if isket(rho0): # Got a wave function as initial state: convert to density matrix. rho0 = ket2dm(rho0) # # prepare output array # n_tsteps = len(tlist) dt = tlist[1] - tlist[0] output = Result() output.solver = "fmmesolve" output.times = tlist if isinstance(e_ops, FunctionType): n_expt_op = 0 expt_callback = True elif isinstance(e_ops, list): n_expt_op = len(e_ops) expt_callback = False if n_expt_op == 0: output.states = [] else: if not f_modes_table: raise TypeError("The Floquet mode table has to be provided " + "when requesting expectation values.") output.expect = [] output.num_expect = n_expt_op for op in e_ops: if op.isherm: output.expect.append(np.zeros(n_tsteps)) else: output.expect.append(np.zeros(n_tsteps, dtype=complex)) else: raise TypeError("Expectation parameter must be a list or a function") # # transform the initial density matrix to the eigenbasis: from # computational basis to the floquet basis # if ekets is not None: rho0 = rho0.transform(ekets) # # setup integrator # initial_vector = mat2vec(rho0.full()) r = scipy.integrate.ode(cy_ode_rhs) r.set_f_params(R.data.data, R.data.indices, R.data.indptr) r.set_integrator('zvode', method=opt.method, order=opt.order, atol=opt.atol, rtol=opt.rtol, max_step=opt.max_step) r.set_initial_value(initial_vector, tlist[0]) # # start evolution # rho = Qobj(rho0) t_idx = 0 for t in tlist: if not r.successful(): break rho.data = vec2mat(r.y) if expt_callback: # use callback method if floquet_basis: e_ops(t, Qobj(rho)) else: f_modes_table_t, T = f_modes_table f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T) e_ops(t, Qobj(rho).transform(f_modes_t, True)) else: # calculate all the expectation values, or output rho if # no operators if n_expt_op == 0: if floquet_basis: output.states.append(Qobj(rho)) else: f_modes_table_t, T = f_modes_table f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T) output.states.append(Qobj(rho).transform(f_modes_t, True)) else: f_modes_table_t, T = f_modes_table f_modes_t = floquet_modes_t_lookup(f_modes_table_t, t, T) for m in range(0, n_expt_op): output.expect[m][t_idx] = \ expect(e_ops[m], rho.transform(f_modes_t, False)) r.integrate(r.t + dt) t_idx += 1 return output