Repository: activeloopai/Hub
File: deeplake/core/index_maintenance.py (Python)

Code before:
    Determine if the index should be regenerated or built incrementally.

    :param len_initial_data: int, length of the original data
    :param len_changed_data: int, length of the changed data
    :return: bool, True if the index should be regenerated, False otherwise
    """
    threshold = 0.7 * len_initial_data
    return len_changed_data < threshold


def index_operation_type_vectorstore(
    self, changed_data_len, index_regeneration, index_delete=False
):
    if not index_used(self.exec_option):
        return INDEX_OP_TYPE.NOOP

    if index_delete:
        return INDEX_OP_TYPE.REMOVE_INDEX

    if not index_exists(self.dataset):
        threshold = self.index_params.get("threshold", -1)
        below_threshold = threshold <= 0 or len(self.dataset) < threshold
        if not below_threshold:
            return INDEX_OP_TYPE.CREATE_INDEX
    else:
        if changed_data_len == 0:
            return INDEX_OP_TYPE.NOOP
        elif (
            not index_regeneration
            and check_index_params(self)
            and check_incr_threshold(len(self.dataset), changed_data_len)
        ):
            return INDEX_OP_TYPE.INCREMENTAL_INDEX
        else:
            return INDEX_OP_TYPE.REGENERATE_INDEX

    return INDEX_OP_TYPE.NOOP


def index_operation_type_dataset(
    self, num_rows, changed_data_len, index_regeneration, index_delete=False
):
    if not index_exists(self):
        if self.index_params is None:
            return INDEX_OP_TYPE.NOOP
        threshold = self.index_params.get("threshold", -1)
        below_threshold = threshold <= 0 or num_rows < threshold
        if not below_threshold:
            return INDEX_OP_TYPE.CREATE_INDEX

    if not check_vdb_indexes(self) or changed_data_len == 0:

Review comment (bug):
Which case does this correspond to? Was it previously erroring out? If yes can we add test for this edge case? I do get that it the case when there are no samples in the dataset, am I right @sounakr?

Code after:
def index_operation_type_dataset(self, num_rows, changed_data_len):
    if not index_exists(self):
        if self.index_params is None:
            return INDEX_OP_TYPE.NOOP
        threshold = self.index_params.get("threshold", -1)
        below_threshold = threshold <= 0 or num_rows < threshold
        if not below_threshold:
            return INDEX_OP_TYPE.CREATE_INDEX

    if not check_vdb_indexes(self) or changed_data_len == 0:
        return INDEX_OP_TYPE.NOOP

    return INDEX_OP_TYPE.INCREMENTAL_INDEX


def get_index_metric(metric):
    if metric not in METRIC_TO_INDEX_METRIC:
        raise ValueError(
            f"Invalid distance metric: {metric} for index. "
            f"Valid options are: {', '.join([e for e in list(METRIC_TO_INDEX_METRIC.keys())])}"
        )
    return METRIC_TO_INDEX_METRIC[metric]


def normalize_additional_params(params: dict) -> dict:
    mapping = {"efconstruction": "efConstruction", "m": "M"}

    allowed_keys = ["efConstruction", "m"]

    # New dictionary to store the result with desired key format
    result_dict = {}

    for key, value in params.items():
        normalized_key = key.lower()

        # Check if the normalized key is one of the allowed keys
        if normalized_key not in mapping:
            raise ValueError(
                f"Unexpected key: {key} in additional_params"
                f" {allowed_keys} should be used instead."
            )

        # Check if the value is an integer
        if not isinstance(value, int):
            raise ValueError(
                f"Expected value for key {key} to be an integer, but got {type(value).__name__}"
            )

        # Populate the result dictionary with the proper format for the keys
        result_dict[mapping[normalized_key]] = value