
    z	i)                     F    S r SSKJr  SSKJr  SSKJrJr   " S S\5      rg)zFCollect sequences of uninterrupted gates acting on a number of qubits.    )AnalysisPass)Gate)	DAGOpNode	DAGInNodec                   B   ^  \ rS rSrSrSU 4S jjrS rS rS rSr	U =r
$ )	CollectMultiQBlocks   a  Collect sequences of uninterrupted gates acting on groups of qubits.
``max_block_size`` specifies the maximum number of qubits that can be acted upon
by any single group of gates

Traverse the DAG and find blocks of gates that act consecutively on
groups of qubits. Write the blocks to ``property_set`` as a list of blocks
of the form::

    [[g0, g1, g2], [g4, g5]]

Blocks are reported in a valid topological order. Further, the gates
within each block are also reported in topological order
Some gates may not be present in any block (e.g. if the number
of operands is greater than ``max_block_size``)

By default, blocks are collected in the direction from the inputs towards the
outputs of the DAG. The option ``collect_from_back`` allows to change this
direction, that is to collect blocks from the outputs towards the inputs.
Note that the blocks are still reported in a valid topological order.

A Disjoint Set Union data structure (DSU) is used to maintain blocks as
gates are processed. This data structure points each qubit to a set at all
times and the sets correspond to current blocks. These change over time
and the data structure allows these changes to be done quickly.
c                 d   > [         TU ]  5         0 U l        0 U l        0 U l        Xl        X l        g )N)super__init__parent
bit_groupsgate_groupsmax_block_sizecollect_from_back)selfr   r   	__class__s      y/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/transpiler/passes/optimization/collect_multiqubit_blocks.pyr   CollectMultiQBlocks.__init__/   s2     ,!2    c                    XR                   ;  a-  XR                   U'   U/U R                  U'   / U R                  U'   U R                   U   U:X  a  U$ U R                  U R                   U   5      U R                   U'   U R                   U   $ )zDSU function for finding root of set of items
If my parent is myself, I am the root. Otherwise we recursively
find the root for my parent. After that, we assign my parent to be
my root, saving recursion in the future.
)r   r   r   find_set)r   indexs     r   r   CollectMultiQBlocks.find_set;   s     #!&KK&+WDOOE"&(DU#;;u&L!]]4;;u+=>E{{5!!r   c                    U R                  U5      nU R                  U5      nX:X  a  g[        U R                  U   5      [        U R                  U   5      :  a  X!p!XR                  U'   U R                  U   R	                  U R                  U   5        U R
                  U   R	                  U R
                  U   5        U R                  U   R                  5         U R
                  U   R                  5         g)zDSU function for unioning two sets together
Find the roots of each set. Then assign one to have the other
as its parent, thus liking the sets.
Merges smaller set into larger set in order to have better runtime
N)r   lenr   r   extendr   clear)r   set1set2s      r   	union_setCollectMultiQBlocks.union_setK   s     }}T"}}T"<t%&T-=-=d-C)DD$ D%%d&6&6t&<=$$T__T%:;$$&##%r   c                 @	   0 U l         0 U l        0 U l        / nS nUR                  US9nU R                  (       a  [        [        U5      5      nU GH  nSnSn[        UR                  SS5      c>  UR                  R                  5       (       d  [        UR                  [        5      (       d  SnUR                   Vs1 s H  oR                  U5      R                  iM     n	nU(       aj  [        5       n
U	 H#  nU
R!                  U R#                  U5      5        M%     SnU
 H  nU[%        U R                  U   5      -  nM      XR&                  :  a  SnU(       d  U	 H  nU R#                  U5      n[%        U R                  U   5      S:X  a  M2  UR)                  U R                  U   SS 5        [        U R                  U   5      nU H0  nXR                   U'   U/U R                  U'   / U R                  U'   M2     M     U(       Gac  0 nSnU	 H`  nU R#                  U5      nUU;   a  UU   S-
  UU'   M'  [%        U R                  U   5      S-
  UU'   U[%        U R                  U   5      -  nMb     / nUR+                  5        H  u  nnUR)                  UU45        M     UR-                  SS	9  XR&                  -
  nU H  nUS:  d  M  UUS   -
  n[%        U R                  US      5      S:  a$  UR)                  U R                  US      SS 5        [        U R                  US      5      nU H0  nXR                   U'   U/U R                  U'   / U R                  U'   M2     M     U(       d  GM(  [%        U	5      U R&                  :  a  GMD  S
nU	 H  nUS
:w  a  U R/                  UU5        UnM     U R                  U R#                  U5         R)                  U5        GM     U R                   R+                  5        HM  u  nnUU:X  d  M  [%        U R                  U   5      S:w  d  M,  UR)                  U R                  U   SS 5        MO     U R                  (       a  USSS
2    Vs/ s H  nUSSS
2   PM     nnX R0                  S'   U$ s  snf s  snf )a  Run the CollectMultiQBlocks pass on `dag`.

The blocks contain "op" nodes in topological sort order
such that all gates in a block act on the same set of
qubits and are adjacent in the circuit.

The blocks are built by examining predecessors and successors of
"cx" gates in the circuit. u1, u2, u3, cx, id gates will be included.

After the execution, ``property_set['block_list']`` is set to
a list of tuples of ``DAGNode`` objects
c                 d   [        U [        5      (       a  g[        U [        5      (       d  g[        U R                  [        5      (       ae  U R                  R                  5       (       d  [        U R                  SS5      b  gS[        [        S5      [        U R                  5      -   5      -   $ g)a  special key function for topological ordering.
Heuristic for this is to push all gates involving measurement
or barriers, etc. as far back as possible (because they force
blocks to end). After that, we process gates in order of lowest
number of qubits acted on to largest number of qubits acted on
because these have less chance of increasing the size of blocks
The key also processes all the non operation notes first so that
input nodes do not mess with the top sort of op nodes
ad
_conditionNcb)
isinstancer   r   opr   is_parameterizedgetattrchrordr   qargs)xs    r   collect_key,CollectMultiQBlocks.run.<locals>.collect_keyr   s     !Y''a++!$$%%44((**gaddL$.O.[SSCL!8999r   )keyTFr'   Nr      )reverse
block_list)r   r   r   topological_op_nodesr   reversedlistr-   r+   r,   r*   r   r0   find_bitr   setaddr   r   r   appenditemssortr!   property_set)r   dagr8   r2   op_nodesndcan_processmakes_too_bigbit
cur_qubitsc_topstot_sizegroupcur_setvsavingstopslistitemvaluesavings_needprevr   blocks                           r   runCollectMultiQBlocks.run^   sL    
	( +++< !!X/HBK!M |T2>55))++!"%%..#=?XXFXc,,s+11XJF %CJJt}}S12 &#EDOOE$: ;;H $111$(M%C--,C4++C01Q6 %%d&6&6s&;A&>?!$//#"67G$)*A./S*.0((+	 % &  %C--,Cg~'.s|a'7'*4??3+?'@1'D C(<$== & #*==?KD%LL%/ $3

4
('*=*==!D $a''3d1g'=t//Q89Q>&--d.>.>tAw.G.JK"%dood1g&>"?!(A-.KKN23DOOA.24D,,Q/ ") "  { z?T%8%88
 %CrztS1D &   t!45<<R@s v  ;;,,.KE4u}T%5%5e%<!=!B!!$"2"25"9!"<= / !!3=dd3CD3C%%"+3CJD*4,'
u Gl Es   ?$R2R)r   r   r   r   r   )   F)__name__
__module____qualname____firstlineno____doc__r   r   r!   rW   __static_attributes____classcell__)r   s   @r   r   r      s#    4
3" &&T Tr   r   N)	r^   qiskit.transpiler.basepassesr   qiskit.circuitr   qiskit.dagcircuitr   r   r    r   r   <module>re      s"    M 5  2^, ^r   