@@ -343,15 +343,13 @@ class ReadOnlyGraph : public deglib::search::SearchGraph {
343343 * The result set contains internal indices.
344344 */
345345 template <deglib::DistanceFunction COMPARATOR , bool use_max_distance_count, bool use_filter>
346- deglib::search::ResultSet searchImpl (const std::vector<uint32_t >& entry_vertex_indices, const std::byte* query, const float eps, const uint32_t initial_k , const deglib::graph::Filter* filter, const uint32_t max_distance_computation_count) const
346+ deglib::search::ResultSet searchImpl (const std::vector<uint32_t >& entry_vertex_indices, const std::byte* query, const uint32_t initial_k, const float eps, const bool include_entry , const deglib::graph::Filter* filter, const uint32_t max_distance_computation_count) const
347347 {
348+ uint32_t distance_computation_count = 0 ;
348349 const auto dist_func_param = this ->feature_space_ .get_dist_func_param ();
349350 const auto feature_size = this ->feature_space_ .get_data_size ();
350- const size_t degree = this ->edges_per_vertex_ ;
351351 const size_t vertex_count = this ->size ();
352-
353352 size_t k = std::min (vertex_count, static_cast <size_t >(initial_k));
354- uint32_t distance_computation_count = 0 ;
355353
356354 // set of checked vertex ids
357355 const auto vl = visited_list_pool_->getFreeVisitedList ();
@@ -360,12 +358,12 @@ class ReadOnlyGraph : public deglib::search::SearchGraph {
360358
361359 // items to traverse next
362360 auto next_vertices = deglib::search::UncheckedSet ();
363- next_vertices.reserve (k*degree );
361+ next_vertices.reserve (k*this -> edges_per_vertex_ );
364362
365363 // result set
366364 // TODO: custom priority queue with an internal Variable Length Array wrapped in a macro with linear-scan search and memcopy
367- auto results = deglib::search::ResultSet ();
368- results.reserve (k);
365+ auto results = deglib::search::ResultSet ();
366+ results.reserve (k+ 1 );
369367
370368 // if the filter only contains few valid ids brute force them all
371369 if constexpr (use_filter) {
@@ -400,13 +398,15 @@ class ReadOnlyGraph : public deglib::search::SearchGraph {
400398 const auto feature = reinterpret_cast <const float *>(this ->feature_by_index (index));
401399 const auto distance = COMPARATOR::compare (query, feature, dist_func_param);
402400 next_vertices.emplace (index, distance);
403- if constexpr (use_filter) {
404- if (filter->is_valid (this ->label_by_index (index))) {
401+ if (include_entry) {
402+ if constexpr (use_filter) {
403+ if (filter->is_valid (this ->label_by_index (index))) {
404+ results.emplace (index, distance);
405+ }
406+ } else {
405407 results.emplace (index, distance);
406- }
407- } else {
408- results.emplace (index, distance);
409- }
408+ }
409+ }
410410
411411 // early stop after to many computations
412412 if constexpr (use_max_distance_count) {
@@ -435,7 +435,7 @@ class ReadOnlyGraph : public deglib::search::SearchGraph {
435435
436436 size_t good_neighbor_count = 0 ;
437437 const auto neighbor_indices = this ->neighbors_by_index (next_vertex.getInternalIndex ());
438- for (size_t i = 0 ; i < degree ; i++) {
438+ for (size_t i = 0 ; i < this -> edges_per_vertex_ ; i++) {
439439 const auto neighbor_index = neighbor_indices[i];
440440 if (checked_ids[neighbor_index] != checked_ids_tag) {
441441 checked_ids[neighbor_index] = checked_ids_tag;
@@ -491,124 +491,26 @@ class ReadOnlyGraph : public deglib::search::SearchGraph {
491491 return results;
492492 }
493493
494- /* *
495- * The result set contains internal indices.
496- */
497- deglib::search::ResultSet search (const std::vector<uint32_t >& entry_vertex_indices, const std::byte* query, const float eps, const uint32_t k, const deglib::graph::Filter* filter = nullptr , const uint32_t max_distance_computation_count = 0 ) const override
498- {
499- return feature_space_.compute ([&]<deglib::DistanceFunction Dist>(Dist) {
500- if (filter) {
501- if (max_distance_computation_count == 0 ) {
502- return searchImpl<Dist, false , true >(entry_vertex_indices, query, eps, k, filter, 0 );
503- } else {
504- return searchImpl<Dist, true , true >(entry_vertex_indices, query, eps, k, filter, max_distance_computation_count);
505- }
506- } else {
507- if (max_distance_computation_count == 0 ) {
508- return searchImpl<Dist, false , false >(entry_vertex_indices, query, eps, k, nullptr , 0 );
509- } else {
510- return searchImpl<Dist, true , false >(entry_vertex_indices, query, eps, k, nullptr , max_distance_computation_count);
511- }
512- }
513- });
514- }
515-
516- /* *
517- * The result set contains internal indices.
518- */
519- template <deglib::DistanceFunction COMPARATOR >
520- deglib::search::ResultSet exploreImpl (const uint32_t entry_vertex_index, const uint32_t k, const bool include_entry, const uint32_t max_distance_computation_count) const
521- {
522- uint32_t distance_computation_count = 0 ;
523- const auto dist_func_param = this ->feature_space_ .get_dist_func_param ();
524- const auto feature_size = this ->feature_space_ .get_data_size ();
525-
526- // set of checked vertex ids
527- const auto vl = visited_list_pool_->getFreeVisitedList ();
528- auto * checked_ids = vl->get_visited ();
529- const auto checked_ids_tag = vl->get_tag ();
530-
531- // items to traverse next
532- auto next_vertices = deglib::search::UncheckedSet ();
533- next_vertices.reserve (k*this ->edges_per_vertex_ );
534-
535- // result set
536- auto results = deglib::search::ResultSet ();
537- results.reserve (k);
538-
539- // add the entry vertex index to the vertices which gets checked next and ignore it for further checks
540- checked_ids[entry_vertex_index] = checked_ids_tag;
541- next_vertices.emplace (entry_vertex_index, 0 .0f );
542- if (include_entry)
543- results.emplace (entry_vertex_index, 0 .0f );
544- const auto query = this ->feature_by_index (entry_vertex_index);
545-
546- // search radius
547- auto radius = std::numeric_limits<float >::max ();
548-
549- // iterate as long as good elements are in the next_vertices queue and max_calcs is not yet reached
550- auto good_neighbors = std::array<uint32_t , 256 >(); // this limits the neighbor count to 256 using Variable Length Array wrapped in a macro
551- while (next_vertices.empty () == false )
494+ protected:
495+ deglib::search::ResultSet search_intern (const std::vector<uint32_t >& entry_vertex_indices, const std::byte* query, const uint32_t k, const float eps = 0 .0f , const bool include_entry = true , const deglib::graph::Filter* filter = nullptr , const uint32_t max_distance_computation_count = 0 ) const override
552496 {
553- // next vertex to check
554- const auto next_vertex = next_vertices.top ();
555- next_vertices.pop ();
556-
557- uint8_t good_neighbor_count = 0 ;
558- const auto neighbor_indices = this ->neighbors_by_index (next_vertex.getInternalIndex ());
559- for (uint8_t i = 0 ; i < this ->edges_per_vertex_ ; i++) {
560- const auto neighbor_index = neighbor_indices[i];
561- if (checked_ids[neighbor_index] != checked_ids_tag) {
562- checked_ids[neighbor_index] = checked_ids_tag;
563- good_neighbors[good_neighbor_count++] = neighbor_index;
564- }
565- }
566-
567- if (good_neighbor_count == 0 )
568- continue ;
569-
570- memory::prefetch (reinterpret_cast <const char *>(this ->feature_by_index (good_neighbors[0 ])), feature_size);
571- for (uint8_t i = 0 ; i < good_neighbor_count; i++) {
572- memory::prefetch (reinterpret_cast <const char *>(this ->feature_by_index (good_neighbors[std::min (i + 1 , good_neighbor_count - 1 )])), feature_size);
573-
574- const auto neighbor_index = good_neighbors[i];
575- const auto neighbor_feature_vector = this ->feature_by_index (neighbor_index);
576- const auto neighbor_distance = COMPARATOR::compare (query, neighbor_feature_vector, dist_func_param);
577-
578- if (neighbor_distance < radius) {
579-
580- // check the neighborhood of this vertex later
581- next_vertices.emplace (neighbor_index, neighbor_distance);
582-
583- // remember the vertex, if its better than the worst in the result list
584- results.emplace (neighbor_index, neighbor_distance);
585-
586- // update the search radius
587- if (results.size () > k) {
588- results.pop ();
589- radius = results.top ().getDistance ();
497+ return feature_space_.compute ([&]<deglib::DistanceFunction Dist>(Dist) {
498+ if (filter) {
499+ if (max_distance_computation_count == 0 ) {
500+ return searchImpl<Dist, false , true >(entry_vertex_indices, query, k, eps, include_entry, filter, 0 );
501+ } else {
502+ return searchImpl<Dist, true , true >(entry_vertex_indices, query, k, eps, include_entry, filter, max_distance_computation_count);
503+ }
504+ } else {
505+ if (max_distance_computation_count == 0 ) {
506+ return searchImpl<Dist, false , false >(entry_vertex_indices, query, k, eps, include_entry, nullptr , 0 );
507+ } else {
508+ return searchImpl<Dist, true , false >(entry_vertex_indices, query, k, eps, include_entry, nullptr , max_distance_computation_count);
590509 }
591510 }
592-
593- // early stop after to many computations
594- if (max_distance_computation_count > 0 && ++distance_computation_count >= max_distance_computation_count)
595- return results;
596- }
511+ });
597512 }
598513
599- return results;
600- }
601-
602- /* *
603- * The result set contains internal indices.
604- */
605- deglib::search::ResultSet explore (const uint32_t entry_vertex_index, const uint32_t k, const bool include_entry, const uint32_t max_distance_computation_count = 0 ) const override
606- {
607- return feature_space_.compute ([&]<deglib::DistanceFunction Dist>(Dist) {
608- return exploreImpl<Dist>(entry_vertex_index, k, include_entry, max_distance_computation_count);
609- });
610- }
611-
612514};
613515
614516
0 commit comments