
    z	i+Z                        S r SSKJr  SSKrSSKrSSKrSSKJ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	KJrJr  SS
KJr  SSKJr  \R4                  (       a  SSKJr   " S S5      rS rg)zEDAGDependency class for representing non-commutativity in a circuit.
    )annotationsN)OrderedDict)Iterator)SessionCommutationChecker)condition_resources)QuantumRegisterQubit)ClassicalRegisterClbit)DAGDependencyError)
DAGDepNodeParameterExpressionc                  "   \ rS rSrSrS r\S 5       r\R                  S$S j5       rS r	S r
S rS	 rS
 rS rS rS%S jrS&S jrS'S jrS(S jrS rS rS rS rS)S jrS rS)S jrS)S jrS rS rS rS rS r S r!S r"S*S! jr#S+S" jr$S#r%g ),DAGDependency8   u  Object to represent a quantum circuit as a Directed Acyclic Graph (DAG)
via operation dependencies (i.e. lack of commutation).

The nodes in the graph are operations represented by quantum gates.
The edges correspond to non-commutation between two operations
(i.e. a dependency). A directed edge from node A to node B means that
operation A does not commute with operation B.
The object's methods allow circuits to be constructed.

The nodes in the graph have the following attributes:
'operation', 'successors', 'predecessors'.

**Example:**

Bell circuit with no measurement.

.. code-block:: text

          ┌───┐
    qr_0: ┤ H ├──■──
          └───┘┌─┴─┐
    qr_1: ─────┤ X ├
               └───┘

The dependency DAG for the above circuit is represented by two nodes.
The first one corresponds to Hadamard gate, the second one to the CNOT gate
as the gates do not commute there is an edge between the two nodes.

**Reference:**

[1] Iten, R., Moyard, R., Metger, T., Sutter, D. and Woerner, S., 2020.
Exact and practical pattern matching for quantum circuit optimization.
`arXiv:1909.05270 <https://arxiv.org/abs/1909.05270>`_

c                    SU l         0 U l        [        R                  " 5       U l        [        5       U l        [        5       U l        / U l        / U l	        SU l
        SU l        SU l        [        U l        g)z 
Create an empty DAGDependency.
Ng        dt)namemetadatarxPyDAG_multi_graphr   qregscregsqubitsclbits_global_phasedurationunitscccomm_checkerselfs    Y/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/dagcircuit/dagdependency.py__init__DAGDependency.__init__]   sf    
 	  HHJ !]
 ]
 :=	    c                    U R                   $ )z'Return the global phase of the circuit.)r   r#   s    r%   global_phaseDAGDependency.global_phasez   s     !!!r(   c                    SSK Jn  [        X5      (       a  Xl        g[	        U5      nU(       d  SU l        gUS[
        R                  -  -  U l        g)zSSet the global phase of the circuit.

Args:
    angle (float, ParameterExpression)
r   r      N)"qiskit.circuit.parameterexpressionr   
isinstancer   floatmathpi)r$   angler   s      r%   r*   r+      sD     	Ke11!& %LE%&"%*a$''k%:"r(   c                    U R                   $ )z-Returns the DAGDependency in retworkx format.)r   r#   s    r%   to_retworkxDAGDependency.to_retworkx   s       r(   c                ,    [        U R                  5      $ )z*Returns the number of gates in the circuit)lenr   r#   s    r%   sizeDAGDependency.size   s    4$$%%r(   c                V    [         R                  " U R                  5      nUS:  a  U$ S$ )z>Return the circuit depth.
Returns:
    int: the circuit depth
r   )r   dag_longest_path_lengthr   )r$   depths     r%   r=   DAGDependency.depth   s+    
 **4+<+<=
u))r(   c                    [        S U 5       5      (       a  [        S5      e[        U R                  5      R	                  U5      nU(       a  [        SU 35      eU R                  R                  U5        g)zAdd individual qubit wires.c              3  L   #    U  H  n[        U[        5      (       + v   M     g 7fN)r/   r	   ).0qubits     r%   	<genexpr>+DAGDependency.add_qubits.<locals>.<genexpr>        @:eU+++   "$znot a Qubit instance.zduplicate qubits N)anyr   setr   intersectionextend)r$   r   duplicate_qubitss      r%   
add_qubitsDAGDependency.add_qubits   c    @@@@$%<==t{{+88@$'89I8J%KLL6"r(   c                    [        S U 5       5      (       a  [        S5      e[        U R                  5      R	                  U5      nU(       a  [        SU 35      eU R                  R                  U5        g)zAdd individual clbit wires.c              3  L   #    U  H  n[        U[        5      (       + v   M     g 7frA   )r/   r   )rB   clbits     r%   rD   +DAGDependency.add_clbits.<locals>.<genexpr>   rF   rG   znot a Clbit instance.zduplicate clbits N)rH   r   rI   r   rJ   rK   )r$   r   duplicate_clbitss      r%   
add_clbitsDAGDependency.add_clbits   rO   r(   c                   [        U[        5      (       d  [        S5      eUR                  U R                  ;   a  [        SUR                   35      eXR                  UR                  '   [        U R                  5      n[        UR                  5       H*  nX   U;  d  M  U R                  R                  X   5        M,     g)z!Add qubits in a quantum register.znot a QuantumRegister instance.duplicate register N)
r/   r   r   r   r   rI   r   ranger9   append)r$   qregexisting_qubitsjs       r%   add_qregDAGDependency.add_qreg   s    $00$%FGG99

"$':499+%FGG $

499dkk*tyy!Awo-""47+ "r(   c                   [        U[        5      (       d  [        S5      eUR                  U R                  ;   a  [        SUR                   35      eXR                  UR                  '   [        U R                  5      n[        UR                  5       H*  nX   U;  d  M  U R                  R                  X   5        M,     g)z#Add clbits in a classical register.z!not a ClassicalRegister instance.rX   N)
r/   r
   r   r   r   rI   r   rY   r9   rZ   )r$   cregexisting_clbitsr]   s       r%   add_cregDAGDependency.add_creg   s    $ 122$%HII99

"$':499+%FGG $

499dkk*tyy!Awo-""47+ "r(   c                H    U R                   R                  U5      nX!l        U$ )zr
Args:
    node (DAGDepNode): considered node.

Returns:
    node_id(int): corresponding label to the added node.
)r   add_nodenode_id)r$   noderg   s      r%   _add_multi_graph_node#DAGDependency._add_multi_graph_node   s$     ##,,T2r(   c                H    [        U R                  R                  5       5      $ )z<
Returns:
    generator(dict): iterator over all the nodes.
)iterr   nodesr#   s    r%   	get_nodesDAGDependency.get_nodes   s    
 D%%++-..r(   c                8    U R                   R                  U5      $ )zd
Args:
    node_id (int): label of considered node.

Returns:
    node: corresponding to the label.
)r   get_node_datar$   rg   s     r%   get_nodeDAGDependency.get_node   s       ..w77r(   c                <    U R                   R                  XU5        g)z
Function to add an edge from given data (dict) between two nodes.

Args:
    src_id (int): label of the first node.
    dest_id (int): label of the second node.
    data (dict): data contained on the edge.

N)r   add_edge)r$   src_iddest_iddatas       r%   _add_multi_graph_edge#DAGDependency._add_multi_graph_edge   s     	""6D9r(   c                8    U R                   R                  X5      $ )z
Edge enumeration between two nodes through method get_all_edge_data.

Args:
    src_id (int): label of the first node.
    dest_id (int): label of the second node.

Returns:
    List: corresponding to all edges between the two nodes.
)r   get_all_edge_data)r$   rw   rx   s      r%   	get_edgesDAGDependency.get_edges   s       226CCr(   c           
         U R                   R                  5        VVVVs/ s H7  nU R                   R                  UR                  5        H
  u  p#nX#U4PM     M9     snnnn$ s  snnnnf )zK
Enumeration of all edges.

Returns:
    List: corresponding to the label.
)r   rm   	out_edgesrg   )r$   src_nodesrcdestry   s        r%   get_all_edgesDAGDependency.get_all_edges  sf     !--335
5%)%6%6%@%@AQAQ%R!D %R 5
 	
 
s   >A$
c                8    U R                   R                  U5      $ )z
Enumeration of all incoming edges for a given node.

Args:
    node_id (int): label of considered node.

Returns:
    List: corresponding incoming edges data.
)r   in_edgesrr   s     r%   get_in_edgesDAGDependency.get_in_edges  s       ))'22r(   c                8    U R                   R                  U5      $ )z
Enumeration of all outgoing edges for a given node.

Args:
    node_id (int): label of considered node.

Returns:
    List: corresponding outgoing edges data.
)r   r   rr   s     r%   get_out_edgesDAGDependency.get_out_edges   s       **733r(   c                h    [        U R                  R                  US5      R                  5       5      $ )z
Direct successors id of a given node as sorted list.

Args:
    node_id (int): label of considered node.

Returns:
    List: direct successors id as a sorted list
Fsortedr   adj_directionkeysrr   s     r%   direct_successorsDAGDependency.direct_successors,  s+     d''55guEJJLMMr(   c                h    [        U R                  R                  US5      R                  5       5      $ )z
Direct predecessors id of a given node as sorted list.

Args:
    node_id (int): label of considered node.

Returns:
    List: direct predecessors id as a sorted list
Tr   rr   s     r%   direct_predecessors!DAGDependency.direct_predecessors8  s+     d''55gtDIIKLLr(   c                L    U R                   R                  U5      R                  $ )z
Successors id of a given node as sorted list.

Args:
    node_id (int): label of considered node.

Returns:
    List: all successors id as a sorted list
)r   rq   
successorsrr   s     r%   r   DAGDependency.successorsD  s!       ..w7BBBr(   c                L    U R                   R                  U5      R                  $ )z
Predecessors id of a given node as sorted list.

Args:
    node_id (int): label of considered node.

Returns:
    List: all predecessors id as a sorted list
)r   rq   predecessorsrr   s     r%   r   DAGDependency.predecessorsP  s!       ..w7DDDr(   c                X    S n[        [        R                  " U R                  US95      $ )z`
Yield nodes in topological order.

Returns:
    generator(DAGNode): node in topological order.
c                    U R                   $ rA   )sort_key)xs    r%   _key-DAGDependency.topological_nodes.<locals>._keyd  s    ::r(   key)rl   r    lexicographical_topological_sortr   )r$   r   s     r%   topological_nodesDAGDependency.topological_nodes\  s'    	 B778I8ItTUUr(   c                   S/n[        USS5      (       d  UR                  U;  a  / nU H-  nUR                  U R                  R	                  U5      5        M/     [        USS5      (       aJ  [        UR                  5      R                  nU Vs/ s H  oR                  R	                  U5      PM     n	nO/ n	O/ n/ n	[        SUUR                  UU/ / UU	S9	n
U
$ s  snf )a5  Creates a DAGDepNode to the graph and update the edges.

Args:
    operation (qiskit.circuit.Operation): operation
    qargs (list[~qiskit.circuit.Qubit]): list of qubits on which the operation acts
    cargs (list[Clbit]): list of classical wires to attach to

Returns:
    DAGDepNode: the newly added node.
measure
_directiveF
_conditionNop)	typer   r   qargscargsr   r   qindicescindices)	getattrr   rZ   r   indexr   r   r   r   )r$   	operationr   r   
directivesqindices_listelem	cond_bitsrR   cindices_listnew_nodes              r%   _create_op_nodeDAGDependency._create_op_nodei  s      [
y,669>>Q[;[M$$T[[%6%6t%<=  y,55 0	0D0DELL	GP Qye!2!25!9y Q "MM""

 % !Rs   $Cc                j    U R                  XU5      nU R                  U5        U R                  5         g)a  Add a DAGDepNode to the graph and update the edges.

Args:
    operation (qiskit.circuit.Operation): operation as a quantum gate
    qargs (list[~qiskit.circuit.Qubit]): list of qubits on which the operation acts
    cargs (list[Clbit]): list of classical wires to attach to
N)r   ri   _update_edges)r$   r   r   r   r   s        r%   add_op_nodeDAGDependency.add_op_node  s0     ''	%@""8,r(   c           	     j   [        U R                  5      S-
  nU R                  U5      nS/U-  n[        US-
  SS5       H  nX4   (       a  U R                  U5      nU R                  R                  UR                  UR                  UR                  UR                  UR                  UR                  5      (       dH  U R                  R                  XASS05        U R                  R                  U5      nU H  nSX7'   M	     M  M  U R                  R                  U5      nU H  nSX7'   M	     M     g)a;  
Updates DagDependency by adding edges to the newly added node (max_node)
from the previously added nodes.
For each previously added node (prev_node), an edge from prev_node to max_node
is added if max_node is "reachable" from prev_node (this means that the two
nodes can be made adjacent by commuting them with other nodes), but the two nodes
themselves do not commute.

Currently. this function is only used when creating a new DAGDependency from another
representation of a circuit, and hence there are no removed nodes (this is why
iterating over all nodes is fine).
   TcommuteFN)r8   r   rs   rY   r"   r   r   r   r   rv   predecessor_indices)r$   max_node_idmax_node	reachableprev_node_id	prev_nodepredecessor_idspredecessor_ids           r%   r   DAGDependency._update_edges  s    $++,q0==-F[(	 "+/2r:L& MM,7	((00LLOOOOKKNNNN  %%..|9V[J\]&*&7&7&K&KL&YO*949	1 +:& #'"3"3"G"G"U&5N05I- '61 ;r(   c                    [        [        U R                  5      S-
  SS5       HK  n[        [        R
                  " U R                  U5      5      U R                  R                  U5      l        MM     g)z
Create the list of successors. Update DAGDependency 'successors' attribute. It has to
be used when the DAGDependency() object is complete (i.e. converters).
r   r   N)rY   r8   r   listr   descendantsrq   r   rr   s     r%   _add_successorsDAGDependency._add_successors  s[    
 S!2!23a7R@GBFt00':CD++G4? Ar(   c                    [        S[        U R                  5      5       HK  n[        [        R
                  " U R                  U5      5      U R                  R                  U5      l        MM     g)z
Create the list of predecessors for each node. Update DAGDependency
'predecessors' attribute. It has to be used when the DAGDependency() object
is complete (i.e. converters).
r   N)rY   r8   r   r   r   	ancestorsrq   r   rr   s     r%   _add_predecessorsDAGDependency._add_predecessors  sS     QD$5$5 67GDHT..8ED++G4A 8r(   c                   [        5       nU R                  Ul        U R                  R                  5       Ul        U R                  R                  5       Ul        U R                  5        H,  nUR                  R                  UR                  5       5        M.     U R                  5        H)  nUR                  R                  US   US   US   5        M+     U$ )zh
Function to copy a DAGDependency object.
Returns:
    DAGDependency: a copy of a DAGDependency object.
r   r   r-   )
r   r   r   copyr   rn   r   rf   r   rv   )r$   dagrh   edgess       r%   r   DAGDependency.copy  s     o99JJOO%	JJOO%	NN$D%%diik2 %'')E%%eAha%(C *
r(   Nc                    SSK Jn  U" XX#S9$ )a  
Draws the DAGDependency graph.

This function needs `pydot <https://github.com/erocarrera/pydot>`, which in turn needs
Graphviz <https://www.graphviz.org/>` to be installed.

Args:
    scale (float): scaling factor
    filename (str): file path to save image to (format inferred from name)
    style (str): 'plain': B&W graph
                 'color' (default): color input/output/op nodes

Returns:
    Ipython.display.Image: if in Jupyter notebook and not saving to file, otherwise None.
r   )
dag_drawer)r   scalefilenamestyle)&qiskit.visualization.dag_visualizationr   )r$   r   r   r   r   s        r%   drawDAGDependency.draw  s      	Fd(PPr(   c           	     f  ^ [        5       n[        5       nU Vs/ s H  owR                  PM     nnU(       d  [        S5      eU Hs  n	U[        U	R                  5      -  nU[        U	R                  5      -  n[        U	R                  SS5      n
U
c  MO  UR                  [        U
5      R                  5        Mu     U R                  U[        UU4S jS9[        UU4S jS9S9n U R                  R                  XUS9Ul        gs  snf ! [        R                   a  n[        S	5      UeSnAff = f)
a  Replace a block of nodes with a single node.

This is used to consolidate a block of DAGDepNodes into a single
operation. A typical example is a block of CX and SWAP gates consolidated
into a LinearFunction. This function is an adaptation of a similar
function from DAGCircuit.

It is important that such consolidation preserves commutativity assumptions
present in DAGDependency. As an example, suppose that every node in a
block [A, B, C, D] commutes with another node E. Let F be the consolidated
node, F = A o B o C o D. Then F also commutes with E, and thus the result of
replacing [A, B, C, D] by F results in a valid DAGDependency. That is, any
deduction about commutativity in consolidated DAGDependency is correct.
On the other hand, suppose that at least one of the nodes, say B, does not commute
with E. Then the consolidated DAGDependency would imply that F does not commute
with E. Even though F and E may actually commute, it is still safe to assume that
they do not. That is, the current implementation of consolidation may lead to
suboptimal but not to incorrect results.

Args:
    node_block (List[DAGDepNode]): A list of dag nodes that represents the
        node block to be replaced
    op (qiskit.circuit.Operation): The operation to replace the
        block with
    wire_pos_map (Dict[~qiskit.circuit.Qubit, int]): The dictionary mapping the qarg to
        the position. This is necessary to reconstruct the qarg order
        over multiple gates in the combined single op node.
    cycle_check (bool): When set to True this method will check that
        replacing the provided ``node_block`` with a single node
        would introduce a cycle (which would invalidate the
        ``DAGDependency``) and will raise a ``DAGDependencyError`` if a cycle
        would be introduced. This checking comes with a run time
        penalty. If you can guarantee that your input ``node_block`` is
        a contiguous block and won't introduce a cycle when it's
        contracted to a single node, this can be set to ``False`` to
        improve the runtime performance of this method.
Raises:
    DAGDependencyError: if ``cycle_check`` is set to ``True`` and replacing
        the specified block introduces a cycle or if ``node_block`` is
        empty.
z!Can't replace an empty node_blockr   Nc                   > TU    $ rA    r   wire_pos_maps    r%   <lambda>5DAGDependency.replace_block_with_op.<locals>.<lambda>I  	    LOr(   r   c                   > TU    $ rA   r   r   s    r%   r   r   J  r   r(   )r   r   )check_cyclez:Replacing the specified node block would introduce a cycle)rI   rg   r   r   r   r   r   updater   r   r   r   r   contract_nodesr   DAGWouldCycle)r$   
node_blockr   r   cycle_checkblock_qargsblock_cargsr   	block_idsndcondr   exs      `         r%   replace_block_with_op#DAGDependency.replace_block_with_op  s$   T ee(23
1YY
	3 $%HIIB3rxx=(K3rxx=(K255,5D""#6t#<#C#CD  ''*CD*CD ( 
	#00??  @  H+ 40  	$L	s   D&D D0D++D0)r   r   r   r"   r   r   r   r   r   r   r    )r3   zfloat | ParameterExpression)rh   r   returnint)r   zIterator[DAGDepNode])rg   r   r   r   )rw   r   rx   r   )rg   r   r   z	list[int])gffffff?Ncolor)T)&__name__
__module____qualname____firstlineno____doc__r&   propertyr*   setterr5   r9   r=   rM   rU   r^   rc   ri   rn   rs   rz   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   __static_attributes__r   r(   r%   r   r   8   s    "H : " " ; ;$!&*	#	#
,
,
/8
:D

3
4
N
M
C
EV*X
/6b	$Q(Gr(   r   c               '  n   #    [        5       n[        R                  " U 6  H  nX!:w  d  M
  UnUv   M     g7f)zMerge K list without duplicate using python heapq ordered merging

Args:
    *iterables: A list of k sorted lists

Yields:
    Iterator: List from the merging of the k ones (without duplicates
N)objectheapqmerge)	iterableslastvals      r%   merge_no_duplicatesr  W  s0      8D{{I&;DI 's   $55)r  
__future__r   r1   r	  typingcollectionsr   collections.abcr   	rustworkxr   "qiskit.circuit.commutation_libraryr   r!   qiskit.circuit.controlflowr   qiskit.circuitr   r	   r
   r   qiskit.dagcircuit.exceptionsr   qiskit.dagcircuit.dagdepnoder   TYPE_CHECKINGr.   r   r   r  r   r(   r%   <module>r     sO    "    # $  O : 1 3 ; 3	F.\ \~r(   