from core.explanations.analyzers.BaseExplanationAnalyzer import BaseExplanationAnalyzer
from core.explanations.utils import bitmask_to_list
from scipy.stats import spearmanr

import numpy as np


class IndividualExplanationAnalyzer(BaseExplanationAnalyzer):

    @staticmethod
    def calc_feature_importance_error(importance_pred, importance_test):
        """ Calculate the normalized mean absolute error. """
        error = 0

        for feature, importance in importance_pred.items():
            error += abs(importance - importance_test[feature])

        # Normalize the error
        error /= len(importance_pred)
        error /= np.mean(list(importance_test.values()))

        return error

    @staticmethod
    def calc_feature_ranking_correlation(ranking_pred, ranking_test):
        correlation, _ = spearmanr(ranking_pred, ranking_test)
        return correlation

    @staticmethod
    def calc_explanation_bounds(explanation, sample, epsilon):
        sample_size = len(sample.flatten())

        if isinstance(explanation, str):
            explanation = bitmask_to_list(explanation, sample_size)

        bounds = []

        for feature in range(sample_size):
            if feature in explanation:
                bounds.append((sample[feature], sample[feature]))
            else:
                lower_bound = max(0, sample[feature] - epsilon)
                upper_bound = min(1, sample[feature] + epsilon)
                bounds.append((lower_bound, upper_bound))

        return bounds
