
    z	icv                    :   S r SSKJr  SSKrSSKJr  SSKJr  SSKJ	r	J
r
      SS jr " S	 S
\" \5      5      r " S S\S9r " S S\5      r " S S\5      r " S S\\\S9r " S S\\5      r " S S\\\S9r " S S\\	5      r " S S\	\\S9rSS.S S jjrg)!a1  
========================================================
Singleton instructions (:mod:`qiskit.circuit.singleton`)
========================================================

.. currentmodule:: qiskit.circuit.singleton

The machinery in this module is for defining subclasses of :class:`~.circuit.Instruction` and
:class:`.Gate` that preferentially return a shared immutable singleton instance when instantiated.
Taking the example of :class:`.XGate`, the final user-facing result is that:

* There is a regular class called :class:`XGate`, which derives from :class:`.Gate`.

* Doing something like ``XGate(label="my_gate")`` produces an object whose type is exactly
  ``XGate``, and all the mutability works completely as expected; all the methods resolve to exactly
  those defined by :class:`.XGate`, :class:`.Gate`, or parents.

* Doing ``XGate()`` produces a singleton object whose type is a synthetic ``_SingletonXGate`` class,
  which derives :class:`.XGate` but overrides :meth:`~object.__setattr__` to make itself immutable.
  The object itself has precisely the same instance attributes as ``XGate()`` would have if there
  was no singleton handling.  This object will return itself under :func:`~copy.copy`,
  :func:`~copy.deepcopy` and roundtrip through :mod:`pickle`.

The same can be true for, for example, :class:`.Measure`, except that it's a subclass of
:class:`~.circuit.Instruction` only, and not :class:`.Gate`.

.. note::

    The classes in this module are for advanced use, because they are closely entwined with the
    heart of Qiskit's data model for circuits.

From a library-author perspective, the minimum that is needed to enhance a :class:`.Gate` or
:class:`~.circuit.Instruction` with this behavior is to inherit from :class:`SingletonGate`
(:class:`SingletonInstruction`) instead of :class:`.Gate` (:class:`~.circuit.Instruction`), and for
the ``__init__`` method to have defaults for all of its arguments (these will be the state of the
singleton instance).  For example::

    class XGate(SingletonGate):
        def __init__(self, label=None):
            super().__init__("x", 1, [], label=label)

    assert XGate() is XGate()


Interface
=========

The public classes correspond to the standard classes :class:`~.circuit.Instruction` and
:class:`.Gate`, respectively, and are subclasses of these.

.. autoclass:: SingletonInstruction
   :class-doc-from: class
.. autoclass:: SingletonGate
   :class-doc-from: class
.. autoclass:: SingletonControlledGate
   :class-doc-from: class

When inheriting from one of these classes, the produced class will have an eagerly created singleton
instance that will be returned whenever the class is constructed with arguments that have been
defined to be singletons.  Typically this will be the defaults.  These instances are immutable;
attempts to modify their properties will raise :exc:`TypeError`.

*All* subclasses of :class:`~.circuit.Instruction` have a :attr:`~.Instruction.mutable` property.
For most instructions this is ``True``, while for the singleton instances it is ``False``.  One can
use the :meth:`~.Instruction.to_mutable` method to get a version of the instruction that is owned
and safe to mutate.

The singleton instances are not exact instances of their base class; they are special subclasses
that cannot construct new objects.  This means that::

    type(XGate()) is not XGate

You should not rely on :class:`type` having an exact value; use :func:`isinstance` instead for type
checking.  If you need to reliably retrieve the base class from an :class:`~.circuit.Instruction`,
see the :attr:`.Instruction.base_class` attribute; singleton instances set this correctly.  For most
cases in using Qiskit, :attr:`.Instruction.name` is a more suitable determiner of what an
instruction "means" in a circuit.

Deriving new singletons
-----------------------

The simplest example of deriving a new singleton instruction is simply to inherit from the correct
base and supply an :meth:`~object.__init__` method that has immutable defaults for any arguments.
For example::

    from qiskit.circuit.singleton import SingletonInstruction

    class MyInstruction(SingletonInstruction):
        def __init__(self, label=None):
            super().__init__("my_instruction", 1, 0, label=label)

    assert MyInstruction() is MyInstruction()
    assert MyInstruction(label="some label") is not MyInstruction()
    assert MyInstruction(label="some label").mutable

The singleton instance will use all the constructor's defaults.

You can also derive from an instruction that is itself a singleton.  The singleton nature of the
class will be inherited, though the singleton instances of the two classes will be different::

    class MyOtherInstruction(MyInstruction):
        pass

    assert MyOtherInstruction() is MyOtherInstruction()
    assert MyOtherInstruction() is not MyInstruction()

If for some reason you want to derive from :class:`SingletonInstruction`, or one of the related or
subclasses but *do not* want the default singleton instance to be created, such as if you are
defining a new abstract base class, you can set the keyword argument
``create_default_singleton=False`` in the class definition::

    class NotASingleton(SingletonInstruction, create_default_singleton=False):
        def __init__(self):
            return super().__init__("my_mutable", 1, 0, [])

    assert NotASingleton() is not NotASingleton()

If your constructor does not have defaults for all its arguments, you must set
``create_default_singleton=False``.

Subclasses of :class:`SingletonInstruction` and the other associated classes can control how their
constructor's arguments are interpreted, in order to help the singleton machinery return the
singleton even in the case than an optional argument is explicitly set to its default.

.. automethod:: SingletonInstruction._singleton_lookup_key

This is set by all Qiskit standard-library gates such that the :attr:`~Instruction.label` and
similar keyword arguments are ignored in the key calculation if they are their defaults, or a
mutable instance is returned if they are not.

You can also specify other combinations of constructor arguments to produce singleton instances
for, using the ``additional_singletons`` argument in the class definition.  This takes an iterable
of ``(args, kwargs)`` tuples, and will build singletons equivalent to ``cls(*args, **kwargs)``.  You
do not need to handle the case of the default arguments with this.  For example, given a class
definition::

    class MySingleton(SingletonGate, additional_singletons=[((2,), {"label": "two"})]):
        def __init__(self, n=1, label=None):
            super().__init__("my", n, [], label=label)

        @staticmethod
        def _singleton_lookup_key(n=1, label=None):
            return (n, label)

there will be two singleton instances instantiated.  One corresponds to ``n=1`` and ``label=None``,
and the other to ``n=2`` and ``label="two"``.  Whenever ``MySingleton`` is constructed with
arguments consistent with one of those two cases, the relevant singleton will be returned.  For
example::

    assert MySingleton() is MySingleton(1, label=None)
    assert MySingleton(2, "two") is MySingleton(n=2, label="two")

The case of the class being instantiated with zero arguments is handled specially to allow an
absolute fast-path for inner-loop performance (although the general machinery is not desperately
slow anyway).


Implementation
==============

.. note::

    This section is primarily developer documentation for the code; none of the machinery described
    here is public, and it is not safe to inherit from any of it directly.

There are several moving parts to tackle here.  The behavior of having ``XGate()`` return some
singleton object that is an (inexact) instance of :class:`.XGate` but *without* calling ``__init__``
requires us to override :class:`type.__call__ <type>`.  This means that :class:`.XGate` must have a
metaclass that defines ``__call__`` to return the singleton instance.

Next, we need to ensure that there *is* a singleton instance for ``XGate()`` to return.  This can be
done dynamically on each call (i.e. check if the instance exists and create it if not), but since
we also want that instance to be very special, it's easier to hook in and create it during the
definition of the ``XGate`` type object.  This also has the advantage that we do not need to make
the singleton object pickleable; we only need to specify where to retrieve it from during the
unpickle, because the creation of the base type object will recreate the singleton.

We want the singleton instance to:

* be immutable; it should reject all attempts to mutate itself.
* have exactly the same state as an ``XGate()`` would have had if there was no singleton handling.

We do this in a three-step procedure:

1. Before creating any singletons, we separately define the overrides needed to make an
   :class:`~.circuit.Instruction` and a :class:`.Gate` immutable.  This is
   ``_SingletonInstructionOverrides`` and the other ``_*Overrides`` classes.

2. While we are creating the ``XGate`` type object, we dynamically *also* create a subclass of it
   that has the immutable overrides in its method-resolution order in the correct place. These
   override the standard methods / properties that are defined on the mutable gate (we do not
   attempt to override any cases where the type object we are creating has extra inplace methods).

3. We can't instantiate this new subclass, because when it calls ``XGate.__init__``, it will attempt
   to set some attributes, and these will be rejected by immutability.  Instead, we first create a
   completely regular ``XGate`` instance, and then we dynamically change its type to the singleton
   class, freezing it.

We could do this entirely within the metaclass machinery, but that would require ``XGate`` to be
defined as something like::

  class XGate(Gate, metaclass=_SingletonMeta, overrides=_SingletonGateOverrides): ...

which is super inconvenient (or we'd have to have ``_SingletonMeta`` do a bunch of fragile
introspection).  Instead, we use the :class:`abc.ABC`/:class:`abc.ABCMeta` pattern of defining a
concrete middle class (:class:`SingletonGate` in the :class:`.XGate` case) that sets the metaclass,
selects the overrides to be applied, and has an :meth:`~object.__init_subclass__` that applies the
singleton-subclass-creation steps above.  The overrides are in separate classes so that *mutable*
:class:`.XGate` instances do not have them in their own method-resolution orders; doing this is
easier to implement, but requires all the setters and checkers to dance around at runtime trying to
validate whether mutating the instance is allowed.

Finally, to actually build all this machinery up, the base is ``_SingletonMeta``, which is a
metaclass compatible with any metaclass of :class:`~.circuit.Instruction`.  This defines the
:meth:`~object.__call__` machinery that overrides :class:`type.__call__ <type>` to return the
singleton instances.  The other component of it is its :meth:`~object.__new__`, which is called
(non-trivially) during the creation of :class:`SingletonGate` and :class:`SingletonInstruction` with
its ``overrides`` keyword argument set to define the ``__init_subclass__`` of those classes with the
above properties.  We use the metaclass to add this method dynamically, because the
:meth:`~object.__init_subclass__` machinery wants to be abstract, closing over the ``overrides`` and
the base class, but still able to call :class:`super`.  It's more convenient to do this dynamically,
closing over the desired class variable and using the two-argument form of :class:`super`, since the
zero-argument form does magic introspection based on where its containing function was defined.

Handling multiple singletons requires storing the initialization arguments in some form, to allow
the :meth:`~.Instruction.to_mutable` method and pickling to be defined.  We do this as a lookup
dictionary on the singleton *type object*.  This is logically an instance attribute, but because we
need to dynamically switch in the dynamic `_Singleton` type onto an instance of the base type, that
gets rather complex; either we have to require that the base already has an instance dictionary, or we
risk breaking the ``__slots__`` layout during the switch.  Since the singletons have lifetimes that
last until garbage collection of their base class's type object, we can fake out this instance
dictionary using a type-object dictionary that maps instance pointers to the data we want to store.
An alternative would be to build a new type object for each individual singleton that closes over
(or stores) the initializer arguments, but type objects are quite heavy and the principle is largely
same anyway.
    )annotationsN   )Instruction)Gate)ControlledGate_ctrl_state_to_intc                4   ^ ^ SSS.U U4S jjn[        U5      $ )NT )create_default_singletonadditional_singletonsc                 >^ ^ [         TT ]  " S0 UD6  U(       d  U(       d  g 0 T l         " U 4S jST	T SS9mST R                   3=Tl        Tl        UU U	4S jnU(       a  U" S0 5      T l        U H  u  pVU" XV5        M     g )Nc                  v   > \ rS rSrSrSr0 rS r\U 4S j5       r\S 5       r	S r
S rS	 rSS
 jrU 4S jrSrg)B_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singletoni  Nr
   c                4    [        SU R                   S35      e)Nzcannot create 'z' instances)	TypeError__name__)singleton_class_args_kwargss      R/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/circuit/singleton.py__new__J_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singleton.__new__'  s    //2J2J1K; WXX    c                   > T$ Nr
   )selfinstruction_classs    r   
base_classM_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singleton.base_class*  s	    ((r   c                    g)NFr
   r   s    r   mutableJ_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singleton.mutable.  s    r   c                t    [        U 5      R                  [        U 5         u  pU R                  " U0 UDSS0D6$ N_force_mutableT)type_singleton_init_argumentsidr   r   argskwargss      r   
to_mutableM_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singleton.to_mutable2  s5    #DzCCBtHMLLtLLr   c                H    [        SU R                  R                   S35      e)NzThis 'zO' object is immutable. You can get a mutable version by calling 'to_mutable()'.)r   r   r   )r   keyvalues      r   __setattr__N_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singleton.__setattr__6  s-    T__556 7P P r   c                    U $ r   r
   r!   s    r   __copy__K_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singleton.__copy__<      r   c                    U $ r   r
   )r   memos     r   __deepcopy__O_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singleton.__deepcopy__?  r7   r   c                |   > [        U 5      R                  [        U 5         u  p[        R                  " T40 UD6U4$ r   )r'   r(   r)   	functoolspartial)r   r+   r,   r   s      r   
__reduce__M_impl_init_subclass.<locals>.__init_subclass__.<locals>._Singleton.__reduce__B  s;      $DzCCBtHM!))*;FvFMMr   r   )r   
__module____qualname____firstlineno__	__slots__r(   r   propertyr   r"   r-   r2   r5   r:   r?   __static_attributes__)r   s   r   
_Singletonr     sf    J I )+%Y ) )  MN Nr   rG   F)r   c                   > T" U 0 UDSS0D6nTR                  U5      nTUl        X4TR                  [        U5      '   TR                  " U 0 UD6nUb  UTR
                  U'   U$ r%   )_prepare_singleton_instance	__class__r(   r)   _singleton_lookup_key_singleton_static_lookup)r+   r,   outr0   rG   r   	overridess       r   _create_singleton_instanceR_impl_init_subclass.<locals>.__init_subclass__.<locals>._create_singleton_instanceO  st    #TIVIDIC77<C&CM=ANJ00C9#994J6JCBE!::3?Jr   r
   )super__init_subclass__rL   r   rB   _singleton_default_instance)
r   r   r   r,   rO   
class_argsclass_kwargsrG   baserN   s
   `      @r   rR   ._impl_init_subclass.<locals>.__init_subclass__  s     	d%8B6B'0E 6826	N$5PU 6	Nt ;EEVE_E_D`8aa
j5
	  $<VWY[]<^9(=$J&z@ )>r   )classmethod)rV   rN   rR   s   `` r   _impl_init_subclassrY     s(     8<SUZA ZAx ())r   c                  H   ^  \ rS rSrSrSS.U 4S jjrSS.U 4S jjrSrU =r$ )	_SingletonMetaig  r
   NrN   c               R   > [         TU ]  " XX#40 UD6nUb  [        Xd5      Ul        U$ r   )rQ   r   rY   rR   )mcsnamebases	namespacerN   r,   clsrJ   s          r   r   _SingletonMeta.__new__s  s2    gocDVD  %8$GC!
r   F)r&   c                 > U(       a  [         TU ]  " U0 UD6$ U(       d  U(       d  U R                  $ U R                  " U0 UD6=nb!   U R                  R                  U5      nUb  U$ [         TU ]  " U0 UD6$ ! [         a    S n N#f = fr   )rQ   __call__rS   rK   rL   getr   )rb   r&   r+   r,   r0   	singletonrJ   s         r   re   _SingletonMeta.__call__|  s    7#T4V44F
 222,,d=f==CJ!88<<SA	
 $   w000  ! !	!s   	A9 9BB)	r   rA   rB   rC   rD   r   re   rF   __classcell__)rJ   s   @r   r[   r[   g  s&     I:>   -2 1 1r   r[   c                  ,    \ rS rSrSrSr\S 5       rSrg)_SingletonBasei  zBase class of all the user-facing (library-author-facing) singleton classes such as
:class:`SingletonGate`.

This defines the shared interface for those singletons.r
   c                     g)a(  Given the arguments to the constructor, return a key tuple that identifies the singleton
instance to retrieve, or ``None`` if the arguments imply that a mutable object must be
created.

For performance, as a special case, this method will not be called if the class constructor
was given zero arguments (e.g. the construction ``XGate()`` will not call this method, but
``XGate(label=None)`` will), and the default singleton will immediately be returned.

This static method can (and probably should) be overridden by subclasses.  The derived
signature should match the class's ``__init__``; this method should then examine the
arguments to determine whether it requires mutability, or what the cache key (if any) should
be.

The function should return either ``None`` or valid ``dict`` key (i.e. hashable and
implements equality).  Returning ``None`` means that the created instance must be mutable.
No further singleton-based processing will be done, and the class creation will proceed as
if there was no singleton handling.  Otherwise, the returned key can be anything hashable
and no special meaning is ascribed to it.  Whenever this method returns the same key, the
same singleton instance will be returned.  We suggest that you use a tuple of the values of
all arguments that can be set while maintaining the singleton nature.

Only keys that match the default arguments or arguments given to ``additional_singletons``
at class-creation time will actually return singletons; other values will return a standard
mutable instance.

.. note::

    The singleton machinery will handle an unhashable return from this function gracefully
    by returning a mutable instance.  Subclasses should ensure that their key is hashable in
    the happy path, but they do not need to manually verify that the user-supplied arguments
    are hashable.  For example, it's safe to implement this as::

        @staticmethod
        def _singleton_lookup_key(*args, **kwargs):
            return None if kwargs else args

    even though a user might give some unhashable type as one of the ``args``.
Nr
   )r   r   s     r   rK   $_SingletonBase._singleton_lookup_key  s    P r   N)	r   rA   rB   rC   __doc__rD   staticmethodrK   rF   r
   r   r   rk   rk     s     ?
 I' 'r   rk   )	metaclassc                  N    \ rS rSrSrS r\=r=r=r=r	=r
=r=rr\=r=r=rrSrg)_frozenlisti  r
   c                    [        S5      e)Nz('params' of singletons cannot be mutated)r   r*   s      r   _reject_mutation_frozenlist._reject_mutation  s    BCCr   N)r   rA   rB   rC   rD   rt   appendclearextendinsertpopremovereversesort__setitem____delitem____iadd____imul__rF   r
   r   r   rr   rr     sM    ID HXWFWUWVWfWsWVWg6FFKF+F8r   rr   c                  :    \ rS rSrSrSr\SS j5       rSS jrSr	g)	_SingletonInstructionOverridesi  zWOverrides for the mutable methods and properties of `Instruction` to make it immutable.r
   c                Z    U R                  5         [        U R                  5      U l        U $ )a  Class-creation hook point.  Given an instance of the type that these overrides correspond
to, this method should ensure that all lazy properties and caches that require mutation to
write to are eagerly defined.

Subclass "overrides" classes can override this method if the user/library-author-facing
class they are providing overrides for has more lazy attributes or user-exposed state
with interior mutability.)_definerr   _params)instructions    r   rI   :_SingletonInstructionOverrides._prepare_singleton_instance  s+     	
 *+*=*=>r   Nc                <    Uc  U $ U R                  5       nXl        U$ r   )r-   r_   )r   r_   rM   s      r   copy#_SingletonInstructionOverrides.copy  s"    <Koo
r   )r   r   r   )
r   rA   rB   rC   rn   rD   ro   rI   r   rF   r
   r   r   r   r     s#    aI   r   r   c                      \ rS rSrSrSrSrg)SingletonInstructioni  a[  A base class to use for :class:`~.circuit.Instruction` objects that by default are singleton
instances.

This class should be used for instruction classes that have fixed definitions and do not contain
any unique state. The canonical example of something like this is :class:`.Measure` which has an
immutable definition and any instance of :class:`.Measure` is the same. Using singleton
instructions as a base class for these types of gate classes provides a large advantage in the
memory footprint of multiple instructions.

The exception to be aware of with this class though are the :class:`~.circuit.Instruction`
attribute :attr:`~.Instruction.label` which can be set differently for
specific instances of gates.  For :class:`SingletonInstruction` usage to be sound setting these
attributes is not available and they can only be set at creation time, or on an object that has
been specifically made mutable using :meth:`~.Instruction.to_mutable`. If any of these
attributes are used during creation, then instead of using a single shared global instance of
the same gate a new separate instance will be created.r
   Nr   rA   rB   rC   rn   rD   rF   r
   r   r   r   r     s    >" Ir   r   r\   c                      \ rS rSrSrSrSrg)_SingletonGateOverridesi	  zOverrides for all the mutable methods and properties of `Gate` to make it immutable.

This class just exists for the principle; there's no additional overrides required compared
to :class:`~.circuit.Instruction`.r
   Nr   r
   r   r   r   r   	  s    *
 Ir   r   c                      \ rS rSrSrSrSrg)SingletonGatei  a  A base class to use for :class:`.Gate` objects that by default are singleton instances.

This class is very similar to :class:`SingletonInstruction`, except implies unitary
:class:`.Gate` semantics as well.  The same caveats around setting attributes in that class
apply here as well.r
   Nr   r
   r   r   r   r     s     Ir   r   c                      \ rS rSrSrSrSrg)!_SingletonControlledGateOverridesi  zOverrides for all the mutable methods and properties of `ControlledGate` to make it immutable.

This class just exists for the principle; there's no additional overrides required compared
to :class:`~.circuit.Instruction`.
r
   Nr   r
   r   r   r   r     s     Ir   r   c                      \ rS rSrSrSrSrg)SingletonControlledGatei&  a0  A base class to use for :class:`.ControlledGate` objects that by default are singleton instances

This class is very similar to :class:`SingletonInstruction`, except implies unitary
:class:`.ControlledGate` semantics as well.  The same caveats around setting attributes in
that class apply here as well.
r
   Nr   r
   r   r   r   r   &  s    
 Ir   r   )num_ctrl_qubitsc                L   ^  T (       a  SSS.U 4S jjjnOSS jn[        U5      $ )a  Create an implementation of the abstract method
:meth:`SingletonInstruction._singleton_lookup_key`, for standard-library instructions whose
``__init__`` signatures match the one given here.

.. warning::

    This method is not safe for use in classes defined outside of Qiskit; it is not included in
    the backwards compatibility guarantees.  This is because we guarantee that the call
    signatures of the base classes are backwards compatible in the sense that we will only
    replace them (without warning) contravariantly, but if you use this method, you effectively
    use the signature *invariantly*, and we cannot guarantee that.

Args:
    num_ctrl_qubits: if given, this implies that the gate is a :class:`.ControlledGate`, and
        will have a fixed number of qubits that are used as the control.  This is necessary to
        allow ``ctrl_state`` to be given as either ``None`` or as an all-ones integer/string.
N)_base_labelc               0   > U c  Uc  [        UT5      nU4$ g r   )r   )label
ctrl_stater   r   s      r   r0   !stdlib_singleton_key.<locals>.keyJ  s$    }!4/
OL
"}$r   c                    U c  gg )Nr
   r
   )r   s    r   r0   r   S  s    }r   )NNr   )ro   )r   r0   s   ` r   stdlib_singleton_keyr   5  s+    & 	D 	 		
 r   )rV   ztype[_SingletonBase]rN   z$type[_SingletonInstructionOverrides])r   int)rn   
__future__r   r=   r   r   gater   controlledgater   r   rY   r'   r[   rk   listrr   r   r   r   r   r   r   r   r
   r   r   <module>r      s   kZ #  $  >a*
a*+Oa*H)1T+& )1X0~ 0fG$ G![ !H;B` *<d D.4K (F / 45 # #r   