/
markov_ets.erl
74 lines (63 loc) · 2.01 KB
/
markov_ets.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
-module(markov_ets).
-export([new/1, from_list/2, to_list/1, append/3, lookup/2, choose_nth/2]).
-define(WORD_MAX, 100).
new(Opts) ->
%% {{{token(), token()}, pair}, integer()}
%% {{{token(), token()}, token()}, integer()}
{Ets, Name, Opts1} = lists:foldr(fun optfold/2,
{ets, ?MODULE, [ordered_set]},
Opts),
{Ets, Ets:new(Name, Opts1)}.
optfold({module, Mod}, {_Mod, Name, Acc}) ->
{Mod, Name, Acc};
optfold({name, Name}, {Mod, _Name, Acc}) ->
{Mod, Name, Acc};
optfold(Opt, {Mod, Name, Acc}) ->
{Mod, Name, [Opt | Acc]}.
from_list([{K, V} | Rest], State={Ets, T}) ->
Total = lists:foldl(
fun ({Token, C}, Acc) ->
true = Ets:insert_new(T, {{K, Token}, C}),
C + Acc
end,
0,
V),
true = Ets:insert_new(T, {{K, pair}, Total}),
from_list(Rest, State);
from_list([], State) ->
State.
to_list(State={Ets, T}) ->
[{K, unroll(K, State)}
|| K <- Ets:select(T, [{{{'$1',pair},'_'},[],['$1']}])].
unroll(K, {Ets, T}) ->
Ets:select(
T,
[{{{K, '$1'}, '$2'}, [{'=/=', '$1', pair}], [{{'$1', '$2'}}]}]).
inc({Ets, T}, K) ->
try Ets:update_counter(T, K, 1)
catch error:badarg ->
Ets:insert_new(T, {K, 1}),
1
end.
append(K, V, State) ->
inc(State, {K, pair}),
inc(State, {K, V}),
State.
lookup(K, State={Ets, T}) ->
try Ets:lookup_element(T, {K, pair}, 2)
of C ->
{value, {C, {K, State}}}
catch error:badarg ->
none
end.
choose_nth(N, {K, State={Ets, T}}) ->
%% NOTE: It's important that 'pair' sorts lower than
%% 'start', 'stop', and any binary!
choose_nth_iter(N, Ets:next(T, {K, pair}), State).
choose_nth_iter(N, K={_Prev, Next}, State={Ets, T}) ->
case Ets:lookup_element(T, K, 2) of
V when N > V ->
choose_nth_iter(N - V, Ets:next(T, K), State);
_ ->
Next
end.