Skip to content

perf(constraint-streams): fused equal indexer#2346

Merged
triceo merged 15 commits into
TimefoldAI:mainfrom
triceo:fused
Jun 11, 2026
Merged

perf(constraint-streams): fused equal indexer#2346
triceo merged 15 commits into
TimefoldAI:mainfrom
triceo:fused

Conversation

@triceo

@triceo triceo commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Optimizes equal-join-heavy workloads by cutting HashMap lookups by 50+ percent. For increased efficiency, reorders joiners so that all equal() joiners come before any others.

@triceo triceo marked this pull request as ready for review June 10, 2026 11:32
Copilot AI review requested due to automatic review settings June 10, 2026 11:32
@triceo triceo self-assigned this Jun 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 improves performance of equal-join-heavy Constraint Streams by reordering joiners so all EQUAL joiners come first and by introducing a unified “fused equal” indexing structure that reduces cross-side lookups.

Changes:

  • Add equal-first joiner reordering (reorderedEqualsFirst()) across bi/tri/quad/penta joiners (and neighborhoods), backed by a shared AbstractJoiner.equalsFirstOrder(...) primitive.
  • Introduce FusedEqualIndex and update indexed join/ifExists nodes to optionally use a unified equal-bucket map (with bucket caching and reuse on suffix-only key changes).
  • Rename/refactor index “backends” into LeafIndexer and expand/adjust indexing tests to cover the new routing and behavior.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
core/src/test/java/ai/timefold/solver/core/impl/bavet/common/joiner/EqualsFirstReorderTest.java New tests for equal-first reordering behavior and equality semantics.
core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/RandomAccessLeafIndexerTest.java Fix test class name and update instantiation to renamed leaf indexer.
core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/FusedEqualIndexTest.java New tests covering fused equal bucket semantics and lazy allocation.
core/src/test/java/ai/timefold/solver/core/impl/bavet/common/index/ComparisonIndexerTest.java New tests ensuring pure-comparison joins route to non-fused indexing and still behave correctly.
core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/joiner/DefaultBiNeighborhoodsJoiner.java Add equal-first reorder capability for neighborhood joiners.
core/src/main/java/ai/timefold/solver/core/impl/neighborhood/stream/joiner/BiNeighborhoodsJoinerComber.java Apply equal-first reordering during merge for neighborhood joiners.
core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/joiner/TriJoinerComber.java Switch to varargs, add nullness, compute equal-first on read, and add addJoiner.
core/src/main/java/ai/timefold/solver/core/impl/bavet/tri/joiner/DefaultTriJoiner.java Add equal-first reorder method and modernize merge/and/matches implementations.
core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/joiner/QuadJoinerComber.java Switch to varargs, add nullness, compute equal-first on read, and add addJoiner.
core/src/main/java/ai/timefold/solver/core/impl/bavet/quad/joiner/DefaultQuadJoiner.java Add equal-first reorder method and modernize merge/and/matches implementations.
core/src/main/java/ai/timefold/solver/core/impl/bavet/penta/joiner/PentaJoinerComber.java Return equal-first reordered merged joiner.
core/src/main/java/ai/timefold/solver/core/impl/bavet/penta/joiner/DefaultPentaJoiner.java Add equal-first reorder method.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/joiner/AbstractJoiner.java Add shared stable permutation helper equalsFirstOrder(...).
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/SingleKeyUnpacker.java Remove old unpacker implementation (replaced by KeyUnpacker.single()).
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/RandomAccessLeafIndexer.java Rename implementation from backend to leaf indexer and update Javadoc.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/package-info.java Expand package-level documentation describing indexing pipeline and fused/non-fused paths.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/LinkedListLeafIndexer.java Rename implementation from backend to leaf indexer.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/LeafIndexer.java Rename sealed interface and update permitted implementations.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/KeyUnpacker.java Replace sealed interface + records with a functional interface and static factory methods.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/IndexerFactory.java Rework indexer level construction around equal-prefix, add fused-equal eligibility and builder, and update key extractors.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/Indexer.java Update sealed permits to include LeafIndexer instead of the former backend type.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/FusedEqualIndex.java New unified equal-prefix bucketed index with lazy downstream allocation and bucket cleanup.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/EqualIndexer.java Update Javadoc terminology to leaf indexer.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/ContainingIndexer.java Update Javadoc terminology to leaf indexer.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/ContainingAnyOfIndexer.java Update Javadoc terminology to leaf indexer.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/ContainedInIndexer.java Update Javadoc terminology to leaf indexer.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/CompositeKeyUnpacker.java Remove old unpacker implementation (replaced by KeyUnpacker.composite(...)).
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/index/ComparisonIndexer.java Update Javadoc terminology to leaf indexer.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedJoinNode.java Add fused-equal indexing path with bucket caching/reuse and shared-bucket iteration.
core/src/main/java/ai/timefold/solver/core/impl/bavet/common/AbstractIndexedIfExistsNode.java Add fused-equal indexing path with bucket caching/reuse and shared-bucket iteration for counters/tuples.
core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/joiner/DefaultBiJoiner.java Add equal-first reorder method and modernize merge/and/matches implementations.
core/src/main/java/ai/timefold/solver/core/impl/bavet/bi/joiner/BiJoinerComber.java Switch to varargs, add nullness, compute equal-first on read, and add addJoiner.

Copilot AI review requested due to automatic review settings June 11, 2026 05:33
@triceo triceo requested a review from TomCools as a code owner June 11, 2026 05:33
@triceo triceo added this to the v2.2.0 milestone Jun 11, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 33 out of 33 changed files in this pull request and generated 3 comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 33 out of 33 changed files in this pull request and generated 1 comment.

@sonarqubecloud

Copy link
Copy Markdown

@triceo triceo merged commit a682654 into TimefoldAI:main Jun 11, 2026
22 checks passed
@triceo triceo deleted the fused branch June 11, 2026 07:20
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.

3 participants