Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Swap move selector applies entity value range filtering to entity classes without entity-level ranges

Aperta
#2,761 0 commenti 0 reazioni 1 assegnatario Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

@zepfred ci sta già lavorando.

Dal 15/10/2026.

Valutazione

Questa issue non è ancora stata valutata.

Descrizione

process/needs triage

Summary

Once any basic variable in the model has an entity-level value range, the default swap move selector
turns on entity value range filtering for every entity class with basic variables, including classes
whose variables only have solution-level ranges. Local search then crashes when it starts.

List variables are not affected: only basic variables are checked.

Error

java.lang.IllegalStateException: Impossible state: no basic variable found for the entity class org.acme.projectjobschedule.domain.ProjectLead.
	at ai.timefold.solver.core.impl.heuristic.selector.entity.decorator.FilteringEntityByEntitySelector.phaseStarted(FilteringEntityByEntitySelector.java:104)
	...
	at ai.timefold.solver.core.impl.neighborhood.MoveSelectorBasedMoveRepository.phaseStarted(MoveSelectorBasedMoveRepository.java:43)
	at ai.timefold.solver.core.impl.localsearch.decider.LocalSearchDecider.phaseStarted(LocalSearchDecider.java:78)
	at ai.timefold.solver.core.impl.localsearch.DefaultLocalSearchPhase.phaseStarted(DefaultLocalSearchPhase.java:136)
	at ai.timefold.solver.core.impl.localsearch.DefaultLocalSearchPhase.solve(DefaultLocalSearchPhase.java:76)

Root cause

SwapMoveSelectorFactory.java (lines 44-47) decides whether to enable entity value range filtering by
looking at all basic variables in the solution, not just those of the entity class being swapped:

var entityDescriptor = deduceEntityDescriptor(configPolicy, entitySelectorConfig.getEntityClass());
var enableEntityValueRangeFilter = entityDescriptor.getSolutionDescriptor().getBasicVariableDescriptorList()
        .stream()
        .anyMatch(v -> !v.canExtractValueRangeFromSolution());

The default swap move selector is unfolded into one child selector per entity class with basic variables.
For an entity class whose variables all have solution-level ranges, the check above still returns true
because of another entity class, so a recorder ID is set and the right entity selector is wrapped in
FilteringEntityByEntitySelector. That selector then finds no entity-level range on this class and throws.

Suggested fix

Scope the check to the entity class being swapped (ideally to the variables the selector actually uses,
honoring variableNameIncludeList):

var enableEntityValueRangeFilter = deduceBasicVariableDescriptorList(entityDescriptor, config.getVariableNameIncludeList())
        .stream()
        .anyMatch(v -> !v.canExtractValueRangeFromSolution());

Reproducer

Quickstart use-cases/project-job-scheduling, branch bug/reproduce-multi-entity-value-range:

  • Allocation (existing) has basic variables with entity-level ranges (executionMode, delay).
  • ProjectLead (new) has a basic variable resource whose range comes from the solution
    (@ValueRangeProvider on ProjectJobSchedule.resources).
  • MultiEntityValueRangeReproducerTest solves for 5 seconds without a best score limit, so the
    local search phase runs and crashes.

Note: the existing SolverManagerTest does not catch this because the test profile's best score limit
ends the solve before local search starts.

Workaround

Give every other entity class with basic variables an entity-level range too, even if it just lists every
value:

@ValueRangeProvider
public List<Resource> getResourceRange() {
    return resourceRange; // all resources
}

With this in place, the reproducer passes and local search runs normally.

Environment

  • Reproduced with the local timefold-solver 999-SNAPSHOT (built 2026-10-12); the same code is on
    solver main. Reported against 2.7.
Lingua principale
Java
Stelle
1.8k
Fork
238
Merge medio
3g 2h
PR unite (30g)
59

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di TimefoldAI/timefold-solver

Tutte le issue di TimefoldAI/timefold-solver

Issue simili

Altre issue su Java

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.