Skip to content

Commit

Permalink
Merge pull request #371 from damar-wicaksono/dev-363
Browse files Browse the repository at this point in the history
function_id and input_id are now properties of ProbInput
  • Loading branch information
damar-wicaksono authored Nov 7, 2024
2 parents f0ed430 + e311390 commit 5c815fb
Show file tree
Hide file tree
Showing 47 changed files with 1,403 additions and 1,563 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `function_id` and `input_id` are now property of `ProbInput`.
- `output_dimension` is now property of `UQTestFunBareABC` and inherited to
all concrete classes of UQ test functions.
- Printing a test function instance now shows whether the function is
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,11 @@ The probabilistic input specification of this test function is built-in:

```python-repl
>>> print(my_testfun.prob_input)
Name : Borehole-Harper-1983
Function ID : Borehole
Input ID : Harper1983
Input Dimension : 8
Description : Probabilistic input model of the Borehole model from
Harper and Gupta (1983).
Harper and Gupta (1983)
Marginals :
No. Name Distribution Parameters Description
Expand Down
27 changes: 0 additions & 27 deletions docs/api/input-spec.rst

This file was deleted.

4 changes: 0 additions & 4 deletions docs/api/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ let's start from the top, the {ref}`built-in test functions <test-functions:avai
- An instance of the ``Marginal`` class has a (parametric) probability
distribution. Although different instances may have different
probability distributions, they are all instances of the same class.
- As lightweight containers to specify the specifications of a ``ProbInput``
and a ``Marginal``, {ref}`three custom <api_reference_input_spec>` ``NamedTuple``
are defined, namely {ref}`api_reference_input_spec_univdist`,
{ref}`api_reference_input_spec_fixdim`, and {ref}`api_reference_input_spec_vardim`.

```{note}
To facilitate the creation of a custom UQ test function
Expand Down
101 changes: 54 additions & 47 deletions docs/development/adding-test-function-implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ Here are the few things we usually use:
```python
import numpy as np

from ..core.uqtestfun_abc import UQTestFunABC
from ..core.prob_input.input_spec import UnivDistSpec, ProbInputSpecFixDim
from uqtestfuns.core.custom_typing import ProbInputSpecs, FunParamSpecs
from uqtestfuns.core.uqtestfun_abc import UQTestFunABC

__all__ = ["Branin"]
```
Expand All @@ -120,16 +120,11 @@ Here are some explanations:
- NumPy is usually a must, especially for implementing the evaluation function.
- All built-in test functions are concrete implementations of the abstract base
class `UQTestFunABC`.
- The specification for a probabilistic input model is stored in `UnivDistSpec`
(the one-dimensional marginal specification) and `ProbInputSpecFixDim`
(the probabilistic input model). These are lightweight _containers_
(meaning no custom methods) of all the information required to construct,
later on, `Marginal` and `ProbInput` instances, respectively.

```{note}
There is also the corresponding `ProbInputSpecVarDim` to store the information
required to construct probabilistic input model with variable dimension.
```
- To assist specifying the data for probabilistic input model the custom type
`ProbInputSpecs` can be used; these are supposed to help you specifying
all the required data via the typechecker.
- Similarly, the custom type `FunParamSpecs` is used for specifying the
function parameters.

### Implementing a concrete evaluation function

Expand Down Expand Up @@ -181,36 +176,36 @@ include the parameters.

The specification of the probabilistic model is stored in a module-level
dictionary. While you're free to name the dictionary anything you like,
the convention is `AVAILABLE_INPUT_SPECS`.
the convention is `AVAILABLE_INPUTS`.
We define the variable as follows:

```python
AVAILABLE_INPUT_SPECS = {
"Dixon1978": ProbInputSpecFixDim(
name="Branin-Dixon-2008",
description=(
AVAILABLE_INPUT_SPECS: ProbInputSpecs = {
"Dixon1978": {
"name": "Branin",
"description": (
"Search domain for the Branin function from Dixon and Szegö (1978)."
),
marginals=[
UnivDistSpec(
name="x1",
distribution="uniform",
parameters=[-5, 10],
description="None",
),
UnivDistSpec(
name="x2",
distribution="uniform",
parameters=[0.0, 15.0],
description="None",
)
"marginals": [
{
"name": "x1",
"distribution": "uniform",
"parameters": [-5, 10],
"description": None,
},
{
"name": "x2",
"distribution": "uniform",
"parameters": [0.0, 15.0],
"description": None,
},
],
copulas=None,
),
"copulas": None,
},
}
```

Each key-value pair of this dictionary contains a complete specification
Each key-value pair of this dictionary contains the specification
to create an input model as an instance of the `ProbInput` class.
For this particular example, we only have one input specification available.
If there were more, we would add them here in the dictionary each with a unique keyword.
Expand All @@ -219,8 +214,8 @@ If there were more, we would add them here in the dictionary each with a unique
The keyword is, by convention, the citation key of the particular reference as listed in the BibTeX file.
```

Also notice that in the code above, we store the specifications of the marginals
in a list of {ref}`api_reference_input_spec_univdist`.
Also notice that in the code above, we store the specifications of
the marginals in a list of marginal specifications.
Each element of this list is used to create an instance of `Marginal`.

With that, we have completed the input specification of the Branin function.
Expand All @@ -232,7 +227,7 @@ dictionary that stores the parameter sets.
Conventionally, we name this variable `AVAILABLE_PARAMETERS`:

```python
AVAILABLE_PARAMETERS = {
AVAILABLE_PARAMETERS: FunParamSpecs = {
"Dixon1978": {
"function_id": "Branin",
"description": "Parameter set for the Branin function from Dixon (1978)",
Expand Down Expand Up @@ -301,9 +296,9 @@ class Branin(UQTestFunABC):

_tags = ["optimization"] # Application tags
_description = "Branin function from Dixon and Szegö (1978)" # Short description
_available_inputs = AVAILABLE_INPUT_SPECS # As defined above
_available_parameters = AVAILABLE_PARAMETERS # As defined above
_default_input_dimension = 2 # input dimension of the function
_available_inputs = AVAILABLE_INPUTS # As defined above
_available_parameters = AVAILABLE_PARAMETERS # As defined above
_default_input_dimension = 2 # input dimension of the function
_default_input = "Dixon1978" # Optional, if only one input is available
_default_parameters = "Dixon1978" # Optional, if only one set of parameters is available

Expand All @@ -313,7 +308,6 @@ class Branin(UQTestFunABC):
There is no need to define an `__init__()` method.
We will use the default `__init__()` from the base class.


Notice the two last class properties: `_default_input` and `_default_parameters`.
In case of only one input specification (resp. set of parameters) is available,
these properties are optional.
Expand Down Expand Up @@ -346,13 +340,26 @@ built-in functions from a Python terminal.
```python
>>> import uqtestfuns as uqtf
>>> uqtf.list_functions()
No. Constructor Input Dim. Parameterized Application Description
----- ----------------------------- ------------ --------------- -------------------------------------- ----------------------------------------------------------------------------
1 Ackley() M True optimization, metamodeling Optimization test function from Ackley (1987)
2 Alemazkoor20D() 20 False metamodeling High-dimensional low-degree polynomial from Alemazkoor & Meidani (2018)
3 Alemazkoor2D() 2 False metamodeling Low-dimensional high-degree polynomial from Alemazkoor & Meidani (2018)
4 Borehole() 8 False metamodeling, sensitivity Borehole function from Harper and Gupta (1983)
5 Branin() 2 True optimization Branin function from Dixon and Szegö (1978)
+-------+-------------------------------+-----------+------------+----------+---------------+--------------------------------+
| No. | Constructor | # Input | # Output | Param. | Application | Description |
+=======+===============================+===========+============+==========+===============+================================+
| 1 | Ackley() | M | 1 | True | optimization, | Optimization test function |
| | | | | | metamodeling | from Ackley (1987) |
+-------+-------------------------------+-----------+------------+----------+---------------+--------------------------------+
| 2 | Alemazkoor20D() | 20 | 1 | False | metamodeling | High-dimensional low-degree |
| | | | | | | polynomial from Alemazkoor & |
| | | | | | | Meidani (2018) |
+-------+-------------------------------+-----------+------------+----------+---------------+--------------------------------+
| 3 | Alemazkoor2D() | 2 | 1 | False | metamodeling | Low-dimensional high-degree |
| | | | | | | polynomial from Alemazkoor & |
| | | | | | | Meidani (2018) |
+-------+-------------------------------+-----------+------------+----------+---------------+--------------------------------+
| 4 | Borehole() | 8 | 1 | False | metamodeling, | Borehole function from Harper |
| | | | | | sensitivity | and Gupta (1983) |
+-------+-------------------------------+-----------+------------+----------+---------------+--------------------------------+
| 5 | Branin() | 2 | 1 | False | optimization | Branin function from Dixon |
| | | | | | | and Szegö (1978) |
+-------+-------------------------------+-----------+------------+----------+---------------+--------------------------------+
...
```

Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ install_requires =
scipy>=1.7.3
tabulate>=0.8.10
importlib-metadata>=1.0; python_version < "3.8"
typing_extensions; python_version > "3.7"

[options.packages.find]
where = src
Expand Down
73 changes: 73 additions & 0 deletions src/uqtestfuns/core/custom_typing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
Core module that contains custom types used in UQTestFuns.
Custom types are used to assist type checker during the code development.
"""

from typing import List, Union, Optional, Any, Dict, Sequence
from typing_extensions import TypedDict

from uqtestfuns.core.prob_input.marginal import Marginal

__all__ = [
"MarginalSpecs",
"ProbInputSpecs",
"ProbInputArgs",
"FunParamSpecs",
"FunParamsArgs",
"DeclaredParameters",
]


class MarginalSpec(TypedDict):
name: str
distribution: str
parameters: List[Union[float, int]]
description: Optional[str]


MarginalSpecs = List[MarginalSpec]


class ProbInputSpec(TypedDict):
function_id: str
description: str
marginals: List[MarginalSpec]
copulas: Optional[Any]


ProbInputSpecs = Dict[str, ProbInputSpec]


class ProbInputArgs(TypedDict):
function_id: str
input_id: str
description: str
marginals: Sequence[Marginal]
copulas: Optional[Any]


class DeclaredParameter(TypedDict):
keyword: str
value: Any
type: Optional[type]
description: Optional[str]


DeclaredParameters = List[DeclaredParameter]


class FunParamsSpec(TypedDict):
function_id: str
description: str
declared_parameters: DeclaredParameters


FunParamSpecs = Dict[str, FunParamsSpec]


class FunParamsArgs(TypedDict):
function_id: str
parameter_id: str
description: str
declared_parameters: DeclaredParameters
5 changes: 3 additions & 2 deletions src/uqtestfuns/core/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import numpy as np

from uqtestfuns.core.custom_typing import DeclaredParameters

FIELD_NAMES = ["Keyword", "Value", "Type", "Description"]

Expand Down Expand Up @@ -44,7 +45,7 @@ def __init__(
function_id: str = "",
parameter_id: str = "",
description: str = "",
declared_parameters: Optional[List[dict]] = None,
declared_parameters: Optional[DeclaredParameters] = None,
):
self._declared_parameters: dict = {}
self._dict: dict = {}
Expand Down Expand Up @@ -166,7 +167,7 @@ def add(
keyword: str,
value: Any,
type: Optional[type] = None,
description: str = "",
description: Optional[str] = "",
) -> None:
"""Add a parameter to the parameter set.
Expand Down
Loading

0 comments on commit 5c815fb

Please sign in to comment.