//////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: LaxityHeap.cs // // Note: // using System; using System.Collections; using System.Diagnostics; using Microsoft.Singularity.Scheduling; namespace Microsoft.Singularity.Scheduling.Laxity { /// /// A generic heap implementation /// public class Heap { private class HeapElem { public object elem; public IComparable key; public HeapElem(object elem, IComparable key) { this.elem = elem; this.key = key; } } private Hashtable map; private ArrayList heap; // float the value at position i down the heap, assuming // subtrees already satisfy the heap property // this is HEAPIFY from CLR pg 143. private void pushdown(int i) { while (i*2 + 1 < heap.Count) { int ichild = i*2 + 1; HeapElem child = (HeapElem)heap[ichild]; if (ichild + 1 < heap.Count) { HeapElem otherchild = (HeapElem)heap[ichild+1]; if (otherchild.key.CompareTo(child.key) < 0) { child = otherchild; ichild++; } } HeapElem cur = (HeapElem)heap[i]; // now child contains the child with the smaller key // if that is smaller than parent's key, swap them if (child.key.CompareTo(cur.key) < 0) { heap[i] = child; heap[ichild] = cur; map[child.elem] = i; map[cur.elem] = ichild; } // and continue one level down i = ichild; } } // push a value up the heap until it exceeds its parent // this is HEAP-INSERT from CLR pg 150 private void pushup(int i) { while (i > 0) { HeapElem cur = (HeapElem) heap[i]; HeapElem parent = (HeapElem) heap[(i-1)/2]; if (parent.key.CompareTo(cur.key) <= 0) { break; } // swap with parent and continue heap[i] = parent; heap[(i-1)/2] = cur; map[parent.elem] = i; map[cur.elem] = (i-1)/2; i = (i-1)/2; } } // assert heap invariant at node i private void assertHeap(int i) { // first make sure map and heap are consistent Debug.Assert(heap.Count == map.Count); for (int j = 0; j < heap.Count; j++) { HeapElem cur = (HeapElem) heap[j]; int jj = (int) map[cur.elem]; Debug.Assert(j == jj); } for (; i < heap.Count/2; i++) { HeapElem cur = (HeapElem) heap[i]; HeapElem child = (HeapElem) heap[i*2+1]; Debug.Assert(child.key.CompareTo(cur.key) >= 0); if (i*2 + 2 < heap.Count) { child = (HeapElem)heap[i*2+2]; Debug.Assert(child.key.CompareTo(cur.key) >= 0); } } } /// /// Create a new, empty heap. /// public Heap() { map = new Hashtable(); heap = new ArrayList(); } public int Count { get { return heap.Count; } } /// /// Check if the heap is legit else assert /// public void AssertHeap() { assertHeap(0); } /// /// Insert an object into the heap /// /// the object to be inserted /// the key value with which the object is associated /// false if object already exists in the heap (key is not updated in this case) public bool Insert(object elem, IComparable key) { if (map.ContainsKey(elem)) { return false; } int i = heap.Count; map[elem] = i; heap.Add(new HeapElem(elem, key)); pushup(i); return true; } /// /// Update a key value for an existing object /// /// the object to update the key for /// the new key value /// false if the object does not exist in the heap public bool Update(object elem, IComparable newkey) { if (!map.ContainsKey(elem)) { return false; } int i = (int)map[elem]; HeapElem cur = (HeapElem) heap[i]; cur.key = newkey; // we need to push it either up or down, just do both pushdown(i); pushup(i); return true; } /// /// Delete an object from the heap /// /// the object to delete /// false if object does not exist in the heap public bool Delete(object elem) { if (!map.ContainsKey(elem)) { return false; } int i = (int) map[elem]; int ilast = heap.Count - 1; HeapElem lastelem = (HeapElem)heap[ilast]; // remove from mapping and shrink the array heap.RemoveAt(ilast); map.Remove(elem); if (i != ilast) { // move erstwhile last elem into current position and update mapping heap[i] = lastelem; map[lastelem.elem] = i; // push up/down to rightful place pushdown(i); pushup(i); } return true; } /// /// Return the heap object with the least key, without removing it. /// /// the heap object with the least key public object Min { get { return (heap.Count > 0) ? ((HeapElem)heap[0]).elem : null; } } // debug the heap static void TestHeap(int maxelem) { Heap newheap = new Heap(); Random r = new Random(); bool[] inserted = new bool[maxelem]; int[] updated = new int[maxelem]; for (int i = 0; i < maxelem; i++) { DebugStub.WriteLine("Inserting {0}\r", i); int ins = r.Next() % maxelem; bool insret = newheap.Insert(ins, ins); newheap.AssertHeap(); Debug.Assert(insret != inserted[ins]); // returns false if already inserted inserted[ins] = true; } DebugStub.WriteLine("{0} inserted", newheap.Count); for (int i = 0; i < maxelem; i++) { DebugStub.WriteLine("Updating {0}", i); int newkey = r.Next() % 1000; bool upret = newheap.Update(i, newkey); newheap.AssertHeap(); Debug.Assert(upret == inserted[i]); updated[i] = upret ? newkey : -1; } DebugStub.WriteLine(); for (int i = 0; i < maxelem; i++) { DebugStub.WriteLine("Deleting {0}", i); int del = r.Next() % maxelem; bool delret = newheap.Delete(del); newheap.AssertHeap(); Debug.Assert(delret == inserted[del]); // returns false if not inserted inserted[del] = false; } DebugStub.WriteLine(); int prev = 0; int c = newheap.Count; DebugStub.WriteLine("{0} remaining", c); for (int i = 0; i < c; i++) { int nextval = (int) newheap.Min; newheap.AssertHeap(); int nextkey = updated[nextval]; Debug.Assert(nextkey != -1); Debug.Assert(nextkey >= prev); DebugStub.Write("{0} ", nextkey); prev = nextkey; Debug.Assert(newheap.Delete(nextval)); newheap.AssertHeap(); } DebugStub.WriteLine() Debug.Assert(newheap.Count == 0); DebugStub.WriteLine("All serene ..."); } } }