Class Name: 
kiasan.examples.binomialqueue.BinomialQueue

Report Rendered: Mon May 04 12:43:42 CDT 2009, by Sireum/Kiasan for Java v0.1.20090504

Methods Covered:
PercentRatio
Class / Method T E Instruction Coverage Branch Coverage Time
2 3
  62/65
  95.38%
  10/12
  83.33%
0.236s
7 1
  242/281
  86.12%
  21/40
  52.5%
0.341s
Total
9 4
  304/346
  87.86%
  31/52
  59.62%
0.577s
Source Code:
1   package kiasan.examples.binomialqueue;
2   
3   import kiasan.examples.common.LinkedList;
4   import kiasan.examples.common.Underflow;
5   
6   /**
7    * Implements a binomial queue. Note that all "matching" is based on the
8    * compareTo method.
9    * 
10   * @author Mark Allen Weiss
11   */
12  public class BinomialQueue {
13    private static class BinomialNode {
14      int element; // The data in the node
15  
16      BinomialNode leftChild; // Left child
17  
18      BinomialNode nextSibling; // Right child
19  
20      // Constructors
21      BinomialNode(final int theElement) {
22        this(theElement, null, null);
23      }
24  
25      BinomialNode(final int theElement, final BinomialNode lt,
26          final BinomialNode nt) {
27        this.element = theElement;
28        this.leftChild = lt;
29        this.nextSibling = nt;
30      }
31    }
32  
33    private static final int DEFAULT_TREES = 1;
34  
35    public static void main(final String[] args) {
36      final int numItems = 10000;
37      final BinomialQueue h = new BinomialQueue();
38      final BinomialQueue h1 = new BinomialQueue();
39      int i = 37;
40  
41      System.out.println("Starting check.");
42  
43      for (= 37; i != 0; i = (+ 37) % numItems) {
44        if (% 2 == 0) {
45          h1.insert(i);
46        } else {
47          h.insert(i);
48        }
49      }
50      assert h.wellFormed();
51      h.merge(h1);
52      assert h.wellFormed();
53      for (= 1; i < numItems; i++) {
54        // assert h.wellFormed();
55        if (h.deleteMin() != i) {
56          System.out.println("Oops! " + i);
57        }
58      }
59  
60      System.out.println("Check done.");
61    }
62  
63    private int currentSize; // # items in priority queue
64    private BinomialNode[] theTrees; // An array of tree roots
65  
66    /**
67     * Construct the binomial queue.
68     */
69    public BinomialQueue() {
70      this.theTrees = new BinomialNode[BinomialQueue.DEFAULT_TREES];
71      makeEmpty();
72    }
73  
74    /**
75     * Construct with a single item.
76     */
77    public BinomialQueue(final int item) {
78      this.currentSize = 1;
79      this.theTrees = new BinomialNode[1];
80      this.theTrees[0] = new BinomialNode(item, null, null);
81    }
82  
83    /**
84     * Return the capacity.
85     */
86    private int capacity() {
87      return (2 * this.theTrees.length) - 1;
88    }
89  
90    /**
91     * Return the result of merging equal-sized t1 and t2.
92     */
93    private BinomialNode combineTrees(final BinomialNode t1, final BinomialNode t2) {
94      if (t1.element > t2.element) {
95        return combineTrees(t2, t1);
96      }
97      t2.nextSibling = t1.leftChild;
98      t1.leftChild = t2;
99      return t1;
100   }
101 
102   /**
103    * Remove the smallest item from the priority queue.
104    * 
105    * @return the smallest item, or null, if empty.
106    */
107   public int deleteMin() {
108     if (isEmpty()) {
109       throw new Underflow();
110     }
111 
112     final int minIndex = findMinIndex();
113     final int minItem = this.theTrees[minIndex].element;
114 
115     BinomialNode deletedTree = this.theTrees[minIndex].leftChild;
116 
117     // Construct H''
118     final BinomialQueue deletedQueue = new BinomialQueue();
119     deletedQueue.expandTheTrees(minIndex + 1);
120 
121     deletedQueue.currentSize = (1 << minIndex) - 1;
122     for (int j = minIndex - 1; j >= 0; j--) {
123       deletedQueue.theTrees[j] = deletedTree;
124       deletedTree = deletedTree.nextSibling;
125       deletedQueue.theTrees[j].nextSibling = null;
126     }
127 
128     // Construct H'
129     this.theTrees[minIndex] = null;
130     this.currentSize -= deletedQueue.currentSize + 1;
131 
132     merge(deletedQueue);
133 
134     return minItem;
135   }
136 
137   private void expandTheTrees(final int newNumTrees) {
138     final BinomialNode[] old = this.theTrees;
139     final int oldNumTrees = this.theTrees.length;
140 
141     this.theTrees = new BinomialNode[newNumTrees];
142     for (int i = 0; i < oldNumTrees; i++) {
143       this.theTrees[i] = old[i];
144     }
145     for (int i = oldNumTrees; i < newNumTrees; i++) {
146       this.theTrees[i] = null;
147     }
148   }
149 
150   /**
151    * Find the smallest item in the priority queue.
152    * 
153    * @return the smallest item, or null, if empty.
154    */
155   //@ requires this.wellFormed();
156   //@ ensures this.wellFormed();
157   public int findMin() {
158     if (isEmpty()) {
159       throw new Underflow();
160     }
161 
162     return this.theTrees[findMinIndex()].element;
163   }
164 
165   /**
166    * Find index of tree containing the smallest item in the priority queue. The
167    * priority queue must not be empty.
168    * 
169    * @return the index of tree containing the smallest item.
170    */
171   private int findMinIndex() {
172     int i;
173     int minIndex;
174 
175     for (= 0; this.theTrees[i] == null; i++) {
176       ;
177     }
178 
179     for (minIndex = i; i < this.theTrees.length; i++) {
180       if ((this.theTrees[i] != null)
181           && (this.theTrees[i].element < this.theTrees[minIndex].element)) {
182         minIndex = i;
183       }
184     }
185 
186     return minIndex;
187   }
188 
189   /**
190    * Insert into the priority queue, maintaining heap order. This implementation
191    * is not optimized for O(1) performance.
192    * 
193    * @param x
194    *          the item to insert.
195    */
196   //@ requires this.wellFormed();
197   //@ ensures this.wellFormed();
198   public void insert(final int x) {
199     merge(new BinomialQueue(x));
200   }
201 
202   private boolean isAcyclic(final BinomialNode start,
203       final LinkedList<BinomialNode> seen) {
204     if (start.leftChild != null) {
205       if (seen.contains(start.leftChild)) {
206         return false;
207       }
208       seen.addToEnd(start.leftChild);
209       if (!isAcyclic(start.leftChild, seen)) {
210         return false;
211       }
212     }
213     final BinomialNode ns = start.nextSibling;
214     if (ns != null) {
215       if (seen.contains(ns)) {
216         return false;
217       }
218       seen.addToEnd(ns);
219       if (!isAcyclic(ns, seen)) {
220         return false;
221         //ns = ns.nextSibling;
222       }
223     }
224     return true;
225   }
226 
227   /**
228    * Test if the priority queue is logically empty.
229    * 
230    * @return true if empty, false otherwise.
231    */
232   public boolean isEmpty() {
233     return this.currentSize == 0;
234   }
235 
236   /**
237    * Make the priority queue logically empty.
238    */
239   public void makeEmpty() {
240     this.currentSize = 0;
241     for (int i = 0; i < this.theTrees.length; i++) {
242       this.theTrees[i] = null;
243     }
244   }
245 
246   /**
247    * Merge rhs into the priority queue. rhs becomes empty. rhs must be different
248    * from this.
249    * 
250    * @param rhs
251    *          the other binomial queue.
252    */
253   public void merge(final BinomialQueue rhs) {
254     if (this == rhs) {
255       return;
256     }
257 
258     this.currentSize += rhs.currentSize;
259 
260     if (this.currentSize > capacity()) {
261       final int newNumTrees = Math.max(this.theTrees.length,
262           rhs.theTrees.length) + 1;
263       expandTheTrees(newNumTrees);
264     }
265 
266     BinomialNode carry = null;
267     for (int i = 0, j = 1; j <= this.currentSize; i++, j *= 2) {
268       final BinomialNode t1 = this.theTrees[i];
269       final BinomialNode t2 = i < rhs.theTrees.length ? rhs.theTrees[i] : null;
270 
271       int whichCase = t1 == null ? 0 : 1;
272       whichCase += t2 == null ? 0 : 2;
273       whichCase += carry == null ? 0 : 4;
274 
275       switch (whichCase) {
276         case 0: /* No trees */
277         case 1: /* Only this */
278           break;
279         case 2: /* Only rhs */
280           this.theTrees[i] = t2;
281           rhs.theTrees[i] = null;
282           break;
283         case 4: /* Only carry */
284           this.theTrees[i] = carry;
285           carry = null;
286           break;
287         case 3: /* this and rhs */
288           carry = combineTrees(t1, t2);
289           this.theTrees[i] = rhs.theTrees[i] = null;
290           break;
291         case 5: /* this and carry */
292           carry = combineTrees(t1, carry);
293           this.theTrees[i] = null;
294           break;
295         case 6: /* rhs and carry */
296           carry = combineTrees(t2, carry);
297           rhs.theTrees[i] = null;
298           break;
299         case 7: /* All three */
300           this.theTrees[i] = carry;
301           carry = combineTrees(t1, t2);
302           rhs.theTrees[i] = null;
303           break;
304       }
305     }
306 
307     for (int k = 0; k < rhs.theTrees.length; k++) {
308       rhs.theTrees[k] = null;
309     }
310     rhs.currentSize = 0;
311   }
312 
313   private boolean ordered(final BinomialNode node) {
314     if (node.leftChild != null) {
315       if (node.leftChild.element < node.element) {
316         return false;
317       }
318       if (!ordered(node.leftChild)) {
319         return false;
320       }
321       for (BinomialNode ns = node.leftChild.nextSibling; ns != null; ns = ns.nextSibling) {
322         if (ns.element < node.element) {
323           return false;
324         }
325         if (!ordered(ns)) {
326           return false;
327         }
328       }
329       return true;
330     } else {
331       return node.nextSibling == null;
332     }
333   }
334 
335   private boolean wellFormed() {
336     if (this.theTrees == null) {
337       return false;
338     }
339     final LinkedList<BinomialNode> seen = new LinkedList<BinomialNode>();
340     for (int i = 0; i < this.theTrees.length; i++) {
341       if (this.theTrees[i] != null) {
342         if (seen.contains(this.theTrees[i])) {
343           return false;
344         }
345         seen.addToEnd(this.theTrees[i]);
346         if (!isAcyclic(this.theTrees[i], seen)) {
347           return false;
348         }
349       }
350     }
351     return wellStructured();
352   }
353 
354   private boolean wellStructured() {
355     if (this.currentSize < 0) {
356       return false;
357     }
358     if (this.theTrees == null) {
359       return false;
360     }
361     int size = this.currentSize;
362     for (int i = 0, j = 1; i < this.theTrees.length; i++, j *= 2) {
363       if (size < 0) {
364         return false;
365       }
366       if ((size == 0) && (this.theTrees[i] != null)) {
367         return false;
368       }
369       if (this.theTrees[i] != null) {
370         if (this.theTrees[i].nextSibling != null) {
371           return false;
372         }
373         if (!wellStructuredBK(this.theTrees[i], i)) {
374           return false;
375         }
376         if (!ordered(this.theTrees[i])) {
377           return false;
378         }
379         size -= j;
380       }
381     }
382     if (size != 0) {
383       return false;
384     }
385     return true;
386   }
387 
388   //specification method
389   //B_k k has to be a power of 2
390   private boolean wellStructuredBK(final BinomialNode node, int k) {
391     assert k >= 0;
392     if (node == null) {
393       return false;
394     }
395     if (== 0) {
396       return (node.leftChild == null) && (node.nextSibling == null);
397     }
398     if (!wellStructuredBK(node.leftChild, --k)) {
399       return false;
400     }
401     --k;
402     for (BinomialNode nc = node.leftChild.nextSibling; k >= 0; nc = nc.nextSibling, --k) {
403       if (!wellStructuredBK(nc, k)) {
404         return false;
405       }
406     }
407     return true;
408   }
409 }