1 package eu.simuline.relana.model;
2
3 import eu.simuline.relana.expressions.Formula;
4 import eu.simuline.relana.expressions.Operation;
5 //import eu.simuline.relana.expressions.Operation;
6 //import eu.simuline.relana.expressions.Type;
7
8 import java.math.BigDecimal;
9
10 import java.util.Set;
11 import java.util.HashSet;
12 import java.util.Map;
13 //import java.util.HashMap;
14 import java.util.TreeMap;
15 import java.util.Iterator;
16 import java.util.List;
17 //import java.util.ArrayList;
18 import java.util.Comparator;
19
20
21 /**
22 * Instance of Component.
23 *
24 *
25 * Created: Thu Apr 14 23:02:05 2005
26 *
27 * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
28 * @version 1.0
29 */
30 public final class FlatCInstance {
31
32 /* -------------------------------------------------------------------- *
33 * constants. *
34 * -------------------------------------------------------------------- */
35
36 static final Comparator<List<String>> PATH_CMP =
37 new Comparator<List<String>>() {
38 public int compare(List<String> list1, List<String> list2) {
39 for (int i = 0; i < Math.min(list1.size(), list2.size()); i++) {
40 int res = list1.get(i).compareTo(list2.get(i));
41 if (res != 0) {
42 return res;
43 }
44 }
45
46 return list1.size() - list2.size();
47 }
48 };
49
50 /* -------------------------------------------------------------------- *
51 * attributes. *
52 * -------------------------------------------------------------------- */
53
54 /**
55 * Maps the names of the effects to their instances.
56 */
57 private final Map<List<String>, SInstance> effects;
58
59 /* -------------------------------------------------------------------- *
60 * constructors. *
61 * -------------------------------------------------------------------- */
62
63 public FlatCInstance(Map<List<String>, SInstance> effects) {
64 this.effects = effects;
65 } // FlatCInstance constructor
66
67 /* -------------------------------------------------------------------- *
68 * methods. *
69 * -------------------------------------------------------------------- */
70
71 Map<List<String>, SInstance> getEffects() {
72 return this.effects;
73 }
74
75 public SInstance getEffect(InstanceLocator loc) {
76 return getEffect(loc.getPath());
77 }
78
79 public SInstance getEffect(List<String> path) {
80 return this.effects.get(path);
81 }
82
83
84 /**
85 * Returns the <code>FlatCInstance</code> arising from this one
86 * by assuming that <code>def</code> does not occur
87 * within <code>serv</code>.
88 *
89 * @param serv
90 * a <code>SInstance</code> with probability distribution.
91 * <code>serv.distr != null</code>.
92 * @param def
93 * a <code>Deficiency</code>
94 * minimal within the type of <code>serv</code>.
95 * **** is this unique or not? ****
96 * @return
97 * a <code>FlatCInstance</code> arising from this one by assuming
98 * that <code>def</code> does not occur within <code>serv</code>.
99 */
100 public FlatCInstance remove(SInstance serv, Deficiency def) {
101 SInstance newServ = serv.remove(def);
102 if (newServ == null) {
103 // remove would cause empty set.
104 return substitute(serv, Formula.EMPTY_EXPRESSION);
105 }
106
107 Formula newVar = new Formula.Var(newServ, serv.getName());
108 return substitute(serv, newVar);
109 }
110
111 /**
112 * Returns the <code>FlatCInstance</code> arising from this one
113 * by assuming that <code>def</code> occurs within <code>serv</code>.
114 *
115 * @param serv
116 * a <code>SInstance</code> with probability distribution.
117 * <code>serv.distr != null</code>.
118 * @param def
119 * a <code>Deficiency</code>
120 * minimal within the type of <code>serv</code>.
121 * **** is this unique or not? ****
122 * @return
123 * a <code>FlatCInstance</code> arising from this one
124 * by assuming that <code>def</code> occurs within <code>serv</code>.
125 */
126 public FlatCInstance add(SInstance serv, Deficiency def) {
127
128 // create the set {def} with type serv.getType()
129 // This works, because def is minimal within serv.getType()
130 Set<Deficiency> defSet =
131 new HashSet<Deficiency>();
132 defSet.add(def);
133 Formula newConst = new Formula.Const(defSet, serv.getType());
134 assert serv.getType().isValid(defSet);
135
136 if (serv.getType().asSet().size() == 1) {
137 // def is the only remaining effect
138 // and removing it implies removing the whole effect.
139 return substitute(serv, newConst);
140 }
141 // Here, serv may assume more than one non-empty set.
142
143 // replace formula "serv" by formula "|({def}, newServ)",
144 // where newServ evolves out of serv by changing the type:
145 // removing def and all deficiencies above.
146
147 // newServ is the effect that occurs by REMOVING def
148 SInstance newServ = serv.add(def);
149 Formula newVar = new Formula.Var(newServ, serv.getName());
150 Set<Formula> args = new HashSet<Formula>();
151 args.add(newConst);
152 args.add(newVar);
153 Formula newComp = Formula.
154 getFormula(Operation.getOperation(Operation.BaseOps.Union)
155 .getEval(null), args);
156
157 return substitute(serv, newComp);
158 }
159
160 /**
161 * Returns the <code>FlatCInstance</code> arising from this one
162 * by substituting <code>serv</code> by <code>form</code> in all effects.
163 *
164 * @param serv
165 * a <code>SInstance</code>.
166 * @param form
167 * a <code>Formula</code> of appropriate type.
168 * ****
169 * @return
170 * a <code>FlatCInstance</code> arising from this one
171 * by substituting <code>serv</code> by <code>form</code>
172 * in all effects using {@link SInstance#substitute}.
173 */
174 FlatCInstance substitute(SInstance serv, Formula form) {
175 Map<List<String>, SInstance> effects =
176 new TreeMap<List<String>, SInstance>(PATH_CMP);
177 for (Map.Entry<List<String>, SInstance> entry
178 : this.effects.entrySet()) {
179 effects.put(entry.getKey(),
180 entry.getValue().substitute(serv, form));
181 }
182
183 return new FlatCInstance(effects);
184 }
185
186 /**
187 * A container comprising an {@link SInstance}
188 * and of one of its minimal {@link Deficiency}s.
189 * This is needed for probability computations:
190 * The variable of the {@link SInstance} is replaced by another one,
191 * eliminating the given {@link Deficiency}.
192 */
193 private static class InstDef {
194 private final SInstance serv;
195 private final Deficiency def;
196 InstDef(SInstance serv, Deficiency def) {
197 this.serv = serv;
198 this.def = def;
199 }
200 } // class InstDef
201
202 /**
203 * Maps the given effect which is given by a formula,
204 * onto an {@link InstDef}
205 * consisting of a variable with probability distribution
206 * occuring in the formula and its minimal deficiency.
207 * If no such variable exists, the variables within the formula
208 * (which are then all associated with formulae)
209 * are substituted within the root formula,
210 * by their associated formulae.
211 *
212 * @param serv
213 * an <code>SInstance</code> given by a formula.
214 * **** what if no formula is present? ****
215 * @return
216 * an <code>InstDef</code>
217 * consisting of a variable occuring in the formula
218 * and its minimal deficiency.
219 * If this does not exist, <code>null</code> is returned.
220 */
221 private InstDef instDefic(SInstance serv) {
222 //System.out.println("+serv: "+serv);
223
224 Formula form = serv.getFormula();
225 assert form != null;
226 // **** no good: impossible to handle effects with distr given directly
227 Set<SInstance> vars;
228
229 // in each loop variables with probability distributions are searched
230 // and if none are present, another variable is substituted
231 // by its formula.
232 // This may yield new aspects, unless alll effects are substituted.
233 // ***** the current algorithm which is NOT PERFORMANT ****
234 // loops up to <code>this.effects.keySet().size()</code> times.
235 for (int ind = 0; ind < this.effects.keySet().size(); ind++) {
236 vars = form.getVars();
237 //System.out.println("form: " + form);
238 //System.out.println("vars: " + vars);
239 // look for variables with probability distribution
240 // and essentially return the first found.
241 for (SInstance var: vars) {
242 if (var.getDistr() != null) {
243 // Here, found variable var within formula form with distr.
244 //System.out.println("var: "+var);
245 //System.out.println("var: "+var.getType());
246
247 Set<Deficiency> minDefs = var.getType().getMin();
248 assert !minDefs.isEmpty();
249 Iterator<Deficiency> iter = minDefs.iterator();
250 //System.out.println("+form: "+form);
251 return new InstDef(var, iter.next());
252 }
253 }
254 // found no variables with probability distribution.
255
256 // substitute all variables within form
257 // (which are all associated with a formula) with their formulae
258 Formula varForm;
259 for (SInstance var: vars) {
260 varForm = var.getFormula();
261 form = form.substitute(var, varForm);
262 }
263 serv.setFormula(form);
264 }
265 // Here, it is sure that form
266 // has no variables with probability distribution
267 // even if other variables are substituted recursively.
268 return null;
269 }
270
271 /**
272 * Returns the probability
273 * that the effect specified by <code>sPath</code>
274 * is not the empty set.
275 * It is intended to be applied primarily to Boolean effects,
276 * i.e. to effects isomorphic to Boolean ones,
277 * i.e. to one-point effects.
278 * Then this method returns the probability for <code>true</code>.
279 *
280 * @param sPath
281 * identifies a effect.
282 * @return
283 * the probability described above as a <code>BigDecimal</code> value.
284 */
285 public BigDecimal getProb(List<String> sPath) {
286 SInstance serv = getEffect(sPath);
287 // Fetch a effect instance inst within the formula attached with serv
288 // such that s is associated with a probability distribution
289 // with a certain deficiency def.
290 // Then instDef comprises both, inst and def.
291 InstDef instDef = instDefic(serv);
292 if (instDef == null) {
293 // the formula attached with serv is constant
294 // (at least after substitution done by instDefic)
295 Set<Deficiency> defs = serv.getFormula().getConst();
296 assert defs != null; // i.e. serv.getFormula() is a constant.
297 return defs.isEmpty() ? BigDecimal.ZERO : BigDecimal.ONE;
298 }
299 // Here, instDef != null
300
301 // cond is the probability that instDef.def occurs.
302 BigDecimal cond = instDef.serv.getDistr().getProb(instDef.def);
303
304 // create copies of this FlatCInstance
305 // by assuming that def occurs within serv
306 // and that it does not occur, respectively.
307 FlatCInstance cInstP = add (instDef.serv, instDef.def);
308 FlatCInstance cInstM = remove(instDef.serv, instDef.def);
309 //System.out.println("cInstP: " + cInstP);
310 //System.out.println("cInstM: " + cInstM);
311 //System.out.println("this: " + this);
312 //throw new IllegalStateException();
313
314 return cond .multiply(cInstP.getProb(sPath))
315 .add(BigDecimal.ONE.subtract(cond).multiply(cInstM.getProb(sPath)));
316 }
317
318 public String toString() {
319 StringBuffer res = new StringBuffer();
320 res.append("\n<FlatCInstance><Effects>");
321 res.append(this.effects);
322 res.append("</Effects>\n</FlatCInstance>\n");
323
324 return res.toString();
325 }
326
327 } // FlatCInstance