add method

void add(
  1. Object? id,
  2. Vector v
)

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;
  }
}