%% orbit-int benchmarks (for RELEASE)
%%
%% Author: Patrick Maier
%%
-module(bench).
-export([%% sets of generators
g/1,
g1/1, g2/1, g3/1, g4/1, g5/1,
g12/1, g13/1, g14/1, g15/1, g23/1, g24/1, g25/1, g34/1, g35/1, g45/1,
g123/1, g124/1, g125/1, g134/1, g135/1, g145/1, g234/1, g235/1, g245/1, g345/1,
g1234/1, g1235/1, g1245/1, g1345/1, g2345/1,
g12345/1,
%% sequential benchmarks
seq/2,
%% parallel benchmarks
par/3, par_seq/3,
%% distributed benchmarks
dist/4, dist_seq/4]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% generators
%% Fibonacci numbers
fib(0) -> 1;
fib(1) -> 1;
fib(N) -> fib(N - 1) + fib(N - 2).
%% mixing polynomials (up to degree 3)
p(A0,_N) -> A0.
p(A1,A0, N) -> A1 * N + p(A0, N).
p(A2,A1,A0, N) -> A2 * N * N + p(A1,A0, N).
p(A3,A2,A1,A0, N) -> A3 * N * N * N + p(A2,A1,A0, N).
%% step functions (up to 4 steps)
s(B0, N) -> if N < B0 -> 0; true -> 1 end.
s(B0,B1, N) -> if N < B0 -> 0; true -> 1 + s(B1, N) end.
s(B0,B1,B2, N) -> if N < B0 -> 0; true -> 1 + s(B1,B2, N) end.
s(B0,B1,B2,B3, N) -> if N < B0 -> 0; true -> 1 + s(B1,B2,B3, N) end.
%% remainder function (range 0..R-1)
r(R, N) -> abs(N) rem R.
%% generators based on Fibonacci numbers;
%% functions f1(N,_),...,f5(N,_) produce numbers in the range 0 .. N-1;
%% computationally f1 = fib(0..15),
%% f2 = fib(5..20),
%% f3 = fib(10..25),
%% f4 = fib(11,19,27), bias 49% to 11, 49% to 19, 2% to 27
%% f5 = fib(10,20,30), bias 90% to 10, 9.9% to 20, 0.1% to 30
f1(N,X) -> r(N, fib(p(1,0, r(16, X))) + p(1,0, X)).
f2(N,X) -> r(N, fib(p(1,5, r(16, X))) + p(2,5,-1, X)).
f3(N,X) -> r(N, fib(p(1,10, r(16, X))) + p(-1,0,8,0,X)).
f4(N,X) -> r(N, fib(p(8,3, s(0,49,98,100, r(100, X)))) + p(-1, X)).
f5(N,X) -> r(N, fib(p(10,0, s(0,900,999,1000, r(1000, X)))) + p(1, X)).
%% sets (= lists) of generators
g(_N) -> [].
g1(N) -> [fun(X) -> f1(N,X) end].
g2(N) -> [fun(X) -> f2(N,X) end].
g3(N) -> [fun(X) -> f3(N,X) end].
g4(N) -> [fun(X) -> f4(N,X) end].
g5(N) -> [fun(X) -> f5(N,X) end].
g12(N) -> g1(N) ++ g2(N).
g13(N) -> g1(N) ++ g3(N).
g14(N) -> g1(N) ++ g4(N).
g15(N) -> g1(N) ++ g5(N).
g23(N) -> g2(N) ++ g3(N).
g24(N) -> g2(N) ++ g4(N).
g25(N) -> g2(N) ++ g5(N).
g34(N) -> g3(N) ++ g4(N).
g35(N) -> g3(N) ++ g5(N).
g45(N) -> g4(N) ++ g5(N).
g123(N) -> g12(N) ++ g3(N).
g124(N) -> g12(N) ++ g4(N).
g125(N) -> g12(N) ++ g5(N).
g134(N) -> g13(N) ++ g4(N).
g135(N) -> g13(N) ++ g5(N).
g145(N) -> g14(N) ++ g5(N).
g234(N) -> g23(N) ++ g4(N).
g235(N) -> g23(N) ++ g5(N).
g245(N) -> g24(N) ++ g5(N).
g345(N) -> g34(N) ++ g5(N).
g1234(N) -> g123(N) ++ g4(N).
g1235(N) -> g123(N) ++ g5(N).
g1245(N) -> g124(N) ++ g5(N).
g1345(N) -> g134(N) ++ g5(N).
g2345(N) -> g234(N) ++ g5(N).
g12345(N) -> g1234(N) ++ g5(N).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% benchmarks, parametrised by
%% * list of Generators
%% * size of space N > 0
%% * number of processors P > 0 (per node)
%% * list of Workers (in short node name format 'name@host')
%% sequential orbit computation
seq(Generators, N) ->
sz(master:orbit(Generators(N), [0], 2 * N)).
%% parallel orbit computation (par_seq/3 does not spawn image computation)
par(Generators, N, P) ->
sz(master:orbit(Generators(N), [0], {P, (2 * N) div P + 1, 0, true})).
par_seq(Generators, N, P) ->
sz(master:orbit(Generators(N), [0], {P, (2 * N) div P + 1, 0, false})).
%% distributed orbit computation (dist_seq/4 does not spawn image computation)
dist(Generators, N, P, Workers) ->
W = length(Workers),
sz(master:orbit(Generators(N), [0], [{H, P, (2 * N) div (W * P) + 1, 1, true} || H <- Workers])).
dist_seq(Generators, N, P, Workers) ->
W = length(Workers),
sz(master:orbit(Generators(N), [0], [{H, P, (2 * N) div (W * P) + 1, 1, false} || H <- Workers])).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% auxiliary functions
%% print size of generated orbit
sz({_Orbit, [MainStats|_OtherStats]}) ->
io:write(lists:keyfind(size, 1, MainStats)), io:nl().