# Path: hub_toolbox/utils.py
# class SynchronizedCounter(object):
#     """ A multiprocessing-safe counter for progress information. """
#     def __init__(self, init:int=-1):
#         self.val = Value('i', init)
# 
#     def increment_and_get_value(self, n=1) -> int:
#         """ Obtain a lock before incrementing, since += isn't atomic. """
#         with self.val.get_lock():
#             self.val.value += n
#             return self.val.value
# 
#     @property
#     def value(self) -> int:
#         return self.val.value
# 
# Path: hub_toolbox/htlogging.py
# class ConsoleLogging(Logging):
#     """Convenience functions for time-stamped logging to the console"""
# 
#     def message(self, *objs, flush=True):
#         """Log normal program function"""
#         print(self._current_time, 'INFO:', *objs)
#         if flush:
#             sys.stdout.flush()
# 
#     def warning(self, *objs, flush=True):
#         """Log warning (program can still continue)"""
#         print(self._current_time, 'WARNING:', *objs, file=sys.stderr)
#         if flush:
#             sys.stderr.flush()
# 
#     def error(self, *objs, flush=True):
#         """Log error (program fails)"""
#         print(self._current_time, 'ERROR:', *objs, file=sys.stderr)
#         if flush:
#             sys.stderr.flush()


import ctypes
import os
import warnings
import numpy as np
import pandas as pd
    import nmslib
    import falconn
from functools import partial
from multiprocessing import cpu_count, RawArray, Pool
from scipy import sparse
from scipy.sparse.base import issparse
from scipy.stats import norm
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.model_selection import StratifiedShuffleSplit, ShuffleSplit
from sklearn.metrics import euclidean_distances
from sklearn.metrics.pairwise import cosine_distances
from sklearn.neighbors.classification import KNeighborsClassifier
from sklearn.utils import check_random_state, check_array
from sklearn.utils.extmath import row_norms, stable_cumsum
from sklearn.utils.validation import check_is_fitted
from hub_toolbox.utils import SynchronizedCounter
from hub_toolbox.htlogging import ConsoleLogging
            num_probes = self.kwargs['falconn__num_probes']
        except KeyError:
            num_probes = 50
        self.num_probes_ = num_probes
        # Set up the LSH index
        lsh_cp = falconn.get_default_parameters(*X.shape, distance=distance)
        lsh_index = falconn.LSHIndex(lsh_cp)
        lsh_index.setup(X)
        # Constructing a query object
        query = lsh_index.construct_query_object()
        query.set_num_probes(num_probes)
        if self.n_jobs == 1:
            ind = np.empty((n_train, k), dtype=np.int32)
            D_train = np.empty_like(ind, dtype=X.dtype)
            for i, x in enumerate(X):
                if self.verbose > 2 or self.verbose > 1 and (i % 1000 == 0 or i == n_train-1):
                    log.message(f"LSH-Filtering: {i+1}/{n_train}", flush=True)
                # LSH will find object itself as 1-NN
                knn = np.array(query.find_k_nearest_neighbors(x, k=k+1))[1:]
                ind[i, :knn.size] = knn
                if self.metric == 'sqeuclidean':
                    D_train[i, :knn.size] = euclidean_distances(
                        x.reshape(1, -1), X[knn], squared=True)
                elif self.metric == 'cosine':
                    D_train[i, :knn.size] = cosine_distances(
                        x.reshape(1, -1), X[knn])
                if knn.size < k:
                    ind[i, knn.size:] = knn[-1]
                    D_train[i, knn.size:] = D_train[i].max()
        else:

# Path: hub_toolbox/utils.py
# class SynchronizedCounter(object):
#     """ A multiprocessing-safe counter for progress information. """
#     def __init__(self, init:int=-1):
#         self.val = Value('i', init)
# 
#     def increment_and_get_value(self, n=1) -> int:
#         """ Obtain a lock before incrementing, since += isn't atomic. """
#         with self.val.get_lock():
#             self.val.value += n
#             return self.val.value
# 
#     @property
#     def value(self) -> int:
#         return self.val.value
# 
# Path: hub_toolbox/htlogging.py
# class ConsoleLogging(Logging):
#     """Convenience functions for time-stamped logging to the console"""
# 
#     def message(self, *objs, flush=True):
#         """Log normal program function"""
#         print(self._current_time, 'INFO:', *objs)
#         if flush:
#             sys.stdout.flush()
# 
#     def warning(self, *objs, flush=True):
#         """Log warning (program can still continue)"""
#         print(self._current_time, 'WARNING:', *objs, file=sys.stderr)
#         if flush:
#             sys.stderr.flush()
# 
#     def error(self, *objs, flush=True):
#         """Log error (program fails)"""
#         print(self._current_time, 'ERROR:', *objs, file=sys.stderr)
#         if flush:
#             sys.stderr.flush()


# Path: hub_toolbox/approximate.py
import ctypes
import os
import warnings
import numpy as np
import pandas as pd
    import nmslib
    import falconn
from functools import partial
from multiprocessing import cpu_count, RawArray, Pool
from scipy import sparse
from scipy.sparse.base import issparse
from scipy.stats import norm
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.model_selection import StratifiedShuffleSplit, ShuffleSplit
from sklearn.metrics import euclidean_distances
from sklearn.metrics.pairwise import cosine_distances
from sklearn.neighbors.classification import KNeighborsClassifier
from sklearn.utils import check_random_state, check_array
from sklearn.utils.extmath import row_norms, stable_cumsum
from sklearn.utils.validation import check_is_fitted
from hub_toolbox.utils import SynchronizedCounter
from hub_toolbox.htlogging import ConsoleLogging

            num_probes = self.kwargs['falconn__num_probes']
        except KeyError:
            num_probes = 50
        self.num_probes_ = num_probes
        # Set up the LSH index
        lsh_cp = falconn.get_default_parameters(*X.shape, distance=distance)
        lsh_index = falconn.LSHIndex(lsh_cp)
        lsh_index.setup(X)
        # Constructing a query object
        query = lsh_index.construct_query_object()
        query.set_num_probes(num_probes)
        if self.n_jobs == 1:
            ind = np.empty((n_train, k), dtype=np.int32)
            D_train = np.empty_like(ind, dtype=X.dtype)
            for i, x in enumerate(X):
                if self.verbose > 2 or self.verbose > 1 and (i % 1000 == 0 or i == n_train-1):
                    log.message(f"LSH-Filtering: {i+1}/{n_train}", flush=True)
                # LSH will find object itself as 1-NN
                knn = np.array(query.find_k_nearest_neighbors(x, k=k+1))[1:]
                ind[i, :knn.size] = knn
                if self.metric == 'sqeuclidean':
                    D_train[i, :knn.size] = euclidean_distances(
                        x.reshape(1, -1), X[knn], squared=True)
                elif self.metric == 'cosine':
                    D_train[i, :knn.size] = cosine_distances(
                        x.reshape(1, -1), X[knn])
                if knn.size < k:
                    ind[i, knn.size:] = knn[-1]
                    D_train[i, knn.size:] = D_train[i].max()
        else:

            counter = SynchronizedCounter()