
    i+                    `   S 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
JrJrJr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#  SSK$J%r%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/J0r0  SSK1J2r2  \Rf                  " \45      r5 " S S5      r6g)zNoise learner program.    )annotations)deepcopy)asdictfieldsreplace)AnyDictIterableOptionalUnionN)QuantumCircuit)	BackendV2)EstimatorPubLike)EstimatorPub   )_get_mode_service_backend)DEFAULT_DECODERS)RuntimeJobV2)
IBMBackend)EstimatorOptions)NoiseLearnerOptions)remove_dict_unset_valuesremove_empty_dict)validate_isa_circuits)is_simulator)QiskitRuntimeLocalService)QiskitRuntimeService)Session)Batchc                      \ rS rSrSr  S   SS jjr\SS j5       rSS jr\	SS j5       r
SS jr S   SS	 jjr\SS
 j5       rSrg)NoiseLearner0   u  Class for executing noise learning experiments.

The noise learner class allows characterizing the noise processes affecting the gates in one or more
circuits of interest, based on the Pauli-Lindblad noise model described in [1].

The :meth:`~run` method allows running a noise learner job for a list of circuits. After the job is
submitted, the gates are collected into independent layers, and subsequently the resulting layers are
characterized individually.

The way in which the gates are collected into layers depends on the twirling ``strategy`` specified
in the given ``options`` (see :class:`.NoiseLearnerOptions` for more details). Note that all
strategies obey barriers. For example, if you have three ISA entangling layers of interest,
consider putting them into one circuit separated by barriers acting on the qubits you wish to
twirl, and select ``strategy="active-circuit"``.

The following snippet shows an example where the noise learner is used to characterized the layers
of two GHZ circuits.

.. code-block:: python

    from qiskit.circuit import QuantumCircuit
    from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
    from qiskit_ibm_runtime import QiskitRuntimeService
    from qiskit_ibm_runtime.noise_learner import NoiseLearner
    from qiskit_ibm_runtime.options import NoiseLearnerOptions

    service = QiskitRuntimeService()
    backend = service.least_busy(operational=True, simulator=False)

    # a circuit returning a two-qubit GHZ state
    ghz = QuantumCircuit(2)
    ghz.h(0)
    ghz.cx(0, 1)

    # another circuit returning a two-qubit GHZ state
    another_ghz = QuantumCircuit(3)
    another_ghz.h(0)
    another_ghz.cx(0, 1)
    another_ghz.cx(1, 2)
    another_ghz.cx(0, 1)

    pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
    circuits = pm.run([ghz, another_ghz])

    # set the options
    options = NoiseLearnerOptions()
    options.layer_pair_depths = [0, 1, 10]

    # run the noise learner job
    learner = NoiseLearner(backend, options)
    job = learner.run(circuits)

Args:
    mode: The execution mode used to make the primitive query. It can be:

        * A :class:`Backend` if you are using job mode.
        * A :class:`Session` if you are using session execution mode.
        * A :class:`Batch` if you are using batch execution mode.

        Refer to the
        `Qiskit Runtime documentation <https://quantum.cloud.ibm.com/docs/guides/execution-modes>`__
        for more information about the execution modes.

    options: :class:`NoiseLearnerOptions`. Alternatively, :class:`EstimatorOptions` can be
        provided for convenience, in which case the estimator options get reformatted into
        noise learner options and all the irrelevant fields are ignored.

References:
    1. E. van den Berg, Z. Minev, A. Kandala, K. Temme, *Probabilistic error
       cancellation with sparse Pauli–Lindblad models on noisy quantum processors*,
       Nature Physics volume 19, pages 1116–1121 (2023).
       `arXiv:2201.09866 [quant-ph] <https://arxiv.org/abs/2201.09866>`_

Nc                    [        U5      u  U l        U l        U l        [	        U R                  [
        5      (       a  [        S5      eU R                  U5        g )Nz7``NoiseLearner`` not currently supported in local mode.)r   _mode_service_backend
isinstancer   
ValueError_set_options)selfmodeoptionss      h/home/james-whalen/.local/lib/python3.13/site-packages/qiskit_ibm_runtime/noise_learner/noise_learner.py__init__NoiseLearner.__init__|   sH    
 4MT3R0
DM4=dmm%>??VWW'"    c                    U R                   $ )z"The options in this noise learner.)_optionsr*   s    r-   r,   NoiseLearner.options   s     }}r0   c           	        [        S U 5       5      (       dA  U Vs/ s H  n[        R                  " U5      PM     nnU Vs/ s H  oDR                  PM     nn[	        U R
                  5      nSU R                  U5      0n[        R                  " U5      nSU0nUR                  U5        Sn	U R                  (       a  U H  n
[        U R                  SS5      (       a;  [        U R                  5      (       d!  [        U
/U R                  R                  5        [        U R                  [         5      (       d  M{  U R                  R#                  U
5        M     [        U R                  SS5      n	[$        R'                  SU5        U R(                  (       aM  U R(                  R+                  U R-                  5       UU[.        R0                  " U R-                  5       5      U	S9$ U R                  (       aM  U R                  US	'   S
U;  a8  [        U R                  [         5      (       a  U R                  R2                  US
'   [        U R4                  [6        5      (       aM  U R4                  R+                  U R-                  5       UU[.        R0                  " U R-                  5       5      U	S9$ U R4                  R+                  U R-                  5       UUU	S9$ s  snf s  snf )a  Submit a request to the noise learner program.

This function breaks the given list of circuits into a list of unique layers, following
the strategy set by the ``twirling_strategy`` field specified in the ``options`` (see
:class:`NoiseLearnerOptions` for more details) and sorting them based on the number of
times they occur in the various circuits. Then, it runs the noise learning experiment
for as many layers as specified by the ``max_layers_to_learn`` field in the ``options``,
prioritizing layers that occur more frequently.

Args:
    circuits: An iterable of circuits to run the noise learner program for. Alternatively,
        estimator pub-like (primitive unified bloc) objects can be specified, such as
        tuples ``(circuit, observables)`` or ``(circuit, observables, parameter_values)``.
        In this case, the pub-like objects are converted to a list of circuits, and all
        the other fields (such as ``observables`` and ``parameter_values``) are ignored.

Returns:
    The submitted job.

c              3  B   #    U  H  n[        U[        5      v   M     g 7fN)r'   r   ).0ts     r-   	<genexpr>#NoiseLearner.run.<locals>.<genexpr>   s     C(Q:a00(s   r,   circuitsNtargetcalibration_idzSubmitting job using options %s)
program_idinputsr,   result_decoderr>   backendinstance)r?   r,   r@   rA   r>   )r?   r,   r@   r>   )allr   coercecircuitr   r,   _get_inputs_optionsr   _get_runtime_optionsupdater&   getattrr   r   r=   r'   r   check_faultyloggerinfor$   _run_program_idr   get	_instancer%   r   )r*   r<   pubcoerced_pubspoptions_dictlearner_optionsruntime_optionsr@   r>   tasks              r-   runNoiseLearner.run   sT   * C(CCC@HIL//4LI+78<a		<H8 dll+$d&>&>|&LM-BB<P h'o&== 4==(D99,t}}B]B])4&$--2F2FGdmmZ88MM..t4 ! %T]]4DdKN5G ::::??++-'/33D4D4D4FG- #   ==)-OI&0Zz5Z5Z.2mm.E.E
+dmm%9::==%%++-'/33D4D4D4FG- &   }}!!'')#)	 " 
 	
a J8s    KKc                    g)zReturn the program ID.znoise-learner )clss    r-   rO   NoiseLearner._program_id   s     r0   c                    U R                   $ )z6Return the backend the primitive query will be run on.)r&   r3   s    r-   rB   NoiseLearner.backend   s    }}r0   c                   U(       d  [        5       U l        g[        U[         5      (       a  [        U5      U l        g[        U[        5      (       a  [        UR                  R                  5      nUR                  R                  US'   UR                  US'   UR                  US'   UR                  US'   UR                  US'   [        S0 UD6U l        g[        S0 UD6U l        g)zK
Sets the options, ensuring that they are of type ``NoiseLearnerOptions``.
twirling_strategymax_execution_time	simulatorenvironmentexperimentalNr\   )r   r2   r'   r   r   r   
resiliencelayer_noise_learningtwirlingstrategyrc   rd   re   rf   )r*   r,   ds      r-   r)   NoiseLearner._set_options   s     /1DM!455#G,DM!122w))>>?A%,%5%5%>%>A!"&-&@&@A"#$..AkN&22Am ' 4 4An/4!4DM/:':DMr0   c                
   0 n/ SQn[        [        5       H,  nUR                  nX@;   d  M  XB;  d  M  [        X   5      X'   M.     [	        U5        [        U5        SUS'   UR                  S0 5      R                  SS5        U$ )zReturns a dictionary of options that must be included in the program inputs,
filtering out every option that is not part of the NoiseLearningOptions.)_VERSIONrc   re   Tsupport_qiskitrf   imageN)r   r   namer   r   r   rP   pop)rU   retignored_namesfieldrq   s        r-   rG    NoiseLearner._get_inputs_options   s     
 /0E::D#(A$\%78	 1
 	!%# $ 	#''6
r0   )r&   r$   r2   r%   )NN)r+   z*Optional[Union[BackendV2, Session, Batch]]r,   <Optional[Union[Dict, NoiseLearnerOptions, EstimatorOptions]])returnr   )r<   z1Iterable[Union[QuantumCircuit, EstimatorPubLike]]rx   r   )rx   str)rx   r   r7   )r,   rw   rx   None)rU   zdict[str, Any]rx   zdict[str, str])__name__
__module____qualname____firstlineno____doc__r.   propertyr,   rY   classmethodrO   rB   r)   staticmethodrG   __static_attributes__r\   r0   r-   r!   r!   0   s    IZ <@PT	#8	# N	#  K
Z  
 W[;S;	;*  r0   r!   )7r   
__future__r   copyr   dataclassesr   r   r   typingr   r	   r
   r   r   loggingqiskit.circuitr   qiskit.providersr   qiskit.primitives.containersr   *qiskit.primitives.containers.estimator_pubr   base_primitiver   	constantsr   runtime_job_v2r   ibm_backendr   options.estimator_optionsr   options.noise_learner_optionsr   options.utilsr   r   utilsr   utils.utilsr   fake_provider.local_servicer   qiskit_runtime_servicer   sessionr   batchr   	getLoggerr{   rL   r!   r\   r0   r-   <module>r      sp     "  / / 7 7  ) & 9 C 6 ( ) $ 8 ? G ) & C 9  			8	$_ _r0   