From 1b540948abde4a71027233c4dbaf4cac4776e60d Mon Sep 17 00:00:00 2001 From: piameier Date: Thu, 17 Jul 2025 17:57:42 +0200 Subject: [PATCH 001/162] basic patching idea --- .../thesis_pm/PatchingExperiment.java | 177 ++++++++++++++++++ .../variation/diff/patching/Patching.java | 5 + 2 files changed, 182 insertions(+) create mode 100644 src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java create mode 100644 src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java new file mode 100644 index 000000000..6854f5c70 --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -0,0 +1,177 @@ +package org.variantsync.diffdetective.experiments.thesis_pm; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.variantsync.diffdetective.diff.result.DiffParseException; +import org.variantsync.diffdetective.show.Show; +import org.variantsync.diffdetective.show.engine.GameEngine; +import org.variantsync.diffdetective.util.fide.FixTrueFalse.Formula; +import org.variantsync.diffdetective.variation.DiffLinesLabel; +import org.variantsync.diffdetective.variation.diff.DiffNode; +import org.variantsync.diffdetective.variation.diff.DiffType; +import org.variantsync.diffdetective.variation.diff.Time; +import org.variantsync.diffdetective.variation.diff.VariationDiff; +import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; +import org.variantsync.diffdetective.variation.diff.view.DiffView; +import org.variantsync.diffdetective.variation.tree.VariationTree; +import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; +import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; + +public class PatchingExperiment { + + private static Relevance calculateFeatureSetToDeselect(VariationTree variant1, VariationTree variant2, boolean debug) { + Set featuresTreeV1 = new HashSet(); + variant1.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + Set featuresTreeV2 = new HashSet(); + variant2.forAllPreorder(node -> {featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + + Set intersectSet1 = new HashSet<>(featuresTreeV1); + intersectSet1.removeAll(featuresTreeV2); + Set intersectSet2 = new HashSet<>(featuresTreeV2); + intersectSet2.removeAll(featuresTreeV1); + intersectSet1.addAll(intersectSet2); + + if (debug) { + System.out.println(featuresTreeV1); + System.out.println(featuresTreeV2); + System.out.println(intersectSet1); + } + + + Formula[] f = new Formula[intersectSet1.size()]; + Iterator iterator = intersectSet1.iterator(); + for (int i = 0; i < f.length; i++) { + f[i] = Formula.not(Formula.var(iterator.next())); + } + Formula formula = Formula.and(f); + + if (debug) System.out.println(formula.get().toString()); + + Relevance rho = new Configure(formula); + return rho; + } + + private static Set> findRootsOfSubtrees(Set> nodes, boolean debug) { + Set> subtreeRoots = new HashSet>(); + for (DiffNode node : nodes) { + if (!nodes.contains(node.getParent(Time.AFTER))) { + subtreeRoots.add(node); + } + } + if (debug) System.out.println(subtreeRoots); + + return subtreeRoots; + } + + private static void patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { + if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { + System.out.println("Parsing error"); + return; + } + + VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); + Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, targetVariant, false); + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + + // add new nodes + Set> addedNodes = new HashSet>(); + optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); + + // find roots of subtrees of added nodes + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, false); + + VariationDiff targetVariantDiff = VariationDiff.fromTrees(targetVariant, targetVariant); + for (DiffNode root : addedSubtreeRoots) { + VariationDiff subTree = new VariationDiff(root.deepCopy(), optimizedDiff.getSource()); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + List> targetNodes = new ArrayList>(); + if (root.isArtifact()) { + targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getPresenceCondition(Time.AFTER)) && node.isAnnotation()); + } else if (root.isAnnotation()) { + targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getParent(Time.AFTER).getPresenceCondition(Time.AFTER)) && node.isAnnotation()); + } + + if (targetNodes.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + System.out.println("subtree added"); + targetNodes.get(0).addChild(root.deepCopy(), Time.AFTER); + } + } + + // remove old nodes + Set> removedNodes = new HashSet>(); + optimizedDiff.forAll(node -> {if (node.isRem()) {removedNodes.add(node);}}); + + Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, false); + +// VariationDiff targetVariantDiff2 = VariationDiff.fromTrees(targetVariant, targetVariant); + for (DiffNode root : removedSubtreeRoots) { + VariationDiff subTree = new VariationDiff(root.deepCopy(), optimizedDiff.getSource()); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + List> targetNodes = new ArrayList>(); + if (root.isArtifact()) { + targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getPresenceCondition(Time.BEFORE)) && node.isAnnotation()); + } else if (root.isAnnotation()) { + targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getParent(Time.BEFORE).getPresenceCondition(Time.BEFORE)) && node.isAnnotation()); + } + if (targetNodes.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + +// System.out.println(targetNodes.get(0)); + DiffNode parent = targetNodes.get(0); + List> nodesToRem = new ArrayList>(); + parent.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, Time.BEFORE)) nodesToRem.add(node);}); + if (nodesToRem.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + System.out.println("subtree removed"); + nodesToRem.get(0).diffType = DiffType.REM; + nodesToRem.get(0).drop(Time.AFTER); + } + } + } + + GameEngine.showAndAwaitAll( + Show.tree(sourceVariantVersion1), + Show.tree(sourceVariantVersion2), + Show.tree(targetVariant), + Show.diff(optimizedDiff), + Show.diff(targetVariantDiff) + ); + + } + + private static VariationTree parseVariationTreeFromFile(String file) { + Path examplesDir = Path.of("data", "examples"); + Path path = examplesDir.resolve(file); + try { + VariationTree tree = VariationTree.fromFile( + path, + VariationDiffParseOptions.Default + ); + return tree; + } catch (IOException e) { + e.printStackTrace(); + } catch (DiffParseException e) { + e.printStackTrace(); + } + return null; + } + + public static void main(String[] args) { + patchVariationTrees(parseVariationTreeFromFile("exampleA1.cpp"), parseVariationTreeFromFile("exampleA2.cpp"), parseVariationTreeFromFile("exampleB.cpp")); + } + +} diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java new file mode 100644 index 000000000..0baed5e9d --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -0,0 +1,5 @@ +package org.variantsync.diffdetective.variation.diff.patching; + +public class Patching { + +} From 692d6c6cc4ca4bb7674fd4e1e785ed03e1be54fb Mon Sep 17 00:00:00 2001 From: piameier Date: Sat, 19 Jul 2025 18:03:21 +0200 Subject: [PATCH 002/162] code refactoring --- .../thesis_pm/PatchingExperiment.java | 118 +++++++++--------- 1 file changed, 57 insertions(+), 61 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 6854f5c70..c80b96e2c 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -18,6 +18,7 @@ import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; +import org.variantsync.diffdetective.variation.diff.source.VariationDiffSource; import org.variantsync.diffdetective.variation.diff.view.DiffView; import org.variantsync.diffdetective.variation.tree.VariationTree; import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; @@ -25,9 +26,12 @@ public class PatchingExperiment { - private static Relevance calculateFeatureSetToDeselect(VariationTree variant1, VariationTree variant2, boolean debug) { + private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { Set featuresTreeV1 = new HashSet(); - variant1.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + variant1version1.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + if (variant1version2 != null) { + variant1version2.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + } Set featuresTreeV2 = new HashSet(); variant2.forAllPreorder(node -> {featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); @@ -69,88 +73,80 @@ private static Set> findRootsOfSubtrees(Set sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { - if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { - System.out.println("Parsing error"); - return; - } + private static void applyChanges(DiffType type, VariationDiff targetVariantDiff, Set> subtreeRoots, VariationDiffSource source, boolean debug) { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; - VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, targetVariant, false); - VariationDiff optimizedDiff = DiffView.optimized(diff, rho); - - // add new nodes - Set> addedNodes = new HashSet>(); - optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); - - // find roots of subtrees of added nodes - Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, false); - - VariationDiff targetVariantDiff = VariationDiff.fromTrees(targetVariant, targetVariant); - for (DiffNode root : addedSubtreeRoots) { - VariationDiff subTree = new VariationDiff(root.deepCopy(), optimizedDiff.getSource()); - GameEngine.showAndAwaitAll(Show.diff(subTree)); + for (DiffNode root : subtreeRoots) { + if (debug) { + VariationDiff subTree = new VariationDiff(root.deepCopy(), source); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + } + List> targetNodes = new ArrayList>(); if (root.isArtifact()) { targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getPresenceCondition(Time.AFTER)) && node.isAnnotation()); + .equals(root.getPresenceCondition(time)) && node.isAnnotation()); } else if (root.isAnnotation()) { targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getParent(Time.AFTER).getPresenceCondition(Time.AFTER)) && node.isAnnotation()); + .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } if (targetNodes.size() != 1) { System.out.println("too much or too less target nodes found"); } else { - System.out.println("subtree added"); - targetNodes.get(0).addChild(root.deepCopy(), Time.AFTER); + if (type == DiffType.ADD) { + System.out.println("subtree added"); + targetNodes.get(0).addChild(root.deepCopy(), Time.AFTER); + System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); + } else if (type == DiffType.REM) { + DiffNode parent = targetNodes.get(0); + List> nodesToRem = new ArrayList>(); + parent.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, Time.BEFORE)) nodesToRem.add(node);}); + if (nodesToRem.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + System.out.println("subtree removed"); + nodesToRem.get(0).diffType = DiffType.REM; + nodesToRem.get(0).drop(Time.AFTER); + System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); + } + } } } - - // remove old nodes + } + + + private static void patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { + if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { + System.out.println("Parsing error"); + return; + } + + VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); + Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, false); + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + VariationDiffSource source = optimizedDiff.getSource(); + VariationDiff targetVariantDiff = targetVariant.toCompletelyUnchangedVariationDiff(); + + // add new nodes + Set> addedNodes = new HashSet>(); + optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, false); + applyChanges(DiffType.ADD, targetVariantDiff, addedSubtreeRoots, source, false); + // remove old nodes Set> removedNodes = new HashSet>(); optimizedDiff.forAll(node -> {if (node.isRem()) {removedNodes.add(node);}}); - Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, false); - -// VariationDiff targetVariantDiff2 = VariationDiff.fromTrees(targetVariant, targetVariant); - for (DiffNode root : removedSubtreeRoots) { - VariationDiff subTree = new VariationDiff(root.deepCopy(), optimizedDiff.getSource()); - GameEngine.showAndAwaitAll(Show.diff(subTree)); - List> targetNodes = new ArrayList>(); - if (root.isArtifact()) { - targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getPresenceCondition(Time.BEFORE)) && node.isAnnotation()); - } else if (root.isAnnotation()) { - targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getParent(Time.BEFORE).getPresenceCondition(Time.BEFORE)) && node.isAnnotation()); - } - if (targetNodes.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - -// System.out.println(targetNodes.get(0)); - DiffNode parent = targetNodes.get(0); - List> nodesToRem = new ArrayList>(); - parent.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, Time.BEFORE)) nodesToRem.add(node);}); - if (nodesToRem.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - System.out.println("subtree removed"); - nodesToRem.get(0).diffType = DiffType.REM; - nodesToRem.get(0).drop(Time.AFTER); - } - } - } + applyChanges(DiffType.REM, targetVariantDiff, removedSubtreeRoots, source, false); GameEngine.showAndAwaitAll( Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), Show.tree(targetVariant), Show.diff(optimizedDiff), - Show.diff(targetVariantDiff) + Show.diff(targetVariantDiff), + Show.tree(targetVariantDiff.project(Time.AFTER)) ); - } private static VariationTree parseVariationTreeFromFile(String file) { From c35bebc78b80236b4cbdbc6707fdf32e41f57ebe Mon Sep 17 00:00:00 2001 From: piameier Date: Mon, 21 Jul 2025 12:30:52 +0200 Subject: [PATCH 003/162] fixed bugs --- .../thesis_pm/PatchingExperiment.java | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index c80b96e2c..13e9955c5 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -61,10 +61,11 @@ private static Relevance calculateFeatureSetToDeselect(VariationTree> findRootsOfSubtrees(Set> nodes, boolean debug) { + private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, boolean debug) { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; Set> subtreeRoots = new HashSet>(); for (DiffNode node : nodes) { - if (!nodes.contains(node.getParent(Time.AFTER))) { + if (!nodes.contains(node.getParent(time))) { subtreeRoots.add(node); } } @@ -73,7 +74,7 @@ private static Set> findRootsOfSubtrees(Set targetVariantDiff, Set> subtreeRoots, VariationDiffSource source, boolean debug) { + private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, VariationDiff targetVariantDiffPatched, Set> subtreeRoots, VariationDiffSource source, boolean debug) { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; for (DiffNode root : subtreeRoots) { @@ -84,29 +85,35 @@ private static void applyChanges(DiffType type, VariationDiff ta List> targetNodes = new ArrayList>(); if (root.isArtifact()) { - targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getPresenceCondition(time)) && node.isAnnotation()); } else if (root.isAnnotation()) { - targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + System.out.println(root.getParent(time).getPresenceCondition(time)); + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } if (targetNodes.size() != 1) { System.out.println("too much or too less target nodes found"); } else { + DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNodes.get(0).getID()); + System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { System.out.println("subtree added"); - targetNodes.get(0).addChild(root.deepCopy(), Time.AFTER); - System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); + // TODO: check for neighbors and calculate insert position + targetNodeInPatch.addChild(root.deepCopy(), time); + System.out.println(targetNodeInPatch.getChildOrder(time)); } else if (type == DiffType.REM) { - DiffNode parent = targetNodes.get(0); List> nodesToRem = new ArrayList>(); - parent.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, Time.BEFORE)) nodesToRem.add(node);}); + System.out.println("Root: " + root.toString()); + System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); + targetNodeInPatch.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, time)) nodesToRem.add(node);}); if (nodesToRem.size() != 1) { System.out.println("too much or too less target nodes found"); } else { System.out.println("subtree removed"); nodesToRem.get(0).diffType = DiffType.REM; + // TODO: check for neighbors nodesToRem.get(0).drop(Time.AFTER); System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } @@ -126,26 +133,27 @@ private static void patchVariationTrees(VariationTree sourceVari Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, false); VariationDiff optimizedDiff = DiffView.optimized(diff, rho); VariationDiffSource source = optimizedDiff.getSource(); - VariationDiff targetVariantDiff = targetVariant.toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); // add new nodes Set> addedNodes = new HashSet>(); optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); - Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, false); - applyChanges(DiffType.ADD, targetVariantDiff, addedSubtreeRoots, source, false); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); + applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSubtreeRoots, source, false); // remove old nodes Set> removedNodes = new HashSet>(); optimizedDiff.forAll(node -> {if (node.isRem()) {removedNodes.add(node);}}); - Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, false); - applyChanges(DiffType.REM, targetVariantDiff, removedSubtreeRoots, source, false); + Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); + applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSubtreeRoots, source, false); GameEngine.showAndAwaitAll( Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), Show.tree(targetVariant), Show.diff(optimizedDiff), - Show.diff(targetVariantDiff), - Show.tree(targetVariantDiff.project(Time.AFTER)) + Show.diff(targetVariantDiffPatched), + Show.tree(targetVariantDiffPatched.project(Time.AFTER)) ); } @@ -167,7 +175,8 @@ private static VariationTree parseVariationTreeFromFile(String f } public static void main(String[] args) { - patchVariationTrees(parseVariationTreeFromFile("exampleA1.cpp"), parseVariationTreeFromFile("exampleA2.cpp"), parseVariationTreeFromFile("exampleB.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); + patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); } } From 91f3ffa55af200617cc2ca0bd9b6953d1dbd1788 Mon Sep 17 00:00:00 2001 From: piameier Date: Mon, 21 Jul 2025 21:21:57 +0200 Subject: [PATCH 004/162] find insert position for ADD and check neigbors for REM --- .../thesis_pm/PatchingExperiment.java | 134 ++++++++++++++++-- .../variation/diff/patching/Patching.java | 36 +++++ 2 files changed, 157 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 13e9955c5..bc2ca5d98 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -18,12 +18,15 @@ import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; +import org.variantsync.diffdetective.variation.diff.patching.Patching; import org.variantsync.diffdetective.variation.diff.source.VariationDiffSource; import org.variantsync.diffdetective.variation.diff.view.DiffView; import org.variantsync.diffdetective.variation.tree.VariationTree; import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; +import com.github.gumtreediff.actions.Diff; + public class PatchingExperiment { private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { @@ -74,6 +77,102 @@ private static Set> findRootsOfSubtrees(Set root, + DiffNode targetNodeInPatch, DiffNode node) { + + DiffNode neighborBeforeTarget = null; + DiffNode neighborAfterTarget = null; + DiffNode neighborBeforeSource = null; + DiffNode neighborAfterSource = null; + boolean correctBefore = false; + boolean correctAfter = false; + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + if (orderedChildrenTarget.contains(node)) { + int indexTarget = orderedChildrenTarget.indexOf(node); + if ((indexTarget - 1) >= 0) { + neighborBeforeTarget = orderedChildrenTarget.get(indexTarget - 1); + } + if ((indexTarget + 1) < orderedChildrenTarget.size()) { + neighborAfterTarget = orderedChildrenTarget.get(indexTarget + 1); + } + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + int indexSource = orderedChildrenSource.indexOf(root); + if ((indexSource - 1) >= 0) { + neighborBeforeSource = orderedChildrenSource.get(indexSource - 1); + } + if ((indexSource + 1) < orderedChildrenTarget.size()) { + neighborAfterSource = orderedChildrenSource.get(indexSource + 1); + } + if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { + System.out.println("Different neighbors"); + } else if (neighborBeforeSource != null && neighborBeforeTarget != null) { + if (Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { + System.out.println("Same neighbor before"); + correctBefore = true; + } + } else { + System.out.println("No neighbor before"); + correctBefore = true; + } + if ((neighborAfterSource != null && neighborAfterTarget == null) || (neighborAfterSource == null && neighborAfterTarget != null)) { + System.out.println("Different neighbors"); + } else if (neighborAfterSource != null && neighborAfterTarget != null) { + if (Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { + System.out.println("Same neighbor after"); + correctAfter = true; + } + } else { + System.out.println("No neighbor after"); + correctAfter = true; + } + } + return correctBefore && correctAfter; + } + + private static List findInsertPositions(Time time, DiffNode root, + DiffNode targetNodeInPatch) { + List insertPositions = new ArrayList(); + DiffNode neighborBeforeSource = null; + DiffNode neighborAfterSource = null; + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + int indexSource = orderedChildrenSource.indexOf(root); + if ((indexSource - 1) >= 0) { + neighborBeforeSource = orderedChildrenSource.get(indexSource - 1); + } + if ((indexSource + 1) < orderedChildrenTarget.size()) { + neighborAfterSource = orderedChildrenSource.get(indexSource + 1); + } + + for (int i = 0; i < orderedChildrenTarget.size(); i++) { + if (neighborBeforeSource != null && neighborAfterSource != null) { + if ((i + 1) < orderedChildrenTarget.size()) { + boolean correctBefore = Patching.isSameAs(orderedChildrenTarget.get(i), neighborBeforeSource, time); + boolean correctAfter = Patching.isSameAs(orderedChildrenTarget.get(i + 1), neighborAfterSource, time); + if (correctBefore && correctAfter) { + System.out.println("Found insert position"); + insertPositions.add(i + 1); + } else if (correctBefore || correctAfter){ + + } + } + } else if (neighborBeforeSource != null) { + if (Patching.isSameAs(orderedChildrenTarget.get(i), neighborBeforeSource, time)) { + System.out.println("Found insert position"); + insertPositions.add(i + 1); + } + } else if (neighborAfterSource != null) { + if ((i + 1) < orderedChildrenTarget.size()) { + if (Patching.isSameAs(orderedChildrenTarget.get(i + 1), neighborAfterSource, time)) { + System.out.println("Found insert position"); + insertPositions.add(i + 1); + } + } + } + } + return insertPositions; + } + private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, VariationDiff targetVariantDiffPatched, Set> subtreeRoots, VariationDiffSource source, boolean debug) { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; @@ -99,29 +198,38 @@ private static void applyChanges(DiffType type, VariationDiff ta DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNodes.get(0).getID()); System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { - System.out.println("subtree added"); - // TODO: check for neighbors and calculate insert position - targetNodeInPatch.addChild(root.deepCopy(), time); - System.out.println(targetNodeInPatch.getChildOrder(time)); + + List insertPositions = findInsertPositions(time, root, targetNodeInPatch); + if (insertPositions.size() != 1) { + System.out.println("no matching insert position found"); + } else { + System.out.println("subtree added"); + targetNodeInPatch.insertChild(root.deepCopy(), insertPositions.get(0), time); + System.out.println(targetNodeInPatch.getChildOrder(time)); + } + } else if (type == DiffType.REM) { List> nodesToRem = new ArrayList>(); System.out.println("Root: " + root.toString()); System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); - targetNodeInPatch.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, time)) nodesToRem.add(node);}); - if (nodesToRem.size() != 1) { + targetNodeInPatch.getAllChildrenStream().forEach(node -> { if (Patching.isSameAs(node, root, time)) nodesToRem.add(node);}); + System.out.println("Nodes to remove: " + nodesToRem); + + List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream().filter((node) -> checkNeighbors(time, root, targetNodeInPatch, node)).toList(); + + if (nodesToRemAfterCheckingNeighbors.size() != 1) { System.out.println("too much or too less target nodes found"); } else { System.out.println("subtree removed"); - nodesToRem.get(0).diffType = DiffType.REM; - // TODO: check for neighbors - nodesToRem.get(0).drop(Time.AFTER); + nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; + nodesToRemAfterCheckingNeighbors.get(0).getAllChildrenStream().forEach(node -> node.diffType = DiffType.REM); + nodesToRemAfterCheckingNeighbors.get(0).drop(Time.AFTER); System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } } } } - } - + } private static void patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { @@ -175,8 +283,8 @@ private static VariationTree parseVariationTreeFromFile(String f } public static void main(String[] args) { -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); - patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); + patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); } } diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 0baed5e9d..cc5674a9f 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -1,5 +1,41 @@ package org.variantsync.diffdetective.variation.diff.patching; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.variantsync.diffdetective.variation.Label; +import org.variantsync.diffdetective.variation.diff.DiffNode; +import org.variantsync.diffdetective.variation.diff.Time; + public class Patching { + public static boolean isSameAs(DiffNode a, DiffNode b, Time time) { + return isSameAs(a, b, new HashSet<>(), time); + } + + private static boolean isSameAs(DiffNode a, DiffNode b, Set> visited, Time time) { + if (!visited.add(a)) { + return true; + } + + if (!( + a.getNodeType().equals(b.getNodeType()) && +// a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && +// a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && + (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) && + a.getLabel().getLines().equals(b.getLabel().getLines()) + )) { + return false; + } + + Iterator> aIt = a.getAllChildren().iterator(); + Iterator> bIt = b.getAllChildren().iterator(); + while (aIt.hasNext() && bIt.hasNext()) { + if (!isSameAs(aIt.next(), bIt.next(), visited, time)) { + return false; + } + } + return aIt.hasNext() == bIt.hasNext(); + } } From 24cf2bf0b69fba77c84e36142128123168e8513b Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 22 Jul 2025 18:47:28 +0200 Subject: [PATCH 005/162] refactoring checkNeighbors method --- .../thesis_pm/PatchingExperiment.java | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index bc2ca5d98..dc831684b 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -77,56 +77,56 @@ private static Set> findRootsOfSubtrees(Set getChildFromListIfIndexInRange(List> childrenList, int index) { + if (index >= 0 && index < childrenList.size()) { + return childrenList.get(index); + } + return null; + } + private static boolean checkNeighbors(Time time, DiffNode root, DiffNode targetNodeInPatch, DiffNode node) { - DiffNode neighborBeforeTarget = null; - DiffNode neighborAfterTarget = null; - DiffNode neighborBeforeSource = null; - DiffNode neighborAfterSource = null; - boolean correctBefore = false; - boolean correctAfter = false; List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); - if (orderedChildrenTarget.contains(node)) { - int indexTarget = orderedChildrenTarget.indexOf(node); - if ((indexTarget - 1) >= 0) { - neighborBeforeTarget = orderedChildrenTarget.get(indexTarget - 1); - } - if ((indexTarget + 1) < orderedChildrenTarget.size()) { - neighborAfterTarget = orderedChildrenTarget.get(indexTarget + 1); - } - List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - int indexSource = orderedChildrenSource.indexOf(root); - if ((indexSource - 1) >= 0) { - neighborBeforeSource = orderedChildrenSource.get(indexSource - 1); - } - if ((indexSource + 1) < orderedChildrenTarget.size()) { - neighborAfterSource = orderedChildrenSource.get(indexSource + 1); - } - if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { - System.out.println("Different neighbors"); - } else if (neighborBeforeSource != null && neighborBeforeTarget != null) { - if (Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { - System.out.println("Same neighbor before"); - correctBefore = true; - } - } else { - System.out.println("No neighbor before"); - correctBefore = true; - } - if ((neighborAfterSource != null && neighborAfterTarget == null) || (neighborAfterSource == null && neighborAfterTarget != null)) { - System.out.println("Different neighbors"); - } else if (neighborAfterSource != null && neighborAfterTarget != null) { - if (Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { - System.out.println("Same neighbor after"); - correctAfter = true; - } - } else { - System.out.println("No neighbor after"); - correctAfter = true; + if (!orderedChildrenTarget.contains(node)) { + // TODO: throw exception + return false; + } + int indexTarget = orderedChildrenTarget.indexOf(node); + DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget - 1); + DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget + 1); + + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + int indexSource = orderedChildrenSource.indexOf(root); + DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource - 1); + DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); + + if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { + System.out.println("Different neighbors before"); + return false; + } + if (neighborBeforeSource != null && neighborBeforeTarget != null) { + if (!Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { + System.out.println("Different neighbor before"); + return false; } } - return correctBefore && correctAfter; + // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no neighbor before) + + if ((neighborAfterSource != null && neighborAfterTarget == null) || (neighborAfterSource == null && neighborAfterTarget != null)) { + System.out.println("Different neighbors after"); + return false; + } + if (neighborAfterSource != null && neighborAfterTarget != null) { + if (!Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { + System.out.println("Different neighbors after"); + return false; + } + } + // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no neighbor after) + + return true; + } private static List findInsertPositions(Time time, DiffNode root, @@ -283,8 +283,8 @@ private static VariationTree parseVariationTreeFromFile(String f } public static void main(String[] args) { - patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); + patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); } } From 1b595080a19bf37a20ece494a2e664556c3c8129 Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 22 Jul 2025 19:44:44 +0200 Subject: [PATCH 006/162] refactoring findInsertPosition method and formatting code --- .../thesis_pm/PatchingExperiment.java | 439 ++++++++++-------- 1 file changed, 242 insertions(+), 197 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index dc831684b..0df9a6930 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -25,83 +25,96 @@ import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; -import com.github.gumtreediff.actions.Diff; - public class PatchingExperiment { - - private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { + + private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, + VariationTree variant1version2, VariationTree variant2, boolean debug) { Set featuresTreeV1 = new HashSet(); - variant1version1.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); - if (variant1version2 != null) { - variant1version2.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); - } - Set featuresTreeV2 = new HashSet(); - variant2.forAllPreorder(node -> {featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); - - Set intersectSet1 = new HashSet<>(featuresTreeV1); - intersectSet1.removeAll(featuresTreeV2); - Set intersectSet2 = new HashSet<>(featuresTreeV2); - intersectSet2.removeAll(featuresTreeV1); - intersectSet1.addAll(intersectSet2); - - if (debug) { - System.out.println(featuresTreeV1); - System.out.println(featuresTreeV2); - System.out.println(intersectSet1); - } - - - Formula[] f = new Formula[intersectSet1.size()]; - Iterator iterator = intersectSet1.iterator(); - for (int i = 0; i < f.length; i++) { - f[i] = Formula.not(Formula.var(iterator.next())); - } - Formula formula = Formula.and(f); - - if (debug) System.out.println(formula.get().toString()); - - Relevance rho = new Configure(formula); - return rho; + variant1version1.forAllPreorder(node -> { + featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + if (variant1version2 != null) { + variant1version2.forAllPreorder(node -> { + featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + } + Set featuresTreeV2 = new HashSet(); + variant2.forAllPreorder(node -> { + featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + + Set intersectSet1 = new HashSet<>(featuresTreeV1); + intersectSet1.removeAll(featuresTreeV2); + Set intersectSet2 = new HashSet<>(featuresTreeV2); + intersectSet2.removeAll(featuresTreeV1); + intersectSet1.addAll(intersectSet2); + + if (debug) { + System.out.println(featuresTreeV1); + System.out.println(featuresTreeV2); + System.out.println(intersectSet1); + } + + Formula[] f = new Formula[intersectSet1.size()]; + Iterator iterator = intersectSet1.iterator(); + for (int i = 0; i < f.length; i++) { + f[i] = Formula.not(Formula.var(iterator.next())); + } + Formula formula = Formula.and(f); + + if (debug) + System.out.println(formula.get().toString()); + + Relevance rho = new Configure(formula); + return rho; } - - private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, boolean debug) { + + private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, + boolean debug) { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; Set> subtreeRoots = new HashSet>(); - for (DiffNode node : nodes) { - if (!nodes.contains(node.getParent(time))) { - subtreeRoots.add(node); - } - } - if (debug) System.out.println(subtreeRoots); - - return subtreeRoots; + for (DiffNode node : nodes) { + if (!nodes.contains(node.getParent(time))) { + subtreeRoots.add(node); + } + } + if (debug) + System.out.println(subtreeRoots); + + return subtreeRoots; } - - private static DiffNode getChildFromListIfIndexInRange(List> childrenList, int index) { + + private static DiffNode getChildFromListIfIndexInRange(List> childrenList, + int index) { if (index >= 0 && index < childrenList.size()) { return childrenList.get(index); } return null; } - - private static boolean checkNeighbors(Time time, DiffNode root, - DiffNode targetNodeInPatch, DiffNode node) { - + + private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, + DiffNode node, Time time) { + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); if (!orderedChildrenTarget.contains(node)) { // TODO: throw exception return false; } int indexTarget = orderedChildrenTarget.indexOf(node); - DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget - 1); - DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget + 1); - + DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, + indexTarget - 1); + DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, + indexTarget + 1); + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); int indexSource = orderedChildrenSource.indexOf(root); - DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource - 1); - DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); - - if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { + DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource - 1); + DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource + 1); + + if ((neighborBeforeSource != null && neighborBeforeTarget == null) + || (neighborBeforeSource == null && neighborBeforeTarget != null)) { System.out.println("Different neighbors before"); return false; } @@ -111,180 +124,212 @@ private static boolean checkNeighbors(Time time, DiffNode root, return false; } } - // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no neighbor before) - - if ((neighborAfterSource != null && neighborAfterTarget == null) || (neighborAfterSource == null && neighborAfterTarget != null)) { + // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no + // neighbor before) + + if ((neighborAfterSource != null && neighborAfterTarget == null) + || (neighborAfterSource == null && neighborAfterTarget != null)) { System.out.println("Different neighbors after"); return false; - } + } if (neighborAfterSource != null && neighborAfterTarget != null) { if (!Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { System.out.println("Different neighbors after"); - return false; + return false; } - } - // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no neighbor after) - + } + // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no + // neighbor after) + return true; - + + } + + private static int findPositionOfMatchingNeighborInList(DiffNode neighbor, + List> list, Time time) throws Exception { + ArrayList positions = new ArrayList(); + for (DiffNode node : list) { + if (Patching.isSameAs(neighbor, node, time)) { + positions.add(list.indexOf(node)); + } + } + if (positions.size() == 1) { + return positions.get(0); + } + if (positions.size() > 1) { + // TODO: throw exception? + throw new Exception(); + } + return -1; } - - private static List findInsertPositions(Time time, DiffNode root, - DiffNode targetNodeInPatch) { - List insertPositions = new ArrayList(); - DiffNode neighborBeforeSource = null; - DiffNode neighborAfterSource = null; + + private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, + Time time) throws Exception { + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); int indexSource = orderedChildrenSource.indexOf(root); - if ((indexSource - 1) >= 0) { - neighborBeforeSource = orderedChildrenSource.get(indexSource - 1); + DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource - 1); + DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource + 1); + int indexBefore = -2; + int indexAfter = -2; + + if (neighborBeforeSource != null) { + indexBefore = findPositionOfMatchingNeighborInList(neighborBeforeSource, orderedChildrenTarget, time); + } + if (neighborAfterSource != null) { + indexAfter = findPositionOfMatchingNeighborInList(neighborAfterSource, orderedChildrenTarget, time); + } + if (indexBefore == -2 && indexAfter == -2) { + System.out.println("No neighbors before or after the target"); + return -1; } - if ((indexSource + 1) < orderedChildrenTarget.size()) { - neighborAfterSource = orderedChildrenSource.get(indexSource + 1); + if (indexBefore > -1 && indexAfter > -1) { + if (indexAfter - indexBefore > 1) { + // TODO: Alignment Problem + return -1; + } + return indexBefore; } - - for (int i = 0; i < orderedChildrenTarget.size(); i++) { - if (neighborBeforeSource != null && neighborAfterSource != null) { - if ((i + 1) < orderedChildrenTarget.size()) { - boolean correctBefore = Patching.isSameAs(orderedChildrenTarget.get(i), neighborBeforeSource, time); - boolean correctAfter = Patching.isSameAs(orderedChildrenTarget.get(i + 1), neighborAfterSource, time); - if (correctBefore && correctAfter) { - System.out.println("Found insert position"); - insertPositions.add(i + 1); - } else if (correctBefore || correctAfter){ - + return Math.max(indexBefore, indexAfter); + } + + private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, + VariationDiff targetVariantDiffPatched, Set> subtreeRoots, + VariationDiffSource source, boolean debug) throws Exception { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; + + for (DiffNode root : subtreeRoots) { + if (debug) { + VariationDiff subTree = new VariationDiff(root.deepCopy(), source); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + } + + List> targetNodes = new ArrayList>(); + if (root.isArtifact()) { + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat( + node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) + && node.isAnnotation()); + } else if (root.isAnnotation()) { + System.out.println(root.getParent(time).getPresenceCondition(time)); + targetNodes = targetVariantDiffUnchanged + .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); + } + + if (targetNodes.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + DiffNode targetNodeInPatch = targetVariantDiffPatched + .getNodeWithID(targetNodes.get(0).getID()); + System.out.println(targetNodeInPatch.toString()); + if (type == DiffType.ADD) { + + int insertPosition = findInsertPosition(root, targetNodeInPatch, time); + if (insertPosition < 0) { + System.out.println("no matching insert position found"); + } else { + System.out.println("subtree added"); + targetNodeInPatch.insertChild(root.deepCopy(), insertPosition, time); + System.out.println(targetNodeInPatch.getChildOrder(time)); } - } - } else if (neighborBeforeSource != null) { - if (Patching.isSameAs(orderedChildrenTarget.get(i), neighborBeforeSource, time)) { - System.out.println("Found insert position"); - insertPositions.add(i + 1); - } - } else if (neighborAfterSource != null) { - if ((i + 1) < orderedChildrenTarget.size()) { - if (Patching.isSameAs(orderedChildrenTarget.get(i + 1), neighborAfterSource, time)) { - System.out.println("Found insert position"); - insertPositions.add(i + 1); + + } else if (type == DiffType.REM) { + List> nodesToRem = new ArrayList>(); + System.out.println("Root: " + root.toString()); + System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); + targetNodeInPatch.getAllChildrenStream().forEach(node -> { + if (Patching.isSameAs(node, root, time)) + nodesToRem.add(node); + }); + System.out.println("Nodes to remove: " + nodesToRem); + + List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream() + .filter((node) -> checkNeighbors(node, root, targetNodeInPatch, time)).toList(); + + if (nodesToRemAfterCheckingNeighbors.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + System.out.println("subtree removed"); + nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; + nodesToRemAfterCheckingNeighbors.get(0).getAllChildrenStream() + .forEach(node -> node.diffType = DiffType.REM); + nodesToRemAfterCheckingNeighbors.get(0).drop(Time.AFTER); + System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } } } } - return insertPositions; } - - private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, VariationDiff targetVariantDiffPatched, Set> subtreeRoots, VariationDiffSource source, boolean debug) { - Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; - - for (DiffNode root : subtreeRoots) { - if (debug) { - VariationDiff subTree = new VariationDiff(root.deepCopy(), source); - GameEngine.showAndAwaitAll(Show.diff(subTree)); - } - - List> targetNodes = new ArrayList>(); - if (root.isArtifact()) { - targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getPresenceCondition(time)) && node.isAnnotation()); - } else if (root.isAnnotation()) { - System.out.println(root.getParent(time).getPresenceCondition(time)); - targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); - } - - if (targetNodes.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNodes.get(0).getID()); - System.out.println(targetNodeInPatch.toString()); - if (type == DiffType.ADD) { - - List insertPositions = findInsertPositions(time, root, targetNodeInPatch); - if (insertPositions.size() != 1) { - System.out.println("no matching insert position found"); - } else { - System.out.println("subtree added"); - targetNodeInPatch.insertChild(root.deepCopy(), insertPositions.get(0), time); - System.out.println(targetNodeInPatch.getChildOrder(time)); - } - - } else if (type == DiffType.REM) { - List> nodesToRem = new ArrayList>(); - System.out.println("Root: " + root.toString()); - System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); - targetNodeInPatch.getAllChildrenStream().forEach(node -> { if (Patching.isSameAs(node, root, time)) nodesToRem.add(node);}); - System.out.println("Nodes to remove: " + nodesToRem); - - List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream().filter((node) -> checkNeighbors(time, root, targetNodeInPatch, node)).toList(); - - if (nodesToRemAfterCheckingNeighbors.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - System.out.println("subtree removed"); - nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; - nodesToRemAfterCheckingNeighbors.get(0).getAllChildrenStream().forEach(node -> node.diffType = DiffType.REM); - nodesToRemAfterCheckingNeighbors.get(0).drop(Time.AFTER); - System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); - } - } - } - } - } - - private static void patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { + + private static void patchVariationTrees(VariationTree sourceVariantVersion1, + VariationTree sourceVariantVersion2, VariationTree targetVariant) + throws Exception { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { System.out.println("Parsing error"); return; } - + VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, false); - VariationDiff optimizedDiff = DiffView.optimized(diff, rho); - VariationDiffSource source = optimizedDiff.getSource(); - VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); - VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); - - // add new nodes - Set> addedNodes = new HashSet>(); - optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); - Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); - applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSubtreeRoots, source, false); - // remove old nodes - Set> removedNodes = new HashSet>(); - optimizedDiff.forAll(node -> {if (node.isRem()) {removedNodes.add(node);}}); - Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); - applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSubtreeRoots, source, false); - - GameEngine.showAndAwaitAll( - Show.tree(sourceVariantVersion1), - Show.tree(sourceVariantVersion2), - Show.tree(targetVariant), - Show.diff(optimizedDiff), - Show.diff(targetVariantDiffPatched), - Show.tree(targetVariantDiffPatched.project(Time.AFTER)) - ); + Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, + false); + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + VariationDiffSource source = optimizedDiff.getSource(); + VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); + + // add new nodes + Set> addedNodes = new HashSet>(); + optimizedDiff.forAll(node -> { + if (node.isAdd()) { + addedNodes.add(node); + } + }); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); + applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSubtreeRoots, source, + false); + // remove old nodes + Set> removedNodes = new HashSet>(); + optimizedDiff.forAll(node -> { + if (node.isRem()) { + removedNodes.add(node); + } + }); + Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); + applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSubtreeRoots, source, + false); + + GameEngine.showAndAwaitAll(Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), + Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), + Show.tree(targetVariantDiffPatched.project(Time.AFTER))); } - + private static VariationTree parseVariationTreeFromFile(String file) { Path examplesDir = Path.of("data", "examples"); - Path path = examplesDir.resolve(file); - try { - VariationTree tree = VariationTree.fromFile( - path, - VariationDiffParseOptions.Default - ); + Path path = examplesDir.resolve(file); + try { + VariationTree tree = VariationTree.fromFile(path, VariationDiffParseOptions.Default); return tree; } catch (IOException e) { e.printStackTrace(); } catch (DiffParseException e) { e.printStackTrace(); } - return null; + return null; } - + public static void main(String[] args) { -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); - patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); + try { + patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), + parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), +// parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); + } catch (Exception e) { + System.out.println("Rejected"); + e.printStackTrace(); + } } } From 28cd47b7e0b8184fe00bd2b10d2375574d7042c7 Mon Sep 17 00:00:00 2001 From: piameier Date: Wed, 23 Jul 2025 16:48:55 +0200 Subject: [PATCH 007/162] consider order when patching (line numbers), fixed bugs --- .../thesis_pm/PatchingExperiment.java | 84 +++++++++++++++---- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 0df9a6930..d6c60ba44 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -7,6 +7,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.variantsync.diffdetective.diff.result.DiffParseException; import org.variantsync.diffdetective.show.Show; @@ -93,11 +95,12 @@ private static DiffNode getChildFromListIfIndexInRange(List root, DiffNode targetNodeInPatch, - DiffNode node, Time time) { + DiffNode node, Time time, boolean debug) { List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); if (!orderedChildrenTarget.contains(node)) { // TODO: throw exception + System.out.println("empty"); return false; } int indexTarget = orderedChildrenTarget.indexOf(node); @@ -112,6 +115,23 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); + + if (neighborBeforeSource != null && neighborBeforeSource.diffType == DiffType.REM) { + neighborBeforeSource = null; + } + + if (debug) { + if (neighborBeforeSource != null) { + System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); + } else { + System.out.print("No neighbor before; "); + } + if (neighborAfterSource != null) { + System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); + } else { + System.out.print("No neighbor after\n"); + } + } if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { @@ -164,15 +184,33 @@ private static int findPositionOfMatchingNeighborInList(DiffNode } private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, - Time time) throws Exception { - + Time time, boolean debug) throws Exception { + if (debug) System.out.println("Root node to insert: " + root.toString()); List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + if (debug) System.out.println("Children of target node: " + orderedChildrenTarget.toString()); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + if (debug) System.out.println("Children of source node: " + orderedChildrenSource.toString()); int indexSource = orderedChildrenSource.indexOf(root); DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource - 1); DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); + if (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { + neighborAfterSource = null; + } + if (debug) { + if (neighborBeforeSource != null) { + System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); + } else { + System.out.print("No neighbor before; "); + } + if (neighborAfterSource != null) { + System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); + } else { + System.out.print("No neighbor after\n"); + } + } + int indexBefore = -2; int indexAfter = -2; @@ -191,14 +229,15 @@ private static int findInsertPosition(DiffNode root, DiffNode targetVariantDiffUnchanged, - VariationDiff targetVariantDiffPatched, Set> subtreeRoots, + VariationDiff targetVariantDiffPatched, List> subtreeRoots, VariationDiffSource source, boolean debug) throws Exception { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; for (DiffNode root : subtreeRoots) { @@ -213,12 +252,11 @@ private static void applyChanges(DiffType type, VariationDiff ta node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) && node.isAnnotation()); } else if (root.isAnnotation()) { - System.out.println(root.getParent(time).getPresenceCondition(time)); targetNodes = targetVariantDiffUnchanged .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } - + if (targetNodes.size() != 1) { System.out.println("too much or too less target nodes found"); } else { @@ -227,7 +265,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { - int insertPosition = findInsertPosition(root, targetNodeInPatch, time); + int insertPosition = findInsertPosition(root, targetNodeInPatch, time, true); if (insertPosition < 0) { System.out.println("no matching insert position found"); } else { @@ -247,10 +285,11 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println("Nodes to remove: " + nodesToRem); List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream() - .filter((node) -> checkNeighbors(node, root, targetNodeInPatch, time)).toList(); + .filter((node) -> checkNeighbors(root, targetNodeInPatch, node, time, true)).toList(); if (nodesToRemAfterCheckingNeighbors.size() != 1) { System.out.println("too much or too less target nodes found"); + System.out.println(nodesToRemAfterCheckingNeighbors.toString()); } else { System.out.println("subtree removed"); nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; @@ -260,6 +299,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } } + GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); } } } @@ -288,8 +328,12 @@ private static void patchVariationTrees(VariationTree sourceVari } }); Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); - applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSubtreeRoots, source, - false); + List> addedSortedSubtreeRoots = addedSubtreeRoots.stream().sorted((n1, n2) -> Integer + .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) + .collect(Collectors.toList()); + applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, + source, false); + // remove old nodes Set> removedNodes = new HashSet>(); optimizedDiff.forAll(node -> { @@ -298,8 +342,12 @@ private static void patchVariationTrees(VariationTree sourceVari } }); Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); - applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSubtreeRoots, source, - false); + List> removedSortedSubtreeRoots = removedSubtreeRoots.stream() + .sorted((n1, n2) -> Integer.compare(n1.getLinesAtTime(Time.BEFORE).fromInclusive(), + n2.getLinesAtTime(Time.BEFORE).fromInclusive())) + .collect(Collectors.toList()); + applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSortedSubtreeRoots, + source, false); GameEngine.showAndAwaitAll(Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), @@ -322,10 +370,10 @@ private static VariationTree parseVariationTreeFromFile(String f public static void main(String[] args) { try { - patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), - parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), -// parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), +// parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); + patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), + parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); } catch (Exception e) { System.out.println("Rejected"); e.printStackTrace(); From c9f05da9e1250e04f693c1ead3eb814e6bfb1bdf Mon Sep 17 00:00:00 2001 From: pmbittner Date: Tue, 23 Sep 2025 14:32:24 +0200 Subject: [PATCH 008/162] feat: VariationDiff::computeAllFeatureNames() --- .../variation/diff/VariationDiff.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/VariationDiff.java b/src/main/java/org/variantsync/diffdetective/variation/diff/VariationDiff.java index c50396503..c0a0f20ea 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/VariationDiff.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/VariationDiff.java @@ -36,8 +36,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -376,6 +378,24 @@ public int count(final Predicate> nodesToCount) { return count.get(); } + + /** + * Returns all variable names occurring in annotations (i.e., formulas of mapping nodes) in this variation diff. + * @return A set of every occuring feature name. + */ + public Set computeAllFeatureNames() { + Set features = new HashSet<>(); + forAll(node -> { + if (node.isConditionalAnnotation()) { + features.addAll(node.getFormula().getUniqueContainedFeatures()); + } + }); + // Since FeatureIDE falsely reports constants "True" and "False" as feature names, we have to remove them from the resulting set. + features.removeIf(FixTrueFalse::isTrueLiteral); + features.removeIf(FixTrueFalse::isFalseLiteral); + return features; + } + /** * Returns all variable names occurring in annotations (i.e., formulas of mapping nodes) in this variation diff. * This method is deterministic: It will return the feature names always in the same order, assuming the variation diff is not changed inbetween. From 8ac9a8661407e30bd14b2d5fc34573f23c045773 Mon Sep 17 00:00:00 2001 From: pmbittner Date: Tue, 23 Sep 2025 14:37:54 +0200 Subject: [PATCH 009/162] feat: configurations from formula assignments --- .../variation/tree/view/relevance/Configure.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/tree/view/relevance/Configure.java b/src/main/java/org/variantsync/diffdetective/variation/tree/view/relevance/Configure.java index 0f613a417..ece3f3f97 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/tree/view/relevance/Configure.java +++ b/src/main/java/org/variantsync/diffdetective/variation/tree/view/relevance/Configure.java @@ -14,6 +14,10 @@ import org.variantsync.diffdetective.variation.tree.VariationNode; import org.variantsync.diffdetective.variation.tree.view.relevance.spec.ConfigureSpec; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Consumer; + /** * Relevance predicate that generates (partial) variants from variation trees. * This relevance predicate is the implementation of Equation 5 in our SPLC'23 paper. @@ -59,7 +63,7 @@ public Configure(final Node configuration) { * then we construct a formula A ∧ (¬ B) ∧ C. */ public Configure(final Map assignment) { - // We use commutativity of ∧ to iterate the map only once instead of twice as shown in the formula above. + // We use commutativity if ∧ to iterate the map only once instead of twice as shown in the formula above. final Formula[] fixedFeatures = new Formula[assignment.size()]; int i = 0; for (Entry entry : assignment.entrySet()) { From 58acae5f1d740de60c0a78a488aaffe14cd5088c Mon Sep 17 00:00:00 2001 From: pmbittner Date: Thu, 25 Sep 2025 10:02:41 +0200 Subject: [PATCH 010/162] fix: LinkedHashSet for deterministic computeAllFeatureNames --- .../variantsync/diffdetective/variation/diff/VariationDiff.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/VariationDiff.java b/src/main/java/org/variantsync/diffdetective/variation/diff/VariationDiff.java index c0a0f20ea..bb167e5e6 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/VariationDiff.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/VariationDiff.java @@ -384,7 +384,7 @@ public int count(final Predicate> nodesToCount) { * @return A set of every occuring feature name. */ public Set computeAllFeatureNames() { - Set features = new HashSet<>(); + Set features = new LinkedHashSet<>(); forAll(node -> { if (node.isConditionalAnnotation()) { features.addAll(node.getFormula().getUniqueContainedFeatures()); From 0437b28dd7f90fd413855a13c0830dd98566e35d Mon Sep 17 00:00:00 2001 From: piameier Date: Thu, 17 Jul 2025 17:57:42 +0200 Subject: [PATCH 011/162] basic patching idea --- .../thesis_pm/PatchingExperiment.java | 177 ++++++++++++++++++ .../variation/diff/patching/Patching.java | 5 + 2 files changed, 182 insertions(+) create mode 100644 src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java create mode 100644 src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java new file mode 100644 index 000000000..6854f5c70 --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -0,0 +1,177 @@ +package org.variantsync.diffdetective.experiments.thesis_pm; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.variantsync.diffdetective.diff.result.DiffParseException; +import org.variantsync.diffdetective.show.Show; +import org.variantsync.diffdetective.show.engine.GameEngine; +import org.variantsync.diffdetective.util.fide.FixTrueFalse.Formula; +import org.variantsync.diffdetective.variation.DiffLinesLabel; +import org.variantsync.diffdetective.variation.diff.DiffNode; +import org.variantsync.diffdetective.variation.diff.DiffType; +import org.variantsync.diffdetective.variation.diff.Time; +import org.variantsync.diffdetective.variation.diff.VariationDiff; +import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; +import org.variantsync.diffdetective.variation.diff.view.DiffView; +import org.variantsync.diffdetective.variation.tree.VariationTree; +import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; +import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; + +public class PatchingExperiment { + + private static Relevance calculateFeatureSetToDeselect(VariationTree variant1, VariationTree variant2, boolean debug) { + Set featuresTreeV1 = new HashSet(); + variant1.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + Set featuresTreeV2 = new HashSet(); + variant2.forAllPreorder(node -> {featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + + Set intersectSet1 = new HashSet<>(featuresTreeV1); + intersectSet1.removeAll(featuresTreeV2); + Set intersectSet2 = new HashSet<>(featuresTreeV2); + intersectSet2.removeAll(featuresTreeV1); + intersectSet1.addAll(intersectSet2); + + if (debug) { + System.out.println(featuresTreeV1); + System.out.println(featuresTreeV2); + System.out.println(intersectSet1); + } + + + Formula[] f = new Formula[intersectSet1.size()]; + Iterator iterator = intersectSet1.iterator(); + for (int i = 0; i < f.length; i++) { + f[i] = Formula.not(Formula.var(iterator.next())); + } + Formula formula = Formula.and(f); + + if (debug) System.out.println(formula.get().toString()); + + Relevance rho = new Configure(formula); + return rho; + } + + private static Set> findRootsOfSubtrees(Set> nodes, boolean debug) { + Set> subtreeRoots = new HashSet>(); + for (DiffNode node : nodes) { + if (!nodes.contains(node.getParent(Time.AFTER))) { + subtreeRoots.add(node); + } + } + if (debug) System.out.println(subtreeRoots); + + return subtreeRoots; + } + + private static void patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { + if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { + System.out.println("Parsing error"); + return; + } + + VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); + Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, targetVariant, false); + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + + // add new nodes + Set> addedNodes = new HashSet>(); + optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); + + // find roots of subtrees of added nodes + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, false); + + VariationDiff targetVariantDiff = VariationDiff.fromTrees(targetVariant, targetVariant); + for (DiffNode root : addedSubtreeRoots) { + VariationDiff subTree = new VariationDiff(root.deepCopy(), optimizedDiff.getSource()); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + List> targetNodes = new ArrayList>(); + if (root.isArtifact()) { + targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getPresenceCondition(Time.AFTER)) && node.isAnnotation()); + } else if (root.isAnnotation()) { + targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getParent(Time.AFTER).getPresenceCondition(Time.AFTER)) && node.isAnnotation()); + } + + if (targetNodes.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + System.out.println("subtree added"); + targetNodes.get(0).addChild(root.deepCopy(), Time.AFTER); + } + } + + // remove old nodes + Set> removedNodes = new HashSet>(); + optimizedDiff.forAll(node -> {if (node.isRem()) {removedNodes.add(node);}}); + + Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, false); + +// VariationDiff targetVariantDiff2 = VariationDiff.fromTrees(targetVariant, targetVariant); + for (DiffNode root : removedSubtreeRoots) { + VariationDiff subTree = new VariationDiff(root.deepCopy(), optimizedDiff.getSource()); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + List> targetNodes = new ArrayList>(); + if (root.isArtifact()) { + targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getPresenceCondition(Time.BEFORE)) && node.isAnnotation()); + } else if (root.isAnnotation()) { + targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getParent(Time.BEFORE).getPresenceCondition(Time.BEFORE)) && node.isAnnotation()); + } + if (targetNodes.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + +// System.out.println(targetNodes.get(0)); + DiffNode parent = targetNodes.get(0); + List> nodesToRem = new ArrayList>(); + parent.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, Time.BEFORE)) nodesToRem.add(node);}); + if (nodesToRem.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + System.out.println("subtree removed"); + nodesToRem.get(0).diffType = DiffType.REM; + nodesToRem.get(0).drop(Time.AFTER); + } + } + } + + GameEngine.showAndAwaitAll( + Show.tree(sourceVariantVersion1), + Show.tree(sourceVariantVersion2), + Show.tree(targetVariant), + Show.diff(optimizedDiff), + Show.diff(targetVariantDiff) + ); + + } + + private static VariationTree parseVariationTreeFromFile(String file) { + Path examplesDir = Path.of("data", "examples"); + Path path = examplesDir.resolve(file); + try { + VariationTree tree = VariationTree.fromFile( + path, + VariationDiffParseOptions.Default + ); + return tree; + } catch (IOException e) { + e.printStackTrace(); + } catch (DiffParseException e) { + e.printStackTrace(); + } + return null; + } + + public static void main(String[] args) { + patchVariationTrees(parseVariationTreeFromFile("exampleA1.cpp"), parseVariationTreeFromFile("exampleA2.cpp"), parseVariationTreeFromFile("exampleB.cpp")); + } + +} diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java new file mode 100644 index 000000000..0baed5e9d --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -0,0 +1,5 @@ +package org.variantsync.diffdetective.variation.diff.patching; + +public class Patching { + +} From a724fb9b6210e2e51cbba56b0168ab8ce172efd8 Mon Sep 17 00:00:00 2001 From: piameier Date: Sat, 19 Jul 2025 18:03:21 +0200 Subject: [PATCH 012/162] code refactoring --- .../thesis_pm/PatchingExperiment.java | 118 +++++++++--------- 1 file changed, 57 insertions(+), 61 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 6854f5c70..c80b96e2c 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -18,6 +18,7 @@ import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; +import org.variantsync.diffdetective.variation.diff.source.VariationDiffSource; import org.variantsync.diffdetective.variation.diff.view.DiffView; import org.variantsync.diffdetective.variation.tree.VariationTree; import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; @@ -25,9 +26,12 @@ public class PatchingExperiment { - private static Relevance calculateFeatureSetToDeselect(VariationTree variant1, VariationTree variant2, boolean debug) { + private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { Set featuresTreeV1 = new HashSet(); - variant1.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + variant1version1.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + if (variant1version2 != null) { + variant1version2.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); + } Set featuresTreeV2 = new HashSet(); variant2.forAllPreorder(node -> {featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); @@ -69,88 +73,80 @@ private static Set> findRootsOfSubtrees(Set sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { - if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { - System.out.println("Parsing error"); - return; - } + private static void applyChanges(DiffType type, VariationDiff targetVariantDiff, Set> subtreeRoots, VariationDiffSource source, boolean debug) { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; - VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, targetVariant, false); - VariationDiff optimizedDiff = DiffView.optimized(diff, rho); - - // add new nodes - Set> addedNodes = new HashSet>(); - optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); - - // find roots of subtrees of added nodes - Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, false); - - VariationDiff targetVariantDiff = VariationDiff.fromTrees(targetVariant, targetVariant); - for (DiffNode root : addedSubtreeRoots) { - VariationDiff subTree = new VariationDiff(root.deepCopy(), optimizedDiff.getSource()); - GameEngine.showAndAwaitAll(Show.diff(subTree)); + for (DiffNode root : subtreeRoots) { + if (debug) { + VariationDiff subTree = new VariationDiff(root.deepCopy(), source); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + } + List> targetNodes = new ArrayList>(); if (root.isArtifact()) { targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getPresenceCondition(Time.AFTER)) && node.isAnnotation()); + .equals(root.getPresenceCondition(time)) && node.isAnnotation()); } else if (root.isAnnotation()) { targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getParent(Time.AFTER).getPresenceCondition(Time.AFTER)) && node.isAnnotation()); + .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } if (targetNodes.size() != 1) { System.out.println("too much or too less target nodes found"); } else { - System.out.println("subtree added"); - targetNodes.get(0).addChild(root.deepCopy(), Time.AFTER); + if (type == DiffType.ADD) { + System.out.println("subtree added"); + targetNodes.get(0).addChild(root.deepCopy(), Time.AFTER); + System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); + } else if (type == DiffType.REM) { + DiffNode parent = targetNodes.get(0); + List> nodesToRem = new ArrayList>(); + parent.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, Time.BEFORE)) nodesToRem.add(node);}); + if (nodesToRem.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + System.out.println("subtree removed"); + nodesToRem.get(0).diffType = DiffType.REM; + nodesToRem.get(0).drop(Time.AFTER); + System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); + } + } } } - - // remove old nodes + } + + + private static void patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { + if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { + System.out.println("Parsing error"); + return; + } + + VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); + Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, false); + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + VariationDiffSource source = optimizedDiff.getSource(); + VariationDiff targetVariantDiff = targetVariant.toCompletelyUnchangedVariationDiff(); + + // add new nodes + Set> addedNodes = new HashSet>(); + optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, false); + applyChanges(DiffType.ADD, targetVariantDiff, addedSubtreeRoots, source, false); + // remove old nodes Set> removedNodes = new HashSet>(); optimizedDiff.forAll(node -> {if (node.isRem()) {removedNodes.add(node);}}); - Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, false); - -// VariationDiff targetVariantDiff2 = VariationDiff.fromTrees(targetVariant, targetVariant); - for (DiffNode root : removedSubtreeRoots) { - VariationDiff subTree = new VariationDiff(root.deepCopy(), optimizedDiff.getSource()); - GameEngine.showAndAwaitAll(Show.diff(subTree)); - List> targetNodes = new ArrayList>(); - if (root.isArtifact()) { - targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getPresenceCondition(Time.BEFORE)) && node.isAnnotation()); - } else if (root.isAnnotation()) { - targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getParent(Time.BEFORE).getPresenceCondition(Time.BEFORE)) && node.isAnnotation()); - } - if (targetNodes.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - -// System.out.println(targetNodes.get(0)); - DiffNode parent = targetNodes.get(0); - List> nodesToRem = new ArrayList>(); - parent.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, Time.BEFORE)) nodesToRem.add(node);}); - if (nodesToRem.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - System.out.println("subtree removed"); - nodesToRem.get(0).diffType = DiffType.REM; - nodesToRem.get(0).drop(Time.AFTER); - } - } - } + applyChanges(DiffType.REM, targetVariantDiff, removedSubtreeRoots, source, false); GameEngine.showAndAwaitAll( Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), Show.tree(targetVariant), Show.diff(optimizedDiff), - Show.diff(targetVariantDiff) + Show.diff(targetVariantDiff), + Show.tree(targetVariantDiff.project(Time.AFTER)) ); - } private static VariationTree parseVariationTreeFromFile(String file) { From 836d6ab7ed2d68d23ce39ce2040a8f739a6e2518 Mon Sep 17 00:00:00 2001 From: piameier Date: Mon, 21 Jul 2025 12:30:52 +0200 Subject: [PATCH 013/162] fixed bugs --- .../thesis_pm/PatchingExperiment.java | 43 +++++++++++-------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index c80b96e2c..13e9955c5 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -61,10 +61,11 @@ private static Relevance calculateFeatureSetToDeselect(VariationTree> findRootsOfSubtrees(Set> nodes, boolean debug) { + private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, boolean debug) { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; Set> subtreeRoots = new HashSet>(); for (DiffNode node : nodes) { - if (!nodes.contains(node.getParent(Time.AFTER))) { + if (!nodes.contains(node.getParent(time))) { subtreeRoots.add(node); } } @@ -73,7 +74,7 @@ private static Set> findRootsOfSubtrees(Set targetVariantDiff, Set> subtreeRoots, VariationDiffSource source, boolean debug) { + private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, VariationDiff targetVariantDiffPatched, Set> subtreeRoots, VariationDiffSource source, boolean debug) { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; for (DiffNode root : subtreeRoots) { @@ -84,29 +85,35 @@ private static void applyChanges(DiffType type, VariationDiff ta List> targetNodes = new ArrayList>(); if (root.isArtifact()) { - targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getPresenceCondition(time)) && node.isAnnotation()); } else if (root.isAnnotation()) { - targetNodes = targetVariantDiff.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + System.out.println(root.getParent(time).getPresenceCondition(time)); + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } if (targetNodes.size() != 1) { System.out.println("too much or too less target nodes found"); } else { + DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNodes.get(0).getID()); + System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { System.out.println("subtree added"); - targetNodes.get(0).addChild(root.deepCopy(), Time.AFTER); - System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); + // TODO: check for neighbors and calculate insert position + targetNodeInPatch.addChild(root.deepCopy(), time); + System.out.println(targetNodeInPatch.getChildOrder(time)); } else if (type == DiffType.REM) { - DiffNode parent = targetNodes.get(0); List> nodesToRem = new ArrayList>(); - parent.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, Time.BEFORE)) nodesToRem.add(node);}); + System.out.println("Root: " + root.toString()); + System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); + targetNodeInPatch.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, time)) nodesToRem.add(node);}); if (nodesToRem.size() != 1) { System.out.println("too much or too less target nodes found"); } else { System.out.println("subtree removed"); nodesToRem.get(0).diffType = DiffType.REM; + // TODO: check for neighbors nodesToRem.get(0).drop(Time.AFTER); System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } @@ -126,26 +133,27 @@ private static void patchVariationTrees(VariationTree sourceVari Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, false); VariationDiff optimizedDiff = DiffView.optimized(diff, rho); VariationDiffSource source = optimizedDiff.getSource(); - VariationDiff targetVariantDiff = targetVariant.toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); // add new nodes Set> addedNodes = new HashSet>(); optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); - Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, false); - applyChanges(DiffType.ADD, targetVariantDiff, addedSubtreeRoots, source, false); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); + applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSubtreeRoots, source, false); // remove old nodes Set> removedNodes = new HashSet>(); optimizedDiff.forAll(node -> {if (node.isRem()) {removedNodes.add(node);}}); - Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, false); - applyChanges(DiffType.REM, targetVariantDiff, removedSubtreeRoots, source, false); + Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); + applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSubtreeRoots, source, false); GameEngine.showAndAwaitAll( Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), Show.tree(targetVariant), Show.diff(optimizedDiff), - Show.diff(targetVariantDiff), - Show.tree(targetVariantDiff.project(Time.AFTER)) + Show.diff(targetVariantDiffPatched), + Show.tree(targetVariantDiffPatched.project(Time.AFTER)) ); } @@ -167,7 +175,8 @@ private static VariationTree parseVariationTreeFromFile(String f } public static void main(String[] args) { - patchVariationTrees(parseVariationTreeFromFile("exampleA1.cpp"), parseVariationTreeFromFile("exampleA2.cpp"), parseVariationTreeFromFile("exampleB.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); + patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); } } From dcf2d8842640f30d6d7ac89e142fcd86499a5b75 Mon Sep 17 00:00:00 2001 From: piameier Date: Mon, 21 Jul 2025 21:21:57 +0200 Subject: [PATCH 014/162] find insert position for ADD and check neigbors for REM --- .../thesis_pm/PatchingExperiment.java | 134 ++++++++++++++++-- .../variation/diff/patching/Patching.java | 36 +++++ 2 files changed, 157 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 13e9955c5..bc2ca5d98 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -18,12 +18,15 @@ import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; +import org.variantsync.diffdetective.variation.diff.patching.Patching; import org.variantsync.diffdetective.variation.diff.source.VariationDiffSource; import org.variantsync.diffdetective.variation.diff.view.DiffView; import org.variantsync.diffdetective.variation.tree.VariationTree; import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; +import com.github.gumtreediff.actions.Diff; + public class PatchingExperiment { private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { @@ -74,6 +77,102 @@ private static Set> findRootsOfSubtrees(Set root, + DiffNode targetNodeInPatch, DiffNode node) { + + DiffNode neighborBeforeTarget = null; + DiffNode neighborAfterTarget = null; + DiffNode neighborBeforeSource = null; + DiffNode neighborAfterSource = null; + boolean correctBefore = false; + boolean correctAfter = false; + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + if (orderedChildrenTarget.contains(node)) { + int indexTarget = orderedChildrenTarget.indexOf(node); + if ((indexTarget - 1) >= 0) { + neighborBeforeTarget = orderedChildrenTarget.get(indexTarget - 1); + } + if ((indexTarget + 1) < orderedChildrenTarget.size()) { + neighborAfterTarget = orderedChildrenTarget.get(indexTarget + 1); + } + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + int indexSource = orderedChildrenSource.indexOf(root); + if ((indexSource - 1) >= 0) { + neighborBeforeSource = orderedChildrenSource.get(indexSource - 1); + } + if ((indexSource + 1) < orderedChildrenTarget.size()) { + neighborAfterSource = orderedChildrenSource.get(indexSource + 1); + } + if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { + System.out.println("Different neighbors"); + } else if (neighborBeforeSource != null && neighborBeforeTarget != null) { + if (Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { + System.out.println("Same neighbor before"); + correctBefore = true; + } + } else { + System.out.println("No neighbor before"); + correctBefore = true; + } + if ((neighborAfterSource != null && neighborAfterTarget == null) || (neighborAfterSource == null && neighborAfterTarget != null)) { + System.out.println("Different neighbors"); + } else if (neighborAfterSource != null && neighborAfterTarget != null) { + if (Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { + System.out.println("Same neighbor after"); + correctAfter = true; + } + } else { + System.out.println("No neighbor after"); + correctAfter = true; + } + } + return correctBefore && correctAfter; + } + + private static List findInsertPositions(Time time, DiffNode root, + DiffNode targetNodeInPatch) { + List insertPositions = new ArrayList(); + DiffNode neighborBeforeSource = null; + DiffNode neighborAfterSource = null; + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + int indexSource = orderedChildrenSource.indexOf(root); + if ((indexSource - 1) >= 0) { + neighborBeforeSource = orderedChildrenSource.get(indexSource - 1); + } + if ((indexSource + 1) < orderedChildrenTarget.size()) { + neighborAfterSource = orderedChildrenSource.get(indexSource + 1); + } + + for (int i = 0; i < orderedChildrenTarget.size(); i++) { + if (neighborBeforeSource != null && neighborAfterSource != null) { + if ((i + 1) < orderedChildrenTarget.size()) { + boolean correctBefore = Patching.isSameAs(orderedChildrenTarget.get(i), neighborBeforeSource, time); + boolean correctAfter = Patching.isSameAs(orderedChildrenTarget.get(i + 1), neighborAfterSource, time); + if (correctBefore && correctAfter) { + System.out.println("Found insert position"); + insertPositions.add(i + 1); + } else if (correctBefore || correctAfter){ + + } + } + } else if (neighborBeforeSource != null) { + if (Patching.isSameAs(orderedChildrenTarget.get(i), neighborBeforeSource, time)) { + System.out.println("Found insert position"); + insertPositions.add(i + 1); + } + } else if (neighborAfterSource != null) { + if ((i + 1) < orderedChildrenTarget.size()) { + if (Patching.isSameAs(orderedChildrenTarget.get(i + 1), neighborAfterSource, time)) { + System.out.println("Found insert position"); + insertPositions.add(i + 1); + } + } + } + } + return insertPositions; + } + private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, VariationDiff targetVariantDiffPatched, Set> subtreeRoots, VariationDiffSource source, boolean debug) { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; @@ -99,29 +198,38 @@ private static void applyChanges(DiffType type, VariationDiff ta DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNodes.get(0).getID()); System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { - System.out.println("subtree added"); - // TODO: check for neighbors and calculate insert position - targetNodeInPatch.addChild(root.deepCopy(), time); - System.out.println(targetNodeInPatch.getChildOrder(time)); + + List insertPositions = findInsertPositions(time, root, targetNodeInPatch); + if (insertPositions.size() != 1) { + System.out.println("no matching insert position found"); + } else { + System.out.println("subtree added"); + targetNodeInPatch.insertChild(root.deepCopy(), insertPositions.get(0), time); + System.out.println(targetNodeInPatch.getChildOrder(time)); + } + } else if (type == DiffType.REM) { List> nodesToRem = new ArrayList>(); System.out.println("Root: " + root.toString()); System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); - targetNodeInPatch.getAllChildrenStream().forEach(node -> { if (node.isSameAs(root, time)) nodesToRem.add(node);}); - if (nodesToRem.size() != 1) { + targetNodeInPatch.getAllChildrenStream().forEach(node -> { if (Patching.isSameAs(node, root, time)) nodesToRem.add(node);}); + System.out.println("Nodes to remove: " + nodesToRem); + + List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream().filter((node) -> checkNeighbors(time, root, targetNodeInPatch, node)).toList(); + + if (nodesToRemAfterCheckingNeighbors.size() != 1) { System.out.println("too much or too less target nodes found"); } else { System.out.println("subtree removed"); - nodesToRem.get(0).diffType = DiffType.REM; - // TODO: check for neighbors - nodesToRem.get(0).drop(Time.AFTER); + nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; + nodesToRemAfterCheckingNeighbors.get(0).getAllChildrenStream().forEach(node -> node.diffType = DiffType.REM); + nodesToRemAfterCheckingNeighbors.get(0).drop(Time.AFTER); System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } } } } - } - + } private static void patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { @@ -175,8 +283,8 @@ private static VariationTree parseVariationTreeFromFile(String f } public static void main(String[] args) { -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); - patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); + patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); } } diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 0baed5e9d..cc5674a9f 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -1,5 +1,41 @@ package org.variantsync.diffdetective.variation.diff.patching; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import org.variantsync.diffdetective.variation.Label; +import org.variantsync.diffdetective.variation.diff.DiffNode; +import org.variantsync.diffdetective.variation.diff.Time; + public class Patching { + public static boolean isSameAs(DiffNode a, DiffNode b, Time time) { + return isSameAs(a, b, new HashSet<>(), time); + } + + private static boolean isSameAs(DiffNode a, DiffNode b, Set> visited, Time time) { + if (!visited.add(a)) { + return true; + } + + if (!( + a.getNodeType().equals(b.getNodeType()) && +// a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && +// a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && + (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) && + a.getLabel().getLines().equals(b.getLabel().getLines()) + )) { + return false; + } + + Iterator> aIt = a.getAllChildren().iterator(); + Iterator> bIt = b.getAllChildren().iterator(); + while (aIt.hasNext() && bIt.hasNext()) { + if (!isSameAs(aIt.next(), bIt.next(), visited, time)) { + return false; + } + } + return aIt.hasNext() == bIt.hasNext(); + } } From bb766aef4b8e8bb52d3f098ac4f2ba6dc2b47828 Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 22 Jul 2025 18:47:28 +0200 Subject: [PATCH 015/162] refactoring checkNeighbors method --- .../thesis_pm/PatchingExperiment.java | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index bc2ca5d98..dc831684b 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -77,56 +77,56 @@ private static Set> findRootsOfSubtrees(Set getChildFromListIfIndexInRange(List> childrenList, int index) { + if (index >= 0 && index < childrenList.size()) { + return childrenList.get(index); + } + return null; + } + private static boolean checkNeighbors(Time time, DiffNode root, DiffNode targetNodeInPatch, DiffNode node) { - DiffNode neighborBeforeTarget = null; - DiffNode neighborAfterTarget = null; - DiffNode neighborBeforeSource = null; - DiffNode neighborAfterSource = null; - boolean correctBefore = false; - boolean correctAfter = false; List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); - if (orderedChildrenTarget.contains(node)) { - int indexTarget = orderedChildrenTarget.indexOf(node); - if ((indexTarget - 1) >= 0) { - neighborBeforeTarget = orderedChildrenTarget.get(indexTarget - 1); - } - if ((indexTarget + 1) < orderedChildrenTarget.size()) { - neighborAfterTarget = orderedChildrenTarget.get(indexTarget + 1); - } - List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - int indexSource = orderedChildrenSource.indexOf(root); - if ((indexSource - 1) >= 0) { - neighborBeforeSource = orderedChildrenSource.get(indexSource - 1); - } - if ((indexSource + 1) < orderedChildrenTarget.size()) { - neighborAfterSource = orderedChildrenSource.get(indexSource + 1); - } - if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { - System.out.println("Different neighbors"); - } else if (neighborBeforeSource != null && neighborBeforeTarget != null) { - if (Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { - System.out.println("Same neighbor before"); - correctBefore = true; - } - } else { - System.out.println("No neighbor before"); - correctBefore = true; - } - if ((neighborAfterSource != null && neighborAfterTarget == null) || (neighborAfterSource == null && neighborAfterTarget != null)) { - System.out.println("Different neighbors"); - } else if (neighborAfterSource != null && neighborAfterTarget != null) { - if (Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { - System.out.println("Same neighbor after"); - correctAfter = true; - } - } else { - System.out.println("No neighbor after"); - correctAfter = true; + if (!orderedChildrenTarget.contains(node)) { + // TODO: throw exception + return false; + } + int indexTarget = orderedChildrenTarget.indexOf(node); + DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget - 1); + DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget + 1); + + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + int indexSource = orderedChildrenSource.indexOf(root); + DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource - 1); + DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); + + if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { + System.out.println("Different neighbors before"); + return false; + } + if (neighborBeforeSource != null && neighborBeforeTarget != null) { + if (!Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { + System.out.println("Different neighbor before"); + return false; } } - return correctBefore && correctAfter; + // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no neighbor before) + + if ((neighborAfterSource != null && neighborAfterTarget == null) || (neighborAfterSource == null && neighborAfterTarget != null)) { + System.out.println("Different neighbors after"); + return false; + } + if (neighborAfterSource != null && neighborAfterTarget != null) { + if (!Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { + System.out.println("Different neighbors after"); + return false; + } + } + // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no neighbor after) + + return true; + } private static List findInsertPositions(Time time, DiffNode root, @@ -283,8 +283,8 @@ private static VariationTree parseVariationTreeFromFile(String f } public static void main(String[] args) { - patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); + patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); } } From 6fbdcb51ce13f75c18d2b3a2edc8620cfeeb1e84 Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 22 Jul 2025 19:44:44 +0200 Subject: [PATCH 016/162] refactoring findInsertPosition method and formatting code --- .../thesis_pm/PatchingExperiment.java | 439 ++++++++++-------- 1 file changed, 242 insertions(+), 197 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index dc831684b..0df9a6930 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -25,83 +25,96 @@ import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; -import com.github.gumtreediff.actions.Diff; - public class PatchingExperiment { - - private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { + + private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, + VariationTree variant1version2, VariationTree variant2, boolean debug) { Set featuresTreeV1 = new HashSet(); - variant1version1.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); - if (variant1version2 != null) { - variant1version2.forAllPreorder(node -> {featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); - } - Set featuresTreeV2 = new HashSet(); - variant2.forAllPreorder(node -> {featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures());}); - - Set intersectSet1 = new HashSet<>(featuresTreeV1); - intersectSet1.removeAll(featuresTreeV2); - Set intersectSet2 = new HashSet<>(featuresTreeV2); - intersectSet2.removeAll(featuresTreeV1); - intersectSet1.addAll(intersectSet2); - - if (debug) { - System.out.println(featuresTreeV1); - System.out.println(featuresTreeV2); - System.out.println(intersectSet1); - } - - - Formula[] f = new Formula[intersectSet1.size()]; - Iterator iterator = intersectSet1.iterator(); - for (int i = 0; i < f.length; i++) { - f[i] = Formula.not(Formula.var(iterator.next())); - } - Formula formula = Formula.and(f); - - if (debug) System.out.println(formula.get().toString()); - - Relevance rho = new Configure(formula); - return rho; + variant1version1.forAllPreorder(node -> { + featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + if (variant1version2 != null) { + variant1version2.forAllPreorder(node -> { + featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + } + Set featuresTreeV2 = new HashSet(); + variant2.forAllPreorder(node -> { + featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + + Set intersectSet1 = new HashSet<>(featuresTreeV1); + intersectSet1.removeAll(featuresTreeV2); + Set intersectSet2 = new HashSet<>(featuresTreeV2); + intersectSet2.removeAll(featuresTreeV1); + intersectSet1.addAll(intersectSet2); + + if (debug) { + System.out.println(featuresTreeV1); + System.out.println(featuresTreeV2); + System.out.println(intersectSet1); + } + + Formula[] f = new Formula[intersectSet1.size()]; + Iterator iterator = intersectSet1.iterator(); + for (int i = 0; i < f.length; i++) { + f[i] = Formula.not(Formula.var(iterator.next())); + } + Formula formula = Formula.and(f); + + if (debug) + System.out.println(formula.get().toString()); + + Relevance rho = new Configure(formula); + return rho; } - - private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, boolean debug) { + + private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, + boolean debug) { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; Set> subtreeRoots = new HashSet>(); - for (DiffNode node : nodes) { - if (!nodes.contains(node.getParent(time))) { - subtreeRoots.add(node); - } - } - if (debug) System.out.println(subtreeRoots); - - return subtreeRoots; + for (DiffNode node : nodes) { + if (!nodes.contains(node.getParent(time))) { + subtreeRoots.add(node); + } + } + if (debug) + System.out.println(subtreeRoots); + + return subtreeRoots; } - - private static DiffNode getChildFromListIfIndexInRange(List> childrenList, int index) { + + private static DiffNode getChildFromListIfIndexInRange(List> childrenList, + int index) { if (index >= 0 && index < childrenList.size()) { return childrenList.get(index); } return null; } - - private static boolean checkNeighbors(Time time, DiffNode root, - DiffNode targetNodeInPatch, DiffNode node) { - + + private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, + DiffNode node, Time time) { + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); if (!orderedChildrenTarget.contains(node)) { // TODO: throw exception return false; } int indexTarget = orderedChildrenTarget.indexOf(node); - DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget - 1); - DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget + 1); - + DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, + indexTarget - 1); + DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, + indexTarget + 1); + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); int indexSource = orderedChildrenSource.indexOf(root); - DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource - 1); - DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); - - if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { + DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource - 1); + DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource + 1); + + if ((neighborBeforeSource != null && neighborBeforeTarget == null) + || (neighborBeforeSource == null && neighborBeforeTarget != null)) { System.out.println("Different neighbors before"); return false; } @@ -111,180 +124,212 @@ private static boolean checkNeighbors(Time time, DiffNode root, return false; } } - // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no neighbor before) - - if ((neighborAfterSource != null && neighborAfterTarget == null) || (neighborAfterSource == null && neighborAfterTarget != null)) { + // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no + // neighbor before) + + if ((neighborAfterSource != null && neighborAfterTarget == null) + || (neighborAfterSource == null && neighborAfterTarget != null)) { System.out.println("Different neighbors after"); return false; - } + } if (neighborAfterSource != null && neighborAfterTarget != null) { if (!Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { System.out.println("Different neighbors after"); - return false; + return false; } - } - // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no neighbor after) - + } + // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no + // neighbor after) + return true; - + + } + + private static int findPositionOfMatchingNeighborInList(DiffNode neighbor, + List> list, Time time) throws Exception { + ArrayList positions = new ArrayList(); + for (DiffNode node : list) { + if (Patching.isSameAs(neighbor, node, time)) { + positions.add(list.indexOf(node)); + } + } + if (positions.size() == 1) { + return positions.get(0); + } + if (positions.size() > 1) { + // TODO: throw exception? + throw new Exception(); + } + return -1; } - - private static List findInsertPositions(Time time, DiffNode root, - DiffNode targetNodeInPatch) { - List insertPositions = new ArrayList(); - DiffNode neighborBeforeSource = null; - DiffNode neighborAfterSource = null; + + private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, + Time time) throws Exception { + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); int indexSource = orderedChildrenSource.indexOf(root); - if ((indexSource - 1) >= 0) { - neighborBeforeSource = orderedChildrenSource.get(indexSource - 1); + DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource - 1); + DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource + 1); + int indexBefore = -2; + int indexAfter = -2; + + if (neighborBeforeSource != null) { + indexBefore = findPositionOfMatchingNeighborInList(neighborBeforeSource, orderedChildrenTarget, time); + } + if (neighborAfterSource != null) { + indexAfter = findPositionOfMatchingNeighborInList(neighborAfterSource, orderedChildrenTarget, time); + } + if (indexBefore == -2 && indexAfter == -2) { + System.out.println("No neighbors before or after the target"); + return -1; } - if ((indexSource + 1) < orderedChildrenTarget.size()) { - neighborAfterSource = orderedChildrenSource.get(indexSource + 1); + if (indexBefore > -1 && indexAfter > -1) { + if (indexAfter - indexBefore > 1) { + // TODO: Alignment Problem + return -1; + } + return indexBefore; } - - for (int i = 0; i < orderedChildrenTarget.size(); i++) { - if (neighborBeforeSource != null && neighborAfterSource != null) { - if ((i + 1) < orderedChildrenTarget.size()) { - boolean correctBefore = Patching.isSameAs(orderedChildrenTarget.get(i), neighborBeforeSource, time); - boolean correctAfter = Patching.isSameAs(orderedChildrenTarget.get(i + 1), neighborAfterSource, time); - if (correctBefore && correctAfter) { - System.out.println("Found insert position"); - insertPositions.add(i + 1); - } else if (correctBefore || correctAfter){ - + return Math.max(indexBefore, indexAfter); + } + + private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, + VariationDiff targetVariantDiffPatched, Set> subtreeRoots, + VariationDiffSource source, boolean debug) throws Exception { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; + + for (DiffNode root : subtreeRoots) { + if (debug) { + VariationDiff subTree = new VariationDiff(root.deepCopy(), source); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + } + + List> targetNodes = new ArrayList>(); + if (root.isArtifact()) { + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat( + node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) + && node.isAnnotation()); + } else if (root.isAnnotation()) { + System.out.println(root.getParent(time).getPresenceCondition(time)); + targetNodes = targetVariantDiffUnchanged + .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); + } + + if (targetNodes.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + DiffNode targetNodeInPatch = targetVariantDiffPatched + .getNodeWithID(targetNodes.get(0).getID()); + System.out.println(targetNodeInPatch.toString()); + if (type == DiffType.ADD) { + + int insertPosition = findInsertPosition(root, targetNodeInPatch, time); + if (insertPosition < 0) { + System.out.println("no matching insert position found"); + } else { + System.out.println("subtree added"); + targetNodeInPatch.insertChild(root.deepCopy(), insertPosition, time); + System.out.println(targetNodeInPatch.getChildOrder(time)); } - } - } else if (neighborBeforeSource != null) { - if (Patching.isSameAs(orderedChildrenTarget.get(i), neighborBeforeSource, time)) { - System.out.println("Found insert position"); - insertPositions.add(i + 1); - } - } else if (neighborAfterSource != null) { - if ((i + 1) < orderedChildrenTarget.size()) { - if (Patching.isSameAs(orderedChildrenTarget.get(i + 1), neighborAfterSource, time)) { - System.out.println("Found insert position"); - insertPositions.add(i + 1); + + } else if (type == DiffType.REM) { + List> nodesToRem = new ArrayList>(); + System.out.println("Root: " + root.toString()); + System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); + targetNodeInPatch.getAllChildrenStream().forEach(node -> { + if (Patching.isSameAs(node, root, time)) + nodesToRem.add(node); + }); + System.out.println("Nodes to remove: " + nodesToRem); + + List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream() + .filter((node) -> checkNeighbors(node, root, targetNodeInPatch, time)).toList(); + + if (nodesToRemAfterCheckingNeighbors.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + System.out.println("subtree removed"); + nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; + nodesToRemAfterCheckingNeighbors.get(0).getAllChildrenStream() + .forEach(node -> node.diffType = DiffType.REM); + nodesToRemAfterCheckingNeighbors.get(0).drop(Time.AFTER); + System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } } } } - return insertPositions; } - - private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, VariationDiff targetVariantDiffPatched, Set> subtreeRoots, VariationDiffSource source, boolean debug) { - Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; - - for (DiffNode root : subtreeRoots) { - if (debug) { - VariationDiff subTree = new VariationDiff(root.deepCopy(), source); - GameEngine.showAndAwaitAll(Show.diff(subTree)); - } - - List> targetNodes = new ArrayList>(); - if (root.isArtifact()) { - targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getPresenceCondition(time)) && node.isAnnotation()); - } else if (root.isAnnotation()) { - System.out.println(root.getParent(time).getPresenceCondition(time)); - targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); - } - - if (targetNodes.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNodes.get(0).getID()); - System.out.println(targetNodeInPatch.toString()); - if (type == DiffType.ADD) { - - List insertPositions = findInsertPositions(time, root, targetNodeInPatch); - if (insertPositions.size() != 1) { - System.out.println("no matching insert position found"); - } else { - System.out.println("subtree added"); - targetNodeInPatch.insertChild(root.deepCopy(), insertPositions.get(0), time); - System.out.println(targetNodeInPatch.getChildOrder(time)); - } - - } else if (type == DiffType.REM) { - List> nodesToRem = new ArrayList>(); - System.out.println("Root: " + root.toString()); - System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); - targetNodeInPatch.getAllChildrenStream().forEach(node -> { if (Patching.isSameAs(node, root, time)) nodesToRem.add(node);}); - System.out.println("Nodes to remove: " + nodesToRem); - - List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream().filter((node) -> checkNeighbors(time, root, targetNodeInPatch, node)).toList(); - - if (nodesToRemAfterCheckingNeighbors.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - System.out.println("subtree removed"); - nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; - nodesToRemAfterCheckingNeighbors.get(0).getAllChildrenStream().forEach(node -> node.diffType = DiffType.REM); - nodesToRemAfterCheckingNeighbors.get(0).drop(Time.AFTER); - System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); - } - } - } - } - } - - private static void patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) { + + private static void patchVariationTrees(VariationTree sourceVariantVersion1, + VariationTree sourceVariantVersion2, VariationTree targetVariant) + throws Exception { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { System.out.println("Parsing error"); return; } - + VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, false); - VariationDiff optimizedDiff = DiffView.optimized(diff, rho); - VariationDiffSource source = optimizedDiff.getSource(); - VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); - VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); - - // add new nodes - Set> addedNodes = new HashSet>(); - optimizedDiff.forAll(node -> {if (node.isAdd()) {addedNodes.add(node);}}); - Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); - applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSubtreeRoots, source, false); - // remove old nodes - Set> removedNodes = new HashSet>(); - optimizedDiff.forAll(node -> {if (node.isRem()) {removedNodes.add(node);}}); - Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); - applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSubtreeRoots, source, false); - - GameEngine.showAndAwaitAll( - Show.tree(sourceVariantVersion1), - Show.tree(sourceVariantVersion2), - Show.tree(targetVariant), - Show.diff(optimizedDiff), - Show.diff(targetVariantDiffPatched), - Show.tree(targetVariantDiffPatched.project(Time.AFTER)) - ); + Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, + false); + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + VariationDiffSource source = optimizedDiff.getSource(); + VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); + + // add new nodes + Set> addedNodes = new HashSet>(); + optimizedDiff.forAll(node -> { + if (node.isAdd()) { + addedNodes.add(node); + } + }); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); + applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSubtreeRoots, source, + false); + // remove old nodes + Set> removedNodes = new HashSet>(); + optimizedDiff.forAll(node -> { + if (node.isRem()) { + removedNodes.add(node); + } + }); + Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); + applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSubtreeRoots, source, + false); + + GameEngine.showAndAwaitAll(Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), + Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), + Show.tree(targetVariantDiffPatched.project(Time.AFTER))); } - + private static VariationTree parseVariationTreeFromFile(String file) { Path examplesDir = Path.of("data", "examples"); - Path path = examplesDir.resolve(file); - try { - VariationTree tree = VariationTree.fromFile( - path, - VariationDiffParseOptions.Default - ); + Path path = examplesDir.resolve(file); + try { + VariationTree tree = VariationTree.fromFile(path, VariationDiffParseOptions.Default); return tree; } catch (IOException e) { e.printStackTrace(); } catch (DiffParseException e) { e.printStackTrace(); } - return null; + return null; } - + public static void main(String[] args) { -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); - patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); + try { + patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), + parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), +// parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); + } catch (Exception e) { + System.out.println("Rejected"); + e.printStackTrace(); + } } } From 0994baea9e9313ca16bfa9cb955541729a5c6212 Mon Sep 17 00:00:00 2001 From: piameier Date: Wed, 23 Jul 2025 16:48:55 +0200 Subject: [PATCH 017/162] consider order when patching (line numbers), fixed bugs --- .../thesis_pm/PatchingExperiment.java | 84 +++++++++++++++---- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 0df9a6930..d6c60ba44 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -7,6 +7,8 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.variantsync.diffdetective.diff.result.DiffParseException; import org.variantsync.diffdetective.show.Show; @@ -93,11 +95,12 @@ private static DiffNode getChildFromListIfIndexInRange(List root, DiffNode targetNodeInPatch, - DiffNode node, Time time) { + DiffNode node, Time time, boolean debug) { List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); if (!orderedChildrenTarget.contains(node)) { // TODO: throw exception + System.out.println("empty"); return false; } int indexTarget = orderedChildrenTarget.indexOf(node); @@ -112,6 +115,23 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); + + if (neighborBeforeSource != null && neighborBeforeSource.diffType == DiffType.REM) { + neighborBeforeSource = null; + } + + if (debug) { + if (neighborBeforeSource != null) { + System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); + } else { + System.out.print("No neighbor before; "); + } + if (neighborAfterSource != null) { + System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); + } else { + System.out.print("No neighbor after\n"); + } + } if ((neighborBeforeSource != null && neighborBeforeTarget == null) || (neighborBeforeSource == null && neighborBeforeTarget != null)) { @@ -164,15 +184,33 @@ private static int findPositionOfMatchingNeighborInList(DiffNode } private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, - Time time) throws Exception { - + Time time, boolean debug) throws Exception { + if (debug) System.out.println("Root node to insert: " + root.toString()); List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + if (debug) System.out.println("Children of target node: " + orderedChildrenTarget.toString()); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + if (debug) System.out.println("Children of source node: " + orderedChildrenSource.toString()); int indexSource = orderedChildrenSource.indexOf(root); DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource - 1); DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); + if (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { + neighborAfterSource = null; + } + if (debug) { + if (neighborBeforeSource != null) { + System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); + } else { + System.out.print("No neighbor before; "); + } + if (neighborAfterSource != null) { + System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); + } else { + System.out.print("No neighbor after\n"); + } + } + int indexBefore = -2; int indexAfter = -2; @@ -191,14 +229,15 @@ private static int findInsertPosition(DiffNode root, DiffNode targetVariantDiffUnchanged, - VariationDiff targetVariantDiffPatched, Set> subtreeRoots, + VariationDiff targetVariantDiffPatched, List> subtreeRoots, VariationDiffSource source, boolean debug) throws Exception { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; for (DiffNode root : subtreeRoots) { @@ -213,12 +252,11 @@ private static void applyChanges(DiffType type, VariationDiff ta node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) && node.isAnnotation()); } else if (root.isAnnotation()) { - System.out.println(root.getParent(time).getPresenceCondition(time)); targetNodes = targetVariantDiffUnchanged .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } - + if (targetNodes.size() != 1) { System.out.println("too much or too less target nodes found"); } else { @@ -227,7 +265,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { - int insertPosition = findInsertPosition(root, targetNodeInPatch, time); + int insertPosition = findInsertPosition(root, targetNodeInPatch, time, true); if (insertPosition < 0) { System.out.println("no matching insert position found"); } else { @@ -247,10 +285,11 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println("Nodes to remove: " + nodesToRem); List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream() - .filter((node) -> checkNeighbors(node, root, targetNodeInPatch, time)).toList(); + .filter((node) -> checkNeighbors(root, targetNodeInPatch, node, time, true)).toList(); if (nodesToRemAfterCheckingNeighbors.size() != 1) { System.out.println("too much or too less target nodes found"); + System.out.println(nodesToRemAfterCheckingNeighbors.toString()); } else { System.out.println("subtree removed"); nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; @@ -260,6 +299,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } } + GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); } } } @@ -288,8 +328,12 @@ private static void patchVariationTrees(VariationTree sourceVari } }); Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); - applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSubtreeRoots, source, - false); + List> addedSortedSubtreeRoots = addedSubtreeRoots.stream().sorted((n1, n2) -> Integer + .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) + .collect(Collectors.toList()); + applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, + source, false); + // remove old nodes Set> removedNodes = new HashSet>(); optimizedDiff.forAll(node -> { @@ -298,8 +342,12 @@ private static void patchVariationTrees(VariationTree sourceVari } }); Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); - applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSubtreeRoots, source, - false); + List> removedSortedSubtreeRoots = removedSubtreeRoots.stream() + .sorted((n1, n2) -> Integer.compare(n1.getLinesAtTime(Time.BEFORE).fromInclusive(), + n2.getLinesAtTime(Time.BEFORE).fromInclusive())) + .collect(Collectors.toList()); + applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSortedSubtreeRoots, + source, false); GameEngine.showAndAwaitAll(Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), @@ -322,10 +370,10 @@ private static VariationTree parseVariationTreeFromFile(String f public static void main(String[] args) { try { - patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), - parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), -// parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), +// parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); + patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), + parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); } catch (Exception e) { System.out.println("Rejected"); e.printStackTrace(); From a3a02fb40fa0fa2b4db6844d120e39ffa0aa644d Mon Sep 17 00:00:00 2001 From: piameier Date: Thu, 24 Jul 2025 15:58:33 +0200 Subject: [PATCH 018/162] fixed bug --- .../experiments/thesis_pm/PatchingExperiment.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index d6c60ba44..809069621 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -100,7 +100,6 @@ private static boolean checkNeighbors(DiffNode root, DiffNode> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); if (!orderedChildrenTarget.contains(node)) { // TODO: throw exception - System.out.println("empty"); return false; } int indexTarget = orderedChildrenTarget.indexOf(node); @@ -116,8 +115,16 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); - if (neighborBeforeSource != null && neighborBeforeSource.diffType == DiffType.REM) { - neighborBeforeSource = null; + int indexSourceBefore = indexSource - 1; + while (neighborBeforeSource != null && neighborBeforeSource.diffType == DiffType.REM && indexSourceBefore > 0) { + indexSourceBefore--; + neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSourceBefore - 1); + } + + int indexTargetBefore = indexTarget - 1; + while (neighborBeforeTarget != null && neighborBeforeTarget.diffType == DiffType.REM && indexTargetBefore > 0) { + indexTargetBefore--; + neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTargetBefore - 1); } if (debug) { From 5fdc4416a1de5ae647bad0c24025bfdf2e120001 Mon Sep 17 00:00:00 2001 From: piameier Date: Thu, 24 Jul 2025 21:50:02 +0200 Subject: [PATCH 019/162] patch with diff generated from files --- .../thesis_pm/PatchingExperiment.java | 133 ++++++++++++------ 1 file changed, 90 insertions(+), 43 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 809069621..1bdcad718 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -8,8 +8,9 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import java.util.stream.Stream; +import org.eclipse.jgit.diff.DiffAlgorithm; +import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm; import org.variantsync.diffdetective.diff.result.DiffParseException; import org.variantsync.diffdetective.show.Show; import org.variantsync.diffdetective.show.engine.GameEngine; @@ -28,8 +29,34 @@ import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; public class PatchingExperiment { + + private static Relevance calculateIntersectionOfFeatureSets(Set featureSet1, Set featureSet2, boolean debug) { + Set intersectSet1 = new HashSet<>(featureSet1); + intersectSet1.removeAll(featureSet2); + Set intersectSet2 = new HashSet<>(featureSet2); + intersectSet2.removeAll(featureSet1); + intersectSet1.addAll(intersectSet2); + + if (debug) { + System.out.println(featureSet1); + System.out.println(featureSet2); + System.out.println(intersectSet1); + } + + Formula[] f = new Formula[intersectSet1.size()]; + Iterator iterator = intersectSet1.iterator(); + for (int i = 0; i < f.length; i++) { + f[i] = Formula.not(Formula.var(iterator.next())); + } + Formula formula = Formula.and(f); + + if (debug) + System.out.println(formula.get().toString()); - private static Relevance calculateFeatureSetToDeselect(VariationTree variant1version1, + return new Configure(formula); + } + + private static Relevance calculateFeatureSetToDeselectFromTrees(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { Set featuresTreeV1 = new HashSet(); variant1version1.forAllPreorder(node -> { @@ -45,30 +72,27 @@ private static Relevance calculateFeatureSetToDeselect(VariationTree intersectSet1 = new HashSet<>(featuresTreeV1); - intersectSet1.removeAll(featuresTreeV2); - Set intersectSet2 = new HashSet<>(featuresTreeV2); - intersectSet2.removeAll(featuresTreeV1); - intersectSet1.addAll(intersectSet2); - - if (debug) { - System.out.println(featuresTreeV1); - System.out.println(featuresTreeV2); - System.out.println(intersectSet1); - } - - Formula[] f = new Formula[intersectSet1.size()]; - Iterator iterator = intersectSet1.iterator(); - for (int i = 0; i < f.length; i++) { - f[i] = Formula.not(Formula.var(iterator.next())); - } - Formula formula = Formula.and(f); - - if (debug) - System.out.println(formula.get().toString()); + + return calculateIntersectionOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); + } + + private static Relevance calculateFeatureSetToDeselectFromDiff(VariationDiff diff, VariationTree variant2, boolean debug) { + Set featuresV1 = new HashSet(); + diff.forAll(node -> { + if (node.getDiffType().existsAtTime(Time.BEFORE)) { + featuresV1.addAll(node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures()); + } + if (node.getDiffType().existsAtTime(Time.AFTER)) { + featuresV1.addAll(node.getFeatureMapping(Time.AFTER).getUniqueContainedFeatures()); + } + }); + + Set featuresV2 = new HashSet(); + variant2.forAllPreorder(node -> { + featuresV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); - Relevance rho = new Configure(formula); - return rho; + return calculateIntersectionOfFeatureSets(featuresV1, featuresV2, debug); } private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, @@ -114,19 +138,19 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); - + int indexSourceBefore = indexSource - 1; while (neighborBeforeSource != null && neighborBeforeSource.diffType == DiffType.REM && indexSourceBefore > 0) { indexSourceBefore--; neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSourceBefore - 1); } - + int indexTargetBefore = indexTarget - 1; while (neighborBeforeTarget != null && neighborBeforeTarget.diffType == DiffType.REM && indexTargetBefore > 0) { indexTargetBefore--; neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTargetBefore - 1); } - + if (debug) { if (neighborBeforeSource != null) { System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); @@ -192,11 +216,14 @@ private static int findPositionOfMatchingNeighborInList(DiffNode private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, Time time, boolean debug) throws Exception { - if (debug) System.out.println("Root node to insert: " + root.toString()); + if (debug) + System.out.println("Root node to insert: " + root.toString()); List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); - if (debug) System.out.println("Children of target node: " + orderedChildrenTarget.toString()); + if (debug) + System.out.println("Children of target node: " + orderedChildrenTarget.toString()); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - if (debug) System.out.println("Children of source node: " + orderedChildrenSource.toString()); + if (debug) + System.out.println("Children of source node: " + orderedChildrenSource.toString()); int indexSource = orderedChildrenSource.indexOf(root); DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource - 1); @@ -229,11 +256,13 @@ private static int findInsertPosition(DiffNode root, DiffNode -1 && indexAfter > -1) { if (indexAfter - indexBefore > 1) { // TODO: Alignment Problem + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + " to " + + indexAfter); return -1; } return indexAfter; @@ -263,7 +292,7 @@ private static void applyChanges(DiffType type, VariationDiff ta .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } - + if (targetNodes.size() != 1) { System.out.println("too much or too less target nodes found"); } else { @@ -318,10 +347,16 @@ private static void patchVariationTrees(VariationTree sourceVari System.out.println("Parsing error"); return; } - VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - Relevance rho = calculateFeatureSetToDeselect(sourceVariantVersion1, sourceVariantVersion2, targetVariant, - false); + patchVariationTrees(diff, targetVariant); + } + + private static void patchVariationTrees(VariationDiff diff, VariationTree targetVariant) + throws Exception { + +// Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, +// false); + Relevance rho = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, false); VariationDiff optimizedDiff = DiffView.optimized(diff, rho); VariationDiffSource source = optimizedDiff.getSource(); VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); @@ -339,7 +374,7 @@ private static void patchVariationTrees(VariationTree sourceVari .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) .collect(Collectors.toList()); applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, - source, false); + source, true); // remove old nodes Set> removedNodes = new HashSet>(); @@ -354,11 +389,18 @@ private static void patchVariationTrees(VariationTree sourceVari n2.getLinesAtTime(Time.BEFORE).fromInclusive())) .collect(Collectors.toList()); applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSortedSubtreeRoots, - source, false); + source, true); + GameEngine.showAndAwaitAll(Show.diff(diff)); +// GameEngine.showAndAwaitAll(Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), +// Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), +// Show.tree(targetVariantDiffPatched.project(Time.AFTER))); + } - GameEngine.showAndAwaitAll(Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), - Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), - Show.tree(targetVariantDiffPatched.project(Time.AFTER))); + private static VariationDiff parseVariationDiffFromFiles(String file1, String file2) + throws IOException, DiffParseException { + Path examplesDir = Path.of("data", "examples"); + return VariationDiff.fromFiles(examplesDir.resolve(file1), examplesDir.resolve(file2), + DiffAlgorithm.SupportedAlgorithm.MYERS, VariationDiffParseOptions.Default); } private static VariationTree parseVariationTreeFromFile(String file) { @@ -379,8 +421,13 @@ public static void main(String[] args) { try { // patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), // parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); - patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), - parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), +// parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); + patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), + parseVariationTreeFromFile("exampleBRemAdd.cpp")); +// patchVariationTrees(parseVariationTreeFromFile("exampleA1RemAdd.cpp"), +// parseVariationTreeFromFile("exampleA2RemAdd.cpp"), +// parseVariationTreeFromFile("exampleBRemAdd.cpp")); } catch (Exception e) { System.out.println("Rejected"); e.printStackTrace(); From 02aa6bac57233410cfd74ea1732a7038670db164 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 25 Jul 2025 19:29:16 +0200 Subject: [PATCH 020/162] refactoring, detect alignment problem for ADD nodes, fixed: show subtrees with root --- .../thesis_pm/PatchingExperiment.java | 71 +++++++++++++------ 1 file changed, 48 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 1bdcad718..043c2b3b1 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -30,21 +30,24 @@ public class PatchingExperiment { - private static Relevance calculateIntersectionOfFeatureSets(Set featureSet1, Set featureSet2, boolean debug) { + private static Set calculateSetMinusOfFeatureSets(Set featureSet1, Set featureSet2, boolean debug) { Set intersectSet1 = new HashSet<>(featureSet1); intersectSet1.removeAll(featureSet2); Set intersectSet2 = new HashSet<>(featureSet2); intersectSet2.removeAll(featureSet1); intersectSet1.addAll(intersectSet2); - if (debug) { System.out.println(featureSet1); System.out.println(featureSet2); System.out.println(intersectSet1); } - - Formula[] f = new Formula[intersectSet1.size()]; - Iterator iterator = intersectSet1.iterator(); + return intersectSet1; + } + + private static Relevance calculateFormulaForDeselection(Set set, boolean debug) { + + Formula[] f = new Formula[set.size()]; + Iterator iterator = set.iterator(); for (int i = 0; i < f.length; i++) { f[i] = Formula.not(Formula.var(iterator.next())); } @@ -56,7 +59,7 @@ private static Relevance calculateIntersectionOfFeatureSets(Set featureS return new Configure(formula); } - private static Relevance calculateFeatureSetToDeselectFromTrees(VariationTree variant1version1, + private static Set calculateFeatureSetToDeselectFromTrees(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { Set featuresTreeV1 = new HashSet(); variant1version1.forAllPreorder(node -> { @@ -71,12 +74,11 @@ private static Relevance calculateFeatureSetToDeselectFromTrees(VariationTree { featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); }); - - return calculateIntersectionOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); + return calculateSetMinusOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); } - private static Relevance calculateFeatureSetToDeselectFromDiff(VariationDiff diff, VariationTree variant2, boolean debug) { + private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diff, VariationTree variant2, boolean debug) { Set featuresV1 = new HashSet(); diff.forAll(node -> { if (node.getDiffType().existsAtTime(Time.BEFORE)) { @@ -92,7 +94,7 @@ private static Relevance calculateFeatureSetToDeselectFromDiff(VariationDiff> findRootsOfSubtrees(Set> nodes, DiffType type, @@ -213,8 +215,19 @@ private static int findPositionOfMatchingNeighborInList(DiffNode } return -1; } + + private static boolean isAlignmentProblem(List> subList, Set deselectedFeatures, Time time) { + boolean isAlignmentProblem = false; + for (DiffNode node : subList) { + Set containedFeatures = node.getPresenceCondition(time).getUniqueContainedFeatures(); + System.out.println(containedFeatures); + isAlignmentProblem = containedFeatures.stream().anyMatch(feature -> deselectedFeatures.contains(feature)); + System.out.println("is alignment problem: " + isAlignmentProblem); + } + return isAlignmentProblem; + } - private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, + private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, Set deselectedFeatures, Time time, boolean debug) throws Exception { if (debug) System.out.println("Root node to insert: " + root.toString()); @@ -260,9 +273,16 @@ private static int findInsertPosition(DiffNode root, DiffNode -1 && indexAfter > -1) { if (indexAfter - indexBefore > 1) { - // TODO: Alignment Problem - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + " to " - + indexAfter); + // Alignment Problem ? + // TODO: Check if code belongs to features which are only present in target variant + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, indexAfter); + System.out.println(orderedChildrenTargetSubList); + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + " to " + + indexAfter); + } else { + throw new Exception("Reject"); + } return -1; } return indexAfter; @@ -272,13 +292,15 @@ private static int findInsertPosition(DiffNode root, DiffNode targetVariantDiffUnchanged, VariationDiff targetVariantDiffPatched, List> subtreeRoots, - VariationDiffSource source, boolean debug) throws Exception { + VariationDiffSource source, Set deselectedFeatures, boolean debug) throws Exception { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; for (DiffNode root : subtreeRoots) { if (debug) { - VariationDiff subTree = new VariationDiff(root.deepCopy(), source); + DiffNode newRoot = DiffNode.createRoot(new DiffLinesLabel()); + newRoot.addChild(root.deepCopy(), time); + VariationDiff subTree = new VariationDiff(newRoot, source); GameEngine.showAndAwaitAll(Show.diff(subTree)); } @@ -301,7 +323,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { - int insertPosition = findInsertPosition(root, targetNodeInPatch, time, true); + int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, true); if (insertPosition < 0) { System.out.println("no matching insert position found"); } else { @@ -356,7 +378,8 @@ private static void patchVariationTrees(VariationDiff diff, Vari // Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, // false); - Relevance rho = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, false); + Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, false); + Relevance rho = calculateFormulaForDeselection(deselectedFeatures, false); VariationDiff optimizedDiff = DiffView.optimized(diff, rho); VariationDiffSource source = optimizedDiff.getSource(); VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); @@ -374,7 +397,7 @@ private static void patchVariationTrees(VariationDiff diff, Vari .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) .collect(Collectors.toList()); applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, - source, true); + source, deselectedFeatures, true); // remove old nodes Set> removedNodes = new HashSet>(); @@ -389,8 +412,8 @@ private static void patchVariationTrees(VariationDiff diff, Vari n2.getLinesAtTime(Time.BEFORE).fromInclusive())) .collect(Collectors.toList()); applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSortedSubtreeRoots, - source, true); - GameEngine.showAndAwaitAll(Show.diff(diff)); + source, deselectedFeatures, true); + GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); // GameEngine.showAndAwaitAll(Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), // Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), // Show.tree(targetVariantDiffPatched.project(Time.AFTER))); @@ -423,11 +446,13 @@ public static void main(String[] args) { // parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); // patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), // parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); - patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), - parseVariationTreeFromFile("exampleBRemAdd.cpp")); +// patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), +// parseVariationTreeFromFile("exampleBRemAdd.cpp")); // patchVariationTrees(parseVariationTreeFromFile("exampleA1RemAdd.cpp"), // parseVariationTreeFromFile("exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); + patchVariationTrees(parseVariationDiffFromFiles("exampleA1AddAlignmentP.cpp", "exampleA2AddAlignmentP.cpp"), + parseVariationTreeFromFile("exampleBAddAlignmentP.cpp")); } catch (Exception e) { System.out.println("Rejected"); e.printStackTrace(); From 7cba4bd54921ff8e7c3ab44f3d4612ff283d0d4e Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 25 Jul 2025 19:38:27 +0200 Subject: [PATCH 021/162] changed gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 758bef454..02649e1ec 100644 --- a/.gitignore +++ b/.gitignore @@ -121,7 +121,6 @@ patches/* /input /error -examples/ docs/javadoc /log.txt From b6e835a74b9a808b65328d83c02bd5f874cf60c6 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 25 Jul 2025 19:42:12 +0200 Subject: [PATCH 022/162] examples add, rem, add-rem, add-alignment, rem-alignment --- data/examples/exampleA1Add.cpp | 14 ++++++++++++++ data/examples/exampleA1AddAlignmentP.cpp | 7 +++++++ data/examples/exampleA1Rem.cpp | 17 +++++++++++++++++ data/examples/exampleA1RemAdd.cpp | 17 +++++++++++++++++ data/examples/exampleA1RemAlignmentP.cpp | 7 +++++++ data/examples/exampleA2Add.cpp | 18 ++++++++++++++++++ data/examples/exampleA2AddAlignmentP.cpp | 10 ++++++++++ data/examples/exampleA2Rem.cpp | 13 +++++++++++++ data/examples/exampleA2RemAdd.cpp | 14 ++++++++++++++ data/examples/exampleA2RemAlignmentP.cpp | 6 ++++++ data/examples/exampleBAdd.cpp | 7 +++++++ data/examples/exampleBAddAlignmentP.cpp | 10 ++++++++++ data/examples/exampleBRem.cpp | 10 ++++++++++ data/examples/exampleBRemAdd.cpp | 14 ++++++++++++++ data/examples/exampleBRemAlignmentP.cpp | 10 ++++++++++ 15 files changed, 174 insertions(+) create mode 100644 data/examples/exampleA1Add.cpp create mode 100644 data/examples/exampleA1AddAlignmentP.cpp create mode 100644 data/examples/exampleA1Rem.cpp create mode 100644 data/examples/exampleA1RemAdd.cpp create mode 100644 data/examples/exampleA1RemAlignmentP.cpp create mode 100644 data/examples/exampleA2Add.cpp create mode 100644 data/examples/exampleA2AddAlignmentP.cpp create mode 100644 data/examples/exampleA2Rem.cpp create mode 100644 data/examples/exampleA2RemAdd.cpp create mode 100644 data/examples/exampleA2RemAlignmentP.cpp create mode 100644 data/examples/exampleBAdd.cpp create mode 100644 data/examples/exampleBAddAlignmentP.cpp create mode 100644 data/examples/exampleBRem.cpp create mode 100644 data/examples/exampleBRemAdd.cpp create mode 100644 data/examples/exampleBRemAlignmentP.cpp diff --git a/data/examples/exampleA1Add.cpp b/data/examples/exampleA1Add.cpp new file mode 100644 index 000000000..d134a213a --- /dev/null +++ b/data/examples/exampleA1Add.cpp @@ -0,0 +1,14 @@ +#ifdef Feature1 + int x = 5; +#ifdef Feature2 + for (int i = 0; i < 10; i++) { + x += 2; + } +#else + x += 10 +#endif +#ifdef Feature4 + int y = 10; +#endif + x *= x; +#endif diff --git a/data/examples/exampleA1AddAlignmentP.cpp b/data/examples/exampleA1AddAlignmentP.cpp new file mode 100644 index 000000000..4c4139535 --- /dev/null +++ b/data/examples/exampleA1AddAlignmentP.cpp @@ -0,0 +1,7 @@ +#ifdef Feature1 + int x = 5; + x *= x; +#endif +#ifdef Feature2 + y *= 10; +#endif diff --git a/data/examples/exampleA1Rem.cpp b/data/examples/exampleA1Rem.cpp new file mode 100644 index 000000000..5ae29af8b --- /dev/null +++ b/data/examples/exampleA1Rem.cpp @@ -0,0 +1,17 @@ +#ifdef Feature1 + int x = 5; +#ifdef Feature2 + for (int i = 0; i < 10; i++) { + x += 2; + } +#else + x += 10 +#endif +#ifdef Feature4 + int y = 10; +#endif + x *= x; +#ifdef Feature4 + x += 5; +#endif +#endif diff --git a/data/examples/exampleA1RemAdd.cpp b/data/examples/exampleA1RemAdd.cpp new file mode 100644 index 000000000..47167427e --- /dev/null +++ b/data/examples/exampleA1RemAdd.cpp @@ -0,0 +1,17 @@ +int x = 0; +#ifdef Feature1 + x += 100; + #ifdef Feature2 + int y = 50; + #ifdef Feature5 + int z = 100; + #endif + #endif + x *= x; +#endif +#ifdef Feature3 + x += 300; +#endif +#ifdef Feature5 + z *= 100; +#endif diff --git a/data/examples/exampleA1RemAlignmentP.cpp b/data/examples/exampleA1RemAlignmentP.cpp new file mode 100644 index 000000000..4c4139535 --- /dev/null +++ b/data/examples/exampleA1RemAlignmentP.cpp @@ -0,0 +1,7 @@ +#ifdef Feature1 + int x = 5; + x *= x; +#endif +#ifdef Feature2 + y *= 10; +#endif diff --git a/data/examples/exampleA2Add.cpp b/data/examples/exampleA2Add.cpp new file mode 100644 index 000000000..cc70cecef --- /dev/null +++ b/data/examples/exampleA2Add.cpp @@ -0,0 +1,18 @@ +#ifdef Feature1 + int x = 5; +#ifdef Feature3 + for (int i = 0; i < 10; i++) { + x += 2; + } +#else + x += 10 +#endif +#ifdef Feature4 + int y = 10; +#endif + x *= x; +#ifdef Feature4 + x += 5; +#endif + x += 1000; +#endif diff --git a/data/examples/exampleA2AddAlignmentP.cpp b/data/examples/exampleA2AddAlignmentP.cpp new file mode 100644 index 000000000..a91d72608 --- /dev/null +++ b/data/examples/exampleA2AddAlignmentP.cpp @@ -0,0 +1,10 @@ +#ifdef Feature1 + int x = 5; +#ifdef Feature2 + int y = 10; +#endif + x *= x; +#endif +#ifdef Feature2 + y *= 10; +#endif diff --git a/data/examples/exampleA2Rem.cpp b/data/examples/exampleA2Rem.cpp new file mode 100644 index 000000000..e457e0641 --- /dev/null +++ b/data/examples/exampleA2Rem.cpp @@ -0,0 +1,13 @@ +#ifdef Feature1 + int x = 5; +#ifdef Feature3 + for (int i = 0; i < 10; i++) { + x += 2; + } +#else + x += 10 +#endif +#ifdef Feature4 + int y = 10; +#endif +#endif diff --git a/data/examples/exampleA2RemAdd.cpp b/data/examples/exampleA2RemAdd.cpp new file mode 100644 index 000000000..7b1992038 --- /dev/null +++ b/data/examples/exampleA2RemAdd.cpp @@ -0,0 +1,14 @@ +int x = 0; +#ifdef Feature1 + x *= x; +#endif +#ifdef Feature3 + x += 300; + #ifdef Feature2 + x *= 3; + #endif + x += 12; +#endif +#ifdef Feature5 + z *= 100; +#endif diff --git a/data/examples/exampleA2RemAlignmentP.cpp b/data/examples/exampleA2RemAlignmentP.cpp new file mode 100644 index 000000000..1883f22fc --- /dev/null +++ b/data/examples/exampleA2RemAlignmentP.cpp @@ -0,0 +1,6 @@ +#ifdef Feature1 + int x = 5; +#endif +#ifdef Feature2 + y *= 10; +#endif diff --git a/data/examples/exampleBAdd.cpp b/data/examples/exampleBAdd.cpp new file mode 100644 index 000000000..6b3092d42 --- /dev/null +++ b/data/examples/exampleBAdd.cpp @@ -0,0 +1,7 @@ +#ifdef Feature1 + int x = 5; +#ifdef Feature4 + int y = 10; +#endif + x *= x; +#endif diff --git a/data/examples/exampleBAddAlignmentP.cpp b/data/examples/exampleBAddAlignmentP.cpp new file mode 100644 index 000000000..36d009d98 --- /dev/null +++ b/data/examples/exampleBAddAlignmentP.cpp @@ -0,0 +1,10 @@ +#ifdef Feature1 + int x = 5; +#ifdef FeatureB + int b = 1234; +#endif + x *= x; +#endif +#ifdef Feature2 + y *= 10; +#endif diff --git a/data/examples/exampleBRem.cpp b/data/examples/exampleBRem.cpp new file mode 100644 index 000000000..342cba653 --- /dev/null +++ b/data/examples/exampleBRem.cpp @@ -0,0 +1,10 @@ +#ifdef Feature1 + int x = 5; +#ifdef Feature4 + int y = 10; +#endif + x *= x; +#ifdef Feature4 + x += 5; +#endif +#endif diff --git a/data/examples/exampleBRemAdd.cpp b/data/examples/exampleBRemAdd.cpp new file mode 100644 index 000000000..974d94b16 --- /dev/null +++ b/data/examples/exampleBRemAdd.cpp @@ -0,0 +1,14 @@ +int x = 0; +#ifdef Feature1 + x += 100; + #ifdef Feature2 + int y = 50; + #endif + x *= x; + #ifdef FeatureB + int b = 987; + #endif +#endif +#ifdef Feature3 + x += 300; +#endif diff --git a/data/examples/exampleBRemAlignmentP.cpp b/data/examples/exampleBRemAlignmentP.cpp new file mode 100644 index 000000000..36d009d98 --- /dev/null +++ b/data/examples/exampleBRemAlignmentP.cpp @@ -0,0 +1,10 @@ +#ifdef Feature1 + int x = 5; +#ifdef FeatureB + int b = 1234; +#endif + x *= x; +#endif +#ifdef Feature2 + y *= 10; +#endif From dbe6ba59ffb6e8a90ba660cab2b7a13c9822060c Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 25 Jul 2025 19:58:42 +0200 Subject: [PATCH 023/162] detect alignment problem for REM nodes --- .../thesis_pm/PatchingExperiment.java | 163 ++++++++++-------- 1 file changed, 95 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 043c2b3b1..f8866d2f7 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -121,7 +121,7 @@ private static DiffNode getChildFromListIfIndexInRange(List root, DiffNode targetNodeInPatch, - DiffNode node, Time time, boolean debug) { + DiffNode node, Set deselectedFeatures, Time time, boolean debug) { List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); if (!orderedChildrenTarget.contains(node)) { @@ -133,73 +133,100 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget + 1); - + + int indexSourceMatchingNeighborBefore = -2; + int indexSourceMatchingNeighborAfter = -2; List> orderedChildrenSource = root.getParent(time).getChildOrder(time); int indexSource = orderedChildrenSource.indexOf(root); - DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, - indexSource - 1); - DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, - indexSource + 1); - - int indexSourceBefore = indexSource - 1; - while (neighborBeforeSource != null && neighborBeforeSource.diffType == DiffType.REM && indexSourceBefore > 0) { - indexSourceBefore--; - neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSourceBefore - 1); - } - - int indexTargetBefore = indexTarget - 1; - while (neighborBeforeTarget != null && neighborBeforeTarget.diffType == DiffType.REM && indexTargetBefore > 0) { - indexTargetBefore--; - neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTargetBefore - 1); - } - - if (debug) { - if (neighborBeforeSource != null) { - System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); - } else { - System.out.print("No neighbor before; "); - } - if (neighborAfterSource != null) { - System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); - } else { - System.out.print("No neighbor after\n"); - } - } - - if ((neighborBeforeSource != null && neighborBeforeTarget == null) - || (neighborBeforeSource == null && neighborBeforeTarget != null)) { - System.out.println("Different neighbors before"); - return false; + if (neighborBeforeTarget != null) { + indexSourceMatchingNeighborBefore = findPositionOfMatchingNeighborInList(neighborBeforeTarget, orderedChildrenSource, time); } - if (neighborBeforeSource != null && neighborBeforeTarget != null) { - if (!Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { - System.out.println("Different neighbor before"); - return false; - } + if (neighborAfterTarget != null) { + indexSourceMatchingNeighborAfter = findPositionOfMatchingNeighborInList(neighborAfterTarget, orderedChildrenSource, time); } - // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no - // neighbor before) - - if ((neighborAfterSource != null && neighborAfterTarget == null) - || (neighborAfterSource == null && neighborAfterTarget != null)) { - System.out.println("Different neighbors after"); - return false; + if (indexSourceMatchingNeighborBefore == -2 && indexSourceMatchingNeighborAfter == -2) { + System.out.println("No neighbors before or after the target"); + return true; } - if (neighborAfterSource != null && neighborAfterTarget != null) { - if (!Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { - System.out.println("Different neighbors after"); - return false; + if (indexSourceMatchingNeighborBefore > -1 && indexSourceMatchingNeighborAfter > -1) { + if (indexSourceMatchingNeighborAfter - indexSourceMatchingNeighborBefore > 1) { + // Alignment Problem ? + // TODO: Check if code belongs to features which are only present in target variant + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexSourceMatchingNeighborBefore + 1, indexSourceMatchingNeighborAfter); + System.out.println(orderedChildrenTargetSubList); + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Node can be removed."); + } else { + return false; + } } } - // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no - // neighbor after) - return true; + +// DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, +// indexSource - 1); +// DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, +// indexSource + 1); + +// int indexSourceBefore = indexSource - 1; +// while (neighborBeforeSource != null && neighborBeforeSource.diffType == DiffType.REM && indexSourceBefore > 0) { +// indexSourceBefore--; +// neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSourceBefore - 1); +// } +// +// int indexTargetBefore = indexTarget - 1; +// while (neighborBeforeTarget != null && neighborBeforeTarget.diffType == DiffType.REM && indexTargetBefore > 0) { +// indexTargetBefore--; +// neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTargetBefore - 1); +// } +// +// if (debug) { +// if (neighborBeforeSource != null) { +// System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); +// } else { +// System.out.print("No neighbor before; "); +// } +// if (neighborAfterSource != null) { +// System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); +// } else { +// System.out.print("No neighbor after\n"); +// } +// } +// +// if ((neighborBeforeSource != null && neighborBeforeTarget == null) +// || (neighborBeforeSource == null && neighborBeforeTarget != null)) { +// System.out.println("Different neighbors before"); +// return false; +// } +// if (neighborBeforeSource != null && neighborBeforeTarget != null) { +// if (!Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { +// System.out.println("Different neighbor before"); +// return false; +// } +// } +// // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no +// // neighbor before) +// +// if ((neighborAfterSource != null && neighborAfterTarget == null) +// || (neighborAfterSource == null && neighborAfterTarget != null)) { +// System.out.println("Different neighbors after"); +// return false; +// } +// if (neighborAfterSource != null && neighborAfterTarget != null) { +// if (!Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { +// System.out.println("Different neighbors after"); +// return false; +// } +// } +// // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no +// // neighbor after) +// +// return true; } private static int findPositionOfMatchingNeighborInList(DiffNode neighbor, - List> list, Time time) throws Exception { + List> list, Time time) { ArrayList positions = new ArrayList(); for (DiffNode node : list) { if (Patching.isSameAs(neighbor, node, time)) { @@ -211,7 +238,8 @@ private static int findPositionOfMatchingNeighborInList(DiffNode } if (positions.size() > 1) { // TODO: throw exception? - throw new Exception(); +// throw new Exception(); + return -1; } return -1; } @@ -337,23 +365,20 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println("Root: " + root.toString()); System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); targetNodeInPatch.getAllChildrenStream().forEach(node -> { - if (Patching.isSameAs(node, root, time)) + if (Patching.isSameAs(node, root, time) && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, debug)) nodesToRem.add(node); }); System.out.println("Nodes to remove: " + nodesToRem); - List> nodesToRemAfterCheckingNeighbors = nodesToRem.stream() - .filter((node) -> checkNeighbors(root, targetNodeInPatch, node, time, true)).toList(); - - if (nodesToRemAfterCheckingNeighbors.size() != 1) { + if (nodesToRem.size() != 1) { System.out.println("too much or too less target nodes found"); - System.out.println(nodesToRemAfterCheckingNeighbors.toString()); + System.out.println(nodesToRem.toString()); } else { System.out.println("subtree removed"); - nodesToRemAfterCheckingNeighbors.get(0).diffType = DiffType.REM; - nodesToRemAfterCheckingNeighbors.get(0).getAllChildrenStream() + nodesToRem.get(0).diffType = DiffType.REM; + nodesToRem.get(0).getAllChildrenStream() .forEach(node -> node.diffType = DiffType.REM); - nodesToRemAfterCheckingNeighbors.get(0).drop(Time.AFTER); + nodesToRem.get(0).drop(Time.AFTER); System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } } @@ -451,8 +476,10 @@ public static void main(String[] args) { // patchVariationTrees(parseVariationTreeFromFile("exampleA1RemAdd.cpp"), // parseVariationTreeFromFile("exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); - patchVariationTrees(parseVariationDiffFromFiles("exampleA1AddAlignmentP.cpp", "exampleA2AddAlignmentP.cpp"), - parseVariationTreeFromFile("exampleBAddAlignmentP.cpp")); +// patchVariationTrees(parseVariationDiffFromFiles("exampleA1AddAlignmentP.cpp", "exampleA2AddAlignmentP.cpp"), +// parseVariationTreeFromFile("exampleBAddAlignmentP.cpp")); + patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAlignmentP.cpp", "exampleA2RemAlignmentP.cpp"), + parseVariationTreeFromFile("exampleBRemAlignmentP.cpp")); } catch (Exception e) { System.out.println("Rejected"); e.printStackTrace(); From c67ea436889c3f75ca77a23cbb40d15091cd578d Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 27 Jul 2025 16:05:02 +0200 Subject: [PATCH 024/162] example rem-add-alignment --- data/examples/exampleA1RemAddAlignmentP.cpp | 17 +++++++++++++++++ data/examples/exampleA2RemAddAlignmentP.cpp | 14 ++++++++++++++ data/examples/exampleBRemAddAlignmentP.cpp | 17 +++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 data/examples/exampleA1RemAddAlignmentP.cpp create mode 100644 data/examples/exampleA2RemAddAlignmentP.cpp create mode 100644 data/examples/exampleBRemAddAlignmentP.cpp diff --git a/data/examples/exampleA1RemAddAlignmentP.cpp b/data/examples/exampleA1RemAddAlignmentP.cpp new file mode 100644 index 000000000..9578697ba --- /dev/null +++ b/data/examples/exampleA1RemAddAlignmentP.cpp @@ -0,0 +1,17 @@ +int x = 0; +#ifdef Feature1 + x += 100; + #ifdef Feature2 + int y = 50; + #ifdef FeatureA + int z = 100; + #endif + #endif + x *= x; +#endif +#ifdef Feature3 + x += 300; +#endif +#ifdef FeatureA + z *= 100; +#endif diff --git a/data/examples/exampleA2RemAddAlignmentP.cpp b/data/examples/exampleA2RemAddAlignmentP.cpp new file mode 100644 index 000000000..0f8a08172 --- /dev/null +++ b/data/examples/exampleA2RemAddAlignmentP.cpp @@ -0,0 +1,14 @@ +int x = 0; +#ifdef Feature1 + x *= x; +#endif +#ifdef Feature3 + x += 300; + #ifdef Feature2 + x *= 3; + #endif + x += 12; +#endif +#ifdef FeatureA + z *= 100; +#endif diff --git a/data/examples/exampleBRemAddAlignmentP.cpp b/data/examples/exampleBRemAddAlignmentP.cpp new file mode 100644 index 000000000..3a199186a --- /dev/null +++ b/data/examples/exampleBRemAddAlignmentP.cpp @@ -0,0 +1,17 @@ +int x = 0; +#ifdef Feature1 + x += 100; + #ifdef FeatureB + int b = 1234; + #endif + #ifdef Feature2 + int y = 50; + #endif + x *= x; +#endif +#ifdef Feature3 + x += 300; + #ifdef FeatureB + b = 987; + #endif +#endif From 8a33fb9fc033a8a1f94c362885bee867cdc7b3f2 Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 27 Jul 2025 16:06:47 +0200 Subject: [PATCH 025/162] fixed bug: alignment problem detection in findInsertPosition() --- .../thesis_pm/PatchingExperiment.java | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index f8866d2f7..6a2e8788d 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -285,19 +285,51 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(0, indexAfter); + if (!orderedChildrenTargetSubList.isEmpty()) { + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + + indexAfter); + } else { + throw new Exception("Reject"); + } + return -1; + } + } + if (indexAfter == -2) { + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, orderedChildrenTarget.size()); + if (!orderedChildrenTargetSubList.isEmpty()) { + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + " to " + + (orderedChildrenTarget.size() - 1)); + } else { + throw new Exception("Reject"); + } + return -1; + } } if (indexBefore > -1 && indexAfter > -1) { if (indexAfter - indexBefore > 1) { @@ -312,6 +344,11 @@ private static int findInsertPosition(DiffNode root, DiffNode ta System.out.println("Root: " + root.toString()); System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); targetNodeInPatch.getAllChildrenStream().forEach(node -> { - if (Patching.isSameAs(node, root, time) && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, debug)) + if (Patching.isSameAs(node, root, time) && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true)) nodesToRem.add(node); }); System.out.println("Nodes to remove: " + nodesToRem); @@ -478,8 +515,10 @@ public static void main(String[] args) { // parseVariationTreeFromFile("exampleBRemAdd.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1AddAlignmentP.cpp", "exampleA2AddAlignmentP.cpp"), // parseVariationTreeFromFile("exampleBAddAlignmentP.cpp")); - patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAlignmentP.cpp", "exampleA2RemAlignmentP.cpp"), - parseVariationTreeFromFile("exampleBRemAlignmentP.cpp")); +// patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAlignmentP.cpp", "exampleA2RemAlignmentP.cpp"), +// parseVariationTreeFromFile("exampleBRemAlignmentP.cpp")); + patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAddAlignmentP.cpp", "exampleA2RemAddAlignmentP.cpp"), + parseVariationTreeFromFile("exampleBRemAddAlignmentP.cpp")); } catch (Exception e) { System.out.println("Rejected"); e.printStackTrace(); From 39e0483b8e61b64b47d1d343da3fdfd3e68e9f9a Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 27 Jul 2025 16:27:05 +0200 Subject: [PATCH 026/162] check for zero variant drift before patching --- .../thesis_pm/PatchingExperiment.java | 19 +++++++++++++++++-- .../variation/diff/patching/Patching.java | 14 ++++++++++---- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 6a2e8788d..4a01e4e40 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -97,6 +97,16 @@ private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diffVariant1, VariationTree variant2, Relevance deselectedFeatures) { + diffVariant1 = DiffView.optimized(diffVariant1.project(Time.BEFORE).toCompletelyUnchangedVariationDiff(), deselectedFeatures); + VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), deselectedFeatures); + GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); + if (Patching.isSameAs(diffVariant1, diffVariant2)) { + return true; + } + return false; + } + private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, boolean debug) { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; @@ -229,7 +239,7 @@ private static int findPositionOfMatchingNeighborInList(DiffNode List> list, Time time) { ArrayList positions = new ArrayList(); for (DiffNode node : list) { - if (Patching.isSameAs(neighbor, node, time)) { + if (Patching.isSameAs(neighbor, node)) { positions.add(list.indexOf(node)); } } @@ -402,7 +412,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println("Root: " + root.toString()); System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); targetNodeInPatch.getAllChildrenStream().forEach(node -> { - if (Patching.isSameAs(node, root, time) && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true)) + if (Patching.isSameAs(node, root) && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true)) nodesToRem.add(node); }); System.out.println("Nodes to remove: " + nodesToRem); @@ -442,6 +452,11 @@ private static void patchVariationTrees(VariationDiff diff, Vari // false); Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, false); Relevance rho = calculateFormulaForDeselection(deselectedFeatures, false); + + if (!checkForZeroVariantDrift(diff, targetVariant, rho)) { + throw new Exception("Variants evolved independently: No Zero Variant Drift"); + } + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); VariationDiffSource source = optimizedDiff.getSource(); VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index cc5674a9f..4bfc2dbd5 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -7,13 +7,19 @@ import org.variantsync.diffdetective.variation.Label; import org.variantsync.diffdetective.variation.diff.DiffNode; import org.variantsync.diffdetective.variation.diff.Time; +import org.variantsync.diffdetective.variation.diff.VariationDiff; public class Patching { - public static boolean isSameAs(DiffNode a, DiffNode b, Time time) { - return isSameAs(a, b, new HashSet<>(), time); + + public static boolean isSameAs(VariationDiff diff1, VariationDiff diff2) { + return isSameAs(diff1.getRoot(), diff2.getRoot()); + } + + public static boolean isSameAs(DiffNode a, DiffNode b) { + return isSameAs(a, b, new HashSet<>()); } - private static boolean isSameAs(DiffNode a, DiffNode b, Set> visited, Time time) { + private static boolean isSameAs(DiffNode a, DiffNode b, Set> visited) { if (!visited.add(a)) { return true; } @@ -31,7 +37,7 @@ private static boolean isSameAs(DiffNode a, DiffNode b, Iterator> aIt = a.getAllChildren().iterator(); Iterator> bIt = b.getAllChildren().iterator(); while (aIt.hasNext() && bIt.hasNext()) { - if (!isSameAs(aIt.next(), bIt.next(), visited, time)) { + if (!isSameAs(aIt.next(), bIt.next(), visited)) { return false; } } From db7a55166bd2ce82f3550e69a834656bcf9b256a Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 29 Jul 2025 20:55:50 +0200 Subject: [PATCH 027/162] compare patched variant and expected result --- .../thesis_pm/PatchingExperiment.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 4a01e4e40..ab4093b39 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -434,18 +434,18 @@ private static void applyChanges(DiffType type, VariationDiff ta } } - private static void patchVariationTrees(VariationTree sourceVariantVersion1, + private static VariationTree patchVariationTrees(VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant) throws Exception { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { System.out.println("Parsing error"); - return; + return null; } VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - patchVariationTrees(diff, targetVariant); + return patchVariationTrees(diff, targetVariant); } - private static void patchVariationTrees(VariationDiff diff, VariationTree targetVariant) + private static VariationTree patchVariationTrees(VariationDiff diff, VariationTree targetVariant) throws Exception { // Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, @@ -490,10 +490,12 @@ private static void patchVariationTrees(VariationDiff diff, Vari .collect(Collectors.toList()); applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSortedSubtreeRoots, source, deselectedFeatures, true); + GameEngine.showAndAwaitAll(Show.diff(diff)); GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); -// GameEngine.showAndAwaitAll(Show.tree(sourceVariantVersion1), Show.tree(sourceVariantVersion2), +// GameEngine.showAndAwaitAll(Show.diff(diff), // Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), // Show.tree(targetVariantDiffPatched.project(Time.AFTER))); + return targetVariantDiffPatched.project(Time.AFTER); } private static VariationDiff parseVariationDiffFromFiles(String file1, String file2) @@ -516,6 +518,10 @@ private static VariationTree parseVariationTreeFromFile(String f } return null; } + + private static boolean comparePatchedVariantWithExpectedResult(VariationTree patchedVariant, VariationTree expectedResult) { + return Patching.isSameAs(patchedVariant.toCompletelyUnchangedVariationDiff(), expectedResult.toCompletelyUnchangedVariationDiff()); + } public static void main(String[] args) { try { @@ -525,15 +531,17 @@ public static void main(String[] args) { // parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); -// patchVariationTrees(parseVariationTreeFromFile("exampleA1RemAdd.cpp"), -// parseVariationTreeFromFile("exampleA2RemAdd.cpp"), -// parseVariationTreeFromFile("exampleBRemAdd.cpp")); + VariationTree patchedVariant = patchVariationTrees(parseVariationTreeFromFile("exampleA1RemAdd.cpp"), + parseVariationTreeFromFile("exampleA2RemAdd.cpp"), + parseVariationTreeFromFile("exampleBRemAdd.cpp")); + VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); + System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1AddAlignmentP.cpp", "exampleA2AddAlignmentP.cpp"), // parseVariationTreeFromFile("exampleBAddAlignmentP.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAlignmentP.cpp", "exampleA2RemAlignmentP.cpp"), // parseVariationTreeFromFile("exampleBRemAlignmentP.cpp")); - patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAddAlignmentP.cpp", "exampleA2RemAddAlignmentP.cpp"), - parseVariationTreeFromFile("exampleBRemAddAlignmentP.cpp")); +// patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAddAlignmentP.cpp", "exampleA2RemAddAlignmentP.cpp"), +// parseVariationTreeFromFile("exampleBRemAddAlignmentP.cpp")); } catch (Exception e) { System.out.println("Rejected"); e.printStackTrace(); From cde399942f0eaff0a432bd28f239fb95701dd8c3 Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 29 Jul 2025 20:56:29 +0200 Subject: [PATCH 028/162] expected result for example rem-add --- data/examples/exampleBRemAddExpected.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 data/examples/exampleBRemAddExpected.cpp diff --git a/data/examples/exampleBRemAddExpected.cpp b/data/examples/exampleBRemAddExpected.cpp new file mode 100644 index 000000000..ce87a9962 --- /dev/null +++ b/data/examples/exampleBRemAddExpected.cpp @@ -0,0 +1,14 @@ +int x = 0; +#ifdef Feature1 + x *= x; + #ifdef FeatureB + int b = 987; + #endif +#endif +#ifdef Feature3 + x += 300; + #ifdef Feature2 + x *= 3; + #endif + x += 12; +#endif From 8e81fa7d458aaacd54e618acec9e41fdfeae3d93 Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 29 Jul 2025 21:24:32 +0200 Subject: [PATCH 029/162] fixed bug in findInsertPosition --- .../experiments/thesis_pm/PatchingExperiment.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index ab4093b39..80ac0b36c 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -280,8 +280,11 @@ private static int findInsertPosition(DiffNode root, DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSource + 1); - if (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { - neighborAfterSource = null; + int currentIndexAfter = indexSource + 1; + // ignore neighbors with DiffType ADD because they are added afterwards + while (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { + currentIndexAfter++; + neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, currentIndexAfter); } if (debug) { if (neighborBeforeSource != null) { From cb25dce4a571176e775cf260a5ef68b4707a1627 Mon Sep 17 00:00:00 2001 From: piameier Date: Wed, 30 Jul 2025 15:04:53 +0200 Subject: [PATCH 030/162] fixed bugs --- .../thesis_pm/PatchingExperiment.java | 214 +++++++----------- 1 file changed, 88 insertions(+), 126 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 80ac0b36c..9e2b09250 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -29,8 +29,9 @@ import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; public class PatchingExperiment { - - private static Set calculateSetMinusOfFeatureSets(Set featureSet1, Set featureSet2, boolean debug) { + + private static Set calculateSetMinusOfFeatureSets(Set featureSet1, Set featureSet2, + boolean debug) { Set intersectSet1 = new HashSet<>(featureSet1); intersectSet1.removeAll(featureSet2); Set intersectSet2 = new HashSet<>(featureSet2); @@ -43,9 +44,9 @@ private static Set calculateSetMinusOfFeatureSets(Set featureSet } return intersectSet1; } - + private static Relevance calculateFormulaForDeselection(Set set, boolean debug) { - + Formula[] f = new Formula[set.size()]; Iterator iterator = set.iterator(); for (int i = 0; i < f.length; i++) { @@ -58,7 +59,7 @@ private static Relevance calculateFormulaForDeselection(Set set, boolean return new Configure(formula); } - + private static Set calculateFeatureSetToDeselectFromTrees(VariationTree variant1version1, VariationTree variant1version2, VariationTree variant2, boolean debug) { Set featuresTreeV1 = new HashSet(); @@ -74,11 +75,12 @@ private static Set calculateFeatureSetToDeselectFromTrees(VariationTree< variant2.forAllPreorder(node -> { featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); }); - + return calculateSetMinusOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); } - - private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diff, VariationTree variant2, boolean debug) { + + private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diff, + VariationTree variant2, boolean debug) { Set featuresV1 = new HashSet(); diff.forAll(node -> { if (node.getDiffType().existsAtTime(Time.BEFORE)) { @@ -88,7 +90,7 @@ private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff featuresV2 = new HashSet(); variant2.forAllPreorder(node -> { featuresV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); @@ -97,16 +99,19 @@ private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diffVariant1, VariationTree variant2, Relevance deselectedFeatures) { - diffVariant1 = DiffView.optimized(diffVariant1.project(Time.BEFORE).toCompletelyUnchangedVariationDiff(), deselectedFeatures); - VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), deselectedFeatures); + private static boolean checkForZeroVariantDrift(VariationDiff diffVariant1, + VariationTree variant2, Relevance deselectedFeatures) { + diffVariant1 = DiffView.optimized(diffVariant1.project(Time.BEFORE).toCompletelyUnchangedVariationDiff(), + deselectedFeatures); + VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), + deselectedFeatures); GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); if (Patching.isSameAs(diffVariant1, diffVariant2)) { return true; } return false; } - + private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, boolean debug) { Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; @@ -143,26 +148,35 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTarget + 1); - + int indexSourceMatchingNeighborBefore = -2; int indexSourceMatchingNeighborAfter = -2; List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - int indexSource = orderedChildrenSource.indexOf(root); + + if (debug) { + System.out.println("Children Target: " + orderedChildrenTarget); + System.out.println("Children Source: " + orderedChildrenSource); + } + if (neighborBeforeTarget != null) { - indexSourceMatchingNeighborBefore = findPositionOfMatchingNeighborInList(neighborBeforeTarget, orderedChildrenSource, time); + indexSourceMatchingNeighborBefore = findPositionOfMatchingNeighborInList(neighborBeforeTarget, + orderedChildrenSource, time); } if (neighborAfterTarget != null) { - indexSourceMatchingNeighborAfter = findPositionOfMatchingNeighborInList(neighborAfterTarget, orderedChildrenSource, time); + indexSourceMatchingNeighborAfter = findPositionOfMatchingNeighborInList(neighborAfterTarget, + orderedChildrenSource, time); } if (indexSourceMatchingNeighborBefore == -2 && indexSourceMatchingNeighborAfter == -2) { System.out.println("No neighbors before or after the target"); return true; } if (indexSourceMatchingNeighborBefore > -1 && indexSourceMatchingNeighborAfter > -1) { - if (indexSourceMatchingNeighborAfter - indexSourceMatchingNeighborBefore > 1) { + if (indexSourceMatchingNeighborAfter - indexSourceMatchingNeighborBefore > 2) { // Alignment Problem ? - // TODO: Check if code belongs to features which are only present in target variant - List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexSourceMatchingNeighborBefore + 1, indexSourceMatchingNeighborAfter); + // Check if code belongs to features which are only present in target + // variant + List> orderedChildrenTargetSubList = orderedChildrenTarget + .subList(indexSourceMatchingNeighborBefore + 1, indexSourceMatchingNeighborAfter); System.out.println(orderedChildrenTargetSubList); if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { System.out.println("ALIGNMENT PROBLEM. Node can be removed."); @@ -172,67 +186,6 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, -// indexSource - 1); -// DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, -// indexSource + 1); - -// int indexSourceBefore = indexSource - 1; -// while (neighborBeforeSource != null && neighborBeforeSource.diffType == DiffType.REM && indexSourceBefore > 0) { -// indexSourceBefore--; -// neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, indexSourceBefore - 1); -// } -// -// int indexTargetBefore = indexTarget - 1; -// while (neighborBeforeTarget != null && neighborBeforeTarget.diffType == DiffType.REM && indexTargetBefore > 0) { -// indexTargetBefore--; -// neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, indexTargetBefore - 1); -// } -// -// if (debug) { -// if (neighborBeforeSource != null) { -// System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); -// } else { -// System.out.print("No neighbor before; "); -// } -// if (neighborAfterSource != null) { -// System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); -// } else { -// System.out.print("No neighbor after\n"); -// } -// } -// -// if ((neighborBeforeSource != null && neighborBeforeTarget == null) -// || (neighborBeforeSource == null && neighborBeforeTarget != null)) { -// System.out.println("Different neighbors before"); -// return false; -// } -// if (neighborBeforeSource != null && neighborBeforeTarget != null) { -// if (!Patching.isSameAs(neighborBeforeSource, neighborBeforeTarget, time)) { -// System.out.println("Different neighbor before"); -// return false; -// } -// } -// // neighborBeforeSource isSameAs neighborBeforeTarget OR both are null (no -// // neighbor before) -// -// if ((neighborAfterSource != null && neighborAfterTarget == null) -// || (neighborAfterSource == null && neighborAfterTarget != null)) { -// System.out.println("Different neighbors after"); -// return false; -// } -// if (neighborAfterSource != null && neighborAfterTarget != null) { -// if (!Patching.isSameAs(neighborAfterSource, neighborAfterTarget, time)) { -// System.out.println("Different neighbors after"); -// return false; -// } -// } -// // neighborAfterSource isSameAs neighborAfterTarget OR both are null (no -// // neighbor after) -// -// return true; - } private static int findPositionOfMatchingNeighborInList(DiffNode neighbor, @@ -253,8 +206,9 @@ private static int findPositionOfMatchingNeighborInList(DiffNode } return -1; } - - private static boolean isAlignmentProblem(List> subList, Set deselectedFeatures, Time time) { + + private static boolean isAlignmentProblem(List> subList, Set deselectedFeatures, + Time time) { boolean isAlignmentProblem = false; for (DiffNode node : subList) { Set containedFeatures = node.getPresenceCondition(time).getUniqueContainedFeatures(); @@ -265,8 +219,8 @@ private static boolean isAlignmentProblem(List> subList return isAlignmentProblem; } - private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, Set deselectedFeatures, - Time time, boolean debug) throws Exception { + private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, + Set deselectedFeatures, Time time, boolean debug) throws Exception { if (debug) System.out.println("Root node to insert: " + root.toString()); List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); @@ -303,7 +257,7 @@ private static int findInsertPosition(DiffNode root, DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(0, indexAfter); if (!orderedChildrenTargetSubList.isEmpty()) { if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " - + indexAfter); + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + indexAfter); } else { throw new Exception("Reject"); } @@ -333,11 +286,13 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, orderedChildrenTarget.size()); + List> orderedChildrenTargetSubList = orderedChildrenTarget + .subList(indexBefore + 1, orderedChildrenTarget.size()); + System.out.println(orderedChildrenTargetSubList); if (!orderedChildrenTargetSubList.isEmpty()) { if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + " to " - + (orderedChildrenTarget.size() - 1)); + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + + " to " + (orderedChildrenTarget.size() - 1)); } else { throw new Exception("Reject"); } @@ -347,17 +302,19 @@ private static int findInsertPosition(DiffNode root, DiffNode -1 && indexAfter > -1) { if (indexAfter - indexBefore > 1) { // Alignment Problem ? - // TODO: Check if code belongs to features which are only present in target variant - List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, indexAfter); + // TODO: Check if code belongs to features which are only present in target + // variant + List> orderedChildrenTargetSubList = orderedChildrenTarget + .subList(indexBefore + 1, indexAfter); System.out.println(orderedChildrenTargetSubList); if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + " to " - + indexAfter); + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + + " to " + indexAfter); } else { throw new Exception("Reject"); } return -1; - } + } if (indexAfter - indexBefore < 0) { // TODO: root must be between neighbors System.out.println("Neighbors in wrong order"); @@ -415,7 +372,8 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println("Root: " + root.toString()); System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); targetNodeInPatch.getAllChildrenStream().forEach(node -> { - if (Patching.isSameAs(node, root) && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true)) + if (Patching.isSameAs(node, root) + && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true)) nodesToRem.add(node); }); System.out.println("Nodes to remove: " + nodesToRem); @@ -426,8 +384,7 @@ private static void applyChanges(DiffType type, VariationDiff ta } else { System.out.println("subtree removed"); nodesToRem.get(0).diffType = DiffType.REM; - nodesToRem.get(0).getAllChildrenStream() - .forEach(node -> node.diffType = DiffType.REM); + nodesToRem.get(0).getAllChildrenStream().forEach(node -> node.diffType = DiffType.REM); nodesToRem.get(0).drop(Time.AFTER); System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } @@ -437,9 +394,9 @@ private static void applyChanges(DiffType type, VariationDiff ta } } - private static VariationTree patchVariationTrees(VariationTree sourceVariantVersion1, - VariationTree sourceVariantVersion2, VariationTree targetVariant) - throws Exception { + private static VariationTree patchVariationTrees( + VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, + VariationTree targetVariant) throws Exception { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { System.out.println("Parsing error"); return null; @@ -448,36 +405,24 @@ private static VariationTree patchVariationTrees(VariationTree patchVariationTrees(VariationDiff diff, VariationTree targetVariant) - throws Exception { - + private static VariationTree patchVariationTrees(VariationDiff diff, + VariationTree targetVariant) throws Exception { + // Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, // false); Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, false); Relevance rho = calculateFormulaForDeselection(deselectedFeatures, false); - + if (!checkForZeroVariantDrift(diff, targetVariant, rho)) { throw new Exception("Variants evolved independently: No Zero Variant Drift"); } - + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); VariationDiffSource source = optimizedDiff.getSource(); VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); - // add new nodes - Set> addedNodes = new HashSet>(); - optimizedDiff.forAll(node -> { - if (node.isAdd()) { - addedNodes.add(node); - } - }); - Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); - List> addedSortedSubtreeRoots = addedSubtreeRoots.stream().sorted((n1, n2) -> Integer - .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) - .collect(Collectors.toList()); - applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, - source, deselectedFeatures, true); + GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched), Show.diff(optimizedDiff)); // remove old nodes Set> removedNodes = new HashSet>(); @@ -493,6 +438,21 @@ private static VariationTree patchVariationTrees(VariationDiff> addedNodes = new HashSet>(); + optimizedDiff.forAll(node -> { + if (node.isAdd()) { + addedNodes.add(node); + } + }); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); + List> addedSortedSubtreeRoots = addedSubtreeRoots.stream().sorted((n1, n2) -> Integer + .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) + .collect(Collectors.toList()); + applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, + source, deselectedFeatures, true); + GameEngine.showAndAwaitAll(Show.diff(diff)); GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); // GameEngine.showAndAwaitAll(Show.diff(diff), @@ -521,9 +481,11 @@ private static VariationTree parseVariationTreeFromFile(String f } return null; } - - private static boolean comparePatchedVariantWithExpectedResult(VariationTree patchedVariant, VariationTree expectedResult) { - return Patching.isSameAs(patchedVariant.toCompletelyUnchangedVariationDiff(), expectedResult.toCompletelyUnchangedVariationDiff()); + + private static boolean comparePatchedVariantWithExpectedResult(VariationTree patchedVariant, + VariationTree expectedResult) { + return Patching.isSameAs(patchedVariant.toCompletelyUnchangedVariationDiff(), + expectedResult.toCompletelyUnchangedVariationDiff()); } public static void main(String[] args) { @@ -534,8 +496,8 @@ public static void main(String[] args) { // parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); - VariationTree patchedVariant = patchVariationTrees(parseVariationTreeFromFile("exampleA1RemAdd.cpp"), - parseVariationTreeFromFile("exampleA2RemAdd.cpp"), + VariationTree patchedVariant = patchVariationTrees( + parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), parseVariationTreeFromFile("exampleBRemAdd.cpp")); VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); From 5e58efb8e4662e9623638a8f436b8139d58da386 Mon Sep 17 00:00:00 2001 From: piameier Date: Wed, 30 Jul 2025 16:39:05 +0200 Subject: [PATCH 031/162] added removeNode to recursively drop nodes --- .../thesis_pm/PatchingExperiment.java | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 9e2b09250..c9677ea8b 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -383,9 +383,7 @@ && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true) System.out.println(nodesToRem.toString()); } else { System.out.println("subtree removed"); - nodesToRem.get(0).diffType = DiffType.REM; - nodesToRem.get(0).getAllChildrenStream().forEach(node -> node.diffType = DiffType.REM); - nodesToRem.get(0).drop(Time.AFTER); + removeNode(nodesToRem.get(0)); System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); } } @@ -393,6 +391,15 @@ && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true) } } } + + private static void removeNode(DiffNode node) { + Set> children = node.getAllChildrenSet(); + if (!children.isEmpty()) { + children.forEach(child -> removeNode(child)); + } + node.diffType = DiffType.REM; + node.drop(Time.AFTER); + } private static VariationTree patchVariationTrees( VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, @@ -496,11 +503,19 @@ public static void main(String[] args) { // parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); + +// VariationTree patchedVariant = patchVariationTrees( +// parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), +// parseVariationTreeFromFile("exampleBRemAdd.cpp")); +// VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); +// System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); + VariationTree patchedVariant = patchVariationTrees( parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), - parseVariationTreeFromFile("exampleBRemAdd.cpp")); - VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); + parseVariationTreeFromFile("exampleA1RemAdd.cpp")); + VariationTree expectedResult = parseVariationTreeFromFile("exampleA2RemAdd.cpp"); System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); + // patchVariationTrees(parseVariationDiffFromFiles("exampleA1AddAlignmentP.cpp", "exampleA2AddAlignmentP.cpp"), // parseVariationTreeFromFile("exampleBAddAlignmentP.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAlignmentP.cpp", "exampleA2RemAlignmentP.cpp"), From e6a5ad628344a19b12572d171390ea1233028bdc Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 1 Aug 2025 09:56:38 +0200 Subject: [PATCH 032/162] fixed bug with untouched nodes but with changed parents --- .../thesis_pm/PatchingExperiment.java | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index c9677ea8b..4ed4b8c5f 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -152,12 +152,12 @@ private static boolean checkNeighbors(DiffNode root, DiffNode> orderedChildrenSource = root.getParent(time).getChildOrder(time); - + if (debug) { System.out.println("Children Target: " + orderedChildrenTarget); System.out.println("Children Source: " + orderedChildrenSource); } - + if (neighborBeforeTarget != null) { indexSourceMatchingNeighborBefore = findPositionOfMatchingNeighborInList(neighborBeforeTarget, orderedChildrenSource, time); @@ -286,8 +286,8 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget - .subList(indexBefore + 1, orderedChildrenTarget.size()); + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, + orderedChildrenTarget.size()); System.out.println(orderedChildrenTargetSubList); if (!orderedChildrenTargetSubList.isEmpty()) { if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { @@ -391,7 +391,7 @@ && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true) } } } - + private static void removeNode(DiffNode node) { Set> children = node.getAllChildrenSet(); if (!children.isEmpty()) { @@ -431,8 +431,18 @@ private static VariationTree patchVariationTrees(VariationDiff> removedNodes = new HashSet>(); + Set> addedNodes = new HashSet>(); + + // find nodes with DiffType NON but changed parents + optimizedDiff.forAll(node -> { + if (node.isNon() && node.getParent(Time.BEFORE) != node.getParent(Time.AFTER)) { + removedNodes.add(node); + addedNodes.add(node); + } + }); + + // remove old nodes optimizedDiff.forAll(node -> { if (node.isRem()) { removedNodes.add(node); @@ -447,7 +457,6 @@ private static VariationTree patchVariationTrees(VariationDiff> addedNodes = new HashSet>(); optimizedDiff.forAll(node -> { if (node.isAdd()) { addedNodes.add(node); @@ -503,19 +512,26 @@ public static void main(String[] args) { // parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); - + // VariationTree patchedVariant = patchVariationTrees( // parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); // VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); // System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); - + VariationTree patchedVariant = patchVariationTrees( - parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), - parseVariationTreeFromFile("exampleA1RemAdd.cpp")); - VariationTree expectedResult = parseVariationTreeFromFile("exampleA2RemAdd.cpp"); + parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", "exampleA2NodesWith2Parents.cpp"), + parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp")); + VariationTree expectedResult = parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); + GameEngine.showAndAwaitAll(Show.tree(patchedVariant), Show.tree(expectedResult)); System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); - + +// VariationTree patchedVariant = patchVariationTrees( +// parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), +// parseVariationTreeFromFile("exampleA1RemAdd.cpp")); +// VariationTree expectedResult = parseVariationTreeFromFile("exampleA2RemAdd.cpp"); +// System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); + // patchVariationTrees(parseVariationDiffFromFiles("exampleA1AddAlignmentP.cpp", "exampleA2AddAlignmentP.cpp"), // parseVariationTreeFromFile("exampleBAddAlignmentP.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAlignmentP.cpp", "exampleA2RemAlignmentP.cpp"), From 170206d5ef404a44ab4e5cf73ca765ae170f8619 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 1 Aug 2025 09:57:23 +0200 Subject: [PATCH 033/162] example nodes-with-2-parents --- data/examples/exampleA1NodesWith2Parents.cpp | 7 +++++++ data/examples/exampleA2NodesWith2Parents.cpp | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 data/examples/exampleA1NodesWith2Parents.cpp create mode 100644 data/examples/exampleA2NodesWith2Parents.cpp diff --git a/data/examples/exampleA1NodesWith2Parents.cpp b/data/examples/exampleA1NodesWith2Parents.cpp new file mode 100644 index 000000000..33d6a0596 --- /dev/null +++ b/data/examples/exampleA1NodesWith2Parents.cpp @@ -0,0 +1,7 @@ +#ifdef Feature1 + int x = 7; + x += 2; +#ifdef Feature2 + x += 3; +#endif +#endif diff --git a/data/examples/exampleA2NodesWith2Parents.cpp b/data/examples/exampleA2NodesWith2Parents.cpp new file mode 100644 index 000000000..bcffe7d31 --- /dev/null +++ b/data/examples/exampleA2NodesWith2Parents.cpp @@ -0,0 +1,7 @@ +#ifdef Feature1 + int x = 7; +#ifdef Feature2 + x += 2; + x += 3; +#endif +#endif From 86d4c22593f4b4a764dff4db0d5e8c1f6f506cee Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 1 Aug 2025 10:02:12 +0200 Subject: [PATCH 034/162] moved source code from PatchingExperiment to Patching class --- .../thesis_pm/PatchingExperiment.java | 484 +---------------- .../variation/diff/patching/Patching.java | 492 ++++++++++++++++++ 2 files changed, 498 insertions(+), 478 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 4ed4b8c5f..3205e43f5 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -30,479 +30,7 @@ public class PatchingExperiment { - private static Set calculateSetMinusOfFeatureSets(Set featureSet1, Set featureSet2, - boolean debug) { - Set intersectSet1 = new HashSet<>(featureSet1); - intersectSet1.removeAll(featureSet2); - Set intersectSet2 = new HashSet<>(featureSet2); - intersectSet2.removeAll(featureSet1); - intersectSet1.addAll(intersectSet2); - if (debug) { - System.out.println(featureSet1); - System.out.println(featureSet2); - System.out.println(intersectSet1); - } - return intersectSet1; - } - - private static Relevance calculateFormulaForDeselection(Set set, boolean debug) { - - Formula[] f = new Formula[set.size()]; - Iterator iterator = set.iterator(); - for (int i = 0; i < f.length; i++) { - f[i] = Formula.not(Formula.var(iterator.next())); - } - Formula formula = Formula.and(f); - - if (debug) - System.out.println(formula.get().toString()); - - return new Configure(formula); - } - - private static Set calculateFeatureSetToDeselectFromTrees(VariationTree variant1version1, - VariationTree variant1version2, VariationTree variant2, boolean debug) { - Set featuresTreeV1 = new HashSet(); - variant1version1.forAllPreorder(node -> { - featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); - }); - if (variant1version2 != null) { - variant1version2.forAllPreorder(node -> { - featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); - }); - } - Set featuresTreeV2 = new HashSet(); - variant2.forAllPreorder(node -> { - featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); - }); - - return calculateSetMinusOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); - } - - private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diff, - VariationTree variant2, boolean debug) { - Set featuresV1 = new HashSet(); - diff.forAll(node -> { - if (node.getDiffType().existsAtTime(Time.BEFORE)) { - featuresV1.addAll(node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures()); - } - if (node.getDiffType().existsAtTime(Time.AFTER)) { - featuresV1.addAll(node.getFeatureMapping(Time.AFTER).getUniqueContainedFeatures()); - } - }); - - Set featuresV2 = new HashSet(); - variant2.forAllPreorder(node -> { - featuresV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); - }); - - return calculateSetMinusOfFeatureSets(featuresV1, featuresV2, debug); - } - - private static boolean checkForZeroVariantDrift(VariationDiff diffVariant1, - VariationTree variant2, Relevance deselectedFeatures) { - diffVariant1 = DiffView.optimized(diffVariant1.project(Time.BEFORE).toCompletelyUnchangedVariationDiff(), - deselectedFeatures); - VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), - deselectedFeatures); - GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); - if (Patching.isSameAs(diffVariant1, diffVariant2)) { - return true; - } - return false; - } - - private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, - boolean debug) { - Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; - Set> subtreeRoots = new HashSet>(); - for (DiffNode node : nodes) { - if (!nodes.contains(node.getParent(time))) { - subtreeRoots.add(node); - } - } - if (debug) - System.out.println(subtreeRoots); - - return subtreeRoots; - } - - private static DiffNode getChildFromListIfIndexInRange(List> childrenList, - int index) { - if (index >= 0 && index < childrenList.size()) { - return childrenList.get(index); - } - return null; - } - - private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, - DiffNode node, Set deselectedFeatures, Time time, boolean debug) { - - List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); - if (!orderedChildrenTarget.contains(node)) { - // TODO: throw exception - return false; - } - int indexTarget = orderedChildrenTarget.indexOf(node); - DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, - indexTarget - 1); - DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, - indexTarget + 1); - - int indexSourceMatchingNeighborBefore = -2; - int indexSourceMatchingNeighborAfter = -2; - List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - - if (debug) { - System.out.println("Children Target: " + orderedChildrenTarget); - System.out.println("Children Source: " + orderedChildrenSource); - } - - if (neighborBeforeTarget != null) { - indexSourceMatchingNeighborBefore = findPositionOfMatchingNeighborInList(neighborBeforeTarget, - orderedChildrenSource, time); - } - if (neighborAfterTarget != null) { - indexSourceMatchingNeighborAfter = findPositionOfMatchingNeighborInList(neighborAfterTarget, - orderedChildrenSource, time); - } - if (indexSourceMatchingNeighborBefore == -2 && indexSourceMatchingNeighborAfter == -2) { - System.out.println("No neighbors before or after the target"); - return true; - } - if (indexSourceMatchingNeighborBefore > -1 && indexSourceMatchingNeighborAfter > -1) { - if (indexSourceMatchingNeighborAfter - indexSourceMatchingNeighborBefore > 2) { - // Alignment Problem ? - // Check if code belongs to features which are only present in target - // variant - List> orderedChildrenTargetSubList = orderedChildrenTarget - .subList(indexSourceMatchingNeighborBefore + 1, indexSourceMatchingNeighborAfter); - System.out.println(orderedChildrenTargetSubList); - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Node can be removed."); - } else { - return false; - } - } - } - return true; - } - - private static int findPositionOfMatchingNeighborInList(DiffNode neighbor, - List> list, Time time) { - ArrayList positions = new ArrayList(); - for (DiffNode node : list) { - if (Patching.isSameAs(neighbor, node)) { - positions.add(list.indexOf(node)); - } - } - if (positions.size() == 1) { - return positions.get(0); - } - if (positions.size() > 1) { - // TODO: throw exception? -// throw new Exception(); - return -1; - } - return -1; - } - - private static boolean isAlignmentProblem(List> subList, Set deselectedFeatures, - Time time) { - boolean isAlignmentProblem = false; - for (DiffNode node : subList) { - Set containedFeatures = node.getPresenceCondition(time).getUniqueContainedFeatures(); - System.out.println(containedFeatures); - isAlignmentProblem = containedFeatures.stream().anyMatch(feature -> deselectedFeatures.contains(feature)); - System.out.println("is alignment problem: " + isAlignmentProblem); - } - return isAlignmentProblem; - } - - private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, - Set deselectedFeatures, Time time, boolean debug) throws Exception { - if (debug) - System.out.println("Root node to insert: " + root.toString()); - List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); - if (debug) - System.out.println("Children of target node: " + orderedChildrenTarget.toString()); - List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - if (debug) - System.out.println("Children of source node: " + orderedChildrenSource.toString()); - int indexSource = orderedChildrenSource.indexOf(root); - DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, - indexSource - 1); - DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, - indexSource + 1); - int currentIndexAfter = indexSource + 1; - // ignore neighbors with DiffType ADD because they are added afterwards - while (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { - currentIndexAfter++; - neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, currentIndexAfter); - } - if (debug) { - if (neighborBeforeSource != null) { - System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); - } else { - System.out.print("No neighbor before; "); - } - if (neighborAfterSource != null) { - System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); - } else { - System.out.print("No neighbor after\n"); - } - } - int indexBefore = -2; - int indexAfter = -2; - - if (neighborBeforeSource != null) { - indexBefore = findPositionOfMatchingNeighborInList(neighborBeforeSource, orderedChildrenTarget, time); - } - if (neighborAfterSource != null) { - indexAfter = findPositionOfMatchingNeighborInList(neighborAfterSource, orderedChildrenTarget, time); - } - if (indexBefore == -2 && indexAfter == -2) { - if (orderedChildrenTarget.isEmpty()) { - System.out.println("No neighbors before or after the target"); - return 0; - } - if (isAlignmentProblem(orderedChildrenTarget, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " - + (orderedChildrenTarget.size() - 1)); - return -1; - } else { - throw new Exception("Reject"); - } - } - if (indexBefore == -2) { - List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(0, indexAfter); - if (!orderedChildrenTargetSubList.isEmpty()) { - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + indexAfter); - } else { - throw new Exception("Reject"); - } - return -1; - } - } - if (indexAfter == -2) { - List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, - orderedChildrenTarget.size()); - System.out.println(orderedChildrenTargetSubList); - if (!orderedChildrenTargetSubList.isEmpty()) { - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) - + " to " + (orderedChildrenTarget.size() - 1)); - } else { - throw new Exception("Reject"); - } - return -1; - } - } - if (indexBefore > -1 && indexAfter > -1) { - if (indexAfter - indexBefore > 1) { - // Alignment Problem ? - // TODO: Check if code belongs to features which are only present in target - // variant - List> orderedChildrenTargetSubList = orderedChildrenTarget - .subList(indexBefore + 1, indexAfter); - System.out.println(orderedChildrenTargetSubList); - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) - + " to " + indexAfter); - } else { - throw new Exception("Reject"); - } - return -1; - } - if (indexAfter - indexBefore < 0) { - // TODO: root must be between neighbors - System.out.println("Neighbors in wrong order"); - return -1; - } - return indexAfter; - } - return Math.max(indexBefore + 1, indexAfter); - } - - private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, - VariationDiff targetVariantDiffPatched, List> subtreeRoots, - VariationDiffSource source, Set deselectedFeatures, boolean debug) throws Exception { - - Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; - - for (DiffNode root : subtreeRoots) { - if (debug) { - DiffNode newRoot = DiffNode.createRoot(new DiffLinesLabel()); - newRoot.addChild(root.deepCopy(), time); - VariationDiff subTree = new VariationDiff(newRoot, source); - GameEngine.showAndAwaitAll(Show.diff(subTree)); - } - - List> targetNodes = new ArrayList>(); - if (root.isArtifact()) { - targetNodes = targetVariantDiffUnchanged.computeAllNodesThat( - node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) - && node.isAnnotation()); - } else if (root.isAnnotation()) { - targetNodes = targetVariantDiffUnchanged - .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); - } - - if (targetNodes.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { - DiffNode targetNodeInPatch = targetVariantDiffPatched - .getNodeWithID(targetNodes.get(0).getID()); - System.out.println(targetNodeInPatch.toString()); - if (type == DiffType.ADD) { - - int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, true); - if (insertPosition < 0) { - System.out.println("no matching insert position found"); - } else { - System.out.println("subtree added"); - targetNodeInPatch.insertChild(root.deepCopy(), insertPosition, time); - System.out.println(targetNodeInPatch.getChildOrder(time)); - } - - } else if (type == DiffType.REM) { - List> nodesToRem = new ArrayList>(); - System.out.println("Root: " + root.toString()); - System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); - targetNodeInPatch.getAllChildrenStream().forEach(node -> { - if (Patching.isSameAs(node, root) - && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true)) - nodesToRem.add(node); - }); - System.out.println("Nodes to remove: " + nodesToRem); - - if (nodesToRem.size() != 1) { - System.out.println("too much or too less target nodes found"); - System.out.println(nodesToRem.toString()); - } else { - System.out.println("subtree removed"); - removeNode(nodesToRem.get(0)); - System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); - } - } - GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); - } - } - } - - private static void removeNode(DiffNode node) { - Set> children = node.getAllChildrenSet(); - if (!children.isEmpty()) { - children.forEach(child -> removeNode(child)); - } - node.diffType = DiffType.REM; - node.drop(Time.AFTER); - } - - private static VariationTree patchVariationTrees( - VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, - VariationTree targetVariant) throws Exception { - if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { - System.out.println("Parsing error"); - return null; - } - VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - return patchVariationTrees(diff, targetVariant); - } - - private static VariationTree patchVariationTrees(VariationDiff diff, - VariationTree targetVariant) throws Exception { - -// Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, -// false); - Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, false); - Relevance rho = calculateFormulaForDeselection(deselectedFeatures, false); - - if (!checkForZeroVariantDrift(diff, targetVariant, rho)) { - throw new Exception("Variants evolved independently: No Zero Variant Drift"); - } - - VariationDiff optimizedDiff = DiffView.optimized(diff, rho); - VariationDiffSource source = optimizedDiff.getSource(); - VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); - VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); - - GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched), Show.diff(optimizedDiff)); - - Set> removedNodes = new HashSet>(); - Set> addedNodes = new HashSet>(); - - // find nodes with DiffType NON but changed parents - optimizedDiff.forAll(node -> { - if (node.isNon() && node.getParent(Time.BEFORE) != node.getParent(Time.AFTER)) { - removedNodes.add(node); - addedNodes.add(node); - } - }); - - // remove old nodes - optimizedDiff.forAll(node -> { - if (node.isRem()) { - removedNodes.add(node); - } - }); - Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); - List> removedSortedSubtreeRoots = removedSubtreeRoots.stream() - .sorted((n1, n2) -> Integer.compare(n1.getLinesAtTime(Time.BEFORE).fromInclusive(), - n2.getLinesAtTime(Time.BEFORE).fromInclusive())) - .collect(Collectors.toList()); - applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSortedSubtreeRoots, - source, deselectedFeatures, true); - - // add new nodes - optimizedDiff.forAll(node -> { - if (node.isAdd()) { - addedNodes.add(node); - } - }); - Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); - List> addedSortedSubtreeRoots = addedSubtreeRoots.stream().sorted((n1, n2) -> Integer - .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) - .collect(Collectors.toList()); - applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, - source, deselectedFeatures, true); - - GameEngine.showAndAwaitAll(Show.diff(diff)); - GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); -// GameEngine.showAndAwaitAll(Show.diff(diff), -// Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), -// Show.tree(targetVariantDiffPatched.project(Time.AFTER))); - return targetVariantDiffPatched.project(Time.AFTER); - } - - private static VariationDiff parseVariationDiffFromFiles(String file1, String file2) - throws IOException, DiffParseException { - Path examplesDir = Path.of("data", "examples"); - return VariationDiff.fromFiles(examplesDir.resolve(file1), examplesDir.resolve(file2), - DiffAlgorithm.SupportedAlgorithm.MYERS, VariationDiffParseOptions.Default); - } - - private static VariationTree parseVariationTreeFromFile(String file) { - Path examplesDir = Path.of("data", "examples"); - Path path = examplesDir.resolve(file); - try { - VariationTree tree = VariationTree.fromFile(path, VariationDiffParseOptions.Default); - return tree; - } catch (IOException e) { - e.printStackTrace(); - } catch (DiffParseException e) { - e.printStackTrace(); - } - return null; - } - - private static boolean comparePatchedVariantWithExpectedResult(VariationTree patchedVariant, - VariationTree expectedResult) { - return Patching.isSameAs(patchedVariant.toCompletelyUnchangedVariationDiff(), - expectedResult.toCompletelyUnchangedVariationDiff()); - } + public static void main(String[] args) { try { @@ -519,12 +47,12 @@ public static void main(String[] args) { // VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); // System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); - VariationTree patchedVariant = patchVariationTrees( - parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", "exampleA2NodesWith2Parents.cpp"), - parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp")); - VariationTree expectedResult = parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); + VariationTree patchedVariant = Patching.patchVariationTrees( + Patching.parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", "exampleA2NodesWith2Parents.cpp"), + Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp")); + VariationTree expectedResult = Patching.parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); GameEngine.showAndAwaitAll(Show.tree(patchedVariant), Show.tree(expectedResult)); - System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); + System.out.println(Patching.comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); // VariationTree patchedVariant = patchVariationTrees( // parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 4bfc2dbd5..bc0131037 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -1,13 +1,31 @@ package org.variantsync.diffdetective.variation.diff.patching; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import org.eclipse.jgit.diff.DiffAlgorithm; +import org.variantsync.diffdetective.diff.result.DiffParseException; +import org.variantsync.diffdetective.show.Show; +import org.variantsync.diffdetective.show.engine.GameEngine; +import org.variantsync.diffdetective.util.fide.FixTrueFalse.Formula; +import org.variantsync.diffdetective.variation.DiffLinesLabel; import org.variantsync.diffdetective.variation.Label; import org.variantsync.diffdetective.variation.diff.DiffNode; +import org.variantsync.diffdetective.variation.diff.DiffType; import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; +import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; +import org.variantsync.diffdetective.variation.diff.source.VariationDiffSource; +import org.variantsync.diffdetective.variation.diff.view.DiffView; +import org.variantsync.diffdetective.variation.tree.VariationTree; +import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; +import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; public class Patching { @@ -44,4 +62,478 @@ private static boolean isSameAs(DiffNode a, DiffNode b, return aIt.hasNext() == bIt.hasNext(); } + + private static Set calculateSetMinusOfFeatureSets(Set featureSet1, Set featureSet2, + boolean debug) { + Set intersectSet1 = new HashSet<>(featureSet1); + intersectSet1.removeAll(featureSet2); + Set intersectSet2 = new HashSet<>(featureSet2); + intersectSet2.removeAll(featureSet1); + intersectSet1.addAll(intersectSet2); + if (debug) { + System.out.println(featureSet1); + System.out.println(featureSet2); + System.out.println(intersectSet1); + } + return intersectSet1; + } + + private static Relevance calculateFormulaForDeselection(Set set, boolean debug) { + + Formula[] f = new Formula[set.size()]; + Iterator iterator = set.iterator(); + for (int i = 0; i < f.length; i++) { + f[i] = Formula.not(Formula.var(iterator.next())); + } + Formula formula = Formula.and(f); + + if (debug) + System.out.println(formula.get().toString()); + + return new Configure(formula); + } + + private static Set calculateFeatureSetToDeselectFromTrees(VariationTree variant1version1, + VariationTree variant1version2, VariationTree variant2, boolean debug) { + Set featuresTreeV1 = new HashSet(); + variant1version1.forAllPreorder(node -> { + featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + if (variant1version2 != null) { + variant1version2.forAllPreorder(node -> { + featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + } + Set featuresTreeV2 = new HashSet(); + variant2.forAllPreorder(node -> { + featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + + return calculateSetMinusOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); + } + + private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diff, + VariationTree variant2, boolean debug) { + Set featuresV1 = new HashSet(); + diff.forAll(node -> { + if (node.getDiffType().existsAtTime(Time.BEFORE)) { + featuresV1.addAll(node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures()); + } + if (node.getDiffType().existsAtTime(Time.AFTER)) { + featuresV1.addAll(node.getFeatureMapping(Time.AFTER).getUniqueContainedFeatures()); + } + }); + + Set featuresV2 = new HashSet(); + variant2.forAllPreorder(node -> { + featuresV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + }); + + return calculateSetMinusOfFeatureSets(featuresV1, featuresV2, debug); + } + + private static boolean checkForZeroVariantDrift(VariationDiff diffVariant1, + VariationTree variant2, Relevance deselectedFeatures) { + diffVariant1 = DiffView.optimized(diffVariant1.project(Time.BEFORE).toCompletelyUnchangedVariationDiff(), + deselectedFeatures); + VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), + deselectedFeatures); + GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); + if (Patching.isSameAs(diffVariant1, diffVariant2)) { + return true; + } + return false; + } + + private static Set> findRootsOfSubtrees(Set> nodes, DiffType type, + boolean debug) { + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; + Set> subtreeRoots = new HashSet>(); + for (DiffNode node : nodes) { + if (!nodes.contains(node.getParent(time))) { + subtreeRoots.add(node); + } + } + if (debug) + System.out.println(subtreeRoots); + + return subtreeRoots; + } + + private static DiffNode getChildFromListIfIndexInRange(List> childrenList, + int index) { + if (index >= 0 && index < childrenList.size()) { + return childrenList.get(index); + } + return null; + } + + private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, + DiffNode node, Set deselectedFeatures, Time time, boolean debug) { + + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + if (!orderedChildrenTarget.contains(node)) { + // TODO: throw exception + return false; + } + int indexTarget = orderedChildrenTarget.indexOf(node); + DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, + indexTarget - 1); + DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, + indexTarget + 1); + + int indexSourceMatchingNeighborBefore = -2; + int indexSourceMatchingNeighborAfter = -2; + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + + if (debug) { + System.out.println("Children Target: " + orderedChildrenTarget); + System.out.println("Children Source: " + orderedChildrenSource); + } + + if (neighborBeforeTarget != null) { + indexSourceMatchingNeighborBefore = findPositionOfMatchingNeighborInList(neighborBeforeTarget, + orderedChildrenSource, time); + } + if (neighborAfterTarget != null) { + indexSourceMatchingNeighborAfter = findPositionOfMatchingNeighborInList(neighborAfterTarget, + orderedChildrenSource, time); + } + if (indexSourceMatchingNeighborBefore == -2 && indexSourceMatchingNeighborAfter == -2) { + System.out.println("No neighbors before or after the target"); + return true; + } + if (indexSourceMatchingNeighborBefore > -1 && indexSourceMatchingNeighborAfter > -1) { + if (indexSourceMatchingNeighborAfter - indexSourceMatchingNeighborBefore > 2) { + // Alignment Problem ? + // Check if code belongs to features which are only present in target + // variant + List> orderedChildrenTargetSubList = orderedChildrenTarget + .subList(indexSourceMatchingNeighborBefore + 1, indexSourceMatchingNeighborAfter); + System.out.println(orderedChildrenTargetSubList); + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Node can be removed."); + } else { + return false; + } + } + } + return true; + } + + private static int findPositionOfMatchingNeighborInList(DiffNode neighbor, + List> list, Time time) { + ArrayList positions = new ArrayList(); + for (DiffNode node : list) { + if (Patching.isSameAs(neighbor, node)) { + positions.add(list.indexOf(node)); + } + } + if (positions.size() == 1) { + return positions.get(0); + } + if (positions.size() > 1) { + // TODO: throw exception? +// throw new Exception(); + return -1; + } + return -1; + } + + private static boolean isAlignmentProblem(List> subList, Set deselectedFeatures, + Time time) { + boolean isAlignmentProblem = false; + for (DiffNode node : subList) { + Set containedFeatures = node.getPresenceCondition(time).getUniqueContainedFeatures(); + System.out.println(containedFeatures); + isAlignmentProblem = containedFeatures.stream().anyMatch(feature -> deselectedFeatures.contains(feature)); + System.out.println("is alignment problem: " + isAlignmentProblem); + } + return isAlignmentProblem; + } + + private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, + Set deselectedFeatures, Time time, boolean debug) throws Exception { + if (debug) + System.out.println("Root node to insert: " + root.toString()); + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + if (debug) + System.out.println("Children of target node: " + orderedChildrenTarget.toString()); + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + if (debug) + System.out.println("Children of source node: " + orderedChildrenSource.toString()); + int indexSource = orderedChildrenSource.indexOf(root); + DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource - 1); + DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, + indexSource + 1); + int currentIndexAfter = indexSource + 1; + // ignore neighbors with DiffType ADD because they are added afterwards + while (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { + currentIndexAfter++; + neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, currentIndexAfter); + } + if (debug) { + if (neighborBeforeSource != null) { + System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); + } else { + System.out.print("No neighbor before; "); + } + if (neighborAfterSource != null) { + System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); + } else { + System.out.print("No neighbor after\n"); + } + } + int indexBefore = -2; + int indexAfter = -2; + + if (neighborBeforeSource != null) { + indexBefore = findPositionOfMatchingNeighborInList(neighborBeforeSource, orderedChildrenTarget, time); + } + if (neighborAfterSource != null) { + indexAfter = findPositionOfMatchingNeighborInList(neighborAfterSource, orderedChildrenTarget, time); + } + if (indexBefore == -2 && indexAfter == -2) { + if (orderedChildrenTarget.isEmpty()) { + System.out.println("No neighbors before or after the target"); + return 0; + } + if (isAlignmentProblem(orderedChildrenTarget, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + + (orderedChildrenTarget.size() - 1)); + return -1; + } else { + throw new Exception("Reject"); + } + } + if (indexBefore == -2) { + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(0, indexAfter); + if (!orderedChildrenTargetSubList.isEmpty()) { + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + indexAfter); + } else { + throw new Exception("Reject"); + } + return -1; + } + } + if (indexAfter == -2) { + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, + orderedChildrenTarget.size()); + System.out.println(orderedChildrenTargetSubList); + if (!orderedChildrenTargetSubList.isEmpty()) { + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + + " to " + (orderedChildrenTarget.size() - 1)); + } else { + throw new Exception("Reject"); + } + return -1; + } + } + if (indexBefore > -1 && indexAfter > -1) { + if (indexAfter - indexBefore > 1) { + // Alignment Problem ? + // TODO: Check if code belongs to features which are only present in target + // variant + List> orderedChildrenTargetSubList = orderedChildrenTarget + .subList(indexBefore + 1, indexAfter); + System.out.println(orderedChildrenTargetSubList); + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + + " to " + indexAfter); + } else { + throw new Exception("Reject"); + } + return -1; + } + if (indexAfter - indexBefore < 0) { + // TODO: root must be between neighbors + System.out.println("Neighbors in wrong order"); + return -1; + } + return indexAfter; + } + return Math.max(indexBefore + 1, indexAfter); + } + + private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, + VariationDiff targetVariantDiffPatched, List> subtreeRoots, + VariationDiffSource source, Set deselectedFeatures, boolean debug) throws Exception { + + Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; + + for (DiffNode root : subtreeRoots) { + if (debug) { + DiffNode newRoot = DiffNode.createRoot(new DiffLinesLabel()); + newRoot.addChild(root.deepCopy(), time); + VariationDiff subTree = new VariationDiff(newRoot, source); + GameEngine.showAndAwaitAll(Show.diff(subTree)); + } + + List> targetNodes = new ArrayList>(); + if (root.isArtifact()) { + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat( + node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) + && node.isAnnotation()); + } else if (root.isAnnotation()) { + targetNodes = targetVariantDiffUnchanged + .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); + } + + if (targetNodes.size() != 1) { + System.out.println("too much or too less target nodes found"); + } else { + DiffNode targetNodeInPatch = targetVariantDiffPatched + .getNodeWithID(targetNodes.get(0).getID()); + System.out.println(targetNodeInPatch.toString()); + if (type == DiffType.ADD) { + + int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, true); + if (insertPosition < 0) { + System.out.println("no matching insert position found"); + } else { + System.out.println("subtree added"); + targetNodeInPatch.insertChild(root.deepCopy(), insertPosition, time); + System.out.println(targetNodeInPatch.getChildOrder(time)); + } + + } else if (type == DiffType.REM) { + List> nodesToRem = new ArrayList>(); + System.out.println("Root: " + root.toString()); + System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); + targetNodeInPatch.getAllChildrenStream().forEach(node -> { + if (Patching.isSameAs(node, root) + && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true)) + nodesToRem.add(node); + }); + System.out.println("Nodes to remove: " + nodesToRem); + + if (nodesToRem.size() != 1) { + System.out.println("too much or too less target nodes found"); + System.out.println(nodesToRem.toString()); + } else { + System.out.println("subtree removed"); + removeNode(nodesToRem.get(0)); + System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); + } + } + GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); + } + } + } + + private static void removeNode(DiffNode node) { + Set> children = node.getAllChildrenSet(); + if (!children.isEmpty()) { + children.forEach(child -> removeNode(child)); + } + node.diffType = DiffType.REM; + node.drop(Time.AFTER); + } + + private static VariationTree patchVariationTrees( + VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, + VariationTree targetVariant) throws Exception { + if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { + System.out.println("Parsing error"); + return null; + } + VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); + return patchVariationTrees(diff, targetVariant); + } + + public static VariationTree patchVariationTrees(VariationDiff diff, + VariationTree targetVariant) throws Exception { + +// Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, +// false); + Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, false); + Relevance rho = calculateFormulaForDeselection(deselectedFeatures, false); + + if (!checkForZeroVariantDrift(diff, targetVariant, rho)) { + throw new Exception("Variants evolved independently: No Zero Variant Drift"); + } + + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + VariationDiffSource source = optimizedDiff.getSource(); + VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); + + GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched), Show.diff(optimizedDiff)); + + Set> removedNodes = new HashSet>(); + Set> addedNodes = new HashSet>(); + + // find nodes with DiffType NON but changed parents + optimizedDiff.forAll(node -> { + if (node.isNon() && node.getParent(Time.BEFORE) != node.getParent(Time.AFTER)) { + removedNodes.add(node); + addedNodes.add(node); + } + }); + + // remove old nodes + optimizedDiff.forAll(node -> { + if (node.isRem()) { + removedNodes.add(node); + } + }); + Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); + List> removedSortedSubtreeRoots = removedSubtreeRoots.stream() + .sorted((n1, n2) -> Integer.compare(n1.getLinesAtTime(Time.BEFORE).fromInclusive(), + n2.getLinesAtTime(Time.BEFORE).fromInclusive())) + .collect(Collectors.toList()); + applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSortedSubtreeRoots, + source, deselectedFeatures, true); + + // add new nodes + optimizedDiff.forAll(node -> { + if (node.isAdd()) { + addedNodes.add(node); + } + }); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); + List> addedSortedSubtreeRoots = addedSubtreeRoots.stream().sorted((n1, n2) -> Integer + .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) + .collect(Collectors.toList()); + applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, + source, deselectedFeatures, true); + + GameEngine.showAndAwaitAll(Show.diff(diff)); + GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); +// GameEngine.showAndAwaitAll(Show.diff(diff), +// Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), +// Show.tree(targetVariantDiffPatched.project(Time.AFTER))); + return targetVariantDiffPatched.project(Time.AFTER); + } + + public static VariationDiff parseVariationDiffFromFiles(String file1, String file2) + throws IOException, DiffParseException { + Path examplesDir = Path.of("data", "examples"); + return VariationDiff.fromFiles(examplesDir.resolve(file1), examplesDir.resolve(file2), + DiffAlgorithm.SupportedAlgorithm.MYERS, VariationDiffParseOptions.Default); + } + + public static VariationTree parseVariationTreeFromFile(String file) { + Path examplesDir = Path.of("data", "examples"); + Path path = examplesDir.resolve(file); + try { + VariationTree tree = VariationTree.fromFile(path, VariationDiffParseOptions.Default); + return tree; + } catch (IOException e) { + e.printStackTrace(); + } catch (DiffParseException e) { + e.printStackTrace(); + } + return null; + } + + public static boolean comparePatchedVariantWithExpectedResult(VariationTree patchedVariant, + VariationTree expectedResult) { + return Patching.isSameAs(patchedVariant.toCompletelyUnchangedVariationDiff(), + expectedResult.toCompletelyUnchangedVariationDiff()); + } } From 33efa25faae15734f5075bfe174e2f0a1afb55b0 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 1 Aug 2025 10:04:22 +0200 Subject: [PATCH 035/162] removed unused imports --- .../thesis_pm/PatchingExperiment.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 3205e43f5..557980511 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -1,32 +1,10 @@ package org.variantsync.diffdetective.experiments.thesis_pm; -import java.io.IOException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -import org.eclipse.jgit.diff.DiffAlgorithm; -import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm; -import org.variantsync.diffdetective.diff.result.DiffParseException; import org.variantsync.diffdetective.show.Show; import org.variantsync.diffdetective.show.engine.GameEngine; -import org.variantsync.diffdetective.util.fide.FixTrueFalse.Formula; import org.variantsync.diffdetective.variation.DiffLinesLabel; -import org.variantsync.diffdetective.variation.diff.DiffNode; -import org.variantsync.diffdetective.variation.diff.DiffType; -import org.variantsync.diffdetective.variation.diff.Time; -import org.variantsync.diffdetective.variation.diff.VariationDiff; -import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; import org.variantsync.diffdetective.variation.diff.patching.Patching; -import org.variantsync.diffdetective.variation.diff.source.VariationDiffSource; -import org.variantsync.diffdetective.variation.diff.view.DiffView; import org.variantsync.diffdetective.variation.tree.VariationTree; -import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; -import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; public class PatchingExperiment { From 3d3fd1cc6a2ab57c0f65d8373b795f61cbb69948 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 1 Aug 2025 12:40:40 +0200 Subject: [PATCH 036/162] prepared patching analysis --- .../thesis_pm/PatchingExperiment.java | 117 ++++++++- .../variation/diff/patching/Patching.java | 240 +++++++++++------- 2 files changed, 246 insertions(+), 111 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 557980511..dcbefec93 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -1,17 +1,108 @@ package org.variantsync.diffdetective.experiments.thesis_pm; -import org.variantsync.diffdetective.show.Show; -import org.variantsync.diffdetective.show.engine.GameEngine; +import java.io.IOException; +import java.nio.file.Path; + +import org.variantsync.diffdetective.AnalysisRunner; +import org.variantsync.diffdetective.analysis.Analysis; import org.variantsync.diffdetective.variation.DiffLinesLabel; import org.variantsync.diffdetective.variation.diff.patching.Patching; import org.variantsync.diffdetective.variation.tree.VariationTree; +import java.util.List; +import org.tinylog.Logger; +import org.variantsync.diffdetective.analysis.*; +import org.variantsync.diffdetective.datasets.Repository; +import org.variantsync.diffdetective.variation.diff.Time; +import org.variantsync.diffdetective.variation.diff.VariationDiff; + +public class PatchingExperiment implements Analysis.Hooks { -public class PatchingExperiment { + private static final AnalysisResult.ResultKey REJECTED_PATCHES_COUNTER_RESULT_KEY = new AnalysisResult.ResultKey<>( + "rejected patches"); + private static final AnalysisResult.ResultKey INCORRECTLY_APPLIED_PATCHES_COUNTER_RESULT_KEY = new AnalysisResult.ResultKey<>( + "incorrectly applied patches"); + private static final AnalysisResult.ResultKey SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY = new AnalysisResult.ResultKey<>( + "successfully applied patches"); + private int commits = 0; + + private static class RejectedPatchesCounter extends SimpleMetadata { + public RejectedPatchesCounter() { + super(0, "rejected patches", Integer::sum); + } + } + private static class IncorrectlyAppliedPatchesCounter + extends SimpleMetadata { + public IncorrectlyAppliedPatchesCounter() { + super(0, "incorrectly applied patches", Integer::sum); + } + } + private static class SuccessfullyAppliedPatchesCounter + extends SimpleMetadata { +public SuccessfullyAppliedPatchesCounter() { + super(0, "successfully applied patches", Integer::sum); +} +} + + @Override + public void initializeResults(Analysis analysis) { + analysis.append(REJECTED_PATCHES_COUNTER_RESULT_KEY, new RejectedPatchesCounter()); + analysis.append(INCORRECTLY_APPLIED_PATCHES_COUNTER_RESULT_KEY, new IncorrectlyAppliedPatchesCounter()); + analysis.append(SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY, new SuccessfullyAppliedPatchesCounter()); + } + + @Override + public boolean beginCommit(Analysis analysis) throws Exception { + ++commits; + return true; + } + + @Override + public boolean analyzeVariationDiff(Analysis analysis) throws Exception { + VariationDiff diff = analysis.getCurrentVariationDiff(); + VariationTree before = diff.project(Time.BEFORE).deepCopy(); + VariationTree after = diff.project(Time.AFTER).deepCopy(); + + try { + VariationTree patchedVariant = Patching.patchVariationTrees(diff, before, false); + + if (!Patching.comparePatchedVariantWithExpectedResult(patchedVariant, after)) { + analysis.get(INCORRECTLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; + } else { + analysis.get(SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; + } + } catch (Exception e) { + e.printStackTrace(); + analysis.get(REJECTED_PATCHES_COUNTER_RESULT_KEY).value++; + } + return true; + } + + @Override + public void endBatch(Analysis analysis) throws Exception { + Logger.info("Batch done: {} commits analyzed", commits); + } + + public static Analysis Create(Repository repo, Path outputDirectory) { + return new Analysis("my analysis", List.of(new PatchingExperiment() +// , new StatisticsAnalysis() +// , new EditClassValidation() + ), repo, outputDirectory); + } public static void main(String[] args) { try { + AnalysisRunner.run( + new AnalysisRunner.Options(Path.of("data", "repos"), Path.of("data", "output"), + Path.of("data", "demo-dataset.md")), + (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path), 20, + 8)); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } +// try { // patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), // parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); // patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), @@ -25,12 +116,12 @@ public static void main(String[] args) { // VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); // System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); - VariationTree patchedVariant = Patching.patchVariationTrees( - Patching.parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", "exampleA2NodesWith2Parents.cpp"), - Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp")); - VariationTree expectedResult = Patching.parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); - GameEngine.showAndAwaitAll(Show.tree(patchedVariant), Show.tree(expectedResult)); - System.out.println(Patching.comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); +// VariationTree patchedVariant = Patching.patchVariationTrees( +// Patching.parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", "exampleA2NodesWith2Parents.cpp"), +// Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp")); +// VariationTree expectedResult = Patching.parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); +// GameEngine.showAndAwaitAll(Show.tree(patchedVariant), Show.tree(expectedResult)); +// System.out.println(Patching.comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); // VariationTree patchedVariant = patchVariationTrees( // parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), @@ -44,10 +135,10 @@ public static void main(String[] args) { // parseVariationTreeFromFile("exampleBRemAlignmentP.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAddAlignmentP.cpp", "exampleA2RemAddAlignmentP.cpp"), // parseVariationTreeFromFile("exampleBRemAddAlignmentP.cpp")); - } catch (Exception e) { - System.out.println("Rejected"); - e.printStackTrace(); - } +// } catch (Exception e) { +// System.out.println("Rejected"); +// e.printStackTrace(); +// } } } diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index bc0131037..8fe210c0f 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -28,42 +28,70 @@ import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; public class Patching { + + public static boolean isSameAs(VariationDiff diff1, VariationDiff diff2) { + return isSameAsWithoutLabel(diff1.getRoot(), diff2.getRoot()); + } + + public static boolean isSameAs(DiffNode a, DiffNode b) { + return isSameAs(a, b, new HashSet<>()); + } + + public static boolean isSameAsWithoutLabel(DiffNode a, DiffNode b) { + return isSameAsWithoutLabel(a, b, new HashSet<>()); + } - public static boolean isSameAs(VariationDiff diff1, VariationDiff diff2) { - return isSameAs(diff1.getRoot(), diff2.getRoot()); + private static boolean isSameAs(DiffNode a, DiffNode b, Set> visited) { + if (!visited.add(a)) { + return true; + } + + if (!(a.getNodeType().equals(b.getNodeType()) && + a.getLabel().equals(b.getLabel()) && +// a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && +// a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && + (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) + && a.getLabel().getLines().equals(b.getLabel().getLines()))) { + return false; + } + + Iterator> aIt = a.getAllChildren().iterator(); + Iterator> bIt = b.getAllChildren().iterator(); + while (aIt.hasNext() && bIt.hasNext()) { + if (!isSameAs(aIt.next(), bIt.next(), visited)) { + return false; + } + } + + return aIt.hasNext() == bIt.hasNext(); } - public static boolean isSameAs(DiffNode a, DiffNode b) { - return isSameAs(a, b, new HashSet<>()); - } - - private static boolean isSameAs(DiffNode a, DiffNode b, Set> visited) { - if (!visited.add(a)) { - return true; - } - - if (!( - a.getNodeType().equals(b.getNodeType()) && + private static boolean isSameAsWithoutLabel(DiffNode a, DiffNode b, Set> visited) { + if (!visited.add(a)) { + return true; + } + + if (!(a.getNodeType().equals(b.getNodeType()) && +// a.getLabel().equals(b.getLabel()) && // a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && // a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && - (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) && - a.getLabel().getLines().equals(b.getLabel().getLines()) - )) { - return false; - } - - Iterator> aIt = a.getAllChildren().iterator(); - Iterator> bIt = b.getAllChildren().iterator(); - while (aIt.hasNext() && bIt.hasNext()) { - if (!isSameAs(aIt.next(), bIt.next(), visited)) { - return false; - } - } - - return aIt.hasNext() == bIt.hasNext(); - } - - private static Set calculateSetMinusOfFeatureSets(Set featureSet1, Set featureSet2, + (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) + && a.getLabel().getLines().equals(b.getLabel().getLines()))) { + return false; + } + + Iterator> aIt = a.getAllChildren().iterator(); + Iterator> bIt = b.getAllChildren().iterator(); + while (aIt.hasNext() && bIt.hasNext()) { + if (!isSameAs(aIt.next(), bIt.next(), visited)) { + return false; + } + } + + return aIt.hasNext() == bIt.hasNext(); + } + + private static Set calculateSetMinusOfFeatureSets(Set featureSet1, Set featureSet2, boolean debug) { Set intersectSet1 = new HashSet<>(featureSet1); intersectSet1.removeAll(featureSet2); @@ -133,12 +161,12 @@ private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diffVariant1, - VariationTree variant2, Relevance deselectedFeatures) { + VariationTree variant2, Relevance deselectedFeatures, boolean debug) { diffVariant1 = DiffView.optimized(diffVariant1.project(Time.BEFORE).toCompletelyUnchangedVariationDiff(), deselectedFeatures); VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), deselectedFeatures); - GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); + if (debug) GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); if (Patching.isSameAs(diffVariant1, diffVariant2)) { return true; } @@ -169,7 +197,7 @@ private static DiffNode getChildFromListIfIndexInRange(List root, DiffNode targetNodeInPatch, - DiffNode node, Set deselectedFeatures, Time time, boolean debug) { + DiffNode node, Set deselectedFeatures, Time time, boolean debug) throws Exception { List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); if (!orderedChildrenTarget.contains(node)) { @@ -200,7 +228,7 @@ private static boolean checkNeighbors(DiffNode root, DiffNode -1 && indexSourceMatchingNeighborAfter > -1) { @@ -210,9 +238,9 @@ private static boolean checkNeighbors(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget .subList(indexSourceMatchingNeighborBefore + 1, indexSourceMatchingNeighborAfter); - System.out.println(orderedChildrenTargetSubList); - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Node can be removed."); + if (debug) System.out.println(orderedChildrenTargetSubList); + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { + if (debug) System.out.println("ALIGNMENT PROBLEM. Node can be removed."); } else { return false; } @@ -222,7 +250,7 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighbor, - List> list, Time time) { + List> list, Time time) throws Exception { ArrayList positions = new ArrayList(); for (DiffNode node : list) { if (Patching.isSameAs(neighbor, node)) { @@ -234,20 +262,19 @@ private static int findPositionOfMatchingNeighborInList(DiffNode } if (positions.size() > 1) { // TODO: throw exception? -// throw new Exception(); - return -1; + throw new Exception("multiple insert positions found: " + positions.size()); } return -1; } private static boolean isAlignmentProblem(List> subList, Set deselectedFeatures, - Time time) { + Time time, boolean debug) { boolean isAlignmentProblem = false; for (DiffNode node : subList) { Set containedFeatures = node.getPresenceCondition(time).getUniqueContainedFeatures(); - System.out.println(containedFeatures); + if (debug) System.out.println(containedFeatures); isAlignmentProblem = containedFeatures.stream().anyMatch(feature -> deselectedFeatures.contains(feature)); - System.out.println("is alignment problem: " + isAlignmentProblem); + if (debug) System.out.println("is alignment problem: " + isAlignmentProblem); } return isAlignmentProblem; } @@ -273,6 +300,7 @@ private static int findInsertPosition(DiffNode root, DiffNode root, DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(0, indexAfter); - if (!orderedChildrenTargetSubList.isEmpty()) { - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + indexAfter); + if (orderedChildrenTargetSubList.size() > 1) { + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { + if (debug) System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + indexAfter); } else { throw new Exception("Reject"); } @@ -321,10 +349,10 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, orderedChildrenTarget.size()); - System.out.println(orderedChildrenTargetSubList); - if (!orderedChildrenTargetSubList.isEmpty()) { - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + if (debug) System.out.println(orderedChildrenTargetSubList); + if (orderedChildrenTargetSubList.size() > 1) { + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { + if (debug) System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + " to " + (orderedChildrenTarget.size() - 1)); } else { throw new Exception("Reject"); @@ -333,15 +361,15 @@ private static int findInsertPosition(DiffNode root, DiffNode -1 && indexAfter > -1) { - if (indexAfter - indexBefore > 1) { + if (indexAfter - (indexBefore + 1) > 1) { // Alignment Problem ? // TODO: Check if code belongs to features which are only present in target // variant List> orderedChildrenTargetSubList = orderedChildrenTarget .subList(indexBefore + 1, indexAfter); - System.out.println(orderedChildrenTargetSubList); - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time)) { - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + if (debug) System.out.println(orderedChildrenTargetSubList); + if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { + if (debug) System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + " to " + indexAfter); } else { throw new Exception("Reject"); @@ -350,7 +378,7 @@ private static int findInsertPosition(DiffNode root, DiffNode ta DiffNode newRoot = DiffNode.createRoot(new DiffLinesLabel()); newRoot.addChild(root.deepCopy(), time); VariationDiff subTree = new VariationDiff(newRoot, source); - GameEngine.showAndAwaitAll(Show.diff(subTree)); + if (debug) GameEngine.showAndAwaitAll(Show.diff(subTree)); } List> targetNodes = new ArrayList>(); @@ -382,46 +410,62 @@ private static void applyChanges(DiffType type, VariationDiff ta .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } - - if (targetNodes.size() != 1) { - System.out.println("too much or too less target nodes found"); - } else { + + List> targetNodes2 = new ArrayList>(); + for (DiffNode targetNode : targetNodes) { DiffNode targetNodeInPatch = targetVariantDiffPatched - .getNodeWithID(targetNodes.get(0).getID()); - System.out.println(targetNodeInPatch.toString()); + .getNodeWithID(targetNode.getID()); + if (debug) System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { - int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, true); + int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug); if (insertPosition < 0) { - System.out.println("no matching insert position found"); + if (debug) System.out.println("no matching insert position found"); } else { - System.out.println("subtree added"); - targetNodeInPatch.insertChild(root.deepCopy(), insertPosition, time); - System.out.println(targetNodeInPatch.getChildOrder(time)); + targetNodes2.add(targetNode); } } else if (type == DiffType.REM) { List> nodesToRem = new ArrayList>(); - System.out.println("Root: " + root.toString()); - System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); + if (debug) System.out.println("Root: " + root.toString()); + if (debug) System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); targetNodeInPatch.getAllChildrenStream().forEach(node -> { - if (Patching.isSameAs(node, root) - && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, true)) - nodesToRem.add(node); + try { + if (Patching.isSameAs(node, root) + && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, debug)) + nodesToRem.add(node); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } }); - System.out.println("Nodes to remove: " + nodesToRem); + if (debug) System.out.println("Nodes to remove: " + nodesToRem); if (nodesToRem.size() != 1) { - System.out.println("too much or too less target nodes found"); - System.out.println(nodesToRem.toString()); + if (debug) System.out.println("too much or too less target nodes found"); + if (debug) System.out.println(nodesToRem.toString()); } else { - System.out.println("subtree removed"); - removeNode(nodesToRem.get(0)); - System.out.println(targetNodes.get(0).getChildOrder(Time.AFTER)); + targetNodes2.add(nodesToRem.get(0)); } } - GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); + if (debug) GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); + } + + if (targetNodes2.size() != 1) { + throw new Exception("too much or too less targetNodes found: " + targetNodes2.size()); + } else { + DiffNode targetNodeInPatch = targetNodes2.get(0); + if (type == DiffType.ADD) { + if (debug) System.out.println("subtree added"); + targetNodeInPatch.insertChild(root.deepCopy(), findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug), time); + if (debug) System.out.println(targetNodeInPatch.getChildOrder(time)); + } else if (type == DiffType.REM) { + if (debug) System.out.println("subtree removed"); + removeNode(targetNodeInPatch); + if (debug) System.out.println(targetNodes2.get(0).getChildOrder(Time.AFTER)); + } } + } } @@ -436,24 +480,24 @@ private static void removeNode(DiffNode node) { private static VariationTree patchVariationTrees( VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, - VariationTree targetVariant) throws Exception { + VariationTree targetVariant, boolean debug) throws Exception { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { - System.out.println("Parsing error"); + if (debug) System.out.println("Parsing error"); return null; } VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - return patchVariationTrees(diff, targetVariant); + return patchVariationTrees(diff, targetVariant, debug); } public static VariationTree patchVariationTrees(VariationDiff diff, - VariationTree targetVariant) throws Exception { + VariationTree targetVariant, boolean debug) throws Exception { // Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, // false); - Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, false); - Relevance rho = calculateFormulaForDeselection(deselectedFeatures, false); + Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, debug); + Relevance rho = calculateFormulaForDeselection(deselectedFeatures, debug); - if (!checkForZeroVariantDrift(diff, targetVariant, rho)) { + if (!checkForZeroVariantDrift(diff, targetVariant, rho, debug)) { throw new Exception("Variants evolved independently: No Zero Variant Drift"); } @@ -462,11 +506,11 @@ public static VariationTree patchVariationTrees(VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); - GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched), Show.diff(optimizedDiff)); + if (debug) GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched), Show.diff(optimizedDiff)); Set> removedNodes = new HashSet>(); Set> addedNodes = new HashSet>(); - + // find nodes with DiffType NON but changed parents optimizedDiff.forAll(node -> { if (node.isNon() && node.getParent(Time.BEFORE) != node.getParent(Time.AFTER)) { @@ -481,13 +525,13 @@ public static VariationTree patchVariationTrees(VariationDiff> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, false); + Set> removedSubtreeRoots = findRootsOfSubtrees(removedNodes, DiffType.REM, debug); List> removedSortedSubtreeRoots = removedSubtreeRoots.stream() .sorted((n1, n2) -> Integer.compare(n1.getLinesAtTime(Time.BEFORE).fromInclusive(), n2.getLinesAtTime(Time.BEFORE).fromInclusive())) .collect(Collectors.toList()); applyChanges(DiffType.REM, targetVariantDiffUnchanged, targetVariantDiffPatched, removedSortedSubtreeRoots, - source, deselectedFeatures, true); + source, deselectedFeatures, debug); // add new nodes optimizedDiff.forAll(node -> { @@ -495,15 +539,15 @@ public static VariationTree patchVariationTrees(VariationDiff> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, false); + Set> addedSubtreeRoots = findRootsOfSubtrees(addedNodes, DiffType.ADD, debug); List> addedSortedSubtreeRoots = addedSubtreeRoots.stream().sorted((n1, n2) -> Integer .compare(n1.getLinesAtTime(Time.AFTER).fromInclusive(), n2.getLinesAtTime(Time.AFTER).fromInclusive())) .collect(Collectors.toList()); applyChanges(DiffType.ADD, targetVariantDiffUnchanged, targetVariantDiffPatched, addedSortedSubtreeRoots, - source, deselectedFeatures, true); + source, deselectedFeatures, debug); - GameEngine.showAndAwaitAll(Show.diff(diff)); - GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); + if (debug) GameEngine.showAndAwaitAll(Show.diff(diff)); + if (debug) GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); // GameEngine.showAndAwaitAll(Show.diff(diff), // Show.tree(targetVariant), Show.diff(optimizedDiff), Show.diff(targetVariantDiffPatched), // Show.tree(targetVariantDiffPatched.project(Time.AFTER))); From f31cfbf74767379da7956ff300ce57cf44a80b9b Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 1 Aug 2025 23:09:11 +0200 Subject: [PATCH 037/162] improved checkNeighbors with findNearestPositionToIndex() --- .../thesis_pm/PatchingExperiment.java | 26 ++++++++------ .../variation/diff/patching/Patching.java | 36 ++++++++++--------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index dcbefec93..1529f00b1 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -12,6 +12,8 @@ import org.tinylog.Logger; import org.variantsync.diffdetective.analysis.*; import org.variantsync.diffdetective.datasets.Repository; +import org.variantsync.diffdetective.show.Show; +import org.variantsync.diffdetective.show.engine.GameEngine; import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; @@ -24,6 +26,7 @@ public class PatchingExperiment implements Analysis.Hooks { private static final AnalysisResult.ResultKey SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY = new AnalysisResult.ResultKey<>( "successfully applied patches"); private int commits = 0; + private boolean firstDiff = true; private static class RejectedPatchesCounter extends SimpleMetadata { public RejectedPatchesCounter() { @@ -65,7 +68,8 @@ public boolean analyzeVariationDiff(Analysis analysis) throws Exception { VariationTree after = diff.project(Time.AFTER).deepCopy(); try { - VariationTree patchedVariant = Patching.patchVariationTrees(diff, before, false); + VariationTree patchedVariant = Patching.patchVariationTrees(diff, before, firstDiff); + firstDiff = false; if (!Patching.comparePatchedVariantWithExpectedResult(patchedVariant, after)) { analysis.get(INCORRECTLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; @@ -102,7 +106,7 @@ public static void main(String[] args) { // TODO Auto-generated catch block e.printStackTrace(); } -// try { + try { // patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), // parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); // patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), @@ -116,12 +120,12 @@ public static void main(String[] args) { // VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); // System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); -// VariationTree patchedVariant = Patching.patchVariationTrees( -// Patching.parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", "exampleA2NodesWith2Parents.cpp"), -// Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp")); -// VariationTree expectedResult = Patching.parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); + VariationTree patchedVariant = Patching.patchVariationTrees( + Patching.parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", "exampleA2NodesWith2Parents.cpp"), + Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp"), false); + VariationTree expectedResult = Patching.parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); // GameEngine.showAndAwaitAll(Show.tree(patchedVariant), Show.tree(expectedResult)); -// System.out.println(Patching.comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); + System.out.println(Patching.comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); // VariationTree patchedVariant = patchVariationTrees( // parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), @@ -135,10 +139,10 @@ public static void main(String[] args) { // parseVariationTreeFromFile("exampleBRemAlignmentP.cpp")); // patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAddAlignmentP.cpp", "exampleA2RemAddAlignmentP.cpp"), // parseVariationTreeFromFile("exampleBRemAddAlignmentP.cpp")); -// } catch (Exception e) { -// System.out.println("Rejected"); -// e.printStackTrace(); -// } + } catch (Exception e) { + System.out.println("Rejected"); + e.printStackTrace(); + } } } diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 8fe210c0f..7aec3de58 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -47,7 +47,8 @@ private static boolean isSameAs(DiffNode a, DiffNode b, } if (!(a.getNodeType().equals(b.getNodeType()) && - a.getLabel().equals(b.getLabel()) && + a.getLabel().toString().equals(b.getLabel().toString()) && +// a.getLabel().equals(b.getLabel()) && // a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && // a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) @@ -76,14 +77,15 @@ private static boolean isSameAsWithoutLabel(DiffNode a, Dif // a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && // a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) - && a.getLabel().getLines().equals(b.getLabel().getLines()))) { + && a.getLabel().getLines().equals(b.getLabel().getLines()) + )) { return false; } Iterator> aIt = a.getAllChildren().iterator(); Iterator> bIt = b.getAllChildren().iterator(); while (aIt.hasNext() && bIt.hasNext()) { - if (!isSameAs(aIt.next(), bIt.next(), visited)) { + if (!isSameAsWithoutLabel(aIt.next(), bIt.next(), visited)) { return false; } } @@ -220,12 +222,14 @@ private static boolean checkNeighbors(DiffNode root, DiffNode positions = findPositionsOfMatchingNeighborInList(neighborBeforeTarget, orderedChildrenSource, time); + indexSourceMatchingNeighborBefore = findNearestPositionToIndex(positions, indexTarget, true); } if (neighborAfterTarget != null) { - indexSourceMatchingNeighborAfter = findPositionOfMatchingNeighborInList(neighborAfterTarget, + List positions = findPositionsOfMatchingNeighborInList(neighborAfterTarget, orderedChildrenSource, time); + indexSourceMatchingNeighborAfter = findNearestPositionToIndex(positions, indexTarget, false); } if (indexSourceMatchingNeighborBefore == -2 && indexSourceMatchingNeighborAfter == -2) { if (debug) System.out.println("No neighbors before or after the target"); @@ -249,7 +253,12 @@ private static boolean checkNeighbors(DiffNode root, DiffNode neighbor, + private static int findNearestPositionToIndex(List positions, int indexTarget, boolean isBefore) { + if (isBefore) return positions.stream().map(pos -> (indexTarget - pos)).filter(pos -> pos > 0).min(Integer::compare).get(); + return positions.stream().map(pos -> (pos - indexTarget)).filter(pos -> pos > 0).min(Integer::compare).get(); + } + + private static ArrayList findPositionsOfMatchingNeighborInList(DiffNode neighbor, List> list, Time time) throws Exception { ArrayList positions = new ArrayList(); for (DiffNode node : list) { @@ -257,14 +266,7 @@ private static int findPositionOfMatchingNeighborInList(DiffNode positions.add(list.indexOf(node)); } } - if (positions.size() == 1) { - return positions.get(0); - } - if (positions.size() > 1) { - // TODO: throw exception? - throw new Exception("multiple insert positions found: " + positions.size()); - } - return -1; + return positions; } private static boolean isAlignmentProblem(List> subList, Set deselectedFeatures, @@ -317,10 +319,10 @@ private static int findInsertPosition(DiffNode root, DiffNode ta if (insertPosition < 0) { if (debug) System.out.println("no matching insert position found"); } else { - targetNodes2.add(targetNode); + targetNodes2.add(targetNodeInPatch); } } else if (type == DiffType.REM) { From 7e9441307ad88d9c0541e9d64a6695e70260c017 Mon Sep 17 00:00:00 2001 From: piameier Date: Sat, 2 Aug 2025 00:18:08 +0200 Subject: [PATCH 038/162] added context size to check more than one neighbor before and after the target --- .../variation/diff/patching/Patching.java | 244 ++++++++++++------ 1 file changed, 163 insertions(+), 81 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 7aec3de58..2ec945366 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -6,6 +6,8 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.NoSuchElementException; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -40,14 +42,13 @@ public static boolean isSameAs(DiffNode a, DiffNode b) { public static boolean isSameAsWithoutLabel(DiffNode a, DiffNode b) { return isSameAsWithoutLabel(a, b, new HashSet<>()); } - + private static boolean isSameAs(DiffNode a, DiffNode b, Set> visited) { if (!visited.add(a)) { return true; } - if (!(a.getNodeType().equals(b.getNodeType()) && - a.getLabel().toString().equals(b.getLabel().toString()) && + if (!(a.getNodeType().equals(b.getNodeType()) && a.getLabel().toString().equals(b.getLabel().toString()) && // a.getLabel().equals(b.getLabel()) && // a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && // a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && @@ -66,8 +67,9 @@ private static boolean isSameAs(DiffNode a, DiffNode b, return aIt.hasNext() == bIt.hasNext(); } - - private static boolean isSameAsWithoutLabel(DiffNode a, DiffNode b, Set> visited) { + + private static boolean isSameAsWithoutLabel(DiffNode a, DiffNode b, + Set> visited) { if (!visited.add(a)) { return true; } @@ -77,8 +79,7 @@ private static boolean isSameAsWithoutLabel(DiffNode a, Dif // a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && // a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) - && a.getLabel().getLines().equals(b.getLabel().getLines()) - )) { + && a.getLabel().getLines().equals(b.getLabel().getLines()))) { return false; } @@ -168,7 +169,8 @@ private static boolean checkForZeroVariantDrift(VariationDiff di deselectedFeatures); VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), deselectedFeatures); - if (debug) GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); + if (debug) + GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); if (Patching.isSameAs(diffVariant1, diffVariant2)) { return true; } @@ -190,27 +192,37 @@ private static Set> findRootsOfSubtrees(Set getChildFromListIfIndexInRange(List> childrenList, - int index) { - if (index >= 0 && index < childrenList.size()) { - return childrenList.get(index); + private static ArrayList> getChildrenFromListIfIndexInRange( + List> childrenList, int index, int numberOfChildren, boolean isBefore) { + int number = 0; + if (isBefore) + index = index - numberOfChildren; + ArrayList> children = new ArrayList<>(); + while (number < numberOfChildren) { + if (index + number >= 0 && index + number < childrenList.size()) { + children.add(childrenList.get(index + number)); + } + number++; } - return null; + return children; } private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, DiffNode node, Set deselectedFeatures, Time time, boolean debug) throws Exception { + // TODO + int contextSize = 10; + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); if (!orderedChildrenTarget.contains(node)) { // TODO: throw exception return false; } int indexTarget = orderedChildrenTarget.indexOf(node); - DiffNode neighborBeforeTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, - indexTarget - 1); - DiffNode neighborAfterTarget = getChildFromListIfIndexInRange(orderedChildrenTarget, - indexTarget + 1); + List> neighborBeforeTarget = getChildrenFromListIfIndexInRange(orderedChildrenTarget, + indexTarget, contextSize, true); + List> neighborAfterTarget = getChildrenFromListIfIndexInRange(orderedChildrenTarget, + indexTarget, contextSize, false); int indexSourceMatchingNeighborBefore = -2; int indexSourceMatchingNeighborAfter = -2; @@ -222,17 +234,18 @@ private static boolean checkNeighbors(DiffNode root, DiffNode positions = findPositionsOfMatchingNeighborInList(neighborBeforeTarget, + List positions = findPositionsOfMatchingNeighborsInList(neighborBeforeTarget, orderedChildrenSource, time); - indexSourceMatchingNeighborBefore = findNearestPositionToIndex(positions, indexTarget, true); + indexSourceMatchingNeighborBefore = findNearestPositionToIndex(positions, indexTarget, true) + contextSize; } if (neighborAfterTarget != null) { - List positions = findPositionsOfMatchingNeighborInList(neighborAfterTarget, - orderedChildrenSource, time); + List positions = findPositionsOfMatchingNeighborsInList(neighborAfterTarget, orderedChildrenSource, + time); indexSourceMatchingNeighborAfter = findNearestPositionToIndex(positions, indexTarget, false); } if (indexSourceMatchingNeighborBefore == -2 && indexSourceMatchingNeighborAfter == -2) { - if (debug) System.out.println("No neighbors before or after the target"); + if (debug) + System.out.println("No neighbors before or after the target"); return true; } if (indexSourceMatchingNeighborBefore > -1 && indexSourceMatchingNeighborAfter > -1) { @@ -242,9 +255,11 @@ private static boolean checkNeighbors(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget .subList(indexSourceMatchingNeighborBefore + 1, indexSourceMatchingNeighborAfter); - if (debug) System.out.println(orderedChildrenTargetSubList); + if (debug) + System.out.println(orderedChildrenTargetSubList); if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { - if (debug) System.out.println("ALIGNMENT PROBLEM. Node can be removed."); + if (debug) + System.out.println("ALIGNMENT PROBLEM. Node can be removed."); } else { return false; } @@ -254,16 +269,38 @@ private static boolean checkNeighbors(DiffNode root, DiffNode positions, int indexTarget, boolean isBefore) { - if (isBefore) return positions.stream().map(pos -> (indexTarget - pos)).filter(pos -> pos > 0).min(Integer::compare).get(); - return positions.stream().map(pos -> (pos - indexTarget)).filter(pos -> pos > 0).min(Integer::compare).get(); + Optional pos; + if (isBefore) { + pos = positions.stream().map(p -> (indexTarget - p)).filter(p -> p > 0) + .min(Integer::compare); + } else { + pos = positions.stream().map(p -> (p - indexTarget)).filter(p -> p > 0) + .min(Integer::compare); + } + try { + return pos.get(); + } catch (NoSuchElementException e) { + return -1; + } + } - private static ArrayList findPositionsOfMatchingNeighborInList(DiffNode neighbor, + private static ArrayList findPositionsOfMatchingNeighborsInList(List> neighbors, List> list, Time time) throws Exception { ArrayList positions = new ArrayList(); - for (DiffNode node : list) { - if (Patching.isSameAs(neighbor, node)) { - positions.add(list.indexOf(node)); + if (neighbors.size() == 0) + return positions; + for (int i = 0; i < list.size(); i++) { + boolean allNeighborsAreSame = false; + if (Patching.isSameAs(neighbors.get(0), list.get(i))) { + allNeighborsAreSame = true; + for (int j = 1; j < neighbors.size(); j++) { + if (list.size() > (i + j) && !Patching.isSameAs(neighbors.get(j), list.get(i + j))) { + allNeighborsAreSame = false; + } + } + if (allNeighborsAreSame) + positions.add(i); } } return positions; @@ -274,15 +311,21 @@ private static boolean isAlignmentProblem(List> subList boolean isAlignmentProblem = false; for (DiffNode node : subList) { Set containedFeatures = node.getPresenceCondition(time).getUniqueContainedFeatures(); - if (debug) System.out.println(containedFeatures); + if (debug) + System.out.println(containedFeatures); isAlignmentProblem = containedFeatures.stream().anyMatch(feature -> deselectedFeatures.contains(feature)); - if (debug) System.out.println("is alignment problem: " + isAlignmentProblem); + if (debug) + System.out.println("is alignment problem: " + isAlignmentProblem); } return isAlignmentProblem; } private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, Set deselectedFeatures, Time time, boolean debug) throws Exception { + + // TODO + int contextSize = 10; + if (debug) System.out.println("Root node to insert: " + root.toString()); List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); @@ -292,17 +335,18 @@ private static int findInsertPosition(DiffNode root, DiffNode neighborBeforeSource = getChildFromListIfIndexInRange(orderedChildrenSource, - indexSource - 1); - DiffNode neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, - indexSource + 1); + List> neighborBeforeSource = getChildrenFromListIfIndexInRange(orderedChildrenSource, + indexSource, contextSize, true); + List> neighborAfterSource = getChildrenFromListIfIndexInRange(orderedChildrenSource, + indexSource, contextSize, false); int currentIndexAfter = indexSource + 1; - // ignore neighbors with DiffType ADD because they are added afterwards - while (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { - currentIndexAfter++; - neighborAfterSource = getChildFromListIfIndexInRange(orderedChildrenSource, currentIndexAfter); - } - + //ignore neighbors with DiffType ADD because they are added afterwards + neighborAfterSource = neighborAfterSource.stream().filter(n -> n.diffType != DiffType.ADD).toList(); +// while (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { +// currentIndexAfter++; +// neighborAfterSource = getChildrenFromListIfIndexInRange(orderedChildrenSource, currentIndexAfter); +// } + if (debug) { if (neighborBeforeSource != null) { System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); @@ -318,20 +362,34 @@ private static int findInsertPosition(DiffNode root, DiffNode positions = findPositionsOfMatchingNeighborsInList(neighborBeforeSource, + orderedChildrenTarget, time); + if (positions.size() == 1) + indexBefore = positions.get(0); + else + throw new Exception( + "too many insert positions found: " + positions.size() + " with context size: " + contextSize); + } + if (!neighborAfterSource.isEmpty()) { + List positions = findPositionsOfMatchingNeighborsInList(neighborAfterSource, orderedChildrenTarget, + time); + if (positions.size() == 1) + indexAfter = positions.get(0); + else + throw new Exception( + "too many insert positions found: " + positions.size() + " with context size: " + contextSize); } if (indexBefore == -2 && indexAfter == -2) { if (orderedChildrenTarget.isEmpty()) { - if (debug) System.out.println("No neighbors before or after the target"); + if (debug) + System.out.println("No neighbors before or after the target"); return 0; } if (isAlignmentProblem(orderedChildrenTarget, deselectedFeatures, time, debug)) { - if (debug) System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " - + (orderedChildrenTarget.size() - 1)); + if (debug) + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + + (orderedChildrenTarget.size() - 1)); return -1; } else { throw new Exception("Reject"); @@ -341,7 +399,9 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(0, indexAfter); if (orderedChildrenTargetSubList.size() > 1) { if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { - if (debug) System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + indexAfter); + if (debug) + System.out.println( + "ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + indexAfter); } else { throw new Exception("Reject"); } @@ -351,11 +411,13 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, orderedChildrenTarget.size()); - if (debug) System.out.println(orderedChildrenTargetSubList); + if (debug) + System.out.println(orderedChildrenTargetSubList); if (orderedChildrenTargetSubList.size() > 1) { if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { - if (debug) System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) - + " to " + (orderedChildrenTarget.size() - 1)); + if (debug) + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + + " to " + (orderedChildrenTarget.size() - 1)); } else { throw new Exception("Reject"); } @@ -369,10 +431,12 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget .subList(indexBefore + 1, indexAfter); - if (debug) System.out.println(orderedChildrenTargetSubList); + if (debug) + System.out.println(orderedChildrenTargetSubList); if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { - if (debug) System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) - + " to " + indexAfter); + if (debug) + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + + " to " + indexAfter); } else { throw new Exception("Reject"); } @@ -380,7 +444,8 @@ private static int findInsertPosition(DiffNode root, DiffNode ta DiffNode newRoot = DiffNode.createRoot(new DiffLinesLabel()); newRoot.addChild(root.deepCopy(), time); VariationDiff subTree = new VariationDiff(newRoot, source); - if (debug) GameEngine.showAndAwaitAll(Show.diff(subTree)); + if (debug) + GameEngine.showAndAwaitAll(Show.diff(subTree)); } List> targetNodes = new ArrayList>(); @@ -412,25 +478,28 @@ private static void applyChanges(DiffType type, VariationDiff ta .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); } - + List> targetNodes2 = new ArrayList>(); for (DiffNode targetNode : targetNodes) { - DiffNode targetNodeInPatch = targetVariantDiffPatched - .getNodeWithID(targetNode.getID()); - if (debug) System.out.println(targetNodeInPatch.toString()); + DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNode.getID()); + if (debug) + System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug); if (insertPosition < 0) { - if (debug) System.out.println("no matching insert position found"); + if (debug) + System.out.println("no matching insert position found"); } else { targetNodes2.add(targetNodeInPatch); } } else if (type == DiffType.REM) { List> nodesToRem = new ArrayList>(); - if (debug) System.out.println("Root: " + root.toString()); - if (debug) System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); + if (debug) + System.out.println("Root: " + root.toString()); + if (debug) + System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); targetNodeInPatch.getAllChildrenStream().forEach(node -> { try { if (Patching.isSameAs(node, root) @@ -441,33 +510,42 @@ && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, debug e.printStackTrace(); } }); - if (debug) System.out.println("Nodes to remove: " + nodesToRem); + if (debug) + System.out.println("Nodes to remove: " + nodesToRem); if (nodesToRem.size() != 1) { - if (debug) System.out.println("too much or too less target nodes found"); - if (debug) System.out.println(nodesToRem.toString()); + if (debug) + System.out.println("too much or too less target nodes found"); + if (debug) + System.out.println(nodesToRem.toString()); } else { targetNodes2.add(nodesToRem.get(0)); } } - if (debug) GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); + if (debug) + GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); } - + if (targetNodes2.size() != 1) { throw new Exception("too much or too less targetNodes found: " + targetNodes2.size()); } else { DiffNode targetNodeInPatch = targetNodes2.get(0); if (type == DiffType.ADD) { - if (debug) System.out.println("subtree added"); - targetNodeInPatch.insertChild(root.deepCopy(), findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug), time); - if (debug) System.out.println(targetNodeInPatch.getChildOrder(time)); + if (debug) + System.out.println("subtree added"); + targetNodeInPatch.insertChild(root.deepCopy(), + findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug), time); + if (debug) + System.out.println(targetNodeInPatch.getChildOrder(time)); } else if (type == DiffType.REM) { - if (debug) System.out.println("subtree removed"); + if (debug) + System.out.println("subtree removed"); removeNode(targetNodeInPatch); - if (debug) System.out.println(targetNodes2.get(0).getChildOrder(Time.AFTER)); + if (debug) + System.out.println(targetNodes2.get(0).getChildOrder(Time.AFTER)); } } - + } } @@ -484,7 +562,8 @@ private static VariationTree patchVariationTrees( VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, VariationTree targetVariant, boolean debug) throws Exception { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { - if (debug) System.out.println("Parsing error"); + if (debug) + System.out.println("Parsing error"); return null; } VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); @@ -508,7 +587,8 @@ public static VariationTree patchVariationTrees(VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); - if (debug) GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched), Show.diff(optimizedDiff)); + if (debug) + GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched), Show.diff(optimizedDiff)); Set> removedNodes = new HashSet>(); Set> addedNodes = new HashSet>(); @@ -548,8 +628,10 @@ public static VariationTree patchVariationTrees(VariationDiff Date: Mon, 4 Aug 2025 17:13:53 +0200 Subject: [PATCH 039/162] fixed bugs --- .../variation/diff/patching/Patching.java | 58 ++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 2ec945366..dc6027803 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -271,11 +271,9 @@ private static boolean checkNeighbors(DiffNode root, DiffNode positions, int indexTarget, boolean isBefore) { Optional pos; if (isBefore) { - pos = positions.stream().map(p -> (indexTarget - p)).filter(p -> p > 0) - .min(Integer::compare); + pos = positions.stream().map(p -> (indexTarget - p)).filter(p -> p > 0).min(Integer::compare); } else { - pos = positions.stream().map(p -> (p - indexTarget)).filter(p -> p > 0) - .min(Integer::compare); + pos = positions.stream().map(p -> (p - indexTarget)).filter(p -> p > 0).min(Integer::compare); } try { return pos.get(); @@ -340,7 +338,7 @@ private static int findInsertPosition(DiffNode root, DiffNode> neighborAfterSource = getChildrenFromListIfIndexInRange(orderedChildrenSource, indexSource, contextSize, false); int currentIndexAfter = indexSource + 1; - //ignore neighbors with DiffType ADD because they are added afterwards + // ignore neighbors with DiffType ADD because they are added afterwards neighborAfterSource = neighborAfterSource.stream().filter(n -> n.diffType != DiffType.ADD).toList(); // while (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { // currentIndexAfter++; @@ -365,20 +363,38 @@ private static int findInsertPosition(DiffNode root, DiffNode positions = findPositionsOfMatchingNeighborsInList(neighborBeforeSource, orderedChildrenTarget, time); - if (positions.size() == 1) - indexBefore = positions.get(0); - else - throw new Exception( - "too many insert positions found: " + positions.size() + " with context size: " + contextSize); + if (positions.size() == 1) { + indexBefore = positions.get(0) + neighborBeforeSource.size(); + } else if (positions.size() > 1) { + List positionsSource = findPositionsOfMatchingNeighborsInList(neighborAfterSource, + orderedChildrenSource, time); + if (positionsSource.size() == positions.size()) { + int arrayIndex = positionsSource.indexOf(indexSource + 1); + indexAfter = positions.get(arrayIndex); + } else { + throw new Exception("target node: " + targetNodeInPatch.toString() + "too many insert positions found: " + + positions.toString() + " with context size: " + contextSize); + } + } + + } if (!neighborAfterSource.isEmpty()) { List positions = findPositionsOfMatchingNeighborsInList(neighborAfterSource, orderedChildrenTarget, time); - if (positions.size() == 1) + if (positions.size() == 1) { indexAfter = positions.get(0); - else - throw new Exception( - "too many insert positions found: " + positions.size() + " with context size: " + contextSize); + } else if (positions.size() > 1) { + List positionsSource = findPositionsOfMatchingNeighborsInList(neighborAfterSource, + orderedChildrenSource, time); + if (positionsSource.size() == positions.size()) { + int arrayIndex = positionsSource.indexOf(indexSource + 1); + indexAfter = positions.get(arrayIndex); + } else { + throw new Exception("target node:" + targetNodeInPatch.toString() + "too many insert positions found: " + + positions.toString() + " with context size: " + contextSize); + } + } } if (indexBefore == -2 && indexAfter == -2) { if (orderedChildrenTarget.isEmpty()) { @@ -409,14 +425,14 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore + 1, + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore, orderedChildrenTarget.size()); if (debug) System.out.println(orderedChildrenTargetSubList); if (orderedChildrenTargetSubList.size() > 1) { if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { if (debug) - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + indexBefore + " to " + (orderedChildrenTarget.size() - 1)); } else { throw new Exception("Reject"); @@ -425,19 +441,20 @@ private static int findInsertPosition(DiffNode root, DiffNode -1 && indexAfter > -1) { - if (indexAfter - (indexBefore + 1) > 1) { + if (indexAfter - indexBefore > 1) { // Alignment Problem ? // TODO: Check if code belongs to features which are only present in target // variant List> orderedChildrenTargetSubList = orderedChildrenTarget - .subList(indexBefore + 1, indexAfter); + .subList(indexBefore, indexAfter); if (debug) System.out.println(orderedChildrenTargetSubList); if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { if (debug) - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore + 1) + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + indexBefore + " to " + indexAfter); } else { + System.out.println("after: " + indexAfter + " before: " + indexBefore); throw new Exception("Reject"); } return -1; @@ -450,7 +467,7 @@ private static int findInsertPosition(DiffNode root, DiffNode targetVariantDiffUnchanged, @@ -527,6 +544,7 @@ && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, debug } if (targetNodes2.size() != 1) { + System.out.println(root); throw new Exception("too much or too less targetNodes found: " + targetNodes2.size()); } else { DiffNode targetNodeInPatch = targetNodes2.get(0); From dddff0f46e0d2b086200ab729dbad1fb48165013 Mon Sep 17 00:00:00 2001 From: piameier Date: Sat, 23 Aug 2025 23:47:28 +0200 Subject: [PATCH 040/162] implemented compareAncestors() and fixed bugs --- .../thesis_pm/PatchingExperiment.java | 95 ++++-- .../variation/diff/patching/Patching.java | 313 ++++++++++++------ 2 files changed, 271 insertions(+), 137 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 1529f00b1..68d845d04 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -4,11 +4,13 @@ import java.nio.file.Path; import org.variantsync.diffdetective.AnalysisRunner; -import org.variantsync.diffdetective.analysis.Analysis; import org.variantsync.diffdetective.variation.DiffLinesLabel; import org.variantsync.diffdetective.variation.diff.patching.Patching; +import org.variantsync.diffdetective.variation.diff.transform.CutNonEditedSubtrees; import org.variantsync.diffdetective.variation.tree.VariationTree; import java.util.List; +import java.util.concurrent.ExecutionException; + import org.tinylog.Logger; import org.variantsync.diffdetective.analysis.*; import org.variantsync.diffdetective.datasets.Repository; @@ -25,8 +27,11 @@ public class PatchingExperiment implements Analysis.Hooks { "incorrectly applied patches"); private static final AnalysisResult.ResultKey SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY = new AnalysisResult.ResultKey<>( "successfully applied patches"); + private static final AnalysisResult.ResultKey SKIPPED_PATCHES_COUNTER_RESULT_KEY = new AnalysisResult.ResultKey<>( + "skipped patches"); private int commits = 0; private boolean firstDiff = true; + private VariationDiff firstIncorrectlyPatchedDiff; private static class RejectedPatchesCounter extends SimpleMetadata { public RejectedPatchesCounter() { @@ -40,19 +45,30 @@ public IncorrectlyAppliedPatchesCounter() { super(0, "incorrectly applied patches", Integer::sum); } } - + private static class SuccessfullyAppliedPatchesCounter - extends SimpleMetadata { -public SuccessfullyAppliedPatchesCounter() { - super(0, "successfully applied patches", Integer::sum); -} -} + extends SimpleMetadata { + public SuccessfullyAppliedPatchesCounter() { + super(0, "successfully applied patches", Integer::sum); + } + } + + private static class SkippedPatchesCounter extends SimpleMetadata { + public SkippedPatchesCounter() { + super(0, "skipped patches", Integer::sum); + } + } + + public VariationDiff getFirstIncorrectlyPatchedDiff() { + return this.firstIncorrectlyPatchedDiff; + } @Override public void initializeResults(Analysis analysis) { analysis.append(REJECTED_PATCHES_COUNTER_RESULT_KEY, new RejectedPatchesCounter()); analysis.append(INCORRECTLY_APPLIED_PATCHES_COUNTER_RESULT_KEY, new IncorrectlyAppliedPatchesCounter()); analysis.append(SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY, new SuccessfullyAppliedPatchesCounter()); + analysis.append(SKIPPED_PATCHES_COUNTER_RESULT_KEY, new SkippedPatchesCounter()); } @Override @@ -66,13 +82,22 @@ public boolean analyzeVariationDiff(Analysis analysis) throws Exception { VariationDiff diff = analysis.getCurrentVariationDiff(); VariationTree before = diff.project(Time.BEFORE).deepCopy(); VariationTree after = diff.project(Time.AFTER).deepCopy(); - try { - VariationTree patchedVariant = Patching.patchVariationTrees(diff, before, firstDiff); - firstDiff = false; + VariationDiff patchedVariant = Patching.patchVariationTrees(diff, before, false, true); - if (!Patching.comparePatchedVariantWithExpectedResult(patchedVariant, after)) { + if (!Patching.comparePatchedVariantWithExpectedResult(patchedVariant.project(Time.AFTER), after)) { analysis.get(INCORRECTLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; + VariationDiff diffCopy = diff.deepCopy(); + VariationDiff patchedCopy = patchedVariant.deepCopy(); + CutNonEditedSubtrees.genericTransform(diffCopy); + CutNonEditedSubtrees.genericTransform(patchedCopy); + GameEngine.showAndAwaitAll(Show.diff(diffCopy), Show.diff(patchedCopy)); + if (firstDiff) { + Patching.patchVariationTrees(diff, before, true, true); + wait(60000); + firstDiff = false; + } + } else { analysis.get(SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; } @@ -88,31 +113,29 @@ public void endBatch(Analysis analysis) throws Exception { Logger.info("Batch done: {} commits analyzed", commits); } - public static Analysis Create(Repository repo, Path outputDirectory) { - return new Analysis("my analysis", List.of(new PatchingExperiment() -// , new StatisticsAnalysis() -// , new EditClassValidation() + public static Analysis Create(Repository repo, Path outputDirectory, PatchingExperiment experiment) { + return new Analysis("my analysis", List.of( + experiment, new StatisticsAnalysis() +// , new EditClassValidation() ), repo, outputDirectory); } public static void main(String[] args) { + PatchingExperiment experiment = new PatchingExperiment(); try { AnalysisRunner.run( new AnalysisRunner.Options(Path.of("data", "repos"), Path.of("data", "output"), Path.of("data", "demo-dataset.md")), - (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path), 20, - 8)); - } catch (IOException e) { - // TODO Auto-generated catch block + (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path, experiment), 20, + 1)); + } catch (Exception e) { e.printStackTrace(); } try { -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Add.cpp"), -// parseVariationTreeFromFile("exampleA2Add.cpp"), parseVariationTreeFromFile("exampleBAdd.cpp")); -// patchVariationTrees(parseVariationTreeFromFile("exampleA1Rem.cpp"), -// parseVariationTreeFromFile("exampleA2Rem.cpp"), parseVariationTreeFromFile("exampleBRem.cpp")); -// patchVariationTrees(parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), -// parseVariationTreeFromFile("exampleBRemAdd.cpp")); +// Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Add.cpp", "exampleA2Add.cpp"), Patching.parseVariationTreeFromFile("exampleBAdd.cpp"), true, true); +// Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Rem.cpp", "exampleA2Rem.cpp"), Patching.parseVariationTreeFromFile("exampleBRem.cpp"), true, true); +// Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), +// Patching.parseVariationTreeFromFile("exampleBRemAdd.cpp"), true, true); // VariationTree patchedVariant = patchVariationTrees( // parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), @@ -120,16 +143,20 @@ public static void main(String[] args) { // VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); // System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); - VariationTree patchedVariant = Patching.patchVariationTrees( - Patching.parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", "exampleA2NodesWith2Parents.cpp"), - Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp"), false); - VariationTree expectedResult = Patching.parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); +// VariationTree patchedVariant = Patching.patchVariationTrees( +// Patching.parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", +// "exampleA2NodesWith2Parents.cpp"), +// Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp"), true); +// VariationTree expectedResult = Patching +// .parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); // GameEngine.showAndAwaitAll(Show.tree(patchedVariant), Show.tree(expectedResult)); - System.out.println(Patching.comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); - -// VariationTree patchedVariant = patchVariationTrees( -// parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), -// parseVariationTreeFromFile("exampleA1RemAdd.cpp")); +// System.out.println(Patching.comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); +// VariationDiff patchedVariant = Patching.patchVariationTrees( +// Patching.parseVariationDiffFromFile("example1.diff"), +// Patching.parseVariationTreeFromFile("example2_B.cpp"), true, true); +// VariationDiff diff = Patching.parseVariationDiffFromFile("motivating_exA_view.diff"); +// VariationTree tree = Patching.parseVariationTreeFromFile("motivating_exB.cpp"); +// GameEngine.showAndAwaitAll( Show.tree(diff.project(Time.BEFORE))); // VariationTree expectedResult = parseVariationTreeFromFile("exampleA2RemAdd.cpp"); // System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index dc6027803..58b383b03 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -3,9 +3,11 @@ import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; @@ -24,12 +26,18 @@ import org.variantsync.diffdetective.variation.diff.VariationDiff; import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; import org.variantsync.diffdetective.variation.diff.source.VariationDiffSource; +import org.variantsync.diffdetective.variation.diff.transform.CutNonEditedSubtrees; import org.variantsync.diffdetective.variation.diff.view.DiffView; import org.variantsync.diffdetective.variation.tree.VariationTree; import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; +import com.ibm.icu.impl.CalendarUtil; + public class Patching { + public static boolean hasSameLabel(DiffNode a, DiffNode b) { + return a.getLabel().toString().equals(b.getLabel().toString()); + } public static boolean isSameAs(VariationDiff diff1, VariationDiff diff2) { return isSameAsWithoutLabel(diff1.getRoot(), diff2.getRoot()); @@ -53,7 +61,8 @@ private static boolean isSameAs(DiffNode a, DiffNode b, // a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && // a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) - && a.getLabel().getLines().equals(b.getLabel().getLines()))) { + // && a.getLabel().getLines().equals(b.getLabel().getLines()) + )) { return false; } @@ -79,7 +88,8 @@ private static boolean isSameAsWithoutLabel(DiffNode a, Dif // a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && // a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) - && a.getLabel().getLines().equals(b.getLabel().getLines()))) { +// && a.getLabel().getLines().equals(b.getLabel().getLines()) + )) { return false; } @@ -118,8 +128,9 @@ private static Relevance calculateFormulaForDeselection(Set set, boolean } Formula formula = Formula.and(f); - if (debug) + if (debug) { System.out.println(formula.get().toString()); + } return new Configure(formula); } @@ -144,22 +155,69 @@ private static Set calculateFeatureSetToDeselectFromTrees(VariationTree< } private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diff, - VariationTree variant2, boolean debug) { + VariationTree variant2, boolean debug, boolean patchNewFeatures) { + Map featuresMapV1 = new HashMap(); Set featuresV1 = new HashSet(); diff.forAll(node -> { + if (debug && node.getDiffType() == DiffType.NON) { + System.out.println("NON features:" + node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures()); + } if (node.getDiffType().existsAtTime(Time.BEFORE)) { - featuresV1.addAll(node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures()); + node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures().forEach(feature -> { + if (featuresMapV1.containsKey(feature) && node.getDiffType() != featuresMapV1.get(feature)) { + featuresMapV1.replace(feature, DiffType.NON); + } else { + featuresMapV1.put(feature, node.getDiffType()); + } + }); } if (node.getDiffType().existsAtTime(Time.AFTER)) { - featuresV1.addAll(node.getFeatureMapping(Time.AFTER).getUniqueContainedFeatures()); + node.getFeatureMapping(Time.AFTER).getUniqueContainedFeatures().forEach(feature -> { + if (featuresMapV1.containsKey(feature)) { + if (!node.getDiffType().equals(featuresMapV1.get(feature))) { + if (debug) { + System.out.println(feature + ": " + node.getDiffType()); + System.out.println(feature + ": " + featuresMapV1.get(feature)); + } + featuresMapV1.replace(feature, DiffType.NON); + } + } else { + if (debug) { + System.out.println(feature + ": " + node.getDiffType()); + } + featuresMapV1.put(feature, node.getDiffType()); + } + }); } }); + featuresMapV1.forEach((feature, diffType) -> { + featuresV1.add(feature); + }); + Set featuresV2 = new HashSet(); variant2.forAllPreorder(node -> { featuresV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); }); + if (patchNewFeatures) { + Set features = calculateSetMinusOfFeatureSets(featuresV1, featuresV2, debug); + featuresMapV1.forEach((feature, diffType) -> { + if (diffType == DiffType.ADD) { + if (features.contains(feature)) { + features.remove(feature); + } + } + }); + + if (!features.isEmpty()) { + System.out.println(featuresV1); + System.out.println(featuresV2); + System.out.println(featuresMapV1); + } + return features; + } + return calculateSetMinusOfFeatureSets(featuresV1, featuresV2, debug); } @@ -169,8 +227,8 @@ private static boolean checkForZeroVariantDrift(VariationDiff di deselectedFeatures); VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), deselectedFeatures); - if (debug) - GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); +// if (debug) +// GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); if (Patching.isSameAs(diffVariant1, diffVariant2)) { return true; } @@ -207,6 +265,33 @@ private static ArrayList> getChildrenFromListIfIndexInR return children; } + private static boolean compareAncestors(DiffNode node1, DiffNode node2, Time time) { + if (node1.getParent(time) == null && node2.getParent(time) == null) + return true; + if (node1.getParent(time) != null && node2.getParent(time) == null) + return false; + if (node1.getParent(time) == null && node2.getParent(time) != null) + return false; + List> siblingsNode1 = node1.getParent(time).getChildOrder(time); + List> siblingsNode2 = node2.getParent(time).getChildOrder(time); + int indexNode1 = siblingsNode1.indexOf(node1); + int indexNode2 = siblingsNode2.indexOf(node2); + if (indexNode1 != indexNode2) { + return false; + } + for (int i = 0; i < siblingsNode1.size(); i++) { + if (!hasSameLabel(siblingsNode1.get(i), siblingsNode2.get(i))) { + return false; + } + } + return compareAncestors(node1.getParent(time), node2.getParent(time), time); + } + + private static boolean checkNeighborsLabels(DiffNode root, + DiffNode targetNodeInPatch, Set deselectedFeatures, Time time, boolean debug) { + return compareAncestors(targetNodeInPatch, root.getParent(time), time); + } + private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, DiffNode node, Set deselectedFeatures, Time time, boolean debug) throws Exception { @@ -372,12 +457,12 @@ private static int findInsertPosition(DiffNode root, DiffNode positions = findPositionsOfMatchingNeighborsInList(neighborAfterSource, orderedChildrenTarget, @@ -391,8 +476,9 @@ private static int findInsertPosition(DiffNode root, DiffNode root, DiffNode 1) { if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { if (debug) - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + indexBefore - + " to " + (orderedChildrenTarget.size() - 1)); + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + indexBefore + " to " + + (orderedChildrenTarget.size() - 1)); } else { throw new Exception("Reject"); } @@ -445,14 +531,14 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget - .subList(indexBefore, indexAfter); + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore, + indexAfter); if (debug) System.out.println(orderedChildrenTargetSubList); if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { if (debug) - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + indexBefore - + " to " + indexAfter); + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + indexBefore + " to " + + indexAfter); } else { System.out.println("after: " + indexAfter + " before: " + indexBefore); throw new Exception("Reject"); @@ -481,8 +567,7 @@ private static void applyChanges(DiffType type, VariationDiff ta DiffNode newRoot = DiffNode.createRoot(new DiffLinesLabel()); newRoot.addChild(root.deepCopy(), time); VariationDiff subTree = new VariationDiff(newRoot, source); - if (debug) - GameEngine.showAndAwaitAll(Show.diff(subTree)); + GameEngine.showAndAwaitAll(Show.diff(subTree)); } List> targetNodes = new ArrayList>(); @@ -497,116 +582,129 @@ private static void applyChanges(DiffType type, VariationDiff ta } List> targetNodes2 = new ArrayList>(); - for (DiffNode targetNode : targetNodes) { - DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNode.getID()); - if (debug) - System.out.println(targetNodeInPatch.toString()); - if (type == DiffType.ADD) { + targetNodes2 = targetNodes.stream() + .filter(targetNode -> checkNeighborsLabels(root, targetNode, deselectedFeatures, time, debug)) + .toList(); + if (targetNodes2.size() != 1) { + throw new Exception("too much or too less target nodes after filtering: " + targetNodes2.size() + "/" + + targetNodes.size()); + } - int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug); - if (insertPosition < 0) { - if (debug) - System.out.println("no matching insert position found"); - } else { - targetNodes2.add(targetNodeInPatch); - } + DiffNode targetNode = targetNodes2.get(0); + if (debug) + System.out.println("targetNode:" + targetNode.toString()); + DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNode.getID()); + if (debug) + System.out.println(targetNodeInPatch.toString()); + if (type == DiffType.ADD) { - } else if (type == DiffType.REM) { - List> nodesToRem = new ArrayList>(); - if (debug) - System.out.println("Root: " + root.toString()); - if (debug) - System.out.println("Children: " + targetNodeInPatch.getAllChildrenSet()); - targetNodeInPatch.getAllChildrenStream().forEach(node -> { - try { - if (Patching.isSameAs(node, root) - && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, debug)) - nodesToRem.add(node); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - }); + int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug); + if (insertPosition < 0) { if (debug) - System.out.println("Nodes to remove: " + nodesToRem); - - if (nodesToRem.size() != 1) { - if (debug) - System.out.println("too much or too less target nodes found"); - if (debug) - System.out.println(nodesToRem.toString()); - } else { - targetNodes2.add(nodesToRem.get(0)); - } + System.out.println("no matching insert position found"); } if (debug) - GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched)); - } + System.out.println("subtree added"); + targetNodeInPatch.insertChild(root.deepCopy(), + findInsertPosition(root, targetNode, deselectedFeatures, time, debug), time); + if (debug) + System.out.println(targetNode.getChildOrder(time)); + + } else if (type == DiffType.REM) { + List> nodesToRem = new ArrayList>(); + targetNodeInPatch.getAllChildrenStream().forEach(node -> { + try { + if (Patching.isSameAs(node, root) +// && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, debug) + ) + nodesToRem.add(node); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + }); + if (debug) + System.out.println("Nodes to remove: " + nodesToRem); - if (targetNodes2.size() != 1) { - System.out.println(root); - throw new Exception("too much or too less targetNodes found: " + targetNodes2.size()); - } else { - DiffNode targetNodeInPatch = targetNodes2.get(0); - if (type == DiffType.ADD) { - if (debug) - System.out.println("subtree added"); - targetNodeInPatch.insertChild(root.deepCopy(), - findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug), time); + if (nodesToRem.size() != 1) { if (debug) - System.out.println(targetNodeInPatch.getChildOrder(time)); - } else if (type == DiffType.REM) { + System.out.println("too much or too less target nodes found"); if (debug) - System.out.println("subtree removed"); - removeNode(targetNodeInPatch); - if (debug) - System.out.println(targetNodes2.get(0).getChildOrder(Time.AFTER)); - } + System.out.println(nodesToRem.toString()); + } + if (debug) + System.out.println("subtree removed"); + removeNode(nodesToRem.get(0)); + if (debug) + System.out.println(targetNode.getChildOrder(Time.AFTER)); + } + if (debug) { + VariationDiff targetVariantDiffPatchedCopy = targetVariantDiffPatched.deepCopy(); +// CutNonEditedSubtrees.genericTransform(targetVariantDiffPatchedCopy); + GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatchedCopy)); } - } } - private static void removeNode(DiffNode node) { + private static void removeNode(DiffNode node) throws Exception { Set> children = node.getAllChildrenSet(); if (!children.isEmpty()) { - children.forEach(child -> removeNode(child)); + children.forEach(child -> { + try { + removeNode(child); + } catch (Exception e) { + e.printStackTrace(); + } + }); } node.diffType = DiffType.REM; - node.drop(Time.AFTER); + if (node.getParent(Time.AFTER) != null) { + node.drop(Time.AFTER); + } else { + throw new Exception("Reject: parent node is null when dropping"); + } + } - private static VariationTree patchVariationTrees( + private static VariationDiff patchVariationTrees( VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, - VariationTree targetVariant, boolean debug) throws Exception { + VariationTree targetVariant, boolean debug, boolean patchNewFeatures) throws Exception { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { if (debug) System.out.println("Parsing error"); return null; } VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - return patchVariationTrees(diff, targetVariant, debug); + return patchVariationTrees(diff, targetVariant, debug, patchNewFeatures); } - public static VariationTree patchVariationTrees(VariationDiff diff, - VariationTree targetVariant, boolean debug) throws Exception { + public static VariationDiff patchVariationTrees(VariationDiff diff, + VariationTree targetVariant, boolean debug, boolean patchNewFeatures) throws Exception { // Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, // false); - Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, debug); - Relevance rho = calculateFormulaForDeselection(deselectedFeatures, debug); - - if (!checkForZeroVariantDrift(diff, targetVariant, rho, debug)) { - throw new Exception("Variants evolved independently: No Zero Variant Drift"); + Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, debug, + patchNewFeatures); + if (!deselectedFeatures.isEmpty()) { + System.out.println(deselectedFeatures); } + Relevance rho = calculateFormulaForDeselection(deselectedFeatures, debug); +// if (!checkForZeroVariantDrift(diff, targetVariant, rho, debug)) { +// throw new Exception("Variants evolved independently: No Zero Variant Drift"); +// } +// +// VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + if (debug) { + GameEngine.showAndAwaitAll(Show.diff(diff), Show.diff(optimizedDiff)); + } +// VariationDiff optimizedDiff = diff.deepCopy(); VariationDiffSource source = optimizedDiff.getSource(); - VariationDiff targetVariantDiffUnchanged = targetVariant.toCompletelyUnchangedVariationDiff(); - VariationDiff targetVariantDiffPatched = targetVariant.toCompletelyUnchangedVariationDiff(); - - if (debug) - GameEngine.showAndAwaitAll(Show.diff(targetVariantDiffPatched), Show.diff(optimizedDiff)); + VariationDiff targetVariantDiffUnchanged = targetVariant.deepCopy() + .toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantDiffPatched = targetVariant.deepCopy() + .toCompletelyUnchangedVariationDiff(); Set> removedNodes = new HashSet>(); Set> addedNodes = new HashSet>(); @@ -646,14 +744,17 @@ public static VariationTree patchVariationTrees(VariationDiff targetVariantDiffPatchedCopy = targetVariantDiffPatched.deepCopy(); + VariationDiff optimizedDiffCopy = optimizedDiff.deepCopy(); + CutNonEditedSubtrees.genericTransform(targetVariantDiffPatchedCopy); + CutNonEditedSubtrees.genericTransform(optimizedDiffCopy); + GameEngine.showAndAwaitAll(Show.diff(optimizedDiffCopy), Show.diff(targetVariantDiffPatchedCopy)); + } + return targetVariantDiffPatched; } public static VariationDiff parseVariationDiffFromFiles(String file1, String file2) @@ -663,6 +764,12 @@ public static VariationDiff parseVariationDiffFromFiles(String f DiffAlgorithm.SupportedAlgorithm.MYERS, VariationDiffParseOptions.Default); } + public static VariationDiff parseVariationDiffFromFile(String file) + throws IOException, DiffParseException { + Path examplesDir = Path.of("data", "examples"); + return VariationDiff.fromFile(examplesDir.resolve(file), VariationDiffParseOptions.Default); + } + public static VariationTree parseVariationTreeFromFile(String file) { Path examplesDir = Path.of("data", "examples"); Path path = examplesDir.resolve(file); From 9da7092811e4b97f82329d7985bbc517dd5ad928 Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 24 Aug 2025 17:47:45 +0200 Subject: [PATCH 041/162] fixed bugs, alternative methods for patching same variants --- .../thesis_pm/PatchingExperiment.java | 36 +++--- .../variation/diff/patching/Patching.java | 113 +++++++++++++----- 2 files changed, 104 insertions(+), 45 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index 68d845d04..d097a6a4c 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -92,11 +92,11 @@ public boolean analyzeVariationDiff(Analysis analysis) throws Exception { CutNonEditedSubtrees.genericTransform(diffCopy); CutNonEditedSubtrees.genericTransform(patchedCopy); GameEngine.showAndAwaitAll(Show.diff(diffCopy), Show.diff(patchedCopy)); - if (firstDiff) { - Patching.patchVariationTrees(diff, before, true, true); - wait(60000); - firstDiff = false; - } +// if (firstDiff) { +// Patching.patchVariationTrees(diff, before, true, true); +// wait(60000); +// firstDiff = false; +// } } else { analysis.get(SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; @@ -121,22 +121,22 @@ experiment, new StatisticsAnalysis() } public static void main(String[] args) { - PatchingExperiment experiment = new PatchingExperiment(); - try { - AnalysisRunner.run( - new AnalysisRunner.Options(Path.of("data", "repos"), Path.of("data", "output"), - Path.of("data", "demo-dataset.md")), - (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path, experiment), 20, - 1)); - } catch (Exception e) { - e.printStackTrace(); - } +// PatchingExperiment experiment = new PatchingExperiment(); +// try { +// AnalysisRunner.run( +// new AnalysisRunner.Options(Path.of("data", "repos"), Path.of("data", "output"), +// Path.of("data", "demo-dataset.md")), +// (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path, experiment), 20, +// 1)); +// } catch (Exception e) { +// e.printStackTrace(); +// } try { // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Add.cpp", "exampleA2Add.cpp"), Patching.parseVariationTreeFromFile("exampleBAdd.cpp"), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Rem.cpp", "exampleA2Rem.cpp"), Patching.parseVariationTreeFromFile("exampleBRem.cpp"), true, true); -// Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), -// Patching.parseVariationTreeFromFile("exampleBRemAdd.cpp"), true, true); - + Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), + Patching.parseVariationTreeFromFile("exampleA1RemAdd.cpp"), true, true); +// Patching.patchVariationTrees(Patching.parseVariationDiffFromFile("exampleCompareAncestors.diff"), Patching.parseVariationTreeFromFile("exampleCompareAncestorsB.cpp"), true, false); // VariationTree patchedVariant = patchVariationTrees( // parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 58b383b03..02e528996 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -36,7 +36,9 @@ public class Patching { public static boolean hasSameLabel(DiffNode a, DiffNode b) { - return a.getLabel().toString().equals(b.getLabel().toString()); + String labelA = a.getLabel().toString().replaceAll(" ", ""); + String labelB = b.getLabel().toString().replaceAll(" ", ""); + return labelA.equals(labelB); } public static boolean isSameAs(VariationDiff diff1, VariationDiff diff2) { @@ -265,7 +267,8 @@ private static ArrayList> getChildrenFromListIfIndexInR return children; } - private static boolean compareAncestors(DiffNode node1, DiffNode node2, Time time) { + private static boolean compareAncestors(DiffNode node1, DiffNode node2, Time time, + boolean debug) { if (node1.getParent(time) == null && node2.getParent(time) == null) return true; if (node1.getParent(time) != null && node2.getParent(time) == null) @@ -274,22 +277,58 @@ private static boolean compareAncestors(DiffNode node1, DiffNode return false; List> siblingsNode1 = node1.getParent(time).getChildOrder(time); List> siblingsNode2 = node2.getParent(time).getChildOrder(time); + + if (debug) { + System.out.println("CA1: " + siblingsNode1); + System.out.println("CA2: " + siblingsNode2); + } + int indexNode1 = siblingsNode1.indexOf(node1); int indexNode2 = siblingsNode2.indexOf(node2); if (indexNode1 != indexNode2) { return false; } + int index2 = 0; for (int i = 0; i < siblingsNode1.size(); i++) { - if (!hasSameLabel(siblingsNode1.get(i), siblingsNode2.get(i))) { + if (i > indexNode1 && siblingsNode1.get(i).getDiffType() == DiffType.ADD) { + continue; + } +// if (i > index2 && siblingsNode2.get(index2).getDiffType() == DiffType.REM) + if (!hasSameLabel(siblingsNode1.get(i), siblingsNode2.get(index2))) { + System.out.println(siblingsNode1.get(i).getLabel().toString()); return false; } + index2++; } - return compareAncestors(node1.getParent(time), node2.getParent(time), time); + return compareAncestors(node1.getParent(time), node2.getParent(time), time, debug); } private static boolean checkNeighborsLabels(DiffNode root, DiffNode targetNodeInPatch, Set deselectedFeatures, Time time, boolean debug) { - return compareAncestors(targetNodeInPatch, root.getParent(time), time); + if (root.getParent(time) == null && targetNodeInPatch == null) { + return true; + } + if((root.getParent(time) != null && targetNodeInPatch == null) || (root.getParent(time) == null && targetNodeInPatch != null)) { + return false; + } + return compareAncestors(root.getParent(time), targetNodeInPatch, time, debug); + } + + private static boolean checkNeighbors2(DiffNode root, DiffNode targetNodeInPatch, + DiffNode node, Time time, boolean debug) { + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + int indexTarget = orderedChildrenTarget.indexOf(node); + int indexSource = orderedChildrenSource.indexOf(root); + if (indexSource != indexTarget) { + return false; + } + for (int i = 0; i < orderedChildrenSource.size(); i++) { + if (!hasSameLabel(orderedChildrenSource.get(i), orderedChildrenTarget.get(i))) { + return false; + } + } + return true; } private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, @@ -403,6 +442,30 @@ private static boolean isAlignmentProblem(List> subList return isAlignmentProblem; } + private static int findInsertPosition2(DiffNode root, DiffNode targetNodeInPatch, + Time time, boolean debug) throws Exception { + List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + List> orderedChildrenSource = root.getParent(time).getChildOrder(time); + Set ignoreIndexesFromSourceSet = new HashSet(); + int indexSource = orderedChildrenSource.indexOf(root); + for (int i = indexSource; i < orderedChildrenSource.size(); i++) { + if (orderedChildrenSource.get(i).getDiffType() == DiffType.ADD) { + ignoreIndexesFromSourceSet.add(i); + } + } + int indexTarget = 0; + for (int i = 0; i < orderedChildrenSource.size(); i++) { + if (ignoreIndexesFromSourceSet.contains(i) || indexSource == i) { + continue; + } + if (!hasSameLabel(orderedChildrenSource.get(i), orderedChildrenTarget.get(indexTarget))) { + throw new Exception("Reject: inserting"); + } + indexTarget++; + } + return indexSource; + } + private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, Set deselectedFeatures, Time time, boolean debug) throws Exception { @@ -511,15 +574,15 @@ private static int findInsertPosition(DiffNode root, DiffNode> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore, + List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore - 1, orderedChildrenTarget.size()); if (debug) System.out.println(orderedChildrenTargetSubList); if (orderedChildrenTargetSubList.size() > 1) { if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { if (debug) - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + indexBefore + " to " - + (orderedChildrenTarget.size() - 1)); + System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore - 1) + + " to " + (orderedChildrenTarget.size() - 1)); } else { throw new Exception("Reject"); } @@ -571,19 +634,19 @@ private static void applyChanges(DiffType type, VariationDiff ta } List> targetNodes = new ArrayList>(); - if (root.isArtifact()) { - targetNodes = targetVariantDiffUnchanged.computeAllNodesThat( - node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) - && node.isAnnotation()); - } else if (root.isAnnotation()) { +// if (root.isArtifact()) { +// targetNodes = targetVariantDiffUnchanged.computeAllNodesThat( +// node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) +// && node.isAnnotation()); +// } else if (root.isAnnotation()) { targetNodes = targetVariantDiffUnchanged .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); - } +// } List> targetNodes2 = new ArrayList>(); targetNodes2 = targetNodes.stream() - .filter(targetNode -> checkNeighborsLabels(root, targetNode, deselectedFeatures, time, debug)) + .filter(targetNode -> checkNeighborsLabels(root, targetVariantDiffPatched.getNodeWithID(targetNode.getID()), deselectedFeatures, time, debug)) .toList(); if (targetNodes2.size() != 1) { throw new Exception("too much or too less target nodes after filtering: " + targetNodes2.size() + "/" @@ -598,31 +661,27 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { - int insertPosition = findInsertPosition(root, targetNodeInPatch, deselectedFeatures, time, debug); + int insertPosition = findInsertPosition2(root, targetNodeInPatch, time, debug); if (insertPosition < 0) { if (debug) System.out.println("no matching insert position found"); } if (debug) System.out.println("subtree added"); - targetNodeInPatch.insertChild(root.deepCopy(), - findInsertPosition(root, targetNode, deselectedFeatures, time, debug), time); + targetNodeInPatch.insertChild(root.deepCopy(), insertPosition, time); if (debug) System.out.println(targetNode.getChildOrder(time)); } else if (type == DiffType.REM) { List> nodesToRem = new ArrayList>(); + List> nodesToRem2 = new ArrayList>(); targetNodeInPatch.getAllChildrenStream().forEach(node -> { - try { - if (Patching.isSameAs(node, root) -// && checkNeighbors(root, targetNodeInPatch, node, deselectedFeatures, time, debug) - ) - nodesToRem.add(node); - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); + + if (Patching.hasSameLabel(node, root)) { + nodesToRem2.add(node); } }); + nodesToRem = nodesToRem2.stream().filter(node -> checkNeighbors2(root, targetNodeInPatch, node, time, debug)).toList(); if (debug) System.out.println("Nodes to remove: " + nodesToRem); @@ -631,7 +690,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println("too much or too less target nodes found"); if (debug) System.out.println(nodesToRem.toString()); - } + } if (debug) System.out.println("subtree removed"); removeNode(nodesToRem.get(0)); From a7c66720fd95e20bcbb70a347c3327e9852117e7 Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 24 Aug 2025 22:14:18 +0200 Subject: [PATCH 042/162] simplified and fixed bugs --- .../variation/diff/patching/Patching.java | 72 ++++++++++--------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 02e528996..bbb40aa08 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -314,21 +314,28 @@ private static boolean checkNeighborsLabels(DiffNode root, return compareAncestors(root.getParent(time), targetNodeInPatch, time, debug); } - private static boolean checkNeighbors2(DiffNode root, DiffNode targetNodeInPatch, - DiffNode node, Time time, boolean debug) { + private static DiffNode checkNeighbors2(DiffNode root, DiffNode targetNodeInPatch, Time time, boolean debug) throws Exception { List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - int indexTarget = orderedChildrenTarget.indexOf(node); int indexSource = orderedChildrenSource.indexOf(root); - if (indexSource != indexTarget) { - return false; - } - for (int i = 0; i < orderedChildrenSource.size(); i++) { - if (!hasSameLabel(orderedChildrenSource.get(i), orderedChildrenTarget.get(i))) { - return false; + List> candidates = new ArrayList<>(); + for (DiffNode node : orderedChildrenTarget) { + int indexTarget = orderedChildrenTarget.indexOf(node); + + if (indexSource != indexTarget) { + continue; + } + for (int i = 0; i < orderedChildrenSource.size(); i++) { + if (!hasSameLabel(orderedChildrenSource.get(i), orderedChildrenTarget.get(i))) { + break; + } } + candidates.add(node); } - return true; + if (candidates.size() != 1) { + throw new Exception("Reject: too many nodes to remove"); + } + return candidates.get(0); } private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, @@ -446,16 +453,10 @@ private static int findInsertPosition2(DiffNode root, DiffNode> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - Set ignoreIndexesFromSourceSet = new HashSet(); int indexSource = orderedChildrenSource.indexOf(root); - for (int i = indexSource; i < orderedChildrenSource.size(); i++) { - if (orderedChildrenSource.get(i).getDiffType() == DiffType.ADD) { - ignoreIndexesFromSourceSet.add(i); - } - } int indexTarget = 0; for (int i = 0; i < orderedChildrenSource.size(); i++) { - if (ignoreIndexesFromSourceSet.contains(i) || indexSource == i) { + if (i >= indexSource && orderedChildrenSource.get(i).getDiffType() == DiffType.ADD) { continue; } if (!hasSameLabel(orderedChildrenSource.get(i), orderedChildrenTarget.get(indexTarget))) { @@ -660,7 +661,9 @@ private static void applyChanges(DiffType type, VariationDiff ta if (debug) System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { - + if (debug) { + GameEngine.showAndAwaitAll(Show.tree(targetVariantDiffPatched.project(Time.AFTER))); + } int insertPosition = findInsertPosition2(root, targetNodeInPatch, time, debug); if (insertPosition < 0) { if (debug) @@ -673,27 +676,27 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println(targetNode.getChildOrder(time)); } else if (type == DiffType.REM) { - List> nodesToRem = new ArrayList>(); - List> nodesToRem2 = new ArrayList>(); - targetNodeInPatch.getAllChildrenStream().forEach(node -> { - - if (Patching.hasSameLabel(node, root)) { - nodesToRem2.add(node); - } - }); - nodesToRem = nodesToRem2.stream().filter(node -> checkNeighbors2(root, targetNodeInPatch, node, time, debug)).toList(); +// List> nodesToRem = new ArrayList>(); +// List> nodesToRem2 = new ArrayList>(); +// targetNodeInPatch.getAllChildrenStream().forEach(node -> { +// +// if (Patching.hasSameLabel(node, root)) { +// nodesToRem2.add(node); +// } +// }); + DiffNode nodesToRem = checkNeighbors2(root, targetNodeInPatch, time, debug); if (debug) System.out.println("Nodes to remove: " + nodesToRem); - if (nodesToRem.size() != 1) { - if (debug) - System.out.println("too much or too less target nodes found"); - if (debug) - System.out.println(nodesToRem.toString()); - } +// if (nodesToRem.size() != 1) { +// if (debug) +// System.out.println("too much or too less target nodes found"); +// if (debug) +// System.out.println(nodesToRem.toString()); +// } if (debug) System.out.println("subtree removed"); - removeNode(nodesToRem.get(0)); + removeNode(nodesToRem); if (debug) System.out.println(targetNode.getChildOrder(Time.AFTER)); } @@ -757,6 +760,7 @@ public static VariationDiff patchVariationTrees(VariationDiff optimizedDiff = DiffView.optimized(diff, rho); if (debug) { GameEngine.showAndAwaitAll(Show.diff(diff), Show.diff(optimizedDiff)); + GameEngine.showAndAwaitAll(Show.tree(optimizedDiff.project(Time.AFTER))); } // VariationDiff optimizedDiff = diff.deepCopy(); VariationDiffSource source = optimizedDiff.getSource(); From 580a77781f20cdaab29f07c92cf1b2c88963c2f7 Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 23 Sep 2025 17:26:54 +0200 Subject: [PATCH 043/162] fixed bugs for incorrect patched variation trees (new features were missing) --- .../variation/diff/patching/Patching.java | 79 +++++++++---------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index bbb40aa08..198b7bda0 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -155,55 +155,59 @@ private static Set calculateFeatureSetToDeselectFromTrees(VariationTree< return calculateSetMinusOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); } + + /** + * Adds a feature to the feature map, if it is not contained in the map or the diffType is different from the value in the map. + * If the diffTypes are different, then DiffType NON is written in the map as the value. + * @param featureMap the map has all features of the variant1 as keys and saves if the feature is only occurring in added lines, and therefore a new feature. + * @param feature the current feature to put in the map + * @param diffType the diffType of the node + */ + private static void addFeatureToFeatureMap(Map featureMap, String feature, DiffType diffType) { + if (featureMap.containsKey(feature)) { + if (!diffType.equals(featureMap.get(feature))) { + featureMap.replace(feature, DiffType.NON); + } + } else { + featureMap.put(feature, diffType); + } + } private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diff, VariationTree variant2, boolean debug, boolean patchNewFeatures) { + // HashMap of Features which only occur in the revision of Variant1 (new features) -> DiffType is ADD Map featuresMapV1 = new HashMap(); + // HashSet of Feature Names of Variant1 Set featuresV1 = new HashSet(); + // Collect all features of the conditional annotation nodes of variant1 diff.forAll(node -> { - if (debug && node.getDiffType() == DiffType.NON) { - System.out.println("NON features:" + node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures()); - } - if (node.getDiffType().existsAtTime(Time.BEFORE)) { + + if (node.isConditionalAnnotation() && node.getDiffType().existsAtTime(Time.BEFORE)) { node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures().forEach(feature -> { - if (featuresMapV1.containsKey(feature) && node.getDiffType() != featuresMapV1.get(feature)) { - featuresMapV1.replace(feature, DiffType.NON); - } else { - featuresMapV1.put(feature, node.getDiffType()); - } + Patching.addFeatureToFeatureMap(featuresMapV1, feature, node.getDiffType()); }); } - if (node.getDiffType().existsAtTime(Time.AFTER)) { + if (node.isConditionalAnnotation() && node.getDiffType().existsAtTime(Time.AFTER)) { node.getFeatureMapping(Time.AFTER).getUniqueContainedFeatures().forEach(feature -> { - if (featuresMapV1.containsKey(feature)) { - if (!node.getDiffType().equals(featuresMapV1.get(feature))) { - if (debug) { - System.out.println(feature + ": " + node.getDiffType()); - System.out.println(feature + ": " + featuresMapV1.get(feature)); - } - featuresMapV1.replace(feature, DiffType.NON); - } - } else { - if (debug) { - System.out.println(feature + ": " + node.getDiffType()); - } - featuresMapV1.put(feature, node.getDiffType()); - } + Patching.addFeatureToFeatureMap(featuresMapV1, feature, node.getDiffType()); }); } }); - - featuresMapV1.forEach((feature, diffType) -> { - featuresV1.add(feature); - }); - + featuresV1 = featuresMapV1.keySet(); + + // Collect all features of the conditional annotation nodes of variant2 Set featuresV2 = new HashSet(); variant2.forAllPreorder(node -> { - featuresV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + if (node.isConditionalAnnotation()) { + featuresV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); + } }); - + + // Calculate the features which are not in both variants + Set features = calculateSetMinusOfFeatureSets(featuresV1, featuresV2, debug); + + // If new features should be patched, then remove new features from the deselected features if they only occur as ADD in the diff if (patchNewFeatures) { - Set features = calculateSetMinusOfFeatureSets(featuresV1, featuresV2, debug); featuresMapV1.forEach((feature, diffType) -> { if (diffType == DiffType.ADD) { if (features.contains(feature)) { @@ -211,16 +215,9 @@ private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diffVariant1, @@ -747,7 +744,7 @@ public static VariationDiff patchVariationTrees(VariationDiff deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, debug, patchNewFeatures); - if (!deselectedFeatures.isEmpty()) { + if (debug) { System.out.println(deselectedFeatures); } Relevance rho = calculateFormulaForDeselection(deselectedFeatures, debug); From aa4c8f09b7b73f175c6453fbe6d8b0a60346f215 Mon Sep 17 00:00:00 2001 From: piameier Date: Wed, 24 Sep 2025 21:07:55 +0200 Subject: [PATCH 044/162] update patching experiment, possibility to write patch out to file --- .../thesis_pm/PatchingExperiment.java | 78 +++++++++++++++---- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index d097a6a4c..c2ed8d894 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -1,7 +1,11 @@ package org.variantsync.diffdetective.experiments.thesis_pm; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.nio.file.Path; +import java.nio.file.Paths; import org.variantsync.diffdetective.AnalysisRunner; import org.variantsync.diffdetective.variation.DiffLinesLabel; @@ -13,11 +17,13 @@ import org.tinylog.Logger; import org.variantsync.diffdetective.analysis.*; +import org.variantsync.diffdetective.datasets.PatchDiffParseOptions; import org.variantsync.diffdetective.datasets.Repository; import org.variantsync.diffdetective.show.Show; import org.variantsync.diffdetective.show.engine.GameEngine; import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; +import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; public class PatchingExperiment implements Analysis.Hooks { @@ -80,18 +86,29 @@ public boolean beginCommit(Analysis analysis) throws Exception { @Override public boolean analyzeVariationDiff(Analysis analysis) throws Exception { VariationDiff diff = analysis.getCurrentVariationDiff(); + VariationTree before = diff.project(Time.BEFORE).deepCopy(); VariationTree after = diff.project(Time.AFTER).deepCopy(); try { VariationDiff patchedVariant = Patching.patchVariationTrees(diff, before, false, true); if (!Patching.comparePatchedVariantWithExpectedResult(patchedVariant.project(Time.AFTER), after)) { + try { + File f = new File(Path.of("data", "examples", "file3.diff").toUri()); + f.createNewFile(); + BufferedWriter myWriter = new BufferedWriter(new FileWriter(f)); + myWriter.write(analysis.getCurrentPatch().getDiff()); + myWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } analysis.get(INCORRECTLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; VariationDiff diffCopy = diff.deepCopy(); VariationDiff patchedCopy = patchedVariant.deepCopy(); CutNonEditedSubtrees.genericTransform(diffCopy); CutNonEditedSubtrees.genericTransform(patchedCopy); GameEngine.showAndAwaitAll(Show.diff(diffCopy), Show.diff(patchedCopy)); + // if (firstDiff) { // Patching.patchVariationTrees(diff, before, true, true); // wait(60000); @@ -103,6 +120,16 @@ public boolean analyzeVariationDiff(Analysis analysis) throws Exception { } } catch (Exception e) { e.printStackTrace(); +// try { +// File f = new File(Path.of("data", "examples", "file3.diff").toUri()); +// f.createNewFile(); +// BufferedWriter myWriter = new BufferedWriter(new FileWriter(f)); +// myWriter.write(analysis.getCurrentPatch().getDiff()); +// myWriter.close(); +// } catch (IOException i) { +// i.printStackTrace(); +// } +// throw new Exception("break"); analysis.get(REJECTED_PATCHES_COUNTER_RESULT_KEY).value++; } return true; @@ -121,35 +148,54 @@ experiment, new StatisticsAnalysis() } public static void main(String[] args) { -// PatchingExperiment experiment = new PatchingExperiment(); -// try { -// AnalysisRunner.run( -// new AnalysisRunner.Options(Path.of("data", "repos"), Path.of("data", "output"), -// Path.of("data", "demo-dataset.md")), -// (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path, experiment), 20, -// 1)); -// } catch (Exception e) { -// e.printStackTrace(); -// } + PatchingExperiment experiment = new PatchingExperiment(); + final AnalysisRunner.Options defaultOptions = AnalysisRunner.Options.DEFAULT(args); + final AnalysisRunner.Options analysisOptions = new AnalysisRunner.Options( + Path.of("data", "repos"), + Path.of("data", "output"), + Path.of("data", "demo-dataset.md"), + repo -> new PatchDiffParseOptions( + PatchDiffParseOptions.DiffStoragePolicy.REMEMBER_FULL_DIFF, + new VariationDiffParseOptions( + true, + false + ) + ), + defaultOptions.getFilterForRepo(), + true, + false + ); try { + AnalysisRunner.run(analysisOptions + , + (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path, experiment), 500, + 8)); + } catch (Exception e) { + e.printStackTrace(); + } + try { +// exampleA2NodesWith2Parents.cpp +// Patching.patchVariationTrees(Patching.parseVariationDiffFromFile("file3.diff"), Patching.parseVariationDiffFromFile("file3.diff").project(Time.BEFORE), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Add.cpp", "exampleA2Add.cpp"), Patching.parseVariationTreeFromFile("exampleBAdd.cpp"), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Rem.cpp", "exampleA2Rem.cpp"), Patching.parseVariationTreeFromFile("exampleBRem.cpp"), true, true); - Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), - Patching.parseVariationTreeFromFile("exampleA1RemAdd.cpp"), true, true); +// Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), +// Patching.parseVariationTreeFromFile("exampleA1RemAdd.cpp"), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFile("exampleCompareAncestors.diff"), Patching.parseVariationTreeFromFile("exampleCompareAncestorsB.cpp"), true, false); // VariationTree patchedVariant = patchVariationTrees( // parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), // parseVariationTreeFromFile("exampleBRemAdd.cpp")); // VariationTree expectedResult = parseVariationTreeFromFile("exampleBRemAddExpected.cpp"); // System.out.println(comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); - -// VariationTree patchedVariant = Patching.patchVariationTrees( +// GameEngine.showAndAwaitAll(Show.diff(Patching.parseVariationDiffFromFile("presentationExample.diff"))); +// +// VariationDiff patchedVariant = Patching.patchVariationTrees( // Patching.parseVariationDiffFromFiles("exampleA1NodesWith2Parents.cpp", // "exampleA2NodesWith2Parents.cpp"), -// Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp"), true); +// Patching.parseVariationTreeFromFile("exampleA1NodesWith2Parents.cpp"), true, true); // VariationTree expectedResult = Patching // .parseVariationTreeFromFile("exampleA2NodesWith2Parents.cpp"); -// GameEngine.showAndAwaitAll(Show.tree(patchedVariant), Show.tree(expectedResult)); +// GameEngine.showAndAwaitAll(Show.tree(patchedVariant.project(Time.AFTER)), Show.tree(expectedResult)); + // System.out.println(Patching.comparePatchedVariantWithExpectedResult(patchedVariant, expectedResult)); // VariationDiff patchedVariant = Patching.patchVariationTrees( // Patching.parseVariationDiffFromFile("example1.diff"), From b1c149e877bba4bc3ebd69343369f01c92378812 Mon Sep 17 00:00:00 2001 From: piameier Date: Wed, 24 Sep 2025 21:10:32 +0200 Subject: [PATCH 045/162] fixed bugs: rejected insert due to unmodified nodes with two parents (different parent before and after the change) --- .../variation/diff/patching/Patching.java | 89 ++++++++++++------- 1 file changed, 57 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 198b7bda0..6d9e5cc7a 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -14,6 +14,7 @@ import java.util.stream.Collectors; import org.eclipse.jgit.diff.DiffAlgorithm; +import org.prop4j.Node; import org.variantsync.diffdetective.diff.result.DiffParseException; import org.variantsync.diffdetective.show.Show; import org.variantsync.diffdetective.show.engine.GameEngine; @@ -155,13 +156,17 @@ private static Set calculateFeatureSetToDeselectFromTrees(VariationTree< return calculateSetMinusOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); } - + /** - * Adds a feature to the feature map, if it is not contained in the map or the diffType is different from the value in the map. - * If the diffTypes are different, then DiffType NON is written in the map as the value. - * @param featureMap the map has all features of the variant1 as keys and saves if the feature is only occurring in added lines, and therefore a new feature. - * @param feature the current feature to put in the map - * @param diffType the diffType of the node + * Adds a feature to the feature map, if it is not contained in the map or the + * diffType is different from the value in the map. If the diffTypes are + * different, then DiffType NON is written in the map as the value. + * + * @param featureMap the map has all features of the variant1 as keys and saves + * if the feature is only occurring in added lines, and + * therefore a new feature. + * @param feature the current feature to put in the map + * @param diffType the diffType of the node */ private static void addFeatureToFeatureMap(Map featureMap, String feature, DiffType diffType) { if (featureMap.containsKey(feature)) { @@ -175,13 +180,14 @@ private static void addFeatureToFeatureMap(Map featureMap, Str private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff diff, VariationTree variant2, boolean debug, boolean patchNewFeatures) { - // HashMap of Features which only occur in the revision of Variant1 (new features) -> DiffType is ADD + // HashMap of Features which only occur in the revision of Variant1 (new + // features) -> DiffType is ADD Map featuresMapV1 = new HashMap(); // HashSet of Feature Names of Variant1 Set featuresV1 = new HashSet(); // Collect all features of the conditional annotation nodes of variant1 diff.forAll(node -> { - + if (node.isConditionalAnnotation() && node.getDiffType().existsAtTime(Time.BEFORE)) { node.getFeatureMapping(Time.BEFORE).getUniqueContainedFeatures().forEach(feature -> { Patching.addFeatureToFeatureMap(featuresMapV1, feature, node.getDiffType()); @@ -194,7 +200,7 @@ private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff featuresV2 = new HashSet(); variant2.forAllPreorder(node -> { @@ -202,11 +208,12 @@ private static Set calculateFeatureSetToDeselectFromDiff(VariationDiff features = calculateSetMinusOfFeatureSets(featuresV1, featuresV2, debug); - - // If new features should be patched, then remove new features from the deselected features if they only occur as ADD in the diff + + // If new features should be patched, then remove new features from the + // deselected features if they only occur as ADD in the diff if (patchNewFeatures) { featuresMapV1.forEach((feature, diffType) -> { if (diffType == DiffType.ADD) { @@ -292,7 +299,7 @@ private static boolean compareAncestors(DiffNode node1, DiffNode } // if (i > index2 && siblingsNode2.get(index2).getDiffType() == DiffType.REM) if (!hasSameLabel(siblingsNode1.get(i), siblingsNode2.get(index2))) { - System.out.println(siblingsNode1.get(i).getLabel().toString()); +// System.out.println(siblingsNode1.get(i).getLabel().toString()); return false; } index2++; @@ -305,20 +312,22 @@ private static boolean checkNeighborsLabels(DiffNode root, if (root.getParent(time) == null && targetNodeInPatch == null) { return true; } - if((root.getParent(time) != null && targetNodeInPatch == null) || (root.getParent(time) == null && targetNodeInPatch != null)) { + if ((root.getParent(time) != null && targetNodeInPatch == null) + || (root.getParent(time) == null && targetNodeInPatch != null)) { return false; } return compareAncestors(root.getParent(time), targetNodeInPatch, time, debug); } - private static DiffNode checkNeighbors2(DiffNode root, DiffNode targetNodeInPatch, Time time, boolean debug) throws Exception { + private static DiffNode checkNeighbors2(DiffNode root, + DiffNode targetNodeInPatch, Time time, boolean debug) throws Exception { List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); int indexSource = orderedChildrenSource.indexOf(root); List> candidates = new ArrayList<>(); for (DiffNode node : orderedChildrenTarget) { int indexTarget = orderedChildrenTarget.indexOf(node); - + if (indexSource != indexTarget) { continue; } @@ -632,19 +641,18 @@ private static void applyChanges(DiffType type, VariationDiff ta } List> targetNodes = new ArrayList>(); -// if (root.isArtifact()) { -// targetNodes = targetVariantDiffUnchanged.computeAllNodesThat( -// node -> node.getPresenceCondition(Time.AFTER).equals(root.getPresenceCondition(time)) -// && node.isAnnotation()); -// } else if (root.isAnnotation()) { - targetNodes = targetVariantDiffUnchanged - .computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(root.getParent(time).getPresenceCondition(time)) && node.isAnnotation()); -// } + if (root.getParent(time).getDiffType().existsAtTime(time)) { + final Node presenceCondition = root.getParent(time).getPresenceCondition(time); + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) + .equals(presenceCondition) && node.isAnnotation()); + } + List> targetNodes2 = new ArrayList>(); targetNodes2 = targetNodes.stream() - .filter(targetNode -> checkNeighborsLabels(root, targetVariantDiffPatched.getNodeWithID(targetNode.getID()), deselectedFeatures, time, debug)) + .filter(targetNode -> checkNeighborsLabels(root, + targetVariantDiffPatched.getNodeWithID(targetNode.getID()), deselectedFeatures, time, + debug)) .toList(); if (targetNodes2.size() != 1) { throw new Exception("too much or too less target nodes after filtering: " + targetNodes2.size() + "/" @@ -754,12 +762,13 @@ public static VariationDiff patchVariationTrees(VariationDiff optimizedDiff = DiffView.optimized(diff, rho); +// VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + VariationDiff optimizedDiff = diff.deepCopy(); if (debug) { GameEngine.showAndAwaitAll(Show.diff(diff), Show.diff(optimizedDiff)); GameEngine.showAndAwaitAll(Show.tree(optimizedDiff.project(Time.AFTER))); } -// VariationDiff optimizedDiff = diff.deepCopy(); + VariationDiffSource source = optimizedDiff.getSource(); VariationDiff targetVariantDiffUnchanged = targetVariant.deepCopy() .toCompletelyUnchangedVariationDiff(); @@ -769,14 +778,30 @@ public static VariationDiff patchVariationTrees(VariationDiff> removedNodes = new HashSet>(); Set> addedNodes = new HashSet>(); - // find nodes with DiffType NON but changed parents + // resolve nodes with two parents to two nodes, one added, one removed + VariationDiff diffCopy = optimizedDiff.deepCopy(); optimizedDiff.forAll(node -> { if (node.isNon() && node.getParent(Time.BEFORE) != node.getParent(Time.AFTER)) { - removedNodes.add(node); - addedNodes.add(node); + DiffNode matchingNode = diffCopy.getNodeWithID(node.getID()); + DiffNode parentAfter = matchingNode.getParent(Time.AFTER); + DiffNode parentBefore = matchingNode.getParent(Time.BEFORE); + int indexAfter = parentAfter.getChildOrder(Time.AFTER).indexOf(matchingNode); + int indexBefore = parentBefore.getChildOrder(Time.BEFORE).indexOf(matchingNode); + matchingNode.drop(Time.AFTER); + matchingNode.drop(Time.BEFORE); + DiffNode nodeAfter = matchingNode.deepCopy(); + nodeAfter.diffType = DiffType.ADD; + DiffNode nodeBefore = matchingNode.deepCopy(); + nodeBefore.diffType = DiffType.REM; + parentAfter.insertChild(nodeAfter, indexAfter, Time.AFTER); + parentBefore.insertChild(nodeBefore, indexBefore, Time.BEFORE); } }); - + if (debug) { + GameEngine.showAndAwaitAll(Show.diff(optimizedDiff), Show.diff(diffCopy)); + } + optimizedDiff = diffCopy; + // remove old nodes optimizedDiff.forAll(node -> { if (node.isRem()) { From 4bd5546a900606a1f3ff6dbfd4d8e36f0d2095d4 Mon Sep 17 00:00:00 2001 From: piameier Date: Thu, 25 Sep 2025 15:51:47 +0200 Subject: [PATCH 046/162] fixed bug: FixTrueFalse Formula for deselecting features in view --- .../thesis_pm/PatchingExperiment.java | 18 +++++++++--------- .../variation/diff/patching/Patching.java | 15 ++++++++++----- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index c2ed8d894..e7fb10c01 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -165,17 +165,17 @@ public static void main(String[] args) { true, false ); - try { - AnalysisRunner.run(analysisOptions - , - (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path, experiment), 500, - 8)); - } catch (Exception e) { - e.printStackTrace(); - } +// try { +// AnalysisRunner.run(analysisOptions +// , +// (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path, experiment), 500, +// 8)); +// } catch (Exception e) { +// e.printStackTrace(); +// } try { // exampleA2NodesWith2Parents.cpp -// Patching.patchVariationTrees(Patching.parseVariationDiffFromFile("file3.diff"), Patching.parseVariationDiffFromFile("file3.diff").project(Time.BEFORE), true, true); + Patching.patchVariationTrees(Patching.parseVariationDiffFromFile("file2.diff"), Patching.parseVariationDiffFromFile("file1.diff").project(Time.BEFORE), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Add.cpp", "exampleA2Add.cpp"), Patching.parseVariationTreeFromFile("exampleBAdd.cpp"), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Rem.cpp", "exampleA2Rem.cpp"), Patching.parseVariationTreeFromFile("exampleBRem.cpp"), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 6d9e5cc7a..a4ca5c47d 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -14,11 +14,14 @@ import java.util.stream.Collectors; import org.eclipse.jgit.diff.DiffAlgorithm; +import org.prop4j.And; +import org.prop4j.Literal; import org.prop4j.Node; import org.variantsync.diffdetective.diff.result.DiffParseException; import org.variantsync.diffdetective.show.Show; import org.variantsync.diffdetective.show.engine.GameEngine; import org.variantsync.diffdetective.util.fide.FixTrueFalse.Formula; +import org.variantsync.diffdetective.util.fide.FormulaUtils; import org.variantsync.diffdetective.variation.DiffLinesLabel; import org.variantsync.diffdetective.variation.Label; import org.variantsync.diffdetective.variation.diff.DiffNode; @@ -123,16 +126,18 @@ private static Set calculateSetMinusOfFeatureSets(Set featureSet } private static Relevance calculateFormulaForDeselection(Set set, boolean debug) { - - Formula[] f = new Formula[set.size()]; + + Node[] f = new Node[set.size()]; +// Formula[] f = new Formula[set.size()]; Iterator iterator = set.iterator(); for (int i = 0; i < f.length; i++) { - f[i] = Formula.not(Formula.var(iterator.next())); +// f[i] = Formula.not(Formula.var(iterator.next())); + f[i] = new Literal(iterator.next(), false); } - Formula formula = Formula.and(f); + Node formula = new And(f); if (debug) { - System.out.println(formula.get().toString()); + System.out.println(formula); } return new Configure(formula); From 77b2d6a763f921ab210417bb187571fa3d76edb4 Mon Sep 17 00:00:00 2001 From: piameier Date: Tue, 30 Sep 2025 20:16:20 +0200 Subject: [PATCH 047/162] fixed bug in resolve() --- .../variation/diff/patching/Patching.java | 118 ++++++++++++++---- 1 file changed, 91 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index a4ca5c47d..912516d22 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -36,6 +36,7 @@ import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; +import com.github.gumtreediff.actions.Diff; import com.ibm.icu.impl.CalendarUtil; public class Patching { @@ -126,12 +127,10 @@ private static Set calculateSetMinusOfFeatureSets(Set featureSet } private static Relevance calculateFormulaForDeselection(Set set, boolean debug) { - + Node[] f = new Node[set.size()]; -// Formula[] f = new Formula[set.size()]; Iterator iterator = set.iterator(); for (int i = 0; i < f.length; i++) { -// f[i] = Formula.not(Formula.var(iterator.next())); f[i] = new Literal(iterator.next(), false); } Node formula = new And(f); @@ -638,21 +637,21 @@ private static void applyChanges(DiffType type, VariationDiff ta Time time = (type == DiffType.ADD) ? Time.AFTER : Time.BEFORE; for (DiffNode root : subtreeRoots) { - if (debug) { - DiffNode newRoot = DiffNode.createRoot(new DiffLinesLabel()); - newRoot.addChild(root.deepCopy(), time); - VariationDiff subTree = new VariationDiff(newRoot, source); - GameEngine.showAndAwaitAll(Show.diff(subTree)); - } +// if (debug) { +// DiffNode newRoot = DiffNode.createRoot(new DiffLinesLabel()); +// newRoot.addChild(root.deepCopy(), time); +// VariationDiff subTree = new VariationDiff(newRoot, source); +// GameEngine.showAndAwaitAll(Show.diff(subTree)); +// } List> targetNodes = new ArrayList>(); if (root.getParent(time).getDiffType().existsAtTime(time)) { final Node presenceCondition = root.getParent(time).getPresenceCondition(time); - targetNodes = targetVariantDiffUnchanged.computeAllNodesThat(node -> node.getPresenceCondition(Time.AFTER) - .equals(presenceCondition) && node.isAnnotation()); + targetNodes = targetVariantDiffUnchanged.computeAllNodesThat( + node -> node.getPresenceCondition(Time.AFTER).equals(presenceCondition) && node.isAnnotation()); } - + List> targetNodes2 = new ArrayList>(); targetNodes2 = targetNodes.stream() .filter(targetNode -> checkNeighborsLabels(root, @@ -750,6 +749,76 @@ private static VariationDiff patchVariationTrees( return patchVariationTrees(diff, targetVariant, debug, patchNewFeatures); } + public static void changeType(DiffNode node, VariationDiff modDiff, DiffType type) { + if (!node.isLeaf()) { + node.getAllChildrenStream().forEach(child -> changeType(child, modDiff, type)); + } + DiffNode matchingNode = modDiff.getNodeWithID(node.getID()); + if (matchingNode == null) { + return; + } + Time time = type == DiffType.ADD ? Time.BEFORE : Time.AFTER; + if (matchingNode.isNon()) { + matchingNode.diffType = type; + matchingNode.drop(time); + } else if (matchingNode.diffType != type) { + matchingNode.drop(); + } + } + + public static void resolve(DiffNode node, VariationDiff modDiff) { + if (!node.isLeaf()) { + node.getAllChildrenStream().forEach(child -> resolve(child, modDiff)); + } + if (node.isNon() && node.getParent(Time.BEFORE) != node.getParent(Time.AFTER)) { +// System.out.println(node.getLabel()); + DiffNode matchingNode = modDiff.getNodeWithID(node.getID()); + // matchingNode can be null because it is a child from two parents + if (matchingNode == null) { + return; + } + DiffNode parentAfter = matchingNode.getParent(Time.AFTER); + DiffNode parentBefore = matchingNode.getParent(Time.BEFORE); + int indexAfter = parentAfter.getChildOrder(Time.AFTER).indexOf(matchingNode); + int indexBefore = parentBefore.getChildOrder(Time.BEFORE).indexOf(matchingNode); + matchingNode.drop(); + DiffNode nodeAfter = matchingNode.deepCopy(); + nodeAfter.diffType = DiffType.ADD; + + DiffNode newRootAfter = DiffNode.createRoot(new DiffLinesLabel()); + newRootAfter.addChild(nodeAfter.deepCopy(), Time.AFTER); + VariationDiff subTreeAfter = new VariationDiff(newRootAfter, modDiff.getSource()); + + if (!nodeAfter.isLeaf()) { + changeType(nodeAfter, subTreeAfter, DiffType.ADD); + // remove all children with difftype REM recursively + // set recursively difftype ADD for all children which have currently difftype + // NON + } + +// GameEngine.showAndAwaitAll(Show.diff(subTreeAfter)); + + DiffNode nodeBefore = matchingNode.deepCopy(); + nodeBefore.diffType = DiffType.REM; + + DiffNode newRootBefore = DiffNode.createRoot(new DiffLinesLabel()); + newRootBefore.addChild(nodeBefore.deepCopy(), Time.BEFORE); + VariationDiff subTreeBefore = new VariationDiff(newRootBefore, modDiff.getSource()); + + if (!nodeBefore.isLeaf()) { + changeType(nodeBefore, subTreeBefore, DiffType.REM); + } + +// GameEngine.showAndAwaitAll(Show.diff(subTreeBefore)); + + parentAfter.insertChild(subTreeAfter.getRoot().getAllChildren().iterator().next(), indexAfter, Time.AFTER); + parentBefore.insertChild(subTreeBefore.getRoot().getAllChildren().iterator().next(), indexBefore, Time.BEFORE); + +// GameEngine.showAndAwaitAll(Show.diff(modDiff)); + + } + } + public static VariationDiff patchVariationTrees(VariationDiff diff, VariationTree targetVariant, boolean debug, boolean patchNewFeatures) throws Exception { @@ -768,9 +837,10 @@ public static VariationDiff patchVariationTrees(VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + VariationDiff optimizedDiff = diff.deepCopy(); if (debug) { - GameEngine.showAndAwaitAll(Show.diff(diff), Show.diff(optimizedDiff)); + GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); GameEngine.showAndAwaitAll(Show.tree(optimizedDiff.project(Time.AFTER))); } @@ -785,28 +855,22 @@ public static VariationDiff patchVariationTrees(VariationDiff diffCopy = optimizedDiff.deepCopy(); + List> nodesToResolve = new ArrayList<>(); + optimizedDiff.forAll(node -> { if (node.isNon() && node.getParent(Time.BEFORE) != node.getParent(Time.AFTER)) { DiffNode matchingNode = diffCopy.getNodeWithID(node.getID()); - DiffNode parentAfter = matchingNode.getParent(Time.AFTER); - DiffNode parentBefore = matchingNode.getParent(Time.BEFORE); - int indexAfter = parentAfter.getChildOrder(Time.AFTER).indexOf(matchingNode); - int indexBefore = parentBefore.getChildOrder(Time.BEFORE).indexOf(matchingNode); - matchingNode.drop(Time.AFTER); - matchingNode.drop(Time.BEFORE); - DiffNode nodeAfter = matchingNode.deepCopy(); - nodeAfter.diffType = DiffType.ADD; - DiffNode nodeBefore = matchingNode.deepCopy(); - nodeBefore.diffType = DiffType.REM; - parentAfter.insertChild(nodeAfter, indexAfter, Time.AFTER); - parentBefore.insertChild(nodeBefore, indexBefore, Time.BEFORE); + nodesToResolve.add(matchingNode); } }); + + resolve(optimizedDiff.getRoot(), diffCopy); + if (debug) { - GameEngine.showAndAwaitAll(Show.diff(optimizedDiff), Show.diff(diffCopy)); + GameEngine.showAndAwaitAll(Show.diff(diffCopy, "resolved")); } optimizedDiff = diffCopy; - + // remove old nodes optimizedDiff.forAll(node -> { if (node.isRem()) { From ff05f1d5fe052824e0db7863bb2a89a6044872b1 Mon Sep 17 00:00:00 2001 From: piameier Date: Sat, 4 Oct 2025 17:11:53 +0200 Subject: [PATCH 048/162] patch variants --- .../variation/diff/patching/Patching.java | 67 +++++++++++-------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 912516d22..5bce5add0 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -47,7 +47,7 @@ public static boolean hasSameLabel(DiffNode a, DiffNode } public static boolean isSameAs(VariationDiff diff1, VariationDiff diff2) { - return isSameAsWithoutLabel(diff1.getRoot(), diff2.getRoot()); + return isSameAs(diff1.getRoot(), diff2.getRoot()); } public static boolean isSameAs(DiffNode a, DiffNode b) { @@ -63,7 +63,7 @@ private static boolean isSameAs(DiffNode a, DiffNode b, return true; } - if (!(a.getNodeType().equals(b.getNodeType()) && a.getLabel().toString().equals(b.getLabel().toString()) && + if (!(a.getNodeType().equals(b.getNodeType()) && hasSameLabel(a, b) && // a.getLabel().equals(b.getLabel()) && // a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && // a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && @@ -312,7 +312,7 @@ private static boolean compareAncestors(DiffNode node1, DiffNode } private static boolean checkNeighborsLabels(DiffNode root, - DiffNode targetNodeInPatch, Set deselectedFeatures, Time time, boolean debug) { + DiffNode targetNodeInPatch, Time time, boolean debug) { if (root.getParent(time) == null && targetNodeInPatch == null) { return true; } @@ -460,21 +460,32 @@ private static boolean isAlignmentProblem(List> subList } private static int findInsertPosition2(DiffNode root, DiffNode targetNodeInPatch, - Time time, boolean debug) throws Exception { + DiffNode targetNodeInPatchView, Time time, boolean debug) throws Exception { List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); + List> orderedChildrenTargetView = targetNodeInPatchView.getChildOrder(time); List> orderedChildrenSource = root.getParent(time).getChildOrder(time); int indexSource = orderedChildrenSource.indexOf(root); int indexTarget = 0; + int insertPosition = indexSource; for (int i = 0; i < orderedChildrenSource.size(); i++) { - if (i >= indexSource && orderedChildrenSource.get(i).getDiffType() == DiffType.ADD) { + if (i == indexSource) { + insertPosition = indexTarget; + continue; + } + if (i > indexSource && orderedChildrenSource.get(i).getDiffType() == DiffType.ADD) { continue; } if (!hasSameLabel(orderedChildrenSource.get(i), orderedChildrenTarget.get(indexTarget))) { - throw new Exception("Reject: inserting"); + if (!hasSameLabel(orderedChildrenSource.get(i), orderedChildrenTargetView.get(indexTarget))) { + throw new Exception("Reject: inserting"); + } + while (!hasSameLabel(orderedChildrenSource.get(i), orderedChildrenTarget.get(indexTarget))) { + indexTarget++; + } } indexTarget++; } - return indexSource; + return insertPosition; } private static int findInsertPosition(DiffNode root, DiffNode targetNodeInPatch, @@ -652,28 +663,25 @@ private static void applyChanges(DiffType type, VariationDiff ta node -> node.getPresenceCondition(Time.AFTER).equals(presenceCondition) && node.isAnnotation()); } - List> targetNodes2 = new ArrayList>(); - targetNodes2 = targetNodes.stream() + VariationDiff targetVariantDiffPatchedView = DiffView.optimized(targetVariantDiffPatched.deepCopy(), calculateFormulaForDeselection(deselectedFeatures, debug)); + targetNodes = targetNodes.stream() .filter(targetNode -> checkNeighborsLabels(root, - targetVariantDiffPatched.getNodeWithID(targetNode.getID()), deselectedFeatures, time, + targetVariantDiffPatchedView.getNodeWithID(targetNode.getID()), time, debug)) .toList(); - if (targetNodes2.size() != 1) { - throw new Exception("too much or too less target nodes after filtering: " + targetNodes2.size() + "/" - + targetNodes.size()); + targetNodes = targetNodes.stream().map(targetNode -> targetVariantDiffPatched.getNodeWithID(targetNode.getID())).toList(); + if (targetNodes.size() != 1) { + throw new Exception("too much or too less target nodes after filtering: " + targetNodes.size()); } - DiffNode targetNode = targetNodes2.get(0); - if (debug) - System.out.println("targetNode:" + targetNode.toString()); - DiffNode targetNodeInPatch = targetVariantDiffPatched.getNodeWithID(targetNode.getID()); + DiffNode targetNodeInPatch = targetNodes.get(0); if (debug) System.out.println(targetNodeInPatch.toString()); if (type == DiffType.ADD) { if (debug) { GameEngine.showAndAwaitAll(Show.tree(targetVariantDiffPatched.project(Time.AFTER))); } - int insertPosition = findInsertPosition2(root, targetNodeInPatch, time, debug); + int insertPosition = findInsertPosition2(root, targetNodeInPatch, targetVariantDiffPatchedView.getNodeWithID(targetNodeInPatch.getID()), time, debug); if (insertPosition < 0) { if (debug) System.out.println("no matching insert position found"); @@ -682,7 +690,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println("subtree added"); targetNodeInPatch.insertChild(root.deepCopy(), insertPosition, time); if (debug) - System.out.println(targetNode.getChildOrder(time)); + System.out.println(targetNodeInPatch.getChildOrder(time)); } else if (type == DiffType.REM) { // List> nodesToRem = new ArrayList>(); @@ -707,7 +715,7 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println("subtree removed"); removeNode(nodesToRem); if (debug) - System.out.println(targetNode.getChildOrder(Time.AFTER)); + System.out.println(targetNodeInPatch.getChildOrder(Time.AFTER)); } if (debug) { VariationDiff targetVariantDiffPatchedCopy = targetVariantDiffPatched.deepCopy(); @@ -836,12 +844,10 @@ public static VariationDiff patchVariationTrees(VariationDiff optimizedDiff = DiffView.optimized(diff, rho); - - VariationDiff optimizedDiff = diff.deepCopy(); + VariationDiff optimizedDiff = DiffView.optimized(diff, rho); + if (debug) { - GameEngine.showAndAwaitAll(Show.diff(optimizedDiff)); - GameEngine.showAndAwaitAll(Show.tree(optimizedDiff.project(Time.AFTER))); + GameEngine.showAndAwaitAll(Show.diff(optimizedDiff), Show.tree(optimizedDiff.project(Time.AFTER))); } VariationDiffSource source = optimizedDiff.getSource(); @@ -897,10 +903,13 @@ public static VariationDiff patchVariationTrees(VariationDiff targetVariantDiffPatchedCopy = targetVariantDiffPatched.deepCopy(); VariationDiff optimizedDiffCopy = optimizedDiff.deepCopy(); From 49018ae218cbbf4a01023139ae0bce9e6e65fb6b Mon Sep 17 00:00:00 2001 From: piameier Date: Sat, 4 Oct 2025 17:24:29 +0200 Subject: [PATCH 049/162] refactoring code --- .../variation/diff/patching/Patching.java | 364 +----------------- 1 file changed, 4 insertions(+), 360 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 5bce5add0..296918226 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -8,8 +8,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -20,8 +18,6 @@ import org.variantsync.diffdetective.diff.result.DiffParseException; import org.variantsync.diffdetective.show.Show; import org.variantsync.diffdetective.show.engine.GameEngine; -import org.variantsync.diffdetective.util.fide.FixTrueFalse.Formula; -import org.variantsync.diffdetective.util.fide.FormulaUtils; import org.variantsync.diffdetective.variation.DiffLinesLabel; import org.variantsync.diffdetective.variation.Label; import org.variantsync.diffdetective.variation.diff.DiffNode; @@ -36,9 +32,6 @@ import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; -import com.github.gumtreediff.actions.Diff; -import com.ibm.icu.impl.CalendarUtil; - public class Patching { public static boolean hasSameLabel(DiffNode a, DiffNode b) { String labelA = a.getLabel().toString().replaceAll(" ", ""); @@ -54,21 +47,14 @@ public static boolean isSameAs(DiffNode a, DiffNode b) { return isSameAs(a, b, new HashSet<>()); } - public static boolean isSameAsWithoutLabel(DiffNode a, DiffNode b) { - return isSameAsWithoutLabel(a, b, new HashSet<>()); - } - private static boolean isSameAs(DiffNode a, DiffNode b, Set> visited) { if (!visited.add(a)) { return true; } if (!(a.getNodeType().equals(b.getNodeType()) && hasSameLabel(a, b) && -// a.getLabel().equals(b.getLabel()) && -// a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && -// a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && + hasSameLabel(a, b) && (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) - // && a.getLabel().getLines().equals(b.getLabel().getLines()) )) { return false; } @@ -84,33 +70,6 @@ private static boolean isSameAs(DiffNode a, DiffNode b, return aIt.hasNext() == bIt.hasNext(); } - private static boolean isSameAsWithoutLabel(DiffNode a, DiffNode b, - Set> visited) { - if (!visited.add(a)) { - return true; - } - - if (!(a.getNodeType().equals(b.getNodeType()) && -// a.getLabel().equals(b.getLabel()) && -// a.getFromLine().atTime(time) == (b.getFromLine().atTime(time)) && -// a.getToLine().atTime(time) == (b.getToLine().atTime(time)) && - (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) -// && a.getLabel().getLines().equals(b.getLabel().getLines()) - )) { - return false; - } - - Iterator> aIt = a.getAllChildren().iterator(); - Iterator> bIt = b.getAllChildren().iterator(); - while (aIt.hasNext() && bIt.hasNext()) { - if (!isSameAsWithoutLabel(aIt.next(), bIt.next(), visited)) { - return false; - } - } - - return aIt.hasNext() == bIt.hasNext(); - } - private static Set calculateSetMinusOfFeatureSets(Set featureSet1, Set featureSet2, boolean debug) { Set intersectSet1 = new HashSet<>(featureSet1); @@ -142,25 +101,6 @@ private static Relevance calculateFormulaForDeselection(Set set, boolean return new Configure(formula); } - private static Set calculateFeatureSetToDeselectFromTrees(VariationTree variant1version1, - VariationTree variant1version2, VariationTree variant2, boolean debug) { - Set featuresTreeV1 = new HashSet(); - variant1version1.forAllPreorder(node -> { - featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); - }); - if (variant1version2 != null) { - variant1version2.forAllPreorder(node -> { - featuresTreeV1.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); - }); - } - Set featuresTreeV2 = new HashSet(); - variant2.forAllPreorder(node -> { - featuresTreeV2.addAll(node.getFeatureMapping().getUniqueContainedFeatures()); - }); - - return calculateSetMinusOfFeatureSets(featuresTreeV1, featuresTreeV2, debug); - } - /** * Adds a feature to the feature map, if it is not contained in the map or the * diffType is different from the value in the map. If the diffTypes are @@ -237,8 +177,8 @@ private static boolean checkForZeroVariantDrift(VariationDiff di deselectedFeatures); VariationDiff diffVariant2 = DiffView.optimized(variant2.toCompletelyUnchangedVariationDiff(), deselectedFeatures); -// if (debug) -// GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); + if (debug) + GameEngine.showAndAwaitAll(Show.diff(diffVariant1), Show.diff(diffVariant2)); if (Patching.isSameAs(diffVariant1, diffVariant2)) { return true; } @@ -260,21 +200,6 @@ private static Set> findRootsOfSubtrees(Set> getChildrenFromListIfIndexInRange( - List> childrenList, int index, int numberOfChildren, boolean isBefore) { - int number = 0; - if (isBefore) - index = index - numberOfChildren; - ArrayList> children = new ArrayList<>(); - while (number < numberOfChildren) { - if (index + number >= 0 && index + number < childrenList.size()) { - children.add(childrenList.get(index + number)); - } - number++; - } - return children; - } - private static boolean compareAncestors(DiffNode node1, DiffNode node2, Time time, boolean debug) { if (node1.getParent(time) == null && node2.getParent(time) == null) @@ -348,117 +273,6 @@ private static DiffNode checkNeighbors2(DiffNode return candidates.get(0); } - private static boolean checkNeighbors(DiffNode root, DiffNode targetNodeInPatch, - DiffNode node, Set deselectedFeatures, Time time, boolean debug) throws Exception { - - // TODO - int contextSize = 10; - - List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); - if (!orderedChildrenTarget.contains(node)) { - // TODO: throw exception - return false; - } - int indexTarget = orderedChildrenTarget.indexOf(node); - List> neighborBeforeTarget = getChildrenFromListIfIndexInRange(orderedChildrenTarget, - indexTarget, contextSize, true); - List> neighborAfterTarget = getChildrenFromListIfIndexInRange(orderedChildrenTarget, - indexTarget, contextSize, false); - - int indexSourceMatchingNeighborBefore = -2; - int indexSourceMatchingNeighborAfter = -2; - List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - - if (debug) { - System.out.println("Children Target: " + orderedChildrenTarget); - System.out.println("Children Source: " + orderedChildrenSource); - } - - if (neighborBeforeTarget != null) { - List positions = findPositionsOfMatchingNeighborsInList(neighborBeforeTarget, - orderedChildrenSource, time); - indexSourceMatchingNeighborBefore = findNearestPositionToIndex(positions, indexTarget, true) + contextSize; - } - if (neighborAfterTarget != null) { - List positions = findPositionsOfMatchingNeighborsInList(neighborAfterTarget, orderedChildrenSource, - time); - indexSourceMatchingNeighborAfter = findNearestPositionToIndex(positions, indexTarget, false); - } - if (indexSourceMatchingNeighborBefore == -2 && indexSourceMatchingNeighborAfter == -2) { - if (debug) - System.out.println("No neighbors before or after the target"); - return true; - } - if (indexSourceMatchingNeighborBefore > -1 && indexSourceMatchingNeighborAfter > -1) { - if (indexSourceMatchingNeighborAfter - indexSourceMatchingNeighborBefore > 2) { - // Alignment Problem ? - // Check if code belongs to features which are only present in target - // variant - List> orderedChildrenTargetSubList = orderedChildrenTarget - .subList(indexSourceMatchingNeighborBefore + 1, indexSourceMatchingNeighborAfter); - if (debug) - System.out.println(orderedChildrenTargetSubList); - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { - if (debug) - System.out.println("ALIGNMENT PROBLEM. Node can be removed."); - } else { - return false; - } - } - } - return true; - } - - private static int findNearestPositionToIndex(List positions, int indexTarget, boolean isBefore) { - Optional pos; - if (isBefore) { - pos = positions.stream().map(p -> (indexTarget - p)).filter(p -> p > 0).min(Integer::compare); - } else { - pos = positions.stream().map(p -> (p - indexTarget)).filter(p -> p > 0).min(Integer::compare); - } - try { - return pos.get(); - } catch (NoSuchElementException e) { - return -1; - } - - } - - private static ArrayList findPositionsOfMatchingNeighborsInList(List> neighbors, - List> list, Time time) throws Exception { - ArrayList positions = new ArrayList(); - if (neighbors.size() == 0) - return positions; - for (int i = 0; i < list.size(); i++) { - boolean allNeighborsAreSame = false; - if (Patching.isSameAs(neighbors.get(0), list.get(i))) { - allNeighborsAreSame = true; - for (int j = 1; j < neighbors.size(); j++) { - if (list.size() > (i + j) && !Patching.isSameAs(neighbors.get(j), list.get(i + j))) { - allNeighborsAreSame = false; - } - } - if (allNeighborsAreSame) - positions.add(i); - } - } - return positions; - } - - private static boolean isAlignmentProblem(List> subList, Set deselectedFeatures, - Time time, boolean debug) { - boolean isAlignmentProblem = false; - for (DiffNode node : subList) { - Set containedFeatures = node.getPresenceCondition(time).getUniqueContainedFeatures(); - if (debug) - System.out.println(containedFeatures); - isAlignmentProblem = containedFeatures.stream().anyMatch(feature -> deselectedFeatures.contains(feature)); - if (debug) - System.out.println("is alignment problem: " + isAlignmentProblem); - } - return isAlignmentProblem; - } - private static int findInsertPosition2(DiffNode root, DiffNode targetNodeInPatch, DiffNode targetNodeInPatchView, Time time, boolean debug) throws Exception { List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); @@ -488,159 +302,6 @@ private static int findInsertPosition2(DiffNode root, DiffNode root, DiffNode targetNodeInPatch, - Set deselectedFeatures, Time time, boolean debug) throws Exception { - - // TODO - int contextSize = 10; - - if (debug) - System.out.println("Root node to insert: " + root.toString()); - List> orderedChildrenTarget = targetNodeInPatch.getChildOrder(time); - if (debug) - System.out.println("Children of target node: " + orderedChildrenTarget.toString()); - List> orderedChildrenSource = root.getParent(time).getChildOrder(time); - if (debug) - System.out.println("Children of source node: " + orderedChildrenSource.toString()); - int indexSource = orderedChildrenSource.indexOf(root); - List> neighborBeforeSource = getChildrenFromListIfIndexInRange(orderedChildrenSource, - indexSource, contextSize, true); - List> neighborAfterSource = getChildrenFromListIfIndexInRange(orderedChildrenSource, - indexSource, contextSize, false); - int currentIndexAfter = indexSource + 1; - // ignore neighbors with DiffType ADD because they are added afterwards - neighborAfterSource = neighborAfterSource.stream().filter(n -> n.diffType != DiffType.ADD).toList(); -// while (neighborAfterSource != null && neighborAfterSource.diffType == DiffType.ADD) { -// currentIndexAfter++; -// neighborAfterSource = getChildrenFromListIfIndexInRange(orderedChildrenSource, currentIndexAfter); -// } - - if (debug) { - if (neighborBeforeSource != null) { - System.out.print("Neighbor before: " + neighborBeforeSource.toString() + "; "); - } else { - System.out.print("No neighbor before; "); - } - if (neighborAfterSource != null) { - System.out.print("Neighbor after: " + neighborAfterSource.toString() + "\n"); - } else { - System.out.print("No neighbor after\n"); - } - } - int indexBefore = -2; - int indexAfter = -2; - - if (!neighborBeforeSource.isEmpty()) { - List positions = findPositionsOfMatchingNeighborsInList(neighborBeforeSource, - orderedChildrenTarget, time); - if (positions.size() == 1) { - indexBefore = positions.get(0) + neighborBeforeSource.size(); - } else if (positions.size() > 1) { - List positionsSource = findPositionsOfMatchingNeighborsInList(neighborAfterSource, - orderedChildrenSource, time); - if (positionsSource.size() == positions.size()) { - int arrayIndex = positionsSource.indexOf(indexSource + 1); - indexAfter = positions.get(arrayIndex); - } else { - throw new Exception( - "target node: " + targetNodeInPatch.toString() + "too many insert positions found: " - + positions.toString() + " with context size: " + contextSize); - } - } - - } - if (!neighborAfterSource.isEmpty()) { - List positions = findPositionsOfMatchingNeighborsInList(neighborAfterSource, orderedChildrenTarget, - time); - if (positions.size() == 1) { - indexAfter = positions.get(0); - } else if (positions.size() > 1) { - List positionsSource = findPositionsOfMatchingNeighborsInList(neighborAfterSource, - orderedChildrenSource, time); - if (positionsSource.size() == positions.size()) { - int arrayIndex = positionsSource.indexOf(indexSource + 1); - indexAfter = positions.get(arrayIndex); - } else { - throw new Exception( - "target node:" + targetNodeInPatch.toString() + "too many insert positions found: " - + positions.toString() + " with context size: " + contextSize); - } - } - } - if (indexBefore == -2 && indexAfter == -2) { - if (orderedChildrenTarget.isEmpty()) { - if (debug) - System.out.println("No neighbors before or after the target"); - return 0; - } - if (isAlignmentProblem(orderedChildrenTarget, deselectedFeatures, time, debug)) { - if (debug) - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " - + (orderedChildrenTarget.size() - 1)); - return -1; - } else { - throw new Exception("Reject"); - } - } - if (indexBefore == -2) { - List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(0, indexAfter); - if (orderedChildrenTargetSubList.size() > 1) { - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { - if (debug) - System.out.println( - "ALIGNMENT PROBLEM. Possible insert positions: from " + 1 + " to " + indexAfter); - } else { - throw new Exception("Reject"); - } - return -1; - } - } - if (indexAfter == -2) { - List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore - 1, - orderedChildrenTarget.size()); - if (debug) - System.out.println(orderedChildrenTargetSubList); - if (orderedChildrenTargetSubList.size() > 1) { - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { - if (debug) - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + (indexBefore - 1) - + " to " + (orderedChildrenTarget.size() - 1)); - } else { - throw new Exception("Reject"); - } - return -1; - } - } - if (indexBefore > -1 && indexAfter > -1) { - if (indexAfter - indexBefore > 1) { - // Alignment Problem ? - // TODO: Check if code belongs to features which are only present in target - // variant - List> orderedChildrenTargetSubList = orderedChildrenTarget.subList(indexBefore, - indexAfter); - if (debug) - System.out.println(orderedChildrenTargetSubList); - if (isAlignmentProblem(orderedChildrenTargetSubList, deselectedFeatures, time, debug)) { - if (debug) - System.out.println("ALIGNMENT PROBLEM. Possible insert positions: from " + indexBefore + " to " - + indexAfter); - } else { - System.out.println("after: " + indexAfter + " before: " + indexBefore); - throw new Exception("Reject"); - } - return -1; - } - if (indexAfter - indexBefore < 0) { - // TODO: root must be between neighbors - if (debug) - System.out.println("Neighbors in wrong order"); - return -1; - } - return indexAfter; - } - return Math.max(indexBefore, indexAfter); - } - private static void applyChanges(DiffType type, VariationDiff targetVariantDiffUnchanged, VariationDiff targetVariantDiffPatched, List> subtreeRoots, VariationDiffSource source, Set deselectedFeatures, boolean debug) throws Exception { @@ -693,24 +354,10 @@ private static void applyChanges(DiffType type, VariationDiff ta System.out.println(targetNodeInPatch.getChildOrder(time)); } else if (type == DiffType.REM) { -// List> nodesToRem = new ArrayList>(); -// List> nodesToRem2 = new ArrayList>(); -// targetNodeInPatch.getAllChildrenStream().forEach(node -> { -// -// if (Patching.hasSameLabel(node, root)) { -// nodesToRem2.add(node); -// } -// }); DiffNode nodesToRem = checkNeighbors2(root, targetNodeInPatch, time, debug); if (debug) System.out.println("Nodes to remove: " + nodesToRem); -// if (nodesToRem.size() != 1) { -// if (debug) -// System.out.println("too much or too less target nodes found"); -// if (debug) -// System.out.println(nodesToRem.toString()); -// } if (debug) System.out.println("subtree removed"); removeNode(nodesToRem); @@ -830,8 +477,6 @@ public static void resolve(DiffNode node, VariationDiff patchVariationTrees(VariationDiff diff, VariationTree targetVariant, boolean debug, boolean patchNewFeatures) throws Exception { -// Relevance rho = calculateFeatureSetToDeselectFromTrees(sourceVariantVersion1, sourceVariantVersion2, targetVariant, -// false); Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, debug, patchNewFeatures); if (debug) { @@ -842,8 +487,7 @@ public static VariationDiff patchVariationTrees(VariationDiff optimizedDiff = DiffView.optimized(diff, rho); if (debug) { From 38ac7fe333140d57859d7395088e7724f135d16b Mon Sep 17 00:00:00 2001 From: piameier Date: Sat, 4 Oct 2025 22:32:08 +0200 Subject: [PATCH 050/162] experiment setup --- .../experiments/thesis_pm/Generator.java | 276 ++++++++++++++++++ .../experiments/thesis_pm/Main.java | 42 +++ .../thesis_pm/PatchingExperiment.java | 66 ++--- 3 files changed, 347 insertions(+), 37 deletions(-) create mode 100644 src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java create mode 100644 src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Main.java diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java new file mode 100644 index 000000000..3627aa035 --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java @@ -0,0 +1,276 @@ +package org.variantsync.diffdetective.experiments.thesis_pm; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.tinylog.Logger; +import org.variantsync.diffdetective.diff.git.PatchDiff; +import org.variantsync.diffdetective.diff.result.DiffParseException; +import org.variantsync.diffdetective.shell.ShellException; +import org.variantsync.diffdetective.shell.ShellExecutor; +import org.variantsync.diffdetective.shell.SimpleCommand; +import org.variantsync.diffdetective.show.Show; +import org.variantsync.diffdetective.show.engine.GameEngine; +import org.variantsync.diffdetective.util.Assert; +import org.variantsync.diffdetective.variation.DiffLinesLabel; +import org.variantsync.diffdetective.variation.Label; +import org.variantsync.diffdetective.variation.diff.Time; +import org.variantsync.diffdetective.variation.diff.VariationDiff; +import org.variantsync.diffdetective.variation.diff.patching.Patching; +import org.variantsync.diffdetective.variation.diff.view.DiffView; +import org.variantsync.diffdetective.variation.tree.VariationTree; +import org.variantsync.diffdetective.variation.tree.view.TreeView; +import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; + +public class Generator { + /** + * This function mutates a boolean assignment by flipping some values by chance. + * This function is pure: It creates a new map and the input map is left + * unchanged. A value is flipped with a chance of (100*probability)%. On + * average, (100*probability)% of elements will end up flipped. + * + * @param probability The probability for an element being assigned 'true'. Must + * be in range [0, 1]. + */ + public static Map mutateByWeightedCoinFlip(final Map a, double probability) { + Assert.assertTrue(0 <= probability); + Assert.assertTrue(probability <= 1.0); + + final Map mutant = new HashMap<>(); + for (Entry e : a.entrySet()) { + mutant.put(e.getKey(), Math.random() <= probability ? !e.getValue() : e.getValue()); + } + + return mutant; + } + + /** + * This function creates a random partition of the given set into two subsets. + * The output set is created by virtual coin flip on every element in the input + * set. On average, (100*probability)% of elements will end up in the 'true' set + * and (100*(1-probability))% elements will end up in the 'false' set. + * + * @param probability The probability for an element being assigned 'true'. Must + * be in range [0, 1]. + */ + public static Map randomPartition(Set s, double probability) { + Assert.assertTrue(0 <= probability); + Assert.assertTrue(probability <= 1.0); + + final Map subsets = new HashMap<>(); + for (T t : s) { + subsets.put(t, Math.random() <= probability); + } + return subsets; + } + + private static void logDiff(String title, String diff) { + System.out.println("===== " + title + " =====\n" + diff + "\n===============\n"); + } + + // function to delete subdirectories and files: + // https://www.geeksforgeeks.org/java/java-program-to-delete-a-directory/ + public static void deleteDirectory(File file) { + if (file.listFiles() != null) { + for (File subfile : file.listFiles()) { + if (subfile.isDirectory()) { + deleteDirectory(subfile); + } + subfile.delete(); + } + } + + } + + public static void writeToFile(String text, Path filePath) { + try { + File f = new File(filePath.toUri()); + f.createNewFile(); + BufferedWriter myWriter = new BufferedWriter(new FileWriter(f)); + myWriter.write(text); + myWriter.close(); + } catch (IOException i) { + i.printStackTrace(); + } + } + + public static void generatePatchScenario(VariationDiff spl) throws Exception { + // ## 1. Sample two variants. + // Since we have no feature model, we create a naive problem space model: + // We just collect all features without constraints. + final Set featureModel = spl.computeAllFeatureNames(); + Logger.info("Extracted feature names: {}", featureModel); + + // To sample variants, we just pick a random subset of features to set to true, + // set the rest to false + // We could use more sophisticated algorithms here, for example based on how + // often features occur. + // Maybe should ask Sebastian. + // The configurations we produce are complete. + // Hypothesis: the lower the probability value (i.e., the more deselected + // features), the harder the patching challenge. + final Map config1 = randomPartition(featureModel, 0.6); + final Map config2 = mutateByWeightedCoinFlip(config1, 0.5); + // FIXME: We should probably ensure that config1 != config2. + Logger.info("Configuration 1: {}", config1); + Logger.info("Configuration 2: {}", config2); + // TODO: We could also distinguish the two major scenarios from these + // configurations: + // There are features in source that are not in target and vice versa? (assumes + // that nothing is labeled to the negation of a feature) + // TODO: Decide how many variants we want to generate per commit / patch and how + // we want to compare them? Have every generated variant be the source once? I + // think this is what Alex did in his ICSME'22 paper. + + // To configure our variation trees and diffs, we need to convert our + // configurations to relevance predicates. + final Configure configureTo1 = new Configure(config1); + final Configure configureTo2 = new Configure(config2); + + // ## 2. We need two variants and two versions of each variant. + final VariationDiff sourcePatch = DiffView.optimized(spl, configureTo1); // input patch to apply to the + // target variant + final VariationDiff targetPatch = DiffView.optimized(spl, configureTo2); // ground truth for target patch; + // this is the "perfect" target + // patch + // FIXME: Maybe we want to distinguish cases where one of the patches (or both) + // are empty (i.e., noop / id)? + + final VariationTree sourceVariantBefore = sourcePatch.project(Time.BEFORE); // input + final VariationTree sourceVariantAfter = sourcePatch.project(Time.AFTER); // input + final VariationTree targetVariantBefore = targetPatch.project(Time.BEFORE); // input + final VariationTree targetVariantAfter = targetPatch.project(Time.AFTER); // ground truth for how the patched + // target variant should ideally + // look like + + // GameEngine.showAndAwaitAll(Show.diff(spl)); + GameEngine.showAndAwaitAll(Show.diff(sourcePatch, "Source Patch " + config1), + Show.diff(targetPatch, "Target Patch " + config2)); + GameEngine.showAndAwaitAll(Show.tree(sourceVariantBefore, "Source Before " + config1), + Show.tree(sourceVariantAfter, "Source After " + config1), + Show.tree(targetVariantBefore, "Target Before " + config2), + Show.tree(targetVariantAfter, "Target After" + config2)); + + // ## 3. To use command-line patchers such as GNU patch and mpatch, we need to + // write our variants to disk. + final String sourceVariantCodeBefore = sourceVariantBefore.unparse(); + final String sourceVariantCodeAfter = sourceVariantAfter.unparse(); + final String targetVariantCodeBefore = targetVariantBefore.unparse(); + final String targetVariantCodeAfter = targetVariantAfter.unparse(); // ground truth for fast comparisons (beware + // of differences in line breaks and + // whitespaces!) + logDiff("Source Before:", sourceVariantCodeBefore); + logDiff("Source After:", sourceVariantCodeAfter); + logDiff("Target Before:", targetVariantCodeBefore); + logDiff("Target After:", targetVariantCodeAfter); + + // TODO: write the code to disk at a reasonable location + String diffDetective = "DiffDetective"; + String directory = "experiment"; + String sourceVariant = "sourceVariant"; + String version1 = "version1"; + String version2 = "version2"; + String targetVariant = "targetVariant"; + String code = "code.txt"; + String patch = "patch.txt"; + +// File f = new File(Path.of(directory).toUri()); +// deleteDirectory(f); +// f.delete(); +// +// if (!(new File(Path.of(directory, targetVariant).toUri())).mkdirs() || +// !(new File(Path.of(directory, sourceVariant).toUri())).mkdir()) { +// throw new Exception("Failed to create directories"); +// } +// if (!(new File(Path.of(directory, sourceVariant, version1).toUri())).mkdirs() || +// !(new File(Path.of(directory, sourceVariant, version2).toUri())).mkdir()) { +// throw new Exception("Failed to create directories"); +// } + + Path sourceVariantBeforePath = Path.of(directory, sourceVariant, version1, code); + Path sourceVariantAfterPath = Path.of(directory, sourceVariant, version2, code); + Path targetVariantBeforePath = Path.of(directory, targetVariant, code); +// writeToFile(sourceVariantCodeBefore, sourceVariantBeforePath); +// writeToFile(sourceVariantCodeAfter, sourceVariantAfterPath); +// writeToFile(targetVariantCodeBefore, targetVariantBeforePath); +// writeToFile(targetVariantCodeAfter, targetVariantAfterPath); + + final ShellExecutor shell = new ShellExecutor(Logger::info, Logger::error, Path.of(directory)); // maybe we have + // to specify + // the working + // directory as + // third + // argument here + try { + Path pathToVersion1Dir = Path.of(sourceVariant, version1); + Path PathToVersion2Dir = Path.of(sourceVariant, version2); + List list = shell.execute( + new SimpleCommand("diff", "-Naur", pathToVersion1Dir.toString(), PathToVersion2Dir.toString())); + } catch (ShellException e) { +// System.out.println(e); + } + + // ## 4. Run the patchers! + + // TODO: Run Pia's new patcher here and store the result. + +// try { +// VariationDiff diff = Patching.patch((VariationDiff) sourcePatch, (VariationTree) targetVariantBefore, false, true); +// System.out.println(diff.project(Time.AFTER).unparse()); +// } catch (Exception e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } + VariationTree gnuPatchResult = null; + VariationTree mpatchResult = null; + // TODO: run mpatch and gnu patch. Here is a sketch for this can be done. + try { + // TODO: configure GNU patch + Path pathToTargetVariantCode = Path.of(targetVariant, code); + Path pathToSourceVariantPatch = Path.of(sourceVariant, patch); + shell.execute(new SimpleCommand("patch", pathToTargetVariantCode.toString(), + pathToSourceVariantPatch.toString())); + gnuPatchResult = VariationTree.fromFile(Path.of(directory, targetVariant, code)); + + // reset target variant + writeToFile(targetVariantCodeBefore, targetVariantBeforePath); + + // TODO: configure mpatch + Path mpatchPath = Path.of("..", "..", "..", "mpatch", "target", "debug", "mpatch"); + pathToSourceVariantPatch = Path.of("..", sourceVariant, patch); + // FIXME: how to change directory? + final ShellExecutor shell2 = new ShellExecutor(Logger::info, Logger::error, + Path.of(directory, targetVariant)); + SimpleCommand command = new SimpleCommand(mpatchPath.toString(), "--strip", "1", "--sourcedir", + Path.of("..", sourceVariant).toString(), "--patchfile", pathToSourceVariantPatch.toString()); + shell2.execute(command); + mpatchResult = VariationTree.fromFile(Path.of(directory, targetVariant, code)); + + } catch (ShellException e) { + // FIXME: When a shell exception occurs, we know that patching failed. + // Either there is a bug or the patcher was not successful! + // We should not throw and catch exceptions in these cases. + // It is probably best to write new ShellCommand subclasses for mpatch and GNU + // patch with a proper interpretResult method. + // We have to distinguish patch success from patch failure anyway somewhere. + Logger.error(e); + } + + // TODO: Read the results of the patchers. The patchers should produce the + // target variants as string if they did not fail. + GameEngine.showAndAwaitAll(Show.tree(targetVariantAfter, "ground truth"), Show.tree(mpatchResult, "mpatch"), Show.tree(gnuPatchResult, "gnu patch")); + + // ## 5. Compare the results of patchers here! + // TODO + } +} diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Main.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Main.java new file mode 100644 index 000000000..21f66bdbf --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Main.java @@ -0,0 +1,42 @@ +package org.variantsync.diffdetective.experiments.thesis_pm; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.ArrayList; + +import org.variantsync.diffdetective.variation.DiffLinesLabel; +import org.variantsync.diffdetective.variation.diff.VariationDiff; +import org.variantsync.diffdetective.variation.diff.parse.VariationDiffParseOptions; +import org.variantsync.diffdetective.diff.result.DiffParseException; +import org.variantsync.diffdetective.util.FileUtils; + +import java.io.IOException; +import org.tinylog.Logger; + +public class Main { + public static void main(String[] args) throws IOException, DiffParseException { + final Path testDir = Path.of("data", "examples", "test"); + List inputDiffs = Files.list(testDir).toList(); + List> diffs = new ArrayList<>(inputDiffs.size()); + + // for debugging, drop all but the first variant + inputDiffs = List.of(inputDiffs.get(0)); + + for (Path p : inputDiffs) { + if (FileUtils.hasExtension(p, ".diff")) { + Logger.info("Loading Diff {}", p); + diffs.add(VariationDiff.fromFile(p, VariationDiffParseOptions.Default)); + } + } + + for (VariationDiff d : diffs) { + try { + Generator.generatePatchScenario(d); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java index e7fb10c01..d53e13f62 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/PatchingExperiment.java @@ -13,12 +13,12 @@ import org.variantsync.diffdetective.variation.diff.transform.CutNonEditedSubtrees; import org.variantsync.diffdetective.variation.tree.VariationTree; import java.util.List; -import java.util.concurrent.ExecutionException; import org.tinylog.Logger; import org.variantsync.diffdetective.analysis.*; import org.variantsync.diffdetective.datasets.PatchDiffParseOptions; import org.variantsync.diffdetective.datasets.Repository; +import org.variantsync.diffdetective.diff.git.PatchDiff; import org.variantsync.diffdetective.show.Show; import org.variantsync.diffdetective.show.engine.GameEngine; import org.variantsync.diffdetective.variation.diff.Time; @@ -36,8 +36,7 @@ public class PatchingExperiment implements Analysis.Hooks { private static final AnalysisResult.ResultKey SKIPPED_PATCHES_COUNTER_RESULT_KEY = new AnalysisResult.ResultKey<>( "skipped patches"); private int commits = 0; - private boolean firstDiff = true; - private VariationDiff firstIncorrectlyPatchedDiff; + private PatchDiff lastPatch; private static class RejectedPatchesCounter extends SimpleMetadata { public RejectedPatchesCounter() { @@ -65,8 +64,8 @@ public SkippedPatchesCounter() { } } - public VariationDiff getFirstIncorrectlyPatchedDiff() { - return this.firstIncorrectlyPatchedDiff; + public PatchDiff getLastPatch() { + return this.lastPatch; } @Override @@ -86,22 +85,14 @@ public boolean beginCommit(Analysis analysis) throws Exception { @Override public boolean analyzeVariationDiff(Analysis analysis) throws Exception { VariationDiff diff = analysis.getCurrentVariationDiff(); + lastPatch = analysis.getCurrentPatch(); VariationTree before = diff.project(Time.BEFORE).deepCopy(); VariationTree after = diff.project(Time.AFTER).deepCopy(); try { - VariationDiff patchedVariant = Patching.patchVariationTrees(diff, before, false, true); + VariationDiff patchedVariant = Patching.patch(diff, before, false, true); if (!Patching.comparePatchedVariantWithExpectedResult(patchedVariant.project(Time.AFTER), after)) { - try { - File f = new File(Path.of("data", "examples", "file3.diff").toUri()); - f.createNewFile(); - BufferedWriter myWriter = new BufferedWriter(new FileWriter(f)); - myWriter.write(analysis.getCurrentPatch().getDiff()); - myWriter.close(); - } catch (IOException e) { - e.printStackTrace(); - } analysis.get(INCORRECTLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; VariationDiff diffCopy = diff.deepCopy(); VariationDiff patchedCopy = patchedVariant.deepCopy(); @@ -109,31 +100,29 @@ public boolean analyzeVariationDiff(Analysis analysis) throws Exception { CutNonEditedSubtrees.genericTransform(patchedCopy); GameEngine.showAndAwaitAll(Show.diff(diffCopy), Show.diff(patchedCopy)); -// if (firstDiff) { -// Patching.patchVariationTrees(diff, before, true, true); -// wait(60000); -// firstDiff = false; -// } - } else { analysis.get(SUCCESSFULLY_APPLIED_PATCHES_COUNTER_RESULT_KEY).value++; } } catch (Exception e) { e.printStackTrace(); -// try { -// File f = new File(Path.of("data", "examples", "file3.diff").toUri()); -// f.createNewFile(); -// BufferedWriter myWriter = new BufferedWriter(new FileWriter(f)); -// myWriter.write(analysis.getCurrentPatch().getDiff()); -// myWriter.close(); -// } catch (IOException i) { -// i.printStackTrace(); -// } -// throw new Exception("break"); - analysis.get(REJECTED_PATCHES_COUNTER_RESULT_KEY).value++; + PatchingExperiment.writeToFile(lastPatch, "file6.diff"); + throw new Exception("break"); +// analysis.get(REJECTED_PATCHES_COUNTER_RESULT_KEY).value++; } return true; } + + public static void writeToFile(PatchDiff p, String filename) { + try { + File f = new File(Path.of("data", "examples", filename).toUri()); + f.createNewFile(); + BufferedWriter myWriter = new BufferedWriter(new FileWriter(f)); + myWriter.write(p.getDiff()); + myWriter.close(); + } catch (IOException i) { + i.printStackTrace(); + } + } @Override public void endBatch(Analysis analysis) throws Exception { @@ -155,7 +144,7 @@ public static void main(String[] args) { Path.of("data", "output"), Path.of("data", "demo-dataset.md"), repo -> new PatchDiffParseOptions( - PatchDiffParseOptions.DiffStoragePolicy.REMEMBER_FULL_DIFF, + PatchDiffParseOptions.DiffStoragePolicy.DO_NOT_REMEMBER, new VariationDiffParseOptions( true, false @@ -171,15 +160,18 @@ public static void main(String[] args) { // (repository, path) -> Analysis.forEachCommit(() -> PatchingExperiment.Create(repository, path, experiment), 500, // 8)); // } catch (Exception e) { +// PatchingExperiment.writeToFile(experiment.getLastPatch(), "file7.diff"); // e.printStackTrace(); // } try { -// exampleA2NodesWith2Parents.cpp - Patching.patchVariationTrees(Patching.parseVariationDiffFromFile("file2.diff"), Patching.parseVariationDiffFromFile("file1.diff").project(Time.BEFORE), true, true); + VariationDiff diff = Patching.patch(Patching.parseVariationDiffFromFile("test_exampleA.diff"), + Patching.parseVariationTreeFromFile("test_exampleB.cpp"), true, true); + System.out.println(diff.project(Time.AFTER).unparse()); +// Patching.patchVariationTrees(Patching.parseVariationDiffFromFile("file5.diff"), Patching.parseVariationDiffFromFile("file5.diff").project(Time.BEFORE), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Add.cpp", "exampleA2Add.cpp"), Patching.parseVariationTreeFromFile("exampleBAdd.cpp"), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1Rem.cpp", "exampleA2Rem.cpp"), Patching.parseVariationTreeFromFile("exampleBRem.cpp"), true, true); -// Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), -// Patching.parseVariationTreeFromFile("exampleA1RemAdd.cpp"), true, true); +// VariationDiff diff = Patching.patchVariationTrees(Patching.parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), +// Patching.parseVariationTreeFromFile("exampleBRemAdd.cpp"), true, true); // Patching.patchVariationTrees(Patching.parseVariationDiffFromFile("exampleCompareAncestors.diff"), Patching.parseVariationTreeFromFile("exampleCompareAncestorsB.cpp"), true, false); // VariationTree patchedVariant = patchVariationTrees( // parseVariationDiffFromFiles("exampleA1RemAdd.cpp", "exampleA2RemAdd.cpp"), From 76eaa2ae780db97198fc7239da38247c147bce46 Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 5 Oct 2025 13:33:30 +0200 Subject: [PATCH 051/162] added method arePatchedVariantsEquivalent --- .../variation/diff/patching/Patching.java | 95 ++++++++++++------- 1 file changed, 62 insertions(+), 33 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 296918226..0bc5d6f2e 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -29,6 +29,7 @@ import org.variantsync.diffdetective.variation.diff.transform.CutNonEditedSubtrees; import org.variantsync.diffdetective.variation.diff.view.DiffView; import org.variantsync.diffdetective.variation.tree.VariationTree; +import org.variantsync.diffdetective.variation.tree.view.TreeView; import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; @@ -52,10 +53,8 @@ private static boolean isSameAs(DiffNode a, DiffNode b, return true; } - if (!(a.getNodeType().equals(b.getNodeType()) && hasSameLabel(a, b) && - hasSameLabel(a, b) && - (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())) - )) { + if (!(a.getNodeType().equals(b.getNodeType()) && hasSameLabel(a, b) && hasSameLabel(a, b) + && (a.getFormula() == null ? b.getFormula() == null : a.getFormula().equals(b.getFormula())))) { return false; } @@ -324,13 +323,12 @@ private static void applyChanges(DiffType type, VariationDiff ta node -> node.getPresenceCondition(Time.AFTER).equals(presenceCondition) && node.isAnnotation()); } - VariationDiff targetVariantDiffPatchedView = DiffView.optimized(targetVariantDiffPatched.deepCopy(), calculateFormulaForDeselection(deselectedFeatures, debug)); + VariationDiff targetVariantDiffPatchedView = DiffView.optimized( + targetVariantDiffPatched.deepCopy(), calculateFormulaForDeselection(deselectedFeatures, debug)); + targetNodes = targetNodes.stream().filter(targetNode -> checkNeighborsLabels(root, + targetVariantDiffPatchedView.getNodeWithID(targetNode.getID()), time, debug)).toList(); targetNodes = targetNodes.stream() - .filter(targetNode -> checkNeighborsLabels(root, - targetVariantDiffPatchedView.getNodeWithID(targetNode.getID()), time, - debug)) - .toList(); - targetNodes = targetNodes.stream().map(targetNode -> targetVariantDiffPatched.getNodeWithID(targetNode.getID())).toList(); + .map(targetNode -> targetVariantDiffPatched.getNodeWithID(targetNode.getID())).toList(); if (targetNodes.size() != 1) { throw new Exception("too much or too less target nodes after filtering: " + targetNodes.size()); } @@ -342,7 +340,8 @@ private static void applyChanges(DiffType type, VariationDiff ta if (debug) { GameEngine.showAndAwaitAll(Show.tree(targetVariantDiffPatched.project(Time.AFTER))); } - int insertPosition = findInsertPosition2(root, targetNodeInPatch, targetVariantDiffPatchedView.getNodeWithID(targetNodeInPatch.getID()), time, debug); + int insertPosition = findInsertPosition2(root, targetNodeInPatch, + targetVariantDiffPatchedView.getNodeWithID(targetNodeInPatch.getID()), time, debug); if (insertPosition < 0) { if (debug) System.out.println("no matching insert position found"); @@ -392,16 +391,16 @@ private static void removeNode(DiffNode node) throws Exception { } - private static VariationDiff patchVariationTrees( - VariationTree sourceVariantVersion1, VariationTree sourceVariantVersion2, - VariationTree targetVariant, boolean debug, boolean patchNewFeatures) throws Exception { + private static VariationDiff patch(VariationTree sourceVariantVersion1, + VariationTree sourceVariantVersion2, VariationTree targetVariant, + boolean debug, boolean patchNewFeatures) throws Exception { if (sourceVariantVersion1 == null || sourceVariantVersion2 == null || targetVariant == null) { if (debug) System.out.println("Parsing error"); return null; } VariationDiff diff = VariationDiff.fromTrees(sourceVariantVersion1, sourceVariantVersion2); - return patchVariationTrees(diff, targetVariant, debug, patchNewFeatures); + return patch(diff, targetVariant, debug, patchNewFeatures); } public static void changeType(DiffNode node, VariationDiff modDiff, DiffType type) { @@ -412,7 +411,7 @@ public static void changeType(DiffNode node, VariationDiff node, VariationDiff nodeAfter = matchingNode.deepCopy(); nodeAfter.diffType = DiffType.ADD; - + DiffNode newRootAfter = DiffNode.createRoot(new DiffLinesLabel()); newRootAfter.addChild(nodeAfter.deepCopy(), Time.AFTER); - VariationDiff subTreeAfter = new VariationDiff(newRootAfter, modDiff.getSource()); - + VariationDiff subTreeAfter = new VariationDiff(newRootAfter, + modDiff.getSource()); + if (!nodeAfter.isLeaf()) { changeType(nodeAfter, subTreeAfter, DiffType.ADD); // remove all children with difftype REM recursively // set recursively difftype ADD for all children which have currently difftype // NON } - + // GameEngine.showAndAwaitAll(Show.diff(subTreeAfter)); - + DiffNode nodeBefore = matchingNode.deepCopy(); nodeBefore.diffType = DiffType.REM; - + DiffNode newRootBefore = DiffNode.createRoot(new DiffLinesLabel()); newRootBefore.addChild(nodeBefore.deepCopy(), Time.BEFORE); - VariationDiff subTreeBefore = new VariationDiff(newRootBefore, modDiff.getSource()); - + VariationDiff subTreeBefore = new VariationDiff(newRootBefore, + modDiff.getSource()); + if (!nodeBefore.isLeaf()) { changeType(nodeBefore, subTreeBefore, DiffType.REM); } - + // GameEngine.showAndAwaitAll(Show.diff(subTreeBefore)); - + parentAfter.insertChild(subTreeAfter.getRoot().getAllChildren().iterator().next(), indexAfter, Time.AFTER); - parentBefore.insertChild(subTreeBefore.getRoot().getAllChildren().iterator().next(), indexBefore, Time.BEFORE); + parentBefore.insertChild(subTreeBefore.getRoot().getAllChildren().iterator().next(), indexBefore, + Time.BEFORE); // GameEngine.showAndAwaitAll(Show.diff(modDiff)); } } - public static VariationDiff patchVariationTrees(VariationDiff diff, + public static VariationDiff patch(VariationDiff diff, VariationTree targetVariant, boolean debug, boolean patchNewFeatures) throws Exception { Set deselectedFeatures = calculateFeatureSetToDeselectFromDiff(diff, targetVariant, debug, @@ -547,13 +549,12 @@ public static VariationDiff patchVariationTrees(VariationDiff targetVariantDiffPatchedCopy = targetVariantDiffPatched.deepCopy(); VariationDiff optimizedDiffCopy = optimizedDiff.deepCopy(); @@ -591,6 +592,34 @@ public static VariationTree parseVariationTreeFromFile(String fi return null; } + public static boolean arePatchedVariantsEquivalent(VariationTree sourceVariantAfter, + VariationTree targetVariantBefore, VariationTree targetVariantAfter, + Configure configSource, Configure configTarget, Configure configIntersection) { + VariationTree sourceVariantAfterRedToCrossVarFeatures = TreeView.tree(sourceVariantAfter, + configSource); + VariationTree targetVariantAfterRedToCrossVarFeatures = TreeView.tree(targetVariantAfter, + configTarget); + + VariationTree targetVariantBeforeRedToVarSpecificFeatures = TreeView.tree(targetVariantBefore, + configIntersection); + VariationTree targetVariantAfterRedToVarSpecificFeatures = TreeView.tree(targetVariantAfter, + configIntersection); + + GameEngine.showAndAwaitAll( + Show.tree(targetVariantAfterRedToVarSpecificFeatures, "targetVariantAfterRedToVarSpecificFeatures"), + Show.tree(targetVariantBeforeRedToVarSpecificFeatures, "targetVariantBeforeRedToVarSpecificFeatures"), + Show.tree(targetVariantAfterRedToCrossVarFeatures, "targetVariantAfterRedToCrossVarFeatures"), + Show.tree(sourceVariantAfterRedToCrossVarFeatures, "sourceVariantAfterRedToCrossVarFeatures")); + + if (Patching.isSameAs(sourceVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff(), + targetVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff()) + && Patching.isSameAs(targetVariantBeforeRedToVarSpecificFeatures.toCompletelyUnchangedVariationDiff(), + targetVariantAfterRedToVarSpecificFeatures.toCompletelyUnchangedVariationDiff())) { + return true; + } + return false; + } + public static boolean comparePatchedVariantWithExpectedResult(VariationTree patchedVariant, VariationTree expectedResult) { return Patching.isSameAs(patchedVariant.toCompletelyUnchangedVariationDiff(), From 01c2fe479b14c49ee4e986b91ea388dd3eb64bd4 Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 5 Oct 2025 17:17:54 +0200 Subject: [PATCH 052/162] shell command classes for diff, gnu patch and mpatch --- .../diffdetective/shell/DiffCommand.java | 56 +++++++++++++++++++ .../diffdetective/shell/GnuPatchCommand.java | 56 +++++++++++++++++++ .../diffdetective/shell/MPatchCommand.java | 56 +++++++++++++++++++ 3 files changed, 168 insertions(+) create mode 100644 src/main/java/org/variantsync/diffdetective/shell/DiffCommand.java create mode 100644 src/main/java/org/variantsync/diffdetective/shell/GnuPatchCommand.java create mode 100644 src/main/java/org/variantsync/diffdetective/shell/MPatchCommand.java diff --git a/src/main/java/org/variantsync/diffdetective/shell/DiffCommand.java b/src/main/java/org/variantsync/diffdetective/shell/DiffCommand.java new file mode 100644 index 000000000..bf713e3e7 --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/shell/DiffCommand.java @@ -0,0 +1,56 @@ +package org.variantsync.diffdetective.shell; + +import java.util.List; + +/** Single executable command with arguments. */ +public class DiffCommand extends ShellCommand { + private final String[] parts; + private boolean filesDifferent; + + /** + * Constructs a single command. + * The first argument has to be a path to an executable which will be given all of the + * remaining arguments as parameters on execution. + * + * @param cmd executable path and arguments for the executable + */ + public DiffCommand(final String... cmd) { + parts = cmd; + } + + @Override + public String[] parts() { + return parts; + } + + /** + * Interpret the result/exit code returned from a shell command. + * An {@code ShellException} is thrown if the result code is an error. + * + * @param resultCode the code that is to be parsed + * @param output the output of the shell command + * @return the output of the shell command + * @throws ShellException if {@code resultCode} is an error + */ + @Override + public List interpretResult(int resultCode, List output) throws ShellException { + System.out.println(resultCode); + // inputs are the same + if (resultCode == 0) { + filesDifferent = false; + return output; + } + // if inputs are different + if (resultCode == 1) { + filesDifferent = true; + return output; + } + // everything else: "serious trouble": exit code 2 + throw new ShellException(output); + + } + + public boolean areFilesDifferent() { + return filesDifferent; + } +} diff --git a/src/main/java/org/variantsync/diffdetective/shell/GnuPatchCommand.java b/src/main/java/org/variantsync/diffdetective/shell/GnuPatchCommand.java new file mode 100644 index 000000000..c4aefde30 --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/shell/GnuPatchCommand.java @@ -0,0 +1,56 @@ +package org.variantsync.diffdetective.shell; + +import java.util.List; + +/** Single executable command with arguments. */ +public class GnuPatchCommand extends ShellCommand { + private final String[] parts; + private boolean patchingSuccessful; + + /** + * Constructs a single command. + * The first argument has to be a path to an executable which will be given all of the + * remaining arguments as parameters on execution. + * + * @param cmd executable path and arguments for the executable + */ + public GnuPatchCommand(final String... cmd) { + parts = cmd; + } + + @Override + public String[] parts() { + return parts; + } + + /** + * Interpret the result/exit code returned from a shell command. + * An {@code ShellException} is thrown if the result code is an error. + * + * @param resultCode the code that is to be parsed + * @param output the output of the shell command + * @return the output of the shell command + * @throws ShellException if {@code resultCode} is an error + */ + @Override + public List interpretResult(int resultCode, List output) throws ShellException { + System.out.println(resultCode); + // patching was successful + if (resultCode == 0) { + patchingSuccessful = true; + return null; + } + // some hunks cannot be applied or merge conflicts + if (resultCode == 1) { + patchingSuccessful = false; + return null; + } + // everything else: "serious trouble": exit code 2 + throw new ShellException(output); + + } + + public boolean isPatchingSuccessful() { + return patchingSuccessful; + } +} diff --git a/src/main/java/org/variantsync/diffdetective/shell/MPatchCommand.java b/src/main/java/org/variantsync/diffdetective/shell/MPatchCommand.java new file mode 100644 index 000000000..827004f23 --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/shell/MPatchCommand.java @@ -0,0 +1,56 @@ +package org.variantsync.diffdetective.shell; + +import java.util.List; + +/** Single executable command with arguments. */ +public class MPatchCommand extends ShellCommand { + private final String[] parts; + private boolean patchingSuccessful; + + /** + * Constructs a single command. + * The first argument has to be a path to an executable which will be given all of the + * remaining arguments as parameters on execution. + * + * @param cmd executable path and arguments for the executable + */ + public MPatchCommand(final String... cmd) { + parts = cmd; + } + + @Override + public String[] parts() { + return parts; + } + + /** + * Interpret the result/exit code returned from a shell command. + * An {@code ShellException} is thrown if the result code is an error. + * + * @param resultCode the code that is to be parsed + * @param output the output of the shell command + * @return the output of the shell command + * @throws ShellException if {@code resultCode} is an error + */ + @Override + public List interpretResult(int resultCode, List output) throws ShellException { + System.out.println(resultCode); + // patching was successful ??? + if (resultCode == 0) { + patchingSuccessful = true; + return null; + } + // some hunks cannot be applied or merge conflicts ??? + if (resultCode == 1) { + patchingSuccessful = false; + return null; + } + // everything else: "serious trouble": exit code 2 ??? + throw new ShellException(output); + + } + + public boolean isPatchingSuccessful() { + return patchingSuccessful; + } +} From 1d3e9e068cb22bf8a58192057b7e14c8114bca22 Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 5 Oct 2025 17:19:20 +0200 Subject: [PATCH 053/162] fixed bug in arePatchedVariantsEquivalent --- .../variation/diff/patching/Patching.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 0bc5d6f2e..e4da79e7c 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -594,22 +594,22 @@ public static VariationTree parseVariationTreeFromFile(String fi public static boolean arePatchedVariantsEquivalent(VariationTree sourceVariantAfter, VariationTree targetVariantBefore, VariationTree targetVariantAfter, - Configure configSource, Configure configTarget, Configure configIntersection) { + Configure configCrossVariant, Configure configTargetVariantSpecific) { VariationTree sourceVariantAfterRedToCrossVarFeatures = TreeView.tree(sourceVariantAfter, - configSource); + configCrossVariant); VariationTree targetVariantAfterRedToCrossVarFeatures = TreeView.tree(targetVariantAfter, - configTarget); + configCrossVariant); VariationTree targetVariantBeforeRedToVarSpecificFeatures = TreeView.tree(targetVariantBefore, - configIntersection); + configTargetVariantSpecific); VariationTree targetVariantAfterRedToVarSpecificFeatures = TreeView.tree(targetVariantAfter, - configIntersection); + configTargetVariantSpecific); - GameEngine.showAndAwaitAll( - Show.tree(targetVariantAfterRedToVarSpecificFeatures, "targetVariantAfterRedToVarSpecificFeatures"), - Show.tree(targetVariantBeforeRedToVarSpecificFeatures, "targetVariantBeforeRedToVarSpecificFeatures"), - Show.tree(targetVariantAfterRedToCrossVarFeatures, "targetVariantAfterRedToCrossVarFeatures"), - Show.tree(sourceVariantAfterRedToCrossVarFeatures, "sourceVariantAfterRedToCrossVarFeatures")); +// GameEngine.showAndAwaitAll( +// Show.tree(targetVariantAfterRedToVarSpecificFeatures, "targetVariantAfterRedToVarSpecificFeatures"), +// Show.tree(targetVariantBeforeRedToVarSpecificFeatures, "targetVariantBeforeRedToVarSpecificFeatures"), +// Show.tree(targetVariantAfterRedToCrossVarFeatures, "targetVariantAfterRedToCrossVarFeatures"), +// Show.tree(sourceVariantAfterRedToCrossVarFeatures, "sourceVariantAfterRedToCrossVarFeatures")); if (Patching.isSameAs(sourceVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff(), targetVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff()) From d1237be52ca648485610fb79023fe6d96ab7233a Mon Sep 17 00:00:00 2001 From: piameier Date: Sun, 5 Oct 2025 17:21:31 +0200 Subject: [PATCH 054/162] modify target patch to fix bug --- .../experiments/thesis_pm/Generator.java | 151 ++++++++++++++---- .../variation/diff/DiffNode.java | 32 ++++ 2 files changed, 149 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java index 3627aa035..2710c64e2 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java @@ -16,6 +16,9 @@ import org.tinylog.Logger; import org.variantsync.diffdetective.diff.git.PatchDiff; import org.variantsync.diffdetective.diff.result.DiffParseException; +import org.variantsync.diffdetective.shell.DiffCommand; +import org.variantsync.diffdetective.shell.GnuPatchCommand; +import org.variantsync.diffdetective.shell.MPatchCommand; import org.variantsync.diffdetective.shell.ShellException; import org.variantsync.diffdetective.shell.ShellExecutor; import org.variantsync.diffdetective.shell.SimpleCommand; @@ -24,6 +27,7 @@ import org.variantsync.diffdetective.util.Assert; import org.variantsync.diffdetective.variation.DiffLinesLabel; import org.variantsync.diffdetective.variation.Label; +import org.variantsync.diffdetective.variation.diff.DiffNode; import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; import org.variantsync.diffdetective.variation.diff.patching.Patching; @@ -103,6 +107,23 @@ public static void writeToFile(String text, Path filePath) { i.printStackTrace(); } } + + public static void writeToFile(List text, Path filePath) { + try { + File f = new File(filePath.toUri()); + f.createNewFile(); + BufferedWriter myWriter = new BufferedWriter(new FileWriter(f)); + for (int i = 0; i < text.size(); i++) { + myWriter.write(text.get(i)); + if (i != text.size() - 1) { + myWriter.newLine(); + } + } + myWriter.close(); + } catch (IOException i) { + i.printStackTrace(); + } + } public static void generatePatchScenario(VariationDiff spl) throws Exception { // ## 1. Sample two variants. @@ -140,9 +161,40 @@ public static void generatePatchScenario(VariationDiff spl) // ## 2. We need two variants and two versions of each variant. final VariationDiff sourcePatch = DiffView.optimized(spl, configureTo1); // input patch to apply to the // target variant - final VariationDiff targetPatch = DiffView.optimized(spl, configureTo2); // ground truth for target patch; + VariationDiff targetPatch = DiffView.optimized(spl, configureTo2); // ground truth for target patch; // this is the "perfect" target // patch + + VariationDiff targetView = DiffView.optimized(targetPatch.deepCopy(), configureTo1); + VariationDiff targetPatchModified = targetPatch.deepCopy(); + GameEngine.showAndAwaitAll(Show.diff(sourcePatch, "source patch"), Show.diff(targetPatch, "target patch"), Show.diff(targetView, "target view")); + targetPatch.forAll(node -> { + if (targetView.getNodeWithID(node.getID()) == null && !node.isNon()) { + node = targetPatchModified.getNodeWithID(node.getID()); + if (node != null) { + DiffNode newNode = DiffNode.unchanged(node); + if (node.isRem()) { + if (node.getParent(Time.BEFORE) != null && node.getParent(Time.BEFORE).isNon()) { + int index = node.getParent(Time.BEFORE).indexOfChild(node, Time.BEFORE); + node.getParent(Time.BEFORE).insertChild(newNode, index, Time.BEFORE); + node.getParent(Time.BEFORE).insertChild(newNode, index, Time.AFTER); + } + } + if (node.isAdd()) { + + if (node.getParent(Time.AFTER) != null && node.getParent(Time.AFTER).isNon()) { + int index = node.getParent(Time.AFTER).indexOfChild(node, Time.AFTER); + node.getParent(Time.AFTER).insertChild(newNode, index, Time.BEFORE); + node.getParent(Time.AFTER).insertChild(newNode, index, Time.AFTER); + } + } + node.drop(); + } + } + }); + targetPatch = targetPatchModified; + GameEngine.showAndAwaitAll(Show.diff(sourcePatch), Show.diff(targetPatch), Show.diff(targetView), Show.diff(targetPatchModified)); + // FIXME: Maybe we want to distinguish cases where one of the patches (or both) // are empty (i.e., noop / id)? @@ -156,10 +208,10 @@ public static void generatePatchScenario(VariationDiff spl) // GameEngine.showAndAwaitAll(Show.diff(spl)); GameEngine.showAndAwaitAll(Show.diff(sourcePatch, "Source Patch " + config1), Show.diff(targetPatch, "Target Patch " + config2)); - GameEngine.showAndAwaitAll(Show.tree(sourceVariantBefore, "Source Before " + config1), - Show.tree(sourceVariantAfter, "Source After " + config1), - Show.tree(targetVariantBefore, "Target Before " + config2), - Show.tree(targetVariantAfter, "Target After" + config2)); +// GameEngine.showAndAwaitAll(Show.tree(sourceVariantBefore, "Source Before " + config1), +// Show.tree(sourceVariantAfter, "Source After " + config1), +// Show.tree(targetVariantBefore, "Target Before " + config2), +// Show.tree(targetVariantAfter, "Target After" + config2)); // ## 3. To use command-line patchers such as GNU patch and mpatch, we need to // write our variants to disk. @@ -184,25 +236,26 @@ public static void generatePatchScenario(VariationDiff spl) String code = "code.txt"; String patch = "patch.txt"; -// File f = new File(Path.of(directory).toUri()); -// deleteDirectory(f); -// f.delete(); -// -// if (!(new File(Path.of(directory, targetVariant).toUri())).mkdirs() || -// !(new File(Path.of(directory, sourceVariant).toUri())).mkdir()) { -// throw new Exception("Failed to create directories"); -// } -// if (!(new File(Path.of(directory, sourceVariant, version1).toUri())).mkdirs() || -// !(new File(Path.of(directory, sourceVariant, version2).toUri())).mkdir()) { -// throw new Exception("Failed to create directories"); -// } + File f = new File(Path.of(directory).toUri()); + deleteDirectory(f); + f.delete(); + + if (!(new File(Path.of(directory, targetVariant).toUri())).mkdirs() || + !(new File(Path.of(directory, sourceVariant).toUri())).mkdir()) { + throw new Exception("Failed to create directories"); + } + if (!(new File(Path.of(directory, sourceVariant, version1).toUri())).mkdirs() || + !(new File(Path.of(directory, sourceVariant, version2).toUri())).mkdir()) { + throw new Exception("Failed to create directories"); + } Path sourceVariantBeforePath = Path.of(directory, sourceVariant, version1, code); Path sourceVariantAfterPath = Path.of(directory, sourceVariant, version2, code); Path targetVariantBeforePath = Path.of(directory, targetVariant, code); -// writeToFile(sourceVariantCodeBefore, sourceVariantBeforePath); -// writeToFile(sourceVariantCodeAfter, sourceVariantAfterPath); -// writeToFile(targetVariantCodeBefore, targetVariantBeforePath); + Path patchPath = Path.of(directory, sourceVariant, patch); + writeToFile(sourceVariantCodeBefore, sourceVariantBeforePath); + writeToFile(sourceVariantCodeAfter, sourceVariantAfterPath); + writeToFile(targetVariantCodeBefore, targetVariantBeforePath); // writeToFile(targetVariantCodeAfter, targetVariantAfterPath); final ShellExecutor shell = new ShellExecutor(Logger::info, Logger::error, Path.of(directory)); // maybe we have @@ -213,9 +266,11 @@ public static void generatePatchScenario(VariationDiff spl) // argument here try { Path pathToVersion1Dir = Path.of(sourceVariant, version1); - Path PathToVersion2Dir = Path.of(sourceVariant, version2); - List list = shell.execute( - new SimpleCommand("diff", "-Naur", pathToVersion1Dir.toString(), PathToVersion2Dir.toString())); + Path pathToVersion2Dir = Path.of(sourceVariant, version2); + writeToFile(shell.execute( + new DiffCommand("diff", "-Naur", pathToVersion1Dir.toString(), pathToVersion2Dir.toString())), patchPath); + +// System.out.println(list); } catch (ShellException e) { // System.out.println(e); } @@ -223,14 +278,15 @@ public static void generatePatchScenario(VariationDiff spl) // ## 4. Run the patchers! // TODO: Run Pia's new patcher here and store the result. - -// try { -// VariationDiff diff = Patching.patch((VariationDiff) sourcePatch, (VariationTree) targetVariantBefore, false, true); -// System.out.println(diff.project(Time.AFTER).unparse()); -// } catch (Exception e) { -// // TODO Auto-generated catch block -// e.printStackTrace(); -// } + VariationTree patchTransformerResult = null; + try { + VariationDiff diff = Patching.patch((VariationDiff) sourcePatch, (VariationTree) targetVariantBefore, false, true); + patchTransformerResult = diff.project(Time.AFTER); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + VariationTree gnuPatchResult = null; VariationTree mpatchResult = null; // TODO: run mpatch and gnu patch. Here is a sketch for this can be done. @@ -238,7 +294,7 @@ public static void generatePatchScenario(VariationDiff spl) // TODO: configure GNU patch Path pathToTargetVariantCode = Path.of(targetVariant, code); Path pathToSourceVariantPatch = Path.of(sourceVariant, patch); - shell.execute(new SimpleCommand("patch", pathToTargetVariantCode.toString(), + shell.execute(new GnuPatchCommand("patch", pathToTargetVariantCode.toString(), pathToSourceVariantPatch.toString())); gnuPatchResult = VariationTree.fromFile(Path.of(directory, targetVariant, code)); @@ -251,7 +307,7 @@ public static void generatePatchScenario(VariationDiff spl) // FIXME: how to change directory? final ShellExecutor shell2 = new ShellExecutor(Logger::info, Logger::error, Path.of(directory, targetVariant)); - SimpleCommand command = new SimpleCommand(mpatchPath.toString(), "--strip", "1", "--sourcedir", + MPatchCommand command = new MPatchCommand(mpatchPath.toString(), "--strip", "2", "--sourcedir", Path.of("..", sourceVariant).toString(), "--patchfile", pathToSourceVariantPatch.toString()); shell2.execute(command); mpatchResult = VariationTree.fromFile(Path.of(directory, targetVariant, code)); @@ -268,9 +324,36 @@ public static void generatePatchScenario(VariationDiff spl) // TODO: Read the results of the patchers. The patchers should produce the // target variants as string if they did not fail. - GameEngine.showAndAwaitAll(Show.tree(targetVariantAfter, "ground truth"), Show.tree(mpatchResult, "mpatch"), Show.tree(gnuPatchResult, "gnu patch")); +// GameEngine.showAndAwaitAll(Show.tree(targetVariantAfter, "ground truth"), Show.tree(patchTransformerResult, "patchTransformer"), Show.tree(mpatchResult, "mpatch"), Show.tree(gnuPatchResult, "gnu patch")); // ## 5. Compare the results of patchers here! + + Map configTargetVariantSpecificFeatures = new HashMap<>(); + Map configCrossVariantFeatures = new HashMap<>(); + for (String feature : config1.keySet()) { + if (config2.containsKey(feature) && config2.get(feature) && !config1.get(feature)) { + // feature is only true in target variant + configTargetVariantSpecificFeatures.put(feature, true); + } else { + configTargetVariantSpecificFeatures.put(feature, false); + } + if (config2.containsKey(feature) && config2.get(feature) && config1.get(feature)) { + configCrossVariantFeatures.put(feature, true); + } else { + configCrossVariantFeatures.put(feature, false); + } + } + + Configure configureToTargetVarSpecificFeatures = new Configure(configTargetVariantSpecificFeatures); + Configure configureToCrossVariantSpecificFeatures = new Configure(configCrossVariantFeatures); + + boolean isMpatchCorrect = mpatchResult == null ? false : Patching.arePatchedVariantsEquivalent((VariationTree) sourceVariantAfter, (VariationTree) targetVariantBefore, mpatchResult, configureToCrossVariantSpecificFeatures, configureToTargetVarSpecificFeatures); + boolean isGnuPatchCorrect = gnuPatchResult == null ? false : Patching.arePatchedVariantsEquivalent((VariationTree) sourceVariantAfter, (VariationTree) targetVariantBefore, gnuPatchResult, configureToCrossVariantSpecificFeatures, configureToTargetVarSpecificFeatures); + boolean isPatchTransformerCorrect = patchTransformerResult == null ? false : Patching.arePatchedVariantsEquivalent((VariationTree) sourceVariantAfter, (VariationTree) targetVariantBefore, patchTransformerResult, configureToCrossVariantSpecificFeatures, configureToTargetVarSpecificFeatures); + + System.out.println("mpatch: " + isMpatchCorrect); + System.out.println("GNU patch: " + isGnuPatchCorrect); + System.out.println("patch transformer " + isPatchTransformerCorrect); // TODO } } diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java b/src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java index 73e474df2..8e69e34ef 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/DiffNode.java @@ -831,6 +831,20 @@ public static , L extends Label> DiffNode uncha variationNode.getLabel() ); } + + public static DiffNode unchangedFlat(DiffNode diffNode) { + DiffLineNumber from = diffNode.getFromLine(); + DiffLineNumber to = diffNode.getFromLine(); + + return new DiffNode<>( + DiffType.NON, + diffNode.getNodeType(), + new DiffLineNumber(from.inDiff(), from.beforeEdit(), from.beforeEdit()), + new DiffLineNumber(to.inDiff(), to.beforeEdit(), to.beforeEdit()), + diffNode.getFormula(), + diffNode.getLabel() + ); + } /** * Transforms a {@code VariationNode} into a {@code DiffNode} by diffing {@code variationNode} @@ -854,6 +868,20 @@ public static , L1 extends Label, L2 extends Labe return diffNode; } + + public static DiffNode unchanged( + final Function, DiffNode> convert, + DiffNode diffNodeToChange) { + + var diffNode = convert.apply(diffNodeToChange); + + for (var variationChildNode : diffNodeToChange.getAllChildren()) { + var diffChildNode = unchanged(convert, variationChildNode); + diffChildNode.getDiffType().forAllTimesOfExistence(time -> diffNode.addChild(diffChildNode, time)); + } + + return diffNode; + } public DiffNode deepCopy() { return deepCopy(new HashMap<>()); @@ -956,6 +984,10 @@ public void makeUnchanged() { public static , L extends Label> DiffNode unchanged(VariationNode variationNode) { return unchanged(DiffNode::unchangedFlat, variationNode); } + + public static DiffNode unchanged(DiffNode diffNode) { + return unchanged(DiffNode::unchangedFlat, diffNode); + } /** * Returns true if this subtree is exactly equal to {@code other}. From 10693dda74226774691d8738432cf0b50da41f6e Mon Sep 17 00:00:00 2001 From: piameier Date: Mon, 6 Oct 2025 16:49:36 +0200 Subject: [PATCH 055/162] remove artifact nodes which are children of the root to compare unchanged variant specific features --- .../variation/diff/patching/Patching.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index e4da79e7c..42573e433 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -595,6 +595,9 @@ public static VariationTree parseVariationTreeFromFile(String fi public static boolean arePatchedVariantsEquivalent(VariationTree sourceVariantAfter, VariationTree targetVariantBefore, VariationTree targetVariantAfter, Configure configCrossVariant, Configure configTargetVariantSpecific) { + + + VariationTree sourceVariantAfterRedToCrossVarFeatures = TreeView.tree(sourceVariantAfter, configCrossVariant); VariationTree targetVariantAfterRedToCrossVarFeatures = TreeView.tree(targetVariantAfter, @@ -604,13 +607,17 @@ public static boolean arePatchedVariantsEquivalent(VariationTree configTargetVariantSpecific); VariationTree targetVariantAfterRedToVarSpecificFeatures = TreeView.tree(targetVariantAfter, configTargetVariantSpecific); - -// GameEngine.showAndAwaitAll( -// Show.tree(targetVariantAfterRedToVarSpecificFeatures, "targetVariantAfterRedToVarSpecificFeatures"), -// Show.tree(targetVariantBeforeRedToVarSpecificFeatures, "targetVariantBeforeRedToVarSpecificFeatures"), -// Show.tree(targetVariantAfterRedToCrossVarFeatures, "targetVariantAfterRedToCrossVarFeatures"), -// Show.tree(sourceVariantAfterRedToCrossVarFeatures, "sourceVariantAfterRedToCrossVarFeatures")); - +// remove artifact nodes which are children of the root + targetVariantBeforeRedToVarSpecificFeatures = removeArtifactNodesWhichAreChildrenOfRoot(targetVariantBeforeRedToVarSpecificFeatures); + targetVariantAfterRedToVarSpecificFeatures = removeArtifactNodesWhichAreChildrenOfRoot(targetVariantAfterRedToVarSpecificFeatures); + + + GameEngine.showAndAwaitAll( + Show.tree(targetVariantAfterRedToVarSpecificFeatures, "targetVariantAfterRedToVarSpecificFeatures"), + Show.tree(targetVariantBeforeRedToVarSpecificFeatures, "targetVariantBeforeRedToVarSpecificFeatures"), + Show.tree(targetVariantAfterRedToCrossVarFeatures, "targetVariantAfterRedToCrossVarFeatures"), + Show.tree(sourceVariantAfterRedToCrossVarFeatures, "sourceVariantAfterRedToCrossVarFeatures")); + if (Patching.isSameAs(sourceVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff(), targetVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff()) && Patching.isSameAs(targetVariantBeforeRedToVarSpecificFeatures.toCompletelyUnchangedVariationDiff(), @@ -620,6 +627,17 @@ public static boolean arePatchedVariantsEquivalent(VariationTree return false; } + private static VariationTree removeArtifactNodesWhichAreChildrenOfRoot(VariationTree targetVariantBefore) { + VariationDiff targetVariantBeforeDiff = targetVariantBefore.toCompletelyUnchangedVariationDiff(); + VariationDiff targetVariantBeforeDiffCopy = targetVariantBeforeDiff.deepCopy(); + targetVariantBeforeDiff.forAll(node -> { + if (!node.isRoot() && node.getParent(Time.AFTER).isRoot() && node.isArtifact()) { + targetVariantBeforeDiffCopy.getNodeWithID(node.getID()).drop(); + } + }); + return targetVariantBeforeDiffCopy.project(Time.AFTER); + } + public static boolean comparePatchedVariantWithExpectedResult(VariationTree patchedVariant, VariationTree expectedResult) { return Patching.isSameAs(patchedVariant.toCompletelyUnchangedVariationDiff(), From 831344f19f0471cd82fe7cf5831d61a44e606889 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 17 Oct 2025 14:02:06 +0200 Subject: [PATCH 056/162] unchanged relevance predicate --- .../tree/view/relevance/Unchanged.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/main/java/org/variantsync/diffdetective/variation/tree/view/relevance/Unchanged.java diff --git a/src/main/java/org/variantsync/diffdetective/variation/tree/view/relevance/Unchanged.java b/src/main/java/org/variantsync/diffdetective/variation/tree/view/relevance/Unchanged.java new file mode 100644 index 000000000..9d6f7e1da --- /dev/null +++ b/src/main/java/org/variantsync/diffdetective/variation/tree/view/relevance/Unchanged.java @@ -0,0 +1,60 @@ +package org.variantsync.diffdetective.variation.tree.view.relevance; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; + +import org.variantsync.diffdetective.editclass.proposed.ProposedEditClasses; +import org.variantsync.diffdetective.util.Assert; +import org.variantsync.diffdetective.variation.DiffLinesLabel; +import org.variantsync.diffdetective.variation.Label; +import org.variantsync.diffdetective.variation.diff.DiffNode; +import org.variantsync.diffdetective.variation.diff.Time; +import org.variantsync.diffdetective.variation.diff.VariationDiff; +import org.variantsync.diffdetective.variation.tree.VariationNode; + +import com.github.gumtreediff.actions.Diff; + +public record Unchanged(VariationDiff diff, Time time) implements Relevance { + + @Override + public boolean test(VariationNode t) { + List> tInDiffMatches = diff.computeAllNodesThat(diffNode -> isSameNode(t, diffNode) + && (time == Time.AFTER ? !diffNode.isRem() : !diffNode.isAdd())); + if (tInDiffMatches.isEmpty()) { + return true; + } + DiffNode tInDiff = tInDiffMatches.get(0); + if (tInDiffMatches.size() > 1) { + Map, Integer> map = new HashMap<>(); + for (DiffNode diffNode : tInDiffMatches) { + Integer lineNumberDiffNode = diffNode.getLinesAtTime(time).fromInclusive(); + map.put(diffNode, Math.abs(t.getLineRange().fromInclusive() - lineNumberDiffNode)); + } + List, Integer>> list = new ArrayList<>(map.entrySet()); + list.sort(Entry.comparingByValue()); + tInDiff = list.get(0).getKey(); + } + return tInDiff.isNon() && tInDiff.beforePathEqualsAfterPath(); + } + + @Override + public String getFunctionName() { + // TODO Auto-generated method stub + return "unchanged"; + } + + @Override + public String parametersToString() { + // TODO Auto-generated method stub + return diff.toString(); + } + + public static boolean isSameNode(VariationNode a, DiffNode b) { + return a.getNodeType().equals(b.getNodeType()) && Objects.equals(a.getFormula(), b.getFormula()) + && Label.observablyEqual(a.getLabel(), b.getLabel()); + } +} From e0adf368fc732a55160bc3b8f9f5ce388769f7e4 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 17 Oct 2025 16:36:05 +0200 Subject: [PATCH 057/162] fixed method arePatchedVariantsEquivalent() --- .../variation/diff/patching/Patching.java | 75 ++++++++++--------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 42573e433..b14ea52ba 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -9,6 +9,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.Map.Entry; import java.util.stream.Collectors; import org.eclipse.jgit.diff.DiffAlgorithm; @@ -31,7 +32,12 @@ import org.variantsync.diffdetective.variation.tree.VariationTree; import org.variantsync.diffdetective.variation.tree.view.TreeView; import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; +import org.variantsync.diffdetective.variation.tree.view.relevance.Inverse; import org.variantsync.diffdetective.variation.tree.view.relevance.Relevance; +import org.variantsync.diffdetective.variation.tree.view.relevance.Trace; +import org.variantsync.diffdetective.variation.tree.view.relevance.TraceSub; +import org.variantsync.diffdetective.variation.tree.view.relevance.TraceSup; +import org.variantsync.diffdetective.variation.tree.view.relevance.Unchanged; public class Patching { public static boolean hasSameLabel(DiffNode a, DiffNode b) { @@ -592,55 +598,54 @@ public static VariationTree parseVariationTreeFromFile(String fi return null; } - public static boolean arePatchedVariantsEquivalent(VariationTree sourceVariantAfter, - VariationTree targetVariantBefore, VariationTree targetVariantAfter, - Configure configCrossVariant, Configure configTargetVariantSpecific) { + public static boolean arePatchedVariantsEquivalent(VariationDiff sourceVariantDiff, + VariationTree targetVariantBefore, VariationTree patchedTargetVariant, + Configure configSourceVariant, Configure configTargetVariant) { - - VariationTree sourceVariantAfterRedToCrossVarFeatures = TreeView.tree(sourceVariantAfter, - configCrossVariant); - VariationTree targetVariantAfterRedToCrossVarFeatures = TreeView.tree(targetVariantAfter, - configCrossVariant); - - VariationTree targetVariantBeforeRedToVarSpecificFeatures = TreeView.tree(targetVariantBefore, - configTargetVariantSpecific); - VariationTree targetVariantAfterRedToVarSpecificFeatures = TreeView.tree(targetVariantAfter, - configTargetVariantSpecific); -// remove artifact nodes which are children of the root - targetVariantBeforeRedToVarSpecificFeatures = removeArtifactNodesWhichAreChildrenOfRoot(targetVariantBeforeRedToVarSpecificFeatures); - targetVariantAfterRedToVarSpecificFeatures = removeArtifactNodesWhichAreChildrenOfRoot(targetVariantAfterRedToVarSpecificFeatures); - + VariationTree sourceVariantAfter = sourceVariantDiff.project(Time.AFTER); + VariationTree sourceVariantAfterRedToCrossVarFeatures = TreeView.tree(sourceVariantAfter, configTargetVariant); + VariationTree targetVariantAfterRedToCrossVarFeatures = TreeView.tree(patchedTargetVariant, configSourceVariant); - GameEngine.showAndAwaitAll( - Show.tree(targetVariantAfterRedToVarSpecificFeatures, "targetVariantAfterRedToVarSpecificFeatures"), - Show.tree(targetVariantBeforeRedToVarSpecificFeatures, "targetVariantBeforeRedToVarSpecificFeatures"), - Show.tree(targetVariantAfterRedToCrossVarFeatures, "targetVariantAfterRedToCrossVarFeatures"), - Show.tree(sourceVariantAfterRedToCrossVarFeatures, "sourceVariantAfterRedToCrossVarFeatures")); + VariationTree patchedTargetVariantRedToUnchanged = TreeView.tree(null, new Unchanged(sourceVariantDiff, Time.AFTER)); + VariationTree targetVariantBeforeRedToUnchanged = TreeView.tree(null, new Unchanged(sourceVariantDiff, Time.BEFORE)); if (Patching.isSameAs(sourceVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff(), targetVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff()) - && Patching.isSameAs(targetVariantBeforeRedToVarSpecificFeatures.toCompletelyUnchangedVariationDiff(), - targetVariantAfterRedToVarSpecificFeatures.toCompletelyUnchangedVariationDiff())) { + && Patching.isSameAs(patchedTargetVariantRedToUnchanged.toCompletelyUnchangedVariationDiff(), + targetVariantBeforeRedToUnchanged.toCompletelyUnchangedVariationDiff())) { return true; } return false; } - private static VariationTree removeArtifactNodesWhichAreChildrenOfRoot(VariationTree targetVariantBefore) { - VariationDiff targetVariantBeforeDiff = targetVariantBefore.toCompletelyUnchangedVariationDiff(); - VariationDiff targetVariantBeforeDiffCopy = targetVariantBeforeDiff.deepCopy(); - targetVariantBeforeDiff.forAll(node -> { - if (!node.isRoot() && node.getParent(Time.AFTER).isRoot() && node.isArtifact()) { - targetVariantBeforeDiffCopy.getNodeWithID(node.getID()).drop(); - } - }); - return targetVariantBeforeDiffCopy.project(Time.AFTER); - } - public static boolean comparePatchedVariantWithExpectedResult(VariationTree patchedVariant, VariationTree expectedResult) { return Patching.isSameAs(patchedVariant.toCompletelyUnchangedVariationDiff(), expectedResult.toCompletelyUnchangedVariationDiff()); } + + public static void testSomething(VariationDiff diff, VariationTree patchedTree, VariationTree targetVariant) { + Configure aWithoutb = new Configure(new Literal("defined(FeatureB)", false)); + +// VariationTree view1 = TreeView.tree(tree, new Configure(new Literal("defined(FeatureB)", true))); +// VariationTree view2 = TreeView.tree(tree, new TraceSup(new Literal("defined(FeatureB)", true))); +// VariationTree view3 = TreeView.tree(tree, config2); + Inverse notAWithoutB = new Inverse(aWithoutb); + VariationTree view_b = TreeView.tree(patchedTree, notAWithoutB); + Unchanged notAddedInA = new Unchanged(diff, Time.BEFORE); + Unchanged notRemovedInA = new Unchanged(diff, Time.AFTER); + VariationTree unchangedView = TreeView.tree(patchedTree, notRemovedInA); + VariationTree view = TreeView.tree(targetVariant, notAddedInA); + System.out.println(Patching.isSameAs(unchangedView.toCompletelyUnchangedVariationDiff(), view.toCompletelyUnchangedVariationDiff())); + GameEngine.showAndAwaitAll(Show.tree(patchedTree, "B'"), Show.tree(view, "B unchanged = " + notAddedInA), + Show.diff(diff, "p_V"), Show.tree(unchangedView, "B'' unchanged = " + notRemovedInA) +// Show.tree(view2, "view2"), Show.tree(view3, "view3"), Show.tree(view, "view") + ); +// VariationTree newTree = TreeView.tree(tree, config); +// GameEngine.showAndAwaitAll(Show.tree(tree, "tree"), Show.tree(newTree, "newTree")); +// VariationTree withA = TreeView.tree(tree, new Configure(new Literal("defined(A)", true))); +// VariationTree withoutA = TreeView.tree(tree, new Configure(new Literal("defined(A)", false))); +// GameEngine.showAndAwaitAll(Show.tree(tree), Show.tree(withA, "withA"), Show.tree(withoutA, "withoutA")); + } } From c1287d55cc19fb8d7994d9281280c469c678e429 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 17 Oct 2025 16:43:58 +0200 Subject: [PATCH 058/162] fixed method arePatchedVariantsEquivalent() --- .../diffdetective/variation/diff/patching/Patching.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index b14ea52ba..02dac9cca 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -607,8 +607,8 @@ public static boolean arePatchedVariantsEquivalent(VariationDiff VariationTree sourceVariantAfterRedToCrossVarFeatures = TreeView.tree(sourceVariantAfter, configTargetVariant); VariationTree targetVariantAfterRedToCrossVarFeatures = TreeView.tree(patchedTargetVariant, configSourceVariant); - VariationTree patchedTargetVariantRedToUnchanged = TreeView.tree(null, new Unchanged(sourceVariantDiff, Time.AFTER)); - VariationTree targetVariantBeforeRedToUnchanged = TreeView.tree(null, new Unchanged(sourceVariantDiff, Time.BEFORE)); + VariationTree patchedTargetVariantRedToUnchanged = TreeView.tree(patchedTargetVariant, new Unchanged(sourceVariantDiff, Time.AFTER)); + VariationTree targetVariantBeforeRedToUnchanged = TreeView.tree(targetVariantBefore, new Unchanged(sourceVariantDiff, Time.BEFORE)); if (Patching.isSameAs(sourceVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff(), targetVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff()) From a798ab837de167aaf62b3a6c3f06be8cb57d026e Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 17 Oct 2025 17:42:58 +0200 Subject: [PATCH 059/162] test equivalence for figure in master thesis --- .../variation/diff/patching/Patching.java | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java index 02dac9cca..5c29dc1af 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/patching/Patching.java @@ -600,7 +600,7 @@ public static VariationTree parseVariationTreeFromFile(String fi public static boolean arePatchedVariantsEquivalent(VariationDiff sourceVariantDiff, VariationTree targetVariantBefore, VariationTree patchedTargetVariant, - Configure configSourceVariant, Configure configTargetVariant) { + Configure configSourceVariant, Configure configTargetVariant, boolean debug) { VariationTree sourceVariantAfter = sourceVariantDiff.project(Time.AFTER); @@ -610,6 +610,12 @@ public static boolean arePatchedVariantsEquivalent(VariationDiff VariationTree patchedTargetVariantRedToUnchanged = TreeView.tree(patchedTargetVariant, new Unchanged(sourceVariantDiff, Time.AFTER)); VariationTree targetVariantBeforeRedToUnchanged = TreeView.tree(targetVariantBefore, new Unchanged(sourceVariantDiff, Time.BEFORE)); + if (debug) { + GameEngine.showAndAwaitAll(Show.diff(sourceVariantDiff, "p_A"), Show.tree(targetVariantBefore, "B"), Show.tree(patchedTargetVariant, "B'"), + Show.tree(targetVariantBeforeRedToUnchanged, "unchanged(B)"), Show.tree(patchedTargetVariantRedToUnchanged, "unchanged(B')"), + Show.tree(sourceVariantAfterRedToCrossVarFeatures, "view(A, configure(B)=V'"), Show.tree(targetVariantAfterRedToCrossVarFeatures, "view(B', configure(A)")); + } + if (Patching.isSameAs(sourceVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff(), targetVariantAfterRedToCrossVarFeatures.toCompletelyUnchangedVariationDiff()) && Patching.isSameAs(patchedTargetVariantRedToUnchanged.toCompletelyUnchangedVariationDiff(), @@ -626,26 +632,24 @@ public static boolean comparePatchedVariantWithExpectedResult(VariationTree diff, VariationTree patchedTree, VariationTree targetVariant) { - Configure aWithoutb = new Configure(new Literal("defined(FeatureB)", false)); + Map featuresSource = new HashMap<>(); + Map featuresTarget = new HashMap<>(); + featuresSource.put("defined(Feature1)", true); + featuresSource.put("defined(Feature2)", true); + featuresSource.put("defined(FeatureB)", false); + featuresTarget.put("defined(Feature1)", true); + featuresTarget.put("defined(Feature2)", true); + featuresTarget.put("defined(FeatureB)", true); + Configure configSource = new Configure(featuresSource); + Configure configTarget = new Configure(featuresTarget); + + try { + VariationTree patched = Patching.patch(diff, targetVariant, false, true).project(Time.AFTER); + System.out.println(Patching.arePatchedVariantsEquivalent(diff, targetVariant, patched, configSource, configTarget, true)); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } -// VariationTree view1 = TreeView.tree(tree, new Configure(new Literal("defined(FeatureB)", true))); -// VariationTree view2 = TreeView.tree(tree, new TraceSup(new Literal("defined(FeatureB)", true))); -// VariationTree view3 = TreeView.tree(tree, config2); - Inverse notAWithoutB = new Inverse(aWithoutb); - VariationTree view_b = TreeView.tree(patchedTree, notAWithoutB); - Unchanged notAddedInA = new Unchanged(diff, Time.BEFORE); - Unchanged notRemovedInA = new Unchanged(diff, Time.AFTER); - VariationTree unchangedView = TreeView.tree(patchedTree, notRemovedInA); - VariationTree view = TreeView.tree(targetVariant, notAddedInA); - System.out.println(Patching.isSameAs(unchangedView.toCompletelyUnchangedVariationDiff(), view.toCompletelyUnchangedVariationDiff())); - GameEngine.showAndAwaitAll(Show.tree(patchedTree, "B'"), Show.tree(view, "B unchanged = " + notAddedInA), - Show.diff(diff, "p_V"), Show.tree(unchangedView, "B'' unchanged = " + notRemovedInA) -// Show.tree(view2, "view2"), Show.tree(view3, "view3"), Show.tree(view, "view") - ); -// VariationTree newTree = TreeView.tree(tree, config); -// GameEngine.showAndAwaitAll(Show.tree(tree, "tree"), Show.tree(newTree, "newTree")); -// VariationTree withA = TreeView.tree(tree, new Configure(new Literal("defined(A)", true))); -// VariationTree withoutA = TreeView.tree(tree, new Configure(new Literal("defined(A)", false))); -// GameEngine.showAndAwaitAll(Show.tree(tree), Show.tree(withA, "withA"), Show.tree(withoutA, "withoutA")); } } From bea648dcbb1347cbe226ac0eb230981078ff6196 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 17 Oct 2025 18:48:34 +0200 Subject: [PATCH 060/162] adjusted generator and fixed gnupatch and mpatch commands --- .../experiments/thesis_pm/Generator.java | 142 +++++++++--------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java index 2710c64e2..fd95a9a8c 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Random; import java.util.Set; import org.tinylog.Logger; @@ -37,6 +38,10 @@ import org.variantsync.diffdetective.variation.tree.view.relevance.Configure; public class Generator { + + private static Random rand1 = new Random(2025); + private static Random rand2 = new Random(9); + /** * This function mutates a boolean assignment by flipping some values by chance. * This function is pure: It creates a new map and the input map is left @@ -52,7 +57,7 @@ public static Map mutateByWeightedCoinFlip(final Map final Map mutant = new HashMap<>(); for (Entry e : a.entrySet()) { - mutant.put(e.getKey(), Math.random() <= probability ? !e.getValue() : e.getValue()); + mutant.put(e.getKey(), rand2.nextDouble() <= probability ? !e.getValue() : e.getValue()); } return mutant; @@ -73,7 +78,7 @@ public static Map randomPartition(Set s, double probability) final Map subsets = new HashMap<>(); for (T t : s) { - subsets.put(t, Math.random() <= probability); + subsets.put(t, rand1.nextDouble() <= probability); } return subsets; } @@ -107,7 +112,7 @@ public static void writeToFile(String text, Path filePath) { i.printStackTrace(); } } - + public static void writeToFile(List text, Path filePath) { try { File f = new File(filePath.toUri()); @@ -115,9 +120,7 @@ public static void writeToFile(List text, Path filePath) { BufferedWriter myWriter = new BufferedWriter(new FileWriter(f)); for (int i = 0; i < text.size(); i++) { myWriter.write(text.get(i)); - if (i != text.size() - 1) { - myWriter.newLine(); - } + myWriter.newLine(); } myWriter.close(); } catch (IOException i) { @@ -162,12 +165,12 @@ public static void generatePatchScenario(VariationDiff spl) final VariationDiff sourcePatch = DiffView.optimized(spl, configureTo1); // input patch to apply to the // target variant VariationDiff targetPatch = DiffView.optimized(spl, configureTo2); // ground truth for target patch; - // this is the "perfect" target - // patch - + // this is the "perfect" target + // patch + VariationDiff targetView = DiffView.optimized(targetPatch.deepCopy(), configureTo1); VariationDiff targetPatchModified = targetPatch.deepCopy(); - GameEngine.showAndAwaitAll(Show.diff(sourcePatch, "source patch"), Show.diff(targetPatch, "target patch"), Show.diff(targetView, "target view")); + targetPatch.forAll(node -> { if (targetView.getNodeWithID(node.getID()) == null && !node.isNon()) { node = targetPatchModified.getNodeWithID(node.getID()); @@ -176,16 +179,8 @@ public static void generatePatchScenario(VariationDiff spl) if (node.isRem()) { if (node.getParent(Time.BEFORE) != null && node.getParent(Time.BEFORE).isNon()) { int index = node.getParent(Time.BEFORE).indexOfChild(node, Time.BEFORE); - node.getParent(Time.BEFORE).insertChild(newNode, index, Time.BEFORE); - node.getParent(Time.BEFORE).insertChild(newNode, index, Time.AFTER); - } - } - if (node.isAdd()) { - - if (node.getParent(Time.AFTER) != null && node.getParent(Time.AFTER).isNon()) { - int index = node.getParent(Time.AFTER).indexOfChild(node, Time.AFTER); - node.getParent(Time.AFTER).insertChild(newNode, index, Time.BEFORE); - node.getParent(Time.AFTER).insertChild(newNode, index, Time.AFTER); + node.getParent(Time.BEFORE).insertChild(newNode, index, Time.BEFORE); + node.getParent(Time.BEFORE).insertChild(newNode, index, Time.AFTER); } } node.drop(); @@ -193,8 +188,8 @@ public static void generatePatchScenario(VariationDiff spl) } }); targetPatch = targetPatchModified; - GameEngine.showAndAwaitAll(Show.diff(sourcePatch), Show.diff(targetPatch), Show.diff(targetView), Show.diff(targetPatchModified)); - + GameEngine.showAndAwaitAll(Show.diff(sourcePatch, "source patch"), Show.diff(targetPatch, "target patch")); + // FIXME: Maybe we want to distinguish cases where one of the patches (or both) // are empty (i.e., noop / id)? @@ -206,12 +201,12 @@ public static void generatePatchScenario(VariationDiff spl) // look like // GameEngine.showAndAwaitAll(Show.diff(spl)); - GameEngine.showAndAwaitAll(Show.diff(sourcePatch, "Source Patch " + config1), - Show.diff(targetPatch, "Target Patch " + config2)); -// GameEngine.showAndAwaitAll(Show.tree(sourceVariantBefore, "Source Before " + config1), -// Show.tree(sourceVariantAfter, "Source After " + config1), -// Show.tree(targetVariantBefore, "Target Before " + config2), -// Show.tree(targetVariantAfter, "Target After" + config2)); +// GameEngine.showAndAwaitAll(Show.diff(sourcePatch, "Source Patch " + config1), +// Show.diff(targetPatch, "Target Patch " + config2)); + GameEngine.showAndAwaitAll(Show.tree(sourceVariantBefore, "Source Before " + config1), + Show.tree(sourceVariantAfter, "Source After " + config1), + Show.tree(targetVariantBefore, "Target Before " + config2), + Show.tree(targetVariantAfter, "Target After" + config2)); // ## 3. To use command-line patchers such as GNU patch and mpatch, we need to // write our variants to disk. @@ -226,8 +221,6 @@ public static void generatePatchScenario(VariationDiff spl) logDiff("Target Before:", targetVariantCodeBefore); logDiff("Target After:", targetVariantCodeAfter); - // TODO: write the code to disk at a reasonable location - String diffDetective = "DiffDetective"; String directory = "experiment"; String sourceVariant = "sourceVariant"; String version1 = "version1"; @@ -236,40 +229,41 @@ public static void generatePatchScenario(VariationDiff spl) String code = "code.txt"; String patch = "patch.txt"; - File f = new File(Path.of(directory).toUri()); - deleteDirectory(f); - f.delete(); + File f = new File(Path.of(directory).toUri()); + deleteDirectory(f); + f.delete(); - if (!(new File(Path.of(directory, targetVariant).toUri())).mkdirs() || - !(new File(Path.of(directory, sourceVariant).toUri())).mkdir()) { - throw new Exception("Failed to create directories"); - } - if (!(new File(Path.of(directory, sourceVariant, version1).toUri())).mkdirs() || - !(new File(Path.of(directory, sourceVariant, version2).toUri())).mkdir()) { - throw new Exception("Failed to create directories"); - } + if (!(new File(Path.of(directory, targetVariant).toUri())).mkdirs() + || !(new File(Path.of(directory, sourceVariant).toUri())).mkdir()) { + throw new Exception("Failed to create directories"); + } + if (!(new File(Path.of(directory, sourceVariant, version1).toUri())).mkdirs() + || !(new File(Path.of(directory, sourceVariant, version2).toUri())).mkdir()) { + throw new Exception("Failed to create directories"); + } Path sourceVariantBeforePath = Path.of(directory, sourceVariant, version1, code); Path sourceVariantAfterPath = Path.of(directory, sourceVariant, version2, code); Path targetVariantBeforePath = Path.of(directory, targetVariant, code); - Path patchPath = Path.of(directory, sourceVariant, patch); - writeToFile(sourceVariantCodeBefore, sourceVariantBeforePath); - writeToFile(sourceVariantCodeAfter, sourceVariantAfterPath); - writeToFile(targetVariantCodeBefore, targetVariantBeforePath); + Path patchPath = Path.of(directory, targetVariant, patch); + writeToFile(sourceVariantCodeBefore, sourceVariantBeforePath); + writeToFile(sourceVariantCodeAfter, sourceVariantAfterPath); + writeToFile(targetVariantCodeBefore, targetVariantBeforePath); // writeToFile(targetVariantCodeAfter, targetVariantAfterPath); - final ShellExecutor shell = new ShellExecutor(Logger::info, Logger::error, Path.of(directory)); // maybe we have + final ShellExecutor shell = new ShellExecutor(Logger::info, Logger::error, Path.of(directory, sourceVariant)); // maybe we have // to specify // the working // directory as // third // argument here try { - Path pathToVersion1Dir = Path.of(sourceVariant, version1); - Path pathToVersion2Dir = Path.of(sourceVariant, version2); + Path pathToVersion1Dir = Path.of(version1); + Path pathToVersion2Dir = Path.of(version2); writeToFile(shell.execute( - new DiffCommand("diff", "-Naur", pathToVersion1Dir.toString(), pathToVersion2Dir.toString())), patchPath); - + new DiffCommand("diff", "-Naur", pathToVersion1Dir.toString(), pathToVersion2Dir.toString())), + patchPath); + // System.out.println(list); } catch (ShellException e) { // System.out.println(e); @@ -280,38 +274,38 @@ public static void generatePatchScenario(VariationDiff spl) // TODO: Run Pia's new patcher here and store the result. VariationTree patchTransformerResult = null; try { - VariationDiff diff = Patching.patch((VariationDiff) sourcePatch, (VariationTree) targetVariantBefore, false, true); + VariationDiff diff = Patching.patch((VariationDiff) sourcePatch, + (VariationTree) targetVariantBefore, false, true); patchTransformerResult = diff.project(Time.AFTER); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } - + VariationTree gnuPatchResult = null; VariationTree mpatchResult = null; // TODO: run mpatch and gnu patch. Here is a sketch for this can be done. try { // TODO: configure GNU patch - Path pathToTargetVariantCode = Path.of(targetVariant, code); - Path pathToSourceVariantPatch = Path.of(sourceVariant, patch); + Path pathToTargetVariantCode = Path.of("..", targetVariant, code); + Path pathToSourceVariantPatch = Path.of("..", targetVariant, patch); shell.execute(new GnuPatchCommand("patch", pathToTargetVariantCode.toString(), pathToSourceVariantPatch.toString())); gnuPatchResult = VariationTree.fromFile(Path.of(directory, targetVariant, code)); - + // reset target variant writeToFile(targetVariantCodeBefore, targetVariantBeforePath); - + // TODO: configure mpatch Path mpatchPath = Path.of("..", "..", "..", "mpatch", "target", "debug", "mpatch"); - pathToSourceVariantPatch = Path.of("..", sourceVariant, patch); // FIXME: how to change directory? final ShellExecutor shell2 = new ShellExecutor(Logger::info, Logger::error, Path.of(directory, targetVariant)); - MPatchCommand command = new MPatchCommand(mpatchPath.toString(), "--strip", "2", "--sourcedir", - Path.of("..", sourceVariant).toString(), "--patchfile", pathToSourceVariantPatch.toString()); + MPatchCommand command = new MPatchCommand(mpatchPath.toString(), "--strip", "1", "--sourcedir", + Path.of("..", sourceVariant, version1).toString(), "--patchfile", patch); shell2.execute(command); mpatchResult = VariationTree.fromFile(Path.of(directory, targetVariant, code)); - + } catch (ShellException e) { // FIXME: When a shell exception occurs, we know that patching failed. // Either there is a bug or the patcher was not successful! @@ -321,13 +315,13 @@ public static void generatePatchScenario(VariationDiff spl) // We have to distinguish patch success from patch failure anyway somewhere. Logger.error(e); } - + // TODO: Read the results of the patchers. The patchers should produce the // target variants as string if they did not fail. -// GameEngine.showAndAwaitAll(Show.tree(targetVariantAfter, "ground truth"), Show.tree(patchTransformerResult, "patchTransformer"), Show.tree(mpatchResult, "mpatch"), Show.tree(gnuPatchResult, "gnu patch")); + GameEngine.showAndAwaitAll(Show.tree(targetVariantAfter, "ground truth"), Show.tree(patchTransformerResult, "patchTransformer"), Show.tree(mpatchResult, "mpatch"), Show.tree(gnuPatchResult, "gnu patch")); // ## 5. Compare the results of patchers here! - + Map configTargetVariantSpecificFeatures = new HashMap<>(); Map configCrossVariantFeatures = new HashMap<>(); for (String feature : config1.keySet()) { @@ -343,14 +337,20 @@ public static void generatePatchScenario(VariationDiff spl) configCrossVariantFeatures.put(feature, false); } } - - Configure configureToTargetVarSpecificFeatures = new Configure(configTargetVariantSpecificFeatures); - Configure configureToCrossVariantSpecificFeatures = new Configure(configCrossVariantFeatures); - - boolean isMpatchCorrect = mpatchResult == null ? false : Patching.arePatchedVariantsEquivalent((VariationTree) sourceVariantAfter, (VariationTree) targetVariantBefore, mpatchResult, configureToCrossVariantSpecificFeatures, configureToTargetVarSpecificFeatures); - boolean isGnuPatchCorrect = gnuPatchResult == null ? false : Patching.arePatchedVariantsEquivalent((VariationTree) sourceVariantAfter, (VariationTree) targetVariantBefore, gnuPatchResult, configureToCrossVariantSpecificFeatures, configureToTargetVarSpecificFeatures); - boolean isPatchTransformerCorrect = patchTransformerResult == null ? false : Patching.arePatchedVariantsEquivalent((VariationTree) sourceVariantAfter, (VariationTree) targetVariantBefore, patchTransformerResult, configureToCrossVariantSpecificFeatures, configureToTargetVarSpecificFeatures); - + + boolean isMpatchCorrect = mpatchResult == null ? false + : Patching.arePatchedVariantsEquivalent((VariationDiff) sourcePatch, + (VariationTree) targetVariantBefore, mpatchResult, + configureTo1, configureTo2, false); + boolean isGnuPatchCorrect = gnuPatchResult == null ? false + : Patching.arePatchedVariantsEquivalent((VariationDiff) sourcePatch, + (VariationTree) targetVariantBefore, gnuPatchResult, + configureTo1, configureTo2, false); + boolean isPatchTransformerCorrect = patchTransformerResult == null ? false + : Patching.arePatchedVariantsEquivalent((VariationDiff) sourcePatch, + (VariationTree) targetVariantBefore, patchTransformerResult, + configureTo1, configureTo2, false); + System.out.println("mpatch: " + isMpatchCorrect); System.out.println("GNU patch: " + isGnuPatchCorrect); System.out.println("patch transformer " + isPatchTransformerCorrect); From 386b37094c2e136b229c8497023ee317dac6af64 Mon Sep 17 00:00:00 2001 From: piameier Date: Fri, 17 Oct 2025 18:50:03 +0200 Subject: [PATCH 061/162] workaround: changed to LF lineendings --- .../java/org/variantsync/diffdetective/util/StringUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/variantsync/diffdetective/util/StringUtils.java b/src/main/java/org/variantsync/diffdetective/util/StringUtils.java index 868ab08f8..07c563164 100644 --- a/src/main/java/org/variantsync/diffdetective/util/StringUtils.java +++ b/src/main/java/org/variantsync/diffdetective/util/StringUtils.java @@ -6,7 +6,7 @@ /** A collection of useful utilities related to string processing. */ public class StringUtils { /** An operating system independent line break used in almost all internal strings. */ - public final static String LINEBREAK = "\r\n"; + public final static String LINEBREAK = "\n"; /** A regex to identify line breaks of any operating system .*/ public final static Pattern LINEBREAK_REGEX = Pattern.compile("\\r\\n|\\r|\\n"); From 80561b05f68b6f9a1f0f08944100c5acc994794e Mon Sep 17 00:00:00 2001 From: piameier Date: Thu, 23 Oct 2025 22:15:38 +0200 Subject: [PATCH 062/162] fixed bug in EliminateEmptyAlternatives --- .../transform/EliminateEmptyAlternatives.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/variation/diff/transform/EliminateEmptyAlternatives.java b/src/main/java/org/variantsync/diffdetective/variation/diff/transform/EliminateEmptyAlternatives.java index 009e67b71..20917716b 100644 --- a/src/main/java/org/variantsync/diffdetective/variation/diff/transform/EliminateEmptyAlternatives.java +++ b/src/main/java/org/variantsync/diffdetective/variation/diff/transform/EliminateEmptyAlternatives.java @@ -2,11 +2,17 @@ package org.variantsync.diffdetective.variation.diff.transform; import org.prop4j.Node; +import org.variantsync.diffdetective.variation.DiffLinesLabel; import org.variantsync.diffdetective.variation.Label; +import org.variantsync.diffdetective.variation.diff.DiffNode; +import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.tree.VariationTree; import org.variantsync.diffdetective.variation.tree.VariationTreeNode; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import static org.variantsync.diffdetective.util.fide.FormulaUtils.*; @@ -37,18 +43,19 @@ */ public class EliminateEmptyAlternatives implements Transformer> { private void elim(VariationTreeNode subtree) { + List> nodesToDrop = new ArrayList<>(); // We simplify only annotations. if (!subtree.isAnnotation()) return; - + final List> children = subtree.getChildren(); // When there are no children, 'subtree' is an empty annotation that can be eliminated. if (children.isEmpty()) { - subtree.drop(); + nodesToDrop.add(subtree); } // When there is exactly one child and that child is an 'else' or 'elif' we can simplify that nesting. else if (children.size() == 1) { - final VariationTreeNode child = children.getFirst(); + final VariationTreeNode child = children.get(0); if ((subtree.isIf() || subtree.isElif()) && (child.isElif() || child.isElse())) { // determine new feaure mapping @@ -59,8 +66,8 @@ else if (children.size() == 1) { subtree.setFormula(newFormula); // simplify tree - child.drop(); - subtree.stealChildrenOf(child); + nodesToDrop.add(child); + subtree.stealChildrenOf(child); } } } @@ -68,5 +75,9 @@ else if (children.size() == 1) { @Override public void transform(VariationTree tree) { tree.forAllPostorder(this::elim); + for (VariationTreeNode node : nodesToDrop) { + node.drop(); + } + } } From dd34a35cef2d091cae73418f548d27b48a28bc1b Mon Sep 17 00:00:00 2001 From: piameier Date: Thu, 23 Oct 2025 22:16:29 +0200 Subject: [PATCH 063/162] eliminate empty alternatives after variant configurations --- .../experiments/thesis_pm/Generator.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java index fd95a9a8c..c7bf057ba 100644 --- a/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java +++ b/src/main/java/org/variantsync/diffdetective/experiments/thesis_pm/Generator.java @@ -32,6 +32,7 @@ import org.variantsync.diffdetective.variation.diff.Time; import org.variantsync.diffdetective.variation.diff.VariationDiff; import org.variantsync.diffdetective.variation.diff.patching.Patching; +import org.variantsync.diffdetective.variation.diff.transform.EliminateEmptyAlternatives; import org.variantsync.diffdetective.variation.diff.view.DiffView; import org.variantsync.diffdetective.variation.tree.VariationTree; import org.variantsync.diffdetective.variation.tree.view.TreeView; @@ -167,11 +168,23 @@ public static void generatePatchScenario(VariationDiff spl) VariationDiff targetPatch = DiffView.optimized(spl, configureTo2); // ground truth for target patch; // this is the "perfect" target // patch - - VariationDiff targetView = DiffView.optimized(targetPatch.deepCopy(), configureTo1); - VariationDiff targetPatchModified = targetPatch.deepCopy(); - - targetPatch.forAll(node -> { + + GameEngine.showAndAwaitAll(Show.diff(sourcePatch, "configured to source"), Show.diff(targetPatch, "configured to target")); + + + VariationTree before = targetPatch.project(Time.BEFORE); + new EliminateEmptyAlternatives<>().transform((VariationTree