
    Xhˀ                         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    rdgZ ed          Zd	gZ edg
           G 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ground_typesc                      e Zd ZdZdZdZdZd Zed             Z	d Z
ed             Zed	             Zed
             Zed             Zd Zd Zd Zed             Zd Zd Zd Zd Zd Zd Zed             Zed             Zd Zd Zed             Zd Zed             Z d Z!ed             Z"d Z#d  Z$d! Z%d" Z&d# Z'd$ Z(d% Z)d& Z*d' Z+d( Z,d) Z-d* Z.d+ Z/d, Z0d- Z1d. Z2ed/             Z3ed0             Z4ed1             Z5ed2             Z6d3 Z7d4 Z8d5 Z9d6 Z:d7 Z;d8 Z<d9 Z=d: Z>d; Z?d< Z@d= ZA eBd>?          d@             ZC eBd>?          dA             ZD eBd>?          dB             ZEdC ZFdD ZG eBd>?          dE             ZHdF ZIdG ZJdSdIZKdJ ZLdTdOZM eBd>?          dUdQ            ZN eBd>?          dUdR            ZOdHS )Vr   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]]

    denseTFc                     |                      |          }d|vr4	  ||          }n,# t          t          f$ r t          d|           w xY w || }|                     |||          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domain	flint_matreps         k/var/www/tools.fuzzalab.pt/emblema-extractor/venv/lib/python3.11/site-packages/sympy/polys/matrices/_dfm.py__new__zDFM.__new__m   s    ''//	E>>Ui))	* U U U%&S6&S&STTTU )U#CxxUF+++s	   ' $Ac                     |                      |||           t                              |           }||_        |x|_        \  |_        |_        ||_        |S )z)Internal constructor from a flint matrix.)_checkobjectr$   r"   r   rowscolsr    )r   r"   r   r    objs        r#   r   zDFM._new{   sS     	

3v&&&nnS!!)..	&CHch

    c                 D    |                      || j        | j                  S )z>Create a new DFM with the same shape and domain but a new rep.)r   r   r    )selfr"   s     r#   _new_repzDFM._new_rep   s    yydj$+666r+   c                    |                                 |                                f}||k    rt          d          |t          k    r)t	          |t
          j                  st          d          |t          k    r)t	          |t
          j	                  st          d          |j
        r5t	          |t
          j        t
          j        f          st          d          |t          t          fvr|j
        st          d          d S 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)nrowsncolsr	   r   
isinstancer   fmpz_matRuntimeErrorr   fmpq_matis_FFfmpz_mod_matnmod_matNotImplementedError)r   r"   r   r    repshapes        r#   r&   z
DFM._check   s    IIKK-u!"LMMMR<<
3 ? ?<<===r\\*S%."A"A\<===\ 	M*S53Eu~2V"W"W 	MRSSSB8##FL#%&KLLL $###r+   c                 >    |t           t          fv p|j        o|j        S )z4Return True if the given domain is supported by DFM.)r   r   r7   	_is_flint)r   r    s     r#   _supports_domainzDFM._supports_domain   s"     "b!FV\%Ff6FFr+   c                 ^   |t           k    rt          j        S |t          k    rt          j        S |j        rg|                                t          |j        t          j	                  rt          j
        fd}nt                                        fd}|S t          d          )z3Return the flint matrix class for the given domain.c                      t          |           dk    r1t          | d         t          j                  r | d                   S  g | R  S )Nr   r   )lenr3   r   r9   )e_clscs    r#   _funcz"DFM._get_flint_func.<locals>._func   sN    1vv{{z!A$'G'G{#tAaDzz)#t{Q{{{{*r+   c                  *    t          j        g | R  S N)r   r8   )rB   ms    r#   <lambda>z%DFM._get_flint_func.<locals>.<lambda>   s    5#5#<q#<!#<#<#< r+   r0   )r   r   r4   r   r6   r7   characteristicr3   onenmodr9   fmpz_mod_ctxr:   )r   r    rE   rC   rD   rH   s      @@@r#   r   zDFM._get_flint_func   s     R<<>!r\\>!\ 	M%%''A&*ej11 	=~+ + + + + + + &&q))<<<<L%&KLLLr+   c                 6    |                      | j                  S )z5Callable to create a flint matrix of the same domain.)r   r    r-   s    r#   rE   z	DFM._func   s     ##DK000r+   c                 D    t          |                                           S )zReturn ``str(self)``.)strto_ddmrO   s    r#   __str__zDFM.__str__   s    4;;==!!!r+   c                 Z    dt          |                                           dd          S )zReturn ``repr(self)``.r      N)reprrR   rO   s    r#   __repr__zDFM.__repr__   s)    .T$++--((,...r+   c                 z    t          |t                    st          S | j        |j        k    o| j        |j        k    S )zReturn ``self == other``.)r3   r   NotImplementedr    r"   r-   others     r#   __eq__z
DFM.__eq__   s9    %%% 	"!! {el*Dtx59/DDr+   c                      | |||          S )r    )r   r   r   r    s       r#   	from_listzDFM.from_list   s     s8UF+++r+   c                 4    | j                                         S )zConvert to a nested list.)r"   tolistrO   s    r#   to_listzDFM.to_list   s    x   r+   c                 \    |                      |                     | j                            S )zReturn a copy of self.)r.   rE   r"   rO   s    r#   copyzDFM.copy   s"    }}TZZ11222r+   c                 f    t          j        |                                 | j        | j                  S )zConvert to a DDM.)DDMr_   rb   r   r    rO   s    r#   rR   z
DFM.to_ddm   "    }T\\^^TZEEEr+   c                 f    t          j        |                                 | j        | j                  S )zConvert to a SDM.)SDMr_   rb   r   r    rO   s    r#   to_sdmz
DFM.to_sdm   rg   r+   c                     | S )zReturn self.r^   rO   s    r#   to_dfmz
DFM.to_dfm   s    r+   c                     | 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^   rO   s    r#   to_dfm_or_ddmzDFM.to_dfm_or_ddm   s	     r+   c                 h    |                      |                                |j        |j                  S )zConvert from a DDM.)r_   rb   r   r    )r   ddms     r#   from_ddmzDFM.from_ddm   s&     }}S[[]]CIszBBBr+   c                     |                      |          }	  |g ||R  }n;# t          $ r t          d|           t          $ r t          d|           w xY w | |||          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"   s         r#   from_list_flatzDFM.from_list_flat   s     ""6**	I$((x(((CC 	U 	U 	U!"SE"S"STTT 	I 	I 	I!"Gv"G"GHHH	Is3v&&&s	   
" 8Ac                 4    | j                                         S )zConvert to a flat list.)r"   entriesrO   s    r#   to_list_flatzDFM.to_list_flat  s    x!!!r+   c                 N    |                                                                  S )z$Convert to a flat list of non-zeros.)rR   
to_flat_nzrO   s    r#   rz   zDFM.to_flat_nz  s    {{}}'')))r+   c                 R    t          j        |||                                          S )zInverse of :meth:`to_flat_nz`.)rf   from_flat_nzrl   )r   rs   datar    s       r#   r|   zDFM.from_flat_nz  s%     $77>>@@@r+   c                 N    |                                                                  S )zConvert to a DOD.)rR   to_dodrO   s    r#   r   z
DFM.to_dod      {{}}##%%%r+   c                 R    t          j        |||                                          S )zInverse of :meth:`to_dod`.)rf   from_dodrl   )r   dodr   r    s       r#   r   zDFM.from_dod  $     |C//66888r+   c                 N    |                                                                  S )zConvert to a DOK.)rR   to_dokrO   s    r#   r   z
DFM.to_dok  r   r+   c                 R    t          j        |||                                          S )zInverse of :math:`to_dod`.)rf   from_dokrl   )r   dokr   r    s       r#   r   zDFM.from_dok  r   r+   c              #      K   | j         \  }}| j        }t          |          D ],}t          |          D ]}|||f         }|r|||f         V  -dS )z/Iterate over the non-zero values of the matrix.Nr   r"   ranger-   rH   nr"   ijrepijs          r#   iter_valueszDFM.iter_values"  sx      z1hq 	$ 	$A1XX $ $AqD	 $ad)OOO$	$ 	$r+   c              #      K   | j         \  }}| j        }t          |          D ](}t          |          D ]}|||f         }|r||f|fV  )dS )zBIterate over indices and values of nonzero elements of the matrix.Nr   r   s          r#   
iter_itemszDFM.iter_items,  s{      z1hq 	* 	*A1XX * *AqD	 *q65/)))*	* 	*r+   c                    || j         k    r|                                 S |t          k    rI| j         t          k    r9|                     t
                              | j                  | j        |          S | 	                    |          r9| 
                                                    |                                          S t          d          )zConvert to a new domain.r0   )r    rd   r   r   r   r   r6   r"   r   r>   rR   
convert_torl   r:   )r-   r    s     r#   r   zDFM.convert_to6  s    T[  99;;r\\dkR//99U^^DH55tz6JJJ""6** 	M;;==++F33::<<< &&KLLLr+   c           	          | j         \  }}|dk     r||z  }|dk     r||z  }	 | j        ||f         S # t          $ r t          d| d| d| j                    w xY w)zGet the ``(i, j)``-th entry.r   Invalid indices (, ) for Matrix of shape r   r"   r   
IndexError)r-   r   r   rH   r   s        r#   getitemzDFM.getitemD  s     z1q55FAq55FA	]8AqD>! 	] 	] 	][[[a[[tz[[\\\	]s	   1 (Ac           	          | j         \  }}|dk     r||z  }|dk     r||z  }	 || j        ||f<   dS # t          $ r t          d| d| d| j                    w xY w)zSet the ``(i, j)``-th entry.r   r   r   r   Nr   )r-   r   r   valuerH   r   s         r#   setitemzDFM.setitemR  s     z1q55FAq55FA	]"DHQTNNN 	] 	] 	][[[a[[tz[[\\\	]s	   0 (Ac                     | j         fd|D             }t          |          t                    f}|                     ||| j                  S )z%Extract a submatrix with no checking.c                 0    g | ]fd D             S )c                 $    g | ]}|f         S r^   r^   ).0r   Mr   s     r#   
<listcomp>z+DFM._extract.<locals>.<listcomp>.<listcomp>d  s!    +++A!Q$+++r+   r^   )r   r   r   	j_indicess    @r#   r   z DFM._extract.<locals>.<listcomp>d  s2    ???++++++++???r+   )r"   rA   r_   r    )r-   	i_indicesr   lolr   r   s     `  @r#   _extractzDFM._extract`  sW     H?????Y???YY0~~c5$+666r+   c                    | j         \  }}g }g }|D ]N}|dk     r||z   }n|}d|cxk    r|k     sn t          d| d| j                    |                    |           O|D ]N}	|	dk     r|	|z   }
n|	}
d|
cxk    r|k     sn t          d|	 d| j                    |                    |
           O|                     ||          S )zExtract a submatrix.r   zInvalid row index z for Matrix of shape zInvalid column index )r   r   appendr   )r-   r   colslistrH   r   new_rowsnew_colsr   i_posr   j_poss              r#   extractzDFM.extracth  s   
 z1 	# 	#A1uuA>>>>>>>> !Za!Z!Zdj!Z!Z[[[OOE"""" 	# 	#A1uuA>>>>>>>> !]!]!]QUQ[!]!]^^^OOE""""}}Xx000r+   c                     | j         \  }}t          |          |         }t          |          |         }|                     ||          S )zSlice a DFM.)r   r   r   )r-   rowslicecolslicerH   r   r   r   s          r#   extract_slicezDFM.extract_slice  sC     z1!HHX&	!HHX&	}}Y	222r+   c                 8    |                      | j                   S zNegate a DFM matrix.r.   r"   rO   s    r#   negzDFM.neg  s    }}dhY'''r+   c                 F    |                      | j        |j        z             S )zAdd two DFM matrices.r   rZ   s     r#   addzDFM.add      }}TX	1222r+   c                 F    |                      | j        |j        z
            S )zSubtract two DFM matrices.r   rZ   s     r#   subzDFM.sub  r   r+   c                 <    |                      | j        |z            S )z1Multiply a DFM matrix from the right by a scalar.r   rZ   s     r#   mulzDFM.mul  s    }}TX-...r+   c                 <    |                      || j        z            S )z0Multiply a DFM matrix from the left by a scalar.r   rZ   s     r#   rmulzDFM.rmul  s    }}UTX-...r+   c                     |                                                      |                                                                           S )z/Elementwise multiplication of two DFM matrices.)rR   mul_elementwiserl   rZ   s     r#   r   zDFM.mul_elementwise  s4     {{}},,U\\^^<<CCEEEr+   c                 p    | j         |j        f}|                     | j        |j        z  || j                  S )zMultiply two DFM matrices.)r(   r)   r   r"   r    )r-   r[   r   s      r#   matmulz
DFM.matmul  s1    EJ'yyEI-udkBBBr+   c                 *    |                                  S r   )r   rO   s    r#   __neg__zDFM.__neg__  s    xxzzr+   c                 `    |                      |          }|                      || ||          S )zReturn a zero DFM matrix.)r   r   )r   r   r    rt   s       r#   zerosz	DFM.zeros  s3     ""6**xxeeV444r+   c                 P    t          j        ||                                          S )zReturn a one DFM matrix.)rf   onesrl   )r   r   r    s      r#   r   zDFM.ones  s"     xv&&--///r+   c                 P    t          j        ||                                          S )z%Return the identity matrix of size n.)rf   eyerl   )r   r   r    s      r#   r   zDFM.eye  s"     wq&!!((***r+   c                 P    t          j        ||                                          S )zReturn a diagonal matrix.)rf   diagrl   )r   rs   r    s      r#   r   zDFM.diag  s"     x&))00222r+   c                 v    |                                                      ||                                          S )z/Apply a function to each entry of a DFM matrix.)rR   	applyfuncrl   )r-   rt   r    s      r#   r   zDFM.applyfunc  s,    {{}}&&tV44;;===r+   c                     |                      | j                                        | j        | j        f| j                  S )zTranspose a DFM matrix.)r   r"   	transposer)   r(   r    rO   s    r#   r   zDFM.transpose  s1    yy++--	49/Et{SSSr+   c                 r     |                                  j        d |D                                              S )zHorizontally stack matrices.c                 6    g | ]}|                                 S r^   rR   r   os     r#   r   zDFM.hstack.<locals>.<listcomp>       %A%A%AQahhjj%A%A%Ar+   )rR   hstackrl   r-   otherss     r#   r   z
DFM.hstack  5    #t{{}}#%A%A&%A%A%ABIIKKKr+   c                 r     |                                  j        d |D                                              S )zVertically stack matrices.c                 6    g | ]}|                                 S r^   r   r   s     r#   r   zDFM.vstack.<locals>.<listcomp>  r   r+   )rR   vstackrl   r   s     r#   r   z
DFM.vstack  r   r+   c                 x    | j         | j        \  }}fdt          t          ||                    D             S )z$Return the diagonal of a DFM matrix.c                 $    g | ]}||f         S r^   r^   )r   r   r   s     r#   r   z DFM.diagonal.<locals>.<listcomp>  s!    222A!Q$222r+   )r"   r   r   min)r-   rH   r   r   s      @r#   diagonalzDFM.diagonal  s?    Hz12222s1ayy!1!12222r+   c                     | j         }t          | j                  D ]5}t          t          || j                            D ]}|||f         r  dS 6dS )z2Return ``True`` if the matrix is upper triangular.FT)r"   r   r(   r   r)   r-   r   r   r   s       r#   is_upperzDFM.is_upper  so    Hty!! 	! 	!A3q$),,-- ! !QT7 ! 555!! tr+   c                     | j         }t          | j                  D ]+}t          |dz   | j                  D ]}|||f         r  dS ,dS )z2Return ``True`` if the matrix is lower triangular.r   FTr"   r   r(   r)   r   s       r#   is_lowerzDFM.is_lower  sk    Hty!! 	! 	!A1q5$),, ! !QT7 ! 555!! tr+   c                 R    |                                  o|                                 S )z*Return ``True`` if the matrix is diagonal.)r   r   rO   s    r#   is_diagonalzDFM.is_diagonal  s    }}24==??2r+   c                     | j         }t          | j                  D ]'}t          | j                  D ]}|||f         r  dS (dS )z1Return ``True`` if the matrix is the zero matrix.FTr   r   s       r#   is_zero_matrixzDFM.is_zero_matrix  se    Hty!! 	! 	!A49%% ! !QT7 ! 555!! tr+   c                 N    |                                                                  S )z5Return the number of non-zero elements in the matrix.)rR   nnzrO   s    r#   r   zDFM.nnz      {{}}  """r+   c                 N    |                                                                  S )z7Return the strongly connected components of the matrix.)rR   sccrO   s    r#   r   zDFM.scc  r   r+   r   r   c                 4    | 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"   detrO   s    r#   r   zDFM.det  s    b x||~~r+   c                 j    | 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"   charpolycoeffsrO   s    r#   r   zDFM.charpoly?  s0    T x  ""))++DDbD11r+   c                 d   | j         }| j        \  }}||k    rt          d          |t          k    rt	          d|z            |t
          k    s|j        rJ	 |                     | j        	                                          S # t          $ r t          d          w xY wt          d|z            )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 %s)r    r   r   r   r
   r   r7   r.   r"   invZeroDivisionErrorr   r:   )r-   KrH   r   s       r#   r   zDFM.invk  s    n Kz166()LMMM77 81 <==="WWWM}}TX\\^^444$ M M M01KLLLM
 &&Ka&OPPPs   +B Bc                     |                                                                  \  }}}|                                |                                |fS )z*Return the LU decomposition of the matrix.)rR   lurl   )r-   LUswapss       r#   r  zDFM.lu  s>    kkmm&&((1exxzz188::u,,r+   c                     |                                                                  \  }}|                                |                                fS )z*Return the QR decomposition of the matrix.)rR   qrrl   )r-   QRs      r#   r  zDFM.qr  s:    {{}}!!1xxzz188::%%r+   c           
      n   | j         |j         k    st          d| j         d|j                   | j         j        st          d| j         z            | j        \  }}|j        \  }}||k    rt	          d|d|d|d|          ||f}||k    rK|                                                     |                                                                          S 	 | j        	                    |j                  }n# t          $ r t          d          w xY w|                     ||| 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: z != zField expected, got %szMatrix size mismatch: z * z vs z Matrix det == 0; not invertible.)r    r
   is_Fieldr   r   rR   lu_solverl   r"   solver   r   r   )r-   rhsrH   r   r   k	sol_shapesols           r#   r  zDFM.lu_solve  sP   \ {cj((-$+++szz Z[[[
 {# 	H 84; FGGGz1y166,QQQPQPQPQSTSTSTVWVWXYYYF	 66;;==))#**,,77>>@@@	Q(..))CC  	Q 	Q 	Q,-OPPP	Q yyi555s   C> >Dc                    | j         t          k    rt          | j        dd          }|| 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   rR   rl   )r-   r  Pr  Dr  rH   r   ddm_pddm_lddm_dddm_us               r#   r  zDFM.fflu  s    ;"48VT22D!X]]__
1az1IIa!Q55IIa!Q55IIa!Q55IIaT[99	  &*[[]]%7%7%9%9"ueULLNNLLNNLLNNLLNN!Qzr+   c                     |                                                                  \  }}|                                |fS )/Return a basis for the nullspace of the matrix.)rR   	nullspacerl   )r-   rp   	nonpivotss      r#   r  zDFM.nullspace5  s4    & 0022Yzz||Y&&r+   Nc                     |                                                      |          \  }}|                                |fS )r  )pivots)rj   nullspace_from_rrefrl   )r-   r  sdmr  s       r#   r   zDFM.nullspace_from_rrefK  s9     ::&:IIYzz||Y&&r+   c                 r    |                                                                                                  S )z+Return a particular solution to the system.)rR   
particularrl   rO   s    r#   r#  zDFM.particularQ  s(    {{}}''))00222r+   Gz?RQ?zbasisapproxc                    d } ||          } ||          }d|cxk     rdk     sn t          d          | j        \  }}| j                                        |k    rt	          d          | j                            |||||          S )zACall the fmpz_mat.lll() method but check rank to avoid segfaults.c                     t          j        |           r)t          | j                  t          | j                  z  S t          |           S rG   )r   of_typefloat	numeratordenominator)xs    r#   to_floatzDFM._lll.<locals>.to_float_  s<    z!}}  Q[))E!-,@,@@@Qxxr+   g      ?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"   rankr   lll)	r-   r0  r1  r2  r"   r3  r/  rH   r   s	            r#   _lllzDFM._lllU  s    	  	  	  hsmmeaABBB z18==??aMNNN x||iu#3UY|ZZZr+         ?c                     | j         t          k    rt          d| j         z            | j        | j        k    rt          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.)r1  )r    r   r
   r(   r)   r   r6  r.   )r-   r1  r"   s      r#   r5  zDFM.llls  sj    , ;" 5 CDDDY""MNNNiiei$$}}S!!!r+   c                 D   | j         t          k    rt          d| j         z            | j        | j        k    rt          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.
        r9  r:  T)r0  r1  )	r    r   r
   r(   r)   r   r6  r.   r   )r-   r1  r"   TbasisT_dfms         r#   lll_transformzDFM.lll_transform  s    2 ;" 5 CDDDY""MNNNT77Qc""		!di3T[AAe|r+   rG   )Fr$  r%  r&  r'  )r7  )P__name__
__module____qualname____doc__fmtis_DFMis_DDMr$   classmethodr   r.   r&   r>   r   propertyrE   rS   rW   r\   r_   rb   rd   rR   rj   rl   rn   rq   ru   rx   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  r  r  r  r  r   r#  r6  r5  r?  r^   r+   r#   r   r   E   s          D CFF, , ,   [7 7 7 M M [M G G [G M M [M, 1 1 X1" " "/ / /E E E , , [,! ! !3 3 3F F FF F F      C C [C 	' 	' [	'" " "* * * A A [A& & & 9 9 [9& & & 9 9 [9$ $ $* * *M M M] ] ]] ] ]7 7 71 1 1<3 3 3( ( (3 3 33 3 3/ / // / /F F F
C C C   5 5 [5 0 0 [0
 + + [+
 3 3 [3> > >T T TL L LL L L3 3 3    3 3 3  # # ## # # W---0 0 .-0d W---)2 )2 .-)2V W---FQ FQ .-FQP- - -
& & &  W---H6 H6 .-H6T  B' ' ',' ' ' '3 3 3[ [ [ [< W---" " " .-": W---      .-     r+   )rf   )ri   N)sympy.external.gmpyr   sympy.external.importtoolsr   sympy.utilities.decoratorr   sympy.polys.domainsr   r   
exceptionsr	   r
   r   r   r   r   r   __doctest_skip__r   __all__r   sympy.polys.matrices.ddmrf   ri   r^   r+   r#   <module>rQ     sY  T - , , , , , 4 4 4 4 4 4 8 8 8 8 8 8 & & & & & & & &                  7u 	g ' '+++l l l l l l l ,+l` ) ( ( ( ( ( ( ( ( ( ( ( ( (r+   