def make_alltoall_subproblem_collective_and_topology(topology, num_copies, relay_nodes, bw=1, share_bw=False):
    local_nodes = topology.num_nodes()
    remote_node = local_nodes
    links = [[0 for _ in range((local_nodes + 1))] for _ in range((local_nodes + 1))]
    for src in range(local_nodes):
        for dst in range(local_nodes):
            links[dst][src] = topology.link(src, dst)
    for relay in relay_nodes:
        links[remote_node][relay] = bw
        links[relay][remote_node] = bw
    switches = topology.switches.copy()
    if share_bw:
        switches.append((relay_nodes, [(num_nodes + 1)], bw, 'remote_out'))
        switches.append(([(num_nodes + 1)], relay_nodes, bw, 'remote_in'))
    collective = _alltoall_subproblem(local_nodes, num_copies)
    topology = Topology(f"Subtopo(local={topology.name},relays=({','.join((str(i) for i in relay_nodes))}))", links, topology.switches)
    return (collective, topology)
def make_alltoall_subproblem_collective_and_topology(topology, num_copies, relay_nodes, bw=1, share_bw=False):
    local_nodes = topology.num_nodes()
    remote_node = local_nodes
    links = [[0 for _ in range((local_nodes + 1))] for _ in range((local_nodes + 1))]
    for src in range(local_nodes):
        for dst in range(local_nodes):
            links[dst][src] = topology.link(src, dst)
    for relay in relay_nodes:
        links[remote_node][relay] = bw
        links[relay][remote_node] = bw
    switches = topology.switches.copy()
    if share_bw:
        switches.append((relay_nodes, [(num_nodes + 1)], bw, 'remote_out'))
        switches.append(([(num_nodes + 1)], relay_nodes, bw, 'remote_in'))
    collective = _alltoall_subproblem(local_nodes, num_copies)
    topology = Topology(f"Subtopo(local={topology.name},relays=({','.join((str(i) for i in relay_nodes))}))", links, topology.switches)
    return (collective, topology)