When writing a member function of the HAMT class, the member function can access resources directly (eg, self._item) and/or call other member functions to get work done, depending on preference and clarity. Beginning with the hamt_hw.py file, find all the member functions with undefined bodies (I've written pass in each). Finish writing these functions so that they work as described in their comments. Do not change any existing code in the file except the definitions of the previously undefined functions and the testing code at the bottom. When wrting the new functions, you may add helper methods or new parameters with default values if you wish. At the bottom of the supplied file is some indented code which is executed whenever you run the supplied file directly. This is a good place to do your testing. Write your test cases here so that I can see them. Leave all your testing code indented so that it only runs when __name__ == '__main__'. HERE IS hamt_hw.py # This implementation requires objects in the set be hashable. # Resulting trie will have expected log height if hash is random. # In this implementaiton the root node always has _item == None from functools import reduce class hamt: DEG = 4 # Children per node (can be set to any power of 2) BITS = 2 # Should be log2(DEG), bits needed to select child MASK = 0b11 # Should be BITS one-bits def __init__(self, item = None, children = None): self._item = item if children == None: self._children = [None] * hamt.DEG # List of DEG Nones else: self._children = children # returns copy of self node with child i set to node x def _updatechild(self, i, x): updatedchildlist = list(self._children) # copy self's child list updatedchildlist[i] = x # update child i return hamt(self._item, updatedchildlist) # build and return new node # Returns reference to new root if change made, else None def _add(self, item, hashbits): if self._item == item: # This node matches item. Return None to indicate no change. return None else: # Continue search using hashbits to pick direction child_num = hashbits & hamt.MASK if self._children[child_num] == None: # item not in trie. Add it as new leaf node. return self._updatechild(child_num, hamt(item)) else: # Ask appropriate child to add item, receive updated reference shiftedhashbits = hashbits >> hamt.BITS newchild = self._children[child_num]._add(item, shiftedhashbits) if newchild == None: return None else: return self._updatechild(child_num, newchild) def add(self, item): # Pass item and hashbits to private recursive helper return self._add(item, hash(item)) # Returns True if trie has no items, else False. Rutime O(1). def empty(self): pass # Returns True if item in trie, else False. Expected rutime O(log n). def contains(self, item): pass # Returns number of items in trie. Runtime O(n). def __len__(self): pass # Returns HAMT that is union of self and other. Expected rutime O(n log n). def union(self, other): pass # Adds self's item string to acc list, then ask each chil.