Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Added conversion functions for layouts of different coordinate types #125

Merged
merged 25 commits into from
Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f76860b
:sparkles: functions to convert layouts to a new layout based on a ne…
Feb 12, 2023
dfa2269
Merge branch 'main' into siqad_coodinates_to_fiction_vs
Feb 12, 2023
e40fbc1
:sparkles: functions to convert layouts to a new layout based on a ne…
Feb 12, 2023
d7de6c3
:art: put functions in different header, added missing attributes, up…
Feb 13, 2023
514b990
:memo: docu updated
Feb 13, 2023
2a058a3
:art: new function to shift layout to positive coordinates
Feb 13, 2023
35e3728
:art: new function to shift layout to positive coordinates
Feb 13, 2023
f46f4e3
:art: updated Marcel's suggestions
Feb 13, 2023
c258e70
:art: reformat code
Feb 13, 2023
8ea6c24
:art: reformat code
Feb 13, 2023
1e04450
:art: reformat code
Feb 13, 2023
5139d74
Delete sidb_surface_analysis.hpp
Drewniok Feb 14, 2023
05111ad
:art: reformat code
Feb 14, 2023
1388803
:art: updated Marcel's suggestions
Feb 15, 2023
1bbf6a2
:memo: Adjusted docstrings
marcelwa Feb 15, 2023
abb53e5
:art: Renamed functions
marcelwa Feb 15, 2023
dd7b264
:art: Fixed code duplication
marcelwa Feb 15, 2023
432449d
:art: Restructured tests
marcelwa Feb 15, 2023
919ddd7
:test_tube: Added failing tests
marcelwa Feb 15, 2023
c26d134
:art: aspect-ratio added for copy process
Feb 15, 2023
c3fc617
:art: aspect-ratio added for copy process
Feb 15, 2023
bc6ed9e
:art: aspect-ratio added for copy process
Feb 16, 2023
04c7b66
Merge branch 'main' into siqad_coodinates_to_fiction_vs
Drewniok Feb 17, 2023
bbb9721
Merge branch 'main' into siqad_coodinates_to_fiction_vs
Drewniok Feb 19, 2023
23db248
Merge branch 'main' into siqad_coodinates_to_fiction_vs
marcelwa Mar 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/utils/utils.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ Layout Utils
.. doxygenfunction:: fiction::num_adjacent_coordinates
.. doxygenfunction:: fiction::relative_to_absolute_cell_position
.. doxygenfunction:: fiction::port_direction_to_coordinate
.. doxygenfunction:: fiction::normalize_layout_coordinates
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
.. doxygenfunction:: fiction::convert_to_siqad_coordinates
.. doxygenfunction:: fiction::convert_to_fiction_coordinates



Placement Utils
Expand Down
4 changes: 4 additions & 0 deletions include/fiction/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,10 @@ inline constexpr const bool has_inml_technology_v = std::is_same_v<technology<Ly
template <typename Lyt>
inline constexpr const bool has_sidb_technology_v = std::is_same_v<technology<Lyt>, sidb_technology>;
template <typename Lyt>
inline constexpr const bool has_offset_ucoord_v = std::is_same_v<coordinate<Lyt>, offset::ucoord_t>;
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
template <typename Lyt>
inline constexpr const bool has_cube_coord_v = std::is_same_v<coordinate<Lyt>, cube::coord_t>;
template <typename Lyt>
inline constexpr const bool has_siqad_coord_v = std::is_same_v<coordinate<Lyt>, siqad::coord_t>;

#pragma region is_cell_level_layout
Expand Down
123 changes: 123 additions & 0 deletions include/fiction/utils/layout_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
#ifndef FICTION_LAYOUT_UTILS_HPP
#define FICTION_LAYOUT_UTILS_HPP

#include "fiction/layouts/cell_level_layout.hpp"
#include "fiction/layouts/coordinates.hpp"
#include "fiction/technology/cell_ports.hpp"
#include "fiction/traits.hpp"
#include "fiction/types.hpp"

#include <cassert>
#include <cstdint>
#include <limits>

namespace fiction
{
Expand All @@ -30,6 +34,7 @@ template <typename Lyt>

return static_cast<uint8_t>(lyt.adjacent_coordinates(c).size());
}

/**
* Converts a relative cell position within a tile to an absolute cell position within a layout. To compute the absolute
* position, the layout topology is taken into account.
Expand Down Expand Up @@ -163,6 +168,7 @@ template <uint16_t GateSizeX, uint16_t GateSizeY, typename GateLyt, typename Cel

return absolute_c;
}

/**
* Port directions address coordinates relative to each other by specifying cardinal directions. This function converts
* such a relative direction to an absolute coordinate when given a layout and a coordinate therein to consider. That
Expand Down Expand Up @@ -224,6 +230,123 @@ template <typename Lyt>
return {};
}

/**
* A new layout is constructed and returned that is equivalent to the given cell-level layout. However, its coordinates
* are normalized, i.e., start at `(0, 0)` and are all positive. To this end, all existing coordinates are shifted by an
* x and y offset.
*
* @tparam Lyt Cell-level layout type.
* @param lyt The layout which is to be normalized.
* @return New normalized equivalent layout.
*/
template <typename Lyt>
Lyt normalize_layout_coordinates(const Lyt& lyt) noexcept
{
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
static_assert(is_cartesian_layout_v<Lyt>, "Lyt is not a Cartesian layout");
static_assert(is_cell_level_layout_v<Lyt>, "Lyt is not a cell-level layout");

Lyt lyt_new{{lyt.x(), lyt.y()}, lyt.get_layout_name(), lyt.get_tile_size_x(), lyt.get_tile_size_y()};

auto x_offset = std::numeric_limits<int32_t>::max();
auto y_offset = std::numeric_limits<int32_t>::max();

lyt.foreach_cell(
[&x_offset, &y_offset](const auto& c)
{
if (c.y <= y_offset)
{
y_offset = c.y;
}
if (c.x <= x_offset)
{
x_offset = c.x;
}
});

lyt.foreach_cell(
[&lyt_new, &lyt, &x_offset, &y_offset](const auto& c)
{
lyt_new.assign_cell_type({c.x - x_offset, c.y - y_offset}, lyt.get_cell_type(c));
lyt_new.assign_cell_mode({c.x - x_offset, c.y - y_offset}, lyt.get_cell_mode(c));
lyt_new.assign_cell_name({c.x - x_offset, c.y - y_offset}, lyt.get_cell_name(c));
});

return lyt_new;
}

/**
* Converts the coordinates of a given cell-level layout to SiQAD coordinates. A new equivalent layout based on SiQAD
* coordinates is returned.
*
* @tparam Lyt Cell-level layout type based on fiction coordinates, e.g., `offset::ucoord_t` or `cube::coord_t`.
* @param lyt The layout that is to be converted to a new layout based on SiQAD coordinates.
* @return A new equivalent layout based on SiQAD coordinates.
*/
template <typename Lyt>
sidb_cell_clk_lyt_siqad convert_to_siqad_coordinates(const Lyt& lyt) noexcept
{
static_assert(is_cartesian_layout_v<Lyt>, "Lyt is not a Cartesian layout");
static_assert(is_cell_level_layout_v<Lyt>, "Lyt is not a cell-level layout");
static_assert(has_sidb_technology_v<Lyt>, "Lyt is not an SiDB layout");

sidb_cell_clk_lyt_siqad lyt_new{{lyt.x(), lyt.y()},
lyt.get_layout_name(),
lyt.get_tile_size_x(),
lyt.get_tile_size_y()};

lyt.foreach_cell(
[&lyt_new, &lyt](const auto& c)
{
lyt_new.assign_cell_type(siqad::to_siqad_coord<cell<Lyt>>(c), lyt.get_cell_type(c));
lyt_new.assign_cell_mode(siqad::to_siqad_coord<cell<Lyt>>(c), lyt.get_cell_mode(c));
lyt_new.assign_cell_name(siqad::to_siqad_coord<cell<Lyt>>(c), lyt.get_cell_name(c));
});

return lyt_new;
}

/**
* Converts the coordinates of a given cell-level layout to fiction coordinates, e.g., `offset::ucoord_t` or
* `cube::coord_t`. A new equivalent layout based on fiction coordinates is returned.
*
* @tparam Lyt Cell-level layout type based on fiction coordinates.
* @param lyt The layout that is to be converted to a new layout based on fiction coordinates.
* @return A new equivalent layout based on fiction coordinates.
*/
template <typename Lyt>
Lyt convert_to_fiction_coordinates(const sidb_cell_clk_lyt_siqad& lyt) noexcept
{
static_assert(is_cartesian_layout_v<Lyt>, "Lyt is not a Cartesian layout");
static_assert(is_cell_level_layout_v<Lyt>, "Lyt is not a cell-level layout");
static_assert(has_sidb_technology_v<Lyt>, "Lyt is not an SiDB layout");

Lyt lyt_new{{lyt.x(), lyt.y()}, lyt.get_layout_name(), lyt.get_tile_size_x(), lyt.get_tile_size_y()};
marcelwa marked this conversation as resolved.
Show resolved Hide resolved

const auto assign_coordinates = [&lyt_new](const auto& base_lyt) noexcept
{
base_lyt.foreach_cell(
[&lyt_new, &base_lyt](const auto& c)
{
lyt_new.assign_cell_type(siqad::to_fiction_coord<cell<Lyt>>(c), base_lyt.get_cell_type(c));
lyt_new.assign_cell_mode(siqad::to_fiction_coord<cell<Lyt>>(c), base_lyt.get_cell_mode(c));
lyt_new.assign_cell_name(siqad::to_fiction_coord<cell<Lyt>>(c), base_lyt.get_cell_name(c));
});
};

if constexpr (has_offset_ucoord_v<Lyt>)
{
auto lyt_normalized = normalize_layout_coordinates<sidb_cell_clk_lyt_siqad>(lyt);

assign_coordinates(lyt_normalized);
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
assign_coordinates(lyt);
}

return lyt_new;
}

} // namespace fiction

#endif // FICTION_LAYOUT_UTILS_HPP
177 changes: 177 additions & 0 deletions test/utils/layout_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <catch2/catch_template_test_macros.hpp>

#include <fiction/layouts/cartesian_layout.hpp>
#include <fiction/layouts/cell_level_layout.hpp>
#include <fiction/layouts/coordinates.hpp>
#include <fiction/layouts/hexagonal_layout.hpp>
#include <fiction/utils/layout_utils.hpp>
Expand Down Expand Up @@ -38,3 +39,179 @@ TEMPLATE_TEST_CASE("Port directions to coordinates", "[layout-utils]", (cartesia
lyt.north_west(c));
});
}

TEMPLATE_TEST_CASE("siqad layout is normalized, shifted to positive coordinates", "[layout-utils]",
sidb_cell_clk_lyt_siqad)
{
SECTION("empty layout")
{
TestType lyt{{}, "layout based on siqad coordinates"};

lyt.assign_cell_type({-5, -1}, TestType::cell_type::NORMAL);
lyt.assign_cell_type({5, 1}, TestType::cell_type::NORMAL);

auto lyt_transformed = normalize_layout_coordinates<TestType>(lyt);

CHECK(lyt_transformed.get_layout_name() == "layout based on siqad coordinates");
CHECK(lyt_transformed.get_cell_type({0, 0}) == TestType::cell_type::NORMAL);
CHECK(lyt_transformed.get_cell_type({10, 2}) == TestType::cell_type::NORMAL);
CHECK(lyt_transformed.get_cell_type({-5, -1}) == TestType::cell_type::EMPTY);
}
}

TEMPLATE_TEST_CASE("Convert offset::ucoord_t layout to SiQAD coordinate layout", "[layout-utils]", sidb_cell_clk_lyt)
{
SECTION("empty layout")
{
TestType lyt{{10, 10}, "test"};

auto lyt_transformed = convert_to_siqad_coordinates<TestType>(lyt);

CHECK(lyt_transformed.is_empty());
CHECK(lyt_transformed.area() == static_cast<int64_t>(lyt.area()));
CHECK(lyt_transformed.get_layout_name() == lyt.get_layout_name());
}

SECTION("layout with one normal and one input cell")
{
TestType lyt{{5, 3}};

lyt.assign_cell_type({5, 3}, TestType::cell_type::NORMAL);
lyt.assign_cell_type({5, 1}, TestType::cell_type::INPUT);

auto lyt_transformed = convert_to_siqad_coordinates<TestType>(lyt);

CHECK(lyt_transformed.num_cells() == 2);
CHECK(lyt_transformed.area() == static_cast<int64_t>(lyt.area()));
CHECK(lyt_transformed.get_cell_type({5, 1, 1}) == TestType::cell_type::NORMAL);
CHECK(lyt_transformed.get_cell_type({5, 0, 1}) == TestType::cell_type::INPUT);
}

SECTION("layout with three cells")
{
TestType lyt{{5, 3}};

lyt.assign_cell_type({0, 0}, TestType::cell_type::NORMAL);
lyt.assign_cell_type({5, 3}, TestType::cell_type::INPUT);
lyt.assign_cell_type({5, 1}, TestType::cell_type::OUTPUT);
lyt.assign_cell_name({0, 0}, "normal cell");
lyt.assign_cell_name({5, 3}, "input cell");
lyt.assign_cell_name({5, 1}, "output cell");

auto lyt_transformed = convert_to_siqad_coordinates<TestType>(lyt);

CHECK(lyt_transformed.num_cells() == 3);
CHECK(lyt_transformed.area() == static_cast<int64_t>(lyt.area()));
CHECK(lyt_transformed.get_cell_type({0, 0, 0}) == TestType::cell_type::NORMAL);
CHECK(lyt_transformed.get_cell_type({5, 1, 1}) == TestType::cell_type::INPUT);
CHECK(lyt_transformed.get_cell_type({5, 0, 1}) == TestType::cell_type::OUTPUT);
CHECK(lyt_transformed.get_cell_name({0, 0, 0}) == "normal cell");
CHECK(lyt_transformed.get_cell_name({5, 1, 1}) == "input cell");
CHECK(lyt_transformed.get_cell_name({5, 0, 1}) == "output cell");
}
}

TEMPLATE_TEST_CASE("Convert SiQAD layout to offset::ucoord_t coordinate layout", "[layout-utils]", sidb_cell_clk_lyt)
{
SECTION("empty layout")
{
const sidb_cell_clk_lyt_siqad lyt{{}, "layout based on siqad coordinates"};

auto lyt_transformed = convert_to_fiction_coordinates<TestType>(lyt);

CHECK(lyt_transformed.is_empty());
CHECK(static_cast<int64_t>(lyt_transformed.area()) == lyt.area());
CHECK(lyt_transformed.get_layout_name() == lyt.get_layout_name());
}

SECTION("layout with one normal and one input cell")
{
sidb_cell_clk_lyt_siqad lyt{{5, 3}};

lyt.assign_cell_type({5, 3}, TestType::cell_type::NORMAL);
lyt.assign_cell_type({-5, -1}, TestType::cell_type::INPUT);

auto lyt_transformed = convert_to_fiction_coordinates<TestType>(lyt);

CHECK(lyt_transformed.num_cells() == 2);
CHECK(static_cast<int64_t>(lyt_transformed.area()) == static_cast<int64_t>(lyt.area()));
CHECK(lyt_transformed.get_cell_type({10, 8}) == TestType::cell_type::NORMAL);
CHECK(lyt_transformed.get_cell_type({0, 0}) == TestType::cell_type::INPUT);
}

SECTION("layout with three cells")
{
sidb_cell_clk_lyt_siqad lyt{{5, 3}};

lyt.assign_cell_type({5, 3}, TestType::cell_type::NORMAL);
lyt.assign_cell_type({0, 0}, TestType::cell_type::INPUT);
lyt.assign_cell_type({5, 1}, TestType::cell_type::OUTPUT);
lyt.assign_cell_name({5, 3}, "normal cell");
lyt.assign_cell_name({0, 0}, "input cell");
lyt.assign_cell_name({5, 1}, "output cell");

auto lyt_transformed = convert_to_fiction_coordinates<TestType>(lyt);

CHECK(lyt_transformed.num_cells() == 3);
CHECK(static_cast<int64_t>(lyt_transformed.area()) == lyt.area());
CHECK(lyt_transformed.get_cell_type({5, 6}) == TestType::cell_type::NORMAL);
CHECK(lyt_transformed.get_cell_type({0, 0}) == TestType::cell_type::INPUT);
CHECK(lyt_transformed.get_cell_type({5, 2}) == TestType::cell_type::OUTPUT);
CHECK(lyt_transformed.get_cell_name({5, 6}) == "normal cell");
CHECK(lyt_transformed.get_cell_name({0, 0}) == "input cell");
CHECK(lyt_transformed.get_cell_name({5, 2}) == "output cell");
}
}

TEMPLATE_TEST_CASE("Convert SiQAD layout to cube::coord_t coordinate layout", "[layout-utils]",
(cell_level_layout<sidb_technology, clocked_layout<cartesian_layout<cube::coord_t>>>))
{
SECTION("empty layout")
{
const sidb_cell_clk_lyt_siqad lyt{{}, "layout based on siqad coordinates"};

auto lyt_transformed = convert_to_fiction_coordinates<TestType>(lyt);

CHECK(lyt_transformed.is_empty());
CHECK(lyt_transformed.area() == static_cast<int64_t>(lyt.area()));
CHECK(lyt_transformed.get_layout_name() == lyt.get_layout_name());
}

SECTION("layout with one normal and one input cell")
{
sidb_cell_clk_lyt_siqad lyt{{5, 1, 1}};

lyt.assign_cell_type({5, -1, 1}, TestType::cell_type::NORMAL);
lyt.assign_cell_type({5, 1, 0}, TestType::cell_type::INPUT);

auto lyt_transformed = convert_to_fiction_coordinates<TestType>(lyt);

CHECK(lyt_transformed.num_cells() == 2);
CHECK(lyt_transformed.area() == static_cast<int64_t>(lyt.area()));
CHECK(lyt_transformed.get_cell_type({5, -1}) == TestType::cell_type::NORMAL);
CHECK(lyt_transformed.get_cell_type({5, 2, 0}) == TestType::cell_type::INPUT);
}

SECTION("layout with three cells")
{
sidb_cell_clk_lyt_siqad lyt{{5, 3}};

lyt.assign_cell_type({5, -3}, TestType::cell_type::NORMAL);
lyt.assign_cell_type({0, 0}, TestType::cell_type::INPUT);
lyt.assign_cell_type({5, 3}, TestType::cell_type::OUTPUT);
lyt.assign_cell_name({5, -3}, "normal cell");
lyt.assign_cell_name({0, 0}, "input cell");
lyt.assign_cell_name({5, 3}, "output cell");

auto lyt_transformed = convert_to_fiction_coordinates<TestType>(lyt);

CHECK(lyt_transformed.num_cells() == 3);
CHECK(lyt_transformed.area() == static_cast<int64_t>(lyt.area()));
CHECK(lyt_transformed.get_cell_type({5, -6}) == TestType::cell_type::NORMAL);
CHECK(lyt_transformed.get_cell_type({0, 0}) == TestType::cell_type::INPUT);
CHECK(lyt_transformed.get_cell_type({5, 6}) == TestType::cell_type::OUTPUT);
CHECK(lyt_transformed.get_cell_name({5, -6}) == "normal cell");
CHECK(lyt_transformed.get_cell_name({0, 0}) == "input cell");
CHECK(lyt_transformed.get_cell_name({5, 6}) == "output cell");
}
}