Repository: damar-wicaksono/uqtestfuns (language: python)

Issue:
Add the Ten-Dimensional Inert Test Function from Linkletter et al. (2006)
The ten-dimensional test function from Linkletter et al. (2006)[^1] is a model with all inert variables (i.e., a function without "signal") and returns zero everywhere in the input domain.

In the paper, the response is standardized (with mean 0 and standard deviation 1.0), but we will skip this in the implementation of the function in UQTestFuns.

The model is used as a test function in the context of sensitivity analysis.

[^1]: C. Linkletter, D. Bingham, N. Hengartner, D. Higdon, and K. Q. Ye, “Variable Selection for Gaussian Process Models in Computer Experiments,” Technometrics, vol. 48, no. 4, pp. 478–490, Nov. 2006, doi: [10.1198/004017006000000228](https://doi.org/10.1198/004017006000000228).



Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 667ea49..a4122ff 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Added
 
+- The ten-dimensional inert function from Linkletter et al. (2006) with
+  no active input variable whatsoever; the function was used in the context of
+  sensitivity analysis.
 - The ten-dimensional sine function from Linkletter et al. (2006) featuring
   only two active input variables out of ten; the function was used in the
   context of metamodeling and sensitivity analysis.
diff --git a/docs/_toc.yml b/docs/_toc.yml
index 0c18199..22bfe4f 100644
--- a/docs/_toc.yml
+++ b/docs/_toc.yml
@@ -128,6 +128,8 @@ parts:
             title: Lim et al. (2002) Polynomial
           - file: test-functions/linkletter-dec-coeffs
             title: Linkletter et al. (2006) Dec. Coeffs.
+          - file: test-functions/linkletter-inert
+            title: Linkletter et al. (2006) Inert
           - file: test-functions/linkletter-linear
             title: Linkletter et al. (2006) Linear
           - file: test-functions/linkletter-sine
diff --git a/docs/fundamentals/sensitivity.md b/docs/fundamentals/sensitivity.md
index a686761..4516d96 100644
--- a/docs/fundamentals/sensitivity.md
+++ b/docs/fundamentals/sensitivity.md
@@ -32,6 +32,7 @@ in the comparison of sensitivity analysis methods.
 |                {ref}`Genz (Discontinuous) <test-functions:genz-discontinuous>`                 |        M        |  `GenzDiscontinuous()`  |
 |                           {ref}`Ishigami <test-functions:ishigami>`                            |        3        |      `Ishigami()`       |
 | {ref}`Linkletter et al. (2006) Decreasing Coefficients <test-functions:linkletter-dec-coeffs>` |       10        | `LinkletterDecCoeffs()` |
+|            {ref}`Linkletter et al. (2006) Inert <test-functions:linkletter-inert>`             |       10        |   `LinkletterInert()`   |
 |           {ref}`Linkletter et al. (2006) Linear <test-functions:linkletter-linear>`            |       10        |  `LinkletterLinear()`   |
 |             {ref}`Linkletter et al. (2006) Sine <test-functions:linkletter-sine>`              |       10        |   `LinkletterSine()`    |
 |                         {ref}`Moon (2010) 3D <test-functions:moon3d>`                          |        3        |       `Moon3D()`        |


Test patch:
diff --git a/docs/test-functions/available.md b/docs/test-functions/available.md
index 38938fc..c314a42 100644
--- a/docs/test-functions/available.md
+++ b/docs/test-functions/available.md
@@ -67,6 +67,7 @@ regardless of their typical applications.
 |             {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}`Linkletter et al. (2006) Decreasing Coefficients <test-functions:linkletter-dec-coeffs>` |       10        |     `LinkletterDecCoeffs()`     |
+|            {ref}`Linkletter et al. (2006) Inert <test-functions:linkletter-inert>`             |       10        |       `LinkletterInert()`       |
 |           {ref}`Linkletter et al. (2006) Linear <test-functions:linkletter-linear>`            |       10        |      `LinkletterLinear()`       |
 |             {ref}`Linkletter et al. (2006) Sine <test-functions:linkletter-sine>`              |       10        |       `LinkletterSine()`        |
 |                          {ref}`McLain S1 <test-functions:mclain-s1>`                           |        2        |          `McLainS1()`           |
diff --git a/docs/test-functions/linkletter-dec-coeffs.md b/docs/test-functions/linkletter-dec-coeffs.md
index d970149..ef27843 100644
--- a/docs/test-functions/linkletter-dec-coeffs.md
+++ b/docs/test-functions/linkletter-dec-coeffs.md
@@ -42,6 +42,8 @@ in the context of Gaussian process metamodeling:
 - {ref}`Sine <test-functions:linkletter-sine>` function features only two
   active input variables (out of 10); the effect of the two inputs on
   the output, however, is very different.
+- {ref}`Inert <test-functions:linkletter-inert>` function does not have any
+  active input variables; a constant zero is returned for any input values.
 ```
 
 
diff --git a/docs/test-functions/linkletter-inert.md b/docs/test-functions/linkletter-inert.md
new file mode 100644
index 0000000..59015e7
--- /dev/null
+++ b/docs/test-functions/linkletter-inert.md
@@ -0,0 +1,107 @@
+---
+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:linkletter-inert)=
+# Inert Function from Linkletter et al. (2006)
+
+```{code-cell} ipython3
+import numpy as np
+import matplotlib.pyplot as plt
+import uqtestfuns as uqtf
+```
+
+The function is a ten-dimensional, scalar-valued function.
+None of the input variables are active, while the rest is inert.
+The function was used in {cite}`Linkletter2006` to demonstrate a variable
+selection method (i.e., sensitivity analysis)
+in the context of Gaussian process metamodeling.
+
+```{note}
+Linkletter et al. {cite}`Linkletter2006` introduced four ten-dimensional
+analytical test functions with some of the input variables inert.
+They are used to demonstrate a variable selection method (i.e., screening)
+in the context of Gaussian process metamodeling:
+
+- {ref}`Linear <test-functions:linkletter-linear>` function features
+  a simple function with four active input variables (out of 10).
+- {ref}`Linear with decreasing coefficients <test-functions:linkletter-dec-coeffs>`
+  function features a slightly more complex linear function with eight active
+  input variables (out of 10).
+- {ref}`Sine <test-functions:linkletter-sine>` function features only two
+  active input variables (out of 10); the effect of the two inputs on
+  the output, however, is very different.
+- {ref}`Inert <test-functions:linkletter-inert>` function does not have any
+  active input variables; a constant zero is returned for any input values.
+  (_this function_)
+```
+
+## Test function instance
+
+To create a default instance of the test function:
+
+```{code-cell} ipython3
+my_testfun = uqtf.LinkletterSine()
+```
+
+Check if it has been correctly instantiated:
+
+```{code-cell} ipython3
+print(my_testfun)
+```
+
+## Description
+
+The test function is defined as[^location]:
+
+$$
+\mathcal{M}(\boldsymbol{x}) = 0,
+$$
+
+where $\boldsymbol{x} = \left( x_1, \ldots x_{10} \right)$
+is the ten-dimensional vector of input variables further defined below.
+Notice that none of the ten input variables are active.
+
+```{note}
+In the original paper, the function was added with an independent identically
+distributed (i.i.d) noise from $\mathcal{N}(0, \sigma)$
+with a standard deviation $\sigma = 0.05$. The response of this function
+is basically just a random noise.
+
+Furthermore, also in the original paper, a batch of data is generated from
+the function and then standardized to have mean $0.0$ and standard deviation
+$1.0$.
+
+The implementation of UQTestFuns does not include any error addition
+or standardization. However, these processes can be done manually
+after the data is generated.
+```
+
+## Probabilistic input
+
+The probabilistic input model for the test function is shown below.
+
+```{code-cell} ipython3
+:tags: [hide-input]
+
+print(my_testfun.prob_input)
+```
+
+## References
+
+```{bibliography}
+:style: unsrtalpha
+:filter: docname in docnames
+```
+
+[^location]: see Example 2, in {cite}`Linkletter2006`.
diff --git a/docs/test-functions/linkletter-linear.md b/docs/test-functions/linkletter-linear.md
index 638a637..0867813 100644
--- a/docs/test-functions/linkletter-linear.md
+++ b/docs/test-functions/linkletter-linear.md
@@ -42,6 +42,8 @@ in the context of Gaussian process metamodeling:
 - {ref}`Sine <test-functions:linkletter-sine>` function features only two
   active input variables (out of 10); the effect of the two inputs on
   the output, however, is very different.
+- {ref}`Inert <test-functions:linkletter-inert>` function does not have any
+  active input variables; a constant zero is returned for any input values.
 ```
 
 
diff --git a/docs/test-functions/linkletter-sine.md b/docs/test-functions/linkletter-sine.md
index ae31ac5..c85e754 100644
--- a/docs/test-functions/linkletter-sine.md
+++ b/docs/test-functions/linkletter-sine.md
@@ -41,6 +41,8 @@ in the context of Gaussian process metamodeling:
 - {ref}`Sine <test-functions:linkletter-sine>` function features only two
   active input variables (out of 10); the effect of the two inputs on
   the output, however, is very different. (_this function_).
+- {ref}`Inert <test-functions:linkletter-inert>` function does not have any
+  active input variables; a constant zero is returned for any input values.  
 ```
 
 Because the function is effectively two dimensional, the surface and contour
diff --git a/src/uqtestfuns/test_functions/__init__.py b/src/uqtestfuns/test_functions/__init__.py
index a139579..d484e27 100644
--- a/src/uqtestfuns/test_functions/__init__.py
+++ b/src/uqtestfuns/test_functions/__init__.py
@@ -35,7 +35,12 @@
 from .hyper_sphere import HyperSphere
 from .ishigami import Ishigami
 from .lim import LimPoly, LimNonPoly
-from .linkletter import LinkletterLinear, LinkletterDecCoeffs, LinkletterSine
+from .linkletter import (
+    LinkletterDecCoeffs,
+    LinkletterInert,
+    LinkletterLinear,
+    LinkletterSine,
+)
 from .oakley2002 import Oakley1D
 from .otl_circuit import OTLCircuit
 from .mclain import McLainS1, McLainS2, McLainS3, McLainS4, McLainS5
@@ -106,6 +111,7 @@
     "LimNonPoly",
     "LimPoly",
     "LinkletterDecCoeffs",
+    "LinkletterInert",
     "LinkletterLinear",
     "LinkletterSine",
     "Oakley1D",
diff --git a/src/uqtestfuns/test_functions/linkletter.py b/src/uqtestfuns/test_functions/linkletter.py
index 140e0b8..efc18c3 100644
--- a/src/uqtestfuns/test_functions/linkletter.py
+++ b/src/uqtestfuns/test_functions/linkletter.py
@@ -11,6 +11,7 @@
 - Linear function with four active input variables.
 - Linear function with decreasing coefficients, eight active input variables.
 - Sine function with two active input variables.
+- Inert function without any active input variables.
 
 References
 ----------
@@ -37,7 +38,12 @@
     for i in range(10)
 ]
 
-__all__ = ["LinkletterLinear", "LinkletterDecCoeffs", "LinkletterSine"]
+__all__ = [
+    "LinkletterLinear",
+    "LinkletterDecCoeffs",
+    "LinkletterInert",
+    "LinkletterSine",
+]
 
 
 def evaluate_linear(xx: np.ndarray) -> np.ndarray:
@@ -115,6 +121,30 @@ def evaluate_sine(xx: np.ndarray) -> np.ndarray:
     return yy
 
 
+def evaluate_inert(xx: np.ndarray) -> np.ndarray:
+    """Evaluate the inert function from Linkletter et al. (2006).
+
+    Parameters
+    ----------
+    xx : np.ndarray
+        M-Dimensional input values given by an N-by-10 array 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.
+
+    Notes
+    -----
+    - None of the input variables is active; the function always returns 0.
+    """
+    yy = np.zeros(xx.shape[0])
+
+    return yy
+
+
 class LinkletterLinear(UQTestFunFixDimABC):
     """A concrete implementation of the linear function."""
 
@@ -173,8 +203,8 @@ class LinkletterSine(UQTestFunFixDimABC):
         "Linkletter2006": {
             "function_id": "LinkletterSine",
             "description": (
-                "Input specification for the sine test function with Eq. (7)"
-                "from Linkletter et al. (2006)"
+                "Input specification for the sine test function Eq. (7) with "
+                "two active inputs from Linkletter et al. (2006)"
             ),
             "marginals": MARGINALS_LINKLETTER2006,
             "copulas": None,
@@ -183,3 +213,26 @@ class LinkletterSine(UQTestFunFixDimABC):
     _available_parameters = None
 
     evaluate = staticmethod(evaluate_sine)  # type: ignore
+
+
+class LinkletterInert(UQTestFunFixDimABC):
+    """A concrete implementation of the inert function."""
+
+    _tags = ["sensitivity"]
+    _description = (
+        "Inert function with 10 inactive inputs from Linkletter et al. (2006)"
+    )
+    _available_inputs: ProbInputSpecs = {
+        "Linkletter2006": {
+            "function_id": "LinkletterInert",
+            "description": (
+                "Input specification for the inert test function "
+                "from Linkletter et al. (2006)"
+            ),
+            "marginals": MARGINALS_LINKLETTER2006,
+            "copulas": None,
+        },
+    }
+    _available_parameters = None
+
+    evaluate = staticmethod(evaluate_inert)  # type: ignore