Skip to content

Commit

Permalink
✨ Support defects in print function. (#261)
Browse files Browse the repository at this point in the history
* 🎨 small changes here and there.

* ✅ add unit test.

* 🎨 add color for defects.

* 🐛 wrong charge state.

* ✅ add additional test.

* 🎨 use ternary conditional operator ``?:``.

* 🎨 remove ``<cstdint>``.

* 🎨 add defect operators as members.

* 🎨 implement suggestions.

* 🎨 siqad coordinates support in bounding box.

* 🔥 delete separate bounding box function for siqad coordinates.

* ✨ print sidbs, charges and defects of sidb layout.

* 🎨 implement clang-tidy suggestions.

* 🎨 Applied some pedantic small fixes

* 🎨 implement suggestions.
  • Loading branch information
Drewniok committed Aug 30, 2023
1 parent 4d9844f commit 73c662f
Show file tree
Hide file tree
Showing 8 changed files with 701 additions and 183 deletions.
2 changes: 1 addition & 1 deletion docs/io/visualization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Layout Printing

.. doxygenfunction:: fiction::print_gate_level_layout
.. doxygenfunction:: fiction::print_cell_level_layout
.. doxygenfunction:: fiction::print_charge_layout
.. doxygenfunction:: fiction::print_sidb_layout
.. doxygenfunction:: fiction::print_layout

Graphviz (DOT) Drawers
Expand Down
170 changes: 134 additions & 36 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_POS_COLOR = fmt::fg(fmt::color::red);
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,90 +335,178 @@ void print_cell_level_layout(std::ostream& os, const Lyt& layout, const bool io_
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 layout (SiDB and defect charges are supported) to an output stream.
*
* @tparam Lyt SiDB cell-level layout with charge-information based on SiQAD coordinates, e.g., a
* charge_distribution_surface object.
* @tparam Lyt SiDB cell-level layout with charge-information based on SiQAD coordinates or defect-information, e.g., a
* `charge_distribution_surface` or `sidb_surface`.
* @param os Output stream to write into.
* @param lyt The layout of which the charge distribution is to be printed.
* @param lyt The layout of which the information is to be printed.
* @param cs_color Flag to utilize color escapes for charge states.
* @param crop_layout Flag to print the 2D bounding box of the layout, while leaving a maximum padding of one dimer row
* and two columns.
* @param draw_lattice Flag to enable lattice background drawing.
*/
template <typename Lyt>
void print_charge_layout(std::ostream& os, const Lyt& lyt, const bool cs_color = true, const bool crop_layout = false,
const bool draw_lattice = true)
void print_sidb_layout(std::ostream& os, const Lyt& lyt, const bool cs_color = true, const bool crop_layout = false,
const bool draw_lattice = true)
{
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");

// 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;
}
}
else
{
os << "[i] empty layout" << std::endl;
return;
}
}

coordinate<Lyt> min{};
coordinate<Lyt> max{lyt.x(), lyt.y(), 1};
const bounding_box_2d bb{lyt};

if (crop_layout)
auto min_nw = bb.get_min();
auto max_se = bb.get_max();

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

// if defects exist in the layout
if constexpr (has_get_sidb_defect_v<Lyt>)
{
const auto bb = bounding_box_2d{lyt};
if (lyt.num_defects() != 0)
{
defects.reserve(lyt.num_defects());
lyt.foreach_sidb_defect([&defects](const auto& c) { defects.push_back(c.first); });

std::sort(defects.begin(), defects.end());

min_nw = min_nw > defects.front() ?
defects.front() :
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() :
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)
{
if (crop_layout && (c.x < min.x || c.x > max.x)) // apply horizontal crop
{
return;
}
// loop coordinate is initialized with the north-west coordinate
auto loop_coordinate = min_nw;

switch (lyt.get_charge_state(c)) // switch over the charge state of the SiDB at the current coordinate
while (loop_coordinate <= max_se)
{
// Is set to true if either charge or defect is printed at loop coordinate
bool already_printed = false;

// Check if layout is only a charge distribution surface
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:
{
os << fmt::format(cs_color ? detail::SIDB_NEG_COLOR : detail::NO_COLOR, "");
already_printed = true;
break;
}
case sidb_charge_state::POSITIVE:
{
os << fmt::format(cs_color ? detail::SIDB_POS_COLOR : detail::NO_COLOR, "");
already_printed = true;
break;
}
case sidb_charge_state::NEUTRAL:
{
os << fmt::format(cs_color ? detail::SIDB_NEUT_COLOR : detail::NO_COLOR, "");
already_printed = true;
break;
}
default: // NONE charge state case -> empty cell
case sidb_charge_state::NONE:
{
os << (draw_lattice || !lyt.is_empty_cell(c) ?
fmt::format(cs_color ? detail::SIDB_LAT_COLOR : detail::NO_COLOR, " · ") :
" ");
break;
}
}
}

if (c.x == max.x)
if constexpr (has_get_sidb_defect_v<Lyt>)
{
if (lyt.get_sidb_defect(loop_coordinate) != sidb_defect{sidb_defect_type::NONE})
{
os << (c.z == 1 ? "\n\n" : "\n");
if (is_negatively_charged_defect(lyt.get_sidb_defect(loop_coordinate)))
{
os << fmt::format(cs_color ? detail::SIDB_DEF_NEG_COLOR : detail::NO_COLOR, "");
already_printed = true;
}
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, "");
already_printed = true;
}
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, "");
already_printed = true;
}
}
},
min, max + coordinate<Lyt>{1, 0});
}

if (!already_printed && lyt.get_cell_type(loop_coordinate) != sidb_technology::cell_type::EMPTY)
{
os << fmt::format(cs_color ? detail::SIDB_DEF_NEU_COLOR : detail::NO_COLOR, " o ");
already_printed = true;
}

if (!already_printed)
{
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;
}
else if (loop_coordinate.x == max_se.x && loop_coordinate != max_se)
{
if (loop_coordinate.z == 1)
{
os << "\n\n"; // gap between two dimers
}
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 All @@ -433,9 +531,9 @@ void print_layout(const Lyt& lyt, std::ostream& os = std::cout)
}
else if constexpr (is_cell_level_layout_v<Lyt>)
{
if constexpr (has_sidb_technology_v<Lyt> && has_siqad_coord_v<Lyt> && has_get_charge_state_v<Lyt>)
if constexpr (has_sidb_technology_v<Lyt>)
{
print_charge_layout(os, lyt);
print_sidb_layout(os, lyt);
}
else
{
Expand Down
91 changes: 73 additions & 18 deletions include/fiction/layouts/bounding_box.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
#ifndef FICTION_BOUNDING_BOX_HPP
#define FICTION_BOUNDING_BOX_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 "fiction/utils/layout_utils.hpp"

// data types cannot properly be converted to bit field types
#pragma GCC diagnostic push
Expand Down Expand Up @@ -53,35 +58,85 @@ class bounding_box_2d
return;
}

// set min to max coordinate in the layout
min = {layout.x(), layout.y()};
// the layout is based on SiQAD coordinates
if constexpr (has_siqad_coord_v<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();

layout.foreach_coordinate(
[this](const auto& c)
{
if (!is_empty_coordinate(c))
uint8_t min_z = 0;
uint8_t max_z = 0;

layout.foreach_cell(
[&min_x, &max_x, &min_y, &max_y, &min_z, &max_z](const auto& c)
{
if (c.x < min.x)
if (c.x < min_x)
{
min_x = c.x;
}
if (c.x > max_x)
{
max_x = c.x;
}

if (c.y == min_y && c.z < min_z)
{
min.x = c.x;
min_z = c.z;
}
if (c.y < min.y)
if (c.y < min_y)
{
min.y = c.y;
min_y = c.y;
min_z = c.z;
}
if (c.x > max.x)

if (c.y == max_y && c.z > max_z)
{
max_z = c.z;
}
if (c.y > max_y)
{
max.x = c.x;
max_y = c.y;
max_z = c.z;
}
if (c.y > max.y)
});
min = {min_x, min_y, min_z};
max = {max_x, max_y, max_z};
}
else
{
// set min to max coordinate in the layout
min = {layout.x(), layout.y()};

layout.foreach_coordinate(
[this](const auto& c)
{
if (!is_empty_coordinate(c))
{
max.y = c.y;
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;
}
}
}
});
});

x_size = max.x - min.x;
y_size = max.y - min.y;
x_size = max.x - min.x;
y_size = max.y - min.y;
}
}
/**
* Returns the minimum corner of the bounding box.
Expand Down
Loading

0 comments on commit 73c662f

Please sign in to comment.