# spectral-norm Erlang HiPE #2 program

## source code

```% The Computer Language Benchmarks Game
% https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
%   contributed by Fredrik Svahn

-module(spectralnorm).
-export([main/1]).
-compile( [ inline, { inline_size, 1000 } ] ).

main([Arg]) ->
register(server, self()),
N = list_to_integer(Arg),
{U, V} = power_method(N, 10, erlang:make_tuple(N, 1), []),
io:format("~.9f\n", [ eigen(N, U, V, 0, 0) ]),
erlang:halt(0).

% eigenvalue of V
eigen(0, _, _, VBV, VV) when VV /= 0 -> math:sqrt(VBV / VV);

eigen(I, U, V, VBV, VV) when I /= 0 ->
VI = element(I, V),
eigen(I-1, U, V, VBV + element(I, U)*VI, VV + VI*VI).

% 2I steps of the power method
power_method(_, 0, A, B) -> {A, B};
power_method(N, I, A, _B) ->
V = atav(N, A),
U = atav(N, V),
power_method(N, I-1, U, V).

% return element i,j of infinite matrix A
a(II,JJ) -> 1/((II+JJ-2)*(II-1+JJ)/2+II).

% multiply vector v by matrix A
av(N, V) -> pmap(N, fun(Begin, End) -> av(N, Begin, End, V) end).

av(N, Begin, End, V) -> server ! { self(), [ avloop(N, I, V, 0.0) || I <- lists:seq(Begin, End) ]}.

avloop(0, _, _, X) ->  X;
avloop(J, I, V, X) ->  avloop(J-1, I, V, X + a(I, J)*element(J, V) ).

% multiply vector v by matrix A transposed
atv(N, V) -> pmap(N, fun(Begin, End)-> atv(N, Begin, End, V) end).

atv(N, Begin, End, V) -> server ! { self(), [ atvloop(N, I, V, 0.0) || I <- lists:seq(Begin, End) ]}.

atvloop(0, _, _, X) -> X;
atvloop(J, I, V, X) -> atvloop(J-1, I, V, X + a(J, I)*element(J, V) ).

% multiply vector v by matrix A and then by matrix A transposed
atav(N, V) -> atv(N, av(N, V)).

%Helper function for multicore
pmap(N, F) ->
Chunks = chunks(0, erlang:system_info(logical_processors), N, []),
Pids = [spawn(fun()-> F(Begin, End) end) || {Begin, End} <- Chunks],
Res = [ receive {Pid, X} -> X end || Pid <- Pids],
list_to_tuple(lists:flatten(Res)).

chunks(I, P, N, A) when I == P-1 -> lists:reverse([{I*(N div P)+1, N} | A ]);
chunks(I, P, N, A) -> chunks(I+1, P, N, [{ I*(N div P)+1, (I+1)*(N div P)} | A ]).

```

## notes, command-line, and program output

```NOTES:
64-bit Ubuntu quad core
Erlang/OTP 21 [erts-10.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe]

Sat, 24 Nov 2018 05:22:35 GMT

MAKE:
mv spectralnorm.hipe-2.hipe spectralnorm.erl
/opt/src/otp_src_21.1/bin/erlc +native +"{hipe, [o3]}" spectralnorm.erl

1.66s to complete and log all make actions

COMMAND LINE:
/opt/src/otp_src_21.1/bin/erl -smp enable -noshell -run  spectralnorm main 5500

PROGRAM OUTPUT:
1.274224153
```