qutip_qip.compiler

Compilers for the hardware models in device

Classes

GateCompiler([num_qubits, params, pulse_dict, N])

Base class of compilers, including the GateCompiler.compile() method.

SpinChainCompiler(num_qubits, params[, ...])

Compiler for SpinChain.

CavityQEDCompiler(num_qubits, params[, ...])

Compiler for DispersiveCavityQED.

SCQubitsCompiler(num_qubits, params)

Compiler for SCQubits.

Scheduler([method, allow_permutation, ...])

A gate (pulse) scheduler for quantum circuits (instructions).

Instruction(gate[, tlist, pulse_info, duration])

Representation of pulses that implement a quantum gate.

class qutip_qip.compiler.CavityQEDCompiler(num_qubits, params, global_phase=0.0, pulse_dict=None, N=None)[source]

Bases: GateCompiler

Compiler for DispersiveCavityQED. Compiled pulse strength is in the unit of GHz.

Supported native gates: “RX”, “RY”, “RZ”, “ISWAP”, “SQRTISWAP”, “GLOBALPHASE”.

Default configuration (see GateCompiler.args and GateCompiler.compile):

key

value

shape

rectangular

params

Hardware Parameters

Parameters
num_qubits: int

The number of qubits in the system.

params: dict

A Python dictionary contains the name and the value of the parameters. See CavityQEDModel for the definition.

global_phase: float, optional

Record of the global phase change and will be returned.

Examples

>>> import numpy as np
>>> from qutip_qip.circuit import QubitCircuit
>>> from qutip_qip.device import ModelProcessor, CavityQEDModel
>>> from qutip_qip.compiler import CavityQEDCompiler
>>>
>>> qc = QubitCircuit(2)
>>> qc.add_gate("ISWAP", targets=[0, 1])
>>>
>>> model = CavityQEDModel(2)
>>> processor = ModelProcessor(model=model)
>>> compiler = CavityQEDCompiler(2, params=model.params)
>>> processor.load_circuit(
...     qc, compiler=compiler)  
({'sz0': array([   0.        , 2500.        , 2500.01316]),
'sz1': array([   0.        , 2500.        , 2500.01316]),
'g0': array([   0.        , 2500.        , 2500.01316]),
'g1': array([   0.        , 2500.        , 2500.01316])},
{'sz0': array([-0.5, -9.5]),
'sz1': array([-0.5, -9.5]),
'g0': array([0.01, 0.  ]),
'g1': array([0.01, 0.  ])})

Notice that the above example is equivalent to using directly the DispersiveCavityQED.

Attributes
gate_compiler: dict

The Python dictionary in the form of {gate_name: decompose_function}. It saves the decomposition scheme for each gate.

globalphase_compiler(gate, args)[source]

Compiler for the GLOBALPHASE gate

iswap_compiler(gate, args)[source]

Compiler for the ISWAP gate.

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
rx_compiler(gate, args)[source]

Compiler for the RX gate

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
rz_compiler(gate, args)[source]

Compiler for the RZ gate

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
sqrtiswap_compiler(gate, args)[source]

Compiler for the SQRTISWAP gate.

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.

Notes

This version of sqrtiswap_compiler has very low fidelity, please use iswap

class qutip_qip.compiler.GateCompiler(num_qubits=None, params=None, pulse_dict=None, N=None)[source]

Bases: object

Base class of compilers, including the GateCompiler.compile() method. It compiles a QubitCircuit into the pulse sequence for the processor. The core member function compile calls compiling method from the sub-class and concatenate the compiled pulses.

Parameters
num_qubits: int

The number of the component systems.

params: dict, optional

A Python dictionary contains the name and the value of the parameters, such as laser frequency, detuning etc. It will be saved in the class attributes and can be used to calculate the control pulses.

Attributes
gate_compiler: dict

The Python dictionary in the form of {gate_name: compiler_function}. It saves the compiling routine for each gate. See sub-classes for implementation. Note that for continuous pulse, the first coeff should always be 0.

args: dict

The compilation configurations. It will be passed to each compiling functions. Available arguments:

  • shape: The compiled pulse shape. rectangular or one of the SciPy window functions.

  • num_samples: Number of samples for continuous pulses. It has no effect for rectangular pulses.

  • params: Hardware parameters computed in the Processor.

compile(circuit, schedule_mode=None, args=None)[source]

Compile the the native gates into control pulse sequence. It calls each compiling method and concatenates the compiled pulses.

Parameters
circuit:class:.QubitCircuit or list of

Gate A list of elementary gates that can be implemented in the corresponding hardware. The gate names have to be in gate_compiler.

schedule_mode: str, optional

"ASAP" for “as soon as possible” or "ALAP" for “as late as possible” or False or None for no schedule. Default is None.

args: dict, optional

A dictionary of arguments used in a specific gate compiler function.

Returns
tlist, coeffs: array_like or dict

Compiled ime sequence and pulse coefficients. if return_array is true, return A 2d NumPy array of the shape (len(ctrls), len(tlist)). Each row corresponds to the control pulse sequence for one Hamiltonian. if return_array is false

classmethod generate_pulse_shape(shape, num_samples, maximum=1.0, area=1.0)[source]

Return a tuple consisting of a coeff list and a time sequence according to a given pulse shape.

Parameters
shapestr

The name "rectangular" for constant pulse or the name of a Scipy window function. See the Scipy documentation for detail.

num_samplesint

The number of the samples of the coefficients.

maximumfloat, optional

The maximum of the coefficients. The absolute value will be used if negative.

areafloat, optional

The total area if one integrates coeff as a function of the time. If the area is negative, the pulse is flipped vertically (i.e. the pulse is multiplied by the sign of the area).

Returns
coeff, tlist :

If the default window "shape"="rectangular" is used, both are float numbers. If Scipy window functions are used, both are a 1-dimensional numpy array with the same size.

Notes

If Scipy window functions are used, it is suggested to set Processor.pulse_mode to "continuous". Notice that finite number of sampling points will also make the total integral of the coefficients slightly deviate from area.

Examples

from qutip_qip.compiler import GateCompiler
import numpy as np
compiler = GateCompiler()
coeff, tlist= compiler.generate_pulse_shape(
    "hann",  # Scipy Hann window
    1000,  # 100 sampling point
    maximum=3.,
    # Notice that 2 pi is added to H by qutip solvers.
    area= 1.,
)

We can plot the generated pulse shape:

import matplotlib.pyplot as plt
plt.plot(tlist, coeff)
plt.show()

(png, hires.png, pdf)

../_images/qutip_qip-compiler-2.png

The pulse is normalized to fit the area. Notice that due to the finite number of sampling points, it is not exactly 1.

>>> round(np.trapz(coeff, tlist), 2)
1.0
globalphase_compiler(gate, args)[source]

Compiler for the GLOBALPHASE gate

idle_compiler(gate, args)[source]

Compiler for the GLOBALPHASE gate

class qutip_qip.compiler.Instruction(gate, tlist=None, pulse_info=(), duration=1)[source]

Bases: object

Representation of pulses that implement a quantum gate. It contains the control pulse required to implement the gate on a particular hardware model.

Parameters
gate:class:~.operations.Gate

The quantum gate.

duration: list, optional

The execution time needed for the instruction.

tlist: array_like, optional

A list of time at which the time-dependent coefficients are applied. See Pulse for detailed information`

pulse_info: list, optional

A list of tuples, each tuple corresponding to a pair of pulse label and pulse coefficient, in the format (str, array_like). This pulses will implement the desired gate.

Attributes
targets: list, optional

The target qubits.

controls: list, optional

The control qubits.

used_qubits: set

Union of the control and target qubits.

property controls

Control qubits

Type

list

property name

Corresponding gate name

property targets

Target qubits

Type

list

class qutip_qip.compiler.SCQubitsCompiler(num_qubits, params)[source]

Bases: GateCompiler

Compiler for SCQubits. Compiled pulse strength is in the unit of GHz.

Supported native gates: “RX”, “RY”, “CNOT”.

Default configuration (see GateCompiler.args and GateCompiler.compile):

key

value

shape

hann

num_samples

1000

params

Hardware Parameters

For single-qubit gate, we apply the DRAG correction [8]

\[ \begin{align}\begin{aligned}\Omega^{x} &= \Omega_0 - \frac{\Omega_0^3}{4 \alpha^2}\\\Omega^{y} &= - \frac{\dot{\Omega}_0 }{\alpha}\\\Omega^{z} &= - \frac{\Omega_0^2}{\alpha} + \frac{2 \Omega_0^2}{ 4 \alpha }\end{aligned}\end{align} \]

where \(\Omega_0\) is the original shape of the pulse. Notice that the \(\Omega_0\) and its first derivative should be 0 from the starts and the end.

Parameters
num_qubits: int

The number of qubits in the system.

params: dict

A Python dictionary contains the name and the value of the parameters. See SCQubitsModel() for the definition.

Examples

>>> import numpy as np
>>> from qutip_qip.circuit import QubitCircuit
>>> from qutip_qip.device import ModelProcessor, SCQubitsModel
>>> from qutip_qip.compiler import SCQubitsCompiler
>>>
>>> qc = QubitCircuit(2)
>>> qc.add_gate("CNOT", targets=0, controls=1)
>>>
>>> model = SCQubitsModel(2)
>>> processor = ModelProcessor(model=model)
>>> compiler = SCQubitsCompiler(2, params=model.params)
>>> processor.load_circuit(qc, compiler=compiler);  

Notice that the above example is equivalent to using directly the SCQubits.

Attributes
num_qubits: int

The number of the component systems.

params: dict

A Python dictionary contains the name and the value of the parameters, such as laser frequency, detuning etc.

gate_compiler: dict

The Python dictionary in the form of {gate_name: decompose_function}. It saves the decomposition scheme for each gate.

cnot_compiler(gate, args)[source]

Compiler for CNOT gate using the cross resonance iteraction. See https://journals.aps.org/prb/abstract/10.1103/PhysRevB.81.134507 for reference.

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
rx_compiler(gate, args)[source]

Compiler for the RX gate

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
ry_compiler(gate, args)[source]

Compiler for the RZ gate

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
class qutip_qip.compiler.Scheduler(method='ALAP', allow_permutation=True, constraint_functions=None)[source]

Bases: object

A gate (pulse) scheduler for quantum circuits (instructions). It schedules a given circuit or instructions to reduce the total execution time by parallelization. It uses heuristic methods mainly from in https://doi.org/10.1117/12.666419.

The scheduler includes two methods, “ASAP”, as soon as possible, and “ALAP”, as late as possible. The later is commonly used in quantum computation because of the finite lifetime of qubits.

The scheduler aims at pulse schedule and therefore does not consider merging gates to reduce the gates number. It assumes that the input circuit is optimized at the gate level and matches the hardware topology.

Parameters
method: str

“ASAP” for as soon as possible. “ALAP” for as late as possible.

constraint_functions: list, optional

A list of hardware constraint functions. Default includes a function qubit_contraint, i.e. one qubit cannot be used by two gates at the same time.

apply_constraint(ind1, ind2, instructions)[source]

Apply hardware constraint among the commuting gates to check if two instructions can be executed in parallel.

Parameters
ind1, ind2: int

indices of the two instructions

instructions: list

The instruction list

commutation_rules(ind1, ind2, instructions)[source]

Determine if two gates commute, given that their used qubits overlap. Since usually the input gates are already in a universal gate sets, it uses an oversimplified condition:

If the two gates do not have the same name, they are considered as not commuting. If they are the same gate and have the same controls or targets, they are considered as commuting. E.g. CNOT 0, 1 commute with CNOT 0, 2.

schedule(circuit, gates_schedule=False, return_cycles_list=False, random_shuffle=False, repeat_num=0)[source]

Schedule a QubitCircuit, a list of Gates or a list of Instruction. For pulse schedule, the execution time for each Instruction is given in its duration attributes.

The scheduler first generates a quantum gates dependency graph, containing information about which gates have to be executed before some other gates. The graph preserves the mobility of the gates, i.e. commuting gates are not dependent on each other, even if they use the same qubits. Next, it computes the longest distance of each node to the start and end nodes. The distance for each dependency arrow is defined by the execution time of the instruction (By default, it is 1 for all gates). This is used as a priority measure in the next step. The gate with a longer distance to the end node and a shorter distance to the start node has higher priority. In the last step, it uses a list-schedule algorithm with hardware constraint and priority and returns a list of cycles for gates/instructions.

For pulse schedule, an additional step is required to compute the start time of each instruction. It adds the additional dependency caused by hardware constraint to the graph and recomputes the distance of each node to the start and end node. This distance is then converted to the start time of each instruction.

Parameters
circuit: QubitCircuit or list

For gate schedule, it should be a QubitCircuit or a list of Gate objects. For pulse schedule, it should be a list of Instruction objects, each with an attribute duration that indicates the execution time of this instruction.

gates_schedule: bool, optional

True, if only gates schedule is needed. This saves some computation that is only useful to pulse schedule. If the input circuit is a QubitCircuit, it will be assigned to True automatically. Otherwise, the default is False.

return_cycles_list: bool, optional

If True, the method returns the cycles_list, e.g. [{0, 2}, {1, 3}], which means that the first cycle contains gates0 and gates2 while the second cycle contains gates1 and gates3. It is only useful for gates schedule.

random_shuffle: bool, optional

If the commuting gates are randomly scuffled to explore larger search space.

repeat_num: int, optional

Repeat the scheduling several times and use the best result. Used together with random_shuffle=True.

Returns
gate_cycle_indices or instruction_start_time: list

The cycle indices for each gate or the start time for each instruction.

Examples

>>> from qutip_qip.circuit import QubitCircuit
>>> from qutip_qip.compiler import Scheduler
>>> circuit = QubitCircuit(7)
>>> circuit.add_gate("SNOT", 3)  # gate0
>>> circuit.add_gate("CZ", 5, 3)  # gate1
>>> circuit.add_gate("CZ", 4, 3)  # gate2
>>> circuit.add_gate("CZ", 2, 3)  # gate3
>>> circuit.add_gate("CZ", 6, 5)  # gate4
>>> circuit.add_gate("CZ", 2, 6)  # gate5
>>> circuit.add_gate("SWAP", [0, 2])  # gate6
>>>
>>> scheduler = Scheduler("ASAP")
>>> scheduler.schedule(circuit, gates_schedule=True)
[0, 1, 3, 2, 2, 3, 4]

The result list is the cycle indices for each gate. It means that the circuit can be executed in 5 gate cycles: [gate0, gate1, (gate3, gate4), (gate2, gate5), gate6] Notice that gate3 and gate4 commute with gate2, therefore, the order is changed to reduce the number of cycles.

class qutip_qip.compiler.SpinChainCompiler(num_qubits, params, setup='linear', global_phase=0.0, pulse_dict=None, N=None)[source]

Bases: GateCompiler

Compiler for SpinChain. Compiled pulse strength is in the unit of MHz.

Supported native gates: “RX”, “RY”, “RZ”, “ISWAP”, “SQRTISWAP”, “GLOBALPHASE”.

Default configuration (see GateCompiler.args and GateCompiler.compile):

key

value

shape

rectangular

params

Hardware Parameters

Parameters
num_qubits: int

The number of qubits in the system.

params: dict

A Python dictionary contains the name and the value of the parameters. See SpinChainModel for the definition.

setup: string

“linear” or “circular” for two sub-classes.

global_phase: bool

Record of the global phase change and will be returned.

pulse_dict: dict, optional

A map between the pulse label and its index in the pulse list. If given, the compiled pulse can be identified with (pulse_label, coeff), instead of (pulse_index, coeff). The number of key-value pairs should match the number of pulses in the processor. If it is empty, an integer pulse_index needs to be used in the compiling routine saved under the attributes gate_compiler.

Examples

>>> import numpy as np
>>> from qutip_qip.circuit import QubitCircuit
>>> from qutip_qip.device import ModelProcessor, SpinChainModel
>>> from qutip_qip.compiler import SpinChainCompiler
>>>
>>> qc = QubitCircuit(2)
>>> qc.add_gate("RX", 0, arg_value=np.pi)
>>> qc.add_gate("RZ", 1, arg_value=np.pi)
>>>
>>> model = SpinChainModel(2, "linear", g=0.1)
>>> processor = ModelProcessor(model=model)
>>> compiler = SpinChainCompiler(2, params=model.params, setup="linear")
>>> processor.load_circuit(
...     qc, compiler=compiler) 
({'sx0': array([0., 1.]), 'sz1': array([0.  , 0.25, 1.  ])},
{'sx0': array([0.25]), 'sz1': array([1., 0.])})

Notice that the above example is equivalent to using directly the LinearSpinChain.

Attributes
num_qubits: int

The number of the component systems.

params: dict

A Python dictionary contains the name and the value of the parameters, such as laser frequency, detuning etc.

gate_compiler: dict

The Python dictionary in the form of {gate_name: decompose_function}. It saves the decomposition scheme for each gate.

setup: string

“linear” or “circular” for two sub-classes.

global_phase: bool

Record of the global phase change and will be returned.

globalphase_compiler(gate, args)[source]

Compiler for the GLOBALPHASE gate

iswap_compiler(gate, args)[source]

Compiler for the ISWAP gate.

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
rx_compiler(gate, args)[source]

Compiler for the RX gate

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
rz_compiler(gate, args)[source]

Compiler for the RZ gate

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.
sqrtiswap_compiler(gate, args)[source]

Compiler for the SQRTISWAP gate.

Parameters
gateGate:

The quantum gate to be compiled.

argsdict

The compilation configuration defined in the attributes GateCompiler.args or given as a parameter in GateCompiler.compile.

Returns
A list ofobj:.Instruction, including the compiled pulse
information for this gate.