U
    Š±Ëh¨G  ã                   @   s¼   d dl m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mZ G dd„ dƒZG dd	„ d	ƒZd
d„ Zd!dd„Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd"dd „ZdS )#é    )Ú_randint)ÚgcdÚinvertÚsqrt)Ú_sqrt_mod_prime_power)Úisprime)Úlogr   c                   @   s   e Zd Zddd„Zdd„ ZdS )ÚSievePolynomial© Nc                 C   s   || _ || _|| _dS )aÄ  This class denotes the seive polynomial.
        If ``g(x) = (a*x + b)**2 - N``. `g(x)` can be expanded
        to ``a*x**2 + 2*a*b*x + b**2 - N``, so the coefficient
        is stored in the form `[a**2, 2*a*b, b**2 - N]`. This
        ensures faster `eval` method because we dont have to
        perform `a**2, 2*a*b, b**2` every time we call the
        `eval` method. As multiplication is more expensive
        than addition, by using modified_coefficient we get
        a faster seiving process.

        Parameters
        ==========

        modified_coeff : modified_coefficient of sieve polynomial
        a : parameter of the sieve polynomial
        b : parameter of the sieve polynomial
        N)Úmodified_coeffÚaÚb)Úselfr   r   r   r
   r
   ú4/tmp/pip-unpacked-wheel-6t8vlncq/sympy/ntheory/qs.pyÚ__init__	   s    zSievePolynomial.__init__c                 C   s$   d}| j D ]}||9 }||7 }q
|S )z¢
        Compute the value of the sieve polynomial at point x.

        Parameters
        ==========

        x : Integer parameter for sieve polynomial
        r   )r   )r   ÚxZansZcoeffr
   r
   r   Úeval   s
    	

zSievePolynomial.eval)r
   NN)Ú__name__Ú
__module__Ú__qualname__r   r   r
   r
   r
   r   r	      s   
r	   c                   @   s   e Zd ZdZdd„ ZdS )ÚFactorBaseElemz7This class stores an element of the `factor_base`.
    c                 C   s.   || _ || _|| _d| _d| _d| _d| _dS )zÿ
        Initialization of factor_base_elem.

        Parameters
        ==========

        prime : prime number of the factor_base
        tmem_p : Integer square root of x**2 = n mod prime
        log_p : Compute Natural Logarithm of the prime
        N)ÚprimeÚtmem_pÚlog_pÚsoln1Úsoln2Úa_invÚb_ainv)r   r   r   r   r
   r
   r   r   2   s    zFactorBaseElem.__init__N)r   r   r   Ú__doc__r   r
   r
   r
   r   r   /   s   r   c           	      C   s¶   ddl m} g }d\}}| d| ¡D ]†}t||d d |ƒdkr$|dkr\|dkr\t|ƒd }|dkrx|dkrxt|ƒd }t||dƒd }tt|ƒd	 ƒ}| t	|||ƒ¡ q$|||fS )
aç  Generate `factor_base` for Quadratic Sieve. The `factor_base`
    consists of all the points whose ``legendre_symbol(n, p) == 1``
    and ``p < num_primes``. Along with the prime `factor_base` also stores
    natural logarithm of prime and the residue n modulo p.
    It also returns the of primes numbers in the `factor_base` which are
    close to 1000 and 5000.

    Parameters
    ==========

    prime_bound : upper prime bound of the factor_base
    n : integer to be factored
    r   )Úsieve©NNé   é   iè  Niˆ  é   )
Zsympy.ntheory.generater   Z
primerangeÚpowÚlenr   Úroundr   Úappendr   )	Úprime_boundÚnr   Úfactor_baseÚidx_1000Úidx_5000r   Zresiduer   r
   r
   r   Ú_generate_factor_baseF   s    r-   Nc                    sè  t |ƒ}td|  ƒ| }d\}}	}
|dkr.dn|}|dkrFt|ƒd n|}tdƒD ]†}d}g }||k r¤d}|dksz||kr†|||ƒ}qj|| j}||9 }| |¡ q^|| }|
dksÌt|d ƒt|
d ƒk rR|}	|}|}
qR|}|	}g }|D ]R}|| j}|| jt|| |ƒ | }||d kr*|| }| || | ¡ qêt	|ƒ}t
|| d| | || |  g||ƒ}|D ]n‰ |ˆ j dkrˆqpt|ˆ jƒˆ _‡ fdd„|D ƒˆ _ˆ jˆ j|  ˆ j ˆ _ˆ jˆ j |  ˆ j ˆ _qp||fS )	ag  This step is the initialization of the 1st sieve polynomial.
    Here `a` is selected as a product of several primes of the factor_base
    such that `a` is about to ``sqrt(2*N) / M``. Other initial values of
    factor_base elem are also initialized which includes a_inv, b_ainv, soln1,
    soln2 which are used when the sieve polynomial is changed. The b_ainv
    is required for fast polynomial change as we do not have to calculate
    `2*b*invert(a, prime)` every time.
    We also ensure that the `factor_base` primes which make `a` are between
    1000 and 5000.

    Parameters
    ==========

    N : Number to be factored
    M : sieve interval
    factor_base : factor_base primes
    idx_1000 : index of prime number in the factor_base near 1000
    idx_5000 : index of prime number in the factor_base near to 5000
    seed : Generate pseudoprime numbers
    r"   )NNNNr   r!   é2   c                    s    g | ]}d | ˆ j  ˆ j ‘qS )r"   )r   r   )Ú.0Zb_elem©Úfbr
   r   Ú
<listcomp>£   s     z0_initialize_first_polynomial.<locals>.<listcomp>)r   r   r%   Úranger   r'   Úabsr   r   Úsumr	   r   r   r   r   )ÚNÚMr*   r+   r,   ÚseedÚrandintZ
approx_valZbest_aZbest_qZ
best_ratioÚstartÚendÚ_r   ÚqZrand_pÚpZratioÚBÚvalZq_lÚgammar   Úgr
   r0   r   Ú_initialize_first_polynomialc   sN    

 
&rC   c                 C   sø   ddl m} d}|}|d dkr2|d7 }|d }q||d|  ƒd dkrPd}nd}|jd| ||d    }	|j}
t|
|
 d|
 |	 |	|	 |  g|
|	ƒ}|D ]T}|
|j dkr²qž|j||j|d    |j |_|j||j|d    |j |_qž|S )aÐ  Initialization stage of ith poly. After we finish sieving 1`st polynomial
    here we quickly change to the next polynomial from which we will again
    start sieving. Suppose we generated ith sieve polynomial and now we
    want to generate (i + 1)th polynomial, where ``1 <= i <= 2**(j - 1) - 1``
    where `j` is the number of prime factors of the coefficient `a`
    then this function can be used to go to the next polynomial. If
    ``i = 2**(j - 1) - 1`` then go to _initialize_first_polynomial stage.

    Parameters
    ==========

    N : number to be factored
    factor_base : factor_base primes
    i : integer denoting ith polynomial
    g : (i - 1)th polynomial
    B : array that stores a//q_l*gamma
    r   )Úceilingr!   r"   éÿÿÿÿ)	Z#sympy.functions.elementary.integersrD   r   r   r	   r   r   r   r   )r6   r*   ÚirB   r?   rD   ÚvÚjZneg_powr   r   r1   r
   r
   r   Ú_initialize_ith_poly©   s$    
& "rI   c                 C   s¤   dgd|  d  }|D ]ˆ}|j dkr&qt| |j  |j d|  |jƒD ]}||  |j7  < qD|jdkrhqt| |j |j d|  |jƒD ]}||  |j7  < q†q|S )a¨  Sieve Stage of the Quadratic Sieve. For every prime in the factor_base
    that does not divide the coefficient `a` we add log_p over the sieve_array
    such that ``-M <= soln1 + i*p <=  M`` and ``-M <= soln2 + i*p <=  M`` where `i`
    is an integer. When p = 2 then log_p is only added using
    ``-M <= soln1 + i*p <=  M``.

    Parameters
    ==========

    M : sieve interval
    factor_base : factor_base primes
    r   r"   r!   N)r   r3   r   r   r   )r7   r*   Úsieve_arrayÚfactorÚidxr
   r
   r   Ú_gen_sieve_arrayÑ   s    
"
"rM   c                 C   s¦   g }| dk r |  d¡ | d9 } n
|  d¡ |D ]R}| |j dkrL|  d¡ q.d}| |j dkrr|d7 }| |j } qP|  |d ¡ q.| dkr’|dfS t| ƒr¢| dfS dS )ab  Here we check that if `num` is a smooth number or not. If `a` is a smooth
    number then it returns a vector of prime exponents modulo 2. For example
    if a = 2 * 5**2 * 7**3 and the factor base contains {2, 3, 5, 7} then
    `a` is a smooth number and this function returns ([1, 0, 0, 1], True). If
    `a` is a partial relation which means that `a` a has one prime factor
    greater than the `factor_base` then it returns `(a, False)` which denotes `a`
    is a partial relation.

    Parameters
    ==========

    a : integer whose smootheness is to be checked
    factor_base : factor_base primes
    r   r!   rE   r"   TFr    )r'   r   r   )Únumr*   ÚvecrK   Z
factor_expr
   r
   r   Ú_check_smoothnessì   s&    



rP   c              	   C   sD  t | ƒ}t|| ƒd | }g }	tƒ }
d|d j }t|ƒD ]þ\}}||k rNq<|| }| |¡}t||ƒ\}}|dkrxq<|j| |j }|dkr*|}||kr q<||kr¸||f||< q<nr|| \}}| 	|¡ zt
|| ƒ}W n" tk
rþ   |
 |¡ Y q<Y nX || | }|| ||  }t||ƒ\}}|	 |||f¡ q<|	|
fS )a)  Trial division stage. Here we trial divide the values generetated
    by sieve_poly in the sieve interval and if it is a smooth number then
    it is stored in `smooth_relations`. Moreover, if we find two partial relations
    with same large prime then they are combined to form a smooth relation.
    First we iterate over sieve array and look for values which are greater
    than accumulated_val, as these values have a high chance of being smooth
    number. Then using these values we find smooth relations.
    In general, let ``t**2 = u*p modN`` and ``r**2 = v*p modN`` be two partial relations
    with the same large prime p. Then they can be combined ``(t*r/p)**2 = u*v modN``
    to form a smooth relation.

    Parameters
    ==========

    N : Number to be factored
    M : sieve interval
    factor_base : factor_base primes
    sieve_array : stores log_p values
    sieve_poly : polynomial from which we find smooth relations
    partial_relations : stores partial relations with one large prime
    ERROR_TERM : error term for accumulated_val
    r#   é€   rE   NF)Úisqrtr   Úsetr   Ú	enumerater   rP   r   r   Úpopr   ÚZeroDivisionErrorÚaddr'   )r6   r7   r*   rJ   Z
sieve_polyÚpartial_relationsÚ
ERROR_TERMZsqrt_nZaccumulated_valÚsmooth_relationsÚproper_factorZpartial_relation_upper_boundrL   r@   r   rG   rO   Z	is_smoothÚuZlarge_primeZu_prevZv_prevZlarge_prime_invr
   r
   r   Ú_trial_division_stage  sB    




r]   c                 C   s    g }| D ]}|  |d ¡ q|S )z|Build a 2D matrix from smooth relations.

    Parameters
    ==========

    smooth_relations : Stores smooth relations
    r"   )r'   )rZ   ÚmatrixZ
s_relationr
   r
   r   Ú_build_matrixR  s    r_   c                 C   sü   ddl }| | ¡}t|ƒ}t|d ƒ}dg| }t|ƒD ]ˆ}t|ƒD ]}|| | dkrD q^qDd||< t|ƒD ]P}||kr|qn|| | dkrnt|ƒD ](}	||	 | ||	 |  d ||	 |< q”qnq8g }
t|ƒD ]"\}}|dkrÎ|
 || |g¡ qÎ|
||fS )aþ  Fast gaussian reduction for modulo 2 matrix.

    Parameters
    ==========

    A : Matrix

    Examples
    ========

    >>> from sympy.ntheory.qs import _gauss_mod_2
    >>> _gauss_mod_2([[0, 1, 1], [1, 0, 1], [0, 1, 0], [1, 1, 1]])
    ([[[1, 0, 1], 3]],
     [True, True, True, False],
     [[0, 1, 0], [1, 0, 0], [0, 0, 1], [1, 0, 1]])

    Reference
    ==========

    .. [1] A fast algorithm for gaussian elimination over GF(2) and
    its implementation on the GAPP. Cetin K.Koc, Sarath N.Arachchiger   NFr!   Tr"   )ÚcopyÚdeepcopyr%   r3   rT   r'   )ÚAr`   r^   ÚrowÚcolÚmarkÚcÚrZc1Zr2Údependent_rowrL   r@   r
   r
   r   Ú_gauss_mod_2`  s*    

*ri   c                 C   sæ   | | d }|| d g}|| d g}| | d }	t |	ƒD ]f\}
}|dkr<tt|ƒƒD ]H}|| |
 dkrX|| dkrX| || d ¡ | || d ¡  q<qXq<d}d}|D ]}||9 }q°|D ]}||9 }qÂt|ƒ}t|| |ƒS )a  Finds proper factor of N. Here, transform the dependent rows as a
    combination of independent rows of the gauss_matrix to form the desired
    relation of the form ``X**2 = Y**2 modN``. After obtaining the desired relation
    we obtain a proper factor of N by `gcd(X - Y, N)`.

    Parameters
    ==========

    dependent_rows : denoted dependent rows in the reduced matrix form
    mark : boolean array to denoted dependent and independent rows
    gauss_matrix : Reduced form of the smooth relations matrix
    index : denoted the index of the dependent_rows
    smooth_relations : Smooth relations vectors matrix
    N : Number to be factored
    r!   r   T)rT   r3   r%   r'   rR   r   )Zdependent_rowsre   Úgauss_matrixÚindexrZ   r6   Zidx_in_smoothZindependent_uZindependent_vZdept_rowrL   r@   rc   r\   rG   rF   r
   r
   r   Ú_find_factor  s&    

rl   é   éÒ  c                 C   sp  |d9 }t || ƒ\}}}g }d}	i }
tƒ }dt|ƒ d }|	dkrXt| ||||ƒ\}}nt| ||	||ƒ}|	d7 }	|	dt|ƒd  krˆd}	t||ƒ}t| |||||
|ƒ\}}||7 }||O }t|ƒt|ƒ| kr:qÒq:t|ƒ}t|ƒ\}}}| }t	t|ƒƒD ]r}t
|||||| ƒ}|dkrø|| k rø| |¡ || dkrB|| }q(t|ƒr\| |¡  ql|dkrø qlqø|S )a  Performs factorization using Self-Initializing Quadratic Sieve.
    In SIQS, let N be a number to be factored, and this N should not be a
    perfect power. If we find two integers such that ``X**2 = Y**2 modN`` and
    ``X != +-Y modN``, then `gcd(X + Y, N)` will reveal a proper factor of N.
    In order to find these integers X and Y we try to find relations of form
    t**2 = u modN where u is a product of small primes. If we have enough of
    these relations then we can form ``(t1*t2...ti)**2 = u1*u2...ui modN`` such that
    the right hand side is a square, thus we found a relation of ``X**2 = Y**2 modN``.

    Here, several optimizations are done like using multiple polynomials for
    sieving, fast changing between polynomials and using partial relations.
    The use of partial relations can speeds up the factoring by 2 times.

    Parameters
    ==========

    N : Number to be Factored
    prime_bound : upper bound for primes in the factor base
    M : Sieve Interval
    ERROR_TERM : Error term for checking smoothness
    threshold : Extra smooth relations for factorization
    seed : generate pseudo prime numbers

    Examples
    ========

    >>> from sympy.ntheory import qs
    >>> qs(25645121643901801, 2000, 10000)
    {5394769, 4753701529}
    >>> qs(9804659461513846513, 2000, 10000)
    {4641991, 2112166839943}

    References
    ==========

    .. [1] https://pdfs.semanticscholar.org/5c52/8a975c1405bd35c65993abf5a4edb667c1db.pdf
    .. [2] https://www.rieselprime.de/ziki/Self-initializing_quadratic_sieve
    r#   r   é   éd   r!   r"   )r-   rS   r%   rC   rI   rM   r]   r_   ri   r3   rl   rW   r   )r6   r(   r7   rY   r8   r+   r,   r*   rZ   Zith_polyrX   r[   Ú	thresholdZith_sieve_polyZB_arrayrJ   Zs_relZp_fr^   rh   re   rj   ZN_copyrk   rK   r
   r
   r   Úqsµ  sD    '



rr   )N)rm   rn   )Zsympy.core.randomr   Zsympy.external.gmpyr   r   r   rR   Zsympy.ntheory.residue_ntheoryr   Zsympy.ntheoryr   Úmathr   r	   r   r-   rC   rI   rM   rP   r]   r_   ri   rl   rr   r
   r
   r
   r   Ú<module>   s    '
F(&@-(