Skip to content

select_next_parent computes child_counts but never uses it; selection is uniform random #29

Description

@j-arndt

Summary

select_next_parent.py builds a child_counts dictionary tracking the number of
descendants each candidate parent has spawned, then immediately discards it and
selects a parent uniformly at random via random.choice. The computation is dead
code, and the selection is not actually novelty-weighted --- both contradict what
a reader of the function would reasonably expect from a method named
select_next_parent in an open-ended exploration framework.

Reproduction

select_next_parent.py:50-57 (current main):

# Build child counts from metadata
child_counts = {genid: 0 for genid in candidates}
for genid in archive:
    parent = get_parent_genid(output_dir, genid)
    if parent in child_counts:
        child_counts[parent] += 1

# Select parent randomly, keeping the search space open
return random.choice(list(candidates.keys()))

child_counts is constructed but never read. The selection ignores it entirely.

Expected behavior

Either:

  • Option A (preferred): the function uses child_counts to implement
    novelty-weighted selection (probability inversely proportional to
    1 + child_counts[genid]), so under-explored candidates are preferentially
    picked. This is the standard mechanism used by FunSearch, MAP-Elites, and
    AlphaEvolve to prevent mode collapse during open-ended search, and it appears
    to be what the existing code structure is reaching for.

  • Option B: if uniform random is genuinely the intended behavior, the
    child_counts computation should be deleted and the docstring/comment updated
    to reflect that the function does not prefer under-explored branches.

Actual behavior

Selection is uniform random. The child_counts table is computed every call and
thrown away. Downstream evolutionary loops that rely on this function for diverse
parent selection silently get unweighted sampling instead.

Impact

In the use case I encountered (a custom domain that ran 10 generations on a
single-incumbent loop), uniform random parent selection contributed to mode
collapse: only 4 distinct child variants emerged across 10 generations. While
that was partly attributable to the calling code, the framework documentation
implies a smarter selection strategy than is actually implemented.

Proposed fix

I have a PR ready that implements Option A (novelty-weighted sampling), with
backward-compatible API and a deterministic unit test. Happy to open it
immediately if maintainers agree on the direction.

Environment

  • HyperAgents commit: main HEAD as of 2026-05-03
  • File: select_next_parent.py lines 50-57

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions