CircuitOperationList#
- class iqm.pulse.circuit_operations.CircuitOperationList(contents=(), *, qubits=None, num_qubits=0, table=None)#
Bases:
listList of
CircuitOperationobjects representing a quantum circuit.The class is used to work with CircuitOperations directly. It is mostly meant as convenience to enable easy creation of circuits, calculations of their properties, and mapping them onto physical qubits. In addition to the circuit contents, this class has two important attributes:
qubitsandtable.qubitsdefines the list of qubits which are allowed to be in the loci of all the CircuitOperations present in the list. Think about it as Qiskit’s QuantumRegister.tableis aQuantumOpTable, which contains all theQuantumOps which are allowed in the circuit. In most cases, the table is simply taken to contain all the default operations defined iniqm.pulse. When you use this class with aScheduleBuilder, it is good practice to settable = builder.op_table. The QuantumOpTable is mutable, so any additional registered gates can automatically be usable in any CircuitOperationList associated with that ScheduleBuilder instance.The fundamental use of the class would be to first define a new instance:
circuit = CircuitOperationList(num_qubits=2)
The
num_qubitsparameter populates thequbitsattribute with qubits QB1-QBn, in this case['QB1', 'QB2'].Alternatively, you can provide
qubitsdirectly:circuit = CircuitOperationList(qubits=['QB1', 'QB2'])
To add your own QuantumOpTable, initialize like this:
circuit = CircuitOperationList(num_qubits=2, table=my_table)
Remembering that the table is mutable.
If you already have a list of CircuitOperations, you can initialize with it:
circuit = CircuitOperationList(circuit_ops, table=my_table) circuit.find_qubits()
Calling the
find_qubits()method populates thequbitsattribute with the qubits found in loci of the operations in the original circuit. If the list is empty, it will setqubitsto an empty list, which most of the time is not what you want to do.The class has the
__add__,__mul__and__getitem__methods redefined, which meanscircuit * 3,circuit1 + circuit2andcircuit[0:4]will produce a CircuitOperationList with the samequbitsandtableattributes as the original.To add a
prxoperation to the list, call:circuit.add_op('prx', [0], angle, phase, impl_name='drag_crf')
The class also has shortcut methods defined, so the above can be shortened to
circuit.prx(angle, phase, 0, impl_name='drag_crf')
which is exactly the same syntax as in Qiskit, with the addition of the implementation name which usually does not need to be used. The names of the shortcut methods are taken from the attached
tableat init. All the operations with non-zero arity will be added as shortcuts.If all the operations in the circuit are unitary, you can calculate the unitary propagator of the entire circuit by calling:
U = circuit.get_unitary()
The dimension of the unitary will always be defined by the
qubitsattribute. In particular, if your circuit contains 3 qubits,'QB1', 'QB2', 'QB3', but you only add gates to the first two, the resulting unitary will still be an 8x8 matrix, corresponding to the three qubits'QB1', 'QB2', 'QB3', in the big endian convention. With no operations affecting'QB3', the action of the unitary on this qubit is identity.To map the circuit onto physical qubits, all you need to do is call:
physical_circuit = circuit.map_loci(physical_qubits)
This will create a copy of the circuit, with all the placeholder qubits replaced by the physical qubits, with the order defined by the
qubitsattribute. For example, ifqubits = ['QB1', 'Alice', 'ZZZ'], andphysical_qubits = ['QB2', 'QB5', 'QB10'], all occurrences of'QB1'will be mapped to'QB2','Alice'to'QB5'and'ZZZ'to'QB10'. The original circuit is not modified, so you can create many copies with different physical qubits, which is helpful when running parallel experiments on a large chip.- Parameters:
contents (Iterable[CircuitOperation]) – Circuit operations to initialize the circuit with. Can be left out.
qubits (list[str]) – Qubits allowed to be used in operation loci in the circuit.
num_qubits (int) – Number of qubits in the circuit, will initialize
qubitswith['QB1', 'QB2', ...]. Ignored ifqubitsis given.table (QuantumOpTable | None) – Allowed quantum operations.
Module:
iqm.pulse.circuit_operationsAttributes
qubitsMethods
Adds a new
CircuitOperationto the circuit.Adds generic placeholder qubits from 1 to n.
Add barrier to the circuit
A safer way to add circuits together, but will probably take time.
Count each type of operation in the circuit.
Set attribute qubits to qubits in the loci of operations in the list.
Calculate the overall unitary implemented by a sequence of CircuitOperations.
Creates a new list of
CircuitOperations with locus mapped onto physical qubits.- find_qubits()#
Set attribute qubits to qubits in the loci of operations in the list.
- Return type:
None
- get_unitary(qubit_names=None)#
Calculate the overall unitary implemented by a sequence of CircuitOperations.
- add_op(name, locus_indices, *args, impl_name=None)#
Adds a new
CircuitOperationto the circuit.Appends a new
CircuitOperationat the end of the list. TheCircuitOperationis created using aQuantumOpname from the QuantumOpTable attached to the CircuitOperationList. The locus of thatCircuitOperationis built from the qubits stored inqubits, by selecting the qubits at indices given bylocus_indices. For example, ifqubitsis['QB1', 'QB2', 'QB4'], and thelocus_indicesis[2, 1], the locus of the newCircuitOperationwill be('QB4', 'QB2'). All arguments for the values of the params of the requestedQuantumOpneed to be provided.- Parameters:
name (str) – Name of the
QuantumOpwhich will generate a newCircuitOperation.locus_indices (Sequence[int]) – Indices of the qubits in the attribute .qubits which will become the locus of the operation.
args – Any arguments the CircuitOperation needs, must correspond to the params of the
QuantumOp.impl_name (str | None) – Name of the implementation to use when converting the
CircuitOperationinto aTimeboxlater.
- Return type:
None
- barrier(*locus_indices)#
Add barrier to the circuit
- Return type:
None
- compose(other, locus_indices=None)#
A safer way to add circuits together, but will probably take time.
All the
CircuitOperations from the'other'list are appended to the end of this list. The wirekof the second circuit is connected to wirelocus_indices[k]of the first. This is achieved by mapping the locus of each operation in the second circuit onto the qubits of the first.For example, if the
qubitsof the first list are['QB1', 'QB2'], the second list has['QB3', 'QB4'], and the locus_indices argument is[1,0], all the operations in the second list will have their'QB3'mapped to'QB2'and'QB4'mapped to'QB1'.
- count_ops()#
Count each type of operation in the circuit.
- Returns:
Counter mapping operation names to numbers of times they occur in the circuit.
- Return type:
- map_loci(locus, make_circuit=True)#
Creates a new list of
CircuitOperations with locus mapped onto physical qubits.Creates a fresh list of fresh
CircuitOperations with fresh arguments. Iflocusis provided, it needs to have the same length as the total number of qubits across the circuit, and the qubits will then be mapped onto the new locus. If it is not provided, this is identical to a deepcopy of the original list.- Parameters:
locus (list[str] | None) – List of new qubits to replace the qubits in the loci of the operations in the circuit.
make_circuit (bool) – If True, creates a
CircuitOperationList. If False, it is just a list.
- Returns:
New CircuitOperationList with loci mapped onto new locus.
- Return type: