View Javadoc
1   package eu.simuline.relana.expressions;
2   
3   import eu.simuline.relana.model.Deficiency;
4   import eu.simuline.relana.model.DeficiencyNode;
5   //import eu.simuline.relana.model.VerifyException;
6   
7   import java.util.Set;
8   import java.util.HashSet;
9   import java.util.Map;
10  import java.util.HashMap;
11  import java.util.Stack;
12  
13  /**
14   * A type maps declared {@link Deficiency}s to their nodes 
15   * and defines minimum and maximum {@link Deficiency}s. 
16   *
17   *
18   * Created: Fri Apr 29 11:18:57 2005
19   *
20   * @author <a href="mailto:ernst.reissner@simuline.eu">Ernst Reissner</a>
21   * @version 1.0
22   */
23  public final class Type {
24  
25      public static final Type EMPTY = new Type();
26      public static final Type BOOLEAN;
27  
28      static {
29  	Map<Deficiency, DeficiencyNode> deficiency2ordering = 
30  	    new HashMap<Deficiency, DeficiencyNode>();
31  	deficiency2ordering.put(Deficiency.UNDET,
32  				new DeficiencyNode(Deficiency.UNDET));
33  	BOOLEAN = new Type(deficiency2ordering);
34      } // static 
35  
36      /* -------------------------------------------------------------------- *
37       * attributes.                                                          *
38       * -------------------------------------------------------------------- */
39  
40      /**
41       * Maps declared <code>Deficiency</code>s **********
42       * (see 
43       * {@link eu.simuline.relana.model.SClass#getDeclaredDeficiency2ordering}) 
44       * to their nodes 
45       * which determine their predecessors and their successors. 
46       * It is required that this relation extends that 
47       * given by {@link eu.simuline.relana.model.SClass#superClass}. 
48       */
49      private Map<Deficiency, DeficiencyNode> deficiency2ordering;
50      // **** valid after verification only {@link #initMMDefics} 
51      private Set<Deficiency> minDefs;
52      // **** valid after verification only {@link #initMMDefics} 
53      private Set<Deficiency> maxDefs;
54  
55  
56      /* -------------------------------------------------------------------- *
57       * constructors.                                                        *
58       * -------------------------------------------------------------------- */
59  
60      public Type(Map<Deficiency, DeficiencyNode> deficiency2ordering) {
61  	this.deficiency2ordering = deficiency2ordering;
62  	assert consistency();
63  	initMMDefics();
64      } // Type constructor
65  
66      // deep copy constructor. 
67      public Type(Type other) {
68  	this(other.copy());
69      }
70  
71      // empty type 
72      public Type() {
73  	this(new HashMap<Deficiency, DeficiencyNode>());
74      }
75  
76      /* -------------------------------------------------------------------- *
77       * methods.                                                             *
78       * -------------------------------------------------------------------- */
79  
80      /**
81       * Returns wheter the successors or the predecessors 
82       * of an value of {@link #deficiency2ordering} are all 
83       * in the value set of {@link #deficiency2ordering}. 
84       */
85      private boolean consistency() {
86  	for (DeficiencyNode node : this.deficiency2ordering.values()) {
87  	    for (DeficiencyNode succ : node.getSuccessors()) {
88  		if (this.deficiency2ordering.get(succ.getDeficiency()) 
89  		    != succ) {
90  //System.out.println("succ.getDeficiency(): "+succ.getDeficiency());
91  //System.out.println("succ: "+ succ);
92  		    return false;
93  		}
94  	    }
95  	    for (DeficiencyNode pred : node.getPredecessors()) {
96  		if (this.deficiency2ordering.get(pred.getDeficiency()) 
97  		    != pred) {
98  //System.out.println("pred.getDeficiency(): "+pred.getDeficiency());
99  //System.out.println("pred: "+ pred);
100 		    return false;
101 		}
102 	    }
103 	}
104 	return true;
105     }
106 
107     public Map<Deficiency, DeficiencyNode> getDeficiency2ordering() {
108 	return this.deficiency2ordering;
109     }
110 
111 
112     // **** also initializes fields minDefs and maxDefs
113     protected void initMMDefics() {
114 	this.minDefs = new HashSet<Deficiency>();
115 	this.maxDefs = new HashSet<Deficiency>();
116 	
117 	for (DeficiencyNode node : this.deficiency2ordering.values()) {
118 	    if (node.getSuccessors().isEmpty()) {
119 		this.minDefs.add(node.getDeficiency());
120 	    }
121 	    if (node.getPredecessors().isEmpty()) {
122 		this.maxDefs.add(node.getDeficiency());
123 	    }
124 	}
125     }
126 
127     public static Type getEmpty() {
128 	return new Type();
129     }
130 
131     protected Map<Deficiency, DeficiencyNode> copy() {
132 	Map<Deficiency, DeficiencyNode> newDeficiency2ordering = 
133 	    new HashMap<Deficiency, DeficiencyNode>();
134 	for (Map.Entry<Deficiency, DeficiencyNode> entry 
135 		 : this.deficiency2ordering.entrySet()) {
136 	    newDeficiency2ordering.put(entry.getKey(),
137 				       new DeficiencyNode(entry.getValue()));
138 	    assert        newDeficiency2ordering.get(entry.getKey())
139 		.equals(this.deficiency2ordering.get(entry.getKey()));
140 	}
141 
142 	DeficiencyNode node;
143 	Set<DeficiencyNode> predSuccs, predSuccsNew;
144 	for (Map.Entry<Deficiency, DeficiencyNode> entry 
145 		 : newDeficiency2ordering.entrySet()) {
146 	    node = entry.getValue();
147 
148 	    predSuccs = node.getPredecessors();
149 	    predSuccsNew = new HashSet<DeficiencyNode>();
150 	    for (DeficiencyNode pred : predSuccs) {
151 		predSuccsNew
152 		    .add(newDeficiency2ordering.get(pred.getDeficiency()));
153 	    }
154 	    predSuccs.clear();
155 	    predSuccs.addAll(predSuccsNew);
156 
157 	    predSuccs = node.getSuccessors();
158 	    predSuccsNew = new HashSet<DeficiencyNode>();
159 	    for (DeficiencyNode succ : predSuccs) {
160 		predSuccsNew
161 		    .add(newDeficiency2ordering.get(succ.getDeficiency()));
162 	    }
163 	    predSuccs.clear();
164 	    predSuccs.addAll(predSuccsNew);
165 	}
166 
167 
168 	return newDeficiency2ordering;
169     }
170 
171     protected DeficiencyNode remove(Map<Deficiency, DeficiencyNode> def2ord,
172 				    Deficiency def) {
173 	DeficiencyNode node = def2ord.remove(def);
174 	if (node == null) {
175 	    throw new IllegalArgumentException
176 		("Tried to remove deficiency \"" + def + 
177 		 "\" which is not present in type " + this + ". ");
178 	}
179 	if (!node.getSuccessors().isEmpty()) {
180 	    throw new IllegalArgumentException
181 		("Tried to remove deficiency which is not minimal: " + 
182 		 node.getSuccessors() + " are below. ");
183 	}
184 	// Remove link to node in predecessors 
185 	for (DeficiencyNode pred : node.getPredecessors()) {
186 	    pred.getSuccessors().remove(node);
187 	}
188 	return node;
189     }
190 
191     /**
192      * Returns whether the given set of deficiencies 
193      * is allowed by this type. 
194      *
195      * @param set 
196      *    a set of deficiencies for which to decide 
197      *    whether this type allows that set. 
198      * @return 
199      *    a <code>boolean</code> value describing 
200      *    whether the given set of deficiencies 
201      *    is allowed by this type. 
202      *    This includes <code>asSet().containsAll(set)</code>. 
203      */
204     public boolean isValid(Set<Deficiency> set) {
205 	DeficiencyNode node;
206 //	Set<DeficiencyNode> successors;
207 	for (Deficiency definSet : set) {
208 	    node = this.deficiency2ordering.get(definSet);
209 	    if (node == null) {
210 		return false;
211 	    }
212 	    for (DeficiencyNode succ : node.getSuccessors()) {
213 		if (!set.contains(succ.getDeficiency())) {
214 		    return false;
215 		}
216 	    }
217 	}
218 	return true;
219     }
220 
221     /**
222      * Returns <em>a copy</em> to be modified without affecting the original 
223      * of the maximal set of deficiencies of this type. 
224      *
225      * @return
226      *    <em>a copy</em> to be modified without affecting the original 
227      *    of the maximal set of deficiencies of this type. 
228      */
229     public Set<Deficiency> asSet() {
230 	return this.deficiency2ordering.keySet();
231     }
232 
233 
234     public Type getInverse() {
235 	Map<Deficiency, DeficiencyNode> invDeficiency2ordering = 
236 	    new HashMap<Deficiency, DeficiencyNode>();
237 	for (Map.Entry<Deficiency, DeficiencyNode> entry 
238 		 : this.deficiency2ordering.entrySet()) {
239 	    invDeficiency2ordering.put(entry.getKey(),
240 				       entry.getValue().getInverse());
241 	}
242 	return new Type(invDeficiency2ordering);
243     }
244 
245     public Set<Deficiency> getMin() {
246 	return this.minDefs;
247     }
248 
249     public Set<Deficiency> getMax() {
250 	return this.maxDefs;
251     }
252 
253     public void addAll(Map<Deficiency, DeficiencyNode> deficiency2ordering) {
254 	for (Map.Entry<Deficiency, DeficiencyNode> entry 
255 		 : deficiency2ordering.entrySet()) {
256 	    DeficiencyNode node = 
257 		this.deficiency2ordering.get(entry.getKey());
258 
259 	    if (node == null) {
260 		node = new DeficiencyNode(entry.getKey());
261 	    } else {
262 		node = new DeficiencyNode(node);
263 	    }
264 
265 	    node.addAll(entry.getValue());
266 	    this.deficiency2ordering.put(entry.getKey(), node);
267 	}
268 	initMMDefics();
269     }
270 
271     public void replace(Deficiency oldDef, 
272 			Deficiency newDefMin,
273 			Deficiency newDefMax,
274 			Type type) {
275 	DeficiencyNode nodeMin = type.getDeficiency2ordering().get(newDefMin);
276 	DeficiencyNode nodeMax = type.getDeficiency2ordering().get(newDefMax);
277 	
278 	boolean assertn = true;
279 	assertn &= nodeMin.getSuccessors  ().isEmpty();
280 	assertn &= nodeMax.getPredecessors().isEmpty();
281 
282 	DeficiencyNode node = this.deficiency2ordering.remove(oldDef);
283 	for (DeficiencyNode pred : node.getPredecessors()) {
284 	    assertn &= pred.getSuccessors().remove(node);
285 	    assertn &= pred.getSuccessors().add(nodeMax);
286 	}
287 	nodeMax.addPredecessors(node.getPredecessors());
288 
289 	for (DeficiencyNode pred : node.getSuccessors()) {
290 	    assertn &= pred.getPredecessors().remove(node);
291 	    assertn &= pred.getPredecessors().add(nodeMin);
292 	}
293 	nodeMin.addSuccessors(node.getSuccessors());
294 
295 	assert assertn;
296 	this.deficiency2ordering.putAll(type.getDeficiency2ordering());
297 	initMMDefics();
298     }
299 
300 
301 
302 
303 
304     public Type remove(Deficiency def) {
305 	Map<Deficiency, DeficiencyNode> newDef2ord = copy();
306 	remove(newDef2ord, def);
307 	return new Type(newDef2ord);
308     }
309 
310 
311     /**
312      * Returns a copy of this type 
313      * where the given Deficiency, and all Deficiencies above it 
314      * are removed. 
315      *
316      * @param def 
317      *    a <code>Deficiency</code> which is assumed 
318      *    to be minimal within this type. 
319      * @return 
320      *    a <code>Type</code> value
321      */
322     public Type removeAndAbove(Deficiency def) {
323 	
324 	Map<Deficiency, DeficiencyNode> newDef2ord = copy();
325 
326 	Stack<Deficiency> defsToBeRemoved = new Stack<Deficiency>();
327 	defsToBeRemoved.push(def);
328 	while (!defsToBeRemoved.empty()) {
329 	    def = defsToBeRemoved.pop();
330 	    DeficiencyNode node = remove(newDef2ord, def);
331 	    for (DeficiencyNode pred : node.getPredecessors()) {
332 		defsToBeRemoved.push(pred.getDeficiency());
333 	    }
334 	}
335 
336 	return new Type(newDef2ord);
337     }
338 
339     public boolean implies(Deficiency def1, Deficiency def2) {
340 	DeficiencyNode node = this.deficiency2ordering.get(def1);
341 	if (node == null) {
342 	    throw new IllegalArgumentException
343 		("Deficiency \"" + def1 + 
344 		 "\" does not occur within type " + this + ". ");
345 	}
346 	Stack<DeficiencyNode> search = new Stack<DeficiencyNode>();
347 	search.push(node);
348 	while (!search.empty()) {
349 	    node = search.pop();
350 	    if (node.getDeficiency().equals(def2)) {
351 		return true;
352 	    }
353 	    search.addAll(node.getSuccessors());
354 	}
355 	return false;
356     }
357 
358     public Set<Deficiency> getCone(Deficiency def) {
359 	Set<Deficiency> result = new HashSet<Deficiency>();
360 	Stack<DeficiencyNode> toBeAdded = new Stack<DeficiencyNode>();
361 	toBeAdded.push(this.deficiency2ordering.get(def));
362 	DeficiencyNode node;
363 	while (!toBeAdded.empty()) {
364 	    node = toBeAdded.pop();
365 
366 	    result.add(node.getDeficiency());
367 	    toBeAdded.addAll(node.getSuccessors());
368 	}
369 	
370 	return result;
371     }
372 
373     // **** this works properly only if deficiency2ordering is minimal. 
374     public boolean equals(Object obj) {
375 	if (!(obj instanceof Type)) {
376 	    return false;
377 	}
378 
379 	Type other = (Type) obj;
380 	if (!asSet().equals(other.asSet())) {
381 	    return false;
382 	}
383 	// Here, the types coincide as types. 
384 
385 	for (Map.Entry<Deficiency, DeficiencyNode> entry 
386 		 : this.deficiency2ordering.entrySet()) {
387 	    if (!other.deficiency2ordering.get(entry.getKey())
388 		.equals(entry.getValue())) {
389 		return false;
390 	    }
391 	}
392 	// Here, found no deviations 
393 	return true;
394     }
395 
396     public int hashCode() {
397 	return this.deficiency2ordering.hashCode();
398     }
399 
400     public String toString() {
401 	StringBuffer buf = new StringBuffer();
402 	buf.append("\n<Type>");
403 	buf.append(this.deficiency2ordering);
404 	buf.append("</Type>");
405 	return buf.toString();
406     }
407 } // Type