func (l *LightLOF) add(v nearest.FeatureVector) ID { var nnID nearest.ID if len(l.kdists) <= l.maxSize { l.kdists = append(l.kdists, 0) l.lrds = append(l.lrds, 0) nnID = nearest.ID(len(l.kdists)) } else { // unlearn nnID = nearest.ID(l.rg.Intn(l.maxSize)) + 1 l.kdists[nnID-1] = 0 l.lrds[nnID-1] = 0 } l.nn.SetRow(nnID, v) neighbors := l.nn.NeighborRowFromID(nnID, l.rnnNum) nestedNeighbors := map[ID][]nearest.IDist{} for i := range neighbors { nnID := neighbors[i].ID id := ID(nnID) nnResult := l.nn.NeighborRowFromID(nnID, l.nnNum) nestedNeighbors[id] = nnResult l.kdists[id-1] = nnResult[len(nnResult)-1].Dist } for i := range neighbors { nnID := neighbors[i].ID id := ID(nnID) nn := nestedNeighbors[id] var lrd float32 = 1 if len(nn) > 0 { length := minInt(len(nn), l.nnNum) var sumReachability float32 for i := 0; i < length; i++ { sumReachability += maxFloat32(nn[i].Dist, l.kdists[nn[i].ID-1]) } if sumReachability == 0 { lrd = inf32 } else { lrd = float32(length) / sumReachability } } l.lrds[id-1] = lrd } return ID(nnID) }
func (l *LightLOF) collectLRDsByID(id ID) (float32, []float32) { nnID := nearest.ID(id) neighbors := l.nn.NeighborRowFromID(nearest.ID(id), l.nnNum+1) if len(neighbors) == 0 { return inf32, nil } for i := range neighbors { if neighbors[i].ID == nnID { copy(neighbors[1:i+1], neighbors[0:]) neighbors = neighbors[1:] break } } if len(neighbors) > l.nnNum { neighbors = neighbors[:l.nnNum] } if len(neighbors) == 0 { return inf32, nil } return l.collectLRDsImpl(neighbors) }