1 | package de.uka.ipd.sdq.reliability.solver.sensitivity; |
2 | |
3 | import java.io.BufferedWriter; |
4 | import java.io.File; |
5 | import java.io.FileWriter; |
6 | import java.io.IOException; |
7 | import java.util.ArrayList; |
8 | import java.util.List; |
9 | |
10 | import org.apache.log4j.Logger; |
11 | import org.eclipse.emf.common.util.EList; |
12 | |
13 | import de.uka.ipd.sdq.pcm.usagemodel.UsageScenario; |
14 | import de.uka.ipd.sdq.pcmsolver.models.PCMInstance; |
15 | import de.uka.ipd.sdq.reliability.core.helper.EMFHelper; |
16 | import de.uka.ipd.sdq.reliability.solver.pcm2markov.MarkovTransformationResult; |
17 | import de.uka.ipd.sdq.sensitivity.DoubleParameterVariation; |
18 | import de.uka.ipd.sdq.sensitivity.SensitivityParameterVariation; |
19 | import de.uka.ipd.sdq.sensitivity.SensitivityResultSpecification; |
20 | import de.uka.ipd.sdq.sensitivity.StringParameterSequence; |
21 | |
22 | /** |
23 | * Base class for (rudimentary) sensitivity analysis. |
24 | * |
25 | * Further refactorings required. |
26 | * |
27 | * @author brosch |
28 | * |
29 | */ |
30 | public abstract class MarkovSensitivity { |
31 | |
32 | /** |
33 | * Character used to separate entries in the sensitivity log file. |
34 | */ |
35 | private static final String LOG_ENTRY_SEPARATOR = "\\"; |
36 | |
37 | /** |
38 | * A logger to give detailed information about the PCM instance |
39 | * transformation. |
40 | */ |
41 | protected Logger logger = null; |
42 | |
43 | /** |
44 | * A calculator for variations and steps during the sensitivity analysis. |
45 | */ |
46 | protected SensitivityCalculator calculator = new SensitivityCalculator(); |
47 | |
48 | /** |
49 | * The current sensitivity analysis step. |
50 | */ |
51 | private int currentStepNumber = 0; |
52 | |
53 | /** |
54 | * Provides EMF utility functions. |
55 | */ |
56 | protected EMFHelper helper = new EMFHelper(); |
57 | |
58 | /** |
59 | * Stores the contents of the log file. |
60 | */ |
61 | private List<List<String>> logContents = null; |
62 | |
63 | /** |
64 | * Provides a writer to the log file. |
65 | */ |
66 | protected BufferedWriter logWriter = null; |
67 | |
68 | /** |
69 | * The model on which sensitivity analysis is based. |
70 | */ |
71 | protected PCMInstance model; |
72 | |
73 | /** |
74 | * The name of this sensitivity (for logging). |
75 | */ |
76 | protected String name = null; |
77 | |
78 | /** |
79 | * The number of steps to take during sensitivity analysis. |
80 | */ |
81 | protected int numberOfSteps; |
82 | |
83 | /** |
84 | * The log file for sensitivity results. |
85 | */ |
86 | private String resultLogfile = null; |
87 | |
88 | /** |
89 | * The list of relevant Markov analysis results. |
90 | */ |
91 | private EList<SensitivityResultSpecification> resultSpecifications = null; |
92 | |
93 | /** |
94 | * The variation of this sensitivity analysis. |
95 | */ |
96 | private SensitivityParameterVariation variation = null; |
97 | |
98 | /** |
99 | * The constructor. |
100 | * |
101 | * Only to be invoked by concrete sub classes. |
102 | * |
103 | * @param name |
104 | * the name of the sensitivity analysis |
105 | * @param variation |
106 | * the parameter variation |
107 | */ |
108 | protected MarkovSensitivity(final String name, |
109 | final SensitivityParameterVariation variation) { |
110 | this.name = name; |
111 | this.logger = Logger.getLogger(this.getClass().getName()); |
112 | if (variation != null) { |
113 | this.variation = variation; |
114 | this.numberOfSteps = calculator.calculateNumberOfSteps(variation); |
115 | } |
116 | } |
117 | |
118 | /** |
119 | * Alters the model according to the next sensitivity analysis step. |
120 | * |
121 | * @return indicates if the model could be successfully altered |
122 | */ |
123 | protected abstract boolean alterModel(); |
124 | |
125 | /** |
126 | * Assures a minimal number of three lines for the log headings. |
127 | * |
128 | * @param list |
129 | * the log headings |
130 | */ |
131 | private void assureLogHeadingsSize(final List<List<String>> list) { |
132 | int numColumns = list.get(0).size(); |
133 | int numLines = list.size(); |
134 | if (numLines < 3) { |
135 | for (int i = numLines; i < 3; i++) { |
136 | ArrayList<String> newLine = new ArrayList<String>(); |
137 | for (int y = 0; y < numColumns; y++) { |
138 | newLine.add(""); |
139 | } |
140 | list.add(0, newLine); |
141 | } |
142 | } |
143 | } |
144 | |
145 | /** |
146 | * Extracts the relevant sensitivity information from the given model. |
147 | */ |
148 | protected abstract void extractSensitivityInformation(); |
149 | |
150 | /** |
151 | * Fills empty entries of the given log headings list. |
152 | * |
153 | * @param list |
154 | * the log headings list |
155 | */ |
156 | private void fillEmptyEntries(List<List<String>> list) { |
157 | int numLines = list.size(); |
158 | int maxNumColumns = 0; |
159 | for (int i = 0; i < numLines; i++) { |
160 | if (list.get(i).size() > maxNumColumns) { |
161 | maxNumColumns = list.get(i).size(); |
162 | } |
163 | } |
164 | for (int i = 0; i < numLines; i++) { |
165 | for (int y = list.get(i).size(); y < maxNumColumns; y++) { |
166 | list.get(i).add(""); |
167 | } |
168 | } |
169 | } |
170 | |
171 | /** |
172 | * Finalizes the sensitivity analysis. |
173 | */ |
174 | public void finalize() { |
175 | try { |
176 | // Do the logging: |
177 | for (int lineNumber = 0; lineNumber < logContents.size(); lineNumber++) { |
178 | for (int index = 0; index < logContents.get(lineNumber).size(); index++) { |
179 | logWriter.append(logContents.get(lineNumber).get(index) |
180 | + LOG_ENTRY_SEPARATOR); |
181 | } |
182 | logWriter.append(System.getProperty("line.separator")); |
183 | } |
184 | logWriter.flush(); |
185 | logWriter.close(); |
186 | } catch (IOException e) { |
187 | logger.error("Log file could not be written :" + e.getMessage()); |
188 | e.printStackTrace(); |
189 | } |
190 | } |
191 | |
192 | /** |
193 | * Retrieves the current step number. |
194 | * |
195 | * @return the current step number |
196 | */ |
197 | protected int getCurrentStepNumber() { |
198 | return currentStepNumber; |
199 | } |
200 | |
201 | /** |
202 | * Returns the double parameter variation. |
203 | * |
204 | * @return the double parameter variation |
205 | */ |
206 | protected DoubleParameterVariation getDoubleVariation() { |
207 | return (DoubleParameterVariation) variation; |
208 | } |
209 | |
210 | /** |
211 | * Builds the headings strings for logging. |
212 | * |
213 | * @return the log headings strings |
214 | */ |
215 | private List<List<String>> getLogHeadings() { |
216 | |
217 | // Create a result list: |
218 | List<List<String>> resultList = getLogHeadingsMulti(); |
219 | |
220 | // Assure that there are at least three lines of headings: |
221 | assureLogHeadingsSize(resultList); |
222 | for (UsageScenario scenario : model.getUsageModel() |
223 | .getUsageScenario_UsageModel()) { |
224 | resultList.get(resultList.size() - 3).add(scenario.getEntityName()); |
225 | resultList.get(resultList.size() - 2).add("Success Probability"); |
226 | resultList.get(resultList.size() - 2).add("Failure Probability"); |
227 | resultList.get(resultList.size() - 1).add(""); |
228 | resultList.get(resultList.size() - 1).add("Total"); |
229 | for (int i = 0; i < resultSpecifications.size(); i++) { |
230 | resultList.get(resultList.size() - 1).add( |
231 | resultSpecifications.get(i).getEntityName()); |
232 | } |
233 | fillEmptyEntries(resultList); |
234 | } |
235 | |
236 | // Return the result: |
237 | return resultList; |
238 | } |
239 | |
240 | /** |
241 | * Builds the headings strings for logging. |
242 | * |
243 | * @return the log headings strings |
244 | */ |
245 | protected abstract List<List<String>> getLogHeadingsMulti(); |
246 | |
247 | /** |
248 | * Builds the results strings for sensitivity logging. |
249 | * |
250 | * @param markovResults |
251 | * the Markov transformation results |
252 | * @return the results strings |
253 | */ |
254 | protected List<String> getLogSingleResults( |
255 | final List<MarkovTransformationResult> markovResults) { |
256 | |
257 | // Create a result list: |
258 | List<String> resultList = getLogSingleResultsMulti(); |
259 | for (MarkovTransformationResult result : markovResults) { |
260 | resultList |
261 | .add(((Double) result.getSuccessProbability()).toString()); |
262 | resultList.add(((Double) (1.0 - result.getSuccessProbability())) |
263 | .toString()); |
264 | for (int i = 0; i < resultSpecifications.size(); i++) { |
265 | resultList.add(((Double) calculator.calculateFailurePotential( |
266 | result, resultSpecifications.get(i))).toString()); |
267 | } |
268 | } |
269 | |
270 | // Return the result: |
271 | return resultList; |
272 | } |
273 | |
274 | /** |
275 | * Builds the results string for sensitivity logging. |
276 | * |
277 | * @return the results strings |
278 | */ |
279 | protected abstract List<String> getLogSingleResultsMulti(); |
280 | |
281 | /** |
282 | * Retrieves the PCM instance. |
283 | * |
284 | * @return the PCM instance |
285 | */ |
286 | protected PCMInstance getModel() { |
287 | return model; |
288 | } |
289 | |
290 | /** |
291 | * Retrieves the model to be used for the next step in the sensitivity |
292 | * analysis. |
293 | * |
294 | * @return the model |
295 | */ |
296 | public PCMInstance getNextModel() { |
297 | |
298 | // Check if there are still steps to perform: |
299 | if (increaseCurrentStepNumber()) { |
300 | return null; |
301 | } |
302 | |
303 | // Perform the next step: |
304 | if (!alterModel()) { |
305 | logger.error("PCM instance could not be successfully altered by Markov sensitivity analysis."); |
306 | return null; |
307 | } else { |
308 | return model; |
309 | } |
310 | } |
311 | |
312 | /** |
313 | * Returns the string parameter sequence. |
314 | * |
315 | * @return the string parameter sequence |
316 | */ |
317 | protected StringParameterSequence getStringSequence() { |
318 | return (StringParameterSequence) variation; |
319 | } |
320 | |
321 | /** |
322 | * Increases the current step number. |
323 | * |
324 | * @return indicates an overflow |
325 | */ |
326 | protected boolean increaseCurrentStepNumber() { |
327 | if (currentStepNumber < numberOfSteps) { |
328 | currentStepNumber++; |
329 | return false; |
330 | } |
331 | return true; |
332 | } |
333 | |
334 | /** |
335 | * Initializes the sensitivity analysis. |
336 | * |
337 | * @param model |
338 | * the PCM instance |
339 | */ |
340 | public void initialize(final PCMInstance model) { |
341 | setModel(model); |
342 | try { |
343 | new File(resultLogfile).delete(); |
344 | logWriter = new BufferedWriter(new FileWriter(resultLogfile, false)); |
345 | } catch (IOException e) { |
346 | logger |
347 | .error("Log file could not be initialized :" |
348 | + e.getMessage()); |
349 | e.printStackTrace(); |
350 | } |
351 | logContents = getLogHeadings(); |
352 | } |
353 | |
354 | /** |
355 | * Logs the results of the current sensitivity analysis step. |
356 | * |
357 | * @param markovResults |
358 | * the markov transformation results |
359 | */ |
360 | public void logResults(final List<MarkovTransformationResult> markovResults) { |
361 | logContents.add(getLogSingleResults(markovResults)); |
362 | } |
363 | |
364 | /** |
365 | * Resets the current step number. |
366 | * |
367 | */ |
368 | protected void resetCurrentStepNumber() { |
369 | currentStepNumber = 1; |
370 | } |
371 | |
372 | /** |
373 | * Sets the result log file name. |
374 | * |
375 | * @param logFileName |
376 | * the log file name |
377 | */ |
378 | public void setLogFileName(final String logFileName) { |
379 | this.resultLogfile = logFileName; |
380 | } |
381 | |
382 | /** |
383 | * Sets the PCM instance. |
384 | * |
385 | * @param model |
386 | * the PCM instance |
387 | */ |
388 | protected void setModel(final PCMInstance model) { |
389 | this.model = model; |
390 | extractSensitivityInformation(); |
391 | } |
392 | |
393 | /** |
394 | * Specifies the relevant Markov analysis results. |
395 | * |
396 | * @param resultSpecifications |
397 | * specification of results |
398 | */ |
399 | public void setResultSpecifications( |
400 | final EList<SensitivityResultSpecification> resultSpecifications) { |
401 | this.resultSpecifications = resultSpecifications; |
402 | } |
403 | } |