A pure ANSI-C implementation of calculating a SimHash over 4-byte tuples (including multiplicities) for a given byte stream. Simple and reasonably fast, no dynamic memory allocations (outside of some stack usage). Uses a counting bloom filter to count multiplicities while keeping memory consumption constant.
A pure ANSI-C implementation of calculating a SimHash over 4-byte tuples
(including multiplicities) for a given byte stream. Simple and reasonably fast,
no dynamic memory allocations (outside of some stack usage).
Calculates a 256-bit hash for the input stream. Two input streams can be
compared to each other by calculating the hamming distance between the hashes;
this is just a matter of XOR and popcount.
The output approximates the cosine similarity –
S = |W1 \cap W2| / sqrt(|W1||W2|). The sets W1 and W2 in this scenario are the
4-byte sequences encountered in the input buffers, where the n-th occurrence of
the same sequence is treated as distinct from the n+1-th occurrence.
Let’s calculate through an example:
Buffer1: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
Buffer2: ABCDEFGHIJKLMNOPQRSTUVWXYZ____abcdefghijklmnopqrstuvwxyz
There are 52 4-tuples in the first buffer, and 56 4-tuples in the second buffer.
Buffer2 does not contain the tuples XYZa, YZab, Zabc
which are present in
Buffer1, and Buffer1 does not contain the tuples XYZ_, YZ__, Z___, ____, ___a, __ab, _abc
which are present in Buffer2.
This means that the cosine similarity is: 49 / sqrt(53 * 56) = 49 / sqrt(2968) =
49 / 54 ~= 0.899. The distance is hence a bit more than 0.1.
Let’s have a look:
$ ./simhash_compare ./testfile1.txt ./testfile2.txt
95e24d0f855f73aa-563488dc5716e32f-0095f987c0616a19-0be46dc9599106b8
d5c04d0e865f73aa-deb4885d5636ea27-1691f983c0616a19-1bc1edea59938679
Hamming Distance: 34 - 0.13
Seems to work.
The code itself is well-suited to be embedded into kernel drivers etc. - the
runtime is predictable in terms of the number of bytes that need to be processed,
outside of some stack use no dynamic allocations can happen, there is no
recursion and no other unwanted surprises.