From d5d4dd9e0e3ac1f361233090be10c39d3040ab7f Mon Sep 17 00:00:00 2001 From: masajiro Date: Wed, 22 May 2019 14:33:19 +0900 Subject: [PATCH] v1.7.4 add C API functions for ngtd --- VERSION | 2 +- bin/ngt/ngt.cpp | 2 + lib/NGT/Capi.cpp | 121 ++++++++++++++++++++++++++++++++++++++------ lib/NGT/Capi.h | 6 +++ lib/NGT/Command.cpp | 1 - lib/NGT/Optimizer.h | 77 ++++++++++++++++++++++++++++ 6 files changed, 192 insertions(+), 17 deletions(-) diff --git a/VERSION b/VERSION index bbf649f..10c0880 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.7.3 \ No newline at end of file +1.7.4 diff --git a/bin/ngt/ngt.cpp b/bin/ngt/ngt.cpp index 4114cda..dd2f71d 100644 --- a/bin/ngt/ngt.cpp +++ b/bin/ngt/ngt.cpp @@ -82,6 +82,8 @@ main(int argc, char **argv) ngt.prune(args); } else if (command == "reconstruct-graph") { ngt.reconstructGraph(args); + } else if (command == "eval") { + NGT::Optimizer::evaluate(args); #ifndef NGT_SHARED_MEMORY_ALLOCATOR } else if (command == "extract-query") { NGT::Optimizer::extractQueries(args); diff --git a/lib/NGT/Capi.cpp b/lib/NGT/Capi.cpp index 5d698aa..f5e5053 100644 --- a/lib/NGT/Capi.cpp +++ b/lib/NGT/Capi.cpp @@ -265,10 +265,57 @@ NGTObjectDistances ngt_create_empty_results(NGTError error) { } } +static bool ngt_search_index_(NGT::Index* pindex, NGT::Object *ngtquery, size_t size, float epsilon, float radius, NGTObjectDistances results) { + // set search prameters. + NGT::SearchContainer sc(*ngtquery); // search parametera container. + + sc.setResults(static_cast(results)); // set the result set. + sc.setSize(size); // the number of resultant objects. + sc.setRadius(radius); // search radius. + sc.setEpsilon(epsilon); // set exploration coefficient. + + pindex->search(sc); + + // delete the query object. + pindex->deleteObject(ngtquery); + return true; +} + bool ngt_search_index(NGTIndex index, double *query, int32_t query_dim, size_t size, float epsilon, float radius, NGTObjectDistances results, NGTError error) { - if(index == NULL || query == NULL || results == NULL){ + if(index == NULL || query == NULL || results == NULL || query_dim <= 0){ + std::stringstream ss; + ss << "Capi : " << __FUNCTION__ << "() : parametor error: index = " << index << " query = " << query << " results = " << results << " query_dim = " << query_dim; + operate_error_string_(ss, error); + return false; + } + + NGT::Index* pindex = static_cast(index); + NGT::Object *ngtquery = NULL; + + if(radius < 0.0){ + radius = FLT_MAX; + } + + try{ + std::vector vquery(&query[0], &query[query_dim]); + ngtquery = pindex->allocateObject(vquery); + ngt_search_index_(pindex, ngtquery, size, epsilon, radius, results); + }catch(std::exception &err) { + std::stringstream ss; + ss << "Capi : " << __FUNCTION__ << "() : Error: " << err.what(); + operate_error_string_(ss, error); + if(ngtquery != NULL){ + pindex->deleteObject(ngtquery); + } + return false; + } + return true; +} + +bool ngt_search_index_as_float(NGTIndex index, float *query, int32_t query_dim, size_t size, float epsilon, float radius, NGTObjectDistances results, NGTError error) { + if(index == NULL || query == NULL || results == NULL || query_dim <= 0){ std::stringstream ss; - ss << "Capi : " << __FUNCTION__ << "() : parametor error: index = " << index << " query = " << query << " results = " << results; + ss << "Capi : " << __FUNCTION__ << "() : parametor error: index = " << index << " query = " << query << " results = " << results << " query_dim = " << query_dim; operate_error_string_(ss, error); return false; } @@ -281,20 +328,9 @@ bool ngt_search_index(NGTIndex index, double *query, int32_t query_dim, size_t s } try{ - std::vector vquery(&query[0], &query[query_dim]); + std::vector vquery(&query[0], &query[query_dim]); ngtquery = pindex->allocateObject(vquery); - // set search prameters. - NGT::SearchContainer sc(*ngtquery); // search parametera container. - - sc.setResults(static_cast(results)); // set the result set. - sc.setSize(size); // the number of resultant objects. - sc.setRadius(radius); // search radius. - sc.setEpsilon(epsilon); // set exploration coefficient. - - pindex->search(sc); - - // delete the query object. - pindex->deleteObject(ngtquery); + ngt_search_index_(pindex, ngtquery, size, epsilon, radius, results); }catch(std::exception &err) { std::stringstream ss; ss << "Capi : " << __FUNCTION__ << "() : Error: " << err.what(); @@ -307,6 +343,7 @@ bool ngt_search_index(NGTIndex index, double *query, int32_t query_dim, size_t s return true; } + // * deprecated * int32_t ngt_get_size(NGTObjectDistances results, NGTError error) { if(results == NULL){ @@ -346,6 +383,13 @@ NGTObjectDistance ngt_get_result(const NGTObjectDistances results, const uint32_ } ObjectID ngt_insert_index(NGTIndex index, double *obj, uint32_t obj_dim, NGTError error) { + if(index == NULL || obj == NULL || obj_dim == 0){ + std::stringstream ss; + ss << "Capi : " << __FUNCTION__ << "() : parametor error: index = " << index << " obj = " << obj << " obj_dim = " << obj_dim; + operate_error_string_(ss, error); + return 0; + } + try{ NGT::Index* pindex = static_cast(index); std::vector vobj(&obj[0], &obj[obj_dim]); @@ -359,6 +403,13 @@ ObjectID ngt_insert_index(NGTIndex index, double *obj, uint32_t obj_dim, NGTErro } ObjectID ngt_append_index(NGTIndex index, double *obj, uint32_t obj_dim, NGTError error) { + if(index == NULL || obj == NULL || obj_dim == 0){ + std::stringstream ss; + ss << "Capi : " << __FUNCTION__ << "() : parametor error: index = " << index << " obj = " << obj << " obj_dim = " << obj_dim; + operate_error_string_(ss, error); + return 0; + } + try{ NGT::Index* pindex = static_cast(index); std::vector vobj(&obj[0], &obj[obj_dim]); @@ -371,6 +422,46 @@ ObjectID ngt_append_index(NGTIndex index, double *obj, uint32_t obj_dim, NGTErro } } +ObjectID ngt_insert_index_as_float(NGTIndex index, float *obj, uint32_t obj_dim, NGTError error) { + if(index == NULL || obj == NULL || obj_dim == 0){ + std::stringstream ss; + ss << "Capi : " << __FUNCTION__ << "() : parametor error: index = " << index << " obj = " << obj << " obj_dim = " << obj_dim; + operate_error_string_(ss, error); + return 0; + } + + try{ + NGT::Index* pindex = static_cast(index); + std::vector vobj(&obj[0], &obj[obj_dim]); + return pindex->insert(vobj); + }catch(std::exception &err) { + std::stringstream ss; + ss << "Capi : " << __FUNCTION__ << "() : Error: " << err.what(); + operate_error_string_(ss, error); + return 0; + } +} + +ObjectID ngt_append_index_as_float(NGTIndex index, float *obj, uint32_t obj_dim, NGTError error) { + if(index == NULL || obj == NULL || obj_dim == 0){ + std::stringstream ss; + ss << "Capi : " << __FUNCTION__ << "() : parametor error: index = " << index << " obj = " << obj << " obj_dim = " << obj_dim; + operate_error_string_(ss, error); + return 0; + } + + try{ + NGT::Index* pindex = static_cast(index); + std::vector vobj(&obj[0], &obj[obj_dim]); + return pindex->append(vobj); + }catch(std::exception &err) { + std::stringstream ss; + ss << "Capi : " << __FUNCTION__ << "() : Error: " << err.what(); + operate_error_string_(ss, error); + return 0; + } +} + bool ngt_batch_append_index(NGTIndex index, float *obj, uint32_t data_count, NGTError error) { try{ NGT::Index* pindex = static_cast(index); diff --git a/lib/NGT/Capi.h b/lib/NGT/Capi.h index b5ee891..12da3cc 100644 --- a/lib/NGT/Capi.h +++ b/lib/NGT/Capi.h @@ -77,6 +77,8 @@ bool ngt_set_property_distance_type_cosine(NGTProperty, NGTError); NGTObjectDistances ngt_create_empty_results(NGTError); bool ngt_search_index(NGTIndex, double*, int32_t, size_t, float, float, NGTObjectDistances, NGTError); + +bool ngt_search_index_as_float(NGTIndex, float*, int32_t, size_t, float, float, NGTObjectDistances, NGTError); int32_t ngt_get_size(NGTObjectDistances, NGTError); // deprecated @@ -88,6 +90,10 @@ ObjectID ngt_insert_index(NGTIndex, double*, uint32_t, NGTError); ObjectID ngt_append_index(NGTIndex, double*, uint32_t, NGTError); +ObjectID ngt_insert_index_as_float(NGTIndex, float*, uint32_t, NGTError); + +ObjectID ngt_append_index_as_float(NGTIndex, float*, uint32_t, NGTError); + bool ngt_batch_append_index(NGTIndex, float*, uint32_t, NGTError); bool ngt_create_index(NGTIndex, uint32_t, NGTError); diff --git a/lib/NGT/Command.cpp b/lib/NGT/Command.cpp index ac1547d..f413e4b 100644 --- a/lib/NGT/Command.cpp +++ b/lib/NGT/Command.cpp @@ -840,4 +840,3 @@ } } - diff --git a/lib/NGT/Optimizer.h b/lib/NGT/Optimizer.h index b453f37..ea4cdb0 100644 --- a/lib/NGT/Optimizer.h +++ b/lib/NGT/Optimizer.h @@ -779,6 +779,83 @@ namespace NGT { return 0; } + static void evaluate(Args &args) + { + const string usage = "Usage: ngt eval [-n number-of-results] [-m mode(r=recall)] [-g ground-truth-size] [-o output-mode] ground-truth search-result\n" + " Make a ground truth list (linear search): \n" + " ngt search -i s -n 20 -o e index query.list > ground-truth.list"; + + string gtFile, resultFile; + try { + gtFile = args.get("#1"); + } catch (...) { + cerr << "ground truth is not specified." << endl; + cerr << usage << endl; + return; + } + try { + resultFile = args.get("#2"); + } catch (...) { + cerr << "result file is not specified." << endl; + cerr << usage << endl; + return; + } + + size_t resultSize = args.getl("n", 0); + if (resultSize != 0) { + cerr << "The specified number of results=" << resultSize << endl; + } + + size_t groundTruthSize = args.getl("g", 0); + + bool recall = false; + if (args.getChar("m", '-') == 'r') { + cerr << "Recall" << endl; + recall = true; + } + char omode = args.getChar("o", '-'); + + ifstream resultStream(resultFile); + if (!resultStream) { + cerr << "Cannot open the specified target file. " << resultFile << endl; + cerr << usage << endl; + return; + } + + ifstream gtStream(gtFile); + if (!gtStream) { + cerr << "Cannot open the specified GT file. " << gtFile << endl; + cerr << usage << endl; + return; + } + + vector accuracies; + string type; + size_t actualResultSize = 0; + evaluate(gtStream, resultStream, accuracies, type, actualResultSize, resultSize, groundTruthSize, recall); + + cout << "# # of evaluated resultant objects per query=" << actualResultSize << endl; + if (recall) { + cout << "# " << type << "\t# of Queries\tRecall\t"; + } else { + cout << "# " << type << "\t# of Queries\tPrecision\t"; + } + if (omode == 'd') { + cout << "# of computations\t# of visted nodes" << endl; + for (auto it = accuracies.begin(); it != accuracies.end(); ++it) { + cout << (*it).keyValue << "\t" << (*it).totalCount << "\t" << (*it).averageAccuracy << "\t" + << (*it).averageDistanceCount << "\t" << (*it).averageVisitCount << endl; + } + } else { + cout << "Time(msec)\t# of computations\t# of visted nodes" << endl; + for (auto it = accuracies.begin(); it != accuracies.end(); ++it) { + cout << (*it).keyValue << "\t" << (*it).totalCount << "\t" << (*it).averageAccuracy << "\t" << (*it).averageTime << "\t" + << (*it).averageDistanceCount << "\t" << (*it).averageVisitCount << endl; + } + } + + } + }; }; // NGT