From d6e423f079cd8ef7c98ab159e410212f23e5db75 Mon Sep 17 00:00:00 2001 From: datelier <57349093+datelier@users.noreply.github.com> Date: Wed, 6 Nov 2024 11:27:04 +0900 Subject: [PATCH] WIP: add rust-agent-qbg --- rust/Cargo.lock | 11 + rust/Cargo.toml | 1 + rust/libs/algorithm/Cargo.toml | 1 + rust/libs/algorithms/qbg/Cargo.toml | 29 +++ rust/libs/algorithms/qbg/build.rs | 35 +++ rust/libs/algorithms/qbg/src/input.cpp | 328 +++++++++++++++++++++++++ rust/libs/algorithms/qbg/src/input.h | 104 ++++++++ rust/libs/algorithms/qbg/src/lib.rs | 218 ++++++++++++++++ 8 files changed, 727 insertions(+) create mode 100644 rust/libs/algorithms/qbg/Cargo.toml create mode 100644 rust/libs/algorithms/qbg/build.rs create mode 100644 rust/libs/algorithms/qbg/src/input.cpp create mode 100644 rust/libs/algorithms/qbg/src/input.h create mode 100644 rust/libs/algorithms/qbg/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 32e11207e8a..fa970e683d5 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -62,6 +62,7 @@ dependencies = [ "faiss", "ngt", "proto", + "qbg", "tonic 0.12.3", ] @@ -3340,6 +3341,16 @@ dependencies = [ "tonic-types", ] +[[package]] +name = "qbg" +version = "0.1.0" +dependencies = [ + "anyhow", + "cxx", + "cxx-build", + "miette", +] + [[package]] name = "quote" version = "1.0.37" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 924c8a24d65..45a4605d515 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -21,5 +21,6 @@ members = [ "bin/agent", "libs/algorithm", "libs/algorithms/ngt", + "libs/algorithms/qbg", "libs/algorithms/faiss", ] diff --git a/rust/libs/algorithm/Cargo.toml b/rust/libs/algorithm/Cargo.toml index 7af0713ebf9..5af2470cd85 100644 --- a/rust/libs/algorithm/Cargo.toml +++ b/rust/libs/algorithm/Cargo.toml @@ -22,5 +22,6 @@ edition = "2021" anyhow = "1.0.88" faiss = { version = "0.1.0", path = "../algorithms/faiss" } ngt = { version = "0.1.0", path = "../algorithms/ngt" } +qbg = { version = "0.1.0", path = "../algorithms/qbg" } proto = { version = "0.1.0", path = "../proto" } tonic = "0.12.2" diff --git a/rust/libs/algorithms/qbg/Cargo.toml b/rust/libs/algorithms/qbg/Cargo.toml new file mode 100644 index 00000000000..6385d00596d --- /dev/null +++ b/rust/libs/algorithms/qbg/Cargo.toml @@ -0,0 +1,29 @@ +# +# Copyright (C) 2019-2024 vdaas.org vald team +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# You may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +[package] +name = "qbg" +version = "0.1.0" +edition = "2021" + +[dependencies] +anyhow = "1.0.88" +cxx = { version = "1.0.128", features = ["c++20"] } + +[build-dependencies] +cxx-build = "1.0.128" +miette = { version = "7.2.0", features = ["fancy"] } + +[dev-dependencies] diff --git a/rust/libs/algorithms/qbg/build.rs b/rust/libs/algorithms/qbg/build.rs new file mode 100644 index 00000000000..46a557607a3 --- /dev/null +++ b/rust/libs/algorithms/qbg/build.rs @@ -0,0 +1,35 @@ +// +// Copyright (C) 2019-2024 vdaas.org vald team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +fn main() -> miette::Result<()> { + let current_dir = std::env::current_dir().unwrap(); + println!("cargo:rustc-link-search=native={}", current_dir.display()); + + cxx_build::bridge("src/lib.rs") + .file("src/input.cpp") + .flag_if_supported("-std=c++20") + .flag_if_supported("-fopenmp") + .flag_if_supported("-DNGT_BFLOAT_DISABLED") + .compile("qbg-rs"); + + println!("cargo:rustc-link-search=native=/usr/local/lib"); + println!("cargo:rustc-link-lib=static=ngt"); + println!("cargo:rustc-link-lib=blas"); + println!("cargo:rustc-link-lib=lapack"); + println!("cargo:rustc-link-lib=dylib=gomp"); + println!("cargo:rerun-if-changed=src/*"); + + Ok(()) +} diff --git a/rust/libs/algorithms/qbg/src/input.cpp b/rust/libs/algorithms/qbg/src/input.cpp new file mode 100644 index 00000000000..f6b0d91ab2d --- /dev/null +++ b/rust/libs/algorithms/qbg/src/input.cpp @@ -0,0 +1,328 @@ +// +// Copyright (C) 2019-2024 vdaas.org vald team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#include "qbg/src/input.h" +#include "qbg/src/lib.rs.h" + +Property::Property() +{ + qbg_construction_parameters = new QBGConstructionParameters(); + qbg_build_parameters = new QBGBuildParameters(); +} + +QBGConstructionParameters *Property::get_qbg_construction_parameters() +{ + return qbg_construction_parameters; +} + +void Property::init_qbg_construction_parameters() +{ + qbg_initialize_construction_parameters(qbg_construction_parameters); +} + +void Property::set_qbg_construction_parameters( + rust::usize extended_dimension, + rust::usize dimension, + rust::usize number_of_subvectors, + rust::usize number_of_blobs, + rust::i32 internal_data_type, + rust::i32 data_type, + rust::i32 distance_type) +{ + qbg_initialize_construction_parameters(qbg_construction_parameters); + qbg_construction_parameters->extended_dimension = extended_dimension; + qbg_construction_parameters->dimension = dimension; + qbg_construction_parameters->number_of_subvectors = number_of_subvectors; + qbg_construction_parameters->number_of_blobs = number_of_blobs; + qbg_construction_parameters->internal_data_type = internal_data_type; + qbg_construction_parameters->data_type = data_type; + qbg_construction_parameters->distance_type = distance_type; +} + +void Property::set_extended_dimension(rust::usize extended_dimension) +{ + qbg_construction_parameters->extended_dimension = extended_dimension; +} + +void Property::set_dimension(rust::usize dimension) +{ + qbg_construction_parameters->dimension = dimension; +} + +void Property::set_number_of_subvectors(rust::usize number_of_subvectors) +{ + qbg_construction_parameters->number_of_subvectors = number_of_subvectors; +} + +void Property::set_number_of_blobs(rust::usize number_of_blobs) +{ + qbg_construction_parameters->number_of_blobs = number_of_blobs; +} + +void Property::set_internal_data_type(rust::i32 internal_data_type) +{ + qbg_construction_parameters->internal_data_type = internal_data_type; +} + +void Property::set_data_type(rust::i32 data_type) +{ + qbg_construction_parameters->data_type = data_type; +} + +void Property::set_distance_type(rust::i32 distance_type) +{ + qbg_construction_parameters->distance_type = distance_type; +} + +QBGBuildParameters *Property::get_qbg_build_parameters() +{ + return qbg_build_parameters; +} + +void Property::init_qbg_build_parameters() +{ + qbg_initialize_build_parameters(qbg_build_parameters); +} + +void Property::set_qbg_build_parameters( + rust::i32 hierarchical_clustering_init_mode, + rust::usize number_of_first_objects, + rust::usize number_of_first_clusters, + rust::usize number_of_second_objects, + rust::usize number_of_second_clusters, + rust::usize number_of_third_clusters, + rust::usize number_of_objects, + rust::usize number_of_subvectors, + rust::i32 optimization_clustering_init_mode, + rust::usize rotation_iteration, + rust::usize subvector_iteration, + rust::usize number_of_matrices, + bool rotation, + bool repositioning) +{ + qbg_initialize_build_parameters(qbg_build_parameters); + qbg_build_parameters->hierarchical_clustering_init_mode = hierarchical_clustering_init_mode; + qbg_build_parameters->number_of_first_objects = number_of_first_objects; + qbg_build_parameters->number_of_first_clusters = number_of_first_clusters; + qbg_build_parameters->number_of_second_objects = number_of_second_objects; + qbg_build_parameters->number_of_second_clusters = number_of_second_clusters; + qbg_build_parameters->number_of_third_clusters = number_of_third_clusters; + qbg_build_parameters->number_of_objects = number_of_objects; + qbg_build_parameters->number_of_subvectors = number_of_subvectors; + qbg_build_parameters->optimization_clustering_init_mode = optimization_clustering_init_mode; + qbg_build_parameters->rotation_iteration = rotation_iteration; + qbg_build_parameters->subvector_iteration = subvector_iteration; + qbg_build_parameters->number_of_matrices = number_of_matrices; + qbg_build_parameters->rotation = rotation; + qbg_build_parameters->repositioning = repositioning; +} + +void Property::set_hierarchical_clustering_init_mode(rust::i16 hierarchical_clustering_init_mode) +{ + qbg_build_parameters->hierarchical_clustering_init_mode = hierarchical_clustering_init_mode; +} + +void Property::set_number_of_first_objects(rust::usize number_of_first_objects) +{ + qbg_build_parameters->number_of_first_objects = number_of_first_objects; +} + +void Property::set_number_of_first_clusters(rust::usize number_of_first_clusters) +{ + qbg_build_parameters->number_of_first_clusters = number_of_first_clusters; +} + +void Property::set_number_of_second_objects(rust::u32 number_of_second_objects) +{ + qbg_build_parameters->number_of_second_objects = number_of_second_objects; +} + +void Property::set_number_of_second_clusters(rust::usize number_of_second_clusters) +{ + qbg_build_parameters->number_of_second_clusters = number_of_second_clusters; +} + +void Property::set_number_of_third_clusters(rust::usize number_of_third_clusters) +{ + qbg_build_parameters->number_of_third_clusters = number_of_third_clusters; +} + +void Property::set_number_of_objects(rust::usize number_of_objects) +{ + qbg_build_parameters->number_of_objects = number_of_objects; +} + +void Property::set_number_of_subvectors_for_bp(rust::usize number_of_subvectors) +{ + qbg_build_parameters->number_of_subvectors = number_of_subvectors; +} + +void Property::set_optimization_clustering_init_mode(rust::i32 optimization_clustering_init_mode) +{ + qbg_build_parameters->optimization_clustering_init_mode = optimization_clustering_init_mode; +} + +void Property::set_rotation_iteration(rust::usize rotation_iteration) +{ + qbg_build_parameters->rotation_iteration = rotation_iteration; +} + +void Property::set_subvector_iteration(rust::usize subvector_iteration) +{ + qbg_build_parameters->subvector_iteration = subvector_iteration; +} + +void Property::set_number_of_matrices(rust::usize number_of_matrices) +{ + qbg_build_parameters->number_of_matrices = number_of_matrices; +} + +void Property::set_rotation(bool rotation) +{ + qbg_build_parameters->rotation = rotation; +} + +void Property::set_repositioning(bool repositioning) +{ + qbg_build_parameters->repositioning = repositioning; +} + +Index::Index(const rust::String &path, Property &p) +{ + NGTError err = ngt_create_error_object(); + std::string cpath(path); + bool ok = qbg_create(cpath.c_str(), p.get_qbg_construction_parameters(), err); + if (!ok) + { + std::cerr << "Error: " << __func__ << std::endl; + std::cerr << ngt_get_error_string(err) << std::endl; + return; + } + open_index(cpath.c_str(), false); +} + +Index::Index(const rust::String &path, bool prebuilt) +{ + std::string cpath(path); + open_index(cpath.c_str(), prebuilt); +} + +// Index::~Index() +// { +// // close_index(); +// } + +void Index::open_index(const rust::String &path, bool prebuilt) +{ + NGTError err = ngt_create_error_object(); + std::string cpath(path); + index = qbg_open_index(cpath.c_str(), prebuilt, err); + if (index == 0) + { + std::cerr << "Error: " << __func__ << std::endl; + std::cerr << ngt_get_error_string(err) << std::endl; + return; + } +} + +void Index::build_index(const rust::String &path, Property &p) +{ + NGTError err = ngt_create_error_object(); + std::string cpath(path); + bool ok = qbg_build_index(cpath.c_str(), p.get_qbg_build_parameters(), err); + if (!ok) + { + std::cerr << "Error: " << __func__ << std::endl; + std::cerr << ngt_get_error_string(err) << std::endl; + return; + } +} + +void Index::save_index() +{ + NGTError err = ngt_create_error_object(); + bool ok = qbg_save_index(index, err); + if (!ok) + { + std::cerr << "Error: " << __func__ << std::endl; + std::cerr << ngt_get_error_string(err) << std::endl; + return; + } +} + +void Index::close_index() +{ + qbg_close_index(index); +} + +rust::i32 Index::append(rust::Slice v) +{ + NGTError err = ngt_create_error_object(); + float *vec = std::vector(v.begin(), v.end()).data(); + unsigned int id = qbg_append_object(index, vec, v.length(), err); + if (id == 0) + { + std::cerr << ngt_get_error_string(err) << std::endl; + return 0; + } + return id; +} + +void Index::search( + rust::Slice v, + rust::i32 *ids, + rust::f32 *distances) +{ + QBGQuery query; + qbg_initialize_query(&query); + float *vec = std::vector(v.begin(), v.end()).data(); + query.query = vec; + + NGTError err = ngt_create_error_object(); + NGTObjectDistances results = ngt_create_empty_results(err); + bool ok = qbg_search_index(index, query, results, err); + if (!ok) + { + std::cerr << "Error: " << __func__ << std::endl; + std::cerr << ngt_get_error_string(err) << std::endl; + return; + } + + size_t rsize = qbg_get_result_size(results, err); + for (size_t i = 0; i < rsize; i++) + { + NGTObjectDistance obj = qbg_get_result(results, i, err); + ids[i] = obj.id; + distances[i] = obj.distance; + } + + qbg_destroy_results(results); + ngt_destroy_error_object(err); +} + +std::unique_ptr new_property() +{ + return std::make_unique(); +} + +std::unique_ptr new_index(const rust::String &path, Property &p) +{ + return std::make_unique(path, p); +} + +std::unique_ptr new_prebuilt_index(const rust::String &path, bool prebuilt) +{ + return std::make_unique(path, prebuilt); +} \ No newline at end of file diff --git a/rust/libs/algorithms/qbg/src/input.h b/rust/libs/algorithms/qbg/src/input.h new file mode 100644 index 00000000000..f62e888642e --- /dev/null +++ b/rust/libs/algorithms/qbg/src/input.h @@ -0,0 +1,104 @@ +// +// Copyright (C) 2019-2024 vdaas.org vald team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#pragma once + +#include +#include "NGT/NGTQ/Capi.h" +#include "NGT/NGTQ/QuantizedGraph.h" +#include "rust/cxx.h" + +class Property +{ + QBGConstructionParameters *qbg_construction_parameters; + QBGBuildParameters *qbg_build_parameters; + +public: + Property(); + QBGConstructionParameters *get_qbg_construction_parameters(); + void init_qbg_construction_parameters(); + void set_qbg_construction_parameters( + rust::usize, + rust::usize, + rust::usize, + rust::usize, + rust::i32, + rust::i32, + rust::i32); + void set_extended_dimension(rust::usize); + void set_dimension(rust::usize); + void set_number_of_subvectors(rust::usize); + void set_number_of_blobs(rust::usize); + void set_internal_data_type(rust::i32); + void set_data_type(rust::i32); + void set_distance_type(rust::i32); + QBGBuildParameters *get_qbg_build_parameters(); + void init_qbg_build_parameters(); + void set_qbg_build_parameters( + // hierarchical kmeans + rust::i32, + rust::usize, + rust::usize, + rust::usize, + rust::usize, + rust::usize, + // optimization + rust::usize, + rust::usize, + rust::i32, + rust::usize, + rust::usize, + rust::usize, + bool, + bool); + void set_hierarchical_clustering_init_mode(rust::i16); + void set_number_of_first_objects(rust::usize); + void set_number_of_first_clusters(rust::usize); + void set_number_of_second_objects(rust::u32); + void set_number_of_second_clusters(rust::usize); + void set_number_of_third_clusters(rust::usize); + void set_number_of_objects(rust::usize); + void set_number_of_subvectors_for_bp(rust::usize); + void set_optimization_clustering_init_mode(rust::i32); + void set_rotation_iteration(rust::usize); + void set_subvector_iteration(rust::usize); + void set_number_of_matrices(rust::usize); + void set_rotation(bool); + void set_repositioning(bool); +}; + +class Index +{ + void *index; + +public: + Index( + const rust::String &, + Property &); + Index( + const rust::String &, + bool); + // ~Index(); + void open_index(const rust::String &, bool); + void build_index(const rust::String &, Property &); + void save_index(); + void close_index(); + rust::i32 append(rust::Slice); + void search(rust::Slice, rust::i32 *, rust::f32 *); +}; + +std::unique_ptr new_property(); +std::unique_ptr new_index(const rust::String &, Property &); +std::unique_ptr new_prebuilt_index(const rust::String &, bool); \ No newline at end of file diff --git a/rust/libs/algorithms/qbg/src/lib.rs b/rust/libs/algorithms/qbg/src/lib.rs new file mode 100644 index 00000000000..6c15c882e7c --- /dev/null +++ b/rust/libs/algorithms/qbg/src/lib.rs @@ -0,0 +1,218 @@ +// +// Copyright (C) 2019-2024 vdaas.org vald team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// You may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +#[cxx::bridge] +pub mod ffi { + unsafe extern "C++" { + include!("qbg/src/input.h"); + + type Property; + fn new_property() -> UniquePtr; + fn init_qbg_construction_parameters(self: Pin<&mut Property>); + fn set_qbg_construction_parameters( + self: Pin<&mut Property>, + extended_dimension: usize, + dimension: usize, + number_of_subvectors: usize, + number_of_blobs: usize, + internal_data_type: i32, + data_type: i32, + distance_type: i32, + ); + fn set_extended_dimension(self: Pin<&mut Property>, extended_dimension: usize); + fn set_dimension(self: Pin<&mut Property>, dimension: usize); + fn set_number_of_subvectors(self: Pin<&mut Property>, number_of_subvectors: usize); + fn set_number_of_blobs(self: Pin<&mut Property>, number_of_blobs: usize); + fn set_internal_data_type(self: Pin<&mut Property>, internal_data_type: i32); + fn set_data_type(self: Pin<&mut Property>, data_type: i32); + fn set_distance_type(self: Pin<&mut Property>, distance_type: i32); + fn init_qbg_build_parameters(self: Pin<&mut Property>); + fn set_qbg_build_parameters( + self: Pin<&mut Property>, + hierarchical_clustering_init_mode: i32, + number_of_first_objects: usize, + number_of_first_clusters: usize, + number_of_second_objects: usize, + number_of_second_clusters: usize, + number_of_third_clusters: usize, + number_of_objects: usize, + number_of_subvectors: usize, + optimization_clustering_init_mode: i32, + rotation_iteration: usize, + subvector_iteration: usize, + number_of_matrices: usize, + rotation: bool, + repositioning: bool, + ); + fn set_hierarchical_clustering_init_mode( + self: Pin<&mut Property>, + hierarchical_clustering_init_mode: i16, + ); + fn set_number_of_first_objects(self: Pin<&mut Property>, number_of_first_objects: usize); + fn set_number_of_first_clusters(self: Pin<&mut Property>, number_of_first_clusters: usize); + fn set_number_of_second_objects(self: Pin<&mut Property>, number_of_second_objects: u32); + fn set_number_of_second_clusters( + self: Pin<&mut Property>, + number_of_second_clusters: usize, + ); + fn set_number_of_third_clusters(self: Pin<&mut Property>, number_of_third_clusters: usize); + fn set_number_of_objects(self: Pin<&mut Property>, number_of_objects: usize); + fn set_number_of_subvectors_for_bp(self: Pin<&mut Property>, number_of_subvectors: usize); + fn set_optimization_clustering_init_mode( + self: Pin<&mut Property>, + optimization_clustering_init_mode: i32, + ); + fn set_rotation_iteration(self: Pin<&mut Property>, rotation_iteration: usize); + fn set_subvector_iteration(self: Pin<&mut Property>, subvector_iteration: usize); + fn set_number_of_matrices(self: Pin<&mut Property>, number_of_matrices: usize); + fn set_rotation(self: Pin<&mut Property>, rotation: bool); + fn set_repositioning(self: Pin<&mut Property>, repositioning: bool); + + type Index; + fn new_index(path: &String, p: Pin<&mut Property>) -> Result>; + fn new_prebuilt_index(path: &String, p: bool) -> Result>; + fn open_index(self: Pin<&mut Index>, path: &String, prebuilt: bool); + fn build_index(self: Pin<&mut Index>, path: &String, p: Pin<&mut Property>); + fn save_index(self: Pin<&mut Index>); + fn close_index(self: Pin<&mut Index>); + fn append(self: Pin<&mut Index>, v: &[f32]) -> Result; + unsafe fn search(self: Pin<&mut Index>, v: &[f32], ids: *mut i32, distances: *mut f32); + } +} + +#[cfg(test)] +mod tests { + use std::vec; + + use anyhow::Result; + + use crate::ffi; + + #[test] + fn test_qbg() -> Result<()> { + let dimension = 128; + let path = "index".to_string(); + + let mut p = ffi::new_property(); + //// Test Setter //// + p.pin_mut().set_extended_dimension(1); + p.pin_mut().set_dimension(1); + p.pin_mut().set_number_of_subvectors(1); + p.pin_mut().set_number_of_blobs(1); + p.pin_mut().set_internal_data_type(1); + p.pin_mut().set_data_type(1); + p.pin_mut().set_distance_type(1); + p.pin_mut().set_hierarchical_clustering_init_mode(1); + p.pin_mut().set_number_of_first_objects(1); + p.pin_mut().set_number_of_first_clusters(1); + p.pin_mut().set_number_of_second_objects(1); + p.pin_mut().set_number_of_second_clusters(1); + p.pin_mut().set_number_of_third_clusters(1); + p.pin_mut().set_number_of_objects(1); + p.pin_mut().set_number_of_subvectors_for_bp(1); + p.pin_mut().set_optimization_clustering_init_mode(1); + p.pin_mut().set_rotation_iteration(1); + p.pin_mut().set_subvector_iteration(1); + p.pin_mut().set_number_of_matrices(1); + p.pin_mut().set_rotation(false); + p.pin_mut().set_repositioning(false); + ///////////////////// + p.pin_mut().init_qbg_construction_parameters(); + p.pin_mut().set_dimension(dimension); + p.pin_mut().set_number_of_subvectors(64); + p.pin_mut().set_number_of_blobs(0); + p.pin_mut().init_qbg_build_parameters(); + p.pin_mut().set_number_of_objects(500); + + // New + println!("create an empty index..."); + let mut index = match ffi::new_index(&path, p.pin_mut()) { + Ok(index) => index, + Err(e) => panic!("{}", e), + }; + + // Append & Build + println!("append objects..."); + for i in 0..100 { + let mut vec: Vec = vec![0.0; dimension]; + for d in 0..dimension { + vec[d] = (i + d) as f32 + } + + let result = index.pin_mut().append(vec.as_slice()); + match result { + Ok(v) => assert_eq!((i + 1) as i32, v), + Err(e) => panic!("{}", e), + } + } + index.pin_mut().save_index(); + index.pin_mut().close_index(); + println!("building the index..."); + index.pin_mut().build_index(&path, p.pin_mut()); + index.pin_mut().open_index(&path, true); + + // Search + let mut ids: Vec = vec![0; dimension]; + let mut distances: Vec = vec![0.0; dimension]; + let mut vec = vec![0.0; dimension]; + for i in 0..dimension { + vec[i] = i as f32 + } + unsafe { + index.pin_mut().search( + vec.as_slice(), + &mut ids[0] as *mut i32, + &mut distances[0] as *mut f32, + ) + }; + println!("{:?}", ids); + println!("{:?}", distances); + index.pin_mut().close_index(); + + return Ok(()); + } + + #[test] + fn test_qbg_reopen() -> Result<()> { + let dimension = 128; + let path = "index".to_string(); + + // New + let mut index = match ffi::new_prebuilt_index(&path, true) { + Ok(index) => index, + Err(e) => panic!("{}", e), + }; + + // Search + let mut ids: Vec = vec![0; dimension]; + let mut distances: Vec = vec![0.0; dimension]; + let mut vec = vec![0.0; dimension]; + for i in 0..dimension { + vec[i] = i as f32 + } + unsafe { + index.pin_mut().search( + vec.as_slice(), + &mut ids[0] as *mut i32, + &mut distances[0] as *mut f32, + ) + }; + println!("{:?}", ids); + println!("{:?}", distances); + index.pin_mut().close_index(); + + return Ok(()); + } +}