Evaluate a Function on a Grid#

import minterpy as mp
import numpy as np

Calling an instance of Grid with a function or a Callable evaluates the given function on the unisolvent nodes and returns the corresponding function values. In the context of polynomial interpolation, these function values are the coefficients of a polynomial in the Lagrange basis.

This guide demonstrates how to call an instance of Grid on a function.

Example: Function with one-dimensional output#

Consider the following problem:

Compute the formula

\[ f(\boldsymbol{x}) = \sum_{i = 1}^{3} x_i^2, \boldsymbol{x} \in [-1, 1]^3 \]

on the interpolation grid that corresponds to a complete multi-index set of polynomial degree \(3\) with respect to the \(l_p\)-degree \(2.0\).

Function to evaluate#

A valid function or callable that can be called with a Grid instance must satisfy the following:

  • it must accept as the first argument a two-dimensional array where each row corresponds to different evaluation points and each column corresponds to different spatial dimension.

  • it must return an array with the same length as the input.

The function or callable may accept additional arguments either positional or keyword.

The function as required above can be defined as follows:

def fun_one_dim(xx: np.ndarray) -> np.ndarray:
    """Compute the sum of squared."""
    return np.sum(xx**2, axis=1)

Grid#

The interpolation grid that corresponds to the complete multi-index set can be created using from_degree() factory method:

spatial_dimension = 3
poly_degree = 3
lp_degree = 2.0
grd = mp.Grid.from_degree(spatial_dimension, poly_degree, lp_degree)

Function values on the grid#

By calling the Grid instance on the function defined above, we evaluate the function on the unisolvent nodes of the grid:

fun_values = grd(fun_one_dim)
fun_values
array([3.  , 3.  , 2.25, 2.25, 3.  , 3.  , 2.25, 2.25, 2.25, 1.5 , 2.25,
       3.  , 3.  , 2.25, 3.  , 3.  , 2.25, 2.25, 2.25, 1.5 , 2.25, 2.25,
       1.5 , 2.25, 2.25, 1.5 , 1.5 , 1.5 , 2.25])

As expected, these values are the same values from evaluating the given function on the unisolvent nodes:

fun_one_dim(grd.unisolvent_nodes)
array([3.  , 3.  , 2.25, 2.25, 3.  , 3.  , 2.25, 2.25, 2.25, 1.5 , 2.25,
       3.  , 3.  , 2.25, 3.  , 3.  , 2.25, 2.25, 2.25, 1.5 , 2.25, 2.25,
       1.5 , 2.25, 2.25, 1.5 , 1.5 , 1.5 , 2.25])

Example: Function with multi-dimensional output#

Consider the following problem:

Compute the formula

\[ \boldsymbol{f}(\boldsymbol{x}) = (f_1(\boldsymbol{x}), f_2(\boldsymbol{x}) ), \; \boldsymbol{x} \in [-1, 1]^3 \]

where

\[\begin{split} \begin{aligned} f_1(\boldsymbol{x}) & = \sum_{i = 1}^{3} x_i^2,\\ f_1(\boldsymbol{x}) & = \prod_{i = 1}^{3} x_i^2, \end{aligned} \end{split}\]

on the same interpolation grid as before.

Notice that the function now returns two outputs per input value.

The function or callable passed to the Grid instance may also return multiple outputs. The function must be defined such that it returns an array whose each column corresponds to the different output.

The required function can therefore be defined as follows:

def fun_two_dim(xx: np.ndarray) -> np.ndarray:
    """Return the sum and product of squared."""
    yy = np.empty((len(xx), 2))
    
    yy[:, 0] = np.sum(xx**2, axis=1)
    yy[:, 1] = np.prod(xx**2, axis=1)
    
    return yy

The previous instance of Grid can be directly used to obtain the values of the multiple-output function:

grd(fun_two_dim)
array([[3.    , 1.    ],
       [3.    , 1.    ],
       [2.25  , 0.25  ],
       [2.25  , 0.25  ],
       [3.    , 1.    ],
       [3.    , 1.    ],
       [2.25  , 0.25  ],
       [2.25  , 0.25  ],
       [2.25  , 0.25  ],
       [1.5   , 0.0625],
       [2.25  , 0.25  ],
       [3.    , 1.    ],
       [3.    , 1.    ],
       [2.25  , 0.25  ],
       [3.    , 1.    ],
       [3.    , 1.    ],
       [2.25  , 0.25  ],
       [2.25  , 0.25  ],
       [2.25  , 0.25  ],
       [1.5   , 0.0625],
       [2.25  , 0.25  ],
       [2.25  , 0.25  ],
       [1.5   , 0.0625],
       [2.25  , 0.25  ],
       [2.25  , 0.25  ],
       [1.5   , 0.0625],
       [1.5   , 0.0625],
       [1.5   , 0.0625],
       [2.25  , 0.25  ]])

As expected, calling the Grid instance with the function returns a two-dimensional array whose each column corresponds to each outputs and each row corresponds to each unisolvent nodes.

Example: Function with additional arguments#

While the function passed to a Grid instance must take as its first argument a two-dimensional array, additional arguments may also be passed to the function by passing positional and keyword arguments to the call.

For instance, suppose the function to be evaluated is defined as follows:

def fun_with_args(xx: np.ndarray, p: float) -> np.ndarray:
    """Return the row-wise lp-norm."""
    return np.sum(np.abs(xx**p), axis=1)**(1/p)

To change the behavior of the function call via one of its argument when the function is evaluated on the grid, pass the additional arguments to the call to the Grid instance.

For instance, with the additional argument to fun_with_args() as a positional argument:

grd(fun_with_args, 1.0)
array([3. , 3. , 2.5, 2.5, 3. , 3. , 2.5, 2.5, 2.5, 2. , 2.5, 3. , 3. ,
       2.5, 3. , 3. , 2.5, 2.5, 2.5, 2. , 2.5, 2.5, 2. , 2.5, 2.5, 2. ,
       2. , 2. , 2.5])
grd(fun_with_args, 2.0)
array([1.73205081, 1.73205081, 1.5       , 1.5       , 1.73205081,
       1.73205081, 1.5       , 1.5       , 1.5       , 1.22474487,
       1.5       , 1.73205081, 1.73205081, 1.5       , 1.73205081,
       1.73205081, 1.5       , 1.5       , 1.5       , 1.22474487,
       1.5       , 1.5       , 1.22474487, 1.5       , 1.5       ,
       1.22474487, 1.22474487, 1.22474487, 1.5       ])

…and as a keyword argument:

grd(fun_with_args, p=3.0)
array([1.44224957, 1.44224957, 1.2856408 , 1.2856408 , 1.44224957,
       1.44224957, 1.2856408 , 1.2856408 , 1.2856408 , 1.07721735,
       1.2856408 , 1.44224957, 1.44224957, 1.2856408 , 1.44224957,
       1.44224957, 1.2856408 , 1.2856408 , 1.2856408 , 1.07721735,
       1.2856408 , 1.2856408 , 1.07721735, 1.2856408 , 1.2856408 ,
       1.07721735, 1.07721735, 1.07721735, 1.2856408 ])