a
    khˀ                     @   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 ZFdd ZGeBdwdxdd ZHdd ZIdd ZJdddZKdd ZLdddZMeBdwdxdddZNeBdwdxdddZOdS )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|vrFz||}W qN ttfyB   td| Y qN0 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   G/var/www/auris/lib/python3.9/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   s   |  | f}||kr td|tkr>t|tjs>tdnZ|tkr\t|tj	s\tdn<|j
r~t|tjtjfs~tdn|ttfvr|j
st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_matz1Rep is not a flint.fmpz_mod_mat or flint.nmod_mat#Only ZZ and QQ are supported by DFM)ZnrowsZncolsr   r   
isinstancer   fmpz_matRuntimeErrorr   fmpq_matis_FFfmpz_mod_matnmod_matNotImplementedError)r   r   r   r   Zrepshaper   r   r   r       s    


z
DFM._checkc                 C   s   |t tfv p|jo|jS )z4Return True if the given domain is supported by DFM.)r   r   r,   Z	_is_flint)r   r   r   r   r   _supports_domain   s    zDFM._supports_domainc                    st   |t krtjS |tkrtjS |jrh| t|jtj	rNtj
  fdd}ntfdd}|S tddS )z3Return the flint matrix class for the given domain.c                     s>   t | dkr(t| d tjr( | d S  g | R  S d S )Nr   r   )lenr(   r   r.   e)_clscr   r   _func   s    z"DFM._get_flint_func.<locals>._funcc                     s   t jg |  R  S N)r   r-   r2   )mr   r   <lambda>       z%DFM._get_flint_func.<locals>.<lambda>r'   N)r   r   r)   r   r+   r,   Zcharacteristicr(   ZoneZnmodr.   Zfmpz_mod_ctxr/   )r   r   r6   r   )r4   r5   r8   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   r6      s    z	DFM._funcc                 C   s   t |  S )zReturn ``str(self)``.)strto_ddmr;   r   r   r   __str__   s    zDFM.__str__c                 C   s   dt |  dd  S )zReturn ``repr(self)``.r      N)reprr=   r;   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   tolistr;   r   r   r   to_list   s    zDFM.to_listc                 C   s   |  | | jS )zReturn a copy of self.)r&   r6   r   r;   r   r   r   copy   s    zDFM.copyc                 C   s   t |  | j| jS )zConvert to a DDM.)DDMrF   rH   r   r   r;   r   r   r   r=      s    z
DFM.to_ddmc                 C   s   t |  | j| jS )zConvert to a SDM.)SDMrF   rH   r   r   r;   r   r   r   to_sdm   s    z
DFM.to_sdmc                 C   s   | S )zReturn self.r   r;   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   r;   r   r   r   to_dfm_or_ddm   s    zDFM.to_dfm_or_ddmc                 C   s   |  | |j|jS )zConvert from a DDM.)rF   rH   r   r   )r   ddmr   r   r   from_ddm   s    zDFM.from_ddmc                 C   sl   |  |}z|g ||R  }W n> ty@   td| Y n  ty^   td| Y n0 | |||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   entriesr;   r   r   r   to_list_flat  s    zDFM.to_list_flatc                 C   s   |    S )z$Convert to a flat list of non-zeros.)r=   
to_flat_nzr;   r   r   r   rV     s    zDFM.to_flat_nzc                 C   s   t ||| S )zInverse of :meth:`to_flat_nz`.)rJ   from_flat_nzrM   )r   rQ   datar   r   r   r   rW     s    zDFM.from_flat_nzc                 C   s   |    S )zConvert to a DOD.)r=   to_dodr;   r   r   r   rY     s    z
DFM.to_dodc                 C   s   t ||| S )zInverse of :meth:`to_dod`.)rJ   from_dodrM   )r   Zdodr   r   r   r   r   rZ     s    zDFM.from_dodc                 C   s   |    S )zConvert to a DOK.)r=   to_dokr;   r   r   r   r[     s    z
DFM.to_dokc                 C   s   t ||| S )zInverse of :math:`to_dod`.)rJ   from_dokrM   )r   Zdokr   r   r   r   r   r\     s    zDFM.from_dokc                 c   sN   | j \}}| j}t|D ]0}t|D ]"}|||f }|r$|||f V  q$qdS )z/Iterate over the non-zero values of the matrix.Nr   r   ranger%   r8   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.Nr]   r_   r   r   r   
iter_items,  s    
zDFM.iter_itemsc                 C   sd   || j kr|  S |tkr<| j tkr<| t| j| j|S | 	|rX| 
 | S tddS )zConvert to a new domain.r'   N)r   rI   r   r   r   r   r+   r   r   r0   r=   
convert_torM   r/   )r%   r   r   r   r   re   6  s    

zDFM.convert_toc              
   C   sn   | j \}}|dk r||7 }|dk r*||7 }z| j||f W S  tyh   td| d| d| j  Y n0 dS )zGet the ``(i, j)``-th entry.r   Invalid indices (, ) for Matrix of shape Nr   r   r   
IndexError)r%   ra   rb   r8   r`   r   r   r   getitemD  s    
zDFM.getitemc              
   C   sp   | j \}}|dk r||7 }|dk r*||7 }z|| j||f< W n. tyj   td| d| d| j  Y n0 dS )zSet the ``(i, j)``-th entry.r   rf   rg   rh   Nri   )r%   ra   rb   valuer8   r`   r   r   r   setitemR  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   ).0rb   )Mra   r   r   
<listcomp>d  r:   z+DFM._extract.<locals>.<listcomp>.<listcomp>r   )rn   ro   	j_indices)ra   r   rp   d  r:   z DFM._extract.<locals>.<listcomp>)r   r1   rF   r   )r%   	i_indicesrr   Zlolr   r   rq   r   _extract`  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 sn 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   rj   appendrt   )r%   r   Zcolslistr8   r`   Znew_rowsZnew_colsra   Zi_posrb   Zj_posr   r   r   extracth  s$    


zDFM.extractc                 C   s.   | j \}}t|| }t|| }| ||S )zSlice a DFM.)r   r^   rt   )r%   ZrowsliceZcolslicer8   r`   rs   rr   r   r   r   extract_slice  s    
zDFM.extract_slicec                 C   s   |  | j S zNegate a DFM matrix.r&   r   r;   r   r   r   neg  s    zDFM.negc                 C   s   |  | j|j S )zAdd two DFM matrices.ry   rC   r   r   r   add  s    zDFM.addc                 C   s   |  | j|j S )zSubtract two DFM matrices.ry   rC   r   r   r   sub  s    zDFM.subc                 C   s   |  | j| S )z1Multiply a DFM matrix from the right by a scalar.ry   rC   r   r   r   mul  s    zDFM.mulc                 C   s   |  || j S )z0Multiply a DFM matrix from the left by a scalar.ry   rC   r   r   r   rmul  s    zDFM.rmulc                 C   s   |   |   S )z/Elementwise multiplication of two DFM matrices.)r=   mul_elementwiserM   rC   r   r   r   r     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%   rD   r   r   r   r   matmul  s    z
DFM.matmulc                 C   s   |   S rx   )rz   r;   r   r   r   __neg__  s    zDFM.__neg__c                 C   s   |  |}| || ||S )zReturn a zero DFM matrix.)r   r   )r   r   r   rR   r   r   r   zeros  s    
z	DFM.zerosc                 C   s   t || S )zReturn a one DFM matrix.)rJ   onesrM   )r   r   r   r   r   r   r     s    zDFM.onesc                 C   s   t || S )z%Return the identity matrix of size n.)rJ   eyerM   )r   r`   r   r   r   r   r     s    zDFM.eyec                 C   s   t || S )zReturn a diagonal matrix.)rJ   diagrM   )r   rQ   r   r   r   r   r     s    zDFM.diagc                 C   s   |   || S )z/Apply a function to each entry of a DFM matrix.)r=   	applyfuncrM   )r%   rR   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   r;   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   r=   rn   or   r   r   rp     r:   zDFM.hstack.<locals>.<listcomp>)r=   hstackrM   r%   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   rp     r:   zDFM.vstack.<locals>.<listcomp>)r=   vstackrM   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   )rn   ra   ro   r   r   rp     r:   z DFM.diagonal.<locals>.<listcomp>)r   r   r^   min)r%   r8   r`   r   r   r   diagonal  s    
zDFM.diagonalc                 C   sD   | j }t| jD ].}tt|| jD ]}|||f r$  dS q$qdS )z2Return ``True`` if the matrix is upper triangular.FT)r   r^   r"   r   r#   r%   ro   ra   rb   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   r^   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   r;   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.)r=   nnzr;   r   r   r   r     s    zDFM.nnzc                 C   s   |    S )z7Return the strongly connected components of the matrix.)r=   sccr;   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   detr;   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coeffsr;   r   r   r   r   ?  s    *zDFM.charpolyc                 C   s   | j }| j\}}||kr td|tkr6td| nJ|tksD|jrtz| | j	 W S  t
yp   tdY q0 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&   r   invZeroDivisionErrorr   r/   )r%   Kr8   r`   r   r   r   r   k  s    7
zDFM.invc                 C   s$   |    \}}}| | |fS )z*Return the LU decomposition of the matrix.)r=   lurM   )r%   LUZswapsr   r   r   r     s    zDFM.luc                 C   s    |    \}}| | fS )z*Return the QR decomposition of the matrix.)r=   qrrM   )r%   QRr   r   r   r     s    zDFM.qrc                 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
y   tdY n0 | ||| 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   r=   lu_solverM   r   Zsolver   r   r   )r%   rhsr8   r`   rb   kZ	sol_shapeZsolr   r   r   r     s     .

zDFM.lu_solvec                 C   s   | j tkrt| jdd}|dur| j \}}}}| j\}}| |||f| j | |||f| j | |||f| j | || j| j fS |   \}}	}
}| }|	 }|
 }| }||||fS )a  
        Fraction-free LU decomposition of DFM.

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

        Uses `python-flint` if possible for a matrix of
        integers otherwise uses the DDM method.

        See Also
        ========

        sympy.polys.matrices.ddm.DDM.fflu
        ffluN)	r   r   getattrr   r   r   r   r=   rM   )r%   r   Pr   Dr   r8   r`   Zddm_pZddm_lZddm_dZddm_ur   r   r   r     s     

zDFM.ffluc                 C   s   |    \}}| |fS )/Return a basis for the nullspace of the matrix.)r=   	nullspacerM   )r%   rO   	nonpivotsr   r   r   r   5  s    zDFM.nullspaceNc                 C   s    |   j|d\}}| |fS )r   )pivots)rL   nullspace_from_rrefrM   )r%   r   Zsdmr   r   r   r   r   K  s    zDFM.nullspace_from_rrefc                 C   s   |     S )z+Return a particular solution to the system.)r=   
particularrM   r;   r   r   r   r   Q  s    zDFM.particularGz?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 r7   )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   r8   r`   r   r   r   _lllU  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  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   )P__name__
__module____qualname____doc__fmtZis_DFMZis_DDMr   classmethodr   r&   r    r0   r   propertyr6   r>   rA   rE   rF   rH   rI   r=   rL   rM   rN   rP   rS   rU   rV   rW   rY   rZ   r[   r\   rc   rd   re   rk   rm   rt   rv   rw   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   r   r   r   r   r   r   r   r   r   r   E   s   "
	



	







	
	


			
2
+
H
J!

)rJ   )rK   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.ddmrJ   rK   r   r   r   r   <module>*   s$   $
      v