Aller au contenu

DM

Autour du sĂ©quençage du gĂ©nome⚓

Dans ce sujet, on s’intĂ©resse Ă  la recherche d’un motif dans une molĂ©cule d’ADN.

Une molĂ©cule d’ADN est constituĂ©e de deux brins complĂ©mentaires, qui sont un long enchaĂźnement de nuclĂ©otides de quatre types diffĂ©rents dĂ©signĂ©s par les lettres A, T, C et G. Les deux brins sont complĂ©mentaires : "en face" d’un ’A’, il y a toujours un ’T’ et "en face" d’un ’C’, il y a toujours un ’G’. Pour simplifier le sujet, on va considĂ©rer qu’une molĂ©cule d’ADN est une chaĂźne de caractĂšres sur l’alphabet {A,C,G,T} (on s’intĂ©resse donc seulement Ă  un des deux brins). On parlera de sĂ©quence d’ADN.

Partie I - GĂ©nĂ©ration d’une sĂ©quence d’ADN⚓

On considùre la chaüne de caractùre seq=’ATCGTACGTACG’.

Q1. Que renvoie la commande seq[3] ? Que renvoie la commande seq[2:6] ?

Les fonctions que nous allons construire par la suite devront prendre en paramĂštre une chaĂźne de caractĂšres ne contenant que des ’A’, ’C’, ’G’ et ’T’ (ceci correspond Ă  une sĂ©quence d’ADN). Nous allons commencer par construire alĂ©atoirement une sĂ©quence d’ADN.

Pour gĂ©nĂ©rer alĂ©atoirement une sĂ©quence d’ADN composĂ©e de n caractĂšres, on utilisera le principe suivant.

  1. On commence par créer une chaßne de caractÚres vide.

  2. Puis on tire aléatoirement n chiffres compris entre 1 et 4 et

  3. si on obtient un 1, alors on ajoute un ’A’ à notre chaüne de caractùres ;

  4. si on obtient un 2, alors on ajoute un ’C’ à notre chaüne de caractùres ;

  5. si on obtient un 3, alors on ajoute un ’G’ à notre chaüne de caractùres ;

  6. si on obtient un 4, alors on ajoute un ’T’ à notre chaüne de caractùres.

  7. On renvoie la chaĂźne de caractĂšres ainsi construite.

Q2. Écrire une fonction generation() qui prend en paramĂštre un entier n et qui renvoie une chaĂźne de caractĂšres alĂ©atoires de longueur n ne contenant que des ’A’, ’C’, ’G’ et ’T’.

On pourra utiliser la fonctions randint() de random.

Q3. Que fait la fonction mystere(seq) qui prend en argument une sĂ©quence d’ADN ’seq’ (une chaĂźne de caractĂšres ne contenant que des ’A’, ’C’, ’G’ et ’T’) ?

Python
def mystere(seq):
    a,b,c,d = 0,0,0,0
    i = len(seq)−1
    while i>= 0:
        if seq[i]=='A':
            a += 1
            i −= 1
        elif seq[i]=='C':
            b += 1
            i −= 1
        elif seq[i]=='G':
            c += 1
            i −= 1
        else:
            d += 1
            i −= 1
        return [a*100/len(seq),b*100/len(seq),c*100/len(seq),d*100/len(seq)]

Q4. Quelle est la complexité de la fonction mystere() ?

Donner le nom de la variable permettant de montrer la terminaison de l’algorithme.

Partie II - Recherche d’un motif⚓

Soit une chaüne de caractùres S=’ACTGGTCACT’, on appelle sous-chaüne de caractùres de S unesuite de caractùres incluse dans S. Par exemple, ’TGG’ est une sous-chaüne de S mais ’TAG’ n’est pas une sous-chaüne de S. Objectif

Rechercher une sous-chaßne de caractÚres M de longueur m appelée motif dans une chaßne de caractÚres S de longueur n.

Il s’agit d’une problĂ©matique classique en informatique, qui rĂ©pond aux besoins de nombreuses applications.

On trouve plus de 100 algorithmes diffĂ©rents pour cette mĂȘme tĂąche, les plus cĂ©lĂšbres datant des annĂ©es 1970, mais plus de la moitiĂ© ont moins de 10 ans. Dans cette partie, nous allons d’abord nous intĂ©resser Ă  l’algorithme naĂŻf , puis Ă  deux autres algorithmes : l’algorithme de Knuth-Morris-Pratt, et un algorithme utilisant une structure de liste .

Les différentes sous-parties sont indépendantes.

II.1 - Algorithme naĂŻf⚓

Principe de l’algorithme naïf

On parcourt la chaĂźne. À chaque Ă©tape, on regarde si on a trouvĂ© le bon motif. Si ce n’est pas le cas, on recommence avec l’élĂ©ment suivant de la chaĂźne de caractĂšres. Cet algorithme a une complexitĂ© en O(nm) avec n, la taille de la chaĂźne de caractĂšre et m, la taille du motif.

Q5. Écrire une fonction recherche() qui Ă  une sous-chaĂźne de caractĂšres M et une chaĂźne de caractĂšres S renvoie -1 si M n’est pas dans S, et la position de la premiĂšre lettre de la chaĂźne de caractĂšres M si M est prĂ©sente dans S. Cet algorithme doit correspondre Ă  l’algorithme naĂŻf.

Q6. Combien faut-il d’opĂ©rations pour chercher un motif de 50 caractĂšres dans une sĂ©quence d’ADN en utilisant l’algorithme naĂŻf ? On supposera qu’une sĂ©quence d’ADN est composĂ©e de \(3 · 10^9\) caractĂšres. En combien de temps un ordinateur rĂ©alisant \(10^{12}\) opĂ©rations par seconde fait-il ce calcul ?

En gĂ©nĂ©tique, on utilise des algorithmes de recherche pour identifier les similaritĂ©s entre deux sĂ©quences d’ADN. Pour cela, on procĂšde de la maniĂšre suivante :

  • dĂ©couper la premiĂšre sĂ©quence d’ADN en morceaux de taille 50 ;

  • rechercher chaque morceau dans la deuxiĂšme sĂ©quence d’ADN.

Q7. En utilisant les calculs prĂ©cĂ©dents, combien de temps faut-il pour un ordinateur rĂ©alisant \(10^{12}\) opĂ©rations par seconde pour comparer deux sĂ©quences d’ADN avec l’algorithme naĂŻf ?

Vous semble-t-il intĂ©ressant d’utiliser l’algorithme de recherche naĂŻf ?

II.2 - Algorithme de Knuth-Morris-Pratt (1970)⚓

Lorsqu’un Ă©chec a lieu dans l’algorithme naĂŻf, c’est-Ă -dire lorsqu’un caractĂšre du motif est diffĂ©rent du caractĂšre correspondant dans la sĂ©quence d’ADN, la recherche reprend Ă  la position suivante en repartant au dĂ©but du motif. Si le caractĂšre qui a provoquĂ© l’échec n’est pas au dĂ©but du motif, cette recherche commence par comparer une partie du motif avec une partie de la sĂ©quence d’ADN qui a dĂ©jĂ  Ă©tĂ© comparĂ©e avec le motif. L’idĂ©e de dĂ©part de l’algorithme de Knuth-Morris-Pratt est d’éviter ces comparaisons inutiles. Pour cela, une fonction annexe qui recherche le plus long prĂ©fixe d’un motif qui soit aussi un suffixe de ce motif est utilisĂ©e.

Avant d’étudier l’algorithme de Knuth-Morris-Pratt nous allons dĂ©finir les notions de prĂ©fixe et suffixe.

II.2.a PrĂ©fixe et suffixe⚓

Un prĂ©fixe d’un motif M est un motif u, diffĂ©rent de M, qui est un dĂ©but de M. Par exemple, ’mo’ et ’m’ sont des prĂ©fixes de ’mot’, mais ’o’ n’est pas un prĂ©fixe de ’mot’ .

Un suffixe d’un motif M est un motif u, diffĂ©rent de M, qui est une fin de M.

Par exemple, ’ot’ et ’t’ sont des suffixes de ’mot’, mais ’mot’ n’est pas un suffixe de ’mot’.

Q8. Donner tous les prĂ©fixes et les suffixes du motif ’ACGTAC’.

Q9. Quel est le plus grand prĂ©fixe de ’ACGTAC’ qui soit aussi un suffixe ?

Quel est le plus grand prĂ©fixe de ’ACAACA’ qui soit aussi un suffixe ?

II.2.b Algorithme de Knuth-Morris-Pratt⚓

Nous rappelons que l’algorithme de Knuth-Morris-Pratt (KMP) est une fonction de recherche qui utilise une fonction annexe prenant en argument une chaüne de caractùres M dont on notera la longueur m.

Cette fonction annexe, appelĂ©e fonctionannexe(), doit permettre, pour chaque lettre Ă  la position i, de trouver le plus grand sous-mot de M qui finit par la lettre M[i] (c’est donc le plus grand suffixe de M[ :i+1]) qui soit aussi un prĂ©fixe de M. Le code de fonctionannexe() se trouve Ă  la question Q11 du DR 6.

Python
    def fonctionannexe(M):
        F=[0]
        i=1
        j=0
        while i < m :
            if M[i]=M[j] :
                F.append(j+1)
                i=i+1
                j=j+1
            else
                if j>0 :
                    j=F[j−1]
            else:
                F.append(0)
                i=i+1
        return F

Q10. Quel est le type de la sortie de la fonction fonctionannexe() ?

Q11. Une ou des erreurs de syntaxe s’est (se sont) glissĂ©e(s) dans la fonction fonctionannexe().

Identifier la ou les erreur(s) et corriger la fonction pour qu’il n’y ait plus de message d’erreur quand on exĂ©cute la fonction.

Q12. DĂ©crire l’exĂ©cution de la fonction fonctionannexe() lorsque M=’ACAACA’ en prĂ©cisant sur le pour les six premiers tours dans la boucle while, Ă  la sortie de la boucle, le contenu des variables : i, j et F.

Q13. L’algorithme KMP.

Python
1   def KMP(M,T):
2       F=fonctionannexe(M)
3       i=0
4       j=0
5       while i < len(T) :
6           if T[i]==M[j]:
7               if j==len(M)−1:
8                   return(i−j)
9               else:
10                  i=i+1
11                  j=j+1
12          else:
13              if j > 0:
14                  j=F[j−1]
15              else:
16                  i=i+1
17      return −1

Expliquer la ligne 2, expliquer les lignes 3 et 4.

Quelles lignes correspondent au cas oĂč on a trouvĂ© le mot ?

Que fait le programme dans ce cas ?

II.3 - Algorithme utilisant la structure de liste⚓

Une autre possibilitĂ© pour chercher un motif dans une chaĂźne de caractĂšres (ou sĂ©quence d’ADN) est de construire une liste contenant tous les sous-motifs de notre chaĂźne, triĂ©s par ordre alphabĂ©tique, puis de faire la recherche dans cette liste. Par exemple, Ă  la chaĂźne ’CATCG’, on peut lui associer la liste :

[’C’,’A’,’T’,’G’,’CA’,’AT’,’TC’,’CG’,’CAT’,’ATC’,’TCG’,’CATC’,’ATCG’,’CATCG’] que l’on peut ensuite trier pour obtenir la liste :

[’A’,’AT’,’ATC’,’ATCG’,’C’,’CA’,’CAT’,’CATC’,’CATCG’,’CG’,’G’,’T’,’TC’,’TCG’].

La premiÚre étape de cette méthode est donc de trier une liste.

Q14. Écrire une fonction triinsertion() de tri par insertion d’une liste de nombres.

Q15. Comment peut-on adapter la fonction triinsertion() Ă  une liste de chaĂźne de caractĂšres ?

AprÚs avoir obtenu une liste triée, on peut faire une recherche dichotomique dans cette nouvelle liste.

Q16. Écrire une fonction recherchedichotomique() de recherche dichotomique dans une liste de nombres triĂ©s.

Quel est l’intĂ©rĂȘt de ce type d’algorithme (on parlera de complexitĂ©) ?

Correction⚓

télécharger la correction