From e6c61d1b1dc45446ba4311ca8d8d960288cdc5c5 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 13:01:31 +0200 Subject: [PATCH 01/14] Give variables n1 and n2 more self-explaining names --- .../ZhangUnorderedTreeEditDistance.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java index 04d9affce..5cd1ddf66 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java @@ -401,11 +401,13 @@ private NodeMapping< T > minCostMaxFlow( final Tree< T > forest1, final Tree< T network.addVertices( childrenForest1 ); network.addVertices( childrenForest2 ); - int n1 = childrenForest1.size(); - int n2 = childrenForest2.size(); - network.addEdge( source, emptyTree1, n2 - Math.min( n1, n2 ), 0 ); - network.addEdge( emptyTree1, emptyTree2, Math.max( n1, n2 ) - Math.min( n1, n2 ), 0 ); // this edge is not needed - network.addEdge( emptyTree2, sink, n1 - Math.min( n1, n2 ), 0 ); + int numberOfChildrenForest1 = childrenForest1.size(); + int numberOfChildrenForest2 = childrenForest2.size(); + int minNumberOfChildren = Math.min( numberOfChildrenForest1, numberOfChildrenForest2 ); + int maxNumberOfChildren = Math.max( numberOfChildrenForest1, numberOfChildrenForest2 ); + network.addEdge( source, emptyTree1, numberOfChildrenForest2 - minNumberOfChildren, 0 ); + network.addEdge( emptyTree1, emptyTree2, maxNumberOfChildren - minNumberOfChildren, 0 ); // this edge is not needed + network.addEdge( emptyTree2, sink, numberOfChildrenForest1 - minNumberOfChildren, 0 ); for ( Tree< T > child1 : childrenForest1 ) { From a08ef0806ca7dca8dd48162afb34469f23ca9e10 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 13:02:42 +0200 Subject: [PATCH 02/14] Remove unneeded edge in flow network --- .../mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java index 5cd1ddf66..9613c4a63 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java @@ -404,9 +404,7 @@ private NodeMapping< T > minCostMaxFlow( final Tree< T > forest1, final Tree< T int numberOfChildrenForest1 = childrenForest1.size(); int numberOfChildrenForest2 = childrenForest2.size(); int minNumberOfChildren = Math.min( numberOfChildrenForest1, numberOfChildrenForest2 ); - int maxNumberOfChildren = Math.max( numberOfChildrenForest1, numberOfChildrenForest2 ); network.addEdge( source, emptyTree1, numberOfChildrenForest2 - minNumberOfChildren, 0 ); - network.addEdge( emptyTree1, emptyTree2, maxNumberOfChildren - minNumberOfChildren, 0 ); // this edge is not needed network.addEdge( emptyTree2, sink, numberOfChildrenForest1 - minNumberOfChildren, 0 ); for ( Tree< T > child1 : childrenForest1 ) From c9a247a9b3e0671e2f3de9c306689a8215bff695 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 13:05:22 +0200 Subject: [PATCH 03/14] Separate building flow network from solving it and collecting results * This reduces the cognitive complexity of minCostMaxFlow method to be below a suggested threshold of 15 --- .../ZhangUnorderedTreeEditDistance.java | 47 +++++++++++-------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java index 9613c4a63..91651cc91 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java @@ -396,6 +396,33 @@ private NodeMapping< T > minCostMaxFlow( final Tree< T > forest1, final Tree< T String emptyTree1 = "empty1"; String emptyTree2 = "empty2"; + FlowNetwork network = buildFlowNetwork( source, sink, emptyTree1, emptyTree2, childrenForest1, childrenForest2 ); + + network.solveMaxFlowMinCost( source, sink ); + + ArrayList< NodeMapping< T > > childMappings = new ArrayList<>(); + + for ( Tree< T > child1 : childrenForest1 ) + if ( isFlowEqualToOne( network.getFlow( child1, emptyTree2 ) ) ) + childMappings.add( NodeMappings.empty( deleteCosts.get( child1 ).treeCost ) ); + + for ( Tree< T > child2 : childrenForest2 ) + if ( isFlowEqualToOne( network.getFlow( emptyTree1, child2 ) ) ) + childMappings.add( NodeMappings.empty( insertCosts.get( child2 ).treeCost ) ); + + for ( Tree< T > child1 : childrenForest1 ) + for ( Tree< T > child2 : childrenForest2 ) + if ( isFlowEqualToOne( network.getFlow( child1, child2 ) ) ) + childMappings.add( treeMapping( child1, child2 ) ); + + return NodeMappings.compose( childMappings ); + } + + private FlowNetwork buildFlowNetwork( + String source, String sink, String emptyTree1, String emptyTree2, Collection< Tree< T > > childrenForest1, + Collection< Tree< T > > childrenForest2 + ) + { FlowNetwork network = new FlowNetwork(); network.addVertices( Arrays.asList( source, sink, emptyTree1, emptyTree2 ) ); network.addVertices( childrenForest1 ); @@ -420,25 +447,7 @@ private NodeMapping< T > minCostMaxFlow( final Tree< T > forest1, final Tree< T network.addEdge( child2, sink, 1, 0 ); network.addEdge( emptyTree1, child2, 1, insertCosts.get( child2 ).treeCost ); } - - network.solveMaxFlowMinCost( source, sink ); - - ArrayList< NodeMapping< T > > childMappings = new ArrayList<>(); - - for ( Tree< T > child1 : childrenForest1 ) - if ( isFlowEqualToOne( network.getFlow( child1, emptyTree2 ) ) ) - childMappings.add( NodeMappings.empty( deleteCosts.get( child1 ).treeCost ) ); - - for ( Tree< T > child2 : childrenForest2 ) - if ( isFlowEqualToOne( network.getFlow( emptyTree1, child2 ) ) ) - childMappings.add( NodeMappings.empty( insertCosts.get( child2 ).treeCost ) ); - - for ( Tree< T > child1 : childrenForest1 ) - for ( Tree< T > child2 : childrenForest2 ) - if ( isFlowEqualToOne( network.getFlow( child1, child2 ) ) ) - childMappings.add( treeMapping( child1, child2 ) ); - - return NodeMappings.compose( childMappings ); + return network; } /** From 8393ff1bd6b2b71c7aad7bc0918e63f0040ecf2b Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 13:07:08 +0200 Subject: [PATCH 04/14] Use shortened version to add vertices in FlowNetwork --- .../java/org/mastodon/mamut/treesimilarity/FlowNetwork.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/FlowNetwork.java b/src/main/java/org/mastodon/mamut/treesimilarity/FlowNetwork.java index b8b47167a..ab5194193 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/FlowNetwork.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/FlowNetwork.java @@ -19,8 +19,7 @@ class FlowNetwork public void addVertices( Collection< ? > vertices ) { - for ( Object v : vertices ) - graph.addVertex( v ); + vertices.forEach( graph::addVertex ); } public void addEdge( Object source, Object target, int capacity, double weight ) From def4ee3dfc62dc80ae8f1a080cfef0b993765b17 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 13:29:45 +0200 Subject: [PATCH 05/14] Remove abstract method writeToMap from AbstractNodeMapping * this abstract method is already defined in the interface NodeMapping that the class AbstractNodeMapping implements --- .../java/org/mastodon/mamut/treesimilarity/NodeMappings.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/NodeMappings.java b/src/main/java/org/mastodon/mamut/treesimilarity/NodeMappings.java index 0aee94dc8..d381d595b 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/NodeMappings.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/NodeMappings.java @@ -71,10 +71,6 @@ public double getCost() { return cost; } - - @Override - public abstract void writeToMap( Map< Tree< T >, Tree< T > > map ); - } private static class EmptyNodeMapping< T > extends AbstractNodeMapping< T > From d39d9e589d0ec267d10b8aa9e47b2d8986c7f1e4 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 13:33:02 +0200 Subject: [PATCH 06/14] Rename variables to not hide names of field declared in the same class --- .../ZhangUnorderedTreeEditDistance.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java index 91651cc91..c53fad8bd 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java @@ -312,9 +312,9 @@ private NodeMapping< T > insertOperationMapping( Tree< T > tree1, Tree< T > tree double insertCostTree2 = insertCosts.get( tree2 ).treeCost; return findBestMapping( tree2.getChildren(), child -> { - NodeMapping< T > insertCosts = NodeMappings.empty( insertCostTree2 - this.insertCosts.get( child ).treeCost ); + NodeMapping< T > insertMapping = NodeMappings.empty( insertCostTree2 - this.insertCosts.get( child ).treeCost ); NodeMapping< T > childMapping = treeMapping( tree1, child ); - return NodeMappings.compose( insertCosts, childMapping ); + return NodeMappings.compose( insertMapping, childMapping ); } ); } @@ -329,9 +329,9 @@ private NodeMapping< T > deleteOperationMapping( Tree< T > tree1, Tree< T > tree double deleteCostTree1 = deleteCosts.get( tree1 ).treeCost; return findBestMapping( tree1.getChildren(), child -> { - NodeMapping< T > deleteCosts = NodeMappings.empty( deleteCostTree1 - this.deleteCosts.get( child ).treeCost ); + NodeMapping< T > deleteMapping = NodeMappings.empty( deleteCostTree1 - this.deleteCosts.get( child ).treeCost ); NodeMapping< T > childMapping = treeMapping( child, tree2 ); - return NodeMappings.compose( deleteCosts, childMapping ); + return NodeMappings.compose( deleteMapping, childMapping ); } ); } @@ -345,9 +345,9 @@ private NodeMapping< T > forestInsertMapping( Tree< T > forest1, Tree< T > fores double insertCostForest2 = insertCosts.get( forest2 ).forestCost; return findBestMapping( forest2.getChildren(), child -> { - NodeMapping< T > insertCosts = NodeMappings.empty( insertCostForest2 - this.insertCosts.get( child ).forestCost ); + NodeMapping< T > insertMapping = NodeMappings.empty( insertCostForest2 - this.insertCosts.get( child ).forestCost ); NodeMapping< T > childMapping = forestMapping( forest1, child ); - return NodeMappings.compose( insertCosts, childMapping ); + return NodeMappings.compose( insertMapping, childMapping ); } ); } @@ -361,9 +361,9 @@ private NodeMapping< T > forestDeleteMapping( Tree< T > forest1, Tree< T > fores double deleteCostForest1 = deleteCosts.get( forest1 ).forestCost; return findBestMapping( forest1.getChildren(), child -> { - NodeMapping< T > deleteCosts = NodeMappings.empty( deleteCostForest1 - this.deleteCosts.get( child ).forestCost ); + NodeMapping< T > deleteMapping = NodeMappings.empty( deleteCostForest1 - this.deleteCosts.get( child ).forestCost ); NodeMapping< T > childMapping = forestMapping( child, forest2 ); - return NodeMappings.compose( deleteCosts, childMapping ); + return NodeMappings.compose( deleteMapping, childMapping ); } ); } From ac7adb43a04c23f0b066cc83e90d57a81042b0c9 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 13:33:40 +0200 Subject: [PATCH 07/14] Rename variable matching to mapping for more consistency --- .../mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java index c53fad8bd..6b832457e 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java @@ -167,8 +167,8 @@ public static < T > Map< Tree< T >, Tree< T > > nodeMapping( Tree< T > tree1, Tr if ( tree1 == null || tree2 == null ) return Collections.emptyMap(); - NodeMapping< T > matching = new ZhangUnorderedTreeEditDistance<>( tree1, tree2, costFunction ).treeMapping( tree1, tree2 ); - return matching.asMap(); + NodeMapping< T > mapping = new ZhangUnorderedTreeEditDistance<>( tree1, tree2, costFunction ).treeMapping( tree1, tree2 ); + return mapping.asMap(); } /** From 72a80343c9a9596cda67e7ac4957a3199b154b03 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 14:14:21 +0200 Subject: [PATCH 08/14] Move classes JGraphtTools and FlowNetwork to new sub-package org.mastodon.mamut.treesimilarity.util --- .../mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java | 1 + .../mastodon/mamut/treesimilarity/{ => util}/FlowNetwork.java | 4 ++-- .../mamut/treesimilarity/{ => util}/JGraphtTools.java | 2 +- .../mamut/treesimilarity/{ => util}/JGraphtToolsTest.java | 3 +-- 4 files changed, 5 insertions(+), 5 deletions(-) rename src/main/java/org/mastodon/mamut/treesimilarity/{ => util}/FlowNetwork.java (93%) rename src/main/java/org/mastodon/mamut/treesimilarity/{ => util}/JGraphtTools.java (98%) rename src/test/java/org/mastodon/mamut/treesimilarity/{ => util}/JGraphtToolsTest.java (95%) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java index 6b832457e..57be9da5f 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java @@ -3,6 +3,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.mastodon.mamut.treesimilarity.tree.Tree; import org.mastodon.mamut.treesimilarity.tree.TreeUtils; +import org.mastodon.mamut.treesimilarity.util.FlowNetwork; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/FlowNetwork.java b/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java similarity index 93% rename from src/main/java/org/mastodon/mamut/treesimilarity/FlowNetwork.java rename to src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java index ab5194193..03adc7b17 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/FlowNetwork.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java @@ -1,4 +1,4 @@ -package org.mastodon.mamut.treesimilarity; +package org.mastodon.mamut.treesimilarity.util; import java.util.Collection; import java.util.HashMap; @@ -8,7 +8,7 @@ import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.SimpleDirectedWeightedGraph; -class FlowNetwork +public class FlowNetwork { private final SimpleDirectedWeightedGraph< Object, DefaultWeightedEdge > graph = new SimpleDirectedWeightedGraph<>( DefaultWeightedEdge.class ); diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/JGraphtTools.java b/src/main/java/org/mastodon/mamut/treesimilarity/util/JGraphtTools.java similarity index 98% rename from src/main/java/org/mastodon/mamut/treesimilarity/JGraphtTools.java rename to src/main/java/org/mastodon/mamut/treesimilarity/util/JGraphtTools.java index 2425f39d6..a7c9d0908 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/JGraphtTools.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/util/JGraphtTools.java @@ -1,4 +1,4 @@ -package org.mastodon.mamut.treesimilarity; +package org.mastodon.mamut.treesimilarity.util; import org.jgrapht.alg.flow.PushRelabelMFImpl; import org.jgrapht.alg.flow.mincost.CapacityScalingMinimumCostFlow; diff --git a/src/test/java/org/mastodon/mamut/treesimilarity/JGraphtToolsTest.java b/src/test/java/org/mastodon/mamut/treesimilarity/util/JGraphtToolsTest.java similarity index 95% rename from src/test/java/org/mastodon/mamut/treesimilarity/JGraphtToolsTest.java rename to src/test/java/org/mastodon/mamut/treesimilarity/util/JGraphtToolsTest.java index 7c943a6d1..3a21291bb 100644 --- a/src/test/java/org/mastodon/mamut/treesimilarity/JGraphtToolsTest.java +++ b/src/test/java/org/mastodon/mamut/treesimilarity/util/JGraphtToolsTest.java @@ -1,9 +1,8 @@ -package org.mastodon.mamut.treesimilarity; +package org.mastodon.mamut.treesimilarity.util; import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.SimpleDirectedWeightedGraph; import org.junit.Test; -import org.mastodon.mamut.treesimilarity.JGraphtTools; import java.util.HashMap; import java.util.Map; From b7c9f0b2fd9659b36c4f2befa63a38c87c4d21f1 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 14:17:34 +0200 Subject: [PATCH 09/14] Improve javadoc of JGraphtTools maxFlowMinCost() --- .../mastodon/mamut/treesimilarity/util/JGraphtTools.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/util/JGraphtTools.java b/src/main/java/org/mastodon/mamut/treesimilarity/util/JGraphtTools.java index a7c9d0908..0faa3b961 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/util/JGraphtTools.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/util/JGraphtTools.java @@ -21,14 +21,14 @@ private JGraphtTools() } /** - * Computes a maximum (source, sink)-flow of minimum cost and returns its cost. - * G is a digraph with edge costs and capacities. There is a source node s and a sink node t. This function finds a maximum flow from s to t whose total cost is minimized. + * Computes a maximum (source, sink)-flow of minimum cost and returns it. + * Assuming {@code graph} is a digraph with edge costs and capacities. There is a source node s and a sink node t. This function finds a maximum flow from s to t whose total cost is minimized. * * @param graph a directed graph with edge costs (i.e. edge weights) * @param capacities a map from edges to their capacities * @param source the source node * @param sink the sink node - * @return the minimum cost of the maximum flow + * @return the maximum flow of minimum cost */ public static < V > MinimumCostFlowAlgorithm.MinimumCostFlow< DefaultWeightedEdge > maxFlowMinCost( final SimpleDirectedWeightedGraph< V, DefaultWeightedEdge > graph, final Map< DefaultWeightedEdge, Integer > capacities, final V source, final V sink ) From 1e47e45fbab1c0fade1f0962d8911ba84608b250 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 14:25:55 +0200 Subject: [PATCH 10/14] Add javadoc to public methods of FlowNetwork --- .../treesimilarity/util/FlowNetwork.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java b/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java index 03adc7b17..c996dce71 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java @@ -8,6 +8,12 @@ import org.jgrapht.graph.DefaultWeightedEdge; import org.jgrapht.graph.SimpleDirectedWeightedGraph; +/** + * A utility class that encapsulates a graph ({@link SimpleDirectedWeightedGraph}), a corresponding map of edge capacities and a minimum cost flow solution for this graph.

+ * + * @author Matthias Arzt + * @author Stefan Hahmann + */ public class FlowNetwork { @@ -17,11 +23,22 @@ public class FlowNetwork private MinimumCostFlowAlgorithm.MinimumCostFlow< DefaultWeightedEdge > flow; + /** + * Adds a collection of vertices to the graph. + * @param vertices vertices to add + */ public void addVertices( Collection< ? > vertices ) { vertices.forEach( graph::addVertex ); } + /** + * Adds an edge to the graph with the given capacity and weight. + * @param source source vertex + * @param target target vertex + * @param capacity capacity of the edge + * @param weight weight of the edge + */ public void addEdge( Object source, Object target, int capacity, double weight ) { DefaultWeightedEdge e1 = graph.addEdge( source, target ); @@ -29,11 +46,23 @@ public void addEdge( Object source, Object target, int capacity, double weight ) capacities.put( e1, capacity ); } + /** + * Solves the maximum flow minimum cost problem on the graph for the given source and sink. + * @param source source vertex + * @param sink sink vertex + */ public void solveMaxFlowMinCost( Object source, Object sink ) { flow = JGraphtTools.maxFlowMinCost( graph, capacities, source, sink ); } + /** + * Returns the flow on the edge from source to target.

+ * NB: The flow is only defined after {@link #solveMaxFlowMinCost(Object, Object)} has been called at least once. + * @param source source vertex + * @param target target vertex + * @return the flow on the edge from source to target + */ public double getFlow( Object source, Object target ) { return flow.getFlow( graph.getEdge( source, target ) ); From 330fd858e4a68393ae5e7b321232666117dede12 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 14:27:50 +0200 Subject: [PATCH 11/14] Add an IllegalStateException to getFlow() method of class FlowNetwork * Make the reason for the Runtime exception that may occur in this method more explicit and suggest the solution for it. --- .../org/mastodon/mamut/treesimilarity/util/FlowNetwork.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java b/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java index c996dce71..8b620811c 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/util/FlowNetwork.java @@ -65,6 +65,8 @@ public void solveMaxFlowMinCost( Object source, Object sink ) */ public double getFlow( Object source, Object target ) { + if ( flow == null ) + throw new IllegalStateException( "Flow is not defined. Call solveMaxFlowMinCost() first." ); return flow.getFlow( graph.getEdge( source, target ) ); } } From 77bdf40dd25467a6dc9a6a8c421a4f8d9b73e532 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 14:32:33 +0200 Subject: [PATCH 12/14] Move classes NodeMapping and NodeMappings to util package --- .../mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java | 2 ++ .../mamut/treesimilarity/{ => util}/NodeMapping.java | 5 +++-- .../mamut/treesimilarity/{ => util}/NodeMappings.java | 5 +++-- .../mamut/treesimilarity/{ => util}/NodeMappingTest.java | 3 ++- 4 files changed, 10 insertions(+), 5 deletions(-) rename src/main/java/org/mastodon/mamut/treesimilarity/{ => util}/NodeMapping.java (85%) rename src/main/java/org/mastodon/mamut/treesimilarity/{ => util}/NodeMappings.java (95%) rename src/test/java/org/mastodon/mamut/treesimilarity/{ => util}/NodeMappingTest.java (97%) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java index 57be9da5f..af2894f80 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java @@ -4,6 +4,8 @@ import org.mastodon.mamut.treesimilarity.tree.Tree; import org.mastodon.mamut.treesimilarity.tree.TreeUtils; import org.mastodon.mamut.treesimilarity.util.FlowNetwork; +import org.mastodon.mamut.treesimilarity.util.NodeMapping; +import org.mastodon.mamut.treesimilarity.util.NodeMappings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/NodeMapping.java b/src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMapping.java similarity index 85% rename from src/main/java/org/mastodon/mamut/treesimilarity/NodeMapping.java rename to src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMapping.java index 012941a02..51d6fdd61 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/NodeMapping.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMapping.java @@ -1,8 +1,9 @@ -package org.mastodon.mamut.treesimilarity; +package org.mastodon.mamut.treesimilarity.util; import java.util.HashMap; import java.util.Map; +import org.mastodon.mamut.treesimilarity.ZhangUnorderedTreeEditDistance; import org.mastodon.mamut.treesimilarity.tree.Tree; /** @@ -15,7 +16,7 @@ * * @see NodeMappings */ -interface NodeMapping< T > +public interface NodeMapping< T > { /** diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/NodeMappings.java b/src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMappings.java similarity index 95% rename from src/main/java/org/mastodon/mamut/treesimilarity/NodeMappings.java rename to src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMappings.java index d381d595b..ed4b8bd93 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/NodeMappings.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMappings.java @@ -1,16 +1,17 @@ -package org.mastodon.mamut.treesimilarity; +package org.mastodon.mamut.treesimilarity.util; import java.util.Arrays; import java.util.List; import java.util.Map; +import org.mastodon.mamut.treesimilarity.ZhangUnorderedTreeEditDistance; import org.mastodon.mamut.treesimilarity.tree.Tree; /** * Utility class for {@link ZhangUnorderedTreeEditDistance} that provides * static factory methods for the easy creation of {@link NodeMapping}s. */ -class NodeMappings +public class NodeMappings { private NodeMappings() { diff --git a/src/test/java/org/mastodon/mamut/treesimilarity/NodeMappingTest.java b/src/test/java/org/mastodon/mamut/treesimilarity/util/NodeMappingTest.java similarity index 97% rename from src/test/java/org/mastodon/mamut/treesimilarity/NodeMappingTest.java rename to src/test/java/org/mastodon/mamut/treesimilarity/util/NodeMappingTest.java index c00123110..a0f4d07ff 100644 --- a/src/test/java/org/mastodon/mamut/treesimilarity/NodeMappingTest.java +++ b/src/test/java/org/mastodon/mamut/treesimilarity/util/NodeMappingTest.java @@ -1,4 +1,4 @@ -package org.mastodon.mamut.treesimilarity; +package org.mastodon.mamut.treesimilarity.util; import static org.junit.Assert.assertEquals; @@ -12,6 +12,7 @@ import java.util.stream.Stream; import org.junit.Test; +import org.mastodon.mamut.treesimilarity.ZhangUnorderedTreeEditDistance; import org.mastodon.mamut.treesimilarity.tree.SimpleTree; import org.mastodon.mamut.treesimilarity.tree.SimpleTreeExamples; import org.mastodon.mamut.treesimilarity.tree.Tree; From 83ff2f1f597b4e9c8c499db52626abcbaab879ee Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 14:43:18 +0200 Subject: [PATCH 13/14] Add javadoc to public method nodeMapping in class ZhangUnorderedTreeEditDistance --- .../ZhangUnorderedTreeEditDistance.java | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java index af2894f80..1fb907dda 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/ZhangUnorderedTreeEditDistance.java @@ -133,6 +133,23 @@ else if ( tree2 == null ) return zhang.compute( tree1, tree2 ); } + /** + * Calculates a mapping between nodes in the given two trees ({@code tree1} and {@code tree2}) that links the nodes from the two trees, which have the minimum tree edit distance to each other.

+ * The required minimum tree edit distance is calculated using the Zhang unordered edit distance. + * @param tree1 The first tree. + * @param tree2 The second tree. + * @param costFunction The cost function. + * @return The mapping between nodes. + */ + public static < T > Map< Tree< T >, Tree< T > > nodeMapping( Tree< T > tree1, Tree< T > tree2, BiFunction< T, T, Double > costFunction ) + { + if ( tree1 == null || tree2 == null ) + return Collections.emptyMap(); + + NodeMapping< T > mapping = new ZhangUnorderedTreeEditDistance<>( tree1, tree2, costFunction ).treeMapping( tree1, tree2 ); + return mapping.asMap(); + } + private static < T > double distanceTreeToNull( Tree< T > tree2, BiFunction< T, T, Double > costFunction ) { double distance = 0; @@ -165,15 +182,6 @@ private ZhangUnorderedTreeEditDistance( final Tree< T > tree1, final Tree< T > t forestDistances = new HashMap<>(); } - public static < T > Map< Tree< T >, Tree< T > > nodeMapping( Tree< T > tree1, Tree< T > tree2, BiFunction< T, T, Double > costFunction ) - { - if ( tree1 == null || tree2 == null ) - return Collections.emptyMap(); - - NodeMapping< T > mapping = new ZhangUnorderedTreeEditDistance<>( tree1, tree2, costFunction ).treeMapping( tree1, tree2 ); - return mapping.asMap(); - } - /** * Calculate the Zhang edit distance between two (labeled) unordered trees. * From e0c2923c39776d600ecca1a950e643d5daa5c178 Mon Sep 17 00:00:00 2001 From: Stefan Hahmann Date: Mon, 14 Aug 2023 15:30:32 +0200 Subject: [PATCH 14/14] Improve javadoc for compose methods in NodeMappings --- .../mamut/treesimilarity/util/NodeMappings.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMappings.java b/src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMappings.java index ed4b8bd93..fb70620f7 100644 --- a/src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMappings.java +++ b/src/main/java/org/mastodon/mamut/treesimilarity/util/NodeMappings.java @@ -38,9 +38,9 @@ public static < T > NodeMapping< T > singleton( double cost, Tree< T > tree1, Tr } /** - * @return A {@link NodeMapping} that represents a composed that contains - * all the map entries of the given {@code children}. The costs of the - * composed mapping is the sum of the costs of the children. + * @return A {@link NodeMapping} that represents a composed mapping that + * contains all the map entries of the given {@code children}. The costs of + * the composed mapping is the sum of the costs of the children. */ @SafeVarargs public static < T > NodeMapping< T > compose( NodeMapping< T >... children ) @@ -49,9 +49,9 @@ public static < T > NodeMapping< T > compose( NodeMapping< T >... children ) } /** - * @return A {@link NodeMapping} that represents a composed that contains - * all the map entries of the given {@code children}. The costs of the - * composed mapping is the sum of the costs of the children. + * @return A {@link NodeMapping} that represents a composed mapping that + * contains all the map entries of the given {@code children}. The costs of + * the composed mapping is the sum of the costs of the children. */ public static < T > NodeMapping< T > compose( List< NodeMapping< T > > children ) {