Skip to content

Conversation

vacmar01
Copy link

I implemented a epsilon greedy candidate selector strategy, added it to the API and added some tests (for all candidate selectors).

It is not fully documented yet, but I wanted to make sure that I'm on the right path with the API. I changed it a bit so that optimize also accepts a CandidateSelector subclass directly, so that we can specify further hyperparameters (like the epsilon in this case).

What do you think, @LakshyAAAgrawal ? :)

Plan is to add more candidate selection strategies (Softmax, Thompson Sampling, UCB1 etc.) to the repo and compare them to each other.

implemented epsilon greedy candidate selector, added it to the API and added some tests (for all candidate selectors)
Copy link

semanticdiff-com bot commented Oct 13, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  src/gepa/api.py  42% smaller
  src/gepa/strategies/candidate_selector.py  0% smaller
  tests/test_candidate_selector.py  0% smaller

@fgn
Copy link

fgn commented Oct 13, 2025

Consider restricting ε-greedy exploration to a more refined pool of candidates. Currently, exploration may select any candidate, including those that are clearly suboptimal.

You might parameterize EpsilonGreedyCandidateSelector with a pool argument accepting values like "pareto", "top_k", or "all", along with an optional k parameter for the "top_k" setting.

One suggestion could be to start with the Pareto set to ensure a good balance between exploration and exploitation, and then experiment with the top_k setting to fine-tune performance.

)

if isinstance(candidate_selection_strategy, str):
candidate_selector_cls = {
Copy link

Choose a reason for hiding this comment

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

Don't call it _cls here when it's not a class.

Copy link

Choose a reason for hiding this comment

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

This will instantiate all three selectors.

Here is a lazy pattern that will instantiate at most one.

factories = {
    "pareto": lambda: ParetoCandidateSelector(rng=rng),
    "best": lambda: CurrentBestCandidateSelector(),
    "epsilon_greedy": lambda: EpsilonGreedyCandidateSelector(epsilon=0.1, rng=rng),
}

try:
    candidate_selector = factories[candidate_selection_strategy]()
except KeyError:
    raise ValueError(
        f"Unknown candidate_selector strategy: {candidate_selection_strategy}. "
        "Supported strategies: 'pareto', 'best', 'epsilon_greedy'"
    )

Copy link
Author

Choose a reason for hiding this comment

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

Great review, thanks :) Will incorporate the changes.

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