<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def separate_groups(groups, key, total):
 """Separate the group into overloaded and under-loaded groups. The revised over-loaded groups increases the choice space for future selection of most suitable group based on search criteria. For example: Given the groups (a:4, b:4, c:3, d:2) where the number represents the number of elements for each group. smart_separate_groups sets 'a' and 'c' as optimal, 'b' as over-loaded and 'd' as under-loaded. separate-groups combines 'a' with 'b' as over-loaded, allowing to select between these two groups to transfer the element to 'd'. :param groups: list of groups :param key: function to retrieve element count from group :param total: total number of elements to distribute :returns: sorted lists of over loaded (descending) and under loaded (ascending) group """

    optimum, extra = compute_optimum(len(groups), total)
    over_loaded, under_loaded, optimal = _smart_separate_groups(groups, key, total)
    # If every group is optimal return
    if not extra:
        return over_loaded, under_loaded
    # Some groups in optimal may have a number of elements that is optimum + 1.
    # In this case they should be considered over_loaded.
    potential_under_loaded = [
        group for group in optimal
        if key(group) == optimum
    ]
    potential_over_loaded = [
        group for group in optimal
        if key(group) > optimum
    ]
    revised_under_loaded = under_loaded + potential_under_loaded
    revised_over_loaded = over_loaded + potential_over_loaded
    return (
        sorted(revised_over_loaded, key=key, reverse=True),
        sorted(revised_under_loaded, key=key),
    )