albero delle mutazioni del mtDNA


13

Sfondo:

MtDNA è una parte del DNA umano che viene trasmessa da una madre a un bambino e raramente muta. Poiché questo è vero per tutti gli esseri umani, è possibile creare un albero enorme che visualizzi come tutti gli esseri umani sono collegati tra loro attraverso la loro origine materna fino all'ipotetico EVE. Ogni mutazione nel MtDNA quando nasce un bambino crea un nuovo sotto-ramo dal suo ramo padre nell'albero.

Scopri di più sul DNA mitocondriale (mtDNA) qui: https://en.wikipedia.org/wiki/Mitochondrial_DNA

Obbiettivo:

Al programma viene fornito un elenco del conteggio delle mutazioni dei rami degli alberi mtDNA e il programma dovrebbe fornire una vista ad albero di esso

Esempio di input e output:

L'input è una tabella separata di punti e virgola a 3 colonne con una linea per ciascun ramo. Esempio:

L0a'b'f'k;L0;14
L0a'b'f;L0a'b'f'k;23
L0;mtEVE;10
L0a'b;L0a'b'f;30
L0a;L0a'b;38
L0a1'4;L0a;39
L0a1;L0a1'4;40
L0a1a;L0a1;42
L0a1a NL;L0a1a;43
L0a1a1;L0a1a NL;44
L0a1a2;L0a1a NL;45
L0a1a3;L0a1a NL;44
L0a1 NL;L0a1;41
L0a1b;L0a1 NL;44
L0a1b NL;L0a1b;45
L0a1b1;L0a1b NL;46
L0a1b1a;L0a1b1;47
L0a1b1a1;L0a1b1a;48
L0a1b2;L0a1b NL;48
L0a1b2a;L0a1b2;50
L0a1c;L0a1 NL;45
L0a1d;L0a1 NL;44
L0a4;L0a1'4;55
L0a2;L0a;47
L0a2a;L0a2;49
L0a2a1;L0a2a;50
L0a2a1a;L0a2a1;51
L0a2a1a1;L0a2a1a;53
L0a2a1a2;L0a2a1a;53
L0a2a2;L0a2a;53
L0a2a2a;L0a2a2;54
L0a2b;L0a2;57
L0a2b1;L0a2b;58
L0a2c;L0a2;60
L0a2d;L0a2;49
L0a3;L0a;53
L0b;L0a'b;48
L0f;L0a'b'f;37
L0f1;L0f;61
L0f2;L0f;41
L0f2a;L0f2;46
L0f2a1;L0f2a;59
L0f2b;L0f2;63
L0k;L0a'b'f'k;39
L0k1;L0k;48
L0k2;L0k;54
L0d;L0;21
L0d1'2;L0d;25
L0d1;L0d1'2;30
L0d1 NL;L0d1;31
L0d1a;L0d1 NL;38
L0d1a1;L0d1a;41
L0d1c;L0d1 NL;39
L0d1c1;L0d1c;45
L0d1c1a;L0d1c1;46
L0d1c1b;L0d1c1;46
L0d1b;L0d1 NL;36
L0d1b1;L0d1b;40
L0d2;L0d1'2;31
L0d2a'b;L0d2;32
L0d2a;L0d2a'b;42
L0d2a1;L0d2a;43
L0d2b;L0d2a'b;46
L0d2c;L0d2;45
L0d3;L0d;39

Il programma dovrebbe generare una vista ad albero da sinistra a destra che includa alcuni numeri in base all'input. Sulla base dell'input di esempio, questo è un output valido:

  0│ ┐                                                               mtEVE               [  0][ 63]
 10│ └♦♦♦♦♦♦♦♦♦┬────────────────┬─────────────────────────────────── L0                  [ 10][ 63]
 21│           │                └♦♦♦♦♦♦♦♦♦♦┬──────┬───────────────── L0d                 [ 11][ 46]
 39│           │                           │      └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0d3                [ 18][ 39]
 25│           │                           └♦♦♦┐                     L0d1'2              [  4][ 46]
 30│           │                               ├♦♦♦♦┬─────────────── L0d1                [  5][ 46]
 31│           │                               │    └┬────┬┐         L0d1 NL             [  1][ 46]
 36│           │                               │     │    │└♦♦♦♦┬─── L0d1b               [  5][ 40]
 40│           │                               │     │    │     └♦♦♦ L0d1b1              [  4][ 40]
 38│           │                               │     │    └♦♦♦♦♦♦┬── L0d1a               [  7][ 41]
 41│           │                               │     │           └♦♦ L0d1a1              [  3][ 41]
 39│           │                               │     └♦♦♦♦♦♦♦┬────── L0d1c               [  8][ 46]
 45│           │                               │             └♦♦♦♦♦┬ L0d1c1              [  6][ 46]
 46│           │                               │                   ├ L0d1c1a             [  1][ 46]
 46│           │                               │                   └ L0d1c1b             [  1][ 46]
 31│           │                               └♦♦♦♦♦┬┬───────────── L0d2                [  6][ 46]
 45│           │                                     │└♦♦♦♦♦♦♦♦♦♦♦♦♦ L0d2c               [ 14][ 45]
 32│           │                                     └┬──┐           L0d2a'b             [  1][ 46]
 42│           │                                      │  └♦♦♦♦♦♦♦♦♦┬ L0d2a               [ 10][ 43]
 43│           │                                      │            └ L0d2a1              [  1][ 43]
 46│           │                                      └♦♦♦♦♦♦♦♦♦♦♦♦♦ L0d2b               [ 14][ 46]
 14│           └♦♦♦┬────────┐                                        L0a'b'f'k           [  4][ 63]
 39│               │        └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦┬─────┬──────── L0k                 [ 25][ 54]
 48│               │                                 │     └♦♦♦♦♦♦♦♦ L0k1                [  9][ 48]
 54│               │                                 └♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0k2                [ 15][ 54]
 23│               └♦♦♦♦♦♦♦♦┬──┐                                     L0a'b'f             [  9][ 63]
 30│                        │  └♦♦♦♦♦♦┬───────────┐                  L0a'b               [  7][ 60]
 48│                        │         │           └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0b                 [ 18][ 48]
 38│                        │         └♦♦♦♦♦♦♦┬────┬─┬────────────── L0a                 [  8][ 60]
 53│                        │                 │    │ └♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0a3                [ 15][ 53]
 39│                        │                 │    └┬────┐           L0a1'4              [  1][ 55]
 40│                        │                 │     │    └┬────┬──── L0a1                [  1][ 50]
 42│                        │                 │     │     │    └♦┬── L0a1a               [  2][ 45]
 43│                        │                 │     │     │      └┬┐ L0a1a NL            [  1][ 45]
 44│                        │                 │     │     │       │├ L0a1a1              [  1][ 44]
 44│                        │                 │     │     │       │└ L0a1a3              [  1][ 44]
 45│                        │                 │     │     │       └♦ L0a1a2              [  2][ 45]
 41│                        │                 │     │     └┬────┬┐   L0a1 NL             [  1][ 50]
 44│                        │                 │     │      │    │└♦♦ L0a1d               [  3][ 44]
 45│                        │                 │     │      │    └♦♦♦ L0a1c               [  4][ 45]
 44│                        │                 │     │      └♦♦┬───── L0a1b               [  3][ 50]
 45│                        │                 │     │         └┬─┐   L0a1b NL            [  1][ 50]
 46│                        │                 │     │          │ └┬─ L0a1b1              [  1][ 48]
 47│                        │                 │     │          │  └┬ L0a1b1a             [  1][ 48]
 48│                        │                 │     │          │   └ L0a1b1a1            [  1][ 48]
 48│                        │                 │     │          └♦♦┬─ L0a1b2              [  3][ 50]
 50│                        │                 │     │             └♦ L0a1b2a             [  2][ 50]
 55│                        │                 │     └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0a4                [ 16][ 55]
 47│                        │                 └♦♦♦♦♦♦♦♦┬─┬───┬────┬─ L0a2                [  9][ 60]
 49│                        │                          │ │   │    └♦ L0a2d               [  2][ 49]
 49│                        │                          │ │   └♦┬┬─── L0a2a               [  2][ 54]
 50│                        │                          │ │     │└┬── L0a2a1              [  1][ 53]
 51│                        │                          │ │     │ └┬─ L0a2a1a             [  1][ 53]
 53│                        │                          │ │     │  ├♦ L0a2a1a1            [  2][ 53]
 53│                        │                          │ │     │  └♦ L0a2a1a2            [  2][ 53]
 53│                        │                          │ │     └♦♦♦┬ L0a2a2              [  4][ 54]
 54│                        │                          │ │         └ L0a2a2a             [  1][ 54]
 57│                        │                          │ └♦♦♦♦♦♦♦♦♦┬ L0a2b               [ 10][ 58]
 58│                        │                          │           └ L0a2b1              [  1][ 58]
 60│                        │                          └♦♦♦♦♦♦♦♦♦♦♦♦ L0a2c               [ 13][ 60]
 37│                        └♦♦♦♦♦♦♦♦♦♦♦♦♦┬─┬─────────────────────── L0f                 [ 14][ 63]
 61│                                      │ └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0f1                [ 24][ 61]
 41│                                      └♦♦♦┬───┬───────────────── L0f2                [  4][ 63]
 46│                                          │   └♦♦♦♦┬──────────── L0f2a               [  5][ 59]
 59│                                          │        └♦♦♦♦♦♦♦♦♦♦♦♦ L0f2a1              [ 13][ 59]
 63│                                          └♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦♦ L0f2b               [ 22][ 63]

Input: dettagli

La tabella di input non è ordinata in alcun ordine particolare. Se riordiniamo casualmente le linee di input, l'output dovrebbe rimanere lo stesso.

Ogni riga nell'input rappresenta un ramo di albero mtDNA o un ipotetico ramo di albero. La tabella di input può essere lunga qualsiasi numero di righe.

Input: Dettagli - Colonna A (nome filiale):

La prima colonna è il nome del ramo effettivo. Il nome divide le righe di input in 2 gruppi di tipi di riga che devono essere gestiti in modo diverso (spiegato più avanti) l'uno dall'altro:

  • Tipo 1: il nome è costituito da uno 'o dal suffissoNL
  • Tipo 2: il nome non è costituito da nessuno 'o dal suffisso NL.

Il nome può contenere fino a 20 caratteri.

Input: Dettagli - Colonna B (nome ramo padre):

La seconda colonna contiene un puntatore al nome del ramo padre. Diverse linee (rami) possono condividere lo stesso genitore. Esiste sempre esattamente 1 nome di ramo padre distinto nella tabella di input che punta a un padre che non è rappresentato tra le righe di input, che il nome del ramo padre è la radice dell'albero. Nel esempio di input che è la terza linea punta alla radice: mtEVE. Se l'input ha più di una radice o loop infiniti, è un input non valido.

Input: Dettagli - Colonna C (N. di mutazioni):

La terza colonna è il numero totale di mutazioni che il particolare ramo ha avuto contando dalla radice. Il mtDNA umano non è mutato più di 100 volte in una sola riga dall'ipotetica radice materna (antenato umano / scimpanzé EVE), ma il tuo programma dovrebbe essere in grado di gestire un numero di mutazioni a 3 cifre, fino a 999.

Dall'input è possibile calcolare un numero di ramo di mutazioni uniche sottraendo il suo numero di mutazioni dal suo numero principale di mutazioni.

Uscita: dettagli

Il tuo programma dovrebbe generare 1 su 3 diversi messaggi di errore se l'input non è valido secondo la descrizione dell'input.

  • Messaggio di errore 1, se l'input ha più di una radice: ERROR: Multiple roots
  • Messaggio di errore 2, se i puntatori padre di input sono in loop: ERROR: Endless loop
  • Messaggio di errore 3, qualsiasi altra cosa non valida sull'input: ERROR: Invalid input

Se l'input non contiene errori, il programma dovrebbe generare l'albero secondo i seguenti vincoli: Ogni riga è composta da 5 parti A, B, C, D ed E:

  • A: 5 caratteri, 3 caratteri # allineati a destra delle mutazioni, un carattere di linea verticale: |e 1 spazio vuoto
  • B: [max # numero di mutazioni] caratteri albero largo + 1 spazio vuoto
  • C: 20 caratteri, nome ramo allineato a sinistra
  • D: 5 caratteri, 3 caratteri allineati a destra # di mutazioni uniche per il ramo incapsulato tra [e ]. (Le mutazioni uniche verranno spiegate di seguito).
  • E: 5 caratteri, numero massimo di 3 caratteri allineati a destra delle mutazioni totali per questo ramo e tutti i rami figlio incapsulati tra [e ].

Un ramo # di mutazioni univoche è la differenza nel numero di mutazioni che il ramo corrente ha dal numero di mutazioni che ha il ramo genitore. La prima riga è la radice e dovrebbe essere rappresentata con 0per # di mutazioni e # di mutazioni uniche.

Output: Dettagli: ordine / ordinamento di riga

Se due o più sotto-rami condividono lo stesso genitore, i rami sono ordinati in base al numero massimo di sotto-rami delle mutazioni totali in ordine decrescente. Nel nostro esempio L0a1'4, L0a3e L0a2le azioni della capogruppo: L0a.

Nella vista ad albero l'ordine dall'alto verso il basso è, sotto-rami numero massimo di mutazioni totali tra parentesi: L0a3(53), L0a1'4(55), L0a2(60).

Se due o più rami secondari condividono lo stesso numero massimo di mutazioni sui rami figlio, sono allineati verticalmente e ramificati dal loro genitore dallo stesso punto, l'ordinamento delle linee tra quei rami secondari è alfabetico.

Output: Dettagli - albero (parte B)

L'albero dovrebbe essere elaborato con i caratteri ASCII seguenti: , , , , , ,

La logica dell'albero è che tutte le mutazioni dovrebbero essere rappresentate. Un ramo da un ramo padre: o rappresenta 1 mutazione. Ulteriori mutazioni uniche sullo stesso ramo sono rappresentate da: e devono essere allineate a sinistra e posizionate prima del primo ramo secondario.

I rami secondari sono ramificati dal loro genitore lungo l'asse x e la posizione è determinata dal numero massimo di mutazioni tra tutti i rami figlio successivi.

Come accennato prima, l'ingresso ha 2 diversi tipi di linee di ingresso. Digitare 1 con qualsiasi 'carattere o il suffisso NL nel nome del ramo, non deve riempire la linea orizzontale all'estrema destra sulla loro linea ma terminare con un sull'ultimo ramo secondario. Nell'esempio viene applicato ai seguenti rami:

L0a'b'f'k;L0;14
L0a'b'f;L0a'b'f'k;23
L0a'b;L0a'b'f;30
L0a1'4;L0a;39
L0a1a NL;L0a1a;43
L0a1 NL;L0a1;41
L0a1b NL;L0a1b;45
L0d1'2;L0d;25
L0d1 NL;L0d1;31
L0d2a'b;L0d2;32

Speriamo che l'input e l'output di esempio rispondano a qualsiasi domanda aggiuntiva su come l'albero dovrebbe essere disegnato, considera parte della sfida capire la logica.

Ispirazione

Puoi provare la mia versione javascript (non giocata a golf) come fonte di ispirazione: http://artificial.se/DNA/mtDNAmutationTree3.html (manca il controllo degli errori e vengono aggiunte alcune statistiche che non fanno parte di questa particolare sfida) .

Una versione completa dell'albero mtDNA [basata su http://www.phylotree.org/ albero mtDNA Build 16 (19 febbraio 2014)] è disponibile qui:

http://artificial.se/DNA/mtDNAfull.html

Il file di dati utilizzato per l'albero completo:

http://artificial.se/DNA/mtDNA_full.txt

Questa è una sfida di code-golf.


L0d1non dovrebbe essere piazzato prima L0d2, secondo la regola di classificazione: "... ordine decrescente ..."
guy777

L0a1'4non è (55) ma (39), L0a2non è (60) ma (47) ... Potresti chiarire questo?
guy777

L0d1 e L0d2 sono entrambi 46, per cui viene applicato l'ordine alfabetico
Plarsen

L0a4 55 e un figlio di L0a1'4, quindi il numero massimo di mutazioni per L0a1'4 è 55
Plarsen

Ho alcune domande: 1) È un vero progetto? Ho l'impressione che qualcosa del genere possa valere soldi veri. 2) Come hai ottenuto l'output di esempio? 3) Perché la parte A ha 8 caratteri anziché 5? 4) Perché la parte D ha 6 caratteri anziché 5? 5) Perché "L0a1 NL" ha "4" nella parte D?
Aditsu ha lasciato perché SE è MALE il

Risposte:


6

Python 3, 925 byte

Sì, meno di 1 KB! Probabilmente ancora spazio per il golf ...

import sys
class L:
 def __init__(x,**k):x.__dict__.update(k)
m={}
def e(x):print('ERROR: '+x);exit()
try:
 for x in sys.stdin:a,b,c=x.split(';');m[a]=L(s=a,p=b,m=int(c),l=0)
except:e('Invalid input')
a=set()
def k(x):
 if x.l<0:e('Endless loop')
 if x.l<1:y=m.get(x.p);x.l=-1;k(y)if y else a.add(x.p);x.l=1
for x in m:k(m[x])
r=L(s=a.pop(),p=0,m=0)
if a:e('Multiple roots')
m[r.s]=r
c={}
def u(x):
 c[x.s]=[m[y]for y in m if m[y].p==x.s];x.x=x.m
 for y in c[x.s]:u(y);x.x=max(x.x,y.x)
u(r)
o=[]
def f(p,x,o=o):
 d=x.m-p.m;j=p.m+r.x-x.x;s=x.s;x.i=len(o);l=sorted(c[s],key=lambda t:(t.x,t.s));q=' '*j+'└'+'♦'*(d-1);z='─'
 if"'"in s or s[-2:]=='NL'or x==r:q+=z*(x.x-l[0].x);z=' '
 o+=list("%3d│ "%x.m+q+z*(r.x-len(q))+' %-20s[%3d][%3d]'%(s,d,x.x)),;j+=5;o[p.i][j]='┐┬'[o[p.i][j]in'─┬']
 for i in range(p.i+1,x.i):o[i][j]='├│'[o[i][j]in' │']
 for y in l:f(x,y)
f(r,r)
print('\n'.join(''.join(x)for x in o))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.