B
    [h                 @   s   d 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 ddlmZmZmZmZ ddlmZmZmZmZmZmZ d	d
 Zdd Zd(ddZd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#d+d$d%Z$d&d' Z%dS ),a  
Algorithms for solving the Risch differential equation.

Given a differential field K of characteristic 0 that is a simple
monomial extension of a base field k and f, g in K, the Risch
Differential Equation problem is to decide if there exist y in K such
that Dy + f*y == g and to find one if there are some.  If t is a
monomial over k and the coefficients of f and g are in k(t), then y is
in k(t), and the outline of the algorithm here is given as:

1. Compute the normal part n of the denominator of y.  The problem is
then reduced to finding y' in k<t>, where y == y'/n.
2. Compute the special part s of the denominator of y.   The problem is
then reduced to finding y'' in k[t], where y == y''/(n*s)
3. Bound the degree of y''.
4. Reduce the equation Dy + f*y == g to a similar equation with f, g in
k[t].
5. Find the solutions in k[t] of bounded degree of the reduced equation.

See Chapter 6 of "Symbolic Integration I: Transcendental Functions" by
Manuel Bronstein.  See also the docstring of risch.py.
    )print_functiondivision)mul)oo)reduce)Dummy)PolygcdZZcancel)gcdex_diophantinefrac_in
derivationsplitfactorNonElementaryIntegralExceptionDecrementLevelc             C   s   | j r
tS |t||kr.| | d d S g }|}| |}d}x2|j rv|||f || }|d9 }| |}qFW d}td|}xDt|dkr| }	||	d  }
| |
}|j r||	d 7 }|
}qW |S )a8  
    Computes the order of a at p, with respect to t.

    For a, p in k[t], the order of a at p is defined as nu_p(a) = max({n
    in Z+ such that p**n|a}), where a != 0.  If a == 0, nu_p(a) = +oo.

    To compute the order at a rational function, a/b, use the fact that
    nu_p(a/b) == nu_p(a) - nu_p(b).
    r         )	is_zeror   r   as_polyZETremappendlenpop)aptZ
power_listZp1rZtracks_powernproductfinalZproductf r!   2lib/python3.7/site-packages/sympy/integrals/rde.pyorder_at'   s.    



r#   c             C   s   | j r
tS ||| | S )z
    Computes the order of a/d at oo (infinity), with respect to t.

    For f in k(t), the order or f at oo is defined as deg(d) - deg(a), where
    f == a/d.
    )r   r   degree)r   dr   r!   r!   r"   order_at_ooO   s    r&   Nc                sD  |p
t d}t| \}}t|| j}||}|t||t| j j j\}}	t| jt	    j
 j}
t|
|}
|
|std j|ffS dd |
 D }tt fdd|D td j}t	| }| ||  }|| }|j|dd\}}|||ffS )ag  
    Weak normalization.

    Given a derivation D on k[t] and f == a/d in k(t), return q in k[t]
    such that f - Dq/q is weakly normalized with respect to t.

    f in k(t) is said to be "weakly normalized" with respect to t if
    residue_p(f) is not a positive integer for any normal irreducible p
    in k[t] such that f is in R_p (Definition 6.1.1).  If f has an
    elementary integral, this is equivalent to no logarithm of
    integral(f) whose argument depends on t has a positive integer
    coefficient, where the arguments of the logarithms not in k(t) are
    in k[t].

    Returns (q, f - Dq/q)
    zr   c             S   s    g | ]}|t kr|d kr|qS )r   )r
   ).0ir!   r!   r"   
<listcomp>~   s    z#weak_normalizer.<locals>.<listcomp>c                s,   g | ]$}t t| jt   qS r!   )r	   r   r   r   )r(   r   )DEr   d1r!   r"   r*      s    T)include)r   r   r	   diffr   quor   r   r   r   Z	resultantZhasZ
real_rootsr   r   r   )r   r%   r+   r'   dndsgZ
d_sqf_parta1br   NqZdqZsnsdr!   )r+   r   r,   r"   weak_normalizer[   s(    
"


r8   c             C   s   t ||\}}t ||\}}||}	|||j|	|	|j}
||
 }||
 }||d rnt|| }|j|dd\}}||  |t|
| |  }|j|dd\}}|||f||f|
fS )a  
    Normal part of the denominator.

    Given a derivation D on k[t] and f, g in k(t) with f weakly
    normalized with respect to t, either raise NonElementaryIntegralException,
    in which case the equation Dy + f*y == g has no solution in k(t), or the
    quadruplet (a, b, c, h) such that a, h in k[t], b, c in k<t>, and for any
    solution y in k(t) of Dy + f*y == g, q = y*h in k<t> satisfies
    a*Dq + b*q == c.

    This constitutes step 1 in the outline given in the rde.py docstring.
    r   T)r-   )	r   r	   r.   r   r/   Zdivr   r   r   )fafdgagdr+   r0   r1   ZenZesr   hr   ccacdbabdr!   r!   r"   normal_denom   s    
&rC   autoc          	   C   s:  ddl m} |dkr|j}|dkr2t|j|j}nd|dkrRt|jd d |j}nD|dkr| |}	| |}
| |	|
td|jfS td	| t|||jt|||j }t|||jt|||j }t	d|t	d| }|s|dkr|j
t|j|j}t|z t|d |d | d |j\}}t||j\}}||||||}|d
k	r|\}}}|dkrt	||}W d
Q R X n&|dkr|j
t|jd d |j}t| tt|td |td | td |j\}}tt|td |td | td |j\}}t||j\}}td| ||r||td | ||  || |||}|d
k	r|\}}}|dkrt	||}W d
Q R X td| || }|| }||  }| | }||| t||j|  t||| |  }	|| | |}
|}||	|
|fS )a  
    Special part of the denominator.

    case is one of {'exp', 'tan', 'primitive'} for the hyperexponential,
    hypertangent, and primitive cases, respectively.  For the
    hyperexponential (resp. hypertangent) case, given a derivation D on
    k[t] and a in k[t], b, c, in k<t> with Dt/t in k (resp. Dt/(t**2 + 1) in
    k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp.
    gcd(a, t**2 + 1) == 1), return the quadruplet (A, B, C, 1/h) such that
    A, B, C, h in k[t] and for any solution q in k<t> of a*Dq + b*q == c,
    r = qh in k[t] satisfies A*Dr + B*r == C.

    For case == 'primitive', k<t> == k[t], so it returns (a, b, c, 1) in
    this case.

    This constitutes step 2 of the outline given in the rde.py docstring.
    r   )parametric_log_derivrD   exptanr   r   )	primitivebasez@case must be one of {'exp', 'tan', 'primitive', 'base'}, not %s.N)sympy.integrals.prderE   caser   r   to_fieldr/   
ValueErrorr#   minr%   r   r   evalZimZsqrtreZrecognize_log_derivativemaxr   )r   rA   rB   r?   r@   r+   rL   rE   r   BCZnbZncr   ZdcoeffalphaaalphadetaaetadAQmr'   betaabetadr5   ZpNZpnr=   r!   r!   r"   special_denom   s^    

,




<<(



2r^   Fc          	      s  ddl m}m}m} |dkr" j}|  j}	| j}
|rVt fdd|D }n| j}t|	 j
   | 	 j
   }|dkrtd|t|
|	d  }|
|	d kr|jrtd|||
 }n|dkr|
|	krtd||
 }ntd||	 d }t j j jd  \}} j}t X t| j\}}|
|	d kry |||||fg \\}}}W n tk
r   Y n&X t|dkrtd	t||d }n|
|	kr||| }|d
k	r|\}}|dkr| t| 	| ||	|  
  | | 
   }t| j\}}y |||||fg \\}}}W n tk
rd   Y n&X t|dkr|td	t||d }W d
Q R X n4|dkrJtd|t|
|	 }|	|
krt jt j j j jd  \}}t N t| j\}}||||| }|d
k	r>|\} }}| dkr>t||}W d
Q R X n|dkr j j} j
 }t|| }td|t|	| d |
 }|
|	| d kr|jrtd|||
 }ntd| |S )a$  
    Bound on polynomial solutions.

    Given a derivation D on k[t] and a, b, c in k[t] with a != 0, return
    n in ZZ such that deg(q) <= n for any solution q in k[t] of
    a*Dq + b*q == c, when parametric=False, or deg(q) <= n for any solution
    c1, ..., cm in Const(k) and q in k[t] of a*Dq + b*q == Sum(ci*gi, (i, 1, m))
    when parametric=True.

    For parametric=False, cQ is c, a Poly; for parametric=True, cQ is Q ==
    [q1, ..., qm], a list of Polys.

    This constitutes step 3 of the outline given in the rde.py docstring.
    r   )rE   limited_integrate!is_log_deriv_k_t_radical_in_fieldrD   c                s   g | ]}|  jqS r!   )r$   r   )r(   r)   )r+   r!   r"   r*     s    z bound_degree.<locals>.<listcomp>rI   r   rH   zLength of m should be 1NrF   )rG   Zother_nonlinearzScase must be one of {'exp', 'tan', 'primitive', 'other_nonlinear', 'base'}, not %s.)rK   rE   r_   r`   rL   r$   r   rR   r   r   LCas_expr
is_Integerr   r%   Tlevelr   r   r   rN   r   r/   r   )r   r4   cQr+   rL   
parametricrE   r_   r`   ZdaZdbZdcalphar   rW   rX   Zt1rU   rV   ZzaZzdr[   rY   Zaar'   betar\   r]   ZdeltaZlamr!   )r+   r"   bound_degree   s    



&

,





rj   c             C   s  t d|j}t d|j}t d|j}x|jr:||d||fS |dk dkrJt| |}||jsdt| |||||  } }}| |jdkr| | }| | }|||||fS t	|| |\}	}
|t
| |7 }|
t
|	| }|| |j8 }|||	 7 }|| 9 }q&W dS )aw  
    Rothstein's Special Polynomial Differential Equation algorithm.

    Given a derivation D on k[t], an integer n and a, b, c in k[t] with
    a != 0, either raise NonElementaryIntegralException, in which case the
    equation a*Dq + b*q == c has no solution of degree at most n in
    k[t], or return the tuple (B, C, m, alpha, beta) such that B, C,
    alpha, beta in k[t], m in ZZ, and any solution q in k[t] of degree
    at most n of a*Dq + b*q == c must be of the form
    q == alpha*h + beta, where h in k[t], deg(h) <= m, and Dh + B*h == C.

    This constitutes step 4 of the outline given in the rde.py docstring.
    r   r   TN)r   r   r   r   r	   r   r/   r$   rM   r   r   )r   r4   r>   r   r+   Zzerorh   ri   r2   r   r'   r!   r!   r"   spdep  s,    
"rk   c             C   s   t d|j}x|js||j| |j }d|  kr@|ksFn tt ||j | |j  |j|  |jdd}|| }|d }|t|| | |  }qW |S )a  
    Poly Risch Differential Equation - No cancellation: deg(b) large enough.

    Given a derivation D on k[t], n either an integer or +oo, and b, c
    in k[t] with b != 0 and either D == d/dt or
    deg(b) > max(0, deg(D) - 1), either raise NonElementaryIntegralException, in
    which case the equation Dq + b*q == c has no solution of degree at
    most n in k[t], or a solution q in k[t] of this equation with
    deg(q) < n.
    r   F)expandr   )r   r   r   r$   r   r   ra   r   )r4   r>   r   r+   r6   r[   r   r!   r!   r"   no_cancel_b_large  s    .rm   c             C   sX  t d|j}xD|jsR|dkr&d}n||j|j|j d }d|  krX|ks^n t|dkrt ||j ||j|j   |j|  |jdd}n| |j||jkrt| |jdkr|| |j|j	d  ||j|j	d  fS t ||j | |j  |jdd}|| }|d }|t
|| | |  }qW |S )al  
    Poly Risch Differential Equation - No cancellation: deg(b) small enough.

    Given a derivation D on k[t], n either an integer or +oo, and b, c
    in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or
    deg(D) >= 2, either raise NonElementaryIntegralException, in which case the
    equation Dq + b*q == c has no solution of degree at most n in k[t],
    or a solution q in k[t] of this equation with deg(q) <= n, or the
    tuple (h, b0, c0) such that h in k[t], b0, c0, in k, and for any
    solution q in k[t] of degree at most n of Dq + bq == c, y == q - h
    is a solution in k of Dy + b0*y == c0.
    r   r   F)rl   )r   r   r   r$   r%   r   r   ra   rd   re   r   )r4   r>   r   r+   r6   r[   r   r!   r!   r"   no_cancel_b_small  s*    0$rn   c       
      C   sx  t d|j}t| |j  |j|j  }|jrF|jrF|}nd}x&|jsrt	||
|j|j
|j d }d|  kr|ksn tt||j|j  | |j  }|jr|||fS |dkrt ||j | |j|  |jdd}	nF|
|j|j
|jd kr*tn ||j | |j  }	||	 }|d }|t|	| | |	  }qNW |S )ax  
    Poly Risch Differential Equation - No cancellation: deg(b) == deg(D) - 1

    Given a derivation D on k[t] with deg(D) >= 2, n either an integer
    or +oo, and b, c in k[t] with deg(b) == deg(D) - 1, either raise
    NonElementaryIntegralException, in which case the equation Dq + b*q == c has
    no solution of degree at most n in k[t], or a solution q in k[t] of
    this equation with deg(q) <= n, or the tuple (h, m, C) such that h
    in k[t], m in ZZ, and C in k[t], and for any solution q in k[t] of
    degree at most n of Dq + b*q == c, y == q - h is a solution in k[t]
    of degree at most m of Dy + b*y == C.
    r   rJ   r   F)rl   )r   r   r   r   ra   r%   rc   Zis_positiver   rR   r$   r   r   )
r4   r>   r   r+   r6   ZlcMr[   ur   r!   r!   r"   no_cancel_equal  s*    ($*

,  rq   c          	   C   s8  ddl m} t|B t| |j\}}||||}|dk	rR|\}}|dkrRtdW dQ R X |jrf|S |||jk rztt	d|j}	x|js2||j}
||
k rtt|. t|
 |j\}}t|||||\}}W dQ R X t	| |  |j|
  |jdd}|	|7 }	|
d }|| | t|| 8 }qW |	S )a  
    Poly Risch Differential Equation - Cancellation: Primitive case.

    Given a derivation D on k[t], n either an integer or +oo, b in k, and
    c in k[t] with Dt in k and b != 0, either raise
    NonElementaryIntegralException, in which case the equation Dq + b*q == c
    has no solution of degree at most n in k[t], or a solution q in k[t] of
    this equation with deg(q) <= n.
    r   )r`   Nr   z7is_deriv_in_field() is required to  solve this problem.F)rl   )rK   r`   r   r   r   NotImplementedErrorr   r$   r   r   ra   rischDErb   r   )r4   r>   r   r+   r`   rA   rB   rY   r'   r6   r[   a2aa2dsar7   stmr!   r!   r"   cancel_primitive  s2    



&rx   c          	   C   s  ddl m} |jt|j|j }t|X t||j\}}t| |j\}}	|||	|||}
|
dk	r|
\}}}|dkrt	dW dQ R X |j
r|S |||jk rttd|j}x|j
s||j}||k rt|  }t|b t||j\}}|| || t||j  }|| }t| |j\}}t|||||\}}W dQ R X t| |  |j|  |jdd}||7 }|d }|| | t|| 8 }qW |S )a  
    Poly Risch Differential Equation - Cancellation: Hyperexponential case.

    Given a derivation D on k[t], n either an integer or +oo, b in k, and
    c in k[t] with Dt/t in k and b != 0, either raise
    NonElementaryIntegralException, in which case the equation Dq + b*q == c
    has no solution of degree at most n in k[t], or a solution q in k[t] of
    this equation with deg(q) <= n.
    r   )rE   Nr   z6is_deriv_in_field() is required to solve this problem.F)rl   )rK   rE   r%   r/   r   r   rb   r   r   rr   r   r$   r   ra   rs   r   )r4   r>   r   r+   rE   ZetarW   rX   rA   rB   rY   r   r[   r'   r6   r3   Za1aZa1drt   ru   rv   r7   rw   r!   r!   r"   
cancel_exp>  s>    




&ry   c          	   C   s  ddl m}m} | jsd|jdksD| |jtd|j|jd krd|rV|| |||S t	| |||S | js| |j|j|jd k rT|jdks|j|jdkrT|r|| |||S t
| |||}t|tr|S |\}}	}
t|Z |	|j|
|j }	}
|	dkrtd|
dkr(tdt|	|
|||j}W dQ R X || S nL|j|jdkr| |j|j|jd kr|| |j  |j|j  kr| |j jstd	|rtd
t| |||}t|tr|S |\}}}t| |||}|| S n| jr.tdn\|jdkrV|rHtdt| |||S |jdkr~|rptdt| |||S tdt |rtdtddS )a  
    Solve a Polynomial Risch Differential Equation with degree bound n.

    This constitutes step 4 of the outline given in the rde.py docstring.

    For parametric=False, cQ is c, a Poly; for parametric=True, cQ is Q ==
    [q1, ..., qm], a list of Polys.
    r   )prde_no_cancel_b_largeprde_no_cancel_b_smallrI   r   r   Nzb0 should be a non-Null valuezc0 should be a non-Null valuezResult should be a numberz0prde_no_cancel_b_equal() is not yet implemented.zWRemaining cases for Poly (P)RDE are not yet implemented (is_deriv_in_field() required).rF   zIParametric RDE cancellation hyperexponential case is not yet implemented.rH   zBParametric RDE cancellation primitive case is not yet implemented.zBOther Poly (P)RDE cancellation cases are not yet implemented (%s).z2Remaining cases for Poly PRDE not yet implemented.z1Remaining cases for Poly RDE not yet implemented.)rK   rz   r{   r   rL   r$   r   rR   r%   rm   rn   
isinstancer   r   r   rN   solve_poly_rdera   Z	is_number	TypeErrorrr   rq   ry   rx   )r4   rf   r   r+   rg   rz   r{   Rr=   Zb0Zc0yr[   rT   r!   r!   r"   r}   x  sb    	$&




 4*


r}   c             C   s   t | ||\}\} }t| ||||\}\}}\}	}
}t||||	|
|\}}}}yt||||}W n tk
rx   t}Y nX t|||||\}}}}}|jr|}nt||||}|| | || fS )a  
    Solve a Risch Differential Equation: Dy + f*y == g.

    See the outline in the docstring of rde.py for more information
    about the procedure used.  Either raise NonElementaryIntegralException, in
    which case there is no solution y in the given differential field,
    or return y in k(t) satisfying Dy + f*y == g, or raise
    NotImplementedError, in which case, the algorithms necessary to
    solve the given Risch Differential Equation have not yet been
    implemented.
    )	r8   rC   r^   rj   rr   r   rk   r   r}   )r9   r:   r;   r<   r+   _r   rA   rB   r?   r@   ZhnrY   rS   rT   Zhsr   r[   rh   ri   r   r!   r!   r"   rs     s     
rs   )N)rD   )rD   F)F)&__doc__Z
__future__r   r   operatorr   Z
sympy.corer   Zsympy.core.compatibilityr   Zsympy.core.symbolr   Zsympy.polysr   r	   r
   r   Zsympy.integrals.rischr   r   r   r   r   r   r#   r&   r8   rC   r^   rj   rk   rm   rn   rq   rx   ry   r}   rs   r!   r!   r!   r"   <module>   s*    (
0"
R
q,,,/:
]