§
    º³Ùg—;  ã                   ó6  — d Z ddlZddlZddlZddlZddlmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZ dd	lmZ  ej        e¦  «        Z ej        d
d¦  «        Z	  ej        ddd¬¦  «        Z G d„ de¦  «        Zd„ Zd„ Zdd„Zd„ Zd„ Zd„ Zd„ Z d„ Z!dS )zAMap input circuit onto a backend topology via insertion of SWAPs.é    N)ÚSwapGate)ÚTransformationPass)ÚTranspilerError)ÚLayout)Ú	DAGOpNode)ÚTarget)Údisjoint_utilsÚ_Step)ÚstateÚswaps_addedÚgates_mappedÚgates_remainingÚ_SystemState)ÚlayoutÚcoupling_mapÚregisterÚswaps©N)Údefaultsc                   ó*   ‡ — e Zd ZdZdˆ fd„	Zd„ Zˆ xZS )ÚLookaheadSwapaÀ  Map input circuit onto a backend topology via insertion of SWAPs.

    Implementation of Sven Jandura's swap mapper submission for the 2018 Qiskit
    Developer Challenge, adapted to integrate into the transpiler architecture.

    The role of the swapper pass is to modify the starting circuit to be compatible
    with the target device's topology (the set of two-qubit gates available on the
    hardware.) To do this, the pass will insert SWAP gates to relocate the virtual
    qubits for each upcoming gate onto a set of coupled physical qubits. However, as
    SWAP gates are particularly lossy, the goal is to accomplish this remapping while
    introducing the fewest possible additional SWAPs.

    This algorithm searches through the available combinations of SWAP gates by means
    of a narrowed best first/beam search, described as follows:

    - Start with a layout of virtual qubits onto physical qubits.
    - Find any gates in the input circuit which can be performed with the current
      layout and mark them as mapped.
    - For all possible SWAP gates, calculate the layout that would result from their
      application and rank them according to the distance of the resulting layout
      over upcoming gates (see _calc_layout_distance.)
    - For the four (search_width) highest-ranking SWAPs, repeat the above process on
      the layout that would be generated if they were applied.
    - Repeat this process down to a depth of four (search_depth) SWAPs away from the
      initial layout, for a total of 256 (search_width^search_depth) prospective
      layouts.
    - Choose the layout which maximizes the number of two-qubit which could be
      performed. Add its mapped gates, including the SWAPs generated, to the
      output circuit.
    - Repeat the above until all gates from the initial circuit are mapped.

    For more details on the algorithm, see Sven's blog post:
    https://medium.com/qiskit/improving-a-quantum-compiler-48410d7a7084
    é   Fc                 ó  •— t          ¦   «                              ¦   «          t          |t          ¦  «        r&|| _        | j                             ¦   «         | _        nd| _        || _        || _        || _        || _	        dS )a´  LookaheadSwap initializer.

        Args:
            coupling_map (Union[CouplingMap, Target]): CouplingMap of the target backend.
            search_depth (int): lookahead tree depth when ranking best SWAP options.
            search_width (int): lookahead tree width when ranking best SWAP options.
            fake_run (bool): if true, it will only pretend to do routing, i.e., no
                swap is effectively added.
        N)
ÚsuperÚ__init__Ú
isinstancer   ÚtargetÚbuild_coupling_mapr   Úsearch_depthÚsearch_widthÚfake_run)Úselfr   r   r    r!   Ú	__class__s        €úe/granary/edev/quantum/lib/python3.11/site-packages/qiskit/transpiler/passes/routing/lookahead_swap.pyr   zLookaheadSwap.__init__V   sw   ø€ õ 	‰Œ×ÒÑÔÐÝ�l¥FÑ+Ô+ð 	-Ø&ˆDŒKØ $¤× >Ò >Ñ @Ô @ˆDÔÐàˆDŒKØ ,ˆDÔØ(ˆÔØ(ˆÔØ ˆŒˆˆó    c                 ó  — | j         €t          d¦  «        ‚t          |j        ¦  «        dk    s|j                             dd¦  «        €t          d¦  «        ‚t          | j         j        ¦  «        }t          |j        ¦  «        |k    r(t          dt          |j        ¦  «        › d|› d�¦  «        ‚t          j        || j	        €| j         n| j	        ¦  «         |j        d         }t          t          j        |¦  «        | j         |¦  «        }g }t          |                     ¦   «         ¦  «        }|r´t                               d	t          |¦  «        ¦  «         t#          ||| j        | j        ¦  «        }|€t          d
¦  «        ‚t                               dt          |j        ¦  «        |j        ¦  «         |j        }|j        }|j        }|                     |¦  «         |°´| j        d         €|j        | j        d<   n3|j                             | j        d         |j        ¦  «        | j        d<   | j        r|S |                     ¦   «         }	|D ]*}
|	                     |
j        |
j         |
j!        d¬¦  «         Œ+|	S )aœ  Run the LookaheadSwap pass on `dag`.

        Args:
            dag (DAGCircuit): the directed acyclic graph to be mapped
        Returns:
            DAGCircuit: A dag mapped to be compatible with the coupling_map in
                the property_set.
        Raises:
            TranspilerError: if the coupling map or the layout are not
            compatible with the DAG, or if the coupling_map=None
        Nz/LookaheadSwap cannot run with coupling_map=Noneé   Úqz-Lookahead swap runs on physical circuits onlyzThe number of DAG qubits (z9) is greater than the number of available device qubits (z).z+Top-level routing step: %d gates remaining.zLLookahead failed to find a swap which mapped gates or improved layout score.z2Found best step: mapped %d gates. Added swaps: %s.Úfinal_layoutF)Úcheck)"r   r   ÚlenÚqregsÚgetÚphysical_qubitsÚqubitsr	   Ú$require_layout_isolated_to_componentr   r   r   Úgenerate_trivial_layoutÚlistÚserial_layersÚloggerÚdebugÚ_search_forward_n_swapsr   r    r   r   r   r   ÚextendÚproperty_setr   Úcomposer!   Úcopy_empty_likeÚapply_operation_backÚopÚqargsÚcargs)r"   ÚdagÚnumber_of_available_qubitsr   Úcurrent_stateÚmapped_gatesr   Ú	best_stepr   Ú
mapped_dagÚnodes              r$   ÚrunzLookaheadSwap.runl   s¹  € ð ÔÐ$Ý!Ð"SÑTÔTÐTåˆsŒy‰>Œ>˜QÒÐ #¤)§-¢-°°TÑ":Ô":Ð"BÝ!Ð"QÑRÔRÐRå%(¨Ô):Ô)JÑ%KÔ%KÐ"ÝˆsŒz‰?Œ?Ð7Ò7Ð7Ý!ðK­S°´©_¬_ð Kð KØ,FðKð Kð Kñô ð õ 	Ô;Ø d¤kÐ&9�Ô"Ð"¸t¼{ñ	
ô 	
ð 	
ð ”9˜S”>ˆÝ$ÝÔ*¨8Ñ4Ô4°dÔ6GÈñ
ô 
ˆð ˆÝ˜s×0Ò0Ñ2Ô2Ñ3Ô3ˆàð 	.Ý�LŠLÐFÍÈOÑH\ÔH\Ñ]Ô]Ð]å/ØØØÔ!ØÔ!ñ	ô ˆIð Ð Ý%Øbñô ð õ �LŠLØDÝ�IÔ*Ñ+Ô+ØÔ%ñô ð ð &œOˆMØ$Ô1ˆLØ'Ô7ˆOà×Ò Ñ-Ô-Ð-ð3 ð 	.ð6 Ô˜^Ô,Ð4Ø0=Ô0DˆDÔ˜nÑ-Ð-à0=Ô0D×0LÒ0LØÔ! .Ô1°3´:ñ1ô 1ˆDÔ˜nÑ-ð Œ=ð 	ØˆJð ×(Ò(Ñ*Ô*ˆ
Ø ð 	Zð 	ZˆDØ×+Ò+¨D¬G°T´ZÀÄÐSXÐ+ÑYÔYÐYÐYàÐr%   )r   r   F)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   rF   Ú__classcell__)r#   s   @r$   r   r   2   s^   ø€ € € € € ð!ð !ðF!ð !ð !ð !ð !ð !ð,Oð Oð Oð Oð Oð Oð Or%   r   c           	      ó|  ‡ ‡— ‰ j         €7‰                      d„ ‰ j                             ¦   «         D ¦   «         ¬¦  «        Š t	          ‰ ‰¦  «        \  }}t          ‰ g ||¦  «        }|r|dk    r|S t          ˆˆ fd„‰ j         D ¦   «         d„ ¬¦  «        }t                               d|d	„ |d|d
z  …         D ¦   «         ¦  «         ddt          j
         }
}	}t          |¦  «        D ]ó\  }\  }}}t          |||dz
  |¦  «        }|€Œ!t          |¦  «        }||
k    r,t                               d||g|j        z   |¦  «         |||}
}	}|t          |t!          |¦  «        dz
  ¦  «        k    rm|	�kt!          |	j        ¦  «        |k    sQt!          |	j        ¦  «        t!          |¦  «        k     s,t'          |	j        |	j        ¦  «        t'          ||¦  «        k     r nŒôdS t+          |‰ ¦  «        }t          |	j        |g|	j        z   ||z   |	j        z   |	j        ¦  «        }t                               d||j        ¦  «         |S )aŽ  Search for SWAPs which allow for application of largest number of gates.

    Args:
        state (_SystemState): The ``namedtuple`` collection containing the state of the physical
            system.  This includes the current layout, the coupling map, the canonical register and
            the possible swaps available.
        gates (list): Gates to be mapped.
        depth (int): Number of SWAP layers to search before choosing a result.
        width (int): Number of SWAPs to consider at each layer.
    Returns:
        Optional(_Step): Describes the solution step found.  If ``None``, no swaps leading to an
        improvement were found.
    Nc                 ó0   — h | ]\  }}||k     r||fn||f’ŒS © rN   )Ú.0ÚaÚbs      r$   ú	<setcomp>z*_search_forward_n_swaps.<locals>.<setcomp>Ï   s0   € Ð\Ð\Ð\±T°Q¸˜a !še˜e�Q˜�F�F¨!¨Q¨Ð\Ð\Ð\r%   )r   r   c              3   ó:   •K  — | ]}t          |‰‰¦  «        V — Œd S r   )Ú_score_state_with_swap)rO   ÚswapÚgatesr   s     €€r$   ú	<genexpr>z*_search_forward_n_swaps.<locals>.<genexpr>Ø   s0   øè è € ÐLÐL¸Õ	  e¨UÑ	3Ô	3ÐLÐLÐLÐLÐLÐLr%   c                 ó   — | d         S )Nr   rN   )Úxs    r$   ú<lambda>z)_search_forward_n_swaps.<locals>.<lambda>Ù   s
   € �a˜”d€ r%   )Úkeyz*At depth %d, ranked candidate swaps: %s...c                 ó   — g | ]
\  }}}||f‘ŒS rN   rN   )rO   ÚscorerU   Ú_s       r$   ú
<listcomp>z+_search_forward_n_swaps.<locals>.<listcomp>Þ   s"   € ÐGÐGÐG™>˜5 $¨ˆ$�ˆÐGÐGÐGr%   é   r'   z0At depth %d, updating best step: %s (score: %f).zAt depth %d, best_swap set: %s.)r   Ú_replacer   Ú	get_edgesÚ_map_free_gatesr
   Úsortedr4   r5   ÚmathÚinfÚ	enumerater6   Ú_score_stepr   Úminr+   r   r   Ú_calc_layout_distancer   Ú_swap_ops_from_edge)r   rV   ÚdepthÚwidthr   r   Ú	base_stepÚranked_swapsÚ	best_swaprC   Ú
best_scoreÚrankr^   rU   Ú	new_stateÚ	next_stepÚ
next_scoreÚbest_swap_gateÚouts   ``                 r$   r6   r6   ¾   s�  øø€ ð „{Ðà—’Ø\Ð\¸UÔ=O×=YÒ=YÑ=[Ô=[Ð\Ñ\Ô\ð ñ 
ô 
ˆõ %4°E¸5Ñ$AÔ$AÑ!€L�/Ý�e˜R ¨Ñ?Ô?€Iàð ˜e qšj˜jØÐåØLÐLÐLÐLÐLÀÄÐLÑLÔLØˆNðñ ô €Lõ ‡L‚LØ4ØØGÐG¨\¸+¸EÀA¹I¸+Ô-FÐGÑGÔGñô ð ð (,¨TµD´H°9˜*ˆy€IÝ&/°Ñ&=Ô&=ð #ð #Ñ"ˆÑ"ˆq�$˜	Ý+¨I°ÈÐPQÉ	ÐSXÑYÔYˆ	àÐØå  Ñ+Ô+ˆ
à˜
Ò"Ð"Ý�LŠLØBØØ�˜Ô.Ñ.Øñ	ô ð ð 04°YÀ
 *�yˆIð •C˜�s <Ñ0Ô0°1Ñ4Ñ5Ô5Ò5Ð5ØÐ%å�IÔ*Ñ+Ô+¨eÒ3Ð3Ý�yÔ0Ñ1Ô1µC¸Ñ4HÔ4HÒHÐHå)¨)Ô*CÀYÄ_ÑUÔUÝ+¨O¸YÑGÔGòHð Hð ˆEøàˆtå(¨°EÑ:Ô:€NÝ
ØŒØ	ˆ�iÔ+Ñ+Ø�~Ñ%¨	Ô(>Ñ>ØÔ!ñ	ô €Cõ ‡L‚LÐ2°E¸3¼?ÑKÔKÐKØ€Jr%   c                 óŠ  — t          ¦   «         }g }g }| j        j        }|D �]ž}|d         sƒt          |d         ¦  «        j        }|sŒ(|                     |¦  «        r+|                     |¦  «         |                     |¦  «         n%t          || ¦  «        }|                     |¦  «         ŒŽ|d         d         }|                     |¦  «        r+|                     |¦  «         |                     |¦  «         ŒÜt          |¦  «        dk    r't          || ¦  «        }|                     |¦  «         �Œ| j
                             ||d                  ||d                  ¦  «        dk    r't          || ¦  «        }|                     |¦  «         �Œt|                     |¦  «         |                     |¦  «         �Œ ||fS )aÅ  Map all gates that can be executed with the current layout.

    Args:
        state (_SystemState): The physical characteristics of the system, including its current
            layout and the coupling map.
        gates (list): Gates to be mapped.

    Returns:
        tuple:
            mapped_gates (list): ops for gates that can be executed, mapped onto layout.
            remaining_gates (list): gates that cannot be executed on the layout.
    Ú	partitionÚgraphr   r'   )Úsetr   Ú_v2pÚ_first_op_noder=   ÚintersectionÚupdateÚappendÚ_transform_gate_for_systemr+   r   Údistance)	r   rV   Úblocked_qubitsrB   Úremaining_gatesÚ
layout_mapÚgater/   Úmapped_gates	            r$   rc   rc     sÚ  € õ ‘U”U€Nà€LØ€OØ”Ô"€Jàð )ñ )ˆð �KÔ ð 	Ý# D¨¤MÑ2Ô2Ô8ˆFàð Øà×*Ò*¨6Ñ2Ô2ð 1Ø×%Ò% fÑ-Ô-Ð-Ø×&Ò& tÑ,Ô,Ð,Ð,å8¸¸uÑEÔE�Ø×#Ò# KÑ0Ô0Ð0Øà�kÔ" 1Ô%ˆà×&Ò& vÑ.Ô.ð 	)Ø×!Ò! &Ñ)Ô)Ð)Ø×"Ò" 4Ñ(Ô(Ð(Ð(Ý�‰[Œ[˜AÒÐÝ4°T¸5ÑAÔAˆKØ×Ò Ñ,Ô,Ð,Ñ,ØÔ×(Ò(¨°F¸1´IÔ)>À
È6ÐRSÌ9Ô@UÑVÔVÐZ[Ò[Ð[Ý4°T¸5ÑAÔAˆKØ×Ò Ñ,Ô,Ð,Ñ,à×!Ò! &Ñ)Ô)Ð)Ø×"Ò" 4Ñ(Ô(Ð(Ñ(à˜Ð(Ð(r%   c                 ó>  — |€ddt          |j        j        ¦  «        z  z   }|j        j        }d}| d|…         D ]b}|d         sŒ|d         d         }t          |¦  «        dk    r6||j                             ||d                  ||d                  ¦  «        z  }Œc|S )z{Return the sum of the distances of two-qubit pairs in each CNOT in gates
    according to the layout and the coupling.
    Né2   é
   r   ry   r`   r'   )r+   r   r.   r   r|   r‚   )rV   r   Ú	max_gatesr…   rw   r†   r/   s          r$   rj   rj   H  s¸   € ð ÐØ˜�c %Ô"4Ô"DÑEÔEÑEÑEˆ	à”Ô"€JØ
€CØ�j�y�jÔ!ð ]ð ]ˆØ�KÔ ð 	ØØ�kÔ" 1Ô%ˆÝˆv‰;Œ;˜!ÒÐØ�5Ô%×.Ò.¨z¸&À¼)Ô/DÀjÐQWÐXYÔQZÔF[Ñ\Ô\Ñ\ˆCøØ€Jr%   c                 óš   — |j                              ¦   «         } |j        | Ž  |                     |¬¦  «        }t	          ||¦  «        | |fS )züCalculate the relative score for a given SWAP.

    Returns:
        float: the score of the given swap.
        Tuple[int, int]: the input swap that should be performed.
        _SystemState: an updated system state with the new layout contained.
    )r   )r   ÚcopyrU   ra   rj   )rU   r   rV   Útrial_layoutrs   s        r$   rT   rT   Z  sQ   € ð ”<×$Ò$Ñ&Ô&€LØ€LÔ�tÐÐØ—’ l�Ñ3Ô3€IÝ  ¨	Ñ2Ô2°D¸)ÐCÐCr%   c                 ón   — t          d„ | j        D ¦   «         ¦  «        dt          | j        ¦  «        z  z
  S )zACount the mapped two-qubit gates, less the number of added SWAPs.c                 óB   — g | ]}t          |j        ¦  «        d k    ¯|‘ŒS )r`   )r+   r=   )rO   Úgs     r$   r_   z_score_step.<locals>.<listcomp>k  s*   € ÐBÐBÐB�aµ°A´G±´ÀÒ0AÐ0A�Ð0AÐ0AÐ0Ar%   é   )r+   r   r   )Ústeps    r$   rh   rh   h  s9   € õ ÐBÐB˜4Ô,ÐBÑBÔBÑCÔCÀaÍ#ÈdÔN^ÑJ_ÔJ_ÑF_Ñ_Ð_r%   c                 óÊ   ‡‡— t          j         t          | d         ¦  «        ¦  «        }|j        Š|j        j        Št          ˆˆfd„|j        D ¦   «         ¦  «        |_        |S )z6Return op implementing a virtual gate on given layout.rz   c              3   ó4   •K  — | ]}‰‰|                  V — Œd S r   rN   )rO   rP   Údevice_qregr…   s     €€r$   rW   z-_transform_gate_for_system.<locals>.<genexpr>t  s,   øè è € Ð ZÐ ZÀ ¨Z¸¬]Ô!;Ð ZÐ ZÐ ZÐ ZÐ ZÐ Zr%   )r�   r}   r   r   r|   Útupler=   )r†   r   Úmapped_op_noder–   r…   s      @@r$   r�   r�   n  sa   øø€ å”Y�~¨d°7¬mÑ<Ô<Ñ=Ô=€Nà”.€KØ”Ô"€JÝ Ð ZÐ ZÐ ZÐ ZÐ ZÀ^ÔEYÐ ZÑ ZÔ ZÑZÔZ€NÔàÐr%   c                 ó†   ‡— |j         Št          ˆfd„| D ¦   «         ¦  «        }t          t          ¦   «         |d¬¦  «        gS )zDGenerate list of ops to implement a SWAP gate along a coupling edge.c              3   ó(   •K  — | ]}‰|         V — Œd S r   rN   )rO   Úir–   s     €r$   rW   z&_swap_ops_from_edge.<locals>.<genexpr>|  s'   øè è € Ð3Ð3¨�k !”nÐ3Ð3Ð3Ð3Ð3Ð3r%   rN   )r<   r=   r>   )r   r—   r   r   )Úedger   Ú	qreg_edger–   s      @r$   rk   rk   y  sJ   ø€ à”.€KÝÐ3Ð3Ð3Ð3¨dÐ3Ñ3Ô3Ñ3Ô3€Iõ �™œ¨9¸BÐ?Ñ?Ô?Ð@Ð@r%   c                 óX   — t          d„ |                      ¦   «         D ¦   «         ¦  «        S )z!Get the first op node from a DAG.c              3   óD   K  — | ]}t          |t          ¦  «        ¯|V — Œd S r   )r   r   )rO   rE   s     r$   rW   z!_first_op_node.<locals>.<genexpr>†  s1   è è € ÐLÐL˜µ
¸4ÅÑ0KÔ0KÐL�ÐLÐLÐLÐLÐLÐLr%   )ÚnextÚnodes)r?   s    r$   r}   r}   ‚  s)   € õ ÐLÐL §¢¡¤ÐLÑLÔLÑLÔLÐLr%   )"rJ   Úcollectionsr�   Úloggingre   Ú%qiskit.circuit.library.standard_gatesr   Úqiskit.transpiler.basepassesr   Úqiskit.transpiler.exceptionsr   Úqiskit.transpiler.layoutr   Úqiskit.dagcircuitr   Úqiskit.transpiler.targetr   Úqiskit.transpiler.passes.layoutr	   Ú	getLoggerrG   r4   Ú
namedtupler
   r   r   r6   rc   rj   rT   rh   r�   rk   r}   rN   r%   r$   ú<module>r­      sÓ  ðð HÐ Gà Ð Ð Ð Ø €€€Ø €€€Ø €€€à :Ð :Ð :Ð :Ð :Ð :Ø ;Ð ;Ð ;Ð ;Ð ;Ð ;Ø 8Ð 8Ð 8Ð 8Ð 8Ð 8Ø +Ð +Ð +Ð +Ð +Ð +Ø 'Ð 'Ð 'Ð 'Ð 'Ð 'Ø +Ð +Ð +Ð +Ð +Ð +Ø :Ð :Ð :Ð :Ð :Ð :à	ˆÔ	˜8Ñ	$Ô	$€ð 	ˆÔ˜wÐ(cÑdÔd€ðð &ˆ{Ô%ØØ3àð	ñ ô €ðIð Ið Ið Ið IÐ&ñ Iô Ið IðXQð Qð Qðh3)ð 3)ð 3)ðlð ð ð ð$Dð Dð Dð`ð `ð `ðð ð ðAð Að AðMð Mð Mð Mð Mr%   