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 d2_rho_heterodyne(A, rho_vec): """ todo: cythonize, docstrings """ M = A[0] + A[3] e1 = cy_expect_rho_vec(M, rho_vec) d1 = spmv(M.data, M.indices, M.indptr, rho_vec) - e1 * rho_vec M = A[0] - A[3] e1 = cy_expect_rho_vec(M, rho_vec) d2 = spmv(M.data, M.indices, M.indptr, rho_vec) - e1 * rho_vec return [1.0/np.sqrt(2) * d1, -1.0j/np.sqrt(2) * d2]
def d1_rho_photocurrent(A, rho_vec): """ Todo: cythonize, add (AdA)_L + AdA_R to precomputed operators """ n_sum = A[4] + A[5] e1 = cy_expect_rho_vec(n_sum, rho_vec, 0) return 0.5 * (e1 * rho_vec - spmv(n_sum, rho_vec))
def d1_rho_photocurrent(A, rho_vec): """ Todo: cythonize, add (AdA)_L + AdA_R to precomputed operators """ n_sum = A[4] + A[5] e1 = cy_expect_rho_vec(n_sum, rho_vec) return -spmv(n_sum.data, n_sum.indices, n_sum.indptr, rho_vec) + e1 * rho_vec
def _rhs_rho_milstein_homodyne(L, rho_t, t, A_ops, dt, dW, d1, d2, args): """ .. note:: Experimental. Milstein scheme for homodyne detection. This implementation works for commuting stochastic jump operators. TODO: optimizations: do calculation for n>m only """ A_len = len(A_ops) M = np.array([A_ops[n][0] + A_ops[n][3] for n in range(A_len)]) e1 = np.array([cy_expect_rho_vec(M[n], rho_t, 0) for n in range(A_len)]) d1_vec = np.sum([spmv(A_ops[n][7], rho_t) for n in range(A_len)], axis=0) d2_vec = np.array([spmv(M[n], rho_t) for n in range(A_len)]) # This calculation is suboptimal. We need only values for m>n in case of # commuting jump operators. d2_vec2 = np.array([[spmv(M[n], d2_vec[m]) for m in range(A_len)] for n in range(A_len)]) e2 = np.array([[cy_expect_rho_vec(M[n], d2_vec[m], 0) for m in range(A_len)] for n in range(A_len)]) drho_t = _rhs_rho_deterministic(L, rho_t, t, dt, args) drho_t += d1_vec * dt drho_t += np.sum([(d2_vec[n] - e1[n] * rho_t) * dW[n, 0] for n in range(A_len)], axis=0) drho_t += 0.5 * np.sum([(d2_vec2[n, n] - 2.0 * e1[n] * d2_vec[n] + (-e2[n, n] + 2.0 * e1[n] * e1[n]) * rho_t) * (dW[n, 0] * dW[n, 0] - dt) for n in range(A_len)], axis=0) # This calculation is suboptimal. We need only values for m>n in case of # commuting jump operators. drho_t += 0.5 * np.sum([(d2_vec2[n, m] - e1[m] * d2_vec[n] - e1[n] * d2_vec[m] + (-e2[n, m] + 2.0 * e1[n] * e1[m]) * rho_t) * (dW[n, 0] * dW[m, 0]) for (n, m) in np.ndindex(A_len, A_len) if n != m], axis=0) return rho_t + drho_t
def d2_rho_homodyne(A, rho_vec): """ D2[a] rho = a rho + rho a^\dagger - Tr[a rho + rho a^\dagger] = (A_L + Ad_R) rho_vec - E[(A_L + Ad_R) rho_vec] Todo: cythonize, add A_L + Ad_R to precomputed operators """ M = A[0] + A[3] e1 = cy_expect_rho_vec(M, rho_vec) return [spmv(M.data, M.indices, M.indptr, rho_vec) - e1 * rho_vec]
def _rhs_rho_milstein_homodyne_single(L, rho_t, t, A_ops, dt, dW, d1, d2, args): """ .. note:: Experimental. Milstein scheme for homodyne detection with single jump operator. """ A = A_ops[0] M = A[0] + A[3] e1 = cy_expect_rho_vec(M, rho_t, 0) d2_vec = spmv(M, rho_t) d2_vec2 = spmv(M, d2_vec) e2 = cy_expect_rho_vec(M, d2_vec, 0) drho_t = _rhs_rho_deterministic(L, rho_t, t, dt, args) drho_t += spmv(A[7], rho_t) * dt drho_t += (d2_vec - e1 * rho_t) * dW[0, 0] drho_t += 0.5 * (d2_vec2 - 2 * e1 * d2_vec + (-e2 + 2 * e1 * e1) * rho_t) * (dW[0, 0] * dW[0, 0] - dt) return rho_t + drho_t
def sop_H(A, rho_vec): """ Evaluate the superoperator H[a] rho = a rho + rho a^\dagger - Tr[a rho + rho a^\dagger] rho -> (A_L + Ad_R) rho_vec - E[(A_L + Ad_R) rho_vec] rho_vec Todo: cythonize, add A_L + Ad_R to precomputed operators """ M = A[0] + A[3] e1 = cy_expect_rho_vec(M, rho_vec, 0) return spmv(M, rho_vec) - e1 * rho_vec
def sop_H(A, rho_vec): """ Evaluate the superoperator H[a] rho = a rho + rho a^\dagger - Tr[a rho + rho a^\dagger] -> (A_L + Ad_R) rho_vec - E[(A_L + Ad_R) rho_vec] Todo: cythonize, add A_L + Ad_R to precomputed operators """ M = A[0] + A[3] e1 = cy_expect_rho_vec(M, rho_vec) return spmv(M.data, M.indices, M.indptr, rho_vec) - e1 * rho_vec
def sop_G(A, rho_vec): """ Evaluate the superoperator G[a] rho = a rho a^\dagger / Tr[a rho a^\dagger] - rho -> A_L Ad_R rho_vec / Tr[A_L Ad_R rho_vec] - rho_vec Todo: cythonize, add A_L + Ad_R to precomputed operators """ e1 = cy_expect_rho_vec(A[6], rho_vec) if e1 > 1e-15: return spmv(A[6].data, A[6].indices, A[6].indptr, rho_vec) / e1 - rho_vec else: return -rho_vec
def sop_G(A, rho_vec): """ Evaluate the superoperator G[a] rho = a rho a^\dagger / Tr[a rho a^\dagger] - rho -> A_L Ad_R rho_vec / Tr[A_L Ad_R rho_vec] - rho_vec Todo: cythonize, add A_L + Ad_R to precomputed operators """ e1 = cy_expect_rho_vec(A[6], rho_vec, 0) if e1 > 1e-15: return spmv(A[6], rho_vec) / e1 - rho_vec else: return -rho_vec
def d2_rho_photocurrent(A, rho_vec): """ Todo: cythonize, add (AdA)_L + AdA_R to precomputed operators """ e1 = cy_expect_rho_vec(A[6], rho_vec) + 1e-15 return [spmv(A[6].data, A[6].indices, A[6].indptr, rho_vec) / e1 - rho_vec]
def d2_rho_photocurrent(A, rho_vec): """ Todo: cythonize, add (AdA)_L + AdA_R to precomputed operators """ e1 = cy_expect_rho_vec(A[6], rho_vec, 0) return [spmv(A[6], rho_vec) / e1 - rho_vec] if e1.real > 1e-15 else [-rho_vec]