o
    *ήc,                     @   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 )#EllipticCurveaG  
    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] http://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| _d S t| jtrd | _d S d S )	Nr                  	   zx y z)r   r   mapconvert_domainmodulus_b2_b4_b6_b8_discrim_a1_a2_a3_a4_a6r   xyzr   _eq
isinstancer   _rankr   )selfa4a6a1a2a3r   domainb2b4b6b8r$   r%   r&    r5   C/tmp/pip-target-vg8gfxp4/lib/python/sympy/ntheory/elliptic_curve.py__init__$   s2    88d

zEllipticCurve.__init__r   c                 C   s   t |||| S NEllipticCurvePoint)r*   r$   r%   r&   r5   r5   r6   __call__@   s   zEllipticCurve.__call__c                 C   s   t |rt|dkrd}n|d }|d d \}}nt|tr+|j|j|j}}}ntd| jdkr:|dkr:dS | j	
| j|| j|| j|iS )Nr   r   zInvalid point.r   T)r
   lenr(   r:   r$   r%   r&   
ValueErrorcharacteristicr'   subs)r*   pointz1x1y1r5   r5   r6   __contains__C   s   
zEllipticCurve.__contains__c                 C   s   d | j| jS )Nz	E({}): {})formatr   r'   r*   r5   r5   r6   __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c4c6r5   r5   r6   minimalU   s   $&zEllipticCurve.minimalc                 C   sr   | j }t }|dkr5t|D ]$}| jj| jj | j|| jdi}t	||}|D ]	}|
||f q(q|S td)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 points)r>   setranger'   lhsrhsr?   r$   r&   r   addr=   )r*   rK   all_pticongruence_eqsolnumr5   r5   r6   pointsl   s   "
zEllipticCurve.pointsc                 C   s|   g }| j tkrt| j| j|D ]	}|||f q| jj| jj | j|| j	di}t
|| jD ]	}|||f q2|S )z2Returns points on with curve where xcoordinate = xr   )r   r   r	   r'   r?   r$   appendrQ   rR   r&   r   r>   )r*   r$   ptr%   rV   r5   r5   r6   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 ]6}t|d }|d |krht| j| j|| jdiD ]}|j	sTqN| ||}| tkrg||| g qNq2|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>   r=   r:   point_at_infinityr	   r'   r?   r%   r&   is_rationalrZ   r   discriminantintorderr   extend)r*   lxxrU   jpr5   r5   r6   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>   rF   r5   r5   r6   r>         
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

        )ra   r   rF   r5   r5   r6   r`      ri   zEllipticCurve.discriminantc                 C   s
   | j dkS )zE
        Return True if curve discriminant is equal to zero.
        r   )r`   rF   r5   r5   r6   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   rH   r   )r   r   r   to_sympyr   )r*   rL   r5   r5   r6   j_invariant   s   zEllipticCurve.j_invariantc                 C   s"   | j dkr	tdt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>   NotImplementedErrorr<   listrY   rF   r5   r5   r6   rb      s   
zEllipticCurve.orderc                 C   s   | j dur| j S td)zj
        Number of independent points of infinite order.

        For Finite field, it must be 0.
        Nrm   )r)   rn   rF   r5   r5   r6   rank   s   
zEllipticCurve.rankN)r   r   r   r   )r   )__name__
__module____qualname____doc__r7   r;   rD   rG   rN   rY   r\   rh   propertyr>   r`   rj   rl   rb   rp   r5   r5   r5   r6   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 )r:   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   r9   )curver5   r5   r6   r^   (  s   z$EllipticCurvePoint.point_at_infinityc                 C   sN   |j j}||| _||| _||| _|| _| jj | _ | j| s%tdd S )Nz%The curve does not contain this point)r   r   r$   r%   r&   _curverD   r=   )r*   r$   r%   r&   rw   domr5   r5   r6   r7   ,  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rU|| ||  }|| ||  ||  }nC|| dkra| 	| jS d|d  d| |  |	 ||  || | d|   }|d  |	|  d|
  ||  || | d|   }|d ||  | | | }||  | | | }| ||dS )Nr   r   r   r   )
r&   r$   r%   rx   r   r    r!   r"   r#   r^   )r*   rg   rB   rC   x2y2r-   r.   r/   r+   r,   slopeyintx3y3r5   r5   r6   __add__6  s*   

86zEllipticCurvePoint.__add__c                 C   s    | j | j| jf|j |j|jfk S r8   )r$   r%   r&   r*   otherr5   r5   r6   __lt__N  s    zEllipticCurvePoint.__lt__c                 C   sd   t |}| | j}|dkr|S |dk r|  |  S | }|r0|d@ r&|| }|dL }|| }|s|S rv   )r   r^   rx   )r*   nrrg   r5   r5   r6   __mul__Q  s   zEllipticCurvePoint.__mul__c                 C   s   | | S r8   r5   )r*   r   r5   r5   r6   __rmul__`  s   zEllipticCurvePoint.__rmul__c                 C   s.   t | j| j | jj| j  | jj | j| jS r8   )r:   r$   r%   rx   r   r!   r&   rF   r5   r5   r6   __neg__c  s   .zEllipticCurvePoint.__neg__c                 C   sX   | j dkrdS | jj}zd|| j|| jW S  ty#   Y nw d| j| jS )Nr   Oz({}, {}))r&   rx   r   rE   rk   r$   r%   	TypeError)r*   ry   r5   r5   r6   rG   f  s   
zEllipticCurvePoint.__repr__c                 C   s   |  | S r8   )r   r   r5   r5   r6   __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rdS d}| jtkrSt|j|jkrQt|j|jkrQ| | }|d7 }|j dkrA|S t|j|jkrQt|j|jks2tS |jj|jkr|jj|jkr| | }|d7 }|dkrotS |j dkrv|S |jj|jkr|jj|jksatS )z5
        Return point order n where nP = 0.

        r   r   r   r      )r&   r%   r   r   ra   r$   r   	numerator)r*   rg   rU   r5   r5   r6   rb   s  s2   


 
 
zEllipticCurvePoint.orderN)rq   rr   rs   rt   staticmethodr^   r7   r   r   r   r   r   rG   r   rb   r5   r5   r5   r6   r:     s    


r:   N)sympy.core.numbersr   sympy.core.relationalr   sympy.core.symbolr   sympy.polys.domainsr   r   r   r   sympy.solvers.solversr	   sympy.utilities.iterablesr
   sympy.utilities.miscr   factor_r   residue_ntheoryr   r   r:   r5   r5   r5   r6   <module>   s     