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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
# File 'lib/neighbor/sqlite.rb', line 36
def self.setup_functions(db)
db.create_function("neighbor_l2_distance", 2) do |func, a, b, c|
func.result =
if a.nil? || b.nil?
nil
else
raise SQLite3::SQLException, "different vector dimensions" if a.bytesize != b.bytesize
fmt = c == 1 ? "c*" : "f*"
a = a.unpack(fmt)
b = b.unpack(fmt)
Math.sqrt(a.zip(b).sum { |ai, bi| (ai - bi)**2 })
end
end
db.create_function("neighbor_max_inner_product", 2) do |func, a, b, c|
func.result =
if a.nil? || b.nil?
nil
else
raise SQLite3::SQLException, "different vector dimensions" if a.bytesize != b.bytesize
fmt = c == 1 ? "c*" : "f*"
a = a.unpack(fmt)
b = b.unpack(fmt)
-a.zip(b).sum { |ai, bi| ai * bi }
end
end
db.create_function("neighbor_cosine_distance", 2) do |func, a, b, c|
func.result =
if a.nil? || b.nil?
nil
else
raise SQLite3::SQLException, "different vector dimensions" if a.bytesize != b.bytesize
fmt = c == 1 ? "c*" : "f*"
a = a.unpack(fmt)
b = b.unpack(fmt)
similarity = a.zip(b).sum { |ai, bi| ai * bi }
norma = a.sum { |v| v * v }
normb = b.sum { |v| v * v }
1.0 - (similarity / Math.sqrt(norma * normb)).clamp(-1.0, 1.0)
end
end
db.create_function("neighbor_l1_distance", 2) do |func, a, b, c|
func.result =
if a.nil? || b.nil?
nil
else
raise SQLite3::SQLException, "different vector dimensions" if a.bytesize != b.bytesize
fmt = c == 1 ? "c*" : "f*"
a = a.unpack(fmt)
b = b.unpack(fmt)
a.zip(b).sum { |ai, bi| (ai - bi).abs }
end
end
db.create_function("neighbor_hamming_distance", 2) do |func, a, b|
func.result =
if a.nil? || b.nil?
nil
else
raise SQLite3::SQLException, "different vector dimensions" if a.bytesize != b.bytesize
a.each_byte.zip(b.each_byte).sum { |ai, bi| (ai ^ bi).to_s(2).count("1") }
end
end
db.create_function("neighbor_jaccard_distance", 2) do |func, a, b|
func.result =
if a.nil? || b.nil?
nil
else
raise SQLite3::SQLException, "different vector dimensions" if a.bytesize != b.bytesize
ab = a.each_byte.zip(b.each_byte).sum { |ai, bi| (ai & bi).to_s(2).count("1") }
aa = a.unpack1("B*").count("1")
bb = b.unpack1("B*").count("1")
ab == 0 ? 1.0 : 1.0 - (ab / (aa + bb - ab).to_f)
end
end
end
|