qudit_sim.pulse_sim

qudit_sim.pulse_sim(hgen, tlist=(10, 100), psi0=None, args=None, e_ops=None, keep_callable=False, final_only=False, reunitarize=True, interval_len=1000, options=None, save_result_to=None, log_level=logging.WARNING)

Run a pulse simulation.

Build the Hamiltonian terms from the HamiltonianBuilder, determine the time points for the simulation if necessary, and run qutip.sesolve.

Regardless of the setup of the input (Hamiltonian frame, initial state, and expectation ops), the simulation is run in the lab frame with the identity operator as the initial state to obtain the time evolution operator for each time point. The evolution operators are then frame-changed to the original frame of the input Hamiltonian before being applied to the initial state (or initial unitary). If expectation ops are given, their expectation values are computed from the resulting evolved states.

All parameters except options, save_result_to, and log_level can be given as lists to trigger a parallel (multiprocess) execution of sesolve. If more than one parameter is a list, their lengths must be identical, and all parameters are “zipped” together to form the argument lists of individual single simulation jobs.

Reunitarization of time evolution

Due to the finite numerical precision in solving the Schrodinger equation, the computed time evolution matrices will stop being unitary at some point, with the rate of divergence dependent on the complexity of the Hamiltonian. In general, the closest unitary \(U\), i.e., one with the smallest 2-norm \(\lVert U-A \rVert\), to an operator \(A\) can be calculated via a singular value decomposition:

\[\begin{split}A & = V \Sigma W^{\dagger}, \\ U & = V W^{\dagger}.\end{split}\]

This function has an option reunitarize to apply the above decomposition and recompute the time evolution matrices. Because reunitarizing at each time step can be rather slow (mostly because of the overhead in calling sesolve), when this option is turned on (default), sesolve is called in time intervals of length interval_len, and the entire array of evolution matrices from each interval is reunitarized (longer interval lengths result in larger reunitarization corrections).

Implementation notes (why we return an original object instead of the QuTiP result)

When the coefficients of the time-dependent Hamiltonian are compiled (preferred method), QuTiP creates a transient python module with file name generated from the code hash, PID, and the current time. When running multiple simulations in parallel this is not strictly safe, and so we enclose sesolve in a context with a temporary directory in this function. The transient module is then deleted at the end of execution, but that in turn causes an error when this function is called in a subprocess and if we try to return the QuTiP result object directly through e.g. multiprocessing.Pipe. Somehow the result object tries to carry with it something defined in the transient module, which would therefore need to be pickled together with the returned object. But the transient module file is gone by the time the parent process receives the result from the pipe. So, the solution was to just return a “sanitized” object, consisting of plain ndarrays.

Parameters
  • hgen (Union[HamiltonianBuilder, List[HamiltonianBuilder]]) – A HamiltonianBuilder or a list thereof.

  • tlist (Union[numpy.ndarray, Tuple[int, int], Dict[str, Union[int, float]], List[Union[numpy.ndarray, Tuple[int, int], Dict[str, Union[int, float]]]]]) – Time points to use in the simulation or a pair (points_per_cycle, num_cycles) where in the latter case the cycle of the fastest oscillating term in the Hamiltonian will be used.

  • psi0 (Union[Qobj, List[Qobj], None]) – Initial state Qobj. Defaults to the identity operator appropriate for the given Hamiltonian.

  • args (Optional[Any]) – Second parameter passed to drive amplitude functions (if callable).

  • e_ops (Union[Sequence[Qobj], List[Sequence[Qobj]], None]) – List of observables passed to the QuTiP solver.

  • keep_callable (Union[bool, List[bool]]) – Keep callable time-dependent Hamiltonian coefficients. Otherwise all callable coefficients are converted to arrays before simulation execution for efficiency (no loss of accuracy observed so far).

  • final_only (bool) – Throw away intermediate states and expectation values to save memory. Due to implementation details, implies unitarize_evolution=True.

  • reunitarize (bool) – Whether to reunitarize the time evolution matrices.

  • interval_len (int) – Number of time steps to run sesolve uninterrupted. Only used when reunitarize=True and psi0 is a unitary.

  • options (Optional[Options]) – QuTiP solver options.

  • save_result_to (Optional[str]) – File name (without the extension) to save the simulation result to.

  • log_level (int) – Log level.

Return type

Union[PulseSimResult, List[PulseSimResult]]

Returns

Result of the pulse simulation.