o
    iJ                     @   st   d Z ddlZdd Zdd Zdd Zd	d
 ZdddZdddZdd ZdddZ	dddZ
dddZdddZdS ) z8
Routines for manipulating partial fraction expansions.
    Nc                 C   s&   ddl }t|  } t|| S )zEnp.roots replacement. XXX: calls into NumPy, then converts back.
    r   N)numpycupyasarraygetroots)arrnp r	   Z/home/ubuntu/veenaModal/venv/lib/python3.10/site-packages/cupyx/scipy/signal/_polyutils.pyr      s   r   c                 C   s   | j }t|dkr|d |d kr|d dkstdddl}|j|  }|j}|jd|d}|D ]}|j	||j
d| f dd	}q3t|jjtjrg|j|td}||||| krg|j }t|S )
z7np.poly replacement for 2D A. Otherwise, use cupy.poly.   r      z*input must be a non-empty square 2d array.N)r   dtypefull)mode)shapelen
ValueErrorr   linalgeigvalsr   r   onesconvolver_
issubclasstyper   complexfloatingr   complexallsort	conjugaterealcopy)Ashr   seq_of_zerosdtazeror   r	   r	   r
   poly   s   (

r(   c                 C   s"   t t | }t | |d|fS )z#Sort roots based on magnitude.
    r   )r   argsortabstake)pindxr	   r	   r
   _cmplx_sort)   s   r.   c           
      C   s  t | d } t |d }| d |d  }t| d }t|d }d|d  }t t|| d df|j}| |j}td|| d D ]}|||  }	|	||< |||| d   |	| 8  < qFt j|d dddr|j	d dkr|dd  }t j|d dddr|j	d dkst||fS )Ng        r   r   g      ?g+=)rtol)
r   
atleast_1dr   zerosmaxr   astyperangeallcloser   )
uvwmnscaleqrkdr	   r	   r
   _polydiv1   s    """rA   MbP?minc                 C   sF  |dv rt j}n|dv rt j}n|dv rt j}ntdt | jd df}t | |dddf< t | |dddf< t j	j
|dddddf |dddddf  d	d
}g }g }t j| jd td}t|D ].\}	}
||	 rsqj|
|k | @ }|
| }|jdkr||| |  ||jd  d||< qjt |t |fS )a  Determine unique roots and their multiplicities from a list of roots.

    Parameters
    ----------
    p : array_like
        The list of roots.
    tol : float, optional
        The tolerance for two roots to be considered equal in terms of
        the distance between them. Default is 1e-3. Refer to Notes about
        the details on roots grouping.
    rtype : {'max', 'maximum', 'min', 'minimum', 'avg', 'mean'}, optional
        How to determine the returned root if multiple roots are within
        `tol` of each other.

          - 'max', 'maximum': pick the maximum of those roots
          - 'min', 'minimum': pick the minimum of those roots
          - 'avg', 'mean': take the average of those roots

        When finding minimum or maximum among complex roots they are compared
        first by the real part and then by the imaginary part.

    Returns
    -------
    unique : ndarray
        The list of unique roots.
    multiplicity : ndarray
        The multiplicity of each root.

    See Also
    --------
    scipy.signal.unique_roots

    Notes
    -----
    If we have 3 roots ``a``, ``b`` and ``c``, such that ``a`` is close to
    ``b`` and ``b`` is close to ``c`` (distance is less than `tol`), then it
    doesn't necessarily mean that ``a`` is close to ``c``. It means that roots
    grouping is not unique. In this function we use "greedy" grouping going
    through the roots in the order they are given in the input `p`.

    This utility function is not specific to roots but can be used for any
    sequence of values for which uniqueness and multiplicity has to be
    determined. For a more general routine, see `numpy.unique`.

    )r3   maximum)rC   minimum)avgmeanzJ`rtype` must be one of {'max', 'maximum', 'min', 'minimum', 'avg', 'mean'}r   r   Nr   r0   )axisr   T)r   r3   rC   rG   r   emptyr   r    imagr   normr2   bool	enumeratesizeappendr   )r,   tolrtypereducepointsdistp_uniquep_multiplicityusedidsmaskgroupr	   r	   r
   unique_rootsD   s0   .8

r\   Fc                 C   s  t dg}|g}t| ddd |ddd D ] \}}t jd| f }tt|D ]}t ||}q*|| q|ddd }g }	t dg}t| ||D ]4\}}}
t jd| f }g }tt|D ]}|dksk|rt|t ||
 t ||}qc|	t	| qN|	|fS )z>Compute the total polynomial divided by factors for each root.r   r0   r   N)
r   arrayzipr   r5   intpolymulrO   extendreversed)r   multiplicityinclude_powerscurrentsuffixespolemultmonomial_factorssuffixblockrX   r	   r	   r
   _compute_factors   s&   &rn   c                 C   s   t | |\}}|| j}g }t| ||D ]Z\}}}|dkr.|t||t||  q| }	tjd| f }
t	||
\}}g }t
t|D ]}t	|	|
\}	}|d |d  }t|	|| }	|| qI|t| qt|S )Nr   r   )rn   r4   r   r^   rO   r   polyvalr!   r   rA   r5   r_   polysubra   rb   r   )polesrc   	numeratordenominator_factorsrj   residuesrg   rh   factornumerri   r@   rm   r;   r>   r	   r	   r
   _compute_residues   s*   

rw   rF   c                 C   s   t | } t |}t t |d}t|||\}}t||dd\}}t|dkr-d}	nt ||}	t| |D ]\}
}t |	|
| }	q8|	|fS )a  Compute b(s) and a(s) from partial fraction expansion.

    If `M` is the degree of numerator `b` and `N` the degree of denominator
    `a`::

              b(s)     b[0] s**(M) + b[1] s**(M-1) + ... + b[M]
      H(s) = ------ = ------------------------------------------
              a(s)     a[0] s**(N) + a[1] s**(N-1) + ... + a[N]

    then the partial-fraction expansion H(s) is defined as::

               r[0]       r[1]             r[-1]
           = -------- + -------- + ... + --------- + k(s)
             (s-p[0])   (s-p[1])         (s-p[-1])

    If there are any repeated roots (closer together than `tol`), then H(s)
    has terms like::

          r[i]      r[i+1]              r[i+n-1]
        -------- + ----------- + ... + -----------
        (s-p[i])  (s-p[i])**2          (s-p[i])**n

    This function is used for polynomials in positive powers of s or z,
    such as analog filters or digital filters in controls engineering.  For
    negative powers of z (typical for digital filters in DSP), use `invresz`.

    Parameters
    ----------
    r : array_like
        Residues corresponding to the poles. For repeated poles, the residues
        must be ordered to correspond to ascending by power fractions.
    p : array_like
        Poles. Equal poles must be adjacent.
    k : array_like
        Coefficients of the direct polynomial term.
    tol : float, optional
        The tolerance for two roots to be considered equal in terms of
        the distance between them. Default is 1e-3. See `unique_roots`
        for further details.
    rtype : {'avg', 'min', 'max'}, optional
        Method for computing a root to represent a group of identical roots.
        Default is 'avg'. See `unique_roots` for further details.

    Returns
    -------
    b : ndarray
        Numerator polynomial coefficients.
    a : ndarray
        Denominator polynomial coefficients.

    See Also
    --------
    scipy.signal.invres
    residue, invresz, unique_roots

    fTrd   r   	r   r1   
trim_zerosr\   rn   r   r`   r^   polyaddr>   r,   r?   rP   rQ   unique_polesrc   rk   denominatorrr   residueru   r	   r	   r
   invres   s   
9

r   c              	   C   s   t | } t |}t t |d}t|||\}}t||dd\}}t|dkr-d}	nt |ddd |ddd }	t| |D ]\}
}t |	|
|ddd  }	qB|	ddd |fS )a  Compute b(z) and a(z) from partial fraction expansion.

    If `M` is the degree of numerator `b` and `N` the degree of denominator
    `a`::

                b(z)     b[0] + b[1] z**(-1) + ... + b[M] z**(-M)
        H(z) = ------ = ------------------------------------------
                a(z)     a[0] + a[1] z**(-1) + ... + a[N] z**(-N)

    then the partial-fraction expansion H(z) is defined as::

                 r[0]                   r[-1]
         = --------------- + ... + ---------------- + k[0] + k[1]z**(-1) ...
           (1-p[0]z**(-1))         (1-p[-1]z**(-1))

    If there are any repeated roots (closer than `tol`), then the partial
    fraction expansion has terms like::

             r[i]              r[i+1]                    r[i+n-1]
        -------------- + ------------------ + ... + ------------------
        (1-p[i]z**(-1))  (1-p[i]z**(-1))**2         (1-p[i]z**(-1))**n

    This function is used for polynomials in negative powers of z,
    such as digital filters in DSP.  For positive powers, use `invres`.

    Parameters
    ----------
    r : array_like
        Residues corresponding to the poles. For repeated poles, the residues
        must be ordered to correspond to ascending by power fractions.
    p : array_like
        Poles. Equal poles must be adjacent.
    k : array_like
        Coefficients of the direct polynomial term.
    tol : float, optional
        The tolerance for two roots to be considered equal in terms of
        the distance between them. Default is 1e-3. See `unique_roots`
        for further details.
    rtype : {'avg', 'min', 'max'}, optional
        Method for computing a root to represent a group of identical roots.
        Default is 'avg'. See `unique_roots` for further details.

    Returns
    -------
    b : ndarray
        Numerator polynomial coefficients.
    a : ndarray
        Denominator polynomial coefficients.

    See Also
    --------
    scipy.signal.invresz
    residuez, unique_roots, invres

    bTry   r   Nr0   rz   r}   r	   r	   r
   invresz  s   
8

 r   c                 C   sP  t | jt jst |jt jr| t} |t}n
| t} |t}t t | d} t t |d}|j	dkr@t
dt|}| j	dkrYt |jt|d t g fS t| t|k rgt d}nt| |\}} t|||d\}}t|\}}|| }t||| }	d}
t||D ]\}}|||
|
| < |
|7 }
q|	|d  ||fS )a  Compute partial-fraction expansion of b(s) / a(s).

    If `M` is the degree of numerator `b` and `N` the degree of denominator
    `a`::

              b(s)     b[0] s**(M) + b[1] s**(M-1) + ... + b[M]
      H(s) = ------ = ------------------------------------------
              a(s)     a[0] s**(N) + a[1] s**(N-1) + ... + a[N]

    then the partial-fraction expansion H(s) is defined as::

               r[0]       r[1]             r[-1]
           = -------- + -------- + ... + --------- + k(s)
             (s-p[0])   (s-p[1])         (s-p[-1])

    If there are any repeated roots (closer together than `tol`), then H(s)
    has terms like::

          r[i]      r[i+1]              r[i+n-1]
        -------- + ----------- + ... + -----------
        (s-p[i])  (s-p[i])**2          (s-p[i])**n

    This function is used for polynomials in positive powers of s or z,
    such as analog filters or digital filters in controls engineering.  For
    negative powers of z (typical for digital filters in DSP), use `residuez`.

    See Notes for details about the algorithm.

    Parameters
    ----------
    b : array_like
        Numerator polynomial coefficients.
    a : array_like
        Denominator polynomial coefficients.
    tol : float, optional
        The tolerance for two roots to be considered equal in terms of
        the distance between them. Default is 1e-3. See `unique_roots`
        for further details.
    rtype : {'avg', 'min', 'max'}, optional
        Method for computing a root to represent a group of identical roots.
        Default is 'avg'. See `unique_roots` for further details.

    Returns
    -------
    r : ndarray
        Residues corresponding to the poles. For repeated poles, the residues
        are ordered to correspond to ascending by power fractions.
    p : ndarray
        Poles ordered by magnitude in ascending order.
    k : ndarray
        Coefficients of the direct polynomial term.

    Warning
    -------
    This function may synchronize the device.

    See Also
    --------
    scipy.signal.residue
    invres, residuez, numpy.poly, unique_roots

    Notes
    -----
    The "deflation through subtraction" algorithm is used for
    computations --- method 6 in [1]_.

    The form of partial fraction expansion depends on poles multiplicity in
    the exact mathematical sense. However there is no way to exactly
    determine multiplicity of roots of a polynomial in numerical computing.
    Thus you should think of the result of `residue` with given `tol` as
    partial fraction expansion computed for the denominator composed of the
    computed poles with empirically determined multiplicity. The choice of
    `tol` can drastically change the result if there are close poles.

    References
    ----------
    .. [1] J. F. Mahoney, B. D. Sivazlian, "Partial fractions expansion: a
           review of computational methodology and efficiency", Journal of
           Computational and Applied Mathematics, Vol. 9, 1983.
    rx   r   Denominator `a` is zero.rP   rQ   )r   
issubdtyper   r   r4   r   floatr{   r1   rN   r   r   r2   r   r.   r]   r   rI   rA   r\   rw   r^   )r   r&   rP   rQ   rq   r?   r~   rc   orderrt   indexrg   rh   r	   r	   r
   r   a  s4   Q




 
r   c                 C   s  t | jt jst |jt jr| t} |t}n
| t} |t}t t | d} t t |d}|j	dkr@t
d|d dkrJt
dt|}| j	dkrct |jt|d t g fS | ddd }|ddd }t|t|k rt d}nt||\}}t|||d\}}	t|\}}
|	|
 }	td| |	|}d}t jt|td	}t||	D ]\}}||||| < dt t| |||| < ||7 }q|| | |d  9 }|||ddd fS )
aS  Compute partial-fraction expansion of b(z) / a(z).

    If `M` is the degree of numerator `b` and `N` the degree of denominator
    `a`::

                b(z)     b[0] + b[1] z**(-1) + ... + b[M] z**(-M)
        H(z) = ------ = ------------------------------------------
                a(z)     a[0] + a[1] z**(-1) + ... + a[N] z**(-N)

    then the partial-fraction expansion H(z) is defined as::

                 r[0]                   r[-1]
         = --------------- + ... + ---------------- + k[0] + k[1]z**(-1) ...
           (1-p[0]z**(-1))         (1-p[-1]z**(-1))

    If there are any repeated roots (closer than `tol`), then the partial
    fraction expansion has terms like::

             r[i]              r[i+1]                    r[i+n-1]
        -------------- + ------------------ + ... + ------------------
        (1-p[i]z**(-1))  (1-p[i]z**(-1))**2         (1-p[i]z**(-1))**n

    This function is used for polynomials in negative powers of z,
    such as digital filters in DSP.  For positive powers, use `residue`.

    See Notes of `residue` for details about the algorithm.

    Parameters
    ----------
    b : array_like
        Numerator polynomial coefficients.
    a : array_like
        Denominator polynomial coefficients.
    tol : float, optional
        The tolerance for two roots to be considered equal in terms of
        the distance between them. Default is 1e-3. See `unique_roots`
        for further details.
    rtype : {'avg', 'min', 'max'}, optional
        Method for computing a root to represent a group of identical roots.
        Default is 'avg'. See `unique_roots` for further details.

    Returns
    -------
    r : ndarray
        Residues corresponding to the poles. For repeated poles, the residues
        are ordered to correspond to ascending by power fractions.
    p : ndarray
        Poles ordered by magnitude in ascending order.
    k : ndarray
        Coefficients of the direct polynomial term.

    Warning
    -------
    This function may synchronize the device.

    See Also
    --------
    scipy.signal.residuez
    invresz, residue, unique_roots
    r   r   r   z6First coefficient of determinant `a` must be non-zero.Nr0   r   r   r   )r   r   r   r   r4   r   r   r{   r1   rN   r   r   r2   r   r.   r]   r   rI   rA   r\   rw   r_   r^   arange)r   r&   rP   rQ   rq   b_reva_revk_revr~   rc   r   rt   r   powersrg   rh   r	   r	   r
   residuez  sB   >




 
r   )rB   rC   )F)rB   rF   )__doc__r   r   r(   r.   rA   r\   rn   rw   r   r   r   r   r	   r	   r	   r
   <module>   s    	

R

L
Kv