ado-trim 1.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ado_trim-1.6.0/PKG-INFO +65 -0
- ado_trim-1.6.0/README.md +53 -0
- ado_trim-1.6.0/ado_trim.egg-info/PKG-INFO +65 -0
- ado_trim-1.6.0/ado_trim.egg-info/SOURCES.txt +29 -0
- ado_trim-1.6.0/ado_trim.egg-info/dependency_links.txt +1 -0
- ado_trim-1.6.0/ado_trim.egg-info/entry_points.txt +2 -0
- ado_trim-1.6.0/ado_trim.egg-info/requires.txt +5 -0
- ado_trim-1.6.0/ado_trim.egg-info/top_level.txt +1 -0
- ado_trim-1.6.0/pyproject.toml +29 -0
- ado_trim-1.6.0/setup.cfg +4 -0
- ado_trim-1.6.0/trim/__init__.py +2 -0
- ado_trim-1.6.0/trim/no_priors_pydantic.py +72 -0
- ado_trim-1.6.0/trim/no_priors_sampler.py +132 -0
- ado_trim-1.6.0/trim/operator.py +189 -0
- ado_trim-1.6.0/trim/test/test_data_documentation.py +357 -0
- ado_trim-1.6.0/trim/test/test_high_dimensional_sampling.py +269 -0
- ado_trim-1.6.0/trim/test/test_rowsring.py +134 -0
- ado_trim-1.6.0/trim/test/test_sampling.py +56 -0
- ado_trim-1.6.0/trim/trim_pydantic.py +237 -0
- ado_trim-1.6.0/trim/trim_sampler.py +762 -0
- ado_trim-1.6.0/trim/utils/__init__.py +2 -0
- ado_trim-1.6.0/trim/utils/exceptions.py +14 -0
- ado_trim-1.6.0/trim/utils/high_dimensional_sampling.py +446 -0
- ado_trim-1.6.0/trim/utils/logging_utils.py +219 -0
- ado_trim-1.6.0/trim/utils/miscellaneous.py +15 -0
- ado_trim-1.6.0/trim/utils/one_dimensional_sampling.py +293 -0
- ado_trim-1.6.0/trim/utils/order.py +365 -0
- ado_trim-1.6.0/trim/utils/rowsring.py +104 -0
- ado_trim-1.6.0/trim/utils/space_df_connector.py +527 -0
- ado_trim-1.6.0/trim/utils/split_common_and_diff.py +65 -0
- ado_trim-1.6.0/trim/utils/stopping_criterion.py +46 -0
ado_trim-1.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ado-trim
|
|
3
|
+
Version: 1.6.0
|
|
4
|
+
Summary: TRIM (Transfer Refined Iterative Modeling) builds an accurate predictive model from a small dataset by iteratively sampling a Discovery Space.
|
|
5
|
+
Requires-Python: <3.14,>=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: ado-core
|
|
8
|
+
Requires-Dist: autogluon-tabular[catboost,xgboost]==1.5
|
|
9
|
+
Requires-Dist: numpy
|
|
10
|
+
Requires-Dist: pandas>=2.2.0
|
|
11
|
+
Requires-Dist: scikit-learn
|
|
12
|
+
|
|
13
|
+
# ADO TRIM Operator
|
|
14
|
+
|
|
15
|
+
`ado-trim` is an operator plugin for the
|
|
16
|
+
[Accelerated Discovery Orchestrator (ADO)](https://github.com/IBM/ado),
|
|
17
|
+
providing the Transfer Refined Iterative Modeling (TRIM) characterization
|
|
18
|
+
operator.
|
|
19
|
+
|
|
20
|
+
**TRIM** is designed to efficiently build a surrogate model of a complex system.
|
|
21
|
+
It is ideal for scenarios where exploring a parameter space is time-consuming or
|
|
22
|
+
expensive. TRIM intelligently samples just enough points to create a stable and
|
|
23
|
+
accurate predictive model, saving significant time and resources.
|
|
24
|
+
|
|
25
|
+
## How it Works
|
|
26
|
+
|
|
27
|
+
The `TRIM` operator works in two main phases:
|
|
28
|
+
|
|
29
|
+
1. **No-Priors Characterization**: If the system has not been measured before,
|
|
30
|
+
TRIM starts by sampling a small, representative set of points using a
|
|
31
|
+
space-filling algorithm to get a baseline understanding of the parameter
|
|
32
|
+
space.
|
|
33
|
+
|
|
34
|
+
2. **Iterative Modeling**: This phase begins by using all currently available
|
|
35
|
+
data to train a single preliminary surrogate model. The feature importance
|
|
36
|
+
from this model is used to order for all remaining unmeasured points. TRIM
|
|
37
|
+
then enters a loop where it:
|
|
38
|
+
- Samples the next point and adds it to the dataset.
|
|
39
|
+
- Trains a model on the gathered data.
|
|
40
|
+
- Evaluates the expected improvement of a model trained on a larger dataset
|
|
41
|
+
by comparing the new model's performance against that of previous models.
|
|
42
|
+
|
|
43
|
+
This loop continues until the improvement is below a threshold, at which point
|
|
44
|
+
TRIM automatically stops. Finally, it trains one high-quality model on all
|
|
45
|
+
collected data and saves it for your use. It also outputs a file containing the
|
|
46
|
+
measured values and predictions for all points in your space.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
You can install the `TRIM` operator and its dependencies (including `ado-core`)
|
|
51
|
+
directly from PyPI:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install ado-trim
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## More Information
|
|
58
|
+
|
|
59
|
+
To learn more about TRIM and explore the full capabilities of ADO, including
|
|
60
|
+
detailed documentation, configuration guides, and additional examples, visit the
|
|
61
|
+
official ADO website:
|
|
62
|
+
|
|
63
|
+
- **TRIM Quickstart**: <https://ibm.github.io/ado/examples/trim/>
|
|
64
|
+
- **Configuring TRIM**: <https://ibm.github.io/ado/operators/trim/>
|
|
65
|
+
- **ADO Documentation**: <https://ibm.github.io/ado/>
|
ado_trim-1.6.0/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# ADO TRIM Operator
|
|
2
|
+
|
|
3
|
+
`ado-trim` is an operator plugin for the
|
|
4
|
+
[Accelerated Discovery Orchestrator (ADO)](https://github.com/IBM/ado),
|
|
5
|
+
providing the Transfer Refined Iterative Modeling (TRIM) characterization
|
|
6
|
+
operator.
|
|
7
|
+
|
|
8
|
+
**TRIM** is designed to efficiently build a surrogate model of a complex system.
|
|
9
|
+
It is ideal for scenarios where exploring a parameter space is time-consuming or
|
|
10
|
+
expensive. TRIM intelligently samples just enough points to create a stable and
|
|
11
|
+
accurate predictive model, saving significant time and resources.
|
|
12
|
+
|
|
13
|
+
## How it Works
|
|
14
|
+
|
|
15
|
+
The `TRIM` operator works in two main phases:
|
|
16
|
+
|
|
17
|
+
1. **No-Priors Characterization**: If the system has not been measured before,
|
|
18
|
+
TRIM starts by sampling a small, representative set of points using a
|
|
19
|
+
space-filling algorithm to get a baseline understanding of the parameter
|
|
20
|
+
space.
|
|
21
|
+
|
|
22
|
+
2. **Iterative Modeling**: This phase begins by using all currently available
|
|
23
|
+
data to train a single preliminary surrogate model. The feature importance
|
|
24
|
+
from this model is used to order for all remaining unmeasured points. TRIM
|
|
25
|
+
then enters a loop where it:
|
|
26
|
+
- Samples the next point and adds it to the dataset.
|
|
27
|
+
- Trains a model on the gathered data.
|
|
28
|
+
- Evaluates the expected improvement of a model trained on a larger dataset
|
|
29
|
+
by comparing the new model's performance against that of previous models.
|
|
30
|
+
|
|
31
|
+
This loop continues until the improvement is below a threshold, at which point
|
|
32
|
+
TRIM automatically stops. Finally, it trains one high-quality model on all
|
|
33
|
+
collected data and saves it for your use. It also outputs a file containing the
|
|
34
|
+
measured values and predictions for all points in your space.
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
You can install the `TRIM` operator and its dependencies (including `ado-core`)
|
|
39
|
+
directly from PyPI:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install ado-trim
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## More Information
|
|
46
|
+
|
|
47
|
+
To learn more about TRIM and explore the full capabilities of ADO, including
|
|
48
|
+
detailed documentation, configuration guides, and additional examples, visit the
|
|
49
|
+
official ADO website:
|
|
50
|
+
|
|
51
|
+
- **TRIM Quickstart**: <https://ibm.github.io/ado/examples/trim/>
|
|
52
|
+
- **Configuring TRIM**: <https://ibm.github.io/ado/operators/trim/>
|
|
53
|
+
- **ADO Documentation**: <https://ibm.github.io/ado/>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ado-trim
|
|
3
|
+
Version: 1.6.0
|
|
4
|
+
Summary: TRIM (Transfer Refined Iterative Modeling) builds an accurate predictive model from a small dataset by iteratively sampling a Discovery Space.
|
|
5
|
+
Requires-Python: <3.14,>=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: ado-core
|
|
8
|
+
Requires-Dist: autogluon-tabular[catboost,xgboost]==1.5
|
|
9
|
+
Requires-Dist: numpy
|
|
10
|
+
Requires-Dist: pandas>=2.2.0
|
|
11
|
+
Requires-Dist: scikit-learn
|
|
12
|
+
|
|
13
|
+
# ADO TRIM Operator
|
|
14
|
+
|
|
15
|
+
`ado-trim` is an operator plugin for the
|
|
16
|
+
[Accelerated Discovery Orchestrator (ADO)](https://github.com/IBM/ado),
|
|
17
|
+
providing the Transfer Refined Iterative Modeling (TRIM) characterization
|
|
18
|
+
operator.
|
|
19
|
+
|
|
20
|
+
**TRIM** is designed to efficiently build a surrogate model of a complex system.
|
|
21
|
+
It is ideal for scenarios where exploring a parameter space is time-consuming or
|
|
22
|
+
expensive. TRIM intelligently samples just enough points to create a stable and
|
|
23
|
+
accurate predictive model, saving significant time and resources.
|
|
24
|
+
|
|
25
|
+
## How it Works
|
|
26
|
+
|
|
27
|
+
The `TRIM` operator works in two main phases:
|
|
28
|
+
|
|
29
|
+
1. **No-Priors Characterization**: If the system has not been measured before,
|
|
30
|
+
TRIM starts by sampling a small, representative set of points using a
|
|
31
|
+
space-filling algorithm to get a baseline understanding of the parameter
|
|
32
|
+
space.
|
|
33
|
+
|
|
34
|
+
2. **Iterative Modeling**: This phase begins by using all currently available
|
|
35
|
+
data to train a single preliminary surrogate model. The feature importance
|
|
36
|
+
from this model is used to order for all remaining unmeasured points. TRIM
|
|
37
|
+
then enters a loop where it:
|
|
38
|
+
- Samples the next point and adds it to the dataset.
|
|
39
|
+
- Trains a model on the gathered data.
|
|
40
|
+
- Evaluates the expected improvement of a model trained on a larger dataset
|
|
41
|
+
by comparing the new model's performance against that of previous models.
|
|
42
|
+
|
|
43
|
+
This loop continues until the improvement is below a threshold, at which point
|
|
44
|
+
TRIM automatically stops. Finally, it trains one high-quality model on all
|
|
45
|
+
collected data and saves it for your use. It also outputs a file containing the
|
|
46
|
+
measured values and predictions for all points in your space.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
You can install the `TRIM` operator and its dependencies (including `ado-core`)
|
|
51
|
+
directly from PyPI:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install ado-trim
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## More Information
|
|
58
|
+
|
|
59
|
+
To learn more about TRIM and explore the full capabilities of ADO, including
|
|
60
|
+
detailed documentation, configuration guides, and additional examples, visit the
|
|
61
|
+
official ADO website:
|
|
62
|
+
|
|
63
|
+
- **TRIM Quickstart**: <https://ibm.github.io/ado/examples/trim/>
|
|
64
|
+
- **Configuring TRIM**: <https://ibm.github.io/ado/operators/trim/>
|
|
65
|
+
- **ADO Documentation**: <https://ibm.github.io/ado/>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
ado_trim.egg-info/PKG-INFO
|
|
4
|
+
ado_trim.egg-info/SOURCES.txt
|
|
5
|
+
ado_trim.egg-info/dependency_links.txt
|
|
6
|
+
ado_trim.egg-info/entry_points.txt
|
|
7
|
+
ado_trim.egg-info/requires.txt
|
|
8
|
+
ado_trim.egg-info/top_level.txt
|
|
9
|
+
trim/__init__.py
|
|
10
|
+
trim/no_priors_pydantic.py
|
|
11
|
+
trim/no_priors_sampler.py
|
|
12
|
+
trim/operator.py
|
|
13
|
+
trim/trim_pydantic.py
|
|
14
|
+
trim/trim_sampler.py
|
|
15
|
+
trim/test/test_data_documentation.py
|
|
16
|
+
trim/test/test_high_dimensional_sampling.py
|
|
17
|
+
trim/test/test_rowsring.py
|
|
18
|
+
trim/test/test_sampling.py
|
|
19
|
+
trim/utils/__init__.py
|
|
20
|
+
trim/utils/exceptions.py
|
|
21
|
+
trim/utils/high_dimensional_sampling.py
|
|
22
|
+
trim/utils/logging_utils.py
|
|
23
|
+
trim/utils/miscellaneous.py
|
|
24
|
+
trim/utils/one_dimensional_sampling.py
|
|
25
|
+
trim/utils/order.py
|
|
26
|
+
trim/utils/rowsring.py
|
|
27
|
+
trim/utils/space_df_connector.py
|
|
28
|
+
trim/utils/split_common_and_diff.py
|
|
29
|
+
trim/utils/stopping_criterion.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
trim
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ado-trim"
|
|
3
|
+
description = "TRIM (Transfer Refined Iterative Modeling) builds an accurate predictive model from a small dataset by iteratively sampling a Discovery Space."
|
|
4
|
+
readme = "README.md"
|
|
5
|
+
requires-python = ">=3.10,<3.14"
|
|
6
|
+
dependencies = [
|
|
7
|
+
"ado-core",
|
|
8
|
+
"autogluon-tabular[catboost,xgboost]==1.5",
|
|
9
|
+
"numpy",
|
|
10
|
+
"pandas>=2.2.0",
|
|
11
|
+
"scikit-learn",
|
|
12
|
+
]
|
|
13
|
+
dynamic = ["version"]
|
|
14
|
+
|
|
15
|
+
[project.entry-points."ado.operators"]
|
|
16
|
+
trim = "trim.operator"
|
|
17
|
+
|
|
18
|
+
[build-system]
|
|
19
|
+
requires = ["setuptools", "setuptools_scm"]
|
|
20
|
+
build-backend = "setuptools.build_meta"
|
|
21
|
+
|
|
22
|
+
[tool.setuptools]
|
|
23
|
+
packages = ["trim"]
|
|
24
|
+
|
|
25
|
+
[tool.setuptools_scm]
|
|
26
|
+
root = "../../../"
|
|
27
|
+
|
|
28
|
+
[tool.uv.sources]
|
|
29
|
+
ado-core = { workspace = true }
|
ado_trim-1.6.0/setup.cfg
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Copyright IBM Corporation 2025, 2026
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
from typing import Annotated, Literal
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, BeforeValidator, Field
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class NoPriorsParameters(BaseModel):
|
|
10
|
+
"""
|
|
11
|
+
Parameters for sampling high-dimensional spaces without prior model structure.
|
|
12
|
+
|
|
13
|
+
The `sampling_strategy` must be one of the Literals supported.
|
|
14
|
+
Source of truth for supported strategies is the comment block right here:
|
|
15
|
+
|
|
16
|
+
strategy (str): sampling subroutine:
|
|
17
|
+
- 'random': selects random points from the beginning
|
|
18
|
+
- 'one_shift': refer to one_shift_then_random_points_high_dimensional_sampling
|
|
19
|
+
- 'recursive_aggregation': refer to recursive_aggregation_high_dimensional_sampling
|
|
20
|
+
- 'clhs': refer to concatenated_latin_hypercube_sampling
|
|
21
|
+
- 'sobol': sobol sampling
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
targetOutput: Annotated[
|
|
25
|
+
str,
|
|
26
|
+
Field(
|
|
27
|
+
description="The measured property you will treat as a target variable.",
|
|
28
|
+
),
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
samples: Annotated[
|
|
32
|
+
int,
|
|
33
|
+
Field(
|
|
34
|
+
ge=1,
|
|
35
|
+
description="Number of unique points to sample (must be >= 1).",
|
|
36
|
+
),
|
|
37
|
+
] = 20
|
|
38
|
+
|
|
39
|
+
batchSize: Annotated[
|
|
40
|
+
int,
|
|
41
|
+
Field(
|
|
42
|
+
ge=1,
|
|
43
|
+
description=(
|
|
44
|
+
"Batch size parameter used by certain samplers (e.g., randomWalk) via continuous batching; "
|
|
45
|
+
"by default set equal to iterationSize in those contexts. Must be >= 1."
|
|
46
|
+
),
|
|
47
|
+
),
|
|
48
|
+
] = 1
|
|
49
|
+
|
|
50
|
+
sampling_strategy: Annotated[
|
|
51
|
+
Literal["random", "one_shift", "recursive_aggregation", "clhs", "sobol"],
|
|
52
|
+
BeforeValidator(lambda s: s.lower()),
|
|
53
|
+
Field(
|
|
54
|
+
description=(
|
|
55
|
+
"Sampling subroutine. Supported values:\n"
|
|
56
|
+
" - 'random': selects random points from the beginning\n"
|
|
57
|
+
" - 'one_shift': see one_shift_then_random_points_high_dimensional_sampling\n"
|
|
58
|
+
" - 'recursive_aggregation': see recursive_aggregation_high_dimensional_sampling\n"
|
|
59
|
+
" - 'clhs': dimension-wise random without replacement until each dim cycles\n"
|
|
60
|
+
" - 'sobol': sobol sampling via scipy\n"
|
|
61
|
+
"Aliases: 'random_shifts' → 'recursive_aggregation'.\n"
|
|
62
|
+
"Validation is case-insensitive; value is normalized to lowercase."
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
] = "clhs"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if __name__ == "__main__":
|
|
69
|
+
params = NoPriorsParameters.model_validate(NoPriorsParameters(targetOutput="test"))
|
|
70
|
+
print(
|
|
71
|
+
f"type of model_validate output on no-priors-characterization default is {type(params)}, printing the full object gives {params}"
|
|
72
|
+
)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Copyright IBM Corporation 2025, 2026
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import logging
|
|
6
|
+
import typing
|
|
7
|
+
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
|
|
10
|
+
from orchestrator.core.discoveryspace.samplers import BaseSampler
|
|
11
|
+
from orchestrator.core.discoveryspace.space import DiscoverySpace, Entity
|
|
12
|
+
from orchestrator.modules.operators.discovery_space_manager import DiscoverySpaceManager
|
|
13
|
+
from trim.no_priors_pydantic import NoPriorsParameters
|
|
14
|
+
from trim.utils.order import order_df_for_sampling_with_no_priors
|
|
15
|
+
from trim.utils.space_df_connector import (
|
|
16
|
+
get_list_of_entities_from_df_and_space,
|
|
17
|
+
get_source_and_target,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
logger_no_priors = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# NOTE: to repeat the operation on the same space I can delete the operation if the output of this operation
|
|
24
|
+
# are not used by another operation
|
|
25
|
+
class NoPriorsSampleSelector(BaseSampler):
|
|
26
|
+
@classmethod
|
|
27
|
+
def samplerCompatibleWithDiscoverySpaceRemote(
|
|
28
|
+
cls, remoteDiscoverySpace: DiscoverySpaceManager # type: ignore[name-defined]
|
|
29
|
+
) -> bool:
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
async def remoteEntityIterator(
|
|
33
|
+
self, remoteDiscoverySpace: DiscoverySpaceManager, batchsize: int = 1
|
|
34
|
+
) -> typing.AsyncGenerator[list[Entity], None]:
|
|
35
|
+
"""
|
|
36
|
+
Generate entities for no-priors characterization sampling.
|
|
37
|
+
|
|
38
|
+
Orders the target space using a high-dimensional sampling strategy (e.g., CLHS, Sobol)
|
|
39
|
+
without relying on prior model knowledge or feature importance.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
remoteDiscoverySpace: Manager for the discovery space state
|
|
43
|
+
batchsize: Number of entities to yield per iteration
|
|
44
|
+
|
|
45
|
+
Yields:
|
|
46
|
+
List of Entity objects to be measured, in the determined order
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
async def iterator_closure(
|
|
50
|
+
stateHandle: DiscoverySpaceManager, # type: ignore[name-defined]
|
|
51
|
+
) -> typing.Callable[[], typing.AsyncGenerator[list[Entity], None]]:
|
|
52
|
+
|
|
53
|
+
logger_no_priors.info("Characterization with no-priors starts.\n")
|
|
54
|
+
logger_no_priors.info(f"PARAMETERS ARE:\n{self.params}\n\n")
|
|
55
|
+
|
|
56
|
+
discoverySpace = await stateHandle.discoverySpace.remote()
|
|
57
|
+
source_df, target_df = get_source_and_target(
|
|
58
|
+
discoverySpace, self.params.targetOutput
|
|
59
|
+
)
|
|
60
|
+
logger_no_priors.info(f"Target dataframe has length {len(target_df)}")
|
|
61
|
+
target_df = order_df_for_sampling_with_no_priors(
|
|
62
|
+
target_df,
|
|
63
|
+
[
|
|
64
|
+
cp.identifier
|
|
65
|
+
for cp in discoverySpace.entitySpace.constitutiveProperties
|
|
66
|
+
],
|
|
67
|
+
self.params.samples - len(source_df),
|
|
68
|
+
strategy=self.params.sampling_strategy,
|
|
69
|
+
)
|
|
70
|
+
list_of_entities_for_no_prior_characterization = (
|
|
71
|
+
get_list_of_entities_from_df_and_space(
|
|
72
|
+
df=target_df, space=discoverySpace
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
logger_no_priors.info(
|
|
77
|
+
"\n\nCharacterization with no-priors finished. Starting Iterative Modeling.\n"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
async def iterator() -> typing.AsyncGenerator[list[Entity], None]: # type: ignore[name-defined]
|
|
81
|
+
logger_no_priors.info(
|
|
82
|
+
"\n\nIteration over sorted entities for no priors characterization starts.\n"
|
|
83
|
+
)
|
|
84
|
+
await asyncio.sleep(0.1)
|
|
85
|
+
for i in range(
|
|
86
|
+
0, len(list_of_entities_for_no_prior_characterization), batchsize
|
|
87
|
+
):
|
|
88
|
+
entities = list_of_entities_for_no_prior_characterization[
|
|
89
|
+
i : i + batchsize
|
|
90
|
+
]
|
|
91
|
+
if len(entities) == 0:
|
|
92
|
+
logger_no_priors.info(
|
|
93
|
+
"\n\nCharacterization with no-priors finished.\n"
|
|
94
|
+
)
|
|
95
|
+
break
|
|
96
|
+
else:
|
|
97
|
+
yield entities
|
|
98
|
+
logger_no_priors.info("\n\nCharacterization with no-priors finished.\n")
|
|
99
|
+
|
|
100
|
+
return iterator
|
|
101
|
+
|
|
102
|
+
retval = await iterator_closure(remoteDiscoverySpace)
|
|
103
|
+
|
|
104
|
+
return retval()
|
|
105
|
+
|
|
106
|
+
def entityIterator(
|
|
107
|
+
self, discoverySpace: DiscoverySpace, batchsize: int = 1
|
|
108
|
+
) -> typing.Generator[list[Entity], None, None]:
|
|
109
|
+
"""Returns an remoteEntityIterator that returns entities in order"""
|
|
110
|
+
|
|
111
|
+
def iterator_closure(
|
|
112
|
+
space: DiscoverySpace,
|
|
113
|
+
) -> typing.Callable[[], typing.Generator[list[Entity], None, None]]:
|
|
114
|
+
|
|
115
|
+
# list_of_entities = list(...) # type: ignore[name-defined]
|
|
116
|
+
# numberEntities = len(list_of_entities)
|
|
117
|
+
|
|
118
|
+
def iterator() -> typing.Generator[list[Entity], None, None]: # type: ignore[name-defined]
|
|
119
|
+
raise NotImplementedError
|
|
120
|
+
# ...for i in range(0, numberEntities, batchsize):
|
|
121
|
+
|
|
122
|
+
return iterator
|
|
123
|
+
|
|
124
|
+
retval = iterator_closure(discoverySpace)
|
|
125
|
+
return retval()
|
|
126
|
+
|
|
127
|
+
@classmethod
|
|
128
|
+
def parameters_model(cls) -> type[BaseModel] | None:
|
|
129
|
+
return NoPriorsParameters
|
|
130
|
+
|
|
131
|
+
def __init__(self, parameters: NoPriorsParameters) -> None:
|
|
132
|
+
self.params = parameters
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Copyright IBM Corporation 2025, 2026
|
|
2
|
+
# SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
from orchestrator.core.discoveryspace.space import DiscoverySpace
|
|
8
|
+
from orchestrator.core.operation.config import FunctionOperationInfo
|
|
9
|
+
from orchestrator.core.operation.operation import OperationOutput
|
|
10
|
+
from orchestrator.modules.operators.collections import characterize_operation
|
|
11
|
+
from trim.trim_pydantic import (
|
|
12
|
+
TrimParameters,
|
|
13
|
+
) # Importing this way works when the package is installed
|
|
14
|
+
from trim.utils.logging_utils import (
|
|
15
|
+
log_and_save_characterization,
|
|
16
|
+
log_unable_to_proceed_with_iterative_modeling_and_raise_error,
|
|
17
|
+
)
|
|
18
|
+
from trim.utils.space_df_connector import get_source_and_target
|
|
19
|
+
|
|
20
|
+
logger_trim = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@characterize_operation(
|
|
24
|
+
name="trim",
|
|
25
|
+
configuration_model=TrimParameters,
|
|
26
|
+
configuration_model_default=TrimParameters.defaultOperationParameters(),
|
|
27
|
+
description="""
|
|
28
|
+
Trim is used to characterise a Discovery space.
|
|
29
|
+
In its first implementation it starts from a space,
|
|
30
|
+
Retrieves all measured entities from the entity source and samples the others following a certain order.
|
|
31
|
+
If the number of measured entity is too small, Trim instantiates a no-priors characterization operation.
|
|
32
|
+
""",
|
|
33
|
+
)
|
|
34
|
+
def trim(
|
|
35
|
+
discoverySpace: DiscoverySpace = None, # type: ignore[name-defined]
|
|
36
|
+
operationInfo: FunctionOperationInfo | None = None,
|
|
37
|
+
**kwargs: object,
|
|
38
|
+
) -> OperationOutput:
|
|
39
|
+
"""
|
|
40
|
+
Execute the TRIM (Transfer Refined Iterative Modeling) operation on a discovery space.
|
|
41
|
+
|
|
42
|
+
TRIM characterizes a discovery space by first ensuring sufficient measured entities exist,
|
|
43
|
+
then performing iterative modeling to sample additional entities in an informed order.
|
|
44
|
+
If insufficient data exists, it runs a no-priors characterization first.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
discoverySpace: The discovery space to characterize
|
|
48
|
+
operationInfo: Optional operation metadata
|
|
49
|
+
**kwargs: Additional parameters validated against TrimParameters model
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
OperationOutput containing the operation resources and metadata
|
|
53
|
+
"""
|
|
54
|
+
# Lazy import to avoid circular import issues during plugin loading
|
|
55
|
+
from orchestrator.modules.operators.randomwalk import (
|
|
56
|
+
CustomSamplerConfiguration,
|
|
57
|
+
RandomWalkParameters,
|
|
58
|
+
SamplerModuleConf,
|
|
59
|
+
random_walk,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
params = TrimParameters.model_validate(kwargs)
|
|
63
|
+
logger_trim.info(
|
|
64
|
+
"Transfer Refined Iterative Modeling starts."
|
|
65
|
+
f"Target variable = {params.targetOutput}"
|
|
66
|
+
)
|
|
67
|
+
logger_trim.info(f"Parameters are {params}")
|
|
68
|
+
|
|
69
|
+
nopriors_module = SamplerModuleConf(
|
|
70
|
+
moduleClass="NoPriorsSampleSelector", moduleName="trim.no_priors_sampler"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Checks if the source space has been already characterized appropriately
|
|
74
|
+
source_df, target_df = get_source_and_target(
|
|
75
|
+
discoverySpace, params.targetOutput, log_string="First query"
|
|
76
|
+
)
|
|
77
|
+
initial_source_space_size = len(source_df)
|
|
78
|
+
|
|
79
|
+
op_output_characterization_no_prior = OperationOutput.model_validate(
|
|
80
|
+
{
|
|
81
|
+
"metadata": {
|
|
82
|
+
"skipping operation": f"Prior source space characterization: {len(source_df)} sample. Minimal sample size: {params.samplingBudget.minPoints }"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if logger_trim.isEnabledFor(logging.DEBUG):
|
|
88
|
+
log_and_save_characterization(source_df, target_df)
|
|
89
|
+
|
|
90
|
+
if len(source_df) < params.samplingBudget.minPoints:
|
|
91
|
+
logger_trim.warning(
|
|
92
|
+
f"Only {len(source_df)} points in the source space.\n"
|
|
93
|
+
"Starting with no-prior characterization operation, "
|
|
94
|
+
f"it will sample {params.samplingBudget.minPoints - len(source_df)} points.\n"
|
|
95
|
+
f"Note: Trim sampler has been called with a minimum budget of {params.samplingBudget.minPoints} points."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
no_priors_params = params.noPriorParameters
|
|
99
|
+
no_priors_sampler_config = CustomSamplerConfiguration(
|
|
100
|
+
module=nopriors_module, parameters=no_priors_params
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
no_priors_rwparams = RandomWalkParameters(
|
|
104
|
+
samplerConfig=no_priors_sampler_config,
|
|
105
|
+
# here you set up the rw params
|
|
106
|
+
batchSize=no_priors_params.batchSize,
|
|
107
|
+
numberEntities=no_priors_params.samples,
|
|
108
|
+
singleMeasurement=True,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
op_output_characterization_no_prior = random_walk(
|
|
112
|
+
discoverySpace=discoverySpace,
|
|
113
|
+
operationInfo=FunctionOperationInfo.model_validate(
|
|
114
|
+
{
|
|
115
|
+
"metadata": {
|
|
116
|
+
"completed operation": "Characterization with no priors",
|
|
117
|
+
"summary of collected data": f"No-priors characterization produced {len(source_df)} samples with the required property {params.targetOutput}. Minimal sample size: {params.samplingBudget.minPoints }",
|
|
118
|
+
},
|
|
119
|
+
"actuatorConfigurationIdentifiers": operationInfo.actuatorConfigurationIdentifiers,
|
|
120
|
+
}
|
|
121
|
+
),
|
|
122
|
+
**no_priors_rwparams.model_dump(),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
source_df, target_df = get_source_and_target(
|
|
126
|
+
discoverySpace, params.targetOutput
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if logger_trim.isEnabledFor(logging.DEBUG):
|
|
130
|
+
logger_trim.debug(
|
|
131
|
+
"Saving updated source space after no-priors characterization"
|
|
132
|
+
)
|
|
133
|
+
log_and_save_characterization(source_df, target_df)
|
|
134
|
+
|
|
135
|
+
if len(source_df) < params.samplingBudget.minPoints:
|
|
136
|
+
log_unable_to_proceed_with_iterative_modeling_and_raise_error(
|
|
137
|
+
discoverySpace,
|
|
138
|
+
target_output=params.targetOutput,
|
|
139
|
+
additional_info=f"This was detected during the no-priors characterization phase: {params.samplingBudget.minPoints - len(source_df)} out of {params.samplingBudget.minPoints}.",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# TRIM Iterative Modeling
|
|
143
|
+
trim_module = SamplerModuleConf(
|
|
144
|
+
moduleClass="TrimSampleSelector", # this is the name of our custom sampler class -> which I guess is CustomSequentialSampleSelector
|
|
145
|
+
moduleName="trim.trim_sampler", ### If CustomSequentialSampleSelector is imported as "from trim.trim_sampler import TrimSampleSelector" then this is correct
|
|
146
|
+
)
|
|
147
|
+
trim_sampler_config = CustomSamplerConfiguration(
|
|
148
|
+
module=trim_module, parameters=params
|
|
149
|
+
)
|
|
150
|
+
numberEntities_iterative_modeling = (
|
|
151
|
+
len(source_df) - initial_source_space_size
|
|
152
|
+
if op_output_characterization_no_prior.operation
|
|
153
|
+
else params.samplingBudget.maxPoints
|
|
154
|
+
)
|
|
155
|
+
trim_rwparams = RandomWalkParameters(
|
|
156
|
+
samplerConfig=trim_sampler_config,
|
|
157
|
+
batchSize=1,
|
|
158
|
+
numberEntities=numberEntities_iterative_modeling,
|
|
159
|
+
singleMeasurement=True,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
op_output_iterative_modeling = random_walk(
|
|
163
|
+
discoverySpace=discoverySpace,
|
|
164
|
+
operationInfo=FunctionOperationInfo.model_validate(
|
|
165
|
+
{
|
|
166
|
+
"metadata": {"completed operation": "Iterative Modeling Operation"},
|
|
167
|
+
"actuatorConfigurationIdentifiers": operationInfo.actuatorConfigurationIdentifiers,
|
|
168
|
+
}
|
|
169
|
+
),
|
|
170
|
+
**trim_rwparams.model_dump(),
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
logger_trim.info(
|
|
174
|
+
f"op_output_iterative_modeling.operation = {op_output_iterative_modeling.operation} "
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
if op_output_characterization_no_prior.operation:
|
|
178
|
+
return OperationOutput(
|
|
179
|
+
other=[],
|
|
180
|
+
resources=[
|
|
181
|
+
op_output_characterization_no_prior.operation,
|
|
182
|
+
op_output_iterative_modeling.operation,
|
|
183
|
+
],
|
|
184
|
+
metadata={},
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return OperationOutput(
|
|
188
|
+
other=[], resources=[op_output_iterative_modeling.operation], metadata={}
|
|
189
|
+
)
|