mattergraph-benchmarks 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,48 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ dist/
7
+ build/
8
+ .venv/
9
+ venv/
10
+ .mypy_cache/
11
+ .ruff_cache/
12
+ .pytest_cache/
13
+ .hypothesis/
14
+ .coverage
15
+ coverage.xml
16
+ htmlcov/
17
+
18
+ # Docs build output
19
+ site/
20
+
21
+ # Env
22
+ .env
23
+ .env.local
24
+ *.local
25
+
26
+ # Node
27
+ node_modules/
28
+ apps/web/dist/
29
+ apps/web/playwright-report/
30
+ apps/web/test-results/
31
+ *.tsbuildinfo
32
+ .next/
33
+ out/
34
+
35
+ # IDE
36
+ .idea/
37
+ .vscode/
38
+ *.swp
39
+
40
+ # OS
41
+ .DS_Store
42
+
43
+ # Data artifacts (keep demo/ tracked)
44
+ data/cache/
45
+ *.sqlite3
46
+
47
+ .claude
48
+ apps/private-platform-ui/
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: mattergraph-benchmarks
3
+ Version: 0.1.0
4
+ Summary: Benchmark adapters and evaluation utilities for MatterGraph.
5
+ Project-URL: Homepage, https://github.com/cyrusmo/MatterGraph
6
+ Project-URL: Repository, https://github.com/cyrusmo/MatterGraph
7
+ Project-URL: Issues, https://github.com/cyrusmo/MatterGraph/issues
8
+ Project-URL: Changelog, https://github.com/cyrusmo/MatterGraph/blob/main/CHANGELOG.md
9
+ Author: MatterGraph contributors
10
+ License-Expression: Apache-2.0
11
+ Keywords: benchmarks,machine-learning,matbench,materials-science,uncertainty
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
20
+ Classifier: Topic :: Scientific/Engineering :: Physics
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: httpx
23
+ Requires-Dist: mattergraph-core~=0.1.0
24
+ Requires-Dist: numpy>=1.24
25
+ Requires-Dist: pandas>=2.0
26
+ Requires-Dist: pymatgen>=2024.1.1
27
+ Requires-Dist: scikit-learn>=1.3
28
+ Description-Content-Type: text/markdown
29
+
30
+ # mattergraph-benchmarks
31
+
32
+ Benchmark adapters and evaluation utilities for [MatterGraph](https://github.com/cyrusmo/MatterGraph).
33
+
34
+ ## What's in here
35
+
36
+ - **Discovery metrics** — ranking-quality measures (nDCG and friends) for screening workflows, where what matters is whether good candidates surface near the top.
37
+ - **Uncertainty** — `coverage_at_target` for checking whether predicted intervals are calibrated.
38
+ - **Validation splits** — stratified splitting helpers that respect composition and structure grouping.
39
+ - **Matbench adapter** — optional bridge to [Matbench](https://matbench.materialsproject.org/) tasks. Install `matbench` separately to enable it.
40
+
41
+ ## Install
42
+
43
+ ```bash
44
+ pip install mattergraph-benchmarks
45
+ ```
46
+
47
+ ## License
48
+
49
+ Apache-2.0
@@ -0,0 +1,20 @@
1
+ # mattergraph-benchmarks
2
+
3
+ Benchmark adapters and evaluation utilities for [MatterGraph](https://github.com/cyrusmo/MatterGraph).
4
+
5
+ ## What's in here
6
+
7
+ - **Discovery metrics** — ranking-quality measures (nDCG and friends) for screening workflows, where what matters is whether good candidates surface near the top.
8
+ - **Uncertainty** — `coverage_at_target` for checking whether predicted intervals are calibrated.
9
+ - **Validation splits** — stratified splitting helpers that respect composition and structure grouping.
10
+ - **Matbench adapter** — optional bridge to [Matbench](https://matbench.materialsproject.org/) tasks. Install `matbench` separately to enable it.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pip install mattergraph-benchmarks
16
+ ```
17
+
18
+ ## License
19
+
20
+ Apache-2.0
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib import import_module
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ if TYPE_CHECKING:
7
+ from mattergraph_benchmarks.discovery_metrics import dcg, ndcg_at_k
8
+ from mattergraph_benchmarks.matbench_adapter import matbench_dataframe, matbench_regression
9
+ from mattergraph_benchmarks.uncertainty import coverage_at_target
10
+ from mattergraph_benchmarks.validation_split import stratified_regression_split
11
+
12
+ _EXPORTS: dict[str, tuple[str, str, str | None]] = {
13
+ "matbench_dataframe": (
14
+ "mattergraph_benchmarks.matbench_adapter",
15
+ "matbench_dataframe",
16
+ None,
17
+ ),
18
+ "matbench_regression": (
19
+ "mattergraph_benchmarks.matbench_adapter",
20
+ "matbench_regression",
21
+ None,
22
+ ),
23
+ "ndcg_at_k": (
24
+ "mattergraph_benchmarks.discovery_metrics",
25
+ "ndcg_at_k",
26
+ None,
27
+ ),
28
+ "dcg": (
29
+ "mattergraph_benchmarks.discovery_metrics",
30
+ "dcg",
31
+ None,
32
+ ),
33
+ "coverage_at_target": (
34
+ "mattergraph_benchmarks.uncertainty",
35
+ "coverage_at_target",
36
+ None,
37
+ ),
38
+ "stratified_regression_split": (
39
+ "mattergraph_benchmarks.validation_split",
40
+ "stratified_regression_split",
41
+ (
42
+ "Install the optional `scikit-learn` dependency or run "
43
+ "`uv sync --all-packages --group dev` to use stratified_regression_split."
44
+ ),
45
+ ),
46
+ }
47
+
48
+ __all__ = [
49
+ "matbench_dataframe",
50
+ "matbench_regression",
51
+ "ndcg_at_k",
52
+ "dcg",
53
+ "coverage_at_target",
54
+ "stratified_regression_split",
55
+ ]
56
+
57
+
58
+ def __getattr__(name: str) -> Any:
59
+ if name not in _EXPORTS:
60
+ msg = f"module {__name__!r} has no attribute {name!r}"
61
+ raise AttributeError(msg)
62
+ module_name, attr_name, hint = _EXPORTS[name]
63
+ try:
64
+ module = import_module(module_name)
65
+ except ImportError as e:
66
+ if hint is None:
67
+ raise
68
+ raise ImportError(hint) from e
69
+ value = getattr(module, attr_name)
70
+ globals()[name] = value
71
+ return value
72
+
73
+
74
+ def __dir__() -> list[str]:
75
+ return sorted(set(globals()) | set(__all__))
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ from numpy.typing import ArrayLike
5
+
6
+
7
+ def dcg(relevances: ArrayLike) -> float:
8
+ r = np.asarray(relevances, dtype=float)
9
+ if r.size == 0:
10
+ return 0.0
11
+ g = 2.0**r - 1.0
12
+ i = np.arange(1, len(r) + 1, dtype=float)
13
+ return float(np.sum(g / np.log2(i + 1)))
14
+
15
+
16
+ def ndcg_at_k(relevances: ArrayLike, k: int = 10) -> float:
17
+ r = np.asarray(relevances, dtype=float)[:k]
18
+ if r.size == 0:
19
+ return 0.0
20
+ ideal = np.sort(r)[::-1]
21
+ d = dcg(r)
22
+ i = dcg(ideal)
23
+ return d / i if i > 0 else 0.0
@@ -0,0 +1,59 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+
9
+ def _load_matbench_task(name: str) -> Any:
10
+ try:
11
+ from matbench.task import MatbenchTask # type: ignore[import-not-found, import-untyped]
12
+ except ImportError as e: # pragma: no cover
13
+ msg = "Install the optional `matbench` package to use the Matbench adapter."
14
+ raise ImportError(msg) from e
15
+ t = MatbenchTask(name) # type: ignore[operator]
16
+ t.load() # type: ignore[no-untyped-call]
17
+ return t
18
+
19
+
20
+ def matbench_dataframe(task: str = "matbench_v0.1_log_gvrh") -> pd.DataFrame:
21
+ """
22
+ Load a Matbench task into a :class:`pandas.DataFrame` with a ``target`` and ``split`` column.
23
+
24
+ The ``matbench`` package is an optional install.
25
+ """
26
+ t = _load_matbench_task(task)
27
+ f = t.get_train_and_val() # type: ignore[no-untyped-call]
28
+ train = f[0] # type: ignore[index]
29
+ test = f[1] # type: ignore[index]
30
+ tr_x, tr_y, _ = train # type: ignore[misc]
31
+ te_x, te_y, _ = test # type: ignore[misc]
32
+
33
+ def _as_df(x: object, y: object, s: str) -> pd.DataFrame:
34
+ d = x.to_pandas() if hasattr(x, "to_pandas") else pd.DataFrame(x) # type: ignore[attr-defined, arg-type, call-overload] # noqa: E501
35
+ d = d.copy()
36
+ d["target"] = np.asarray(y).ravel()
37
+ d["split"] = s
38
+ return d
39
+
40
+ tr = _as_df(tr_x, tr_y, "train")
41
+ te = _as_df(te_x, te_y, "test")
42
+ return pd.concat([tr, te], ignore_index=True)
43
+
44
+
45
+ def matbench_regression(task: str = "matbench_v0.1_log_gvrh") -> dict[str, Any]:
46
+ """Return simple numpy arrays for train/test splits of a Matbench regression task."""
47
+ df = matbench_dataframe(task=task)
48
+ train = df[df["split"] == "train"]
49
+ test = df[df["split"] == "test"]
50
+ y_tr = train["target"].to_numpy()
51
+ y_te = test["target"].to_numpy()
52
+ x_tr = train.drop(columns=["target", "split"], errors="ignore")
53
+ x_te = test.drop(columns=["target", "split"], errors="ignore")
54
+ return {
55
+ "train_X": x_tr,
56
+ "train_y": y_tr,
57
+ "test_X": x_te,
58
+ "test_y": y_te,
59
+ }
@@ -0,0 +1,17 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ from numpy.typing import ArrayLike
5
+
6
+
7
+ def coverage_at_target(
8
+ y_true: ArrayLike,
9
+ y_lo: ArrayLike,
10
+ y_hi: ArrayLike,
11
+ ) -> float:
12
+ """Fraction of points where the interval ``[y_lo, y_hi]`` contains ``y_true``."""
13
+ yt = np.asarray(y_true, dtype=float).ravel()
14
+ lo = np.asarray(y_lo, dtype=float).ravel()
15
+ hi = np.asarray(y_hi, dtype=float).ravel()
16
+ m = (yt >= lo) & (yt <= hi)
17
+ return float(np.mean(m)) if m.size else 0.0
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ import numpy as np
6
+ import pandas as pd
7
+ from numpy.typing import ArrayLike, NDArray
8
+
9
+
10
+ def _load_train_test_split() -> Any:
11
+ try:
12
+ from sklearn.model_selection import train_test_split
13
+ except ImportError as e:
14
+ msg = "Install the optional `scikit-learn` dependency to use stratified_regression_split."
15
+ raise ImportError(msg) from e
16
+ return train_test_split
17
+
18
+
19
+ def stratified_regression_split(
20
+ y: ArrayLike,
21
+ n_bins: int = 8,
22
+ test_size: float = 0.2,
23
+ random_state: int = 0,
24
+ ) -> tuple[NDArray[np.int_], NDArray[np.int_]]:
25
+ """Bin continuous ``y`` and return train/test index arrays (stratified by bin)."""
26
+ train_test_split = _load_train_test_split()
27
+ yv = np.asarray(y, dtype=float).ravel()
28
+ yq, _ = pd.qcut(yv, n_bins, labels=False, retbins=True, duplicates="drop")
29
+ yq = np.nan_to_num(yq, nan=0.0)
30
+ i = np.arange(len(yv))
31
+ i_train, i_test = train_test_split(
32
+ i, test_size=test_size, random_state=random_state, stratify=yq
33
+ )
34
+ return i_train, i_test
@@ -0,0 +1,48 @@
1
+ [project]
2
+ name = "mattergraph-benchmarks"
3
+ version = "0.1.0"
4
+ description = "Benchmark adapters and evaluation utilities for MatterGraph."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "Apache-2.0"
8
+ authors = [{ name = "MatterGraph contributors" }]
9
+ keywords = ["materials-science", "benchmarks", "matbench", "machine-learning", "uncertainty"]
10
+ classifiers = [
11
+ "Development Status :: 3 - Alpha",
12
+ "Intended Audience :: Science/Research",
13
+ "Operating System :: OS Independent",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Topic :: Scientific/Engineering :: Chemistry",
19
+ "Topic :: Scientific/Engineering :: Physics",
20
+ ]
21
+ dependencies = [
22
+ "mattergraph-core~=0.1.0",
23
+ "numpy>=1.24",
24
+ "pandas>=2.0",
25
+ "scikit-learn>=1.3",
26
+ "pymatgen>=2024.1.1",
27
+ "httpx",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/cyrusmo/MatterGraph"
32
+ Repository = "https://github.com/cyrusmo/MatterGraph"
33
+ Issues = "https://github.com/cyrusmo/MatterGraph/issues"
34
+ Changelog = "https://github.com/cyrusmo/MatterGraph/blob/main/CHANGELOG.md"
35
+
36
+ [build-system]
37
+ requires = ["hatchling"]
38
+ build-backend = "hatchling.build"
39
+
40
+ [tool.uv.sources]
41
+ mattergraph-core = { workspace = true }
42
+
43
+ [tool.hatch.build.targets.wheel]
44
+ packages = ["mattergraph_benchmarks"]
45
+ core-metadata-version = "2.4"
46
+
47
+ [tool.hatch.build.targets.sdist]
48
+ core-metadata-version = "2.4"
@@ -0,0 +1,21 @@
1
+ import importlib
2
+
3
+ import mattergraph_benchmarks
4
+ import pytest
5
+
6
+
7
+ def test_stratified_split_has_helpful_optional_dependency_error(
8
+ monkeypatch: pytest.MonkeyPatch,
9
+ ) -> None:
10
+ module = importlib.reload(mattergraph_benchmarks)
11
+ real_import_module = module.import_module
12
+
13
+ def fake_import_module(name: str, package: str | None = None) -> object:
14
+ if name == "mattergraph_benchmarks.validation_split":
15
+ raise ImportError("No module named 'sklearn'")
16
+ return real_import_module(name, package)
17
+
18
+ monkeypatch.setattr(module, "import_module", fake_import_module)
19
+
20
+ with pytest.raises(ImportError, match="scikit-learn"):
21
+ _ = module.stratified_regression_split
@@ -0,0 +1,9 @@
1
+ from mattergraph_benchmarks import dcg, ndcg_at_k
2
+
3
+
4
+ def test_dcg_and_ndcg_bounds() -> None:
5
+ rel = [3, 2, 1]
6
+ assert dcg(rel) > 0
7
+ score = ndcg_at_k(rel, k=3)
8
+ assert 0.0 <= score <= 1.0
9
+ assert ndcg_at_k([], k=3) == 0.0