Skip to content

Commit

Permalink
🎨 Add an example CellLevelLayout type to pyfiction to showcase Pyth…
Browse files Browse the repository at this point in the history
…onic naming and factory classes
  • Loading branch information
marcelwa committed Dec 2, 2024
1 parent 6242831 commit d57bde4
Show file tree
Hide file tree
Showing 4 changed files with 285 additions and 0 deletions.
2 changes: 2 additions & 0 deletions bindings/mnt/pyfiction/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@
# Layouts
cartesian_layout,

CellLevelLayout,
qca_technology,
inml_technology,
sidb_technology,
Expand Down Expand Up @@ -656,6 +657,7 @@
"qca_technology",
"inml_technology",
"sidb_technology",
"CellLevelLayout",
"qca_layout",
"inml_layout",
"sidb_layout",
Expand Down
185 changes: 185 additions & 0 deletions bindings/mnt/pyfiction/include/pyfiction/layouts/CellLevelLayout.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
//
// Created by marcel on 04.06.22.
//

#ifndef PYFICTION_CELLLEVELLAYOUT_HPP
#define PYFICTION_CELLLEVELLAYOUT_HPP

#include "pyfiction/documentation.hpp"
#include "pyfiction/types.hpp"

#include <fiction/technology/cell_technologies.hpp>
#include <fiction/traits.hpp>
#include <fiction/utils/layout_utils.hpp>

#include <fmt/format.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <algorithm>
#include <cctype>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>

namespace pyfiction
{

namespace detail
{

class py_cartesian_cell_layout : public fiction::clocked_layout<
fiction::tile_based_layout<fiction::cartesian_layout<fiction::offset::ucoord_t>>>
{
public:
template <typename... Args>
py_cartesian_cell_layout(std::string technology, Args... args)
{
std::transform(technology.begin(), technology.end(), technology.begin(), ::tolower);

if (technology == "qca")
{
underlying_layout = py_qca_layout(args...);
}
else if (technology == "inml")
{
underlying_layout = py_inml_layout(args...);
}
else if (technology == "sidb")
{
underlying_layout = py_sidb_layout(args...);
}
else
{
throw std::runtime_error(fmt::format("'{}' does not refer to a supported technology", technology));
}
}

std::variant<py_qca_layout, py_inml_layout, py_sidb_layout> underlying_layout{};
};

inline void cell_level_layout(pybind11::module& m)
{
namespace py = pybind11;

/**
* Cell-level clocked Cartesian layout.
*/
py::class_<
py_cartesian_cell_layout,
fiction::clocked_layout<fiction::tile_based_layout<fiction::cartesian_layout<fiction::offset::ucoord_t>>>>(
m, "CellLevelLayout", DOC(fiction_cell_level_layout))
.def(py::init<std::string>(), py::arg("technology"), DOC(fiction_cell_level_layout_cell_level_layout))
.def(py::init<std::string, const fiction::aspect_ratio<py_cartesian_cell_layout>&>(), py::arg("technology"),
py::arg("dimension"), DOC(fiction_cell_level_layout_cell_level_layout))
// .def(py::init(
// [](const fiction::aspect_ratio<py_cartesian_cell_layout>& dimension,
// const std::string& scheme_name,
// const std::string& layout_name) -> py_cartesian_cell_layout
// {
// if (const auto scheme =
// fiction::get_clocking_scheme<py_cartesian_cell_layout>(scheme_name);
// scheme.has_value())
// {
// return py_cartesian_cell_layout{dimension, *scheme, layout_name};
// }
//
// throw std::runtime_error("Given name does not refer to a supported clocking scheme");
// }),
// py::arg("dimension"), py::arg("clocking_scheme") = "2DDWave", py::arg("layout_name") = "",
// DOC(fiction_cell_level_layout_cell_level_layout_2))
//
// .def("assign_cell_type", &py_cartesian_technology_cell_layout::assign_cell_type, py::arg("c"), py::arg("ct"),
// DOC(fiction_cell_level_layout_assign_cell_type))
// .def("get_cell_type", &py_cartesian_technology_cell_layout::get_cell_type, py::arg("c"),
// DOC(fiction_cell_level_layout_get_cell_type))
// .def("is_empty_cell", &py_cartesian_technology_cell_layout::is_empty_cell, py::arg("c"),
// DOC(fiction_cell_level_layout_is_empty_cell))
// .def("assign_cell_name", &py_cartesian_technology_cell_layout::assign_cell_name, py::arg("c"), py::arg("n"),
// DOC(fiction_cell_level_layout_assign_cell_name))
// .def("get_cell_name", &py_cartesian_technology_cell_layout::get_cell_name, py::arg("c"),
// DOC(fiction_cell_level_layout_get_cell_name))
// .def("set_layout_name", &py_cartesian_technology_cell_layout::set_layout_name, py::arg("name"),
// DOC(fiction_cell_level_layout_set_layout_name))
// .def("get_layout_name", &py_cartesian_technology_cell_layout::get_layout_name,
// DOC(fiction_cell_level_layout_get_layout_name))
// .def("num_cells", &py_cartesian_technology_cell_layout::num_cells, DOC(fiction_cell_level_layout_num_cells))
// .def("is_empty", &py_cartesian_technology_cell_layout::is_empty, DOC(fiction_cell_level_layout_is_empty))
// .def("num_pis", &py_cartesian_technology_cell_layout::num_pis, DOC(fiction_cell_level_layout_num_pis))
// .def("num_pos", &py_cartesian_technology_cell_layout::num_pos, DOC(fiction_cell_level_layout_num_pos))
// .def("is_pi", &py_cartesian_technology_cell_layout::is_pi, py::arg("c"),
// DOC(fiction_cell_level_layout_is_pi)) .def("is_po", &py_cartesian_technology_cell_layout::is_po,
// py::arg("c"), DOC(fiction_cell_level_layout_is_po))
//
.def("cells",
[](const py_cartesian_cell_layout& lyt)
{
const auto apply = [](const auto& cell_layout)
{
using Lyt = std::decay_t<decltype(cell_layout)>;

std::vector<fiction::coordinate<Lyt>> cells{};
cells.reserve(cell_layout.num_cells());
cell_layout.foreach_cell([&cells](const auto& c) { cells.push_back(c); });

return cells;
};

return std::visit(apply, lyt.underlying_layout);
})
// .def("pis",
// [](const py_cartesian_technology_cell_layout& lyt)
// {
// std::vector<fiction::coordinate<py_cartesian_technology_cell_layout>> pis{};
// pis.reserve(lyt.num_pis());
// lyt.foreach_pi([&pis](const auto& c) { pis.push_back(c); });
// return pis;
// })
// .def("pos",
// [](const py_cartesian_technology_cell_layout& lyt)
// {
// std::vector<fiction::coordinate<py_cartesian_technology_cell_layout>> pos{};
// pos.reserve(lyt.num_pos());
// lyt.foreach_po([&pos](const auto& c) { pos.push_back(c); });
// return pos;
// })
// .def(
// "bounding_box_2d",
// [](const py_cartesian_technology_cell_layout& lyt)
// {
// const auto bb = fiction::bounding_box_2d<py_cartesian_technology_cell_layout>(lyt);
// return std::make_pair(bb.get_min(), bb.get_max());
// },
// DOC(fiction_bounding_box_2d_overridden))
//
// .def("__repr__",
// [](const py_cartesian_technology_cell_layout& lyt) -> std::string
// {
// std::stringstream stream{};
//
// if constexpr (std::is_same_v<Technology, fiction::sidb_technology>)
// {
// print_layout(convert_layout_to_siqad_coordinates(lyt), stream);
// }
// else
// {
// print_layout(lyt, stream);
// }
//
// return stream.str();
// })

;
}

} // namespace detail

inline void cell_level_layout(pybind11::module& m)
{
detail::cell_level_layout(m);
}

} // namespace pyfiction

#endif // PYFICTION_CELLLEVELLAYOUT_HPP
2 changes: 2 additions & 0 deletions bindings/mnt/pyfiction/pyfiction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
#include "pyfiction/inout/write_sqd_layout.hpp"
#include "pyfiction/inout/write_sqd_sim_result.hpp"
#include "pyfiction/inout/write_svg_layout.hpp"
#include "pyfiction/layouts/CellLevelLayout.hpp"
#include "pyfiction/layouts/cartesian_layout.hpp"
#include "pyfiction/layouts/cell_level_layout.hpp"
#include "pyfiction/layouts/clocked_layout.hpp"
Expand Down Expand Up @@ -123,6 +124,7 @@ PYBIND11_MODULE(pyfiction, m, pybind11::mod_gil_not_used())
pyfiction::clocked_layouts(m);
pyfiction::gate_level_layouts(m);
pyfiction::cell_level_layouts(m);
pyfiction::cell_level_layout(m);
pyfiction::obstruction_layouts(m);
/**
* Algorithms: Simulation
Expand Down
96 changes: 96 additions & 0 deletions bindings/mnt/pyfiction/test/layouts/TestCellLevelLayout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from mnt.pyfiction import (CellLevelLayout)
import unittest


class TestCellLevelLayout(unittest.TestCase):

def test_cell_layout_inheritance(self):
for tech in ["qca", "inml", "sidb"]:
layout = CellLevelLayout(tech, (9, 9, 1))

for t in layout.coordinates():
self.assertTrue(t <= (9, 9, 1))
self.assertTrue(layout.is_within_bounds(t))

for t in layout.ground_coordinates():
self.assertTrue(t.z == 0)
self.assertTrue(t <= (9, 9, 0))
self.assertTrue(layout.is_within_bounds(t))

for t in layout.adjacent_coordinates((2, 2)):
self.assertIn(t, [(1, 2), (2, 1), (3, 2), (2, 3)])

# def test_cell_type_assignment(self):
# layout = qca_layout((4, 4), "OPEN", "AND")
#
# self.assertTrue(layout.is_empty())
#
# layout.assign_cell_type((0, 2), qca_technology.cell_type.INPUT)
# layout.assign_cell_type((2, 4), qca_technology.cell_type.INPUT)
# layout.assign_cell_type((2, 0), qca_technology.cell_type.CONST_0)
# layout.assign_cell_type((2, 1), qca_technology.cell_type.NORMAL)
# layout.assign_cell_type((2, 2), qca_technology.cell_type.NORMAL)
# layout.assign_cell_type((2, 3), qca_technology.cell_type.NORMAL)
# layout.assign_cell_type((1, 2), qca_technology.cell_type.NORMAL)
# layout.assign_cell_type((3, 2), qca_technology.cell_type.NORMAL)
# layout.assign_cell_type((4, 2), qca_technology.cell_type.OUTPUT)
#
# self.assertFalse(layout.is_empty())
#
# layout.assign_cell_name((0, 2), "a")
# layout.assign_cell_name((2, 4), "b")
# layout.assign_cell_name((4, 2), "f")
#
# self.assertEqual(layout.get_layout_name(), "AND")
# self.assertEqual(layout.get_cell_name((0, 2)), "a")
# self.assertEqual(layout.get_cell_name((2, 4)), "b")
# self.assertEqual(layout.get_cell_name((4, 2)), "f")
#
# self.assertEqual(layout.num_cells(), 9)
# self.assertEqual(layout.num_pis(), 2)
# self.assertEqual(layout.num_pos(), 1)
#
# self.assertTrue(layout.is_pi((0, 2)))
# self.assertTrue(layout.is_pi((2, 4)))
# self.assertTrue(layout.is_po((4, 2)))
#
# self.assertEqual(layout.get_cell_type((2, 0)), qca_technology.cell_type.CONST_0)
# self.assertEqual(layout.get_cell_type((2, 4)), qca_technology.cell_type.INPUT)
# self.assertEqual(layout.get_cell_type((0, 2)), qca_technology.cell_type.INPUT)
# self.assertEqual(layout.get_cell_type((2, 1)), qca_technology.cell_type.NORMAL)
# self.assertEqual(layout.get_cell_type((2, 2)), qca_technology.cell_type.NORMAL)
# self.assertEqual(layout.get_cell_type((2, 3)), qca_technology.cell_type.NORMAL)
# self.assertEqual(layout.get_cell_type((1, 2)), qca_technology.cell_type.NORMAL)
# self.assertEqual(layout.get_cell_type((3, 2)), qca_technology.cell_type.NORMAL)
# self.assertEqual(layout.get_cell_type((4, 2)), qca_technology.cell_type.OUTPUT)
#
# self.assertTrue(layout.is_empty_cell((0, 0)))
# self.assertTrue(layout.is_empty_cell((0, 1)))
# self.assertTrue(layout.is_empty_cell((1, 0)))
# self.assertTrue(layout.is_empty_cell((1, 1)))
# self.assertTrue(layout.is_empty_cell((3, 0)))
# self.assertTrue(layout.is_empty_cell((3, 1)))
# self.assertTrue(layout.is_empty_cell((4, 0)))
# self.assertTrue(layout.is_empty_cell((4, 1)))
# self.assertTrue(layout.is_empty_cell((0, 3)))
# self.assertTrue(layout.is_empty_cell((1, 3)))
# self.assertTrue(layout.is_empty_cell((0, 4)))
# self.assertTrue(layout.is_empty_cell((1, 0)))
# self.assertTrue(layout.is_empty_cell((3, 3)))
# self.assertTrue(layout.is_empty_cell((3, 4)))
# self.assertTrue(layout.is_empty_cell((4, 3)))
# self.assertTrue(layout.is_empty_cell((4, 4)))
#
# self.assertFalse(layout.is_empty_cell((2, 0)))
# self.assertFalse(layout.is_empty_cell((2, 4)))
# self.assertFalse(layout.is_empty_cell((0, 2)))
# self.assertFalse(layout.is_empty_cell((2, 1)))
# self.assertFalse(layout.is_empty_cell((2, 2)))
# self.assertFalse(layout.is_empty_cell((2, 3)))
# self.assertFalse(layout.is_empty_cell((1, 2)))
# self.assertFalse(layout.is_empty_cell((3, 2)))
# self.assertFalse(layout.is_empty_cell((4, 2)))


if __name__ == '__main__':
unittest.main()

0 comments on commit d57bde4

Please sign in to comment.