John Kozak | 1 Jul 12:53 2004

some newbie FFI questions

I'm trying to experiment with image processing in haskell (with which
I haven't much experience).  I've written some FFI code to talk to
the ImageMagick library which provokes a few questions (environment is
ghc 6.2.1 on debian):

1. Speed: I'm reading in a 2000x1500 pixel image, and have defined a
   Pixel type like this:

data Pixel a = Pixel !a !a !a deriving Show

  I use ImageMagick to load the image, then build an Array of Pixel
  Floats.  Building the array takes 45 seconds on a 2.5Ghz P4 with
  code compiled -O2, which seems slow to me - are my expectations
  unrealistic?  I've tried various UNPACK things which didn't make
  much difference.

2. How do I convert a CFloat into a Float?

3. I get the wrong answer ;-)  I expect the C and haskell code below
   to produce the same pixel data, but they don't (the C code is right).

C code:

#include <stdio.h>
#include <wand/magick_wand.h>

int main(int argc,char *argv[])
{
    MagickWand *wand = NewMagickWand();
    int         width,height;
(Continue reading)

Ketil Malde | 1 Jul 13:16 2004
Picon
Picon

Re: some newbie FFI questions

John Kozak <jk <at> xylema.org> writes:

> data Pixel a = Pixel !a !a !a deriving Show

>   I use ImageMagick to load the image, then build an Array of Pixel
>   Floats.  Building the array takes 45 seconds on a 2.5Ghz P4 with
>   code compiled -O2, which seems slow to me - are my expectations
>   unrealistic?  I've tried various UNPACK things which didn't make
>   much difference.

Are you using UArrays?  If you're going to read the whole image
anyway, they will probably be faster than the normal arrays.

Also, I read somewhere that operations are often specialized for
Double but not Float - since you talk about image loading rather than
processing, it may be worth it to use Floats to save space, even if
Doubles could be faster.

-kzm
--

-- 
If I haven't seen further, it is by standing in the footprints of giants
MR K P SCHUPKE | 1 Jul 13:30 2004
Picon

Re: some newbie FFI questions

If you are using GHC the fastest way I know to do this
is to build the array using a mutable-unboxed array in the
state-monad. Then freeze the array and return an
unboxed immutable array. This is a lot faster than
building the array by copying (every time you set a
value in an immutable array the whole array much be
copied - for a sizeable image this is quite a lot of
work!)

	Keean.
MR K P SCHUPKE | 1 Jul 13:34 2004
Picon

Re: some newbie FFI questions

Oh... also when using unboxed arrays you may well have
to have a separate array for each colour plane (r,g,b,a)
as I think unboxed arrays can only contain primitive types - although
I am not certain about this - it may be enough to have the
contents strict.

	Keean.
Duncan Coutts | 1 Jul 13:56 2004
Picon
Picon

Re: some newbie FFI questions

On Thu, 2004-07-01 at 12:34, MR K P SCHUPKE wrote:
> Oh... also when using unboxed arrays you may well have
> to have a separate array for each colour plane (r,g,b,a)
> as I think unboxed arrays can only contain primitive types - although
> I am not certain about this - it may be enough to have the
> contents strict.

Sadly arrays of unboxed records are not currently possible. The only
instances for MArray / IArray with unboxed arrays are simple primitive
types.

See the instances for mutable arrays:
http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data.Array.MArray.html#1
and for imutable arrays
http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data.Array.IArray.html#1

I don't think it is easy for non-ghc hackers to add extra instances.

Intuitively it seems obvious that user defined types that are just
products of unboxable types are also unboxable. Being able to say
'deriving Unboxable' would be nice...

Duncan
MR K P SCHUPKE | 1 Jul 14:26 2004
Picon

Re: some newbie FFI questions

Yes, deriving unboxable would be nice... I think for images though
it is not too much of a problem to work with a record of arrays
rather that an array of records. 

	Keean.
Simon Marlow | 1 Jul 16:33 2004
Picon

RE: some newbie FFI questions

On 01 July 2004 11:53, John Kozak wrote:

> I'm trying to experiment with image processing in haskell (with which
> I haven't much experience).  I've written some FFI code to talk to
> the ImageMagick library which provokes a few questions (environment is
> ghc 6.2.1 on debian):
> 
> 1. Speed: I'm reading in a 2000x1500 pixel image, and have defined a
>    Pixel type like this:
> 
> data Pixel a = Pixel !a !a !a deriving Show
> 
>   I use ImageMagick to load the image, then build an Array of Pixel
>   Floats.  Building the array takes 45 seconds on a 2.5Ghz P4 with
>   code compiled -O2, which seems slow to me - are my expectations
>   unrealistic?  I've tried various UNPACK things which didn't make
>   much difference.

It depends how you want to use the image data, but this is almost
certainly not the best representation.

The fastest choice would be simply 'Ptr CFloat' (i.e. do no conversion
or marshalling at all).  This is essentially what your C program is
doing.  In Haskell you can allocate the memory using allocaBytes or
mallocForeignPtr (no free required).

Your other choices are:

 - IOUArray Int Float
   Fast access, but you need to convert the entire array into one
(Continue reading)

Crypt Master | 1 Jul 18:01 2004
Picon

Newbie questions


Hi

I consider myself a pretty good imperative programmer, been at it for 
decades, and am tryibng my hand at Haskell now. Unfrituantly I am not 
"getting" it all that quickly despite having the multimedia haskell book.

To start ghetting some hands on, I thought iI owuld do something which i 
have done many times before in imperatives, a basic Genetic Algorithm 
Library. Unfortunatly I am comming unstuck straight away and was hoping some 
of you kind folk could point in the direction of dry land :-)

iIf your not familiar with GAs its not too important, simply a GA searches 
over the whole solution space randomly. Well not quiet, its a guided search, 
its guided by evolution ie by the fitness of each indicidual of a random 
initial population. Evolution is simulated by 3 basic operators, selection, 
cross over and mutation. selection is which indiviuals get to breed, cross 
over is how they breed, and mutation is just things intetresting.

So after reading the multimedia book, Iimmediately thought of a defining the 
solution space as a infinite list. I was hoping then I could do things like 
take 5 gaSolutionSpace to get 5 iterations or generations. My first attempt 
tied to use lis syntax [], but it wouldnt compile and after seeing 
"numsFrom" ina  tutorial I redefined it as such. Here is what I have so far:

-- gaSolutionSpace :: [a] -> [a]
-- gaSolutionSpace [] = gaSolutionSpace createRandomPopulation -- recursive 
base case
gaSolutionSpace x = x : gaSolutionSpace (evolvepopulation x)

(Continue reading)

Crypt Master | 1 Jul 18:01 2004
Picon

Newbie questions


Hi

I consider myself a pretty good imperative programmer, been at it for 
decades, and am tryibng my hand at Haskell now. Unfrituantly I am not 
"getting" it all that quickly despite having the multimedia haskell book.

To start ghetting some hands on, I thought iI owuld do something which i 
have done many times before in imperatives, a basic Genetic Algorithm 
Library. Unfortunatly I am comming unstuck straight away and was hoping some 
of you kind folk could point in the direction of dry land :-)

iIf your not familiar with GAs its not too important, simply a GA searches 
over the whole solution space randomly. Well not quiet, its a guided search, 
its guided by evolution ie by the fitness of each indicidual of a random 
initial population. Evolution is simulated by 3 basic operators, selection, 
cross over and mutation. selection is which indiviuals get to breed, cross 
over is how they breed, and mutation is just things intetresting.

So after reading the multimedia book, Iimmediately thought of a defining the 
solution space as a infinite list. I was hoping then I could do things like 
take 5 gaSolutionSpace to get 5 iterations or generations. My first attempt 
tied to use lis syntax [], but it wouldnt compile and after seeing 
"numsFrom" ina  tutorial I redefined it as such. Here is what I have so far:

-- gaSolutionSpace :: [a] -> [a]
-- gaSolutionSpace [] = gaSolutionSpace createRandomPopulation -- recursive 
base case
gaSolutionSpace x = x : gaSolutionSpace (evolvepopulation x)

(Continue reading)

Duncan Coutts | 1 Jul 18:29 2004
Picon
Picon

Re: Newbie questions

On Thu, 2004-07-01 at 17:01, Crypt Master wrote:
> I consider myself a pretty good imperative programmer, been at it for 
> decades, and am tryibng my hand at Haskell now. Unfrituantly I am not 
> "getting" it all that quickly despite having the multimedia haskell book.

[snip]

> The take operator doesnt work on this. from hugs:
> 
> HAGA> take 5 gaSolutionSpace [1,2,3,4,5]
> ERROR - Type error in application
> *** Expression     : take 5 gaSolutionSpace [1,2,3,4,5]
> *** Term           : take
> *** Type           : Int -> [e] -> [e]
> *** Does not match : a -> b -> c -> d

What this error message is telling you is this:
      * The 'take' function wants two parameters, an Int and a list of
        some type '[e]'. It will give you back a list of the same type
      * You have given it three parameters, or to put it another way you
        are using 'take' as if it had type 'a -> b -> c -> d' (for some
        a,b,c & d)

The solution then is to just pass two arguments. How do you do that?
In what you've written can you see that you're passing 3 arguments?
take 5 gaSolutionSpace [1,2,3,4,5]

People say function application in Haskell is written without brackets
but this can be misleading, here you do need brackets to indicate that
'gaSolutionSpace [1,2,3,4,5]' is one argument and not two. So you should
(Continue reading)


Gmane