
    z	i$                     n    S r SSKrSSKJr  SSKJr  SSKJr  SSKJ	r	  SSK
Jr  SSKJr   " S	 S
\5      rg)z Creating Sabre starting layouts.    N)AnalysisPass)CouplingMap)TranspilerError)	VF2Layout)Target)ErrorMapc                   X   ^  \ rS rSrSr     S
U 4S jjrS rS rS rS r	S r
S	rU =r$ )SabrePreLayout   a  Choose a starting layout to use for additional Sabre layout trials.

Property Set Values Written
---------------------------

``sabre_starting_layouts`` (``list[Layout]``)
    An optional list of :class:`~.Layout` objects to use for additional Sabre layout trials.

**References:**

[1] Henry Zou and Matthew Treinish and Kevin Hartman and Alexander Ivrii and Jake Lishman.
"LightSABRE: A Lightweight and Enhanced SABRE Algorithm"
`arXiv:2409.08368 <https://doi.org/10.48550/arXiv.2409.08368>`__
c                    > X l         X0l        X@l        XPl        X`l        [        U[        5      (       a&  Xl        U R                  R                  5       U l	        OSU l        Xl	        [        TU ]-  5         g)aq  SabrePreLayout initializer.

The pass works by augmenting the coupling map with more and more "extra" edges
until VF2 succeeds to find a perfect graph isomorphism. More precisely, the
augmented coupling map contains edges between nodes that are within a given
distance ``d`` in the original coupling map, and the value of ``d`` is increased
until an isomorphism is found.

Intuitively, a better layout involves fewer extra edges. The pass also optionally
minimizes the number of extra edges involved in the layout until a local minimum
is found. This involves removing extra edges and running VF2 to see if an
isomorphism still exists.

Args:
    coupling_map (Union[CouplingMap, Target]): directed graph representing the
        original coupling map or a target modelling the backend (including its
        connectivity).
    max_distance (int): the maximum distance to consider for augmented coupling maps.
    error_rate (float): the error rate to assign to the "extra" edges. A non-zero
        error rate prioritizes VF2 to choose original edges over extra edges.
    max_trials_vf2 (int): specifies the maximum number of VF2 trials. A larger number
        allows VF2 to explore more layouts, eventually choosing the one with the smallest
        error rate.
    call_limit_vf2 (int): limits each call to VF2 by bounding the number of VF2 state visits.
    improve_layout (bool): whether to improve the layout by minimizing the number of
        extra edges involved. This might be time-consuming as this requires additional
        VF2 calls.

Raises:
    TranspilerError: At runtime, if neither ``coupling_map`` or ``target`` are provided.
N)max_distance
error_ratemax_trials_vf2call_limit_vf2improve_layout
isinstancer   targetbuild_coupling_mapcoupling_mapsuper__init__)selfr   r   r   r   r   r   	__class__s          j/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/transpiler/passes/layout/sabre_pre_layout.pyr   SabrePreLayout.__init__)   sb    R )$,,,lF++&K $ > > @DDK ,    c                 B   U R                   c  [        S5      eSnSnX0R                  ::  a  U R                  U5      u  pE[	        USU R
                  U R                  S9nXVR                  S'   UR                  U5        SUR                  ;   a  UR                  S   nOUS-  nX0R                  ::  a  M  US:  af  Ubb  U R                  (       a  U R                  X5      nSU R                  ;  a  U/U R                  S'   gU R                  S   R                  U5        ggg)	zRun the SabrePreLayout pass on `dag`.

The discovered starting layout is written to the property set
value ``sabre_starting_layouts``.

Args:
    dag (DAGCircuit): DAG to create starting layout for.
NzSSabrePreLayout requires coupling_map to be used with eitherCouplingMap or a Target.   seed
max_trials
call_limitvf2_avg_error_maplayoutsabre_starting_layouts)r   r   r   _add_extra_edgesr   r   r   property_setrunr   _minimize_extra_edgesappend)r   dagstarting_layoutcur_distanceaugmented_mapaugmented_error_mappass_s          r   r)   SabrePreLayout.runa   s1    $!+ 
 ///151F1F|1T.M....	E 7J23IIcN5---"'"4"4X">AL ///" ! ;"""&"<"<S"R't/@/@@?N>O!!":;!!":;BB?S !<r   c                 \   [        U R                  R                  5      n[        5       nU R                  R                  R	                  5       Ul        [        U5      n[        R                  " U R                  R                  R                  5       S5       H  u  pVU R                  R                  XV5      nSUs=:  a  U::  d  M/  O  M3  SSU R                  -
  U-  -
  nUR                  XV5        UR                  XV4U5        UR                  Xe5        UR                  Xe4U5        M     X44$ )zAugments the coupling map with extra edges that connect nodes ``distance``
apart in the original graph. The extra edges are assigned errors allowing VF2
to prioritize real edges over extra edges.
   r   )lenr   graphr   copyr   	itertoolscombinationsnode_indicesdistancer   add_edge	add_error)	r   r;   nqaugmented_coupling_mapr0   xydr   s	            r   r'   SabrePreLayout._add_extra_edges   s   
 ""(()!,'+'8'8'>'>'C'C'E$&rl**4+<+<+B+B+O+O+QSTUDA!!**10A1   1t#61"<=
&//5#--qfjA&//5#--qfjA V &::r   c                 &   [        5       nUR                  5       nUR                  5        Hb  nXER                  S      nXER                  S      nU R                  R                  Xg5      S:  d  MF  Xg:  a  Xg4OXv4nUR                  U5        Md     U$ )z6Returns the set of extra edges involved in the layout.r   r   )setget_virtual_bitstwo_qubit_opsqargsr   r;   add)	r   r,   r%   extra_edges_usedvirtual_bitsnodep0p1
extra_edges	            r   _get_extra_edges_used$SabrePreLayout._get_extra_edges_used   s    5..0%%'Djjm,Bjjm,B  ))"1A5)+bXrh
 $$Z0 (  r   c                     [        U5      n[        USSU R                  S9nUR                  U5        UR                  R                  SS5      $ )z5Checks if there is a layout for a given set of edges.r   r   r    r%   N)r   r   r   r)   r(   get)r   r,   edgescmr1   s        r   _find_layoutSabrePreLayout._find_layout   sF    "1t?R?RS		#!!%%h55r   c                 L   / n[         R                  " U R                  R                  R	                  5       S5       H:  u  pEU R                  R                  XE5      nUS:X  d  M(  UR                  XE45        M<     Un/ nU R                  X5      n	U	(       a  [        [        U	5      5      n
U	R                  U
5        U R                  XU-   [        U	5      -   5      nUc  UR                  U
5        O+U R                  X5      R                  [        U5      5      n	UnU	(       a  M  U$ )zMinimizes the set of extra edges involved in the layout. This iteratively
removes extra edges from the coupling map and uses VF2 to check if a layout
still exists. This is reasonably efficiently as it only looks for a local
minimum.
r4   r   )r8   r9   r   r6   r:   r;   r+   rP   nextiterremoverV   list
differencerE   )r   r,   r-   
real_edgesr@   rA   rB   best_layoutextra_edges_necessaryextra_edges_unprocessed_setedge_chosenr%   s               r   r*   $SabrePreLayout._minimize_extra_edges   s     
**4+<+<+B+B+O+O+QSTUDA!!**10AAv!!1&) V
 & !#&*&@&@&V#)t$?@AK'..{; &&"77$?Z:[[F ~%,,[9
 /3.H.H.U.`.`-./+ %) *), r   )r   r   r   r   r   r   r   )r4   g?d   NT)__name__
__module____qualname____firstlineno____doc__r   r)   r'   rP   rV   r*   __static_attributes____classcell__)r   s   @r   r
   r
      s?    $ 6p+TZ;*
 6+ +r   r
   )ri   r8   qiskit.transpiler.basepassesr   qiskit.transpiler.couplingr   qiskit.transpiler.exceptionsr   *qiskit.transpiler.passes.layout.vf2_layoutr   qiskit.transpiler.targetr   qiskit._accelerate.error_mapr   r
    r   r   <module>rs      s-    '  5 2 8 @ + 1H\ Hr   