Source code for n3fit.tests.test_backend

"""
    This module tests the mathematical functions in the n3fit backend
    and ensures they do the same thing as their numpy counterparts
"""

import operator

import numpy as np

from n3fit.backends import operations as op

# General parameters
DIM = 7
THRESHOLD = 1e-6

# Arrays to be used during testing
ARR1 = np.random.rand(DIM)
ARR2 = np.random.rand(DIM)
ARR3 = np.random.rand(DIM + 1, DIM)
C = np.random.rand(DIM, DIM)
INVCOVMAT = np.linalg.inv(C @ C.T)

# Backend-tensors to be used during testing
T1 = op.numpy_to_tensor(ARR1)
T2 = op.numpy_to_tensor(ARR2)
T3 = op.numpy_to_tensor(ARR3)


[docs] def are_equal(result, reference, threshold=THRESHOLD): """checks the difference between array `reference` and tensor `result` is below `threshold` for all elements""" res = op.tensor_to_numpy_or_python(result) assert np.allclose(res, reference, atol=threshold)
[docs] def numpy_check(backend_op, python_op, mode="same"): """Receives a backend operation (`backend_op`) and a python operation `python_op` and asserts that, applied to two random arrays, the result is the same. The option `mode` selects the two arrays to be tested and accepts the following options: - `same` (default): two arrays of the same dimensionality - `diff`: first array has one extra dimension that second array - `single`: only one array enters the operation - (tensor, array): if passed a tuple (backend tensor, numpy array), uses these values as tensor and array inputs for the operations """ if mode == "same": tensors = [T1, T2] arrays = [ARR1, ARR2] elif mode == "diff": tensors = [T3, T1] arrays = [ARR3, ARR1] elif mode == "four": tensors = [T1, T2, T1, T1] arrays = [ARR1, ARR2, ARR1, ARR1] elif mode == "twenty": tensors = [T1, T2, T1, T1, T1, T1, T1, T1, T1, T1, T1, T2, T1, T1, T1, T1, T1, T1, T1, T1] arrays = [ ARR1, ARR2, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ARR2, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ] elif mode == "ten": tensors = [T1, T2, T1, T1, T1, T1, T1, T1, T1, T1] arrays = [ARR1, ARR2, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1, ARR1] elif mode == "single": tensors = [T1] arrays = [ARR1] elif isinstance(mode, tuple): tensors = mode[0] arrays = mode[1] result = backend_op(tensors) reference = python_op(*arrays) are_equal(result, reference)
# Test NNPDF operations
[docs] def test_c_to_py_fun(): # Null function op_null = op.c_to_py_fun("NULL") numpy_check(op_null, lambda x: x, "single") # Add op_add = op.c_to_py_fun("ADD") numpy_check(op_add, operator.add) # Ratio op_rat = op.c_to_py_fun("RATIO") numpy_check(op_rat, operator.truediv) # ASY op_asy = op.c_to_py_fun("ASY") reference = lambda x, y: (x - y) / (x + y) numpy_check(op_asy, reference) # SMN op_smn = op.c_to_py_fun("SMN") reference = lambda x, y, z, d: (x + y) / (z + d) numpy_check(op_smn, reference, "four") # x - abs(y) op_addp = op.c_to_py_fun("SUBTRACT_ABS") reference = lambda x, y: x - np.abs(y) numpy_check(op_addp, reference, "same") # x + y - abs(z+d) op_smp = op.c_to_py_fun("SUBTRACT_ABSPAIR") reference = lambda x, y, z, d: x + y - np.abs(z + d) numpy_check(op_smp, reference, "four") # COM op_com = op.c_to_py_fun("COM") reference = lambda x, y, z, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t: ( x + y + z + d + e + f + g + h + i + j ) / (k + l + m + n + o + p + q + r + s + t) numpy_check(op_com, reference, "twenty") # SMT op_smt = op.c_to_py_fun("SMT") reference = lambda x, y, z, d, e, f, g, h, i, j: (x + y + z + d + e + f + g + h + i + j) numpy_check(op_smt, reference, "ten")
# Tests operations
[docs] def test_op_multiply(): numpy_check(op.op_multiply, operator.mul)
[docs] def test_op_log(): numpy_check(op.op_log, np.log, mode='single')
[docs] def test_flatten(): numpy_check(op.flatten, np.ndarray.flatten, mode=(T3, [ARR3]))
[docs] def test_tensor_product(): np_result = np.tensordot(ARR3, ARR1, axes=1) tf_result = op.tensor_product(T3, T1, axes=1) are_equal(tf_result, np_result)
[docs] def test_sum(): numpy_check(op.sum, np.sum, mode='single')