विकिपीडिया ए * पाथफाइंडिंग एल्गोरिथ्म में बहुत समय लगता है


9

मैंने C # में सफलतापूर्वक A * पाथफ़ाइंग लागू किया है, लेकिन यह बहुत धीमा है, और मुझे समझ नहीं आता कि क्यों। मैंने ओपनऑनोड्स सूची को क्रमबद्ध नहीं करने की भी कोशिश की थी लेकिन यह अभी भी वैसा ही है।

नक्शा 80x80 है, और 10-11 नोड्स हैं।

मैं यहाँ से विकिपीडिया पर छद्मकोड ले गया

और यह मेरा कार्यान्वयन है:

 public static List<PGNode> Pathfind(PGMap mMap, PGNode mStart, PGNode mEnd)
    {
        mMap.ClearNodes();

        mMap.GetTile(mStart.X, mStart.Y).Value = 0;
        mMap.GetTile(mEnd.X, mEnd.Y).Value = 0;

        List<PGNode> openNodes = new List<PGNode>();
        List<PGNode> closedNodes = new List<PGNode>();
        List<PGNode> solutionNodes = new List<PGNode>();

        mStart.G = 0;
        mStart.H = GetManhattanHeuristic(mStart, mEnd);

        solutionNodes.Add(mStart);
        solutionNodes.Add(mEnd);

        openNodes.Add(mStart); // 1) Add the starting square (or node) to the open list.

        while (openNodes.Count > 0) // 2) Repeat the following:
        {
            openNodes.Sort((p1, p2) => p1.F.CompareTo(p2.F));

            PGNode current = openNodes[0]; // a) We refer to this as the current square.)

            if (current == mEnd)
            {
                while (current != null)
                {
                    solutionNodes.Add(current);
                    current = current.Parent;
                }

                return solutionNodes;
            }

            openNodes.Remove(current);
            closedNodes.Add(current); // b) Switch it to the closed list.

            List<PGNode> neighborNodes = current.GetNeighborNodes();
            double cost = 0;
            bool isCostBetter = false;

            for (int i = 0; i < neighborNodes.Count; i++)
            {
                PGNode neighbor = neighborNodes[i];
                cost = current.G + 10;
                isCostBetter = false;

                if (neighbor.Passable == false || closedNodes.Contains(neighbor))
                    continue; // If it is not walkable or if it is on the closed list, ignore it.

                if (openNodes.Contains(neighbor) == false)
                {
                    openNodes.Add(neighbor); // If it isn’t on the open list, add it to the open list.
                    isCostBetter = true;
                }
                else if (cost < neighbor.G)
                {
                    isCostBetter = true;
                }

                if (isCostBetter)
                {
                    neighbor.Parent = current; //  Make the current square the parent of this square. 
                    neighbor.G = cost;
                    neighbor.H = GetManhattanHeuristic(current, neighbor);
                }
            }
        }

        return null;
    }

यहाँ वह प्रयोगवादी है जिसका मैं उपयोग कर रहा हूँ:

    private static double GetManhattanHeuristic(PGNode mStart, PGNode mEnd)
    {
        return Math.Abs(mStart.X - mEnd.X) + Math.Abs(mStart.Y - mEnd.Y);
    }

मैं क्या गलत कर रहा हूं? यह एक पूरे दिन है मैं एक ही कोड को देखता रहता हूं।


2
हेयुरिस्टिक के बिना इसे (आमतौर पर) अधिक समय लेना चाहिए क्योंकि आप अंत तक अधिक नोड्स से गुजरते हैं। इसके अलावा, एक सॉर्ट की गई सूची का उपयोग करने का प्रयास करें जो क्रमबद्ध रहता है (अधिमानतः एक सॉर्ट किया गया सेट, इस तरह से आपको यह जांचना होगा कि क्या सूची में कोई आइटम मौजूद है जिसे आप इसे जोड़ सकते हैं)
Elva

जवाबों:


10

मैं तीन चीजें देखता हूं, एक गलत, दो संदिग्ध।

1) आप हर पुनरावृत्ति पर छंटनी कर रहे हैं। मत करो। या तो एक प्राथमिकता कतार का उपयोग करें, या बहुत कम से कम न्यूनतम खोजने के लिए एक रैखिक खोज करें। आपको वास्तव में पूरी सूची को हर समय क्रमबद्ध करने की आवश्यकता नहीं है!

2) openNodes.Contains () शायद धीमा है (सी # सूची की बारीकियों के बारे में निश्चित नहीं है, लेकिन मुझे यकीन है कि यह एक रैखिक खोज करता है)। आप प्रत्येक नोड में एक ध्वज जोड़ सकते हैं और इसे O (1) में कर सकते हैं।

3) GetNeighborNodes () धीमा हो सकता है।


2
2) हाँ, सम्‍मिलित () काफी धीमा होगा। सूचियों में अपने सभी नोड्स को संग्रहीत करने के बजाय, एक शब्दकोश <int, PGNode> का उपयोग करें। तब आपको O (1) लुकअप समय मिलता है और फिर भी वह सूची को पुन: व्यवस्थित कर सकता है। यदि नोड में एक आईडी फ़ील्ड है, तो कुंजी के लिए उसका उपयोग करें, अन्यथा PGNode.GetHashCode () काम करेगा।
०१

2
@ क्षमता: शब्दकोश नहीं होगा <PGNode, PGNode> बेहतर होगा? दो वस्तुओं का समान हैश कोड हो सकता है लेकिन समान नहीं। "नतीजतन, इस पद्धति का डिफ़ॉल्ट कार्यान्वयन हैशिंग उद्देश्यों के लिए एक अद्वितीय वस्तु पहचानकर्ता के रूप में उपयोग नहीं किया जाना चाहिए।" msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx - .NET 3.5 HashSet प्रदान करता है, जो बेहतर है - msdn.microsoft.com/en-us/library/bbb9438.aspx

अच्छी बात, हशसेट के बारे में भूल गए।
२३:३४ पर लेन्सिटी

9

पहले से बने बिंदु के अलावा, आपको प्राथमिकता के ढेर का उपयोग करना चाहिए, आपने हेयुरिस्ट को गलत समझा है। आपके पास

अगर (isCostBetter)
{
    ...
    पड़ोसी। = गेटमैनहट्टनहेयरस्टिक (वर्तमान, पड़ोसी);
}
लेकिन अनुमान को गंतव्य की दूरी के लिए अनुमान माना जाता है। आपको इसे एक बार सेट करना चाहिए, जब आप पहली बार पड़ोसी को जोड़ते हैं:
अगर (OpenNodes.Contains (पड़ोसी) == गलत)
{
    पड़ोसी। = गेटहार्टिस्टिक (पड़ोसी, एमईएन);
    ...
}

और एक और मामूली बिंदु के रूप में, आप आवेगी नोड्स को छानकर ए * को सरल बना सकते हैं GetNeighbourNodes()


+1, मैंने एल्गोरिथम जटिलता पर ध्यान केंद्रित किया और पूरी तरह से गलत के गलत उपयोग से चूक गया!
ggambett

4

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


3

यह स्पष्ट नहीं है कि जब आप विभिन्न नोड्स के एफ की तुलना करते हैं तो आप क्या तुलना कर रहे हैं। क्या F को G + H के रूप में परिभाषित किया गया है? यह होना चाहिए। (साइड-रैंट: यह एक उदाहरण है कि एक समान पहुंच सिद्धांत क्यों बकवास है।)

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

(आपको O (n) सम्मिलन + प्रकार मिल सकता है यदि C # में एक अच्छा छँटाई एल्गोरिथ्म है। यह अभी भी बहुत अधिक है। एक वास्तविक प्राथमिकता कतार का उपयोग करें।)


2

http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html

  • एक चरम पर, यदि h (n) 0 है, तो केवल g (n) एक भूमिका निभाता है, और A * दीजकस्ट्रा के एल्गोरिथ्म में बदल जाता है, जिसे सबसे छोटा रास्ता खोजने की गारंटी है।
  • यदि h (n) हमेशा n से लक्ष्य तक जाने की लागत (या बराबर) से कम है, तो A * को सबसे छोटा रास्ता खोजने की गारंटी है। निचला h (n) है, अधिक नोड A * फैलता है, जिससे यह धीमा हो जाता है।
  • यदि h (n) n से लक्ष्य की ओर बढ़ने की लागत के बराबर है, तो A * केवल सर्वोत्तम पथ का अनुसरण करेगा और कभी भी किसी अन्य चीज़ का विस्तार नहीं करेगा, जिससे यह बहुत तेज़ हो जाएगा। यद्यपि आप सभी मामलों में ऐसा नहीं कर सकते, लेकिन आप इसे कुछ विशेष मामलों में सटीक बना सकते हैं। यह जानकर अच्छा लगता है कि दी गई सही जानकारी, ए * पूरी तरह से व्यवहार करेगी।
  • यदि h (n) कभी-कभी n से लक्ष्य की ओर बढ़ने की लागत से अधिक है, तो A * को सबसे छोटा रास्ता खोजने की गारंटी नहीं है, लेकिन यह तेजी से चल सकता है।
  • दूसरे चरम पर, यदि h (n) g (n) के सापेक्ष बहुत अधिक है, तो केवल h (n) एक भूमिका निभाता है, और A * सर्वश्रेष्ठ-प्रथम-खोज में बदल जाता है।

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


-1, समस्या हेयुरिस्टिक नहीं है, लेकिन कार्यान्वयन है।

2

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


1

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


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