def test_array_input():
    arr = [Variable('x', 0.5), Variable('x', 0.5)]
    t1 = sin(arr)
    t2 = arcsin(arr)
    t3 = cos(arr)
    t4 = arccos(arr)
    t5 = tan(arr)
    t6 = arctan(arr)
    t7 = exp(arr)
    t8 = log(arr)
    t9 = sinh(arr)
    t10 = cosh(arr)
    t11 = tanh(arr)
    t12 = sqrt(arr)
    t13 = sigmoid(arr)
    assert t1[0].val == pytest.approx(np.sin(0.5))
    assert t2[1].val == pytest.approx(np.arcsin(0.5))
    assert t3[0].val == pytest.approx(np.cos(0.5))
    assert t4[1].val == pytest.approx(np.arccos(0.5))
    assert t5[0].val == pytest.approx(np.tan(0.5))
    assert t6[1].val == pytest.approx(np.arctan(0.5))
    assert t8[0].val == pytest.approx(np.log(0.5))
    assert t9[1].val == pytest.approx(np.sinh(0.5))
    assert t10[0].val == pytest.approx(np.cosh(0.5))
    assert t11[1].val == pytest.approx(np.tanh(0.5))
    assert t12[0].val == pytest.approx(np.sqrt(0.5))
    assert t13[1].val == pytest.approx(1 / (1 + np.exp(-0.5)))
Пример #2
0
def test_string_input_var():
    with pytest.raises(TypeError):
        x = Variable('x', 'test')
    with pytest.raises(TypeError):
        x = Variable('x', 3)
        x.val = 2
        x.val = 'test'
def test_sqrt():
    value = 9
    x = Variable('x', value)
    a = sqrt(value)
    assert a == pytest.approx(np.sqrt(value))
    g = sqrt(x)
    assert g.val == pytest.approx(np.sqrt(value))
def test_sigmoid():
    value = 0.5
    x = Variable('x', value)
    g = sigmoid(x)
    a = sigmoid(value)
    assert a == pytest.approx(1 / (1 + np.exp(-value)))
    assert g.val == pytest.approx(1 / (1 + np.exp(-value)))
def test_log():
    value = 4
    x = Variable('x', value)
    f = log(x)
    a = log(value)
    assert a == pytest.approx(np.log(value))
    assert f._val == np.log(value)
    assert f._der['v1'] == pytest.approx(0.25)
def test_exp():
    value = 67
    x = Variable('x', value)
    f = exp(x)
    a = exp(value)
    assert a == pytest.approx(np.exp(value))
    assert f._val == pytest.approx(np.exp(value), rel=1e-5)
    assert f._der['v1'] == f._val
def test_other_domains():
    x = Variable('x', -2)
    y = -2
    with pytest.raises(ValueError):
        f = log(x)
    with pytest.raises(ValueError):
        f = log(y)
    with pytest.raises(ValueError):
        f = sqrt(x)
    with pytest.raises(ValueError):
        f = sqrt(y)
def test_arc_domains():
    x = Variable('x', 2)
    y = 2
    with pytest.raises(ValueError):
        f = arcsin(x)
    with pytest.raises(ValueError):
        f = arccos(x)
    with pytest.raises(ValueError):
        f = arcsin(y)
    with pytest.raises(ValueError):
        f = arccos(y)
def test_composition_val():
    value = np.pi / 6
    x = Variable('x', value)
    c = cos(x)
    s = sin(x)
    t = tan(x)
    e = exp(x)
    f = c * t + e
    g = c + s
    assert isinstance(f, Trace)
    assert f._val == np.cos(value) * np.tan(value) + np.exp(value)
def test_sin():
    value = 0.5
    x = Variable('x', value)
    a = sin(value)
    b = arcsin(value)
    c = sinh(value)
    assert a == pytest.approx(np.sin(value))
    assert b == pytest.approx(np.arcsin(value))
    assert c == pytest.approx(np.sinh(value))
    g = sin(x)
    h = arcsin(x)
    i = sinh(x)
    assert g.val == pytest.approx(np.sin(value))
    assert h.val == pytest.approx(np.arcsin(value))
    assert i.val == pytest.approx(np.sinh(value))
def test_tan():
    value = 0.5
    x = Variable('x', value)
    a = tan(value)
    b = arctan(value)
    c = tanh(value)
    assert a == pytest.approx(np.tan(value))
    assert b == pytest.approx(np.arctan(value))
    assert c == pytest.approx(np.tanh(value))
    g = tan(x)
    h = arctan(x)
    i = tanh(x)
    assert g.val == pytest.approx(np.tan(value))
    assert h.val == pytest.approx(np.arctan(value))
    assert i.val == pytest.approx(np.tanh(value))
def test_cos():
    value = 0.5
    x = Variable('x', value)
    a = cos(value)
    b = arccos(value)
    c = cosh(value)
    assert a == pytest.approx(np.cos(value))
    assert b == pytest.approx(np.arccos(value))
    assert c == pytest.approx(np.cosh(value))
    g = cos(x)
    h = arccos(x)
    i = cosh(x)
    assert g.val == pytest.approx(np.cos(value))
    assert h.val == pytest.approx(np.arccos(value))
    assert i.val == pytest.approx(np.cosh(value))
Пример #13
0
def trace(f, seed, mode=None, return_second_deriv=False, verbose=False):
    '''
    f : a function
    seed: a vector/list of scalars. If f is single-dimensional, seed can be a scalar

    Optional parameter mode
        When mode = None, this function infers the more efficient mode from the number of input and output variables

    Optional parameter return_second_deriv (default is False)
        When return_second_deriv = True, this function returns f' AND f''

    f can be
    f: R --> R using explicit single-variable input
    f: Rm --> R using explicit multi-variable input
    f: R --> Rn using explicit single-variable input and explicit vector output
    f: Rm --> R using explicit vector input
    f: Rm --> Rn using explicit vector input and explicit vector output
    f: Rm --> Rn using explicit multi-variable input and explicit vector output
    f: Rm --> Rn using IMPLICIT vector input and IMPLICIT vector output
    '''

    ######################## make your Variable objects #########################
    # for now, always reset the CompGraph when tracing a new function
    CompGraph.reset()

    # infer the dimensionality of the input
    try:  # if multidimensional input
        M = len(seed)  # get the dimension of the input
        seed = np.array(seed)
    except TypeError:  # if single-dimensional input
        M = 1
        seed = np.array([seed])
    if verbose:
        print(f'Inferred {M}-dimensional input')

    # create new variables
    names = [f'v{i+1}' for i in range(M)]
    new_variables = np.array([Variable(names[i], seed[i]) for i in range(M)])
    #############################################################################

    ################ Trace the function ##############
    if verbose:
        print('Scanning the computational graph...')
    # Apply f to the new variables
    # Infer the way f was meant to be applied
    if M > 1:
        # multi-variable input

        try:
            # as a vector
            output = f(new_variables)
            if verbose:
                print('...inferred the input is a vector...')
        except TypeError:
            # as variables
            output = f(*new_variables)
            if verbose:
                print('...inferred the inputs are variables...')

    else:
        # single-variable input
        output = f(new_variables[0])
        if verbose:
            print('...inferred the input is a variable...')
    if verbose:
        print('...finished')
    ############################################

    ################ Get Outputs #################
    try:
        N = len(output)
    except AttributeError:
        N = 1
        output = [output]
    except TypeError:
        N = 1
        output = [output]
    if verbose:
        print(f'Inferred {N}-dimensional output')
        print(output)
    ##############################################

    ##################### Second Derivative #########################
    if return_second_deriv:
        if mode is not None and mode.lower() != 'reverse':
            raise ValueError(
                'Second derivative is automatically calculated in reverse mode'
            )
        if N > 1:
            raise ValueError(
                'Can only compute second derivative for scalar output f')
        print('Computing reverse mode first AND second derivative...')
        return CompGraph.hessian(output, verbose)
    ######################################################

    ####### get user-defined mode or infer the more efficient mode ##########
    if mode is None:
        if M > N:
            mode = 'reverse'
        else:
            mode = 'forward'
    else:
        mode = mode.lower()
    ######################################################################

    ############## First Derivative ####################
    #if verbose:
    print(f'Computing {mode} mode derivative...')
    if mode == 'forward':
        return CompGraph.forward_mode(output, verbose)
    elif mode == 'reverse':
        return CompGraph.reverse_mode(output, verbose)
    else:
        raise ValueError('Didnt recognize mode, should be forward or reverse')
def test_exp_base2():
    x = Variable('x', 5)
    base = 2
    f = exp(x, base=base)
    assert f._val == pytest.approx(32)
    assert f._der['v1'] == (base**x._val) * np.log(base)
def test_log_base2():
    x = Variable('x', 32)
    base = 2
    f = log(x, base=base)
    assert f._val == pytest.approx(5)
    assert f._der['v1'] == 1 / (x._val * np.log(base))