Skip to content
Browse files

experiment with a variant of splay tree

  • Loading branch information...
1 parent 8a277c6 commit d2520d356a2873198e9af09e36f068d87d49c02b @etrepum committed May 31, 2012
Showing with 178 additions and 2 deletions.
  1. +106 −0 src/cstree.erl
  2. +56 −0 src/markov_cstree.erl
  3. +16 −2 src/markov_server.erl
View
106 src/cstree.erl
@@ -0,0 +1,106 @@
+%% @doc Counting splay tree.
+-module(cstree).
+
+-type(cstree_node(T) :: {Left :: cstree(T),
+ Right :: cstree(T),
+ Value :: T,
+ ElemCount :: non_neg_integer(),
+ TotalCount :: non_neg_integer()}).
+
+-type(cstree(T) :: empty | cstree_node(T)).
+-export([new/0, increment/2, increment/3, total/1, count/1,
+ from_list/1, to_list/1, seek/2]).
+-define(E, empty).
+
+-spec new() -> cstree(_).
+new() ->
+ ?E.
+
+-spec from_list([{T, non_neg_integer()}]) -> cstree(T).
+from_list(L) ->
+ lists:foldl(fun increment/2, new(), L).
+
+-spec to_list(cstree(T)) -> [{T, non_neg_integer()}].
+to_list(T) ->
+ to_list(T, [], []).
+
+-spec increment({T, non_neg_integer()}, cstree(T)) -> cstree(T).
+increment({Elem, Inc}, T) ->
+ increment(Elem, Inc, T).
+
+-spec increment(T, non_neg_integer(), cstree(T)) -> cstree(T).
+increment(Elem, Inc, T) ->
+ case partition(Elem, T) of
+ {{Left, Right, X, XC, _XTC}, Big} when X =:= Elem ->
+ Right = ?E,
+ t(Left, Big, X, Inc + XC);
+ {Small, Big} ->
+ t(Small, Big, Elem, Inc)
+ end.
+
+-spec total(cstree(_)) -> non_neg_integer().
+total({_Left, _Right, _Elem, _ElemCount, Total}) ->
+ Total;
+total(?E) ->
+ 0.
+
+-spec count(cstree(_)) -> non_neg_integer().
+count({_Left, _Right, _Elem, ElemCount, _Total}) ->
+ ElemCount;
+count(?E) ->
+ 0.
+
+-spec seek(non_neg_integer(), cstree_node(T)) -> T.
+seek(N, {L, R, X, XC, _XTC}) ->
+ case N - total(L) of
+ NL when NL >= 0 ->
+ case NL - XC of
+ NR when NR >= 0 ->
+ seek(NR, R);
+ _ ->
+ X
+ end;
+ _ ->
+ seek(N, L)
+ end.
+
+partition(Pivot, T={Left, Right, X, XC, _XTC}) when X =< Pivot ->
+ case Right of
+ {Right1, Right2, Y, YC, _YTC} ->
+ case Y =< Pivot of
+ true ->
+ {Small, Big} = partition(Pivot, Right2),
+ {t(t(Left, Right1, X, XC), Small, Y, YC), Big};
+ false ->
+ {Small, Big} = partition(Pivot, Right1),
+ {t(Left, Small, X, XC), t(Big, Right2, Y, YC)}
+ end;
+ ?E ->
+ {T, Right}
+ end;
+partition(Pivot, T={Left, Right, X, XC, _TC}) ->
+ case Left of
+ {Left1, Left2, Y, YC, _YTC} ->
+ case Y =< Pivot of
+ true ->
+ {Small, Big} = partition(Pivot, Left2),
+ {t(Left1, Small, Y, YC), t(Big, Right, X, XC)};
+ false ->
+ {Small, Big} = partition(Pivot, Left1),
+ {Small, t(Big, t(Left2, Right, X, XC), Y, YC)}
+ end;
+ ?E ->
+ {Left, T}
+ end;
+partition(_Pivot, T=?E) ->
+ {T, T}.
+
+t(Left, Right, Elem, ElemCount) ->
+ {Left, Right, Elem, ElemCount, total(Left) + total(Right) + ElemCount}.
+
+to_list(T={_Left, Right, _X, _XC, _XTC}, Stack, Acc) ->
+ to_list(Right, [T | Stack], Acc);
+to_list(?E, [{Left, _Right, X, XC, _XTC} | Stack], Acc) ->
+ to_list(Left, Stack, [{X, XC} | Acc]);
+to_list(?E, [], Acc) ->
+ Acc.
View
56 src/markov_cstree.erl
@@ -0,0 +1,56 @@
+-module(markov_cstree).
+-export([new/1, from_list/2, to_list/1, append/3, lookup/2,
+ choose_nth/2]).
+
+-define(WORD_MAX, 100).
+
+new([]) ->
+ gb_trees:empty().
+
+from_list(L, EmptyT) ->
+ lists:foldl(fun ({K, V}, T) ->
+ gb_trees:insert(K, subtree_from_list(V), T)
+ end,
+ EmptyT,
+ L).
+
+to_list(T) ->
+ to_orddict_iter(gb_trees:next(gb_trees:iterator(T))).
+
+append(K, V, T) ->
+ case gb_trees:lookup(K, T) of
+ none ->
+ gb_trees:insert(K, increment(V, cstree:new()), T);
+ {value, SubT} ->
+ gb_trees:update(K, increment(V, SubT), T)
+ end.
+
+increment(K, SubT) ->
+ cstree:increment(K, 1, SubT).
+
+lookup(K, T) ->
+ case gb_trees:lookup(K, T) of
+ {value, SubT} ->
+ case cstree:total(SubT) of
+ Total when Total > 0 ->
+ {value, {Total, SubT}};
+ Total ->
+ error({total_is_zero, Total, K, SubT})
+ end;
+ none ->
+ none
+ end.
+
+choose_nth(N, SubT) ->
+ cstree:seek(N - 1, SubT).
+
+subtree_from_list(L) ->
+ cstree:from_list(L).
+
+to_orddict_iter(none) ->
+ [];
+to_orddict_iter({K, V, Iter}) ->
+ [{K, to_orddict_subtree(V)} | to_orddict_iter(gb_trees:next(Iter))].
+
+to_orddict_subtree(T) ->
+ cstree:to_list(T).
View
18 src/markov_server.erl
@@ -1,12 +1,22 @@
-module(markov_server).
-behaviour(gen_server).
+-export([input/1, output/1, output/0]).
-export([start_link/1, start/1]).
-export([code_change/3, handle_call/3, handle_cast/2, handle_info/2,
init/1, terminate/2]).
--record(state, {}).
+-record(state, {t :: term()}).
+
+output() ->
+ output([]).
+
+output(L) ->
+ gen_server:call(?MODULE, {output, L}).
+
+input(B) ->
+ ok = gen_server:cast(?MODULE, {input, B}).
start_link(Args) ->
gen_server:start_link(?MODULE, Args, []).
@@ -15,14 +25,18 @@ start(Args) ->
gen_server:start(?MODULE, Args, []).
init([]) ->
- {ok, #state{}}.
+ {ok, #state{t=markov:new(markov_cstree)}}.
+handle_cast({input, B}, S=#state{t=T}) ->
+ {noreply, S#state{t=markov:input(B, T)}};
handle_cast(_Req, State) ->
{noreply, State}.
handle_info(_Req, State) ->
{noreply, State}.
+handle_call({output, L}, _From, S=#state{t=T}) ->
+ {reply, markov:output(L, T), S};
handle_call(_Req, _From, State) ->
{reply, ignored, State}.

0 comments on commit d2520d3

Please sign in to comment.
Something went wrong with that request. Please try again.