Ensembles et Relations binaires avec CAML

Voici quelques fonctions permettant de travailler sur les relations binaires à l'aide de CAML. Attention ! Cette présentation n'est vraiment pas performante mais uniquement destinée à être utilisée par des apprentis mathématiciens-programmeurs très débutants...

OCaml
(* ---------------------------------------------------------------------------------------
---------------------------- E N S E M B L E S ----------------------------------------
 -------------------------------------------------------------------------------------  *)
 
 
 
type 'a ens =
  | Vide 
  | Ens of ('a * 'a ens);;
 
 
 
exception Ensemble_vide;;
 
 
let rec ensemble_of_liste liste =
  match liste with
  |[] -> Vide
  |t::q -> Ens(t,ensemble_of_liste q);;
 
(* attention au symbole = ne fonctionne que pour des types simples... *)
let rec appartient el ensemble =
  match ensemble with
    |Vide -> false
    |Ens(t,q) ->
      if t = el then true
      else appartient el q;;
 
 
let ajoute el ens =
  if appartient el ens then ens
  else Ens(el,ens);;
 
let (@+) el ens = ajoute el ens;;
 
let rec union ens1 ens2 =
  match ens1 with
    |Vide -> ens2
    |Ens(t,q) -> t @+ (union q ens2) ;;
 
let (@|) ens1 ens2 = union ens1 ens2;;
 
 
 
let rec cardinal = function
    | Vide -> 0
    | Ens(t,q) -> if appartient t q then cardinal q else 1 + cardinal q;;
 
let rec applique f ens =
  match ens with
    |Vide -> Vide
    |Ens(t,q) -> Ens(f(t),applique f q);;
 
 
 
let rec parties  = function
  |Vide ->  Ens(Vide,Vide)
  |Ens(t,q) ->  (parties q) @| (applique (ajoute t) (parties q));;
 
 
 
 
let rec liste_el = function
    |Vide -> []
    |Ens(a,e) -> a::liste_el(e);; 
 
let rec ens_of_list = function
  |[] -> Vide
  |t::q -> t @+ (ens_of_list q);;
 
let rec retire el ens  =
  match ens with
    |Vide -> Vide
    |Ens(t,q) ->
      if t = el then q
      else Ens(t, retire el q);;
 
let rec selec pred ens =
  match ens with
    |Vide -> Vide
    |Ens(t,q) ->
      if pred t then Ens(t,selec pred q)
      else selec pred q;;
 
 
 
let rec parties_taille_n ens n =
  selec (fun x -> cardinal x = n) (parties ens);; 
 
 
 
let rec existe pred ens =
  match ens with
    |Vide -> false
    |Ens(t,q) ->
      if pred t then true
      else existe pred q;;
 
let rec pour_tout pred ens =
  match ens with
    |Vide -> true
    |Ens(t,q) ->
      if pred t then pour_tout pred q
      else false;;
 
let positif nb  =
  nb >= 0;;
 
 
let ensemble_1 = Ens(-1,Ens(1,Ens(2,Ens(3,Vide))));;
 
pour_tout positif ensemble_1;;  
 
 
let partition pred ens  = 
  let  rec temp pred ens e1 e2 =
  match ens with
    |Vide -> (e1,e2)
    |Ens(t,q) ->
      if pred t then temp pred q (Ens(t,e1)) e2
      else temp pred q e1 (Ens(t,e2))
  in temp pred ens Vide Vide;;
 
 
let trouve_tout pred ens  = 
  let  rec remplit pred ens panier =
  match ens with
    |Vide -> panier
    |Ens(t,q) ->
      if pred t then remplit pred q (ajoute t panier) 
      else remplit pred q panier
  in remplit pred ens Vide ;;
 
 
 
 
 
let projection rang couple =
  match couple with
    |(a,b) -> if rang = 0 then a else b;;
 
let p0 (a,b) = a;;
 
let p1 (a,b) = b;;
 
let rec couples el ens =
  match ens with
    |Vide -> Vide
    |Ens(t,q) -> Ens((el,t),couples el q);;
 
 
let rec produit_cart ens1 ens2 =
  match ens1 with
    |Vide -> Vide
    |Ens(t,q) -> union (couples t ens2) (produit_cart q ens2);;
 
 
let rec inter ens1 ens2 =
  match ens1 with
    |Vide -> Vide
    |Ens(t,q) ->
      if appartient t ens2 then Ens(t,inter q ens2)
      else inter q ens2;;
 
 
let rec complement ens univers =
  match univers with
    |Vide -> Vide
    |Ens(t,q) ->
      if appartient t ens then complement ens q
      else Ens(t,complement ens q );;
 
let rec difference ens1 ens2 =
    match ens1 with
      |Vide -> Vide
      |Ens(t,q) ->
        if appartient t ens2 then difference q ens2
        else Ens(t,difference q ens2);;
 
 
let est_inclus ens1 ens2 =
  if inter ens1 ens2 = ens1 then true
  else false;;
 
let est_egal ens1 ens2 =
  (est_inclus ens1 ens2) && (est_inclus ens2 ens1);;
 
 
let max2 a b =
  if a >= b then a else b;;
 
let rec max ens =
  match ens with
    |Vide -> raise Ensemble_vide
    |Ens(t,Vide) -> t
    |Ens(t,q) -> max2 t (max q);;
 
exception Cle_inconnue;;
 
let rec assoc cle ens =
  match ens with
    |Vide -> raise Cle_inconnue
    |Ens(t,q) ->
      if fst t = cle then snd t
      else assoc cle q;;
 
let rec ens_assoc cle ens =
  match ens with
    |Vide -> Vide
    |Ens(t,q) ->
      if fst t = cle then Ens(snd t,ens_assoc cle q)
      else ens_assoc cle q;;
 
(*
----------------------------------------------------------------------------------------------
-------------- R E L A T I O N S -------------------------------------------------------------
----------------------------------------------------------------------------------------------
*)
 
(*-- Crée des relations avec le type ens
   --*)
 
type ('a,'b) relation =
  Rel of ('a * 'b ens)  ens ;;
 
let r =  Rel
   (Ens
      ((1, Ens ('a', Ens ('b', Vide))),
       Ens((2, Ens ('c', Vide)),
           Ens((3, Ens ('b', Vide)),
               Ens((4, Vide),
                   Ens ((5, Ens ('b', Vide)),
                        Vide))))));;
 
 
let s = Rel
  (Ens
     (('a',Ens(1,Vide)),
      Ens(('b',Ens(1,Ens(2,Vide))),
          Ens(('b',Ens(1,Ens(2,Vide))),
              Ens(('c',Ens(2,Vide)),
                  Ens(('d',Vide),
                      Ens(('e',Ens(2,Ens(4,Vide))),
                          Vide))))))
                );;
 
r;;
 
s;;
 
 
 
(* écriture d'une relation à partir d'une liste de couples (som,liste d'images) *)
 
 
let rec relation liste =
  match liste with
  |[] -> Rel(Vide)
  |tete::queue -> rel_union (Rel(Ens((fst tete,ensemble_of_liste (snd tete)),Vide))) (relation queue);;
 
let r = relation ([
                (1,['a';'b']);
                (2,['c']);
                (3,['b']);
                (4,[]);
                (5,['b'])
                ]);;
 
 
let s = relation ([
                ('a',[1]);
                ('b',[1;2]);
                ('c',[2]);
                ('d',[]);
                ('e',[2;4])
                ]);;
 
 
 
(* Lecture d'une relation sous forme d'une liste *)
 
let rec liste_of_ensemble = function
  |Vide -> []
  |Ens(t,q) -> t::(liste_of_ensemble q);;
 
 
let rec liste_of_relation rel =
  match rel with
  |Rel(Vide) -> []
  |Rel(Ens(tete,queue)) -> (fst tete,liste_of_ensemble (snd tete))::(liste_of_relation (Rel(queue)));;
 
 
 
liste_of_relation r;;
 
 
 
 
(*-- donne le domaine de r --*)
 
let rec domaine  = function
  |Rel(Vide) -> Vide
  |Rel(Ens(el,queue)) ->
    if (snd el) = Vide
    then domaine (Rel(queue))
    else ajoute (fst el) (domaine (Rel(queue)));;
 
let rec codomaine  = function
  |Rel(Vide) -> Vide
  |Rel(Ens(el,queue)) -> union (snd el) (codomaine (Rel(queue)));;
 
 
 
(*-- l'ensemble des  images de a par r --*)
 
let rec ens_images rel a =
  match rel with
  |Rel(Vide) -> Vide
  |Rel(Ens(tete,queue)) ->
    if (fst tete) = a
    then (snd tete)
    else ens_images (Rel(queue)) a ;;
 
ens_images r 1;;
ens_images r 4;;
 
 
 
(*-- teste si un arc relie som1 à som2 dans r privilégiant l'antécédent
     mem el liste teste si el appartient à liste --*)
 
let a_image rel som1 som2  =
  appartient som2 (ens_images rel som1);;
 
(*-- variante privilégiant l'image --*)
 
let a_antecedent rel som2 som1 =
  appartient som2 (ens_images rel som1);;
 
a_image r 1 'a' ;;
 
a_antecedent r 'a' 1 ;;
 
 
(* ajoute un couple à un ensemble de couples *)
 
let rec fusionne_image_ens couple ens_couples =
  match ens_couples with
  |Vide -> Ens(couple,Vide)
  |Ens(t,q) ->
    if fst t = fst couple then Ens((fst t,union (snd t) (snd couple)) ,q)
    else Ens(t,fusionne_image_ens couple q);;
  
 
(* ajoute  une image à l'ens_images d'un sommet dans relation*)
 
 
let fusionne_image_rel couple relation =
    match relation with
    |Rel(Vide) -> Rel(Ens(couple,Vide))
    |Rel(Ens(a,b)) ->   Rel(fusionne_image_ens couple (Ens(a,b)));;
 
 
 
 
(* union de deux relations *)
 
exception Relations_non_compatibles;;
 
let rec rel_union r1 r2 =
    match r1 with
    |Rel(Vide) -> r2
    |Rel(Ens(tete,queue)) -> rel_union (Rel(queue)) (fusionne_image_rel tete r2);;
 
 
(*-- crée un opérateur infixe de l'union --*)
 
let (+@) r1 r2 = rel_union r1 r2;;
 
 
 
 
 
(*-- renvoie l'ens  des images des éléments d'un ens par r --*)
 
let rec images_d_un_ens rel ens =
  match ens  with
    |Vide -> Vide
    |Ens(tete,queue) -> union (ens_images rel tete)  (images_d_un_ens rel queue);;
 
images_d_un_ens r (Ens(1,Ens(2,Ens(3,Vide)))) ;;
 
 
 
 
(*-- renvoie la  relation r suivie de s --*)
 
let  rec suivie_de r s =
  match r with
  |Rel(Vide) -> Rel(Vide)
  |Rel(Ens(tete,queue)) -> fusionne_image_rel (fst tete, images_d_un_ens s (ens_images r (fst tete)) ) (suivie_de (Rel(queue)) s);;
 
 
suivie_de r s;;
 
 
liste_of_relation (suivie_de r s);;
 
 
let (@@) r s = suivie_de r s;;
 
r @@ s;;
 
 
let rec iter_compo r  n =
  match n with
    |1 -> r
    |n -> r @@ (iter_compo r (n-1));;
 
 
 
let u = relation ([
                (1,[1]);
                (2,[1;2]);
                (3,[2]);
                (4,[]);
                (5,[2;4])
                ]);;
 
iter_compo u 5;;
 
 
(*-- fermeture transitive : renvoie r+ = Uri pour 1<=i<=card E --*)
 
let r_plus r =
  let n = cardinal (domaine r) in
  let rec loop  = function
    |1 -> r
    |k -> rel_union (iter_compo r k)  (loop (k-1))
  in loop n;;
    
r_plus u;;
 
 
 
 
 
(*-- renvoie la relation identité de même taille que r --*)
 
let id r =
  let rec loop = function
    | Vide -> Vide
    | Ens(tete,queue) -> Ens((tete,Ens(tete,Vide)),(loop queue))
  in Rel(loop (domaine r));;
 
id r;;
 
(*-- fermeture transitive et reflexive : revoie r* = id U r+ --*)
 
let r_star r =
  rel_union (id r)  (r_plus r);;
 
r_star u;;
 
 
 
 
(*-- teste si r1 est incluse dans r2 (opérateur infixe)--*)
 
let (<@) r1 r2 =
  est_inclus (produit_cart (domaine r1) (codomaine r1)) (produit_cart (domaine r2) (codomaine r2)) ;;  
 
 
 
 
(*--teste la transitivité avec r^2 incluse dans r  --*)
 
let est_transitive r =
  (r @@ r)  <@ r;;
 
 
est_transitive u;;
 
est_transitive (r_plus u);;
 
(*-- teste si une relation est reflexive  --*)
 
let est_reflexive1 r =
  let test a =  appartient a (ens_images r a) in
  pour_tout test (domaine r);;
 
(*-- ou bien si Id incluse dans r --*)
 
let est_reflexive r =
  (id r) <@ r;;
 
est_reflexive u;;
 
 
(*-- teste si une relation est symétrique :
     a appartient à la liste des images de ses images par r --*)
 
let est_symetrique r =
  let test a =  appartient a (images_d_un_ens r (ens_images r a)) in
  pour_tout test (domaine r);;
 
 
est_symetrique u;;
 
 
let v = relation ([
                (1,[1;2]);
                (2,[1;2;3;5]);
                (3,[2]);
                (4,[5]);
                (5,[2;4])
                ]);;
 
 
 
est_symetrique v;;
 
 
(*-- teste si une relation est antisymétrique  :
     aucun a n'appartient à la liste des images de ses images par r --*)
 
let est_antisymetrique r =
  let test a = not ( appartient a (images_d_un_ens r (ens_images r a))) in
  pour_tout test (domaine r);;
 
 
est_antisymetrique v;;
 
let w = relation ([
                (1,[2]);
                (2,[3;5]);
                (3,[1]);
                (4,[5]);
                (5,[1;3])
                ]);;
 
est_antisymetrique w;;
 
 
 
(*-- transposée d'une relation : on parcourt les sommets et on teste quels sont
     les antécédents de ce sommet avec trouve_tout :
     trouve_tout pred ens renvoie l'ensemble de tous les éléments de ens vérifiant pred --*)
 
let transposee1 r =
  let dom = domaine r in
  let rec recherche = function
    |Vide -> Vide 
    |Ens(tete,queue) ->
        let test_ante s = a_antecedent r tete s in
        try Ens((tete,trouve_tout test_ante dom), recherche queue)
        with Not_found -> Vide
  in Rel(recherche dom);;
 
 
let transposee r =
  let rec recherche_antecedents ens =
    match ens with
    |Vide -> Rel(Vide)
    |Ens(tete,queue) ->
      fusionne_image_rel (tete, trouve_tout (a_antecedent r tete) (domaine r)) (recherche_antecedents queue)
  in recherche_antecedents (codomaine r);;
 
transposee w;;
 
(*-- teste si une relation est une fonction : la longueur de l'ensemble des images de chaque élément du domaine  est <= 1--*)
 
let est_fonction r =
  let test s = cardinal (ens_images r s) <= 1 in
  pour_tout test (domaine r);; 
 
est_fonction w;;
 
 
let r' = relation ([
                (1,[2]);
                (2,[3]);
                (3,[1]);
                (4,[]);
                (5,[1])
                ]);;
 
 
 
est_fonction r';;
 
 
(*-- teste si une relation est totale : (transposée f)of est reflexive--*)
 
let est_totale r =
  est_reflexive (r @@ (transposee r));;
 
est_totale r';;
 
(*-- teste si une relation est une application version 1:
     tout élément a exactement une image --*)
 
let est_application1 r =
  let test s = cardinal (ens_images r s) = 1 in
  pour_tout test (domaine r);;
 
(*-- teste si une relation est une application version 2:
     c'est une fonction totale --*)
 
let est_application r =
  (est_fonction r) && (est_totale r);;
 
est_application1 r';;
 
est_application r';;
 
 
let r2 = relation ([
                (1,[2]);
                (2,[3]);
                (3,[1]);
                (4,[4]);
                (5,[1])
                ]);;
 
 
est_application r2;;
 
(*-- teste si une relation est injective : sa transposée est une fonction --*)
 
let est_injective r =
  est_fonction (transposee r);;
 
est_injective r2;;
 
 
let r3 = relation ([
                (1,[2]);
                (2,[3;5]);
                (3,[1]);
                (4,[4]);
                (5,[])
                ]);;
 
est_injective r3;;
 
(*-- teste si une relation est surjective : sa transposée est totale --*)
 
let est_surjective r =
  est_totale (transposee r);;
 
est_surjective r2;;
 
est_surjective r3;;
 
(*-- variante : ro(transposee r) est reflexive --*)
 
let est_surjective2 r =
  est_reflexive ( (transposee r) @@ r);;
 
est_surjective2 r2;;
 
est_surjective2 r3;;
 
(*-- teste si une relation est bijective : fonction surjective et bijective --*)
 
let est_bijective r =
  (est_fonction r) && (est_injective r) && (est_surjective r);;
 
est_bijective r3;;
 
 
let r4 = relation ([
                (1,[2]);
                (2,[3]);
                (3,[1]);
                (4,[5]);
                (5,[4])
                ]);;
 
est_bijective r4;;