Processing math: 100%

qml.ftqc.QubitMgr

class QubitMgr(num_qubits=0, start_idx=0)[source]

Bases: object

The QubitMgr object maintains a list of active and inactive qubit wire indices used and for use during execution of a workload. Its purpose is to allow tracking of free qubit indices that are in the |0 state to participate in MCM-based workloads, under the assumption of reset upon measurement. Qubit wires indices will be tracked with a monotonically increasing set of values, starting from the initial input start_idx.

Parameters
  • num_qubits (int) – Total number of wire indices to track.

  • start_idx (int) – Starting index of wires to track. Defaults to 0.

Example:

The following MBQC example workload uses the QubitMgr to assist with recycling of indices between iterations

import pennylane as qml
from pennylane.ftqc import QubitGraph, diagonalize_mcms, generate_lattice, measure_x, measure_y
dev = qml.device('null.qubit')

@qml.qnode(dev, mcm_method="one-shot")
def circuit_mbqc(start_state, angles):
    q_mgr = QubitMgr(num_qubits=5, start_idx=0)
    input_idx = q_mgr.acquire_qubit()

    # prep input node
    qml.StatePrep(start_state, wires=[input_idx])

    # prep and consume graph state iteratively
    for i in range(num_iter):
        # Acquire 4 free qubit indices
        graph_wires = q_mgr.acquire_qubits(4)

        # Denote the index for the final output state
        output_idx = graph_wires[-1]

        # Prepare the state
        qml.ftqc.GraphStatePrep(lattice.graph, wires=graph_wires)

        # entangle input and graph using first qubit
        qml.CZ([input_idx, graph_wires[0]])

        # MBQC Z rotation: X, X, +/- angle, X
        # Reset operations allow qubits to be returned to the pool
        m0 = measure_x(input_idx, reset=True)
        m1 = measure_x(graph_wires[0], reset=True)
        m2 = cond_measure(m1, partial(measure, angle=angle, reset=True), partial(measure, angle=-angle, reset=True))(plane="XY", wires=graph_wires[1])
        m3 = measure_x(graph_wires[2], reset=True)

        # corrections based on measurement outcomes
        qml.cond((m0+m2)%2, qml.Z)(graph_wires[3])
        qml.cond((m1+m3)%2, qml.X)(graph_wires[3])

        # The input qubit can be freed and the output qubit becomes the next iteration's input
        q_mgr.release_qubit(input_idx)
        input_idx = output_idx

        # We can now free all but the last qubit, which has become the new input_idx
        q_mgr.release_qubits(graph_wires[0:-1])

    # Perform the measurements on the output qubit from the last iteration
    return qml.expval(X(output_idx)), qml.expval(Y(output_idx)), qml.expval(Z(output_idx))

For each loop iteration, the measured and reset wire labels are returned to the QubitMgr instance, which are then reallocated on the next step, which when combined with the MCM resets allows for qubit index recycling.

active

Defines the active wire indices.

all_qubits

Defines all active and inactive wire indices.

inactive

Defines the inactive wire indices.

num_qubits

Defines the total number of wire indices tracked by the manager.

active

Defines the active wire indices. Any wire index in this set is unavailable for use, as it may be participating in existing algorithms and/or not be in a reset state.

Returns

active wire indices

Return type

set[int]

all_qubits

Defines all active and inactive wire indices.

Returns

union of active and inactive wire indices

Return type

set[int]

inactive

Defines the inactive wire indices. Any wire index in this set is available for use, and is assumed to be in a reset (|0) state.

Returns

inactive wire indices

Return type

set[int]

num_qubits

Defines the total number of wire indices tracked by the manager.

Returns

total number of qubit wire indices

Return type

int

acquire_qubit()

Acquires an available qubit wire index from the inactive pool, and makes it active.

acquire_qubits(num_qubits)

Acquires num_qubits qubit wire indices from the inactive pool, and makes them active.

release_qubit(idx)

Release an active qubit wire index, idx, from the active pool, and makes it inactive.

release_qubits(indices)

Release the list of active qubit wire indices, indices, from the active pool, and makes them inactive.

reserve_qubit(idx)

Explicitly reserve the qubit wire index, idx, to be active.

acquire_qubit()[source]

Acquires an available qubit wire index from the inactive pool, and makes it active. If there are no inactive qubits available a RuntimeError will be raised.

Returns

newly activated qubit wire index

Return type

int

acquire_qubits(num_qubits)[source]

Acquires num_qubits qubit wire indices from the inactive pool, and makes them active. If there are no inactive qubits available a RuntimeError will be raised.

See also

acquire_qubit().

Returns

newly activated qubit wire indices

Return type

list[int]

release_qubit(idx)[source]

Release an active qubit wire index, idx, from the active pool, and makes it inactive. If idx is not in the active pool a RuntimeError will be raised.

release_qubits(indices)[source]

Release the list of active qubit wire indices, indices, from the active pool, and makes them inactive. If any of the given indices are not in the active pool a RuntimeError will be raised.

See also

release_qubit().

reserve_qubit(idx)[source]

Explicitly reserve the qubit wire index, idx, to be active. If given index is not in the active pool a RuntimeError will be raised.