def d1_psi_heterodyne(A, psi): """ not working/tested Todo: cythonize """ e1 = cy_expect(A[0].data, A[0].indices, A[0].indptr, 0, psi) B = A[0].T.conj() e2 = cy_expect(B.data, B.indices, B.indptr, 0, psi) return (e2 * spmv(A[0].data, A[0].indices, A[0].indptr, psi) - 0.5 * spmv(A[2].data, A[2].indices, A[2].indptr, psi) - 0.5 * e1 * e2 * psi)
def _ssesolve_single_trajectory(H, dt, tlist, N_store, N_substeps, psi_t, A_ops, e_ops, data, rhs, d1, d2, d2_len, homogeneous, distribution, args, store_measurement=False, noise=None): """ Internal function. See ssesolve. """ 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 = cy_expect(e.data.data, e.data.indices, e.data.indptr, psi_t) data.expect[e_idx, t_idx] += s data.ss[e_idx, t_idx] += s ** 2 else: states_list.append(Qobj(psi_t)) psi_prev = np.copy(psi_t) for j in range(N_substeps): if noise is None and not homogeneous: for a_idx, A in enumerate(A_ops): dw_expect = norm(spmv(A[0].data, A[0].indices, A[0].indptr, psi_t)) ** 2 * dt dW[a_idx, t_idx, j, :] = np.random.poisson(dw_expect, d2_len) psi_t = rhs(H.data, psi_t, t + dt * j, A_ops, dt, dW[:, t_idx, j, :], d1, d2, args) # optionally renormalize the wave function: TODO: make the # renormalization optional througha configuration parameter in # Odeoptions psi_t /= norm(psi_t) if store_measurement: for a_idx, A in enumerate(A_ops): phi = spmv(A[0].data, A[0].indices, A[0].indptr, psi_prev) measurements[t_idx, a_idx] = (norm(phi) ** 2 * dt * N_substeps + dW[a_idx, t_idx, :, 0].sum()) return states_list, dW, measurements
def d1_psi_heterodyne(A, psi): """ Todo: cythonize .. math:: D_1(\psi, t) = -\\frac{1}{2}(C^\\dagger C - \\langle C^\\dagger \\rangle C + \\frac{1}{2}\\langle C \\rangle\\langle C^\\dagger \\rangle))\psi """ e_C = cy_expect(A[0].data, A[0].indices, A[0].indptr, psi) # e_C B = A[0].T.conj() e_Cd = cy_expect(B.data, B.indices, B.indptr, psi) # e_Cd return (-0.5 * spmv(A[3].data, A[3].indices, A[3].indptr, psi) + 0.5 * e_Cd * spmv(A[0].data, A[0].indices, A[0].indptr, psi) - 0.25 * e_C * e_Cd * psi)
def d2_psi_heterodyne(A, psi): """ not working/tested Todo: cythonize """ e1 = cy_expect(A[0].data, A[0].indices, A[0].indptr, 0, psi) return spmv(A[0].data, A[0].indices, A[0].indptr, psi) - e1 * psi
def d2_psi_homodyne(A, psi): """ OK Todo: cythonize """ e1 = cy_expect(A[1].data, A[1].indices, A[1].indptr, 0, psi) return (spmv(A[0].data, A[0].indices, A[0].indptr, psi) - 0.5 * e1 * psi)
def d1_psi_homodyne(A, psi): """ OK Todo: cythonize """ e1 = cy_expect(A[1].data, A[1].indices, A[1].indptr, 0, psi) return 0.5 * (e1 * spmv(A[0].data, A[0].indices, A[0].indptr, psi) - spmv(A[2].data, A[2].indices, A[2].indptr, psi) - 0.25 * e1 ** 2 * psi)
def d2_psi_heterodyne(A, psi): """ Todo: cythonize X = \\frac{1}{2}(C + C^\\dagger) Y = \\frac{1}{2}(C - C^\\dagger) D_{2,1}(\psi, t) = \\sqrt(1/2) * (C - \\langle X \\rangle) \\psi D_{2,2}(\psi, t) = -i\\sqrt(1/2) * (C - \\langle Y \\rangle) \\psi """ X = 0.5 * cy_expect(A[1].data, A[1].indices, A[1].indptr, psi) Y = 0.5 * cy_expect(A[2].data, A[2].indices, A[2].indptr, psi) d2_1 = np.sqrt(0.5) * (spmv(A[0].data, A[0].indices, A[0].indptr, psi) - X * psi) d2_2 = -1.0j * np.sqrt(0.5) * (spmv(A[0].data, A[0].indices, A[0].indptr, psi) - Y * psi) return [d2_1, d2_2]
def d2_psi_homodyne(A, psi): """ OK Todo: cythonize .. math:: D_2(\psi, t) = (C - \\frac{1}{2}\\langle C + C^\\dagger\\rangle)\\psi """ e1 = cy_expect(A[1].data, A[1].indices, A[1].indptr, psi) return [spmv(A[0].data, A[0].indices, A[0].indptr, psi) - 0.5 * e1 * psi]
def _ssesolve_single_trajectory(H, dt, tlist, N_store, N_substeps, psi_t, A_ops, e_ops, data, rhs, d1, d2, d2_len, homogeneous, ssdata): """ Internal function. See ssesolve. """ if homogeneous: if ssdata.incr_distr == '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 ssdata.incr_distr != 'poisson': raise TypeError('Unsupported increment distribution for inhomogeneous process.') states_list = [] for t_idx, t in enumerate(tlist): if e_ops: for e_idx, e in enumerate(e_ops): s = cy_expect(e.data.data, e.data.indices, e.data.indptr, 0, psi_t) data.expect[e_idx, t_idx] += s data.ss[e_idx, t_idx] += s ** 2 else: states_list.append(Qobj(psi_t)) for j in range(N_substeps): dpsi_t = (-1.0j * dt) * (H.data * psi_t) for a_idx, A in enumerate(A_ops): if homogeneous: dw = dW[a_idx, t_idx, j, :] else: dw_expect = norm(spmv(A[0].data, A[0].indices, A[0].indptr, psi_t)) ** 2 * dt dw = np.random.poisson(dw_expect, d2_len) dpsi_t += rhs(H.data, psi_t, A, dt, dw, d1, d2) # increment and renormalize the wave function psi_t += dpsi_t psi_t /= norm(psi_t) return states_list
def d1_psi_homodyne(A, psi): """ OK Todo: cythonize .. math:: D_1(\psi, t) = \\frac{1}{2}(\\langle C + C^\\dagger\\rangle\\psi - C^\\dagger C\\psi - \\frac{1}{4}\\langle C + C^\\dagger\\rangle^2\\psi) """ e1 = cy_expect(A[1].data, A[1].indices, A[1].indptr, psi) return 0.5 * (e1 * spmv(A[0].data, A[0].indices, A[0].indptr, psi) - spmv(A[3].data, A[3].indices, A[3].indptr, psi) - 0.25 * e1 ** 2 * psi)
def _sepdpsolve_single_trajectory(Heff, dt, tlist, N_store, N_substeps, psi_t, c_ops, e_ops, data): """ Internal function. """ states_list = [] phi_t = np.copy(psi_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): s = cy_expect(e.data.data, e.data.indices, e.data.indptr, psi_t) data.expect[e_idx, t_idx] += s data.ss[e_idx, t_idx] += s ** 2 else: states_list.append(Qobj(psi_t)) for j in range(N_substeps): if norm(phi_t) ** 2 < r_jump: # jump occurs p = np.array([norm(c.data * psi_t) ** 2 for c in c_ops]) p = np.cumsum(p / np.sum(p)) n = np.where(p >= r_op)[0][0] # apply jump psi_t = c_ops[n].data * psi_t psi_t /= norm(psi_t) phi_t = np.copy(psi_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 dphi_t = (-1.0j * dt) * (Heff.data * phi_t) # deterministic evolution with correction for norm decay dpsi_t = (-1.0j * dt) * (Heff.data * psi_t) A = 0.5 * np.sum([norm(c.data * psi_t) ** 2 for c in c_ops]) dpsi_t += dt * A * psi_t # increment wavefunctions phi_t += dphi_t psi_t += dpsi_t # ensure that normalized wavefunction remains normalized # this allows larger time step than otherwise would be possible psi_t /= norm(psi_t) return states_list, jump_times, jump_op_idx