
    Ed                     2   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 dWd	Zd
 Zd Zd Zd Zd Zd Zd Zd Zd Zd ZdXdZd ZdXd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/ Z6d0 Z7d1 Z8d2 Z9d3 Z:d4 Z;d5 Z<d6 Z=d7 Z>d8 Z?d9 Z@d: ZAd; ZBd< ZCd= ZDd> ZEeDeEd?ZFd@ ZGdA ZHdB ZIdYdDZJdE ZKdF ZLdG ZMdH ZNdI ZOdJ ZPdK ZQdL ZRdM ZSeMeReSdNZTdWdOZUdP ZVdQ ZWdR ZXdS ZYdZdUZZdV Z[dS )[zADense univariate polynomials with coefficients in Galois fields.     )ceilsqrtprod)uniform)
SYMPY_INTS)query)ExactQuotientFailed)_sort_factorsNc                     t          ||j                  }|j        }t          | |          D ]2\  }}||z  }|                    ||          \  }}	}	||||z  |z  z  z  }3||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
             7lib/python3.11/site-packages/sympy/polys/galoistools.pygf_crtr      s|    D 	QaeA	AAq		  1F''!Q--1a	Q!a[q5L    c                     g g }}t          | |j                  }| D ]R}|                    ||z             |                    |                    |d         |          d         |z             S|||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   s     rqAQaeA + +	a	2""1%)****a7Nr   c                 j    |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1oo  
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     q66A: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      v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      vur   c                 N    | 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;      sU      ! 	A   	EFAAQRR5Lr   c                 :    t          fd| D                       S )z
    Reduce all coefficients modulo ``p``.

    Examples
    ========

    >>> from sympy.polys.galoistools import gf_trunc

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

    c                     g | ]}|z  S r)   r)   ).0r*   r   s     r   
<listcomp>zgf_trunc.<locals>.<listcomp>   s    (((a!e(((r   )r;   r0   r   s    `r   gf_truncrA      s(     ((((Q((()))r   c                 X    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]

    )rA   listmapr0   r   r   s      r   	gf_normalrF      s"     DQOOQ'''r   c                    t          |                                           g }}t          |t                    rFt	          |dd          D ]3}|                    |                     ||j                  |z             4nJ|\  }t	          |dd          D ]4}|                    |                     |f|j                  |z             5t          ||          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   rA   )r0   r   r   nhr9   s         r   gf_from_dictrO      s     qvvxx=="qA!Z   .q"b!! 	+ 	+AHHQUU1af%%)****	+ q"b!! 	. 	.AHHQUUA4((1,----Aq>>r   Tc                     t          |           i }}t          d|dz             D ]0}|rt          | ||z
           |          }n| ||z
           }|r|||<   1|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   rK   r+   )r0   r   	symmetricrM   resultr9   r*   s          r   
gf_to_dictrS     ss     !bvA1a!e__   	qQx##AA!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]

    )rA   r@   s     r   gf_from_int_polyrU   2  s     Aq>>r   c                 (    |rfd| D             S | S )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]

    c                 0    g | ]}t          |          S r)   )r+   )r>   cr   s     r   r?   z"gf_to_int_poly.<locals>.<listcomp>S  s!    ***!1***r   r)   )r0   r   rQ   s    ` r   gf_to_int_polyrY   B  s,       ****q****r   c                      fd| D             S )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]

    c                     g | ]}| z  	S r)   r)   )r>   r:   r   s     r   r?   zgf_neg.<locals>.<listcomp>f  s    (((EeVaZ(((r   r)   rE   s    ` r   gf_negr\   X  s     )(((Q((((r   c                 ~    | s||z  }n/| d         |z   |z  }t          |           dk    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_groundr_   i  sb       ErUQY!Oq66A: 	 SbS6QC< 	s
r   c                     | s| |z  }n/| d         |z
  |z  }t          |           dk    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.   r^   s       r   gf_sub_groundra     sd       BFrUQY!Oq66A: 	 SbS6QC< 	s
r   c                 ,    sg S fd| D             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_mul_ground

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

    c                      g | ]
}|z  z  S r)   r)   )r>   br*   r   s     r   r?   z!gf_mul_ground.<locals>.<listcomp>  s!    '''q!A#'''r   r)   r^   s    `` r   gf_mul_groundre     s0      (	'''''A''''r   c                 N    t          | |                    ||          ||          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]

    )re   invertr^   s       r   gf_quo_groundrh     s$     AHHQNNAq111r   c                 n   | s|S |s| S t          |           }t          |          }||k    r)t          fdt          | |          D                       S t          ||z
            }||k    r| d|         | |d         } }n|d|         ||d         }}|fdt          | |          D             z   S )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]

    c                 &    g | ]\  }}||z   z  S r)   r)   r>   r*   rd   r   s      r   r?   zgf_add.<locals>.<listcomp>  %    ===$!Q1q5A+===r   Nc                 &    g | ]\  }}||z   z  S r)   r)   rk   s      r   r?   zgf_add.<locals>.<listcomp>  %    888TQa!eq[888r   )r1   r;   r   absr0   gr   r   dfdgr9   rN   s     `     r   gf_addrt     s       	1B	1B	Rx 
9====#a))===>>>RLL7 	 RaR5!ABB%qAARaR5!ABB%qA8888SAYY88888r   c                    |s| S | st          ||          S t          |           }t          |          }||k    r)t          fdt          | |          D                       S t	          ||z
            }||k    r| d|         | |d         } }n#t          |d|         |          ||d         }}|fdt          | |          D             z   S )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]

    c                 &    g | ]\  }}||z
  z  S r)   r)   rk   s      r   r?   zgf_sub.<locals>.<listcomp>   rl   r   Nc                 &    g | ]\  }}||z
  z  S r)   r)   rk   s      r   r?   zgf_sub.<locals>.<listcomp>	  rn   r   )r\   r1   r;   r   ro   rp   s     `     r   gf_subrx     s       aA	1B	1B	Rx 
9====#a))===>>>RLL7 	.RaR5!ABB%qAA!BQB%A&&!""qA8888SAYY88888r   c                 Z   t          |           }t          |          }||z   }dg|dz   z  }t          d|dz             D ]]}|j        }	t          t          d||z
            t	          ||          dz             D ]}
|	| |
         |||
z
           z  z  }	|	|z  ||<   ^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   rK   r   rH   minr;   )r0   rq   r   r   rr   rs   dhrN   ir:   js              r   gf_mulr     s     
1B	1B	bB	
R!VA1b1f  s1a"f~~s1bzzA~66 	# 	#AQqT!AE(]"EEqy!A;;r   c                    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-   rz   )r0   r   r   rr   r|   rN   r}   r:   jminjmaxrM   r~   elems                r   gf_sqrr   +  s    
1B	
2B	
R!VA1b1f  1a"f~~1bzz4K!Oa1f}q tTAX&& 	# 	#AQqT!AE(]"EEq5 	TAX;DT1WEqy!A;;r   c           	      F    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]
    )rt   r   r0   rq   rN   r   r   s        r   
gf_add_mulr   V  s&     !VAq!Q''A...r   c           	      F    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]

    )rx   r   r   s        r   
gf_sub_mulr   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]

    )rJ   tupler   gf_powr   )Fr   r   lcrq   r0   r9   s          r   	gf_expandr   v  so     !U AAU	A  11aA1aAHr   c                 8   t          |           }t          |          }|st          d          ||k     rg | fS |                    |d         |          }t          |           ||z
  |dz
  }	}}t	          d|dz             D ]r}
||
         }t	          t          d||
z
            t          ||
z
  |	          dz             D ]}|||
|z   |z
           |||z
           z  z  } |
|k    r||z  }||z  ||
<   s|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   ZeroDivisionErrorrg   rC   rK   rH   r{   r;   r0   rq   r   r   rr   rs   invrN   dqdrr}   r:   r~   s                r   gf_divr     sH   8 
1B	1B  5666	b 1u
((1Q4

CQb"q&2rA1b1f 	 	!s1b1f~~s262':;; 	/ 	/AQq1urz]QrAvY..EE7 	SLEqy!Wb1fW:x"q&''
++++r   c                 2    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   rq   r   r   s       r   gf_remr     s     !Q1a  r   c                    t          |           }t          |          }|st          d          ||k     rg S |                    |d         |          }| dd         ||z
  |dz
  }	}}t          d|dz             D ]j}
||
         }t          t	          d||
z
            t          ||
z
  |	          dz             D ]}|||
|z   |z
           |||z
           z  z  } ||z  |z  ||
<   k|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   rg   rK   rH   r{   r   s                r   gf_quor     s     
1B	1B  5666	b 	
((1Q4

C!!!b2grAv2rA1b1f ! !!s1b1f~~s262':;; 	/ 	/AQq1urz]QrAvY..EEq !Wb1fW:r   c                 T    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   rq   r   r   qrs         r   gf_exquor      s8    & !Q1DAq (!!Q'''r   c                 &    | 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   rM   r   s      r   	gf_lshiftr     s#      AF8A:~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   /  s3      "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nt          | ||          } 6|S )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   r   r   )r0   rM   r   r   rN   s        r   r   r   C  s      w	
a 	
a aA	
A
q5 	q!Q""AFA	a 	1aOO
 Hr   c                    t          |           }|dk    rg S dg|z  }dg|d<   ||k     rCt          d|          D ]1}t          ||dz
           ||          }t          || ||          ||<   2nz|dk    rtt	          |j        |j        g|| ||          |d<   t          d|          D ]A}t          ||dz
           |d         ||          ||<   t          ||         | ||          ||<   B|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   rK   r   r   
gf_pow_modr   r   r   )rq   r   r   rM   rd   r}   mons          r   gf_frobenius_monomial_baser   h  s    	!AAv 		
AA3AaD1u )q! 	( 	(AAa!eHa++C#q!Q''AaDD	( 
Q )15!&/1aA66!q! 	) 	)A!AE(AaD!Q//AaD!A$1a((AaDDHr   c                 8   t          |          }t          |           |k    rt          | |||          } | sg S t          |           }| d         g}t          d|dz             D ]5}t          ||         | ||z
           ||          }	t	          ||	||          }6|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   rK   re   rt   )
r0   rq   rd   r   r   r   rM   sfr}   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 ]9}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   rK   r   r   r   )
r0   rM   rq   rd   r   r   rN   r   r}   ress
             r   _gf_pow_pnm1d2r     s     	q!QA	A	A1a[[  Q1a++1aA1aA
QQ
Aq!
,
,CJr   c                 ^   |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n$t          | ||          } t          | |||          } Z|S )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   r   r   )r0   rM   rq   r   r   rN   s         r   r   r     s    .  0w	
a 0aAq!!!	
a 0fQ1ooq!Q///	
Aq5 	q!Q""Aq!Q""AFA	a 	1aOO1aA Hr   c                 `    |r|t          | |||          }} |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     sF      %&Aq!$$1  % Aq!Qr   c           	          | 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   r   r   r   r0   rq   r   r   rN   s        r   gf_lcmr     se      A 	vaAq!!aAq!!1a	) 	)A Aq!Qr   c                     | 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     s`      Q B|q!QAvaAq!!1aA   r   c                 x   | s|s|j         gg g fS t          | ||          \  }}t          |||          \  }}| sg |                    ||          g|fS |s|                    ||          gg |fS |                    ||          gg }	}g |                    ||          g}}
	 t          ||||          \  }}|sn|t          |||          |c\  }}}|                    ||          }t	          ||	|||          }t	          |
||||          }t          ||||          |	}}	t          ||||          |}
}|	||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   rg   r   r   re   )r0   rq   r   r   p0r0p1r1s0s1t0t1QRr   r   r   ts                     r   gf_gcdexr   1  s   B   wBaAFBaAFB )AHHROO$b(( )Q "b((hhr1ooB!((2q//"B1b"a##1 	1a(("R"hhr1oor2q!Q''r2q!Q''q#q!,,bBq#q!,,bB1  r2:r   c                     | s	|j         g fS | d         }|                    |          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_onerC   rh   )r0   r   r   r   s       r   r   r   s  s\      2vrzqT88B<< 	2tAww;}QAq1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   rr   rN   rM   r:   s          r   gf_diffr     s}     
1BF8B;qA3B3  1
 	Ab1fI	QA;;r   c                 <    |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   rR   rX   s         r   gf_evalr     s<     VF  !!!Mr   c                 (      fd|D             S )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]

    c                 4    g | ]}t          |          S r)   r   )r>   r*   r   r0   r   s     r   r?   z!gf_multi_eval.<locals>.<listcomp>  s'    ---QWQ1a  ---r   r)   )r0   Ar   r   s   ` ``r   gf_multi_evalr     s'     .-----!----r   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   r   r_   )r0   rq   r   r   rN   rX   s         r   
gf_composer     s     1vv{ 9E!QKKA667888 		
1AqrrU & &1aA!Q1%%Hr   c                     | sg S | d         g}| dd         D ]8}t          ||||          }t          ||||          }t          ||||          }9|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)r   r_   r   )rq   rN   r0   r   r   compr*   s          r   gf_compose_modr     ss      	aD6DqrrU % %dAq!$$T1a++dAq!$$Kr   c           
         t          | ||||          }|}|dz  rt          | |||          }	|}
n| }	|}
|dz  }|rxt          |t          |||||          ||          }t          |||||          }|dz  r6t          |	t          ||
|||          ||          }	t          ||
|||          }
|dz  }|xt          | |
|||          |	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   rt   )r*   rd   rX   rM   r0   r   r   r   r   r   Vs              r   gf_trace_mapr     s   > 	q!Q1%%A	A1u 1aA!GA
 1nQ1a33Q::1aAq))q5 	.q.Aq!Q77A>>Aq!Q1--A	a   !Q1a((!++r   c                     t          | |||          } | }| }t          d|          D ]9}t          |||||          }t          ||||          }t          ||||          }:|S )z&
    utility for ``gf_edf_shoup``
    r-   )r   rK   r   rt   )	r0   rM   rq   rd   r   r   rN   r   r}   s	            r   _gf_trace_mapr   B  sz     	q!QA	A	A1a[[  Q1a++1aA1aAHr   c                 R    j         gfdt          d|           D             z   S )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]

    c           
      \    g | ](} t          t          d                               )S r   )intr   )r>   r}   r   r   s     r   r?   zgf_random.<locals>.<listcomp>]  s3    CCCqqWQ]]++,,CCCr   r   )r   rK   )rM   r   r   s    ``r   	gf_randomr   P  s5     E7CCCCCeAqkkCCCCCr   c                 N    	 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)rM   r   r   r0   s       r   gf_irreducibler   `  s6    aAAq!$$ 	Hr   c                    t          |           }|dk    rdS t          | ||          \  }} |dk     rt          |j        |j        g|| ||          x}}t          d|dz            D ]R}t          ||j        |j        g||          }t          | |||          |j        gk    rt          ||| ||          }P dS nt          | ||          }	t          |j        |j        g| |	||          x}}t          d|dz            D ]R}t          ||j        |j        g||          }t          | |||          |j        gk    rt          || |	||          }P dS dS )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   rK   rx   r   r   r   r   )
r0   r   r   rM   r   HrN   r}   rq   rd   s
             r   gf_irred_p_ben_orr   s  s     	!AAv tAq!DAq1u AE16?Aq!Q777Aq!Q$ 	 	Aq15!&/1a00AaAq!!aeW, "1aAq11uu	 'q!Q// !%!Q1===Aq!Q$ 	 	Aq15!&/1a00AaAq!!aeW, $Q1a33uu4r   c                    t          |           dk    rdS t          | ||          \  }} |j        |j        g}ddlm} fd |          D             }t          | ||          }|d         }t          d          D ]J}	|	|v r1t          ||||          }
t          | |
||          |j        gk    r dS t          || |||          }K||k    S )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   	factorintc                     h | ]}|z  S r)   r)   )r>   drM   s     r   	<setcomp>z#gf_irred_p_rabin.<locals>.<setcomp>  s    ,,,1,,,r   F)r1   r   r   r   sympy.ntheoryr   r   rK   rx   r   r   )r0   r   r   r   xr   indicesrd   rN   r}   rq   rM   s              @r   gf_irred_p_rabinr     s     	!AAv tAq!DAq	
A'''''',,,,iill,,,G"1a++A	!A1a[[ , ,< 	q!Q""AaAq!!aeW, uuQ1a++6Mr   )zben-orrabinc                 z    t          d          }|t          |         | ||          }n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     sH      $%%F *v&q!Q// Aq))Lr   c                     t          | ||          \  }} | sdS 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     sO      Aq!DAq <taAq))1a00QUG;;r   c                 r    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   r   )r0   r   r   r   sqfrq   s         r   gf_sqf_partr     sO     Aq!!FAs	
A  11aAHr   Fc                    ddg t          |          f\  }}}}t          | ||          \  }} t          |           dk     r|g fS 	 t          | ||          }	|	g k    rt	          | |	||          }
t          | |
||          }d}||j        gk    rvt	          |
|||          }t          ||||          }t          |          dk    r|                    |||z  f           t          |
|||          ||dz   }}}
||j        gk    v|
|j        gk    rd}n|
} |sIt          |           |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!   rK   
ValueError)r0   r   r   allrM   r   factorsr   r   r   rq   rN   r}   Gr   r   s                   r   r   r     s   V E2s1vv-AsGQQ1EB||a 2vAq!7 	q!Q""Aq!Q""AAw, 71aA&&1aA&&Q<<!# -NNAqs8,,, Aq!,,aQa1 w, 7 QUG|  	!!A1a!e__  1v!Va!eV9acqAA?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 ]}|d          | d         z  |z  g|d         }	}t          d|          D ]3}
|                    ||
dz
           |	| |
 dz
           z  z
  |z             4||z  st	          |          |||z  <   |}|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   rC   rK   r!   )r0   r   r   rM   r   r   r   r}   qqrX   r~   s              r   
gf_Qmatrixr  t  s   * Q<<QqA	
16(AE""A	a	RD!a%L A1q1uai!m$$ 	 	R5&2,!#$aeAq! 	4 	4AIIqQx!Aqb1fI+-23333A 	2hhAadGHr   c                 8   d | D             t          |           }} t          d|          D ]$}| |         |         |j        z
  |z  | |         |<   %t          d|          D ]"}t          ||          D ]}| |         |         r n'|                    | |         |         |          }t          d|          D ]}| |         |         |z  |z  | |         |<    t          d|          D ]2}| |         |         }| |         |         | |         |<   || |         |<   3t          d|          D ]U}||k    rM| |         |         }	t          d|          D ].}| |         |         | |         |         |	z  z
  |z  | |         |<   /V$t          d|          D ]Y}t          d|          D ]F}||k    r#|j        | |         |         z
  |z  | |         |<   +| |         |          |z  | |         |<   GZg }
| D ]&}	t	          |	          r|
                    |	           '|
S )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]]

    c                 ,    g | ]}t          |          S r)   )rC   )r>   r   s     r   r?   zgf_Qbasis.<locals>.<listcomp>  s    !!!T!WW!!!r   r   )r/   rK   r   rg   anyr!   )r   r   r   rM   r9   r}   r   r~   r   r   basiss              r   	gf_Qbasisr
    st   " "!a!!!3q66qA1a[[ ( (Q47QU?a'!Q1a[[ 8 8q! 	 	AtAw  hhqtAw""q! 	( 	(AtAws{a'AaDGGq! 	 	A!QAd1gAaDGAaDGGq! 	8 	8AAv 8aDGq! 8 8A tAw1a2a7AaDGG	8 1a[[ ) )q! 	) 	)AAv )51Q47?a/!QaDG8q.!Q		) E  q66 	LLOOOLr   c                    t          | ||          }t          |||          }t          |          D ]1\  }}t          t	          t          |                              ||<   2| g}t          dt          |                    D ]}t	          |          D ]} |j        }	|	|k     rt          ||         |	||          }
t          | |
||          }||j        gk    rD|| k    r>|                    |            t          | |||          } |                    | |g           t          |          t          |          k    rt          |d          c c S |	|j        z  }	|	|k     ό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;   rC   reversedrK   r/   r   ra   r   r   remover   extendr
   )r0   r   r   r   r   r}   r   r  r9   r   rq   rN   s               r   gf_berlekampr    s    	1aA!QA! + +1Xa[[))**!cG1c!ff  g 	 	AAa% !!A$1a001aA&&< +AF +NN1%%%q!Q**ANNAq6***w<<3q66) B(5AAAAAAAAQU
 a% 	$ 51111r   c           	      "   d|j         |j        gg }}}t          | ||          }d|z  t          |           k    rt	          || |||          }t          | t          ||j         |j        g||          ||          }||j         gk    rL|                    ||f           t          | |||          } t          || ||          }t          | ||          }|dz  }d|z  t          |           k    | |j         gk    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   rx   r!   r   r   )r0   r   r   r}   rq   r  rd   rN   s           r   gf_ddf_zassenhausr    s/   F qv'qA"1a++A
A#1
 Q1a++1fQA661==< 	4NNAq6"""q!Q""Aq!Q""A*1a33A	Q A#1
  	QUG| 1ill+,,,r   c           	         | g}t          |           |k    r|S t          |           |z  }|dk    rt          | ||          }|j        |j        g}t	          |          |k     r|dk    rb|x}}	t          |dz
            D ]'}
t          |	d| ||          }	t          ||	||          }(t          | |||          }||j        |j        gz  }nRt          d|z  dz
  ||          }	t          |	|| |||          }t          | t          ||j        ||          ||          }||j        gk    r;|| k    r5t          ||||          t          t          | |||          |||          z   }t	          |          |k     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/   rK   r   rt   r   r   r   ra   gf_edf_zassenhausr   r
   )r0   rM   r   r   r  Nrd   r   rN   r   r}   rq   s               r   r  r  ?  s   @ cG||q !AAv 0&q!Q//	
A
g,,
 A6 	?IA1q5\\ ' 'q!Q1--1aA&&q!Q""A!&!&!!AA!a%!)Q**Aq!Q1a00Aq-15!Q77A>>A< 	AAF 	A'1a33#F1aA$6$61a@@AG! g,,
 A& 511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 ]8}t          ||||          }t          ||||          }t          || ||          }9t          | |||          }t          | |||          } t!          |          D ]i}t          ||||          }t          ||||          }||j        gk    r |
                    |||dz   z  |z
  f           t          ||||          |dz
  }}j| |j        gk    r$|
                    | 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   rK   r   r  rx   r   r   r   r   r  r!   )r0   r   r   rM   r9   rd   rN   r   r}   r   r  r   r~   r   rq   r   s                   r   gf_ddf_shoupr    s   @ 	!AE%1++A"1a++A!%!Q155A
%!xQ//A1a!e__ 4 4!A#1a33!Q42A2qA	
qvhAA1a[[ 4 4aAh1a33!G! - -1wA1 	# 	#Aq!Q""Aq!Q""Aq!Q""AA1aA1aA! 	- 	-Aq!Q""Aq!Q""AQUG| 31a!e9q=1222!Q1%%q1uqAA	- 	QUG| *9Q<<()))Nr   c           	      h   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   ra   r   r
   )r0   rM   r   r   r  r   r  r   r   rN   r   h1h2rd   h3s                  r   r  r    s   8 Q<<QqA 	Av s
quafoQG!a%AAAv (q!Q1%%Aq!a%Aq11!4Aq!QAr1a  r1a++2q!Q''( 'q!Q//!Q1a++q1q51*aA..Aq!QA}Qq!44a;;Avb"a++Q22r1a++2q!Q''(2q!Q''( 51111r   c                     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  factorrM   s         r   gf_zassenhausr$  
  sV     G&q!Q// 6 6	$VQ155551111r   c                     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&     sU     G!!Q** 1 1	<1a00051111r   )	berlekamp
zassenhausshoupc                     t          | ||          \  }} t          |           dk     r|g fS |pt          d          }|t          |         | ||          }n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-  <  s     Q1EB||a 2v0u/00F )!&)!Q221a((w;r   c                    t          | ||          \  }} t          |           dk     r|g fS g }t          | ||          d         D ]6\  }}t          |||          d         D ]}|                    ||f           7|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  rq   rM   rN   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*   rR   rX   s       r   gf_valuer1    s1     F  !!Mr   c                     ddl m} | z  dk    r'z  dk    rt          t                              S g S  ||           \  }z  dk    rg S fdt                    D             S )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   c                 8    g | ]}z  z  |z  z  z   z  S r)   r)   )r>   r   rd   rq   r   r   s     r   r?   z%linear_congruence.<locals>.<listcomp>  s3    <<<aQUaZ!a%1*$)<<<r   )sympy.polys.polytoolsr   rC   rK   )r*   rd   r   r   r   rq   r   s    ``  @@r   linear_congruencer5    s    . ,+++++1uz q5A: 	a>>!IeAqkkGAq!1uz 	<<<<<<<588<<<<r   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.domainsr8  r   r1  r5  )r   r   r   r0   r8  f_falphabetas           r   _raise_mod_powerr=    sb    B '&&&&&
!Q

CS!Ea^^q!t#DUD!,,,r   r-   c           	         	
 ddl m  fdt                    D             }|dk    r|S g }t          t	          |dgt          |          z                      }|rr|                                \  
}||k    r|                    
           n=|dz   	|z  |                    	
fdt          
|           D                        |rt          |          S )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   r7  c                 @    g | ]}t          |          d k    |S r   r   )r>   r}   r8  r0   r   s     r   r?   z csolve_prime.<locals>.<listcomp>
	  s1    	;	;	;Aq"!5!5!:	;!	;	;	;r   r-   c                 $    g | ]}|z  z   fS r)   r)   )r>   r   psr   r   s     r   r?   z csolve_prime.<locals>.<listcomp>	  s%    KKKq1R4xnKKKr   )r9  r8  rK   rC   r   r/   popr!   r  r=  sorted)r0   r   r   X1Xr#   r   r8  rA  r   r   s   ``     @@@@r   csolve_primerF    s   " '&&&&&	;	;	;	;	;	;U1XX	;	;	;BAv 	
ASaSR[!!""A
 Muuww16 	MHHQKKKKQBABHHKKKKKK.>q!Q.J.JKKKLLL  M !99r   c                 \   	 ddl m ddlm}  ||          } fd|                                D             }t          t          t          |                    }g g}|D ]		fd|D             }d |                                D             t          fd|D                       S )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   r7  r   c                 8    g | ]\  }}t          ||          S r)   )rF  )r>   r   r   r0   s      r   r?   zgf_csolve.<locals>.<listcomp>5	  s)    55541aaA		555r   c                 &    g | ]}D ]}||gz   	S r)   r)   )r>   r   ypools      r   r?   zgf_csolve.<locals>.<listcomp>9	  s,    666Q66AaS6666r   c                 4    g | ]\  }}t          ||          S r)   )pow)r>   r   r   s      r   r?   zgf_csolve.<locals>.<listcomp>:	  s$    444$!QC1II444r   c                 2    g | ]}t          |          S r)   )r   )r>   perr8  dist_factorss     r   r?   zgf_csolve.<locals>.<listcomp>;	  s%    BBBS6#|R00BBBr   )	r9  r8  r   r   itemsrC   rD   r   rC  )
r0   rM   r   PrE  poolspermsr8  rP  rK  s
   `      @@@r   	gf_csolverU  	  s    0 '&&&&&''''''	!A555517799555AUAEDE 7 76666%66644!''))444LBBBBBEBBBCCCr   )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;   rA   rF   rO   rS   rU   rY   r\   r_   ra   re   rh   rt   rx   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/  r1  r5  r=  rF  rU  r)   r   r   <module>r]     sF   G G 3 3 3 3 3 3 3 3 3 3 % % % % % % * * * * * * ( ( ( ( ( ( 6 6 6 6 6 6 / / / / / /* * * *Z  0  8  *  $  (  (  8* * * ( ( ("  8   :      ,) ) )"  8  8( ( ((2 2 2" 9  9  9F 9  9  9F  >( ( (V/ / // / /"  83, 3, 3,l! ! !"$ $ $N( ( (6  (  (# # #J  @# # #J  ". . .b     (     .     .? ? ?D2 2 22  <  0. . ."  :  65, 5, 5,n  D D D   &* * *Z) ) )X     4< < <0  0V V V Vr% % %P; ; ;|)2 )2 )2X6 6 6r=2 =2 =2@J J JX<2 <2 <2~2 2 2,2 2 2,     :=& =& =&@  ( =  =  =F%- %- %-P   D!D !D !D !D !Dr   