§
    ¹³Ùg‚3  ã                  ó†   — d Z ddlmZ ddlmZ ddlZddlmZ ddl	m
Z
mZ ddlmZ ddlmZ d	d
lmZ  G d„ de¦  «        ZdS )z=Piecewise polynomial Chebyshev approximation to a given f(x).é    )Úannotations)ÚCallableN)Ú	Chebyshev)ÚQuantumRegisterÚAncillaRegister)ÚBlueprintCircuit)ÚCircuitErroré   )Ú!PiecewisePolynomialPauliRotationsc                  ól  ‡ — e Zd ZdZ	 	 	 	 d&d'ˆ fd„Zd(d)d„Zed*d„¦   «         Zej        d+d„¦   «         Zed,d„¦   «         Z	e	j        d-d„¦   «         Z	ed.d„¦   «         Z
e
j        d/d„¦   «         Z
ed0d„¦   «         Zej        d1d!„¦   «         Zed,d"„¦   «         Zej        d2d#„¦   «         Zd2d$„Zˆ fd%„Zˆ xZS )3ÚPiecewiseChebysheva¬  Piecewise Chebyshev approximation to an input function.

    For a given function :math:`f(x)` and degree :math:`d`, this class implements a piecewise
    polynomial Chebyshev approximation on :math:`n` qubits to :math:`f(x)` on the given intervals.
    All the polynomials in the approximation are of degree :math:`d`.

    The values of the parameters are calculated according to [1] and see [2] for a more
    detailed explanation of the circuit construction and how it acts on the qubits.

    Examples:

        .. plot::
           :alt: Circuit diagram output by the previous code.
           :include-source:

            import numpy as np
            from qiskit import QuantumCircuit
            from qiskit.circuit.library.arithmetic.piecewise_chebyshev import PiecewiseChebyshev
            f_x, degree, breakpoints, num_state_qubits = lambda x: np.arcsin(1 / x), 2, [2, 4], 2
            pw_approximation = PiecewiseChebyshev(f_x, degree, breakpoints, num_state_qubits)
            pw_approximation._build()
            qc = QuantumCircuit(pw_approximation.num_qubits)
            qc.h(list(range(num_state_qubits)))
            qc.append(pw_approximation.to_instruction(), qc.qubits)
            qc.draw(output='mpl')

    References:

        [1]: Haener, T., Roetteler, M., & Svore, K. M. (2018).
             Optimizing Quantum Circuits for Arithmetic.
             `arXiv:1805.12445 <http://arxiv.org/abs/1805.12445>`_
        [2]: Carrera Vazquez, A., Hiptmair, H., & Woerner, S. (2022).
             Enhancing the Quantum Linear Systems Algorithm Using Richardson Extrapolation.
             `ACM Transactions on Quantum Computing 3, 1, Article 2 <https://doi.org/10.1145/3490631>`_
    NÚpw_chebÚf_xúfloat | Callable[[int], float]Údegreeú
int | NoneÚbreakpointsúlist[int] | NoneÚnum_state_qubitsÚnameÚstrÚreturnÚNonec                ó²   •— t          ¦   «                              |¬¦  «         d| _        || _        |�|nd| _        |�|ndg| _        d| _        || _        dS )aà  
        Args:
            f_x: the function to be approximated. Constant functions should be specified
             as f_x = constant.
            degree: the degree of the polynomials.
                Defaults to ``1``.
            breakpoints: the breakpoints to define the piecewise-linear function.
                Defaults to the full interval.
            num_state_qubits: number of qubits representing the state.
            name: The name of the circuit object.
        ©r   Nr
   r   )ÚsuperÚ__init__Ú_num_state_qubitsÚ_f_xÚ_degreeÚ_breakpointsÚ_polynomialsr   )Úselfr   r   r   r   r   Ú	__class__s         €úk/granary/edev/quantum/lib/python3.11/site-packages/qiskit/circuit/library/arithmetic/piecewise_chebyshev.pyr   zPiecewiseChebyshev.__init__@   sl   ø€ õ& 	‰Œ×Ò˜dÐÑ#Ô#Ð#ð "&ˆÔð ˆŒ	Ø!'Ð!3�v�v¸ˆŒØ+6Ð+B˜K˜KÈÈˆÔà6:ˆÔà 0ˆÔÐÐó    TÚraise_on_failureÚboolc                ó>  — d}| j         €d}|rt          d¦  «        ‚| j        €d}|rt          d¦  «        ‚| j        €d}|rt          d¦  «        ‚| j        €d}|rt          d¦  «        ‚| j        | j        dz   k     rd}|rt          d	| j        dz   › d
�¦  «        ‚|S )z,Check if the current configuration is valid.TNFz1The function to be approximated has not been set.z/The degree of the polynomials has not been set.z"The breakpoints have not been set.z&The number of qubits has not been set.r
   z0Not enough qubits in the circuit, need at least ú.)r   ÚAttributeErrorr    r!   r   Ú
num_qubitsr	   )r#   r'   Úvalids      r%   Ú_check_configurationz'PiecewiseChebyshev._check_configurationa   s÷   € àˆàŒ9ÐØˆEØð ZÝ$Ð%XÑYÔYÐYàŒ<ÐØˆEØð XÝ$Ð%VÑWÔWÐWàÔÐ$ØˆEØð KÝ$Ð%IÑJÔJÐJàÔ Ð(ØˆEØð OÝ$Ð%MÑNÔNÐNàŒ?˜TÔ2°QÑ6Ò6Ð6ØˆEØð Ý"ð4ØÔ,¨qÑ0ð4ð 4ð 4ñô ð ð
 ˆr&   c                ó   — | j         S )zhThe function to be approximated.

        Returns:
            The function to be approximated.
        )r   ©r#   s    r%   r   zPiecewiseChebyshev.f_xƒ   s   € ð ŒyÐr&   ú%float | Callable[[int], float] | Nonec                ó˜   — | j         �|| j         k    r7|                      ¦   «          || _         |                      | j        ¦  «         dS dS )zåSet the function to be approximated.

        Note that this may change the underlying quantum register, if the number of state qubits
        changes.

        Args:
            f_x: The new function to be approximated.
        N)r   Ú_invalidateÚ_reset_registersr   )r#   r   s     r%   r   zPiecewiseChebyshev.f_xŒ   sV   € ð Œ9Ð  t¤yÒ 0Ð 0Ø×ÒÑÔÐØˆDŒIà×!Ò! $Ô"7Ñ8Ô8Ð8Ð8Ð8ð	 !1Ð 0r&   Úintc                ó   — | j         S )zdThe degree of the polynomials.

        Returns:
            The degree of the polynomials.
        )r    r0   s    r%   r   zPiecewiseChebyshev.degreeœ   s   € ð Œ|Ðr&   c                ó˜   — | j         �|| j         k    r7|                      ¦   «          || _         |                      | j        ¦  «         dS dS )zÇSet the error tolerance.

        Note that this may change the underlying quantum register, if the number of state qubits
        changes.

        Args:
            degree: The new degree.
        N)r    r3   r4   r   )r#   r   s     r%   r   zPiecewiseChebyshev.degree¥   sV   € ð Œ<Ð 6¨T¬\Ò#9Ð#9Ø×ÒÑÔÐØ!ˆDŒLà×!Ò! $Ô"7Ñ8Ô8Ð8Ð8Ð8ð	 $:Ð#9r&   ú	list[int]c                ó~   — | j         }| j        �.d| j        z  }|d         |k     r||gz   }|d         dk    rdg|z   }|S )zˆThe breakpoints for the piecewise approximation.

        Returns:
            The breakpoints for the piecewise approximation.
        Né   éÿÿÿÿr   )r!   r   )r#   r   Ú
num_statess      r%   r   zPiecewiseChebyshev.breakpointsµ   sd   € ð Ô'ˆð Ô Ð,Ø˜DÔ1Ñ1ˆJð ˜2Œ Ò+Ð+Ø)¨Z¨LÑ8�ð ˜1Œ~ Ò!Ð!Ø ˜c KÑ/�àÐr&   c                ó¢   — | j         �|| j         k    r<|                      ¦   «          |�|ndg| _         |                      | j        ¦  «         dS dS )a  Set the breakpoints for the piecewise approximation.

        Note that this may change the underlying quantum register, if the number of state qubits
        changes.

        Args:
            breakpoints: The new breakpoints for the piecewise approximation.
        Nr   )r!   r3   r4   r   )r#   r   s     r%   r   zPiecewiseChebyshev.breakpointsÌ   se   € ð ÔÐ$¨°tÔ7HÒ(HÐ(HØ×ÒÑÔÐØ/:Ð/F  ÈQÈCˆDÔà×!Ò! $Ô"7Ñ8Ô8Ð8Ð8Ð8ð	 )IÐ(Hr&   úlist[list[float]]c           	     óV  — | j         €g gS | j        }|dgk    rdd| j         z  g}t          |¦  «        }g }t          d|dz
  ¦  «        D �]}	 t	          | j        t          t          f¦  «        r|                     | j        g¦  «         n†t          j
        | j        | j        ||         ||dz            g¬¦  «        }d|                     t          j        j        ¬¦  «        j        z  }|                     |                     ¦   «         ¦  «         ŒÈ# t$          $ r3}t'          d| j        j        j        d         z   dz   d	z   ¦  «        |‚d}~ww xY w|d
         d| j         z  k     r|dt          j        d¦  «        z  ggz   }|d         dk    rdt          j        d¦  «        z  gg|z   }|S )zäThe polynomials for the piecewise approximation.

        Returns:
            The polynomials for the piecewise approximation.

        Raises:
            TypeError: If the input function is not in the correct format.
        Nr   r:   r
   )Údomain)Úkindz5 <lambda>() missing 1 required positional argument: 'z'.z< Constant functions should be specified as 'f_x = constant'.r;   )r   r!   ÚlenÚrangeÚ
isinstancer   Úfloatr5   Úappendr   Úinterpolater   ÚconvertÚnpÚ
polynomialÚ
PolynomialÚcoefÚtolistÚ
ValueErrorÚ	TypeErrorÚ__code__Úco_varnamesÚarcsin)r#   r   Únum_intervalsÚpolynomialsÚiÚpolyÚerrs          r%   rT   zPiecewiseChebyshev.polynomialsÜ   sé  € ð Ô Ð(Ø�4ˆKð
 Ô'ˆà˜1˜#ÒÐØ˜a Ô!6Ñ6Ð7ˆKå˜KÑ(Ô(ˆð ˆÝ�q˜-¨!Ñ+Ñ,Ô,ð 	ñ 	ˆAðå˜dœh­µ¨Ñ5Ô5ð 
6à×&Ò&¨¬ zÑ2Ô2Ð2Ð2å$Ô0Øœ $¤+°{À1´~À{ÐSTÐWXÑSXÔGYÐ6Zðñ ô �Dð ˜tŸ|š|µ´Ô1I˜|ÑJÔJÔOÑO�Dà×&Ò& t§{¢{¡}¤}Ñ5Ô5Ð5øøÝð ð ð ÝØKØ”hÔ'Ô3°AÔ6ñ7àñð UñUñô ð
 ðøøøøðøøøð �rŒ?˜Q Ô 5Ñ5Ò5Ð5Ø%¨!­b¬i¸©l¬lÑ*:Ð);Ð(<Ñ<ˆKð �qŒ>˜AÒÐØ¥¤	¨!¡¤Ñ,Ð-Ð.°Ñ<ˆKàÐs   ÁCDÄ
EÄ.E	Å	ErT   úlist[list[float]] | Nonec                ó˜   — | j         �|| j         k    r7|                      ¦   «          || _         |                      | j        ¦  «         dS dS )a  Set the polynomials for the piecewise approximation.

        Note that this may change the underlying quantum register, if the number of state qubits
        changes.

        Args:
            polynomials: The new breakpoints for the piecewise approximation.
        N)r"   r3   r4   r   )r#   rT   s     r%   rT   zPiecewiseChebyshev.polynomials  sZ   € ð ÔÐ$¨°tÔ7HÒ(HÐ(HØ×ÒÑÔÐØ +ˆDÔà×!Ò! $Ô"7Ñ8Ô8Ð8Ð8Ð8ð	 )IÐ(Hr&   c                ó   — | j         S )z‡The number of state qubits representing the state :math:`|x\rangle`.

        Returns:
            The number of state qubits.
        )r   r0   s    r%   r   z#PiecewiseChebyshev.num_state_qubits&  s   € ð Ô%Ð%r&   c                ó¸   — | j         �|| j         k    rG|                      ¦   «          || _         |�| j        €dd|z  g| _        |                      |¦  «         dS dS )zâSet the number of state qubits.

        Note that this may change the underlying quantum register, if the number of state qubits
        changes.

        Args:
            num_state_qubits: The new number of qubits.
        Nr   r:   )r   r3   r!   r   r4   )r#   r   s     r%   r   z#PiecewiseChebyshev.num_state_qubits/  s|   € ð Ô!Ð)Ð-=ÀÔAWÒ-WÐ-WØ×ÒÑÔÐØ%5ˆDÔ"ð  Ð+°Ô0AÐ0IØ$% qÐ*:Ñ':Ð#;�Ô à×!Ò!Ð"2Ñ3Ô3Ð3Ð3Ð3ð .XÐ-Wr&   c                óÊ   — g | _         |�Wt          |d¦  «        }t          dd¦  «        }||g| _         |}|dk    r(t          |¦  «        }|                      |¦  «         dS dS dS )zReset the registers.NÚstater
   Útargetr   )Úqregsr   r   Úadd_register)r#   r   Úqr_stateÚ	qr_targetÚnum_ancillasÚ
qr_ancillas         r%   r4   z#PiecewiseChebyshev._reset_registersC  s�   € àˆŒ
àÐ'Ý&Ð'7¸ÑAÔAˆHÝ'¨¨8Ñ4Ô4ˆIØ" IÐ.ˆDŒJà+ˆLØ˜aÒÐÝ,¨\Ñ:Ô:�
Ø×!Ò! *Ñ-Ô-Ð-Ð-Ð-ð (Ð'ð  Ðr&   c                ó  •— | j         rdS t          ¦   «                              ¦   «          t          | j        | j        | j        | j        ¬¦  «        }|                      | 	                    ¦   «         | j
        ¦  «         dS )zvBuild the circuit if not already build. The operation is considered successful
        when q_objective is :math:`|1>`Nr   )Ú	_is_builtr   Ú_buildr   r   r   rT   r   rF   Úto_gateÚqubits)r#   Úpoly_rr$   s     €r%   rg   zPiecewiseChebyshev._buildQ  sx   ø€ ð Œ>ð 	ØˆFå‰Œ�ŠÑÔÐå2ØÔ! 4Ô#3°TÔ5EÈDÌIð
ñ 
ô 
ˆð 	�Š�F—N’NÑ$Ô$ d¤kÑ2Ô2Ð2Ð2Ð2r&   )NNNr   )r   r   r   r   r   r   r   r   r   r   r   r   )T)r'   r(   r   r(   )r   r   )r   r1   r   r   )r   r5   )r   r   r   r   )r   r8   )r   r   r   r   )r   r>   )rT   rX   r   r   )r   r   r   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r.   Úpropertyr   Úsetterr   r   rT   r   r4   rg   Ú__classcell__)r$   s   @r%   r   r      sô  ø€ € € € € ð"ð "ðN "Ø(,Ø'+Øð1ð 1ð 1ð 1ð 1ð 1ð 1ðB ð  ð  ð  ð  ðD ðð ð ñ „Xðð 	„Zð9ð 9ð 9ñ „Zð9ð ðð ð ñ „Xðð „]ð9ð 9ð 9ñ „]ð9ð ðð ð ñ „Xðð, Ôð9ð 9ð 9ñ Ôð9ð ð7ð 7ð 7ñ „Xð7ðr Ôð9ð 9ð 9ñ Ôð9ð ð&ð &ð &ñ „Xð&ð Ôð4ð 4ð 4ñ Ôð4ð&.ð .ð .ð .ð3ð 3ð 3ð 3ð 3ð 3ð 3ð 3ð 3r&   r   )rn   Ú
__future__r   Útypingr   ÚnumpyrI   Únumpy.polynomial.chebyshevr   Úqiskit.circuitr   r   Ú'qiskit.circuit.library.blueprintcircuitr   Úqiskit.circuit.exceptionsr	   Ú$piecewise_polynomial_pauli_rotationsr   r   © r&   r%   ú<module>r{      sÝ   ðð DÐ Cà "Ð "Ð "Ð "Ð "Ð "Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ø 0Ð 0Ð 0Ð 0Ð 0Ð 0à ;Ð ;Ð ;Ð ;Ð ;Ð ;Ð ;Ð ;Ø DÐ DÐ DÐ DÐ DÐ DØ 2Ð 2Ð 2Ð 2Ð 2Ð 2à SÐ SÐ SÐ SÐ SÐ SðG3ð G3ð G3ð G3ð G3Ð)ñ G3ô G3ð G3ð G3ð G3r&   