Table Talk TuningDRAFT
We needed to arrange the tables for a real wedding. That practical problem became the MiniZinc model in No More Awkward Silences with Table Talk Tuning, a paper by Martin Butler and me to be presented at ModRef 2026.
A seating plan can satisfy every capacity and grouping request and still leave someone with little to talk about. That gap was visible in the actual planning problem, so the model treats conversational fit as part of the assignment rather than something to inspect afterwards.
The input records the available tables, their capacities, groups that should sit together or apart, and each guest’s interest in a set of conversation topics. The model assigns guests to tables; the exact seat order around each table is left for a later step.
The MiniZinc model
The main artefact is a portable MiniZinc model of the complete problem. Its central decision is deliberately simple: one variable records the table assigned to each guest. A global cardinality constraint connects those assignments to table occupancy, while direct constraints handle groups that must sit together or apart.
% Table assignment for each guestarray[Guests] of var Tables: table_of;
% Number of guests at each tablearray[Tables] of var 0..max(table_capacities): occupancy;
constraint global_cardinality_closed( table_of, [table | table in Tables], occupancy);
constraint forall (table in Tables) ( occupancy[table] <= table_capacities[table]);
constraint forall (group in same_table) ( forall (g1, g2 in group where g1 < g2) ( table_of[g1] = table_of[g2] ));constraint forall (group in different_tables) ( forall (g1, g2 in group where g1 < g2) ( table_of[g1] != table_of[g2] ));Once the hard constraints are satisfied, the model still has to choose between many feasible plans. It first prefers plans with fewer empty seats, less slack at the emptiest table, and a lower total imbalance under the model’s simple gender-balance measure. It then considers the weakest and total conversational scores. The last two terms need a way to decide whether a topic has enough support at a table.
Finding a supported topic for each guest
For each guest, the model asks whether there is a topic they care about that is also supported by a strict majority of their table. It protects the guest with the weakest conversational connection before improving the total interest across all guests.
The complete interest table from the paper provides the input for the running example. The first five guests are currently assigned to table 19. Farah, Niko, and Sana sit elsewhere, which helps show that these are individual interest scores rather than fixed guest clusters.
Guest interests in the running example
The highlighted row gives the strict-majority topic floor for the five guests at table 19.
| Guest | Table | Jazz | Hiking | Food | Garden | Travel | Games |
|---|---|---|---|---|---|---|---|
| Mina | Table 19 | 9 | 3 | 5 | 4 | 1 | 2 |
| Theo | Table 19 | 8 | 6 | 5 | 4 | 2 | 1 |
| Leila | Table 19 | 7 | 5 | 4 | 3 | 1 | 2 |
| Oskar | Table 19 | 1 | 4 | 9 | 2 | 2 | 1 |
| Petra | Table 19 | 2 | 2 | 1 | 8 | 1 | 1 |
| Topic floor | Table 19 | 7 | 4 | 5 | 4 | 1 | 1 |
| Farah | Table X | 6 | 2 | 3 | 2 | 8 | 9 |
| Niko | Table Y | 2 | 3 | 4 | 2 | 7 | 6 |
| Sana | Table Z | 3 | 3 | 2 | 2 | 9 | 7 |
The figure pulls out the three topics that work best for someone at table 19. At a table of five, the topic floor is the third-highest guest score: the highest level supported by a strict majority. Mina, Theo, and Leila get 7 from jazz. Oskar instead gets 5 from food, while Petra gets 4 from gardening. The model does not require one topic to work for everybody; it looks for one supported topic from each guest’s perspective.
In the MiniZinc model, base_interest contains the majority-supported score for each table and topic. The score available to a guest is capped by their own interest in that topic. Taking the maximum then gives each guest their best supported topic.
array[Guests] of var int: best_table_interest = [ let { array[Topics] of var int: table_interest = [ min( base_interest[table_of[guest], topic], guests[guest].interest[topic] ) | topic in Topics ] } in max(table_interest)| guest in Guests];
var int: min_interest = min(best_table_interest);var int: total_interest = sum(best_table_interest);Five priorities, one objective
MiniZinc exposes one optimisation objective to ordinary FlatZinc back ends, while Table Talk Tuning has five priorities. The model therefore uses mixed-radix weights. Each weight is large enough that improving its objective level outweighs every possible change in all lower-priority levels. This preserves the intended order inside one scalar objective.
var int: goal = total_slack * total_slack_weight+ max_slack * max_slack_weight+ total_imbalance * imbalance_weight+ min_interest_penalty * min_interest_weight+ total_interest_penalty * total_interest_weight;
solve minimize goal;To check whether the conversation terms actually change the seating, we removed them and then evaluated both returned seatings on the conversation measures. In 35 of the 45 synthetic cases, both versions returned a feasible seating within the 60-second limit. On those paired cases, the full objective produced a better table-talk score in 28 and tied in seven; it was never worse on the conversation measures. Most of the difference came from total interest, while minimum interest usually stayed fixed.
The paper also includes synthetic instances from 10 to 150 guests and a native Gecode implementation for comparing the MiniZinc model’s scalar objective with direct lexicographic and sequential optimisation. The complete portable MiniZinc model is available with this post.
The wedding plan supplied the practical test. The conversation terms had to improve real assignments without displacing the structural requests. The resulting MiniZinc model makes that tradeoff explicit and can be adapted to other table-assignment problems. The complete model and evaluation are described in the paper.