Skip to content

Bug: ElementSimilarityDiffElementAligner scores Modify against the wrong sub-alignment #22

Description

@lassevk

In ElementSimilarityDiffElementAligner<T>.CalculateBestAlignment (src/DiffLib/Alignment/ElementSimilarityAligner.cs:171), the Modify candidate node is built like this:

AlignmentNode restAfterInsert = CalculateBestAlignment(nodes, collection1, lower1, upper1, collection2, lower2 + 1, upper2);
// ...
AlignmentNode restAfterChange = CalculateBestAlignment(nodes, collection1, lower1 + 1, upper1, collection2, lower2 + 1, upper2);
double similarity = _SimilarityFunc(collection1[lower1], collection2[lower2]);
AlignmentNode? resultChange = null;
if (similarity >= _ModificationThreshold)
    resultChange = new AlignmentNode(DiffOperation.Modify, similarity + restAfterInsert.Similarity, restAfterChange.NodeCount + 1, restAfterChange);

A Modify consumes one element from each collection, so its continuation is restAfterChange (which is correctly used as Next and for NodeCount). But the cumulative Similarity is computed as similarity + restAfterInsert.Similarity — the similarity total of the insert branch, which advanced only collection2.

So the node's Similarity/AverageSimilarity (used to pick the winning operation) does not correspond to the path actually linked via Next. It should be:

resultChange = new AlignmentNode(DiffOperation.Modify, similarity + restAfterChange.Similarity, restAfterChange.NodeCount + 1, restAfterChange);

Impact: the aligner can pick a suboptimal operation (insert+delete vs. modify, or the wrong modify position) because the score it compares is inconsistent with the alignment it stores. It happens to not change the outcome on the current small test cases, which is why nothing failed — see the related testing-gap issue.

This looks like a copy/paste slip (restAfterInsert where restAfterChange was meant).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions