
    \hˀ                         S SK Jr  S SKJr  S SKJr  S SKJrJr  SSK	J
r
JrJrJrJrJrJr  \S:w  a  S/r\" S5      rS	/r\" S/S
9 " S S	5      5       rS SKJr  S SKJr  g)    )GROUND_TYPES)import_module)doctest_depends_on)ZZQQ   )DMBadInputErrorDMDomainErrorDMNonSquareMatrixErrorDMNonInvertibleMatrixErrorDMRankErrorDMShapeErrorDMValueErrorflint*DFMground_typesc                      \ rS rSrSrSrSrSrS r\	S 5       r
S r\	S	 5       r\	S
 5       r\	S 5       r\S 5       rS rS rS r\	S 5       rS rS rS rS rS rS r\	S 5       r\	S 5       rS rS r\	S 5       rS r \	S 5       r!S r"\	S 5       r#S  r$S! r%S" r&S# r'S$ r(S% r)S& r*S' r+S( r,S) r-S* r.S+ r/S, r0S- r1S. r2S/ r3\	S0 5       r4\	S1 5       r5\	S2 5       r6\	S3 5       r7S4 r8S5 r9S6 r:S7 r;S8 r<S9 r=S: r>S; r?S< r@S= rAS> rB\C" S?S@9SA 5       rD\C" S?S@9SB 5       rE\C" S?S@9SC 5       rFSD rGSE rH\C" S?S@9SF 5       rISG rJSH rKSPSJ jrLSK rMSQSL jrN\C" S?S@9SRSM j5       rO\C" S?S@9SRSN j5       rPSOrQgI)Sr   E   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                     U R                  U5      nSU;  a
   U" U5      nOU" U6 nU R	                  XRU5      $ ! [        [        4 a    [        SU 35      ef = f)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         Q/var/www/auris/envauris/lib/python3.13/site-packages/sympy/polys/matrices/_dfm.py__new__DFM.__new__m   sq    ''/	E>U) U#CxxF++ 	* U%(J6(&STTUs	   9 Ac                     U R                  XU5        [        R                  U 5      nXl        U=Ul        u  Ul        Ul        X4l        U$ )z)Internal constructor from a flint matrix.)_checkobjectr%   r#   r    rowscolsr!   )r   r#   r    r!   objs        r$   r   DFM._new{   sD     	

3v&nnS!)..	&CHch

    c                 N    U R                  XR                  U R                  5      $ )z>Create a new DFM with the same shape and domain but a new rep.)r   r    r!   )selfr#   s     r$   _new_repDFM._new_rep   s    yyjj$++66r.   c                 $   UR                  5       UR                  5       4nXB:w  a  [        S5      eU[        :X  a*  [	        U[
        R                  5      (       d  [        S5      eU[        :X  a*  [	        U[
        R                  5      (       d  [        S5      eUR                  (       a:  [	        U[
        R                  [
        R                  45      (       d  [        S5      eU[        [        4;  a  UR                  (       d  [        S5      eg g )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(   
DFM._check   s    IIK-!"LMMR<
3 ? ?<==r\*S%.."A"A<==\\*S53E3Eu~~2V"W"WRSSB8#FLL%&KLL -9#r.   c                 l    U[         [        4;   =(       d    UR                  =(       a    UR                  $ )z4Return True if the given domain is supported by DFM.)r   r   r;   	_is_flint)r   r!   s     r$   _supports_domainDFM._supports_domain   s'     "b!FV\\%Ff6F6FFr.   c                   ^^^ U[         :X  a  [        R                  $ U[        :X  a  [        R                  $ UR
                  (       ao  UR                  5       m[        UR                  [        R                  5      (       a  [        R                  mUU4S jnU$ [        R                  T5      mU4S jnU$ [        S5      e)z3Return the flint matrix class for the given domain.c                     > [        U 5      S:X  a-  [        U S   [        R                  5      (       a  T" U S   5      $ T" / U QTP76 $ )Nr   r   )lenr7   r   r=   )e_clscs    r$   _func"DFM._get_flint_func.<locals>._func   s@    1v{z!A$'G'G#AaDz)#{Q{{*r.   c                  4   > [         R                  " / U QTP76 $ N)r   r<   )rH   ms    r$   <lambda>%DFM._get_flint_func.<locals>.<lambda>   s    5#5#5#<q#<!#<r.   r4   )r   r   r8   r   r:   r;   characteristicr7   onenmodr=   fmpz_mod_ctxr>   )r   r!   rK   rI   rJ   rO   s      @@@r$   r   DFM._get_flint_func   s     R<>>!r\>>!\\%%'A&**ejj11~~+ L &&q)<L%&KLLr.   c                 8    U R                  U R                  5      $ )z5Callable to create a flint matrix of the same domain.)r   r!   r0   s    r$   rK   	DFM._func   s     ##DKK00r.   c                 4    [        U R                  5       5      $ )zReturn ``str(self)``.)strto_ddmrX   s    r$   __str__DFM.__str__   s    4;;=!!r.   c                 @    S[        U R                  5       5      SS  3$ )zReturn ``repr(self)``.r      N)reprr\   rX   s    r$   __repr__DFM.__repr__   s"    T$++-(,-..r.   c                     [        U[        5      (       d  [        $ U R                  UR                  :H  =(       a    U R                  UR                  :H  $ )zReturn ``self == other``.)r7   r   NotImplementedr!   r#   r0   others     r$   __eq__
DFM.__eq__   s<    %%%!! {{ell*Dtxx599/DDr.   c                     U " XU5      $ )r    )r   r   r    r!   s       r$   	from_listDFM.from_list   s     8F++r.   c                 6    U R                   R                  5       $ )zConvert to a nested list.)r#   tolistrX   s    r$   to_listDFM.to_list   s    xx  r.   c                 V    U R                  U R                  U R                  5      5      $ )zReturn a copy of self.)r1   rK   r#   rX   s    r$   copyDFM.copy   s    }}TZZ122r.   c                 v    [         R                  " U R                  5       U R                  U R                  5      $ )zConvert to a DDM.)DDMrl   rp   r    r!   rX   s    r$   r\   
DFM.to_ddm   #    }}T\\^TZZEEr.   c                 v    [         R                  " U R                  5       U R                  U R                  5      $ )zConvert to a SDM.)SDMrl   rp   r    r!   rX   s    r$   to_sdm
DFM.to_sdm   rx   r.   c                     U $ )zReturn self.rk   rX   s    r$   to_dfm
DFM.to_dfm   s    r.   c                     U $ )a  
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
rk   rX   s    r$   to_dfm_or_ddmDFM.to_dfm_or_ddm   s	     r.   c                 l    U R                  UR                  5       UR                  UR                  5      $ )zConvert from a DDM.)rl   rp   r    r!   )r   ddms     r$   from_ddmDFM.from_ddm   s%     }}S[[]CIIszzBBr.   c                     U R                  U5      n U" / UQUP76 nU " XRU5      $ ! [         a    [        SU 35      e[         a    [        SU 35      ef = f)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_flatDFM.from_list_flat   s}     ""6*	I((x(C
 3v&&	  	U!$KE7"STT 	I!$>vh"GHH	Is	   
& 0Ac                 6    U R                   R                  5       $ )zConvert to a flat list.)r#   entriesrX   s    r$   to_list_flatDFM.to_list_flat  s    xx!!r.   c                 >    U R                  5       R                  5       $ )z$Convert to a flat list of non-zeros.)r\   
to_flat_nzrX   s    r$   r   DFM.to_flat_nz  s    {{}''))r.   c                 L    [         R                  " XU5      R                  5       $ )zInverse of :meth:`to_flat_nz`.)rv   from_flat_nzr~   )r   r   datar!   s       r$   r   DFM.from_flat_nz  s      7>>@@r.   c                 >    U R                  5       R                  5       $ )zConvert to a DOD.)r\   to_dodrX   s    r$   r   
DFM.to_dod      {{}##%%r.   c                 L    [         R                  " XU5      R                  5       $ )zInverse of :meth:`to_dod`.)rv   from_dodr~   )r   dodr    r!   s       r$   r   DFM.from_dod       ||C/6688r.   c                 >    U R                  5       R                  5       $ )zConvert to a DOK.)r\   to_dokrX   s    r$   r   
DFM.to_dok  r   r.   c                 L    [         R                  " XU5      R                  5       $ )zInverse of :math:`to_dod`.)rv   from_dokr~   )r   dokr    r!   s       r$   r   DFM.from_dok  r   r.   c              #      #    U R                   u  pU R                  n[        U5       H,  n[        U5       H  nX4U4   nU(       d  M  X4U4   v   M     M.     g7f)z/Iterate over the non-zero values of the matrix.Nr    r#   ranger0   rO   nr#   ijrepijs          r$   iter_valuesDFM.iter_values"  sP     zzhhqA1XqD	5d)O  s   AAAc              #      #    U R                   u  pU R                  n[        U5       H+  n[        U5       H  nX4U4   nU(       d  M  XE4U4v   M     M-     g7f)zBIterate over indices and values of nonzero elements of the matrix.Nr   r   s          r$   
iter_itemsDFM.iter_items,  sQ     zzhhqA1XqD	565/)  s   AAAc                    XR                   :X  a  U R                  5       $ U[        :X  aN  U R                   [        :X  a:  U R	                  [
        R                  U R                  5      U R                  U5      $ U R                  U5      (       a-  U R                  5       R                  U5      R                  5       $ [        S5      e)zConvert to a new domain.r4   )r!   rs   r   r   r   r   r:   r#   r    rC   r\   
convert_tor~   r>   )r0   r!   s     r$   r   DFM.convert_to6  s    [[ 99;r\dkkR/99U^^DHH5tzz6JJ""6**;;=++F3::<< &&KLLr.   c           	          U R                   u  p4US:  a  X-  nUS:  a  X$-  n U R                  X4   $ ! [         a    [        SU SU SU R                    35      ef = f)zGet the ``(i, j)``-th entry.r   Invalid indices (, ) for Matrix of shape r    r#   r   
IndexError)r0   r   r   rO   r   s        r$   getitemDFM.getitemD  sv     zzq5FAq5FA	]88AD>! 	]02aS8Ntzzl[\\	]	   4 )Ac           	          U R                   u  pEUS:  a  X-  nUS:  a  X%-  n X0R                  X4'   g! [         a    [        SU SU SU R                    35      ef = f)zSet the ``(i, j)``-th entry.r   r   r   r   Nr   )r0   r   r   valuerO   r   s         r$   setitemDFM.setitemR  ss     zzq5FAq5FA	]"HHQTN 	]02aS8Ntzzl[\\	]r   c           
          U R                   nU VVs/ s H  oB Vs/ s H  oSXE4   PM
     snPM     nnn[        U5      [        U5      4nU R                  XgU R                  5      $ s  snf s  snnf )z%Extract a submatrix with no checking.)r#   rG   rl   r!   )r0   	i_indices	j_indicesMr   r   lolr    s           r$   _extractDFM._extract`  sc     HH5>?Y+A!$+Y?YY0~~c$++66 ,?s   	A+A&A+&A+c                    U R                   u  p4/ n/ nU HK  nUS:  a  Xs-   nOUnSUs=::  a  U:  d  O  [        SU SU R                    35      eUR                  U5        MM     U HK  n	U	S:  a  X-   n
OU	n
SU
s=::  a  U:  d  O  [        SU	 SU R                    35      eUR                  U
5        MM     U R                  XV5      $ )zExtract a submatrix.r   zInvalid row index z for Matrix of shape zInvalid column index )r    r   appendr   )r0   r   colslistrO   r   new_rowsnew_colsr   i_posr   j_poss              r$   extractDFM.extracth  s    
 zzA1u>> #5aS8Mdjj\!Z[[OOE"  A1u>> #8;PQUQ[Q[P\!]^^OOE"  }}X00r.   c                 x    U R                   u  p4[        U5      U   n[        U5      U   nU R                  XV5      $ )zSlice a DFM.)r    r   r   )r0   rowslicecolslicerO   r   r   r   s          r$   extract_sliceDFM.extract_slice  s:     zz!HX&	!HX&	}}Y22r.   c                 :    U R                  U R                  * 5      $ zNegate a DFM matrix.r1   r#   rX   s    r$   negDFM.neg  s    }}dhhY''r.   c                 R    U R                  U R                  UR                  -   5      $ )zAdd two DFM matrices.r   rf   s     r$   addDFM.add      }}TXX		122r.   c                 R    U R                  U R                  UR                  -
  5      $ )zSubtract two DFM matrices.r   rf   s     r$   subDFM.sub  r   r.   c                 >    U R                  U R                  U-  5      $ )z1Multiply a DFM matrix from the right by a scalar.r   rf   s     r$   mulDFM.mul  s    }}TXX-..r.   c                 <    U R                  XR                  -  5      $ )z0Multiply a DFM matrix from the left by a scalar.r   rf   s     r$   rmulDFM.rmul  s    }}UXX-..r.   c                 x    U R                  5       R                  UR                  5       5      R                  5       $ )z/Elementwise multiplication of two DFM matrices.)r\   mul_elementwiser~   rf   s     r$   r   DFM.mul_elementwise  s*     {{},,U\\^<CCEEr.   c                     U R                   UR                  4nU R                  U R                  UR                  -  X R                  5      $ )zMultiply two DFM matrices.)r*   r+   r   r#   r!   )r0   rg   r    s      r$   matmul
DFM.matmul  s6    EJJ'yyEII-ukkBBr.   c                 "    U R                  5       $ r   )r   rX   s    r$   __neg__DFM.__neg__  s    xxzr.   c                 N    U R                  U5      nU R                  U" U6 X5      $ )zReturn a zero DFM matrix.)r   r   )r   r    r!   r   s       r$   zeros	DFM.zeros  s)     ""6*xxee44r.   c                 J    [         R                  " X5      R                  5       $ )zReturn a one DFM matrix.)rv   onesr~   )r   r    r!   s      r$   r   DFM.ones  s     xx&--//r.   c                 J    [         R                  " X5      R                  5       $ )z%Return the identity matrix of size n.)rv   eyer~   )r   r   r!   s      r$   r   DFM.eye  s     wwq!((**r.   c                 J    [         R                  " X5      R                  5       $ )zReturn a diagonal matrix.)rv   diagr~   )r   r   r!   s      r$   r   DFM.diag  s     xx)0022r.   c                 \    U R                  5       R                  X5      R                  5       $ )z/Apply a function to each entry of a DFM matrix.)r\   	applyfuncr~   )r0   r   r!   s      r$   r  DFM.applyfunc  s"    {{}&&t4;;==r.   c                     U R                  U R                  R                  5       U R                  U R                  4U R
                  5      $ )zTranspose a DFM matrix.)r   r#   	transposer+   r*   r!   rX   s    r$   r  DFM.transpose  s3    yy++-		499/Et{{SSr.   c                     U R                  5       R                  " U Vs/ s H  o"R                  5       PM     sn6 R                  5       $ s  snf )zHorizontally stack matrices.)r\   hstackr~   r0   othersos      r$   r  
DFM.hstack  8    {{}##&%A&Qhhj&%ABIIKK%A   A
c                     U R                  5       R                  " U Vs/ s H  o"R                  5       PM     sn6 R                  5       $ s  snf )zVertically stack matrices.)r\   vstackr~   r  s      r$   r  
DFM.vstack  r  r  c                     U R                   nU R                  u  p#[        [        X#5      5       Vs/ s H  oAXD4   PM
     sn$ s  snf )z$Return the diagonal of a DFM matrix.)r#   r    r   min)r0   r   rO   r   r   s        r$   diagonalDFM.diagonal  s=    HHzz!&s1y!12!1A!$!1222s   Ac                     U R                   n[        U R                  5       H6  n[        [        X R                  5      5       H  nXU4   (       d  M      g   M8     g)z2Return ``True`` if the matrix is upper triangular.FT)r#   r   r*   r  r+   r0   r   r   r   s       r$   is_upperDFM.is_upper  sI    HHtyy!A3q)),-T77  . " r.   c                     U R                   n[        U R                  5       H1  n[        US-   U R                  5       H  nXU4   (       d  M      g   M3     g)z2Return ``True`` if the matrix is lower triangular.r   FTr#   r   r*   r+   r  s       r$   is_lowerDFM.is_lower  sJ    HHtyy!A1q5$)),T77  - " r.   c                 P    U R                  5       =(       a    U R                  5       $ )z*Return ``True`` if the matrix is diagonal.)r  r  rX   s    r$   is_diagonalDFM.is_diagonal  s    }}24==?2r.   c                     U R                   n[        U R                  5       H-  n[        U R                  5       H  nXU4   (       d  M      g   M/     g)z1Return ``True`` if the matrix is the zero matrix.FTr  r  s       r$   is_zero_matrixDFM.is_zero_matrix  sD    HHtyy!A499%T77  & " r.   c                 >    U R                  5       R                  5       $ )z5Return the number of non-zero elements in the matrix.)r\   nnzrX   s    r$   r$  DFM.nnz      {{}  ""r.   c                 >    U R                  5       R                  5       $ )z7Return the strongly connected components of the matrix.)r\   sccrX   s    r$   r(  DFM.scc  r&  r.   r   r   c                 6    U R                   R                  5       $ )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#   detrX   s    r$   r+  DFM.det  s    b xx||~r.   c                 ^    U R                   R                  5       R                  5       SSS2   $ )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coeffsrX   s    r$   r/  DFM.charpoly?  s*    T xx  "))+DbD11r.   c                 ^   U R                   nU R                  u  p#X#:w  a  [        S5      eU[        :X  a  [	        SU-  5      eU[
        :X  d  UR                  (       a*   U R                  U R                  R                  5       5      $ [        SU-  5      e! [         a    [        S5      ef = f)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   r;   r1   r#   invZeroDivisionErrorr   r>   )r0   KrO   r   s       r$   r3  DFM.invk  s    n KKzz6()LMM7 81 <=="WM}}TXX\\^44 &&Ka&OPP % M01KLLMs   (B B,c                     U R                  5       R                  5       u  pnUR                  5       UR                  5       U4$ )z*Return the LU decomposition of the matrix.)r\   lur~   )r0   LUswapss       r$   r8  DFM.lu  s3    kkm&&(exxz188:u,,r.   c                     U R                  5       R                  5       u  pUR                  5       UR                  5       4$ )z*Return the QR decomposition of the matrix.)r\   qrr~   )r0   QRs      r$   r>  DFM.qr  s/    {{}!xxz188:%%r.   c           
         U R                   UR                   :X  d'  [        SU R                   < SUR                   < 35      eU R                   R                  (       d  [        SU R                   -  5      eU R                  u  p#UR                  u  pEX$:w  a  [	        SU< SU< SU< SU< 35      eX54nX#:w  a;  U R                  5       R                  UR                  5       5      R                  5       $  U R                  R                  UR                  5      nU R                  XvU R                   5      $ ! [         a    [        S5      ef = f)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   r\   lu_solver~   r#   solver4  r   r   )r0   rhsrO   r   r   k	sol_shapesols           r$   rD  DFM.lu_solve  s	   \ {{cjj($++szz Z[[
 {{## 84;; FGGzzyy6QPQSTVWXYYF	 6;;=))#**,7>>@@	Q((..)C yy55 ! 	Q,-OPP	Qs   5%D6 6Ec                 z   U R                   [        :X  a  [        U R                  SS5      nUb  U R                  R	                  5       u  p#pEU R
                  u  pgU R                  X&U4U R                   5      U R                  X6U4U R                   5      U R                  XFU4U R                   5      U R                  XPR
                  U R                   5      4$ U R                  5       R	                  5       u  ppUR                  5       nU	R                  5       nU
R                  5       nUR                  5       nX#XE4$ )z
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#   rL  r    r   r\   r~   )r0   rL  Pr9  Dr:  rO   r   ddm_pddm_lddm_dddm_us               r$   rL  DFM.fflu  s     ;;"488VT2D!XX]]_
azzIIaQ5IIaQ5IIaQ5IIaT[[9	  &*[[]%7%7%9"eLLNLLNLLNLLNQzr.   c                 f    U R                  5       R                  5       u  pUR                  5       U4$ )/Return a basis for the nullspace of the matrix.)r\   	nullspacer~   )r0   r   	nonpivotss      r$   rW  DFM.nullspace5  s+    & 002zz|Y&&r.   Nc                 d    U R                  5       R                  US9u  p#UR                  5       U4$ )rV  )pivots)r{   nullspace_from_rrefr~   )r0   r[  sdmrX  s       r$   r\  DFM.nullspace_from_rrefK  s0     ::&:Izz|Y&&r.   c                 Z    U R                  5       R                  5       R                  5       $ )z+Return a particular solution to the system.)r\   
particularr~   rX   s    r$   r`  DFM.particularQ  s     {{}'')0022r.   c                     S nU" U5      nU" U5      nSUs=:  a  S:  d  O  [        S5      eU R                  u  pxU R                  R                  5       U:w  a  [	        S5      eU R                  R                  XX4US9$ )zACall the fmpz_mat.lll() method but check rank to avoid segfaults.c                     [         R                  " U 5      (       a+  [        U R                  5      [        U R                  5      -  $ [        U 5      $ rN   )r   of_typefloat	numeratordenominator)xs    r$   to_floatDFM._lll.<locals>.to_float_  s5    zz!}}Q[[)E!--,@@@Qx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)	r0   rk  rl  rm  r#   rn  ri  rO   r   s	            r$   _lllDFM._lllU  s{    	  smeaABB zz88==?aMNN xx||i#UY|ZZr.   c                     U R                   [        :w  a  [        SU R                   -  5      eU R                  U R                  :  a  [        S5      eU R                  US9nU R                  U5      $ )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.)rl  )r!   r   r
   r*   r+   r   rq  r1   )r0   rl  r#   s      r$   rp  DFM.llls  s`    , ;;" 5 CDDYY"MNNiiei$}}S!!r.   c                 T   U R                   [        :w  a  [        SU R                   -  5      eU R                  U R                  :  a  [        S5      eU R                  SUS9u  p#U R                  U5      nU R                  X0R                  U R                  4U R                   5      nXE4$ )a  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.
rt  ru  T)rk  rl  )	r!   r   r
   r*   r+   r   rq  r1   r   )r0   rl  r#   TbasisT_dfms         r$   lll_transformDFM.lll_transform  s    2 ;;" 5 CDDYY"MNNT7c"		!ii3T[[A|r.   rk   rN   )FgGz?gRQ?zbasisapprox)g      ?)R__name__
__module____qualname____firstlineno____doc__fmtis_DFMis_DDMr%   classmethodr   r1   r(   rC   r   propertyrK   r]   rb   rh   rl   rp   rs   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/  r3  r8  r>  rD  rL  rW  r\  r`  rq  rp  r{  __static_attributes__rk   r.   r$   r   r   E   s    D CFF,  7 M M G G M M, 1 1"/E , ,!3FF  C C 	' 	'"* A A& 9 9& 9 9$*M]]71<3(33//F
C 5 5 0 0
 + +
 3 3>TLL33## W-0 .0d W-)2 .)2V W-FQ .FQP-
&  W-H6 .H6TB','3[< W-" .": W-  . r.   )rv   )rz   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.ddmrv   rz   rk   r.   r$   <module>r     sv   T - 4 8 &   7u 	g ' '+l l ,l` ) (r.   