| 1 | package de.uka.ipd.sdq.dsexplore.opt4j.representation; |
| 2 | |
| 3 | import java.util.ArrayList; |
| 4 | import java.util.LinkedList; |
| 5 | import java.util.List; |
| 6 | |
| 7 | import org.apache.log4j.Logger; |
| 8 | import org.eclipse.core.runtime.CoreException; |
| 9 | import org.eclipse.emf.common.util.EList; |
| 10 | import org.eclipse.emf.ecore.EObject; |
| 11 | import org.eclipse.emf.ecore.util.EcoreUtil; |
| 12 | import org.opt4j.core.problem.Decoder; |
| 13 | |
| 14 | import com.google.inject.Inject; |
| 15 | |
| 16 | import de.uka.ipd.sdq.dsexplore.analysis.PCMPhenotype; |
| 17 | import de.uka.ipd.sdq.dsexplore.designdecisions.alternativecomponents.AlternativeComponent; |
| 18 | import de.uka.ipd.sdq.dsexplore.exception.ChoiceOutOfBoundsException; |
| 19 | import de.uka.ipd.sdq.dsexplore.exception.ExceptionHelper; |
| 20 | import de.uka.ipd.sdq.dsexplore.exception.InvalidChoiceForDegreeException; |
| 21 | import de.uka.ipd.sdq.dsexplore.helper.DegreeOfFreedomHelper; |
| 22 | import de.uka.ipd.sdq.dsexplore.helper.EMFHelper; |
| 23 | import de.uka.ipd.sdq.dsexplore.helper.ResultsWriter; |
| 24 | import de.uka.ipd.sdq.dsexplore.opt4j.genotype.DesignDecisionGenotype; |
| 25 | import de.uka.ipd.sdq.dsexplore.opt4j.start.Opt4JStarter; |
| 26 | import de.uka.ipd.sdq.pcm.allocation.AllocationContext; |
| 27 | import de.uka.ipd.sdq.pcm.core.composition.AssemblyContext; |
| 28 | import de.uka.ipd.sdq.pcm.core.entity.Entity; |
| 29 | import de.uka.ipd.sdq.pcm.cost.helper.CostUtil; |
| 30 | import de.uka.ipd.sdq.pcm.designdecision.AllocationDegree; |
| 31 | import de.uka.ipd.sdq.pcm.designdecision.AssembledComponentDegree; |
| 32 | import de.uka.ipd.sdq.pcm.designdecision.CapacityDegree; |
| 33 | import de.uka.ipd.sdq.pcm.designdecision.Choice; |
| 34 | import de.uka.ipd.sdq.pcm.designdecision.ContinousRangeChoice; |
| 35 | import de.uka.ipd.sdq.pcm.designdecision.ContinuousProcessingRateDegree; |
| 36 | import de.uka.ipd.sdq.pcm.designdecision.ContinuousRangeDegree; |
| 37 | import de.uka.ipd.sdq.pcm.designdecision.DegreeOfFreedomInstance; |
| 38 | import de.uka.ipd.sdq.pcm.designdecision.DiscreteProcessingRateDegree; |
| 39 | import de.uka.ipd.sdq.pcm.designdecision.DiscreteRangeChoice; |
| 40 | import de.uka.ipd.sdq.pcm.designdecision.DiscreteRangeDegree; |
| 41 | import de.uka.ipd.sdq.pcm.designdecision.ClassChoice; |
| 42 | import de.uka.ipd.sdq.pcm.designdecision.ClassDegree; |
| 43 | import de.uka.ipd.sdq.pcm.designdecision.ExchangeComponentRule; |
| 44 | import de.uka.ipd.sdq.pcm.designdecision.NumberOfCoresDegree; |
| 45 | import de.uka.ipd.sdq.pcm.designdecision.ProcessingRateDegree; |
| 46 | import de.uka.ipd.sdq.pcm.designdecision.ProcessingResourceDegree; |
| 47 | import de.uka.ipd.sdq.pcm.designdecision.RangeDegree; |
| 48 | import de.uka.ipd.sdq.pcm.designdecision.ResourceContainerReplicationDegree; |
| 49 | import de.uka.ipd.sdq.pcm.designdecision.ResourceContainerReplicationDegreeWithComponentChange; |
| 50 | import de.uka.ipd.sdq.pcm.designdecision.SchedulingPolicyChoice; |
| 51 | import de.uka.ipd.sdq.pcm.designdecision.SchedulingPolicyDegree; |
| 52 | import de.uka.ipd.sdq.pcm.designdecision.designdecisionFactory; |
| 53 | import de.uka.ipd.sdq.pcm.designdecision.impl.designdecisionFactoryImpl; |
| 54 | import de.uka.ipd.sdq.pcm.repository.PassiveResource; |
| 55 | import de.uka.ipd.sdq.pcm.repository.RepositoryComponent; |
| 56 | import de.uka.ipd.sdq.pcm.resourceenvironment.LinkingResource; |
| 57 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
| 58 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceContainer; |
| 59 | import de.uka.ipd.sdq.pcm.resourceenvironment.SchedulingPolicy; |
| 60 | import de.uka.ipd.sdq.pcm.resourcetype.ProcessingResourceType; |
| 61 | import de.uka.ipd.sdq.pcmsolver.models.PCMInstance; |
| 62 | |
| 63 | /** |
| 64 | * The {@link DSEDecoder} is responsible for converting the genotypes into |
| 65 | * proper PCM instances that can then be analysed. |
| 66 | * |
| 67 | * @author Anne |
| 68 | * |
| 69 | */ |
| 70 | public class DSEDecoder implements Decoder<DesignDecisionGenotype, PCMPhenotype> { |
| 71 | |
| 72 | //private final DSEProblem problem; |
| 73 | |
| 74 | /** Logger for log4j. */ |
| 75 | private static Logger logger = |
| 76 | Logger.getLogger("de.uka.ipd.sdq.dsexplore"); |
| 77 | |
| 78 | /** Store first MTTF and rate values to adjust later MTTF with (see {@link #applyChangeProcessingRateDecision(ContinuousProcessingRateDegree, Choice)}).*/ |
| 79 | private double initialMTTF = Double.NaN; |
| 80 | /** @see #initialMTTF */ |
| 81 | private double initialRate = Double.NaN; |
| 82 | |
| 83 | @Inject |
| 84 | public DSEDecoder(){ |
| 85 | //XXX like this you can only set the problem once. Maybe don't save the reference. |
| 86 | //this.problem = Opt4JStarter.problem; |
| 87 | } |
| 88 | |
| 89 | @Override |
| 90 | public PCMPhenotype decode(DesignDecisionGenotype genotype) { |
| 91 | |
| 92 | //get PCM Instance |
| 93 | PCMInstance pcm = Opt4JStarter.getProblem().getInitialInstance(); |
| 94 | |
| 95 | int index = 0; |
| 96 | //adjust values as in genotype |
| 97 | for (Choice doubleGene : genotype) { |
| 98 | |
| 99 | applyChange(doubleGene.getDegreeOfFreedomInstance(), doubleGene); |
| 100 | |
| 101 | index++; |
| 102 | } |
| 103 | |
| 104 | String genotypeString = getGenotypeString(genotype); |
| 105 | |
| 106 | //encapsulate as phenotype |
| 107 | //return new PCMPhenotype(pcm.deepCopy(),genotypeStringBuilder.toString()); |
| 108 | return new PCMPhenotype(pcm,genotypeString, genotype.getNumericID()); |
| 109 | } |
| 110 | |
| 111 | /** |
| 112 | * Applies the given change to the initial pcm instance (as this is |
| 113 | * referenced by the design decisions. More precisely, this one calls |
| 114 | * calls specialized methods for dealing with different types of design |
| 115 | * decisions. |
| 116 | * |
| 117 | * @param designDecision |
| 118 | * @param pcm |
| 119 | * @param choice The new value the design decision should take. |
| 120 | */ |
| 121 | private void applyChange(DegreeOfFreedomInstance designDecision, Choice choice) { |
| 122 | |
| 123 | /** |
| 124 | * TODO Make the selection of the appropriate applyChange method more implicit. Maybe move the method to DesignDecision itself. |
| 125 | */ |
| 126 | if (ProcessingRateDegree.class.isInstance(designDecision)){ |
| 127 | this.applyChangeProcessingRateDecision((ProcessingRateDegree)designDecision, choice); |
| 128 | } else if (AssembledComponentDegree.class.isInstance(designDecision)){ |
| 129 | this.applyChangeAssembledComponentDecision((AssembledComponentDegree)designDecision, choice); |
| 130 | } else if (AllocationDegree.class.isInstance(designDecision)){ |
| 131 | this.applyChangeAllocationDecision((AllocationDegree)designDecision, choice); |
| 132 | } else if (SchedulingPolicyDegree.class.isInstance(designDecision)){ |
| 133 | this.applyChangeSchedulingDecision((SchedulingPolicyDegree)designDecision, choice); |
| 134 | } else if (CapacityDegree.class.isInstance(designDecision)){ |
| 135 | this.applyChangeCapacityDecision((CapacityDegree)designDecision, choice); |
| 136 | } else if (NumberOfCoresDegree.class.isInstance(designDecision)){ |
| 137 | this.applyChangeNumberOfCoresDecision((NumberOfCoresDegree)designDecision, choice); |
| 138 | } else if (ResourceContainerReplicationDegree.class.isInstance(designDecision)){ |
| 139 | this.applyChangeResourceContainerReplicationDegree((ResourceContainerReplicationDegree)designDecision, choice); |
| 140 | } else { |
| 141 | logger.warn("There was an unrecognised design decision "+designDecision.getClass()); |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | private void applyChangeResourceContainerReplicationDegree( |
| 146 | ResourceContainerReplicationDegree designDecision, Choice choice) { |
| 147 | |
| 148 | if (!(choice instanceof DiscreteRangeChoice)){ |
| 149 | throwNewInvalidChoiceException(designDecision, choice); |
| 150 | } |
| 151 | DiscreteRangeChoice discreteChoice = (DiscreteRangeChoice)choice; |
| 152 | |
| 153 | int numberOfServers = discreteChoice.getChosenValue(); |
| 154 | |
| 155 | EObject changeableEntity = designDecision.getPrimaryChanged(); |
| 156 | if (!(changeableEntity instanceof ResourceContainer)){ |
| 157 | throwInvalidEntityException(designDecision, changeableEntity, ResourceContainer.class); |
| 158 | } |
| 159 | ResourceContainer server = (ResourceContainer)changeableEntity; |
| 160 | |
| 161 | if (numberOfServers < 1){ |
| 162 | throw new ChoiceOutOfBoundsException(discreteChoice); |
| 163 | } |
| 164 | |
| 165 | PCMInstance pcm = Opt4JStarter.getProblem().getInitialInstance(); |
| 166 | |
| 167 | // first reset the changes possibly made for earlier candidates |
| 168 | List<ResourceContainer> allServers = pcm.getResourceEnvironment().getResourceContainer_ResourceEnvironment(); |
| 169 | List<ResourceContainer> previousReplicasToRemove = new ArrayList<ResourceContainer>(); |
| 170 | for (ResourceContainer resourceContainer : allServers) { |
| 171 | if (resourceContainer.getId().contains(server.getId()) && resourceContainer.getEntityName().contains("Replica")){ |
| 172 | previousReplicasToRemove.add(resourceContainer); |
| 173 | } |
| 174 | } |
| 175 | allServers.removeAll(previousReplicasToRemove); |
| 176 | // also remove them from linking resources |
| 177 | List<LinkingResource> linkingResources = pcm.getResourceEnvironment().getLinkingResources__ResourceEnvironment(); |
| 178 | for (LinkingResource linkingResource : linkingResources) { |
| 179 | linkingResource.getConnectedResourceContainers_LinkingResource().removeAll(previousReplicasToRemove); |
| 180 | } |
| 181 | |
| 182 | List<AllocationContext> allocationContextsToRemove = new ArrayList<AllocationContext>(); |
| 183 | for (AllocationContext allocationContext : pcm.getAllocation().getAllocationContexts_Allocation()) { |
| 184 | if (previousReplicasToRemove.contains(allocationContext.getResourceContainer_AllocationContext())){ |
| 185 | allocationContextsToRemove.add(allocationContext); |
| 186 | } |
| 187 | } |
| 188 | pcm.getAllocation().getAllocationContexts_Allocation().removeAll(allocationContextsToRemove); |
| 189 | |
| 190 | // Apply the current value of the genome. |
| 191 | if (numberOfServers == 1){ |
| 192 | // no replication, keep original model with just one resource container. |
| 193 | // XXX: assumes that the original model has no replication. |
| 194 | } else { |
| 195 | // retrieve components deployed to this server |
| 196 | List<AllocationContext> allocationContexts = pcm.getAllocation().getAllocationContexts_Allocation(); |
| 197 | List<AllocationContext> allocationContextsOnServer = getAllocationContextsOnServer(allocationContexts, server); |
| 198 | |
| 199 | // the initial server is already there, so add numberOfServers - 1 new servers |
| 200 | for (int i = 1; i < numberOfServers; i++){ |
| 201 | // add a server, replicate all components on it. |
| 202 | |
| 203 | ResourceContainer serverCopy = (ResourceContainer) EcoreUtil.copy(server); |
| 204 | serverCopy.setId(serverCopy.getId()+i); |
| 205 | serverCopy.setEntityName(serverCopy.getEntityName()+"Replica"+i); |
| 206 | pcm.getResourceEnvironment().getResourceContainer_ResourceEnvironment().add(serverCopy); |
| 207 | |
| 208 | // connect the new server copy to all linking resources that the old one is connected to |
| 209 | for (LinkingResource linkingResource : linkingResources) { |
| 210 | if (linkingResource.getConnectedResourceContainers_LinkingResource().contains(server)){ |
| 211 | linkingResource.getConnectedResourceContainers_LinkingResource().add(serverCopy); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | for (AllocationContext allocationContext : allocationContextsOnServer) { |
| 216 | AllocationContext allocationContextCopy = (AllocationContext) EcoreUtil.copy(allocationContext); |
| 217 | allocationContextCopy.setId(allocationContextCopy.getId()+i); |
| 218 | allocationContextCopy.setEntityName(allocationContextCopy.getEntityName()+"Replica"+i); |
| 219 | |
| 220 | allocationContextCopy.setResourceContainer_AllocationContext(serverCopy); |
| 221 | |
| 222 | pcm.getAllocation().getAllocationContexts_Allocation().add(allocationContextCopy); |
| 223 | } |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | private List<AllocationContext> getAllocationContextsOnServer( |
| 229 | List<AllocationContext> allocationContexts, ResourceContainer server) { |
| 230 | List<AllocationContext> allocationContextsOnThisServer = new LinkedList<AllocationContext>(); |
| 231 | for (AllocationContext allocationContext : allocationContexts) { |
| 232 | if (EMFHelper.checkIdentity(allocationContext.getResourceContainer_AllocationContext(), server)){ |
| 233 | allocationContextsOnThisServer.add(allocationContext); |
| 234 | } |
| 235 | } |
| 236 | return allocationContextsOnThisServer; |
| 237 | } |
| 238 | |
| 239 | private void applyChangeNumberOfCoresDecision( |
| 240 | NumberOfCoresDegree designDecision, Choice choice) { |
| 241 | if (!(choice instanceof DiscreteRangeChoice)){ |
| 242 | throwNewInvalidChoiceException(designDecision, choice); |
| 243 | } |
| 244 | |
| 245 | DiscreteRangeChoice discreteChoice = (DiscreteRangeChoice)choice; |
| 246 | |
| 247 | ProcessingResourceSpecification rightPrs = getProcessingRateSpecification(designDecision); |
| 248 | rightPrs.setNumberOfReplicas(discreteChoice.getChosenValue()); |
| 249 | |
| 250 | } |
| 251 | |
| 252 | private void applyChangeCapacityDecision(CapacityDegree designDecision, |
| 253 | Choice choice) { |
| 254 | if (!(choice instanceof DiscreteRangeChoice)){ |
| 255 | throwNewInvalidChoiceException(designDecision, choice); |
| 256 | } |
| 257 | |
| 258 | DiscreteRangeChoice discreteChoice = (DiscreteRangeChoice)choice; |
| 259 | |
| 260 | PassiveResource passiveResource = (PassiveResource)designDecision.getPrimaryChanged(); |
| 261 | passiveResource.getCapacity_PassiveResource().setSpecification(String.valueOf(discreteChoice.getChosenValue())); |
| 262 | |
| 263 | } |
| 264 | |
| 265 | private void applyChangeAllocationDecision( |
| 266 | AllocationDegree designDecision, Choice choice) { |
| 267 | |
| 268 | if (!(choice instanceof ClassChoice)){ |
| 269 | throwNewInvalidChoiceException(designDecision, choice); |
| 270 | } |
| 271 | ClassChoice enumChoice = (ClassChoice)choice; |
| 272 | |
| 273 | EObject entity = enumChoice.getChosenValue(); |
| 274 | if (!(entity instanceof ResourceContainer)){ |
| 275 | throwInvalidEntityException(designDecision,entity,ResourceContainer.class); |
| 276 | } |
| 277 | |
| 278 | ResourceContainer rc = (ResourceContainer)entity; |
| 279 | |
| 280 | ((AllocationContext)designDecision.getPrimaryChanged()).setResourceContainer_AllocationContext(rc); |
| 281 | |
| 282 | logger.debug("Handling a "+designDecision.getClass()+", setting resource container to "+rc.getEntityName()+ " for allocation context "+designDecision.getPrimaryChanged()); |
| 283 | |
| 284 | } |
| 285 | |
| 286 | private void applyChangeSchedulingDecision( |
| 287 | SchedulingPolicyDegree designDecision, Choice choice) { |
| 288 | if (!(choice instanceof SchedulingPolicyChoice)){ |
| 289 | throwNewInvalidChoiceException(designDecision, choice); |
| 290 | } |
| 291 | |
| 292 | SchedulingPolicyChoice schedChoice = (SchedulingPolicyChoice)choice; |
| 293 | SchedulingPolicy chosenPolicy = schedChoice.getChosenValue(); |
| 294 | |
| 295 | ProcessingResourceSpecification rightPrs = getProcessingRateSpecification(designDecision); |
| 296 | |
| 297 | rightPrs.setSchedulingPolicy(chosenPolicy); |
| 298 | |
| 299 | } |
| 300 | |
| 301 | /** |
| 302 | * @see applyChange(DesignDecision, PCMInstance, Double) |
| 303 | * @param designDecision |
| 304 | * @param pcm |
| 305 | * @param doubleGene |
| 306 | */ |
| 307 | private void applyChangeProcessingRateDecision (ProcessingRateDegree designDecision, Choice choice) { |
| 308 | //XXX The value is changed in the original model, not in a copy. |
| 309 | |
| 310 | if (!(choice instanceof ContinousRangeChoice || choice instanceof DiscreteRangeChoice)){ |
| 311 | throwNewInvalidChoiceException(designDecision,choice); |
| 312 | } |
| 313 | |
| 314 | double newRate = 0; |
| 315 | if (choice instanceof ContinousRangeChoice){ |
| 316 | ContinousRangeChoice doubleGene = (ContinousRangeChoice)choice; |
| 317 | newRate = doubleGene.getChosenValue(); |
| 318 | } else { |
| 319 | DiscreteRangeChoice doubleGene = (DiscreteRangeChoice)choice; |
| 320 | DiscreteProcessingRateDegree degree = (DiscreteProcessingRateDegree)designDecision; |
| 321 | newRate = degree.getFrom() + ((degree.getTo() - degree.getFrom()) / degree.getNumberOfSteps()) * doubleGene.getChosenValue(); |
| 322 | |
| 323 | } |
| 324 | |
| 325 | ProcessingResourceSpecification rightPrs = getProcessingRateSpecification(designDecision); |
| 326 | |
| 327 | // get initial models MTTF and rate to scale upcoming candidates MTTF with |
| 328 | if (Double.isNaN(this.initialRate)){ |
| 329 | //old spec for adjusting MTTF |
| 330 | String oldRateString = rightPrs.getProcessingRate_ProcessingResourceSpecification().getSpecification(); |
| 331 | this.initialRate = CostUtil.getInstance().getDoubleFromSpecification(oldRateString); |
| 332 | } |
| 333 | if (Double.isNaN(this.initialMTTF)){ |
| 334 | this.initialMTTF = rightPrs.getMTTF(); |
| 335 | } |
| 336 | |
| 337 | double mttf = this.initialMTTF * newRate / this.initialRate; |
| 338 | |
| 339 | //round to just four digits after decimal sign, to maybe have no errors by the above |
| 340 | //long l = (int)Math.round(mttf * 100000000); // truncates |
| 341 | //mttf = l / 100000000.0; |
| 342 | |
| 343 | rightPrs.getProcessingRate_ProcessingResourceSpecification().setSpecification(String.valueOf(newRate)); |
| 344 | rightPrs.setMTTF(mttf); |
| 345 | |
| 346 | logger.debug("Handling a "+designDecision.getClass()+", setting rate to "+newRate+" and MTTF to "+mttf+" (inital MTTF: "+this.initialMTTF+")"); |
| 347 | } |
| 348 | |
| 349 | private ProcessingResourceSpecification getProcessingRateSpecification( |
| 350 | ProcessingResourceDegree designDecision) { |
| 351 | ResourceContainer rc = ((ResourceContainer)designDecision.getPrimaryChanged()); |
| 352 | ProcessingResourceType prt = designDecision.getProcessingresourcetype(); |
| 353 | |
| 354 | ProcessingResourceSpecification rightPrs = null; |
| 355 | for (ProcessingResourceSpecification prs : rc.getActiveResourceSpecifications_ResourceContainer()) { |
| 356 | if (EMFHelper.checkIdentity(prs.getActiveResourceType_ActiveResourceSpecification(),prt)){ |
| 357 | rightPrs = prs; |
| 358 | break; |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | if (rightPrs == null){ |
| 363 | throw new RuntimeException("Invalid degree of freedom "+designDecision.toString()+". The references ProcessingResourceType is not available in the given ResourceContainer."); |
| 364 | } |
| 365 | return rightPrs; |
| 366 | } |
| 367 | |
| 368 | private void throwNewInvalidChoiceException( |
| 369 | DegreeOfFreedomInstance designDecision, Choice choice) { |
| 370 | throw new InvalidChoiceForDegreeException(choice); |
| 371 | |
| 372 | } |
| 373 | |
| 374 | private void applyChangeAssembledComponentDecision ( AssembledComponentDegree designDecision, Choice choice) { |
| 375 | |
| 376 | if (!(choice instanceof ClassChoice)){ |
| 377 | throwNewInvalidChoiceException(designDecision, choice); |
| 378 | } |
| 379 | ClassChoice enumChoice = (ClassChoice)choice; |
| 380 | |
| 381 | //use the order of the enumeration of EquivalentComponents in the Domain |
| 382 | EObject entity = enumChoice.getChosenValue(); |
| 383 | if (!(entity instanceof RepositoryComponent)){ |
| 384 | throwInvalidEntityException(designDecision,entity,RepositoryComponent.class); |
| 385 | } |
| 386 | RepositoryComponent componentToBeAssembled = (RepositoryComponent)entity; |
| 387 | |
| 388 | AssemblyContext changedAssemblyContext = (AssemblyContext)designDecision.getPrimaryChanged(); |
| 389 | RepositoryComponent currentComponent = changedAssemblyContext.getEncapsulatedComponent__AssemblyContext(); |
| 390 | |
| 391 | //Do not replace component if it is already assembled. |
| 392 | if (!EMFHelper.checkIdentity(currentComponent, componentToBeAssembled)){ |
| 393 | AlternativeComponent.getInstance().applyChange(changedAssemblyContext, componentToBeAssembled); |
| 394 | } |
| 395 | |
| 396 | |
| 397 | logger.debug("Handling a "+designDecision.getClass()+", using component "+componentToBeAssembled.getEntityName()); |
| 398 | } |
| 399 | |
| 400 | @SuppressWarnings("unchecked") |
| 401 | private void throwInvalidEntityException( |
| 402 | DegreeOfFreedomInstance designDecision, EObject changeableEntity, |
| 403 | Class expectedClass) { |
| 404 | throw new RuntimeException("Entity "+changeableEntity+" of type "+changeableEntity.getClass().getName()+" is not an applicable value for degree of freedom "+designDecision.getClass().getName()+", required type is "+expectedClass.getName()); |
| 405 | |
| 406 | } |
| 407 | |
| 408 | public static String getGenotypeString(DesignDecisionGenotype genotype) { |
| 409 | StringBuilder genotypeStringBuilder = new StringBuilder(100); |
| 410 | for (Choice choice : genotype) { |
| 411 | genotypeStringBuilder.append(DSEDecoder.getDecisionString(choice)+";"); |
| 412 | } |
| 413 | return genotypeStringBuilder.toString(); |
| 414 | } |
| 415 | |
| 416 | public static String getDecisionString(Choice choice){ |
| 417 | DegreeOfFreedomInstance designDecision = choice.getDegreeOfFreedomInstance(); |
| 418 | |
| 419 | String result = ""; |
| 420 | /** |
| 421 | * TODO Make the selection of the appropriate applyChange method more implicit. Maybe move the method to DesignDecision itself. |
| 422 | */ |
| 423 | if (choice instanceof ContinousRangeChoice){ |
| 424 | result = ResultsWriter.formatDouble(((ContinousRangeChoice) choice).getChosenValue()); |
| 425 | } else if (choice instanceof ClassChoice){ |
| 426 | if (((ClassChoice) choice).getChosenValue() instanceof Entity){ |
| 427 | result = ((Entity)((ClassChoice)choice).getChosenValue()).getEntityName(); |
| 428 | } else { |
| 429 | result = ((ClassChoice)choice).getChosenValue().toString(); |
| 430 | } |
| 431 | } else if (choice instanceof DiscreteRangeChoice){ |
| 432 | result = String.valueOf(((DiscreteRangeChoice)choice).getChosenValue()); |
| 433 | } else if (choice instanceof SchedulingPolicyChoice){ |
| 434 | result = ((SchedulingPolicyChoice)choice).getChosenValue().getLiteral(); |
| 435 | } else { |
| 436 | logger.warn("There was an unrecognised design decision "+designDecision.getClass()); |
| 437 | } |
| 438 | return result; |
| 439 | } |
| 440 | |
| 441 | /** |
| 442 | * Calls getDoubleValueFor(String decisionString, DesignDecision designDecision) |
| 443 | * @param index |
| 444 | * @param decisionString |
| 445 | * @return |
| 446 | * @throws CoreException |
| 447 | */ |
| 448 | public static Choice getChoiceForIndex(int index, String decisionString) throws CoreException{ |
| 449 | |
| 450 | DegreeOfFreedomInstance designDecision = Opt4JStarter.getProblem().getDesignDecision(index); |
| 451 | |
| 452 | Choice value = getChoiceFor(decisionString, designDecision); |
| 453 | |
| 454 | return value; |
| 455 | |
| 456 | } |
| 457 | |
| 458 | public static Choice getChoiceFor(String decisionString, |
| 459 | DegreeOfFreedomInstance designDecision) throws CoreException { |
| 460 | Choice choice; |
| 461 | |
| 462 | designdecisionFactory factory = designdecisionFactoryImpl.init(); |
| 463 | |
| 464 | if (designDecision instanceof ContinuousRangeDegree){ |
| 465 | ContinuousRangeDegree contDegree = (ContinuousRangeDegree) designDecision; |
| 466 | double d = Double.parseDouble(decisionString); |
| 467 | if (!validRange(d, contDegree, contDegree.getFrom(), contDegree.getTo())){ |
| 468 | throw ExceptionHelper.createNewCoreException("Error: Value "+d+" is not a valid value for degree "+designDecision+" "+DegreeOfFreedomHelper.getDegreeDescription(designDecision)); |
| 469 | } |
| 470 | ContinousRangeChoice contChoice = factory.createContinousRangeChoice(); |
| 471 | contChoice.setChosenValue(d); |
| 472 | choice = contChoice; |
| 473 | } else if (designDecision instanceof DiscreteRangeDegree){ |
| 474 | DiscreteRangeDegree discDegree = (DiscreteRangeDegree) designDecision; |
| 475 | int i = Integer.parseInt(decisionString); |
| 476 | if (!validRange(i, discDegree, discDegree.getFrom(), discDegree.getTo())){ |
| 477 | throw ExceptionHelper.createNewCoreException("Error: Value "+i+"\" is not a valid value for degree "+designDecision+" "+DegreeOfFreedomHelper.getDegreeDescription(designDecision)); |
| 478 | } |
| 479 | DiscreteRangeChoice discChoice = factory.createDiscreteRangeChoice(); |
| 480 | discChoice.setChosenValue(i); |
| 481 | choice = discChoice; |
| 482 | } else if (designDecision instanceof ClassDegree){ |
| 483 | |
| 484 | ClassChoice enumChoice = factory.createClassChoice(); |
| 485 | Entity entity = getEntityFor((ClassDegree)designDecision, decisionString); |
| 486 | if (entity == null){ |
| 487 | throw ExceptionHelper.createNewCoreException("Error: Decision string \""+decisionString+"\" is not a valid value for degree "+designDecision+" "+DegreeOfFreedomHelper.getDegreeDescription(designDecision)); |
| 488 | } |
| 489 | enumChoice.setChosenValue(entity); |
| 490 | choice = enumChoice; |
| 491 | } else if (designDecision instanceof SchedulingPolicyDegree){ |
| 492 | |
| 493 | SchedulingPolicyChoice schedChoice = factory.createSchedulingPolicyChoice(); |
| 494 | |
| 495 | SchedulingPolicy chosenPolicy = SchedulingPolicy.get(decisionString); |
| 496 | |
| 497 | if (chosenPolicy == null){ |
| 498 | throw ExceptionHelper.createNewCoreException("Error: Decision string \""+decisionString+"\" is not a valid value for degree "+designDecision+" "+DegreeOfFreedomHelper.getDegreeDescription(designDecision)); |
| 499 | } |
| 500 | schedChoice.setChosenValue(chosenPolicy); |
| 501 | choice = schedChoice; |
| 502 | } else { |
| 503 | logger.warn("There was an unrecognised design decision "+designDecision.getClass()); |
| 504 | return null; |
| 505 | } |
| 506 | choice.setDegreeOfFreedomInstance(designDecision); |
| 507 | return choice; |
| 508 | } |
| 509 | |
| 510 | private static boolean validRange(double value, RangeDegree designDecision, double from, |
| 511 | double to) { |
| 512 | return (value >= from && value <= to); |
| 513 | } |
| 514 | |
| 515 | private static Entity getEntityFor(ClassDegree designDecision, |
| 516 | String decisionString) { |
| 517 | List<Entity> entities = new ArrayList<Entity>(); |
| 518 | for (EObject entity : designDecision.getClassDesignOptions()) { |
| 519 | if (entity instanceof Entity){ |
| 520 | entities.add((Entity) entity); |
| 521 | } |
| 522 | } |
| 523 | return getEntityByName(entities, decisionString); |
| 524 | } |
| 525 | |
| 526 | private static Entity getEntityByName(List<Entity> entities, |
| 527 | String decisionString) { |
| 528 | for (Entity entity : entities) { |
| 529 | if (entity.getEntityName().equals(decisionString)){ |
| 530 | return entity; |
| 531 | } |
| 532 | } |
| 533 | return null; |
| 534 | } |
| 535 | |
| 536 | /** |
| 537 | * Edits the passed genotype by inserting the passed choice at the index |
| 538 | * for the passed {@link DegreeOfFreedomInstance}. |
| 539 | * @param genotype |
| 540 | * @param degree |
| 541 | * @param choice |
| 542 | */ |
| 543 | public static void applyChangeToGenotype(DesignDecisionGenotype genotype, DegreeOfFreedomInstance degree, Choice choice){ |
| 544 | int index = Opt4JStarter.getProblem().getDesignDecisions().indexOf(degree); |
| 545 | genotype.set(index, choice); |
| 546 | } |
| 547 | |
| 548 | } |