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