qutip_qip.compiler package

Submodules

qutip_qip.compiler.cavityqedcompiler module

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

Bases: qutip_qip.compiler.gatecompiler.GateCompiler

Decompose a QubitCircuit into the pulse sequence for the processor.

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 DispersiveCavityQED.set_up_params() for the definition.

global_phase: float, optional

Record of the global phase change and will be returned.

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

rx_compiler(gate, args)[source]

Compiler for the RX gate

rz_compiler(gate, args)[source]

Compiler for the RZ gate

sqrtiswap_compiler(gate, args)[source]

Compiler for the SQRTISWAP gate

Notes

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

qutip_qip.compiler.circuitqedcompiler module

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

Bases: qutip_qip.compiler.gatecompiler.GateCompiler

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

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

single_qubit_compiler(gate, args)[source]

Compiler for the RX and RY gate.

qutip_qip.compiler.gatecompiler module

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

Bases: object

Base class. 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

Arguments for individual compiling routines. It adds more flexibility in customizing compiler.

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

globalphase_compiler(gate, args)[source]

Compiler for the GLOBALPHASE gate

idle_compiler(gate, args)[source]

Compiler for the GLOBALPHASE gate

qutip_qip.compiler.instruction module

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

Bases: object

The instruction that implements a quantum gate. It contains the control pulse required to implement the gate on a particular hardware model.

Parameters
gate: :class:`.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

qutip_qip.compiler.scheduler module

class qutip_qip.compiler.scheduler.InstructionsGraph(instructions)[source]

Bases: object

A directed acyclic graph (DAG) representation of the quantum instruction dependency. An example is Fig3(b) in https://doi.org/10.1117/12.666419. It contains methods of generating the instruction dependency graph, a list-schedule algorithm to find the topological order and the computation of the distance in the weighted graph (circuit latency).

It uses the Instruction object as a representation of node and adds the following attributes to it:

predecessors, successors: dependency arrow of the DAG distance_to_start, distance_to_end: longest distance to the start and end

Parameters
instructions: list

A list of instructions

Attributes
nodes: list

The input list of instruction with additional graph information.

start, end: list

List of indices of nodes connected to the start or end nodes.

add_constraint_dependency(constraint_dependency)[source]

Add the dependency caused by hardware constraint to the graph.

Parameters
constraint_dependency: list

constraint_dependency obtained by the method find_topological_order.

compute_distance(cycles_list)[source]

Compute the longest distance of each node to the start and end nodes. The weight for each dependency arrow is the duration of the source instruction (which should be 1 for gates schedule). The method solves the longest path problem by using the topological order in cycles_list. It makes sure that by following the list, the distance to the predecessors (successors) of the source (target) node is always calculated before the target (source) node.

Parameters
cycles_list: list

A cycles_list obtained by the method find_topological_order.

find_topological_order(priority=True, apply_constraint=None, random=False)[source]

A list-schedule algorithm, it finds the topological order of the directed graph under certain constraint and priority indicator. The function returns a list of cycles, where each cycle is a list of instructions that can be executed in parallel. In the case of gates schedule, the result will be the gates cycle list.

Parameters
priority: bool

If use distance to the start and end nodes as a priority measure for the schedule problem.

apply_constraint: function

A Python function that determines if to instruction can be executed in parallel. E.g. if two gates apply to the same qubit, the function returns False.

Returns
cycles_list: list

A list of cycles, where each cycle is a list of instructions that can be executed in parallel.

constraint_dependency: set

A set of instruction pairs that are found conflicted due to the hardware constraints. Because of this, they are executed in different cycles. This set is used to add this dependency to the graph in another method.

generate_dependency_graph(commuting)[source]

Generate the instruction dependency graph. It modifies the class attribute nodes, where each element (node) is an Instruction. The graph is represented by attributes predecessors and successors, each a set of indices pointing to the position of the target node in the nodes list.

The graph preserves the mobility of the gates, i.e. if two gates commute with each other, such as CNOT 2, 3 and CNOT 2, 1, there should be no dependency arrow between them. Because of this, the generated graph does not consider the hardware constraints, e.g. two commuting gates addressing the same qubits cannot be executed at the same time. A dependency arrow between Instruction 1 and instruction 2 means that they do not commute. However, the converse does not hold because we do not need gate1->gate3 if we already have gate1->gate2->gate3.

Parameters
commuting: function

A Python function that determines if two gates commute, given that their used qubits overlap.

reverse_graph()[source]

Reverse the graph. The start node becomes the end node Predecessors and successors of each node are exchanged.

class qutip_qip.compiler.scheduler.Scheduler(method='ALAP', 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 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 usefull 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=Ture.

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.

qutip_qip.compiler.scheduler.qubit_constraint(ind1, ind2, instructions)[source]

Determine if two instructions have overlap in the used qubits.

qutip_qip.compiler.spinchaincompiler module

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

Bases: qutip_qip.compiler.gatecompiler.GateCompiler

Compile a QubitCircuit into the pulse sequence for the processor.

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 SpinChain.set_up_params() 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.

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

rx_compiler(gate, args)[source]

Compiler for the RX gate

rz_compiler(gate, args)[source]

Compiler for the RZ gate

sqrtiswap_compiler(gate, args)[source]

Compiler for the SQRTISWAP gate

Module contents