spectral-norm OCaml #3 program
source code
(* The Computer Language Benchmarks Game
* http://benchmarksgame.alioth.debian.org/
*
* Contributed by Sebastien Loisel
* Cleanup by Troestler Christophe
* Parallelized by Mauricio Fernandez
*)
open Bigarray
type v = (float, float64_elt, c_layout) Array1.t
let max_workers = 8
let map_chunks f low hi =
let step = (hi - low) / max_workers in
let rec loop acc n =
if n < hi then
let n' = n + step in loop (f (n, (min hi n')) :: acc) n'
else acc
in loop [] low
let wait_for = List.iter (fun f -> f())
(* original function due to Jon D. Harrop *)
let invoke (f : 'a -> 'b) x : unit -> 'b =
let input, output = Unix.pipe() in
match Unix.fork() with
| -1 -> Unix.close input; Unix.close output; (let v = f x in fun () -> v)
| 0 ->
Unix.close input;
let output = Unix.out_channel_of_descr output in
Marshal.to_channel output (try `Res(f x) with e -> `Exn e) [];
close_out output;
exit 0
| pid ->
Unix.close output;
let input = Unix.in_channel_of_descr input in fun () ->
let v = Marshal.from_channel input in
ignore (Unix.waitpid [] pid);
close_in input;
match v with `Res x -> x | `Exn e -> raise e
let eval_A i j = 1. /. float((i+j)*(i+j+1)/2+i+1)
let eval_A_times_u (u : v) (v : v) =
let n = Array1.dim v - 1 in
let compute (p, q) =
for i = p to q do
let vi = ref 0. in
for j = 0 to n do vi := !vi +. eval_A i j *. u.{j} done;
v.{i} <- !vi
done
in wait_for (map_chunks (invoke compute) 0 n)
let eval_At_times_u (u : v) (v : v) =
let n = Array1.dim v - 1 in
let compute (p, q) =
for i = p to q do
let vi = ref 0. in
for j = 0 to n do vi := !vi +. eval_A j i *. u.{j} done;
v.{i} <- !vi
done
in wait_for (map_chunks (invoke compute) 0 n)
let make_array n x =
let v = Array1.map_file
(Unix.openfile "/dev/zero" [Unix.O_RDWR] 0o755)
float64 c_layout true n in
for i = 0 to n - 1 do v.{i} <- x done;
v
let eval_AtA_times_u u v =
let w = make_array (Array1.dim u) 0.0 in
eval_A_times_u u w; eval_At_times_u w v
let () =
let n = try int_of_string(Array.get Sys.argv 1) with _ -> 2000 in
let u = make_array n 1.0 and v = make_array n 0.0 in
for i = 0 to 9 do
eval_AtA_times_u u v; eval_AtA_times_u v u
done;
let vv = ref 0.0 and vBv = ref 0.0 in
for i=0 to n-1 do
vv := !vv +. v.{i} *. v.{i};
vBv := !vBv +. u.{i} *. v.{i}
done;
Printf.printf "%0.9f\n" (sqrt(!vBv /. !vv))
notes, command-line, and program output
NOTES:
64-bit Ubuntu quad core
The OCaml native-code compiler, version 4.06.0
Sun, 05 Nov 2017 22:28:56 GMT
MAKE:
mv spectralnorm.ocaml-3.ocaml spectralnorm.ocaml-3.ml
/opt/src/ocaml-4.06.0/bin/ocamlopt -noassert -unsafe -fPIC -nodynlink -inline 100 -O3 unix.cmxa bigarray.cmxa spectralnorm.ocaml-3.ml -o spectralnorm.ocaml-3.ocaml_run
File "spectralnorm.ocaml-3.ml", line 66, characters 10-25:
Warning 3: deprecated: Bigarray.Array1.map_file
Use [array1_of_genarray (Unix.map_file ...)] instead.
Note that Bigarray.Array1.map_file raises Sys_error while
Unix.map_file raises Unix_error.
rm spectralnorm.ocaml-3.ml
0.26s to complete and log all make actions
COMMAND LINE:
./spectralnorm.ocaml-3.ocaml_run 5500
PROGRAM OUTPUT:
1.274224153