2012-11-14 5 views
5

Mein Freund schrieb ein Programm, das zufällige Anordnungen von Gesichtern vergleicht, um das mit den am gleichmäßigsten verteilten Gesichtern zu finden - besonders, wenn die Gesichtern keine bloße Sequenz sind.Haskell Tipps/warum skaliert das nicht linear?

Ich habe sein Programm in Haskell übersetzt, weil ich nach einem Grund gesucht habe, jemandes Ohr darüber zu reden, wie cool Haskell ist. Allerdings bin ich nicht sehr gut mit Haskell (es dauerte ewig, um dies zu schreiben und es hat ein paar riesige Refactorings unterzogen) und so habe ich zwei Probleme.

  1. er war groß auf die Optimierung seiner Versionen, und das ist nicht sehr schnell, und es skaliert nicht linear. Habe ich eine Schwanzrekursion durcheinander gebracht oder ist es ein größeres Problem?
  2. der Code, der daraus entstand, ist nicht wirklich so elegant, wie ich es vorhergesagt hatte. Ich weiß, dass dies nicht eine Diskussionsrunde, aber wenn Sie irgendwelche Ideen haben, wie man es vereinfachen, ich bin ganz Ohr

Dies ist der entsprechende Code:

-- _CENTERS :: [{ x :: Float, y :: Float, z :: Float}] 
-- _VALUES :: [Num] 

-- Basically just (repeat $ map rand [0.._SIDES]), but never using a seed twice 
randstates from = (take _SIDES (infrand from)) : randstates newseed 
    where infrand seed = seed : infrand (shuffle seed) 
      newseed  = (infrand from) !! (_SIDES + 1) 

-- yates shuffle 
yates _ (last:[]) = [last] 
yates (rand:pass) (swap:order) = choice:yates pass rorder 
     where choice = order !! index 
       index = (randfrom rand) `mod` (length order) 
       rorder = take (index) order ++ swap : drop (index + 1) order 

arrangements seed = map arrange $ randstates seed 
     where arrange rands = yates rands [0.._SIDES - 2] 

-- fns comparing arrangements -- 
arcLength i j = 1/(1 + _WEIGHT * acos(dot3D/_VEC_LEN_SQUARED)) 
     where dot3D = apply x + apply y + apply z 
       apply fn = (fn i) * (fn j) 

matrix arr = map crosscmp arr 
     where crosscmp s1 = [ value s1 * (distance s1 s2) | s2 <- arr ] 
       distance a b = arcLength (_CENTERS !! a) (_CENTERS !! b) 
       value s  = fromInteger $ _VALUES !! s 

variance arr = sum $ map perside (matrix arr) 
     where perside s = (sum s - mean)^2 
       mean  = (sum (concat $ matrix arr))/(sides + 1) 
       sides  = fromInteger $ toInteger _SIDES 

maxDistr = maximumBy (\a b -> variance a `compare` variance b) 

Main ist im Grunde nur

+3

Vielleicht versuchen Sie http://codereview.stackexchange.com? –

+6

Die offensichtliche Sache ist, dass die Indexierung der Liste "O (Index)" ist. Wenn deine Listen nicht wirklich kurz sind, wird das wehtun. –

+0

Danke, ich habe dort einen Posten eingerichtet, wo es relevanter ist. Würden Sie also empfehlen, Seiten 0 = _, Seiten 1 = _ usw. zu definieren, oder sollte ich eine andere Datenstruktur wie ein Array verwenden? –

Antwort

1

Wie die Kommentare beachten, kann es nicht linear skalieren, wenn die Indizierung in eine Liste O(index) ist. Sie müssen zu einer Array-Struktur wechseln, um Verbesserungen zu sehen.

Verwandte Themen