Skip to content

Commit

Permalink
Make Crit-bit trees work. Insertion is currently slow.
Browse files Browse the repository at this point in the history
  • Loading branch information
jlouis committed Feb 17, 2011
1 parent af1fdd5 commit 4dcfbf8
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 72 deletions.
120 changes: 68 additions & 52 deletions src/bench_map.erl
Original file line number Original file line Diff line number Diff line change
@@ -1,33 +1,34 @@
-module(bench_map). -module(bench_map).


-export([run/0]). -export([run/0, runs/1]).


-ifdef(TEST). -ifdef(TEST).
-include_lib("eqc/include/eqc.hrl"). -include_lib("eqc/include/eqc.hrl").
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
-endif. -endif.


run() -> run() ->
[{sets, runs( [
fun () -> {patricia, timer:tc(fun() -> patricia_test(), ok end, [])}
timer:tc(fun() -> set_test(), ok end, []) %% {sets, timer:tc(fun() -> set_test(), ok end, [])},
end)}, %% {dict, timer:tc(fun() -> dict_test(), ok end, [])},
{dict, timer:tc(fun() -> dict_test(), ok end, [])}, %% {gb_sets, timer:tc(fun() -> gb_sets_test(), ok end, [])},
{gb_sets, runs( %% {gb_trees, timer:tc(fun() -> gb_trees_test(), ok end, [])},
fun () -> %% {h_rb_sets, timer:tc(fun() -> h_rb_set_test(), ok end, [])},
timer:tc(fun() -> gb_sets_test(), ok end, []) %% {rb_sets, timer:tc(fun() -> rb_sets_test(), ok end, [])}
end)}, ].
{gb_trees, timer:tc(fun() -> gb_trees_test(), ok end, [])},
{h_rb_sets, timer:tc(fun() -> h_rb_set_test(), ok end, [])},
{rb_sets, timer:tc(fun() -> rb_sets_test(), ok end, [])}].


runs(F) -> runs(F) ->
[F() || _ <- lists:seq(1, 10)]. [F() || _ <- lists:seq(1, 10)].


words() -> words() ->
Words = "/usr/share/dict/words", Words = "/usr/share/dict/words",
{ok, Content} = file:read_file(Words), {ok, Content} = file:read_file(Words),
[binary_to_list(W) || W <- binary:split(Content, <<"\n">>, [global])]. {Taken, _} = lists:split(500,
[binary_to_list(W)
|| W <- binary:split(Content, <<"\n">>, [global])]),
Taken.



list_shuffle(L) -> list_shuffle(L) ->
random:seed(), %% Reset Random function random:seed(), %% Reset Random function
Expand Down Expand Up @@ -63,6 +64,15 @@ test_gb_sets_words(Words, Set) ->
end, end,
Words). Words).


test_patricia_words(Words, Tree) ->
lists:foreach(
fun(Word) ->
true = patricia:is_element(Word, Tree)
end,
Words),
false = patricia:is_element(notthere, Tree).


test_dict_words(Words, Dict) -> test_dict_words(Words, Dict) ->
lists:foreach( lists:foreach(
fun(W) -> fun(W) ->
Expand All @@ -84,46 +94,52 @@ test_map(Generator, TestFun) ->
TestFun(lists:reverse(Ws), S), TestFun(lists:reverse(Ws), S),
TestFun(list_shuffle(Ws), S). TestFun(list_shuffle(Ws), S).


h_rb_set_test() -> %% h_rb_set_test() ->
test_map(fun(Ws) -> %% test_map(fun(Ws) ->
h_rb_set:from_list(Ws) %% h_rb_set:from_list(Ws)
end, %% end,
fun test_h_rb_set_words/2). %% fun test_h_rb_set_words/2).


set_test() -> %% set_test() ->
test_map(fun(Ws) -> %% test_map(fun(Ws) ->
sets:from_list(Ws) %% sets:from_list(Ws)
end, %% end,
fun test_sets_words/2). %% fun test_sets_words/2).


dict_test() -> %% dict_test() ->
test_map(fun(Ws) -> %% test_map(fun(Ws) ->
dict:from_list([{K, true} || K <- Ws]) %% dict:from_list([{K, true} || K <- Ws])
end, %% end,
fun test_dict_words/2). %% fun test_dict_words/2).


gb_sets_test() -> %% gb_sets_test() ->
test_map(fun(Ws) -> %% test_map(fun(Ws) ->
gb_sets:from_list(Ws) %% gb_sets:from_list(Ws)
end, %% end,
fun test_gb_sets_words/2). %% fun test_gb_sets_words/2).


gb_trees_test() -> %% gb_trees_test() ->
test_map(fun(Ws) -> %% test_map(fun(Ws) ->
lists:foldl( %% lists:foldl(
fun(K, Tree) -> %% fun(K, Tree) ->
gb_trees:enter(K, true, Tree) %% gb_trees:enter(K, true, Tree)
end, %% end,
gb_trees:empty(), %% gb_trees:empty(),
Ws) %% Ws)
end, %% end,
fun test_gb_trees_words/2). %% fun test_gb_trees_words/2).


rb_sets_test() -> %% rb_sets_test() ->
%% test_map(fun(Ws) ->
%% rbsets:from_list(Ws)
%% end,
%% fun test_rb_sets_words/2).

patricia_test() ->
test_map(fun(Ws) -> test_map(fun(Ws) ->
rbsets:from_list(Ws) patricia:from_list(Ws)
end, end,
fun test_rb_sets_words/2). fun test_patricia_words/2).


-ifdef(EUNIT). -ifdef(EUNIT).
-ifdef(EQC). -ifdef(EQC).
Expand Down
42 changes: 22 additions & 20 deletions src/patricia.erl
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
-define(BIT_MAX, 27). % Set by virtue of erlang:phash2 -define(BIT_MAX, 27). % Set by virtue of erlang:phash2
-type ptree(A) :: empty | {leaf, [A]} | {node, pos_integer(), ptree(A), ptree(A)}. -type ptree(A) :: empty | {leaf, [A]} | {node, pos_integer(), ptree(A), ptree(A)}.


-spec insert(A, ptree(A)) -> ptree(A) | already.


hash(X) -> hash(X) ->
erlang:phash2(X). erlang:phash2(X).
Expand All @@ -20,13 +20,15 @@ from_list(L) ->
new() -> new() ->
empty. empty.


-spec insert(A, ptree(A)) -> ptree(A) | already.
insert(E, empty) -> insert(E, empty) ->
{leaf, [E]}; {leaf, [E]};
insert(E, Tree) -> insert(E, Tree) ->
H = hash(E), H = hash(E),
{Bit, Lt} = find_bit(H, Tree), {Bit, Lt} = find_bit(H, Tree),
insert(H, E, Bit, Lt, Tree). insert(H, E, Bit, Lt, Tree).


-spec find_bit(integer(), ptree(_)) -> {pos_integer(), boolean()}.
find_bit(H, {leaf, [A | _]}) -> find_bit(H, {leaf, [A | _]}) ->
H1 = hash(A), H1 = hash(A),
crit_bit(H, H1); crit_bit(H, H1);
Expand All @@ -39,21 +41,23 @@ find_bit(H, {node, Bit, Left, Right}) ->
crit_bit(I1, I2) -> crit_bit(I1, I2) ->
crit_bit(I1, I2, ?BIT_MAX). crit_bit(I1, I2, ?BIT_MAX).


cmp_lt_bit(I1, I2, N) ->
Bit = (1 bsr N),
(Bit band I1) < (Bit band I2).

crit_bit(I1, I2, N) -> crit_bit(I1, I2, N) ->
Bit = (1 bsr N), Bit = (1 bsl N),
case (Bit band I1) bxor (Bit band I2) of case (Bit band I1) bxor (Bit band I2) of
0 -> 0 ->
crit_bit(I1, I2, N-1); crit_bit(I1, I2, N-1);
_ -> _ ->
{N, cmp_lt_bit(I1, I2, N)} {N, cmp_lt_bit(I1, I2, N)}
end. end.


-spec cmp_lt_bit(integer(), integer(), pos_integer()) -> boolean().
cmp_lt_bit(I1, I2, N) ->
Bit = (1 bsl N),
(Bit band I1) < (Bit band I2).


inspect_bit(H, Bit) -> inspect_bit(H, Bit) ->
case H band (1 bsr Bit) of case H band (1 bsl Bit) of
0 -> left; 0 -> left;
_ -> right _ -> right
end. end.
Expand All @@ -74,9 +78,9 @@ insert(_H, E, Bit, Lt, {leaf, Es} = Lf) ->
insert(H, E, Bit, Lt, {node, CBit, Left, Right}) when Bit < CBit -> insert(H, E, Bit, Lt, {node, CBit, Left, Right}) when Bit < CBit ->
case inspect_bit(H, CBit) of case inspect_bit(H, CBit) of
left -> left ->
{node, CBit, insert(H, E, Lt, Bit, Left), Right}; {node, CBit, insert(H, E, Bit, Lt, Left), Right};
right -> right ->
{node, CBit, Left, insert(H, E, Lt, Bit, Right)} {node, CBit, Left, insert(H, E, Bit, Lt, Right)}
end; end;
insert(_H, E, Bit, Lt, {node, CBit, _Left, _Right} = N) when Bit > CBit -> insert(_H, E, Bit, Lt, {node, CBit, _Left, _Right} = N) when Bit > CBit ->
case Lt of case Lt of
Expand All @@ -88,23 +92,21 @@ insert(_H, E, Bit, Lt, {node, CBit, _Left, _Right} = N) when Bit > CBit ->


is_element(Key, Tree) -> is_element(Key, Tree) ->
H = hash(Key), H = hash(Key),
is_element1(H, Key, 0, Tree). is_element(H, Key, Tree).


is_element1(_, _, _, empty) -> false; is_element(_, _, empty) -> false;
is_element1(_H, Key, _Cnt, {leaf, Elems}) -> is_element(_H, Key, {leaf, Elems}) ->
lists:member(Key, Elems); lists:member(Key, Elems);
is_element1(H, Key, Cnt, {node, Bit, L, R}) -> is_element(H, Key, {node, Bit, L, R}) ->
case H band (1 bsr (Cnt + Bit)) of case inspect_bit(H, Bit) of
0 -> is_element1(H, Key, Cnt+Bit, L); left ->
1 -> is_element1(H, Key, Cnt+Bit, R) is_element(H, Key, L);
right ->
is_element(H, Key, R)
end. end.
















0 comments on commit 4dcfbf8

Please sign in to comment.