1
+ /**
2
+ * @file
3
+ * @brief [Gale-Shapley
4
+ * Algorithm](https://en.wikipedia.org/wiki/Gale%E2%80%93Shapley_algorithm):
5
+ * Stable matching between two sets.
6
+ * @details
7
+ * This implementation uses the Gale-Shapley algorithm to find stable matches
8
+ * between two equally sized sets, given their preferences.
9
+ *
10
+ * **Gale Shapley Algorithm** aims to find a stable matching between two equally
11
+ * sized sets of elements given an ordinal preference for each element. The
12
+ * algorithm was introduced by David Gale and Lloyd Shapley in 1962.
13
+ *
14
+ * Reference:
15
+ * - [Wikipedia](https://en.wikipedia.org/wiki/Gale%E2%80%93Shapley_algorithm)
16
+ * - [Stable matching
17
+ * problem](https://en.wikipedia.org/wiki/Stable_matching_problem)
18
+ * - [Original
19
+ * Paper](https://sites.math.washington.edu/~billey/classes/562.winter.2018/articles/Gale.Shapley.pdf)
20
+ *
21
+ * Math: Stable matching means no pair prefers each other over their current
22
+ * match.
23
+ *
24
+ * @author [Mastermind-sap](https://github.com/Mastermind-sap)
25
+ */
26
+
27
+ #include <assert.h> /// for assert
28
+ #include <stdio.h> /// for IO operations
29
+
30
+ #define N 4 // number of proposers and acceptors
31
+
32
+ /**
33
+ * @brief Find the index of value in an array
34
+ * @param arr array to search
35
+ * @param size length of array
36
+ * @param val value to find
37
+ * @return index of value if found, -1 otherwise
38
+ */
39
+ int index_of (int arr [], int size , int val )
40
+ {
41
+ for (int i = 0 ; i < size ; i ++ )
42
+ {
43
+ if (arr [i ] == val )
44
+ return i ;
45
+ }
46
+ return -1 ;
47
+ }
48
+
49
+ /**
50
+ * @brief Initialize matches and free status
51
+ * @param matches array to store final matches
52
+ * @param is_free_proposer array to check which proposer free
53
+ * @param proposal_index array to keep track of next index to propose for each
54
+ * proposer
55
+ * @returns void
56
+ */
57
+ void initialize (int matches [], int is_free_proposer [], int proposal_index [])
58
+ {
59
+ for (int i = 0 ; i < N ; i ++ )
60
+ {
61
+ matches [i ] = -1 ; // all acceptors unmatched
62
+ is_free_proposer [i ] = 1 ; // all proposers are free
63
+ proposal_index [i ] = 0 ; // start from first preference
64
+ }
65
+ }
66
+
67
+ /**
68
+ * @brief Find the next free proposer
69
+ * @param is_free_proposer array to check which proposer is free
70
+ * @returns index of free proposer or -1 if none free
71
+ */
72
+ int get_free_proposer (int is_free_proposer [])
73
+ {
74
+ for (int i = 0 ; i < N ; i ++ )
75
+ {
76
+ if (is_free_proposer [i ])
77
+ return i ;
78
+ }
79
+ return -1 ;
80
+ }
81
+
82
+ /**
83
+ * @brief Gale–Shapley stable matching algorithm
84
+ * @param proposer_pref preferences of proposers
85
+ * @param acceptor_pref preferences of acceptors
86
+ * @param matches output: matches[j] = i means acceptor j is matched with
87
+ * proposer i
88
+ * @returns void
89
+ */
90
+ void gale_shapley (int proposer_pref [N ][N ], int acceptor_pref [N ][N ],
91
+ int matches [])
92
+ {
93
+ int is_free_proposer [N ];
94
+ int proposal_index [N ];
95
+ initialize (matches , is_free_proposer , proposal_index );
96
+
97
+ while (1 )
98
+ {
99
+ int p = get_free_proposer (is_free_proposer ); // free proposer
100
+ if (p == -1 )
101
+ break ; // no free proposer left
102
+
103
+ int s = proposer_pref [p ][proposal_index [p ]]; // acceptor to propose
104
+ proposal_index [p ]++ ;
105
+
106
+ int current_match = matches [s ];
107
+
108
+ if (current_match == -1 )
109
+ {
110
+ // acceptor is free
111
+ matches [s ] = p ;
112
+ is_free_proposer [p ] = 0 ;
113
+ }
114
+ else
115
+ {
116
+ // acceptor already matched, check preference
117
+ int rank_new = index_of (acceptor_pref [s ], N , p );
118
+ int rank_current = index_of (acceptor_pref [s ], N , current_match );
119
+
120
+ if (rank_new < rank_current )
121
+ {
122
+ // acceptor prefers new proposer
123
+ matches [s ] = p ;
124
+ is_free_proposer [p ] = 0 ;
125
+ is_free_proposer [current_match ] = 1 ; // old match becomes free
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * @brief Print final matches
133
+ * @param matches output: matches[j] = i means acceptor j is matched with
134
+ * proposer i
135
+ */
136
+ void print_matches (int matches [])
137
+ {
138
+ printf ("Stable Matching Results:\n" );
139
+ for (int s = 0 ; s < N ; s ++ )
140
+ {
141
+ printf ("acceptor %d is matched with proposer %d\n" , s , matches [s ]);
142
+ }
143
+ }
144
+
145
+ /**
146
+ * @brief Self-test for Gale-Shapley implementation
147
+ * @returns void
148
+ */
149
+ static void test ()
150
+ {
151
+ // Test case 1:
152
+ int proposer_pref1 [N ][N ] = {
153
+ {1 , 0 , 2 , 3 }, {2 , 1 , 3 , 0 }, {2 , 1 , 0 , 3 }, {3 , 0 , 1 , 2 }};
154
+ int acceptor_pref1 [N ][N ] = {
155
+ {1 , 0 , 2 , 3 }, {3 , 0 , 1 , 2 }, {0 , 2 , 1 , 3 }, {1 , 2 , 0 , 3 }};
156
+ int matches1 [N ];
157
+ gale_shapley (proposer_pref1 , acceptor_pref1 , matches1 );
158
+ int expected1 [N ] = {3 , 0 , 2 , 1 };
159
+ for (int i = 0 ; i < N ; i ++ )
160
+ {
161
+ assert (matches1 [i ] == expected1 [i ]);
162
+ }
163
+
164
+ // Test case 2:
165
+ int proposer_pref2 [N ][N ] = {
166
+ {0 , 1 , 2 , 3 }, {0 , 1 , 2 , 3 }, {0 , 1 , 2 , 3 }, {0 , 1 , 2 , 3 }};
167
+ int acceptor_pref2 [N ][N ] = {
168
+ {0 , 1 , 2 , 3 }, {1 , 0 , 2 , 3 }, {2 , 1 , 0 , 3 }, {3 , 2 , 1 , 0 }};
169
+ int matches2 [N ];
170
+ gale_shapley (proposer_pref2 , acceptor_pref2 , matches2 );
171
+ int expected2 [N ] = {0 , 1 , 2 , 3 };
172
+ for (int i = 0 ; i < N ; i ++ )
173
+ {
174
+ assert (matches2 [i ] == expected2 [i ]);
175
+ }
176
+
177
+ // Test case 3:
178
+ int proposer_pref3 [N ][N ] = {
179
+ {3 , 2 , 1 , 0 }, {3 , 2 , 1 , 0 }, {3 , 2 , 1 , 0 }, {3 , 2 , 1 , 0 }};
180
+ int acceptor_pref3 [N ][N ] = {
181
+ {3 , 2 , 1 , 0 }, {2 , 3 , 1 , 0 }, {1 , 2 , 3 , 0 }, {0 , 1 , 2 , 3 }};
182
+ int matches3 [N ];
183
+ gale_shapley (proposer_pref3 , acceptor_pref3 , matches3 );
184
+ int expected3 [N ] = {3 , 2 , 1 , 0 };
185
+ for (int i = 0 ; i < N ; i ++ )
186
+ {
187
+ assert (matches3 [i ] == expected3 [i ]);
188
+ }
189
+
190
+ printf ("All Gale-Shapley tests have successfully passed!\n" );
191
+ }
192
+
193
+ /**
194
+ * @brief Main function with test case
195
+ * @returns 0 on exit
196
+ */
197
+ int main ()
198
+ {
199
+ test (); // Run Gale-Shapley self-test
200
+ return 0 ;
201
+ }
0 commit comments