
    \h?                         S SK JrJr  S SKJrJrJr  S SKJrJ	r	  S SK
Jr  S SKJr  S SKJr  S SKJr  S SKJr  S S	KJrJrJr  S S
KJr  S SKJr  S SKJr  S SKJrJ r   S SK!J"r"J#r#  S r$SS jr%SS jr&g)    )SPow)
DerivativeAppliedUndefdiff)EqualityEq)Dummy)sympify)BooleanAtom)exp)Order)simplifyposify
besselsimp)trigsimp)
sqrtdenest)solve)_preprocess	ode_order)iterableis_sequencec                     X0nU R                  [        5       HQ  nUR                  U:X  a  UR                  " UR                  6 X4'   M0  UR                  X05      R                  SS9X4'   MS     U R                  U5      $ )a%  
When replacing the func with something else, we usually want the
derivative evaluated, so this function helps in making that happen.

Examples
========

>>> from sympy import Derivative, symbols, Function
>>> from sympy.solvers.ode.subscheck import sub_func_doit
>>> x, z = symbols('x, z')
>>> y = Function('y')

>>> sub_func_doit(3*Derivative(y(x), x) - 1, y(x), x)
2

>>> sub_func_doit(x*Derivative(y(x), x) - y(x)**2 + y(x), y(x),
... 1/(x*(z + 1/x)))
x*(-1/(x**2*(z + 1/x)) + 1/(x**3*(z + 1/x)**2)) + 1/(x*(z + 1/x))
...- 1/(x**2*(z + 1/x)**2)
F)deep)atomsr   exprr   variable_countxreplacedoit)eqfuncnewrepsds        S/var/www/auris/envauris/lib/python3.13/site-packages/sympy/solvers/ode/subscheck.pysub_func_doitr&      sp    * +DXXj!66T>hh 0 01DGjj$-222>DG	 "
 ;;t    Nc                    [        U 5      (       a
  [        XUS9$ [        U [        5      (       d  [	        U S5      n Uc   [        U R                  5      u  pR[        U[        5      (       a  [        UR                  5      S:w  a  [        SU-  5      e[        U[        5      (       a*  [!        U5      " U Vs/ s H  n[#        XX4S9PM     sn5      $ [        U[        5      (       d  [	        X!5      nOUR$                  U:X  a  UR&                  nUS:X  a  [)        X5      nUR                  U:H  =(       a     UR$                  R+                  U5      (       + n	U(       aS  U	(       dL  [-        X5      n
U
(       a:  U
 Vs/ s H  n[	        X+5      PM     nn[        U
5      S:X  a  US   n[#        XUSS9$ UR                  S   nUR+                  [.        5      (       Ga  UR                  U:X  d   eUR$                  R1                  5       nUR$                  R3                  5       nUR4                  n[        U[6        5      (       d   eUR8                  nU[/        UU-  5      :X  d   eU R                  U R$                  -
  R;                  X/5      R=                  5       R?                  5       n[/        UUU-
  -  5      nUU-   nUR1                  5       U:X  d   eUR3                  5       nUS:H  U4$ S	nSnU(       Ga  US:X  a  U R                  U R$                  -
  nUR                  U:X  a"  [A        UX!R$                  5      n[C        U5      nOUS-  nM`  [E        URG                  [8        5      5      nU(       a  UR?                  S	S
9nOSnUS-  nGOUS:X  ar  [E        [I        [K        UR                  X5      [K        UR$                  X5      -
  5      [I        U R                  5      -
  [I        U R$                  5      -   5      nUS-  nGO~US:X  Gav  UR                  U:X  a/  UR$                  R+                  U5      (       d  SUR$                  0nOAUR$                  U:X  a/  UR                  R+                  U5      (       d  SUR                  0nO0 nUR                  UR$                  -
  n[M        SUS-   5       Hh  nUS:X  aE  URK                  U5      n [-        UURK                  X5      5      nU(       d  [N        e US   UU'   MN  UUS-
     RK                  U5      UU'   Mj     US:  a  GM:  U R                  U R$                  n
n[M        USS5       H  nUS:X  a  SU;  a    O[A        UURK                  X5      UU   5      n[A        XRK                  X5      UU   5      n
[	        UU
5      n[E        U5      n[        U[P        [R        45      (       a  U(       a  [T        RV                  =nn
M  M  UR                  nUR$                  n
M     [I        UU
-
  RY                  5       S   5      n[[        S5      nUR;                  UU5      n[]        U5      u  nn[E        U5      R_                  U5      R_                  UU05      nUS-  nOO
U(       a  GM  U(       d  S	U4$ US	L a)  [O        S[a        U5      -   S-   [a        U 5      -   S-   5      eSU4$ ! [         a    [        U[        5      (       a  UOU/ Vs/ s H  ofR                  [        5      PM     Os  snf nn[        5       R                  " U6 n[        U5      S:w  a  [        S5      eUR                  5       n GNf = fs  snf s  snf ! [N         a    US-  n   GM\  f = f)a
  
Substitutes ``sol`` into ``ode`` and checks that the result is ``0``.

This works when ``func`` is one function, like `f(x)` or a list of
functions like `[f(x), g(x)]` when `ode` is a system of ODEs.  ``sol`` can
be a single solution or a list of solutions.  Each solution may be an
:py:class:`~sympy.core.relational.Equality` that the solution satisfies,
e.g. ``Eq(f(x), C1), Eq(f(x) + C1, 0)``; or simply an
:py:class:`~sympy.core.expr.Expr`, e.g. ``f(x) - C1``. In most cases it
will not be necessary to explicitly identify the function, but if the
function cannot be inferred from the original equation it can be supplied
through the ``func`` argument.

If a sequence of solutions is passed, the same sort of container will be
used to return the result for each solution.

It tries the following methods, in order, until it finds zero equivalence:

1. Substitute the solution for `f` in the original equation.  This only
   works if ``ode`` is solved for `f`.  It will attempt to solve it first
   unless ``solve_for_func == False``.
2. Take `n` derivatives of the solution, where `n` is the order of
   ``ode``, and check to see if that is equal to the solution.  This only
   works on exact ODEs.
3. Take the 1st, 2nd, ..., `n`\th derivatives of the solution, each time
   solving for the derivative of `f` of that order (this will always be
   possible because `f` is a linear operator). Then back substitute each
   derivative into ``ode`` in reverse order.

This function returns a tuple.  The first item in the tuple is ``True`` if
the substitution results in ``0``, and ``False`` otherwise. The second
item in the tuple is what the substitution results in.  It should always
be ``0`` if the first item is ``True``. Sometimes this function will
return ``False`` even when an expression is identically equal to ``0``.
This happens when :py:meth:`~sympy.simplify.simplify.simplify` does not
reduce the expression to ``0``.  If an expression returned by this
function vanishes identically, then ``sol`` really is a solution to
the ``ode``.

If this function seems to hang, it is probably because of a hard
simplification.

To use this function to test, test the first item of the tuple.

Examples
========

>>> from sympy import (Eq, Function, checkodesol, symbols,
...     Derivative, exp)
>>> x, C1, C2 = symbols('x,C1,C2')
>>> f, g = symbols('f g', cls=Function)
>>> checkodesol(f(x).diff(x), Eq(f(x), C1))
(True, 0)
>>> assert checkodesol(f(x).diff(x), C1)[0]
>>> assert not checkodesol(f(x).diff(x), x)[0]
>>> checkodesol(f(x).diff(x, 2), x**2)
(False, 2)

>>> eqs = [Eq(Derivative(f(x), x), f(x)), Eq(Derivative(g(x), x), g(x))]
>>> sol = [Eq(f(x), C1*exp(x)), Eq(g(x), C2*exp(x))]
>>> checkodesol(eqs, sol)
(True, [0, 0])

)r!   r      z0must pass func arg to checkodesol for this case./func must be a function of one variable, not %s)ordersolve_for_funcautoFTforce   r!   zUnable to test if z is a solution to .)1r   checksysodesol
isinstancer   r	   r   lhs
ValueErrorr   setr   r   unionlenpopargstypecheckodesolrhsreversedr   hasr   r   getOremoveOr   r   r   subsr   expandr&   r   r   rewriter   r   rangeNotImplementedErrorboolr   r   Zeroas_numer_denomr
   r   r   str) odesolr!   r+   r,   _sfuncsisolvedr>   teqsxOtermsolrhsOexprsorderodesubsneworderresidualtestnumode_diffssdiffsolsdssdfr5   ode_or_boolnum_funcr#   s                                    r%   r=   r=   0   s   B }}cT22c8$$aj|		!#''*GA dL))S^q-@=DF 	F3Cycfgcf^_+cEYcfghhc8$$m	Dll#$WW_6SWW[[%6!6FfC(+,12d;C,3x1}!fsu$& & 			!A wwu~~ww$"

%%%%%ai((((77377?((6;;=DDFVe^,-H$||~)))??$Ax((AG
a< ww(Hww$!(D'':qM1!))C.)B IIDI)qLG\ cggq043JJK!"$,SWW$567A qLG\ ww$sww{{4'8'8sww<DT):):sww<''CGG#C1eai(
 6!B-#B		!8""55  # '*!f #+1q5/"6"6q"9HQK% )* { 77CGGSub"-AAv!8"3 'TYYq_hqkJC'YYq_hqkJC"$S#,K"*;"7K!+k/BCC&().C# ' *oo)oo .$ c	99;A>? fhhtU+"3K	TSM**40995$-H1Q !T ay	
d!"6S"A #!#&s8#,.1#2 3 	3 qzO  	"3,,3%7:7 01WW\*7:E :EKK'E5zQ FH H99;D	 h -t / 1s=    [	 7]:]"(]'	&]/\A	]]']<;]<c           	         S nU" U 5      n [        [        U 5      5       H;  n[        X   [        5      (       d  M  X   R                  X   R
                  -
  X'   M=     Uc  / nU  Hc  nUR                  [        5      n[        5       R                  " U Vs/ s H  oR                  [        5      PM     sn6 nUR                  U5        Me     [        [        U5      5      n[        S W 5       5      (       d7  [        U Vs1 s H  o"R                  iM     sn5      S:w  a  [        SW-  5      eU H0  n	[        U	R                  [        5      5      S:w  d  M'  [        S5      e   [        U5      [        U V	s1 s H  oR                  iM     sn	5      :w  a  [        S5      e0 n
U H  n	[        U	R                  [        5      5      S   nU	R
                  U:X  a  U	R                   n	U	R                  U:H  =(       a     U	R
                  R#                  U5      (       + nU(       d  [%        X5      nU(       d  [&        eOU	R
                  nXU'   M     / nU  Hm  nU H  n[)        XbX   5      nM     [+        U5      nUS:w  a/  UR-                  SS	9nUS:w  a  [/        U5      R+                  5       nOSnUR1                  U5        Mo     [        [        U5      5      S:X  a  [        [        U5      5      S   S:X  a  SU4$ S
U4$ s  snf s  snf s  sn	f )a	  
Substitutes corresponding ``sols`` for each functions into each ``eqs`` and
checks that the result of substitutions for each equation is ``0``. The
equations and solutions passed can be any iterable.

This only works when each ``sols`` have one function only, like `x(t)` or `y(t)`.
For each function, ``sols`` can have a single solution or a list of solutions.
In most cases it will not be necessary to explicitly identify the function,
but if the function cannot be inferred from the original equation it
can be supplied through the ``func`` argument.

When a sequence of equations is passed, the same sequence is used to return
the result for each equation with each function substituted with corresponding
solutions.

It tries the following method to find zero equivalence for each equation:

Substitute the solutions for functions, like `x(t)` and `y(t)` into the
original equations containing those functions.
This function returns a tuple.  The first item in the tuple is ``True`` if
the substitution results for each equation is ``0``, and ``False`` otherwise.
The second item in the tuple is what the substitution results in.  Each element
of the ``list`` should always be ``0`` corresponding to each equation if the
first item is ``True``. Note that sometimes this function may return ``False``,
but with an expression that is identically equal to ``0``, instead of returning
``True``.  This is because :py:meth:`~sympy.simplify.simplify.simplify` cannot
reduce the expression to ``0``.  If an expression returned by each function
vanishes identically, then ``sols`` really is a solution to ``eqs``.

If this function seems to hang, it is probably because of a difficult simplification.

Examples
========

>>> from sympy import Eq, diff, symbols, sin, cos, exp, sqrt, S, Function
>>> from sympy.solvers.ode.subscheck import checksysodesol
>>> C1, C2 = symbols('C1:3')
>>> t = symbols('t')
>>> x, y = symbols('x, y', cls=Function)
>>> eq = (Eq(diff(x(t),t), x(t) + y(t) + 17), Eq(diff(y(t),t), -2*x(t) + y(t) + 12))
>>> sol = [Eq(x(t), (C1*sin(sqrt(2)*t) + C2*cos(sqrt(2)*t))*exp(t) - S(5)/3),
... Eq(y(t), (sqrt(2)*C1*cos(sqrt(2)*t) - sqrt(2)*C2*sin(sqrt(2)*t))*exp(t) - S(46)/3)]
>>> checksysodesol(eq, sol)
(True, [0, 0])
>>> eq = (Eq(diff(x(t),t),x(t)*y(t)**4), Eq(diff(y(t),t),y(t)**3))
>>> sol = [Eq(x(t), C1*exp(-1/(4*(C2 + t)))), Eq(y(t), -sqrt(2)*sqrt(-1/(C2 + t))/2),
... Eq(x(t), C1*exp(-1/(4*(C2 + t)))), Eq(y(t), sqrt(2)*sqrt(-1/(C2 + t))/2)]
>>> checksysodesol(eq, sol)
(True, [0, 0])

c                 j    [        [        [        [        U 5      (       a
  U 5      5      $ U /5      5      $ N)listmapr   r   )r    s    r%   _sympify checksysodesol.<locals>._sympifyW  s)    Cx||>??">??r'   c              3      #    U  H4  n[        U[        5      =(       a    [        UR                  5      S :H  v   M6     g7f)r)   N)r4   r   r9   r;   ).0r!   s     r%   	<genexpr>!checksysodesol.<locals>.<genexpr>d  s.     XRW$z$-E#dii.A2EERWs   <>r)   r*   z'solutions should have one function onlyzCnumber of solutions provided does not match the number of equationsr   Tr.   F)rF   r9   r4   r   r5   r>   r   r   r7   r8   r   extendri   allr;   r6   r?   r@   r   rG   r&   r   rD   r   append)rT   solsr!   rk   rQ   rP   r    derivsr$   rM   dictsolrR   r>   checkeqr_   s                  r%   r3   r3   #  s   h@
3-C3s8_cfh''VZZ#&**,CF  |BXXj)F5;; G1!6 GHDLL  SZ XRWXXX5)54YY5)*A-JTQRRsyy&'1,FGG  5zST2Tc''T233^__GCIIl+,Q/77d?,,CD:T):%:"C))  ''C  GDr7B b\7&BQw^,,.Br  3w<A$s7|"4Q"71"<gwO !H *
 3s   L 
L8L

)Nr-   Trh   )'
sympy.corer   r   sympy.core.functionr   r   r   sympy.core.relationalr   r	   sympy.core.symbolr
   sympy.core.sympifyr   sympy.logic.boolalgr   sympy.functionsr   sympy.seriesr   sympy.simplify.simplifyr   r   r   sympy.simplify.trigsimpr   sympy.simplify.sqrtdenestr   sympy.solversr   sympy.solvers.deutilsr   r   sympy.utilities.iterablesr   r   r&   r=   r3    r'   r%   <module>r      sG     @ @ . # & +   @ @ , 0  8 ;<pfe r'   