a
    RG5d`@                     @   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
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mZ ddlmZmZmZ ddlmZ ddlmZ dd Zdd Z dd Z!eddddZ"dd Z#dd Z$ed%dddd d!Z%ed&ddd"d#d$Z&dS )'a@  
Functions in ``polys.numberfields.subfield`` solve the "Subfield Problem" and
allied problems, for algebraic number fields.

Following Cohen (see [Cohen93]_ Section 4.5), we can define the main problem as
follows:

* **Subfield Problem:**

  Given two number fields $\mathbb{Q}(\alpha)$, $\mathbb{Q}(\beta)$
  via the minimal polynomials for their generators $\alpha$ and $\beta$, decide
  whether one field is isomorphic to a subfield of the other.

From a solution to this problem flow solutions to the following problems as
well:

* **Primitive Element Problem:**

  Given several algebraic numbers
  $\alpha_1, \ldots, \alpha_m$, compute a single algebraic number $\theta$
  such that $\mathbb{Q}(\alpha_1, \ldots, \alpha_m) = \mathbb{Q}(\theta)$.

* **Field Isomorphism Problem:**

  Decide whether two number fields
  $\mathbb{Q}(\alpha)$, $\mathbb{Q}(\beta)$ are isomorphic.

* **Field Membership Problem:**

  Given two algebraic numbers $\alpha$,
  $\beta$, decide whether $\alpha \in \mathbb{Q}(\beta)$, and if so write
  $\alpha = f(\beta)$ for some $f(x) \in \mathbb{Q}[x]$.
    )Add)AlgebraicNumberS)Dummy)sympify_sympify)sieve)dup_eval)QQ)_choose_factorminimal_polynomial)IsomorphismFailed)PolyPurePolyfactor_list)public)	MPContextc                 C   s   | j  }|j  }|| dkr$dS ||kr0dS | j  }|j  }d|| |d   }}}t| }	|	| }
|
|krvq||	 d r||
 sdS |d7 }q\dS )z3Necessary but not sufficient test for isomorphism. r   FT      )minpolydegreediscriminantr	   )abnmdadbikhalfpP r$   ]/var/www/html/django/DPS/env/lib/python3.9/site-packages/sympy/polys/numberfields/subfield.pyis_isomorphism_possible3   s"    




r&   c                    s@  | j jr|j jstd| j}|j|j}d|j d  }}}t }tddD ]}| j 	|}	|j 	| d g fddtd|D  |	 g }
||_
|j|
d	d
ddu r q<|krȈ}n q<fdddd D d s  qttt|jdd}|||jr2  S |d9 }qRdS )z2Construct field isomorphism using PSLQ algorithm. z)PSLQ doesn't support complex coefficientsd   Nr      c                    s   g | ]} | qS r$   r$   ).0r   )Br$   r%   
<listcomp>a       z*field_isomorphism_pslq.<locals>.<listcomp>r   l    d(	 i  )maxcoeffmaxstepsc                    s   g | ]}t | d   qS )r   )r)   c)coeffsr$   r%   r+   u   r,   r/   r   domain)rootis_realNotImplementedErrorr   replacegenr   r   rangeevalfdpspslqpoplistreversedr   composeremis_zero)r   r   fgr   r   prevctxr   Abasishr$   )r*   r1   r%   field_isomorphism_pslqR   s4    (

rJ   c                 C   s   t | j|d\}}|D ]\}}| dkr|j  }| }t|d g  }}t|D ] \}	}
||
|j	||	    qXt
| }| j|| r|  S qdS )z/Construct field isomorphism via factorization. 	extensionr   N)r   r   r   repTCto_sympy_listlen	enumerateappendr4   r   	same_root)r   r   _factorsrC   r0   r1   dtermsr   coeffrr$   r$   r%   field_isomorphism_factor   s    
rZ   T)fastc                C   s   t | t | } }| js t| } |js.t|}|  } | }| |krN|  S | j }|j }|dkrr| jgS || dkrdS |rzt| |}|dur|W S W n t	y   Y n0 t
| |S )a  
    Find an embedding of one number field into another.

    Explanation
    ===========

    This function looks for an isomorphism from $\mathbb{Q}(a)$ onto some
    subfield of $\mathbb{Q}(b)$. Thus, it solves the Subfield Problem.

    Examples
    ========

    >>> from sympy import sqrt, field_isomorphism, I
    >>> print(field_isomorphism(3, sqrt(2)))  # doctest: +SKIP
    [3]
    >>> print(field_isomorphism( I*sqrt(3), I*sqrt(3)/2))  # doctest: +SKIP
    [2, 0]

    Parameters
    ==========

    a : :py:class:`~.Expr`
        Any expression representing an algebraic number.
    b : :py:class:`~.Expr`
        Any expression representing an algebraic number.
    fast : boolean, optional (default=True)
        If ``True``, we first attempt a potentially faster way of computing the
        isomorphism, falling back on a slower method if this fails. If
        ``False``, we go directly to the slower method, which is guaranteed to
        return a result.

    Returns
    =======

    List of rational numbers, or None
        If $\mathbb{Q}(a)$ is not isomorphic to some subfield of
        $\mathbb{Q}(b)$, then return ``None``. Otherwise, return a list of
        rational numbers representing an element of $\mathbb{Q}(b)$ to which
        $a$ may be mapped, in order to define a monomorphism, i.e. an
        isomorphism from $\mathbb{Q}(a)$ to some subfield of $\mathbb{Q}(b)$.
        The elements of the list are the coefficients of falling powers of $b$.

    r   r   N)r   is_AlgebraicNumberr   to_primitive_elementr1   r   r   r4   rJ   r6   rZ   )r   r   r[   r   r   resultr$   r$   r%   field_isomorphism   s.    -



r_   c                 C   s*   | j  }|j|dd}| || jd S )NT)frontr   )rM   injectejectnewgens)rD   KZfrepZhrepr$   r$   r%   _switch_domain   s    
rf   c                 C   s   | j j \}}| | S )NrM   )r"   r0   rV   r$   r$   r%   	_linsolve   s    rh   NF)expolysc                   sd  | st ddd | D } |dur2t|t }}ntdt }}|s| d dg }}t||dd	}| dd D ]V}|jr|d qnt||d
\}	}
t	|
||}|
 \}}	}||| 7 }|| qn|s| |fS |||fS | d dg }}t||dd	}t||f  jg}| dd D ]}|jrL|d | | q"t||dd	}t||f}t||d\}	}
t	|
||}|
 \}}}||| 7 }|| t||f t| }t||} j||   fdd|D |g }q" jjjr4 fdd| D }dgt|  }||td}ndd |D }|sV| ||fS |||fS dS )a	  
    Find a single generator for a number field given by several generators.

    Explanation
    ===========

    The basic problem is this: Given several algebraic numbers
    $\alpha_1, \alpha_2, \ldots, \alpha_n$, find a single algebraic number
    $\theta$ such that
    $\mathbb{Q}(\alpha_1, \alpha_2, \ldots, \alpha_n) = \mathbb{Q}(\theta)$.

    This function actually guarantees that $\theta$ will be a linear
    combination of the $\alpha_i$, with non-negative integer coefficients.

    Furthermore, if desired, this function will tell you how to express each
    $\alpha_i$ as a $\mathbb{Q}$-linear combination of the powers of $\theta$.

    Examples
    ========

    >>> from sympy import primitive_element, sqrt, S, minpoly, simplify
    >>> from sympy.abc import x
    >>> f, lincomb, reps = primitive_element([sqrt(2), sqrt(3)], x, ex=True)

    Then ``lincomb`` tells us the primitive element as a linear combination of
    the given generators ``sqrt(2)`` and ``sqrt(3)``.

    >>> print(lincomb)
    [1, 1]

    This means the primtiive element is $\sqrt{2} + \sqrt{3}$.
    Meanwhile ``f`` is the minimal polynomial for this primitive element.

    >>> print(f)
    x**4 - 10*x**2 + 1
    >>> print(minpoly(sqrt(2) + sqrt(3), x))
    x**4 - 10*x**2 + 1

    Finally, ``reps`` (which was returned only because we set keyword arg
    ``ex=True``) tells us how to recover each of the generators $\sqrt{2}$ and
    $\sqrt{3}$ as $\mathbb{Q}$-linear combinations of the powers of the
    primitive element $\sqrt{2} + \sqrt{3}$.

    >>> print([S(r) for r in reps[0]])
    [1/2, 0, -9/2, 0]
    >>> theta = sqrt(2) + sqrt(3)
    >>> print(simplify(theta**3/2 - 9*theta/2))
    sqrt(2)
    >>> print([S(r) for r in reps[1]])
    [-1/2, 0, 11/2, 0]
    >>> print(simplify(-theta**3/2 + 11*theta/2))
    sqrt(3)

    Parameters
    ==========

    extension : list of :py:class:`~.Expr`
        Each expression must represent an algebraic number $\alpha_i$.
    x : :py:class:`~.Symbol`, optional (default=None)
        The desired symbol to appear in the computed minimal polynomial for the
        primitive element $\theta$. If ``None``, we use a dummy symbol.
    ex : boolean, optional (default=False)
        If and only if ``True``, compute the representation of each $\alpha_i$
        as a $\mathbb{Q}$-linear combination over the powers of $\theta$.
    polys : boolean, optional (default=False)
        If ``True``, return the minimal polynomial as a :py:class:`~.Poly`.
        Otherwise return it as an :py:class:`~.Expr`.

    Returns
    =======

    Pair (f, coeffs) or triple (f, coeffs, reps), where:
        ``f`` is the minimal polynomial for the primitive element.
        ``coeffs`` gives the primitive element as a linear combination of the
        given generators.
        ``reps`` is present if and only if argument ``ex=True`` was passed,
        and is a list of lists of rational numbers. Each list gives the
        coefficients of falling powers of the primitive element, to recover
        one of the original, given generators.

    z4Cannot compute primitive element for empty extensionc                 S   s   g | ]}t |qS r$   )r   )r)   extr$   r$   r%   r+   W  r,   z%primitive_element.<locals>.<listcomp>Nxr   r   Trj   rK   r2   c                    s   g | ]}t |j qS r$   )r
   rM   r)   rT   re   Zogenr$   r%   r+     r,   c                    s   g | ]}  |jqS r$   )convertrM   rn   )re   r$   r%   r+     r,   c                 S   s   g | ]
}|j qS r$   rg   rn   r$   r$   r%   r+     r,   )
ValueErrorr   r   r   r   r   is_RationalrR   r   r   sqf_normas_exprr   algebraic_fieldunitrp   rf   rh   gcdrk   r4   rP   )rL   rl   ri   rj   clsr8   r1   rD   rk   rT   rU   srC   repsr"   LrI   ZerepHr$   ro   r%   primitive_element  sd    S



r}   r8   aliasc                C   s   t | drt| } n| g} t| dkrDt| d trDt| d |dS t| |dd\}}tdd t|| D }|d	u rt||f|dS t	|}|j
st|||d
}t||}|d	urt|||dS td||jf d	S )a
  
    Express one algebraic number in the field generated by another.

    Explanation
    ===========

    Given two algebraic numbers $\eta, \theta$, this function either expresses
    $\eta$ as an element of $\mathbb{Q}(\theta)$, or else raises an exception
    if $\eta \not\in \mathbb{Q}(\theta)$.

    This function is essentially just a convenience, utilizing
    :py:func:`~.field_isomorphism` (our solution of the Subfield Problem) to
    solve this, the Field Membership Problem.

    As an additional convenience, this function allows you to pass a list of
    algebraic numbers $\alpha_1, \alpha_2, \ldots, \alpha_n$ instead of $\eta$.
    It then computes $\eta$ for you, as a solution of the Primitive Element
    Problem, using :py:func:`~.primitive_element` on the list of $\alpha_i$.

    Examples
    ========

    >>> from sympy import sqrt, to_number_field
    >>> eta = sqrt(2)
    >>> theta = sqrt(2) + sqrt(3)
    >>> a = to_number_field(eta, theta)
    >>> print(type(a))
    <class 'sympy.core.numbers.AlgebraicNumber'>
    >>> a.root
    sqrt(2) + sqrt(3)
    >>> print(a)
    sqrt(2)
    >>> a.coeffs()
    [1/2, 0, -9/2, 0]

    We get an :py:class:`~.AlgebraicNumber`, whose ``.root`` is $\theta$, whose
    value is $\eta$, and whose ``.coeffs()`` show how to write $\eta$ as a
    $\mathbb{Q}$-linear combination in falling powers of $\theta$.

    Parameters
    ==========

    extension : :py:class:`~.Expr` or list of :py:class:`~.Expr`
        Either the algebraic number that is to be expressed in the other field,
        or else a list of algebraic numbers, a primitive element for which is
        to be expressed in the other field.
    theta : :py:class:`~.Expr`, None, optional (default=None)
        If an :py:class:`~.Expr` representing an algebraic number, behavior is
        as described under **Explanation**. If ``None``, then this function
        reduces to a shorthand for calling :py:func:`~.primitive_element` on
        ``extension`` and turning the computed primitive element into an
        :py:class:`~.AlgebraicNumber`.
    gen : :py:class:`~.Symbol`, None, optional (default=None)
        If provided, this will be used as the generator symbol for the minimal
        polynomial in the returned :py:class:`~.AlgebraicNumber`.
    alias : str, :py:class:`~.Symbol`, None, optional (default=None)
        If provided, this will be used as the alias symbol for the returned
        :py:class:`~.AlgebraicNumber`.

    Returns
    =======

    AlgebraicNumber
        Belonging to $\mathbb{Q}(\theta)$ and equaling $\eta$.

    Raises
    ======

    IsomorphismFailed
        If $\eta \not\in \mathbb{Q}(\theta)$.

    See Also
    ========

    field_isomorphism
    primitive_element

    __iter__r   r   )r   Trm   c                 S   s   g | ]\}}|| qS r$   r$   )r)   rX   rk   r$   r$   r%   r+     r,   z#to_number_field.<locals>.<listcomp>Nr~   z%s is not in a subfield of %s)hasattrr>   rP   
isinstancetupler   r}   sumzipr   r\   r_   r   r4   )rL   thetar8   r   r   r1   r4   r$   r$   r%   to_number_field  s$    P


r   )N)N)'__doc__Zsympy.core.addr   sympy.core.numbersr   Zsympy.core.singletonr   sympy.core.symbolr   sympy.core.sympifyr   r   sympy.ntheoryr	   sympy.polys.densetoolsr
   sympy.polys.domainsr    sympy.polys.numberfields.minpolyr   r   sympy.polys.polyerrorsr   sympy.polys.polytoolsr   r   r   Zsympy.utilitiesr   mpmathr   r&   rJ   rZ   r_   rf   rh   r}   r   r$   r$   r$   r%   <module>   s2   "8O
 