packages feed

dph-examples (empty) → 0.5.1.1

raw patch · 46 files changed

+3031/−0 lines, 46 filesdep +basedep +dph-basedep +dph-parsetup-changed

Dependencies added: base, dph-base, dph-par, dph-prim-par, dph-prim-seq, dph-seq, gloss, old-time, parseargs, random, vector

Files

+ LICENSE view
@@ -0,0 +1,31 @@+Copyright (c) 2001-2011, The DPH Team+All rights reserved.++The DPH Team is:+  Manuel M T Chakravarty+  Gabriele Keller+  Roman Leshchinskiy+  Ben Lippmeier+  George Roldugin++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:+    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.+    * Redistributions in binary form must reproduce the above copyright+      notice, this list of conditions and the following disclaimer in the+      documentation and/or other materials provided with the distribution.+    * Neither the name of the University of New South Wales nor the+      names of its contributors may be used to endorse or promote products+      derived from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS BE LIABLE FOR ANY+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ dph-examples.cabal view
@@ -0,0 +1,240 @@++++Name:                dph-examples+Version:             0.5.1.1+License:             BSD3+License-file:        LICENSE+Author:              The DPH Team+Maintainer:          Ben Lippmeier <benl@ouroborus.net>+Build-Type:          Simple+Cabal-Version:       >=1.8+Stability:           experimental+Category:            Data Structures+Homepage:            http://www.cse.unsw.edu.au/~chak/project/dph/+Description:         Examples using the DPH library.+Synopsis:            Examples using the DPH library.++Flag gloss+ Description:        Enable graphical front ends that use the gloss library.+ Default:            False++-- With these examples, +--   the plain dph-NAME versions are parallel versions built against dph-par+--   while the dph_NAME-seq versions are sequential ones built against dph-seq++-- Sum of Squares -------------------------------------------------------------+Executable dph-sumsq+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  SumSquaresVector+                  SumSquaresVectorised+                  Timing Randomish+  hs-source-dirs: lib imaginary/SumSquares/dph+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++Executable dph-sumsq-seq+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  SumSquaresVector+                  SumSquaresVectorised+                  Timing Randomish+  hs-source-dirs: lib imaginary/SumSquares/dph+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++-- Dot Product ----------------------------------------------------------------+Executable dph-dotp+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  DotProductVector+                  DotProductVectorised+                  Timing Randomish+  hs-source-dirs: lib imaginary/DotProduct/dph+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++Executable dph-dotp-seq+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  DotProductVector+                  DotProductVectorised+                  Timing Randomish+  hs-source-dirs: lib imaginary/DotProduct/dph+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++-- Evens ----------------------------------------------------------------------+Executable dph-evens+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  EvensVector+                  EvensVectorised+                  Timing Randomish+  hs-source-dirs: imaginary/Evens/dph lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++Executable dph-evens-seq+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  EvensVector+                  EvensVectorised+                  Timing Randomish+  hs-source-dirs: imaginary/Evens/dph lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++-- Primes ---------------------------------------------------------------------+-- Primes dies with a bounds check error+-- Executable dph-primes+--  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+--  Main-is:        Main.hs+--  hs-source-dirs: imaginary/Primes lib+--  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++-- Executable dph-primes-seq+--  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+--  Main-is:        Main.hs+--  hs-source-dirs: imaginary/Primes lib+--  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++-- Reverse --------------------------------------------------------------------+Executable dph-reverse+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  ReverseVector+                  ReverseVectorised+                  Util Timing Randomish+  hs-source-dirs: imaginary/Reverse/dph lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++Executable dph-reverse-seq+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  ReverseVector+                  ReverseVectorised+                  Util Timing Randomish+  hs-source-dirs: imaginary/Reverse/dph lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++-- Words ---------------------------------------------------------------------+-- This builds and runs, but takes ~5min. +-- Executable dph-words+--  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+--  Main-is:        Main.hs+--  hs-source-dirs: imaginary/Words lib+--  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3 -fno-liberate-case++-- This one also stalls in SpecConstr, like quicksort-seq+-- Executable dph-words-seq+--   Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+--   Main-is:        Main.hs+--   hs-source-dirs: imaginary/Words lib+--   ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++-- SMVM ---------------------------------------------------------------------+Executable dph-smvm+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  SMVMVectorised+                  Timing+  hs-source-dirs: spectral/SMVM/dph lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++Executable dph-smvm-seq+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  SMVMVectorised+                  Timing+  hs-source-dirs: spectral/SMVM/dph lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++++-- QuickHull ------------------------------------------------------------------+Executable dph-quickhull+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  QuickHullVect+                  Timing Points2D.Types SVG+  hs-source-dirs: lib spectral/QuickHull/dph spectral/QuickHull/lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++Executable dph-quickhull-seq+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  QuickHullVect+                  Timing Points2D.Types SVG+  hs-source-dirs: lib spectral/QuickHull/dph spectral/QuickHull/lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++Executable dph-quickhull-vector+  Build-depends: +        base          == 4.*,+        vector        == 0.7.*,    +        old-time      == 1.0.*,+        random        == 1.0.*+  Main-is:        Main.hs+  other-modules:  QuickHullIO+                  QuickHullSplit+                  QuickHullVector+                  Timing Points2D.Types SVG+  hs-source-dirs: lib spectral/QuickHull/vector spectral/QuickHull/lib+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++-- QuickSort ------------------------------------------------------------------+Executable dph-quicksort+  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*+  Main-is:        Main.hs+  other-modules:  QuickSortVect+                  Timing+  hs-source-dirs: lib spectral/QuickSort/dph+  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3++-- This one stalls in SpecConstr then eventually runs out of memory.+-- Executable dph-quicksort-seq+--  Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*+--  Main-is:        Main.hs+--  other-modules:  QuickSortVect+--                  Timing+--  hs-source-dirs: lib spectral/QuickSort/dph+--  ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+++-- NBody ----------------------------------------------------------------------+Executable dph-nbody+  Main-is:        Main.hs+  other-modules:  Common.Dump Common.World Common.Body Common.Util +                  Solver Solver.ListBH.Solver+                         Solver.NestedBH.Solver+                         Solver.VectorBH.Solver+                         Solver.VectorNaive.Solver+                  Timing Points2D.Types Points2D.Generate++  if flag(gloss)+    other-modules:  Gloss.MainArgs Gloss.Draw Gloss.Config+    Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*, parseargs == 0.1.*, gloss == 1.3.*+    hs-source-dirs: lib real/NBody real/NBody/Gloss+    ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3 -fno-liberate-case+  else+    other-modules:  Batch.MainArgs Batch.Config+    Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-par == 0.5.*, dph-par == 0.5.*, random == 1.0.*, old-time == 1.0.*, parseargs == 0.1.*+    hs-source-dirs: lib real/NBody real/NBody/Batch+    ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-par -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3 -fno-liberate-case+  endif++-- Executable dph-nbody-seq+--  Main-is:        Main.hs+--  if flag(gloss)+--    Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*, parseargs == 0.1.*, gloss == 1.3.*+--    hs-source-dirs: lib real/NBody real/NBody/Gloss+--    ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+--  else+--    Build-depends:  base == 4.4.*, vector == 0.7.*, dph-base == 0.5.*, dph-prim-seq == 0.5.*, dph-seq == 0.5.*, random == 1.0.*, old-time == 1.0.*, parseargs == 0.1.*+--    hs-source-dirs: lib real/NBody real/NBody/Batch+--    ghc-options:    -rtsopts -threaded -fllvm -Odph -fdph-seq -fcpr-off -fsimplifier-phases=4 -fstrictness-before=3+--  endif
+ imaginary/DotProduct/dph/DotProductVector.hs view
@@ -0,0 +1,7 @@++module DotProductVector (dotV) where+import Data.Vector.Unboxed		(Vector)+import qualified Data.Vector.Unboxed	as V++dotV :: Vector Double -> Vector Double -> Double+dotV vec1 vec2 = V.sum $ V.zipWith (*) vec1 vec2
+ imaginary/DotProduct/dph/DotProductVectorised.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}+module DotProductVectorised ( dotPA ) where++import Data.Array.Parallel+import Data.Array.Parallel.Prelude.Double as D++import qualified Prelude++dotPA :: PArray Double -> PArray Double -> Double+{-# NOINLINE dotPA #-}+dotPA v w = dotp' (fromPArrayP v) (fromPArrayP w)++dotp' :: [:Double:] -> [:Double:] -> Double+dotp' v w = D.sumP (zipWithP (*) v w)
+ imaginary/DotProduct/dph/Main.hs view
@@ -0,0 +1,45 @@++import Timing+import Randomish+import System.Environment+import Data.Array.Parallel	as P+import Data.Array.Parallel.PArray	as P+import qualified Data.Vector.Unboxed	as V+import qualified DotProductVector	as V+import qualified DotProductVectorised	as Z++main :: IO ()+main + = do	args	<- getArgs+	case args of+	  [alg, len] 	-> run alg (read len) +	  _		-> usage++usage+ = putStr $ unlines+ 	[ "usage: dotp <alg> <length>"+ 	, "  alg one of " ++ show ["vectorised", "vector"] ]+	+run alg len+ = do	let vec1 = randomishDoubles len 0 1 1234+	let vec2 = randomishDoubles len 0 1 12345++	(result, tElapsed) <- runAlg alg vec1 vec2++	putStr	$ prettyTime tElapsed+	putStr	$ (take 12 $ show result) ++ "\n"++runAlg "vectorised" vec1 vec2 + = do	let arr1 = fromUArrPA' vec1+	let arr2 = fromUArrPA' vec2+	arr1 `seq` arr2 `seq` return ()++	time	$ let result	= Z.dotPA arr1 arr2+		  in  result `seq` return result++runAlg "vector" vec1 vec2+ = do	vec1 `seq` vec2 `seq` return ()++	time	$ let result	= V.dotV vec1 vec2 +		  in  result `seq` return result+		
+ imaginary/Evens/dph/EvensVector.hs view
@@ -0,0 +1,8 @@++module EvensVector (evensV) where+import Data.Vector.Unboxed		(Vector)+import qualified Data.Vector.Unboxed	as V++evensV :: Vector Int -> Vector Int+evensV ints = V.filter (\x -> x `mod` 2 == 0) ints+
+ imaginary/Evens/dph/EvensVectorised.hs view
@@ -0,0 +1,16 @@+{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}++module EvensVectorised (evensPA) where+import Data.Array.Parallel+import Data.Array.Parallel.Prelude.Int+import qualified Prelude as P++-- | DPH filter opereations are reasonably involved because they use packByTag.+evens :: [:Int:] -> [:Int:]+evens ints = filterP (\x -> x `mod` 2 == 0) ints++evensPA :: PArray Int -> PArray Int+{-# NOINLINE evensPA #-}+evensPA arr = toPArrayP (evens (fromPArrayP arr))+
+ imaginary/Evens/dph/Main.hs view
@@ -0,0 +1,45 @@++import EvensVectorised			as Z+import EvensVector			as V+import qualified Data.Vector.Unboxed	as V+import Timing+import System.Environment+import Data.Array.Parallel.PArray	as P++main :: IO ()+main + = do	args	<- getArgs+	case args of+	  [alg, len]	-> run alg (read len)+	  _ 		-> usage++usage+ = putStr $ unlines+ 	[ "usage: evens <alg> <length>"+ 	, "  alg one of " ++ show ["vectorised", "vector"] ]++run alg len+ = do	let vec	= V.fromList [0..len - 1]+	runAlg alg vec+	+runAlg "vectorised" vec+ = do	let arr	= P.fromUArrPA' vec+	arr `seq` return ()++	(arr', tElapsed)+	 <- time $ let	arr' = evensPA arr+		   in	arr' `seq` return arr'+					+	putStr   $ prettyTime tElapsed+	putStrLn $ show $ P.length arr'++runAlg "vector" vec+ = do	vec `seq` return ()+	+	(vec', tElapsed)+	 <- time $ let	vec' = evensV vec+		   in	vec' `seq` return vec'+		+	putStr   $ prettyTime tElapsed+	putStrLn $ show $ V.length vec'+	
+ imaginary/Reverse/dph/Main.hs view
@@ -0,0 +1,58 @@++import Util+import Timing+import Randomish+import System.Environment+import System.Random+import Control.Exception+import qualified ReverseVector                  as RV+import qualified ReverseVectorised              as RD+import qualified Data.Array.Parallel.PArray     as P+import qualified Data.Vector.Unboxed            as V+++main + = do   args    <- getArgs+        +        case args of+         [alg, count]   +           |  not $ isPowerOfTwo (read count)+           -> error "reverse: length of array must be a power of two."++           | otherwise -> run alg (read count)++         _ -> usage+++run "vectorised" count+ = do   let arr = P.fromList [0 .. count - 1]+        arr `seq` return ()     +                +        (arrReversed, tElapsed)+         <- time+         $  let  arr'    = RD.treeReversePA arr+            in   arr' `seq` return arr'++        print arrReversed+        putStr  $ prettyTime tElapsed++run "vector" count+ = do   let arr = V.fromList [0 .. count - 1]+        arr `seq` return ()+        +        (arrReversed, tElapsed)+         <- time+         $  let arr'    = RV.treeReverse arr+            in  arr' `seq` return arr'+            +        print arrReversed+        putStr  $ prettyTime tElapsed++run _ _+ = usage+++usage   = putStr $ unlines+        [ "usage: reverse <algorithm> <count>\n"+        , "  algorithm one of " ++ show ["vectorised"]+        , ""]
+ imaginary/Reverse/dph/ReverseVector.hs view
@@ -0,0 +1,21 @@++module ReverseVector+        (treeReverse)+where+import qualified Data.Vector.Unboxed as V+import Data.Vector.Unboxed              (Vector)++-- | Reverse the elements in an array using a tree.+treeReverse :: Vector Int -> Vector Int+{-# NOINLINE treeReverse #-}+treeReverse xx+        | V.length xx == 1+        = xx+        +        | otherwise+        = let   len     = V.length xx+                half    = len `div` 2+                s1      = V.slice 0    half  xx+                s2      = V.slice half half  xx         +          in    treeReverse s2 V.++ treeReverse s1+
+ imaginary/Reverse/dph/ReverseVectorised.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}+module ReverseVectorised        +        (treeReversePA)+where+import Data.Array.Parallel+import Data.Array.Parallel.Prelude.Int+import qualified Prelude as P+++treeReversePA :: PArray Int -> PArray Int+{-# NOINLINE treeReversePA #-}+treeReversePA ps+        = toPArrayP (treeReverse (fromPArrayP ps))+++-- | Reverse the elements in an array using a tree.+treeReverse :: [:Int:] -> [:Int:]+{-# NOINLINE treeReverse #-}+treeReverse xx+        | lengthP xx == 1+        = xx+        +        | otherwise+        = let   len     = lengthP xx+                half    = len `div` 2+                s1      = sliceP 0    half xx+                s2      = sliceP half half  xx           +          in    concatP (mapP treeReverse [: s2, s1 :])
+ imaginary/SumSquares/dph/Main.hs view
@@ -0,0 +1,34 @@++import Timing+import Randomish+import System.Environment+import qualified Data.Vector.Unboxed	as V+import qualified SumSquaresVector	as V+import qualified SumSquaresVectorised	as Z++main :: IO ()+main + = do	args	<- getArgs+	case args of+	  [alg, len] 	-> run alg (read len) +	  _		-> usage++usage+ = putStr $ unlines+ 	[ "usage: sumsq <alg> <length>"+ 	, "  alg one of " ++ show ["vectorised", "vector"] ]+	+run alg num+ = do	(result, tElapsed) <- runAlg alg num++	putStr	$ prettyTime tElapsed+	print result++runAlg "vectorised" num+ =	time	$ let result	= Z.sumSq num+		  in  result `seq` return result++runAlg "vector" num+ =	time	$ let result	= V.sumSq num+		  in  result `seq` return result+		
+ imaginary/SumSquares/dph/SumSquaresVector.hs view
@@ -0,0 +1,11 @@++module SumSquaresVector where+import qualified Data.Vector.Unboxed	 as V+	+sumSq :: Int -> Double+sumSq num	+	= V.sum +	$ V.map (\x -> x * x) +	$ V.map fromIntegral +	$ V.enumFromTo 1 num+	
+ imaginary/SumSquares/dph/SumSquaresVectorised.hs view
@@ -0,0 +1,15 @@+{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}+module SumSquaresVectorised (sumSq) where+import Data.Array.Parallel+import Data.Array.Parallel.Prelude.Int 		as I+import Data.Array.Parallel.Prelude.Double	as D+import qualified Prelude++sumSq :: Int -> Double+{-# NOINLINE sumSq #-}+sumSq n	+ = 	D.sumP +	(mapP (\x -> x D.* x) +	(mapP D.fromInt +	(enumFromToP 1 n)))
+ lib/Points2D/Generate.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE TypeOperators #-}+module Points2D.Generate +	( genPointsUniform+	, genPointsUniformWithSeed+	, genPointsDisc+	, genPointsCombo+	, pointsPArrayOfUArray )+where+import Points2D.Types+import Randomish+import qualified Data.Array.Parallel.Unlifted 	    as U+import qualified Data.Array.Parallel 	    as P+import qualified Data.Array.Parallel.PArray         as P+import Data.Array.Parallel.PArray		    (PArray)+import Control.Exception++-- Random points generation+-- IMPORTANT: We use the same seed with the same random generator in all+--            quickhull codes.  The asymptotic work complexity of quickhull+--            is between O (N) and O (N^2) depending on the input.+--            To compare benchmark results, they always need to use the same+--            input.+seed :: Int+seed 	= 42742++-- | Some uniformly distributed points+genPointsUniform +	:: Int			-- ^ number of points+	-> Double		-- ^ minimum coordinate+	-> Double		-- ^ maximum coordinate+        -> U.Array (Double, Double)++genPointsUniform n pointMin pointMax+ = let  pts             = randomishDoubles (n*2) pointMin pointMax seed+        xs              = U.extract pts 0 n+        ys              = U.extract pts n n+   in   U.zip xs ys+++-- | Some uniformly distributed points+genPointsUniformWithSeed+	:: Int			-- ^ seed+	-> Int			-- ^ number of points+	-> Double		-- ^ minimum coordinate+	-> Double		-- ^ maximum coordinate+        -> U.Array (Double, Double)++genPointsUniformWithSeed seed' n pointMin pointMax+ = let  pts             = randomishDoubles (n*2) pointMin pointMax seed'+        xs              = U.extract pts 0 n+        ys              = U.extract pts n n+   in   U.zip xs ys+++-- | Some points distributed as a disc+genPointsDisc+	:: Int			-- ^ number of points+	-> (Double, Double) 	-- ^ center of disc+	-> Double 		-- ^ radius of disc+        -> U.Array (Double, Double)++genPointsDisc n (originX, originY) radiusMax+ = let	radius = randomishDoubles n 0     radiusMax seed+        angle  = randomishDoubles n (-pi) pi        (seed + 1234)++	makeXY r a	+	 	= ( originX + r * cos a+		  , originY + r * sin a)	++    in	originX `seq` originY `seq` U.zipWith makeXY radius angle+++-- | A point cloud with areas of high an low density+genPointsCombo +	:: Int 			-- ^ number of points+        -> U.Array (Double, Double)++genPointsCombo n+ 	=  genPointsDisc    (n `div` 5) (250, 250) 200+	U.+:+ genPointsDisc (n `div` 5) (100, 100) 80 +	U.+:+ genPointsDisc (n `div` 5) (150, 300) 30 +	U.+:+ genPointsDisc (n `div` 5) (500, 120) 30 +	U.+:+ genPointsDisc (n `div` 5) (300, 200) 150+++-- | Convert a list of points to a PArray+pointsPArrayOfUArray +	:: U.Array (Double, Double)+	-> IO (PArray Point)++pointsPArrayOfUArray ps+  = do+      let pts = makePointsPA +			(P.fromUArrPA' (U.fsts ps))+ 			(P.fromUArrPA' (U.snds ps))+      evaluate $ P.nf pts+      return pts+
+ lib/Points2D/Types.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}++module Points2D.Types +	( Point+	, Line+	, makePoints, makePointsPA+	, xsOf, xsOfPA+	, ysOf, ysOfPA)+where+import Data.Array.Parallel++type Point = (Double, Double)+type Line  = (Point, Point)++-- | Make some points from their components.+makePoints :: [:Double:] -> [:Double:] -> [:Point:]+makePoints = zipP+++-- | Make some points from their components, as a `PArray`.+makePointsPA :: PArray Double -> PArray Double -> PArray Point+{-# NOINLINE makePointsPA #-}+makePointsPA xs ys+	= toPArrayP (makePoints (fromPArrayP xs) (fromPArrayP ys))+++-- | Take the x values of some points.+xsOf :: [:Point:] -> [:Double:]+xsOf ps = [: x | (x, _) <- ps :]+++-- | Take the x values of some points as a `PArray`.+xsOfPA :: PArray Point -> PArray Double+{-# NOINLINE xsOfPA #-}+xsOfPA ps = toPArrayP (xsOf (fromPArrayP ps))+++-- | Take the y values of some points.+ysOf :: [:Point:] -> [:Double:]+ysOf ps = [: y | (_, y) <- ps :]+++-- | Take the y values of some points as a `PArray`.+ysOfPA :: PArray Point -> PArray Double+{-# NOINLINE ysOfPA #-}+ysOfPA ps = toPArrayP (ysOf (fromPArrayP ps))++
+ lib/Randomish.hs view
@@ -0,0 +1,82 @@+{-# LANGUAGE BangPatterns #-}++module Randomish+ 	( randomishInts+	, randomishDoubles)+where+import Data.Word+import Data.Vector.Unboxed			(Vector)+import qualified Data.Vector.Unboxed.Mutable	as MV+import qualified Data.Vector.Unboxed		as V+import qualified Data.Vector.Generic		as G		+++-- | Use the "minimal standard" Lehmer generator to quickly generate some random+--   numbers with reasonable statistical properties. By "reasonable" we mean good+--   enough for games and test data, but not cryptography or anything where the+--   quality of the randomness really matters.+-- +--   From "Random Number Generators: Good ones are hard to find"+--   Stephen K. Park and Keith W. Miller.+--   Communications of the ACM, Oct 1988, Volume 31, Number 10.+--+randomishInts +	:: Int 			-- Length of vector.+	-> Int 			-- Minumum value in output.+	-> Int 			-- Maximum value in output.+	-> Int 			-- Random seed.	+	-> Vector Int		-- Vector of random numbers.++randomishInts !len !valMin' !valMax' !seed'+	+ = let	-- a magic number (don't change it)+	multiplier :: Word64+	multiplier = 16807++	-- a merzenne prime (don't change it)+	modulus	:: Word64+	modulus	= 2^(31 :: Integer) - 1++	-- if the seed is 0 all the numbers in the sequence are also 0.+	seed	+	 | seed' == 0	= 1+	 | otherwise	= seed'++	!valMin	= fromIntegral valMin'+	!valMax	= fromIntegral valMax' + 1+	!range	= valMax - valMin++	{-# INLINE f #-}+	f x		= multiplier * x `mod` modulus+ in G.create +     $ do	+	vec		<- MV.new len++	let go !ix !x +	  	| ix == len	= return ()+		| otherwise+		= do	let x'	= f x+			MV.write vec ix $ fromIntegral $ (x `mod` range) + valMin+			go (ix + 1) x'++	go 0 (f $ f $ f $ fromIntegral seed)+	return vec+++-- | Generate some randomish doubles with terrible statistical properties.+--   This is good enough for test data, but not much else.+randomishDoubles +	:: Int			-- Length of vector+	-> Double		-- Minimum value in output+	-> Double		-- Maximum value in output+	-> Int			-- Random seed.+	-> Vector Double	-- Vector of randomish doubles.++randomishDoubles !len !valMin !valMax !seed+ = let	range	= valMax - valMin++	mx	= 2^(30 :: Integer) - 1+	mxf	= fromIntegral mx+	ints	= randomishInts len 0 mx seed+	+   in	V.map (\n -> valMin + (fromIntegral n / mxf) * range) ints
+ lib/Timing.hs view
@@ -0,0 +1,70 @@+module Timing+	(time, showTime, prettyTime)+where+import GHC.Exts	(traceEvent)+import System.CPUTime+import System.Time+++-- Time -----------------------------------------------------------------------+data Time +	= Time +	{ cpu_time  :: Integer+        , wall_time :: Integer+        }++zipT :: (Integer -> Integer -> Integer) -> Time -> Time -> Time+zipT f (Time cpu1 wall1) (Time cpu2 wall2) +	= Time (f cpu1 cpu2) (f wall1 wall2)++minus :: Time -> Time -> Time+minus = zipT (-)+++-- TimeUnit -------------------------------------------------------------------+type TimeUnit +	= Integer -> Integer++milliseconds :: TimeUnit+milliseconds n = n `div` 1000000000++cpuTime :: TimeUnit -> Time -> Integer+cpuTime f = f . cpu_time++wallTime :: TimeUnit -> Time -> Integer+wallTime f = f . wall_time+++-- | Get the current time.+getTime :: IO Time+getTime =+  do+    cpu          <- getCPUTime+    TOD sec pico <- getClockTime+    return $ Time cpu (pico + sec * 1000000000000)+++-- | Show a time as a string, in milliseconds.+showTime :: Time -> String+showTime t = (show $ wallTime milliseconds t)+          ++ "/"+          ++ (show $ cpuTime  milliseconds t)++-- | Pretty print the times.+prettyTime :: Time -> String+prettyTime t+	= unlines+	[ "elapsedTimeMS   = " ++ (show $ wallTime milliseconds t)+	, "cpuTimeMS       = " ++ (show $ cpuTime  milliseconds t) ]+++-- Timing benchmarks ----------------------------------------------------------+time :: IO a -> IO (a, Time)+{-# NOINLINE time #-}+time p = do+           start <- getTime+           traceEvent "dph-examples: start timing"+           x     <- p+           traceEvent "dph-examples: finished timing"+           end   <- getTime+           return (x, end `minus` start)
+ lib/Util.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE PatternGuards #-}+module Util +	( isPowerOfTwo+	, isSorted)+where+	++-- | Check if an integer is a power of two.+isPowerOfTwo :: Int -> Bool+isPowerOfTwo n+	| 0	<- n		= True+	| 2	<- n		= True+	| n `mod` 2 == 0	= isPowerOfTwo (n `div` 2)+	| otherwise		= False+++isSorted :: Ord a => [a] -> Bool+isSorted xx+ = case xx of+	[]		-> True+	[x]		-> True+	(x1:x2:rest)+	 | x1 <= x2	-> isSorted (x2 : rest)+	 | otherwise	-> False+
+ real/NBody/Batch/Config.hs view
@@ -0,0 +1,57 @@++module Batch.Config+	( Config(..)+	, loadConfig)+where+import Batch.MainArgs+import System.Console.ParseArgs+import Data.Maybe+++-- | Program config+data Config+	= Config {+	-- What solver to use+	  configSolverName	:: String++	-- System setup+	, configBodyCount	:: Int+	, configBodyMass	:: Double+	, configTimeStep	:: Double+	, configEpsilon		:: Double++	-- Initial conditions.+	, configStartDiscSize	:: Double+	, configStartSpeed	:: Double++	-- Terminating conditions.+	, configMaxSteps	:: Int+	+	-- Dump points to file+	, configDumpFinal	:: Maybe FilePath }+	++-- | Load program config from its command line arguments.	+loadConfig :: Args MainArg -> Config+loadConfig args+ = let	Just solverName	= getArgString	args ArgSolver+	Just timeStep	= getArgDouble	args ArgTimeStep+	Just bodyCount	= getArgInt	args ArgBodyCount+	Just bodyMass	= getArgDouble  args ArgBodyMass+	Just epsilon	= getArgDouble	args ArgEpsilon+	Just discSize	= getArgDouble	args ArgDiscSize+	Just startSpeed	= getArgDouble	args ArgStartSpeed++	Just maxSteps	= getArgInt	args ArgMaxSteps+	mFilePath	= getArgString	args ArgDumpFinal++   in	Config+	{ configSolverName	= solverName+	, configBodyCount	= bodyCount+	, configBodyMass	= bodyMass+	, configTimeStep	= timeStep+	, configEpsilon		= epsilon+	, configStartDiscSize	= discSize+	, configStartSpeed	= startSpeed+	, configMaxSteps	= maxSteps+	, configDumpFinal	= mFilePath }
+ real/NBody/Batch/MainArgs.hs view
@@ -0,0 +1,87 @@++module Batch.MainArgs+	( MainArg(..)+	, mainArgs)+where+import System.Console.ParseArgs++data MainArg+	= ArgHelp+	| ArgSolver+	| ArgMaxSteps+	| ArgTimeStep+	| ArgBodyCount+	| ArgBodyMass+	| ArgEpsilon+	| ArgDiscSize+	| ArgStartSpeed+		+	-- Dump output+	| ArgDumpFinal+	deriving (Eq, Ord, Show)+	+mainArgs :: [Arg MainArg]+mainArgs+ = 	[ Arg	{ argIndex	= ArgHelp+		, argAbbr	= Just 'h'+		, argName	= Just "help"+		, argData	= Nothing+		, argDesc	= "Print this usage help." }++	-- Solver selection.+	, Arg	{ argIndex	= ArgSolver+		, argAbbr	= Just 's'+		, argName	= Just "solver"+		, argData	= argDataDefaulted "name" ArgtypeString "vector-naive"+		, argDesc	= "One of: list-bh, vector-naive, vector-bh, nested-bh. (default vector-naive)" }++	-- Simulation setup.+	, Arg	{ argIndex	= ArgTimeStep+		, argAbbr	= Just 't'+		, argName	= Just "timestep"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 1+		, argDesc	= "Time step between states (default 1)" }++	, Arg	{ argIndex	= ArgBodyCount+		, argAbbr	= Just 'b'+		, argName	= Just "bodies"+		, argData	= argDataDefaulted "Int" ArgtypeInt 200 +		, argDesc	= "Number of bodies in simulation (default 200)" }++	, Arg	{ argIndex	= ArgBodyMass+		, argAbbr	= Just 'm'+		, argName	= Just "mass"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 10+		, argDesc	= "Mass of each body (default 10)" }++	, Arg	{ argIndex	= ArgEpsilon+		, argAbbr	= Just 'e'+		, argName	= Just "epsilon"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 100+		, argDesc	= "Smoothing parameter (default 100)" }+		+	, Arg	{ argIndex	= ArgDiscSize+		, argAbbr	= Just 'd'+		, argName	= Just "disc"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 50+		, argDesc	= "Starting size of disc containing bodies (default 50)" }++	, Arg	{ argIndex	= ArgStartSpeed+		, argAbbr	= Just 'p'+		, argName	= Just "speed"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 0.5+		, argDesc	= "Starting rotation speed of bodies (default 0.5)" }++	, Arg	{ argIndex	= ArgMaxSteps+		, argAbbr	= Nothing+		, argName	= Just "max-steps"+		, argData	= argDataDefaulted "steps" ArgtypeInt 1000+		, argDesc	= "Exit simulation after this many steps (default 1000)" }++	, Arg	{ argIndex	= ArgDumpFinal+		, argAbbr	= Nothing+		, argName	= Just "dump-final"+		, argData	= argDataOptional "FilePath" ArgtypeString+		, argDesc	= "Dump final body positions and masses to file" }++	]
+ real/NBody/Common/Body.hs view
@@ -0,0 +1,103 @@+{-# LANGUAGE BangPatterns #-}++-- | Massful bodies in the simulation.+module Common.Body+	( Velocity+	, Accel+	, MassPoint+	, Body+	+	, accel++	, unitBody+	, massPointOfBody+	, setMassOfBody+	, setAccelOfBody+	, setStartVelOfBody+	, advanceBody)+where+import Common.Util+++-- Types ----------------------------------------------------------------------+-- We're using tuples instead of ADTs so we can put them in unboxed vectors.++-- | The velocity of a point.+type Velocity	= (Double, Double)++-- | The acceleration of a point.+type Accel	= (Double, Double)++-- | A point in 2D space with its mass.+type MassPoint	= (Double, Double, Double)++-- | Bodies consist of a MassPoint, but also carry their velocity+--   and acceleration between steps of the simulation.+type Body	= (MassPoint, Velocity, Accel)+++-- Acceleration ---------------------------------------------------------------+-- | Calculate the acceleration on a point due to some other point.+accel 	:: Double 	-- ^ Smoothing parameter.+	-> MassPoint	-- ^ The point being acclerated.+	-> MassPoint	-- ^ Neibouring point.+	-> Accel++{-# INLINE accel #-}+accel epsilon (!x1, !y1, _) (!x2, !y2, !m)  + = (aabs * dx / r , aabs * dy / r)  + where	dx   = x1 - x2 +	dy   = y1 - y2 +	rsqr = (dx * dx) + (dy * dy) + epsilon * epsilon+	r    = sqrt rsqr +	aabs = m / rsqr +++-- Body -----------------------------------------------------------------------+-- | Make a body with unit mass and zero vel and acc.+unitBody :: Double -> Double -> Body+unitBody x y+	= ((x, y, 1), (0, 0), (0, 0))+++-- | Take the MassPoint of a body.+massPointOfBody :: Body -> MassPoint+massPointOfBody (mp, vel, acc)	+	= mp+++-- | Set the mass of a body.+setMassOfBody :: Double -> Body -> Body+setMassOfBody mass ((x, y, _), vel, acc)+	= ((x, y, mass), vel, acc)+++-- | Set the acceleration of a body.+setAccelOfBody :: Accel -> Body -> Body+setAccelOfBody acc' (mp, vel, _)	+	= (mp, vel, acc')++	+-- | Set the starting velocity of a body.+--   It is set to rotate around the origin, with the speed proportional+--   to the sqrt of the distance from it. This seems to make nice simulations.+setStartVelOfBody :: Double -> Body -> Body+setStartVelOfBody startVel (mp@(x, y, mass), vel, acc)+ = let	pos		= (x, y)+	(x', y')	= normaliseV (x, y)+   	vel'		= (y', -x')+	vel''		= mulSV (sqrt (magV pos) * startVel) vel'+	+   in	(mp, vel'', acc)+++-- | Advance a body forwards in time.+advanceBody :: Double -> Body -> Body+advanceBody time +	( (px, py, mass) +	, (vx, vy) +	, acc@(ax, ay))++  =	( (px + time * vx, py + time * vy, mass)+	, (vx + time * ax, vy + time * ay)+	, acc)
+ real/NBody/Common/Dump.hs view
@@ -0,0 +1,32 @@+{-# LANGUAGE ScopedTypeVariables #-}+module Common.Dump+	(dumpWorld)+where+import Common.Body+import Common.World+import System.IO+import Data.List+import qualified Data.Vector.Unboxed	as V+++-- | Dump the bodies in a world to a file.+dumpWorld :: World -> FilePath -> IO ()+dumpWorld world filePath+ = do	h	<- openFile filePath WriteMode+	mapM_ (hWriteBody h)+		$ V.toList +		$ worldBodies world++-- | Write a single body to a file.+hWriteBody :: Handle -> Body -> IO ()+hWriteBody h ((px, py, mass), (vx, vy), (ax, ay))+ 	= hPutStrLn h +	$ concat +	$ (  (padRc 8 ' ' $ show mass)+	  :  " " : (intersperse " " $ map (padRc 22 ' ' . show) [ px, py, vx, vy, ax, ay ]))+		++-- | Right justify a doc, padding with a given character.+padRc :: Int -> Char -> String -> String+padRc n c str+	= replicate (n - length str) c ++ str
+ real/NBody/Common/Util.hs view
@@ -0,0 +1,18 @@++module Common.Util+	( magV+	, mulSV+	, normaliseV)+where+	+-- | The magnitude of a vector.+magV :: (Double, Double) -> Double+magV (x, y)	= sqrt (x * x + y * y)+	+-- | Multiply a vector by a scalar.+mulSV :: Double -> (Double, Double) -> (Double, Double)+mulSV s (x, y)	= (s * x, s * y)+	+-- | Normalise a vector, so it has a magnitude of 1.+normaliseV :: (Double, Double) -> (Double, Double)+normaliseV v	= mulSV (1 / magV v) v
+ real/NBody/Common/World.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE BangPatterns #-}++module Common.World+	( World(..)+	, advanceWorld)+where+import Common.Body+import qualified Data.Vector.Unboxed		as V++data World +	= World+	{ -- | Bodies in the simulation.+	  worldBodies	:: !(V.Vector Body)++	  -- | Number of steps taken in the simulation so far.+	, worldSteps	:: !Int }+++-- | Advance the world forward in time.+advanceWorld +	:: (V.Vector MassPoint	-> V.Vector Accel)+				-- ^ Fn to compute accelerations of each point.+	-> Double		-- ^ Time step.+	-> World+	-> World++advanceWorld calcAccels timeStep world+ = let	+	-- Calculate the accelerations on each body.+	accels	= calcAccels +		$ V.map massPointOfBody +		$ worldBodies world++	-- Apply the accelerations to the bodies and advance them.+	bodies'	= V.zipWith +		(\body (ax, ay) +			-> advanceBody timeStep+				(setAccelOfBody (-ax, -ay) body))+		(worldBodies world)+		accels++	-- Update the world.+	steps'	= worldSteps world + 1++   in	world	{ worldBodies	= bodies'+		, worldSteps	= steps' }++	
+ real/NBody/Gloss/Config.hs view
@@ -0,0 +1,74 @@++module Gloss.Config+	( Config (..)+	, loadConfig)+where+import Gloss.MainArgs+import System.Console.ParseArgs+import Data.Maybe++-- | Program config.+data Config+	= Config {+	 +	-- How to present the output.+	  configWindowSize	:: Maybe Int+	, configShouldDrawTree	:: Bool+	, configRate		:: Int++	-- What solver to use+	, configSolverName	:: String++	-- System setup+	, configBodyCount	:: Int+	, configBodyMass	:: Double+	, configTimeStep	:: Double+	, configEpsilon		:: Double++	-- Initial conditions.+	, configStartDiscSize	:: Double+	, configStartSpeed	:: Double++	-- Terminating conditions.+	, configMaxSteps	:: Maybe Int+	+	-- dump points to file+	, configDumpFinal	:: Maybe FilePath }+	++-- | Load program config from its command line arguments.	+loadConfig :: Args MainArg -> Config+loadConfig args+ = let	mWindowSize	= getArgInt	args ArgGloss+	Just solverName	= getArgString	args ArgSolver+	shouldDrawTree	= gotArg  	args ArgDrawTree+	Just timeStep	= getArgDouble	args ArgTimeStep+	Just rate	= getArgInt	args ArgRate+	Just bodyCount	= getArgInt	args ArgBodyCount+	Just bodyMass	= getArgDouble  args ArgBodyMass+	Just epsilon	= getArgDouble	args ArgEpsilon+	Just discSize	= getArgDouble	args ArgDiscSize+	Just startSpeed	= getArgDouble	args ArgStartSpeed++	mMaxSteps	= getArgInt	args ArgMaxSteps+	mFilePath	= getArgString	args ArgDumpFinal++	checkMode x+	 = if not (isJust mWindowSize || isJust mMaxSteps)+		then error "you must specify either --max-steps or --gloss <window size :: Int>"+		else x	++   in	checkMode $+	Config+	{ configWindowSize	= mWindowSize+	, configShouldDrawTree	= shouldDrawTree+	, configRate		= rate+	, configSolverName	= solverName+	, configBodyCount	= bodyCount+	, configBodyMass	= bodyMass+	, configTimeStep	= timeStep+	, configEpsilon		= epsilon+	, configStartDiscSize	= discSize+	, configStartSpeed	= startSpeed+	, configMaxSteps	= mMaxSteps +	, configDumpFinal	= mFilePath }
+ real/NBody/Gloss/Draw.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE PatternGuards #-}+-- | Drawing the world as a gloss picture.+module Gloss.Draw+	(drawWorld)+where+import Common.World+import Common.Body+import Graphics.Gloss+import qualified Solver.ListBH.Solver		as L+import qualified Data.Vector.Unboxed		as V+++-- | Radius of the circle representing each body.+pointSize :: Float+pointSize	= 4+++-- | Draw the world, and optionally show the Barnes-Hut tree.+--   NOTE: We always show the list version tree, which might not be the one+--         that's actually being used to calculate the accelerations.+--         To display the other trees we'd have to write draw functions for them,+--         or functions to convert them to the list version.+--+drawWorld :: Bool -> World -> Picture+drawWorld shouldDrawTree world+ = let	picPoints	= Color (makeColor 1 1 1 0.4)+			$ Pictures +			$ map drawBody+			$ V.toList +			$ worldBodies world++   	picTree		= drawBHTree+			$ L.buildTree +			$ map massPointOfBody+			$ V.toList +			$ worldBodies world++   in	Pictures +		[ if shouldDrawTree +			then Color (makeColor 0.5 1.0 0.5 0.2) $ picTree+			else Blank+			+		, picPoints ]+++-- | Draw a list version Barnes-Hut tree.+drawBHTree :: L.BHTree -> Picture+drawBHTree bht+ = drawBHTree' 0 bht++drawBHTree' depth bht+ = let	+	-- The bounding box+	L.Box left down right up	= L.bhTreeBox bht+	[left', down', right', up']	= map realToFrac [left, down, right, up]++	picCell		= lineLoop [(left', down'), (left', up'), (right', up'), (right', down')]+++	-- Draw a circle with an area equal to the mass of the centroid.+	centroidX	= realToFrac $ L.bhTreeCenterX bht+	centroidY	= realToFrac $ L.bhTreeCenterY bht+	+	centroidMass	= L.bhTreeMass bht+	circleRadius	= realToFrac $ sqrt (centroidMass / pi)++	midX		= (left' + right') / 2+	midY		= (up'   + down')  / 2++	picCentroid	+	 | _:_	<- L.bhTreeBranch bht+	 , depth >= 1+	 = Color (makeColor 0.5 0.5 1.0 0.4)+		$  Pictures+			[ Line [(midX, midY), (centroidX, centroidY)]+			, Translate centroidX centroidY +			$ ThickCircle+				(circleRadius * 4 / 2) +				(circleRadius * 4) ]+			+	 | otherwise+	 = Blank++	-- The complete picture for this cell.+	picHere		= Pictures [picCentroid, picCell]+		+	-- Pictures of children.+	picSubs		= map (drawBHTree' (depth + 1))+			$ L.bhTreeBranch bht++   in	Pictures (picHere : picSubs)+++-- | Draw a single body.+drawBody :: Body -> Picture+drawBody ((x, y, _), _, _)+	= drawPoint (x, y)+++-- | Draw a point using a filled circle.+drawPoint :: (Double, Double) -> Picture+drawPoint (x, y)+	= Translate (realToFrac x) (realToFrac y) +	$ ThickCircle (pointSize / 2) pointSize
+ real/NBody/Gloss/Main.hs view
@@ -0,0 +1,151 @@+{-# LANGUAGE ParallelListComp, BangPatterns #-}++import Gloss.MainArgs+import Gloss.Draw+import Gloss.Config++import Common.Dump+import Common.World+import Common.Body+import Common.Util++import Solver+import Timing+import Points2D.Generate++import Graphics.Gloss+import Graphics.Gloss.Interface.Simulate++import System.Environment+import System.Console.ParseArgs+import System.IO.Unsafe+import Control.Monad+import Data.Maybe+import qualified Data.Vector.Unboxed		as V+++main :: IO ()+main  + = do	args	<- parseArgsIO ArgsComplete mainArgs+	+	when (gotArg args ArgHelp)+	 $ usageError args ""++	mainWithArgs args+	++mainWithArgs :: Args MainArg -> IO ()+mainWithArgs args+ = let	config		= loadConfig args++	-- The solver we're using to calculate the acclerations.+	solverName	= configSolverName config+	calcAccels	= fromMaybe (error $ unlines+					[ "unknown solver " ++ show solverName+					, "choose one of "  ++ (show $ map fst solvers) ])+			$ lookup solverName solvers+	+	-- Setup initial world+	vPoints 	= genPointsDisc +				(configBodyCount config)+	 			(0, 0) +				(configStartDiscSize config)++	vBodies		= V.map (setStartVelOfBody $ configStartSpeed config)+			$ V.map (setMassOfBody     $ configBodyMass   config)+			$ V.map (uncurry unitBody) +			$ vPoints++	worldStart	= World+			{ worldBodies	= vBodies+			, worldSteps	= 0 }+				+    in	case configWindowSize config of+	 Just windowSize	-> mainGloss config calcAccels worldStart windowSize+	 Nothing		-> mainBatch config calcAccels worldStart +++-- | Run the simulation in a gloss window.+mainGloss +	:: Config+	-> Solver	-- ^ Fn to calculate accels of each point.+	-> World	-- ^ Initial world.+	-> Int		-- ^ Size of window.+	-> IO ()+	+mainGloss config calcAccels worldStart windowSize+ = let	draw	= drawWorld (configShouldDrawTree config)++	advance _viewport time world	+	 = let	world'	= advanceWorld +				(calcAccels $ configEpsilon config)+				(configTimeStep config)+				world++		-- if we've done enough steps then bail out now.+	   in	case configMaxSteps config of+	 	 Nothing		-> world'+	 	 Just maxSteps+	  	   | worldSteps world' < maxSteps	-> world'+	  +		   -- Gloss doesn't provide a clean way to end the animation...+	  	   | otherwise	+	  	   -> unsafePerformIO (mainEnd (configDumpFinal config) world' >> (error $ "done")) +			`seq` error "advanceWorld: we're finished, stop calling me."++   in	simulateInWindow+		"Barnes-Hut"		-- window name+		(windowSize, windowSize)-- window size+		(10, 10)		-- window position+		black			-- background color+		(configRate config)	-- number of iterations per second+		worldStart		-- initial world+		draw			-- fn to convert a world to a picture+		advance			-- fn to advance the world+++-- | Run the simulation in batch mode, not displaying anything to the screen.+mainBatch+	:: Config+	-> Solver		-- ^ Fn to calculate accels of each point.+	-> World		-- ^ Initial world.+	-> IO ()+	+mainBatch config calcAccels worldStart+ = do+	worldStart `seq` return ()++	(world', tElapsed)+		<- time +		$  let 	world	= mainBatchRun config calcAccels worldStart+		   in	world `seq` return world+					+	putStr $ prettyTime tElapsed+	mainEnd (configDumpFinal config) world'+	++mainBatchRun config calcAccels worldStart + = go worldStart+ where	go !world+ 	  = let world' = advanceWorld+				(calcAccels $ configEpsilon config)+				(configTimeStep config)+				world+	    in case configMaxSteps config of+		Nothing	-> go world'+		Just maxSteps+ 		  | worldSteps world' < maxSteps -> go world'+		  | otherwise 	-> world'+++-- | Called at end of run to dump final world state.+mainEnd +	:: Maybe FilePath	-- ^ Write final bodies to this file.+	-> World		-- ^ Final world state.+	-> IO ()++mainEnd mDumpFinal world+ = do	-- Dump the final world state to file if requested.+	maybe 	(return ()) (dumpWorld world) mDumpFinal++
+ real/NBody/Gloss/MainArgs.hs view
@@ -0,0 +1,113 @@++module Gloss.MainArgs+	( MainArg(..)+	, mainArgs)+where+import System.Console.ParseArgs++data MainArg+	= ArgHelp+	| ArgSolver+	| ArgMaxSteps+	| ArgTimeStep+	| ArgBodyCount+	| ArgBodyMass+	| ArgEpsilon+	| ArgDiscSize+	| ArgStartSpeed+	+	-- Gloss output+	| ArgGloss+	| ArgRate+	| ArgDrawTree+	+	-- Dump output+	| ArgDumpFinal+	deriving (Eq, Ord, Show)+	+mainArgs :: [Arg MainArg]+mainArgs+ = 	[ Arg	{ argIndex	= ArgHelp+		, argAbbr	= Just 'h'+		, argName	= Just "help"+		, argData	= Nothing+		, argDesc	= "Print this usage help." }++	-- Solver selection.+	, Arg	{ argIndex	= ArgSolver+		, argAbbr	= Just 's'+		, argName	= Just "solver"+		, argData	= argDataDefaulted "name" ArgtypeString "vector-naive"+		, argDesc	= "One of: list-bh, vector-naive, vector-bh, nested-bh. (default vector-naive)" }++	-- Simulation setup.+	, Arg	{ argIndex	= ArgTimeStep+		, argAbbr	= Just 't'+		, argName	= Just "timestep"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 1+		, argDesc	= "Time step between states (default 1)" }++	, Arg	{ argIndex	= ArgBodyCount+		, argAbbr	= Just 'b'+		, argName	= Just "bodies"+		, argData	= argDataDefaulted "Int" ArgtypeInt 200 +		, argDesc	= "Number of bodies in simulation (default 200)" }++	, Arg	{ argIndex	= ArgBodyMass+		, argAbbr	= Just 'm'+		, argName	= Just "mass"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 10+		, argDesc	= "Mass of each body (default 10)" }++	, Arg	{ argIndex	= ArgEpsilon+		, argAbbr	= Just 'e'+		, argName	= Just "epsilon"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 100+		, argDesc	= "Smoothing parameter (default 100)" }+		+	, Arg	{ argIndex	= ArgDiscSize+		, argAbbr	= Just 'd'+		, argName	= Just "disc"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 50+		, argDesc	= "Starting size of disc containing bodies (default 50)" }++	, Arg	{ argIndex	= ArgStartSpeed+		, argAbbr	= Just 'p'+		, argName	= Just "speed"+		, argData	= argDataDefaulted "Double" ArgtypeDouble 0.5+		, argDesc	= "Starting rotation speed of bodies (default 0.5)" }++	-- Termination conditions.+	, Arg	{ argIndex	= ArgMaxSteps+		, argAbbr	= Nothing+		, argName	= Just "max-steps"+		, argData	= argDataOptional "steps" ArgtypeInt+		, argDesc	= "Exit simulation after this many steps." }++	-- Gloss animation output.+	, Arg	{ argIndex	= ArgGloss+		, argAbbr	= Nothing+		, argName	= Just "gloss"+		, argData	= argDataOptional "Int" ArgtypeInt+		, argDesc	= "Animate simulation in window of this size" }++	, Arg	{ argIndex	= ArgRate+		, argAbbr	= Nothing+		, argName	= Just "gloss-rate"+		, argData	= argDataDefaulted "Double" ArgtypeInt 50+		, argDesc	= "(opt. for gloss) Number of steps per second of real time (default 50)" }++	, Arg	{ argIndex	= ArgDrawTree+		, argAbbr	= Nothing+		, argName	= Just "gloss-tree"+		, argData	= Nothing+		, argDesc	= "(opt. for gloss) Draw the Barnes-Hut quad tree"}++	-- Dump points to file+	, Arg	{ argIndex	= ArgDumpFinal+		, argAbbr	= Nothing+		, argName	= Just "dump-final"+		, argData	= argDataOptional "FilePath" ArgtypeString+		, argDesc	= "Dump final body positions and masses to file" }++	]
+ real/NBody/Solver.hs view
@@ -0,0 +1,59 @@++-- | Wrappers for the various solvers.+module Solver+	( Solver+	, solvers)+where+import Common.Body++import qualified Solver.ListBH.Solver		as SolverLB++import qualified Data.Vector.Unboxed		as V+import qualified Solver.VectorBH.Solver		as SolverVB+import qualified Solver.VectorNaive.Solver	as SolverVN++import qualified Data.Array.Parallel	as P+import qualified Data.Array.Parallel.PArray	as P+import qualified Solver.NestedBH.Solver		as SolverNB++type Solver	= Double -> V.Vector MassPoint -> V.Vector Accel++solvers :: [(String, Solver)]+solvers+ = 	[ ("list-bh",		calcAccels_lb)+	, ("vector-naive",	calcAccels_vn)+	, ("vector-bh",		calcAccels_vb)+	, ("nested-bh",		calcAccels_nb) ]+++-- | Lists + Barnes-Hut algorithm.+calcAccels_lb	:: Solver+calcAccels_lb epsilon mpts+	= V.fromList+	$ SolverLB.calcAccels epsilon+	$ V.toList mpts+++-- | Vector + Naive algorithm.+calcAccels_vn	:: Solver+calcAccels_vn epsilon+	= SolverVN.calcAccels epsilon +	++-- | Vector + Barnes-Hut algorithm.+calcAccels_vb 	:: Solver+calcAccels_vb epsilon mpts+	= SolverVB.calcAccels epsilon mpts+++-- | Nested Data Parallelism + Barnes-Hut algorithm.+calcAccels_nb	:: Solver+calcAccels_nb epsilon mpts+ = let	+	-- bounds finding isn't vectorised yet.+	(llx, lly, rux, ruy)	= SolverVB.findBounds mpts++	mpts'	= P.fromList $ V.toList mpts+	accels'	= SolverNB.calcAccelsWithBoxPA epsilon llx lly rux ruy mpts'+	+   in	V.fromList $ P.toList accels'
+ real/NBody/Solver/ListBH/Solver.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE BangPatterns, PatternGuards #-}++-- | The list version of the solver also builds the bounding box at every+--   node of the tree, which is good for visualisation.+module Solver.ListBH.Solver+	( MassPoint	(..)+	, BoundingBox	(..)+	, BHTree	(..)+	, calcAccels+	, buildTree)+where+import Common.Body++eClose :: Double+eClose  = square 500++square x = x * x++-- | A rectangular region in 2D space.+data BoundingBox+	= Box+	{ boxLowerLeftX	 :: {-# UNPACK #-} !Double+	, boxLowerLeftY	 :: {-# UNPACK #-} !Double+	, boxUpperRightX :: {-# UNPACK #-} !Double+	, boxUpperRightY :: {-# UNPACK #-} !Double }+	deriving Show+	+-- | The Barnes-Hut tree we use to organise the points.+data BHTree+	= BHT+	{ bhTreeBox	:: {-# UNPACK #-} !BoundingBox+	, bhTreeCenterX	:: {-# UNPACK #-} !Double+	, bhTreeCenterY	:: {-# UNPACK #-} !Double+	, bhTreeMass	:: {-# UNPACK #-} !Double+	, bhTreeBranch	:: ![BHTree] }+	deriving Show+++-- | Compute the acclerations on all these points.+calcAccels :: Double -> [MassPoint] -> [Accel]+calcAccels epsilon mpts+	= map (calcAccel epsilon (buildTree mpts)) mpts+	++-- | Build a Barnes-Hut tree from these points.+buildTree :: [MassPoint] -> BHTree+buildTree mpts+ = let	(llx, lly, rux, ruy)	= findBounds mpts+	box			= Box llx lly rux ruy+   in	buildTreeWithBox box mpts+++-- | Find the coordinates of the bounding box that contains these points.+findBounds :: [MassPoint] -> (Double, Double, Double, Double)+{-# INLINE findBounds #-}+findBounds ((x1, y1, _) : rest1)+ = go x1 y1 x1 y1 rest1	+ where	go !left !right !down !up pts+	 = case pts of+		[]	-> (left, down, right, up)+		(x, y, _) : rest+		 -> let	left'	= min left  x+			right'	= max right x+			down'	= min down  y+			up'	= max up    y+	   	    in	go left' right' down' up' rest+++-- | Given a bounding box that contains all the points, +--   build the Barnes-Hut tree for them.+buildTreeWithBox+	:: BoundingBox		-- ^ bounding box containing all the points.+	-> [MassPoint]		-- ^ points in the box.+	-> BHTree++buildTreeWithBox bb particles+  | length particles <= 1	= BHT bb x y m []+  | otherwise			= BHT bb x y m subTrees+  where	(x, y, m)		= calcCentroid particles+    	(boxes, splitPnts)	= splitPoints bb particles +    	subTrees		= [buildTreeWithBox bb' ps | (bb', ps) <- zip boxes splitPnts]++  +-- | Split massPoints according to their locations in the quadrants.+splitPoints+	:: BoundingBox		-- ^ bounding box containing all the points.+	-> [MassPoint]		-- ^ points in the box.+	-> ( [BoundingBox]	-- +	   , [[MassPoint]])++splitPoints b@(Box llx lly rux  ruy) particles +  | noOfPoints <= 1 = ([b], [particles])+  | otherwise         +  = unzip [ (b,p) | (b,p) <- zip boxes splitPars, length p > 0]+  where+        noOfPoints	= length particles++	-- The midpoint of the parent bounding box.+        (midx,  midy)	= ((llx + rux) / 2.0 , (lly + ruy) / 2.0) ++	-- Split the parent bounding box into four quadrants.+        b1		= Box llx  lly  midx midy+        b2		= Box llx  midy midx  ruy+        b3		= Box midx midy rux   ruy+        b4		= Box midx lly  rux  midy+        boxes		= [b1,   b2,  b3,  b4]++	-- Sort the particles into the smaller boxes.+        lls		= [ p | p <- particles, inBox b1 p ]+        lus		= [ p | p <- particles, inBox b2 p ]+        rus		= [ p | p <- particles, inBox b3 p ]+        rls		= [ p | p <- particles, inBox b4 p ]+        splitPars	= [lls, lus, rus, rls]+++-- | Check if a particle is in box (excluding left and lower border)+inBox:: BoundingBox -> MassPoint -> Bool+{-# INLINE inBox #-}+inBox (Box llx  lly rux  ruy) (px, py, _) +	= (px > llx) && (px <= rux) && (py > lly) && (py <= ruy)+++-- | Calculate the centroid of some points.+calcCentroid :: [MassPoint] -> MassPoint+{-# INLINE calcCentroid #-}+calcCentroid mpts = (sum xs / mass, sum ys / mass, mass)+  where+    mass     = sum   [ m | (_, _, m)  <- mpts ]+    (xs, ys) = unzip [ (m * x, m * y) | (x, y,  m) <- mpts ]   +++-- | Calculate the accelleration of a point due to the points in the given tree.+--   If the distance between the points is less then some small number+--   we set the accel to zero to avoid the acceleration going to infinity+--   and the points escaping the simulation. +--+--   We also use this behavior as a hacky way to discard the acceleration+--   of a point due to interaction with itself.+--+calcAccel:: Double -> BHTree -> MassPoint -> (Double, Double)	+calcAccel !epsilon (BHT _ x y m subtrees) mpt+	| []	<- subtrees+	= accel epsilon mpt (x, y, m)+	+	| not $ isClose mpt x y+	= accel epsilon mpt (x, y, m)++	| otherwise+	= let	(xs, ys)  = unzip [ calcAccel epsilon st mpt | st <- subtrees]+	  in	(sum xs, sum ys) +++-- | If the a point is "close" to a region in the Barnes-Hut tree then we compute+--   the "real" acceleration on it due to all the points in the region, otherwise+--   we just use the centroid as an approximation of all the points in the region.+--+isClose :: MassPoint -> Double -> Double -> Bool+{-# INLINE isClose #-}+isClose (x1, y1, m) x2 y2 +	= (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2) < eClose+
+ real/NBody/Solver/NestedBH/Solver.hs view
@@ -0,0 +1,154 @@+{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}+module Solver.NestedBH.Solver +	(calcAccelsWithBoxPA)+where+import Data.Array.Parallel+import Data.Array.Parallel.Prelude.Double+import qualified Data.Array.Parallel.Prelude.Int as I+import qualified Prelude++data BoundingBox	+	= Box	Double 		-- lower left  X+		Double 		-- lower left  Y+		Double		-- upper right X+		Double		-- upper right Y++data MassPoint+	= MP 	Double 		-- pos X+		Double		-- pos Y+		Double		-- mass++type Accel	+	= (Double, Double)++data BHTree+	= BHT	Double		-- size of cell+		Double		-- centroid X+		Double		-- centroid Y+		Double		-- centroid mass+		[:BHTree:]	-- children++calcAccelsWithBoxPA+	:: Double+	-> Double -> Double -> Double -> Double+	-> PArray (Double, Double, Double)+	-> PArray (Double, Double)++calcAccelsWithBoxPA epsilon llx lly rux ruy mpts+ = let	mpts'	= [: MP x y m | (x, y, m) <- fromPArrayP mpts :]+	accs'	= calcAccelsWithBox epsilon llx lly rux ruy mpts'+   in	toPArrayP accs'+	++-- | Given the extend of a bounding box containing all the points,+--   calculate the accelerations on all of them.+calcAccelsWithBox+	:: Double+	-> Double -> Double -> Double -> Double+	-> [: MassPoint :]+	-> [: Accel :]++calcAccelsWithBox epsilon llx lly rux ruy mspts+ = accs+ where	accs = [: calcAccel epsilon m tree | m <- mspts :]+	tree = buildTree (Box llx lly rux ruy) mspts+++-- | Build the Barnes-Hut quadtree tree.+buildTree :: BoundingBox -> [: MassPoint :] -> BHTree+buildTree bb particles+ | lengthP particles I.<= 1	= BHT s x y m emptyP+ | otherwise			= BHT s x y m subTrees+ where	(MP x y m)		= calcCentroid particles+	(boxes, splitPnts)	= splitPoints bb particles +    	subTrees		= [:buildTree bb' ps | (bb', ps) <- zipP boxes splitPnts:]+  +	(Box llx lly rux ruy)	= bb+	sx			= rux - llx+	sy			= ruy - lly+	s			= if sx < sy then sx else sy+++-- | Split massPoints according to their locations in the quadrants.+splitPoints+	:: BoundingBox+	-> [: MassPoint :]+	-> ([:BoundingBox:], [:[: MassPoint :]:])++splitPoints b@(Box llx lly rux  ruy) particles +  | noOfPoints I.<= 1 = (singletonP b, singletonP particles)+  | otherwise         +  = unzipP [: (b,p) | (b,p) <- zipP boxes splitPars, lengthP p I.> 0:]+  where	noOfPoints	= lengthP particles+	lls		= [: p | p <- particles, inBox b1 p :]+	lus		= [: p | p <- particles, inBox b2 p :]+	rus		= [: p | p <- particles, inBox b3 p :]+	rls		= [: p | p <- particles, inBox b4 p :]+	b1		= Box llx  lly  midx midy+	b2		= Box llx  midy midx  ruy+	b3		= Box midx midy rux   ruy+ 	b4		= Box midx lly  rux  midy+	boxes		= singletonP b1  +:+ singletonP b2  +:+ singletonP b3 +:+ singletonP b4 +	splitPars	= singletonP lls +:+ singletonP lus +:+ singletonP rus +:+ singletonP rls+	(midx,  midy)	= ((llx + rux) / 2.0 , (lly + ruy) / 2.0) +++-- | Checks if particle is in box (excluding left and lower border)+inBox :: BoundingBox -> MassPoint -> Bool+inBox (Box llx  lly rux  ruy) (MP px  py  _) + 	= (px > llx) && (px <= rux) && (py > lly) && (py <= ruy)+++-- | Calculate the centroid of some points.+calcCentroid:: [:MassPoint:] -> MassPoint+calcCentroid mpts + = MP  (sumP xs / mass) (sumP ys / mass) mass+ where	mass     = sumP [: m | MP _ _ m  <- mpts :]+	(xs, ys) = unzipP [: (m * x, m * y) | MP x y m <- mpts :]   +++-- | Calculate the accelleration of a point due to the points in the given tree.+calcAccel :: Double -> MassPoint -> BHTree -> (Double, Double)+calcAccel epsilon mpt (BHT s x y m subtrees)+	| lengthP subtrees I.== 0+	= accel epsilon mpt (MP x y m)++	| isFar mpt s x y +	= accel epsilon mpt (MP x y m)++	| otherwise+	= let	(xs, ys) = unzipP [: calcAccel epsilon mpt st | st <- subtrees :]+	  in	(sumP xs, sumP ys)+++-- | Calculate the acceleration on a point due to some other point.+accel 	:: Double 	-- ^ If the distance between the points is smaller than this+			--   then ignore the forces between them.+	-> MassPoint	-- ^ The point being acclerated.+	-> MassPoint	-- ^ Neibouring point.+	-> Accel++accel epsilon (MP x1 y1 _) (MP x2 y2 m)  + = (aabs * dx / r , aabs * dy / r)  + where	rsqr = (dx * dx) + (dy * dy) + epsilon+	r    = sqrt rsqr +	dx   = x1 - x2 +	dy   = y1 - y2 +	aabs = m / rsqr +++-- | If the point is far from a cell in the tree then we can use+--   it's centroid as an approximation of all the points in the region.+isFar 	:: MassPoint 	-- point being accelerated+	-> Double	-- size of region+	-> Double	-- position of center of mass of cell+	-> Double	-- position of center of mass of cell+	-> Bool++isFar (MP x1 y1 m) s x2 y2 + = let	dx	= x2 - x1+	dy	= y2 - y1+	dist	= sqrt (dx * dx + dy * dy)+   in	(s / dist) < 1+
+ real/NBody/Solver/VectorBH/Solver.hs view
@@ -0,0 +1,163 @@+{-# LANGUAGE BangPatterns, PatternGuards #-}++-- | The list version of the solver also builds the bounding box at every+--   node of the tree, which is good for visualisation.+module Solver.VectorBH.Solver+	( MassPoint	(..)+	, BoundingBox	(..)+	, BHTree	(..)+	, calcAccels+	, buildTree+	, findBounds)+where+import Common.Body+import Data.Vector.Unboxed			(Vector)+import qualified Data.Vector.Unboxed		as V+	+type BoundingBox+	= (Double, Double, Double, Double)+	+sizeOfBox :: BoundingBox -> Double+{-# INLINE sizeOfBox #-}+sizeOfBox (llx, lly, rux, ruy)+	= min (abs (rux - llx)) (abs (ruy - lly))+++-- | The Barnes-Hut tree we use to organise the points.+data BHTree+	= BHT+	{ bhTreeSize	:: {-# UNPACK #-} !Double	-- minimum of hight and width of cell+	, bhTreeCenterX	:: {-# UNPACK #-} !Double+	, bhTreeCenterY	:: {-# UNPACK #-} !Double+	, bhTreeMass	:: {-# UNPACK #-} !Double+	, bhTreeBranch	:: ![BHTree] }+	deriving Show+++-- | Compute the acclerations on all these points.+calcAccels :: Double -> Vector MassPoint -> Vector Accel+calcAccels epsilon mpts+ = V.map (calcAccel epsilon (buildTree mpts)) mpts+++-- | Build a Barnes-Hut tree from these points.+buildTree :: Vector MassPoint -> BHTree+buildTree mpts+	= buildTreeWithBox (findBounds mpts) mpts+++-- | Find the coordinates of the bounding box that contains these points.+findBounds :: Vector MassPoint -> (Double, Double, Double, Double)+{-# INLINE findBounds #-}+findBounds bounds+ = V.foldl' acc (x1, y1, x1, y1) bounds+ where+	(x1, y1, _)	= bounds V.! 0++	acc (!llx, !lly, !rux, !ruy) (x, y, _)+	 = let	!llx'	= min llx  x+		!lly'	= min lly  y+		!rux'	= max rux  x+		!ruy'	= max ruy  y+	   in	(llx', lly', rux', ruy')+++-- | Given a bounding box that contains all the points, +--   build the Barnes-Hut tree for them.+buildTreeWithBox+	:: BoundingBox		-- ^ bounding box containing all the points.+	-> Vector MassPoint	-- ^ points in the box.+	-> BHTree++buildTreeWithBox bb mpts+  | V.length mpts <= 1		= BHT s x y m []+  | otherwise			= BHT s x y m subTrees+  where	+	s			= sizeOfBox bb+	(x, y, m)		= calcCentroid   mpts+    	(boxes, splitPnts)	= splitPoints bb mpts+    	subTrees		= [buildTreeWithBox bb' ps+					| (bb', ps) <- zip boxes splitPnts]++  +-- | Split massPoints according to their locations in the quadrants.+splitPoints+	:: BoundingBox		-- ^ bounding box containing all the points.+	-> Vector MassPoint	-- ^ points in the box.+	-> ( [BoundingBox]	-- +	   , [Vector MassPoint])++splitPoints b@(llx, lly, rux, ruy) mpts+  | noOfPoints <= 1 = ([b], [mpts])+  | otherwise         +  = unzip [ (b,p) +		| (b,p) <- zip boxes splitPars+		, V.length p > 0]+  where+        noOfPoints	= V.length mpts++	-- The midpoint of the parent bounding box.+        (midx,  midy)	= ((llx + rux) / 2.0 , (lly + ruy) / 2.0) ++	-- Split the parent bounding box into four quadrants.+        b1		= (llx,  lly,  midx,  midy)+        b2		= (llx,  midy, midx,  ruy)+        b3		= (midx, midy, rux,   ruy)+        b4		= (midx, lly,  rux,   midy)+        boxes		= [b1,   b2,   b3,   b4]++	-- Sort the particles into the smaller boxes.+        lls		= V.filter (inBox b1) mpts+        lus		= V.filter (inBox b2) mpts+        rus		= V.filter (inBox b3) mpts+        rls		= V.filter (inBox b4) mpts+        splitPars	= [lls, lus, rus, rls]+++-- | Check if a particle is in box (excluding left and lower border)+inBox:: BoundingBox -> MassPoint -> Bool+{-# INLINE inBox #-}+inBox (llx, lly, rux, ruy) (px, py, _) +	= (px > llx) && (px <= rux) && (py > lly) && (py <= ruy)+++-- | Calculate the centroid of some points.+calcCentroid :: Vector MassPoint -> MassPoint+{-# INLINE calcCentroid #-}+calcCentroid mpts +  = (V.sum xs / mass, V.sum ys / mass, mass)+  where	mass     = V.sum   $ V.map (\(_, _, m) -> m) mpts+	(xs, ys) = V.unzip $ V.map (\(x, y, m) -> (m * x, m * y)) mpts+++-- | Calculate the accelleration of a point due to the points in the given tree.+calcAccel:: Double -> BHTree -> MassPoint -> (Double, Double)+calcAccel !epsilon (BHT s x y m subtrees) mpt+	| []	<- subtrees+	= accel epsilon mpt (x, y, m)+	+	| isFar mpt s x y+	= accel epsilon mpt (x, y, m)++	| otherwise+	= let	(xs, ys)  = unzip [ calcAccel epsilon st mpt | st <- subtrees]+	  in	(sum xs, sum ys) +++-- | If the point is far from a cell in the tree then we can use+--   it's centroid as an approximation of all the points in the region.+--+isFar 	:: MassPoint 	-- point being accelerated+	-> Double	-- size of region+	-> Double	-- position of center of mass of cell+	-> Double	-- position of center of mass of cell+	-> Bool++{-# INLINE isFar #-}+isFar (x1, y1, m) s x2 y2 + = let	!dx	= x2 - x1+	!dy	= y2 - y1+	!dist	= sqrt (dx * dx + dy * dy)+   in	(s / dist) < 1++
+ real/NBody/Solver/VectorNaive/Solver.hs view
@@ -0,0 +1,18 @@++-- | Naive n^2 computation of accelerations.+module Solver.VectorNaive.Solver+	(calcAccels)+where+import Common.Body+import Data.Vector.Unboxed		(Vector)+import qualified Data.Vector.Unboxed	as V++-- | Calculate accelerations on these point in a naive O(n^2) way+calcAccels :: Double -> Vector MassPoint -> Vector Accel+calcAccels epsilon mps+	= V.map (calcAccel epsilon mps) mps++calcAccel :: Double -> Vector MassPoint -> MassPoint -> Accel+calcAccel epsilon mps mp+ = let	(xs, ys)	= V.unzip $ V.map (accel epsilon mp) mps+   in	(V.sum xs, V.sum ys)
+ spectral/QuickHull/dph/Main.hs view
@@ -0,0 +1,59 @@++import QuickHullVect+import SVG+import Timing+import Points2D.Generate+import Points2D.Types+import System.Environment+import Data.Array.Parallel.PArray	as P++main :: IO ()+main + = do	args	<- getArgs+	case args of+	  [pointCount]	+	    -> run (read pointCount) Nothing+	+	  [pointCount, fileSVG]+	    -> run (read pointCount) (Just fileSVG)++	  _ -> do+		putStr usage+		return ()+++-- | Command line usage information.+usage :: String+usage	= unlines+	[ "Usage: quickhull <points> [out.svg]"	]+++-- | Run the benchmark.+run 	:: Int 			-- ^ How many points to use.+	-> Maybe String 	-- ^ File name to dump an SVG of the output to.+	-> IO ()+	+run pointCount mFileSVG+ = do+	vPoints	<- pointsPArrayOfUArray+		$ genPointsDisc pointCount (400, 400) 350 ++	-- Force points to create the input vector.+	vPoints `seq` return ()++	-- Compute the convex hull.+	(vHull, tElapsed)+		<- time +		$  let 	vHull	= quickhullPA vPoints+		   in	vHull `seq` return vHull+					+	-- Print how long it took.+	putStr $ prettyTime tElapsed+	+	-- If we were asked for an SVG then write it out to file.+	maybe 	(return ())+	 	(\fileSVG -> +			writeFile fileSVG+			 $ makeSVG 	(roundPoints $ P.toList vPoints) +					(roundPoints $ P.toList vHull))+		mFileSVG
+ spectral/QuickHull/dph/QuickHullVect.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}++module QuickHullVect (quickhullPA) where+import Points2D.Types+import Data.Array.Parallel+import Data.Array.Parallel.Prelude.Double+import qualified Data.Array.Parallel.Prelude.Int as Int+import qualified Prelude as P+++distance :: Point -> Line -> Double+distance (xo, yo) ((x1, y1), (x2, y2))+  = (x1-xo) * (y2 - yo) - (y1 - yo) * (x2 - xo)+++hsplit :: [:Point:] -> Line -> [:Point:]+hsplit points line@(p1, p2)+  | lengthP packed Int.== 0 = [:p1:]+  | otherwise+  = concatP [: hsplit packed ends | ends <- [:(p1, pm), (pm, p2):] :]+  where+    cross  = [: distance p line | p <- points :]+    packed = [: p | (p,c) <- zipP points cross, c > 0.0 :]+    pm     = points !: maxIndexP cross+++quickHull :: [:Point:] -> [:Point:]+quickHull points+  | lengthP points Int.== 0 = points+  | otherwise+  = concatP [: hsplit points ends | ends <- [: (minx, maxx), (maxx, minx) :] :]+  where+    xs   = [: x | (x, y) <- points :]+    minx = points !: minIndexP xs+    maxx = points !: maxIndexP xs+++quickhullPA :: PArray Point -> PArray Point+{-# NOINLINE quickhullPA #-}+quickhullPA ps = toPArrayP (quickHull (fromPArrayP ps))+
+ spectral/QuickHull/lib/SVG.hs view
@@ -0,0 +1,34 @@++module SVG where++-- Making a SVG diagram of the points and hull+makeSVG :: [(Int, Int)] -> [(Int, Int)] -> String+makeSVG points hull+	= unlines+	$  [ "<svg width=\"100%\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">" ]+	++ [svgPolygon hull]+	++ map svgPoint points+	++ map svgPointHull hull+	++ ["</svg>"]++svgPolygon  :: [(Int, Int)] -> String+svgPolygon points+	=  "<polygon"+	++ " points=\"" ++ (concat [show x ++ "," ++ show y ++ " " | (x, y) <- points]) ++ "\"" +	++ " style=\"fill:#d0d0ff;stroke:#000000;stroke-width:1\""+	++ "/>"++svgPoint :: (Int, Int) -> String+svgPoint (x, y)+	= "<circle cx=\"" ++ show x ++ "\" cy=\"" ++ show y ++ "\" r=\"0.5\""+	++ " style=\"stroke:#000000\""+	++ "/>"++svgPointHull :: (Int, Int) -> String+svgPointHull (x, y)+	= "<circle cx=\"" ++ show x ++ "\" cy=\"" ++ show y ++ "\" r=\"1\""+	++ " style=\"stroke:#ff0000\""+	++ "/>"+	+roundPoints :: [(Double, Double)] -> [(Int, Int)]+roundPoints ps = [(round x, round y) | (x, y) <- ps]
+ spectral/QuickHull/vector/Main.hs view
@@ -0,0 +1,71 @@+{-# LANGUAGE PatternGuards #-}++import qualified QuickHullVector+import qualified QuickHullIO+import qualified QuickHullSplit+import Points2D.Types+import Points2D.Generate+import Timing+import SVG++import System.Environment+import Data.Function+import qualified Data.Vector.Unboxed	as V+import Data.Vector.Unboxed		(Vector)+import Control.Monad++algs = 	[ ("vector",	(\v -> return $ QuickHullVector.quickHull v))+	, ("io",	QuickHullIO.quickHull)+	, ("split",	(\v -> return $ QuickHullSplit.quickHull v)) ]++parseArgs args+	| [alg, strCount]	<- args+	, Just fun 		<- lookup alg algs+	= Just (fun, read strCount, Nothing)++	| [alg, strCount, file]	<- args+	, Just fun 		<- lookup alg algs+	= Just (fun, read strCount, Just file)++	| otherwise+	= Nothing+++main :: IO ()+main+ = do	argStrs		<- getArgs+	case parseArgs argStrs of+	 Just args	-> run args+	 _ 		-> putStr $ unlines+				[ "usage: quickhull <alg> <points> [out.svg]"+				, "   algs: " ++ (show $ map fst algs) ++ "\n" ]++run ::	( Vector Point -> IO (Vector Point)+	, Int+	, Maybe FilePath)+    ->	IO ()+	+run (fun, pointCount, mFileSVG) + = do+	let vPoints	= genPointsDisc pointCount (400, 400) 350 ++	-- Force points to create the input vector.+	V.force vPoints `seq` return ()++	-- Compute the convex hull.+	(vHull, tElapsed)+	 	<- time+		$  do	vHull	<- fun vPoints+		     	vHull `seq` return vHull+		+	-- Print how long it took	+	putStr $ prettyTime tElapsed++	-- If we were asked for an SVG then write it out to file.+	maybe 	(return ())+	 	(\fileSVG -> +			writeFile fileSVG+			 $ makeSVG 	(roundPoints $ V.toList vPoints) +					(roundPoints $ V.toList vHull))+		mFileSVG+
+ spectral/QuickHull/vector/QuickHullIO.hs view
@@ -0,0 +1,269 @@+{-# LANGUAGE BangPatterns, PatternGuards, RankNTypes #-}++module QuickHullIO+	(quickHull)+where+import Data.Function+import Control.Monad+import Control.Exception+import Control.Concurrent+import Control.Concurrent.MVar+import Control.Monad.ST+import GHC.Conc+import Data.IORef+import Data.List+import Data.Ord+import Data.Vector.Unboxed			(Vector)+import qualified Data.Vector.Unboxed		as V+import qualified Data.Vector.Unboxed.Mutable	as MV+import qualified Data.Vector.Generic		as G+import Debug.Trace++type Point	= (Double, Double)+type Line	= (Point, Point)+++-- | Compute the convex hull of a vector of points.+quickHull :: Vector Point -> IO (Vector Point)+quickHull !points+  | V.length points == 0	+  = return points++  | otherwise+  = do	-- Find the left and right-most points.+	let (minx, maxx) 	= minmax points++	-- Hull points get written to the vector in this IORef.+	hullRef	<- newIORef V.empty++	-- Fork off computations to handle half of the points each.+	-- For uniformly distributed points this first iteration takes most of the time.+	parIO 	[ hsplit hullRef points minx maxx+		, hsplit hullRef points maxx minx]++	-- Grab the finished hull points.+	hull	<- readIORef hullRef++	-- We've got the hull points, but they can appear in arbitrary order.+	-- Do a rubbish via-lists merge phase so that they appear clockwise around the edge.+	-- This isn't too expensive if there aren't many points on the hull.+	let (above, below) +		= V.unstablePartition +			(\p -> distance minx maxx p > 0)+			hull+	+	let aboveSorted	= V.fromList $ sortBy (comparing fst) $ V.toList above+	let belowSorted	= V.fromList $ sortBy (comparing fst) $ V.toList below+	let hull' = aboveSorted V.++ V.reverse belowSorted++	return hull'+	++hsplit :: IORef (Vector Point) -> Vector Point -> Point -> Point -> IO ()+{-# INLINE hsplit #-}+hsplit hullRef !points !p1@(!p1X, !p1Y) !p2@(!p2X, !p2Y)+	-- we've found one.+	| V.length packed == 0+	= addHullPoint hullRef p1+	+	-- do the two new segments in parallel.+	| V.length packed > 1000+	= parIO+		[ hsplit hullRef packed p1 pm+		, hsplit hullRef packed pm p2 ]+		+	| otherwise+	= do	hsplit hullRef packed p1 pm+		hsplit hullRef packed pm p2++	where	(packed, pm)	= parPackPoints points p1X p1Y p2X p2Y+	++-- | Copy points from the input vector that are on the left of the line into a+--	new buffer. While we're doing this, determine the point that is furthest+--	from the line.+--+--	If we have a big enough vector then split it in two and do both halves+--	in parallel. Doing this requires a copy afterwards to join the two+--	results back together. It's a trade off between decreased FP load and +--	increased memory traffic. +--+parPackPoints +	:: Vector Point +	-> Double -> Double+	-> Double -> Double+	-> ( Vector Point+	   , Point)+	+{-# INLINE parPackPoints #-}+parPackPoints !points !p1X !p1Y !p2X !p2Y+ |   numCapabilities == 1+  || V.length points < 1000+ = packPoints p1X p1Y p2X p2Y points++ | otherwise+ = let	+	numSegments	= numCapabilities++	-- Total number of points to process.+	lenPoints	= V.length points++	-- How many points to process in each segment.+	lenSeg		= lenPoints `div` numSegments++ 	-- If the total number of points doesn't divide evenly into segments+	-- then there may be an odd number. Make sure to get the rest into the last segment.+	splitPacked count ixStart +	    | count == 0	= []++	    | count == 1	+	    = let points'		= V.unsafeSlice ixStart (lenPoints - ixStart) points+	      	  result@(packed', _)	= packPoints p1X p1Y p2X p2Y points'+	      in  packed' `pseq` (result : [])++	    | otherwise	+	    = let points'		= V.unsafeSlice ixStart lenSeg points+	          result@(packed', _)	= packPoints p1X p1Y p2X p2Y points'+		  rest			= splitPacked (count - 1) (ixStart + lenSeg)+	      in  packed' `par` rest `par` (result : rest)++	results	= splitPacked numSegments 0+	vResult	= concatVectors $ map fst results+	pMax	= selectFurthest p1X p1Y p2X p2Y results+	+   in	(vResult, pMax)+++selectFurthest + 	:: Double -> Double +	-> Double -> Double+	-> [(Vector Point, Point)] +	-> Point+	+selectFurthest !p1X !p1Y !p2X !p2Y ps+ = go (0, 0) 0 ps++ where	go pMax !distMax []	+	 = pMax++	go pMax !distMax ((packed, pm):rest)+	 | V.length packed == 0+	 = go pMax distMax rest+	+	 | otherwise+	 , dist		<-  distance (p1X, p1Y) (p2X, p2Y) pm +  	 = if dist > distMax+		then go pm   dist    rest+		else go pMax distMax rest+++packPoints +	:: Double -> Double 		-- First point on dividing line.+	-> Double -> Double 		-- Second point on dividing line.+	-> Vector Point 		-- Source points.+	-> ( Vector Point		-- Packed vector containing only points on the left of the line.+	   , Point)			-- The point on the left that was furthest from the line.++{-# INLINE packPoints #-}+packPoints !p1X !p1Y !p2X !p2Y !points + = let+	result	+	 = G.create + 	 $ do	packed		 <- MV.new (V.length points + 1)+		(pMax, ixPacked) <- fill points packed p1X p1Y p2X p2Y 0 0++		-- We stash the maximum point on the end of the vector to get+		-- it through the create call.+		MV.unsafeWrite packed ixPacked pMax+		return $ MV.unsafeSlice 0 (ixPacked + 1) packed+	+   in	( V.unsafeSlice 0 (V.length result - 1) result+	, result `V.unsafeIndex` (V.length result - 1))+			++fill 	:: forall s+	.  Vector Point 		-- Source points.+	-> MV.MVector s Point 		-- Vector to write packed points into.+	-> Double -> Double 		-- First point on dividing line.+	-> Double -> Double		-- Second poitn on dividing line.+	-> Int 				-- Index into source points to start reading from.+	-> Int				-- Index into packed points to start writing to.+	-> ST s +		( Point			-- Furthest point from the line that was found.+		, Int)			-- The number of packed points written.++{-# INLINE fill #-}+fill !points !packed !p1X !p1Y !p2X !p2Y !ixPoints' !ixPacked'+ = go (0, 0) 0 ixPoints' ixPacked'+ where go pMax !distMax !ixPoints !ixPacked+	| ixPoints >= V.length points	+	= do	return (pMax, ixPacked)+		+	| p	<- points `V.unsafeIndex` ixPoints+	, d	<- distance (p1X, p1Y) (p2X, p2Y) p+	, d > 0+	= do	MV.unsafeWrite packed ixPacked p+		if d > distMax+		 then	go p    d       (ixPoints + 1) (ixPacked + 1)+		 else	go pMax distMax (ixPoints + 1) (ixPacked + 1)+			+	| otherwise+	= go pMax distMax (ixPoints + 1) ixPacked+++minmax :: Vector Point -> (Point, Point)+{-# INLINE minmax #-}+minmax !vec+ = go first first 0+ where	first	= vec V.! 0++	go pMin@(!minX, !minY) pMax@(!maxX, !maxY) !ix+	  | ix >= V.length vec	= (pMin, pMax)++	  | (x, y)	<- vec `V.unsafeIndex` ix+	  = if       x < minX then go (x, y) pMax   (ix + 1)+	    else if  x > maxX then go pMin   (x, y) (ix + 1)+	    else go pMin pMax (ix + 1)+	++distance :: Point -> Point -> Point -> Double+{-# INLINE distance #-}+distance (x1, y1) (x2, y2) (xo, yo)+  = (x1-xo) * (y2 - yo) - (y1 - yo) * (x2 - xo)+++addHullPoint :: IORef (Vector Point) -> Point -> IO ()+addHullPoint hullRef p+ = atomicModifyIORef hullRef+ $ \hull -> (V.singleton p V.++ hull, ())++++-- Can't find an equivalent for this in Control.Concurrent.+parIO :: [IO ()] -> IO ()+parIO stuff+ = do	mVars	<- replicateM (length stuff) newEmptyMVar+	zipWithM_ (\c v -> forkIO $ c `finally` putMVar v ()) stuff mVars+	mapM_ readMVar mVars+	++-- We really want a function in the vector library for this.+concatVectors :: [Vector Point] -> Vector Point+{-# NOINLINE concatVectors #-}+concatVectors vectors+ = G.create+ $ do	let len	= sum $ map V.length vectors+	vOut	<- MV.new len+	go vectors vOut 0+	return vOut++ where	{-# INLINE go #-}+	go [] _ _+	 = return ()++	go (vSrc:vsSrc) vDest !ixStart	+	 = do	let lenSrc	= V.length vSrc+		let vDestSlice	= MV.unsafeSlice ixStart lenSrc vDest+		V.copy vDestSlice vSrc+		go vsSrc vDest (ixStart + lenSrc) +
+ spectral/QuickHull/vector/QuickHullSplit.hs view
@@ -0,0 +1,38 @@++module QuickHullSplit+	(quickHull)+where+import qualified Data.Vector.Unboxed	as V+import Data.Vector.Unboxed		(Vector)++quickHull :: Vector (Double, Double) -> Vector (Double, Double)+quickHull vv+	= uncurry V.zip $ quickhull $ V.unzip vv++quickhull :: (Vector Double, Vector Double) -> (Vector Double, Vector Double)+{-# NOINLINE quickhull #-}+quickhull (xs, ys) = xs' `seq` ys' `seq` (xs',ys')+    where+      (xs',ys') = V.unzip+                $ hsplit points pmin pmax V.++ hsplit points pmax pmin++      imin = V.minIndex xs+      imax = V.maxIndex xs++      points = V.zip xs ys+      pmin   = points V.! imin+      pmax   = points V.! imax+++      hsplit points p1 p2+        | V.length packed < 2 = p1 `V.cons` packed+        | otherwise = hsplit packed p1 pm V.++ hsplit packed pm p2+        where+          cs     = V.map (\p -> cross p p1 p2) points+          packed = V.map fst+                 $ V.filter (\t -> snd t > 0)+                 $ V.zip points cs++          pm     = points V.! V.maxIndex cs++      cross (x,y) (x1,y1) (x2,y2) = (x1-x)*(y2-y) - (y1-y)*(x2-x)
+ spectral/QuickHull/vector/QuickHullVector.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE BangPatterns, PatternGuards #-}++module QuickHullVector+	(quickHull)+where+import Points2D.Types+import Data.Function+import Data.Vector.Unboxed		as V+import Data.Vector.Unboxed.Mutable	as MV+import Data.Vector.Unboxed		(Vector)+import qualified Data.Vector.Generic	as G+import System.IO.Unsafe++++distance :: Point -> Point -> Point -> Double+{-# INLINE distance #-}+distance (x1, y1) (x2, y2) (xo, yo)+  = (x1-xo) * (y2 - yo) - (y1 - yo) * (x2 - xo)+++hsplit :: Vector Point -> Point -> Point -> Vector Point+{-# INLINE hsplit #-}+hsplit !points !p1@(!p1X, !p1Y) !p2@(!p2X, !p2Y)+ = let !packed	= packPoints points p1X p1Y p2X p2Y+   in  if V.length packed == 1+	 then V.singleton p1+	 else 	let pm		= packed `V.unsafeIndex` (V.length packed - 1)+		    packed'	= V.unsafeSlice 0 (V.length packed - 1) packed+		in  hsplit packed' p1 pm V.++ hsplit packed' pm p2+++packPoints :: Vector Point -> Double -> Double -> Double -> Double -> Vector Point+{-# INLINE packPoints #-}+packPoints !points !p1X !p1Y !p2X !p2Y+ = G.create + $ do	packed	<- MV.new (V.length points + 1)+	+	-- stash the furthest point on the end of the returned vector.	+	let fill !pMax !distMax !ixPoints !ixPacked+		| ixPoints >= V.length points	+		= do	MV.unsafeWrite packed ixPacked pMax+			return $ MV.unsafeSlice 0 (ixPacked + 1) packed++		| p	<- points `V.unsafeIndex` ixPoints+		, d	<- distance (p1X, p1Y) (p2X, p2Y) p+		, d > 0+		= do	MV.unsafeWrite packed ixPacked p+			if d > distMax+			 then	fill p    d       (ixPoints + 1) (ixPacked + 1)+			 else	fill pMax distMax (ixPoints + 1) (ixPacked + 1)+			+		| otherwise+		= fill pMax distMax (ixPoints + 1) ixPacked+			+	fill (0, 0) 0 0 0+++quickHull :: Vector Point -> Vector Point+quickHull !points+  	| V.length points == 0	= points++	| (minx, maxx) 		<- minmax points+	= hsplit points minx maxx V.++ hsplit points maxx minx+++minmax :: Vector Point -> (Point, Point)+{-# INLINE minmax #-}+minmax !vec+ = go first first 0+ where	first	= vec V.! 0++	go pMin@(!minX, !minY) pMax@(!maxX, !maxY) !ix+	  | ix >= V.length vec	= (pMin, pMax)++	  | (x, y)	<- vec `V.unsafeIndex` ix+	  = if       x < minX then go (x, y) pMax   (ix + 1)+	    else if  x > maxX then go pMin   (x, y) (ix + 1)+	    else go pMin pMax (ix + 1)+	
+ spectral/QuickSort/dph/Main.hs view
@@ -0,0 +1,50 @@++import QuickSortVect+import Timing+import Randomish+import System.Environment+import Data.Vector.Unboxed		(Vector)+import Data.Array.Parallel	as P+import Data.Array.Parallel.PArray	as P+import qualified Data.Vector.Unboxed	as V+import Data.Maybe++main :: IO ()+main + = do	args	<- getArgs+	case args of+	  [len]	-> run (read len) +	  _	-> putStr usage+++-- | Command line usage information.+usage :: String+usage	= unlines+	[ "Usage: quicksort <length>" ]+++-- | Run the benchmark.+run :: Int -> IO ()+run len+ = do	-- Create the input vector+	let vInts 	= fromUArrPA'+			$ randomishDoubles len 0 1 1234++	vInts `seq` return ()++	-- Compute the convex hull.+	(vSorted, tElapsed)+		<- time +		$  let 	vSorted	= quicksortPA vInts+		   in	vSorted `seq` return vSorted+					+	-- Print how long it took.+	putStr $ prettyTime tElapsed+	+	-- Check they're really sorted.+	print	$ isSorted $ P.toUArrPA vSorted+	++-- | Check if a vector is sorted (monotonically increasing)+isSorted :: Vector Double -> Bool+isSorted = isJust . V.fold1M (\x y -> if y >= x then Just y else Nothing)
+ spectral/QuickSort/dph/QuickSortVect.hs view
@@ -0,0 +1,25 @@+{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}+{-# OPTIONS -fno-spec-constr-count #-}+module QuickSortVect (quicksortPA) where++import Data.Array.Parallel+import Data.Array.Parallel.Prelude.Double+import qualified Data.Array.Parallel.Prelude.Int as I++import qualified Prelude++quicksortPA:: PArray Double -> PArray Double +quicksortPA xs = toPArrayP  (qsortVect' (fromPArrayP xs))++qsortVect':: [: Double :] -> [: Double :]+{-# NOINLINE qsortVect' #-}+qsortVect' xs | lengthP xs I.<=  1 = xs+              | otherwise =+  let p  = xs !: (lengthP xs `I.div` 2)+      ls = [:x | x <- xs, x < p:]+      gs = [:x | x <- xs, x > p:]++      ss = mapP qsortVect' [:ls, gs:]+ in+ (ss !: 0) +:+ [:x | x <- xs, x == p:] +:+ (ss !: 1)
+ spectral/SMVM/dph/Main.hs view
@@ -0,0 +1,102 @@+{-# LANGUAGE ScopedTypeVariables #-}++import Timing+import SMVMVectorised+import System.IO+import Foreign.Storable+import Foreign.Marshal.Alloc+import Data.Array.Parallel.PArray	as P+import Data.Array.Parallel+import qualified Data.Array.Parallel.Unlifted as U+import System.Environment+import Control.Exception (evaluate)++main :: IO ()+main + = do	args	<- getArgs+	case args of+	  [fileName] -> run fileName+	  _	     -> usage+	+usage	+ = putStr $ unlines+	[ "usage: smvm <file>" ]++run fileName+ = do	(matrix, vector) <- loadPA fileName++	matrix `seq` return ()+	vector `seq` return ()++	-- Multiply sparse matrix by the dense vector.+	(vResult, tElapsed)+	 <- time $ let result	= smvmPA matrix vector+		   in  P.nf result `seq` return result+					+	-- Print how long it took.+	putStr $ prettyTime tElapsed++	-- Print some info about the test setup.+	putStrLn $ "vector length   = " ++ show (U.length (toUArrPA vector))+--	putStrLn $ "matrix height   = " ++ show (U.length (toUArrPA matrix))+	+	+	-- Print checksum of resulting vector.+	putStrLn $ "result sum      = " ++ show (U.sum (toUArrPA vResult))++++-- | Load a test file containing a sparse matrix and dense vector.+loadPA 	:: String 				-- ^ filename.+	-> IO  ( PArray (PArray (Int, Double))	-- sparse matrix+	       , PArray Double)			-- dense vector++loadPA fileName+ = do 	(segd, arrMatrixElems, arrVector) <- loadUArr fileName++    	let paMatrix	= nestUSegdPA' segd (fromUArrPA_2' arrMatrixElems)+	let paVector	= fromUArrPA' arrVector+	return (paMatrix, paVector)+++-- | Load a test file containing a sparse matrix and dense vector.+loadUArr :: String				-- ^ filename+	 -> IO ( U.Segd				-- segment descriptor saying what array elements+						--    belong to each row of the matrix.+	       , U.Array (Int, Double)		-- column indices and matrix elements+	       , U.Array Double)		-- the dense vector++loadUArr fname + = do	h <- openBinaryFile fname ReadMode++	-- check magic numbers at start of file to guard against word-size screwups.+	alloca $ \ptr -> do+		hGetBuf h ptr (sizeOf (undefined :: Int))+		magic1 :: Int	<- peek ptr+		hGetBuf h ptr (sizeOf (undefined :: Int))+		magic2	:: Int <- peek ptr+		if magic1 == 0xc0ffee00 Prelude.&& magic2 == 0x12345678 +			then return ()+			else error $ "bad magic in " ++ fname++	-- number of elements in each row of the matrix.+	lengths <- U.hGet h++	-- indices of all the elements.+	indices <- U.hGet h++	-- values of the matrix elements.+	values  <- U.hGet h++	-- the dense vector.+	vector  <- U.hGet h++	evaluate lengths+	evaluate indices+	evaluate values+	evaluate vector++	let segd    = U.lengthsToSegd lengths+	    matrix  = U.zip indices values++	return (segd, matrix, vector)
+ spectral/SMVM/dph/SMVMVectorised.hs view
@@ -0,0 +1,18 @@++{-# LANGUAGE ParallelArrays #-}+{-# OPTIONS -fvectorise #-}+module SMVMVectorised (smvmPA) where++import Data.Array.Parallel+import Data.Array.Parallel.Prelude.Double as D+import Data.Array.Parallel.Prelude.Int    as I++import qualified Prelude as P++smvmPA :: PArray (PArray (Int, Double)) -> PArray Double -> PArray Double+{-# NOINLINE smvmPA #-}+smvmPA m v = toPArrayP (smvm (fromNestedPArrayP m) (fromPArrayP v))++smvm :: [:[: (Int, Double) :]:] -> [:Double:] -> [:Double:]+smvm m v = [: D.sumP [: x D.* (v !: i) | (i,x) <- row :] | row <- m :]+