मेटा रेडिएशन हार्डनर


19

पृष्ठभूमि

इस साइट पर, हमारे पास कभी-कभी प्रश्न हैं जो "विकिरण कठोर" होने के कार्यक्रमों की आवश्यकता होती है; इसका मतलब यह है कि कार्यक्रम को एक या एक से अधिक बाइट्स को हटाने में सक्षम होना है, चाहे जो भी बाइट्स हटाए जाएं।

जैसा कि उन कार्यों के लिए आम है जो अक्सर प्रोग्रामिंग चुनौतियों में सेट हो जाते हैं, ऐसी चुनौतियों के लिए विशेष रूप से अच्छी भाषा बनाना चाहते हैं। यह देखते हुए कि इसे बनाने का प्राकृतिक तरीका कुछ मेटाडेटा जोड़ना है जो भ्रष्टाचार को दूर करना संभव बनाता है, यह वास्तव में एक ऐसी भाषा नहीं है जिसे डिजाइनिंग की आवश्यकता है, लेकिन एक एन्कोडिंग; विचार प्रत्येक इनपुट को बाइट्स के अनुक्रम में बदलने के लिए है, इस तरह से कि यदि अनुक्रम थोड़ा विकिरणित है, तो भी मूल इनपुट को निकालना संभव है।

काम

दो कार्यक्रम या कार्य लिखें, E (एक एनकोडर) और D (एक डिकोडर), जैसे कि:

  • ई दो तर्क लेता है, ऑक्टेट्स का एक अनुक्रम (जिसे हम इस विनिर्देश में " इनपुट " कहेंगे ) और एक नॉनगेटिव पूर्णांक " विकिरण ", और ऑक्टेट " एन्कोडिंग " के एक अनुक्रम को आउटपुट करता है ;
  • डी एक तर्क लेता है, ऑक्टेट्स का एक क्रम (" एन्कंड "), और ऑक्टेट्स के एक अनुक्रम को " पुनर्निर्माण " करता है;
  • यदि आप E और D दोनों को चलाते हैं ( Encdng के साथ , D को इनपुट, एन्कोडिंग से विकिरण तत्वों से अधिक नहीं हटाकर चुना जाता है (जरूरी नहीं कि आकस्मिक रूप से ), तो पुनर्निर्माण इनपुट के बराबर होगा , जो वर्ण एन्कोडिंग बनाने के लिए हटाए गए थे ।

स्पष्टीकरण

  • आप कार्यों सबमिट करते हैं, तो आप उन्हें कॉल करने के लिए की जरूरत नहीं है Eऔर D; आप जो भी नाम चुन सकते हैं, वह आपकी भाषा के लिए सबसे उपयुक्त है।
  • एक "ऑक्टेट" मूल रूप से 0 से 255 समावेशी का पूर्णांक है, जिसे आप पूर्णांक, एक चरित्र या अपनी भाषा के लिए उपयुक्त के रूप में सांकेतिक शब्दों में बदलना कर सकते हैं।
  • ई और डी पूरी तरह से नियतात्मक होना चाहिए (यानी उन्हें समान इनपुट देने से हमेशा वही आउटपुट मिलेगा, जहां "इनपुट" को ई के लिए इनपुट और विकिरण के रूप में परिभाषित किया गया है , या डी के लिए एनकॉर्डिंग )। विशेष रूप से, ई एक साइड चैनल के माध्यम से डी को जानकारी संवाद नहीं कर सकता है।
  • अनुक्रम के एक तत्व को हटाकर विलोपन किया जाता है; एक संपादक में seuqence खोलने के बारे में सोचें, कर्सर को एक मनमाना बिंदु पर रखें, और बैकस्पेस दबाएं। यदि कोई तत्व कई बार दिखाई देता है, तो यह संभव है कि तत्व की केवल एक प्रति हटा दी जाएगी (यानी उसी ऑक्टेट के अन्य उदाहरण प्रभावित नहीं होंगे)।
  • हालाँकि स्कोर की गणना काफी कम इनपुट के आधार पर की जाती है , लेकिन आपके प्रोग्राम को किसी भी इनपुट और विकिरण के लिए सिद्धांत रूप में काम करना चाहिए । विशेष रूप से, यह काम नहीं करना चाहिए जो इनपुट में ऑक्टेट दिखाई देते हैं । (क्षमा करें, वे लोग जो अनपेक्षित वर्णों का उपयोग करने की क्षमता चाहते हैं, जिन्हें वे जानते हैं कि वे इनपुट में दिखाई नहीं देंगे, लेकिन मुझे यह सुनिश्चित करने की आवश्यकता है कि इनपुट असंगत है, ताकि चुनौती संपीड़न के बजाय विकिरण सख्त के बारे में हो।)
  • आप या तो एक फ़ाइल जमा कर सकते हैं जो दो कार्यों को परिभाषित करती है; दो फाइलें जो प्रत्येक एक फ़ंक्शन को परिभाषित करती हैं या जो दोनों पूर्ण कार्यक्रम हैं; या तीन फाइलें, जिनमें से दो क्रमशः डी और ई को लागू करती हैं (या तो पूर्ण कार्यक्रमों के माध्यम से या एक फ़ंक्शन को परिभाषित करने के माध्यम से), और तीसरी जो एक हेडर फ़ाइल या लाइब्रेरी है जो डी और ई दोनों के लिए आम है। भले ही आप किस रूप में उपयोग करते हैं। , आपकी प्रोग्रामिंग भाषा कार्यान्वयन को आगे के तर्कों के बिना दोनों कार्यक्रमों को समझने में सक्षम होना चाहिए (जैसे कि आपको हमारे मानक नियमों के अनुसार, अपने कार्यान्वयन को असामान्य तरीके से लागू करने के लिए एक बाइट जुर्माना देना होगा)।

विजय की स्थिति

प्रत्येक लंबाई और विकिरण के लिए , f ( लंबाई , विकिरण ) एन्कोडिंग s की कुल लंबाई हो जो लंबाई लंबाई और दिए गए विकिरण के साथ सभी इनपुट के अनुरूप हो । (अर्थात, एफ ( लंबाई , विकिरण ) = योग इनपुट की लंबाई लंबाई (ई ( इनपुट , विकिरण )) है।) फिर जी ( लंबाई , विकिरण ) को बराबर एफ ( लंबाई ) देंविकिरण ) length 256 लंबाई । दूसरे शब्दों में, जी एन्कोडेड आउटपुट की औसत लंबाई है, इनपुट की एक लंबी लंबाई और एक दिए गए विकिरण सख्त आवश्यकता के लिए। (सिद्धांत रूप में आप इसे क्रूर बल द्वारा गणना कर सकते हैं, लेकिन यह संभवतः आपके स्कोर को इस तरह से काम करने के लिए लंबे समय तक ले जाएगा। मुझे उम्मीद है कि अधिकांश प्रस्तुतियाँ एक गणितीय तर्क बनाने में सक्षम होंगी कि उनका स्कोर क्या है। यदि आप ' यकीन नहीं है, एक अनुमानित स्कोर पोस्ट करें और आप या कोई और इसे और अधिक गहराई में गणना कर सकता है यदि कोई अन्य प्रविष्टि समान स्कोर पोस्ट करता है।)

आपका स्कोर 0 से 9 की रेंज में सभी विकिरण के लिए जी ( लंबाई , विकिरण ) के योग के बराबर है , और 0 से 99 की रेंज में सभी लंबाई समावेशी है, प्लस (ज्यादातर हार्डकोडिंग से बचने के लिए, या प्रतियोगिता को जारी रखने के लिए अगर किसी ने गणितीय रूप से सही एन्कोडिंग का पता लगाया है, यह अन्यथा एक न्यूनतम कारक होने की संभावना है) चुनौती को प्रस्तुत करने में बाइट्स की कुल संख्या (साथ ही असामान्य दुभाषिया झंडे या विशिष्ट फ़ाइलनाम की आवश्यकता जैसी चीजों के लिए मानक दंड)। विजेता सबसे कम स्कोर वाली प्रविष्टि है (सबमिट करने के लिए पहली प्रविष्टि से जुड़ा हुआ)।


क्या विकोडक विकिरण पैरामीटर को भी जान सकता है?
orlp

(या लंबाई , लेकिन मेरा मानना ​​है कि या तो आपको सबसे ज्यादा योजनाओं के लिए दूसरे को देना चाहिए)
orlp

1
@orlp: नहीं, इसमें केवल स्ट्रिंग है। एक में विकिरण सख्त समस्या, विकोडक (यानी भाषा) विकिरण नियमों का उपयोग किया तो अपने विकोडक उन्हें या तो पता नहीं है पता नहीं है; इसके इनपुट से उन्हें कटौती करनी होगी।

इस कंप्यूटरफाइल वीडियो के आधार पर, मैं एक ऐसी भाषा बनाऊंगा जिसमें 3-बाइट ट्रिपल में कोडल्स हों: यदि वे सभी मेल नहीं खाते हैं, तो कुछ गलत हो गया है और हमारे पास यह जानने के लिए पर्याप्त जानकारी है कि सही मूल्य क्या है। शायद कम बिट्स के साथ ऐसा करने का एक तरीका है, लेकिन मेरे पास इस समय काम करने का मस्तिष्क नहीं है।
ड्रेको १।

आप शीर्ष लेख और कार्यक्रमों को कैसे संयोजित करते हैं?
कैलक्यूलेटरफैनलाइन

जवाबों:


8

सीजाम, स्कोर ≤ 286,516 + 54 + 36 = 286,606

एनकोडर

{_{1\+_:e>)_0a+@@b0\{{)_256b_,\e`,-}g}*256b+\)e*}{*}?}

इसे ऑनलाइन आज़माएं!

डिकोडर

{_{e`1f=(\256b{256b_,\e`,=},,\b1>}&}

इसे ऑनलाइन आज़माएं!

ये दोनों एक सूची पूर्णांक लेते हैं। TIO लिंक में सुविधा के लिए / से स्ट्रिंग्स में रूपांतरण शामिल है। ध्यान दें कि ये लंबे तार के लिए अविश्वसनीय रूप से अक्षम हैं। यदि आप कुछ और चरित्रों को आजमाना चाहते हैं, तो मैं छोटे चरित्र कोड वाले पात्रों का उपयोग करने की सलाह देता हूं।

विकिरण-कठोर एन्कोडिंग बनाने के लिए मूल विचार में दो चरण शामिल हैं:

  1. एक एन्कोडिंग का पता लगाएं, जिसमें दो लगातार समरूप ऑक्टेट नहीं होते हैं।
  2. प्रत्येक ओकटेट को एन्कोडेड स्ट्रिंग आर + 1 में दोहराएं , जहां आर विकिरण स्तर है।

इस तरह, विकिरण समान वर्णों के एक रन को पूरी तरह से हटा नहीं सकता है, ताकि हम प्रत्येक रन से एक चरित्र को ले कर स्ट्रिंग को डिकोड कर सकें और फिर चरण 1 को डिकोड कर सकें।

तो केवल दिलचस्प हिस्सा एक एन्कोडिंग ढूंढ रहा है जो कभी भी दोहराया ऑक्टेट नहीं देता है। मूल विचार एक संख्या प्रणाली के रूप में A043096 जैसी किसी चीज़ का उपयोग करना है। यही है, एक पूर्णांक को सांकेतिक शब्दों में बदलना एन , हम बस कुछ बेस बी में गिनती करते हैं , दोहराया ऑक्टेट्स के साथ सभी संख्याओं को छोड़ देते हैं। मेरा मानना ​​है कि अंकों की मात्रा को इस तरह से d अंकों तक दर्शाया जा सकता है, संख्याओं की मात्रा के समान है जो कि जीवनी आधार b-1 में दर्शाई जा सकती है (जब से, आप ऐसी संख्या लिखना चाहते हैं, आप कर सकते हैं बाधा का उल्लंघन किए बिना प्रत्येक स्थिति के लिए बी -1 अंक चुनें ।

बेशक, अधिकतम संपीड़न प्राप्त करने के लिए हम b = 256 का उपयोग करेंगे । इनपुट को पूर्णांक में बदलने के लिए, हम आधार रूपांतरण का भी उपयोग कर सकते हैं। यदि मैं आलसी नहीं था, तो मैं इनपुट के लिए एक विशेषण आधार का उपयोग करूंगा, लेकिन अभी के लिए मैं सिर्फ एक 1( पूर्ववर्ती कोई शून्य नहीं हैं यह सुनिश्चित करने के लिए) का उपयोग कर रहा हूं और फिर सबसे छोटे संभव आधार का उपयोग कर सकता हूं , जैसे कि सभी ओकटेट इनपुट बेस से कम हैं।

इस बेस को फिर एन्कोडिंग से जोड़ा जाता है (ताकि डिकोडर को पता हो कि किस बेस का उपयोग करना है) और शेष संख्या से 0-ऑक्टेट द्वारा अलग किया गया है (यह काम करता है क्योंकि शेष संख्या कभी भी शून्य से शुरू नहीं होगी)। एक मामूली अनुकूलन के रूप में, खाली स्ट्रिंग एक रिक्त स्ट्रिंग बनी हुई है।

जिस कारण से मैंने ऊपर एक सटीक स्कोर की गणना नहीं की है, वह यह है कि मैं केवल एक ऊपरी सीमा की गणना कर रहा हूं कि प्रत्येक इनपुट इसकी लंबाई और इसकी अधिकतम ओक्टेट पर आधारित होगा। हालांकि, इन दो मापदंडों के लिए, अक्सर दो अलग-अलग आउटपुट लंबाई होगी, और मैंने अभी तक यह पता लगाने की जहमत नहीं उठाई है कि उनके बीच की टिपिंग बिंदु कहां होती है। मैंने उस लंबाई का अनुमान लगाने के लिए विशेष आधार 255 की बजाय सामान्य आधार 255 की लंबाई का भी उपयोग किया है, जो होने की तुलना में फिर से थोड़ा बड़ा है। गणना के लिए मेरे द्वारा उपयोग किया गया सटीक गणित कोड निम्नलिखित है:

num[l_, 1] = 0;
num[l_, base_] := num[l, base] = base^l - Sum[num[l, b], {b, base - 1}]
Sum[
  num[l, b]*(r + 1)*(2 + IntegerLength[2*b^l - 1, 255])/256^l, 
  {r, 0, 9}, {l, 1, 99}, {b, 2, 256}
]
N@%

num[l, b]lअधिकतम ऑक्टेट के साथ लंबाई के तारों की संख्या देना चाहिए b-1(सिवाय b == 1, जहां मैंने इसे हार्डकोड किया है 0क्योंकि मैं हमेशा कम से कम बेस का उपयोग कर रहा हूं 2)।


"यह मानते हुए कि लंबाई N की एक स्ट्रिंग औसत से (r + 1) से कम एनकोडिंग नहीं हो सकती। मुझे इसके सत्य होने का कोई कारण नहीं दिखता। मैं एक एन्कोडिंग योजना को देखकर आश्चर्यचकित नहीं रहूंगा जो ओ (एन + आर) है।
orlp

1
@orlp मैं यह नहीं देख रहा हूं कि यह कैसे संभव होगा, लेकिन मैं गलत साबित होने का इंतजार कर रहा हूं। :)
मार्टिन एंडर

अछा सुझाव। मुझे CJam का पता नहीं है, लेकिन आपके विवरण से, ऐसा लगता है कि आप आधार को एन्कोडेड डेटा में प्रस्तुत कर रहे हैं। यदि ऐसा है, तो क्या कोई समस्या है यदि पहले से मौजूद डेटा से हटाए गए वर्ण हैं? (यही गलती मैंने की थी @Leo ने बताया, कि मुझे अपने समाधान में ठीक करना था।)
मिशेल स्पेक्टर

प्रत्येक वर्ण r + 1 बार दोहराने से पहले @MitchellSpector को आधार बनाया गया है। तो आधार विकिरण सुरक्षित भी है।
मार्टिन एंडर

यह अच्छा है - यही मैंने अपने समाधान में भी किया है। आपको बस यह सुनिश्चित करने की आवश्यकता है कि आधार क्या है यह जानने से पहले डिकोडर पहले से तैयार डेटा को डीकोड कर सकता है।
मिशेल स्पेक्टर

6

bash + GNU उपयोगिताओं, स्कोर 294506 283468

संपादित 1: एक समस्या को ठीक करता है जो @Leo ने देखा - धन्यवाद!

संपादित 2: बेहतर स्कोर के लिए, विकिरण पैरामीटर के लिए एन्कोडिंग विधि में सुधार हुआ।

एनकोडर (97 बाइट्स):

for((j=0;j<$1;j++)){ p+=p\;;}
(sed 's/\(.\)\1/\1a\1a/g'<<<$1;cat)|xxd -p -c1|sed ${p-;}|xxd -r -p

विकोडक (121 बाइट्स):

read n
n=`sed 's/\(.\)\1*/\1/g'<<<$n`
sed -r "s/( ..)\1{0,${n//a}}/\1/g"<<<' 0a '`xxd -p -c1`|sed 's/^ [^ ]*//'|xxd -r -p

एनकोडर के लिए: स्टेंट में वर्णों के रूप में ऑक्टेट अनुक्रम पारित किया गया, विकिरण पैरामीटर आर एक तर्क के रूप में पारित हुआ।

डिकोडर के लिए: इनपुट स्टड में वर्णों के रूप में पारित हुआ।

दोनों के लिए: स्टडआउट पर आउटपुट।

एनकोडर इनपुट डेटा को r के अंकों का संकेत देता है, जिसमें एक अक्षर 'a' होता है, जो कि एक समान नई अंकों की प्रत्येक जोड़ी के बीच होता है, उसके बाद एक एकल न्यूलाइन होता है। यह तब सभी इनपुट (पहले से वर्णों के साथ शुरू) की प्रतिलिपि बनाता है, प्रत्येक वर्ण को उस वर्ण की r + 1 प्रतियों द्वारा प्रतिस्थापित करता है।

डिकोडर इसे पूर्ववत करता है, इसके इनपुट में शेष वर्ण x में से प्रत्येक के माध्यम से जा रहा है, एक्स के बाद x की लगातार समान प्रतियों तक स्किप करता है और जो रहता है उसे प्रिंट करता है। पूर्व-निर्धारित डेटा में कोई दोहराए गए वर्ण नहीं हैं, इसलिए r ज्ञात होने से पहले इसे डीकोड किया जा सकता है। उस बिंदु पर, आर ज्ञात है, और बाकी डेटा को सही ढंग से डिकोड करने के लिए उस मूल्य की आवश्यकता है।

आप देख सकते हैं कि यह काम करता है भले ही मूल इनपुट में समान अक्षर दोहराए गए हों।


स्कोर अभिकलन:

मान लीजिए कि इनपुट की लंबाई एल है और विकिरण पैरामीटर आर है (जो स्कोरिंग गणना के लिए अधिकतम 9 पर है, इसलिए यह एक अंक में फिट बैठता है और इसलिए लगातार दोहराया वर्ण नहीं है)। प्रीपेड डेटा 2 बाइट्स (अंक, न्यूलाइन) है, इसलिए इनकोडेड स्ट्रीम के लिए आउटपुट (r + 1) (L + 2) बाइट्स है।

तो जी (एल, आर) = (आर + 1) (एल + 2)।

यह निम्नानुसार है कि कुल स्कोर की गणना की जा सकती है

यहाँ छवि विवरण दर्ज करें


क्या होगा अगर गिरा हुआ ओकटेट पहला है? डिकोडर rपढ़ने के लिए एक नहीं होगा
लियो

@ आप सही हैं। मैं उस कल को ठीक करके देखूंगा - आज रात बहुत देर हो चुकी है। इसे जगह देने के लिए धन्यवाद।
मिशेल स्पेक्टर

@ मुझे लगता है कि यह r के 1 अंक की r + 1 प्रतियों को शामिल करके इसे ठीक करने योग्य है, इसके बाद r + 1 newlines। अगर यह सही है, तो स्कोर बहुत ऊपर नहीं जाएगा।
मिशेल स्पेक्टर

कुछ ऐसा काम करना चाहिए। मुझे लगता है कि आपको यह सुनिश्चित करने के लिए कुछ अतिरिक्त उपाय करने चाहिए कि यह उच्च विकिरणों (जैसे एक विकिरण 222) के साथ ठीक से काम करता है , लेकिन सौभाग्य से स्कोर की गणना केवल 0-9 विकिरणों से अधिक की जाती है, इसलिए यह अधिक प्रभावित नहीं होगा। PS मैं इसी एन्कोडिंग को लागू करने के बारे में सोच रहा था, इसीलिए मैंने इस त्रुटि को तुरंत दूर कर दिया;)
सिंह

@ ठीक है, विकिरण के लिए सभी मानों के लिए फिक्स काम करता है, भले ही स्कोर केवल 9. 9 के विकिरण मूल्यों को ध्यान में रखता है
मिशेल स्पेक्टर

3

पर्ल + मैथ :: {मोडिएंट, पॉलीनोमियल, प्राइम :: यूटिलि}, स्कोर 28 92819

$m=Math::Polynomial;sub l{($n,$b,$d)=@_;$n||$d||return;$n%$b,l($n/$b,$b,$d&&$d-1)}sub g{$p=$m->interpolate([grep ref$_[$_],0..$map{$p->evaluate($_)}0..$}sub p{prev_prime(128**$s)}sub e{($_,$r)=@_;length||return'';$s=$r+1;s/^[␀␁]/␁$&/;@l=map{mod($_,p$s)}l(Math::BigInt->from_bytes($_),p$s);$@l+$r>p($s)&&return e($_,$s);$a=0;join'',map{map{chr$_+$a}l($_->residue,128,$s,($a^=128))}g(@l)}sub d{@l=split/([␀-␡]+)/,$_[0];@l||return'';$s=vecmax map length,@l;@l=g map{length==$s&&mod($m->new(map{ord()%128}split//)->evaluate(128),p$s)}@l;$$_=$m->new(map{$_->residue}@l)->evaluate(p$s)->to_bytes;s/^␁//;$_}

नियंत्रण चित्रों का उपयोग संबंधित नियंत्रण वर्ण (जैसे एक शाब्दिक NUL वर्ण) का प्रतिनिधित्व करने के लिए किया जाता है । कोड पढ़ने की कोशिश करने के बारे में ज्यादा चिंता न करें; नीचे एक और पठनीय संस्करण है।

के साथ भागो -Mbigint -MMath::ModInt=mod -MMath::Polynomial -MNtheory=:all-MMath::Bigint=lib,GMPआवश्यक नहीं है (और इस तरह स्कोर में शामिल नहीं), लेकिन यदि आप इसे अन्य पुस्तकालयों से पहले जोड़ते हैं तो यह कार्यक्रम को कुछ और तेज कर देगा।

स्कोर गणना

यहां एल्गोरिदम कुछ हद तक कामचलाऊ है, लेकिन इसे लिखना कठिन होगा (पर्ल के उपयुक्त लाइब्रेरी नहीं होने के कारण)। इस वजह से, मैंने कोड में कुछ आकार / दक्षता वाले ट्रेडऑफ़ बनाए, इस आधार पर कि बाइट्स को एन्कोडिंग में सहेजा जा सकता है, हर बिंदु को गोल्फ से दाढ़ी बनाने की कोशिश करने का कोई मतलब नहीं है।

कार्यक्रम में 600 बाइट्स कोड, प्लस 78 बाइट्स ऑफ़ कमांड-लाइन विकल्प, 678 पॉइंट पेनल्टी देते हैं। बाकी के अंक की गणना 0 से 99 तक की लंबाई और हर विकिरण स्तर पर 0 से 9 तक के सर्वश्रेष्ठ-केस और सबसे खराब स्थिति (आउटपुट लंबाई के संदर्भ में) पर कार्यक्रम चलाकर की गई; औसत मामला कहीं न कहीं है, और यह स्कोर पर सीमा देता है। (यह सटीक मूल्य की गणना करने की कोशिश करने के लायक नहीं है जब तक कि एक समान स्कोर के साथ एक और प्रविष्टि न आए।)

इसका मतलब यह है कि एन्कोडिंग दक्षता से स्कोर 91100 से 92141 की सीमा में है, इस प्रकार अंतिम स्कोर है:

91100 + 600 + 78 = 91778 ≤ स्कोर 19 92819 = 92141 + 600 + 78

कम-गोल्फ संस्करण, टिप्पणियों और परीक्षण कोड के साथ

यह मूल कार्यक्रम + newlines, इंडेंटेशन, और टिप्पणियां हैं। (वास्तव में, इस संस्करण से newlines / इंडेंटेशन / टिप्पणियों को हटाकर गोल्फ संस्करण का निर्माण किया गया था।)

use 5.010;                    # -M5.010; free
use Math::BigInt lib=>'GMP';  # not necessary, but makes things much faster
use bigint;                   # -Mbigint
use Math::ModInt 'mod';       # -MMath::ModInt=mod
use Math::Polynomial;         # -MMath::Polynomial
use ntheory ':all';           # -Mntheory=:all
use warnings;                 # for testing; clearly not necessary

### Start of program

$m=Math::Polynomial;          # store the module in a variable for golfiness

sub l{ # express a number $n in base $b with at least $d digits, LSdigit first
    # Note: we can't use a builtin for this because the builtins I'm aware of
    # assume that $b fits into an integer, which is not necessarily the case.
    ($n,$b,$d)=@_;
    $n||$d||return;
    $n%$b,l($n/$b,$b,$d&&$d-1)
}

sub g{ # replaces garbled blocks in the input with their actual values
    # The basic idea here is to interpolate a polynomial through all the blocks,
    # of the lowest possible degree. Unknown blocks then get the value that the
    # polynomial evaluates to. (This is a special case of Reed-Solomon coding.)
    # Clearly, if we have at least as many ungarbled blocks as we did original
    # elements, we'll get the same polynomial, thus we can always reconstruct
    # the input.
    # Note (because it's confusing): @_ is the input, $_ is the current element
    # in a loop, but @_ is written as $_ when using the [ or # operator (e.g.
    # $_[0] is the first element of @_.
    # We waste a few bytes of source for efficiency, storing the polynomial
    # in a variable rather than recalculating it each time.
    $p=$m->interpolate([grep ref$_[$_],0..$#_],[grep ref,@_]);
    # Then we just evaluate the polynomial for each element of the input.
    map{$p->evaluate($_)}0..$#_
}

sub p{ # determines maximum value of a block, given (radiation+1)
    # We split the input up into blocks. Each block has a prime number of
    # possibilities, and is stored using the top 7 bits of (radiation+1)
    # consecutive bytes of the output. Work out the largest possible prime that
    # satisfies this property.
    prev_prime(128**$s)
}

sub e{ # encoder; arguments: input (bytestring), radiation (integer)
    ($_,$r)=@_; # Read the arguments into variables, $_ and $r respectively
    length||return''; # special case for empty string
    $s=$r+1; # Also store radiation+1; we use it a lot
    # Ensure that the input doesn't start with NUL, via prepending SOH to it if
    # it starts with NUL or SOH. This means that it can be converted to a number
    # and back, roundtripping correctly.
    s/^[␀␁]/␁$&/; #/# <- unconfuse Stack Exchange's syntax highlighting
    # Convert the input to a bignum, then to digits in base p$s, to split it
    # into blocks.
    @l=map{mod($_,p$s)}l(Math::BigInt->from_bytes($_),p$s);
    # Encoding can reuse code from decoding; we append $r "garbled blocks" to
    # the blocks representing the input, and run the decoder, to figure out what
    # values they should have.
    $#l+=$r;
    # Our degarbling algorithm can only handle at most p$s blocks in total. If
    # that isn't the case, try a higher $r (which will cause a huge increase in
    # $b and a reduction in @l).
    @l+$r>p($s)&&return e($_,$s);
    # Convert each block to a sequence of $s digits in base 128, adding 128 to
    # alternating blocks; this way, deleting up to $r (i.e. less than $s) bytes
    # will preserve the boundaries between each block; then convert that to a
    # string
    $a=0; # we must initialize $a to make this function deterministic
    join'',map{map{chr$_+$a}l($_->residue,128,$s,($a^=128))}g(@l)
}

sub d{ # decoder: arguments; encdng (bytestring)
    # Reconstruct the original blocks by looking at their top bits
    @l=split/([␀-␡]+)/,$_[0];
    @l||return''; # special case for empty string
    # The length of the longest block is the radiation parameter plus 1 (i.e.
    # $s). Use that to reconstruct the value of $s.
    $s=vecmax map length,@l;
    # Convert each block to a number, or to undef if it has the wrong length.
    # Then work out the values for the undefs.
    @l=g map{
        # Convert blocks with the wrong length to undef.
        length==$s&&
            # Convert other blocks to numbers, via removing any +128 and then
            # using Math::Polynomial to convert the digit list to a number.
            mod($m->new(map{ord()%128}split// #/# <- fix syntax highlighting
            )->evaluate(128),p$s)
    }@l;
    # Remove the redundant elements at the end; now that they've reconstructed
    # the garbled elements they have no further use.
    $#l-=$s-1;
    # Convert @l to a single number (reversing the conversion into blocks.)
    $_=$m->new(map{$_->residue}@l)->evaluate(p$s)
        # Convert that number into a string.
        ->to_bytes;
    # Delete a leading SOH.
    s/^␁//;  #/# <- unconfuse Stack Exchange's syntax highlighting
    # Finally, return the string.
    $_
}


### Testing code
use Encode qw/encode decode/;

# Express a string using control pictures + IBM437, to make binary strings
# easier for a human to parse
sub format_string {
    ($_)=@_;
    $_ = decode("Latin-1", $_);
    s/[\0-\x1f]/chr (0x2400 + ord $&)/eag;
    s/\x7f/chr 0x2421/eag;
    s/[ -~\x80-\xff]/decode("IBM437",$&)/eag;
    encode("UTF-8","\x{ff62}$_\x{ff63}")
}

sub test {
    my ($string, $radiation, $samples) = @_;
    say "Input: ", format_string($string);
    my $encoding = e($string, $radiation);
    say "Encoding: ", format_string($encoding);
    say "Input length ", length($string), ", encoding length ", length($encoding), ", radiation $radiation";
    my $decoding = d($encoding);
    $decoding eq $string or die "Mistake in output!";
    say "Decoding: ", format_string($decoding), " from ",
        format_string($encoding);

    # Pseudo-randomly generate $samples radiation-damaged versions.
    srand 1;
    for my $i (1..$samples) {
        my $encdng = $encoding;
        for my $r (1..$radiation) {
            substr $encdng, int(rand(length $encdng)), 1, "";
        }
        my $newdecoding = d($encdng);
        say "Decoding: ", format_string($newdecoding), " from ",
            format_string($encdng);
        $newdecoding eq $string or die "Mistake in output!";
    }

    say "";
    length $encoding;
}

test "abcdefghijklm", 1, 10;
test "abcdefghijklm", 2, 10;
test "abcdefghijklm", 5, 10;
test "abcdefghijklm", 10, 10;
test "\0\0\0\0\0", 1, 10;
test "\5\4\3\2\1", 2, 10;
test "a", 10, 10;

my %minlength = ();
my %maxlength = ();

for my $length (0..99) {
    my ($min, $max) = ("", "");
    $length and ($min, $max) =
        ("\2" . "\0" x ($length - 1), "\1" . "\377" x ($length - 1));
    for my $radiation (0..9) {
        $minlength{"$length-$radiation"} = test $min, $radiation, 1;
        $maxlength{"$length-$radiation"} = test $max, $radiation, 1;
    }
}

say "Minimum score: ", vecsum values %minlength;
say "Maximum score: ", vecsum values %maxlength;

कलन विधि

समस्या को सरल बनाना

मूल विचार यह है कि इस "विलोपन कोडिंग" समस्या को कम करना (जो कि व्यापक रूप से पता लगाया नहीं गया है) एक इरेज़िंग कोडिंग समस्या (गणित का एक व्यापक रूप से खोजा गया क्षेत्र) में। इरेज़र कोडिंग के पीछे का विचार यह है कि आप "इरेज़र चैनल" पर भेजे जाने वाले डेटा को तैयार कर रहे हैं, एक चैनल जो कभी-कभी अपने द्वारा भेजे जाने वाले अक्षरों को "गार्बल" वर्ण से बदल देता है जो किसी त्रुटि की ज्ञात स्थिति को इंगित करता है। (दूसरे शब्दों में, यह हमेशा स्पष्ट है कि भ्रष्टाचार कहां हुआ है, हालांकि मूल चरित्र अभी भी अज्ञात है।) इसके पीछे का विचार बहुत सरल है: हम इनपुट को लंबाई के ब्लॉक में विभाजित करते हैं ( विकिरण+ 1), और डेटा के लिए प्रत्येक ब्लॉक में आठ बिट्स में से सात का उपयोग करें, जबकि शेष बिट (इस निर्माण में, MSB) एक पूरे ब्लॉक के लिए सेट होने के बीच वैकल्पिक होता है, पूरे अगले ब्लॉक के लिए स्पष्ट होता है, ब्लॉक के लिए सेट होता है। उसके बाद, और इसी तरह। क्योंकि ब्लॉक विकिरण पैरामीटर से अधिक लंबे होते हैं, इसलिए प्रत्येक ब्लॉक से कम से कम एक वर्ण आउटपुट में जीवित रहता है; इसलिए एक ही MSB के साथ पात्रों के रन लेने से, हम यह काम कर सकते हैं कि प्रत्येक वर्ण किस ब्लॉक से संबंधित है। ब्लॉकों की संख्या भी हमेशा विकिरण पैरामीटर से अधिक होती है, इसलिए हमारे पास हमेशा कम से कम एक अनमैडेड ब्लॉक होता है; हम इस प्रकार जानते हैं कि सभी ब्लॉक जो सबसे लंबे समय तक या सबसे लंबे समय तक बंधे होते हैं, वे अप्रकाशित होते हैं, जिससे हम किसी भी छोटे ब्लॉक को क्षतिग्रस्त (इस प्रकार एक गार्बेल) समझ सकते हैं। हम इस तरह से विकिरण पैरामीटर भी घटा सकते हैं (यह)

मिटाना कोडिंग

समस्या के उन्मूलन कोडिंग भाग के लिए, यह रीड-सोलोमन निर्माण के एक साधारण विशेष मामले का उपयोग करता है। यह एक व्यवस्थित निर्माण है: आउटपुट (इरेज़र कोडिंग एल्गोरिथ्म का) इनपुट प्लस के बराबर और अतिरिक्त ब्लॉकों की संख्या, विकिरण पैरामीटर के बराबर है। हम इन ब्लॉकों के लिए आवश्यक मूल्यों की गणना एक सरल (और गोल्फरी!) तरीके से कर सकते हैं, उन्हें गार्लेस के रूप में मानकर, फिर उनके मूल्य को "पुनर्निर्माण" करने के लिए उन पर डिकोडिंग एल्गोरिदम चला रहे हैं।

निर्माण के पीछे का वास्तविक विचार भी बहुत सरल है: हम एन्कोडिंग में सभी ब्लॉकों के लिए एक बहुपद को फिट करते हैं, एन्कोडिंग के सभी ब्लॉकों के लिए (अन्य तत्वों से प्रक्षेपित गार्बल्स के साथ); यदि बहुपद f है , तो पहला खंड f (0) है, दूसरा f (1) है, और इसी तरह। यह स्पष्ट है कि बहुपद की डिग्री इनपुट माइनस 1 के ब्लॉकों की संख्या के बराबर होगी (क्योंकि हम पहले उन लोगों के लिए एक बहुपद फिट होते हैं, फिर इसका उपयोग अतिरिक्त "चेक" ब्लॉकों के निर्माण के लिए करते हैं); और क्योंकि +1 अंक विशिष्ट डिग्री के एक बहुपद परिभाषित , किसी भी संख्या में ब्लॉक (रेडिएशन पैरामीटर तक) को गार्बलिंग करने से मूल इनपुट के बराबर कई बिना ब्लॉक वाले ब्लॉक निकल जाएंगे, जो एक ही बहुपद के पुनर्निर्माण के लिए पर्याप्त जानकारी है। (हम तो बस एक खंड को खंडित करने के लिए बहुपद का मूल्यांकन करना है।)

आधार रूपांतरण

अंतिम विचार यहां छोड़ दिया गया है कि ब्लॉक द्वारा उठाए गए वास्तविक मूल्यों के साथ क्या करना है; यदि हम पूर्णांक पर बहुपद प्रक्षेप करते हैं, तो परिणाम तर्कसंगत संख्याएँ हो सकते हैं (पूर्णांक की बजाय), इनपुट मानों की तुलना में बहुत बड़ा, या अन्यथा अवांछनीय। जैसे, पूर्णांक का उपयोग करने के बजाय, हम एक परिमित क्षेत्र का उपयोग करते हैं; इस कार्यक्रम में, परिमित क्षेत्र का उपयोग किया जाता है जो पूर्णांक मॉडुलो p का क्षेत्र है , जहां p सबसे बड़ा अभाज्य है जो कि विकिरण विकिरण से कम है +1(अर्थात सबसे बड़ा अभाज्य जिसके लिए हम उस ब्लॉक के डेटा भाग में उस संख्या के बराबर कई अलग-अलग मान फिट कर सकते हैं)। परिमित क्षेत्रों का बड़ा लाभ यह है कि विभाजन (0 को छोड़कर) विशिष्ट रूप से परिभाषित है और हमेशा उस क्षेत्र के भीतर एक मूल्य पैदा करेगा; इस प्रकार, बहुपद के प्रक्षेपित मान उसी तरह से एक ब्लॉक में फिट होंगे जिस तरह से इनपुट मान करते हैं।

इनपुट को ब्लॉक डेटा की एक श्रृंखला में बदलने के लिए, हमें आधार रूपांतरण करने की आवश्यकता है: इनपुट को आधार 256 से एक संख्या में परिवर्तित करें, फिर बेस पी में परिवर्तित करें (उदाहरण 1 के विकिरण पैरामीटर के लिए, हमारे पास पी है= 16381)। यह ज्यादातर पर्ल कन्वर्जन बेस बेसिन रूटीन की कमी के कारण आयोजित किया गया था (मैथ :: प्राइम :: यूटील में कुछ है, लेकिन वे बिग्नम बेस के लिए काम नहीं करते हैं, और कुछ प्राइम्स जो हम यहां काम करते हैं वे अविश्वसनीय रूप से बड़े हैं)। जैसा कि हम पहले से ही गणित का उपयोग कर रहे हैं :: बहुपद प्रक्षेप के लिए बहुपद, मैं इसे "अंकों के अनुक्रम से रूपांतरण" फ़ंक्शन के रूप में पुन: उपयोग करने में सक्षम था (अंकों को एक बहुपद के गुणांक के रूप में देखने और इसका मूल्यांकन करने के लिए, और यह बोली के लिए काम करता है) बस ठीक। दूसरे तरीके से जा रहे हैं, हालांकि, मुझे खुद ही फंक्शन लिखना था। सौभाग्य से, यह लिखना बहुत कठिन (या क्रिया) नहीं है। दुर्भाग्य से, इस आधार रूपांतरण का अर्थ है कि इनपुट आम तौर पर अपठनीय है। अग्रणी शून्य के साथ एक मुद्दा भी है;

यह ध्यान दिया जाना चाहिए कि हम आउटपुट में पी ब्लॉक से अधिक नहीं हो सकते हैं (अन्यथा दो ब्लॉकों के सूचकांक समान हो जाएंगे, और फिर भी संभवतः अलग-अलग आउटपुट का उत्पादन बहुपद बनाने की आवश्यकता है)। यह केवल तब होता है जब इनपुट बहुत बड़ा होता है। यह कार्यक्रम इस मुद्दे को बहुत ही सरल तरीके से हल करता है: बढ़ते विकिरण (जो ब्लॉक को बड़ा और p को अधिक बड़ा बनाता है , जिसका अर्थ है कि हम बहुत अधिक डेटा को फिट कर सकते हैं, और जो स्पष्ट रूप से एक सही परिणाम की ओर ले जाता है)।

बनाने के लिए एक और बात यह है कि हम अशक्त स्ट्रिंग को अपने आप में एन्कोड करते हैं, क्योंकि लिखित प्रोग्राम अन्यथा उस पर क्रैश होगा। यह स्पष्ट रूप से सबसे अच्छा संभव एन्कोडिंग है, और कोई फर्क नहीं पड़ता कि विकिरण पैरामीटर क्या है।

संभावित सुधार

इस कार्यक्रम में मुख्य स्पर्शोन्मुख अक्षमता है, यह सवाल में परिमित क्षेत्रों के रूप में मॉडुलो-प्राइम के उपयोग के साथ करना है। आकार 2 एन के परिमित क्षेत्र मौजूद हैं (जो कि वास्तव में हम यहां चाहते हैं, क्योंकि ब्लॉक का पेलोड आकार स्वाभाविक रूप से 128 की शक्ति है)। दुर्भाग्य से, वे एक साधारण मोडुलो निर्माण की तुलना में अधिक जटिल हैं, जिसका अर्थ है कि गणित :: ModInt इसे काट नहीं सकता है (और मैं गैर-प्रमुख आकारों के परिमित क्षेत्रों को संभालने के लिए CPAN पर कोई लाइब्रेरी नहीं पा सका); मुझे गणित के लिए अतिभारित अंकगणित के साथ एक पूरी कक्षा लिखनी होगी :: बहुपद इसे संभालने में सक्षम होने के लिए, और उस समय बाइट लागत संभावित रूप से 16384 की तुलना में 16381 (जैसे, 16381) का उपयोग करने से नुकसान हो सकता है।

पॉवर ऑफ -2 साइज का उपयोग करने का एक और फायदा यह है कि बेस कन्वर्जन काफी आसान हो जाएगा। हालांकि, किसी भी मामले में, इनपुट की लंबाई का प्रतिनिधित्व करने का एक बेहतर तरीका उपयोगी होगा; "अस्पष्ट मामलों में एक प्रस्तुत करना" विधि सरल लेकिन बेकार है। जीवनात्मक आधार रूपांतरण यहां एक प्रशंसनीय दृष्टिकोण है (विचार यह है कि आपके पास आधार एक अंक के रूप में है, और 0 अंक के रूप में नहीं है, ताकि प्रत्येक संख्या एक स्ट्रिंग से मेल खाती हो)।

यद्यपि इस एन्कोडिंग का स्पर्शोन्मुख प्रदर्शन बहुत अच्छा है (उदाहरण के लिए लंबाई 99 के इनपुट और 3 के विकिरण पैरामीटर के लिए, एन्कोडिंग हमेशा 128 बाइट्स लंबा होता है, बजाय ~ 400 बाइट्स कि पुनरावृत्ति-आधारित दृष्टिकोण प्राप्त होगा), इसके प्रदर्शन शॉर्ट इनपुट पर कम अच्छा है; एन्कोडिंग की लंबाई हमेशा (विकिरण पैरामीटर + 1) का वर्ग कम से कम होती है। तो विकिरण 9 पर बहुत कम आदानों (लंबाई 1 से 8) के लिए, आउटपुट की लंबाई फिर भी 100 है। (लंबाई 9 पर, आउटपुट की लंबाई कभी 100 और कभी 110 होती है।) दोहराव-आधारित दृष्टिकोण स्पष्ट रूप से इस क्षरण को हरा देते हैं। बहुत छोटे इनपुट पर कोडिंग-आधारित दृष्टिकोण; यह इनपुट के आकार के आधार पर कई एल्गोरिदम के बीच बदलने लायक हो सकता है।

अंत में, यह वास्तव में स्कोरिंग में नहीं आता है, लेकिन बहुत ही उच्च विकिरण मापदंडों के साथ, प्रत्येक बाइट (आउटपुट आकार के come) का उपयोग करके ब्लॉकों को परिसीमित करना बेकार है; इसके बजाय ब्लॉक के बीच सीमांकक का उपयोग करना सस्ता होगा। डेलिमिटर से ब्लॉक का पुनर्निर्माण वैकल्पिक-एमएसबी दृष्टिकोण के बजाय कठिन है, लेकिन मेरा मानना ​​है कि यह संभव है, कम से कम यदि डेटा पर्याप्त रूप से लंबा है (शॉर्ट डेटा के साथ, आउटपुट से विकिरण पैरामीटर को कम करना मुश्किल हो सकता है) । यह देखने के लिए कुछ होगा अगर मापदंडों की परवाह किए बिना एक विषम आदर्श दृष्टिकोण के लिए लक्ष्य किया जाए।

(और निश्चित रूप से, एक पूरी तरह से अलग एल्गोरिथ्म हो सकता है जो इस एक से बेहतर परिणाम पैदा करता है!)

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.