Beispiel #1
0
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_psi_csr(A[0].data, A[0].indices, A[0].indptr, psi)  # e_C
    B = A[0].T.conj()
    e_Cd = cy_expect_psi_csr(B.data, B.indices, B.indptr, psi)  # e_Cd

    return (-0.5 * spmv(A[3], psi) +
            0.5 * e_Cd * spmv(A[0], psi) -
            0.25 * e_C * e_Cd * psi)
Beispiel #2
0
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_psi_csr(A[1].data, A[1].indices, A[1].indptr, psi)
    Y = 0.5 * cy_expect_psi_csr(A[2].data, A[2].indices, A[2].indptr, psi)

    d2_1 = np.sqrt(0.5) * (spmv(A[0], psi) - X * psi)
    d2_2 = -1.0j * np.sqrt(0.5) * (spmv(A[0], psi) - Y * psi)

    return [d2_1, d2_2]
Beispiel #3
0
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_psi_csr(A[1].data, A[1].indices, A[1].indptr, psi)
    return [spmv(A[0], psi) - 0.5 * e1 * psi]
Beispiel #4
0
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_psi_csr(A[1].data, A[1].indices, A[1].indptr, psi)
    return 0.5 * (e1 * spmv(A[0], psi) -
                  spmv(A[3], psi) -
                  0.25 * e1 ** 2 * psi)
Beispiel #5
0
def _mc_alg_evolve(nt, config, opt, seeds):
    """
    Monte Carlo algorithm returning state-vector or expectation values
    at times tlist for a single trajectory.
    """

    global _cy_rhs_func
    global _cy_col_spmv_func, _cy_col_expect_func
    global _cy_col_spmv_call_func, _cy_col_expect_call_func

    tlist = config.tlist
    num_times = len(tlist)

    if not _cy_rhs_func:
        _mc_func_load(config)

    if config.options.steady_state_average:
        states_out = np.zeros((1), dtype=object)
    else:
        states_out = np.zeros((num_times), dtype=object)

    temp = sp.csr_matrix(
        np.reshape(config.psi0, (config.psi0.shape[0], 1)),
        dtype=complex)
    if (config.options.average_states and
            not config.options.steady_state_average):
        # output is averaged states, so use dm
        states_out[0] = Qobj(temp*temp.conj().transpose(),
                             [config.psi0_dims[0],
                              config.psi0_dims[0]],
                             [config.psi0_shape[0],
                              config.psi0_shape[0]],
                             fast='mc-dm')
    elif (not config.options.average_states and
          not config.options.steady_state_average):
        # output is not averaged, so write state vectors
        states_out[0] = Qobj(temp, config.psi0_dims,
                             config.psi0_shape, fast='mc')
    elif config.options.steady_state_average:
        states_out[0] = temp * temp.conj().transpose()

    # PRE-GENERATE LIST FOR EXPECTATION VALUES
    expect_out = []
    for i in range(config.e_num):
        if config.e_ops_isherm[i]:
            # preallocate real array of zeros
            expect_out.append(np.zeros(num_times, dtype=float))
        else:
            # preallocate complex array of zeros
            expect_out.append(np.zeros(num_times, dtype=complex))

        expect_out[i][0] = \
            cy_expect_psi_csr(config.e_ops_data[i],
                              config.e_ops_ind[i],
                              config.e_ops_ptr[i],
                              config.psi0,
                              config.e_ops_isherm[i])

    collapse_times = []
    which_oper = []

    # SEED AND RNG AND GENERATE
    prng = RandomState(seeds[nt])
    # first rand is collapse norm, second is which operator
    rand_vals = prng.rand(2)

    # CREATE ODE OBJECT CORRESPONDING TO DESIRED TIME-DEPENDENCE
    if config.tflag in [1, 10, 11]:
        ODE = ode(_cy_rhs_func)
        code = compile('ODE.set_f_params(' + config.string + ')',
                       '<string>', 'exec')
        exec(code)
    elif config.tflag == 2:
        ODE = ode(_cRHStd)
        ODE.set_f_params(config)
    elif config.tflag in [20, 22]:
        if config.options.rhs_with_state:
            ODE = ode(_tdRHStd_with_state)
        else:
            ODE = ode(_tdRHStd)
        ODE.set_f_params(config)
    elif config.tflag == 3:
        if config.options.rhs_with_state:
            ODE = ode(_pyRHSc_with_state)
        else:
            ODE = ode(_pyRHSc)
        ODE.set_f_params(config)
    else:
        ODE = ode(_cy_rhs_func)
        ODE.set_f_params(config.h_data, config.h_ind,
                         config.h_ptr)

    # initialize ODE solver for RHS
    ODE._integrator = qutip_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)

    if not len(ODE._y):
        ODE.t = 0.0
        ODE._y = np.array([0.0], complex)
    ODE._integrator.reset(len(ODE._y), ODE.jac is not None)

    # set initial conditions
    ODE.set_initial_value(config.psi0, tlist[0])

    # make array for collapse operator inds
    cinds = np.arange(config.c_num)

    # RUN ODE UNTIL EACH TIME IN TLIST
    for k in range(1, num_times):
        # ODE WHILE LOOP FOR INTEGRATE UP TO TIME TLIST[k]
        while ODE.t < tlist[k]:
            t_prev = ODE.t
            y_prev = ODE.y
            norm2_prev = dznrm2(ODE._y) ** 2
            # integrate up to tlist[k], one step at a time.
            ODE.integrate(tlist[k], step=1)
            if not ODE.successful():
                raise Exception("ZVODE failed!")
            norm2_psi = dznrm2(ODE._y) ** 2
            if norm2_psi <= rand_vals[0]:
                # collapse has occured:
                # find collapse time to within specified tolerance
                # ------------------------------------------------
                ii = 0
                t_final = ODE.t
                while ii < config.norm_steps:
                    ii += 1
                    t_guess = t_prev + \
                        np.log(norm2_prev / rand_vals[0]) / \
                        np.log(norm2_prev / norm2_psi) * (t_final - t_prev)
                    ODE._y = y_prev
                    ODE.t = t_prev
                    ODE._integrator.call_args[3] = 1
                    ODE.integrate(t_guess, step=0)
                    if not ODE.successful():
                        raise Exception(
                            "ZVODE failed after adjusting step size!")
                    norm2_guess = dznrm2(ODE._y)**2
                    if (np.abs(rand_vals[0] - norm2_guess) <
                            config.norm_tol * rand_vals[0]):
                        break
                    elif (norm2_guess < rand_vals[0]):
                        # t_guess is still > t_jump
                        t_final = t_guess
                        norm2_psi = norm2_guess
                    else:
                        # t_guess < t_jump
                        t_prev = t_guess
                        y_prev = ODE.y
                        norm2_prev = norm2_guess
                if ii > config.norm_steps:
                    raise Exception("Norm tolerance not reached. " +
                                    "Increase accuracy of ODE solver or " +
                                    "Options.norm_steps.")

                collapse_times.append(ODE.t)

                # some string based collapse operators
                if config.tflag in [1, 11]:
                    n_dp = [cy_expect_psi_csr(config.n_ops_data[i],
                                              config.n_ops_ind[i],
                                              config.n_ops_ptr[i],
                                              ODE._y, 1)
                            for i in config.c_const_inds]

                    _locals = locals()
                    # calculates the expectation values for time-dependent
                    # norm collapse operators
                    exec(_cy_col_expect_call_func, globals(), _locals)
                    n_dp = np.array(_locals['n_dp'])

                elif config.tflag in [2, 20, 22]:
                    # some Python function based collapse operators
                    n_dp = [cy_expect_psi_csr(config.n_ops_data[i],
                                              config.n_ops_ind[i],
                                              config.n_ops_ptr[i],
                                              ODE._y, 1)
                            for i in config.c_const_inds]
                    n_dp += [abs(config.c_funcs[i](
                                 ODE.t, config.c_func_args)) ** 2 *
                             cy_expect_psi_csr(config.n_ops_data[i],
                                               config.n_ops_ind[i],
                                               config.n_ops_ptr[i],
                                               ODE._y, 1)
                             for i in config.c_td_inds]
                    n_dp = np.array(n_dp)
                else:
                    # all constant collapse operators.
                    n_dp = np.array(
                        [cy_expect_psi_csr(config.n_ops_data[i],
                                           config.n_ops_ind[i],
                                           config.n_ops_ptr[i],
                                           ODE._y, 1)
                         for i in range(config.c_num)])

                # determine which operator does collapse and store it
                kk = np.cumsum(n_dp / np.sum(n_dp))
                j = cinds[kk >= rand_vals[1]][0]
                which_oper.append(j)
                if j in config.c_const_inds:
                    state = spmv_csr(config.c_ops_data[j],
                                     config.c_ops_ind[j],
                                     config.c_ops_ptr[j], ODE._y)
                else:
                    if config.tflag in [1, 11]:
                        _locals = locals()
                        # calculates the state vector for collapse by a
                        # time-dependent collapse operator
                        exec(_cy_col_spmv_call_func, globals(), _locals)
                        state = _locals['state']
                    else:
                        state = \
                            config.c_funcs[j](ODE.t,
                                              config.c_func_args) * \
                            spmv_csr(config.c_ops_data[j],
                                     config.c_ops_ind[j],
                                     config.c_ops_ptr[j], ODE._y)
                state = state / dznrm2(state)
                ODE._y = state
                ODE._integrator.call_args[3] = 1
                rand_vals = prng.rand(2)

        # after while loop
        # ----------------
        out_psi = ODE._y / dznrm2(ODE._y)
        if config.e_num == 0 or config.options.store_states:
            out_psi_csr = sp.csr_matrix(np.reshape(out_psi,
                                                   (out_psi.shape[0], 1)),
                                        dtype=complex)
            if (config.options.average_states and
                    not config.options.steady_state_average):
                states_out[k] = Qobj(
                    out_psi_csr * out_psi_csr.conj().transpose(),
                    [config.psi0_dims[0], config.psi0_dims[0]],
                    [config.psi0_shape[0], config.psi0_shape[0]],
                    fast='mc-dm')

            elif config.options.steady_state_average:
                states_out[0] = (
                    states_out[0] +
                    (out_psi_csr * out_psi_csr.conj().transpose()))

            else:
                states_out[k] = Qobj(out_psi_csr, config.psi0_dims,
                                     config.psi0_shape, fast='mc')

        for jj in range(config.e_num):
            expect_out[jj][k] = cy_expect_psi_csr(
                config.e_ops_data[jj], config.e_ops_ind[jj],
                config.e_ops_ptr[jj], out_psi,
                config.e_ops_isherm[jj])

    # Run at end of mc_alg function
    # -----------------------------
    if config.options.steady_state_average:
        states_out = np.array([Qobj(states_out[0] / float(len(tlist)),
                              [config.psi0_dims[0],
                               config.psi0_dims[0]],
                              [config.psi0_shape[0],
                               config.psi0_shape[0]],
                              fast='mc-dm')])

    return (states_out, expect_out,
            np.array(collapse_times, dtype=float),
            np.array(which_oper, dtype=int))
Beispiel #6
0
def _evolve_no_collapse_expect_out(config):
    """
    Calculates expect.values at times tlist if no collapse ops. given
    """

    global _cy_rhs_func
    global _cy_col_spmv_func, _cy_col_expect_func
    global _cy_col_spmv_call_func, _cy_col_expect_call_func

    if debug:
        print(inspect.stack()[0][3])

    num_times = len(config.tlist)
    expect_out = []
    for i in range(config.e_num):
        if config.e_ops_isherm[i]:
            # preallocate real array of zeros
            expect_out.append(np.zeros(num_times, dtype=float))
        else:
            # preallocate complex array of zeros
            expect_out.append(np.zeros(num_times, dtype=complex))

        expect_out[i][0] = \
            cy_expect_psi_csr(config.e_ops_data[i],
                              config.e_ops_ind[i],
                              config.e_ops_ptr[i],
                              config.psi0,
                              config.e_ops_isherm[i])

    if not _cy_rhs_func:
        _mc_func_load(config)

    opt = config.options
    if config.tflag in [1, 10, 11]:
        ODE = ode(_cy_rhs_func)
        code = compile('ODE.set_f_params(' + config.string + ')',
                       '<string>', 'exec')
        exec(code)
    elif config.tflag == 2:
        ODE = ode(_cRHStd)
        ODE.set_f_params(config)
    elif config.tflag in [20, 22]:
        if config.options.rhs_with_state:
            ODE = ode(_tdRHStd_with_state)
        else:
            ODE = ode(_tdRHStd)
        ODE.set_f_params(config)
    elif config.tflag == 3:
        if config.options.rhs_with_state:
            ODE = ode(_pyRHSc_with_state)
        else:
            ODE = ode(_pyRHSc)
        ODE.set_f_params(config)
    else:
        ODE = ode(cy_ode_rhs)
        ODE.set_f_params(config.h_data, config.h_ind, config.h_ptr)

    ODE.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)
    ODE.set_initial_value(config.psi0, config.tlist[0])
    for jj in range(config.e_num):
        expect_out[jj][0] = cy_expect_psi_csr(
            config.e_ops_data[jj], config.e_ops_ind[jj],
            config.e_ops_ptr[jj], config.psi0,
            config.e_ops_isherm[jj])

    for k in range(1, num_times):
        ODE.integrate(config.tlist[k], step=0)  # integrate up to tlist[k]
        if ODE.successful():
            state = ODE.y / dznrm2(ODE.y)
            for jj in range(config.e_num):
                expect_out[jj][k] = cy_expect_psi_csr(
                    config.e_ops_data[jj], config.e_ops_ind[jj],
                    config.e_ops_ptr[jj], state,
                    config.e_ops_isherm[jj])
        else:
            raise ValueError('Error in ODE solver')

    return expect_out
Beispiel #7
0
def _ssepdpsolve_single_trajectory(data, Heff, dt, times, N_store, N_substeps,
                                   psi_t, dims, c_ops, e_ops):
    """
    Internal function. See ssepdpsolve.
    """
    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(times):

        if e_ops:
            for e_idx, e in enumerate(e_ops):
                s = cy_expect_psi_csr(e.data.data, e.data.indices,
                                      e.data.indptr, psi_t, 0)
                data.expect[e_idx, t_idx] += s
                data.ss[e_idx, t_idx] += s**2
        else:
            states_list.append(Qobj(psi_t, dims=dims))

        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(times[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
Beispiel #8
0
def _mc_alg_evolve(nt, args, config):
    """
    Monte-Carlo algorithm returning state-vector or expectation values
    at times tlist for a single trajectory.
    """

    global _cy_rhs_func
    global _cy_col_spmv_func, _cy_col_expect_func
    global _cy_col_spmv_call_func, _cy_col_expect_call_func

    if not _cy_rhs_func:
        _mc_func_load(config)

    try:
        # get input data
        mc_alg_out, opt, tlist, num_times, seeds = args

        collapse_times = []  # times of collapses
        which_oper = []  # which operator did the collapse

        # SEED AND RNG AND GENERATE
        prng = RandomState(seeds[nt])
        # first rand is collapse norm, second is which operator
        rand_vals = prng.rand(2)

        # CREATE ODE OBJECT CORRESPONDING TO DESIRED TIME-DEPENDENCE
        if config.tflag in array([1, 10, 11]):
            ODE = ode(_cy_rhs_func)
            code = compile("ODE.set_f_params(" + config.string + ")", "<string>", "exec")
            exec(code)
        elif config.tflag == 2:
            ODE = ode(_cRHStd)
            ODE.set_f_params(config)
        elif config.tflag in array([20, 22]):
            if config.options.rhs_with_state:
                ODE = ode(_tdRHStd_with_state)
            else:
                ODE = ode(_tdRHStd)
            ODE.set_f_params(config)
        elif config.tflag == 3:
            if config.options.rhs_with_state:
                ODE = ode(_pyRHSc_with_state)
            else:
                ODE = ode(_pyRHSc)
            ODE.set_f_params(config)
        else:
            ODE = ode(_cy_rhs_func)
            ODE.set_f_params(config.h_data, config.h_ind, config.h_ptr)

        # initialize ODE solver for RHS
        ODE.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,
        )

        # set initial conditions
        ODE.set_initial_value(config.psi0, tlist[0])

        # make array for collapse operator inds
        cinds = np.arange(config.c_num)

        # RUN ODE UNTIL EACH TIME IN TLIST
        for k in range(1, num_times):
            # ODE WHILE LOOP FOR INTEGRATE UP TO TIME TLIST[k]
            while ODE.t < tlist[k]:
                t_prev = ODE.t
                y_prev = ODE.y
                norm2_prev = dznrm2(ODE.y) ** 2
                # integrate up to tlist[k], one step at a time.
                ODE.integrate(tlist[k], step=1)
                if not ODE.successful():
                    raise Exception("ZVODE failed!")
                # check if ODE jumped over tlist[k], if so,
                # integrate until tlist exactly
                if ODE.t > tlist[k]:
                    ODE.set_initial_value(y_prev, t_prev)
                    ODE.integrate(tlist[k], step=0)
                    if not ODE.successful():
                        raise Exception("ZVODE failed!")
                norm2_psi = dznrm2(ODE.y) ** 2
                if norm2_psi <= rand_vals[0]:  # <== collapse has occured
                    # find collapse time to within specified tolerance
                    # ---------------------------------------------------
                    ii = 0
                    t_final = ODE.t
                    while ii < config.norm_steps:
                        ii += 1
                        t_guess = t_prev + np.log(norm2_prev / rand_vals[0]) / np.log(norm2_prev / norm2_psi) * (
                            t_final - t_prev
                        )
                        ODE.set_initial_value(y_prev, t_prev)
                        ODE.integrate(t_guess, step=0)
                        if not ODE.successful():
                            raise Exception("ZVODE failed after adjusting step size!")
                        norm2_guess = dznrm2(ODE.y) ** 2
                        if np.abs(rand_vals[0] - norm2_guess) < config.norm_tol * rand_vals[0]:
                            break
                        elif norm2_guess < rand_vals[0]:
                            # t_guess is still > t_jump
                            t_final = t_guess
                            norm2_psi = norm2_guess
                        else:
                            # t_guess < t_jump
                            t_prev = t_guess
                            y_prev = ODE.y
                            norm2_prev = norm2_guess
                    if ii > config.norm_steps:
                        raise Exception(
                            "Norm tolerance not reached. "
                            + "Increase accuracy of ODE solver or "
                            + "Options.norm_steps."
                        )
                    # ---------------------------------------------------
                    collapse_times.append(ODE.t)

                    # some string based collapse operators
                    if config.tflag in array([1, 11]):
                        n_dp = [
                            cy_expect_psi_csr(config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE.y, 1)
                            for i in config.c_const_inds
                        ]

                        _locals = locals()
                        # calculates the expectation values for time-dependent
                        # norm collapse operators
                        exec(_cy_col_expect_call_func, globals(), _locals)
                        n_dp = array(_locals["n_dp"])

                    # some Python function based collapse operators
                    elif config.tflag in array([2, 20, 22]):
                        n_dp = [
                            cy_expect_psi_csr(config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE.y, 1)
                            for i in config.c_const_inds
                        ]
                        n_dp += [
                            abs(config.c_funcs[i](ODE.t, config.c_func_args)) ** 2
                            * cy_expect_psi_csr(
                                config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE.y, 1
                            )
                            for i in config.c_td_inds
                        ]
                        n_dp = array(n_dp)
                    # all constant collapse operators.
                    else:
                        n_dp = array(
                            [
                                cy_expect_psi_csr(
                                    config.n_ops_data[i], config.n_ops_ind[i], config.n_ops_ptr[i], ODE.y, 1
                                )
                                for i in range(config.c_num)
                            ]
                        )

                    # determine which operator does collapse and store it
                    kk = cumsum(n_dp / sum(n_dp))
                    j = cinds[kk >= rand_vals[1]][0]
                    which_oper.append(j)
                    if j in config.c_const_inds:
                        state = spmv_csr(config.c_ops_data[j], config.c_ops_ind[j], config.c_ops_ptr[j], ODE.y)
                    else:
                        if config.tflag in array([1, 11]):
                            _locals = locals()
                            # calculates the state vector for collapse by a
                            # time-dependent collapse operator
                            exec(_cy_col_spmv_call_func, globals(), _locals)
                            state = _locals["state"]
                        else:
                            state = config.c_funcs[j](ODE.t, config.c_func_args) * spmv_csr(
                                config.c_ops_data[j], config.c_ops_ind[j], config.c_ops_ptr[j], ODE.y
                            )
                    state = state / dznrm2(state)
                    ODE.set_initial_value(state, ODE.t)
                    rand_vals = prng.rand(2)
            # -------------------------------------------------------

            # -- after while loop --
            out_psi = ODE.y / dznrm2(ODE.y)
            if config.e_num == 0:
                out_psi = sp.csr_matrix(np.reshape(out_psi, (out_psi.shape[0], 1)), dtype=complex)
                if config.options.average_states and not config.options.steady_state_average:
                    mc_alg_out[k] = Qobj(
                        out_psi * out_psi.conj().transpose(),
                        [config.psi0_dims[0], config.psi0_dims[0]],
                        [config.psi0_shape[0], config.psi0_shape[0]],
                        fast="mc-dm",
                    )

                elif config.options.steady_state_average:
                    mc_alg_out[0] = mc_alg_out[0] + (out_psi * out_psi.conj().transpose())

                else:
                    mc_alg_out[k] = Qobj(out_psi, config.psi0_dims, config.psi0_shape, fast="mc")
            else:
                for jj in range(config.e_num):
                    mc_alg_out[jj][k] = cy_expect_psi_csr(
                        config.e_ops_data[jj],
                        config.e_ops_ind[jj],
                        config.e_ops_ptr[jj],
                        out_psi,
                        config.e_ops_isherm[jj],
                    )

        # Run at end of mc_alg function
        # ------------------------------
        if config.options.steady_state_average:
            mc_alg_out = array(
                [
                    Qobj(
                        mc_alg_out[0] / float(len(tlist)),
                        [config.psi0_dims[0], config.psi0_dims[0]],
                        [config.psi0_shape[0], config.psi0_shape[0]],
                        fast="mc-dm",
                    )
                ]
            )

        return (nt, mc_alg_out, np.array(collapse_times, dtype=float), np.array(which_oper, dtype=int))

    except Exception as e:
        print("failed to run _mc_alg_evolve: " + str(e))
Beispiel #9
0
def _no_collapse_expect_out(num_times, expect_out, config):
    """
    Calculates expect.values at times tlist if no collapse ops. given
    """

    global _cy_rhs_func
    global _cy_col_spmv_func, _cy_col_expect_func
    global _cy_col_spmv_call_func, _cy_col_expect_call_func

    if debug:
        print(inspect.stack()[0][3])

    if not _cy_rhs_func:
        _mc_func_load(config)

    opt = config.options
    if config.tflag in array([1, 10, 11]):
        ODE = ode(_cy_rhs_func)
        code = compile("ODE.set_f_params(" + config.string + ")", "<string>", "exec")
        exec(code)
    elif config.tflag == 2:
        ODE = ode(_cRHStd)
        ODE.set_f_params(config)
    elif config.tflag in array([20, 22]):
        if config.options.rhs_with_state:
            ODE = ode(_tdRHStd_with_state)
        else:
            ODE = ode(_tdRHStd)
        ODE.set_f_params(config)
    elif config.tflag == 3:
        if config.options.rhs_with_state:
            ODE = ode(_pyRHSc_with_state)
        else:
            ODE = ode(_pyRHSc)
        ODE.set_f_params(config)
    else:
        ODE = ode(cy_ode_rhs)
        ODE.set_f_params(config.h_data, config.h_ind, config.h_ptr)

    ODE.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,
    )
    ODE.set_initial_value(config.psi0, config.tlist[0])
    for jj in range(config.e_num):
        expect_out[jj][0] = cy_expect_psi_csr(
            config.e_ops_data[jj], config.e_ops_ind[jj], config.e_ops_ptr[jj], config.psi0, config.e_ops_isherm[jj]
        )

    for k in range(1, num_times):
        ODE.integrate(config.tlist[k], step=0)  # integrate up to tlist[k]
        if ODE.successful():
            state = ODE.y / dznrm2(ODE.y)
            for jj in range(config.e_num):
                expect_out[jj][k] = cy_expect_psi_csr(
                    config.e_ops_data[jj], config.e_ops_ind[jj], config.e_ops_ptr[jj], state, config.e_ops_isherm[jj]
                )
        else:
            raise ValueError("Error in ODE solver")

    return expect_out
Beispiel #10
0
    def run(self):

        if debug:
            print(inspect.stack()[0][3])

        if self.config.c_num == 0:
            if self.config.ntraj != 1:
                # ntraj != 1 is pointless for no collapse operators
                self.config.ntraj = 1
            if self.config.e_num == 0:  # return psi at each requested time
                self.psi_out = _no_collapse_psi_out(self.num_times, self.psi_out, self.config)
            else:  # return expectation values of requested operators
                self.expect_out = _no_collapse_expect_out(self.num_times, self.expect_out, self.config)

        elif self.config.c_num != 0:

            if self.seeds is None:
                self.seeds = random_integers(1e8, size=self.config.ntraj)
            # else:
            #    if len(self.seeds) != self.config.ntraj:
            #        raise "Incompatible size of seeds vector in config."

            if self.config.e_num == 0:
                if config.options.steady_state_average:
                    mc_alg_out = zeros((1), dtype=object)
                else:
                    mc_alg_out = zeros((self.num_times), dtype=object)
                temp = sp.csr_matrix(np.reshape(self.config.psi0, (self.config.psi0.shape[0], 1)), dtype=complex)
                if self.config.options.average_states and not config.options.steady_state_average:
                    # output is averaged states, so use dm
                    mc_alg_out[0] = Qobj(
                        temp * temp.conj().transpose(),
                        [config.psi0_dims[0], config.psi0_dims[0]],
                        [config.psi0_shape[0], config.psi0_shape[0]],
                        fast="mc-dm",
                    )
                elif not self.config.options.average_states and not config.options.steady_state_average:
                    # output is not averaged, so write state vectors
                    mc_alg_out[0] = Qobj(temp, config.psi0_dims, config.psi0_shape, fast="mc")
                elif config.options.steady_state_average:
                    mc_alg_out[0] = temp * temp.conj().transpose()

            else:
                # PRE-GENERATE LIST OF EXPECTATION VALUES
                mc_alg_out = []
                for i in range(self.config.e_num):
                    if self.config.e_ops_isherm[i]:
                        # preallocate real array of zeros
                        mc_alg_out.append(zeros(self.num_times, dtype=float))
                    else:
                        # preallocate complex array of zeros
                        mc_alg_out.append(zeros(self.num_times, dtype=complex))

                    mc_alg_out[i][0] = cy_expect_psi_csr(
                        self.config.e_ops_data[i],
                        self.config.e_ops_ind[i],
                        self.config.e_ops_ptr[i],
                        self.config.psi0,
                        self.config.e_ops_isherm[i],
                    )

            # set arguments for input to monte-carlo
            args = (mc_alg_out, self.config.options, self.config.tlist, self.num_times, self.seeds)

            self.config.progress_bar.start(self.config.ntraj)
            self.parallel(args, self)
            self.config.progress_bar.finished()
Beispiel #11
0
    def __init__(self, config):

        # -----------------------------------
        # INIT MC CLASS
        # -----------------------------------

        self.config = config

        # ----MAIN OBJECT PROPERTIES--------------------
        # holds instance of the ProgressBar class
        self.bar = None
        # holds instance of the Pthread class
        self.thread = None
        # Number of completed trajectories
        self.count = 0
        # step-size for count attribute
        self.step = 1
        # Percent of trajectories completed
        self.percent = 0.0
        # used in implimenting the command line progress ouput
        self.level = 0.1
        # times at which to output state vectors or expectation values
        # number of time steps in tlist
        self.num_times = len(self.config.tlist)
        # holds seed for random number generator
        self.seeds = self.config.options.seeds
        # number of cpus to be used
        self.cpus = self.config.options.num_cpus
        # set output variables, even if they are not used to simplify output
        # code.
        self.psi_out = None
        self.expect_out = []
        self.collapse_times_out = None
        self.which_op_out = None

        # FOR EVOLUTION FOR NO COLLAPSE OPERATORS
        if config.c_num == 0:
            if config.e_num == 0:
                # Output array of state vectors calculated at times in tlist
                self.psi_out = array([Qobj()] * self.num_times)
            elif config.e_num != 0:  # no collapse expectation values
                # List of output expectation values calculated at times in
                # tlist
                self.expect_out = []
                for i in range(config.e_num):
                    if config.e_ops_isherm[i]:
                        # preallocate real array of zeros
                        self.expect_out.append(zeros(self.num_times, dtype=float))
                    else:  # preallocate complex array of zeros
                        self.expect_out.append(zeros(self.num_times, dtype=complex))
                    self.expect_out[i][0] = cy_expect_psi_csr(
                        config.e_ops_data[i],
                        config.e_ops_ind[i],
                        config.e_ops_ptr[i],
                        config.psi0,
                        config.e_ops_isherm[i],
                    )

        # FOR EVOLUTION WITH COLLAPSE OPERATORS
        elif config.c_num != 0:
            # preallocate #ntraj arrays for state vectors, collapse times, and
            # which operator
            self.collapse_times_out = zeros((config.ntraj), dtype=ndarray)
            self.which_op_out = zeros((config.ntraj), dtype=ndarray)
            if config.e_num == 0:
                # if no expectation operators, preallocate #ntraj arrays
                # for state vectors
                if self.config.options.steady_state_average:
                    self.psi_out = array([zeros((1), dtype=object) for q in range(config.ntraj)])
                else:
                    self.psi_out = array([zeros((self.num_times), dtype=object) for q in range(config.ntraj)])

            else:  # preallocate array of lists for expectation values
                self.expect_out = [[] for x in range(config.ntraj)]
Beispiel #12
0
def _sepdpsolve_single_trajectory(data, Heff, dt, tlist, N_store, N_substeps,
                                  psi_t, c_ops, e_ops):
    """
    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_psi_csr(
                    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
Beispiel #13
0
def _ssesolve_single_trajectory(data, H, dt, tlist, N_store, N_substeps, psi_t,
                                A_ops, e_ops, m_ops, rhs, d1, d2, d2_len,
                                dW_factors, homogeneous, distribution, args,
                                store_measurement=False, noise=None,
                                normalize=True):
    """
    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(m_ops), d2_len), dtype=complex)

    for t_idx, t in enumerate(tlist):

        if e_ops:
            for e_idx, e in enumerate(e_ops):
                s = cy_expect_psi_csr(e.data.data, e.data.indices, e.data.indptr, psi_t, 0)
                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], 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
            if normalize:
                psi_t /= norm(psi_t)

        if store_measurement:
            for m_idx, m in enumerate(m_ops):
                for dW_idx, dW_factor in enumerate(dW_factors):
                    if m[dW_idx]:
                        m_expt = norm(spmv(m[dW_idx].data, psi_prev)) ** 2
                    else:
                        m_expt = 0
                    measurements[t_idx, m_idx, dW_idx] = (m_expt +
                       dW_factor * dW[m_idx, t_idx, :, dW_idx].sum() / (dt * N_substeps))

    if d2_len == 1:
        measurements = measurements.squeeze(axis=(2))

    return states_list, dW, measurements
Beispiel #14
0
def _mc_alg_evolve(nt, config, opt, seeds):
    """
    Monte Carlo algorithm returning state-vector or expectation values
    at times tlist for a single trajectory.
    """

    global _cy_rhs_func
    global _cy_col_spmv_func, _cy_col_expect_func
    global _cy_col_spmv_call_func, _cy_col_expect_call_func

    tlist = config.tlist
    num_times = len(tlist)

    if not _cy_rhs_func:
        _mc_func_load(config)

    if config.options.steady_state_average:
        states_out = np.zeros((1), dtype=object)
    else:
        states_out = np.zeros((num_times), dtype=object)

    temp = sp.csr_matrix(
        np.reshape(config.psi0, (config.psi0.shape[0], 1)),
        dtype=complex)
    if (config.options.average_states and
            not config.options.steady_state_average):
        # output is averaged states, so use dm
        states_out[0] = Qobj(temp*temp.conj().transpose(),
                             [config.psi0_dims[0],
                              config.psi0_dims[0]],
                             [config.psi0_shape[0],
                              config.psi0_shape[0]],
                             fast='mc-dm')
    elif (not config.options.average_states and
          not config.options.steady_state_average):
        # output is not averaged, so write state vectors
        states_out[0] = Qobj(temp, config.psi0_dims,
                             config.psi0_shape, fast='mc')
    elif config.options.steady_state_average:
        states_out[0] = temp * temp.conj().transpose()

    # PRE-GENERATE LIST FOR EXPECTATION VALUES
    expect_out = []
    for i in range(config.e_num):
        if config.e_ops_isherm[i]:
            # preallocate real array of zeros
            expect_out.append(np.zeros(num_times, dtype=float))
        else:
            # preallocate complex array of zeros
            expect_out.append(np.zeros(num_times, dtype=complex))

        expect_out[i][0] = \
            cy_expect_psi_csr(config.e_ops_data[i],
                              config.e_ops_ind[i],
                              config.e_ops_ptr[i],
                              config.psi0,
                              config.e_ops_isherm[i])

    collapse_times = []
    which_oper = []

    # SEED AND RNG AND GENERATE
    prng = RandomState(seeds[nt])
    # first rand is collapse norm, second is which operator
    rand_vals = prng.rand(2)

    # CREATE ODE OBJECT CORRESPONDING TO DESIRED TIME-DEPENDENCE
    if config.tflag in [1, 10, 11]:
        ODE = ode(_cy_rhs_func)
        code = compile('ODE.set_f_params(' + config.string + ')',
                       '<string>', 'exec')
        exec(code)
    elif config.tflag == 2:
        ODE = ode(_cRHStd)
        ODE.set_f_params(config)
    elif config.tflag in [20, 22]:
        if config.options.rhs_with_state:
            ODE = ode(_tdRHStd_with_state)
        else:
            ODE = ode(_tdRHStd)
        ODE.set_f_params(config)
    elif config.tflag == 3:
        if config.options.rhs_with_state:
            ODE = ode(_pyRHSc_with_state)
        else:
            ODE = ode(_pyRHSc)
        ODE.set_f_params(config)
    else:
        ODE = ode(_cy_rhs_func)
        ODE.set_f_params(config.h_data, config.h_ind,
                         config.h_ptr)

    # initialize ODE solver for RHS
    ODE._integrator = qutip_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)

    if not len(ODE._y):
        ODE.t = 0.0
        ODE._y = np.array([0.0], complex)
    ODE._integrator.reset(len(ODE._y), ODE.jac is not None)

    # set initial conditions
    ODE.set_initial_value(config.psi0, tlist[0])

    # make array for collapse operator inds
    cinds = np.arange(config.c_num)

    # RUN ODE UNTIL EACH TIME IN TLIST
    for k in range(1, num_times):
        # ODE WHILE LOOP FOR INTEGRATE UP TO TIME TLIST[k]
        while ODE.t < tlist[k]:
            t_prev = ODE.t
            y_prev = ODE.y
            norm2_prev = dznrm2(ODE._y) ** 2
            # integrate up to tlist[k], one step at a time.
            ODE.integrate(tlist[k], step=1)
            if not ODE.successful():
                raise Exception("ZVODE failed!")
            norm2_psi = dznrm2(ODE._y) ** 2
            if norm2_psi <= rand_vals[0]:
                # collapse has occured:
                # find collapse time to within specified tolerance
                # ------------------------------------------------
                ii = 0
                t_final = ODE.t
                while ii < config.norm_steps:
                    ii += 1
                    t_guess = t_prev + \
                        np.log(norm2_prev / rand_vals[0]) / \
                        np.log(norm2_prev / norm2_psi) * (t_final - t_prev)
                    ODE._y = y_prev
                    ODE.t = t_prev
                    ODE._integrator.call_args[3] = 1
                    ODE.integrate(t_guess, step=0)
                    if not ODE.successful():
                        raise Exception(
                            "ZVODE failed after adjusting step size!")
                    norm2_guess = dznrm2(ODE._y)**2
                    if (np.abs(rand_vals[0] - norm2_guess) <
                            config.norm_tol * rand_vals[0]):
                        break
                    elif (norm2_guess < rand_vals[0]):
                        # t_guess is still > t_jump
                        t_final = t_guess
                        norm2_psi = norm2_guess
                    else:
                        # t_guess < t_jump
                        t_prev = t_guess
                        y_prev = ODE.y
                        norm2_prev = norm2_guess
                if ii > config.norm_steps:
                    raise Exception("Norm tolerance not reached. " +
                                    "Increase accuracy of ODE solver or " +
                                    "Options.norm_steps.")

                collapse_times.append(ODE.t)

                # some string based collapse operators
                if config.tflag in [1, 11]:
                    n_dp = [cy_expect_psi_csr(config.n_ops_data[i],
                                              config.n_ops_ind[i],
                                              config.n_ops_ptr[i],
                                              ODE._y, 1)
                            for i in config.c_const_inds]

                    _locals = locals()
                    # calculates the expectation values for time-dependent
                    # norm collapse operators
                    exec(_cy_col_expect_call_func, globals(), _locals)
                    n_dp = np.array(_locals['n_dp'])

                elif config.tflag in [2, 20, 22]:
                    # some Python function based collapse operators
                    n_dp = [cy_expect_psi_csr(config.n_ops_data[i],
                                              config.n_ops_ind[i],
                                              config.n_ops_ptr[i],
                                              ODE._y, 1)
                            for i in config.c_const_inds]
                    n_dp += [abs(config.c_funcs[i](
                                 ODE.t, config.c_func_args)) ** 2 *
                             cy_expect_psi_csr(config.n_ops_data[i],
                                               config.n_ops_ind[i],
                                               config.n_ops_ptr[i],
                                               ODE._y, 1)
                             for i in config.c_td_inds]
                    n_dp = np.array(n_dp)
                else:
                    # all constant collapse operators.
                    n_dp = np.array(
                        [cy_expect_psi_csr(config.n_ops_data[i],
                                           config.n_ops_ind[i],
                                           config.n_ops_ptr[i],
                                           ODE._y, 1)
                         for i in range(config.c_num)])

                # determine which operator does collapse and store it
                kk = np.cumsum(n_dp / np.sum(n_dp))
                j = cinds[kk >= rand_vals[1]][0]
                which_oper.append(j)
                if j in config.c_const_inds:
                    state = spmv_csr(config.c_ops_data[j],
                                     config.c_ops_ind[j],
                                     config.c_ops_ptr[j], ODE._y)
                else:
                    if config.tflag in [1, 11]:
                        _locals = locals()
                        # calculates the state vector for collapse by a
                        # time-dependent collapse operator
                        exec(_cy_col_spmv_call_func, globals(), _locals)
                        state = _locals['state']
                    else:
                        state = \
                            config.c_funcs[j](ODE.t,
                                              config.c_func_args) * \
                            spmv_csr(config.c_ops_data[j],
                                     config.c_ops_ind[j],
                                     config.c_ops_ptr[j], ODE._y)
                state = state / dznrm2(state)
                ODE._y = state
                ODE._integrator.call_args[3] = 1
                rand_vals = prng.rand(2)

        # after while loop
        # ----------------
        out_psi = ODE._y / dznrm2(ODE._y)
        if config.e_num == 0 or config.options.store_states:
            out_psi_csr = sp.csr_matrix(np.reshape(out_psi,
                                                   (out_psi.shape[0], 1)),
                                        dtype=complex)
            if (config.options.average_states and
                    not config.options.steady_state_average):
                states_out[k] = Qobj(
                    out_psi_csr * out_psi_csr.conj().transpose(),
                    [config.psi0_dims[0], config.psi0_dims[0]],
                    [config.psi0_shape[0], config.psi0_shape[0]],
                    fast='mc-dm')

            elif config.options.steady_state_average:
                states_out[0] = (
                    states_out[0] +
                    (out_psi_csr * out_psi_csr.conj().transpose()))

            else:
                states_out[k] = Qobj(out_psi_csr, config.psi0_dims,
                                     config.psi0_shape, fast='mc')

        for jj in range(config.e_num):
            expect_out[jj][k] = cy_expect_psi_csr(
                config.e_ops_data[jj], config.e_ops_ind[jj],
                config.e_ops_ptr[jj], out_psi,
                config.e_ops_isherm[jj])

    # Run at end of mc_alg function
    # -----------------------------
    if config.options.steady_state_average:
        states_out = np.array([Qobj(states_out[0] / float(len(tlist)),
                              [config.psi0_dims[0],
                               config.psi0_dims[0]],
                              [config.psi0_shape[0],
                               config.psi0_shape[0]],
                              fast='mc-dm')])

    return (states_out, expect_out,
            np.array(collapse_times, dtype=float),
            np.array(which_oper, dtype=int))
Beispiel #15
0
def _evolve_no_collapse_expect_out(config):
    """
    Calculates expect.values at times tlist if no collapse ops. given
    """

    global _cy_rhs_func
    global _cy_col_spmv_func, _cy_col_expect_func
    global _cy_col_spmv_call_func, _cy_col_expect_call_func

    if debug:
        print(inspect.stack()[0][3])

    num_times = len(config.tlist)
    expect_out = []
    for i in range(config.e_num):
        if config.e_ops_isherm[i]:
            # preallocate real array of zeros
            expect_out.append(np.zeros(num_times, dtype=float))
        else:
            # preallocate complex array of zeros
            expect_out.append(np.zeros(num_times, dtype=complex))

        expect_out[i][0] = \
            cy_expect_psi_csr(config.e_ops_data[i],
                              config.e_ops_ind[i],
                              config.e_ops_ptr[i],
                              config.psi0,
                              config.e_ops_isherm[i])

    if not _cy_rhs_func:
        _mc_func_load(config)

    opt = config.options
    if config.tflag in [1, 10, 11]:
        ODE = ode(_cy_rhs_func)
        code = compile('ODE.set_f_params(' + config.string + ')',
                       '<string>', 'exec')
        exec(code)
    elif config.tflag == 2:
        ODE = ode(_cRHStd)
        ODE.set_f_params(config)
    elif config.tflag in [20, 22]:
        if config.options.rhs_with_state:
            ODE = ode(_tdRHStd_with_state)
        else:
            ODE = ode(_tdRHStd)
        ODE.set_f_params(config)
    elif config.tflag == 3:
        if config.options.rhs_with_state:
            ODE = ode(_pyRHSc_with_state)
        else:
            ODE = ode(_pyRHSc)
        ODE.set_f_params(config)
    else:
        ODE = ode(cy_ode_rhs)
        ODE.set_f_params(config.h_data, config.h_ind, config.h_ptr)

    ODE.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)
    ODE.set_initial_value(config.psi0, config.tlist[0])
    for jj in range(config.e_num):
        expect_out[jj][0] = cy_expect_psi_csr(
            config.e_ops_data[jj], config.e_ops_ind[jj],
            config.e_ops_ptr[jj], config.psi0,
            config.e_ops_isherm[jj])

    for k in range(1, num_times):
        ODE.integrate(config.tlist[k], step=0)  # integrate up to tlist[k]
        if ODE.successful():
            state = ODE.y / dznrm2(ODE.y)
            for jj in range(config.e_num):
                expect_out[jj][k] = cy_expect_psi_csr(
                    config.e_ops_data[jj], config.e_ops_ind[jj],
                    config.e_ops_ptr[jj], state,
                    config.e_ops_isherm[jj])
        else:
            raise ValueError('Error in ODE solver')

    return expect_out