o
    3IhL                     @  s  d 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
 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 ddlmZ G dd deZG dd deZG dd deZG dd dZG dd deeZe  Ze_G dd deeZe  Ze_dS )zDomains of Gaussian type.    )annotations)I)DMP)CoercionFailed)ZZ)QQ)AlgebraicField)Domain)DomainElement)Field)Ringc                      s   e Zd ZU dZded< ded< dZd7ddZe f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edd Zdd ZeZdd  Zd!d" Zd#d$ ZeZd%d& Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Z   Z!S )8GaussianElementz1Base class for elements of Gaussian type domains.r	   base_parent)xyr   c                 C  s   | j j}| ||||S N)r   convertnew)clsr   r   conv r   c/home/air/sanwanet/gpt-api/venv/lib/python3.10/site-packages/sympy/polys/domains/gaussiandomains.py__new__   s   zGaussianElement.__new__c                   s   t  | }||_||_|S )z0Create a new GaussianElement of the same domain.)superr   r   r   )r   r   r   obj	__class__r   r   r      s   zGaussianElement.newc                 C  s   | j S )z4The domain that this is an element of (ZZ_I or QQ_I))r   selfr   r   r   parent#   s   zGaussianElement.parentc                 C  s   t | j| jfS r   )hashr   r   r   r   r   r   __hash__'      zGaussianElement.__hash__c                 C  s(   t || jr| j|jko| j|jkS tS r   )
isinstancer   r   r   NotImplementedr   otherr   r   r   __eq__*   s   zGaussianElement.__eq__c                 C  s&   t |tstS | j| jg|j|jgk S r   )r$   r   r%   r   r   r&   r   r   r   __lt__0   s   
zGaussianElement.__lt__c                 C     | S r   r   r   r   r   r   __pos__5      zGaussianElement.__pos__c                 C  s   |  | j | j S r   r   r   r   r   r   r   r   __neg__8      zGaussianElement.__neg__c                 C  s   d| j j| j| jf S )Nz
%s(%s, %s))r   repr   r   r   r   r   r   __repr__;   s   zGaussianElement.__repr__c                 C  s   t | j| S r   )strr   to_sympyr   r   r   r   __str__>   r#   zGaussianElement.__str__c                 C  s<   t || sz| j|}W n
 ty   Y dS w |j|jfS )N)NN)r$   r   r   r   r   r   )r   r'   r   r   r   _get_xyA   s   
zGaussianElement._get_xyc                 C  s2   |  |\}}|d ur| | j| | j| S tS r   r5   r   r   r   r%   r   r'   r   r   r   r   r   __add__J      zGaussianElement.__add__c                 C  s2   |  |\}}|d ur| | j| | j| S tS r   r6   r7   r   r   r   __sub__S   r9   zGaussianElement.__sub__c                 C  s2   |  |\}}|d ur| || j || j S tS r   r6   r7   r   r   r   __rsub__Z   r9   zGaussianElement.__rsub__c                 C  sF   |  |\}}|d ur!| | j| | j|  | j| | j|  S tS r   r6   r7   r   r   r   __mul__a   s   ,zGaussianElement.__mul__c                 C  s   |dkr
|  ddS |dk rd|  | } }|dkr| S | }|d r$| n| jj}|d }|r@||9 }|d r:||9 }|d }|s.|S )Nr         )r   r   one)r   exppow2prodr   r   r   __pow__j   s    zGaussianElement.__pow__c                 C  s   t | jp	t | jS r   )boolr   r   r   r   r   r   __bool__{   r/   zGaussianElement.__bool__c                 C  sJ   | j dkr| jdkrdS dS | j dk r| jdk rdS dS | jdkr#dS dS )zIReturn quadrant index 0-3.

        0 is included in quadrant 0.
        r   r=   r>      )r   r   r   r   r   r   quadrant~   s
   

zGaussianElement.quadrantc                 C  s2   z| j |}W n ty   t Y S w || S r   )r   r   r   r%   
__divmod__r&   r   r   r   __rdivmod__   s   
zGaussianElement.__rdivmod__c                 C  s0   zt |}W n ty   t Y S w || S r   )QQ_Ir   r   r%   __truediv__r&   r   r   r   __rtruediv__   s   
zGaussianElement.__rtruediv__c                 C     |  |}|tu r|S |d S Nr   rH   r%   r   r'   qrr   r   r   __floordiv__      
zGaussianElement.__floordiv__c                 C  rM   rN   rI   r%   rP   r   r   r   __rfloordiv__   rS   zGaussianElement.__rfloordiv__c                 C  rM   Nr=   rO   rP   r   r   r   __mod__   rS   zGaussianElement.__mod__c                 C  rM   rV   rT   rP   r   r   r   __rmod__   rS   zGaussianElement.__rmod__)r   )"__name__
__module____qualname____doc____annotations__	__slots__r   classmethodr   r    r"   r(   r)   r+   r.   r1   r4   r5   r8   __radd__r:   r;   r<   __rmul__rC   rE   rG   rI   rL   rR   rU   rW   rX   __classcell__r   r   r   r   r      sB   
 

r   c                   @  $   e Zd ZdZeZdd Zdd ZdS )GaussianIntegerzGaussian integer: domain element for :ref:`ZZ_I`

        >>> from sympy import ZZ_I
        >>> z = ZZ_I(2, 3)
        >>> z
        (2 + 3*I)
        >>> type(z)
        <class 'sympy.polys.domains.gaussiandomains.GaussianInteger'>
    c                 C  s   t | | S )Return a Gaussian rational.)rJ   r   r&   r   r   r   rK      s   zGaussianInteger.__truediv__c           
      C  s   |s	t d| | |\}}|d u rtS | j| | j|  | j | | j|  }}|| ||  }d| | d|  }d| | d|  }t||}	|	| |	|  fS )Nzdivmod({}, 0)r>   )ZeroDivisionErrorformatr5   r%   r   r   rd   )
r   r'   r   r   abcqxqyqr   r   r   rH      s   ,
zGaussianInteger.__divmod__N)rY   rZ   r[   r\   r   r   rK   rH   r   r   r   r   rd      s
    	rd   c                   @  rc   )GaussianRationala  Gaussian rational: domain element for :ref:`QQ_I`

        >>> from sympy import QQ_I, QQ
        >>> z = QQ_I(QQ(2, 3), QQ(4, 5))
        >>> z
        (2/3 + 4/5*I)
        >>> type(z)
        <class 'sympy.polys.domains.gaussiandomains.GaussianRational'>
    c                 C  sp   |s	t d| | |\}}|du rtS || ||  }t| j| | j|  | | j | | j|  | S )re   z{} / 0N)rf   rg   r5   r%   rn   r   r   )r   r'   r   r   rj   r   r   r   rK      s   zGaussianRational.__truediv__c                 C  sH   z| j |}W n ty   t Y S w |std| | | tjfS )Nz{} % 0)r   r   r   r%   rf   rg   rJ   zeror&   r   r   r   rH      s   zGaussianRational.__divmod__N)rY   rZ   r[   r\   r   r   rK   rH   r   r   r   r   rn      s
    	rn   c                   @  s   e Zd ZU dZded< dZdZdZ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d Zdd Zdd Zdd Zdd  Zd!d" Zd#S )$GaussianDomainz Base class for Gaussian domains.r	   domTc                 C  s    | j j}||jt||j  S )z!Convert ``a`` to a SymPy object. )rq   r3   r   r   r   )r   rh   r   r   r   r   r3      s   zGaussianDomain.to_sympyc                 C  sb   |  \}}| j|}|s| |dS | \}}| j|}|tu r*| ||S td|)z)Convert a SymPy object to ``self.dtype``.r   z{} is not Gaussian)as_coeff_Addrq   
from_sympyr   as_coeff_Mulr   r   rg   )r   rh   rri   r   r   r   r   r   rs     s   zGaussianDomain.from_sympyc                 G  s
   | j | S )z$Inject generators into this domain. )	poly_ring)r   gensr   r   r   inject  s   
zGaussianDomain.injectc                 C  s   | j |   }|S r   )unitsrG   )r   dunitr   r   r   canonical_unit  s   zGaussianDomain.canonical_unitc                 C     dS z/Returns ``False`` for any ``GaussianElement``. Fr   r   elementr   r   r   is_negative     zGaussianDomain.is_negativec                 C  r}   r~   r   r   r   r   r   is_positive  r   zGaussianDomain.is_positivec                 C  r}   r~   r   r   r   r   r   is_nonnegative"  r   zGaussianDomain.is_nonnegativec                 C  r}   r~   r   r   r   r   r   is_nonpositive&  r   zGaussianDomain.is_nonpositivec                 C     | |S )z%Convert a GMPY mpz to ``self.dtype``.r   K1rh   K0r   r   r   from_ZZ_gmpy*     zGaussianDomain.from_ZZ_gmpyc                 C  r   z.Convert a ZZ_python element to ``self.dtype``.r   r   r   r   r   from_ZZ.  r   zGaussianDomain.from_ZZc                 C  r   r   r   r   r   r   r   from_ZZ_python2  r   zGaussianDomain.from_ZZ_pythonc                 C  r   z%Convert a GMPY mpq to ``self.dtype``.r   r   r   r   r   from_QQ6  r   zGaussianDomain.from_QQc                 C  r   r   r   r   r   r   r   from_QQ_gmpy:  r   zGaussianDomain.from_QQ_gmpyc                 C  r   )z.Convert a QQ_python element to ``self.dtype``.r   r   r   r   r   from_QQ_python>  r   zGaussianDomain.from_QQ_pythonc                 C  s$   |j jd tkr| ||S dS )z9Convert an element from ZZ<I> or QQ<I> to ``self.dtype``.r   N)extargsr   rs   r3   r   r   r   r   from_AlgebraicFieldB  s   z"GaussianDomain.from_AlgebraicFieldN)rY   rZ   r[   r\   r]   is_Numericalis_Exacthas_assoc_Ringhas_assoc_Fieldr3   rs   rx   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rp      s,   
 rp   c                   @  s   e Zd ZdZeZeejejejgeZ	e
ZeededZeededZeededZeee e fZdZdZdZdZdd Zdd	 Zd
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 )!GaussianIntegerRinga{
  Ring of Gaussian integers ``ZZ_I``

    The :ref:`ZZ_I` domain represents the `Gaussian integers`_ `\mathbb{Z}[i]`
    as a :py:class:`~.Domain` in the domain system (see
    :ref:`polys-domainsintro`).

    By default a :py:class:`~.Poly` created from an expression with
    coefficients that are combinations of integers and ``I`` (`\sqrt{-1}`)
    will have the domain :ref:`ZZ_I`.

    >>> from sympy import Poly, Symbol, I
    >>> x = Symbol('x')
    >>> p = Poly(x**2 + I)
    >>> p
    Poly(x**2 + I, x, domain='ZZ_I')
    >>> p.domain
    ZZ_I

    The :ref:`ZZ_I` domain can be used to factorise polynomials that are
    reducible over the Gaussian integers.

    >>> from sympy import factor
    >>> factor(x**2 + 1)
    x**2 + 1
    >>> factor(x**2 + 1, domain='ZZ_I')
    (x - I)*(x + I)

    The corresponding `field of fractions`_ is the domain of the Gaussian
    rationals :ref:`QQ_I`. Conversely :ref:`ZZ_I` is the `ring of integers`_
    of :ref:`QQ_I`.

    >>> from sympy import ZZ_I, QQ_I
    >>> ZZ_I.get_field()
    QQ_I
    >>> QQ_I.get_ring()
    ZZ_I

    When using the domain directly :ref:`ZZ_I` can be used as a constructor.

    >>> ZZ_I(3, 4)
    (3 + 4*I)
    >>> ZZ_I(5)
    (5 + 0*I)

    The domain elements of :ref:`ZZ_I` are instances of
    :py:class:`~.GaussianInteger` which support the rings operations
    ``+,-,*,**``.

    >>> z1 = ZZ_I(5, 1)
    >>> z2 = ZZ_I(2, 3)
    >>> z1
    (5 + 1*I)
    >>> z2
    (2 + 3*I)
    >>> z1 + z2
    (7 + 4*I)
    >>> z1 * z2
    (7 + 17*I)
    >>> z1 ** 2
    (24 + 10*I)

    Both floor (``//``) and modulo (``%``) division work with
    :py:class:`~.GaussianInteger` (see the :py:meth:`~.Domain.div` method).

    >>> z3, z4 = ZZ_I(5), ZZ_I(1, 3)
    >>> z3 // z4  # floor division
    (1 + -1*I)
    >>> z3 % z4   # modulo division (remainder)
    (1 + -2*I)
    >>> (z3//z4)*z4 + z3%z4 == z3
    True

    True division (``/``) in :ref:`ZZ_I` gives an element of :ref:`QQ_I`. The
    :py:meth:`~.Domain.exquo` method can be used to divide in :ref:`ZZ_I` when
    exact division is possible.

    >>> z1 / z2
    (1 + -1*I)
    >>> ZZ_I.exquo(z1, z2)
    (1 + -1*I)
    >>> z3 / z4
    (1/2 + -3/2*I)
    >>> ZZ_I.exquo(z3, z4)
    Traceback (most recent call last):
        ...
    ExactQuotientFailed: (1 + 3*I) does not divide (5 + 0*I) in ZZ_I

    The :py:meth:`~.Domain.gcd` method can be used to compute the `gcd`_ of any
    two elements.

    >>> ZZ_I.gcd(ZZ_I(10), ZZ_I(2))
    (2 + 0*I)
    >>> ZZ_I.gcd(ZZ_I(5), ZZ_I(2, 1))
    (2 + 1*I)

    .. _Gaussian integers: https://en.wikipedia.org/wiki/Gaussian_integer
    .. _gcd: https://en.wikipedia.org/wiki/Greatest_common_divisor

    r   r=   ZZ_ITc                 C  r}   )zFor constructing ZZ_I.Nr   r   r   r   r   __init__      zGaussianIntegerRing.__init__c                 C     t |trdS tS z0Returns ``True`` if two domains are equivalent. T)r$   r   r%   r&   r   r   r   r(        
zGaussianIntegerRing.__eq__c                 C     t dS )Compute hash code of ``self``. r   r!   r   r   r   r   r"     r   zGaussianIntegerRing.__hash__c                 C  r}   NTr   r   r   r   r   has_CharacteristicZero  r   z*GaussianIntegerRing.has_CharacteristicZeroc                 C  r}   rN   r   r   r   r   r   characteristic  r,   z"GaussianIntegerRing.characteristicc                 C  r*   z)Returns a ring associated with ``self``. r   r   r   r   r   get_ring  r   zGaussianIntegerRing.get_ringc                 C     t S z*Returns a field associated with ``self``. )rJ   r   r   r   r   	get_field  r   zGaussianIntegerRing.get_fieldc                   s:   |  | | 9 }t fdd|D }|r|f| S |S )zReturn first quadrant element associated with ``d``.

        Also multiply the other arguments by the same power of i.
        c                 3  s    | ]}|  V  qd S r   r   ).0rh   r{   r   r   	<genexpr>  s    z0GaussianIntegerRing.normalize.<locals>.<genexpr>)r|   tuple)r   rz   r   r   r   r   	normalize  s   
zGaussianIntegerRing.normalizec                 C  s    |r||| }}|s|  |S )z-Greatest common divisor of a and b over ZZ_I.)r   r   rh   ri   r   r   r   gcd  s   
zGaussianIntegerRing.gcdc                 C  s|   | j }| j}| j}| j }|r/|| }||||  }}||||  }}||||  }}|s| |||\}}}|||fS )z6Return x, y, g such that x * a + y * b = g = gcd(a, b))r?   ro   r   )r   rh   ri   x_ax_by_ay_brm   r   r   r   gcdex  s   
zGaussianIntegerRing.gcdexc                 C  s   || |  || S )z+Least common multiple of a and b over ZZ_I.)r   r   r   r   r   lcm  s   zGaussianIntegerRing.lcmc                 C     |S )zConvert a ZZ_I element to ZZ_I.r   r   r   r   r   from_GaussianIntegerRing  r   z,GaussianIntegerRing.from_GaussianIntegerRingc                 C     |  t|jt|jS )zConvert a QQ_I element to ZZ_I.)r   r   r   r   r   r   r   r   r   from_GaussianRationalField     z.GaussianIntegerRing.from_GaussianRationalFieldN) rY   rZ   r[   r\   r   rq   r   r?   ro   modrd   dtype	imag_unitry   r0   is_GaussianRingis_ZZ_Iis_PIDr   r(   r"   propertyr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   H  s6    c

r   c                   @  s   e Zd ZdZeZeejejejgeZ	e
ZeededZeededZeededZeee e fZdZdZdZdd Zdd	 Zd
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 )!GaussianRationalFielda  Field of Gaussian rationals ``QQ_I``

    The :ref:`QQ_I` domain represents the `Gaussian rationals`_ `\mathbb{Q}(i)`
    as a :py:class:`~.Domain` in the domain system (see
    :ref:`polys-domainsintro`).

    By default a :py:class:`~.Poly` created from an expression with
    coefficients that are combinations of rationals and ``I`` (`\sqrt{-1}`)
    will have the domain :ref:`QQ_I`.

    >>> from sympy import Poly, Symbol, I
    >>> x = Symbol('x')
    >>> p = Poly(x**2 + I/2)
    >>> p
    Poly(x**2 + I/2, x, domain='QQ_I')
    >>> p.domain
    QQ_I

    The polys option ``gaussian=True`` can be used to specify that the domain
    should be :ref:`QQ_I` even if the coefficients do not contain ``I`` or are
    all integers.

    >>> Poly(x**2)
    Poly(x**2, x, domain='ZZ')
    >>> Poly(x**2 + I)
    Poly(x**2 + I, x, domain='ZZ_I')
    >>> Poly(x**2/2)
    Poly(1/2*x**2, x, domain='QQ')
    >>> Poly(x**2, gaussian=True)
    Poly(x**2, x, domain='QQ_I')
    >>> Poly(x**2 + I, gaussian=True)
    Poly(x**2 + I, x, domain='QQ_I')
    >>> Poly(x**2/2, gaussian=True)
    Poly(1/2*x**2, x, domain='QQ_I')

    The :ref:`QQ_I` domain can be used to factorise polynomials that are
    reducible over the Gaussian rationals.

    >>> from sympy import factor, QQ_I
    >>> factor(x**2/4 + 1)
    (x**2 + 4)/4
    >>> factor(x**2/4 + 1, domain='QQ_I')
    (x - 2*I)*(x + 2*I)/4
    >>> factor(x**2/4 + 1, domain=QQ_I)
    (x - 2*I)*(x + 2*I)/4

    It is also possible to specify the :ref:`QQ_I` domain explicitly with
    polys functions like :py:func:`~.apart`.

    >>> from sympy import apart
    >>> apart(1/(1 + x**2))
    1/(x**2 + 1)
    >>> apart(1/(1 + x**2), domain=QQ_I)
    I/(2*(x + I)) - I/(2*(x - I))

    The corresponding `ring of integers`_ is the domain of the Gaussian
    integers :ref:`ZZ_I`. Conversely :ref:`QQ_I` is the `field of fractions`_
    of :ref:`ZZ_I`.

    >>> from sympy import ZZ_I, QQ_I, QQ
    >>> ZZ_I.get_field()
    QQ_I
    >>> QQ_I.get_ring()
    ZZ_I

    When using the domain directly :ref:`QQ_I` can be used as a constructor.

    >>> QQ_I(3, 4)
    (3 + 4*I)
    >>> QQ_I(5)
    (5 + 0*I)
    >>> QQ_I(QQ(2, 3), QQ(4, 5))
    (2/3 + 4/5*I)

    The domain elements of :ref:`QQ_I` are instances of
    :py:class:`~.GaussianRational` which support the field operations
    ``+,-,*,**,/``.

    >>> z1 = QQ_I(5, 1)
    >>> z2 = QQ_I(2, QQ(1, 2))
    >>> z1
    (5 + 1*I)
    >>> z2
    (2 + 1/2*I)
    >>> z1 + z2
    (7 + 3/2*I)
    >>> z1 * z2
    (19/2 + 9/2*I)
    >>> z2 ** 2
    (15/4 + 2*I)

    True division (``/``) in :ref:`QQ_I` gives an element of :ref:`QQ_I` and
    is always exact.

    >>> z1 / z2
    (42/17 + -2/17*I)
    >>> QQ_I.exquo(z1, z2)
    (42/17 + -2/17*I)
    >>> z1 == (z1/z2)*z2
    True

    Both floor (``//``) and modulo (``%``) division can be used with
    :py:class:`~.GaussianRational` (see :py:meth:`~.Domain.div`)
    but division is always exact so there is no remainder.

    >>> z1 // z2
    (42/17 + -2/17*I)
    >>> z1 % z2
    (0 + 0*I)
    >>> QQ_I.div(z1, z2)
    ((42/17 + -2/17*I), (0 + 0*I))
    >>> (z1//z2)*z2 + z1%z2 == z1
    True

    .. _Gaussian rationals: https://en.wikipedia.org/wiki/Gaussian_rational
    r   r=   rJ   Tc                 C  r}   )zFor constructing QQ_I.Nr   r   r   r   r   r     r   zGaussianRationalField.__init__c                 C  r   r   )r$   r   r%   r&   r   r   r   r(     r   zGaussianRationalField.__eq__c                 C  r   )r   rJ   r   r   r   r   r   r"     r   zGaussianRationalField.__hash__c                 C  r}   r   r   r   r   r   r   r     r   z,GaussianRationalField.has_CharacteristicZeroc                 C  r}   rN   r   r   r   r   r   r     r,   z$GaussianRationalField.characteristicc                 C  r   r   )r   r   r   r   r   r     r   zGaussianRationalField.get_ringc                 C  r*   r   r   r   r   r   r   r     r   zGaussianRationalField.get_fieldc                 C  s   t | jtS )z0Get equivalent domain as an ``AlgebraicField``. )r   rq   r   r   r   r   r   as_AlgebraicField  s   z'GaussianRationalField.as_AlgebraicFieldc                 C  s   |   }||| | S )zGet the numerator of ``a``.)r   r   denom)r   rh   r   r   r   r   numer  s   zGaussianRationalField.numerc                 C  s@   | j  }| j }|  }|||j||j}|||jS )zGet the denominator of ``a``.)rq   r   r   r   r   r   ro   )r   rh   r   r   r   denom_ZZr   r   r   r     s
   
zGaussianRationalField.denomc                 C  s   |  |j|jS )zConvert a ZZ_I element to QQ_I.r-   r   r   r   r   r     s   z.GaussianRationalField.from_GaussianIntegerRingc                 C  r   )zConvert a QQ_I element to QQ_I.r   r   r   r   r   r     r   z0GaussianRationalField.from_GaussianRationalFieldc                 C  r   )z'Convert a ComplexField element to QQ_I.)r   r   r   realimagr   r   r   r   from_ComplexField  r   z'GaussianRationalField.from_ComplexFieldN)rY   rZ   r[   r\   r   rq   r   r?   ro   r   rn   r   r   ry   r0   is_GaussianFieldis_QQ_Ir   r(   r"   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r     s4    t
r   N) r\   
__future__r   sympy.core.numbersr   sympy.polys.polyclassesr   sympy.polys.polyerrorsr   sympy.polys.domains.integerringr   !sympy.polys.domains.rationalfieldr   "sympy.polys.domains.algebraicfieldr   sympy.polys.domains.domainr	   !sympy.polys.domains.domainelementr
   sympy.polys.domains.fieldr   sympy.polys.domains.ringr   r   rd   rn   rp   r   r   r   r   rJ   r   r   r   r   <module>   s.     (#R ; >