évaluation paresseuse ; mots de Lukasiewicz ; mots de Lyndon ; permutations
Retour à la page générale de La lettre de Caml.
type 'a glaçon =
| Gelé of unit -> 'a
| Connu of 'a;;
type 'a lazy_list =
| Nil
| Cons of 'a cellule
and 'a cellule = { hd : 'a; mutable tl : 'a lazy_list glaçon};;
let force cellule =
let glaçon = cellule.tl in
match glaçon with
| Connu val -> val
| Gelé g ->
let val = g () in
cellule.tl <- Connu val;
val;;
let rec lazy_map f = function
| Nil -> Nil
| Cons ({hd = x; _} as cellule) ->
Cons {hd = f x; tl = Gelé (function () -> lazy_map f (force cellule))};;
let rec nat = Cons {hd = 0; tl = Gelé (fun () -> lazy_map succ nat)};;
let rec lazy_do_list f n = function
| Nil -> ()
| Cons ({hd = x; _} as cellule) ->
if n > 0 then begin f x; lazy_do_list f (n - 1) (force cellule) end;;
(* Utilitaires sur les grands nombres *)
#open "num";;
(* Impression *)
#open "format";;
let print_num n = print_string (string_of_num n);;
install_printer "print_num";;
let prefix + = prefix +/
and prefix - = prefix -/
and prefix * = prefix */
and prefix / = prefix //
and prefix >= = prefix >=/
and prefix = = prefix =/;;
(* Quelques constantes *)
let un = num_of_int 1;;
let zéro = num_of_int 0;;
let moins_un = zéro - un;;
type 'a glaçon =
| Gelé of unit -> 'a
| Connu of 'a;;
type série = {Constante : num; mutable Reste : série glaçon};;
let reste_de_série s =
match s.Reste with
| Connu rest -> rest
| Gelé r -> let rest = r () in s.Reste <- Connu rest; rest;;
let rec add_série s1 s2 =
{Constante = s1.Constante + s2.Constante;
Reste =
Gelé
(function () -> add_série (reste_de_série s1) (reste_de_série s2))};;
let rec mult_série_par_constante c s =
{Constante = c * s.Constante;
Reste = Gelé
(function () -> mult_série_par_constante c (reste_de_série s))};;
let rec mult_série s1 s2 =
{Constante = s1.Constante * s2.Constante;
Reste =
Gelé
(function () ->
add_série (mult_série_par_constante s1.Constante (reste_de_série s2))
(mult_série (reste_de_série s1) s2))};;
let opposée_de_série s = mult_série_par_constante moins_un s;;
let rec integre_série c0 s =
{Constante = c0;
Reste = Gelé (function () -> integre_depuis un s)}
and integre_depuis n s =
{Constante = s.Constante / n;
Reste = Gelé (function () -> integre_depuis (n + un) (reste_de_série s))};;
let print_variable = function
0 -> false
| 1 -> print_string "z"; true
| n -> print_string "z^"; print_int n; true;;
let print_terme plus degré s =
let c = s.Constante in
if c = zéro then false else
if c = un then begin print_string plus; print_variable degré end else
if c = moins_un
then begin print_string "- "; print_variable degré end
else
begin
if c >= zéro then print_string plus else print_string "- ";
print_num (abs_num c);
print_variable degré
end;;
let print_first_terme s =
let c = s.Constante in
if c = zéro then false else begin print_num c; true end;;
let rec print_série until s =
open_hovbox 1;
let c = s.Constante in
if until == 0 then print_num c else
let rest = ref s in
let zéro = not (print_first_terme !rest) in
if not zéro then print_space();
for i = 1 to until do
rest := reste_de_série !rest;
let delim = if i == 1 & zéro then "" else "+ " in
if print_terme delim i !rest then print_space()
done;
print_string "+ O(z^"; print_int (succ until);
print_string ")";
close_box();;
let rec sinus =
{Constante = zéro;
Reste = Gelé (function () -> integre_depuis un cosinus)}
and cosinus =
{Constante = un;
Reste = Gelé (function () -> integre_depuis un (opposée_de_série sinus))};;
let s = add_série (mult_série sinus sinus) (mult_série cosinus cosinus);;
print_série 10 s;;
#open "graphics" ;;
open_graph "" ;;
exception Not_Lukasiewicz ;;
let rec somme m k =
if k = 0 then 0
else (hd m) + somme (tl m) (k - 1) ;;
let rec rho = function
| 1 :: -1 :: -1 :: reste -> true, -1 :: reste
| x :: reste -> let flag, m' = rho reste in flag, x::m'
| m -> false, m ;;
let rec rho_étoile m =
match rho m with
| false, m' -> m'
| true, m' -> rho_étoile m' ;;
let est_Lukasiewicz m =
match rho_étoile m with
| [-1] -> true
| _ -> false ;;
let rec décompose suffixe =
let rec décomp_rec m s =
match m with
| n :: m' -> if n + s = -1 then [n] , m'
else let g,d = décomp_rec m' (n + s)
in
n :: g , d
| _ -> raise Not_Lukasiewicz
in
décomp_rec suffixe 0 ;;
type arbre = Feuille | Nud of arbre * arbre ;;
let rec Lukasiewicz_of_arbre = function
| Feuille -> [-1]
| Nud(g,d) -> 1 :: (Lukasiewicz_of_arbre g) @ (Lukasiewicz_of_arbre d) ;;
let rec arbre_of_Lukasiewicz = function
| [-1] -> Feuille
| 1 :: reste -> let gauche,droit = décompose reste
in
Nud((arbre_of_Lukasiewicz gauche),(arbre_of_Lukasiewicz droit))
| _ -> raise Not_Lukasiewicz ;;
let rec profondeur_arbre = function
| Feuille -> -1
| Nud(g,d) -> 1 + max (profondeur_arbre g) (profondeur_arbre d) ;;
let profondeur_Lukasiewicz m = profondeur_arbre (arbre_of_Lukasiewicz m) ;;
let rotation (x,y) = (y-x+240,276-x-y) ;;
let point x y = let x',y' = rotation(x,y) in fill_circle x' y' 2 ;;
let va_à x y = let x',y' = rotation(x,y) in moveto x' y' ;;
let tracer x y = let x',y' = rotation(x,y) in lineto x' y' ;;
let rec deux_puissance = function
| 0 -> 1
| n -> let x = deux_puissance (n/2) in if n mod 2 = 0 then x * x else 2 * x * x ;;
let dessine mot =
let rec dessin_rec a x0 y0 =
point x0 y0 ;
match a with
| Feuille -> ()
| Nud(g,d) -> let delta = 3 * (deux_puissance (profondeur_arbre a))
in
begin
dessin_rec g (x0 + delta) y0 ;
dessin_rec d x0 (y0 + delta) ;
va_à (x0 + delta) y0 ;
tracer x0 y0 ;
tracer x0 (y0 + delta)
end
in
dessin_rec (arbre_of_Lukasiewicz mot) 0 0 ;;
exception Not_Lyndon ;;
type comparaison = Inférieur | Égal | Supérieur ;;
let rec ordre u v = match u,v with
| [],[] -> Égal
| [],_ -> Inférieur
| _,[] -> Supérieur
| u0 :: u' , v0 :: v'
-> if u0 = v0 then ordre u' v'
else if u0 < v0 then Inférieur else Supérieur ;;
let rec est_préfixe a mot = match a with
| [] -> true
| a0 :: a' -> match mot with
| m0 :: m' when a0 = m0 -> est_préfixe a' m'
| _ -> false ;;
let est_suffixe a mot =
let rec shift l = function
| 0 -> l
| n -> shift (tl l) (n - 1)
in
let la,lm = (list_length a),(list_length mot)
in
if la > lm then false
else a = (shift mot (lm - la)) ;;
let rotation mot = (tl mot) @ [ hd mot ] ;;
let est_Lyndon_def mot =
let n = list_length mot
and m = ref mot
in
try
for i = 1 to n do
m := rotation !m ;
if (ordre mot !m) = Supérieur then raise Not_Lyndon
done ;
true
with Not_Lyndon -> false ;;
let est_Lyndon mot =
let rec test = function
| [] -> true
| (a :: q) as m' -> (Inférieur = ordre mot m') && (test q)
in
test (tl mot) ;;
let factorisation_de_Lyndon mot =
let rec réduit = function
| (a :: b :: q) as ll
-> ( if (ordre a b) = Inférieur then
let m,_ = réduit ((a @ b) :: q) in m,true
else
match réduit (b :: q) with
| m,true -> réduit (a :: m)
| m,false -> ll,false )
| ll -> ll,false
in
match réduit (map (function x -> [x]) mot) with ll,_ -> ll ;;
let Lyndon =
let rec insertion x = function
| [] -> [x]
| y :: q -> match ordre x y with
| Inférieur -> x :: y :: q
| Égal -> y :: q
| Supérieur -> y :: (insertion x q)
in
let rec map_accu f accu = function
| [] -> accu
| x :: q -> match f(x) with
| [] -> map_accu f accu q
| y -> map_accu f (insertion y accu) q
in
let compose_un x1 l2 accu =
map_accu (function x2 -> if Inférieur = ordre x1 x2 then x1 @ x2 else [])
accu l2
in
let rec compose l1 l2 accu =
match l1 with
| [] -> accu
| x1 :: q -> compose q l2 (compose_un x1 l2 accu)
in
let rec compose_tout f n k accu =
if k < n then compose_tout f n (k+1) (compose (f k) (f (n-k)) accu)
else accu
in
let mémoire = ref [ (0,[]) ; (1,[ [0] ; [1] ]) ]
in
let rec f n =
try assoc n !mémoire
with Not_found -> let res = compose_tout f n 1 []
in
mémoire := (n,res) :: !mémoire ;
res
in
f ;;
let image v k = v.(k - 1)
and affecte v k x = v.(k-1) <- x ;;
let identité n =
let v = make_vect n 1
in
for i = 1 to n do affecte v i i done ;
v ;;
let compose v v' =
let n,n' = (vect_length v),(vect_length v')
in
if n = n' then
let w = make_vect n 1
in
for i = 1 to n do affecte w i (image v (image v' i)) done ;
w
else
failwith "Composition de deux permutations de tailles différentes" ;;
let rec intervalle_d'entiers i j =
if i > j then []
else i :: (intervalle_d'entiers (i+1) j) ;;
let est_permutation v =
let n = vect_length v
in
let un_a_n = intervalle_d'entiers 1 n
in
let rec est_ok = function
| [] -> true
| a :: q -> (not (mem a q)) && (mem a un_a_n) && (est_ok q)
in
est_ok (list_of_vect v) ;;
let orbite v k =
let rec augmente_orbite k liste =
if mem (image v k) liste then liste
else augmente_orbite (image v k) ((image v k) :: liste)
in
augmente_orbite k [ k ] ;;
let rec select f = function
| [] -> []
| a :: q -> if (f a) then a :: (select f q) else select f q ;;
let points_fixes v =
let n = vect_length v
in
select (function x -> x = (image v x)) (intervalle_d'entiers 1 n) ;;
let réciproque v =
let n = vect_length v
in
let w = make_vect n 1
in
for i = 1 to n do affecte w (image v i) i done ;
w ;;
let rec ôte x = function
| [] -> []
| a :: q when a = x -> q
| a :: q -> a :: (ôte x q) ;;
let cycles v =
let rec un_cycle x0 x candidats =
if (image v x) = x0 then [ x0 ] , (ôte x candidats)
else
let queue,c' = un_cycle x0 (image v x) (ôte x candidats)
in
x :: queue,c'
in
let rec épuise = function
| [] -> []
| a :: _ as liste -> let cycle,candidats = un_cycle a a liste
in
cycle :: (épuise candidats)
in
épuise (list_of_vect v) ;;
let échange v i j =
let x = v.(i)
in
v.(i) <- v.(j) ;
v.(j) <- x ;;
let applique_aux_permutations f n =
let v = vect_of_list (intervalle_d'entiers 1 n)
in
let rec perm_rec i =
if i = n - 1 then f v
else
for j = i to n - 1 do
échange v i j ;
perm_rec (i+1) ;
échange v i j
done
in
perm_rec 0 ;;
let print_permutation v =
for i = 0 to (vect_length v) - 1 do
print_int v.(i) ;
print_char ` `
done ;
print_newline () ;;
let toutes_les_permutations = applique_aux_permutations print_permutation ;;
exception No_more_permutation ;;
let permutation_suivante v =
let n = vect_length v
in
let rec début_suffixe i =
if i <= 0 then raise No_more_permutation
else
if v.(i) < v.(i-1) then début_suffixe (i-1)
else i-1
and retourne_suffixe a b =
if a < b then
begin
échange v a b ;
retourne_suffixe (a + 1) (b - 1)
end
and place k j =
if v.(j) > v.(k) then échange v j k
else place k (j + 1)
and modifie_suffixe k =
retourne_suffixe (k + 1) (n - 1) ;
place k (k + 1)
in
modifie_suffixe ( début_suffixe (n - 1) ) ;;
Retour à la page générale de La lettre de Caml.