////////////////////////////////////////////////////////////////////////////////
//
// 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 ...");
}
}
}