6.17. Rješavači i slučajni brojevi

Kada je proučavana funkcija definirana Python kodom umjesto međuspremnikom uzoraka, prava je odluka drukčija obitelj alata: gdje je korijen funkcije, njezin minimum, njezin integral preko zadanog intervala? Podmoduli scipy.integrate i scipy.optimize pokrivaju taj posao. Svaki algoritam poziva natrag korisnički zadanu Python funkciju, pa je trošak po iteraciji veći nego kod redukcije međuspremnika; pogodnost je u tome što ne morate pisati rješavač.

Podmodul scipy.special pokriva statističke specijalne funkcije (funkcija pogreške, gama) koje se pojavljuju pri izračunavanju kumulativne funkcije distribucije (CDF, vjerojatnost da je uzorak najviše određene vrijednosti) ili funkcije gustoće vjerojatnosti (PDF, relativna vjerojatnost pri određenoj vrijednosti) neke distribucije vjerojatnosti. numpy.random pokriva pseudoslučajni generator za zaglađivanje (dithering), simulaciju i sintetičke testne podatke.

6.17.1. Numerička integracija pozivne funkcije

Kada je podintegralna funkcija Python funkcija umjesto međuspremnika uzoraka, scipy.integrate izlaže četiri kvadraturna algoritma:

  • quad() – adaptivni Gauss-Kronrod. Pravi zadani izbor za glatke podintegralne funkcije. Vraća (value, error).

  • romberg() – klasični Romberg / Newton-Cotes. Vraća jedan float. Zastarjelo na izvoru; uključeno radi kompatibilnosti.

  • simpson() – adaptivno Simpsonovo pravilo. Vraća jedan float.

  • tanhsinh() – dvostruko eksponencijalna kvadratura. Koristite kada podintegralna funkcija ima singularitete na rubovima ili beskonačnu granicu. Vraća (value, error).

Gaussov integral izračunat dvostruko eksponencijalnim pravilom (tanhsinh):

from math import exp
from math import pi
from math import sqrt
from ulab import numpy as np
from ulab import scipy as sp

f = lambda x: exp(-x * x)
value, err = sp.integrate.tanhsinh(f, -np.inf, np.inf)
print("approx:", value, "   exact:", sqrt(pi))

Izlaz:

approx: 1.7724538...   exact: 1.7724538...

6.17.2. Pronalaženje korijena i minimizacija

scipy.optimize pokriva tri klasična rješavača za jednu varijablu. Svaka iteracija poziva natrag korisnički zadanu Python funkciju, pa je ubrzanje u odnosu na čisto Python rješavač skromno (otprilike 2x); pogodnost je u tome što ne morate pisati rješavač.

  • bisect() – pronađite korijen funkcije f na [a, b] raspolavljanjem intervala. f(a) i f(b) moraju imati suprotne predznake:

    def f(x):
        return x * x - 1
    
    sp.optimize.bisect(f, 0, 4)        # ~1.0
    
  • newton() – pronađite korijen koristeći iteraciju sekante / Newton-Raphsona:

    def f(x):
        return x * x * x - 2.0
    
    sp.optimize.newton(f, 3., tol=0.001, rtol=0.01)
    # ~1.260
    
  • fmin() – pronađite lokalni minimum koristeći metodu silaznog simpleksa (Nelder-Mead):

    def f(x):
        return (x - 1) ** 2 - 1
    
    sp.optimize.fmin(f, 3.0)           # ~1.0
    

Doseg jedne varijable dovoljan je za većinu optimizacija na strani kamere – konstanta kalibracije senzora, pojačanje koje maksimizira mjeru kontrasta, prag pri kojem je bimodalnost histograma najizraženija. Za probleme s više varijabli pravi je odgovor obično preoblikovati problem u malen linearno-algebarski izračun umjesto posezanja za općim nelinearnim optimizatorom.

6.17.3. Specijalne funkcije

scipy.special izlaže nekoliko statističkih i vjerojatnosnih funkcija koje se ponašaju poput univerzalnih funkcija – prihvaćaju skalar, iterabilni objekt ili ndarray i vraćaju ndarray s pomičnim zarezom:

x = np.linspace(0, 4, num=8)

sp.special.erf(x)         # error function
sp.special.erfc(x)        # complementary error function
sp.special.gamma(x + 1)   # gamma function
sp.special.gammaln(x + 1) # log-gamma function

Funkcija pogreške i njezin komplement pojavljuju se u CDF-u Gaussove distribucije – prava primjena za pretvaranje između izmjerenog z-rezultata i vjerojatnosti ili za izračunavanje repnog integrala normalne distribucije. Gama i log-gama funkcije pojavljuju se u beta / hi-kvadrat / studentovim t izračunima; gammaln je numerički stabilan oblik za velike argumente gdje bi sam gamma prelio.

6.17.4. Slučajni brojevi

numpy.random pruža klasu Generator koja izvlači uzorke iz uobičajenih distribucija. Generator je stanjivit: svaki poziv napreduje njegovo interno stanje, pa uzastopni pozivi vraćaju nezavisne uzorke:

from ulab import numpy as np

rng = np.random.Generator(seed=42)

rng.random(size=5)             # 5 uniform [0.0, 1.0) samples
rng.uniform(low=-1.0, high=1.0, size=10)
rng.normal(loc=0.0, scale=1.0, size=(2, 4))

Izlazni dtype uvijek je float. size= prihvaća cijeli broj (1-D izlaz) ili torku (n-D izlaz); kada je izostavljen, vraća se jedan Python float.

Generator je prikladan za simulaciju, zaglađivanje (dithering), sintetičke testne podatke i svaku drugu primjenu gdje kriptografska snaga nije potrebna. Nije prikladan za ključeve ili tokene; za njih koristite sustavski izvor slučajnosti putem os.

6.17.5. Dostupnost pri izgradnji

Je li svaki podmodul stvarno prisutan ovisi o tome kako je kamera izgrađena. scipy.optimize i scipy.special nisu omogućeni na svakoj kameri; pozivanje funkcije koju kamera ne uključuje izaziva AttributeError. dir(sp), dir(sp.optimize), dir(np.random) i njima slični izvještavaju što je dostupno na ciljanoj kameri.