#!/usr/bin/env python2
# -*- coding: utf-8 -*-
"""
Created on Wed May  3 12:12:53 2017

@author: daniele
"""

import numpy as np


def minmaxlog(value):
    """
    Rounds the value as max(min(value,1−10^{-15},10^{-15})), wrapped by the
    natural logarithm. This is useful for calculating the cross-entropy on
    (regulated) probabilites.
    """
    return np.log(max(min(value, 1-10**(-15)), 10**(-15)))


def repeat_array(array_to_repeat, num_repeats):
    """
    Helper function to oversample_array. Concatenates array_to_repeat to
    itself, num_repeats times.
    """
    return np.concatenate(tuple([array_to_repeat
                                 for kk in range(num_repeats)]))


def agnosticize(probs, times):
    """
    Average probability with completely agnostic probabilities, a
    user-specified number of times.
    Input:
        probs: probabilities to average with agnostic probabilities
        times: number of times to average
    Returns:
        mean_probs: the averaged probabilities
    """
    agnostic_prob = np.full(len(probs), 1. / len(probs))
    probs_to_average = np.concatenate((repeat_array([agnostic_prob], times),
                                       [probs]))
    mean_probs = average_probabilities(probs_to_average)
    return mean_probs


def average_probabilities(list_of_probabilities):
    """
    Convenienvce function for taking a list of of probabilities of the form
    [probabilities1, probabilities2,...] and returns their average probability.
    """
    return np.mean(list_of_probabilities, axis=0)


def multiply_probabilities(list_of_probabilities):
    """
    Multiplies label-probabilities together elementwise, and then normalizes
    them. E.g. two input-probabilities, each with a single element,
    [[[0.1, 0.2, 0.7]], [[0.8, 0.1, 0.1]]] gives [[0.47059, 0.11765, 0.41176]].
    """
    multiplied_probs = reduce(lambda x, y: x*y, list_of_probabilities)
    sum_probs = np.sum(multiplied_probs, axis=1)
    normalized_probs = np.array([prob / psum
                                 for prob, psum in zip(multiplied_probs,
                                                       sum_probs)])
    return normalized_probs


def compute_loss(probabilities, labels):
    """
    Comutes the mean cross-entropy loss given probabilities and the correct
    labels.
    """
    vlog = np.vectorize(minmaxlog)
    log_probas = vlog(probabilities)
    loss = - np.mean(log_probas * labels)
    return loss

Include module for probability manipulations
feat: Include module for probability manipulations

