<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def heap(height=3, is_max=True, is_perfect=False):
 """Generate a random heap and return its root node. :param height: Height of the heap (default: 3, range: 0 - 9 inclusive). :type height: int :param is_max: If set to True (default: True), generate a max heap. If set to False, generate a min heap. A binary tree with only the root node is considered both a min and max heap. :type is_max: bool :param is_perfect: If set to True (default: False), a perfect heap with all levels filled is returned. If set to False, a perfect heap may still be generated by chance. :type is_perfect: bool :return: Root node of the heap. :rtype: binarytree.Node :raise binarytree.exceptions.TreeHeightError: If height is invalid. **Example**: .. doctest:: 3 True .. doctest:: 4 True .. doctest:: 5 True True .. doctest:: Traceback (most recent call last):
 TreeHeightError: height must be an int between 0 - 9 """

    _validate_tree_height(height)
    values = _generate_random_node_values(height)

    if not is_perfect:
        # Randomly cut some of the leaf nodes away
        random_cut = random.randint(2 ** height, len(values))
        values = values[:random_cut]

    if is_max:
        negated = [-v for v in values]
        heapq.heapify(negated)
        return build([-v for v in negated])
    else:
        heapq.heapify(values)
        return build(values)