Hello and thank you.
In the meantime I found some documentation that led me to implement this:
defp cosine_similarity(a, b) do
dot(a, b) / (euclidean_norm(a) * euclidean_norm(b))
end
defp dot(a, b, acc \\ 0)
defp dot([ha | ta], [hb | tb], acc), do: dot(ta, tb, acc + ha * hb)
defp dot([], [], acc), do: acc
defp euclidean_norm(values) do
# ||A|| = √(A₁² + A₂² + … + Aₙ²)
values |> Enum.reduce(0, fn v, sum -> sum + :math.pow(v, 2) end) |> :math.sqrt()
end
Which seems similar but does not seem to be equal to what you wrote.
It works anyway. I’m going to try your code.
Actually it is way faster than with NX because I do not have everything in “the Nx way”. I have an ETS table that contains 150 000 tensors of 200 f32 values.
I should convert that to a single tensor “keyed” with binary names if possible and try with that. But for now with my ad hoc implementation and my raw data (coming from parsing a word2vec file) it’s faster to just have lists of floats.
I also tried to use exla but it was slower (I do not have a graphic card on this computer).
Edit well your code is faster (less traversals I guess) and seems to yield the same results, though I am not sure why because I suck at maths but I guess divide by norm for each coordinate or divide at the end is the same).
I am building a solver for the french version of cemantle.
Thanks!






















