1 | package de.uka.ipd.sdq.reliability.solver.pcm2markov; |
2 | |
3 | import java.io.BufferedWriter; |
4 | import java.io.File; |
5 | import java.io.FileWriter; |
6 | import java.io.IOException; |
7 | import java.net.URL; |
8 | import java.util.HashMap; |
9 | import java.util.List; |
10 | import java.util.Map; |
11 | |
12 | import org.apache.log4j.Logger; |
13 | import org.eclipse.core.runtime.FileLocator; |
14 | |
15 | import de.uka.ipd.sdq.markov.MarkovChain; |
16 | import de.uka.ipd.sdq.markov.State; |
17 | import de.uka.ipd.sdq.pcm.usagemodel.UsageScenario; |
18 | import de.uka.ipd.sdq.pcmsolver.runconfig.PCMSolverWorkflowRunConfiguration; |
19 | import de.uka.ipd.sdq.reliability.core.MarkovFailureType; |
20 | |
21 | /** |
22 | * Aggregates the results of a PCM2MarkovTransformation. |
23 | * |
24 | * @author brosch |
25 | * |
26 | */ |
27 | public class MarkovTransformationResult { |
28 | |
29 | /** |
30 | * A logger to give detailed information about the PCM instance |
31 | * transformation. |
32 | */ |
33 | private static Logger logger = Logger |
34 | .getLogger(MarkovTransformationResult.class.getName()); |
35 | |
36 | /** |
37 | * Indicates if an approximation scheme shall be used for printing of |
38 | * probabilities. |
39 | */ |
40 | private boolean approximate; |
41 | |
42 | /** |
43 | * Configuration options of the transformation. |
44 | */ |
45 | private PCMSolverWorkflowRunConfiguration configuration; |
46 | |
47 | /** |
48 | * Overall failure type probabilities, accumulated over all considered |
49 | * physical system states. |
50 | */ |
51 | private Map<MarkovFailureType, Double> cumulatedFailureTypeProbabilities = new HashMap<MarkovFailureType, Double>(); |
52 | |
53 | /** |
54 | * Overall physical state probability, accumulated over all considered |
55 | * physical system states. |
56 | */ |
57 | private double cumulatedPhysicalStateProbability; |
58 | |
59 | /** |
60 | * Overall success probability, accumulated over all considered physical |
61 | * system states. |
62 | */ |
63 | private double cumulatedSuccessProbability; |
64 | |
65 | /** |
66 | * The list of potential failure types. |
67 | */ |
68 | private List<MarkovFailureType> failureTypes; |
69 | |
70 | /** |
71 | * A helper class providing functionality for Markov chains. |
72 | */ |
73 | private MarkovBuilder markovBuilder; |
74 | |
75 | /** |
76 | * Holds state information required during the PCM2MarkovTransformation. |
77 | */ |
78 | private MarkovTransformationSource markovSource; |
79 | |
80 | /** |
81 | * Indicates the number of physical system states (which is n^2 for n |
82 | * resources). |
83 | */ |
84 | private long numberOfPhysicalSystemStates; |
85 | |
86 | /** |
87 | * Counts the evaluated physical system states. |
88 | */ |
89 | private long physicalStateEvaluationCount; |
90 | |
91 | /** |
92 | * Holds the Makov chain that results from the transformation. |
93 | */ |
94 | private MarkovChain resultChain; |
95 | |
96 | /** |
97 | * The usage scenario which has been evaluated. |
98 | */ |
99 | private UsageScenario scenario; |
100 | |
101 | /** |
102 | * Creates a new Markov results aggregator. |
103 | * |
104 | * @param configuration |
105 | * configuration options of the transformation |
106 | * @param markovSource |
107 | * the Markov state holder |
108 | * @param scenario |
109 | * the usage scenario to evaluate |
110 | * @param failureTypes |
111 | * the list of potential failure types |
112 | */ |
113 | public MarkovTransformationResult( |
114 | final PCMSolverWorkflowRunConfiguration configuration, |
115 | final MarkovTransformationSource markovSource, |
116 | final UsageScenario scenario, |
117 | final List<MarkovFailureType> failureTypes) { |
118 | this.configuration = configuration; |
119 | this.cumulatedPhysicalStateProbability = 0.0; |
120 | this.cumulatedSuccessProbability = 0.0; |
121 | this.markovBuilder = new MarkovBuilder(false); |
122 | this.markovSource = markovSource; |
123 | this.physicalStateEvaluationCount = 0; |
124 | this.numberOfPhysicalSystemStates = (long) Math.pow(2, markovSource |
125 | .getUnreliableResourceDescriptors().size()); |
126 | this.resultChain = null; |
127 | this.scenario = scenario; |
128 | this.failureTypes = failureTypes; |
129 | } |
130 | |
131 | /** |
132 | * Adds the results of the evaluation of a single physical system state |
133 | * during the PCM2Markov transformation. |
134 | * |
135 | * @param resultChain |
136 | * the Markov chain resulting from the evaluation of the physical |
137 | * system state |
138 | * @param markovProbabilityMatrix |
139 | * the matrix with the probabilities to get from state i to state |
140 | * j in the Markov chain |
141 | * @param physicalStateProbability |
142 | * the probability of the evaluated physical system state to |
143 | * occur |
144 | */ |
145 | public void addPhysicalStateResults(final MarkovChain resultChain, |
146 | final double[][] markovProbabilityMatrix, |
147 | final double physicalStateProbability) { |
148 | |
149 | // Check plausibility of input parameters: |
150 | if (physicalStateProbability < 0.0 || physicalStateProbability > 1.0) { |
151 | throw new MarkovException("Illegal physical state probability (" |
152 | + physicalStateProbability |
153 | + "). The value must be in [0,1]."); |
154 | } |
155 | |
156 | // Store the first resulting Markov Chain: |
157 | if (physicalStateEvaluationCount == 0) { |
158 | this.resultChain = resultChain; |
159 | } |
160 | |
161 | // Get the indices of the Start and Success States: |
162 | int indexStart = markovBuilder.indexOf(resultChain, markovBuilder |
163 | .getStartState(resultChain)); |
164 | int indexSuccess = markovBuilder.indexOf(resultChain, markovBuilder |
165 | .getSuccessState(resultChain)); |
166 | |
167 | // Check plausibility of Markov probabilities: |
168 | double successProbability = markovProbabilityMatrix[indexStart][indexSuccess]; |
169 | if (successProbability < 0.0 || successProbability > 1.0) { |
170 | // It should never happen that the success probability is outside |
171 | // [0,1]. |
172 | // The only feasible explanation is a rounding error (which has been |
173 | // observed for certain sample PCM instances): |
174 | double correctedSuccessProbability = (successProbability < 0.5) ? 0.0 |
175 | : 1.0; |
176 | logger.warn("Illegal success probability " + successProbability |
177 | + " outside [0,1]. Assuming a rounding error. " |
178 | + "Setting success probability to " |
179 | + correctedSuccessProbability); |
180 | successProbability = correctedSuccessProbability; |
181 | } |
182 | |
183 | // Accumulate results: |
184 | cumulatedPhysicalStateProbability += physicalStateProbability; |
185 | cumulatedSuccessProbability += physicalStateProbability |
186 | * successProbability; |
187 | |
188 | // Consider also the failure type probabilities: |
189 | List<State> failureStates = markovBuilder.getFailureStates(resultChain); |
190 | for (int i = 0; i < failureStates.size(); i++) { |
191 | |
192 | // Check plausibility of Markov probabilities: |
193 | double failureTypeProbability = markovProbabilityMatrix[indexStart][markovBuilder |
194 | .indexOf(resultChain, failureStates.get(i))]; |
195 | if (failureTypeProbability < 0.0 || failureTypeProbability > 1.0) { |
196 | throw new MarkovException("Illegal failure type probability (" |
197 | + failureTypeProbability |
198 | + "). The value must be in [0,1]."); |
199 | } |
200 | |
201 | // Determine the failure type probability for this physical system |
202 | // state: |
203 | double failureTypeProbabilityDelta = physicalStateProbability |
204 | * failureTypeProbability; |
205 | |
206 | // Add the failure type probability to the already existing value: |
207 | String failureTypeId = markovBuilder.getFailureTypeId(failureStates |
208 | .get(i)); |
209 | MarkovFailureType failureType = getFailureType(failureTypeId); |
210 | |
211 | Double failureProbability = cumulatedFailureTypeProbabilities |
212 | .get(failureType); |
213 | cumulatedFailureTypeProbabilities.put(failureType, |
214 | ((failureProbability == null) ? 0.0 : failureProbability) |
215 | + failureTypeProbabilityDelta); |
216 | } |
217 | |
218 | // Increase the counter of evaluated physical system states: |
219 | physicalStateEvaluationCount++; |
220 | |
221 | // Do the logging: |
222 | if (configuration.isPrintMarkovSingleResults()) { |
223 | // yes - write output to log file |
224 | BufferedWriter out = null; |
225 | String filePath = resolveFile(configuration.getLogFile()); |
226 | try { |
227 | if (physicalStateEvaluationCount == 1) { |
228 | File f = new File(filePath); |
229 | // if the file exists, we will delete it and create a new, |
230 | // empty one |
231 | // (i.e., overwrite the existing file) once, and then |
232 | // repeatedly append |
233 | // to this file |
234 | if (f.exists()) { |
235 | f.delete(); // delete current ("old") file |
236 | f.createNewFile(); // create a new, empty file |
237 | } |
238 | out = new BufferedWriter(new FileWriter(filePath, true)); |
239 | logger |
240 | .info("Logging results of all Markov transformation runs to: " |
241 | + filePath); |
242 | out.append(getLogHeadings() |
243 | + System.getProperty("line.separator")); |
244 | out.flush(); |
245 | out.close(); |
246 | } |
247 | out = new BufferedWriter(new FileWriter(filePath, true)); |
248 | out.append(getLogSingleResults(successProbability, |
249 | physicalStateProbability) |
250 | + System.getProperty("line.separator")); |
251 | out.flush(); |
252 | } catch (IOException e) { |
253 | e.printStackTrace(); |
254 | } finally { |
255 | try { |
256 | if (out != null) { |
257 | out.flush(); |
258 | out.close(); |
259 | } |
260 | } catch (IOException e) { |
261 | e.printStackTrace(); |
262 | } |
263 | } |
264 | } |
265 | } |
266 | |
267 | /** |
268 | * Gets the overall failure type probabilities, accumulated over all |
269 | * considered physical system states. |
270 | * |
271 | * @return the overall failure type probabilities |
272 | */ |
273 | public Map<MarkovFailureType, Double> getCumulatedFailureTypeProbabilities() { |
274 | return cumulatedFailureTypeProbabilities; |
275 | } |
276 | |
277 | /** |
278 | * Gets the overall physical state probability, accumulated over all |
279 | * considered physical system states. |
280 | * |
281 | * @return the overall physical state probability |
282 | */ |
283 | public double getCumulatedPhysicalStateProbability() { |
284 | return cumulatedPhysicalStateProbability; |
285 | } |
286 | |
287 | /** |
288 | * Retrieves the failure type with the given id. |
289 | * |
290 | * @param failureTypeId |
291 | * the failure type id |
292 | * @return the failure type |
293 | */ |
294 | private MarkovFailureType getFailureType(String failureTypeId) { |
295 | for (MarkovFailureType failureType : failureTypes) { |
296 | if (failureType.getId().equals(failureTypeId)) { |
297 | return failureType; |
298 | } |
299 | } |
300 | throw new IllegalArgumentException( |
301 | "MarkovTransformationResult: Failure type with ID \"" |
302 | + failureTypeId + "\" not found!"); |
303 | } |
304 | |
305 | /** |
306 | * Builds the headings string for Markov transformation logging. |
307 | * |
308 | * @return the log headings string |
309 | */ |
310 | private String getLogHeadings() { |
311 | |
312 | // Build a result string: |
313 | StringBuilder resultString = new StringBuilder(); |
314 | |
315 | // Append state number heading: |
316 | resultString.append("physical system state number;"); |
317 | |
318 | // Append resource state headings: |
319 | for (ProcessingResourceDescriptor descriptor : markovSource |
320 | .getUnreliableResourceDescriptors()) { |
321 | resultString.append(descriptor.getResourceContainerName() + " - " |
322 | + descriptor.getType().getName() + ";"); |
323 | } |
324 | |
325 | // Append success probability heading: |
326 | resultString.append("success probability;"); |
327 | |
328 | // Append state probability heading: |
329 | resultString.append("physical state probability"); |
330 | |
331 | // Return the result: |
332 | return resultString.toString(); |
333 | } |
334 | |
335 | /** |
336 | * Builds the results string for Markov transformation logging. |
337 | * |
338 | * @param successProbability |
339 | * success probability of the current physical system state |
340 | * @param physicalStateProbability |
341 | * occurrence probability of the current physical system state |
342 | * @return the results string |
343 | */ |
344 | private String getLogSingleResults(final double successProbability, |
345 | final double physicalStateProbability) { |
346 | |
347 | // Build a result string: |
348 | StringBuilder resultString = new StringBuilder(); |
349 | |
350 | // Append state number: |
351 | resultString.append(physicalStateEvaluationCount + ";"); |
352 | |
353 | // Append resource states: |
354 | for (ProcessingResourceDescriptor descriptor : markovSource |
355 | .getUnreliableResourceDescriptors()) { |
356 | resultString.append(descriptor.getCurrentState().name() + ";"); |
357 | } |
358 | |
359 | // Append success probability: |
360 | resultString.append(successProbability + ";"); |
361 | |
362 | // Append state probability: |
363 | resultString.append(physicalStateProbability); |
364 | |
365 | // Return the result: |
366 | return resultString.toString(); |
367 | } |
368 | |
369 | /** |
370 | * Retrieves the number of physical system states. |
371 | * |
372 | * @return the number of physical system states |
373 | */ |
374 | public long getNumberOfPhysicalSystemStates() { |
375 | return numberOfPhysicalSystemStates; |
376 | } |
377 | |
378 | /** |
379 | * Retrieves the current number of evaluated physical system states. |
380 | * |
381 | * @return the current number of evaluated physical system states |
382 | */ |
383 | public long getPhysicalStateEvaluationCount() { |
384 | return physicalStateEvaluationCount; |
385 | } |
386 | |
387 | /** |
388 | * Retrieves the Markov chain that results from the transformation. |
389 | * |
390 | * @return the Markov chain that results from the transformation |
391 | */ |
392 | public MarkovChain getResultChain() { |
393 | return resultChain; |
394 | } |
395 | |
396 | /** |
397 | * Gets the usage scenario which has been evaluated |
398 | * |
399 | * @return the usage scenario |
400 | */ |
401 | public UsageScenario getScenario() { |
402 | return scenario; |
403 | } |
404 | |
405 | /** |
406 | * Retrieves the overall success probability. |
407 | * |
408 | * @return the success probability |
409 | */ |
410 | public double getSuccessProbability() { |
411 | return cumulatedSuccessProbability; |
412 | } |
413 | |
414 | /** |
415 | * Determines if the calculated success probability conforms to a given |
416 | * required accuracy. |
417 | * |
418 | * @param requiredAccuracy |
419 | * the required accuracy in decimal places |
420 | * @return true if the required accuracy has been reached |
421 | */ |
422 | public boolean hasRequiredAccuracy(final int requiredAccuracy) { |
423 | |
424 | // Create an approximation for the accumulated success probability: |
425 | MarkovResultApproximation approximation = new MarkovResultApproximation( |
426 | cumulatedSuccessProbability, cumulatedSuccessProbability |
427 | + (1.0 - cumulatedPhysicalStateProbability)); |
428 | |
429 | // Check for the required accuracy: |
430 | return approximation.hasRequiredAccuracy(requiredAccuracy); |
431 | } |
432 | |
433 | /** |
434 | * Indicates if an approximation scheme shall be used for printing of |
435 | * probabilities. |
436 | * |
437 | * @return <code>true</code>, if an approximation scheme shall be used for |
438 | * printing probabilities, <code>false</code> otherwise. |
439 | */ |
440 | public boolean isDoApproximate() { |
441 | return (configuration.isIterationOverPhysicalSystemStatesEnabled()) |
442 | && approximate |
443 | && (physicalStateEvaluationCount < Math.pow(markovSource |
444 | .getUnreliableResourceDescriptors().size(), 2)); |
445 | } |
446 | |
447 | /** |
448 | * Resolves a file's path in case it starts with "platform:/" and returns |
449 | * the entire absolute path to the file, including the file's name. |
450 | * |
451 | * @param fileURL |
452 | * the path to a file, including the file's name (and its |
453 | * extension) |
454 | * @return the absolute path to the file, including the file's name |
455 | */ |
456 | private String resolveFile(String fileURL) { |
457 | // if this is a platform URL, first resolve it to an absolute path |
458 | if (fileURL.startsWith("platform:")) { |
459 | try { |
460 | URL solvedURL = FileLocator.resolve(new URL(fileURL)); |
461 | fileURL = solvedURL.getPath(); |
462 | } catch (Exception e) { |
463 | e.printStackTrace(); |
464 | return ""; |
465 | } |
466 | } |
467 | return fileURL; |
468 | } |
469 | |
470 | /** |
471 | * Method for setting a value responsible for telling if an approximation |
472 | * scheme shall be used for printing probabilities. |
473 | * |
474 | * @param approximate |
475 | * the value indicating if an approximation scheme shall be used |
476 | * for printing probabilities |
477 | */ |
478 | public void setApproximate(boolean approximate) { |
479 | this.approximate = approximate; |
480 | } |
481 | } |