2016-11-01 10 views
6

जब मैं सबसे कम पथ एल्गोरिदम को कोड करने का प्रयास करता हूं, तो मैं एक अजीब चीज में चला जाता हूं। floydWarshall फ़ंक्शन के बाद सरणी रूप में आसन्नता मैट्रिक्स उत्पन्न करता है, main फ़ंक्शन कई बार सरणी (replicateM_ लूप में) क्वेरी करने का प्रयास करता है।फ़ंक्शन का परिणाम पुन: उपयोग क्यों नहीं किया जाता है?

मुझे जो मिला वह यह है कि मेरा कोड बहुत धीमा है। इसलिए मैंने traceShow "doing"floydWarshall के शीर्ष पर रखा और यह पता लगाने के लिए फिर से चलाया कि प्रत्येक res ! (start,end)floydWarshall बार-बार कॉल करता है।

सरणी हर बार फिर से उत्पन्न क्यों करती है?

नमूना इनपुट के साथ पूर्ण स्रोत: https://gist.github.com/cwyang/27ab81bee731e6d01bb3a7483fdb748e

floydWarshall :: AdjMatrix (Maybe Int) -> AdjMatrix (Maybe Int) 
floydWarshall am = traceShow "doing" $ runST $ do 
    arr <- thaw am :: ST s (STArray s (Vertex,Vertex) (Maybe Int)) 
    sequence_ [ go arr k i j | k <- r, i <- r, j <- r] 
    freeze arr 
    where ((minb,_), (maxb,_)) = bounds am 
     r = [minb..maxb] 
     go :: STArray s (Vertex,Vertex) (Maybe Int) 
      -> Vertex -> Vertex -> Vertex -> ST s() 
     go arr k i j = do 
      ij <- readArray arr (i,j) 
      ik <- readArray arr (i,k) 
      kj <- readArray arr (k,j) 
      case (ik, kj) of 
      (Nothing, _) -> return() 
      (_, Nothing) -> return() 
      (Just a, Just b) -> case ij of 
       Nothing -> do 
       writeArray arr (i,j) $ Just (a+b) 
       (Just c) -> when (c > a+b) $ do 
       writeArray arr (i,j) $ Just (a+b) 
readInt :: B.ByteString -> Int 
readInt = fst . fromJust . B.readInt 

main :: IO() 
main = do 
    [n,m] <- rl 
    edges <- replicateM m $ do 
    [from,to,weight] <- rl 
    return (from,to,weight) 
    [q] <- rl 
    let am = buildAdjMatrix (1,n) edges 
     res= floydWarshall am 
    replicateM_ q $ do 
    [start,end] <- rl 
    putStrLn . show $ maybe (-1) id (res ! (start,end)) 
    where rl = map readInt . B.words <$> B.getLine 

नमूना रन:

$ graph < floyd3.txt hs 
"doing"  <-- floydWarshall keeps calling 
1395 
"doing" 
975 
"doing" 
1593 
"doing" 
1023 
"doing" 
1521 
... 
+0

कोई मौका आपके पास कहीं भी पूर्ण कोड है? सबसे अच्छा, आप यह देखने के लिए कोर आउटपुट देखना चाहते हैं कि क्या हो रहा है, लेकिन यह केवल कुछ ऐसा है जो संकलित करता है। इसके अलावा, जब आप संकलित करते हैं तो आप किस झंडे का उपयोग कर रहे हैं? – Alec

+1

फ़्लॉइड-वारशेल शास्त्रीय गतिशील प्रोग्रामिंग एल्गोरिदम है। आप इस पोस्ट में _Haskell_ का उपयोग करके ऐसी समस्याओं को हल करने के लिए बेहतर दृष्टिकोण प्राप्त कर सकते हैं: http://jelv.is/blog/Lazy- गतिशील- प्रोग्रामिंग/ – Shersh

+0

मैंने पूर्ण कोड और नमूना इनपुट अपलोड किया है: https: //gist.github। com/cwyang/27ab81bee731e6d01bb3a7483fdb748e –

उत्तर

4

Frustratingly, इस GHC मुद्दा "Costly let binding gets duplicated in IO action value" की वजह से हो रहा है।

forM_ का उपयोग replicateM_ के बजाय या BangPatterns का उपयोग करके इस समस्या को हल करता है।

+1

में 'replicateM_' की बग हो सकती है @ शेरश की टिप्पणी ऊपर बहुत अच्छी लगती है:" आप इस पोस्ट में हास्केल का उपयोग करके ऐसी समस्याओं को हल करने के लिए बेहतर दृष्टिकोण प्राप्त कर सकते हैं: jelv.is/blog/आलसी-गतिशील-प्रोग्रामिंग "आम तौर पर, आपको आईओ मोनड में जितना संभव हो उतना करना चाहिए ... प्रोग्रामिंग हास्केल के दौरान आपको अपनी सोच को थोड़ा सा बदलना होगा, लेकिन समय के साथ आप इसे और अधिक आनंद लेंगे:) – mb21

+0

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

+1

@ mb21 जबकि मैं आपकी टिप्पणी की भावना से सहमत हूं, ओपी 'आईओ' मोनैड के अंदर अपना काम नहीं कर रहा है, लेकिन 'एसटी 'मोनैड के अंदर (बग वास्तव में एल्गोरिदम में भी नहीं है बल्कि कॉल में है यह)। साथ ही, जैसा कि इस विशेष एल्गोरिदम के लिए बहुत सारे अपडेट की आवश्यकता है 'एसटी' एक बहुत अच्छी पसंद की तरह लगता है। – Alec

संबंधित मुद्दे