U
    9%e,                     @   s   d dl mZ d dlmZ d dlmZ d dlmZ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 G dd dZG dd dZdS )    )oo)Eq)symbols)FiniteFieldQQRationalFieldFF)solve)is_sequence)as_int   )divisors)polynomial_congruencec                   @   s   e Zd ZdZd!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edd Zedd Zedd Zedd Zedd Zedd Zd S )#EllipticCurveaH  
    Create the following Elliptic Curve over domain.

    `y^{2} + a_{1} x y + a_{3} y = x^{3} + a_{2} x^{2} + a_{4} x + a_{6}`

    The default domain is ``QQ``. If no coefficient ``a1``, ``a2``, ``a3``,
    it create curve as following form.

    `y^{2} = x^{3} + a_{4} x + a_{6}`

    Examples
    ========

    References
    ==========

    .. [1] J. Silverman "A Friendly Introduction to Number Theory" Third Edition
    .. [2] https://mathworld.wolfram.com/EllipticDiscriminant.html
    .. [3] G. Hardy, E. Wright "An Introduction to the Theory of Numbers" Sixth Edition

    r   c                 C   s  |dkrt }nt|}t|j|||||f\}}}}}|| _|| _|d d|  }d| ||  }	|d d|  }
|d | d| |  || |  ||d   |d  }||	|
|f\| _| _| _| _	|d  | d|	d   d|
d   d| |	 |
  | _
|| _|| _|| _|| _|| _td\}}}|||  | _| _| _t|d | || | |  || |d   |d ||d  |  || |d   ||d   | _t| jtrd| _nt| jtrd | _d S )	Nr                  	   zx y z)r   r   mapconvert_domainmodulus_b2_b4_b6Z_b8_discrim_a1_a2_a3_a4_a6r   xyzr   _eq
isinstancer   _rankr   )selfa4a6a1a2a3r   domainb2Zb4Zb6Zb8r#   r$   r%    r1   [/var/www/html/Darija-Ai-API/env/lib/python3.8/site-packages/sympy/ntheory/elliptic_curve.py__init__$   s0     88dzEllipticCurve.__init__r   c                 C   s   t |||| S NEllipticCurvePoint)r)   r#   r$   r%   r1   r1   r2   __call__@   s    zEllipticCurve.__call__c                 C   s   t |r4t|dkrd}n|d }|d d \}}n*t|trV|j|j|j  }}}ntd| jdkrt|dkrtdS | j	
| j|| j|| j|iS )Nr   r   zInvalid point.r   T)r
   lenr'   r6   r#   r$   r%   
ValueErrorcharacteristicr&   subs)r)   pointZz1x1y1r1   r1   r2   __contains__C   s    
zEllipticCurve.__contains__c                 C   s   d | j| jS )Nz	E({}): {})formatr   r&   r)   r1   r1   r2   __repr__R   s    zEllipticCurve.__repr__c                 C   s   | j }|dkr| S |dkr>t| jd | jd | jd | jdS | jd d| j  }| jd  d| j | j  d| j  }td| d	| | jd
S )a)  
        Return minimal Weierstrass equation.

        Examples
        ========

        >>> from sympy.ntheory.elliptic_curve import EllipticCurve

        >>> e1 = EllipticCurve(-10, -20, 0, -1, 1)
        >>> e1.minimal()
        E(QQ): Eq(y**2*z, x**3 - 13392*x*z**2 - 1080432*z**3)

        r   r   r   )r-   r      $      ii)r   )r:   r   r   r   r   r   )r)   charc4Zc6r1   r1   r2   minimalU   s    $&zEllipticCurve.minimalc                 C   sv   | j }t }|dkrjt|D ]H}| jj| jj | j|| jdi}t	||}|D ]}|
||f qPq|S tddS )a5  
        Return points of curve over Finite Field.

        Examples
        ========

        >>> from sympy.ntheory.elliptic_curve import EllipticCurve
        >>> e2 = EllipticCurve(1, 1, 1, 1, 1, modulus=5)
        >>> e2.points()
        {(0, 2), (1, 4), (2, 0), (2, 2), (3, 0), (3, 1), (4, 0)}

        r   zInfinitely many pointsN)r:   setranger&   lhsrhsr;   r#   r%   r   addr9   )r)   rF   Zall_pticongruence_eqZsolnumr1   r1   r2   pointsl   s    "
zEllipticCurve.pointsc                 C   s|   g }| j tkr6t| j| j|D ]}|||f q"| jj| jj | j|| j	di}t
|| jD ]}|||f qd|S )z2Returns points on with curve where xcoordinate = xr   )r   r   r	   r&   r;   r#   appendrK   rL   r%   r   r:   )r)   r#   ptr$   rO   r1   r1   r2   points_x   s    
"zEllipticCurve.points_xc                 C   s   | j dkrtdt| g}t| j| jd| jdiD ]}|j	r:|
| |d q:t| jddD ]l}t|d }|d |krdt| j| j|| jdiD ]2}|j	sq| ||}| tkr||| g qqd|S )al  
        Return torsion points of curve over Rational number.

        Return point objects those are finite order.
        According to Nagell-Lutz theorem, torsion point p(x, y)
        x and y are integers, either y = 0 or y**2 is divisor
        of discriminent. According to Mazur's theorem, there are
        at most 15 points in torsion collection.

        Examples
        ========

        >>> from sympy.ntheory.elliptic_curve import EllipticCurve
        >>> e2 = EllipticCurve(-43, 166)
        >>> sorted(e2.torsion_points())
        [(-5, -16), (-5, 16), O, (3, -8), (3, 8), (11, -32), (11, 32)]

        r   z"No torsion point for Finite Field.r   T)	generatorg      ?r   )r:   r9   r6   point_at_infinityr	   r&   r;   r$   r%   Zis_rationalrR   r   discriminantintorderr   extend)r)   lZxxrN   jpr1   r1   r2   torsion_points   s     
  
zEllipticCurve.torsion_pointsc                 C   s
   | j  S )z
        Return domain characteristic.

        Examples
        ========

        >>> from sympy.ntheory.elliptic_curve import EllipticCurve
        >>> e2 = EllipticCurve(-43, 166)
        >>> e2.characteristic
        0

        )r   r:   rA   r1   r1   r2   r:      s    zEllipticCurve.characteristicc                 C   s
   t | jS )z
        Return curve discriminant.

        Examples
        ========

        >>> from sympy.ntheory.elliptic_curve import EllipticCurve
        >>> e2 = EllipticCurve(0, 17)
        >>> e2.discriminant
        -124848

        )rX   r   rA   r1   r1   r2   rW      s    zEllipticCurve.discriminantc                 C   s
   | j dkS )zE
        Return True if curve discriminant is equal to zero.
        r   )rW   rA   r1   r1   r2   is_singular   s    zEllipticCurve.is_singularc                 C   s*   | j d d| j  }| j|d | j S )z
        Return curve j-invariant.

        Examples
        ========

        >>> from sympy.ntheory.elliptic_curve import EllipticCurve
        >>> e1 = EllipticCurve(-2, 0, 0, 1, 1)
        >>> e1.j_invariant
        1404928/389

        r   rC   r   )r   r   r   to_sympyr   )r)   rG   r1   r1   r2   j_invariant   s    zEllipticCurve.j_invariantc                 C   s   | j dkrtdt|  S )z
        Number of points in Finite field.

        Examples
        ========

        >>> from sympy.ntheory.elliptic_curve import EllipticCurve
        >>> e2 = EllipticCurve(1, 0, modulus=19)
        >>> e2.order
        19

        r   Still not implemented)r:   NotImplementedErrorr8   rQ   rA   r1   r1   r2   rY      s    
zEllipticCurve.orderc                 C   s   | j dk	r| j S tddS )zj
        Number of independent points of infinite order.

        For Finite field, it must be 0.
        Nrb   )r(   rc   rA   r1   r1   r2   rank   s    
zEllipticCurve.rankN)r   r   r   r   )r   )__name__
__module____qualname____doc__r3   r7   r?   rB   rH   rQ   rT   r^   propertyr:   rW   r_   ra   rY   rd   r1   r1   r1   r2   r      s*   

$




r   c                   @   sd   e Zd ZdZe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 Zdd ZdS )r6   a  
    Point of Elliptic Curve

    Examples
    ========

    >>> from sympy.ntheory.elliptic_curve import EllipticCurve
    >>> e1 = EllipticCurve(-17, 16)
    >>> p1 = e1(0, -4, 1)
    >>> p2 = e1(1, 0)
    >>> p1 + p2
    (15, -56)
    >>> e3 = EllipticCurve(-1, 9)
    >>> e3(1, -3) * 3
    (664/169, 17811/2197)
    >>> (e3(1, -3) * 3).order()
    oo
    >>> e2 = EllipticCurve(-2, 0, 0, 1, 1)
    >>> p = e2(-1,1)
    >>> q = e2(0, -1)
    >>> p+q
    (4, 8)
    >>> p-q
    (1, 0)
    >>> 3*p-5*q
    (328/361, -2800/6859)
    c                 C   s   t ddd| S Nr   r   r5   )curver1   r1   r2   rV   (  s    z$EllipticCurvePoint.point_at_infinityc                 C   sN   |j j}||| _||| _||| _|| _| jj | _ | j| sJtdd S )Nz%The curve does not contain this point)r   r   r#   r$   r%   _curver?   r9   )r)   r#   r$   r%   rk   domr1   r1   r2   r3   ,  s    



zEllipticCurvePoint.__init__c                 C   sp  | j dkr|S |j dkr| S | j| j  | j| j   }}|j|j  |j|j   }}| jj}| jj}| jj}| jj}	| jj}
||kr|| ||  }|| ||  ||  }n|| dkr| 	| jS d|d  d| |  |	 ||  || | d|   }|d  |	|  d|
  ||  || | d|   }|d ||  | | | }||  | | | }| ||dS )Nr   r   r   r   )
r%   r#   r$   rl   r   r   r    r!   r"   rV   )r)   r]   r=   r>   Zx2y2r,   r-   r.   r*   r+   ZslopeZyintZx3Zy3r1   r1   r2   __add__6  s*    

86zEllipticCurvePoint.__add__c                 C   s    | j | j| jf|j |j|jfk S r4   )r#   r$   r%   r)   otherr1   r1   r2   __lt__N  s    zEllipticCurvePoint.__lt__c                 C   sb   t |}| | j}|dkr |S |dk r4|  |  S | }|r^|d@ rL|| }|dL }|| }q8|S rj   )r   rV   rl   )r)   nrr]   r1   r1   r2   __mul__Q  s    
zEllipticCurvePoint.__mul__c                 C   s   | | S r4   r1   )r)   rs   r1   r1   r2   __rmul__`  s    zEllipticCurvePoint.__rmul__c                 C   s.   t | j| j | jj| j  | jj | j| jS r4   )r6   r#   r$   rl   r   r    r%   rA   r1   r1   r2   __neg__c  s    zEllipticCurvePoint.__neg__c                 C   sZ   | j dkrdS | jj}zd|| j|| jW S  tk
rH   Y nX d| j| jS )Nr   Oz({}, {}))r%   rl   r   r@   r`   r#   r$   	TypeError)r)   rm   r1   r1   r2   rB   f  s    
zEllipticCurvePoint.__repr__c                 C   s   |  | S r4   )ro   rp   r1   r1   r2   __sub__p  s    zEllipticCurvePoint.__sub__c                 C   s   | j dkrdS | jdkrdS | d }|j| j kr6dS d}| jtkrt|j|jkrt|j|jkr| | }|d7 }|j dkrD|S qDtS |jj|jkr|jj|jkr| | }|d7 }|dkrtS |j dkr|S qtS )z5
        Return point order n where nP = 0.

        r   r   r   r      )r%   r$   r   r   rX   r#   r   	numerator)r)   r]   rN   r1   r1   r2   rY   s  s.    


 

zEllipticCurvePoint.orderN)re   rf   rg   rh   staticmethodrV   r3   ro   rr   ru   rv   rw   rB   rz   rY   r1   r1   r1   r2   r6     s   


r6   N)Zsympy.core.numbersr   Zsympy.core.relationalr   Zsympy.core.symbolr   Zsympy.polys.domainsr   r   r   r   Zsympy.solvers.solversr	   Zsympy.utilities.iterablesr
   Zsympy.utilities.miscr   Zfactor_r   Zresidue_ntheoryr   r   r6   r1   r1   r1   r2   <module>   s      