1 | package de.uka.ipd.sdq.stoex.analyser.visitors; |
2 | |
3 | import java.util.ArrayList; |
4 | import java.util.HashMap; |
5 | import java.util.List; |
6 | |
7 | import org.apache.log4j.Logger; |
8 | |
9 | import de.uka.ipd.sdq.probfunction.BoxedPDF; |
10 | import de.uka.ipd.sdq.probfunction.ContinuousSample; |
11 | import de.uka.ipd.sdq.probfunction.ProbabilityDensityFunction; |
12 | import de.uka.ipd.sdq.probfunction.ProbabilityFunction; |
13 | import de.uka.ipd.sdq.probfunction.ProbabilityMassFunction; |
14 | import de.uka.ipd.sdq.probfunction.ProbfunctionFactory; |
15 | import de.uka.ipd.sdq.probfunction.Sample; |
16 | import de.uka.ipd.sdq.probfunction.math.IProbabilityDensityFunction; |
17 | import de.uka.ipd.sdq.probfunction.math.IProbabilityFunctionFactory; |
18 | import de.uka.ipd.sdq.probfunction.math.IProbabilityMassFunction; |
19 | import de.uka.ipd.sdq.probfunction.math.ISample; |
20 | import de.uka.ipd.sdq.probfunction.math.ISamplePDF; |
21 | import de.uka.ipd.sdq.probfunction.math.exception.DifferentDomainsException; |
22 | import de.uka.ipd.sdq.probfunction.math.exception.DomainNotNumbersException; |
23 | import de.uka.ipd.sdq.probfunction.math.exception.DoubleSampleException; |
24 | import de.uka.ipd.sdq.probfunction.math.exception.FunctionNotInTimeDomainException; |
25 | import de.uka.ipd.sdq.probfunction.math.exception.FunctionsInDifferenDomainsException; |
26 | import de.uka.ipd.sdq.probfunction.math.exception.IncompatibleUnitsException; |
27 | import de.uka.ipd.sdq.probfunction.math.exception.ProbabilitySumNotOneException; |
28 | import de.uka.ipd.sdq.probfunction.math.exception.UnknownPDFTypeException; |
29 | import de.uka.ipd.sdq.stoex.BoolLiteral; |
30 | import de.uka.ipd.sdq.stoex.BooleanOperatorExpression; |
31 | import de.uka.ipd.sdq.stoex.CompareExpression; |
32 | import de.uka.ipd.sdq.stoex.DoubleLiteral; |
33 | import de.uka.ipd.sdq.stoex.Expression; |
34 | import de.uka.ipd.sdq.stoex.FunctionLiteral; |
35 | import de.uka.ipd.sdq.stoex.IfElseExpression; |
36 | import de.uka.ipd.sdq.stoex.IntLiteral; |
37 | import de.uka.ipd.sdq.stoex.NotExpression; |
38 | import de.uka.ipd.sdq.stoex.NumericLiteral; |
39 | import de.uka.ipd.sdq.stoex.Parenthesis; |
40 | import de.uka.ipd.sdq.stoex.PowerExpression; |
41 | import de.uka.ipd.sdq.stoex.ProbabilityFunctionLiteral; |
42 | import de.uka.ipd.sdq.stoex.ProductExpression; |
43 | import de.uka.ipd.sdq.stoex.StoexFactory; |
44 | import de.uka.ipd.sdq.stoex.StringLiteral; |
45 | import de.uka.ipd.sdq.stoex.TermExpression; |
46 | import de.uka.ipd.sdq.stoex.Variable; |
47 | import de.uka.ipd.sdq.stoex.analyser.operations.AddOperation; |
48 | import de.uka.ipd.sdq.stoex.analyser.operations.AndOperation; |
49 | import de.uka.ipd.sdq.stoex.analyser.operations.CompareOperation; |
50 | import de.uka.ipd.sdq.stoex.analyser.operations.DivOperation; |
51 | import de.uka.ipd.sdq.stoex.analyser.operations.EqualsOperation; |
52 | import de.uka.ipd.sdq.stoex.analyser.operations.GreaterEqualOperation; |
53 | import de.uka.ipd.sdq.stoex.analyser.operations.GreaterOperation; |
54 | import de.uka.ipd.sdq.stoex.analyser.operations.LessEqualOperation; |
55 | import de.uka.ipd.sdq.stoex.analyser.operations.LessOperation; |
56 | import de.uka.ipd.sdq.stoex.analyser.operations.LogicalOperation; |
57 | import de.uka.ipd.sdq.stoex.analyser.operations.ModOperation; |
58 | import de.uka.ipd.sdq.stoex.analyser.operations.MultOperation; |
59 | import de.uka.ipd.sdq.stoex.analyser.operations.NotEqualOperation; |
60 | import de.uka.ipd.sdq.stoex.analyser.operations.OrOperation; |
61 | import de.uka.ipd.sdq.stoex.analyser.operations.SubOperation; |
62 | import de.uka.ipd.sdq.stoex.analyser.operations.TermProductOperation; |
63 | import de.uka.ipd.sdq.stoex.analyser.probfunction.ProbfunctionHelper; |
64 | import de.uka.ipd.sdq.stoex.util.StoexSwitch; |
65 | |
66 | /** |
67 | * A visitor for stochastic expressions, which evaluates |
68 | * the operations within a expression and returns the |
69 | * resulting expression, which does not contain any operation |
70 | * any more. |
71 | * For example, when a stochastic expression contains a |
72 | * division operation between a INT_PMF and a constant it |
73 | * returns an INT_PMF divided by the constant. |
74 | * The visitor is invoked as usual via the |
75 | * doSwitch(Expression toSolve) command. It returns the solved |
76 | * expression. |
77 | * This class uses the operations in |
78 | * de.uka.ipd.sdq.stoex.analyser.operations as an interface |
79 | * to the probability function package. |
80 | * |
81 | * @author koziolek |
82 | */ |
83 | public class ExpressionSolveVisitor extends StoexSwitch<Object> { |
84 | |
85 | private static Logger logger = Logger |
86 | .getLogger(ExpressionSolveVisitor.class.getName()); |
87 | |
88 | /** |
89 | * For the Trunc function with a DoublePDF parameter, the DoublePDF is |
90 | * transformed into an IntPMF. Here, a sample is generated for each |
91 | * integer lying in the range of the DoublePDF. This can easily cause an |
92 | * OutOfMemoryException, thus, we constraint the maximum number of samples here. |
93 | * Then, only each e.g. third integer value is used if the interval is too large |
94 | */ |
95 | private static final int MAX_NUMBER_OF_SAMPLES_FOR_TRUNC =1000; |
96 | |
97 | protected IProbabilityFunctionFactory iProbFuncFactory = |
98 | IProbabilityFunctionFactory.eINSTANCE; |
99 | |
100 | protected ProbfunctionFactory probFuncFactory = ProbfunctionFactory.eINSTANCE; |
101 | |
102 | protected StoexFactory stocFactory = StoexFactory.eINSTANCE; |
103 | |
104 | protected HashMap<Expression, TypeEnum> typeAnnotation; |
105 | |
106 | /** |
107 | * Constructor storing the evaluated type annotations. |
108 | * @param typeAnn |
109 | */ |
110 | public ExpressionSolveVisitor(HashMap<Expression, TypeEnum> typeAnn) { |
111 | this.typeAnnotation = typeAnn; |
112 | } |
113 | |
114 | /** |
115 | * Performs compare operations. |
116 | */ |
117 | public Object caseCompareExpression(CompareExpression expr){ |
118 | String opName = expr.getOperation().getName(); |
119 | CompareOperation op; |
120 | if (opName.equals("GREATER")) |
121 | op = new GreaterOperation(); |
122 | else if(opName.equals("EQUALS")) |
123 | op = new EqualsOperation(); |
124 | else if(opName.equals("LESS")) |
125 | op = new LessOperation(); |
126 | else if(opName.equals("NOTEQUAL")) |
127 | op = new NotEqualOperation(); |
128 | else if(opName.equals("GREATEREQUAL")) |
129 | op = new GreaterEqualOperation(); |
130 | else if(opName.equals("LESSEQUAL")) |
131 | op = new LessEqualOperation(); |
132 | else |
133 | throw new UnsupportedOperationException(); |
134 | |
135 | Expression left = (Expression) doSwitch(expr.getLeft()); |
136 | Expression right = (Expression) doSwitch(expr.getRight()); |
137 | |
138 | return handleComparison(left, right, op); |
139 | } |
140 | |
141 | /** |
142 | * Performs logical operations (AND, OR). |
143 | */ |
144 | public Object caseBooleanOperatorExpression(BooleanOperatorExpression expr) { |
145 | |
146 | String opName = expr.getOperation().getName(); |
147 | LogicalOperation op; |
148 | if (opName.equals("AND")) |
149 | op = new AndOperation(); |
150 | else if(opName.equals("OR")) |
151 | op = new OrOperation(); |
152 | else |
153 | throw new UnsupportedOperationException(); |
154 | |
155 | Expression left = (Expression) doSwitch(expr.getLeft()); |
156 | Expression right = (Expression) doSwitch(expr.getRight()); |
157 | |
158 | return handleLogical(left, right, op); |
159 | } |
160 | |
161 | /** |
162 | * Performs term operations (ADD, SUB) |
163 | */ |
164 | public Object caseTermExpression(TermExpression expr) { |
165 | String opName = expr.getOperation().getName(); |
166 | TermProductOperation op; |
167 | if (opName.equals("ADD")) |
168 | op = new AddOperation(); |
169 | else if (opName.equals("SUB")) |
170 | op = new SubOperation(); |
171 | else |
172 | throw new UnsupportedOperationException(); |
173 | |
174 | Expression left = (Expression) doSwitch(expr.getLeft()); |
175 | Expression right = (Expression) doSwitch(expr.getRight()); |
176 | TypeEnum exprType = this.typeAnnotation.get(expr); |
177 | |
178 | return handleComputation(exprType, left, right, op); |
179 | } |
180 | |
181 | /** |
182 | * Performs product operations (MULT, DIV, MOD). |
183 | */ |
184 | public Object caseProductExpression(ProductExpression expr) { |
185 | String opName = expr.getOperation().getName(); |
186 | TermProductOperation op; |
187 | if (opName.equals("MULT")) |
188 | op = new MultOperation(); |
189 | else if (opName.equals("DIV")) |
190 | op = new DivOperation(); |
191 | else if (opName.equals("MOD")) |
192 | op = new ModOperation(); |
193 | else |
194 | throw new UnsupportedOperationException(); |
195 | |
196 | Expression left = (Expression) doSwitch(expr.getLeft()); |
197 | Expression right = (Expression) doSwitch(expr.getRight()); |
198 | TypeEnum exprType = this.typeAnnotation.get(expr); |
199 | |
200 | |
201 | return handleComputation(exprType, left, right, op); |
202 | } |
203 | |
204 | @Override |
205 | public Object caseIfElseExpression(IfElseExpression expr) { |
206 | |
207 | // first get the probability function from the condition expression and determine the if-probability |
208 | ProbabilityFunctionLiteral conditionExpr = (ProbabilityFunctionLiteral) doSwitch(expr.getConditionExpression()); |
209 | ProbabilityMassFunction pmf = (ProbabilityMassFunction)conditionExpr.getFunction_ProbabilityFunctionLiteral(); |
210 | |
211 | double ifProb = 1.0; |
212 | List<Sample> points = pmf.getSamples(); |
213 | for (Sample point : points) { |
214 | String bool = point.getValue().toString(); |
215 | if (bool.toLowerCase().equals("true")) { |
216 | ifProb = point.getProbability(); |
217 | } |
218 | } |
219 | |
220 | // now build a new DoublePMF to replace the IfElseExpression |
221 | Expression ifExpr = (Expression) doSwitch(expr.getIfExpression()); |
222 | Expression elseExpr = (Expression) doSwitch(expr.getElseExpression()); |
223 | |
224 | if (ifExpr instanceof NumericLiteral && elseExpr instanceof NumericLiteral){ |
225 | // we only support NumericLiterals here, i.e., INT or DOUBLE. |
226 | List<ISample> newPoints = new ArrayList<ISample>(); |
227 | double ifValue = getDoubleFromNumericLiteral(ifExpr); |
228 | newPoints.add(iProbFuncFactory.createSample(ifValue, ifProb)); |
229 | double elseValue = getDoubleFromNumericLiteral(elseExpr); |
230 | newPoints.add(iProbFuncFactory.createSample(elseValue, 1-ifProb)); |
231 | |
232 | IProbabilityMassFunction iPMF = iProbFuncFactory.createProbabilityMassFunction(newPoints, null, false); |
233 | ProbabilityMassFunction resultPMF = iProbFuncFactory.transformToModelPMF(iPMF); |
234 | ProbabilityFunctionLiteral resultPMFLiteral = stocFactory.createProbabilityFunctionLiteral(); |
235 | resultPMFLiteral.setFunction_ProbabilityFunctionLiteral(resultPMF); |
236 | return resultPMFLiteral; |
237 | } else |
238 | // any probability functions involved are not supported: |
239 | throw new UnsupportedOperationException(); |
240 | } |
241 | |
242 | /** |
243 | * Forwards the visitor to the inner expression within the parenthesis. |
244 | */ |
245 | public Object caseParenthesis(Parenthesis parenthesis) { |
246 | Expression child = (Expression)doSwitch(parenthesis.getInnerExpression()); |
247 | return child; |
248 | } |
249 | |
250 | /** |
251 | * Skips variables. This visitor cannot handle variables. Use the |
252 | * PCM Solver to handle variables in stochastic expressions. |
253 | */ |
254 | public Object caseVariable(Variable var){ |
255 | // Cannot handle variables! Use inheritance to add this. |
256 | return var; |
257 | } |
258 | |
259 | /** |
260 | * Creates a BoolPMF for the given BoolLiteral. |
261 | */ |
262 | public Object caseBoolLiteral(BoolLiteral bl) { |
263 | EqualsOperation eo = new EqualsOperation(); |
264 | IProbabilityMassFunction iPMF = null; |
265 | if (bl.isValue()){ |
266 | iPMF = eo.getBoolPMF(1.0); |
267 | } else { |
268 | iPMF = eo.getBoolPMF(0.0); |
269 | } |
270 | return createLiteralForIPMF(iPMF); |
271 | } |
272 | |
273 | /** |
274 | * Just returns the given int literal. |
275 | */ |
276 | public Object caseIntLiteral(IntLiteral il) { |
277 | return il; |
278 | } |
279 | |
280 | /** |
281 | * Just returns the given double literal. |
282 | */ |
283 | public Object caseDoubleLiteral(DoubleLiteral dl) { |
284 | return dl; |
285 | } |
286 | |
287 | |
288 | @Override |
289 | public Object caseStringLiteral(StringLiteral object) { |
290 | // TODO Auto-generated method stub |
291 | return object; |
292 | } |
293 | |
294 | /** |
295 | * Just returns the given probfunction literal. |
296 | */ |
297 | public Object caseProbabilityFunctionLiteral( |
298 | ProbabilityFunctionLiteral probFuncLit) { |
299 | return probFuncLit; |
300 | } |
301 | |
302 | /** |
303 | * Performs a power operation (only for constants). |
304 | */ |
305 | public Object casePowerExpression(PowerExpression expr) { |
306 | Expression base = (Expression) doSwitch(expr.getBase()); |
307 | Expression exponent = (Expression) doSwitch(expr.getExponent()); |
308 | |
309 | double baseValue = getDoubleFromNumericLiteral(base); |
310 | double exponentValue = getDoubleFromNumericLiteral(exponent); |
311 | |
312 | DoubleLiteral doubleLiteral = StoexFactory.eINSTANCE.createDoubleLiteral(); |
313 | doubleLiteral.setValue(Math.pow(baseValue, exponentValue)); |
314 | |
315 | return doubleLiteral; |
316 | } |
317 | |
318 | @Override |
319 | public ProbabilityFunctionLiteral caseFunctionLiteral(FunctionLiteral object) { |
320 | for (Expression e : object.getParameters_FunctionLiteral()) |
321 | doSwitch(e); |
322 | |
323 | List<Expression> parameterList = new ArrayList<Expression>(); |
324 | for (Expression parameter : object.getParameters_FunctionLiteral()) { |
325 | parameterList.add((Expression)doSwitch(parameter)); |
326 | } |
327 | |
328 | if (ProbfunctionHelper.isFunctionID(object.getId())){ |
329 | ProbabilityFunction func = ProbfunctionHelper.createFunction(parameterList, object.getId(), probFuncFactory); |
330 | ProbabilityFunctionLiteral literal = StoexFactory.eINSTANCE.createProbabilityFunctionLiteral(); |
331 | literal.setFunction_ProbabilityFunctionLiteral(func); |
332 | return literal; |
333 | } else if (object.getId().equals("Trunc")) { |
334 | //Create an equivalent ProbabilityMassFunction or Integer from the given expression. |
335 | |
336 | //Trunc must only have one parameter |
337 | if (object.getParameters_FunctionLiteral().size() == 1){ |
338 | Expression solvedParam = parameterList.get(0); |
339 | //Parameter for Trunc must can be a DoublePDF or a DoubleLiteral? |
340 | if (solvedParam instanceof ProbabilityFunctionLiteral){ |
341 | ProbabilityFunctionLiteral pfl = (ProbabilityFunctionLiteral)solvedParam; |
342 | ProbabilityFunction insideFunction = pfl.getFunction_ProbabilityFunctionLiteral(); |
343 | if (insideFunction instanceof BoxedPDF){ |
344 | //create a ProbabilityMassFunction for this BoxedPDF |
345 | return truncPMFFromBoxedPDF((BoxedPDF)insideFunction, object); |
346 | } |
347 | } else if (solvedParam instanceof DoubleLiteral) { |
348 | IntLiteral intLit = StoexFactory.eINSTANCE.createIntLiteral(); |
349 | intLit.setValue((int)Math.round(((DoubleLiteral)solvedParam).getValue())); |
350 | } else |
351 | throw new ExpressionSolvingFailedException("Function Trunc is only supported supported for a DoublePDF or a single double parameter!", object); |
352 | } |
353 | } else |
354 | throw new UnsupportedOperationException("Function "+object.getId()+" not supported!"); |
355 | return null; |
356 | } |
357 | |
358 | /** |
359 | * Returns the result of interpreting the object as an instance of '<em>Not Expression</em>'. |
360 | * <!-- begin-user-doc --> |
361 | * This implementation casts the result of its inner expression to boolean and returns the |
362 | * resulting values. If it cannot be cast to Boolean or BoolPMF, an exception is thrown. |
363 | * <!-- end-user-doc --> |
364 | * @param notExpression the target of the switch. |
365 | * @return the result of interpreting the object as an instance of '<em>Not Expression</em>'. |
366 | * @see #doSwitch(org.eclipse.emf.ecore.EObject) doSwitch(EObject) |
367 | * @generated |
368 | */ |
369 | @Override |
370 | public Object caseNotExpression(NotExpression notExpression) { |
371 | Expression child = (Expression)doSwitch(notExpression.getInner()); |
372 | |
373 | if (child instanceof ProbabilityFunctionLiteral){ |
374 | IProbabilityMassFunction massFunction = extractIPMFFromLiteral(child); |
375 | IProbabilityMassFunction invertedFunction = CompareOperation.invertBoolPMF(massFunction); |
376 | return createLiteralForIPMF(invertedFunction); |
377 | |
378 | } else { |
379 | throw new UnsupportedComputationException(notExpression, "NOT"); |
380 | } |
381 | |
382 | } |
383 | |
384 | |
385 | /** |
386 | * Converts a PDF to an IntPMF for the Trunc function. This is just a rough estimates. Especially for small values, it is far from the original. |
387 | * |
388 | * The Boundaries of the PDF are rounded down to the next integer. Then, the possible integer values are evenly distributed with the probability of the respective ContinousSample. |
389 | * If no integer value exists between two ContinousSamples, their probabilities are added. |
390 | * |
391 | * In this way, the distribution is changed a lot for small values. For large values, it does not matter. |
392 | * |
393 | * If the range of the whole PDF is too small, the closest surrounding integers is used with probability one. |
394 | * |
395 | * Maybe this should be moved in the probfunction package. |
396 | * |
397 | * @param pdf |
398 | * @param object |
399 | * @return |
400 | */ |
401 | @SuppressWarnings("unchecked") |
402 | private ProbabilityFunctionLiteral truncPMFFromBoxedPDF(BoxedPDF pdf, FunctionLiteral object) { |
403 | |
404 | List<ContinuousSample> samples = pdf.getSamples(); |
405 | |
406 | if (samples.size() == 0){ |
407 | throw new ExpressionSolvingFailedException("Cannot handle an empty DoublePDF for Trunc.",object); |
408 | } |
409 | double leftBorder = samples.get(0).getProbability() > 0 ? samples.get(0).getValue() : 0; |
410 | int range = (int)Math.ceil(samples.get(samples.size()-1).getValue() - leftBorder); |
411 | |
412 | int distance = range / MAX_NUMBER_OF_SAMPLES_FOR_TRUNC + 1; |
413 | |
414 | ISamplePDF samplePDF = null; |
415 | try { |
416 | samplePDF = iProbFuncFactory.transformToSamplePDF(iProbFuncFactory.transformToPDF(pdf),distance); |
417 | } catch (Exception e) { |
418 | throw new ExpressionSolvingFailedException(object, e); |
419 | } |
420 | |
421 | if (samplePDF.getLowerDomainBorder() < 0){ |
422 | throw new ExpressionSolvingFailedException("Cannot Trunc a DoublePDF with negative values.",object); |
423 | } |
424 | if (samplePDF.getDistance() != distance){ |
425 | throw new ExpressionSolvingFailedException("Bug! Distance of SamplePDF is not "+distance, object); |
426 | } |
427 | |
428 | ProbabilityMassFunction pmf = this.probFuncFactory.createProbabilityMassFunction(); |
429 | |
430 | pmf.setOrderedDomain(true); |
431 | List<Double> probabilities = samplePDF.getValuesAsDouble(); |
432 | |
433 | //TODO: There is a bug in the probfunction stuff |
434 | // input Trunc(DoublePDF[ (0.2; 0.30000000) (1.7; 0.20000000) (2.7; 0.50000000) ]) |
435 | // results in IntPMF[ (0;1.0899999999999999) (1;0.13333333333333333) (2;0.4266666666666666) (3;0.10000000000000006) ] |
436 | // not too bad, but wrong. |
437 | int numberOfSamples = samplePDF.numberOfSamples(); |
438 | for (int i = 0; i < numberOfSamples; i++){ |
439 | Sample sample = this.probFuncFactory.createSample(); |
440 | sample.setProbability(probabilities.get(i)); |
441 | sample.setValue(i*distance); |
442 | pmf.getSamples().add(sample); |
443 | } |
444 | |
445 | ProbabilityFunctionLiteral literal = StoexFactory.eINSTANCE.createProbabilityFunctionLiteral(); |
446 | literal.setFunction_ProbabilityFunctionLiteral(pmf); |
447 | |
448 | logger.debug("Trunc result: "+new StoExPrettyPrintVisitor().prettyPrint(literal)); |
449 | |
450 | return literal; |
451 | } |
452 | |
453 | /** |
454 | * @param base |
455 | */ |
456 | private double getDoubleFromNumericLiteral(Expression base) { |
457 | |
458 | if (base instanceof IntLiteral){ |
459 | IntLiteral intLiteral = (IntLiteral)base; |
460 | Integer intValue = intLiteral.getValue(); |
461 | return intValue.doubleValue(); |
462 | } else if (base instanceof DoubleLiteral){ |
463 | DoubleLiteral doubleLiteral = (DoubleLiteral)base; |
464 | return doubleLiteral.getValue(); |
465 | } else |
466 | throw new UnsupportedOperationException(); |
467 | } |
468 | |
469 | /** |
470 | * @param left |
471 | * @param right |
472 | * @param op |
473 | * @return |
474 | */ |
475 | private Object handleComparison(Expression left, Expression right, |
476 | CompareOperation op) { |
477 | IProbabilityMassFunction iPMF = null; |
478 | |
479 | if (isIntDouble(left) && isIntDouble(right)) |
480 | iPMF = op.compare(extractDoubleFromLiteral(left), |
481 | extractDoubleFromLiteral(right)); |
482 | else if (isProbFunc(left) && isIntDouble(right)) |
483 | iPMF = op.compare(extractIPMFFromLiteral(left), |
484 | extractDoubleFromLiteral(right)); |
485 | else if (isIntDouble(left) && isProbFunc(right)) |
486 | iPMF = op.compare(extractDoubleFromLiteral(left), |
487 | extractIPMFFromLiteral(right)); |
488 | else if (isProbFunc(left) && isProbFunc(right)) |
489 | iPMF = op.compare(extractIPMFFromLiteral(left), |
490 | extractIPMFFromLiteral(right)); |
491 | else if (isString(left) && isString(right)) |
492 | iPMF = op.compare(extractStringFromLiteral(left), |
493 | extractStringFromLiteral(right)); |
494 | else if (isString(left) && isProbFunc(right)) |
495 | iPMF = op.compare(extractStringFromLiteral(left), |
496 | extractIPMFFromLiteral(right)); |
497 | else if (isString(right) && isProbFunc(left)) |
498 | iPMF = op.compare(extractStringFromLiteral(right), |
499 | extractIPMFFromLiteral(left)); |
500 | else |
501 | throw new UnsupportedOperationException(); |
502 | |
503 | return createLiteralForIPMF(iPMF); |
504 | } |
505 | |
506 | private Object handleLogical(Expression left, Expression right, |
507 | LogicalOperation op) { |
508 | IProbabilityMassFunction iPMF = null; |
509 | if (isProbFunc(left) && isProbFunc(right)) |
510 | iPMF = op.evaluate(extractIPMFFromLiteral(left), |
511 | extractIPMFFromLiteral(right)); |
512 | else |
513 | throw new UnsupportedOperationException(); |
514 | |
515 | return createLiteralForIPMF(iPMF); |
516 | } |
517 | |
518 | private String extractStringFromLiteral(Expression left) { |
519 | return ((StringLiteral)left).getValue(); |
520 | } |
521 | |
522 | private boolean isString(Expression expr) { |
523 | return expr instanceof StringLiteral; |
524 | } |
525 | |
526 | /** |
527 | * @param expr |
528 | * @param op |
529 | * @return |
530 | * @throws ProbabilitySumNotOneException |
531 | */ |
532 | private Expression handleComputation(TypeEnum exprType, Expression left, |
533 | Expression right, TermProductOperation op) { |
534 | |
535 | if (exprType == TypeEnum.ANY_PMF){ |
536 | if (left instanceof ProbabilityFunctionLiteral){ |
537 | exprType = resolveActualType(exprType, left); |
538 | } else if (right instanceof ProbabilityFunctionLiteral){ |
539 | exprType = resolveActualType(exprType, right); |
540 | } else if (left instanceof FunctionLiteral){ |
541 | exprType = ProbfunctionHelper.isFunctionID(((FunctionLiteral)left).getId()) ? TypeEnum.CONTINOUS_PROBFUNCTION : TypeEnum.AUX_FUNCTION; |
542 | } else if (right instanceof FunctionLiteral){ |
543 | exprType = ProbfunctionHelper.isFunctionID(((FunctionLiteral)right).getId()) ? TypeEnum.CONTINOUS_PROBFUNCTION : TypeEnum.AUX_FUNCTION; |
544 | } else if (left instanceof IntLiteral && right instanceof IntLiteral){ |
545 | //both are integers |
546 | exprType = TypeEnum.INT; |
547 | } else if (left instanceof NumericLiteral && right instanceof NumericLiteral){ |
548 | //both are double, or one is int, the other double. |
549 | exprType = TypeEnum.DOUBLE; |
550 | } else |
551 | throw new UnsupportedComputationException(right, left, op, exprType); |
552 | } |
553 | |
554 | switch (exprType) { |
555 | case INT: |
556 | return handle(extractIntFromLiteral(left), |
557 | extractIntFromLiteral(right), op); |
558 | case DOUBLE: |
559 | return handle(extractDoubleFromLiteral(left), |
560 | extractDoubleFromLiteral(right), op); |
561 | case ANY_PMF: |
562 | throw new UnsupportedComputationException(right, left, op, exprType); |
563 | case INT_PMF: |
564 | if (left instanceof IntLiteral && right instanceof IntLiteral){ |
565 | // this case can happen because the |
566 | // typeAnnotation assumes INT_PMF as type |
567 | // for some parameter characterisations |
568 | // where in fact they could be composed just out |
569 | // of INTs in an expression |
570 | return handle(extractIntFromLiteral(left), |
571 | extractIntFromLiteral(right), op); |
572 | } else if (left instanceof IntLiteral |
573 | && right instanceof ProbabilityFunctionLiteral) { |
574 | return handle(extractIPMFFromLiteral(right),extractIntFromLiteral(left), op); |
575 | } else if (left instanceof ProbabilityFunctionLiteral |
576 | && right instanceof IntLiteral) { |
577 | return handle(extractIPMFFromLiteral(left),extractIntFromLiteral(right), op); |
578 | } else if (left instanceof ProbabilityFunctionLiteral |
579 | && right instanceof ProbabilityFunctionLiteral) { |
580 | return handle(extractIPMFFromLiteral(left),extractIPMFFromLiteral(right), op); |
581 | } else |
582 | throw new UnsupportedComputationException(right, left, op, exprType); |
583 | case DOUBLE_PMF: |
584 | if (left instanceof NumericLiteral && right instanceof NumericLiteral) { |
585 | return handle(extractDoubleFromLiteral(left), extractDoubleFromLiteral(right), op); |
586 | } else if(left instanceof ProbabilityFunctionLiteral |
587 | && right instanceof NumericLiteral){ |
588 | return handle(extractIPMFFromLiteral(left),extractDoubleFromLiteral(right), op); |
589 | } else if(left instanceof NumericLiteral |
590 | && right instanceof ProbabilityFunctionLiteral){ |
591 | return handle(extractIPMFFromLiteral(right),extractDoubleFromLiteral(left), op); |
592 | } else if(left instanceof ProbabilityFunctionLiteral |
593 | && right instanceof ProbabilityFunctionLiteral){ |
594 | return handle(extractIPMFFromLiteral(left), extractIPMFFromLiteral(right), op); |
595 | } else |
596 | throw new UnsupportedComputationException(right, left, op, exprType); |
597 | case DOUBLE_PDF: |
598 | if (left instanceof ProbabilityFunctionLiteral){ |
599 | if (right instanceof IntLiteral){ |
600 | return handle(extractIPDFFromLiteral(left), extractIntFromLiteral(right), op); |
601 | } else if (right instanceof DoubleLiteral){ |
602 | return handle(extractIPDFFromLiteral(left), extractDoubleFromLiteral(right), op); |
603 | } else if (right instanceof ProbabilityFunctionLiteral){ |
604 | return handle(extractIPDFFromLiteral(left),extractIPDFFromLiteral(right), op); |
605 | } else |
606 | throw new UnsupportedComputationException(right, left, op, exprType); |
607 | } else if (right instanceof ProbabilityFunctionLiteral){ |
608 | if (left instanceof IntLiteral){ |
609 | return handle(extractIPDFFromLiteral(right), extractIntFromLiteral(left), op); |
610 | } else if (left instanceof DoubleLiteral){ |
611 | return handle(extractIPDFFromLiteral(right), extractDoubleFromLiteral(left), op); |
612 | } else |
613 | throw new UnsupportedComputationException(right, left, op, exprType); |
614 | } else |
615 | throw new UnsupportedComputationException(right, left, op, exprType); |
616 | case CONTINOUS_PROBFUNCTION: |
617 | if (left instanceof FunctionLiteral){ |
618 | if (right instanceof IntLiteral) { |
619 | double rightDouble = ((IntLiteral)right).getValue(); |
620 | return handle(extractIPDFFromLiteral(caseFunctionLiteral((FunctionLiteral) left)),rightDouble, op); |
621 | } else if (right instanceof DoubleLiteral){ |
622 | double rightDouble = ((DoubleLiteral)right).getValue(); |
623 | return handle(extractIPDFFromLiteral(caseFunctionLiteral((FunctionLiteral) left)),rightDouble, op); |
624 | } else throw new UnsupportedOperationException("I can only apply operation "+op.getClass().getName()+" to a function and an number, not more."); |
625 | } if (right instanceof FunctionLiteral){ |
626 | if (left instanceof IntLiteral){ |
627 | double leftDouble = ((IntLiteral)left).getValue(); |
628 | return handle(extractIPDFFromLiteral(caseFunctionLiteral((FunctionLiteral) right)),leftDouble, op); |
629 | } else if (left instanceof DoubleLiteral){ |
630 | double leftDouble = ((DoubleLiteral)left).getValue(); |
631 | return handle(extractIPDFFromLiteral(caseFunctionLiteral((FunctionLiteral) right)),leftDouble, op); |
632 | } else throw new UnsupportedOperationException("I can only apply operation "+op.getClass().getName()+" to a function and an number, not more."); |
633 | } else throw new UnsupportedComputationException(right, left, op, exprType); |
634 | case AUX_FUNCTION: |
635 | //TODO: |
636 | throw new UnsupportedOperationException("It is not yet supported to do calculations with auxiliary functions."); |
637 | |
638 | } |
639 | return null; |
640 | |
641 | } |
642 | |
643 | private TypeEnum getFunctionType(Expression right) { |
644 | // TODO Auto-generated method stub |
645 | return null; |
646 | } |
647 | |
648 | private Expression handle(IProbabilityDensityFunction iLeftPDF, double right, TermProductOperation op) { |
649 | IProbabilityDensityFunction resultIPDF = null; |
650 | |
651 | try { |
652 | resultIPDF = op.compute(iLeftPDF, right); |
653 | } catch (DomainNotNumbersException e) { |
654 | logger.error("Calculation with PDF and Literal failed!"); |
655 | e.printStackTrace(); |
656 | } |
657 | return createLiteralForIPDF(resultIPDF); |
658 | } |
659 | |
660 | /** |
661 | * @param exprType |
662 | * @param expr |
663 | * @return |
664 | */ |
665 | private TypeEnum resolveActualType(TypeEnum exprType, Expression expr) { |
666 | ProbabilityFunctionLiteral pfl = (ProbabilityFunctionLiteral)expr; |
667 | ProbabilityFunction probFunc = pfl.getFunction_ProbabilityFunctionLiteral(); |
668 | |
669 | if (probFunc instanceof ProbabilityMassFunction){ |
670 | IProbabilityMassFunction iPMF = extractIPMFFromLiteral(expr); |
671 | ISample samplePoint = iPMF.getSamples().get(0); |
672 | |
673 | if (samplePoint.getValue() instanceof Integer){ |
674 | exprType = TypeEnum.INT_PMF; |
675 | } else if (samplePoint.getValue() instanceof Double){ |
676 | exprType = TypeEnum.DOUBLE_PMF; |
677 | } |
678 | return exprType; |
679 | } else if (probFunc instanceof ProbabilityDensityFunction){ |
680 | return TypeEnum.DOUBLE_PDF; |
681 | } else |
682 | throw new UnsupportedOperationException(); |
683 | |
684 | } |
685 | |
686 | /** |
687 | * @param iLeftPDF |
688 | * @param iRightPDF |
689 | * @param op |
690 | * @return |
691 | */ |
692 | private Expression handle(IProbabilityDensityFunction iLeftPDF, IProbabilityDensityFunction iRightPDF, TermProductOperation op) { |
693 | IProbabilityDensityFunction resultIPDF = null; |
694 | |
695 | try { |
696 | resultIPDF = op.compute(iLeftPDF, iRightPDF); |
697 | } catch (FunctionsInDifferenDomainsException e){ |
698 | logger.error("Calculation with two PDFs failed!"); |
699 | e.printStackTrace(); |
700 | } catch (UnknownPDFTypeException e){ |
701 | logger.error("Calculation with two PDFs failed!"); |
702 | e.printStackTrace(); |
703 | } catch (IncompatibleUnitsException e){ |
704 | logger.error("Calculation with two PDFs failed!"); |
705 | e.printStackTrace(); |
706 | } |
707 | //logger.debug("Result: "+resultIPDF.toString()); |
708 | |
709 | return createLiteralForIPDF(resultIPDF); |
710 | |
711 | } |
712 | |
713 | /** |
714 | * @param resultIPMF |
715 | * @return |
716 | */ |
717 | private ProbabilityFunctionLiteral createLiteralForIPMF( |
718 | IProbabilityMassFunction resultIPMF) { |
719 | ProbabilityMassFunction resultPMF = iProbFuncFactory |
720 | .transformToModelPMF(resultIPMF); |
721 | ProbabilityFunctionLiteral resultPMFLiteral = stocFactory |
722 | .createProbabilityFunctionLiteral(); |
723 | resultPMFLiteral.setFunction_ProbabilityFunctionLiteral(resultPMF); |
724 | |
725 | return resultPMFLiteral; |
726 | } |
727 | |
728 | /** |
729 | * @param iPDF |
730 | * @return |
731 | */ |
732 | private Expression createLiteralForIPDF(IProbabilityDensityFunction iPDF) { |
733 | ProbabilityDensityFunction pdf = null; |
734 | try { |
735 | pdf = iProbFuncFactory.transformToModelPDF(iPDF); |
736 | } catch (UnknownPDFTypeException e) { |
737 | e.printStackTrace(); |
738 | } catch (DoubleSampleException e) { |
739 | e.printStackTrace(); |
740 | } catch (FunctionNotInTimeDomainException e) { |
741 | e.printStackTrace(); |
742 | } |
743 | |
744 | ProbabilityFunctionLiteral resultPDFLiteral = stocFactory.createProbabilityFunctionLiteral(); |
745 | resultPDFLiteral.setFunction_ProbabilityFunctionLiteral(pdf); |
746 | |
747 | return resultPDFLiteral; |
748 | } |
749 | |
750 | /** |
751 | * @param iLeftPMF |
752 | * @param iRightPMF |
753 | * @param operation |
754 | * @return |
755 | */ |
756 | private ProbabilityFunctionLiteral handle(IProbabilityMassFunction iLeftPMF, |
757 | IProbabilityMassFunction iRightPMF, TermProductOperation operation) { |
758 | IProbabilityMassFunction resultIPMF = null; |
759 | try { |
760 | resultIPMF = operation.compute(iLeftPMF, iRightPMF); |
761 | } catch (DifferentDomainsException e) { |
762 | logger.error("Calculation with two PMFs failed!"); |
763 | e.printStackTrace(); |
764 | throw new RuntimeException(e); |
765 | } |
766 | //logger.debug("Result: "+resultIPMF.getSamples().toString()); |
767 | return createLiteralForIPMF(resultIPMF); |
768 | } |
769 | |
770 | |
771 | /** |
772 | * @param iIntPMF |
773 | * @param doubleValue |
774 | * @param operation |
775 | * @return |
776 | */ |
777 | private ProbabilityFunctionLiteral handle(IProbabilityMassFunction iIntPMF, |
778 | double doubleValue, TermProductOperation operation) { |
779 | IProbabilityMassFunction resultIPMF = null; |
780 | try { |
781 | resultIPMF = operation.compute(iIntPMF, doubleValue); |
782 | } catch (Exception e) { |
783 | logger.error("Calculation with PMF and int failed!"); |
784 | e.printStackTrace(); |
785 | } |
786 | //logger.debug("Result: "+resultIPMF.getSamples().toString()); |
787 | return createLiteralForIPMF(resultIPMF); |
788 | } |
789 | |
790 | |
791 | /** |
792 | * @param leftValue |
793 | * @param rightValue |
794 | * @param operation |
795 | * @return |
796 | */ |
797 | private DoubleLiteral handle(double leftValue, double rightValue, |
798 | TermProductOperation operation) { |
799 | DoubleLiteral result = stocFactory.createDoubleLiteral(); |
800 | double resultValue = operation.compute(leftValue, rightValue); |
801 | result.setValue(resultValue); |
802 | return result; |
803 | } |
804 | |
805 | |
806 | /** |
807 | * @param leftValue |
808 | * @param rightValue |
809 | * @param operation |
810 | * @return |
811 | */ |
812 | private IntLiteral handle(int leftValue, int rightValue, |
813 | TermProductOperation operation) { |
814 | IntLiteral result = stocFactory.createIntLiteral(); |
815 | int resultValue = operation.compute(leftValue, rightValue); |
816 | result.setValue(resultValue); |
817 | return result; |
818 | } |
819 | |
820 | /** |
821 | * @param expr |
822 | * @return |
823 | */ |
824 | private boolean isProbFunc(Expression expr) { |
825 | return (expr instanceof ProbabilityFunctionLiteral); |
826 | } |
827 | |
828 | /** |
829 | * @param expr |
830 | * @return |
831 | */ |
832 | private boolean isIntDouble(Expression expr) { |
833 | return (expr instanceof IntLiteral || expr instanceof DoubleLiteral); |
834 | } |
835 | |
836 | /** |
837 | * @param expr |
838 | * @return |
839 | */ |
840 | private double extractDoubleFromLiteral(Expression expr) { |
841 | if (expr instanceof IntLiteral) { |
842 | return (double) ((IntLiteral) expr).getValue(); |
843 | } else if (expr instanceof DoubleLiteral) { |
844 | return (double) ((DoubleLiteral) expr).getValue(); |
845 | } else { |
846 | logger.error("Could not get Double value from NumericLiteral!"); |
847 | return 0.0; |
848 | } |
849 | } |
850 | |
851 | /** |
852 | * @param expr |
853 | * @return |
854 | */ |
855 | private int extractIntFromLiteral(Expression expr) { |
856 | return ((IntLiteral) expr).getValue(); |
857 | } |
858 | |
859 | /** |
860 | * @param expr |
861 | * @return |
862 | */ |
863 | private IProbabilityMassFunction extractIPMFFromLiteral(Expression expr) { |
864 | ProbabilityFunctionLiteral probFuncLiteral = (ProbabilityFunctionLiteral)expr; |
865 | ProbabilityFunction function = probFuncLiteral.getFunction_ProbabilityFunctionLiteral(); |
866 | if (function instanceof ProbabilityMassFunction){ |
867 | ProbabilityMassFunction pmf = (ProbabilityMassFunction)function; |
868 | return iProbFuncFactory.transformToPMF(pmf); |
869 | } else if (function instanceof ProbabilityDensityFunction){ |
870 | String msg = "Could not transform expression to PMF. Note that NUMBER_OF_ELEMENT and BYTESIZE characterisations are assumed to be PMFs and must not be PDFs. Maybe you need to fix your models here."; |
871 | logger.error(msg); |
872 | throw new TypeInferenceFailedException(expr, msg); |
873 | } else { |
874 | String msg = "Unknown ProbabilityFunction subclass "+function.getClass().getName()+" that cannot be handled by "+this.getClass().getName(); |
875 | logger.error(msg); |
876 | throw new TypeInferenceFailedException(expr, msg); |
877 | } |
878 | } |
879 | |
880 | /** |
881 | * @param expr |
882 | * @return |
883 | */ |
884 | private IProbabilityDensityFunction extractIPDFFromLiteral(Expression expr) { |
885 | ProbabilityFunctionLiteral pfl = (ProbabilityFunctionLiteral)expr; |
886 | ProbabilityDensityFunction pdf = (ProbabilityDensityFunction)pfl.getFunction_ProbabilityFunctionLiteral(); |
887 | IProbabilityDensityFunction ipdf = null; |
888 | try { |
889 | ipdf = iProbFuncFactory.transformToPDF(pdf); |
890 | } catch (UnknownPDFTypeException e) { |
891 | e.printStackTrace(); |
892 | } catch (ProbabilitySumNotOneException e) { |
893 | e.printStackTrace(); |
894 | } catch (DoubleSampleException e) { |
895 | e.printStackTrace(); |
896 | } |
897 | return ipdf; |
898 | } |
899 | |
900 | } |
901 | |
902 | class UnsupportedComputationException extends UnsupportedOperationException { |
903 | |
904 | |
905 | public UnsupportedComputationException(Expression right, Expression left, |
906 | TermProductOperation op, TypeEnum exprType) { |
907 | super("Cannot compute operation "+op+" with expression type "+exprType+" on expressions "+right.getClass()+" and "+left.getClass()); |
908 | } |
909 | |
910 | public UnsupportedComputationException(Expression exp, |
911 | String op) { |
912 | super("Cannot compute operation "+op+" on expression "+exp.getClass()); |
913 | } |
914 | |
915 | |
916 | |
917 | |
918 | /** |
919 | * |
920 | */ |
921 | private static final long serialVersionUID = 653425379466321794L; |
922 | |
923 | |
924 | } |
925 | |
926 | |