6.6. Solutions: Lecture 6#

6.6.1. Exercise 6.1#

  • es_6.1.py

#!/usr/bin/python
'''
Si determini con il metodo della bisezione lo zero della funzione g(x) = cos(x) nell’intervallo (0, 4).
Quali controlli sono stati omessi, nell’implementazione dell’algoritmo descritta nel testo della lezione, 
che potrebbero accelerare il risultato?
'''

from bisezione import bisezione, bisezione_ricorsiva
import sys
from math import cos

def func (x) :
    '''
    Funzione di cui trovare lo zero
    '''
    return cos (x)
    

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def main () :
    '''
    Funzione che implementa il programma principale
    '''
    args = len (sys.argv) - 1
    print ('The name of this script is ' + sys.argv[0])
    print ('Zero della funzione = ', bisezione (func, 0., 4.))
    

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


if __name__ == "__main__":
    main ()
  • bisezione.py

#!/usr/bin/python

def bisezione (
    g,              # funzione di cui trovare lo zero
    xMin,           # minimo dell'intervallo          
    xMax,           # massimo dell'intervallo         
    prec = 0.0001): # precisione della funzione        
    '''
    Funzione che calcola zeri
    con il metodo della bisezione
    '''
    xAve = xMin 
    while ((xMax - xMin) > prec) :
        xAve = 0.5 * (xMax + xMin) 
        if (g (xAve) * g (xMin) > 0.): xMin = xAve 
        else                         : xMax = xAve 
    return xAve 
    

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def bisezione_ricorsiva (
    g,              # funzione di cui trovare lo zero  
    xMin,           # minimo dell'intervallo            
    xMax,           # massimo dell'intervallo          
    prec = 0.0001): # precisione della funzione        
    '''
    Funzione che calcola zeri
    con il metodo della bisezione ricorsivo
    '''
    xAve = 0.5 * (xMax + xMin)
    if ((xMax - xMin) < prec): return xAve ;
    if (g (xAve) * g (xMin) > 0.): return bisezione_ricorsiva (g, xAve, xMax, prec) ;
    else                         : return bisezione_ricorsiva (g, xMin, xAve, prec) ;

6.6.2. Exercise 6.2#

  • es_6.2.py

#!/usr/bin/python
'''
Si svolga l’esercizio precedente utilizzando una funzione ricorsiva.
Quale delle due implementazioni è più rapida?
'''

from bisezione import bisezione, bisezione_ricorsiva
import sys
from math import cos


def func (x) :
    '''
    Funzione di cui trovare lo zero
    '''
    return cos (x)
    

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def main () :
    '''
    Funzione che implementa il programma principale
    '''
    args = len(sys.argv) - 1
    print ('The name of this script is ' + sys.argv[0])
    print ('Zero della funzione = ', bisezione_ricorsiva (func, 0., 4.))
    

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


if __name__ == "__main__":
    main ()

6.6.3. Exercise 6.3#

  • es_6.3.py

#!/usr/bin/python
'''
Si implementi una funzione che calcola il fattoriale di un numero utilizzando una funzione ricorsiva.
'''

import sys


def fattoriale (n):
    '''
    Funzione che calcola il fattoriale
    '''
    if (n == 0): return 1;
    return (n * fattoriale (n-1))
    

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def main () :
    '''
    Funzione che implementa il programma principale
    '''
    args = len(sys.argv) - 1
    num = 6
    if (num < 0) :
        print ('Numero negativo, il fattoriale non è definito')
        exit ()

    print (num, '! = ', fattoriale (num))
    

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


if __name__ == "__main__":
    main ()

6.6.4. Exercise 6.4#

  • es_6.4.py

#!/usr/bin/python
'''
Si determini con il metodo della sezione aurea il minimo 
della funzione g(x) = x2 + 7.3x + 4 nell’intervallo (-10, 10).
'''

import sys
from sez_aurea import sezioneAureaMin


def funz (x) :
    '''
    Funzione di cui trovare l'estremante
    '''
    return x*x + 7.3*x + 4


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def main () :
    '''
    Funzione che implementa il programma principale
    '''

    x_min = - 10.
    x_max = 10.
    risoluzione = 0.0001
  
    print ('Minimo della funzione: ', sezioneAureaMin (funz, x_min, x_max, risoluzione))
  

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


if __name__ == "__main__":
    main ()

  • sez_aurea.py

#!/usr/bin/python

def sezioneAureaMin (
    g,              # funzione di cui trovare lo zero
    x0,             # estremo dell'intervallo          
    x1,             # altro estremo dell'intervallo         
    prec = 0.0001): # precisione della funzione        
    '''
    Funzione che calcola estremanti
    con il metodo della sezione aurea
    '''

    r = 0.618
    x2 = 0.
    x3 = 0. 
    larghezza = abs (x1 - x0)
     
    while (larghezza > prec):
        x2 = x0 + r * (x1 - x0) 
        x3 = x0 + (1. - r) * (x1 - x0)  
      
        # si restringe l'intervallo tenendo fisso uno dei due estremi e spostando l'altro        
        if (g (x3) > g (x2)): 
            x0 = x3
            # x1 = x1  this extreme does not change       
        else :
            x1 = x2
            # x0 = x0  this extreme does not change         
            
        larghezza = abs (x1-x0)             
                                   
    return (x0 + x1) / 2. 


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def sezioneAureaMin_ricorsiva (
    g,              # funzione di cui trovare lo zero
    x0,             # estremo dell'intervallo          
    x1,             # altro estremo dell'intervallo         
    prec = 0.0001): # precisione della funzione        
    '''
    Funzione che calcola estremanti
    con il metodo della sezione aurea
    implementata ricorsivamente
    '''

    r = 0.618
    x2 = x0 + r * (x1 - x0)
    x3 = x0 + (1. - r) * (x1 - x0) 
    larghezza = abs (x1 - x0)

    if (larghezza < prec)  : return ( x0 + x1) / 2.
    elif (g (x3) > g (x2)) : return sezioneAureaMin_ricorsiva (g, x3, x1, prec)
    else                   : return sezioneAureaMin_ricorsiva (g, x0, x2, prec)   


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def sezioneAureaEffMin (
    g,              # funzione di cui trovare lo zero
    x0,             # estremo dell'intervallo          
    x1,             # altro estremo dell'intervallo         
    prec = 0.0001): # precisione della funzione        
    '''
    Funzione che calcola estremanti
    con il metodo della sezione aurea,
    riutilizzando nel ciclo uno dei punti calcolati 
    nell'iterazione precedente
    '''

    r = 0.618
    x2 = x0 + r * (x1 - x0)
    g_x2 = g (x2)
    x3 = 0. 
    larghezza = abs (x1 - x0)
     
    while (larghezza > prec):

        x3 = x0 + (1. - r) * (x1 - x0)
        g_x3 = g (x3)
        # si restringe l'intervallo tenendo fisso uno dei due estremi e spostando l'altro        
        if (g_x3 < g_x2):
            # x0 = x0 this extreme does not change
            x1 = x2
            x2 = x3
            g_x2 = g_x3
        else :
            x0 = x1
            x1 = x3
            # x2 = x2 this point does not change

        larghezza = abs (x1-x0)             
                                   
    return (x0 + x1) / 2. 


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def sezioneAureaEffMin_ricorsiva (
    g,              # funzione di cui trovare lo zero
    x0,             # estremo dell'intervallo          
    x1,             # altro estremo dell'intervallo   
    x2,             # punto intermedio dell'intervallo 
    g_x2,           # valore della funzione g in x2     
    prec = 0.0001): # precisione della funzione        
    '''
    Funzione che calcola estremanti
    con il metodo della sezione aurea
    implementata ricorsivamente,
    riutilizzando nel ciclo uno dei punti calcolati 
    nell'iterazione precedente.
    '''

    r = 0.618
    x3 = x0 + (1. - r) * (x1 - x0) 
    g_x3 = g (x3)
    larghezza = abs (x1 - x0)

    if (larghezza < prec)  : return (x0 + x1) / 2.
    elif g_x3 < g_x2 : return sezioneAureaEffMin_ricorsiva (g, x0, x2, x3, g_x3, prec)
    else             : return sezioneAureaEffMin_ricorsiva (g, x1, x3, x2, g_x2, prec)   


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def sezioneAureaMax (
    g,              # funzione di cui trovare lo zero
    x0,             # estremo dell'intervallo          
    x1,             # altro estremo dell'intervallo         
    prec = 0.0001): # precisione della funzione        
    '''
    Funzione che calcola estremanti
    con il metodo della sezione aurea
    '''

    r = 0.618
    x2 = 0.
    x3 = 0. 
    larghezza = abs (x1 - x0)
     
    while (larghezza > prec):
        x2 = x0 + r * (x1 - x0) 
        x3 = x0 + (1. - r) * (x1 - x0)  
      
        # si restringe l'intervallo tenendo fisso uno dei due estremi e spostando l'altro        
        if (g (x3) < g (x2)): 
            x0 = x3
            # x1 = x1   this extreme does not change      
        else :
            x1 = x2
            # x0 = x0   this extreme does not change
            
        larghezza = abs (x1-x0)             
                                   
    return (x0 + x1) / 2. 


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def sezioneAureaMax_ricorsiva (
    g,              # funzione di cui trovare lo zero
    x0,             # estremo dell'intervallo          
    x1,             # altro estremo dell'intervallo         
    prec = 0.0001): # precisione della funzione        
    '''
    Funzione che calcola estremanti
    con il metodo della sezione aurea
    implementata ricorsivamente
    '''

    r = 0.618
    x2 = x0 + r * (x1 - x0)
    x3 = x0 + (1. - r) * (x1 - x0) 
    larghezza = abs (x1 - x0)

    if (larghezza < prec)  : return ( x0 + x1) / 2.
    elif (g (x3) < g (x2)) : return sezioneAureaMax_ricorsiva (g, x3, x1, prec)
    else                   : return sezioneAureaMax_ricorsiva (g, x0, x2, prec)   

6.6.5. Exercise 6.5#

  • es_6.5.py

#!/usr/bin/python
'''
Si svolga l’esercizio precedente utilizzando una funzione ricorsiva.
Quale delle due implementazioni è più rapida?
'''

import sys
from sez_aurea import sezioneAureaMin, sezioneAureaEffMin, sezioneAureaMin_ricorsiva, sezioneAureaEffMin_ricorsiva



def funz (x) :
    '''
    Funzione di cui trovare l'estremante
    '''
    return x*x + 7.3*x + 4


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def main () :
    '''
    Funzione che implementa il programma principale
    '''

    x_min = - 10.
    x_max = 10.
    risoluzione = 0.0001
  
    print ('Minimo della funzione: ', sezioneAureaMin (funz, x_min, x_max, risoluzione))
    print ('Minimo della funzione: ', sezioneAureaEffMin (funz, x_min, x_max, risoluzione))
    print ('Minimo della funzione: ', sezioneAureaMin_ricorsiva (funz, x_min, x_max, risoluzione))
    x2 = x_min + 0.618 * (x_max - x_min)
    print ('Minimo della funzione: ', sezioneAureaEffMin_ricorsiva (funz, x_min, x_max, x2, risoluzione))
  

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


if __name__ == "__main__":
    main ()

6.6.6. Exercise 6.6#

  • es_6.6.py

#!/usr/bin/python
'''
Si svolgano i due esercizi precedenti cercando il massimo di una funzione a scelta.
'''

import sys
from math import pi, sin
from sez_aurea import sezioneAureaMax, sezioneAureaMax_ricorsiva


def funz (x) :
    '''
    Funzione di cui trovare l'estremante
    '''
    return sin (0.5 * x)


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def main () :
    '''
    Funzione che implementa il programma principale
    '''

    x_min = 0.
    x_max = 2. * pi
    risoluzione = 0.0001
  
    print ('Massimo della funzione: ', sezioneAureaMax (funz, x_min, x_max, risoluzione))
    print ('Massimo della funzione: ', sezioneAureaMax_ricorsiva (funz, x_min, x_max, risoluzione))
  

# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


if __name__ == "__main__":
    main ()

6.6.7. Exercise 6.7#

  • es_6.7.py

#!/usr/bin/python
'''
Modificando i programmi sviluppati precedentemente, 
si disegnino le funzioni studiate ed i punti trovati con i metodi della bisezione e della sezione aurea.
'''

import sys
from math import cos
import matplotlib.pyplot as plt
import numpy as np


def bisezione_mod (
    g,              # funzione di cui trovare lo zero
    xMin,           # minimo dell'intervallo          
    xMax,           # massimo dell'intervallo         
    prec = 0.0001): # precisione della funzione
    '''
    Funzione che calcola zeri
    con il metodo della bisezione,
    ritornando anche la collezione di intervalli considerati
    '''
    extremes = []
    xAve = xMin
    while ((xMax - xMin) > prec) :
        extremes.append ([xMin, xMax])
        xAve = 0.5 * (xMax + xMin) 
        if (g (xAve) * g (xMin) > 0.): xMin = xAve 
        else                         : xMax = xAve 
    return xAve , extremes


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def func (x) :
    '''
    Funzione di cui trovare lo zero
    '''
    return np.cos (x)


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


def main () :
    '''
    Funzione che implementa il programma principale
    '''
    args = len (sys.argv) - 1
    print ('The name of this script is ' + sys.argv[0])
    xMin = 0.
    xMax = 4.
    zero, extremes = bisezione_mod (func, xMin, xMax)
    print ('Zero della funzione = ', zero)

    # creazione dei punti per il disegno della funzione
    x = np.linspace(-5, 5, 1000)
    y = np.cos (x)

    # disegno della funzione
    fig, ax = plt.subplots ()
    ax.plot (x, y, label='f(x)= cos (x)')
    ax.set_title ('il metodo della bisezione', size=14)
    ax.set_xlim (0., 4)
    yMin = -1.5
    yMax = 1.5
    ax.set_ylim (yMin, yMax)
    # disegno di un singolo punto
    # l'opzione "zorder" porta il punto in primo piano
    plt.scatter([zero], [0], color='red', zorder = 5)

    steps = len (extremes)
    yMin_local = yMin
    yMax_local = yMax
    for i in range (len (extremes)):
        ax.add_patch(plt.Rectangle (
                      (extremes[i][0], yMin_local),     # bottom - left vertex coordinates
                       extremes[i][1] - extremes[i][0], # width 
                       yMax_local - yMin_local,         # height
                       edgecolor = 'silver',
                       fill = False,
                     ))
        yMin_local = 0.5 * yMin_local
        yMax_local = 0.5 * yMax_local

    plt.savefig ('es_5.7.png')


# ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- 


if __name__ == "__main__":
    main ()