Simulation Module

The simulation module contains time evolution engines for quantum systems.

Lindblad System

class qepsilon.simulation.LindbladSystem(num_states: int, batchsize: int = 1)[source]

Bases: Module

This class represents a generic open quantum system. The states are represented by a density matrix. The evolution of the system is governed by the Lindblad equation, which is a generalization of the Schrodinger equation for open quantum systems. Both the Hamiltonian and the jump operators here allows fluctuating coefficients. So technically, we are dealing with a stochastic master equation.

The Lindblad equation is given as \(d\rho(t) / dt = -i [H(t), \rho(t)] + \sum_k \gamma_k L_k(t) \rho(t) L_k(t)^\dagger - 1/2 \{L_k(t)^\dagger L_k(t), \rho(t)\}\) where \(H(t)\) is the Hamiltonian, \(L_k(t)\) is the jump operator. Note that the coefficients of the jump operators are absorbed into \(L_k(t)\).

In this class, each component of the Hamiltonian \(H(t)\), and each jump operator \(L_k(t)\), is represented by a OperatorGroup object. Each OperatorGroup object contains a group of operators and the corresponding coefficients. The operators themselves are time-independent, like a Pauli operator. But the coefficients can be time-dependent stochastic processes. This corresponds to the case where the qubits are coupled to noisy environments such as inhomogeneous, fluctuating magnetic fields.

__init__(num_states: int, batchsize: int = 1)[source]

Initialize internal Module state, shared by both nn.Module and ScriptModule.

to(device='cuda')[source]

This overrides the to method of PyTorch Module. It is used to move all relevant components of the system to a specific device.

property hamiltonian_operator_groups
property jumping_operator_groups
property channel_operator_groups
get_hamiltonian_operator_group_by_ID(id: str)[source]
get_jumping_operator_group_by_ID(id: str)[source]
get_channel_operator_group_by_ID(id: str)[source]
property rho

This property returns the density matrix of the system.

property hamiltonian
property jump
reset()[source]

Reset the system.

HamiltonianParameters()[source]
JumpingParameters()[source]
ChannelParameters()[source]
add_operator_group_to_hamiltonian(operator_group: OperatorGroup)[source]

This function adds an operator group to the Hamiltonian part of the system. :param operator_group: an OperatorGroup object, containing a group of operators and the corresponding coefficients.

add_operator_group_to_jumping(operator_group: OperatorGroup)[source]

This function adds an operator group to the jumping part of the system. :param operator_group: an OperatorGroup object, containing a group of operators and the corresponding coefficients.

add_operator_group_to_channel(operator_group: OperatorGroup)[source]

This function adds an operator group to the channel part of the system.

remove_operator_group_from_hamiltonian(id: str)[source]

This function removes an operator group from the Hamiltonian part of the system.

remove_operator_group_from_jumping(id: str)[source]

This function removes an operator group from the jumping part of the system.

remove_operator_group_from_channel(id: str)[source]

This function removes an operator group from the channel part of the system.

step_hamiltonian(dt: float, set_buffer: bool = False)[source]

This function steps the Hamiltonian for a time step dt. :param dt: a float, the time step.

Returns:

a (self.nb, self.ns, self.ns) tensor, the Hamiltonian operator at time t.

Return type:

hamiltonian

step_jumping(dt: float, set_buffer: bool = False)[source]

This function steps the density matrix for a time step dt. :param dt: a float, the time step.

Returns:

a list of (self.nb, self.ns, self.ns) tensors, the jump operators at time t.

Return type:

jump_operator_list

step_rho(dt: float, hamiltonian: Tensor, jump_operators: list[Tensor], time_independent: bool = False, profile: bool = False)[source]

This function steps the density matrix for a time step dt. :param dt: a float, the time step. :param hamiltonian: a (self.nb, self.ns, self.ns) tensor, the Hamiltonian operator at time t. :param jump_operators: a list of (self.nb, self.ns, self.ns) tensors, the jump operators at time t.

Returns:

a (self.nb, self.ns, self.ns) tensor, the density matrix at time t+dt.

Return type:

rho_new

normalize()[source]
step(dt: float, set_buffer: bool = False, time_independent: bool = False, profile: bool = False)[source]

This function steps the system for a time step dt.

step_unitary(dt: float, set_buffer: bool = False)[source]

This function steps the system for a time step dt without considering the jump operators.

observe(operator)[source]

This function observes the system with an operator.

class qepsilon.simulation.QubitLindbladSystem(n_qubits: int, batchsize: int)[source]

Bases: LindbladSystem

This class represents the states of n physical qubits as a open quantum system. The states are represented by a density matrix. The evolution of the system is governed by the Lindblad equation, which is a generalization of the Schrodinger equation for open quantum systems. Both the Hamiltonian and the jump operators in the Lindblad equation allows fluctuating coefficients. So technically, we are dealing with a stochastic master equation.

The Lindblad equation is given as \(d\rho(t) / dt = -i [H(t), \rho(t)] + \sum_k L_k(t) \rho(t) L_k(t)^\dagger - 1/2 \{L_k(t)^\dagger L_k(t), \rho(t)\}\) where \(H(t)\) is the Hamiltonian, \(L_k(t)\) is the jump operator. Note that the coefficients of the jump operators are absorbed into \(L_k(t)\).

In this class, each component of the Hamiltonian \(H(t)\), and each jump operator \(L_k(t)\), is represented by a OperatorGroup object. Each OperatorGroup object contains a group of operators and the corresponding coefficients. The operators themselves are time-independent, like a Pauli operator. But the coefficients can be time-dependent stochastic processes. This corresponds to the case where the qubits are coupled to noisy environments such as inhomogeneous, fluctuating magnetic fields.

__init__(n_qubits: int, batchsize: int)[source]

Initialize internal Module state, shared by both nn.Module and ScriptModule.

set_rho_by_config(config)[source]
rotate(direction: Tensor, angle: float, config=None, inplace: bool = True)[source]

Apply a rotation operator about the Cartesian axes in the Bloch Basis.

kraus_operate(kraus_operators: list[Tensor], config=None, inplace: bool = True)[source]

Apply a Kraus operation.

class qepsilon.simulation.ParticleLindbladSystem(n_qubits: int, batchsize: int, particles: Particles)[source]

Bases: QubitLindbladSystem

This class represents the states of n physical qubits as a open quantum system. The quantum states include the two-level states of each qubit and the center-of-mass position and momentum of each qubit. We take a ring-polymer (number of beads = p) representation of the center-of-mass state for sampling the qubit distribution. The two-level states will be represented by a (p x 2^n x 2^n) density matrix. The center-of-mass position will be represented by a (p x 3n) matrix.

For harmonic trapping with frequency omega, the number of beads needed for convergence can be estimated by (hbar omega / kT).

__init__(n_qubits: int, batchsize: int, particles: Particles)[source]

Initialize internal Module state, shared by both nn.Module and ScriptModule.

reset()[source]

Reset the system. In addition to the reset of the quantum system, the center-of-mass positions and momenta of the particles are also reset to arbitrary thermal states.

step_particles(dt: float)[source]

This function steps the thermal motino of the particles for a time step dt.

step(dt: float, set_buffer: bool = False, profile: bool = False)[source]

This function steps the system for a time step dt.

Unitary System

class qepsilon.simulation.UnitarySystem(num_states: int, batchsize: int = 1)[source]

Bases: Module

This class represents an ensemble of unitary pure quantum systems. Each pure state is represented by a vector. The evolution of the system is governed by Schrodinger equation for pure states.

In this class, each component of the Hamiltonian $H(t)$ is represented by a OperatorGroup object. Each OperatorGroup object contains a group of operators and the corresponding coefficients. The operators themselves are time-independent, like a Pauli operator. But the coefficients can be time-dependent stochastic processes. This corresponds to the case where the qubits are coupled to noisy environments such as inhomogeneous, fluctuating magnetic fields.

__init__(num_states: int, batchsize: int = 1)[source]

Initialize internal Module state, shared by both nn.Module and ScriptModule.

reset_evo()[source]
accumulate_evo(evo: Tensor)[source]
property evo
to(device='cuda')[source]

This overrides the to method of PyTorch Module. It is used to move all relevant components of the system to a specific device.

property hamiltonian_operator_groups
get_hamiltonian_operator_group_by_ID(id: str)[source]
property pse

This property returns the pure state ensemble of the system.

property hamiltonian
reset()[source]

Reset the system.

HamiltonianParameters()[source]
add_operator_group_to_hamiltonian(operator_group: OperatorGroup)[source]

This function adds an operator group to the Hamiltonian part of the system. :param operator_group: an OperatorGroup object, containing a group of operators and the corresponding coefficients.

remove_operator_group_from_hamiltonian(id: str)[source]

This function removes an operator group from the Hamiltonian part of the system.

normalize()[source]
step_hamiltonian(dt: float, set_buffer: bool = False, verbose: bool = False)[source]

This function steps the Hamiltonian for a time step dt. :param dt: a float, the time step.

Returns:

a (self.nb, self.ns, self.ns) tensor, the Hamiltonian operator at time t.

Return type:

hamiltonian

step_pse(dt: float, hamiltonian: Tensor, set_buffer=False, set_buffer_evo=False)[source]

This function steps the pure state ensemble for a time step dt with Euler’s method.

step(dt: float, set_buffer: bool = False, time_independent: bool = False, set_buffer_evo: bool = False, profile: bool = False)[source]

This function steps the system for a time step dt.

step_exact(dt: float, set_buffer: bool = False)[source]

This function steps the system for a time step dt using the exact matrix exponential method.

step_leap_frog(dt: float, set_buffer: bool = False)[source]

This function steps the system for a time step dt using the leap frog method. This only works for real-valued Hamiltonian.

step_AB_scheme(dt: float, set_buffer: bool = False)[source]

This function steps the system for a time step dt using the AB scheme. A is the diagonal part of the Hamiltonian, and B is the off-diagonal part. The step is given by: pse(t+dt) = (1 - 1j * dt * B) * exp(-dt * A) * pse(t)

observe(operator)[source]

This function observes the system with an operator.

class qepsilon.simulation.TightBindingUnitarySystem(n_sites: int, batchsize: int)[source]

Bases: UnitarySystem

This class represents the states of an ensemble of tight binding systems.

__init__(n_sites: int, batchsize: int)[source]

Initialize internal Module state, shared by both nn.Module and ScriptModule.

set_pse_by_config(config: Tensor)[source]
class qepsilon.simulation.QubitUnitarySystem(n_qubits: int, batchsize: int)[source]

Bases: UnitarySystem

This class represents the states of an ensemble of pure n-qubit systems. Each pure state is represented by a vector. The evolution of the system is governed by the Schrodinger equation.

In this class, each component of the Hamiltonian $H(t)$ is represented by a OperatorGroup object. Each OperatorGroup object contains a group of operators and the corresponding coefficients. The operators themselves are time-independent, like a Pauli operator. But the coefficients can be time-dependent stochastic processes. This corresponds to the case where the qubits are coupled to noisy environments such as inhomogeneous, fluctuating magnetic fields.

__init__(n_qubits: int, batchsize: int)[source]

Initialize internal Module state, shared by both nn.Module and ScriptModule.

set_pse_by_config(config)[source]
rotate(direction: Tensor, angle: float, config=None, inplace: bool = True)[source]

Apply a rotation operator about the Cartesian axes in the Bloch Basis.

Mixed Unitary System

class qepsilon.simulation.OscillatorQubitUnitarySystem(n_qubits: int, batchsize: int, cls_dt: float = 0.1)[source]

Bases: QubitUnitarySystem

This class represents the states of mixed classical quantum system. This class is not general since only (classical position * onsite number operator) type of classical-quantum coupling is supported. Implementation of other types of classical-quantum coupling is possible by modifying the bind_oscillators_to_qubit method and implementing the needed coupling operator as a OperatorGroup object.

The classical degrees of freedom are harmonic oscillators, represented by a Particles object. The quantum degrees of freedom are represented by a QubitPureEnsemble object.

__init__(n_qubits: int, batchsize: int, cls_dt: float = 0.1)[source]
Parameters:
  • n_qubits – int, the number of qubits.

  • batchsize – int, the batch size.

  • cls_dt – float, the time step of the classical oscillators.

get_oscilator_by_id(id: str)[source]
get_all_oscillators()[source]
reset(temp: float = None)[source]

Reset the system. In addition to the reset of the quantum system, the center-of-mass positions and momenta of the particles are also reset to arbitrary thermal states.

add_classical_oscillators(id: str, nmodes: int, freqs: Tensor, masses: Tensor, couplings: Tensor, x0: Tensor = None, init_temp: float = None, tau: float = None, unit: str = 'pm_ps')[source]

Add onsite classical oscillators to the system. :param id: str, the id of the oscillator. :param nmodes: int, the number of modes of the oscillator. :param freqs: th.Tensor, the frequencies of the oscillators. shape: (nmodes,) :param masses: th.Tensor, the masses of the oscillators. shape: (nmodes,) :param couplings: th.Tensor, the couplings between the oscillators and the qubits. shape: (nmodes,) :param x0: th.Tensor, the initial positions of the oscillators. shape: (nmodes, ndim) :param tau: float, the relaxation time of the oscillators. :param unit: str, the unit of the oscillator motion.

bind_oscillators_to_qubit(qubit_idx: int, oscillators_id: str, requires_grad: bool = False)[source]

Bind the oscillators to a qubit. Each oscillator is coupled to the qubit with interaction $g omega sqrt{2Momega} x hat{N}$. Here $g$ is the coupling strength, $omega$ is the frequency of the oscillator, $M$ is the mass of the oscillator, and $hat{N}$ is the number operator of the qubit.

step_particles(temp: float = None, feedback: bool = True)[source]

This function steps the thermal motino of the particles for a time step. There are two types of forces on the particles: 1. The harmonic force from the harmonic trap. 2. The binding force from the interaction between the oscillators and the qubit.

step(dt: float, temp: float = None, set_buffer: bool = False, profile: bool = False, feedback: bool = True)[source]

This function steps the system for a time step dt. Overrides the step function in the QubitUnitarySystem class.

class qepsilon.simulation.OscillatorTightBindingUnitarySystem(n_sites: int, batchsize: int, cls_dt: float = 0.1)[source]

Bases: TightBindingUnitarySystem

This class represents the states of mixed classical quantum system.

The classical degrees of freedom are harmonic oscillators, represented by a Particles object. The quantum degrees of freedom are represented by a TightBindingPureEnsemble object, i.e. single-particle tight binding system.

__init__(n_sites: int, batchsize: int, cls_dt: float = 0.1)[source]
Parameters:
  • n_sites – int, the number of sites.

  • batchsize – int, the batch size.

  • cls_dt – float, the time step of the classical oscillators.

get_oscilator_by_id(id: str)[source]
get_all_oscillators()[source]
reset(temp: float = None)[source]

Reset the system. In addition to the reset of the quantum system, the center-of-mass positions and momenta of the particles are also reset to arbitrary thermal states.

add_classical_oscillators(id: str, nmodes: int, freqs: Tensor, masses: Tensor, couplings: Tensor, x0: Tensor = None, init_temp: float = None, tau: float = None, unit: str = 'pm_ps')[source]

Add onsite classical oscillators to the system. :param id: str, the id of the oscillator. :param nmodes: int, the number of modes of the oscillator. :param freqs: th.Tensor, the frequencies of the oscillators. shape: (nmodes,) :param masses: th.Tensor, the masses of the oscillators. shape: (nmodes,) :param couplings: th.Tensor, the couplings between the oscillators and the tight-binding sites. shape: (nmodes,) :param x0: th.Tensor, the initial positions of the oscillators. shape: (batchsize, nmodes, ndim) or (nmodes, ndim) :param tau: float, the relaxation time of the oscillators. :param unit: str, the unit of the oscillator motion.

bind_oscillators_to_tb(site_idx: int, oscillators_id: str, requires_grad: bool = False)[source]

Bind the oscillators to a tight-binding site. Each oscillator is coupled to the tight-binding site with interaction $g omega sqrt{2Momega} x hat{N}$. Here $g$ is the coupling strength, $omega$ is the frequency of the oscillator, $M$ is the mass of the oscillator, and $hat{N}$ is the number operator of the tight-binding site.

step_particles(temp: float = None, feedback: bool = True)[source]

This function steps the thermal motino of the particles for a time step. There are two types of forces on the particles: 1. The harmonic force from the harmonic trap. 2. The binding force from the interaction between the oscillators and the tight-binding sites.

step(dt: float, temp: float = None, set_buffer: bool = False, profile: bool = False, feedback: bool = True)[source]

This function steps the system for a time step dt. Overrides the step function in the TightBindingUnitarySystem class.