rubberruler 0.1.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.
@@ -0,0 +1,10 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .rubberruler/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ .hypothesis/
8
+ .coverage
9
+ dist/
10
+ CLAUDE.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 The University of Fukuchiyama
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.5
2
+ Name: rubberruler
3
+ Version: 0.1.0
4
+ Summary: Decide with BBOB, MA-BBOB, or your own objective functions whether to compute features value-based or rank-based.
5
+ Project-URL: Repository, https://github.com/shuheitnk/rubberruler
6
+ Project-URL: Changelog, https://github.com/shuheitnk/rubberruler/blob/main/CHANGELOG.md
7
+ Author: Shuhei Tanaka
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: BBOB,MA-BBOB,algorithm selection,benchmarking,black-box optimization,exploratory landscape analysis,performance prediction
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Scientific/Engineering
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: cloudpickle>=3.0
23
+ Requires-Dist: ioh>=0.3.17
24
+ Requires-Dist: joblib>=1.6
25
+ Requires-Dist: matplotlib>=3.10
26
+ Requires-Dist: numpy>=1.24
27
+ Requires-Dist: pandas>=2.0
28
+ Requires-Dist: psutil>=7.2
29
+ Requires-Dist: pyarrow>=25.0
30
+ Requires-Dist: rich>=13.7
31
+ Requires-Dist: scipy>=1.10
32
+ Requires-Dist: threadpoolctl>=3.7
33
+ Description-Content-Type: text/markdown
34
+
35
+ # rubberruler
36
+
37
+ rubberruler tells you whether your algorithm-selection features should be computed value-based (from the objective values) or rank-based (from their ranks).
38
+
39
+ <img alt="R² of value-based and rank-based features: on the test instances value 0.41 and rank 0.30; on the transformed test instances value 0.26 and rank 0.31; a dashed line marks the R² without features, 0.13 and 0.14" src="https://raw.githubusercontent.com/shuheitnk/rubberruler/main/assets/rubber_ruler_test.png" width="560">
40
+
41
+ ## Installation
42
+
43
+ ```sh
44
+ pip install rubberruler
45
+ ```
46
+
47
+ rubberruler needs Python 3.11 or later.
48
+
49
+ ## Quickstart
50
+
51
+ ```sh
52
+ pip install rubberruler scikit-learn
53
+ curl -O https://raw.githubusercontent.com/shuheitnk/rubberruler/main/examples/example1.py
54
+ python example1.py
55
+ ```
56
+
57
+ The Quickstart is [example1.py](https://github.com/shuheitnk/rubberruler/blob/main/examples/example1.py), the first of the [examples](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md). It defines a portfolio of three SciPy optimizers, a feature extractor of four features, and a random forest, and ends with the test:
58
+
59
+ ```python
60
+ predictor = RandomForestRegressor(random_state=0)
61
+
62
+ result = rr.run_test(
63
+ portfolio,
64
+ simple_features,
65
+ predictor,
66
+ # Small settings for a first try.
67
+ # Without them, run_test takes about an hour on a 16-core PC.
68
+ dimension=2,
69
+ budget_per_dimension=100,
70
+ n_runs=5,
71
+ )
72
+ print(result)
73
+ ```
74
+
75
+ It takes about half a minute on 24 CPUs and prints the card:
76
+
77
+ ```text
78
+ Rubber Ruler Test: use RANK-based features
79
+ R^2 on the transformed test instances: rank 0.31 > value 0.26
80
+
81
+ R^2 on R^2 on
82
+ feature type test instances transformed test instances degradation
83
+ value 0.41 0.26 0.14
84
+ rank 0.30 0.31 -0.01
85
+ no features 0.13 0.14 -0.01
86
+
87
+ With value-based features, the predictor does not generalize to
88
+ strictly increasing transformations of the objective.
89
+
90
+ 3 algorithms, 2400 training instances, 240 test instances,
91
+ 240 transformed test instances
92
+ seed=42, suite=bbob, dimension=2 (default 10),
93
+ budget_per_dimension=100 (default 1000), n_runs=5 (default 31)
94
+ ```
95
+
96
+ The first line is the answer: the feature type with the larger R² on the transformed test instances. The degradation is the drop in R² from the test to the transformed test instances. The row "no features" is a reference: features that help the predictor score above it.
97
+
98
+ ## Use your own portfolio, feature extractor, and predictor
99
+
100
+ ```python
101
+ import numpy as np
102
+ from sklearn.ensemble import RandomForestRegressor
103
+
104
+ import rubberruler as rr
105
+
106
+
107
+ # An algorithm minimizes problem(x) until rubberruler ends the run at the budget.
108
+ def random_search(problem):
109
+ rng = np.random.default_rng(problem.seed)
110
+ while True:
111
+ problem(rng.uniform(problem.lower_bounds, problem.upper_bounds))
112
+
113
+
114
+ def local_search(problem):
115
+ rng = np.random.default_rng(problem.seed)
116
+ x = rng.uniform(problem.lower_bounds, problem.upper_bounds)
117
+ fx = problem(x)
118
+ while True:
119
+ step = rng.normal(0, 0.5, problem.dimension)
120
+ candidate = np.clip(x + step, problem.lower_bounds, problem.upper_bounds)
121
+ if (value := problem(candidate)) <= fx:
122
+ x, fx = candidate, value
123
+
124
+
125
+ # A feature extractor maps a sample X of shape (n, d) and its values y to features.
126
+ def my_features(X, y):
127
+ return {"mean": float(np.mean(y)), "spread": float(np.std(y))}
128
+
129
+
130
+ portfolio = {"random-search": random_search, "local-search": local_search}
131
+ predictor = RandomForestRegressor(random_state=0) # any regressor with fit and predict
132
+ result = rr.run_test(portfolio, my_features, predictor)
133
+ print(result)
134
+ ```
135
+
136
+ [examples/README.md](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md) connects ModularCMAES, ModDE, pymoo, pycma, Nevergrad, pflacco, DeepELA, and PyTorch.
137
+
138
+ ## Options
139
+
140
+ - [MA-BBOB](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#ma-bbob): `rr.run_test(..., suite="ma-bbob")`.
141
+ - [example2.py](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#example-2-your-own-objective-functions): your own objective functions, with `rr.run_test(..., instances=rr.objective_instances(objectives, split_seed=1))`.
142
+ - [Precomputed tables](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#precomputed-tables): `rr.run_test(..., performance=result.performance, features=result.features)`.
143
+ - [example3.py](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#example-3-augmentation-with-transformed-objectives): augmentation, with `rr.transform_objective`, which applies a random rubber ruler to any objective function.
144
+ - [example7.py](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#example-7-a-feature-free-model-in-pytorch): a feature-free model, with an extractor that returns the sample itself.
145
+ - [Parallel computation and memory](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#parallel-computation-and-memory): `rr.run_test(..., n_jobs=4)`.
146
+ - Settings: the defaults follow the paper (dimension 10, 50 x dimension sample points, a budget of 1000 x dimension evaluations, 31 runs, training instances 11-110 and test instances 1-10 on BBOB, and the same distribution of rubber rulers), except that the sample points are uniform random rather than a Latin hypercube and the test uses one seed rather than the paper's 11. Finished runs are cached in `cache_dir`, and `help(rr.run_test)` lists every setting.
147
+
148
+ ## How it works
149
+
150
+ rubberruler takes training and test instances from BBOB, from MA-BBOB (`suite="ma-bbob"`), or from your own objective functions (the suite `"objectives"`, given with `instances=rr.objective_instances(...)`), and makes a transformed test instance from each test instance by passing its objective through a random strictly increasing function, the rubber ruler. It runs every algorithm on every instance and measures its performance J, the probability that one of its runs beats a run of another algorithm, with a tie counting as half. For each feature type, the extractor receives uniform random points and their values (value) or the ranks of their values (rank), both min-max normalized to [0, 1], and the predictor fitted on the training instances is scored by R² on the test and the transformed test instances. The answer is the feature type with the larger R² on the transformed test instances; a tie selects rank. The row "no features" predicts the mean J of each algorithm on the training instances, so it shows how much of R² needs no features.
151
+
152
+ ## Citing
153
+
154
+ Please cite rubberruler with [CITATION.cff](https://github.com/shuheitnk/rubberruler/blob/main/CITATION.cff); "Cite this repository" on GitHub gives it in APA and BibTeX.
155
+
156
+ ## License
157
+
158
+ [MIT](https://github.com/shuheitnk/rubberruler/blob/main/LICENSE)
@@ -0,0 +1,124 @@
1
+ # rubberruler
2
+
3
+ rubberruler tells you whether your algorithm-selection features should be computed value-based (from the objective values) or rank-based (from their ranks).
4
+
5
+ <img alt="R² of value-based and rank-based features: on the test instances value 0.41 and rank 0.30; on the transformed test instances value 0.26 and rank 0.31; a dashed line marks the R² without features, 0.13 and 0.14" src="https://raw.githubusercontent.com/shuheitnk/rubberruler/main/assets/rubber_ruler_test.png" width="560">
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ pip install rubberruler
11
+ ```
12
+
13
+ rubberruler needs Python 3.11 or later.
14
+
15
+ ## Quickstart
16
+
17
+ ```sh
18
+ pip install rubberruler scikit-learn
19
+ curl -O https://raw.githubusercontent.com/shuheitnk/rubberruler/main/examples/example1.py
20
+ python example1.py
21
+ ```
22
+
23
+ The Quickstart is [example1.py](https://github.com/shuheitnk/rubberruler/blob/main/examples/example1.py), the first of the [examples](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md). It defines a portfolio of three SciPy optimizers, a feature extractor of four features, and a random forest, and ends with the test:
24
+
25
+ ```python
26
+ predictor = RandomForestRegressor(random_state=0)
27
+
28
+ result = rr.run_test(
29
+ portfolio,
30
+ simple_features,
31
+ predictor,
32
+ # Small settings for a first try.
33
+ # Without them, run_test takes about an hour on a 16-core PC.
34
+ dimension=2,
35
+ budget_per_dimension=100,
36
+ n_runs=5,
37
+ )
38
+ print(result)
39
+ ```
40
+
41
+ It takes about half a minute on 24 CPUs and prints the card:
42
+
43
+ ```text
44
+ Rubber Ruler Test: use RANK-based features
45
+ R^2 on the transformed test instances: rank 0.31 > value 0.26
46
+
47
+ R^2 on R^2 on
48
+ feature type test instances transformed test instances degradation
49
+ value 0.41 0.26 0.14
50
+ rank 0.30 0.31 -0.01
51
+ no features 0.13 0.14 -0.01
52
+
53
+ With value-based features, the predictor does not generalize to
54
+ strictly increasing transformations of the objective.
55
+
56
+ 3 algorithms, 2400 training instances, 240 test instances,
57
+ 240 transformed test instances
58
+ seed=42, suite=bbob, dimension=2 (default 10),
59
+ budget_per_dimension=100 (default 1000), n_runs=5 (default 31)
60
+ ```
61
+
62
+ The first line is the answer: the feature type with the larger R² on the transformed test instances. The degradation is the drop in R² from the test to the transformed test instances. The row "no features" is a reference: features that help the predictor score above it.
63
+
64
+ ## Use your own portfolio, feature extractor, and predictor
65
+
66
+ ```python
67
+ import numpy as np
68
+ from sklearn.ensemble import RandomForestRegressor
69
+
70
+ import rubberruler as rr
71
+
72
+
73
+ # An algorithm minimizes problem(x) until rubberruler ends the run at the budget.
74
+ def random_search(problem):
75
+ rng = np.random.default_rng(problem.seed)
76
+ while True:
77
+ problem(rng.uniform(problem.lower_bounds, problem.upper_bounds))
78
+
79
+
80
+ def local_search(problem):
81
+ rng = np.random.default_rng(problem.seed)
82
+ x = rng.uniform(problem.lower_bounds, problem.upper_bounds)
83
+ fx = problem(x)
84
+ while True:
85
+ step = rng.normal(0, 0.5, problem.dimension)
86
+ candidate = np.clip(x + step, problem.lower_bounds, problem.upper_bounds)
87
+ if (value := problem(candidate)) <= fx:
88
+ x, fx = candidate, value
89
+
90
+
91
+ # A feature extractor maps a sample X of shape (n, d) and its values y to features.
92
+ def my_features(X, y):
93
+ return {"mean": float(np.mean(y)), "spread": float(np.std(y))}
94
+
95
+
96
+ portfolio = {"random-search": random_search, "local-search": local_search}
97
+ predictor = RandomForestRegressor(random_state=0) # any regressor with fit and predict
98
+ result = rr.run_test(portfolio, my_features, predictor)
99
+ print(result)
100
+ ```
101
+
102
+ [examples/README.md](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md) connects ModularCMAES, ModDE, pymoo, pycma, Nevergrad, pflacco, DeepELA, and PyTorch.
103
+
104
+ ## Options
105
+
106
+ - [MA-BBOB](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#ma-bbob): `rr.run_test(..., suite="ma-bbob")`.
107
+ - [example2.py](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#example-2-your-own-objective-functions): your own objective functions, with `rr.run_test(..., instances=rr.objective_instances(objectives, split_seed=1))`.
108
+ - [Precomputed tables](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#precomputed-tables): `rr.run_test(..., performance=result.performance, features=result.features)`.
109
+ - [example3.py](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#example-3-augmentation-with-transformed-objectives): augmentation, with `rr.transform_objective`, which applies a random rubber ruler to any objective function.
110
+ - [example7.py](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#example-7-a-feature-free-model-in-pytorch): a feature-free model, with an extractor that returns the sample itself.
111
+ - [Parallel computation and memory](https://github.com/shuheitnk/rubberruler/blob/main/examples/README.md#parallel-computation-and-memory): `rr.run_test(..., n_jobs=4)`.
112
+ - Settings: the defaults follow the paper (dimension 10, 50 x dimension sample points, a budget of 1000 x dimension evaluations, 31 runs, training instances 11-110 and test instances 1-10 on BBOB, and the same distribution of rubber rulers), except that the sample points are uniform random rather than a Latin hypercube and the test uses one seed rather than the paper's 11. Finished runs are cached in `cache_dir`, and `help(rr.run_test)` lists every setting.
113
+
114
+ ## How it works
115
+
116
+ rubberruler takes training and test instances from BBOB, from MA-BBOB (`suite="ma-bbob"`), or from your own objective functions (the suite `"objectives"`, given with `instances=rr.objective_instances(...)`), and makes a transformed test instance from each test instance by passing its objective through a random strictly increasing function, the rubber ruler. It runs every algorithm on every instance and measures its performance J, the probability that one of its runs beats a run of another algorithm, with a tie counting as half. For each feature type, the extractor receives uniform random points and their values (value) or the ranks of their values (rank), both min-max normalized to [0, 1], and the predictor fitted on the training instances is scored by R² on the test and the transformed test instances. The answer is the feature type with the larger R² on the transformed test instances; a tie selects rank. The row "no features" predicts the mean J of each algorithm on the training instances, so it shows how much of R² needs no features.
117
+
118
+ ## Citing
119
+
120
+ Please cite rubberruler with [CITATION.cff](https://github.com/shuheitnk/rubberruler/blob/main/CITATION.cff); "Cite this repository" on GitHub gives it in APA and BibTeX.
121
+
122
+ ## License
123
+
124
+ [MIT](https://github.com/shuheitnk/rubberruler/blob/main/LICENSE)
@@ -0,0 +1,112 @@
1
+ [project]
2
+ name = "rubberruler"
3
+ version = "0.1.0"
4
+ description = "Decide with BBOB, MA-BBOB, or your own objective functions whether to compute features value-based or rank-based."
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Shuhei Tanaka" }]
10
+ keywords = [
11
+ "algorithm selection",
12
+ "black-box optimization",
13
+ "BBOB",
14
+ "MA-BBOB",
15
+ "exploratory landscape analysis",
16
+ "performance prediction",
17
+ "benchmarking",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 3 - Alpha",
21
+ "Intended Audience :: Science/Research",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Topic :: Scientific/Engineering",
29
+ "Typing :: Typed",
30
+ ]
31
+ dependencies = [
32
+ "numpy>=1.24",
33
+ "scipy>=1.10",
34
+ "pandas>=2.0",
35
+ "pyarrow>=25.0",
36
+ "ioh>=0.3.17",
37
+ "joblib>=1.6",
38
+ "cloudpickle>=3.0",
39
+ "threadpoolctl>=3.7",
40
+ "rich>=13.7",
41
+ "matplotlib>=3.10",
42
+ "psutil>=7.2",
43
+ ]
44
+
45
+ [project.urls]
46
+ Repository = "https://github.com/shuheitnk/rubberruler"
47
+ Changelog = "https://github.com/shuheitnk/rubberruler/blob/main/CHANGELOG.md"
48
+
49
+ [dependency-groups]
50
+ dev = [
51
+ "pytest",
52
+ "hypothesis",
53
+ "ruff",
54
+ "pyright",
55
+ "pandas-stubs",
56
+ "scikit-learn>=1.2",
57
+ ]
58
+ examples = [
59
+ "pymoo==0.6.2",
60
+ ]
61
+
62
+ # uv sync and uv run install the libraries of the examples too, so the tests run them.
63
+ [tool.uv]
64
+ default-groups = ["dev", "examples"]
65
+
66
+ [build-system]
67
+ requires = ["hatchling"]
68
+ build-backend = "hatchling.build"
69
+
70
+ # The sdist has what it takes to build the wheel, and nothing for development.
71
+ [tool.hatch.build.targets.sdist]
72
+ include = ["/src/rubberruler", "/README.md", "/LICENSE", "/pyproject.toml"]
73
+
74
+ [tool.ruff.lint]
75
+ select = ["E", "F", "I", "UP", "B", "NPY", "PD", "RUF"]
76
+
77
+ [tool.pyright]
78
+ include = ["src", "tests", "examples"]
79
+ exclude = ["tests/typing/fail"]
80
+ strict = [
81
+ "src/rubberruler/__init__.py",
82
+ "src/rubberruler/_errors.py",
83
+ "src/rubberruler/_seeding.py",
84
+ "src/rubberruler/_problem.py",
85
+ "src/rubberruler/_instances.py",
86
+ "src/rubberruler/_objective.py",
87
+ "src/rubberruler/_performance.py",
88
+ "src/rubberruler/_features.py",
89
+ "src/rubberruler/_prediction.py",
90
+ "src/rubberruler/_card.py",
91
+ "src/rubberruler/_run_test.py",
92
+ ]
93
+ typeCheckingMode = "standard"
94
+ pythonVersion = "3.11"
95
+ # The examples are for users to copy, so they carry no comments for the tools.
96
+ # Some import libraries that are not installed here (pflacco, ModularCMAES, ModDE,
97
+ # DeepELA, PyTorch), and example1.py passes seed= to differential_evolution, which
98
+ # SciPy 1.10 needs and which SciPy 1.15 and later leave out of the types.
99
+ executionEnvironments = [
100
+ { root = "examples", reportMissingImports = false, reportCallIssue = false },
101
+ ]
102
+
103
+ [tool.pytest.ini_options]
104
+ testpaths = ["tests"]
105
+ pythonpath = ["tests"]
106
+ minversion = "9.0"
107
+ addopts = ["--import-mode=importlib", "-ra", "--strict-markers", "--strict-config"]
108
+ xfail_strict = true
109
+ markers = [
110
+ "slow: runs the README tutorial for real (about 20 seconds) and waits out the 60-second limit of the pre-check; pytest -m 'not slow' skips them, and CI runs them",
111
+ "locked: needs the versions in uv.lock (the README card, pyright); the pflacco environment skips it",
112
+ ]
@@ -0,0 +1,29 @@
1
+ """Decide with BBOB, MA-BBOB, or your own objective functions whether to compute
2
+ features value-based or rank-based.
3
+
4
+ Stretch the ruler. Keep the features that still measure.
5
+ """
6
+
7
+ from rubberruler._errors import RubberRulerError
8
+ from rubberruler._features import compute_features
9
+ from rubberruler._instances import bbob_instances, ma_bbob_instances, transform
10
+ from rubberruler._objective import objective_instances, transform_objective
11
+ from rubberruler._performance import measure_performance
12
+ from rubberruler._prediction import fit_predictor, r2_score
13
+ from rubberruler._problem import Problem
14
+ from rubberruler._run_test import run_test
15
+
16
+ __all__ = [
17
+ "Problem",
18
+ "RubberRulerError",
19
+ "bbob_instances",
20
+ "compute_features",
21
+ "fit_predictor",
22
+ "ma_bbob_instances",
23
+ "measure_performance",
24
+ "objective_instances",
25
+ "r2_score",
26
+ "run_test",
27
+ "transform",
28
+ "transform_objective",
29
+ ]