diff --git a/BINF2025_TP3.ipynb b/BINF2025_TP3.ipynb
index 61e87c2..43e04e5 100644
--- a/BINF2025_TP3.ipynb
+++ b/BINF2025_TP3.ipynb
@@ -1,481 +1,1013 @@
{
- "nbformat": 4,
- "nbformat_minor": 0,
- "metadata": {
- "colab": {
- "provenance": [],
- "authorship_tag": "ABX9TyNSXnqaXAUgZK9rmJ1TWbGo"
- },
- "kernelspec": {
- "name": "python3",
- "display_name": "Python 3"
- },
- "language_info": {
- "name": "python"
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "V09wQ1WIOmgn"
+ },
+ "source": [
+ "# BINF TP3 - Algorithmes d'alignement par paire"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "er6CtAyOxC6F"
+ },
+ "source": [
+ "Dans ce TP nous allons manipuler les algorithmes d'alignement par paire."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "kCJGGGYQ2GNi"
+ },
+ "source": [
+ "_________________________________________________________________________\n",
+ "\n",
+ "Hello Professor,\n",
+ "\n",
+ "Yes, the code of the few exercises showed underneath is made through chatGPT.\n",
+ "I was to lazy to write them and to be fair, we have a few project to do at the same time and I don't want redo a ING1.\n",
+ "Futhermore I would not be sure of finishing the tp elsewise because I code pretty slowly.\n",
+ "\n",
+ "But all the non code question where made by hand.\n",
+ "\n",
+ "And I always re-read the code to make sure I understand everything, make sure there is no weird things happening and that I understand everything.\n",
+ "\n",
+ "Still, I want to point out I didn't understand how to traduce those sequences x = \"đŽđ678264â\". And thus those parts are wrong.\n",
+ "\n",
+ "Sincerly,\n",
+ "\n",
+ "David GONCALVES\n",
+ "\n",
+ "_________________________________________________________________________"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "BqEa3BJ1xICM"
+ },
+ "source": [
+ "# Exercice 0 - Echauffement"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "qqiiq5bcxYvM"
+ },
+ "source": [
+ "Q1. Donnez le score de la superposition :\n",
+ "\n",
+ "| | |\n",
+ "| :---: | :---: |\n",
+ "x | ATGTCATGA---TAC |\n",
+ "y | AT--CTAAATGTTAC |\n",
+ "\n",
+ "\n",
+ "étant donne le schéma d'évaluation :\n",
+ "\n",
+ "| | A | T | G | C |\n",
+ "| :---: | :---: | :---: | :---: | :---: |\n",
+ "| **A** | 1 | -1 | -1 | -1 |\n",
+ "| **T** | -1 | 1 | -1 | -1 |\n",
+ "| **G** | -1 | -1 | 1 | -1 |\n",
+ "| **C** | -1 | -1 | -1 | 1 |\n",
+ "\n",
+ "et\n",
+ "\n",
+ "$\\gamma(g) = 0.5 |g| + 0.5$"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "kCJGGGYQ2GNi"
+ },
+ "source": [
+ "```markdown\n",
+ "We have 3 gaps for x and 2 gaps for y:\n",
+ "\n",
+ "y(5) = 0.5 * 5 = 2.5 (not affine, linear, so it's the same than doing them separately)\n",
+ "\n",
+ "and for the association we have:\n",
+ "\n",
+ "7 - 3 = 4\n",
+ "\n",
+ "so the score is:\n",
+ "\n",
+ "score(x, y) = 4 - 2.5 = 1.5\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "XyhXAhK-2NKJ"
+ },
+ "source": [
+ "Q2. Alignez les séquences suivantes avec l'algorithme de Levenshtein : x = ATG et y = ACTG."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "b9iovhyZ2bXw"
+ },
+ "source": [
+ "```markdown\n",
+ "\n",
+ " O A T G\n",
+ "O 0 1 2 3\n",
+ "A 1 0 1 2\n",
+ "C 2 1 1 2\n",
+ "T 3 2 1 2\n",
+ "G 4 3 2 1\n",
+ "\n",
+ " O A T G\n",
+ "O 0 - - -\n",
+ "A | \\ - -\n",
+ "C | | \\ -\n",
+ "T | | \\ \\\n",
+ "G | | | \\\n",
+ "\n",
+ "So the we do:\n",
+ "\n",
+ "GG - TT - CA - AA - 00\n",
+ "GTCA\n",
+ "Insertion of C\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "OV_YaQHr2elB"
+ },
+ "source": [
+ "Q3.\tAlignez les séquences suivantes avec l'algorithme de Needleman-Wunsch global x = TAT et y = ATGAC en considérant le schéma d'évaluation suivant\n",
+ "\n",
+ "| | A | T | G | C |\n",
+ "| :---: | :---: | :---: | :---: | :---: |\n",
+ "| **A** | 1 | -0.5 | -0.5 | -0.5 |\n",
+ "| **T** | -0.5 | 1 | -0.5 | -0.5 |\n",
+ "| **G** | -0.5 | -0.5 | 1 | -0.5 |\n",
+ "| **C** | -0.5 | -0.5 | -0.5 | 1 |\n",
+ "\n",
+ "et\n",
+ "\n",
+ "$\\gamma(g) = 0.5 |g|$\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "g_MrecVs3Nrw"
+ },
+ "source": [
+ "```markdown\n",
+ " 0 A T G A C\n",
+ "0 0 -0.5 -1 -1.5 -2 -2.5\n",
+ "T -0.5 -0.5 0.5 0 -0.5 -1\n",
+ "A -1 0.5 0 0 1 -0.5\n",
+ "T -1.5 0 1.5 1 0.5 0.5 \n",
+ "\n",
+ " 0 A T G A C\n",
+ "0 0 - - - - -\n",
+ "T | \\ \\ - - -\n",
+ "A | \\ \\ - \\ -\n",
+ "T | | \\ - - \\\n",
+ "\n",
+ "_T_AT\n",
+ "ATGAC\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "y1YF-G6E3Qoo"
+ },
+ "source": [
+ "Q4. Alignez les séquences suivantes avec l'algorithme de Smith-Waterman x = TTGG y = ATGAC en utilisant le schéma d'évaluation de la question précédente.\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "LLMECocb3pgI"
+ },
+ "source": [
+ "```markdown\n",
+ " 0 A T G A C\n",
+ "0 0 -0.5 -1 -1.5 -2 -2.5\n",
+ "T -0.5 -0.5 0.5 0 -0.5 -1\n",
+ "T -1 -1 0.5 0 -0.5 -1\n",
+ "G -1.5 -1.5 0 1.5 1 0.5\n",
+ "G -2 -2 -0.5 1 1 0.5\n",
+ "\n",
+ " 0 A T G A C\n",
+ "0 0 - - - - -\n",
+ "T | \\ \\ - - -\n",
+ "T | \\ \\ \\ \\ \\\n",
+ "G | \\ | \\ - -\n",
+ "G | \\ | \\ \\ \\\n",
+ "\n",
+ "\n",
+ "\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "46gw0avh3wGw"
+ },
+ "source": [
+ "# Exercice 1 : Algorithme de Levenshtein - version récursive"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "ZKc09Kyg4a6v"
+ },
+ "source": [
+ "Q1. Ecrivez une fonction\n",
+ "\n",
+ "levenshtein(x: str, y: str) -> int\n",
+ "\n",
+ "qui retourne la distance de Levenshtein entre les séquences x et y en utilisant la version récursive de l'algorithme."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {
+ "id": "FJR69IEQ4aHv"
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Levenshtein Distance: 4\n",
+ "Aligned X: ATGT-CATGATAC\n",
+ "Aligned Y: ATCTAAATGTTAC\n"
+ ]
}
+ ],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "def levenshtein(x: str, y: str):\n",
+ " m, n = len(x), len(y)\n",
+ " \n",
+ " # Initialize matrices\n",
+ " S = np.zeros((m + 1, n + 1), dtype=int)\n",
+ " B = np.empty((m + 1, n + 1), dtype=object)\n",
+ " \n",
+ " # Fill first row and first column\n",
+ " for i in range(1, m + 1):\n",
+ " S[i, 0] = i\n",
+ " B[i, 0] = (i - 1, 0) # Up\n",
+ " \n",
+ " for j in range(1, n + 1):\n",
+ " S[0, j] = j\n",
+ " B[0, j] = (0, j - 1) # Left\n",
+ " \n",
+ " # Fill matrices\n",
+ " for i in range(1, m + 1):\n",
+ " for j in range(1, n + 1):\n",
+ " if x[i - 1] == y[j - 1]: # Match\n",
+ " S[i, j] = S[i - 1, j - 1]\n",
+ " B[i, j] = (i - 1, j - 1) # Diagonal\n",
+ " else:\n",
+ " options = [(S[i - 1, j - 1], (i - 1, j - 1)), # Substitution\n",
+ " (S[i, j - 1], (i, j - 1)), # Insertion\n",
+ " (S[i - 1, j], (i - 1, j))] # Deletion\n",
+ " \n",
+ " S[i, j], B[i, j] = min(options, key=lambda t: t[0])\n",
+ " S[i, j] += 1\n",
+ " \n",
+ " # Traceback to find alignment\n",
+ " i, j = m, n\n",
+ " sx, sy = \"\", \"\"\n",
+ " \n",
+ " while (i, j) != (0, 0):\n",
+ " prev_i, prev_j = B[i, j]\n",
+ " if prev_i == i - 1 and prev_j == j - 1:\n",
+ " sx = x[i - 1] + sx\n",
+ " sy = y[j - 1] + sy\n",
+ " elif prev_i == i - 1:\n",
+ " sx = x[i - 1] + sx\n",
+ " sy = \"-\" + sy\n",
+ " else:\n",
+ " sx = \"-\" + sx\n",
+ " sy = y[j - 1] + sy\n",
+ " i, j = prev_i, prev_j\n",
+ " \n",
+ " return S[m, n], sx, sy\n",
+ "\n",
+ "# Example usage\n",
+ "x = \"ATGTCATGA---TAC\".replace(\"-\", \"\") # Removing gaps from input\n",
+ "y = \"AT--CTAAATGTTAC\".replace(\"-\", \"\")\n",
+ "distance, aligned_x, aligned_y = levenshtein(x, y)\n",
+ "\n",
+ "print(\"Levenshtein Distance:\", distance)\n",
+ "print(\"Aligned X:\", aligned_x)\n",
+ "print(\"Aligned Y:\", aligned_y)\n"
+ ]
},
- "cells": [
- {
- "cell_type": "markdown",
- "source": [
- "# BINF TP3 - Algorithmes d'alignement par paire"
- ],
- "metadata": {
- "id": "V09wQ1WIOmgn"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Dans ce TP nous allons manipuler les algorithmes d'alignement par paire."
- ],
- "metadata": {
- "id": "er6CtAyOxC6F"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "# Exercice 0 - Echauffement"
- ],
- "metadata": {
- "id": "BqEa3BJ1xICM"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q1. Donnez le score de la superposition :\n",
- "\n",
- "| | |\n",
- "| :---: | :---: |\n",
- "x | ATGTCATGA---TAC |\n",
- "y | AT--CTAAATGTTAC |\n",
- "\n",
- "\n",
- "étant donne le schéma d'évaluation :\n",
- "\n",
- "| | A | T | G | C |\n",
- "| :---: | :---: | :---: | :---: | :---: |\n",
- "| **A** | 1 | -1 | -1 | -1 |\n",
- "| **T** | -1 | 1 | -1 | -1 |\n",
- "| **G** | -1 | -1 | 1 | -1 |\n",
- "| **C** | -1 | -1 | -1 | 1 |\n",
- "\n",
- "et\n",
- "\n",
- "$\\gamma(g) = 0.5 |g| + 0.5$"
- ],
- "metadata": {
- "id": "qqiiq5bcxYvM"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "```markdown\n",
- "Votre réponse ici\n",
- "```"
- ],
- "metadata": {
- "id": "kCJGGGYQ2GNi"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q2. Alignez les séquences suivantes avec l'algorithme de Levenshtein : x = ATG et y = ACTG."
- ],
- "metadata": {
- "id": "XyhXAhK-2NKJ"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "```markdown\n",
- "Votre réponse ici\n",
- "```"
- ],
- "metadata": {
- "id": "b9iovhyZ2bXw"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q3.\tAlignez les séquences suivantes avec l'algorithme de Needleman-Wunsch global x = TAT et y = ATGAC en considérant le schéma d'évaluation suivant\n",
- "\n",
- "| | A | T | G | C |\n",
- "| :---: | :---: | :---: | :---: | :---: |\n",
- "| **A** | 1 | -0.5 | -0.5 | -0.5 |\n",
- "| **T** | -0.5 | 1 | -0.5 | -0.5 |\n",
- "| **G** | -0.5 | -0.5 | 1 | -0.5 |\n",
- "| **C** | -0.5 | -0.5 | -0.5 | 1 |\n",
- "\n",
- "et\n",
- "\n",
- "$\\gamma(g) = 0.5 |g|$\n"
- ],
- "metadata": {
- "id": "OV_YaQHr2elB"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "```markdown\n",
- "Votre réponse ici\n",
- "```"
- ],
- "metadata": {
- "id": "g_MrecVs3Nrw"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q4. Alignez les séquences suivantes avec l'algorithme de Smith-Waterman x = TTGG y = ATGAC en utilisant le schéma d'évaluation de la question précédente.\n"
- ],
- "metadata": {
- "id": "y1YF-G6E3Qoo"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "```markdown\n",
- "Votre réponse ici\n",
- "```"
- ],
- "metadata": {
- "id": "LLMECocb3pgI"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "# Exercice 1 : Algorithme de Levenshtein - version récursive"
- ],
- "metadata": {
- "id": "46gw0avh3wGw"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q1. Ecrivez une fonction\n",
- "\n",
- "levenshtein(x: str, y: str) -> int\n",
- "\n",
- "qui retourne la distance de Levenshtein entre les séquences x et y en utilisant la version récursive de l'algorithme."
- ],
- "metadata": {
- "id": "ZKc09Kyg4a6v"
- }
- },
- {
- "cell_type": "code",
- "source": [
- "#Votre code ici"
- ],
- "metadata": {
- "id": "FJR69IEQ4aHv"
- },
- "execution_count": null,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q2. Vous pouvez tester votre code sur les exemples suivants:\n",
- "\n",
- "\n",
- "* $L('CCAG', 'CA') = 2$\n",
- "* $L('CCGT', 'CGTCA') = 3$\n",
- "* $L(AY678264^*, OQ870305^*) = 310$\n",
- "\n",
- "$^*$ ids genbank de deux sequences."
- ],
- "metadata": {
- "id": "arFVwA6E5NWn"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "# Exercice 2 : Algorithme de Smith-Waterman - version itérative"
- ],
- "metadata": {
- "id": "erCpfG7O7BV-"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q1. Ecrivez la fonction\n",
- "\n",
- "sw_fwd(x: str, y: str, cmap: dict, sigma: array, (go, ge): list) -> (array, array)\n",
- "\n",
- "qui construit les matrices $S$ et $B$ en utilisant l'algorithme de Smith-Waterman pour aligner les séquences x et y suivant le schéma d'évaluation donné par la matrice de substitution $\\Sigma$ et la fonction d'évaluation des trous $\\gamma(n)= g_o + g_e \\times n$. Le dictionnaire cmap donne la position des différents nucléotides dans la matrice $\\Sigma$. La fonction retourne la paire de matrices de score $S$ et de retour $B$."
- ],
- "metadata": {
- "id": "rv2Y78y37IOd"
- }
- },
- {
- "cell_type": "code",
- "source": [
- "#Votre code ici"
- ],
- "metadata": {
- "id": "njn3JB0b-WHj"
- },
- "execution_count": null,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q2. Ecrivez la fonction\n",
- "\n",
- "sw_bwd(x: str, y: str, S: array, B: array) -> (str, str, float)\n",
- "\n",
- "qui effectue l'etape de retour de l'algorithme de Smith-Waterman etant donné les séquences $x$ et $y$ et les matrices de score $S$ et de retour $B$. La fonction retourne un tuple contenant les alignements des séquences x et y et le score de l'alignement."
- ],
- "metadata": {
- "id": "55n8mt9U-Wai"
- }
- },
- {
- "cell_type": "code",
- "source": [
- "#Votre code ici"
- ],
- "metadata": {
- "id": "ij9JDpBm_UZ7"
- },
- "execution_count": null,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q3. Vous pouvez tester votre code en utilisant le schéma d'évaluation suivant :"
- ],
- "metadata": {
- "id": "kwmxg2dxAiwS"
- }
- },
- {
- "cell_type": "code",
- "source": [
- "cmap = {\"A\": 0, \"T\": 1, \"G\": 2, \"C\": 3}\n",
- "m = np.array([[1, -0.5, -0.5, -0.5],\n",
- " [-0.5, 1, -0.5, -0.5],\n",
- " [-0.5, -0.5, 1, -0.5],\n",
- " [-0.5, -0.5, -0.5, 1]])\n",
- "go = 0\n",
- "ge = 0.5"
- ],
- "metadata": {
- "id": "JUtYRFTBAwwZ"
- },
- "execution_count": null,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "source": [
- "* $SW('TCGC', 'CTTAG')$ retourne un score de $1.5$ Ă la position $(3,5)$ et l'alignement"
- ],
- "metadata": {
- "id": "eMGh4K5aIFxE"
- }
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "arFVwA6E5NWn"
+ },
+ "source": [
+ "Q2. Vous pouvez tester votre code sur les exemples suivants:\n",
+ "\n",
+ "\n",
+ "* $L('CCAG', 'CA') = 2$\n",
+ "* $L('CCGT', 'CGTCA') = 3$\n",
+ "* $L(AY678264^*, OQ870305^*) = 310$\n",
+ "\n",
+ "$^*$ ids genbank de deux sequences."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 37,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Levenshtein Distance: 2\n",
+ "Aligned X: CCAG\n",
+ "Aligned Y: -CA-\n"
+ ]
+ }
+ ],
+ "source": [
+ "x = \"CCAG\"\n",
+ "y = \"CA\"\n",
+ "distance, aligned_x, aligned_y = levenshtein(x, y)\n",
+ "print(\"Levenshtein Distance:\", distance)\n",
+ "print(\"Aligned X:\", aligned_x)\n",
+ "print(\"Aligned Y:\", aligned_y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 38,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Levenshtein Distance: 3\n",
+ "Aligned X: CCGT--\n",
+ "Aligned Y: -CGTCA\n"
+ ]
+ }
+ ],
+ "source": [
+ "x = \"CCGT\"\n",
+ "y = \"CGTCA\"\n",
+ "distance, aligned_x, aligned_y = levenshtein(x, y)\n",
+ "print(\"Levenshtein Distance:\", distance)\n",
+ "print(\"Aligned X:\", aligned_x)\n",
+ "print(\"Aligned Y:\", aligned_y)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 39,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Levenshtein Distance: 7\n",
+ "Aligned X: đŽđ678264â\n",
+ "Aligned Y: đđ870305â\n"
+ ]
+ }
+ ],
+ "source": [
+ "x = \"đŽđ678264â\"\n",
+ "y = \"đđ870305â\"\n",
+ "distance, aligned_x, aligned_y = levenshtein(x, y)\n",
+ "print(\"Levenshtein Distance:\", distance)\n",
+ "print(\"Aligned X:\", aligned_x)\n",
+ "print(\"Aligned Y:\", aligned_y)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "erCpfG7O7BV-"
+ },
+ "source": [
+ "# Exercice 2 : Algorithme de Smith-Waterman - version itérative"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "rv2Y78y37IOd"
+ },
+ "source": [
+ "Q1. Ecrivez la fonction\n",
+ "\n",
+ "sw_fwd(x: str, y: str, cmap: dict, sigma: array, (go, ge): list) -> (array, array)\n",
+ "\n",
+ "qui construit les matrices $S$ et $B$ en utilisant l'algorithme de Smith-Waterman pour aligner les séquences x et y suivant le schéma d'évaluation donné par la matrice de substitution $\\Sigma$ et la fonction d'évaluation des trous $\\gamma(n)= g_o + g_e \\times n$. Le dictionnaire cmap donne la position des différents nucléotides dans la matrice $\\Sigma$. La fonction retourne la paire de matrices de score $S$ et de retour $B$."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 40,
+ "metadata": {
+ "id": "njn3JB0b-WHj"
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "def sw_fwd(x: str, y: str, cmap: dict, sigma: np.ndarray, penalties: list):\n",
+ " \"\"\"\n",
+ " Implements the Smith-Waterman algorithm for local sequence alignment.\n",
+ "\n",
+ " Parameters:\n",
+ " - x (str): First sequence\n",
+ " - y (str): Second sequence\n",
+ " - cmap (dict): Mapping of nucleotide to index in sigma\n",
+ " - sigma (np.ndarray): Substitution matrix\n",
+ " - penalties (list): [gap opening (go), gap extension (ge)]\n",
+ "\n",
+ " Returns:\n",
+ " - S (np.ndarray): Score matrix\n",
+ " - B (np.ndarray): Backtracking matrix\n",
+ " \"\"\"\n",
+ " go, ge = penalties\n",
+ " len_x, len_y = len(x), len(y)\n",
+ " \n",
+ " # Initialize matrices\n",
+ " S = np.zeros((len_x + 1, len_y + 1))\n",
+ " B = np.zeros((len_x + 1, len_y + 1), dtype=int)\n",
+ " \n",
+ " # Fill matrices\n",
+ " for i in range(1, len_x + 1):\n",
+ " for j in range(1, len_y + 1):\n",
+ " match = S[i - 1, j - 1] + sigma[cmap[x[i - 1]], cmap[y[j - 1]]]\n",
+ " delete = S[i - 1, j] + (go if B[i - 1, j] != 2 else ge) # Gap penalty\n",
+ " insert = S[i, j - 1] + (go if B[i, j - 1] != 3 else ge)\n",
+ " S[i, j] = max(0, match, delete, insert)\n",
+ "\n",
+ " # Assign backtracking directions\n",
+ " if S[i, j] == 0:\n",
+ " B[i, j] = 0 # Stop (local alignment)\n",
+ " elif S[i, j] == match:\n",
+ " B[i, j] = 1 # Diagonal (match/mismatch)\n",
+ " elif S[i, j] == delete:\n",
+ " B[i, j] = 2 # Up (gap in y)\n",
+ " elif S[i, j] == insert:\n",
+ " B[i, j] = 3 # Left (gap in x)\n",
+ "\n",
+ " return S, B"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 41,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Score Matrix (S):\n",
+ "[[0. 0. 0. 0. 0. 0. ]\n",
+ " [0. 0. 1. 1. 1. 1.5]\n",
+ " [0. 1. 1. 1. 1. 1.5]\n",
+ " [0. 1. 1.5 1.5 1.5 2. ]\n",
+ " [0. 1.5 2. 2. 2. 2. ]]\n",
+ "\n",
+ "Backtracking Matrix (B):\n",
+ "[[0 0 0 0 0 0]\n",
+ " [0 0 1 1 3 3]\n",
+ " [0 1 2 2 2 2]\n",
+ " [0 2 2 2 2 1]\n",
+ " [0 2 2 2 2 2]]\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Define cmap and sigma for DNA sequences\n",
+ "cmap = {\"A\": 0, \"T\": 1, \"G\": 2, \"C\": 3}\n",
+ "m = np.array([[1, -0.5, -0.5, -0.5],\n",
+ " [-0.5, 1, -0.5, -0.5],\n",
+ " [-0.5, -0.5, 1, -0.5],\n",
+ " [-0.5, -0.5, -0.5, 1]])\n",
+ "go = 0\n",
+ "ge = 0.5\n",
+ "\n",
+ "# Example sequences\n",
+ "# Sequences\n",
+ "x = \"TCGC\"\n",
+ "y = \"CTTAG\"\n",
+ "\n",
+ "# Run Smith-Waterman\n",
+ "S, B = sw_fwd(x, y, cmap, sigma, (go, ge)) # Gap opening = -2, gap extension = -1\n",
+ "\n",
+ "print(\"Score Matrix (S):\")\n",
+ "print(S)\n",
+ "print(\"\\nBacktracking Matrix (B):\")\n",
+ "print(B)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "55n8mt9U-Wai"
+ },
+ "source": [
+ "Q2. Ecrivez la fonction\n",
+ "\n",
+ "sw_bwd(x: str, y: str, S: array, B: array) -> (str, str, float)\n",
+ "\n",
+ "qui effectue l'etape de retour de l'algorithme de Smith-Waterman etant donné les séquences $x$ et $y$ et les matrices de score $S$ et de retour $B$. La fonction retourne un tuple contenant les alignements des séquences x et y et le score de l'alignement."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 42,
+ "metadata": {
+ "id": "ij9JDpBm_UZ7"
+ },
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "\n",
+ "def sw_bwd(x: str, y: str, S: np.ndarray, B: np.ndarray) -> (str, str, float):\n",
+ " \"\"\"\n",
+ " Performs the traceback step of the Smith-Waterman algorithm.\n",
+ "\n",
+ " Parameters:\n",
+ " - x (str): First sequence\n",
+ " - y (str): Second sequence\n",
+ " - S (np.ndarray): Score matrix\n",
+ " - B (np.ndarray): Backtracking matrix\n",
+ "\n",
+ " Returns:\n",
+ " - (str, str, float): Aligned sequences and the final alignment score\n",
+ " \"\"\"\n",
+ " # Find the maximum score in S (starting point for traceback)\n",
+ " i, j = np.unravel_index(np.argmax(S), S.shape)\n",
+ " max_score = S[i, j]\n",
+ "\n",
+ " aligned_x = []\n",
+ " aligned_y = []\n",
+ "\n",
+ " # Traceback\n",
+ " while B[i, j] != 0 and i > 0 and j > 0:\n",
+ " if B[i, j] == 1: # Diagonal (match/mismatch)\n",
+ " aligned_x.append(x[i - 1])\n",
+ " aligned_y.append(y[j - 1])\n",
+ " i -= 1\n",
+ " j -= 1\n",
+ " elif B[i, j] == 2: # Up (gap in y)\n",
+ " aligned_x.append(x[i - 1])\n",
+ " aligned_y.append('-')\n",
+ " i -= 1\n",
+ " elif B[i, j] == 3: # Left (gap in x)\n",
+ " aligned_x.append('-')\n",
+ " aligned_y.append(y[j - 1])\n",
+ " j -= 1\n",
+ "\n",
+ " # Reverse alignments (since we built them backwards)\n",
+ " aligned_x = ''.join(aligned_x[::-1])\n",
+ " aligned_y = ''.join(aligned_y[::-1])\n",
+ "\n",
+ " return aligned_x, aligned_y, max_score\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "kwmxg2dxAiwS"
+ },
+ "source": [
+ "Q3. Vous pouvez tester votre code en utilisant le schéma d'évaluation suivant :"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 43,
+ "metadata": {
+ "id": "JUtYRFTBAwwZ"
+ },
+ "outputs": [],
+ "source": [
+ "cmap = {\"A\": 0, \"T\": 1, \"G\": 2, \"C\": 3}\n",
+ "m = np.array([[1, -0.5, -0.5, -0.5],\n",
+ " [-0.5, 1, -0.5, -0.5],\n",
+ " [-0.5, -0.5, 1, -0.5],\n",
+ " [-0.5, -0.5, -0.5, 1]])\n",
+ "go = 0\n",
+ "ge = 0.5"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 44,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Alignment Score: 2.0\n",
+ "Aligned x: T-CG\n",
+ "Aligned y: TA-G\n",
+ "Max Score: 2.0 at Position: (3, 5)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Sequences\n",
+ "x = \"TCGC\"\n",
+ "y = \"CTTAG\"\n",
+ "\n",
+ "# Step 1: Compute S and B matrices\n",
+ "S, B = sw_fwd(x, y, cmap, sigma, (go, ge))\n",
+ "\n",
+ "# Step 2: Perform traceback to get alignment and score\n",
+ "aligned_x, aligned_y, score = sw_bwd(x, y, S, B)\n",
+ "\n",
+ "# Step 3: Print results\n",
+ "print(f\"Alignment Score: {score}\")\n",
+ "print(f\"Aligned x: {aligned_x}\")\n",
+ "print(f\"Aligned y: {aligned_y}\")\n",
+ "\n",
+ "# Step 4: Check best score position\n",
+ "max_score = np.max(S)\n",
+ "best_position = np.unravel_index(np.argmax(S), S.shape)\n",
+ "print(f\"Max Score: {max_score} at Position: {best_position}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "eMGh4K5aIFxE"
+ },
+ "source": [
+ "* $SW('TCGC', 'CTTAG')$ retourne un score de $1.5$ Ă la position $(3,5)$ et l'alignement"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 45,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 60
},
+ "id": "joHNwJ9AIf6F",
+ "outputId": "a9206810-a083-4d86-8b14-38183f1dd80c"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "source": [
- "HTML(\"
\")"
+ "data": {
+ "text/html": [
+ ""
],
- "metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 60
- },
- "id": "joHNwJ9AIf6F",
- "outputId": "a9206810-a083-4d86-8b14-38183f1dd80c"
- },
- "execution_count": null,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/plain": [
- ""
- ],
- "text/html": [
- ""
- ]
- },
- "metadata": {},
- "execution_count": 18
- }
+ "text/plain": [
+ ""
]
+ },
+ "execution_count": 45,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from IPython.core.display import HTML\n",
+ "\n",
+ "HTML(\"\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "JJlU5yvZI43D"
+ },
+ "source": [
+ "* $SW(AY678264^*, OQ870305^*)$ retourne un score de $342.1$ Ă la position $(708,717)$ et l'alignement"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 46,
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "KeyError",
+ "evalue": "'O'",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[1;31mKeyError\u001b[0m Traceback (most recent call last)",
+ "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_7144\\39445628.py\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;31m# Step 1: Compute S and B matrices\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[0mS\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mB\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msw_fwd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0my\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcmap\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msigma\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mgo\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mge\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 7\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;31m# Step 2: Perform traceback to get alignment and score\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;32m~\\AppData\\Local\\Temp\\ipykernel_7144\\321429888.py\u001b[0m in \u001b[0;36msw_fwd\u001b[1;34m(x, y, cmap, sigma, penalties)\u001b[0m\n\u001b[0;32m 26\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlen_x\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 27\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlen_y\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 28\u001b[1;33m \u001b[0mmatch\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mS\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mj\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0msigma\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mcmap\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mx\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcmap\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mj\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 29\u001b[0m \u001b[0mdelete\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mS\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mj\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mgo\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mB\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mj\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m!=\u001b[0m \u001b[1;36m2\u001b[0m \u001b[1;32melse\u001b[0m \u001b[0mge\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# Gap penalty\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 30\u001b[0m \u001b[0minsert\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mS\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mj\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mgo\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mB\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mi\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mj\u001b[0m \u001b[1;33m-\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m!=\u001b[0m \u001b[1;36m3\u001b[0m \u001b[1;32melse\u001b[0m \u001b[0mge\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+ "\u001b[1;31mKeyError\u001b[0m: 'O'"
+ ]
+ }
+ ],
+ "source": [
+ "# Sequences\n",
+ "x = \"AY678264*\"\n",
+ "y = \"OQ870305*\"\n",
+ "\n",
+ "# Step 1: Compute S and B matrices\n",
+ "S, B = sw_fwd(x, y, cmap, sigma, (go, ge))\n",
+ "\n",
+ "# Step 2: Perform traceback to get alignment and score\n",
+ "aligned_x, aligned_y, score = sw_bwd(x, y, S, B)\n",
+ "\n",
+ "# Step 3: Print results\n",
+ "print(f\"Alignment Score: {score}\")\n",
+ "print(f\"Aligned x: {aligned_x}\")\n",
+ "print(f\"Aligned y: {aligned_y}\")\n",
+ "\n",
+ "# Step 4: Check best score position\n",
+ "max_score = np.max(S)\n",
+ "best_position = np.unravel_index(np.argmax(S), S.shape)\n",
+ "print(f\"Max Score: {max_score} at Position: {best_position}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 47,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 80
},
+ "id": "HUELvWKMFtIO",
+ "outputId": "976bab6f-f1fc-4c5a-c69c-8de02fc838d0"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "source": [
- "* $SW(AY678264^*, OQ870305^*)$ retourne un score de $342.1$ Ă la position $(708,717)$ et l'alignement"
- ],
- "metadata": {
- "id": "JJlU5yvZI43D"
- }
- },
- {
- "cell_type": "code",
- "source": [
- "from IPython.display import HTML\n",
- "HTML(\"| x: | ATGGTGAGCAAGGGCGAGGAGGATAACATGGCCATCATCAAGGAGTTCATGCGCTTCAAGGTGC-A-CATGGAGGGCTCCGTGAACGGCCACGAGTTCGAGATCGAG---GGCGAGGGCGAGGGC--CGCC-CCTACGAGGGCACCCAGACCGC-CAAGCTGAAGGTG-ACCA-AGG---G-TGGCC---CCCT-GCCCTTCGCCT-GGGA-CATCCTGTCC--C--C-T-CAGTTCATGT-A-CGGCT-CCAAGGCCTACGTG-A--AGCAC--C--C--C--G-CCGACATCCCCG-A--CTAC-T--TGAAGCTG-TCCTTC--C--C-----CGA-GG--GCTTCAAGTGGGAGCG-CGTGATGAACTTCGAGGACGGCGGCGTGGTG-ACCG--T-GA-C-CCAGGAC-TC--CTCCCTGCAGGACGGCGAGTTCATCTACAAGGTG---AAGCTGCGCGGCACCAACTTCCCCT-CCGACGGCCCCGTA-ATGCA-GAAGAAGACCATGGGCTG--GGA-GGCCTCCTCCGAGCGGATGTACCCCGAGGA-CGGCGCC-CTGAAGGGCGAGATCAAGCAGA-GGCTGAAGC-TGAAGGACGGCGGCCACTACGACGCTGAGGTCAAGACCACCTACA-AGGCCAAGAAG-CCCGTGCAGCTGCCCGGC-GCCTACAACGTCAACATCAAGT-TG----GA-CATCACCTCCCACAACGAGGA-CTAC-A-C-CA---T-C-G-TGGAACAGTACG-AACGCGCCGAGGGCCGCCACTCCAC-CGGCGGCATGGACGAGCTGTACAAG |
|---|
| y: | ATGGTGAGCAAGGGCGAGGA-G----C-T-G--TTCA-C-CGG-GGTGGTGCCCATCCTGGT-CGAGC-TGGACGGCGACGTAAACGGCCACAAGTTC-AG--CGTGTCCGGCGAGGGCGAGGGCGATGCCACCTAC---GGCAAGCTGACC-CTGAAG-TTCATTTGCACCACCGGCAAGCTGCCCGTGCCCTGGCCC-AC-CCTCGTGACCACCCTGACCTACGGCGTGCAGTGC-T-TCAGCCGCTACCCCGACC-ACATGAAGCAGCACGACTTCTTCAAGTCCGCCATGCCCGAAGGCTACGTCCAGGAGC-GCACCATCTTCTTCAAGGACGACGGCAACTACAAGA-CCCGCGCCGAGGTGAAGTTCGAGGGCGACACCCTGGTGAACCGCATCGAGCTGAAGGGCATCGACTTCAAGGAGGACGGC-A--ACATC--C-TGGGGCACAAGCTG-G-AGTA-CAACTACAACAGCC-ACAACGTC-TATAT-CATG--GCCGA-CAA--GCAGAAGAACGG-CA--T-C-A-AGG-TGAACTTC-AAGATC--CGCCAC--AA---C---ATCGAG--GACGGC---AGCGTGCAGCTCGCCGACCACTACCA-GC--A-G--AACACC-CC--CATCGGCGACG--GCCCCGTGCTGCTGCCCGACAACC-ACTACCTGAGCACCCAGTCCGCCCTGAGCAA-A-GACCC-CAACGAGAAGC-GCGATCACATGGTCCTGCTGG---AGTTCGTGAC-CGCC----GCCGGGA-T-CACTC-TCGGCATGGACGAGCTGTACAAG |
|---|
\")"
+ "data": {
+ "text/html": [
+ "| x: | ATGGTGAGCAAGGGCGAGGAGGATAACATGGCCATCATCAAGGAGTTCATGCGCTTCAAGGTGC-A-CATGGAGGGCTCCGTGAACGGCCACGAGTTCGAGATCGAG---GGCGAGGGCGAGGGC--CGCC-CCTACGAGGGCACCCAGACCGC-CAAGCTGAAGGTG-ACCA-AGG---G-TGGCC---CCCT-GCCCTTCGCCT-GGGA-CATCCTGTCC--C--C-T-CAGTTCATGT-A-CGGCT-CCAAGGCCTACGTG-A--AGCAC--C--C--C--G-CCGACATCCCCG-A--CTAC-T--TGAAGCTG-TCCTTC--C--C-----CGA-GG--GCTTCAAGTGGGAGCG-CGTGATGAACTTCGAGGACGGCGGCGTGGTG-ACCG--T-GA-C-CCAGGAC-TC--CTCCCTGCAGGACGGCGAGTTCATCTACAAGGTG---AAGCTGCGCGGCACCAACTTCCCCT-CCGACGGCCCCGTA-ATGCA-GAAGAAGACCATGGGCTG--GGA-GGCCTCCTCCGAGCGGATGTACCCCGAGGA-CGGCGCC-CTGAAGGGCGAGATCAAGCAGA-GGCTGAAGC-TGAAGGACGGCGGCCACTACGACGCTGAGGTCAAGACCACCTACA-AGGCCAAGAAG-CCCGTGCAGCTGCCCGGC-GCCTACAACGTCAACATCAAGT-TG----GA-CATCACCTCCCACAACGAGGA-CTAC-A-C-CA---T-C-G-TGGAACAGTACG-AACGCGCCGAGGGCCGCCACTCCAC-CGGCGGCATGGACGAGCTGTACAAG |
|---|
| y: | ATGGTGAGCAAGGGCGAGGA-G----C-T-G--TTCA-C-CGG-GGTGGTGCCCATCCTGGT-CGAGC-TGGACGGCGACGTAAACGGCCACAAGTTC-AG--CGTGTCCGGCGAGGGCGAGGGCGATGCCACCTAC---GGCAAGCTGACC-CTGAAG-TTCATTTGCACCACCGGCAAGCTGCCCGTGCCCTGGCCC-AC-CCTCGTGACCACCCTGACCTACGGCGTGCAGTGC-T-TCAGCCGCTACCCCGACC-ACATGAAGCAGCACGACTTCTTCAAGTCCGCCATGCCCGAAGGCTACGTCCAGGAGC-GCACCATCTTCTTCAAGGACGACGGCAACTACAAGA-CCCGCGCCGAGGTGAAGTTCGAGGGCGACACCCTGGTGAACCGCATCGAGCTGAAGGGCATCGACTTCAAGGAGGACGGC-A--ACATC--C-TGGGGCACAAGCTG-G-AGTA-CAACTACAACAGCC-ACAACGTC-TATAT-CATG--GCCGA-CAA--GCAGAAGAACGG-CA--T-C-A-AGG-TGAACTTC-AAGATC--CGCCAC--AA---C---ATCGAG--GACGGC---AGCGTGCAGCTCGCCGACCACTACCA-GC--A-G--AACACC-CC--CATCGGCGACG--GCCCCGTGCTGCTGCCCGACAACC-ACTACCTGAGCACCCAGTCCGCCCTGAGCAA-A-GACCC-CAACGAGAAGC-GCGATCACATGGTCCTGCTGG---AGTTCGTGAC-CGCC----GCCGGGA-T-CACTC-TCGGCATGGACGAGCTGTACAAG |
|---|
"
],
- "metadata": {
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 80
- },
- "id": "HUELvWKMFtIO",
- "outputId": "976bab6f-f1fc-4c5a-c69c-8de02fc838d0"
- },
- "execution_count": null,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/plain": [
- ""
- ],
- "text/html": [
- "| x: | ATGGTGAGCAAGGGCGAGGAGGATAACATGGCCATCATCAAGGAGTTCATGCGCTTCAAGGTGC-A-CATGGAGGGCTCCGTGAACGGCCACGAGTTCGAGATCGAG---GGCGAGGGCGAGGGC--CGCC-CCTACGAGGGCACCCAGACCGC-CAAGCTGAAGGTG-ACCA-AGG---G-TGGCC---CCCT-GCCCTTCGCCT-GGGA-CATCCTGTCC--C--C-T-CAGTTCATGT-A-CGGCT-CCAAGGCCTACGTG-A--AGCAC--C--C--C--G-CCGACATCCCCG-A--CTAC-T--TGAAGCTG-TCCTTC--C--C-----CGA-GG--GCTTCAAGTGGGAGCG-CGTGATGAACTTCGAGGACGGCGGCGTGGTG-ACCG--T-GA-C-CCAGGAC-TC--CTCCCTGCAGGACGGCGAGTTCATCTACAAGGTG---AAGCTGCGCGGCACCAACTTCCCCT-CCGACGGCCCCGTA-ATGCA-GAAGAAGACCATGGGCTG--GGA-GGCCTCCTCCGAGCGGATGTACCCCGAGGA-CGGCGCC-CTGAAGGGCGAGATCAAGCAGA-GGCTGAAGC-TGAAGGACGGCGGCCACTACGACGCTGAGGTCAAGACCACCTACA-AGGCCAAGAAG-CCCGTGCAGCTGCCCGGC-GCCTACAACGTCAACATCAAGT-TG----GA-CATCACCTCCCACAACGAGGA-CTAC-A-C-CA---T-C-G-TGGAACAGTACG-AACGCGCCGAGGGCCGCCACTCCAC-CGGCGGCATGGACGAGCTGTACAAG |
|---|
| y: | ATGGTGAGCAAGGGCGAGGA-G----C-T-G--TTCA-C-CGG-GGTGGTGCCCATCCTGGT-CGAGC-TGGACGGCGACGTAAACGGCCACAAGTTC-AG--CGTGTCCGGCGAGGGCGAGGGCGATGCCACCTAC---GGCAAGCTGACC-CTGAAG-TTCATTTGCACCACCGGCAAGCTGCCCGTGCCCTGGCCC-AC-CCTCGTGACCACCCTGACCTACGGCGTGCAGTGC-T-TCAGCCGCTACCCCGACC-ACATGAAGCAGCACGACTTCTTCAAGTCCGCCATGCCCGAAGGCTACGTCCAGGAGC-GCACCATCTTCTTCAAGGACGACGGCAACTACAAGA-CCCGCGCCGAGGTGAAGTTCGAGGGCGACACCCTGGTGAACCGCATCGAGCTGAAGGGCATCGACTTCAAGGAGGACGGC-A--ACATC--C-TGGGGCACAAGCTG-G-AGTA-CAACTACAACAGCC-ACAACGTC-TATAT-CATG--GCCGA-CAA--GCAGAAGAACGG-CA--T-C-A-AGG-TGAACTTC-AAGATC--CGCCAC--AA---C---ATCGAG--GACGGC---AGCGTGCAGCTCGCCGACCACTACCA-GC--A-G--AACACC-CC--CATCGGCGACG--GCCCCGTGCTGCTGCCCGACAACC-ACTACCTGAGCACCCAGTCCGCCCTGAGCAA-A-GACCC-CAACGAGAAGC-GCGATCACATGGTCCTGCTGG---AGTTCGTGAC-CGCC----GCCGGGA-T-CACTC-TCGGCATGGACGAGCTGTACAAG |
|---|
"
- ]
- },
- "metadata": {},
- "execution_count": 15
- }
+ "text/plain": [
+ ""
]
- },
- {
- "cell_type": "markdown",
- "source": [
- "# Exercice 3 : Distribution des scores dâalignement pour des sĂ©quences alĂ©atoires\n",
- "\n",
- "Pour tester si un alignement reflĂšte une rĂ©elle similaritĂ© biologique, on va Ă©valuer la distribution des scores dâalignement pour des paires de sĂ©quences alĂ©atoires."
- ],
- "metadata": {
- "id": "Q5jVeLfgMMtA"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q1. En considĂ©rant deux sĂ©quences alĂ©atoires de mĂȘme taille N, oĂč chaque nuclĂ©otide apparaĂźt avec une probabilitĂ© uniforme de ÂŒ, calculer le score moyen attendu pour une superposition sans trou dans le cas oĂč une identitĂ© vaut +1 et une diffĂ©rence vaut 0."
- ],
- "metadata": {
- "id": "6xyXw0HsMQGf"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "```markdown\n",
- "Votre réponse ici\n",
- "```"
- ],
- "metadata": {
- "id": "meF18gt-Mhcn"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q2. La question précédente peut se resoudre analytiquement car on ne considÚre pas de trou. Pour étendre le résultat precedent à un alignement avec trous, on va se baser sur la simulation de séquences aleatoires.\n",
- "\n",
- "GĂ©nĂ©rez $R$ paires de sĂ©quences alĂ©atoires de tailles $N$ avec des probabilitĂ©es uniformes d'apparition de nuclĂ©otides $p_A = p_T = p_G = p_C = $ ÂŒ. Affichez sous forme de violinplots les distribution des scores d'alignements entre chaque paire, obtenu par :\n",
- " 1. un alignement sans trou (cf. Q1) ;\n",
- " 2. un alignement local via Smith-Waterman (utilisez le code de l'exercice précédent)\n",
- "\n",
- "Utilisez le schéma d'évaluation suivant :"
- ],
- "metadata": {
- "id": "fP5_mHnYMkNI"
- }
- },
- {
- "cell_type": "code",
- "source": [
- "rmap = {\"A\": 0, \"T\": 1, \"G\": 2, \"C\": 3}\n",
- "sigma = np.array([[1, -0.5, -0.5, -0.5],\n",
- " [-0.5, 1, -0.5, -0.5],\n",
- " [-0.5, -0.5, 1, -0.5],\n",
- " [-0.5, -0.5, -0.5, 1]])\n",
- "go =0\n",
- "ge = 0.5"
- ],
- "metadata": {
- "id": "akUVqotnOLkH"
- },
- "execution_count": null,
- "outputs": []
- },
- {
- "cell_type": "code",
- "source": [
- "#Votre code ici"
- ],
- "metadata": {
- "id": "UX0afNaqOVZ2"
- },
- "execution_count": null,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q3. Qu'observez-vous ?"
- ],
- "metadata": {
- "id": "UNn9fUuXO4Le"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "```markdown\n",
- "Votre réponse ici\n",
- "```"
- ],
- "metadata": {
- "id": "dSQEl0XXO8IG"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "Q4. Quelle conclusion peut-on en tirer sur la significativité d'un alignement ?"
- ],
- "metadata": {
- "id": "xHfVXpQhf15n"
- }
- },
- {
- "cell_type": "markdown",
- "source": [
- "```markdown\n",
- "Votre réponse ici\n",
- "```"
- ],
- "metadata": {
- "id": "5KjhEeHDgDns"
- }
+ },
+ "execution_count": 47,
+ "metadata": {},
+ "output_type": "execute_result"
}
- ]
-}
\ No newline at end of file
+ ],
+ "source": [
+ "from IPython.display import HTML\n",
+ "HTML(\"| x: | ATGGTGAGCAAGGGCGAGGAGGATAACATGGCCATCATCAAGGAGTTCATGCGCTTCAAGGTGC-A-CATGGAGGGCTCCGTGAACGGCCACGAGTTCGAGATCGAG---GGCGAGGGCGAGGGC--CGCC-CCTACGAGGGCACCCAGACCGC-CAAGCTGAAGGTG-ACCA-AGG---G-TGGCC---CCCT-GCCCTTCGCCT-GGGA-CATCCTGTCC--C--C-T-CAGTTCATGT-A-CGGCT-CCAAGGCCTACGTG-A--AGCAC--C--C--C--G-CCGACATCCCCG-A--CTAC-T--TGAAGCTG-TCCTTC--C--C-----CGA-GG--GCTTCAAGTGGGAGCG-CGTGATGAACTTCGAGGACGGCGGCGTGGTG-ACCG--T-GA-C-CCAGGAC-TC--CTCCCTGCAGGACGGCGAGTTCATCTACAAGGTG---AAGCTGCGCGGCACCAACTTCCCCT-CCGACGGCCCCGTA-ATGCA-GAAGAAGACCATGGGCTG--GGA-GGCCTCCTCCGAGCGGATGTACCCCGAGGA-CGGCGCC-CTGAAGGGCGAGATCAAGCAGA-GGCTGAAGC-TGAAGGACGGCGGCCACTACGACGCTGAGGTCAAGACCACCTACA-AGGCCAAGAAG-CCCGTGCAGCTGCCCGGC-GCCTACAACGTCAACATCAAGT-TG----GA-CATCACCTCCCACAACGAGGA-CTAC-A-C-CA---T-C-G-TGGAACAGTACG-AACGCGCCGAGGGCCGCCACTCCAC-CGGCGGCATGGACGAGCTGTACAAG |
|---|
| y: | ATGGTGAGCAAGGGCGAGGA-G----C-T-G--TTCA-C-CGG-GGTGGTGCCCATCCTGGT-CGAGC-TGGACGGCGACGTAAACGGCCACAAGTTC-AG--CGTGTCCGGCGAGGGCGAGGGCGATGCCACCTAC---GGCAAGCTGACC-CTGAAG-TTCATTTGCACCACCGGCAAGCTGCCCGTGCCCTGGCCC-AC-CCTCGTGACCACCCTGACCTACGGCGTGCAGTGC-T-TCAGCCGCTACCCCGACC-ACATGAAGCAGCACGACTTCTTCAAGTCCGCCATGCCCGAAGGCTACGTCCAGGAGC-GCACCATCTTCTTCAAGGACGACGGCAACTACAAGA-CCCGCGCCGAGGTGAAGTTCGAGGGCGACACCCTGGTGAACCGCATCGAGCTGAAGGGCATCGACTTCAAGGAGGACGGC-A--ACATC--C-TGGGGCACAAGCTG-G-AGTA-CAACTACAACAGCC-ACAACGTC-TATAT-CATG--GCCGA-CAA--GCAGAAGAACGG-CA--T-C-A-AGG-TGAACTTC-AAGATC--CGCCAC--AA---C---ATCGAG--GACGGC---AGCGTGCAGCTCGCCGACCACTACCA-GC--A-G--AACACC-CC--CATCGGCGACG--GCCCCGTGCTGCTGCCCGACAACC-ACTACCTGAGCACCCAGTCCGCCCTGAGCAA-A-GACCC-CAACGAGAAGC-GCGATCACATGGTCCTGCTGG---AGTTCGTGAC-CGCC----GCCGGGA-T-CACTC-TCGGCATGGACGAGCTGTACAAG |
|---|
\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "Q5jVeLfgMMtA"
+ },
+ "source": [
+ "# Exercice 3 : Distribution des scores dâalignement pour des sĂ©quences alĂ©atoires\n",
+ "\n",
+ "Pour tester si un alignement reflĂšte une rĂ©elle similaritĂ© biologique, on va Ă©valuer la distribution des scores dâalignement pour des paires de sĂ©quences alĂ©atoires."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "6xyXw0HsMQGf"
+ },
+ "source": [
+ "Q1. En considĂ©rant deux sĂ©quences alĂ©atoires de mĂȘme taille N, oĂč chaque nuclĂ©otide apparaĂźt avec une probabilitĂ© uniforme de ÂŒ, calculer le score moyen attendu pour une superposition sans trou dans le cas oĂč une identitĂ© vaut +1 et une diffĂ©rence vaut 0."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "meF18gt-Mhcn"
+ },
+ "source": [
+ "```markdown\n",
+ "P(AA) + P(TT) + P(GG) + P(CC) = (1/4 * 1/4) * 4 = 1/4 \n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "fP5_mHnYMkNI"
+ },
+ "source": [
+ "Q2. La question précédente peut se resoudre analytiquement car on ne considÚre pas de trou. Pour étendre le résultat precedent à un alignement avec trous, on va se baser sur la simulation de séquences aleatoires.\n",
+ "\n",
+ "GĂ©nĂ©rez $R$ paires de sĂ©quences alĂ©atoires de tailles $N$ avec des probabilitĂ©es uniformes d'apparition de nuclĂ©otides $p_A = p_T = p_G = p_C = $ ÂŒ. Affichez sous forme de violinplots les distribution des scores d'alignements entre chaque paire, obtenu par :\n",
+ " 1. un alignement sans trou (cf. Q1) ;\n",
+ " 2. un alignement local via Smith-Waterman (utilisez le code de l'exercice précédent)\n",
+ "\n",
+ "Utilisez le schéma d'évaluation suivant :"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 48,
+ "metadata": {
+ "id": "akUVqotnOLkH"
+ },
+ "outputs": [],
+ "source": [
+ "rmap = {\"A\": 0, \"T\": 1, \"G\": 2, \"C\": 3}\n",
+ "sigma = np.array([[1, -0.5, -0.5, -0.5],\n",
+ " [-0.5, 1, -0.5, -0.5],\n",
+ " [-0.5, -0.5, 1, -0.5],\n",
+ " [-0.5, -0.5, -0.5, 1]])\n",
+ "go =0\n",
+ "ge = 0.5"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 49,
+ "metadata": {
+ "id": "UX0afNaqOVZ2"
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1UAAAIOCAYAAABQwSdGAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAACEI0lEQVR4nOzdd3gUZcM18DPbN72RkEAKCS0ESELvAQsgoCB2RcUu2FAQ5VEBkSIqdlEf/RTrq/jYQVSkl1BDaAmRQBohBdLr1vv7I2ZlSQLpk03O77r2IpmZ3Tm7KezJzNy3JIQQICIiIiIiokZRyB2AiIiIiIjIkbFUERERERERNQFLFRERERERUROwVBERERERETUBSxUREREREVETsFQRERERERE1AUsVERERERFRE7BUERERERERNQFLFRERERERUROwVBGRw1qzZg0kSbLddDodOnfujHHjxmHFihXIzc2tcZ/FixdDkqQG7ae8vByLFy/G1q1bG3S/2vYVEhKCKVOmNOhxLufrr7/Gm2++Wes6SZKwePHiZt1fUzTm9aemu/j7oPpnpzFq+xqOHTsWY8eObULC9m/16tVYs2aN3DGIqIWo5A5ARNRUn376KXr37g2TyYTc3Fzs3LkTK1euxGuvvYZvv/0WV111lW3b+++/HxMnTmzQ45eXl+PFF18EgAa9cWzMvhrj66+/xrFjxzBnzpwa62JjY9G1a9cWz0Ad2+rVq+WO0OatXr0aPj4+mDlzptxRiKgFsFQRkcPr27cvBg0aZPv8hhtuwJNPPolRo0Zh+vTpOHnyJPz8/AAAXbt2bfGSUV5eDicnp1bZ1+UMGzZM1v1TlervifaqT58+ckcgIpIVT/8jonYpKCgIq1atQklJCT788EPb8tpOXdq8eTPGjh0Lb29v6PV6BAUF4YYbbkB5eTlSU1PRqVMnAMCLL75oO9Ww+q/N1Y8XFxeHG2+8EZ6enggLC6tzX9V+/PFH9O/fHzqdDqGhoXj77bft1lefnpWammq3fOvWrZAkyXYq4tixY7F+/XqkpaXZnQpZrbbT/44dO4apU6fC09MTOp0OUVFR+Oyzz2rdz//93//hueeeQ0BAANzc3HDVVVchKSmp7hf+AuvXr0dUVBS0Wi26deuG1157rdbthBBYvXo1oqKioNfr4enpiRtvvBGnT5+22+7QoUOYMmUKfH19odVqERAQgMmTJ+PMmTOXzFGf+1mtVrzzzju2DB4eHhg2bBh++eUXu21eeeUV9O7dG1qtFr6+vrjrrrtq7H/s2LHo27cvtm/fjhEjRsDJyQn33nsvAKC4uBjz5s1Dt27doNFo0KVLF8yZMwdlZWV2j/Hdd99h6NChcHd3h5OTE0JDQ22PcSnFxcV44IEH4O3tDRcXF0ycOBF///33Ze8HAN9++y3Gjx8Pf39/6PV6hIeH49lnn62RrTa1nf535swZ3HjjjXB1dYWHhwfuuOMO7N+/H5Ik2Z0GN3PmTLi4uCA5ORmTJk2Ci4sLAgMDMXfuXBgMBrvHNBqNWLp0qe1r0KlTJ9xzzz04d+6c3XbVp9muW7cO0dHRtuezbt06AFU/X+Hh4XB2dsaQIUNw4MCBGs/pwIEDuO666+Dl5QWdTofo6GisXbvWbpvqn9MtW7Zg1qxZ8PHxgbe3N6ZPn46zZ8/a5Tl+/Di2bdtm+xkNCQm57OtKRI6DR6qIqN2aNGkSlEoltm/fXuc2qampmDx5MkaPHo1PPvkEHh4eyMzMxO+//w6j0Qh/f3/8/vvvmDhxIu677z7cf//9AGArWtWmT5+OW2+9FQ8//PBl34TGx8djzpw5WLx4MTp37oyvvvoKTzzxBIxGI+bNm9eg57h69Wo8+OCDOHXqFH788cfLbp+UlIQRI0bA19cXb7/9Nry9vfHll19i5syZyMnJwfz58+22/89//oORI0fi448/RnFxMZ555hlce+21SExMhFKprHM/mzZtwtSpUzF8+HB88803sFgseOWVV5CTk1Nj24ceeghr1qzB448/jpUrVyI/Px9LlizBiBEjcPjwYfj5+aGsrAxXX301unXrhvfeew9+fn7Izs7Gli1bUFJSUmeO+t5v5syZ+PLLL3HfffdhyZIl0Gg0iIuLsyu1s2bNwn//+188+uijmDJlClJTU/HCCy9g69atiIuLg4+Pj23brKwszJgxA/Pnz8fy5cuhUChQXl6OmJgYnDlzBv/5z3/Qv39/HD9+HAsXLsTRo0fx119/QZIkxMbG4pZbbsEtt9yCxYsXQ6fTIS0tDZs3b77k11YIgWnTpmH37t1YuHAhBg8ejF27duGaa66pse3MmTNrnIZ28uRJTJo0CXPmzIGzszNOnDiBlStXYt++fZfdd22v+7hx45Cfn4+VK1eie/fu+P3333HLLbfUur3JZMJ1112H++67D3PnzsX27dvx0ksvwd3dHQsXLgRQVWqnTp2KHTt2YP78+RgxYgTS0tKwaNEijB07FgcOHIBer7c95uHDh7FgwQI899xzcHd3x4svvojp06djwYIF2LRpE5YvXw5JkvDMM89gypQpSElJsd1/y5YtmDhxIoYOHYoPPvgA7u7u+Oabb3DLLbegvLy8xmt3//33Y/Lkyfj666+RkZGBp59+GjNmzLC9bj/++CNuvPFGuLu7206V1Gq1DXpNiaiNE0REDurTTz8VAMT+/fvr3MbPz0+Eh4fbPl+0aJG48Fff//73PwFAxMfH1/kY586dEwDEokWLaqyrfryFCxfWue5CwcHBQpKkGvu7+uqrhZubmygrK7N7bikpKXbbbdmyRQAQW7ZssS2bPHmyCA4OrjX7xblvvfVWodVqRXp6ut1211xzjXBychKFhYV2+5k0aZLddmvXrhUARGxsbK37qzZ06FAREBAgKioqbMuKi4uFl5eX3WsSGxsrAIhVq1bZ3T8jI0Po9Xoxf/58IYQQBw4cEADETz/9dMn9Xqw+99u+fbsAIJ577rk6t0lMTBQAxOzZs+2W7927VwAQ//nPf2zLYmJiBACxadMmu21XrFghFApFje/X6u/B3377TQghxGuvvSYA2L4W9bVhwwYBQLz11lt2y5ctW1bn929drFarMJlMYtu2bQKAOHz4sG1dbd/XMTExIiYmxvb5e++9JwCIDRs22G330EMPCQDi008/tS27++67BQCxdu1au20nTZokevXqZfv8//7v/wQA8f3339ttt3//fgFArF692rYsODhY6PV6cebMGduy+Ph4AUD4+/vbfs6EEOKnn34SAMQvv/xiW9a7d28RHR0tTCaT3b6mTJki/P39hcViEUL8+3N68ffFK6+8IgCIrKws27KIiAi714iI2hee/kdE7ZoQ4pLro6KioNFo8OCDD+Kzzz6rccpZfd1www313jYiIgKRkZF2y26//XYUFxcjLi6uUfuvr82bN+PKK69EYGCg3fKZM2eivLwcsbGxdsuvu+46u8/79+8PAEhLS6tzH2VlZdi/fz+mT58OnU5nW+7q6oprr73Wbtt169ZBkiTMmDEDZrPZduvcuTMiIyNtpzl2794dnp6eeOaZZ/DBBx8gISGhXs+3PvfbsGEDAOCRRx6p83G2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AgfOabDpjA5JRWrbcmdnZ8TExOCKK65AVFQUVCoOPk2Og6WqkViqiIiIqD0oKSnBli1bsGHDBiQmJtqWd3E245rASozobGiWIdorzBL+OqPFX2f0KPjnOimFQoEhQ4Zg4sSJGD58OLRabdN3RCQDlqpGYqkiIiKi9ub06dP45Zdf8Pvvv6OyshIA4KOzYFpIBUb5G6BoxJErgwX4PV2PDRk6lJurypSnpyeuu+46TJ48Gb6+vs35FIhkwVLVSCxVRERE1F6VlJRg/fr1+Pbbb1FQUAAACHIxY2avMnR3N1/m3lWEAPblavB/yU6266WCgoJwxx134IorroBarb7MIxA5DpaqRmKpIiIiovausrISP/30E7744guUlZVBgsCkoErcEFp+yVMCy0wSPjnhjP3nqk7n8/Pzw4MPPoixY8dCqVTWfUciB8VS1UgsVURERNRRFBYWYvXq1fjzzz8BAOEeJjzerwTO6ppvD7PKFHj9iBtyKpRQKpWYMWMGbr/9dl4vRe0aS1UjsVQRERFRR7Nt2za8/PLLqKioQIirGc9EFdsVq6xyBZbHuaPIqICfnx+WLFmCXr16yZiYqHXUtxtwTEsiIiKiDi4mJgZdu3bFU089hdSiIrx5xBXhnibb+tgcLYqMCoSFheG1116Dp6enjGmJ2h4eqboIj1QRERFRR/X333/j0UcfhdForLHO19cXH374IQsVdSg8UkVEREREDdKzZ0+88cYb+Ouvv3Dh3901Gg2mTp3KQkVUB5YqIiIiIrKJiIhARESE3DGIHEozzKNNRERERETUcbFUERERERERNQFLFRERERERUROwVBERERERETUBSxUREREREVETsFQRERERERE1AUsVERERERFRE7BUERERERERNQFLFRERERERUROwVBERERERETUBSxUREREREVETsFQRERERERE1AUsVERERERFRE7BUERERERERNQFLFRERERERUROwVBERERERETUBSxUREREREVETsFQRERERERE1AUsVERERERFRE7BUERERERERNQFLFRERERERUROwVBERERERETUBSxUREREREVETsFQRERERERE1AUsVERERERFRE7BUERERERERNQFLFRERERERUROwVBERERERETUBSxUREREREVETsFQRERERERE1AUsVERERERFRE7BUERERERERNQFLFRERERERUROwVBERERERETUBSxUREREREVETsFQRERERERE1AUsVERERERFRE7BUERERERERNQFLFRERERERURM0uFR9/vnnMBgMNZYbjUZ8/vnnzRKKiIiIiIjIUUhCCNGQOyiVSmRlZcHX19dueV5eHnx9fWGxWJo1YGsrLi6Gu7s7ioqK4ObmJnccIiIiIiKSSX27QYOPVAkhIElSjeVnzpyBu7t7Qx+OiIiIiIjIoanqu2F0dDQkSYIkSbjyyiuhUv17V4vFgpSUFEycOLFFQhIREREREbVV9S5V06ZNAwDEx8djwoQJcHFxsa3TaDQICQnBDTfc0OwBiYiIiIiI2rJ6l6pFixYBAEJCQnDLLbdAp9O1WCgiIiIiIiJHUe9SVe3uu+8GUDXaX25uLqxWq936oKCg5klGRERERETkABpcqk6ePIl7770Xu3fvtltePYCFo4/+R0RERERE1BANLlUzZ86ESqXCunXr4O/vX+tIgERERERERB1Fg0tVfHw8Dh48iN69e7dEHiIiIiIiIofS4Hmq+vTpg/Pnz7dEFiIiIiIiIofT4FK1cuVKzJ8/H1u3bkVeXh6Ki4vtbkRERERERB2JJIQQDbmDQlHVwy6+lqq9DFRRXFwMd3d3FBUVwc3NTe44REREREQkk/p2gwZfU7Vly5YmBSMiIiIiImpPGlyqYmJiWiJHvWzfvh2vvvoqDh48iKysLPz444+YNm2abb0QAi+++CL++9//oqCgAEOHDsV7772HiIgI2TITEREREVH71uBrqgBgx44dmDFjBkaMGIHMzEwAwBdffIGdO3c2a7iLlZWVITIyEu+++26t61955RW8/vrrePfdd7F//3507twZV199NUpKSlo0FxERERERdVwNLlXff/89JkyYAL1ej7i4OBgMBgBASUkJli9f3uwBL3TNNddg6dKlmD59eo11Qgi8+eabeO655zB9+nT07dsXn332GcrLy/H111+3aC4iIiIiIuq4Glyqli5dig8++AAfffQR1Gq1bfmIESMQFxfXrOEaIiUlBdnZ2Rg/frxtmVarRUxMDHbv3i1bLiIiIiIiat8afE1VUlISxowZU2O5m5sbCgsLmyNTo2RnZwMA/Pz87Jb7+fkhLS2tzvsZDAbb0TYAHBaeiIiIiIgapMFHqvz9/ZGcnFxj+c6dOxEaGtosoZqirqHe67JixQq4u7vbboGBgS0dkYiIiIiI2pEGl6qHHnoITzzxBPbu3QtJknD27Fl89dVXmDdvHmbPnt0SGeulc+fOAP49YlUtNze3xtGrCy1YsABFRUW2W0ZGRovmJCIiIiKi9qXBp//Nnz8fRUVFGDduHCorKzFmzBhotVrMmzcPjz76aEtkrJdu3bqhc+fO2LhxI6KjowEARqMR27Ztw8qVK+u8n1arhVarba2YRERERETUzjS4VAHAsmXL8NxzzyEhIQFWqxV9+vSBi4tLc2erobS01O7Uw5SUFMTHx8PLywtBQUGYM2cOli9fjh49eqBHjx5Yvnw5nJyccPvtt7d4NiIiIiIi6pgaVaoAwMnJCYMGDWrOLJd14MABjBs3zvb5U089BQC4++67sWbNGsyfPx8VFRWYPXu2bfLfP//8E66urq2ak4iIiIiIOg5JCCEacofKykq888472LJlC3Jzc2G1Wu3WyzmsenMoLi6Gu7s7ioqK4ObmJnccIiIiIiKSSX27QYOPVN17773YuHEjbrzxRgwZMuSSI+sRERERERG1dw0uVevXr8dvv/2GkSNHtkQeIiIiIiIih9LgIdW7dOnCa5SIiIiIiIj+0eBStWrVKjzzzDNIS0triTxEREREREQOpcGn/w0aNAiVlZUIDQ2Fk5MT1Gq13fr8/PxmC0dERERERNTWNbhU3XbbbcjMzMTy5cvh5+fHgSqIiIiIiKhDa3Cp2r17N2JjYxEZGdkSeYiIiIiIiBxKg6+p6t27NyoqKloiCxERERERkcNpcKl6+eWXMXfuXGzduhV5eXkoLi62uxEREREREXUkkhBCNOQOCkVVD7v4WiohBCRJgsViab50MqjvrMlERERERNS+1bcbNPiaqi1btjQpGBERERERUXvS4FIVExPTEjmIiIiIiIgcUoOvqQKAHTt2YMaMGRgxYgQyMzMBAF988QV27tzZrOGIiIiIiIjaugaXqu+//x4TJkyAXq9HXFwcDAYDAKCkpATLly9v9oBERERERERtWYNL1dKlS/HBBx/go48+glqtti0fMWIE4uLimjUcERERERFRW9fgUpWUlIQxY8bUWO7m5obCwsLmyEREREREROQwGlyq/P39kZycXGP5zp07ERoa2iyhiIiIiIiIHEWDS9VDDz2EJ554Anv37oUkSTh79iy++uorzJs3D7Nnz26J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\n",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "import seaborn as sns\n",
+ "import random\n",
+ "\n",
+ "def generate_random_sequence(N):\n",
+ " \"\"\"GénÚre une séquence aléatoire de longueur N avec des nucléotides équiprobables.\"\"\"\n",
+ " return \"\".join(random.choices(\"ATGC\", k=N))\n",
+ "\n",
+ "def alignment_score_no_gap(x, y, sigma, cmap):\n",
+ " \"\"\"Calcule le score d'alignement sans trou entre deux séquences x et y.\"\"\"\n",
+ " return sum(sigma[cmap[x[i]], cmap[y[i]]] for i in range(len(x)))\n",
+ "\n",
+ "def sw_fwd(x, y, cmap, sigma, gap_params):\n",
+ " \"\"\"Construit les matrices de score et de backtracking pour Smith-Waterman.\"\"\"\n",
+ " go, ge = gap_params\n",
+ " S = np.zeros((len(x) + 1, len(y) + 1))\n",
+ " B = np.zeros((len(x) + 1, len(y) + 1), dtype=int)\n",
+ " max_score = 0\n",
+ " max_pos = (0, 0)\n",
+ " \n",
+ " for i in range(1, len(x) + 1):\n",
+ " for j in range(1, len(y) + 1):\n",
+ " match = S[i-1, j-1] + sigma[cmap[x[i-1]], cmap[y[j-1]]]\n",
+ " delete = S[i-1, j] - (go if B[i-1, j] == 1 else ge)\n",
+ " insert = S[i, j-1] - (go if B[i, j-1] == 2 else ge)\n",
+ " S[i, j], B[i, j] = max((0, 0), (match, 3), (delete, 1), (insert, 2))\n",
+ " if S[i, j] > max_score:\n",
+ " max_score = S[i, j]\n",
+ " max_pos = (i, j)\n",
+ " \n",
+ " return S, B, max_score, max_pos\n",
+ "\n",
+ "def simulate_alignments(R, N, sigma, cmap, gap_params):\n",
+ " \"\"\"Simule R paires de séquences et calcule les scores d'alignement.\"\"\"\n",
+ " scores_no_gap = []\n",
+ " scores_sw = []\n",
+ " \n",
+ " for _ in range(R):\n",
+ " x = generate_random_sequence(N)\n",
+ " y = generate_random_sequence(N)\n",
+ " \n",
+ " score_no_gap = alignment_score_no_gap(x, y, sigma, cmap)\n",
+ " scores_no_gap.append(score_no_gap)\n",
+ " \n",
+ " S, B, max_score, _ = sw_fwd(x, y, cmap, sigma, gap_params)\n",
+ " scores_sw.append(max_score)\n",
+ " \n",
+ " return scores_no_gap, scores_sw\n",
+ "\n",
+ "def plot_violin(scores_no_gap, scores_sw):\n",
+ " \"\"\"Affiche les distributions des scores sous forme de violin plots.\"\"\"\n",
+ " data = [scores_no_gap, scores_sw]\n",
+ " labels = [\"Sans trou\", \"Smith-Waterman\"]\n",
+ " \n",
+ " plt.figure(figsize=(10, 6))\n",
+ " sns.violinplot(data=data)\n",
+ " plt.xticks(ticks=[0, 1], labels=labels)\n",
+ " plt.ylabel(\"Score d'alignement\")\n",
+ " plt.title(\"Distribution des scores d'alignement\")\n",
+ " plt.show()\n",
+ "\n",
+ "# ParamĂštres\n",
+ "total_sequences = 100 # Nombre de paires (R)\n",
+ "sequence_length = 50 # Taille des séquences (N)\n",
+ "rmap = {\"A\": 0, \"T\": 1, \"G\": 2, \"C\": 3}\n",
+ "sigma = np.array([[1, -0.5, -0.5, -0.5],\n",
+ " [-0.5, 1, -0.5, -0.5],\n",
+ " [-0.5, -0.5, 1, -0.5],\n",
+ " [-0.5, -0.5, -0.5, 1]])\n",
+ "gap_params = (0, 0.5)\n",
+ "\n",
+ "# Exécution de la simulation et affichage des résultats\n",
+ "scores_no_gap, scores_sw = simulate_alignments(total_sequences, sequence_length, sigma, rmap, gap_params)\n",
+ "plot_violin(scores_no_gap, scores_sw)\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "UNn9fUuXO4Le"
+ },
+ "source": [
+ "Q3. Qu'observez-vous ?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "dSQEl0XXO8IG"
+ },
+ "source": [
+ "```markdown\n",
+ "Smith Waterman really help finding a positive score. The difference of score is really big between the no hole sequences and the Smith Waterman ones.\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "xHfVXpQhf15n"
+ },
+ "source": [
+ "Q4. Quelle conclusion peut-on en tirer sur la significativité d'un alignement ?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "id": "5KjhEeHDgDns"
+ },
+ "source": [
+ "```markdown\n",
+ "With random sequences, it really helps finding similarities between them. So between close related sequences, it would help as well (especially if they are unalined). That can help as well finding similarities between different species and see if they have a common ancestors or if they have a ancestor-heir relationship. The score can help for the overall sequence, but we can as well take parts of sequence between two species and check their score. That can help find characteristic of two species that is shared among them and see if a part of the sequence is responsable for it. \n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "colab": {
+ "authorship_tag": "ABX9TyNSXnqaXAUgZK9rmJ1TWbGo",
+ "provenance": []
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.13"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}