
    Ui                         d dl Zd dlmZ d dlmZmZmZ dgZ G d de          Z	 G d de          Z
 G d d	e          Z G d
 de          Z G d d          ZdS )    N)LinearOperator)kron	eye_array	dia_arrayLaplacianNdc                   z     e Zd ZdZdej        d fd
Zd ZddZd Z	d	 Z
dd
Zd Zd Zd Zd Zd Zd Z xZS )r   ay"  
    The grid Laplacian in ``N`` dimensions and its eigenvalues/eigenvectors.

    Construct Laplacian on a uniform rectangular grid in `N` dimensions
    and output its eigenvalues and eigenvectors.
    The Laplacian ``L`` is square, negative definite, real symmetric array
    with signed integer entries and zeros otherwise.

    Parameters
    ----------
    grid_shape : tuple
        A tuple of integers of length ``N`` (corresponding to the dimension of
        the Lapacian), where each entry gives the size of that dimension. The
        Laplacian matrix is square of the size ``np.prod(grid_shape)``.
    boundary_conditions : {'neumann', 'dirichlet', 'periodic'}, optional
        The type of the boundary conditions on the boundaries of the grid.
        Valid values are ``'dirichlet'`` or ``'neumann'``(default) or
        ``'periodic'``.
    dtype : dtype
        Numerical type of the array. Default is ``np.int8``.

    Methods
    -------
    toarray()
        Construct a dense array from Laplacian data
    tosparse()
        Construct a sparse array from Laplacian data
    eigenvalues(m=None)
        Construct a 1D array of `m` largest (smallest in absolute value)
        eigenvalues of the Laplacian matrix in ascending order.
    eigenvectors(m=None):
        Construct the array with columns made of `m` eigenvectors (``float``)
        of the ``Nd`` Laplacian corresponding to the `m` ordered eigenvalues.

    .. versionadded:: 1.12.0

    Notes
    -----
    Compared to the MATLAB/Octave implementation [1] of 1-, 2-, and 3-D
    Laplacian, this code allows the arbitrary N-D case and the matrix-free
    callable option, but is currently limited to pure Dirichlet, Neumann or
    Periodic boundary conditions only.

    The Laplacian matrix of a graph (`scipy.sparse.csgraph.laplacian`) of a
    rectangular grid corresponds to the negative Laplacian with the Neumann
    conditions, i.e., ``boundary_conditions = 'neumann'``.

    All eigenvalues and eigenvectors of the discrete Laplacian operator for
    an ``N``-dimensional  regular grid of shape `grid_shape` with the grid
    step size ``h=1`` are analytically known [2].

    References
    ----------
    .. [1] https://github.com/lobpcg/blopex/blob/master/blopex_tools/matlab/laplacian/laplacian.m
    .. [2] "Eigenvalues and eigenvectors of the second derivative", Wikipedia
           https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors_of_the_second_derivative

    Examples
    --------
    >>> import numpy as np
    >>> from scipy.sparse.linalg import LaplacianNd
    >>> from scipy.sparse import diags_array, csgraph
    >>> from scipy.linalg import eigvalsh

    The one-dimensional Laplacian demonstrated below for pure Neumann boundary
    conditions on a regular grid with ``n=6`` grid points is exactly the
    negative graph Laplacian for the undirected linear graph with ``n``
    vertices using the sparse adjacency matrix ``G`` represented by the
    famous tri-diagonal matrix:

    >>> n = 6
    >>> G = diags_array(np.ones(n - 1), offsets=1, format='csr')
    >>> Lf = csgraph.laplacian(G, symmetrized=True, form='function')
    >>> grid_shape = (n, )
    >>> lap = LaplacianNd(grid_shape, boundary_conditions='neumann')
    >>> np.array_equal(lap.matmat(np.eye(n)), -Lf(np.eye(n)))
    True

    Since all matrix entries of the Laplacian are integers, ``'int8'`` is
    the default dtype for storing matrix representations.

    >>> lap.tosparse()
    <DIAgonal sparse array of dtype 'int8'
        with 16 stored elements (3 diagonals) and shape (6, 6)>
    >>> lap.toarray()
    array([[-1,  1,  0,  0,  0,  0],
           [ 1, -2,  1,  0,  0,  0],
           [ 0,  1, -2,  1,  0,  0],
           [ 0,  0,  1, -2,  1,  0],
           [ 0,  0,  0,  1, -2,  1],
           [ 0,  0,  0,  0,  1, -1]], dtype=int8)
    >>> np.array_equal(lap.matmat(np.eye(n)), lap.toarray())
    True
    >>> np.array_equal(lap.tosparse().toarray(), lap.toarray())
    True

    Any number of extreme eigenvalues and/or eigenvectors can be computed.

    >>> lap = LaplacianNd(grid_shape, boundary_conditions='periodic')
    >>> lap.eigenvalues()
    array([-4., -3., -3., -1., -1.,  0.])
    >>> lap.eigenvalues()[-2:]
    array([-1.,  0.])
    >>> lap.eigenvalues(2)
    array([-1.,  0.])
    >>> lap.eigenvectors(1)
    array([[0.40824829],
           [0.40824829],
           [0.40824829],
           [0.40824829],
           [0.40824829],
           [0.40824829]])
    >>> lap.eigenvectors(2)
    array([[ 0.5       ,  0.40824829],
           [ 0.        ,  0.40824829],
           [-0.5       ,  0.40824829],
           [-0.5       ,  0.40824829],
           [ 0.        ,  0.40824829],
           [ 0.5       ,  0.40824829]])
    >>> lap.eigenvectors()
    array([[ 0.40824829,  0.28867513,  0.28867513,  0.5       ,  0.5       ,
             0.40824829],
           [-0.40824829, -0.57735027, -0.57735027,  0.        ,  0.        ,
             0.40824829],
           [ 0.40824829,  0.28867513,  0.28867513, -0.5       , -0.5       ,
             0.40824829],
           [-0.40824829,  0.28867513,  0.28867513, -0.5       , -0.5       ,
             0.40824829],
           [ 0.40824829, -0.57735027, -0.57735027,  0.        ,  0.        ,
             0.40824829],
           [-0.40824829,  0.28867513,  0.28867513,  0.5       ,  0.5       ,
             0.40824829]])

    The two-dimensional Laplacian is illustrated on a regular grid with
    ``grid_shape = (2, 3)`` points in each dimension.

    >>> grid_shape = (2, 3)
    >>> n = np.prod(grid_shape)

    Numeration of grid points is as follows:

    >>> np.arange(n).reshape(grid_shape + (-1,))
    array([[[0],
            [1],
            [2]],
    <BLANKLINE>
           [[3],
            [4],
            [5]]])

    Each of the boundary conditions ``'dirichlet'``, ``'periodic'``, and
    ``'neumann'`` is illustrated separately; with ``'dirichlet'``

    >>> lap = LaplacianNd(grid_shape, boundary_conditions='dirichlet')
    >>> lap.tosparse()
    <Compressed Sparse Row sparse array of dtype 'int8'
        with 20 stored elements and shape (6, 6)>
    >>> lap.toarray()
    array([[-4,  1,  0,  1,  0,  0],
           [ 1, -4,  1,  0,  1,  0],
           [ 0,  1, -4,  0,  0,  1],
           [ 1,  0,  0, -4,  1,  0],
           [ 0,  1,  0,  1, -4,  1],
           [ 0,  0,  1,  0,  1, -4]], dtype=int8)
    >>> np.array_equal(lap.matmat(np.eye(n)), lap.toarray())
    True
    >>> np.array_equal(lap.tosparse().toarray(), lap.toarray())
    True
    >>> lap.eigenvalues()
    array([-6.41421356, -5.        , -4.41421356, -3.58578644, -3.        ,
           -1.58578644])
    >>> eigvals = eigvalsh(lap.toarray().astype(np.float64))
    >>> np.allclose(lap.eigenvalues(), eigvals)
    True
    >>> np.allclose(lap.toarray() @ lap.eigenvectors(),
    ...             lap.eigenvectors() @ np.diag(lap.eigenvalues()))
    True

    with ``'periodic'``

    >>> lap = LaplacianNd(grid_shape, boundary_conditions='periodic')
    >>> lap.tosparse()
    <Compressed Sparse Row sparse array of dtype 'int8'
        with 24 stored elements and shape (6, 6)>
    >>> lap.toarray()
        array([[-4,  1,  1,  2,  0,  0],
               [ 1, -4,  1,  0,  2,  0],
               [ 1,  1, -4,  0,  0,  2],
               [ 2,  0,  0, -4,  1,  1],
               [ 0,  2,  0,  1, -4,  1],
               [ 0,  0,  2,  1,  1, -4]], dtype=int8)
    >>> np.array_equal(lap.matmat(np.eye(n)), lap.toarray())
    True
    >>> np.array_equal(lap.tosparse().toarray(), lap.toarray())
    True
    >>> lap.eigenvalues()
    array([-7., -7., -4., -3., -3.,  0.])
    >>> eigvals = eigvalsh(lap.toarray().astype(np.float64))
    >>> np.allclose(lap.eigenvalues(), eigvals)
    True
    >>> np.allclose(lap.toarray() @ lap.eigenvectors(),
    ...             lap.eigenvectors() @ np.diag(lap.eigenvalues()))
    True

    and with ``'neumann'``

    >>> lap = LaplacianNd(grid_shape, boundary_conditions='neumann')
    >>> lap.tosparse()
    <Compressed Sparse Row sparse array of dtype 'int8'
        with 20 stored elements and shape (6, 6)>
    >>> lap.toarray()
    array([[-2,  1,  0,  1,  0,  0],
           [ 1, -3,  1,  0,  1,  0],
           [ 0,  1, -2,  0,  0,  1],
           [ 1,  0,  0, -2,  1,  0],
           [ 0,  1,  0,  1, -3,  1],
           [ 0,  0,  1,  0,  1, -2]], dtype=int8)
    >>> np.array_equal(lap.matmat(np.eye(n)), lap.toarray())
    True
    >>> np.array_equal(lap.tosparse().toarray(), lap.toarray())
    True
    >>> lap.eigenvalues()
    array([-5., -3., -3., -2., -1.,  0.])
    >>> eigvals = eigvalsh(lap.toarray().astype(np.float64))
    >>> np.allclose(lap.eigenvalues(), eigvals)
    True
    >>> np.allclose(lap.toarray() @ lap.eigenvectors(),
    ...             lap.eigenvectors() @ np.diag(lap.eigenvalues()))
    True

    neumann)boundary_conditionsdtypec                    |dvrt          d|d          || _        || _        t          j        |          }t                                          |||f           d S )N)	dirichletr	   periodiczUnknown value zv is given for 'boundary_conditions' parameter. The valid options are 'dirichlet', 'periodic', and 'neumann' (default).)r   shape)
ValueError
grid_shaper
   npprodsuper__init__)selfr   r
   r   N	__class__s        /var/www/development/aibuddy-work/election-extract/venv/lib/python3.11/site-packages/scipy/sparse/linalg/_special_sparse_arrays.pyr   zLaplacianNd.__init__   s     &JJJD!4 D D D   %#6 GJuQF33333    c           
      d   | j         }|)t          j        |          }t          j        |          }nZt	          |t          t          j        |          |z                      }t          j        |          }t          j        |          }t          ||          D ]\  }}| j        dk    r7|dt          j	        t          j
        |dz   z  d|dz   z  z            dz  z  z  }G| j        dk    r1|dt          j	        t          j
        |z  d|z  z            dz  z  z  }|dt          j	        t          j
        t          j        |dz   dz            z  |z            dz  z  z  }|                                }t          j        |          }	||	         }
||
| d         }
|	| d         }	|
|	fS )zCompute `m` largest eigenvalues in each of the ``N`` directions,
        i.e., up to ``m * N`` total, order them and return `m` largest.
        Nr         r	   )r   r   indiceszerosmintuple	ones_likezipr
   sinpifloorravelargsort)r   mr   r   Leiggrid_shape_minjn
Leig_ravelindeigenvaluess              r   _eigenvalue_orderingz LaplacianNd._eigenvalue_ordering  s    _
9j,,G8J''DD !&r|J'?'?!'C!D!DF FNj00G8N++D,, 	L 	LDAq';66RVBEQUOqAE{$CDDIII)Y66RVBEAIQ$788A===RVBEBHa!eq[,A,A$AA$EFF!KKKZZ\\
j$$ o=%qbcc*Kqbcc(CCr   Nc                 6    |                      |          \  }}|S )a  Return the requested number of eigenvalues.

        Parameters
        ----------
        m : int, optional
            The positive number of smallest eigenvalues to return.
            If not provided, then all eigenvalues will be returned.

        Returns
        -------
        eigenvalues : float array
            The requested `m` smallest or all eigenvalues, in ascending order.
        )r2   )r   r*   r1   _s       r   r1   zLaplacianNd.eigenvalues%  s!     22155Qr   c                    | j         dk    rat          j        t          j        |          dz   z  |dz   z  }t          j        d|dz   z            t          j        ||dz   z            z  }nS| j         dk    r_t          j        t          j        |          dz   z  |z  }t          j        |dk    rdnd|z            t          j        ||z            z  }n|dk    r-t          j        d|z            t          j        |          z  }n|dz   |k    r<|dz  dk    r3t          j        d|z            t          j        dd	g|dz            z  }nqdt          j        z  t          j        |          dz   z  |z  }t          j        d|z            t          j        |t          j	        |dz   dz            z            z  }d
|t          j
        |          t          j        t          j                  j        k     <   |S )ziReturn 1 eigenvector in 1d with index `j`
        and number of grid points `n` where ``j < n``.
        r   r   g       @      ?r	         ?r   r   g        )r
   r   r&   arangesqrtr%   cosonestiler'   absfinfofloat64eps)r   r-   r.   ievs        r   _ev1dzLaplacianNd._ev1d6  s    #{221)*a!e4Aq2v''"&a!e*=*==BB%221+,q0AQ""B!344rva!e}}DBBAvvWR!V__rwqzz1Q!A

WR!V__rw2w1'='==J")A,,"459WR!V__rva"(AEQ;2G2G.G'H'HH 5726"::,,001	r   c                       fdt          | j                  D             }|d         }|dd         D ]}t          j        ||d          }t          j        |                                          S )zzReturn 1 eigenvector in Nd with multi-index `j`
        as a tensor product of the corresponding 1d eigenvectors.
        c                 B    g | ]\  }}                     ||          S  )rD   ).0r-   r.   r   s      r   
<listcomp>z(LaplacianNd._one_eve.<locals>.<listcomp>Q  s+    DDDDAqtzz!QDDDr   r   r   N)axes)r$   r   r   	tensordotasarrayr(   )r   kphiresults   `   r   _one_evezLaplacianNd._one_eveM  s     EDDDC4?,C,CDDDQqrr7 	7 	7C\&#A666FFz&!!'')))r   c                 T                          |          \  }}| j        }n<t           j        t          t	          j         j                  |z                      }t	          j        ||          }d t          | D             } fd|D             }t	          j        |          S )a  Return the requested number of eigenvectors for ordered eigenvalues.

        Parameters
        ----------
        m : int, optional
            The positive number of eigenvectors to return. If not provided,
            then all eigenvectors will be returned.

        Returns
        -------
        eigenvectors : float array
            An array with columns made of the requested `m` or all eigenvectors.
            The columns are ordered according to the `m` ordered eigenvalues.
        Nc                 ,    g | ]}t          |          S rG   )r"   rH   xs     r   rI   z,LaplacianNd.eigenvectors.<locals>.<listcomp>n  s    777!U1XX777r   c                 :    g | ]}                     |          S rG   )rP   )rH   rM   r   s     r   rI   z,LaplacianNd.eigenvectors.<locals>.<listcomp>o  s%    AAA!T]]1--AAAr   )	r2   r   r!   r"   r   r#   unravel_indexr$   column_stack)r   r*   r4   r0   r,   	N_indiceseigenvectors_lists   `      r   eigenvectorszLaplacianNd.eigenvectorsW  s     **1--39!_NN  %bl4?&C&Ca&G H HJ JN $S.99	77sI777	AAAAyAAA0111r   c           
         | j         }t          j        |          }t          j        ||gt          j                  }t          j        |          }t          j        |          }t          |          D ]\  }}d|dd<   dt          j        d|d|d|f                   dd<   dt          j        d|d|dz
  d|f                   dd<   dt          j        d|d|d|dz
  f                   dd<   | j        dk    rd|d	<   d||dz
  |dz
  f<   nL| j        d
k    rA|dk    r+|d|dz
  fxx         dz  cc<   ||dz
  dfxx         dz  cc<   n|d	xx         dz  cc<   |}|dk    r]t          j        |d|                   }	t          d|	          D ]0}
|d|d|f         ||
|z  |
dz   |z  |
|z  |
dz   |z  f<   ||z  }1|d|d|f         |d|d|f<   t          t          j        ||dz   d                             }	d|d|d|f<   d t          |	          D             }|d|d|f         |                    ||	||	f          dd|dd|f<   ||z  }|                    | j                  S )z
        Converts the Laplacian data to a dense array.

        Returns
        -------
        L : ndarray
            The shape is ``(N, N)`` where ``N = np.prod(grid_shape)``.

        r   r   Nzii->ir   r	   r8   r   r   r   c                     g | ]}|S rG   rG   rS   s     r   rI   z'LaplacianNd.toarray.<locals>.<listcomp>  s    +++1+++r   )r   r   r   r    int8
empty_like	enumerateeinsumr
   rangeintreshapeastyper   )r   r   r.   LL_iLtempr0   dimnew_dimtilesr-   idxs               r   toarrayzLaplacianNd.toarrayr  s    _
GJHaV27+++mAa  !*-- +	 +	HCCF 68BIgs4C4#://2;<BIgs9S1W9ae#3455aaa8;<BIgs1S5)C!G)#3455aaa8'944D	(*C!GS1W$%%)Z777737
OOOq(OOOa
OOOq(OOOOIIINIII GQww
4C4 011q% # #A<?dsd
OC#qsCi3!Sy89sNGG ),HWHhwh,>(?E(7(HWH$%
3q566 23344E&'C(7("#++eEll+++C %*(7(HWH*<$= KK%%!  !!S!!!S."
 HAAxx
###r   c           	         t          | j                  }t          j        | j                  }t	          ||ft          j                  }t          |          D ]v}| j        |         }t          j        d|gt          j                  }|dddfxx         dz  cc<   | j        dk    r
d|d<   d|d	<   t	          |g d
f||ft          j                  }| j        dk    rYt	          ||ft          j                  }|	                    dg| dz              |	                    dg|dz
             ||z  }t          |          D ]6}	t          t          | j        |	         t          j                  |          }7t          |dz   |          D ]6}	t          |t          | j        |	         t          j                            }7||z  }x|                    | j                  S )a)  
        Constructs a sparse array from the Laplacian data. The returned sparse
        array format is dependent on the selected boundary conditions.

        Returns
        -------
        L : scipy.sparse.sparray
            The shape is ``(N, N)`` where ``N = np.prod(grid_shape)``.

        r\      r   Nr]   r	   r8   r   r   )r   r8   r8   r   r   )r   r   r   )rM   )lenr   r   r   r   r`   rd   r<   r
   setdiagr   r   rg   r   )
r   r   prh   rB   rk   datari   tr-   s
             r   tosparsezLaplacianNd.tosparse  s      GDO$$q!fBG,,,q 	 	A/!$C7As827333DAAAJJJ"JJJ'944T
 UT:::.sCj"$'  C ':55sCj888		1##a	(((		1#Q	'''q1XX N N9T_Q%7rwGGGMM1q5!__ N N3	$/!*<BG L L LMMHAAxx
###r   c           	         | j         }t          |          }|                    |dz             }d|z  |z  }t          |          D ]i}|t	          j        |d|          z  }|t	          j        |d|          z  }| j        dv r(|t          d           f|z  dz   t          d           f||z
  dz
  z  z   xx         t	          j        |d|          t          d           f|z  dz   t          d           f||z
  dz
  z  z            z  cc<   |t          d           f|z  dz   t          d           f||z
  dz
  z  z   xx         t	          j        |d|          t          d           f|z  dz   t          d           f||z
  dz
  z  z            z  cc<   | j        dk    r|t          d           f|z  dz   t          d           f||z
  dz
  z  z   xx         t	          j        |d	|          t          d           f|z  dz   t          d           f||z
  dz
  z  z            z  cc<   |t          d           f|z  dz   t          d           f||z
  dz
  z  z   xx         t	          j        |d	|          t          d           f|z  dz   t          d           f||z
  dz
  z  z            z  cc<   k|                    d|j        d                   S )
N)r8   r]   r   )axisr8   )r	   r   )r   r	   r   )	r   rt   rf   rd   r   rollr
   slicer   )r   rT   r   r   XYrB   s          r   _matveczLaplacianNd._matvec  s5   _

OOIIj5())FQJq 	 	AAA&&&&ABQ''''A'+CCC5;;."T)U4[[NAaCE,BB   wq!!,,,4[[NQ&-t!A#a%0HH    4[[NQ&.%++1Q3q51II  WQ+++4[[NQ&.%++1Q3q51II    +y88t*T1U4[[Nac!e4LL  AA...t*T1U4[[Nac!e4LL   
 t*U2eDkk^qs1u5MM  AA...t*U2eDkk^qs1u5MM    yyQWR[)))r   c                 ,    |                      |          S Nr   r   rT   s     r   _matmatzLaplacianNd._matmat  s    ||Ar   c                     | S r   rG   r   s    r   _adjointzLaplacianNd._adjoint      r   c                     | S r   rG   r   s    r   
_transposezLaplacianNd._transpose  r   r   r   )__name__
__module____qualname____doc__r   r`   r   r2   r1   rD   rP   rZ   ro   ry   r   r   r   r   __classcell__r   s   @r   r   r   
   s       h hV &/w4 4 4 4 4 4 4"     >   "  .* * *2 2 2 26>$ >$ >$@'$ '$ '$R* * *B          r   c                   b     e Zd ZdZej        f fd	ZddZd Zd Z	d Z
d Zd	 Zd
 Zd Z xZS )Sakuraia  
    Construct a Sakurai matrix in various formats and its eigenvalues.

    Constructs the "Sakurai" matrix motivated by reference [1]_:
    square real symmetric positive definite and 5-diagonal
    with the main diagonal ``[5, 6, 6, ..., 6, 6, 5], the ``+1`` and ``-1``
    diagonals filled with ``-4``, and the ``+2`` and ``-2`` diagonals
    made of ``1``. Its eigenvalues are analytically known to be
    ``16. * np.power(np.cos(0.5 * k * np.pi / (n + 1)), 4)``.
    The matrix gets ill-conditioned with its size growing.
    It is useful for testing and benchmarking sparse eigenvalue solvers
    especially those taking advantage of its banded 5-diagonal structure.
    See the notes below for details.

    Parameters
    ----------
    n : int
        The size of the matrix.
    dtype : dtype
        Numerical type of the array. Default is ``np.int8``.

    Methods
    -------
    toarray()
        Construct a dense array from Laplacian data
    tosparse()
        Construct a sparse array from Laplacian data
    tobanded()
        The Sakurai matrix in the format for banded symmetric matrices,
        i.e., (3, n) ndarray with 3 upper diagonals
        placing the main diagonal at the bottom.
    eigenvalues
        All eigenvalues of the Sakurai matrix ordered ascending.

    Notes
    -----
    Reference [1]_ introduces a generalized eigenproblem for the matrix pair
    `A` and `B` where `A` is the identity so we turn it into an eigenproblem
    just for the matrix `B` that this function outputs in various formats
    together with its eigenvalues.

    .. versionadded:: 1.12.0

    References
    ----------
    .. [1] T. Sakurai, H. Tadano, Y. Inadomi, and U. Nagashima,
       "A moment-based method for large-scale generalized
       eigenvalue problems",
       Appl. Num. Anal. Comp. Math. Vol. 1 No. 2 (2004).

    Examples
    --------
    >>> import numpy as np
    >>> from scipy.sparse.linalg._special_sparse_arrays import Sakurai
    >>> from scipy.linalg import eig_banded
    >>> n = 6
    >>> sak = Sakurai(n)

    Since all matrix entries are small integers, ``'int8'`` is
    the default dtype for storing matrix representations.

    >>> sak.toarray()
    array([[ 5, -4,  1,  0,  0,  0],
           [-4,  6, -4,  1,  0,  0],
           [ 1, -4,  6, -4,  1,  0],
           [ 0,  1, -4,  6, -4,  1],
           [ 0,  0,  1, -4,  6, -4],
           [ 0,  0,  0,  1, -4,  5]], dtype=int8)
    >>> sak.tobanded()
    array([[ 1,  1,  1,  1,  1,  1],
           [-4, -4, -4, -4, -4, -4],
           [ 5,  6,  6,  6,  6,  5]], dtype=int8)
    >>> sak.tosparse()
    <DIAgonal sparse array of dtype 'int8'
        with 24 stored elements (5 diagonals) and shape (6, 6)>
    >>> np.array_equal(sak.dot(np.eye(n)), sak.tosparse().toarray())
    True
    >>> sak.eigenvalues()
    array([0.03922866, 0.56703972, 2.41789479, 5.97822974,
           10.54287655, 14.45473055])
    >>> sak.eigenvalues(2)
    array([0.03922866, 0.56703972])

    The banded form can be used in scipy functions for banded matrices, e.g.,

    >>> e = eig_banded(sak.tobanded(), eigvals_only=True)
    >>> np.allclose(sak.eigenvalues(), e, atol= n * n * n * np.finfo(float).eps)
    True

    c                 p    || _         || _        ||f}t                                          ||           d S r   )r.   r   r   r   )r   r.   r   r   r   s       r   r   zSakurai.__init__a  s:    
A&&&&&r   Nc           
         || j         }t          j        | j         dz   |z
  | j         dz             }t          j        dt          j        t          j        d|z  t          j        z  | j         dz   z            d          z            S )a  Return the requested number of eigenvalues.

        Parameters
        ----------
        m : int, optional
            The positive number of smallest eigenvalues to return.
            If not provided, then all eigenvalues will be returned.

        Returns
        -------
        eigenvalues : `np.float64` array
            The requested `m` smallest or all eigenvalues, in ascending order.
        Nr   g      0@r7      )r.   r   r9   flippowerr;   r&   )r   r*   rM   s      r   r1   zSakurai.eigenvaluesg  sq     9AIdfqj!mTVaZ00wsRXbfS1Wru_
-K&L&LaPPPQQQr   c                 X   t           j        ddt          j        | j        dz
  | j                  z  df         }dt          j        | j        | j                  z  }t          j        | j        | j                  }t          j        |||g                              | j                  S )zA
        Construct the Sakurai matrix as a banded array.
              r   r\   r   )r   r_r<   r.   r   arrayrg   )r   d0d1d2s       r   tobandedzSakurai.tobandedz  s     U1a"'$&1*DJ????BC"'$&
3333WTV4:...xR%%,,TZ888r   c                     ddl m} |                                 } ||d         |d         |d         |d         |d         gg d| j        | j        f|j                  S )zB
        Construct the Sakurai matrix in a sparse format.
        r   diags_arrayr   r   )r]   r8   r   r   r   offsetsr   r   )scipy.sparser   r   r.   r   )r   r   ds      r   ry   zSakurai.tosparse  s|     	-,,,,,MMOO {AaD!A$!adAaD9CTCTCT"&&$&!1B B B 	Br   c                 N    |                                                                  S r   ry   ro   r   s    r   ro   zSakurai.toarray      }}&&(((r   c                 p   |                     | j        d          }t          j        |j        | j                  }t          j        ||          }d|dddf         z  d|dddf         z  z
  |dddf         z   |dddf<   d|dddf         z  d|d	ddf         z  z
  |d
ddf         z   |dddf<   d|ddddf         z  d|dd	ddf         |ddddf         z   z  z
  t          j        |dd
ddf         d          z   t          j        |ddddf         d          z   |ddddf<   |S )z
        Construct matrix-free callable banded-matrix-vector multiplication by
        the Sakurai matrix without constructing or storing the matrix itself
        using the knowledge of its entries and the 5-diagonal format.
        r8   r\   r   r   Nr   r   r   r]   r   )rr   r^   rq   ))r   r   r^   )rf   r.   r   promote_typesr   
zeros_likepad)r   rT   result_dtypesxs       r   r   zSakurai._matvec  sz    IIdfb!!'<<]1L111qAAAw;Qq!!!tW,qAAAw61aaa4"aaa%L1qQQQx</!BE(:2qqq5	AaeQQQhK!q"aaay1QRRU8/C*DDq"aaay*:;;<qQQQx)9::;1b5!!!8 	r   c                 ,    |                      |          S )z
        Construct matrix-free callable matrix-matrix multiplication by
        the Sakurai matrix without constructing or storing the matrix itself
        by reusing the ``_matvec(x)`` that supports both 1D and 2D arrays ``x``.
        r   r   s     r   r   zSakurai._matmat       ||Ar   c                     | S r   rG   r   s    r   r   zSakurai._adjoint  r   r   c                     | S r   rG   r   s    r   r   zSakurai._transpose  r   r   r   )r   r   r   r   r   r`   r   r1   r   ry   ro   r   r   r   r   r   r   s   @r   r   r     s        Y Yt !# ' ' ' ' ' 'R R R R&9 9 9	B 	B 	B) ) )             r   r   c                   `     e Zd ZdZej        f fd	Zd Zd Zd Z	d Z
d Zd Zd	 Zd
 Z xZS )MikotaMas  
    Construct a mass matrix in various formats of Mikota pair.

    The mass matrix `M` is square real diagonal
    positive definite with entries that are reciprocal to integers.

    Parameters
    ----------
    shape : tuple of int
        The shape of the matrix.
    dtype : dtype
        Numerical type of the array. Default is ``np.float64``.

    Methods
    -------
    toarray()
        Construct a dense array from Mikota data
    tosparse()
        Construct a sparse array from Mikota data
    tobanded()
        The format for banded symmetric matrices,
        i.e., (1, n) ndarray with the main diagonal.
    c                 h    || _         || _        t                                          ||           d S r   )r   r   r   r   )r   r   r   r   s      r   r   zMikotaM.__init__  s1    

&&&&&r   c                 ~    dt          j        d| j        d         dz             z                      | j                  S )Nr6   r   r   )r   r9   r   rg   r   r   s    r   _diagzMikotaM._diag  s6     RYq$*Q-!"3444<<TZHHHr   c                 *    |                                  S r   )r   r   s    r   r   zMikotaM.tobanded  s    zz||r   c                 h    ddl m}  ||                                 gdg| j        | j                  S )Nr   r   r   )r   r   r   r   r   r   r   s     r   ry   zMikotaM.tosparse  sF    ,,,,,,{DJJLL>A3!%4:? ? ? 	?r   c                 ~    t          j        |                                                               | j                  S r   )r   diagr   rg   r   r   s    r   ro   zMikotaM.toarray  s*    wtzz||$$++DJ777r   c                     |                     | j        d         d          }|                                 ddt          j        f         |z  S )z
        Construct matrix-free callable banded-matrix-vector multiplication by
        the Mikota mass matrix without constructing or storing the matrix itself
        using the knowledge of its entries and the diagonal format.
        r   r8   N)rf   r   r   r   newaxisr   s     r   r   zMikotaM._matvec  s?     IIdjmR((zz||AAArzM*Q..r   c                 ,    |                      |          S )z
        Construct matrix-free callable matrix-matrix multiplication by
        the Mikota mass matrix without constructing or storing the matrix itself
        by reusing the ``_matvec(x)`` that supports both 1D and 2D arrays ``x``.
        r   r   s     r   r   zMikotaM._matmat  r   r   c                     | S r   rG   r   s    r   r   zMikotaM._adjoint  r   r   c                     | S r   rG   r   s    r   r   zMikotaM._transpose  r   r   )r   r   r   r   r   r@   r   r   r   ry   ro   r   r   r   r   r   r   s   @r   r   r     s         . %'J ' ' ' ' ' '
I I I
  ? ? ?
8 8 8/ / /          r   r   c                   Z     e Zd ZdZej        f fd	Zd Zd Zd Z	d Z
d Zd Zd	 Z xZS )
MikotaKa  
    Construct a stiffness matrix in various formats of Mikota pair.

    The stiffness matrix `K` is square real tri-diagonal symmetric
    positive definite with integer entries.

    Parameters
    ----------
    shape : tuple of int
        The shape of the matrix.
    dtype : dtype
        Numerical type of the array. Default is ``np.int32``.

    Methods
    -------
    toarray()
        Construct a dense array from Mikota data
    tosparse()
        Construct a sparse array from Mikota data
    tobanded()
        The format for banded symmetric matrices,
        i.e., (2, n) ndarray with 2 upper diagonals
        placing the main diagonal at the bottom.
    c                    || _         || _        t                                          ||           |d         }t	          j        d|z  dz
  dd| j                  | _        t	          j        |dz
  dd| j                   | _        d S )Nr   r   r   r]   r\   r8   )r   r   r   r   r   r9   _diag0_diag1)r   r   r   r.   r   s       r   r   zMikotaK.__init__  s    

&&& !HiA	1b
CCC	!a%BdjAAAAr   c                 j    t          j        t          j        | j        dd          | j        g          S )Nrr   constant)r   r   r   r   r   r   s    r   r   zMikotaK.tobanded  s)    xVZ@@$+NOOOr   c                 h    ddl m}  || j        | j        | j        gg d| j        | j                  S )Nr   r   rs   r   )r   r   r   r   r   r   r   s     r   ry   zMikotaK.tosparse  sK    ,,,,,,{DKdkBJJJ!%4:? ? ? 	?r   c                 N    |                                                                  S r   r   r   s    r   ro   zMikotaK.toarray   r   r   c                 N   |                     | j        d         d          }t          j        |j        | j                  }t          j        ||          }| j        }| j        }|d         |dddf         z  |d         |dddf         z  z   |dddf<   |d         |dddf         z  |d         |dddf         z  z   |dddf<   |dddf         |ddddf         z  |dddf         |ddddf         z  z   |dddf         |ddddf         z  z   |ddddf<   |S )z
        Construct matrix-free callable banded-matrix-vector multiplication by
        the Mikota stiffness matrix without constructing or storing the matrix
        itself using the knowledge of its entries and the 3-diagonal format.
        r   r8   r\   Nr   r]   r   )rf   r   r   r   r   r   r   r   )r   rT   r   kxr   r   s         r   r   zMikotaK._matvec#  sb    IIdjmR(('<<]1L111[[a51QT7?RUQq!!!tW_41aaa4rFQr111uX%22qqq5(992qqq5	3B39$B$'
2QUD[/AaeQQQhK78QRRX,122qqq5121b5!!!8 	r   c                 ,    |                      |          S )z
        Construct matrix-free callable matrix-matrix multiplication by
        the Stiffness mass matrix without constructing or storing the matrix itself
        by reusing the ``_matvec(x)`` that supports both 1D and 2D arrays ``x``.
        r   r   s     r   r   zMikotaK._matmat5  r   r   c                     | S r   rG   r   s    r   r   zMikotaK._adjoint=  r   r   c                     | S r   rG   r   s    r   r   zMikotaK._transpose@  r   r   )r   r   r   r   r   int32r   r   ry   ro   r   r   r   r   r   r   s   @r   r   r     s         0 %'H B B B B B BP P P? ? ?
) ) )  $          r   r   c                   .    e Zd ZdZej        fdZddZdS )
MikotaPaira  
    Construct the Mikota pair of matrices in various formats and
    eigenvalues of the generalized eigenproblem with them.

    The Mikota pair of matrices [1, 2]_ models a vibration problem
    of a linear mass-spring system with the ends attached where
    the stiffness of the springs and the masses increase along
    the system length such that vibration frequencies are subsequent
    integers 1, 2, ..., `n` where `n` is the number of the masses. Thus,
    eigenvalues of the generalized eigenvalue problem for
    the matrix pair `K` and `M` where `K` is the system stiffness matrix
    and `M` is the system mass matrix are the squares of the integers,
    i.e., 1, 4, 9, ..., ``n * n``.

    The stiffness matrix `K` is square real tri-diagonal symmetric
    positive definite. The mass matrix `M` is diagonal with diagonal
    entries 1, 1/2, 1/3, ...., ``1/n``. Both matrices get
    ill-conditioned with `n` growing.

    Parameters
    ----------
    n : int
        The size of the matrices of the Mikota pair.
    dtype : dtype
        Numerical type of the array. Default is ``np.float64``.

    Attributes
    ----------
    eigenvalues : 1D ndarray, ``np.uint64``
        All eigenvalues of the Mikota pair ordered ascending.

    Methods
    -------
    MikotaK()
        A `LinearOperator` custom object for the stiffness matrix.
    MikotaM()
        A `LinearOperator` custom object for the mass matrix.

    .. versionadded:: 1.12.0

    References
    ----------
    .. [1] J. Mikota, "Frequency tuning of chain structure multibody oscillators
       to place the natural frequencies at omega1 and N-1 integer multiples
       omega2,..., omegaN", Z. Angew. Math. Mech. 81 (2001), S2, S201-S202.
       Appl. Num. Anal. Comp. Math. Vol. 1 No. 2 (2004).
    .. [2] Peter C. Muller and Metin Gurgoze,
       "Natural frequencies of a multi-degree-of-freedom vibration system",
       Proc. Appl. Math. Mech. 6, 319-320 (2006).
       http://dx.doi.org/10.1002/pamm.200610141.

    Examples
    --------
    >>> import numpy as np
    >>> from scipy.sparse.linalg._special_sparse_arrays import MikotaPair
    >>> n = 6
    >>> mik = MikotaPair(n)
    >>> mik_k = mik.k
    >>> mik_m = mik.m
    >>> mik_k.toarray()
    array([[11., -5.,  0.,  0.,  0.,  0.],
           [-5.,  9., -4.,  0.,  0.,  0.],
           [ 0., -4.,  7., -3.,  0.,  0.],
           [ 0.,  0., -3.,  5., -2.,  0.],
           [ 0.,  0.,  0., -2.,  3., -1.],
           [ 0.,  0.,  0.,  0., -1.,  1.]])
    >>> mik_k.tobanded()
    array([[ 0., -5., -4., -3., -2., -1.],
           [11.,  9.,  7.,  5.,  3.,  1.]])
    >>> mik_m.tobanded()
    array([1.        , 0.5       , 0.33333333, 0.25      , 0.2       ,
        0.16666667])
    >>> mik_k.tosparse()
    <DIAgonal sparse array of dtype 'float64'
        with 16 stored elements (3 diagonals) and shape (6, 6)>
    >>> mik_m.tosparse()
    <DIAgonal sparse array of dtype 'float64'
        with 6 stored elements (1 diagonals) and shape (6, 6)>
    >>> np.array_equal(mik_k(np.eye(n)), mik_k.toarray())
    True
    >>> np.array_equal(mik_m(np.eye(n)), mik_m.toarray())
    True
    >>> mik.eigenvalues()
    array([ 1,  4,  9, 16, 25, 36])
    >>> mik.eigenvalues(2)
    array([ 1,  4])

    c                     || _         || _        ||f| _        t          | j        | j                  | _        t          | j        | j                  | _        d S r   )r.   r   r   r   r*   r   rM   )r   r.   r   s      r   r   zMikotaPair.__init__  sI    
V
TZ00TZ00r   Nc                 f    || j         }t          j        d|dz   t          j                  }||z  S )a  Return the requested number of eigenvalues.

        Parameters
        ----------
        m : int, optional
            The positive number of smallest eigenvalues to return.
            If not provided, then all eigenvalues will be returned.

        Returns
        -------
        eigenvalues : `np.uint64` array
            The requested `m` smallest or all eigenvalues, in ascending order.
        Nr   r\   )r.   r   r9   uint64)r   r*   arange_plus1s      r   r1   zMikotaPair.eigenvalues  s7     9AyAE;;;l**r   r   )r   r   r   r   r   r@   r   r1   rG   r   r   r   r   D  sP        W Wp !#
 1 1 1 1+ + + + + +r   r   )numpyr   scipy.sparse.linalgr   r   r   r   r   __all__r   r   r   r   r   rG   r   r   <module>r      sP       . . . . . . 3 3 3 3 3 3 3 3 3 3/
y y y y y. y y yxg g g g gn g g gTB B B B Bn B B BJL L L L Ln L L L^q+ q+ q+ q+ q+ q+ q+ q+ q+ q+r   