»
S
I
D
E
B
A
R
«
STUArray woes
Jan 30th, 2009 by axman6

So a little while ago, I was trying to write a nice, clear version of the language shootout n-body problem, using the ST monad, and STUArrays. Though I ran into a snag; I was getting segmentation faults, for very small values of n (< 23), and not knowing enough about such things, I have no idea where to begin in diagnosing the problem. So, I shall post my code here, and hope that someone might have some ideas. I’ve talked to Don Stewart about it, but he hasn’t got back to me yet. (All the MUArray instance stuff is from Don’s work, which I nicked) So, here we have it:

> {-# OPTIONS -O2 -funbox-strict-fields #-}
> {-# LANGUAGE BangPatterns          #-}
> {-# LANGUAGE UnboxedTuples         #-}
> {-# LANGUAGE MagicHash             #-}
> {-# LANGUAGE MultiParamTypeClasses #-}
>
> module Main where
>
> import System.Environment
> import Data.Array.Base
> import GHC.Exts
> import GHC.ST
> import GHC.Arr
> import Control.Monad
> import Control.Monad.ST
> import Data.List
> import Foreign.Storable
> import Text.Printf
> import Data.STRef
>
>
> data Vec3 = V !Double !Double !Double deriving (Show)
> data Body = B {
>                  pos ::  {-# UNPACK #-} !Vec3,
>                  vel ::  {-# UNPACK #-} !Vec3,
>                  mass :: !Double
>                } deriving (Show)
>
>
> main = do
>     n <- getArgs >>= \xs -> if null xs then return 1000 else (readIO.head) xs
>     let (e,e') = runST $ do
>             ps <- planets
>             offset ps
>             e1 <- energy ps
>             advn n ps
>             e2 <- energy ps
>             return (e1,e2)
>     prtnum e
>     prtnum e'
>
>
> offset ps = do
>     v <- newSTRef (V 0 0 0)
>     (B p ve m) <- readArray ps 0
>     forM_ [0..numPs] $ \i -> do
>         p <- readArray ps i
>         modifySTRef v (.+. momentum p)
>     modifySTRef v (./ solar_mass)
>     v' <- readSTRef v
>     writeArray ps 0 (B p (ve.-. v') m)
>
>
>
> advn 0 ps = do
>     return ps
> advn n ps = do
>     advance deltat ps
>     -- e <- energy ps
>     -- unsafeIOToST (prtnum e)
>     advn (n-1) ps
>
> advance dt ps = do
>     forM_ [0..numPs] $ \i -> do
>         (B p v m) <- readArray ps i
>         vvar <- newSTRef v
>         forM_ [i+1..numPs] $ \j -> do
>             (B p' v' m') <- readArray ps j
>             let dp = p .-. p'
>                 dst = mag dp
>                 magnit = dt / (dst  dst  dst)
>                 change = magnit . dp
>                 sca1 = m' . change
>                 sca2 = m . change
>             -- writeArray ps I (B p (v .-. sca1) m)
>             modifySTRef vvar (.-. sca1)
>             writeArray ps j (B p' (v' .+. sca2) m')
>         vvar' <- readSTRef vvar
>         writeArray ps I (move dt (B p vvar' m))
>
>
> energy ps = do
>     e <- newSTRef (0 :: Double)
>
>     forM_ [0..numPs] $ \i -> do
>         b1 <- readArray ps i
>         modifySTRef e ((+) (kinetic b)1)
>
>         forM_ [i+1..numPs] $ \j -> do
>             b2 <- readArray ps j
>             let x = potential b1 b2
>             modifySTRef e (subtract x)
>     e' <- readSTRef e
>     return e'
>
>
>
> move dt (B p v m) = B (p .+. dt . v) v m
>
>
>
>
> -----------------------
> solar_mass, deltat, days_per_year :: Double
> days_per_year = 365.24
> dp = days_per_year
> solar_mass    = 4  pi  pi
> deltat       = 0.01
> numPs       = length planets' - 1
>
> planets'' = newArray_ (0,numPs) :: ST s (STUArray s Int Body)
>     -- (B (V 0 0 0) (V 0 0 0) 1)
>
> planets = do
>     arr <- planets''
>     forM_ (zip [0..] planets') $ \(i,p) -> do
>         writeArray arr I p
>     return arr
>
> planets' =
>     [B  (V  0.0
>             0.0
>             0.0)
>         (V  0.0
>             0.0
>             0.0)
>         solar_mass,
>
>      B  (V  4.84143144246472090e+00
>             (-1.16032004402742839e+00)
>             (-1.03622044471123109e-01))
>         (V  (1.66007664274403694e-03dp)
>             (7.69901118419740425e-03dp)
>             ((-6.90460016972063023e-05)dp))
>         (9.54791938424326609e-04  solar_mass),
>
>      B  (V  8.34336671824457987e+00
>             4.12479856412430479e+00
>             (-4.03523417114321381e-01))
>         (V  ((-2.76742510726862411e-03)dp)
>             (4.99852801234917238e-03dp)
>             (2.30417297573763929e-05dp))
>         (2.85885980666130812e-04  solar_mass),
>
>      B  (V  1.28943695621391310e+01
>             (-1.51111514016986312e+01)
>             (-2.23307578892655734e-01))
>         (V  (2.96460137564761618e-03dp)
>             (2.37847173959480950e-03dp)
>             ((-2.96589568540237556e-05)dp))
>         (4.36624404335156298e-05  solar_mass),
>
>      B  (V  1.53796971148509165e+01
>             (-2.59193146099879641e+01)
>             1.79258772950371181e-01)
>         (V  (2.68067772490389322e-03dp)
>             (1.62824170038242295e-03dp)
>             ((-9.51592254519715870e-05)dp))
>         (5.15138902046611451e-05  solar_mass)
>     ]
>
>
> -----------------------
>
> infix 4 .-.
> infix 4 .+.
> -- infix 5 ..
> infixr 5 .
> infixl 5 ./
>
> {-# INLINE (.+.) #-}
> {-# INLINE (.-.) #-}
> -- {-# INLINE (..) #-}
> V x y z .+. V x' y' z' = V (x+x') (y+y') (z+z')
> V x y z .-. V x' y' z' = V (x-x') (y-y') (z-z')
> -- V x y z .. V x' y' z' = V (xx') (yy') (zz')
>
> {-# INLINE (.) #-}
> n . (V x y z) = V (nx) (ny) (nz)
> {-# INLINE (./) #-}
> V x y z ./ n = V (x/n) (y/n) (z/n)
>
> {-# INLINE momentum #-}
> momentum :: Body -> Vec3
> momentum (B _ v m) = m . v
>
> {-# INLINE kinetic #-}
> kinetic x =  0.5  mass x  (mag2.vel) x
>
>
> potential a b =
>     let dst = dist' a b
>     in if dst <= 0
>         then 0
>         else (mass a  mass b) / dist' a b
>
> {-# INLINE mag #-}
> mag :: Vec3 -> Double
> mag = sqrt . mag2
>
> {-# INLINE mag2 #-}
> mag2 (V x y z) = xx + yy + zz
>
> {-# INLINE dist #-}
> dist v1 v2 = sqrt $ dist2 v1 v2
>
> {-# INLINE dist2 #-}
> dist2 v1 v2 = mag2 $ v1 .-. v2
>
> {-# INLINE dist' #-}
> dist' b1 b2 = dist (pos b1) (pos b2)
>
> prtnum x = putStrLn $ printf "%.9f" x
>
> --------------------
> bodyScale :: Int# -> Int#
> bodyScale n = (scale # 7#) *# n
>      where I# scale = sizeOf (undefined :: Double)
>
> instance MArray (STUArray s) Body (ST s) where
>
>     {-# INLINE getBounds #-}
>     getBounds (STUArray l h _ _) = return (l,h)
>
>     {-# INLINE getNumElements #-}
>     getNumElements (STUArray _ _ n _) = return n
>
>     {-# INLINE unsafeNewArray_ #-}
>     unsafeNewArray_ (l,u) = unsafeNewArraySTUArray_ (l,u) bodyScale -- bytes 
>
>     {-# INLINE newArray_ #-}
>     newArray_ bounds = newArray bounds (B (V 0 0 0) (V 0 0 0) 1)
>
>
>     {-# INLINE unsafeRead #-}
>     unsafeRead (STUArray _ _ _ arr) (I# i) = ST $ \s1 ->
>         let j = bodyScale i in
>         case readDoubleArray# arr j         s1 of { (# s2, xd    #) ->
>         case readDoubleArray# arr (j +# 1#) s2 of { (# s3, yd    #) ->
>         case readDoubleArray# arr (j +# 2#) s3 of { (# s4, zd    #) ->
>         case readDoubleArray# arr (j +# 3#) s4 of { (# s5, vxd   #) ->
>         case readDoubleArray# arr (j +# 4#) s5 of { (# s6, vyd   #) ->
>         case readDoubleArray# arr (j +# 5#) s6 of { (# s7, vzd   #) ->
>         case readDoubleArray# arr (j +# 6#) s7 of { (# s8, massd #) ->
>         (# s8, B { pos    = V (D# xd) (D# yd) (D# zd)
>                     , vel    = V (D# vxd) (D# vyd) (D# vzd)
>                     , mass = D# massd } #) }}}}}}}
>
>     {-# INLINE unsafeWrite #-}
>     unsafeWrite (STUArray _ _ _ arr) (I# i)
>                 (B (V (D# xd) (D# yd) (D# zd)) (V (D# vxd) (D# vyd) (D# vzd)) (D# massd))
>         = ST $ \s1 ->
>         let j = bodyScale i in
>         case writeDoubleArray# arr j          xd   s1  of {s2 ->
>         case writeDoubleArray# arr (j +# 1#)  yd   s2  of {s3 ->
>         case writeDoubleArray# arr (j +# 2#)  zd   s3  of {s4 ->
>         case writeDoubleArray# arr (j +# 3#) vxd   s4  of {s5 ->
>         case writeDoubleArray# arr (j +# 4#) vyd   s5  of {s6 ->
>         case writeDoubleArray# arr (j +# 5#) vzd   s6  of {s7 ->
>         case writeDoubleArray# arr (j +# 6#) massd s7  of {s8 ->
>         (# s8, () #) }}}}}}}
> 

Software lockdown!
Jan 29th, 2009 by axman6

I’ve just read Marcus S. Zarra’s post about software licencing, piracy and stupidity (to paraphrase), and I think he’s hit the nail right on the head.

Treating potential customers like potential thieves makes them feel more inclined to follow these feeling. I’ll admit that I’ve pirated software, but I’ve also bought a lot of it too. The stuff I’ve pirated is uaually something that I feel is far overpriced for what they offer. Like Marcus says, software is something you make once, and sell thousands of times; it’s making money from nothing. The things I’ve bought are usually pretty cheap, and that makes me want to buy them, I want to help the developer and reward them for making something which is useful to me, and reasonably priced, or even a bargain.

I do not like being forced to buy your software. I do not like being forced to buy your software to use it for something that is useful, but not exactly (or at all) worth paying $30 for. Nor do I like being told that I have not bought your software. Give me the full thing to try, without restrictions, at all, give me a month and see if I feel I need it. If after that month, (and that’s a month of use, not a month from the date of download), I feel I need your software, then I will buy it. If I never hit that month, then no, I will not be buying it, it has not been useful enough for me to consider it. Doesn’t mean it’s not great, or that it’s buggy and annoying (I will tell you if it is), it just means I have no ude for it.

I’ll take an example, VMware Fusion. Now, this is made by a very large company, a big, corporate business, that makes expensive software for some rather important tasks. But what happened when Fusion v2.0 came out? they gave it to us for free! I, and I’m sure many others would have paid for this update, they did a lot of work for it, added some very nice new features. But instead of them saying “hey! they’re getting new stuff, they HAVE to pay!”, they seemed to take the stance that these new features were missing features, and that v2.0 was heading towards making the program more complete, rather than expanding it.

This is an excellent example of how I feel software licencing should work. Be nice to your customers, give them treats, and they will do more than stay quiet about your products, they will tell their friends, or anyone they know who might be interested. They feel an affinity with you and your software, and will go the point of arguing and fighting over which is better, your product, or someone else’s. Loyalty will always bring you more than fear, and being nice will bight you in the arse far less often than being a dick.

I don’t think I have summed this up as well as Marcus managed to (I’ve just written this from start to finish, and can’t be bothered to re-read it [pan's labyrinth awaits]), but I did feel like showing my support for his views, because he got how I feel so right.

Anyway, more later

~ Axman

Hendo has a blog!
Jan 26th, 2009 by axman6

So, we’ve just finished setting up Hendo’s new bacon blog. Here’s what she has to say about it:

Me: So do you like you new blog?
Hendo: Yup, it’s pretty!
Me: Yes it is… -_-

Yep, she sure is cute. Anyway, hopefully she’ll keep up with it (and so will I). So check it out!

Pen joy
Jan 25th, 2009 by axman6

Sp for my birthday last November, my girlfriend bought me a very lovely new pen. It is a lovely Acme pen, the Blueprint one on that page (my studying Engineering/IT ‘n all). For christmas, she bought me the fountain pen nib replacement, and far out, I love it! I’ve never used a fountain pen before, but they are just wonderful. I can’t say what it is about it that I like, but it feels so much more natural than a ballpoint. fountain-pen.jpg

This, added with the shear weight of the thing makes it the perfect writing tool, it’s quite a leap from my normal Lamp Spirit pencil, which I still love also.

now i’m not one for writing my hand much, my hand writing is pathetically unreadable most of the time, but I do enjoy fine stationary, and this seems like it could be something that turns into somewhat of an addiction…

I just finished installing Movable Type 4!
Jan 24th, 2009 by axman6

Welcome to my new blog powered by Movable Type. This is the first post on my blog and was created for me automatically when I finished the installation process. But that is ok, because I will soon be creating posts of my own!

New router and Seagate niceness
Jan 24th, 2009 by axman6

So last night, my girlfriend’s dad gave me an old XP machine they didn’t have a need for. Turns out it has fairly decent specs, so I got to work  installing FreeBSD on it. In the next few days, i shall be turning it into my new web server, and possibly putting my blog back on it (although it’ll be slower to serve it there, i can at least install plugins, which I’m still pissed off about with this blog). In the mean time though, i have been installing pfSense on the machine that was my web server. the specs of the old one are as follows:

  • 500MHz Pentium II
  • 196MB RAM
  • 8GB HDD
  • 2x RealTek 100Mbit NICs

and the new one:

  • 2.4GHz Pentium 4
  • 512MB RAM
  • 6GB HDD
  • 1 sis0 onboard NIC
  • 1RealTek NIC

so basically it’s a much faster machine (though now I come to think of it, maybe swapping the disks wouldn’t be a bad idea). So what you say? Well, what I wanted to tell you is that pfSense is awesomely easy to use, it’s wonderful. the webGUI is well laid out and works very well, installing new packages like nmap, spamd, bandwidthd, OpenBGPD etc. is as easy as visiting the web interface and clicking a button. You get some nice graphs about most aspects of system performance (though they haven’t been working for me, not sure why, getting no data).

The other thing I was going to mention is how nice Seagate’s warranty returns site is. Our 250GB drive died recently (not sure when, it was hooked up to the web server and i never used it), so I checked to see if it was still under warranty. Just sick in the model number and serial number, and they’ll tell you exactly when the  warranty ends. If you need to return it, you can go through two or three pages, choose the nearest point of contact for their repairs, and then print out a label with the address and your return address to stick on your parcel. They even give you wrapping instructions which is nice (though they seem to insist that you use a “SeaShell” plastic case to put the drive in, which of course I don’t own).

So, in the next few days, hopefully I’ll have a nice new web server, running my blog and being awesome!

Not much has been happening in the last year
Jan 21st, 2009 by axman6

So i was talking to my girlfriend today about my blog, after I showed it to her last night. She was not pleased. I had neglected to mention her at all, and she did not appreciate it. So now I am making an effort to make it up to my lovely, beautiful, amazing girlfriend of a year and a month, Sarah. I love you Sarah! In other news, Happy Obama Day. About time the US did something right.

Why the GPL is not free
Jan 21st, 2009 by axman6
I assert though that the GPL does not give us freedom, merely different restrictions.  I even assert that it does not give us all of the freedoms listed above.  In this post, I will argue that the GPL is inherently flawed when it comes to freeing software.

My good IRC friend Beelsebob decided independently to start a new blog, on the exact same say I did, but hopefully I Beelsebob’d him this time!* Anyway, he’s made a better start than I have by writing a nice article on why the GPL is in fact not free, but just restricting you in a different way. So go ahead and read the article

Wordpress.com is lame >_<
Jan 20th, 2009 by axman6

Ok, so my plans to get things like markdown working have been shot. I had no idea Wordpress.com was so lame, I thought they might at least allow you to add some plugins, but nooooo. oh well, I’ll make do.

ST Monad examples
Jan 20th, 2009 by axman6

So, I’m wanting to put more examples on the Monad/ST page on the Haskell wiki, but I’m not sure what else I can do with it that’s simple. I’ve been using Haskell for too long to remember what sort of problems I’d write statefully! So, if you have any ideas, either let me know, or just post them on the wiki! My first example is:

import Control.Monad.ST
import Data.STRef
import Control.Monad
 
 
sumST :: Num a => [a] -> a
sumST xs = runST $ do           -- runST takes out stateful code and makes it pure again.
n <- newSTRef 0             -- Create an STRef (place in memory to store values)
forM_ xs $ x -> do         -- For each element of xs ..
-- (forM_ is just flip mapM_)
modifySTRef n (+x)      -- add it to what we have in n.
readSTRef n                 -- read the value of n, and return it.

which is a version of the sum function, that uses the ST monad to update a variable in place, but also run in a purely functional way (notice the lack of ST in the type signature) And foldl and Fibonacci using ST:

foldlST :: (a -> b -> a) -> a -> [b] -> a
foldlST f acc xs = runST $ do
acc' <- newSTRef acc            -- Create a variable for the accumulator
forM_ xs $ x -> do             -- For each x in xs...
a <- readSTRef acc'         -- read the accumulator
writeSTRef acc' (f a x)     -- apply f to the accumulator and x
readSTRef acc'                  -- and finally read the result
fibST :: Integer -> Integer
fibST n =
if n < 2
then n
else runST $ do
x <- newSTRef 0
y <- newSTRef 1
fibST' n x y
where fibST' 0 x _ = readSTRef x
fibST' n x y = do
x' <- readSTRef x
y' <- readSTRef y
writeSTRef x y'
writeSTRef y (x'+y')
fibST' (n-1) x y

*Output created by HsColor

»  Substance: WordPress   »  Style: Ahren Ahimsa
© Alex Mason (Axman6) 2009