Source code for toqito.perms.perfect_matchings

"""Perfect matchings refers to ways of grouping an even number of objects into pairs."""

import numpy as np


[docs] def perfect_matchings(num: list[int] | int | np.ndarray) -> np.ndarray: r"""Give all perfect matchings of `num` objects. The input can be either an even natural number (the number of objects to be matched) or a `numpy` array containing an even number of distinct objects to be matched. Returns all perfect matchings of a given list of objects. That is, it returns all ways of grouping an even number of objects into pairs. This function is adapted from QETLAB. [@QETLAB_link]. Examples: This is an example of how to generate all perfect matchings of the numbers 0, 1, 2, 3. ```python exec="1" source="above" from toqito.perms import perfect_matchings print(perfect_matchings(4)) ``` Args: num: Either an even integer, indicating that you would like all perfect matchings of the integers 0, 1, ... N-1, or a `list` or `np.array` containing an even number of distinct entries, indicating that you would like all perfect matchings of those entries. Returns: An array containing all valid perfect matchings of size `num`. """ if isinstance(num, int): num = np.arange(num) if isinstance(num, list): num = np.array(num) # Base case, `num = 2`: only one perfect matching. if (len_num := len(num)) == 2: return num # There are no perfect matchings of an odd number of objects. if len_num % 2 == 1: return np.zeros((0, len_num)) # Recursive step: build perfect matchings from smaller ones. # Only do the recursive step once instead of `num-1` times: we will then tweak # the output n-1 times. lower_fac = perfect_matchings(num[2:]) if len(lower_fac.shape) == 1: lfac_size = 1 else: lfac_size = lower_fac.shape[0] matchings = np.zeros((0, len_num), dtype=int) # Now build the perfect matchings we actually want. for j in range(1, len_num): tlower_fac = lower_fac.copy() tlower_fac[tlower_fac == num[j]] = num[1] one_vec = np.ones((lfac_size, 2), dtype=int) * [num[0], num[j]] if lfac_size == 1: one_vec = one_vec[0] s_vec = np.hstack((one_vec, tlower_fac)) matchings = np.vstack((matchings, s_vec)) return matchings