Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ jobs:
--cov-report=term-missing
--cov-fail-under=90

aldes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: actions/setup-python@v6
with:
python-version: "3.11"
cache: pip
- run: python -m pip install --upgrade pip
- run: python -m pip install ".[test,aldes]"
- run: python -W error -m pytest tests/unit/test_aldes.py

package:
runs-on: ubuntu-latest
steps:
Expand All @@ -80,7 +92,7 @@ jobs:
from autooptlib.problems import cec2013_f1
from autooptlib.utils.solve import input_algorithm

assert autooptlib.__version__ == "1.2.0"
assert autooptlib.__version__ == "1.3.0"
problems, data, _ = cec2013_f1([SimpleNamespace()], [10], "construct")
assert problems[0].bound.shape == (2, 10)
assert data[0].o.shape == (10,)
Expand Down
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,44 @@

All notable changes to AutoOptLib are documented here.

## 1.3.0 - 2026-07-19

### Added

- Integrated ALDes as an optional learning-based design backend with an
ALDes-compatible 32-token vocabulary, a deliberately constrained grammar,
an autoregressive PyTorch generator, PPO trainer, and EWC
continual-learning penalty.
- Added a pure-Python ALDes sequence codec and evaluator that execute generated
algorithms through the common AutoOptLib pathway engine.
- Added an optional IOH PBO problem adapter and the missing `search_reset_n`
component required by the ALDes vocabulary.
- Added `Designer="aldes"` to the high-level `autoopt` workflow, including
checkpoint loading, problem features, candidate count, temperature, and
greedy-decoding controls.

### Changed

- Corrected discrete uniform-crossover and random-reset parameter bounds to
match the reference implementation.
- Defined one consistent multi-path rule: a fork follows choose, every branch
evaluates one search row (a crossover may include a paired mutation), and
the branches merge before a shared population update. ALDes no longer
generates unused later search rows.
- Made single-problem ALDes design the default with no landscape-feature
extraction or input. Continual design explicitly enables problem-feature
conditioning and paper-style random-walk feature extraction.
- Matched the paper's 5,000-FE training budget, deterministic PPO likelihood
calculation, 100-step learning-rate annealing, and EWC weight of 200.
- Made candidate evaluation order-independent through common random streams
and added reuse of feature-sampling solutions as initial populations.
- Added deterministic candidate-level CPU multiprocessing for ALDes PBO
evaluation, including duplicate-sequence caching and persistent workers.
- Made option lookup safe when an earlier option value is a NumPy array, which
is required for in-memory ALDes problem features.
- Kept PyTorch, IOH, pflacco, pandas, and scikit-learn behind the optional
`autooptlib[aldes]` dependency group.

## 1.2.0 - 2026-07-19

### Added
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ cff-version: 1.2.0
message: "If you use AutoOptLib, please cite this software and the accompanying paper."
title: "AutoOptLib"
type: software
version: 1.2.0
version: 1.3.0
date-released: 2026-07-19
license: Apache-2.0
repository-code: "https://github.com/auto4opt/AutoOptLib"
Expand Down
56 changes: 55 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AutoOptLib

[![Version](https://img.shields.io/badge/version-1.2.0-blue.svg)](https://github.com/auto4opt/AutoOptLib/releases)
[![Version](https://img.shields.io/badge/version-1.3.0-blue.svg)](https://github.com/auto4opt/AutoOptLib/releases)
[![License](https://img.shields.io/badge/license-Apache--2.0-green.svg)](LICENSE)
[![Tests](https://github.com/auto4opt/AutoOptLib/actions/workflows/tests.yml/badge.svg)](https://github.com/auto4opt/AutoOptLib/actions/workflows/tests.yml)
[![Documentation](https://readthedocs.org/projects/autooptlib/badge/?version=latest)](https://autooptlib.readthedocs.io/)
Expand Down Expand Up @@ -30,6 +30,8 @@ historical releases.
- Retry, hard-timeout, failure-penalty, evaluation-cache, and JSONL logging
controls for external objectives.
- Automatic experiment manifests with software and invocation provenance.
- Optional ALDes autoregressive generation, PPO training, continual-learning,
and pure-Python execution of an ALDes-compatible discrete token vocabulary.

## Installation

Expand All @@ -50,6 +52,13 @@ python -m ruff format --check .
python -m pytest -W error
```

Install the learning-based ALDes designer separately so core users do not
need PyTorch or IOH:

```bash
python -m pip install "autooptlib[aldes]"
```

## Quick start

The following example designs a small optimizer for the bundled CEC 2013
Expand Down Expand Up @@ -125,6 +134,51 @@ MATLAB procedure, `AlgFE` counts newly proposed algorithms after the initial
`AlgN` incumbents; held-out evaluation of the final algorithms is separate.
Sequential problems receive a fresh `ProbFE` budget at every stage.

## Learning-based design with ALDes

`autooptlib.aldes` contains a constrained 32-token ALDes grammar,
sequence-to-pathway codec,
PyTorch generator, PPO/EWC training utilities, IOH PBO adapter, and a direct
evaluation bridge. A trained generator can be used through the same high-level
entry point:

```python
from autooptlib import autoopt

algorithms, trace = autoopt(
Mode="design",
Designer="aldes",
Problem=my_discrete_problem,
InstanceTrain=[train_instance],
InstanceTest=[test_instance],
ALDesModel="checkpoints/aldes.pt",
ALDesCandidates=32,
AlgN=5,
ProbN=50,
ProbFE=5_000,
AlgRuns=5,
Seed=2026,
)
```

Single-problem design is the default: create the generator with the default
`GeneratorConfig`, use `ALDesMode="single"` (or omit it), and do not calculate
or pass landscape features. For continual design, train a generator with
`GeneratorConfig(condition_on_features=True)` and call the workflow with
`ALDesMode="continual"` plus `ALDesFeatures=problem_features`. The continual
feature extractor is available as `autooptlib.aldes.extract_pbo_features` and
returns both the feature vector and sampled initial populations. Its result
object can be passed directly as `ALDesFeatures`; the associated populations
are then reused automatically, or they can be supplied separately through
`ALDesInitialPopulations`.

The ordinary `Designer="search"` workflow remains the default. ALDes decodes
its generated programs into the same `Design` and pathway objects used by the
rest of AutoOptLib; MATLAB and MATLAB Engine are not required.
`ALDesModel` checkpoint paths must be produced by
`ALDesGenerator.save_checkpoint`; unversioned checkpoints from the historical
standalone ALDes repository are not loaded implicitly.

## Reproducibility

Pass `Seed=<integer>` to `autoopt`. Version 1.2.0 routes this seed through
Expand Down
34 changes: 34 additions & 0 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ Common options:
- `CheckpointDir`: optional Solve or Design checkpoint directory.
- `CheckpointEvery`: generations or candidate evaluations between atomic writes.
- `Resume`: resume matching completed or interrupted checkpoints.
- `Designer`: `search` (default) or `aldes` in design mode.
- `ALDesModel`: trained `ALDesGenerator` or checkpoint path.
- `ALDesMode`: `single` (default, no problem features) or `continual`.
- `ALDesFeatures`: target-problem feature vector or `.npy` path, required only
in continual mode and rejected in single-problem mode.
- `ALDesInitialPopulations`: optional sampled populations or `.npy`/`.npz`
path reused across candidate algorithms and runs.
- `ALDesCandidates`: number of generated candidates; must be at least `AlgN`.
- `ALDesTemperature`: positive sampling temperature (default `1.0`).
- `ALDesGreedy`: use grammar-constrained greedy decoding (default `False`).

The mode-specific defaults match the reference MATLAB package: Design uses
`AlgQ=4`, `ProbN=20`, `ProbFE=5000`, `InnerFE=500`, `AlgN=10`, `AlgFE=5000`,
Expand All @@ -46,6 +56,30 @@ Design returns `(algorithms, trace)`. Solve returns
algorithms on held-out instances after the `AlgFE` search budget.
Every completed call also writes `experiment.json` to `OutputDir`.

## `autooptlib.aldes`

The optional ALDes API exposes `validate_sequence`, `allowed_next_tokens`,
`decode_sequence`, `AutoOptEvaluator`, `EvaluationConfig`, and
`make_pbo_problem` without importing PyTorch. Single-problem generators do not
use landscape features. Continual generators opt in with
`GeneratorConfig(condition_on_features=True)` and can use
`extract_pbo_features` to obtain paper-style random-walk features and reusable
initial populations. `ALDesGenerator`, `PPOTrainer`, and
`ElasticWeightConsolidation` load PyTorch lazily and require
`pip install "autooptlib[aldes]"`.

`EvaluationConfig(initial_populations=...)` accepts `(N,D)`, `(runs,N,D)`,
`(instances,runs,N,D)`, or an instance-index mapping. Candidate batches reuse
the same initial random stream so their ranking is independent of enumeration
order.

`evaluate_pbo_actions(..., workers=None)` evaluates unique ALDes candidates
in a persistent CPU process pool, automatically bounded by the number of
logical CPU cores. Pass `workers=1` for serial execution or a positive integer
for an explicit limit. Neural-network tensors remain on their configured
PyTorch accelerator; only token sequences and CPU evaluation data cross the
process boundary.

## `make_problem(...)`

Wrap an ordinary scalar minimization objective. See
Expand Down
33 changes: 32 additions & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,45 @@ AutoOptLib separates four concerns:
1. A **problem definition** constructs related training and test instances.
2. A **design space** supplies type-compatible selection, search, update, and
archive components.
3. The **design engine** searches graph structures and component parameters.
3. A **design backend** either searches graph structures and parameters or
uses ALDes to generate a grammar-constrained token sequence.
4. The **execution engine** applies either a designed JSON algorithm or a
built-in baseline under a strict objective-evaluation budget.

This separation is important for application studies: the problem code does
not contain optimizer logic, and a selected algorithm can be exported and
executed later without rerunning automated design.

ALDes token programs are decoded into the same pathway representation before
execution. The learning backend and search backend therefore share component,
budget, problem, serialization, and reliability semantics rather than
maintaining separate Python and MATLAB evaluators.

For a multi-path or ALDes fork algorithm, one outer iteration selects and
partitions the population, evaluates only the first primary search step of
each branch, merges the offspring, and applies the shared update. A mutation
paired with a crossover is part of that first step and is also executed. ALDes
fork sequences cannot contain later search rows, keeping generation and
execution consistent. This is AutoOptLib's constrained ALDes dialect, not a
claim that every permissive sequence accepted by the historical generator or
the paper's general pointer notation has identical semantics.
The fork parameter has two non-aliased modes: both branches execute the whole
search row, or—only for crossover plus mutation—the second branch starts at
the mutation.

The 32-token component vocabulary and ten-bin parameter decoder follow the
released ALDes source. They are intentionally versioned separately from the
paper's Appendix A2 table, which lists a different component set and is itself
inconsistent with the paper's `always_select` example. Parameter bins retain
the released implementation's linear interpolation over each component's
bounds; AutoOptLib does not silently reinterpret them as percentages.

ALDes uses two explicit learning modes. Single-problem design is the default
and conditions only on the generated token prefix. Continual design opts into
a problem-feature token, paper-style random-walk feature extraction, and EWC.
The sampled random-walk populations can be supplied to `EvaluationConfig` so
all candidate algorithms are compared from the same initial solutions.

The supported public surface is documented in [Public API](api.md). Internal
mode-based component functions remain implementation details and may evolve
between minor releases.
10 changes: 10 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,13 @@ applications = [
surrogate = [
"scikit-learn>=1.2,<2",
]
aldes = [
"torch>=2.1,<3",
"ioh>=0.3.14,<1",
"pandas>=2,<4",
"pflacco>=1.2,<2",
"scikit-learn>=1.2,<2",
]

[project.urls]
Homepage = "https://github.com/auto4opt/AutoOptLib"
Expand Down Expand Up @@ -101,6 +108,9 @@ ignore_missing_imports = true
check_untyped_defs = true
show_error_codes = true

[tool.coverage.run]
omit = ["src/autooptlib/aldes/*"]

[tool.ruff]
target-version = "py39"
line-length = 88
Expand Down
2 changes: 2 additions & 0 deletions src/autooptlib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from __future__ import annotations

from . import aldes
from ._version import __version__
from .applications import (
MaterialStackingInstance,
Expand All @@ -23,6 +24,7 @@

__all__ = [
"Design",
"aldes",
"MaterialStackingInstance",
"RISBeamformingInstance",
"StackingWeights",
Expand Down
2 changes: 1 addition & 1 deletion src/autooptlib/_version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Single source of truth for the package version."""

__version__ = "1.2.0"
__version__ = "1.3.0"
84 changes: 84 additions & 0 deletions src/autooptlib/aldes/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""ALDes: autoregressive learning for metaheuristic algorithm design.

The codec and evaluator require only NumPy and AutoOptLib. PyTorch is loaded
only when the generator or PPO training APIs are requested.
"""

from __future__ import annotations

from importlib import import_module

from .codec import ComponentInstruction, decode_sequence
from .evaluator import AutoOptEvaluator, EvaluationConfig, evaluate_pbo_actions
from .features import PBOFeatureResult, extract_pbo_features, standardize_features
from .problems import make_pbo_problem
from .vocabulary import (
BEGIN_INDEX,
END_INDEX,
TOKEN_BY_INDEX,
TOKEN_BY_NAME,
TOKENS,
VOCABULARY_SIZE,
SequenceValidationError,
allowed_next_tokens,
normalize_sequence,
tokens_to_names,
validate_sequence,
)

_TORCH_EXPORTS = {
"ALDesGenerator": ("model", "ALDesGenerator"),
"GenerationResult": ("model", "GenerationResult"),
"GeneratorConfig": ("model", "GeneratorConfig"),
"ElasticWeightConsolidation": ("training", "ElasticWeightConsolidation"),
"PPOConfig": ("training", "PPOConfig"),
"PPOTrainer": ("training", "PPOTrainer"),
}


def __getattr__(name: str):
if name not in _TORCH_EXPORTS:
raise AttributeError(name)
module_name, attribute = _TORCH_EXPORTS[name]
try:
module = import_module(f".{module_name}", __name__)
except ImportError as exc:
if exc.name == "torch":
raise ImportError(
"PyTorch is required for ALDes generation and training. Install "
"AutoOptLib with `pip install 'autooptlib[aldes]'`."
) from exc
raise
value = getattr(module, attribute)
globals()[name] = value
return value


__all__ = [
"ALDesGenerator",
"AutoOptEvaluator",
"BEGIN_INDEX",
"ComponentInstruction",
"END_INDEX",
"ElasticWeightConsolidation",
"EvaluationConfig",
"GenerationResult",
"GeneratorConfig",
"PPOConfig",
"PPOTrainer",
"PBOFeatureResult",
"SequenceValidationError",
"TOKENS",
"TOKEN_BY_INDEX",
"TOKEN_BY_NAME",
"VOCABULARY_SIZE",
"allowed_next_tokens",
"decode_sequence",
"evaluate_pbo_actions",
"extract_pbo_features",
"make_pbo_problem",
"normalize_sequence",
"tokens_to_names",
"standardize_features",
"validate_sequence",
]
Loading