Skip to content

Commit

Permalink
Merge pull request #377 from damar-wicaksono/dev-337
Browse files Browse the repository at this point in the history
Add Lim et al. (2002) non-polynomial test function
  • Loading branch information
damar-wicaksono authored Nov 11, 2024
2 parents 451ca85 + f802934 commit 72b8be7
Show file tree
Hide file tree
Showing 8 changed files with 216 additions and 5 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- The two-dimensional non-polynomial test function for metamodeling from

- The two-dimensional polynomial test function for metamodeling from
Lim et al. (2002).
- The three-dimensional sensitivity test function from Moon (2010).
Expand Down
2 changes: 2 additions & 0 deletions docs/_toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ parts:
title: Hyper-sphere Bound
- file: test-functions/ishigami
title: Ishigami
- file: test-functions/lim-non-poly
title: Lim et al. (2002) Non-Polynomial
- file: test-functions/lim-poly
title: Lim et al. (2002) Polynomial
- file: test-functions/mclain-s1
Expand Down
1 change: 1 addition & 0 deletions docs/fundamentals/metamodeling.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ in the comparison of metamodeling approaches.
| {ref}`Friedman (6D) <test-functions:friedman-6d>` | 6 | `Friedman6D()` |
| {ref}`Friedman (10D) <test-functions:friedman-10d>` | 10 | `Friedman10D()` |
| {ref}`Gramacy (2007) 1D Sine <test-functions:gramacy-1d-sine>` | 1 | `Gramacy1DSine()` |
| {ref}`Lim et al. (2002) Non-Polynomial <test-functions:lim-non-poly>` | 2 | `LimNonPoly()` |
| {ref}`Lim et al. (2002) Polynomial <test-functions:lim-poly>` | 2 | `LimPoly()` |
| {ref}`McLain S1 <test-functions:mclain-s1>` | 2 | `McLainS1()` |
| {ref}`McLain S2 <test-functions:mclain-s2>` | 2 | `McLainS2()` |
Expand Down
1 change: 1 addition & 0 deletions docs/test-functions/available.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ regardless of their typical applications.
| {ref}`Gramacy (2007) 1D Sine <test-functions:gramacy-1d-sine>` | 1 | `Gramacy1DSine()` |
| {ref}`Hyper-sphere Bound <test-functions:hyper-sphere>` | 2 | `HyperSphere()` |
| {ref}`Ishigami <test-functions:ishigami>` | 3 | `Ishigami()` |
| {ref}`Lim et al. (2002) Non-Polynomial <test-functions:lim-non-poly>` | 2 | `LimNonPoly()` |
| {ref}`Lim et al. (2002) Polynomial <test-functions:lim-poly>` | 2 | `LimPoly()` |
| {ref}`McLain S1 <test-functions:mclain-s1>` | 2 | `McLainS1()` |
| {ref}`McLain S2 <test-functions:mclain-s2>` | 2 | `McLainS2()` |
Expand Down
150 changes: 150 additions & 0 deletions docs/test-functions/lim-non-poly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
---
jupytext:
formats: ipynb,md:myst
text_representation:
extension: .md
format_name: myst
format_version: 0.13
jupytext_version: 1.14.1
kernelspec:
display_name: Python 3 (ipykernel)
language: python
name: python3
---

(test-functions:lim-non-poly)=
# Two-dimensional Non-Polynomial Function from Lim et al. (2002)

```{code-cell} ipython3
import numpy as np
import matplotlib.pyplot as plt
import uqtestfuns as uqtf
```

The non-polynomial test function from Lim et al. (2002) (or `LimNonPoly` for
short) is a two-dimensional scalar-valued function.
The function was used in {cite}`Lim2002` in the context of establishing the
connection between Gaussian process metamodel and polynomials.

```{code-cell} ipython3
:tags: [remove-input]
from mpl_toolkits.axes_grid1 import make_axes_locatable
my_fun = uqtf.LimNonPoly()
# --- Create 2D data
xx_1d = np.linspace(0.0, 1.0, 1000)[:, np.newaxis]
mesh_2d = np.meshgrid(xx_1d, xx_1d)
xx_2d = np.array(mesh_2d).T.reshape(-1, 2)
yy_2d = my_fun(xx_2d)
# --- Create two-dimensional plots
fig = plt.figure(figsize=(10, 5))
# Surface
axs_1 = plt.subplot(121, projection='3d')
axs_1.plot_surface(
mesh_2d[0],
mesh_2d[1],
yy_2d.reshape(1000,1000).T,
linewidth=0,
cmap="plasma",
antialiased=False,
alpha=0.5
)
axs_1.set_xlabel("$x_1$", fontsize=14)
axs_1.set_ylabel("$x_2$", fontsize=14)
axs_1.set_zlabel("$\mathcal{M}(x_1, x_2)$", fontsize=14)
axs_1.set_title("Surface plot of LimPoly", fontsize=14)
# Contour
axs_2 = plt.subplot(122)
cf = axs_2.contourf(
mesh_2d[0], mesh_2d[1], yy_2d.reshape(1000, 1000).T, cmap="plasma", levels=10,
)
axs_2.set_xlabel("$x_1$", fontsize=14)
axs_2.set_ylabel("$x_2$", fontsize=14)
axs_2.set_title("Contour plot of LimPoly", fontsize=14)
divider = make_axes_locatable(axs_2)
cax = divider.append_axes('right', size='5%', pad=0.05)
fig.colorbar(cf, cax=cax, orientation='vertical')
axs_2.axis('scaled')
fig.tight_layout(pad=4.0)
plt.gcf().set_dpi(75);
```


## Test function instance

To create a default instance of the test function:

```{code-cell} ipython3
my_testfun = uqtf.LimNonPoly()
```

Check if it has been correctly instantiated:

```{code-cell} ipython3
print(my_testfun)
```

## Description

The test function is defined as follows[^location]:

$$
\mathcal{M}(\boldsymbol{x}) = \frac{(30 + 5 x_1 \sin{(5 x_1)}) (4 + \exp{(-5x_2)}) - 100}{6}
$$
where $\boldsymbol{x} = \{ x_1, x_2 \}$
is the two-dimensional vector of input variables further defined below.

```{note}
This function is a rescaled version of Eq. (6) in {cite}`Welch1992`.
The function is also similar to its
{ref}`polynomial counterpart <test-functions:lim-poly>`; in fact,
the coefficients of the polynomial are chosen with that goal in mind.
```

## Probabilistic input

The input consists of two uniformly distributed random variables as shown
below.

```{code-cell} ipython3
:tags: [hide-input]
print(my_testfun.prob_input)
```

## Reference results

This section provides several reference results of typical UQ analyses involving
the test function.

### Sample histogram

Shown below is the histogram of the output based on $100'000$ random points:

```{code-cell} ipython3
:tags: [hide-input]
xx_test = my_testfun.prob_input.get_sample(100000)
yy_test = my_testfun(xx_test)
plt.hist(yy_test, bins="auto", color="#8da0cb");
plt.grid();
plt.ylabel("Counts [-]");
plt.xlabel("$\mathcal{M}(\mathbf{X})$");
plt.gcf().set_dpi(150);
```

## References

```{bibliography}
:style: unsrtalpha
:filter: docname in docnames
```

[^location]: See Eq. (28), Section 7, p. 121 {cite}`Lim2002`.
12 changes: 9 additions & 3 deletions docs/test-functions/lim-poly.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,6 @@ fig.tight_layout(pad=4.0)
plt.gcf().set_dpi(75);
```

As shown in the plots above, the function features a saddle shaped surface.

## Test function instance

To create a default instance of the test function:
Expand All @@ -93,14 +91,20 @@ print(my_testfun)

## Description

The test function is defined as follows:
The test function is defined as follows[^location]:

$$
\mathcal{M}(\boldsymbol{x}) = 9 + \frac{5}{2} x_1 - \frac{35}{2} x_2 + \frac{5}{2} x_1 x_2 + 19 x_2^2 - \frac{15}{2} x_1^3 - \frac{5}{2} x_1 x_2^2 - \frac{11}{2} x_2^4 + x_1^3 x_2^2,
$$
where $\boldsymbol{x} = \{ x_1, x_2 \}$
is the two-dimensional vector of input variables further defined below.

```{note}
The coefficients of the test function are chosen such that its global features
are similar to its
{ref}`non-polynomial counterpart <test-functions:lim-non-poly>`.
```

## Probabilistic input

The input consists of two uniformly distributed random variables as shown
Expand Down Expand Up @@ -140,3 +144,5 @@ plt.gcf().set_dpi(150);
:style: unsrtalpha
:filter: docname in docnames
```

[^location]: See Eq. (27), Section 7, p. 119 {cite}`Lim2002`.
3 changes: 2 additions & 1 deletion src/uqtestfuns/test_functions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from .gramacy2007 import Gramacy1DSine
from .hyper_sphere import HyperSphere
from .ishigami import Ishigami
from .lim import LimPoly
from .lim import LimPoly, LimNonPoly
from .oakley2002 import Oakley1D
from .otl_circuit import OTLCircuit
from .mclain import McLainS1, McLainS2, McLainS3, McLainS4, McLainS5
Expand Down Expand Up @@ -69,6 +69,7 @@
"Gramacy1DSine",
"HyperSphere",
"Ishigami",
"LimNonPoly",
"LimPoly",
"Oakley1D",
"OTLCircuit",
Expand Down
50 changes: 49 additions & 1 deletion src/uqtestfuns/test_functions/lim.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@


def evaluate_poly(xx: np.ndarray) -> np.ndarray:
"""Evaluate the non-polynomial test function from Lim et al (2002).
"""Evaluate the polynomial test function from Lim et al (2002).
The function is a polynomial with maximum total degree of 5.
Expand Down Expand Up @@ -89,3 +89,51 @@ class LimPoly(UQTestFunFixDimABC):
_available_parameters = None

evaluate = staticmethod(evaluate_poly) # type: ignore


def evaluate_non_poly(xx: np.ndarray) -> np.ndarray:
"""Evaluate the non-polynomial test function from Lim et al (2002).
The function is a polynomial with maximum total degree of 5.
Parameters
----------
xx : np.ndarray
Two-Dimensional input values given by N-by-2 arrays where
N is the number of input values.
Returns
-------
np.ndarray
The output of the test function evaluated on the input values.
The output is a 1-dimensional array of length N.
"""
trm_1 = 30 + 5 * xx[:, 0] * np.sin(5 * xx[:, 0])
trm_2 = 4 + np.exp(-5 * xx[:, 1])

yy = (trm_1 * trm_2 - 100) / 6.0

return yy


class LimNonPoly(UQTestFunFixDimABC):
"""An implementation of the 2D non-polynomial from Lim et al. (2002)."""

_tags = ["metamodeling"]
_description = (
"Two-dimensional non-polynomial function from Lim et al. (2002)"
)
_available_inputs: ProbInputSpecs = {
"Lim2002": {
"function_id": "LimNonPoly",
"description": (
"Input specification for the non-polynomial function "
"from Lim et al. (2002)"
),
"marginals": MARGINALS_LIM2002,
"copulas": None,
}
}
_available_parameters = None

evaluate = staticmethod(evaluate_non_poly) # type: ignore

0 comments on commit 72b8be7

Please sign in to comment.