Finds the maximal phrase in the run starting from the given index.  It uses the dictionary to find sequences of ids
         that can be merged into a phrase.
        :param run: a run of ids
        :param idx: the position in the run to start looking for a merge sequence
        :param dictionary: the dictionary to use to determine if a merge id is present.  This should be a dictionary of
        dictionaries.  Each inner dictionary is a continuation of a mergable run.  The end of a run is donated by a None key
        in a dictionary.  The value associated with the None key is the integer of the merge id.
        :return: phrase_id or None, index after the phrase_id or the current index if no phrase was found.

def return_max_phrase(run, idx, dictionary):
        """
        Finds the maximal phrase in the run starting from the given index.  It uses the dictionary to find sequences of ids
         that can be merged into a phrase.
        :param run: a run of ids
        :param idx: the position in the run to start looking for a merge sequence
        :param dictionary: the dictionary to use to determine if a merge id is present.  This should be a dictionary of
        dictionaries.  Each inner dictionary is a continuation of a mergable run.  The end of a run is donated by a None key
        in a dictionary.  The value associated with the None key is the integer of the merge id.
        :return: phrase_id or None, index after the phrase_id or the current index if no phrase was found.
        """
        if idx < len(run) and run[idx] in dictionary:
            id = run[idx]
            rv, rv_idx = PhraseDictionary.return_max_phrase(run, idx + 1, dictionary[id])
            if rv is not None:
                return rv, rv_idx

        if None in dictionary:
            return dictionary[None], idx
        else:
            return None, None