# Path: hub_toolbox/io.py
# def load_dexter():
# def check_is_nD_array(arr:np.ndarray, n:int, arr_type=''):
# def check_distance_matrix_shape(D:np.ndarray):
# def check_distance_matrix_shape_fits_vectors(D:np.ndarray, vectors:np.ndarray):
# def check_distance_matrix_shape_fits_labels(D:np.ndarray, classes:np.ndarray):
# def check_vector_matrix_shape_fits_labels(X:np.ndarray, classes:np.ndarray):
# def check_sample_shape_fits(D:np.ndarray, idx:np.ndarray):
# def check_valid_metric_parameter(metric:str):
# def matrix_split(rows, cols, elem_size=8, nr_matrices=4): # pragma: no cover
# def random_sparse_matrix(size, density=0.05):
# def save_csr_matrix(file, matrix):
# def load_csr_matrix(file):
#     def __init__(self, unit='kB'):
#     def _factor(self):
#     def total(self):
#     def used(self):
#     def used_real(self):
#     def shared(self):
#     def buffers(self):
#     def cached(self):
#     def user_free(self):
#     def swap(self):
#     def swap_free(self):
#     def swap_used(self):
#     D = cosine_distance(vectors)
#     S = sparse.rand(size, size, density, 'csr')
# class FreeMemLinux(object): # pragma: no cover
# 
# 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 multiprocessing as mp
import numpy as np
from functools import partial
from scipy.sparse.base import issparse
from sklearn.preprocessing.label import LabelEncoder
from hub_toolbox import io
from hub_toolbox.htlogging import ConsoleLogging
    sample_idx : ...
        TODO add description

    filter_self : bool, optional, default: True
        Remove self similarities from sparse ``D``.
        This assumes that the highest similarity per row is the self
        similarity.
        
        NOTE: Quadratic dense matrices are always filtered for self
        distances/similarities, even if `filter_self` is set t0 `False`.
        
    Returns
    -------
    acc : ndarray (shape=(n_k x 1), dtype=float)
        Classification accuracy (`n_k`... number of items in parameter `k`)

        HINT: Refering to the above example... 
        ... ``acc[0]`` gives the accuracy of the ``k=1`` experiment.
    corr : ndarray (shape=(n_k x n), dtype=int)
        Raw vectors of correctly classified items

        HINT: ... ``corr[1, :]`` gives these items for the ``k=5`` experiment.
    cmat : ndarray (shape=(n_k x n_t x n_t), dtype=int) 
        Confusion matrix (``n_t`` number of unique items in parameter target)

        HINT: ... ``cmat[2, :, :]`` gives the confusion matrix of
        the ``k=20`` experiment.
    """

    # Check input sanity

# Path: hub_toolbox/io.py
# def load_dexter():
# def check_is_nD_array(arr:np.ndarray, n:int, arr_type=''):
# def check_distance_matrix_shape(D:np.ndarray):
# def check_distance_matrix_shape_fits_vectors(D:np.ndarray, vectors:np.ndarray):
# def check_distance_matrix_shape_fits_labels(D:np.ndarray, classes:np.ndarray):
# def check_vector_matrix_shape_fits_labels(X:np.ndarray, classes:np.ndarray):
# def check_sample_shape_fits(D:np.ndarray, idx:np.ndarray):
# def check_valid_metric_parameter(metric:str):
# def matrix_split(rows, cols, elem_size=8, nr_matrices=4): # pragma: no cover
# def random_sparse_matrix(size, density=0.05):
# def save_csr_matrix(file, matrix):
# def load_csr_matrix(file):
#     def __init__(self, unit='kB'):
#     def _factor(self):
#     def total(self):
#     def used(self):
#     def used_real(self):
#     def shared(self):
#     def buffers(self):
#     def cached(self):
#     def user_free(self):
#     def swap(self):
#     def swap_free(self):
#     def swap_used(self):
#     D = cosine_distance(vectors)
#     S = sparse.rand(size, size, density, 'csr')
# class FreeMemLinux(object): # pragma: no cover
# 
# 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/knn_classification.py
import ctypes
import multiprocessing as mp
import numpy as np
from functools import partial
from scipy.sparse.base import issparse
from sklearn.preprocessing.label import LabelEncoder
from hub_toolbox import io
from hub_toolbox.htlogging import ConsoleLogging

    sample_idx : ...
        TODO add description

    filter_self : bool, optional, default: True
        Remove self similarities from sparse ``D``.
        This assumes that the highest similarity per row is the self
        similarity.
        
        NOTE: Quadratic dense matrices are always filtered for self
        distances/similarities, even if `filter_self` is set t0 `False`.
        
    Returns
    -------
    acc : ndarray (shape=(n_k x 1), dtype=float)
        Classification accuracy (`n_k`... number of items in parameter `k`)

        HINT: Refering to the above example... 
        ... ``acc[0]`` gives the accuracy of the ``k=1`` experiment.
    corr : ndarray (shape=(n_k x n), dtype=int)
        Raw vectors of correctly classified items

        HINT: ... ``corr[1, :]`` gives these items for the ``k=5`` experiment.
    cmat : ndarray (shape=(n_k x n_t x n_t), dtype=int) 
        Confusion matrix (``n_t`` number of unique items in parameter target)

        HINT: ... ``cmat[2, :, :]`` gives the confusion matrix of
        the ``k=20`` experiment.
    """

    # Check input sanity

    log = ConsoleLogging()