6.17. Ratkaisijat ja satunnaisluvut

Kun tutkittava funktio määritellään Python-koodilla näytepuskurin sijaan, oikea valinta on eri työkaluperhe: missä on funktion juuri, sen minimi, sen integraali annetulla välillä? Alimoduulit scipy.integrate ja scipy.optimize kattavat tämän työn. Kukin algoritmi kutsuu takaisin käyttäjän antamaa Python-funktiota, joten iteraatiokohtainen kustannus on korkeampi kuin puskurin redusoinnissa; mukavuus on siinä, ettei ratkaisijaa tarvitse kirjoittaa itse.

Alimoduuli scipy.special kattaa tilastolliset erikoisfunktiot (virhefunktio, gamma), jotka tulevat vastaan laskettaessa todennäköisyysjakauman kertymäfunktiota (CDF, todennäköisyys että näyte on korkeintaan annettu arvo) tai tiheysfunktiota (PDF, suhteellinen todennäköisyys annetulla arvolla). numpy.random kattaa pseudosatunnaisgeneraattorin ditteröintiin, simulointiin ja synteettiseen testidataan.

6.17.1. Kutsuttavan numeerinen integrointi

Kun integroitava on Python-funktio näytepuskurin sijaan, scipy.integrate tarjoaa neljä kvadratuurialgoritmia:

  • quad() – adaptiivinen Gauss-Kronrod. Oikea oletus sileille integroitaville. Palauttaa (value, error).

  • romberg() – klassinen Romberg / Newton-Cotes. Palauttaa yksittäisen liukuluvun. Vanhentunut lähdekoodissa; sisällytetty yhteensopivuuden vuoksi.

  • simpson() – adaptiivinen Simpsonin sääntö. Palauttaa yksittäisen liukuluvun.

  • tanhsinh() – kaksoiseksponentiaalinen kvadratuuri. Käytä, kun integroitavalla on päätepistesingulariteetteja tai ääretön raja. Palauttaa (value, error).

Gaussin integraali laskettuna kaksoiseksponentiaalisella säännöllä (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))

Tuloste:

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

6.17.2. Juurten etsintä ja minimointi

scipy.optimize kattaa kolme klassista yhden muuttujan ratkaisijaa. Kukin iteraatio kutsuu takaisin käyttäjän antamaa Python-funktiota, joten nopeutus puhtaaseen Python-ratkaisijaan verrattuna on maltillinen (noin 2x); mukavuus on siinä, ettei ratkaisijaa tarvitse kirjoittaa itse.

  • bisect() – etsii funktion f juuren välillä [a, b] puolittamalla väliä. f(a) ja f(b) on oltava vastakkaismerkkisiä:

    def f(x):
        return x * x - 1
    
    sp.optimize.bisect(f, 0, 4)        # ~1.0
    
  • newton() – etsii juuren käyttäen sekantti- / Newton-Raphson-iteraatiota:

    def f(x):
        return x * x * x - 2.0
    
    sp.optimize.newton(f, 3., tol=0.001, rtol=0.01)
    # ~1.260
    
  • fmin() – etsii paikallisen minimin käyttäen alaspäin laskevan simpleksin (Nelder-Mead) menetelmää:

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

Yhden muuttujan laajuus riittää useimpiin kamerapuolen optimointeihin – sensorin kalibrointivakio, vahvistus joka maksimoi kontrastimittauksen, kynnysarvo jossa histogrammin kaksihuippuisuus on terävimmillään. Moniulotteisiin ongelmiin oikea vastaus on yleensä muotoilla ongelma uudelleen pienenä lineaarialgebran ratkaisuna sen sijaan, että tartuttaisiin yleiseen epälineaariseen optimoijaan.

6.17.3. Erikoisfunktiot

scipy.special tarjoaa kourallisen tilastollisia ja todennäköisyysfunktioita, jotka käyttäytyvät kuin universaalit funktiot – ne hyväksyvät skalaarin, iteroitavan tai ndarray-taulukon ja palauttavat liukuluku-ndarray-taulukon:

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

Virhefunktio ja sen komplementti esiintyvät Gaussin kertymäfunktiossa – valinta z-arvon ja todennäköisyyden välillä muuntamiseen tai normaalijakauman häntäintegraalin laskemiseen. Gamma- ja log-gammafunktiot tulevat esiin beta- / khii-toiseen- / studentin t -laskelmissa; gammaln on numeerisesti vakaa muoto suurille argumenteille, joilla gamma itse ylivuotaisi.

6.17.4. Satunnaisluvut

numpy.random tarjoaa Generator-luokan, joka poimii näytteitä yleisistä jakaumista. Generaattori on tilallinen: jokainen kutsu edistää sen sisäistä tilaa, joten peräkkäiset kutsut palauttavat riippumattomia näytteitä:

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))

Tuloksen dtype on aina float. size= hyväksyy kokonaisluvun (yksiulotteinen tuloste) tai monikon (n-ulotteinen tuloste); kun se jätetään pois, palautetaan yksittäinen Python-liukuluku.

Generaattori soveltuu simulointiin, ditteröintiin, synteettiseen testidataan ja kaikkiin muihin sovelluksiin, joissa kryptografista lujuutta ei vaadita. Se ei sovellu avaimiin tai poletteihin; käytä niihin järjestelmän satunnaislähdettä os-moduulin kautta.

6.17.5. Saatavuus käännösaikana

Se, onko kukin alimoduuli todella läsnä, riippuu siitä, miten kamera käännettiin. scipy.optimize ja scipy.special eivät ole käytössä jokaisessa kamerassa; sellaisen funktion kutsuminen, jota kamera ei sisällä, nostaa AttributeError. dir(sp), dir(sp.optimize), dir(np.random) ja kumppanit raportoivat, mitä kohdekameralla on saatavilla.