diff --git a/docs/utils/utils.rst b/docs/utils/utils.rst index 17a2a7f7f..fc85b87d3 100644 --- a/docs/utils/utils.rst +++ b/docs/utils/utils.rst @@ -57,7 +57,7 @@ Layout Utils .. doxygenfunction:: fiction::normalize_layout_coordinates .. doxygenfunction:: fiction::convert_to_siqad_coordinates .. doxygenfunction:: fiction::convert_to_fiction_coordinates - +.. doxygenfunction:: fiction::random_coordinate Placement Utils diff --git a/include/fiction/utils/layout_utils.hpp b/include/fiction/utils/layout_utils.hpp index 777005679..83b674238 100644 --- a/include/fiction/utils/layout_utils.hpp +++ b/include/fiction/utils/layout_utils.hpp @@ -11,9 +11,13 @@ #include "fiction/traits.hpp" #include "fiction/types.hpp" +#include #include #include #include +#include +#include +#include namespace fiction { @@ -350,6 +354,49 @@ Lyt convert_to_fiction_coordinates(const sidb_cell_clk_lyt_siqad& lyt) noexcept return lyt_new; } +/** + * Generates a random coordinate within the region spanned by two given coordinates. The two given coordinates form the + * top left corner and the bottom right corner of the spanned region. + * + * @OffsetCoordinateType The coordinate implementation to be used. + * @param coordinate1 Top left Coordinate. + * @param coordinate2 Bottom right Coordinate (coordinate order is not important, automatically swapped if + * necessary). + * @return Randomly generated coordinate. + */ +template +CoordinateType random_coordinate(CoordinateType coordinate1, CoordinateType coordinate2) noexcept +{ + static_assert(std::is_same_v || std::is_same_v || + std::is_same_v, + "CoordinateType is unknown"); + + static std::mt19937_64 generator(std::random_device{}()); + + if (coordinate1 > coordinate2) + { + std::swap(coordinate1, coordinate2); + } + + if constexpr (std::is_same_v) + { + std::uniform_int_distribution<> dist_x(coordinate1.x, coordinate2.x); + std::uniform_int_distribution<> dist_y(coordinate1.y, coordinate2.y); + std::uniform_int_distribution<> dist_z(0, 1); + + return std::clamp(siqad::coord_t{dist_x(generator), dist_y(generator), dist_z(generator)}, coordinate1, + coordinate2); + } + + else + { + std::uniform_int_distribution<> dist_x(coordinate1.x, coordinate2.x); + std::uniform_int_distribution<> dist_y(coordinate1.y, coordinate2.y); + std::uniform_int_distribution<> dist_z(coordinate1.z, coordinate2.z); + + return {dist_x(generator), dist_y(generator), dist_z(generator)}; + } +} } // namespace fiction diff --git a/test/utils/layout_utils.cpp b/test/utils/layout_utils.cpp index 9ddf8871e..a41d278dc 100644 --- a/test/utils/layout_utils.cpp +++ b/test/utils/layout_utils.cpp @@ -232,3 +232,109 @@ TEMPLATE_TEST_CASE("Convert SiQAD layout to cube::coord_t coordinate layout", "[ CHECK(lyt_transformed.get_cell_name({5, 6}) == "output cell"); } } + +TEST_CASE("Generate random offset::ucoord_t coordinate", "[layout-utils]") +{ + SECTION("two identical cells as input") + { + const auto randomly_generated_coordinate = random_coordinate({0, 0, 0}, {0, 0, 0}); + CHECK(randomly_generated_coordinate.x == 0); + CHECK(randomly_generated_coordinate.y == 0); + CHECK(randomly_generated_coordinate.z == 0); + + const auto randomly_generated_coordinate_second = random_coordinate({1, 0, 0}, {1, 0, 0}); + CHECK(randomly_generated_coordinate_second.x == 1); + CHECK(randomly_generated_coordinate_second.y == 0); + CHECK(randomly_generated_coordinate_second.z == 0); + } + + SECTION("two unidentical cells as input, correct order") + { + const auto randomly_generated_coordinate_second = random_coordinate({1, 1, 1}, {5, 2, 3}); + CHECK(randomly_generated_coordinate_second.x >= 1); + CHECK(randomly_generated_coordinate_second.x <= 5); + CHECK(randomly_generated_coordinate_second.y <= 2); + CHECK(randomly_generated_coordinate_second.y >= 0); + CHECK(randomly_generated_coordinate_second.z <= 3); + CHECK(randomly_generated_coordinate_second.z >= 1); + } + + SECTION("two unidentical cells as input, switched correct order") + { + const auto randomly_generated_coordinate = random_coordinate({5, 2, 3}, {1, 1, 1}); + CHECK(randomly_generated_coordinate.x >= 1); + CHECK(randomly_generated_coordinate.x <= 5); + CHECK(randomly_generated_coordinate.y <= 2); + CHECK(randomly_generated_coordinate.y >= 0); + CHECK(randomly_generated_coordinate.z <= 3); + CHECK(randomly_generated_coordinate.z >= 1); + } +} + +TEST_CASE("Generate random cube::coord_t coordinate", "[layout-utils]") +{ + SECTION("two identical cells as input") + { + const auto randomly_generated_coordinate = random_coordinate({-10, -5, 0}, {-10, -5, 0}); + CHECK(randomly_generated_coordinate.x == -10); + CHECK(randomly_generated_coordinate.y == -5); + CHECK(randomly_generated_coordinate.z == 0); + + const auto randomly_generated_coordinate_second = random_coordinate({1, 0, 0}, {1, 0, 0}); + CHECK(randomly_generated_coordinate_second.x == 1); + CHECK(randomly_generated_coordinate_second.y == 0); + CHECK(randomly_generated_coordinate_second.z == 0); + } + + SECTION("two unidentical cells as input, correct order") + { + const auto randomly_generated_coordinate = random_coordinate({-10, -1, 3}, {-10, -1, 6}); + CHECK(randomly_generated_coordinate.x == -10); + CHECK(randomly_generated_coordinate.y == -1); + CHECK(randomly_generated_coordinate.z >= 3); + CHECK(randomly_generated_coordinate.z <= 6); + } + + SECTION("two unidentical cells as input, switched correct order") + { + const auto randomly_generated_coordinate = random_coordinate({-10, -1, 6}, {-10, -1, 3}); + CHECK(randomly_generated_coordinate.x == -10); + CHECK(randomly_generated_coordinate.y == -1); + CHECK(randomly_generated_coordinate.z >= 3); + CHECK(randomly_generated_coordinate.z <= 6); + } +} + +TEST_CASE("Generate random siqad::coord_t coordinate", "[layout-utils]") +{ + SECTION("two identical cells as input") + { + const auto randomly_generated_coordinate = random_coordinate({-10, -5, 0}, {-10, -5, 0}); + CHECK(randomly_generated_coordinate.x == -10); + CHECK(randomly_generated_coordinate.y == -5); + CHECK(randomly_generated_coordinate.z == 0); + + const auto randomly_generated_coordinate_second = random_coordinate({1, 0, 0}, {1, 0, 0}); + CHECK(randomly_generated_coordinate_second.x == 1); + CHECK(randomly_generated_coordinate_second.y == 0); + CHECK(randomly_generated_coordinate_second.z == 0); + } + + SECTION("two unidentical cells as input, correct order") + { + const auto randomly_generated_coordinate = random_coordinate({-10, -1, 0}, {-10, -1, 1}); + CHECK(randomly_generated_coordinate.x == -10); + CHECK(randomly_generated_coordinate.y == -1); + CHECK(randomly_generated_coordinate.z >= 0); + CHECK(randomly_generated_coordinate.z <= 1); + } + + SECTION("two unidentical cells as input, switched correct order") + { + const auto randomly_generated_coordinate = random_coordinate({-10, -1, 1}, {-10, -1, 0}); + CHECK(randomly_generated_coordinate.x == -10); + CHECK(randomly_generated_coordinate.y == -1); + CHECK(randomly_generated_coordinate.z >= 0); + CHECK(randomly_generated_coordinate.z <= 1); + } +}