Source code for qiskit.circuit.classical.types.types
# This code is part of Qiskit.
#
# (C) Copyright IBM 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""Type-system definition for the expression tree."""
# Given the nature of the tree representation and that there are helper functions associated with
# many of the classes whose arguments naturally share names with themselves, it's inconvenient to
# use synonyms everywhere. This goes for the builtin 'type' as well.
# pylint: disable=redefined-builtin,redefined-outer-name
from __future__ import annotations
__all__ = [
"Type",
"Bool",
"Uint",
]
import typing
class _Singleton(type):
"""Metaclass to make the child, which should take zero initialisation arguments, a singleton
object."""
def _get_singleton_instance(cls):
return cls._INSTANCE
@classmethod
def __prepare__(mcs, name, bases): # pylint: disable=unused-argument
return {"__new__": mcs._get_singleton_instance}
@staticmethod
def __new__(cls, name, bases, namespace):
out = super().__new__(cls, name, bases, namespace)
out._INSTANCE = object.__new__(out) # pylint: disable=invalid-name
return out
[docs]class Type:
"""Root base class of all nodes in the type tree. The base case should never be instantiated
directly.
This must not be subclassed by users; subclasses form the internal data of the representation of
expressions, and it does not make sense to add more outside of Qiskit library code."""
__slots__ = ()
@property
def kind(self):
"""Get the kind of this type. This is exactly equal to the Python type object that defines
this type, that is ``t.kind is type(t)``, but is exposed like this to make it clear that
this a hashable enum-like discriminator you can rely on."""
return self.__class__
# Enforcement of immutability. The constructor methods need to manually skip this.
def __setattr__(self, _key, _value):
raise AttributeError(f"'{self.kind.__name__}' instances are immutable")
def __copy__(self):
return self
def __deepcopy__(self, _memo):
return self
def __setstate__(self, state):
_dict, slots = state
for slot, value in slots.items():
# We need to overcome the type's enforcement of immutability post initialisation.
super().__setattr__(slot, value)
[docs]@typing.final
class Bool(Type, metaclass=_Singleton):
"""The Boolean type. This has exactly two values: ``True`` and ``False``."""
__slots__ = ()
def __repr__(self):
return "Bool()"
def __eq__(self, other):
return isinstance(other, Bool)
[docs]@typing.final
class Uint(Type):
"""An unsigned integer of fixed bit width."""
__slots__ = ("width",)
def __init__(self, width: int):
if isinstance(width, int) and width <= 0:
raise ValueError("uint width must be greater than zero")
super(Type, self).__setattr__("width", width)
def __repr__(self):
return f"Uint({self.width})"
def __eq__(self, other):
return isinstance(other, Uint) and self.width == other.width