add method
Add v under key id. Runs one graph-insertion step; not thread
safe. Ids need not be unique, but removeId removes only the
first match.
Implementation
void add(Object? id, Vector v) {
if (v.dim != dim) {
throw StateError(
'HnswIndex.add: vector dim ${v.dim} != index dim $dim',
);
}
final nodeId = _ids.length;
_ensureCapacity(nodeId + 1);
_data.setRange(nodeId * dim, (nodeId + 1) * dim, v.values);
_ids.add(id);
final level = _randomLevel();
_nodeLevel.add(level);
_links.add(List<List<int>>.generate(level + 1, (_) => <int>[]));
if (_entry < 0) {
_entry = nodeId;
_topLayer = level;
return;
}
var cur = _entry;
for (var lc = _topLayer; lc > level; lc--) {
cur = _greedyDescendNode(nodeId, cur, lc);
}
for (var lc = math.min(level, _topLayer); lc >= 0; lc--) {
final candidates = _searchLayerNode(nodeId, cur, efConstruction, lc);
final selected = _selectHeuristic(candidates, _maxLinksAt(lc)).toList();
_links[nodeId][lc] = selected;
for (final nb in selected) {
final nbLinks = _links[nb][lc];
nbLinks.add(nodeId);
final maxL = _maxLinksAt(lc);
if (nbLinks.length > maxL) {
final cand = <(double, int)>[
for (final v in nbLinks) (_distNodeNode(nb, v), v),
];
final trimmed = _selectHeuristic(cand, maxL).toList();
_links[nb][lc]
..clear()
..addAll(trimmed);
}
}
cur = _closestOf(candidates);
}
if (level > _topLayer) {
_topLayer = level;
_entry = nodeId;
}
}