import numpy as np


def _output(result, out):
    if out is None:
        return result
    else:
        np.copyto(out, result)
        return out


def sigmoid(x, out=None):
    result = 1.0/(1.0+np.exp(-x))
    return _output(result, out)


def sigmoid_d(x, out=None):
    s = sigmoid(x)
    result = s*(1-s)
    return _output(result, out)


def tanh_d(x, out=None):
    result = 1-np.tanh(x)**2
    return _output(result, out)


def relu(x, out=None):
    result = np.maximum(0.0, x)
    return _output(result, out)


def relu_d(x, out=None):
    result = np.zeros(x.shape)
    result[x >= 0] = 1
    return _output(result, out)


def softplus(x, out=None):
    result = np.log1p(np.exp(x))
    mask = x > 25.0
    result[mask] = x[mask]
    return _output(result, out)


def softplus_d(x, out=None):
    result = 1.0 - 1.0/(1.0 + np.exp(x))
    result[x > 25.0] = 1.0
    return _output(result, out)
