From cde1672dca14968f9e914258bed495ff70b475f8 Mon Sep 17 00:00:00 2001 From: Nguyen Phuc Chuong <72879387+hollowcrust@users.noreply.github.com> Date: Fri, 4 Oct 2024 21:09:03 +0800 Subject: [PATCH 1/2] feat: Create gray_code.cpp (#2750) * Create gray_code.cpp * Update gray_code.cpp Remove extra lines, add bit_manipulation and gray_code namespaces, add negative number test --- bit_manipulation/gray_code.cpp | 113 +++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 bit_manipulation/gray_code.cpp diff --git a/bit_manipulation/gray_code.cpp b/bit_manipulation/gray_code.cpp new file mode 100644 index 000000000..952758dea --- /dev/null +++ b/bit_manipulation/gray_code.cpp @@ -0,0 +1,113 @@ +/** + * @brief Program to generate n-bit [Gray + * code](https://en.wikipedia.org/wiki/Gray_code) + * + * @details + * Gray code is a binary numeral system + * where consecutive values differ in exactly 1 bit. + * The following code offers one of many possible Gray codes + * given some pre-determined number of bits. + */ + +#include /// for gray code representation +#include /// for assert +#include /// for IO operations +#include /// for vector data structure + +/** + * @namespace bit_manipulation + * @brief Bit manipulation algorithms + */ +namespace bit_manipulation { +/** + * @namespace gray_code + * @brief Generate n-bit Gray code + */ +namespace gray_code { +/** + * @brief The main function to generate n-bit Gray code + * + * @param n Number of bits + * @return A vector that stores the n-bit Gray code + */ +std::vector> gray_code_generation(int n) { + std::vector> gray_code = {}; // Initialise empty vector + + // No Gray codes for non-positive values of n + if (n <= 0) { + return gray_code; + } + + int total_codes = 1 << n; // Number of n-bit gray codes + + for (int i = 0; i < total_codes; i++) { + int gray_num = i ^ (i >> 1); // Gray code formula + gray_code.push_back(std::bitset<32>(gray_num)); // Store the value + } + + return gray_code; +} +} // namespace gray_code +} // namespace bit_manipulation + +/** + * @brief Self-test implementation + * + * @returns void + */ +static void test() { + std::vector> gray_code_negative_1 = {}; + + std::vector> gray_code_0 = {}; + + std::vector> gray_code_1 = { + std::bitset<32>(0), std::bitset<32>(1) + }; + + std::vector> gray_code_2 = { + std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2) + }; + + std::vector> gray_code_3 = { + std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2), + std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4) + }; + + std::vector> gray_code_4 = { + std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2), + std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4), + std::bitset<32>(12), std::bitset<32>(13), std::bitset<32>(15), std::bitset<32>(14), + std::bitset<32>(10), std::bitset<32>(11), std::bitset<32>(9), std::bitset<32>(8) + }; + + std::vector> gray_code_5 = { + std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2), + std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4), + std::bitset<32>(12), std::bitset<32>(13), std::bitset<32>(15), std::bitset<32>(14), + std::bitset<32>(10), std::bitset<32>(11), std::bitset<32>(9), std::bitset<32>(8), + std::bitset<32>(24), std::bitset<32>(25), std::bitset<32>(27), std::bitset<32>(26), + std::bitset<32>(30), std::bitset<32>(31), std::bitset<32>(29), std::bitset<32>(28), + std::bitset<32>(20), std::bitset<32>(21), std::bitset<32>(23), std::bitset<32>(22), + std::bitset<32>(18), std::bitset<32>(19), std::bitset<32>(17), std::bitset<32>(16) + }; + + // invalid values for n + assert(bit_manipulation::gray_code::gray_code_generation(-1) == gray_code_negative_1); + assert(bit_manipulation::gray_code::gray_code_generation(0) == gray_code_0); + + // valid values for n + assert(bit_manipulation::gray_code::gray_code_generation(1) == gray_code_1); + assert(bit_manipulation::gray_code::gray_code_generation(2) == gray_code_2); + assert(bit_manipulation::gray_code::gray_code_generation(3) == gray_code_3); + assert(bit_manipulation::gray_code::gray_code_generation(4) == gray_code_4); + assert(bit_manipulation::gray_code::gray_code_generation(5) == gray_code_5); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); //Run self-test implementation + return 0; +} From 901f231d592ddc7fa41c2f809adb3fd6cc620927 Mon Sep 17 00:00:00 2001 From: B Karthik <115967163+BKarthik7@users.noreply.github.com> Date: Fri, 4 Oct 2024 18:48:54 +0530 Subject: [PATCH 2/2] feat: Added gale_shapley.cpp in greedy_algorithms (#2743) * Added gale_shapley.cpp in greedy_algorithms * Added gale_shapley.cpp in greedy_algorithms * Genralized GaleShapley with reviewed change * fix: added description * fix: fixed nameing of namespace * fix: reviewed changes * fix: reviewed changes * TestCase Empty vector * function description * Update greedy_algorithms/gale_shapley.cpp Co-authored-by: realstealthninja <68815218+realstealthninja@users.noreply.github.com> * Update greedy_algorithms/gale_shapley.cpp Co-authored-by: realstealthninja <68815218+realstealthninja@users.noreply.github.com> * Change type * typechange with header documentation --------- Co-authored-by: realstealthninja <68815218+realstealthninja@users.noreply.github.com> --- greedy_algorithms/gale_shapley.cpp | 129 +++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 greedy_algorithms/gale_shapley.cpp diff --git a/greedy_algorithms/gale_shapley.cpp b/greedy_algorithms/gale_shapley.cpp new file mode 100644 index 000000000..ddc6298fa --- /dev/null +++ b/greedy_algorithms/gale_shapley.cpp @@ -0,0 +1,129 @@ +/** + * @file + * @brief [Gale Shapley Algorithm](https://en.wikipedia.org/wiki/Gale%E2%80%93Shapley_algorithm) + * @details + * This implementation utilizes the Gale-Shapley algorithm to find stable matches. + * + * **Gale Shapley Algorithm** aims to find a stable matching between two equally sized + * sets of elements given an ordinal preference for each element. The algorithm was + * introduced by David Gale and Lloyd Shapley in 1962. + * + * Reference: + * [Wikipedia](https://en.wikipedia.org/wiki/Gale%E2%80%93Shapley_algorithm) + * [Wikipedia](https://en.wikipedia.org/wiki/Stable_matching_problem) + * + * @author [B Karthik](https://github.com/BKarthik7) + */ + +#include /// for std::u32int_t +#include /// for std::vector +#include /// for std::find +#include /// for assert + +/** + * @namespace + * @brief Greedy Algorithms + */ +namespace greedy_algorithms { +/** + * @namespace + * @brief Functions for the Gale-Shapley Algorithm + */ +namespace stable_matching { +/** + * @brief The main function that finds the stable matching between two sets of elements + * using the Gale-Shapley Algorithm. + * @note This doesn't work on negative preferences. the preferences should be continuous integers starting from + * 0 to number of preferences - 1. + * @param primary_preferences the preferences of the primary set should be a 2D vector + * @param secondary_preferences the preferences of the secondary set should be a 2D vector + * @returns matches the stable matching between the two sets + */ +std::vector gale_shapley(const std::vector>& secondary_preferences, const std::vector>& primary_preferences) { + std::uint32_t num_elements = secondary_preferences.size(); + std::vector matches(num_elements, -1); + std::vector is_free_primary(num_elements, true); + std::vector proposal_index(num_elements, 0); // Tracks the next secondary to propose for each primary + + while (true) { + int free_primary_index = -1; + + // Find the next free primary + for (std::uint32_t i = 0; i < num_elements; i++) { + if (is_free_primary[i]) { + free_primary_index = i; + break; + } + } + + // If no free primary is found, break the loop + if (free_primary_index == -1) break; + + // Get the next secondary to propose + std::uint32_t secondary_to_propose = primary_preferences[free_primary_index][proposal_index[free_primary_index]]; + proposal_index[free_primary_index]++; + + // Get the current match of the secondary + std::uint32_t current_match = matches[secondary_to_propose]; + + // If the secondary is free, match them + if (current_match == -1) { + matches[secondary_to_propose] = free_primary_index; + is_free_primary[free_primary_index] = false; + } else { + // Determine if the current match should be replaced + auto new_proposer_rank = std::find(secondary_preferences[secondary_to_propose].begin(), + secondary_preferences[secondary_to_propose].end(), + free_primary_index); + auto current_match_rank = std::find(secondary_preferences[secondary_to_propose].begin(), + secondary_preferences[secondary_to_propose].end(), + current_match); + + // If the new proposer is preferred over the current match + if (new_proposer_rank < current_match_rank) { + matches[secondary_to_propose] = free_primary_index; + is_free_primary[free_primary_index] = false; + is_free_primary[current_match] = true; // Current match is now free + } + } + } + + return matches; +} +} // namespace stable_matching +} // namespace greedy_algorithms + +/** + * @brief Self-test implementations + * @returns void + */ +static void tests() { + // Test Case 1 + std::vector> primary_preferences = {{0, 1, 2, 3}, {2, 1, 3, 0}, {1, 2, 0, 3}, {3, 0, 1, 2}}; + std::vector> secondary_preferences = {{1, 0, 2, 3}, {3, 0, 1, 2}, {0, 2, 1, 3}, {1, 2, 0, 3}}; + assert(greedy_algorithms::stable_matching::gale_shapley(secondary_preferences, primary_preferences) == std::vector({0, 2, 1, 3})); + + // Test Case 2 + primary_preferences = {{0, 2, 1, 3}, {2, 3, 0, 1}, {3, 1, 2, 0}, {2, 1, 0, 3}}; + secondary_preferences = {{1, 0, 2, 3}, {3, 0, 1, 2}, {0, 2, 1, 3}, {1, 2, 0, 3}}; + assert(greedy_algorithms::stable_matching::gale_shapley(secondary_preferences, primary_preferences) == std::vector({0, 3, 1, 2})); + + // Test Case 3 + primary_preferences = {{0, 1, 2}, {2, 1, 0}, {1, 2, 0}}; + secondary_preferences = {{1, 0, 2}, {2, 0, 1}, {0, 2, 1}}; + assert(greedy_algorithms::stable_matching::gale_shapley(secondary_preferences, primary_preferences) == std::vector({0, 2, 1})); + + // Test Case 4 + primary_preferences = {}; + secondary_preferences = {}; + assert(greedy_algorithms::stable_matching::gale_shapley(secondary_preferences, primary_preferences) == std::vector({})); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + tests(); // Run self-test implementations + return 0; +}