<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def get_hyperedge_id(self, tail, head):
 """From a tail and head set of nodes, returns the ID of the hyperedge that these sets comprise. :param tail: iterable container of references to nodes in the tail of the hyperedge to be added :param head: iterable container of references to nodes in the head of the hyperedge to be added :returns: str -- ID of the hyperedge that has that the specified tail and head sets comprise. :raises: ValueError -- No such hyperedge exists. Examples: :: (("A", "B"), ("C"), {weight: 2}), (set(["B"]), set(["A", "C"]))) """

        frozen_tail = frozenset(tail)
        frozen_head = frozenset(head)

        if not self.has_hyperedge(frozen_tail, frozen_head):
            raise ValueError("No such hyperedge exists.")

        return self._successors[frozen_tail][frozen_head]