संख्यात्मक एल्गोरिदम को एन्कैप करने के लिए कक्षाओं का उपयोग करने के लिए निहित लाभ और कमियां क्या हैं?


13

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

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

हालांकि पारंपरिक दृष्टिकोण में केवल एक फ़ंक्शन है जो कई अन्य फ़ंक्शन को कॉल करता है, जिस तरह से प्रासंगिक तर्क पारित करते हैं, ओओपी एक अलग दृष्टिकोण प्रदान करता है, जिसमें एल्गोरिदम को कक्षाओं के रूप में समझाया जा सकता है। स्पष्टता के लिए, एक वर्ग में एक एल्गोरिथ्म को एनकैप्सुलेट करने से मेरा मतलब है कि एक वर्ग बनाना जिसमें एल्गोरिथ्म इनपुट को कक्षा निर्माता में दर्ज किया जाता है, और फिर एक सार्वजनिक विधि को वास्तव में एल्गोरिथ्म को लागू करने के लिए कहा जाता है। C ++ pededocode में मल्टीग्रिड का ऐसा कार्यान्वयन जैसा लग सकता है:

class multigrid {
    private:
        x_, b_
        [grid structure]

        restrict(...)
        interpolate(...)
        relax(...)
    public:
        multigrid(x,b) : x_(x), b_(b) { }
        run()
}

multigrid::run() {
     [call restrict, interpolate, relax, etc.]
}

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


2
यह हमेशा एक बुरा संकेत है जब आपकी कक्षा का नाम संज्ञा के बजाय विशेषण होता है।
डेविड केचेसन

3
एक वर्ग जटिलता के प्रबंधन के लिए कार्यों के आयोजन के लिए एक सांविधिक नाम स्थान के रूप में कार्य कर सकता है, लेकिन भाषाओं में जटिलता का प्रबंधन करने के अन्य तरीके हैं जो कक्षाएं प्रदान करते हैं। (सी ++ में नाम स्थान और पायथन में मॉड्यूल दिमाग में आते हैं।)
ज्योफ ऑक्सबेरी

@GeoffOxberry मैं यह नहीं बोल सकता कि क्या यह अच्छा या बुरा उपयोग है - यही कारण है कि मैं पहली जगह में पूछ रहा हूं - लेकिन नाम स्थान या मॉड्यूल के विपरीत कक्षाएं, "अस्थायी राज्य" का प्रबंधन भी कर सकती हैं, जैसे ग्रिड पदानुक्रम मल्टीग्रिड में, जो एल्गोरिथ्म के पूरा होने पर छोड़ दिया जाता है।
बेन

जवाबों:


13

15 वर्षों के लिए संख्यात्मक सॉफ्टवेयर करने के बाद, मैं निम्नलिखित को स्पष्ट रूप से बता सकता हूं:

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

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

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

केवल इन तीन बिंदुओं से, यह स्पष्ट होना चाहिए कि ऑब्जेक्ट ओरिएंटेड प्रोग्रामिंग सबसे निश्चित रूप से संख्यात्मक कोड के साथ भी लागू होती है, और यह कि इस शैली के कई लाभों को अनदेखा करना मूर्खतापूर्ण होगा। यह सच हो सकता है कि BLAS / LAPACK इस प्रतिमान का उपयोग नहीं करते हैं (और MATLAB द्वारा उजागर सामान्य इंटरफ़ेस या तो नहीं करता है), लेकिन मैं इस अनुमान का उपक्रम करूंगा कि पिछले 10 वर्षों में लिखा गया हर सफल संख्यात्मक सॉफ्टवेयर वास्तव में है, वस्तु के उन्मुख।


16

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

इंटरफेस अच्छे हैं। एक कार्यान्वयन के आधार पर बुरा है। चाहे आप इसे C ++ क्लासेस, C ऑब्जेक्ट्स, हास्केल टाइपकालेज़, या कुछ अन्य भाषा फीचर का उपयोग करके प्राप्त कर रहे हैं। एक इंटरफ़ेस की क्षमता, मजबूती, और व्यापकता वैज्ञानिक पुस्तकालयों में क्या मायने रखती है।


8

कक्षाओं का उपयोग केवल तभी किया जाना चाहिए जब कोड की संरचना पदानुक्रमित हो। चूंकि आप अल्गोरिदम का उल्लेख कर रहे हैं, उनकी प्राकृतिक संरचना एक प्रवाह चार्ट है, न कि वस्तुओं का एक पदानुक्रम।

OpenFOAM के मामले में, एल्गोरिथम का हिस्सा सामान्य ऑपरेटरों (डिव, ग्रेड, कर्ल, आदि) के संदर्भ में लागू किया जाता है जो मूल रूप से विभिन्न प्रकार के संख्यात्मक योजनाओं का उपयोग करके विभिन्न प्रकार के टेनर्स पर काम कर रहे हैं। कोड का यह हिस्सा मूल रूप से कक्षाओं पर काम करने वाले बहुत सारे सामान्य एल्गोरिदम से बनाया गया है। यह क्लाइंट को कुछ लिखने की अनुमति देता है:

solve(ddt(U) + div(phi, U)  == rho*g + ...);

ट्रांसपोर्ट मॉडल, टर्बुलेंस मॉडल, डिफरेंसेसिंग स्कीम, ग्रेडिएंट स्कीम, बाउंड्री कंडीशन आदि जैसे पदानुक्रम C ++ क्लासेस (फिर से, सामान्य टेंसर मात्रा पर) के संदर्भ में लागू किए जाते हैं।

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

पदानुक्रमित संरचना ==> कक्षाएं

प्रक्रियात्मक, प्रवाह चार्ट ==> एल्गोरिदम


5

यहां तक ​​कि अगर यह एक पुराना सवाल है, तो मुझे लगता है कि यह जूलिया के विशेष समाधान का उल्लेख करने योग्य है । यह भाषा क्या करती है "वर्ग-कम OOP": मुख्य निर्माण प्रकार हैं, अर्थात, समग्र डेटा ऑब्जेक्ट structसी में s करने के लिए समान है, जिस पर एक विरासत संबंध परिभाषित किया गया है। प्रकारों में "सदस्य फ़ंक्शन" नहीं होते हैं, लेकिन प्रत्येक फ़ंक्शन में एक प्रकार का हस्ताक्षर होता है और उपप्रकार स्वीकार करता है। उदाहरण के लिए, आप एक सार हो सकता था Matrixप्रकार और उप-प्रकार DenseMatrix, SparseMatrixऔर एक सामान्य विधि है do_something(a::Matrix, b::Matrix)विशेषज्ञता के साथ do_something(a::SparseMatrix, b::SparseMatrix)। कॉल करने के लिए सबसे उपयुक्त संस्करण का चयन करने के लिए एकाधिक प्रेषण का उपयोग किया जाता है।

यह दृष्टिकोण क्लास-आधारित ओओपी से अधिक शक्तिशाली है, जो केवल पहले तर्क पर विरासत के आधार पर प्रेषण के बराबर है, यदि आप इस कन्वेंशन को अपनाते हैं कि "एक विधि thisइसके पहले पैरामीटर के रूप में एक फ़ंक्शन है " (आम उदाहरण पायथन में)। कई प्रेषण के कुछ रूप में, सी + + का अनुकरण किया जा सकता है, लेकिन काफी विरोधाभासों के साथ ।

मुख्य अंतर यह है कि विधियां कक्षाओं से संबंधित नहीं हैं, लेकिन वे अलग-अलग संस्थाओं के रूप में मौजूद हैं और विरासत सभी मापदंडों पर हो सकती है।

कुछ संदर्भ:

http://docs.julialang.org/en/release-0.4/manual/methods/

http://assoc.tumblr.com/post/71454527084/cool-things-you-can-do-in-julia

https://thenewphalls.wordpress.com/2014/03/06/understanding-object-oriented-programming-in-julia-inheritance-part-2/


1

OO दृष्टिकोण के दो फायदे हो सकते हैं:

  • βαcalculate_alpha()αcalculate_beta()calculate_alpha()α

  • calculate_f()f(x,y,z)zset_z()zcalculate_f()z

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