226 lines
7.3 KiB
OCaml
226 lines
7.3 KiB
OCaml
(* Implémentation des codes linéaires *
|
|
|
|
* un code linéaire est une application linéaire f de S = {0,1}^k dans D = {0,1}^n injective
|
|
* le terme code désigne aussi l'espace C = Im(f)
|
|
* k représente la dimension de l'espace source, on l'appelle dimension du code
|
|
* n représente la dimension de l'espace des codes, on l'appelle longueur du code
|
|
* on modèlise un code linéaire par sa matrice génératrice G, celle-ci possède n lignes et k colonnes, elle est à coefficients dans {0,1}
|
|
* tout calcul matriciel se fait dans le corps F_2
|
|
* nous nous intéressons dans un premier temps à des codes systématiques càd recopiants le mot d'entré puis rajoutants des redondances
|
|
* pour aider le décodage on introduit le concept de matrice de contrôle H dont on n'a pas l'unicité, il s'agit d'une matrice comportant n-k lignes et n colonnes et dont le noyau correspond à l'image du code
|
|
* la distance minimale d_f d'un code correspond à la plus petite distance séparant deux mots distincts du code
|
|
* on définit à partir de celle-ci la capacité de détection e_d du code ainsi que celle de correction e_c
|
|
* un code est parfait si pour tout mot de code M de D, il existe un unique Y appartenant à C minimisant la distance de M à Y
|
|
|
|
* on souhaite transmettre un mot source X, pour ce faire on l'encode en Y = f(X) puis on envoit Y, après transmission (et donc des apparitions d'erreurs) est reçu Z
|
|
* notre but est de construire un algorithme capable de déterminer le mot de code Y' le plus proche de Z et donc de décoder Z en X' = f<-1>(Y')
|
|
* on pose E = Z + Y le mot d'erreur associé à Z
|
|
* pour M un mot de code, on appelle syndrome de M le mot HM, on note en particulier S le syndrome de Z
|
|
* en remarquant que E est dans la classe lattérale de Z (càd qu'il a le même syndrome que Z), la recherche de Y' se ramène à celle du mot de plus petit poids (au sens de Hamming) dans la classe lattérale de Z
|
|
|
|
*NOTE SUR LA PROGRAMMATION*
|
|
* on représente un vecteur dans F_2 par un entier dont la décomposition binaire correspond aux composantes du vecteur
|
|
* on représente une matrice par un liste d'entier, il s'agit de la liste de ses colonnes (qui sont donc des vecteurs)
|
|
|
|
|
|
|
|
#cd "/home/mysaa/Documents/Arbeiten/TIPE2021/";;
|
|
#load "Math.cmo";;
|
|
*)
|
|
|
|
open Math;;
|
|
|
|
(*************************************************************)
|
|
(************************Module CLineaire*********************)
|
|
(*************************************************************)
|
|
|
|
module CLineaire =
|
|
struct
|
|
;;
|
|
|
|
(* La bonne structure *)
|
|
type t = {k : int; n : int; g : Math.matrice; h : Math.matrice};;
|
|
type code_lineaire = t;; (* Le type du module *)
|
|
|
|
(* Calcule Y = GX *)
|
|
let encoder code x = produit code.g x ;;
|
|
|
|
|
|
let systematiqueFromRedondance k n redondance =
|
|
let g =
|
|
let decalage = deux_puissance k in
|
|
let rec iteredon ajout = function
|
|
| [] -> []
|
|
| tete :: queue ->
|
|
let c = tete * decalage + ajout in
|
|
c :: (iteredon (ajout * 2) queue)
|
|
in iteredon 1 redondance
|
|
and h = redondance @ (identite (n-k)) in
|
|
{k = k; n = n; g = g; h = h}
|
|
;;
|
|
|
|
(* Etant donnés tous les vecteurs de poids p dans un espace de dimension d, retourne touts ceux de poids p+1 dans ce même espace *)
|
|
let suivants d vecteurs =
|
|
let contraintes = ref [] in
|
|
let resultats = ref [] in
|
|
let rec iterer = function
|
|
| [] -> ()
|
|
| x :: r ->
|
|
let donne_un_resultat = ref false in
|
|
for i=0 to d-1 do
|
|
let y = changer_bit i x in
|
|
if x < y && (respecter y !contraintes)
|
|
then begin
|
|
resultats := y :: !resultats;
|
|
donne_un_resultat := true;
|
|
end;
|
|
done;
|
|
if !donne_un_resultat
|
|
then contraintes := x :: !contraintes;
|
|
iterer r;
|
|
in iterer vecteurs; !resultats
|
|
;;
|
|
|
|
|
|
|
|
(* Renvoit le plus petit mot (au sens de Hamming) dans F_2^d vérifiant 'propriete' et de poids inférieur à poids_max. Renvoie le couple (-1, 0) si aucun mot n'a été trouvé *)
|
|
let plus_petit_verifiant propriete poids_max d =
|
|
let rec chercher p vecteurs =
|
|
match List.find_opt propriete vecteurs with
|
|
| Some v -> (p, v)
|
|
| None ->
|
|
if p < poids_max
|
|
then chercher (p+1) (suivants d vecteurs)
|
|
else (-1, 0)
|
|
in chercher 0 [0]
|
|
;;
|
|
|
|
|
|
exception PasDansLeCodeException;;
|
|
|
|
(* Calcul de façons à ouf l'antécédent de 'y' pour le code 'code' *)
|
|
let antecedent code y =
|
|
let mot_max = (deux_puissance code.k) - 1 in
|
|
let rec iterer = function
|
|
| x when x = mot_max -> raise PasDansLeCodeException
|
|
| x ->
|
|
if (encoder code x) = y
|
|
then x else iterer (x+1)
|
|
in iterer 0
|
|
;;
|
|
|
|
exception IndecodableException;;
|
|
|
|
|
|
let appartenir code v = produit code.h v = 0;;
|
|
|
|
(* Calcul la distance minimale d'un code *)
|
|
let distance_minimale code =
|
|
let n = code.n in
|
|
let propriete = fun v -> (0 < v) && (appartenir code v) in
|
|
let (p, _) = plus_petit_verifiant propriete n n in p
|
|
;;
|
|
|
|
(* Applique notre algorithme préféré *)
|
|
let decoder code z =
|
|
let d_min = distance_minimale code in
|
|
let e_c = (d_min - 1) / 2 and n = code.n in
|
|
let propriete = fun v -> appartenir code ((lxor) z v) in
|
|
match plus_petit_verifiant propriete e_c n with
|
|
| (-1, 0) -> raise IndecodableException
|
|
| (_, e) -> antecedent code ((lxor) z e)
|
|
;;
|
|
|
|
|
|
(*** Décodage avec stockage des syndromes ***)
|
|
|
|
(* syndr est une fonction qui à un vecteur associe son syndrome.
|
|
En effet, la notion de syndrome dépend de quelle matrice H nous avons choisi.
|
|
Créer cette fonction ici permet de ne plus dépendre de la matrice H de code_lineaire *)
|
|
type classesLaterales = {syndr : Math.vecteur -> Math.vecteur;
|
|
erreur : Math.vecteur -> Math.vecteur;
|
|
babr : Math.vecteur Math.binabr};;
|
|
|
|
|
|
let genererClasses code =
|
|
let syndr = function z -> Math.produit code.h z in
|
|
let compacteur babr v = if BFeuille<>babr && not (appartenir code v)
|
|
then (print_int v;putWho babr (syndr v)) v false
|
|
else BFeuille in
|
|
let rec iter babr0 lst =
|
|
let svts = suivants code.n lst in
|
|
let babr = List.fold_left compacteur babr0 svts in
|
|
if babr<>BFeuille
|
|
then iter babr svts
|
|
else babr0 (*On a dépassé la capacité de correction*)
|
|
in
|
|
let babr = iter (put BFeuille 0 0) [0] in
|
|
let erreur = function z -> get babr z
|
|
in {syndr=syndr;erreur=erreur;babr=babr}
|
|
;;
|
|
|
|
let decoder2 classes z :vecteur=
|
|
let s = classes.syndr z in
|
|
let e = classes.erreur s in
|
|
z lxor e;;
|
|
end;;
|
|
|
|
(*************************************************************)
|
|
(************************Module CCyclique*********************)
|
|
(*************************************************************)
|
|
|
|
module CCyclique =
|
|
struct
|
|
;;
|
|
(* La super stucture *)
|
|
type t = {k : int; n: int; pol: polynome};;
|
|
type code_cyclique = t;;
|
|
|
|
let get k n pol = {k=k;n=n;pol=pol};;
|
|
|
|
|
|
let cyclencode code (x:vecteur) :vecteur = polmul code.pol x;;
|
|
|
|
end;;
|
|
|
|
(*************************************************************)
|
|
(*****************************Suite***************************)
|
|
(*************************************************************)
|
|
|
|
open CLineaire;;
|
|
open CCyclique;;
|
|
|
|
(* Construit le code linéaire associé au code cyclique *)
|
|
let cycliqueVersLineaire code =
|
|
let k=code.k and n=code.n and pol=code.pol in
|
|
let g =
|
|
let rec itdecal i l =
|
|
if i<0
|
|
then l
|
|
else itdecal (i-1) ((pol lsl i)::l)
|
|
in itdecal (k-1) []
|
|
and h =
|
|
let polh = poldiv ((deux_puissance n) + 1) pol in
|
|
print_polynome polh;
|
|
let filtre = (deux_puissance (n-k+1))-1 in
|
|
let rec sub i l =
|
|
if i<(-k)
|
|
then l
|
|
else sub (i-1) (((decagauche polh i) land filtre)::l)
|
|
in sub (n-k-1) []
|
|
in {k = k; n = n; g = g; h = h}
|
|
;;
|
|
|
|
|
|
let lineaireVersCyclique code =
|
|
(*TODO*)1
|
|
;;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(* Voilà *)
|