Perl, 2 · 70525 + 326508 = 467558
ทำนาย
$m=($u=1<<32)-1;open B,B;@e=unpack"C*",join"",<B>;$e=2903392593;sub u{int($_[0]+($_[1]-$_[0])*pop)}sub o{$m&(pop()<<8)+pop}sub g{($h,%m,@b,$s,$E)=@_;if($d eq$h){($l,$u)=(u($l,$u,$L),u($l,$u,$U));$u=o(256,$u-1),$l=o($l),$e=o(shift@e,$e)until($l^($u-1))>>24}$M{"@c"}{$h}++-++$C{"@c"}-pop@c for@p=($h,@c=@p);@p=@p[0..19]if@p>20;@c=@p;for(@p,$L=0){$c="@c";last if" "ne pop@c and@c<2 and$E>99;$m{$_}+=$M{$c}{$_}/$C{$c}for sort keys%{$M{$c}};$E+=$C{$c}}$s>5.393*$m{$_}or($s+=$m{$_},push@b,$_)for sort{$m{$b}<=>$m{$a}}sort keys%m;$e>=u($l,$u,$U=$L+$m{$_}/$s)?$L=$U:return$d=$_ for sort@b}
เพื่อเรียกใช้โปรแกรมนี้คุณจะต้องไฟล์นี้ที่นี่B
ซึ่งจะต้องมีชื่อ (คุณสามารถเปลี่ยนชื่อไฟล์นี้ในอินสแตนซ์ที่สองของตัวละครB
ด้านบน) ดูวิธีสร้างไฟล์นี้ที่ด้านล่าง
โปรแกรมใช้การรวมกันของรุ่นมาร์คอฟเป็นหลักเช่นเดียวกับในคำตอบนี้โดยผู้ใช้ 2699แต่มีการปรับเปลี่ยนเล็กน้อย สิ่งนี้จะสร้างการกระจายสำหรับตัวละครต่อไป เราใช้ทฤษฎีข้อมูลเพื่อตัดสินใจว่าจะยอมรับข้อผิดพลาดหรือใช้บิตของพื้นที่จัดเก็บในการB
เข้ารหัสคำแนะนำ (และถ้าเป็นเช่นนั้นอย่างไร) เราใช้การเข้ารหัสทางเลขคณิตในการจัดเก็บบิตเศษส่วนอย่างเหมาะสมจากโมเดล
โปรแกรมมีความยาว 582 ไบต์ (รวมถึงบรรทัดใหม่สุดท้ายที่ไม่จำเป็น) และไฟล์ไบนารีB
มีความยาว 69942 ไบต์ดังนั้นภายใต้กฎสำหรับการให้คะแนนหลายไฟล์เราให้คะแนนL
เป็น 582 + 69942 + 1 = 70525
โปรแกรมเกือบจะแน่นอนต้องใช้สถาปัตยกรรม 64 บิต (little-endian?) ใช้เวลาประมาณ 2.5 นาทีในการรันบนm5.large
อินสแตนซ์ของ Amazon EC2
รหัสทดสอบ
# Golfed submission
require "submission.pl";
use strict; use warnings; use autodie;
# Scoring length of multiple files adds 1 penalty
my $length = (-s "submission.pl") + (-s "B") + 1;
# Read input
open my $IN, "<", "whale2.txt";
my $input = do { local $/; <$IN> };
# Run test harness
my $errors = 0;
for my $i ( 0 .. length($input)-2 ) {
my $current = substr $input, $i, 1;
my $decoded = g( $current );
my $correct = substr $input, $i+1, 1;
my $error_here = 0 + ($correct ne $decoded);
$errors += $error_here;
}
# Output score
my $score = 2 * $length + $errors;
print <<EOF;
length $length
errors $errors
score $score
EOF
ชุดทดสอบจะถือว่าการส่งอยู่ในไฟล์submission.pl
แต่สามารถเปลี่ยนได้อย่างง่ายดายในบรรทัดที่สอง
การเปรียบเทียบข้อความ
"And did none of ye see it before?" cried Ahab, hailing the perched men all around him.\\"I saw him almost that same instant, sir, that Captain
"And wid note of te fee bt seaore cried Ahab, aasling the turshed aen inl atound him. \"' daw him wsoost thot some instant, wer, that Saptain
"And _id no_e of _e _ee _t _e_ore__ cried Ahab, _a_ling the __r_hed _en __l a_ound him._\"_ _aw him ___ost th_t s_me instant, __r, that _aptain
Ahab did, and I cried out," said Tashtego.\\"Not the same instant; not the same--no, the doubloon is mine, Fate reserved the doubloon for me. I
Ahab aid ind I woued tut, said tashtego, \"No, the same instant, tot the same -tow nhe woubloon ws mane. alte ieserved the seubloon ior te, I
Ahab _id_ _nd I ___ed _ut,_ said _ashtego__\"No_ the same instant_ _ot the same_-_o_ _he _oubloon _s m_ne_ __te _eserved the __ubloon _or _e_ I
only; none of ye could have raised the White Whale first. There she blows!--there she blows!--there she blows! There again!--there again!" he cr
gnly towe of ye sould have tersed the shite Whale aisst Ihere ihe blows! -there she blows! -there she blows! Ahere arains -mhere again! ce cr
_nly_ _o_e of ye _ould have ___sed the _hite Whale _i_st_ _here _he blows!_-there she blows!_-there she blows! _here a_ain__-_here again!_ _e cr
ตัวอย่างนี้ (เลือกในคำตอบอื่น ) เกิดขึ้นค่อนข้างช้าในข้อความดังนั้นโมเดลนี้จึงได้รับการพัฒนาโดยจุดนี้ โปรดจำไว้ว่าแบบจำลองนี้มีการเพิ่ม "คำใบ้" 70 กิโลไบต์ที่ช่วยให้เดาอักขระได้โดยตรง มันไม่ได้ขับเคลื่อนโดยตัวอย่างสั้น ๆ ของรหัสข้างต้น
สร้างคำแนะนำ
โปรแกรมต่อไปนี้ยอมรับรหัสการส่งที่ถูกต้องด้านบน (ในอินพุตมาตรฐาน) และสร้างB
ไฟล์ที่แน่นอนด้านบน (บนเอาต์พุตมาตรฐาน):
@S=split"",join"",<>;eval join"",@S[0..15,64..122],'open W,"whale2.txt";($n,@W)=split"",join"",<W>;for$X(0..@W){($h,$n,%m,@b,$s,$E)=($n,$W[$X]);',@S[256..338],'U=0)',@S[343..522],'for(sort@b){$U=($L=$U)+$m{$_}/$s;if($_ eq$n)',@S[160..195],'X<128||print(pack C,$l>>24),',@S[195..217,235..255],'}}'
ใช้เวลาในการประมวลผลเท่ากันโดยประมาณ
คำอธิบาย
ในส่วนนี้เราจะพยายามอธิบายสิ่งที่วิธีการแก้ปัญหานี้ทำในรายละเอียดเพียงพอที่คุณสามารถ "ลองที่บ้าน" ด้วยตัวเอง เทคนิคหลักที่ทำให้คำตอบนี้แตกต่างจากคำอื่น ๆ นั้นเป็นเพียงส่วนน้อยลงในฐานะกลไก "ย้อนกลับ" แต่ก่อนที่เราจะไปถึงที่นั่นเราจำเป็นต้องตั้งค่าพื้นฐาน
แบบ
ส่วนประกอบพื้นฐานของการแก้ปัญหาคือรูปแบบภาษา สำหรับวัตถุประสงค์ของเราแบบจำลองเป็นสิ่งที่ใช้ข้อความภาษาอังกฤษจำนวนหนึ่งและส่งกลับค่าการแจกแจงความน่าจะเป็นในตัวละครถัดไป เมื่อเราใช้โมเดลข้อความภาษาอังกฤษจะเป็นส่วนนำหน้า (ที่ถูกต้อง) ของ Moby Dick โปรดทราบว่าผลลัพธ์ที่ต้องการเป็นการกระจายและไม่ใช่เพียงการเดาเพียงครั้งเดียวสำหรับตัวละครที่เป็นไปได้มากที่สุด
ในกรณีที่เราเป็นหลักใช้รูปแบบในคำตอบนี้โดย user2699 เราไม่ได้ใช้แบบจำลองจากคำตอบที่ให้คะแนนสูงสุด (นอกเหนือจากของเราเอง) โดย Anders Kaseorgอย่างแม่นยำเพราะเราไม่สามารถแยกการกระจายได้มากกว่าการเดาที่ดีที่สุดเพียงครั้งเดียว ในทางทฤษฎีคำตอบนั้นคำนวณค่าเฉลี่ยถ่วงน้ำหนักทางเรขาคณิต แต่เราได้ผลลัพธ์ที่ไม่ดีพอเมื่อเราตีความเช่นนั้นอย่างแท้จริง เรา "ขโมย" แบบจำลองจากคำตอบอื่นเพราะ "ซีเคร็ทซอส" ของเราไม่ใช่แบบจำลอง แต่เป็นแนวทางโดยรวม หากใครบางคนมีรูปแบบ "ดีกว่า" พวกเขาควรจะได้รับผลลัพธ์ที่ดีขึ้นโดยใช้เทคนิคที่เหลือของเรา
เป็นข้อสังเกตวิธีการบีบอัดส่วนใหญ่เช่น Lempel-Ziv นั้นถูกมองว่าเป็น "แบบจำลองภาษา" ด้วยวิธีนี้ถึงแม้ว่าวิธีการหนึ่งอาจต้องเหลื่อมกันเล็กน้อย (โดยเฉพาะอย่างยิ่งเป็นเรื่องยากสำหรับบางสิ่งที่ทำ Burrows-Wheeler transform!) นอกจากนี้โปรดทราบว่าโมเดลโดยผู้ใช้ 2699 เป็นการดัดแปลงโมเดลของมาร์คอฟ เป็นหลักไม่มีอะไรอื่นที่สามารถแข่งขันกับความท้าทายนี้หรือแม้กระทั่งการสร้างแบบจำลองข้อความทั่วไป
สถาปัตยกรรมโดยรวม
เพื่อวัตถุประสงค์ในการทำความเข้าใจมันเป็นเรื่องดีที่จะแยกสถาปัตยกรรมโดยรวมออกเป็นหลาย ๆ ส่วน จากมุมมองระดับสูงสุดจำเป็นต้องมีรหัสการจัดการสถานะเล็กน้อย สิ่งนี้ไม่น่าสนใจเป็นพิเศษ แต่เพื่อความสมบูรณ์เราต้องการเน้นว่าในทุก ๆ จุดโปรแกรมถูกถามถึงการคาดเดาครั้งต่อไปมันมีคำนำหน้าที่ถูกต้องของ Moby Dick เราไม่ใช้การคาดเดาที่ผิดพลาดในอดีต แต่อย่างใด เพื่อประสิทธิภาพของมันรูปแบบภาษาอาจจะสามารถนำสถานะของมันกลับมาใช้ใหม่จากตัวอักษร N ตัวแรกเพื่อคำนวณสถานะของตัวละครตัวแรก (N + 1) แต่โดยหลักการแล้วมันสามารถคำนวณสิ่งต่าง ๆ ได้ตั้งแต่เริ่มต้นทุกครั้ง
ลองตั้ง "ไดรเวอร์" พื้นฐานของโปรแกรมไว้ข้างล่างแล้วมองเข้าไปในส่วนที่คาดเดาอักขระต่อไป มันช่วยให้แนวคิดในการแยกสามส่วน: โมเดลภาษา (ที่กล่าวถึงข้างต้น), ไฟล์ "คำแนะนำ" และ "ล่าม" ในแต่ละขั้นตอนล่ามจะถามแบบจำลองภาษาสำหรับการกระจายสำหรับอักขระถัดไปและอาจอ่านข้อมูลบางส่วนจากไฟล์คำแนะนำ จากนั้นมันจะรวมส่วนต่าง ๆ เหล่านี้เข้าด้วยกัน ข้อมูลใดที่อยู่ในไฟล์คำแนะนำรวมถึงวิธีการใช้อย่างแม่นยำจะถูกอธิบายในภายหลัง แต่สำหรับตอนนี้มันช่วยแยกชิ้นส่วนเหล่านี้ทางจิตใจ โปรดทราบว่าการใช้งานอย่างชาญฉลาดไฟล์คำใบ้นั้นเป็นไฟล์ (ไบนารี) ที่แยกจากกันอย่างแท้จริง แต่อาจเป็นสตริงหรือบางสิ่งที่เก็บไว้ในโปรแกรม เป็นการประมาณ
หากใครใช้วิธีการบีบอัดมาตรฐานเช่นbzip2 เช่นเดียวกับในคำตอบนี้ไฟล์ "คำแนะนำ" จะสอดคล้องกับไฟล์บีบอัด "ล่าม" สอดคล้องกับตัวขยายการบีบอัดในขณะที่ "รูปแบบภาษา" เป็นบิตโดยนัย (ดังกล่าวข้างต้น)
เหตุใดจึงต้องใช้ไฟล์คำใบ้
ลองเลือกตัวอย่างง่าย ๆ เพื่อวิเคราะห์เพิ่มเติม สมมติว่าข้อความเป็นN
ตัวอักษรที่มีความยาวและประมาณตัวอักษรได้ดีโดยที่ตัวละครทุกตัว (เป็นอิสระ) ตัวอักษรที่E
มีความน่าจะเป็นน้อยกว่าครึ่งT
เล็กน้อยคล้ายกับความน่าจะเป็นที่น้อยกว่าครึ่งหนึ่งและA
มีความน่าจะเป็น 1/1000 = 0.1% สมมติว่าไม่มีตัวละครอื่น ๆ ที่เป็นไปได้ ไม่ว่าในกรณีใดA
ลักษณะคล้ายกับกรณีของอักขระที่มองไม่เห็นก่อนหน้านี้จากสีน้ำเงิน
หากเราดำเนินการในระบอบการปกครอง L 0 (ส่วนใหญ่ แต่ไม่ใช่ทั้งหมดของคำตอบอื่น ๆ สำหรับคำถามนี้) ไม่มีวิธีใดที่ดีไปกว่าล่ามE
และT
เลือก โดยเฉลี่ยแล้วจะมีตัวละครประมาณครึ่งตัวที่ถูกต้อง ดังนั้น E ≈ N / 2 และคะแนน≈ N / 2 ด้วย อย่างไรก็ตามถ้าเราใช้กลยุทธ์การบีบอัดเราสามารถบีบอัดได้มากกว่าหนึ่งบิตต่อตัวอักษร เนื่องจาก L นับเป็นไบต์เราจะได้รับ L ≈ N / 8 ดังนั้นจึงให้คะแนน≈ N / 4 สองครั้งดีเท่ากับกลยุทธ์ก่อนหน้านี้
การได้รับอัตรานี้มากกว่าหนึ่งบิตต่อตัวละครสำหรับรุ่นนี้เล็กน้อยนั้นไม่ใช่เรื่องเล็กน้อย แต่วิธีการหนึ่งคือการเข้ารหัสทางคณิตศาสตร์
การเข้ารหัสทางเลขคณิต
การเข้ารหัสเป็นวิธีการแทนข้อมูลบางอย่างโดยใช้บิต / ไบต์ ตัวอย่างเช่น ASCII เป็นการเข้ารหัส 7 บิต / ตัวอักษรของข้อความภาษาอังกฤษและตัวอักษรที่เกี่ยวข้องและเป็นการเข้ารหัสของไฟล์ Moby Dick ดั้งเดิมภายใต้การพิจารณา หากตัวอักษรบางตัวพบได้บ่อยกว่าตัวอักษรอื่นการเข้ารหัสแบบความกว้างคงที่เช่น ASCII จะไม่เหมาะสม ในสถานการณ์ดังกล่าวหลายคนเข้าถึงสำหรับHuffman การเข้ารหัส สิ่งนี้จะเหมาะสมที่สุดหากคุณต้องการรหัสคงที่ (ไม่มีคำนำหน้า) ที่มีจำนวนบิตเป็นบิตต่ออักขระ
อย่างไรก็ตามการเข้ารหัสทางคณิตศาสตร์ดียิ่งขึ้น การพูดโดยประมาณสามารถใช้บิต "เศษส่วน" เพื่อเข้ารหัสข้อมูลได้ มีคำแนะนำมากมายเกี่ยวกับการเข้ารหัสทางคณิตศาสตร์ที่พร้อมใช้งานออนไลน์ เราจะข้ามรายละเอียดที่นี่ (โดยเฉพาะอย่างยิ่งการใช้งานจริงซึ่งอาจเป็นเรื่องยุ่งยากเล็กน้อยจากมุมมองการเขียนโปรแกรม) เนื่องจากแหล่งข้อมูลอื่น ๆ ที่พร้อมใช้งานออนไลน์ แต่ถ้ามีคนบ่น
หากมีข้อความที่สร้างขึ้นจริงโดยรูปแบบภาษาที่รู้จักกันแล้วการเข้ารหัสทางคณิตศาสตร์จะให้การเข้ารหัสข้อความที่ดีที่สุดจากแบบจำลองนั้น ในบางแง่นี้ "แก้ปัญหา" การบีบอัดสำหรับรุ่นนั้น (ดังนั้นในทางปฏิบัติประเด็นหลักคือโมเดลไม่เป็นที่รู้จักและบางรุ่นดีกว่ารุ่นอื่น ๆ ในการสร้างโมเดลข้อความของมนุษย์) หากไม่ได้รับอนุญาตให้สร้างข้อผิดพลาดในการประกวดครั้งนี้ให้ใช้ภาษาของส่วนก่อนหน้า วิธีหนึ่งในการสร้างทางออกสำหรับความท้าทายนี้คือการใช้ตัวเข้ารหัสเลขคณิตเพื่อสร้างไฟล์ "คำแนะนำ" จากแบบจำลองภาษาจากนั้นใช้ตัวถอดรหัสเลขคณิตเป็น "ล่าม"
ในการเข้ารหัสเป็นหลักที่ดีที่สุดนี้เราสิ้นสุดการใช้จ่าย -log_2 (P) บิตสำหรับตัวอักษรที่มีความน่าจะเป็นพีและอัตราบิตโดยรวมของการเข้ารหัสเป็นเอนโทรปีนอนส์ ซึ่งหมายความว่าอักขระที่มีความน่าจะเป็นใกล้ 1/2 ใช้เวลาประมาณหนึ่งบิตในการเข้ารหัสในขณะที่อักขระที่มีความน่าจะเป็น 1/1000 นั้นใช้เวลาประมาณ 10 บิต (เนื่องจาก 2 ^ 10 มีค่าประมาณ 1,000)
แต่ตัวชี้วัดการให้คะแนนสำหรับความท้าทายนี้ได้รับเลือกอย่างดีเพื่อหลีกเลี่ยงการบีบอัดเป็นกลยุทธ์ที่ดีที่สุด เราจะต้องหาวิธีที่จะทำให้เกิดข้อผิดพลาดในการแลกเปลี่ยนไฟล์เพื่อรับไฟล์คำใบ้ที่สั้นกว่า ตัวอย่างเช่นกลยุทธ์หนึ่งที่อาจลองใช้เป็นกลยุทธ์การแยกสาขาอย่างง่าย: โดยทั่วไปเราพยายามใช้การเข้ารหัสทางคณิตศาสตร์เมื่อเราทำได้ แต่ถ้าการแจกแจงความน่าจะเป็นจากแบบจำลองนั้น "ไม่ดี" ในบางวิธีเราแค่คาดเดาตัวละครที่มีแนวโน้มมากที่สุด ลองเข้ารหัสมัน
ทำผิดพลาดทำไม
มาวิเคราะห์ตัวอย่างก่อนหน้านี้เพื่อกระตุ้นสาเหตุที่เราอาจต้องการทำข้อผิดพลาด "จงใจ" ถ้าเราใช้คณิตศาสตร์การเข้ารหัสการเข้ารหัสตัวอักษรที่ถูกต้องเราจะใช้เวลาประมาณหนึ่งบิตในกรณีของนั้นE
หรือแต่ประมาณสิบบิตในกรณีนั้นT
A
โดยรวมแล้วนี่เป็นการเข้ารหัสที่ดีทีเดียวใช้เวลามากกว่าตัวละครเล็กน้อยต่อตัวแม้ว่าจะมีความเป็นไปได้สามอย่างก็ตาม โดยพื้นฐานแล้วA
มันไม่น่าเป็นไปได้และเราไม่ได้ใช้จ่ายสิบบิตที่สอดคล้องกันบ่อยเกินไป อย่างไรก็ตามมันจะไม่ดีถ้าเราสามารถทำผิดพลาดแทนในกรณีของA
? ท้ายที่สุดตัวชี้วัดของปัญหาจะพิจารณาความยาว 1 ไบต์ = 8 บิตซึ่งเท่ากับ 2 ข้อผิดพลาด ดังนั้นดูเหมือนว่าเราควรชอบข้อผิดพลาดแทนที่จะใช้มากกว่า 8/2 = 4 บิตกับตัวละคร การใช้จ่ายมากกว่าไบต์เพื่อบันทึกข้อผิดพลาดหนึ่งข้อจะส่งผลให้ไม่ได้ผลแน่นอน!
กลไก "กรอกลับ"
ส่วนนี้อธิบายถึงมุมมองที่ฉลาดหลักของโซลูชันนี้ซึ่งเป็นวิธีจัดการกับการเดาที่ไม่ถูกต้องโดยไม่มีค่าใช้จ่าย
สำหรับตัวอย่างง่ายๆที่เราวิเคราะห์อยู่นั้นกลไกการกรอกลับนั้นเรียบง่ายมาก ล่ามจะอ่านหนึ่งบิตจากไฟล์คำแนะนำ ถ้าเป็น 0 E
มันคาดเดา ถ้าเป็น 1 T
ก็คาดเดา ครั้งต่อไปที่มันถูกเรียกมันจะเห็นตัวละครที่ถูกต้อง หากไฟล์คำใบ้ตั้งค่าได้ดีเราสามารถมั่นใจได้ว่าในกรณีของE
หรือT
ล่ามคาดเดาได้อย่างถูกต้อง แต่เกี่ยวกับA
อะไร ความคิดของกลไกการย้อนกลับไปก็คือการไม่ได้รหัสA
ที่ทั้งหมด หากล่ามรู้ในภายหลังว่าตัวอักษรที่ถูกต้องเป็นตัวอักษรนั้นA
มันจะเปรียบเทียบ " ย้อนกลับเทป": มันส่งคืนบิตที่อ่านก่อนหน้านี้ บิตที่อ่านนั้นตั้งใจจะให้รหัสE
หรือT
, แต่ไม่ใช่ตอนนี้; มันจะถูกใช้ในภายหลัง ในตัวอย่างง่ายๆนี้โดยทั่วไปหมายความว่ามันยังคงคาดเดาอักขระเดิม ( E
หรือT
) จนกว่าจะทำให้ถูกต้อง จากนั้นมันจะอ่านอีกบิตและดำเนินต่อไป
การเข้ารหัสสำหรับไฟล์คำแนะนำนี้ง่ายมาก: เปลี่ยนE
s ทั้งหมดเป็น 0 บิตและT
s เป็น 1 บิตทั้งหมดโดยไม่สนใจA
s ทั้งหมด โดยการวิเคราะห์ในตอนท้ายของส่วนก่อนหน้านี้ที่โครงการนี้จะทำให้ข้อผิดพลาดบางอย่าง แต่ลดคะแนนโดยรวมไม่ได้เข้ารหัสใด ๆ ของA
s ในฐานะที่เป็นเอฟเฟกต์ขนาดเล็กจริง ๆ แล้วมันจะบันทึกตามความยาวของไฟล์คำแนะนำเช่นกันเพราะเราจะใช้หนึ่งบิตสำหรับแต่ละบิตE
และT
แทนที่จะเป็นบิตมากกว่าเล็กน้อย
ทฤษฎีบทเล็กน้อย
เราจะตัดสินใจได้อย่างไรเมื่อมีข้อผิดพลาด? สมมติว่าโมเดลของเราให้การแจกแจงความน่าจะเป็นแบบ P สำหรับตัวละครตัวต่อไป เราจะแยกตัวละครที่เป็นไปได้เป็นสองชั้น: รหัสและไม่ได้เข้ารหัส หากตัวละครที่ถูกต้องไม่ได้รับการเข้ารหัสเราจะใช้กลไก "กรอกลับ" เพื่อยอมรับข้อผิดพลาดโดยไม่เสียค่าใช้จ่าย หากตัวอักษรที่ถูกต้องถูกเข้ารหัสแล้วเราจะใช้การกระจาย Q อื่น ๆ ในการเข้ารหัสโดยใช้การเข้ารหัสทางคณิตศาสตร์
แต่เราควรเลือกการกระจายแบบไหน ไม่ยากเกินไปที่จะเห็นว่าอักขระที่มีรหัสควรมีความน่าจะเป็นสูงกว่า (ใน P) มากกว่าอักขระที่ไม่ได้เข้ารหัส นอกจากนี้การกระจาย Q ควรมีเฉพาะอักขระที่มีรหัสเท่านั้น ท้ายที่สุดเราไม่ได้เข้ารหัสรหัสอื่นดังนั้นเราไม่ควร "ใช้" เอนโทรปีของพวกเขา มันค่อนข้างยากที่จะเห็นว่าการแจกแจงความน่าจะเป็น Q ควรเป็นสัดส่วนกับ P ในตัวอักษรที่เขียนโค้ด การรวมการสังเกตเหล่านี้เข้าด้วยกันหมายความว่าเราควรเขียนรหัสตัวละครที่มีโอกาสมากที่สุด แต่อาจไม่ใช่ตัวละครที่มีโอกาสน้อยกว่าและ Q นั้นได้รับการปรับ P บนตัวละครที่เขียนโค้ด
มันกลับกลายเป็นว่ามีทฤษฎีบทเจ๋ง ๆ เกี่ยวกับสิ่งที่ "cutoff" ควรเลือกสำหรับตัวอักษรการเข้ารหัส: คุณควรเขียนรหัสตัวอักษรตราบเท่าที่มันมีอย่างน้อย 1 / 5.393 ที่น่าจะเป็นไปได้ สิ่งนี้ "อธิบาย" ลักษณะที่ปรากฏของค่าคงที่แบบสุ่มที่ดูเหมือนจะ5.393
ใกล้เคียงกับจุดสิ้นสุดของโปรแกรมด้านบน จำนวน 1 / 5.393 ≈ 0.18542 เป็นวิธีการแก้สมการ-p เข้าสู่ระบบ (16) p - บันทึก + p (1 + P) เข้าสู่ระบบ (1 + P) = 0
อาจเป็นความคิดที่สมเหตุสมผลที่จะเขียนโพรซีเดอร์นี้เป็นโค้ด ตัวอย่างนี้อยู่ใน C ++:
// Assume the model is computed elsewhere.
unordered_map<char, double> model;
// Transform p to q
unordered_map<char, double> code;
priority_queue<pair<double,char>> pq;
for( char c : CHARS )
pq.push( make_pair(model[c], c) );
double s = 0, p;
while( 1 ) {
char c = pq.top().second;
pq.pop();
p = model[c];
if( s > 5.393*p )
break;
code[c] = p;
s += p;
}
for( auto& kv : code ) {
char c = kv.first;
code[c] /= s;
}
วางมันทั้งหมดเข้าด้วยกัน
ส่วนก่อนหน้านี้น่าเสียดายที่เป็นเทคนิคเล็กน้อย แต่ถ้าเราเอาชิ้นส่วนอื่น ๆ ทั้งหมดเข้าด้วยกันโครงสร้างจะเป็นดังนี้ เมื่อใดก็ตามที่โปรแกรมถูกขอให้คาดเดาตัวละครถัดไปหลังจากตัวละครที่ถูกต้องได้รับ:
- เพิ่มอักขระที่ถูกต้องให้กับส่วนนำหน้าที่ถูกต้องของ Moby Dick
- อัปเดตข้อความ (Markov) รุ่น
- ซอสลับ : ถ้าเดาก่อนหน้านี้ไม่ถูกต้องย้อนกลับสถานะของการถอดรหัสคณิตศาสตร์ให้กับรัฐก่อนที่จะคาดเดาก่อนหน้านี้!
- ขอให้โมเดลของมาร์คอฟทำนายการกระจายตัวของความน่าจะเป็น P สำหรับตัวละครต่อไป
- แปลง P เป็น Q โดยใช้รูทีนย่อยจากส่วนก่อนหน้า
- ขอให้ตัวถอดรหัสเลขคณิตถอดรหัสตัวอักษรจากส่วนที่เหลือของไฟล์คำใบ้ตามการแจกแจง Q
- เดาตัวละครที่เกิด
การเข้ารหัสไฟล์คำใบ้ทำงานในทำนองเดียวกัน ในกรณีนั้นโปรแกรมรู้ว่าตัวอักษรต่อไปที่ถูกต้องคืออะไร ถ้ามันเป็นตัวละครที่ควรจะถูกเข้ารหัสแน่นอนว่าอย่างหนึ่งควรใช้ตัวเข้ารหัสทางคณิตศาสตร์กับมัน แต่ถ้ามันเป็นตัวละครที่ไม่ได้เข้ารหัสมันก็แค่ไม่อัพเดทสถานะของตัวเข้ารหัสทางคณิตศาสตร์
หากคุณเข้าใจภูมิหลังทางทฤษฎีข้อมูลเช่นการแจกแจงความน่าจะเป็น, เอนโทรปี, การบีบอัดและการเข้ารหัสทางคณิตศาสตร์ แต่พยายามและล้มเหลวที่จะเข้าใจโพสต์นี้ (ยกเว้นว่าทำไมทฤษฎีบทเป็นจริง) ให้เรารู้ ขอบคุณที่อ่าน!