So I tested your code @Colab with a smaller group of 20 persons, defined as part of the code instead of loading from an xlsx file:
# 20 People names
people_names = [
"Alice", "Bob", "Charlie", "David", "Eve", "Frank", "Grace", "Hank", "Ivy", "Jack",
"Kate", "Leo", "Mia", "Nick", "Olivia", "Paul", "Quinn", "Rachel", "Steve", "Tina"
]
# Generate a symmetric affinity matrix (values 0-5, 0 on the diagonal)
np.random.seed(42) # For reproducibility
affinity_matrix = np.random.randint(0, 6, (20, 20))
np.fill_diagonal(affinity_matrix, 0) # No self-affinity
affinity_matrix = (affinity_matrix + affinity_matrix.T) // 2 # Make it symmetric
# Run optimization
groups = optimize_groups(affinity_matrix, min_size=3, max_size=6)
# Print results
if groups:
for idx, group in enumerate(groups, start=1):
print(f"Group {idx}: {group}")
else:
print("No valid grouping found.")
… and got a result after approx. 50s.
Basically, the code works as expected, but not very efficiently.
Going thru your code, I noticed that you make use of .add_multiplication_equality()
quite a lot.
While convenient .add_multiplication_equality() is rather costly.
An alternative, linear formulation helps to reduce the solver time by an order of magnitude:
model.add(pair_var <= x[i, g])
model.add(pair_var <= x[j, g])
model.add(pair_var >= x[i, g] + x[j, g] - 1)
… and produces the result after 2-5s (also @Colab).
As mentioned in my previous comments, you may also want to have a closer look at the example of a wedding tables’ seating from ortools for further inspiration and improvement potentials.