class IntersectionCosineRescalEvaluation(EvaluationAlgorithm):

    def __init__(self, args, output_folder, logger, ground_truth, start_time):
        self.init(args, output_folder, logger, ground_truth, start_time)
        self.report2 = EvaluationReport(logger, args.fbeta)
        self.report3 = EvaluationReport(logger, args.fbeta)

    def log1(self):
        self.logger.info('Intersection of predictions of cosine similarity and rescal algorithms: ')

    def log2(self):
        self.logger.info('For RESCAL prediction with threshold %f:' % float(self.args.intersection[1]))

    def log3(self):
        self.logger.info('For prediction of cosine similarity between needs with thresholds: %f:' %
                  float(self.args.intersection[2]))

    def evaluate_fold(self, test_tensor, test_needs, idx_test):
        inter_pred, cosine_pred, rescal_pred = self.predict_intersect_cosine_rescal(
            test_tensor, test_needs, idx_test, int(self.args.intersection[0]),
            float(self.args.intersection[1]), float(self.args.intersection[2]),
            bool(self.args.intersection[3]))
        self.log1()
        self.report.add_evaluation_data(self.ground_truth.getArrayFromSliceMatrix(
            SparseTensor.CONNECTION_SLICE, idx_test), inter_pred)
        self.log2()
        self.report2.add_evaluation_data(self.ground_truth.getArrayFromSliceMatrix(
            SparseTensor.CONNECTION_SLICE,idx_test), rescal_pred)
        self.log3()
        self.report3.add_evaluation_data(self.ground_truth.getArrayFromSliceMatrix(
            SparseTensor.CONNECTION_SLICE,idx_test), cosine_pred)

    def finish_evaluation(self):
        self.log1()
        self.report.summary()
        self.log2()
        self.report2.summary()
        self.log3()
        self.report3.summary()

    # predict connections by intersection of RESCAL and cosine results
    def predict_intersect_cosine_rescal(self, input_tensor, test_needs, idx_test, rank,
                                        rescal_threshold, cosine_threshold, useNeedTypeSlice):

        wants = input_tensor.getWantIndices()
        offers = input_tensor.getOfferIndices()

        # execute the cosine algorithm
        binary_pred_cosine = cosinus_link_prediciton(input_tensor, test_needs, cosine_threshold, 0.0, False)

        # execute the rescal algorithm
        A,R = execute_rescal(input_tensor, rank)
        P_bin = predict_rescal_connections_by_threshold(A, R, rescal_threshold, offers, wants, test_needs)

        # return the intersection of the prediction of both algorithms
        binary_pred_cosine = matrix_to_array(binary_pred_cosine, idx_test)
        binary_pred_rescal = matrix_to_array(P_bin, idx_test)
        binary_pred = [min(binary_pred_cosine[i], binary_pred_rescal[i]) for i in range(len(binary_pred_cosine))]
        return binary_pred, binary_pred_cosine, binary_pred_rescal
class CombineCosineRescalEvaluation(EvaluationAlgorithm):

    def __init__(self, args, output_folder, logger, ground_truth, start_time):
        self.init(args, output_folder, logger, ground_truth, start_time)
        self.report2 = EvaluationReport(logger, args.fbeta)

    def log1(self):
        self.logger.info('First step for prediction of cosine similarity with threshold: %f:' %
                         float(self.args.cosine_rescal[2]))

    def log2(self):
        self.logger.info('And second step for combined RESCAL prediction with parameters: %d, %f:'
                         % (int(self.args.cosine_rescal[0]), float(self.args.cosine_rescal[1])))

    def evaluate_fold(self, test_tensor, test_needs, idx_test):
        cosine_pred, rescal_pred = self.predict_combine_cosine_rescal(
            test_tensor, test_needs, idx_test, int(self.args.cosine_rescal[0]),
            float(self.args.cosine_rescal[1]), float(self.args.cosine_rescal[2]),
            bool(self.args.cosine_rescal[3]))
        self.log1()
        self.report.add_evaluation_data(self.ground_truth.getArrayFromSliceMatrix(
                SparseTensor.CONNECTION_SLICE, idx_test), cosine_pred)
        self.log2()
        self.report2.add_evaluation_data(self.ground_truth.getArrayFromSliceMatrix(
            SparseTensor.CONNECTION_SLICE,idx_test), rescal_pred)

    def finish_evaluation(self):
        self.log1()
        self.report.summary()
        self.log2()
        self.report2.summary()

    # predict connections by combining the execution of algorithms
    def predict_combine_cosine_rescal(self, input_tensor, test_needs, idx_test, rank,
                                      rescal_threshold, cosine_threshold, useNeedTypeSlice):

        wants = input_tensor.getWantIndices()
        offers = input_tensor.getOfferIndices()

        # execute the cosine algorithm first
        binary_pred_cosine = cosinus_link_prediciton(input_tensor, test_needs, cosine_threshold, 0.0, False)

        # use the connection prediction of the cosine algorithm as input for rescal
        temp_tensor = input_tensor.copy()
        temp_tensor.addSliceMatrix(binary_pred_cosine, SparseTensor.CONNECTION_SLICE)
        A,R = execute_rescal(temp_tensor, rank)
        P_bin = predict_rescal_connections_by_threshold(A, R, rescal_threshold, offers, wants, test_needs)

        # return both predictions the earlier cosine and the combined rescal
        binary_pred_cosine = binary_pred_cosine[idx_test]
        binary_pred_rescal = matrix_to_array(P_bin, idx_test)
        return binary_pred_cosine, binary_pred_rescal