Λ-पथरी के इष्टतम मूल्यांकनकर्ता बिना फॉर्मूलों के बड़े मॉड्यूलर घातांक की गणना करने में सक्षम क्यों हैं?


135

चर्च संख्या कार्यों के रूप में प्राकृतिक संख्याओं का एन्कोडिंग है।

(\ f x  (f x))             -- church number 1
(\ f x  (f (f (f x))))     -- church number 3
(\ f x  (f (f (f (f x))))) -- church number 4

केवल, आप उन्हें लागू करने के द्वारा 2 चर्च संख्या को दर्शा सकते हैं। यही है, यदि आप 4 से 2 लागू करते हैं, तो आपको चर्च नंबर मिलता है 16, या 2^4। जाहिर है, यह पूरी तरह से अव्यावहारिक है। चर्च के नंबरों को स्मृति की एक रैखिक राशि की आवश्यकता होती है और वास्तव में, वास्तव में धीमी होती है। कुछ इस तरह की गणना करना 10^10- जो GHCI जल्दी से सही उत्तर देता है - उम्र लेगा और वैसे भी आपके कंप्यूटर पर मेमोरी को फिट नहीं कर सकता है।

मैं हाल ही में इष्टतम λ मूल्यांकनकर्ताओं के साथ प्रयोग कर रहा हूं। मेरे परीक्षणों पर, मैंने अपने इष्टतम λ-कैलकुलेटर पर गलती से निम्नलिखित टाइप किया:

10 ^ 10 % 13

यह गुणन माना जाता था, न कि घातांक। इससे पहले कि मैं निराशा में हमेशा के लिए चल रहे कार्यक्रम को रद्द करने के लिए अपनी उंगलियों को हिला सकता, इसने मेरे अनुरोध का जवाब दिया:

3
{ iterations: 11523, applications: 5748, used_memory: 27729 }

real    0m0.104s
user    0m0.086s
sys     0m0.019s

अपने "बग अलर्ट" चमकती के साथ, मैं Google पर गया और सत्यापित किया, 10^10%13 == 3वास्तव में। लेकिन λ- कैलकुलेटर उस परिणाम को खोजने वाला नहीं था, यह मुश्किल से 10 ^ 10 स्टोर कर सकता है। मैंने इस पर जोर देना शुरू किया, विज्ञान के लिए। यह तुरंत मुझे जवाब 20^20%13 == 3, 50^50%13 == 4, 60^60%3 == 0। मुझे उन परिणामों को सत्यापित करने के लिए बाहरी साधनों का उपयोग करना पड़ा , क्योंकि हास्केल स्वयं इसकी गणना करने में सक्षम नहीं था (पूर्णांक अतिप्रवाह के कारण) (यह है यदि आप इंटर्ज़र्स का उपयोग नहीं करते हैं, तो बेशक!)। इसकी सीमाओं को धता बताते हुए, इसका उत्तर था 200^200%31:

5
{ iterations: 10351327, applications: 5175644, used_memory: 23754870 }

real    0m4.025s
user    0m3.686s
sys 0m0.341s

यदि हमारे पास ब्रह्मांड के प्रत्येक परमाणु के लिए ब्रह्मांड की एक प्रति थी, और हमारे पास कुल प्रत्येक परमाणु के लिए एक कंप्यूटर था, तो हम चर्च संख्या को संग्रहीत नहीं कर सकते थे 200^200। इसने मुझे सवाल करने के लिए प्रेरित किया कि क्या मेरा मैक वास्तव में इतना शक्तिशाली था। हो सकता है कि इष्टतम मूल्यांकनकर्ता अनावश्यक शाखाओं को छोड़ दे और एक ही अंदाज में जवाब पर पहुंचे, हास्केल आलसी मूल्यांकन के साथ करता है। इसे जांचने के लिए, मैंने λ प्रोग्राम को हास्केल में संकलित किया:

data Term = F !(Term -> Term) | N !Double
instance Show Term where {
    show (N x) = "(N "++(if fromIntegral (floor x) == x then show (floor x) else show x)++")";
    show (F _) = "(λ...)"}
infixl 0 #
(F f) # x = f x
churchNum = F(\(N n)->F(\f->F(\x->if n<=0 then x else (f#(churchNum#(N(n-1))#f#x)))))
expMod    = (F(\v0->(F(\v1->(F(\v2->((((((churchNum # v2) # (F(\v3->(F(\v4->(v3 # (F(\v5->((v4 # (F(\v6->(F(\v7->(v6 # ((v5 # v6) # v7))))))) # v5))))))))) # (F(\v3->(v3 # (F(\v4->(F(\v5->v5)))))))) # (F(\v3->((((churchNum # v1) # (churchNum # v0)) # ((((churchNum # v2) # (F(\v4->(F(\v5->(F(\v6->(v4 # (F(\v7->((v5 # v7) # v6))))))))))) # (F(\v4->v4))) # (F(\v4->(F(\v5->(v5 # v4))))))) # ((((churchNum # v2) # (F(\v4->(F(\v5->v4))))) # (F(\v4->v4))) # (F(\v4->v4))))))) # (F(\v3->(((F(\(N x)->F(\(N y)->N(x+y)))) # v3) # (N 1))))) # (N 0))))))))
main = print $ (expMod # N 5 # N 5 # N 4)

यह सही ढंग से आउटपुट 1( 5 ^ 5 % 4) - लेकिन ऊपर कुछ भी फेंक दें 10^10और यह परिकल्पना को समाप्त कर, अटक जाएगा।

इष्टतम मूल्यांकनकर्ता मैं प्रयोग किया जाता एक 160 लाइनों लंबे, unoptimized जावास्क्रिप्ट प्रोग्राम है जो घातीय मापांक गणित के किसी भी प्रकार को शामिल नहीं किया है - और लैम्ब्डा-पथरी मापांक समारोह मैं भी उतना ही आसान था प्रयोग किया है:

ab.(bcd.(ce.(dfg.(f(efg)))e))))(λc.(cde.e)))(λc.(a(bdef.(dg.(egf))))(λd.d)(λde.(ed)))(bde.d)(λd.d)(λd.d))))))

मैंने कोई विशिष्ट मॉड्यूलर अंकगणितीय एल्गोरिथ्म या सूत्र का उपयोग नहीं किया। तो, कैसे सही मूल्यांकन करने के लिए इष्टतम मूल्यांकनकर्ता आने में सक्षम है?


2
क्या आप हमें आपके द्वारा उपयोग किए जाने वाले इष्टतम मूल्यांकन के प्रकार के बारे में अधिक बता सकते हैं? शायद एक पेपर उद्धरण? धन्यवाद!
जेसन डगिट

11
मैं लैम्पिंग के अमूर्त एल्गोरिथ्म का उपयोग कर रहा हूं, जैसा कि कार्यात्मक प्रोग्रामिंग भाषाओं की इष्टतम कार्यान्वयन पर समझाया गया है । ध्यान दें कि मैं "oracle" (कोई क्रोइसैन / ब्रैकेट) का उपयोग नहीं कर रहा हूँ क्योंकि यह शब्द ईएएल-टाइप करने योग्य है। इसके अलावा, समानांतर में प्रशंसकों को बेतरतीब ढंग से कम करने के बजाय, मैं क्रमिक रूप से ग्राफ को
ट्रेस कर

7
ठीक है, अगर किसी के लिए उत्सुक है, तो मैंने अपने इष्टतम मूल्यांकनकर्ता के लिए स्रोत कोड के साथ GitHub रिपॉजिटरी स्थापित की है। इसकी कई टिप्पणियां हैं और आप इसे चालू कर सकते हैं node test.js। अगर आपका कोई प्रश्न हैं, तो मुझे से पूछें।
MaiaVictor

1
नीट का पता लगाएं! मुझे इष्टतम मूल्यांकन के बारे में पर्याप्त जानकारी नहीं है, लेकिन मैं कह सकता हूं कि यह मुझे Fermat के लिटिल प्रमेय / यूलर के प्रमेय की याद दिलाता है। यदि आप इससे अनजान हैं, तो यह एक अच्छा शुरुआती बिंदु हो सकता है।
लूकी जू

5
यह पहली बार है, जहाँ मुझे इस बात का ज़रा सा भी सुराग नहीं है कि सवाल क्या है, लेकिन फिर भी इस सवाल का जवाब देना चाहिए, और विशेष रूप से, बकाया प्रथम-उत्तर-उत्तर।
Marco13

जवाबों:


124

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

साझा करने का मतलब है कि आपके लैम्ब्डा-टर्म का प्रतिनिधित्व जिसमें एक "नोड" आपके द्वारा दर्शाए गए वास्तविक लैम्ब्डा-टर्म के कई समान हिस्सों का वर्णन कर सकता है। उदाहरण के लिए, आप इस शब्द का प्रतिनिधित्व कर सकते हैं

\x. x ((\y.y)a) ((\y.y)a)

एक (निर्देशित एसाइक्लिक) ग्राफ का उपयोग करना जिसमें सबग्राफ का केवल एक ही घटना होती है (\y.y)a, और उस सबग्राफ को लक्षित करने वाले दो किनारों। हास्केल के संदर्भ में, आपके पास एक थंक है, कि आप केवल एक बार मूल्यांकन करते हैं, और इस थंक के दो संकेत।

हास्केल-शैली का संस्मरण पूरा सबटर्म्स का साझाकरण लागू करता है। साझा करने के इस स्तर को निर्देशित चक्रीय रेखांकन द्वारा दर्शाया जा सकता है। इष्टतम साझाकरण में यह प्रतिबंध नहीं है: यह "आंशिक" सब्टरम्स को भी साझा कर सकता है, जो ग्राफ प्रतिनिधित्व में चक्र का संकेत दे सकता है।

साझा करने के इन दो स्तरों के बीच अंतर देखने के लिए, शब्द पर विचार करें

\x. (\z.z) ((\z.z) x)

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

थोड़े विस्तारित स्पष्टीकरण के लिए, आप पेपर कमजोर ऑप्टिमिलिटी, और शेयरिंग का अर्थ (जो आप में रुचि रखते हैं, परिचय और अनुभाग 4.1 है, और शायद अंत में ग्रंथ सूची के कुछ) देख सकते हैं।

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

जैसा कि आपने स्वयं कहा, इस तरह की एन्कोडिंग पूरी तरह से अव्यावहारिक है, लेकिन वे अभी भी समझने के एक अच्छे तरीके का प्रतिनिधित्व करते हैं कि क्या चल रहा है। और मुझे आगे की जांच के लिए एक चुनौती के साथ निष्कर्ष निकालना चाहिए: क्या आप एक उदाहरण ढूंढ पाएंगे, जिस पर इन कथित खराब एन्कोडिंग पर इष्टतम मूल्यांकन वास्तव में एक उचित डेटा प्रतिनिधित्व पर पारंपरिक मूल्यांकन के बराबर है? (जहाँ तक मुझे पता है यह एक वास्तविक खुला प्रश्न है)।


34
यह सबसे असामान्य रूप से पूरी तरह से पहली पोस्ट है। StackOverflow में आपका स्वागत है!
डेफ़र

2
आनंददायक से कम कुछ नहीं। धन्यवाद, और समुदाय में आपका स्वागत है!
MaiaVictor

7

यह एक अन्वेषक नहीं है, लेकिन यह एक सुझाव है कि आप कहाँ देखना शुरू कर सकते हैं।

विशेष रूप से पुनर्लेखन द्वारा, थोड़ी सी जगह में मॉड्यूलर एक्सप्रेशन की गणना करने के लिए एक तुच्छ तरीका है

(a * x ^ y) % z

जैसा

(((a * x) % z) * x ^ (y - 1)) % z

यदि कोई मूल्यांकनकर्ता इस तरह का मूल्यांकन करता है और संचय पैरामीटर aको सामान्य रूप में रखता है तो आप बहुत अधिक स्थान का उपयोग करने से बचेंगे। अगर वास्तव में अपने मूल्यांकनकर्ता है इष्टतम तो शायद यह इस एक से किसी भी अधिक काम नहीं करना चाहिए, इसलिए विशेष रूप से कर सकते हैं में समय यह एक मूल्यांकन करने के लिए ले जाता है और अधिक से अधिक स्थान का उपयोग नहीं।

मुझे वास्तव में यकीन नहीं है कि वास्तव में एक इष्टतम मूल्यांकनकर्ता क्या है इसलिए मुझे डर है कि मैं इसे और अधिक कठोर नहीं बना सकता हूं।


4
@ विल के रूप में @ विलिब फाइबोनैचि एक अच्छा उदाहरण है। fibभोले तरीके से घातांक समय की आवश्यकता होती है, जिसे एक साधारण ज्ञापन / गतिशील प्रोग्रामिंग के साथ रैखिक में कम किया जा सकता है। यहां तक ​​कि लघुगणक (!) समय n- वें मैट्रिक्स की शक्ति की गणना के माध्यम से संभव है [[0,1],[1,1]](जब तक आप प्रत्येक गुणन को एक निरंतर लागत के लिए गिनते हैं)।
चि।

1
यहां तक ​​कि लगातार समय यदि आप पर्याप्त रूप से लगभग साहस कर रहे हैं :)
जे। अब्राहमसन

5
@TomEllis ऐसा कुछ क्यों होगा जो केवल यह जानता है कि मनमाने ढंग से लैम्ब्डा कैलकुलस एक्सप्रेशन को कैसे कम किया जाए, (a * b) % n = ((a % n) * b) % nहालांकि इसका कोई विचार नहीं है ? वह रहस्यमय हिस्सा निश्चित रूप से है।
बार्टन

2
@ReidBarton निश्चित रूप से मैंने इसे आज़माया! वही परिणाम, हालांकि।
MaiaVictor

2
@TomEllis और Chi, हालांकि अभी एक छोटी सी टिप्पणी है। कि सभी मानते हैं कि पारंपरिक पुनरावर्ती कार्य "भोली" रेशेदार कार्यान्वयन है, लेकिन आईएमओ इसे व्यक्त करने का एक वैकल्पिक तरीका है जो बहुत अधिक प्राकृतिक है। उस नए निरूपण के सामान्य रूप में पारंपरिक के आकार का आधा हिस्सा होता है), और ऑप्टलम उस एक रेखीय की गणना करता है! इसलिए मेरा तर्क है कि जहां तक ​​λ-पथरी का संबंध है, फ़ाइब की "भोली" परिभाषा है। मैं एक ब्लॉग पोस्ट करूँगा, लेकिन मुझे यकीन नहीं है कि यह वास्तव में इसके लायक है ...
MaiaVictor
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.