Vous êtes sur la page 1sur 6

Optimisation des fonctions rcursives e

Universit Montpellier-II - UFR - ULIN201 - Langages Applicatifs e - C. Dony Cours No 7

14
14.1

Simplication de certaines fonctions rcursives e


Rappels sur itrations e

Processus de calcul itratif : processus bas sur une suite de transformation de ltat de lordinateur e e e spci par au moins une boucle et des aectations. e e Aectation Instruction permettant de moer la valeur stocke ` lemplacement mmoire associ au nom de la e a e e variable. x := 12; ;; en Algol, Simula, Pascal (syntaxe classique) x = 12; ;; en C, Java, C++ (set! x 12) ;; en scheme (set! x (+ x 1)) Une structure de contrle pour crire les boucles en Scheme o e (do (initialisation des variables) (condition-darret expression-si-condition-darret-vrifie) e e (instruction 1) ... (instruction n))

14.2

Equivalence itration - rcursions terminales e e

Du point de vue de la quantit despace pile consomm par linterprtation, les deux fonctions suivantes e e e sont quivalentes. e (define (ipgcd a b) (do ((m (modulo a b))) ((= m 0) b) (set! a b) (set! b m) (set! m (modulo a b)))) (define (pgcd a b) (let ((m (modulo a b))) (if (= m 0) b (pgcd b m))))

14.3
14.3.1

Rcursions enveloppes simples : lexemple de factorielle e e


Une version itrative (en C) e

int fact(n){ int cpt = 0; int acc = 1; while (cpt < n){ // acc = fact(cpt) -- invariant de boucle cpt = cpt + 1; acc = acc * cpt; // acc = fact(cpt) -- invariant de boucle } // en sortie de boucle, cpt = n, acc = fact(n) return(acc) } 14.3.2 Une version itrative (en scheme) e

(define (ifact n) (do ((cpt 0) (acc 1)) ;; test darr`t et valeur rendue si le test est #t e ((= cpt n) acc) ;; acc = fact(cpt) -- invariant de boucle (set! cpt (+ cpt 1)) (set! acc (* acc cpt)) ;; acc = fact(cpt) -- invariant de boucle )) 14.3.3 Version rcursive terminale (en scheme) e

Solution gnrale ` la drcursivation : passer le calcul denveloppe (ce quil y a ` faire une fois que e e a ee a lappel rcursif est achv) en argument de lappel rcursif. e e e e Exemple de factorielle : deux param`tres supplmentaire qui vont prendre au l des appels rcursifs les e e e valeurs successives de cpt et acc dans la version itrative. e (define (ifact n cpt acc) ;; acc = fact(cpt) (if (= cpt n) acc (ifact n (+ cpt 1) (* (+ cpt 1) acc)))) Il est ccessaire de raliser lappel initial correctement : (ifact 7 0 1) e e Version plus lgante, qui vite le passage du param`tre n ` chaque appel rcursi et vite le contrle de ee e e a e e o lappel initial.

(define (ifact n) (letrec ((boucle (lambda (cpt acc) ;; acc = fact(cpt) (if (= cpt n) acc (boucle (+ cpt 1) (* (+ cpt 1) acc)))))) (boucle 0 1))) Version encore plus simple o` le compteur est initialis ` n. (multiplication associative donc ordre des u ea multiplications est indirent). e (define (ifact n) (letrec ((boucle (lambda (cpt acc) ;; acc = fact(n-cpt) (if (= cpt 0) acc (boucle (- cpt 1) (* cpt acc)))))) (boucle n 1))) Trouver ce que calcule la fonction interne boucle revient ` trouver linvariant de boucle en programmation a imprative. A chaque tour de boucle, on vrie pour cette version que acc = f act(n cpt). e e

14.4

Recursion vers iteration, le cas des listes

Mmes principes, les oprateurs changent. e e (define (longueur l) (letrec ((boucle (lambda (l1 acc) ;; acc = taille de l - taille de l1 (if (null l1) acc (boucle (cdr l1) (+ 1 acc)))))) (boucle l 0))

14.5

Autres exemples de transformation

Somme des lments dune liste ee Version explicitement itrative : e (define (do-somme-liste l) (do ((l1 l) (acc 0)) ((null l1) acc) (set! accc (+ acc (car l))) (set! l1 (cdr l1)))) Version rcursive terminale : e

(define (isomme-liste l) (define (boucle l acc) (if (null l) acc (boucle (cdr l) (+ (car l) acc)))) (boucle l 0)) Renversement dune liste Version explicitement itrative. e (define (do-reverse l) (do ((current l) (result ())) ((null? l) result) (set! result (cons (car l) result)) (set! l (cdr l)) ;; invariant : result == reverse (initial(l) - current(l)) )) Version rcursive terminale. Laccumulateur est une liste puisque le rsultat doit en tre une. A surveiller e e e le sens dans lequel la liste se construit par rapport ` la version rcursive non terminale. a e (define (ireverse l) (letrec ((boucle (lambda (l acc) (if (null? l) acc (boucle (cdr l) (cons (car l) acc)))))) (boucle l ()))

14.6

Autres amliorations de fonctions rcursives e e

Etude mathmatique ou informatique du probl`me. e e Exemple avec la fonction puissance : amlioration des formules de rcurrence conjugue ` une drcursivation. e e e a ee Version rcursive standard. Cette version ralise n multiplications par x et consomme n blocs de pile. e e (define (puissance x n) (if (= n 0) 1 (* x (puissance x (- n 1))))) Une version rcursive terminale conforme au schma de drcursivation prcdent ncessite toujours e e ee e e e n multiplications par x mais ne consomme plus de pile. (define (puissance-v2 x n) (letrec ((boucle (lambda (cpt acc) ;; puis(x,n-cpt) = acc (if (= cpt 0) acc (boucle (- cpt 1) (* acc x)))))) (boucle n 1))) Une version rcursive dite dichotomique ncessitant moins de multiplications. Elle est base sur la e e e proprit suivante de la fonction puissance : ee si n est pair, m = n/2 et xn = x2m = (x2 )m ,

si n est impair, xn = x2m+1 = x.x2m = x.(x2 )m , (define (puissance-v3 x n) (cond ((= n 0) 1) ((even? n) (puissance-v3 (* x x) (quotient n 2))) ((odd? n) (* x (puissance-v3 (* x x) (quotient n 2)) Cette version1 nest pas rcursive terminale quand n est impair, par contre elle neectue plus que de e lordre de log(n) multiplications. Couplage des deux amliorations e Une version itrative de la fonction puissance dichotomique suppose ` nouveau le passage par un e a accumulateur pass en param`tre. e e (define (puissance-v4 x n) (letrec ((boucle (lambda (x n acc) (cond ((= n 0) acc) ((even? n) (boucle (* x x) (quotient n 2) acc)) ((odd? n) (boucle (* x x) (quotient n 2) (* x acc))))))) (boucle x n 1)))

14.7
14.7.1

Transformation des rcursions arborescentes - Lexemple de bonacci. e


Solution gnrale e e

Dune faon gnrale, les rcursions arborescentes peuvent tre transformes en itrations en passant en c e e e e e e param`tre la continuation. e Continuation : pour un calcul donn, nom donn ` ce qui doit tre fait avec son rsultat. e ea e e Exemple : avec la fonction factorielle, la continuation de lappel rcursif est une multiplication par n. e Pour bonacci, apr`s le premier appel rcursif qui donne un rsultat acc1, il y a un autre appel rcursif e e e e a e ` raliser qui donnera un rsultat r2 et apr`s le second appel rcursif il y a une addition des deux. e e e Le CPS (Continuation passing style) est une gnralisation de la rsorbtion des enveloppes. Avec le CPS, e e e on passe en argument ` lappel rcursif, la continuation du calcul. Pour b, lappel rcursif est terminal et a e e on passe en argument la fonction qui devra tre xcute une fois la valeur trouve. Lutilisation de ce style e e e e e en toute gnralit suppose de pouvoir passer des fonctions en arguments. e e e (define (k-fib n k) ; la continuation est appelee k (cond ((= n 0) (k 0)) ; application de la continuation au resultat ((= n 1) (k 1)) ; application de la continuation au resultat (#t (k-fib (- n 1) (lambda (acc1) ; explicitation de la continuation (k-fib (- n 2) ; sous forme dune fonction (lambda (acc2) (k (+ acc1 acc2))))))))) Cette version est uniquement intressante en thorie. Elle ne consomme pas de pile mais son excution e e e est pourtant encore plus longue que celle de b standard parce que : on eectue le mme nombre daddition que dans la version standard e la consommation mmoire en pile est remplace par une consommation mmoire encore plus grande e e e en code des fonctions intermdiaires. Pour sen convaincre on peut imprimer k en dbut de fonction e e k-b.
1

Attention, utiliser quotient plutt que / car quotient rend un entier compatible avec les fonctions even et odd. o

14.7.2

Une solution en 0(n) : la mmoization e

Memoization : Du latin memorandum. In computing, memoization is an optimization technique used primarily to speed up computer programs by storing the results of function calls for later reuse, rather than recomputing them at each invocation of the function - Wikipedia (define (memo-fib n) (define (val n memoire) (cadr (assq n memoire))) (define (memo n memoire) ;; rend une liste dans laquelle la valeur de fib(n) est stocke e (let ((dejaCalcule (assq n memoire))) (if dejaCalcule memoire (let ((memoire (memo (- n 1) memoire))) (let ((memoire (memo (- n 2) memoire))) (let ((fibn (+ (val (- n 1) memoire) (val (- n 2) memoire)))) ;; on ajoute ` la liste memoire la derni`re valeur calcule et on la rend a e e (cons (list n fibn) memoire))))))) (val n (memo n ((1 1) (0 0))))) 14.7.3 Une version itrative de b en O(n) e

Transformation du probl`me : utiliser des variables ou la pile dexcution pour conserver en mmoire les e e e deux derni`res valeurs qui sont susantes pour calculer la suivante. e Observons les valeurs successives de deux suites : an = an1 + bn1 avec a0 = 1 et bn = an1 avec b0 = 0 On note que pour tout n, bn = f ib(n). On en dduit la fonction rcursive terminale suivante : e e (define (ifib n a b) (if (= n 0) b (ifib (- n 1) (+ a b) a))) ou (define (ifib n) (letrec ((boucle (lambda (cpt a b) (if (= cpt n) b (boucle (+ cpt 1) (+ a b) a))))))) (boucle 0 1 0)))

Vous aimerez peut-être aussi