Your code can be optimized in several ways, including improvements to the recursion and type annotations. Here's a revised version of your code:
1. Improved the `powerset` function to avoid recalculating the same subsets.
2. Optimized the recursive function to avoid redundant data and unnecessary recalculations.
3. Added type hints to enhance readability and debugging.
from itertools import chain, combinations
from typing import Generator, List, Set, Tuple
def powerset(s: Set[int], minsize: int) -> Generator[Tuple[int, ...], None, None]:
"""
Computes a generator with all the set objects representing subsets of 's' of size at least 'minsize'
"""
return chain.from_iterable(combinations(s, r) for r in range(minsize, len(s)+1))
def GenHyperTrees(d: int) -> Generator[List[Tuple[int, ...]], None, None]:
"""
Generates all hypertrees with d hyperedges and range(d) as vertex set.
"""
def main_loop(P: List[Tuple[int, ...]], union: Set[int], left: Set[int]) -> Generator[List[Tuple[int, ...]], None, None]:
if len(P) == d - 1:
for v in union:
yield P + [tuple(left) + (v,)]
return
for subset in powerset(left, minsize=0):
subset_set = set(subset)
new_union = union.union(subset_set)
new_left = left.difference(subset_set)
for v in left:
new_edge = tuple(subset_set) + (v,)
yield from main_loop(P + [new_edge], new_union, new_left)
space = set(range(d))
for A in powerset(space, minsize=1):
A_set = set(A)
for result in main_loop([A], A_set, space.difference(A_set)):
yield result
# Example usage
for hypertree in GenHyperTrees(3):
print(hypertree)