क्या कोई मुझे सरल शब्दों में समझा सकता है कि एक निर्देशित एसाइक्लिक ग्राफ क्या है? मैंने विकिपीडिया पर देखा है, लेकिन यह वास्तव में मुझे प्रोग्रामिंग में इसका उपयोग नहीं दिखता है।
क्या कोई मुझे सरल शब्दों में समझा सकता है कि एक निर्देशित एसाइक्लिक ग्राफ क्या है? मैंने विकिपीडिया पर देखा है, लेकिन यह वास्तव में मुझे प्रोग्रामिंग में इसका उपयोग नहीं दिखता है।
जवाबों:
ग्राफ = संरचना जिसमें नोड्स होते हैं, जो किनारों के साथ एक दूसरे से जुड़े होते हैं
निर्देशित = नोड्स (किनारों) के बीच के कनेक्शन की एक दिशा है: ए -> बी, बी -> ए के समान नहीं है
एसाइक्लिक = "नॉन-सर्कुलर" = किनारों से अनुसरण करके नोड से नोड की ओर बढ़ते हुए, आप दूसरी बार उसी नोड का सामना नहीं करेंगे।
एक निर्देशित चक्रीय ग्राफ का एक अच्छा उदाहरण एक पेड़ है। हालांकि, ध्यान दें कि सभी निर्देशित एसाइक्लिक ग्राफ पेड़ नहीं हैं।
मुझे DAG (डायरेक्टेड एसाइक्लिक ग्राफ) के अर्थ को दर्शाने वाले बहुत से उत्तर दिखाई देते हैं लेकिन इसके अनुप्रयोगों पर कोई उत्तर नहीं मिलता है। यहाँ एक बहुत ही सरल है -
पूर्व-अपेक्षित ग्राफ़ - एक इंजीनियरिंग कोर्स के दौरान प्रत्येक छात्र को उन विषयों को चुनने का काम करना पड़ता है जो पूर्व-अपेक्षाओं जैसी आवश्यकताओं का पालन करते हैं। अब यह स्पष्ट है कि आप आर्टिफिशियल इंटेलिजेंस [बी] पर एक क्लास नहीं ले सकते हैं, बिना पूर्व-निर्धारित पाठ्यक्रम के एलगोरिदम [ए] पर। इसलिए बी ए पर निर्भर करता है या बेहतर शब्दों में ए की बी के लिए निर्देशित एक बढ़त है। इसलिए नोड बी तक पहुंचने के लिए आपको नोड ए पर जाना होगा। जल्द ही यह स्पष्ट होगा कि सभी विषयों को अपनी पूर्व आवश्यकता के साथ एक ग्राफ में जोड़ दिया जाए। , यह एक डायरेक्टेड एसाइक्लिक ग्राफ बन जाएगा।
यदि कोई चक्र होता तो आप कभी भी एक कोर्स पूरा नहीं करते: पी
विश्वविद्यालय में एक सॉफ्टवेयर प्रणाली जो छात्रों को पाठ्यक्रमों के लिए पंजीकरण करने की अनुमति देती है, वे विषयों को मॉडल बना सकते हैं ताकि यह सुनिश्चित हो सके कि छात्र ने वर्तमान पाठ्यक्रम के लिए पंजीकरण करने से पहले एक पूर्व-आवश्यक पाठ्यक्रम लिया है।
मेरे प्रोफेसर ने यह सादृश्य दिया और इससे मुझे कुछ जटिल अवधारणा का उपयोग करने के बजाय डीएजी को समझने में मदद मिली!
एक और वास्तविक समय उदाहरण -> वास्तविक समय उदाहरण है कि कैसे DAG का संस्करण प्रणाली में उपयोग किया जा सकता है
प्रोग्रामिंग में एक निर्देशित चक्रीय ग्राफ के उदाहरण उपयोग में कम या ज्यादा कुछ भी शामिल है जो कनेक्टिविटी और कारण का प्रतिनिधित्व करता है।
उदाहरण के लिए, मान लीजिए कि आपके पास एक संगणना पाइपलाइन है जो रनटाइम पर कॉन्फ़िगर करने योग्य है। इसके एक उदाहरण के रूप में, मान लीजिए कि A, B, C, D, E, F, और G एक दूसरे पर निर्भर हैं: A, C पर निर्भर करता है, C, E और F पर निर्भर करता है, B, D और E पर निर्भर करता है, और D पर निर्भर करता है F. यह एक DAG के रूप में दर्शाया जा सकता है। एक बार जब आपके पास स्मृति में DAG हो, तो आप इसके लिए एल्गोरिदम लिख सकते हैं:
कई अन्य बातों के अलावा।
अनुप्रयोग प्रोग्रामिंग के दायरे के बाहर, कोई भी सभ्य स्वचालित बिल्ड टूल (मेक, एंट, स्कैन्स, आदि) प्रोग्राम के घटकों के उचित निर्माण क्रम को सुनिश्चित करने के लिए डीएजी का उपयोग करेगा।
कई उत्तरों ने रेखांकन (जैसे नेटवर्क मॉडलिंग) के उपयोग के उदाहरण दिए हैं और आपने पूछा है "प्रोग्रामिंग के साथ इसका क्या करना है?"।
उस उप-प्रश्न का उत्तर यह है कि प्रोग्रामिंग से इसका कोई लेना-देना नहीं है। इसका समाधान समस्या से करना है।
जैसे लिंक्ड-लिस्ट कुछ विशेष वर्गों की समस्याओं के लिए उपयोग की जाने वाली डेटा संरचनाएँ हैं, ग्राफ़ कुछ रिश्तों का प्रतिनिधित्व करने के लिए उपयोगी हैं। लिंक की गई सूची, पेड़, रेखांकन, और अन्य सार संरचनाएं केवल प्रोग्रामिंग के लिए एक कनेक्शन है कि आप उन्हें कोड में लागू कर सकते हैं। वे अमूर्तता के उच्च स्तर पर मौजूद हैं। यह प्रोग्रामिंग के बारे में नहीं है, यह समस्याओं के समाधान में डेटा संरचनाओं को लागू करने के बारे में है।
डायरेक्टेड एसाइक्लिक ग्राफ (डीएजी) में निम्नलिखित गुण होते हैं जो उन्हें अन्य ग्राफ से अलग करते हैं:
ठीक है, मैं अभी एक उपयोग के बारे में सोच सकता हूं - डीएजी ( वेट-फॉर-ग्राफ के रूप में जाना जाता है - अधिक तकनीकी विवरण ) गतिरोधों का पता लगाने में आसान हैं क्योंकि वे प्रक्रियाओं और संसाधनों के एक सेट के बीच निर्भरता का वर्णन करते हैं (दोनों डीएजी में नोड हैं) । गतिरोध तब होता है जब एक चक्र का पता लगाया जाता है।
मुझे लगता है कि आप पहले से ही बुनियादी ग्राफ शब्दावली जानते हैं; अन्यथा आपको ग्राफ सिद्धांत पर लेख से शुरू करना चाहिए ।
निर्देशित इस तथ्य को संदर्भित करता है कि किनारों (कनेक्शन) में दिशाएं हैं। आरेख में, इन दिशाओं को तीरों द्वारा दिखाया गया है। इसके विपरीत एक अप्रत्यक्ष ग्राफ है, जिसके किनारे दिशाओं को निर्दिष्ट नहीं करते हैं।
चक्रीय का मतलब है कि, यदि आप किसी भी मनमाने ढंग से नोड X से शुरू करते हैं और सभी संभावित किनारों से गुजरते हैं, तो आप पहले से ही उपयोग किए गए किनारे पर वापस जाने के बिना X पर नहीं लौट सकते।
कई अनुप्रयोग:
DAG एक ऐसा ग्राफ़ है जहाँ सब कुछ एक ही दिशा में बहता है और कोई भी नोड अपने आप को वापस संदर्भित नहीं कर सकता है।
पूर्वजों के पेड़ों के बारे में सोचो; वे वास्तव में डीएजी हैं।
सभी डीएजी हैं
DAG पेड़ों से अलग हैं। पेड़ जैसी संरचना में, हर दो नोड्स के बीच एक अनूठा पथ होना चाहिए। DAG में, एक नोड में दो मूल नोड हो सकते हैं।
यहां डीएजी के बारे में एक अच्छा लेख है । मुझे आशा है कि वह मदद करेंगे।
सभी प्रकार के ग्राफ़, विभिन्न वास्तविक दुनिया के रिश्तों को मॉडल करने के लिए प्रोग्रामिंग में उपयोग किए जाते हैं। उदाहरण के लिए, एक सामाजिक नेटवर्क को अक्सर ग्राफ (इस मामले में चक्रीय) द्वारा दर्शाया जाता है। इसी तरह, नेटवर्क टोपोलॉजी, परिवार के पेड़, एयरलाइन मार्ग, ...
एक स्रोत कोड या यहां तक कि तीन पते (TAC) कोड के नजरिए से आप इस पृष्ठ पर वास्तव में आसानी से समस्या की कल्पना कर सकते हैं ...
http://cgm.cs.mcgill.ca/~hagha/topic30/topic30.html#Exptree
यदि आप एक्सप्रेशन ट्री सेक्शन में जाते हैं, और फिर थोड़ा नीचे पेज करते हैं, तो यह ट्री का "टोपोलॉजिकल सॉर्टिंग" और अभिव्यक्ति का मूल्यांकन करने के लिए एल्गोरिदम को दर्शाता है।
तो उस स्थिति में आप अभिव्यक्ति का मूल्यांकन करने के लिए डीएजी का उपयोग कर सकते हैं, जो मूल्यांकन के बाद से सामान्य रूप से व्याख्यायित है और इस तरह के डीएजी मूल्यांकनकर्ता का उपयोग करने से प्रिंसिपल में सरल इंट्रेप्रेटर बन जाएंगे क्योंकि यह एक स्टैक को धक्का और पॉपिंग नहीं कर रहा है और इसलिए भी कि यह समाप्त हो रहा है। सामान्य उप-अभिव्यक्तियाँ।
गैर-प्राचीन मिस्र (यानी अंग्रेजी) में DAG की गणना करने के लिए बुनियादी एल्गोरिदम यह है:
1) अपने डीएजी ऑब्जेक्ट को ऐसा बनाएं
आपको एक लाइव सूची की आवश्यकता है और यह सूची सभी वर्तमान लाइव DAG नोड्स और DAG उप-अभिव्यक्तियों को रखती है। DAG उप अभिव्यक्ति एक DAG नोड है, या आप इसे आंतरिक नोड भी कह सकते हैं। लाइव डीएजी नोड द्वारा मेरा मतलब है कि यदि आप एक चर एक्स को असाइन करते हैं तो यह लाइव हो जाता है। एक सामान्य उप-अभिव्यक्ति जो तब X का उपयोग करती है वह उदाहरण का उपयोग करती है। यदि X को फिर से सौंपा गया है, तो एक नया DAG NODE बनाया गया है और लाइव सूची में जोड़ा गया है और पुरानी X को हटा दिया गया है, इसलिए अगली उप-अभिव्यक्ति जो X का उपयोग करती है, नए उदाहरण को संदर्भित करेगी और इस प्रकार उप-अभिव्यक्तियों के साथ संघर्ष नहीं करेगी जो केवल एक ही चर नाम का उपयोग करें।
एक बार जब आप एक चर X को असाइन करते हैं, तो सह-संयोग से सभी DAG उप-अभिव्यक्ति नोड्स जो असाइनमेंट के बिंदु पर रहते हैं, लाइव नहीं होते हैं, क्योंकि नया असाइनमेंट पुराने मूल्य का उपयोग करके उप अभिव्यक्तियों के अर्थ को अमान्य करता है।
class Dag {
TList LiveList;
DagNode Root;
}
// In your DagNode you need a way to refer to the original things that
// the DAG is computed from. In this case I just assume an integer index
// into the list of variables and also an integer index for the opertor for
// Nodes that refer to operators. Obviously you can create sub-classes for
// different kinds of Dag Nodes.
class DagNode {
int Variable;
int Operator;// You can also use a class
DagNode Left;
DagNode Right;
DagNodeList Parents;
}
तो आप क्या करते हैं अपने पेड़ से अपने कोड में चलते हैं, जैसे कि उदाहरण के लिए स्रोत कोड में अभिव्यक्ति का एक पेड़। उदाहरण के लिए मौजूदा नोड XNodes को कॉल करें।
इसलिए प्रत्येक XNode के लिए आपको यह तय करने की आवश्यकता है कि इसे DAG में कैसे जोड़ा जाए, और इस बात की संभावना है कि यह पहले से ही DAG में है।
यह बहुत ही सरल छद्म कोड है। संकलन का इरादा नहीं है।
DagNode XNode::GetDagNode(Dag dag) {
if (XNode.IsAssignment) {
// The assignment is a special case. A common sub expression is not
// formed by the assignment since it creates a new value.
// Evaluate the right hand side like normal
XNode.RightXNode.GetDagNode();
// And now take the variable being assigned to out of the current live list
dag.RemoveDagNodeForVariable(XNode.VariableBeingAssigned);
// Also remove all DAG sub expressions using the variable - since the new value
// makes them redundant
dag.RemoveDagExpressionsUsingVariable(XNode.VariableBeingAssigned);
// Then make a new variable in the live list in the dag, so that references to
// the variable later on will see the new dag node instead.
dag.AddDagNodeForVariable(XNode.VariableBeingAssigned);
}
else if (XNode.IsVariable) {
// A variable node has no child nodes, so you can just proces it directly
DagNode n = dag.GetDagNodeForVariable(XNode.Variable));
if (n) XNode.DagNode = n;
else {
XNode.DagNode = dag.CreateDagNodeForVariable(XNode.Variable);
}
return XNode.DagNode;
}
else if (XNode.IsOperator) {
DagNode leftDagNode = XNode.LeftXNode.GetDagNode(dag);
DagNode rightDagNode = XNode.RightXNode.GetDagNode(dag);
// Here you can observe how supplying the operator id and both operands that it
// looks in the Dags live list to check if this expression is already there. If
// it is then it returns it and that is how a common sub-expression is formed.
// This is called an internal node.
XNode.DagNode =
dag.GetOrCreateDagNodeForOperator(XNode.Operator,leftDagNode,RightDagNode) );
return XNode.DagNode;
}
}
तो यह देखने का एक तरीका है। पेड़ का एक मूल चलना और इसमें जाते ही डैग नोड्स को जोड़ना और संदर्भित करना। डाग की जड़ जो भी है DagNode पेड़ की जड़ उदाहरण के लिए वापस आती है।
स्पष्ट रूप से उदाहरण प्रक्रिया को छोटे भागों में तोड़ा जा सकता है या आभासी कार्यों के साथ उप-वर्ग के रूप में बनाया जा सकता है।
दाग को छांटने के लिए, आप प्रत्येक दाईं ओर से दाएं तरफ जाते हैं। दूसरे शब्दों में DagNodes बाएं हाथ के किनारे, और फिर दाहिने हाथ की ओर किनारे का पालन करें। संख्याओं को रिवर्स में सौंपा गया है। दूसरे शब्दों में, जब आप बिना बच्चों के डागनोड पर पहुंचते हैं, तो असाइन करें कि वर्तमान छँटाई संख्या को नोड करें और छँटाई संख्या बढ़ाएँ, ताकि पुनरावृत्ति की संख्या बढ़ती क्रम में असाइन हो जाए।
यह उदाहरण केवल शून्य या दो बच्चों वाले पेड़ों को संभालता है। स्पष्ट रूप से कुछ पेड़ों में दो से अधिक बच्चों के साथ नोड्स हैं इसलिए तर्क अभी भी समान है। बाएं और दाएं गणना करने के बजाय, बाएं से दाएं आदि की गणना करें ...
// Most basic DAG topological ordering example.
void DagNode::OrderDAG(int* counter) {
if (this->AlreadyCounted) return;
// Count from left to right
for x = 0 to this->Children.Count-1
this->Children[x].OrderDag(counter)
// And finally number the DAG Node here after all
// the children have been numbered
this->DAGOrder = *counter;
// Increment the counter so the caller gets a higher number
*counter = *counter + 1;
// Mark as processed so will count again
this->AlreadyCounted = TRUE;
}
यदि आप जानते हैं कि प्रोग्रामिंग में पेड़ क्या हैं, तो प्रोग्रामिंग में डीएजी समान हैं लेकिन वे एक नोड को एक से अधिक माता-पिता होने की अनुमति देते हैं। यह तब आसान हो सकता है जब आप एक नोड को केवल एक ही माता-पिता से अधिक के तहत clumped होने देना चाहते हैं, फिर भी चक्रों के साथ एक सामान्य ग्राफ़ की नॉटेड गड़बड़ की समस्या नहीं है। आप अभी भी एक डीएजी को आसानी से नेविगेट कर सकते हैं, लेकिन रूट पर वापस आने के कई तरीके हैं (क्योंकि एक से अधिक माता-पिता हो सकते हैं)। एक एकल डीएजी की कई जड़ें हो सकती हैं, लेकिन व्यवहार में एक पेड़ की तरह सिर्फ एक जड़ के साथ रहना बेहतर हो सकता है। यदि आप OOP में एकल बनाम एकाधिक वंशानुक्रम को समझते हैं, तो आप वृक्ष बनाम DAG जानते हैं। इसका उत्तर मैंने पहले ही यहाँ दे दिया है ।
यह नाम आपको सबसे अधिक बताता है कि आपको इसकी परिभाषा के बारे में क्या पता होना चाहिए: यह एक ऐसा ग्राफ़ है, जिसमें हर किनारा केवल एक दिशा में बहता है और एक बार जब आप एक किनारे पर क्रॉल करते हैं तो आपका रास्ता कभी भी आपके द्वारा छोड़े गए शीर्ष पर वापस नहीं आएगा।
मैं सभी उपयोगों से बात नहीं कर सकता (विकिपीडिया वहां मदद करता है), लेकिन मेरे लिए संसाधनों के बीच निर्भरता का निर्धारण करते समय डीएजी बेहद उपयोगी हैं। उदाहरण के लिए मेरा गेम इंजन एक ही डीएजी के रूप में सभी लोड किए गए संसाधनों (सामग्री, बनावट, शेड्स, प्लेनटेक्स्ट, पार्स जूसन आदि) का प्रतिनिधित्व करता है। उदाहरण:
एक सामग्री एन जीएल कार्यक्रम है, कि प्रत्येक को दो शेड की आवश्यकता होती है, और प्रत्येक शेडर को एक सादा शेडर स्रोत की आवश्यकता होती है। इन संसाधनों को एक DAG के रूप में प्रस्तुत करके, मैं डुप्लिकेट लोड से बचने के लिए मौजूदा संसाधनों के ग्राफ को आसानी से क्वेरी कर सकता हूं। मान लें कि आप एक ही सोर्स कोड के साथ कई सामग्री का उपयोग करना चाहते हैं। स्रोत को फिर से लोड करना और हर उपयोग के लिए शेड को फिर से जोड़ना बेकार है जब आप मौजूदा संसाधन के लिए एक नया किनारा स्थापित कर सकते हैं। इस तरह आप ग्राफ़ का उपयोग यह निर्धारित करने के लिए भी कर सकते हैं कि कुछ भी संसाधन पर निर्भर करता है, और यदि नहीं, तो इसे हटा दें और इसकी मेमोरी को मुक्त करें, वास्तव में यह बहुत अधिक स्वचालित रूप से होता है।
विस्तार से, DAG डेटा प्रोसेसिंग पाइपलाइनों को व्यक्त करने के लिए उपयोगी होते हैं। चक्रीय प्रकृति का मतलब है कि आप संदर्भ प्रसंस्करण कोड को सुरक्षित रूप से लिख सकते हैं जो एक ही शीर्ष पर पुन: एनकाउंटर किए बिना एक शीर्ष से किनारों को नीचे का अनुसरण कर सकते हैं। वीवीवीवी , मैक्स एमएसपी या ऑटोडेस्क माया के नोड-आधारित इंटरफेस जैसे दृश्य प्रोग्रामिंग भाषा सभी डीएजी पर निर्भर हैं।
जब आप प्रतिनिधित्व करना चाहते हैं तो एक निर्देशित एसाइक्लिक ग्राफ उपयोगी है ... एक निर्देशित एसाइक्लिक ग्राफ! विहित उदाहरण परिवार का पेड़ या वंशावली है।