BlogJamun – Thinks Aloud

thinking feverishly for a tagline..

Inversions problem – haskell way

Given an array of numbers A, we need to find the number of distinct pairs such that,
i < j,  A[i] > A[j]
The naive algorithm would be to make ‘n’ choose 2 comparisons and determine the number of inversions in them. This has a worst case complexity of O(n^2).
We can do better than that by modifying merge sort algorithm, which has a worst case complexity of O(nlogn). That takes care of introduction to the problem and the solution.
I learned haskell but never really used it. It was fading away like high school math did. This problem provided the opportunity to dust some manuals and read some bookmarked sites on programming in haskell. The fun I get out of writing small programs in haskell is that, it allows me to think of a problem without knowing how a computer works. All imperative programming languages need you to understand that you manipulate system’s memory to get the desired result.
The following is an implementation of the solution in haskell:
‘imerge’ takes two sorted lists and returns a tuple containing number of inversions present in the merged list and the merged list.

‘imsort’ takes a list and it’s length and returns a tuple containing number of inversions present in the initial list and the sorted list.

imerge :: (Ord a) => [a] -> [a] -> (Int, [a])
imerge [] bs = (0, bs)
imerge as [] = (0, as)
imerge (a:as) (b:bs)
	| a == b = (fst (imerge as bs), a:b:snd (imerge as bs))
	| a < b = (fst (imerge as (b:bs)), a:snd (imerge as (b:bs)))
	| otherwise = (length (a:as) + (fst (imerge (a:as) bs)), b:snd (imerge (a:as) bs))

imsort :: (Ord a) => [a] -> Int -> (Int, [a])
imsort [a] 1 = (0, [a])
imsort a n = ((fst algo) + (fst (imsort (drop r a) (n-r))) + (fst (imsort (take r a) r)), snd algo )
	where r = n `div` 2
              algo = imerge (snd (imsort (take r a) r)) (snd (imsort (drop r a) (n-r)))

sort :: (Ord a) => [a] -> [a]
sort a = snd (imsort a (length a))

inversions :: (Ord a) => [a] -> Int
inversions a = fst (imsort a (length a))

I hope to see some haskell experts come by and comment on the code.

Advertisement

September 6, 2010 - Posted by | haskell | ,

3 Comments »

  1. I haven’t done any Haskell, but I’ve done some ML programming and I can read some parts. How easy would you rate this attempt in comparison to say C++?
    Also, did you try running this on large inputs? – I just wanted to get a feel for the performance of a functional programming language. I can see that some tail recursions could be optimized in this code.

    Comment by Karthik Swaminathan | September 6, 2010 | Reply

    • Thinking in haskell is different from thinking in C/C++. It was difficult to avoid the natural tendency for me to think in C/C++.
      I just now ran the inversion function for [1000000,99999..1] and almost ran out of memory. Not the best of implementations in haskell.
      This post was actually written a long while back. Finally made up mind on posting it :-)

      Comment by blogjamun | September 6, 2010 | Reply

      • Interesting.. Maybe it was using too much of stack memory, without doing a lot of compiler optimizations. My take on performance of functional languages is mostly with the efficiency of the compiler in generating fast target code.
        Thanks for running those tests for my sake! :)

        Comment by Karthik Swaminathan | September 6, 2010


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.