qml.allocate¶
- allocate(num_wires, state=AllocateState.ZERO, restored=False)[source]¶
Dynamically allocates new wires in-line, or as a context manager which also safely deallocates the new wires upon exiting the context.
- Parameters:
num_wires (int) – The number of wires to dynamically allocate.
- Keyword Arguments:
state (Literal["any", "zero"]) – Specifies whether to allocate
num_wires
in the all-zeros state ("zero"
) or in any arbitrary state ("any"
). The default value isstate="zero"
.restored (bool) – Whether or not the dynamically allocated wires are returned to the same state they started in.
restored=True
indicates that the user promises to restore the dynamically allocated wires to their original state before being deallocated.restored=False
indicates that the user does not promise to restore the dynamically allocated wires before being deallocated. The default value isFalse
.
- Returns:
an object, behaving similarly to
Wires
, that represents the dynamically allocated wires.- Return type:
DynamicRegister
Note
The
allocate
function can be used as a context manager with automatic deallocation (recommended for most cases) or with manual deallocation viadeallocate()
.Note
The
num_wires
argument must be static when capture is enabled.See also
Example
Using
allocate
to dynamically request wires returns an array of wires (DynamicRegister
) that can be indexed into:>>> wires = qml.allocate(3) >>> wires <DynamicRegister: size=3> >>> wires[1] <DynamicWire>
Note that allocating just one wire still requires indexing into:
>>> wire = qml.allocate(1) >>> wire <DynamicRegister: size=1> >>> wire[0] <DynamicWire>
Most use cases for
allocate
are covered by using it as a context manager, which ensures that allocation and safe deallocation are controlled within a localized scope.import pennylane as qml @qml.qnode(qml.device("default.qubit")) def circuit(): qml.H(0) qml.H(1) with qml.allocate(2, state="zero", restored=False) as new_wires: qml.H(new_wires[0]) qml.H(new_wires[1]) return qml.expval(qml.Z(0))
>>> print(qml.draw(circuit)()) 0: ──H───────────────────────┤ <Z> 1: ──H───────────────────────┤ <DynamicWire>: ─╭Allocate──H─╭Deallocate─┤ <DynamicWire>: ─╰Allocate──H─╰Deallocate─┤
Equivalenty,
allocate
can be used in-line along withdeallocate()
for manual handling:new_wires = qml.allocate(2, state="zero", restored=False) qml.H(new_wires[0]) qml.H(new_wires[1]) qml.deallocate(new_wires)
Usage details
Efficient wire management
For more complex dynamic allocation in circuits, PennyLane will resolve the dynamic allocation calls in a resource-efficient manner before sending the program to the device. Consider the following circuit, which contains two dynamic allocations within a
for
loop.@qml.qnode(qml.device("default.qubit"), mcm_method="tree-traversal") def circuit(): qml.H(0) for i in range(2): with qml.allocate(1, state="zero", restored=True) as new_qubit1: with qml.allocate(1, state="any", restored=False) as new_qubit2: m0 = qml.measure(new_qubit1[0], reset=True) qml.cond(m0 == 1, qml.Z)(new_qubit2[0]) qml.CNOT((0, new_qubit2[0])) return qml.expval(qml.Z(0))
>>> print(qml.draw(circuit)()) 0: ──H─────────────────────╭●───────────────────────╭●─────────────┤ <Z> <DynamicWire>: ──Allocate──┤↗│ │0⟩────│──────────Deallocate────│──────────────┤ <DynamicWire>: ──Allocate───║────────Z─╰X─────────Deallocate────│──────────────┤ <DynamicWire>: ─────────────║────────║──Allocate──┤↗│ │0⟩──────│───Deallocate─┤ <DynamicWire>: ─────────────║────────║──Allocate───║──────────Z─╰X──Deallocate─┤ ╚════════╝ ╚══════════╝
The user-level circuit drawing shows four separate allocations and deallocations (two per loop iteration). However, the circuit that the device receives gets automatically compiled to only use two additional wires (wires labelled
1
and2
in the diagram below). This is due to the fact thatnew_qubit1
andnew_qubit2
can both be reused after they’ve been deallocated in the first iteration of thefor
loop:>>> print(qml.draw(circuit, level="device")()) 0: ──H───────────╭●──────────────╭●─┤ <Z> 1: ──┤↗│ │0⟩────│───┤↗│ │0⟩────│──┤ 2: ───║────────Z─╰X───║────────Z─╰X─┤ ╚════════╝ ╚════════╝
Additionally, in circuits that deallocate a wire in “any” state, this wire can be reused as a “zero”. The arbitrary-state wire is reset back to a zero state by introducing a mid-circuit measurement. This is illustrated in the example below, where the first wire allocation is deallocated in an arbitrary state, but the only other dynamic wire allocation in the circuit requires a zero state:
@qml.qnode(qml.device("default.qubit"), mcm_method="device") def circuit(): with qml.allocate(1, state="zero", restored=False) as [wire]: qml.H(wire) with qml.allocate(1, state="zero", restored=False) as [wire]: qml.X(wire) return qml.expval(qml.Z(0))
>>> print(qml.draw(circuit, level="user")()) <DynamicWire>: ──Allocate──H──Deallocate─┤ <DynamicWire>: ──Allocate──X──Deallocate─┤ 0: ──────────────────────────┤ <Z> >>> print(qml.draw(circuit, level="device")()) 0: ─────────────────┤ <Z> 1: ──H──┤↗│ │0⟩──X─┤