%%% -*- erlang-indent-level: 2 -*- %%%------------------------------------------------------------------- %%% Author: Kostis Sagonas %%% %%% A test for list handling created using the 'random' module. %%%------------------------------------------------------------------- -module(basic_random). -export([test/0]). %% It can be used as a benchmark by playing with the following defines -define(N, 1000). -define(Iter, 500). test() -> ok = random(?N). random(N) -> random(N, ?Iter). random(N, Iter) -> random:seed(1, 2, 3), t(ranlist(N, [], N*100), Iter). ranlist(0, L, _N) -> L; ranlist(N, L, N0) -> ranlist(N-1, [random:uniform(N0)+300 | L], N0). t(_, 0) -> ok; t(L, Iter) -> %% io:format("Sort starting~n"), sort(L), t(L, Iter-1). sort([X, Y | L]) when X =< Y -> split_1(X, Y, L, [], []); sort([X, Y | L]) -> split_2(X, Y, L, [], []); sort(L) -> L. %% Ascending. split_1(X, Y, [Z | L], R, Rs) when Z >= Y -> split_1(Y, Z, L, [X | R], Rs); split_1(X, Y, [Z | L], R, Rs) when Z >= X -> split_1(Z, Y, L, [X | R], Rs); split_1(X, Y, [Z | L], [], Rs) -> split_1(X, Y, L, [Z], Rs); split_1(X, Y, [Z | L], R, Rs) -> split_1_1(X, Y, L, R, Rs, Z); split_1(X, Y, [], R, Rs) -> rmergel([[Y, X | R] | Rs], []). %% One out-of-order element, S. split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= Y -> split_1_1(Y, Z, L, [X | R], Rs, S); split_1_1(X, Y, [Z | L], R, Rs, S) when Z >= X -> split_1_1(Z, Y, L, [X | R], Rs, S); split_1_1(X, Y, [Z | L], R, Rs, S) when S =< Z -> split_1(S, Z, L, [], [[Y, X | R] | Rs]); split_1_1(X, Y, [Z | L], R, Rs, S) -> split_1(Z, S, L, [], [[Y, X | R] | Rs]); split_1_1(X, Y, [], R, Rs, S) -> rmergel([[S], [Y, X | R] | Rs], []). %% Descending. split_2(X, Y, [Z | L], R, Rs) when Z =< Y -> split_2(Y, Z, L, [X | R], Rs); split_2(X, Y, [Z | L], R, Rs) when Z =< X -> split_2(Z, Y, L, [X | R], Rs); split_2(X, Y, [Z | L], [], Rs) -> split_2(X, Y, L, [Z], Rs); split_2(X, Y, [Z | L], R, Rs) -> split_2_1(X, Y, L, R, Rs, Z); split_2(X, Y, [], R, Rs) -> mergel([[Y, X | R] | Rs], []). split_2_1(X, Y, [Z | L], R, Rs, S) when Z =< Y -> split_2_1(Y, Z, L, [X | R], Rs, S); split_2_1(X, Y, [Z | L], R, Rs, S) when Z =< X -> split_2_1(Z, Y, L, [X | R], Rs, S); split_2_1(X, Y, [Z | L], R, Rs, S) when S > Z -> split_2(S, Z, L, [], [[Y, X | R] | Rs]); split_2_1(X, Y, [Z | L], R, Rs, S) -> split_2(Z, S, L, [], [[Y, X | R] | Rs]); split_2_1(X, Y, [], R, Rs, S) -> mergel([[S], [Y, X | R] | Rs], []). mergel([[] | L], Acc) -> mergel(L, Acc); mergel([A, [H2 | T2], [H3 | T3] | L], Acc) -> mergel(L, [merge3_1(A, [], H2, T2, H3, T3) | Acc]); mergel([A, [H | T]], Acc) -> rmergel([merge2_1(A, H, T, []) | Acc], []); mergel([L], []) -> L; mergel([L], Acc) -> rmergel([lists:reverse(L, []) | Acc], []); mergel([], []) -> []; mergel([], Acc) -> rmergel(Acc, []); mergel([A, [] | L], Acc) -> mergel([A | L], Acc); mergel([A, B, [] | L], Acc) -> mergel([A, B | L], Acc). rmergel([A, [H2 | T2], [H3 | T3] | L], Acc) -> rmergel(L, [rmerge3_1(A, [], H2, T2, H3, T3) | Acc]); rmergel([A, [H | T]], Acc) -> mergel([rmerge2_1(A, H, T, []) | Acc], []); rmergel([L], Acc) -> mergel([lists:reverse(L, []) | Acc], []); rmergel([], Acc) -> mergel(Acc, []). %% Take L1 apart. merge3_1([H1 | T1], M, H2, T2, H3, T3) when H1 =< H2 -> merge3_12(T1, H1, H2, T2, H3, T3, M); merge3_1([H1 | T1], M, H2, T2, H3, T3) -> merge3_21(T1, H1, H2, T2, H3, T3, M); merge3_1(_nil, M, H2, T2, H3, T3) when H2 =< H3 -> merge2_1(T2, H3, T3, [H2 | M]); merge3_1(_nil, M, H2, T2, H3, T3) -> merge2_1(T3, H2, T2, [H3 | M]). %% Take L2 apart. merge3_2(T1, H1, M, [H2 | T2], H3, T3) when H1 =< H2 -> merge3_12(T1, H1, H2, T2, H3, T3, M); merge3_2(T1, H1, M, [H2 | T2], H3, T3) -> merge3_21(T1, H1, H2, T2, H3, T3, M); merge3_2(T1, H1, M, _nil, H3, T3) when H1 =< H3 -> merge2_1(T1, H3, T3, [H1 | M]); merge3_2(T1, H1, M, _nil, H3, T3) -> merge2_1(T3, H1, T1, [H3 | M]). %% H1 <= H2. Inlined. merge3_12(T1, H1, H2, T2, H3, T3, M) when H3 < H1 -> merge3_12_3(T1, H1, H2, T2, [H3 | M], T3); merge3_12(T1, H1, H2, T2, H3, T3, M) -> merge3_1(T1, [H1 | M], H2, T2, H3, T3). %% H1 <= H2, take L3 apart. merge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 < H1 -> merge3_12_3(T1, H1, H2, T2, [H3 | M], T3); merge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) -> merge3_1(T1, [H1 | M], H2, T2, H3, T3); merge3_12_3(T1, H1, H2, T2, M, _nil) -> merge2_1(T1, H2, T2, [H1 | M]). %% H1 > H2. Inlined. merge3_21(T1, H1, H2, T2, H3, T3, M) when H3 < H2 -> merge3_21_3(T1, H1, H2, T2, [H3 | M], T3); merge3_21(T1, H1, H2, T2, H3, T3, M) -> merge3_2(T1, H1, [H2 | M], T2, H3, T3). %% H1 > H2, take L3 apart. merge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 < H2 -> merge3_21_3(T1, H1, H2, T2, [H3 | M], T3); merge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) -> merge3_2(T1, H1, [H2 | M], T2, H3, T3); merge3_21_3(T1, H1, H2, T2, M, _nil) -> merge2_1(T2, H1, T1, [H2 | M]). %% Take L1 apart. rmerge3_1([H1 | T1], M, H2, T2, H3, T3) when H1 > H2 -> rmerge3_12(T1, H1, H2, T2, H3, T3, M); rmerge3_1([H1 | T1], M, H2, T2, H3, T3) -> rmerge3_21(T1, H1, H2, T2, H3, T3, M); rmerge3_1(_nil, M, H2, T2, H3, T3) when H2 > H3 -> rmerge2_1(T2, H3, T3, [H2 | M]); rmerge3_1(_nil, M, H2, T2, H3, T3) -> rmerge2_1(T3, H2, T2, [H3 | M]). %% Take L2 apart. rmerge3_2(T1, H1, M, [H2 | T2], H3, T3) when H1 > H2 -> rmerge3_12(T1, H1, H2, T2, H3, T3, M); rmerge3_2(T1, H1, M, [H2 | T2], H3, T3) -> rmerge3_21(T1, H1, H2, T2, H3, T3, M); rmerge3_2(T1, H1, M, _nil, H3, T3) when H1 > H3 -> rmerge2_1(T1, H3, T3, [H1 | M]); rmerge3_2(T1, H1, M, _nil, H3, T3) -> rmerge2_1(T3, H1, T1, [H3 | M]). %% H1 > H2. Inlined. rmerge3_12(T1, H1, H2, T2, H3, T3, M) when H3 >= H1 -> rmerge3_12_3(T1, H1, H2, T2, [H3 | M], T3); rmerge3_12(T1, H1, H2, T2, H3, T3, M) -> rmerge3_1(T1, [H1 | M], H2, T2, H3, T3). %% H1 > H2, take L3 apart. rmerge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 >= H1 -> rmerge3_12_3(T1, H1, H2, T2, [H3 | M], T3); rmerge3_12_3(T1, H1, H2, T2, M, [H3 | T3]) -> rmerge3_1(T1, [H1 | M], H2, T2, H3, T3); rmerge3_12_3(T1, H1, H2, T2, M, _nil) -> rmerge2_1(T1, H2, T2, [H1 | M]). %% H1 =< H2. Inlined. rmerge3_21(T1, H1, H2, T2, H3, T3, M) when H3 >= H2 -> rmerge3_21_3(T1, H1, H2, T2, [H3 | M], T3); rmerge3_21(T1, H1, H2, T2, H3, T3, M) -> rmerge3_2(T1, H1, [H2 | M], T2, H3, T3). %% H1 =< H2, take L3 apart. rmerge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) when H3 >= H2 -> rmerge3_21_3(T1, H1, H2, T2, [H3 | M], T3); rmerge3_21_3(T1, H1, H2, T2, M, [H3 | T3]) -> rmerge3_2(T1, H1, [H2 | M], T2, H3, T3); rmerge3_21_3(T1, H1, H2, T2, M, _nil) -> rmerge2_1(T2, H1, T1, [H2 | M]). merge2_1([H1 | T1], H2, T2, M) when H2 < H1 -> merge2_2(T1, H1, T2, [H2 | M]); merge2_1([H1 | T1], H2, T2, M) -> merge2_1(T1, H2, T2, [H1 | M]); merge2_1(_nil, H2, T2, M) -> lists:reverse(T2, [H2 | M]). merge2_2(T1, H1, [H2 | T2], M) when H1 < H2 -> merge2_1(T1, H2, T2, [H1 | M]); merge2_2(T1, H1, [H2 | T2], M) -> merge2_2(T1, H1, T2, [H2 | M]); merge2_2(T1, H1, _nil, M) -> lists:reverse(T1, [H1 | M]). rmerge2_1([H1 | T1], H2, T2, M) when H2 >= H1 -> rmerge2_2(T1, H1, T2, [H2 | M]); rmerge2_1([H1 | T1], H2, T2, M) -> rmerge2_1(T1, H2, T2, [H1 | M]); rmerge2_1(_nil, H2, T2, M) -> lists:reverse(T2, [H2 | M]). rmerge2_2(T1, H1, [H2 | T2], M) when H1 >= H2 -> rmerge2_1(T1, H2, T2, [H1 | M]); rmerge2_2(T1, H1, [H2 | T2], M) -> rmerge2_2(T1, H1, T2, [H2 | M]); rmerge2_2(T1, H1, _nil, M) -> lists:reverse(T1, [H1 | M]).