From 671826e3afcce4511b2af14aca9cc7264fdf26b4 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Thu, 5 Jan 2023 12:35:42 +0100 Subject: [PATCH 1/6] [Graph] fix asUndirected, keep weights. Special compound graph case (not duplicating reversible reacions) redefined as a separate method rather than asUndirected Override --- .../metexplore/met4j_graph/core/BioGraph.java | 8 +++++--- .../core/compound/CompoundGraph.java | 19 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/BioGraph.java b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/BioGraph.java index 73cbcaf53..e79ff3551 100644 --- a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/BioGraph.java +++ b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/BioGraph.java @@ -527,11 +527,13 @@ public abstract class BioGraph<V extends BioEntity, E extends Edge<V>> extends D /** * For each edges in the graph, create a copy with reversed source and target. * This makes this directed graph effectively undirected, but with twice the number of edges + * Reversed edges keep the same weight as their origin */ public void asUndirected(){ - - for(E e : new HashSet<>(this.edgeSet())){ - this.addEdge(reverseEdge(e)); + for(E edge : new HashSet<>(this.edgeSet())){ + E reversedEdge = this.reverseEdge(edge); + this.addEdge(reversedEdge); + this.setEdgeWeight(reversedEdge, this.getEdgeWeight(edge)); } } diff --git a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/compound/CompoundGraph.java b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/compound/CompoundGraph.java index 5ec7f0202..1b2be087c 100644 --- a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/compound/CompoundGraph.java +++ b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/compound/CompoundGraph.java @@ -220,18 +220,17 @@ public class CompoundGraph extends BioGraph<BioMetabolite, ReactionEdge> { return null; } - @Override /** - * Handle graph as undirected by creating reverse edges for each existing edge. Do not duplicated edges for reversible reactions + * Similar to BioGraph.asUndirected, creating reverse edges from existing ones. + * Does not create edge if reverse already exist with same associated reaction, + * thus not duplicating reversible reactions edges. */ - public void asUndirected(){ - for(ReactionEdge e : new HashSet<>(this.edgeSet())){ - if(e.getReaction()==null){ - this.addEdge(reverseEdge(e)); - }else if(!e.getReaction().isReversible()){ - this.addEdge(reverseEdge(e)); - }else if(this.getEdge(e.getV2(),e.getV1(),e.getReaction())==null){ - this.addEdge(reverseEdge(e)); + public void asAllReactionsReversible(){ + for(ReactionEdge edge : new HashSet<>(this.edgeSet())){ + if(edge.getReaction()==null || this.getEdge(edge.getV2(),edge.getV1(),edge.getReaction())==null){ + ReactionEdge reversedEdge = this.reverseEdge(edge); + this.addEdge(reversedEdge); + this.setEdgeWeight(reversedEdge, this.getEdgeWeight(edge)); } } } -- GitLab From dc3e11108a40719f77b9f37b6f2a8a24ed9e941c Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Thu, 5 Jan 2023 15:24:47 +0100 Subject: [PATCH 2/6] add new test case to undirected shortest path --- .../met4j_graph/TestShortestPaths.java | 62 ++++++++++++++++++- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestShortestPaths.java b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestShortestPaths.java index cfdb3f2ce..788116daf 100644 --- a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestShortestPaths.java +++ b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestShortestPaths.java @@ -43,6 +43,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.FloydWarshall; import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.KShortestPath; @@ -50,6 +51,7 @@ import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.ShortestPath import fr.inrae.toulouse.metexplore.met4j_graph.computation.analyze.centrality.PathBasedCentrality; import fr.inrae.toulouse.metexplore.met4j_graph.computation.utils.ComputeAdjacencyMatrix; import fr.inrae.toulouse.metexplore.met4j_graph.core.BioPath; +import fr.inrae.toulouse.metexplore.met4j_graph.core.GraphFactory; import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.CompoundGraph; import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.ReactionEdge; import fr.inrae.toulouse.metexplore.met4j_mathUtils.matrix.BioMatrix; @@ -180,7 +182,7 @@ public class TestShortestPaths { BioPath<BioMetabolite,ReactionEdge> path = pathSearch.getShortest(a, new BioMetabolite("u")); System.out.println(path); } - + @Test public void testGetShortestundirected() { ReactionEdge[] expectedPath = {bc, ab}; @@ -188,8 +190,8 @@ public class TestShortestPaths { BioPath<BioMetabolite,ReactionEdge> path = pathSearch.getShortest(c, a); assertNotNull(path); List<ReactionEdge> sp = path.getEdgeList(); - assertTrue("wrong path", Arrays.asList(expectedPath).containsAll(sp)); - assertTrue("wrong path", sp.containsAll(Arrays.asList(expectedPath))); + assertTrue("wrong path "+sp, Arrays.asList(expectedPath).containsAll(sp)); + assertTrue("wrong path "+sp, sp.containsAll(Arrays.asList(expectedPath))); g.setEdgeWeight(bc, 1000.0); g.setEdgeWeight(ab, 1000.0); @@ -200,6 +202,60 @@ public class TestShortestPaths { assertTrue("wrong weighted path", Arrays.asList(expectedLightestPath).containsAll(res)); assertTrue("wrong weighted path", res.containsAll(Arrays.asList(expectedLightestPath))); } + + @Test + public void testShortestVsShortestUnion() { + + ShortestPath<BioMetabolite, ReactionEdge, CompoundGraph> pathSearch = new ShortestPath<>(g, false); + BioPath<BioMetabolite,ReactionEdge> path1 = pathSearch.getShortest(c, a); + + HashSet source = new HashSet(); source.add(c); + HashSet target = new HashSet(); target.add(a); + List<BioPath<BioMetabolite,ReactionEdge>> pathUnion = pathSearch.getShortestPathsUnionList(source, target); + assertEquals(1,pathUnion.size()); + BioPath<BioMetabolite,ReactionEdge> path2 = pathUnion.get(0); + assertNotNull(path1); + assertNotNull(path2); + assertEquals(path1.getEdgeList(), path2.getEdgeList()); + + g.setEdgeWeight(bc, 1000.0); + g.setEdgeWeight(ab, 1000.0); + BioPath<BioMetabolite,ReactionEdge> path3 =pathSearch.getShortest(c, a); + List<BioPath<BioMetabolite,ReactionEdge>> pathUnion2 = pathSearch.getShortestPathsUnionList(source, target); + assertEquals(1,pathUnion2.size()); + BioPath<BioMetabolite,ReactionEdge> path4 = pathUnion2.get(0); + assertNotNull(path3); + assertNotNull(path4); + assertEquals(path3.getEdgeList(), path4.getEdgeList()); + } + + @Test + public void testUndirectedShortestVsShortestOnUndirected() { + + ShortestPath<BioMetabolite, ReactionEdge, CompoundGraph> pathSearch = new ShortestPath<>(g, false); + BioPath<BioMetabolite,ReactionEdge> path1 = pathSearch.getShortest(c, a); + + CompoundGraph g2 = CompoundGraph.getFactory().createGraphFromElements(g.vertexSet(),g.edgeSet()); + g2.asUndirected(); + ShortestPath<BioMetabolite, ReactionEdge, CompoundGraph> pathSearch2 = new ShortestPath<>(g2, false); + BioPath<BioMetabolite,ReactionEdge> path2 = pathSearch2.getShortest(c, a); + + assertEquals(path1.getEdgeList().stream().map(e->e.getReaction().getId()).collect(Collectors.toList()), + path2.getEdgeList().stream().map(e->e.getReaction().getId()).collect(Collectors.toList())); + + + g.setEdgeWeight(bc, 1000.0); + g.setEdgeWeight(ab, 1000.0); + BioPath<BioMetabolite,ReactionEdge> path3 =pathSearch.getShortest(c, a); + CompoundGraph g3 = CompoundGraph.getFactory().createGraphFromElements(g.vertexSet(),g.edgeSet()); + g3.asUndirected(); + BioPath<BioMetabolite,ReactionEdge> path4 = new ShortestPath<>(g3, false).getShortest(c,a); + + assertEquals(path3.getEdgeList().stream().map(e->e.getReaction().getId()).collect(Collectors.toList()), + path4.getEdgeList().stream().map(e->e.getReaction().getId()).collect(Collectors.toList())); + + } + // @Test // public void testReversibility() { -- GitLab From b9b1488e63d1e223f962d4851e52fea45e30244f Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Thu, 5 Jan 2023 16:12:37 +0100 Subject: [PATCH 3/6] Add new test case in testCompoundGraph, covering asUndirected --- .../met4j_graph/TestCompoundGraph.java | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestCompoundGraph.java b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestCompoundGraph.java index d9608c79e..9c9786139 100644 --- a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestCompoundGraph.java +++ b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestCompoundGraph.java @@ -138,6 +138,9 @@ public class TestCompoundGraph { cg.addEdgesFromReaction(bn,r3); Assert.assertEquals(3, cg.vertexSet().size()); Assert.assertEquals(4, cg.edgeSet().size()); + cg.removeEdge(cg.getEdge(v2,v3,r3)); + Assert.assertEquals(3, cg.vertexSet().size()); + Assert.assertEquals(3, cg.edgeSet().size()); } @Test @@ -171,13 +174,20 @@ public class TestCompoundGraph { assertTrue(g2.containsEdge(e2)); assertTrue(g2.containsVertex(v1)); assertTrue(g2.containsVertex(v2)); + BioMetabolite v4 = new BioMetabolite("v4"); + g2.addVertex(v4); + g2.addEdge(v3,v4,new ReactionEdge(v3,v4,new BioReaction("r4"))); + Assert.assertEquals(cg.vertexSet().size()+1, g2.vertexSet().size()); + Assert.assertEquals(cg.edgeSet().size()+1, g2.edgeSet().size()); + } @Test public void testAddEdge(){ - CompoundGraph g2 = (CompoundGraph) cg.clone(); - g2.addEdge(v3, v1); - Assert.assertEquals(3, g2.edgeSet().size()); + cg.addEdge(v3, v1); + Assert.assertEquals(3, cg.edgeSet().size()); + cg.removeEdge(v3,v1); + Assert.assertEquals(2, cg.edgeSet().size()); } @Test @@ -202,4 +212,39 @@ public class TestCompoundGraph { assertTrue(gr2.containsVertex(v2)); assertTrue(gr2.containsVertex(v3)); } + + @Test + public void testAsUndirected() { + cg.setEdgeWeight(e1,42); + CompoundGraph g2 = new CompoundGraph(cg); + g2.asUndirected(); + Assert.assertEquals(cg.vertexSet().size(), g2.vertexSet().size()); + Assert.assertEquals(cg.edgeSet().size()*2, g2.edgeSet().size()); + for(ReactionEdge e : cg.edgeSet()){ + assertTrue(g2.containsEdge(e.getV1(),e.getV2())); + assertTrue(g2.containsEdge(e.getV2(),e.getV1())); + } + assertEquals(42, g2.getEdgeWeight(g2.getEdge(v1, v2, r1)),Double.MIN_VALUE); + assertEquals(42, g2.getEdgeWeight(g2.getEdge(v2, v1, r1)),Double.MIN_VALUE); + cg.setEdgeWeight(e1,1.0); + } + + @Test + public void testAsAllReactionsReversible() { + CompoundGraph g2 = new CompoundGraph(cg); + ReactionEdge e3 = new ReactionEdge(v2, v1, r1); + ReactionEdge e4 = new ReactionEdge(v3, v2, new BioReaction("r4")); + g2.addEdge(e3); g2.setEdgeWeight(e3,42); + g2.addEdge(e4); + g2.asAllReactionsReversible(); + + Assert.assertEquals(cg.vertexSet().size(), g2.vertexSet().size()); + Assert.assertEquals(cg.edgeSet().size()*2+2, g2.edgeSet().size()); + for(ReactionEdge e : cg.edgeSet()){ + assertTrue(g2.containsEdge(e.getV1(),e.getV2())); + assertTrue(g2.containsEdge(e.getV2(),e.getV1())); + } + assertEquals(1.0, g2.getEdgeWeight(g2.getEdge(v1, v2, r1)),Double.MIN_VALUE); + assertEquals(42.0, g2.getEdgeWeight(g2.getEdge(v2, v1, r1)),Double.MIN_VALUE); + } } -- GitLab From a4f49c72ffc8864c39e451b3e6589c56284651b9 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Thu, 5 Jan 2023 20:19:58 +0100 Subject: [PATCH 4/6] Use java8 lambda expression for weighting policy added to WeightUtils and as CustomWeightPolicy --- .../connect/weighting/CustomWeightPolicy.java | 34 ++++++++++++++ .../connect/weighting/WeightUtils.java | 15 +++++++ .../met4j_graph/TestWeightUtils.java | 25 +++++++++++ .../met4j_graph/TestWeightingPolicy.java | 45 +++++++++++++++---- 4 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/computation/connect/weighting/CustomWeightPolicy.java diff --git a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/computation/connect/weighting/CustomWeightPolicy.java b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/computation/connect/weighting/CustomWeightPolicy.java new file mode 100644 index 000000000..fc17ea42a --- /dev/null +++ b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/computation/connect/weighting/CustomWeightPolicy.java @@ -0,0 +1,34 @@ +package fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.weighting; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity; +import fr.inrae.toulouse.metexplore.met4j_graph.core.BioGraph; +import fr.inrae.toulouse.metexplore.met4j_graph.core.Edge; +import fr.inrae.toulouse.metexplore.met4j_graph.core.WeightingPolicy; + +import java.util.function.Function; + +/** + * An all-purpose class to provides edge weights from a given function + * @param <V> + * @param <E> + * @param <G> + */ +public class CustomWeightPolicy<V extends BioEntity, E extends Edge<V>,G extends BioGraph<V,E>> extends WeightingPolicy<V,E,G> { + + Function<E,Double> lambda; + + /** + * Create a CustomWeightPolicy + * @param function that takes an edge an return its weight + */ + public CustomWeightPolicy(Function<E,Double> function){ + this.lambda=function; + } + + @Override + public void setWeight(G bioGraph) { + for(E edge : bioGraph.edgeSet()){ + bioGraph.setEdgeWeight(edge,lambda.apply(edge)); + } + } +} diff --git a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/computation/connect/weighting/WeightUtils.java b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/computation/connect/weighting/WeightUtils.java index 6e531ac1c..1a9819936 100644 --- a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/computation/connect/weighting/WeightUtils.java +++ b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/computation/connect/weighting/WeightUtils.java @@ -40,6 +40,7 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.function.DoubleFunction; import fr.inrae.toulouse.metexplore.met4j_graph.core.BioGraph; import fr.inrae.toulouse.metexplore.met4j_graph.core.Edge; @@ -57,6 +58,20 @@ public class WeightUtils { */ public WeightUtils() { } + + /** + * Apply a function on every edge weight + * @param g the graph + * @param lambda a function that takes an edge weight (Double) and produce a Double + * @param <E> Edge type + * @param <G> Graph type + */ + public static <E extends Edge<?>, G extends BioGraph<?,E>> void process(G g, DoubleFunction<Double> lambda){ + for(E e : g.edgeSet()){ + double w = g.getEdgeWeight(e); + g.setEdgeWeight(e, lambda.apply(w)); + } + } /** * Scale weights between 0 and 1. diff --git a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestWeightUtils.java b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestWeightUtils.java index 67893b9a6..b7df0ec72 100644 --- a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestWeightUtils.java +++ b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestWeightUtils.java @@ -106,6 +106,31 @@ public class TestWeightUtils { g.setEdgeWeight(e, 0.0); } } + + @Test + public void testProcess(){ + double abWeight,bcWeight,adWeight,efWeight,bxWeight,ebWeight,deWeight,fcWeight,ycWeight; + abWeight=1;g.setEdgeWeight(ab, abWeight); + bcWeight=2;g.setEdgeWeight(bc, bcWeight); + adWeight=3;g.setEdgeWeight(ad, adWeight); + efWeight=4;g.setEdgeWeight(ef, efWeight); + bxWeight=5;g.setEdgeWeight(bx, bxWeight); + ebWeight=6;g.setEdgeWeight(eb, ebWeight); + deWeight=7;g.setEdgeWeight(de, deWeight); + fcWeight=8;g.setEdgeWeight(fc, fcWeight); + ycWeight=9;g.setEdgeWeight(yc, ycWeight); + WeightUtils.process(g, w -> StrictMath.pow(w, 2)); + + assertEquals("wrong weight after pow", 1, g.getEdgeWeight(ab),Double.MIN_VALUE); + assertEquals("wrong weight after pow", 9, g.getEdgeWeight(ad),Double.MIN_VALUE); + assertEquals("wrong weight after pow", 4, g.getEdgeWeight(bc),Double.MIN_VALUE); + assertEquals("wrong weight after pow", 25, g.getEdgeWeight(bx),Double.MIN_VALUE); + assertEquals("wrong weight after pow", 49, g.getEdgeWeight(de),Double.MIN_VALUE); + assertEquals("wrong weight after pow", 36, g.getEdgeWeight(eb),Double.MIN_VALUE); + assertEquals("wrong weight after pow", 16, g.getEdgeWeight(ef),Double.MIN_VALUE); + assertEquals("wrong weight after pow", 64, g.getEdgeWeight(fc),Double.MIN_VALUE); + assertEquals("wrong weight after pow", 81, g.getEdgeWeight(yc),Double.MIN_VALUE); + } /** * Test the weights inversion diff --git a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestWeightingPolicy.java b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestWeightingPolicy.java index 291b6a227..08ad8f683 100644 --- a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestWeightingPolicy.java +++ b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestWeightingPolicy.java @@ -175,15 +175,42 @@ public class TestWeightingPolicy { adWeight=efWeight=4; bxWeight=1; wp.setWeight(g); - assertEquals("wrong weight with probability weighting policy", abWeight, g.getEdgeWeight(ab),Double.MIN_VALUE); - assertEquals("wrong weight with probability weighting policy", adWeight, g.getEdgeWeight(ad),Double.MIN_VALUE); - assertEquals("wrong weight with probability weighting policy", bcWeight, g.getEdgeWeight(bc),Double.MIN_VALUE); - assertEquals("wrong weight with probability weighting policy", bxWeight, g.getEdgeWeight(bx),Double.MIN_VALUE); - assertEquals("wrong weight with probability weighting policy", deWeight, g.getEdgeWeight(de),Double.MIN_VALUE); - assertEquals("wrong weight with probability weighting policy", ebWeight, g.getEdgeWeight(eb),Double.MIN_VALUE); - assertEquals("wrong weight with probability weighting policy", efWeight, g.getEdgeWeight(ef),Double.MIN_VALUE); - assertEquals("wrong weight with probability weighting policy", fcWeight, g.getEdgeWeight(fc),Double.MIN_VALUE); - assertEquals("wrong weight with probability weighting policy", ycWeight, g.getEdgeWeight(yc),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", abWeight, g.getEdgeWeight(ab),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", adWeight, g.getEdgeWeight(ad),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", bcWeight, g.getEdgeWeight(bc),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", bxWeight, g.getEdgeWeight(bx),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", deWeight, g.getEdgeWeight(de),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", ebWeight, g.getEdgeWeight(eb),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", efWeight, g.getEdgeWeight(ef),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", fcWeight, g.getEdgeWeight(fc),Double.MIN_VALUE); + assertEquals("wrong weight with degree weighting policy", ycWeight, g.getEdgeWeight(yc),Double.MIN_VALUE); + } + + @Test + public void testCustomWeightPolicy(){ + WeightingPolicy<BioMetabolite,ReactionEdge,CompoundGraph> wp = new CustomWeightPolicy<BioMetabolite,ReactionEdge,CompoundGraph>( + e -> { + Double w = Double.valueOf(g.inDegreeOf(e.getV2())); + w += Double.valueOf(g.outDegreeOf(e.getV2())); + w = StrictMath.pow(w,2); + return w; + }); + double abWeight,bcWeight,adWeight,efWeight,bxWeight,ebWeight,deWeight,fcWeight,ycWeight; + abWeight=ebWeight=16; + bcWeight=fcWeight=ycWeight=deWeight=9; + adWeight=efWeight=4; + bxWeight=1; + wp.setWeight(g); + assertEquals("wrong weight with custom weighting policy", abWeight, g.getEdgeWeight(ab),Double.MIN_VALUE); + assertEquals("wrong weight with custom weighting policy", adWeight, g.getEdgeWeight(ad),Double.MIN_VALUE); + assertEquals("wrong weight with custom weighting policy", bcWeight, g.getEdgeWeight(bc),Double.MIN_VALUE); + assertEquals("wrong weight with custom weighting policy", bxWeight, g.getEdgeWeight(bx),Double.MIN_VALUE); + assertEquals("wrong weight with custom weighting policy", deWeight, g.getEdgeWeight(de),Double.MIN_VALUE); + assertEquals("wrong weight with custom weighting policy", ebWeight, g.getEdgeWeight(eb),Double.MIN_VALUE); + assertEquals("wrong weight with custom weighting policy", efWeight, g.getEdgeWeight(ef),Double.MIN_VALUE); + assertEquals("wrong weight with custom weighting policy", fcWeight, g.getEdgeWeight(fc),Double.MIN_VALUE); + assertEquals("wrong weight with custom weighting policy", ycWeight, g.getEdgeWeight(yc),Double.MIN_VALUE); + } /** -- GitLab From 1013b5d32e721530499e32aea12bd1cb4b53d2ef Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Thu, 5 Jan 2023 20:24:32 +0100 Subject: [PATCH 5/6] [stub] add fix for non-symmetric weighting policy in app Todo: test --- .../networkAnalysis/CompoundNet.java | 14 ++++++++++++- .../networkAnalysis/DistanceMatrix.java | 21 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/CompoundNet.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/CompoundNet.java index 53e189201..2ddae4d1d 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/CompoundNet.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/CompoundNet.java @@ -131,18 +131,30 @@ public class CompoundNet extends AbstractMet4jApplication { if (weightFile != null) { System.err.println("Setting edge weights..."); wp = new WeightsFromFile(weightFile); - } else if (degree) { + } else if (degree && !undirected) { System.err.println("Setting edge weights..."); int pow = 2; wp = new DegreeWeightPolicy(pow); } wp.setWeight(graph); + System.out.println(" Done."); //invert graph as undirected (copy edge weight to reversed edge) if(undirected){ System.out.print("Create Undirected..."); graph.asUndirected(); System.out.println(" Done."); + if(degree){ + //since degree weighting policy is not symmetric, for undirected case we create reversed edges, apply + //a corrected degree computation for each edge, and treat the graph as normal + System.err.println("Setting edge weights (target degree)..."); + int pow = 2; + wp = new DegreeWeightPolicy(1); + wp.setWeight(graph); + //adjust degree to ignore edges added for undirected case support + WeightUtils.process(graph, x -> StrictMath.pow((x/2),pow)); + System.out.println(" Done."); + } } //merge compartment diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/DistanceMatrix.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/DistanceMatrix.java index 38220f317..a6d784fbf 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/DistanceMatrix.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/networkAnalysis/DistanceMatrix.java @@ -6,9 +6,11 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection; // import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.FloydWarshall; // import fr.inrae.toulouse.metexplore.met4j_graph.computation.utils.ComputeAdjacencyMatrix; import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.ShortestPath; +import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.weighting.CustomWeightPolicy; import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.weighting.UnweightedPolicy; import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.weighting.DegreeWeightPolicy; import fr.inrae.toulouse.metexplore.met4j_graph.computation.connect.weighting.WeightsFromFile; +import fr.inrae.toulouse.metexplore.met4j_graph.core.BioGraph; import fr.inrae.toulouse.metexplore.met4j_graph.core.BioPath; import fr.inrae.toulouse.metexplore.met4j_graph.core.WeightingPolicy; import fr.inrae.toulouse.metexplore.met4j_graph.core.compound.CompoundGraph; @@ -117,8 +119,23 @@ public class DistanceMatrix extends AbstractMet4jApplication { if (weightFile != null) { wp = new WeightsFromFile(weightFile, true); } else if (degree) { - int pow = 2; - wp = new DegreeWeightPolicy(pow); + if(!undirected){ + int pow = 2; + wp = new DegreeWeightPolicy(pow); + }else{ + //since degree weighting policy is not symmetric, for undirected case we create reversed edges, apply + //a corrected degree computation for each edge, and treat the graph as normal + graph.asUndirected(); + undirected=false; + wp = new CustomWeightPolicy<BioMetabolite,ReactionEdge,CompoundGraph>( + e -> { + Double w = Double.valueOf(graph.inDegreeOf(e.getV2())); + w += Double.valueOf(graph.outDegreeOf(e.getV2())); + w = w/2; //adjust for undirected doubled edges + w = StrictMath.pow(w,2); + return w; + }); + } } wp.setWeight(graph); -- GitLab From 16ce7a9c03ff9a1c6f5e9f29c803d2b1efd80d04 Mon Sep 17 00:00:00 2001 From: cfrainay <clement.frainay@inrae.fr> Date: Fri, 6 Jan 2023 15:20:40 +0100 Subject: [PATCH 6/6] Remove special compound graph case, as already covered by base implementation. The equals methods of ReactionEdge and the addEdge implementation in JGraphT already prevent edge duplication --- .../metexplore/met4j_graph/core/BioGraph.java | 6 +++--- .../met4j_graph/core/compound/CompoundGraph.java | 16 ---------------- .../met4j_graph/TestCompoundGraph.java | 5 +++-- 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/BioGraph.java b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/BioGraph.java index e79ff3551..5522c9315 100644 --- a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/BioGraph.java +++ b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/BioGraph.java @@ -525,9 +525,9 @@ public abstract class BioGraph<V extends BioEntity, E extends Edge<V>> extends D } /** - * For each edges in the graph, create a copy with reversed source and target. - * This makes this directed graph effectively undirected, but with twice the number of edges - * Reversed edges keep the same weight as their origin + * For each edges in the graph, create a copy with reversed source and target (if not existing already). + * This makes this directed graph effectively undirected, but with twice the number of edges. + * Reversed edges keep the same weight as their origin. */ public void asUndirected(){ for(E edge : new HashSet<>(this.edgeSet())){ diff --git a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/compound/CompoundGraph.java b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/compound/CompoundGraph.java index 1b2be087c..88b425119 100644 --- a/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/compound/CompoundGraph.java +++ b/met4j-graph/src/main/java/fr/inrae/toulouse/metexplore/met4j_graph/core/compound/CompoundGraph.java @@ -220,22 +220,6 @@ public class CompoundGraph extends BioGraph<BioMetabolite, ReactionEdge> { return null; } - /** - * Similar to BioGraph.asUndirected, creating reverse edges from existing ones. - * Does not create edge if reverse already exist with same associated reaction, - * thus not duplicating reversible reactions edges. - */ - public void asAllReactionsReversible(){ - for(ReactionEdge edge : new HashSet<>(this.edgeSet())){ - if(edge.getReaction()==null || this.getEdge(edge.getV2(),edge.getV1(),edge.getReaction())==null){ - ReactionEdge reversedEdge = this.reverseEdge(edge); - this.addEdge(reversedEdge); - this.setEdgeWeight(reversedEdge, this.getEdgeWeight(edge)); - } - } - } - - /** {@inheritDoc} */ @Override public ReactionEdge copyEdge(ReactionEdge edge) { diff --git a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestCompoundGraph.java b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestCompoundGraph.java index 9c9786139..e76de06db 100644 --- a/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestCompoundGraph.java +++ b/met4j-graph/src/test/java/fr/inrae/toulouse/metexplore/met4j_graph/TestCompoundGraph.java @@ -230,13 +230,13 @@ public class TestCompoundGraph { } @Test - public void testAsAllReactionsReversible() { + public void testAsUndirected2() { CompoundGraph g2 = new CompoundGraph(cg); ReactionEdge e3 = new ReactionEdge(v2, v1, r1); ReactionEdge e4 = new ReactionEdge(v3, v2, new BioReaction("r4")); g2.addEdge(e3); g2.setEdgeWeight(e3,42); g2.addEdge(e4); - g2.asAllReactionsReversible(); + g2.asUndirected(); Assert.assertEquals(cg.vertexSet().size(), g2.vertexSet().size()); Assert.assertEquals(cg.edgeSet().size()*2+2, g2.edgeSet().size()); @@ -247,4 +247,5 @@ public class TestCompoundGraph { assertEquals(1.0, g2.getEdgeWeight(g2.getEdge(v1, v2, r1)),Double.MIN_VALUE); assertEquals(42.0, g2.getEdgeWeight(g2.getEdge(v2, v1, r1)),Double.MIN_VALUE); } + } -- GitLab