Task: Bioinformatics_Global alignment




Go: package main

import (
    "fmt"
    "strings"
)


func factorial(n int) int {
    fact := 1
    for i := 2; i <= n; i++ {
        fact *= i
    }
    return fact
}


func getPerms(input []string) [][]string {
    perms := [][]string{input}
    le := len(input)
    a := make([]string, le)
    copy(a, input)
    n := le - 1
    fact := factorial(n + 1)

    for c := 1; c < fact; c++ {
        i := n - 1
        j := n
        for i >= 0 && a[i] > a[i+1] {
            i--
        }
        if i == -1 {
            i = n
        }
        for a[j] < a[i] {
            j--
        }
        a[i], a[j] = a[j], a[i]
        j = n
        i++
        if i == n+1 {
            i = 0
        }
        for i < j {
            a[i], a[j] = a[j], a[i]
            i++
            j--
        }
        b := make([]string, le)
        copy(b, a)
        perms = append(perms, b)
    }
    return perms
}


func distinct(slist []string) []string {
    distinctSet := make(map[string]int, len(slist))
    i := 0
    for _, s := range slist {
        if _, ok := distinctSet[s]; !ok {
            distinctSet[s] = i
            i++
        }
    }
    result := make([]string, len(distinctSet))
    for s, i := range distinctSet {
        result[i] = s
    }
    return result
}


func printCounts(seq string) {
    bases := [][]rune{{'A', 0}, {'C', 0}, {'G', 0}, {'T', 0}}
    for _, c := range seq {
        for _, base := range bases {
            if c == base[0] {
                base[1]++
            }
        }
    }
    sum := 0
    fmt.Println("\nNucleotide counts for", seq, "\b:\n")
    for _, base := range bases {
        fmt.Printf("%10c%12d\n", base[0], base[1])
        sum += int(base[1])
    }
    le := len(seq)
    fmt.Printf("%10s%12d\n", "Other", le-sum)
    fmt.Printf("  ____________________\n%14s%8d\n", "Total length", le)
}


func headTailOverlap(s1, s2 string) int {
    for start := 0; ; start++ {
        ix := strings.IndexByte(s1[start:], s2[0])
        if ix == -1 {
            return 0
        } else {
            start += ix
        }
        if strings.HasPrefix(s2, s1[start:]) {
            return len(s1) - start
        }
    }
}


func deduplicate(slist []string) []string {
    var filtered []string
    arr := distinct(slist)
    for i, s1 := range arr {
        withinLarger := false
        for j, s2 := range arr {
            if j != i && strings.Contains(s2, s1) {
                withinLarger = true
                break
            }
        }
        if !withinLarger {
            filtered = append(filtered, s1)
        }
    }
    return filtered
}


func shortestCommonSuperstring(slist []string) string {
    ss := deduplicate(slist)
    shortestSuper := strings.Join(ss, "")
    for _, perm := range getPerms(ss) {
        sup := perm[0]
        for i := 0; i < len(ss)-1; i++ {
            overlapPos := headTailOverlap(perm[i], perm[i+1])
            sup += perm[i+1][overlapPos:]
        }
        if len(sup) < len(shortestSuper) {
            shortestSuper = sup
        }
    }
    return shortestSuper
}

func main() {
    testSequences := [][]string{
        {"TA", "AAG", "TA", "GAA", "TA"},
        {"CATTAGGG", "ATTAG", "GGG", "TA"},
        {"AAGAUGGA", "GGAGCGCAUC", "AUCGCAAUAAGGA"},
        {
            "ATGAAATGGATGTTCTGAGTTGGTCAGTCCCAATGTGCGGGGTTTCTTTTAGTACGTCGGGAGTGGTATTAT",
            "GGTCGATTCTGAGGACAAAGGTCAAGATGGAGCGCATCGAACGCAATAAGGATCATTTGATGGGACGTTTCGTCGACAAAGT",
            "CTATGTTCTTATGAAATGGATGTTCTGAGTTGGTCAGTCCCAATGTGCGGGGTTTCTTTTAGTACGTCGGGAGTGGTATTATA",
            "TGCTTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTGAGGACAAAGGTCAAGATGGAGCGCATC",
            "AACGCAATAAGGATCATTTGATGGGACGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTCTT",
            "GCGCATCGAACGCAATAAGGATCATTTGATGGGACGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTC",
            "CGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTCTTCGATTCTGCTTATAACACTATGTTCT",
            "TGCTTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTGAGGACAAAGGTCAAGATGGAGCGCATC",
            "CGTAAAAAATTACAACGTCCTTTGGCTATCTCTTAAACTCCTGCTAAATGCTCGTGC",
            "GATGGAGCGCATCGAACGCAATAAGGATCATTTGATGGGACGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTCTTCGATT",
            "TTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTGAGGACAAAGGTCAAGATGGAGCGCATC",
            "CTATGTTCTTATGAAATGGATGTTCTGAGTTGGTCAGTCCCAATGTGCGGGGTTTCTTTTAGTACGTCGGGAGTGGTATTATA",
            "TCTCTTAAACTCCTGCTAAATGCTCGTGCTTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTGAGGACAAAGGTCAAGA",
        },
    }

    for _, test := range testSequences {
        scs := shortestCommonSuperstring(test)
        printCounts(scs)
    }
}




Python: import os

from collections import Counter
from functools import reduce
from itertools import permutations

BASES = ("A", "C", "G", "T")


def deduplicate(sequences):
    
    sequences = set(sequences)
    duplicates = set()

    for s, t in permutations(sequences, 2):
        if s != t and s in t:
            duplicates.add(s)

    return sequences - duplicates


def smash(s, t):
    
    for i in range(len(s)):
        if t.startswith(s[i:]):
            return s[:i] + t
    return s + t


def shortest_superstring(sequences):
    
    sequences = deduplicate(sequences)
    shortest = "".join(sequences)

    for perm in permutations(sequences):
        superstring = reduce(smash, perm)
        if len(superstring) < len(shortest):
            shortest = superstring

    return shortest


def shortest_superstrings(sequences):
    
    sequences = deduplicate(sequences)

    shortest = set(["".join(sequences)])
    shortest_length = sum(len(s) for s in sequences)

    for perm in permutations(sequences):
        superstring = reduce(smash, perm)
        superstring_length = len(superstring)
        if superstring_length < shortest_length:
            shortest.clear()
            shortest.add(superstring)
            shortest_length = superstring_length
        elif superstring_length == shortest_length:
            shortest.add(superstring)

    return shortest


def print_report(sequence):
    
    buf = [f"Nucleotide counts for {sequence}:\n"]

    counts = Counter(sequence)
    for base in BASES:
        buf.append(f"{base:>10}{counts.get(base, 0):>12}")

    other = sum(v for k, v in counts.items() if k not in BASES)
    buf.append(f"{'Other':>10}{other:>12}")

    buf.append(" " * 5 + "_" * 17)
    buf.append(f"{'Total length':>17}{sum(counts.values()):>5}")

    print(os.linesep.join(buf), "\n")


if __name__ == "__main__":
    test_cases = [
        ("TA", "AAG", "TA", "GAA", "TA"),
        ("CATTAGGG", "ATTAG", "GGG", "TA"),
        ("AAGAUGGA", "GGAGCGCAUC", "AUCGCAAUAAGGA"),
        (
            "ATGAAATGGATGTTCTGAGTTGGTCAGTCCCAATGTGCGGGGTTTCTTTTAGTACGTCGGGAGTGGTATTAT",
            "GGTCGATTCTGAGGACAAAGGTCAAGATGGAGCGCATCGAACGCAATAAGGATCATTTGATGGGACGTTTCGTCGACAAAGT",
            "CTATGTTCTTATGAAATGGATGTTCTGAGTTGGTCAGTCCCAATGTGCGGGGTTTCTTTTAGTACGTCGGGAGTGGTATTATA",
            "TGCTTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTGAGGACAAAGGTCAAGATGGAGCGCATC",
            "AACGCAATAAGGATCATTTGATGGGACGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTCTT",
            "GCGCATCGAACGCAATAAGGATCATTTGATGGGACGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTC",
            "CGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTCTTCGATTCTGCTTATAACACTATGTTCT",
            "TGCTTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTGAGGACAAAGGTCAAGATGGAGCGCATC",
            "CGTAAAAAATTACAACGTCCTTTGGCTATCTCTTAAACTCCTGCTAAATGCTCGTGC",
            "GATGGAGCGCATCGAACGCAATAAGGATCATTTGATGGGACGTTTCGTCGACAAAGTCTTGTTTCGAGAGTAACGGCTACCGTCTTCGATT",
            "TTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTGAGGACAAAGGTCAAGATGGAGCGCATC",
            "CTATGTTCTTATGAAATGGATGTTCTGAGTTGGTCAGTCCCAATGTGCGGGGTTTCTTTTAGTACGTCGGGAGTGGTATTATA",
            "TCTCTTAAACTCCTGCTAAATGCTCGTGCTTTCCAATTATGTAAGCGTTCCGAGACGGGGTGGTCGATTCTGAGGACAAAGGTCAAGA",
        ),
    ]

    for case in test_cases:
        for superstring in shortest_superstrings(case):
            print_report(superstring)