Skip to content

Add LIS-based differentiator for minimal child reordering mutations (#56094)#56094

Closed
javache wants to merge 1 commit intofacebook:mainfrom
javache:export-D96334873
Closed

Add LIS-based differentiator for minimal child reordering mutations (#56094)#56094
javache wants to merge 1 commit intofacebook:mainfrom
javache:export-D96334873

Conversation

@javache
Copy link
Member

@javache javache commented Mar 13, 2026

Summary:

The current Differentiator Stage 4 uses a greedy two-pointer algorithm to
reconcile reordered children. When children are shuffled, it produces excessive
REMOVE+INSERT pairs because it doesn't find the minimal edit.

This adds an alternative code path that uses Longest Increasing Subsequence
(LIS) to identify which children can stay in place vs which need to be moved.
Items in the LIS maintain their relative order — only items outside the LIS
need REMOVE+INSERT.

Example: moving last element to front [A,B,C,D,E] → [E,A,B,C,D]:

  • Greedy: 4 REMOVEs + 5 INSERTs = 9 mutations
  • LIS: LIS=[A,B,C,D], only E moves = 1 REMOVE + 1 INSERT = 2 mutations

The LIS algorithm is O(n log n) time, O(n) space. Since average child count
is <10, the position mapping uses linear scan instead of hash tables.

Guarded by useLISAlgorithmInDifferentiator feature flag (default off).

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D96334873

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Mar 13, 2026
@meta-codesync
Copy link

meta-codesync bot commented Mar 13, 2026

@javache has exported this pull request. If you are a Meta employee, you can view the originating Diff in D96334873.

@facebook-github-tools facebook-github-tools bot added the p: Facebook Partner: Facebook label Mar 13, 2026
@meta-codesync meta-codesync bot changed the title Add LIS-based differentiator for minimal child reordering mutations Add LIS-based differentiator for minimal child reordering mutations (#56094) Mar 14, 2026
javache added a commit to javache/react-native that referenced this pull request Mar 14, 2026
…acebook#56094)

Summary:

The current Differentiator Stage 4 uses a greedy two-pointer algorithm to
reconcile reordered children. When children are shuffled, it produces excessive
REMOVE+INSERT pairs because it doesn't find the minimal edit.

This adds an alternative code path that uses Longest Increasing Subsequence
(LIS) to identify which children can stay in place vs which need to be moved.
Items in the LIS maintain their relative order — only items outside the LIS
need REMOVE+INSERT.

Example: moving last element to front [A,B,C,D,E] → [E,A,B,C,D]:
- Greedy: 4 REMOVEs + 5 INSERTs = 9 mutations
- LIS: LIS=[A,B,C,D], only E moves = 1 REMOVE + 1 INSERT = 2 mutations

The LIS algorithm is O(n log n) time, O(n) space. Since average child count
is <10, the position mapping uses linear scan instead of hash tables.

Guarded by `useLISAlgorithmInDifferentiator` feature flag (default off).

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D96334873
javache added a commit to javache/react-native that referenced this pull request Mar 14, 2026
…acebook#56094)

Summary:
Pull Request resolved: facebook#56094

The current Differentiator Stage 4 uses a greedy two-pointer algorithm to
reconcile reordered children. When children are shuffled, it produces excessive
REMOVE+INSERT pairs because it doesn't find the minimal edit.

This adds an alternative code path that uses Longest Increasing Subsequence
(LIS) to identify which children can stay in place vs which need to be moved.
Items in the LIS maintain their relative order — only items outside the LIS
need REMOVE+INSERT.

Example: moving last element to front [A,B,C,D,E] → [E,A,B,C,D]:
- Greedy: 4 REMOVEs + 5 INSERTs = 9 mutations
- LIS: LIS=[A,B,C,D], only E moves = 1 REMOVE + 1 INSERT = 2 mutations

The LIS algorithm is O(n log n) time, O(n) space. Since average child count
is <10, the position mapping uses linear scan instead of hash tables.

Guarded by `useLISAlgorithmInDifferentiator` feature flag (default off).

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D96334873
@javache javache force-pushed the export-D96334873 branch 2 times, most recently from 204e70a to 6b4b8da Compare March 16, 2026 11:48
javache added a commit to javache/react-native that referenced this pull request Mar 16, 2026
…acebook#56094)

Summary:

The current Differentiator Stage 4 uses a greedy two-pointer algorithm to
reconcile reordered children. When children are shuffled, it produces excessive
REMOVE+INSERT pairs because it doesn't find the minimal edit.

This adds an alternative code path that uses Longest Increasing Subsequence
(LIS) to identify which children can stay in place vs which need to be moved.
Items in the LIS maintain their relative order — only items outside the LIS
need REMOVE+INSERT.

Example: moving last element to front [A,B,C,D,E] → [E,A,B,C,D]:
- Greedy: 4 REMOVEs + 5 INSERTs = 9 mutations
- LIS: LIS=[A,B,C,D], only E moves = 1 REMOVE + 1 INSERT = 2 mutations

The LIS algorithm is O(n log n) time, O(n) space. Since average child count
is <10, the position mapping uses linear scan instead of hash tables.

Guarded by `useLISAlgorithmInDifferentiator` feature flag (default off).

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D96334873
…acebook#56094)

Summary:
Pull Request resolved: facebook#56094

The current Differentiator Stage 4 uses a greedy two-pointer algorithm to
reconcile reordered children. When children are shuffled, it produces excessive
REMOVE+INSERT pairs because it doesn't find the minimal edit.

This adds an alternative code path that uses Longest Increasing Subsequence
(LIS) to identify which children can stay in place vs which need to be moved.
Items in the LIS maintain their relative order — only items outside the LIS
need REMOVE+INSERT.

Example: moving last element to front [A,B,C,D,E] → [E,A,B,C,D]:
- Greedy: 4 REMOVEs + 5 INSERTs = 9 mutations
- LIS: LIS=[A,B,C,D], only E moves = 1 REMOVE + 1 INSERT = 2 mutations

The LIS algorithm is O(n log n) time, O(n) space. Since average child count
is <10, the position mapping uses linear scan instead of hash tables.

Guarded by `useLISAlgorithmInDifferentiator` feature flag (default off).

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D96334873
@meta-codesync meta-codesync bot closed this in 44ac8c2 Mar 16, 2026
@react-native-bot
Copy link
Collaborator

This pull request was successfully merged by @javache in 44ac8c2

When will my fix make it into a release? | How to file a pick request?

@facebook-github-tools facebook-github-tools bot added the Merged This PR has been merged. label Mar 16, 2026
@meta-codesync
Copy link

meta-codesync bot commented Mar 16, 2026

This pull request has been merged in 44ac8c2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported Merged This PR has been merged. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants