効率的なエラーのない*エンコード[終了]


20

使命

よく知られているように、地球上のすべての既知の生物の遺伝物質はDNAにエンコードされています。アデニン、チミン、シトシン、グアニンの4つのヌクレオチドを使用します。(一般にATGCで表されます)。

ゲノム全体を保存したい生物情報学者は、もちろんこれをASCIIとして保存することを望まないでしょう。なぜなら、それぞれの選択肢はたった2ビットで表現できるからです!

仕様

あなたがそれを受け入れることを選択した場合、あなたの使命は、ASCII表現をバイナリ表現に変換して戻すための一対のプログラム、関数、またはメソッドを書くことです。Aas b00Tas b01Gas b10Cas b11(以下「ユニット」)を表します。

さらに、各バイトの上位ビットにはバイト内のユニット数が含まれている必要があり、各バイトはトリプレットを表します。

たとえば、次のように"GATTACCA"なりb11 100001 b11 010011 b10 1100xxます。

ASCIIからバイナリへの入力では、スペース、タブ、改行を無視する必要があります。のセットにない文字は[ \r\n\tATGC]エラーであり、無視されるか、処理を終了します。

バイナリからASCIIへの入力では、上位2ビットが含まb00れるバイトは無視されます。

ASCII出力には空白が含まれる場合があります。ただし、バイナリ入力のサイズの4倍に1バイトを加えた長さであってはならず、改行で終わる必要があります。

バイナリ出力には、任意の数のb00xxxxxx「制御」バイトが含まれる場合があります。ただし、ASCII入力より長くすることはできません。

各変換プログラムは、任意の長さの入力をサポートする必要があります。エンコードまたはデコードをほぼ線形の時間で完了する必要があります。

ひねり

残念ながら、あなたがこのタスクを実行している生物情報学者にとって、彼は何らかの形であなたを不当に扱いました。

おそらく、彼はあなたの妹と一度出かけ、二度と電話をかけなかったのでしょう。おそらく彼はあなたの犬の尻尾を踏みました。詳細は本当に重要ではありません。

重要なのは、投資回収のチャンスがあるということです!

詳細

各変換では小さなエラー率が発生するはずです。処理される1万から100万単位ごとに1エラーのオーダー。

エラーは次のいずれかです。

  • 複製エラー:に"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"
  • トリプレットスリッページ:に"GAT TAC CA"なります"TAC GAT CA"
  • トリプレット反転:に"GAT TAC CA"なります"GAT CAT CA"

もちろん、エラーが発生することは、コードからすぐには明らかにならないはずです。入力の長さに関係なく; 変換により、少なくとも1つのエラーが発生するはずです。

同一の入力で2回実行しても、必ずしも同一の出力が生成されるとは限りません。

トリック

下劣な生物情報学者は、適度に有能なコーダーです。そのため、一部の構成要素は自動的に検出され、禁止されています。

  • 彼は、rand()、random()、/ dev / urandomまたは/ dev / random(または同等の言語)からの読み取りなど、システム乱数ジェネレーターへの呼び出しを自動的に検出します。
  • また、余分な変数、カウンター、またはループに気付くでしょう。

得点

エンコーダーとデコーダーは個別にスコアリングされます。

それぞれが、ランダムに生成された100個の入力ファイルのセットに対して3回実行され、各ファイルのサイズは300万単位のオーダーです。

エンコーダテストケースのデータは、およそ次のように作成されます。

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

エンコーダー

  • 実際の長さで予想される最小長から欠落している各バイトは、最大-1000までの-1ポイントを獲得します。(予想される最小の長さはceil(count(ATGC) / 3)です。)

デコーダー

  • 実際の長さで予想される最大長を超える各バイトは、最大-1000までの-1ポイントを獲得します。(予想される最大長はsize(input) * 4 + 1です。)

両方

  • 発生する可能性のある各種類のエラーは、100ポイントを獲得します。それぞれ合計600ポイント、合計1200ポイント。
  • エンコーダーがそれ自体の平均よりも30%以上またはそれ以下のエラーを生成する各テストケースは、-5ポイント減点されます。
  • エンコーダーがそれ自体の平均よりも15%未満または少ないエラーを生成する各テストケースには、5ポイントが与えられます。
  • 3つの実行すべてが同一の出力を生成する各テストケースには、-10ポイントのペナルティが科せられます。

厳しい要件

次の場合、エントリは失格となります。

  • 1つのトリプレットより長い有効な入力の場合、1つのエラーも生成できません。
  • そのパフォーマンスは、テストガントレットを約1時間以内に完了することができないほどです。
  • 平均すると、1万単位ごとに複数のエラーが発生します。
  • 平均すると、100万個ごとに1つ未満のエラーが生成されます。

インターフェース

参加者は、標準入力で入力を受け入れ、標準出力に出力する必要があります。

エントリが2つの機能を持つ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は、提出物が相互作用する課題のためのものです。また、「人手不足」のコンポーネントを客観的に実施することは困難または不可能になると思います。
マーティンエンダー14年

2
下手な部分を判断するのは難しいという@ m.buettnerのコメントに同意します。一方で、これがチャレンジの唯一の興味深い部分だと感じています。エラーの生成と発生率が仕様の範囲内であり、したがって最大のポイントを持っていることを保証できます。または、仕様から何かを見逃していますか?さらに、追加の種類のエラーが受け入れられた場合、上記のリストに追加されます。そして、すべての答えがそれに採点されます。人々が働き始めたり、解決策を提出した後、あなたは挑戦を変えようとしているように聞こえますが、それは良い考えではありません。
ハワード14年

@ハワード:注目。ルールは特定の利き手基準で更新されます。そして、突然変異の側面は。エラーが削除されます。
ウィリハムトットランド14年

1
私は答えを与えようとします..しかし、2つの文「変換ごとに小さなエラー率が発生するはずです。1万から100万単位あたり1エラーのオーダーで処理されます。」「次の場合、エントリは失格になります。平均で1万ユニットごとに複数のエラーが発生する」互換性がありません。「各変換で小さなエラー率が発生するはずです。1万から100万単位が処理されるごとに1エラー程度です。」「次の場合、エントリは失格になります。平均して、100万ユニットごとに1つ未満のエラーが生成されます。」
マットスティール

1
このサイトでは、手に負えない課題がトピックではなくなったため、この質問をトピック外として終了することに投票しています。meta.codegolf.stackexchange.com/a/8326/20469
cat

回答:


3

Perl 5.10

私のソリューションをPerlで紹介できてうれしいです。

チャレンジを始めたとき、Perlが1時間の制限を十分に下回っていると確信していました。

テストのために、単純なサンプルジェネレーターとコード化されたサンプルジェネレーターを開発しました。

それから私は、より大きな労力を費やし、より長いコードを生成するエンコーダーを開発しました。エンコーダは次のように機能します。

  1. 最初のループはファイル全体を読み取り、データを分割してすべてのトリプレットの配列を取得します
  2. 2番目のループは配列を走査し、各要素の長さを先頭に追加します
  3. 3番目のループは再度トラバースし、各文字をマッピングして出力を提供します。

コード化されたバイナリ出力は、20オクテットの改行で終わる「行」としてフォーマットされ、各オクテットは2文字のプレフィックス(循環行番号など)で1つのトリプレットをコード化します。

たとえば、最短 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ÑéÍÊÓïææùîâÔôáæÔäûñù

万一小さいため、エラーレートのは:最小の入力の場合、スクリプトは1つのエラーを紹介します。

300万のトリプレットファイルを実行すると、エンコーダーで11のエラーが発生します。

スクリプトがdnacodec3.plである場合、通常どおりコマンドプロンプトで実行が呼び出されます。

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

デコーダーは次のように機能します。

  1. 最初のループはファイル全体を読み取り、データを分割してすべてのオクテットの配列にします。すべての改行を追跡します。
  2. 2番目のループは各オクテットを検査し、00で始まらないものを保持し、残りを無視します。プレーンAscii出力は、1つのスペースで区切られたトリプレットの改行で終わる行としてフォーマットされます。改行は、入力と同じ位置にあります。

300万のトリプレットサンプルテストファイル(約12Mバイト)を準備し、タイミングをテストしました。2.6 GHzでIntel Core i5 vProを搭載したラップトップを使用すると、3Mエンコーダーの実行に常に20秒もかかりません。実行中には、200〜220 MBの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' ;

エラーが挿入される場所を示すのを忘れました。2番目のループのプッシュ@bufがトリックを行います。
マットスティール

それは微妙です、私はあなたにそれをあげます。複数の競合他社が存在するまで本格的なテストを実行しませんが、これは良いことです。:)
ウィリーハムトットランド

ありがとう。私は、私は(まだ未使用)時間funcを使用して、エラー位置のランダム性を改善したいと思います...これは他の友人のための提案である知っている:奇数または偶数秒で実行開始すると、異なる出力得なければならない
Mattsteel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.