
    MZd                     0   d Z ddlmZmZmZ ddlmZ ddl	m
Z
 ddlmZ ddlmZ ddlmZ dTd	Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd ZdUdZd ZdUd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$ Z,d% Z-d& Z.d' Z/d( Z0d) Z1d* Z2d+ Z3d, Z4d- Z5d. Z6d/ Z7d0 Z8d1 Z9d2 Z:d3 Z;d4 Z<d5 Z=d6 Z>d7 Z?d8 Z@d9 ZAd: ZBd; ZCd< ZDd= ZEeDeEd>ZFd? ZGd@ ZHdA ZIdVdBZJdC ZKdD ZLdE ZMdF ZNdG ZOdH ZPdI ZQdJ ZRdK ZSeMeReSdLZTdTdMZUdN ZVdO ZWdP ZXdQ ZYdWdRZZdS Z[y)XzADense univariate polynomials with coefficients in Galois fields.     )ceilsqrtprod)uniform)
SYMPY_INTS)query)ExactQuotientFailed)_sort_factorsNc                     t        ||j                        }|j                  }t        | |      D ].  \  }}||z  }|j	                  ||      \  }}	}	||||z  |z  z  z  }0 ||z  S )aH  
    Chinese Remainder Theorem.

    Given a set of integer residues ``u_0,...,u_n`` and a set of
    co-prime integer moduli ``m_0,...,m_n``, returns an integer
    ``u``, such that ``u = u_i mod m_i`` for ``i = ``0,...,n``.

    Examples
    ========

    Consider a set of residues ``U = [49, 76, 65]``
    and a set of moduli ``M = [99, 97, 95]``. Then we have::

       >>> from sympy.polys.domains import ZZ
       >>> from sympy.polys.galoistools import gf_crt

       >>> gf_crt([49, 76, 65], [99, 97, 95], ZZ)
       639985

    This is the correct result because::

       >>> [639985 % m for m in [99, 97, 95]]
       [49, 76, 65]

    Note: this is a low-level routine with no error checking.

    See Also
    ========

    sympy.ntheory.modular.crt : a higher level crt routine
    sympy.ntheory.modular.solve_congruence

    start)r   onezerozipgcdex)
UMKpvumes_s
             9/usr/lib/python3/dist-packages/sympy/polys/galoistools.pygf_crtr      sv    D 	QaeeA	AAq	 1F''!Q-1a	Q!a[
 q5L    c                     g g }}t        | |j                        }| D ]@  }|j                  ||z         |j                  |j                  |d   |      d   |z         B |||fS )a  
    First part of the Chinese Remainder Theorem.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_crt1

    >>> gf_crt1([99, 97, 95], ZZ)
    (912285, [9215, 9405, 9603], [62, 24, 12])

    r   r   )r   r   appendr   )r   r   ESr   r   s         r   gf_crt1r$   9   sn     rqAQaeeA +	a	2"1%)*+ a7Nr   c                 p    |j                   }t        | |||      D ]  \  }}}	}
||	||
z  |z  z  z  } ||z  S )a`  
    Second part of the Chinese Remainder Theorem.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_crt2

    >>> U = [49, 76, 65]
    >>> M = [99, 97, 95]
    >>> p = 912285
    >>> E = [9215, 9405, 9603]
    >>> S = [62, 24, 12]

    >>> gf_crt2(U, M, p, E, S, ZZ)
    639985

    )r   r   )r   r   r   r"   r#   r   r   r   r   r   r   s              r   gf_crt2r&   Q   sO    ( 	
A!Q1o 
1a	Q!a[ q5Lr   c                      | |dz  k  r| S | |z
  S )z
    Coerce ``a mod p`` to an integer in the range ``[-p/2, p/2]``.

    Examples
    ========

    >>> from sympy.polys.galoistools import gf_int

    >>> gf_int(2, 7)
    2
    >>> gf_int(5, 7)
    -2

        )ar   s     r   gf_intr+   m   s     	AF{1ur   c                     t        |       dz
  S )z
    Return the leading degree of ``f``.

    Examples
    ========

    >>> from sympy.polys.galoistools import gf_degree

    >>> gf_degree([1, 1, 2, 0])
    3
    >>> gf_degree([])
    -1

       len)fs    r   	gf_degreer1      s     q6A:r   c                 (    | s|j                   S | d   S )z
    Return the leading coefficient of ``f``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_LC

    >>> gf_LC([3, 0, 1], ZZ)
    3

    r   r   r0   r   s     r   gf_LCr5      s     vvtr   c                 (    | s|j                   S | d   S )z
    Return the trailing coefficient of ``f``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_TC

    >>> gf_TC([3, 0, 1], ZZ)
    1

    r    r3   r4   s     r   gf_TCr7      s     vvur   c                 B    | r| d   r| S d}| D ]  }|r n|dz  } | |d S )z
    Remove leading zeros from ``f``.


    Examples
    ========

    >>> from sympy.polys.galoistools import gf_strip

    >>> gf_strip([0, 0, 0, 3, 0, 1])
    [3, 0, 1]

    r   r-   Nr)   )r0   kcoeffs      r   gf_stripr;      sB     !	A FA	 QR5Lr   c                 D    t        | D cg c]  }||z  	 c}      S c c}w )z
    Reduce all coefficients modulo ``p``.

    Examples
    ========

    >>> from sympy.polys.galoistools import gf_trunc

    >>> gf_trunc([7, -2, 3], 5)
    [2, 3, 3]

    )r;   )r0   r   r*   s      r   gf_truncr=      s!     Q(a!e())(s   c                 @    t        t        t        ||             |      S )z
    Normalize all coefficients in ``K``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_normal

    >>> gf_normal([5, 10, 21, -3], 5, ZZ)
    [1, 2]

    )r=   listmap)r0   r   r   s      r   	gf_normalrA      s     DQOQ''r   c                 |   t        | j                               g }}t        |t              rAt	        |dd      D ]0  }|j                  | j                  ||j                        |z         2 nE|\  }t	        |dd      D ]1  }|j                  | j                  |f|j                        |z         3 t        ||      S )a  
    Create a ``GF(p)[x]`` polynomial from a dict.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_from_dict

    >>> gf_from_dict({10: ZZ(4), 4: ZZ(33), 0: ZZ(-1)}, 5, ZZ)
    [4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4]

    r    )	maxkeys
isinstancer   ranger!   getr   r=   )r0   r   r   nhr9   s         r   gf_from_dictrJ      s     qvvx="qA!Z q"b! 	+AHHQUU1aff%)*	+ q"b! 	.AHHQUUA4(1,-	. Aq>r   c                     t        |       i }}t        d|dz         D ]'  }|rt        | ||z
     |      }n| ||z
     }|s#|||<   ) |S )aA  
    Convert a ``GF(p)[x]`` polynomial to a dict.

    Examples
    ========

    >>> from sympy.polys.galoistools import gf_to_dict

    >>> gf_to_dict([4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4], 5)
    {0: -1, 4: -2, 10: -1}
    >>> gf_to_dict([4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4], 5, symmetric=False)
    {0: 4, 4: 3, 10: 4}

    r   r-   )r1   rF   r+   )r0   r   	symmetricrH   resultr9   r*   s          r   
gf_to_dictrN     sa     !bvA1a!e_ qQx#A!a%AF1I Mr   c                     t        | |      S )z
    Create a ``GF(p)[x]`` polynomial from ``Z[x]``.

    Examples
    ========

    >>> from sympy.polys.galoistools import gf_from_int_poly

    >>> gf_from_int_poly([7, -2, 3], 5)
    [2, 3, 3]

    )r=   )r0   r   s     r   gf_from_int_polyrP   2  s     Aq>r   c                 H    |r| D cg c]  }t        ||       c}S | S c c}w )a  
    Convert a ``GF(p)[x]`` polynomial to ``Z[x]``.


    Examples
    ========

    >>> from sympy.polys.galoistools import gf_to_int_poly

    >>> gf_to_int_poly([2, 3, 3], 5)
    [2, -2, -2]
    >>> gf_to_int_poly([2, 3, 3], 5, symmetric=False)
    [2, 3, 3]

    )r+   )r0   r   rL   cs       r   gf_to_int_polyrS   B  s(      '(*!1** +s   c                 4    | D cg c]  }| |z  
 c}S c c}w )z
    Negate a polynomial in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_neg

    >>> gf_neg([3, 2, 1, 0], 5, ZZ)
    [2, 3, 4, 0]

    r)   )r0   r   r   r:   s       r   gf_negrU   X  s     &'(EeVaZ(((s   c                 d    | s||z  }n"| d   |z   |z  }t        |       dkD  r	| dd |gz   S |sg S |gS )a  
    Compute ``f + a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_add_ground

    >>> gf_add_ground([3, 2, 4], 2, 5, ZZ)
    [3, 2, 1]

    r    r-   Nr.   r0   r*   r   r   s       r   gf_add_groundrX   i  sM     ErUQY!Oq6A:Sb6QC<	s
r   c                 f    | s| |z  }n"| d   |z
  |z  }t        |       dkD  r	| dd |gz   S |sg S |gS )a  
    Compute ``f - a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_sub_ground

    >>> gf_sub_ground([3, 2, 4], 2, 5, ZZ)
    [3, 2, 2]

    r    r-   Nr.   rW   s       r   gf_sub_groundrZ     sO     BFrUQY!Oq6A:Sb6QC<	s
r   c                 @    |sg S | D cg c]
  }||z  |z   c}S c c}w )a  
    Compute ``f * a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_mul_ground

    >>> gf_mul_ground([3, 2, 4], 2, 5, ZZ)
    [1, 4, 3]

    r)   )r0   r*   r   r   bs        r   gf_mul_groundr]     s(     	$%'q!A#'''s   c                 >    t        | |j                  ||      ||      S )a  
    Compute ``f/a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_quo_ground

    >>> gf_quo_ground(ZZ.map([3, 2, 4]), ZZ(2), 5, ZZ)
    [4, 1, 2]

    )r]   invertrW   s       r   gf_quo_groundr`     s     AHHQNAq11r   c                 \   | s|S |s| S t        |       }t        |      }||k(  r.t        t        | |      D cg c]  \  }}||z   |z   c}}      S t        ||z
        }||kD  r| d| | |d } }	n
|d| ||d }}	|	t        | |      D cg c]  \  }}||z   |z   c}}z   S c c}}w c c}}w )z
    Add polynomials in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_add

    >>> gf_add([3, 2, 4], [2, 2, 2], 5, ZZ)
    [4, 1]

    N)r1   r;   r   abs
r0   gr   r   dfdgr*   r\   r9   rI   s
             r   gf_addrg     s     	1B	1B	Rx#a)=$!Q1q5A+=>>RL7Ra5!AB%qARa5!AB%qASAY8TQa!eq[888 > 9s   B"

B(c                    |s| S | st        |||      S t        |       }t        |      }||k(  r.t        t        | |      D cg c]  \  }}||z
  |z   c}}      S t	        ||z
        }||kD  r| d| | |d } }	nt        |d| ||      ||d }}	|	t        | |      D cg c]  \  }}||z
  |z   c}}z   S c c}}w c c}}w )z
    Subtract polynomials in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_sub

    >>> gf_sub([3, 2, 4], [2, 2, 2], 5, ZZ)
    [1, 0, 2]

    N)rU   r1   r;   r   rb   rc   s
             r   gf_subri     s     aA	1B	1B	Rx#a)=$!Q1q5A+=>>RL7Ra5!AB%qA!BQ%A&!"qASAY8TQa!eq[888 > 9s   B8
 B>c                 (   t        |       }t        |      }||z   }dg|dz   z  }t        d|dz         D ]R  }|j                  }	t        t        d||z
        t	        ||      dz         D ]  }
|	| |
   |||
z
     z  z  }	 |	|z  ||<   T t        |      S )z
    Multiply polynomials in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_mul

    >>> gf_mul([3, 2, 4], [2, 2, 2], 5, ZZ)
    [1, 0, 3, 2, 3]

    r   r-   r1   rF   r   rC   minr;   )r0   rd   r   r   re   rf   dhrI   ir:   js              r   gf_mulrp     s     
1B	1B	bB	
R!VA1b1f s1a"f~s1bzA~6 	#AQqT!AE(]"E	# qy! A;r   c                 t   t        |       }d|z  }dg|dz   z  }t        d|dz         D ]  }|j                  }t        d||z
        }t	        ||      }	|	|z
  dz   }
||
dz  z   dz
  }	t        ||	dz         D ]  }|| |   | ||z
     z  z  } ||z  }|
dz  r| |	dz      }||dz  z  }||z  ||<    t        |      S )z
    Square polynomials in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_sqr

    >>> gf_sqr([3, 2, 4], 5, ZZ)
    [4, 2, 3, 1, 1]

    r(   r   r-   rk   )r0   r   r   re   rm   rI   rn   r:   jminjmaxrH   ro   elems                r   gf_sqrru   +  s     
1B	
2B	
R!VA1b1f 1a"f~1bz4K!Oa1f}q tTAX& 	#AQqT!AE(]"E	# 	q5TAX;DT1WEqy!'* A;r   c           	      6    t        | t        ||||      ||      S )a  
    Returns ``f + g*h`` where ``f``, ``g``, ``h`` in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_add_mul
    >>> gf_add_mul([3, 2, 4], [2, 2, 2], [1, 4], 5, ZZ)
    [2, 3, 2, 2]
    )rg   rp   r0   rd   rI   r   r   s        r   
gf_add_mulrx   V  s      !VAq!Q'A..r   c           	      6    t        | t        ||||      ||      S )a  
    Compute ``f - g*h`` where ``f``, ``g``, ``h`` in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_sub_mul

    >>> gf_sub_mul([3, 2, 4], [2, 2, 2], [1, 4], 5, ZZ)
    [3, 3, 2, 1]

    )ri   rp   rw   s        r   
gf_sub_mulrz   e  s      !VAq!Q'A..r   c                     t        | t              r| \  }} n|j                  }|g}| D ]!  \  }}t        ||||      }t	        ||||      }# |S )a  
    Expand results of :func:`~.factor` in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_expand

    >>> gf_expand([([3, 2, 4], 1), ([2, 2], 2), ([3, 1], 3)], 5, ZZ)
    [4, 3, 0, 3, 0, 1, 4, 1]

    )rE   tupler   gf_powrp   )Fr   r   lcrd   r0   r9   s          r   	gf_expandr   v  sa     !UAUU	A 11aA1aA Hr   c                    t        |       }t        |      }|st        d      ||k  rg | fS |j                  |d   |      }t        |       ||z
  |dz
  }	}}t	        d|dz         D ]^  }
||
   }t	        t        d||
z
        t        ||
z
  |	      dz         D ]  }|||
|z   |z
     |||z
     z  z  } |
|k  r||z  }||z  ||
<   ` |d|dz    t        ||dz   d       fS )a	  
    Division with remainder in ``GF(p)[x]``.

    Given univariate polynomials ``f`` and ``g`` with coefficients in a
    finite field with ``p`` elements, returns polynomials ``q`` and ``r``
    (quotient and remainder) such that ``f = q*g + r``.

    Consider polynomials ``x**3 + x + 1`` and ``x**2 + x`` in GF(2)::

       >>> from sympy.polys.domains import ZZ
       >>> from sympy.polys.galoistools import gf_div, gf_add_mul

       >>> gf_div(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ)
       ([1, 1], [1])

    As result we obtained quotient ``x + 1`` and remainder ``1``, thus::

       >>> gf_add_mul(ZZ.map([1]), ZZ.map([1, 1]), ZZ.map([1, 1, 0]), 2, ZZ)
       [1, 0, 1, 1]

    References
    ==========

    .. [1] [Monagan93]_
    .. [2] [Gathen99]_

    polynomial divisionr   r-   N)r1   ZeroDivisionErrorr_   r?   rF   rC   rl   r;   r0   rd   r   r   re   rf   invrI   dqdrrn   r:   ro   s                r   gf_divr     s   8 
1B	1B 566	b1u
((1Q4
CQb"q&2rA1b1f 	!s1b1f~s262':; 	/AQq1urz]QrAvY..E	/ 7SLEqy!	 Wb1f:x"q&'
+++r   c                 $    t        | |||      d   S )z
    Compute polynomial remainder in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_rem

    >>> gf_rem(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ)
    [1]

    r-   )r   r0   rd   r   r   s       r   gf_remr     s     !Q1a  r   c                    t        |       }t        |      }|st        d      ||k  rg S |j                  |d   |      }| dd ||z
  |dz
  }	}}t        d|dz         D ]W  }
||
   }t        t	        d||
z
        t        ||
z
  |	      dz         D ]  }|||
|z   |z
     |||z
     z  z  } ||z  |z  ||
<   Y |d|dz    S )aG  
    Compute exact quotient in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_quo

    >>> gf_quo(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ)
    [1, 1]
    >>> gf_quo(ZZ.map([1, 0, 3, 2, 3]), ZZ.map([2, 2, 2]), 5, ZZ)
    [3, 2, 4]

    r   r   Nr-   )r1   r   r_   rF   rC   rl   r   s                r   gf_quor     s      
1B	1B 566	b	
((1Q4
C!b2grAv2rA1b1f !!s1b1f~s262':; 	/AQq1urz]QrAvY..E	/ q !! Wb1f:r   c                 D    t        | |||      \  }}|s|S t        | |      )a  
    Compute polynomial quotient in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_exquo

    >>> gf_exquo(ZZ.map([1, 0, 3, 2, 3]), ZZ.map([2, 2, 2]), 5, ZZ)
    [3, 2, 4]

    >>> gf_exquo(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ)
    Traceback (most recent call last):
    ...
    ExactQuotientFailed: [1, 1, 0] does not divide [1, 0, 1, 1]

    )r   r	   )r0   rd   r   r   qrs         r   gf_exquor      s-    & !Q1DAq!!Q''r   c                 0    | s| S | |j                   g|z  z   S )z
    Efficiently multiply ``f`` by ``x**n``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_lshift

    >>> gf_lshift([3, 2, 4], 4, ZZ)
    [3, 2, 4, 0, 0, 0, 0]

    r3   r0   rH   r   s      r   	gf_lshiftr     s      AFF8A:~r   c                 &    |s| g fS | d|  | | d fS )z
    Efficiently divide ``f`` by ``x**n``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_rshift

    >>> gf_rshift([1, 2, 3, 4, 0], 3, ZZ)
    ([1, 2], [3, 4, 0])

    Nr)   r   s      r   	gf_rshiftr   /  s*     "u1"vq!v~r   c                     |s|j                   gS |dk(  r| S |dk(  rt        | ||      S |j                   g}	 |dz  rt        || ||      }|dz  }|dz  }|s	 |S t        | ||      } 0)z
    Compute ``f**n`` in ``GF(p)[x]`` using repeated squaring.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_pow

    >>> gf_pow([3, 2, 4], 3, 5, ZZ)
    [2, 4, 4, 2, 2, 1, 4]

    r-   r(   )r   ru   rp   )r0   rH   r   r   rI   s        r   r}   r}   C  s     w	
a	
aaA	
A
q5q!Q"AFA	a H 1aO r   c                    t        |       }|dk(  rg S dg|z  }dg|d<   ||k  r7t        d|      D ]&  }t        ||dz
     ||      }t        || ||      ||<   ( |S |dkD  rgt	        |j
                  |j                  g|| ||      |d<   t        d|      D ]0  }t        ||dz
     |d   ||      ||<   t        ||   | ||      ||<   2 |S )ah  
    return the list of ``x**(i*p) mod g in Z_p`` for ``i = 0, .., n - 1``
    where ``n = gf_degree(g)``

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_frobenius_monomial_base
    >>> g = ZZ.map([1, 0, 2, 1])
    >>> gf_frobenius_monomial_base(g, 5, ZZ)
    [[1], [4, 4, 2], [1, 2]]

    r   r-   r(   )r1   rF   r   r   
gf_pow_modr   r   rp   )rd   r   r   rH   r\   rn   mons          r   gf_frobenius_monomial_baser   h  s     	!AAv		
AA3AaD1uq! 	(AAa!eHa+C#q!Q'AaD	( H 
Q155!&&/1aA6!q! 	)A!AE(AaD!Q/AaD!A$1a(AaD	) Hr   c                     t        |      }t        |       |k\  rt        | |||      } | sg S t        |       }| d   g}t        d|dz         D ]'  }t        ||   | ||z
     ||      }	t	        ||	||      }) |S )aS  
    compute gf_pow_mod(f, p, g, p, K) using the Frobenius map

    Parameters
    ==========

    f, g : polynomials in ``GF(p)[x]``
    b : frobenius monomial base
    p : prime number
    K : domain

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_frobenius_monomial_base, gf_frobenius_map
    >>> f = ZZ.map([2, 1, 0, 1])
    >>> g = ZZ.map([1, 0, 2, 1])
    >>> p = 5
    >>> b = gf_frobenius_monomial_base(g, p, ZZ)
    >>> r = gf_frobenius_map(f, g, b, p, ZZ)
    >>> gf_frobenius_map(f, g, b, p, ZZ)
    [4, 0, 3]
    r    r-   )r1   r   rF   r]   rg   )
r0   rd   r\   r   r   r   rH   sfrn   r   s
             r   gf_frobenius_mapr     s    2 	!A|q1aA	!A
B%B1a!e_ !!A$!a%!Q/B1a ! Ir   c                     t        | |||      } | }| }t        d|      D ]-  }t        |||||      }t        ||||      }t        ||||      }/ t	        ||dz
  dz  |||      }	|	S )z
    utility function for ``gf_edf_zassenhaus``
    Compute ``f**((p**n - 1) // 2)`` in ``GF(p)[x]/(g)``
    ``f**((p**n - 1) // 2) = (f*f**p*...*f**(p**n - 1))**((p - 1) // 2)``
    r-   r(   )r   rF   r   rp   r   )
r0   rH   rd   r\   r   r   rI   r   rn   ress
             r   _gf_pow_pnm1d2r     s     	q!QA	A	A1a[ Q1a+1aA1aA
 QQ
Aq!
,CJr   c                 6   |s|j                   gS |dk(  rt        | |||      S |dk(  rt        t        | ||      |||      S |j                   g}	 |dz  r!t        || ||      }t        ||||      }|dz  }|dz  }|s	 |S t        | ||      } t        | |||      } L)a*  
    Compute ``f**n`` in ``GF(p)[x]/(g)`` using repeated squaring.

    Given polynomials ``f`` and ``g`` in ``GF(p)[x]`` and a non-negative
    integer ``n``, efficiently computes ``f**n (mod g)`` i.e. the remainder
    of ``f**n`` from division by ``g``, using the repeated squaring algorithm.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_pow_mod

    >>> gf_pow_mod(ZZ.map([3, 2, 4]), 3, ZZ.map([1, 1]), 5, ZZ)
    []

    References
    ==========

    .. [1] [Gathen99]_

    r-   r(   )r   r   ru   rp   )r0   rH   rd   r   r   rI   s         r   r   r     s    . w	
aaAq!!	
afQ1oq!Q//	
A
q5q!Q"Aq!Q"AFA	a
 H 1aO1aA r   c                 L    |r|t        | |||      }} |rt        | ||      d   S )z
    Euclidean Algorithm in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_gcd

    >>> gf_gcd(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ)
    [1, 3]

    r-   )r   gf_monicr   s       r   gf_gcdr     s6     &Aq!$1  Aq!Qr   c           	      z    | r|sg S t        t        | |||      t        | |||      ||      }t        |||      d   S )z
    Compute polynomial LCM in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_lcm

    >>> gf_lcm(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ)
    [1, 2, 0, 4]

    r-   )r   rp   r   r   r0   rd   r   r   rI   s        r   gf_lcmr     sM     A	vaAq!aAq!1a	)A Aq!Qr   c                 j    | s|sg g g fS t        | |||      }|t        | |||      t        ||||      fS )a   
    Compute polynomial GCD and cofactors in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_cofactors

    >>> gf_cofactors(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ)
    ([1, 3], [3, 3], [2, 1])

    )r   r   r   s        r   gf_cofactorsr     sM     QB|q!QAvaAq!1aA   r   c                    | s|s|j                   gg g fS t        | ||      \  }}t        |||      \  }}| sg |j                  ||      g|fS |s|j                  ||      gg |fS |j                  ||      gg }	}g |j                  ||      g}}
	 t        ||||      \  }}|sndt        |||      |c\  }}}|j                  ||      }t	        ||	|||      }t	        |
||||      }t        ||||      |	}}	t        ||||      |}
}x|	||fS )a  
    Extended Euclidean Algorithm in ``GF(p)[x]``.

    Given polynomials ``f`` and ``g`` in ``GF(p)[x]``, computes polynomials
    ``s``, ``t`` and ``h``, such that ``h = gcd(f, g)`` and ``s*f + t*g = h``.
    The typical application of EEA is solving polynomial diophantine equations.

    Consider polynomials ``f = (x + 7) (x + 1)``, ``g = (x + 7) (x**2 + 1)``
    in ``GF(11)[x]``. Application of Extended Euclidean Algorithm gives::

       >>> from sympy.polys.domains import ZZ
       >>> from sympy.polys.galoistools import gf_gcdex, gf_mul, gf_add

       >>> s, t, g = gf_gcdex(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ)
       >>> s, t, g
       ([5, 6], [6], [1, 7])

    As result we obtained polynomials ``s = 5*x + 6`` and ``t = 6``, and
    additionally ``gcd(f, g) = x + 7``. This is correct because::

       >>> S = gf_mul(s, ZZ.map([1, 8, 7]), 11, ZZ)
       >>> T = gf_mul(t, ZZ.map([1, 7, 1, 7]), 11, ZZ)

       >>> gf_add(S, T, 11, ZZ) == [1, 7]
       True

    References
    ==========

    .. [1] [Gathen99]_

    )r   r   r_   r   rz   r]   )r0   rd   r   r   p0r0p1r1s0s1t0t1QRr   r   r   ts                     r   gf_gcdexr   1  sI   B wBaAFBaAFBAHHRO$b((Q "b((hhr1oB!((2q/"B
b"a#11a("R"hhr1or2q!Q'r2q!Q'q#q!,bBq#q!,bB   r2:r   c                     | s|j                   g fS | d   }|j                  |      r|t        |       fS |t        | |||      fS )z
    Compute LC and a monic polynomial in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_monic

    >>> gf_monic(ZZ.map([3, 2, 4]), 5, ZZ)
    (3, [1, 4, 3])

    r   )r   is_oner?   r`   )r0   r   r   r   s       r   r   r   s  sM     vvrzqT88B<tAw;}QAq111r   c                     t        |       }|j                  g|z  |}}| dd D ]!  }| ||      z  }||z  }|r||||z
  <   |dz  }# t        |      S )z
    Differentiate polynomial in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_diff

    >>> gf_diff([3, 2, 4], 5, ZZ)
    [1, 2]

    Nr    r-   )r1   r   r;   )r0   r   r   re   rI   rH   r:   s          r   gf_diffr     sp     
1BFF8B;qA3B 1
Ab1fI	Q A;r   c                 J    |j                   }| D ]  }||z  }||z  }||z  } |S )z
    Evaluate ``f(a)`` in ``GF(p)`` using Horner scheme.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_eval

    >>> gf_eval([3, 2, 4], 2, 5, ZZ)
    0

    r3   )r0   r*   r   r   rM   rR   s         r   gf_evalr     s>     VVF !!!
 Mr   c           	      D    |D cg c]  }t        | |||       c}S c c}w )a  
    Evaluate ``f(a)`` for ``a`` in ``[a_1, ..., a_n]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_multi_eval

    >>> gf_multi_eval([3, 2, 4], [0, 1, 2, 3, 4], 5, ZZ)
    [4, 4, 0, 2, 0]

    )r   )r0   Ar   r   r*   s        r   gf_multi_evalr     s#     +,-QWQ1a ---s   c           	          t        |      dk  r"t        t        | t        ||      ||      g      S | sg S | d   g}| dd D ]  }t	        ||||      }t        ||||      }  |S )a  
    Compute polynomial composition ``f(g)`` in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_compose

    >>> gf_compose([3, 2, 4], [2, 2, 2], 5, ZZ)
    [2, 4, 0, 3, 0]

    r-   r   N)r/   r;   r   r5   rp   rX   )r0   rd   r   r   rI   rR   s         r   
gf_composer     s}     1v{E!QKA6788		
1AqrU &1aA!Q1%& Hr   c                     | sg S | d   g}| dd D ],  }t        ||||      }t        ||||      }t        ||||      }. |S )a&  
    Compute polynomial composition ``g(h)`` in ``GF(p)[x]/(f)``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_compose_mod

    >>> gf_compose_mod(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 2]), ZZ.map([4, 3]), 5, ZZ)
    [4]

    r   r-   N)rp   rX   r   )rd   rI   r0   r   r   compr*   s          r   gf_compose_modr     sc     	aD6DqrU %dAq!$T1a+dAq!$%
 Kr   c           
      J   t        | ||||      }|}|dz  rt        | |||      }	|}
n| }	|}
|dz  }|rat        |t        |||||      ||      }t        |||||      }|dz  r*t        |	t        ||
|||      ||      }	t        ||
|||      }
|dz  }|rat        | |
|||      |	fS )a  
    Compute polynomial trace map in ``GF(p)[x]/(f)``.

    Given a polynomial ``f`` in ``GF(p)[x]``, polynomials ``a``, ``b``,
    ``c`` in the quotient ring ``GF(p)[x]/(f)`` such that ``b = c**t
    (mod f)`` for some positive power ``t`` of ``p``, and a positive
    integer ``n``, returns a mapping::

       a -> a**t**n, a + a**t + a**t**2 + ... + a**t**n (mod f)

    In factorization context, ``b = x**p mod f`` and ``c = x mod f``.
    This way we can efficiently compute trace polynomials in equal
    degree factorization routine, much faster than with other methods,
    like iterated Frobenius algorithm, for large degrees.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_trace_map

    >>> gf_trace_map([1, 2], [4, 4], [1, 1], 4, [3, 2, 4], 5, ZZ)
    ([1, 3], [1, 3])

    References
    ==========

    .. [1] [Gathen92]_

    r-   )r   rg   )r*   r\   rR   rH   r0   r   r   r   r   r   Vs              r   gf_trace_mapr     s    > 	q!Q1%A	A1u1aA!GA
1nQ1a3Q:1aAq)q5q.Aq!Q7A>Aq!Q1-A	a  !Q1a(!++r   c                     t        | |||      } | }| }t        d|      D ]-  }t        |||||      }t        ||||      }t        ||||      }/ |S )z&
    utility for ``gf_edf_shoup``
    r-   )r   rF   r   rg   )	r0   rH   rd   r\   r   r   rI   r   rn   s	            r   _gf_trace_mapr   B  sl     	q!QA	A	A1a[ Q1a+1aA1aA Hr   c                     |j                   gt        d|       D cg c]  } |t        t        d|                   c}z   S c c}w )a  
    Generate a random polynomial in ``GF(p)[x]`` of degree ``n``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_random
    >>> gf_random(10, 5, ZZ) #doctest: +SKIP
    [1, 2, 3, 2, 1, 1, 1, 2, 0, 4, 2]

    r   )r   rF   intr   )rH   r   r   rn   s       r   	gf_randomr   P  s9     EE7eAqkCqWQ]+,CCCCs   "Ac                 >    	 t        | ||      }t        |||      r|S )a,  
    Generate random irreducible polynomial of degree ``n`` in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_irreducible
    >>> gf_irreducible(10, 5, ZZ) #doctest: +SKIP
    [1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]

    )r   gf_irreducible_p)rH   r   r   r0   s       r   gf_irreducibler   `  s+     aAAq!$H r   c                    t        |       }|dk  ryt        | ||      \  }} |dk  rt        |j                  |j                  g|| ||      x}}t        d|dz        D ]S  }t        ||j                  |j                  g||      }t        | |||      |j                  gk(  rt        ||| ||      }S y yt        | ||      }	t        |j                  |j                  g| |	||      x}}t        d|dz        D ]S  }t        ||j                  |j                  g||      }t        | |||      |j                  gk(  rt        || |	||      }S y y)a_  
    Ben-Or's polynomial irreducibility test over finite fields.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_irred_p_ben_or

    >>> gf_irred_p_ben_or(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ)
    True
    >>> gf_irred_p_ben_or(ZZ.map([3, 2, 4]), 5, ZZ)
    False

    r-   T   r   r(   F)r1   r   r   r   r   rF   ri   r   r   r   r   )
r0   r   r   rH   r   HrI   rn   rd   r\   s
             r   gf_irred_p_ben_orr   s  sV     	!AAvAq!DAq1uAEE166?Aq!Q77Aq!Q$ 	Aq155!&&/1a0AaAq!aeeW,"1aAq1	"  'q!Q/ !%%!Q1==Aq!Q$ 	Aq155!&&/1a0AaAq!aeeW,$Q1a3	 r   c                    t        |       }|dk  ryt        | ||      \  }} |j                  |j                  g}ddlm}  ||      D ch c]  }||z  	 }}t        | ||      }	|	d   }
t        d|      D ]A  }||v r,t        |
|||      }t        | |||      |j                  gk7  r yt        |
| |	||      }
C |
|k(  S c c}w )a[  
    Rabin's polynomial irreducibility test over finite fields.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_irred_p_rabin

    >>> gf_irred_p_rabin(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ)
    True
    >>> gf_irred_p_rabin(ZZ.map([3, 2, 4]), 5, ZZ)
    False

    r-   Tr   	factorintF)r1   r   r   r   sympy.ntheoryr   r   rF   ri   r   r   )r0   r   r   rH   r   xr   dindicesr\   rI   rn   rd   s                r   gf_irred_p_rabinr     s      	!AAvAq!DAq	
A''l,1,G,"1a+A	!A1a[ ,<q!Q"AaAq!aeeW,Q1a+, 6M -s   
B?)zben-orrabinc                 ^    t        d      }|t        |   | ||      }|S t        | ||      }|S )a[  
    Test irreducibility of a polynomial ``f`` in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_irreducible_p

    >>> gf_irreducible_p(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ)
    True
    >>> gf_irreducible_p(ZZ.map([3, 2, 4]), 5, ZZ)
    False

    GF_IRRED_METHOD)r   _irred_methodsr   )r0   r   r   methodirreds        r   r   r     sD      $%Fv&q!Q/ L !Aq)Lr   c                 v    t        | ||      \  }} | syt        | t        | ||      ||      |j                  gk(  S )a5  
    Return ``True`` if ``f`` is square-free in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_sqf_p

    >>> gf_sqf_p(ZZ.map([3, 2, 4]), 5, ZZ)
    True
    >>> gf_sqf_p(ZZ.map([2, 4, 4, 2, 2, 1, 4]), 5, ZZ)
    False

    T)r   r   r   r   )r0   r   r   r   s       r   gf_sqf_pr     sA      Aq!DAqaAq)1a0QUUG;;r   c                 p    t        | ||      \  }}|j                  g}|D ]  \  } }t        || ||      } |S )a  
    Return square-free part of a ``GF(p)[x]`` polynomial.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_sqf_part

    >>> gf_sqf_part(ZZ.map([1, 1, 3, 0, 1, 0, 2, 2, 1]), 5, ZZ)
    [1, 4, 3]

    )gf_sqf_listr   rp   )r0   r   r   r   sqfrd   s         r   gf_sqf_partr     sK     Aq!FAs	
A 11aA Hr   c                    ddg t        |      f\  }}}}t        | ||      \  }} t        |       dk  r|g fS 	 t        | ||      }	|	g k7  rt	        | |	||      }
t        | |
||      }d}||j                  gk7  rft	        |
|||      }t        ||||      }t        |      dkD  r|j                  |||z  f       t        |
|||      ||dz   }}}
||j                  gk7  rf|
|j                  gk(  rd}n|
} |s;t        |       |z  }t        d|dz         D ]  }| ||z     | |<    | d|dz    ||z  }} nn|rt        d      ||fS )a  
    Return the square-free decomposition of a ``GF(p)[x]`` polynomial.

    Given a polynomial ``f`` in ``GF(p)[x]``, returns the leading coefficient
    of ``f`` and a square-free decomposition ``f_1**e_1 f_2**e_2 ... f_k**e_k``
    such that all ``f_i`` are monic polynomials and ``(f_i, f_j)`` for ``i != j``
    are co-prime and ``e_1 ... e_k`` are given in increasing order. All trivial
    terms (i.e. ``f_i = 1``) are not included in the output.

    Consider polynomial ``f = x**11 + 1`` over ``GF(11)[x]``::

       >>> from sympy.polys.domains import ZZ

       >>> from sympy.polys.galoistools import (
       ...     gf_from_dict, gf_diff, gf_sqf_list, gf_pow,
       ... )
       ... # doctest: +NORMALIZE_WHITESPACE

       >>> f = gf_from_dict({11: ZZ(1), 0: ZZ(1)}, 11, ZZ)

    Note that ``f'(x) = 0``::

       >>> gf_diff(f, 11, ZZ)
       []

    This phenomenon does not happen in characteristic zero. However we can
    still compute square-free decomposition of ``f`` using ``gf_sqf()``::

       >>> gf_sqf_list(f, 11, ZZ)
       (1, [([1, 1], 11)])

    We obtained factorization ``f = (x + 1)**11``. This is correct because::

       >>> gf_pow([1, 1], 11, 11, ZZ) == f
       True

    References
    ==========

    .. [1] [Geddes92]_

    r-   FTr   Nz'all=True' is not supported yet)
r   r   r1   r   r   r   r   r!   rF   
ValueError)r0   r   r   allrH   r   factorsr   r   r~   rd   rI   rn   Gr   r   s                   r   r   r     s   V E2s1v-AsGQQ1EB|a2v
Aq!7q!Q"Aq!Q"AAw,1aA&1aA&Q<!#NNAqs8, Aq!,aQa1 w, QUUG|!!A1a!e_ 1v! Va!e9acqA? B :;;w;r   c           	         t        |       t        |      }}|j                  g|j                  g|dz
  z  z   }t	        |      gg g|dz
  z  z   }t        d|dz
  |z  dz         D ]g  }|d    | d   z  |z  g|d   }	}t        d|      D ])  }
|j                  ||
dz
     |	| |
 dz
     z  z
  |z         + ||z  st	        |      |||z  <   |}i |S )ad  
    Calculate Berlekamp's ``Q`` matrix.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_Qmatrix

    >>> gf_Qmatrix([3, 2, 4], 5, ZZ)
    [[1, 0],
     [3, 4]]

    >>> gf_Qmatrix([1, 0, 0, 0, 1], 5, ZZ)
    [[1, 0, 0, 0],
     [0, 4, 0, 0],
     [0, 0, 1, 0],
     [0, 0, 0, 4]]

    r-   r    )r1   r   r   r   r?   rF   r!   )r0   r   r   rH   r   r   r   rn   qqrR   ro   s              r   
gf_Qmatrixr   t  s    * Q<QqA	
166(AE""A	a	RD!a%L A1q1uai!m$ 	R5&2,!#$aeAq! 	4AIIqQx!Aqb1fI+-23	4 A2hAadG	 Hr   c                 ~   | D cg c]  }t        |       c}t        |       }} t        d|      D ]   }| |   |   |j                  z
  |z  | |   |<   " t        d|      D ]  }t        ||      D ]  }| |   |   s n |j	                  | |   |   |      }t        d|      D ]  }| |   |   |z  |z  | |   |<    t        d|      D ]   }| |   |   }	| |   |   | |   |<   |	| |   |<   " t        d|      D ]>  }||k7  s	| |   |   }t        d|      D ]  }| |   |   | |   |   |z  z
  |z  | |   |<   ! @  t        d|      D ]I  }t        d|      D ]8  }||k(  r|j                  | |   |   z
  |z  | |   |<   '| |   |    |z  | |   |<   : K g }
| D ]  }t        |      s|
j                  |       ! |
S c c}w )a_  
    Compute a basis of the kernel of ``Q``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_Qmatrix, gf_Qbasis

    >>> gf_Qbasis(gf_Qmatrix([1, 0, 0, 0, 1], 5, ZZ), 5, ZZ)
    [[1, 0, 0, 0], [0, 0, 1, 0]]

    >>> gf_Qbasis(gf_Qmatrix([3, 2, 4], 5, ZZ), 5, ZZ)
    [[1, 0]]

    r   )r?   r/   rF   r   r_   anyr!   )r   r   r   r   rH   r9   rn   r   ro   r   basiss              r   	gf_Qbasisr     s7   "  !T!W!3q6qA1a[ (Q47QUU?a'!Q( 1a[ 8q! 	AtAw	 hhqtAw"q! 	(AtAws{a'AaDG	( q! 	A!QAd1gAaDGAaDG	
 q! 	8AAvaDGq! 8A tAw1a2a7AaDG8		8#80 1a[ )q! 	)AAv551Q47?a/!QaDG8q.!Q		)) E q6LLO LU "s   F:c                 z   t        | ||      }t        |||      }t        |      D ]%  \  }}t        t	        t        |                  ||<   ' | g}t        dt        |            D ]  }t	        |      D ]  } |j                  }	|	|k  st        ||   |	||      }
t        | |
||      }||j                  gk7  r7|| k7  r2|j                  |        t        | |||      } |j                  | |g       t        |      t        |      k(  rt        |d      c c S |	|j                  z  }	|	|k  r  t        |d      S )a  
    Factor a square-free ``f`` in ``GF(p)[x]`` for small ``p``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_berlekamp

    >>> gf_berlekamp([1, 0, 0, 0, 1], 5, ZZ)
    [[1, 0, 2], [1, 0, 3]]

    r-   Fmultiple)r   r   	enumerater;   r?   reversedrF   r/   r   rZ   r   r   remover   extendr
   )r0   r   r   r   r   rn   r   r   r9   r   rd   rI   s               r   gf_berlekampr     s9    	1aA!QA! +1Xa[)*!+ cG1c!f g 	AAa%!!A$1a01aA&<AFNN1%q!Q*ANNAq6*w<3q6)(5AAQUU
 a%	& 511r   c           	          d|j                   |j                  gg }}}t        | ||      }d|z  t        |       k  rt	        || |||      }t        | t        ||j                   |j                  g||      ||      }||j                   gk7  r<|j                  ||f       t        | |||      } t        || ||      }t        | ||      }|dz  }d|z  t        |       k  r| |j                   gk7  r|| t        |       fgz   S |S )a{  
    Cantor-Zassenhaus: Deterministic Distinct Degree Factorization

    Given a monic square-free polynomial ``f`` in ``GF(p)[x]``, computes
    partial distinct degree factorization ``f_1 ... f_d`` of ``f`` where
    ``deg(f_i) != deg(f_j)`` for ``i != j``. The result is returned as a
    list of pairs ``(f_i, e_i)`` where ``deg(f_i) > 0`` and ``e_i > 0``
    is an argument to the equal degree factorization routine.

    Consider the polynomial ``x**15 - 1`` in ``GF(11)[x]``::

       >>> from sympy.polys.domains import ZZ
       >>> from sympy.polys.galoistools import gf_from_dict

       >>> f = gf_from_dict({15: ZZ(1), 0: ZZ(-1)}, 11, ZZ)

    Distinct degree factorization gives::

       >>> from sympy.polys.galoistools import gf_ddf_zassenhaus

       >>> gf_ddf_zassenhaus(f, 11, ZZ)
       [([1, 0, 0, 0, 0, 10], 1), ([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2)]

    which means ``x**15 - 1 = (x**5 - 1) (x**10 + x**5 + 1)``. To obtain
    factorization into irreducibles, use equal degree factorization
    procedure (EDF) with each of the factors.

    References
    ==========

    .. [1] [Gathen99]_
    .. [2] [Geddes92]_

    r-   r(   )
r   r   r   r1   r   r   ri   r!   r   r   )r0   r   r   rn   rd   r   r\   rI   s           r   gf_ddf_zassenhausr     s   F qvv'qA"1a+A
A#1
Q1a+1fQA61=<NNAq6"q!Q"Aq!Q"A*1a3A	Q A#1
 	QUUG|1il+,,,r   c           	         | g}t        |       |k  r|S t        |       |z  }|dk7  rt        | ||      }|j                  |j                  g}t	        |      |k  r|dk(  r^|x}}	t        |dz
        D ]  }
t        |	d| ||      }	t        ||	||      }! t        | |||      }||j                  |j                  gz  }nGt        d|z  dz
  ||      }	t        |	|| ||      }t        | t        ||j                  ||      ||      }||j                  gk7  r.|| k7  r)t        ||||      t        t        | |||      |||      z   }t	        |      |k  rt        |d      S )a  
    Cantor-Zassenhaus: Probabilistic Equal Degree Factorization

    Given a monic square-free polynomial ``f`` in ``GF(p)[x]`` and
    an integer ``n``, such that ``n`` divides ``deg(f)``, returns all
    irreducible factors ``f_1,...,f_d`` of ``f``, each of degree ``n``.
    EDF procedure gives complete factorization over Galois fields.

    Consider the square-free polynomial ``f = x**3 + x**2 + x + 1`` in
    ``GF(5)[x]``. Let's compute its irreducible factors of degree one::

       >>> from sympy.polys.domains import ZZ
       >>> from sympy.polys.galoistools import gf_edf_zassenhaus

       >>> gf_edf_zassenhaus([1,1,1,1], 1, 5, ZZ)
       [[1, 1], [1, 2], [1, 3]]

    Notes
    =====

    The case p == 2 is handled by Cohen's Algorithm 3.4.8. The case p odd is
    as in Geddes Algorithm 8.9 (or Cohen's Algorithm 3.4.6).

    References
    ==========

    .. [1] [Gathen99]_
    .. [2] [Geddes92]_ Algorithm 8.9
    .. [3] [Cohen93]_ Algorithm 3.4.8

    r(   r-   Fr   )r1   r   r   r   r/   rF   r   rg   r   r   r   rZ   gf_edf_zassenhausr   r
   )r0   rH   r   r   r   Nr\   r   rI   r   rn   rd   s               r   r   r   ?  sw   @ cG|q!AAv&q!Q/	
A
g,
6IA1q5\ 'q!Q1-1aA&' q!Q"A!&&!&&!!A!a%!)Q*Aq!Q1a0Aq-155!Q7A>A<AF'1a3#F1aA$61a@AG! g,
& 511r   c                    t        |       }t        t        t        |dz                    }t	        | ||      }t        |j                  |j                  g| |||      }|j                  |j                  g|g|j                  g|dz
  z  z   }t        d|dz         D ]  }t        ||dz
     | |||      ||<    ||   |d| }}|g|j                  g|dz
  z  z   }	t        d|      D ]  }t        |	|dz
     || ||      |	|<    g }
t        |	      D ]  \  }}|j                  g|dz
  }}|D ],  }t        ||||      }t        ||||      }t        || ||      }. t        | |||      }t        | |||      } t!        |      D ]]  }t        ||||      }t        ||||      }||j                  gk7  r|
j#                  |||dz   z  |z
  f       t        ||||      |dz
  }}_  | |j                  gk7  r|
j#                  | t        |       f       |
S )a  
    Kaltofen-Shoup: Deterministic Distinct Degree Factorization

    Given a monic square-free polynomial ``f`` in ``GF(p)[x]``, computes
    partial distinct degree factorization ``f_1,...,f_d`` of ``f`` where
    ``deg(f_i) != deg(f_j)`` for ``i != j``. The result is returned as a
    list of pairs ``(f_i, e_i)`` where ``deg(f_i) > 0`` and ``e_i > 0``
    is an argument to the equal degree factorization routine.

    This algorithm is an improved version of Zassenhaus algorithm for
    large ``deg(f)`` and modulus ``p`` (especially for ``deg(f) ~ lg(p)``).

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_ddf_shoup, gf_from_dict

    >>> f = gf_from_dict({6: ZZ(1), 5: ZZ(-1), 4: ZZ(1), 3: ZZ(1), 1: ZZ(-1)}, 3, ZZ)

    >>> gf_ddf_shoup(f, 3, ZZ)
    [([1, 1, 0], 1), ([1, 1, 0, 1, 2], 2)]

    References
    ==========

    .. [1] [Kaltofen98]_
    .. [2] [Shoup95]_
    .. [3] [Gathen92]_

    r(   r-   N)r1   r   _ceil_sqrtr   r   r   r   rF   r   r   ri   rp   r   r   r   r   r!   )r0   r   r   rH   r9   r\   rI   r   rn   r   r   r   ro   r   rd   r~   s                   r   gf_ddf_shoupr    sE   @ 	!AE%1+A"1a+A!%%!Q15A
%%!xQ//A1a!e_ 4!A#1a3!4 Q42AqA	
qvvhAA1a[ 4aAh1a3!4 G! -1wA1 	#Aq!Q"Aq!Q"Aq!Q"A	#
 1aA1aA! 	-Aq!Q"Aq!Q"AQUUG|1a!e9q=12!Q1%q1uqA	--( 	QUUG|9Q<()Nr   c           	         t        |       t        |      }}|sg S ||k  r| gS | g|j                  |j                  g}}t	        |dz
  ||      }|dk(  r`t        ||| ||      }	t        ||	||dz
  | ||      d   }
t        | |
||      }t        | |||      }t        ||||      t        ||||      z   }nt        | ||      }t        ||| |||      }
t        |
|dz
  dz  | ||      }	t        | |	||      }t        | t        |	|j                  ||      ||      }t        | t        ||||      ||      }t        ||||      t        ||||      z   t        ||||      z   }t        |d      S )a  
    Gathen-Shoup: Probabilistic Equal Degree Factorization

    Given a monic square-free polynomial ``f`` in ``GF(p)[x]`` and integer
    ``n`` such that ``n`` divides ``deg(f)``, returns all irreducible factors
    ``f_1,...,f_d`` of ``f``, each of degree ``n``. This is a complete
    factorization over Galois fields.

    This algorithm is an improved version of Zassenhaus algorithm for
    large ``deg(f)`` and modulus ``p`` (especially for ``deg(f) ~ lg(p)``).

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_edf_shoup

    >>> gf_edf_shoup(ZZ.map([1, 2837, 2277]), 1, 2917, ZZ)
    [[1, 852], [1, 1985]]

    References
    ==========

    .. [1] [Shoup91]_
    .. [2] [Gathen92]_

    r-   r(   Fr   )r1   r   r   r   r   r   r   r   r   gf_edf_shoupr   r   rZ   rp   r
   )r0   rH   r   r   r  r   r   r   r   rI   r   h1h2r\   h3s                  r   r  r    s   8 Q<QqA	Avs
quuaffoQG!a%AAAvq!Q1%Aq!a%Aq1!4Aq!QAr1a r1a+2q!Q'( 'q!Q/!Q1a+q1q51*aA.Aq!QA}Qq!4a;Avb"a+Q2r1a+2q!Q'(2q!Q'( 511r   c                 l    g }t        | ||      D ]  \  }}|t        ||||      z  } t        |d      S )a  
    Factor a square-free ``f`` in ``GF(p)[x]`` for medium ``p``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_zassenhaus

    >>> gf_zassenhaus(ZZ.map([1, 4, 3]), 5, ZZ)
    [[1, 1], [1, 3]]

    Fr   )r   r   r
   r0   r   r   r   factorrH   s         r   gf_zassenhausr  
  sJ     G&q!Q/ 6	$VQ1556 511r   c                 l    g }t        | ||      D ]  \  }}|t        ||||      z  } t        |d      S )a  
    Factor a square-free ``f`` in ``GF(p)[x]`` for large ``p``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_shoup

    >>> gf_shoup(ZZ.map([1, 4, 3]), 5, ZZ)
    [[1, 1], [1, 3]]

    Fr   )r  r  r
   r  s         r   gf_shoupr     sI     G!!Q* 1	<1a001 511r   )	berlekamp
zassenhausshoupc                     t        | ||      \  }} t        |       dk  r|g fS |xs t        d      }|t        |   | ||      }||fS t	        | ||      }||fS )a  
    Factor a square-free polynomial ``f`` in ``GF(p)[x]``.

    Examples
    ========

    >>> from sympy.polys.domains import ZZ
    >>> from sympy.polys.galoistools import gf_factor_sqf

    >>> gf_factor_sqf(ZZ.map([3, 2, 4]), 5, ZZ)
    (3, [[1, 1], [1, 3]])

    r-   GF_FACTOR_METHOD)r   r1   r   _factor_methodsr  )r0   r   r   r   r   r   s         r   gf_factor_sqfr  <  sz     Q1EB|a2v0u/0F!&)!Q2 w;  1a(w;r   c                     t        | ||      \  }} t        |       dk  r|g fS g }t        | ||      d   D ]-  \  }}t        |||      d   D ]  }|j	                  ||f        / |t        |      fS )a  
    Factor (non square-free) polynomials in ``GF(p)[x]``.

    Given a possibly non square-free polynomial ``f`` in ``GF(p)[x]``,
    returns its complete factorization into irreducibles::

                 f_1(x)**e_1 f_2(x)**e_2 ... f_d(x)**e_d

    where each ``f_i`` is a monic polynomial and ``gcd(f_i, f_j) == 1``,
    for ``i != j``.  The result is given as a tuple consisting of the
    leading coefficient of ``f`` and a list of factors of ``f`` with
    their multiplicities.

    The algorithm proceeds by first computing square-free decomposition
    of ``f`` and then iteratively factoring each of square-free factors.

    Consider a non square-free polynomial ``f = (7*x + 1) (x + 2)**2`` in
    ``GF(11)[x]``. We obtain its factorization into irreducibles as follows::

       >>> from sympy.polys.domains import ZZ
       >>> from sympy.polys.galoistools import gf_factor

       >>> gf_factor(ZZ.map([5, 2, 7, 2]), 11, ZZ)
       (5, [([1, 2], 1), ([1, 8], 2)])

    We arrived with factorization ``f = 5 (x + 2) (x + 8)**2``. We did not
    recover the exact form of the input polynomial because we requested to
    get monic factors of ``f`` and its leading coefficient separately.

    Square-free factors of ``f`` can be factored into irreducibles over
    ``GF(p)`` using three very different methods:

    Berlekamp
        efficient for very small values of ``p`` (usually ``p < 25``)
    Cantor-Zassenhaus
        efficient on average input and with "typical" ``p``
    Shoup-Kaltofen-Gathen
        efficient with very large inputs and modulus

    If you want to use a specific factorization method, instead of the default
    one, set ``GF_FACTOR_METHOD`` with one of ``berlekamp``, ``zassenhaus`` or
    ``shoup`` values.

    References
    ==========

    .. [1] [Gathen99]_

    r-   )r   r1   r   r  r!   r
   )r0   r   r   r   r   rd   rH   rI   s           r   	gf_factorr  Y  s    d Q1EB|a2vGAq!$Q' #1q!Q'* 	#ANNAq6"	## }W%%%r   c                 ,    d}| D ]  }||z  }||z  } |S )z
    Value of polynomial 'f' at 'a' in field R.

    Examples
    ========

    >>> from sympy.polys.galoistools import gf_value

    >>> gf_value([1, 7, 2, 4], 11)
    2204

    r   r)   )r0   r*   rM   rR   s       r   gf_valuer    s1     F !! Mr   c                     ddl m} | |z  dk(  r||z  dk(  rt        t        |            S g S  || |      \  }}}||z  dk7  rg S t        |      D cg c]  }||z  |z  ||z  |z  z   |z   c}S c c}w )a  
    Returns the values of x satisfying a*x congruent b mod(m)

    Here m is positive integer and a, b are natural numbers.
    This function returns only those values of x which are distinct mod(m).

    Examples
    ========

    >>> from sympy.polys.galoistools import linear_congruence

    >>> linear_congruence(3, 12, 15)
    [4, 9, 14]

    There are 3 solutions distinct mod(15) since gcd(a, m) = gcd(3, 15) = 3.

    References
    ==========

    .. [1] https://en.wikipedia.org/wiki/Linear_congruence_theorem

    r   )r   )sympy.polys.polytoolsr   r?   rF   )r*   r\   r   r   r   r   rd   r   s           r   linear_congruencer    s    . ,1uzq5A:a>!IAqkGAq!1uz	388<aQUaZ!a%1*$)<<<s   A/c                     ddl m} t        |||      }t        ||       }t        ||        ||z  z  }t	        |||      S )a0  
    Used in gf_csolve to generate solutions of f(x) cong 0 mod(p**(s + 1))
    from the solutions of f(x) cong 0 mod(p**s).

    Examples
    ========

    >>> from sympy.polys.galoistools import _raise_mod_power
    >>> from sympy.polys.galoistools import csolve_prime

    These is the solutions of f(x) = x**2 + x + 7 cong 0 mod(3)

    >>> f = [1, 1, 7]
    >>> csolve_prime(f, 3)
    [1]
    >>> [ i for i in range(3) if not (i**2 + i + 7) % 3]
    [1]

    The solutions of f(x) cong 0 mod(9) are constructed from the
    values returned from _raise_mod_power:

    >>> x, s, p = 1, 1, 3
    >>> V = _raise_mod_power(x, s, p, f)
    >>> [x + v * p**s for v in V]
    [1, 4, 7]

    And these are confirmed with the following:

    >>> [ i for i in range(3**2) if not (i**2 + i + 7) % 3**2]
    [1, 4, 7]

    r   ZZ)sympy.polys.domainsr!  r   r  r  )r   r   r   r0   r!  f_falphabetas           r   _raise_mod_powerr&    sH    B '
!Q
CS!Ea^q!t#DUD!,,r   c           	         ddl m} t        |      D cg c]  }t        | |||      dk(  s| }}|dk(  r|S g }t	        t        |dgt        |      z              }|rj|j                         \  }}	|	|k(  r|j                  |       n=|	dz   }
||	z  }|j                  t        ||	||       D cg c]  }|||z  z   |
f c}       |rjt        |      S c c}w c c}w )aU  
    Solutions of f(x) congruent 0 mod(p**e).

    Examples
    ========

    >>> from sympy.polys.galoistools import csolve_prime

    >>> csolve_prime([1, 1, 7], 3, 1)
    [1]
    >>> csolve_prime([1, 1, 7], 3, 2)
    [1, 4, 7]

    Solutions [7, 4, 1] (mod 3**2) are generated by ``_raise_mod_power()``
    from solution [1] (mod 3).
    r   r   r-   )r"  r!  rF   r   r?   r   r/   popr!   r   r&  sorted)r0   r   r   r!  rn   X1Xr#   r   r   r   psr   s                r   csolve_primer-    s    " '1X	;Aq"!5!:!	;B	;Av	
ASaSR[!"A
uuw16HHQKQBABHH.>q!Q.JKq1R4xnKL  !9 
< Ls   CC-Cc           
         ddl m} ddlm}  ||      }|j	                         D cg c]  \  }}t        | ||       }}}t        t        t        |            }g g}	|D ]  }
|	D cg c]  }|
D ]  }||gz   
  }	}}  |j	                         D cg c]  \  }}t        ||       }}}t        |	D cg c]  }t        |||       c}      S c c}}w c c}}w c c}}w c c}w )a=  
    To solve f(x) congruent 0 mod(n).

    n is divided into canonical factors and f(x) cong 0 mod(p**e) will be
    solved for each factor. Applying the Chinese Remainder Theorem to the
    results returns the final answers.

    Examples
    ========

    Solve [1, 1, 7] congruent 0 mod(189):

    >>> from sympy.polys.galoistools import gf_csolve
    >>> gf_csolve([1, 1, 7], 189)
    [13, 49, 76, 112, 139, 175]

    References
    ==========

    .. [1] 'An introduction to the Theory of Numbers' 5th Edition by Ivan Niven,
           Zuckerman and Montgomery.

    r   r   r   )r"  r!  r   r   itemsr-  r?   r@   r|   powr)  r   )r0   rH   r!  r   Pr   r   r+  poolspermspoolr   ydist_factorspers                  r   	gf_csolver8  	  s    0 ''!A+,779541aaA	5A5UAEDE 7"'6Q6AaS6667*+'')4$!QC1I4L4EBS6#|R0BCC 	6 74Bs   C(CC6C#)N)T)F)r-   )\__doc__mathr   r  r   r  r   sympy.core.randomr   sympy.external.gmpyr   sympy.polys.polyconfigr   sympy.polys.polyerrorsr	   sympy.polys.polyutilsr
   r   r$   r&   r+   r1   r5   r7   r;   r=   rA   rJ   rN   rP   rS   rU   rX   rZ   r]   r`   rg   ri   rp   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  r&  r-  r8  r)   r   r   <module>r@     s   G 3 3 % * ( 6 /*Z08*$((8* ("8: ,)"88((2" 9F 9F>(V//"83,l!"$N(6((#J@#J".b ( . .?D22<0.":65,nD &*Z)X  4<00Vr%P;|)2X6r=2@JX<2~2,2, :=&@( =F%-PD!Dr   