From fd3684b5440dacca0c4bf4be15930555a79e2100 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Tue, 21 May 2019 17:00:01 -0400 Subject: VIATRA DSE and COIN-OR CBC implementations of CPS case study --- .../dslreasoner/domains/cps/cplex/CbcCpsMain.xtend | 53 +++++++ .../domains/cps/cplex/CpsToLpTranslator.xtend | 171 +++++++++++++++++++++ .../domains/cps/dse/CpsStateCoder.xtend | 134 ++++++++++++++++ .../domains/cps/dse/RuleBasedCpsMain.xtend | 39 +++++ .../domains/cps/dse/RuleBasedCpsSolver.xtend | 74 +++++++++ .../domains/cps/generator/CpsGenerator.xtend | 7 + .../dslreasoner/domains/cps/queries/CpsQueries.vql | 82 ++++++++-- 7 files changed, 547 insertions(+), 13 deletions(-) create mode 100644 Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/cplex/CbcCpsMain.xtend create mode 100644 Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/cplex/CpsToLpTranslator.xtend create mode 100644 Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/CpsStateCoder.xtend create mode 100644 Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/RuleBasedCpsMain.xtend create mode 100644 Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/RuleBasedCpsSolver.xtend (limited to 'Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit') diff --git a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/cplex/CbcCpsMain.xtend b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/cplex/CbcCpsMain.xtend new file mode 100644 index 00000000..7ec0f84d --- /dev/null +++ b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/cplex/CbcCpsMain.xtend @@ -0,0 +1,53 @@ +package hu.bme.mit.inf.dslreasoner.domains.cps.cplex + +import hu.bme.mit.inf.dslreasoner.domains.cps.CpsPackage +import hu.bme.mit.inf.dslreasoner.domains.cps.generator.CpsGenerator +import java.io.BufferedReader +import java.io.BufferedWriter +import java.io.FileReader +import java.io.FileWriter +import org.eclipse.emf.ecore.EPackage +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl +import java.util.concurrent.TimeUnit + +class CbcCpsMain { + static val PROBLEM_FILE = "problem.lp" + static val SOLUTION_FILE = "solution.txt" + + private new() { + new IllegalStateException("This is a static utility class and should not be instantiated directly.") + } + + static def void main(String[] args) { + Resource.Factory.Registry.INSTANCE.extensionToFactoryMap.put(Resource.Factory.Registry.DEFAULT_EXTENSION, + new XMIResourceFactoryImpl) + EPackage.Registry.INSTANCE.put(CpsPackage.eNS_URI, CpsPackage.eINSTANCE) + val generator = new CpsGenerator(1, 4, 1) + val problem = generator.generateCpsProblem + val toLp = new CpsToLpTranslator(problem, 10, true) + val lp = toLp.lpProblem + val writer = new BufferedWriter(new FileWriter(PROBLEM_FILE)) + try { + writer.append(lp) + } finally { + writer.close + } + val process = new ProcessBuilder().inheritIO.command("cbc", PROBLEM_FILE, "solve", "solu", SOLUTION_FILE).start + if (!process.waitFor(120, TimeUnit.SECONDS)) { + System.err.println("Timeout reached") + process.destroyForcibly + System.exit(-1) + } + if (process.exitValue != 0) { + System.err.println("Unexpected exit value " + process.exitValue) + System.exit(-1) + } + val reader = new BufferedReader(new FileReader(SOLUTION_FILE)) + try { + reader.lines.forEach[println(it)] + } finally { + reader.close + } + } +} diff --git a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/cplex/CpsToLpTranslator.xtend b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/cplex/CpsToLpTranslator.xtend new file mode 100644 index 00000000..c38af3a0 --- /dev/null +++ b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/cplex/CpsToLpTranslator.xtend @@ -0,0 +1,171 @@ +package hu.bme.mit.inf.dslreasoner.domains.cps.cplex + +import com.google.common.collect.ImmutableList +import com.google.common.collect.ImmutableMap +import hu.bme.mit.inf.dslreasoner.domains.cps.ApplicationType +import hu.bme.mit.inf.dslreasoner.domains.cps.CyberPhysicalSystem +import hu.bme.mit.inf.dslreasoner.domains.cps.HostType +import hu.bme.mit.inf.dslreasoner.domains.cps.Requirement +import java.util.List +import java.util.Map + +class CpsToLpTranslator { + static val MINIMUM_MEMORY_USAGE = 0.25 + static val MINIMUM_HDD_USAGE = 0.25 + + val CyberPhysicalSystem cps + val Map> appInstances + val Map> hostInstances + val boolean breakSymmetry + + new(CyberPhysicalSystem cps, int hostInstanceCount, boolean breakSymmetry) { + this.cps = cps + appInstances = createAppInstances + hostInstances = createHostInstances(hostInstanceCount) + this.breakSymmetry = breakSymmetry + } + + private def createAppInstances() { + val builder = ImmutableMap.builder + var int i = 0 + for (req : requirements) { + val listBuilder = ImmutableList.builder + for (var int j = 0; j < req.count; j++) { + listBuilder.add('''r«i»a«j»''') + } + builder.put(req, listBuilder.build) + i++ + } + builder.build + } + + private def createHostInstances(int hostInstanceCount) { + val builder = ImmutableMap.builder + var int i = 0 + for (hostType : cps.hostTypes) { + val listBuilder = ImmutableList.builder + for (var int j = 0; j < hostInstanceCount; j++) { + listBuilder.add('''h«i»i«j»''') + } + builder.put(hostType, listBuilder.build) + i++ + } + builder.build + } + + def getLpProblem() { + ''' + Minimize + total_cost: «objective» + Subject To + «constraints» + Bounds + «bounds» + Binary + «binaryVariables» + End + ''' + } + + private def getObjective() { + '''«FOR pair : hostInstancesWithType SEPARATOR " + "»«pair.key.cost» «pair.value.existsVariable»«ENDFOR»''' + } + + private def getConstraints() { + ''' + «FOR appPair : appInstancesWithType» + «appPair.value»_allocated: «FOR host : appPair.key.possibleHostInstances SEPARATOR " + "»«getAllocatedToVariable(appPair.value, host)»«ENDFOR» = 1 + «FOR host : appPair.key.possibleHostInstances» + «appPair.value»_to_«host»_exists: «host.existsVariable» - «getAllocatedToVariable(appPair.value, host)» >= 0 + «ENDFOR» + «ENDFOR» + «FOR hostPair : hostInstancesWithType» + «hostPair.value»_mem_use: «FOR appPair : hostPair.key.possibleAppInstancesWithRequirements SEPARATOR " + "»«appPair.key.requiredMemory» «getAllocatedToVariable(appPair.value, hostPair.value)»«ENDFOR» - «hostPair.key.defaultMemory» «hostPair.value.memoryUsageVariable» = 0 + «hostPair.value»_hdd_use: «FOR appPair : hostPair.key.possibleAppInstancesWithRequirements SEPARATOR " + "»«appPair.key.requiredHdd» «getAllocatedToVariable(appPair.value, hostPair.value)»«ENDFOR» - «hostPair.key.defaultHdd» «hostPair.value.hddUsageVariable» = 0 + «ENDFOR» + average_mem: «FOR host : allHostInstances SEPARATOR " + "»«host.memoryUsageVariable» - «MINIMUM_MEMORY_USAGE» «host.existsVariable»«ENDFOR» >= 0 + average_hdd: «FOR host : allHostInstances SEPARATOR " + "»«host.memoryUsageVariable» - «MINIMUM_HDD_USAGE» «host.existsVariable»«ENDFOR» >= 0 + «FOR reqPair : requirements.filter[count > 1].indexed» + «FOR host : reqPair.value.type.requirements.flatMap[hostInstances.get(hostType)]» + r«reqPair.key»_«host»_redundant: «FOR app : appInstances.get(reqPair.value) SEPARATOR " + "»«getAllocatedToVariable(app, host)»«ENDFOR» <= 1 + «ENDFOR» + «ENDFOR» + «IF breakSymmetry» + «FOR hosts : hostInstances.values» + «FOR i : 0 ..< (hosts.size - 1)» + «hosts.get(i + 1)»_after_«hosts.get(i)»: «hosts.get(i).existsVariable» - «hosts.get(i + 1).existsVariable» >= 0 + «ENDFOR» + «ENDFOR» + «ENDIF» + ''' + } + + private def getBounds() { + ''' + «FOR host : allHostInstances» + 0 <= «host.memoryUsageVariable» <= 1 + 0 <= «host.hddUsageVariable» <= 1 + «ENDFOR» + ''' + } + + private def getBinaryVariables() { + ''' + «FOR host : allHostInstances» + «host.existsVariable» + «ENDFOR» + «FOR appPair : appInstancesWithType» + «FOR host : appPair.key.possibleHostInstances» + «getAllocatedToVariable(appPair.value, host)» + «ENDFOR» + «ENDFOR» + ''' + } + + private def getRequirements() { + cps.requests.flatMap[requirements] + } + + private def getAllHostInstances() { + hostInstances.values.flatMap[it] + } + + private def getHostInstancesWithType() { + hostInstances.entrySet.flatMap[pair|pair.value.map[pair.key -> it]] + } + + private def getAppInstancesWithType() { + appInstances.entrySet.flatMap[pair|pair.value.map[pair.key.type -> it]] + } + + private def getPossibleHostInstances(ApplicationType appType) { + appType.requirements.flatMap[req|hostInstances.get(req.hostType)] + } + + private def getPossibleAppInstancesWithRequirements(HostType hostType) { + appInstances.entrySet.flatMap [ pair | + val resourceReq = pair.key.type.requirements.findFirst[it.hostType == hostType] + if (resourceReq === null) { + emptyList + } else { + pair.value.map[resourceReq -> it] + } + ] + } + + private def getExistsVariable(String hostInstance) { + '''«hostInstance»_exists''' + } + + private def getMemoryUsageVariable(String hostInstance) { + '''«hostInstance»_mem''' + } + + private def getHddUsageVariable(String hostInstance) { + '''«hostInstance»_hdd''' + } + + private def getAllocatedToVariable(String appInstance, String hostInstance) { + '''«appInstance»_to_«hostInstance»''' + } +} diff --git a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/CpsStateCoder.xtend b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/CpsStateCoder.xtend new file mode 100644 index 00000000..223cee03 --- /dev/null +++ b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/CpsStateCoder.xtend @@ -0,0 +1,134 @@ +package hu.bme.mit.inf.dslreasoner.domains.cps.dse + +import hu.bme.mit.inf.dslreasoner.domains.cps.ApplicationInstance +import hu.bme.mit.inf.dslreasoner.domains.cps.CyberPhysicalSystem +import hu.bme.mit.inf.dslreasoner.domains.cps.HostInstance +import hu.bme.mit.inf.dslreasoner.domains.cps.HostType +import hu.bme.mit.inf.dslreasoner.domains.cps.Request +import hu.bme.mit.inf.dslreasoner.domains.cps.Requirement +import org.eclipse.emf.common.notify.Notifier +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.emf.ecore.resource.ResourceSet +import org.eclipse.viatra.dse.statecode.IStateCoder +import org.eclipse.viatra.dse.statecode.IStateCoderFactory +import org.eclipse.viatra.query.runtime.api.IPatternMatch +import org.eclipse.xtend2.lib.StringConcatenationClient + +class CpsStateCoder implements IStateCoder { + CyberPhysicalSystem cps + + protected new() { + } + + override init(Notifier notifier) { + cps = switch (notifier) { + ResourceSet: getCpsFromResourceSet(notifier) + Resource: getCpsFromResource(notifier) + CyberPhysicalSystem: notifier + default: throw new IllegalArgumentException("notifier is not a CyberPhysicalSystem") + } + } + + private def getCpsFromResourceSet(ResourceSet resourceSet) { + if (resourceSet.resources.empty) { + throw new IllegalArgumentException("No Resource in ResourceSet") + } + val resource = resourceSet.resources.head + getCpsFromResource(resource) + } + + private def getCpsFromResource(Resource resource) { + if (resource.contents.empty) { + throw new IllegalArgumentException("No EObject in Resource") + } + val cps = resource.contents.head + if (cps instanceof CyberPhysicalSystem) { + cps + } else { + throw new IllegalArgumentException("EObject in Resource is not a CyberPhysicalSystem") + } + } + + override String createStateCode() { + '''«createRequestsCode»«createHostTypesCode»''' + } + + private def StringConcatenationClient createRequestsCode() { + '''«FOR request : cps.requests»«createRequestCode(request)»«ENDFOR»''' + } + + private def StringConcatenationClient createRequestCode(Request request) { + '''[«FOR requirement : request.requirements»«createRequirementCode(requirement)»«ENDFOR»]''' + } + + private def StringConcatenationClient createRequirementCode(Requirement requirement) { + '''[«FOR app : requirement.instances SEPARATOR ","»«createAppCode(app)»«ENDFOR»]''' + } + + private def createAppCode(ApplicationInstance app) { + if (app.allocatedTo === null) { + "-" + } else { + createMatchArgumentCode(app.allocatedTo) + } + } + + private def createHostTypesCode() { + '''(«FOR hostType : cps.hostTypes SEPARATOR ","»«hostType.instances.size»«ENDFOR»)''' + } + + override String createActivationCode(IPatternMatch match) { + '''«match.specification.simpleName»(«FOR arg : match.toArray SEPARATOR ","»«createMatchArgumentCode(arg)»«ENDFOR»)''' + } + + protected dispatch def String createMatchArgumentCode(Requirement requirement) { + val request = requirement.eContainer + if (request instanceof Request) { + if (request.eContainer != cps) { + throw new IllegalArgumentException("Request is not contained in the CPS") + } + val requestIndex = cps.requests.indexOf(request) + val requirementIndex = request.requirements.indexOf(requirement) + requestIndex + "." + requirementIndex + } else { + throw new IllegalArgumentException("Requirement is not contained in a request") + } + } + + protected dispatch def String createMatchArgumentCode(ApplicationInstance app) { + val requirement = app.requirement + if (requirement === null) { + throw new IllegalArgumentException("Application instance is not associated with a requirement") + } + val instanceIndex = requirement.instances.indexOf(app) + createMatchArgumentCode(requirement) + "." + instanceIndex + } + + protected dispatch def String createMatchArgumentCode(HostInstance host) { + val hostType = host.eContainer + if (hostType instanceof HostType) { + val hostIndex = hostType.instances.indexOf(host) + createMatchArgumentCode(hostType) + "." + hostIndex + } else { + throw new IllegalArgumentException("Host is not contained in a host type") + } + } + + protected dispatch def String createMatchArgumentCode(HostType hostType) { + if (hostType.eContainer != cps) { + throw new IllegalArgumentException("Host type is not contained in the CPS") + } + val hostTypeIndex = cps.hostTypes.indexOf(hostType) + hostTypeIndex.toString + } + + protected dispatch def createMatchArgumentCode(Object object) { + throw new IllegalArgumentException("Unknown match argument: ") + } + + static class Factory implements IStateCoderFactory { + override createStateCoder() { + new CpsStateCoder + } + } +} diff --git a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/RuleBasedCpsMain.xtend b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/RuleBasedCpsMain.xtend new file mode 100644 index 00000000..b2cc0063 --- /dev/null +++ b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/RuleBasedCpsMain.xtend @@ -0,0 +1,39 @@ +package hu.bme.mit.inf.dslreasoner.domains.cps.dse + +import hu.bme.mit.inf.dslreasoner.domains.cps.CpsPackage +import hu.bme.mit.inf.dslreasoner.domains.cps.generator.CpsGenerator +import hu.bme.mit.inf.dslreasoner.domains.cps.queries.CpsQueries +import org.eclipse.emf.ecore.EPackage +import org.eclipse.emf.ecore.EStructuralFeature +import org.eclipse.emf.ecore.resource.Resource +import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl +import org.eclipse.viatra.addon.querybasedfeatures.runtime.QueryBasedFeatureSettingDelegateFactory +import org.eclipse.viatra.addon.querybasedfeatures.runtime.handler.QueryBasedFeatures +import org.eclipse.viatra.dse.api.DesignSpaceExplorer +import org.eclipse.viatra.dse.api.DesignSpaceExplorer.DseLoggingLevel +import org.eclipse.viatra.query.runtime.extensibility.SingletonQueryGroupProvider +import org.eclipse.viatra.query.runtime.registry.QuerySpecificationRegistry +import org.eclipse.viatra.query.runtime.registry.connector.QueryGroupProviderSourceConnector + +class RuleBasedCpsMain { + private new() { + new IllegalStateException("This is a static utility class and should not be instantiated directly.") + } + + static def void main(String[] args) { + DesignSpaceExplorer.turnOnLogging(DseLoggingLevel.VERBOSE_FULL) + Resource.Factory.Registry.INSTANCE.extensionToFactoryMap.put(Resource.Factory.Registry.DEFAULT_EXTENSION, + new XMIResourceFactoryImpl) + EStructuralFeature.Internal.SettingDelegate.Factory.Registry.INSTANCE.put(QueryBasedFeatures.ANNOTATION_SOURCE, + new QueryBasedFeatureSettingDelegateFactory) + EPackage.Registry.INSTANCE.put(CpsPackage.eNS_URI, CpsPackage.eINSTANCE) + QuerySpecificationRegistry.instance.addSource( + new QueryGroupProviderSourceConnector("CpsQueries", new SingletonQueryGroupProvider(CpsQueries.instance), + true)) + val generator = new CpsGenerator(1, 4, 1) + val problem = generator.generateCpsProblem +// problem.eResource.save(emptyMap) + val solver = new RuleBasedCpsSolver + solver.solve(problem) + } +} diff --git a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/RuleBasedCpsSolver.xtend b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/RuleBasedCpsSolver.xtend new file mode 100644 index 00000000..e4c758f0 --- /dev/null +++ b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/dse/RuleBasedCpsSolver.xtend @@ -0,0 +1,74 @@ +package hu.bme.mit.inf.dslreasoner.domains.cps.dse + +import hu.bme.mit.inf.dslreasoner.domains.cps.CpsFactory +import hu.bme.mit.inf.dslreasoner.domains.cps.CpsPackage +import hu.bme.mit.inf.dslreasoner.domains.cps.CyberPhysicalSystem +import hu.bme.mit.inf.dslreasoner.domains.cps.queries.Allocate +import hu.bme.mit.inf.dslreasoner.domains.cps.queries.AverageFreeHddMetric +import hu.bme.mit.inf.dslreasoner.domains.cps.queries.AverageFreeMemoryMetric +import hu.bme.mit.inf.dslreasoner.domains.cps.queries.CostMetric +import hu.bme.mit.inf.dslreasoner.domains.cps.queries.CreateHostInstance +import hu.bme.mit.inf.dslreasoner.domains.cps.queries.GuidanceObjective +import hu.bme.mit.inf.dslreasoner.domains.cps.queries.RequirementNotSatisfied +import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.CompositeDirectionalThresholdObjective +import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.ObjectiveKind +import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.ObjectiveThreshold +import hu.bme.mit.inf.dslreasoner.viatrasolver.reasoner.optimization.QueryBasedObjective +import org.eclipse.viatra.dse.api.DesignSpaceExplorer +import org.eclipse.viatra.dse.evolutionary.EvolutionaryStrategyBuilder +import org.eclipse.viatra.transformation.runtime.emf.rules.batch.BatchTransformationRuleFactory + +class RuleBasedCpsSolver { + extension val BatchTransformationRuleFactory = new BatchTransformationRuleFactory + extension val CpsFactory = CpsFactory.eINSTANCE + + def solve(CyberPhysicalSystem problem) { +// for (request : problem.requests) { +// for (req : request.requirements) { +// for (i : 0 ..< req.count) { +// val app = createApplicationInstance +// req.type.instances += app +// req.instances += app +// } +// } +// } + val dse = new DesignSpaceExplorer + dse.addMetaModelPackage(CpsPackage.eINSTANCE) + dse.initialModel = problem.eResource.resourceSet + dse.addTransformationRule(createRule(RequirementNotSatisfied.instance).action [ + val app = createApplicationInstance + req.type.instances += app + req.instances += app + ].build) + dse.addTransformationRule(createRule(Allocate.instance).action [ + app.allocatedTo = host + ].build) +// dse.addTransformationRule(createRule(UnallocateAppInstance.instance).action [ +// app.allocatedTo = null +// ].build) + dse.addTransformationRule(createRule(CreateHostInstance.instance).action [ + hostType.instances += createHostInstance + ].build) +// dse.addTransformationRule(createRule(RemoveHostInstance.instance).action [ +// hostInstance.type.instances -= hostInstance +// ].build) + dse.addObjective( + new CompositeDirectionalThresholdObjective("Composite", + new QueryBasedObjective(GuidanceObjective.instance, ObjectiveKind.LOWER_IS_BETTER, + new ObjectiveThreshold.Inclusive(0), 0), + new QueryBasedObjective(AverageFreeMemoryMetric.instance, ObjectiveKind.LOWER_IS_BETTER, + new ObjectiveThreshold.Inclusive(0.75), 0), + new QueryBasedObjective(AverageFreeHddMetric.instance, ObjectiveKind.LOWER_IS_BETTER, + new ObjectiveThreshold.Inclusive(0.75), 0))) + dse.addObjective( + new QueryBasedObjective(CostMetric.instance, ObjectiveKind.LOWER_IS_BETTER, + ObjectiveThreshold.NO_THRESHOLD, 0)) + dse.maxNumberOfThreads = 1 + dse.stateCoderFactory = new CpsStateCoder.Factory + val strategy = EvolutionaryStrategyBuilder.createNsga2Strategy(25) + dse.startExplorationWithTimeout(strategy, 2 * 60 * 1000) + for (solution : dse.solutions) { + println("Found solution: " + solution.stateCode + " " + solution.arbitraryTrajectory.fitness) + } + } +} diff --git a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/generator/CpsGenerator.xtend b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/generator/CpsGenerator.xtend index 0a510f0f..390d13d3 100644 --- a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/generator/CpsGenerator.xtend +++ b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/generator/CpsGenerator.xtend @@ -5,6 +5,8 @@ import hu.bme.mit.inf.dslreasoner.domains.cps.CyberPhysicalSystem import hu.bme.mit.inf.dslreasoner.domains.cps.HostType import java.util.Collection import java.util.Random +import org.eclipse.emf.common.util.URI +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl class CpsGenerator { extension val CpsFactory = CpsFactory.eINSTANCE @@ -28,8 +30,11 @@ class CpsGenerator { } def generateCpsProblem() { + val resourceSet = new ResourceSetImpl + val resource = resourceSet.createResource(URI.createFileURI("dummy.dummyext")) createCyberPhysicalSystem => [ val cps = it + resource.contents += cps createLowCpuHostTypes val highCpuHostTypes = createHighCpuHostTypes for (var int i = 0; i < applicationTypeCount; i++) { @@ -58,6 +63,7 @@ class CpsGenerator { val hdd = nextInt(MIN_HDD, MAX_HDD) for (hostType : allowedHostTypes) { appType.requirements += createResourceRequirement => [ + it.hostType = hostType requiredMemory = memory requiredHdd = hdd ] @@ -83,6 +89,7 @@ class CpsGenerator { private def createHostType(CyberPhysicalSystem it, int cost, int memory, int hdd) { val hostType = createHostType => [ + it.cost = cost defaultMemory = memory defaultHdd = hdd ] diff --git a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/queries/CpsQueries.vql b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/queries/CpsQueries.vql index 40337443..aa78dc38 100644 --- a/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/queries/CpsQueries.vql +++ b/Domains/hu.bme.mit.inf.dslreasoner.domains.cps/src/hu/bme/mit/inf/dslreasoner/domains/cps/queries/CpsQueries.vql @@ -3,28 +3,23 @@ package hu.bme.mit.inf.dslreasoner.domains.cps.queries import "http://www.eclipse.org/emf/2002/Ecore" import "http://www.example.org/cps" -@QueryBasedFeature(feature = "applications") -pattern cpsApplications(Cps : CyberPhysicalSystem, AppInstance : ApplicationInstance) { +private pattern cpsApplications(Cps : CyberPhysicalSystem, AppInstance : ApplicationInstance) { CyberPhysicalSystem.applicationTypes.instances(Cps, AppInstance); } -@QueryBasedFeature(feature = "hosts") -pattern cpsHosts(Cps : CyberPhysicalSystem, HostInstance : HostInstance) { +private pattern cpsHosts(Cps : CyberPhysicalSystem, HostInstance : HostInstance) { CyberPhysicalSystem.hostTypes.instances(Cps, HostInstance); } -@QueryBasedFeature(feature = "totalMemory") -pattern totalMemory(Host : HostInstance, Memory : EInt) { +private pattern totalMemory(Host : HostInstance, Memory : EInt) { HostInstance.type.defaultMemory(Host, Memory); } -@QueryBasedFeature(feature = "totalHdd") -pattern totalHdd(Host : HostInstance, Hdd : EInt) { +private pattern totalHdd(Host : HostInstance, Hdd : EInt) { HostInstance.type.defaultHdd(Host, Hdd); } -@QueryBasedFeature(feature = "availableMemory") -pattern availableMemory(Host : HostInstance, Memory : java Integer) { +private pattern availableMemory(Host : HostInstance, Memory : java Integer) { find totalMemory(Host, TotalMemory); RequiredMemory == sum find memoryRequirement(Host, _, #_); Memory == eval(TotalMemory - RequiredMemory); @@ -35,8 +30,7 @@ private pattern memoryRequirement(Host : HostInstance, App : ApplicationInstance ResourceRequirement.requiredMemory(Req, Memory); } -@QueryBasedFeature(feature = "availableHdd") -pattern availableHdd(Host : HostInstance, Hdd : java Integer) { +private pattern availableHdd(Host : HostInstance, Hdd : java Integer) { find totalHdd(Host, TotalHdd); RequiredHdd == sum find hddRequirement(Host, _, #_); Hdd == eval(TotalHdd - RequiredHdd); @@ -47,7 +41,7 @@ private pattern hddRequirement(Host : HostInstance, App : ApplicationInstance, H ResourceRequirement.requiredHdd(Req, Hdd); } -private pattern resourceRequirement(Host : HostInstance, App : ApplicationInstance, Req : ResourceRequirement) { +pattern resourceRequirement(Host : HostInstance, App : ApplicationInstance, Req : ResourceRequirement) { ApplicationInstance.allocatedTo(App, Host); ApplicationInstance.type.requirements(App, Req); HostInstance.type(Host, HostType); @@ -106,6 +100,12 @@ pattern redundantInstancesOnSameHost(Req : Requirement) { ApplicationInstance.allocatedTo(App2, Host); } +// +// Metrics +// + +// Free memory + pattern averageFreeMemoryMetric(Average : java Double) { Average == avg find freeMemoryPercentage(_, #_); } @@ -116,6 +116,8 @@ private pattern freeMemoryPercentage(Host : HostInstance, Free : java Double) { Free == eval((Available as double) / Total); } +// Free HDD + pattern averageFreeHddMetric(Average : java Double) { Average == avg find freeHddPercentage(_, #_); } @@ -126,6 +128,8 @@ private pattern freeHddPercentage(Host : HostInstance, Free : java Double) { Free == eval((Available as double) / Total); } +// Total cost + pattern costMetric(Cost : java Integer) { Cost == sum find cpsCost(_, #_); } @@ -140,3 +144,55 @@ private pattern hostInstanceCost(Cps : CyberPhysicalSystem, Host : HostInstance, find cpsHosts(Cps, Host); HostInstance.type.cost(Host, Cost); } + +// +// Transformation rule preconditions for rule-based DSE +// + +pattern allocate(App : ApplicationInstance, Host : HostInstance) { + ApplicationInstance.type.requirements(App, Req); + ResourceRequirement.hostType.instances(Req, Host); + find unallocatedAppInstance(App); + find availableMemory(Host, AvailableMem); + find availableHdd(Host, AvailableHdd); + ResourceRequirement.requiredMemory(Req, RequiredMem); + ResourceRequirement.requiredHdd(Req, RequiredHdd); + check(AvailableMem >= RequiredMem); + check(AvailableHdd >= RequiredHdd); + neg ApplicationInstance.requirement.instances.allocatedTo(App, Host); +} + +pattern unallocateAppInstance(App : ApplicationInstance) { + ApplicationInstance.allocatedTo(App, _); +} + +pattern createHostInstance(HostType : HostType) { + find unallocatedAppInstance(App); + ApplicationInstance.type.requirements.hostType(App, HostType); +} + +pattern removeHostInstance(HostInstance : HostInstance) { + neg HostInstance.applications(HostInstance, _); +} + +private pattern unallocatedAppInstance(App : ApplicationInstance) { + neg ApplicationInstance.allocatedTo(App, _); +} + +private pattern requiredAppInstances(Req : Requirement, Remaining : java Integer) { + Instances == count find satisfyingInstance(Req, _); + Requirement.count(Req, RequiredCount); + Remaining == eval(RequiredCount - Instances); +} + +private pattern noHostToAllocateTo(App : ApplicationInstance) { + find unallocatedAppInstance(App); + neg find allocate(App, _); +} + +pattern guidanceObjective(Value : java Integer) { + UnallocatedInstances == count find unallocatedAppInstance(_); + RequiredInstances == sum find requiredAppInstances(_, #_); + NoHostToAllocate == count find noHostToAllocateTo(_); + Value == eval(2 * UnallocatedInstances + 4 * RequiredInstances + NoHostToAllocate); +} -- cgit v1.2.3-54-g00ecf