caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Comments welcomed to progr. style / speed of my first ocaml program "Error correcting LDPC decoder"
@ 2005-12-15 10:33 Andries Hekstra
       [not found] ` <OFB50A01B3.ECDA5A94-ONC12570D8.00394FEA-C12570D8.003A2427@philips.com >
  2005-12-16 19:35 ` Jon Harrop
  0 siblings, 2 replies; 5+ messages in thread
From: Andries Hekstra @ 2005-12-15 10:33 UTC (permalink / raw)
  To: caml-list


[-- Attachment #1.1: Type: text/plain, Size: 1277 bytes --]

Dear All,

I am an applied scientist in the areas of signal processing and error 
correction at Philips Research. Having done the programming work of my 
computer simulations in C/C++ for almost 10-15 years with increasingly 
mixed feelings about the languange, a friend pointed me to functional 
programming. This way I found ocaml and I must say I am very enthusiastic 
about it. The built-in arrays, the functions that are really meta 
functions and remove a lot of tedious programming and debugging. Also the 
combined availability of an interpreter and compiler is comforbable and 
not unlike matlab (which I hate). 

I am also intrigued by the promise of functional languages when multi-core 
computers will be the defacto standard. 

Attached please find the first program I wrote. It has about the same 
speed as its C++ counterpart (slightly faster). I welcome comments w.r.t. 
programming style, esp. when it affects the speed of the program.

Regards,

Andries Hekstra




------------------------------------------------------------------------
Dr. Ir. Andries P. Hekstra
Philips Research 
High Tech Campus 37 
5656 AG Eindhoven
Tel./Fax/Secr. +31 40 27 42048/42566/44051 

If you need anti-RSI break software : Look at http://www.workrave.org 
(good and for free)

[-- Attachment #1.2: Type: text/html, Size: 1628 bytes --]

[-- Attachment #2: Main.ml --]
[-- Type: application/octet-stream, Size: 16249 bytes --]

(* Parameters of the LDPC code, left and right degree*)
let    ldpc_j = 3
let    ldpc_k = 30
let    codeRate = 1. -. float_of_int ldpc_j /. float_of_int ldpc_k
let    targetCodewordLength = (ldpc_k * 300)
let    blockSize = targetCodewordLength / ldpc_k
let    codewordLength = blockSize * ldpc_k
let    numberOfParityChecks = blockSize * ldpc_j
let    fudgeFactor = 0.75
let    maxNumberOfIterations = 30
;;

print_string "LDPC decoder for rate 1 - ";
print_int ldpc_j;
print_string "/";
print_int ldpc_k;
print_string " Gallager code with length ";
print_int codewordLength;
flush stdout
;;

(* Construction of a sparse parity check matrix*)
let height a = Array.length a
let width a = Array.length a.(0)

let applyToMatrix f a =
    let rec applyToMatrixAux i j f a = 
        if (i >= 0) then begin 
            a.(i).(j) <- f i j a.(i).(j); 
            if (j-1 >= 0) 
                then applyToMatrixAux i     (j-1)         f a 
                else applyToMatrixAux (i-1) (width a - 1) f a
        end
        in applyToMatrixAux (height a - 1) (width a - 1) f a

let order =       Array.create_matrix ldpc_j codewordLength 0
let permutation = Array.create_matrix ldpc_j codewordLength 0
;;

applyToMatrix (fun j -> fun i -> fun x -> (Random.int (100 * codewordLength))) order;; 
applyToMatrix (fun j -> fun i -> fun x -> i) permutation;;

let swapElement i j a = let x = a.(i) in a.(i) <- a.(j); a.(j) <- x

let qsort op a = 
    let l = Array.length a in     
    let rec qsortAux i j op a =
        if (i < j) then begin 
            let x = a.((i + j) / 2) in
            let i1 = ref i in
            let j1 = ref j in                                
            
            while (!i1 <= !j1) do 
                while (op a.(!i1) x) do incr i1 done;
                while (op x a.(!j1)) do decr j1 done;
                if (i1 <= j1) then begin
                    swapElement !i1 !j1 a; 
                    incr i1;
                    decr j1
                end
            done;                                        
            
            qsortAux !i1 j op a;
            qsortAux i !j1 op a;                                 
         end                
        in qsortAux 0 (l - 1) op a;;

let qsort2 op a b = 
    let l = Array.length a in     
    let rec qsort2Aux i j op a b =
        if (i < j) then begin 
            let x = a.((i + j) / 2) in
            let i1 = ref i in
            let j1 = ref j in
                            
            while (!i1 <= !j1) do 
                while (op a.(!i1) x) do incr i1 done;
                while (op x a.(!j1)) do decr j1 done;
                if (i1 <= j1) then begin
                    swapElement !i1 !j1 a; 
                    swapElement !i1 !j1 b; 
                    incr i1;
                    decr j1
                 end
            done;                            
            qsort2Aux !i1 j op a b;
            qsort2Aux i !j1 op a b;        
        end                
        in qsort2Aux 0 (l - 1) op a b;;

let sortRows a = 
    let rec sortRowsAux i a = if (i >= 0) then begin qsort (<) a.(i); sortRowsAux (i-1) a end  
        in sortRowsAux (Array.length a - 1) a

let sortRows2 a b = 
    let rec sortRows2Aux i a b = if (i >= 0) then begin qsort2 (<) a.(i) b.(i); sortRows2Aux (i-1) a b end  
        in sortRows2Aux (Array.length a - 1) a b;;

sortRows2 order permutation;;                                                                                

let inversePermutation = Array.create_matrix ldpc_j codewordLength 0;;

for j = 0 to ldpc_j - 1 do
    for i = 0 to codewordLength - 1 do 
        inversePermutation.(j).(permutation.(j).(i)) <- i
    done
done;;     

let oneColumnInRow = Array.create_matrix numberOfParityChecks ldpc_k 0;;
let jOneColumnInRow = Array.create_matrix numberOfParityChecks ldpc_k 0;;

    (* Here, i indexes parity checks *)
applyToMatrix (fun i -> fun k -> fun x -> inversePermutation.(i / blockSize).(k + ldpc_k * (i mod blockSize))) oneColumnInRow;;
applyToMatrix (fun i -> fun k -> fun x -> i / blockSize) jOneColumnInRow;;

sortRows2 oneColumnInRow jOneColumnInRow;;

let oneRowInColumn = Array.create_matrix codewordLength ldpc_j 0;;
let kOneRowInColumn = Array.create_matrix codewordLength ldpc_j 0;;

for j = 0 to ldpc_j-1 do
    for r = 0 to blockSize -1 do 
        let i = r + j * blockSize in 
        for k = 0 to ldpc_k-1 do
            oneRowInColumn .(oneColumnInRow.(i).(k)).(j) <- i;
            kOneRowInColumn.(oneColumnInRow.(i).(k)).(j) <- k;
        done                        
    done
done;;

sortRows2 oneRowInColumn kOneRowInColumn;;

let numberOfColumnPairsWithOverlap = ref 0;; 
for i1 = 0 to codewordLength - 1 do
    for i2 = 0 to i1-1 do
        let overlap = ref 0 in begin 
            for j1 = 0 to ldpc_j-1 do
                for j2 = 0 to ldpc_j-1 do
                    if (oneRowInColumn.(i1).(j1) = oneRowInColumn.(i2).(j2)) then incr overlap;
                done
            done;
            if (!overlap > 1) then incr numberOfColumnPairsWithOverlap;
        end        
    done
done;;
print_string "\nnumberOfColumnPairsWithOverlap = ";;
print_int !numberOfColumnPairsWithOverlap;;

(* Random bit vector *)
let bitArrayFromInt n iii = 
    let rec bitArrayFromIntAux i n iii = 
        if (i < n) then 
            Array.append [| (iii mod 2) |]  (bitArrayFromIntAux (i+1) n (iii / 2)) 
        else [||]
        in bitArrayFromIntAux 0 n iii 

let makeRandomBit a = 
    let rec makeRandomBitAux i a = 
        if (i > 0) then begin
            let b = bitArrayFromInt 8 (Random.int 256) in
            let i1 = ref i in 
            let count = ref 0 in begin       
                while (!i1 >= 0) & (!count < 8) do
                    a.(!i1) <- b.(!count);
                    decr i1;
                    incr count;
                done;
                makeRandomBitAux !i1 a
            end    
        end         
    in makeRandomBitAux (Array.length a - 1) a

(* Normal distribution *)    
let randomGaussian sigma =
    let u1 = Random.float 1. in
    let u2 = Random.float 1. in        
    let r = sqrt (-2. *. log (u1)) in
    let pi = 2. *. asin 1. in
    let phi = 2. *. pi *. u2 
        in sigma *. r *. cos (phi)        
         
(* Message passing functions *)
let sum a = let rec sum i a = if (i > 0) then a.(i) +. sum (i-1) a else if (i = 0) then a.(i) else 0.
    in sum ((Array.length a) - 1) a
let hardBit softBit = if (softBit >= 0.) then 0 else 1
let reliability softBit = if (softBit >= 0.) then softBit else (-. softBit)

(* LDPC decode *)
let softBitOut channelLLR1 messageSymbolNodeIn1 = channelLLR1 +. sum messageSymbolNodeIn1 
let hardBitOut channelLLR1 messageSymbolNodeIn1 = hardBit (softBitOut channelLLR1 messageSymbolNodeIn1)         

let processCheckNode channelLLR 
                     oneColumnInRow 
                     jOneColumnInRow
                     syndrome  
                     messagesSymbolNodeIn 
                     messageCheckNodeIn 
                     messageCheckNodeOut = 
                     
    let messageSymbolNodeOut channelLLR1 messageSymbolNodeIn1 j = 
            (softBitOut channelLLR1 messageSymbolNodeIn1) -. messageSymbolNodeIn1.(j) in begin
            
        (* Get the input messages to the current check node *)
        for k = 0 to ldpc_k-1 do 
            messageCheckNodeIn.(k) <- fudgeFactor *. 
                                          (messageSymbolNodeOut channelLLR.(oneColumnInRow.(k)) 
                                                                messagesSymbolNodeIn.(oneColumnInRow.(k)) 
                                                                jOneColumnInRow.(k))                                    
        done; 

        (* Compute the total EXOR, the min. and second min. reliability and the index *)
        let k1 = ref 0 in  
        let minReliability1 = ref 1e10 in 
        let minReliability2 = ref 1e10 in
        let totalExor = ref syndrome in begin                
           
            for k = 0 to ldpc_k-1 do 
                totalExor := !totalExor + hardBit messageCheckNodeIn.(k);
                
                let h = reliability messageCheckNodeIn.(k) in  
                    if !minReliability1 >= h then begin
                        minReliability2 := !minReliability1;
                        minReliability1 := h;
                        k1 := k;
                    end else begin
                        if !minReliability2 >= h then minReliability2 := h                                
                    end
            done; 
        
            totalExor := !totalExor mod 2;          
            
            (* Compute the output messages *)
            for k = 0 to ldpc_k-1 do 
                let h = if k = !k1 then !minReliability2 else !minReliability1 in
                    if ((!totalExor + (hardBit messageCheckNodeIn.(k))) mod 2) = 0 then
                        messageCheckNodeOut.(k) <- h
                    else 
                        messageCheckNodeOut.(k) <- (-. h)
            done;
            
            (* Assign the output messages *)
            for k = 0 to ldpc_k-1 do 
                messagesSymbolNodeIn.(oneColumnInRow.(k)).(jOneColumnInRow.(k)) <- messageCheckNodeOut.(k); 
            done;
            
            (!totalExor = 0)    
        end
    end 
          
let ldpcDecode transmittedCodeword 
               syndrome
               channelLLR 
               decodedCodeword 
               oneColumnInRow 
               jOneColumnInRow 
               messagesSymbolNodeIn 
               numberOfIterations =
    
    let messageCheckNodeIn = Array.create ldpc_k 0. in
    let messageCheckNodeOut = Array.create ldpc_k 0. in
    let allZeroesSyndrome = ref false in begin
        numberOfIterations := 0;
    
        while (!numberOfIterations < maxNumberOfIterations) & not !allZeroesSyndrome do 
            allZeroesSyndrome := true;
            for row = 0 to numberOfParityChecks - 1 do 
                if not (processCheckNode channelLLR 
                                         oneColumnInRow.(row) 
                                         jOneColumnInRow.(row) 
                                         syndrome.(row)
                                         messagesSymbolNodeIn
                                         messageCheckNodeIn
                                         messageCheckNodeOut) then
                    allZeroesSyndrome := false;                    
            done;    
            incr numberOfIterations;
        done;  
        
        let numberOfBitErrors = ref 0 in begin
            for column = 0 to codewordLength - 1 do
                decodedCodeword.(column) <- hardBitOut channelLLR.(column) messagesSymbolNodeIn.(column);
                if (decodedCodeword.(column) <> transmittedCodeword.(column)) then
                    incr numberOfBitErrors;    
            done;
    
            !numberOfBitErrors;   
        end
    end
        
(* Simulation parameters *)
let ebOverNoDbLow = 3.4
let ebOverNoDbHigh = 4.
(*let ebOverNoDbLow = 10.0
let ebOverNoDbHigh = 10.0*)
let ebOverNoDbStep = 0.1
let numberOfCodewordsToSimulate = 30000

let ebOverNoDb = ref ebOverNoDbLow
let totalNumberOfFrameErrors = ref 1  
;;

while (!ebOverNoDb <= ebOverNoDbHigh) & (!totalNumberOfFrameErrors > 0) do

    print_string "\n\nEbOverNoDb = ";
    print_float  !ebOverNoDb;    
    print_string ", time = ";
    print_float (Sys.time());
    print_string " seconds!\n";
    flush stdout;

    let ebOverNo = 10. ** (!ebOverNoDb /. 10.) in 
    let lc = 4. *. ebOverNo *. codeRate in 
    let sigmaNoise = 1. /. sqrt (2. *. ebOverNo *. codeRate) in 
    
    let totalNumberOfChannelBitErrors = ref 0. in
    let totalNumberOfBits = ref 0. in
    let totalNumberOfDecodedBitErrors = ref 0. in 
    let totalNumberOfFrames = ref 0 in 
    let totalNumberOfIterations = ref 0. in 
        
    let transmittedCodeword = Array.create codewordLength 0 in 
    let decodedCodeword = Array.create codewordLength 0 in 
    let syndrome = Array.create numberOfParityChecks 0 in 
    let channelLLR = Array.create codewordLength 0. in 
    
    let messagesSymbolNodeIn = Array.create_matrix codewordLength ldpc_j 0. in begin
    
        totalNumberOfFrameErrors := 0; 
    
        while (!totalNumberOfFrames < numberOfCodewordsToSimulate) 
                & ((!totalNumberOfDecodedBitErrors < 500.) or (!totalNumberOfFrameErrors < 200)) do    
        
            makeRandomBit transmittedCodeword;
                                
            for r = 0 to numberOfParityChecks-1 do
                syndrome.(r) <- 0;
                for k = 0 to ldpc_k-1 do
                    syndrome.(r) <- ((syndrome.(r) + transmittedCodeword.(oneColumnInRow.(r).(k))) mod 2)
                done
            done;
            
            for i = 0 to codewordLength - 1 do
                channelLLR.(i) <- float_of_int (1 - 2*transmittedCodeword.(i)) +. randomGaussian sigmaNoise
            done;
            
            let numberOfChannelBitErrors = ref 0 in begin
                for i = 0 to codewordLength-1 do
                    if transmittedCodeword.(i) <> hardBit channelLLR.(i) then incr numberOfChannelBitErrors
                done;                
                
                totalNumberOfChannelBitErrors := !totalNumberOfChannelBitErrors +. float_of_int !numberOfChannelBitErrors;
                totalNumberOfBits := !totalNumberOfBits +. float_of_int codewordLength;
            end;         
        
            let numberOfIterations = ref 0 in  
                let numberOfDecodedBitErrors = ldpcDecode transmittedCodeword 
                                                          syndrome
                                                          channelLLR 
                                                          decodedCodeword 
                                                          oneColumnInRow 
                                                          jOneColumnInRow 
                                                          messagesSymbolNodeIn 
                                                          numberOfIterations in begin
                    totalNumberOfDecodedBitErrors := !totalNumberOfDecodedBitErrors +. float_of_int numberOfDecodedBitErrors; 
                    totalNumberOfIterations := !totalNumberOfIterations +. float_of_int !numberOfIterations;
                    if numberOfDecodedBitErrors > 0 then incr totalNumberOfFrameErrors;
                    incr totalNumberOfFrames;
                end;

            if (!totalNumberOfFrames mod 100) = 0 then begin                       
                let avgChannelBER = !totalNumberOfChannelBitErrors /. !totalNumberOfBits in 
                let avgDecodedBER = !totalNumberOfDecodedBitErrors /. !totalNumberOfBits in 
                let avgFER = float_of_int !totalNumberOfFrameErrors /. float_of_int !totalNumberOfFrames in 
                let avgIter = !totalNumberOfIterations /. float_of_int !totalNumberOfFrames in 
                begin
                    print_int !totalNumberOfFrames;
                    print_string "\tChannelBER = ";
                    print_float avgChannelBER;
                    print_string "\tDecodedBER = ";
                    print_float avgDecodedBER;
                    print_string "\tFER = ";
                    print_float avgDecodedBER;
                    print_string "\tavgIter = ";
                    print_float avgIter;
                    print_string "\n";
                    flush stdout;
                end     
            end
        done
    end;
    ebOverNoDb := !ebOverNoDb +. ebOverNoDbStep;
done;;
            
print_string "\n\nSuccesful completion in ";;
print_float (Sys.time());;
print_string " seconds!\n";;



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Comments welcomed to progr. style / speed of my  first ocaml program "Error correcting LDPC decoder"
       [not found] ` <OFB50A01B3.ECDA5A94-ONC12570D8.00394FEA-C12570D8.003A2427@philips.com >
@ 2005-12-15 12:03   ` Gerd Stolpmann
  2005-12-15 12:40     ` Gerd Stolpmann
  0 siblings, 1 reply; 5+ messages in thread
From: Gerd Stolpmann @ 2005-12-15 12:03 UTC (permalink / raw)
  To: Andries Hekstra; +Cc: caml-list


Andries Hekstra said:
> Attached please find the first program I wrote. It has about the same
> speed as its C++ counterpart (slightly faster). I welcome comments w.r.t.
> programming style, esp. when it affects the speed of the program.

As you are doing a lot of array manipulation, this tip may increase
performance significantly: because "float array" is stored with a
different layout than all other arrays, the compiler generates a dynamic
check for every access when the type of the array elements cannot be
statically determined. For example, your function

let swapElement i j a = let x = a.(i) in a.(i) <- a.(j); a.(j) <- x

is polymorphic in the element type. If you define instead

let swapFloatElement i j (a : float array) =
  let x = a.(i) in a.(i) <- a.(j); a.(j) <- x

better code is generated because the mentioned check can be omitted by the
compiler. This applies only if the function is not inlined; swapElement
could be small enough (but qsort, for instance, is definitely not).

Unfortunately, one cannot define swapNonFloatElement because there is no
way to constrain a type that it is not float. So the type system cannot
represent this duality float/non-float, and one must fall back to as many
definitions as element types are actually used.

Gerd
------------------------------------------------------------
Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany
gerd@gerd-stolpmann.de          http://www.gerd-stolpmann.de
------------------------------------------------------------



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Comments welcomed to progr. style / speed of my   first ocaml program "Error correcting LDPC decoder"
  2005-12-15 12:03   ` [Caml-list] " Gerd Stolpmann
@ 2005-12-15 12:40     ` Gerd Stolpmann
  2005-12-15 15:09       ` Xavier Leroy
  0 siblings, 1 reply; 5+ messages in thread
From: Gerd Stolpmann @ 2005-12-15 12:40 UTC (permalink / raw)
  To: Gerd Stolpmann; +Cc: Andries Hekstra, caml-list

I forgot one thing: This comment is only correct for 32 bit code. 64 bit
code has a uniform array layout for all element types.

Gerd

Gerd Stolpmann said:
>
> Andries Hekstra said:
>> Attached please find the first program I wrote. It has about the same
>> speed as its C++ counterpart (slightly faster). I welcome comments
>> w.r.t.
>> programming style, esp. when it affects the speed of the program.
>
> As you are doing a lot of array manipulation, this tip may increase
> performance significantly: because "float array" is stored with a
> different layout than all other arrays, the compiler generates a dynamic
> check for every access when the type of the array elements cannot be
> statically determined. For example, your function
>
> let swapElement i j a = let x = a.(i) in a.(i) <- a.(j); a.(j) <- x
>
> is polymorphic in the element type. If you define instead
>
> let swapFloatElement i j (a : float array)   let x = a.(i) in a.(i) <-
> a.(j); a.(j) <- x
>
> better code is generated because the mentioned check can be omitted by the
> compiler. This applies only if the function is not inlined; swapElement
> could be small enough (but qsort, for instance, is definitely not).
>
> Unfortunately, one cannot define swapNonFloatElement because there is no
> way to constrain a type that it is not float. So the type system cannot
> represent this duality float/non-float, and one must fall back to as many
> definitions as element types are actually used.
>
> Gerd
> ------------------------------------------------------------
> Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany
> gerd@gerd-stolpmann.de          http://www.gerd-stolpmann.de
> ------------------------------------------------------------
>
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
>


------------------------------------------------------------
Gerd Stolpmann * Viktoriastr. 45 * 64293 Darmstadt * Germany
gerd@gerd-stolpmann.de          http://www.gerd-stolpmann.de
------------------------------------------------------------



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Comments welcomed to progr. style / speed of my  first ocaml program "Error correcting LDPC decoder"
  2005-12-15 12:40     ` Gerd Stolpmann
@ 2005-12-15 15:09       ` Xavier Leroy
  0 siblings, 0 replies; 5+ messages in thread
From: Xavier Leroy @ 2005-12-15 15:09 UTC (permalink / raw)
  To: Gerd Stolpmann; +Cc: caml-list

> I forgot one thing: This comment is only correct for 32 bit code. 64 bit
> code has a uniform array layout for all element types.

Yes, but a generic access to a float array still involves an extra
boxing operation.  So, your advice is sound for 64-bit plaforms as well.

I had a very quick look at the original poster's code: it seems
reasonable performance-wise.  There are a few extra hacks that could
be done to increase performance at some expense in code clarity, for
instance turning

            a.(i).(j) <- f i j a.(i).(j);
in
            (let b = a.(i) in b.(j) <- f i j b.(j));

but I wouldn't recommend doing this unless profiling exhibits a big
"hot spot" in this function.

- Xavier Leroy


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Caml-list] Comments welcomed to progr. style / speed of my first ocaml program "Error correcting LDPC decoder"
  2005-12-15 10:33 Comments welcomed to progr. style / speed of my first ocaml program "Error correcting LDPC decoder" Andries Hekstra
       [not found] ` <OFB50A01B3.ECDA5A94-ONC12570D8.00394FEA-C12570D8.003A2427@philips.com >
@ 2005-12-16 19:35 ` Jon Harrop
  1 sibling, 0 replies; 5+ messages in thread
From: Jon Harrop @ 2005-12-16 19:35 UTC (permalink / raw)
  To: caml-list

On Thursday 15 December 2005 10:33, Andries Hekstra wrote:
> I am an applied scientist in the areas of signal processing and error
> correction at Philips Research. Having done the programming work of my
> computer simulations in C/C++ for almost 10-15 years with increasingly
> mixed feelings about the languange, a friend pointed me to functional
> programming.

You may be interested in my book Objective CAML for Scientists:

  http://www.ffconsultancy.com/products/ocaml_for_scientists

It covers everything you need and is written for people with similar 
backgrounds to your own.

> I welcome comments w.r.t. programming style, esp. when it affects the speed
> of the program.

You don't need to use ";;" in compiled source.

You can replace:

  print_string "LDPC decoder for rate 1 - ";
  print_int ldpc_j;
  print_string "/";
  print_int ldpc_k;
  print_string " Gallager code with length ";
  print_int codewordLength;
  flush stdout

with a call to "Printf.printf".

You can replace:

  fun j -> fun i -> fun x -> 

with

  fun j i x ->

Try to avoid superfluous parentheses:

        if (i < j) then begin

Use Array.sort instead of writing your own "qsort". Use an array of 2-tuples 
(pairs) instead of two arrays and a custom "qsort2" function.

Put a space either side of a bracketed prefix operator, to avoid problems with 
(*):

  qsort (<) a.(i)

Coalesce computations into a single "let () = ...", rather than spreading them 
out over the source.

Spread your code out more:

  let sum a = let rec sum i a = if (i > 0) then a.(i) +. sum (i-1) a else if 
(i = 0) then a.(i) else 0.
      in sum ((Array.length a) - 1) a

  let sum a =
    let rec sum i a =
      if i > 0 then a.(i) +. sum (i-1) a else
        if i = 0 then a.(i) else 0. in
    sum (Array.length a - 1) a

It looks like you might be creating several arrays that are only filled in at 
the end, in which case it is probably better to create them at the end of a 
calculating using something like Array.init.

Your code often has similar looking parts. You can probably factor out a lot 
of common functionality into higher-order functions, reducing code size and 
the number of mistakes at the cost of a little performance due to the 
genericity of the resulting code.

Especially with long variable names, you may be able to shrink your code by 
nesting more. For example, to avoid passing parameters across many function 
calls. This can also conflict with performance but for more subtle reasons.

Use "&&" and "||" rather than "&" and "or".

You often write:

  let x=1 in begin
    for i=1 to 10 do
      ...
    done
  end

when you could write:

  let x=1 in
  for i=1 to 10 do
    ...
  done

Reducing maxNumberOfIterations to 1, the final time given is 78.54s on my 
900MHz 32-bit Athlon and 55.67s on my 800MHz AMD64.

You can shave 2% off the time by factoring the computation of pi from 
randomGaussian. You can reduce the run-time by 25% by using a faster 
randomGaussian function (e.g. the one given in NR) and compiling with 
"-inline 100".

HTH.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2005-12-16 19:41 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-12-15 10:33 Comments welcomed to progr. style / speed of my first ocaml program "Error correcting LDPC decoder" Andries Hekstra
     [not found] ` <OFB50A01B3.ECDA5A94-ONC12570D8.00394FEA-C12570D8.003A2427@philips.com >
2005-12-15 12:03   ` [Caml-list] " Gerd Stolpmann
2005-12-15 12:40     ` Gerd Stolpmann
2005-12-15 15:09       ` Xavier Leroy
2005-12-16 19:35 ` Jon Harrop

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).