Source code for pennylane.labs.resource_estimation.qubit_manager
# Copyright 2025 Xanadu Quantum Technologies Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
r"""This module contains the base class for qubit management"""
from typing import Union
import pennylane as qml
# pylint: disable= too-few-public-methods
[docs]
class QubitManager:
r"""Manages and tracks the auxiliary and algorithmic qubits used in a quantum circuit.
Args:
work_wires (int or Dict[str, int]): Number of work wires or a dictionary containing
number of clean and dirty work wires. All ``work_wires`` are assumed to be clean when
`int` is provided.
algo_wires (int): Number of algorithmic wires, default value is ``0``.
tight_budget (bool): Determines whether extra clean qubits can be allocated when they
exceed the available amount. The default is ``False``.
**Example**
>>> q = QubitManager(
... work_wires={"clean": 2, "dirty": 2},
... tight_budget=False,
... )
>>> print(q)
QubitManager(clean=2, dirty=2, logic=0, tight_budget=False)
"""
def __init__(self, work_wires: Union[int, dict], algo_wires=0, tight_budget=False) -> None:
if isinstance(work_wires, dict):
clean_wires = work_wires["clean"]
dirty_wires = work_wires["dirty"]
else:
clean_wires = work_wires
dirty_wires = 0
self.tight_budget = tight_budget
self._logic_qubit_counts = algo_wires
self._clean_qubit_counts = clean_wires
self._dirty_qubit_counts = dirty_wires
def __str__(self):
return (
f"QubitManager(clean qubits={self._clean_qubit_counts}, dirty qubits={self._dirty_qubit_counts}, "
f"algorithmic qubits={self._logic_qubit_counts}, tight budget={self.tight_budget})"
)
def __repr__(self) -> str:
work_wires_str = repr(
{"clean": self._clean_qubit_counts, "dirty": self._dirty_qubit_counts}
)
return (
f"QubitManager(work_wires={work_wires_str}, algo_wires={self._logic_qubit_counts}, "
f"tight_budget={self.tight_budget})"
)
def __eq__(self, other: object) -> bool:
return (
isinstance(other, self.__class__)
and (self.clean_qubits == other.clean_qubits)
and (self.dirty_qubits == other.dirty_qubits)
and (self.algo_qubits == other.algo_qubits)
and (self.tight_budget == other.tight_budget)
)
@property
def clean_qubits(self):
r"""Returns the number of clean qubits."""
return self._clean_qubit_counts
@property
def dirty_qubits(self):
r"""Returns the number of dirty qubits."""
return self._dirty_qubit_counts
@property
def algo_qubits(self):
r"""Returns the number of algorithmic qubits."""
return self._logic_qubit_counts
@property
def total_qubits(self):
r"""Returns the number of total qubits."""
return self._clean_qubit_counts + self._dirty_qubit_counts + self.algo_qubits
@algo_qubits.setter
def algo_qubits(self, count: int): # these get set manually, the rest are dynamically updated
r"""Setter for algorithmic qubits."""
self._logic_qubit_counts = count
[docs]
def allocate_qubits(self, num_qubits: int):
r"""Allocates extra clean qubits.
Args:
num_qubits(int): number of qubits to be allocated
"""
self._clean_qubit_counts += num_qubits
[docs]
def grab_clean_qubits(self, num_qubits: int):
r"""Grabs clean qubits.
Args:
num_qubits(int) : number of clean qubits to be grabbed
Raises:
ValueError: If tight_budget is `True` number of qubits to be grabbed is greater than
available clean qubits.
"""
available_clean = self.clean_qubits
if num_qubits > available_clean:
if self.tight_budget:
raise ValueError(
f"Grabbing more qubits than available clean qubits."
f"Number of clean qubits available is {available_clean}, while {num_qubits} are being grabbed."
)
self._clean_qubit_counts = 0
else:
self._clean_qubit_counts -= num_qubits
self._dirty_qubit_counts += num_qubits
[docs]
def free_qubits(self, num_qubits: int):
r"""Frees dirty qubits and converts them to clean qubits.
Args:
num_qubits(int) : number of qubits to be freed
Raises:
ValueError: If number of qubits to be freed is greater than available dirty qubits.
"""
if num_qubits > self.dirty_qubits:
raise ValueError(
f"Freeing more qubits than available dirty qubits."
f"Number of dirty qubits available is {self.dirty_qubits}, while {num_qubits} qubits are being released."
)
self._dirty_qubit_counts -= num_qubits
self._clean_qubit_counts += num_qubits
class _WireAction:
"""Base class for operations that manage qubit resources."""
_queue_category = "_resource_qubit_action"
def __init__(self, num_wires):
self.num_wires = num_wires
if qml.QueuingManager.recording():
self.queue()
def queue(self, context=qml.QueuingManager):
r"""Adds the wire action object to a queue."""
context.append(self)
return self
def __eq__(self, other: "_WireAction") -> bool:
return self.num_wires == other.num_wires
[docs]
class AllocWires(_WireAction):
r"""Allows users to allocate clean work wires.
Args:
num_wires (int): number of work wires to be allocated.
"""
def __repr__(self) -> str:
return f"AllocWires({self.num_wires})"
[docs]
class FreeWires(_WireAction):
r"""Allows users to free dirty work wires.
Args:
num_wires (int): number of dirty work wires to be freed.
"""
def __repr__(self) -> str:
return f"FreeWires({self.num_wires})"
_modules/pennylane/labs/resource_estimation/qubit_manager
Download Python script
Download Notebook
View on GitHub