def create_difference_matrix_difference(
        dm_original: pd.DataFrame,
        dm_reduced: pd.DataFrame,
        removed_nodes: [int],
        save_info: sl.MemoryAccess,
        save: bool = True,
        check_for_existing: bool = True,
        reduce_o_dm: bool = True) -> pd.DataFrame:

    if check_for_existing and save_info.has_diff_matrix(removed_nodes):
        diff, _ = save_info.load_diff_matrix(removed_nodes)
        return diff

    # reduce original dem to match red dm
    if reduce_o_dm:
        dm_o = reduce_dm(dm_original=dm_original, rem_node=removed_nodes[-1])
    else:
        dm_o = dm_original
    # assert (removed_nodes[-1] not in list(dm_o.index))
    utils.assure_same_labels(
        [dm_o, dm_reduced], f"compute difference matrix: differing Indices! "
        f"For removed nodes {removed_nodes}\n Save_info: {save_info}")
    diff = dm_o - dm_reduced

    if save:
        save_info.save_diff_matrix(removed_nodes,
                                   diff,
                                   diff_type=save_info.get_diff_type())
    return diff
def compute_diff_matrix_helper(o_dm_list: List[pd.DataFrame],
                               r_dm_list: List[pd.DataFrame],
                               removed_nodes: List[int],
                               save_info: sl.MemoryAccess,
                               save: bool = True,
                               check_for_existing: bool = True):
    # check for existing
    if check_for_existing and save_info.has_diff_matrix(
            removed_nodes=removed_nodes):
        return save_info.load_diff_matrix(removed_nodes)

    min_diff_size = np.inf
    min_diff: pd.DataFrame
    min_r_dm: pd.DataFrame
    min_r_dm_index: int
    r_dm_list = list(
        r_dm_list
    )  # must be called multiple times hence a generator can not be used
    for o_dm in o_dm_list:
        o_dm_reduced = cf.reduce_dm(dm_original=o_dm,
                                    rem_node=removed_nodes[-1])
        for index, r_dm in enumerate(r_dm_list):

            diff = cf.create_difference_matrix_difference(
                dm_original=o_dm_reduced,
                dm_reduced=r_dm,
                removed_nodes=removed_nodes,
                save_info=save_info,
                save=False,
                check_for_existing=False,
                reduce_o_dm=False)
            diff_size = compute_diff_size(diff)
            if diff_size < min_diff_size:
                min_diff = diff
                min_diff_size = diff_size
                min_r_dm = r_dm
                min_r_dm_index = index

    if save:
        save_info.save_diff_matrix(removed_nodes=removed_nodes,
                                   diff=min_diff,
                                   diff_type=save_info.diff_type,
                                   r_dm_index=min_r_dm_index)
    return min_diff, min_r_dm
def create_difference_matrix_ratio(
        dm_original: pd.DataFrame,
        dm_reduced: pd.DataFrame,
        removed_nodes: [int],
        save_info: sl.MemoryAccess,
        save: bool = True,
        check_for_existing: bool = True) -> pd.DataFrame:

    if not save_info.is_diff_type(dt.DiffType.RATIO):
        raise ValueError(
            f"MemoryAccess object does not specify a difference type. To run this function"
            f"the diff type must be diff type '{dt.DiffType.DIFFERENCE}'")

    if check_for_existing and save_info.has_diff_matrix(removed_nodes):
        print("difference matrix for removed nodes {} and\
         num iterations {} and type {} already exists!".format(
            removed_nodes, save_info.num_iterations, dt.DiffType.RATIO))
        return save_info.load_diff_matrix(removed_nodes)

    # reduce original dem to match red dm
    dm_o = reduce_dm(dm_original=dm_original, rem_node=list(dm_reduced.index))
    assert (removed_nodes[-1] not in list(dm_o.index))

    # utils.assure_same_labels([dm_o, dm_reduced],
    #                         f"Checking of original distance matrix (removed nodes {removed_nodes[:-1]}) \
    #                                  and reduced distance matrix
    #                                  (removed nodes {removed_nodes}) have the same labels \
    #                                  after removing the last label from the ordginal distance matrix")

    ratio = dm_o / dm_reduced
    if save:
        save_info.save_diff_matrix(removed_nodes,
                                   ratio,
                                   diff_type=dt.DiffType.RATIO)

    return ratio