Skip to content
This repository was archived by the owner on Dec 17, 2024. It is now read-only.

Commit 5bce9df

Browse files
author
Grigory Starinkin
authored
Merge pull request #20 from elbrujohalcon/brujo-behavior
Improve behavior implementation
2 parents 4b1abc4 + e74923f commit 5bce9df

File tree

3 files changed

+89
-14
lines changed

3 files changed

+89
-14
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
_build
12
.eunit
23
deps
34
ebin
@@ -8,4 +9,4 @@ erl_crash.dump
89
*.so
910
*.o
1011
*.d
11-
.rebar
12+
.rebar

src/hyper.erl

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ new(P) ->
3737

3838
-spec new(precision(), module()) -> filter().
3939
new(P, Mod) when 4 =< P andalso P =< 16 andalso is_atom(Mod) ->
40-
#hyper{p = P, registers = {Mod, Mod:new(P)}}.
40+
#hyper{p = P, registers = {Mod, hyper_register:new(Mod, P)}}.
4141

4242
-spec is_hyper(filter()) -> boolean().
4343
is_hyper(#hyper{}) -> true;
@@ -53,7 +53,7 @@ insert(Value, #hyper{registers = {Mod, Registers}, p = P} = Hyper)
5353
ZeroCount = run_of_zeroes(RegisterValue) + 1,
5454

5555
%% Registers are only allowed to increase, implement by backend
56-
Hyper#hyper{registers = {Mod, Mod:set(Index, ZeroCount, Registers)}};
56+
Hyper#hyper{registers = {Mod, hyper_register:set(Mod, Index, ZeroCount, Registers)}};
5757

5858
insert(_Value, _Hyper) ->
5959
error(badarg).
@@ -76,7 +76,7 @@ union(Filters) when is_list(Filters) ->
7676
end, Filters),
7777

7878
[First | _] = Filters,
79-
First#hyper{registers = {Mod, Mod:max_merge(Registers)}};
79+
First#hyper{registers = {Mod, hyper_register:max_merge(Mod, Registers)}};
8080

8181
%% mixed P, but still must have same backend
8282
[{MinP, Mod} | _] ->
@@ -103,17 +103,17 @@ intersect_card(Left, Right) when Left#hyper.p =:= Right#hyper.p ->
103103
-spec card(filter()) -> float().
104104
card(#hyper{registers = {Mod, Registers0}, p = P}) ->
105105
M = trunc(pow(2, P)),
106-
Registers = Mod:compact(Registers0),
106+
Registers = hyper_register:compact(Mod, Registers0),
107107

108-
RegisterSum = Mod:register_sum(Registers),
108+
RegisterSum = hyper_register:register_sum(Mod, Registers),
109109

110110
E = alpha(M) * pow(M, 2) / RegisterSum,
111111
Ep = case E =< 5 * M of
112112
true -> E - estimate_bias(E, P);
113113
false -> E
114114
end,
115115

116-
V = Mod:zero_count(Registers),
116+
V = hyper_register:zero_count(Mod, Registers),
117117

118118
H = case V of
119119
0 ->
@@ -133,14 +133,14 @@ precision(#hyper{p = Precision}) ->
133133
Precision.
134134

135135
bytes(#hyper{registers = {Mod, Registers}}) ->
136-
Mod:bytes(Registers).
136+
hyper_register:bytes(Mod, Registers).
137137

138138
compact(#hyper{registers = {Mod, Registers}} = Hyper) ->
139-
Hyper#hyper{registers = {Mod, Mod:compact(Registers)}}.
139+
Hyper#hyper{registers = {Mod, hyper_register:compact(Mod, Registers)}}.
140140

141141
reduce_precision(P, #hyper{p = OldP, registers = {Mod, Registers}} = Hyper)
142142
when P < OldP ->
143-
Hyper#hyper{p = P, registers = {Mod, Mod:reduce_precision(P, Registers)}};
143+
Hyper#hyper{p = P, registers = {Mod, hyper_register:reduce_precision(Mod, P, Registers)}};
144144
reduce_precision(P, #hyper{p = P} = Filter) ->
145145
Filter.
146146

@@ -150,12 +150,12 @@ reduce_precision(P, #hyper{p = P} = Filter) ->
150150

151151
-spec to_json(filter()) -> any().
152152
to_json(#hyper{p = P, registers = {Mod, Registers}}) ->
153-
Compact = Mod:compact(Registers),
153+
Compact = hyper_register:compact(Mod, Registers),
154154
{[
155155
{<<"p">>, P},
156156
{<<"registers">>, base64:encode(
157157
zlib:gzip(
158-
Mod:encode_registers(Compact)))}
158+
hyper_register:encode_registers(Mod, Compact)))}
159159
]}.
160160

161161
-spec from_json(any()) -> filter().
@@ -168,7 +168,7 @@ from_json({Struct}, Mod) ->
168168
Bytes = zlib:gunzip(
169169
base64:decode(
170170
proplists:get_value(<<"registers">>, Struct))),
171-
Registers = Mod:decode_registers(Bytes, P),
171+
Registers = hyper_register:decode_registers(Mod, Bytes, P),
172172

173173
#hyper{p = P, registers = {Mod, Registers}}.
174174

@@ -354,7 +354,7 @@ perf_report() ->
354354
Filter = insert_many(generate_unique(Card), new(P, Mod)),
355355

356356
{Mod, Registers} = Filter#hyper.registers,
357-
Bytes = Mod:encode_registers(Registers),
357+
Bytes = hyper_register:encode_registers(Mod, Registers),
358358
Filled = lists:filter(fun (I) -> binary:at(Bytes, I) =/= 0 end,
359359
lists:seq(0, M-1)),
360360

src/hyper_register.erl

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
%% to allow for backend-specific optimizations.
55
-module(hyper_register).
66

7+
-type t() :: module().
8+
9+
-export_type([t/0]).
10+
11+
-export([new/2, set/4, compact/2, max_merge/2, max_merge/3, reduce_precision/3,
12+
register_sum/2, zero_count/2, encode_registers/2, decode_registers/3, bytes/2]).
13+
714
%% @doc: Creates a new instance of the backend. The return value of
815
%% this function will be passed to all functions in this module.
916
-callback new(P :: hyper:precision()) ->
@@ -63,3 +70,70 @@
6370
%% @doc: Size in bytes used to represent the registers in memory.
6471
-callback bytes(hyper:registers()) ->
6572
integer().
73+
74+
%% @doc: Creates a new instance of the backend. The return value of
75+
%% this function will be passed to all functions in this module.
76+
-spec new(t(), P :: hyper:precision()) -> hyper:registers().
77+
new(RegisterImpl, P) ->
78+
RegisterImpl:new(P).
79+
80+
%% @doc: Set the register to the given value, *only* if the value
81+
%% already stored is lower than the new value. The backend needs to
82+
%% ensure the register value is only allowed to increase.
83+
-spec set(t(), Index :: integer(), Value :: integer(), hyper:registers()) ->
84+
hyper:registers().
85+
set(RegisterImpl, Index, Value, Registers) ->
86+
RegisterImpl:set(Index, Value, Registers).
87+
88+
%% @doc: Compact is always called before any attempt at reading (sum,
89+
%% zero count, etc) or merging. It is intended to give backends that
90+
%% buffer the writes a chance to flush the buffer before the registers
91+
%% are needed.
92+
-spec compact(t(), hyper:registers()) -> hyper:registers().
93+
compact(RegisterImpl, Registers) ->
94+
RegisterImpl:compact(Registers).
95+
96+
%% @doc: Merge any number of registers, used to calculate the
97+
%% union. For two register values at the same index, the max value
98+
%% must be in the resulting register.
99+
-spec max_merge(t(), [hyper:registers()]) -> hyper:registers().
100+
max_merge(RegisterImpl, RegisterLists) ->
101+
RegisterImpl:max_merge(RegisterLists).
102+
103+
%% @doc: Same as max_merge/1 but used when we know only two filters
104+
%% are merged.
105+
-spec max_merge(t(), hyper:registers(), hyper:registers()) -> hyper:registers().
106+
max_merge(RegisterImpl, Registers1, Registers2) ->
107+
RegisterImpl:max_merge(Registers1, Registers2).
108+
109+
%% @doc: Reduce the precision of the registers. Used for mixed-precision
110+
%% union by first reducing the precision to the lowest of all filters.
111+
-spec reduce_precision(t(), hyper:precision(), hyper:registers()) -> hyper:registers().
112+
reduce_precision(RegisterImpl, Precision, Registers) ->
113+
RegisterImpl:reduce_precision(Precision, Registers).
114+
115+
%% @doc: Sum of 2^-R where R is the value in each register.
116+
-spec register_sum(t(), hyper:registers()) -> float().
117+
register_sum(RegisterImpl, Registers) ->
118+
RegisterImpl:register_sum(Registers).
119+
120+
%% @doc: Count of registers set to 0.
121+
-spec zero_count(t(), hyper:registers()) -> integer().
122+
zero_count(RegisterImpl, Registers) ->
123+
RegisterImpl:zero_count(Registers).
124+
125+
%% @doc: Encode and decode are called to convert the in-memory
126+
%% representation of the backend to the serialized format. Must return
127+
%% one binary where each register is encoded as an 8-bit integer.
128+
-spec encode_registers(t(), hyper:registers()) -> binary().
129+
encode_registers(RegisterImpl, Registers) ->
130+
RegisterImpl:encode_registers(Registers).
131+
132+
-spec decode_registers(t(), binary(), hyper:precision()) -> hyper:registers().
133+
decode_registers(RegisterImpl, Encoded, Precision) ->
134+
RegisterImpl:decode_registers(Encoded, Precision).
135+
136+
%% @doc: Size in bytes used to represent the registers in memory.
137+
-spec bytes(t(), hyper:registers()) -> integer().
138+
bytes(RegisterImpl, Registers) ->
139+
RegisterImpl:bytes(Registers).

0 commit comments

Comments
 (0)