Skip to content

Fix two Neighborhoods bugs#2314

Open
triceo wants to merge 2 commits into
TimefoldAI:mainfrom
triceo:neighborhoods-bugs
Open

Fix two Neighborhoods bugs#2314
triceo wants to merge 2 commits into
TimefoldAI:mainfrom
triceo:neighborhoods-bugs

Conversation

@triceo
Copy link
Copy Markdown
Collaborator

@triceo triceo commented May 22, 2026

See attached issue for a description of what was wrong.
Independent bugs, independent commits. Will not be squashed.

Copilot AI review requested due to automatic review settings May 22, 2026 11:17
@triceo triceo linked an issue May 22, 2026 that may be closed by this pull request
@triceo triceo self-assigned this May 22, 2026
@triceo triceo requested a review from zepfred May 22, 2026 11:22
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses two independent defects by (1) fixing neighborhood stream iteration state handling to avoid persisting invalid iterators across solver steps, and (2) changing multiple config classes to store class references as class-name strings (resolved lazily) so config I/O remains stable and inheritance works on raw configured values.

Changes:

  • Removed tuple-store-based caching of right-side iterators and replaced it with iterator-local caching in BiRandomMoveIterator.
  • Simplified left dataset instantiation by removing the now-unused “right iterator store index” plumbing.
  • Introduced ConfigUtils.resolveClass(...) and updated many config classes to store class names (String) instead of Class<?>, resolving on demand in getters/visitors.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDatasetInstance.java Updates constructor/signature to match removal of right-iterator store index.
core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/UniLeftDataset.java Updates dataset instantiation API to only reserve/pass entry store index.
core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/uni/LeftTerminalUniEnumeratingStream.java Reserves a single tuple store index for left dataset instance creation.
core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDatasetInstance.java Removes right-iterator store index field/accessor.
core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/enumerating/common/AbstractLeftDataset.java Updates abstract instantiate signature to reflect removed index.
core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/BiRandomMoveIterator.java Fixes iterator caching scope by storing right iterators in a local map instead of tuple store.
core/src/main/java/ai/timefold/solver/core/config/util/ConfigUtils.java Adds resolveClass(...) helper for lazy class resolution from stored class-name strings.
core/src/main/java/ai/timefold/solver/core/config/solver/SolverManagerConfig.java Stores threadFactoryClass as string; resolves lazily in getter/visitor/inheritance.
core/src/main/java/ai/timefold/solver/core/config/solver/SolverConfig.java Stores threadFactoryClass, solutionClass, entityClassList, nearbyDistanceMeterClass as strings; resolves lazily and inherits raw values.
core/src/main/java/ai/timefold/solver/core/config/score/director/ScoreDirectorFactoryConfig.java Stores calculator/provider classes as strings; resolves lazily and inherits raw values.
core/src/main/java/ai/timefold/solver/core/config/phase/custom/CustomPhaseConfig.java Stores custom phase command classes as strings; resolves lazily and inherits raw values.
core/src/main/java/ai/timefold/solver/core/config/partitionedsearch/PartitionedSearchPhaseConfig.java Stores partitioner class as string; resolves lazily and inherits raw value.
core/src/main/java/ai/timefold/solver/core/config/localsearch/LocalSearchPhaseConfig.java Stores neighborhood provider class as string; resolves lazily and inherits raw value.
core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/value/ValueSelectorConfig.java Stores several selector-related classes as strings; resolves lazily and inherits raw values.
core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/MultistageMoveSelectorConfig.java Stores stage provider/entity classes as strings; resolves lazily and inherits raw values.
core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/generic/list/ListMultistageMoveSelectorConfig.java Stores stage provider class as string; resolves lazily and inherits raw value.
core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveListFactoryConfig.java Stores move list factory class as string; resolves lazily and inherits raw value.
core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/factory/MoveIteratorFactoryConfig.java Stores move iterator factory class as string; resolves lazily and inherits raw value.
core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/move/composite/UnionMoveSelectorConfig.java Stores probability weight factory class as string; resolves lazily and inherits raw value.
core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/entity/EntitySelectorConfig.java Stores selector-related classes as strings; resolves lazily (but toString() now resolves too).
core/src/main/java/ai/timefold/solver/core/config/heuristic/selector/common/nearby/NearbySelectionConfig.java Stores nearby distance meter class as string; resolves lazily and inherits raw value.
core/src/main/java/ai/timefold/solver/core/config/constructionheuristic/placer/QueuedValuePlacerConfig.java Stores entity class as string; resolves lazily and inherits raw value.

Comment on lines 342 to 345
@Override
public String toString() {
return getClass().getSimpleName() + "(" + entityClass + ")";
return getClass().getSimpleName() + "(" + getEntityClass() + ")";
}
Comment on lines +58 to +65
var tccl = Thread.currentThread().getContextClassLoader();
var cl = tccl != null ? tccl : ConfigUtils.class.getClassLoader();
try {
return (Class<T>) Class.forName(trimmedClassName, true, cl);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException(
"The %s (%s) of %s cannot be found.".formatted(fieldName, trimmedClassName, context), e);
}
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
62.1% Coverage on New Code (required ≥ 70%)
12.0% Duplication on New Code (required ≤ 5%)
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

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.

Improve error message: misconfigured neighborhood feature.

2 participants