Note
Go to the end to download the full example code
Model Definition
This tutorial describes how to setup a function with random inputs.
We start by defining a function of two random variables. We will use the Rosenbrock benchmark. See pyapprox.benchmarks.benchmarks.setup_rosenbrock_function()
import numpy as np
from scipy import stats
from pyapprox.variables import IndependentMarginalsVariable
def fun(samples):
return np.sum(samples*2, axis=0)[:, None]
Now lets define the inputs to the function of interest. For independent random variables we use SciPy random variablest to represent each one-dimensional variables. For documentation refer to the scipy.stats module.
We define multivariate random variables by specifying each 1D variable in a list. Here we will setup a 2D variable which is the tensor product of two independent and identically distributed uniform random variables
univariate_variables = [stats.uniform(-2, 4), stats.uniform(-2, 4)]
variable = IndependentMarginalsVariable(univariate_variables)
To print a summary of the random variable use
print(variable)
Independent Marginal Variable
Number of variables: 2
Unique variables and global id:
uniform(loc=[-2],scale=[4]): z0, z1
We can draw random samples from variable and evaluate the function using
nsamples = 1000
samples = variable.rvs(nsamples)
values = fun(samples)
Summary statistics of the samples and values can be printed using
from pyapprox.variables import print_statistics
print_statistics(samples, values)
z0 z1 y0
count 1000.000000 1000.000000 1000.000000
mean -0.038207 -0.041565 -0.159543
std 1.165293 1.175000 3.340050
min -1.992304 -1.996393 -7.725900
max 1.995606 1.988541 7.762915
User defined functions
PyApprox can be used with pretty much any function provided an appropriate interface is defined. Here will show how to setup a simple function.
PyApprox requires all functions to take 2D np.ndarray with shape (nvars,nsamples) and requires a function to return a 2D np.ndarray with shape (nsampels,nqoi). nqoi==1 for scalar valued functions and nqoi>1 for vectored value functions.
Lets define a function which does not match this criteria and use wrappers provided by PyApprox to convert it to the correct format. Specifically we will define a function that only takes a 1D np.ndarray and returns a scalar. We import these functions from a separate file
def fun_0(sample):
assert sample.ndim == 1
return np.sum(sample**2)
def pyapprox_fun_0(samples):
values = evaluate_1darray_function_on_2d_array(fun_0, samples)
return values
from __util import pyapprox_fun_0, fun_0
values = pyapprox_fun_0(samples)
The function pyapprox.interface.wrappers.evaluate_1darray_function_on_2d_array()
avoids the need to write a for loop but we can do this also and does some checking to make sure values is the correct shape
values_loop = np.array([np.atleast_1d(fun_0(s)) for s in samples.T])
assert np.allclose(values, values_loop)
Total running time of the script: ( 0 minutes 0.021 seconds)