Jeśli chcesz zobaczyć, jak rzeczy są obliczane, pdb
jest rzeczywiście jedno rozwiązanie.
Jednak z debugerem takim jak pdb
, trudno jest uzyskać ogólny przegląd tego, co się dzieje. Dlatego też przydatne jest czytanie kodu. Na przykład, jeśli chcesz się dowiedzieć, co robi a+b
, możesz sprawdzić, czy istnieje type(a).__add__
, ponieważ jeśli tak, to obsługuje dodawanie. Tak jest w przypadku pakietu niepewności.
To powiedziawszy, __add__
jest rzeczywiście zaimplementowany w niepewnościach za pomocą ogólnego mechanizmu, zamiast być specjalnie kodowanym, więc mogę powiedzieć Ci, co kryje się za jego implementacją, ponieważ tego właśnie szukasz.
W przykładzie a
i b
są Variable
obiektów:
>>> from uncertainties import ufloat
>>> a = ufloat(1, 3)
>>> b = ufloat(2, 4)
>>> type(a)
<class 'uncertainties.Variable'>
Następnie c = a + b
faktycznie liniowy funkcja z a
i b
reprezentowanym przez jego pochodnych w stosunku do a
i b
:
>>> c = a + b
>>> type(c)
<class 'uncertainties.AffineScalarFunc'>
>>> c.derivatives
{1.0+/-3.0: 1.0, 2.0+/-4.0: 1.0}
Jeśli znasz pochodną es funkcji w odniesieniu do zmiennych, można łatwo uzyskać approximation of its standard deviation from the standard deviations of its variables.
Zatem główny Idee wykonania uncertainties package jest to, że wartości są albo:
- zmiennymi losowymi jak x = 3,14 ± 0.0.1 i y = 0 ± 0,01 (
Variable
obiekty), opisali ich odchylenie standardowe,
- lub przybliżenia liniowe funkcji (
AffineScalarFunc
obiekty: "afiniczne", ponieważ są liniowe, "skalarne", ponieważ ich wartości są rzeczywiste, a "func", ponieważ są one funkcjami).
Aby przyjąć bardziej skomplikowany przykład, z = 2 * x + sin (y) jest przybliżony w (x, y) = (3.14, 0) jako 2 * x + y.W realizacji, ponieważ przybliżeniem jest liniowy, tylko pochodne względem zmiennych są przechowywane:
>>> x = ufloat(3.14, 0.01)
>>> y = ufloat(0, 0.01)
>>> from uncertainties.umath import sin
>>> z = 2*x + sin(y)
>>> type(z)
<class 'uncertainties.AffineScalarFunc'>
>>> z.derivatives
{3.14+/-0.01: 2.0, 0.0+/-0.01: 1.0}
Główne prace wykonane przez pakiet niejasności zatem obliczyć pochodne dowolnej funkcji udziałem zmienne. Odbywa się to za pomocą wydajnej metody automatic differentiation. Konkretnie, gdy robisz coś takiego jak a+b
, Python automatycznie wywołuje metodę Variable.__add__()
, która tworzy nową funkcję liniową przez obliczanie pochodnych a+b
w odniesieniu do jej zmiennych (pochodne są oba, ponieważ pochodna a
w odniesieniu do a
jest jeden i taki sam dla b
). Mówiąc bardziej ogólnie, dodaje się zmienne nie będące czystymi: pochodne f(a,b) + g(a,b)
w odniesieniu do a
i b
oblicza się za pomocą reguły łańcuchowej. W ten sposób działa automatyczne różnicowanie i to właśnie jest realizowane w pakiecie niepewności. Kluczową funkcją jest tutaj uncertainties.wrap()
. Jest to największa i najbardziej skomplikowana funkcja całego pakietu, ale kod jest w dużej mierze komentowany i dostępne są details on the method.
Instrumenty pochodne dają standardowe odchylenie funkcji końcowej w funkcji standardowych odchyleń zmiennych (kod AffineScalarFunc.std_dev()
jest bardzo prosty: trudniejszym zadaniem jest automatyczne obliczanie pochodnych).
Użyj debuggera? – BartoszKP
Uważam, że Google jest zwykle bardziej celowy niż debugger. Zapoznaj się z dokumentacją. Lub, co najgorsze, po prostu nurkowanie w źródle, jeśli na przykład wiesz, że obiekty mogą określać metody takie jak "__add__" w celu implementacji zachowania z operatorami arytmetycznymi. – roippi
@roippi Dokumentacja Pythona, którą spotkałem, różni się bardzo od Javadocs, do których jestem przyzwyczajona i nie jest intuicyjna do naśladowania, a także nie wiem, jak ją zbudować (lub jeśli istnieje) pakiet niepewności. Wiem, że obiekty mogą pisać własną funkcję "__add__", z tym wyjątkiem, że myślę, że są one dodawane przez odbicie, przechodzenie przez komentarze, więc próba śledzenia wszystkiego za pomocą kodu źródłowego jest trochę trudna. – masher