2013-04-11 4 views
6

Zasadniczo, biorąc pod uwagę to funkcja, która produkuje tak wyjść dla różnych parametrów:Szybko znalezieniu pierwszego punktu, w którym funkcja jest równa 0 użyciem scipy.optimize

enter image description here

chcę szybko znaleźć pierwsze xw której funkcja równa się 0. Tak więc przy parametrach, które tworzą niebieską krzywą ponad x, chcę znaleźć x = 134. Na zielonej krzywej, chcę znaleźć x = 56 itd

myślę funkcja zawsze będzie monotonicznie maleje, aż spadnie do zera, ale nie jestem całkowicie pewien.

Funkcja niekoniecznie maleje monotonicznie.

I am pewność, że uderzy tylko 0 raz, a następnie pozostanie zero.

Obecnie jestem brutalnie-forsujący to przez iterowanie przez wartości x, aż osiągnę zero, ale chcę czegoś, co będzie lepsze w wykształconych domysłach (na podstawie nachylenia?) I iteracji.

Idealnie chcę użyć czegoś już wypalonego (since 90% of programmers can't even write a binary search correctly), jak coś z scipy.optimize, ale wygląda na to, że wszyscy chcą znaleźć albo globalne minimum, albo przejście przez zero.

(Ta funkcja to rodzaj distance_to_the_wall kostki RGB dla danej barwy w przestrzeni kolorów Lch (czyli po prostu budowanie funkcji "sanely clip to RGB"), ale ponieważ odwzorowanie między IRGB i LCh może się różnić w zależności od biblioteki i z parametrami takimi jak iluminant itp. Myślę, że najlepiej jest wypróbować kilka wartości, aż znajdzie się właściwy, a nie próbować odwrócić - obliczyć wartość bezpośrednio?)

+1

Czy funkcja całkowita wahał (lub podobnie dyskretny)? W przeciwnym razie, jak możesz iterować przez wartości x? – abarnert

+0

Ponadto, jeśli masz globalny algorytm minimalny i nie możesz znaleźć algorytmu przecinającego zero ... zawsze możesz użyć wartości 'global_minimum (lambda x: abs (foo (x))). (Nie twierdzę, że to oczywiście rozwiązanie _right_). – abarnert

+0

Nie sądzę, że równania są takie, że można je rozwiązać za pomocą rachunku różniczkowego. Innymi słowy, musisz użyć metod numerycznych do przybliżenia? – vossad01

Odpowiedz

2

Oto kod, który wcielił się w bisekcji @ exp/binarnego wyszukiwania odpowiedzi:

def find_first_zero(func, min, max, tol=1e-3): 
    min, max = float(min), float(max) 
    assert (max + tol) > max 
    while (max - min) > tol: 
     mid = (min + max)/2 
     if func(mid) == 0: 
      max = mid 
     else: 
      min = mid 
    return max 
0

Jeśli nie z faktu, że prawa ręka krzywa wynosi 0 wszędzie, metoda Newtona (https://en.wikipedia.org/wiki/Newton's_method) byłaby świetna. Ale myślę, że wariant nadal będzie działał dobrze:

1) Wybierz punkt.

2) Jeśli jesteśmy na zboczu, weźmy lokalnie nachylenie zbocza i prześledźmy linię stamtąd do punktu przecięcia x i potraktujmy go jako nowy punkt (przejdź do 1)).

3) Jeśli znajdujemy się na płaskiej równinie (x = 0, pochodna = 0), to jeśli nieco po lewej stronie jest nachylenie (trzeba by było to dostroić, aby określić, ile zostało do sprawdzenia), a następnie wykonaj wyszukiwanie lokalne (prawdopodobnie wyszukiwanie binarne z tolerancją), aby znaleźć punkt, w którym funkcja najpierw jest równa zero. Jeśli nie, to weź punkt będący środkiem między tym punktem a ostatnim punktem na zboczu, którego próbowaliśmy (przejdź do 1 z tym nowym punktem).

Aby oszacować pochodną (w celu ustalenia, czy znajdujesz się na zboczu, czy nie), możesz wypróbować punkt po lewej i po prawej stronie, na tyle daleko, aby mieć pewność, że uzyskasz płynne przybliżenie pochodnej.

+0

Newton, jak to jest, nie działa: Jest oparty na gradiencie (więc najpierw trzeba to skądś dostać), a gradient funkcji wynosi 0, gdy jego wartość osiągnie 0. To doprowadziłoby do podziału przez 0 -> niepowodzenie. Artykuł wiki, do którego się odwołujesz, pokazuje także inne przypadki, w których Newton nie będzie działał. –

+0

@ExP Dlatego sugeruję zmodyfikowaną wersję metody Newtona. Przeczytaj moją odpowiedź :) – Patashu

+0

"Jeśli jesteśmy na zboczu" i "jeśli jesteśmy na równinie" to nie jest coś, co znacie po wybraniu punktu, to jednak należy go obliczyć jako osobny krok, nie? – endolith

2

Wypróbuj bisection: Sprawdź, czy w środku interwału jest 0; jeśli tak, kontynuuj po lewej, w przeciwnym razie po prawej. Zrób to samo z rekurencyjnie zredukowanym interwałem, aż będziesz wystarczająco blisko. Ta metoda ma złożoność O (log n) w porównaniu do twojej, która jest O (n).

+1

Tylko po to, aby wyjaśnić - Funkcja nie musi nawet monotonicznie maleć. "Raz zero, zawsze zero" oznacza, że ​​zasadniczo masz już "posortowaną" listę, gdzie wszystkie zera są po jednej stronie, a ty po prostu szukasz pierwszego. – job

Powiązane problemy