diff --git a/conda/recipes/cuvs_bench/meta.yaml b/conda/recipes/cuvs_bench/meta.yaml index c39658222..9ecbf82bb 100644 --- a/conda/recipes/cuvs_bench/meta.yaml +++ b/conda/recipes/cuvs_bench/meta.yaml @@ -74,6 +74,7 @@ requirements: - glog {{ glog_version }} - libcuvs {{ version }} - nlohmann_json {{ nlohmann_json_version }} + - openblas # rmm is needed to determine if package is gpu-enabled - python - rapids-build-backend>=0.3.0,<0.4.0.dev0 diff --git a/conda/recipes/cuvs_bench_cpu/meta.yaml b/conda/recipes/cuvs_bench_cpu/meta.yaml index e69c8416b..0ce5db744 100644 --- a/conda/recipes/cuvs_bench_cpu/meta.yaml +++ b/conda/recipes/cuvs_bench_cpu/meta.yaml @@ -48,6 +48,7 @@ requirements: - fmt {{ fmt_version }} - glog {{ glog_version }} - nlohmann_json {{ nlohmann_json_version }} + - openblas - python - rapids-build-backend>=0.3.0,<0.4.0.dev0 - spdlog {{ spdlog_version }} diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 61ae63e9f..17d729c35 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -428,6 +428,12 @@ if(BUILD_SHARED_LIBS) src/neighbors/refine/detail/refine_host_int8_t_float.cpp src/neighbors/refine/detail/refine_host_uint8_t_float.cpp src/neighbors/sample_filter.cu + src/neighbors/vamana_build_float.cu + src/neighbors/vamana_build_uint8.cu + src/neighbors/vamana_build_int8.cu + src/neighbors/vamana_serialize_float.cu + src/neighbors/vamana_serialize_uint8.cu + src/neighbors/vamana_serialize_int8.cu src/selection/select_k_float_int64_t.cu src/selection/select_k_float_int32_t.cu src/selection/select_k_float_uint32_t.cu diff --git a/cpp/include/cuvs/neighbors/vamana.hpp b/cpp/include/cuvs/neighbors/vamana.hpp new file mode 100644 index 000000000..bec17937f --- /dev/null +++ b/cpp/include/cuvs/neighbors/vamana.hpp @@ -0,0 +1,275 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "common.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace cuvs::neighbors::experimental::vamana { +/** + * @defgroup vamana_cpp_index_params Vamana index build parameters + * @{ + */ + +/** + * @brief ANN parameters used by VAMANA to build index + * + */ +struct index_params : cuvs::neighbors::index_params { + /** Maximum degree of output graph corresponds to the R parameter in the original Vamana + * literature. */ + uint32_t graph_degree = 32; + /** Maximum number of visited nodes per search corresponds to the L parameter in the Vamana + * literature **/ + uint32_t visited_size = 64; + /** Number of Vamana vector insertion iterations (each iteration inserts all vectors). */ + uint32_t vamana_iters = 1; + /** Alpha for pruning parameter */ + float alpha = 1.2; + /** Maximum fraction of dataset inserted per batch. * + * Larger max batch decreases graph quality, but improves speed */ + float max_fraction = 0.06; + /** Base of growth rate of batch sies **/ + float batch_base = 2; + /** Size of candidate queue structure - should be (2^x)-1 */ + uint32_t queue_size = 127; +}; + +/** + * @} + */ + +static_assert(std::is_aggregate_v); + +/** + * @defgroup vamana_cpp_index Vamana index type + * @{ + */ + +/** + * @brief Vamana index. + * + * The index stores the dataset and the Vamana graph in device memory. + * + * @tparam T data element type + * @tparam IdxT type of the vector indices (represent dataset.extent(0)) + * + */ +template +struct index : cuvs::neighbors::index { + static_assert(!raft::is_narrowing_v, + "IdxT must be able to represent all values of uint32_t"); + + public: + /** Distance metric used for clustering. */ + [[nodiscard]] constexpr inline auto metric() const noexcept -> cuvs::distance::DistanceType + { + return metric_; + } + + /** Total length of the index (number of vectors). */ + [[nodiscard]] constexpr inline auto size() const noexcept -> IdxT + { + auto data_rows = dataset_->n_rows(); + return data_rows > 0 ? data_rows : graph_view_.extent(0); + } + + /** Dimensionality of the data. */ + [[nodiscard]] constexpr inline auto dim() const noexcept -> uint32_t { return dataset_->dim(); } + /** Graph degree */ + [[nodiscard]] constexpr inline auto graph_degree() const noexcept -> uint32_t + { + return graph_view_.extent(1); + } + + /** Dataset [size, dim] */ + [[nodiscard]] inline auto data() const noexcept -> const cuvs::neighbors::dataset& + { + return *dataset_; + } + + /** vamana graph [size, graph-degree] */ + [[nodiscard]] inline auto graph() const noexcept + -> raft::device_matrix_view + { + return graph_view_; + } + + /** Return the id of the vector selected as the medoid. */ + [[nodiscard]] inline auto medoid() const noexcept -> IdxT { return medoid_id_; } + + // Don't allow copying the index for performance reasons (try avoiding copying data) + index(const index&) = delete; + index(index&&) = default; + auto operator=(const index&) -> index& = delete; + auto operator=(index&&) -> index& = default; + ~index() = default; + + /** Construct an empty index. */ + index(raft::resources const& res, + cuvs::distance::DistanceType metric = cuvs::distance::DistanceType::L2Expanded) + : cuvs::neighbors::index(), + metric_(metric), + graph_(raft::make_device_matrix(res, 0, 0)), + dataset_(new cuvs::neighbors::empty_dataset(0)) + { + } + + /** Construct an index from dataset and vamana graph + * + */ + template + index(raft::resources const& res, + cuvs::distance::DistanceType metric, + raft::mdspan, raft::row_major, data_accessor> dataset, + raft::mdspan, raft::row_major, graph_accessor> + vamana_graph, + IdxT medoid_id) + : cuvs::neighbors::index(), + metric_(metric), + graph_(raft::make_device_matrix(res, 0, 0)), + dataset_(make_aligned_dataset(res, dataset, 16)), + medoid_id_(medoid_id) + { + RAFT_EXPECTS(dataset.extent(0) == vamana_graph.extent(0), + "Dataset and vamana_graph must have equal number of rows"); + update_graph(res, vamana_graph); + + raft::resource::sync_stream(res); + } + + /** + * Replace the graph with a new graph. + * + * Since the new graph is a device array, we store a reference to that, and it is + * the caller's responsibility to ensure that knn_graph stays alive as long as the index. + */ + void update_graph(raft::resources const& res, + raft::device_matrix_view new_graph) + { + graph_view_ = new_graph; + } + + /** + * Replace the graph with a new graph. + * + * We create a copy of the graph on the device. The index manages the lifetime of this copy. + */ + void update_graph(raft::resources const& res, + raft::host_matrix_view new_graph) + { + RAFT_LOG_DEBUG("Copying Vamana graph from host to device"); + + if ((graph_.extent(0) != new_graph.extent(0)) || (graph_.extent(1) != new_graph.extent(1))) { + // clear existing memory before allocating to prevent OOM errors on large graphs + if (graph_.size()) { graph_ = raft::make_device_matrix(res, 0, 0); } + graph_ = + raft::make_device_matrix(res, new_graph.extent(0), new_graph.extent(1)); + } + raft::copy(graph_.data_handle(), + new_graph.data_handle(), + new_graph.size(), + raft::resource::get_cuda_stream(res)); + graph_view_ = graph_.view(); + } + + private: + cuvs::distance::DistanceType metric_; + raft::device_matrix graph_; + raft::device_matrix_view graph_view_; + std::unique_ptr> dataset_; + IdxT medoid_id_; +}; +/** + * @} + */ + +/** + * @defgroup vamana_cpp_index_build Vamana index build functions + * @{ + */ +/** + * @brief Build the index from the dataset for efficient search. + * + */ +auto build(raft::resources const& handle, + const cuvs::neighbors::experimental::vamana::index_params& params, + raft::device_matrix_view dataset) + -> cuvs::neighbors::experimental::vamana::index; + +auto build(raft::resources const& handle, + const cuvs::neighbors::experimental::vamana::index_params& params, + raft::host_matrix_view dataset) + -> cuvs::neighbors::experimental::vamana::index; + +auto build(raft::resources const& handle, + const cuvs::neighbors::experimental::vamana::index_params& params, + raft::device_matrix_view dataset) + -> cuvs::neighbors::experimental::vamana::index; + +auto build(raft::resources const& handle, + const cuvs::neighbors::experimental::vamana::index_params& params, + raft::host_matrix_view dataset) + -> cuvs::neighbors::experimental::vamana::index; + +auto build(raft::resources const& handle, + const cuvs::neighbors::experimental::vamana::index_params& params, + raft::device_matrix_view dataset) + -> cuvs::neighbors::experimental::vamana::index; + +auto build(raft::resources const& handle, + const cuvs::neighbors::experimental::vamana::index_params& params, + raft::host_matrix_view dataset) + -> cuvs::neighbors::experimental::vamana::index; + +/** + * @defgroup vamana_cpp_serialize Vamana serialize functions + * @{ + */ +/** + * Save the index to file. + */ + +void serialize(raft::resources const& handle, + const std::string& file_prefix, + const cuvs::neighbors::experimental::vamana::index& index); + +void serialize(raft::resources const& handle, + const std::string& file_prefix, + const cuvs::neighbors::experimental::vamana::index& index); + +void serialize(raft::resources const& handle, + const std::string& file_prefix, + const cuvs::neighbors::experimental::vamana::index& index); + +/** + * @} + */ + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/src/neighbors/detail/cagra/graph_core.cuh b/cpp/src/neighbors/detail/cagra/graph_core.cuh index 9edbbf5c1..43bf1ba2b 100644 --- a/cpp/src/neighbors/detail/cagra/graph_core.cuh +++ b/cpp/src/neighbors/detail/cagra/graph_core.cuh @@ -475,12 +475,12 @@ void sort_knn_graph( { RAFT_EXPECTS(dataset.extent(0) == knn_graph.extent(0), "dataset size is expected to have the same number of graph index size"); - const uint32_t dataset_size = dataset.extent(0); - const uint32_t dataset_dim = dataset.extent(1); + const uint64_t dataset_size = dataset.extent(0); + const uint64_t dataset_dim = dataset.extent(1); const DataT* dataset_ptr = dataset.data_handle(); const IdxT graph_size = dataset_size; - const uint32_t input_graph_degree = knn_graph.extent(1); + const uint64_t input_graph_degree = knn_graph.extent(1); IdxT* const input_graph_ptr = knn_graph.data_handle(); auto large_tmp_mr = raft::resource::get_large_workspace_resource(res); @@ -528,7 +528,7 @@ void sort_knn_graph( kernel_sort = kern_sort; } else { RAFT_FAIL( - "The degree of input knn graph is too large (%u). " + "The degree of input knn graph is too large (%lu). " "It must be equal to or smaller than %d.", input_graph_degree, 1024); diff --git a/cpp/src/neighbors/detail/vamana/greedy_search.cuh b/cpp/src/neighbors/detail/vamana/greedy_search.cuh new file mode 100644 index 000000000..f51c6c91b --- /dev/null +++ b/cpp/src/neighbors/detail/vamana/greedy_search.cuh @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "macros.cuh" +#include "priority_queue.cuh" +#include "vamana_structs.cuh" +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace cuvs::neighbors::experimental::vamana::detail { + +/* @defgroup greedy_search_detail greedy search + * @{ + */ + +/* Combines edge and candidate lists, removes duplicates, and sorts by distance + * Uses CUB primitives, so needs to be templated. Called with Macros for supported sizes above */ +template +__forceinline__ __device__ void sort_visited( + QueryCandidates* query, + typename cub::BlockMergeSort, 32, (CANDS / 32)>::TempStorage* sort_mem) +{ + const int ELTS = CANDS / 32; + using BlockSortT = cub::BlockMergeSort, 32, ELTS>; + DistPair tmp[ELTS]; + for (int i = 0; i < ELTS; i++) { + tmp[i].idx = query->ids[ELTS * threadIdx.x + i]; + tmp[i].dist = query->dists[ELTS * threadIdx.x + i]; + } + + __syncthreads(); + BlockSortT(*sort_mem).Sort(tmp, CmpDist()); + __syncthreads(); + + for (int i = 0; i < ELTS; i++) { + query->ids[ELTS * threadIdx.x + i] = tmp[i].idx; + query->dists[ELTS * threadIdx.x + i] = tmp[i].dist; + } + __syncthreads(); +} + +namespace { + +/******************************************************************************************** + GPU kernel to perform a batched GreedySearch on a graph. Since this is used for + Vamana construction, the entire visited list is kept and stored within the query_list. + Input - graph with edge lists, dataset vectors, query_list_ptr with the ids of dataset + vectors to be searched. All inputs, including dataset, must be device accessible. + + Output - the id and dist lists in query_list_ptr will be updated with the nodes visited + during the GreedySearch. +**********************************************************************************************/ +template , + raft::memory_type::host>> +__global__ void GreedySearchKernel( + raft::device_matrix_view graph, + raft::mdspan, raft::row_major, Accessor> dataset, + void* query_list_ptr, + int num_queries, + int medoid_id, + int topk, + cuvs::distance::DistanceType metric, + int max_queue_size, + int sort_smem_size) +{ + int n = dataset.extent(0); + int dim = dataset.extent(1); + int degree = graph.extent(1); + + QueryCandidates* query_list = + static_cast*>(query_list_ptr); + + static __shared__ int topk_q_size; + static __shared__ int cand_q_size; + static __shared__ accT cur_k_max; + static __shared__ int k_max_idx; + + static __shared__ Point s_query; + + union ShmemLayout { + // All blocksort sizes have same alignment (16) + typename cub::BlockMergeSort, 32, 1>::TempStorage sort_mem; + T coords; + Node topk_pq; + int neighborhood_arr; + DistPair candidate_queue; + }; + + // Dynamic shared memory used for blocksort, temp vector storage, and neighborhood list + extern __shared__ __align__(alignof(ShmemLayout)) char smem[]; + + size_t smem_offset = sort_smem_size; // temp sorting memory takes first chunk + + T* s_coords = reinterpret_cast(&smem[smem_offset]); + smem_offset += dim * sizeof(T); + + Node* topk_pq = reinterpret_cast*>(&smem[smem_offset]); + smem_offset += topk * sizeof(Node); + + int* neighbor_array = reinterpret_cast(&smem[smem_offset]); + smem_offset += degree * sizeof(int); + + DistPair* candidate_queue_smem = + reinterpret_cast*>(&smem[smem_offset]); + + s_query.coords = s_coords; + s_query.Dim = dim; + + PriorityQueue heap_queue; + + if (threadIdx.x == 0) { + heap_queue.initialize(candidate_queue_smem, max_queue_size, &cand_q_size); + } + + static __shared__ int num_neighbors; + + for (int i = blockIdx.x; i < num_queries; i += gridDim.x) { + __syncthreads(); + + // resetting visited list + query_list[i].reset(); + + // storing the current query vector into shared memory + update_shared_point(&s_query, &dataset(0, 0), query_list[i].queryId, dim); + + if (threadIdx.x == 0) { + topk_q_size = 0; + cand_q_size = 0; + s_query.id = query_list[i].queryId; + cur_k_max = 0; + k_max_idx = 0; + heap_queue.reset(); + } + + __syncthreads(); + + Point* query_vec; + + // Just start from medoid every time, rather than multiple set_ups + query_vec = &s_query; + query_vec->Dim = dim; + const T* medoid = &dataset((size_t)medoid_id, 0); + accT medoid_dist = dist(query_vec->coords, medoid, dim, metric); + + if (threadIdx.x == 0) { heap_queue.insert_back(medoid_dist, medoid_id); } + __syncthreads(); + + while (cand_q_size != 0) { + __syncthreads(); + + int cand_num; + accT cur_distance; + if (threadIdx.x == 0) { + Node test_cand; + DistPair test_cand_out = heap_queue.pop(); + test_cand.distance = test_cand_out.dist; + test_cand.nodeid = test_cand_out.idx; + cand_num = test_cand.nodeid; + cur_distance = test_cand_out.dist; + } + __syncthreads(); + + cand_num = raft::shfl(cand_num, 0); + + __syncthreads(); + + if (query_list[i].check_visited(cand_num, cur_distance)) { continue; } + + cur_distance = raft::shfl(cur_distance, 0); + + // stop condition for the graph traversal process + bool done = false; + bool pass_flag = false; + + if (topk_q_size == topk) { + // Check the current node with the worst candidate in top-k queue + if (threadIdx.x == 0) { + if (cur_k_max <= cur_distance) { done = true; } + } + + done = raft::shfl(done, 0); + if (done) { + if (query_list[i].size < topk) { + pass_flag = true; + } + + else if (query_list[i].size >= topk) { + break; + } + } + } + + // The current node is closer to the query vector than the worst candidate in top-K queue, so + // enquee the current node in top-k queue + Node new_cand; + new_cand.distance = cur_distance; + new_cand.nodeid = cand_num; + + if (check_duplicate(topk_pq, topk_q_size, new_cand) == false) { + if (!pass_flag) { + parallel_pq_max_enqueue( + topk_pq, &topk_q_size, topk, new_cand, &cur_k_max, &k_max_idx); + + __syncthreads(); + } + } else { + // already visited + continue; + } + + num_neighbors = degree; + __syncthreads(); + + for (size_t j = threadIdx.x; j < degree; j += blockDim.x) { + // Load neighbors from the graph array and store them in neighbor array (shared memory) + neighbor_array[j] = graph(cand_num, j); + if (neighbor_array[j] == raft::upper_bound()) + atomicMin(&num_neighbors, (int)j); // warp-wide min to find the number of neighbors + } + + // computing distances between the query vector and neighbor vectors then enqueue in priority + // queue. + enqueue_all_neighbors( + num_neighbors, query_vec, &dataset(0, 0), neighbor_array, heap_queue, dim, metric); + + __syncthreads(); + + } // End cand_q_size != 0 loop + + bool self_found = false; + // Remove self edges + for (int j = threadIdx.x; j < query_list[i].size; j += blockDim.x) { + if (query_list[i].ids[j] == query_vec->id) { + query_list[i].dists[j] = raft::upper_bound(); + query_list[i].ids[j] = raft::upper_bound(); + self_found = true; // Flag to reduce size by 1 + } + } + + for (int j = query_list[i].size + threadIdx.x; j < query_list[i].maxSize; j += blockDim.x) { + query_list[i].ids[j] = raft::upper_bound(); + query_list[i].dists[j] = raft::upper_bound(); + } + + __syncthreads(); + if (self_found) query_list[i].size--; + + SEARCH_SELECT_SORT(topk); + } + + return; +} + +} // namespace + +/** + * @} + */ + +} // namespace cuvs::neighbors::experimental::vamana::detail diff --git a/cpp/src/neighbors/detail/vamana/macros.cuh b/cpp/src/neighbors/detail/vamana/macros.cuh new file mode 100644 index 000000000..5692650a0 --- /dev/null +++ b/cpp/src/neighbors/detail/vamana/macros.cuh @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 + +namespace cuvs::neighbors::experimental::vamana::detail { + +/* Macros to compute the shared memory requirements for CUB primitives used by search and prune */ +#define COMPUTE_SMEM_SIZES(degree, visited_size, DEG, CANDS) \ + if (degree == DEG && visited_size <= CANDS && visited_size > CANDS / 2) { \ + search_smem_sort_size = static_cast( \ + sizeof(typename cub::BlockMergeSort, 32, CANDS / 32>::TempStorage)); \ + \ + prune_smem_sort_size = static_cast(sizeof( \ + typename cub::BlockMergeSort, 32, (CANDS + DEG) / 32>::TempStorage)); \ + } + +// Current supported sizes for degree and visited_size. Note that visited_size must be > degree +#define SELECT_SMEM_SIZES(degree, visited_size) \ + COMPUTE_SMEM_SIZES(degree, visited_size, 32, 64); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 32, 128); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 32, 256); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 32, 512); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 64, 128); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 64, 256); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 64, 512); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 128, 256); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 128, 512); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 256, 512); \ + COMPUTE_SMEM_SIZES(degree, visited_size, 256, 1024); + +/* Macros to call the CUB BlockSort primitives for supported sizes for ROBUST_PRUNE*/ +#define PRUNE_CALL_SORT(degree, visited_list, DEG, CANDS) \ + if (degree == DEG && visited_list <= CANDS && visited_list > CANDS / 2) { \ + using BlockSortT = cub::BlockMergeSort, 32, (DEG + CANDS) / 32>; \ + auto& sort_mem = reinterpret_cast(smem); \ + sort_edges_and_cands(new_nbh_list, &query_list[i], &sort_mem); \ + } + +#define PRUNE_SELECT_SORT(degree, visited_list) \ + PRUNE_CALL_SORT(degree, visited_size, 32, 64); \ + PRUNE_CALL_SORT(degree, visited_size, 32, 128); \ + PRUNE_CALL_SORT(degree, visited_size, 32, 256); \ + PRUNE_CALL_SORT(degree, visited_size, 32, 512); \ + PRUNE_CALL_SORT(degree, visited_size, 64, 128); \ + PRUNE_CALL_SORT(degree, visited_size, 64, 256); \ + PRUNE_CALL_SORT(degree, visited_size, 64, 512); \ + PRUNE_CALL_SORT(degree, visited_size, 128, 256); \ + PRUNE_CALL_SORT(degree, visited_size, 128, 512); \ + PRUNE_CALL_SORT(degree, visited_size, 256, 512); \ + PRUNE_CALL_SORT(degree, visited_size, 256, 1024); + +/* Macros to call the CUB BlockSort primitives for supported sizes for GREEDY SEARCH */ +#define SEARCH_CALL_SORT(topk, CANDS) \ + if (topk <= CANDS && topk > CANDS / 2) { \ + using BlockSortT = cub::BlockMergeSort, 32, CANDS / 32>; \ + auto& sort_mem = reinterpret_cast(smem); \ + sort_visited(&query_list[i], &sort_mem); \ + } + +// SEARCH only relies on visited_size (not degree) for shared memory. +#define SEARCH_SELECT_SORT(topk) \ + SEARCH_CALL_SORT(topk, 64); \ + SEARCH_CALL_SORT(topk, 128); \ + SEARCH_CALL_SORT(topk, 256); \ + SEARCH_CALL_SORT(topk, 512); \ + SEARCH_CALL_SORT(topk, 1024); + +} // namespace cuvs::neighbors::experimental::vamana::detail diff --git a/cpp/src/neighbors/detail/vamana/priority_queue.cuh b/cpp/src/neighbors/detail/vamana/priority_queue.cuh new file mode 100644 index 000000000..4b3bd8466 --- /dev/null +++ b/cpp/src/neighbors/detail/vamana/priority_queue.cuh @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "vamana_structs.cuh" +#include +#include + +namespace cuvs::neighbors::experimental::vamana::detail { + +/*************************************************************************************** +***************************************************************************************/ +/** + * @defgroup vamana_priority_queue Vamana Priority queue structure + * @{ + */ + +/** + * @brief Priority Queue structure used by Vamana GreedySearch during + * graph construction. + * + * The structure keeps the nearest visited neighbors seen thus far during + * search and lets us efficiently find the next node to visit during the search. + * Stores a total of KVAL pairs, where currently KVAL must be 2i-1 for some integer + * i since the heap must be complete. + * This size is determined during vamana build with the "queue_size" parameter (default 127) + * + * The queue and all methods are device-side, with a work group size or 32 (one warp). + * During search, each warp creates their own queue to search a single query at a time. + * The device memory pointed to by `vals` is assigned during the call to `initialize`. + * The Vamana GreedySearch call uses shared memory, but any device-accessible memory is applicable. + * + * + * @tparam IdxT type of the vector indices (represent dataset.extent(0)) + * @tparam accT type of distances between vectors (accumuator type) + * + */ +template +class PriorityQueue { + public: + int KVAL; + int insert_pointer; + DistPair* vals; + DistPair temp; + + int* q_size; + // Enforce max-heap property on the entries + __forceinline__ __device__ void heapify() + { + int i = 0; + int swapDest = 0; + + while (2 * i + 2 < KVAL) { + swapDest = 2 * i; + swapDest += + (vals[i].dist > vals[2 * i + 1].dist && vals[2 * i + 2].dist >= vals[2 * i + 1].dist); + swapDest += + 2 * (vals[i].dist > vals[2 * i + 2].dist && vals[2 * i + 1].dist > vals[2 * i + 2].dist); + + if (swapDest == 2 * i) return; + + swap(&vals[i], &vals[swapDest]); + + i = swapDest; + } + } + + // Starts the heapify process starting at a particular index + __forceinline__ __device__ void heapifyAt(int idx) + { + int i = idx; + int swapDest = 0; + + while (2 * i + 2 < KVAL) { + swapDest = 2 * i; + swapDest += + (vals[i].dist > vals[2 * i + 1].dist && vals[2 * i + 2].dist <= vals[2 * i + 1].dist); + swapDest += + 2 * (vals[i].dist > vals[2 * i + 2].dist && vals[2 * i + 1].dist < vals[2 * i + 2].dist); + + if (swapDest == 2 * i) return; + + swap(&vals[i], &vals[swapDest]); + i = swapDest; + } + } + + // Heapify from the bottom up, used with insert_back + __forceinline__ __device__ void heapifyReverseAt(int idx) + { + int i = idx; + int swapDest = 0; + while (i > 0) { + swapDest = ((i - 1) / 2); + if (vals[swapDest].dist <= vals[i].dist) return; + + swap(&vals[i], &vals[swapDest]); + i = swapDest; + } + } + + __device__ void reset() + { + *q_size = 0; + for (int i = 0; i < KVAL; i++) { + vals[i].dist = raft::upper_bound(); + vals[i].idx = raft::upper_bound(); + } + } + + __device__ void initialize(DistPair* v, int _kval, int* _q_size) + { + vals = v; + KVAL = _kval; + insert_pointer = _kval / 2; + q_size = _q_size; + reset(); + } + + // Initialize all nodes of the heap to +infinity + __device__ void initialize() + { + for (int i = 0; i < KVAL; i++) { + vals[i].idx = raft::upper_bound(); + vals[i].dist = raft::upper_bound(); + } + } + + __device__ void write_to_gmem(int* gmem) + { + for (int i = 0; i < KVAL; i++) { + gmem[i] = vals[i].idx; + } + } + + // Replace the root of the heap with new pair + __device__ void insert(accT newDist, IdxT newIdx) + { + vals[0].dist = newDist; + vals[0].idx = newIdx; + + heapify(); + } + + // Replace a specific element in the heap (and maintain heap properties) + __device__ void insertAt(accT newDist, IdxT newIdx, int idx) + { + vals[idx].dist = newDist; + vals[idx].idx = newIdx; + + heapifyAt(idx); + } + + // Return value of the root of the heap (largest value) + __device__ accT top() { return vals[0].dist; } + + __device__ IdxT top_node() { return vals[0].idx; } + + __device__ void insert_back(accT newDist, IdxT newIdx) + { + if (newDist < vals[insert_pointer].dist) { + if (vals[insert_pointer].idx == raft::upper_bound()) *q_size += 1; + vals[insert_pointer].dist = newDist; + vals[insert_pointer].idx = newIdx; + heapifyReverseAt(insert_pointer); + } + insert_pointer++; + + if (insert_pointer == KVAL) insert_pointer = KVAL / 2; + } + + // Pop root node off and heapify + __device__ DistPair pop() + { + DistPair result; + result.dist = vals[0].dist; + result.idx = vals[0].idx; + vals[0].dist = raft::upper_bound(); + vals[0].idx = raft::upper_bound(); + heapify(); + *q_size -= 1; + return result; + } +}; + +/*************************************************************************************** + * Node structure used for simplified lists during GreedySearch. + * Used for other operations like checking for duplicates, etc. + ****************************************************************************************/ +template +class __align__(16) Node +{ + public: + SUMTYPE distance; + int nodeid; +}; + +// Less-than operator between two Nodes. +template +__host__ __device__ bool operator<(const Node& first, const Node& other) +{ + return first.distance < other.distance; +} + +// Less-than operator between two Nodes. +template +__host__ __device__ bool operator>(const Node& first, const Node& other) +{ + return first.distance > other.distance; +} + +template +__device__ bool check_duplicate(const Node* pq, const int size, Node new_node) +{ + bool found = false; + for (int i = threadIdx.x; i < size; i += blockDim.x) { + if (pq[i].nodeid == new_node.nodeid) { + found = true; + break; + } + } + + unsigned mask = raft::ballot(found); + + if (mask == 0) + return false; + + else + return true; +} + +/* + Enqueuing a input value into parallel queue with tracker +*/ +template +__inline__ __device__ void parallel_pq_max_enqueue(Node* pq, + int* size, + const int pq_size, + Node input_data, + SUMTYPE* cur_max_val, + int* max_idx) +{ + if (*size < pq_size) { + __syncthreads(); + if (threadIdx.x == 0) { + pq[*size].distance = input_data.distance; + pq[*size].nodeid = input_data.nodeid; + *size = *size + 1; + if (input_data.distance > (*cur_max_val)) { + *cur_max_val = input_data.distance; + *max_idx = *size - 1; + } + } + __syncthreads(); + return; + } else { + if (input_data.distance >= (*cur_max_val)) { + __syncthreads(); + return; + } + if (threadIdx.x == 0) { + pq[*max_idx].distance = input_data.distance; + pq[*max_idx].nodeid = input_data.nodeid; + } + int idx = 0; + SUMTYPE max_val = pq[0].distance; + + for (int i = threadIdx.x; i < pq_size; i += 32) { + if (pq[i].distance > max_val) { + max_val = pq[i].distance; + idx = i; + } + } + + for (int offset = 16; offset > 0; offset /= 2) { + SUMTYPE new_max_val = raft::shfl_up(max_val, offset); + int new_idx = raft::shfl_up(idx, offset); + if (new_max_val > max_val) { + max_val = new_max_val; + idx = new_idx; + } + } + + if (threadIdx.x == 31) { + *max_idx = idx; + *cur_max_val = max_val; + } + } + __syncthreads(); +} + +/* + Compute the distances between the source vector and all nodes in the neighbor_array and enqueue + them in the PQ +*/ +template +__forceinline__ __device__ void enqueue_all_neighbors(int num_neighbors, + Point* query_vec, + const T* vec_ptr, + int* neighbor_array, + PriorityQueue& heap_queue, + int dim, + cuvs::distance::DistanceType metric) +{ + for (int i = 0; i < num_neighbors; i++) { + accT dist_out = dist( + query_vec->coords, &vec_ptr[(size_t)(neighbor_array[i]) * (size_t)(dim)], dim, metric); + + __syncthreads(); + if (threadIdx.x == 0) { heap_queue.insert_back(dist_out, neighbor_array[i]); } + __syncthreads(); + } +} + +} // namespace cuvs::neighbors::experimental::vamana::detail diff --git a/cpp/src/neighbors/detail/vamana/robust_prune.cuh b/cpp/src/neighbors/detail/vamana/robust_prune.cuh new file mode 100644 index 000000000..8446ac136 --- /dev/null +++ b/cpp/src/neighbors/detail/vamana/robust_prune.cuh @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 + +#include "macros.cuh" +#include "vamana_structs.cuh" + +namespace cuvs::neighbors::experimental::vamana::detail { + +// Load candidates (from query) and previous edges (from nbh_list) into registers (tmp) spanning +// warp +template +__forceinline__ __device__ void load_to_registers(DistPair* tmp, + QueryCandidates* query, + DistPair* nbh_list) +{ + int cands_per_thread = CANDS / 32; + for (int i = 0; i < cands_per_thread; i++) { + tmp[i].idx = query->ids[cands_per_thread * threadIdx.x + i]; + tmp[i].dist = query->dists[cands_per_thread * threadIdx.x + i]; + + if (cands_per_thread * threadIdx.x + i >= query->size) { + tmp[i].idx = raft::upper_bound(); + tmp[i].dist = raft::upper_bound(); + } + } + int nbh_per_thread = DEG / 32; + for (int i = 0; i < nbh_per_thread; i++) { + tmp[cands_per_thread + i] = nbh_list[nbh_per_thread * threadIdx.x + i]; + } +} + +/* Combines edge and candidate lists, removes duplicates, and sorts by distance + * Uses CUB primitives, so needs to be templated. Called with Macros for supported sizes above */ +template +__forceinline__ __device__ void sort_edges_and_cands( + DistPair* new_nbh_list, + QueryCandidates* query, + typename cub::BlockMergeSort, 32, (DEG + CANDS) / 32>::TempStorage* sort_mem) +{ + const int ELTS = (DEG + CANDS) / 32; + using BlockSortT = cub::BlockMergeSort, 32, ELTS>; + DistPair tmp[ELTS]; + + load_to_registers(tmp, query, new_nbh_list); + + __syncthreads(); + BlockSortT(*sort_mem).Sort(tmp, CmpDist()); + __syncthreads(); + + // Mark duplicates and re-sort + // Copy last element over and shuffle to check for duplicate between threads + new_nbh_list[ELTS * threadIdx.x + (ELTS - 1)] = tmp[ELTS - 1]; + if (tmp[ELTS - 1].idx == tmp[ELTS - 2].idx) { + new_nbh_list[ELTS * threadIdx.x + (ELTS - 1)].idx = raft::upper_bound(); + new_nbh_list[ELTS * threadIdx.x + (ELTS - 1)].dist = raft::upper_bound(); + } + __shfl_up_sync(0xffffffff, tmp[ELTS - 1].idx, 1); + __syncthreads(); + + for (int i = ELTS - 2; i > 0; i--) { + if (tmp[i].idx == tmp[i - 1].idx) { + tmp[i].idx = raft::upper_bound(); + tmp[i].dist = raft::upper_bound(); + } + } + if (threadIdx.x == 0) { + if (tmp[0].idx == tmp[ELTS - 1].idx) { + tmp[0].idx = raft::upper_bound(); + tmp[0].dist = raft::upper_bound(); + } + } + + tmp[ELTS - 1].idx = + new_nbh_list[ELTS * threadIdx.x + (ELTS - 1)].idx; // copy back to tmp for re-shuffling + tmp[ELTS - 1].dist = new_nbh_list[ELTS * threadIdx.x + (ELTS - 1)].dist; + + __syncthreads(); + BlockSortT(*sort_mem).Sort(tmp, CmpDist()); + __syncthreads(); + + for (int i = 0; i < ELTS; i++) { + new_nbh_list[ELTS * threadIdx.x + i].idx = tmp[i].idx; + new_nbh_list[ELTS * threadIdx.x + i].dist = tmp[i].dist; + } + __syncthreads(); +} + +namespace { + +/******************************************************************************************** + GPU kernel for RobustPrune operation for Vamana graph creation + Input - *graph to be an edgelist of degree number of edges per vector, + query_list should contain the list of visited nodes during GreedySearch. + All inputs, including dataset, must be device accessible. + + Output - candidate_ptr contains the new set of *degree* new neighbors that each node + should have. +**********************************************************************************************/ +template , + raft::memory_type::host>> +__global__ void RobustPruneKernel( + raft::device_matrix_view graph, + raft::mdspan, raft::row_major, Accessor> dataset, + void* query_list_ptr, + int num_queries, + int visited_size, + cuvs::distance::DistanceType metric, + float alpha, + int sort_smem_size) +{ + int n = dataset.extent(0); + int dim = dataset.extent(1); + int degree = graph.extent(1); + QueryCandidates* query_list = + static_cast*>(query_list_ptr); + + union ShmemLayout { + // All blocksort sizes have same alignment (16) + typename cub::BlockMergeSort, 32, 3>::TempStorage sort_mem; + T coords; + DistPair nbh_list; + }; + + // Dynamic shared memory used for blocksort, temp vector storage, and neighborhood list + extern __shared__ __align__(alignof(ShmemLayout)) char smem[]; + + T* s_coords = reinterpret_cast(&smem[sort_smem_size]); + DistPair* new_nbh_list = + reinterpret_cast*>(&smem[dim * sizeof(T) + sort_smem_size]); + + static __shared__ Point s_query; + s_query.coords = s_coords; + s_query.Dim = dim; + + for (int i = blockIdx.x; i < num_queries; i += gridDim.x) { + int queryId = query_list[i].queryId; + + update_shared_point(&s_query, &dataset(0, 0), query_list[i].queryId, dim); + + // Load new neighbors to be sorted with candidates + for (int j = threadIdx.x; j < degree; j += blockDim.x) { + new_nbh_list[j].idx = graph(queryId, j); + } + __syncthreads(); + for (int j = 0; j < degree; j++) { + if (new_nbh_list[j].idx != raft::upper_bound()) { + new_nbh_list[j].dist = + dist(s_query.coords, &dataset((size_t)new_nbh_list[j].idx, 0), dim, metric); + } else { + new_nbh_list[j].dist = raft::upper_bound(); + } + } + __syncthreads(); + + // combine and sort candidates and existing edges (and removes duplicates) + // Resulting list is stored in new_nbh_list + PRUNE_SELECT_SORT(degree, visited_size); + + __syncthreads(); + + // If less than degree total neighbors, don't need to prune + if (new_nbh_list[degree].idx == raft::upper_bound()) { + if (threadIdx.x == 0) { + int writeId = 0; + for (; new_nbh_list[writeId].idx != raft::upper_bound(); writeId++) { + query_list[i].ids[writeId] = new_nbh_list[writeId].idx; + query_list[i].dists[writeId] = new_nbh_list[writeId].dist; + } + query_list[i].size = writeId; + for (; writeId < degree; writeId++) { + query_list[i].ids[writeId] = raft::upper_bound(); + query_list[i].dists[writeId] = raft::upper_bound(); + } + } + } else { + // loop through list, writing nearest to visited_list, + // while nulling out violating neighbors in shared memory + if (threadIdx.x == 0) { + query_list[i].ids[0] = new_nbh_list[0].idx; + query_list[i].dists[0] = new_nbh_list[0].dist; + } + + int writeId = 1; + for (int j = 1; j < degree + query_list[i].size && writeId < degree; j++) { + __syncthreads(); + if (new_nbh_list[j].idx == queryId || new_nbh_list[j].idx == raft::upper_bound()) { + continue; + } + __syncthreads(); + if (threadIdx.x == 0) { + query_list[i].ids[writeId] = new_nbh_list[j].idx; + query_list[i].dists[writeId] = new_nbh_list[j].dist; + } + writeId++; + __syncthreads(); + + update_shared_point(&s_query, &dataset(0, 0), new_nbh_list[j].idx, dim); + + int tot_size = degree + query_list[i].size; + for (int k = j + 1; k < tot_size; k++) { + T* mem_ptr = const_cast(&dataset((size_t)new_nbh_list[k].idx, 0)); + if (new_nbh_list[k].idx != raft::upper_bound()) { + accT dist_starprime = dist(s_query.coords, mem_ptr, dim, metric); + // TODO - create cosine and selector fcn + + if (threadIdx.x == 0 && alpha * dist_starprime <= new_nbh_list[k].dist) { + new_nbh_list[k].idx = raft::upper_bound(); + } + } + } + } + __syncthreads(); + if (threadIdx.x == 0) { query_list[i].size = writeId; } + + __syncthreads(); + for (int j = writeId + threadIdx.x; j < degree; + j += blockDim.x) { // Zero out any unfilled neighbors + query_list[i].ids[j] = raft::upper_bound(); + query_list[i].dists[j] = raft::upper_bound(); + } + } + } +} + +} // namespace + +} // namespace cuvs::neighbors::experimental::vamana::detail diff --git a/cpp/src/neighbors/detail/vamana/vamana_build.cuh b/cpp/src/neighbors/detail/vamana/vamana_build.cuh new file mode 100644 index 000000000..da24decb3 --- /dev/null +++ b/cpp/src/neighbors/detail/vamana/vamana_build.cuh @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "greedy_search.cuh" +#include "robust_prune.cuh" +#include "vamana_structs.cuh" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +namespace cuvs::neighbors::experimental::vamana::detail { + +/* @defgroup vamana_build_detail vamana build + * @{ + */ + +static const std::string RAFT_NAME = "raft"; + +static const int blockD = 32; +static const int maxBlocks = 10000; + +// generate random permutation of inserts - TODO do this on GPU / faster +template +void create_insert_permutation(std::vector& insert_order, uint32_t N) +{ + insert_order.resize(N); + for (uint32_t i = 0; i < N; i++) { + insert_order[i] = (IdxT)i; + } + for (uint32_t i = 0; i < N; i++) { + uint32_t temp; + uint32_t rand_idx = rand() % N; + temp = insert_order[i]; + insert_order[i] = insert_order[rand_idx]; + insert_order[rand_idx] = temp; + } +} + +/******************************************************************************************** + * Main Vamana building function - insert vectors into empty graph in batches + * Pre - dataset contains the vector data, host matrix allocated to store the graph + * Post - graph matrix contains the graph edges of the final Vamana graph + *******************************************************************************************/ +template , + raft::memory_type::host>> +void batched_insert_vamana( + raft::resources const& res, + const index_params& params, + raft::mdspan, raft::row_major, Accessor> dataset, + raft::host_matrix_view graph, + IdxT* medoid_id, + cuvs::distance::DistanceType metric) +// int dim) +{ + auto stream = raft::resource::get_cuda_stream(res); + int N = dataset.extent(0); + int dim = dataset.extent(1); + int degree = graph.extent(1); + + // Algorithm params + int max_batchsize = (int)(params.max_fraction * (float)N); + if (max_batchsize > (int)dataset.extent(0)) { + RAFT_LOG_WARN( + "Max fraction is the fraction of the total dataset, so it cannot be larger 1.0, reducing it " + "to 1.0"); + max_batchsize = (int)dataset.extent(0); + } + int insert_iters = (int)(params.vamana_iters); + double base = (double)(params.batch_base); + float alpha = (float)(params.alpha); + int visited_size = params.visited_size; + int queue_size = params.queue_size; + + if ((visited_size & (visited_size - 1)) != 0) { + RAFT_LOG_WARN("visited_size must be a power of 2, rounding up."); + int power = params.graph_degree; + while (power < visited_size) + power <<= 1; + visited_size = power; + } + + // create gpu graph and set to all -1s + auto d_graph = raft::make_device_matrix(res, graph.extent(0), graph.extent(1)); + raft::linalg::map(res, d_graph.view(), raft::const_op{raft::upper_bound()}); + + // Temp storage about each batch of inserts being performed + auto query_ids = raft::make_device_vector(res, max_batchsize); + auto query_list_ptr = raft::make_device_mdarray>( + res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(max_batchsize + 1)); + QueryCandidates* query_list = + static_cast*>(query_list_ptr.data_handle()); + + // Results of each batch of inserts during build - Memory is used by query_list structure + auto visited_ids = + raft::make_device_mdarray(res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(max_batchsize, visited_size)); + auto visited_dists = + raft::make_device_mdarray(res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(max_batchsize, visited_size)); + + // Assign memory to query_list structures and initiailize + init_query_candidate_list<<<256, blockD, 0, stream>>>(query_list, + visited_ids.data_handle(), + visited_dists.data_handle(), + (int)max_batchsize, + visited_size); + + // Create random permutation for order of node inserts into graph + std::vector insert_order; + create_insert_permutation(insert_order, (uint32_t)N); + + // Memory needed to sort reverse edges - potentially large memory footprint + auto edge_dest = + raft::make_device_mdarray(res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(max_batchsize, degree)); + auto edge_src = + raft::make_device_mdarray(res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(max_batchsize, degree)); + + size_t temp_storage_bytes = max_batchsize * degree * (2 * sizeof(IdxT)); + RAFT_LOG_DEBUG("Temp storage needed for sorting (bytes): %lu", temp_storage_bytes); + auto temp_sort_storage = + raft::make_device_mdarray(res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(2 * max_batchsize, degree)); + + // Calculate the shared memory sizes of each kernel + int search_smem_sort_size = 0; + int prune_smem_sort_size = 0; + SELECT_SMEM_SIZES(degree, visited_size); // Sets above 2 variables to appropriate sizes + + // Total dynamic shared memory used by GreedySearch + int search_smem_total_size = + static_cast(search_smem_sort_size + dim * sizeof(T) + visited_size * sizeof(Node) + + degree * sizeof(int) + queue_size * sizeof(DistPair)); + + // Total dynamic shared memory size needed by both RobustPrune calls + int prune_smem_total_size = + prune_smem_sort_size + dim * sizeof(T) + (degree + visited_size) * sizeof(DistPair); + + RAFT_LOG_DEBUG("Dynamic shared memory usage (bytes): GreedySearch: %d, RobustPrune: %d", + search_smem_total_size, + prune_smem_total_size); + + if (prune_smem_sort_size == 0) { // If sizes not supported, smem sizes will be 0 + RAFT_FAIL("Vamana graph parameters not supported: graph_degree=%d, visited_size:%d\n", + degree, + visited_size); + } + + // Random medoid has minor impact on recall + // TODO: use heuristic for better medoid selection, issue: + // https://github.com/rapidsai/cuvs/issues/355 + *medoid_id = rand() % N; + + // size of current batch of inserts, increases logarithmically until max_batchsize + int step_size = 1; + // Number of passes over dataset (default 1) + for (int iter = 0; iter < insert_iters; iter++) { + // Loop through batches and call the insert and prune kernels + for (int start = 0; start < N;) { + if (start + step_size > N) { + int new_size = N - start; + step_size = new_size; + } + RAFT_LOG_DEBUG("Starting batch of inserts indices_start:%d, batch_size:%d", start, step_size); + + int num_blocks = min(maxBlocks, step_size); + + // Copy ids to be inserted for this batch + raft::copy(query_ids.data_handle(), &insert_order.data()[start], step_size, stream); + set_query_ids<<>>( + query_list_ptr.data_handle(), query_ids.data_handle(), step_size); + + // Call greedy search to get candidates for every vector being inserted + GreedySearchKernel + <<>>(d_graph.view(), + dataset, + query_list_ptr.data_handle(), + step_size, + *medoid_id, + visited_size, + metric, + queue_size, + search_smem_sort_size); + + // Run on candidates of vectors being inserted + RobustPruneKernel + <<>>(d_graph.view(), + dataset, + query_list_ptr.data_handle(), + step_size, + visited_size, + metric, + alpha, + prune_smem_sort_size); + + // Write results from first prune to graph edge list + write_graph_edges_kernel<<>>( + d_graph.view(), query_list_ptr.data_handle(), degree, step_size); + + // compute prefix sums of query_list sizes - TODO parallelize prefix sums + auto d_total_edges = raft::make_device_mdarray( + res, raft::resource::get_workspace_resource(res), raft::make_extents(1)); + prefix_sums_sizes + <<<1, 1, 0, stream>>>(query_list, step_size, d_total_edges.data_handle()); + + int total_edges; + raft::copy(&total_edges, d_total_edges.data_handle(), 1, stream); + + // Create reverse edge list + create_reverse_edge_list + <<>>(query_list_ptr.data_handle(), + step_size, + degree, + edge_src.data_handle(), + edge_dest.data_handle()); + + // Sort to group reverse edges by destination + cub::DeviceMergeSort::SortPairs(temp_sort_storage.data_handle(), + temp_storage_bytes, + edge_dest.data_handle(), + edge_src.data_handle(), + total_edges, + CmpEdge(), + stream); + + // Get number of unique node destinations + IdxT unique_dests = + raft::sparse::neighbors::get_n_components(edge_dest.data_handle(), total_edges, stream); + + // Find which node IDs have reverse edges and their indices in the reverse edge list + thrust::device_vector edge_dest_vec(edge_dest.data_handle(), + edge_dest.data_handle() + total_edges); + auto unique_indices = raft::make_device_vector(res, total_edges); + raft::linalg::map_offset(res, unique_indices.view(), raft::identity_op{}); + thrust::unique_by_key( + edge_dest_vec.begin(), edge_dest_vec.end(), unique_indices.data_handle()); + + // Allocate reverse QueryCandidate list based on number of unique destinations + // TODO - Do this in batches to reduce memory footprint / support larger datasets + auto reverse_list_ptr = raft::make_device_mdarray>( + res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(unique_dests)); + auto rev_ids = + raft::make_device_mdarray(res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(unique_dests, visited_size)); + auto rev_dists = + raft::make_device_mdarray(res, + raft::resource::get_large_workspace_resource(res), + raft::make_extents(unique_dests, visited_size)); + + QueryCandidates* reverse_list = + static_cast*>(reverse_list_ptr.data_handle()); + + init_query_candidate_list<<<256, blockD, 0, stream>>>(reverse_list, + rev_ids.data_handle(), + rev_dists.data_handle(), + (int)unique_dests, + visited_size); + + // May need more blocks for reverse list + num_blocks = min(maxBlocks, unique_dests); + + // Populate reverse list ids and candidate lists from edge_src and edge_dest + populate_reverse_list_struct + <<>>(reverse_list, + edge_src.data_handle(), + edge_dest.data_handle(), + unique_indices.data_handle(), + unique_dests, + total_edges, + dataset.extent(0)); + + // Recompute distances (avoided keeping it during sorting) + recompute_reverse_dists + <<>>(reverse_list, dataset, unique_dests, metric); + + // Call 2nd RobustPrune on reverse query_list + RobustPruneKernel + <<>>(d_graph.view(), + raft::make_const_mdspan(dataset), + reverse_list_ptr.data_handle(), + unique_dests, + visited_size, + metric, + alpha, + prune_smem_sort_size); + + // Write new edge lists to graph + write_graph_edges_kernel<<>>( + d_graph.view(), reverse_list_ptr.data_handle(), degree, unique_dests); + + start += step_size; + step_size *= base; + if (step_size > max_batchsize) step_size = max_batchsize; + + } // Batch of inserts + + } // insert iterations + + raft::copy(graph.data_handle(), d_graph.data_handle(), d_graph.size(), stream); + + RAFT_CHECK_CUDA(stream); +} + +template , + raft::memory_type::host>> +index build( + raft::resources const& res, + const index_params& params, + raft::mdspan, raft::row_major, Accessor> dataset) +{ + uint32_t graph_degree = params.graph_degree; + + RAFT_EXPECTS(params.metric == cuvs::distance::DistanceType::L2Expanded, + "Currently only L2Expanded metric is supported"); + + const int* deg_size = std::find(std::begin(DEGREE_SIZES), std::end(DEGREE_SIZES), graph_degree); + RAFT_EXPECTS(deg_size != std::end(DEGREE_SIZES), "Provided graph_degree not currently supported"); + + RAFT_EXPECTS(params.visited_size > graph_degree, "visited_size must be > graph_degree"); + + int dim = dataset.extent(1); + // TODO - Fix issue with alignment when dataset dimension is odd + RAFT_EXPECTS(dim % 2 == 0, "Datasets with an odd number of dimensions not currently supported"); + + RAFT_LOG_DEBUG("Creating empty graph structure"); + auto vamana_graph = raft::make_host_matrix(dataset.extent(0), graph_degree); + + RAFT_LOG_DEBUG("Running Vamana batched insert algorithm"); + + cuvs::distance::DistanceType metric = cuvs::distance::DistanceType::L2Expanded; + + IdxT medoid_id; + batched_insert_vamana( + res, params, dataset, vamana_graph.view(), &medoid_id, metric); + + try { + return index( + res, params.metric, dataset, raft::make_const_mdspan(vamana_graph.view()), medoid_id); + } catch (std::bad_alloc& e) { + RAFT_LOG_DEBUG("Insufficient GPU memory to construct VAMANA index with dataset on GPU"); + // We just add the graph. User is expected to update dataset separately (e.g allocating in + // managed memory). + } catch (raft::logic_error& e) { + // The memory error can also manifest as logic_error. + RAFT_LOG_DEBUG("Insufficient GPU memory to construct VAMANA index with dataset on GPU"); + } + index idx(res, params.metric); + RAFT_LOG_WARN("Constructor not called, returning empty index"); + return idx; +} + +/** + * @} + */ + +} // namespace cuvs::neighbors::experimental::vamana::detail diff --git a/cpp/src/neighbors/detail/vamana/vamana_serialize.cuh b/cpp/src/neighbors/detail/vamana/vamana_serialize.cuh new file mode 100644 index 000000000..a554464f6 --- /dev/null +++ b/cpp/src/neighbors/detail/vamana/vamana_serialize.cuh @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "vamana_structs.cuh" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../dataset_serialize.hpp" + +#include +#include +#include +#include + +namespace cuvs::neighbors::experimental::vamana::detail { + +/** + * Save the index to file. + * + * Experimental, both the API and the serialization format are subject to change. + * + * @param[in] res the raft resource handle + * @param[in] file_name the path and name of the DiskAN index file generated + * @param[in] index_ VAMANA index + * + */ + +template +void serialize(raft::resources const& res, + const std::string& file_name, + const index& index_) +{ + // Write graph to first index file (format from MSFT DiskANN OSS) + std::ofstream index_of(file_name, std::ios::out | std::ios::binary); + if (!index_of) { RAFT_FAIL("Cannot open file %s", file_name.c_str()); } + + size_t file_offset = 0; + index_of.seekp(file_offset, index_of.beg); + uint32_t max_degree = 0; + size_t index_size = 24; // Starting metadata + uint32_t start = static_cast(index_.medoid()); + size_t num_frozen_points = 0; + uint32_t max_observed_degree = 0; + + index_of.write((char*)&index_size, sizeof(uint64_t)); + index_of.write((char*)&max_observed_degree, sizeof(uint32_t)); + index_of.write((char*)&start, sizeof(uint32_t)); + index_of.write((char*)&num_frozen_points, sizeof(size_t)); + + auto d_graph = index_.graph(); + auto h_graph = raft::make_host_matrix(d_graph.extent(0), d_graph.extent(1)); + raft::copy(h_graph.data_handle(), + d_graph.data_handle(), + d_graph.size(), + raft::resource::get_cuda_stream(res)); + + size_t total_edges = 0; + size_t num_sparse = 0; + size_t num_single = 0; + + for (uint32_t i = 0; i < h_graph.extent(0); i++) { + uint32_t node_edges = 0; + for (; node_edges < h_graph.extent(1); node_edges++) { + if (h_graph(i, node_edges) == raft::upper_bound()) { break; } + } + + if (node_edges < 3) num_sparse++; + if (node_edges < 2) num_single++; + total_edges += node_edges; + + index_of.write((char*)&node_edges, sizeof(uint32_t)); + if constexpr (!std::is_same_v) { + RAFT_FAIL("serialization is only implemented for uint32_t graph"); + } + index_of.write((char*)&h_graph(i, 0), node_edges * sizeof(uint32_t)); + + max_degree = node_edges > max_degree ? (uint32_t)node_edges : max_degree; + index_size += (size_t)(sizeof(uint32_t) * (node_edges + 1)); + } + index_of.seekp(file_offset, index_of.beg); + index_of.write((char*)&index_size, sizeof(uint64_t)); + index_of.write((char*)&max_degree, sizeof(uint32_t)); + + RAFT_LOG_DEBUG( + "Wrote file out, index size:%lu, max_degree:%u, num_sparse:%ld, num_single:%ld, total " + "edges:%ld, avg degree:%f", + index_size, + max_degree, + num_sparse, + num_single, + total_edges, + (float)total_edges / (float)h_graph.extent(0)); + + index_of.close(); + if (!index_of) { RAFT_FAIL("Error writing output %s", file_name.c_str()); } +} + +} // namespace cuvs::neighbors::experimental::vamana::detail diff --git a/cpp/src/neighbors/detail/vamana/vamana_structs.cuh b/cpp/src/neighbors/detail/vamana/vamana_structs.cuh new file mode 100644 index 000000000..86cb4e1f8 --- /dev/null +++ b/cpp/src/neighbors/detail/vamana/vamana_structs.cuh @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace cuvs::neighbors::experimental::vamana::detail { + +/* @defgroup vamana_structures vamana structures + * @{ + */ + +#define FULL_BITMASK 0xFFFFFFFF + +// Currently supported values for graph_degree. +static const int DEGREE_SIZES[4] = {32, 64, 128, 256}; + +// Object used to store id,distance combination graph construction operations +template +struct __align__(16) DistPair +{ + accT dist; + IdxT idx; + + __device__ __host__ DistPair& operator=(const DistPair& other) + { + dist = other.dist; + idx = other.idx; + return *this; + } + + __device__ __host__ DistPair& operator=(const volatile DistPair& other) + { + dist = other.dist; + idx = other.idx; + return *this; + } +}; + +// Swap the values of two DistPair objects +template +__device__ __host__ void swap(DistPair* a, DistPair* b) +{ + DistPair temp; + temp.dist = a->dist; + temp.idx = a->idx; + a->dist = b->dist; + a->idx = b->idx; + b->dist = temp.dist; + b->idx = temp.idx; +} + +// Structure to sort by distance +struct CmpDist { + template + __device__ bool operator()(const DistPair& lhs, const DistPair& rhs) + { + return lhs.dist < rhs.dist; + } +}; + +// Used to sort reverse edges by destination +template +struct CmpEdge { + __device__ bool operator()(const IdxT& lhs, const IdxT& rhs) { return lhs < rhs; } +}; + +/********************************************************************* + * Object representing a Dim-dimensional point, with each coordinate + * represented by a element of datatype T + * Note, memory is allocated separately and coords set to offsets + *********************************************************************/ +template +class Point { + public: + int id; + int Dim; + T* coords; + + __host__ __device__ Point& operator=(const Point& other) + { + for (int i = 0; i < Dim; i++) { + coords[i] = other.coords[i]; + } + id = other.id; + return *this; + } +}; + +/* L2 fallback for low dimension when ILP is not possible */ +template +__device__ SUMTYPE l2_SEQ(Point* src_vec, Point* dst_vec) +{ + SUMTYPE partial_sum = 0; + + for (int i = threadIdx.x; i < src_vec->Dim; i += blockDim.x) { + partial_sum = fmaf((src_vec[0].coords[i] - dst_vec[0].coords[i]), + (src_vec[0].coords[i] - dst_vec[0].coords[i]), + partial_sum); + } + + for (int offset = 16; offset > 0; offset /= 2) { + partial_sum += __shfl_down_sync(FULL_BITMASK, partial_sum, offset); + } + return partial_sum; +} + +/* L2 optimized with 2-way ILP for DIM >= 64 */ +template +__device__ SUMTYPE l2_ILP2(Point* src_vec, Point* dst_vec) +{ + T temp_dst[2] = {0, 0}; + SUMTYPE partial_sum[2] = {0, 0}; + for (int i = threadIdx.x; i < src_vec->Dim; i += 2 * blockDim.x) { + temp_dst[0] = dst_vec->coords[i]; + if (i + 32 < src_vec->Dim) temp_dst[1] = dst_vec->coords[i + 32]; + + partial_sum[0] = fmaf( + (src_vec[0].coords[i] - temp_dst[0]), (src_vec[0].coords[i] - temp_dst[0]), partial_sum[0]); + if (i + 32 < src_vec->Dim) + partial_sum[1] = fmaf((src_vec[0].coords[i + 32] - temp_dst[1]), + (src_vec[0].coords[i + 32] - temp_dst[1]), + partial_sum[1]); + } + partial_sum[0] += partial_sum[1]; + + for (int offset = 16; offset > 0; offset /= 2) { + partial_sum[0] += __shfl_down_sync(FULL_BITMASK, partial_sum[0], offset); + } + return partial_sum[0]; +} + +/* L2 optimized with 4-way ILP for optimal performance for DIM >= 128 */ +template +__device__ SUMTYPE l2_ILP4(Point* src_vec, Point* dst_vec) +{ + T temp_dst[4] = {0, 0, 0, 0}; + SUMTYPE partial_sum[4] = {0, 0, 0, 0}; + for (int i = threadIdx.x; i < src_vec->Dim; i += 4 * blockDim.x) { + temp_dst[0] = dst_vec->coords[i]; + if (i + 32 < src_vec->Dim) temp_dst[1] = dst_vec->coords[i + 32]; + if (i + 64 < src_vec->Dim) temp_dst[2] = dst_vec->coords[i + 64]; + if (i + 92 < src_vec->Dim) temp_dst[3] = dst_vec->coords[i + 96]; + + partial_sum[0] = fmaf( + (src_vec[0].coords[i] - temp_dst[0]), (src_vec[0].coords[i] - temp_dst[0]), partial_sum[0]); + if (i + 32 < src_vec->Dim) + partial_sum[1] = fmaf((src_vec[0].coords[i + 32] - temp_dst[1]), + (src_vec[0].coords[i + 32] - temp_dst[1]), + partial_sum[1]); + if (i + 64 < src_vec->Dim) + partial_sum[2] = fmaf((src_vec[0].coords[i + 64] - temp_dst[2]), + (src_vec[0].coords[i + 64] - temp_dst[2]), + partial_sum[2]); + if (i + 92 < src_vec->Dim) + partial_sum[3] = fmaf((src_vec[0].coords[i + 96] - temp_dst[3]), + (src_vec[0].coords[i + 96] - temp_dst[3]), + partial_sum[3]); + } + partial_sum[0] += partial_sum[1] + partial_sum[2] + partial_sum[3]; + + for (int offset = 16; offset > 0; offset /= 2) { + partial_sum[0] += __shfl_down_sync(FULL_BITMASK, partial_sum[0], offset); + } + return partial_sum[0]; +} + +/* Selects ILP optimization level based on dimension */ +template +__forceinline__ __device__ SUMTYPE l2(Point* src_vec, Point* dst_vec) +{ + if (src_vec->Dim >= 128) { + return l2_ILP4(src_vec, dst_vec); + } else if (src_vec->Dim >= 64) { + return l2_ILP2(src_vec, dst_vec); + } else { + return l2_SEQ(src_vec, dst_vec); + } +} + +/* Convert vectors to point structure to performance distance comparison */ +template +__host__ __device__ SUMTYPE l2(const T* src, const T* dest, int dim) +{ + Point src_p; + src_p.coords = const_cast(src); + src_p.Dim = dim; + Point dest_p; + dest_p.coords = const_cast(dest); + dest_p.Dim = dim; + + return l2(&src_p, &dest_p); +} + +// Currently only L2Expanded is supported +template +__host__ __device__ SUMTYPE +dist(const T* src, const T* dest, int dim, cuvs::distance::DistanceType metric) +{ + return l2(src, dest, dim); +} + +/*************************************************************************************** + * Structure that holds information about and results of a query. Use by both + * GreedySearch and RobustPrune, as well as reverse edge lists. + ***************************************************************************************/ +template +struct QueryCandidates { + IdxT* ids; + accT* dists; + int queryId; + int size; + int maxSize; + + __device__ void reset() + { + for (int i = threadIdx.x; i < maxSize; i += blockDim.x) { + ids[i] = raft::upper_bound(); + dists[i] = raft::upper_bound(); + } + size = 0; + } + + // Checks current list to see if a node as previously been visited + __inline__ __device__ bool check_visited(IdxT target, accT dist) + { + __syncthreads(); + __shared__ bool found; + found = false; + __syncthreads(); + + if (size < maxSize) { + __syncthreads(); + for (int i = threadIdx.x; i < size; i += blockDim.x) { + if (ids[i] == target) { found = true; } + } + __syncthreads(); + if (!found && threadIdx.x == 0) { + ids[size] = target; + dists[size] = dist; + size++; + } + __syncthreads(); + } + return found; + } + // For debugging + /* + __inline__ __device__ void print_visited() { + printf("queryId:%d, size:%d\n", queryId, size); + for(int i=0; i +__global__ void print_query_results(void* query_list_ptr, int count) +{ + QueryCandidates* query_list = + static_cast*>(query_list_ptr); + + for (int i = 0; i < count; i++) { + query_list[i].print_visited(); + } +} + +// Initialize a list of QueryCandidates objects: assign memory to mpointers and initialize values +template +__global__ void init_query_candidate_list(QueryCandidates* query_list, + IdxT* visited_id_ptr, + accT* visited_dist_ptr, + int num_queries, + int maxSize) +{ + IdxT* ids_ptr = static_cast(visited_id_ptr); + accT* dist_ptr = static_cast(visited_dist_ptr); + + for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < num_queries * maxSize; + i += blockDim.x + gridDim.x) { + ids_ptr[i] = raft::upper_bound(); + dist_ptr[i] = raft::upper_bound(); + } + + for (size_t i = blockIdx.x * blockDim.x + threadIdx.x; i < num_queries; + i += blockDim.x + gridDim.x) { + query_list[i].maxSize = maxSize; + query_list[i].size = 0; + query_list[i].ids = &ids_ptr[i * (size_t)(maxSize)]; + query_list[i].dists = &dist_ptr[i * (size_t)(maxSize)]; + } +} + +// Copy query ID values from input array +template +__global__ void set_query_ids(void* query_list_ptr, IdxT* d_query_ids, int step_size) +{ + QueryCandidates* query_list = + static_cast*>(query_list_ptr); + + for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < step_size; i += blockDim.x * gridDim.x) { + query_list[i].queryId = d_query_ids[i]; + query_list[i].size = 0; + } +} + +// Compute prefix sums on sizes. Currently only works with 1 thread +// TODO replace with parallel version +template +__global__ void prefix_sums_sizes(QueryCandidates* query_list, + int num_queries, + int* total_edges) +{ + if (threadIdx.x == 0 && blockIdx.x == 0) { + int sum = 0; + for (int i = 0; i < num_queries + 1; i++) { + sum += query_list[i].size; + query_list[i].size = sum - query_list[i].size; // exclusive prefix sum + } + *total_edges = query_list[num_queries].size; + } +} + +// Device fcn to have a threadblock copy coordinates into shared memory +template +__device__ void update_shared_point(Point* shared_point, + const T* data_ptr, + int id, + int dim) +{ + shared_point->id = id; + shared_point->Dim = dim; + for (size_t i = threadIdx.x; i < dim; i += blockDim.x) { + shared_point->coords[i] = data_ptr[(size_t)(id) * (size_t)(dim) + i]; + } +} + +// Update the graph from the results of the query list (or reverse edge list) +template +__global__ void write_graph_edges_kernel(raft::device_matrix_view graph, + void* query_list_ptr, + int degree, + int num_queries) +{ + QueryCandidates* query_list = + static_cast*>(query_list_ptr); + + for (int i = blockIdx.x; i < num_queries; i += gridDim.x) { + for (int j = threadIdx.x; j < query_list[i].size; j += blockDim.x) { + graph(query_list[i].queryId, j) = query_list[i].ids[j]; + } + } +} + +// Create src and dest edge lists used to sort and create reverse edges +template +__global__ void create_reverse_edge_list( + void* query_list_ptr, int num_queries, int degree, IdxT* edge_src, IdxT* edge_dest) +{ + QueryCandidates* query_list = + static_cast*>(query_list_ptr); + + for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < num_queries; + i += blockDim.x * gridDim.x) { + int read_idx = i * query_list[i].maxSize; + int cand_count = query_list[i + 1].size - query_list[i].size; + + for (int j = 0; j < cand_count; j++) { + edge_src[query_list[i].size + j] = query_list[i].queryId; + edge_dest[query_list[i].size + j] = query_list[i].ids[j]; + } + } +} + +// Populate reverse edge QueryCandidates structure based on sorted edge list and unique indices +// values +template +__global__ void populate_reverse_list_struct(QueryCandidates* reverse_list, + IdxT* edge_src, + IdxT* edge_dest, + int* unique_indices, + int unique_dests, + int total_edges, + int N) +{ + for (int i = blockIdx.x * blockDim.x + threadIdx.x; i < unique_dests; + i += blockDim.x * gridDim.x) { + reverse_list[i].queryId = edge_dest[unique_indices[i]]; + if (i == unique_dests - 1) { + reverse_list[i].size = total_edges - unique_indices[i]; + } else { + reverse_list[i].size = unique_indices[i + 1] - unique_indices[i]; + } + if (reverse_list[i].size > reverse_list[i].maxSize) { + reverse_list[i].size = reverse_list[i].maxSize; + } + + for (int j = 0; j < reverse_list[i].size; j++) { + reverse_list[i].ids[j] = edge_src[unique_indices[i] + j]; + } + for (int j = reverse_list[i].size; j < reverse_list[i].maxSize; j++) { + reverse_list[i].ids[j] = raft::upper_bound(); + reverse_list[i].dists[j] = raft::upper_bound(); + } + } +} + +// Recompute distances of reverse list. Allows us to avoid keeping distances during sort +template , + raft::memory_type::host>> +__global__ void recompute_reverse_dists( + QueryCandidates* reverse_list, + raft::mdspan, raft::row_major, Accessor> dataset, + int unique_dests, + cuvs::distance::DistanceType metric) +{ + int dim = dataset.extent(1); + const T* vec_ptr = dataset.data_handle(); + + for (int i = blockIdx.x; i < unique_dests; i += gridDim.x) { + for (int j = 0; j < reverse_list[i].size; j++) { + reverse_list[i].dists[j] = + dist(&vec_ptr[(size_t)(reverse_list[i].queryId) * (size_t)dim], + &vec_ptr[(size_t)(reverse_list[i].ids[j]) * (size_t)dim], + dim, + metric); + } + } +} + +} // namespace + +/** + * @} + */ + +} // namespace cuvs::neighbors::experimental::vamana::detail diff --git a/cpp/src/neighbors/vamana.cuh b/cpp/src/neighbors/vamana.cuh new file mode 100644 index 000000000..9b9e8d271 --- /dev/null +++ b/cpp/src/neighbors/vamana.cuh @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "detail/vamana/vamana_build.cuh" +#include "detail/vamana/vamana_serialize.cuh" + +#include +#include +#include +#include + +#include +#include + +#include + +#include + +namespace cuvs::neighbors::experimental::vamana { + +/** + * @defgroup VAMANA ANN Graph-based nearest neighbor search + * @{ + */ + +/** + * @brief Build the VAMANA / DiskANN index from the dataset. + * + * The Vamana index construction algorithm is an iterative insertion based algorithm. + * We start with an empty graph and insert batches of new nodes into the graph until + * all nodes have been inserted. Each insertion involves: + * - Perform GreedySearch into the current graph and collect all visited nodes. + * - Perform RobustPrune on the list of visited nodes to get the edge list for new node. + * - Compute the reverse edges for all edges from the newly inserted node. + * - Combine reverse edges with existing edge lists and perform RobustPrune as needed. + * + * Currently only build and serialize (write to graph) is supported in cuVS. The format + * of the serialized graph matches the DiskANN format, so search can be done with other + * CPU DiskANN libraries as needed. + * + * The following distance metrics are supported: + * - L2Expanded + * + * Usage example: + * @code{.cpp} + * using namespace cuvs::neighbors; + * // use default index parameters + * vamana::index_params index_params; + * // create and fill the index from a [N, D] dataset + * auto index = vamana::build(res, index_params, dataset); + * // write graph to file for later use. + vamana.serialize(res, filename, index); + * @endcode + * + * @tparam T data element type + * @tparam IdxT type of the indices in the source dataset + * + * @param[in] res + * @param[in] params parameters for building the index + * @param[in] dataset a matrix view (host or device) to a row-major matrix [n_rows, dim] + * + * @return the constructed vamana index + */ +template , + raft::memory_type::host>> +index build( + raft::resources const& res, + const index_params& params, + raft::mdspan, raft::row_major, Accessor> dataset) +{ + return cuvs::neighbors::experimental::vamana::detail::build( + res, params, dataset); +} + +template +void serialize(raft::resources const& res, + const std::string& file_prefix, + const index& index_) +{ + cuvs::neighbors::experimental::vamana::detail::build(res, file_prefix, index_); +} + +/** @} */ // end group vamana + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/src/neighbors/vamana_build_float.cu b/cpp/src/neighbors/vamana_build_float.cu new file mode 100644 index 000000000..b83af6122 --- /dev/null +++ b/cpp/src/neighbors/vamana_build_float.cu @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "vamana.cuh" +#include + +namespace cuvs::neighbors::experimental::vamana { + +#define RAFT_INST_VAMANA_BUILD(T, IdxT) \ + auto build(raft::resources const& handle, \ + const cuvs::neighbors::experimental::vamana::index_params& params, \ + raft::device_matrix_view dataset) \ + ->cuvs::neighbors::experimental::vamana::index \ + { \ + return cuvs::neighbors::experimental::vamana::build(handle, params, dataset); \ + } \ + \ + auto build(raft::resources const& handle, \ + const cuvs::neighbors::experimental::vamana::index_params& params, \ + raft::host_matrix_view dataset) \ + ->cuvs::neighbors::experimental::vamana::index \ + { \ + return cuvs::neighbors::experimental::vamana::build(handle, params, dataset); \ + } + +RAFT_INST_VAMANA_BUILD(float, uint32_t); + +#undef RAFT_INST_VAMANA_BUILD + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/src/neighbors/vamana_build_int8.cu b/cpp/src/neighbors/vamana_build_int8.cu new file mode 100644 index 000000000..91d2cf028 --- /dev/null +++ b/cpp/src/neighbors/vamana_build_int8.cu @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "vamana.cuh" +#include + +namespace cuvs::neighbors::experimental::vamana { + +#define RAFT_INST_VAMANA_BUILD(T, IdxT) \ + auto build(raft::resources const& handle, \ + const cuvs::neighbors::experimental::vamana::index_params& params, \ + raft::device_matrix_view dataset) \ + ->cuvs::neighbors::experimental::vamana::index \ + { \ + return cuvs::neighbors::experimental::vamana::build(handle, params, dataset); \ + } \ + \ + auto build(raft::resources const& handle, \ + const cuvs::neighbors::experimental::vamana::index_params& params, \ + raft::host_matrix_view dataset) \ + ->cuvs::neighbors::experimental::vamana::index \ + { \ + return cuvs::neighbors::experimental::vamana::build(handle, params, dataset); \ + } + +RAFT_INST_VAMANA_BUILD(int8_t, uint32_t); + +#undef RAFT_INST_VAMANA_BUILD + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/src/neighbors/vamana_build_uint8.cu b/cpp/src/neighbors/vamana_build_uint8.cu new file mode 100644 index 000000000..bba93e7f4 --- /dev/null +++ b/cpp/src/neighbors/vamana_build_uint8.cu @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023-2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "vamana.cuh" +#include + +namespace cuvs::neighbors::experimental::vamana { + +#define RAFT_INST_VAMANA_BUILD(T, IdxT) \ + auto build(raft::resources const& handle, \ + const cuvs::neighbors::experimental::vamana::index_params& params, \ + raft::device_matrix_view dataset) \ + ->cuvs::neighbors::experimental::vamana::index \ + { \ + return cuvs::neighbors::experimental::vamana::build(handle, params, dataset); \ + } \ + \ + auto build(raft::resources const& handle, \ + const cuvs::neighbors::experimental::vamana::index_params& params, \ + raft::host_matrix_view dataset) \ + ->cuvs::neighbors::experimental::vamana::index \ + { \ + return cuvs::neighbors::experimental::vamana::build(handle, params, dataset); \ + } + +RAFT_INST_VAMANA_BUILD(uint8_t, uint32_t); + +#undef RAFT_INST_VAMANA_BUILD + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/src/neighbors/vamana_serialize.cuh b/cpp/src/neighbors/vamana_serialize.cuh new file mode 100644 index 000000000..a49d267b3 --- /dev/null +++ b/cpp/src/neighbors/vamana_serialize.cuh @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "detail/vamana/vamana_serialize.cuh" + +namespace cuvs::neighbors::experimental::vamana { + +/** + * @defgroup VAMANA graph serialize/derserialize + * @{ + */ + +#define CUVS_INST_VAMANA_SERIALIZE(DTYPE) \ + void serialize(raft::resources const& handle, \ + const std::string& file_prefix, \ + const cuvs::neighbors::experimental::vamana::index& index_) \ + { \ + cuvs::neighbors::experimental::vamana::detail::serialize( \ + handle, file_prefix, index_); \ + }; + +/** @} */ // end group vamana + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/src/neighbors/vamana_serialize_float.cu b/cpp/src/neighbors/vamana_serialize_float.cu new file mode 100644 index 000000000..f25369368 --- /dev/null +++ b/cpp/src/neighbors/vamana_serialize_float.cu @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "vamana_serialize.cuh" + +namespace cuvs::neighbors::experimental::vamana { + +CUVS_INST_VAMANA_SERIALIZE(float); + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/src/neighbors/vamana_serialize_int8.cu b/cpp/src/neighbors/vamana_serialize_int8.cu new file mode 100644 index 000000000..1cd54b198 --- /dev/null +++ b/cpp/src/neighbors/vamana_serialize_int8.cu @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "vamana_serialize.cuh" + +namespace cuvs::neighbors::experimental::vamana { + +CUVS_INST_VAMANA_SERIALIZE(int8_t); + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/src/neighbors/vamana_serialize_uint8.cu b/cpp/src/neighbors/vamana_serialize_uint8.cu new file mode 100644 index 000000000..3e6d945b8 --- /dev/null +++ b/cpp/src/neighbors/vamana_serialize_uint8.cu @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "vamana_serialize.cuh" + +namespace cuvs::neighbors::experimental::vamana { + +CUVS_INST_VAMANA_SERIALIZE(uint8_t); + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt index 5f7b5b02b..58cfc3862 100644 --- a/cpp/test/CMakeLists.txt +++ b/cpp/test/CMakeLists.txt @@ -159,6 +159,19 @@ if(BUILD_TESTS) 100 ) + ConfigureTest( + NAME + NEIGHBORS_ANN_VAMANA_TEST + PATH + neighbors/ann_vamana/test_float_uint32_t.cu + neighbors/ann_vamana/test_int8_t_uint32_t.cu + neighbors/ann_vamana/test_uint8_t_uint32_t.cu + GPUS + 1 + PERCENT + 100 + ) + if(BUILD_CAGRA_HNSWLIB) ConfigureTest(NAME NEIGHBORS_HNSW_TEST PATH neighbors/hnsw.cu GPUS 1 PERCENT 100) endif() diff --git a/cpp/test/neighbors/ann_vamana.cuh b/cpp/test/neighbors/ann_vamana.cuh new file mode 100644 index 000000000..9d9df4470 --- /dev/null +++ b/cpp/test/neighbors/ann_vamana.cuh @@ -0,0 +1,339 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 "../test_utils.cuh" +#include "ann_utils.cuh" +#include + +#include "naive_knn.cuh" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include + +namespace cuvs::neighbors::experimental::vamana { + +struct edge_op { + template + constexpr RAFT_INLINE_FUNCTION auto operator()(const Type& in, UnusedArgs...) const + { + return in == raft::upper_bound() ? Type(0) : in; + } +}; + +struct AnnVamanaInputs { + int n_rows; + int dim; + int graph_degree; + int visited_size; + double max_fraction; + cuvs::distance::DistanceType metric; + bool host_dataset; + + // cagra search params + int n_queries; + int k; + cagra::search_algo algo; + int max_queries; + int itopk_size; + int search_width; + double min_recall; +}; + +template +inline void CheckGraph(vamana::index* index_, + AnnVamanaInputs inputs, + cudaStream_t stream) +{ + EXPECT_TRUE(index_->graph().size() == (inputs.n_rows * inputs.graph_degree)); + EXPECT_TRUE(index_->graph().extent(0) == inputs.n_rows); + EXPECT_TRUE(index_->graph().extent(1) == inputs.graph_degree); + + // Copy graph to host + auto h_graph = raft::make_host_matrix(inputs.n_rows, inputs.graph_degree); + raft::copy(h_graph.data_handle(), index_->graph().data_handle(), index_->graph().size(), stream); + + size_t edge_count = 0; + int max_degree = 0; + for (int i = 0; i < h_graph.extent(0); i++) { + int temp_degree = 0; + for (int j = 0; j < h_graph.extent(1); j++) { + if (h_graph(i, j) < (uint32_t)(inputs.n_rows)) temp_degree++; + } + if (temp_degree > max_degree) max_degree = temp_degree; + edge_count += (size_t)temp_degree; + } + + // Tests for acceptable range of edges - low dim can also impact this + // Minimum expected maximum degree across the whole graph + EXPECT_TRUE(max_degree >= std::min(inputs.graph_degree, inputs.dim)); + + float max_edges = (float)(inputs.n_rows * std::min(inputs.graph_degree, inputs.dim)); + + RAFT_LOG_INFO("dim:%d, degree:%d, visited_size:%d, Total edges:%lu, Maximum edges:%lu", + inputs.dim, + inputs.graph_degree, + inputs.visited_size, + edge_count, + (size_t)max_edges); + + // Graph won't always be full, but <75% is very unlikely + EXPECT_TRUE(((float)edge_count / max_edges) > 0.75); +} + +template +class AnnVamanaTest : public ::testing::TestWithParam { + public: + AnnVamanaTest() + : stream_(raft::resource::get_cuda_stream(handle_)), + ps(::testing::TestWithParam::GetParam()), + database(0, stream_), + search_queries(0, stream_) + { + } + + protected: + void testVamana() + { + vamana::index_params index_params; + index_params.metric = ps.metric; + index_params.graph_degree = ps.graph_degree; + index_params.visited_size = ps.visited_size; + index_params.max_fraction = ps.max_fraction; + + auto database_view = raft::make_device_matrix_view( + (const DataT*)database.data(), ps.n_rows, ps.dim); + + vamana::index index(handle_); + if (ps.host_dataset) { + auto database_host = raft::make_host_matrix(ps.n_rows, ps.dim); + raft::copy(database_host.data_handle(), database.data(), database.size(), stream_); + auto database_host_view = raft::make_host_matrix_view( + (const DataT*)database_host.data_handle(), ps.n_rows, ps.dim); + + index = vamana::build(handle_, index_params, database_host_view); + } else { + index = vamana::build(handle_, index_params, database_view); + }; + + CheckGraph(&index, ps, stream_); + + vamana::serialize(handle_, "vamana_index", index); + + // Test recall by searching with CAGRA search + if (ps.graph_degree < 256) { // CAGRA search result buffer cannot support larger graph degree + size_t queries_size = ps.n_queries * ps.k; + std::vector indices_Cagra(queries_size); + std::vector indices_naive(queries_size); + std::vector distances_Cagra(queries_size); + std::vector distances_naive(queries_size); + + { + rmm::device_uvector distances_naive_dev(queries_size, stream_); + rmm::device_uvector indices_naive_dev(queries_size, stream_); + + cuvs::neighbors::naive_knn(handle_, + distances_naive_dev.data(), + indices_naive_dev.data(), + search_queries.data(), + database.data(), + ps.n_queries, + ps.n_rows, + ps.dim, + ps.k, + ps.metric); + raft::update_host( + distances_naive.data(), distances_naive_dev.data(), queries_size, stream_); + raft::update_host(indices_naive.data(), indices_naive_dev.data(), queries_size, stream_); + raft::resource::sync_stream(handle_); + } + + // Replace invalid edges with an edge to node 0 + auto graph_valid = raft::make_device_matrix( + handle_, index.graph().extent(0), index.graph().extent(1)); + raft::linalg::map(handle_, graph_valid.view(), edge_op{}, index.graph()); + + auto cagra_index = cagra::index(handle_, + ps.metric, + raft::make_const_mdspan(database_view), + raft::make_const_mdspan(graph_valid.view())); + + cagra::search_params search_params; + search_params.algo = ps.algo; + search_params.max_queries = ps.max_queries; + search_params.team_size = 0; + + rmm::device_uvector distances_dev(queries_size, stream_); + rmm::device_uvector indices_dev(queries_size, stream_); + + auto search_queries_view = raft::make_device_matrix_view( + search_queries.data(), ps.n_queries, ps.dim); + auto indices_out_view = + raft::make_device_matrix_view(indices_dev.data(), ps.n_queries, ps.k); + auto dists_out_view = + raft::make_device_matrix_view(distances_dev.data(), ps.n_queries, ps.k); + + cagra::search( + handle_, search_params, cagra_index, search_queries_view, indices_out_view, dists_out_view); + raft::update_host(distances_Cagra.data(), distances_dev.data(), queries_size, stream_); + raft::update_host(indices_Cagra.data(), indices_dev.data(), queries_size, stream_); + + raft::resource::sync_stream(handle_); + + double min_recall = ps.min_recall; + EXPECT_TRUE(eval_neighbours(indices_naive, + indices_Cagra, + distances_naive, + distances_Cagra, + ps.n_queries, + ps.k, + 0.003, + min_recall)); + } + } + + void SetUp() override + { + database.resize(((size_t)ps.n_rows) * ps.dim, stream_); + search_queries.resize(((size_t)ps.n_queries) * ps.dim, stream_); + raft::random::RngState r(1234ULL); + if constexpr (std::is_same{}) { + raft::random::normal(handle_, r, database.data(), ps.n_rows * ps.dim, DataT(0.1), DataT(2.0)); + raft::random::normal( + handle_, r, search_queries.data(), ps.n_queries * ps.dim, DataT(0.1), DataT(2.0)); + } else { + raft::random::uniformInt( + handle_, r, database.data(), ps.n_rows * ps.dim, DataT(1), DataT(20)); + raft::random::uniformInt( + handle_, r, search_queries.data(), ps.n_queries * ps.dim, DataT(1), DataT(20)); + } + raft::resource::sync_stream(handle_); + } + + void TearDown() override + { + raft::resource::sync_stream(handle_); + database.resize(0, stream_); + search_queries.resize(0, stream_); + } + + private: + raft::resources handle_; + rmm::cuda_stream_view stream_; + AnnVamanaInputs ps; + rmm::device_uvector database; + rmm::device_uvector search_queries; +}; + +inline std::vector generate_inputs() +{ + std::vector inputs = raft::util::itertools::product( + {1000}, + // {1, 3, 5, 7, 8, 17, 64, 128, 137, 192, 256, 512, 619, 1024}, // TODO - fix alignment + // issue for odd dims + {16, 32, 64, 128, 192, 256, 512, 1024}, // dim + {32}, // graph degree + {64, 128, 256}, // visited_size + {0.06, 0.1}, + {cuvs::distance::DistanceType::L2Expanded}, + {false}, + {100}, + {10}, + {cagra::search_algo::AUTO}, + {10}, + {64}, + {1}, + {0.2}); + + std::vector inputs2 = + raft::util::itertools::product({1000}, + {16, 32, 64, 128, 192, 256, 512, 1024}, // dim + {64}, // graph degree + {128, 256, 512}, // visited_size + {0.06, 0.1}, + {cuvs::distance::DistanceType::L2Expanded}, + {false}, + {100}, + {10}, + {cagra::search_algo::AUTO}, + {10}, + {32}, + {1}, + {0.2}); + inputs.insert(inputs.end(), inputs2.begin(), inputs2.end()); + + inputs2 = + raft::util::itertools::product({1000}, + {16, 32, 64, 128, 192, 256, 512, 1024}, // dim + {128}, // graph degree + {256, 512}, // visited_size + {0.06, 0.1}, + {cuvs::distance::DistanceType::L2Expanded}, + {false}, + {100}, + {10}, + {cagra::search_algo::AUTO}, + {10}, + {64}, + {1}, + {0.2}); + inputs.insert(inputs.end(), inputs2.begin(), inputs2.end()); + + inputs2 = + raft::util::itertools::product({1000}, + {16, 32, 64, 128, 192, 256, 512, 1024}, // dim + {256}, // graph degree + {512, 1024}, // visited_size + {0.06, 0.1}, + {cuvs::distance::DistanceType::L2Expanded}, + {false}, + {100}, + {10}, + {cagra::search_algo::AUTO}, + {10}, + {64}, + {1}, + {0.2}); + inputs.insert(inputs.end(), inputs2.begin(), inputs2.end()); + + return inputs; +} + +const std::vector inputs = generate_inputs(); + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/test/neighbors/ann_vamana/test_float_uint32_t.cu b/cpp/test/neighbors/ann_vamana/test_float_uint32_t.cu new file mode 100644 index 000000000..9aa9da1b8 --- /dev/null +++ b/cpp/test/neighbors/ann_vamana/test_float_uint32_t.cu @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 + +#include "../ann_vamana.cuh" + +namespace cuvs::neighbors::experimental::vamana { + +typedef AnnVamanaTest AnnVamanaTestF_U32; +TEST_P(AnnVamanaTestF_U32, AnnVamana) { this->testVamana(); } + +INSTANTIATE_TEST_CASE_P(AnnVamanaTest, AnnVamanaTestF_U32, ::testing::ValuesIn(inputs)); + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/test/neighbors/ann_vamana/test_int8_t_uint32_t.cu b/cpp/test/neighbors/ann_vamana/test_int8_t_uint32_t.cu new file mode 100644 index 000000000..0a6b563b2 --- /dev/null +++ b/cpp/test/neighbors/ann_vamana/test_int8_t_uint32_t.cu @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 + +#include "../ann_vamana.cuh" + +namespace cuvs::neighbors::experimental::vamana { + +typedef AnnVamanaTest AnnVamanaTestI8_U32; +TEST_P(AnnVamanaTestI8_U32, AnnVamana) { this->testVamana(); } + +INSTANTIATE_TEST_CASE_P(AnnVamanaTest, AnnVamanaTestI8_U32, ::testing::ValuesIn(inputs)); + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/cpp/test/neighbors/ann_vamana/test_uint8_t_uint32_t.cu b/cpp/test/neighbors/ann_vamana/test_uint8_t_uint32_t.cu new file mode 100644 index 000000000..c0680dc18 --- /dev/null +++ b/cpp/test/neighbors/ann_vamana/test_uint8_t_uint32_t.cu @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 + +#include "../ann_vamana.cuh" + +namespace cuvs::neighbors::experimental::vamana { + +typedef AnnVamanaTest AnnVamanaTestU8_U32; +TEST_P(AnnVamanaTestU8_U32, AnnVamana) { this->testVamana(); } + +INSTANTIATE_TEST_CASE_P(AnnVamanaTest, AnnVamanaTestU8_U32, ::testing::ValuesIn(inputs)); + +} // namespace cuvs::neighbors::experimental::vamana diff --git a/examples/build.sh b/examples/build.sh index 59f589af2..6aad8fe46 100755 --- a/examples/build.sh +++ b/examples/build.sh @@ -7,6 +7,7 @@ # Abort script on first error set -e + PARALLEL_LEVEL=${PARALLEL_LEVEL:=`nproc`} BUILD_TYPE=Release @@ -14,7 +15,10 @@ BUILD_DIR=build/ CUVS_REPO_REL="" EXTRA_CMAKE_ARGS="" -set -e +BUILD_ALL_GPU_ARCH=0 +if hasArg --allgpuarch; then + BUILD_ALL_GPU_ARCH=1 +fi # Root of examples EXAMPLES_DIR=$(dirname "$(realpath "$0")") @@ -32,6 +36,14 @@ if [ "$1" == "clean" ]; then exit 0 fi +if (( ${BUILD_ALL_GPU_ARCH} == 0 )); then + CUVS_CMAKE_CUDA_ARCHITECTURES="NATIVE" + echo "Building for the architecture of the GPU in the system..." +else + CUVS_CMAKE_CUDA_ARCHITECTURES="RAPIDS" + echo "Building for *ALL* supported GPU architectures..." +fi + ################################################################################ # Add individual libcuvs examples build scripts down below @@ -44,7 +56,7 @@ build_example() { cmake -S ${example_dir} -B ${build_dir} \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DCUVS_NVTX=OFF \ - -DCMAKE_CUDA_ARCHITECTURES="native" \ + -DCMAKE_CUDA_ARCHITECTURES=${CUVS_CMAKE_CUDA_ARCHITECTURES} \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ ${EXTRA_CMAKE_ARGS} # Build diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index d47cd4f1c..ec8ca827a 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -18,11 +18,14 @@ cmake_minimum_required(VERSION 3.26.4 FATAL_ERROR) include(../cmake/thirdparty/fetch_rapids.cmake) include(rapids-cmake) include(rapids-cpm) +include(rapids-cuda) include(rapids-export) include(rapids-find) # ------------- configure project --------------# +rapids_cuda_init_architectures(test_cuvs) + project(test_cuvs_c LANGUAGES C CXX CUDA) # ------------- configure cuvs -----------------# diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt index 15f494d3d..092b65ed9 100644 --- a/examples/cpp/CMakeLists.txt +++ b/examples/cpp/CMakeLists.txt @@ -40,6 +40,7 @@ add_executable(CAGRA_EXAMPLE src/cagra_example.cu) add_executable(CAGRA_PERSISTENT_EXAMPLE src/cagra_persistent_example.cu) add_executable(IVF_FLAT_EXAMPLE src/ivf_flat_example.cu) add_executable(IVF_PQ_EXAMPLE src/ivf_pq_example.cu) +add_executable(VAMANA_EXAMPLE src/vamana_example.cu) # `$` is a generator expression that ensures that targets are # installed in a conda environment, if one exists @@ -49,3 +50,4 @@ target_link_libraries( ) target_link_libraries(IVF_PQ_EXAMPLE PRIVATE cuvs::cuvs $) target_link_libraries(IVF_FLAT_EXAMPLE PRIVATE cuvs::cuvs $) +target_link_libraries(VAMANA_EXAMPLE PRIVATE cuvs::cuvs $) diff --git a/examples/cpp/src/common.cuh b/examples/cpp/src/common.cuh index aade6d4af..1c93dec0e 100644 --- a/examples/cpp/src/common.cuh +++ b/examples/cpp/src/common.cuh @@ -98,3 +98,29 @@ subsample(raft::device_resources const &dev_resources, return trainset; } + +template +raft::device_matrix read_bin_dataset(raft::device_resources const &dev_resources, + std::string fname, + int max_N = INT_MAX) { + + // Read datafile in + std::ifstream datafile(fname, std::ifstream::binary); + uint32_t N; + uint32_t dim; + datafile.read((char*)&N, sizeof(uint32_t)); + datafile.read((char*)&dim, sizeof(uint32_t)); + + if(N > max_N) N = max_N; + printf("Read in file - N:%u, dim:%u\n", N, dim); + std::vector data; + data.resize((size_t)N*(size_t)dim); + datafile.read(reinterpret_cast(data.data()), (size_t)N*(size_t)dim*sizeof(T)); + datafile.close(); + + auto dataset = raft::make_device_matrix(dev_resources, N, dim); + raft::copy(dataset.data_handle(), data.data(), data.size(), raft::resource::get_cuda_stream(dev_resources)); + + return dataset; +} + diff --git a/examples/cpp/src/vamana_example.cu b/examples/cpp/src/vamana_example.cu new file mode 100644 index 000000000..60bf14d56 --- /dev/null +++ b/examples/cpp/src/vamana_example.cu @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2024, NVIDIA CORPORATION. + * + * 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 + * + * http://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 +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "common.cuh" + +template +void vamana_build_and_write(raft::device_resources const &dev_resources, + raft::device_matrix_view dataset, + std::string out_fname, int degree, int visited_size, + float max_fraction, int iters) { + using namespace cuvs::neighbors::experimental; + + // use default index parameters + vamana::index_params index_params; + index_params.max_fraction = max_fraction; + index_params.visited_size = visited_size; + index_params.graph_degree = degree; + index_params.vamana_iters = iters; + + std::cout << "Building Vamana index (search graph)" << std::endl; + + auto start = std::chrono::system_clock::now(); + auto index = vamana::build(dev_resources, index_params, dataset); + auto end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + + std::cout << "Vamana index has " << index.size() << " vectors" << std::endl; + std::cout << "Vamana graph has degree " << index.graph_degree() + << ", graph size [" << index.graph().extent(0) << ", " + << index.graph().extent(1) << "]" << std::endl; + + std::cout << "Time to build index: " << elapsed_seconds.count() << "s\n"; + + // Output index to file + serialize(dev_resources, out_fname, index); +} + +void usage() { + printf("Usage: ./vamana_example \n"); + printf("Input file expected to be binary file of fp32 vectors.\n"); + printf("Graph degree sizes supported: 32, 64, 128, 256\n"); + printf("Visited_size must be > degree and a power of 2.\n"); + printf("max_fraction > 0 and <= 1. Typical values are 0.06 or 0.1.\n"); + printf("Default iterations = 1, increase for better quality graph.\n"); + exit(1); +} + +int main(int argc, char *argv[]) { + raft::device_resources dev_resources; + + // Set pool memory resource with 1 GiB initial pool size. All allocations use + // the same pool. + rmm::mr::pool_memory_resource pool_mr( + rmm::mr::get_current_device_resource(), 1024 * 1024 * 1024ull); + rmm::mr::set_current_device_resource(&pool_mr); + + // Alternatively, one could define a pool allocator for temporary arrays (used + // within RAFT algorithms). In that case only the internal arrays would use + // the pool, any other allocation uses the default RMM memory resource. Here + // is how to change the workspace memory resource to a pool with 2 GiB upper + // limit. raft::resource::set_workspace_to_pool_resource(dev_resources, 2 * + // 1024 * 1024 * 1024ull); + + if (argc != 7) + usage(); + + std::string data_fname = (std::string)(argv[1]); // Input filename + std::string out_fname = (std::string)argv[2]; // Output index filename + int degree = atoi(argv[3]); + int max_visited = atoi(argv[4]); + float max_fraction = atof(argv[5]); + int iters = atoi(argv[6]); + + // Read in binary dataset file + auto dataset = + read_bin_dataset(dev_resources, data_fname, INT_MAX); + + // Simple build example to create graph and write to a file + vamana_build_and_write( + dev_resources, raft::make_const_mdspan(dataset.view()), out_fname, degree, + max_visited, max_fraction, iters); +} diff --git a/notebooks/cuvs_hpo_example.ipynb b/notebooks/cuvs_hpo_example.ipynb new file mode 100644 index 000000000..d8b11a82c --- /dev/null +++ b/notebooks/cuvs_hpo_example.ipynb @@ -0,0 +1,7181 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "6c47d37e-fd75-4604-a787-ccccf392e9d3", + "metadata": {}, + "source": [ + "## Background \n", + "This notebook showcases how to leverage Optuna for hyperparameter tuning, specifically for the n_lists and n_probes parameters. We will demonstrate how to optimize these parameters using Optuna's Bayesian optimization capabilities. \n", + "\n", + "Note: This notebook has been tested on Sagemaker Studio with an instance type of ml.g5.12xlarge." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d35868b-93ad-43b4-ae15-59e75aa89e3c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#Install Required Packages\n", + "%mamba install -c conda-forge -c nvidia -c rapidsai-nightly cuvs optuna -y\n", + "%pip install cupy" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "9ebbb352-260c-4078-8589-e0538338a275", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import cupy as cp\n", + "import numpy as np\n", + "from cuvs.neighbors import ivf_flat\n", + "import urllib.request\n", + "import numpy as np\n", + "import time\n", + "import optuna\n", + "from utils import calc_recall\n", + "from optuna.visualization import plot_optimization_history\n", + "import math\n", + "import os\n" + ] + }, + { + "cell_type": "markdown", + "id": "933b9ab7-4c81-4124-9890-dbda75eb9fd9", + "metadata": {}, + "source": [ + "## Download wiki-all dataset\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "4f819371-019b-4378-8a47-389de1689c05", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import tarfile\n", + "home_dir = os.path.expanduser(\"~/\")\n", + "#wiki-all datasets are in tar format\n", + "def download_files(url, file):\n", + " if os.path.exists(home_dir + \"/\" + file):\n", + " print(\"tar file is already downloaded\")\n", + " else:\n", + " urllib.request.urlretrieve(url, home_dir + \"/\" + file)\n", + " # Open the .tar file\n", + " with tarfile.open(home_dir + \"/\" + file, 'r') as tar:\n", + " filename = file.split(\".\")[0]\n", + " if os.path.exists(home_dir + \"/\" + filename + \"/\"):\n", + " print(\"Files already extracted\")\n", + " return home_dir + \"/\" + filename + \"/\"\n", + " # Extract all contents into the specified directory\n", + " extract_path=home_dir + \"/\" +file.split(\".\")[0]\n", + " tar.extractall(extract_path)\n", + " return extract_path" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "26197a6e-f5c6-443f-9c1d-95105cc7038d", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tar file is already downloaded\n", + "Files already extracted\n" + ] + } + ], + "source": [ + "extracted_path=download_files('https://data.rapids.ai/raft/datasets/wiki_all_1M/wiki_all_1M.tar', 'wiki_all_1M.tar')" + ] + }, + { + "cell_type": "markdown", + "id": "1b0ead9f-417b-4305-8277-92ca34352ed1", + "metadata": {}, + "source": [ + "## Dataset Preparation: Load fbin, ibin files \n", + "This example utilizes the Wiki-1M dataset, a collection of four binary files containing: \n", + "\n", + "Database vectors: Used for index building and searching.\n", + "Query vectors: Used for index building and searching.\n", + "Ground truth neighbors: Associated with a particular distance, used for evaluation.\n", + "Distances: Associated with a particular distance, used for evaluation.\n", + "The file suffixes denote the data type of vectors stored in the file: \n", + "\n", + ".fbin: float32\n", + ".ibin: int\n", + "For more information on the Wiki-1M dataset, please refer to the [RAPIDS documentation](https://docs.rapids.ai/api/raft/nightly/ann_benchmarks_dataset)\n", + "." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "2c6a0772-bb7c-43b7-aecc-8864140b0353", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def read_data(file_path, dtype):\n", + " with open(file_path, \"rb\") as f:\n", + " rows,cols = np.fromfile(f, count=2, dtype= np.int32)\n", + " d = np.fromfile(f,count=rows*cols,dtype=dtype).reshape(rows, cols)\n", + " return cp.asarray(d)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "b46775d5-37c2-4be2-8c89-019ee5474f6b", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "vectors= read_data(extracted_path + \"/base.1M.fbin\",np.float32)\n", + "queries = read_data(extracted_path + \"/queries.fbin\",np.float32)\n", + "gt_neighbors = read_data(extracted_path + \"/groundtruth.1M.neighbors.ibin\",np.int32)" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "id": "fae0ab44-a9da-4443-817c-325364ff0ee7", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "#Get the dataset size of database vectors\n", + "dataset_size = vectors.shape[0]\n", + "dim = vectors.shape[1]" + ] + }, + { + "cell_type": "markdown", + "id": "d35b88c4-a005-4bef-90bd-da33fee63f8b", + "metadata": {}, + "source": [ + "## Visualization\n", + "\n", + "Generates and displays Pareto front plots for a given Optuna study object." + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "id": "d321bd84-b6f7-4bdb-889f-578a8512cd8c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def visualization(study_obj):\n", + " \"\"\"\n", + " This function creates two Pareto front plots to visualize trade-offs between different \n", + " optimization objectives. The plots help in understanding the balance between competing \n", + " objectives in the optimization process.\n", + "\n", + " Args:\n", + " study_obj (optuna.Study): The Optuna study object containing the optimization results.\n", + "\n", + " The function produces the following plots:\n", + " 1. **Figure 1**: A Pareto front plot showing the trade-off between `build_time_in_secs` \n", + " and `recall`. It visualizes how the optimization process balances the build time \n", + " and recall score.\n", + " 2. **Figure 2**: A Pareto front plot showing the trade-off between `latency_in_ms` \n", + " and `recall`. This plot illustrates the relationship between latency and recall score.\n", + " \n", + " \"\"\"\n", + " \n", + " fig1 = optuna.visualization.plot_pareto_front(\n", + " study_obj,\n", + " targets=lambda t: (t.values[0], t.values[2]),\n", + " target_names=[\"build_time_in_secs\", \"recall\"],\n", + " )\n", + " fig1.show()\n", + "\n", + " fig2 = optuna.visualization.plot_pareto_front(\n", + " study_obj,\n", + " targets=lambda t: (t.values[1], t.values[2]),\n", + " target_names=[\"latency_in_ms\", \"recall\"],\n", + " )\n", + " fig2.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "id": "449d2a28-4286-451f-89bc-10ce535aa134", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def print_target_instance_summary(target_instance):\n", + " print(f\"\\tnumber: {target_instance.number}\")\n", + " print(f\"\\tparams: {target_instance.params}\")\n", + " print(f\"\\tvalues: {target_instance.values}\")\n", + " \n", + "def print_best_trial_values(optuna_study):\n", + " \"\"\"\n", + " Prints details about the trials on the Pareto front of an Optuna study.\n", + "\n", + " This function analyzes the best trials from an Optuna study, which are typically \n", + " those with the most favorable trade-offs among multiple objectives. It prints \n", + " information on three specific metrics:\n", + "\n", + " 1. The number of trials on the Pareto front.\n", + " 2. The trial with the highest accuracy among the best trials.\n", + " 3. The trial with the lowest build time among the best trials.\n", + " 4. The trial with the lowest latency among the best trials.\n", + "\n", + " Parameters:\n", + " optuna_study (optuna.study.Study): An Optuna study object that contains information\n", + " about the trials and their respective metrics.\n", + "\n", + " The function assumes that each trial has three metrics recorded in the `values` list:\n", + " - `values[0]`: Build time\n", + " - `values[1]`: latency\n", + " - `values[2]`: Accuracy\n", + " \n", + " \"\"\"\n", + " print(f\"Number of trials on the Pareto front: {len(optuna_study.best_trials)}\")\n", + "\n", + " trial_with_lowest_build_time = min(optuna_study.best_trials, key=lambda t: t.values[0])\n", + " print(f\"Trial with lowest build time in secs: \")\n", + " print_target_instance_summary(trial_with_lowest_build_time)\n", + "\n", + " trial_with_lowest_latency = min(optuna_study.best_trials, key=lambda t: t.values[1])\n", + " print(f\"Trial with lowest latency in ms: \")\n", + " print_target_instance_summary(trial_with_lowest_latency)\n", + " \n", + " trial_with_highest_accuracy = max(optuna_study.best_trials, key=lambda t: t.values[2])\n", + " print(f\"Trial with highest accuracy: \")\n", + " print_target_instance_summary(trial_with_highest_accuracy)" + ] + }, + { + "cell_type": "markdown", + "id": "f08a88d8-b805-4ed3-8521-f9cb0c2bd28b", + "metadata": {}, + "source": [ + "## Hyperparameter Optimization (HPO) for CUVS Libraries\n", + "\n", + "An Optuna trial object used to suggest values for the hyperparameters of various CUVS libraries (such as ivf_flat, ivf_pq, and cagra).\n", + "\n", + "The multi-objective function returns a tuple of three float values, each rounded to four decimal places:\n", + "\n", + "build_time_in_secs: Time taken to build the index, measured in seconds.\n", + "latency_in_ms: Average search latency, measured in milliseconds. Calculated as the total search time divided by the number of queries.\n", + "recall: Recall metric, indicating the proportion of relevant neighbors retrieved.\n" + ] + }, + { + "cell_type": "markdown", + "id": "47c43a77-f3d0-4920-a45d-9c4566d5b01f", + "metadata": {}, + "source": [ + "## ivf_flat HPO example" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "id": "bfdde156-f624-495d-aa52-bc03e9113120", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def multi_objective_ivf_flat(trial):\n", + " \"\"\"\n", + " Optimizes the parameters for an Inverted File Index (IVF) Flat index in a multi-objective setting.\n", + "\n", + " \"\"\"\n", + " # Suggest an integer for the number of lists\n", + " n_lists = trial.suggest_int(\"n_lists\", 10, dataset_size*0.1)\n", + " # Suggest an integer for the number of probes\n", + " n_probes = trial.suggest_int(\"n_probes\",n_lists*0.01 , n_lists*0.1)\n", + " build_params = ivf_flat.IndexParams(\n", + " n_lists=n_lists,\n", + " )\n", + " start_build_time = time.time()\n", + " index = ivf_flat.build(build_params, vectors)\n", + " build_time_in_secs = time.time() - start_build_time\n", + "\n", + " # Configure search parameters\n", + " search_params = ivf_flat.SearchParams(n_probes=n_probes)\n", + " # Perform the search\n", + " start_search_time = time.time()\n", + " distances, indices = ivf_flat.search(search_params, index, queries, k=10)\n", + " search_time = time.time() - start_search_time\n", + " \n", + " latency_in_ms = (search_time * 1000)/queries.shape[0]\n", + " \n", + " found_distances, found_indices = cp.asnumpy(distances), cp.asnumpy(indices)\n", + " recall = calc_recall(found_indices, gt_neighbors)\n", + " return round(build_time_in_secs,4), round(latency_in_ms,4), round(recall,4)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "id": "23944214-d72f-486a-bb9c-22a6c8b9516e", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:24:19,149] A new study created in memory with name: no-name-ab0e88bd-1516-4eb2-a60d-01ae30ad08c4\n", + "[I 2024-08-19 16:24:51,762] Trial 0 finished with values: [23.1406, 0.3441, 0.9994] and parameters: {'n_lists': 48570, 'n_probes': 2511}. \n", + "[I 2024-08-19 16:25:28,379] Trial 1 finished with values: [24.232, 0.6336, 0.9999] and parameters: {'n_lists': 51021, 'n_probes': 4945}. \n", + "[I 2024-08-19 16:25:58,230] Trial 2 finished with values: [22.675, 0.1172, 0.9949] and parameters: {'n_lists': 47692, 'n_probes': 760}. \n", + "[I 2024-08-19 16:26:54,339] Trial 3 finished with values: [42.3469, 0.7272, 0.9997] and parameters: {'n_lists': 91882, 'n_probes': 6687}. \n", + "[I 2024-08-19 16:27:29,832] Trial 4 finished with values: [27.2722, 0.2141, 0.9985] and parameters: {'n_lists': 57879, 'n_probes': 1657}. \n", + "[I 2024-08-19 16:28:22,050] Trial 5 finished with values: [42.7912, 0.2936, 0.999] and parameters: {'n_lists': 92899, 'n_probes': 2804}. \n", + "[I 2024-08-19 16:28:54,048] Trial 6 finished with values: [24.9842, 0.0949, 0.9935] and parameters: {'n_lists': 52962, 'n_probes': 668}. \n", + "[I 2024-08-19 16:29:32,878] Trial 7 finished with values: [26.306, 0.6545, 0.9999] and parameters: {'n_lists': 55683, 'n_probes': 5439}. \n", + "[I 2024-08-19 16:30:02,789] Trial 8 finished with values: [20.7545, 0.3232, 0.9992] and parameters: {'n_lists': 43405, 'n_probes': 2093}. \n", + "[I 2024-08-19 16:30:31,208] Trial 9 finished with values: [17.2627, 0.5324, 0.9998] and parameters: {'n_lists': 35266, 'n_probes': 3028}. \n" + ] + } + ], + "source": [ + "ivf_flat_study = optuna.create_study(directions=['minimize', 'minimize', 'maximize'])\n", + "ivf_flat_study.optimize(multi_objective_ivf_flat, n_trials=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "id": "3c6c30d1-13e1-4f5f-99c2-6f2c6c1d389b", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of trials on the Pareto front: 8\n", + "Trial with lowest build time in secs: \n", + "\tnumber: 9\n", + "\tparams: {'n_lists': 35266, 'n_probes': 3028}\n", + "\tvalues: [17.2627, 0.5324, 0.9998]\n", + "Trial with lowest latency in ms: \n", + "\tnumber: 6\n", + "\tparams: {'n_lists': 52962, 'n_probes': 668}\n", + "\tvalues: [24.9842, 0.0949, 0.9935]\n", + "Trial with highest accuracy: \n", + "\tnumber: 1\n", + "\tparams: {'n_lists': 51021, 'n_probes': 4945}\n", + "\tvalues: [24.232, 0.6336, 0.9999]\n" + ] + } + ], + "source": [ + "print_best_trial_values(ivf_flat_study)" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "id": "1ed2ec62-0b0b-43e5-abbc-9bd7d06e5ebd", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{text}Trial", + "marker": { + "color": [ + 3, + 7 + ], + "colorbar": { + "title": { + "text": "Trial" + } + }, + "colorscale": [ + [ + 0, + "rgb(247,251,255)" + ], + [ + 0.125, + "rgb(222,235,247)" + ], + [ + 0.25, + "rgb(198,219,239)" + ], + [ + 0.375, + "rgb(158,202,225)" + ], + [ + 0.5, + "rgb(107,174,214)" + ], + [ + 0.625, + "rgb(66,146,198)" + ], + [ + 0.75, + "rgb(33,113,181)" + ], + [ + 0.875, + "rgb(8,81,156)" + ], + [ + 1, + "rgb(8,48,107)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [ + "{
\"number\": 3,
\"values\": [
42.3469,
0.7272,
0.9997
],
\"params\": {
\"n_lists\": 91882,
\"n_probes\": 6687
}
}", + "{
\"number\": 7,
\"values\": [
26.306,
0.6545,
0.9999
],
\"params\": {
\"n_lists\": 55683,
\"n_probes\": 5439
}
}" + ], + "type": "scatter", + "x": [ + 42.3469, + 26.306 + ], + "y": [ + 0.9997, + 0.9999 + ] + }, + { + "hovertemplate": "%{text}Best Trial", + "marker": { + "color": [ + 0, + 1, + 2, + 4, + 5, + 6, + 8, + 9 + ], + "colorbar": { + "title": { + "text": "Best Trial" + }, + "x": 1.1, + "xpad": 40, + "y": 0.5 + }, + "colorscale": [ + [ + 0, + "rgb(255,245,240)" + ], + [ + 0.125, + "rgb(254,224,210)" + ], + [ + 0.25, + "rgb(252,187,161)" + ], + [ + 0.375, + "rgb(252,146,114)" + ], + [ + 0.5, + "rgb(251,106,74)" + ], + [ + 0.625, + "rgb(239,59,44)" + ], + [ + 0.75, + "rgb(203,24,29)" + ], + [ + 0.875, + "rgb(165,15,21)" + ], + [ + 1, + "rgb(103,0,13)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [ + "{
\"number\": 0,
\"values\": [
23.1406,
0.3441,
0.9994
],
\"params\": {
\"n_lists\": 48570,
\"n_probes\": 2511
}
}", + "{
\"number\": 1,
\"values\": [
24.232,
0.6336,
0.9999
],
\"params\": {
\"n_lists\": 51021,
\"n_probes\": 4945
}
}", + "{
\"number\": 2,
\"values\": [
22.675,
0.1172,
0.9949
],
\"params\": {
\"n_lists\": 47692,
\"n_probes\": 760
}
}", + "{
\"number\": 4,
\"values\": [
27.2722,
0.2141,
0.9985
],
\"params\": {
\"n_lists\": 57879,
\"n_probes\": 1657
}
}", + "{
\"number\": 5,
\"values\": [
42.7912,
0.2936,
0.999
],
\"params\": {
\"n_lists\": 92899,
\"n_probes\": 2804
}
}", + "{
\"number\": 6,
\"values\": [
24.9842,
0.0949,
0.9935
],
\"params\": {
\"n_lists\": 52962,
\"n_probes\": 668
}
}", + "{
\"number\": 8,
\"values\": [
20.7545,
0.3232,
0.9992
],
\"params\": {
\"n_lists\": 43405,
\"n_probes\": 2093
}
}", + "{
\"number\": 9,
\"values\": [
17.2627,
0.5324,
0.9998
],
\"params\": {
\"n_lists\": 35266,
\"n_probes\": 3028
}
}" + ], + "type": "scatter", + "x": [ + 23.1406, + 24.232, + 22.675, + 27.2722, + 42.7912, + 24.9842, + 20.7545, + 17.2627 + ], + "y": [ + 0.9994, + 0.9999, + 0.9949, + 0.9985, + 0.999, + 0.9935, + 0.9992, + 0.9998 + ] + } + ], + "layout": { + "autosize": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Pareto-front Plot" + }, + "xaxis": { + "autorange": true, + "range": [ + 15.745768536042302, + 44.3081314639577 + ], + "title": { + "text": "build_time_in_secs" + }, + "type": "linear" + }, + "yaxis": { + "autorange": true, + "range": [ + 0.9929718446601943, + 1.0004281553398058 + ], + "title": { + "text": "recall" + }, + "type": "linear" + } + } + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA40AAAFoCAYAAADzQh4hAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQmcTtX/xz9jzJjFmBkzw9jGlrVkKdkjkjXSQvbSQrSRIlr4CckWRUKUiFASJYpItojsIfs+YxtjVrP8/+fOPM/s5t659547d+ZzX69e033uOed77vt7H7znnHuOS1JSUhJ4kAAJkAAJkAAJkAAJkAAJkAAJkEAWBFwojXwuSIAESIAESIAESIAESIAESIAEsiNAaeSzQQIkQAIkQAIkQAIkQAIkQAIkkC0BSiMfDhIgARIgARIgARIgARIgARIgAUojnwESIAESIAESIAESIAESIAESIAHtBDjSqJ0Za5AACZAACZAACZAACZAACZBAgSFAaSwwqeaNkgAJkAAJkAAJkAAJkAAJkIB2ApRG7cxYgwRIgARIgARIgARIgARIgAQKDAFKY4FJNW+UBEiABEiABEiABEiABEiABLQToDRqZ8YaJEACJEACJEACJEACJEACJFBgCFAaC0yqeaMkQAIkQAIkQAIkQAIkQAIkoJ0ApVE7M9YgARIgARIgARIgARIgARIggQJDgNJYYFLNGyUBEiABEiABEiABEiABEiAB7QQojdqZsQYJkAAJkAAJkAAJkAAJkAAJFBgClMYCk2reKAmQAAmQAAmQAAmQAAmQAAloJ0Bp1M6MNUiABEiABEiABEiABEiABEigwBCgNBaYVPNGSYAESIAESIAESIAESIAESEA7AUqjdmasQQIkQAIkQAIkQAIkQAIkQAIFhgClscCkmjdKAiRAAiRAAiRAAiRAAiRAAtoJUBq1M2MNEiABEiABEiABEiABEiABEigwBCiNBSbVvFESIAESIAESIAESIAESIAES0E6A0qidGWuQAAmQAAmQAAmQAAmQAAmQQIEhQGksMKnmjZIACZAACZAACZAACZAACZCAdgKURu3MWIMESIAESIAESIAESIAESIAECgwBSmOBSTVvlARIgARIgARIgARIgARIgAS0E6A0amfGGiRAAiRAAiRAAiRAAiRAAiRQYAhQGgtMqnmjJEACJEACJEACJEACJEACJKCdAKVROzPWIAESIAESIAESIAESIAESIIECQ4DSWGBSzRslARIgARIgARIgARIgARIgAe0EKI3ambEGCZAACZAACZAACZAACZAA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Ux1bZHsvQhpzypmonHF6qvhMLb875UA1ZBYkARIgARIgARIgARIgARJQCNhaGtXmUEwhPXshVJG40iUDFUnUc4h9HkOvXIe/rw8C/Isp0zozHmIk72LoVWXRHSFnaQ8hNaI/Af6+ynuEMg/RrzPnL6Nw4cIQwipWmNV7CKEW0ljU21NhYvahlt+dcmB2H9k+CZAACZAACZAACZAACeQXAgVCGvNLsngfJEACJEACJEACJEACJEACJCCbAKVRNnHGIwESIAESIAESIAESIAESIAEbEaA02ihZ7CoJkAAJkAAJkAAJkAAJkAAJyCZAaZRNnPFIgARIgARIgARIgARIgARIwEYEKI02Sha7SgIkQAIkQAIkQAIkQAIkQAKyCVAaZRNnPBIgARIgARIgARIgARIgARKwEQFKo42Sxa6SAAmQAAmQAAmQAAmQAAmQgGwClEbZxBmPBEiABEiABEiABEiABEiABGxEgNJoo2SxqyRAAiRAAiRAAiRAAiRAAiQgmwClUTZxxiMBEiABEiABEiABEiABEiABGxGgNNooWewqCZAACZAACZAACZAACZAACcgmQGmUTZzxSIAESIAESIAESIAESIAESMBGBCiNNkoWu0oCJEACJEACJEACJEACJEACsglQGmUTZzwSIAESIAESIAESIAESIAESsBEBSqONksWukgAJkAAJkAAJkAAJkAAJkIBsApRG2cQZjwRIgARIgARIgARIgARIgARsRIDSaKNksaskQAIkQAIkQAIkQAIkQAIkIJsApVE2ccYjARIgARIgARIgARIgARIgARsRoDTaKFnsKgmQAAmQAAmQAAmQAAmQAAnIJkBplE2c8UiABEiABEiABEiABEiABEjARgQojTZKFrtKAiRAAiRAAiRAAiRAAiRAArIJUBplE2c8EiABEiABEiABEiABEiABErARAUqjjZLFrpIACZAACZAACZAACZAACZCAbAKURtnEGY8ESIAESIAESIAESIAESIAEbESA0mijZLGrJEACJEACJEACJEACJEACJCCbAKVRNnHGIwESIAESIAESIAESIAESIAEbEaA02ihZ7CoJkAAJkAAJkAAJkAAJkAAJyCZAaZRNnPFIgARIgARIgARIgARIgARIwEYEKI02Sha7SgIkQAIkQAIkQAIkQAIkQAKyCVAaZRNnPBIgARIgARIgARIgARIgARKwEQFKo42Sxa6SAAmQAAmQAAmQAAmQAAmQgGwClEbZxBmPBEiABEiABEiABEiABEiABGxEgNJoo2SxqyRAAiRAAiRAAiRAAiRAAiQgmwClUTZxxiMBEiABEiABEiABEiABEiABGxGgNNooWewqCZAACZAACZAACZAACZAACcgmQGmUTZzxSIAESIAESIAESIAESIAESMBGBCiNNkoWu0oCJEACJEACJEACJEACJEACsglQGmUTZzwSIAESIAESIAESIAESIAESsBEBSqONksWukgAJkAAJkAAJkAAJkAAJkIBsApRG2cQZjwRIgARIgARIgARIgARIgARsRIDSaKNksaskQAIkQAIkQAIkQAIkQAIkIJsApVE2ccYjARIgARIgARIgARIgARIgARsRoDTaKFnsKgmQAAmQAAmQAAmQAAmQAAnIJkBplE2c8UiABEiABEiABEiABEiABEjARgQojTZKFrtKAiRAAiRAAiRAAiRAAiRAArIJUBplE2c8EiABEiABEiABEiABEiABErARAUqjjZLFrpIACZAACZAACZAACZAACZCAbAKURtnEGY8ESIAESIAESIAESIAESIAEbESA0mijZLGrJEACJEACJEACJEACJEACJCCbAKVRJ/ELV6N1tsDqagm4AAgO8MRFMleLzLJyQX4euBERi9sJSZb1gYFzJuDr7Yb4hCRExsTnXJglLCPg6e4KjyKuuB4RZ1kfGDhnAoUKuaCEbxFcuh6Tc2GWMJRA6QBPQ9tjYyRAApkJUBp1PhWURp0ANVSnNGqAZXFRSqPFCVAZntKoEpTFxSiNFidAZXhKo0pQJhSjNJoAlU2SQAYClEadjwSlUSdADdUpjRpgWVyU0mhxAlSGpzSqBGVxMUqjxQlQGZ7SqBKUCcUojSZAZZMkQGk09hmgNBrL806tURrlsdYbidKol6Cc+pRGOZz1RqE06iUopz6lUQ7nrKJQGq1jz8gFhwBHGnXmmtKoE6CG6pRGDbAsLkpptDgBKsNTGlWCsrgYpdHiBKgMT2lUCcqEYpRGE6CySRLIQIDSqPKRSEpKQkJiIgq7uqarQWlUCdCAYpRGAyBKaoLSKAm0zjCURp0AJVWnNEoCrTMMpVEnQB3VKY064LEqCagkQGlUCWrVuq2YOmcZNiybSmlUyczoYpRGo4ma1x6l0Ty2RrZMaTSS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SqPOgFk9CZAACeRGICEx2SIcX5/0dy4acSUmJcv3GuZ1idlX0zsolfRRzPwlp6TmGSrqs3ZWV0kfGEMCJEACJEACJKCOAKVRHS9GkwAJkAAJkAAJkAAJkAAJkIBLEaA0ulS6OVgSIAESIAESIAESIAESIAESUEeA0qiOF6NJgARIgARIgARIgARIgARIwKUIUBpdKt0cLAmQAAmQAAmQAAmQAAmQAAmoI0BpVMeL0SRAAiRAAiRAAiRAAiRAAiTgUgQojS6Vbg6WBEiABEiABEiABEiABEiABNQRoDSq48VoEiABEiABEiABEiABEiABEnApApRGl0o3B0sCJEACJEACJEACJEACJEAC6ghQGtXxYjQJkAAJkAAJkAAJkAAJkAAJuBQBSqNLpZuDJQESIAESIAESIAESIAESIAF1BCiN6ngxmgRIgARIgARIgARIgARIgARcigCl0aXSzcGSAAmQAAmQAAmQAAmQAAmQgDoClEZ1vBhNAiRAAiRAAiRAAiRAAiRAAi5FgNLoUunmYEmABEiABEiABEiABEiABEhAHQFKozpejCYBEiABEiABEiABEiABEiABlyJAaXSpdHOwJEACJEACJEACJEACJEACJKCOAKVRHS9GkwAJkAAJkAAJkAAJkAAJkIBLEaA0ulS6OVgSIAESIAESIAESIAESIAESUEeA0qiOF6NJgARIgARIgARIgARIgARIwKUIUBpdKt0cLAmQAAmQAAmQAAmQAAmQAAmoI0BpVMeL0SRAAiRAAiRAAiRAAiRAAiTgUgQojS6Vbg6WBEiABEiABEiABEiABEiABNQRoDSq48VoEiABEiABEiABEiABEiABEnApApRGl0o3B0sCJEACJEACJEACJEACJEAC6ghQGtXxYjQJkAAJkAAJkAAJkAAJkAAJuBQBSqNLpZuDJQESIAESIAESIAESIAESIAF1BCiN6ngxmgRIgARIgARIgARIgARIgARcigCl0aXSzcGSAAmQAAmQAAmQAAmQAAmQgDoClEZ1vBhNAiRAAiRAAiRAAiRAAiRAAi5FgNLoUunmYEmABEiABEiABEiABEiABEhAHQFKozpejCYBEiABEiABEiABEiABEiABlyJAaXSpdHOwJEACJEACJEACJEACJEACJKCOAKVRHS9GkwAJkAAJkAAJkAAJkAAJkIBLEaA0ulS6OVgSIAESIAESIAESIAESIAESUEeA0qiOF6NJgARIgARIgARIgARIgARIwKUIUBpdKt0cLAmQAAmQAAmQAAmQAAmQAAmoI0BpVMeL0SRAAiRAAiRAAiRAAiRAAiTgUgT+H4huzZfMCUNAAAAAAElFTkSuQmCC", + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{text}Trial", + "marker": { + "color": [ + 3, + 7 + ], + "colorbar": { + "title": { + "text": "Trial" + } + }, + "colorscale": [ + [ + 0, + "rgb(247,251,255)" + ], + [ + 0.125, + "rgb(222,235,247)" + ], + [ + 0.25, + "rgb(198,219,239)" + ], + [ + 0.375, + "rgb(158,202,225)" + ], + [ + 0.5, + "rgb(107,174,214)" + ], + [ + 0.625, + "rgb(66,146,198)" + ], + [ + 0.75, + "rgb(33,113,181)" + ], + [ + 0.875, + "rgb(8,81,156)" + ], + [ + 1, + "rgb(8,48,107)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [ + "{
\"number\": 3,
\"values\": [
42.3469,
0.7272,
0.9997
],
\"params\": {
\"n_lists\": 91882,
\"n_probes\": 6687
}
}", + "{
\"number\": 7,
\"values\": [
26.306,
0.6545,
0.9999
],
\"params\": {
\"n_lists\": 55683,
\"n_probes\": 5439
}
}" + ], + "type": "scatter", + "x": [ + 0.7272, + 0.6545 + ], + "y": [ + 0.9997, + 0.9999 + ] + }, + { + "hovertemplate": "%{text}Best Trial", + "marker": { + "color": [ + 0, + 1, + 2, + 4, + 5, + 6, + 8, + 9 + ], + "colorbar": { + "title": { + "text": "Best Trial" + }, + "x": 1.1, + "xpad": 40, + "y": 0.5 + }, + "colorscale": [ + [ + 0, + "rgb(255,245,240)" + ], + [ + 0.125, + "rgb(254,224,210)" + ], + [ + 0.25, + "rgb(252,187,161)" + ], + [ + 0.375, + "rgb(252,146,114)" + ], + [ + 0.5, + "rgb(251,106,74)" + ], + [ + 0.625, + "rgb(239,59,44)" + ], + [ + 0.75, + "rgb(203,24,29)" + ], + [ + 0.875, + "rgb(165,15,21)" + ], + [ + 1, + "rgb(103,0,13)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [ + "{
\"number\": 0,
\"values\": [
23.1406,
0.3441,
0.9994
],
\"params\": {
\"n_lists\": 48570,
\"n_probes\": 2511
}
}", + "{
\"number\": 1,
\"values\": [
24.232,
0.6336,
0.9999
],
\"params\": {
\"n_lists\": 51021,
\"n_probes\": 4945
}
}", + "{
\"number\": 2,
\"values\": [
22.675,
0.1172,
0.9949
],
\"params\": {
\"n_lists\": 47692,
\"n_probes\": 760
}
}", + "{
\"number\": 4,
\"values\": [
27.2722,
0.2141,
0.9985
],
\"params\": {
\"n_lists\": 57879,
\"n_probes\": 1657
}
}", + "{
\"number\": 5,
\"values\": [
42.7912,
0.2936,
0.999
],
\"params\": {
\"n_lists\": 92899,
\"n_probes\": 2804
}
}", + "{
\"number\": 6,
\"values\": [
24.9842,
0.0949,
0.9935
],
\"params\": {
\"n_lists\": 52962,
\"n_probes\": 668
}
}", + "{
\"number\": 8,
\"values\": [
20.7545,
0.3232,
0.9992
],
\"params\": {
\"n_lists\": 43405,
\"n_probes\": 2093
}
}", + "{
\"number\": 9,
\"values\": [
17.2627,
0.5324,
0.9998
],
\"params\": {
\"n_lists\": 35266,
\"n_probes\": 3028
}
}" + ], + "type": "scatter", + "x": [ + 0.3441, + 0.6336, + 0.1172, + 0.2141, + 0.2936, + 0.0949, + 0.3232, + 0.5324 + ], + "y": [ + 0.9994, + 0.9999, + 0.9949, + 0.9985, + 0.999, + 0.9935, + 0.9992, + 0.9998 + ] + } + ], + "layout": { + "autosize": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Pareto-front Plot" + }, + "xaxis": { + "autorange": true, + "range": [ + 0.057328040634567215, + 0.7647719593654327 + ], + "title": { + "text": "latency_in_ms" + }, + "type": "linear" + }, + "yaxis": { + "autorange": true, + "range": [ + 0.9929718446601943, + 1.0004281553398058 + ], + "title": { + "text": "recall" + }, + "type": "linear" + } + } + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA40AAAFoCAYAAADzQh4hAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQd4FUXbhp+TAqmkh9BC7yKCUhVBkI4gFpBmQREEUUEUFFH4EBBpgoIoSBMEqSIognSkCVKkSe8tJCEhIb38/2yyJ52ck905ySbPXpdX2LM7szP3u4m5804xJScnJ4MHCZAACZAACZAACZAACZAACZAACWRDwERp5HtBAiRAAiRAAiRAAiRAAiRAAiSQEwFKI98NEiABEiABEiABEiABEiABEiCBHAlQGvlykAAJkAAJkAAJkAAJkAAJkAAJUBr5DpAACZAACZAACZAACZAACZAACVhPgJlG65mxBAmQAAmQAAmQAAmQAAmQAAkUGQKUxiITanaUBEiABEiABEiABEiABEiABKwnQGm0nhlLkAAJkAAJkAAJkAAJkAAJkECRIUBpLDKhZkdJgARIgARIgARIgARIgARIwHoClEbrmbEECZAACZAACZAACZAACZAACRQZApTGIhNqdpQESIAESIAESIAESIAESIAErCdAabSeGUuQAAmQAAmQAAmQAAmQAAmQQJEhQGksMqFmR0mABEiABEiABEiABEiABEjAegKURuuZsQQJkAAJkAAJkAAJkAAJkAAJFBkClMYiE2p2lARIgARIgARIgARIgARIgASsJ0BptJ4ZS5AACZAACZAACZAACZAACZBAkSFAaSwyoWZHSYAESIAESIAESIAESIAESMB6ApRG65mxBAmQAAmQAAmQAAmQAAmQAAkUGQKUxiITanaUBEiABEiABEiABEiABEiABKwnQGm0nhlLkAAJkAAJkAAJkAAJkAAJkECRIUBpLDKhZkdJgARIgARIgARIgARIgARIwHoClEbrmbEECZAACZAACZAACZAACZAACRQZApTGIhNqdpQESIAESIAESIAESIAESIAErCdAabSeGUuQAAmQAAmQAAmQAAmQAAmQQJEhQGksMqFmR0mABEiABEiABEiABEiABEjAegKURuuZsQQJkAAJkAAJkAAJkAAJkAAJFBkClMYiE2p2lARIgARIgARIgARIgARIgASsJ0BptJ4ZS5AACZAACZAACZAACZAACZBAkSFAaSwyoWZHSYAESIAESIAESIAESIAESMB6ApRG65mxBAmQAAmQAAmQAAmQAAmQAAkU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ucVMFM48PFV8Zim/B8XAYsi8kQRIgARIgARIgARIgARIQCFgaGm0NIZiCOnVG0GKxJUu6atIopZD7PMYFHwXXh7u8PEqoQzrzHyITN7NoBBl0R0hZ+kPITWiPT5eHso8Qlseol1Xrt+Gg4MDhLCKFWa1HkKohTS6uTorTGQflvJ7UAxkt5H1kwAJkAAJkAAJkAAJkEBhIVAkpLGwBIv9IAESIAESIAESIAESIAESIAFbE6A02po4n0cCJEACJEACJEACJEACJEACBiJAaTRQsNhUEiABEiABEiABEiABEiABErA1AUqjrYnzeSRAAiRAAiRAAiRAAiRAAiRgIAKURgMFi00lARIgARIgARIgARIgARIgAVsToDTamjifRwIkQAIkQAIkQAIkQAIkQAIGIkBpNFCw2FQSIAESIAESIAESIAESIAESsDUBSqOtifN5JEACJEACJEACJEACJEACJGAgApRGAwWLTSUBEiABEiABEiABEiABEiABWxOgNNqaOJ9HAiRAAiRAAiRAAiRAAiRAAgYiQGk0ULDYVBIgARIgARIgARIgARIgARKwNQFKo62J83kkQAIkQAIkQAIkQAIkQAIkYCAClEYDBYtNJQESIAESIAESIAESIAESIAFbE6A02po4n0cCJEACJEACJEACJEACJEACBiJAaTRQsNhUEiABEiABEiABEiABEiABErA1AUqjrYnzeSRAAiRAAiRAAiRAAiRAAiRgIAKURgMFi00lARIgARIgARIgARIgARIgAVsToDTamjifRwIkQAIkQAIkQAIkQAIkQAIGIkBpNFCw2FQSIAESIAESIAESIAESIAESsDUBSqOtifN5JEACJEACJEACJEACJEACJGAgApRGAwWLTSUBEiABEiABEiABEiABEiABWxOgNNqaOJ9HAiRAAiRAAiRAAiRAAiRAAgYiQGk0ULDYVBIgARIgARIgARIgARIgARKwNQFKo62J83kkQAIkQAIkQAIkQAIkQAIkYCAClEYDBYtNJQESIAESIAESIAESIAESIAFbE6A02po4n0cCJEACJEACJEACJEACJEACBiJAaTRQsNhUEiABEiABEiABEiABEiABErA1AUqjrYnzeSRAAiRAAiRAAiRAAiRAAiRgIAKURgMFi00lARIgARIgARIgARIgARIgAVsToDTamjifRwIkQAIkQAIk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", + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "visualization(ivf_flat_study)" + ] + }, + { + "cell_type": "markdown", + "id": "8cca41e4-b697-4a0e-98f8-f3b682bf552f", + "metadata": {}, + "source": [ + "## ivf_pq HPO example" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "id": "dc4f0458-52e8-4663-82d7-afa33d68f242", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from cuvs.neighbors import ivf_pq,refine" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "id": "81c092df-fd11-472c-aa90-85b31f66d494", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "def multi_objective_ivf_pq(trial):\n", + " \"\"\"\n", + " Optimizes hyperparameters for Inverted File Product Quantization (IVF-PQ) in a multi-objective setting..\n", + "\n", + " \"\"\"\n", + " # Suggest values for build parameters\n", + " pq_dim = trial.suggest_int(\"pq_dim\", dim*0.25, dim, step=2)\n", + " n_lists = 1000\n", + "\n", + " # Suggest an integer for the number of probes\n", + " n_probes = trial.suggest_int(\"n_probes\",n_lists*0.01 , n_lists*0.1)\n", + "\n", + " build_params = ivf_pq.IndexParams(\n", + " n_lists=n_lists,\n", + " pq_dim=pq_dim,\n", + " )\n", + "\n", + " start_build_time = time.time()\n", + " index = ivf_pq.build(build_params, vectors)\n", + " build_time_in_secs = time.time() - start_build_time\n", + "\n", + " # Configure search parameters\n", + " search_params = ivf_pq.SearchParams(n_probes=n_probes)\n", + "\n", + " # perform search and refine to increase recall/accuracy\n", + " start_search_time = time.time()\n", + " distances, indices = ivf_pq.search(search_params, index, queries, k=10)\n", + " search_time = time.time() - start_search_time\n", + "\n", + " latency_in_ms = (search_time * 1000)/queries.shape[0]\n", + "\n", + " found_distances, found_indices = cp.asnumpy(distances), cp.asnumpy(indices)\n", + " recall = calc_recall(found_indices, gt_neighbors)\n", + "\n", + " return round(build_time_in_secs,4), round(latency_in_ms, 4), round(recall,4)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "6d805aee-d93c-4423-84f7-0c0a38f036fe", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:41:17,476] A new study created in memory with name: no-name-f823ce34-eccc-4c5a-a90d-1963f50a3a89\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 662\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:41:39,686] Trial 0 finished with values: [9.7626, 0.6995, 0.9562] and parameters: {'pq_dim': 662, 'n_probes': 79}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 210\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:41:51,544] Trial 1 finished with values: [4.9705, 0.1443, 0.8414] and parameters: {'pq_dim': 210, 'n_probes': 57}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 678\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:42:15,891] Trial 2 finished with values: [10.0147, 0.8856, 0.9581] and parameters: {'pq_dim': 678, 'n_probes': 98}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 432\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:42:34,553] Trial 3 finished with values: [9.3991, 0.3831, 0.9497] and parameters: {'pq_dim': 432, 'n_probes': 70}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 410\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:42:52,606] Trial 4 finished with values: [9.018, 0.3598, 0.9471] and parameters: {'pq_dim': 410, 'n_probes': 69}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 242\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:43:04,224] Trial 5 finished with values: [4.2757, 0.1919, 0.8495] and parameters: {'pq_dim': 242, 'n_probes': 66}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 688\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:43:24,543] Trial 6 finished with values: [10.1002, 0.4773, 0.9518] and parameters: {'pq_dim': 688, 'n_probes': 50}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 388\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:43:42,703] Trial 7 finished with values: [8.6237, 0.411, 0.9475] and parameters: {'pq_dim': 388, 'n_probes': 85}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 286\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:43:57,057] Trial 8 finished with values: [6.0929, 0.2856, 0.8991] and parameters: {'pq_dim': 286, 'n_probes': 79}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 284\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:44:09,228] Trial 9 finished with values: [6.0429, 0.0726, 0.8775] and parameters: {'pq_dim': 284, 'n_probes': 19}. \n" + ] + } + ], + "source": [ + "ivf_pq_study = optuna.create_study(directions=['minimize', 'minimize', 'maximize'])\n", + "ivf_pq_study.optimize(multi_objective_ivf_pq, n_trials=10)" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "id": "b7479455-9859-4e17-94df-19834360a0e5", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of trials on the Pareto front: 10\n", + "Trial with lowest build time in secs: \n", + "\tnumber: 5\n", + "\tparams: {'pq_dim': 242, 'n_probes': 66}\n", + "\tvalues: [4.2757, 0.1919, 0.8495]\n", + "Trial with lowest latency in ms: \n", + "\tnumber: 9\n", + "\tparams: {'pq_dim': 284, 'n_probes': 19}\n", + "\tvalues: [6.0429, 0.0726, 0.8775]\n", + "Trial with highest accuracy: \n", + "\tnumber: 2\n", + "\tparams: {'pq_dim': 678, 'n_probes': 98}\n", + "\tvalues: [10.0147, 0.8856, 0.9581]\n" + ] + } + ], + "source": [ + "print_best_trial_values(ivf_pq_study)" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "15ce945b-0c46-4f55-bcbb-3b836c80db2c", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{text}Trial", + "marker": { + "color": [], + "colorbar": { + "title": { + "text": "Trial" + } + }, + "colorscale": [ + [ + 0, + "rgb(247,251,255)" + ], + [ + 0.125, + "rgb(222,235,247)" + ], + [ + 0.25, + "rgb(198,219,239)" + ], + [ + 0.375, + "rgb(158,202,225)" + ], + [ + 0.5, + "rgb(107,174,214)" + ], + [ + 0.625, + "rgb(66,146,198)" + ], + [ + 0.75, + "rgb(33,113,181)" + ], + [ + 0.875, + "rgb(8,81,156)" + ], + [ + 1, + "rgb(8,48,107)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [], + "type": "scatter", + "x": [], + "y": [] + }, + { + "hovertemplate": "%{text}Best Trial", + "marker": { + "color": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "colorbar": { + "title": { + "text": "Best Trial" + }, + "x": 1.1, + "xpad": 40, + "y": 0.5 + }, + "colorscale": [ + [ + 0, + "rgb(255,245,240)" + ], + [ + 0.125, + "rgb(254,224,210)" + ], + [ + 0.25, + "rgb(252,187,161)" + ], + [ + 0.375, + "rgb(252,146,114)" + ], + [ + 0.5, + "rgb(251,106,74)" + ], + [ + 0.625, + "rgb(239,59,44)" + ], + [ + 0.75, + "rgb(203,24,29)" + ], + [ + 0.875, + "rgb(165,15,21)" + ], + [ + 1, + "rgb(103,0,13)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [ + "{
\"number\": 0,
\"values\": [
9.7626,
0.6995,
0.9562
],
\"params\": {
\"pq_dim\": 662,
\"n_probes\": 79
}
}", + "{
\"number\": 1,
\"values\": [
4.9705,
0.1443,
0.8414
],
\"params\": {
\"pq_dim\": 210,
\"n_probes\": 57
}
}", + "{
\"number\": 2,
\"values\": [
10.0147,
0.8856,
0.9581
],
\"params\": {
\"pq_dim\": 678,
\"n_probes\": 98
}
}", + "{
\"number\": 3,
\"values\": [
9.3991,
0.3831,
0.9497
],
\"params\": {
\"pq_dim\": 432,
\"n_probes\": 70
}
}", + "{
\"number\": 4,
\"values\": [
9.018,
0.3598,
0.9471
],
\"params\": {
\"pq_dim\": 410,
\"n_probes\": 69
}
}", + "{
\"number\": 5,
\"values\": [
4.2757,
0.1919,
0.8495
],
\"params\": {
\"pq_dim\": 242,
\"n_probes\": 66
}
}", + "{
\"number\": 6,
\"values\": [
10.1002,
0.4773,
0.9518
],
\"params\": {
\"pq_dim\": 688,
\"n_probes\": 50
}
}", + "{
\"number\": 7,
\"values\": [
8.6237,
0.411,
0.9475
],
\"params\": {
\"pq_dim\": 388,
\"n_probes\": 85
}
}", + "{
\"number\": 8,
\"values\": [
6.0929,
0.2856,
0.8991
],
\"params\": {
\"pq_dim\": 286,
\"n_probes\": 79
}
}", + "{
\"number\": 9,
\"values\": [
6.0429,
0.0726,
0.8775
],
\"params\": {
\"pq_dim\": 284,
\"n_probes\": 19
}
}" + ], + "type": "scatter", + "x": [ + 9.7626, + 4.9705, + 10.0147, + 9.3991, + 9.018, + 4.2757, + 10.1002, + 8.6237, + 6.0929, + 6.0429 + ], + "y": [ + 0.9562, + 0.8414, + 0.9581, + 0.9497, + 0.9471, + 0.8495, + 0.9518, + 0.9475, + 0.8991, + 0.8775 + ] + } + ], + "layout": { + "autosize": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Pareto-front Plot" + }, + "xaxis": { + "autorange": true, + "range": [ + 3.929601822989145, + 10.446298177010853 + ], + "title": { + "text": "build_time_in_secs" + }, + "type": "linear" + }, + "yaxis": { + "autorange": true, + "range": [ + 0.8317694174757282, + 0.9677305825242718 + ], + "title": { + "text": "recall" + }, + "type": "linear" + } + } + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA40AAAFoCAYAAADzQh4hAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQmcjdX/xz939pUZxr7vSkKl0ioqKSV+Rdb2kqKIlFKklD2KlFZGSkqiRJESkiKEhGTf1xkzY9b//5xxr5kxY+6d556ve5/5PK9Xr+nO85zzfc77ezDvOZsjKysrC7xIgARIgARIgARIgARIgARIgARIIB8CDkoj+wUJkAAJkAAJkAAJkAAJkAAJkEBBBCiN7BskQAIkQAIkQAIkQAIkQAIkQAIFEqA0snOQAAmQAAmQAAmQAAmQAAmQAAlQGtkHSIAESIAESIAESIAESIAESIAEPCfAkUbPmbEECZAACZAACZAACZAACZAACRQbApTGYpNqNpQESIAESIAESIAESIAESIAEPCdAafScGUuQAAmQAAmQAAmQAAmQAAmQQLEhQGksNqlmQ0mABEiABEiABEiABEiABEjAcwKURs+ZsQQJkAAJkAAJkAAJkAAJkAAJFBsClMZik2o2lARIgARIgARIgARIgARIgAQ8J0Bp9JwZS5AACZAACZAACZAACZAACZBAsSFAaSw2qWZDSYAESIAESIAESIAESIAESMBzApRGz5mxBAmQAAmQAAmQAAmQAAmQAAkUGwKUxmKTajaUBEiABEiABEiABEiABEiABDwnQGn0nBlLkAAJkAAJkAAJkAAJkAAJkECxIUBpLDapZkNJgARIgARIgARIgARIgARIwHMClEbPmbEECZAACZAACZAACZAACZAACRQbApTGYpNqNpQESIAESIAESIAESIAESIAEPCdAafScGUuQAAmQAAmQAAmQAAmQAAmQQLEhQGksNqlmQ0mABEiABEiABEiABEiABEjAcwKURs+ZsQQJkAAJkAAJkAAJkAAJkAAJFBsClMZik2o2lARIgARIgARIgARIgARIgAQ8J0Bp9JwZS5AACZAACZAACZAACZAACZBAsSFAaSw2qWZDSYAESIAESIAESIAESIAESMBzApRGz5mxBAmQAAmQAAmQAAmQAAmQAAkUGwKUxmKTajaUBEiABEiABEiABEiABEiABDwnQGn0nBlLkAAJkAAJkAAJkAAJkAAJkECxIUBpLDapZkNJgARIgARIgARIgARIgARIwHMClEbPmbEECZAACZAACZAACZAACZAACRQb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p7MXaQFW1+B+9+HuNs0LbIuSxsJypgrnnZ6qvucuv3PlwG3IfJAESIAESIAESIAESIAESEAT8GtpdDeHagrpzj0HtMRVLBenJdHKpc55PHDoKGJLRqN0bAk9rTPvpUby9h44rDfdUXKW81JSo96ndGxJvY5Q8lLvtWP3fgQFBUEJq9ph1uqlhFpJY1RkuGZi+nKX37lyYPodWT8JkAAJkAAJkAAJkAAJ2IVAsZBGuySL7SABEiABEiABEiABEiABEiABaQKURmnijEcCJEACJEACJEACJEACJEACfkSA0uhHyeKrkgAJkAAJkAAJkAAJkAAJkIA0AUqjNHHGIwESIAESIAESIAESIAESIAE/IkBp9KNk8VVJgARIgARIgARIgARIgARIQJoApVGaOOORAAmQAAmQAAmQAAmQAAmQgB8RoDT6UbL4qiRAAiRAAiRAAiRAAiRAAiQgTYDSKE2c8UiABEiABEiABEiABEiABEjAjwhQGv0oWXxVEiABEiABEiABEiABEiABEpAmQGmUJs54JEACJEACJEACJEACJEACJOBHBCiNfpQsvioJkAAJkAAJkAAJkAAJkAAJSBOgNEoTZzwSIAESIAESIAESIAESIAES8CMClEY/ShZflQRIgARIgARIgARIgARIgASkCVAapYkzHgmQAAmQAAmQAAmQAAmQAAn4EQFKox8li69KAiRAAiRAAiRAAiRAAiRAAtIEKI3SxBmPBEiABEiABEiABEiABEiABPyIAKXRj5LFVyUBEiABEiABEiABEiABEiABaQKURmnijEcCJEACJEACJEACJEACJEACfkSA0uhHyeKrkgAJkAAJkAAJkAAJkAAJkIA0AUqjNHHGIwESIAESIAESIAESIAESIAE/IkBp9KNk8VVJgARIgARIgARIgARIgARIQJoApVGaOOORAAmQAAmQAAmQAAmQAAmQgB8RoDT6UbL4qiRAAiRAAiRAAiRAAiRAAiQgTYDSKE2c8UiABEiABEiABEiABEiABEjAjwhQGv0oWXxVEiABEiABEiABEiABEiABEpAmQGmUJs54JEACJEACJEACJEACJEACJOBHBCiNfpQsvioJkAAJkAAJkAAJkAAJkAAJSBOgNEoTZzwSIAESIAESIAESIAESIAES8CMClEY/ShZflQRIgARIgARIgARIgARIgASkCVAapYkzHgmQAAmQAAmQAAmQAAmQAAn4EQFKox8li69KAiRAAiRAAiRAAiRAAiRAAtIEKI3SxBmPBEiABEiABEiABEiABEiABPyIAKXRj5LFVyUBEiABEiABEiABEiABEiABaQKURmnijEcCJEACJEACJEACJEACJEACfkSA0uhHyeKrkgAJkAAJkAAJkAAJkAAJkIA0AUqjNHHGIwESIAESIAESIAESIAESIAE/IkBp9KNk8VVJgARIgARIgARIgARIgARIQJoApVGaOOORAAmQAAmQAAmQAAmQAAmQgB8RoDT6UbL4qiRAAiRAAiRAAiRAAiRAAiQgTYDSKE2c8UiABEiABEiABEiABEiABEjAjwhQGv0oWXxVEiABEiABEiABEiABEiABEpAmQGmUJs54JEACJEACJEACJEACJEACJOBHBCiNfpQsvioJkAAJkAAJkAAJkAAJkAAJSBOgNEoTZzwSIAESIAESIAESIAESIAES8CMClEY/ShZflQRIgARIgARIgARIgARIgASkCVAapYkzHgmQAAmQAAmQAAmQAAmQAAn4EQFKox8li69KAiRAAiRAAiRAAiRAAiRAAtIEKI3SxBmPBEiABEiABEiABEiABEiABPyIAKXRj5LFVyUBEiABEiABEiABEiABEiABaQKURovE9xxOPmcN5WLDcOj4KWRkZlmMxOLuEogrEYoTyWlITct0twifs0ggNioEKWkZSD6VYbEmFneXQHR4EOBwICEpzd0ifM4igYjQQIQEB+JYYqrFmljcXQIhQQEoERms/x3lJUMgMMCBuJKh2H80RSagF6JULB3uhVpYBQmQwLkIUBot9g9Ko0WABopTGg1ALaRKSqM8c0qjPHNKozxzSqM8c0qjPHNGJAF/IEBptJglSqNFgAaKUxoNQKU0ykMtJCKlUT4llEZ55pRGeeaURnnmjEgC/kCA0mgxS5RGiwANFKc0GoBKaZSHSmn0OeaURvmUUBrlmVMa5ZkzIgn4AwFKo8UsURotAjRQnNJoACqlUR4qpdHnmFMa5VNCaZRnTmmUZ86IJOAPBCiNFrNEabQI0EBxSqMBqJRGeaiURp9jTmmUTwmlUZ45pVGeOSOSgD8QoDRazBKl0SJAA8UpjQagUhrloVIafY45pVE+JZRGeeaURnnmjEgC/kCA0mgxS5RGiwANFKc0GoBKaZSHSmn0OeaURvmUUBrlmVMa5ZkzIgn4AwFKo8UsURotAjRQnNJoACqlUR4qpdHnmFMa5VNCaZRnTmmUZ86IJOAPBCiNFrNEabQI0EBxSqMBqJRGeaiURp9jTmmUTwmlUZ65ksasU8fw35Z/ERJZAjFlKiIsPFz+RTyIWLG0b7+fB03hoyTgswQojRZTQ2m0CNBAcUqjAaiURnmolEafY05plE8JpVGe+aZff0CZ1CMoHxWCEylp2HYyC1WatkRUTGn5l3EzIqXRTVB8jAQsEKA0WoCnilIaLQI0UJzSaAAqpVEeKqXR55hTGuVTQmk8N/OkpJOIiIj0WmKOHtwHbFyM+mVKuOo8mZqOtclhqHnlzV6L4+2KKI3eJsr6SOBsApRGi72C0mgRoIHilEYDUCmN8lApjT7HnNIonxJKY/7Md237GwlHD6NEiSicSstA2Sq1EBVV0nKCdqxfhdqndiA2PCRXXX8czUCpxi28KqiWXzZHBZRGb9L0Tl0JiUlY+effrsqCg4MQFRmOi+rVgPp/yeu31X8j8WRSgSEDAwNxfbNGZ93fsfsA/li7Cc2vaozYktGFvnLKqVTc32c4et7bFtdecXGhz/vbA5RGixmjNFoEaKA4pdEAVEqjPFRKo88xpzTKp4TSeDbzXf/+jZKhWahbqyYcDof+YXjlmr9Qrf6lltce7v9vE2L2rkXVmNyjl4v2pKBBy/byHcDNiJRGN0EJPrZx83bc9fBLZ0UsFRON90Y/g3q1qlh+m1Opabjk5ocx7LmH0bbV1QXW1+6BF/DPv7vOGW/94o/Ouv/Nwl/xzNBJ+Oydl7TsFnYlJZ9C09aP4vWBj+D2m68q7HG/u09ptJgySqNFgAaKUxoNQKU0ykOlNPocc0qjfEoojWcz3/DHEtx4zRW5bvy3cxeOpQWhbIWqlpKUnHQSO5bOxWXlIhARHKjr+ufgCZwoXQtVGjS1VLfJwpRGk3SLVrdTGt8d2Q9XN70ImZlZWPf3v+jccyjuvOUavPrsQ0WrOEcpNbJ3aatH8MqAB9Gu9bUF1peekYGsrOzbW7bt0jL75iu9ce2V2aOLDgcQFJjd33NeaWnpOJmUgqio8Hzv532e0mg5pfaugNLoe/mlNMrnJDYqBClpGUg+lSEfvJhGjA4P0v/SJSSlFVMC8s2mNMozpzTmZp50MhEJ+/5Fk4vq57px9NhxbN59CJVrXmA5SUnHD+Pw5tUITE3B0ZQ0lChXBVUaXGa5XpMVUBpN0i1a3Xml0VlLi7v76KmbQ/rd76p4yYp1eGfq11j912ZUrlAGbW+5Bg93aYPgoECkpqZh0tSv8d2Pv+Hg4eOoULaUni7a99EOeHzgG1i87E9dpkzpGF3f5FH9ER6We3p1zhZs3rYLd97/Aia+1sc1JXXNhq0YOfFTDOl/P75d+CvU5xZXX4KG9Wtg+ITpGDvkcV3/8t/XY/Q7M7B9134kJaegbs3KuP+e1rjj5uxRTkpj0fpKsSlFafS9VFMa5XNCaZRnTmmUZ05plGdOaTyb+dYNf+DSC2sjIscxGBv+2QxElkNMqTjLSXKe0/jvrkOIjIyyXJ9EBZRGCcqexXBK47NPdEajC2sh5VQafly2GjPn/oQp45/DBXWq6QqXrFiLHgPG6OmcN157KdZu2Ir3p3+Lp3t0wAP33Iq3PpiFt6fMRv/H7kHlimWwacsOfDRjPlbOm4TP5y7G4FEf4baWV6JJwzq6vrvaNNeyWdCVnzQ630GVqVWtIi6oWw2NLqyNapXL4ZH+ozB/+kgtpvMX/4ZfV21E4wa1ERYagkVLV2Hu98sx9c3ncUnDOpRGz7pI8Xua0uh7Oac0yueE0ijPnNIoz5zSKM+c0ng288SEY9iz5S/UrFoJ0VFR2Lv/AA4cT0Ldht6ZPuqUxv1HUwpMeFZmJo4cOYjIqBIICzv/ZyRSGuX/bBYWsaA1jeXKxOKFp7qjxdVNdBVqvaEaxVPTWJ1X38ETsGXbbnz98TD0GDAaakOauVNeR0CAQz+SnJKqRxPdnZ6a813PJY2vDXzYNWqoyixd+VcuaXTWk5WVhRMJSTh87ARu7/4c+vXoqEccOdJYWK/w0ftq7vSBw0cRV6qkW/OQ1bzlQ0eOo0xcjFvPO5tNafS9DkBplM8JpVGeOaVRnjmlUZ45pTF/5mrt4bGjh5CanIQSsWUQU6q03hTHG1dh0rj754XYv3g+4rZuxomy5RFQvwHq3fcY1A6U5+uiNJ4v8gXHdUrjuKG9cOUlFyIjMxPHTyTqUcLPZi/CzMlDULt6JTS+6SGozXHKlSnlqsw5/VNtTjNjzmIMGf2RHulrcc0laNqoHq5v1hiBgQFel8YfZozR01+dV15pPHo8AaPe/gwLfvpdT091Xo/f307vmEpp9L1+WOgb/bR8Dfq9/LYroS89fR863N68wHIffPotRk+a4bqfc0HtwiWr0HvQ+LPKrlowGaEhwTynsdBsyD9AaZRnTmmUZ05plGdOaZRnTmmUZ34uaTyxfy92vfIs6m9Y63qxfaXL4FSXh1CjbQf5lz0dkdJ43tAXGLigNY3OHU+VaN17dytcfmsP3N2mOVpee0meuhy49oqG+nur1v2jp7X+umoD9h88qncy/XTSi1B1ubMRTs6KzzXSWJg0duo5FLv2HMCzvbro9Y5xpWLQqlM/dGp3I6XR97pg4W+khqyva9cbTzzQDl3a36gXyD456E3XfOS8NTjnMY8f2hvXX9UI8xauwLPD3sWcKa+hZtUK+GHJH3hu2GT9G5GcV9VKZfVv9TjSWHhOpJ+gNEoTByiN8swpjfLMKY3yzH1RGo/t34WkQ/sRXaEKokuVlYdiOOK5pPG/n35A5LhhKH38aK63WH3b/3Bp3xcMv1nB1VMazxt6j6Vxz75DuOmefq4pndfe2QtNG1+AMYN75qpLTQFVP2dnZGTqUUV1qe/N+PpHvDx2Cj5/dzDq1qqCRi0fxIt9uqNj2xZuQSiqNMaUiMIVtz2GPo/cjYc63+aKpd6f0ugWet97SI0y9nxuLFYvmIyQkGD9grd2HaAFskv7m856YbUrkjp8NKcU3nHvQNzV5np0v7uVlkY1LL7kqzfzbSyl0ff6AKVRPieURnnmlEZ55pRGeea+JI2pKSnYMn86yp86hLhgB/alAidiq6LmjXchICD7h1o7XOeSxn8XL0Ds2FdQMjEhV1PX3dYeFz35HAIDZQ9td74EpdH3ep5zpFGNKKpRObX+cO/+w5j25Q84ciwBsz4YqqecfjJrIV4dNxUPdrpVb4aTmpqOP9dvhvp5Xq1zfKDPcFzXrJE+tiMkOBgffjpPb4Dz48w3UDYuRq95TDyZguef7IrjCSdxWaN651xmVlRpVO+qjuoIDAjA0z06IiMjA198+zPmLVoBTk/1vf7n1hupuc8ffTYP38YPdz3f6/lxqF6lgt6JKe/1xuSZegtddXCn81LTUSuWi4Pa8UlJoxqpVIeGhoaG6M7YqnlTV4fceyT5nO9VNiYMh4+fQobzgBi3WsGHrBAoHR2KhOQ0pKZnWqmGZT0gEBOZfeRGSiqP3PAAm6VHo8Kyj9xITLZ25Ib6q8lLS6EstccfCoeHBCIkOBDHT6b6w+va4h1DAgMQHRmMwydOnff27F75Iyru+B3lQs6sHdyanIXUJq1Qus7F5/39vPUCgQ4HSpcMxYFjZ2+Ec3TPLhwc+ixqbVrvCnc8qgQO3/8Y6rS7x1uv4HE9FUqd/814PH5pmxfIbyMctQlO4wZ18Ph9bVGreiVNQI0kTvvye7z5waxc6wSVRKpjNdTyMbWMzHnfnQ9mAAAgAElEQVRd0rCu3nTGuZGO+hn+tTenYev2PfoRtatqRHhYgXSd0jhpeF999Ie6nLMOF34+BuVzrK1UdT/UbyQWfDoKlcrH6Y1xXh7zMXbtPajLtbmpmd49Vc1ufKx7W71Bz2W3PILXBz6iBdhulyNLjfXa6Hrvk2/0WS45Rw7V+saoiHAM7nffWS1VZ7Gog0bVsLZaqLtj9358POM73HZjMy2N6/7eprfYLRkdiT37D+th8c7tWuL5J7vpugqjp34Y04BtRdm3OwyZy+fHKR2F/XmQfzP7RvQW87SMTASfnvpjX1reaZm3mHvnbczUkpSUhN3r1yPpyBFUbtwYpcuVMxPI3VodgFI0dVZbcHD27KHzcakflX79/GNcnrJTv4/zOpkBbKnUGE1uvv18vJaZmKeZF/T3+ao5s5Gw8HvEbNqAk+UrIqFhYzR/vBdCQ0PNvI8btfIXX25A8vFH1J8xtSGl6nelY0u4pqSq107PyNBnNEZGhKFEVES+LTlw6BiioyLOeUajNxCo9/xv5z6Uii2h3aA4XbaTRk9HGlWy1W8Sps9eqLfPrV+7KqbOXIABj3fS01PzXl9++zMGjfgAaxa+r0cbOT3V9/64cHqqfE44PVWeOaenyjO3+/TUI1s3Y92ENxC1dh1CkpKRULUKotq2x8WdusrDPh0xKzUJ+5cvwMndO5CS5UCJyjVQ6epbEBAkPw3yn+9nomnyfwjLMRP1cFoWtla5AtUuu+68MfJ24MJ2T1Xx1O6tR48cQkRkNGJiz+w26e13cbc+Tk91lxSfI4GiE7CdNDrXNP75/XsIDs7+R6VVp/7ofvfN+a5pzItO7dDUrdcwvcD2wrrVzyK7ZMU6PX/6j/nv6oM9KY1F73ymSlIaTZEtuF5KozxzSqM8c7tL44rRryF26lQEpZ6Z8rz/4oa4cOJklCxVWh44gLWfTsCl+zYgFtnvtMMRhl21LkftNvIiu2fLekSu/g51w89MHVqVHIzw6+5CqXLZU+3scLkjjb7WTkqjr2WE72NHAraTRucZKWqksHM+u6eqTW/U5jejX+qJapWzp92oIe3YmGj8u30PXhzxgV5Y++arT+p7aoFuvVpVtEAeT0hE/5cnITgoEB+MHaDvUxp9748FpVE+J5RGeeaURnnmdpbGxIQT2PTic4idvyAX2MRSsYgaNQY1r7xGHPixwweR/ulIXJh2LFfsFSWqo2LnPggVPlReTUvb8ddKJO/agrKBGdiTHoi4ek1QvtYF4mxMBqQ0mqTLuknAfwnYThpVKhYtXQ21+Y3zeuGpbuh0Z0v98cdlq/HEwHH48v2hWgbV1fHRIfhr0za9cLZd62v0rkjqDEZ1jXlnBt6ffmYB7sUX1sLIQT30jk+URt/s+JRG+bxQGuWZUxrlmdtZGjMy0rF8yAuoOPOLXGAPV6mMKuPeQvn6DcSB7/17LcrOn4wKWbk3wdkSHIv0e/qhVOnsf4elL7VrYsLxo4gpFScdWiQepVEEM4OQgN8RsKU0qiyo3Zj2HTyCsqVjXNNUC8rOseOJSD6VivJlYvWZMHkvtU3wwcPHEB0ZgZiSUbluc6TR9/o8pVE+J5RGeeaURnnmdpZGRXPtp/FIe38yYndn70KYFh6Gvbe2xlWDhiIkRH6TE7Vu7uAno3FZ4q5cyf6x9AVo0K2PfAcoJhEpjcUk0WwmCXhIwLbS6CGHIj9OaSwyOmMFKY3G0BZYMaVRnjmlUZ653aVRTb/cOHsmjmxYj9DERARUr4567e5GVJnzt4Pq9l8XInzNYlRMOYJTCMDOyDKIuPoOlL2gsXwHKCYRKY3FJNFsJgl4SIDS6CGwvI9TGi0CNFCc0mgAaiFVUhrlmVMa5ZnbXRqdRDMzM3EqJQXhEflvbS9JPiQoAKknj2L7xg0IDApBiSo1UaJkrOQrFLtYlMZil3I2mATcIkBpdAtTwQ9RGi0CNFCc0mgAKqVRHmohESmN8ikpLtIoT7bgiEoaS0QG49Dx3Osafekd7fYulEa7ZVS+PYsWLYL673xcLVq0gPqPl/cJUBotMqU0WgRooDil0QBUSqM8VEqjzzGnNMqnhNIoz5zSKM/cbhGnTJmCWSPHosT+I0BWFuBwQE1/1/uGGPycWL407uzfB927d7cbUp9oD6XRYhoojRYBGihOaTQAldIoD5XS6HPMKY3yKaE0yjOnNMozt1tEJY3zhryOuG27tCgqT8y+ssXR1OdDNSqi9UvPURoNdShKo0WwlEaLAA0UpzQagEpplIdKafQ55pRG+ZRQGuWZUxrlmdstopLG+S+/jrL/7XGNLDpHGLO/an/UI5C5v+/8XLT7B2pUQqsXn6U0GupQlEaLYCmNFgEaKE5pNACV0igPldLoc8wpjfIpoTTKM6c0yjO3W0Qljd+//DrK/bfntB9mwQFHtidqHzTzeW/1iriZ0misO1EaLaKlNFoEaKA4pdEAVEqjPFRKo88xpzTKp4TSKM+c0ijP3G4RlTT+8PLrqLg9+8xXLYzOEUaDn/fUqIgbB3Gk0VR/ojRaJEtptAjQQHFKowGolEZ5qJRGn2NOaZRPCaVRnjmlUZ653SIqaVw0dDgqb9/tGlvMMSc1R3PPjD164/6uahXQgtJorDtRGi2ipTRaBGigOKXRAFRKozxUSqPPMac0yqeE0ijPnNIoz9xuEZU0Lh46HFV37Ml/yWJBSxktfn9n9Ypo/sIArmk01KEojRbBUhotAjRQnNJoACqlUR4qpdHnmFMa5VNCaZRnTmmUZ263iEoaf35lOKqp6akFbnZj0RDzqXd71Qq4jtJorDtRGi2ipTRaBGigOKXRAFRKozxUSqPPMac0yqeE0ijPnNIoz9xuEZU0LnllOGru3JtjpPHMcRvZvuf9z/9Vq4hrnudIo6n+RGm0SJbSaBGggeKURgNQKY3yUCmNPsec0iifEkqjPHNKozxzu0VU0rj01eGotWNvjjWNzlY6z9vw/ud/q1bAVQVIY3pGBg4fOYFyZWLthlusPZRGi6gpjRYBGihOaTQAldIoD5XS6HPMKY3yKaE0yjOnNMozt1tEJY3LXx2BOrvUSGOO4zWcI4zO4ze8/Hlr1Qq4cuAzudY0Kll8bfw0LPhppcYcHRWBJ+5vj1tbXmE37MbbQ2m0iJjSaBGggeKURgNQKY3yUCmNPsec0iifEkqjPHNKozxzu0VU0rhi2AjU3alGGuWuf6pUwBV5pHHm3J8wfMJ0zJ8+EqViojFr3hIMGz8NP335BiLCw+RezgaRKI0Wk0hptAjQQHFKowGolEZ5qJRGn2NOaZRPCaVRnjmlUZ653SIqafxt2AhcsGsfgOxjNZxrGJ1tPfPZe/c3VamApnmkceJHX2H2/KX4+uNhCA0Jxo7d+9G6ywAs+HQUKpWPsxt6o+2hNFrES2m0CNBAcUqjAaiURnmolEafY05plE8JpVGeOaVRnrndIipp/OO1Ebhg577szVNzndZ4Zk1jVtbpzVW9dH9D5fK49Lnc01OVJHZ5/BXElSqJR7rejnk/rtAjjK8PfMRu2I23h9JoETGl0SJAA8UpjQagUhrloVIafY45pVE+JZRGeeaURnnmdouopHHVayNw0e79aptU17EbDkf2iGNBx3BYvb++cgU0ea5/rjWNySmpGPDqJCQln8K/2/dg/8GjGD+0N1pee4ndsBtvD6XRImJKo0WABopTGg1ApTTKQ6U0+hxzSqN8SiiN8swpjfLM7RZRSeOfr4/ExWp6qnNgUeDruorl0SiPNI5993Os2bAVH4wZoIV1yufzMWrSZ/jqw1dQp0Zlu6E32h5Ko0W8lEaLAA0UpzQagEpplIdKafQ55pRG+ZRQGuWZUxrlmdstopLGta+PROM9+3Ocx+g8l9Hc17WVyqPhs7lHGjs+OgSXXFwXAx7vpDFnZmahYYv78WKf7ujYtoXd0BttD6XRIl5Ko0WABopTGg1ApTTKQ6U0+hxzSqN8SiiN8swpjfLM7RZRSeNfp6VRDTA6L+faRlOfV1csh4vySOOQMR/jh59/x7QJg1ClYhl8//Mf6PPSW9wIpwidjtJYBGg5i1AaLQI0UJzSaAAqpVEeKqXR55hTGuVTQmmUZ05plGdut4hOabx07wHRkcbVlcqjwYB+udY0HjueiDcmz8Q3C3/VmKtVLof7OtyCNjc1sxt24+2hNFpETGm0CNBAcUqjAaiURnmolEafY05plE8JpVGeOaVRnrndIipp3DB8FC7ds1+0aX9ULIcL80ij8wXSMzJw6MhxlC9TSvSd7BSM0mgxm5RGiwANFKc0GoBKaZSHSmn0OeaURvmUUBrlmVMa5ZnbLaKSxo3DR+GyvQf07ql5d0U19fn3iuVwQQHSaDfG56M9lEaL1CmNFgEaKE5pNACV0igPldLoc8wpjfIpoTTKM6c0yjO3W0QljX8PH4Wmew+4Nk91tvHMKY3Z3/Hm55UVyqI+pdFYd6I0WkRLabQI0EBxSqMBqJRGeaiURp9jTmmUTwmlUZ45pVGeud0iKmncNHwUrth3UHRN48qK5VD3madzrWm0G9vz2R5Ko0X6lEaLAA0UpzQagEpplIdKafQ55pRG+ZRQGuWZUxrlmdstopLGf0aMxpVqeqrgtaJCWdShNBojTmm0iJbSaBGggeKURgNQKY3yUCmNPsec0iifEkqjPHNKozxzu0VU0rh5xGg023cQQPZBG1mn1zaqNY5wOPRaR/3Vi/eVNNamNBrrTpRGi2gpjRYBGihOaTQAldIoD5XS6HPMKY3yKaE0yjOnNMozt1tEJY1bRozGVUoavbloUYE6R33Ly5dBLUqjse5EabSIltJoEaCB4pRGA1ApjfJQKY0+x5zSKJ8SSqM8c0qjPHO7RVTSuHXEaFyz/5DomsZlFcqiZv++XNNoqENRGi2CpTRaBGigOKXRAFRKozxUSqPPMac0yqeE0ijPnNIoz9xuEZU0bhs5BlfvO+gaGDwzEfX0hFTnDFXXBFXnRNWi3/+lfBnUoDQa606URotoKY0WARooTmk0AJXSKA+V0uhzzCmN8imhNMozpzTKM7dbRKc0Xrf/4OkViznWNOZaw+gURe/cV9JYndJorDtRGi2ipTRaBGigOKXRAFRKozxUSqPPMac0yqeE0ijPnNIoz9xuEZU0bh85Bkoasze9cbbQuQmOmc8/l4tDNUqjse5EabSIltJoEaCB4pRGA1ApjfJQKY0+x5zSKJ8SSqM8c0qjPHO7RVTSuGPUGDTff/j0msYcI4rIgkPtpur8qndV9c79n8uVQZV+fbim0VCHojRaBEtptAjQQHFKowGolEZ5qJRGn2NOaZRPCaVRnjmlUZ653SIqadw5aiyau0YalRiqKajO0zacn88cv+GN+z+WjaM0GuxMlEaLcCmNFgEaKE5pNACV0igPldLoc8wpjfIpoTTKM6c0yjO3W0QljbtGjUWLA4fyrGnMu4bRu58Xl4tDJY40GutOlEaLaCmNFgEaKE5pNACV0igPldLoc8wpjfIpoTTKM6c0yjO3W0QljbtHj0XL/YfOrGnU26eeGVnMnpOaY42jF+4vKlMaFSmNxroTpdEiWkqjRYAGilMaDUClNMpDpTT6HHNKo3xKKI3yzCmN8sztFlFJ457RY3HjgcOiTVtYtjQqPM01jaagUxotkqU0WgRooDil0QBUSqM8VEqjzzGnNMqnhNIoz5zSKM/cbhGVNO4d8wZuOigrjT+UKY3yfZ/iRjiGOhSl0SJYSqNFgAaKUxoNQKU0ykOlNPocc0qjfEoojfLMKY3yzO0WUUnjvrFv4OZDR9Sc1NOb4KhzN/QcVGOfv48rjXJ9KI2m+hOl0SJZSqNFgAaKUxoNQKU0ykOlNPocc0qjfEoojfLMKY3yzO0WUUnj/jfGodVhNdKoRNF5OY/bOPPZm/cXlI5F2acojab6E6XRIllKo0WABopTGg1ApTTKQ6U0+hxzSqN8SiiN8swpjfLM7RZRSeOBcePQ+sjRM+cx5hhhzHVOY85zG/WxHHnOcfTg/vxSpVDmySc5PdVQh6I0WgRLabQI0EBxSqMBqJRGeaiURp9jTmmUTwmlUZ45pVGeud0iKmk8NH4cbjl69PSEVDWe6DgtkM5jNvJ+tX5/XmwM4npTGk31JyPS+M7UOVi7catb7zxyUA9EhIe59awvPkRp9L2sUBrlcxIbFYKUtAwkn8qQD15MI0aHB+mtzBOS0oopAflmUxrlmVMa5ZlTGuWZ2y2ilsY3x+O2Y8eyRdE1gnhaFPOOKHrp/ryYWJTu1bvAkcbMzCwcOHwUkeFhiI6KsBt24+0xIo3vxs/Buo3/uvXyw194lNLoFik+5C4BSqO7pLz3HKXReyzdrYnS6C4p7z1HafQeS3drojS6S8p7z1EavceyuNakpPHIW+Nx6/FjeVY05l3B6N3P35SMQaknzpbGhMQkvDo+HnMWLNMpadW8KcYMfry4pqfI7TYijUV+Gz8syJFG30sapVE+J5RGeeaURnnmlEZ55pRGeeaURnnmdouopXHCm7g94RiysvSkGJGv35SIQezjvXKNNKrRxQ6PDkZgQAAe6NQa117RCIknk1E2LsZu2I23h9JoETGl0SJAA8UpjQagFlIlpVGeOaVRnjmlUZ45pVGeOaVRnrndIippPDZRSeNx0abNiS6JmJ65pXHR0tXo9fw4fBs/HNUqlxN9H7sFMyKNfQdPwPzFK91itWzOBJSMjnTrWV98iNLoe1mhNMrnhNIoz5zSKM+c0ijPnNIoz5zSKM/cbhG1NL79JtqePOEaYtS7ouYYcjTxeU5UDEo+9kSukcbhE6Zj5tyfcMsNl2PLf7tRpnRJPNjpNjS6sJbdsBtvjxFp/HHZauzac9Ctl+9wxw0IDQl261lffIjS6HtZoTTK54TSKM+c0ijPnNIoz5zSKM+c0ijP3G4RlTSemPQW2p48fnpuqrOFzrmqZj7PjiyBEj1yS2PvQeOxactO3NfxFpSLi8V3P/6Gbxb+irlTXkONqhXsht5oe4xIo9E39rHKKY0+lhAAlEb5nFAa5ZlTGuWZUxrlmVMa5ZlTGuWZ2y2iksaEd97CnckJMosZT49gfhVREtGPPp5rpFFJY6XyZTDg8U4ac0ZGJpr/70k8du+d6Nyupd3QG22PmDSqRafJKafOakxcqZLZw9V+elEafS9xlEb5nFAa5ZlTGuWZUxrlmVMa5ZlTGuWZ2y2iksbEdyegXfKJM01TP+pn5Wipgc+zwkog6pHc0jh60gxs3rYTk4Y/7ZLGK9v0xOP334n7OtxiN/RG22NcGvcfPIreL4zHX5u25dsQrmk0mt9iWTmlUT7tlEZ55pRGeeaURnnmlEZ55pRGeeZ2i6ik8eTkCfjfqYTTu6Y6oNYw6vM39AzV7M9nljh65/6XYdGIfDi3NK7ZsBWdew7FuyP74fLG9fHV/F8weNRHmDl5CC6oU81u6I22x7g0DhnzMX74+Xc83KUN1GLUVwY8iNiS0RjzzgyUL1sKE17rg+CgQKONNFk5RxpN0i1a3ZTGonGzUorSaIVe0cpSGovGzUopSqMVekUrS2ksGjcrpSiNVuixrCKgpDHpvYlaGp1i6CRj8vMXodGIeKhnrumpKu6Hn87DqEmfuZKjXKRd62uZLA8JGJfGdg+8gDY3XYVu/7sJTW5+GF9/PAy1qlXET8vXoOdzY/Hbt5MQGRHm4Wv7zuOURt/JhfNNKI3yOaE0yjOnNMozpzTKM6c0yjOnNMozt1tEJY3J70/E3WmJ+ZzPmL2LasHnNxb9/hchUQh78GxpVHxTTqXi4OFjKF+2tF8PVp3PvmJcGlt16o8HO9+GDrc3R9PWPTBi0KO44aom2LX3INS9TyYO8uttbymN57P75h+b0iifE0qjPHNKozxzSqM8c0qjPHNKozxzu0VU0pjywdtaGnOcsnEOUTy9yapzc9Uifp0RFIWwBx47a6TRbnzPV3uMS2OnnkPRpEFtPPN4J6jzG48dT8TowT0xZ8EyPV31hxljUKFsKfH2p6am4ejxRJSNi3FrI57DR08gMCAAMSWjcr0rpVE8dYUGpDQWisjrD1AavY600AopjYUi8voDlEavIy20QkpjoYi8/gCl0etIi12FWho/fBsdM5KQhSw44Mj91bmmMe/3nZ+LeP/zwCiE3t+D0mioxxmXxvHvf4FNW3diwrCn4FyM6mxLq+ZNMWbw44aaln+1auHt21O+xoQPZ+kHSsVE461hTxU42rl73yH0fWmCayOfpo3rY/RLPVE6toQuT2kUTZ9bwSiNbmHy6kOURq/idKsySqNbmLz6EKXRqzjdqozS6BYmrz5EafQqzmJZmZLGUx9PQofMJNH2zwiIQOi9lEZT0I1LY94X37xtF379YwPq1aqKpo3ruTXK583Gr/5rM7o+8SqmvjkQDevXxPj3v8Q3C5fjh8/GICDg7KM/1A5L+w4expB+DyA0JBiPPjMatapXxLDnHqY0ejMxXqyL0uhFmG5WRWl0E5QXH6M0ehGmm1VRGt0E5cXHKI1ehOlmVZRGN0HxsQIJaGmc8g46Ivn0LqmOAs9rzN5F1Tv3ZzgiENL9UY40GuqbxqVx4+btmLdoBe5q0xxVK5V1NePd+DkoUzpGfPcidV7Lxi3b8d6o/vpdDhw6hhvueirfrXdPJCahWZuemPhaH1zfrJF+ftEvq9BLHSHy44e6k3Ok0VDPtFAtpdECvCIWLUwaD+/aiYNb/kFc7TqIq1y1iFFYLCcBSqN8f6A0yjOnNMozpzTKM7dbRCWNqVPfRQdHcq6pqdkHNeaZqprjs9X7n2WFIaTbI5RGQx3KuDQ+//p72PDPf5g5+WUEBga4mvHJrIV4ddxU/P7duwgPCzHUvLOr7ffy24gtGYXnn+zmutmg+X25xNB5I/FkMq647TF9IOi1VzTU3/57yw7876EX8fOs8XqKKqVRLHVuB6I0uo3Kaw8WJI3p6en4ceSrSPj5Z4QcPIzUuNKIuu5a3ND/eQQHB3stfnGsiNIon3VKozxzSqM8c0qjPHO7RdTSGD8Z9wSeOrOW8fSIomuNo4HPM7LCENzlYUqjoQ5lXBrvuHcg7mh1NR7qfFuuJqhtb5v/7yl8+f5Q1KtVxVDzzq72kf6j9NTYp3t0cN1Uu7oO7ncfbmt55VkFHnt2LDZt3YFeD7RHcFAQFvy8EguXrHJJY3pG5jnfXYlyRob6zYr6j5cEAbVhUWZWVvZBsrxECKip3Qp3Xuar58zFHwMHIXTXHtd7pFYoh4Yvv4jL77pL5N3sGiRATecBdF+3cqVnAH58VK6VpntcVs0uUdgzM60x9zhwMS6gmKu+npF57n9rizEiA013IDDQgYxCfr4xELjIVQblGJQociUs6DUCWho/eU9LI3Ku/MoeaDxzefnzZ+mhCO78EKXRa5nMXZFxaez46BBcWK86Xup7b67If6z9B917D8OcKa+hZtUKhpp3drVqpFFtfjOwd1fXzYJGGtUDCYlJeO+Tb/QmPtGR4UhLT8eSFetc01MPHDt1znePKxGCo4mp8KO/e8VyYSpQbFQwElPSkZbOH+xMMc5bb8mIYJxKz0BKau4f7H56+02cGD0WAampriKZwUGIfOJx3PBUP/E1zVI8JOJEhgXqPcpPJqdLhGMMAOEhAfp8rxNJaeQhRCA4yIGo8CAcTSBzIeRQ/qVmjxw6cebvbanYRY1TNia0qEVZzgABLY3T30OnkDTXmkbn2kWTX7U03vMgpdFATlWVxqVRHasx5fP5+jzGi+rV0FNU1TrCF0e+jz/Wbsayr99CcHCQoeadXa1a06hGDt8d2U/fPNeaxvxe6oE+wxEZEYY3X31S3+b0VLHUuR2I01PdRuW1Bwuanrpiygc4NGoUghISXbEyIiMQ07cvrnrgEa/FL44VcXqqfNY5PVWeOaenyjPn9FR55naLqKQx7bMPcE+I+sWDGlo8c+yGyc/TU4MQ3JHSaKo/GZfG4ydOot2DL2D/waOICA9D5Qpx+OffXbo9rw98BLfffJWptuVb75ndU59HwwtqYtx7M/Htwl9du6d+NOM7Pf1U7a6qLrWuUU2PSc/IwNzvl2HY+Gn4dNJLaFi/BqVRNHPuB6M0us/KW08WJI27N23A788NQNjqNa5QKY0a4pLXR6BK/QbeCl8s66E0yqed0ijPnNIoz5zSKM/cbhG1NM74AJ3CsmfC6HMa1VIKvazitEDqz9kt99b9T08FI6jD/RxpNNShjEujeu+k5BR8NvtHrPt7G5JTTqF6lfJoc2MzNKhX3VCzCq5Wddq3PpyFSVO+1g8pkX135NNoclEd/XnkxE8xY85irJw3SX9euvIvqHWQ6qpVrSKG9L/f9az6HkcaxVNYaEBKY6GIvP5AQdKo/rxtXbEc//6yGEG79yKjUgVUu+p61L3qaq+/Q3GrkNIon3FKozxzSqM8c0qjPHO7RVTSmD7zQ3QKyzC6hvH0ZqwufNOTAhF0N6XRVH8SkUZTL2+l3pRTqThy9ATKly2d7/mMzrrVCOPe/Yf1TqlKMPNelEYrWTBTltJohuu5ai3syA0lj0ePHkZMTCkEBJzZRVn+Te0TkdIon0tKozxzSqM8c0qjPHO7RdTS+MVH6ByZKbqm8dOkQAT+7z6ONBrqUCLSuGL1RsyatwTbd+1Hj2536DMPR036DKVjSuD+e1obappMtZRGGc6eRKE0ekLLO88WJo3eicJachKgNMr3B0qjPHNKozxzSqM8c7tF1NL45cfoHKU2x8uekirxdXqiA4Ht76U0GupQxqVx/ab/0OHRwShXJhYJicl4sU93vY7ReU7jH/PfRVio3DmN3uZIafQ2Uev1URqtM/S0Bkqjp8SsP09ptM7Q0xoojZ4Ss/48pdE6Q09roDR6SozP5yWgpXHWFHQpoc7iUr6Yvabx9JJGY5+1NN7ZndJoqEsal8ZBIz7A8YREjAMB2m8AACAASURBVHu5Fx59ZjRuv+kqLY3bduxFm+7P4euPXkWt6pUMNc98tZRG84w9jUBp9JSY9ecpjdYZeloDpdFTYtafpzRaZ+hpDZRGT4lZf57SaJ1hca9BSWPG7KnoXMK1941GctofXQOPOfbG8cr9aSeAwLbdKI2GOqBxabz2zl7o88jdaH/rdXpDGac0HjmWAHVv5uQhuKBONUPNM18tpdE8Y08jUBo9JWb9eUqjdYae1kBp9JSY9ecpjdYZeloDpdFTYtafpzRaZ1jca9DS+PVUdI0NEF3T+MlxIOD2rpRGQx3QuDQ+1G+k3kRm+POP5pLGud8vx4BX38GvcyciOirCUPPMV0tpNM/Y0wiURk+JWX+e0midoac1UBo9JWb9eUqjdYae1kBp9JSY9ecpjdYZFvcalDRmzp2GLrGnz9TQQJxrG510vP952tEMBLShNJrqf8al8fuff8dTL76Fzu1aYsWqjWh+VWOUiimBkW9/ijtvuQavPvuQqbaJ1EtpFMHsURBKo0e4vPIwpdErGD2qhNLoES6vPExp9ApGjyqhNHqEyysPUxq9grFYV6Kl8Ztp6Fo6ENlTUM+saTT5+ZMjGXDc1oUjjYZ6n3FpVO+tzj1U5x+q8xqd120tr8TzT3VDyehIQ02TqZbSKMPZkyiURk9oeedZSqN3OHpSC6XRE1reeZbS6B2OntRCafSElneepTR6h2NxrkVL47efoGtckCiGaYfS4bi1M6XREHXj0rj89/U4kXgSN1zVBLv2HdLiWLl8GcSUjDLUJNlqKY2yvN2JRml0h5J3n6E0epenO7VRGt2h5N1nKI3e5elObZRGdyh59xlKo3d5FsfatDTOm46uZUNweqhRf3WOOOptVJ274OT4avW+lsZb7qE0Gup0xqWx7+AJSDyZjHdH9jPUhPNbLaXx/PLPLzqlUT4nlEZ55pRGeeaURnnmlEZ55pRGeeZ2i6ilcf5n2dIoeE07kApHq46URkPMjUvjxI9nY/Z3v2D+9JGGmnB+q6U0nl/+lEbf4E9plM8DpVGeOaVRnjmlUZ45pVGeud0iamlcMANdy4XqprlGEE831NTnaftPwXFzhwKl8afla9DzubGY+FofXN+skd2wG2+PcWk8dOQ4WncZgDGDe+LaKy423iDpAJRGaeKFx+NIY+GMvP0EpdHbRAuvj9JYOCNvP0Fp9DbRwuujNBbOyNtPUBq9TbT41ael8fvP0bV8WPZBjWoKqvMy+HnavhQ4bro7X2nctHUnuj7xql4mR2ksWp80Lo39Xn4b8xatKPDtls2Z4Neb4VAai9bxTJaiNJqkm3/dlEZ55pRGeeaURnnmlEZ55pRGeeZ2i6il8YeZ6FYxQvScxml7k+G48a6zpPHg4WPo2GMI+j7SAUPGfIxRLz7GkcYidDrj0rhwySrs3HOgwFfr1K4lQkOCi/DqvlGE0ugbecj5FpRG+ZxQGuWZUxrlmVMa5ZlTGuWZUxrlmdstopLGrIVfoEulMyckeP9URiDH+KU+BTJ+90k4Wv4vlzQmp6Tividf07Mdn3igHZq27kFpLGKHMy6NRXwvvylGafS9VFEa5XNCaZRnTmmUZ05plGdOaZRnTmmUZ263iHqkcdGX6FYlWnakUUnjDe1c0piZmQU141FdanQxIMBBabTQ2SiNFuCpopRGiwANFKc0GoBaSJWURnnmlEZ55pRGeeaURnnmlEZ55naLqEcaF3+FLpWjsjfBUZvhIHtkMNdX5zEcXrofvzMBjuZ3uqTxwKFjuOGup3BXm+sRGR6mMX/8+Xw0v6ox7rj5arRq3tRu6I22h9JoES+l0SJAA8UpjQagUhrloRYSkdIonxJKozxzSqM8c0qjPHO7RdQjjT/NRreqJQoWxoJE0cL3p+04Acf1bV3SqDa9if/i+1x4x733Bdrc1Axtbmxmyw06TfYlSqNFupRGiwANFKc0GoBKaZSHSmn0OeaURvmUUBrlmVMa5ZnbLaIeafz5a3SpVvLMyGKOXVPzHXn0wv34/47Bcd0d5zynkWsai97bKI1FZ6dLUhotAjRQnNJoACqlUR4qpdHnmFMa5VNCaZRnTmmUZ263iHqkcckcdKsRK7umcfsxOK65ndJoqENRGi2CpTRaBGigOKXRAFRKozxUSqPPMac0yqeE0ijPnNIoz9xuEfVI4y9z0bVmqVxNc44wFtReq/fjtx2B4+o255RGu7GWbA+l0SJtSqNFgAaKUxoNQKU0ykOlNPocc0qjfEoojfLMKY3yzO0WUY80Lv0G3WrHyY40/nsEjqtupTQa6lCURotgKY0WARooTmk0ANVDacw6vSOa/JsUn4jcCEc+15RGeeaURnnmlEZ55naLqEcal89D19px2U3LygLUmkXnZehz/JZDcDRrTWk01KEojRbBUhotAjRQnNJoAKqb0ngiMRkblv2CXRvXIygkFLWaXo5aFzXSW27z8i4BSqN3ebpTG6XRHUrefYbS6F2e7tRGaXSHEp85FwE90rh8HrrVLZvDE7Ny/SyQ95fL3vg8TUnjlbdQGg11T0qjRbCURosADRSnNBqA6qY0Th8xAhvf/xjpBw7BERKC8Lo1cc1TT+KKNm3lX8rmESmN8gmmNMozpzTKM6c0yjO3W0Q90rhiPrrmkEZXG3Pskppvuy3cj//nABxXtKI0GupQlEaLYCmNFgEaKE5pNADVDWnctWcv3rmrIxJXrcv1dLX7OqHbiNEICAiUfzEbR6Q0yieX0ijPnNIoz5zSKM/cbhG1NP62AF3rlz8zNdU5JdXg1/h/9sPR9GZKo6EORWm0CJbSaBGggeKURgNQ3ZDG33/5BZ91vg/pBw7nerpUs6bo8vFHiC11em2D/OvZMiKlUT6tlEZ55pRGeeaURnnmdouopXHlD+h6QfkcTVPLVPI7odH5iPX78X/vgeOymyiNhjoUpdEiWEqjRYAGilMaDUB1Qxr37NuPt9VI4+9rco803t8Z3UeM4bpGL6eF0uhloG5UR2l0A5KXH6E0ehmoG9VRGt2AxEfOSUBL4+8L0bVBxdOe6Dg94uj0RjOf4zfugePSlpRGQ/2T0mgRLKXRIkADxSmNBqC6IY0paRn4VK1pjJ+O9H0H4QgNRXidGriuVy9cdmsb+ZeyeURKo3yCKY3yzCmN8swpjfLM7RZRS+OqRejaoHLuplk9iLGQ8vHrd8FxSQtKo6EORWm0CJbSaBGggeKURgNQ3ZTGxJOn8Pfypdixfh2CQ8NQ+8pmqH5BA/kXKgYRKY3ySaY0yjOnNMozpzTKM7dbRC2Nq39E14ZVs0cYUcDUU9emN965H//XLjiaNKc0GupQlEaLYCmNFgEaKE5pNADVTWlMPpWhn+Q5jeZzQGk0zzhvBEqjPHNKozxzSqM8c7tF1NL450/Z0ljQUkUD349fuwOOxtdTGg11KEqjRbCURosADRSnNBqA6qE0yr9B8YtIaZTPOaVRnjmlUZ45pVGeud0iamlc8zO6Nqp+pmm5ppbmWNPofMIL9+PXbYfj4mspjYY6FKXRIlhKo0WABopTGg1ApTTKQy0kIqVRPiWURnnmlEZ55pRGeeZ2i6ilce0v6Nq4hmjT4tdsg6PhNZRGQ9QpjRbBUhotAjRQnNJoACqlUR4qpdHnmFMa5VNCaZRnTmmUZ263iFoa1y1F10tqyZ7T+Oc2OC66itJoqENRGi2CpTRaBGigOKXRAFRKozxUSqPPMac0yqeE0ijPnNIoz9xuEbU0rl+GrpfUFm1a/KqtcDRoRmk0RJ3SaBEspdEiQAPFKY0GoFIa5aFSGn2OOaVRPiWURnnmlEZ55naLqKVxw3J0vazu6XMa9Q55gN4t1bmZqvc/x6/aAscFV1IaDXUoSqNFsJRGiwANFKc0GoBKaZSHSmn0OeaURvmUUBrlmVMa5ZnbLaKWxo0r0LVp3dOG6Gxh3oMWvfs5/vdNcNS/gtJoqENRGi2CpTRaBGigOKXRAFRKozxUSqPPMac0yqeE0ijPnNIoz9xuEbU0/v0bul5xQe5zGvOey+jlz/ErN8FRryml0VCHojRaBEtptAjQQHFKowGolEZ5qJRGn2NOaZRPCaVRnjmlUZ653SJqafznd3S9/ALZcxpXbISj7mWURkMditJoESyl0SJAA8UpjQagUhrloVIafY45pVE+JZRGeeaURnnmdouYLY1/oGuzBmea5lzT6PyOgc/xShrrXEJpNNShKI0WwVIaLQI0UJzSaAAqpVEeKqXR55hTGuVTQmmUZ05plGdut4haGresPi2NDrULjnP3mwLWOHrnfvzyv+Co3eQsaczMzMKRYycQHByEktGRdsMt1h5Ko0XUlEaLAA0UpzQagEpplIdKafQ55pRG+ZRQGuWZUxrlmdstopbGrX+i69UXy57TqKSxZqNc0rj89/XoPehNJCWnaMxNG9dHv8c64qJ6NeyG3Xh7KI0WEVMaLQI0UJzSaAAqpVEeKqXR55hTGuVTQmmUZ05plGdut4haGv9dg67XNBJtWvzStXDUuDiXNP66agMOHjqG65o1QkpKKl4e+zHUyOPbr/cRfTc7BKM0WswipdEiQAPFKY0GoFIa5aFSGn2OOaVRPiWURnnmlEZ55naLqKVx21p0vbaJblr2Jqlnjtcw9Tn+lzVwVG94zjWNcxYsw7PD3sWahe8jKDDQbuiNtofSaBEvpdEiQAPFKY0GoFIa5aFSGn2OOaVRPiWURnnmlEZ55naLqKXxv7/Q9bomp43R2cIso5/jl6yCo9pF55RGJYxbtu3GzMlD7IbdeHsojRYRUxotAjRQnNJoACqlUR4qpdHnmFMa5VNCaZRnTmmUZ263iFoat69Ht+aX6RFGh8Mh8nXaz6uAqhcWKI3OUcb3RvVHs8ty7OxqtwQYag+l0SJYSqNFgAaKUxoNQKU0ykOlNPocc0qjfEoojfLMKY3yzO0WUUvjzo3oev1lp6emqgFGpzg698bx/uepi1fCUeWCfKVx6cq/8Ej/UXip773ocMcNdkMu0h5Ko0XMlEaLAA0UpzQagEpplIdKafQ55pRG+ZRQGuWZUxrlmdstYrY0/o1uLS5H9nGMBY005hXIvM95dn/a4pVA5XpnSeP8xb+h7+CJeGXAg2jX+lq74RZrD6XRImpKo0WABopTGg1ApTTKQ6U0+hxzSqN8SiiN8swpjfLM7RZRS+Puf9C1xRVQpzQWdJ3ZGif/Jzy9H79oBVCpbi5pnD1/KQa+NhnPPtEZLa65xBUotmQUIsLD7IbeaHsojRbxUhotAjRQnNJoACqlUR4qpdHnmFMa5VNCaZRnTmmUZ263iFoa92xGt5bNkIUsOOCAUwDP/uq9+9MW/gpUrJ1LGl8eOwWfzV50FmKOOnre6yiNnjPLVYLSaBGggeKURgNQKY3yUCmNPsec0iifEkqjPHNKozxzu0XU0rh3K7rdeJVo0+J/WAZUqHXO3VNFX8hmwSiNFhNKabQI0EBxSqMBqJRGeaiURp9jTmmUTwmlUZ45pVGeud0iamnc9y+63XyNXpToXNPo3BXH1GctjeVqUBoNdShKo0WwlEaLAA0UpzQagEpplIdKafQ55pRG+ZRQGuWZUxrlmdstopbG/dvQ7eZrT5/LqCalnr4cjuzdbQx8jl/wC1CuOqXRUIeiNFoES2m0CNBAcUqjAaiURnmolEafY05plE8JpVGeOaVRnrndImppPLAd3W+5XuR8RufIZfyCJUCZqpRGQx2K0mgRLKXRIkADxSmNBqBSGuWhUhp9jjmlUT4llEZ55pRGeeZ2i6ikEQd3oGvr5mcGFAG9GY5rgNHA56nf/QTEVaE0GupQlEaLYCmNFgEaKE5pNACV0igPldLoc8wpjfIpoTTKM6c0yjO3W0Q90nhoJ7rf2uLMrqnOtY2APoYjy8Dn+O8WA6UrUxoNdShKo0WwlEaLAA0UpzQagEpplIdKafQ55pRG+ZRQGuWZUxrlmdstoh5pPLwbXW9rmeucxrznLnr789RvFwGlKlIaDXUo20pjZmYWDhw+irhSJREUGOgWvr0HjqBcXCwCAs51FGnuqiiNbqEVfYjSKIpbB4uNCkFKWgaST2XIBy+mEaPDg/QGAwlJacWUgHyzKY3yzCmN8swpjfLM7RZRjzQe2YPut9+UPaKoz2k8s4uqcw2i66uX7sd/sxCIrUBpNNShbCmNPy1fg34vv42k5BSN7aWn70OH28/Mq87Lcsrn8zHtyx+Qlp6OtLR0tGt9Lfo+2kE/tnDJKvQeNP4s/KsWTEZoSDAojYZ6poVqKY0W4BWxKKWxiOAsFKM0WoBXxKKUxiKCs1CM0mgBXhGLUhqLCI7FXAT0SOPRfeh2+03OyagiX6fOXQDElKc0GuqLtpPG5JRUXNeuN554oB26tL8Ri5f9iScHvYn500eicoUyZ2Fcv+k/dHh0MD4c+ywub1If/+7Yi9u7P4dPJg5Cowtr4Yclf+C5YZMxc/KQXGWrViqrz52hNBrqmRaqpTRagFfEopTGIoKzUIzSaAFeEYtSGosIzkIxSqMFeEUsSmksIjgWyy2Nx/ajW9tbso/XcDhcaxidn/N+da5xtHI/fs4CoGRZSqOhvmg7aVSjjD2fG4vVCyYjJCRYY7u16wAtkF3aq9945L5WrN6IB/oMx7xpw1G1Ujl989o7e+GZnp1w+81XaWkcMvojLPnqzXxTcL6l8eiu7Ti+7nekJR5DZKVqKH3pNQgNDTPUXfyjWkqjfJ4ojfLMKY3yzCmN8swpjfLMKY3yzO0WUY80Hj+QLY3Z297kaKK5z1O/ng+UKENpNNShbCeNM+YsxkefzcO38cNdyHo9Pw7Vq1TA0z2yp5zmvFJT0/Dg0yPx95Yd6P1geyQmJWPB4pX4ePxAlIiK0NKoRirbtroaoaEhuKxRPbRq3tS1TvJ8SuORLRtxfNqbqHFkD0qkncKBsCj8V/cS1H6wH4KCs4W5OF6URvmsUxrlmVMa5ZlTGuWZUxrlmVMa5ZnbLaKWxhMH0f3O1nrg0HXl8UWHI3sg0lv3p379HRAdR2k01KFsJ43vffINvvvxt1zTSdX6xqiIcAzud1++GCdPm4s5C5YhPCwUf23ahoc634ZeD7bXYrju722Yv/g3lIyOxJ79hzHj6x/RuV1LPP9kN11X0qn0c6YmLCQQp1Iz9QJgb1+rJo9Hg6VzEZZx5h3+iyyFoMeeQ6VGl3o7nN/UFxociLSMTKjNkHjJEFA/2Cne6cWMuftbZnk/D0GBAbrS9IxMS5WrnAV5sPmXpWB+Xlj9MK02SktLL5w5//bxTrIDHQ4EBQXgVBo32fIO0cJrUZuWhIYEICXVf5hHhAYV3jA+IUZAS2PCIXRre2vBMfMOOOZ9sgj3p86eB0SXpjQayrTtpNHTkcYlK9aix4AxWD53oh5ZXLryLzz14lvo16MDOrZtcRb2L7/9GYNGfIA1C9/XUnk0IfWcqSkZGYyE5DRkFv4zhkcpTko6ib2TR6HB2iW5yiUGheDfOx9G3dbtPKrPTg+rEZjk1AykZ/DHNqm8RoYFITUjE2lpXu7oUg0oYpzz2cPCQwL0OhGrO9a61pEUkUFxKhYaHAAl6ydTzv3LQsXkfP5CwU45CQx0QI3wJiQVztxO7T6fbQkIAKLDg3H8pP/szBwbHXI+kTF2HgLZ0ngY3drdpocSz9ot9fQaR/VvmDfvx8+eh6yoUpRGQz3SdtLoXNP45/fvITg4+zdPrTr1R/e7b853TeMbk2di0S+r8PXHw1yIHx/4BiLDwzBiUI+zsC9ZsQ49BozGH/PfRVhoyHndCGdT/AQ0Xv4twjLP/GO6PbIUUu7vj7INLjHUZXy/Wk5Plc8Rp6fKM+f0VHnmnJ4qz5zTU+WZc3qqPHO7RdTSmHgkWxrzXM7jNwpqs5X7U2d9A1AajXUn20ljUvIpNG39KAY83gmd89k9deWff2P4hOkY/VJPVKtcDt8uXIH+Q9/GpOF9cc3lDbFzz0G07vIM+j92D+7reAs+mbUQ9WpVwYV1q+N4QiL6vzwJwUGB+GDsAJ2U87mm8fDmDUj85C3UPLwbUemncDA0ClvrXYraDzyN4JDi+1s3SqOxvy8KrJjSKM+c0ijPnNIoz5zSKM+c0ijP3G4Rs6XxKLq3b6MXZzlnmpr+Gj9rLrIiYznSaKhD2U4aFadFS1dDbX7jvF54qhs63dlSf/xx2Wo8MXAcvnx/qJZBtQ7rnfiv8dW8X3DkWAKio8Jxx81X4/H722k5HPPODLw//VtXXRdfWAsjB/VwHd9xPqVRvdThndtwfN0fSD95HBEVq6KM2j01LNxQd/GPaimN8nmiNMozpzTKM6c0yjOnNMozpzTKM7dbRC2NJ4+hW/vbXU0rSBidD3jj/pQv5wCRMZRGQx3KltKoWGVkZGLfwSMoWzrGNU21MIZ79h1C+bKl9UYHOa+UU6k4ePgYoiMjEFMyKte98y2NzpfJysyEQy1E4AVKo3wnoDTKM6c0yjOnNMozpzTKM6c0yjO3W0SnNHa/q63rfEbn+nmTX+O/nIOsiJKURkMdyrbSaIjXWdX6ijRKtdcf4lAa5bNEaZRnTmmUZ05plGdOaZRnTmmUZ263iFoak46j2//aZu9145yimqX3bzP2ecrMr4GIEpRGQx2K0mgRLKXRIkADxSmNBqAWUiWlUZ45pVGeOaVRnjmlUZ45pVGeud0iamlMPoHud92pz2E0KYo564+fORtZ4dGURkMditJoESyl0SJALxVPT8/eGjwoKJjTU73E1JNqKI2e0PLOs5RG73D0pBZKoye0vPMspdE7HD2phdLoCS0+mx+BbGlMQPe7s49/c440Op819XnqzK+QFRZFaTTULSmNFsFSGi0CtFg8LTUVezavxamkE7qm0IgSaHjpZUjJCEBqMTsz0CJKS8UpjZbwFakwpbFI2CwVojRawlekwpTGImGzVIjSaAkfCwPQ0piSiO4d2suuaVTSGBqZrzSmpqbh6PFElI2L0edG8vKcAKXRc2a5SlAaLQK0WHz98h/QuFpZxMVE65oOHT+Bv3YdRsOrbqQ0WmTrSXFKoye0vPMspdE7HD2phdLoCS3vPEtp9A5HT2qhNHpCi8/mR0BL46mT6HZ3ez019axzN04Xck4t9db9qTO+PEsa1cY7b0/5GhM+nKWjloqJxlvDnkKjC2sxeR4SoDR6CCzv45RGiwAtFE9MOIHEbavRpHbVXLWs+XcXStRqjLDwbJHkZZ4ApdE847wRKI3yzCmN8swpjfLMKY3yzO0WMVsak9C94/9yjDSeXtvoXOPo+pqlR/5caxMt3I///AtkhUTkGmlc/ddmdH3iVUx9cyAa1q+J8e9/iW8WLscPn40567QEu+XB2+2hNFokSmm0CNBC8YMH9qJEwk5Ur1AmVy3/7T2I5JhqiCldzkLtLOoJAUqjJ7S88yyl0TscPamF0ugJLe88S2n0DkdPaqE0ekKLz+ZHQEtjajK6d7zr9O28qxjzlvLO/amfzURWSHguaRw9aQY2btmO90b110EPHDqGG+56CjMnD8EFdaoxgR4QoDR6ACu/RymNFgFaKK42v9m26idcd1HuKQZLN/yL2k2bIzMr0ELtLOoJAUqjJ7S88yyl0TscPamF0ugJLe88S2n0DkdPaqE0ekKLz55TGu/pkD03VY8kZsGB03NVDX2OV9IYHJZLGvu9/DZiS0bh+Se7uV61QfP7MPG1Pri+WSMm0AMClEYPYFEaLcIyUHzvf/8g/chuVC5dQte++/AJlKxYFaWr1OGaRgO8C6qS0igI+3QoSqM8c0qjPHNKozxzSqM8c7tFVCONa1evQqOGDUSbtmbdelzc5JJc0vhI/1GoV6sqnu6hBDb7atq6Bwb3uw+3tbxS9P38PRil0WIGOdJoEaAXiiecOI6EI/t1TdGlyqFG5bI4kZxGafQCW3eroDS6S8p7z1EavcfS3Zooje6S8t5zlEbvsXS3Jkqju6T4XEEE1qxZA/Xf+bgaNWoE9Z/zUiONavObgb27ur7HkcaiZYbSWDRurlKURosADRSPKxFKaTTA9VxVUhqFgatfkIQH6Sk/CUnZZ5TyMk+A0miecd4IlEZ55pRGeeaMaI6AWtO4aesOvDuynw7CNY1FZ01pLDo7XZLSaBGggeKURgNQC6mS0ijPnNIoz5zSKM+c0ijPnNIoz5wRzRE4s3vq82h4QU2Me28mvl34K3dPLQJySmMRoOUsQmm0CNBAcUqjAaiURnmohUSkNMqnhNIoz5zSKM+c0ijPnBHNEVAb8Lz14SxMmvK1DhIRHoZ3Rz6NJhfVMRfUpjVTGi0mltJoEaCB4pRGA1ApjfJQKY0+x5zSKJ8SSqM8c0qjPHNGNE8g5VQqjhw9gfJlS/N8xiLipjQWEZyzGKXRIkADxSmNBqBSGuWhUhp9jjmlUT4llEZ55pRGeeaMSAL+QIDSaDFLlEaLAA0UpzQagEpplIdKafQ55pRG+ZRQGuWZUxrlmTMiCfgDAUqjxSxRGi0CNFCc0mgAKqVRHiql0eeYUxrlU0JplGdOaZRnzogk4A8EKI0Ws0RptAjQQHFKowGolEZ5qJRGn2NOaZRPCaVRnjmlUZ45I5KAPxCgNFrMEqXRIkADxSmNBqBSGuWhUhp9jjmlUT4llEZ55pRGeeaMSAL+QIDS6A9Z4juSAAmQAAmQAAmQAAmQAAmQwHkiQGk8T+AZlgRIgARIgARIgARIgARIgAT8gQCl0R+yxHckARIgARIgARIgARIgARIggfNEgNJ4nsAzLAnYjcDJpBScSExCubhYHpxrt+SyPZpAUnIK0tIyULJEJIkIEVB/r6j/ypQuCYfDIRS1+IVJz8hAgCMg37+7ExKToO7HlowufmDYYhIgARcBSqPhzrB73yHcef8L6HRnC/R9tIPhaMW7+uETpmPK5/NzQWhyUR3Ev/V88QZjuPU/LV+D4RM+wfZdHwirUwAAFNBJREFU+3WkWR+8gro1KxuOWnyrv/bOXjhyLOEsALM/fBW1a1QqvmAMtnz/waN45Y0p+HXVRh2lfu2qGNi7Cy6oU81g1OJddWpqGgaN/ABzv1+uQZQrE4txQ3ujYf0axRuMgdYnp6Si46OD8UjX29HmpmauCOqXJANeeQeLlq7W37v4wlp485XeiCtV0sBbsEoSIAFfJ0BpNJgh9du5Lo+/gq3b9+DBTrdSGg2yVlW//tYn2LnnAJ7p2ckVKTQ0GOXLlDIcufhWv3jZn3h84Bt4uEsbtG11tf5NdGhoCMLDQoovFMMtV308MzPLFWXDP/+h38tvY9HnY/UP1ry8T+CZoZNw7EQiJgx7Co4AB4aM/hgHDx/FpOFPez8Ya9QEvln4K/6vvTuP87Hq/zj+jhlbiexKizY/W4rEuBMhokEKoaIsGcuEyhKJyFa2jBCK3HYlSahsRYvcVNIiSYukyL7PMPfvc/zm24zGzPdS19Dvel3/eBjne851nud6jHnPWa7BcdM0/tnHdHXRIho4aqo+WLNB818eqKxZIlH6mwSGjpulSTMXudqG9GqbIjROnP6m5ryxQv+O6+W+p7frMUJFLyus/t1a/k2tUw0CCPyTBAiNPo2WLeXo2HOkCuXP65bsFSmcj9Dok3VStRYa7Qe7wT0f8rklqjeBxMRE3dWqt4pdfRnmZ/GRiOk+TPnzXsQPcj6OwX0dB+jyIgU1oEdr18pri1Yq7qW5Lqhz+SNg5mVLXxP6f3P33v26uX6sZr/QVyWLXeFPowGsdc/eAzpy7Jiate+vRx5qnCI0NmzTR7Wqlne/FLTrrRUf65G+Y7Rh+SSWCgfwWaHLCBAafXoGBo6apm+3bNULzzyq7gPGExp9ck5erYXGt99do4plS7gZr2o3l1W5667NgJaD2YQtkbSlktX+dYPiExJ08NBRRZUroZZN6yhbVmYaM+KpWPPp13qg82C9M3OoLi6ULyOaDGQby1atU+wTo1S9clk1qF1Zz46ZqZZN6qhhdJVAemREp+9p+5Sibiypzm0ahporWfUBPdc/VjUql8uIWwhUG7WadlVsy7tShMbytWP0dPdWLjjaZasaGj3UVx+88bxy5WRfb6AeEDqLgCRCow+PwYx5SzV51mL3G1E7MMF+M8dMow/Qp1T5xtsf6Put293SpQ0bt2jpynUa3re9alW9yf/GA9jCV5t+kP0mulF0VVUqX0r79h+U7Su9o3pF9X3sgQCKZGyXbaa3SUw/lb3uWnXv8MeS7Iy9i2C0ZnvT2zz2rK698lK9v2aDsmWN1KQRPdhD6uPwT5692IXzru2aqHDBPFr/5XeyrxEa/UE/NTTa95dStz6oMYO6qEpUGdfo5u9/Vr0HemnJrGEqXDCvPzdCrQggcM4KEBp9GBr75mtLma6+4uShFEtXrVPOC3KkWObhQ7NUeYpAj4HjtWfvfvYd+fRkJIXGlfPilCf3yVP15i58T4PipuvjhWNZvuSTe1K1S1auVafecXp37nMcTOGztc16Val0vdq3qC/bq95n6GStXL1eHy54XhGZM/vcejCrt9Aya/5y2SyvXZcUzq/Z85ezPNWnx+F0M422JLtmlRtdq8w0+oRPtQj8QwQIjT4M1KzXl2nv/oOhmuctXqU8uS9U3duidE/9aj60SJWpCYyc8IrWrv9G/47rCZAPAvaMV6rbQTPG9Han6tllP9Q9Nfxlfb5sEq/d8ME8qUrbM12vRU/VrlbBLSnj8k/AXvdwU50Yd2qkLXm364uN36tx276aN+lpXVOUk4L90/+j5vFT39CEaW/qvddGcdCWD+CphUZbSXL7rTepdbM7XIvsafQBnioR+AcJEBozYLBYnpoByJJGjJ+jejUr6bIihbRx8496sPMQ959d2/vrZswNBLAVO4TFTvIc2a+jdu7ap679xrplS/Z3Lv8EkmZ0l8wext4i/5hDNdsP1EUvK6QhT8QoR7assl9ILf/gE3eSJzON/gyAfV/5ffdet0rH9u7a/6MPt7pL9zes6U+DAa3VfgGVeCJR0c0fV0zzeoquEaXIyAinMWHaAr2y4F13emqO7FkV0304p6cG9Dmh2wiYAKExA54DQmMGIEuyJWS2lzHpuvP2m9W7S3MOZfGRf+svO9T5ydGypap2VbihuJ7pHcNySR/Njx6LV43Gj6h5o1qhUw19bI6q//d7iz3fY6e87vZJ58ieTTeWKeaWqpYufiU+PgnYOwLtIBa7bPl7bKu71bhuVZ9aC2619vOJzSAmvxZMGeTCoc2y2+t83vvoM/fPpYoVVdyATiqQL3dwweg5AgEWIDQGePD/P3bd9hvZ0ez2CgLeFZhxI/zbzj2KiMgc2tuYcS3TEgIZJ2A/RCckHHcHnHH5L7B9xy5FRkQo70UX+t8YLZxWwLYixMcn8MtAnhEEAi5AaAz4A0D3EUAAAQQQQAABBBBAAIG0BAiNPB8IIIAAAggggAACCCCAAAKnFSA08nAggAACCCCAAAIIIIAAAggQGnkGEEAAAQQQQAABBBBAAAEEvAsw0+jdjE8ggAACCCCAAAIIIIAAAoERIDQGZqjpKAIIIIAAAggggAACCCDgXYDQ6N2MTyCAAAIIIIAAAggggAACgREgNAZmqOkoAggggAACCCCAAAIIIOBdgNDo3YxPIIAAAggggAACCCCAAAKBESA0Bmao6SgCCCCAAAIIIIAAAggg4F2A0OjdjE8ggAACCCCAAAIIIIAAAoERIDQGZqjpKAIIIIAAAggggAACCCDgXYDQ6N2MTyCAAAIIIIAAAggggAACgREgNAZmqOkoAggggAACCCCAAAIIIOBdgNDo3YxPIIAAAggggAACCCCAAAKBESA0Bmao6SgCCCQXeGLIi7ri0kJq3eyOM4b58efftHb9RlWtdL0uypVT67/crEGjp2tU/1jlz5s71XrHTZmvX3fuVp9HWpxxu/bBU9v+S5X9xQ9/smGTtm7bobo1K/3Fmvg4AggggAACCJyLAoTGc3FUuCcEEPBdoGGbPipd/Mq/FN7eXPqRuvUfp1kv9FGpYkX1/poNeqjrUL0141kVKZw/1T70GjxRP2z9VVNH9wq7j/fHDtTlRQrq6e6tQp85te2wK/OhYN+hkzVnwQp9sWKyD7VTJQIIIIAAAgicbQFC49keAdpHAIGzIvB3hMb4+AQdPHREF1yQXRGZM/sWGu/rOMCFxgE9WoesTm37rCD+X6OHDh9VfEKCcuU8/2zeBm0jgAACCCCAgE8ChEafYKkWAQTObQELjYUL5FGhAnm0ePnHOnI0XvfUv1WdWjdUZERm7d67X7G9RunRmMa6odQ1rjMJx4/rgU6D1apZHd1a6QZ9/tV3GvL8DI14qoNbjpraTOOSlWv1/KTX9M13W3XV5Rfr6LF4VzbcmcbxU9/QcxNfVY7s2VTsqkvdfXRr30TnnXdeirZnvb5MH679UhXLldD0uUv0y2+7VL1yWT0ee6+mzV2i1xevcsGuWYMauveu25Q9WxZX1/HjJzR17jt6dcG72vzDNl17ZRHFNK+vWlXLhz2ANsv44X++0PC+Hdxnej/zkvJedKFOnDihBUs+VGREhJreWV3NGlRXliyRYdc7/+33NWXO225mNk/unCp33bXq8lAj5xfOfds9TZi2QJ9/vUX58+ZSVLmS6tiygVtKnFbdYd8gBRFAAAEEEAiIAKExIANNNxFAIKWAhcavNv2gqBtL6ubypWXhzvbmPdK2sVo1raNfd+xWtUZdNGZQF1WJKhMKjWWqt9JTjz2ohtFV/hQSTw2NK1evV0z34W6W8P6GNWWzg5NnL9bFBfOFHRot+PQaMlH58+TWnbVvdvdRpWIZbflpe4qlsMNfmK0XZyx0y2Lt3o4di9eYl1935S2s2md37zmgl2Yu1HP9Y1Wjcjn3b/a5GfOWqemd1XRdiatcgF60bLWmj+mtMiWuCuuxGfXiq5q3eJWWzRnhyifZWtiuWeVG/bTtN01/banGDXlUlSuUDqtO63frx55V43q3uvHZ9utOzZi31M22Wr3p3fe7H36m9o+PcCG4Sf1q2n/wsF6evVijB3bWoUNH0qw7rBukEAIIIIAAAgESIDQGaLDpKgII/CFgwcYOwhn6ZLvQF20Z6I7f97g9iX9HaLyn7VPas++AFk17RpkynefaOZM9jaktTz01oFqIem3RSr0za5iyZT05ixjTfZi2bf9dr07sp8jICPc1u6cSxa5wezl/371PtzR4OBSU7d9tNjUquoPuvuMW9ejYLKxHJrXQaOHVZmBtRtSuei16qkLZ4urV6f6w6rRwO2zcbC1/ZaQK5Dt5qJDNLtrs5b4Dh9K9b2vPZnVtLJOuQ4ePKDFRmjV/2WnrTnIK6yYphAACCCCAQEAECI0BGWi6iQACKQVS29OYNFv32dIX9fuufX9pptGWvdqspM0wJg9ffobGt1asSRGS7ITYTd9tdQf1JF2xvZ5zy1Rt1u8/n21Ui06D3OxkzgtyhMrYDKydCPv8wM5hPTaphcZTDxlq1+PkLOTYwV3CqnPj5p90V6veblmuLZW9vuTVqlO9gvt7evdty2TL1myjFo1qqVuHpn9qL626w7o5CiGAAAIIIBAwAUJjwAac7iKAwEmBcEPj6IGd3P5Fu2wWLtzlqbYHr3ztGLcHL/lrPTIyNPYZOklfb/oxRWh8uPcot3TVQuPK1Z+72cieD9+nyy4pkOLRyJ0rp0r/T9GwHpdwQqOF1YTjJ8IOjdbwlh9/cUtn133+jVtKbIFx/uQB+vb7bWned9FLC6nCHe3c/sV2zeun2ofT1V24YN6w+kwhBBBAAAEEgiRAaAzSaNNXBBAICaQWGhu0fMItgZz/8kAdOHjYBQ97zUWD2pXd52xP4vW3tQ57T6OFxopliytuQKdQuz0HTXDvWAz3IBz7oL3G44Lzc2h43/ahelJbnnrqTGN6odHuo/a93dxSVds7mPxKTEwMLS1N77HxIzTaOGTOnCnUtB0kZONjs7ZVoq5P974r3xnr9o4mn2W1yk6cSJT17XR128wwFwIIIIAAAgikFCA08kQggEAgBSw02v41CyF2Wqod5GKnjCYdcmModhDLnr0H1KvTfdq1e78mznhT67/cHHZoHDhqqquzZZM6uqXide7gHDvN0w5y8RIaJ81c5A61saWdWSIjVKhAXm3asvVPB+F4DY3WR5t5XLpyneuTnU5q+xzf++gzZcqUSZ3bNAzr2fAjNI4YP0eHjxxVdI0o5cuTS++tXq/+I6a4JbO2dDa9+7ZDgWy5caPoqro7uoqOHj3mDsJpfW+0lq1al2bdYXWaQggggAACCARIgNAYoMGmqwgg8IeAHQhjJ3Lu2rM/9EVbRvpwq7tDs1Afrf1SFvzsVRR2WfizA1r6dW3pDopJOuHz7ZlDdUmhfH/6uwXO2CdGueWVdhW/5nJlzpTJhVUvofHn7TvVe8iLWv3JV66eiUO7uj8t1Ca1bSHLTj5NfvBL36GT3bLO5LNtnZ8c7Q6ISdpbuHf/QY2c8Ipmz18ecrCltbZktXa1CmE9MnEvzXWH8CSdnpr8sJ2kCizk2exhuPskFy5drUFxU0PjYyfA1q1ZSW3ujXZVpnff8QnH9cKU+Ro75eQJsnaVKlbUHc7z6Reb06w7rE5TCAEEEEAAgQAJEBoDNNh0FQEE/ixw8NARbd+xy72z0fbMpXbZMs6C+S9SVg/vGExej53EaqeIJp0CeqbjYO+OtBnAXDnPP9MqTvs526+5Y+ceZcuWxb3H8Fy4bBmphXoLm6ezS+++7bO/7dyt88/PrguTHfYTTt3nggH3gAACCCCAwLkgQGg8F0aBe0AAgcAJ2DLQ25t1S7ffHy8cG/bewnQr81igafv++nbLz2l+6qXh3WQnpYZ7rfjgU3XtPy7N4v8qX0oj+3UMt0rKIYAAAggggIDPAoRGn4GpHgEEEDidwOEjx9LFyZ7t5DsXz8Z15Ogx917DtC6bfU16B2U492gzf8fiE9IsavWd6axuOPdAGQQQQAABBBDwJkBo9OZFaQQQQAABBBBAAAEEEEAgUAKExkANN51FAAEEEEAAAQQQQAABBLwJEBq9eVEaAQQQQAABBBBAAAEEEAiUAKExUMNNZxFAAAEEEEAAAQQQQAABbwKERm9elEYAAQQQQAABBBBAAAEEAiVAaAzUcNNZBBBAAAEEEEAAAQQQQMCbAKHRmxelEUAAAQQQQAABBBBAAIFACRAaAzXcdBYBBBBAAAEEEEAAAQQQ8CZAaPTmRWkEEEAAAQQQQAABBBBAIFAChMZADTedRQABBBBAAAEEEEAAAQS8CRAavXlRGgEEEEAAAQQQQAABBBAIlAChMVDDTWcRQAABBBBAAAEEEEAAAW8ChEZvXpRGAAEEEEAAAQQQQAABBAIlQGgM1HDTWQQQQAABBBBAAAEEEEDAmwCh0ZsXpRFAAAEEEEAAAQQQQACBQAkQGgM13HQWAQQQQAABBBBAAAEEEPAmQGj05kVpBBBAAAEEEEAAAQQQQCBQAoTGQA03nUUAAQQQQAABBBBAAAEEvAkQGr15URoBBBBAAAEEEEAAAQQQCJQAoTFQw01nEUAAAQQQQAABBBBAAAFvAoRGb16URgABBBBAAAEEEEAAAQQCJUBoDNRw01kEEEAAAQQQQAABBBBAwJsAodGbF6URQAABBBBAAAEEEEAAgUAJEBoDNdx0FgEEEEAAAQQQQAABBBDwJkBo9OZFaQQQQAABBBBAAAEEEEAgUAKExkANN51FAAEEEEAAAQQQQAABBLwJEBq9eVEaAQQQQAABBBBAAAEEEAiUAKExUMNNZxFAAAEEEEAAAQQQQAABbwKERm9elEYAAQQQQAABBBBAAAEEAiVAaAzUcNNZBBBAAAEEEEAAAQQQQMCbAKHRmxelEUAAAQQQQAABBBBAAIFACRAaAzXcdBYBBBBAAAEEEEAAAQQQ8CZAaPTmRWkEEEAAAQQQQAABBBBAIFAChMZADTedRQABBBBAAAEEEEAAAQS8CRAavXlRGgEEEEAAAQQQQAABBBAIlAChMVDDTWcRQAABBBBAAAEEEEAAAW8ChEZvXpRGAAEEEEAAAQQQQAABBAIl8F82hcPFlmTkxAAAAABJRU5ErkJggg==", + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{text}Trial", + "marker": { + "color": [], + "colorbar": { + "title": { + "text": "Trial" + } + }, + "colorscale": [ + [ + 0, + "rgb(247,251,255)" + ], + [ + 0.125, + "rgb(222,235,247)" + ], + [ + 0.25, + "rgb(198,219,239)" + ], + [ + 0.375, + "rgb(158,202,225)" + ], + [ + 0.5, + "rgb(107,174,214)" + ], + [ + 0.625, + "rgb(66,146,198)" + ], + [ + 0.75, + "rgb(33,113,181)" + ], + [ + 0.875, + "rgb(8,81,156)" + ], + [ + 1, + "rgb(8,48,107)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [], + "type": "scatter", + "x": [], + "y": [] + }, + { + "hovertemplate": "%{text}Best Trial", + "marker": { + "color": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "colorbar": { + "title": { + "text": "Best Trial" + }, + "x": 1.1, + "xpad": 40, + "y": 0.5 + }, + "colorscale": [ + [ + 0, + "rgb(255,245,240)" + ], + [ + 0.125, + "rgb(254,224,210)" + ], + [ + 0.25, + "rgb(252,187,161)" + ], + [ + 0.375, + "rgb(252,146,114)" + ], + [ + 0.5, + "rgb(251,106,74)" + ], + [ + 0.625, + "rgb(239,59,44)" + ], + [ + 0.75, + "rgb(203,24,29)" + ], + [ + 0.875, + "rgb(165,15,21)" + ], + [ + 1, + "rgb(103,0,13)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [ + "{
\"number\": 0,
\"values\": [
9.7626,
0.6995,
0.9562
],
\"params\": {
\"pq_dim\": 662,
\"n_probes\": 79
}
}", + "{
\"number\": 1,
\"values\": [
4.9705,
0.1443,
0.8414
],
\"params\": {
\"pq_dim\": 210,
\"n_probes\": 57
}
}", + "{
\"number\": 2,
\"values\": [
10.0147,
0.8856,
0.9581
],
\"params\": {
\"pq_dim\": 678,
\"n_probes\": 98
}
}", + "{
\"number\": 3,
\"values\": [
9.3991,
0.3831,
0.9497
],
\"params\": {
\"pq_dim\": 432,
\"n_probes\": 70
}
}", + "{
\"number\": 4,
\"values\": [
9.018,
0.3598,
0.9471
],
\"params\": {
\"pq_dim\": 410,
\"n_probes\": 69
}
}", + "{
\"number\": 5,
\"values\": [
4.2757,
0.1919,
0.8495
],
\"params\": {
\"pq_dim\": 242,
\"n_probes\": 66
}
}", + "{
\"number\": 6,
\"values\": [
10.1002,
0.4773,
0.9518
],
\"params\": {
\"pq_dim\": 688,
\"n_probes\": 50
}
}", + "{
\"number\": 7,
\"values\": [
8.6237,
0.411,
0.9475
],
\"params\": {
\"pq_dim\": 388,
\"n_probes\": 85
}
}", + "{
\"number\": 8,
\"values\": [
6.0929,
0.2856,
0.8991
],
\"params\": {
\"pq_dim\": 286,
\"n_probes\": 79
}
}", + "{
\"number\": 9,
\"values\": [
6.0429,
0.0726,
0.8775
],
\"params\": {
\"pq_dim\": 284,
\"n_probes\": 19
}
}" + ], + "type": "scatter", + "x": [ + 0.6995, + 0.1443, + 0.8856, + 0.3831, + 0.3598, + 0.1919, + 0.4773, + 0.411, + 0.2856, + 0.0726 + ], + "y": [ + 0.9562, + 0.8414, + 0.9581, + 0.9497, + 0.9471, + 0.8495, + 0.9518, + 0.9475, + 0.8991, + 0.8775 + ] + } + ], + "layout": { + "autosize": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Pareto-front Plot" + }, + "xaxis": { + "autorange": true, + "range": [ + 0.02429064848316169, + 0.9339093515168384 + ], + "title": { + "text": "latency_in_ms" + }, + "type": "linear" + }, + "yaxis": { + "autorange": true, + "range": [ + 0.8317694174757282, + 0.9677305825242718 + ], + "title": { + "text": "recall" + }, + "type": "linear" + } + } + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA40AAAFoCAYAAADzQh4hAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQmcTeX/xz9jVmPGzDDGviV7Qr9UKiWSlBIVYWiPVIpIkVBR9pAltDESiWyJspRsKRJCSPZlLDOM2Zf//zkz95oZM86dc+59znPv/ZzX6/ea353nPOf7Pe/P9ft5e87ik5WVlQVuJEACJEACJEACJEACJEACJEACJFAAAR9KI78XJEACJEACJEACJEACJEACJEAChRGgNPK7QQIkQAIkQAIkQAIkQAIkQAIkUCgBSiO/HCRAAiRAAiRAAiRAAiRAAiRAApRGfgdIgARIgARIgARIgARIgARIgASKToArjUVnxhkkQAIkQAIkQAIkQAIkQAIk4DUEKI1eEzVPlARIgARIgARIgARIgARIgASKToDSWHRmnEECJEACJEACJEACJEACJEACXkOA0ug1UfNESYAESIAESIAESIAESIAESKDoBCiNRWfGGSRAAiRAAiRAAiRAAiRAAiTgNQQojV4TNU+UBEiABEiABEiABEiABEiABIpOgNJYdGacQQIkQAIkQAIkQAIkQAIkQAJeQ4DS6DVR80RJgARIgARIgARIgARIgARIoOgEKI1FZ8YZJEACJEACJEACJEACJEACJOA1BCiNXhM1T5QESIAESIAESIAESIAESIAEik6A0lh0ZpxBAiRAAiRAAiRAAiRAAiRAAl5DgNLoNVHzREmABEiABEiABEiABEiABEig6AQojUVnxhkkQAIkQAIkQAIkQAIkQAIk4DUEKI1eEzVPlARIgARIgARIgARIgARIgASKToDSWHRmnEECJEACJEACJEACJEACJEACXkOA0ug1UfNESYAESIAESIAESIAESIAESKDoBCiNRWfGGSRAAiRAAiRAAiRAAiRAAiTgNQQojV4TNU+UBEiABEiABEiABEiABEiABIpOgNJYdGacQQIkQAIkQAIkQAIkQAIkQAJeQ4DS6DVR80RJgARIgARIgARIgARIgARIoOgEKI1FZ8YZJEACJEACJEACJEACJEACJOA1BCiNXhM1T5QESIAESIAESIAESIAESIAEik6A0lh0ZpxBAiRAAiRAAiRAAiRAAiRAAl5DgNLoNVHzREmABEiABEiABEiABEiABEig6AQojUVnxhkkQAIkQAIkQAIk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abG2zXZPo/idGLNtn3+9Al8vXqMJsNiG9nsKj7dtXui5CGnUy0xMzn95qvido/yulYHDkLkjCZAACZAACZAACZAACZCARsCtpdHRDMUlpEdPnNEkrkLZSE0SzWziPY9nzl5ARFgoSkeU1C7rzL+JlbyTZ85pD90RcpZ7E1Ij+ikdEabdRyhzE30dOX4afn5+EMIqnjBrdhNCLaQxpERxjYmrN0f5XSsDV/fI45MACZAACZAACZAACZCApxDwCmn0lLB4HiRAAiRAAiRAAiRAAiRAAiQgmwClUTZx1iMBEiABEiABEiABEiABEiABNyJAaXSjsNgqCZAACZAACZAACZAACZAACcgmQGmUTZz1SIAESIAESIAESIAESIAESMCNCFAa3SgstkoCJEACJEACJEACJEACJEACsglQGmUTZz0SIAESIAESIAESIAESIAEScCMClEY3CoutkgAJkAAJkAAJkAAJkAAJkIBsApRG2cRZjwRIgARIgARIgARIgARIgATciACl0Y3CYqskQAIkQAIkQAIkQAIkQAIkIJsApVE2cdYjARIgARIgARIgARIgARIgATciQGl0o7DYKgmQAAmQAAmQAAmQAAmQAAnIJkBplE2c9UiABEiABEiABEiABEiABEjAjQhQGt0oLLZKAiRAAiRAAiRAAiRAAiRAArIJUBplE2c9EiABEiABEiABEiABEiABEnAjApRGNwqLrZIACZAACZAACZAACZAACZCAbAKURtnEWY8ESIAESIAESIAESIAESIAE3IgApdGNwmKrJEACJEACJEACJEACJEACJCCbAKVRNnHWIwESIAESIAESIAESIAESIAE3IkBpdKOw2CoJkAAJkAAJkAAJkAAJkAAJyCZAaZRNnPVIgARIgARIgARIgARIgARIwI0IUBrdKCy2SgIkQAIkQAIkQAIkQAIkQAKyCVAaZRNnPRIgARIgARIgARIgARIgARJwIwKURjcKi62SAAmQAAmQAAmQAAmQAAmQgGwClEbZxFmPBEiABEiABEiABEiABEiABNyIAKXRjcJiqyRAAiRAAiRAAiRAAiRAAiQgmwClUTZx1iMBEiABEiABEiABEiABEiABNyJAaXSjsNgqCZAACZAACZAACZAACZAACcgmQGmUTZz1SIAESIAESIAESIAESIAESMCNCFAa3SgstkoCJEACJEACJEACJEACJEACsglQGmUTZz0SIAESIAESIAESIAESIAEScCMClEY3CoutkgAJkAAJkAAJkAAJkAAJkIBsApRG2cRZjwRIgARIgARIgARIgARIgATciACl0Y3CYqskQAIkQAIkQAIkQAIkQAIkIJsApVE2cdYjARIgARIgARIgARIgARIgATciQGl0o7DYKgmQAAmQAAmQAAmQAAmQAAnIJkBplE2c9UiABEiABEiABEiABEiABEjAjQhQGt0oLLZKAiRAAiRAAiRAAiRAAiRAArIJUBplE2c9EiABEiABEiABEiABEiABEnAjApRGNwqLrZIACZAACZAACZAACZAACZCAbAKURtnEWY8ESIAESIAESIAESIAESIAE3IgApdGNwmKrJEACJEACJEACJEACJEACJCCbAKVRNnHWIwESIAESIAESIAESIAESIAE3IkBpdKOw2CoJkAAJkAAJkAAJkAAJkAAJyCZAaZRNnPVIgARIgARIgARIgARIgARIwI0IUBrdKCy2SgIkQAIkQAIkQAIkQAIkQAKyCVAaZRNnPRIgARIgARIgARIgARIgARJwIwKURjcKi62SAAmQAAmQAAmQAAmQAAmQgGwClEbZxFmPBEiABEiABEiABEiABEiABNyIAKXRjcJiqyRAAiRAAiRAAiRAAiRAAiQgmwCl0STxE+eSTB6B01Uk4O/rg/CQAMTGp6jYHnuyiEBkWCDiL6chLT3Tog5YVjUCxQN8ERToiwuXUlVrjf1YSKBcqeI4cyEJmVkWNuFFpSuULu5FZ8tTJQFrCFAaTXKnNJoEqOh0SqOiwVjcFqXR4gAULE9pVDAUBVqiNMoNgdIolzereScBSqPJ3CmNJgEqOp3SqGgwFrdFabQ4AAXLUxoVDEWBliiNckOgNMrlzWreSYDSaDJ3SqNJgIpOpzQqGozFbVEaLQ5AwfKURgVDUaAlSqPcECiNcnmzmncSoDSazJ3SaBKgotMpjYoGY3FblEaLA1CwPKVRwVAUaInSKDcESqNc3qzmnQQojSZzpzSaBKjodEqjosFY3Bal0eIAFCxPaVQwFAVaojTKDYHSKJc3q3knAUqjydwpjSYBKjqd0qhoMBa3RWm0OAAFy1MaFQxFgZYojXJDoDTK5c1q3kmA0mgyd0qjSYCKTqc0KhqMxW1RGi0OQMHylEYFQ1GgJUqj3BAojXJ5s5p3EqA0msyd0mgSoKLTKY2KBmNxW5RGiwNQsDylUcFQFGiJ0ig3BEqjXN6s5p0EKI0mc6c0mgSo6HRKo6LBWNwWpdHiABQsT2lUMBQFWvJkaczKysKFs2eQEHscgaHhCI+qgMDAIEupUxotxc/iXkKA0mgyaEqjSYCKTqc0KhqMxW1RGi0OQMHylEYFQ1GgJU+VRiGM/2z6EVHpF1AuJBBxyWk4nAhUueVeBJeMsIw8pdEy9CzsRQQojSbDpjSaBKjodEqjosFY3Bal0eIAFCxPabwSyuVLl1AiNFTBlOS35KnSeP7UUfju34hakVdyvpichj0Zoah2cwv5oHMqUhotQ8/CXkSA0mgybEqjSYCKTqc0KhqMxW1RGi0OQMHylEbgfOxJnDt1FGGhJRB38RJKl6uM0lEVFUxLXkueKo3/7foNddNPomSgfx6Yv53PRPmb70WARZepUhrlfbcdrXQpIRFb/9xr393f3w8hJYrjhtrVIf67zO237XuRcDmx0JK+vr64u2nDq8aPHD+DP/7ah+a3N0JEmP4/iCWnpOLpPiPR68l2aHbrjTJPUUotSqNJzJRGkwAVnU5pVDQYi9uiNFocgILlvV0az587g8TYo2hYrzYCAwOQmpaG3Xv/gV/JcigdVV7BxOS05KnSeOrALkSe3YuKYcF2kBmZWfg1Nh11mreTA7eAKpRGy9AXWnjP/sN47PkhV42XCg/FzLFvoHaNyqabTklNw033PY8Rbz2Pdq3vKPR47Z95G//8e+ya9Xav++Kq8eWrN+ON96Zh3idDNNnV2xKTUtCkTQ98OPAFPHTf7Xq7u904pdFkZJRGkwAVnU5pVDQYi9uiNFocgILlvV0aj+zfjVpVyqBUeLg9nYuXErDzwBFUr9NIwcTktOSp0piQEI+Tm1fgf1ElUNzfF1lZwN7YeCSVq4eKta9eqZFDG6A0yiLteB2bNE4f3Q93NLkBmZlZ2Ln3X3Tp9R4euf9ODH/zOccPVsieYmXvf61fwPsDnkX7Ns0KPV56Rob2XRXbgUPHNJmd9H5vNLst+zvr4wP4+fpeNT8tLR2XE5MRElK8wPH8EyiNpiP17ANQGj0zX0qjZ+Zq9qwojWYJet58b5ZG8VCUQ3u24dYb68Df/8rlipmZmdi4bSeq17sZPuJvY164eao0iigvnTuNU/u2o4RPOuKS0hBeoToqWPwPBJRG9f6Q5ZdGW4ctHu+jXbo5rN/T9qbXb9mJT2YvwfZd+1GpfBm0u/9OPN+1Lfz9fJGamoZps5fgh7W/IfZcPMpHldIuF+3boyNeGvgR1m38U5tTpnT2P1zNGNMfxYMCCgWy/9AxPPL025jyQR/7Jak7/j6I0VO+xrD+T+P71ZshPre44yY0qFMdIyfPxfhhL2nH3/T7boz9ZD4OHzuNxKRk1LquEp5+og0evi97lZPSqN73UKmOKI1KxeG0ZiiNTkPpUQeiNHpUnE45GW+WRgHw5NF/UTbED5UqlLPzPHUmFsfOXUaFarWcwtgdD+LJ0mjL43LCJZQI0b/PS0Z+lEYZlItWwyaNb77cBQ3r1UByShrWbtyOBct+xqyJb6FuzaraAddv+Qs9B4zTLue8t9n/8NffB/Hp3O/xes+OeOaJB/DxZ4swddZi9H/xCVSqUAb7DhzBF/NXYuuKafhm2ToMHfMFHmx5Gxo3qKkd77G2zTXZLGwrSBptPYg5NapWQN1aVdGw3vWoWqksXug/BivnjtbEdOW637B52x40qn89ggIDsGbDNiz7cRNmTxqEmxrUpDQW7SvifXtTGj0zc0qjZ+Zq9qw8SRpTkpNwOSEBEaUjvXY1yOz3Qcz3dmlMTU3VVhsrly2FMpGlcfbseRw7fQ5VajdCYJC17+5zRr5Gj+EN0miUjSvmURpdQdXcMQu7p7FsmQi8/Vp3tLijsVZA3G8oVvHEZay2re/QyThw6DiWfDkCPQeMhXggzbJZH6JYsewrF5KSU7XVREcvT819JteSxg8GPm9fNRRzNmzdlUcabccRV1lcvJSIc3EX8VD3t9CvZydtxZErjea+M5bNFtdOnzl3AZGlwhy6Dllct3z2fDzKRIY7tL/txCiNlkXs0sKURpfidduDe4I0ZmRkYM/nU4F9uxF65hTO1aiJcs1bo8JdLd02Fysb93ZpFOzFd0o8EOfyxTiUCC2JiNJR8PPL+3RNKzOyojalUS51SqNc3o5Us0njhPdewW031UNGZibiLyZoq4TzFq/BghnDcH21imjU6jmIh+OULVPKfljb5Z/i4TTzl67DsLFfaCt9Le68CU0a1sbdTRvB17eY06Xxp/njtMtfbVt+abwQfwljps7Dqp9/1y5PtW0vPd1ee2IqpdGRb4Zi+/y8aQf6vTvVHuiQ159Cx4eaF9rlZ19/j7HT5tvHc99Qu3r9NvQePPGqudtWzUBggD8ojYqF76R2KI1OAulhh/EEafx38TwUj5mJsufP2tPZU78hqrz9IUKjrlxi6GHRuex0KI0uQ+vWB6Y0yo2P0iiXtyPVCrun0fbEUyFaTz7eGrc80BOPt22Ols1uyndYHzS7tYH2u207/9Eua9287W+cjr2gPcn062nvQBzLkQfh5D7wtVYa9aSxc6/3cOzEGbz5SlftfsfIUuFo3bkfOre/l9LoyJdCtX3EkvVd7Xvj5Wfao2uHe7UbZF8dPMl+PXL+fm3XMU98rzfuvr0hVqzegjdHTMfSWR/guirl8dP6P/DWiBnav4jk3qpUjNIu6aI0qvYNcE4/lEbncFT9KPFnTuBy7EmElquM0NJRuu26uzSKS2q2jR+Oxsu/zXOu58IjkPjqQFS9615dBtwhLwFKI78RBRGgNMr9XlAa5fJ2pFph0nji1Fm0eqKf/ZLOZo+8giaN6mLc0F55Div+/0r8PTsjI1NbVRSb+N38JWvx7vhZ+Gb6UNSqURkNWz6Ld/p0R6d2LRxpC0alMbxkCG598EX0eeFxPNflQXst0T+l0SH06u0kVhl7vTUe21fNQEBA9uUxD0QP0ASya4dWVzUsnookXj6aWwoffnIgHmt7N7o/3lqTRrEsvv67SQWeLKVRve+AMzqiNDqDorrHSEtLxf4VX6FsUizKBPjgdCpwIbwSatz7OMRLfgvb3F0aM9LTsHvih7hh+cI8pxgXUhJxfQbhuub3qRuaop1RGhUNxuK2KI1yA6A0yuXtSDWbNIoVRbEqJ+4/PHn6HOYs/Ann4y5h0WfvaZecfrVoNYZPmI1nOz+gPQwnNTUdf+7eD/H3eXGf4zN9RuKupg2113YE+Pvj869XaA/AWbvgI0RFhmv3PCZcTsagV6MRf+kybm5Y+5q3mRmVRtGreFWHb7FieL1nJ+2y/G+//wUr1mwBL0915Buh4D7i2ucv5q3A9zEj7d29MmgCqlUurz2JKf/20YwF2iN0xYs7bZu4HLVC2UiIJz4JaRQrleKloeLFxeLL2Lp5E/sX8uT5JAUpsCWzBPyL+SAsJABnL6aYPRTnK0jgxLb1KHdoM8oFXHkdwH/JWbh8430oc413jZUuGYiLl9OQlpGp4Fk51tI/i75Gmc8mo+TlBPuEA3XqI2rwh4goX8mxg3AvO4Egf18EBfoiLiGVVEjATqBsRHHExiUhM+fdcETjWgLlSxV3bQEevcgECnoQjngITqP6NfHSU+1Qo1pF7ZhiJXHOwh8x6bNFee4TFBIpXqshbh8Tt5HZtpsa1NIeOmN7kI74O/wHk+bg4OET2i7iqarBxQt/CJdNGqeN7Ku9+kNstqsOV38zDuVy3Vspjv1cv9GCfUN4AAAgAElEQVRY9fUYVCwXqT0Y591xX+LYyVhtXttWTbWnp4qrG1/s3k57QM/N97+ADwe+oAmwp20+WWKt14O2mV8t197lknvlUNzfGBJcHEP7PXXVmYp3sYgXjYplbXGj7pHjp/Hl/B/w4L1NNWncufeQ9ojdsNASOHH6nLYs3qV9Swx6tZt2LM+i50FfBLOn4gMInWC+ZkG6fn5aWlqed8TpVRTvkNu6eC5uuvgvfHO9Qi4pE9hX9gbc1KZ9oYcQr5zT/gcz3/9qXrwYj+M7dyMjJQWVGjVEeKkrN9Lr9SN7PDk5Gesmf4ySu/5EiVMncKFWPYTd2wqNH2onuxWPqGd7DSH/t8Ij4nTaSWj/W+FRf7tyGhqXHMhLXwfqEpZWHVToiHggpfhzUzqipP2SVNFPekaG9o7GEsFBKBkSXGCLZ87GITQk+JrvaHTGuYk+/zt6CqUiSmpu4E2bx0ljUVcaRdjiXxLmLl6tPT63zvVVMHvBKgx4qbN2eWr+beH3v2DwqM+wY/Wn2mojL0/1zD8uvDxV/VxTEhNwasNKpMceR3KWD0pWqo6Kd9yPYn5+us3vX7sY/7u4H8VzXYl6IS0L+8s3RtXbCr+vr6DLU49u3YT/Pp+JkL37UCw9HQnXVUfUE11R8/62un1YuUPchXNIvHxZe+VG8eIF/5+wlf25S21enuouScntk5enyuXNy1Pl8mY17yTgcdJou6fxzx9nwt8/+y+PrTv3R/fH7yvwnsb8sYsnNHV7ZYR2g229WtWu+las37JTu376j5XTtRd7Uho98w8OpVH9XHfMnYybT/+NCKRpzR7xCcKxGrfg+rbRus2fOrgHgdu+R53iV5YC/kz2R8AdHVC6fOVC5xckjb8MeROVvsn7YJkTLe5BkzETEBjES6Z0w3DzHSiNbh6gi9qnNLoIbCGHpTTK5c1q3knA46TR9o4UsVLYpYCnp4qH3oiH34wd0gtVK5XVUhdL2hHhofj38Am8M+oz7cbaScNf1cbEDbq1a1TWBDL+UgL6vzsN/n6++Gz8AG2c0uiZf3AojWrnGncuFulzR6NeelyeRreUrIYKXfroypq4vOTY338g4fA+lPXLxIl0X5Sq2RAVata/5onnl8ZzZ8/gv14vIGLX7jzz4iqUR9lPZqBijdpqg2R3pglQGk0j9MgDUBrlxkpplMub1byTgMdJo4hxzYbtEA+/sW1vv9YNnR/JfnH12o3b8fLACVj46XuaDIqtU49h2LXvkHbjbPs2d2pPRRLvYBTbuE/m49O5V27AvbFeDYwe3FN74hOl0XP/0FAa1c725N6/ELVyBspn5X1Q0QH/CKQ/0Q+lSmf/+dTbxNPP4uMvoFSpSL1dtfH80piUeBnb3+iDcmvW5pl/5ob6qPPJZwiPUPfeRodOmDvpEqA06iLyyh0ojXJjpzTK5c1q3knAI6VRRCmexnQq9jyiSofbL1MtLOK4+AQkpaSiXJkI7Z0w+TfxmODYc3EILRGM8LCQPMNcafTMPziURrVzFbIWO2cMbr58PE+jayPro3509lUCrtgKujx189QJCP5qLkLOndNKppQIxpmOj+Pu/m+7ogUeUzEClEbFAlGkHUqj3CAojXJ5s5p3EvBYaZQVJ6VRFmm5dSiNcnkbqfbvxp9Q4q91qJhyASkohqMlyiD4jocRVbeRkcM5NKcgaUxLScHehfNw8cB++KanI6j6dajdoSOKlwxz6Jjcyb0JUBrdOz9XdU9pdBXZgo9LaZTLm9W8kwCl0WTulEaTABWdTmlUNJh8bV04G4uLxw7A1y8AJStfh5JhES5tvCBptBVMT09HRkYaAgP58BuXhqDYwSmNigWiSDuURrlBUBrl8mY17yRAaTSZO6XRJEBFp1MaFQ3G4rauJY0Wt8byFhGgNFoEXvGylEa5AVEa5fLWq7ZmzRqI/1ixtWjRAuI/3JxPgNJokiml0SRARadTGhUNxuK2KI0WB6BgeUqjgqEo0BKlUW4IlEa5vPWqzZo1C4tGj0fJ0+eBrCzAxwfiqeXac0Nc+DmhXGk80r8Punfvrtcixw0QoDQagJZ7CqXRJEBFp1MaFQ3G4rYojRYHoGB5SqOCoSjQEqVRbgiURrm89aoJaVwx7ENEHjqmiaLwxOwtWxxd9fls9QpoM+QtSqNeQAbHKY0GwdmmURpNAlR0OqVR0WAsbovSaHEACpanNCoYigItURrlhkBplMtbr5qQxpXvfoio/07YVxZtK4zZPzV/1FYg8/7e9tnY+JnqFdH6nTcpjXoBGRynNBoER2k0CU7x6ZRGxQOyqD1Ko0XgFS5LaVQ4HAtbozTKhU9plMtbr5qQxh/f/RBl/zuR44dZ8IFPtidqPuiazyerVcB9lEa9eAyPUxoNo8ueyJVGkwAVnU5pVDQYi9uiNFocgILlKY0KhqJAS5RGuSFQGuXy1qsmpPGndz9EhcMntF01YbStMLrw84nqFXDvYK406uVjdJzSaJRczjxKo0mAik6nNCoajMVtURotDkDB8pRGBUNRoCVKo9wQKI1yeetVE9K45r2RqHT4uH1tMdc1qbmmX1l7dMb4sarl0YLSqBeP4XFKo2F02RMpjSYBKjqd0qhoMBa3RWm0OAAFy1MaFQxFgZYojXJDoDTK5a1XTUjjuvdGosqREwXfsljYrYwmf3+0WgU0f3sA72nUC8jgOKXRIDjbNEqjSYCKTqc0KhqMxW1RGi0OQMHylEYFQ1GgJUqj3BAojXJ561UT0vjL+yNRVVyeWujDbkwaYgHHPVylPO6iNOrFY3ic0mgYHVcaTaJTejqlUel4LGuO0mgZemULUxqVjcbSxiiNcvFTGuXy1qsmpHH9+yNx3dGTuVYar7xuI9v3nP/5v6oVcOcgrjTq5WN0nNJolFzOPK40mgSo6HRKo6LBWNwWpdHiABQsT2lUMBQFWqI0yg2B0iiXt141IY0bho9EjSMnc93TaJtle9+G8z//W6U8bi9EGtMzMnDu/EWULROh1z7HCyFAaTT51aA0mgSo6HRKo6LBWNwWpdHiABQsT2lUMBQFWqI0yg2B0iiXt141IY2bho9CzWNipTHX6zVsK4y21284+fPBKuVx28A38tzTKGTxg4lzsOrnrVrboSHBePnpDnig5a16p8HxfAQojSa/EpRGkwAVnU5pVDQYi9uiNFocgILlKY0KhqJAS5RGuSFQGuXy1qsmpHHLiFGodVSsNMrb/qlcHrfmk8YFy37GyMlzsXLuaJQKD8WiFesxYuIc/LzwIwQXD5LXnAdUojSaDJHSaBKgotMpjYoGY3FblEaLA1CwPKVRwVAUaInSKDcESqNc3nrVhDT+NmIU6h47BSD7tRq2exhtc698dt74vsrl0SSfNE754jssXrkBS74cgcAAfxw5fhptug7Aqq/HoGK5SL1T4XguApRGk18HSqNJgIpOpzQqGozFbVEaLQ5AwfKURgVDUaAlSqPcECiNcnnrVRPS+McHo1D36Knsh6fmeVvjlXsas7JyHq7qpPG/K5XD/97Ke3mqkMSuL72PyFJheCH6IaxYu0VbYfxw4At6p8HxfAQojSa/EpRGkwAVnU5pVDQYi9uiNFocgILlKY0KhqJAS5RGuSFQGuXy1qsmpHHbB6Nww/HT4jGp9tdu+PhkrzgW9hoOs+O7K5VH47f657mnMSk5FQOGT0NiUgr+PXwCp2MvYOJ7vdGy2U16p8FxSqNzvwOURufyVOVolEZVklCrD0qjWnmo0A2lUYUU1OuB0ig3E0qjXN561YQ0/vnhaNwoLk+1LSxK+LmzQjk0zCeN46d/gx1/H8Rn4wZowjrrm5UYM20evvv8fdSsXknvVDieiwBXGk1+HSiNJgEqOp3SqGgwFrdFabQ4AAXLUxoVDEWBliiNckOgNMrlrVdNSONfH45GoxOnc72P0fZeRtf9/KtiOTR4M+9KY6cew3DTjbUw4KXOWtuZmVlo0OJpvNOnOzq1a6F3KhynNDrvO0BpdB5LlY5EaVQpDXV6oTSqk4UqnVAaVUlCrT4ojXLzoDTK5a1XTUjjrhxpFAuMts12b6OrPm+vUBY35JPGYeO+xE+//I45kwejcoUy+PGXP9BnyMd8EI5eiAWMc6XRALTcUyiNJgEqOp3SqGgwFrdFabQ4AAXLUxoVDEWBliiNckOgNMrlrVfNJo3/O3lG6krj9orlUH9Avzz3NMbFJ+CjGQuwfPVmre2qlcriqY73o22rpnqnwfF8BCiNJr8SlEaTABWdTmlUNBiL26I0WhyAguUpjQqGokBLlEa5IVAa5fLWqyak8e+RY/C/E6f1dnXq+B8VyqJePmm0FUjPyMDZ8/EoV6aUU2t608EojSbTpjSaBKjodEqjosFY3Bal0eIAFCxPaVQwFAVaojTKDYHSKJe3XjUhjXtGjsHNJ89oT0/N/1RUV33+vUJZ1C1EGvV65rg+AUqjPqNr7kFpNAlQ0emURkWDsbgtSqPFAShYntKoYCgKtERplBsCpVEub71qQhr3jhyDJifP2B+eaptz5S2N2b9x5uet5aNQh9KoF4/hcUqjYXTZEymNJgEqOp3SqGgwFrdFabQ4AAXLUxoVDEWBliiNckOgNMrlrVdNSOO+kWNw66lYqfc0bq1QFrXeeD3PPY16vXLccQKURsdZFbgnpdEkQEWnUxoVDcbitiiNFgegYHlKo4KhKNASpVFuCJRGubz1qglp/GfUWNwmLk+VuG0pH4WalEaXEac0mkRLaTQJUNHplEZFg7G4LUqjxQEoWJ7SqGAoCrREaZQbAqVRLm+9akIa948ai6anYgFkv2gjK+feRnGPI3x8tHsdtZ9OHBfSeD2lUS8ew+OURsPosidSGk0CVHQ6pVHRYCxui9JocQAKlqc0KhiKAi1RGuWGQGmUy1uvmpDGA6PG4nYhjc68aVEUvsbxNpUrgxqURr14DI9TGg2jozSaRKf0dEqj0vFY1hyl0TL0yhamNCobjaWNURrl4qc0yuWtV01I48FRY3Hn6bNS72ncWD4K1/Xvy3sa9QIyOE5pNAjONo0rjSYBKjqd0qhoMBa3RWm0OAAFy1MaFQxFgZYojXJDoDTK5a1XTUjjodHjcMepWPvC4JULUXMuSLVdoWq/QNV2oarx8V/LlUF1SqNePIbHKY2G0XGl0SQ6padTGpWOx7LmKI2WoVe2MKVR2WgsbYzSKBc/pVEub71qNmm863Rszh2Lue5pzHMPo00UnTMupLEapVEvHsPjlEbD6CiNJtEpPZ3SqHQ8ljVHabQMvbKFKY3KRmNpY5RGufgpjXJ561UT0nh49DgIacx+6I1thu0hOK75/EvZSFSlNOrFY3ic0mgYHaXRJDqlp1MalY7HsuYojZahV7YwpVHZaCxtjNIoFz+lUS5vvWpCGo+MGYfmp8/l3NOYa0URWfART1O1/dSequqc8V/KlkHlfn14T6NeQAbHKY0Gwdmm8Z5GkwAVnU5pVDQYi9uiNFocgILlKY0KhqJAS5RGuSFQGuXy1qsmpPHomPFobl9pFGIoLkG1vW3D9vnK6zecMb42KpLSqBeOiXFKowl4Yiql0SRARadTGhUNxuK2KI0WB6BgeUqjgqEo0BKlUW4IlEa5vPWqCWk8NmY8Wpw5m++exvz3MDr387qykajIlUa9eAyPUxoNo8ueSGk0CVDR6ZRGRYOxuC1Ko8UBKFie0qhgKAq0RGmUGwKlUS5vvWpCGo+PHY+Wp89euadRe3zqlZXF7GtSc93j6ITxNWVKowKlUS8ew+OURsPoKI0m0Sk9ndKodDyWNUdptAy9soUpjcpGY2ljlEa5+CmNcnnrVRPSeGLseNx75pzerk4dXx1VGuVf5z2NToWa62CURpNkudJoEqCi0ymNigZjcVuURosDULA8pVHBUBRoidIoNwRKo1zeetWENJ4c9xFaxcqVxp/KlEa5vq/xQTh6ARkcpzQaBGebRmk0CVDR6ZRGRYOxuC1Ko8UBKFie0qhgKAq0RGmUGwKlUS5vvWpCGk+N/wj3nT0vrknNeQiOeO+Gdg2qyz7/GFkaZftQGvXyMTpOaTRKLmcepdEkQEWnUxoVDcbitiiNFgegYHlKo4KhKNASpVFuCJRGubz1qglpPP3RBLQ+J1YahSjaNtvrNq58dub4qtIRiHqN0qiXj9FxSqNRcpRGk+TUnk5pVDsfq7qjNFpFXt26lEZ1s7GyM0qjXPqURrm89aoJaTwzYQLanL9w5X2MuVYY87ynMfd7G7XXcuR7j2MRxleWKoUyr77Ky1P1AjI4Tmk0CM42jSuNJgEqOp3SqGgwFrdFabQ4AAXLUxoVDEWBliiNckOgNMrlrVdNSOPZiRNw/4ULORekivVEnxyBtL1mI/9P8+MrIsIR2ZvSqJeP0XGXSOMns5firz0HHepp9OCeCC4e5NC+Ku5EaVQxFfM9URrNM/TEI1AaPTFVc+dEaTTHz1NnUxrlJktplMtbr5omjZMm4sG4uGxRtK8g5ohi/hVFJ42vCI9A6Vd6F7rSmJmZhTPnLqBE8SCEhgTrnQbH8xFwiTROj1mKnXv+dQj2yLd7UBodIsWdZBKgNMqk7T61KI3uk5WsTimNski7Vx1Ko9y8KI1yeetVE9J4/uOJeCA+Lt8djfnvYHTu5+Vh4Sj18tXSeCkhEcMnxmDpqo1a662bN8G4oS/pnQbHZUijN1HmSqNnpk1p9MxczZ4VpdEsQc+bT2n0vEydcUaURmdQdPwYlEbHWcnYU5PGyZPw0KU4ZGUBPj6Q8nN5yXBEvPRKnpVGsbrYscdQ+BYrhmc6t0GzWxsi4XISoiLDZaDwqBouWWn0KEI6J0Np9My0KY2emavZs6I0miXoefMpjZ6XqTPOiNLoDIqOH4PS6DgrGXsKaYybIqQxXkY5e42loWEI75VXGtds2I5XBk3A9zEjUbVSWan9eFoxl0hj36GTsXLdVodYbVw6GWGhJRzaV8WdKI0qpmK+J0qjeYaeeARKoyemau6cKI3m+HnqbEqj3GQpjXJ561XTpHHqJLS7fNG+xKg9FTXXkqMrPi8NCUfYiy/nWWkcOXkuFiz7GfffcwsO/HccZUqH4dnOD6JhvRp6p8HxfARcIo1rN27HsROxDsHu+PA9CAzwd2hfFXeiNKqYivmeKI3mGXriESiNnpiquXOiNJrj56mzKY1yk6U0yuWtV01I48VpH6Pd5fica1NtM2zXqrrm8+ISJVGyZ15p7D14IvYdOIqnOt2PspER+GHtb1i+ejOWzfoA1auU1zsVjuci4BJp9CbClEbPTJvS6Jm5mj0rSqNZgp43n9LoeZk644wojc6g6PgxKI2Os5Kxp5DGS598jEeSLsm5mTFnBfO74DCE9ngpz0qjkMaK5cpgwEudtVPPyMhE80dfxYtPPoIu7VvKwOExNaRJo7jpNCk55SpwkaXCsper3XSjNLppcDptUxo9M1ezZ0VpNEvQ8+ZTGj0vU2ecEaXRGRQdPwal0XFWMvYU0pgwfTLaJ128Uk78VT8rV3UXfF4UVBIhL+SVxrHT5mP/oaOYNvJ1uzTe1rYXXnr6ETzV8X4ZODymhsul8XTsBfR+eyJ27TtUIDTe0+gx3yWPOhFKo0fF6bSToTQ6DaXHHIjS6DFROvVEKI1Oxal7MEqjLiKpOwhpvDxjMh5NuZTz1FQfiHsYtfdvaFeoZn++coujc8YXBoWixPN5pXHH3wfRpdd7mD66H25pVAffrfwVQ8d8gQUzhqFuzapSubh7MZdL47BxX+KnX37H813bQtyM+v6AZxERFopxn8xHuahSmPxBH/j7+botR640um1012yc0uiZuZo9K0qjWYKeN5/S6HmZOuOMKI3OoOj4MSiNjrOSsaeQxsSZUzRptImhra4rP38bGIrg53rluTxV1P386xUYM22e/dSFi7Rv00wGCo+q4XJpbP/M22jb6nZ0e7QVGt/3PJZ8OQI1qlbAz5t2oNdb4/Hb99NQIjjIbaFSGt02OkqjZ0bn0rOiNLoUr1senNLolrG5vGlKo8sR5ylAaZTLW6+akMakT6fg8bSEAt7PmP0U1cLf32h8/NuAEAQ9e7U0in6TU1IRey4O5aJKu/VilR57V467XBpbd+6PZ7s8iI4PNUeTNj0xanAP3HN7Yxw7GQsx9tWUwW792FtKoyu/ntYdmyuN1rFXuTKlUeV0rOmN0mgNd9WrUhrlJkRplMtbr5qQxuTPpmrSmOstG9cQxZyHrNoermrw53y/EAQ98+JVK416/XLcMQIul8bOvd5D4/rX442XOkO8vzEuPgFjh/bC0lUbtctVf5o/DuWjSjnWrRP3Sk1Nw4X4BERFhjv0IJ5zFy7Ct1gxhIeF5OmC0ujEUBQ6FKVRoTAUaoXSqFAYirRCaVQkCMXaoDTKDYTSKJe3XjVNGj+fik4ZichCFnzgk/en7Z7G/L+3fTY4/o1vCAKf7klp1AvI4LjLpXHip99i38GjmDziNdhuRrX12rp5E4wb+pLB1o1NEzfeTp21BJM/X6QdoFR4KD4e8Vqhq53HT51F3yGT7Q/yadKoDsYO6YXSESW1+ZRGYzmoPovSqHpC1vRHabSGu8pVKY0qp2Ndb5RGuewpjXJ561UT0pjy5TR0zEzU29Wp4/OLBSPwSUqjU6HmOpjLpTF/4/sPHcPmP/5G7RpV0KRRbYdW+Zx58tt37Uf0y8Mxe9JANKhzHSZ+uhDLV2/CT/PGoVixq1/9IZ6wdCr2HIb1ewaBAf7o8cZY1KhWASPeep7S6MxgFDsWpVGxQBRph9KoSBAKtUFpVCgMhVqhNMoNg9Iol7deNU0aZ32CTkjKeUqqT6Hva8x+iqpzxuf7BCOgew+uNOoFZHDc5dK4Z/9hrFizBY+1bY4qFaPsbU6PWYoypcOlP71IvK9lz4HDmDmmv9bLmbNxuOex1wp89O7FhEQ0bdsLUz7og7ubNtT2X/PrNrwiXiGy9nPtS86VRoPfPMWneYM0nvn3AC4cOYKydeoivFx5xRNRoz1Koxo5qNQFpVGlNNTphdIoNwtKo1zeetWENKbOno6OPkl5Lk3NflFjvktVc302Oz4vKwgB3V6gNOoFZHDc5dI46MOZ+Puf/7Bgxrvw9S1mb/OrRasxfMJs/P7DdBQPCjDYftGn9Xt3KiLCQjDo1W72yfWbP5VHDG0DCZeTcOuDL2ovBG12awPt13sPHMGjz72DXxZN1C5RpTQWPQN3mOHJ0piSmIgfRwxF2m9b4X8hDqnlyqJ0q1Zo9vJrKFbMfV9/I+N7RWmUQdm9alAa3SsvWd1SGmWRzq5DaZTLW6+aJo0xM/CEb8qVexlzVhTt9zi64PP8rCD4d32e0qgXkMFxl0vjw08OxMOt78BzXR7M06J47G3zR1/Dwk/fQ+0alQ22X/RpL/Qfo10a+3rPjvbJ4qmuQ/s9hQdb3nbVAV98czz2HTyCV57pAH8/P6z6ZStWr99ml8b0jMyiN8EZyhMQN22Ly5UzMj0v33XTZ+Lf0WPhf/a8PYfk6lVx15SJqH3b1X8GlA9LYoPiYViZWVnZLyn2kC09A3DjV+VanoK44kRcWZWZ6TnfCcuhekADfr7FwL8fyAtS8OamDgFNGr+aqUkjct/5lb3QeGVz8ud56YHw7/IcpdFFXwWXS2OnHsNQr3Y1DOn7ZJ5T+OOvf9C99wgsnfUBrqsi79I4sdIoHn4zsHe0vZ/CVhrFDpcSEjHzq+XaQ3xCSxRHWno61m/Zab889Uxcioui4WGtJCD+El0y2B/nL6VZ2YbTa2dmZuLHUcORPuWTPMfOKBGMMgPeRNOnnnF6TU86YESoPy4lpSM9nYLgSbmaOZcg/2IIDPBF/GXP+t8KM0w4FxBXJZy/mAL+W4Kcb0NUeKCcQqziEAFNGufOROeANPs9jbZ7F135U5PGJ56lNDqUUtF3crk0itdqzPpmpfY+xhtqV9cuURX3Eb4z+lP88dd+bFzyMfz9/YreucEZ4p5GsXI4fXQ/7QjXuqexoBLP9BmJEsFBmDT8VW2Yl6caDELxaZ58eeraiWORPHkKiqVe+UtuWqkIVH7nHTRs96jiyVjbHi9PtZa/itV5eaqKqVjfEy9PlZsBL0+Vy1uvmpDGtHmf4YmA1JylxSuv3cheanTN57mpfvDvRGnUy8fouMulMf7iZbR/9m2cjr2A4OJBqFQ+Ev/8e0zr98OBL+Ch+2432ruheVeenjoIDepehwkzF+D71ZvtT0/9Yv4P2uWn4umqYhP3NYrLj9IzMrDsx40YMXEOvp42BA3qVKc0GkrAPSZ5sjTu37Qeu98ZjOIH/rWHkXLXHbj9w7GILF/BPQKyqEtKo0XgFS5LaVQ4HAtbozTKhU9plMtbr5omjfM/Q+egdG1X7T2N4rYOcS2/TRi1z9lHctb41yn+8Ov4NFca9QIyOO5yaRR9JSYlY97itdi59xCSklNQrXI5tL23KerXrmawbePTxJf2488XYdqsJdpBhMhOH/06Gt9QU/s8esrXmL90HbaumKZ93rB1F8R9kGKrUbUChvV/2r6v+B1XGo1nofJMT5bGrMxM7F77E05u3Qzf07HIrFIZNVu1RtUbsp8QzK1wApRGfjvyE6A08jtREAFKo9zvBaVRLm+9akIa0xd8js5BGS69hzHnYaz2duYm+sLvcUqjXj5Gx6VIo9HmXDkvOSUV5y9cRLmo0gW+n9FWW6wwnjx9TntSqhDM/Bul0ZUpWXdsT5ZGG9WM9HRcuhSP8IjS1oF2s8qURjcLTEK7lEYJkN2wBKVRbmiURrm89app0vjtF+hSIlPqPY1fJ/rC99GnuNKoF5DBcSnSuGX7HixasR6Hj51Gz24Pa+88HDNtHkqHl8TTT7Qx2Loa0yiNauTg7C68QRqdzcwbjkdp9IaUi3aOlMai8fKWvSmNcpOmNMrlrVdNk8aFX6JLiHgCffYlqTJ+zk3wgW+HJ5fQrB0AACAASURBVCmNegEZHHe5NO7e9x869hiKsmUicCkhCe/06a7dx2h7T+MfK6cjKFDeexoNcip0GqXR2UTVOB6lUY0cVOuC0qhaItb3Q2m0PgMVO6A0yk2F0iiXt141TRoXzULXklk5vph9T2POLY3avY2u+KxJ4yPdKY16ARkcd7k0Dh71GeIvJWDCu6+gxxtj8VCr2zVpPHTkJNp2fwtLvhiOGtUqGmzf+mmURuszcEUHlEZXUHX/Y1Ia3T9DZ58BpdHZRD3jeJRGuTlSGuXy1qsmpDFj8Wx0KWl/9o02RVtvzLXwmOvZOE4Zn3MR8G3XjdKoF5DBcZdLY7NHXkGfFx5Hhwfu0h4oY5PG83GXIMYWzBiGujWrGmzf+mmURuszcEUHlEZXUHX/Y1Ia3T9DZ58BpdHZRD3jeJRGuTlSGuXy1qumSeOS2YiOKCb1nsav4oFiD0VTGvUCMjjucml8rt9o7SEyIwf1yCONy37chAHDP8HmZVMQGhJssH3rp1Earc/AFR1QGl1B1f2PSWl0/wydfQaURmcT9YzjURrl5khplMtbr5qQxsxlc9A1IuedGtoE2xKjbbbzP8+5kIFibSmNevkYHXe5NP74y+947Z2P0aV9S2zZtgfNb2+EUuElMXrq13jk/jsx/M3njPauxDxKoxIxOL0JSqPTkXrEASmNHhGjU0+C0uhUnB5zMEqj3CgpjXJ561XTpHH5HESX9kX2JahX7mF05eevzmfA58GuXGnUC8jguMulUfQl3nso3n8o3tdo2x5seRsGvdYNYaElDLauxjRKoxo5OLsLSqOziXrG8SiNnpGjM8+C0uhMmp5zLEqj3CwpjXJ561XTpPH7rxAd6ae3q1PH55xNh88DXSiNTqV65WAul8ZNv+/GxYTLuOf2xjh26qwmjpXKlUF4WIiLTknuYSmNcnnLqkZplEXavepQGt0rLxndUhplUHa/GpRGuZlRGuXy1qumSeOKuYiOCkDOUqP207biqD0Nx/YUnFw/zY5r0nj/E5RGvYAMjrtcGvsOnYyEy0mYPrqfwRbVnkZpVDsfo91RGo2S8+x5lEbPztfI2VEajVDz/DmURrkZUxrl8tarpknjynnZ0ihxm3MmFT6tO1EaXcTc5dI45cvFWPzDr1g5d7SLTsHaw1IareXvquqURleRde/jUhrdOz9XdE9pdAVV9z8mpVFuhpRGubz1qmnSuGo+ossGarvaVxBzJrrq85zTKfC5r2Oh0vjzph3o9dZ4TPmgD+5u2lDvNDiej4DLpfHs+Xi06ToA44b2QrNbb/S4ACiNHhepdkKURs/M1exZURrNEvS8+ZRGz8vUGWdEaXQGRcePQWl0nJWMPTVp/PEbRJcLyn4xo7gE1ba58POcU8nwafV4gdK47+BRRL88XLtNjtJo7Fvgcmns9+5UrFizpdDuNi6d7NYPw6E0GvviqT6L0qh6Qtb0R2m0hrvKVSmNKqdjXW+URrnsKY1yeetV06TxpwXoViFY6nsa55xMgs+9j10ljbHn4tCp5zD0faEjho37EmPeeZErjXohFjDucmlcvX4bjp44U2hrndu3RGCAv4HW1ZhCaVQjB2d3QWl0NlHPOB6l0TNydOZZUBqdSdNzjkVplJslpVEub71qQhqzVn+LrhWvvCHB+W9lBHKtX2pvgYw5fhk+LR/NI41Jyal46tUPtKsdX36mPZq06Ulp1AuwkHGXS6PBvtxmGqXRbaIqUqOUxiLh8pqdKY1eE7XDJ0ppdBiVV+1IaZQbN6VRLm+9atpK45qF6FY5VO5Ko5DGe9rbpTEzMwviikexidXFYsV8KI164V1jnNJoAp6YSmk0CVDR6ZRGRYOxuC1Ko8UBKFie0qhgKAq0RGmUGwKlUS5vvWraSuO679C1Ukj2Q3DEw3CQvTKY56ftNRxOGo85egk+zR+xS+OZs3G457HX8Fjbu1GieJDW9pffrETz2xvh4fvuQOvmTfROheO5CFAaTX4dKI0mASo6ndKoaDAWt0VptDgABctTGhUMRYGWKI1yQ6A0yuWtV01bafx5MbpVKVm4MBYmiiZ+P+fIRfjc3c4ujeKhNzHf/pin3Qkzv0XbVk3R9t6mHvmATr1szIxTGs3Q40qjSXrqTqc0qpuNlZ1RGq2kr2ZtSqOauVjdFaVRbgKURrm89appK42/LEHXqmFXVhZzPTW1wJVHJ4zH/BcHn7sevuZ7GnlPo156hY9TGo2z02ZypdEkQEWnUxoVDcbitiiNFgegYHlKo4KhKNASpVFuCJRGubz1qmkrjeuXolv1CLn3NB6Og8+dD1Ea9QIyOE5pNAjONo3SaBKgotMpjYoGY3FblEaLA1CwPKVRwVAUaInSKDcESqNc3nrVtJXGX5ch+rpSeXa1rTAWNt/seMyh8/C5o+01pVGvd44XToDSaPLbQWk0CVDR6ZRGRYOxuC1Ko8UBKFie0qhgKAq0RGmUGwKlUS5vvWraSuOG5eh2faTclcZ/z8Pn9gcojXoBGRynNBoEp9pKY2ZmJooVK2bybDjdRoDSyO9CQQQojfxe5CdAaeR3oiAClEa53wtKo1zeetW0lcZNKxB9fWT2rllZgLhn0ba56HPMgbPwadqG0qgXkMFxSqNBcKpI49GD/2D/pk1IjI9DVLXquLHFvQgqHmzyrDid0sjvAKWR3wFHCFAaHaHkfftQGuVmTmmUy1uvmrbSuGkFutWKyuWJWdrrN654o/M/zxHSeNv9lEa9gAyOUxoNglNBGg/u2I6lQ4Yg4a/dyLyUAL8ykajyyIPoOPR9BAQEmDwz755OafTu/As7e6408nuRnwClkd+JgghQGuV+LyiNcnnrVdNWGresRHQuabTPyfWU1AKPY2I85p8z8Lm1NaVRLyCD45RGg+BUkMaFo0Zg94SpyEpJtZ9FQPUqaD9lEmo3uc3kmXn3dEqjd+dPaWT+jhKgNDpKyrv2ozTKzZvSKJe3XjVNGn9bheg65a5cmmq7JNWFP2P+OQ2fJvdRGvUCMjhOaTQIzmppTEy8jIUD38K/MfPynEGxkGDcNeoD3NXxCZNn5t3TKY3enT+lkfk7SoDS6Cgp79qP0ig3b0qjXN561TRp3PoTouuWy7WruDS1oDc02nYxPx6z9wR8bm5FadQLyOA4pdEgOKulUdQXK41/T/oEmUnJ9rMIrFEV7SdPQq2bbzV5Zt49ndLo3flTGpm/owQojY6S8q79KI1y86Y0yuWtV02Txt9XI7p+hRxP9MlZcbR5o2s+x+w5AZ//taQ06gVkcJzSaBCcCtJ4ePdOfDfkHVzetRcZ8RfhV7YMKj/QCk+8OwJ+fv4mz8y7p1MavTt/SiPzd5QApdFRUt61H6VRbt6URrm89app0rhtDaLrV8q7q9kXMerMj9l9DD43taA06gVkcJzSaBCcCtIoejh15BD2rl+PhAsXUP7669HgnnsREBho8qw4ndLI70BBBPggHH4v8hOgNPI7URABSqPc7wWlUS5vvWqaNG5fi+gGVbJXGFHIpaf2h944Zzxm1zH4NG5OadQLyOA4pdEgOFWk0WT7nF4IAUojvxqURn4HHCFAaXSEkvftQ2mUmzmlUS5vvWqaNP75c7Y0Fnarogt+H/PXEfg0upvSqBeQwXFKo0FwlEaT4BSfTmlUPCCL2uNKo0XgFS5LaVQ4HAtbozTKhU9plMtbr5omjTt+QXTDald2zXNpaa57Gm17OGE8Zudh+NzYjNKoF5DBcUqjQXCURpPgFJ9OaVQ8IIvaozRaBF7hspRGhcOxsDVKo1z4lEa5vPWqadL416+IblRdb1enjsfsOASfBndSGp1K9crBKI0mwZ44l2TyCJyuIgFKo4qpWN8TpdH6DFTrgNKoWiJq9ENplJsDpVEub71qmjTu3IDom2rIfU/jn4fgc8PtlEa9gAyOUxoNguNKo0lwik+nNCoekEXtURotAq9wWUqjwuFY2BqlUS58SqNc3nrVNGncvRHRN12vt6tTx2O2HYRP/aaURqdS5Uqj03BypdFpKJU6EKVRqTiUaYbSqEwUyjRCaVQmCqUaoTTKjYPSKJe3XjVNGv/ehOiba+W8p1G8nzEL0J6WanuYqvM/x2w7AJ+6t1Ea9QIyOM6VRoPguNJoEpzi0ymNigdkUXuURovAK1yW0qhwOBa2RmmUC5/SKJe3XjVNGvdsQXSTWjmGaJuR/0WLzv0c8/s++NS5ldKoF5DBcUqjQXCURpPgFJ9OaVQ8IIvaozRaBF7hspRGhcOxsDVKo1z4lEa5vPWqadK49zdE31o373sa87+X0cmfY7bug0/tJpRGvYAMjlMaDYKjNJoEp/h0SqPiAVnUHqXRIvAKl6U0KhyOha1RGuXCpzTK5a1XTZPGf35H9C115b6nccse+NS6mdKoF5DBcUqjQXCURpPgFJ9OaVQ8IIvaozRaBF7hspRGhcOxsDVKo1z4lEa5vPWqZUvjH4huWv/KrrZ7Gm2/ccHnGCGNNW+iNOoFZHCc0mgQHKXRJDjFp1MaFQ/IovYojRaBV7gspVHhcCxsjdIoFz6lUS5vvWqaNB7YniONPuIpOLan3xRyj6NzxmM27YLP9Y2vksbMzCycj7sIf38/hIWW0Guf44UQoDSa/Grw6akmASo6ndKoaDAWt0VptDgABctTGhUMRYGWKI1yQ6A0yuWtV02TxoN/IvqOG+W+p1FI43UN80jjpt93o/fgSUhMStbabtKoDvq92Ak31K6udxocz0eA0mjyK0FpNAlQ0emURkWDsbgtSqPFAShYntKoYCgKtERplBsCpVEub71qmjT+uwPRdzbU29Wp4zEb/oJP9RvzSOPmbX8j9mwc7mraEMnJqXh3/JcQK49TP+zj1NrecDBKo8mUKY0mASo6ndKoaDAWt0VptDgABctTGhUMRYGWKI1yQ6A0yuWtV02TxkN/IbpZY23X7IekXnm9hqs+x/y6Az7VGlzznsalqzbizRHTsWP1p/Dz9dU7FY7nIkBpNPl1oDSaBKjodEqjosFY3Bal0eIAFCxPaVQwFAVaojTKDYHSKJe3XjVNGv/bhei7GucYo21Glks/x6zfBp+qN1xTGoUwHjh0HAtmDNM7DY7nI0BpNPmVoDSaBKjodEqjosFY3Bal0eIAFCxPaVQwFAVaojTKDYHSKJe3XjVNGg/vRrfmN2srjD4+PlJ+zvllG1ClXqHSaFtlnDmmP5renOvJrnonxHGNAKXR5BeB0mgSoKLTKY2KBmNxW5RGiwNQsDylUcFQFGiJ0ig3BEqjXN561TRpPLoH0XffnHNpqlhgtImj7dk4zv88e91W+FSuW6A0bti6Cy/0H4MhfZ9Ex4fv0TsFjhdAgNJo8mtBaTQJUNHplEZFg7G4LUqjxQEoWJ7SqGAoCrREaZQbAqVRLm+9atnSuBfdWtyC7NcxFrbSmF8g8+9XtPE567YClWpfJY0r1/2GvkOn4P0Bz6J9m2Z67XO8EAKURpNfDUqjSYCKTqc0KhqMxW1RGi0OQMHylEYFQ1GgJUqj3BAojXJ561XTpPH4P4hucSvEWxoL2648GqfgPYo6HrNmC1CxVh5pXLxyAwZ+MANvvtwFLe68yV4oIiwEwcWD9E6F47kIUBpNfh0ojSYBKjqd0qhoMBa3RWm0OAAFy1MaFQxFgZYojXJDoDTK5a1XTZPGE/vRrWVTZCELPvCBTQCv/um88TmrNwMVrs8jje+On4V5i9dc1TJXHfVSvHqc0lh0ZnlmUBpNAlR0OqVR0WAsbovSaHEACpanNCoYigItURrlhkBplMtbr5omjScPotu9t+vt6tTxmJ82AuVrXPPpqU4t6GUHozSaDJzSaBKgotMpjYoGY3FblEaLA1CwPKVRwVAUaInSKDcESqNc3nrVNGk89S+63XendlOi7Z5G21NxXPVZk8ay1SmNegEZHKc0GgRnm0ZpNAlQ0emURkWDsbgtSqPFAShYntKoYCgKtERplBsCpVEub71qmjSePoRu9zXLeS+juCg1Z/PxyX66jQs+x6z6FShbjdKoF5DBcUqjQXCURpPgFJ9OaVQ8IIvaozRaBF7hspRGhcOxsDVKo1z4lEa5vPWqadJ45jC633+3lPcz2lYuY1atB8pUoTTqBWRwnNJoEByl0SQ4xadTGhUPyKL2KI0WgVe4LKVR4XAsbI3SKBc+pVEub71qQhoRewTRbZpfWVAEtIfh2DbxVFVnf579w89AZGVKo15ABscpjQbBURpNglN8OqVR8YAsao/SaBF4hctSGhUOx8LWKI1y4VMa5fLWq6atNJ49iu4PtLjy1FTbvY2A9hqOLBd8jvlhHVC6EqVRLyCD45RGg+AojSbBKT6d0qh4QBa1R2m0CLzCZSmNCodjYWuURrnwKY1yeetV01Yazx1H9IMt87ynMf97F539efb3a4BSFSiNegEZHPdYaczMzMKZcxcQWSoMfr6+DuE5eeY8ykZGoFixa72KNO+h+CAch9C63U6URreLTErDlEYpmN2qCKXRreKS1iylURpqrRClUS5vvWraSuP5E+j+UKvsFUXtPY1XnqJquwfR/tNJ4zHLVwMR5SmNegEZHPdIafx50w70e3cqEpOSNSxDXn8KHR+6cl11flazvlmJOQt/Qlp6OtLS0tG+TTP07dFR2231+m3oPXjiVXi3rZqBwAB/UBoNfvMUn0ZpVDwgi9qjNFoEXuGylEaFw7GwNUqjXPiURrm89appK40XTqHbQ61sF6NK+Tl72SogvBylUS8gg+MeJ41Jyam4q31vvPxMe3TtcC/WbfwTrw6ehJVzR6NS+TJXYdq97z907DEUn49/E7c0roN/j5zEQ93fwldTBqNhvRr4af0feGvEDCyYMSzP3CoVo7T3zlAaDX7zFJ9GaVQ8IIvaozRaBF7hspRGhcOxsDVKo1z4lEa5vPWqadIYdxrd2t2f/XoNHx/7PYy2z/l/2u5xNDMes3QVEBZFadQLyOC4x0mjWGXs9dZ4bF81AwEB/hqWB6IHaALZtYP4F4+825bte/BMn5FYMWckqlQsqw02e+QVvNGrMx6673ZNGoeN/QLrv5tUIGJKo8FvngLT0tPTcXbn77h0cC+KBQSgZN1GKFOzntYZpVGBgBRsgdKoYCgWt0RptDgARctTGuUGQ2mUy1uvmiaN8WeypTH7sTe5prju8+wlK4GSZSiNegEZHPc4aZy/dB2+mLcC38eMtCN5ZdAEVKtcHq/3zL7kNPeWmpqGZ18fjb0HjqD3sx2QkJiEVeu24suJA1EyJFiTRrFS2a71HQgMDMDNDWujdfMm9vskKY0Gv3kKTNvz9XRU3roaUSkJSC3mi6OhpZHRpjMq3XkfpVGBfFRsgdKoYirW9kRptJa/qtUpjXKToTTK5a1XTZPGi7Ho/kgbbeHQvuXzRR+f7IVIZ43PXvIDEBpJadQLyOC4x0njzK+W44e1v+W5nFTc3xgSXBxD+z1VIKYZc5Zh6aqNKB4UiF37DuG5Lg/ilWc7aGK4c+8hrFz3G8JCS+DE6XOYv2QturRviUGvdtOOlZiSbhA9p1lJIO7cWZx8/3XUO3s0TxubbrgDt/QfpmUf4FcMyWkZVrbJ2ooRCPT3RVp6JjJz/l/O8UdmKXYiudpJz8yCXxEe/qXumVjTmW8xH+3haeJ7kXvL/fcgazpjVSsJFA/wQ3Jqep71FSv78fTawYF+nn6KbnV+mjReOotu7R4ovO/8C4759zQwPnvxCiC0NKXRRd8Wj5PGoq40rt/yF3oOGIdNy6ZoK4sbtu7Ca+98jH49O6JTuxZXYV/4/S8YPOoz7Fj9qSYWFy6luigaHtaVBI7s+B0R099HmeSEPGUOlq+BwNfeQ9moKAQH+eFSIv9RwJU5uNuxQ4P9kJiSgYyMbCXwBDGw30fibmEo0q/4x6UA/2JISMr7vxWe8A8KiiB2yzbCQgJw8XJq3lUUtzwT92g6IjTAPRr1ki6zpfEcurV/UFtKvOppqTn3OIp7HZ05HrN4BbJCSlEaXfQ98zhptN3T+OePM+Hvn/0vT60790f3x+8r8J7Gj2YswJpft2HJlyPsiF8a+BFKFA/CqME9r8K+fstO9BwwFn+snI6gwAA+CMdFX0xXHzb+wlkkjh2AeueO5Sm1sf4dqPXiIAQF+CE8JACx8SmuboXHdyMCvDzVjcKS1CovT5UE2s3K8PJUuYHx8lS5vPWqadKYcD5bGvNtttdvFHYMM+OzFy0HKI168Rge9zhpTExKQZM2PTDgpc7oUsDTU7f+uRcjJ8/F2CG9ULVSWXy/egv6vzcV00b2xZ23NMDRE7Fo0/UN9H/xCTzV6X58tWg1ateojHq1qiH+UgL6vzsN/n6++Gz8AA0672k0/N2zfOLfc6ej2tafUCYlAWk59zSmiXsam7XmPY2Wp6NmA5RGNXOxsitKo5X01a1NaZSbDaVRLm+9atnSeAHdO7TVrsixXWnq6p8xi5Yhq0QEVxr1AjI47nHSKDis2bAd4uE3tu3t17qh8yMttY9rN27HywMnYOGn72kymJmZhU9iluC7Fb/ifNwlhIYUx8P33YGXnm6vyeG4T+bj07nf2491Y70aGD24p/31HZRGg988Baalp6fhzF9bkfDvP/Dx90fJug0RVbO+dhkFn56qQEAKtkBpVDAUi1uiNFocgKLlKY1yg6E0yuWtV02Txstx6NbhIfuuhQmjbQdnjM9auBQoEU5p1AvI4LhHSqNgkZGRiVOx5xFVOtx+maoeoxOnzqJcVGntoQa5t+SUVMSei0NoiWCEh4XkGaM06lFVf7yge7oojernZkWHlEYrqKtdk9Kodj5WdUdplEue0iiXt141mzR2f6yd/f2Mtr9rufJnzMKlyAoOozTqBWRw3GOl0SCPIk+jNBYZmVtMoDS6RUzSm6Q0SkeufEFKo/IRWdIgpVEudkqjXN561TRpTIxHt0fbZT/rxnaJahZc+nnWgiVAcElKo15ABscpjQbB2aZRGk0CVHQ6pVHRYCxui9JocQAKlqc0KhiKAi1RGuWGQGmUy1uvmiaNSRfR/bFHtCcIyxLHmAWLkVU8lNKoF5DBcUqjQXCURpPgck3PzMxAWloaAgODnHdQk0eiNJoE6KHTKY0eGqyJ06I0moDnwVMpjXLDpTTK5a1XLVsaL6H74+21XW0rjbZ5rvo8e8F3yAoKoTTqBWRwnNJoEByl0SQ4AJmZmTj2zw4kxp9HUKA/sooFovz1NyAouIT5g5s8AqXRJEAPnU5p9NBgTZwWpdEEPA+eSmmUGy6lUS5vvWqaNCYnoHvHDnLvaRTSGFiiQGlMTU3DhfgEREWGaw885FZ0ApTGojPLM4OXpxoHuP/PjagW5o8qZSO1g1xKTMLGvUdww+2tUKyYr/EDO2EmpdEJED3wEJRGDwzV5ClRGk0C9NDplEa5wVIa5fLWq6ZJY8pldHu8g3Zp6lXv3cg5gO3SVWeNz56/8CppFA/emTprCSZ/vkirWio8FB+PeA0N69XQOw2O5yNAaTT5laA0GgOYmpqCYzs34I661fMcYN+RE0iPrIFSkeWMHdhJsyiNTgLpYYehNHpYoE44HUqjEyB64CEojXJDpTTK5a1XLVsaE9G906O5Vhpz7m203eNo/5mlrfzZ7300MR7zzbfICgjOs9K4fdd+RL88HLMnDUSDOtdh4qcLsXz1Jvw0b9xVb0vQOy9vH6c0mvwGUBqNAYyLOw+fU3tRp0r5PAc4ee4CTmeFomyVmsYO7KRZlEYngfSww1AaPSxQJ5wOpdEJED3wEJRGuaFSGuXy1qumSWNqErp3eixn1/x3MeY/gnPGZ89bgKyA4nmkcey0+dhz4DBmjumvFT1zNg73PPYaFswYhro1q+qdCsdzEaA0mvw6UBqNA9y7ZTXuql8NvsWK2Q/yxz//IbxmEwSXyPs+TONVjM2kNBrj5umzKI2ennDRz4/SWHRm3jCD0ig3ZUqjXN561ezS+ETH7GtTtZXELPgg51pVF32OEdLoH5RHGvu9OxURYSEY9Go3e9v1mz+FKR/0wd1NG+qdCscpjc77DlAajbM8d/o44o/sQZUy4Qjy98PxcxeRHBCKqnUaGz+ok2ZSGp0E0sMOQ2n0sECdcDqURidA9MBDUBrlhkpplMtbr5qQxr+2b0PDBvX1dnXq+I6du3Fj45vySOML/cegdo0qeL2nENjsrUmbnhja7yk82PI2p9b39INxpdFkwpRGcwATLycg/uxppKenomTpcggLjzB3QCfNpjQ6CaSHHYbS6GGBOuF0KI1OgOiBh6A0yg2V0iiXt161HTt2QPzHiq1hw4YQ/7FtYqVRPPxmYO9o+++40mgsGUqjMW72WZRGkwAVnU5pVDQYi9uiNFocgILlKY0KhqJAS5RGuSFQGuXydqdq4p7GfQePYProflrbvKfReHqURuPstJmURpMAFZ1OaVQ0GIvbojRaHICC5SmNCoaiQEuURrkhUBrl8nanaleenjoIDepehwkzF+D71Zv59FQDIVIaDUDLPYXSaBKgotMpjYoGY3FblEaLA1CwPKVRwVAUaInSKDcESqNc3u5UTTyA5+PPF2HarCVa28HFgzB99OtofIO1T+l3J4a2XimNJlOjNJoEqOh0SqOiwVjcFqXR4gAULE9pVDAUBVqiNMoNgdIol7c7VktOScX5CxdRLqo0389oMEBKo0FwtmmURpMAFZ1OaVQ0GIvbojRaHICC5SmNCoaiQEuURrkhUBrl8mY17yRAaTSZO6XRJEBFp1MaFQ3G4rYojRYHoGB5SqOCoSjQEqVRbgiURrm8Wc07CVAaTeZOaTQJUNHplEZFg7G4LUqjxQEoWJ7SqGAoCrREaZQbAqVRLm9W804ClEaTuVMaTQJUdDqlUdFgLG6L0mhxAAqWpzQqGIoCLVEa5YZAaZTLm9W8kwCl0WTulEaTABWdTmlUNBiL26I0WhyAguUpT6+NLAAAFbxJREFUjQqGokBLlEa5IVAa5fJmNe8kQGn0ztx51iRAAiRAAiRAAiRAAiRAAiTgEAFKo0OYuBMJkAAJkAAJkAAJkAAJkAAJeCcBSqN35s6zJgESIAESIAESIAESIAESIAGHCFAaHcLEnTyVQGpqGi7EJyAqMhw+Pj7XPM3MzCycj7sIf38/hIWW8FQkPC8AZ8/Ho0RwcRQPCiAPEtAIXEpIRHpGBiLCQh0mkpaWjjPn4lCmVBgCAvwdnscd3YOA+P+EM+cuILJUGPx8fR1q+uSZ8ygbGcGXiztEizuRAAmoRIDSqFIa7EUagaysLEydtQSTP1+k1SwVHoqPR7yGhvVqFNjDpt93o/fgSUhMStbGmzSqg34vdsINtatL65mFXE/gyPHT6DlgHA4fO60V6/DAXXin75Pw97v2XwjFPz48+/poJCWnYMGMYa5vlBWkERB/5ge8/wnWbNiu1byxXg1Mer+3JgqFbYeOnMQ7oz/Htp3/aLsM7tMdT7RrIa1nFnI9gZ837UC/d6fa/z9hyOtPoeNDzQstPOublZiz8CekpadD/GNC+zbN0LdHR9c3ygokQAIk4CQClEYngeRh3IvA9l37Ef3ycMyeNBAN6lyHiZ8uxPLVm/DTvHEF/gvw5m1/I/ZsHO5q2hDJyal4d/yXEP/KPPXDPu514uz2mgRe6D8GISWKY/ibz+PUmXPo2GMY3unTHQ/dd3uh88Q/QLw98lN898OvqFuzKqXRw75jM79ajm+WrsPsSYO0lecX3xyP6lXK4703ninwTE/HXkCLx/ugTYtb0aV9S9StWQ3JKSlFWqH0MIQedzpJyam4q31v/F979x5nc7X/cfxdnYNxv8vp8uv6ww8nlKT4RXIXkduQOzVuidwnxzAhZ1xGLg0jQnJNuTSTqWEk9xKF8isnKteEMEM0nMdafnv/xhhmb+nXmr1f669qf/d3r/X8fJuZ917ru749OjZW6yZPKmn9NvUaMlEr50Xp9uJFrhjvzt171fz5CM0cP1APly+pf31/UE+1HaS3pwy56heVAYfGgBBAIMsLEBqzfAkZwPUIjI1ZqK++3afpY/rZtx85ekLVm75o/+A3f/hn1pYnrNfAkdO0PfENn5clZXZOXv9zBX45laxHn+qutyaFq3yZ+21nRkyYo0NHjmniiF5X7Vzs3BWKS9yoBjUfVfyqTYTGP7eMN/zTm3YZqtrVKqpL6wb23CuTNqtPxBTtWD0zwyXt/5w8T8s/XK/V70Tzs+GGV8ONE5pZxm6DxuvzhFjvsuN6zw6wAbJ1k5pXdHLT51+pY+/Rip87WnfeVsy+XvXpnurfLfSaX0i5MVp6gQACCFwSIDRyJQSlgFlWVCBfboX3auMdf+lq7TVlVG89XvmBTE1MYPz2u/0EhEylss4Be/buV8P24Up6J1pFCuW3HZ+zOEFLV667ap0T1nyqyPGztCh2mD7esF0LlydxTWSdkvvU04p1w/TKgE42OJq263/2qtlzEVq/fHKG9zY3bDdYITmyq3ixQjp4+Gf7JVRYu4a6tUhBnz6Pg9wXMP+fv7kgXnFvjfZ2tmf4BN11R3G9FHblklPP8vWvv/1eL3RqotMpZ5SQtEWzXhusvLlzuj9geogAAggQGrkGglXALEMsce+dl/2CN38cRvRtr/o1Hrkmi2eW0cxSVn6odLASBty4PUuW04YB88dhzOylWrVo/BXj/fLr7+zswYzxA1S25N1auGw1oTHArgqz9LhM9Q6XfZnk+XLhowVjbTBM38yXT5XKl7L3rGXL9hfFzn3f3ve2dOYIu4kWLesLmCXLH6zefNkXROaLyNw5Q+zvkIyaWZFgfneYLxR27P5OnVvVV89OTZiNzvqXAyNAIGgEmGkMmlIz0LQC5he82fxm8AvPev+zLzON67bskAmcQ/u0U/OG1UENIAFPGFizZIJ3k5NrzTRGjp+tDZ/tVLXK5azCrm/2ydy71KzB4+rarpHyMIMQEFeH+TJpxMDOqvX4Q5fqnMlMo/k58lrkC6pRtYI93myK06DtIC15I1Il7r0jIEyCfRD+zjSu3fSF3WBrw4opdmbR/B558R+T1DesuVqwQVKwX06MH4EsI0BozDKloqM3UsDc07h7z/eaFtXXntaXexo99zKZpWpmFoEWWAIZ3dNoguGRo8czvKfR/CH41Tf7vAjbd+3RF7v2qE3TWnr2mZrKGZIjsICCdDTmnsY61R+2M0OmZXZPoznerFbo0LKuPd7zZcT8mKF2RpqW9QU89zRu+3C6d/a4dmg/tW1WK8N7GqNjF2vVJ1u1bNZI7+C7D45WrpAc+ueQsKwPwggQQCAoBAiNQVFmBple4P92Tw1X2VL3aML0xXYzE8/uqW8u/ECJa7fa3VVNM/e1DR4Vq4E9WumJKpdmEEwz90USDgLn+urcN0p5c+eyM0vpd081z+nr0Hu0OoXWsztjpm8sTw2c6yDtSMyywsUr1tjdU3OGZLczRml3T03/s2LG/DjNnB8vExLNTrzjpy5S4iefKWH+WJ77GSCXSMqZX1Wx7vMa0D1UrTLYPTX9z4q4xE3qF/m6Ykb3UZWHy+qHAz+pbuv+6te1pdq3qBMgKgwDAQQCXYDQGOgVZnwZCph7lSbNfFcxs5fZ103wmxb1knfXzKgp8+39aVviY+zrw8fP1oKlq644F7OOgXWBmaWEJhT8ePAnO7Cn61RRxEvt7WzCLyeT9WjD7nr5xTYKfboGoTGwSn/V0SSnnLXP4/t443Z7jHk2q9lNt2jhS5slpf9ZYTY9GfzqdLuTrmnFihRQ9LAe9vmOtMARMM/tNJvfeFranwvpf1aYxzNNfWuZ3ov/RMdOnFKe3CFqWOsxde/QONNnwAaOGCNBAIGsLkBozOoVpP+/S+Dsr+d07PhJ3Vq0UIbPZ/xdJ+fNWVbAPGvPzBLlyskS0yxbxBvccbN82TyUvXDBfD6d+eTpFCUnn9GtRQtm+GgOn07CQU4LpKZe0KGfjqloofw+b3J04NBRft84XVU6hwACVxMgNHJtIIAAAggggAACCCCAAAIIXFWA0MjFgQACCCCAAAIIIIAAAgggQGjkGkAAAQQQQAABBBBAAAEEEPBfgJlG/814BwIIIIAAAggggAACCCAQNAKExqApNQNFAAEEEEAAAQQQQAABBPwXIDT6b8Y7EEAAAQQQQAABBBBAAIGgESA0Bk2pGSgCCCCAAAIIIIAAAggg4L8AodF/M96BAAIIIIAAAggggAACCASNAKExaErNQBFAAAEEEEAAAQQQQAAB/wUIjf6b8Q4EEEAAAQQQQAABBBBAIGgECI1BU2oGigACCCCAAAIIIIAAAgj4L0Bo9N+MdyCAAAIIIIAAAggggAACQSNAaAyaUjNQBBBAAAEEEEAAAQQQQMB/AUKj/2a8AwEEEEAAAQQQQAABBBAIGgFCY9CUmoEigAACCCCAAAIIIIAAAv4LEBr9N+MdCCCAgL7YtUejJr2t1yJ7qkih/AEvsjJpi/LmzqnKD5UO+LEyQAQQQAABBBC4XIDQyBWBAAIIXIfAui079Fy/MVo5L0q3Fy+S6Rl+PXdeFWp10chBXdSo9mOZHu/aAU80661S9/+HJo980bWu0R8EEEAAAQQQ+IMFCI1/MDCnRwCBwBTwNzSe/fWcHqz9nF4Z0EmN61bNcignT6folptvVq6cObJc3+kwAggggAACCPw+AULj7/Pj3QggEKQC6UPjhk93auzUhdr342GlnDmr/7zndnVoWVcNa12aVew+OFpJ67fZWUnPctbYMf0UkiOb1m76UlPnLNPnO76xrzeqU0VdWjfQX/9yi7bv2qOoKfPVqvGTWrh8tXbu3qvqj5ZTu+Z1VLrEXV797/cfVnTsO9q28xudP/+bHvx7CYW1bagFy1br4oWLiujb3nvs+d9S1TM8WlUrPaDWTZ70qYLDxs3S34oVsv06c/acuvSNUoOalfXp9t1as2G7St53p9o0raVajz/k0/nMQZ6xtWz0hOYvXWXHX7FcSQ3v10E7vt6rWQs/0L++P2hDdocWdVS8WCF77sM/HdeE6Yu1cesunTp9RiXuvUMtGlbXU7Ue9fmzORABBBBAAAEEfBcgNPpuxZEIIICAVyB9aFyZtFkbt36lcqXvU47s2bRq3Vat+HCD5kwMV4Wy92vRiiRFjHlT9Ws8ovJl77fnadqgmjZ+tlNhA8bZwPNk1QftvZJvzIvTS2HN1bFlPa3d9IV93bS2zWrrjr8VtWEqf97cWjB1qDdEmeWjBfPnUesmNVUgX24tiVur2tUrKldIDg0fP1vLZ4/SPXcWt8d/tPYz9RoyUYtjh9klp7600G6Ruu+u2xTZv6NOnU7RIw262bd5xrNmwzYbfjesmGLvffSlpR1bp9B6KlakgGJmL9OxE6eUMySH2jStqbx5cmnyzPf0TP3/1sAerexpn+0xQgcOH1XPjk2UPVs2bdn+tQ4dOabXX+3ty8dyDAIIIIAAAgj4KUBo9BOMwxFAAAEjcLXlqRcvXtTJUyn6+cRJPdV2kPqGtbAzjldbntq448t25nFaVF8vbJ+Iyfr2u/1aNmukNzS+M324nc0zLXHtVr0w5DWtXhytooXza/TkeZq9aKU+WjhOxYsWtMdcuHBRx06ctAG2Uv2uNnAO6B5qX+vYe7TOnf9Nb00K97mYGYXG8F5t1KpxDXsOE/SqPt1T4yK6q3a1ij6d1xMal7wRaWcLTZsxP05jYxYqcdE43Vrk0ljGT1ukD1ZvtvePpqZe0N9rdLSfaz7f08zsp5m1pSGAAAIIIIDAjRcgNN54U86IAAJBIJA+NB7/5ZTGvL5ACWs+tctTPa17h8bq1q5RhqHRLCMtV7OznSEs9r8BybzPs8R1Z9Kb3tCYNhB++fV3ahk2TPNjhqpsybvVpudInU5O0bszXslQfuRrc/Vu/FqtWRKtg4d/VsP24RoX0U21qz3sc6UyCo1RQ7qqXo1K3nOUrtZe/bq1VPvmdXw6ryc0ph3bsoR1GjQyVpvjYrz3T85ZnKBXJ70t42Fan4gpMjO75cvcr0cq/Jcer/yAypa6x6fP5CAEEEAAAQQQ8F+A0Oi/Ge9AAAEErphpNKHqxwNHNLBnaxvkChfMr9qhfRXa+MmrhsbklLN6uF6YmjWophpVK6RTvUlVK5XNMDR+9c0+Ne0y1BsaWzw/TCEh2fVm9MAMK7Nn734bFIf366jde35Q/KqNWrU42t4z6Wv7/wqNZknvgBFTLwuNb7+bqBET5nhD42+pqXov/hOZJbFmSbAJ6Z1b1Vfv55r5OhyOQwABBBBAAAE/BAiNfmBxKAIIIOARSDvTaO4vNEtATWgx4cXTzHJNT2g0QeeBGp30j95t1aLRE5cdU7FcKTvzl7aZZa433XSTT6Fx8KhYLV257or7Cc1Szltuudme1ixJ3X/oqH48+JNe7NLUbmjjT3MpNKYdl5mtHRI1Q8sT1uuLxBne8fozNo5FAAEEEEAAgWsLEBq5QhBAAIHrEEi/PNXM/JlHUrwU1kKpqal6J+5jxa/aJM/yVPMRYQPG6nTyWYX3ela/nErWQw+U0MJlSXYWzWwEYzbDOXfuN7sDqtmR1NznmNESzvQzjWbXUbM5TKXypez9k+Yeyfc/2qjChfKpXbPadnSe+yDNP69ZMkGFC+bza9SuhEbjFtp1uHp0aKIyJe9WcsoZu8FQ6oULWjQtwgZtGgIIIIAAAgjcWAFC44315GwIIBAkAuYRG537Rilh/hjddmthu1x1+LhZdibPNPM4CrPUskfHxuratpH9b+Y9oybO1Z59B+y/b4mPsbt/zl3yoSbOePeyeyFNiOzzfHNvaEy7MYwnNJrdU8uUuNueKy5xk0ZNfMtuSGOa2Yk0sn8nPVaxjP33X8+dV4VaXfR0nSoaMbCz31VKGxpPJ5+xM6sZ3dPYv3uoN6hm9iGeQJx2bO8nblT/yBhrY3ZQNS3t8lSz4U3PlydYS08zS3t7dXpG9951W2YfyesIIIAAAgggcB0ChMbrQOMtCCCAQEYCZknp3h8OqWCBvMqXJ9dVkY4cPaE8uXNettunee/RY7/o4kWpUIG8173M0pzDNHOOtLNuq9d/rh6DJ3jvg8zqFTQh+MjR4ypWuICyZftrVh8O/UcAAQQQQMBpAUKj0+WhcwgggMCNETA7rJr7KudNGeI94c/HT6pOq/6ZfsDmuNf9WvaZtH6b+kXGXPO8ZgY0eniPTD+bAxBAAAEEEEDgzxcgNP75NaAHCCCAwB8qcODQUfUeOlnPt3lKT1S5fJdWs9wzs+bv8w/NRjXmOZDXajfffJOyM0OYGT2vI4AAAggg4IQAodGJMtAJBBBAAAEEEEAAAQQQQMBNAUKjm3WhVwgggAACCCCAAAIIIICAEwKERifKQCcQQAABBBBAAAEEEEAAATcFCI1u1oVeIYAAAggggAACCCCAAAJOCBAanSgDnUAAAQQQQAABBBBAAAEE3BQgNLpZF3qFAAIIIIAAAggggAACCDghQGh0ogx0AgEEEEAAAQQQQAABBBBwU4DQ6GZd6BUCCCCAAAIIIIAAAggg4IQAodGJMtAJBBBAAAEEEEAAAQQQQMBNAUKjm3WhVwgggAACCCCAAAIIIICAEwKERifKQCcQQAABBBBAAAEEEEAAATcFCI1u1oVeIYAAAggggAACCCCAAAJOCBAanSgDnUAAAQQQQAABBBBAAAEE3BQgNLpZF3qFAAIIIIAAAggggAACCDghQGh0ogx0AgEEEEAAAQQQQAABBBBwU4DQ6GZd6BUCCCCAAAIIIIAAAggg4IQAodGJMtAJBBBAAAEEEEAAAQQQQMBNAUKjm3WhVwgggAACCCCAAAIIIICAEwKERifKQCcQQAABBBBAAAEEEEAAATcFCI1u1oVeIYAAAggggAACCCCAAAJOCBAanSgDnUAAAQQQQAABBBBAAAEE3BQgNLpZF3qFAAIIIIAAAggggAACCDghQGh0ogx0AgEEEEAAAQQQQAABBBBwU4DQ6GZd6BUCCCCAAAIIIIAAAggg4IQAodGJMtAJBBBAAAEEEEAAAQQQQMBNAUKjm3WhVwgggAACCCCAAAIIIICAEwKERifKQCcQQAABBBBAAAEEEEAAATcFCI1u1oVeIYAAAggggAACCCCAAAJOCBAanSgDnUAAAQQQQAABBBBAAAEE3BQgNLpZF3qFAAIIIIAAAggggAACCDghQGh0ogx0AgEEEEAAAQQQQAABBBBwU4DQ6GZd6BUCCCCAAAIIIIAAAggg4IQAodGJMtAJBBBAAAEEEEAAAQQQQMBNAUKjm3WhVwgggAACCCCAAAIIIICAEwKERifKQCcQQAABBBBAAAEEEEAAATcFCI1u1oVeIYAAAggggAACCCCAAAJOCBAanSgDnUAAAQQQQAABBBBAAAEE3BT4Nx6Tfz7P+j5wAAAAAElFTkSuQmCC", + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "visualization(ivf_pq_study)" + ] + }, + { + "cell_type": "markdown", + "id": "7d5494bb-b254-4dfd-9029-f546365be894", + "metadata": { + "tags": [] + }, + "source": [ + "## cagra HPO example" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "id": "98828ce8-fec0-4096-8a5a-9be3e181a0ce", + "metadata": {}, + "outputs": [], + "source": [ + "from cuvs.neighbors import cagra\n" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "id": "c644ded3-644b-4f51-81f6-15b612123678", + "metadata": {}, + "outputs": [], + "source": [ + "def multi_objective_cagra(trial):\n", + " \"\"\"\n", + " Optimizes the parameters for the cagra index using a multi-objective approach.\n", + "\n", + " \"\"\"\n", + " # Suggest values for build parameters\n", + " intermediate_graph_degree = trial.suggest_int(\"intermediate_graph_degree\", 64, 128, step=2 )\n", + "\n", + " # Suggest an integer for the number of probes\n", + " itopk_size = trial.suggest_int(\"itopk_size\", 64, 128, step=2)\n", + "\n", + " build_params = cagra.IndexParams(\n", + " intermediate_graph_degree=intermediate_graph_degree\n", + " )\n", + "\n", + " start_build_time = time.time()\n", + " cagra_index = cagra.build(build_params, vectors)\n", + " build_time_in_secs = time.time() - start_build_time\n", + "\n", + " # Configure search parameters\n", + " search_params = cagra.SearchParams(itopk_size=itopk_size)\n", + "\n", + " # perform search and refine to increase recall/accuracy\n", + " start_search_time = time.time()\n", + " distances, indices = cagra.search(search_params, cagra_index, queries, k=10)\n", + " search_time = time.time() - start_search_time\n", + "\n", + " latency_in_ms = (search_time * 1000)/queries.shape[0]\n", + "\n", + " found_distances, found_indices = cp.asnumpy(distances), cp.asnumpy(indices)\n", + " recall = calc_recall(found_indices, gt_neighbors)\n", + "\n", + " return round(build_time_in_secs,4), round(latency_in_ms,4), round(recall,4)" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "id": "516b9b78-ba13-490c-ba47-d6786fb33606", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:53:39,324] A new study created in memory with name: no-name-b457b87f-2a54-4e19-944d-5902bf10ea8e\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 192\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:56:22,063] Trial 0 finished with values: [157.0238, 0.0412, 0.9903] and parameters: {'intermediate_graph_degree': 76, 'itopk_size': 124}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[I] [16:56:15.120128] optimizing graph\n", + "[I] [16:56:16.300838] Graph optimized, creating index\n", + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 192\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 16:59:03,390] Trial 1 finished with values: [155.633, 0.0364, 0.9884] and parameters: {'intermediate_graph_degree': 72, 'itopk_size': 106}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[I] [16:58:56.534874] optimizing graph\n", + "[I] [16:58:57.649931] Graph optimized, creating index\n", + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 192\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 17:01:51,648] Trial 2 finished with values: [162.741, 0.0231, 0.9801] and parameters: {'intermediate_graph_degree': 90, 'itopk_size': 66}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[I] [17:01:44.581010] optimizing graph\n", + "[I] [17:01:46.084702] Graph optimized, creating index\n", + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 192\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 17:04:46,930] Trial 3 finished with values: [169.5533, 0.0396, 0.9915] and parameters: {'intermediate_graph_degree': 110, 'itopk_size': 114}. \n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[I] [17:04:39.128583] optimizing graph\n", + "[I] [17:04:41.155907] Graph optimized, creating index\n", + "using ivf_pq::index_params nrows 1000000, dim 768, n_lits 1000, pq_dim 192\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[I 2024-08-19 17:07:31,215] Trial 4 finished with values: [158.4761, 0.0414, 0.9905] and parameters: {'intermediate_graph_degree': 80, 'itopk_size': 126}. \n" + ] + } + ], + "source": [ + "cagra_study = optuna.create_study(directions=['minimize', 'minimize', 'maximize'])\n", + "cagra_study.optimize(multi_objective_cagra, n_trials=5)" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "id": "293050f3-09ad-4333-b2e7-5887f2a25465", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of trials on the Pareto front: 5\n", + "Trial with lowest build time in secs: \n", + "\tnumber: 1\n", + "\tparams: {'intermediate_graph_degree': 72, 'itopk_size': 106}\n", + "\tvalues: [155.633, 0.0364, 0.9884]\n", + "Trial with lowest latency in ms: \n", + "\tnumber: 2\n", + "\tparams: {'intermediate_graph_degree': 90, 'itopk_size': 66}\n", + "\tvalues: [162.741, 0.0231, 0.9801]\n", + "Trial with highest accuracy: \n", + "\tnumber: 3\n", + "\tparams: {'intermediate_graph_degree': 110, 'itopk_size': 114}\n", + "\tvalues: [169.5533, 0.0396, 0.9915]\n" + ] + } + ], + "source": [ + "print_best_trial_values(cagra_study)" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "id": "0b431ad6-fd07-40b4-b751-39a3ee5169d7", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{text}Trial", + "marker": { + "color": [], + "colorbar": { + "title": { + "text": "Trial" + } + }, + "colorscale": [ + [ + 0, + "rgb(247,251,255)" + ], + [ + 0.125, + "rgb(222,235,247)" + ], + [ + 0.25, + "rgb(198,219,239)" + ], + [ + 0.375, + "rgb(158,202,225)" + ], + [ + 0.5, + "rgb(107,174,214)" + ], + [ + 0.625, + "rgb(66,146,198)" + ], + [ + 0.75, + "rgb(33,113,181)" + ], + [ + 0.875, + "rgb(8,81,156)" + ], + [ + 1, + "rgb(8,48,107)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [], + "type": "scatter", + "x": [], + "y": [] + }, + { + "hovertemplate": "%{text}Best Trial", + "marker": { + "color": [ + 0, + 1, + 2, + 3, + 4 + ], + "colorbar": { + "title": { + "text": "Best Trial" + }, + "x": 1.1, + "xpad": 40, + "y": 0.5 + }, + "colorscale": [ + [ + 0, + "rgb(255,245,240)" + ], + [ + 0.125, + "rgb(254,224,210)" + ], + [ + 0.25, + "rgb(252,187,161)" + ], + [ + 0.375, + "rgb(252,146,114)" + ], + [ + 0.5, + "rgb(251,106,74)" + ], + [ + 0.625, + "rgb(239,59,44)" + ], + [ + 0.75, + "rgb(203,24,29)" + ], + [ + 0.875, + "rgb(165,15,21)" + ], + [ + 1, + "rgb(103,0,13)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [ + "{
\"number\": 0,
\"values\": [
157.0238,
0.0412,
0.9903
],
\"params\": {
\"intermediate_graph_degree\": 76,
\"itopk_size\": 124
}
}", + "{
\"number\": 1,
\"values\": [
155.633,
0.0364,
0.9884
],
\"params\": {
\"intermediate_graph_degree\": 72,
\"itopk_size\": 106
}
}", + "{
\"number\": 2,
\"values\": [
162.741,
0.0231,
0.9801
],
\"params\": {
\"intermediate_graph_degree\": 90,
\"itopk_size\": 66
}
}", + "{
\"number\": 3,
\"values\": [
169.5533,
0.0396,
0.9915
],
\"params\": {
\"intermediate_graph_degree\": 110,
\"itopk_size\": 114
}
}", + "{
\"number\": 4,
\"values\": [
158.4761,
0.0414,
0.9905
],
\"params\": {
\"intermediate_graph_degree\": 80,
\"itopk_size\": 126
}
}" + ], + "type": "scatter", + "x": [ + 157.0238, + 155.633, + 162.741, + 169.5533, + 158.4761 + ], + "y": [ + 0.9903, + 0.9884, + 0.9801, + 0.9915, + 0.9905 + ] + } + ], + "layout": { + "autosize": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Pareto-front Plot" + }, + "xaxis": { + "autorange": true, + "range": [ + 154.8058405093237, + 170.38045949067632 + ], + "title": { + "text": "build_time_in_secs" + }, + "type": "linear" + }, + "yaxis": { + "autorange": true, + "range": [ + 0.9791592233009708, + 0.9924407766990292 + ], + "title": { + "text": "recall" + }, + "type": "linear" + } + } + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA40AAAFoCAYAAADzQh4hAAAAAXNSR0IArs4c6QAAIABJREFUeF7s3QmcTfX/x/H3nX3GDIaxJpK0l1J+pVKiTSlRkbXSQooiIi1IlGxFpLRhtKBkKVGkhKRISakksm8zGDPDGPP/f7/jXjNjhvv9nHvuPWfmfR+P38Pvzr3fe895fo94OZsnJycnB3xQgAIUoAAFKEABClCAAhSgAAUKEfAwGrldUIACFKAABShAAQpQgAIUoEBRAoxGbhsUoAAFKEABClCAAhSgAAUoUKQAo5EbBwUoQAEKUIACFKAABShAAQowGrkNUIACFKAABShAAQpQgAIUoIC5APc0mptxBAUoQAEKUIACFKAABShAgRIjwGgsMVPNFaUABShAAQpQgAIUoAAFKGAuwGg0N+MIClCAAhSgAAUoQAEKUIACJUaA0VhipporSgEKUIACFKAABShAAQpQwFyA0WhuxhEUoAAFKEABClCAAhSgAAVKjACjscRMNVeUAhSgAAUoQAEKUIACFKCAuQCj0dyMIyhAAQpQgAIUoAAFKEABCpQYAUZjiZlqrigFKEABClCAAhSgAAUoQAFzAUajuRlHUIACFKAABShAAQpQgAIUKDECjMYSM9VcUQpQgAIUoAAFKEABClCAAuYCjEZzM46gAAUoQAEKUIACFKAABShQYgQYjSVmqrmiFKAABShAAQpQgAIUoAAFzAUYjeZmHEEBClCAAhSgAAUoQAEKUKDECDAaS8xUc0UpQAEKUIACFKAABShAAQqYCzAazc04ggIUoAAFKEABClCAAhSgQIkRYDSWmKnmilKAAhSgAAUoQAEKUIACFDAXYDSam3EEBShAAQpQgAIUoAAFKECBEiPAaCwxU80VpQAFKEABClCAAhSgAAUoYC7AaDQ34wgKUIACFKAABShAAQpQgAIlRoDRWGKmmitKAQpQgAIUoAAFKEABClDAXIDRaG7GERSgAAUoQAEKUIACFKAABUqMAKOxxEw1V5QCFKAABShAAQpQgAIUoIC5AKPR3IwjKEABClCAAhSgAAUoQAEKlBgBRmOJmWquKAUoQAEKUIACFKAABShAAXMBRqO5GUdQgAIUoAAFKEABClCAAhQoMQKMxhIz1VxRClCAAhSgAAUoQAEKUIAC5gKMRnMzjqAABShAAQpQgAIUoAAFKFBiBBiNJWaquaIUoAAFKEABClCAAhSgAAXMBRiN5mYcQQEKUIACFKAABShAAQpQoMQIMBpLzFRzRSlAAQpQgAIUoAAFKEABCpgLMBrNzTiCAhSgAAUoQAEKUIACFKBAiRFgNLp0qtdv3IolP/6GnbtTEV8qFm2aX4e42GiXrs3xiz37y6VI2bsf7e+8odisE1eEAhSgAAUoQAEKUIACbhRwdTTWa9IZ6RmZPve42BicfUZ1tL69MW5ufFlI5uOjGQuwdccePP7gnbZ9//cr1uD+Hi/n+/wFU0eiUoVE276zsA9evHw1vv9pDdrecR0qVyjn13f7O2ftHh2Elav/wm8L3/Prc/O+KRhzYLxQHEABClCAAhSgAAUoQAGXChSLaGzb4jpkHc7Gth178O33q/RUdO3YAp073Bb0aWnfdTBW/PqnKHb8Xdh7H38Jy3/+A28N64V6F5+NA+mZiI+LRXh4mL8fEZD3jZ0wA2PenY6P3uiH88+q6ddneqPxZHNmJRqDMQd+rSzfRAEKUIACFKAABShAgWIg4PpojImOxKJPR/um4tc/1uPuzgP082Wfva4P3Qzmw99gycnJgcfjES2aCq+zap2K5NeeFo03HVTUskqj0Z85O1k0nsjP3zkwdeD7KUABClCAAhSgAAUoUBIFil00qkns0X8M5i5crqPqtFMr48VRk/HH3xv1YaPqcNYzT6+GO5teg5a3NUJkRLie98yDh9C93xjUvaA2Wt52LT757Fv8+sc/SIiPw4Ce9+n3rNuwBa++NQ0rf/0Le1L34+Lza+Phe5rhynrn69cHvToJn36xWH/H1ZfX8W1PzzzeHqdUTtLPp85eiGmzvsHqtetRrUoFXFO/Dh574E6Uios56fZ3ODsbXZ8epfemqkNxL61zlh5zc6PLcP01l550+dUeUBV6q35bBxVul1x4Fnp0ugvVT6nk++7f1v6L196djruaXoPN23ZhxtzF+P2vDahVoyqe6NxKL696TJv9DcZPno1NW3fiwnNroWzpeP3zu5s18r2nsBVSwVswGgvOmXItKhpP5ufPHJwUmm+gAAUoQAEKUIACFKAABXwCxTIa+744XsfOxFF9UaF8GTRp21uf73dO7Rr6EM6lP67RYdfx7pvxROeWGiPtQAYuu+Vh/b6srMM6CtWjXNkEvSfzx1Vrcc9jL+qf1b3gTJSKi8aiZb/q52MGP46GV1yEJweOw2fzv9c/U9/lfYzo30WH2ctjPsCEqXP1Z175vwuwfsNWHY81qlXCx28NRGxM1Ak3TXUIbuuHn9cRl/c7Wt7aEDc3vvyEy//Vop/w2LO5e2RvbFgPGZmHfIfyTn/nBR3S6rFo2S/o3HuEbzmUhzr0VQWzesyZ/DKqn1IRE6fO1dGonFT8qrhWjwfb3oIbG/6vyPUoKhrzztklF55ZaDT643eyOeDvfQpQgAIUoAAFKEABClDATKDYReOOXam4pX0fHYWLZ7yG6OgobN66E2fUPMUns3f/ATRt3weZB7OwfM44/XNvNKr/37hBXXS480ac/v971/anpeOUKklo0fFZHU4z3xuEWqflfpa6gmnTDk/p4FLhpR5FHRq57t/NuO3ep3VMvjuyty+yRrwxBW9/8LmOVxWx/jzOa3ivDtdJo/v63n6i5a9csRyatH0S23emYPbEF1GzehU97pulq9DlqZFocNkFGDfkCf0zbzSqPYsDe9+POufW0j8f+96nGPPep/mWM1CHpxacs7Jl4o+LRhM/Hp7qz1bE91CAAhSgAAUoQAEKUMA/AddHo1rNF3p3RHrGQWzeukvvyVPB2Kn9reh2/x0+BXX46d//bsb2HSnYs3cfJk2dpyNwyawxKJNQyheNeQPKO9h7nqQ6bPWZx9rnk1V7H9VVPlfOG4+oqMgio/Gt9z/DyDen4pXnH8X1V196XOypmJw2PvdczI8/+1bfSiPvQ0Xi/y4+W//oRNFY2PKr5VOHe7ZtcT36dmub73O9h4EunT0WpePjfNH4XPcOaNWske+9a9f9hxb3P4s2zRvj6aMG0mj0Z84KHp5q4sdo9O83P99FAQpQgAIUoAAFKEABfwRcH415b7nhXeG+3drpc+vUoajZ2UfwRvIsfZXPwh5qb6Tas+XdU6cOrVSHk+Z9fD5/GXoNfP2Enl9+OAxVKycVGY3PvvwOPvn823x7+rwfeHO73tiwabvviqvNOz6DP//ZlO/71JVg1RVhTxaNhS3/rHlL0Gfwmxj4ZEe0uPnqfJ87eNRkTP7kS3z81vP6diXePY0Fo1GdD3pdyx76XFDvOZ7SaDzZnKkFLBiNJn6MRn9+6/M9FKAABShAAQpQgAIU8E/A9dGoVnP0oG6ICA+HOgxT/U/9f+/jtXem4/WJM/SFXB5s2xS1T6+GpHJl9PmF6vxDf6JRXXyl/7D3cOsNV+DSC3MvPlPwoe4LqS5OU1SweM+1m/fhMN9Fcbyf4Y3E1V+/q6+o+tf6TcjMPJTvKyoklfXdC/FEexoLi0bv8r/U9yG9DnkfQ8d+iPemfIEPxj6rL2hTVDSqQ0ivvfPxgETjyeassGg08WM0+vebn++iAAUoQAEKUIACFKCAPwKuj8bCrsSZd8Vvu6dvvsNQva95L7ziTzR+v2IN7u/xMrrc0wyP3Nf8hK5FBcvodz7BuIkzMeHVp3xXPVUfpPaEXt60i75gz+fJQ/yZsxMenlpYNC798Tc80HNoofeu9F5p9utpr6BiUllRNL4/9lnfuY8nW4GiLoRTcFzBPY0mfozGk80CX6cABShAAQpQgAIUoID/AsU+Gr03k/9+9ljfxWf2paWj05PD8cuadX7taUzZux9XNeuq9ySqC8moK4p6H0eO5GDhkpVodFVd/aNuz47C/EUr4I0w7/u8F51pen19DHm6k2/8vG9+RPd+r+nDRtXho/48TPc07tqzF9e0eEwvt7r6aXRUpP6abTv3oPFdPfTP508ZofdymuxpfH/6fH2bEXU474mumJp3naTRaOJX1Bz4Y8v3UIACFKAABShAAQpQgAL5BYp9NPboPxZzF/6g76l47ZUXQwXU7C+X+G6p4c+eRkWmzvtT5/+pcLzv7ib6EFN19dRvlv6szz/8beF7WlbdhuKV8dNQ76Kz9a0t1BVL1QVlKldIRJtHXtChqg4RvebyOvoeh+q96lHYYatFbaym0ag+Z9TbH+ONSbP0IajqfE91W5GxEz7Vy5c3+kyiccWvf6F910E6Ou9r1QQHD2XhvDNPQ/1Lzyvy95k0GnNycvz2K2oOqlQsx9//FKAABShAAQpQgAIUoIChgOujMSE+FgumjixytdW5eF2fflXfD9H7uKXx5Toel638HUtmjkGZ0qVwID0T/7u5s95jVvBCOGqcipYvvv4BQ1//UIeW96EislWza9Gzcyv9I3VBnVffmoZPv1isr+KqHt7bdOzddwADRryHuQuX+8arexwO69cFF5xd0++pU9GoovS9V/r4xpxs+Q9nZ+PN5Nn5Lgikll1d8CbveY6Ll6/GQ72GoV+Pe6CuFut9eM9pVD9Tr3kf7344Bx/OWKADWD3697wXdzVtWOS6qGg82ZypwQUPT1U/89fvRHPgNzLfSAEKUIACFKAABShAAQpoAVdHo79zqA4h/W/LDh1xVSsl6Ui08lD3edyxKwWJZRJQPrG0Pqyz4EPtydu6Y7e+6I6Ks7wPFTVqeconltHnEQbzoZZr4+btiIiIgApWdYVZqw8V1Coa40vFahO7H/76nWgO7F5Gfj4FKEABClCAAhSgAAWKi0CJiMbiMllcDwpQgAIUoAAFKEABClCAAsEWYDQGW5zfRwEKUIACFKAABShAAQpQwEUCjEYXTRYXlQIUoAAFKEABClCAAhSgQLAFGI3BFuf3UYACFKAABShAAQpQgAIUcJEAo9FFk8VFpQAFKEABClCAAhSgAAUoEGwBRmOwxfl9FKAABShAAQpQgAIUoAAFXCTAaHTRZHFRKUABClCAAhSgAAUoQAEKBFuA0RhscX4fBShAAQpQgAIUoAAFKEABFwkwGl00WVxUClCAAhSgAAUoQAEKUIACwRZgNAZbnN9HAQpQgAIUoAAFKEABClDARQKMRhdNFheVAhSgAAUoQAEKUIACFKBAsAUYjcEW5/dRgAIUoAAFKEABClCAAhRwkQCj0UWTxUWlAAUoQAEKUIACFKAABSgQbAFGY7DF+X0UoAAFKEABClCAAhSgAAVcJMBodNFkcVEpQAEKUIACFKAABShAAQoEW4DRGGxxfh8FKEABClCAAhSgAAUoQAEXCTAaXTRZXFQKUIACFKAABShAAQpQgALBFmA0Bluc30cBClCAAhSgAAUoQAEKUMBFAoxGF00WF5UCFKAABShAAQpQgAIUoECwBRiNwRbn91GAAhSgAAUoQAEKUIACFHCRAKPRRZPFRaUABShAAQpQgAIUoAAFKBBsAUZjsMX5fRSgAAUoQAEKUIACFKAABVwkwGh00WRxUSlAAQpQgAIUoAAFKEABCgRbgNEYbHF+HwUoQAEKUIACFKAABShAARcJMBpdNFlcVApQgAIUoAAFKEABClCAAsEWYDQGW5zfRwEKUIACFKAABShAAQpQwEUCjEYXTRYXlQIUoAAFKEABClCAAhSgQLAFGI3BFuf3UYACFKAABShAAQpQgAIUcJEAo9FFk8VFpQAFKEABClCAAhSgAAUoEGwBRmOwxfl9FKAABShAAQpQgAIUoAAFXCTAaHTRZHFRKUABClCAAhSgAAUoQAEKBFuA0RhscX4fBShAAQpQgAIUoAAFKEABFwkwGl00WVxUClCAAhSgAAUoQAEKUIACwRZgNAZbnN9HAQpQgAIUoAAFKEABClDARQKMRhdNFheVAhSgAAUoQAEKUIACFKBAsAUYjcEW5/dRgAIUoAAFKEABClCAAhRwkQCj0UWTxUWlAAUoQAEKUIACFKAABSgQbAFGY7DF+X0UoAAFKEABClCAAhSgAAVcJMBodNFkcVEpQAEKUIACFKAABShAAQoEW4DRGGxxfh8FKEABClCAAhSgAAUoQAEXCTAaXTRZXFQKUIACFKAABShAAQpQgALBFmA0Bluc30cBClCAAhSgAAUoQAEKUMBFAoxGF00WF5UCFKAABShAAQpQgAIUoECwBRiNwRbn91GAAhSgAAUoQAEKUIACFHCRAKPRRZPFRaUABShAAQpQgAIUoAAFKBBsAUZjsMX5fRSgAAUoQAEKUIACFKAABVwkwGh00WRxUSlAAQpQgAIUoAAFKEABCgRbgNEYbHF+HwUoQAEKUIACFKAABShAARcJMBpdNFlcVApQgAIUoAAFKEABClCAAsEWYDRaFN+yO8PiJ4R2eOVysdiRkoEjOaFdDrd9e9XysXD73Afb3AOgcvlYbHX575lgu4WHeZBUJhrbUzKD/dWu/r6IcA8SE6KxM5VuJhMZFRGG0qUisWvvQZNhJf69MVHhiIsOx579h0q8hQmAMouKDEdqmjU39WcyHxSggL0CjEaLvm4PB0ajbANgNJq7MRrNzdQIRqPMjdEoc2M0ytwYjTI3RqPMjaMoEAoBRqNFdUajRUCXDmc0mk8co9HcjNEoM1OjGI0yO0ajzI3RKHNjNMrcOIoCoRBgNFpUZzRaBHTpcEaj+cQxGs3NGI0yM0aj3I3RKLNjNMrcGI0yN46iQCgEGI0W1RmNFgFdOpzRaD5xjEZzM0ajzIzRKHdjNMrsGI0yN0ajzI2jKBAKAUajRXVGo0VAlw5nNJpPHKPR3IzRKDNjNMrdGI0yO0ajzI3RKHPjKAqEQoDRaFGd0WgR0KXDGY3mE8doNDdjNMrMGI1yN0ajzI7RKHNjNMrcOIoCoRBgNFpUZzRaBHTpcEaj+cQxGs3NGI0yM0aj3I3RKLNjNMrcGI0yN46iQCgEGI0W1RmNFgFdOpzRaD5xjEZzM0ajzIzRKHdjNMrsGI0yN0ajzI2jKBAKAUajRXVGo0VAlw5nNJpPHKPR3IzRKDNjNMrdGI0yu5IUjTk5Odi9ZTNS/vwdcZUqI6lWbURHx4jgGI0iNg6iQEgEGI0W2RmNFgFdOpzRaD5xjEZzM0ajzIzRKHdjNMrsSko0qmBc8c4bCPtsFhK2bUNGQmnsveQS1HnsCSRUqmKMx2g0JuMACoRMgNFokZ7RaBHQpcMZjeYTx2g0N2M0yswYjXI3RqPMrqRE486//sDmno+j4rr1PqiM+FI4cP8DuPDBLsZ4jEZjMg6gQMgEGI0W6RmNFgFdOpzRaD5xjEZzM0ajzIzRKHdjNMrsSko0/vHFLET164eYAwfyQW27606c3+dZRBkepspolG1vbhi1Py0dy3/+w7eokZERiC8Vi/PPqgn1/4P5+GHlH0g7kF7kV4aHh+Oa+nWOe33j5h346Ze1aHjFRUgsk3DSRc48eAj3dR+CLvc0Q4PLLjzp+932BkajxRljNFoEdOlwRqP5xDEazc0YjTIzRqPcjdEosysp0fjvd9/gQL+nkbh9pw/qSHg4NrVtjcuffNYYj9FoTOaaAb//tQF3PtjvuOUtVzYBbw1/EmfVOtXyuhw8lIW6NzyIwU89iGY3Xlnk5zXv+Az+/GfTCb/vt4XvHff6Z/O/x5MDx+GjN/rp2D3ZIz3jIOo16YSX+j6EW2+44mRvd93rjEaLU8ZotAjo0uGMRvOJYzSamzEaZWaMRrkbo1FmV1KiMW1vKlY91wfVvluCyIMHkePxYFvNGij7eE/UanS9MR6j0ZjMNQO80fjm0J64st75OHIkB7/+8Q/adBmI22+6CoP6PGB5XdSevUtufAgv9L4fzZs0KPLzDmdnIycn9+W/12/SMTv6hW5ocHnu3kWPB4gIDz9ufFbWYRxIz0R8fGyhrxccwGi0PKXF+wMYjcV7fotaO0aj+bwzGs3NGI0yM0aj3I3RKLMrKdGodFI2/IN/Zs9A+KZNyEhMRMW6l6LWdTeJ4BiNIjZXDCoYjd6FbnRXd33o5oCe9/nWY9GyX/HGpJlYufovVKtSAc1uugoPtm2KyIhwHDqUhXGTZuKLr3/Azt17UaViOX24aI9OLfFI31ewcMnPekyF8mX1540f1guxMVFFGv21fhNuv+8ZjH2xu++Q1FVr1mHo2A8xoNd9+Hz+91DPG11ZFxecXRNDxnyAkQMe0Z+/9MffMPyNKdiwaTvSMzJx5unVcN/dTXDbDbl7ORmNrtg0Q7eQjMbQ2YfymxmN5vqMRnMzRqPMjNEod2M0yuxKUjR6hQ6k7Uep+JOf53UiUUajbHtzwyhvNPZ5tA3qnFsLmQez8PWSlZg2+xtMHPUUzqldQ6/GomW/oHPvEfpwzusaXIJf1qzD2x98jic6t0THu2/Ga+9Mx+sTZ6DXw3ejWtUKWPv3Rrw3ZS6WzxmHqbMXov+w93BL48tx8QW19efd2bShjs2iHoVFo3cZ1JhaNarinDNroM65Z6BGtUp4qNcwzP1gqA7TuQt/wPcrfsdF552BmOgoLFi8ArO/XIpJo59G3QtqMxrdsGGGchkZjaHUD913MxrN7RmN5maMRpkZo1HuxmiU2ZXEaJRJ5R/FaAyEojM/o6hzGitVSMQzj3dAoysv1guuzjdUe/HUYazeR4/+Y/D3+s2YOWEwOvceDnVBmtkTX0JYmPqbBJCReUjvTfT38NS8QieKxhf7Pujba6jGLF6+Ol80ej9H3Xpm3/507E7dh1s7PIWenVvpPY7c0+jMbdExS8VodMxUBHVBGI3m3IxGczNGo8yM0Sh3YzTK7BiNMjdGo8zNDaO80fjqwK64vO65yD5yBHv3pem9hB/NWIBp4wfgjNNOwUXXPwB1cZxKFcr5Vst7+Ke6OM2UWQsxYPh7ek9fo6vqol6ds3BN/YsQHh4W8Gj8asoIffir91EwGlP27sew1z/CvG9+1Ieneh+P3NdcXzGV0eiGLTOEy8hoDCF+CL+a0WiOz2g0N2M0yswYjXI3RqPMjtEoc2M0ytzcMKqocxq9VzxVoXXPXTfifzd3xl1NG6Jxg7oFVsuDBpddoH+24tc/9WGt369Yg+07U/SVTD8c9xzUZ/lzIZy8H3yiPY0ni8bWXQZi05Yd6NO1rT7fMalcWdzYuidaN7+O0eiGjTLUy8hoDPUMhOb7GY3m7oxGczNGo8yM0Sh3YzTK7BiNMjdGo8zNDaOKisYt23bh+rt7+g7pbHB7V9S76ByM6N8l32qpQ0A9Hg+ys4/ovYrqoX42ZebXeH7kREx9sz/OrHUq6jS+H89174BWzRr5xSKNxrKl43HZLQ+j+0N34YE2t/i+Sy0/o9Ever6J0VgytwFGo/m8MxrNzRiNMjNGo9yN0SizYzTK3BiNMjc3jPJGo9qjqPbKqfMPt27fjcmffIU9qfsx/Z2B+pDT96fPx6BXJ+H+1jfri+EcOnQYP//2F75Zukqf59ix+xBcXb+Ovm1HVGQk3v1wjr4AztfTXkHFpLL6nMe0A5l4+rF22Lv/AC6tc9YJb48hjUa1rOpWHeFhYXiicytkZ2fj48+/xZwFy8DDU92wRTpgGRmNDpiEECxCoKJR/avZkezDCI+IDMFaBPcrGY0y7/AwD5LKRGN7yrHzJ2SfVLJGRYR7kJgQjZ2pdDOZeUajidax9zIaZW6MRpmbG0YVdiEcdRGci86rjUfubYZap52iV0PtSZz8yZcY/c70fOcJqohUt9UYPm4K3vnwc98q173gTH3RGe+FdNRtMF4cPRnrNmzR71FXVY2LjSmSyBuN44b00Lf+UA/v1VPnTx2BynnOrVSf/UDPoZj34TCcUjlJXxjn+RETsGnrTj2u6fX19dVTH+3YHA93aKYv0HPpTQ/hpb4P6QAubg9PjvpbKx9iAUajmM7VA61G4+GsLHz30fvYvPYPICsLFWqdgatat0WcxcuXOxmV0SibHUajzI3RKHNjNMrcGI0yN0ajzK04jlI5smvPXqgqKZ9Y2ndIqlrXw9nZ+h6NpeJiUDo+rtDV37ErFQnxcSe8R2Mg3NRy/vvfNpRLLI0yCaUC8ZGu+QxGo8WpYjRaBHTpcKvROHPUCPz27iRk/Zf7L2Ph5cri9A53o/UzA1wqcvLFZjSe3KiwdzAaZW6MRpkbo1HmxmiUuTEaZW4cRYFQCDAaLaozGi0CnmB4ZkY69qbuQZnE8oiJibXviwSfbCUaD2ZmYMIjD2PbjDn5vjnh0otwT3IyyiVVECyR84cwGmVzxGiUuTEaZW6MRpkbo1HmxmiUuXEUBUIhwGi0qM5otAhYyPAjR45gw5+/IhyHUaVCeWzdsQtHwqNQ/YzzERaWewWtUD+sROOeXTvxXstWSPvlt3yrEXlKZdzx7ts4s+6loV49W76f0ShjZTTK3BiNMjdGo8yN0ShzYzTK3DiKAqEQKLbReORIDnbsTkFSuTInvIqSFz0r67A+lrpCUtlC3787ZZ++YlLZMvH55onRGPjNdvuWDYj3HETt00/zffhf6/7BAU8cKlapHvgvFHyilWhUx8NPeqon/n0rOd83V2x6A+55/Q3ExhZ+vL5gMR01hNEomw5Go8yN0ShzYzTK3BiNMjdGo8yNo2QC6oqsXZ4aibEvdsc19evIPqQEjyqW0ag2ip7Pv+67ClO/J+5Fy1sbFjnN6qpM6upM3scLve9H8yYN9NPN23ahR78xWL12vX5e76KzMbxfF32SrnowGgP/u+fv337EpefVRlzssUNS0w6kY+Xa9ah1zsWB/0LBJ1qJRvV1v3+/GF+PHYO9K39FTtZhJJxzJi65715ccVtzwdK4YwijUTZPjEaZG6NR5sZolLkxGmX0HKUGAAAgAElEQVRujEaZG0eZC6xd9x/aPTpItwGj0dxPjSh20agud3t182768rdtW1yHhUt+xmPPjsbcD4bq+8EUfHgvsztqYDdcc0UdzJm/DH0Gv4lZE1/E6dWroP+w97Bt524M6NkR0VGR6PTkcNQ6rSoGP/Ugo1G2zZ10VEmIRoWwb28KNq75DYcPHUL1885HuaSKJ7Vx8xsYjbLZYzTK3BiNMjdGo8yN0ShzYzTK3DjKTGDn7lS06jwAPR5qiQEjJmDYcw9zT6MZoX53sYtG767nlfPGIyoq9953N7frrQOybYvrjyMaMuYDLP/5D0wbf+yqlbfd0xd3Nr0GtzdpgPpNu+T7F4kF361A12dGYfXX78Lj8XBPo2CjO9kQdXhqgicTZ5xe0/fWP9etR7ontlgcnnqy9S+urzMaZTPLaJS5MRplboxGmRujUebGaJS5cZT/Ampn0r2Pvajvyah2KNVr0pnR6D9fvncWu2icMmsh3vtoDj5PHuJb0a5Pv4rTTq2CJzq3PI7plfHToG7e+dEb/XyvdXt2FKpWSsKj9zXHZbc8jHFDnkCDyy7Qr//x90bc8cBz+Hb6KH2IKg9PFW55JximLoTz71+/IjLnMKpULI8t29WFcKJR/YzzisWFcAIv5o5PZDTK5onRKHNjNMrcGI0yN0ajzI3RKHNz+qgFCxZA/S8Uj0aNGkH9Tz3U9U3U6WrqofYuhoV5GI0WJqXYReNb73+GL77+Id+eQ7XBxMfFon/Pe4+jWrVmHdp0GYhWzRrh8rrnYuPm7Zgw5Qvccl199Hm0DR7uMxJr121E144tEBkRgXnfLsf8RSt80Zh64JAF/tAPLR0XhbT0QzgS+kXJ/68ZANLTDyA1JQWJ5cojNs/5jU5Y1DKlorDX5XMfCsfSpaKwj25G9OqIhviYCOzPyDIa5++bj+TkIMyjkr54PdQ6xcVEIM0mt+KldWxt1AXfYqLCcCDzcHFdRVvWKyI8DCq40w+6yy3HFg3/P1SZRYSFIf2QNbeypaL8/1K+03aBiRMnYvrQkSi9fQ+QkwN4PFAXAVR/ntn5PK1yedzeqzs6dOig13HHrlRce+fj+ujBUrEx+mcTps5Fwysuwm03XIkbG9az3aI4fUGxi0bTPY1qMtWexg9mzMe+/ek4+4zqmDRtHno/0hod7roR+9PSoUJUxWVCqVhkHT6MRct+9R2eeiDD2n/oQr0xqb9U6T/kQv0nRwEIhy3OcdMUH6v+MuruuQ/2tqeyJC42Am7/PRNstzAPEBMdjvTMbFu+Wu3Zd8qtbAK5guruPNGR4cg4aI9bIJfVSZ8VHgZE0c14StSebfW/zENO+yfYE69KqP+5SJmFhXtwyKJbqdgI4znjAPsEVDTOGfASktZv0qGoujH3kRuOdj3fVbMqmvR7yheN6qI3yR9/mW9FX33rYzS9vj6aXldfH7LKh/8CxS4avec0/vzlW4iMzP2PyI2te6HDXTcUek5jQaoVv/6J9l0HY+qb/XHumcdu+eB9X8fuQ1AqLgajBz2mf8TDU/3f2IrTO61ePbU4Wfi7Ljw81V+p/O/j4akyNx6eKnPj4akyNx6eKnPj4akyN6ePUtE49/mXUPHfLb49i949jLm/6n7UeyDz/9z7XPb6jpqn4Mbn+viisTAnntMo33qKXTSmZxxEvSad9J7CNoVcPVVd9EZd/EbdNqNGtUpaTu2+TiybgH82bMFzL7+DikllfVGYdiBD/6vI4exszP5yCQaPmowPx/XDBWfnXqSF0Sjf+Nw8ktFoPnuMRnMzNYLRKHNjNMrcGI0yN0ajzI3RKHNz+igVjV8+/xIq/bvlaB/mwANPbifqHrTn+dbTquIGRqNtm0exi0YltWDxSqiL33gfzzzeHq1vb6yffr1kJR7t+yo+eXsgzqp1qv5Zq04D9H0Y42Jj0LzJVXiicyt9ew31WLx8NR7qNUz//1o1qmJAr/tw8fm1fZ/NaLRt23T0BzMazaeH0WhuxmiUmalRjEaZHaNR5sZolLkxGmVuTh+lovGr519C1Q1b9KLqYPTuYbTx+ZaaVXHdsyfe0+h0OycvX7GMRgWenX0E23buQcXyZX2HqRY1Eal705Bx8BAqV0jMPUk3z0PtYdy6fbe+UqqKyoIPRqOTN2/7lo3RaG7LaDQ3YzTKzBiNcjdGo8yO0ShzYzTK3Jw+SkXjgoFDUG3DZt++xTzHpOZZ/GP7HgPx+qYaVdCI0Wjb5lFso9E2sQIfzGgMlrSzvofRaD4fjEZzM0ajzIzRKHdjNMrsGI0yN0ajzM3po1Q0Lhw4BNU3bin8lMWiTmW0+PP/TquKhs/0PuE5jU63c/LyMRotzg6j0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxm9fGIIa6vDUIi92Y7EQC/ncDdWr4GpGo22bB6PRIi2j0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxkUvDMHp/23Ns6fx2O02cnsv8M//rVEVVz3NPY12bR+MRouyjEaLgC4dzmg0nzhGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRRKhoXDxqCWhu35jmn0bvU3vttBP75P9Wr4ApGo22bB6PRIi2j0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxqWDXkbtTWpPY57ba3j3MHpvvxHg5+uqV8HlfZ/kOY02bSCMRouwjEaLgC4dzmg0nzhGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRRKhqXDX4ZZ/6n9jQG7/HnqVVwGaPRNnBGo0VaRqNFQJcOZzSaTxyj0dyM0SgzYzTK3RiNMjtGo8yN0Shzc/ooFY0/DH4Z52zaBiD3threcxi9y37seeBeX3tqFdRjNNq2eTAaLdIyGi0CunQ4o9F84hiN5maMRpkZo1HuxmiU2TEaZW6MRpmb00epaPzpxZdxzn/bci+emu9ujcfOaczJOXpx1QC9vqZaZVzyFA9PtWv7YDRalGU0WgR06XBGo/nEMRrNzRiNMjNGo9yN0SizYzTK3BiNMjenj1LRuOLFl3H+5u3qMqm+2254PLl7HIu6DYfV13+rVgUXP9WL5zTatIEwGi3CMhotArp0OKPRfOIYjeZmjEaZGaNR7sZolNkxGmVujEaZm9NHqWj8+aWhuFAdnurdsRiEX3+tWhl1GI22bR6MRou0jEaLgC4dzmg0nzhGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRRKhp/eWkoLtqyPc/9GL33ZbTv119OqYwL+nBPo13bB6PRoiyj0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxtVHo1H92e99eM9ttOv5yqqVcD6j0bbNg9FokZbRaBHQpcMZjeYTx2g0N2M0yswYjXI3RqPMjtEoc2M0ytycPsobjZds3RHUPY0rT6mM83r35DmNNm0gjEaLsKGOxoOZGUjdsQUH96UioXI1lC1fEepEYn8flcvFYkdKBo6of/7hw28BRqPfVL43MhrNzRiNMjNGo9yN0SizYzTK3BiNMjenj1LRuGbIMFyyZXtQF/WnqpVwLqPRNnNGo0XaUEZj+r4UbFw6BzWiD6NsdAS2pWdhZ0wl1K5/AzxhYX6tGaPRL6bj3sRoNHdjNJqbMRplZoxGuRujUWbHaJS5MRplbk4fpaLx9yHDcOnWHfrqqQWvimrX8x+rVsI5jEbbNg9Go0XaUEbj+u/n4TzPbiRERfjWYu2eDOScdy0SK5/q15oxGv1iYjTKmPKNYjTKEMPDPEgqE43tKZmyDyihoyLCPUhMiMbOVLqZbAKMRhOtY+9lNMrcGI0yN6ePUtH4x5BhqLd1h+/iqd5lPnaXxtyfBPL58ioVcTaj0bbNg9FokTZU0ZiZkYEdy+eiXkJWvjXYd/Awfo+ridMuvNyvNWM0+sXEaJQxMRoD4MZolCEyGmVujEaZG6NR5sZolLk5fZSKxrVDhuGybTuDek7j8qqVcOaTT/CcRps2EEajRdhQRaNa7D/mf4yrymZD/aXS+9i0/yB2V6mDyrUv8GvNGI1+MTEaZUyMxgC4MRpliIxGmRujUebGaJS5MRplbk4fpaLxz5eH43J1eGoQH8uqVERtRqNt4oxGi7ShjMZNv69Aqc2/4OzypfRaZGRl46c9Wah6ZTOUSijt15oxGv1iYjTKmBiNAXBjNMoQGY0yN0ajzI3RKHNjNMrcnD5KReNfLw9H/W07AeTeaCPn6LmN6hxHqAs2en8N4OsqGs9gNNq2eTAaLdKGMhrVom9eswKpm/9BYkw40sOiUensukgoX9nvtWI0+k2V7428EI65G89pNDdTIxiNMjdGo8yN0ShzYzTK3BiNMjenj1LR+PfLw3GFisZAnrSoVvwEn7e0cgXUYjTatnkwGi3ShjoavYuflrYf8fEJxmvDaDQm0wMYjeZujEZzM0ajzEyNYjTK7BiNMjdGo8yN0Shzc/ooFY3rXh6Oq7bvCuo5jUuqVMTpvXrwnEabNhBGo0VYp0SjdDUYjTI5RqO5G6PR3IzRKDNjNMrdGI0yO0ajzI3RKHNz+igVjeuHjsCV23b6dgx6dxD6fvUeoeo7gNV7IOvRXwWvf1e5AmoyGm3bPBiNFmkZjRYBXTqc0Wg+cYxGczNGo8yM0Sh3YzTK7BiNMjdGo8zN6aO80Xj19p1Hz1jMc05jvnMYvaEYmNdVNJ7GaLRt82A0WqRlNFoEdOlwRqP5xDEazc0YjTIzRqPcjdEos2M0ytwYjTI3p49S0bhh6AioaMy96I13ib0XwbHn+beVklCjkGhUF+FJ2ZuGtAMZqFQhEdFRkU4ndOTyMRotTguj0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxo3DRqDh9t1Hz2nMs0cROfCoq6l6f9VXVQ3M699WqoBTe3bPd07jL2vW4ZG+r2BP6n7NFhcbg77d2qJ5kwZOZ3Tc8jEaLU4Jo9EioEuHMxrNJ47RaG7GaJSZMRrlboxGmR2jUebGaJS5OX2Uisb/ho1EQ9+eRhWG6hBU7902vM+P3X4jEK9/XTHpuGhctWYd/vpnExpdVRcJ8XEYN3EGxk2ciRXzxnOPo+GGxGg0BCv4dkajRUCXDmc0mk8co9HcjNEoM2M0yt0YjTI7RqPMjdEoc3P6KBWNm4aNRKMduwqc01jwHMbAPl9YKQmnFNjTWNBqyqyFGP32x1gw7RVERoQ7ndJRy8dotDgdjEaLgC4dzmg0nzhGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRRKho3Dx+Jxtt3HTunUV829diexdxjUvOc4xiA1xdUKI+qRUTjT7/8iZnzFmPRsl/wROdWuKXx5U5ndNzyMRotTgmj0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxi3DR+K6HbuDuqjzK5ZHlSfyn9PoXYDZXy7FZ/O/x+o//kHnDrehbYvrg7psxeHLGI0WZ5HRaBHQpcMZjeYTx2g0N2M0yswYjXI3RqPMjtEoc2M0ytycPkpF49YRr+D6ncGNxq8qlEflHo/nuxBOQSu1x7FDt8H44v2XcWrVik6ndNTyMRotTgej0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxm0jX8ENu/aoY1KPXgRH3XdDH4Nq2/Mvk8qjUvcTR+OuPXtxTYvHkPza07j4/NpOp3TU8jEaLU4Ho9EioEuHMxrNJ47RaG7GaJSZMRrlboxGmR2jUebGaJS5OX2Uisbtr7yKG3erPY3qT3/vw3u7jWPPA/n6vPKJqPh4/micPmcRyiSUwiV1zkKYx4OR46dh1rwlWDB1hL6aKh/+CzAa/bcq9J2MRouALh3OaDSfOEajuRmjUWbGaJS7MRpldoxGmRujUebm9FEqGne8+iqa7Ek5dj/GPHsY892nMe99G/VtOQrcx9Hg9bnlyqHCY4/lOzxVXS11wPD3fGSVKiRicJ8Hcfkl5zqd0XHLx2i0OCWMRouALh3OaDSfOEajuRmjUWbGaJS7MRpldoxGmRujUebm9FEqGneNehU3paQcPSBV7U/0HA1I7202Cv5q/fU5iWWR1C1/NCqrw9nZ2L1nn/7+iuUTERaWd++n0zWds3ziaHxj0iz88vs6v9Zk6LOdERcb49d73fYmRqPbZiwwy8toNHdkNJqbMRplZoxGuRujUWbHaJS5MRplbk4fpaNx9CjckpqaG4q+PYhHQ7HgHsUAvT6nbCLKd+12wgvhON3OycsnjsY3k2fh19//8WvdhjzTidHol1Tw31S5XCx2pGTgiDo/mQ+/BRiNflP53shoNDdjNMrMGI1yN0ajzI7RKHNjNMrcnD5KReOe10bh5r2pBc5oLHgGY2Cff1amLMo9ymi0a/sQR6NdC+S2z+WeRrfNWGCWl9Fo7shoNDdjNMrMGI1yN0ajzI7RKHNjNMrcnD5KR+OY0bh1fypycgCPB0H59bPSZZH4SFfuabRpA2E0WoRlNFoEdOlwRqP5xDEazc0YjTIzRqPcjdEos2M0ytwYjTI3p49S0Zg6VkXj3qAu6qyEMijbhdFoF7o4Gnv0H4O5C5f7tVxLZo3Rl7stjg9GY3Gc1ZOvE6Px5EYF38FoNDdjNMrMGI1yN0ajzI7RKHNjNMrcnD5KR+Pro9HswD7fLkZ9VdQ8uxzteD4rvizKPPwo9zTatIGIo/HrJSuxactOvxar5W3XIjoq0q/3uu1NjEa3zVhglpfRaO7IaDQ3YzTKzBiNcjdGo8yO0ShzYzTK3Jw+SkXjvnGvodmBvUePTfUusfdYVXuezyhVGqU7Mxrt2j7E0WjXArntcxmNbpuxwCwvo9HckdFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxv1vvIbbM/YH52TGo3swP40rg4ROj3BPo00bSECjMe1ABjIyDx63qEnlyuTuki6GD0ZjMZxUP1aJ0egHUoG3MBrNzRiNMjNGo9yN0SizYzTK3BiNMjenj1LRmPbmGDTP2HdsUdVfAvJeqd+G59NjSiP+IUajXdtHQKJx+84UdHtmFFavXV/ocvKcRrumz/rn8pYbMkNGo7kbo9HcjNEoM2M0yt0YjTI7RqPMjdEoc3P6KBWNB8aPwR0H9x+9aqoH6hxGff8NfYRq7vNjpzgG5vVPYhJQ6kFGo13bR0CiccCICfjq2x/xYNumGDLmA7zQ+34klknAiDemoHLFchjzYndERoTbtQ4h/VzuaQwpf8i+nNFoTs9oNDdjNMrMGI1yN0ajzI7RKHNjNMrcnD5KRWP6W2N1NHrD0LvMdj7/ODoBcQ904eGpNm0gAYnG5h2fQdPrr0D7O67HxTc8iJkTBqNWjar4ZukqdHlqJH74fBxKxcXYtAqh/VhGY2j9Q/XtjEZzeUajuRmjUWbGaJS7MRpldoxGmRujUebm9FEqGjPeHou7stIKuT9j7lVUi75/o/z1j6PiEXM/o9Gu7SMg0Xhj6164v80taHlrQ9Rr0hkvP9sJ115xMTZt3Qn12vtjn0Wdc2vZtQ4h/VxGY0j5Q/bljEZzekajuRmjUWbGaJS7MRpldoxGmRujUebm9FEqGjPfeV1HY567bJwgFI9eZNV7cVXhr1Mi4hHT8WHuabRpAwlINLbuMhAXn3cGnnykNdT9G1P3pmF4/y6YNW+JPlz1qykjUKViOZtWIbQfy2gMrX+ovp3RaC7PaDQ3YzTKzBiNcjdGo8yO0ShzYzTK3Jw+Skfju6+jVXY6cpADDzz5f/We01jw597nwtenhscj+r7OjEabNpCAROOotz/G2nX/Yczgx7FqzTq06TLQt7g3NqyHEf0fsWnxQ/+xjMbQz0EoloDRaK7OaDQ3YzTKzBiNcjdGo8yO0ShzYzTK3Jw+SkXjwQnj0PJIelAXdUpYHKLvYTTahR6QaCy4cH+t34Tvf1qDs2pVR72Lziq2t9tQ681otGvTdPbnMhrN54fRaG7GaJSZMRrlboxGmR2jUebGaJS5OX2UjsaJb6AVMo5eJdVT5P0ac6+iGpjXp3jiENWhE/c02rSBBCQaf/9rA+YsWIY7mzZE9VMq+hb1zeRZqFC+LJo3aWDT4of+YxmNoZ+DUCwBo9FcndFobsZolJkxGuVujEaZHaNR5sZolLk5fZSKxkOT3kRLT0a+Q1Nzb9RY4FDVPM+tvv5RTgyi2j/EaLRpAwlIND790ltY8+e/mDb+eYSHh/kW9f3p8zHo1Un48Ys3ERsTZdMqhPZjGY2h9Q/VtzMazeUZjeZmjEaZGaNR7sZolNkxGmVujEaZm9NH6WhMHo+7ww8eO5fx6B5F3zmONjyfkhODyLYPMhpt2kACEo233dMXt914JR5oc0u+xdy5OxUN73gcn7w9EGfVOtWmVQjtxzIaQ+sfqm9nNJrLMxrNzRiNMjNGo9yN0SizYzTK3BiNMjenj9LR+P5bOhqh/vD3PnJ3NNr2/KPD0Yhs8wCj0aYNJCDR2KrTAJx71mno1+OefIv50y9/okO3wZg18UWcXr2KTasQ2o9lNIbWP1Tfzmg0l2c0mpsxGmVmjEa5G6NRZsdolLkxGmVuTh+lo/GDt9A6Kst3TqP33EU7f9XRePf9jEabNpCARKO6rcbEqXP1/RjPP6umPkR1x65UPDf0bfz0y19YMvM1REZG2LQKof1YRmNo/UP17YxGc3lGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRRKhqzPnoHd0cdOrpr8dhtN3J3Ndrz/INDEYhsxWi0a/sISDTu3XcAze9/Btt3piAuNgbVqiThz3826WV+qe9DuPWGK+xa/pB/LqMx5FMQkgVgNJqzMxrNzRiNMjNGo9yN0SizYzTK3BiNMjenj9LROOUdtI45rBdV36cxJwdQV0n1BqN+nrsmgXr9w4ORiGh5H/c02rSBBCQa1bKlZ2Tioxlf49c/1iMj8yBOO7Uyml5XH+eddZpNi+6Mj2U0OmMegr0UjEZzcUajuRmjUWbGaJS7MRpldoxGmRujUebm9FEqGg9PexetY7JtPYfx6MVYfRwfpIcj4i5Go13bR8Ci0a4FdPrnMhqdPkP2LB+j0dyV0WhuxmiUmTEa5W6MRpkdo1HmxmiUuTl9lI7Gj99Dm1JHgnpO44fp4Qi/417uabRpAwlYNC5b+Tumz1mEDZu2o3P723BN/ToYNu4jlC9bGvfd3cSWxd+1Zy9KxcX6dTuPI0dysGN3CsokxBf5/q079qBSUiLCwvJe2unEi85otGVqHf+hjEbzKWI0mpsxGmVmjEa5G6NRZsdolLkxGmVuTh+lo/GTCWgTf8R3TqP3XEY7f/0gzYPwFvccF42qAfak7tPXVymTUMrpfI5dvoBE429r/0XLTv1RqUIi9qdl4LnuHfR5jN77NP40903ERAfuPo0bN29H594jdKCqR4ubr8ZzPe5BZER4odCLl69Gn0FvYE/qfv16m+aN8VTXdr44VBfxmfzJV8g6fBhZWYfRvEkD9OjUUr93/qIV6PbsqOM+d8W88YiOigSj0bHbtq0Lxmg052U0mpsxGmVmjEa5G6NRZsdolLkxGmVuTh+lo3H6RLQtnaNOYdTnMuZeNVWf0mjbcx2Nt3fIF41Lf/wN3Z4drU+jU496F52Nng+30hfu5MNMICDR+OzL72Dv/jS8+nxXdHpyOG69/godjes3bkXTDk9h5nuDUOu0U8yW7ATvfqjXMMSXisWgPg9i247daNlpgC9UCw5TeyOvafEYHmzbFA+1a4pNW3ehecdn8ELv+3UceoP33ZF98L+Lz8Y/G7fi1g5P6SvB1jm3Fr5a9BOeGjwe08YPyPfR1U+pCI/Hw2gM2Ky664MYjebzxWg0N2M0yswYjXI3RqPMjtEoc2M0ytycPkpFY/aMSWhT2nftG73IR3vx6P8B8lwbJyCvT94HhDdrny8av1+xBjt3peLq+nWQmXkIz4+cALXn8fWXujud0XHLF5BobHB7V3R/6C69x08FnTca1Z499ZoKrnNq1wjIyu/dfwBX3PoIkl97GhefX1t/5qBXJ2Hbjj0YPeix475jwXcr0PWZUVgya4xvl7S6RYjaWzlm8ONQh9V27D4EcyYPQfVTKunxapmf7NJah6+KxgHD38OiT0cXuvzc0xiQaXXdhzAazaeM0WhuxmiUmTEa5W6MRpkdo1HmxmiUuTl9lI7GmZPQLjEsqOc0vr8XCLu13QnPaZw1bwn6DH4Tq+a/jYjwwo9QdLpvqJYvINH4QM+hKJ9YGkOe7pQvGmd/uRS9B72B72ePRUJ8XEDWcd2/m3HbvU9j4cevoEL5svozJ02bhxlzFx+3N1C9tmjZr+jce3i+ZVCHzX746XzMnDAYhw5l4f4nhuKPvzei2/0tkJaegXkLl2PCqL4oHR+no/GxZ0ej2Y1XIjo6CpfWOQs3Nqzn29AYjQGZVtd9CKPRfMoYjeZmjEaZGaNR7sZolNkxGmVujEaZm9NHqWg8Mnsy2ibmvUaI99hU79IH/vnklGyENT1xNKpg/Hv95kKbwemuoV6+gETjl9/+iMefe02fK7hsxe9oeMVFKFe2NIa+/iFuv+kqDOrzQMDWc+Xqv9Du0UH59hxOmbUQ4ybOwIKpI4/7HrVnsmn7PqhdsxpaNbsWe/en44PpXyE7+4iORvUYP3k21L88xMZEY/Xa9XigzS3oen8LHYbqFiJzF/6g91Ju2b4bU2Z+rdfz6cfa67EZB7MDtm6h+CD1B93BrGx9iAAf/gvERoe7fu79X9vAvFP98RAdHY5Ml/+eyafh/zWzxIjaLTIMmVnqggKBf2Rn5yA8PAgrEvhFP+EnquuZRUaE4aBNbiddHZf+NzUsDIgMD6HbSWGd+YbwMI/+fXQoVNubM1lOulTKLMzjQdZha/99U+z0kcMAACAASURBVH8m8+EcAR2Nn01Gu/LhRw9BPXZOY+4hqfY8f39PNjy3tC1yT6N3L+Nbw3qh/qXnOQfMJUsSkGhU66rCbejYD30nmqqf3dL4cjz9ePuAXqnIu6fxm09eRVK5Mpr5RHsa1evqgjkqDNWvp1RJwpq1/+LUUyrqw1MXLftFX1Rn6eyxes+iumiOCuCenVuiVbNGx03jJ59/C3UOp3e39p79B10y1YUvZtn4aOxNO6iPM+fDf4FyCdFw+9z7v7aBe2diQjRSXP57Jp9GEH7jqKs5J8RFYm/aocBNRJ5P8p1TYsunh+5Dw8I9iI+JxL4D9riddM1c2uERYWGIjQnH/vSsk64i33BMQP0DRXREGNIyc29mzod/AsosIiIMByy6qT+T+XCOgI7Gz99Hu6SIoC7U5F2H4bm5TaHRqP5+r06h69fjHrS87dqgLldx+bKARKO6MtG+tAO49oqLsWnbLh2O1SpXQNky8QF3KuycxoEjJ2LHrpRCz2ksuABq2eo16Yw+j7ZB+ztvwCvjp0Gd9+jd66je/0jfV1AqNgYvP9v5uOX3Hu7qvSIsD08N+BS74gN5eKr5NPHwVHMzNULtwUgqE43tKblXfuPDP4GIcA/UP1LsTKWbf2K57+LhqSZax97Lw1Nlbjw8Vebm9FE6Gud8gHYVo45d7UZfPTV3D6O+jGohv1p9XUfjTXcfF43qiMEe/cf6LoLpdD+nLl9AorFH/zFIO5CBN4f2DMp6qnMoS8eX0oe9Fnb1VLVhVK1cHj07t9LLsztlH0onlMLulL0Y/fYn+Pb7VZj7wVDExcbg8/nL0Gvg6xg3pAeu+t8F+G/LTjRp+yR6PXw37m11k75tyFm1TsW5Z56mrxDb6/lx+tYe74zsrT+b0RiUKXfclzAazaeE0WhuxmiUmalRjEaZHaNR5sZolLkxGmVuTh+lo3HuR7nRGMTH5B2H4LmxVb5oVNc86fvieL2zqNFVdX1Lk1gmXncAH/4LBCQax06YgRlffKdDLBgPdSsPdUjppq079dep8yb7P3GvvmmneqhbatSsXgUj+j+in6u9ierwVPVocNkFGNCzo76npHqoy+6+kTwTn875Tt/HMSE+FrfdcCUeua+5jsMRb0zB2x987lutC8+thaHPdka1KhX0zxiNwZhx530Ho9F8ThiN5mZqBPc0ytwYjTI3RqPMjdEoc2M0ytycPkpH47wpaFcp97Bh3x7Eowtu1/PJ2w/Cc0PLfNH4/MiJ+GjGguPIvLfec7qlk5YvINGo7oXYpG1vjOjfBQ0uuzBo67d9Z4q+X2OpuBP/S0F6xkG9l7FyxfI6BIt6bNm2S79HnUOU95F58BB27k5FQqm44w65ZTQGbbod9UWMRvPpYDSamzEaZWZqFKNRZsdolLkxGmVujEaZm9NH6Wj8ciraVY45diiqd6G9h6ba8Hzytkx4rr/rhLfccLqdk5cvINHY8/nXMWfBsiLXM+89Ep2MIVk2RqNEzf1jGI3mc8hoNDdjNMrMGI1yN0ajzI7RKHNjNMrcnD5KR+NX09C+alxQ79M4eWsGPNfdyWi0aQMJSDTOX7QC/23ZUeQitm7eGNFRkTatQmg/ltEYWv9QfTuj0Vye0WhuxmiUmTEa5W6MRpkdo1HmxmiUuTl9lIrGnPkfo+0ppXyLGvi7MiLflf/V5ydvPgBP4zsYjTZtIAGJRpuWzRUfy2h0xTQFfCEZjeakjEZzM0ajzIzRKHdjNMrsGI0yN0ajzM3po/SexgWfoP2pCcHd06ii8drmjEabNhBGo0VYRqNFQJcOZzSaTxyj0dyM0SgzYzTK3RiNMjtGo8yN0Shzc/oovadx4adoWy0+9yI46mI4yN0zmO9X7204AvR68n/74Wl4O6PRpg2E0WgRltFoEdClwxmN5hPHaDQ3YzTKzBiNcjdGo8yO0ShzYzTK3Jw+Su9p/GYG2lcvXXQwFhWKFn4+eeM+eK5pxmi0aQNhNFqEZTRaBHTpcEaj+cQxGs3NGI0yM0aj3I3RKLNjNMrcGI0yN6eP0nsav52JtjXKHNuzmOeqqYXueQzA68n/psJz9W2MRps2EEajRVhGo0VAlw5nNJpPHKPR3IzRKDNjNMrdGI0yO0ajzI3RKHNz+ii9p3HRLLSvmRjccxo3pMJz1a2MRps2EEajRVhGo0VAlw5nNJpPHKPR3IzRKDNjNMrdGI0yO0ajzI3RKHNz+ii9p/G72Wh3erl8i+rdw1jU8lt9PXn9HniubMpotGkDYTRahGU0WgR06XBGo/nEMRrNzRiNMjNGo9yN0SizYzTK3BiNMjenj9J7Ghd/hvZnJAV3T+M/e+C54mZGo00bCKPRIiyj0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZTe07h0DtqdkZS7qDk5gDpn0fuw6Xny37vgqd+E0WjTBsJotAjLaLQI6NLhjEbziWM0mpsxGmVmjEa5G6NRZsdolLkxGmVuTh+l9zQunYP2Z1bM04k5+vYbx7ox8M8nq2i8/CZGo00bCKPRIiyj0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZTe07hsLtrliUbfMue5Smqh62Hh9eQ/d8Bz2Y2MRps2EEajRVhGo0VAlw5nNJpPHKPR3IzRKDNjNMrdGI0yO0ajzI3RKHNz+igdjT/MQ7uzKx87NNV7SKqNvyb/uR2eejcwGm3aQBiNFmEZjRYBXTqc0Wg+cYxGczNGo8yM0Sh3YzTK7BiNMjdGo8zN6aN0NC7/Cu3OqZxnUdXfAgq7Q6P3LdZfT/5jCzyXXs9otGkDYTRahGU0WgR06XBGo/nEMRrNzRiNMjNGo9yN0SizYzTK3BiNMjenj9LR+ON8tDuv6tFO9Bzd4+jtRnueJ/++BZ5LGjMabdpAGI0WYRmNFgFdOpzRaD5xjEZzM0ajzIzRKHdjNMrsGI0yN0ajzM3po3Q0rliAdudVy7+oVm/EeJLxyb9tgqduI0ajTRsIo9EiLKPRIqBLhzMazSeO0WhuxmiUmTEa5W6MRpkdo1HmxmiUuTl9lI7GlV+j3QXVc/cwoohDT30XvQnM68mrN8FzcUNGo00bCKPRIiyj0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSOxp+/yY3Gok5VtOHnyb9shOeiaxiNNm0gjEaLsIxGi4AuHc5oNJ84RqO5GaNRZsZolLsxGmV2jEaZG6NR5ub0UToaV32LdnVOO7ao+Q4tzXNOo/cdAXg9+dcN8FzYgNFo0wbCaLQIy2i0COjS4YxG84ljNJqbMRplZoxGuRujUWbHaJS5MRplbk4fpaPxl+/Q7qKaQV3U5FXr4bngKkajTeqMRouwjEaLgC4dzmg0nzhGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRROhp/XYx2dWsF9z6NP6+H5/wrGI02bSCMRouwjEaLgC4dzmg0nzhGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRROhp/W4J2dc8I6qImr1gHz3n1GY02qTMaLcIyGi0CunQ4o9F84hiN5maMRpkZo1HuxmiU2TEaZW6MRpmb00fpaFyzFO0uPfPofRrV/RlzAH21VO/FVAP/PHnF3/Ccczmj0aYNhNFoEZbRaBHQpcMZjeYTx2g0N2M0yswYjXI3RqPMjtEoc2M0ytycPkpH4+/L0K7emUcL0bvEBW+0GNjnyT+uhefsyxiNNm0gjEaLsIxGi4AuHc5oNJ84RqO5GaNRZsZolLsxGmV2jEaZG6NR5ub0UToa//gB7S47J/99GgvelzHAz5OXr4XnrHpFRuPh7GxEhIc7nc+xy8dotDg1jEaLgC4dzmg0nzhGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRROhr//BHt/ndOcO/TuOx3eM68tNBo3Lh5B5q0fRJffjgMVSsnOZ3QkcvHaLQ4LYxGi4AuHc5oNJ84RqO5GaNRZsZolLsxGmV2jEaZG6NR5ub0UbnR+BPa1T/v2KJ6z2n0/sSG58kqGmvXPS4aW3cZiF/WrNPfzGiUbz2MRrmdHslotAjo0uGMRvOJYzSamzEaZWaMRrkbo1Fmx2iUuTEaZW5OH6Wj8e+VR6NR/envu/pNEec4Bub15KWr4Tnj4uOicceuVGzbsRsqHhmN8q2H0Si3YzRatHPzcEaj+ewxGs3NGI0yM0aj3I3RKLNjNMrcGI0yN6eP0tG47me0u/LC4N6nUUXj6XUKPTx1+84UNLqrO6PRwsbDaLSAxz2NFvFcPJzRaD55jEZzM0ajzIzRKHdjNMrsGI0yN0ajzM3po3Q0/rMK7a6qE9RFTV78Czw1L2Q02qTOaLQIy8NTLQK6dDij0XziGI3mZoxGmRmjUe7GaJTZMRplboxGmZvTR+loXP8L2jW4WC9q7kVSj91ew67nyd+tgue0CxiNNm0gjEaLsIxGi4AuHc5oNJ84RqO5GaNRZsZolLsxGmV2jEaZG6NR5ub0UToa/12NdldffLQYvUucY+vz5EUr4KlxPqPRpg2E0WgRltFoEdClwxmN5hPHaDQ3YzTKzBiNcjdGo8yO0ShzYzTK3Jw+Skfjht/QvuGleg+jx+MJyq+Tv10BVD/3uGjMOpytL4RzU5sn8XnyEH3LjcgI3q/RdDtiNJqKFXg/o9EioEuHMxrNJ47RaG7GaJSZMRrlboxGmR2jUebGaJS5OX2Ujsb/fke7ay49emiq2sHoDUfvtXEC/3zSwuXwnHrOcdFYr0lnpGdk+tjKlU3Aok9HO53RccvHaLQ4JYxGi4AuHc5oNJ84RqO5GaNRZsZolLsxGmV2jEaZG6NR5ub0UbnR+AfaN/ofcm/HWNSexoIBWfB9Zq9PXrgcqHZWoYenOt3MDcvHaLQ4S4xGi4AuHc5oNJ84RqO5GaNRZsZolLsxGmV2jEaZG6NR5ub0UToaN/+Jdo0ug/qzv6jHsUvjFP4O09eTFywDTjmT0WjTBsJotAjLaLQI6NLhjEbziWM0mpsxGmVmjEa5G6NRZsdolLkxGmVuTh+lo3HLX2jfuD5ykAMPPPAG4PG/Bu71yfO/B6qewWi0aQNhNFqEZTRaBHTpcEaj+cQxGs3NGI0yM0aj3I3RKLNjNMrcGI0yN6eP0tG4dR3aX3dFUBc1+aslQJVajEab1BmNFmEZjRYBXTqc0Wg+cYxGczNGo8yM0Sh3YzTK7BiNMjdGo8zN6aN0NG77B+1vuEqflOg9p9F7VRy7nutorFST0WjTBsJotAjLaLQI6NLhjEbziWM0mpsxGmVmjEa5G6NRZsdolLkxGmVuTh+lo3H7erS/ocHR+zKqg1KPPjye3Kvb2PA8ed53QKXTGI02bSCMRouwjEaLgC4dzmg0nzhGo7kZo1FmxmiUuzEaZXaMRpkbo1Hm5vRROhp3bECHm64Jyv0ZvXsuk+ctAipUZzTatIEwGi3CMhotArp0OKPRfOIYjeZmjEaZGaNR7sZolNkxGmVujEaZm9NHqWjEzo1o16ThsR2KgL4Yjveh/k4Q6OeTvvgGSDqV0WjTBsJotAjLaLQI6NLhjEbziWM0mpsxGmVmjEa5G6NRZsdolLkxGmVuTh+l9zTu+g8dbm507Kqp3nMbAX0bjhwbnid/sRAoX43RaNMGwmi0CMtotAjo0uGMRvOJYzSamzEaZWaMRrkbo1Fmx2iUuTEaZW5OH6X3NO7ejHa3NM53n8aC910M9PNJny8AylVlNNq0gTAaLcIyGi0CunQ4o9F84hiN5maMRpkZo1HuxmiU2TEaZW6MRpmb00fpPY17tqDDrdfn7lHU92k8dhVV7zmIvl8D9HryZ/OBxCqMRps2EEajRVhGo0VAlw5nNJpPHKPR3IzRKDNjNMrdGI0yO0ajzI3RKHNz+ii9pzFlG9rfer33YNSg/Dpp9jygbGVGo00bCKPRIiyj0SKgS4czGs0njtFobsZolJkxGuVujEaZHaNR5sZolLk5fZSOxtTtaN/sptzba3g8vnMYvc8L/uo9x9HK68mz5gFlKjIabdpAGI0WYRmNFgFdOpzRaD5xjEZzM0ajzIzRKHdjNMrsGI0yN0ajzM3po3Q07t2RG425l73Js8j2PZ80cy5QugKj0aYNhNFoEZbRaBHQpcMZjeYTx2g0N2M0yswYjXI3RqPMjtEoc2M0ytycPkpH476d6HB7E73j0Pco0IseT+6OyEC9PmnmF0BCEqPRpg2E0WgRltFoEdClwxmN5hPHaDQ3YzTKzBiNcjdGo8yO0ShzYzTK3Jw+Skfj/l1o3+zmohe14A7Hgu8UvD5pxhwgoTyj0aYNhNFoEZbRaBHQpcMZjeYTx2g0N2M0yswYjXI3RqPMjtEoc2M0ytycPio3GnejffNb9K7E466WevQcR3WuYyBfT54xBznx5RiNNm0gjEaLsIxGi4AuHc5oNJ84RqO5GaNRZsZolLsxGmV2jEaZG6NR5ub0UToa0/bkRmOBh/f2G0Wtg5XXJ03/DGA02rZ5MBot0jIaLQK6dDij0XziGI3mZoxGmRmjUe7GaJTZMRplboxGmZvTR+VGYwo6tGiqL4HjPdLU7l+Tp89GTqlE7mm0aQNhNFqEZTRaBHTpcEaj+cQxGs3NGI0yM0aj3I3RKLNjNMrcGI0yN6eP0tF4IBXtW9zqW9SigtH7hkC8PvGTWUCpsoxGmzYQRqNFWEajRUCXDmc0mk8co9HcjNEoM2M0yt0YjTI7RqPMjdEoc3P6KG80drizme/+jN77MNr5a/Ins5ATV4bRaNMGwmi0CMtotAjo0uGMRvOJYzSamzEaZWaMRrkbo1Fmx2iUuTEaZW5OH6WjMX0v2t/RLPdaN95DVHNg6/OJ02YCcaUZjTZtIIxGi7CMRouALh3OaDSfOEajuRmjUWbGaJS7MRpldoxGmRujUebm9FE6GjP2ocOdt+v7MAYrHJOnzUBObAKj0aYNpNhG45EjOdixOwVJ5cogIjz8pHxZWYexa89eVEgqW+j70zMykZWVjTKlS+X7LEbjSWmL5RsYjebTymg0NwtlNKanpyEuLl620A4YFRHuQWJCNHamZjpgadyzCIxG2VwxGmVujEaZm9NH5UbjfnS4q7leVO+eRu9y2/V80rRPkRMTz2i0aQMpltH4zdJV6Pn861Chpx79nrgXLW9tWCThOx9+juHjpvhef6H3/WjepIF+vn1nCl54ZSK+X/G7fn72GdXRt1tbnFO7hn7OaLRpy3T4xzIazSeI0WhuFopo3Lh4Lvb98wfKZmUgs2wlVL7qJsRXrCJb+BCOYjTK8BmNMjdGo8yN0Shzc/ooHY2ZaejQskVwz2lU0RhdqtBoPHQoCyl701Axqay+byQf5gLFLhozMg/h6ubd8GjH5mjb4josXPIzHnt2NOZ+MBTVqlQ4TmjRsl/QufcIjBrYDddcUQdz5i9Dn8FvYtbEF3F69Sp4cuA4pO5Lw5jBj8MT5sGA4ROwc3cKxg15gtFovr0VmxGMRvOpZDSamwU7Gjcu+gJlvp2G2gdT9cKmh0Xgx0rnoMa9vRAbGydbgRCNYjTK4BmNMjdGo8yN0Shzc/ooHY0HD6D9XS30oanH3Xfj6Ap4D10N1OuTpnxyXDSqC++8PnEmxrw7XX9rubIJeG3w46hzbi2nMzpu+YpdNKq9jF2eGomV88YjKipSg9/crrcOyLYtrj9uAoaM+QDLf/4D08YP8L122z19cWfTa9DhrhvR7tFBqFGtEgb1eUC/Pn3OIox+5xMsmDqS0ei4zTl4C8RoNLdmNJqbBTsaV08YiUbrFudb0I2RCdjX4lFUPO8S2QqEaBSjUQbPaJS5MRplboxGmZvTR+VGYzo6tLojz57Go+c2es9x9P2ao/f8+c59tPB68tSPkRMVl29P48rVf+m/y08a3RcXnH06Rr39CT6bvxRffTQCYWHc42iyLRW7aJwyayHe+2gOPk8e4nPo+vSrOO3UKniic8vjbF4ZPw1Lf/wNH73Rz/dat2dHoWqlJPR5tA0WfLcCXZ8ZhcYN6upDVoeO/RAd775ZR6V68PBUk82t+LyX0Wg+l4xGc7NgRmN6+gGkTngZF239Ld+CpoTHYP21rVHt6ltkKxCiUYxGGTyjUebGaJS5MRplbk4fpaPxUAY6tLrz6KIWPIux4BoE5vVJH01DTlRsvmhUp5/9/vcGvDWsl/7SHbtSce2dj+udRd5TzZzu6ZTlK3bR+Nb7n+GLr3/It+dQnd8YHxeL/j3vPc591Zp1aNNlIFo1a4TL656LjZu3Y8KUL3DLdfV1NG7etgsP9hyKM08/FYuXr0ZMdCTeHdkHZ9Q8RX9Wdrba0N37UP/KckT9847TVsPh//gTHuZB9hGnoTl/O9TbG92MJ0r9Y6hdbIeyjiAqMkwv008TXsfZK+Yi7shh3zL+HpuEio+/gKSq1YyXO9QD7HQL9brZ9f3qP73qcDK7tje7ljvUn+tatxD/MaYPXVS3ZDhibQbDwx3+lwZrq+e60b5ovFvtrMnddajvz6gm28bnySoaI2PyRaNqgMQy8Xj6sfY+x/Ma3ouxL3bHNfXruM42lAtc7KLRdE+jwld7Gj+YMR/79qfrC91MmjYPvR9prQ9PbdVpAK654iJ0uacZ9qelo9+w96DOg1w6e4y+yuq2lIxQzp/l765YNha7UjNg8b/XlpfjuA8I8R9kJ1uhyuVisW2Pu+f+ZOsY6NfVHxUVy8ViO92MaNU/UJQrbeNVQPP8A2/azq34b9p41Ni5HglHsrA1tgz2nHslzr61jdEyO+HNak9jmfho7N7Lq6eazEdkRBgS4iKxZ99Bk2El/r3RUeGIjQpHatohd1mEuLWUWVREOPamW3OrnBjrLvdivrQqGn9ZuQJ1LjgvqGu66tffcOHFdfNF40O9huGsWtXzHW1Yr0lnvSPplsaXB3X53P5lxS4avec0/vzlW4iMjNDzc2PrXuhw1w2FntNYcAJX/Pon2ncdjKlv9keNapXxv5s7Y/QL3dDoqrr6rb+t/RctO/XHp+++gNo1q/HwVLf/DhAuPw9PNYfj4anmZmqEisakMtHYnhKc+MnISMfe//5B1r4UxNeojcQKlWULHuJRPDxVNgE8PFXmxsNTZW48PFXm5vRRq1atgvpfKB516tSB+p/3ofY0qovf9O3Wzvcz7mmUzUyxi8b0jIOo16ST3lPYppCrp6qL3qiL3wzv10Vf4EY91PHNiWUT8M+GLXju5Xf05XhHD3rMF5w1q1fGkGc6Iy4mGuocyK+XrMTMCYP1nkae0yjb8Nw+itFoPoOMRnOzUESjbCmdN4rRKJsTRqPMjdEoc2M0ytw4yn8BdU7j2nUb8ebQnr6/8/OcRv/98r6z2EWjWrkFi1dCXfzG+3jm8fZofXtj/VQF36N9X8Unbw/EWbVO1T9Th6CuXrsecbExaN7kKjzRuRWij1559fe/NuD1iTMwf9EK/fqldc7Sh6pecM7peiyjUbbhuX0Uo9F8BhmN5maMRpmZGsVolNkxGmVujEaZG6NR5sZR/gscu3rq0/rv7q++NQ2fz/+eV0/1n9D3zmIZjWrtsrOPYNvOPahYvqzvMNWifFL3piHj4CFUrpBY5A0/D6Rn4vDhbJQpXSrfxzAaBVtdMRjCaDSfREajuRmjUWbGaJS7MRpldoxGmRujUebGUf4LqAvwvPbudIybOFMPUjuA3hz6BC4+v7b/H8J3aoFiG43Bml9GY7CknfU9jEbz+WA0mpsxGmVmjEa5G6NRZsdolLkxGmVuHGUukHnwEPak7EPliuV5f0ZzPkaj0CzfMEZjIBTd9xmMRvM5YzSamzEaZWaMRrkbo1Fmx2iUuTEaZW4cRYFQCHBPo0V1RqNFQJcOZzSaTxyj0dyM0SgzYzTK3RiNMjtGo8yN0Shz4ygKhEKA0WhRndFoEdClwxmN5hPHaDQ3YzTKzBiNcjdGo8yO0ShzYzTK3DiKAqEQYDRaVGc0WgR06XBGo/nEMRrNzRiNMjNGo9yN0SizYzTK3BiNMjeOokAoBBiNFtUZjRYBXTqc0Wg+cYxGczNGo8yM0Sh3YzTK7BiNMjdGo8yNoygQCgFGYyjU+Z0UoAAFKEABClCAAhSgAAVcIsBodMlEcTEpQAEKUIACFKAABShAAQqEQoDRGAp1ficFKEABClCAAhSgAAUoQAGXCDAaXTJR0sXMyclB9pEjiAgPF33EkSM52LE7BaViY5AQHyf6DDcOUuut7MLDw4wXPz0jE1lZ2ShTupTxWLcP8Mdtd8o+vZrlE0vnW939aek4nJ2NxDIJbmcwXv6TuRX1+1B57dy9F+XKJiA6KtL4e90+QOrm9vW2uvxquwnzhBV5g+uT/Xf/QHom9qWlo1JSYom6SfbJ3LKyDmPH7lRUKFcGUQV+P+7asxfxpWIREx1ldfpcN/5kbidaIeVWKi4WsTElz811E80FLvYCjMZiPsWz5i3ByPFTsWDqyHxrets9fbFuw5Z8P3vk3tvR5d7b9c/UX+AHjUqGGq8eNzashxH9HynmWrmrp2Kx//D39P8f0PM+v92270zBC69MxPcrftdjzj6jOvp2a4tzatco8W7qL6Fvf/AZJk6diz2p+xEXG4Plc8ZpFxXZvV94AwsWr9TPLzy3Fka/0A1J5cqUeLcT/T4cP3k2Xhk/zWekfo/263FvifnHihP9PvX3v18j35yKt97/DEtnj0XpEvKPYhmZh9CqU3881O5WNL2+fr7fYydz+2bpKgwZ8z42bNqux01/5wWceXq1EvH79ERu6zduxXND38WKX//UFs9274C7mzXS/3/x8tV47d3p2LRlBzIPZqH+pedicJ8HdUCWhEdRbg1u76r/LCj4mPHuIJxR8xRs3LwdnXuP8G1rLW6+Gs/1uAeREbJ/AC8J1lxHCtgtwGi0WzhEn6/+g/tgz2HYtHUnKlVILDQaKTWnPwAAGLhJREFUb7muPm669n++JSyTUAply8RD/QW/Zaf+CA8LQ8fWTdDgsjpIO5CBikllQ7Q2wfvauQt/wAuvTNJ/mN3Z9JpCo7EotycHjkPqvjSMGfw4PGEeDBg+ATt3p2DckCeCtwIh+qaTuQ0fNwWffrEInTs0Q5NGl+FQVhYqVyinl1b9pX3qrIWYNPpp/a/JD/cZiZrVq2Dgkx1DtDbB+9oTuZ3s9+HU2QtxatWKqHPuGfhvyw7c32MI7m99C+5tdVPwViBE32TFzbvI0+cswjND3tZPS0o0Dhv3Ed79cI5e5yFPd8oXjSfb3hYu+RmP9H0FD7ZtimY3XqmPCIiOjioRe4BO5Kb+sbDRXd31f9faNG+Mc2qfhsyDB7WP2sNWp/H9eLRjc3RufxsyMg/izgf76T9bOt59c4h+9wTva0/kpv6bpbY572PNn/+i5/Ov67+rqL+zPNRrmA7rQX0exLYdu9Gy0wA8170Dbr3hiuCtAL+JAhTIJ8BoLKYbxP+1d9/xUVRrGMdfQu9CpFgRUBAEaSJFEQQvCESKCAKKVDWU0KRJjDRpUkIv0pEuXURQmoICKiioKCKiUkR6JxXufQ/smoTNZoeYS8j5zT9+JLOzc75nNtlnzjnv6B8rndaxYcu3MnXeKo+hUb9c6t27uJuO+AQFj5bVc4ZKvnvzpFAhz826dDlczl24KDoCodOIPI00xuf2coeBxmtgrzbm4PqldOz0pTfYp0RQb27HT56RKg06yzs9W0v9mpVuaL5+idJRMv0yqpsGgq59J8gPG2dIqlT6oI6Uu3lzc/o5DHl3uhz+67hMD+2ZcsGutyyxbl9/97O0e3OU9O/e0nxRtSU0njl7QcIiIqRpuwHS9bVGsUKjt+tNR3Wfbx0ihR+8X4b0fi3FX19xG+jN7d3x8+XDT7+UjUtG3bAMRK/TsjVfj/W7r/fgKZI6dWorbop5c4trHNhzhOTyz2Fczp6/KBWfay9zxgVLqWIPmV0Hjn5fjh47JWMHdrLu+qPBCCQXAUJjcumJJDqPjzdsl2ETF3gMjZkzZ5SC+e6Wu/P4my8P999zLSAOHT9fFq/6zIxC/vr7Ycnln92MYJQoWjCJzjL5HbZ/6GyJjo72GBrjc9uwZacEvTVGqlUqbcLRsAkLzN1kvatsy+bJbf3mndIxZIyZrvXLb4ckffq0Uqd6RalT/QnDUrZmoPlSpcFRN73j3PC1vvLlh+NFR79t2Dy5OfkcRkZFS40m3aR2tQryRmAjG8hMG2/GTadW6o2KUf07mDV5dVsGWxMaXRdGjSbdJajV87FCo7frTWde6HTCqk+UksioKLl4KVwqlCkqrZrUsmqNnic3XeqRMUN6uSuPv/z190mzHCGweR33TIqRkxfJtPmrpWXjmuZnQ8bOlfeGdbNm2YJec57cYv6S0ps4LToPkU8XDJe7894p+38/LHVaBMumJaMkl/+1GU7vL/5EVqz9QhZP6WfN7zcaikByEyA0Jrce+ZfPJ77QOH7GMvFL7Sf/W74nGnb0i9SSqf1McNQv+Ht/PWimuemXqjUbv5KP1m+TVbMHm2mDNmzxhUZvboePnpBXuw2TQgXuM+tYMqRPKzNCe5n1GbZsntzmLl0ng8bMMVO0Che4T/b+dlDGTV8m74YESq2q5aTY0y1lwuAuUrlCCcPk+sKwbuEI80XMhs2Tm5PPYZ/hM2T1+u3y0ftDrJhG7romnLrlvCObmXrfvNGzZirhrwcOExqvY3q73sLCI0zQbhhQRSqWLSbnzl80NxdrVysvfbu1sOEjatroKfw8UqWFlCtVxNwoTJcujUyZ+5FZp61r89KmTSPbdu6R7v0nmrXaOsX3ibLFZNjbba25IZZQaNRR7MaB/aX0o4WkZ/smxvnbH/aJztyJeeNw0YebZNLsFVbM3LHmA0VDbzsBQuNt12XOTji+0BjzKFrxrUbT7tKsQXVzN1S/PNyTN5f7F3h09BWp0qCTtG1ez3zRsmGLLzR6c3vx9X5SuWJJade8rikk1Gf4TNm8fbdsXTX+pqvX3m7W8YXGhSs2yMpZg9zN6TXoPQkLizCjPTrSqFN6q1d+zPyckcZrTL5+DifMXC7jZy6XBZP6SPGH899ul0yizje+0Bjf7y//HFnN1OdXGtYQnfh86ux5U+zrxbpVpWFAZWtGfzyFH2/XW6liD5rQuHn5WFOpV7elqz+XwWPnyVerJ6b4aeSuizS+0DhmQEczw0Q3LYoT8MqbsnTaAMmbO6eZZqlTxjVYaq2BDr1Hy4P575WRfdsl6tq/nV7sbaRx3eYd0ilkrHy2dLS7+JnrxmHMf2Ok8Xbqcc41pQoQGlNqz15vly+hUXeNGXi0aMm+AwfdBVw0NJYPaCftW9aTFo1SfpEN9fAlNMZ0a96whjxeK9BU/az65LUvDz/u/d2Maiyf8Y48lN+OCoOe3LTiYrs3Q+W7ddPcle90HZkWhdCiQfplVKdCt2la27jZtKbR9evHk1tCn0MtIjFi0kLRO/CzRveSooUeSOG/zW5snlO3So8Xl/VbdroPpOu+dST89WbPmVGzgg/YMSvA05d4b9ebjqJp+Jk/IcSMmOm2aOVG6Tdylny/YYY1j93w5Ka/v/Ta0RuuurkCj97E0TV9ulbvixXjTJE53bSC9Njpy9zVo2340MYXGrX2gk7v1SJCOl3atXla0zggdLYcO3GaNY02XDC0MdkKEBqTbdck7sR0ykdUVLSZWqqP3Fg7b5ip6KnPa9S7nVr0QL+o++fILms3fiU9B06W2WN6S5lHC8muPftNoQRdd/F4yYdl+dot0nf4TLOWIKU/PkID8pX/PdfyndHvG7++b7QwRQv8/FIl6KZ/GPPfn1eGvhUomTKkN49D2Pjlt2aE7Wafk5m4q+D/92pvbvo8t2oNu4oG67bN68oPew+Y6yu4UzMzcq2PjtA1tFo9NVPG9KbMui3VU725JfQ51MqfWmxJq/MWyPfPtHGtPGjz9ZaQW8xPhW3TU/VL+tUrV81IWOArdSTgmQpmCqVuCblp+NEbFTo74MSpc2bKpU4f1/9P6Zs3t+kLVpuKtBoStdpn6OQPZP2WHfLJghFy6sw5qd64m5l9oo84uRweIe16hZpnHk8c0iWls5nqsfFdb9p412j1ukUjbpiu26bbMMmWJbOZhUL11BR/qdDA20SA0HibdJTT03R9GYr5Oi1VrZXvNDTqonMtFe7adC2BTtlybfpHUMtlu7b4Kl86Pa/kvr/r7nnM89RqblplNiG3n/b9IRNnrxAt/KLPIXysRGHzZaF4kQLJvdmJPj9vbnrwrd/8KB1Dxpq1PrppWOzZoakJN/qgcB15/HzbLvOzYoXzm7vJNjziJSE3b59DvUmhj9SJu9lQ9TgxbjaHRp2aqyP5MbeYa9W9XW96rXV+e5zo7znddLqlrku24Xmq3twiIiKl95CporN6dNObNqP6dXCPyKr3+4s/lb37D5qf6zT8oNbPuwvlJPqXbzI+gDe38IhIeaZRV/O9w1U5O2ZTdJqv3kB0/Y6r9+yT5iau6yZHMm42p4ZAihUgNKbYrvXeMB2J1Ip4+iVe7xZ7GpnQ4gf6uIS8uf15oO51Tl/cNATpKGX2bHZU/vT1I6R3nfVGRY7sWUyojrvplCRdX2vDl1BfzXQ/PodOtP7ZF7ekcTt24oykSZPavbbx5t4l5b1KZ1RcvHjZrGP09Kgg/VuaLWtmSZ8ubcprfBK2SP9m6Ahu5kw3/s1Iwrfl0Agg4EGA0MhlgQACCCCAAAIIIIAAAgggEK8AoZGLAwEEEEAAAQQQQAABBBBAgNDINYAAAggggAACCCCAAAIIIOBcgJFG52a8AgEEEEAAAQQQQAABBBCwRoDQaE1X01AEEEAAAQQQQAABBBBAwLkAodG5Ga9AAAEEEEAAAQQQQAABBKwRIDRa09U0FAEEEEAAAQQQQAABBBBwLkBodG7GKxBAAAEEEEAAAQQQQAABawQIjdZ0NQ1FAAEEEEAAAQQQQAABBJwLEBqdm/EKBBBAAAEEEEAAAQQQQMAaAUKjNV1NQxFAAAEEEEAAAQQQQAAB5wKERudmvAIBBBBAAAEEEEAAAQQQsEaA0GhNV9NQBBBAAAEEEEAAAQQQQMC5AKHRuRmvQAABBBBAAAEEEEAAAQSsESA0WtPVNBQBBBBAAAEEEEAAAQQQcC5AaHRuxisQQCAFCLw1dJo8cF9eadO09k235s/Dx2TH7r1SpWJJyZE9q+zes18Gj5snYwYESS7/Ozwed9LslfL3idPSp2vzm35ffWHc907UwRL54m9/2CeHjhyX56pXTOSReDkCCCCAAAIIJEcBQmNy7BXOCQEEklzghVf7SPEiBRIV3j5av016DJgkCyf3kWKF88sXX/8gr3UfLmvnD5N778rlsQ3BQ6bKH4f+ljnjgn1uY7OgQZLv3jzyTs/W7tfEfW+fD5YEO/YdPlM+WLVJftw0MwmOziERQAABBBBA4FYLEBpvdQ/w/gggcEsE/o3QGBkZJRcvhUmWLBklTerUSRYaX+4w0ITGgb3auK3ivvctQbz+ppcuh0tkVJRkz5r5Vp4G740AAggggAACSSRAaEwiWA6LAALJW0BD4125c0re3DllzcavJCw8Ul6s+7R0avOCpE2TWk6fPS9BwWPkjcBGUqrYQ6YxUdHR0qLTEGndtJY8XbGUfP/TbzJ0/HwJ7dfeTEf1NNK4bvMOGT9jmfzy2yEpmO9uCY+INPv6OtL43pwPZfTUJZIpYwYpXPA+cx492jWWVKlSxXrvhSs2yNYde6R8maIyb+k6+evYKalWqbS8GfSSzF26Tlas2WKCXdP6z8hLz/9HMmZIZ44VHX1F5iz9VJas+kz2/3FEChW4VwJfqSs1qpT1uQN1lHHrNz/KyL7tzWtC3p0u/jmyyZUrV2TVuq2SNk0aaVKvmjStX03SpUvr83FXfvKFzP7gEzMym/OOrFLm0ULS5bWGxs+X89ZzmjJ3lXz/8wHJ5Z9dKpR5RDq0qm+mEns7ts8nyI4IIIAAAghYIkBotKSjaSYCCMQW0ND4074/pMJjj8iTZYuLhjtdm9f19UbSukkt+fv4aanasItMGNxFKlco4Q6NJaq1ln7dWsoLAZVvCIlxQ+Pm7bslsOdIM0rY7IXqoqODMxetkbvz3OlzaNTgEzx0quTKeYfUq/mkOY/K5UvIgYNHY02FHTl5kUybv9pMi9Vzi4iIlAmzVpj9Nazqa0+fuSDTF6yW0QOC5JlKZczP9HXzl2+QJvWqyqNFC5oA/fGG7TJvQoiUKFrQp8tmzLQlsnzNFtnwQajZ32WrYbt65cfk4JFjMm/Zepk09A2pVK64T8fUdrfpNkwa1Xna9M+Rv0/I/OXrzWirHjeh8/5s6y5p92aoCcGN61aV8xcvy6xFa2TcoM5y6VKY12P7dILshAACCCCAgEUChEaLOpumIoDAPwIabLQQzvC327r/UaeBHj95xqxJ/DdC44uv95Mz5y7Ix3PfFT+/VOZ9bmZNo6fpqXEDqoaoZR9vlk8XjpAM6a+NIgb2HCFHjp6UJVP7S9q0acy/6TkVLfyAWct58vQ5eap+R3dQ1p/raGqFgPbSoPZT0qtDU58uGU+hUcOrjsDqiKhudZr3lnKli0hwp2Y+HVPD7YhJi2Tj4lGS+85rRYV0dFFHL89duJTgeev76aiu9qVru3Q5TK5eFVm4ckO8x3Y5+XSS7IQAAggggIAlAoRGSzqaZiKAQGwBT2saXaN1u9ZPk5OnziVqpFGnveqopI4wxgxfSRka1276OlZI0gqx+347ZAr1uLag4NFmmqqO+n2za6807zTYjE5mzZLJvY+OwGpF2PGDOvt02XgKjXGLDLXtdW0UcuKQLj4dc+/+g/J86xAzLVenypZ85EGpVa2c+f+EzlunyZau/qo0b1hDerRvcsP7eTu2TyfHTggggAACCFgmQGi0rMNpLgIIXBPwNTSOG9TJrF/UTUfhfJ2eqmvwytYMNGvwYj7W4/8ZGvsMnyE/7/szVmjsGDLGTF3V0Lh5+/dmNLJ3x5fl/ntyx7o07sieVYo/nN+ny8WX0KhhNSr6is+hUd/4wJ9/mamzO7//xUwl1sC4cuZA+fX3I17PO/99eaVc7bZm/WLbV+p6bEN8x74rj79PbWYnBBBAAAEEbBIgNNrU27QVAQTcAp5CY/1Wb5kpkCtnDZILFy+b4KGPuahfs5J5na5JLPmfNj6vadTQWL50ERk7sJP7fXsPnmKesehrIRx9oT7GI0vmTDKybzv3cTxNT4070phQaNTzqPlSDzNVVdcOxtyuXr3qnlqa0GWTFKFR+yF1aj/3W2shIe0fHbWtXKFkguddqV6QWTsac5RVD3blylXRtsV3bB0ZZkMAAQQQQACB2AKERq4IBBCwUkBDo65f0xCi1VK1kItWGXUVuVEULcRy5uwFCe70spw6fV6mzv9Idu/Z73NoHDRmjjlmq8a15Knyj5rCOVrNUwu5OAmNMxZ8bIra6NTOdGnTSN7c/rLvwKEbCuE4DY3aRh15XL95p2mTVifVdY6fb9slfn5+0vnVF3y6NpIiNIa+94FcDguXgGcqyJ05s8vn23fLgNDZZsqsTp1N6Ly1KJBON24YUEUaBFSW8PAIUwinzUsBsmHLTq/H9qnR7IQAAggggIBFAoRGizqbpiKAwD8CWhBGK3KeOnPe/Y86jbRj6wbuUahtO/aIBj99FIVuGv60QEv/7q1MoRhXhc9PFgyXe/LeecP/a+AMemuMmV6pW5GH8klqPz8TVp2ExsNHT0jI0Gmy/dufzHGmDu9u/quh1vXeGrK08mnMwi99h8800zpjjrZ1fnucKRDjWlt49vxFGTVlsSxaudHtoFNrdcpqzarlfLpkxk5faorwuKqnxiy24zqAhjwdPfR1neTq9dtl8Ng57v7RCrDPVa8or74UYA6Z0HlHRkXL5NkrZeLsaxVkdStWOL8pzvPdj/u9HtunRrMTAggggAACFgkQGi3qbJqKAAI3Cly8FCZHj58yz2zUNXOeNp3GmSdXDknv4BmDMY+jlVi1iqirCujN9oM+O1JHALNnzXyzh4j3dbpe8/iJM5IhQzrzHMPksOk0Ug31Gjbjs0vovPW1x06clsyZM0q2GMV+fDl2cjDgHBBAAAEEEEgOAoTG5NALnAMCCFgnoNNAn23aI8F2f7V6os9rCxM8mMMdmrQbIL8eOOz1VdNH9hCtlOrrtunL76T7gEled3+ibDEZ1b+Dr4dkPwQQQAABBBBIYgFCYxIDc3gEEEAgPoHLYREJ4mTMcO2Zi7diCwuPMM819Lbp6KvrGZS+nKOO/EVERnndVY93s6O6vpwD+yCAAAIIIICAMwFCozMv9kYAAQQQQAABBBBAAAEErBIgNFrV3TQWAQQQQAABBBBAAAEEEHAmQGh05sXeCCCAAAIIIIAAAggggIBVAoRGq7qbxiKAAAIIIIAAAggggAACzgQIjc682BsBBBBAAAEEEEAAAQQQsEqA0GhVd9NYBBBAAAEEEEAAAQQQQMCZAKHRmRd7I4AAAggggAACCCCAAAJWCRAarepuGosAAggggAACCCCAAAIIOBMgNDrzYm8EEEAAAQQQQAABBBBAwCoBQqNV3U1jEUAAAQQQQAABBBBAAAFnAoRGZ17sjQACCCCAAAIIIIAAAghYJUBotKq7aSwCCCCAAAIIIIAAAggg4EyA0OjMi70RQAABBBBAAAEEEEAAAasECI1WdTeNRQABBBBAAAEEEEAAAQScCRAanXmxNwIIIIAAAggggAACCCBglQCh0aruprEIIIAAAggggAACCCCAgDMBQqMzL/ZGAAEEEEAAAQQQQAABBKwSIDRa1d00FgEEEEAAAQQQQAABBBBwJkBodObF3ggggAACCCCAAAIIIICAVQKERqu6m8YigAACCCCAAAIIIIAAAs4ECI3OvNgbAQQQQAABBBBAAAEEELBKgNBoVXfTWAQQQAABBBBAAAEEEEDAmQCh0ZkXeyOAAAIIIIAAAggggAACVgkQGq3qbhqLAAIIIIAAAggggAACCDgTIDQ682JvBBBAAAEEEEAAAQQQQMAqAUKjVd1NYxFAAAEEEEAAAQQQQAABZwKERmde7I0AAggggAACCCCAAAIIWCVAaLSqu2ksAggggAACCCCAAAIIIOBMgNDozIu9EUAAAQQQQAABBBBAAAGrBAiNVnU3jUUAAQQQQAABBBBAAAEEnAkQGp15sTcCCCCAAAIIIIAAAgggYJUAodGq7qaxCCCAAAIIIIAAAggggIAzAUKjMy/2RgABBBBAAAEEEEAAAQSsEiA0WtXdNBYBBBBAAAEEEEAAAQQQcCZAaHTmxd4IIIAAAggggAACCCCAgFUChEarupvGIoAAAggggAACCCCAAALOBAiNzrzYGwEEEEAAAQQQQAABBBCwSuC/4Kq243vqCyoAAAAASUVORK5CYII=", + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hovertemplate": "%{text}Trial", + "marker": { + "color": [], + "colorbar": { + "title": { + "text": "Trial" + } + }, + "colorscale": [ + [ + 0, + "rgb(247,251,255)" + ], + [ + 0.125, + "rgb(222,235,247)" + ], + [ + 0.25, + "rgb(198,219,239)" + ], + [ + 0.375, + "rgb(158,202,225)" + ], + [ + 0.5, + "rgb(107,174,214)" + ], + [ + 0.625, + "rgb(66,146,198)" + ], + [ + 0.75, + "rgb(33,113,181)" + ], + [ + 0.875, + "rgb(8,81,156)" + ], + [ + 1, + "rgb(8,48,107)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [], + "type": "scatter", + "x": [], + "y": [] + }, + { + "hovertemplate": "%{text}Best Trial", + "marker": { + "color": [ + 0, + 1, + 2, + 3, + 4 + ], + "colorbar": { + "title": { + "text": "Best Trial" + }, + "x": 1.1, + "xpad": 40, + "y": 0.5 + }, + "colorscale": [ + [ + 0, + "rgb(255,245,240)" + ], + [ + 0.125, + "rgb(254,224,210)" + ], + [ + 0.25, + "rgb(252,187,161)" + ], + [ + 0.375, + "rgb(252,146,114)" + ], + [ + 0.5, + "rgb(251,106,74)" + ], + [ + 0.625, + "rgb(239,59,44)" + ], + [ + 0.75, + "rgb(203,24,29)" + ], + [ + 0.875, + "rgb(165,15,21)" + ], + [ + 1, + "rgb(103,0,13)" + ] + ], + "line": { + "color": "Grey", + "width": 0.5 + } + }, + "mode": "markers", + "showlegend": false, + "text": [ + "{
\"number\": 0,
\"values\": [
157.0238,
0.0412,
0.9903
],
\"params\": {
\"intermediate_graph_degree\": 76,
\"itopk_size\": 124
}
}", + "{
\"number\": 1,
\"values\": [
155.633,
0.0364,
0.9884
],
\"params\": {
\"intermediate_graph_degree\": 72,
\"itopk_size\": 106
}
}", + "{
\"number\": 2,
\"values\": [
162.741,
0.0231,
0.9801
],
\"params\": {
\"intermediate_graph_degree\": 90,
\"itopk_size\": 66
}
}", + "{
\"number\": 3,
\"values\": [
169.5533,
0.0396,
0.9915
],
\"params\": {
\"intermediate_graph_degree\": 110,
\"itopk_size\": 114
}
}", + "{
\"number\": 4,
\"values\": [
158.4761,
0.0414,
0.9905
],
\"params\": {
\"intermediate_graph_degree\": 80,
\"itopk_size\": 126
}
}" + ], + "type": "scatter", + "x": [ + 0.0412, + 0.0364, + 0.0231, + 0.0396, + 0.0414 + ], + "y": [ + 0.9903, + 0.9884, + 0.9801, + 0.9915, + 0.9905 + ] + } + ], + "layout": { + "autosize": true, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Pareto-front Plot" + }, + "xaxis": { + "autorange": true, + "range": [ + 0.02201259393264681, + 0.042487406067353184 + ], + "title": { + "text": "latency_in_ms" + }, + "type": "linear" + }, + "yaxis": { + "autorange": true, + "range": [ + 0.9791592233009708, + 0.9924407766990292 + ], + "title": { + "text": "recall" + }, + "type": "linear" + } + } + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA40AAAFoCAYAAADzQh4hAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQmcTeX/xz/XMGbMjH0nSwopiVIoEZVIxC+UrT1SFBFRIVGyhUhRiZEskaVEkVKWFFmSlKSsY2cYY4z5/59n3GtmzIzvmXPPY+49n/N69ZrunO/3POd5fw/mPc9yPElJSUngQQIkQAIkQAIkQAIkQAIkQAIkQALpEPBQGvlckAAJkAAJkAAJkAAJkAAJkAAJZESA0shngwRIgARIgARIgARIgARIgARIIEMClEY+HCRAAiRAAiRAAiRAAiRAAiRAApRGPgMkQAIkQAIkQAIkQAIkQAIkQALWCXCk0TozZpAACZAACZAACZAACZAACZCAawhQGl1TanaUBEiABEiABEiABEiABEiABKwToDRaZ8YMEiABEiABEiABEiABEiABEnANAUqja0rNjpIACZAACZAACZAACZAACZCAdQKURuvMmEECJEACJEACJEACJEACJEACriFAaXRNqdlREiABEiABEiABEiABEiABErBOgNJonRkzSIAESIAESIAESIAESIAESMA1BCiNrik1O0oCJEACJEACJEACJEACJEAC1glQGq0zYwYJkAAJkAAJkAAJkAAJkAAJuIYApdE1pWZHSYAESIAESIAESIAESIAESMA6AUqjdWbMIAESIAESIAESIAESIAESIAHXEKA0uqbU7CgJkAAJkAAJkAAJkAAJkAAJWCdAabTOjBkkQAIkQAIkQAIkQAIkQAIk4BoClEbXlJodJQESIAESIAESIAESIAESIAHrBCiN1pkxgwRIgARIgARIgARIgARIgARcQ4DS6JpSs6MkQAIkQAIkQAIkQAIkQAIkYJ0ApdE6M2aQAAmQAAmQAAmQAAmQAAmQgGsIUBpdU2p2lARIgARIgARIgARIgARIgASsE6A0WmfGDBIgARIgARIgARIgARIgARJwDQFKo2tKzY6SAAmQAAmQAAmQAAmQAAmQgHUClEbrzJhBAiRAAiRAAiRAAiRAAiRAAq4hQGl0TanZURIgARIgARIgARIgARIgARKwToDSaJ0ZM0iABEiABEiABEiABEiABEjANQQoja4pNTtKAiRAAiRAAiRAAiRAAiRAAtYJUBqtM2MGCZAACZAACZAACZAACZAACbiGAKXRNaVm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mUpOOz1VfU/KL7MaiCEzkARIgARIgARIgARIgARIQBMIaGmU1lBNIf1vT4yWuJLFCmtJtHOo9zzGHDyCAvmiUKhAXj2tM+2hRvL2xhzSm+4oOUt5KKlR91OoQD69jtDkoe7r3937kTNnTihhVTvM2j2UUCtpjIwI10ycPqT8MquB0/fI65MACZAACZAACZAACZBAsBBwhTQGS7HYDxIgARIgARIgARIgARIgARIwTYDSaJo42yMBEiABEiABEiABEiABEiCBACJAaQygYvFWSYAESIAESIAESIAESIAESMA0AUqjaeJsjwRIgARIgARIgARIgARIgAQCiAClMYCKxVslARIgARIgARIgARIgARIgAdMEKI2mibM9EiABEiABEiABEiABEiABEgggApTGACoWb5UESIAESIAESIAESIAESIAETBOgNJomzvZIgARIgARIgARIgARIgARIIIAIUBoDqFi8VRIgARIgARIgARIgARIgARIwTYDSaJo42yMBEiABEiABEiABEiABEiCBACJAaQygYvFWSYAESIAESIAESIAESIAESMA0AUqjaeJsjwRIgARIgARIgARIgARIgAQCiAClMYCKxVslARIgARIgARIgARIgARIgAdMEKI2mibM9EiABEiABEiABEiABEiABEgggApTGACoWb5UESIAESIAESIAESIAESIAETBOgNJomzvZIgARIgARIgARIgARIgARIIIAIUBoDqFi8VRIgARIgARIgARIgARIgARIwTYDSaJo42yMBEiABEiABEiABEiABEiCBACJAaQygYvFWSYAESIAESIAESIAESIAESMA0AUqjaeJsjwRIgARIgARIgARIgARIgAQCiAClMYCKxVslARIgARIgARIgARIgARIgAdMEKI2mibM9EiABEiABEiABEiABEiABEgggApTGACoWb5UESIAESIAESIAESIAESIAETBOgNJomzvZIgARIgARIgARIgARIgARIIIAIUBoDqFi8VRIgARIgARIgARIgARIgARIwTYDSaJo42yMBEiABEiABEiABEiABEiCBACJAaQygYvFWSYAESIAESIAESIAESIAESMA0AUqjaeJsjwRIgARIgARIgARIgARIgAQCiAClMYCKxVslARIgARIgARIgARIgARIgAdMEKI2mibM9EiABEiABEiABEiABEiABEgggApTGACoWb5UESIAESIAESIAESIAESIAETBOgNJomzvZIgARIgARIgARIgARIgARIIIAIUBoDqFi8VRIgARIgARIgARIgARIgARIwTYDSaJo42yMBEiABEiABEiABEiABEiCBACJAaQygYvFWSYAESIAESIAESIAESIAESMA0AUqjaeJsjwRIgARIgARIgARIgARIgAQCiAClMYCKxVslARIgARIgARIgARIgARIgAdMEKI2mibM9EiABEiABEiABEiABEiABEgggApTGACoWb5UESIAESIAESIAESIAESIAETBOgNJomzvZIgARIgARIgARIgARIgARIIIAIUBoDqFi8VRIgARIgARIgARIgARIgARIwTYDSaJo42yMBEiABEiABEiABEiABEiCBACJAaQygYvFWSYAESIAESIAESIAESIAESMA0AUqjaeJsjwRIgARIgARIgARIgARIgAQCiAClMYCKxVslARIgARIgARIgARIgARIgAdMEKI2mibM9EiABEiABEiABEiABEiABEgggApTGACoWb5UESIAESIAESIAESIAESIAETBOgNJomzvZIgARIgARIgARIgARIgARIIIAIUBoDqFi8VRIgARIgARIgARIgARIgARIwTYDSaJP4nkNxNq/AdAmBYgXCcOBYPM6dS5KEM4YEMiVQMCoUp06fxemEcyRFArYJRIXnBDwenDiVYPtavAAJhIWGIE/uEBw+cYYwhARKFgoXRjKMBEggqwQojVkldz6P0mgToDCd0igExTARAUqjCBODhAQojUJQDBMRoDSKMKUKojRaZ8YMErBKgNJolViaeEqjTYDCdEqjEBTDRAQojSJMDBISoDQKQTFMRIDSKMJEabSOiRkkYIsApdEWPoDSaBOgMJ3SKATFMBEBSqMIE4OEBCiNQlAMExGgNIowURqtY2IGCdgiQGm0hY/SaBOfOJ3SKEbFQAEBSqMAEkPEBCiNYlQMFBCgNAogpQnh9FTrzJhBAlYJUBqtEksTz5FGmwCF6ZRGISiGiQhQGkWYGCQkQGkUgmKYiAClUYQpVRCl0TozZpCAVQKURqvEKI02iWUtndKYNW7MSp8ApZFPhj8JUBr9SZPXojRafwYojdaZMYMErBKgNFolRmm0SSxr6ZTGrHFjFqWRz4DzBCiNzjN2UwuURuvVpjRaZ8YMErBKgNJo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", + "text/html": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "visualization(cagra_study)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "conda_python3", + "language": "python", + "name": "conda_python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}