Skip to content

feat(optim): noise-aware confirmation, islands and MAP-Elites for evolve - #509

Merged
Aria068 merged 3 commits into
SylphAI-Inc:mainfrom
shangliy:feat/evolution-noise-diversity
Oct 30, 2026
Merged

Aria068 merged 3 commits into
SylphAI-Inc:mainfrom
shangliy:feat/evolution-noise-diversity

Conversation

@shangliy

@shangliy shangliy commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #508. This branch contains #508's three commits; the last two commits (fbe0d70 feature, b27f5e1 docs) are new here. Rebased onto main after #504 and #507 merged; I'll rebase again once #508 merges.

Adds noise handling and diversity mechanisms to adalflow.optim.evolution.evolve, each with tests and a benchmark that reports where it helps and where it does not.

Changes

  • confirm=n (noisy evaluators). When a candidate's first score beats the best so far, it and the incumbent are re-evaluated until each has 1 + n samples, and the means decide. Only fully sampled candidates can be the best. A proposal starts only if the remaining budget can finish its comparison, so the returned best is always fully sampled. Candidate keeps its samples, and evaluation is their mean (types.combine).
  • islands=k, migrate_every=m. Proposals rotate over sub-populations. Parents and inspirations come from the current island, and every m proposals the next island's best is shown as the inspiration (logged as a migration event).
  • selection="map_elites" with a descriptor (candidate -> tuple, which can read evaluator metrics). One elite is kept per behavior cell, parents are drawn uniformly over cells, and the inspiration comes from another cell.
  • benchmarks/evolution:
    • a binpack behavior descriptor: agreement with best fit × code length;
    • map_elites and islands strategies in run.py;
    • noise_sim.py, a model-free simulation of confirm.

Results

Diversity (claude-haiku-5-5, binpack, budget 30, 3 runs each):

strategy search best held-out best cells reached (of 20)
pareto 0.954 [0.952, 0.959] 0.948 [0.947, 0.949] 4.3
map_elites 0.953 [0.951, 0.955] 0.950 [0.947, 0.953] 5.0
islands 0.952 [0.952, 0.952] 0.950 [0.949, 0.951] 4.3
  • The differences are within run-to-run spread.
  • pareto overfit the most: its highest search score had its lowest held-out score.
  • Runs reach only 4–6 cells, so the proposer's narrow output, not parent selection, is what limits diversity on this task.

Noise (noise_sim.py, no model, greedy, budget 60, 200 runs per cell). confirm always reduces how much the reported best overstates its true quality (noise sd 0.1: +0.23 → +0.08). The re-evaluations cost budget, though:

  • With little noise, the true quality found drops (sd 0: 0.95 → 0.75 with confirm=2).
  • With large noise, it improves only slightly (about +0.02).

The docs therefore describe confirm as a way to get honest scores, not as a way to search better.

Tests

  • 23 evolution tests:
    • sample averaging that skips failed samples;
    • a lucky first score that is rejected after confirmation;
    • budget reservation;
    • island rotation and migration;
    • MAP-Elites elites and selection;
    • descriptor errors.
  • Existing behavior: with the defaults (confirm=0, islands=1), behavior is unchanged and the earlier tests pass as before.

Docs and example (commit 4):

  • docs/source/new_tutorials/evolution.md, a tutorial covering:
    • the minimal function example (output from a real run);
    • writing evaluators;
    • evolving prompts;
    • choosing a strategy;
    • held-out checks;
    • confirm for noisy evaluators;
    • result and log fields.
  • use_cases/evolution/evolve_prompt.py evolves a ticket-routing instruction against labeled tickets, with a held-out split.
  • Real run (claude-haiku-5-5): train went from 0.69 to 1.0 in three rewrites, and held-out from 0.50 to 0.92. One intermediate candidate was worse on average but was kept by Pareto selection, and the eventual winner descends from it.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RS4zJj45n2d6zbs4vhsEFx

@Aria068 Aria068 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, what is the main benefit to this update. Could you link a doc

@shangliy
shangliy force-pushed the feat/evolution-noise-diversity branch from fbc680c to b27f5e1 Compare October 23, 2026 04:34
@shangliy

Copy link
Copy Markdown
Contributor Author

Thanks for taking a look! The main benefit is that evolve can now be trusted, and kept from collapsing onto one approach, in the two situations where the plain loop in #508 falls short.

1. Noisy evaluators (confirm=n). With an LLM judge, sampled tests or a stochastic agent, the highest single score in the archive is usually a lucky draw, so the plain loop returns an overstated "best". With confirm=n, a candidate that looks better is re-scored together with the current best until both have 1 + n samples, and their means decide.

  • In simulation (benchmarks/evolution/noise_sim.py, noise sd 0.1), the reported best overstated its true quality by +0.23 without confirm and by +0.08 with it.
  • The trade-off: the re-evaluations come out of the budget. It only finds better candidates when the noise is large, so it is off by default and is not needed for deterministic evaluators.

2. Diversity (islands=k, selection="map_elites" with a descriptor). These keep several lineages or behaviorally different solutions instead of letting one take over the archive. They are the standard mechanisms in OpenEvolve and FunSearch-style systems, and are intended for open-ended tasks.

  • To be upfront: on the bin-packing benchmark they did not measurably beat the default (held-out 0.950 vs. 0.948, within run-to-run spread).
  • The runs reached only 4–6 of 20 behavior cells, which points to the proposer's output diversity as the current bottleneck. The full tables are in the PR description.

Docs:

shangliy and others added 3 commits October 29, 2026 20:48
ubuntu-latest moved to 26.04, which has no Python 3.9 build, so the 3.9 job
failed at setup and fail-fast cancelled the other three. Pin the runner for
the test and release workflows (the package supports >=3.9) and stop
cancelling sibling jobs when one fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FRbbGopnKbeX5NUc35UoPk
…evolve

- confirm=n: a candidate whose first score beats the best is re-evaluated
  with the incumbent to 1+n samples each; only fully sampled candidates can
  be the best, and a proposal starts only if the budget can finish its
  comparison. Candidate keeps its samples; evaluation is their mean
  (types.combine).
- islands=k / migrate_every=m: proposals rotate over sub-populations, and
  each island periodically gets the next island's best as inspiration.
- selection="map_elites" with a descriptor: one elite per behavior cell,
  parents uniform over cells, inspiration from another cell.
- benchmarks/evolution: a binpack behavior descriptor, map_elites and
  islands strategies, and noise_sim.py (no model) for confirm. The README
  reports the results, which show no clear gain from either diversity
  method on binpack and that confirm mainly reduces score overstatement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RS4zJj45n2d6zbs4vhsEFx
- docs/source/new_tutorials/evolution.md: the minimal function example,
  writing evaluators, evolving prompts, choosing a strategy (pareto, best,
  map_elites, islands, resample), held-out checks, confirm for noisy
  evaluators, and the result and log fields. Example outputs are from real
  runs.
- use_cases/evolution/evolve_prompt.py: evolves a ticket-routing
  instruction scored on labeled tickets, with a held-out split.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RS4zJj45n2d6zbs4vhsEFx
@shangliy
shangliy force-pushed the feat/evolution-noise-diversity branch from b27f5e1 to fcea6f6 Compare October 30, 2026 03:49
@Aria068
Aria068 merged commit 521c742 into SylphAI-Inc:main Oct 30, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants