U
    ZÊ¹jly  ã                   @   sª   d dl mZ d dlmZ d dlmZ d dlmZmZ ddl	m
Z
mZmZmZmZmZmZ edkrfdgZedƒZd	gZedgd
�G dd	„ d	ƒƒZd dlmZ d dlmZ dS )é    )ÚGROUND_TYPES)Úimport_module)Údoctest_depends_on©ÚZZÚQQé   )ÚDMBadInputErrorÚDMDomainErrorÚDMNonSquareMatrixErrorÚDMNonInvertibleMatrixErrorÚDMRankErrorÚDMShapeErrorÚDMValueErrorÚflintÚ*ÚDFM©Zground_typesc                   @   s¼  e Zd ZdZdZdZdZdd„ Zedd„ ƒZ	d	d
„ Z
edd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZdd„ Zdd„ Zdd„ Zedd„ ƒZdd„ Z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/d0„ ƒZd1d2„ Zed3d4„ ƒZ d5d6„ Z!ed7d8„ ƒZ"d9d:„ Z#d;d<„ Z$d=d>„ Z%d?d@„ Z&dAdB„ Z'dCdD„ Z(dEdF„ Z)dGdH„ Z*dIdJ„ Z+dKdL„ Z,dMdN„ Z-dOdP„ Z.dQdR„ Z/dSdT„ Z0dUdV„ Z1dWdX„ Z2edYdZ„ ƒZ3ed[d\„ ƒZ4ed]d^„ ƒZ5ed_d`„ ƒZ6dadb„ Z7dcdd„ Z8dedf„ Z9dgdh„ Z:didj„ Z;dkdl„ Z<dmdn„ Z=dodp„ Z>dqdr„ Z?dsdt„ Z@dudv„ ZAeBdwdx�dydz„ ƒZCeBdwdx�d{d|„ ƒZDeBdwdx�d}d~„ ƒZEdd€„ ZFeBdwdx�d�d‚„ ƒZGdƒd„„ ZHd•d†d‡„ZIdˆd‰„ ZJd–dŽd�„ZKeBdwdx�d—d‘d’„ƒZLeBdwdx�d˜d“d”„ƒZMd…S )™r   a&  
    Dense FLINT matrix. This class is a wrapper for matrices from python-flint.

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.matrices.dfm import DFM
    >>> dfm = DFM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ)
    >>> dfm
    [[1, 2], [3, 4]]
    >>> dfm.rep
    [1, 2]
    [3, 4]
    >>> type(dfm.rep)  # doctest: +SKIP
    <class 'flint._flint.fmpz_mat'>

    Usually, the DFM class is not instantiated directly, but is created as the
    internal representation of :class:`~.DomainMatrix`. When
    `SYMPY_GROUND_TYPES` is set to `flint` and `python-flint` is installed, the
    :class:`DFM` class is used automatically as the internal representation of
    :class:`~.DomainMatrix` in dense format if the domain is supported by
    python-flint.

    >>> from sympy.polys.matrices.domainmatrix import DM
    >>> dM = DM([[1, 2], [3, 4]], ZZ)
    >>> dM.rep
    [[1, 2], [3, 4]]

    A :class:`~.DomainMatrix` can be converted to :class:`DFM` by calling the
    :meth:`to_dfm` method:

    >>> dM.to_dfm()
    [[1, 2], [3, 4]]

    ZdenseTFc              	   C   s^   |   |¡}d|krHz||ƒ}W qP ttfk
rD   td|› �ƒ‚Y qPX n||Ž }|  |||¡S )úConstruct from a nested list.r   z"Input should be a list of list of )Ú_get_flint_funcÚ
ValueErrorÚ	TypeErrorr	   Ú_new)ÚclsÚrowslistÚshapeÚdomainZ	flint_matÚrep© r   úX/var/www/html/bwave/python/venv/lib/python3.8/site-packages/sympy/polys/matrices/_dfm.pyÚ__new__m   s    
zDFM.__new__c                 C   s:   |   |||¡ t | ¡}||_| |_\|_|_||_|S )z)Internal constructor from a flint matrix.)Ú_checkÚobjectr    r   r   ÚrowsÚcolsr   )r   r   r   r   Úobjr   r   r   r   {   s    
zDFM._newc                 C   s   |   || j| j¡S )z>Create a new DFM with the same shape and domain but a new rep.)r   r   r   )Úselfr   r   r   r   Ú_new_rep…   s    zDFM._new_repc                 C   st   |  ¡ | ¡ f}||kr tdƒ‚|tkr>t|tjƒs>tdƒ‚n2|tkr\t|tj	ƒs\tdƒ‚n|ttfkrpt
dƒ‚d S )Nz(Shape of rep does not match shape of DFMzRep is not a flint.fmpz_matzRep is not a flint.fmpq_matú#Only ZZ and QQ are supported by DFM)ZnrowsZncolsr	   r   Ú
isinstancer   Úfmpz_matÚRuntimeErrorr   Úfmpq_matÚNotImplementedError)r   r   r   r   Zrepshaper   r   r   r!   ‰   s    

z
DFM._checkc                 C   s   |t tfkS )z4Return True if the given domain is supported by DFM.r   ©r   r   r   r   r   Ú_supports_domain•   s    zDFM._supports_domainc                 C   s(   |t krtjS |tkrtjS tdƒ‚dS )z3Return the flint matrix class for the given domain.r(   N)r   r   r*   r   r,   r-   r.   r   r   r   r   š   s
    zDFM._get_flint_funcc                 C   s   |   | j¡S )z5Callable to create a flint matrix of the same domain.)r   r   ©r&   r   r   r   Ú_func¤   s    z	DFM._funcc                 C   s   t |  ¡ ƒS )zReturn ``str(self)``.)ÚstrÚto_ddmr0   r   r   r   Ú__str__©   s    zDFM.__str__c                 C   s   dt |  ¡ ƒdd… › �S )zReturn ``repr(self)``.r   é   N)Úreprr3   r0   r   r   r   Ú__repr__­   s    zDFM.__repr__c                 C   s&   t |tƒstS | j|jko$| j|jkS )zReturn ``self == other``.)r)   r   ÚNotImplementedr   r   ©r&   Úotherr   r   r   Ú__eq__±   s    
z
DFM.__eq__c                 C   s   | |||ƒS )r   r   )r   r   r   r   r   r   r   Ú	from_listº   s    zDFM.from_listc                 C   s
   | j  ¡ S )zConvert to a nested list.)r   Útolistr0   r   r   r   Úto_list¿   s    zDFM.to_listc                 C   s   |   |  | j¡¡S )zReturn a copy of self.)r'   r1   r   r0   r   r   r   ÚcopyÃ   s    zDFM.copyc                 C   s   t  |  ¡ | j| j¡S )zConvert to a DDM.)ÚDDMr<   r>   r   r   r0   r   r   r   r3   Ç   s    z
DFM.to_ddmc                 C   s   t  |  ¡ | j| j¡S )zConvert to a SDM.)ÚSDMr<   r>   r   r   r0   r   r   r   Úto_sdmË   s    z
DFM.to_sdmc                 C   s   | S )zReturn self.r   r0   r   r   r   Úto_dfmÏ   s    z
DFM.to_dfmc                 C   s   | S )aL  
        Convert to a :class:`DFM`.

        This :class:`DFM` method exists to parallel the :class:`~.DDM` and
        :class:`~.SDM` methods. For :class:`DFM` it will always return self.

        See Also
        ========

        to_ddm
        to_sdm
        sympy.polys.matrices.domainmatrix.DomainMatrix.to_dfm_or_ddm
        r   r0   r   r   r   Úto_dfm_or_ddmÓ   s    zDFM.to_dfm_or_ddmc                 C   s   |   | ¡ |j|j¡S )zConvert from a DDM.)r<   r>   r   r   )r   Úddmr   r   r   Úfrom_ddmã   s    zDFM.from_ddmc                 C   sl   |   |¡}z|||fžŽ }W nB tk
r>   td|› �ƒ‚Y n" tk
r^   td|› �ƒ‚Y nX | |||ƒS )z Inverse of :meth:`to_list_flat`.z'Incorrect number of elements for shape zInput should be a list of )r   r   r	   r   )r   Úelementsr   r   Úfuncr   r   r   r   Úfrom_list_flatè   s    
zDFM.from_list_flatc                 C   s
   | j  ¡ S )zConvert to a flat list.)r   Úentriesr0   r   r   r   Úto_list_flatô   s    zDFM.to_list_flatc                 C   s   |   ¡  ¡ S )z$Convert to a flat list of non-zeros.)r3   Ú
to_flat_nzr0   r   r   r   rL   ø   s    zDFM.to_flat_nzc                 C   s   t  |||¡ ¡ S )zInverse of :meth:`to_flat_nz`.)r@   Úfrom_flat_nzrC   )r   rG   Údatar   r   r   r   rM   ü   s    zDFM.from_flat_nzc                 C   s   |   ¡  ¡ S )zConvert to a DOD.)r3   Úto_dodr0   r   r   r   rO     s    z
DFM.to_dodc                 C   s   t  |||¡ ¡ S )zInverse of :meth:`to_dod`.)r@   Úfrom_dodrC   )r   Zdodr   r   r   r   r   rP     s    zDFM.from_dodc                 C   s   |   ¡  ¡ S )zConvert to a DOK.)r3   Úto_dokr0   r   r   r   rQ   
  s    z
DFM.to_dokc                 C   s   t  |||¡ ¡ S )zInverse of :math:`to_dod`.)r@   Úfrom_dokrC   )r   Zdokr   r   r   r   r   rR     s    zDFM.from_dokc                 c   sN   | j \}}| j}t|ƒD ]0}t|ƒD ]"}|||f }|r$|||f V  q$qdS )z0Iterater over the non-zero values of the matrix.N©r   r   Úrange©r&   ÚmÚnr   ÚiÚjZrepijr   r   r   Úiter_values  s    
zDFM.iter_valuesc                 c   sN   | j \}}| j}t|ƒD ]0}t|ƒD ]"}|||f }|r$||f|fV  q$qdS )zBIterate over indices and values of nonzero elements of the matrix.NrS   rU   r   r   r   Ú
iter_items  s    
zDFM.iter_itemsc                 C   sl   || j kr|  ¡ S |tkr<| j tkr<|  t | j¡| j|¡S |tkr`| j tkr`|  	¡  
|¡ ¡ S tdƒ‚dS )zConvert to a new domain.r(   N)r   r?   r   r   r   r   r,   r   r   r3   Ú
convert_torC   r-   )r&   r   r   r   r   r\   '  s    
zDFM.convert_toc              
   C   sp   | j \}}|dk r||7 }|dk r*||7 }z| j||f W S  tk
rj   td|› d|› d| j › �ƒ‚Y nX dS )zGet the ``(i, j)``-th entry.r   úInvalid indices (ú, ú) for Matrix of shape N©r   r   r   Ú
IndexError)r&   rX   rY   rV   rW   r   r   r   Úgetitem5  s    
zDFM.getitemc              
   C   sr   | j \}}|dk r||7 }|dk r*||7 }z|| j||f< W n0 tk
rl   td|› d|› d| j › �ƒ‚Y nX dS )zSet the ``(i, j)``-th entry.r   r]   r^   r_   Nr`   )r&   rX   rY   ÚvaluerV   rW   r   r   r   ÚsetitemC  s    
zDFM.setitemc                    s:   | j ‰ ‡ ‡fdd„|D ƒ}t|ƒtˆƒf}|  ||| j¡S )z%Extract a submatrix with no checking.c                    s    g | ]‰ ‡‡ fd d„ˆD ƒ‘qS )c                    s   g | ]}ˆ ˆ|f ‘qS r   r   )Ú.0rY   )ÚMrX   r   r   Ú
<listcomp>U  s     z+DFM._extract.<locals>.<listcomp>.<listcomp>r   )re   ©rf   Ú	j_indices)rX   r   rg   U  s     z DFM._extract.<locals>.<listcomp>)r   Úlenr<   r   )r&   Ú	i_indicesri   Zlolr   r   rh   r   Ú_extractQ  s    zDFM._extractc                 C   sÊ   | j \}}g }g }|D ]P}|dk r,|| }n|}d|  krD|k s\n td|› d| j › �ƒ‚| |¡ q|D ]P}	|	dk r‚|	| }
n|	}
d|
  krš|k s²n td|	› d| j › �ƒ‚| |
¡ ql|  ||¡S )zExtract a submatrix.r   zInvalid row index z for Matrix of shape zInvalid column index )r   ra   Úappendrl   )r&   r   ZcolslistrV   rW   Znew_rowsZnew_colsrX   Zi_posrY   Zj_posr   r   r   ÚextractY  s$    


zDFM.extractc                 C   s.   | j \}}t|ƒ| }t|ƒ| }|  ||¡S )zSlice a DFM.)r   rT   rl   )r&   ZrowsliceZcolslicerV   rW   rk   ri   r   r   r   Úextract_slicew  s    
zDFM.extract_slicec                 C   s   |   | j ¡S ©zNegate a DFM matrix.©r'   r   r0   r   r   r   Úneg  s    zDFM.negc                 C   s   |   | j|j ¡S )zAdd two DFM matrices.rq   r9   r   r   r   Úaddƒ  s    zDFM.addc                 C   s   |   | j|j ¡S )zSubtract two DFM matrices.rq   r9   r   r   r   Úsub‡  s    zDFM.subc                 C   s   |   | j| ¡S )z1Multiply a DFM matrix from the right by a scalar.rq   r9   r   r   r   Úmul‹  s    zDFM.mulc                 C   s   |   || j ¡S )z0Multiply a DFM matrix from the left by a scalar.rq   r9   r   r   r   Úrmul�  s    zDFM.rmulc                 C   s   |   ¡  |  ¡ ¡ ¡ S )z/Elementwise multiplication of two DFM matrices.)r3   Úmul_elementwiserC   r9   r   r   r   rw   “  s    zDFM.mul_elementwisec                 C   s$   | j |jf}|  | j|j || j¡S )zMultiply two DFM matrices.)r#   r$   r   r   r   )r&   r:   r   r   r   r   Úmatmul˜  s    z
DFM.matmulc                 C   s   |   ¡ S rp   )rr   r0   r   r   r   Ú__neg__¡  s    zDFM.__neg__c                 C   s   |   |¡}|  ||Ž ||¡S )zReturn a zero DFM matrix.)r   r   )r   r   r   rH   r   r   r   Úzeros¥  s    
z	DFM.zerosc                 C   s   t  ||¡ ¡ S )zReturn a one DFM matrix.)r@   ÚonesrC   )r   r   r   r   r   r   r{   ¯  s    zDFM.onesc                 C   s   t  ||¡ ¡ S )z%Return the identity matrix of size n.)r@   ÚeyerC   )r   rW   r   r   r   r   r|   µ  s    zDFM.eyec                 C   s   t  ||¡ ¡ S )zReturn a diagonal matrix.)r@   ÚdiagrC   )r   rG   r   r   r   r   r}   »  s    zDFM.diagc                 C   s   |   ¡  ||¡ ¡ S )z/Apply a function to each entry of a DFM matrix.)r3   Ú	applyfuncrC   )r&   rH   r   r   r   r   r~   À  s    zDFM.applyfuncc                 C   s   |   | j ¡ | j| jf| j¡S )zTranspose a DFM matrix.)r   r   Ú	transposer$   r#   r   r0   r   r   r   r   Ä  s    zDFM.transposec                 G   s   |   ¡ jdd„ |D ƒŽ  ¡ S )zHorizontally stack matrices.c                 S   s   g | ]}|  ¡ ‘qS r   ©r3   ©re   Úor   r   r   rg   Ê  s     zDFM.hstack.<locals>.<listcomp>)r3   ÚhstackrC   ©r&   Zothersr   r   r   rƒ   È  s    z
DFM.hstackc                 G   s   |   ¡ jdd„ |D ƒŽ  ¡ S )zVertically stack matrices.c                 S   s   g | ]}|  ¡ ‘qS r   r€   r�   r   r   r   rg   Î  s     zDFM.vstack.<locals>.<listcomp>)r3   ÚvstackrC   r„   r   r   r   r…   Ì  s    z
DFM.vstackc                    s,   | j ‰ | j\}}‡ fdd„tt||ƒƒD ƒS )z$Return the diagonal of a DFM matrix.c                    s   g | ]}ˆ ||f ‘qS r   r   )re   rX   ©rf   r   r   rg   Ô  s     z DFM.diagonal.<locals>.<listcomp>)r   r   rT   Úmin)r&   rV   rW   r   r†   r   ÚdiagonalÐ  s    
zDFM.diagonalc                 C   s<   | j }t| jƒD ]&}t|ƒD ]}|||f r  dS qqdS )z2Return ``True`` if the matrix is upper triangular.FT)r   rT   r#   ©r&   rf   rX   rY   r   r   r   Úis_upperÖ  s    zDFM.is_upperc                 C   sD   | j }t| jƒD ].}t|d | jƒD ]}|||f r$  dS q$qdS )z2Return ``True`` if the matrix is lower triangular.r   FT©r   rT   r#   r$   r‰   r   r   r   Úis_lowerß  s    zDFM.is_lowerc                 C   s   |   ¡ o|  ¡ S )z*Return ``True`` if the matrix is diagonal.)rŠ   rŒ   r0   r   r   r   Úis_diagonalè  s    zDFM.is_diagonalc                 C   s>   | j }t| jƒD ](}t| jƒD ]}|||f r  dS qqdS )z1Return ``True`` if the matrix is the zero matrix.FTr‹   r‰   r   r   r   Úis_zero_matrixì  s    zDFM.is_zero_matrixc                 C   s   |   ¡  ¡ S )z5Return the number of non-zero elements in the matrix.)r3   Únnzr0   r   r   r   r�   õ  s    zDFM.nnzc                 C   s   |   ¡  ¡ S )z7Return the strongly connected components of the matrix.)r3   Úsccr0   r   r   r   r�   ù  s    zDFM.sccr   r   c                 C   s
   | j  ¡ S )a£  
        Compute the determinant of the matrix using FLINT.

        Examples
        ========

        >>> from sympy import Matrix
        >>> M = Matrix([[1, 2], [3, 4]])
        >>> dfm = M.to_DM().to_dfm()
        >>> dfm
        [[1, 2], [3, 4]]
        >>> dfm.det()
        -2

        Notes
        =====

        Calls the ``.det()`` method of the underlying FLINT matrix.

        For :ref:`ZZ` or :ref:`QQ` this calls ``fmpz_mat_det`` or
        ``fmpq_mat_det`` respectively.

        At the time of writing the implementation of ``fmpz_mat_det`` uses one
        of several algorithms depending on the size of the matrix and bit size
        of the entries. The algorithms used are:

        - Cofactor for very small (up to 4x4) matrices.
        - Bareiss for small (up to 25x25) matrices.
        - Modular algorithms for larger matrices (up to 60x60) or for larger
          matrices with large bit sizes.
        - Modular "accelerated" for larger matrices (60x60 upwards) if the bit
          size is smaller than the dimensions of the matrix.

        The implementation of ``fmpq_mat_det`` clears denominators from each
        row (not the whole matrix) and then calls ``fmpz_mat_det`` and divides
        by the product of the denominators.

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.det
            Higher level interface to compute the determinant of a matrix.
        )r   Údetr0   r   r   r   r‘   ý  s    1zDFM.detc                 C   s   | j  ¡  ¡ ddd… S )a#  
        Compute the characteristic polynomial of the matrix using FLINT.

        Examples
        ========

        >>> from sympy import Matrix
        >>> M = Matrix([[1, 2], [3, 4]])
        >>> dfm = M.to_DM().to_dfm()  # need ground types = 'flint'
        >>> dfm
        [[1, 2], [3, 4]]
        >>> dfm.charpoly()
        [1, -5, -2]

        Notes
        =====

        Calls the ``.charpoly()`` method of the underlying FLINT matrix.

        For :ref:`ZZ` or :ref:`QQ` this calls ``fmpz_mat_charpoly`` or
        ``fmpq_mat_charpoly`` respectively.

        At the time of writing the implementation of ``fmpq_mat_charpoly``
        clears a denominator from the whole matrix and then calls
        ``fmpz_mat_charpoly``. The coefficients of the characteristic
        polynomial are then multiplied by powers of the denominator.

        The ``fmpz_mat_charpoly`` method uses a modular algorithm with CRT
        reconstruction. The modular algorithm uses ``nmod_mat_charpoly`` which
        uses Berkowitz for small matrices and non-prime moduli or otherwise
        the Danilevsky method.

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.charpoly
            Higher level interface to compute the characteristic polynomial of
            a matrix.
        Néÿÿÿÿ)r   ÚcharpolyZcoeffsr0   r   r   r   r“   0  s    *zDFM.charpolyc                 C   s€   | j }| j\}}||kr tdƒ‚|tkr6td| ƒ‚nF|tkrpz|  | j ¡ ¡W S  t	k
rl   t
dƒ‚Y q|X ntd| ƒ‚dS )aä  
        Compute the inverse of a matrix using FLINT.

        Examples
        ========

        >>> from sympy import Matrix, QQ
        >>> M = Matrix([[1, 2], [3, 4]])
        >>> dfm = M.to_DM().to_dfm().convert_to(QQ)
        >>> dfm
        [[1, 2], [3, 4]]
        >>> dfm.inv()
        [[-2, 1], [3/2, -1/2]]
        >>> dfm.matmul(dfm.inv())
        [[1, 0], [0, 1]]

        Notes
        =====

        Calls the ``.inv()`` method of the underlying FLINT matrix.

        For now this will raise an error if the domain is :ref:`ZZ` but will
        use the FLINT method for :ref:`QQ`.

        The FLINT methods for :ref:`ZZ` and :ref:`QQ` are ``fmpz_mat_inv`` and
        ``fmpq_mat_inv`` respectively. The ``fmpz_mat_inv`` method computes an
        inverse with denominator. This is implemented by calling
        ``fmpz_mat_solve`` (see notes in :meth:`lu_solve` about the algorithm).

        The ``fmpq_mat_inv`` method clears denominators from each row and then
        multiplies those into the rhs identity matrix before calling
        ``fmpz_mat_solve``.

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.inv
            Higher level method for computing the inverse of a matrix.
        z!cannot invert a non-square matrixzfield expected, got %szmatrix is not invertiblez#DFM.inv() is not implemented for %sN)r   r   r   r   r
   r   r'   r   ÚinvÚZeroDivisionErrorr   r-   )r&   ÚKrV   rW   r   r   r   r”   \  s    7
zDFM.invc                 C   s$   |   ¡  ¡ \}}}| ¡ | ¡ |fS )z*Return the LU decomposition of the matrix.)r3   ÚlurC   )r&   ÚLÚUZswapsr   r   r   r—   ¥  s    zDFM.luc                 C   sÌ   | j |j ks td| j |j f ƒ‚| j js6td| j  ƒ‚| j\}}|j\}}||krftd||||f ƒ‚||f}||krŒ|  ¡  | ¡ ¡ ¡ S z| j 	|j¡}W n t
k
rº   tdƒ‚Y nX |  ||| j ¡S )aè  
        Solve a matrix equation using FLINT.

        Examples
        ========

        >>> from sympy import Matrix, QQ
        >>> M = Matrix([[1, 2], [3, 4]])
        >>> dfm = M.to_DM().to_dfm().convert_to(QQ)
        >>> dfm
        [[1, 2], [3, 4]]
        >>> rhs = Matrix([1, 2]).to_DM().to_dfm().convert_to(QQ)
        >>> dfm.lu_solve(rhs)
        [[0], [1/2]]

        Notes
        =====

        Calls the ``.solve()`` method of the underlying FLINT matrix.

        For now this will raise an error if the domain is :ref:`ZZ` but will
        use the FLINT method for :ref:`QQ`.

        The FLINT methods for :ref:`ZZ` and :ref:`QQ` are ``fmpz_mat_solve``
        and ``fmpq_mat_solve`` respectively. The ``fmpq_mat_solve`` method
        uses one of two algorithms:

        - For small matrices (<25 rows) it clears denominators between the
          matrix and rhs and uses ``fmpz_mat_solve``.
        - For larger matrices it uses ``fmpq_mat_solve_dixon`` which is a
          modular approach with CRT reconstruction over :ref:`QQ`.

        The ``fmpz_mat_solve`` method uses one of four algorithms:

        - For very small (<= 3x3) matrices it uses a Cramer's rule.
        - For small (<= 15x15) matrices it uses a fraction-free LU solve.
        - Otherwise it uses either Dixon or another multimodular approach.

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.lu_solve
            Higher level interface to solve a matrix equation.
        zDomains must match: %s != %szField expected, got %sz(Matrix size mismatch: %s * %s vs %s * %sz Matrix det == 0; not invertible.)r   r
   Zis_Fieldr   r   r3   Úlu_solverC   r   Zsolver•   r   r   )r&   ÚrhsrV   rW   rY   ÚkZ	sol_shapeZsolr   r   r   rš   µ  s     .

zDFM.lu_solvec                 C   s   |   ¡  ¡ \}}| ¡ |fS )ú/Return a basis for the nullspace of the matrix.)r3   Ú	nullspacerC   )r&   rE   Ú	nonpivotsr   r   r   rž      s    zDFM.nullspaceNc                 C   s    |   ¡ j|d�\}}| ¡ |fS )r�   )Úpivots)rB   Únullspace_from_rrefrC   )r&   r    ZsdmrŸ   r   r   r   r¡     s    zDFM.nullspace_from_rrefc                 C   s   |   ¡  ¡  ¡ S )z+Return a particular solution to the system.)r3   Ú
particularrC   r0   r   r   r   r¢     s    zDFM.particularç®Gáz®ï?çR¸…ëQà?ÚzbasisÚapproxc           	      C   sl   dd„ }||ƒ}||ƒ}d|  k r,dk s6n t dƒ‚| j\}}| j ¡ |krVtdƒ‚| jj|||||d�S )zACall the fmpz_mat.lll() method but check rank to avoid segfaults.c                 S   s*   t  | ¡rt| jƒt| jƒ S t| ƒS d S )N)r   Zof_typeÚfloatÚ	numeratorÚdenominator)Úxr   r   r   Úto_float*  s    
zDFM._lll.<locals>.to_floatg      Ð?r   z delta must be between 0.25 and 1z-Matrix must have full row rank for Flint LLL.)Ú	transformÚdeltaÚetar   Úgram)r   r   r   Zrankr   Úlll)	r&   r¬   r­   r®   r   r¯   r«   rV   rW   r   r   r   Ú_lll   s    

zDFM._lllç      è?c                 C   sD   | j tkrtd| j  ƒ‚n| j| jkr.tdƒ‚| j|d�}|  |¡S )a  Compute LLL-reduced basis using FLINT.

        See :meth:`lll_transform` for more information.

        Examples
        ========

        >>> from sympy import Matrix
        >>> M = Matrix([[1, 2, 3], [4, 5, 6]])
        >>> M.to_DM().to_dfm().lll()
        [[2, 1, 0], [-1, 1, 3]]

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.lll
            Higher level interface to compute LLL-reduced basis.
        lll_transform
            Compute LLL-reduced basis and transform matrix.
        úZZ expected, got %sú,Matrix must not have more rows than columns.)r­   )r   r   r
   r#   r$   r   r±   r'   )r&   r­   r   r   r   r   r°   >  s    
zDFM.lllc                 C   sj   | j tkrtd| j  ƒ‚n| j| jkr.tdƒ‚| jd|d�\}}|  |¡}|  || j| jf| j ¡}||fS )ad  Compute LLL-reduced basis and transform using FLINT.

        Examples
        ========

        >>> from sympy import Matrix
        >>> M = Matrix([[1, 2, 3], [4, 5, 6]]).to_DM().to_dfm()
        >>> M_lll, T = M.lll_transform()
        >>> M_lll
        [[2, 1, 0], [-1, 1, 3]]
        >>> T
        [[-2, 1], [3, -1]]
        >>> T.matmul(M) == M_lll
        True

        See Also
        ========

        sympy.polys.matrices.domainmatrix.DomainMatrix.lll
            Higher level interface to compute LLL-reduced basis.
        lll
            Compute LLL-reduced basis without transform matrix.
        r³   r´   T)r¬   r­   )	r   r   r
   r#   r$   r   r±   r'   r   )r&   r­   r   ÚTZbasisZT_dfmr   r   r   Úlll_transform\  s    

zDFM.lll_transform)N)Fr£   r¤   r¥   r¦   )r²   )r²   )NÚ__name__Ú
__module__Ú__qualname__Ú__doc__ÚfmtZis_DFMZis_DDMr    Úclassmethodr   r'   r!   r/   r   Úpropertyr1   r4   r7   r;   r<   r>   r?   r3   rB   rC   rD   rF   rI   rK   rL   rM   rO   rP   rQ   rR   rZ   r[   r\   rb   rd   rl   rn   ro   rr   rs   rt   ru   rv   rw   rx   ry   rz   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   E   sº   "
	


	
	







	
	


			
2
+
H
J

)r@   )rA   N)Zsympy.external.gmpyr   Zsympy.external.importtoolsr   Zsympy.utilities.decoratorr   Zsympy.polys.domainsr   r   Ú
exceptionsr	   r
   r   r   r   r   r   Z__doctest_skip__r   Ú__all__r   Zsympy.polys.matrices.ddmr@   rA   r   r   r   r   Ú<module>*   s$   $
      A