diff --git a/gipsl.all.build.mappingpreservation/.classpath b/gipsl.all.build.mappingpreservation/.classpath new file mode 100644 index 00000000..0b423a2c --- /dev/null +++ b/gipsl.all.build.mappingpreservation/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/gipsl.all.build.mappingpreservation/.project b/gipsl.all.build.mappingpreservation/.project new file mode 100644 index 00000000..15c5fda9 --- /dev/null +++ b/gipsl.all.build.mappingpreservation/.project @@ -0,0 +1,25 @@ + + + gipsl.all.build.mappingpreservation + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.emoflon.gips.gipsl.ui.gipsNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/gipsl.all.build.mappingpreservation/.settings/org.eclipse.jdt.core.prefs b/gipsl.all.build.mappingpreservation/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..3a79233b --- /dev/null +++ b/gipsl.all.build.mappingpreservation/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,10 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=21 diff --git a/gipsl.all.build.mappingpreservation/META-INF/MANIFEST.MF b/gipsl.all.build.mappingpreservation/META-INF/MANIFEST.MF new file mode 100644 index 00000000..3d204907 --- /dev/null +++ b/gipsl.all.build.mappingpreservation/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: gipsl.all.build.mappingpreservation +Bundle-ManifestVersion: 2 +Bundle-Name: gipsl.all.build.mappingpreservation +Bundle-Vendor: My Company +Bundle-Version: 1.0.0.qualifier +Export-Package: gipsl.all.build.mappingpreservation.connector +Bundle-SymbolicName: gipsl.all.build.mappingpreservation; singleton:=true +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-21 +Require-Bundle: org.emoflon.ibex.common, + org.emoflon.ibex.gt, + org.emoflon.gips.core, + org.emoflon.ibex.gt.democles, + org.emoflon.ibex.gt.hipe, + gipsl.all.build.model;bundle-version="0.0.1", + test.suite.utils;bundle-version="1.0.0" diff --git a/gipsl.all.build.mappingpreservation/build.properties b/gipsl.all.build.mappingpreservation/build.properties new file mode 100644 index 00000000..14acfb7c --- /dev/null +++ b/gipsl.all.build.mappingpreservation/build.properties @@ -0,0 +1,5 @@ +source.. = src/,\ + src-gen/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/gipsl.all.build.mappingpreservation/src/gipsl/all/build/mappingpreservation/Model.gipsl b/gipsl.all.build.mappingpreservation/src/gipsl/all/build/mappingpreservation/Model.gipsl new file mode 100644 index 00000000..e1db1241 --- /dev/null +++ b/gipsl.all.build.mappingpreservation/src/gipsl/all/build/mappingpreservation/Model.gipsl @@ -0,0 +1,100 @@ +package "gipsl.all.build.mappingpreservation" +import "platform:/resource/gipsl.all.build.model/model/Model.ecore" + +config { + solver := GUROBI [home:="fu", license:="bar"]; + launchConfig := true [main := "TODO"]; + timeLimit := true [value := 5.0]; + randomSeed := true [value := 0]; + presolve := true; + debugOutput := false; +} + +condition vnodeNotMapped = forbid vnodeIsMapped +pattern vnodeIsMapped { + host: SubstrateNode + + vnode: VirtualNode { + -host -> host + } +} + +pattern vnodeNotMapped { + vnode: VirtualNode +} +when vnodeNotMapped + +rule mapVnode { + root: Root { + -containers -> substrateContainer + -containers -> virtualContainer + } + + substrateContainer: SubstrateContainer { + -substrateNodes -> snode + } + + virtualContainer: VirtualContainer { + -virtualNodes -> vnode + } + + snode: SubstrateResourceNode + + vnode: VirtualResourceNode { + ++ -host -> snode + } + + # vnode.resourceDemand != 10 +} + +rule mapVnodeWith10ResDem { + root: Root { + -containers -> substrateContainer + -containers -> virtualContainer + } + + substrateContainer: SubstrateContainer { + -substrateNodes -> snode + } + + virtualContainer: VirtualContainer { + -virtualNodes -> vnode + } + + snode: SubstrateResourceNode + + vnode: VirtualResourceNode { + ++ -host -> snode + } + + # vnode.resourceDemand == 10 +} + +// +// GIPSL starts here! +// + +mapping n2n with mapVnode; +mapping resDem with mapVnodeWith10ResDem; + +// At most one mapping per virtual node is allowed +constraint -> class::VirtualNode { + mappings.n2n->filter(m | m.nodes().vnode == self)->count() <= 1 +} + +constraint -> class::VirtualNode { + mappings.resDem->filter(m | m.nodes().vnode == self)->count() <= 1 +} + +// Cost = 1 per mapped virtual node +objective maps -> mapping::n2n { + 1 +} + +objective map10ResDem -> mapping::resDem { + 1 +} + +global objective : max { + maps + map10ResDem +} diff --git a/gipsl.all.build.mappingpreservation/src/gipsl/all/build/mappingpreservation/connector/MappingPreservationConnector.java b/gipsl.all.build.mappingpreservation/src/gipsl/all/build/mappingpreservation/connector/MappingPreservationConnector.java new file mode 100644 index 00000000..a42f995b --- /dev/null +++ b/gipsl.all.build.mappingpreservation/src/gipsl/all/build/mappingpreservation/connector/MappingPreservationConnector.java @@ -0,0 +1,93 @@ +package gipsl.all.build.mappingpreservation.connector; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.emoflon.gips.core.ilp.ILPSolverOutput; + +import gipsl.all.build.mappingpreservation.api.gips.MappingpreservationGipsAPI; +import gipsl.all.build.mappingpreservation.api.gips.mapping.N2nMapping; +import gipsl.all.build.mappingpreservation.api.gips.mapping.ResDemMapping; +import gipsl.all.build.mappingpreservation.api.matches.MapVnodeMatch; +import gipsl.all.build.mappingpreservation.api.matches.MapVnodeWith10ResDemMatch; +import test.suite.gips.utils.AConnector; +import test.suite.gips.utils.GipsTestUtils; +import test.suite.gips.utils.GlobalTestConfig; + +public class MappingPreservationConnector extends AConnector { + + public MappingPreservationConnector(final String modelPath) { + api = new MappingpreservationGipsAPI(); + api.init(GipsTestUtils.pathToAbsUri(modelPath)); + GlobalTestConfig.overrideSolver(api); + } + + @Override + public ILPSolverOutput run(final String outputPath) { + final ILPSolverOutput output = solve(); + ((MappingpreservationGipsAPI) api).getN2n().applyNonZeroMappings(); + save(outputPath); + return output; + } + + public ILPSolverOutput runWithNoApplication(final String outputPath) { + final ILPSolverOutput output = solve(); + save(outputPath); + return output; + } + + public List> applyMappingWithVnodeName(final String vnodeName) { + final var mappings = ((MappingpreservationGipsAPI) api).getN2n().getNonZeroVariableMappings(); + final var filtered = mappings.stream().filter(t -> { + return t.getMatch().getVnode().getName().equals(vnodeName); + }).toList(); + + // Check that only one mapping should be applied + if (filtered.size() != 1) { + throw new UnsupportedOperationException(); + } + + // Check if mapping to be applied has a value > 0 + if (!(filtered.get(0).getValue() > 0)) { + throw new InternalError(); + } + + final var rule = ((MappingpreservationGipsAPI) api).getN2n().getGTRule(); + return filtered.stream().map(m -> rule.apply(m.getMatch(), true)).collect(Collectors.toList()); + } + + public void save(final String path) { + super.save(path); + } + + public Collection getN2nMappings() { + return ((MappingpreservationGipsAPI) api).getN2n().getMappings().values(); + } + + public Collection getResDemMappings() { + return ((MappingpreservationGipsAPI) api).getResDem().getMappings().values(); + } + + public List> applyMappingWithVnode10Name(final String vnodeName) { + final var mappings = ((MappingpreservationGipsAPI) api).getResDem().getNonZeroVariableMappings(); + final var filtered = mappings.stream().filter(t -> { + return t.getMatch().getVnode().getName().equals(vnodeName); + }).toList(); + + // Check that only one mapping should be applied + if (filtered.size() != 1) { + throw new UnsupportedOperationException(); + } + + // Check if mapping to be applied has a value > 0 + if (!(filtered.get(0).getValue() > 0)) { + throw new InternalError(); + } + + final var rule = ((MappingpreservationGipsAPI) api).getResDem().getGTRule(); + return filtered.stream().map(m -> rule.apply(m.getMatch(), true)).collect(Collectors.toList()); + } + +} diff --git a/gipsl.all.build.mappingpreservationb/.classpath b/gipsl.all.build.mappingpreservationb/.classpath new file mode 100644 index 00000000..0b423a2c --- /dev/null +++ b/gipsl.all.build.mappingpreservationb/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/gipsl.all.build.mappingpreservationb/.project b/gipsl.all.build.mappingpreservationb/.project new file mode 100644 index 00000000..756a6069 --- /dev/null +++ b/gipsl.all.build.mappingpreservationb/.project @@ -0,0 +1,25 @@ + + + gipsl.all.build.mappingpreservationb + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.xtext.ui.shared.xtextBuilder + + + + + + org.emoflon.gips.gipsl.ui.gipsNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.PluginNature + org.eclipse.xtext.ui.shared.xtextNature + + diff --git a/gipsl.all.build.mappingpreservationb/.settings/org.eclipse.jdt.core.prefs b/gipsl.all.build.mappingpreservationb/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..3a79233b --- /dev/null +++ b/gipsl.all.build.mappingpreservationb/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,10 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.compliance=21 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=21 diff --git a/gipsl.all.build.mappingpreservationb/META-INF/MANIFEST.MF b/gipsl.all.build.mappingpreservationb/META-INF/MANIFEST.MF new file mode 100644 index 00000000..07661c8e --- /dev/null +++ b/gipsl.all.build.mappingpreservationb/META-INF/MANIFEST.MF @@ -0,0 +1,17 @@ +Manifest-Version: 1.0 +Automatic-Module-Name: gipsl.all.build.mappingpreservationb +Bundle-ManifestVersion: 2 +Bundle-Name: gipsl.all.build.mappingpreservationb +Bundle-Vendor: My Company +Bundle-Version: 1.0.0.qualifier +Export-Package: gipsl.all.build.mappingpreservationb.connector +Bundle-SymbolicName: gipsl.all.build.mappingpreservationb; singleton:=true +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-21 +Require-Bundle: org.emoflon.ibex.common, + org.emoflon.ibex.gt, + org.emoflon.gips.core, + org.emoflon.ibex.gt.democles, + org.emoflon.ibex.gt.hipe, + gipsl.all.build.model, + test.suite.utils diff --git a/gipsl.all.build.mappingpreservationb/build.properties b/gipsl.all.build.mappingpreservationb/build.properties new file mode 100644 index 00000000..14acfb7c --- /dev/null +++ b/gipsl.all.build.mappingpreservationb/build.properties @@ -0,0 +1,5 @@ +source.. = src/,\ + src-gen/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/gipsl.all.build.mappingpreservationb/src/gipsl/all/build/mappingpreservationb/Model.gipsl b/gipsl.all.build.mappingpreservationb/src/gipsl/all/build/mappingpreservationb/Model.gipsl new file mode 100644 index 00000000..96797168 --- /dev/null +++ b/gipsl.all.build.mappingpreservationb/src/gipsl/all/build/mappingpreservationb/Model.gipsl @@ -0,0 +1,66 @@ +package "gipsl.all.build.mappingpreservationb" +import "platform:/resource/gipsl.all.build.model/model/Model.ecore" + +config { + solver := GUROBI [home:="fu", license:="bar"]; + launchConfig := true [main := "TODO"]; + timeLimit := true [value := 5.0]; + randomSeed := true [value := 0]; + presolve := true; + debugOutput := false; +} + +rule incrementVNodeRD { + root: Root { + -containers -> virtualContainer + } + + virtualContainer: VirtualContainer { + -virtualNodes -> vnode + } + + vnode: VirtualResourceNode { + .resourceDemand := vnode.resourceDemand + 1 + } + +// # vnode.resourceDemand != 10 +} + +rule incrementVNodeRDIfZero { + root: Root { + -containers -> virtualContainer + } + + virtualContainer: VirtualContainer { + -virtualNodes -> vnode + } + + vnode: VirtualResourceNode { + .resourceDemand := vnode.resourceDemand + 1 + } + + # vnode.resourceDemand == 0 +} + +mapping incr with incrementVNodeRD; +mapping incrIfZero with incrementVNodeRDIfZero; + +constraint -> class::VirtualNode { + mappings.incr->filter(m | m.nodes().vnode == self)->count() == 1 +} + +constraint -> pattern::incrementVNodeRDIfZero { + mappings.incrIfZero->filter(m | m.nodes().vnode == self.nodes().vnode)->count() == 1 +} + +objective objIncr -> mapping::incr { + 1 +} + +objective objIncrIfZero -> mapping::incrIfZero { + 1 +} + +global objective : max { + objIncr + objIncrIfZero +} \ No newline at end of file diff --git a/gipsl.all.build.mappingpreservationb/src/gipsl/all/build/mappingpreservationb/connector/MappingPreservationBConnector.java b/gipsl.all.build.mappingpreservationb/src/gipsl/all/build/mappingpreservationb/connector/MappingPreservationBConnector.java new file mode 100644 index 00000000..d8e2c808 --- /dev/null +++ b/gipsl.all.build.mappingpreservationb/src/gipsl/all/build/mappingpreservationb/connector/MappingPreservationBConnector.java @@ -0,0 +1,75 @@ +package gipsl.all.build.mappingpreservationb.connector; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.emoflon.gips.core.ilp.ILPSolverOutput; + +import gipsl.all.build.mappingpreservationb.api.gips.MappingpreservationbGipsAPI; +import gipsl.all.build.mappingpreservationb.api.gips.mapping.IncrIfZeroMapping; +import gipsl.all.build.mappingpreservationb.api.gips.mapping.IncrMapping; +import gipsl.all.build.mappingpreservationb.api.matches.IncrementVNodeRDMatch; +import test.suite.gips.utils.AConnector; +import test.suite.gips.utils.GipsTestUtils; +import test.suite.gips.utils.GlobalTestConfig; + +public class MappingPreservationBConnector extends AConnector { + + public MappingPreservationBConnector(final String modelPath) { + api = new MappingpreservationbGipsAPI(); + api.init(GipsTestUtils.pathToAbsUri(modelPath)); + GlobalTestConfig.overrideSolver(api); + } + + @Override + public ILPSolverOutput run(final String outputPath) { + final ILPSolverOutput output = solve(); + save(outputPath); + return output; + } + + public ILPSolverOutput runWithNoApplication(final String outputPath) { + final ILPSolverOutput output = solve(); + save(outputPath); + return output; + } + + public void applyIncrMatches() { + ((MappingpreservationbGipsAPI) api).getIncr().applyNonZeroMappings(); + } + +// public List> applyMappingWithVnodeName(final String vnodeName) { +// final var mappings = ((MappingpreservationbGipsAPI) api).getIncr().getNonZeroVariableMappings(); +// final var filtered = mappings.stream().filter(t -> { +// return t.getMatch().getVnode().getName().equals(vnodeName); +// }).toList(); +// +// // Check that only one mapping should be applied +// if (filtered.size() != 1) { +// throw new UnsupportedOperationException(); +// } +// +// // Check if mapping to be applied has a value > 0 +// if (!(filtered.get(0).getValue() > 0)) { +// throw new InternalError(); +// } +// +// final var rule = ((MappingpreservationbGipsAPI) api).getIncr().getGTRule(); +// return filtered.stream().map(m -> rule.apply(m.getMatch(), true)).collect(Collectors.toList()); +// } + + public void save(final String path) { + super.save(path); + } + + public Collection getIncrMappings() { + return ((MappingpreservationbGipsAPI) api).getIncr().getMappings().values(); + } + + public Collection getIncrIfZeroMappings() { + return ((MappingpreservationbGipsAPI) api).getIncrIfZero().getMappings().values(); + } + +} diff --git a/test.suite.gips/META-INF/MANIFEST.MF b/test.suite.gips/META-INF/MANIFEST.MF index f03cafec..3b284cef 100644 --- a/test.suite.gips/META-INF/MANIFEST.MF +++ b/test.suite.gips/META-INF/MANIFEST.MF @@ -40,6 +40,8 @@ Import-Package: gips.enumequals.connector, gipsl.all.build.implication.connector, gipsl.all.build.implicationstatic.connector, gipsl.all.build.inheritedtypecontext.connector, + gipsl.all.build.mappingpreservation.connector, + gipsl.all.build.mappingpreservationb.connector, gipsl.all.build.nogt.connector, gipsl.all.build.objbug.connector, gipsl.all.build.objbugb.connector, diff --git a/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildMappingPreservationBTest.java b/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildMappingPreservationBTest.java new file mode 100644 index 00000000..cd90eb6c --- /dev/null +++ b/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildMappingPreservationBTest.java @@ -0,0 +1,88 @@ +package test.suite.gipsl.all.build; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.File; + +import org.emoflon.gips.core.ilp.ILPSolverOutput; +import org.emoflon.gips.core.ilp.ILPSolverStatus; +import org.junit.jupiter.api.Test; + +import gipsl.all.build.mappingpreservationb.connector.MappingPreservationBConnector; +import model.Container; +import model.Root; +import model.VirtualContainer; +import model.VirtualNode; +import model.VirtualResourceNode; + +public class GipslAllBuildMappingPreservationBTest extends AGipslAllBuildTest { + + // Setup method + + public void callableSetUp() { + gen.persistModel(MODEL_PATH); + con = new MappingPreservationBConnector(MODEL_PATH); + + // Delete possible file of previous run + final File output = new File(OUTPUT_PATH); + output.delete(); + } + + // Actual tests + // Positive tests + + @Test + public void testOneVNodeZero() { + gen.genVirtualNode("v1", 0); + callableSetUp(); + + final ILPSolverOutput ret = ((MappingPreservationBConnector) con).runWithNoApplication(OUTPUT_PATH); + + // Pre-checks + assertEquals(ILPSolverStatus.OPTIMAL, ret.status()); + + // One VNode with two applied mappings + assertEquals(2, Math.abs(ret.objectiveValue())); + + gen.loadModel(OUTPUT_PATH); + + // Check model state (pre-first application) + checkNumberOfZeroVnodes(1); + assertEquals(1, ((MappingPreservationBConnector) con).getIncrMappings().size()); + assertEquals(1, ((MappingPreservationBConnector) con).getIncrIfZeroMappings().size()); + + // Apply all (one) mapping of type "increment" + ((MappingPreservationBConnector) con).applyIncrMatches(); + + // First mapping (of type "increment") must be present + assertEquals(1, ((MappingPreservationBConnector) con).getIncrMappings().size()); + + // Second mapping (of type "increment if zero") will be gone + assertEquals(0, ((MappingPreservationBConnector) con).getIncrIfZeroMappings().size()); + } + + // + // Utility methods + // + + private void checkNumberOfZeroVnodes(final int expected) { + int vnodeCntr = 0; + + final Root root = gen.getRoot(); + for (final Container c : root.getContainers()) { + if (c instanceof VirtualContainer) { + final VirtualContainer vc = (VirtualContainer) c; + for (final VirtualNode vn : vc.getVirtualNodes()) { + if (vn instanceof VirtualResourceNode vrn) { + if (vrn.getResourceDemand() == 0) { + vnodeCntr++; + } + } + } + } + } + + assertEquals(expected, vnodeCntr); + } + +} diff --git a/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildMappingPreservationTest.java b/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildMappingPreservationTest.java new file mode 100644 index 00000000..9c4b9e5e --- /dev/null +++ b/test.suite.gips/src/test/suite/gipsl/all/build/GipslAllBuildMappingPreservationTest.java @@ -0,0 +1,200 @@ +package test.suite.gipsl.all.build; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.util.Collection; + +import org.emoflon.gips.core.ilp.ILPSolverOutput; +import org.emoflon.gips.core.ilp.ILPSolverStatus; +import org.junit.jupiter.api.Test; + +import gipsl.all.build.mappingpreservation.api.gips.mapping.N2nMapping; +import gipsl.all.build.mappingpreservation.api.gips.mapping.ResDemMapping; +import gipsl.all.build.mappingpreservation.connector.MappingPreservationConnector; +import model.Container; +import model.Root; +import model.VirtualContainer; +import model.VirtualNode; + +public class GipslAllBuildMappingPreservationTest extends AGipslAllBuildTest { + + // Setup method + + public void callableSetUp() { + gen.persistModel(MODEL_PATH); + con = new MappingPreservationConnector(MODEL_PATH); + + // Delete possible file of previous run + final File output = new File(OUTPUT_PATH); + output.delete(); + } + + // Actual tests + // Positive tests + + @Test + public void testMap2to1IndividualApplication() { + gen.genSubstrateNode("s1", 2); + gen.genVirtualNode("v1", 1); + gen.genVirtualNode("v2", 1); + callableSetUp(); + + final ILPSolverOutput ret = ((MappingPreservationConnector) con).runWithNoApplication(OUTPUT_PATH); + + // Pre-checks + assertEquals(ILPSolverStatus.OPTIMAL, ret.status()); + assertEquals(2, Math.abs(ret.objectiveValue())); + + gen.loadModel(OUTPUT_PATH); + + // Check model state (pre-first application) + checkNumberOfEmbeddedVnodes(0); + + final var appliedFirst = ((MappingPreservationConnector) con).applyMappingWithVnodeName("v1"); + assertEquals(1, appliedFirst.size()); + assertEquals("v1", appliedFirst.get(0).get().getVnode().getName()); + + // Check model state (after first application) + ((MappingPreservationConnector) con).save(OUTPUT_PATH); + gen.loadModel(OUTPUT_PATH); + checkNumberOfEmbeddedVnodes(1); + + final var appliedSecond = ((MappingPreservationConnector) con).applyMappingWithVnodeName("v2"); + assertEquals(1, appliedSecond.size()); + assertEquals("v2", appliedSecond.get(0).get().getVnode().getName()); + + // Check model state (after second application) + ((MappingPreservationConnector) con).save(OUTPUT_PATH); + gen.loadModel(OUTPUT_PATH); + checkNumberOfEmbeddedVnodes(2); + } + + @Test + public void testMap2to1ApplyNonZeroMappings() { + gen.genSubstrateNode("s1", 2); + gen.genVirtualNode("v1", 1); + gen.genVirtualNode("v2", 1); + callableSetUp(); + + final ILPSolverOutput ret = ((MappingPreservationConnector) con).run(OUTPUT_PATH); + assertEquals(ILPSolverStatus.OPTIMAL, ret.status()); + assertEquals(2, Math.abs(ret.objectiveValue())); + + // Check model state + gen.loadModel(OUTPUT_PATH); + checkNumberOfEmbeddedVnodes(2); + + // Actual check: Both mappings must still have the value > 0, even if PM got + // updated + final Collection mappings = ((MappingPreservationConnector) con).getN2nMappings(); + // There are only two possible combinations + assertEquals(2, mappings.size()); + for (final N2nMapping m : mappings) { + assertTrue(m.getValue() > 0); + } + } + + @Test + public void testMap10to3ApplyNonZeroMappings() { + gen.genSubstrateNode("s1", 4); + gen.genSubstrateNode("s2", 4); + gen.genSubstrateNode("s3", 4); + for (int i = 1; i <= 10; i++) { + gen.genVirtualNode("v" + i, 1); + } + callableSetUp(); + + final ILPSolverOutput ret = ((MappingPreservationConnector) con).run(OUTPUT_PATH); + assertEquals(ILPSolverStatus.OPTIMAL, ret.status()); + assertEquals(10, Math.abs(ret.objectiveValue())); + + // Check model state + gen.loadModel(OUTPUT_PATH); + checkNumberOfEmbeddedVnodes(10); + + // Actual check: Both mappings must still have the value > 0, even if PM got + // updated + final Collection mappings = ((MappingPreservationConnector) con).getN2nMappings(); + // There are 30 possible combinations + assertEquals(30, mappings.size()); + // Check that there are exactly 10 mappings with value > 0 (one for each virtual + // node) + int counter = 0; + for (final N2nMapping m : mappings) { + if (m.getValue() > 0) { + counter++; + } + } + assertEquals(10, counter); + } + + @Test + public void testTwoSpecMappingsAfterEachOther() { + gen.genSubstrateNode("s1", 100); + gen.genVirtualNode("v1", 1); + gen.genVirtualNode("v2", 1); + gen.genVirtualNode("v100", 10); + callableSetUp(); + + // The first run application does not apply the matches for rule #2. + // (This is intended!) + final ILPSolverOutput ret = ((MappingPreservationConnector) con).run(OUTPUT_PATH); + assertEquals(ILPSolverStatus.OPTIMAL, ret.status()); + assertEquals(3, Math.abs(ret.objectiveValue())); + + // Check model state + gen.loadModel(OUTPUT_PATH); + checkNumberOfEmbeddedVnodes(2); + + // Check that all valid matches of rule #2 are still selected (value > 0) + final Collection resDemMappings = ((MappingPreservationConnector) con).getResDemMappings(); + // There is 1 possible combination + assertEquals(1, resDemMappings.size()); + // The one mapping must also be selected + for (final ResDemMapping m : resDemMappings) { + assertTrue(m.getValue() > 0); + } + + // Next step: Also apply the last mapping + final var appliedSecond = ((MappingPreservationConnector) con).applyMappingWithVnode10Name("v100"); + assertEquals(1, appliedSecond.size()); + assertEquals("v100", appliedSecond.get(0).get().getVnode().getName()); + + // Check model state (after second application) + ((MappingPreservationConnector) con).save(OUTPUT_PATH); + gen.loadModel(OUTPUT_PATH); + checkNumberOfEmbeddedVnodes(3); + + // Check N2N mapping afterwards + final Collection n2nMappings = ((MappingPreservationConnector) con).getN2nMappings(); + // There are 2 possible combinations + assertEquals(2, n2nMappings.size()); + // All two mappings must also be selected + for (final N2nMapping m : n2nMappings) { + assertTrue(m.getValue() > 0); + } + } + + // Utility methods + + private void checkNumberOfEmbeddedVnodes(final int expected) { + int hostedVnodeCntr = 0; + + final Root root = gen.getRoot(); + for (final Container c : root.getContainers()) { + if (c instanceof VirtualContainer) { + final VirtualContainer vc = (VirtualContainer) c; + for (final VirtualNode vn : vc.getVirtualNodes()) { + if (vn.getHost() != null) { + hostedVnodeCntr++; + } + } + } + } + + assertEquals(expected, hostedVnodeCntr); + } + +} diff --git a/test.suite.gips/src/test/suite/gipsl/all/build/utils/AllBuildModelGenerator.java b/test.suite.gips/src/test/suite/gipsl/all/build/utils/AllBuildModelGenerator.java index 116eb93b..b15435d9 100644 --- a/test.suite.gips/src/test/suite/gipsl/all/build/utils/AllBuildModelGenerator.java +++ b/test.suite.gips/src/test/suite/gipsl/all/build/utils/AllBuildModelGenerator.java @@ -86,4 +86,8 @@ public Container getContainer(final String name) { return null; } + public Root getRoot() { + return root; + } + }