
    [h&                         S SK J r   SSKJr   " S S\5      rS rS
S jr\\l        \S	:X  a  S SKr\R                  " 5         gg)    )bisect   )xrangec                       \ rS rSrSrg)
ODEMethods    N)__name__
__module____qualname____firstlineno____static_attributes__r	       L/var/www/auris/envauris/lib/python3.13/site-packages/mpmath/calculus/odes.pyr   r      s    r   r   c                    U R                  SU* 5      =pg[        U5      nU/n	U/n
UnUnU R                  n USU-   -  U l        [        U5       H_  nU" X5      n[	        [        U5      5       Vs/ s H  oU   XoU   -  -   PM     nnX-  nU	R                  U5        U
R                  U5        Ma     [        U5       Vs/ s H  n/ PM     nn[        US-   5       H  nS/U-  nSUS-  -  nSn[        US-   5       H>  n[        U5       H  nUU==   UX   U   -  -  ss'   M     UUU-
  S-   -  U* -  nUS-  nM@     UU* -  U R                  U5      -  n[        U5       H%  nUU   U-  UU'   UU   R                  UU   5        M'     M     Xl        U R                  nU H:  nUS   (       d  M  [        UU R                  U[        US   5      -  U5      5      nM<     US-  nUUU-   4$ s  snf s  snf ! Xl        f = f)N   r   r   )ldexplenprecranger   appendfaconeminnthrootabs)ctxderivsx0y0tol_precnhtoldimxsysxyorigifxydserjsbkscaleradiustss                            r   
ode_taylorr7      s   iiH9%%A
b'C
B
B
A
A88D1: qA,C(.s1v711aAhA7FAIIaLIIaL  !:&:ar:&qsACAQAA1Q3ZsAaDAaL(D $!A#a%[qb)Q	  
 Gcggaj(E3Zte|!Aad#     WWFb66SRV_a!@AF  aKF6	>9 8
 ' s*   9G6 0G,9G6 ?G1CG6 ,
G6 6G>Nc           	        ^ ^^^^^^^^^^^^ U(       a   [        T R                  US5      * 5      S-   mOT R                  S-   mT=(       d    S[        ST R                  -  S-  5      -   mT R                  S-   m [	        U5        Sm[        T TTUTT5      u  pTU	/mUTU	4/mU 4S	 jmUU UUUUUUU4	S
 jmU UUUU4S jn
U
$ ! [
         a    TmU4S jmU/nSm NUf = f)a  
Returns a function `y(x) = [y_0(x), y_1(x), \ldots, y_n(x)]`
that is a numerical solution of the `n+1`-dimensional first-order
ordinary differential equation (ODE) system

.. math ::

    y_0'(x) = F_0(x, [y_0(x), y_1(x), \ldots, y_n(x)])

    y_1'(x) = F_1(x, [y_0(x), y_1(x), \ldots, y_n(x)])

    \vdots

    y_n'(x) = F_n(x, [y_0(x), y_1(x), \ldots, y_n(x)])

The derivatives are specified by the vector-valued function
*F* that evaluates
`[y_0', \ldots, y_n'] = F(x, [y_0, \ldots, y_n])`.
The initial point `x_0` is specified by the scalar argument *x0*,
and the initial value `y(x_0) =  [y_0(x_0), \ldots, y_n(x_0)]` is
specified by the vector argument *y0*.

For convenience, if the system is one-dimensional, you may optionally
provide just a scalar value for *y0*. In this case, *F* should accept
a scalar *y* argument and return a scalar. The solution function
*y* will return scalar values instead of length-1 vectors.

Evaluation of the solution function `y(x)` is permitted
for any `x \ge x_0`.

A high-order ODE can be solved by transforming it into first-order
vector form. This transformation is described in standard texts
on ODEs. Examples will also be given below.

**Options, speed and accuracy**

By default, :func:`~mpmath.odefun` uses a high-order Taylor series
method. For reasonably well-behaved problems, the solution will
be fully accurate to within the working precision. Note that
*F* must be possible to evaluate to very high precision
for the generation of Taylor series to work.

To get a faster but less accurate solution, you can set a large
value for *tol* (which defaults roughly to *eps*). If you just
want to plot the solution or perform a basic simulation,
*tol = 0.01* is likely sufficient.

The *degree* argument controls the degree of the solver (with
*method='taylor'*, this is the degree of the Taylor series
expansion). A higher degree means that a longer step can be taken
before a new local solution must be generated from *F*,
meaning that fewer steps are required to get from `x_0` to a given
`x_1`. On the other hand, a higher degree also means that each
local solution becomes more expensive (i.e., more evaluations of
*F* are required per step, and at higher precision).

The optimal setting therefore involves a tradeoff. Generally,
decreasing the *degree* for Taylor series is likely to give faster
solution at low precision, while increasing is likely to be better
at higher precision.

The function
object returned by :func:`~mpmath.odefun` caches the solutions at all step
points and uses polynomial interpolation between step points.
Therefore, once `y(x_1)` has been evaluated for some `x_1`,
`y(x)` can be evaluated very quickly for any `x_0 \le x \le x_1`.
and continuing the evaluation up to `x_2 > x_1` is also fast.

**Examples of first-order ODEs**

We will solve the standard test problem `y'(x) = y(x), y(0) = 1`
which has explicit solution `y(x) = \exp(x)`::

    >>> from mpmath import *
    >>> mp.dps = 15; mp.pretty = True
    >>> f = odefun(lambda x, y: y, 0, 1)
    >>> for x in [0, 1, 2.5]:
    ...     print((f(x), exp(x)))
    ...
    (1.0, 1.0)
    (2.71828182845905, 2.71828182845905)
    (12.1824939607035, 12.1824939607035)

The solution with high precision::

    >>> mp.dps = 50
    >>> f = odefun(lambda x, y: y, 0, 1)
    >>> f(1)
    2.7182818284590452353602874713526624977572470937
    >>> exp(1)
    2.7182818284590452353602874713526624977572470937

Using the more general vectorized form, the test problem
can be input as (note that *f* returns a 1-element vector)::

    >>> mp.dps = 15
    >>> f = odefun(lambda x, y: [y[0]], 0, [1])
    >>> f(1)
    [2.71828182845905]

:func:`~mpmath.odefun` can solve nonlinear ODEs, which are generally
impossible (and at best difficult) to solve analytically. As
an example of a nonlinear ODE, we will solve `y'(x) = x \sin(y(x))`
for `y(0) = \pi/2`. An exact solution happens to be known
for this problem, and is given by
`y(x) = 2 \tan^{-1}\left(\exp\left(x^2/2\right)\right)`::

    >>> f = odefun(lambda x, y: x*sin(y), 0, pi/2)
    >>> for x in [2, 5, 10]:
    ...     print((f(x), 2*atan(exp(mpf(x)**2/2))))
    ...
    (2.87255666284091, 2.87255666284091)
    (3.14158520028345, 3.14158520028345)
    (3.14159265358979, 3.14159265358979)

If `F` is independent of `y`, an ODE can be solved using direct
integration. We can therefore obtain a reference solution with
:func:`~mpmath.quad`::

    >>> f = lambda x: (1+x**2)/(1+x**3)
    >>> g = odefun(lambda x, y: f(x), pi, 0)
    >>> g(2*pi)
    0.72128263801696
    >>> quad(f, [pi, 2*pi])
    0.72128263801696

**Examples of second-order ODEs**

We will solve the harmonic oscillator equation `y''(x) + y(x) = 0`.
To do this, we introduce the helper functions `y_0 = y, y_1 = y_0'`
whereby the original equation can be written as `y_1' + y_0' = 0`. Put
together, we get the first-order, two-dimensional vector ODE

.. math ::

    \begin{cases}
    y_0' = y_1 \\
    y_1' = -y_0
    \end{cases}

To get a well-defined IVP, we need two initial values. With
`y(0) = y_0(0) = 1` and `-y'(0) = y_1(0) = 0`, the problem will of
course be solved by `y(x) = y_0(x) = \cos(x)` and
`-y'(x) = y_1(x) = \sin(x)`. We check this::

    >>> f = odefun(lambda x, y: [-y[1], y[0]], 0, [1, 0])
    >>> for x in [0, 1, 2.5, 10]:
    ...     nprint(f(x), 15)
    ...     nprint([cos(x), sin(x)], 15)
    ...     print("---")
    ...
    [1.0, 0.0]
    [1.0, 0.0]
    ---
    [0.54030230586814, 0.841470984807897]
    [0.54030230586814, 0.841470984807897]
    ---
    [-0.801143615546934, 0.598472144103957]
    [-0.801143615546934, 0.598472144103957]
    ---
    [-0.839071529076452, -0.54402111088937]
    [-0.839071529076452, -0.54402111088937]
    ---

Note that we get both the sine and the cosine solutions
simultaneously.

**TODO**

* Better automatic choice of degree and step size
* Make determination of Taylor series convergence radius
  more robust
* Allow solution for `x < x_0`
* Allow solution for complex `x`
* Test for difficult (ill-conditioned) problems
* Implement Runge-Kutta and other algorithms

r   
      g       @(   Tc                    > T" XS   5      /$ Nr   r	   )r)   r*   F_s     r   <lambda>odefun.<locals>.<lambda>   s    "Q!+r   Fc           	      `   > U  Vs/ s H  nTR                  US S S2   U5      PM     sn$ s  snf )Nr   )polyval)r/   ar1   r   s      r   mpolyvalodefun.<locals>.mpolyval   s.    145AAddGQ'555s   "+c                 <  >	 U T:  a  [         e[        T
U 5      nU[        T
5      :  a  TUS-
     $  TS   u  p#nT(       a  [        SX44-  5        T	" X$U-
  5      nUn[	        TTXETT5      u  p$T
R                  U5        TR                  X#U45        X::  a  TS   $ Ml  )Nr   r   z$Computing Taylor series for [%f, %f])
ValueErrorr   r   printr7   r   )r)   r#   r/   xaxbr*   Fr   degreerD   series_boundariesseries_datar"   verboser    s         r   
get_seriesodefun.<locals>.get_series   s    r6$a(s$%%qs##%b/KCR<xGHe$AB a&AGC$$R(}-w"2& r   c                    > TR                  U 5      n TR                  n TTl        T" U 5      u  p#nT	" X U-
  5      nUTl        T
(       a  U Vs/ s H  of7PM     sn$ US   7$ ! UTl        f = fs  snf r=   )convertr   )r)   r+   r/   rI   rJ   r*   ykr   rP   rD   return_vectorworkprecs          r   interpolantodefun.<locals>.interpolant  sw    KKNxx	CH$Q-KCRd#ACH"#$!BC!$$aD5L	 CH$s   A$ A0$	A-)intlogr   dpsr   	TypeErrorr7   )r   rK   r    r!   r%   rL   methodrO   r/   rJ   rW   r>   rP   rD   rU   rM   rN   r"   rV   s   ```  ` `   @@@@@@@@r   odefunr^   3   s    f Q'(+88B;.C#''	"--Fxx"}HB aR6:GCRR=/K6' '$  W  &T	s   ;C CC__main__)NNtaylorF)
r   libmp.backendr   objectr   r7   r^   r
   doctesttestmodr	   r   r   <module>re      sH     "	 	*XgR 
 zOO r   