#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
    This file contains the generators and their inverses for common archimedean copulas.
"""

import numpy as np

def boundsConditions(x):
    if x < 0 or x > 1:
        raise ValueError("Unable to compute generator for x equals to {}".format(x))

def claytonGenerator(x, theta):
    boundsConditions(x)
    if theta == 0:
        raise ValueError("The parameter of a Clayton copula must not be equal to 0.")
    if theta < -1:
        raise ValueError("The parameter of a Clayton copula must be greater than -1 and different from 0.")
    return (1. / theta) * (x**(-theta) - 1.)

def claytonGeneratorInvert(x, theta):
    if theta == 0:
        raise ValueError("The parameter of a Clayton copula must not be equal to 0.")
    if theta < -1:
        raise ValueError("The parameter of a Clayton copula must be greater than -1 and different from 0.")
    return (1. + theta * x)**(-1. / max(theta,1e-6))

def gumbelGenerator(x, theta):
    boundsConditions(x)
    if theta < 1:
        raise ValueError("The parameter of a Gumbel copula must be greater than 1.")
    return (-np.log(x))**theta

def gumbelGeneratorInvert(x, theta):
    if len(theta) > 1: 
        theta = theta[0]
    if theta < 1:
        raise ValueError("The parameter of a Gumbel copula must be greater than 1.")
    if (x < 1 and theta != 1):
        raise(ValueError("The inverse Gumbel generator cannot be evaluated for negative input and theta > 1"))
    return np.exp(-np.power(x,np.divide(1, theta)))


def frankGenerator(x, theta):
    boundsConditions(x)
    if theta == 0:
        raise ValueError("The parameter of a Frank copula must not be equal to 0.")
    return -np.log((np.exp(-theta[0] * x) - 1) / (np.exp(-theta[0]) - 1))

def frankGeneratorInvert(x, theta):
    if theta == 0:
        raise ValueError("The parameter of a Frank copula must not be equal to 0.")
    return -1. / theta * np.log(1. + np.exp(-x) * (np.exp(-theta) - 1.))

def joeGenerator(x, theta):
    boundsConditions(x)
    if theta < 1:
        raise ValueError("The parameter of a Joe copula must be greater than 1.")
    return -np.log(1. - (1. - x)**theta)

def joeGeneratorInvert(x, theta):
    if theta < 1:
        raise ValueError("The parameter of a Joe copula must be greater than 1.")
    return 1. - (1. - np.exp(-x))**(1. / max(theta,1e-6))

def aliMikhailHaqGenerator(x, theta):
    boundsConditions(x)
    if theta < -1 or theta >= 1:
        raise ValueError("The parameter of an Ali-Mikhail-Haq copula must be between -1 included and 1 excluded.")
    return np.log((1. - theta * (1. - x)) / x)

def aliMikhailHaqGeneratorInvert(x, theta):
    if theta < -1 or theta >= 1:
        raise ValueError("The parameter of an Ali-Mikhail-Haq copula must be between -1 included and 1 excluded.")
    return (1. - theta) / (np.exp(x) - theta)

[((2585, 2622), 'numpy.log', 'np.log', (['((1.0 - theta * (1.0 - x)) / x)'], {}), '((1.0 - theta * (1.0 - x)) / x)\n', (2591, 2622), True, 'import numpy as np\n'), ((2141, 2173), 'numpy.log', 'np.log', (['(1.0 - (1.0 - x) ** theta)'], {}), '(1.0 - (1.0 - x) ** theta)\n', (2147, 2173), True, 'import numpy as np\n'), ((1128, 1137), 'numpy.log', 'np.log', (['x'], {}), '(x)\n', (1134, 1137), True, 'import numpy as np\n'), ((2841, 2850), 'numpy.exp', 'np.exp', (['x'], {}), '(x)\n', (2847, 2850), True, 'import numpy as np\n'), ((1508, 1527), 'numpy.divide', 'np.divide', (['(1)', 'theta'], {}), '(1, theta)\n', (1517, 1527), True, 'import numpy as np\n'), ((2327, 2337), 'numpy.exp', 'np.exp', (['(-x)'], {}), '(-x)\n', (2333, 2337), True, 'import numpy as np\n'), ((1709, 1730), 'numpy.exp', 'np.exp', (['(-theta[0] * x)'], {}), '(-theta[0] * x)\n', (1715, 1730), True, 'import numpy as np\n'), ((1739, 1756), 'numpy.exp', 'np.exp', (['(-theta[0])'], {}), '(-theta[0])\n', (1745, 1756), True, 'import numpy as np\n'), ((1940, 1950), 'numpy.exp', 'np.exp', (['(-x)'], {}), '(-x)\n', (1946, 1950), True, 'import numpy as np\n'), ((1954, 1968), 'numpy.exp', 'np.exp', (['(-theta)'], {}), '(-theta)\n', (1960, 1968), True, 'import numpy as np\n')]