stable-diffusion-implementation
/
main
/myenv
/lib
/python3.10
/site-packages
/mpmath
/calculus
/differentiation.py
| from ..libmp.backend import xrange | |
| from .calculus import defun | |
| try: | |
| iteritems = dict.iteritems | |
| except AttributeError: | |
| iteritems = dict.items | |
| #----------------------------------------------------------------------------# | |
| # Differentiation # | |
| #----------------------------------------------------------------------------# | |
| def difference(ctx, s, n): | |
| r""" | |
| Given a sequence `(s_k)` containing at least `n+1` items, returns the | |
| `n`-th forward difference, | |
| .. math :: | |
| \Delta^n = \sum_{k=0}^{\infty} (-1)^{k+n} {n \choose k} s_k. | |
| """ | |
| n = int(n) | |
| d = ctx.zero | |
| b = (-1) ** (n & 1) | |
| for k in xrange(n+1): | |
| d += b * s[k] | |
| b = (b * (k-n)) // (k+1) | |
| return d | |
| def hsteps(ctx, f, x, n, prec, **options): | |
| singular = options.get('singular') | |
| addprec = options.get('addprec', 10) | |
| direction = options.get('direction', 0) | |
| workprec = (prec+2*addprec) * (n+1) | |
| orig = ctx.prec | |
| try: | |
| ctx.prec = workprec | |
| h = options.get('h') | |
| if h is None: | |
| if options.get('relative'): | |
| hextramag = int(ctx.mag(x)) | |
| else: | |
| hextramag = 0 | |
| h = ctx.ldexp(1, -prec-addprec-hextramag) | |
| else: | |
| h = ctx.convert(h) | |
| # Directed: steps x, x+h, ... x+n*h | |
| direction = options.get('direction', 0) | |
| if direction: | |
| h *= ctx.sign(direction) | |
| steps = xrange(n+1) | |
| norm = h | |
| # Central: steps x-n*h, x-(n-2)*h ..., x, ..., x+(n-2)*h, x+n*h | |
| else: | |
| steps = xrange(-n, n+1, 2) | |
| norm = (2*h) | |
| # Perturb | |
| if singular: | |
| x += 0.5*h | |
| values = [f(x+k*h) for k in steps] | |
| return values, norm, workprec | |
| finally: | |
| ctx.prec = orig | |
| def diff(ctx, f, x, n=1, **options): | |
| r""" | |
| Numerically computes the derivative of `f`, `f'(x)`, or generally for | |
| an integer `n \ge 0`, the `n`-th derivative `f^{(n)}(x)`. | |
| A few basic examples are:: | |
| >>> from mpmath import * | |
| >>> mp.dps = 15; mp.pretty = True | |
| >>> diff(lambda x: x**2 + x, 1.0) | |
| 3.0 | |
| >>> diff(lambda x: x**2 + x, 1.0, 2) | |
| 2.0 | |
| >>> diff(lambda x: x**2 + x, 1.0, 3) | |
| 0.0 | |
| >>> nprint([diff(exp, 3, n) for n in range(5)]) # exp'(x) = exp(x) | |
| [20.0855, 20.0855, 20.0855, 20.0855, 20.0855] | |
| Even more generally, given a tuple of arguments `(x_1, \ldots, x_k)` | |
| and order `(n_1, \ldots, n_k)`, the partial derivative | |
| `f^{(n_1,\ldots,n_k)}(x_1,\ldots,x_k)` is evaluated. For example:: | |
| >>> diff(lambda x,y: 3*x*y + 2*y - x, (0.25, 0.5), (0,1)) | |
| 2.75 | |
| >>> diff(lambda x,y: 3*x*y + 2*y - x, (0.25, 0.5), (1,1)) | |
| 3.0 | |
| **Options** | |
| The following optional keyword arguments are recognized: | |
| ``method`` | |
| Supported methods are ``'step'`` or ``'quad'``: derivatives may be | |
| computed using either a finite difference with a small step | |
| size `h` (default), or numerical quadrature. | |
| ``direction`` | |
| Direction of finite difference: can be -1 for a left | |
| difference, 0 for a central difference (default), or +1 | |
| for a right difference; more generally can be any complex number. | |
| ``addprec`` | |
| Extra precision for `h` used to account for the function's | |
| sensitivity to perturbations (default = 10). | |
| ``relative`` | |
| Choose `h` relative to the magnitude of `x`, rather than an | |
| absolute value; useful for large or tiny `x` (default = False). | |
| ``h`` | |
| As an alternative to ``addprec`` and ``relative``, manually | |
| select the step size `h`. | |
| ``singular`` | |
| If True, evaluation exactly at the point `x` is avoided; this is | |
| useful for differentiating functions with removable singularities. | |
| Default = False. | |
| ``radius`` | |
| Radius of integration contour (with ``method = 'quad'``). | |
| Default = 0.25. A larger radius typically is faster and more | |
| accurate, but it must be chosen so that `f` has no | |
| singularities within the radius from the evaluation point. | |
| A finite difference requires `n+1` function evaluations and must be | |
| performed at `(n+1)` times the target precision. Accordingly, `f` must | |
| support fast evaluation at high precision. | |
| With integration, a larger number of function evaluations is | |
| required, but not much extra precision is required. For high order | |
| derivatives, this method may thus be faster if f is very expensive to | |
| evaluate at high precision. | |
| **Further examples** | |
| The direction option is useful for computing left- or right-sided | |
| derivatives of nonsmooth functions:: | |
| >>> diff(abs, 0, direction=0) | |
| 0.0 | |
| >>> diff(abs, 0, direction=1) | |
| 1.0 | |
| >>> diff(abs, 0, direction=-1) | |
| -1.0 | |
| More generally, if the direction is nonzero, a right difference | |
| is computed where the step size is multiplied by sign(direction). | |
| For example, with direction=+j, the derivative from the positive | |
| imaginary direction will be computed:: | |
| >>> diff(abs, 0, direction=j) | |
| (0.0 - 1.0j) | |
| With integration, the result may have a small imaginary part | |
| even even if the result is purely real:: | |
| >>> diff(sqrt, 1, method='quad') # doctest:+ELLIPSIS | |
| (0.5 - 4.59...e-26j) | |
| >>> chop(_) | |
| 0.5 | |
| Adding precision to obtain an accurate value:: | |
| >>> diff(cos, 1e-30) | |
| 0.0 | |
| >>> diff(cos, 1e-30, h=0.0001) | |
| -9.99999998328279e-31 | |
| >>> diff(cos, 1e-30, addprec=100) | |
| -1.0e-30 | |
| """ | |
| partial = False | |
| try: | |
| orders = list(n) | |
| x = list(x) | |
| partial = True | |
| except TypeError: | |
| pass | |
| if partial: | |
| x = [ctx.convert(_) for _ in x] | |
| return _partial_diff(ctx, f, x, orders, options) | |
| method = options.get('method', 'step') | |
| if n == 0 and method != 'quad' and not options.get('singular'): | |
| return f(ctx.convert(x)) | |
| prec = ctx.prec | |
| try: | |
| if method == 'step': | |
| values, norm, workprec = hsteps(ctx, f, x, n, prec, **options) | |
| ctx.prec = workprec | |
| v = ctx.difference(values, n) / norm**n | |
| elif method == 'quad': | |
| ctx.prec += 10 | |
| radius = ctx.convert(options.get('radius', 0.25)) | |
| def g(t): | |
| rei = radius*ctx.expj(t) | |
| z = x + rei | |
| return f(z) / rei**n | |
| d = ctx.quadts(g, [0, 2*ctx.pi]) | |
| v = d * ctx.factorial(n) / (2*ctx.pi) | |
| else: | |
| raise ValueError("unknown method: %r" % method) | |
| finally: | |
| ctx.prec = prec | |
| return +v | |
| def _partial_diff(ctx, f, xs, orders, options): | |
| if not orders: | |
| return f() | |
| if not sum(orders): | |
| return f(*xs) | |
| i = 0 | |
| for i in range(len(orders)): | |
| if orders[i]: | |
| break | |
| order = orders[i] | |
| def fdiff_inner(*f_args): | |
| def inner(t): | |
| return f(*(f_args[:i] + (t,) + f_args[i+1:])) | |
| return ctx.diff(inner, f_args[i], order, **options) | |
| orders[i] = 0 | |
| return _partial_diff(ctx, fdiff_inner, xs, orders, options) | |
| def diffs(ctx, f, x, n=None, **options): | |
| r""" | |
| Returns a generator that yields the sequence of derivatives | |
| .. math :: | |
| f(x), f'(x), f''(x), \ldots, f^{(k)}(x), \ldots | |
| With ``method='step'``, :func:`~mpmath.diffs` uses only `O(k)` | |
| function evaluations to generate the first `k` derivatives, | |
| rather than the roughly `O(k^2)` evaluations | |
| required if one calls :func:`~mpmath.diff` `k` separate times. | |
| With `n < \infty`, the generator stops as soon as the | |
| `n`-th derivative has been generated. If the exact number of | |
| needed derivatives is known in advance, this is further | |
| slightly more efficient. | |
| Options are the same as for :func:`~mpmath.diff`. | |
| **Examples** | |
| >>> from mpmath import * | |
| >>> mp.dps = 15 | |
| >>> nprint(list(diffs(cos, 1, 5))) | |
| [0.540302, -0.841471, -0.540302, 0.841471, 0.540302, -0.841471] | |
| >>> for i, d in zip(range(6), diffs(cos, 1)): | |
| ... print("%s %s" % (i, d)) | |
| ... | |
| 0 0.54030230586814 | |
| 1 -0.841470984807897 | |
| 2 -0.54030230586814 | |
| 3 0.841470984807897 | |
| 4 0.54030230586814 | |
| 5 -0.841470984807897 | |
| """ | |
| if n is None: | |
| n = ctx.inf | |
| else: | |
| n = int(n) | |
| if options.get('method', 'step') != 'step': | |
| k = 0 | |
| while k < n + 1: | |
| yield ctx.diff(f, x, k, **options) | |
| k += 1 | |
| return | |
| singular = options.get('singular') | |
| if singular: | |
| yield ctx.diff(f, x, 0, singular=True) | |
| else: | |
| yield f(ctx.convert(x)) | |
| if n < 1: | |
| return | |
| if n == ctx.inf: | |
| A, B = 1, 2 | |
| else: | |
| A, B = 1, n+1 | |
| while 1: | |
| callprec = ctx.prec | |
| y, norm, workprec = hsteps(ctx, f, x, B, callprec, **options) | |
| for k in xrange(A, B): | |
| try: | |
| ctx.prec = workprec | |
| d = ctx.difference(y, k) / norm**k | |
| finally: | |
| ctx.prec = callprec | |
| yield +d | |
| if k >= n: | |
| return | |
| A, B = B, int(A*1.4+1) | |
| B = min(B, n) | |
| def iterable_to_function(gen): | |
| gen = iter(gen) | |
| data = [] | |
| def f(k): | |
| for i in xrange(len(data), k+1): | |
| data.append(next(gen)) | |
| return data[k] | |
| return f | |
| def diffs_prod(ctx, factors): | |
| r""" | |
| Given a list of `N` iterables or generators yielding | |
| `f_k(x), f'_k(x), f''_k(x), \ldots` for `k = 1, \ldots, N`, | |
| generate `g(x), g'(x), g''(x), \ldots` where | |
| `g(x) = f_1(x) f_2(x) \cdots f_N(x)`. | |
| At high precision and for large orders, this is typically more efficient | |
| than numerical differentiation if the derivatives of each `f_k(x)` | |
| admit direct computation. | |
| Note: This function does not increase the working precision internally, | |
| so guard digits may have to be added externally for full accuracy. | |
| **Examples** | |
| >>> from mpmath import * | |
| >>> mp.dps = 15; mp.pretty = True | |
| >>> f = lambda x: exp(x)*cos(x)*sin(x) | |
| >>> u = diffs(f, 1) | |
| >>> v = mp.diffs_prod([diffs(exp,1), diffs(cos,1), diffs(sin,1)]) | |
| >>> next(u); next(v) | |
| 1.23586333600241 | |
| 1.23586333600241 | |
| >>> next(u); next(v) | |
| 0.104658952245596 | |
| 0.104658952245596 | |
| >>> next(u); next(v) | |
| -5.96999877552086 | |
| -5.96999877552086 | |
| >>> next(u); next(v) | |
| -12.4632923122697 | |
| -12.4632923122697 | |
| """ | |
| N = len(factors) | |
| if N == 1: | |
| for c in factors[0]: | |
| yield c | |
| else: | |
| u = iterable_to_function(ctx.diffs_prod(factors[:N//2])) | |
| v = iterable_to_function(ctx.diffs_prod(factors[N//2:])) | |
| n = 0 | |
| while 1: | |
| #yield sum(binomial(n,k)*u(n-k)*v(k) for k in xrange(n+1)) | |
| s = u(n) * v(0) | |
| a = 1 | |
| for k in xrange(1,n+1): | |
| a = a * (n-k+1) // k | |
| s += a * u(n-k) * v(k) | |
| yield s | |
| n += 1 | |
| def dpoly(n, _cache={}): | |
| """ | |
| nth differentiation polynomial for exp (Faa di Bruno's formula). | |
| TODO: most exponents are zero, so maybe a sparse representation | |
| would be better. | |
| """ | |
| if n in _cache: | |
| return _cache[n] | |
| if not _cache: | |
| _cache[0] = {(0,):1} | |
| R = dpoly(n-1) | |
| R = dict((c+(0,),v) for (c,v) in iteritems(R)) | |
| Ra = {} | |
| for powers, count in iteritems(R): | |
| powers1 = (powers[0]+1,) + powers[1:] | |
| if powers1 in Ra: | |
| Ra[powers1] += count | |
| else: | |
| Ra[powers1] = count | |
| for powers, count in iteritems(R): | |
| if not sum(powers): | |
| continue | |
| for k,p in enumerate(powers): | |
| if p: | |
| powers2 = powers[:k] + (p-1,powers[k+1]+1) + powers[k+2:] | |
| if powers2 in Ra: | |
| Ra[powers2] += p*count | |
| else: | |
| Ra[powers2] = p*count | |
| _cache[n] = Ra | |
| return _cache[n] | |
| def diffs_exp(ctx, fdiffs): | |
| r""" | |
| Given an iterable or generator yielding `f(x), f'(x), f''(x), \ldots` | |
| generate `g(x), g'(x), g''(x), \ldots` where `g(x) = \exp(f(x))`. | |
| At high precision and for large orders, this is typically more efficient | |
| than numerical differentiation if the derivatives of `f(x)` | |
| admit direct computation. | |
| Note: This function does not increase the working precision internally, | |
| so guard digits may have to be added externally for full accuracy. | |
| **Examples** | |
| The derivatives of the gamma function can be computed using | |
| logarithmic differentiation:: | |
| >>> from mpmath import * | |
| >>> mp.dps = 15; mp.pretty = True | |
| >>> | |
| >>> def diffs_loggamma(x): | |
| ... yield loggamma(x) | |
| ... i = 0 | |
| ... while 1: | |
| ... yield psi(i,x) | |
| ... i += 1 | |
| ... | |
| >>> u = diffs_exp(diffs_loggamma(3)) | |
| >>> v = diffs(gamma, 3) | |
| >>> next(u); next(v) | |
| 2.0 | |
| 2.0 | |
| >>> next(u); next(v) | |
| 1.84556867019693 | |
| 1.84556867019693 | |
| >>> next(u); next(v) | |
| 2.49292999190269 | |
| 2.49292999190269 | |
| >>> next(u); next(v) | |
| 3.44996501352367 | |
| 3.44996501352367 | |
| """ | |
| fn = iterable_to_function(fdiffs) | |
| f0 = ctx.exp(fn(0)) | |
| yield f0 | |
| i = 1 | |
| while 1: | |
| s = ctx.mpf(0) | |
| for powers, c in iteritems(dpoly(i)): | |
| s += c*ctx.fprod(fn(k+1)**p for (k,p) in enumerate(powers) if p) | |
| yield s * f0 | |
| i += 1 | |
| def differint(ctx, f, x, n=1, x0=0): | |
| r""" | |
| Calculates the Riemann-Liouville differintegral, or fractional | |
| derivative, defined by | |
| .. math :: | |
| \,_{x_0}{\mathbb{D}}^n_xf(x) = \frac{1}{\Gamma(m-n)} \frac{d^m}{dx^m} | |
| \int_{x_0}^{x}(x-t)^{m-n-1}f(t)dt | |
| where `f` is a given (presumably well-behaved) function, | |
| `x` is the evaluation point, `n` is the order, and `x_0` is | |
| the reference point of integration (`m` is an arbitrary | |
| parameter selected automatically). | |
| With `n = 1`, this is just the standard derivative `f'(x)`; with `n = 2`, | |
| the second derivative `f''(x)`, etc. With `n = -1`, it gives | |
| `\int_{x_0}^x f(t) dt`, with `n = -2` | |
| it gives `\int_{x_0}^x \left( \int_{x_0}^t f(u) du \right) dt`, etc. | |
| As `n` is permitted to be any number, this operator generalizes | |
| iterated differentiation and iterated integration to a single | |
| operator with a continuous order parameter. | |
| **Examples** | |
| There is an exact formula for the fractional derivative of a | |
| monomial `x^p`, which may be used as a reference. For example, | |
| the following gives a half-derivative (order 0.5):: | |
| >>> from mpmath import * | |
| >>> mp.dps = 15; mp.pretty = True | |
| >>> x = mpf(3); p = 2; n = 0.5 | |
| >>> differint(lambda t: t**p, x, n) | |
| 7.81764019044672 | |
| >>> gamma(p+1)/gamma(p-n+1) * x**(p-n) | |
| 7.81764019044672 | |
| Another useful test function is the exponential function, whose | |
| integration / differentiation formula easy generalizes | |
| to arbitrary order. Here we first compute a third derivative, | |
| and then a triply nested integral. (The reference point `x_0` | |
| is set to `-\infty` to avoid nonzero endpoint terms.):: | |
| >>> differint(lambda x: exp(pi*x), -1.5, 3) | |
| 0.278538406900792 | |
| >>> exp(pi*-1.5) * pi**3 | |
| 0.278538406900792 | |
| >>> differint(lambda x: exp(pi*x), 3.5, -3, -inf) | |
| 1922.50563031149 | |
| >>> exp(pi*3.5) / pi**3 | |
| 1922.50563031149 | |
| However, for noninteger `n`, the differentiation formula for the | |
| exponential function must be modified to give the same result as the | |
| Riemann-Liouville differintegral:: | |
| >>> x = mpf(3.5) | |
| >>> c = pi | |
| >>> n = 1+2*j | |
| >>> differint(lambda x: exp(c*x), x, n) | |
| (-123295.005390743 + 140955.117867654j) | |
| >>> x**(-n) * exp(c)**x * (x*c)**n * gammainc(-n, 0, x*c) / gamma(-n) | |
| (-123295.005390743 + 140955.117867654j) | |
| """ | |
| m = max(int(ctx.ceil(ctx.re(n)))+1, 1) | |
| r = m-n-1 | |
| g = lambda x: ctx.quad(lambda t: (x-t)**r * f(t), [x0, x]) | |
| return ctx.diff(g, x, m) / ctx.gamma(m-n) | |
| def diffun(ctx, f, n=1, **options): | |
| r""" | |
| Given a function `f`, returns a function `g(x)` that evaluates the nth | |
| derivative `f^{(n)}(x)`:: | |
| >>> from mpmath import * | |
| >>> mp.dps = 15; mp.pretty = True | |
| >>> cos2 = diffun(sin) | |
| >>> sin2 = diffun(sin, 4) | |
| >>> cos(1.3), cos2(1.3) | |
| (0.267498828624587, 0.267498828624587) | |
| >>> sin(1.3), sin2(1.3) | |
| (0.963558185417193, 0.963558185417193) | |
| The function `f` must support arbitrary precision evaluation. | |
| See :func:`~mpmath.diff` for additional details and supported | |
| keyword options. | |
| """ | |
| if n == 0: | |
| return f | |
| def g(x): | |
| return ctx.diff(f, x, n, **options) | |
| return g | |
| def taylor(ctx, f, x, n, **options): | |
| r""" | |
| Produces a degree-`n` Taylor polynomial around the point `x` of the | |
| given function `f`. The coefficients are returned as a list. | |
| >>> from mpmath import * | |
| >>> mp.dps = 15; mp.pretty = True | |
| >>> nprint(chop(taylor(sin, 0, 5))) | |
| [0.0, 1.0, 0.0, -0.166667, 0.0, 0.00833333] | |
| The coefficients are computed using high-order numerical | |
| differentiation. The function must be possible to evaluate | |
| to arbitrary precision. See :func:`~mpmath.diff` for additional details | |
| and supported keyword options. | |
| Note that to evaluate the Taylor polynomial as an approximation | |
| of `f`, e.g. with :func:`~mpmath.polyval`, the coefficients must be reversed, | |
| and the point of the Taylor expansion must be subtracted from | |
| the argument: | |
| >>> p = taylor(exp, 2.0, 10) | |
| >>> polyval(p[::-1], 2.5 - 2.0) | |
| 12.1824939606092 | |
| >>> exp(2.5) | |
| 12.1824939607035 | |
| """ | |
| gen = enumerate(ctx.diffs(f, x, n, **options)) | |
| if options.get("chop", True): | |
| return [ctx.chop(d)/ctx.factorial(i) for i, d in gen] | |
| else: | |
| return [d/ctx.factorial(i) for i, d in gen] | |
| def pade(ctx, a, L, M): | |
| r""" | |
| Computes a Pade approximation of degree `(L, M)` to a function. | |
| Given at least `L+M+1` Taylor coefficients `a` approximating | |
| a function `A(x)`, :func:`~mpmath.pade` returns coefficients of | |
| polynomials `P, Q` satisfying | |
| .. math :: | |
| P = \sum_{k=0}^L p_k x^k | |
| Q = \sum_{k=0}^M q_k x^k | |
| Q_0 = 1 | |
| A(x) Q(x) = P(x) + O(x^{L+M+1}) | |
| `P(x)/Q(x)` can provide a good approximation to an analytic function | |
| beyond the radius of convergence of its Taylor series (example | |
| from G.A. Baker 'Essentials of Pade Approximants' Academic Press, | |
| Ch.1A):: | |
| >>> from mpmath import * | |
| >>> mp.dps = 15; mp.pretty = True | |
| >>> one = mpf(1) | |
| >>> def f(x): | |
| ... return sqrt((one + 2*x)/(one + x)) | |
| ... | |
| >>> a = taylor(f, 0, 6) | |
| >>> p, q = pade(a, 3, 3) | |
| >>> x = 10 | |
| >>> polyval(p[::-1], x)/polyval(q[::-1], x) | |
| 1.38169105566806 | |
| >>> f(x) | |
| 1.38169855941551 | |
| """ | |
| # To determine L+1 coefficients of P and M coefficients of Q | |
| # L+M+1 coefficients of A must be provided | |
| if len(a) < L+M+1: | |
| raise ValueError("L+M+1 Coefficients should be provided") | |
| if M == 0: | |
| if L == 0: | |
| return [ctx.one], [ctx.one] | |
| else: | |
| return a[:L+1], [ctx.one] | |
| # Solve first | |
| # a[L]*q[1] + ... + a[L-M+1]*q[M] = -a[L+1] | |
| # ... | |
| # a[L+M-1]*q[1] + ... + a[L]*q[M] = -a[L+M] | |
| A = ctx.matrix(M) | |
| for j in range(M): | |
| for i in range(min(M, L+j+1)): | |
| A[j, i] = a[L+j-i] | |
| v = -ctx.matrix(a[(L+1):(L+M+1)]) | |
| x = ctx.lu_solve(A, v) | |
| q = [ctx.one] + list(x) | |
| # compute p | |
| p = [0]*(L+1) | |
| for i in range(L+1): | |
| s = a[i] | |
| for j in range(1, min(M,i) + 1): | |
| s += q[j]*a[i-j] | |
| p[i] = s | |
| return p, q | |