1 | package de.uka.ipd.sdq.simucomframework.variables.cache; |
2 | |
3 | import java.util.Collection; |
4 | import java.util.Collections; |
5 | import java.util.HashMap; |
6 | import java.util.Iterator; |
7 | |
8 | import org.apache.log4j.Logger; |
9 | import org.eclipse.emf.common.util.EList; |
10 | import org.eclipse.emf.ecore.EObject; |
11 | import org.eclipse.emf.ecore.util.EcoreUtil; |
12 | |
13 | import de.uka.ipd.sdq.probfunction.BoxedPDF; |
14 | import de.uka.ipd.sdq.probfunction.ContinuousSample; |
15 | import de.uka.ipd.sdq.probfunction.ProbabilityMassFunction; |
16 | import de.uka.ipd.sdq.probfunction.Sample; |
17 | import de.uka.ipd.sdq.probfunction.math.IProbabilityDensityFunction; |
18 | import de.uka.ipd.sdq.probfunction.math.IProbabilityFunction; |
19 | import de.uka.ipd.sdq.probfunction.math.IProbabilityFunctionFactory; |
20 | import de.uka.ipd.sdq.probfunction.math.IProbabilityMassFunction; |
21 | import de.uka.ipd.sdq.probfunction.print.ProbFunctionPrettyPrint; |
22 | import de.uka.ipd.sdq.probfunction.util.ProbfunctionSwitch; |
23 | import de.uka.ipd.sdq.stoex.Expression; |
24 | |
25 | /** |
26 | * A cache for Probability Functions. This saves the time to calculate the |
27 | * inverse commulative distribution function every time again |
28 | * @author Steffen Becker |
29 | * |
30 | */ |
31 | public class ProbFunctionCache { |
32 | private static Logger logger = |
33 | Logger.getLogger(ProbFunctionCache.class.getName()); |
34 | |
35 | private HashMap<EObject,IProbabilityFunction> probFunctions = new HashMap<EObject,IProbabilityFunction>(); |
36 | |
37 | /** |
38 | * Polymorphic switch to analyse and store probability functions |
39 | */ |
40 | private ProbfunctionSwitch<Object> probFunctionAnnotator = new ProbfunctionSwitch<Object>() { |
41 | @Override |
42 | public Object caseBoxedPDF(BoxedPDF object) { |
43 | adjustPDF(object); |
44 | IProbabilityDensityFunction pdf = null; |
45 | try { |
46 | pdf = IProbabilityFunctionFactory.eINSTANCE.transformToPDF(object); |
47 | pdf.checkConstrains(); |
48 | } catch(Exception ex) { |
49 | RuntimeException ex2 = new RuntimeException("PDF not valid: "+new ProbFunctionPrettyPrint().doSwitch(object)+". Caused by "+ex.getMessage(), ex); |
50 | logger.error("PMF not valid!", ex2); |
51 | throw ex2; |
52 | } |
53 | probFunctions.put(object, pdf); |
54 | return super.caseBoxedPDF(object); |
55 | } |
56 | |
57 | private void adjustPDF(BoxedPDF object) { |
58 | // Adjust PDFs which do not sum up to 1. Issue a warning if needed |
59 | EList<ContinuousSample> samples = object.getSamples(); |
60 | double sum = 0; |
61 | for(ContinuousSample sample : samples) { |
62 | sum += sample.getProbability(); |
63 | } |
64 | if (Math.abs(sum - 1) > 10e-10 ){ |
65 | //Get the problematic PDF as a string so the user can find it. |
66 | String sampleString = "...PDF["; |
67 | for (ContinuousSample continuousSample : samples) { |
68 | sampleString += "("+continuousSample.getValue()+";"+continuousSample.getProbability()+")"; |
69 | } |
70 | sampleString += "]"; |
71 | |
72 | // Adjust wrong PDFs |
73 | double delta = (1 - sum) / countNonZeroContiniousSamples(samples); |
74 | for(ContinuousSample sample : samples) { |
75 | if (sample.getProbability() > 0) |
76 | sample.setProbability(sample.getProbability()+delta); |
77 | } |
78 | |
79 | String sampleStringNew = "...PDF["; |
80 | for (ContinuousSample continuousSample : samples) { |
81 | sampleStringNew += "("+continuousSample.getValue()+";"+continuousSample.getProbability()+")"; |
82 | } |
83 | sampleStringNew += "]"; |
84 | |
85 | logger.warn("Probfunction needed adjustment as it didn't sum up to 1! Fix your input specification!! Was: "+sampleString+", now is: "+sampleStringNew); |
86 | } |
87 | |
88 | } |
89 | |
90 | private double countNonZeroContiniousSamples(EList<ContinuousSample> samples) { |
91 | int count=0; |
92 | for (ContinuousSample s : samples) |
93 | if (s.getProbability()>0) |
94 | count++; |
95 | return count; |
96 | } |
97 | |
98 | private double countNonZeroSamples(EList<Sample> samples) { |
99 | int count=0; |
100 | for (Sample s : samples) |
101 | if (s.getProbability()>0) |
102 | count++; |
103 | return count; |
104 | } |
105 | |
106 | @Override |
107 | public Object caseProbabilityMassFunction(ProbabilityMassFunction object) { |
108 | adjustPMF(object); |
109 | |
110 | IProbabilityMassFunction pmf = IProbabilityFunctionFactory.eINSTANCE.transformToPMF(object); |
111 | try { |
112 | pmf.checkConstrains(); |
113 | } catch(Exception ex) { |
114 | RuntimeException ex2 = new RuntimeException("PMF not valid: "+new ProbFunctionPrettyPrint().doSwitch(object), ex); |
115 | logger.error("PMF not valid!", ex2); |
116 | throw ex2; |
117 | } |
118 | probFunctions.put(object, pmf); |
119 | return super.caseProbabilityMassFunction(object); |
120 | } |
121 | |
122 | private void adjustPMF(ProbabilityMassFunction object) { |
123 | // Adjust wrong PMFs |
124 | EList<Sample> samples = object.getSamples(); |
125 | double sum = 0; |
126 | for(Sample sample : (Collection<Sample>)samples) { |
127 | sum += sample.getProbability(); |
128 | } |
129 | if (Math.abs(sum - 1) > 10e-10 ){ |
130 | double delta = (1 - sum) / countNonZeroSamples(samples); |
131 | for(Sample sample : (Collection<Sample>)samples) { |
132 | if (sample.getProbability() > 0) |
133 | sample.setProbability(sample.getProbability()+delta); |
134 | } |
135 | logger.warn("Probfunction needed adjustment as it didn't sum up to 1! Fix your input specification!!"); |
136 | } |
137 | } |
138 | }; |
139 | |
140 | |
141 | /** |
142 | * Initialise the probfunctition cache for all probfunctions in the |
143 | * given expression. A visitor is used to search for and cache all |
144 | * probfuntions |
145 | * @param ex The stoex to analyse |
146 | */ |
147 | public ProbFunctionCache(Expression ex) { |
148 | for (Iterator<EObject> it=EcoreUtil.getAllContents(Collections.singleton(ex)); |
149 | it.hasNext(); ) { |
150 | probFunctionAnnotator.doSwitch(it.next()); |
151 | } |
152 | } |
153 | |
154 | |
155 | /** |
156 | * Return the cached probfuntion for partial expression e |
157 | * @param e SubExpession which has to be a probfunction literal for |
158 | * which to query the cache |
159 | * @return Cached probfunction |
160 | */ |
161 | public IProbabilityFunction getProbFunction(EObject e) { |
162 | assert probFunctions.containsKey(e); |
163 | return probFunctions.get(e); |
164 | } |
165 | } |