diff --git a/td/lifpf-td2-correction.pdf b/td/lifpf-td2-correction.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..76adc698deda312b494ae20dcad36360876d295c
Binary files /dev/null and b/td/lifpf-td2-correction.pdf differ
diff --git a/td/lifpf-td3-correction.pdf b/td/lifpf-td3-correction.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..3a06b3161c647cf0411c3c374f3a1461b7bde27a
Binary files /dev/null and b/td/lifpf-td3-correction.pdf differ
diff --git a/td/lifpf-td4-correction.pdf b/td/lifpf-td4-correction.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..60243a514d43edf76c38532b851e5aabf580fd09
Binary files /dev/null and b/td/lifpf-td4-correction.pdf differ
diff --git a/tp/tp3.ml b/tp/tp3.ml
new file mode 100644
index 0000000000000000000000000000000000000000..7599c79c9c140802121dd6c1eb4e794553a41325
--- /dev/null
+++ b/tp/tp3.ml
@@ -0,0 +1,214 @@
+(* LIFPF TP3 Récursion sur les arbres *)
+
+(**********************************************************************)
+(* Arbres binaires *)
+(**********************************************************************)
+
+(**
+Arbres binaires avec feuilles vides, 
+le contenu est seulement sur les noeuds.    
+*)
+type arbre_bin = ABVide | ABNoeud of int * arbre_bin * arbre_bin
+
+(* Quelques arbres pour tester *)
+let ab1 = ABNoeud (3, ABVide, ABVide)
+let ab2 = ABNoeud (5, ab1, ABVide)
+let ab3 = ABNoeud (7, ABVide, ab1)
+let ab4 = ABNoeud (11, ab2, ab3)
+
+(**
+Taille d'un arbre binaire.
+@param a l'arbre dont on veut calculer la taille
+@return le nombre d'int stockés dans l'arbre
+*)
+let rec taille_ab (a : arbre_bin) : int =
+  match a with
+  | ABVide -> 0
+  | ABNoeud (_, fg, fd) -> 1 + taille_ab fg + taille_ab fd
+;;
+
+assert (taille_ab ab1 = 1);;
+assert (taille_ab ab2 = 2);;
+assert (taille_ab ab3 = 2);;
+assert (taille_ab ab4 = 5)
+
+(**
+Fait le produit des éléments d'un arbre binaire.
+Un arbre vide aura 1 comme produit   
+@param a l'arbre dont on veut faire le produit des éléments
+@return le produit (1 pour l'arbre vide)
+*)
+let rec produit_ab (a : arbre_bin) : int =
+  match a with
+  | ABVide -> 1
+  | ABNoeud (n, fg, fd) -> n * produit_ab fg * produit_ab fd
+;;
+
+assert (produit_ab ABVide = 1);;
+assert (produit_ab ab1 = 3);;
+assert (produit_ab ab2 = 15);;
+assert (produit_ab ab3 = 21);;
+assert (produit_ab ab4 = 3465)
+
+(**
+Construit la liste des éléments d'un arbre binaire. Les éléments sont produits
+dans l'ordre de parcours infix, c'est à dire les éléments du fils gauche puis
+l'élément du noeud puis ceux fils droit.
+
+@param a l'arbre binaire dont on veut les éléments 
+@return la liste des éléments de l'arbre
+*)
+let rec list_of_arbre_bin (a : arbre_bin) : int list =
+  match a with
+  | ABVide -> []
+  | ABNoeud (n, fg, fd) ->
+      (* On peut aussi utiliser la fonction concatene du TP2 *)
+      list_of_arbre_bin fg @ (n :: list_of_arbre_bin fd)
+;;
+
+assert (list_of_arbre_bin ABVide = []);;
+assert (list_of_arbre_bin ab1 = [ 3 ]);;
+assert (list_of_arbre_bin ab2 = [ 3; 5 ]);;
+assert (list_of_arbre_bin ab3 = [ 7; 3 ]);;
+assert (list_of_arbre_bin ab4 = [ 3; 5; 11; 7; 3 ])
+
+(**
+Insère un élément dans un arbre binaire de recherche.
+
+@param e l'élément à insérer
+@param a l'arbre dans lequel on fait l'insersion
+@return un arbre binaire de recherche contenant les éléments de a ainsi que e
+*)
+let rec insere_arbre_bin_recherche (e : int) (a : arbre_bin) : arbre_bin =
+  match a with
+  | ABVide -> ABNoeud (e, ABVide, ABVide)
+  | ABNoeud (x, fg, fd) ->
+      if e < x then ABNoeud (x, insere_arbre_bin_recherche e fg, fd)
+      else ABNoeud (x, fg, insere_arbre_bin_recherche e fd)
+
+let abr1 = insere_arbre_bin_recherche 7 ABVide
+let abr2 = insere_arbre_bin_recherche 5 abr1
+let abr3 = insere_arbre_bin_recherche 3 abr2
+let abr4 = insere_arbre_bin_recherche 11 abr3;;
+
+assert (list_of_arbre_bin abr1 = [ 7 ]);;
+assert (list_of_arbre_bin abr2 = [ 5; 7 ]);;
+assert (list_of_arbre_bin abr3 = [ 3; 5; 7 ]);;
+assert (list_of_arbre_bin abr4 = [ 3; 5; 7; 11 ])
+
+(**
+Créée un arbre binaire de recherche contenant les éléments de la liste
+
+@param l la liste contenant les éléments à placer dans l'arbre à créer
+@return l'arbre binaire de recherche contenant les éléments de l
+*)
+let rec arbre_bin_rech_of_int_list (l : int list) : arbre_bin =
+  match l with
+  | [] -> ABVide
+  | x :: l' -> insere_arbre_bin_recherche x (arbre_bin_rech_of_int_list l')
+;;
+
+assert (list_of_arbre_bin (arbre_bin_rech_of_int_list []) = []);;
+assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 3 ]) = [ 3 ]);;
+assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 3; 5 ]) = [ 3; 5 ]);;
+assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 5; 3 ]) = [ 3; 5 ]);;
+
+assert (
+  list_of_arbre_bin (arbre_bin_rech_of_int_list [ 1; 2; 3; 4 ]) = [ 1; 2; 3; 4 ])
+;;
+
+assert (
+  list_of_arbre_bin (arbre_bin_rech_of_int_list [ 4; 2; 1; 3 ]) = [ 1; 2; 3; 4 ])
+
+(**
+Trie une list d'int en utilisant un arbre binaire de recherche
+
+@param l la liste à trier
+@return la liste triée
+*)
+let tri_abr (l : int list) : int list =
+  list_of_arbre_bin (arbre_bin_rech_of_int_list l)
+;;
+
+assert (tri_abr [] = []);;
+assert (tri_abr [ 3 ] = [ 3 ]);;
+assert (tri_abr [ 3; 5 ] = [ 3; 5 ]);;
+assert (tri_abr [ 5; 3 ] = [ 3; 5 ]);;
+assert (tri_abr [ 1; 2; 3; 4 ] = [ 1; 2; 3; 4 ]);;
+assert (tri_abr [ 4; 2; 1; 3 ] = [ 1; 2; 3; 4 ])
+
+(**********************************************************************)
+(* Expressions arithmétiques et variables *)
+(**********************************************************************)
+
+(**
+Type représentant les opérateurs binaires.    
+*)
+type binop = Plus | Moins | Mult | Div
+
+(**
+Expressions arithmétiques + let    
+*)
+type expr =
+  | Cst of int
+  | Binop of binop * expr * expr
+  | Var of string
+  | Let of string * expr * expr
+
+(** affichage **)
+let rec string_of_expr (e : expr) : string =
+  let string_of_binop (b : binop) =
+    match b with Plus -> " + " | Moins -> " - " | Mult -> " * " | Div -> " / "
+  in
+
+  match e with
+  | Cst n -> string_of_int n
+  | Binop (op, l, r) ->
+      "(" ^ string_of_expr l ^ string_of_binop op ^ string_of_expr r ^ ")"
+  | Var x -> x
+  | Let (v, e1, e2) ->
+      "(let " ^ v ^ " = " ^ string_of_expr e1 ^ " in " ^ string_of_expr e2 ^ ")"
+
+(** Erreurs *)
+type eval_err = DivZero | VarNonDef
+
+(** Résultats: int ou erreur *)
+type resultat = Ok of int | Err of eval_err
+
+(**
+Évalue une expression dans un environnement
+*)
+let rec eval_expr (e : expr) (env : (string * int) list) : resultat =
+  match e with
+  | Cst n -> Ok n
+  | Binop (op, e1, e2) -> (
+      match (eval_expr e1 env, eval_expr e2 env) with
+      | Ok v1, Ok v2 -> (
+          match op with
+          | Plus -> Ok (v1 + v2)
+          | Moins -> Ok (v1 - v2)
+          | Mult -> Ok (v1 * v2)
+          | Div -> if v2 = 0 then Err DivZero else Ok (v1 / v2))
+      | Err e, _ -> Err e
+      | _, Err e -> Err e)
+  | Var x -> (
+      match List.assoc_opt x env with None -> Err VarNonDef | Some n -> Ok n)
+  | Let (x, e1, e2) -> (
+      match eval_expr e1 env with
+      | Ok v1 -> eval_expr e2 ((x, v1) :: env)
+      | Err e -> Err e)
+
+let e1 = Cst 3
+let e2 = Binop (Plus, Cst 3, Cst 5)
+let e3 = Binop (Div, Cst 3, Cst 0)
+let e4 = Let ("a", Cst 3, Binop (Moins, Var "a", Cst 3))
+let e5 = Let ("a", Cst 3, Var "b");;
+
+assert (eval_expr e1 [] = Ok 3);;
+assert (eval_expr e2 [] = Ok 8);;
+assert (eval_expr e3 [] = Err DivZero);;
+assert (eval_expr e4 [] = Ok 0);;
+assert (eval_expr e5 [] = Err VarNonDef);;
+assert (eval_expr e5 [ ("b", 11) ] = Ok 11)
+
+(**********************************************************************)
diff --git a/tp/tp4.ml b/tp/tp4.ml
new file mode 100644
index 0000000000000000000000000000000000000000..2bf80016a6015e5717e65c667ccd4bd3365ca77b
--- /dev/null
+++ b/tp/tp4.ml
@@ -0,0 +1,240 @@
+(**********************************************************************)
+(* Arbres n-aires *)
+(**********************************************************************)
+(** Arbre avec un nombre quelconque de fils *)
+type 'a arbre_n = Feuille of 'a | Noeud of 'a arbre_n list
+
+let a1 = Feuille 1
+let a2 = Feuille 2
+let a3 = Noeud []
+let a4 = Noeud [ a1 ]
+let a5 = Noeud [ a1; a2 ]
+let a6 = Noeud [ a1; a2; a3; a4; a5 ]
+let a_vide_1 = Noeud []
+let a_vide_2 = Noeud [ Noeud [] ]
+(* Le type de ces arbres vide est 'a arbre_n. En effet, comme ces arbres ne
+   contiennent pas d'éléments ils peuvent être vus comme des arbresavec ce qu'on
+   veut comme type d'élément. *)
+
+let rec hauteur (a : 'a arbre_n) : int =
+  match a with Feuille _ -> 1 | Noeud l -> hauteur_foret l + 1
+
+and hauteur_foret (l : 'arbre_n list) : int =
+  match l with
+  | [] -> 0
+  | a :: l' -> max (hauteur a) (hauteur_foret l')
+;;
+
+assert (hauteur a1 = 1);;
+assert (hauteur a3 = 1);;
+assert (hauteur a4 = 2);;
+assert (hauteur a5 = 2);;
+assert (hauteur a6 = 3)
+
+(**
+Renvoie une liste contenant tous les éléments de l'arbre
+
+@param a: l'arbre
+@return la liste de ses éléments
+*)
+let list_of_arbre (a : 'a arbre_n) : 'a list =
+  let rec list_of_arbre_aux (a : 'a arbre_n) (acc : 'a list) : 'a list
+      =
+    match a with
+    | Feuille x -> x :: acc
+    | Noeud f -> list_of_foret f acc
+  and list_of_foret (f : 'a arbre_n list) (acc : 'a list) : 'a list =
+    match f with
+    | [] -> acc
+    | a :: f' -> list_of_arbre_aux a (list_of_foret f' acc)
+  in
+  list_of_arbre_aux a []
+;;
+
+assert (list_of_arbre a1 = [ 1 ]);;
+assert (list_of_arbre a4 = [ 1 ]);;
+assert (list_of_arbre a5 = [ 1; 2 ]);;
+assert (list_of_arbre a6 = [ 1; 2; 1; 1; 2 ])
+
+(**
+[minimum arbre] est le plus grand élément de arbre si arbre en contient au moins 1.
+
+@param arbre l'arbre dans lequel on cherche le minimum
+@return None si l'arbre ne contient pas d'élément, ou sinon Some m avec m le plus petit élément de l'arbre 
+*)
+let rec minimum (arbre : 'a arbre_n) : 'a option =
+  match arbre with
+  | Feuille x -> Some x
+  | Noeud la -> minimum_foret la
+
+(**
+[minimum_foret l] donne l'élément minimal que l'on peut trouver dans une forêt
+
+@param l la forêt
+@return None si la forêt ne contient pas d'élément ou sinon Some m où m est le plus petit élément de la forêt
+*)
+and minimum_foret (la : 'a arbre_n list) : 'a option =
+  match la with
+  | [] -> None
+  | a :: la' -> (
+      match minimum_foret la' with
+      | None -> minimum a
+      | Some n -> (
+          match minimum a with
+          | None -> Some n
+          | Some n' -> Some (min n n')))
+;;
+
+assert (minimum a1 = Some 1);;
+assert (minimum a3 = None);;
+assert (minimum a4 = Some 1);;
+assert (minimum a5 = Some 1);;
+assert (minimum a6 = Some 1)
+
+(**
+[reduce f a] renvoie:
+- None si a ne contient aucun élément
+- Some x si a contient un seul élément x
+- Some x où x est le résultat de la combinaison des éléments de a en utilisant f
+
+@param f la fonction de combinaison des éléments
+@param a l'arbre qui contient les éléments
+*)
+let rec reduce (f : 'a -> 'a -> 'a) (arbre : 'a arbre_n) : 'a option =
+  match arbre with Feuille x -> Some x | Noeud l -> reduce_foret f l
+
+(**
+[reduce_foret f l] renvoie:
+- None si l (en tant que forêt) ne contient aucun élément
+- Some x si l contient un seul élément x
+- Some x où x est le résultat de la combinaison des éléments de l en utilisant f
+
+@param f la fonction de combinaison des éléments
+@param la forêt qui contient les éléments
+*)
+and reduce_foret (f : 'a -> 'a -> 'a) (la : 'a arbre_n list) :
+    'a option =
+  match la with
+  | [] -> None
+  | a :: la' -> (
+      match reduce_foret f la' with
+      | None -> reduce f a
+      | Some n -> (
+          match reduce f a with
+          | None -> Some n
+          | Some n' -> Some (f n n')))
+;;
+
+assert (reduce min a1 = Some 1);;
+assert (reduce min a3 = None);;
+assert (reduce min a4 = Some 1);;
+assert (reduce min a5 = Some 1);;
+assert (reduce min a6 = Some 1);;
+assert (reduce ( + ) a1 = Some 1);;
+assert (reduce ( + ) a3 = None);;
+assert (reduce ( + ) a5 = Some 3);;
+assert (reduce ( + ) a6 = Some 7)
+
+(**********************************************************************)
+(* Files (FIFO) implémentées avec deux listes *)
+(**********************************************************************)
+
+type 'a fifo = Fifo of ('a list * 'a list)
+
+(** File vide *)
+let empty_fifo : 'a fifo = Fifo ([], [])
+
+(**
+[push_fifo e f] Ajoute e dans f
+
+@param e l'élément a ajouter
+@param f la fifo dans laquelle on veut ajouter l'élément
+@return la fifo contenant les éléments de f puis e
+*)
+let push_fifo (e : 'a) (f : 'a fifo) : 'a fifo =
+  match f with Fifo (l1, l2) -> Fifo (e :: l1, l2)
+
+let f1 = push_fifo 1 empty_fifo
+let f2 = push_fifo 2 f1
+let f3 = push_fifo 3 f2
+let f4 = push_fifo 4 f3;;
+
+assert (f1 = Fifo ([ 1 ], []));;
+assert (f2 = Fifo ([ 2; 1 ], []));;
+assert (f3 = Fifo ([ 3; 2; 1 ], []));;
+assert (f4 = Fifo ([ 4; 3; 2; 1 ], []))
+
+(**
+[push_list_fifo l f] ajoute les éléments de l à la file f
+
+@param l les éléments à ajouter
+@param f la file dans laquelle ajouter les éléments
+@return la file contenant les éléments de f puis les éléments de l
+*)
+let rec push_list_fifo (l : 'a list) (f : 'a fifo) : 'a fifo =
+  match l with
+  | [] -> f
+  | x :: l' -> push_list_fifo l' (push_fifo x f)
+;;
+
+assert (push_list_fifo [] empty_fifo = empty_fifo);;
+assert (push_list_fifo [] f2 = f2);;
+assert (push_list_fifo [ 1 ] empty_fifo = f1);;
+assert (push_list_fifo [ 3; 4 ] f2 = f4);;
+assert (push_list_fifo [ 1; 2; 3; 4 ] empty_fifo = f4)
+
+(**
+Fonction utilitaire transférant tous les éléments de la liste de gauche dans
+celle de droite en en renversant l'ordre au passage.
+*)
+let rec transfert_fifo (f : 'a fifo) : 'a fifo =
+  match f with
+  | Fifo ([], l2) -> Fifo ([], l2)
+  | Fifo (x :: l1, l2) -> transfert_fifo (Fifo (l1, x :: l2))
+;;
+
+assert (transfert_fifo f4 = Fifo ([], [ 1; 2; 3; 4 ]));;
+assert (transfert_fifo f1 = Fifo ([], [ 1 ]))
+
+(**
+[pop_fifo f] renvoie le premier élément de f s'il y en a un, ainsi que la file contenant le reste des éléments de f.
+
+@param f la file dans laquelle on veut prendre un élément
+@return (f',r) où
+- f' est la file contenant les éléments de f sauf le premier
+- r est Some x si f a pour premier élément x ou bien None si f est vide
+*)
+let pop_fifo (f : 'a fifo) : 'a fifo * 'a option =
+  match f with
+  | Fifo (l1, []) -> (
+      match transfert_fifo f with
+      | Fifo (_, []) -> (Fifo ([], []), None)
+      | Fifo (_, x :: l2') -> (Fifo ([], l2'), Some x))
+  | Fifo (l1, x :: l2') -> (Fifo (l1, l2'), Some x)
+;;
+
+assert (pop_fifo empty_fifo = (empty_fifo, None));;
+assert (pop_fifo f1 = (empty_fifo, Some 1));;
+assert (pop_fifo f2 = (Fifo ([], [ 2 ]), Some 1));;
+assert (pop_fifo (fst (pop_fifo f2)) = (empty_fifo, Some 2))
+
+(**
+Renvoie tous les éléments de la file dans l'ordre de celle-ci
+
+@param f la file dont on veut les éléments
+@return une liste contenant les éléments de f dans l'ordre
+*)
+let rec pop_all_fifo (f : 'a fifo) : 'a list =
+  match pop_fifo f with
+  | _, None -> []
+  | f', Some x -> x :: pop_all_fifo f'
+;;
+
+assert (pop_all_fifo empty_fifo = []);;
+assert (pop_all_fifo f1 = [ 1 ]);;
+assert (pop_all_fifo f4 = [ 1; 2; 3; 4 ]);;
+
+(* Un test mélangeant les opérations de push et de pop de la file *)
+assert (
+  pop_all_fifo (push_list_fifo [ 3; 4 ] (fst (pop_fifo f2)))
+  = [ 2; 3; 4 ])