효율적인 오류없는 * 인코딩 [닫기]


20

미션

잘 알려진 바와 같이, 지구상의 모든 알려진 생물체의 유전 물질은 DNA로 인코딩됩니다. 4 개의 뉴클레오타이드 아데닌, 티민, 사이토 신 및 구아닌을 사용함. (일반적으로 ATGC로 표시).

전체 게놈을 저장하고자하는 생물 정보 학자는 물론 각 선택이 단지 2 비트로 표현 될 수 있기 때문에 이것을 ASCII로 저장하고 싶지 않을 것입니다!

사양

당신이 그것을 받아들이기로 선택한다면, 당신의 임무는 ASCII 표현을 이진 표현으로 변환하는 프로그램, 함수 또는 메소드 쌍을 작성하는 것입니다. 대표 Ab00, Tb01, Gb10, 그리고 C같은 b11(이제부터는 "단위").

또한 각 바이트의 상위 비트는 바이트 단위 수를 포함해야하므로 각 바이트는 삼중 항을 나타냅니다.

예를 들면 다음과 같습니다 "GATTACCA"된다 b11 100001 b11 010011 b10 1100xx.

ASCII에서 이진 입력으로, 공백, 탭 및 줄 바꿈은 무시해야합니다. 세트에없는 문자 [ \r\n\tATGC]는 오류이며 무시되거나 처리가 종료 될 수 있습니다.

2 진 대 ASCII 입력에서 2 개의 상위 비트가 b00무시 되는 바이트는 무시 될 수 있습니다.

ASCII 출력에는 공백이 포함될 수 있습니다. 그러나 이진 입력 크기의 4 배 이상 1 바이트 길이를 초과해서는 안되며 개행 문자로 끝나야합니다.

이진 출력에는 임의의 수의 b00xxxxxx"제어"바이트 가 포함될 수 있습니다 . 그러나 ASCII 입력보다 길어서는 안됩니다.

각 변환 프로그램은 임의 길이의 입력을 지원해야합니다. 대략 선형 시간으로 인코딩 또는 디코딩을 완료해야합니다.

트위스트

불행히도, 당신이이 일을 수행하고있는 생물 정보 학자에게, 그는 개인적이지만 아직 사소한 수준에서 당신을 어떤 식 으로든 잘못 판단했습니다.

아마 그는 언니와 한 번 나갔고 다시는 전화하지 않았습니다. 아마도 그는 당신의 개 꼬리를 밟았을 것입니다. 세부 사항은 실제로 중요하지 않습니다.

중요한 것은 회수 할 기회가 있다는 것입니다!

상세

각 변환은 작은 오류율을 가져야합니다. 처리 된 10,000 ~ 백만 단위 당 하나의 오류의 순서로.

오류는 다음 중 하나 일 수 있습니다.

  • 중복 오류 : "GAT TAC CA"이된다"GAT TAA CCA"
  • 삭제 오류 : "GAT TAC CA"이된다"GAT TAC A"
  • 번역 오류 : "GAT TAC CA"된다"GTA TAC CA"
  • 삼중 중복 : "GAT TAC CA"이된다"GAT TAC TAC CA"
  • 삼중 slippages : "GAT TAC CA"이된다"TAC GAT CA"
  • 삼중 반전 : "GAT TAC CA"이된다"GAT CAT CA"

물론 오류는 코드에서 즉시 명백하지 않아야합니다. 입력의 길이에 관계없이; 변환시 하나 이상의 오류가 발생해야합니다.

동일한 입력을 가진 두 개의 런이 반드시 동일한 출력을 생성 할 필요 는 없습니다 .

트릭

사악한 생물 정보 학자는 적당히 유능한 코더입니다. 따라서 일부 구조는 자동으로 발견되며 금지됩니다.

  • rand (), random () 또는 / dev / urandom 또는 / dev / random (또는 동등한 언어)에서 읽는 것과 같은 시스템 난수 생성기에 대한 호출을 자동으로 감지합니다.
  • 또한 불필요한 변수, 카운터 또는 루프를 알 수 있습니다.

득점

인코더와 디코더는 개별적으로 점수가 매겨집니다.

각 파일은 무작위로 생성 된 100 개의 입력 파일 세트에 대해 3 번 실행되며 각 파일의 크기는 3 백만 단위입니다.

인코더 테스트 사례에 대한 데이터는 대략 다음과 같이 생성됩니다.

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

디코더 테스트 사례에 대한 데이터는 대략 다음과 같이 생성됩니다.

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

인코더

  • 실제 길이에서 예상되는 최소 길이에서 누락 된 각 바이트는 -1 점 (최대 -1000)입니다. (예상되는 최소 길이는 ceil(count(ATGC) / 3)입니다.)

디코더

  • 실제 길이에서 예상되는 최대 길이를 초과하는 각 바이트는 -1 점 (최대 -1000)입니다. (예상 최대 길이는 size(input) * 4 + 1입니다.)

양자 모두

  • 생성 될 수있는 각 종류의 오류는 100 점을받습니다. 각각에 대해 총 600 점, 총 1200 점.
  • 엔코더가 자체 평균보다 30 % 이상 많은 오차를 생성하는 각 테스트 케이스에는 -5 포인트가 부과됩니다.
  • 엔코더가 자체 평균보다 15 % 미만의 오차를 생성하는 각 테스트 케이스에는 5 포인트가 부여됩니다.
  • 세 번의 런이 모두 동일한 출력을 생성하는 각 테스트 케이스에는 -10 포인트가 부과됩니다.

어려운 요구 사항

다음과 같은 경우 참가 자격이 박탈됩니다.

  • 하나의 삼중 항보다 긴 유효한 입력의 경우 하나의 오류도 생성하지 않습니다.
  • 성능은 약 1 시간 내에 테스트 건틀릿을 완료 할 수 없습니다.
  • 평균적으로 만 단위마다 하나 이상의 오류가 발생합니다.
  • 평균적으로 백만 단위마다 하나 미만의 오류가 발생합니다.

인터페이스

참가자는 표준 입력의 입력을 수락하고 표준 출력으로 출력해야합니다.

항목이 이중 기능을 가진 하나의 프로그램 인 경우; 스위치 -e-d각각 인코딩 및 디코딩을위한 프로그램을 설정해야합니다.

예제 호출 :

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

승자

승자가 가장 높은 점수를받은 항목입니다. 이론상 최대 값은 오류 종류의 경우 1200이고 오류 발생률의 안정성은 3000 포인트입니다.

드물게 추첨의 경우; 우승자는 투표 수에 따라 결정됩니다.

추가 메모

테스트 건틀릿을 실행하기 위해 각 항목에는 실행 또는 컴파일 지침이 포함되어야합니다.

모든 항목은 X가없는 Linux 시스템에서 실행 가능해야합니다.


4
태그를 변경했습니다. KotH는 제출물이 서로 상호 작용하는 문제에 대한 것입니다. 또한 "손잡은"구성 요소를 객관적으로 시행하는 것이 불가능하기가 두렵습니다.
Martin Ender 2016 년

2
나는 언더 파트가 판단하기 어렵다는 @ m.buettner의 의견에 동의합니다. 반면에 나는 이것이 도전에서 유일하게 흥미로운 부분이라고 생각합니다. 오류 생성 및 속도가 정확히 사양 내에 있으므로 최대 점수를 갖도록 보장 할 수 있습니다. 아니면 사양에서 뭔가를 놓치게 되나요? 또한 다른 종류의 오류가 허용되면 위 목록에 추가됩니다. 모든 답변에 점수가 매겨집니다. 사람들이 작업을 시작하거나 솔루션을 제출 한 후 좋은 생각이 아니라고 생각하면 도전을 바꿀 것 같습니다.
Howard

@Howard : 주목했다. 규칙은 특정한 미달 조건으로 업데이트됩니다. 및 돌연변이 측면 wrt. 오류가 제거됩니다.
Williham Totland

1
나는 대답을하려고한다. 그러나 나는 두 개의 문장은 "각 변환마다 약간의 오류율이 발생해야한다; 처리되는 1 만에서 1 백만 단위 당 하나의 오류의 순서로"라고 생각한다. 그리고 "만약 엔트리가 평균적으로 만 단위마다 두 개 이상의 에러를 생성한다면" 호환되지 않습니다. "각 변환마다 작은 오류율이 발생해야합니다. 처리 된 작업은 1 만에서 1 백만 단위당 한 번의 오류입니다." "다음과 같은 경우 참가 자격이 박탈됩니다. 평균적으로 백만 단위로 1 개 미만의 오류가 발생합니다."
Mattsteel

1
나는이 문제를 주제로 다루지 않기로 결심했다. 왜냐하면이 사이트에서 미숙 한 도전은 더 이상 주제가 아니기 때문이다. meta.codegolf.stackexchange.com/a/8326/20469
cat

답변:


3

펄 5.10

Perl에서 솔루션을 소개하게되어 기쁩니다.

도전을 시작했을 때 나는 Perl이 1 시간의 한도보다 훨씬 낮을 것이라고 확신했다.

테스트 목적으로 일반 샘플 생성기와 코딩 된 샘플 생성기를 개발했습니다.

그런 다음 더 큰 노력을 기울이고 더 긴 코드를 생성하는 인코더를 개발했습니다. 인코더는 다음과 같이 작동합니다.

  1. 첫 번째 루프는 전체 파일을 읽고 모든 세 쌍둥이 배열을 갖도록 데이터를 분할합니다.
  2. 두 번째 루프는 배열을 통과하고 각 요소 앞에 길이를 붙입니다.
  3. 세 번째 루프는 다시 순회하고 각 문자를 매핑하여 출력을 제공합니다.

코딩 된 이진 출력은 20 옥텟의 줄 바꿈으로 끝나는 "행"으로 형식화됩니다. 여기서 각 옥텟은 두 개의 접두어 문자 (순환 행 번호와 같은)로 한 개의 삼중 항을 코딩합니다.

예를 들어 가장 짧은 3 바이트 입력 :

AAA

3 바이트의 가장 짧은 출력과 줄 바꾸기를 제공해야합니다.

00ÿ

그건

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

다음 바이너리를 제공해야합니다.

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

해야 하기 때문에 작은 오류 속도 : 가장 작은 입력의 경우, 스크립트를 소개 한 오류입니다.

3 백만 개의 트리플렛 파일 실행의 경우 인코더에 11 개의 오류가 발생합니다.

스크립트가 dnacodec3.pl 인 경우 평소와 같이 명령 프롬프트에서 실행이 호출됩니다.

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

디코더는 다음과 같이 작동합니다.

  1. 첫 번째 루프는 전체 파일을 읽고 모든 옥텟의 배열을 갖도록 데이터를 분할합니다. 모든 개행을 추적합니다.
  2. 두 번째 루프는 각 옥텟을 검사하여 00으로 시작하지 않는 것을 유지하고 나머지는 무시합니다. 일반 Ascii 출력은 한 줄 간격으로 구분 된 줄 바꿈으로 끝나는 줄 바꿈 형식으로 표시됩니다. 줄 바꾸기는 입력 과 동일한 위치에 있습니다.

3 백만 개의 삼중 샘플 테스트 파일 (약 12MByte)을 준비하고 타이밍 테스트를 거쳤습니다. 2.6GHz에서 Intel Core i5 vPro와 함께 랩톱을 사용하면 3M 인코더 실행에 항상 20 초 미만이 소요됩니다. 실행하는 동안 200-220MB의 RAM이 필요합니다. 정말 낭비입니다!

디코드 실행은 10 초 미만입니다. 지금은 오류가 발생할 수 없습니다 ...

다시, 디코딩 실행을 위해

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

여기 코드가 있습니다

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

다음은 샘플 생성기입니다.

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

오류가 주입되는 위치를 잊어 버렸습니다. 두 번째 루프의 push @buf가 트릭을 수행합니다.
Mattsteel

미묘하다, 나는 당신에게 그것을 줄 것이다. 경쟁 업체가 두 명 이상이 될 때까지 본격적인 테스트를 실시하지는 않지만 좋은 결과입니다. :)
Williham Totland

감사. 나는 이것이 다른 친구들을위한 제안이라는 것을 알고 있습니다 ... (아직 사용하지 않는) 시간 기능을 사용하여 오류 위치의 임의성을 개선하고 싶습니다. 홀수 또는 초 단위로 실행을 시작하면 다른 출력을 산출해야합니다
Mattsteel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.