décompositions d'un entier ; partitions d'un entier et algorithme RSK ; entrées-sorties des lambda-termes et termes de de Bruijn ; lambda-calcul
Retour à la page générale de La lettre de Caml.
let rec décompose_1 = function | 0 -> [] | 1 -> [[1]] | n -> let res = ref [] in for k = 1 to n - 1 do do_list (function l -> res := (k :: l) :: !res) (décompose_1 (n - k)) done ; [n] :: !res ;; let rec décompose_2 n = let rec décompose_rec n accu = function | 0 -> accu | k -> let ll = décompose (n - k) in décompose_rec n ((map (function l -> k :: l) ll) @ accu) (k - 1) in match n with | 0 -> [] | 1 -> [ [1] ] | n -> décompose_rec n [ [n] ] (n - 1) ;; let rec décompose n = let rec gonfle_accu k ll accu = match ll with | [] -> accu | t :: q -> gonfle_accu k q ((k :: t) :: accu) in let rec décompose_rec n accu = function | 0 -> accu | k -> let ll = décompose (n - k) in décompose_rec n (gonfle_accu k ll accu) (k - 1) in match n with | 0 -> [] | 1 -> [ [1] ] | n -> décompose_rec n [ [n] ] (n - 1) ;;
#open "format" ;; (* l'impression sous forme de tableau *) let print_partition p = let rec make_bullets = function | 0 -> "" | n -> "· " ^ (make_bullets (n - 1)) in let print_n_stars n = ( print_string (make_bullets n) ; print_break(0,0) ) in open_vbox 0 ; do_list print_n_stars p ; close_box () ;; install_printer "print_partition" ;; (* la partition 3.2.2.1 |- 8 *) (* est représentée par la liste [ 3 ; 2 ; 2 ; 1 ] *) let somme = it_list (prefix +) 0 ;; let transpose p = let nb_de_plus_grands k liste = it_list (fun n x -> if x >= k then n + 1 else n) 0 liste in let rec intervalle i j = if i > j then [] else i :: (intervalle (i+1) j) in map (function x -> nb_de_plus_grands x p) (intervalle 1 (hd p)) ;; let exemple = [ 3 ; 2 ; 2 ; 1 ] ;; exemple ;; (transpose exemple) ;; (transpose (transpose exemple)) ;; (* une décomposition de n est une liste de somme n, tout simplement *) let partition_de_décomposition = sort__sort (prefix >=) ;; (* je représente -- basiquement -- une permutation de n objets *) (* par un vecteur des n éléments 0, 1, ..., n-1 *) let applique_permutation sigma k = sigma.(k) (* calcule sigma(k) *) and inverse_permutation sigma = let n = vect_length sigma in let res = make_vect n 0 in for i = 0 to n-1 do res.(sigma.(i)) <- i done ; res and compose_permutations s1 s2 = (* calcule évidemment s1 o s2 *) let n = vect_length s1 in let res = make_vect n 0 in for i = 0 to n-1 do res.(i) <- s1.(s2.(i)) done ; res ;; let partition_de_permutation sigma = let n = vect_length sigma and partition = ref [] in let coches = make_vect n false in for i = 0 to n-1 do if not coches.(i) then let j = ref i and longueur = ref 0 in while not coches.(!j) do coches.(!j) <- true ; incr longueur ; j := sigma.(!j) done ; partition := !longueur :: !partition done ; partition_de_décomposition !partition ;; (* --------- génération des partitions ------------- *) let rec intervalle i j = if i > j then [] else i :: (intervalle (i+1) j) ;; let partitions n = let cons a b = a :: b in let rec aux n k = if k > n then aux n n else if k = 0 && n = 0 then [[]] (* fin normale de récursion *) else if k = 0 then [] (* pas de solution ici ! *) else it_list (fun l j -> map (cons j) (aux (n-j) j) @ l) [] (intervalle 1 k) in aux n n ;; let partitions_sans_répétition n = let cons a b = a :: b in let rec aux n k = if k > n then aux n n else if k = 0 && n = 0 then [[]] else if k = 0 then [] else it_list (fun l j -> map (cons j) (aux (n-j) (j-1)) @ l) [] (intervalle 1 k) in aux n n ;; (* ----- manipulation des partitions sans répétition ---- *) let rec last = function | [] -> failwith "last" | [a] -> a | t :: q -> last q ;; let taille_base = last ;; let rec taille_flanc = function | [] -> 0 | a :: b :: q when a = b + 1 -> 1 + (taille_flanc (b :: q)) | _ -> 1 ;; let intersection_BF l = (taille_flanc l) = (list_length l) ;; type manipulation = BF | FB | NOP ;; let que_faire l = let tf = taille_flanc l and tb = taille_base l and n = list_length l in if (n = tf) && ( (tb = tf) || (tb = 1 + tf)) then NOP else if tf >= tb then BF else FB ;; let rec équeute = function (* détruit le dernier élément d'une liste *) | [] -> failwith "équeute" | [a] -> [] | t :: q -> t :: (équeute q) ;; let rec map_borné f k = function | [] -> [] | t :: q when k > 0 -> (f t) :: (map_borné f (k - 1) q) | l -> l ;; let manipule l = match que_faire l with | NOP -> l | BF -> équeute (map_borné succ (taille_base l) l) | FB -> (map_borné pred (taille_flanc l) l) @ [ taille_flanc l ] ;; exception Stop ;; let even n = (n mod 2) = 0 and odd n = (n mod 2) = 1 ;; let rec nb_de_partitions_naïf n = if n < 0 then 0 else if n < 2 then 1 else let résultat = ref 0 and k = ref 1 in try while true do let k1 = (!k * (3 * !k - 1)) / 2 and k2 = (!k * (3 * !k + 1)) / 2 in if k1 > n then raise Stop ; if even(!k) then résultat := !résultat - (nb_de_partitions_naïf (n - k1)) - (nb_de_partitions_naïf (n - k2)) else résultat := !résultat + (nb_de_partitions_naïf (n - k1)) + (nb_de_partitions_naïf (n - k2)) ; incr k done ; 0 with Stop -> !résultat ;; let nb_de_partitions = let mémoire = ref [ (0,1) ; (1,1) ; (2,2) ] in let rec f n = if n < 0 then 0 else try assoc n !mémoire with Not_found -> let résultat = ref 0 and k = ref 1 in try while true do let k1 = !k * (3 * !k - 1) / 2 and k2 = !k * (3 * !k + 1) / 2 in if k1 > n then raise Stop ; if even(!k) then résultat := !résultat - (f (n - k1)) - (f (n - k2)) else résultat := !résultat + (f (n - k1)) + (f (n - k2)) ; incr k done ; 0 with Stop -> ( mémoire := (n,!résultat) :: !mémoire ; !résultat ) in f ;; let iota n = let rec aux a b k = if k = n then a else aux b (b + (k + 1)*a) (k + 1) in aux 1 1 0 ;; (* ----- algorithme RSK direct ------ *) let RSK_direct sigma = let n = vect_length sigma in let rec substitue k a dl el = match dl,el with | [],[] -> [a],[k],None | (td::qd),(te::qe) when td < a -> let qd',qe',suite = substitue k a qd qe in (td::qd'),(te::qe'),suite | (td::qd),_ -> (a::qd),el,Some(td) | _ -> failwith "bug" in let rec insertion k a_k (d,e) = match d,e with | [],[] -> ([[a_k]],[[k]]) | (dl :: dq),(el :: eq) -> ( match substitue k a_k dl el with | dl',el',None -> (dl'::dq),(el'::eq) | dl',el',Some(a) -> let dq',eq' = insertion k a (dq,eq) in (dl'::dq'),(el'::eq') ) | _ -> failwith "bug" in it_list (fun (d,e) k -> insertion k sigma.(k) (d,e)) ([],[]) (intervalle 0 (n-1)) ;; (* ----- algorithme RSK inverse ------ *) let RSK_inverse (d,e) = let dv = vect_of_list d and ev = vect_of_list e and n = it_list (fun x l -> x + (list_length l)) 0 d in let sigma = make_vect n 0 in let cherche k = let rec aux i = if last ev.(i) = k then let a = last dv.(i) in dv.(i) <- équeute dv.(i) ; ev.(i) <- équeute ev.(i) ; (i,a) else aux (i+1) in aux 0 in let rec substitue l a = match l with | [ x ] -> [a],x | x :: y :: q when y > a -> (a::y::q),x | x :: q -> let q',a = substitue q a in (x::q'),a | _ -> failwith "bug" in let rec remonte i a = match i,(substitue dv.(i) a) with | 0,(l,a) -> dv.(i) <- l ; a | _,(l,a) -> dv.(i) <- l ; remonte (i-1) a in let calcule k = match cherche k with | 0,a -> sigma.(k) <- a | i,a -> sigma.(k) <- remonte (i-1) a in for k = n-1 downto 0 do calcule k done ; sigma ;;
type lambda_terme = | Variable of string | Application of lambda_terme * lambda_terme | Abstraction of string * lambda_terme ;; type lexème = ParG | ParD | Flèche | Identificateur of string ;; let string_of_char_list l = let s = make_string (list_length l) `.` in let rec construit i = function | [] -> s | t :: q -> s.[i] <- t ; construit (i+1) q in construit 0 l;; let mange flot c = let rec accumule () = try let c,_ = stream_get flot in if c == ` ` || c == `)` then [] else ( stream_next flot ; c :: (accumule ()) ) with Parse_failure -> [] in string_of_char_list (c :: accumule ()) ;; let rec fin_ligne flot = match flot with | [< '`\n` >] -> [< flot >] | [< 'c >] -> fin_ligne flot ;; let rec lexeur flot = match flot with | [< '(` ` | `\r` | `\n`) >] -> lexeur flot | [< '`%` >] -> lexeur (fin_ligne flot) | [< '`(` >] -> ParG :: (lexeur flot) | [< '`)` >] -> ParD :: (lexeur flot) | [< '`-` >] -> ( match flot with | [< '`>` >] -> Flèche :: (lexeur flot) | [< >] -> let u = Identificateur(mange flot `-`) in u :: (lexeur flot) ) | [< 'c >] -> let u = Identificateur(mange flot c) in u :: (lexeur flot) | [< >] -> [] ;; let rec parse_terme lex_list = let r,_ = parse_T lex_list in r and parse_T lex_list = match lex_list with | (Identificateur v) :: Flèche :: q -> let t,q = parse_T q in Abstraction(v,t),q | _ -> parse_E lex_list and parse_E lex_list = let f,q = parse_F lex_list in parse_E' f q and parse_E' f = function | (ParD :: _) as lex_list -> f,lex_list | [] -> f,[] | lex_list -> let f',q = parse_F lex_list in parse_E' (Application(f,f')) q and parse_F = function | (Identificateur v) :: q -> Variable(v),q | ParG :: q -> let t,q = parse_T q in match q with | ParD :: q -> t,q | _ -> failwith "Erreur de syntaxe" ;; let parseur chaîne = parse_terme (lexeur (stream_of_string chaîne)) ;; #open "format" ;; let print_lambda_terme e = let ps = print_string and pc = print_char and space = print_space and open() = open_hovbox 3 and close = close_box in let rec print e p = open() ; if p then pc `(` ; ( match e with | Variable(v) -> ps v | Abstraction(x,u) -> ps x ; space() ; ps "->" ; space() ; print u false | Application(g,d) -> let pg,pd = match g,d with | Variable(_),Abstraction(_) -> false,true | Variable(_),_ -> false,false | Application(_),Variable(_) -> false,false | Abstraction(_),Variable(_) -> true,false | _ -> true,true in print g pg ; space() ; print d pd ) ; if p then pc `)` ; close() in print e false ; print_newline () ;; install_printer "print_lambda_terme" ;; type terme_de_de_Bruijn = | Index of int | Appl of terme_de_de_Bruijn * terme_de_de_Bruijn | Lambda of terme_de_de_Bruijn ;; let print_terme_de_de_Bruijn e = let ps = print_string and pi = print_int and pc = print_char and space = print_space and open() = open_hovbox 3 and close = close_box in let rec print e = open() ; ( match e with | Index(i) -> pi i | Lambda(u) -> ps "(\\" ; space() ; print u ; pc `)` | Appl(g,d) -> pc `(` ; print g ; space() ; print d ; pc `)` ) ; close() in print e ;; install_printer "print_terme_de_de_Bruijn" ;;
include "parseur" ;; (* définit entre autre : type lambda_terme = | Variable of string | Application of lambda_terme * lambda_terme | Abstraction of string * lambda_terme ;; type terme_de_de_Bruijn = | Index of int | Appl of terme_de_de_Bruijn * terme_de_de_Bruijn | Lambda of terme_de_de_Bruijn ;; *) (*************************************** AUXILIAIRES ********************************************) let rec intervalle i j = if i > j then [] else i :: (intervalle (i+1) j) ;; let variables = let v = make_vect 26 "" in for i = 0 to 25 do v.(i) <- make_string 1 (char_of_int (int_of_char `a` + i)) done ; v ;; let vect_index v a = let i = ref 0 in try while v.(!i) <> a do incr i done ; !i with _ -> raise Not_found ;; let var_index a = vect_index variables a ;; let index_var = var_index ;; let index l a = let rec aux i = function | [] -> raise Not_found | t :: _ when t = a -> i | _ :: q -> aux (i+1) q in aux 0 l ;; let rec nth k l = match k,l with | _,[] -> raise Not_found | 0,t::_ -> t | _,_::q -> nth (k - 1) q ;; let cons a b = a :: b ;; (************************** Gestion des lambda-termes ******************************************* lt_occurrences : string -> lambda_terme -> int list list * int list list prend en arguments le nom d'une variable et un lambda-terme et renvoie le couple constitué des occurrences libres et liées de cette variable dans ce terme lt_libres : lambda_terme -> (int list * string) list prend en argument un lambda-terme et renvoie la liste des couples constitués d'une occurrence de variable libre et de cette variable ************************************************************************************************) let lt_occurrences x t = let ajoute c = map (cons c) in let rec aux est_liée = function | Variable(a) when a = x -> if est_liée then [[]],[] else [],[[]] | Variable(_) -> [],[] | Application(t1,t2) -> let free1,bound1 = aux est_liée t1 and free2,bound2 = aux est_liée t2 in (ajoute 1 free1) @ (ajoute 2 free2) , (ajoute 1 bound1) @ (ajoute 2 bound2) | Abstraction(a,t) -> let free,bound = aux (est_liée || x = a) t in (ajoute 1 free),(ajoute 1 bound) in aux false t ;; let lt_libres t = let ajoute c = map (function (o,v) -> (c::o,v)) in let rec aux liées = function | Variable(a) -> if mem a liées then [] else [[],a] | Application(t1,t2) -> (ajoute 1 (aux liées t1)) @ (ajoute 2 (aux liées t2)) | Abstraction(x,t) -> ajoute 1 (aux (x :: liées) t) in aux [] t ;; (************************** Gestion des termes de de Bruijn ************************************** db_occurrences : string -> terme_de_de_Bruijn -> int list list prend en arguments le nom d'une variable et un terme de de Bruijn et renvoie la liste des occurrences libres de cette variable dans ce terme db_libres : terme_de_de_Bruijn -> (int list * string) list prend en argument un et renvoie la liste des couples constitués d'une occurrence de variable libre et de cette variable la variable globale `variables' contient la liste de toutes les variables du monde, la partie auxiliaire l'initialise avec [ "a" ; "b" ; ... ; "z" ] ************************************************************************************************) let db_occurrences x t = let ajoute c = map (cons c) in let rec aux p = function | Index(i) when i < p -> [] | Index(i) -> if variables.(i-p) = x then [[]] else [] | Appl(t1,t2) -> (ajoute 1 (aux p t1)) @ (ajoute 2 (aux p t2)) | Lambda(t) -> ajoute 1 (aux (p + 1) t) in aux 0 t ;; let db_libres t = let ajoute c = map (function (o,v) -> (c::o,v)) in let rec aux p = function | Index(i) -> if i < p then [] else [[],variables.(i-p)] | Appl(t1,t2) -> (ajoute 1 (aux p t1)) @ (ajoute 2 (aux p t2)) | Lambda(t) -> ajoute 1 (aux (p + 1) t) in aux 0 t ;; (****************** Conversion lambda-termes <--> termes de de Bruijn **************************** db_of_lt : lambda_terme -> terme_de_de_Bruijn lt_of_db : terme_de_de_Bruijn -> lambda_terme ************************************************************************************************) let db_of_lt t = let rec aux liées = function | Variable(x) -> Index( try index liées x with Not_found -> (list_length liées) + (var_index x) ) | Application(t1,t2) -> Appl(aux liées t1 , aux liées t2) | Abstraction (x,t) -> Lambda(aux (x :: liées) t) in aux [] t ;; let lt_of_db t = let libres = map snd (db_libres t) in let rec aux p liées k = function | Index(i) when i < p -> Variable(nth i liées) | Index(i) -> Variable(variables.(i - p)) | Appl(t1,t2) -> Application(aux p liées k t1 , aux p liées k t2) | Lambda(t) -> if mem variables.(k) libres then aux p liées (k + 1) (Lambda t) else let x = variables.(k) in Abstraction(x,aux (p + 1) (x :: liées) (k + 1) t) in aux 0 [] 0 t ;; (**************************** Quelques exemples simples *****************************************) let identité = parseur "x -> x" ;; let omega = parseur "(x -> (x x)) (x -> (x x))" ;; let exemple1 = parseur "(x -> (w -> ((y -> y) w) x))" and exemple2 = parseur "(x -> (y -> ((x -> x) y) x))" and exemple3 = parseur "x -> y -> x x y" and exemple4 = parseur "x -> y -> z x y" and exemple5 = parseur "x -> (z (z -> x z))" ;; let à_réduire = parseur "(x -> x x)((y -> x y) a)" ;; let identité' = db_of_lt identité and omega' = db_of_lt omega and exemple1' = db_of_lt exemple1 and exemple2' = db_of_lt exemple2 and exemple3' = db_of_lt exemple3 and exemple4' = db_of_lt exemple4 and exemple5' = db_of_lt exemple5 ;; let à_réduire' = db_of_lt à_réduire ;; (********************************** Alpha-équivalence ******************************************** db_alpha_équivalence : terme_de_de_Bruijn -> terme_de_de_Bruijn -> bool est l'égalité stricte, tout simplement ! lt_alpha_équivalence : lambda_terme -> lambda_terme -> bool ************************************************************************************************) let rec db_alpha_équivalence t1 t2 = match t1,t2 with | Index(i1),Index(i2) -> i1 = i2 | Appl(t11,t12),Appl(t21,t22) -> (db_alpha_équivalence t11 t21) && (db_alpha_équivalence t12 t22) | Lambda(t1),Lambda(t2) -> db_alpha_équivalence t1 t2 | _ -> false ;; let lt_alpha_équivalence t1 t2 = db_alpha_équivalence (db_of_lt t1) (db_of_lt t2) ;; (********************************** Bêta-réduction *********************************************** bêta : terme_de_de_Bruijn -> terme_de_de_Bruijn -> terme_de_de_Bruijn bêta a t réalise la bêta-réduction supposant que a est un Lambda(u) bêta_un : terme_de_de_Bruijn -> terme_de_de_Bruijn réalise la première bêta-réduction à gauche possible ou déclenche Stop si aucune bêta-réduction n'est possible bêta_réduction : terme_de_de_Bruijn -> terme_de_de_Bruijn itère tant que possible bêta_un peut donc boucler ... (sur les termes non normalisables) db_bêta_réduction : terme_de_de_Bruijn -> terme_de_de_Bruijn est un synonyme de bêta_réduction lt_bêta_réduction : lambda_terme -> lambda_terme opère sur les lambda-termes ************************************************************************************************) let bêta (Lambda u) t = let décalage d t = let rec aux_décale p = function | Appl(t1,t2) -> Appl(aux_décale p t1,aux_décale p t2) | Lambda(t) -> Lambda(aux_décale (p + 1) t) | Index(i) when i < p -> Index(i) | Index(i) -> Index(i + d) in aux_décale 0 t in let rec aux p = function | Appl(u1,u2) -> Appl(aux p u1,aux p u2) | Lambda(v) -> Lambda(aux (p + 1) v) | Index(i) when i = p -> décalage p t | Index(i) when i < p -> Index(i) | Index(i) -> Index(i - 1) in aux 0 u ;; exception Stop ;; let rec bêta_un = function | Index(_) -> raise Stop | Lambda(t) -> Lambda(bêta_un t) | Appl(Lambda(u),t) -> bêta (Lambda u) t | Appl(t1,t2) -> try Appl(bêta_un t1,t2) with Stop -> Appl(t1,bêta_un t2) ;; let rec bêta_réduction t = try bêta_réduction (bêta_un t) with Stop -> t ;; let db_bêta_réduction = bêta_réduction and lt_bêta_réduction t = lt_of_db (bêta_réduction (db_of_lt t)) ;;
Retour à la page générale de La lettre de Caml.