एक संकलक की समय जटिलता


54

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

मेरा अनुमान है कि कुछ अनुकूलन कदम हैं जो घातीय हैं, लेकिन जिनका वास्तविक समय पर बहुत कम प्रभाव है। उदाहरण के लिए, संख्या के आधार पर घातीय एक फ़ंक्शन के तर्क हैं।

मेरे सिर के ऊपर से, मैं कहूंगा कि एएसटी पेड़ पैदा करना रैखिक होगा। आईआर पीढ़ी को कभी बढ़ते हुए तालिकाओं में मूल्यों को देखते हुए पेड़ के माध्यम से कदम बढ़ाने की आवश्यकता होगी, इसलिए या । कोड जनरेशन और लिंकिंग एक समान प्रकार का ऑपरेशन होगा। इसलिए, मेरा अनुमान , अगर हम उन चरों के घातांक को हटा देते हैं जो वास्तविक रूप से विकसित नहीं होते हैं।O(n2)O(nlogn)O(n2)

मैं हालांकि पूरी तरह से गलत हो सकता है। क्या इस पर किसी का कोई विचार है?


7
जब आप कुछ भी "घातीय", "रैखिक", , या दावा करते हैं तो आपको सावधान रहना होगा । कम से कम मेरे लिए, यह बिल्कुल स्पष्ट नहीं है कि आप अपने इनपुट को कैसे मापते हैं (एक्सपोनेंशियल इन व्हाट? व्हाट स्टैंड फॉर?)O(n2)O(nlogn)n
जुहो

2
जब आप LLVM कहते हैं, तो क्या आपका मतलब क्लैंग है? LLVM कई अलग-अलग संकलक उपप्रोजेक्ट्स के साथ एक बड़ी परियोजना है इसलिए यह थोड़ा अस्पष्ट है।
नैट CK

5
C # के लिए यह सबसे खराब स्थिति की समस्याओं के लिए कम से कम घातांक है (आप C # में NP पूर्ण SAT समस्या को एन्कोड कर सकते हैं)। यह सिर्फ अनुकूलन नहीं है, यह एक फ़ंक्शन के सही अधिभार को चुनने के लिए आवश्यक है। C ++ जैसी भाषा के लिए, यह अविश्वसनीय होगा, क्योंकि टेम्प्लेट पूर्ण रूप से ट्यूरिंग होते हैं।
कोडइन्चोस

2
@ ज़ैन मुझे आपकी बात समझ में नहीं आती। संकलन के दौरान टेम्पलेट तात्कालिकता होती है। आप एक समस्‍या में कठोर समस्‍याओं को सांकेतिक शब्दों में बदलना कर सकते हैं जो कंपाइलर को उस समस्‍या को हल करने के लिए मजबूर करती है ताकि एक सही आउटपुट तैयार किया जा सके। आप कंपाइलर को ट्यूरिंग पूर्ण टेम्प्लेट प्रोग्रामिंग भाषा का एक दुभाषिया मान सकते हैं।
कोडइन्चौस

3
जब आप लैम्ब्डा एक्सप्रेशन के साथ कई ओवरलोड्स को जोड़ते हैं तो C # ओवरलोड रेजोल्यूशन काफी मुश्किल है। आप एक बूलियन फॉर्मूला को इस तरह से एनकोड करने के लिए उपयोग कर सकते हैं, यह निर्धारित करते हुए कि लागू ओवरलोड होने पर एनपी-पूर्ण 3SAT समस्या की आवश्यकता होती है। वास्तव में समस्या को हल करने के लिए, कंपाइलर को वास्तव में उस फॉर्मूले का हल खोजना होगा, जो शायद कठिन भी हो। एरिक
लिपर्ट

जवाबों:


50

आपके प्रश्न का उत्तर देने के लिए सबसे अच्छी पुस्तक शायद होगी: कूपर और टॉरकोन, "इंजीनियरिंग एक कंपाइलर," 2003. यदि आपके पास एक विश्वविद्यालय पुस्तकालय तक पहुंच है, तो आपको एक प्रति उधार लेने में सक्षम होना चाहिए।

Llvm या gcc जैसे प्रोडक्शन कंपाइलर में डिज़ाइनर नीचे सभी एल्गोरिदम को रखने का हर संभव प्रयास करते हैं जहाँ इनपुट का आकार होता है। "अनुकूलन" के कुछ विश्लेषणों के लिए इसका मतलब यह है कि आपको वास्तव में इष्टतम कोड का निर्माण करने के बजाय उत्तराधिकार का उपयोग करने की आवश्यकता है।O(n2)n

लेक्सर एक परिमित अवस्था वाली मशीन है, इसलिए इनपुट के आकार में (वर्णों में) है और टोकन की एक धारा का निर्माण करती है जो पार्सर को पास की जाती है।O(n)O(n)

कई भाषाओं के लिए कई कंपाइलरों के लिए पार्सर LALR (1) है और इस प्रकार इनपुट टोकन की संख्या में समय में टोकन स्ट्रीम को संसाधित करता है । पार्सिंग के दौरान आपको आमतौर पर एक प्रतीक तालिका का ट्रैक रखना पड़ता है, लेकिन, कई भाषाओं के लिए, जिसे हैश टेबल ("शब्दकोशों") के ढेर के साथ संभाला जा सकता है। प्रत्येक शब्दकोश का उपयोग , लेकिन आपको कभी-कभी एक प्रतीक को देखने के लिए स्टैक पर चलना पड़ सकता है। ढेर की गहराई जहां scopes की घोंसले की गहराई है। (इसलिए सी जैसी भाषाओं में, आपके अंदर घुंघराले ब्रेसिज़ की कितनी परतें हैं।)O(n)O(1)O(s)s

तब तोता का पेड़ आम तौर पर एक नियंत्रण प्रवाह ग्राफ में "चपटा" होता है। नियंत्रण प्रवाह ग्राफ के नोड्स 3-पता निर्देश (RISC असेंबली भाषा के समान) हो सकते हैं, और नियंत्रण प्रवाह ग्राफ़ का आकार आमतौर पर पार्स ट्री के आकार में रैखिक होगा।

फिर अतिरेक उन्मूलन चरणों की एक श्रृंखला आम तौर पर लागू की जाती है (सामान्य सबप्रेसेशन उन्मूलन, लूप इनवेरिएंट कोड मोशन, निरंतर प्रसार, ...)। (इसे अक्सर "अनुकूलन" कहा जाता है, हालांकि परिणाम के बारे में शायद ही कुछ इष्टतम है, वास्तविक लक्ष्य कोड में सुधार करना है जितना संभव समय और अंतरिक्ष बाधाओं को हमने संकलक पर रखा है।) प्रत्येक अतिरेक उन्मूलन कदम। आमतौर पर नियंत्रण प्रवाह ग्राफ के बारे में कुछ तथ्यों के प्रमाण की आवश्यकता होती है। ये सबूत आमतौर पर डेटा प्रवाह विश्लेषण का उपयोग करके किए जाते हैं । अधिकांश डेटा-फ्लो विश्लेषणों को डिज़ाइन किया गया है ताकि वे में प्रवाह ग्राफ में परिवर्तित हो जाएँ जहाँ (मोटे तौर पर बोल रहा हो) लूप नेस्टिंग डेप्थ है और फ्लो ग्राफ़ के ऊपर से गुजरने में समय लगता हैO(d)dO(n)जहां 3-पता निर्देशों की संख्या है।n

अधिक परिष्कृत अनुकूलन के लिए आप अधिक परिष्कृत विश्लेषण करना चाह सकते हैं। इस बिंदु पर आप ट्रेडऑफ़ में दौड़ना शुरू करते हैं। आप अपने विश्लेषण एल्गोरिदम को से बहुत कम लेना चाहते हैंO(n2)पूरे कार्यक्रम के प्रवाह ग्राफ के आकार में समय, लेकिन इसका मतलब है कि आपको बिना जानकारी के (और प्रोग्राम में सुधार के लिए) बदलाव करने की आवश्यकता है जो साबित करने के लिए महंगा हो सकता है। इसका एक उत्कृष्ट उदाहरण उर्फ ​​विश्लेषण है, जहां कुछ जोड़ी स्मृति के लिए लिखता है आप यह साबित करना चाहेंगे कि दो लिखता कभी भी एक ही स्मृति स्थान को लक्षित नहीं कर सकता है। (आप यह देखने के लिए एक अन्य विश्लेषण कर सकते हैं कि क्या आप एक निर्देश को दूसरे से ऊपर ले जा सकते हैं।) लेकिन उपनामों के बारे में सटीक जानकारी प्राप्त करने के लिए आपको कार्यक्रम के माध्यम से हर संभव नियंत्रण पथ का विश्लेषण करने की आवश्यकता हो सकती है, जो शाखाओं की संख्या में घातांक है। कार्यक्रम में (और इस प्रकार नियंत्रण प्रवाह ग्राफ में नोड्स की संख्या में घातांक है।)

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

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


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

4
ओह, एक और बात: आज उपयोग में कुछ प्रकार के सिस्टम हैं जो सिद्धांत रूप में बहुत जटिल हैं। हिंडले-मिलनर प्रकार का निष्कर्ष DEXPTIME-complete के लिए जाना जाता है, और एमएल जैसी भाषाओं को इसे सही ढंग से लागू करना चाहिए। हालाँकि, रन टाइम व्यवहार में रैखिक है क्योंकि a) पैथोलॉजिकल मामले कभी भी वास्तविक दुनिया के कार्यक्रमों में नहीं आते हैं, और b) वास्तविक-दुनिया प्रोग्रामर टाइप एनोटेशन में डालते हैं, यदि केवल बेहतर त्रुटि संदेश प्राप्त करने के लिए।
छद्म नाम

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

@ बदनामी, तथ्य यह है कि कई बार संकलक को हल करने की समस्या को हल करना होगा (या बहुत बुरा एनपी कठिन समस्याओं का) एक कारण है कि मानकों को अपरिभाषित व्यवहार मानने में कंपाइलर लेखक को कोई रास्ता नहीं देता है (जैसे अनंत लूप और इस तरह) )।
वॉनब्रांड

15

दरअसल, संकलन के समय कुछ भाषाएं (जैसे सी ++, लिस्प और डी) ट्यूरिंग-पूर्ण होती हैं, इसलिए उनका संकलन सामान्य रूप से अनिर्दिष्ट है। C ++ के लिए, यह पुनरावर्ती टेम्पलेट तात्कालिकता के कारण है। लिस्प और डी के लिए, आप संकलन समय पर लगभग किसी भी कोड को निष्पादित कर सकते हैं, इसलिए यदि आप चाहें तो आप कंपाइलर को अनंत लूप में फेंक सकते हैं।


3
हास्केल (एक्सटेंशन के साथ) और स्काला के टाइप सिस्टम भी ट्यूरिंग-पूर्ण हैं, जिसका अर्थ है कि टाइप-चेकिंग में अनंत समय लग सकता है। स्काला में अब शीर्ष पर ट्यूरिंग-पूर्ण मैक्रो भी है।
जॉर्ग डब्ल्यू मित्तग

5

C # संकलक के साथ अपने वास्तविक अनुभव से, मैं कह सकता हूं कि कुछ कार्यक्रमों के लिए आउटपुट बाइनरी का आकार इनपुट स्रोत के आकार के संबंध में तेजी से बढ़ता है (यह वास्तव में C # युक्ति द्वारा आवश्यक है और इसे कम नहीं किया जा सकता है), इसलिए समय जटिलता कम से कम घातीय होना चाहिए।

C # में सामान्य अधिभार संकल्प कार्य को NP-hard (और वास्तविक कार्यान्वयन जटिलता कम से कम घातीय) के रूप में जाना जाता है।

C # स्रोतों में XML दस्तावेज़ीकरण टिप्पणियों की एक प्रक्रिया को संकलन-समय पर मनमाने ढंग से XPath 1.0 अभिव्यक्तियों का मूल्यांकन करने की आवश्यकता होती है, जो कि घातीय, AFAIK भी है।


क्या सी # बायनेरिज़ को इस तरह उड़ा देता है? मेरे लिए एक भाषा बग की तरह लगता है ...
vonbrand

1
यह तरीका है कि कैसे मेटाडेटा में सामान्य प्रकार एन्कोड किए जाते हैं। class X<A,B,C,D,E> { class Y : X<Y,Y,Y,Y,Y> { Y.Y.Y.Y.Y.Y.Y.Y.Y y; } }
व्लादिमीर रेशेतनिकोव

-2

इसे वास्तविक कोड बेस के साथ मापें, जैसे कि ओपन सोर्स प्रोजेक्ट्स का एक सेट। यदि आप परिणामों को (कोडसाइज़, फ़िनटाइम) के रूप में प्लॉट करते हैं, तो आप उन ग्राफ़ को प्लॉट कर सकते हैं। यदि आपका डेटा f (x) = y O (n) है, तो डेटा के बड़े होने के बाद g = f (x) / x को प्लॉट करना आपको एक सीधी रेखा प्रदान करना चाहिए।

प्लॉट f (x) / x, f (x) / lg (x), f (x) / (x * lg (x)), f (x) / (x * x) आदि ग्राफ या तो डाइव करेगा। शून्य से दूर, बिना बंधे वृद्धि, या बाहर समतल। यह विचार एक खाली डेटाबेस से प्रारंभ डालने के समय को मापने जैसी स्थितियों के लिए काम में आता है (यानी: लंबी अवधि के लिए 'प्रदर्शन रिसाव' देखने के लिए।)।


1
चलने के समय की अनुभवजन्य माप कम्प्यूटेशनल जटिलता स्थापित नहीं करती है। सबसे पहले, कम्प्यूटेशनल जटिलता सबसे आम तौर पर सबसे खराब चल रहे समय के संदर्भ में व्यक्त की जाती है। दूसरा, यहां तक ​​कि अगर आप किसी प्रकार के औसत मामले को मापना चाहते हैं, तो आपको यह स्थापित करने की आवश्यकता होगी कि आपके इनपुट उस अर्थ में "औसत" हैं।
डेविड रिचेर्बी

अच्छा यकीन है कि यह केवल एक अनुमान है। लेकिन बहुत सारे वास्तविक डेटा के साथ सरल अनुभवजन्य परीक्षण (जीआईटी रिपोस के एक समूह के लिए प्रत्येक प्रतिबद्ध) एक सावधान मॉडल को अच्छी तरह से हरा सकता है। किसी भी स्थिति में, यदि कोई फ़ंक्शन वास्तव में O (n ^ 3) है और आप f (n) / (n n n) प्लॉट करते हैं , तो आपको लगभग शून्य के ढलान के साथ एक शोर लाइन मिलनी चाहिए। यदि आपने O (n ^ 3) / (n * n) केवल प्लॉट किया है, तो आप देखेंगे कि यह रैखिक रूप से बढ़ेगा। यह वास्तव में स्पष्ट है कि अगर आप ओवरएस्टीमेट करते हैं और लाइन को जल्दी से शून्य पर गोता लगाते हैं।
रॉब

1
उदाहरण के लिए, क्विकॉर्ट अधिकांश इनपुट डेटा पर time में चलता है, लेकिन कुछ कार्यान्वयनों में सबसे खराब स्थिति में (आमतौर पर पहले से छंटे हुए इनपुट पर चल रहा है। हालाँकि, यदि आप बस रनिंग टाइम को प्लॉट करते हैं, तो आप वाले मामलों की तुलना में मामलों में चलने की अधिक संभावना रखते हैं। Θ(nlogn)Θ(n2)Θ(nlogn)Θ(n2)
डेविड रिचरबी

मैं मानता हूं कि आपको यह जानने की जरूरत है कि क्या आप किसी ऐसे हमलावर से सेवा से वंचित होने के बारे में चिंतित हैं जो आपको खराब इनपुट दे रहा है, कुछ वास्तविक समय में महत्वपूर्ण इनपुट पार्सिंग कर रहा है। वास्तविक कार्य जो संकलन समय को मापता है, बहुत शोर करने वाला है, और जिस मामले की हम परवाह करते हैं, वह वास्तविक कोड विकृति में होने वाला है।
रॉब

1
नहीं। प्रश्न समस्या की समय जटिलता के बारे में पूछता है। आमतौर पर इसकी व्याख्या सबसे खराब स्थिति में चलने वाले समय के रूप में की जाती है, जो रिपॉजिटरी में कोड पर सशर्त रूप से चलने का समय नहीं है। आपके द्वारा प्रस्तावित किए जाने वाले परीक्षण इस बात पर एक उचित नियंत्रण देते हैं कि आप कंपाइलर को दिए गए कोड पर कितनी देर तक चलने की उम्मीद कर सकते हैं, जो एक अच्छी और उपयोगी बात है। लेकिन वे आपको समस्या की कम्प्यूटेशनल जटिलता के बारे में लगभग कुछ भी नहीं बताते हैं।
डेविड रिचरबी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.