C/C++

Tema 9 · Comparació de seqüències

Introducció

Comparar seqüències d'ADN o proteïnes és una de les tasques fonamentals en bioinformàtica. Ens permet determinar el grau de similitud entre dues seqüències, identificar mutacions puntuals i establir relacions evolutives. La identitat mesura el percentatge de posicions idèntiques, mentre que la similitud considera també propietats bioquímiques dels aminoàcids.

Objectius

  • Alinear dues seqüències i calcular el percentatge d'identitat
  • Detectar diferències (mutacions, insercions, delecions) entre seqüències
  • Implementar un sistema bàsic de similitud amb matrius de substitució
  • Visualitzar alineaments en format text

Càlcul d'identitat

Funció per comparar dues seqüències de la mateixa longitud i calcular el percentatge d'identitat:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

float calcular_identitat(char seq1[], char seq2[]) {
    int i, coincidencies = 0;
    int len1 = strlen(seq1);
    int len2 = strlen(seq2);
    int min_len = len1 < len2 ? len1 : len2;
    
    for (i = 0; i < min_len; i++) {
        if (toupper(seq1[i]) == toupper(seq2[i])) {
            coincidencies++;
        }
    }
    
    return 100.0 * coincidencies / min_len;
}

int main() {
    char adn1[] = "AGCTTAGGCTA";
    char adn2[] = "AGCTTAGCCTA";
    
    float identitat = calcular_identitat(adn1, adn2);
    printf("Identitat: %.2f%%\n", identitat);
    
    return 0;
}
Compara caràcter a caràcter i compta les coincidències

Detecció de mutacions

A més de calcular la identitat, podem mostrar exactament on es troben les diferències entre dues seqüències:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

void mostrar_diferencies(char seq1[], char seq2[]) {
    int i, coincidencies = 0;
    int len1 = strlen(seq1);
    int len2 = strlen(seq2);
    int min_len = len1 < len2 ? len1 : len2;
    
    printf("Posició | Seq1 | Seq2 | Tipus\n");
    printf("--------+------+------+--------\n");
    
    for (i = 0; i < min_len; i++) {
        if (toupper(seq1[i]) != toupper(seq2[i])) {
            printf("%7d |  %c   |  %c   | Substitució\n", 
                   i+1, seq1[i], seq2[i]);
        } else {
            coincidencies++;
        }
    }
    
    // Si una seqüència és més llarga, indiquem inserció/deleció
    if (len1 != len2) {
        printf("Nota: les seqüències tenen longituds diferents ");
        printf("(%d vs %d).\n", len1, len2);
        printf("Les posicions extra poden ser insercions o delecions.\n");
    }
    
    printf("\nCoincidències: %d/%d (%.1f%%)\n", 
           coincidencies, min_len, 100.0 * coincidencies / min_len);
}

int main() {
    char normal[] = "AGCTTAGGCTA";
    char mutada[] = "AGCTTAGCCTA";  // mutació G→C a la posició 8
    
    mostrar_diferencies(normal, mutada);
    return 0;
}
Mostra una taula amb les posicions on les bases són diferents

Alineament simple amb penalització

Podem crear una funció que alineï dues seqüències i calculi una puntuació de similitud, penalitzant les diferències.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

// Puntuació: coincidència = +1, diferència = -1
int puntuar_alineament(char seq1[], char seq2[]) {
    int i, puntuacio = 0;
    int len1 = strlen(seq1);
    int len2 = strlen(seq2);
    int min_len = len1 < len2 ? len1 : len2;
    
    for (i = 0; i < min_len; i++) {
        if (toupper(seq1[i]) == toupper(seq2[i])) {
            puntuacio += 1;   // coincidència
        } else {
            puntuacio -= 1;   // substitució
        }
    }
    // Penalització per diferència de longitud (insercions/delecions)
    puntuacio -= abs(len1 - len2) * 2;
    
    return puntuacio;
}

void mostrar_alineament(char seq1[], char seq2[]) {
    int i, len1 = strlen(seq1), len2 = strlen(seq2);
    char linia_match[200] = "";
    
    for (i = 0; i < len1 && i < len2; i++) {
        if (toupper(seq1[i]) == toupper(seq2[i]))
            strcat(linia_match, "|");
        else
            strcat(linia_match, " ");
    }
    
    printf("Seq1:  %s\n", seq1);
    printf("       %s\n", linia_match);
    printf("Seq2:  %s\n", seq2);
    printf("Puntuació: %d\n", puntuar_alineament(seq1, seq2));
}

int main() {
    char seq1[] = "AGCTTAGGCTA";
    char seq2[] = "AGCTTA-CCTA";  // deleció representada amb guió
    
    mostrar_alineament(seq1, seq2);
    return 0;
}
L'alineament mostra '|' per a coincidències i espais per a diferències

Exercicis

  1. Compara dues seqüències d'ADN introduïdes per l'usuari i mostra el percentatge d'identitat.
  2. Llegeix dues seqüències des d'un fitxer i detecta totes les mutacions, indicant si són transicions (A↔G, C↔T) o transversions (altres canvis).
  3. Implementa una matriu de substitució simple per a aminoàcids (hidrofòbic, polar, carregat) i calcula la similitud entre dues proteïnes curtes.

Mini Projecte – Alineador de seqüències

Escriu un programa complet que:

  • Llegeixi dues seqüències d'ADN des d'un fitxer (cada seqüència en una línia o en format FASTA).
  • Calculi i mostri el percentatge d'identitat global.
  • Generi un alineament visual (com en l'exemple anterior) amb caràcters '|' per indicar coincidències.
  • Llisti totes les mutacions trobades amb la seva posició i tipus (substitució, inserció, deleció).
  • Separi les mutacions en transicions (A↔G, C↔T) i transversions, i mostri un resum estadístic.

Repte: guarda l'alineament i l'informe de mutacions en un fitxer de sortida.