Metadata-Version: 2.4
Name: gloss-opt
Version: 1.0.1
Summary: GLOSS: Global-LOcal-unexplored Sampling Strategy for surrogate-based optimization in vast chemical spaces
Author-email: Baicheng Zhang <zbc@mail.ustc.edu.cn>
License: MIT License
        
        Copyright (c) 2026 Baicheng Zhang
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/zbc0315/gloss-opt
Project-URL: Repository, https://github.com/zbc0315/gloss-opt
Project-URL: Issues, https://github.com/zbc0315/gloss-opt/issues
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.21
Requires-Dist: scipy>=1.7
Requires-Dist: scikit-learn>=1.0
Provides-Extra: surrogates
Requires-Dist: torch>=1.9; extra == "surrogates"
Requires-Dist: xgboost>=1.5; extra == "surrogates"
Requires-Dist: lightgbm>=3.3; extra == "surrogates"
Provides-Extra: benchmarks
Requires-Dist: pandas>=1.3; extra == "benchmarks"
Requires-Dist: matplotlib>=3.5; extra == "benchmarks"
Requires-Dist: rdkit>=2022.9; extra == "benchmarks"
Requires-Dist: openpyxl>=3.0; extra == "benchmarks"
Provides-Extra: full
Requires-Dist: torch>=1.9; extra == "full"
Requires-Dist: xgboost>=1.5; extra == "full"
Requires-Dist: lightgbm>=3.3; extra == "full"
Requires-Dist: pandas>=1.3; extra == "full"
Requires-Dist: matplotlib>=3.5; extra == "full"
Requires-Dist: rdkit>=2022.9; extra == "full"
Requires-Dist: openpyxl>=3.0; extra == "full"
Requires-Dist: pytest>=7.0; extra == "full"
Dynamic: license-file

# GLOSS: Global-LOcal-unexplored Sampling Strategy

GLOSS is a batch recommendation algorithm for surrogate-based optimization in
large, sparsely sampled chemical spaces. It lessens over-reliance on the
surrogate model by dividing each recommended batch across three complementary
strategies:

- **Global**: upper-confidence-bound (UCB) acquisition over the whole space,
  with a diversity radius that keeps the batch from collapsing onto a single
  predicted optimum.
- **Local**: harvests the surrogate's multiple local optima directly through a
  BallTree spatial index.
- **Unexplored**: distance-gated sampling of regions far from all observed
  points, where surrogate predictions are unreliable and greedy search stalls.

This repository contains the reference implementation, the test suite, and the
complete benchmark used in the accompanying paper.

## Installation

From PyPI (library only):

```bash
pip install gloss-opt
```

From source (library plus benchmarks and data):

```bash
git clone https://github.com/zbc0315/gloss-opt.git
cd gloss-opt
pip install -e .
```

Requires Python >= 3.9. Core dependencies: numpy, scipy, scikit-learn.
Optional surrogate backends (torch, xgboost, lightgbm) and benchmark extras
(pandas, matplotlib, rdkit, openpyxl) install with:

```bash
pip install -e ".[full]"
```

## Quickstart

```python
import numpy as np
from gloss import GLOSS

# Discrete candidate pool: 10,000 points in 5 dimensions
rng = np.random.default_rng(0)
candidates = rng.uniform(0.0, 1.0, size=(10_000, 5))

opt = GLOSS(
    space={"candidates": candidates},
    mode="discrete",
    direction="maximize",
    ucb_kappa=2.0,
    diversity_radius=0.02,
    seed=0,
)

# Initial observations
X_obs = candidates[:8]
y_obs = np.sin(X_obs).sum(axis=1)

# One recommendation round: 4 global + 2 local + 2 unexplored points
batch = opt.recommend(
    X_train=X_obs,
    y_train=y_obs,
    strategy_points={"global_best": 4, "local_best": 2, "unexplored": 2, "unconverged": 0},
)

points = np.array([r["point"] for r in batch])   # (8, 5) points to evaluate next
```

`recommend()` fits a surrogate on the observations (or accepts a pre-fitted
one via `surrogate=`) and runs the three strategies in sequence with
deduplication. It returns a list of dicts, one per recommended point, each
carrying the `point` itself, its `predicted_value`, and the `strategy` that
proposed it. Continuous spaces are supported via `mode="continuous"` and
`space={"bounds": [(lo, hi), ...]}`.

## Reproducing the paper benchmarks

The benchmark compares GLOSS against four baselines (BO-EI, BO-UCB, GA, and
random sampling) on three chemical datasets, with all algorithms sharing one
Random Forest surrogate and identical bottom-20% initializations.

```bash
# Quick validation (1 seed, 10 rounds)
python -m benchmarks.bench_main --study pilot

# Individual studies
python -m benchmarks.bench_main --study main         # 3 datasets x 5 algorithms
python -m benchmarks.bench_main --study scaling      # QM9 pool 5k -> 100k
python -m benchmarks.bench_main --study complexity   # Arrhenius C1 -> C5
python -m benchmarks.bench_main --study ratio_scaling
python -m benchmarks.bench_main --study ratio_complexity

# Everything (5 seeds; several hours on a single machine)
python -m benchmarks.bench_main --study all

# Local top-K ablation (Supporting Information S2)
python -m benchmarks.bench_local_topk

# Regenerate all paper figures from the result CSVs
python -m benchmarks.plot_benchmark
```

Result CSVs land in `benchmarks/results/` and figures in `benchmarks/plots/`.
The CSVs backing the published figures are included in this repository, so
`plot_benchmark.py` reproduces every figure without re-running the campaigns.

### Datasets

No manual download is needed. On first use, `benchmarks/datasets.py` fetches
each dataset from its original public source into `benchmarks/data/`:

| Dataset | Source | Size |
|---|---|---|
| QM9 (HOMO-LUMO gap) | DeepChem S3 mirror of QM9 | 134k molecules |
| Buchwald-Hartwig yields | rxn_yields repository (Dreher and Doyle) | 3,955 reactions |
| Arrhenius-2D | virtual landscape, generated by `benchmarks/virtual_functions.py` | analytic |

Molecular features (20 RDKit descriptors) are computed locally; the
precomputed stratified QM9 pools for the scaling study can be rebuilt with
`python -m benchmarks.build_qm9_strat`.

## Tests

```bash
pytest tests/ -v
```

## Citing

If you use GLOSS in your work, please cite the paper (see `CITATION.cff`).

## License

MIT. See `LICENSE`.
