(* Benchmark script *)

(* Set up output stream *)
SetOptions[$Output, FormatType -> OutputForm];

(* Test if system has a C compiler and if so set target to "C"*)
Needs["CCompilerDriver`"];
If[ Length[CCompilers[]] > 0,
	$CompilationTarget = "C"
];


ClearAll[$printOutput];
$printOutput = True;

ClearAll[timeit];
SetAttributes[timeit, HoldFirst];
timeit[ex_, name_String] := Module[
	{t},
	t = Infinity;
	Do[
		t = Min[t, N[First[AbsoluteTiming[ex]]]];
		,
		{i, 1, 5}
	];
	If[$printOutput,
		(*Print[OutputForm["mathematica," <> name <> ","], t*1000];*)
		Print["mathematica,", name, ",", t*1000];
	];
];

ClearAll[test];
SetAttributes[test, HoldFirst];
test[ex_] := Assert[ex];
On[Assert];


(* recursive fib *)

ClearAll[fib];
fib = Compile[{{n, _Integer}}, 
	If[n < 2, n, fib[n - 1] + fib[n - 2]],
	CompilationTarget -> "WVM"
];

test[fib[20] == 6765];
timeit[fib[20], "fib"];

(* parse integer *)

ClearAll[parseintperf];
parseintperf[t_] := Module[
	{n, m, i, s},
	Do[
		n = RandomInteger[{0, 4294967295}];
		s = IntegerString[n, 16];
		m = FromDigits[s, 16];
		,
		{i, 1, t}
	];
	test[ m == n];
	n
];

timeit[parseintperf[1000], "parse_int"];

(* array constructors *)

test[ And @@ And @@@ Thread /@ Thread[ConstantArray[1, {200, 200}] == 1]];

(* matmul and transpose *)

ClearAll[A];
A = ConstantArray[1, {200, 200}];
test[And @@ And @@@ Thread /@ Thread[A.ConjugateTranspose[A] == 200]];

(* mandelbrot set: complex arithmetic and comprehensions *)

ClearAll[mandel];
(*mandel[zin_] := Module[
	{z, c, maxiter, n},
	z = zin;
	c = z;
	maxiter = 80;
	Do[
		If[ Abs[z] > 2,
			maxiter = n-1;
			Break[]
		];
		z = z^2 + c;
		,
		{n, 1, maxiter}
	];
	maxiter
];*)
mandel = Compile[{{zin, _Complex}},
	Module[
		{z = zin, c = zin, maxiter = 80, n = 0},
		Do[
			If[ Abs[z] > 2,
				maxiter = n-1;
				Break[]
			];
			z = z^2 + c;
			,
			{n, 1, maxiter}
		];
		maxiter
	]
];

ClearAll[mandelperf];
mandelperf[] := Table[mandel[r + i*I], {i, -1., 1., 0.1}, {r, -2.0, 0.5, 0.1}];

test[ Total[mandelperf[], 2] == 14791];
timeit[mandelperf[], "mandel"];

(* numeric vector sort *)

ClearAll[qsort];
(* qsort[ain_, loin_, hiin_] := Module[
	{a = ain, i = loin, j = hiin, lo = loin, hi = hiin, pivot},
	While[ i < hi,
		pivot = a[[BitShiftRight[lo + hi] ]];
		While[ i <= j,
			While[a[[i]] < pivot, i++];
			While[a[[j]] > pivot, j--];
			If[ i <= j,
				a[[{i,j}]] = a[[{j, i}]];
				i++; j--;
			];
		];
		If[ lo < j, a = qsort[a, lo, j] ];
		{lo, j} = {i, hi};
	];
	a
]; *)
qsort = Compile[
	{{ain, _Real, 1}, {loin, _Integer}, {hiin, _Integer}},
	Module[
		{a = ain, i = loin, j = hiin, lo = loin, hi = hiin, pivot},
		While[ i < hi,
			pivot = a[[ Floor[(lo + hi)/2] ]];
			While[ i <= j,
				While[a[[i]] < pivot, i++];
				While[a[[j]] > pivot, j--];
				If[ i <= j,
					a[[{i,j}]] = a[[{j, i}]];
					i++; j--;
				];
			];
			If[ lo < j, a[[lo;;j]] = qsort[ a[[lo;;j]], 1, j - lo + 1] ];
			{lo, j} = {i, hi};
		];
		a
	]
];


ClearAll[sortperf];
sortperf[n_] := Module[{vec = RandomReal[1, n]}, qsort[vec, 1, n]];

test[OrderedQ[sortperf[5000]] ];
timeit[sortperf[5000], "quicksort"];

(* slow pi series  *)

ClearAll[pisum];
pisum = Compile[ {},
	Module[
		{sum = 0.`},
		Do[sum = Sum[1/(k*k), {k, 1, 10000}],
			{500}];
		sum
	]
];


test[Abs[pisum[] - 1.644834071848065`] < 1.`*^-12 ];
timeit[pisum[], "pi_sum"];

(* slow pi series, vectorized *)

pisumvec = Compile[{},
	Module[
		{sum = 0.},
		Do[
			sum = Total[1/Range[1, 10000]^2];,
			{500}
		];
		sum
	]
];

(* test[Abs[pisumvec[] - 1.644834071848065`] < 1.`*^-12 ];*)
(* timeit[pisumvec[], "pi_sum_vec"];*)

(* random matrix statistics *)

ClearAll[randmatstat];
(*randmatstat[t_] := Module[
	{n, v, w, a, b, c, d, P, Q},
	n = 5;
	v = w = ConstantArray[0., {t}];
	Do[
		a = RandomReal[NormalDistribution[], {n, n}];
		b = RandomReal[NormalDistribution[], {n, n}];
		c = RandomReal[NormalDistribution[], {n, n}];
		d = RandomReal[NormalDistribution[], {n, n}];
		P = Join[a, b, c, d, 2];
		Q = ArrayFlatten[{{a, b}, {c, d}}];
		v[[i]] = Tr[MatrixPower[Transpose[P].P, 4]];
		w[[i]] = Tr[MatrixPower[Transpose[Q].Q, 4]];
		,
		{i, 1, t}
	];
	{StandardDeviation[v]/Mean[v], StandardDeviation[w]/Mean[w]}
];*)
randmatstat = Compile[{{t, _Integer}},
	Module[
		{
			n = 5, 
			v = ConstantArray[0., t], 
			w = ConstantArray[0., t], 
			a = {{0.}}, b = {{0.}}, 
			c = {{0.}}, d = {{0.}}, 
			P = {{0.}}, Q = {{0.}}
		},
		Do[
			a = RandomReal[NormalDistribution[], {n, n}];
			b = RandomReal[NormalDistribution[], {n, n}];
			c = RandomReal[NormalDistribution[], {n, n}];
			d = RandomReal[NormalDistribution[], {n, n}];
			P = Join[a, b, c, d, 2];
			Q = ArrayFlatten[{{a, b}, {c, d}}];
			v[[i]] = Tr[MatrixPower[Transpose[P].P, 4]];
			w[[i]] = Tr[MatrixPower[Transpose[Q].Q, 4]];
			,
			{i, 1, t}
		];
		{StandardDeviation[v]/Mean[v], StandardDeviation[w]/Mean[w]}
	],
	{{_ArrayFlatten, _Real, 2}}
];


ClearAll[s1,s2];
{s1, s2} = randmatstat[1000];
test[0.5 < s1 < 1.0 && 0.5 < s2 < 1.0];

timeit[randmatstat[1000], "rand_mat_stat"];

(* largish random number gen & matmul *)

timeit[RandomReal[1, {1000, 1000}].RandomReal[1, {1000, 1000}], "rand_mat_mul"];

(* printfd *)

(* only on unix systems *)
If[ $OperatingSystem == "Linux"||$OperatingSystem == "MacOSX",
	
	ClearAll[printfd];
	printfd[n_] := Module[
		{stream},
		stream = OpenWrite["/dev/null"];
		Do[
			WriteString[stream, i, " ", i+1, "\n" ];
			,
			{i, 1, n}
		];
		Close[stream];
	];
	
	timeit[printfd[100000], "printfd"];
	
];
