
    Ed&H                         d dl mZmZ d dlmZ d dlmZ d dlmZ d dl	m
Z
mZ d dlZ ej                    Z G d d          Z G d	 d
          Zd ZddZd Zd Zd Zd Zd Zd Zd ZddZdS )    )igcdmod_inverse)integer_nthroot)_sqrt_mod_prime_power)isprime)logsqrtNc                       e Zd ZddZd ZdS )SievePolynomial Nc                 0    || _         || _        || _        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   s       0lib/python3.11/site-packages/sympy/ntheory/qs.py__init__zSievePolynomial.__init__   s    $ -    c                 2    d}| j         D ]}||z  }||z  }|S )z
        Compute the value of the sieve polynomial at point x.

        Parameters
        ==========

        x : Integer parameter for sieve polynomial
        r   )r   )r   xanscoeffs       r   evalzSievePolynomial.eval!   s4     ( 	 	E1HC5LCC
r   )r   NN)__name__
__module____qualname__r   r   r   r   r   r   r   
   s7           ,    r   r   c                       e Zd ZdZd ZdS )FactorBaseElemz7This class stores an element of the `factor_base`.
    c                 h    || _         || _        || _        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"   s       r   r   zFactorBaseElem.__init__4   s9     




r   N)r   r   r   __doc__r   r   r   r   r   r   1   s-             r   r   c                    ddl m} g }d\  }}|                    d|           D ]}t          ||dz
  dz  |          dk    r|dk    r|t	          |          dz
  }|dk    r|t	          |          dz
  }t          ||d          d         }t          t          |          d	z            }|                    t          |||                     |||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     )
sympy.ntheory.generater)   
primerangepowlenr   roundr   appendr   )	prime_boundnr)   factor_baseidx_1000idx_5000r    residuer"   s	            r   _generate_factor_baser:   H   s    -,,,,,K#Hh!!![11 F Fq519"E**a/ 	Ft| 0 0{++a/t| 0 0{++a/+Aua88;G#e**U*++E~eWeDDEEEX{**r   c                 Z   |t                               |           t          d| z            |z  }d\  }}}	|dn|}
|t          |          dz
  n|}t	          d          D ]}d}g }||k     r^d}|dk    s||v r%t                               |
|          }|dk    !||v %||         j        }||z  }|                    |           ||k     ^||z  }|	&t          |dz
            t          |	dz
            k     r|}|}|}	|}|}g }t          |          D ]_\  }}||         j        }||         j
        t          ||z  |          z  |z  }||dz  k    r||z
  }|                    ||z  |z             `t          |          }t          ||z  d|z  |z  ||z  | z
  g||          }|D ]}|j        z  dk    rt          |j                  _        fd|D             _        j        j
        |z
  z  j        z  _        j        j
         |z
  z  j        z  _        ~||fS )ai  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 intialized 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*mod_inverse(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 numbe in the factor_base near 1000
    idx_5000 : index of primenumber in the factor_base near to 5000
    seed : Generate pseudoprime numbers
    Nr,   )NNNr   r+   2   c                 :    g | ]}d |z  j         z  j        z  S )r,   )r%   r    ).0b_elemfbs     r   
<listcomp>z0_initialize_first_polynomial.<locals>.<listcomp>   s+    BBBfQvXbh&1BBBr   )rgenseedr	   r1   rangerandintr    r3   abs	enumerater!   r   sumr   r%   r&   r#   r$   )NMr6   r7   r8   rC   
approx_valbest_abest_q
best_ratiostartend_r   qrand_ppratioBidxvalq_lgammar   gr@   s                            @r   _initialize_first_polynomialr\   e   s   *  		$acQJ
 "2FFJ/AAxE"*
@#k

Q

C2YY  *n 	FA+ 21 2eS11 A+ 21 2F#)AFAHHV *n 	 J 	UQY#j1n2E2E!E 	FFJAA
AaLL  S#$C '+a3h*D*DDsJ37? 	 %KE	CAA1ac!eQqS1W-q!44A : :rx<1 	q"(++BBBBBBB	Hbi!m,8Hryj1n-9a4Kr   c                    ddl m} d}|}|dz  dk    r|dz  }|dz  }|dz  dk     ||d|z  z            dz  dk    rd}nd}|j        d|z  ||dz
           z  z   }	|j        }
t	          |
|
z  d|
z  |	z  |	|	z  | z
  g|
|	          }|D ]a}|
|j        z  dk    r|j        ||j        |dz
           z  z
  |j        z  |_        |j        ||j        |dz
           z  z
  |j        z  |_        b|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,   )	#sympy.functions.elementary.integersr^   r   r   r   r    r#   r&   r$   )rI   r6   ir[   rV   r^   vjneg_powr   r   r@   s               r   _initialize_ith_polyre      sN   $ <;;;;;	A	A
a%1* 	Q	a a%1*  wqAqDzQ!# 	ai!a%  A	A1ac!eQqS1W-q!44A D Drx<1 	HwryQ'77728CHwryQ'77728CHr   c                 T   dgd| z  dz   z  }|D ]}|j         
t          | |j         z   |j        z  d| z  |j                  D ]}||xx         |j        z  cc<   |j        dk    rWt          | |j        z   |j        z  d| z  |j                  D ]}||xx         |j        z  cc<   |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+   )r#   rD   r    r"   r$   )rJ   r6   sieve_arrayfactorrW   s        r   _gen_sieve_arrayri      s     #qsQw-K 	- 	-< 	!fl*fl:AaCNN 	- 	-C,<1 	!fl*fl:AaCNN 	- 	-C,	-r   c                    g }| dk     r|                     d           | dz  } n|                     d           |D ]k}| |j        z  dk    r|                     d           &d}| |j        z  dk    r|dz  }| |j        z  } | |j        z  dk    |                     |dz             l| 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+   r_   r,   TFr*   )r3   r    r   )numr6   vecrh   
factor_exps        r   _check_smoothnessrn      s    C
Qw 

1r	

1 # #" 	JJqMMM
FL A% 	!!OJFL C FL A% 	! 	

:>""""
ax Dys|| Ez:r   c                    t          t          |                     }t          ||z            dz  |z
  }g }	t                      }
d|d         j        z  }t          |          D ]\  }}||k     r||z
  }|                    |          }t          ||          \  }}|<|j        |z  |j	        z   }|du r|}||k    r[||vr||f||<   g||         \  }}|
                    |           	 t          ||           }n%# t          $ r |
                    |           Y w xY w||z  |z  }||z  ||z  z  }t          ||          \  }}|	                    |||f           |	|
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-      r_   NF)r	   floatr   setr    rG   r   rn   r   r   popr   
ValueErroraddr3   )rI   rJ   r6   rg   
sieve_polypartial_relations
ERROR_TERMsqrt_naccumulated_valsmooth_relationsproper_factorpartial_relation_upper_boundrW   rX   r   rb   rl   	is_smoothularge_primeu_prevv_prevlarge_prime_invs                          r   _trial_division_stager     s   . %((^^F!f*ooe+j8OEEM#&{2'<#< k** - -S  	!GOOA*1k::Y 	LNZ\)  	CK99 "33 C23Q!+.!2;!?!%%k222&1+q&A&AOO!   !%%k222H fH_,fH[!89!21k!B!BYAs,,,,]**s   ,C==DDc                 J    g }| D ]}|                     |d                    |S )z|Build a 2D matrix from smooth relations.

    Parameters
    ==========

    smooth_relations : Stores smooth relations
    r,   )r3   )r{   matrix
s_relations      r   _build_matrixr   U  s6     F& % %
jm$$$$Mr   c                 L   ddl }|                    |           }t          |          }t          |d                   }dg|z  }t          |          D ]}t          |          D ]}||         |         dk    r nd||<   t          |          D ]V}||k    r	||         |         dk    r;t          |          D ]+}	||	         |         ||	         |         z   dz  ||	         |<   ,Wg }
t	          |          D ](\  }}|dk    r|
                    ||         |g           )|
||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deepcopyr1   rD   rG   r3   )Ar   r   rowcolmarkcrc1r2dependent_rowrW   rX   s                r   _gauss_mod_2r   c  sq   , KKK]]1F
f++C
fQi..C73;D3ZZ 
J 
Js 	 	Aay|q  Q** 	J 	JBQw ay}! J** J JB&,Rjnvbz!}&D%IF2JrNN	J MdOO 5 5S%< 	5  &+s!3444$&&r   c                 0   | |         d         }||         d         g}||         d         g}| |         d         }	t          |	          D ]\  }
}|dk    rt          t          |                    D ]d}||         |
         dk    rP||         dk    rD|                    ||         d                    |                    ||         d                     ned}d}|D ]}||z  }|D ]}||z  }t	          |d          d         }t          ||z
  |          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   Tr,   )rG   rD   r1   r3   r   r   )dependent_rowsr   gauss_matrixindexr{   rI   idx_in_smoothindependent_uindependent_vdept_rowrW   rX   r   r   rb   ra   s                   r   _find_factorr     s\     #5)!,M%m4Q78M%m4Q78Me$Q'Hh''  S!8 	S..//  $S)Q. 493D !(()9#)>q)ABBB!(()9#)>q)ABBBE	A	A  	Q  	Q1a AAq>>r        c           	         |dz  }t                               |           t          ||           \  }}}g }d}	i }
t                      }dt	          |          z  dz  }	 |	dk    rt          | ||||          \  }}nt          | ||	||          }|	dz  }	|	dt	          |          dz
  z  k    rd}	t          ||          }t          | |||||
|          \  }}||z  }||z  }t	          |          t	          |          |z   k    rnt          |          }t          |          \  }}}| }t          t	          |                    D ]|}t          ||||||           }|dk    r`|| k     rZ|                    |           ||z  dk    r||z  }||z  dk    t          |          r|                    |            n	|dk    r n}|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 muliple 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   Tr+   r,   )rB   rC   r:   rr   r1   r\   re   ri   r   r   r   rD   r   ru   r   )rI   r4   rJ   rx   rC   r7   r8   r6   r{   ith_polyrw   r|   	thresholdith_sieve_polyB_arrayrg   s_relp_fr   r   r   r   N_copyr   rh   s                            r   qsr     s=   N JIIdOOO&;K&K&K#HhHEEM#k"""c)Iq= 	e&B1aV^`h&i&i#NGG1![(N\cddNAq3w<<!+,, 	H&q+66*1ak>[lnxyy
sE!  C$4$4y$@@ 	 +,,F(4V(<(<%M4Fs=))** 
 
mT<HXZ[\\A: 	&1* 	f%%%6/Q& "6! 6/Q& "v !!&))){ r   )N)r   r   )sympy.core.numbersr   r   sympy.core.powerr   sympy.ntheory.residue_ntheoryr   sympy.ntheoryr   mathr   r	   randomRandomrB   r   r   r:   r\   re   ri   rn   r   r   r   r   r   r   r   r   <module>r      s   0 0 0 0 0 0 0 0 , , , , , , ? ? ? ? ? ? ! ! ! ! ! !         v}$ $ $ $ $ $ $ $N       .+ + +:D D D DN% % %P  6# # #L<+ <+ <+@  *' *' *'Z% % %PK K K K K Kr   