Current section

Files

Jump to
fixpoint src bitset.erl.save
Raw

src/bitset.erl.save

-module(bitset).
-export([new/0, new/1, from_list/1, insert/2,
intersect/1, union/1, difference/2,
contains/2, foldl/3, foldr/3,
pmap/2]).
%% Create a new bitset, with no bits set.
%% return A new bitset
new() ->
{ ?MODULE, { 1, 0 }}.
%% Create a new bitset from the entries in the given list of numbers
%% Elems A list of integers that should be set in this new bitset
new(Elems) when is_list(Elems) ->
from_list(Elems, new()).
from_list(Elems) when is_list(Elems) ->
from_list(Elems, new()).
%% Put a given Key (non-negative integer) into the bitset
%% Key Non-negative integer to be stored in the set
%% Set The set in which to store the key
%% return A new bitset, with the desired key set
insert(Key, { ?MODULE, Tree = { Depth, _}}) when is_integer(Key), Key >= 0 ->
{ ToMake, Path } = split_key(Depth, Key),
LargeEnough = grow(ToMake, Tree),
{ ?MODULE, set(Path, LargeEnough) }.
%% Determine the intersection of the given list of bitsets. The resulting
%% bitset will have bits set where all given sets had them set, and nowhere
%% else.
%% List A list of bitsets
%% return A new bitset that is the intersection of the given bitsets
intersect([]) -> bitset:new();
intersect([Final]) -> Final;
intersect([{ ?MODULE, First }, { ?MODULE, Second } | Rest]) ->
intersect([{ ?MODULE, imerge(First, Second)} | Rest]).
%% Determine the union of the given list of bitsets. The resulting bitset will
%% have bits set where any of the given sets had them set, and nowhere else.
%% List A list of bitsets to union together
%% return A new bitset which is the union of the given bitsets
union([]) -> bitset:new();
union([Final]) -> Final;
union([{ ?MODULE, First }, { ?MODULE, Second } | Rest]) ->
union([{ ?MODULE, umerge(First, Second)} | Rest]).
difference({ ?MODULE, Left = { LD, _ }}, { ?MODULE, Right = { RD, _ }}) ->
{ SLeft, SRight } = if
LD < RD ->
{ grow(RD-LD, Left), Right };
LD > RD ->
{ Left, grow(LD-RD, Right) };
LD =:= RD ->
{ Left, Right }
end,
{ ?MODULE, diff_eq(SLeft, SRight) }.
%% Test whether a bit is set in the given bitset.
%% Key The key to test
%% Set The bitset to test against
%% return true of that bit is set, false otherwise
contains(Key, { ?MODULE, { Depth, _ } = Tree })
when is_integer(Key), Key >= 0 ->
case split_key(Depth, Key) of
{ 0, Path } ->
%io:format("Path is ~w~n", [Path]),
contains2(Path, Tree);
{ _ToMake, _Exists } ->
%io:format("Key is too large for this set~n"),
false
end.
foldl(Fun, Accum0, { ?MODULE, Tree }) -> fold(left, Fun, Accum0, 0, Tree).
foldr(Fun, Accum0, { ?MODULE, Tree }) -> fold(right, Fun, Accum0, 0, Tree).
pmap(Fun, { ?MODULE, Tree }) ->
pmap(Fun, Tree, 0, 2).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helper for new/1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
from_list([], Bs) -> Bs;
from_list([Head | Tail ], Bs) when is_integer(Head) ->
from_list(Tail, insert(Head, Bs)).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helper for insert/2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% empty entry at the bottom becomes a number with the correct bit set
set([Final], empty) when is_integer(Final), Final >= 0 ->
{ 1, 1 bsl Final };
%% good node at the bottom gets a new bit set
set([Final], { 1, Number })
when is_integer(Final), Final >= 0 ->
{ 1, Number bor (1 bsl Final) };
%% non-bottom node gets a new child
set([Pos0 | Rest], { Depth, Children })
when is_integer(Pos0), Pos0 >= 0 ->
Pos = Pos0+1,
New = set(Rest, element(Pos, Children)),
{ Depth, setelement(Pos, Children, New) };
%% non-bottom empty becomes a child container, and gets a child
set([Pos0 | Rest], empty)
when is_integer(Pos0), Pos0 >= 0 ->
Pos = Pos0 + 1,
Children = erlang:make_tuple(27, empty),
Depth = length(Rest)+1,
{ Depth, setelement(Pos, Children, set(Rest, empty)) }.
%% Function used to make the tree deeper, so it can hold elements that are too
%% large for its current size
grow(0, Tree) -> Tree;
grow(Levels, { ChildDepth, _ } = Tree)
when is_integer(Levels), Levels > 0 ->
%io:format("Growing, Levels is ~p~n", [Levels]),
Children = erlang:make_tuple(27, empty),
grow(Levels-1, { ChildDepth+1, setelement(1, Children, Tree) }).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helpers for intersect/1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
imerge(First = { FDepth, FTree }, Second = { SDepth, STree }) ->
if
FDepth > SDepth ->
imerge(element(1, FTree), Second);
FDepth < SDepth ->
imerge(First, element(1, STree));
FDepth =:= SDepth ->
imerge_equal(First, Second)
end.
imerge_equal(_, empty) -> empty;
imerge_equal(empty, _) -> empty;
imerge_equal({ 1, FNumber }, { 1, SNumber }) ->
{ 1, FNumber band SNumber };
imerge_equal({ Depth, FTree }, { Depth, STree }) ->
NewTree = lists:zipwith(fun imerge_equal/2,
tuple_to_list(FTree), tuple_to_list(STree)),
{ Depth, list_to_tuple(NewTree) }.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helpers for union/1
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
umerge(First = { FDepth, _ }, Second = { SDepth, _ }) ->
if
FDepth > SDepth ->
umerge_equal(First, grow(FDepth-SDepth, Second));
FDepth < SDepth ->
umerge_equal(grow(SDepth-FDepth, First), Second);
FDepth =:= SDepth ->
umerge_equal(First, Second)
end.
umerge_equal(empty, empty) -> empty;
umerge_equal(First, empty) -> First;
umerge_equal(empty, Second) -> Second;
umerge_equal({ 1, FNumber }, { 1, SNumber }) ->
{ 1, FNumber bor SNumber };
umerge_equal({ Depth, FTree }, { Depth, STree }) ->
NewTree = lists:zipwith(fun umerge_equal/2,
tuple_to_list(FTree), tuple_to_list(STree)),
{ Depth, list_to_tuple(NewTree) }.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helpers for difference/2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff_eq(empty, _) -> empty;
diff_eq(Left, empty) -> Left;
diff_eq({ 1, LNumber }, { 1, RNumber }) ->
RInvert = ((1 bsl 27 - 1) bxor RNumber),
{ 1, LNumber band RInvert };
diff_eq({ Depth, Left }, { Depth, Right }) ->
NewTree = lists:zipwith(fun diff_eq/2,
tuple_to_list(Left), tuple_to_list(Right)),
{ Depth, list_to_tuple(NewTree) }.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helpers for fold[lr]/3
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
fold(_Dir, _Fun, Accum, _Pre, empty) -> Accum;
fold(Dir, Fun, Accum, Pre, { 1, Number }) ->
%io:format("Iterating on leaf, pre is ~p, Number is ~p~n", [ Pre, Number ]),
lists:foldl(
fun(Bit, AccumI) ->
case Number band (1 bsl Bit) of
0 -> AccumI;
_ -> Fun(Pre * 27 + Bit, AccumI)
end
end,
Accum,
case Dir of
left -> lists:seq(0, 26);
right -> lists:reverse(lists:seq(0, 26))
end);
fold(Dir, Fun, Accum, Pre, { _Depth, Children }) ->
%io:format("Pre is ~p, Tree is ~p~n", [ Pre, { Depth, Children }]),
Offset = Pre*27,
lists:foldl(
fun(Element, AccumI) ->
Child = element(Element+1, Children),
fold(Dir, Fun, AccumI, Offset+Element, Child)
end,
Accum,
case Dir of
left -> lists:seq(0,26);
right -> lists:reverse(lists:seq(0, 26))
end).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helper for pmap/2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
pmap(Fun, Tree, Pre, 0) ->
pmap_fold(Fun, Tree, Pre);
pmap(_Fun, empty, _, _) ->
[];
pmap(Fun, Tree = { Depth, _Children }, Pre, _Levels) when Depth =< 3 ->
pmap_fold(Fun, Tree, Pre);
pmap(Fun, { _Depth, Children }, Pre, Levels) ->
Offset = Pre*27,
Root = self(),
Pids = [
spawn(fun() ->
Root ! { self(), pmap(Fun, Child, Offset+Element, Levels-1) }
end)
|| { Element, Child }
<- lists:zip(lists:seq(0,26), tuple_to_list(Children)) ],
lists:foldl(
fun(Pid, Accum) ->
receive { Pid, Result } ->
Result ++ Accum
end
end,
[],
Pids).
pmap_fold(Fun, Tree, Pre) ->
fold(
left,
fun(Bit, Accum) ->
case Fun(Bit) of
{ ok, Value } ->
[ Value | Accum ];
nil ->
Accum
end
end,
[],
Pre,
Tree).
%% Helper function for split_key, generates X and Y where X*27+Y = Key; used for
%% converting the key to base-27, which is how our values are stored.
%% Key Non-negative integer to divmod to our satisfaction
%% return { Next, Diff } where Diff < 27 and Next * 27 + Diff = Key
next_diff(Key) when is_integer(Key), Key >= 0 ->
Next = Key div 27,
Diff = Key - ( Next * 27 ),
{ Next, Diff }.
%% Determine the base-27 form of the given non-negative integer. This will be
%% returned as a list of numbers in the range [0, 26]; each number is a
%% coefficient in the base-27 form of the given key, with the most significant
%% at the head of the list.
%% Also given to this function is the current depth of the tree; this function
%% will return how much larger the tree would have to be to hold this key, or 0
%% if the tree is already large enough.
%% Depth The size of the tree we are generating a key address for
%% Key The key we want to find in the tree
%% return { NewLevels, Path }
split_key(Depth, Key) when is_integer(Key), Key >= 0 ->
split_key(Depth, Key, 0, []).
%% Helper functions for split_key/2, with some accumulators added.
split_key(0, 0, New, Path) ->
{ New, Path };
split_key(0, Key, New, Path) when is_integer(Key), Key >= 0 ->
{ Next, Diff } = next_diff(Key),
split_key(0, Next, New + 1,[ Diff | Path ]);
split_key(Depth, 0, New, Path) ->
split_key(Depth-1, 0, New, [ 0 | Path ]);
split_key(Depth, Key, New, Path) when is_integer(Key), Key >= 0 ->
{ Next, Diff } = next_diff(Key),
split_key(Depth-1, Next, New, [ Diff | Path ]).
contains2(_, empty) ->
%io:format("Empty is false~n"),
false;
contains2([ Final ], { 1, Number })
when is_integer(Final), Final >= 0 ->
%io:format("Final is ~p, Number is ~p~n", [Final, Number]),
(Number band (1 bsl Final)) =/= 0;
contains2([ Pos0 | Rest ], { _Depth, Children })
when is_integer(Pos0), Pos0 >= 0 ->
Pos = Pos0+1,
%io:format("Children are ~p, Pos is ~p~n", [Children, Pos]),
contains2(Rest, element(Pos, Children)).