Ceci est un long texte. S'il vous plaît, supportez-moi. En résumé, la question est: existe-t-il un algorithme de tri Radix sur place ?
Préliminaire
J'ai un grand nombre de petites chaînes de longueur fixe qui n'utilisent que les lettres «A», «C», «G» et «T» (oui, vous l'avez deviné: ADN ) que je veux trier.
Pour le moment, j'utilise std::sort
qui utilise introsort dans toutes les implémentations courantes de la STL . Cela fonctionne assez bien. Cependant, je suis convaincu que le tri Radix correspond parfaitement à mon problème et devrait fonctionner beaucoup mieux dans la pratique.
Détails
J'ai testé cette hypothèse avec une implémentation très naïve et pour des entrées relativement petites (de l'ordre de 10 000), cela était vrai (enfin, au moins plus de deux fois plus rapide). Cependant, le temps d'exécution se dégrade de façon catastrophique lorsque la taille du problème augmente ( N > 5 000 000).
La raison est évidente: le tri radix nécessite de copier toutes les données (plus d'une fois dans mon implémentation naïve, en fait). Cela signifie que j'ai mis ~ 4 Gio dans ma mémoire principale, ce qui tue évidemment les performances. Même si ce n'était pas le cas, je ne peux pas me permettre d'utiliser autant de mémoire car les tailles de problème deviennent encore plus importantes.
Cas d'utilisation
Idéalement, cet algorithme devrait fonctionner avec n'importe quelle longueur de chaîne entre 2 et 100, pour l'ADN ainsi que pour l'ADN5 (qui permet un caractère générique supplémentaire "N"), ou même l'ADN avec des codes d'ambiguïté IUPAC (résultant en 16 valeurs distinctes). Cependant, je me rends compte que tous ces cas ne peuvent pas être couverts, donc je suis satisfait de toute amélioration de vitesse que j'obtiens. Le code peut décider dynamiquement vers quel algorithme envoyer.
Recherche
Malheureusement, l'article Wikipédia sur le tri radix est inutile. La section sur une variante sur place est une poubelle complète. La section NIST-DADS sur le tri radix est pratiquement inexistante. Il existe un article à consonance prometteuse appelé Efficient Adaptive In-Place Radix Sorting qui décrit l'algorithme «MSL». Malheureusement, ce document est également décevant.
En particulier, il y a les choses suivantes.
Premièrement, l'algorithme contient plusieurs erreurs et laisse beaucoup inexpliqué. En particulier, il ne détaille pas l'appel de récursivité (je suppose simplement qu'il incrémente ou réduit un certain pointeur pour calculer les valeurs de décalage et de masque actuelles). De plus, il utilise les fonctions dest_group
et dest_address
sans donner de définitions. Je ne vois pas comment les implémenter efficacement (c'est-à-dire dans O (1); au moins, ce dest_address
n'est pas trivial).
Enfin et surtout, l'algorithme atteint la place en échangeant des indices de tableau avec des éléments à l'intérieur du tableau d'entrée. Cela ne fonctionne évidemment que sur des tableaux numériques. Je dois l'utiliser sur des cordes. Bien sûr, je pourrais juste taper un typage fort et continuer en supposant que la mémoire tolérera que je stocke un index où il n'appartient pas. Mais cela ne fonctionne que tant que je peux compresser mes chaînes dans 32 bits de mémoire (en supposant des entiers 32 bits). Cela ne fait que 16 caractères (ignorons pour l'instant que 16> log (5 000 000)).
Un autre article de l'un des auteurs ne donne aucune description précise, mais il donne l'exécution de MSL comme sous-linéaire, ce qui est complètement faux.
Pour récapituler : Y a-t-il un espoir de trouver une implémentation de référence de travail ou au moins un bon pseudocode / description d'un type de radix en place qui fonctionne sur les chaînes d'ADN?