
    MZd*                     ~    d dl mZ ddlmZmZmZmZ ddlmZ 	 ddZ		 	 ddZ
efdZed	d	fd
Zed	fdZed	ddfdZy)    )FunctionType   )_get_intermediate_simp_iszero_dotprodsimp	_simplify)_find_reasonable_pivotTc	                 ~     fd}	 fd}
 fd}t        t              d\  }}g }g }|k  r||k  rt         |	|      |d ||      \  }}}}|D ]  \  }}||z  }| |z  |z   <    ||dz  }I|j                  |       |dk7  r" |
|||z          |j                  |||z   f       |du rB||}}| |z  |z   <   t	        |z  |z   dz   |dz   z        D ]  }  |   |z         |<    |}t	        |      D ]1  }||k(  r	|du r||k  r |z  |z      } ||      r' |||||       3 |dz  }|k  r||k  r|d	u r^|d	u rZt        |      D ]L  \  }} |z  |z      }| |z  |z   <   t	        |z  |z   dz   |dz   z        D ]  }  |   |z         |<    N  t        |      t        |      fS )
a  Row reduce a flat list representation of a matrix and return a tuple
    (rref_matrix, pivot_cols, swaps) where ``rref_matrix`` is a flat list,
    ``pivot_cols`` are the pivot columns and ``swaps`` are any row swaps that
    were used in the process of row reduction.

    Parameters
    ==========

    mat : list
        list of matrix elements, must be ``rows`` * ``cols`` in length

    rows, cols : integer
        number of rows and columns in flat list representation

    one : SymPy object
        represents the value one, from ``Matrix.one``

    iszerofunc : determines if an entry can be used as a pivot

    simpfunc : used to simplify elements and test if they are
        zero if ``iszerofunc`` returns `None`

    normalize_last : indicates where all row reduction should
        happen in a fraction-free manner and then the rows are
        normalized (so that the pivots are 1), or whether
        rows should be normalized along the way (like the naive
        row reduction algorithm)

    normalize : whether pivot rows should be normalized so that
        the pivot value is 1

    zero_above : whether entries above the pivot should be zeroed.
        If ``zero_above=False``, an echelon matrix will be returned.
    c                     | d    S N )icolsmats    ;/usr/lib/python3/dist-packages/sympy/matrices/reductions.pyget_colz!_row_reduce_list.<locals>.get_col,   s    17d7|    c                 p    |z  |dz   z   | z  | dz   z   c| z  | dz   z   |z  |dz   z   y )Nr   r   )r   jr   r   s     r   row_swapz"_row_reduce_list.<locals>.row_swap/   s]    $At|$c!D&!a%&> 	;AdFAE4< #afa!eT\":r   c                     ||z
  z  }t        |z  |dz   z        D ]  } | |   z  |||z      z  z
        |<   ! y)z,Does the row op row[i] = a*row[i] - b*row[j]r   N)range)	ar   br   qpr   isimpr   s	         r   cross_cancelz&_row_reduce_list.<locals>.cross_cancel3   sY    UDLqvAt|, 	4A1SV8aAE
l23CF	4r   r   r   Nr   r   FT)r   r   r	   appendr   	enumeratetuple)r   rowsr   one
iszerofuncsimpfuncnormalize_last	normalize
zero_abover   r   r   piv_rowpiv_col
pivot_colsswapspivot_offset	pivot_valassumed_nonzeronewly_determinedoffsetvalr   r   r   rowpiv_ipiv_jr   s   ` `                         @r   _row_reduce_listr7      s|   J?4 #<0EGWJE D.Wt^,B *J-B	*i)
 . 	-MVSgF),Ctg%&	- qLG'"1WlW45LL'<'#9:; U"GqA!C$
O1T6A:>AE4<8 3s1v	12A3 I ; 	7Cg~U"sW}c$h()C#Cg6	7 	1Y D.Wt^^ )t"3%j1 	3LE5E$J./I&)Cd
U"#5:-1EAIt3CD 3s1v	12A3	3 j!5<//r   c                     t        t        |       | j                  | j                  | j                  |||||	      \  }}}| j                  | j                  | j                  |      ||fS )Nr'   r(   r)   )r7   listr#   r   r$   _new)	Mr%   r&   r'   r(   r)   r   r,   r-   s	            r   _row_reducer=   y   s]     .d1gqvvqvvquuJ8CU 66!&&!&&#&
E99r   c                     | j                   dk  s| j                  dk  ryt        fd| dddf   D              } | d         r|xr t        | ddddf         S |xr t        | ddddf         S )zReturns `True` if the matrix is in echelon form. That is, all rows of
    zeros are at the bottom, and below each leading non-zero in a row are
    exclusively zeros.r   Tc              3   .   K   | ]  } |        y wr   r   ).0tr%   s     r   	<genexpr>z_is_echelon.<locals>.<genexpr>   s     6jm6s   r   Nr   )r#   r   all_is_echelon)r<   r%   zeros_belows    ` r   rD   rD      s}    
 	vv{affk6Qqr1uX66K!D'@{1QU8Z@@=;qQRy*==r   Fc                 l    t        |t              r|nt        }t        | ||ddd      \  }}}|r||fS |S )an  Returns a matrix row-equivalent to ``M`` that is in echelon form. Note
    that echelon form of a matrix is *not* unique, however, properties like the
    row space and the null space are preserved.

    Examples
    ========

    >>> from sympy import Matrix
    >>> M = Matrix([[1, 2], [3, 4]])
    >>> M.echelon_form()
    Matrix([
    [1,  2],
    [0, -2]])
    TFr9   
isinstancer   r   r=   )r<   r%   simplifywith_pivotsr&   r   pivots_s           r   _echelon_formrM      sF      &h=x9H J5UDNC F{Jr   c                    d }t        |t              r|nt        }| j                  dk  s| j                  dk  ry| j                  dk  s| j                  dk  r| D cg c]
  } ||       }}d|v ry| j                  dk(  rU| j                  dk(  rF| D cg c]
  } ||       }}d|vrd|vry| j                         } ||      rd|v ry ||      du ry || |      \  }}	t        |||ddd	      \  }	}
}	t        |
      S c c}w c c}w )
zReturns the rank of a matrix.

    Examples
    ========

    >>> from sympy import Matrix
    >>> from sympy.abc import x
    >>> m = Matrix([[1, 2], [x, 1 - 1/x]])
    >>> m.rank()
    2
    >>> n = Matrix(3, 3, range(1, 10))
    >>> n.rank()
    2
    c                       fd}t         j                        D cg c]  } ||      |f }}t        |      D cg c]  \  }}|	 }}} j                  |d      |fS c c}w c c}}w )a  Permute columns with complicated elements as
        far right as they can go.  Since the ``sympy`` row reduction
        algorithms start on the left, having complexity right-shifted
        speeds things up.

        Returns a tuple (mat, perm) where perm is a permutation
        of the columns to perform to shift the complex columns right, and mat
        is the permuted matrix.c                 :    t        fdd d | f   D              S )Nc              3   6   K   | ]  } |      dnd  y w)Nr   r   r   )r@   er%   s     r   rB   zO_rank.<locals>._permute_complexity_right.<locals>.complexity.<locals>.<genexpr>   s     JQJqM1qq8Js   )sum)r   r<   r%   s    r   
complexityz<_rank.<locals>._permute_complexity_right.<locals>.complexity   s     J!AqD'JJJr   r   )orientation)r   r   sortedpermute)r<   r%   rT   r   complexr   perms   ``     r   _permute_complexity_rightz(_rank.<locals>._permute_complexity_right   sj    	K
 05QVV}=!JqM1%==#)'?3!Q133		$F	3T:: >3s   A%A*r   r   F   N)r%   Tr9   )rH   r   r   r#   r   detr=   len)r<   r%   rI   rZ   r&   xzerosdr   rL   rK   s              r   _rankra      s    ;( &h=x9H
 	vv{affkvv{affk()*1A**E>vv{qvv{()*1A**$e"3EEGa=Ue^a=E!,Q:FFCsJ/LAvq v;- + +s   DD	c                 l    t        |t              r|nt        }t        | |||dd      \  }}}|r||f}|S )a'	  Return reduced row-echelon form of matrix and indices of pivot vars.

    Parameters
    ==========

    iszerofunc : Function
        A function used for detecting whether an element can
        act as a pivot.  ``lambda x: x.is_zero`` is used by default.

    simplify : Function
        A function used to simplify elements when looking for a pivot.
        By default SymPy's ``simplify`` is used.

    pivots : True or False
        If ``True``, a tuple containing the row-reduced matrix and a tuple
        of pivot columns is returned.  If ``False`` just the row-reduced
        matrix is returned.

    normalize_last : True or False
        If ``True``, no pivots are normalized to `1` until after all
        entries above and below each pivot are zeroed.  This means the row
        reduction algorithm is fraction free until the very last step.
        If ``False``, the naive row reduction procedure is used where
        each pivot is normalized to be `1` before row operations are
        used to zero above and below the pivot.

    Examples
    ========

    >>> from sympy import Matrix
    >>> from sympy.abc import x
    >>> m = Matrix([[1, 2], [x, 1 - 1/x]])
    >>> m.rref()
    (Matrix([
    [1, 0],
    [0, 1]]), (0, 1))
    >>> rref_matrix, rref_pivots = m.rref()
    >>> rref_matrix
    Matrix([
    [1, 0],
    [0, 1]])
    >>> rref_pivots
    (0, 1)

    ``iszerofunc`` can correct rounding errors in matrices with float
    values. In the following example, calling ``rref()`` leads to
    floating point errors, incorrectly row reducing the matrix.
    ``iszerofunc= lambda x: abs(x)<1e-9`` sets sufficiently small numbers
    to zero, avoiding this error.

    >>> m = Matrix([[0.9, -0.1, -0.2, 0], [-0.8, 0.9, -0.4, 0], [-0.1, -0.8, 0.6, 0]])
    >>> m.rref()
    (Matrix([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 0]]), (0, 1, 2))
    >>> m.rref(iszerofunc=lambda x:abs(x)<1e-9)
    (Matrix([
    [1, 0, -0.301369863013699, 0],
    [0, 1, -0.712328767123288, 0],
    [0, 0,         0,          0]]), (0, 1))

    Notes
    =====

    The default value of ``normalize_last=True`` can provide significant
    speedup to row reduction, especially on matrices with symbols.  However,
    if you depend on the form row reduction algorithm leaves entries
    of the matrix, set ``noramlize_last=False``
    T)r(   r)   rG   )	r<   r%   rI   rK   r'   r&   r   r,   rL   s	            r   _rrefrc      sG    R &h=x9H$Q
Hdt=CQ JJr   N)TTT)typesr   	utilitiesr   r   r   r   determinantr	   r7   r=   rD   rM   ra   rc   r   r   r   <module>rg      sd     O O / AEn0d 9=+/: & >  !(%U 8  % CL  %Qr   