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
95 changes: 95 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.3.0] - 2026-05-11

### Deprecated
- `AdaptiveModeAdamW` and `AdaptiveModeSGD` are deprecated and will be removed
in 0.4.0. Use `AEES`, which wraps any `torch.optim.Optimizer`. Importing or
instantiating either class now emits a `DeprecationWarning`.

## [0.2.2] - 2026-05-10

Patch release with packaging cleanup and security hardening.

### Added
- `MANIFEST.in` to refine PyPI source distribution contents.
- Runnable examples included in the source distribution (wheel kept minimal).

### Changed
- Clarified README documentation around examples and repository layout.
- Updated test configuration.
- Pinned third-party GitHub Actions to commit SHAs to reduce CI supply-chain risk.

### Fixed
- Replaced an unsafe `assert` state check in `Scheduler.step_end` with an
explicit runtime check.

## [0.2.1] - 2026-05-07

Metadata-only patch.

### Added
- `Changelog` URL under `[project.urls]` so PyPI surfaces a link to the
changelog in the project sidebar.

## [0.2.0] - 2026-05-07

Breaking-change release that removes the `trend_phase` context mode.

### Removed
- `pulseopt.TREND_PHASE_CONTEXT_BUCKETS`.
- `context_mode="trend_phase"`.
- `total_training_steps` kwarg on `AEES` and `StructuredEpisodeManager` (was
only used to compute the `trend_phase` boundary).
- `StructuredSelection.context_bucket_id`, `.context_bucket_name`,
`.context_phase`, `.context_trend`.
- Episode log keys `context_bucket_ids`, `context_bucket_names`,
`context_phases`, `context_trends`.

### Changed
- `StructuredSelection` now exposes a single `context_bucket: str | None`
field; episode logs expose a single `context_buckets` list (only present
when `context_mode != "none"`).

### Migration
- If you used `context_mode="trend_phase"`, switch to `"trend"` (or `"none"`).
- If you read any of the removed `StructuredSelection` fields or log keys,
read `context_bucket` / `context_buckets` instead.

## [0.1.6rc1] - 2026-05-06

### Added
- CI/CD workflows and ruff lint/format configuration.
- Release smoke test for the CI/CD pipeline.

## [0.1.5] - 2026-05-06

### Removed
- Files irrelevant to the PyPI package that remained from thesis experiments.

### Changed
- Default `reward_instability_lambda` set to `0.0` in `reward.py`.

## [0.1.4] - 2026-05-05

### Fixed
- Changed repo-relative paths to absolute.

### Changed
- Set reward instability constant to `0.0`.

[Unreleased]: https://github.com/davidkfoss/pulseopt/compare/v0.3.0...HEAD
[0.3.0]: https://github.com/davidkfoss/pulseopt/compare/v0.2.2...v0.3.0
[0.2.2]: https://github.com/davidkfoss/pulseopt/compare/v0.2.1...v0.2.2
[0.2.1]: https://github.com/davidkfoss/pulseopt/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/davidkfoss/pulseopt/compare/v0.1.6rc1...v0.2.0
[0.1.6rc1]: https://github.com/davidkfoss/pulseopt/compare/v0.1.5...v0.1.6rc1
[0.1.5]: https://github.com/davidkfoss/pulseopt/compare/v0.1.4...v0.1.5
[0.1.4]: https://github.com/davidkfoss/pulseopt/releases/tag/v0.1.4
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ dev = [
Homepage = "https://github.com/davidkfoss/pulseopt"
Repository = "https://github.com/davidkfoss/pulseopt"
Issues = "https://github.com/davidkfoss/pulseopt/issues"
Changelog = "https://github.com/davidkfoss/pulseopt/releases"
Changelog = "https://github.com/davidkfoss/pulseopt/blob/main/CHANGELOG.md"

[tool.setuptools]
include-package-data = true
Expand Down
2 changes: 1 addition & 1 deletion src/pulseopt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Adaptive Episodic Exploration Scheduling package."""

__version__ = "0.2.2"
__version__ = "0.3.0"

from pulseopt.controller import (
TREND_CONTEXT_BUCKETS,
Expand Down
36 changes: 33 additions & 3 deletions src/pulseopt/optimizer.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
"""Scheduler-compatible optimizer wrappers with AEES mode scaling."""
"""Scheduler-compatible optimizer wrappers with AEES mode scaling.

.. deprecated:: 0.3.0
``AdaptiveModeAdamW`` and ``AdaptiveModeSGD`` are deprecated and will be
removed in 0.4.0. Use :class:`pulseopt.AEES`, which wraps any
``torch.optim.Optimizer``.
"""

from __future__ import annotations

import warnings
from collections.abc import Iterable
from copy import deepcopy
from typing import Any
Expand All @@ -11,9 +18,18 @@

from pulseopt.types import CandidateConfig

_DEPRECATION_MESSAGE = (
"{cls} is deprecated and will be removed in pulseopt 0.4.0. "
"Use pulseopt.AEES, which wraps any torch.optim.Optimizer."
)


class AdaptiveModeAdamW(torch.optim.AdamW):
"""AdamW optimizer that applies AEES multipliers on top of scheduled bases."""
"""AdamW optimizer that applies AEES multipliers on top of scheduled bases.

.. deprecated:: 0.3.0
Use :class:`pulseopt.AEES` instead. Will be removed in 0.4.0.
"""

def __init__(
self,
Expand All @@ -26,6 +42,11 @@ def __init__(
mode: CandidateConfig | None = None,
noise_seed: int | None = None,
) -> None:
warnings.warn(
_DEPRECATION_MESSAGE.format(cls="AdaptiveModeAdamW"),
DeprecationWarning,
stacklevel=2,
)
if not torch.isfinite(torch.tensor(float(lr))):
raise ValueError("lr must be finite.")
if lr <= 0.0:
Expand Down Expand Up @@ -269,7 +290,11 @@ def _restore_base_list(


class AdaptiveModeSGD(torch.optim.SGD):
"""SGD optimizer that applies AEES multipliers on top of scheduled bases."""
"""SGD optimizer that applies AEES multipliers on top of scheduled bases.

.. deprecated:: 0.3.0
Use :class:`pulseopt.AEES` instead. Will be removed in 0.4.0.
"""

def __init__(
self,
Expand All @@ -282,6 +307,11 @@ def __init__(
mode: CandidateConfig | None = None,
noise_seed: int | None = None,
) -> None:
warnings.warn(
_DEPRECATION_MESSAGE.format(cls="AdaptiveModeSGD"),
DeprecationWarning,
stacklevel=2,
)
if not torch.isfinite(torch.tensor(float(lr))):
raise ValueError("lr must be finite.")
if lr <= 0.0:
Expand Down
3 changes: 3 additions & 0 deletions tests/test_optimizer_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

from __future__ import annotations

import pytest
import torch

from pulseopt.optimizer import AdaptiveModeAdamW
from pulseopt.types import CandidateConfig

pytestmark = pytest.mark.filterwarnings("ignore:AdaptiveModeAdamW is deprecated:DeprecationWarning")


def build_model(weight: float = 1.0) -> torch.nn.Linear:
"""Create a tiny deterministic linear model."""
Expand Down