示例#1
0
def test_pow():
    """Test of exponent special method (__pow__) of Rnode class."""
    # Test for exponent with scalar Rnode object and float value
    x = Rnode(0.11)
    z = x**2
    z.grad_value = 1.0

    try:
        assert z.value == x.value**2
        assert x.grad() == x.value**2 * np.log(x.value)
        # assert x.children == (x.value ** 2 * np.log(x.value), z)
    except AssertionError as e:
        print(e)


# Test for exponent with two scalar Rnode object
    x = Rnode(0.11)
    y = Rnode(0.2)
    z = x**y
    z.grad_value = 1.0

    try:
        assert z.value == x.value**y.value
        assert x.grad() == x.value**y.value * np.log(x.value)
    except AssertionError as e:
        print(e)
示例#2
0
def test_clear():
    """Test of clear special method (clear) of Rnode class."""
    # Test for clear with scalar Rnode object and float value
    x = Rnode(0.11)
    z = x**2 + x
    z.grad_value = 1.0
    x.grad()
    x.clear()

    try:
        # assert z.value == x.value **2 + x.value
        assert x.grad() is None
    except AssertionError as e:
        print(e)
示例#3
0
def test_tanh():
    """Test of tanh method."""
    # Test for sin with Rnode objects

    x = Rnode(1.0)
    z = Elem.tanh(x)
    z.grad_value = 1.0
    try:
        assert z.value == np.tanh(x.value)
        assert x.grad() == 1 / np.cosh(x.value)**2

    except AssertionError as e:
        print(e)
    # Test for tan with two Dual objects
    val = Dual(3, [4, 1])
    z = Elem.tanh(val)
    der = val.der / (np.cosh(val.val))**2

    try:
        assert z.val == np.tanh(val.val)
        assert np.all(z.der == der)

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for tanh with int,
    x = 3
    fx = Elem.tanh(x)
    try:
        assert fx == np.tanh(x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#4
0
def test_cosh():
    """Test of cosh method."""
    # Test for sin with Rnode objects

    x = Rnode(1.0)
    z = Elem.cosh(x)
    z.grad_value = 1.0
    try:
        assert z.value == np.cosh(x.value)
        assert x.grad() == np.sinh(x.value)

    except AssertionError as e:
        print(e)
    # Test for cosh with two Dual objects
    val = Dual(3, [4, 1])
    z = Elem.cosh(val)

    try:
        assert z.val == np.cosh(val.val)
        assert z.der[0] == np.sinh(val.val) * val.der[0]
        assert z.der[1] == np.sinh(val.val) * val.der[1]

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for cosh with int,
    x = 3
    fx = Elem.cosh(x)
    try:
        assert fx == np.cosh(x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#5
0
def test_add():
    """Test of addition special method (__add__) of Rnode class."""
    # Test for addition with scalar Rnode object and float value
    x = Rnode(0.11)
    z = x**2 + x
    z.grad_value = 1.0

    try:
        assert z.value == x.value**2 + x.value
        assert x.grad() == sum(weight * var.grad()
                               for weight, var in x.children)
    except AssertionError as e:
        print(e)
示例#6
0
def test_arccos():
    """Test of arccos method."""
    # Test for arccos with Rnode objects

    x = Rnode(0.11)
    z = Elem.arccos(x)
    z.grad_value = 1.0
    temp = 1 - x.value**2
    print(temp)
    if temp <= 0:
        raise ValueError('Domain of sqrt is {x >= 0}')
    try:
        assert z.value == np.arccos(x.value)
        assert x.grad() == -1 / np.sqrt(temp)
    except AssertionError as e:
        print(e)

    # Test for arccos with invalid Rnode objects
    with pytest.raises(ValueError, match=r".* sqrt .*"):
        x = Rnode(2.0)
        z = Elem.arccos(x)
        Elem.arcsin(x)
        z.grad_value = 1.0

    # Test for arccos with two Dual objects
    # arccos() input (-1,1)
    x = Dual(0.2, [0.4, 0.1])
    z = Elem.arccos(x)
    print(z)
    der = -1 / np.sqrt(1 - x.val**2) * np.asarray(x.der)
    try:
        assert z.val == np.arccos(x.val)
        assert np.all(z.der == der)

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for arccos with int
    x = 0.1
    fx = Elem.arccos(x)
    try:
        assert fx == np.arccos(x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#7
0
def test_relu6():
    """Test of relu6 method."""
    # Test for sin with Rnode objects

    x = Rnode(7.0)
    z = Elem.relu6(x)
    z.grad_value = 1.0

    a = max(0, x.value)
    b = np.where(0.0 < a < 6.0, 1, 0)
    if a > 6.0:  # clip output to a maximum of 6
        a = 6.0
    try:
        assert z.value == a
        assert x.grad() == b

    except AssertionError as e:
        print(e)
    # Test for relu6 with two Dual objects
    x = Dual(8, [4, 1])
    z = Elem.relu6(x)

    a = max(0, x.val)
    b = np.where(0.0 < a < 6.0, 1, 0)
    print(b)
    if a > 6:  # clip output to a maximum of 6
        a = 6
    result = Dual(a, b * x.der)

    try:
        assert z.val == result.val
        assert np.all(z.der == result.der)

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for tanh with int,
    x = 3
    fx = Elem.relu6(x)
    try:
        assert fx == min(max(0, x), 6)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#8
0
def test_relu():
    """Test of relu method."""
    # Test for sin with Rnode objects

    x = Rnode(1.0)
    z = Elem.relu(x)
    z.grad_value = 1.0

    a = max(0, x.value)
    b = np.where(a > 0, 1, 0)
    try:
        assert z.value == a
        assert x.grad() == b

    except AssertionError as e:
        print(e)
    # Test for relu with two Dual objects
    x = Dual(3, [4, 1])
    z = Elem.relu(x)

    a = max(0, x.val)
    b = np.where(a > 0, 1, 0)
    result = Dual(a, b * x.der)

    try:
        assert z.val == result.val
        assert np.all(z.der == result.der)

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for tanh with int,
    x = 3
    fx = Elem.relu(x)
    try:
        assert fx == max(0, x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#9
0
def test_log2():
    """Test of log2 method."""
    # Test for sin with Rnode objects

    x = Rnode(1.0)
    z = Elem.log2(x)
    z.grad_value = 1.0
    try:
        assert z.value == np.log2(x.value)
        assert x.grad() == 1 / (x.value * np.log(2))

    except AssertionError as e:
        print(e)
    # Test for log2 with two Dual objects
    val1 = Dual(3, [4, 1])
    val2 = Dual(2, [3, 1])
    val = val1 * val2
    z = Elem.log2(val)

    try:
        assert z.val == np.log2(val.val)
        assert z.der[0] == 1 / (val.val * np.log(2)) * val.der[0]
        assert z.der[1] == 1 / (val.val * np.log(2)) * val.der[1]

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for log2 with invalid Dual objects
    with pytest.raises(ValueError, match=r".* logarithm .*"):
        Elem.log2(Dual(-1, [4, 1]))

    # Test for log2 with int,
    x = 3
    fx = Elem.log2(x)
    try:
        assert fx == np.log2(x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#10
0
def test_sin():
    """Test of sin method."""
    # Test for sin with Rnode objects

    x = Rnode(1.0)
    z = Elem.sin(x)
    z.grad_value = 1.0
    try:
        assert z.value == np.sin(x.value)
        assert x.grad() == np.cos(x.value)

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for sin with two Dual objects
    val1 = Dual(3, [4, 1])
    val2 = Dual(2, [3, 1])
    val = val1 + val2
    z = Elem.sin(val)

    try:
        assert z.val == np.sin(val.val)
        assert z.der[0] == np.cos(val.val) * val.der[0]
        assert z.der[1] == np.cos(val.val) * val.der[1]

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for sin with int
    x = 3
    fx = Elem.sin(x)
    try:
        assert fx == np.sin(x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#11
0
def test_sqrt():
    """Test of sqrt method."""
    # Test for sqrt with Rnode objects

    x = Rnode(1.0)
    z = Elem.sqrt(x)
    z.grad_value = 1.0

    try:
        assert z.value == x.value**0.5
        assert x.grad() == 0.5 * x.value**(-0.5)

    except AssertionError as e:
        print(e)
    # Test for sqrt with two Dual objects
    x = Dual(3, [4, 1])
    z = Elem.sqrt(x)
    result = x**0.5

    try:
        assert z.val == np.sqrt(x.val)
        assert z.der[0] == result.der[0]
        assert z.der[1] == result.der[1]

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for sqrt with double
    x = 3.0
    fx = Elem.sqrt(x)
    try:
        assert fx == np.sqrt(x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#12
0
def test_logistic():
    """Test of logistic method."""
    # Test for sin with Rnode objects

    x = Rnode(1.0)
    z = Elem.logistic(x)
    z.grad_value = 1.0

    nominator = np.exp(x.value)
    denominator = (1 + np.exp(x.value))**2
    try:
        assert z.value == 1 / (1 + np.exp(-x.value))
        assert x.grad() == nominator / denominator

    except AssertionError as e:
        print(e)
    # Test for logistic with two Dual objects
    x = Dual(3, [4, 1])
    z = Elem.logistic(x)
    result = (1 / (1 + np.exp(-x.val)),
              np.exp(x.val) / ((1 + np.exp(x.val))**2))
    try:
        assert z == result

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for logistic with int
    x = 3
    fx = Elem.logistic(x)
    try:
        assert fx == 1 / (1 + np.exp(-x))

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#13
0
def test_arctan():
    """Test of arctan method."""
    # Test for arctan with Rnode objects

    x = Rnode(0.11)
    z = Elem.arctan(x)
    z.grad_value = 1.0

    try:
        assert z.value == np.arctan(x.value)
        assert x.grad() == 1 / (1 + x.value**2)
    except AssertionError as e:
        print(e)

    # Test for arctan with two Dual objects
    # arctan() input (-1,1)
    x = Dual(0.2, [0.4, 0.1])
    z = Elem.arctan(x)
    der = 1 / (1 + x.val**2) * np.asarray(x.der)
    try:
        assert z.val == np.arctan(x.val)
        assert np.all(z.der == der)

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for arctan with int
    x = 0.1
    fx = Elem.arctan(x)
    try:
        assert fx == np.arctan(x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#14
0
def test_exp():
    """Test of exp method."""
    # Test for sin with Rnode objects

    x = Rnode(1.0)
    z = Elem.exp(x)
    z.grad_value = 1.0

    try:
        assert z.value == np.exp(x.value)
        assert x.grad() == np.exp(x.value)

    except AssertionError as e:
        print(e)
    # Test for exp with two Dual objects
    x = Dual(3, [4, 1])
    z = Elem.exp(x)
    der = np.exp(x.val) * np.asarray(x.der)

    try:
        assert z.val == np.exp(x.val)
        assert np.all(z.der == der)

    except AssertionError as e:
        print(e)
        raise AssertionError

    # Test for exp with int,
    x = 3
    fx = Elem.exp(x)
    try:
        assert fx == np.exp(x)

    except AssertionError as e:
        print(e)
        raise AssertionError
示例#15
0
class RAutoDiff:
    def __init__(self, fn):
        """Constructor for RAutoDiff class.

        Parameters
        ==========
        fn: The specific AD method for calculating the derivative.
        """
        self.fn = fn
        self._roots = None
        self._value = None
        self._der = None

    def forwardpass(self, x):
        """Constructor the tree structure with input X for specific AD method
        fn. Update the value and derivative of the AD method.

        Parameters
        ==========
        x: array_like

        Returns:
        No returns.

        """
        self._roots = None
        self._value = None
        self._der = None
        x = np.asarray(x)
        try:
            nf = len(self.fn)  # if fn is a list of functions
        except TypeError:
            nf = 1
        if nf == 1:  # only one function
            self._value, self._der = self._forwardpass1f(x, self.fn)
        else:  # vector functions
            #for now, all the input functions must contain exactly the same parameters
            #with the same order. function with only a subset of total Parameters
            # is not allowed
            nparams_all = [len(signature(fi).parameters) for fi in self.fn]
            if len(set(nparams_all)) > 1:
                raise TypeError('all input functions must contain the same parameters')
            self._value = []
            self._der = []
            for idxf in range(nf):
                tmp = self._forwardpass1f(x, self.fn[idxf])
                self._value.append(tmp[0])
                self._der.append(tmp[1])
        self._value = np.asarray(self._value)
        self._der = np.asarray(self._der)
        if len(self._value.shape) == 2 and len(self._der.shape) == 2:
            self._value = np.transpose(self._value, (1, 0))
            self._der = np.transpose(self._der, (1, 0))
        elif len(self._value.shape) == 2 and len(self._der.shape) == 3:
            self._value = np.transpose(self._value, (1, 0))
            self._der = np.transpose(self._der, (1, 0, 2))

        try:  # if _value or _der is a scalar array (size = 1), convert array to scalar
            if self._value.size ==1:
                self._value = np.asscalar(self._value)
            if self._der.size == 1:
                self._der = np.asscalar(self._der)
        except AttributeError:
            pass

    def _forwardpass1f(self, x, fi):  # deal with only one function case
        """Constructor the tree structure with input X for one single AD method
        fi. This _forwardpass1f method will be called when dealing with vector function
        input fn = [f1, f2, f3, ...]

        Parameters
        ==========
        x: array_like
        fi: One AD method

        Returns:
        tmpval: array_like, the value of fi(x)
        tmpder : array_like, the derivative of fi(x)

        """
# shoule only be called from forwardpass
        self._roots = None
        nparams = len(signature(fi).parameters)  # number of parameters of input function
        if nparams == 1:  # function has only one parameter
            if x.size == 1:  # scalar input
                self._roots = Rnode(x)
                f = fi(self._roots)
                f.grad_value = 1.0
                tmpval = f.value
                tmpder = self._roots.grad()
            else:  # vector input
                if len(x.shape) > 1:
                    raise TypeError('input dimension size not supported')
                else:
                    tmpval = np.zeros(len(x))
                    tmpder = np.zeros(len(x))
                    tmpidx = 0
                    for xi in x:
                        self._roots = Rnode(xi)
                        f = fi(self._roots)
                        f.grad_value = 1.0
                        tmpval[tmpidx] = f.value
                        tmpder[tmpidx] = self._roots.grad()
                        tmpidx = tmpidx + 1

        else:  # multiple input parameters (vector input)
            if x.size == 1:
                raise TypeError('input has insufficient parameters')
            if len(x.shape) == 1:  # evaluate at one vector point
                if len(x) != nparams:
                    raise TypeError('input dimension size mismatch')
                self._roots = [Rnode(xi) for xi in x]
                f = fi(*self._roots)
                f.grad_value = 1.0
                tmpval = f.value
                tmpder = [root.grad() for root in self._roots]
            else:  # evaluate at multiple vector points
                if x.shape[1] != nparams:
                    raise TypeError('input dimension size mismatch')
                nm = x.shape[0]  # number of vector points to be evaluated
                tmpval = np.zeros(nm)
                tmpder = np.zeros((nm, nparams))
                self._roots = []
                for im in range(nm):
                    self._roots.append([Rnode(xi) for xi in x[im, :]])
                    f = fi(*self._roots[im])
                    f.grad_value = 1.0
                    tmpval[im] = f.value
                    tmpder[im, :] = [root.grad() for root in self._roots[im]]
        return tmpval, tmpder

    def values(self):  # return the value of the function
        """Get value of the input method fn for given X

        Returns:
        y : array_like

        """
        return self._value

    def reverse(self):  # return the derivative with respect to varname variable
        """Get the derivatives (scalar, vector, or matrix depending on the
        the dimension of input method fn and X)

        Returns:
        y : array_like

        """
        return self._der