
    z	i{P                    <   S r SSKJr  SSK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  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KJrJrJr  SSKJr  \R@                  (       a  SSK!J"r"   " S S5      r# " S S\5      r$SS jr%          SS jr&g)z'
High-level-synthesis transpiler pass.
    )annotationsN)Callable)	Operation)TransformationPass)QuantumCircuit)EquivalenceLibrary)OptimizationMetric)Target)CouplingMap)
DAGCircuit)TranspilerError)QubitTrackerHighLevelSynthesisData
run_on_dag   )HighLevelSynthesisPluginManager)	DAGOpNodec                  <    \ rS rSrSr   S     SS jjrS rSrg)		HLSConfig.   a  The high-level-synthesis config allows to specify a list of "methods" used by
:class:`~.HighLevelSynthesis` transformation pass to synthesize different types
of higher-level objects.

A higher-level object is an object of type :class:`~.Operation` (e.g., :class:`.Clifford` or
:class:`.LinearFunction`).  Each object is referred to by its :attr:`~.Operation.name` field
(e.g., ``"clifford"`` for :class:`.Clifford` objects), and the applicable synthesis methods are
tied to this name.

In the config, each method is specified in one of several ways:

1. a tuple consisting of the name of a known synthesis plugin and a dictionary providing
   additional arguments for the algorithm.
2. a tuple consisting of an instance of :class:`.HighLevelSynthesisPlugin` and additional
   arguments for the algorithm.
3. a single string of a known synthesis plugin
4. a single instance of :class:`.HighLevelSynthesisPlugin`.

The following example illustrates different ways how a config file can be created::

    from qiskit.transpiler.passes.synthesis.high_level_synthesis import HLSConfig
    from qiskit.transpiler.passes.synthesis.high_level_synthesis import ACGSynthesisPermutation

    # All the ways to specify hls_config are equivalent
    hls_config = HLSConfig(permutation=[("acg", {})])
    hls_config = HLSConfig(permutation=["acg"])
    hls_config = HLSConfig(permutation=[(ACGSynthesisPermutation(), {})])
    hls_config = HLSConfig(permutation=[ACGSynthesisPermutation()])

The names of the synthesis plugins should be declared in ``entry-points`` table for
``qiskit.synthesis`` in ``pyproject.toml``, in the form
<higher-level-object-name>.<synthesis-method-name>.

The standard higher-level-objects are recommended to have a synthesis method
called "default", which would be called automatically when synthesizing these objects,
without having to explicitly set these methods in the config.

To avoid synthesizing a given higher-level-object, one can give it an empty list of methods.

For an explicit example of using such config files, refer to the documentation for
:class:`~.HighLevelSynthesis`.

For an overview of the complete process of using high-level synthesis, see
:ref:`using-high-level-synthesis-plugins`.
Nc                    Xl         X l        Ub  UOS U l        0 U l        UR	                  5        H  u  pVU R                  XV5        M     g)a  Creates a high-level-synthesis config.

Args:
    use_default_on_unspecified: if True, every higher-level-object without an
        explicitly specified list of methods will be synthesized using the "default"
        algorithm if it exists.
    plugin_selection: if set to ``"sequential"`` (default), for every higher-level-object
        the synthesis pass will consider the specified methods sequentially, stopping
        at the first method that is able to synthesize the object. If set to ``"all"``,
        all the specified methods will be considered, and the best synthesized circuit,
        according to ``plugin_evaluation_fn`` will be chosen.
    plugin_evaluation_fn: a callable that evaluates the quality of the synthesized
        quantum circuit in the case that ``plugin_selection="sequential"``;
        a smaller value means a better circuit. If ``None``, the
        quality of the circuit is its size (i.e. the number of gates that it contains).
    kwargs: a dictionary mapping higher-level-objects to lists of synthesis methods.
Nc                "    U R                  5       $ )N)size)qcs    q/home/james-whalen/.local/lib/python3.13/site-packages/qiskit/transpiler/passes/synthesis/high_level_synthesis.py<lambda>$HLSConfig.__init__.<locals>.<lambda>x   s    UWU\U\U^    )use_default_on_unspecifiedplugin_selectionplugin_evaluation_fnmethodsitemsset_methods)selfr   r    r!   kwargskeyvalues          r   __init__HLSConfig.__init__]   sN    0 +E' 0$8$D J^ 	!  ,,.JCS( )r   c                     X R                   U'   g)zSets the list of synthesis methods for a given higher-level-object. This overwrites
the lists of methods if also set previously.N)r"   )r%   hls_namehls_methodss      r   r$   HLSConfig.set_methods   s     "-Xr   )r"   r!   r    r   )T
sequentialN)r   boolr    strr!   z&Callable[[QuantumCircuit], int] | None)__name__
__module____qualname____firstlineno____doc__r)   r$   __static_attributes__ r   r   r   r   .   s;    ,` ,0 ,GK	 )$( )  ) E	 )D-r   r   c            	         ^  \ rS rSrSrSSSSSSSS\R                  4	                 S
U 4S jjjrSS jrS	r	U =r
$ )HighLevelSynthesis   a  Synthesize higher-level objects and unroll custom definitions.

The input to this pass is a DAG that may contain higher-level objects,
including abstract mathematical objects (e.g., objects of type :class:`.LinearFunction`),
annotated operations (objects of type :class:`.AnnotatedOperation`), and
custom gates.

In the most common use-case when either ``basis_gates`` or ``target`` is specified,
all higher-level objects are synthesized, so the output is a :class:`.DAGCircuit`
without such objects.
More precisely, every gate in the output DAG is either directly supported by the target,
or is in ``equivalence_library``.

The abstract mathematical objects are synthesized using synthesis plugins, applying
synthesis methods specified in the high-level-synthesis config (refer to the documentation
for :class:`~.HLSConfig`).

As an example, let us assume that ``op_a`` and ``op_b`` are names of two higher-level objects,
that ``op_a``-objects have two synthesis methods ``default`` which does require any additional
parameters and ``other`` with two optional integer parameters ``option_1`` and ``option_2``,
that ``op_b``-objects have a single synthesis method ``default``, and ``qc`` is a quantum
circuit containing ``op_a`` and ``op_b`` objects. The following code snippet::

    hls_config = HLSConfig(op_b=[("other", {"option_1": 7, "option_2": 4})])
    pm = PassManager([HighLevelSynthesis(hls_config=hls_config)])
    transpiled_qc = pm.run(qc)

shows how to run the alternative synthesis method ``other`` for ``op_b``-objects, while using the
``default`` methods for all other high-level objects, including ``op_a``-objects.

The annotated operations (consisting of a base operation and a list of inverse, control and power
modifiers) are synthesizing recursively, first synthesizing the base operation, and then applying
synthesis methods for creating inverted, controlled, or powered versions of that).

The custom gates are synthesized by recursively unrolling their definitions, until every gate
is either supported by the target or is in the equivalence library.

When neither ``basis_gates`` nor ``target`` is specified, the pass synthesizes only the top-level
abstract mathematical objects and annotated operations, without descending into the gate
``definitions``. This is consistent with the older behavior of the pass, allowing to synthesize
some higher-level objects using plugins and leaving the other gates untouched.

The high-level-synthesis passes information about available auxiliary qubits, and whether their
state is clean (defined as :math:`|0\rangle`) or dirty (unknown state) to the synthesis routine
via the respective arguments ``"num_clean_ancillas"`` and ``"num_dirty_ancillas"``.
If ``qubits_initially_zero`` is ``True`` (default), the qubits are assumed to be in the
:math:`|0\rangle` state. When appending a synthesized block using auxiliary qubits onto the
circuit, we first use the clean auxiliary qubits.

.. note::

    Synthesis methods are assumed to maintain the state of the auxiliary qubits.
    Concretely this means that clean auxiliary qubits must still be in the :math:`|0\rangle`
    state after the synthesized block, while dirty auxiliary qubits are re-used only
    as dirty qubits.

NFr   Tc
                  > [         TU ]  5         U=(       d    [        S5      n[        5       n
[	        U
R
                  R                  5       5      R                  [	        UR                  R                  5       5      5      nUb  UR                  5       nUSL =(       d    [        U5      S:H  =(       a#    USL =(       d    [        UR                  5      S:H  (       + nU(       a#  Ub  UR                  c  1 SknU[	        U5      -  nO
[	        5       nXl        [        UU
UUUUUUUUU	[        R                   :H  S9U l        g)a  
HighLevelSynthesis initializer.

Args:
    hls_config: Optional, the high-level-synthesis config that specifies synthesis methods
        and parameters for various high-level-objects in the circuit. If it is not specified,
        the default synthesis methods and parameters will be used.
    coupling_map: Optional, directed graph represented as a coupling map.
    target: Optional, the backend target to use for this pass. If it is specified,
        it will be used instead of the coupling map.
    use_qubit_indices: a flag indicating whether this synthesis pass is running before or after
        the layout is set, that is, whether the qubit indices of higher-level-objects correspond
        to qubit indices on the target backend.
    equivalence_library: The equivalence library used (instructions in this library will not
        be unrolled by this pass).
    basis_gates: Optional, target basis names to unroll to, e.g. `['u3', 'cx']`.
        Ignored if ``target`` is also specified.
    min_qubits: The minimum number of qubits for operations in the input
        dag to translate.
    qubits_initially_zero: Indicates whether the qubits are initially in the state
        :math:`|0\rangle`. This allows the high-level-synthesis to use clean auxiliary qubits
        (i.e. in the zero state) to synthesize an operation.
    optimization_metric:  Specifies the optimization criterion used by the default synthesis
        methods for high-level-objects (when available).
TNr   >   delayresetstorebarriermeasuresnapshot)
hls_confighls_plugin_managercoupling_maptargetequivalence_libraryhls_op_namesdevice_instsuse_physical_indices
min_qubitsunroll_definitionsoptimize_clifford_t)superr)   r   r   setplugins_by_opkeysunionr"   build_coupling_maplenoperation_names
num_qubitsqubits_initially_zeror   r	   COUNT_Tdata)r%   rC   rE   rF   use_qubit_indicesrG   basis_gatesrK   rW   optimization_metricrD   rH   rL   basic_instsrI   	__class__s                  r   r)   HighLevelSynthesis.__init__   s-   J 	  29T?
<>-;;@@BCII
""'')*
 !446L D 9C$4$9 E4C3v'='=#>!#C
 6>V5F5F5NWK&[)99L5L%:"*!1% 3%%!2!1 37I7Q7Q Q
	r   c                P    [        XR                  U R                  5      nUb  U$ U$ )a*  Run the HighLevelSynthesis pass on `dag`.

Args:
    dag: input dag.

Returns:
    Output dag with higher-level operations synthesized.

Raises:
    TranspilerError: when the transpiler is unable to synthesize the given DAG
    (for instance, when the specified synthesis method is not available).
)r   rY   rW   )r%   dagress      r   runHighLevelSynthesis.run  s)     ii)C)CDos.3.r   )rY   rW   )rC   zHLSConfig | NonerE   zCouplingMap | NonerF   zTarget | NonerZ   r0   rG   zEquivalenceLibrary | Noner[   zlist[str] | NonerK   intrW   r0   r\   r	   )ra   r   returnr   )r2   r3   r4   r5   r6   r	   COUNT_2Qr)   rc   r7   __classcell__)r^   s   @r   r:   r:      s    8x (,+/ $"'9=(,&*2D2M2ML
$L
 )L
 	L

  L
 7L
 &L
 L
  $L
 0L
 L
\/ /r   r:   c                    U R                   R                  R                  U5      =nb  U$ U R                   R                  (       a"  SU R                  R                  U5      ;   a  S/$ / $ )z5Get a sequence of methods to try for a given op name.default)rC   r"   getr   rD   method_names)rY   namer"   s      r   _methods_to_tryrn     s^    ??**..t44A 2200==dCC
 {Ir   c                   [        X R                  5      n[        U5      S:X  a  gUR                  nUR	                  U5      nUR                  U5      nSn[        R                  n	U GHg  n
[        U
[        5      (       a  U
u  pOU
n0 n[        U[        5      (       aV  XR                  U R                  5      ;  a  [        SU SU R                   35      eUR                  U R                  U5      nOUnXS'   X,S'   X<S'   XlS'   X|S	'   UR                  (       a  [        R                   US
'   O[        R"                  US
'   UR$                  (       a  UOSnUR&                  " U 4UR(                  UR*                  US.UD6nUc  GM!  UR,                  R.                  S:X  a  Un  O-UR,                  R1                  U5      nUU	:  d  GMc  UnUn	GMj     UnUbj  UR2                  [        U5      :  a-  UR5                  UR2                  [        U5      -
  U5      nUU-   nUR2                  [        U5      :w  a  [        S5      eUc  gUU4$ )a  
Attempts to synthesize an operation using plugin mechanism.

Input:
    operation: the operation to be synthesized.
    input_qubits: a list of global qubits (qubits in the original circuit) over
        which the operation is defined.
    data: high-level-synthesis data and options.
    tracker: the global tracker, tracking the state of global qubits.
    hls_methods: the list of synthesis methods to try.

The function is called from within Rust code.

Returns either the synthesized circuit or ``None`` (which may occur
when no synthesis methods is available or specified, or when there is
an insufficient number of auxiliary qubits).
r   NzSpecified method: z$ not found in available plugins for input_qubitshls_dataqubit_trackernum_clean_ancillasnum_dirty_ancillasr\   )rE   rF   qubitsr/   zNHighLevelSynthesis: the result from 'synthesize_op_using_plugin' is incorrect.)rn   rm   rT   rD   	num_clean	num_dirtynpinf
isinstancetupler1   rl   r   methodrM   r	   rX   rg   rJ   rc   rE   rF   rC   r    r!   rV   borrow)	operationrp   rY   trackerr-   rD   rs   rt   best_decomposition
best_scorer|   plugin_specifierplugin_argsplugin_methodru   decompositioncurrent_scoreoutput_qubitsglobal_aux_qubitss                      r   _synthesize_op_using_pluginsr   0  sr   . "$7K
;100 **<8 **<8J fe$$,2)k%K &,,'F'Fy~~'VV%()9(: ;##,>>"24  /55innFVWM,M '3N#"&J'.O$,>(),>()##1C1K1KK-.1C1L1LK-.!%!:!:%))
**;;	

 
 $//<? &3" !OO@@OMz)%2"*
Y f !M%((3|+<< '"--L0AA<! *,==M ((C,>>!`  !..r   )rY   r   rm   r1   )
r~   r   rp   z
tuple[int]rY   r   r   r   rf   z6tuple[QuantumCircuit, tuple[int], QubitTracker] | None)'r6   
__future__r   typingcollections.abcr   numpyrx   qiskit.circuit.operationr   qiskit.transpiler.basepassesr   qiskit.circuit.quantumcircuitr   qiskit.circuitr   %qiskit.transpiler.optimization_metricr	   qiskit.transpiler.targetr
   qiskit.transpiler.couplingr   qiskit.dagcircuit.dagcircuitr   qiskit.transpiler.exceptionsr   'qiskit._accelerate.high_level_synthesisr   r   r   pluginr   TYPE_CHECKINGqiskit.dagcircuitr   r   r:   rn   r   r8   r   r   <module>r      s    #  $  . ; 8 - D + 2 3 8  4	+T- T-nW/+ W/t"G/G/G/ !G/ 	G/
 <G/r   