qutip_qip.device

Simulation of quantum hardware.

Classes

Processor([num_qubits, dims, spline_kind, ...])

The noisy quantum device simulator using QuTiP dynamic solvers.

Model(num_qubits[, dims])

Template class for a physical model representing quantum hardware.

ModelProcessor([num_qubits, dims, ...])

The base class for a circuit processor simulating a physical device, e.g cavityQED, spinchain.

LinearSpinChain([num_qubits, ...])

Spin chain model with open-end topology.

CircularSpinChain([num_qubits, ...])

Spin chain model with circular topology.

SpinChainModel(num_qubits, setup, **params)

The physical model for the spin chian processor (CircularSpinChain and LinearSpinChain).

DispersiveCavityQED(num_qubits[, ...])

The processor based on the physical implementation of a dispersive cavity QED system (CavityQEDModel).

CavityQEDModel(num_qubits[, num_levels])

The physical model for a dispersive cavity-QED processor (DispersiveCavityQED).

SCQubits(num_qubits[, dims, zz_crosstalk])

A chain of superconducting qubits with fixed frequency (SCQubitsModel).

SCQubitsModel(num_qubits[, dims, zz_crosstalk])

The physical model for superconducting-qubit model processor (SCQubits) with fixed frequency.

OptPulseProcessor([num_qubits, drift, dims])

A processor that uses qutip.control.optimize_pulse_unitary to find optimized pulses for a given quantum circuit.

class qutip_qip.device.CavityQEDModel(num_qubits, num_levels=10, **params)[source]

Bases: Model

The physical model for a dispersive cavity-QED processor (DispersiveCavityQED). It is a qubit-resonator model that describes a system composed of a single resonator and a few qubits connected to it. The coupling is kept small so that the resonator is rarely excited but acts only as a mediator for entanglement generation. The single-qubit control Hamiltonians used are \(\sigma_x\) and \(\sigma_z\). The dynamics between the resonator and the qubits is captured by the Tavis-Cummings Hamiltonian, \(\propto\sum_j a^\dagger \sigma_j^{-} + a \sigma_j^{+}\), where \(a\), \(a^\dagger\) are the destruction and creation operators of the resonator, while \(\sigma_j^{-}\), \(\sigma_j^{+}\) are those of each qubit. The control of the qubit-resonator coupling depends on the physical implementation, but in the most general case we have single and multi-qubit control in the form

\[\begin{split}H= \\sum_{j=0}^{N-1} \\epsilon^{\\rm{max}}_{j}(t) \\sigma^x_{j} + \\Delta^{\\rm{max}}_{j}(t) \\sigma^z_{j} + J_{j}(t) (a^\\dagger \\sigma^{-}_{j} + a \\sigma^{+}_{j}).\end{split}\]

The effective qubit-qubit coupling is computed by the

\[\begin{split}J_j = \\frac{g_j g_{j+1}}{2}(\\frac{1}{\\Delta_j} + \\frac{1}{\\Delta_{j+1}}),\end{split}\]

with \(\\Delta=w_q-w_0\) and the dressed qubit frequency \(w_q\) defined as \(w_q=\sqrt{\epsilon^2+\delta^2}\).

Parameters
num_qubitsint

The number of qubits \(N\).

num_levelsint, optional

The truncation level of the Hilbert space for the resonator.

**params

Keyword arguments for hardware parameters, in the unit of GHz. Qubit parameters can either be a float or a list of the length \(N\).

  • deltamax: float or list, optional

    The pulse strength of sigma-x control, \(\\Delta^{\\rm{max}}\), default 1.0.

  • epsmax: float or list, optional

    The pulse strength of sigma-z control, \(\\epsilon^{\\rm{max}}\), default 9.5.

  • eps: float or list, optional

    The bare transition frequency for each of the qubits, default 9.5.

  • deltafloat or list, optional

    The coupling between qubit states, default 0.0.

  • gfloat or list, optional

    The coupling strength between the resonator and the qubit, default 1.0.

  • w0float, optional

    The bare frequency of the resonator \(w_0\). Should only be a float, default 0.01.

  • t1float or list, optional

    Characterize the amplitude damping for each qubit.

  • t2list of list, optional

    Characterize the total dephasing for each qubit.

get_all_drift()[source]

Get all the drift Hamiltonians.

Returns
drift_hamiltonian_listlist

A list of drift Hamiltonians in the form of [(qobj, targets), ...].

get_control_latex()[source]

Get the labels for each Hamiltonian. It is used in the method method Processor.plot_pulses(). It is a 2-d nested list, in the plot, a different color will be used for each sublist.

class qutip_qip.device.CircularSpinChain(num_qubits=None, correct_global_phase=True, **params)[source]

Bases: SpinChain

Spin chain model with circular topology. See SpinChain for details. For the control Hamiltonian please refer to SpinChainModel.

Parameters
num_qubitsint

The number of qubits in the system.

correct_global_phasefloat, optional

Save the global phase, the analytical solution will track the global phase. It has no effect on the numerical solution.

**params:

Hardware parameters. See SpinChainModel.

Examples

import numpy as np
import qutip
from qutip_qip.circuit import QubitCircuit
from qutip_qip.device import CircularSpinChain

qc = QubitCircuit(2)
qc.add_gate("RX", 0, arg_value=np.pi)
qc.add_gate("RY", 1, arg_value=np.pi)
qc.add_gate("ISWAP", [1, 0])

processor = CircularSpinChain(2, g=0.1, t1=300)
processor.load_circuit(qc)
init_state = qutip.basis([2, 2], [0, 0])
result = processor.run_state(init_state)
print(round(qutip.fidelity(result.states[-1], qc.run(init_state)), 4))
0.994
load_circuit(qc, schedule_mode='ASAP', compiler=None)[source]

The default routine of compilation. It first calls the transpile() to convert the circuit to a suitable format for the hardware model. Then it calls the compiler and save the compiled pulses.

Parameters
qcQubitCircuit

Takes the quantum circuit to be implemented.

schedule_mode: string

“ASAP” or “ALAP” or None.

compiler: subclass ofclass:.GateCompiler

The used compiler.

Returns
tlist, coeffs: dict of 1D NumPy array

A dictionary of pulse label and the time sequence and compiled pulse coefficients.

property sxsy_ops

A list of tensor(sigmax, sigmay) interacting Hamiltonians for each qubit.

Type

list

property sxsy_u

Pulse coefficients for tensor(sigmax, sigmay) interacting Hamiltonians.

Type

array-like

topology_map(qc)[source]

Map the circuit to the hardware topology.

class qutip_qip.device.DispersiveCavityQED(num_qubits, num_levels=10, correct_global_phase=True, **params)[source]

Bases: ModelProcessor

The processor based on the physical implementation of a dispersive cavity QED system (CavityQEDModel). The available Hamiltonian of the system is predefined. For a given pulse amplitude matrix, the processor can calculate the state evolution under the given control pulse, either analytically or numerically. (Only additional attributes are documented here, for others please refer to the parent class ModelProcessor)

Parameters
num_qubits: int

The number of qubits in the system.

num_levels: int, optional

The number of energy levels in the resonator.

correct_global_phase: float, optional

Save the global phase, the analytical solution will track the global phase. It has no effect on the numerical solution.

**params:

Hardware parameters. See CavityQEDModel.

Examples

import numpy as np
import qutip
from qutip_qip.circuit import QubitCircuit
from qutip_qip.device import DispersiveCavityQED

qc = QubitCircuit(2)
qc.add_gate("RX", 0, arg_value=np.pi)
qc.add_gate("RY", 1, arg_value=np.pi)
qc.add_gate("ISWAP", [1, 0])

processor = DispersiveCavityQED(2, g=0.1)
processor.load_circuit(qc)
result = processor.run_state(
    qutip.basis([10, 2, 2], [0, 0, 0]),
    options=qutip.Options(nsteps=5000))
final_qubit_state = result.states[-1].ptrace([1, 2])
print(round(qutip.fidelity(
    final_qubit_state,
    qc.run(qutip.basis([2, 2], [0, 0]))
), 4))
0.9994
property cavityqubit_ops

A list of interacting Hamiltonians between cavity and each qubit.

Type

list

eliminate_auxillary_modes(U)[source]

Eliminate the auxillary modes like the cavity modes in cqed.

property g_u

Pulse matrix for interacting Hamiltonians between cavity and each qubit.

Type

array-like

generate_init_processor_state(init_circuit_state: Optional[Qobj] = None) Qobj[source]

Generate the initial state with the dimensions of the DispersiveCavityQED processor.

Parameters
init_circuit_statequtip.Qobj

Initial state provided with the dimensions of the circuit.

Returns
qutip.Qobj

Return the initial state with the dimensions of the DispersiveCavityQED processor model. If initial_circuit_state was not provided, return the zero state.

get_final_circuit_state(final_processor_state: Qobj) Qobj[source]

Truncate the final processor state to get rid of the cavity subsystem.

Parameters
final_processor_statequtip.Qobj

State provided with the dimensions of the DispersiveCavityQED processor model.

Returns
qutip.Qobj

Return the truncated final state with the dimensions of the circuit.

load_circuit(qc, schedule_mode='ASAP', compiler=None)[source]

The default routine of compilation. It first calls the transpile() to convert the circuit to a suitable format for the hardware model. Then it calls the compiler and save the compiled pulses.

Parameters
qcQubitCircuit

Takes the quantum circuit to be implemented.

schedule_mode: string

“ASAP” or “ALAP” or None.

compiler: subclass ofclass:.GateCompiler

The used compiler.

Returns
tlist, coeffs: dict of 1D NumPy array

A dictionary of pulse label and the time sequence and compiled pulse coefficients.

property sx_ops

A list of sigmax Hamiltonians for each qubit.

Type

list

property sx_u

Pulse matrix for sigmax Hamiltonians.

Type

array-like

property sz_ops

A list of sigmaz Hamiltonians for each qubit.

Type

list

property sz_u

Pulse matrix for sigmaz Hamiltonians.

Type

array-like

class qutip_qip.device.LinearSpinChain(num_qubits=None, correct_global_phase=True, **params)[source]

Bases: SpinChain

Spin chain model with open-end topology. For the control Hamiltonian please refer to SpinChainModel.

Parameters
num_qubits: int

The number of qubits in the system.

correct_global_phase: float, optional

Save the global phase, the analytical solution will track the global phase. It has no effect on the numerical solution.

**params:

Hardware parameters. See SpinChainModel.

Examples

import numpy as np
import qutip
from qutip_qip.circuit import QubitCircuit
from qutip_qip.device import LinearSpinChain

qc = QubitCircuit(2)
qc.add_gate("RX", 0, arg_value=np.pi)
qc.add_gate("RY", 1, arg_value=np.pi)
qc.add_gate("ISWAP", [1, 0])

processor = LinearSpinChain(2, g=0.1, t1=300)
processor.load_circuit(qc)
init_state = qutip.basis([2, 2], [0, 0])
result = processor.run_state(init_state)
print(round(qutip.fidelity(result.states[-1], qc.run(init_state)), 4))
0.994
load_circuit(qc, schedule_mode='ASAP', compiler=None)[source]

The default routine of compilation. It first calls the transpile() to convert the circuit to a suitable format for the hardware model. Then it calls the compiler and save the compiled pulses.

Parameters
qcQubitCircuit

Takes the quantum circuit to be implemented.

schedule_mode: string

“ASAP” or “ALAP” or None.

compiler: subclass ofclass:.GateCompiler

The used compiler.

Returns
tlist, coeffs: dict of 1D NumPy array

A dictionary of pulse label and the time sequence and compiled pulse coefficients.

property sxsy_ops

A list of tensor(sigmax, sigmay) interacting Hamiltonians for each qubit.

Type

list

property sxsy_u

Pulse coefficients for tensor(sigmax, sigmay) interacting Hamiltonians.

Type

array-like

topology_map(qc)[source]

Map the circuit to the hardware topology.

class qutip_qip.device.Model(num_qubits, dims=None, **params)[source]

Bases: object

Template class for a physical model representing quantum hardware. The concrete model class does not have to inherit from this, as long as the following methods are defined.

Parameters
num_The number of qubits

The number of qubits.

dimslist, optional

The dimension of each component system. Default value is a qubit system of dim=[2,2,2,...,2].

**params

Hardware parameters for the model.

Attributes
num_The number of qubits

The number of qubits.

dimslist, optional

The dimension of each component system.

paramsdict

Hardware parameters for the model.

get_all_drift() List[Tuple[Qobj, List[int]]][source]

Get all the drift Hamiltonians.

Returns
drift_hamiltonian_listlist

A list of drift Hamiltonians in the form of [(qobj, targets), ...].

get_control(label: Hashable) Tuple[Qobj, List[int]][source]

Get the control Hamiltonian corresponding to the label.

Parameters
labelhashable object

A label that identifies the Hamiltonian.

Returns
control_hamiltoniantuple

The control Hamiltonian in the form of (qobj, targets).

get_control_labels() List[Hashable][source]

Get a list of all available control Hamiltonians. Optional, required only when plotting the pulses or using the optimal control algorithm.

Returns
label_listlist of hashable objects

A list of hashable objects each corresponds to an available control Hamiltonian.

get_noise() List[Noise][source]

Get a list of Noise objects. Single qubit relaxation (T1, T2) are not included here. Optional method.

Returns
noise_listlist

A list of Noise.

class qutip_qip.device.ModelProcessor(num_qubits=None, dims=None, correct_global_phase=True, model=None, **params)[source]

Bases: Processor

The base class for a circuit processor simulating a physical device, e.g cavityQED, spinchain. The available Hamiltonian of the system is predefined. The processor can simulate the evolution under the given control pulses either numerically or analytically. It cannot be used alone, please refer to the sub-classes. (Only additional attributes are documented here, for others please refer to the parent class Processor)

Parameters
num_qubits: int, optional

The number of qubits. It replaces the old API N.

dims: list, optional

The dimension of each component system. Default value is a qubit system of dim=[2,2,2,...,2].

correct_global_phase: boolean, optional

If true, the analytical solution will track the global phase. It has no effect on the numerical solution.

**params:
  • t1: float or list, optional

    Characterize the amplitude damping for each qubit. A list of size num_qubits or a float for all qubits.

  • t2: float or list, optional

    Characterize the total dephasing for each qubit. A list of size num_qubits or a float for all qubits.

generate_init_processor_state(init_circuit_state: Optional[Qobj] = None) Qobj[source]

Generate the initial state with the dimensions of the processor.

Parameters
init_circuit_statequtip.Qobj

Initial state provided with the dimensions of the circuit.

Returns
qutip.Qobj

Return the initial state with the dimensions of the processor model. If initial_circuit_state was not provided, return the zero state.

get_final_circuit_state(final_processor_state: Qobj) Qobj[source]

Convert the state with the dimensions of the processor model to a state with the dimensions of the circuit.

Parameters
final_processor_statequtip.Qobj

State provided with the dimensions of the processor model.

Returns
qutip.Qobj

Return the final state with the dimensions of the circuit.

get_ops_and_u()[source]

Get the labels for each Hamiltonian.

Returns
ctrls: list

The list of Hamiltonians

coeffs: array_like

The transposed pulse matrix

load_circuit(qc, schedule_mode='ASAP', compiler=None)[source]

The default routine of compilation. It first calls the transpile() to convert the circuit to a suitable format for the hardware model. Then it calls the compiler and save the compiled pulses.

Parameters
qcQubitCircuit

Takes the quantum circuit to be implemented.

schedule_mode: string

“ASAP” or “ALAP” or None.

compiler: subclass ofclass:.GateCompiler

The used compiler.

Returns
tlist, coeffs: dict of 1D NumPy array

A dictionary of pulse label and the time sequence and compiled pulse coefficients.

pulse_matrix(dt=0.01)[source]

Generates the pulse matrix for the desired physical system.

Returns
t, u, labels:

Returns the total time and label for every operation.

run_state(init_state=None, analytical=False, qc=None, states=None, **kwargs)[source]

If analytical is False, use qutip.mesolve() to calculate the time of the state evolution and return the result. Other arguments of qutip.mesolve() can be given as keyword arguments. If analytical is True, calculate the propagator with matrix exponentiation and return a list of matrices.

Parameters
init_state: Qobj

Initial density matrix or state vector (ket).

analytical: boolean

If True, calculate the evolution with matrices exponentiation.

qcQubitCircuit, optional

A quantum circuit. If given, it first calls the load_circuit and then calculate the evolution.

statesqutip.Qobj, optional

Old API, same as init_state.

**kwargs

Keyword arguments for the qutip solver.

Returns
evo_result:class:qutip.Result

If analytical is False, an instance of the class qutip.Result will be returned.

If analytical is True, a list of matrices representation is returned.

set_up_params()[source]

Save the parameters in the attribute params and check the validity. (Defined in subclasses)

Notes

All parameters will be multiplied by 2*pi for simplicity

topology_map(qc)[source]

Map the circuit to the hardware topology.

transpile(qc)[source]

Convert the circuit to one that can be executed on given hardware. If there is a method topology_map defined, it will use it to map the circuit to the hardware topology. If the processor has a set of native gates defined, it will decompose the given circuit to the native gates.

Parameters
qc:class:.QubitCircuit

The input quantum circuit.

Returns
qc:class:.QubitCircuit

The transpiled quantum circuit.

class qutip_qip.device.OptPulseProcessor(num_qubits=None, drift=None, dims=None, **params)[source]

Bases: Processor

A processor that uses qutip.control.optimize_pulse_unitary to find optimized pulses for a given quantum circuit. The processor can simulate the evolution under the given control pulses using qutip.mesolve(). (For attributes documentation, please refer to the parent class Processor)

Parameters
num_qubitsint

The number of qubits.

drift: `:class:`qutip.Qobj`

The drift Hamiltonian. The size must match the whole quantum system.

dims: list

The dimension of each component system. Default value is a qubit system of dim=[2,2,2,...,2]

**params:
  • t1float or list, optional

    Characterize the amplitude damping for each qubit. A list of size num_qubits or a float for all qubits.

  • t2float or list, optional

    Characterize the total dephasing for each qubit. A list of size num_qubits or a float for all qubits.

load_circuit(qc, min_fid_err=inf, merge_gates=True, setting_args=None, verbose=False, **kwargs)[source]

Find the pulses realizing a given Circuit using qutip.control.optimize_pulse_unitary(). Further parameter for for qutip.control.optimize_pulse_unitary() needs to be given as keyword arguments. By default, it first merge all the gates into one unitary and then find the control pulses for it. It can be turned off and one can set different parameters for different gates. See examples for details.

Parameters
qcQubitCircuit or list of Qobj

The quantum circuit to be translated.

min_fid_err: float, optional

The minimal fidelity tolerance, if the fidelity error of any gate decomposition is higher, a warning will be given. Default is infinite.

merge_gates: boolean, optimal

If True, merge all gate/Qobj into one Qobj and then find the optimal pulses for this unitary matrix. If False, find the optimal pulses for each gate/Qobj.

setting_args: dict, optional

Only considered if merge_gates is False. It is a dictionary containing keyword arguments for different gates.

verbose: boolean, optional

If true, the information for each decomposed gate will be shown. Default is False.

**kwargs

keyword arguments for :func:qutip.control.optimize_pulse_unitary

Returns
tlist: array_like

A NumPy array specifies the time of each coefficient

coeffs: array_like

A 2d NumPy array of the shape (len(ctrls), len(tlist)-1). Each row corresponds to the control pulse sequence for one Hamiltonian.

Notes

len(tlist)-1=coeffs.shape[1] since tlist gives the beginning and the end of the pulses

Examples

Same parameter for all the gates

>>> from qutip_qip.circuit import QubitCircuit
>>> from qutip_qip.device import OptPulseProcessor
>>> qc = QubitCircuit(1)
>>> qc.add_gate("SNOT", 0)
>>> num_tslots = 10
>>> evo_time = 10
>>> processor = OptPulseProcessor(1, drift=sigmaz())
>>> processor.add_control(sigmax())
>>> # num_tslots and evo_time are two keyword arguments
>>> tlist, coeffs = processor.load_circuit(                qc, num_tslots=num_tslots, evo_time=evo_time)

Different parameters for different gates

>>> from qutip_qip.circuit import QubitCircuit
>>> from qutip_qip.device import OptPulseProcessor
>>> qc = QubitCircuit(2)
>>> qc.add_gate("SNOT", 0)
>>> qc.add_gate("SWAP", targets=[0, 1])
>>> qc.add_gate('CNOT', controls=1, targets=[0])
>>> processor = OptPulseProcessor(2, drift=tensor([sigmaz()]*2))
>>> processor.add_control(sigmax(), cyclic_permutation=True)
>>> processor.add_control(sigmay(), cyclic_permutation=True)
>>> processor.add_control(tensor([sigmay(), sigmay()]))
>>> setting_args = {"SNOT": {"num_tslots": 10, "evo_time": 1},                        "SWAP": {"num_tslots": 30, "evo_time": 3},                        "CNOT": {"num_tslots": 30, "evo_time": 3}}
>>> tlist, coeffs = processor.load_circuit(                qc, setting_args=setting_args, merge_gates=False)
class qutip_qip.device.Processor(num_qubits=None, dims=None, spline_kind='step_func', model=None, N=None, t1=None, t2=None)[source]

Bases: object

The noisy quantum device simulator using QuTiP dynamic solvers. It compiles quantum circuit into a Hamiltonian model and then simulate the time-evolution described by the master equation.

Note

This is an abstract class that includes the general API but has no concrete physical model implemented. In particular, it provides a series of low-level APIs that allow direct modification of the Hamiltonian model and control pulses, which can usually be achieved automatically using Model and build-in workflows. They provides more flexibility but are not always the most elegant approaches.

Parameters
num_qubitsint, optional

The number of qubits. It replaces the old API N.

dimslist, optional

The dimension of each component system. Default value is a qubit system of dim=[2,2,2,...,2].

spline_kindstr, optional

Type of the coefficient interpolation. Default is “step_func” Note that they have different requirements for the length of coeff.

-“step_func”: The coefficient will be treated as a step function. E.g. tlist=[0,1,2] and coeff=[3,2], means that the coefficient is 3 in t=[0,1) and 2 in t=[1,2). It requires len(coeff)=len(tlist)-1 or len(coeff)=len(tlist), but in the second case the last element of coeff has no effect.

-“cubic”: Use cubic interpolation for the coefficient. It requires len(coeff)=len(tlist)

modelModel

Provide a predefined physical model of the simulated hardware. If other parameters, such as t1 is given as input, it will overwrite those saved in Processor.model.params.

t1float or list, optional

Characterize the amplitude damping for each qubit. A list of size num_qubits or a float for all qubits.

t2float or list, optional

Characterize the total dephasing for each qubit. A list of size num_qubits or a float for all qubits.

add_control(qobj, targets=None, cyclic_permutation=False, label=None)[source]

Add a control Hamiltonian to the model. The new control Hamiltonian is saved in the Processor.model attributes.

Parameters
qobjqutip.Qobj

The control Hamiltonian.

targetslist, optional

The indices of the target qubits (or composite quantum systems).

cyclic_permutationbool, optional

If true, the Hamiltonian will be added for all qubits, e.g. if targets=[0,1], and there are 2 qubits, the Hamiltonian will be added to the target qubits [0,1], [1,2] and [2,0].

labelstr, optional

The hashable label (name) of the control Hamiltonian. If None, it will be set to the current number of control Hamiltonians in the system.

Examples

>>> import qutip
>>> from qutip_qip.device import Processor
>>> processor = Processor(1)
>>> processor.add_control(qutip.sigmax(), 0, label="sx")
>>> processor.get_control_labels()
['sx']
>>> processor.get_control("sx") 
(Quantum object: dims = [[2], [2]], shape = (2, 2),
type = oper, isherm = True
Qobj data =
[[0. 1.]
[1. 0.]], [0])
add_drift(qobj, targets=None, cyclic_permutation=False)[source]

Add the drift Hamiltonian to the model. The drift Hamiltonians are intrinsic of the quantum system and cannot be controlled by an external field.

Parameters
qobjqutip.Qobj

The drift Hamiltonian.

targetslist, optional

The indices of the target qubits (or subquantum system of other dimensions).

cyclic_permutationbool, optional

If true, the Hamiltonian will be added for all qubits, e.g. if targets=[0,1], and there are 2 qubits, The Hamiltonian will be added to the target qubits [0,1], [1,2] and [2,0].

add_noise(noise)[source]

Add a noise object to the processor.

Parameters
noiseNoise

The noise object defined outside the processor.

add_pulse(pulse)[source]

Add a new pulse to the device.

Parameters
pulsePulse

Pulse object to be added.

property coeffs

A list of ideal control coefficients for all saved pulses. The order matches with Processor.controls

property controls

A list of the ideal control Hamiltonians in all saved pulses. Note that control Hamiltonians with no pulse will not be included. The order matches with Processor.coeffs

property ctrls

A list of the ideal control Hamiltonians in all saved pulses. Note that control Hamiltonians with no pulse will not be included. The order matches with Processor.coeffs

property dims

The dimension of each component system. :type: list

property drift

The drift Hamiltonian in the form [(qobj, targets), ...] :type: list

eliminate_auxillary_modes(U)[source]

Eliminate the auxillary modes like the cavity modes in cqed. (Defined in subclasses)

get_all_drift()[source]

Get all the drift Hamiltonians.

Returns
drift_hamiltonian_listlist

A list of drift Hamiltonians in the form of [(qobj, targets), ...].

get_control(label)[source]

Get the control Hamiltonian corresponding to the label.

Parameters
label

A label that identifies the Hamiltonian.

Returns
control_hamiltoniantuple

The control Hamiltonian in the form of (qobj, targets).

Examples

>>> from qutip_qip.device import LinearSpinChain
>>> processor = LinearSpinChain(1)
>>> processor.get_control_labels()
['sx0', 'sz0']
>>> processor.get_control('sz0') 
(Quantum object: dims = [[2], [2]], shape = (2, 2),
type = oper, isherm = True
Qobj data =
[[ 6.28319  0.     ]
 [ 0.      -6.28319]], 0)
get_control_labels()[source]

Get a list of all available control Hamiltonians.

Returns
label_listlist

A list of hashable objects each corresponds to an available control Hamiltonian.

get_control_latex()[source]

Get the latex string for each Hamiltonian. It is used in the method Processor.plot_pulses(). It is a list of dictionaries. In the plot, a different color will be used for each dictionary in the list.

Returns
nested_latex_strlist of dict

E.g.: [{"sx": "\sigma_z"}, {"sy": "\sigma_y"}].

get_full_coeffs(full_tlist=None)[source]

Return the full coefficients in a 2d matrix form. Each row corresponds to one pulse. If the tlist are different for different pulses, the length of each row will be the same as the full_tlist (see method get_full_tlist). Interpolation is used for adding the missing coefficients according to spline_kind.

Returns
coeffs: array-like 2d

The coefficients for all ideal pulses.

get_full_tlist(tol=1e-10)[source]

Return the full tlist of the ideal pulses. If different pulses have different time steps, it will collect all the time steps in a sorted array.

Returns
full_tlist: array-like 1d

The full time sequence for the ideal evolution.

get_noise()[source]

Get a list of Noise objects.

Returns
noise_listlist

A list of Noise.

get_noisy_pulses(device_noise=False, drift=False)[source]

It takes the pulses defined in the Processor and adds noise according to Processor.noise. It does not modify the pulses saved in Processor.pulses but returns a new list. The length of the new list of noisy pulses might be longer because of drift Hamiltonian and device noise. They will be added to the end of the pulses list.

Parameters
device_noise: bool, optional

If true, include pulse independent noise such as single qubit Relaxation. Default is False.

drift: bool, optional

If true, include drift Hamiltonians. Default is False.

Returns
noisy_pulseslist of Drift

A list of noisy pulses.

get_qobjevo(args=None, noisy=False)[source]

Create a qutip.QobjEvo representation of the evolution. It calls the method Processor.get_noisy_pulses() and create the QobjEvo from it.

Parameters
args: dict, optional

Arguments for qutip.QobjEvo

noisy: bool, optional

If noise are included. Default is False.

Returns
qobjevoqutip.QobjEvo

The qutip.QobjEvo representation of the unitary evolution.

c_ops: list ofclass:qutip.QobjEvo

A list of lindblad operators is also returned. if noisy==False, it is always an empty list.

load_circuit(qc)[source]

Translate an QubitCircuit to its corresponding Hamiltonians. (Defined in subclasses)

property noise

.coverage

property num_qubits

Number of qubits (or subsystems). For backward compatibility. :type: int

property params

Hardware parameters. :type: dict

plot_pulses(title=None, figsize=(12, 6), dpi=None, show_axis=False, rescale_pulse_coeffs=True, num_steps=1000, pulse_labels=None, use_control_latex=True)[source]

Plot the ideal pulse coefficients.

Parameters
title: str, optional

Title for the plot.

figsize: tuple, optional

The size of the figure.

dpi: int, optional

The dpi of the figure.

show_axis: bool, optional

If the axis are shown.

rescale_pulse_coeffs: bool, optional

Rescale the hight of each pulses.

num_steps: int, optional

Number of time steps in the plot.

pulse_labels: list of dict, optional

A map between pulse labels and the labels shown in the y axis. E.g. [{"sx": "sigmax"}]. Pulses in each dictionary will get a different color. If not given and use_control_latex==False, the string label defined in each Pulse is used.

use_control_latex: bool, optional

Use labels defined in Processor.model.get_control_latex.

pulse_labels: list of dict, optional

A map between pulse labels and the labels shown on the y axis. E.g. ["sx", "sigmax"]. If not given and use_control_latex==False, the string label defined in each Pulse is used.

use_control_latex: bool, optional

Use labels defined in Processor.model.get_control_latex.

Returns
fig: matplotlib.figure.Figure

The Figure object for the plot.

axis: list of matplotlib.axes._subplots.AxesSubplot

The axes for the plot.

Notes

:meth:.Processor.plot_pulses` only works for array_like coefficients.

property pulse_mode

If the given pulse is going to be interpreted as “continuous” or “discrete”.

Type

str

read_coeff(file_name, inctime=True)[source]

Read the control amplitudes matrix and time list saved in the file by save_amp.

Parameters
file_name: string

Name of the file.

inctime: bool, optional

True if the time list in included in the first column.

Returns
tlist: array_like

The time list read from the file.

coeffs: array_like

The pulse matrix read from the file.

remove_pulse(indices=None, label=None)[source]

Remove the control pulse with given indices.

Parameters
indices: int or list of int

The indices of the control Hamiltonians to be removed.

label: str

The label of the pulse

run(qc=None)[source]

Calculate the propagator of the evolution by matrix exponentiation. This method won’t include noise or collpase.

Parameters
qcQubitCircuit, optional

Takes the quantum circuit to be implemented. If not given, use the quantum circuit saved in the processor by load_circuit.

Returns
U_list: list

The propagator matrix obtained from the physical implementation.

run_analytically(init_state=None, qc=None)[source]

Simulate the state evolution under the given qutip.QubitCircuit with matrice exponentiation. It will calculate the propagator with matrix exponentiation and return a list of qutip.Qobj. This method won’t include noise or collpase.

Parameters
qcQubitCircuit, optional

Takes the quantum circuit to be implemented. If not given, use the quantum circuit saved in the processor by load_circuit.

init_statequtip.Qobj, optional

The initial state of the qubits in the register.

Returns
U_list: list

A list of propagators obtained for the physical implementation.

run_state(init_state=None, analytical=False, states=None, noisy=True, solver='mesolve', **kwargs)[source]

If analytical is False, use qutip.mesolve() to calculate the time of the state evolution and return the result. Other arguments of mesolve can be given as keyword arguments.

If analytical is True, calculate the propagator with matrix exponentiation and return a list of matrices. Noise will be neglected in this option.

Parameters
init_statequtip.Qobj

Initial density matrix or state vector (ket).

analytical: bool

If True, calculate the evolution with matrices exponentiation.

statesqutip.Qobj, optional

Old API, same as init_state.

solver: str

“mesolve” or “mcsolve”, for mesolve() and mcsolve().

noisy: bool

Include noise or not.

**kwargs

Keyword arguments for the qutip solver. E.g tlist for time points for recording intermediate states and expectation values; args for the solvers and qutip.QobjEvo.

Returns
evo_resultqutip.Result

If analytical is False, an instance of the class qutip.Result will be returned.

If analytical is True, a list of matrices representation is returned.

save_coeff(file_name, inctime=True)[source]

Save a file with the control amplitudes in each timeslot.

Parameters
file_name: string

Name of the file.

inctime: bool, optional

True if the time list should be included in the first column.

set_all_coeffs(coeffs)

Clear all the existing pulses and reset the coefficients for the control Hamiltonians.

Parameters
coeffs: NumPy arrays, dict or list.
  • If it is a dict, it should be a map of the label of control Hamiltonians and the corresponding coefficients. Use Processor.get_control_labels() to see the available Hamiltonians.

  • If it is a list of arrays or a 2D NumPy array, it is treated same to dict, only that the pulse label is assumed to be integers from 0 to len(coeffs)-1.

set_all_tlist(tlist)

Set the tlist for all existing pulses. It assumes that pulses all already added to the processor. To add pulses automatically, first use Processor.set_coeffs.

Parameters
tlist: dict or list of NumPy arrays.

If it is a dict, it should be a map between pulse label and the time sequences. If it is a list of arrays or a 2D NumPy array, each array will be associated to a pulse, following the order in the pulse list.

set_coeffs(coeffs)[source]

Clear all the existing pulses and reset the coefficients for the control Hamiltonians.

Parameters
coeffs: NumPy arrays, dict or list.
  • If it is a dict, it should be a map of the label of control Hamiltonians and the corresponding coefficients. Use Processor.get_control_labels() to see the available Hamiltonians.

  • If it is a list of arrays or a 2D NumPy array, it is treated same to dict, only that the pulse label is assumed to be integers from 0 to len(coeffs)-1.

set_tlist(tlist)[source]

Set the tlist for all existing pulses. It assumes that pulses all already added to the processor. To add pulses automatically, first use Processor.set_coeffs.

Parameters
tlist: dict or list of NumPy arrays.

If it is a dict, it should be a map between pulse label and the time sequences. If it is a list of arrays or a 2D NumPy array, each array will be associated to a pulse, following the order in the pulse list.

property t1

Characterize the total amplitude damping of each qubit. :type: float or list

property t2

Characterize the total dephasing for each qubit. :type: float or list

class qutip_qip.device.SCQubits(num_qubits, dims=None, zz_crosstalk=False, **params)[source]

Bases: ModelProcessor

A chain of superconducting qubits with fixed frequency (SCQubitsModel). Single-qubit control is realized by rotation around the X and Y axis while two-qubit gates are implemented with Cross Resonance gates. A 3-level system is used to simulate the superconducting qubit system, in order to simulation leakage. Various types of interaction can be realized on a superconducting system, as a demonstration and for simplicity, we only use a ZX Hamiltonian for the two-qubit interaction.

See the mathematical details in SCQubitsCompiler and SCQubitsModel.

Parameters
num_qubits: int

The number of qubits in the system.

dims: list, optional

The dimension of each component system. Default value is a qubit system of dim=[2,2,2,...,2].

zz_crosstalk: bool, optional

If ZZ cross-talk is included.

**params:

Hardware parameters. See SCQubitsModel.

Examples

import numpy as np
import qutip
from qutip_qip.circuit import QubitCircuit
from qutip_qip.device import SCQubits

qc = QubitCircuit(2)
qc.add_gate("RZ", 0, arg_value=np.pi)
qc.add_gate("RY", 1, arg_value=np.pi)
qc.add_gate("CNOT", targets=0, controls=1)

processor = SCQubits(2)
processor.load_circuit(qc)
init_state = qutip.basis([3, 3], [0, 0])
result = processor.run_state(init_state)
topology_map(qc)[source]

Map the circuit to the hardware topology.

class qutip_qip.device.SCQubitsModel(num_qubits, dims=None, zz_crosstalk=False, **params)[source]

Bases: Model

The physical model for superconducting-qubit model processor (SCQubits) with fixed frequency. Each qubit is simulated by a multi-level Duffing model [7], in which the qubit subspace is provided by the ground state and the first excited state. By default, the creation and annihilation operators are truncated at the third level, which can be adjusted. The multi-level representation can capture the leakage of the population out of the qubit subspace during single-qubit gates. The single-qubit control is generated by two orthogonal quadratures \(a_j^{\dagger}+a_j\) and \(i(a_j^{\dagger}-a_j)\). The interaction is possible only between adjacent qubits. Although this interaction is mediated by a resonator, for simplicity, we replace the complicated dynamics among two superconducting qubits and the resonator with a two-qubit effective Hamiltonian derived in Ref. [2].

As an example, we choose the cross resonance interaction in the form of \(\sigma^z_{j} \sigma^x_{j+1}\), acting only on the two-qubit levels, which is widely used, e.g., in fixed-frequency superconducting qubits. We can write the Hamiltonian as

\[\begin{split}H &= H_{\rm{d}} + \sum_{j=0}^{N-1} \Omega^x_{j} (a_j^{\dagger} + a_j) + \Omega^y_{j} i(a_j^{\dagger} - a_j) \\ & + \sum_{j=0}^{N-2} \Omega^{\rm{cr}1}_{j} \sigma^z_j \sigma^x_{j+1} + \Omega^{\rm{cr}2}_{j} \sigma^x_j \sigma^z_{j+1}\end{split}\]

where the drift Hamiltonian is defined as

\[H_{\rm{d}} = \sum_{j=0}^{N-1} \frac{\alpha_j}{2} a_j^{\dagger}a_j^{\dagger}a_j a_j\]
Parameters
num_qubits: int

The number of qubits.

dims: list, optional

The dimension of each component system. Default value is a qubit system of dim=[2,2,2,...,2].

zz_crosstalk: bool, optional

If ZZ cross-talk is included.

**params:

Keyword arguments for hardware parameters, in the unit of GHz. Each should be given as list:

  • wqlist, optional

    Qubits bare frequency, default 5.15 and 5.09 for each pair of superconducting qubits, default [5.15, 5.09, 5.15, ...].

  • wrlist, optional

    Resonator bare frequency, default [5.96]*num_qubits.

  • glist, optional

    The coupling strength between the resonator and the qubits, default [0.1]*(num_qubits - 1).

  • alphalist, optional

    Anharmonicity for each superconducting qubit, default [-0.3]*num_qubits.

  • omega_singlelist, optional

    The maximal control strength for single-qubit gate, \(\Omega^x\) and \(\Omega^y\), default [0.01]*num_qubits.

  • omega_crlist, optional

    Control strength for cross resonance gate, default [0.01]*num_qubits.

  • t1float or list, optional

    Characterize the amplitude damping for each qubit.

  • t2list of list, optional

    Characterize the total dephasing for each qubit.

get_control_latex()[source]

Get the labels for each Hamiltonian. It is used in the method method Processor.plot_pulses(). It is a 2-d nested list, in the plot, a different color will be used for each sublist.

class qutip_qip.device.SpinChainModel(num_qubits, setup, **params)[source]

Bases: Model

The physical model for the spin chian processor (CircularSpinChain and LinearSpinChain). The interaction is only possible between adjacent qubits. The single-qubit control Hamiltonians are \(\sigma_j^x\), \(\sigma_j^z\), while the interaction is realized by the exchange Hamiltonian \(\sigma^x_{j}\sigma^x_{j+1}+\sigma^y_{j}\sigma^y_{j+1}\). The overall Hamiltonian model is written as:

\[H= \sum_{j=0}^{N-1} \Omega^x_{j}(t) \sigma^x_{j} + \Omega^z_{j}(t) \sigma^z_{j} + \sum_{j=0}^{N-2} g_{j}(t) (\sigma^x_{j}\sigma^x_{j+1}+ \sigma^y_{j}\sigma^y_{j+1}).\]
Parameters
num_qubits: int

The number of qubits, \(N\).

setupstr

“linear” for an open end and “circular” for a closed end chain.

**params

Keyword arguments for hardware parameters, in the unit of frequency (MHz, GHz etc, the unit of time list needs to be adjusted accordingly). Parameters can either be a float or list with parameters for each qubits.

  • sxfloat or list, optional

    The pulse strength of sigma-x control, \(\Omega^x\), default 0.25.

  • szfloat or list, optional

    The pulse strength of sigma-z control, \(\Omega^z\), default 1.0.

  • sxsyfloat or list, optional

    The pulse strength for the exchange interaction, \(g\), default 0.1. It should be either a float or an array of the length \(N-1\) for the linear setup or \(N\) for the circular setup.

  • t1float or list, optional

    Characterize the amplitude damping for each qubit.

  • t2list of list, optional

    Characterize the total dephasing for each qubit.

get_control_latex()[source]

Get the labels for each Hamiltonian. It is used in the method method Processor.plot_pulses(). It is a 2-d nested list, in the plot, a different color will be used for each sublist.