def get_closure(rel, v):
    """
    Return transitive closure of values v1 such that "v rel v1",
    given a dictionary of direct relations.

    Termination depends on directed relation; i.e.

        v1 in rel(v) => v not in get_closure(rel, v1)

    Thus the get_closure recursive call can never include v, as
    all values (v1) for which get_closure is called recursively are 
    values that have been added to the closure result (cv).
    """
    if v not in rel:
        return set()
    v1s = rel[v]
    cv  = v1s.union(*[get_closure(rel, v1) for v1 in v1s])
    return cv