Mã hóa * không có lỗi hiệu quả [đã đóng]


20

Nhiệm vụ

Như đã biết, vật liệu di truyền của tất cả các sinh vật được biết đến trên Trái đất được mã hóa trong DNA; sử dụng bốn nucleotide adenine, thymine, cytosine và guanine. (Thường được đại diện bởi ATGC).

Một nhà sinh lý học muốn lưu trữ toàn bộ bộ gen tất nhiên sẽ không muốn lưu trữ nó dưới dạng ASCII, bởi vì mỗi lựa chọn có thể được biểu thị bằng chỉ hai bit!

Các đặc điểm kỹ thuật

Nhiệm vụ của bạn, nếu bạn chọn chấp nhận nó, là viết một cặp chương trình, hàm hoặc phương thức để chuyển đổi một biểu diễn ASCII thành biểu diễn nhị phân và ngược lại; đại diện Anhư b00, Tnhư b01, Gnhư b10, và Cnhư b11(từ đó "đơn vị").

Ngoài ra, các bit cao của mỗi byte nên chứa số đơn vị trong byte, làm cho mỗi byte đại diện cho một bộ ba.

Ví dụ: "GATTACCA"trở thành b11 100001 b11 010011 b10 1100xx.

Trong ASCII đến đầu vào nhị phân, không gian, tab và dòng mới nên được bỏ qua. Bất kỳ ký tự nào không có trong tập hợp [ \r\n\tATGC]là một lỗi và có thể bị bỏ qua hoặc chấm dứt xử lý.

Trong đầu vào nhị phân sang ASCII, các byte có hai bit cao b00có thể bị bỏ qua.

Đầu ra ASCII có thể chứa khoảng trắng; nhưng không bao giờ được lớn hơn 4 lần kích thước của đầu vào nhị phân cộng với một byte dài và phải kết thúc bằng một dòng mới.

Đầu ra nhị phân có thể chứa một số b00xxxxxxbyte "điều khiển" tùy ý ; nhưng không bao giờ được dài hơn đầu vào ASCII.

Mỗi chương trình chuyển đổi phải hỗ trợ đầu vào có độ dài tùy ý; và nên hoàn thành mã hóa hoặc giải mã trong khoảng thời gian tuyến tính.

Vắt

Thật không may cho nhà sinh lý học mà bạn đang thực hiện nhiệm vụ này, anh ta bằng một cách nào đó đã làm bạn sai, ở mức độ cá nhân nhưng có lẽ nhỏ nhặt.

Có lẽ anh ấy đã đi chơi với em gái bạn một lần, và không bao giờ gọi lại cho cô ấy nữa. Có lẽ anh ta giẫm lên đuôi chó của bạn. Các chi tiết cụ thể không thực sự quan trọng.

Điều quan trọng là bạn có cơ hội hoàn vốn!

Các chi tiết

Mỗi chuyển đổi nên đưa ra một tỷ lệ lỗi nhỏ; theo thứ tự một lỗi trên mười nghìn đến một triệu đơn vị được xử lý.

Một lỗi có thể là một trong những điều sau đây:

  • Lỗi trùng lặp: "GAT TAC CA"trở thành"GAT TAA CCA"
  • Lỗi xóa: "GAT TAC CA"trở thành"GAT TAC A"
  • Lỗi dịch: "GAT TAC CA"trở thành"GTA TAC CA"
  • Sao chép bộ ba: "GAT TAC CA"trở thành"GAT TAC TAC CA"
  • Trượt ba lần: "GAT TAC CA"trở thành"TAC GAT CA"
  • Đảo ngược bộ ba: "GAT TAC CA"trở thành"GAT CAT CA"

Tất nhiên, các lỗi đó sẽ được đưa ra nên không rõ ràng ngay từ mã; và không phân biệt độ dài của đầu vào; việc chuyển đổi sẽ giới thiệu ít nhất một lỗi.

Hai lần chạy với đầu vào giống hệt nhau không nhất thiết phải tạo ra đầu ra giống hệt nhau.

Bí quyết

Nhà sinh lý học tệ hại là một lập trình viên có năng lực vừa phải; và như vậy, một số cấu trúc sẽ được tự động phát hiện và bị cấm như vậy:

  • Anh ta sẽ tự động khám phá bất kỳ cuộc gọi nào đến các trình tạo số ngẫu nhiên của hệ thống, chẳng hạn như rand (), Random () hoặc đọc từ / dev / urandom hoặc / dev / Random (hoặc bất cứ ngôn ngữ nào tương đương).
  • Anh ta cũng sẽ nhận thấy bất kỳ biến, bộ đếm hoặc vòng lặp thừa.

Việc ghi bàn

Bộ mã hóa và giải mã sẽ được ghi điểm riêng.

Mỗi tệp sẽ được chạy 3 lần so với bộ 100 tệp đầu vào được tạo ngẫu nhiên, mỗi tệp có kích thước theo thứ tự 3 triệu đơn vị.

Dữ liệu cho các trường hợp kiểm tra bộ mã hóa sẽ được tạo ra như sau:

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

Dữ liệu cho các trường hợp kiểm tra bộ giải mã sẽ được tạo ra như sau:

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

Bộ mã hóa

  • Mỗi byte bị thiếu từ độ dài tối thiểu dự kiến ​​trong độ dài thực tế sẽ ghi -1 điểm, tối đa -1000. (Độ dài tối thiểu dự kiến ​​là ceil(count(ATGC) / 3).)

Bộ giải mã

  • Mỗi byte trên độ dài tối đa dự kiến ​​trong chiều dài thực tế sẽ ghi -1 điểm, tối đa -1000. (Độ dài tối đa dự kiến ​​là size(input) * 4 + 1.)

Cả hai

  • Mỗi loại lỗi có thể được tạo ra sẽ ghi được 100 điểm; cho tổng số 600 điểm có thể cho mỗi, tổng cộng 1200.
  • Mỗi trường hợp thử nghiệm mà bộ mã hóa tạo ra nhiều hơn hoặc ít hơn 30% lỗi so với mức trung bình của chính nó sẽ bị phạt -5 điểm.
  • Mỗi trường hợp thử nghiệm mà bộ mã hóa tạo ra ít hơn 15% lỗi hoặc ít hơn mức trung bình của chính nó sẽ được cho 5 điểm.
  • Mỗi trường hợp thử nghiệm trong đó cả ba lần chạy tạo ra kết quả đầu ra giống hệt nhau sẽ bị phạt -10 điểm.

Yêu cầu khó

Một mục sẽ bị loại nếu:

  • Đối với bất kỳ đầu vào hợp lệ nào dài hơn một bộ ba, nó không tạo ra một lỗi.
  • Hiệu suất của nó là như vậy mà nó không thể hoàn thành găng tay thử nghiệm trong vòng khoảng một giờ.
  • Nó trung bình tạo ra nhiều hơn một lỗi trong mỗi mười nghìn đơn vị.
  • Nó trung bình tạo ra ít hơn một lỗi trong mỗi triệu đơn vị.

Giao diện

Những người tham gia nên chấp nhận đầu vào trên đầu vào tiêu chuẩn và đầu ra cho đầu ra tiêu chuẩn.

Nếu mục nhập là một chương trình có chức năng kép; các công tắc -e-dnên đặt chương trình để mã hóa và giải mã tương ứng.

Ví dụ yêu cầu:

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

Người chiến thắng

Người chiến thắng là bài dự thi có số điểm cao nhất; tối đa theo lý thuyết là 1200 cho các loại lỗi cộng với 3000 điểm cho sự ổn định trong tốc độ tạo lỗi.

Trong trường hợp không thể rút thăm; người chiến thắng sẽ được xác định bằng số phiếu.

Các ghi chú bổ sung

Đối với mục đích chạy găng tay kiểm tra, mỗi mục nên bao gồm các hướng dẫn chạy hoặc biên dịch.

Tất cả các mục tốt nhất là có thể chạy được trên máy Linux mà không cần X.


4
Thay đổi thẻ. KotH dành cho những thách thức trong đó các bài nộp tương tác với nhau. Ngoài ra, tôi e rằng sẽ khó có thể thực thi thành phần "ngầm" một cách khách quan.
Martin Ender

2
Tôi đồng ý với nhận xét của @ m.buettner rằng phần khó hiểu là khó đánh giá. Mặt khác tôi cảm thấy rằng đây là phần thú vị duy nhất trong thử thách. Tôi có thể đảm bảo rằng việc tạo và tỷ lệ lỗi chính xác trong các thông số kỹ thuật và do đó có điểm tối đa. Hay tôi bỏ lỡ một cái gì đó từ thông số kỹ thuật? Hơn nữa, nếu một loại lỗi bổ sung được chấp nhận, nó sẽ được thêm vào danh sách trên; và tất cả các câu trả lời sẽ được ghi vào nó. Có vẻ như bạn sẽ thay đổi thử thách sau khi mọi người bắt đầu làm việc hoặc gửi giải pháp mà tôi nghĩ không phải là một ý tưởng tốt.
Howard

@Howard: Lưu ý. Các quy tắc được cập nhật với các tiêu chí ngầm cụ thể; và khía cạnh đột biến wrt. lỗi được loại bỏ.
Williham Totland

1
Tôi sẽ đưa ra câu trả lời của mình .. nhưng tôi nghĩ hai câu "Mỗi chuyển đổi sẽ đưa ra một tỷ lệ lỗi nhỏ; theo thứ tự một lỗi trên mười nghìn đến một triệu đơn vị được xử lý." và "Một mục nhập sẽ bị loại nếu: Trung bình nó tạo ra nhiều hơn một lỗi trong mỗi mười nghìn đơn vị." không tương thích. Giống nhau giữa "Mỗi chuyển đổi sẽ đưa ra một tỷ lệ lỗi nhỏ; theo thứ tự một lỗi trên mười nghìn đến một triệu đơn vị được xử lý." và "Một mục nhập sẽ bị loại nếu: Trung bình nó tạo ra ít hơn một lỗi trong mỗi triệu đơn vị."
Mattsteel 24/07/2015

1
Tôi đang bỏ phiếu để đóng câu hỏi này dưới dạng ngoài chủ đề vì các thử thách ngầm không còn thuộc chủ đề trên trang web này. meta.codegolf.stackexchange.com/a/8326/20469
mèo

Câu trả lời:


3

Perl 5.10

Tôi rất vui khi trình bày giải pháp của mình trong Perl.

Khi tôi bắt đầu thử thách, tôi khá chắc chắn rằng Perl sẽ ở dưới mức giới hạn 1 giờ.

Để thử nghiệm, tôi đã phát triển một trình tạo mẫu đơn giản và một trình tạo mẫu được mã hóa.

Sau đó, tôi đã phát triển bộ mã hóa cần một nỗ lực lớn hơn và tạo ra một mã dài hơn. Bộ mã hóa hoạt động như sau:

  1. vòng lặp đầu tiên đọc toàn bộ tệp và phân tách dữ liệu để có một mảng gồm tất cả các bộ ba
  2. vòng lặp thứ hai đi qua mảng và thêm vào mỗi phần tử chiều dài của nó
  3. vòng lặp thứ ba đi qua một lần nữa và ánh xạ từng ký tự để đưa ra đầu ra.

Đầu ra nhị phân được mã hóa được định dạng như là "dòng" kết thúc dòng mới gồm 20 octet trong đó mỗi octet mã một bộ ba, với hai ký tự tiền tố (như số dòng theo chu kỳ).

ví dụ, đầu vào ba byte ngắn nhất :

AAA

sẽ cung cấp đầu ra ngắn nhất trong ba byte cộng với dòng mới.

00ÿ

đó là

30 30 FF 0A

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

nên cho nhị phân sau.

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

Nên vì tỷ lệ lỗi nhỏ: Đối với đầu vào nhỏ nhất, tập lệnh đưa ra 1 lỗi.

Đối với tệp 3 triệu bộ ba chạy, bộ mã hóa đưa ra 11 lỗi.

Với điều kiện là tập lệnh là dnacodec3.pl, việc chạy được gọi tại dấu nhắc lệnh như bình thường:

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

Bộ giải mã hoạt động như sau:

  1. vòng lặp đầu tiên đọc toàn bộ tệp và phân tách dữ liệu để có một mảng gồm tất cả các octet. Nó theo dõi mọi dòng mới.
  2. vòng lặp thứ hai kiểm tra từng octet, giữ lại những cái không bắt đầu bằng 00 và bỏ qua phần còn lại. Đầu ra đơn giản của Ascii được định dạng là các dòng ba kết thúc dòng mới được phân tách bằng một khoảng trắng. Dòng mới ở cùng vị trí với đầu vào.

Tôi đã chuẩn bị một tệp thử nghiệm mẫu 3 triệu triplets (khoảng 12MByte) và kiểm tra thời gian. Sử dụng máy tính xách tay của tôi với Intel Core i5 vPro tốc độ 2,6 GHz, bộ mã hóa 3M chạy luôn chỉ mất chưa đến 20 giây. Trong quá trình chạy, phải mất 200-220 MByte RAM. Thật là lãng phí!

Quá trình giải mã mất ít hơn 10 giây. Nó không thể giới thiệu lỗi ... bây giờ.

Một lần nữa, để chạy giải mã

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

Đây là mã

#!/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' ;

Và đây là trình tạo mẫu:

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' ;

Tôi đã quên chỉ ra lỗi được đưa vào đâu: đẩy @buf trong vòng lặp thứ hai thực hiện thủ thuật.
Mattsteel

Thật tinh tế, tôi sẽ cung cấp cho bạn điều đó. Tôi sẽ không chạy thử nghiệm toàn diện cho đến khi có nhiều hơn một đối thủ cạnh tranh, nhưng đây là công cụ tốt. :)
Williham Totland

Cảm ơn. Tôi biết đây là một gợi ý cho những người bạn khác ... Tôi muốn cải thiện tính ngẫu nhiên của vị trí lỗi bằng cách sử dụng func thời gian (vẫn chưa được sử dụng): bắt đầu chạy ở số lẻ hoặc chẵn giây sẽ mang lại đầu ra khác nhau
Mattsteel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.