Procházet zdrojové kódy

transformation of graph done

Claudio Gomes před 5 roky
rodič
revize
8b56f28adc

+ 31 - 6
HintCOEngine/src/ua/ansymo/hintco/AlgebraicLoopVariantProcessor.xtend

@@ -2,8 +2,8 @@ package ua.ansymo.hintco
 
 import java.util.Deque
 import org.eclipse.core.runtime.Assert
-import org.jgrapht.graph.DefaultWeightedEdge
-import org.jgrapht.graph.Multigraph
+import org.jgrapht.graph.DirectedMultigraph
+import org.jgrapht.util.SupplierUtil
 
 class AlgebraicLoopVariantProcessor implements IVariantProcessor {
 	
@@ -16,15 +16,40 @@ class AlgebraicLoopVariantProcessor implements IVariantProcessor {
 	/*
 	 * Transforms a scenario into a cosim unit graph. 
 	 * The scenario already has some ordering constraints, as cosim units and ports are both precedence nodes.
-	 * The precendence constraints are placed in a way that it is easy to know whether two cosim units A and B should precede each other: whenever there is a precedence path that goes between them, of the following form:
-	 *  A -> B.in -> B where B.in is one of the input ports of B. If this is the case, then an edge should be created A --w-> B where w is the cost of extrapolating B.in.
+	 * The precedence constraints are placed in a way that it is easy to know whether two cosim units A and B should precede each other: 
+	 * 	whenever there is a precedence path that goes between them, of the form
+	 *  A.out -> B.in -> B where A.out is an output port of A, and B.in is an input port of B, 
+	 * then an edge should be created A --w-> B where w is the cost of extrapolating B.in.
 	 * In every other case, there is no edge between A->B.
 	 * This way, we preserve the extrapolation adaptations that have been defined by other hints.
 	 */
 	def transformToCosimUnitGraph(Scenario scenario) {
-		val g = new Multigraph(DefaultWeightedEdge)
+		val resultGraph = new DirectedMultigraph(SupplierUtil.createSupplier(CosimUnitInstance), SupplierUtil.createDefaultWeightedEdgeSupplier, true)
 		
-		return g
+		val vertices = scenario.cosimunits.filter(CosimUnitInstance).toList
+		
+		vertices.forEach[u | Assert.isTrue(resultGraph.addVertex(u))]
+		
+		for (A : vertices) {
+			for (Aout : A.outputPorts) {
+				for (Bin : Aout.precedes) {
+					if (Bin instanceof InputPortInstance) {
+						if (Bin.unit !== A) {
+							// Found path of the form A.out -> B.in
+							for (B : Bin.precedes) {
+								if (B == Bin.unit) {
+									// Found path of the form A.out -> B.in -> B
+									val ABEdge = resultGraph.addEdge(A, B as CosimUnitInstance)
+									resultGraph.setEdgeWeight(ABEdge, Bin.extrapolationCost)
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		
+		return resultGraph
 	}
 	
 	/*

+ 10 - 5
HintCOEngine/src/ua/ansymo/hintco/CandidatesGenerator.xtend

@@ -385,13 +385,18 @@ class CandidatesGenerator {
 		// check if constraint already exists.
 		if (!constraints.stackContains(src, trg) && !src.precedes.contains(trg)) {
 			// Add constraint
-			if (constraintChecker.constraintIsFeasible(src, trg, n, constraints, cs)) { // avoid rec calls to children for variants that cannot be implemented.
-				constraints.safeAdd(src, trg)
-				src.precedes.add(trg)
-				return AddConstraintResult.SUCCESS
+			
+			// the following result avoids calls to children for variants that cannot be implemented.
+			val result = if (constraintChecker.constraintIsFeasible(src, trg, n, constraints, cs)) { 
+				AddConstraintResult.SUCCESS
 			} else {
-				return AddConstraintResult.CYCLE
+				AddConstraintResult.CYCLE
 			}
+			// Even if a cycle is introduced, we add the constraint.
+			// This is because either the calling code tolerates cycles, or it will undo the constraints that introduced cycles.
+			constraints.safeAdd(src, trg)
+			src.precedes.add(trg)
+			return result
 		} else {
 			return AddConstraintResult.EXISTS
 		}

+ 57 - 3
HintCOEngine/test/ua/ansymo/hintco/test/AlgebraicLoopVariantProcessorTest.xtend

@@ -2,21 +2,75 @@ package ua.ansymo.hintco.test
 
 import org.junit.Test
 import ua.ansymo.hintco.AlgebraicLoopVariantProcessor
+import ua.ansymo.hintco.CandidatesGenerator
+import ua.ansymo.hintco.ConstraintChecker
+import ua.ansymo.hintco.CosimUnitInstance
+import ua.ansymo.hintco.ModelQuery
 import ua.ansymo.hintco.ModelStorage
-import ua.ansymo.hintco.Scenario
 
 import static org.junit.Assert.*
 
+// TODO Rename this to AlgebraicLoopProcessingTest
 class AlgebraicLoopVariantProcessorTest {
 	
+	@Test
+	def void addConstraintsWithAlgebraicLoopsTest() {
+		val loader = new ModelStorage()
+		
+		val src = loader.loadCandidates("instances/algebraic_loop_opt_test.hintco")
+		
+		val generator = new CandidatesGenerator(new ConstraintChecker(), [n, alternatives, ns |
+				true
+			],
+			[ns, vId, constraints, cs |
+				val scenario = ModelQuery.findRootScenario(ns)
+				val cosimUnits = scenario.cosimunits.filter(CosimUnitInstance)
+				val A = cosimUnits.findFirst[u | u.identifier=="A"]
+				val B = cosimUnits.findFirst[u | u.identifier=="B"]
+				assertTrue(A.inputPorts.findFirst[p|p.identifier=="3fromB"].precedes.contains(A))
+				assertTrue(A.inputPorts.findFirst[p|p.identifier=="5fromC"].precedes.contains(A))
+				assertFalse(B.inputPorts.findFirst[p|p.identifier=="10fromC"].precedes.contains(B))
+			])
+		generator.createVariantTree(src)
+		generator.generateVariants(src, 1, true)
+	}
+	
 	@Test
 	def void transformToCosimUnitGraphTest(){
 		val loader = new ModelStorage()
 		
 		val src = loader.loadCandidates("instances/algebraic_loop_opt_test.hintco")
-		val scenario = src.eAllContents.filter(Scenario).head
 		
-		assertNotNull(new AlgebraicLoopVariantProcessor(null).transformToCosimUnitGraph(scenario))
+		val generator = new CandidatesGenerator(new ConstraintChecker(), [n, alternatives, ns |
+				true
+			],
+			[ns, vId, constraints, cs |
+				val scenario = ModelQuery.findRootScenario(ns)
+				
+				val graph = new AlgebraicLoopVariantProcessor(null).transformToCosimUnitGraph(scenario)
+				
+				assertNotNull(graph)
+		
+				val vertices = graph.vertexSet
+				assertEquals(3, vertices.size)
+				val A = vertices.findFirst[v | v.identifier == "A"]
+				val B = vertices.findFirst[v | v.identifier == "B"]
+				val C = vertices.findFirst[v | v.identifier == "C"]
+				
+				val A4B = graph.getAllEdges(A, B).head
+				val B3A = graph.getAllEdges(B, A).head
+				val B3C = graph.getAllEdges(B, C).head
+				
+				assertNotNull(A4B)
+				assertNotNull(B3A)
+				assertNotNull(B3C)
+				assertTrue(graph.getAllEdges(C, B).isEmpty)
+				assertEquals(4.0,graph.getEdgeWeight(A4B),1e-4)
+				assertEquals(3.0,graph.getEdgeWeight(B3A),1e-4)
+				assertEquals(3.0,graph.getEdgeWeight(B3C),1e-4)
+			])
+		generator.createVariantTree(src)
+		generator.generateVariants(src, 1, true)
 	}
 	
 }