o
    oh@l                     @   s   d Z ddlmZ ddlmZ ddlmZ ddlmZm	Z	m
Z
mZ ddlmZ ddlmZmZmZmZmZmZmZmZmZmZmZmZmZmZ dd	lmZmZ ed
krVddgZ G dd de!Z"ddl#m$Z$ ddl%m&Z& dS )a  

Module for the DDM class.

The DDM class is an internal representation used by DomainMatrix. The letters
DDM stand for Dense Domain Matrix. A DDM instance represents a matrix using
elements from a polynomial Domain (e.g. ZZ, QQ, ...) in a dense-matrix
representation.

Basic usage:

    >>> from sympy import ZZ, QQ
    >>> from sympy.polys.matrices.ddm import DDM
    >>> A = DDM([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ)
    >>> A.shape
    (2, 2)
    >>> A
    [[0, 1], [-1, 0]]
    >>> type(A)
    <class 'sympy.polys.matrices.ddm.DDM'>
    >>> A @ A
    [[-1, 0], [0, -1]]

The ddm_* functions are designed to operate on DDM as well as on an ordinary
list of lists:

    >>> from sympy.polys.matrices.dense import ddm_idet
    >>> ddm_idet(A, QQ)
    1
    >>> ddm_idet([[0, 1], [-1, 0]], QQ)
    1
    >>> A
    [[-1, 0], [0, -1]]

Note that ddm_idet modifies the input matrix in-place. It is recommended to
use the DDM.det method as a friendlier interface to this instead which takes
care of copying the matrix:

    >>> B = DDM([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ)
    >>> B.det()
    1

Normally DDM would not be used directly and is just part of the internal
representation of DomainMatrix which adds further functionality including e.g.
unifying domains.

The dense format used by DDM is a list of lists of elements e.g. the 2x2
identity matrix is like [[1, 0], [0, 1]]. The DDM class itself is a subclass
of list and its list items are plain lists. Elements are accessed as e.g.
ddm[i][j] where ddm[i] gives the ith row and ddm[i][j] gets the element in the
jth column of that row. Subclassing list makes e.g. iteration and indexing
very efficient. We do not override __getitem__ because it would lose that
benefit.

The core routines are implemented by the ddm_* functions defined in dense.py.
Those functions are intended to be able to operate on a raw list-of-lists
representation of matrices with most functions operating in-place. The DDM
class takes care of copying etc and also stores a Domain object associated
with its elements. This makes it possible to implement things like A + B with
domain checking and also shape checking so that the list of lists
representation is friendlier.

    )chain)GROUND_TYPES)doctest_depends_on   )DMBadInputErrorDMDomainErrorDMNonSquareMatrixErrorDMShapeError)QQ)ddm_transposeddm_iaddddm_isubddm_inegddm_imul	ddm_irmulddm_imatmul	ddm_irrefddm_irref_denddm_idetddm_iinvddm_ilu_splitddm_ilu_solveddm_berk)ddm_lllddm_lll_transformflint
DDM.to_dfmDDM.to_dfm_or_ddmc                       s  e Zd ZdZdZdZdZ fddZdd Zd	d
 Z	dd Z
dd Zedd Zedd Zdd Zdd Zedd Zdd Zdd Zdd Zedd  Zd!d" Zed#d$ Zd%d& Zed'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zed1gd2d3d4 Zed1gd2d5d6 Z d7d8 Z!d9d: Z"d;d< Z# fd=d>Z$d?d@ Z%edAdB Z&edCdD Z'edEdF Z(dGdH Z)dIdJ Z*dKdL Z+dMdN Z,dOdP Z-dQdR Z.dSdT Z/dUdV Z0edWdX Z1dYdZ Z2d[d\ Z3d]d^ Z4d_d` Z5dadb Z6dcdd Z7dedf Z8dgdh Z9didj Z:dkdl Z;dmdn Z<dodp Z=edqdr Z>dsdt Z?dudv Z@dwdx ZAddzd{ZBd|d} ZCd~d ZDdd ZEdd ZFdd ZGdd ZHdd ZIdd ZJdd ZKdd ZLdd ZMeNddfddZOeNddfddZP  ZQS )DDMzDense matrix based on polys domain elements

    This is a list subclass and is a wrapper for a list of lists that supports
    basic matrix arithmetic +, -, *, **.
    denseFTc                    s   t |trtdd |D std|\} t||ks't fdd|D r+tdt | | f| _|| _	 | _
|| _d S )Nc                 s   s    | ]	}t |tu V  qd S N)typelist.0row r&   l/var/www/html/construction_image-detection-poc/venv/lib/python3.10/site-packages/sympy/polys/matrices/ddm.py	<genexpr>r       zDDM.__init__.<locals>.<genexpr>z rowslist must be a list of listsc                 3   s    | ]	}t | kV  qd S r    )lenr#   nr&   r'   r(   u   r)   zInconsistent row-list/shape)
isinstancer"   allr   r*   anysuper__init__shaperowscolsdomain)selfrowslistr2   r5   m	__class__r+   r'   r1   q   s   "

zDDM.__init__c                 C   s   | | | S r    r&   )r6   ijr&   r&   r'   getitem~      zDDM.getitemc                 C   s   || | |< d S r    r&   )r6   r;   r<   valuer&   r&   r'   setitem      zDDM.setitemc                    sV    fdd| | D }t |}|rt |d n
t t| jd   }t|||f| jS )Nc                    s   g | ]}|  qS r&   r&   r#   slice2r&   r'   
<listcomp>       z%DDM.extract_slice.<locals>.<listcomp>r   r   )r*   ranger2   r   r5   )r6   slice1rC   ddmr3   r4   r&   rB   r'   extract_slice   s   &zDDM.extract_slicec                    sH   g }|D ]}| |  |  fdd|D  qt|t|t|f| jS )Nc                    s   g | ]} | qS r&   r&   r$   r<   rowir&   r'   rD      rE   zDDM.extract.<locals>.<listcomp>)appendr   r*   r5   )r6   r3   r4   rH   r;   r&   rK   r'   extract   s
   zDDM.extractc                 C   s   | |||S )a  
        Create a :class:`DDM` from a list of lists.

        Examples
        ========

        >>> from sympy import ZZ
        >>> from sympy.polys.matrices.ddm import DDM
        >>> A = DDM.from_list([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ)
        >>> A
        [[0, 1], [-1, 0]]
        >>> A == DDM([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ)
        True

        See Also
        ========

        from_list_flat
        r&   )clsr7   r2   r5   r&   r&   r'   	from_list   s   zDDM.from_listc                 C   s   |  S r    )copy)rO   otherr&   r&   r'   from_ddm   s   zDDM.from_ddmc                 C   s   t | S )a  
        Convert to a list of lists.

        Examples
        ========

        >>> from sympy import QQ
        >>> from sympy.polys.matrices.ddm import DDM
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> A.to_list()
        [[1, 2], [3, 4]]

        See Also
        ========

        to_list_flat
        sympy.polys.matrices.domainmatrix.DomainMatrix.to_list
        )r"   r6   r&   r&   r'   to_list   s   zDDM.to_listc                 C      g }| D ]}| | q|S )a  
        Convert to a flat list of elements.

        Examples
        ========

        >>> from sympy import QQ
        >>> from sympy.polys.matrices.ddm import DDM
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> A.to_list_flat()
        [1, 2, 3, 4]
        >>> A == DDM.from_list_flat(A.to_list_flat(), A.shape, A.domain)
        True

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.to_list_flat
        extend)r6   flatr%   r&   r&   r'   to_list_flat   s   zDDM.to_list_flatc                    sT   t tu sJ |\} t|  kstd fddt|D }| |||S )a  
        Create a :class:`DDM` from a flat list of elements.

        Examples
        ========

        >>> from sympy import QQ
        >>> from sympy.polys.matrices.ddm import DDM
        >>> A = DDM.from_list_flat([1, 2, 3, 4], (2, 2), QQ)
        >>> A
        [[1, 2], [3, 4]]
        >>> A == DDM.from_list_flat(A.to_list_flat(), A.shape, A.domain)
        True

        See Also
        ========

        to_list_flat
        sympy.polys.matrices.domainmatrix.DomainMatrix.from_list_flat
        zInconsistent flat-list shapec                    s$   g | ]}|  |d     qS )r   r&   r$   r;   r4   rY   r&   r'   rD         $ z&DDM.from_list_flat.<locals>.<listcomp>)r!   r"   r*   r   rF   )rO   rY   r2   r5   r3   lolr&   r\   r'   from_list_flat   s   zDDM.from_list_flatc                 C   s
   t | S r    )r   from_iterablerT   r&   r&   r'   flatiter   s   
zDDM.flatiterc                 C   rV   r    rW   )r6   itemsr%   r&   r&   r'   rY      s   zDDM.flatc                 C      |    S )a@  
        Convert to a flat list of nonzero elements and data.

        Explanation
        ===========

        This is used to operate on a list of the elements of a matrix and then
        reconstruct a matrix using :meth:`from_flat_nz`. Zero elements are
        included in the list but that may change in the future.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> elements, data = A.to_flat_nz()
        >>> elements
        [1, 2, 3, 4]
        >>> A == DDM.from_flat_nz(elements, data, A.domain)
        True

        See Also
        ========

        from_flat_nz
        sympy.polys.matrices.sdm.SDM.to_flat_nz
        sympy.polys.matrices.domainmatrix.DomainMatrix.to_flat_nz
        )to_sdm
to_flat_nzrT   r&   r&   r'   re      s   zDDM.to_flat_nzc                 C   s   t ||| S )aF  
        Reconstruct a :class:`DDM` after calling :meth:`to_flat_nz`.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> elements, data = A.to_flat_nz()
        >>> elements
        [1, 2, 3, 4]
        >>> A == DDM.from_flat_nz(elements, data, A.domain)
        True

        See Also
        ========

        to_flat_nz
        sympy.polys.matrices.sdm.SDM.from_flat_nz
        sympy.polys.matrices.domainmatrix.DomainMatrix.from_flat_nz
        )SDMfrom_flat_nzto_ddm)rO   elementsdatar5   r&   r&   r'   rg      s   zDDM.from_flat_nzc                 C   s8   i }t | D ]\}}dd t |D }|r|||< q|S )a  
        Convert to a dictionary of dictionaries (dod) format.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> A.to_dod()
        {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}

        See Also
        ========

        from_dod
        sympy.polys.matrices.sdm.SDM.to_dod
        sympy.polys.matrices.domainmatrix.DomainMatrix.to_dod
        c                 S   s   i | ]	\}}|r||qS r&   r&   )r$   r<   er&   r&   r'   
<dictcomp>P      zDDM.to_dod.<locals>.<dictcomp>	enumerate)r6   dodr;   r%   r&   r&   r'   to_dod:  s   z
DDM.to_dodc           
         s\   |\}  fddt |D }| D ]\}}| D ]
\}}	|	|| |< qqt||S )a  
        Create a :class:`DDM` from a dictionary of dictionaries (dod) format.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> dod = {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}
        >>> A = DDM.from_dod(dod, (2, 2), QQ)
        >>> A
        [[1, 2], [3, 4]]

        See Also
        ========

        to_dod
        sympy.polys.matrices.sdm.SDM.from_dod
        sympy.polys.matrices.domainmatrix.DomainMatrix.from_dod
        c                       g | ]}j g  qS r&   zeror$   _r4   r5   r&   r'   rD   l      z DDM.from_dod.<locals>.<listcomp>rF   rb   r   )
rO   rp   r2   r5   r3   r^   r;   r%   r<   elementr&   rw   r'   from_dodU  s   zDDM.from_dodc                 C   s<   i }t | D ]\}}t |D ]\}}|r||||f< qq|S )a  
        Convert :class:`DDM` to dictionary of keys (dok) format.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> A.to_dok()
        {(0, 0): 1, (0, 1): 2, (1, 0): 3, (1, 1): 4}

        See Also
        ========

        from_dok
        sympy.polys.matrices.sdm.SDM.to_dok
        sympy.polys.matrices.domainmatrix.DomainMatrix.to_dok
        rn   )r6   dokr;   r%   r<   rz   r&   r&   r'   to_dokr  s   z
DDM.to_dokc           	         sN   |\}  fddt |D }| D ]\\}}}||| |< qt||S )a  
        Create a :class:`DDM` from a dictionary of keys (dok) format.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> dok = {(0, 0): 1, (0, 1): 2, (1, 0): 3, (1, 1): 4}
        >>> A = DDM.from_dok(dok, (2, 2), QQ)
        >>> A
        [[1, 2], [3, 4]]

        See Also
        ========

        to_dok
        sympy.polys.matrices.sdm.SDM.from_dok
        sympy.polys.matrices.domainmatrix.DomainMatrix.from_dok
        c                    rr   r&   rs   ru   rw   r&   r'   rD     rx   z DDM.from_dok.<locals>.<listcomp>ry   )	rO   r|   r2   r5   r3   r^   r;   r<   rz   r&   rw   r'   from_dok  s
   zDDM.from_dokc                 c   s     | D ]
}t d|E dH  qdS )a  
        Iterater over the non-zero values of the matrix.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[QQ(1), QQ(0)], [QQ(3), QQ(4)]], (2, 2), QQ)
        >>> list(A.iter_values())
        [1, 3, 4]

        See Also
        ========

        iter_items
        to_list_flat
        sympy.polys.matrices.domainmatrix.DomainMatrix.iter_values
        N)filter)r6   r%   r&   r&   r'   iter_values  s   zDDM.iter_valuesc                 c   s<    t | D ]\}}t |D ]\}}|r||f|fV  qqdS )a  
        Iterate over indices and values of nonzero elements of the matrix.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[QQ(1), QQ(0)], [QQ(3), QQ(4)]], (2, 2), QQ)
        >>> list(A.iter_items())
        [((0, 0), 1), ((1, 0), 3), ((1, 1), 4)]

        See Also
        ========

        iter_values
        to_dok
        sympy.polys.matrices.domainmatrix.DomainMatrix.iter_items
        Nrn   )r6   r;   r%   r<   rz   r&   r&   r'   
iter_items  s   zDDM.iter_itemsc                 C   s   | S )au  
        Convert to a :class:`DDM`.

        This just returns ``self`` but exists to parallel the corresponding
        method in other matrix types like :class:`~.SDM`.

        See Also
        ========

        to_sdm
        to_dfm
        to_dfm_or_ddm
        sympy.polys.matrices.sdm.SDM.to_ddm
        sympy.polys.matrices.domainmatrix.DomainMatrix.to_ddm
        r&   rT   r&   r&   r'   rh     s   z
DDM.to_ddmc                 C   s   t | | j| jS )a  
        Convert to a :class:`~.SDM`.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> A.to_sdm()
        {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}
        >>> type(A.to_sdm())
        <class 'sympy.polys.matrices.sdm.SDM'>

        See Also
        ========

        SDM
        sympy.polys.matrices.sdm.SDM.to_ddm
        )rf   rP   r2   r5   rT   r&   r&   r'   rd     s   z
DDM.to_sdmr   )ground_typesc                 C   s   t t| | j| jS )a  
        Convert to :class:`~.DDM` to :class:`~.DFM`.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> A.to_dfm()
        [[1, 2], [3, 4]]
        >>> type(A.to_dfm())
        <class 'sympy.polys.matrices._dfm.DFM'>

        See Also
        ========

        DFM
        sympy.polys.matrices._dfm.DFM.to_ddm
        )DFMr"   r2   r5   rT   r&   r&   r'   to_dfm  s   r   c                 C   s   t | jr
|  S | S )a  
        Convert to :class:`~.DFM` if possible or otherwise return self.

        Examples
        ========

        >>> from sympy.polys.matrices.ddm import DDM
        >>> from sympy import QQ
        >>> A = DDM([[1, 2], [3, 4]], (2, 2), QQ)
        >>> A.to_dfm_or_ddm()
        [[1, 2], [3, 4]]
        >>> type(A.to_dfm_or_ddm())
        <class 'sympy.polys.matrices._dfm.DFM'>

        See Also
        ========

        to_dfm
        to_ddm
        sympy.polys.matrices.domainmatrix.DomainMatrix.to_dfm_or_ddm
        )r   _supports_domainr5   r   rT   r&   r&   r'   to_dfm_or_ddm  s   r   c                    s8   | j  kr|  S  fdd| D }t|| j S )Nc                    s    g | ]} fd d|D qS )c                    s   g | ]}  |qS r&   )convert_from)r$   rk   KKoldr&   r'   rD   9  rx   z-DDM.convert_to.<locals>.<listcomp>.<listcomp>r&   r#   r   r&   r'   rD   9       z"DDM.convert_to.<locals>.<listcomp>)r5   rQ   r   r2   )r6   r   r3   r&   r   r'   
convert_to5  s
   zDDM.convert_toc                 C   s   dd | D }dd | S )Nc                 S   s    g | ]}d d tt| qS )[%s], )joinmapstrr#   r&   r&   r'   rD   =  r   zDDM.__str__.<locals>.<listcomp>r   r   )r   )r6   rowsstrr&   r&   r'   __str__<  s   zDDM.__str__c                 C   s(   t | j}t| }d||| j| jf S )Nz%s(%s, %s, %s))r!   __name__r"   __repr__r2   r5   )r6   rO   r3   r&   r&   r'   r   @  s   

zDDM.__repr__c                    s&   t |tsdS t |o| j|jkS )NF)r-   r   r0   __eq__r5   r6   rR   r9   r&   r'   r   E  s   
z
DDM.__eq__c                 C   s   |  | S r    )r   r   r&   r&   r'   __ne__J  r>   z
DDM.__ne__c                    2   |j |\}  fddt|D }t|||S )Nc                       g | ]}g  qS r&   r&   ru   r,   zr&   r'   rD   Q      zDDM.zeros.<locals>.<listcomp>)rt   rF   r   )rO   r2   r5   r8   r7   r&   r   r'   zerosM     z	DDM.zerosc                    r   )Nc                    r   r&   r&   ru   r,   oner&   r'   rD   X  r   zDDM.ones.<locals>.<listcomp>)r   rF   r   )rO   r2   r5   r8   rowlistr&   r   r'   onesT  r   zDDM.onesc                 C   s`   t |tr
|\}}n	t |tr| }}|j}| ||f|}tt||D ]}||| |< q%|S r    )r-   tupleintr   r   rF   min)rO   sizer5   r8   r,   r   rH   r;   r&   r&   r'   eye[  s   


zDDM.eyec                 C   s   dd | D }t || j| jS )Nc                 S   s   g | ]}|d d  qS r    r&   r#   r&   r&   r'   rD   h  rx   zDDM.copy.<locals>.<listcomp>)r   r2   r5   )r6   copyrowsr&   r&   r'   rQ   g  s   zDDM.copyc                 C   s4   | j \}}|rt| }ng g| }t|||f| jS r    )r2   r   r   r5   )r6   r3   r4   ddmTr&   r&   r'   	transposek  s
   


zDDM.transposec                 C      t |tstS | |S r    )r-   r   NotImplementedaddabr&   r&   r'   __add__s     

zDDM.__add__c                 C   r   r    )r-   r   r   subr   r&   r&   r'   __sub__x  r   zDDM.__sub__c                 C   s   |   S r    )negr   r&   r&   r'   __neg__}  s   zDDM.__neg__c                 C      || j v r
| |S tS r    r5   mulr   r   r&   r&   r'   __mul__     

zDDM.__mul__c                 C   r   r    r   r   r&   r&   r'   __rmul__  r   zDDM.__rmul__c                 C   s   t |tr
| |S tS r    )r-   r   matmulr   r   r&   r&   r'   
__matmul__  r   zDDM.__matmul__c                 C   sL   |j |j krd|j ||j f }t|||kr$d|j||jf }t|d S )NzDomain mismatch: %s %s %szShape mismatch: %s %s %s)r5   r   r2   r	   )rO   r   opr   ashapebshapemsgr&   r&   r'   _check  s   z
DDM._checkc                 C   ,   |  | d|| j|j |  }t|| |S )za + b+)r   r2   rQ   r   r   r   cr&   r&   r'   r        
zDDM.addc                 C   r   )za - b-)r   r2   rQ   r   r   r&   r&   r'   r     r   zDDM.subc                 C   s   |   }t| |S )z-a)rQ   r   r   r&   r&   r'   r     s   zDDM.negc                 C      |   }t|| |S r    )rQ   r   r   r&   r&   r'   r        
zDDM.mulc                 C   r   r    )rQ   r   r   r&   r&   r'   rmul  r   zDDM.rmulc                 C   sH   | j \}}|j \}}| | d||| | ||f| j}t|| | |S )za @ b (matrix product)*)r2   r   r   r5   r   )r   r   r8   oo2r,   r   r&   r&   r'   r     s   

z
DDM.matmulc                 C   sD   | j |j ksJ | j|jksJ dd t| |D }t|| j | jS )Nc                 S   s$   g | ]\}}d d t ||D qS )c                 S   s   g | ]\}}|| qS r&   r&   )r$   aijbijr&   r&   r'   rD     rx   z2DDM.mul_elementwise.<locals>.<listcomp>.<listcomp>)zip)r$   aibir&   r&   r'   rD     r]   z'DDM.mul_elementwise.<locals>.<listcomp>)r2   r5   r   r   r   r&   r&   r'   mul_elementwise  s   zDDM.mul_elementwisec                 G   s   t |  }| j\}}| j}|D ](}|j\}}||ksJ |j|ks$J ||7 }t|D ]\}	}
||	 |
 q,qt|||f| jS )a	  Horizontally stacks :py:class:`~.DDM` matrices.

        Examples
        ========

        >>> from sympy import ZZ
        >>> from sympy.polys.matrices.sdm import DDM

        >>> A = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
        >>> B = DDM([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ)
        >>> A.hstack(B)
        [[1, 2, 5, 6], [3, 4, 7, 8]]

        >>> C = DDM([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ)
        >>> A.hstack(B, C)
        [[1, 2, 5, 6, 9, 10], [3, 4, 7, 8, 11, 12]]
        )r"   rQ   r2   r5   ro   rX   r   )ABAnewr3   r4   r5   BkBkrowsBkcolsr;   Bkir&   r&   r'   hstack  s   

z
DDM.hstackc           	      G   sr   t |  }| j\}}| j}|D ]}|j\}}||ksJ |j|ks$J ||7 }||  qt|||f| jS )a  Vertically stacks :py:class:`~.DDM` matrices.

        Examples
        ========

        >>> from sympy import ZZ
        >>> from sympy.polys.matrices.sdm import DDM

        >>> A = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
        >>> B = DDM([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ)
        >>> A.vstack(B)
        [[1, 2], [3, 4], [5, 6], [7, 8]]

        >>> C = DDM([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ)
        >>> A.vstack(B, C)
        [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]]
        )r"   rQ   r2   r5   rX   r   )	r   r   r   r3   r4   r5   r   r   r   r&   r&   r'   vstack  s   

z
DDM.vstackc                    s     fdd| D }t || j|S )Nc                    s   g | ]	}t t |qS r&   )r"   r   r#   funcr&   r'   rD     rm   z!DDM.applyfunc.<locals>.<listcomp>)r   r2   )r6   r   r5   ri   r&   r   r'   	applyfunc  s   zDDM.applyfuncc                 C   s   t dd | D S )zNumber of non-zero entries in :py:class:`~.DDM` matrix.

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.nnz
        c                 s   s    | ]
}t tt|V  qd S r    )sumr   boolr#   r&   r&   r'   r(     s    zDDM.nnz.<locals>.<genexpr>)r   r   r&   r&   r'   nnz  s   zDDM.nnzc                 C   rc   )a  Strongly connected components of a square matrix *a*.

        Examples
        ========

        >>> from sympy import ZZ
        >>> from sympy.polys.matrices.sdm import DDM
        >>> A = DDM([[ZZ(1), ZZ(0)], [ZZ(0), ZZ(1)]], (2, 2), ZZ)
        >>> A.scc()
        [[0], [1]]

        See also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.scc

        )rd   sccr   r&   r&   r'   r     s   zDDM.sccc                 C   s   t || S )a|  Returns a square diagonal matrix with *values* on the diagonal.

        Examples
        ========

        >>> from sympy import ZZ
        >>> from sympy.polys.matrices.sdm import DDM
        >>> DDM.diag([ZZ(1), ZZ(2), ZZ(3)], ZZ)
        [[1, 0, 0], [0, 2, 0], [0, 0, 3]]

        See also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.diag
        )rf   diagrh   )rO   valuesr5   r&   r&   r'   r   -  s   zDDM.diagc                 C   s.   |   }| j}|jp|j}t||d}||fS )a"  Reduced-row echelon form of a and list of pivots.

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.rref
            Higher level interface to this function.
        sympy.polys.matrices.dense.ddm_irref
            The underlying algorithm.
        )_partial_pivot)rQ   r5   is_RealFieldis_ComplexFieldr   )r   r   r   partial_pivotpivotsr&   r&   r'   rref@  s
   zDDM.rrefc                 C   s&   |   }| j}t||\}}|||fS )a:  Reduced-row echelon form of a with denominator and list of pivots

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.rref_den
            Higher level interface to this function.
        sympy.polys.matrices.dense.ddm_irref_den
            The underlying algorithm.
        )rQ   r5   r   )r   r   r   denomr   r&   r&   r'   rref_denQ  s   
zDDM.rref_denc                 C   s   |   \}}||S )zReturns a basis for the nullspace of a.

        The domain of the matrix must be a field.

        See Also
        ========

        rref
        sympy.polys.matrices.domainmatrix.DomainMatrix.nullspace
        )r   nullspace_from_rref)r   r   r   r&   r&   r'   	nullspacea  s   
zDDM.nullspaceNc                    s$  | j \}}| j |du r2g }d}t|D ]|  }t|d |D ]}|| r0|}||  nq!q|s@| | tt|fS | d |d  g }g }t|D ]3|v rWqP|  fddt|D }	t|D ]\}
}|	|  | |
  8  < qm||	 qPt|t||f }||fS )a9  Compute the nullspace of a matrix from its rref.

        The domain of the matrix can be any domain.

        Returns a tuple (basis, nonpivots).

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.nullspace
            The higher level interface to this function.
        Nr   r   c                    s   g | ]}|kr
n j qS r&   rs   rJ   r   r;   	pivot_valr&   r'   rD     s    z+DDM.nullspace_from_rref.<locals>.<listcomp>)	r2   r5   rF   rM   r   r"   ro   r   r*   )r   r   r8   r,   
last_pivotr   r<   basis	nonpivotsveciijj	basis_ddmr&   r   r'   r   o  s:   


zDDM.nullspace_from_rrefc                 C   s   |     S r    )rd   
particularrh   r   r&   r&   r'   r     rA   zDDM.particularc                 C   s6   | j \}}||krtd|  }|j}t||}|S )zDeterminant of a Determinant of non-square matrix)r2   r   rQ   r5   r   )r   r8   r,   r   r   detar&   r&   r'   det  s   

zDDM.detc                 C   s8   | j \}}||krtd|  }| j}t|| | |S )zInverse of ar   )r2   r   rQ   r5   r   )r   r8   r,   ainvr   r&   r&   r'   inv  s   
zDDM.invc                 C   s:   | j \}}| j}|  }| ||}t|||}|||fS )zL, U decomposition of a)r2   r5   rQ   r   r   )r   r8   r,   r   ULswapsr&   r&   r'   lu  s   

zDDM.luc           
      C   sj   | j \}}|j \}}| | d||| | jjstd|  \}}}| ||f| j}	t|	|||| |	S )zx where a*x = blu_solvezlu_solve requires a field)r2   r   r5   is_Fieldr   r  r   r   )
r   r   r8   r,   m2r   r  r  r  xr&   r&   r'   r    s   

zDDM.lu_solvec                    sH   | j }| j\}}||krtdt| |  fddt|d D }|S )z.Coefficients of characteristic polynomial of azCharpoly of non-square matrixc                    s   g | ]} | d  qS )r   r&   r[   r   r&   r'   rD     rx   z DDM.charpoly.<locals>.<listcomp>r   )r5   r2   r   r   rF   )r   r   r8   r,   coeffsr&   r  r'   charpoly  s   

zDDM.charpolyc                    s"   | j j t fdd|  D S )z@
        Says whether this matrix has all zero entries.
        c                 3   s    | ]}| kV  qd S r    r&   )r$   Mijrs   r&   r'   r(     s    z%DDM.is_zero_matrix.<locals>.<genexpr>)r5   rt   r.   ra   rT   r&   rs   r'   is_zero_matrix  s   zDDM.is_zero_matrixc                    "   | j j t fddt| D S )z~
        Says whether this matrix is upper-triangular. True can be returned
        even if the matrix is not square.
        c                 3   s.    | ]\}}|d | D ]}| kV  qqd S r    r&   r$   r;   Mir  rs   r&   r'   r(     s   , zDDM.is_upper.<locals>.<genexpr>r5   rt   r.   ro   rT   r&   rs   r'   is_upper     zDDM.is_upperc                    r  )z~
        Says whether this matrix is lower-triangular. True can be returned
        even if the matrix is not square.
        c                 3   s2    | ]\}}||d  d D ]}| kV  qqdS )r   Nr&   r  rs   r&   r'   r(     s   0 zDDM.is_lower.<locals>.<genexpr>r  rT   r&   rs   r'   is_lower  r  zDDM.is_lowerc                 C   s   |   o|  S )zv
        Says whether this matrix is diagonal. True can be returned even if
        the matrix is not square.
        )r  r  rT   r&   r&   r'   is_diagonal  s   zDDM.is_diagonalc                    s&    j \}} fddtt||D S )zQ
        Returns a list of the elements from the diagonal of the matrix.
        c                    s   g | ]} | | qS r&   r&   r[   rT   r&   r'   rD     rx   z DDM.diagonal.<locals>.<listcomp>)r2   rF   r   )r6   r8   r,   r&   rT   r'   diagonal  s   
zDDM.diagonal      c                 C      t | |dS N)delta)r   r   r  r&   r&   r'   lll  r>   zDDM.lllc                 C   r  r  )r   r  r&   r&   r'   lll_transform   r>   zDDM.lll_transformr    )Rr   
__module____qualname____doc__fmtis_DFMis_DDMr1   r=   r@   rI   rN   classmethodrP   rS   rU   rZ   r_   ra   rY   re   rg   rq   r{   r}   r~   r   r   rh   rd   r   r   r   r   r   r   r   r   r   r   r   rQ   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r  r  r  r  r
   r   r!  __classcell__r&   r&   r9   r'   r   f   s    


 










	"!


0


r   )rf   )r   N)'r$  	itertoolsr   sympy.external.gmpyr   sympy.utilities.decoratorr   
exceptionsr   r   r   r	   sympy.polys.domainsr
   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   __doctest_skip__r"   r   sdmrf   dfmr   r&   r&   r&   r'   <module>   s(    ?@       %