Newtons metode

I dette eksempelet skal vi finna eit eller fleire nullpunkt for ein funksjon vha. Newton Raphson-metoden.

Den første funksjonen vi skal bruka er $ f(x) = x^3 - 2x +2 $, samt den deriverte av funksjonen, som er: $ f'(x) = 3x^2 - 2 $

No kan vi like godt begynna å koda ved å definera disse som to funksjonar:

In [1]:
def f(x):
    return x**3-2*x+2
def df(x):
    return 3*x**2-2

Hvis du treng oppfrisking på korleis funksjonar virkar, så sjekk her eller her. Merk at potensar i python lagar vi med to stjerner. Så er det alltid greit å testa om funksjonen virkar. Vi kan be den rekna ut f(-1) og f'(-1). Då skal vi få f(-1) = -1 +2 + 2 = 3, og f'(-1) = 3 - 2 = 1:

In [2]:
print("Vi tester: f(-1)=",f(1),"og f'(-1) =",df(-1))
Vi tester: f(-1)= 1 og f'(-1) = 1

Det funkar! Så no er vi klar for å bruka formelen i Newtons metode:

$ x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}$

La oss starta med verdien x0 = -1, rekna ut neste verdi med formelen vår, og skriva den ut:

In [3]:
x0 = -1 #Startverdi for x0. Dette er vår gjetning på nullpunktet.
x0 = x0 - f(x0)/df(x0)
print("x0=",x0)
x0= -4.0

Men stopp litt! Korfor bruker vi x0 både på venstre og høgre side i formelen no? Svaret er vi har ikkje tenkt å ta vare på alle verdiane $x_n$, så vi treng bare ein variabel, som vi har kalla x0. Før vi bruker formelen er den lik -1. Etter at vi har brukt formelen er den lik -4. Dermed kan vi bruka denne formelen inne i ei løkke for å stadig finna betre (forhåpentlig) verdiar for x0:

In [4]:
x0 = -1
n = 0 #Tellevariabel som vi set lik 0 før løkka.

while n < 10:
    n += 1 #Vi aukar tellevariabelen med 1 for kvar iterasjon
    x0 = x0 - f(x0)/df(x0)
print("Vi fant rota x = ",x0)
Vi fant rota x =  -1.7692923542386314

Hurra, det stemte! GeoGebra gir det samme svaret, så vi har grunn til å tru at dette vart suksess. Her har vi brukt n som ein tellevariabel og stoppa løkka når n vart 9. Men det kan henda at vi treng fleire iterasjonar for å finna eit svar. Så vi vil heller innføra eit anna stoppkriterium. Vi innfører ein variabel toleranse, som vi kan setja til det vi vil, og så stoppar vi når funksjonsverdien vår er lavare enn denne toleransen:

In [5]:
x0 = -1
n = 0
toleranse = 1e-12 #Vi stoppar når absoluttverdien av f(x) er mindre enn denne.

while abs(f(x0)) > toleranse and n < 100:
    n += 1
    x0 = x0 - f(x0)/df(x0)
print("Vi fant rota x = ",x0,"etter",n,"iterasjonar")
Vi fant rota x =  -1.7692923542386314 etter 8 iterasjonar

Merk to ting:

  1. Vi har brukt absoluttverdien av f(x) fordi ellers kan den stoppa på ka som helst negatv verdi for f, og
  2. Vi har no latt n gå heilt til 100. Det er fordi vårt egentlige stoppkriterium no er at f(x) skal vera mindre enn 1e-12 frå null. Dermed er stoppkravet n < 100 bare ein sikkerhet. Husk at det er ikkje alltid at Newtons metode finn eit nullpunkt, og vi vil derfor unngå ei evig løkke!

No er det på tide å skriva opp heile programmet. Det innfører ein del nye ting som vi kommenterer under.

In [6]:
"""
Newtons metode
"""

def f(x):
    return x**3-2*x+2
def df(x):
    return 3*x**2-2

def g(x): #Alternativ funksjon
    return 6*x**5 -5*x**4 -4*x**3 +3*x**2
def dg(x):
    return 30*x**4 -20*x**3 -12*x**2 +6*x


#Definerer funksjonen newtons_metode som tar navnet på den matematiske funksjonen og dens deriverte som input
#Den treng også startverdien, toleransen og ein Boolsk variabel "skriv"     
def newtons_metode(funksjon, derivert, x0, toleranse, skriv=False):
    start = x0 #brukt bare i utskriften
    n = 0

    while abs(funksjon(x0)) > toleranse and n < 100:
        n += 1
        x0 = x0 - funksjon(x0)/derivert(x0)

    if skriv: #Vi testar om skriv er lik True
        print ("Startverdi",start,"gav rota:", x0,"med y-verdi",funksjon(x0))
        print ("Antal iterasjonar:",n)
    return x0

#Her begynnar hovedprogrammet:
startverdiar = [-1, -0.5, 0.1, 0.5, 1.2]    
        
for x0 in startverdiar:
    newtons_metode(f, df, x0, 1e-12, True)
Startverdi -1 gav rota: -1.7692923542386314 med y-verdi 0.0
Antal iterasjonar: 8
Startverdi -0.5 gav rota: 1.0 med y-verdi 1.0
Antal iterasjonar: 100
Startverdi 0.1 gav rota: 0.0 med y-verdi 2.0
Antal iterasjonar: 100
Startverdi 0.5 gav rota: -1.7692923542386314 med y-verdi 0.0
Antal iterasjonar: 9
Startverdi 1.2 gav rota: -1.7692923542386487 med y-verdi -1.2789769243681803e-13
Antal iterasjonar: 29

Det første du sikkert la merke til er at vi også har definert ein ny funksjon g(x), og dens deriverte. Det er fordi vi nedanfor har laga funksjonen newtons_metode, der vi kan gi navnet til funksjonen vår og til den deriverte som input.

Logikken inne i newtons_metode er som før, men vi har bytta ut f(x) med funksjon(x) og df(x) med derivert(x). Disse to variablane vil då visa til enten f(x) og df(x) eller g(x) og dg(x), eller det vi vil. Dermed kan vi finna nullpunkt til den funksjonen som vi måtte foretrekkja.

For å starta funksjonen newtons_metode må vi då nederst kjøra den i hovedprogrammet. Vi skriv feks.: newtons_metode(f, df, x0, 1e-12, True). Det betyr at funksjonen vår er f, den deriverte er df, toleransen er 1e-12, og vi skal ha utskrift (skriv er lik True).

Det siste vi legg merke til er at vi har laga ei liste med startverdiar. Nederst kan vi dermed kjøra newtons_metode i ei løkke som går gjennom alle verdiane i startverdiar og bruker som input-verdien x0.

No kan vi kjøre metoden vår med startverdien -2 og ein litt romsligare toleranse (1e-6), samt setta skriv=False. Det betyr at ingen av dei printsetningane inne i newtons_metode vil bli brukt. Derfor må vi skriva ut svaret eksmplisitt med ein print-setning. Merk at newton_metode har "return x0" som siste statement. Det betyr at vi kan fanga opp dette talet, og her har vi putta det inn i variabelen nullpkt.

In [7]:
nullpkt = newtons_metode(f, df, -2, 1e-6, False)
print("nullpunkt = ",nullpkt)
nullpunkt =  -1.7692923542386998

Til slutt skal vi sjå eit eksempel på at Newtons metode ikkje klarer å finna nullpunktet. Denne gongen gir vi inn x0 = 1.1 og ser kva som skjer.

In [9]:
newtons_metode(f, df, 1.1, 1e-6, True)
Startverdi 1.1 gav rota: 0.0 med y-verdi 2.0
Antal iterasjonar: 100
Out[9]:
0.0

Som vi ser: vi fant ikkje nullpunktet, og algoritmen gjekk derfor derfor heilt til n = 100 før den stoppa.

Oppgaver

  1. Kjør newtons_metode med g som funksjon og dg som derivert. Kva blir svaret / svara?
  2. Prøv ulike verdiar for x0 og toleranse.
  3. Lag din egen funksjon med tilhøyrande derivert og sjå om du kan finna nullpunkt(a)
  4. Prøv funksjonen $x^2+1$. Prøv ulike startverdiar. Kva finn du? Kan du forklara kva som skjer?