1 package eu.simuline.relana.model;
2
3 import eu.simuline.relana.expressions.Type;
4
5 import java.math.BigDecimal;
6 import java.math.MathContext;
7
8 import java.util.Map;
9 import java.util.EnumMap;
10 import java.util.HashMap;
11 import java.util.Set;
12 import java.util.SortedSet;
13 import java.util.TreeSet;
14 import java.util.HashSet;
15 import java.util.Stack;
16 import java.util.Iterator;
17
18
19
20
21
22
23
24
25
26
27 public final class ProbDistr {
28
29
30
31
32
33
34
35
36
37 enum Inverter {
38 Identity() {
39 BigDecimal filterProb(BigDecimal prob) {
40 return prob;
41 }
42 Set<DeficiencyNode> getSuccsPreds(DeficiencyNode node) {
43 return node.getSuccessors();
44 }
45 void addSuccsPreds(DeficiencyNode source,
46 DeficiencyNode target) {
47 target.addSuccessors(source.getSuccessors());
48 }
49 String andOr() {
50 return "AND";
51 }
52 String condEventName(String event, SortedSet<String> conds) {
53 return neg() + event + "|" + andOr() + conds;
54 }
55 String neg() {
56 return "";
57 }
58 },
59 Invert () {
60 BigDecimal filterProb(BigDecimal prob) {
61 return BigDecimal.ONE.subtract(prob);
62 }
63 Set<DeficiencyNode> getSuccsPreds(DeficiencyNode node) {
64 return node.getPredecessors();
65 }
66 void addSuccsPreds(DeficiencyNode source,
67 DeficiencyNode target) {
68 target.addPredecessors(source.getPredecessors());
69 }
70 String andOr() {
71 return "OR";
72 }
73 String condEventName(String event, SortedSet<String> conds) {
74 return andOr() + conds + "|" + neg() + event;
75 }
76 String neg() {
77 return "~";
78 }
79 };
80
81 abstract BigDecimal filterProb(BigDecimal prob);
82 abstract Set<DeficiencyNode> getSuccsPreds(DeficiencyNode node);
83 abstract void addSuccsPreds(DeficiencyNode source,
84 DeficiencyNode target);
85 abstract String andOr();
86 abstract String condEventName(String event, SortedSet<String> conds);
87 abstract String neg();
88
89 }
90
91
92
93
94
95
96 static class Validator {
97
98
99
100
101
102
103
104
105
106 private final Map<Deficiency, DeficiencySetNode> extOrdering;
107
108
109
110
111
112 private final Map<Deficiency, BigDecimal> def2prob;
113
114
115
116
117
118 private final Set<Deficiency> invalids;
119
120
121
122
123
124 private final Set<Deficiency> degenerates;
125
126
127
128
129
130 Validator(Map<Deficiency, BigDecimal> def2prob) {
131 this.extOrdering = new HashMap<Deficiency, DeficiencySetNode>();
132 this.def2prob = new HashMap<Deficiency, BigDecimal>(def2prob);
133 this.invalids = new HashSet<Deficiency>();
134 this.degenerates = new HashSet<Deficiency>();
135 }
136
137
138
139
140
141 void put(Deficiency def, BigDecimal prob) {
142 this.def2prob.put(def, prob);
143 int cmp = prob.compareTo(BigDecimal.ONE);
144 if (cmp == 0) {
145 this.degenerates.add(def);
146 }
147 if (cmp > 0) {
148 this.invalids.add(def);
149 }
150 }
151
152 void put(Deficiency def, DeficiencySetNode dsn) {
153 this.extOrdering.put(def, dsn);
154 }
155
156 DeficiencySetNode get(Deficiency def) {
157 return this.extOrdering.get(def);
158 }
159
160 boolean isValid() {
161 return this.invalids.isEmpty();
162 }
163
164 boolean isDegenerate() {
165 return !this.degenerates.isEmpty();
166 }
167
168 Map<Deficiency, BigDecimal> error() {
169 return warningError(this.invalids);
170 }
171
172 Map<Deficiency, BigDecimal> warning() {
173 return warningError(this.degenerates);
174 }
175
176 Map<Deficiency, BigDecimal> warningError(Set<Deficiency> invOrDeg) {
177 Map<Deficiency, BigDecimal> def2prob =
178 new HashMap<Deficiency, BigDecimal>();
179 for (Deficiency def : invOrDeg) {
180 def2prob.put(def, this.def2prob.get(def));
181 }
182
183 return def2prob;
184 }
185
186 BigDecimal getProb(Set<Deficiency> defs) {
187 Set<Deficiency> elDefs = new HashSet<Deficiency>();
188 for (Deficiency def: defs) {
189 elDefs.addAll(this.extOrdering.get(def).getDeficiencySet());
190 }
191 BigDecimal result = BigDecimal.ONE;
192 for (Deficiency def: elDefs) {
193 result = result.multiply(this.def2prob.get(def));
194 }
195 return result;
196 }
197
198 public String toString() {
199 StringBuffer res = new StringBuffer();
200 res.append("<Validator>\nextOrdering: ");
201 res.append(extOrdering);
202 res.append("\ndef2prob: ");
203 res.append(def2prob);
204 res.append("\ninvalids: ");
205 res.append(invalids);
206 res.append("\ndegenerates: ");
207 res.append(degenerates);
208 res.append("</Validator>");
209 return res.toString();
210 }
211 }
212
213
214
215
216
217
218
219
220
221
222
223 private Type type;
224
225 private Map<Deficiency, BigDecimal> def2prob;
226
227 private Map<Inverter, Validator> validators;
228
229
230
231
232
233 public ProbDistr(Type type,
234 Map<Deficiency, BigDecimal> def2prob) {
235
236 checkIn01(def2prob);
237
238 this.type = type;
239 this.def2prob = def2prob;
240 }
241
242
243
244
245
246
247
248
249 public ProbDistr(Type type,
250 Map<Deficiency, ProbDistr> old2ProbDistr,
251 Map<Deficiency, BigDecimal> def2prob) {
252 this(type, def2prob);
253 for (ProbDistr distr : old2ProbDistr.values()) {
254 this.def2prob.putAll(distr.def2prob);
255 }
256 }
257
258 private static void checkIn01(Map<Deficiency, BigDecimal> def2prob) {
259 for (BigDecimal prob : def2prob.values()) {
260 if (prob.compareTo(BigDecimal.ONE ) >= 0 ||
261 prob.compareTo(BigDecimal.ZERO) <= 0) {
262 throw new IllegalArgumentException
263 ("Expected probability in (0, 1) but found " + prob + ". ");
264 }
265 }
266 }
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290 private Validator init(Inverter inv,
291 Stack<Deficiency> minDefs,
292 Set<DeficiencyNode> nMinNodes) {
293
294 for (DeficiencyNode node
295 : getType()
296 .getDeficiency2ordering()
297 .values()) {
298 if (inv.getSuccsPreds(node).isEmpty()) {
299 minDefs.push(node.getDeficiency());
300 } else {
301
302 DeficiencyNode cpNode =
303 new DeficiencyNode(node.getDeficiency());
304 inv.addSuccsPreds(node, cpNode);
305
306 nMinNodes.add(cpNode);
307 }
308 }
309
310
311
312
313 Map<Deficiency, BigDecimal> minDef2prob =
314 new HashMap<Deficiency, BigDecimal>();
315 for (Deficiency minDef : minDefs) {
316 minDef2prob.put(minDef, inv.filterProb(getProb(minDef)));
317 }
318
319 return new Validator(minDef2prob);
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333 Validator getValidator(Inverter inv) {
334
335
336
337 Stack<Deficiency> minDefs = new Stack<Deficiency>();
338
339
340
341
342 Set<DeficiencyNode> nMinNodes = new HashSet<DeficiencyNode>();
343
344 Validator val = init(inv, minDefs, nMinNodes);
345
346
347 while (!minDefs.isEmpty()) {
348
349
350
351
352 DeficiencyNode node = getType().getDeficiency2ordering()
353 .get(minDefs.pop());
354
355 Set<Deficiency> predDefs = DeficiencyNode.unwrap
356 (inv.getSuccsPreds(node));
357
358
359
360
361
362
363 SortedSet<String> namesBelow = new TreeSet<String>();
364 Set<Deficiency> subseqDefs = new HashSet<Deficiency>();
365 for (Deficiency def : predDefs) {
366 namesBelow.add(inv.neg() + def.getName());
367
368 subseqDefs.addAll(val.get(def).getDeficiencySet());
369 }
370
371
372
373
374 DeficiencySetNode andDefN =
375 new DeficiencySetNode(new Deficiency(inv.andOr() + namesBelow),
376 subseqDefs);
377
378 BigDecimal andProb = andDefN.getProb(val.def2prob);
379
380
381
382
383 String name = inv.condEventName(node.getDeficiency().getName(),
384 namesBelow);
385 Deficiency condDef = new Deficiency(name);
386 BigDecimal condProb = inv.filterProb(getProb(node.getDeficiency()))
387 .divide(andProb, MathContext.DECIMAL128);
388 val.put(condDef, condProb);
389
390
391 Set<Deficiency> subseqCondDefs =
392 new HashSet<Deficiency>(subseqDefs);
393 subseqCondDefs.add(condDef);
394 DeficiencySetNode condDefN =
395 new DeficiencySetNode(node.getDeficiency(), subseqCondDefs);
396 val.put(node.getDeficiency(), condDefN);
397
398
399 Iterator<DeficiencyNode> iter = nMinNodes.iterator();
400 Set<DeficiencyNode> succs;
401 while (iter.hasNext()) {
402 DeficiencyNode nMinNode = iter.next();
403 succs = inv.getSuccsPreds(nMinNode);
404
405 if (succs.remove(node) && succs.isEmpty()) {
406 iter.remove();
407 minDefs.add(nMinNode.getDeficiency());
408 }
409
410 }
411
412
413
414
415
416 }
417
418 return val;
419 }
420
421
422
423
424
425 private Type getType() {
426 return this.type;
427 }
428
429
430 public BigDecimal getProb(Deficiency def) {
431 BigDecimal res = this.def2prob.get(def);
432 if (res == null) {
433 throw new IllegalArgumentException
434 ("Deficiency \"" + def + "\" is unknown. ");
435 }
436 return res;
437 }
438
439 public void validate() {
440 this.validators = new EnumMap<Inverter, Validator>(Inverter.class);
441 validateUp(Inverter.Identity);
442 validateUp(Inverter.Invert);
443 }
444
445 private void validateUp(Inverter inv) {
446 Validator val = getValidator(inv);
447 this.validators.put(inv, getValidator(inv));
448 if (!val.isValid()) {
449 throw new IllegalStateException("invalid: " + val.error());
450 }
451 if (val.isDegenerate()) {
452 System.out.println("degenerate: " + val.warning());
453 }
454 }
455
456
457 ProbDistr remove(Deficiency def) {
458 return this;
459 }
460
461
462 ProbDistr add(Deficiency def) {
463 return this;
464 }
465
466 public String toString() {
467 StringBuffer res = new StringBuffer();
468 res.append("\n<ProbDistr>");
469 res.append(this.def2prob);
470 res.append("\n</ProbDistr>");
471 return res.toString();
472 }
473 }