1 | package de.uka.ipd.sdq.dsexplore.helper; |
2 | |
3 | import java.io.BufferedReader; |
4 | import java.io.File; |
5 | import java.io.FileInputStream; |
6 | import java.io.FileNotFoundException; |
7 | import java.io.IOException; |
8 | import java.io.InputStreamReader; |
9 | import java.net.URL; |
10 | import java.util.ArrayList; |
11 | import java.util.Collections; |
12 | import java.util.Iterator; |
13 | import java.util.LinkedList; |
14 | import java.util.List; |
15 | |
16 | import org.apache.log4j.Logger; |
17 | import org.eclipse.core.runtime.CoreException; |
18 | import org.eclipse.core.runtime.FileLocator; |
19 | import org.eclipse.emf.ecore.EObject; |
20 | import org.eclipse.emf.ecore.resource.ResourceSet; |
21 | import org.eclipse.emf.ecore.util.EcoreUtil; |
22 | import org.opt4j.core.Criterion; |
23 | import org.opt4j.core.DoubleValue; |
24 | import org.opt4j.core.Value; |
25 | import org.opt4j.start.Opt4JTask; |
26 | |
27 | import de.uka.ipd.sdq.context.aggregatedUsageContext.ComputedAggregatedUsage; |
28 | import de.uka.ipd.sdq.dsexplore.analysis.AbstractPerformanceAnalysisResult; |
29 | import de.uka.ipd.sdq.dsexplore.analysis.IAnalysis; |
30 | import de.uka.ipd.sdq.dsexplore.analysis.IAnalysisResult; |
31 | import de.uka.ipd.sdq.dsexplore.analysis.PCMPhenotype; |
32 | import de.uka.ipd.sdq.dsexplore.exception.ExceptionHelper; |
33 | import de.uka.ipd.sdq.dsexplore.launch.DSEConstantsContainer; |
34 | import de.uka.ipd.sdq.dsexplore.opt4j.genotype.DesignDecisionGenotype; |
35 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEDecoder; |
36 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEEvaluator; |
37 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividual; |
38 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEIndividualBuilder; |
39 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEObjectives; |
40 | import de.uka.ipd.sdq.dsexplore.opt4j.representation.DSEProblem; |
41 | import de.uka.ipd.sdq.dsexplore.opt4j.start.Opt4JStarter; |
42 | import de.uka.ipd.sdq.dsexplore.qml.handling.QMLConstantsContainer; |
43 | import de.uka.ipd.sdq.dsexplore.qml.reader.QMLDimensionReader; |
44 | import de.uka.ipd.sdq.pcm.core.entity.Entity; |
45 | import de.uka.ipd.sdq.pcm.designdecision.Candidate; |
46 | import de.uka.ipd.sdq.pcm.designdecision.Candidates; |
47 | import de.uka.ipd.sdq.pcm.designdecision.Choice; |
48 | import de.uka.ipd.sdq.pcm.designdecision.DegreeOfFreedomInstance; |
49 | import de.uka.ipd.sdq.pcm.resourceenvironment.LinkingResource; |
50 | import de.uka.ipd.sdq.pcm.resourceenvironment.ProcessingResourceSpecification; |
51 | import de.uka.ipd.sdq.pcm.resourceenvironment.ResourceContainer; |
52 | import de.uka.ipd.sdq.pcm.resourcetype.ResourceType; |
53 | import de.uka.ipd.sdq.pcm.resultdecorator.ResultDecoratorRepository; |
54 | import de.uka.ipd.sdq.pcm.resultdecorator.ResultdecoratorFactory; |
55 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.ActiveResourceUtilisationResult; |
56 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.LinkingResourceResults; |
57 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.ProcessingResourceSpecificationResult; |
58 | import de.uka.ipd.sdq.pcm.resultdecorator.resourceenvironmentdecorator.ResourceenvironmentdecoratorFactory; |
59 | import de.uka.ipd.sdq.pcmsolver.models.PCMInstance; |
60 | import de.uka.ipd.sdq.statistics.estimation.ConfidenceInterval; |
61 | import de.uka.ipd.sdq.workflow.exceptions.UserCanceledException; |
62 | import de.uka.ipd.sdq.workflow.mdsd.blackboard.MDSDBlackboard; |
63 | |
64 | public class GenotypeReader { |
65 | |
66 | /**QUICKHACK need to inject objectives!!!**/ |
67 | private static Opt4JTask task = null; |
68 | public static void setTask(Opt4JTask t){ |
69 | task = t; |
70 | } |
71 | |
72 | private static final String SEPARATOR = ";"; |
73 | |
74 | /** Logger for log4j. */ |
75 | private static Logger logger = |
76 | Logger.getLogger("de.uka.ipd.sdq.dsexplore.helper.GenotypeReader"); |
77 | |
78 | /** |
79 | * Reads the genotypes from the specified files. |
80 | * If the file contains pretty printed genotypes and |
81 | * objectives are given, reads them and updates the DSEEvaluator cache |
82 | * by calling DSEEvaluator.addToPhenotypeCache(..). Requires confidence intervals |
83 | * to be available for all objectives with statistical evaluators. |
84 | * Reading in of objectives and confidence values is not supported for raw genotype files. |
85 | * Note that this method changes the internal objectives and deletes all objectives that are not |
86 | * found in the file. |
87 | * @param blackboard |
88 | */ |
89 | public static List<DesignDecisionGenotype> getGenotypes(String filename, MDSDBlackboard blackboard) |
90 | throws CoreException { |
91 | |
92 | if ("".equals(filename)){ |
93 | return Collections.emptyList(); |
94 | } |
95 | |
96 | if (filename.contains("csv")) { |
97 | try { |
98 | |
99 | List<DSEIndividual> individuals = readInPrettyPrintedIndividuals(getReaderFor(filename), blackboard); |
100 | List<DesignDecisionGenotype> results = new ArrayList<DesignDecisionGenotype>( |
101 | individuals.size()); |
102 | for (DSEIndividual individual : individuals) { |
103 | results.add(individual.getGenotype()); |
104 | } |
105 | |
106 | return results; |
107 | |
108 | } catch (Exception ex) { |
109 | throw ExceptionHelper.createNewCoreException( |
110 | "Could not evaluate predefined instances. See nested Exceptions for cause. " |
111 | + ex.getMessage(), ex); |
112 | } |
113 | } else if (filename.contains("designdecision")) { |
114 | return loadGenotypesFromEMF(filename); |
115 | |
116 | } else |
117 | throw ExceptionHelper |
118 | .createNewCoreException("Genotype file to read must must be of type csv or designdecision."); |
119 | } |
120 | |
121 | /** |
122 | * Load complete Individuals from the file (with objectives and utilisation info, if present). |
123 | * @param filename |
124 | * @param blackboard |
125 | * @return |
126 | * @throws CoreException |
127 | */ |
128 | public static List<DSEIndividual> getIndividuals(String filename, MDSDBlackboard blackboard) throws CoreException{ |
129 | |
130 | if (filename.contains("csv")) { |
131 | try { |
132 | |
133 | List<DSEIndividual> individuals = readInPrettyPrintedIndividuals(getReaderFor(filename), blackboard); |
134 | return individuals; |
135 | |
136 | } catch( Exception ex ) { |
137 | throw ExceptionHelper.createNewCoreException("Could not evaluate predefined instances. See nested Exceptions for cause. "+ex.getMessage(), ex); |
138 | } |
139 | } else if (filename.contains("designdecision")) { |
140 | List<DesignDecisionGenotype> genotypes = loadGenotypesFromEMF(filename); |
141 | List<DSEIndividual> individuals = new ArrayList<DSEIndividual>(genotypes.size()); |
142 | for (DesignDecisionGenotype designDecisionGenotype : genotypes) { |
143 | DSEIndividualBuilder builder = Opt4JStarter.getIndividualBuilder(); |
144 | DSEIndividual individual = builder.build(designDecisionGenotype); |
145 | individuals.add(individual); |
146 | } |
147 | return individuals; |
148 | |
149 | } else |
150 | throw ExceptionHelper |
151 | .createNewCoreException("Genotype file to read must must be of type csv or designdecision."); |
152 | } |
153 | |
154 | /** |
155 | * Note that this method changes the internal objectives and deletes all objectives that are not |
156 | * found in the file. |
157 | * @param filename |
158 | * @return |
159 | * @throws CoreException |
160 | */ |
161 | public static List<DSEObjectives> getObjectives (String filename) throws CoreException{ |
162 | |
163 | try { |
164 | |
165 | List<DSEObjectives> results = readInPrettyPrintedObjectives(getReaderFor(filename)); |
166 | |
167 | return results; |
168 | |
169 | } catch( Exception ex ) { |
170 | throw ExceptionHelper.createNewCoreException("Could not evaluate predefined instances. Leave field blank for evolutionary search or type \"random\" for a random search. "+ex.getMessage(), ex); |
171 | } |
172 | } |
173 | |
174 | private static List<DesignDecisionGenotype> loadGenotypesFromEMF( |
175 | String filename) { |
176 | PCMInstance pcm = Opt4JStarter.getProblem().getInitialInstance(); |
177 | ResourceSet pcmResourceSet = pcm.getAllocation().eResource().getResourceSet(); |
178 | |
179 | EObject eCandidates = EMFHelper.loadFromXMIFile(filename, pcmResourceSet); |
180 | EcoreUtil.resolveAll(eCandidates); |
181 | FixDesignDecisionReferenceSwitch refSwitch = new FixDesignDecisionReferenceSwitch(Opt4JStarter.getProblem().getInitialInstance()); |
182 | refSwitch.doSwitch(eCandidates); |
183 | |
184 | if (!(eCandidates instanceof Candidates)){ |
185 | throw new RuntimeException("Cannot read candidate model file "+filename+". Please create a new one.", null); |
186 | } |
187 | Candidates candidates = (Candidates)eCandidates ; |
188 | EcoreUtil.resolveAll(candidates); |
189 | |
190 | List<DesignDecisionGenotype> genotypeList = new ArrayList<DesignDecisionGenotype>(candidates.getCandidate().size()); |
191 | for (Candidate candidate : candidates.getCandidate()) { |
192 | DesignDecisionGenotype genotype = new DesignDecisionGenotype(candidate, candidates.getProblem(), Opt4JStarter.getProblem().getGenotypeOfInitialPCMInstance()); |
193 | genotypeList.add(genotype); |
194 | } |
195 | |
196 | return genotypeList; |
197 | } |
198 | |
199 | //FIXME: copied from readInPrettyPrintedGenotypes. Refactor to use a proper serialisation!! |
200 | private static List<DSEObjectives> readInPrettyPrintedObjectives(BufferedReader in) throws CoreException, IOException { |
201 | List<DSEObjectives> results = new ArrayList<DSEObjectives>(); |
202 | |
203 | //order design decisions |
204 | String headline = in.readLine(); |
205 | if (headline == null){ |
206 | throw ExceptionHelper.createNewCoreException("Predefined instances file could not be read because it is empty. Specify a valid file or \"random\" or leave the field blank for an evolutionary search."); |
207 | } |
208 | String[] headlineArray = headline.split(SEPARATOR); |
209 | |
210 | List<CriterionAndEvaluator> objectiveList = Opt4JStarter.getDSEEvaluator().getCriterionAndEvaluatorList(); |
211 | |
212 | //Empty list if no objectives are specified. |
213 | List<List<CriterionAndEvaluator>> orderedObjectives = getOrderedObjectiveCollection(headlineArray, objectiveList); |
214 | |
215 | //count confidence intervals to determine boundaries of areas in file (objectives, confidences, genotype) |
216 | int numberOfConfidenceIntervals = countConfidenceIntervals(headlineArray); |
217 | |
218 | int startIndexOfConfidence = orderedObjectives.size(); |
219 | if( orderedObjectives.size() == 0){ |
220 | ExceptionHelper.createNewCoreException("Tried to read in Pareto front that has no objectives in it. Fix your file."); |
221 | } |
222 | |
223 | int expectedLineArrayLength = headlineArray.length; |
224 | |
225 | String line; |
226 | while ( null != (line = in.readLine()) ) { |
227 | String[] lineArray = line.split(SEPARATOR); |
228 | //Check minimum length, a last semicolon is ok that makes the line array one longer than the list. |
229 | if (lineArray.length < expectedLineArrayLength){ |
230 | throw ExceptionHelper.createNewCoreException("A line in the predefined instances file has not the right length"); |
231 | } |
232 | DSEObjectives objectives = readInObjectivesAndConfidence( |
233 | orderedObjectives, startIndexOfConfidence, |
234 | numberOfConfidenceIntervals, lineArray); |
235 | results.add(objectives); |
236 | } |
237 | in.close(); |
238 | |
239 | return results; |
240 | } |
241 | |
242 | private static BufferedReader getReaderFor(String path) throws FileNotFoundException { |
243 | // if this is a platform URL, first resolve it to an absolute path |
244 | if (path.startsWith("platform:")){ |
245 | try { |
246 | URL solvedURL = FileLocator.resolve(new URL(path)); |
247 | path = solvedURL.getPath(); |
248 | } catch (Exception e) { |
249 | e.printStackTrace(); |
250 | return null; |
251 | } |
252 | } |
253 | File file = new File(path); |
254 | |
255 | InputStreamReader ir = new InputStreamReader( |
256 | new FileInputStream( file ) ); |
257 | BufferedReader in = new BufferedReader(ir); |
258 | return in; |
259 | } |
260 | |
261 | /** |
262 | * Reads the genotypes from the specified files. |
263 | * If objectives are given, reads them and updates the DSEEvaluator cache |
264 | * by calling DSEEvaluator.addToPhenotypeCache(..). Requires confidence intervals |
265 | * to be available for all objectives with statistical evaluators. |
266 | * @param in Is used and modify and closed |
267 | * @param blackboard |
268 | * @return |
269 | * @throws CoreException |
270 | * @throws IOException |
271 | */ |
272 | private static List<DSEIndividual> readInPrettyPrintedIndividuals(BufferedReader in, MDSDBlackboard blackboard) throws CoreException, IOException { |
273 | List<DSEIndividual> results = new LinkedList<DSEIndividual>(); |
274 | |
275 | DSEProblem problem = Opt4JStarter.getProblem(); |
276 | List<DegreeOfFreedomInstance> decisionList = problem.getDesignDecisions(); |
277 | |
278 | //order design decisions |
279 | String headline = in.readLine(); |
280 | if (headline == null){ |
281 | throw ExceptionHelper.createNewCoreException("Predefined instances file could not be read because it is empty. Specify a valid file or \"random\" or leave the field blank for an evolutionary search."); |
282 | } |
283 | String[] headlineArray = headline.split(SEPARATOR); |
284 | |
285 | // the configured list of objectives |
286 | List<CriterionAndEvaluator> objectiveList = Opt4JStarter.getDSEEvaluator().getCriterionAndEvaluatorList(); |
287 | |
288 | // Empty list if no objectives are specified. |
289 | // The inner lists must not be empty. |
290 | // The inner lists contain all evaluators that are interested in one column of the result file. For example, |
291 | // if there is a response time objective and a response time constraint, these two are in one list. |
292 | List<List<CriterionAndEvaluator>> orderedObjectives = getOrderedObjectiveCollection(headlineArray, objectiveList); |
293 | |
294 | boolean hasObjectives = orderedObjectives.size() != 0; |
295 | |
296 | //determine missing objectives |
297 | List<CriterionAndEvaluator> missingObjectives = determineMissingObjectives(objectiveList, orderedObjectives); |
298 | |
299 | // special case: find one performance criterion to determine whether confidence intervals are required. |
300 | Criterion performance = null; |
301 | if (hasObjectives){ |
302 | for (List<CriterionAndEvaluator> objectiveAndEvaluatorList : orderedObjectives) { |
303 | |
304 | if (objectiveAndEvaluatorList.size()>0){ |
305 | CriterionAndEvaluator first = objectiveAndEvaluatorList.get(0); |
306 | //XXX: Read the dimension name from definition rather than the constants container |
307 | if (ResultsWriter.getDimensionName(first.getCriterion()).contains(new QMLDimensionReader().getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_RESPONSETIME_DEFINITION_PATH).getEntityName()) |
308 | || ResultsWriter.getDimensionName(first.getCriterion()).contains(new QMLDimensionReader().getDimension(QMLConstantsContainer.QUALITY_ATTRIBUTE_DIMENSION_THROUGHPUT_DEFINITION_PATH).getEntityName())){ |
309 | performance = first.getCriterion(); |
310 | break; |
311 | } |
312 | } |
313 | } |
314 | |
315 | } |
316 | |
317 | //count confidence intervals to determine boundaries of areas in file (objectives, confidences, genotype) |
318 | int numberOfConfidenceIntervals = countConfidenceIntervals(headlineArray); |
319 | |
320 | // determine number of objective columns. |
321 | |
322 | int startIndexOfConfidence = orderedObjectives.size(); |
323 | |
324 | //Its always three columns per objective that has confidence |
325 | int startIndexOfGenotype = orderedObjectives.size() + numberOfConfidenceIntervals*3; |
326 | |
327 | //order the design decision in the problem based on the found order. |
328 | List<DegreeOfFreedomInstance> orderedDesignDecisions = getOrderedDesignDecisions( |
329 | decisionList, headlineArray, startIndexOfGenotype, problem); |
330 | |
331 | int minExpectedLineArrayLength = startIndexOfGenotype + orderedDesignDecisions.size(); |
332 | |
333 | List<ResourcesWithUtilisationDescriptor> resourceDescriptorsWithUtilResults = getDescriptorsForResourcesWithUtilisation(headlineArray, minExpectedLineArrayLength, problem); |
334 | |
335 | String line; |
336 | while ( null != (line = in.readLine()) ) { |
337 | String[] lineArray = line.split(SEPARATOR); |
338 | //Check minimum length, a last semicolon is ok that makes the line array one longer than the list. |
339 | if (lineArray.length < minExpectedLineArrayLength){ |
340 | throw ExceptionHelper.createNewCoreException("A line in the predefined instances file has not the right length"); |
341 | } |
342 | DesignDecisionGenotype genotype = extractGenotypeAndAddToList(startIndexOfGenotype, |
343 | orderedDesignDecisions, lineArray); |
344 | |
345 | |
346 | DSEIndividualBuilder builder = Opt4JStarter.getIndividualBuilder(); |
347 | DSEIndividual individual = builder.build(genotype); |
348 | results.add(individual); |
349 | |
350 | if (hasObjectives){ |
351 | DSEObjectives objectives = readInObjectivesAndConfidence( |
352 | orderedObjectives, startIndexOfConfidence, |
353 | numberOfConfidenceIntervals, lineArray); |
354 | |
355 | //has utilisations? |
356 | if (resourceDescriptorsWithUtilResults.size() > 0 && performance != null){ |
357 | objectives.addResultDecoratorFor(performance, getResultDecorator(lineArray, minExpectedLineArrayLength, resourceDescriptorsWithUtilResults)); |
358 | |
359 | //if the processor list is non-empty, but no utilisations were found, warn because the read in values might be old versions |
360 | if (objectives.getResultDecoratorFor(performance).getUtilisationResults_ResultDecoratorRepository().size() == 0 && !objectives.getValueForCriterion(performance).equals(new DoubleValue(Double.POSITIVE_INFINITY))){ |
361 | logger.warn("Empty utilisation values for non-infinity objectives encountered when reading in individuals, check that this is ok."); |
362 | } |
363 | } |
364 | |
365 | //if (Opt4JStarter.getDSEWorkflowConfig().getUseAntipatternKnowledge()){ |
366 | if (Opt4JStarter.getDSEWorkflowConfig().isUseHeuristics()){ |
367 | |
368 | //PCMResourceSetPartition analysisPartition = (PCMResourceSetPartition)blackboard.getPartition(LoadPCMModelsIntoBlackboardJob.PCM_MODELS_PARTITION_ID); |
369 | //PCMInstance model = new PCMInstance(analysisPartition); |
370 | PCMInstance model = Opt4JStarter.getProblem().getInitialInstance(); |
371 | |
372 | //solve dependencies for performance |
373 | Opt4JStarter.getDSEDecoder().decode(genotype); |
374 | AbstractPerformanceAnalysisResult.solveDependencies(model); |
375 | |
376 | ComputedAggregatedUsage computedAggregatedUsage = model.getComputedAggregatedUsage(); |
377 | if (computedAggregatedUsage != null){ |
378 | objectives.addComputedAggregatedUsage(performance, computedAggregatedUsage); |
379 | } |
380 | } |
381 | |
382 | //add objective to phenotype cache with genotype string |
383 | Opt4JStarter.getDSEEvaluator().addToPhenotypeCache(DSEDecoder.getGenotypeString(genotype), objectives); |
384 | |
385 | //add objectives to individual |
386 | individual.setObjectives(objectives); |
387 | } |
388 | |
389 | } |
390 | in.close(); |
391 | |
392 | if (hasObjectives && missingObjectives.size() > 0){ |
393 | // evaluate the objectives that are not read in |
394 | evaluateMissingObjectives(results, missingObjectives); |
395 | } |
396 | |
397 | return results; |
398 | } |
399 | |
400 | /** |
401 | * Return those objectives in desiredObjectives that are not contained in orderedObjectives. |
402 | * @param desiredObjectives |
403 | * @param availableObjectives |
404 | * @return |
405 | */ |
406 | static public List<CriterionAndEvaluator> determineMissingObjectives(List<CriterionAndEvaluator> desiredObjectives, List<List<CriterionAndEvaluator>> availableObjectives) { |
407 | |
408 | List<CriterionAndEvaluator> flattenedAvailableObjectives = new ArrayList<CriterionAndEvaluator>(availableObjectives.size()*3); |
409 | for (List<CriterionAndEvaluator> list : availableObjectives) { |
410 | flattenedAvailableObjectives.addAll(list); |
411 | } |
412 | List<CriterionAndEvaluator> missingObjectives = new ArrayList<CriterionAndEvaluator>(); |
413 | // from the set of desired objectives... |
414 | missingObjectives.addAll(desiredObjectives); |
415 | // ... remove all objectives that are already included in the files |
416 | missingObjectives.removeAll(flattenedAvailableObjectives); |
417 | |
418 | // the resulting list are all desired objectives that are not in orderObjectives. |
419 | return missingObjectives; |
420 | |
421 | } |
422 | |
423 | /** |
424 | * Check all objectives of the indivuals and evaluate the missing ones |
425 | * @param results |
426 | * @param missingObjectives |
427 | * @throws |
428 | * @throws JobFailedException |
429 | * @throws UserCanceledException |
430 | * @throws CoreException |
431 | */ |
432 | private static void evaluateMissingObjectives(List<DSEIndividual> results, List<CriterionAndEvaluator> missingObjectives) throws CoreException { |
433 | |
434 | for (DSEIndividual individual : results) { |
435 | |
436 | DSEEvaluator dseEvaluator = task.getInstance(DSEEvaluator.class); |
437 | DSEDecoder decoder = task.getInstance(DSEDecoder.class); |
438 | |
439 | PCMPhenotype pheno = (PCMPhenotype) decoder.decode(individual.getGenotype()); |
440 | individual.setPhenotype(pheno); |
441 | |
442 | List<IAnalysis> alreadyEvaluatedMissingObjectives = new LinkedList<IAnalysis>(); |
443 | |
444 | for (CriterionAndEvaluator criterionAndEvaluator : missingObjectives) { |
445 | IAnalysis evaluator = criterionAndEvaluator.getEvaluator(); |
446 | |
447 | try { |
448 | if (!alreadyEvaluatedMissingObjectives.contains(evaluator)){ |
449 | evaluator.analyse(pheno, dseEvaluator.getMonitor()); |
450 | |
451 | alreadyEvaluatedMissingObjectives.add(evaluator); |
452 | |
453 | } |
454 | |
455 | dseEvaluator.retrieveCriterion(pheno, individual.getObjectives(), criterionAndEvaluator); |
456 | |
457 | } catch (Exception e){ |
458 | throw ExceptionHelper.createNewCoreException("Analysis of missing objectives when reading in genotypes failed. See nested cause.", e); |
459 | } |
460 | |
461 | } |
462 | |
463 | } |
464 | |
465 | } |
466 | |
467 | private static List<ResourcesWithUtilisationDescriptor> getDescriptorsForResourcesWithUtilisation( |
468 | String[] headlineArray, int minExpectedLineArrayLength, DSEProblem problem) { |
469 | |
470 | List<ResourcesWithUtilisationDescriptor> allPotentialResourcesWithUtil = getAllProcessors(problem); |
471 | List<ResourcesWithUtilisationDescriptor> orderedListOfUsedResourceDesccriptors = new ArrayList<ResourcesWithUtilisationDescriptor>(allPotentialResourcesWithUtil.size()); |
472 | for (int i = minExpectedLineArrayLength; i < headlineArray.length; i++) { |
473 | String entry = headlineArray[i]; |
474 | for (Iterator<ResourcesWithUtilisationDescriptor> iterator = allPotentialResourcesWithUtil.iterator(); iterator |
475 | .hasNext();) { |
476 | ResourcesWithUtilisationDescriptor processor = iterator |
477 | .next(); |
478 | if ( entry.contains(processor.getEntity().getEntityName()) |
479 | && entry.contains(processor.getResourceType().getEntityName())){ |
480 | orderedListOfUsedResourceDesccriptors.add(processor); |
481 | iterator.remove(); |
482 | break; |
483 | } |
484 | } |
485 | } |
486 | |
487 | |
488 | return orderedListOfUsedResourceDesccriptors; |
489 | } |
490 | |
491 | private static List<ResourcesWithUtilisationDescriptor> getAllProcessors( |
492 | DSEProblem problem) { |
493 | List<ResourceContainer> containers = problem.getInitialInstance().getResourceEnvironment().getResourceContainer_ResourceEnvironment(); |
494 | List<ResourcesWithUtilisationDescriptor> descriptorList = new LinkedList<ResourcesWithUtilisationDescriptor>(); |
495 | for (ResourceContainer resourceContainer : containers) { |
496 | List<ProcessingResourceSpecification> processorsOnContainer = resourceContainer.getActiveResourceSpecifications_ResourceContainer(); |
497 | for (ProcessingResourceSpecification processingResourceSpecification : processorsOnContainer) { |
498 | descriptorList.add(new ResourcesWithUtilisationDescriptor(resourceContainer, processingResourceSpecification.getActiveResourceType_ActiveResourceSpecification())); |
499 | } |
500 | |
501 | } |
502 | List<LinkingResource> links = problem.getInitialInstance().getResourceEnvironment().getLinkingResources__ResourceEnvironment(); |
503 | for (LinkingResource linkingResource : links) { |
504 | descriptorList.add(new ResourcesWithUtilisationDescriptor(linkingResource, linkingResource.getCommunicationLinkResourceSpecifications_LinkingResource().getCommunicationLinkResourceType_CommunicationLinkResourceSpecification())); |
505 | } |
506 | return descriptorList; |
507 | } |
508 | |
509 | private static ResultDecoratorRepository getResultDecorator(String[] lineArray, |
510 | int minExpectedLineArrayLength, List<ResourcesWithUtilisationDescriptor> processorsWithUtilResults) throws CoreException { |
511 | |
512 | ResultDecoratorRepository repo = ResultdecoratorFactory.eINSTANCE.createResultDecoratorRepository(); |
513 | |
514 | for (int i = 0; i < lineArray.length - minExpectedLineArrayLength && i < processorsWithUtilResults.size(); i++) { |
515 | String entry = lineArray[i+minExpectedLineArrayLength]; |
516 | if (entry.length() > 0){ |
517 | ResourcesWithUtilisationDescriptor processor = processorsWithUtilResults.get(i); |
518 | ActiveResourceUtilisationResult result = processor.createUtilisationResult(); |
519 | |
520 | result.setResourceUtilisation(Double.parseDouble(entry)); |
521 | //TODO: implement these if possible. |
522 | result.setDemandedTime(Double.NaN); |
523 | result.setAverageWaitTime(Double.NaN); |
524 | repo.getUtilisationResults_ResultDecoratorRepository().add(result); |
525 | } |
526 | |
527 | } |
528 | return repo; |
529 | |
530 | } |
531 | |
532 | private static int countConfidenceIntervals( |
533 | String[] headlineArray) throws CoreException { |
534 | //now count confidence intervals. |
535 | int numberOfConfidenceIntervals = 0; |
536 | for (int i = 0; i < headlineArray.length; i++) { |
537 | if (headlineArray[i].contains(DSEConstantsContainer.LOWER_BOUND_CONFIDENCE+"(")){ |
538 | //|| headlineArray[i].contains(DSEConstantsContainer.UPPER_BOUND_CONFIDENCE+"(") |
539 | //|| headlineArray[i].contains(DSEConstantsContainer.ALPHA) ){ |
540 | numberOfConfidenceIntervals++; |
541 | } |
542 | } |
543 | return numberOfConfidenceIntervals; |
544 | } |
545 | |
546 | private static DesignDecisionGenotype extractGenotypeAndAddToList( |
547 | int startIndexOfGenotype, |
548 | List<DegreeOfFreedomInstance> orderedDesignDecisions, String[] lineArray) throws CoreException { |
549 | |
550 | DesignDecisionGenotype genotype = new DesignDecisionGenotype(); |
551 | //read in genotype |
552 | int decisionIndex = 0; |
553 | for (int i = startIndexOfGenotype; i < lineArray.length && decisionIndex < orderedDesignDecisions.size(); i++) { |
554 | Choice gene = DSEDecoder.getChoiceFor(lineArray[i], orderedDesignDecisions.get(decisionIndex)); |
555 | genotype.add(gene); |
556 | decisionIndex++; |
557 | } |
558 | return genotype; |
559 | } |
560 | |
561 | private static DSEObjectives readInObjectivesAndConfidence( |
562 | List<List<CriterionAndEvaluator>> orderedObjectives, |
563 | int startIndexOfConfidence, int numberOfConfidenceIntervals, |
564 | String[] lineArray) throws CoreException { |
565 | //Read in objectives |
566 | DSEObjectives objectives = readInObjectives(lineArray, startIndexOfConfidence, orderedObjectives); |
567 | |
568 | //read in confidence |
569 | readInConfidenceIntervals(lineArray, startIndexOfConfidence, numberOfConfidenceIntervals, orderedObjectives, objectives); |
570 | return objectives; |
571 | } |
572 | |
573 | /** |
574 | * Orders the objectives based on the file and also adjusts the DSEProblem accordingly. |
575 | * @param decisionList |
576 | * @param headlineArray |
577 | * @param startIndexOfGenotype |
578 | * @param problem |
579 | * @return |
580 | */ |
581 | private static List<DegreeOfFreedomInstance> getOrderedDesignDecisions( |
582 | List<DegreeOfFreedomInstance> decisionList, String[] headlineArray, |
583 | int startIndexOfGenotype, DSEProblem problem) throws CoreException{ |
584 | List<DegreeOfFreedomInstance> orderedDesignDecisions = new ArrayList<DegreeOfFreedomInstance>(); |
585 | for (int i = startIndexOfGenotype; i < headlineArray.length; i++) { |
586 | String headlineEntry = headlineArray[i]; |
587 | for (DegreeOfFreedomInstance decision : decisionList) { |
588 | //We could use an iterator here and directly delete all design decision that have been matched from the list, to make the subsequent steps faster. |
589 | if (DegreeOfFreedomHelper.getDegreeDescription(decision).contains(headlineEntry)){ |
590 | orderedDesignDecisions.add(decision); |
591 | break; |
592 | } |
593 | } |
594 | } |
595 | |
596 | //Check that the last colums are only utilisation values. |
597 | int numberOfUtilColumns = 0; |
598 | for (int i = startIndexOfGenotype + orderedDesignDecisions.size(); i < headlineArray.length; i++){ |
599 | String headlineString = headlineArray[i]; |
600 | if (headlineString.contains("Util") || headlineString.contains("Candidate ID")){ |
601 | numberOfUtilColumns++; |
602 | } |
603 | } |
604 | |
605 | // If there were unrecognised headline entries (entries that are not before the genotype and that do |
606 | // not contain the Substring Util, throw an exception |
607 | if (headlineArray.length - startIndexOfGenotype - numberOfUtilColumns > orderedDesignDecisions.size()) |
608 | throw ExceptionHelper.createNewCoreException("Not all design decisions in the file were recognised. Check your file.\n" |
609 | + " Design decisions from index "+startIndexOfGenotype+" to index "+(headlineArray.length - numberOfUtilColumns -1) |
610 | + ", but expected "+orderedDesignDecisions.size()+ " decisions.\n These decisions are expected: "+orderedDesignDecisions.toString() |
611 | + "\n Make sure that you provided a designdecision file that matches the predefined candidates (i.e. there is a decision for each column in the predefined candidates files)."); |
612 | |
613 | //set the internal design decisions to the same order |
614 | problem.getDesignDecisions().clear(); |
615 | problem.getDesignDecisions().addAll(orderedDesignDecisions); |
616 | |
617 | return orderedDesignDecisions; |
618 | } |
619 | |
620 | /** |
621 | * Fills the confidence intervals of the passed objective and returns it. |
622 | * @param lineArray |
623 | * @param startIndexOfConfidence |
624 | * @param numberOfConfidenceIntervals |
625 | * @param orderedObjectives |
626 | * @param objectives |
627 | * @return |
628 | * @throws CoreException |
629 | */ |
630 | private static DSEObjectives readInConfidenceIntervals(String[] lineArray, |
631 | int startIndexOfConfidence, int numberOfConfidenceIntervals, |
632 | List<List<CriterionAndEvaluator>> orderedObjectives, DSEObjectives objectives) throws CoreException { |
633 | |
634 | //read in confidence |
635 | int index = startIndexOfConfidence; |
636 | for (List<CriterionAndEvaluator> objectiveAndEvaluatorList : orderedObjectives) { |
637 | if (objectiveAndEvaluatorList.size() > 0){ |
638 | |
639 | // only the first evaluator has to be handled because they all point to the same IAnalysis (e.g. SimuCom) |
640 | CriterionAndEvaluator objectiveAndEvaluator = objectiveAndEvaluatorList.get(0); |
641 | |
642 | if (objectiveAndEvaluator.getEvaluator().hasStatisticResults() && index < lineArray.length - 2){ |
643 | String lowerConfidenceString = lineArray[index]; |
644 | String upperConfidenceString = lineArray[index+1]; |
645 | String alphaConfidenceString = lineArray[index+2]; |
646 | |
647 | Criterion criterion = objectiveAndEvaluator.getCriterion(); |
648 | Value<?> value = objectives.getValueForCriterion(criterion); |
649 | |
650 | ConfidenceInterval ci = readInConfidenceInterval(lowerConfidenceString, upperConfidenceString, alphaConfidenceString, value); |
651 | index = index +3; |
652 | objectives.addConfidence(objectiveAndEvaluator.getCriterion(), ci); |
653 | } else { |
654 | |
655 | } |
656 | } |
657 | } |
658 | return objectives; |
659 | } |
660 | |
661 | /** |
662 | * Objective definition must be in the first columns of the file. |
663 | * |
664 | * @param headline |
665 | * @param objectiveList: A list of lists. The inner lists contains the {@link Criterion} for one headline entry. |
666 | * The list is in the same order as the headline, so the values in the lines can be associated with a {@link Criterion} by index. |
667 | * The inner lists are not empty. |
668 | * @return never null, but may be an empty list. |
669 | */ |
670 | private static List<List<CriterionAndEvaluator>> getOrderedObjectiveCollection(String[] headline, List<CriterionAndEvaluator> objectiveList) throws CoreException{ |
671 | |
672 | List<List<CriterionAndEvaluator>> orderedObjectives = new ArrayList<List<CriterionAndEvaluator>>(objectiveList.size()); |
673 | |
674 | for (int i = 0; i < headline.length; i++) { |
675 | String objectiveString = headline[i]; |
676 | List<CriterionAndEvaluator> o = matchObjective(objectiveList, objectiveString); |
677 | if (o.size() == 0){ |
678 | //The current entry is not an objective, so the objective columns are done |
679 | break; |
680 | } else { |
681 | orderedObjectives.add(o); |
682 | } |
683 | } |
684 | |
685 | if (objectiveList.size() < orderedObjectives.size()){ |
686 | // I cannot have more objectives than evaluators. |
687 | // throw Exception and notify user that there must be only one column per objective |
688 | throw ExceptionHelper.createNewCoreException("Error reading in objectives: There must be only one column for each objective."); |
689 | } |
690 | |
691 | return orderedObjectives; |
692 | } |
693 | |
694 | |
695 | private static ConfidenceInterval readInConfidenceInterval( |
696 | String lowerConfidenceString, String upperConfidenceString, |
697 | String alphaConfidenceString, |
698 | Value<?> value) throws CoreException { |
699 | |
700 | try { |
701 | double lowerBound = parseToDouble(lowerConfidenceString); |
702 | double upperBound = parseToDouble(upperConfidenceString); |
703 | double level = parseToDouble(alphaConfidenceString); |
704 | return new ConfidenceInterval(value.getDouble(), lowerBound, upperBound, level); |
705 | } catch (NumberFormatException e){ |
706 | throw ExceptionHelper.createNewCoreException("Could not read in confidence interval. Expected this to be a confidence interval: " |
707 | +lowerConfidenceString+SEPARATOR+upperConfidenceString+SEPARATOR+alphaConfidenceString, e); |
708 | } |
709 | |
710 | |
711 | } |
712 | |
713 | |
714 | |
715 | private static List<CriterionAndEvaluator> matchObjective( |
716 | List<CriterionAndEvaluator> objectiveList, String objectiveString) { |
717 | List<CriterionAndEvaluator> results = new ArrayList<CriterionAndEvaluator>(objectiveList.size()); |
718 | for (CriterionAndEvaluator objective : objectiveList) { |
719 | if (objectiveString.equals(ResultsWriter.getDimensionName(objective.getCriterion()))){ |
720 | results.add(objective); |
721 | } |
722 | } |
723 | return results; |
724 | } |
725 | |
726 | /** |
727 | * Reads in |
728 | * @param orderedObjectives |
729 | * @param endIndex |
730 | * @param |
731 | * @return |
732 | * @throws IOException |
733 | * @throws CoreException |
734 | */ |
735 | private static DSEObjectives readInObjectives(String[] objectiveLine, int endIndex, List<List<CriterionAndEvaluator>> orderedObjectives) throws CoreException { |
736 | |
737 | //objective line must have at least the length of the passed list |
738 | if (objectiveLine.length < orderedObjectives.size()){ |
739 | throw ExceptionHelper.createNewCoreException("Error when reading in result line: the line is shorter ("+objectiveLine+" entries) than the number of objectives I look for ("+orderedObjectives.size()+"entries)."); |
740 | } |
741 | |
742 | DSEObjectives obj; |
743 | if (task != null){ |
744 | obj = task.getInstance(DSEObjectives.class);//QUICKHACK |
745 | } else { |
746 | //TODO: LEGACY, but required in PredefinedInstanceEvaluator because that one does not initialise the Opt4J environment. |
747 | obj = new DSEObjectives(); |
748 | } |
749 | |
750 | int lineIndex = 0; |
751 | for (List<CriterionAndEvaluator> criterionList : orderedObjectives) { |
752 | try { |
753 | double d = parseToDouble(objectiveLine[lineIndex]); |
754 | for (CriterionAndEvaluator criterionAndEvaluator : criterionList) { |
755 | Criterion criterion = criterionAndEvaluator.getCriterion(); |
756 | obj.addValueForCriterion(criterion, d); |
757 | } |
758 | } catch (NumberFormatException e){ |
759 | throw ExceptionHelper.createNewCoreException("Could not parse objective value "+objectiveLine[lineIndex]+". Fix your input genome file."); |
760 | } |
761 | lineIndex++; |
762 | } |
763 | |
764 | return obj; |
765 | } |
766 | |
767 | private static double parseToDouble(String number) { |
768 | double d = Double.parseDouble(number); |
769 | if (Double.isInfinite(d)){ |
770 | logger.warn("Read in an infinite objective or confidence interval from predefined file, please check that this is correct and not result of an incomplete previous analysis step."); |
771 | } else if (Double.isNaN(d)){ |
772 | logger.warn("Read in an objective or confidence interval with NaN value from predefined file, please check that this is correct and not result of an incomplete previous analysis step."); |
773 | } |
774 | return d; |
775 | } |
776 | |
777 | } |
778 | |
779 | class ResourcesWithUtilisationDescriptor{ |
780 | |
781 | Entity resource; |
782 | |
783 | ResourceType resourceType; |
784 | |
785 | public ResourcesWithUtilisationDescriptor(Entity resource, ResourceType resourceType) { |
786 | super(); |
787 | this.resource = resource; |
788 | this.resourceType = resourceType; |
789 | } |
790 | |
791 | public ResourceType getResourceType() { |
792 | return this.resourceType; |
793 | } |
794 | |
795 | public Entity getEntity() { |
796 | return this.resource; |
797 | } |
798 | |
799 | public ActiveResourceUtilisationResult createUtilisationResult() throws CoreException{ |
800 | if (resource instanceof ResourceContainer){ |
801 | if (resourceType != null){ |
802 | ResourceContainer rc = (ResourceContainer)resource; |
803 | |
804 | for (ProcessingResourceSpecification procRes : rc.getActiveResourceSpecifications_ResourceContainer()) { |
805 | if (procRes.getActiveResourceType_ActiveResourceSpecification().getId().equals(resourceType.getId())){ |
806 | |
807 | ProcessingResourceSpecificationResult result = ResourceenvironmentdecoratorFactory.eINSTANCE.createProcessingResourceSpecificationResult(); |
808 | result.setProcessingResourceSpecification_ProcessingResourceSpecificationResult(procRes); |
809 | result.setEntityName("Util of "+resource.getEntityName() |
810 | +"_"+resourceType.getEntityName()); |
811 | return result; |
812 | } |
813 | } |
814 | throw ExceptionHelper.createNewCoreException("No processing resource of type "+this.resourceType+" found for ResourceContainer "+this.resource.getEntityName()); |
815 | |
816 | } else { |
817 | // TODO: as soon as we support aggregated results for the whole resource container, this has to be handled here |
818 | throw ExceptionHelper.createNewCoreException("Aggregated utilisation results for resource containers are not yet supported, define a resource type."); |
819 | } |
820 | } else if (resource instanceof LinkingResource){ |
821 | LinkingResourceResults result = ResourceenvironmentdecoratorFactory.eINSTANCE.createLinkingResourceResults(); |
822 | result.setEntityName("Util of "+resource.getEntityName()+"_"+resourceType.getEntityName()); |
823 | result.setLinkingResource_LinkingResourceResults((LinkingResource) resource); |
824 | return result; |
825 | } else { |
826 | throw ExceptionHelper.createNewCoreException("Unknown entity to create utilisation results for: "+this.resource.getClass().getName()); |
827 | } |
828 | } |
829 | |
830 | } |
831 | |