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

✨ Support defects in print function. #261

Merged
merged 61 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
9622e83
:arrow_up: Bump libs/Catch2 from `6783411` to `1f881ab` (#27)
dependabot[bot] Apr 2, 2023
2da4f7e
Merge branch 'marcelwa:main' into main
Drewniok Apr 14, 2023
8f5f52f
:arrow_up: Bump libs/parallel-hashmap from `7883cb6` to `d2bed96` (#33)
dependabot[bot] Apr 14, 2023
a8cbc27
Merge branch 'marcelwa:main' into main
Drewniok Apr 18, 2023
3b11f93
Merge branch 'marcelwa:main' into main
Drewniok Apr 18, 2023
e9e2fa3
Merge branch 'marcelwa:main' into main
Drewniok Apr 18, 2023
37c881e
Merge branch 'marcelwa:main' into main
Drewniok Apr 19, 2023
4aa8489
Merge branch 'marcelwa:main' into main
Drewniok Apr 19, 2023
1587ef3
Merge branch 'marcelwa:main' into main
Drewniok Apr 20, 2023
04ed1c3
Merge branch 'marcelwa:main' into main
Drewniok Apr 21, 2023
9eaaf1f
Merge branch 'marcelwa:main' into main
Drewniok Apr 25, 2023
0dca9cf
Merge branch 'marcelwa:main' into main
Drewniok Apr 26, 2023
ce8b2e2
Merge branch 'marcelwa:main' into main
Drewniok May 1, 2023
64501c1
Merge branch 'marcelwa:main' into main
Drewniok May 10, 2023
68f6885
Merge branch 'marcelwa:main' into main
Drewniok May 11, 2023
84634cd
Merge branch 'marcelwa:main' into main
Drewniok May 12, 2023
597b1a7
Merge branch 'marcelwa:main' into main
Drewniok May 12, 2023
1920794
Merge branch 'marcelwa:main' into main
Drewniok May 14, 2023
5d74ac6
Merge branch 'marcelwa:main' into main
Drewniok May 21, 2023
f408962
Merge branch 'marcelwa:main' into main
Drewniok May 24, 2023
b4138de
Merge branch 'marcelwa:main' into main
Drewniok May 25, 2023
930fcf2
Merge branch 'marcelwa:main' into main
Drewniok Jun 5, 2023
cbd8345
Merge branch 'marcelwa:main' into main
Drewniok Jun 7, 2023
2903532
Merge branch 'marcelwa:main' into main
Drewniok Jun 12, 2023
f70ceb6
Merge branch 'marcelwa:main' into main
Drewniok Jun 14, 2023
24ff3a7
Merge branch 'marcelwa:main' into main
Drewniok Jun 16, 2023
a4f3150
Merge branch 'marcelwa:main' into main
Drewniok Jun 19, 2023
9c78984
Merge branch 'marcelwa:main' into main
Drewniok Jun 23, 2023
c3f4e96
Merge branch 'marcelwa:main' into main
Drewniok Jun 28, 2023
853be74
Merge branch 'cda-tum:main' into main
Drewniok Jul 5, 2023
13eab3c
Merge branch 'cda-tum:main' into main
Drewniok Jul 10, 2023
1c59a58
Merge branch 'cda-tum:main' into main
Drewniok Jul 18, 2023
1f87c22
Merge branch 'cda-tum:main' into main
Drewniok Jul 20, 2023
d300bc1
Merge branch 'cda-tum:main' into main
Drewniok Jul 24, 2023
2dc75ac
Merge branch 'cda-tum:main' into main
Drewniok Jul 25, 2023
9fc5819
Merge branch 'cda-tum:main' into main
Drewniok Jul 26, 2023
bd5cfc3
Merge branch 'cda-tum:main' into main
Drewniok Jul 26, 2023
51b93cb
Merge branch 'cda-tum:main' into main
Drewniok Jul 26, 2023
88dee4d
:art: small changes here and there.
Drewniok Jul 28, 2023
337c655
:white_check_mark: add unit test.
Drewniok Jul 28, 2023
dc51c99
:art: add color for defects.
Drewniok Jul 28, 2023
e652382
:bug: wrong charge state.
Drewniok Jul 28, 2023
62fcaa7
:white_check_mark: add additional test.
Drewniok Jul 28, 2023
2c911d8
:art: use ternary conditional operator ``?:``.
Drewniok Aug 2, 2023
53d06af
:art: remove ``<cstdint>``.
Drewniok Aug 2, 2023
751369c
Merge branch 'cda-tum:main' into main
Drewniok Aug 3, 2023
8031b33
Merge branch 'main' into add_defects_to_print_function
Drewniok Aug 3, 2023
0cae87e
:art: add defect operators as members.
Drewniok Aug 3, 2023
0bad685
:art: implement Marcel's suggestions.
Drewniok Aug 3, 2023
b466760
:art: implement Marcel's suggestions.
Drewniok Aug 5, 2023
311339b
Merge branch 'cda-tum:main' into main
Drewniok Aug 10, 2023
df7e094
Merge branch 'main' into add_defects_to_print_function
Drewniok Aug 10, 2023
16c12e4
Merge branch 'cda-tum:main' into main
Drewniok Aug 27, 2023
317c887
Merge branch 'main' into add_defects_to_print_function
Drewniok Aug 27, 2023
7b2fc73
:art: siqad coordinates support in bounding box.
Drewniok Aug 28, 2023
e3123c6
:fire: delete separate bounding box function for siqad coordinates.
Drewniok Aug 28, 2023
b6aec60
:sparkles: print sidbs, charges and defects of sidb layout.
Drewniok Aug 28, 2023
3ea1c74
:art: implement clang-tidy suggestions.
Drewniok Aug 28, 2023
a984dc9
:art: Applied some pedantic small fixes
marcelwa Aug 29, 2023
15641f1
:art: implement suggestions.
Drewniok Aug 29, 2023
859d79a
Merge branch 'main' into add_defects_to_print_function
Drewniok Aug 29, 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
188 changes: 162 additions & 26 deletions include/fiction/io/print_layout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@

#include "fiction/layouts/bounding_box.hpp"
#include "fiction/technology/charge_distribution_surface.hpp"
#include "fiction/technology/sidb_defects.hpp"
#include "fiction/technology/sidb_surface.hpp"
#include "fiction/traits.hpp"
#include "fiction/types.hpp"
#include "fiction/utils/layout_utils.hpp"

#include <fmt/color.h>
#include <fmt/format.h>
Expand Down Expand Up @@ -45,6 +48,13 @@
static const auto SIDB_NEUT_COLOR = fmt::fg(fmt::color::white);
// Escape color sequence for lattice background colors (grey).
static const auto SIDB_LAT_COLOR = fmt::fg(fmt::color::gray);

// Escape color sequence for positively charged defect colors (red).
static const auto SIDB_DEF_POS_COLOR = fmt::fg(fmt::color::red);
// Escape color sequence for negatively charged defect colors (blue).
static const auto SIDB_DEF_NEG_COLOR = fmt::fg(fmt::color::blue);
// Escape color sequence for neutrally charged defect colors (yellow).
static const auto SIDB_DEF_NEU_COLOR = fmt::fg(fmt::color::yellow);
// Empty escape color sequence
inline constexpr auto NO_COLOR = fmt::text_style{};

Expand Down Expand Up @@ -325,7 +335,7 @@
os << std::endl;
}
/**
* Writes a simplified 2D representation of an SiDB charge layout to an output stream.
* Writes a simplified 2D representation of an SiDB surface or charge distribution surface to an output stream.
*
* @tparam Lyt SiDB cell-level layout with charge-information based on SiQAD coordinates, e.g., a
* charge_distribution_surface object.
Expand All @@ -343,41 +353,147 @@
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");
static_assert(has_siqad_coord_v<Lyt>, "Lyt is not based on SiQAD coordinates");
static_assert(has_get_charge_state_v<Lyt>, "Lyt does not implement the get_charge_state function");
static_assert(has_get_charge_state_v<Lyt> | has_get_sidb_defect_v<Lyt>,
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
"Lyt does not implement the get_charge_state function");

// empty layout
if (lyt.is_empty())
{
os << "[i] empty layout" << std::endl;
return;
if constexpr (has_get_sidb_defect_v<Lyt>)
{
if (lyt.num_defects() == 0)
{
os << "[i] empty layout" << std::endl;
return;
}
}
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
else
{
os << "[i] empty layout" << std::endl;
return;
}
}

coordinate<Lyt> min{};
coordinate<Lyt> max{lyt.x(), lyt.y(), 1};
// determine the north-west and south-west cell in siqad-coordinates.
const auto [nw, se] = bounding_box_siqad<Lyt>(lyt);

if (crop_layout)
auto min_nw = nw;
auto max_se = se;

std::vector<typename Lyt::cell> defects{};

// Check if defects exist in the layout.
if constexpr (has_get_sidb_defect_v<Lyt>)
{
const auto bb = bounding_box_2d{lyt};

defects.reserve(lyt.num_defects());
lyt.foreach_sidb_defect([&defects](const auto& c) { defects.push_back(c.first); });
std::sort(defects.begin(), defects.end());
if (!defects.empty())
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
{
min_nw = min_nw > defects.front() ?
defects.front() :

Check warning on line 395 in include/fiction/io/print_layout.hpp

View check run for this annotation

Codecov / codecov/patch

include/fiction/io/print_layout.hpp#L395

Added line #L395 was not covered by tests
min_nw; // if a defect is more north-west than nw, this position is used as min.
max_se = max_se < defects.back() ?
defects.back() :

Check warning on line 398 in include/fiction/io/print_layout.hpp

View check run for this annotation

Codecov / codecov/patch

include/fiction/io/print_layout.hpp#L398

Added line #L398 was not covered by tests
max_se; // if a defect is more south-east than se, this position is used as max.
}
}

if (crop_layout)
{
// apply padding of maximally one dimer row and two columns
min = bb.get_min() - coordinate<Lyt>{2, 1};
max = bb.get_max() + coordinate<Lyt>{2, 1};
min_nw = min_nw - coordinate<Lyt>{2, 1};
max_se = max_se + coordinate<Lyt>{2, 1};

// ensure only full dimer rows are printed
min.z = 0;
max.z = 1;
min_nw.z = 0;
max_se.z = 1;
}

// iterate over all coordinates in the rows determined by the vertical crop
lyt.foreach_coordinate(
[&](const coordinate<Lyt>& c)
// loop coordinate is initialized with the north-west coordinate.
auto loop_coordinate = min_nw;

while (loop_coordinate <= max_se)
{
// Check if layout is a sidb_surface and a charge distribution surface.
if constexpr (has_get_sidb_defect_v<Lyt> && has_get_charge_state_v<Lyt>)
{
if (crop_layout && (c.x < min.x || c.x > max.x)) // apply horizontal crop
if (lyt.get_sidb_defect(loop_coordinate) != sidb_defect{sidb_defect_type::NONE})
{
return;
if (is_negatively_charged_defect(lyt.get_sidb_defect(loop_coordinate)))
{
os << fmt::format(cs_color ? detail::SIDB_NEG_COLOR : detail::NO_COLOR, " ⊟ ");
}

else if (is_positively_charged_defect(lyt.get_sidb_defect(loop_coordinate)))
{
os << fmt::format(cs_color ? detail::SIDB_NEG_COLOR : detail::NO_COLOR, " ⊞ ");
}
else if (is_neutrally_charged_defect(lyt.get_sidb_defect(loop_coordinate)))
{
os << fmt::format(cs_color ? detail::SIDB_NEG_COLOR : detail::NO_COLOR, " ⊡ ");
}
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
switch (lyt.get_charge_state(
loop_coordinate)) // switch over the charge state of the SiDB at the current coordinate
{
case sidb_charge_state::NEGATIVE:
{
os << fmt::format(cs_color ? detail::SIDB_NEG_COLOR : detail::NO_COLOR, " ● ");
break;
}
case sidb_charge_state::POSITIVE:
{
os << fmt::format(cs_color ? detail::SIDB_POS_COLOR : detail::NO_COLOR, " ⨁ ");
break;
}
case sidb_charge_state::NEUTRAL:
{
os << fmt::format(cs_color ? detail::SIDB_NEUT_COLOR : detail::NO_COLOR, " ◯ ");
break;
}
default: // NONE charge state case -> empty cell
{
os << (draw_lattice ? fmt::format(cs_color ? detail::SIDB_LAT_COLOR : detail::NO_COLOR, " · ") :
" ");
}
}
}
}

// Check if layout is only a sidb_surface.
else if constexpr (has_get_sidb_defect_v<Lyt>)
{
if (lyt.get_sidb_defect(loop_coordinate) != sidb_defect{sidb_defect_type::NONE})
{
if (is_negatively_charged_defect(lyt.get_sidb_defect(loop_coordinate)))
{
os << fmt::format(cs_color ? detail::SIDB_DEF_NEG_COLOR : detail::NO_COLOR, " ⊟ ");
}

else if (is_positively_charged_defect(lyt.get_sidb_defect(loop_coordinate)))
{
os << fmt::format(cs_color ? detail::SIDB_DEF_POS_COLOR : detail::NO_COLOR, " ⊞ ");
}
else if (is_neutrally_charged_defect(lyt.get_sidb_defect(loop_coordinate)))
{
os << fmt::format(cs_color ? detail::SIDB_DEF_NEU_COLOR : detail::NO_COLOR, " ⊡ ");
}
}
else
{
os << (draw_lattice ? fmt::format(cs_color ? detail::SIDB_LAT_COLOR : detail::NO_COLOR, " · ") : " ");
}
}

switch (lyt.get_charge_state(c)) // switch over the charge state of the SiDB at the current coordinate
// Check if layout is only a charge distribution surface.
else if constexpr (has_get_charge_state_v<Lyt>)
{
switch (lyt.get_charge_state(
loop_coordinate)) // switch over the charge state of the SiDB at the current coordinate
{
case sidb_charge_state::NEGATIVE:
{
Expand All @@ -396,19 +512,39 @@
}
default: // NONE charge state case -> empty cell
{
os << (draw_lattice || !lyt.is_empty_cell(c) ?
fmt::format(cs_color ? detail::SIDB_LAT_COLOR : detail::NO_COLOR, " · ") :
" ");
os << (draw_lattice ? fmt::format(cs_color ? detail::SIDB_LAT_COLOR : detail::NO_COLOR, " · ") :
" ");
}
}
}

// If the x-coordinate of loop_coordinate is still less than the x-coordinate of the south-west cell, the
// x-coordinate is increased by 1.
if (loop_coordinate.x < max_se.x)
{
loop_coordinate.x += 1;
}

if (c.x == max.x)
else if (loop_coordinate.x == max_se.x && loop_coordinate != max_se)
{
if (loop_coordinate.z == 1)
{
os << (c.z == 1 ? "\n\n" : "\n");
os << "\n\n"; // gap between two dimers.
}
},
min, max + coordinate<Lyt>{1, 0});

else
{
os << "\n";
}
loop_coordinate.x = min_nw.x;
loop_coordinate.y += (loop_coordinate.z == 1) ? 1 : 0;
loop_coordinate.z = (loop_coordinate.z == 0) ? 1 : 0;
}
else if (loop_coordinate == max_se)
{
os << "\n\n"; // add a gap between two dimers.
break;
}
}
// flush stream
os << std::endl;
}
Expand Down
58 changes: 57 additions & 1 deletion include/fiction/technology/sidb_defects.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef FICTION_SIDB_DEFECTS_HPP
#define FICTION_SIDB_DEFECTS_HPP

#include <cassert>
#include <cmath>
#include <cstdint>
#include <utility>
Expand Down Expand Up @@ -57,7 +58,7 @@ struct sidb_defect
lambda_tf{screening_distance}
{

assert(((std::fmod(charge, 1) == 0)) && "charge value has to be an integer");
assert((std::fmod(charge, 1) == 0) && "charge value has to be an integer");
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
assert((epsilon_r >= 0) && "epsilon_r has to be >= 0.0");
assert((lambda_tf >= 0.0) && "lambda_tf has to be >= 0.0 nanometer");
}
Expand All @@ -78,6 +79,31 @@ struct sidb_defect
*/
const double lambda_tf;
};
/**
* This operator compares two sidb_defect instances for equality. It checks if the type, charge,
* epsilon_r, and lambda_tf members of the two instances are equal.
*
* @param lhs The left-hand side sidb_defect instance.
* @param rhs The right-hand side sidb_defect instance.
* @return Returns true if the two sidb_defect instances are equal, false otherwise.
*/
static constexpr bool operator==(const sidb_defect& lhs, const sidb_defect& rhs) noexcept
{
return lhs.type == rhs.type && lhs.charge == rhs.charge && lhs.epsilon_r == rhs.epsilon_r &&
lhs.lambda_tf == rhs.lambda_tf;
}
/**
* This operator compares two sidb_defect instances for inequality. It uses the operator== to check
* if the two instances are equal and returns the negation of the result.
*
* @param lhs The left-hand side sidb_defect instance.
* @param rhs The right-hand side sidb_defect instance.
* @return Returns true if the two sidb_defect instances are not equal, false if they are equal.
*/
static constexpr bool operator!=(const sidb_defect& lhs, const sidb_defect& rhs) noexcept
{
return !(lhs == rhs);
}
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
/**
* Checks whether the given defect is charged. Charged defects are to be avoided by a larger distance.
*
Expand All @@ -88,6 +114,36 @@ struct sidb_defect
{
return defect.type == sidb_defect_type::DB || defect.type == sidb_defect_type::SI_VACANCY;
}
/**
* Checks whether the given defect is positively charged.
*
* @param defect Defect to check.
* @return `true` iff defect is positively charged.
*/
[[nodiscard]] static constexpr bool is_positively_charged_defect(const sidb_defect& defect) noexcept
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
{
return defect.charge > 0;
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
}
/**
* Checks whether the given defect is negatively charged.
*
* @param defect Defect to check.
* @return `true` iff defect is negatively charged.
*/
[[nodiscard]] static constexpr bool is_negatively_charged_defect(const sidb_defect& defect) noexcept
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
{
return defect.charge < 0;
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
}
/**
* Checks whether the given defect is neutrally charged.
*
* @param defect Defect to check.
* @return `true` iff defect is neutrally charged.
*/
[[nodiscard]] static constexpr bool is_neutrally_charged_defect(const sidb_defect& defect) noexcept
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
{
return defect.charge == 0;
Drewniok marked this conversation as resolved.
Show resolved Hide resolved
}
/**
* Checks whether the given defect is not charged. Neutral defects are to be avoided but not by such a large distance.
* Even though the `NONE` defect type is technically neutral, it is not a defect per se which is why this function
Expand Down
51 changes: 51 additions & 0 deletions include/fiction/utils/layout_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,57 @@ CoordinateType random_coordinate(CoordinateType coordinate1, CoordinateType coor
}
}

/**
* Calculates the north-west and south-east cells of a minimum-sized box around all non-empty cells in a given layout
* which is based on SiQAD coordinates.
*
* @tparam Lyt SiDB cell-level layout type.
* @param lyt The layout for which the two corner cells of the minimum-sized box are determined.
* @return North-west and south-east cells of minimum-sized box.
*/
template <typename Lyt>
std::pair<typename Lyt::cell, typename Lyt::cell> bounding_box_siqad(const Lyt& lyt) noexcept
{
static_assert(has_siqad_coord_v<Lyt>, "Layout is not based on siqad coordinates");

if (lyt.num_cells() == 0)
{
return {typename Lyt::cell{}, typename Lyt::cell{}};
}

const auto converted_layout = convert_to_fiction_coordinates<
cell_level_layout<sidb_technology, clocked_layout<cartesian_layout<cube::coord_t>>>>(lyt);

int32_t min_x = std::numeric_limits<int32_t>::max();
int32_t max_x = std::numeric_limits<int32_t>::min();

int32_t min_y = std::numeric_limits<int32_t>::max();
int32_t max_y = std::numeric_limits<int32_t>::min();

converted_layout.foreach_cell(
[&converted_layout, &min_x, &max_x, &min_y, &max_y](const auto& c)
{
if (c.x < min_x)
{
min_x = c.x;
}
if (c.y < min_y)
{
min_y = c.y;
}
if (c.x > max_x)
{
max_x = c.x;
}
if (c.y > max_y)
{
max_y = c.y;
}
});

return {siqad::to_siqad_coord(cube::coord_t{min_x, min_y}), siqad::to_siqad_coord(cube::coord_t{max_x, max_y})};
}
Drewniok marked this conversation as resolved.
Show resolved Hide resolved

} // namespace fiction

#endif // FICTION_LAYOUT_UTILS_HPP
Loading
Loading