Ejemplo n.º 1
0
Archivo: wigner.py Proyecto: tmng/qutip
def _wigner_laguerre(rho, xvec, yvec, g, parallel):
    """
    Using Laguerre polynomials from scipy to evaluate the Wigner function for
    the density matrices :math:`|m><n|`, :math:`W_{mn}`. The total Wigner
    function is calculated as :math:`W = \sum_{mn} \\rho_{mn} W_{mn}`.
    """

    M = np.prod(rho.shape[0])
    X, Y = meshgrid(xvec, yvec)
    A = 0.5 * g * (X + 1.0j * Y)
    W = zeros(np.shape(A))

    # compute wigner functions for density matrices |m><n| and
    # weight by all the elements in the density matrix
    B = 4 * abs(A) ** 2
    if sp.isspmatrix_csr(rho.data):
        # for compress sparse row matrices
        if parallel:
            iterator = (
                (m, rho, A, B) for m in range(len(rho.data.indptr) - 1))
            W1_out = parfor(_par_wig_eval, iterator)
            W += sum(W1_out)
        else:
            for m in range(len(rho.data.indptr) - 1):
                for jj in range(rho.data.indptr[m], rho.data.indptr[m + 1]):
                    n = rho.data.indices[jj]

                    if m == n:
                        W += real(rho[m, m] * (-1) ** m * genlaguerre(m, 0)(B))

                    elif n > m:
                        W += 2.0 * real(rho[m, n] * (-1) ** m *
                                        (2 * A) ** (n - m) *
                                        sqrt(factorial(m) / factorial(n)) *
                                        genlaguerre(m, n - m)(B))
    else:
        # for dense density matrices
        B = 4 * abs(A) ** 2
        for m in range(M):
            if abs(rho[m, m]) > 0.0:
                W += real(rho[m, m] * (-1) ** m * genlaguerre(m, 0)(B))
            for n in range(m + 1, M):
                if abs(rho[m, n]) > 0.0:
                    W += 2.0 * real(rho[m, n] * (-1) ** m *
                                    (2 * A) ** (n - m) *
                                    sqrt(factorial(m) / factorial(n)) *
                                    genlaguerre(m, n - m)(B))

    return 0.5 * W * g ** 2 * np.exp(-B / 2) / pi
Ejemplo n.º 2
0
def _wigner_laguerre(rho, xvec, yvec, g, parallel):
    """
    Using Laguerre polynomials from scipy to evaluate the Wigner function for
    the density matrices :math:`|m><n|`, :math:`W_{mn}`. The total Wigner
    function is calculated as :math:`W = \sum_{mn} \\rho_{mn} W_{mn}`.
    """

    M = prod(rho.shape[0])
    X, Y = meshgrid(xvec, yvec)
    A = 0.5 * g * (X + 1.0j * Y)
    W = zeros(np.shape(A))

    # compute wigner functions for density matrices |m><n| and
    # weight by all the elements in the density matrix
    B = 4 * abs(A) ** 2
    if sp.isspmatrix_csr(rho.data):
        # for compress sparse row matrices
        if parallel:
            iterator = (
                (m, rho, A, B) for m in range(len(rho.data.indptr) - 1))
            W1_out = parfor(_par_wig_eval, iterator)
            W += sum(W1_out)
        else:
            for m in range(len(rho.data.indptr) - 1):
                for jj in range(rho.data.indptr[m], rho.data.indptr[m + 1]):
                    n = rho.data.indices[jj]

                    if m == n:
                        W += real(rho[m, m] * (-1) ** m * genlaguerre(m, 0)(B))

                    elif n > m:
                        W += 2.0 * real(rho[m, n] * (-1) ** m *
                                        (2 * A) ** (n - m) *
                                        sqrt(factorial(m) / factorial(n)) *
                                        genlaguerre(m, n - m)(B))
    else:
        # for dense density matrices
        B = 4 * abs(A) ** 2
        for m in range(M):
            if abs(rho[m, m]) > 0.0:
                W += real(rho[m, m] * (-1) ** m * genlaguerre(m, 0)(B))
            for n in range(m + 1, M):
                if abs(rho[m, n]) > 0.0:
                    W += 2.0 * real(rho[m, n] * (-1) ** m *
                                    (2 * A) ** (n - m) *
                                    sqrt(factorial(m) / factorial(n)) *
                                    genlaguerre(m, n - m)(B))

    return 0.5 * W * g ** 2 * np.exp(-B / 2) / pi
Ejemplo n.º 3
0
def mcsolve(H, psi0, tlist, c_ops, e_ops, ntraj=None, args={}, options=Options()):
    """Monte-Carlo evolution of a state vector :math:`|\psi \\rangle` for a
    given Hamiltonian and sets of collapse operators, and possibly, operators
    for calculating expectation values. Options for the underlying ODE solver
    are given by the Options class.

    mcsolve supports time-dependent Hamiltonians and collapse operators using
    either Python functions of strings to represent time-dependent
    coefficients. Note that, the system Hamiltonian MUST have at least one
    constant term.

    As an example of a time-dependent problem, consider a Hamiltonian with two
    terms ``H0`` and ``H1``, where ``H1`` is time-dependent with coefficient
    ``sin(w*t)``, and collapse operators ``C0`` and ``C1``, where ``C1`` is
    time-dependent with coeffcient ``exp(-a*t)``.  Here, w and a are constant
    arguments with values ``W`` and ``A``.

    Using the Python function time-dependent format requires two Python
    functions, one for each collapse coefficient. Therefore, this problem could
    be expressed as::

        def H1_coeff(t,args):
            return sin(args['w']*t)

        def C1_coeff(t,args):
            return exp(-args['a']*t)

        H=[H0,[H1,H1_coeff]]

        c_op_list=[C0,[C1,C1_coeff]]

        args={'a':A,'w':W}

    or in String (Cython) format we could write::

        H=[H0,[H1,'sin(w*t)']]

        c_op_list=[C0,[C1,'exp(-a*t)']]

        args={'a':A,'w':W}

    Constant terms are preferably placed first in the Hamiltonian and collapse
    operator lists.

    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    psi0 : qobj
        Initial state vector
    tlist : array_like
        Times at which results are recorded.
    ntraj : int
        Number of trajectories to run.
    c_ops : array_like
        single collapse operator or ``list`` or ``array`` of collapse
        operators.
    e_ops : array_like
        single operator or ``list`` or ``array`` of operators for calculating
        expectation values.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Options
        Instance of ODE solver options.

    Returns
    -------
    results : Result
        Object storing all results from simulation.

    """

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

    if ntraj is None:
        ntraj = options.ntraj

    if not psi0.isket:
        raise Exception("Initial state must be a state vector.")

    if isinstance(c_ops, Qobj):
        c_ops = [c_ops]

    if isinstance(e_ops, Qobj):
        e_ops = [e_ops]

    if isinstance(e_ops, dict):
        e_ops_dict = e_ops
        e_ops = [e for e in e_ops.values()]
    else:
        e_ops_dict = None

    config.options = options
    if isinstance(ntraj, list):
        config.progress_bar = TextProgressBar(max(ntraj))
    else:
        config.progress_bar = TextProgressBar(ntraj)

    # set num_cpus to the value given in qutip.settings if none in Options
    if not config.options.num_cpus:
        config.options.num_cpus = qutip.settings.num_cpus

    # set initial value data
    if options.tidy:
        config.psi0 = psi0.tidyup(options.atol).full().ravel()
    else:
        config.psi0 = psi0.full().ravel()

    config.psi0_dims = psi0.dims
    config.psi0_shape = psi0.shape

    # set options on ouput states
    if config.options.steady_state_average:
        config.options.average_states = True

    # set general items
    config.tlist = tlist
    if isinstance(ntraj, (list, ndarray)):
        config.ntraj = sort(ntraj)[-1]
    else:
        config.ntraj = ntraj

    # set norm finding constants
    config.norm_tol = options.norm_tol
    config.norm_steps = options.norm_steps

    # convert array based time-dependence to string format
    H, c_ops, args = _td_wrap_array_str(H, c_ops, args, tlist)

    # ----------------------------------------------
    # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING
    # ----------------------------------------------
    if (not options.rhs_reuse) or (not config.tdfunc):
        # reset config collapse and time-dependence flags to default values
        config.soft_reset()

        # check for type of time-dependence (if any)
        time_type, h_stuff, c_stuff = _td_format_check(H, c_ops, "mc")
        h_terms = len(h_stuff[0]) + len(h_stuff[1]) + len(h_stuff[2])
        c_terms = len(c_stuff[0]) + len(c_stuff[1]) + len(c_stuff[2])
        # set time_type for use in multiprocessing
        config.tflag = time_type

        # check for collapse operators
        if c_terms > 0:
            config.cflag = 1
        else:
            config.cflag = 0

        # Configure data
        _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options, config)

        # compile and load cython functions if necessary
        _mc_func_load(config)

    else:
        # setup args for new parameters when rhs_reuse=True and tdfunc is given
        # string based
        if config.tflag in array([1, 10, 11]):
            if any(args):
                config.c_args = []
                arg_items = args.items()
                for k in range(len(args)):
                    config.c_args.append(arg_items[k][1])
        # function based
        elif config.tflag in array([2, 3, 20, 22]):
            config.h_func_args = args

    # load monte-carlo class
    mc = _MC_class(config)

    # RUN THE SIMULATION
    mc.run()

    # remove RHS cython file if necessary
    if not options.rhs_reuse and config.tdname:
        try:
            os.remove(config.tdname + ".pyx")
        except:
            pass

    # AFTER MCSOLVER IS DONE --------------------------------------
    # ------- COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT --------------
    output = Result()
    output.solver = "mcsolve"
    # state vectors
    if mc.psi_out is not None and config.options.average_states and config.cflag and ntraj != 1:
        output.states = parfor(_mc_dm_avg, mc.psi_out.T)
    elif mc.psi_out is not None:
        output.states = mc.psi_out
    # expectation values
    elif mc.expect_out is not None and config.cflag and config.options.average_expect:
        # averaging if multiple trajectories
        if isinstance(ntraj, int):
            output.expect = [mean([mc.expect_out[nt][op] for nt in range(ntraj)], axis=0) for op in range(config.e_num)]
        elif isinstance(ntraj, (list, ndarray)):
            output.expect = []
            for num in ntraj:
                expt_data = mean(mc.expect_out[:num], axis=0)
                data_list = []
                if any([not op.isherm for op in e_ops]):
                    for k in range(len(e_ops)):
                        if e_ops[k].isherm:
                            data_list.append(np.real(expt_data[k]))
                        else:
                            data_list.append(expt_data[k])
                else:
                    data_list = [data for data in expt_data]
                output.expect.append(data_list)
    else:
        # no averaging for single trajectory or if average_states flag
        # (Options) is off
        if mc.expect_out is not None:
            output.expect = mc.expect_out

    # simulation parameters
    output.times = config.tlist
    output.num_expect = config.e_num
    output.num_collapse = config.c_num
    output.ntraj = config.ntraj
    output.col_times = mc.collapse_times_out
    output.col_which = mc.which_op_out

    if e_ops_dict:
        output.expect = {e: output.expect[n] for n, e in enumerate(e_ops_dict.keys())}

    return output
Ejemplo n.º 4
0
def mcsolve(H,
            psi0,
            tlist,
            c_ops,
            e_ops,
            ntraj=500,
            args={},
            options=Odeoptions()):
    """Monte-Carlo evolution of a state vector :math:`|\psi \\rangle` for a given
    Hamiltonian and sets of collapse operators, and possibly, operators
    for calculating expectation values. Options for the underlying ODE solver are 
    given by the Odeoptions class.
    
    mcsolve supports time-dependent Hamiltonians and collapse operators using either
    Python functions of strings to represent time-dependent coefficients.  Note that, 
    the system Hamiltonian MUST have at least one constant term.
    
    As an example of a time-dependent problem, consider a Hamiltonian with two terms ``H0``
    and ``H1``, where ``H1`` is time-dependent with coefficient ``sin(w*t)``, and collapse operators
    ``C0`` and ``C1``, where ``C1`` is time-dependent with coeffcient ``exp(-a*t)``.  Here, w and a are
    constant arguments with values ``W`` and ``A``.  
    
    Using the Python function time-dependent format requires two Python functions,
    one for each collapse coefficient. Therefore, this problem could be expressed as::
    
        def H1_coeff(t,args):
            return sin(args['w']*t)
    
        def C1_coeff(t,args):
            return exp(-args['a']*t)
    
        H=[H0,[H1,H1_coeff]]
    
        c_op_list=[C0,[C1,C1_coeff]]
    
        args={'a':A,'w':W}
    
    or in String (Cython) format we could write::
    
        H=[H0,[H1,'sin(w*t)']]
    
        c_op_list=[C0,[C1,'exp(-a*t)']]
    
        args={'a':A,'w':W}
    
    Constant terms are preferably placed first in the Hamiltonian and collapse 
    operator lists.
    
    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    psi0 : qobj 
        Initial state vector
    tlist : array_like 
        Times at which results are recorded.
    ntraj : int 
        Number of trajectories to run.
    c_ops : array_like 
        ``list`` or ``array`` of collapse operators.
    e_ops : array_like 
        ``list`` or ``array`` of operators for calculating expectation values.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Odeoptions
        Instance of ODE solver options.
    
    Returns
    -------
    results : Odedata    
        Object storing all results from simulation.
        
    """
    if psi0.type != 'ket':
        raise Exception("Initial state must be a state vector.")
    odeconfig.options = options
    #set num_cpus to the value given in qutip.settings if none in Odeoptions
    if not odeconfig.options.num_cpus:
        odeconfig.options.num_cpus = qutip.settings.num_cpus
    #set initial value data
    if options.tidy:
        odeconfig.psi0 = psi0.tidyup(options.atol).full()
    else:
        odeconfig.psi0 = psi0.full()
    odeconfig.psi0_dims = psi0.dims
    odeconfig.psi0_shape = psi0.shape
    #set general items
    odeconfig.tlist = tlist
    if isinstance(ntraj, (list, ndarray)):
        odeconfig.ntraj = sort(ntraj)[-1]
    else:
        odeconfig.ntraj = ntraj
    #set norm finding constants
    odeconfig.norm_tol = options.norm_tol
    odeconfig.norm_steps = options.norm_steps
    #----

    #----------------------------------------------
    # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING
    #----------------------------------------------
    if (not options.rhs_reuse) or (not odeconfig.tdfunc):
        #reset odeconfig collapse and time-dependence flags to default values
        _reset_odeconfig()

        #check for type of time-dependence (if any)
        time_type, h_stuff, c_stuff = _ode_checks(H, c_ops, 'mc')
        h_terms = len(h_stuff[0]) + len(h_stuff[1]) + len(h_stuff[2])
        c_terms = len(c_stuff[0]) + len(c_stuff[1]) + len(c_stuff[2])
        #set time_type for use in multiprocessing
        odeconfig.tflag = time_type

        #-Check for PyObjC on Mac platforms
        if sys.platform == 'darwin' and odeconfig.options.gui:
            try:
                import Foundation
            except:
                odeconfig.options.gui = False

        #check if running in iPython and using Cython compiling (then no GUI to work around error)
        if odeconfig.options.gui and odeconfig.tflag in array([1, 10, 11]):
            try:
                __IPYTHON__
            except:
                pass
            else:
                odeconfig.options.gui = False
        if qutip.settings.qutip_gui == "NONE":
            odeconfig.options.gui = False

        #check for collapse operators
        if c_terms > 0:
            odeconfig.cflag = 1
        else:
            odeconfig.cflag = 0

        #Configure data
        _mc_data_config(H, psi0, h_stuff, c_ops, c_stuff, args, e_ops, options)
        if odeconfig.tflag in array([1, 10,
                                     11]):  #compile time-depdendent RHS code
            os.environ['CFLAGS'] = '-O3 -w'
            import pyximport
            pyximport.install(
                setup_args={'include_dirs': [numpy.get_include()]})
            if odeconfig.tflag in array([1, 11]):
                code = compile(
                    'from ' + odeconfig.tdname +
                    ' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>',
                    'exec')
                exec(code, globals())
                odeconfig.tdfunc = cyq_td_ode_rhs
                odeconfig.colspmv = col_spmv
                odeconfig.colexpect = col_expect
            else:
                code = compile(
                    'from ' + odeconfig.tdname + ' import cyq_td_ode_rhs',
                    '<string>', 'exec')
                exec(code, globals())
                odeconfig.tdfunc = cyq_td_ode_rhs
            try:
                os.remove(odeconfig.tdname + ".pyx")
            except:
                print("Error removing pyx file.  File not found.")
        elif odeconfig.tflag == 0:
            odeconfig.tdfunc = cyq_ode_rhs
    else:  #setup args for new parameters when rhs_reuse=True and tdfunc is given
        #string based
        if odeconfig.tflag in array([1, 10, 11]):
            if any(args):
                odeconfig.c_args = []
                arg_items = args.items()
                for k in range(len(args)):
                    odeconfig.c_args.append(arg_items[k][1])
        #function based
        elif odeconfig.tflag in array([2, 3, 20, 22]):
            odeconfig.h_func_args = args

    #load monte-carlo class
    mc = _MC_class()
    #RUN THE SIMULATION
    mc.run()

    #AFTER MCSOLVER IS DONE --------------------------------------

    #-------COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT --------------#
    output = Odedata()
    output.solver = 'mcsolve'
    #state vectors
    if mc.psi_out != None and odeconfig.options.mc_avg and odeconfig.cflag:
        output.states = parfor(_mc_dm_avg, mc.psi_out.T)
    elif mc.psi_out != None:
        output.states = mc.psi_out
    #expectation values
    elif mc.expect_out != None and odeconfig.cflag and odeconfig.options.mc_avg:  #averaging if multiple trajectories
        if isinstance(ntraj, int):
            output.expect = mean(mc.expect_out, axis=0)
        elif isinstance(ntraj, (list, ndarray)):
            output.expect = []
            for num in ntraj:
                expt_data = mean(mc.expect_out[:num], axis=0)
                data_list = []
                if any([op.isherm == False for op in e_ops]):
                    for k in range(len(e_ops)):
                        if e_ops[k].isherm:
                            data_list.append(real(expt_data[k]))
                        else:
                            data_list.append(expt_data[k])
                else:
                    data_list = [data for data in expt_data]
                output.expect.append(data_list)
    else:  #no averaging for single trajectory or if mc_avg flag (Odeoptions) is off
        if mc.expect_out != None:
            output.expect = mc.expect_out

    #simulation parameters
    output.times = odeconfig.tlist
    output.num_expect = odeconfig.e_num
    output.num_collapse = odeconfig.c_num
    output.ntraj = odeconfig.ntraj
    output.col_times = mc.collapse_times_out
    output.col_which = mc.which_op_out
    return output
Ejemplo n.º 5
0
def mcsolve(H,psi0,tlist,c_ops,e_ops,ntraj=500,args={},options=Odeoptions()):
    """Monte-Carlo evolution of a state vector :math:`|\psi \\rangle` for a given
    Hamiltonian and sets of collapse operators, and possibly, operators
    for calculating expectation values. Options for the underlying ODE solver are 
    given by the Odeoptions class.
    
    mcsolve supports time-dependent Hamiltonians and collapse operators using either
    Python functions of strings to represent time-dependent coefficients.  Note that, 
    the system Hamiltonian MUST have at least one constant term.
    
    As an example of a time-dependent problem, consider a Hamiltonian with two terms ``H0``
    and ``H1``, where ``H1`` is time-dependent with coefficient ``sin(w*t)``, and collapse operators
    ``C0`` and ``C1``, where ``C1`` is time-dependent with coeffcient ``exp(-a*t)``.  Here, w and a are
    constant arguments with values ``W`` and ``A``.  
    
    Using the Python function time-dependent format requires two Python functions,
    one for each collapse coefficient. Therefore, this problem could be expressed as::
    
        def H1_coeff(t,args):
            return sin(args['w']*t)
    
        def C1_coeff(t,args):
            return exp(-args['a']*t)
    
        H=[H0,[H1,H1_coeff]]
    
        c_op_list=[C0,[C1,C1_coeff]]
    
        args={'a':A,'w':W}
    
    or in String (Cython) format we could write::
    
        H=[H0,[H1,'sin(w*t)']]
    
        c_op_list=[C0,[C1,'exp(-a*t)']]
    
        args={'a':A,'w':W}
    
    Constant terms are preferably placed first in the Hamiltonian and collapse 
    operator lists.
    
    Parameters
    ----------
    H : qobj
        System Hamiltonian.
    psi0 : qobj 
        Initial state vector
    tlist : array_like 
        Times at which results are recorded.
    ntraj : int 
        Number of trajectories to run.
    c_ops : array_like 
        single collapse operator or ``list`` or ``array`` of collapse operators.
    e_ops : array_like 
        single operator or ``list`` or ``array`` of operators for calculating expectation values.
    args : dict
        Arguments for time-dependent Hamiltonian and collapse operator terms.
    options : Odeoptions
        Instance of ODE solver options.
    
    Returns
    -------
    results : Odedata    
        Object storing all results from simulation.
        
    """


    # if single operator is passed for c_ops or e_ops, convert it to
    # list containing only that operator
    if isinstance(c_ops, Qobj):
        c_ops = [c_ops]
    if isinstance(e_ops, Qobj):
        e_ops = [e_ops]


    if psi0.type!='ket':
        raise Exception("Initial state must be a state vector.")
    odeconfig.options=options
    #set num_cpus to the value given in qutip.settings if none in Odeoptions
    if not odeconfig.options.num_cpus:
        odeconfig.options.num_cpus=qutip.settings.num_cpus
    #set initial value data
    if options.tidy:
        odeconfig.psi0=psi0.tidyup(options.atol).full()
    else:
        odeconfig.psi0=psi0.full()
    odeconfig.psi0_dims=psi0.dims
    odeconfig.psi0_shape=psi0.shape
    #set general items
    odeconfig.tlist=tlist
    if isinstance(ntraj,(list,ndarray)):
        odeconfig.ntraj=sort(ntraj)[-1]
    else:
        odeconfig.ntraj=ntraj
    #set norm finding constants
    odeconfig.norm_tol=options.norm_tol
    odeconfig.norm_steps=options.norm_steps
    #----
    
    #----------------------------------------------
    # SETUP ODE DATA IF NONE EXISTS OR NOT REUSING
    #----------------------------------------------
    if (not options.rhs_reuse) or (not odeconfig.tdfunc):
        #reset odeconfig collapse and time-dependence flags to default values
        _reset_odeconfig()
        
        #check for type of time-dependence (if any)
        time_type,h_stuff,c_stuff=_ode_checks(H,c_ops,'mc')
        h_terms=len(h_stuff[0])+len(h_stuff[1])+len(h_stuff[2])
        c_terms=len(c_stuff[0])+len(c_stuff[1])+len(c_stuff[2])
        #set time_type for use in multiprocessing
        odeconfig.tflag=time_type
        
        #-Check for PyObjC on Mac platforms
        if sys.platform=='darwin' and odeconfig.options.gui:
            try:
                import Foundation
            except:
                odeconfig.options.gui=False

        #check if running in iPython and using Cython compiling (then no GUI to work around error)
        if odeconfig.options.gui and odeconfig.tflag in array([1,10,11]):
            try:
                __IPYTHON__
            except:
                pass
            else:
                odeconfig.options.gui=False    
        if qutip.settings.qutip_gui=="NONE":
            odeconfig.options.gui=False

        #check for collapse operators
        if c_terms>0:
            odeconfig.cflag=1
        else:
            odeconfig.cflag=0
    
        #Configure data
        _mc_data_config(H,psi0,h_stuff,c_ops,c_stuff,args,e_ops,options)
        if odeconfig.tflag in array([1,10,11]): #compile time-depdendent RHS code
            os.environ['CFLAGS'] = '-O3 -w'
            import pyximport
            pyximport.install(setup_args={'include_dirs':[numpy.get_include()]})
            if odeconfig.tflag in array([1,11]):
                code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs,col_spmv,col_expect', '<string>', 'exec')
                exec(code, globals())
                odeconfig.tdfunc=cyq_td_ode_rhs
                odeconfig.colspmv=col_spmv
                odeconfig.colexpect=col_expect
            else:
                code = compile('from '+odeconfig.tdname+' import cyq_td_ode_rhs', '<string>', 'exec')
                exec(code, globals())
                odeconfig.tdfunc=cyq_td_ode_rhs
            try:
                os.remove(odeconfig.tdname+".pyx")
            except:
                print("Error removing pyx file.  File not found.")
        elif odeconfig.tflag==0:
            odeconfig.tdfunc=cyq_ode_rhs
    else:#setup args for new parameters when rhs_reuse=True and tdfunc is given
        #string based
        if odeconfig.tflag in array([1,10,11]):
            if any(args):
                odeconfig.c_args=[]
                arg_items=args.items()
                for k in range(len(args)):
                    odeconfig.c_args.append(arg_items[k][1])
        #function based
        elif odeconfig.tflag in array([2,3,20,22]):
            odeconfig.h_func_args=args
    
    
    #load monte-carlo class
    mc=_MC_class()
    #RUN THE SIMULATION
    mc.run()
    
    
    #AFTER MCSOLVER IS DONE --------------------------------------
    
    
    
    #-------COLLECT AND RETURN OUTPUT DATA IN ODEDATA OBJECT --------------#
    output=Odedata()
    output.solver='mcsolve'
    #state vectors
    if mc.psi_out is not None and odeconfig.options.mc_avg and odeconfig.cflag:
        output.states=parfor(_mc_dm_avg,mc.psi_out.T)
    elif mc.psi_out is not None:
        output.states=mc.psi_out
    #expectation values
    elif mc.expect_out is not None and odeconfig.cflag and odeconfig.options.mc_avg:#averaging if multiple trajectories
        if isinstance(ntraj,int):
            output.expect=mean(mc.expect_out,axis=0)
        elif isinstance(ntraj,(list,ndarray)):
            output.expect=[]
            for num in ntraj:
                expt_data=mean(mc.expect_out[:num],axis=0)
                data_list=[]
                if any([op.isherm==False for op in e_ops]):
                    for k in range(len(e_ops)):
                        if e_ops[k].isherm:
                            data_list.append(real(expt_data[k]))
                        else:
                            data_list.append(expt_data[k])
                else:
                    data_list=[data for data in expt_data]
                output.expect.append(data_list)
    else:#no averaging for single trajectory or if mc_avg flag (Odeoptions) is off
        if mc.expect_out is not None:        
            output.expect=mc.expect_out

    #simulation parameters
    output.times=odeconfig.tlist
    output.num_expect=odeconfig.e_num
    output.num_collapse=odeconfig.c_num
    output.ntraj=odeconfig.ntraj
    output.col_times=mc.collapse_times_out
    output.col_which=mc.which_op_out
    return output