import networkx as nx

def max_weight_matching[T1, T2](
    edges: dict[tuple[T1, T2], float],
    min_weight: bool = False
) -> dict[T1, T2]:
    """ Takes as edges a dictionary T1 -> [T2], with a float value giving the weight for each match in the
        second set.
        Returns the maximum weight bipartite matching as a list of tuples (T1, T2).
        If min_weight is true, uses negative weight values.
    """
    # Construct a weighted bipartite graph
    g = nx.Graph()
    for (a, b), w in edges.items():
        g.add_node(a)
        g.add_node(b)
        g.add_edge(a, b, weight = ((2 - w) if min_weight else w))

    # Find the maximal matching
    matching = nx.max_weight_matching(g, maxcardinality = True)
    keys: set[T1] = {k for k, _ in edges.keys()}
    out: dict[T1, T2] = dict()
    for a, b in matching:
        if a in keys:
            out[a] = b
        elif b in keys:
            out[b] = a
        else:
            raise RuntimeError

    return out
