L i<nddlZddlmZmZmZmZddlmcm Z ddl m Z ddl mZd dZdZdddd d d Zy) N)array_namespacexp_ravelxp_copy xp_promote) _RichResult)specialc| t||n|}|j||\}}|j||fd}tj|dS)Nraxis)rbroadcast_arraysstackr logsumexp)xyxpxys e/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/scipy/stats/_continued_fraction.py _logaddexprsS"$*A "B  q! $DAq 1a&q !B   Ra ((c t|r t|s tdtj|s|f}|dg||dg|}}t ||g|}t ||g|dd|d^}}}|j |j} } d||ft|zD^}}}|in|}|jdd} |jdd} d} tj| | nd | | nd g}tj|jtj xs.tj|jtj}|stj|dknd }tjtj | }|j d k7}|s|s|s|r t| t#|}||k7s|dkr td t%|t&s td |||| | ||||| | |f S)Nz`a` and `b` must be callable.rT)force_floating broadcastrc32K|]}t|ywN)r).0args r z)_continued_fraction_iv..'sEsXc]EsepstinyzX`eps` and `tiny` must be (or represent the logarithm of) finite, positive, real scalars.F)z)`maxiter` must be a non-negative integer.z`log` must be boolean.)callable ValueErrornpiterablerrshapedtypetuplegetasarray issubdtypenumbercomplexfloatinganyallisfiniteint isinstancebool)abargs tolerancesmaxiterloga0b0rr&r'rrmessagetolsnot_real not_positive not_finite not_scalar maxiter_ints r_continued_fraction_ivrCs A;hqk899 ;;t wq[4[!A++B R '$ 'Br2&&TT"$&MBT88RXX5EEr2ht.DEMBT!)zJ .. %C >>&$ 'D1G ::cos1#/tQ8 9DMM$**bii88A==R-?-?@ ,/266$!)$ULVVBKK-..Jt#J<:!!g,K+1DEE c4 122 asD'3Bub HHrdF)r6r7r8r9ct|||}|\ }}}}} } d} dfd dfd fd} j|tjj} d\}}|d n|}|Ksj j n-tjj j }Qsj j d zn0d tjj j zr j nd }j| |k(| }t|}j||}j|j}td |||||||| }gd }fd}fd}fd}d}fd}tj|| | || |||||||S)a!Evaluate a generalized continued fraction numerically. `_continued_fraction` iteratively evaluates convergents of a continued fraction given coefficients returned by callables `a` and `b`. Iteration terminates when `maxiter` terms have been evaluated or a termination criterion controlled by `tolerances` is satisfied, and the final convergent is returned as the ``f`` attribute of the result object. This function works elementwise when `args` contains (broadcastable) arrays. Parameters ---------- a, b: callable Functions that provide the *numerator* and *denominator* coefficients of the continued fraction, respectively. The signature of each must be:: a(n: int, *argsj) -> ndarray where ``n`` is the coefficient number and ``argsj`` is a tuple, which may contain an arbitrary number of arrays of any shape. `a` and `b` must be elementwise functions: each scalar element ``a(n, *argsj)[i]`` must equal ``a(n, *[argj[i] for argj in argsj])`` for valid indices ``i``. `a` and `b` must not mutate the arrays in ``argsj``. The result shape is the broadcasted shape of ``a(0, *args)`` and ``b(0, *args)``. The dtype used throughout computation is the result dtype of these terms if it is a float, and the default float of the array library otherwise. The numerical value of ``a(0, *args)`` is ignored, and the value of the leading term ``b(0, *args)`` is the so-called "integer" part of the continued fraction (although it need not be integral). args : tuple of array_like, optional Additional positional *array* arguments to be passed to `a` and `b`. Arrays must be broadcastable with one another. If the coefficient callables require additional arguments that are not broadcastable with one another, wrap them with callables `a` and `b` such that `a` and `b` accept only ``n`` and broadcastable array arguments. tolerances : dictionary of floats, optional Tolerances and numerical thresholds used by the algorithm. Currently, valid keys of the dictionary are: - ``eps`` - the convergence threshold of Lentz' algorithm - ``tiny`` - not strictly a "tolerance", but a very small positive number used to avoid division by zero The default `eps` is the precision of the appropriate dtype, and the default `tiny` is the precision squared. [1]_ advises that ``eps`` is "as small as you like", but for most purposes, it should not be set smaller than the default because it may prevent convergence of the algorithm. [1]_ also advises that ``tiny`` should be less than typical values of ``eps * b(n)``, so the default is a good choice unless the :math:`b_n` are very small. See [1]_ for details. maxiter : int, default: 100 The maximum number of iterations of the algorithm to perform. log : bool, default: False If True, `a` and `b` return the (natural) logarithm of the terms, `tolerances` contains the logarithm of the tolerances, and the result object reports the logarithm of the convergent. Returns ------- res : _RichResult An object similar to an instance of `scipy.optimize.OptimizeResult` with the following attributes. The descriptions are written as though the values will be scalars; however, if `f` returns an array, the outputs will be arrays of the same shape. success : bool array ``True`` where the algorithm terminated successfully (status ``0``); ``False`` otherwise. status : int array An integer representing the exit status of the algorithm. - ``0`` : The algorithm converged to the specified tolerances. - ``-2`` : The maximum number of iterations was reached. - ``-3`` : A non-finite value was encountered. f : float array The convergent which satisfied a termination criterion. nit : int array The number of iterations of the algorithm that were performed. nfev : int array The number of terms that were evaluated. Notes ----- A generalized continued fraction is an expression of the form .. math:: b_0 + \frac{a_1}{b_1 + \frac{a_2}{b_2 + \frac{a_3}{b_3 + \cdots}}} Successive "convergents" approximate the infinitely recursive continued fraction with a finite number of terms :math:`a_n` and :math:`b_n`, which are provided by callables `a` and `b`, respectively. This implementation follows the modified Lentz algorithm ([1]_, [2]_) to evaluate successive convergents until a termination condition is satisfied. References ---------- .. [1] Press, William H., and Saul A. Teukolsky. "Evaluating continued fractions and computing exponential integrals." Computers in Physics 2.5 (1988): 88-89. .. [2] Lentz's algorithm. Wikipedia. https://en.wikipedia.org/wiki/Lentz%27s_algorithm .. [3] Continued fraction. Wikipedia. https://en.wikipedia.org/wiki/Continued_fraction .. [4] Generalized continued fraction. Wikipedia. https://en.wikipedia.org/wiki/Generalized_continued_fraction Examples -------- The "simple continued fraction" of :math:`\pi` is given in [3]_ as .. math:: 3 + \frac{1}{7 + \frac{1}{15 + \frac{1}{1 + \cdots}}} where the :math:`b_n` terms follow no obvious pattern: >>> b = [3, 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1] and the :math:`a_n` terms are all :math:`1`. In this case, all the terms have been precomputed, so we call `_continued_fraction` with simple callables which simply return the precomputed coefficients: >>> import numpy as np >>> from scipy.special._continued_fraction import _continued_fraction >>> res = _continued_fraction(a=lambda n: 1, b=lambda n: b[n], maxiter=len(b) - 1) >>> (res.f - np.pi) / np.pi np.float64(7.067899292141148e-15) A generalized continued fraction for :math:`\pi` is given by: .. math:: 3 + \frac{1^2}{6 + \frac{3^2}{6 + \frac{5^2}{6 + \cdots}}} We define the coefficient callables as: >>> def a(n): ... return (2*n - 1)**2 >>> >>> def b(n): ... if n == 0: ... return 3 ... else: ... return 6 Then the continued fraction can be evaluated as: >>> res = _continued_fraction(a, b) >>> res success: False status: -2 f: 3.1415924109719846 nit: 100 nfev: 101 Note that the requested tolerance was not reached within the (default) maximum number of iterations because it converges very slowly. An expression that converges more rapidly is expressed as the difference between two continued fractions. We will compute both of them in one vectorized call to `_continued_fraction`. >>> u, v = 5, 239 >>> >>> def a(n, a1, _): ... # The shape of the output must be the shape of the arguments ... shape = a1.shape ... if n == 0: ... return np.zeros(shape) ... elif n == 1: ... return a1 ... else: ... return np.full(shape, (n-1)**2) >>> >>> def b(n, _, uv): ... shape = uv.shape ... if n == 0: ... return np.zeros(shape) ... return np.full(shape, (2*n - 1)*uv) >>> >>> res = _continued_fraction(a, b, args=([16, 4], [u, v])) >>> res success: [ True True] status: [0 0] f: [ 3.158e+00 1.674e-02] nit: [10 4] nfev: [11 5] Note that the second term converged in fewer than half the number of iterations as the first. The approximation of :math:`\pi` is the difference between the two: >>> pi = res.f[0] - res.f[1] >>> (pi - np.pi) / np.pi np.float64(2.8271597168564594e-16) If it is more efficient to compute the :math:`a_n` and :math:`b_n` terms together, consider instantiating a class with a method that computes both terms and stores the results in an attribute. Separate methods of the class retrieve the coefficients, and these methods are passed to `_continued_fraction` as arguments `a` and `b`. Similarly,if the coefficients can be computed recursively in terms of previous coefficients, use a class to maintain state between callable evaluations. N)r4cbtjt|d}||g|SNrr1realr)nr4r6rs rr4z_continued_fraction..a-  $Q' ({T{r)r5cbtjt|d}||g|SrHrI)rKr5r6rs rr5z_continued_fraction..b#rLrcJj|g||g|fdS)Nr )r )rKr6r4r5rs rfuncz!_continued_fraction..func's+xx1takDk2x<.pre_func_evalEs/BJJtvvz2E:vv rc|d|d}} sdn j } s|||jzznt|||jz } |||k(< sd|z n| } s|||jz znt|||jz } |||k(< s||zn||z|_ s|j |jzn|j |jz|_||c|_|_y)N).r).r rrr )infrTrrSrUrR) rKabr\anbnzero denominatorDnCnr9rrs rpost_func_evalz+_continued_fraction..post_func_evalIsFRZBq"&&14rBtyyL(&r2 >bA +/ K4'(#&a m< *-b2 >!b"tyy.R8 2:%(R"Wr' .1477TYY&$))+  "2 49rcj|jj}r)j|jjdznd}sj |jdz n&j t|j|}||jk}tj|j|<d||<sj|jn6j|j|jj k(z}tj|j|<d||<|S)NrQy?r r_T) zeros_likerUr3 full_likepiabsrJrreim _ECONVERGEDrXr0rRr` _EVALUEERR)r\stoppijresidualir9rs rcheck_terminationz._continued_fraction..check_terminationcs}}TYYbgg}647bll499beeBh/D14BFF499q=)DIIsr!BC  txx  AQ+.bkk$''" "KK(DGGw,>?@  AQ rcyrrD)r\s rpost_termination_checkz3_continued_fraction..post_termination_checkws rc~j|d|d<|djdk(r|ddn|d|d<|S)NrYrQrrD)r*ndim)resr&r'rs rcustomize_resultz-_continued_fraction..customize_resultzsH::c#he:4C#&s8==A#53s8B<3s8C rr_)rCrkrn _EINPROGRESSint32finforr$r9r`whererr_loop)r4r5r6r7r8r9rzrr:r;r&callbackrPrXrVrWrdrRrSrTrUr\res_work_pairsr]rhrurwr{r'rrs`` ` @@@r_continued_fractionrDs` !AtZ# FCDGAAq$T7CRrH=\\"c..bhh\ ?FIC_c'G {),bhhuo!!"&&%9L9L2M |-0rxx""A%arxx?R?R8S6SBFF7qD "*dB 'B 2;D <<D !D <<BFF #D r4dTT& :D8N&4(  99T8UGT4"N4E+-=~ rr)numpyr$scipy._lib._array_apirrrr(scipy._lib._elementwise_iterative_method_lib_elementwise_iterative_methodrnscipy._lib._utilrscipyrrrCrrDrrrs=76())IX')T3Er