CS 345 Homework 10

Due Monday Apr 17 at 9pm. Upload to Desire 2 Learn dropbox for homework 10.

Max Heap Priority Queue Solution

Description

This homework exercise will allow you to explore using a priority queue to manage jobs for a high performance computing center. At this center jobs with the highest projected runtime have high priority. Your task is to modify the file linked below to make it a MAX heap (instead of a MIN heap).

Start here: hw_10_priority_queue.py

Tasks:

A. ClusterJob class

  1. Overload the > operator in the ClusterJob class using the load factor for each object.

  2. Complete the unit test to make sure ClusterJob objects are compared correctly. a > b.

B. BinHeapList class and Unit Tests

  1. Turn the BinHeapList class into a max heap.
    • add delmax function that should return the cluster job with the highest runtime. See the delmin function for example.
    • modify percUp and percDown accordingly so that they ensure the heap stays in heap order (highest at top).
    • add maxChildIndex function to determine the index of the largest child of parent p. See minChildIndex for an example that returns the index of the smallest child of parent p. Remember to call maxChildIndex at the appropriate location of the code.
  2. Complete the unit test to make sure the max heap always returns the highest runtime cluster job.

Please test with at least 5 cluster job objects and verify they removed in highest to lowest order! You will want to insert job objects, then delete them (delmax function) to verify that the heap is deleting largest to the smallest items in order.

Turn In:

Rename the source code file containing your version of the program according to syllabus.

Solution

# solution hw_10_priority_queue.py cs 345 sp 2017

import unittest

class ClusterJob():
    def __init__(self, tag, rtime, lines):
        self.tag = tag
        self.runtime = rtime  # estimated runtime in seconds.
        self.code_lines = lines  # lines of code.

    def __str__(self):
        return str(self.load_factor())

    def __gt__(self, other_obj):
        return self.load_factor() > other_obj.load_factor()

    def __lt__(self, other_obj):
        return self.load_factor() < other_obj.load_factor()

    def load_factor(self):
        return self.runtime / float(self.code_lines)

class BinHeapList:
    """
    Binary heap as a priority queue using a list.
    """
    def __init__(self):
        """Creates a new, empty, binary heap as a list."""
        self.heap = [0]  # set first position to zero placeholder

    def __iter__(self):
        """Custom iterator for the tree. (uses breadth first traversal)"""
        for i in self.heap[1:]:
            yield i.load_factor()

    def insert(self, k):
        self.heap.append(k)  # add to end of list
        self.percUp(self.size())  # move new k up the tree 

    def getMax(self):
        return self.heap[1]

    def delMax(self):
        retval = self.heap[1]  # copy the front item.
        self.heap[1] = self.heap[-1]  # put last item first
        self.heap.pop() # clear last item (list decreases by 1)
        self.percDown(1)  # move first item down the tree
        return retval

    def percUp(self, p):
        """Maintains heap order property after insertion."""
        parent = self.parent(p)
        while parent > 0:
          if self.heap[p] > self.heap[parent]:
             tmp = self.heap[parent]
             self.heap[parent] = self.heap[p]
             self.heap[p] = tmp
          p = parent
          parent = self.parent(p)

    def percDown(self, p):
        """Maintains heap order property after deletion of root.
        Also note that the while loop processes the entire list
        """
        left = self.left(p)
        while left <= self.size():
            max_child = self.maxChildIndex(p)
            if self.heap[p] < self.heap[max_child]:  # swap child and parent
                tmp = self.heap[p]
                self.heap[p] = self.heap[max_child]
                self.heap[max_child] = tmp
            p = max_child  # keep moving down the tree
            left = self.left(p)

    def maxChildIndex(self, p):
        """Determines index of the larger of left and right values."""
        left, right = self.left(p), self.right(p)
        
        if right > self.size():  # right node does not exist
            return left
        
        elif self.heap[left] > self.heap[right]:
            return left
        
        return right

    def buildHeap(self, alist):
        i = len(alist) // 2  # start in middle of alist.
        self.heap = [0] + alist[:]  # initialize the heap list
        while (i > 0):
            self.percDown(i)
            i = i - 1

    def size(self):
        return len(self.heap)-1

    def left(self, p):
        return p * 2

    def right(self, p):
        return p * 2 + 1

    def parent(self, p):
        return p // 2


class TestClusterJob(unittest.TestCase):
    """Unit tests for ClusterJob"""

    def test_cluster_job_compare_lt(self):
        a = ClusterJob('a', 5, 10)
        b = ClusterJob('b', 10, 100)
        self.assertEqual(a < b, False)

    def test_cluster_job_compare_gt(self):
        # write a test that verifies cluster jobs can be compared as a>b
        a = ClusterJob('a', 5, 10)
        b = ClusterJob('b', 10, 100)
        self.assertEqual(a > b, True)      

    def test_heap_max(self):
        # write a test that verifies that the largest job is returned.
        a = ClusterJob('a', 50, 100)
        b = ClusterJob('b', 10, 100)
        c = ClusterJob('c', 30, 100)
        d = ClusterJob('d', 90, 100)
        e = ClusterJob('e', 5, 100)
        f = ClusterJob('f', 99, 100)
        
        print '\nINSERTION ORDER ==>', 
        print [i.load_factor() for i in [a, b, c, d, e, f]]
        
        h = BinHeapList()
        h.buildHeap([a, b, c, d, e, f])

        print '\nHEAP BUILT ==>', [i for i in h]        
        print '\n'

        self.assertEqual(h.delMax().load_factor(), .99)
        print '\nHEAP BUILT ==>', [i for i in h]
        self.assertEqual(h.delMax().load_factor(), .9)
        print '\nHEAP BUILT ==>', [i for i in h]
        self.assertEqual(h.delMax().load_factor(), .5)
        print '\nHEAP BUILT ==>', [i for i in h]
        self.assertEqual(h.delMax().load_factor(), .3)
        print '\nHEAP BUILT ==>', [i for i in h]
        self.assertEqual(h.delMax().load_factor(), .1)
        print '\nHEAP BUILT ==>', [i for i in h]
        self.assertEqual(h.delMax().load_factor(), .05)


if __name__ == '__main__':
    unittest.main()

© 2017 - . All rights reserved
Built using Jekyll