Pengkodean efisien * bebas kesalahan [ditutup]

20

Misi

Seperti diketahui, materi genetik semua makhluk yang dikenal di Bumi dikodekan dalam DNA; menggunakan empat nukleotida adenin, timin, sitosin, dan guanin. (Biasa diwakili oleh ATGC).

Seorang ahli bioinformatika yang ingin menyimpan seluruh genom tentu saja tidak ingin menyimpan ini sebagai ASCII, karena setiap pilihan dapat diwakili oleh hanya dua bit!

Spesifikasi

Misi Anda, jika Anda memilih untuk menerimanya, adalah menulis sepasang program, fungsi atau metode untuk mengubah representasi ASCII menjadi representasi biner dan kembali; mewakili Asebagai b00, Tsebagai b01, Gsebagai b10, dan Csebagai b11(selanjutnya "unit").

Selain itu, bit tinggi setiap byte harus berisi jumlah unit dalam byte, membuat setiap byte mewakili triplet.

Misalnya: "GATTACCA"menjadi b11 100001 b11 010011 b10 1100xx.

Dalam ASCII ke input biner, spasi, tab, dan baris baru harus diabaikan. Karakter apa pun yang tidak ada dalam set [ \r\n\tATGC]adalah kesalahan dan dapat diabaikan atau dihentikan pemrosesan.

Dalam input biner ke ASCII, byte yang dua bit tingginya b00dapat diabaikan.

Output ASCII dapat berisi spasi putih; tetapi tidak boleh lebih dari 4 kali ukuran input biner ditambah satu byte panjang, dan harus diakhiri dengan baris baru.

Output biner dapat berisi jumlah b00xxxxxxbyte "kontrol" yang sewenang-wenang ; tetapi tidak boleh lebih dari input ASCII.

Setiap program konversi harus mendukung input dengan panjang sewenang-wenang; dan harus menyelesaikan encoding atau decoding dalam waktu yang kurang lebih linier.

Twist

Sayangnya untuk ahli bioinformatika untuk siapa Anda melakukan tugas ini, ia dalam beberapa cara telah menganiaya Anda, pada tingkat pribadi namun mungkin kecil.

Mungkin dia pernah berkencan dengan kakakmu, dan tidak pernah memanggilnya lagi. Mungkin dia menginjak ekor anjing Anda. Spesifikasinya tidak terlalu penting.

Yang penting adalah Anda memiliki kesempatan untuk pengembalian!

Rinciannya

Setiap konversi harus menghasilkan tingkat kesalahan kecil; pada urutan satu kesalahan per sepuluh ribu hingga satu juta unit diproses.

Kesalahan dapat berupa salah satu dari yang berikut:

  • Kesalahan duplikasi: "GAT TAC CA"menjadi"GAT TAA CCA"
  • Kesalahan penghapusan: "GAT TAC CA"menjadi"GAT TAC A"
  • Kesalahan terjemahan: "GAT TAC CA"menjadi"GTA TAC CA"
  • Duplikasi triplet: "GAT TAC CA"menjadi"GAT TAC TAC CA"
  • Slippage triplet: "GAT TAC CA"menjadi"TAC GAT CA"
  • Pembalikan triplet: "GAT TAC CA"menjadi"GAT CAT CA"

Kesalahan itu akan diperkenalkan tentu saja tidak harus segera jelas dari kode; dan terlepas dari panjang input; konversi harus menghasilkan setidaknya satu kesalahan.

Dua proses dengan input yang identik tidak harus menghasilkan output yang identik.

Trik-nya

Bioinformatis vile adalah pembuat kode yang kompeten; dan dengan demikian, beberapa konstruksi akan ditemukan secara otomatis, dan karenanya dilarang:

  • Dia akan secara otomatis menemukan panggilan ke generator nomor acak sistem, seperti rand (), random (), atau membaca dari / dev / urandom atau / dev / random (atau apa pun yang setara dengan bahasa).
  • Dia juga akan melihat adanya variabel, penghitung atau loop berlebih.

Penilaian

Encoder dan decoder akan dinilai secara individual.

Masing-masing akan dijalankan 3 kali terhadap 100 file input yang dihasilkan secara acak, masing-masing file dengan ukuran 3 juta unit.

Data untuk kasus uji enkoder akan dibuat kira-kira seperti itu:

for (l = 1 => bigNum)
  for (t = 1 => 20)
    random_pick(3,ATGC)
    t == 20 ? newline : space

Data untuk kasus uji dekoder akan dibuat kira-kira seperti itu:

for (u = 1 => bigNum)
  for (t = 1 => 20)
    random_byte() | 0b11000000
   0x00

Encoder

  • Setiap byte yang hilang dari panjang minimum yang diharapkan pada panjang aktual akan mencetak -1 poin, hingga maksimum -1000. (Panjang minimum yang diharapkan adalah ceil(count(ATGC) / 3).)

Dekoder

  • Setiap byte melebihi panjang maksimum yang diharapkan dalam panjang aktual akan mencetak -1 poin, hingga maksimum -1000. (Panjang maksimum yang diharapkan adalah size(input) * 4 + 1.)

Kedua

  • Setiap jenis kesalahan yang dapat dihasilkan akan mendapat skor 100 poin; untuk total 600 poin yang mungkin untuk masing-masing, total 1200.
  • Setiap test case dimana encoder menghasilkan lebih dari 30% kesalahan lebih atau kurang dari rata-rata sendiri akan dihukum oleh -5 poin.
  • Setiap test case dimana encoder menghasilkan kesalahan kurang dari 15% lebih atau kurang dari rata-rata sendiri akan diberikan 5 poin.
  • Setiap test case di mana ketiga berjalan menghasilkan output yang identik akan dikenakan sanksi oleh -10 poin.

Persyaratan sulit

Entri akan didiskualifikasi jika:

  • Untuk input yang valid lebih dari satu triplet, gagal menghasilkan bahkan satu kesalahan.
  • Kinerjanya sedemikian rupa sehingga tidak dapat menyelesaikan tantangan pengujian dalam waktu sekitar satu jam.
  • Ini rata-rata menghasilkan lebih dari satu kesalahan dalam setiap sepuluh ribu unit.
  • Ini rata-rata menghasilkan kurang dari satu kesalahan dalam setiap juta unit.

Antarmuka

Peserta harus menerima input pada input standar, dan output ke output standar.

Jika entri adalah satu program dengan fungsi ganda; switch -edan masing-masing -dharus mengatur program untuk encoding dan decoding.

Contoh doa:

$ encoder <infile.txt >outfile.bin
$ decoder <infile.bin >outfile.txt
$ recoder -e <infile.txt >outfile.bin

Pemenang

Pemenangnya adalah entri dengan skor tertinggi; maksimum teoritis adalah 1200 untuk jenis kesalahan ditambah 3000 poin untuk stabilitas dalam tingkat pembangkitan kesalahan.

Dalam hal yang tidak mungkin terjadi seri; pemenang akan ditentukan oleh jumlah suara.

Catatan tambahan

Untuk keperluan menjalankan tantangan pengujian, setiap entri harus menyertakan instruksi jalankan atau kompilasi.

Semua entri sebaiknya dijalankan pada mesin Linux tanpa X.

Williham Totland
sumber
4
Mengubah tag. KotH adalah untuk tantangan di mana pengiriman berinteraksi satu sama lain. Juga saya khawatir sulit untuk menegakkan komponen "curang" secara objektif.
Martin Ender
2
Saya setuju dengan komentar @ m.buettner bahwa bagian yang curang sulit untuk dinilai. Di sisi lain saya merasa bahwa ini adalah satu-satunya bagian yang menarik dalam tantangan. Saya dapat menjamin bahwa pembuatan dan tingkat kesalahan tepat dalam spesifikasi dan karenanya memiliki poin maksimum. Atau apakah saya melewatkan sesuatu dari spec? Selain itu, Jika jenis kesalahan tambahan diterima, itu akan ditambahkan ke daftar di atas; dan semua jawaban akan diberi skor di atasnya. Sepertinya Anda akan mengubah tantangan setelah orang mulai bekerja atau mengirimkan solusi yang menurut saya bukan ide yang baik.
Howard
@ Howard: Tercatat Aturan diperbarui dengan kriteria curang yang spesifik; dan aspek mutasi wrt. kesalahan dihapus.
Williham Totland
1
Saya akan memberikan jawaban saya .. tapi saya pikir dua kalimat "Setiap konversi harus memperkenalkan tingkat kesalahan kecil; pada urutan satu kesalahan per sepuluh ribu hingga satu juta unit diproses." dan "Sebuah entri akan didiskualifikasi jika: Secara rata-rata menghasilkan lebih dari satu kesalahan dalam setiap sepuluh ribu unit." tidak kompatibel. Hal yang sama antara "Setiap konversi harus menghasilkan tingkat kesalahan kecil; berdasarkan urutan satu kesalahan per sepuluh ribu hingga satu juta unit yang diproses." dan "Entri akan didiskualifikasi jika: Secara rata-rata menghasilkan kurang dari satu kesalahan dalam setiap juta unit."
Mattsteel
1
Saya memberikan suara untuk menutup pertanyaan ini sebagai di luar topik karena tantangan curang tidak lagi pada topik di situs ini. meta.codegolf.stackexchange.com/a/8326/20469
cat

Jawaban:

3

Perl 5.10

Saya senang mempersembahkan solusi saya di Perl.

Ketika saya memulai tantangan saya cukup yakin bahwa Perl akan tetap di bawah batas 1 jam.

Untuk tujuan pengujian saya mengembangkan generator sampel polos dan generator sampel berkode.

Kemudian saya mengembangkan encoder yang membutuhkan upaya lebih besar dan menghasilkan kode yang lebih panjang. Encoder berfungsi sebagai berikut:

  1. loop pertama membaca seluruh file dan membagi data untuk memiliki array dari semua kembar tiga
  2. loop kedua melintasi array dan menambahkan ke setiap elemen panjangnya
  3. loop ketiga melintasi lagi dan memetakan setiap karakter untuk memberikan output.

Output biner yang dikodekan diformat sebagai "garis" yang diakhiri baris baru dari 20 oktet di mana setiap oktet mengkodekan satu triplet, dengan dua karakter awalan (seperti nomor baris siklikal).

misalnya, input tiga byte terpendek :

AAA

harus memberikan output terpendek tiga byte plus baris baru.

00ÿ

itu adalah

30 30 FF 0A

dan

AGG CGC AAC GGC TAA ATC GTT TTC ACA CCA CGT TTG AAA CGG GTG ACA CGA GAT TTA GTC
TAT GGT ACT AGG TAC GCC GTG GTG CGT GCG GAG TTA CTA GAT GTG TTA GTA CGC CAT CGT

harus memberikan biner berikut.

01ÊûÃëÐÇå×ÌüùÖÀúæÌøáÔç
00ÑéÍÊÓïææùîâÔôáæÔäûñù

Haruskah karena tingkat kesalahan kecil: Untuk input terkecil, skrip memperkenalkan 1 kesalahan.

Untuk menjalankan file 3 juta triplets, encoder memperkenalkan 11 kesalahan.

Asalkan skripnya adalah dnacodec3.pl, proses dijalankan pada prompt perintah seperti biasa:

$> perl dnacodec3.pl -e < plain.txt > coded.txt

Dekoder berfungsi sebagai berikut:

  1. loop pertama membaca seluruh file dan membagi data untuk memiliki array semua oktet. Ini melacak setiap baris baru.
  2. loop kedua memeriksa setiap oktet, mempertahankan yang tidak dimulai dengan 00 dan mengabaikan sisanya. Output Ascii biasa diformat sebagai garis triplet terminasi baris baru yang dipisahkan oleh satu ruang. Baris baru berada di posisi yang sama seperti di input.

Saya menyiapkan file tes sampel 3 juta kembar tiga (sekitar 12MByte) dan diuji waktunya. Menggunakan laptop saya dengan Intel Core i5 vPro pada 2,6 GHz, proses encoder 3M selalu membutuhkan waktu kurang dari 20 detik. Selama menjalankannya dibutuhkan 200-220 MByte RAM. Sayang sekali!

Proses dekode memakan waktu kurang dari 10 detik. Itu tidak dapat memperkenalkan kesalahan ... untuk saat ini.

Sekali lagi, untuk menjalankan decoding

$> perl dnacodec3.pl -d < coded.txt > plain.txt

Ini kodenya

#!/usr/bin/perl
use strict ;
use warnings ;
my $switch = shift || die "usage $0 [-e|-d]\n";
my %map = qw( x 10  X 11  c 0b  ? 00
              A 00  T 01  G 10  C 11  
              0 00  1 01  2 10  3 11  
              00 A  01 T  10 G  11 C  ) ;
my $r = 20 ;
my @dummy = unpack ( '(A4)*', '0xxx' x $r ) ;
my $map = oct( $map{ c } . ($map{ C } x 9) ) ;
my $t = time() ;
my @inp = () ;
my @out = () ;
my @buf = () ;
my $n ;

sub arch {
    push @buf, @dummy[ 0 .. $r - $#buf - 2 ] ;
    push @out, "@buf" ;
    @buf = () ;
}

sub encode {
    my $mask = '(A3)*' ;
    while ( my $row = <STDIN> ) {
        chomp $row ;
        $row =~ s/\s+//g ;
        $row =~ s/[^\r\n\tATGC]//g ;
        next unless $row ;
        my @row = unpack( $mask, $row ) ;
        push @inp, @row if $row ;
    }
    $n = scalar @inp ;
    $r = $n if $r > $n ;
    for ( my $i = $n - 1 ; $i >= 0 ; --$i ) {
        my $e = $inp[$n-$i-1] ;
        my $l = length( $e ) ;
        my $d = $e =~ /\?/? 0: $l ;
        push @buf, ( $d -((($i-($n>>1))&$map)?0:1) )
           . $e . 'x'x(3-$l) ;
        arch unless $i % $r ;
    }
    arch if scalar @buf ;
    my $m = scalar @out ;
    for ( my $j = $m - 1 ; $j >= 0; --$j ) {
        my @ary = () ;
        my $e = $out[$m-$j-1] ;
        for my $byte ( split / /, $e ) {
            my @byte = split ( //, $byte ) ;
            my @trad = map { $map{ $_ } } @byte ;
            my $byte = join( '', @trad ) ;
            push @ary, $byte ;
        };
        my $row = sprintf( '%02d', $j % $r) ;
        $row .= pack( '(B8)*', @ary ) ;
        print "$row\n" ;
    }
}

sub decode {
    my $mask = '(B8)*' ;
    while ( my $row = <STDIN> ) {
        chomp $row ;
        next unless $row ;
        my @row = unpack( $mask, $row ) ;
        push @inp, @row[0..$#row], '?' if $row ;
    }
    $n = scalar @inp ;
    my @ary = () ;
    for ( my $i = $n - 1 ; $i >= 0 ; --$i ) {
        my $e = $inp[$n-$i-1] ;
        if ( $e ne '?' ) {
            my $u = oct( '0b'. substr($e,0,2) ) ;
            my $a = '' ;
            for my $j ( 1 .. $u ) {
                $a .= $map{ substr($e,$j+$j,2) } ;
            }
            push @ary, $a if $u ;
        }
        else {
            my $row = "@ary" ;
            $row =~ s/\s{2,}//g ;
            print "$row\n" if $row ;
            @ary =() ;
        }
    }
}

decode if $switch eq '-d' ;
encode if $switch eq '-e' ;

Dan inilah contoh generatornya:

sub test_coder {
    my $n = shift || 1000 ;
    my @b = qw( A C G T ) ;
    for (my $l = 0; $l < $n; $l++) {
        my @ary = () ;
        for (my $t = 0; $t < 20; $t++) {
            push @ary, $b[ int(rand(4)) ] . $b[ int(rand(4)) ] . $b[ int(rand(4)) ] ;
        }
        print "@ary\n" ;
    }
    1;
}

sub test_decoder {
    my $n = shift || 1000;
    for (my $l = 0; $l < $n; $l++) {
        my @ary = () ;
        for (my $t = 0; $t < 20; $t++) {
            push @ary, int(rand(256)) | 0b11000000 ;
        }
        my $row = pack( 'C*', @ary ) ;
        print "$row\000" ;
    }
    1;
}


test_coder( @ARGV ) if $switch eq '-g' ;
test_decoder( @ARGV )  if $switch eq '-h' ;
Mattsteel
sumber
Saya lupa menunjukkan di mana kesalahan disuntikkan: push @ buf di loop kedua melakukan trik.
Mattsteel
Ini halus, aku akan memberimu itu. Saya tidak akan menjalankan tes skala penuh sampai ada lebih dari satu pesaing, tetapi ini bagus. :)
Williham Totland
Terima kasih. Saya tahu ini adalah saran untuk teman-teman lain ... Saya ingin meningkatkan keacakan posisi kesalahan menggunakan fungsi waktu (masih belum digunakan): mulai dijalankan pada detik ganjil atau genap akan menghasilkan output yang berbeda
Mattsteel