From 3507e073c25380552b5df08dfe7b70567a1d921a Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 22 Apr 2024 18:49:04 +0200 Subject: [PATCH 01/95] :sparkles: Added I/O coloring to SiDB layout printing --- include/fiction/io/print_layout.hpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/include/fiction/io/print_layout.hpp b/include/fiction/io/print_layout.hpp index 28df4dda9..001ad738b 100644 --- a/include/fiction/io/print_layout.hpp +++ b/include/fiction/io/print_layout.hpp @@ -486,9 +486,22 @@ void print_sidb_layout(std::ostream& os, const Lyt& lyt, const bool lat_color = } } - if (!already_printed && lyt.get_cell_type(loop_coordinate) != sidb_technology::cell_type::EMPTY) + if (const auto ct = lyt.get_cell_type(loop_coordinate); + ct != sidb_technology::cell_type::EMPTY && !already_printed) { - os << fmt::format(lat_color ? detail::SIDB_DEF_NEU_COLOR : detail::NO_COLOR, " ◯ "); + if (ct == sidb_technology::cell_type::INPUT) + { + os << fmt::format(lat_color ? detail::INP_COLOR : detail::NO_COLOR, " ◯ "); + } + else if (ct == sidb_technology::cell_type::OUTPUT) + { + os << fmt::format(lat_color ? detail::OUT_COLOR : detail::NO_COLOR, " ◯ "); + } + else // NORMAL cell + { + os << fmt::format(lat_color ? detail::SIDB_DEF_NEU_COLOR : detail::NO_COLOR, " ◯ "); + } + already_printed = true; } From 744f58c8c42c34399396e861b007ca3aec6b7f24 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Fri, 26 Apr 2024 11:32:17 +0200 Subject: [PATCH 02/95] :art: Changed the default operational/non-operational tags to `1` and `0` --- .../fiction/io/write_operational_domain.hpp | 28 +++++++++++++------ test/io/write_operational_domain.cpp | 13 ++++----- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/include/fiction/io/write_operational_domain.hpp b/include/fiction/io/write_operational_domain.hpp index 8cd2f07ae..2014c649a 100644 --- a/include/fiction/io/write_operational_domain.hpp +++ b/include/fiction/io/write_operational_domain.hpp @@ -25,11 +25,11 @@ struct write_operational_domain_params /** * The tag used to represent the operational value of a parameter set. */ - std::string_view operational_tag = "operational"; + std::string_view operational_tag = "1"; /** * The tag used to represent the non-operational value of a parameter set. */ - std::string_view non_operational_tag = "non-operational"; + std::string_view non_operational_tag = "0"; }; namespace detail @@ -69,9 +69,15 @@ sweep_parameter_to_string(const operational_domain::sweep_parameter& param) noex * Writes a CSV representation of an operational domain to the specified output stream. The data are written * as rows, each corresponding to one set of simulation parameters and their corresponding operational status. * - * The output CSV format is as follows: - * X_DIMENSION, Y_DIMENSION, OPERATIONAL STATUS - * ... subsequent rows for each set of simulation parameters. + * The output CSV format is e.g. as follows: + \verbatim embed:rst + .. code-block:: RST + + epsilon_r, lambda_tf, operational status + 0.0, 0.0, 0 + 0.1, 0.0, 1 + ... subsequent rows for each set of simulation parameters + \endverbatim * * The operational status is a binary value represented by specified tags in `params` indicating whether the simulation * parameters are within the operational domain or not. @@ -101,9 +107,15 @@ inline void write_operational_domain(const operational_domain& opdom, std::ostre * Writes a CSV representation of an operational domain to the specified file. The data are written as rows, each * corresponding to one set of simulation parameters and their corresponding operational status. * - * The output CSV format is as follows: - * X_DIMENSION, Y_DIMENSION, OPERATIONAL STATUS - * ... subsequent rows for each set of simulation parameters. + * The output CSV format is e.g. as follows: + \verbatim embed:rst + .. code-block:: RST + + epsilon_r, lambda_tf, operational status + 0.0, 0.0, 0 + 0.1, 0.0, 1 + ... subsequent rows for each set of simulation parameters + \endverbatim * * The operational status is a binary value represented by specified tags in `params` indicating whether the simulation * parameters are within the operational domain or not. diff --git a/test/io/write_operational_domain.cpp b/test/io/write_operational_domain.cpp index 5bf2e49ee..9285bf541 100644 --- a/test/io/write_operational_domain.cpp +++ b/test/io/write_operational_domain.cpp @@ -50,8 +50,7 @@ TEST_CASE("Write simple operational domain", "[write-operational-domain]") SECTION("default operational tags") { - std::set expected{"epsilon_r,lambda_tf,operational status", "0,0,operational", - "0,1,non-operational"}; + std::set expected{"epsilon_r,lambda_tf,operational status", "0,0,1", "0,1,0"}; write_operational_domain(opdom, os); const auto os_str = os.str(); @@ -94,8 +93,8 @@ TEST_CASE("Write operational domain with floating-point parameter values", "[wri SECTION("default operational tags") { - std::set expected{"epsilon_r,lambda_tf,operational status", "0.1,0.2,operational", - "0.3,0.4,non-operational", "1.2,1.4,operational", "2.4,5.75,non-operational"}; + std::set expected{"epsilon_r,lambda_tf,operational status", "0.1,0.2,1", "0.3,0.4,0", "1.2,1.4,1", + "2.4,5.75,0"}; write_operational_domain(opdom, os); const auto os_str = os.str(); @@ -109,10 +108,10 @@ TEST_CASE("Write operational domain with floating-point parameter values", "[wri } SECTION("custom operational tags") { - const write_operational_domain_params params = {"1", "0"}; + const write_operational_domain_params params = {"operational", "non-operational"}; - std::set expected{"epsilon_r,lambda_tf,operational status", "0.1,0.2,1", "0.3,0.4,0", "1.2,1.4,1", - "2.4,5.75,0"}; + std::set expected{"epsilon_r,lambda_tf,operational status", "0.1,0.2,operational", + "0.3,0.4,non-operational", "1.2,1.4,operational", "2.4,5.75,non-operational"}; write_operational_domain(opdom, os, params); const auto os_str = os.str(); From edee07fa5ee02aed284ff5acfe4e0c970beadfb9 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Fri, 26 Apr 2024 11:56:03 +0200 Subject: [PATCH 03/95] :art: Small changes --- include/fiction/algorithms/simulation/sidb/is_operational.hpp | 4 ++-- .../fiction/algorithms/simulation/sidb/operational_domain.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/is_operational.hpp b/include/fiction/algorithms/simulation/sidb/is_operational.hpp index 5e449c70a..d5e4776c5 100644 --- a/include/fiction/algorithms/simulation/sidb/is_operational.hpp +++ b/include/fiction/algorithms/simulation/sidb/is_operational.hpp @@ -35,7 +35,7 @@ namespace fiction /** * Possible operational status of a layout. */ -enum class operational_status +enum class operational_status : uint8_t { /** * The layout is operational. @@ -384,7 +384,7 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational * @tparam TT Type of the truth table. * @param lyt The SiDB layout. * @param spec Vector of truth table specifications. - * @param params Parameters to simualte if a input combination is operational. + * @param params Parameters to simulate if a input combination is operational. * @return The count of operational input combinations. */ template diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index fc3146c73..bad3c3a5d 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -56,7 +56,7 @@ struct operational_domain /** * Possible sweep parameters for the operational domain computation. */ - enum class sweep_parameter + enum class sweep_parameter : uint8_t { /** * The relative permittivity of the dielectric material. From 0e19a7516c01628d8fb82039c9e2133a23e24987 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sun, 19 May 2024 12:56:28 +0000 Subject: [PATCH 04/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index fdf506117..f2e64811c 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -12219,7 +12219,7 @@ Parameter ``spec``: Vector of truth table specifications. Parameter ``params``: - Parameters to simualte if a input combination is operational. + Parameters to simulate if a input combination is operational. Returns: The count of operational input combinations.)doc"; @@ -15476,9 +15476,11 @@ output stream. The data are written as rows, each corresponding to one set of simulation parameters and their corresponding operational status. -The output CSV format is as follows: X_DIMENSION, Y_DIMENSION, -OPERATIONAL STATUS ... subsequent rows for each set of simulation -parameters. +The output CSV format is e.g. as follows: \verbatim embed:rst .. code- +block:: RST + +epsilon_r, lambda_tf, operational status 0.0, 0.0, 0 0.1, 0.0, 1 ... +subsequent rows for each set of simulation parameters \endverbatim The operational status is a binary value represented by specified tags in `params` indicating whether the simulation parameters are within @@ -15505,9 +15507,11 @@ R"doc(Writes a CSV representation of an operational domain to the specified file. The data are written as rows, each corresponding to one set of simulation parameters and their corresponding operational status. -The output CSV format is as follows: X_DIMENSION, Y_DIMENSION, -OPERATIONAL STATUS ... subsequent rows for each set of simulation -parameters. +The output CSV format is e.g. as follows: \verbatim embed:rst .. code- +block:: RST + +epsilon_r, lambda_tf, operational status 0.0, 0.0, 0 0.1, 0.0, 1 ... +subsequent rows for each set of simulation parameters \endverbatim The operational status is a binary value represented by specified tags in `params` indicating whether the simulation parameters are within From 69eb8f10e0b004bee406a55b9169ae1e3138a47d Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 22 May 2024 08:53:11 +0200 Subject: [PATCH 05/95] :poop: Save commit, stuff doesn't work yet --- .../algorithms/iter/bdl_input_iterator.hpp | 106 ++++++++++++++++++ .../simulation/sidb/detect_bdl_pairs.hpp | 15 ++- .../pyfiction/layouts/cartesian_layout.hpp | 2 +- bindings/pyfiction/pyfiction.cpp | 11 +- .../test/algorithms/iter/__init__.py | 16 +++ .../algorithms/iter/bdl_input_iterator.py | 20 ++++ .../algorithms/iter/bdl_input_iterator.hpp | 14 +-- test/algorithms/iter/bdl_input_iterator.cpp | 19 +++- .../simulation/sidb/critical_temperature.cpp | 5 +- 9 files changed, 185 insertions(+), 23 deletions(-) create mode 100644 bindings/pyfiction/include/pyfiction/algorithms/iter/bdl_input_iterator.hpp create mode 100644 bindings/pyfiction/test/algorithms/iter/__init__.py create mode 100644 bindings/pyfiction/test/algorithms/iter/bdl_input_iterator.py diff --git a/bindings/pyfiction/include/pyfiction/algorithms/iter/bdl_input_iterator.hpp b/bindings/pyfiction/include/pyfiction/algorithms/iter/bdl_input_iterator.hpp new file mode 100644 index 000000000..c8aba8128 --- /dev/null +++ b/bindings/pyfiction/include/pyfiction/algorithms/iter/bdl_input_iterator.hpp @@ -0,0 +1,106 @@ +// +// Created by marcel on 19.05.24. +// + +#ifndef PYFICTION_BDL_INPUT_ITERATOR_HPP +#define PYFICTION_BDL_INPUT_ITERATOR_HPP + +#include "pyfiction/documentation.hpp" +#include "pyfiction/types.hpp" + +#include +#include + +#include +#include +#include + +#include +#include + +namespace pyfiction +{ + +namespace detail +{ + +template +void bdl_input_iterator(pybind11::module& m, const std::string& lattice) +{ + namespace py = pybind11; + using namespace py::literals; + + py::class_>(m, fmt::format("bdl_input_iterator_{}", lattice).c_str(), + DOC(fiction_bdl_input_iterator)) + .def(py::init(), "lyt"_a, + "params"_a = fiction::detect_bdl_pairs_params{}, DOC(fiction_bdl_input_iterator_bdl_input_iterator)) + .def( + "__next__", + [](fiction::bdl_input_iterator& self) -> Lyt& + { + auto result = *self; + ++self; + return result; + }, + DOC(fiction_bdl_input_iterator_operator_mul)) + .def( + "__eq__", [](const fiction::bdl_input_iterator& self, const uint64_t m) -> bool { return self == m; }, + "m"_a, DOC(fiction_bdl_input_iterator_operator_eq)) + .def( + "__ne__", [](const fiction::bdl_input_iterator& self, const uint64_t m) -> bool { return self != m; }, + "m"_a, DOC(fiction_bdl_input_iterator_operator_ne)) + .def( + "__lt__", [](const fiction::bdl_input_iterator& self, const uint64_t m) -> bool { return self < m; }, + "m"_a, DOC(fiction_bdl_input_iterator_operator_lt)) + .def( + "__le__", [](const fiction::bdl_input_iterator& self, const uint64_t m) -> bool { return self <= m; }, + "m"_a, DOC(fiction_bdl_input_iterator_operator_le)) + .def( + "__gt__", [](const fiction::bdl_input_iterator& self, const uint64_t m) -> bool { return self > m; }, + "m"_a, DOC(fiction_bdl_input_iterator_operator_gt)) + .def( + "__ge__", [](const fiction::bdl_input_iterator& self, const uint64_t m) -> bool { return self >= m; }, + "m"_a, DOC(fiction_bdl_input_iterator_operator_ge)) + .def( + "__add__", [](const fiction::bdl_input_iterator& self, const int m) -> fiction::bdl_input_iterator + { return self + m; }, "m"_a, DOC(fiction_bdl_input_iterator_operator_add)) + .def( + "__iadd__", + [](fiction::bdl_input_iterator& self, const int m) -> fiction::bdl_input_iterator& + { + self += m; + return self; + }, + "m"_a, DOC(fiction_bdl_input_iterator_operator_iadd)) + .def( + "__sub__", [](const fiction::bdl_input_iterator& self, const int m) { return self - m; }, "m"_a, + DOC(fiction_bdl_input_iterator_operator_sub)) + .def( + "__isub__", + [](fiction::bdl_input_iterator& self, const int m) -> fiction::bdl_input_iterator& + { + self -= m; + return self; + }, + "m"_a, DOC(fiction_bdl_input_iterator_operator_isub)) + .def( + "__getitem__", [](const fiction::bdl_input_iterator& self, int m) -> fiction::bdl_input_iterator + { return self[m]; }, "m"_a, DOC(fiction_bdl_input_iterator_operator_array)) + + .def("num_input_pairs", &fiction::bdl_input_iterator::num_input_pairs); + ; +} + +} // namespace detail + +inline void bdl_input_iterator(pybind11::module& m) +{ + // NOTE be careful with the order of the following calls! Python will resolve the first matching overload! + + detail::bdl_input_iterator(m, "100"); + detail::bdl_input_iterator(m, "111"); +} + +} // namespace pyfiction + +#endif // PYFICTION_BDL_INPUT_ITERATOR_HPP diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp index 2e4fac5fa..75f08b686 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp @@ -9,10 +9,15 @@ #include "pyfiction/types.hpp" #include +#include +#include +#include #include #include +#include + namespace pyfiction { @@ -25,7 +30,7 @@ void detect_bdl_pairs(pybind11::module& m, const std::string& lattice = "") namespace py = pybind11; using namespace pybind11::literals; - py::class_>(m, fmt::format("bdl_pair{}", lattice).c_str(), DOC(fiction_bdl_pair)) + py::class_>(m, fmt::format("bdl_pair_{}", lattice).c_str(), DOC(fiction_bdl_pair)) .def(py::init<>(), DOC(fiction_bdl_pair_bdl_pair)) .def(py::init, fiction::cell>(), "t"_a, "u"_a, "l"_a, DOC(fiction_bdl_pair_bdl_pair_2)) @@ -50,12 +55,14 @@ inline void detect_bdl_pairs(pybind11::module& m) .def_readwrite("minimum_distance", &fiction::detect_bdl_pairs_params::minimum_distance, DOC(fiction_detect_bdl_pairs_params_minimum_distance)) .def_readwrite("maximum_distance", &fiction::detect_bdl_pairs_params::maximum_distance, - DOC(fiction_detect_bdl_pairs_params_maximum_distance)); + DOC(fiction_detect_bdl_pairs_params_maximum_distance)) + + ; // NOTE be careful with the order of the following calls! Python will resolve the first matching overload! - detail::detect_bdl_pairs(m, "_100"); - detail::detect_bdl_pairs(m, "_111"); + detail::detect_bdl_pairs(m, "100"); + detail::detect_bdl_pairs(m, "111"); } } // namespace pyfiction diff --git a/bindings/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp b/bindings/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp index e0b6f9040..c465ee2a8 100644 --- a/bindings/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp +++ b/bindings/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp @@ -24,7 +24,7 @@ inline void cartesian_layout(pybind11::module& m) namespace py = pybind11; using namespace pybind11::literals; - /** + /**ü * Cartesian layout. */ py::class_(m, "cartesian_layout", DOC(fiction_cartesian_layout_overridden)) diff --git a/bindings/pyfiction/pyfiction.cpp b/bindings/pyfiction/pyfiction.cpp index f21c5fed3..5de9172ec 100644 --- a/bindings/pyfiction/pyfiction.cpp +++ b/bindings/pyfiction/pyfiction.cpp @@ -7,6 +7,7 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" +#include "pyfiction/algorithms/iter/bdl_input_iterator.hpp" #include "pyfiction/algorithms/network_transformation/fanout_substitution.hpp" #include "pyfiction/algorithms/network_transformation/network_balancing.hpp" #include "pyfiction/algorithms/network_transformation/technology_mapping.hpp" @@ -101,6 +102,11 @@ PYBIND11_MODULE(pyfiction, m) pyfiction::cube_coordinate(m); pyfiction::siqad_coordinate(m); pyfiction::coordinate_utility(m); + /** + * Logic + */ + pyfiction::logic_networks(m); + pyfiction::truth_tables(m); /** * Layouts */ @@ -139,10 +145,9 @@ PYBIND11_MODULE(pyfiction, m) pyfiction::determine_groundstate_from_simulation_results(m); pyfiction::check_simulation_results_for_equivalence(m); /** - * Logic + * Algorithms: Iterators */ - pyfiction::logic_networks(m); - pyfiction::truth_tables(m); + pyfiction::bdl_input_iterator(m); /** * Algorithms: Network Transformation */ diff --git a/bindings/pyfiction/test/algorithms/iter/__init__.py b/bindings/pyfiction/test/algorithms/iter/__init__.py new file mode 100644 index 000000000..5fde0b8ad --- /dev/null +++ b/bindings/pyfiction/test/algorithms/iter/__init__.py @@ -0,0 +1,16 @@ +from os.path import dirname, basename, isfile, join +import glob +import os +import sys +from pathlib import Path + +if sys.platform == "win32" and sys.version_info > (3, 8, 0) and "Z3_ROOT" in os.environ: + lib_path = Path(os.environ["Z3_ROOT"]) / "lib" + if lib_path.exists(): + os.add_dll_directory(str(lib_path)) + bin_path = Path(os.environ["Z3_ROOT"]) / "bin" + if bin_path.exists(): + os.add_dll_directory(str(bin_path)) + +modules = glob.glob(join(dirname(__file__), "*.py")) +__all__ = [basename(f)[:-3] for f in modules if isfile(f) and not f.endswith('__init__.py')] diff --git a/bindings/pyfiction/test/algorithms/iter/bdl_input_iterator.py b/bindings/pyfiction/test/algorithms/iter/bdl_input_iterator.py new file mode 100644 index 000000000..562aa9bcd --- /dev/null +++ b/bindings/pyfiction/test/algorithms/iter/bdl_input_iterator.py @@ -0,0 +1,20 @@ +from mnt.pyfiction import * +import unittest + + +class TestBDLInputIterator(unittest.TestCase): + def test_empty_layout(self): + layout = sidb_100_lattice((0,0)) + + bii = bdl_input_iterator_100(layout) + + self.assertEqual(bii.num_input_pairs(), 0) + self.assertEqual(bii, 0) + self.assertNotEqual(bii, 1) + self.assertLess(bii, 1) + self.assertLessEqual(bii, 1) + self.assertGreaterEqual(bii, 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/include/fiction/algorithms/iter/bdl_input_iterator.hpp b/include/fiction/algorithms/iter/bdl_input_iterator.hpp index 31598afc7..b780b2f72 100644 --- a/include/fiction/algorithms/iter/bdl_input_iterator.hpp +++ b/include/fiction/algorithms/iter/bdl_input_iterator.hpp @@ -7,6 +7,7 @@ #include "fiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp" #include "fiction/technology/cell_technologies.hpp" +#include "fiction/traits.hpp" #include "fiction/types.hpp" #include @@ -42,8 +43,7 @@ class bdl_input_iterator */ explicit bdl_input_iterator(const Lyt& lyt, const detect_bdl_pairs_params& params = {}) noexcept : layout{lyt.clone()}, - input_pairs{detect_bdl_pairs(layout, sidb_technology::cell_type::INPUT, params)}, - num_inputs{static_cast(input_pairs.size())} + input_pairs{detect_bdl_pairs(layout, sidb_technology::cell_type::INPUT, params)} { static_assert(is_cell_level_layout_v, "Lyt is not a cell-level layout"); static_assert(has_sidb_technology_v, "Lyt is not an SiDB layout"); @@ -271,9 +271,9 @@ class bdl_input_iterator * * @return The number of input BDL pairs. */ - [[nodiscard]] uint64_t get_number_of_inputs() const noexcept + [[nodiscard]] uint64_t num_input_pairs() const noexcept { - return num_inputs; + return input_pairs.size(); } private: @@ -285,10 +285,6 @@ class bdl_input_iterator * The detected input BDL pairs. */ const std::vector> input_pairs; - /** - * The amount of input BDL pairs. - */ - const uint8_t num_inputs; /** * The current input index. There are \f$2^n\f$ possible input states for an \f$n\f$-input BDL layout. */ @@ -302,7 +298,7 @@ class bdl_input_iterator */ void set_all_inputs() noexcept { - for (uint8_t i = 0; i < num_inputs; ++i) + for (uint64_t i = 0; i < input_pairs.size(); ++i) { const auto& input_i = input_pairs[i]; diff --git a/test/algorithms/iter/bdl_input_iterator.cpp b/test/algorithms/iter/bdl_input_iterator.cpp index 038f05c11..5590a3cd0 100644 --- a/test/algorithms/iter/bdl_input_iterator.cpp +++ b/test/algorithms/iter/bdl_input_iterator.cpp @@ -5,14 +5,11 @@ #include #include -#include #include #include -#include #include #include -#include #include #include @@ -113,16 +110,20 @@ TEST_CASE("Empty layout iteration", "[bdl-input-iterator]") bdl_input_iterator bii{lyt}; + CHECK(bii.num_input_pairs() == 0); CHECK((*bii).num_cells() == 0); // increment ++bii; + CHECK(bii.num_input_pairs() == 0); CHECK((*bii).num_cells() == 0); auto bii_cp = bii++; + CHECK(bii.num_input_pairs() == 0); + CHECK(bii_cp.num_input_pairs() == 0); CHECK((*bii).num_cells() == 0); CHECK((*bii_cp).num_cells() == 0); @@ -130,12 +131,15 @@ TEST_CASE("Empty layout iteration", "[bdl-input-iterator]") --bii; + CHECK(bii.num_input_pairs() == 0); CHECK((*bii).num_cells() == 0); auto bii_cm = bii--; + CHECK(bii.num_input_pairs() == 0); CHECK((*bii).num_cells() == 0); + CHECK(bii_cm.num_input_pairs() == 0); CHECK((*bii_cm).num_cells() == 0); } @@ -161,6 +165,10 @@ TEST_CASE("BDL wire iteration", "[bdl-input-iterator]") bdl_input_iterator bii{lat}; + CHECK((*bii).num_cells() == 7); // 2 inputs (1 already deleted for input pattern 0), 4 normal, 2 outputs + + CHECK(bii.num_input_pairs() == 1); + CHECK(bii == 0ull); // start by incrementing over all input states @@ -235,7 +243,7 @@ TEST_CASE("SiQAD's AND gate iteration", "[bdl-input-iterator]") const sidb_100_cell_clk_lyt_siqad lat{lyt}; - SECTION("siqad coordinates") + SECTION("SiQAD coordinates") { bdl_input_iterator bii{lat}; @@ -301,7 +309,8 @@ TEST_CASE("SiQAD's AND gate iteration", "[bdl-input-iterator]") SECTION("cube coordinates") { - const auto layout_cube = convert_to_fiction_coordinates(lyt); + const auto layout_cube = convert_to_fiction_coordinates(lyt); + bdl_input_iterator bii{sidb_100_cell_clk_lyt_cube{layout_cube}}; for (auto i = 0; bii < 4; ++bii, ++i) diff --git a/test/algorithms/simulation/sidb/critical_temperature.cpp b/test/algorithms/simulation/sidb/critical_temperature.cpp index 6ec69cc31..feafffb41 100644 --- a/test/algorithms/simulation/sidb/critical_temperature.cpp +++ b/test/algorithms/simulation/sidb/critical_temperature.cpp @@ -3,13 +3,16 @@ // #include +#include #include #include #include +#include +#include +#include #include #include -#include #include #include From 2dc2bf8e00a9675bcc1939624ee1024386adebac Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Sat, 25 May 2024 13:54:12 +0200 Subject: [PATCH 06/95] :sparkles: Exposed `bdl_input_iterator` in pyfiction --- .../algorithms/iter/bdl_input_iterator.hpp | 11 +- .../simulation/sidb/detect_bdl_pairs.hpp | 2 +- .../algorithms/iter/bdl_input_iterator.py | 164 +++++++++++++++++- .../simulation/sidb/test_detect_bdl_pairs.py | 2 +- .../simulation/sidb/test_time_to_solution.py | 2 +- include/fiction/utils/layout_utils.hpp | 2 + 6 files changed, 177 insertions(+), 6 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/iter/bdl_input_iterator.hpp b/bindings/pyfiction/include/pyfiction/algorithms/iter/bdl_input_iterator.hpp index c8aba8128..45dbe7fda 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/iter/bdl_input_iterator.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/iter/bdl_input_iterator.hpp @@ -38,6 +38,11 @@ void bdl_input_iterator(pybind11::module& m, const std::string& lattice) "__next__", [](fiction::bdl_input_iterator& self) -> Lyt& { + if (self >= ((1ull << self.num_input_pairs()) - 1)) + { + throw py::stop_iteration(); + } + auto result = *self; ++self; return result; @@ -87,8 +92,10 @@ void bdl_input_iterator(pybind11::module& m, const std::string& lattice) "__getitem__", [](const fiction::bdl_input_iterator& self, int m) -> fiction::bdl_input_iterator { return self[m]; }, "m"_a, DOC(fiction_bdl_input_iterator_operator_array)) - .def("num_input_pairs", &fiction::bdl_input_iterator::num_input_pairs); - ; + .def("num_input_pairs", &fiction::bdl_input_iterator::num_input_pairs) + .def("get_layout", [](const fiction::bdl_input_iterator& self) -> const Lyt& { return *self; }) + + ; } } // namespace detail diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp index 75f08b686..00485876c 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp @@ -40,7 +40,7 @@ void detect_bdl_pairs(pybind11::module& m, const std::string& lattice = "") ; - m.def(fmt::format("detect_bdl_pairs{}", lattice).c_str(), &fiction::detect_bdl_pairs, "lyt"_a, "type"_a, + m.def(fmt::format("detect_bdl_pairs_{}", lattice).c_str(), &fiction::detect_bdl_pairs, "lyt"_a, "type"_a, "params"_a = fiction::detect_bdl_pairs_params{}, DOC(fiction_detect_bdl_pairs)); } diff --git a/bindings/pyfiction/test/algorithms/iter/bdl_input_iterator.py b/bindings/pyfiction/test/algorithms/iter/bdl_input_iterator.py index 562aa9bcd..f0a667b22 100644 --- a/bindings/pyfiction/test/algorithms/iter/bdl_input_iterator.py +++ b/bindings/pyfiction/test/algorithms/iter/bdl_input_iterator.py @@ -4,7 +4,7 @@ class TestBDLInputIterator(unittest.TestCase): def test_empty_layout(self): - layout = sidb_100_lattice((0,0)) + layout = sidb_100_lattice((0, 0)) bii = bdl_input_iterator_100(layout) @@ -15,6 +15,168 @@ def test_empty_layout(self): self.assertLessEqual(bii, 1) self.assertGreaterEqual(bii, 0) + def test_iteration_empty_layout(self): + layout = sidb_100_lattice((0, 0)) + + bii = bdl_input_iterator_100(layout) + + self.assertEqual(bii.num_input_pairs(), 0) + self.assertEqual(bii, 0) + self.assertEqual(bii.get_layout().num_cells(), 0) + + bii = bii + 1 + + self.assertEqual(bii.num_input_pairs(), 0) + self.assertEqual(bii, 1) + self.assertEqual(bii.get_layout().num_cells(), 0) + + bii = bii - 1 + + self.assertEqual(bii.num_input_pairs(), 0) + self.assertEqual(bii, 0) + self.assertEqual(bii.get_layout().num_cells(), 0) + + def test_manual_bdl_wire_iteration(self): + layout = sidb_100_lattice((20, 0)) + + layout.assign_cell_type((0, 0, 0), sidb_technology.cell_type.INPUT) + layout.assign_cell_type((2, 0, 0), sidb_technology.cell_type.INPUT) + + layout.assign_cell_type((6, 0, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((8, 0, 0), sidb_technology.cell_type.NORMAL) + + layout.assign_cell_type((12, 0, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((14, 0, 0), sidb_technology.cell_type.NORMAL) + + layout.assign_cell_type((18, 0, 0), sidb_technology.cell_type.OUTPUT) + layout.assign_cell_type((20, 0, 0), sidb_technology.cell_type.OUTPUT) + + bii = bdl_input_iterator_100(layout) + + self.assertEqual(bii.get_layout().num_cells(), + 7) # 2 inputs (1 already deleted for input pattern 0), 4 normal, 2 outputs + self.assertEqual(bii.num_input_pairs(), 1) + self.assertEqual(bii, 0) + + lyt0 = bii.get_layout() + + self.assertEqual(lyt0.get_cell_type((0, 0, 0)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt0.get_cell_type((2, 0, 0)), sidb_technology.cell_type.EMPTY) + + bii = bii + 1 + + lyt1 = bii.get_layout() + + self.assertEqual(lyt1.get_cell_type((0, 0, 0)), sidb_technology.cell_type.EMPTY) + self.assertEqual(lyt1.get_cell_type((2, 0, 0)), sidb_technology.cell_type.INPUT) + + bii = bii + 1 + + lyt2 = bii.get_layout() + + self.assertEqual(lyt2.get_cell_type((0, 0, 0)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt2.get_cell_type((2, 0, 0)), sidb_technology.cell_type.EMPTY) + + bii = bii - 1 + + lyt1 = bii.get_layout() + + self.assertEqual(lyt1.get_cell_type((0, 0, 0)), sidb_technology.cell_type.EMPTY) + self.assertEqual(lyt1.get_cell_type((2, 0, 0)), sidb_technology.cell_type.INPUT) + + bii = bii - 1 + + lyt0 = bii.get_layout() + + self.assertEqual(lyt0.get_cell_type((0, 0, 0)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt0.get_cell_type((2, 0, 0)), sidb_technology.cell_type.EMPTY) + + def test_automatic_bdl_wire_iteration(self): + layout = sidb_100_lattice((20, 0)) + + layout.assign_cell_type((0, 0, 0), sidb_technology.cell_type.INPUT) + layout.assign_cell_type((2, 0, 0), sidb_technology.cell_type.INPUT) + + layout.assign_cell_type((6, 0, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((8, 0, 0), sidb_technology.cell_type.NORMAL) + + layout.assign_cell_type((12, 0, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((14, 0, 0), sidb_technology.cell_type.NORMAL) + + layout.assign_cell_type((18, 0, 0), sidb_technology.cell_type.OUTPUT) + layout.assign_cell_type((20, 0, 0), sidb_technology.cell_type.OUTPUT) + + bii = bdl_input_iterator_100(layout) + + for (index, bii_iterator) in enumerate(bii): + lyt = bii_iterator.get_layout() + if index == 0: + self.assertEqual(lyt.get_cell_type((0, 0, 0)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt.get_cell_type((2, 0, 0)), sidb_technology.cell_type.EMPTY) + elif index == 1: + self.assertEqual(lyt.get_cell_type((0, 0, 0)), sidb_technology.cell_type.EMPTY) + self.assertEqual(lyt.get_cell_type((2, 0, 0)), sidb_technology.cell_type.INPUT) + elif index == 2: + self.assertEqual(lyt.get_cell_type((0, 0, 0)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt.get_cell_type((2, 0, 0)), sidb_technology.cell_type.EMPTY) + elif index == 3: + break + + def test_automatic_siqad_and_gate_iteration(self): + layout = sidb_100_lattice((20, 10), "AND gate") + + layout.assign_cell_type((0, 0, 1), sidb_technology.cell_type.INPUT) + layout.assign_cell_type((2, 1, 1), sidb_technology.cell_type.INPUT) + + layout.assign_cell_type((20, 0, 1), sidb_technology.cell_type.INPUT) + layout.assign_cell_type((18, 1, 1), sidb_technology.cell_type.INPUT) + + layout.assign_cell_type((4, 2, 1), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((6, 3, 1), sidb_technology.cell_type.NORMAL) + + layout.assign_cell_type((14, 3, 1), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((16, 2, 1), sidb_technology.cell_type.NORMAL) + + layout.assign_cell_type((10, 6, 0), sidb_technology.cell_type.OUTPUT) + layout.assign_cell_type((10, 7, 0), sidb_technology.cell_type.OUTPUT) + + layout.assign_cell_type((10, 9, 1), sidb_technology.cell_type.NORMAL) + + bii = bdl_input_iterator_100(layout) + + for (index, bii_iterator) in enumerate(bii): + lyt = bii_iterator.get_layout() + if index == 0: + self.assertEqual(lyt.get_cell_type((0, 0, 1)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt.get_cell_type((2, 1, 1)), sidb_technology.cell_type.EMPTY) + + self.assertEqual(lyt.get_cell_type((20, 0, 1)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt.get_cell_type((18, 1, 1)), sidb_technology.cell_type.EMPTY) + + elif index == 1: + self.assertEqual(lyt.get_cell_type((0, 0, 1)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt.get_cell_type((2, 1, 1)), sidb_technology.cell_type.EMPTY) + + self.assertEqual(lyt.get_cell_type((20, 0, 1)), sidb_technology.cell_type.EMPTY) + self.assertEqual(lyt.get_cell_type((18, 1, 1)), sidb_technology.cell_type.INPUT) + + elif index == 2: + self.assertEqual(lyt.get_cell_type((0, 0, 1)), sidb_technology.cell_type.EMPTY) + self.assertEqual(lyt.get_cell_type((2, 1, 1)), sidb_technology.cell_type.INPUT) + + self.assertEqual(lyt.get_cell_type((20, 0, 1)), sidb_technology.cell_type.INPUT) + self.assertEqual(lyt.get_cell_type((18, 1, 1)), sidb_technology.cell_type.EMPTY) + + elif index == 3: + self.assertEqual(lyt.get_cell_type((0, 0, 1)), sidb_technology.cell_type.EMPTY) + self.assertEqual(lyt.get_cell_type((2, 1, 1)), sidb_technology.cell_type.INPUT) + + self.assertEqual(lyt.get_cell_type((20, 0, 1)), sidb_technology.cell_type.EMPTY) + self.assertEqual(lyt.get_cell_type((18, 1, 1)), sidb_technology.cell_type.INPUT) + + else: + break + if __name__ == '__main__': unittest.main() diff --git a/bindings/pyfiction/test/algorithms/simulation/sidb/test_detect_bdl_pairs.py b/bindings/pyfiction/test/algorithms/simulation/sidb/test_detect_bdl_pairs.py index 813cdf464..fba2fc995 100644 --- a/bindings/pyfiction/test/algorithms/simulation/sidb/test_detect_bdl_pairs.py +++ b/bindings/pyfiction/test/algorithms/simulation/sidb/test_detect_bdl_pairs.py @@ -31,7 +31,7 @@ def test_detect_bdl_pairs_100_lattice(self): self.assertEqual(len(output_bdl_pairs), 0) self.assertEqual(len(normal_bdl_pairs), 2) - def test_detect_bdl_pairs_100_lattice(self): + def test_detect_bdl_pairs_111_lattice(self): lyt = sidb_111_lattice((7, 0)) lyt = charge_distribution_surface_111(lyt) diff --git a/bindings/pyfiction/test/algorithms/simulation/sidb/test_time_to_solution.py b/bindings/pyfiction/test/algorithms/simulation/sidb/test_time_to_solution.py index 9a9b79981..89157cac2 100644 --- a/bindings/pyfiction/test/algorithms/simulation/sidb/test_time_to_solution.py +++ b/bindings/pyfiction/test/algorithms/simulation/sidb/test_time_to_solution.py @@ -23,7 +23,7 @@ def test_one_sidb_100_lattice(self): self.assertGreater(stats.time_to_solution, 0.0) self.assertGreater(stats.mean_single_runtime, 0.0) - def test_one_DBs_111_lattice(self): + def test_one_sidb_111_lattice(self): layout = sidb_111_lattice((0, 0)) layout.assign_cell_type((0, 0), sidb_technology.cell_type.NORMAL) diff --git a/include/fiction/utils/layout_utils.hpp b/include/fiction/utils/layout_utils.hpp index c81b833e2..f193faddb 100644 --- a/include/fiction/utils/layout_utils.hpp +++ b/include/fiction/utils/layout_utils.hpp @@ -454,6 +454,7 @@ LytDest convert_to_fiction_coordinates(const LytSrc& lyt) noexcept lyt_new_cds.assign_sidb_defect(siqad::to_fiction_coord>(cd.first), cd.second); }); + return lyt_new_cds; } else if constexpr (is_sidb_defect_surface_v && !is_charge_distribution_surface_v) @@ -465,6 +466,7 @@ LytDest convert_to_fiction_coordinates(const LytSrc& lyt) noexcept lyt_surface.assign_sidb_defect(siqad::to_fiction_coord>(cd.first), lyt.get_sidb_defect(cd.first)); }); + return lyt_surface; } else if constexpr (is_charge_distribution_surface_v && !is_sidb_defect_surface_v) From 7afa4431cc37bf5abdaab10cd9721e6742dbd531 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Sat, 25 May 2024 13:57:15 +0200 Subject: [PATCH 07/95] :memo: Added RST documentation --- docs/algorithms/iterators.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/algorithms/iterators.rst b/docs/algorithms/iterators.rst index 7536af9a3..0d590dddf 100644 --- a/docs/algorithms/iterators.rst +++ b/docs/algorithms/iterators.rst @@ -19,7 +19,13 @@ Gray Code Iterator BDL Input Iterator ------------------ -**Header:** ``fiction/algorithms/iter/bdl_input_iterator.hpp`` +.. tabs:: + .. tab:: C++ + **Header:** ``fiction/algorithms/iter/bdl_input_iterator.hpp`` -.. doxygenclass:: fiction::bdl_input_iterator - :members: + .. doxygenclass:: fiction::bdl_input_iterator + :members: + + .. tab:: Python + .. autoclass:: mnt.pyfiction.bdl_input_iterator + :members: From 76ba0368eb3ba3e99fe4f9cd6a6f3d367690bad6 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Sat, 25 May 2024 11:58:31 +0000 Subject: [PATCH 08/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../include/pyfiction/pybind11_mkdoc_docstrings.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index f2e64811c..e6f27ec76 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -485,19 +485,17 @@ static const char *__doc_fiction_bdl_input_iterator_current_input_index = R"doc(The current input index. There are :math:`2^n` possible input states for an :math:`n`-input BDL layout.)doc"; -static const char *__doc_fiction_bdl_input_iterator_get_number_of_inputs = +static const char *__doc_fiction_bdl_input_iterator_input_pairs = R"doc(The detected input BDL pairs.)doc"; + +static const char *__doc_fiction_bdl_input_iterator_layout = R"doc(The layout to iterate over.)doc"; + +static const char *__doc_fiction_bdl_input_iterator_num_input_pairs = R"doc(Returns the total number of input BDL pairs of the given SiDB gate layout. Returns: The number of input BDL pairs.)doc"; -static const char *__doc_fiction_bdl_input_iterator_input_pairs = R"doc(The detected input BDL pairs.)doc"; - -static const char *__doc_fiction_bdl_input_iterator_layout = R"doc(The layout to iterate over.)doc"; - -static const char *__doc_fiction_bdl_input_iterator_num_inputs = R"doc(The amount of input BDL pairs.)doc"; - static const char *__doc_fiction_bdl_input_iterator_operator_add = R"doc(Addition operator. Computes the input state of the current iterator plus the given integer. From a2c0a45cafe0979d8e500e2ede5b5acd23339643 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Sat, 1 Jun 2024 16:47:22 +0200 Subject: [PATCH 09/95] :thread: First attempt to port grid search from execution policies to manual threading --- .../simulation/sidb/operational_domain.hpp | 62 ++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 6b3b75097..9631d3901 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -306,14 +307,55 @@ class operational_domain_impl { mockturtle::stopwatch stop{stats.time_total}; - // for each x value in parallel - std::for_each(FICTION_EXECUTION_POLICY_PAR_UNSEQ x_indices.cbegin(), x_indices.cend(), - [this](const auto x) - { - // for each y value in parallel - std::for_each(FICTION_EXECUTION_POLICY_PAR_UNSEQ y_indices.cbegin(), y_indices.cend(), - [this, x](const auto y) { is_step_point_operational({x, y}); }); - }); + // calculate the size of each slice + const auto x_slice_size = (x_indices.size() + num_threads - 1) / num_threads; + + std::vector threads{}; + threads.reserve(num_threads); + + // launch threads, each with its own slice of the x indices + for (auto i = 0ul; i < num_threads; ++i) + { + const auto start = i * x_slice_size; + const auto end = std::min(start + x_slice_size, x_indices.size()); + + // no more work to distribute + if (start >= end) + { + break; + } + + threads.emplace_back( + [this, start, end] + { + for (auto it = x_indices.begin() + start; it != x_indices.begin() + end; ++it) + { + const auto x = *it; + + // process y_indices sequentially on each thread + std::for_each(y_indices.cbegin(), y_indices.cend(), + [this, x](const auto y) { is_step_point_operational({x, y}); }); + } + }); + } + + // wait for all threads to complete + for (auto& thread : threads) + { + if (thread.joinable()) + { + thread.join(); + } + } + + // // for each x value in parallel + // std::for_each(std::execution::par_unseq, x_indices.cbegin(), x_indices.cend(), + // [this](const auto x) + // { + // // for each y value in parallel + // std::for_each(std::execution::par_unseq, y_indices.cbegin(), y_indices.cend(), + // [this, x](const auto y) { is_step_point_operational({x, y}); }); + // }); log_stats(); @@ -540,6 +582,10 @@ class operational_domain_impl * Number of evaluated parameter combinations. */ std::atomic num_evaluated_parameter_combinations{0}; + /** + * Number of available hardware threads. + */ + const std::size_t num_threads{std::thread::hardware_concurrency()}; /** * A step point represents a point in the x and y dimension from 0 to the maximum number of steps. A step point does * not hold the actual parameter values, but the step values in the x and y dimension, respectively. From afe01f2cef8e69f9bdc0a41a81fa4152617a77e3 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 24 Jun 2024 16:47:48 +0200 Subject: [PATCH 10/95] :thread: Rewrite `random_sampling` in `operational_domain.hpp` to use `std::thread`s instead of execution policies --- .../simulation/sidb/operational_domain.hpp | 66 +++++++++++++------ 1 file changed, 45 insertions(+), 21 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 73361f765..e976fe7b8 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -319,16 +319,16 @@ class operational_domain_impl const auto start = i * x_slice_size; const auto end = std::min(start + x_slice_size, x_indices.size()); - // no more work to distribute if (start >= end) { - break; + break; // no more work to distribute } threads.emplace_back( [this, start, end] { - for (auto it = x_indices.begin() + start; it != x_indices.begin() + end; ++it) + for (auto it = x_indices.cbegin() + static_cast(start); + it != x_indices.cbegin() + static_cast(end); ++it) { const auto x = *it; @@ -348,15 +348,6 @@ class operational_domain_impl } } - // // for each x value in parallel - // std::for_each(std::execution::par_unseq, x_indices.cbegin(), x_indices.cend(), - // [this](const auto x) - // { - // // for each y value in parallel - // std::for_each(std::execution::par_unseq, y_indices.cbegin(), y_indices.cend(), - // [this, x](const auto y) { is_step_point_operational({x, y}); }); - // }); - log_stats(); return op_domain; @@ -374,9 +365,42 @@ class operational_domain_impl const auto step_point_samples = generate_random_step_points(samples); - // for each sample point in parallel - std::for_each(FICTION_EXECUTION_POLICY_PAR_UNSEQ step_point_samples.cbegin(), step_point_samples.cend(), - [this](const auto& sp) { is_step_point_operational(sp); }); + // calculate the size of each slice + const auto slice_size = (step_point_samples.size() + num_threads - 1) / num_threads; + + std::vector threads{}; + threads.reserve(num_threads); + + // launch threads, each with its own slice of random step points + for (auto i = 0ul; i < num_threads; ++i) + { + const auto start = i * slice_size; + const auto end = std::min(start + slice_size, step_point_samples.size()); + + if (start >= end) + { + break; // no more work to distribute + } + + threads.emplace_back( + [this, start, end, &step_point_samples] + { + for (auto it = step_point_samples.cbegin() + static_cast(start); + it != step_point_samples.cbegin() + static_cast(end); ++it) + { + is_step_point_operational(*it); + } + }); + } + + // wait for all threads to complete + for (auto& thread : threads) + { + if (thread.joinable()) + { + thread.join(); + } + } log_stats(); @@ -841,13 +865,13 @@ class operational_domain_impl return operational(); } /** - * Generates (potentially repeating) random `step_points` in the stored parameter range. The number of generated - * points is exactly equal to `samples`. + * Generates unique random `step_points` in the stored parameter range. The number of generated points is at most + * equal to `samples`. * - * @param samples Number of random `step_point`s to generate. - * @return A set of random `step_point`s in the stored parameter range. + * @param samples Maximum number of random `step_point`s to generate. + * @return A vector of unique random `step_point`s in the stored parameter range of size at most equal to `samples`. */ - [[nodiscard]] std::set generate_random_step_points(const std::size_t samples) noexcept + [[nodiscard]] std::vector generate_random_step_points(const std::size_t samples) noexcept { static std::mt19937_64 generator{std::random_device{}()}; @@ -864,7 +888,7 @@ class operational_domain_impl step_point_samples.insert(step_point{x_distribution(generator), y_distribution(generator)}); } - return step_point_samples; + return std::vector(step_point_samples.cbegin(), step_point_samples.cend()); } /** * Performs random sampling to find any operational parameter combination. This function is useful if a single From e97e8333faf9fb380651d8734cfeca02cb022434 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 24 Jun 2024 14:49:06 +0000 Subject: [PATCH 11/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../include/pyfiction/pybind11_mkdoc_docstrings.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index fe7d3fb58..9f6f7e9dc 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5773,15 +5773,15 @@ Parameter ``samples``: The (partial) operational domain of the layout.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_generate_random_step_points = -R"doc(Generates (potentially repeating) random `step_points` in the stored -parameter range. The number of generated points is exactly equal to -`samples`. +R"doc(Generates unique random `step_points` in the stored parameter range. +The number of generated points is at most equal to `samples`. Parameter ``samples``: - Number of random `step_point`s to generate. + Maximum number of random `step_point`s to generate. Returns: - A set of random `step_point`s in the stored parameter range.)doc"; + A vector of unique random `step_point`s in the stored parameter + range of size at most equal to `samples`.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_grid_search = R"doc(Performs a grid search over the specified parameter ranges with the @@ -5851,6 +5851,8 @@ static const char *__doc_fiction_detail_operational_domain_impl_num_evaluated_pa static const char *__doc_fiction_detail_operational_domain_impl_num_simulator_invocations = R"doc(Number of simulator invocations.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_num_threads = R"doc(Number of available hardware threads.)doc"; + static const char *__doc_fiction_detail_operational_domain_impl_num_x_steps = R"doc(Calculates the number of steps in the x dimension based on the provided parameters. From 99a43c7dab5ac51781f5a532cbf2a830e61a21ae Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 24 Jun 2024 17:21:53 +0200 Subject: [PATCH 12/95] :art: Reduced code duplication; more work can be done here in `grid_search` --- .../simulation/sidb/operational_domain.hpp | 86 ++++++++++--------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index e976fe7b8..48baa1b91 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -365,42 +365,7 @@ class operational_domain_impl const auto step_point_samples = generate_random_step_points(samples); - // calculate the size of each slice - const auto slice_size = (step_point_samples.size() + num_threads - 1) / num_threads; - - std::vector threads{}; - threads.reserve(num_threads); - - // launch threads, each with its own slice of random step points - for (auto i = 0ul; i < num_threads; ++i) - { - const auto start = i * slice_size; - const auto end = std::min(start + slice_size, step_point_samples.size()); - - if (start >= end) - { - break; // no more work to distribute - } - - threads.emplace_back( - [this, start, end, &step_point_samples] - { - for (auto it = step_point_samples.cbegin() + static_cast(start); - it != step_point_samples.cbegin() + static_cast(end); ++it) - { - is_step_point_operational(*it); - } - }); - } - - // wait for all threads to complete - for (auto& thread : threads) - { - if (thread.joinable()) - { - thread.join(); - } - } + simulate_operational_status_in_parallel(step_point_samples); log_stats(); @@ -422,9 +387,7 @@ class operational_domain_impl const auto step_point_samples = generate_random_step_points(samples); - // for each sample point in parallel - std::for_each(FICTION_EXECUTION_POLICY_PAR_UNSEQ step_point_samples.cbegin(), step_point_samples.cend(), - [this](const auto& sp) { is_step_point_operational(sp); }); + simulate_operational_status_in_parallel(step_point_samples); // a queue of (x, y) dimension step points to be evaluated std::queue queue{}; @@ -890,6 +853,51 @@ class operational_domain_impl return std::vector(step_point_samples.cbegin(), step_point_samples.cend()); } + /** + * Simulates the operational status of the given points in parallel. It divides the work among multiple threads to + * speed up the computation. + * + * @param step_points A vector of step points for which the operational status is to be simulated. + */ + void simulate_operational_status_in_parallel(const std::vector& step_points) + { + // calculate the size of each slice + const auto slice_size = (step_points.size() + num_threads - 1) / num_threads; + + std::vector threads{}; + threads.reserve(num_threads); + + // launch threads, each with its own slice of random step points + for (auto i = 0ul; i < num_threads; ++i) + { + const auto start = i * slice_size; + const auto end = std::min(start + slice_size, step_points.size()); + + if (start >= end) + { + break; // no more work to distribute + } + + threads.emplace_back( + [this, start, end, &step_points] + { + for (auto it = step_points.cbegin() + static_cast(start); + it != step_points.cbegin() + static_cast(end); ++it) + { + is_step_point_operational(*it); + } + }); + } + + // wait for all threads to complete + for (auto& thread : threads) + { + if (thread.joinable()) + { + thread.join(); + } + } + } /** * Performs random sampling to find any operational parameter combination. This function is useful if a single * starting point is required within the domain to expand from. This function returns the step in x and y dimension From 01a001363b280e3ffbabe57f2d683363a8e2c0f4 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 24 Jun 2024 15:53:26 +0000 Subject: [PATCH 13/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../include/pyfiction/pybind11_mkdoc_docstrings.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 9f6f7e9dc..e509fb8c0 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5937,6 +5937,14 @@ Parameter ``sim_params``: Parameter ``val``: Value to set the y dimension to.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_simulate_operational_status_in_parallel = +R"doc(Simulates the operational status of the given points in parallel. It +divides the work among multiple threads to speed up the computation. + +Parameter ``step_points``: + A vector of step points for which the operational status is to be + simulated.)doc"; + static const char *__doc_fiction_detail_operational_domain_impl_stats = R"doc(The statistics of the operational domain computation.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_step_point = From f3d507ecb3dfeff146a3805557b84576627e4d5b Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 27 Jun 2024 15:43:05 +0200 Subject: [PATCH 14/95] :sparkles: Introduce n-dimensional operational domain computation (needs testing) --- .../simulation/sidb/operational_domain.hpp | 466 ++++++++---------- include/fiction/utils/hash.hpp | 1 + .../simulation/sidb/operational_domain.cpp | 154 +++--- 3 files changed, 281 insertions(+), 340 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 48baa1b91..5c700a525 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -12,7 +12,6 @@ #include "fiction/technology/cell_technologies.hpp" #include "fiction/technology/physical_constants.hpp" #include "fiction/traits.hpp" -#include "fiction/utils/execution_utils.hpp" #include "fiction/utils/hash.hpp" #include "fiction/utils/phmap_utils.hpp" @@ -32,9 +31,8 @@ #include #include #include +#include #include -#include -#include #include namespace fiction @@ -73,54 +71,46 @@ struct operational_domain MU_MINUS }; /** - * X dimension sweep parameter. + * The dimensions to sweep over, ordered by priority. The first dimension is the x dimension, the second dimension + * is the y dimension, etc. */ - sweep_parameter x_dimension{operational_domain::sweep_parameter::EPSILON_R}; + std::vector dimensions{}; /** - * Y dimension sweep parameter. - */ - sweep_parameter y_dimension{operational_domain::sweep_parameter::LAMBDA_TF}; - /** - * The parameter point holds parameter values in the x and y dimension. + * The parameter point holds parameter values in an arbitrary number of dimensions. */ struct parameter_point { /** - * Standard default constructor. + * Default constructor. */ parameter_point() = default; /** * Standard constructor. * - * @param x_val X dimension parameter value. - * @param y_val Y dimension parameter value. - */ - parameter_point(const double x_val, const double y_val) : x{x_val}, y{y_val} {} - /** - * X dimension parameter value. + * @param values Parameter values for each dimension. */ - double x; + explicit parameter_point(const std::vector& values) : parameters(values) {} /** - * Y dimension parameter value. + * Parameter values for each dimension. */ - double y; + std::vector parameters; /** * Equality operator. * * @param other Other parameter point to compare with. - * @return `true` iff the parameter points are equal. + * @return `true` if the parameter points are equal. */ - [[nodiscard]] bool operator==(const parameter_point& other) const noexcept + bool operator==(const parameter_point& other) const noexcept { - return x == other.x && y == other.y; + return parameters == other.parameters; } /** * Inequality operator. * * @param other Other parameter point to compare with. - * @return `true` iff the parameter points are not equal. + * @return `true` if the parameter points are not equal. */ - [[nodiscard]] bool operator!=(const parameter_point& other) const noexcept + bool operator!=(const parameter_point& other) const noexcept { return !(*this == other); } @@ -131,18 +121,14 @@ struct operational_domain * @return The parameter value at the specified index. */ template - auto get() const noexcept + auto get() const { - static_assert(I < 2, "Index out of bounds for parameter_point"); - - if constexpr (I == 0) - { - return x; - } - else // I == 1 + if (I >= parameters.size()) { - return y; + throw std::out_of_range("Index out of bounds for parameter_point"); } + + return parameters[I]; } }; /** @@ -152,54 +138,50 @@ struct operational_domain */ locked_parallel_flat_hash_map operational_values{}; }; - /** - * Parameters for the operational domain computation. The parameters are used across the different operational domain - * computation algorithms. + * A range of values for a dimension sweep. The range is defined by a minimum value, a maximum value and a step size. */ -struct operational_domain_params +struct operational_domain_value_range { /** - * The simulation parameters for the operational domain computation. Most parameters will be kept constant across - * sweeps, but the sweep parameters are adjusted in each simulation step and thus overwritten in this object. + * The sweep parameter of the dimension. */ - sidb_simulation_parameters simulation_parameters{}; + operational_domain::sweep_parameter dimension; /** - * The simulation engine to be used for the operational domain computation. + * The minimum value of the dimension sweep. */ - sidb_simulation_engine sim_engine{sidb_simulation_engine::QUICKEXACT}; + double min{1.0}; /** - * The sweep parameter for the x dimension. + * The maximum value of the dimension sweep. */ - operational_domain::sweep_parameter x_dimension{operational_domain::sweep_parameter::EPSILON_R}; + double max{10.0}; /** - * The minimum value of the x dimension sweep. + * The step size of the dimension sweep. */ - double x_min{1.0}; - /** - * The maximum value of the x dimension sweep. - */ - double x_max{10.0}; - /** - * The step size of the x dimension sweep. - */ - double x_step{0.1}; - /** - * The sweep parameter for the y dimension. - */ - operational_domain::sweep_parameter y_dimension{operational_domain::sweep_parameter::LAMBDA_TF}; + double step{0.1}; +}; +/** + * Parameters for the operational domain computation. The parameters are used across the different operational domain + * computation algorithms. + */ +struct operational_domain_params +{ /** - * The minimum value of the y dimension sweep. + * The simulation parameters for the operational domain computation. Most parameters will be kept constant across + * sweeps, but the sweep parameters are adjusted in each simulation step and thus overwritten in this object. */ - double y_min{1.0}; + sidb_simulation_parameters simulation_parameters{}; /** - * The maximum value of the y dimension sweep. + * The simulation engine to be used for the operational domain computation. */ - double y_max{10.0}; + sidb_simulation_engine sim_engine{sidb_simulation_engine::QUICKEXACT}; /** - * The step size of the y dimension sweep. + * The dimensions to sweep over together with their value ranges, ordered by priority. The first dimension is the x + * dimension, the second dimension is the y dimension, etc. */ - double y_step{0.1}; + std::vector sweep_dimensions{ + operational_domain_value_range{operational_domain::sweep_parameter::EPSILON_R, 1.0, 10.0, 0.1}, + operational_domain_value_range{operational_domain::sweep_parameter::LAMBDA_TF, 1.0, 10.0, 0.1}}; /** * The parameters for the BDL pair detection, which is necessary during the operational domain computation to * detect input and output BDL pairs. @@ -258,43 +240,39 @@ class operational_domain_impl params{ps}, stats{st}, output_bdl_pairs{detect_bdl_pairs(layout, sidb_technology::cell_type::OUTPUT, params.bdl_params)}, - x_indices(num_x_steps() + 1), // pre-allocate the x dimension indices - y_indices(num_y_steps() + 1) // pre-allocate the y dimension indices + num_dimensions{params.sweep_dimensions.size()} { - x_values.reserve(num_x_steps() + 1); - y_values.reserve(num_y_steps() + 1); - - op_domain.x_dimension = params.x_dimension; - op_domain.y_dimension = params.y_dimension; + op_domain.dimensions.reserve(num_dimensions); - std::iota(x_indices.begin(), x_indices.end(), 0ul); - std::iota(y_indices.begin(), y_indices.end(), 0ul); + indices.reserve(num_dimensions); + values.reserve(num_dimensions); - // if the value of the x-parameter is greater than params.x_max after num_x_steps() steps, this value is - // ignored in the operational domain calculation. - if ((params.x_min + static_cast(x_indices.size() - 1) * params.x_step) - params.x_max > - physical_constants::POP_STABILITY_ERR) + for (auto d = 0u; d < num_dimensions; ++d) { - x_indices.pop_back(); - } - // if the value of the y-parameter is greater than params.y_max after num_y_steps() steps, this value is - // ignored in the operational domain calculation. - if (((params.y_min + static_cast(y_indices.size() - 1) * params.y_step) - params.y_max) > - physical_constants::POP_STABILITY_ERR) - { - y_indices.pop_back(); - } + op_domain.dimensions.push_back(params.sweep_dimensions[d].dimension); + + // generate the step points for the dimension + indices.push_back(std::vector(num_steps(d) + 1)); + std::iota(indices[d].begin(), indices[d].end(), 0ul); + + // if the value of the parameter is greater than params.max after num_x_steps() steps, this value is + // ignored in the operational domain calculation. + if ((params.sweep_dimensions[d].min + + static_cast(indices[d].size() - 1) * params.sweep_dimensions[d].step) - + params.sweep_dimensions[d].max > + physical_constants::POP_STABILITY_ERR) + { + indices[d].pop_back(); + } - // generate the x dimension values - for (std::size_t i = 0; i < x_indices.size(); ++i) - { - x_values.push_back(params.x_min + static_cast(i) * params.x_step); - } + values.emplace_back(); - // generate the y dimension values - for (std::size_t i = 0; i < y_indices.size(); ++i) - { - y_values.push_back(params.y_min + static_cast(i) * params.y_step); + // generate the values for the dimension + for (const auto i : indices[d]) + { + values[d].push_back(params.sweep_dimensions[d].min + + static_cast(i) * params.sweep_dimensions[d].step); + } } } /** @@ -307,47 +285,25 @@ class operational_domain_impl { mockturtle::stopwatch stop{stats.time_total}; - // calculate the size of each slice - const auto x_slice_size = (x_indices.size() + num_threads - 1) / num_threads; - - std::vector threads{}; - threads.reserve(num_threads); - - // launch threads, each with its own slice of the x indices - for (auto i = 0ul; i < num_threads; ++i) + // generate all possible step point combinations via the cartesian product + std::vector all_step_points{step_point{}}; + for (const auto& dimension : indices) { - const auto start = i * x_slice_size; - const auto end = std::min(start + x_slice_size, x_indices.size()); - - if (start >= end) + std::vector expanded_products{}; + for (const auto& product : all_step_points) { - break; // no more work to distribute - } - - threads.emplace_back( - [this, start, end] + for (const auto& element : dimension) { - for (auto it = x_indices.cbegin() + static_cast(start); - it != x_indices.cbegin() + static_cast(end); ++it) - { - const auto x = *it; - - // process y_indices sequentially on each thread - std::for_each(y_indices.cbegin(), y_indices.cend(), - [this, x](const auto y) { is_step_point_operational({x, y}); }); - } - }); - } - - // wait for all threads to complete - for (auto& thread : threads) - { - if (thread.joinable()) - { - thread.join(); + step_point new_product = product; + new_product.step_values.push_back(element); + expanded_products.push_back(new_product); + } } + all_step_points = expanded_products; } + simulate_operational_status_in_parallel(all_step_points); + log_stats(); return op_domain; @@ -383,6 +339,8 @@ class operational_domain_impl */ [[nodiscard]] operational_domain flood_fill(const std::size_t samples) noexcept { + assert(num_dimensions == 2 && "Flood fill is only supported for two dimensions"); + mockturtle::stopwatch stop{stats.time_total}; const auto step_point_samples = generate_random_step_points(samples); @@ -453,6 +411,8 @@ class operational_domain_impl */ [[nodiscard]] operational_domain contour_tracing(const std::size_t samples) noexcept { + assert(num_dimensions == 2 && "Contour tracing is only supported for two dimensions"); + mockturtle::stopwatch stop{stats.time_total}; // first, perform random sampling to find an operational starting point @@ -482,9 +442,11 @@ class operational_domain_impl const auto contour_starting_point = find_operational_contour_step_point(*starting_point); auto current_contour_point = contour_starting_point; - auto backtrack_point = current_contour_point.x == 0 ? - current_contour_point : - step_point{current_contour_point.x - 1, current_contour_point.y}; + + const auto x = current_contour_point.step_values[0]; + const auto y = current_contour_point.step_values[1]; + + auto backtrack_point = x == 0 ? current_contour_point : step_point{{x - 1, y}}; auto current_neighborhood = moore_neighborhood(current_contour_point); @@ -538,25 +500,21 @@ class operational_domain_impl */ operational_domain_stats& stats; /** - * The output BDL pair of the layout. + * The output BDL pairs of the layout. */ const std::vector>> output_bdl_pairs; /** - * X dimension steps. + * The number of dimensions. */ - std::vector x_indices; + const std::size_t num_dimensions; /** - * Y dimension steps. + * Dimension steps. */ - std::vector y_indices; + std::vector> indices; /** - * All x dimension values. + * All dimension values. */ - std::vector x_values; - /** - * All y dimension values. - */ - std::vector y_values; + std::vector> values; /** * The operational domain of the layout. */ @@ -588,18 +546,13 @@ class operational_domain_impl /** * Standard constructor. * - * @param x_step X dimension step value. - * @param y_step Y dimension step value. - */ - step_point(const std::size_t x_step, const std::size_t y_step) : x{x_step}, y{y_step} {} - /** - * X dimension step value. + * @param steps All dimension step values. */ - std::size_t x; + explicit step_point(const std::vector& steps) : step_values(steps) {} /** - * Y dimension step value. + * All dimension step values. */ - std::size_t y; + std::vector step_values; /** * Equality operator. * @@ -608,7 +561,7 @@ class operational_domain_impl */ [[nodiscard]] bool operator==(const step_point& other) const noexcept { - return x == other.x && y == other.y; + return step_values == other.step_values; } /** * Inequality operator. @@ -628,11 +581,7 @@ class operational_domain_impl */ [[nodiscard]] bool operator<(const step_point& other) const noexcept { - if (y != other.y) - { - return y < other.y; - } - return x < other.x; + return step_values < other.step_values; } }; /** @@ -643,7 +592,13 @@ class operational_domain_impl */ [[nodiscard]] operational_domain::parameter_point to_parameter_point(const step_point& sp) const noexcept { - return {x_values[sp.x], y_values[sp.y]}; + std::vector parameter_values{}; + for (auto d = 0u; d < num_dimensions; ++d) + { + parameter_values.push_back(values[d][sp.step_values[d]]); + } + + return operational_domain::parameter_point{parameter_values}; } /** * Converts a parameter point to a step point. @@ -653,49 +608,33 @@ class operational_domain_impl */ [[nodiscard]] step_point to_step_point(const operational_domain::parameter_point& pp) const noexcept { - const auto it_x = std::lower_bound(x_values.cbegin(), x_values.cend(), pp.x); - const auto it_y = std::lower_bound(y_values.cbegin(), y_values.cend(), pp.y); + std::vector step_values; + for (auto d = 0u; d < num_dimensions; ++d) + { + const auto it = std::lower_bound(values[d].cbegin(), values[d].cend(), pp.parameters[d]); - assert(it_x != x_values.cend() && "parameter point is outside of the x range"); - assert(it_y != y_values.cend() && "parameter point is outside of the y range"); + assert(it != values[d].cend() && "parameter point is outside of the value range"); - const auto x_dis = std::distance(x_values.cbegin(), it_x); - const auto y_dis = std::distance(y_values.cbegin(), it_y); + const auto dis = std::distance(values[d].cbegin(), it); - return {static_cast(x_dis), static_cast(y_dis)}; - } - /** - * Calculates the number of steps in the x dimension based on the provided parameters. - * - * @return The number of steps in the x dimension. - */ - [[nodiscard]] inline std::size_t num_x_steps() const noexcept - { - return static_cast(std::round((params.x_max - params.x_min) / params.x_step)); + step_values.push_back(static_cast(dis)); + } + + return step_point{step_values}; } /** - * Calculates the number of steps in the y dimension based on the provided parameters. + * Calculates the number of steps in the given dimension based on the provided parameters. * - * @return The number of steps in the y dimension. + * @return The number of steps in the given dimension. */ - [[nodiscard]] inline std::size_t num_y_steps() const noexcept + [[nodiscard]] inline std::size_t num_steps(const std::size_t dimension) const noexcept { - return static_cast(std::round((params.y_max - params.y_min) / params.y_step)); + assert(dimension < num_dimensions && "Invalid dimension"); + + return static_cast( + std::round((params.sweep_dimensions[dimension].max - params.sweep_dimensions[dimension].min) / + params.sweep_dimensions[dimension].step)); } - /** - * Potential sweep dimensions. - */ - enum class sweep_dimension : uint8_t - { - /** - * Sweep dimension X. - */ - X, - /** - * Sweep dimension Y. - */ - Y - }; /** * Helper function that sets the value of a sweep dimension in the simulation parameters. * @@ -704,10 +643,9 @@ class operational_domain_impl * @param dim Sweep dimension to set the value `val` to. */ inline void set_dimension_value(sidb_simulation_parameters& sim_parameters, const double val, - const sweep_dimension dim) const noexcept + const std::size_t dim) const noexcept { - operational_domain::sweep_parameter sweep_parameter = - dim == sweep_dimension::X ? params.x_dimension : params.y_dimension; + const operational_domain::sweep_parameter sweep_parameter = op_domain.dimensions[dim]; switch (sweep_parameter) { @@ -733,33 +671,13 @@ class operational_domain_impl } } /** - * Helper function that sets the value of the x dimension in the simulation parameters. - * - * @param sim_params Simulation parameter object to set the x dimension value of. - * @param val Value to set the x dimension to. - */ - inline void set_x_dimension_value(sidb_simulation_parameters& sim_params, const double val) const noexcept - { - set_dimension_value(sim_params, val, sweep_dimension::X); - } - /** - * Helper function that sets the value of the y dimension in the simulation parameters. - * - * @param sim_params Simulation parameter object to set the y dimension value of. - * @param val Value to set the y dimension to. - */ - inline void set_y_dimension_value(sidb_simulation_parameters& sim_params, const double val) const noexcept - { - set_dimension_value(sim_params, val, sweep_dimension::Y); - } - /** - * Determines whether the point at step position `(x, y)` has already been sampled and returns the operational value - * at `(x, y)` if it already exists. Here, `x` and `y` represent steps in the x and y dimension, respectively, not + * Determines whether the point at step position `(d1, ..., dn)` has already been sampled and returns the + * operational value at `(d1, ..., dn)` if it already exists. Here, `di` represents steps in the i-th dimension, not * the actual values of the parameters. * * @param sp Step point to check. - * @return The operational status of the point at step position `sp = (x, y)` or `std::nullopt` if `(x, y)` has not - * been sampled yet. + * @return The operational status of the point at step position `sp = (d1, ..., dn)` or `std::nullopt` if the point + * `(d1, ..., dn)` has not been sampled yet. */ [[nodiscard]] inline std::optional has_already_been_sampled(const step_point& sp) const noexcept { @@ -772,11 +690,11 @@ class operational_domain_impl return std::nullopt; } /** - * Logs and returns the operational status at the given point `sp = (x, y)`. If the point has already been sampled, - * it returns the cached value. Otherwise, a ground state simulation is performed for all input combinations of the - * stored layout using the given simulation parameters. It terminates as soon as a non-operational state is found. - * In the worst case, the function performs \f$2^n\f$ simulations, where \f$n\f$ is the number of inputs of the - * layout. This function is used by all operational domain computation techniques. + * Logs and returns the operational status at the given point `sp = (d1, ..., dn)`. If the point has already been + * sampled, it returns the cached value. Otherwise, a ground state simulation is performed for all input + * combinations of the stored layout using the given simulation parameters. It terminates as soon as a + * non-operational state is found. In the worst case, the function performs \f$2^i\f$ simulations, where \f$i\f$ is + * the number of inputs of the layout. This function is used by all operational domain computation techniques. * * Any investigated point is added to the stored `op_domain`, regardless of its operational status. * @@ -812,8 +730,10 @@ class operational_domain_impl ++num_evaluated_parameter_combinations; sidb_simulation_parameters sim_params = params.simulation_parameters; - set_x_dimension_value(sim_params, param_point.x); - set_y_dimension_value(sim_params, param_point.y); + for (auto d = 0u; d < num_dimensions; ++d) + { + set_dimension_value(sim_params, values[d][sp.step_values[d]], d); + } const auto& [status, sim_calls] = is_operational(layout, truth_table, is_operational_params{sim_params, params.sim_engine}); @@ -839,16 +759,29 @@ class operational_domain_impl static std::mt19937_64 generator{std::random_device{}()}; // instantiate distributions - std::uniform_int_distribution x_distribution{0, x_indices.size() - 1}; - std::uniform_int_distribution y_distribution{0, y_indices.size() - 1}; + std::vector> distributions{}; + distributions.reserve(num_dimensions); + + for (auto d = 0u; d < num_dimensions; ++d) + { + distributions.emplace_back(0, indices[d].size() - 1); + } // container for the random samples std::set step_point_samples{}; for (std::size_t i = 0; i < samples; ++i) { - // sample x and y dimension - step_point_samples.insert(step_point{x_distribution(generator), y_distribution(generator)}); + std::vector dimension_samples{}; + dimension_samples.reserve(num_dimensions); + + // sample all dimensions + for (auto d = 0u; d < num_dimensions; ++d) + { + dimension_samples.push_back(distributions[d](generator)); + } + + step_point_samples.insert(step_point{dimension_samples}); } return std::vector(step_point_samples.cbegin(), step_point_samples.cend()); @@ -900,7 +833,7 @@ class operational_domain_impl } /** * Performs random sampling to find any operational parameter combination. This function is useful if a single - * starting point is required within the domain to expand from. This function returns the step in x and y dimension + * starting point is required within the domain to expand from. This function returns the step in all dimensions * of the first operational point found. If no operational parameter combination can be found within the given * number of samples, the function returns `std::nullopt`. * @@ -917,7 +850,7 @@ class operational_domain_impl // determine the operational status const auto operational_value = is_step_point_operational(sample_step_point); - // if the parameter combination is operational, return its step values in x and y dimension + // if the parameter combination is operational, return its step values in all dimensions if (operational_value == operational_status::OPERATIONAL) { return sample_step_point; @@ -938,12 +871,17 @@ class operational_domain_impl */ [[nodiscard]] step_point find_operational_contour_step_point(const step_point& starting_point) noexcept { + assert(num_dimensions == 2 && "Contour tracing is only supported for two dimensions"); + assert(starting_point.step_values.size() == 2 && "Given step point must have 2 dimensions"); + auto latest_operational_point = starting_point; // move towards the left border of the parameter range - for (std::size_t x = starting_point.x; x > 0; --x) + for (std::size_t x = starting_point.step_values[0]; x > 0; --x) { - const auto left_step = step_point{x, starting_point.y}; + const auto y = starting_point.step_values[1]; + + const auto left_step = step_point{{x, y}}; const auto operational_status = is_step_point_operational(left_step); @@ -972,57 +910,64 @@ class operational_domain_impl */ [[nodiscard]] std::vector moore_neighborhood(const step_point& sp) const noexcept { + assert(num_dimensions == 2 && "Moore neighborhood is only supported for 2 dimensions"); + assert(sp.step_values.size() == 2 && "Given step point must have 2 dimensions"); + std::vector neighbors{}; neighbors.reserve(8); - const auto& [x, y] = sp; + const auto x = sp.step_values[0]; + const auto y = sp.step_values[1]; + + const auto num_x_indices = indices[0].size(); + const auto num_y_indices = indices[1].size(); const auto decr_x = (x > 0) ? x - 1 : x; - const auto incr_x = (x + 1 < x_indices.size()) ? x + 1 : x; + const auto incr_x = (x + 1 < num_x_indices) ? x + 1 : x; const auto decr_y = (y > 0) ? y - 1 : y; - const auto incr_y = (y + 1 < y_indices.size()) ? y + 1 : y; + const auto incr_y = (y + 1 < num_y_indices) ? y + 1 : y; // add neighbors in clockwise direction // right if (x != incr_x) { - neighbors.emplace_back(incr_x, y); + neighbors.emplace_back(std::vector{incr_x, y}); } // lower-right if (x != incr_x && y != decr_y) { - neighbors.emplace_back(incr_x, decr_y); + neighbors.emplace_back(std::vector{incr_x, decr_y}); } // down if (y != decr_y) { - neighbors.emplace_back(x, decr_y); + neighbors.emplace_back(std::vector{x, decr_y}); } // lower-left if (x != decr_x && y != decr_y) { - neighbors.emplace_back(decr_x, decr_y); + neighbors.emplace_back(std::vector{decr_x, decr_y}); } // left if (x != decr_x) { - neighbors.emplace_back(decr_x, y); + neighbors.emplace_back(std::vector{decr_x, y}); } // upper-left if (x != decr_x && y != incr_y) { - neighbors.emplace_back(decr_x, incr_y); + neighbors.emplace_back(std::vector{decr_x, incr_y}); } // up if (y != incr_y) { - neighbors.emplace_back(x, incr_y); + neighbors.emplace_back(std::vector{x, incr_y}); } // upper-right if (x != incr_x && y != incr_y) { - neighbors.emplace_back(incr_x, incr_y); + neighbors.emplace_back(std::vector{incr_x, incr_y}); } return neighbors; @@ -1179,6 +1124,11 @@ operational_domain operational_domain_flood_fill(const Lyt& lyt, const std::vect static_assert(has_sidb_technology_v, "Lyt is not an SiDB layout"); static_assert(kitty::is_truth_table::value, "TT is not a truth table"); + if (params.sweep_dimensions.size() != 2 && params.sweep_dimensions.size() != 3) + { + throw std::runtime_error("Flood fill is only applicable to 2 or 3 dimensions"); + } + operational_domain_stats st{}; detail::operational_domain_impl p{lyt, spec, params, st}; @@ -1234,6 +1184,11 @@ operational_domain operational_domain_contour_tracing(const Lyt& lyt, const std: static_assert(has_sidb_technology_v, "Lyt is not an SiDB layout"); static_assert(kitty::is_truth_table::value, "TT is not a truth table"); + if (params.sweep_dimensions.size() != 2) + { + throw std::runtime_error("Contour tracing is only applicable to exactly 2 dimensions"); + } + operational_domain_stats st{}; detail::operational_domain_impl p{lyt, spec, params, st}; @@ -1251,16 +1206,6 @@ operational_domain operational_domain_contour_tracing(const Lyt& lyt, const std: namespace std { -// make `operational_domain::parameter_point` compatible with `std::integral_constant` -template <> -struct tuple_size : std::integral_constant -{}; -// make `operational_domain::parameter_point` compatible with `std::tuple_element` -template -struct tuple_element -{ - using type = double; -}; // make `operational_domain::parameter_point` compatible with `std::hash` template <> struct hash @@ -1268,7 +1213,10 @@ struct hash size_t operator()(const fiction::operational_domain::parameter_point& p) const noexcept { size_t h = 0; - fiction::hash_combine(h, p.x, p.y); + for (const auto& d : p.parameters) + { + fiction::hash_combine(h, d); + } return h; } diff --git a/include/fiction/utils/hash.hpp b/include/fiction/utils/hash.hpp index 24ad5710e..21744f073 100644 --- a/include/fiction/utils/hash.hpp +++ b/include/fiction/utils/hash.hpp @@ -6,6 +6,7 @@ #define FICTION_HASH_HPP #include +#include #include #include #include diff --git a/test/algorithms/simulation/sidb/operational_domain.cpp b/test/algorithms/simulation/sidb/operational_domain.cpp index 80f4817d2..2bfe85ef5 100644 --- a/test/algorithms/simulation/sidb/operational_domain.cpp +++ b/test/algorithms/simulation/sidb/operational_domain.cpp @@ -14,37 +14,35 @@ #include #include +#include + #include #include using namespace fiction; -TEST_CASE("Structured binding support for parameter_points", "[operational-domain]") -{ - auto param_point = operational_domain::parameter_point{1.0, 2.0}; - - CHECK(param_point.x == 1.0); - CHECK(param_point.y == 2.0); - - const auto& [x, y] = param_point; - - CHECK(x == 1.0); - CHECK(y == 2.0); -} - void check_op_domain_params_and_operational_status(const operational_domain& op_domain, const operational_domain_params& params, const std::optional& status) noexcept { - CHECK(op_domain.x_dimension == params.x_dimension); - CHECK(op_domain.y_dimension == params.y_dimension); + REQUIRE(params.sweep_dimensions.size() == op_domain.dimensions.size()); + + for (auto d = 0u; d < params.sweep_dimensions.size(); ++d) + { + CHECK(op_domain.dimensions[d] == params.sweep_dimensions[d].dimension); + } for (const auto& [coord, op_value] : op_domain.operational_values) { - CHECK(coord.x - params.x_min > -physical_constants::POP_STABILITY_ERR); - CHECK(params.x_max - coord.x > -physical_constants::POP_STABILITY_ERR); - CHECK(coord.y - params.y_min > -physical_constants::POP_STABILITY_ERR); - CHECK(params.y_max - coord.y > -physical_constants::POP_STABILITY_ERR); + for (auto d = 0u; d < params.sweep_dimensions.size(); ++d) + { + const auto& sweep_param = params.sweep_dimensions[d]; + const auto& coord_value = coord.parameters[d]; + + CHECK(sweep_param.min <= coord_value); + CHECK(sweep_param.max >= coord_value); + CHECK(sweep_param.step > 0.0); + } if (status) { @@ -81,20 +79,22 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; - op_domain_params.x_dimension = operational_domain::sweep_parameter::EPSILON_R; - op_domain_params.y_dimension = operational_domain::sweep_parameter::LAMBDA_TF; + op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, + {operational_domain::sweep_parameter::LAMBDA_TF}}; operational_domain_stats op_domain_stats{}; SECTION("operational area, only one parameter point") { - op_domain_params.x_min = 5.5; - op_domain_params.x_max = 5.5; - op_domain_params.x_step = 0.1; + // set x-dimension + op_domain_params.sweep_dimensions[0].min = 5.5; + op_domain_params.sweep_dimensions[0].max = 5.5; + op_domain_params.sweep_dimensions[0].step = 0.1; - op_domain_params.y_min = 5.0; - op_domain_params.y_max = 5.0; - op_domain_params.y_step = 0.1; + // set y-dimension + op_domain_params.sweep_dimensions[1].min = 5.0; + op_domain_params.sweep_dimensions[1].max = 5.0; + op_domain_params.sweep_dimensions[1].step = 0.1; SECTION("grid_search") { @@ -169,13 +169,15 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("operational area, same number of steps in x- and y-direction") { - op_domain_params.x_min = 5.1; - op_domain_params.x_max = 6.0; - op_domain_params.x_step = 0.1; + // set x-dimension + op_domain_params.sweep_dimensions[0].min = 5.1; + op_domain_params.sweep_dimensions[0].max = 6.0; + op_domain_params.sweep_dimensions[0].step = 0.1; - op_domain_params.y_min = 4.5; - op_domain_params.y_max = 5.4; - op_domain_params.y_step = 0.1; + // set y-dimension + op_domain_params.sweep_dimensions[1].min = 4.5; + op_domain_params.sweep_dimensions[1].max = 5.4; + op_domain_params.sweep_dimensions[1].step = 0.1; SECTION("grid_search") { @@ -250,13 +252,15 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("operational area, different number of steps in x- and y-direction") { - op_domain_params.x_min = 5.1; - op_domain_params.x_max = 6.0; - op_domain_params.x_step = 0.1; + // set x-dimension + op_domain_params.sweep_dimensions[0].min = 5.1; + op_domain_params.sweep_dimensions[0].max = 6.0; + op_domain_params.sweep_dimensions[0].step = 0.1; - op_domain_params.y_min = 4.5; - op_domain_params.y_max = 4.9; - op_domain_params.y_step = 0.1; + // set y-dimension + op_domain_params.sweep_dimensions[1].min = 4.5; + op_domain_params.sweep_dimensions[1].max = 4.9; + op_domain_params.sweep_dimensions[1].step = 0.1; SECTION("grid_search") { @@ -332,13 +336,15 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("non-operational area") { - op_domain_params.x_min = 2.5; - op_domain_params.x_max = 3.4; - op_domain_params.x_step = 0.1; + // set x-dimension + op_domain_params.sweep_dimensions[0].min = 2.5; + op_domain_params.sweep_dimensions[0].max = 3.4; + op_domain_params.sweep_dimensions[0].step = 0.1; - op_domain_params.y_min = 4.5; - op_domain_params.y_max = 5.4; - op_domain_params.y_step = 0.1; + // set y-dimension + op_domain_params.sweep_dimensions[1].min = 4.5; + op_domain_params.sweep_dimensions[1].max = 5.4; + op_domain_params.sweep_dimensions[1].step = 0.1; SECTION("grid_search") { @@ -415,13 +421,15 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") } SECTION("floating-point error") { - op_domain_params.x_min = 2.5; - op_domain_params.x_max = 4.4; - op_domain_params.x_step = 0.9; + // set x-dimension + op_domain_params.sweep_dimensions[0].min = 2.5; + op_domain_params.sweep_dimensions[0].max = 4.4; + op_domain_params.sweep_dimensions[0].step = 0.9; - op_domain_params.y_min = 2.5; - op_domain_params.y_max = 2.5; - op_domain_params.y_step = 0.1; + // set y-dimension + op_domain_params.sweep_dimensions[1].min = 2.5; + op_domain_params.sweep_dimensions[1].max = 2.5; + op_domain_params.sweep_dimensions[1].step = 0.1; SECTION("flood_fill") { @@ -437,13 +445,15 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") } SECTION("semi-operational area") { - op_domain_params.x_min = 0.5; - op_domain_params.x_max = 4.25; - op_domain_params.x_step = 0.25; + // set x-dimension + op_domain_params.sweep_dimensions[0].min = 0.5; + op_domain_params.sweep_dimensions[0].max = 4.25; + op_domain_params.sweep_dimensions[0].step = 0.25; - op_domain_params.y_min = 0.5; - op_domain_params.y_max = 4.25; - op_domain_params.y_step = 0.25; + // set y-dimension + op_domain_params.sweep_dimensions[1].min = 0.5; + op_domain_params.sweep_dimensions[1].max = 4.25; + op_domain_params.sweep_dimensions[1].step = 0.25; SECTION("grid_search") { @@ -547,14 +557,8 @@ TEST_CASE("SiQAD's AND gate operational domain computation", "[operational-domai operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; - op_domain_params.x_dimension = operational_domain::sweep_parameter::EPSILON_R; - op_domain_params.x_min = 5.1; - op_domain_params.x_max = 6.0; - op_domain_params.x_step = 0.1; - op_domain_params.y_dimension = operational_domain::sweep_parameter::LAMBDA_TF; - op_domain_params.y_min = 4.5; - op_domain_params.y_max = 5.4; - op_domain_params.y_step = 0.1; + op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R, 5.1, 6.0, 0.1}, + {operational_domain::sweep_parameter::LAMBDA_TF, 4.5, 5.4, 0.1}}; operational_domain_stats op_domain_stats{}; @@ -670,14 +674,8 @@ TEST_CASE("SiQAD's AND gate operational domain computation, using cube coordinat operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; - op_domain_params.x_dimension = operational_domain::sweep_parameter::EPSILON_R; - op_domain_params.x_min = 5.1; - op_domain_params.x_max = 6.0; - op_domain_params.x_step = 0.1; - op_domain_params.y_dimension = operational_domain::sweep_parameter::LAMBDA_TF; - op_domain_params.y_min = 4.5; - op_domain_params.y_max = 5.4; - op_domain_params.y_step = 0.1; + op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R, 5.1, 6.0, 0.1}, + {operational_domain::sweep_parameter::LAMBDA_TF, 4.5, 5.4, 0.1}}; operational_domain_stats op_domain_stats{}; @@ -762,14 +760,8 @@ TEMPLATE_TEST_CASE("AND gate on the H-Si(111)-1x1 surface", "[operational-domain operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; - op_domain_params.x_dimension = operational_domain::sweep_parameter::EPSILON_R; - op_domain_params.x_min = 5.60; - op_domain_params.x_max = 5.61; - op_domain_params.x_step = 0.01; - op_domain_params.y_dimension = operational_domain::sweep_parameter::LAMBDA_TF; - op_domain_params.y_min = 5.0; - op_domain_params.y_max = 5.01; - op_domain_params.y_step = 0.01; + op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R, 5.60, 5.61, 0.01}, + {operational_domain::sweep_parameter::LAMBDA_TF, 5.0, 5.01, 0.01}}; operational_domain_stats op_domain_stats{}; From 73f6cca9b56fe9b872d3e97e2ad63a0ff7b812eb Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 27 Jun 2024 13:44:18 +0000 Subject: [PATCH 15/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 151 +++++++----------- 1 file changed, 54 insertions(+), 97 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index e509fb8c0..44562c6ac 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5743,7 +5743,7 @@ static const char *__doc_fiction_detail_operational_domain_impl_find_operational R"doc(Performs random sampling to find any operational parameter combination. This function is useful if a single starting point is required within the domain to expand from. This function returns the -step in x and y dimension of the first operational point found. If no +step in all dimensions of the first operational point found. If no operational parameter combination can be found within the given number of samples, the function returns `std::nullopt`. @@ -5792,26 +5792,29 @@ The operational status is computed for each parameter combination. The operational domain of the layout.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_has_already_been_sampled = -R"doc(Determines whether the point at step position `(x, y)` has already -been sampled and returns the operational value at `(x, y)` if it -already exists. Here, `x` and `y` represent steps in the x and y -dimension, respectively, not the actual values of the parameters. +R"doc(Determines whether the point at step position `(d1, ..., dn)` has +already been sampled and returns the operational value at `(d1, ..., +dn)` if it already exists. Here, `di` represents steps in the i-th +dimension, not the actual values of the parameters. Parameter ``sp``: Step point to check. Returns: - The operational status of the point at step position `sp = (x, y)` - or `std::nullopt` if `(x, y)` has not been sampled yet.)doc"; + The operational status of the point at step position `sp = (d1, + ..., dn)` or `std::nullopt` if the point `(d1, ..., dn)` has not + been sampled yet.)doc"; + +static const char *__doc_fiction_detail_operational_domain_impl_indices = R"doc(Dimension steps.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_is_step_point_operational = -R"doc(Logs and returns the operational status at the given point `sp = (x, -y)`. If the point has already been sampled, it returns the cached -value. Otherwise, a ground state simulation is performed for all input -combinations of the stored layout using the given simulation +R"doc(Logs and returns the operational status at the given point `sp = (d1, +..., dn)`. If the point has already been sampled, it returns the +cached value. Otherwise, a ground state simulation is performed for +all input combinations of the stored layout using the given simulation parameters. It terminates as soon as a non-operational state is found. -In the worst case, the function performs :math:`2^n` simulations, -where :math:`n` is the number of inputs of the layout. This function +In the worst case, the function performs :math:`2^i` simulations, +where :math:`i` is the number of inputs of the layout. This function is used by all operational domain computation techniques. Any investigated point is added to the stored `op_domain`, regardless @@ -5847,25 +5850,20 @@ Parameter ``sp``: Returns: The Moore neighborhood of the step point at `sp = (x, y)`.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_num_dimensions = R"doc(The number of dimensions.)doc"; + static const char *__doc_fiction_detail_operational_domain_impl_num_evaluated_parameter_combinations = R"doc(Number of evaluated parameter combinations.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_num_simulator_invocations = R"doc(Number of simulator invocations.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_num_threads = R"doc(Number of available hardware threads.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_num_x_steps = -R"doc(Calculates the number of steps in the x dimension based on the +static const char *__doc_fiction_detail_operational_domain_impl_num_steps = +R"doc(Calculates the number of steps in the given dimension based on the provided parameters. Returns: - The number of steps in the x dimension.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_num_y_steps = -R"doc(Calculates the number of steps in the y dimension based on the -provided parameters. + The number of steps in the given dimension.)doc"; -Returns: - The number of steps in the y dimension.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_num_threads = R"doc(Number of available hardware threads.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_op_domain = R"doc(The operational domain of the layout.)doc"; @@ -5888,7 +5886,7 @@ Parameter ``ps``: Parameter ``st``: Statistics of the process.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_output_bdl_pairs = R"doc(The output BDL pair of the layout.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_output_bdl_pairs = R"doc(The output BDL pairs of the layout.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_params = R"doc(The parameters for the operational domain computation.)doc"; @@ -5917,26 +5915,6 @@ Parameter ``val``: Parameter ``dim``: Sweep dimension to set the value `val` to.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_set_x_dimension_value = -R"doc(Helper function that sets the value of the x dimension in the -simulation parameters. - -Parameter ``sim_params``: - Simulation parameter object to set the x dimension value of. - -Parameter ``val``: - Value to set the x dimension to.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_set_y_dimension_value = -R"doc(Helper function that sets the value of the y dimension in the -simulation parameters. - -Parameter ``sim_params``: - Simulation parameter object to set the y dimension value of. - -Parameter ``val``: - Value to set the y dimension to.)doc"; - static const char *__doc_fiction_detail_operational_domain_impl_simulate_operational_status_in_parallel = R"doc(Simulates the operational status of the given points in parallel. It divides the work among multiple threads to speed up the computation. @@ -5988,21 +5966,10 @@ static const char *__doc_fiction_detail_operational_domain_impl_step_point_step_ static const char *__doc_fiction_detail_operational_domain_impl_step_point_step_point_2 = R"doc(Standard constructor. -Parameter ``x_step``: - X dimension step value. - -Parameter ``y_step``: - Y dimension step value.)doc"; +Parameter ``steps``: + All dimension step values.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_step_point_x = R"doc(X dimension step value.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_step_point_y = R"doc(Y dimension step value.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_sweep_dimension = R"doc(Potential sweep dimensions.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_sweep_dimension_X = R"doc(Sweep dimension X.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_sweep_dimension_Y = R"doc(Sweep dimension Y.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_step_point_step_values = R"doc(All dimension step values.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_to_parameter_point = R"doc(Converts a step point to a parameter point. @@ -6024,13 +5991,7 @@ Parameter ``pp``: static const char *__doc_fiction_detail_operational_domain_impl_truth_table = R"doc(The specification of the layout.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_x_indices = R"doc(X dimension steps.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_x_values = R"doc(All x dimension values.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_y_indices = R"doc(Y dimension steps.)doc"; - -static const char *__doc_fiction_detail_operational_domain_impl_y_values = R"doc(All y dimension values.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_values = R"doc(All dimension values.)doc"; static const char *__doc_fiction_detail_optimize_output_positions = R"doc(Utility function that moves outputs from the last row to the previous @@ -11953,6 +11914,10 @@ Parameter ``stats``: Returns: The (partial) operational domain of the layout.)doc"; +static const char *__doc_fiction_operational_domain_dimensions = +R"doc(The dimensions to sweep over, ordered by priority. The first dimension +is the x dimension, the second dimension is the y dimension, etc.)doc"; + static const char *__doc_fiction_operational_domain_flood_fill = R"doc(Computes the operational domain of the given SiDB cell-level layout. The operational domain is the set of all parameter combinations for @@ -12059,7 +12024,9 @@ map is the parameter point, which holds the parameter values in the x and y dimension. The operational status is stored as the value of the map.)doc"; -static const char *__doc_fiction_operational_domain_parameter_point = R"doc(The parameter point holds parameter values in the x and y dimension.)doc"; +static const char *__doc_fiction_operational_domain_parameter_point = +R"doc(The parameter point holds parameter values in an arbitrary number of +dimensions.)doc"; static const char *__doc_fiction_operational_domain_parameter_point_get = R"doc(Support for structured bindings. @@ -12077,7 +12044,7 @@ Parameter ``other``: Other parameter point to compare with. Returns: - `true` iff the parameter points are equal.)doc"; + `true` if the parameter points are equal.)doc"; static const char *__doc_fiction_operational_domain_parameter_point_operator_ne = R"doc(Inequality operator. @@ -12086,22 +12053,17 @@ Parameter ``other``: Other parameter point to compare with. Returns: - `true` iff the parameter points are not equal.)doc"; + `true` if the parameter points are not equal.)doc"; -static const char *__doc_fiction_operational_domain_parameter_point_parameter_point = R"doc(Standard default constructor.)doc"; +static const char *__doc_fiction_operational_domain_parameter_point_parameter_point = R"doc(Default constructor.)doc"; static const char *__doc_fiction_operational_domain_parameter_point_parameter_point_2 = R"doc(Standard constructor. -Parameter ``x_val``: - X dimension parameter value. - -Parameter ``y_val``: - Y dimension parameter value.)doc"; +Parameter ``values``: + Parameter values for each dimension.)doc"; -static const char *__doc_fiction_operational_domain_parameter_point_x = R"doc(X dimension parameter value.)doc"; - -static const char *__doc_fiction_operational_domain_parameter_point_y = R"doc(Y dimension parameter value.)doc"; +static const char *__doc_fiction_operational_domain_parameter_point_parameters = R"doc(Parameter values for each dimension.)doc"; static const char *__doc_fiction_operational_domain_params = R"doc(Parameters for the operational domain computation. The parameters are @@ -12122,21 +12084,10 @@ parameters will be kept constant across sweeps, but the sweep parameters are adjusted in each simulation step and thus overwritten in this object.)doc"; -static const char *__doc_fiction_operational_domain_params_x_dimension = R"doc(The sweep parameter for the x dimension.)doc"; - -static const char *__doc_fiction_operational_domain_params_x_max = R"doc(The maximum value of the x dimension sweep.)doc"; - -static const char *__doc_fiction_operational_domain_params_x_min = R"doc(The minimum value of the x dimension sweep.)doc"; - -static const char *__doc_fiction_operational_domain_params_x_step = R"doc(The step size of the x dimension sweep.)doc"; - -static const char *__doc_fiction_operational_domain_params_y_dimension = R"doc(The sweep parameter for the y dimension.)doc"; - -static const char *__doc_fiction_operational_domain_params_y_max = R"doc(The maximum value of the y dimension sweep.)doc"; - -static const char *__doc_fiction_operational_domain_params_y_min = R"doc(The minimum value of the y dimension sweep.)doc"; - -static const char *__doc_fiction_operational_domain_params_y_step = R"doc(The step size of the y dimension sweep.)doc"; +static const char *__doc_fiction_operational_domain_params_sweep_dimensions = +R"doc(The dimensions to sweep over together with their value ranges, ordered +by priority. The first dimension is the x dimension, the second +dimension is the y dimension, etc.)doc"; static const char *__doc_fiction_operational_domain_random_sampling = R"doc(Computes the operational domain of the given SiDB cell-level layout. @@ -12205,9 +12156,17 @@ static const char *__doc_fiction_operational_domain_sweep_parameter_LAMBDA_TF = static const char *__doc_fiction_operational_domain_sweep_parameter_MU_MINUS = R"doc(The energy transition level.)doc"; -static const char *__doc_fiction_operational_domain_x_dimension = R"doc(X dimension sweep parameter.)doc"; +static const char *__doc_fiction_operational_domain_value_range = +R"doc(A range of values for a dimension sweep. The range is defined by a +minimum value, a maximum value and a step size.)doc"; + +static const char *__doc_fiction_operational_domain_value_range_dimension = R"doc(The sweep parameter of the dimension.)doc"; + +static const char *__doc_fiction_operational_domain_value_range_max = R"doc(The maximum value of the dimension sweep.)doc"; -static const char *__doc_fiction_operational_domain_y_dimension = R"doc(Y dimension sweep parameter.)doc"; +static const char *__doc_fiction_operational_domain_value_range_min = R"doc(The minimum value of the dimension sweep.)doc"; + +static const char *__doc_fiction_operational_domain_value_range_step = R"doc(The step size of the dimension sweep.)doc"; static const char *__doc_fiction_operational_input_patterns = R"doc(This function determines the input combinations for which the SiDB- @@ -15943,8 +15902,6 @@ static const char *__doc_std_hash_operator_call_6 = R"doc()doc"; static const char *__doc_std_iterator_traits = R"doc()doc"; -static const char *__doc_std_tuple_size = R"doc()doc"; - #if defined(__GNUG__) #pragma GCC diagnostic pop #endif From efaa0812c7108285d306ebb4700612adca19ad85 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 27 Jun 2024 15:46:55 +0200 Subject: [PATCH 16/95] :art: Small code clean up --- .../simulation/sidb/operational_domain.hpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 5c700a525..c74a702ac 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -916,6 +916,9 @@ class operational_domain_impl std::vector neighbors{}; neighbors.reserve(8); + const auto emplace = [&neighbors](const auto x, const auto y) noexcept + { neighbors.emplace_back(std::vector{x, y}); }; + const auto x = sp.step_values[0]; const auto y = sp.step_values[1]; @@ -932,42 +935,42 @@ class operational_domain_impl // right if (x != incr_x) { - neighbors.emplace_back(std::vector{incr_x, y}); + emplace(incr_x, y); } // lower-right if (x != incr_x && y != decr_y) { - neighbors.emplace_back(std::vector{incr_x, decr_y}); + emplace(incr_x, decr_y); } // down if (y != decr_y) { - neighbors.emplace_back(std::vector{x, decr_y}); + emplace(x, decr_y); } // lower-left if (x != decr_x && y != decr_y) { - neighbors.emplace_back(std::vector{decr_x, decr_y}); + emplace(decr_x, decr_y); } // left if (x != decr_x) { - neighbors.emplace_back(std::vector{decr_x, y}); + emplace(decr_x, y); } // upper-left if (x != decr_x && y != incr_y) { - neighbors.emplace_back(std::vector{decr_x, incr_y}); + emplace(decr_x, incr_y); } // up if (y != incr_y) { - neighbors.emplace_back(std::vector{x, incr_y}); + emplace(x, incr_y); } // upper-right if (x != incr_x && y != incr_y) { - neighbors.emplace_back(std::vector{incr_x, incr_y}); + emplace(incr_x, incr_y); } return neighbors; From 5326399017f245a3dd19ee42be40e2bc002ed6d5 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 17 Jul 2024 14:01:47 +0200 Subject: [PATCH 17/95] :sparkles: Added 3D Moore neighborhood --- .../simulation/sidb/operational_domain.hpp | 105 +++++++++++++++--- 1 file changed, 90 insertions(+), 15 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index c74a702ac..591fe7a4e 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -339,7 +339,8 @@ class operational_domain_impl */ [[nodiscard]] operational_domain flood_fill(const std::size_t samples) noexcept { - assert(num_dimensions == 2 && "Flood fill is only supported for two dimensions"); + assert((num_dimensions == 2 || num_dimensions == 3) && + "Flood fill is only supported for two and three dimensions"); mockturtle::stopwatch stop{stats.time_total}; @@ -347,17 +348,30 @@ class operational_domain_impl simulate_operational_status_in_parallel(step_point_samples); - // a queue of (x, y) dimension step points to be evaluated + // a queue of (x, y[, z]) dimension step points to be evaluated std::queue queue{}; // a utility function that adds the adjacent points to the queue for further evaluation const auto queue_next_points = [this, &queue](const step_point& sp) { - for (const auto& m : moore_neighborhood(sp)) + if (num_dimensions == 2) { - if (!has_already_been_sampled(m)) + for (const auto& m : moore_neighborhood_2d(sp)) { - queue.push(m); + if (!has_already_been_sampled(m)) + { + queue.push(m); + } + } + } + else // num_dimensions == 3 + { + for (const auto& m : moore_neighborhood_3d(sp)) + { + if (!has_already_been_sampled(m)) + { + queue.push(m); + } } } }; @@ -448,7 +462,7 @@ class operational_domain_impl auto backtrack_point = x == 0 ? current_contour_point : step_point{{x - 1, y}}; - auto current_neighborhood = moore_neighborhood(current_contour_point); + auto current_neighborhood = moore_neighborhood_2d(current_contour_point); auto next_point = contour_starting_point; @@ -473,7 +487,7 @@ class operational_domain_impl backtrack_point = next_point; } - current_neighborhood = moore_neighborhood(current_contour_point); + current_neighborhood = moore_neighborhood_2d(current_contour_point); next_point = next_clockwise_point(current_neighborhood, backtrack_point); } @@ -900,17 +914,17 @@ class operational_domain_impl return latest_operational_point; } /** - * Returns the Moore neighborhood of the step point at `sp = (x, y)`. The Moore neighborhood is the set of all - * points that are adjacent to `(x, y)` including the diagonals. Thereby, the Moore neighborhood contains up to 8 - * points as points outside of the parameter range are not gathered. The points are returned in clockwise order - * starting from the right neighbor. + * Returns the 2D Moore neighborhood of the step point at `sp = (x, y)`. The 2D Moore neighborhood is the set of all + * points that are adjacent to `(x, y)` in the plane including the diagonals. Thereby, the 2D Moore neighborhood + * contains up to 8 points as points outside of the parameter range are not gathered. The points are returned in + * clockwise order starting from the right neighbor. * - * @param sp Step point to get the Moore neighborhood of. - * @return The Moore neighborhood of the step point at `sp = (x, y)`. + * @param sp Step point to get the 2D Moore neighborhood of. + * @return The 2D Moore neighborhood of the step point at `sp = (x, y)`. */ - [[nodiscard]] std::vector moore_neighborhood(const step_point& sp) const noexcept + [[nodiscard]] std::vector moore_neighborhood_2d(const step_point& sp) const noexcept { - assert(num_dimensions == 2 && "Moore neighborhood is only supported for 2 dimensions"); + assert(num_dimensions == 2 && "2D Moore neighborhood is only supported for 2 dimensions"); assert(sp.step_values.size() == 2 && "Given step point must have 2 dimensions"); std::vector neighbors{}; @@ -975,6 +989,67 @@ class operational_domain_impl return neighbors; }; + /** + * Returns the 3D Moore neighborhood of the step point at `sp = (x, y)`. The 3D Moore neighborhood is the set of all + * points that are adjacent to `(x, y)` in the 3D space including the diagonals. Thereby, the 3D Moore neighborhood + * contains up to 26 points as points outside of the parameter range are not gathered. The points are returned in + * no particular order. + * + * @param sp Step point to get the 3D Moore neighborhood of. + * @return The 3D Moore neighborhood of the step point at `sp = (x, y)`. + */ + [[nodiscard]] std::vector moore_neighborhood_3d(const step_point& sp) const noexcept + { + assert(num_dimensions == 3 && "3D Moore neighborhood is only supported for 3 dimensions"); + assert(sp.step_values.size() == 3 && "Given step point must have 3 dimensions"); + + std::vector neighbors{}; + neighbors.reserve(26); + + const auto emplace = [&neighbors](const auto x, const auto y, const auto z) noexcept + { neighbors.emplace_back(std::vector{x, y, z}); }; + + const auto x = sp.step_values[0]; + const auto y = sp.step_values[1]; + const auto z = sp.step_values[2]; + + const auto num_x_indices = indices[0].size(); + const auto num_y_indices = indices[1].size(); + const auto num_z_indices = indices[2].size(); + + // add neighbors in no particular order + + // iterate over all combinations of (-1, 0, 1) offsets for x, y, and z + for (const int64_t x_offset : {-1, 0, 1}) + { + for (const int64_t y_offset : {-1, 0, 1}) + { + for (const int64_t z_offset : {-1, 0, 1}) + { + // skip the center cell + if (x_offset == 0 && y_offset == 0 && z_offset == 0) + { + continue; + } + + // calculate new coordinate + const int64_t dx = static_cast(x) + x_offset; + const int64_t dy = static_cast(y) + y_offset; + const int64_t dz = static_cast(z) + z_offset; + + // check if the new coordinate is within the bounds + if ((dx >= 0 && dx < static_cast(num_x_indices)) && + (dy >= 0 && dy < static_cast(num_y_indices)) && + (dz >= 0 && dz < static_cast(num_z_indices))) + { + emplace(static_cast(dx), static_cast(dy), static_cast(dz)); + } + } + } + } + + return neighbors; + } /** * Helper function that writes the the statistics of the operational domain computation to the statistics object. * Due to data races that can occur during the computation, each value is temporarily held in an atomic variable and From f0b28904d3aa66b52de9ece828d999a44eec7b22 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 17 Jul 2024 16:45:31 +0200 Subject: [PATCH 18/95] :white_check_mark: Added test cases for 3-dimensional operational domain computation --- .../simulation/sidb/operational_domain.cpp | 223 +++++++++++++++++- 1 file changed, 220 insertions(+), 3 deletions(-) diff --git a/test/algorithms/simulation/sidb/operational_domain.cpp b/test/algorithms/simulation/sidb/operational_domain.cpp index 2bfe85ef5..70c4c81df 100644 --- a/test/algorithms/simulation/sidb/operational_domain.cpp +++ b/test/algorithms/simulation/sidb/operational_domain.cpp @@ -4,13 +4,13 @@ #include +#include "fiction/layouts/coordinates.hpp" #include "utils/blueprints/layout_blueprints.hpp" #include #include #include #include -#include #include #include @@ -112,6 +112,30 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations == 1); CHECK(op_domain_stats.num_operational_parameter_combinations == 1); CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_grid_search(lat, std::vector{create_id_tt()}, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct size + CHECK(op_domain_3d.operational_values.size() == 1); + + // for the selected range, all samples should be within the parameters and operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations == 2); + CHECK(op_domain_stats.num_evaluated_parameter_combinations == 1); + CHECK(op_domain_stats.num_operational_parameter_combinations == 1); + CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + } } SECTION("random_sampling") { @@ -130,6 +154,31 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations > 0); CHECK(op_domain_stats.num_operational_parameter_combinations <= 100); CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_random_sampling(lat, std::vector{create_id_tt()}, 100, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct size + CHECK(op_domain_3d.operational_values.size() == 1); + + // for the selected range, all samples should be within the parameters and operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations <= 200); + CHECK(op_domain_stats.num_evaluated_parameter_combinations <= 100); + CHECK(op_domain_stats.num_evaluated_parameter_combinations > 0); + CHECK(op_domain_stats.num_operational_parameter_combinations <= 100); + CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + } } SECTION("flood_fill") { @@ -147,6 +196,30 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations == 1); CHECK(op_domain_stats.num_operational_parameter_combinations == 1); CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 1, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct size + CHECK(op_domain_3d.operational_values.size() == 1); + + // for the selected range, all samples should be within the parameters and operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations == 2); + CHECK(op_domain_stats.num_evaluated_parameter_combinations == 1); + CHECK(op_domain_stats.num_operational_parameter_combinations == 1); + CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + } } SECTION("contour_tracing") { @@ -267,7 +340,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") const auto op_domain = operational_domain_grid_search(lat, std::vector{create_id_tt()}, op_domain_params, &op_domain_stats); - // check if the operational domain has the correct size (10 steps in each dimension) + // check if the operational domain has the correct size CHECK(op_domain.operational_values.size() == 50); // for the selected range, all samples should be within the parameters and operational @@ -278,6 +351,30 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations == 50); CHECK(op_domain_stats.num_operational_parameter_combinations == 50); CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_grid_search(lat, std::vector{create_id_tt()}, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct size + CHECK(op_domain_3d.operational_values.size() == 350); + + // for the selected range, all samples should be within the parameters and operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations == 700); + CHECK(op_domain_stats.num_evaluated_parameter_combinations == 350); + CHECK(op_domain_stats.num_operational_parameter_combinations == 350); + CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + } } SECTION("random_sampling") { @@ -296,8 +393,32 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations > 0); CHECK(op_domain_stats.num_operational_parameter_combinations <= 100); CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); - } + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_random_sampling(lat, std::vector{create_id_tt()}, 100, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct size + CHECK(op_domain_3d.operational_values.size() <= 350); + + // for the selected range, all samples should be within the parameters and operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations <= 700); + CHECK(op_domain_stats.num_evaluated_parameter_combinations <= 350); + CHECK(op_domain_stats.num_evaluated_parameter_combinations > 0); + CHECK(op_domain_stats.num_operational_parameter_combinations <= 350); + CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + } + } SECTION("flood_fill") { const auto op_domain = operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 1, @@ -314,6 +435,30 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations == 50); CHECK(op_domain_stats.num_operational_parameter_combinations == 50); CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 100, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct size + CHECK(op_domain_3d.operational_values.size() == 350); + + // for the selected range, all samples should be within the parameters and operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations == 700); + CHECK(op_domain_stats.num_evaluated_parameter_combinations == 350); + CHECK(op_domain_stats.num_operational_parameter_combinations == 350); + CHECK(op_domain_stats.num_non_operational_parameter_combinations == 0); + } } SECTION("contour_tracing") { @@ -363,6 +508,30 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations == 100); CHECK(op_domain_stats.num_operational_parameter_combinations == 0); CHECK(op_domain_stats.num_non_operational_parameter_combinations == 100); + + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_grid_search(lat, std::vector{create_id_tt()}, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct size + CHECK(op_domain_3d.operational_values.size() == 500); + + // for the selected range, all samples should be within the parameters and non-operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::NON_OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations <= 1000); + CHECK(op_domain_stats.num_evaluated_parameter_combinations == 500); + CHECK(op_domain_stats.num_operational_parameter_combinations == 0); + CHECK(op_domain_stats.num_non_operational_parameter_combinations == 500); + } } SECTION("random_sampling") { @@ -381,6 +550,30 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations <= 5000); CHECK(op_domain_stats.num_operational_parameter_combinations == 0); CHECK(op_domain_stats.num_non_operational_parameter_combinations <= 5000); + + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_random_sampling(lat, std::vector{create_id_tt()}, 5000, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct maximum size + CHECK(op_domain_3d.operational_values.size() <= 5000); + + // for the selected range, all samples should be within the parameters and non-operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::NON_OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations < 10000); + CHECK(op_domain_stats.num_evaluated_parameter_combinations <= 5000); + CHECK(op_domain_stats.num_operational_parameter_combinations == 0); + CHECK(op_domain_stats.num_non_operational_parameter_combinations <= 5000); + } } SECTION("flood_fill") { @@ -399,6 +592,30 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") CHECK(op_domain_stats.num_evaluated_parameter_combinations <= 100); CHECK(op_domain_stats.num_operational_parameter_combinations == 0); CHECK(op_domain_stats.num_non_operational_parameter_combinations <= 100); + + SECTION("3-dimensional") + { + const auto z_dimension = + operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; + + op_domain_params.sweep_dimensions.push_back(z_dimension); + + const auto op_domain_3d = operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 25, + op_domain_params, &op_domain_stats); + + // check if the operational domain has the correct maximum size + CHECK(op_domain_3d.operational_values.size() <= 500); + + // for the selected range, all samples should be within the parameters and non-operational + check_op_domain_params_and_operational_status(op_domain_3d, op_domain_params, + operational_status::NON_OPERATIONAL); + + CHECK(mockturtle::to_seconds(op_domain_stats.time_total) > 0.0); + CHECK(op_domain_stats.num_simulator_invocations <= 1000); + CHECK(op_domain_stats.num_evaluated_parameter_combinations <= 500); + CHECK(op_domain_stats.num_operational_parameter_combinations == 0); + CHECK(op_domain_stats.num_non_operational_parameter_combinations <= 500); + } } SECTION("contour_tracing") { From 4b13e7f3999b3ca5b38f8482de50ab47f2e4f577 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 17 Jul 2024 17:03:46 +0200 Subject: [PATCH 19/95] :sparkles: Support n-dimensional operational domains in `write_operational_domain` --- .../fiction/io/write_operational_domain.hpp | 43 ++++++++++++++++--- test/io/write_operational_domain.cpp | 34 ++++++++++----- 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/include/fiction/io/write_operational_domain.hpp b/include/fiction/io/write_operational_domain.hpp index 2014c649a..175f6ec68 100644 --- a/include/fiction/io/write_operational_domain.hpp +++ b/include/fiction/io/write_operational_domain.hpp @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -93,14 +94,46 @@ inline void write_operational_domain(const operational_domain& opdom, std::ostre { csv_writer writer{os}; - writer.write_line(detail::sweep_parameter_to_string(opdom.x_dimension), - detail::sweep_parameter_to_string(opdom.y_dimension), "operational status"); + const auto num_dimensions = opdom.dimensions.size(); + + if (num_dimensions == 0 || num_dimensions > 3) + { + throw std::invalid_argument("unsupported number of dimensions in the given operational domain"); + } + + if (num_dimensions == 1) + { + writer.write_line(detail::sweep_parameter_to_string(opdom.dimensions[0]), "operational status"); + } + else if (num_dimensions == 2) + { + writer.write_line(detail::sweep_parameter_to_string(opdom.dimensions[0]), + detail::sweep_parameter_to_string(opdom.dimensions[1]), "operational status"); + } + else // num_dimensions == 3 + { + writer.write_line(detail::sweep_parameter_to_string(opdom.dimensions[0]), + detail::sweep_parameter_to_string(opdom.dimensions[1]), + detail::sweep_parameter_to_string(opdom.dimensions[2]), "operational status"); + } for (const auto& [sim_param, op_val] : opdom.operational_values) { - writer.write_line(sim_param.x, sim_param.y, - op_val == operational_status::OPERATIONAL ? params.operational_tag : - params.non_operational_tag); + const auto tag = + op_val == operational_status::OPERATIONAL ? params.operational_tag : params.non_operational_tag; + + if (num_dimensions == 1) + { + writer.write_line(sim_param.parameters[0], tag); + } + else if (num_dimensions == 2) + { + writer.write_line(sim_param.parameters[0], sim_param.parameters[1], tag); + } + else // num_dimensions == 3 + { + writer.write_line(sim_param.parameters[0], sim_param.parameters[1], sim_param.parameters[2], tag); + } } } /** diff --git a/test/io/write_operational_domain.cpp b/test/io/write_operational_domain.cpp index 9285bf541..4053fdab7 100644 --- a/test/io/write_operational_domain.cpp +++ b/test/io/write_operational_domain.cpp @@ -15,12 +15,15 @@ using namespace fiction; TEST_CASE("Write empty operational domain", "[write-operational-domain]") { - operational_domain opdom{}; - std::ostringstream os{}; SECTION("default sweep dimensions") { + operational_domain opdom{}; + + opdom.dimensions.push_back(operational_domain::sweep_parameter::EPSILON_R); + opdom.dimensions.push_back(operational_domain::sweep_parameter::LAMBDA_TF); + static constexpr const char* expected = "epsilon_r,lambda_tf,operational status\n"; write_operational_domain(opdom, os); @@ -29,8 +32,10 @@ TEST_CASE("Write empty operational domain", "[write-operational-domain]") } SECTION("custom sweep dimensions") { - opdom.x_dimension = operational_domain::sweep_parameter::LAMBDA_TF; - opdom.y_dimension = operational_domain::sweep_parameter::MU_MINUS; + operational_domain opdom{}; + + opdom.dimensions.push_back(operational_domain::sweep_parameter::LAMBDA_TF); + opdom.dimensions.push_back(operational_domain::sweep_parameter::MU_MINUS); static constexpr const char* expected = "lambda_tf,mu_minus,operational status\n"; @@ -43,8 +48,12 @@ TEST_CASE("Write empty operational domain", "[write-operational-domain]") TEST_CASE("Write simple operational domain", "[write-operational-domain]") { operational_domain opdom{}; - opdom.operational_values = {{{0, 0}, operational_status::OPERATIONAL}, - {{0, 1}, operational_status::NON_OPERATIONAL}}; + + opdom.dimensions.push_back(operational_domain::sweep_parameter::EPSILON_R); + opdom.dimensions.push_back(operational_domain::sweep_parameter::LAMBDA_TF); + + opdom.operational_values = {{operational_domain::parameter_point{{0, 0}}, operational_status::OPERATIONAL}, + {operational_domain::parameter_point{{0, 1}}, operational_status::NON_OPERATIONAL}}; std::ostringstream os{}; @@ -84,10 +93,15 @@ TEST_CASE("Write simple operational domain", "[write-operational-domain]") TEST_CASE("Write operational domain with floating-point parameter values", "[write-operational-domain]") { operational_domain opdom{}; - opdom.operational_values = {{{0.1, 0.2}, operational_status::OPERATIONAL}, - {{0.3, 0.4}, operational_status::NON_OPERATIONAL}, - {{1.2, 1.4}, operational_status::OPERATIONAL}, - {{2.4, 5.75}, operational_status::NON_OPERATIONAL}}; + + opdom.dimensions.push_back(operational_domain::sweep_parameter::EPSILON_R); + opdom.dimensions.push_back(operational_domain::sweep_parameter::LAMBDA_TF); + + opdom.operational_values = { + {operational_domain::parameter_point{{0.1, 0.2}}, operational_status::OPERATIONAL}, + {operational_domain::parameter_point{{0.3, 0.4}}, operational_status::NON_OPERATIONAL}, + {operational_domain::parameter_point{{1.2, 1.4}}, operational_status::OPERATIONAL}, + {operational_domain::parameter_point{{2.4, 5.75}}, operational_status::NON_OPERATIONAL}}; std::ostringstream os{}; From 27d06bcb2df974c4c2249e7ebf739f09a1a70aec Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 17 Jul 2024 17:21:06 +0000 Subject: [PATCH 20/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 44562c6ac..f97f4cb45 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5836,19 +5836,33 @@ can occur during the computation, each value is temporarily held in an atomic variable and written to the statistics object only after the computation has finished.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_moore_neighborhood = -R"doc(Returns the Moore neighborhood of the step point at `sp = (x, y)`. The -Moore neighborhood is the set of all points that are adjacent to `(x, -y)` including the diagonals. Thereby, the Moore neighborhood contains -up to 8 points as points outside of the parameter range are not -gathered. The points are returned in clockwise order starting from the -right neighbor. +static const char *__doc_fiction_detail_operational_domain_impl_moore_neighborhood_2d = +R"doc(Returns the 2D Moore neighborhood of the step point at `sp = (x, y)`. +The 2D Moore neighborhood is the set of all points that are adjacent +to `(x, y)` in the plane including the diagonals. Thereby, the 2D +Moore neighborhood contains up to 8 points as points outside of the +parameter range are not gathered. The points are returned in clockwise +order starting from the right neighbor. Parameter ``sp``: - Step point to get the Moore neighborhood of. + Step point to get the 2D Moore neighborhood of. Returns: - The Moore neighborhood of the step point at `sp = (x, y)`.)doc"; + The 2D Moore neighborhood of the step point at `sp = (x, y)`.)doc"; + +static const char *__doc_fiction_detail_operational_domain_impl_moore_neighborhood_3d = +R"doc(Returns the 3D Moore neighborhood of the step point at `sp = (x, y)`. +The 3D Moore neighborhood is the set of all points that are adjacent +to `(x, y)` in the 3D space including the diagonals. Thereby, the 3D +Moore neighborhood contains up to 26 points as points outside of the +parameter range are not gathered. The points are returned in no +particular order. + +Parameter ``sp``: + Step point to get the 3D Moore neighborhood of. + +Returns: + The 3D Moore neighborhood of the step point at `sp = (x, y)`.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_num_dimensions = R"doc(The number of dimensions.)doc"; From 635248954a3a174a569d83ab81add8447d40c897 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 18 Jul 2024 15:47:31 +0200 Subject: [PATCH 21/95] :sparkles: Support n-dimensional operational domains in experiments --- .../operational_domain_siqad.cpp | 25 +++++++++---------- test/algorithms/mockturtle.cpp | 3 +-- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/experiments/operational_domain/operational_domain_siqad.cpp b/experiments/operational_domain/operational_domain_siqad.cpp index e29299391..d53d2e597 100644 --- a/experiments/operational_domain/operational_domain_siqad.cpp +++ b/experiments/operational_domain/operational_domain_siqad.cpp @@ -10,12 +10,11 @@ #include // reader for SiDB layouts #include // writer for operational domains #include -#include #include // pre-defined types suitable for the FCN domain #include // truth tables helper functions -#include // string formatting -#include // truth tables +#include // string formatting +#include #include #include @@ -46,16 +45,16 @@ int main() // NOLINT // operational domain parameters operational_domain_params op_domain_params{}; - op_domain_params.simulation_parameters = sim_params; - op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.x_dimension = operational_domain::sweep_parameter::EPSILON_R; - op_domain_params.x_min = 1.0; - op_domain_params.x_max = 10.0; - op_domain_params.x_step = 0.05; - op_domain_params.y_dimension = operational_domain::sweep_parameter::LAMBDA_TF; - op_domain_params.y_min = 1.0; - op_domain_params.y_max = 10.0; - op_domain_params.y_step = 0.05; + op_domain_params.simulation_parameters = sim_params; + op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; + op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, + {operational_domain::sweep_parameter::LAMBDA_TF}}; + op_domain_params.sweep_dimensions[0].min = 1.0; + op_domain_params.sweep_dimensions[0].max = 10.0; + op_domain_params.sweep_dimensions[0].step = 0.05; + op_domain_params.sweep_dimensions[1].min = 1.0; + op_domain_params.sweep_dimensions[1].max = 10.0; + op_domain_params.sweep_dimensions[1].step = 0.05; // write operational domain parameters static const write_operational_domain_params write_op_domain_params{"1", "0"}; diff --git a/test/algorithms/mockturtle.cpp b/test/algorithms/mockturtle.cpp index 006178988..f1d6dcbfc 100644 --- a/test/algorithms/mockturtle.cpp +++ b/test/algorithms/mockturtle.cpp @@ -4,6 +4,7 @@ #include +#include "fiction/layouts/coordinates.hpp" #include "utils/blueprints/layout_blueprints.hpp" #include "utils/blueprints/network_blueprints.hpp" #include "utils/equivalence_checking_utils.hpp" @@ -26,8 +27,6 @@ #include #include -#include - using namespace fiction; TEST_CASE("Simulation", "[mockturtle]") From f2d7c2445fa50be30cb03c0d39ed7d029ef5a947 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 18 Jul 2024 19:59:46 +0200 Subject: [PATCH 22/95] :sparkles: Added Bestagon experiment script --- .../operational_domain_siqad.cpp | 42 ++++++++++++------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/experiments/operational_domain/operational_domain_siqad.cpp b/experiments/operational_domain/operational_domain_siqad.cpp index d53d2e597..95f5fe40b 100644 --- a/experiments/operational_domain/operational_domain_siqad.cpp +++ b/experiments/operational_domain/operational_domain_siqad.cpp @@ -4,17 +4,16 @@ #include "fiction_experiments.hpp" // experiment class -#include // operational domain computation algorithms -#include -#include -#include // reader for SiDB layouts -#include // writer for operational domains -#include +#include // operational domain computation algorithms +#include // SiDB simulation engines +#include // SiDB simulation parameters +#include // reader for SiDB layouts +#include // writer for operational domains #include // pre-defined types suitable for the FCN domain #include // truth tables helper functions -#include // string formatting -#include +#include // string formatting +#include // stopwatch for measuring time #include #include @@ -32,16 +31,31 @@ int main() // NOLINT experiments::experiment opdomain_exp{ - "Operational Domain", "Name", "#SiDBs", // Benchmark - "#Samples (GS)", "op. (GS)", "sim calls (GS)", "t in s (GS)", // Grid Search - "#Samples (RS)", "op. (RS)", "sim calls (RS)", "t in s (RS)", // Random Sampling - "#Samples (FF)", "op. (FF)", "sim calls (FF)", "t in s (FF)", // Flood Fill - "#Samples (CT)", "op. (CT)", "sim calls (CT)", "t in s (CT)" // Contour Tracing + "Operational Domain SiQAD", + "Name", + "#SiDBs", // Benchmark + "#Samples (GS)", + "op. (GS)", + "sim calls (GS)", + "t in s (GS)", // Grid Search + "#Samples (RS)", + "op. (RS)", + "sim calls (RS)", + "t in s (RS)", // Random Sampling + "#Samples (FF)", + "op. (FF)", + "sim calls (FF)", + "t in s (FF)", // Flood Fill + "#Samples (CT)", + "op. (CT)", + "sim calls (CT)", + "t in s (CT)" // Contour Tracing }; // simulation parameters sidb_simulation_parameters sim_params{}; - sim_params.base = 2; + sim_params.base = 2; + sim_params.mu_minus = -0.28; // operational domain parameters operational_domain_params op_domain_params{}; From 2189358e7c3828c442d4dca3ddba8ec784e53ddd Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Fri, 19 Jul 2024 16:09:54 +0200 Subject: [PATCH 23/95] :sparkles: Enabled Contour Tracing-based operational domain computation to work on operational domains that possess multiple islands --- .../simulation/sidb/operational_domain.hpp | 183 ++++++++++++++---- 1 file changed, 150 insertions(+), 33 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 591fe7a4e..6f42a6bee 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -15,6 +15,7 @@ #include "fiction/utils/hash.hpp" #include "fiction/utils/phmap_utils.hpp" +#include #include #include #include @@ -30,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -429,14 +429,9 @@ class operational_domain_impl mockturtle::stopwatch stop{stats.time_total}; - // first, perform random sampling to find an operational starting point - const auto starting_point = find_operational_step_point_via_random_sampling(samples); + const auto step_point_samples = generate_random_step_points(samples); - // if no operational point was found within the specified number of samples, return - if (!starting_point.has_value()) - { - return op_domain; - } + simulate_operational_status_in_parallel(step_point_samples); const auto next_clockwise_point = [](std::vector& neighborhood, const step_point& backtrack) noexcept -> step_point @@ -452,43 +447,61 @@ class operational_domain_impl return neighborhood.front(); }; - // find an operational point on the contour starting from the randomly determined starting point - const auto contour_starting_point = find_operational_contour_step_point(*starting_point); + // for each sampled point + for (const auto& starting_point : step_point_samples) + { + // if the current starting point is non-operational, skip to the next one + if (op_domain.operational_values[to_parameter_point(starting_point)] == operational_status::NON_OPERATIONAL) + { + continue; + } - auto current_contour_point = contour_starting_point; + // if the current step point has been inferred as operational, skip to the next one + if (is_step_point_inferred_operational(starting_point)) + { + continue; + } - const auto x = current_contour_point.step_values[0]; - const auto y = current_contour_point.step_values[1]; + // find an operational point on the contour starting from the randomly determined starting point + const auto contour_starting_point = find_operational_contour_step_point(starting_point); - auto backtrack_point = x == 0 ? current_contour_point : step_point{{x - 1, y}}; + auto current_contour_point = contour_starting_point; - auto current_neighborhood = moore_neighborhood_2d(current_contour_point); + const auto x = current_contour_point.step_values[0]; + const auto y = current_contour_point.step_values[1]; - auto next_point = contour_starting_point; + auto backtrack_point = x == 0 ? current_contour_point : step_point{{x - 1, y}}; - if (!current_neighborhood.empty()) - { - next_point = current_contour_point == backtrack_point ? - current_neighborhood.front() : - next_clockwise_point(current_neighborhood, backtrack_point); - } + auto current_neighborhood = moore_neighborhood_2d(current_contour_point); - while (next_point != contour_starting_point) - { - const auto operational_status = is_step_point_operational(next_point); + auto next_point = contour_starting_point; - if (operational_status == operational_status::OPERATIONAL) + if (!current_neighborhood.empty()) { - backtrack_point = current_contour_point; - current_contour_point = next_point; + next_point = current_contour_point == backtrack_point ? + current_neighborhood.front() : + next_clockwise_point(current_neighborhood, backtrack_point); } - else + + while (next_point != contour_starting_point) { - backtrack_point = next_point; + const auto operational_status = is_step_point_operational(next_point); + + if (operational_status == operational_status::OPERATIONAL) + { + backtrack_point = current_contour_point; + current_contour_point = next_point; + } + else + { + backtrack_point = next_point; + } + + current_neighborhood = moore_neighborhood_2d(current_contour_point); + next_point = next_clockwise_point(current_neighborhood, backtrack_point); } - current_neighborhood = moore_neighborhood_2d(current_contour_point); - next_point = next_clockwise_point(current_neighborhood, backtrack_point); + infer_operational_status_in_enclosing_contour(starting_point); } log_stats(); @@ -533,6 +546,14 @@ class operational_domain_impl * The operational domain of the layout. */ operational_domain op_domain{}; + /** + * Forward-declare step_point. + */ + struct step_point; + /** + * All the points inferred (assumed) to be operational but not actually simulated. + */ + phmap::btree_set inferred_op_domain; /** * Number of simulator invocations. */ @@ -761,6 +782,21 @@ class operational_domain_impl // if we made it here, the layout is operational return operational(); } + /** + * Checks whether the given step point is part of the inferred operational domain. If it is, the point is marked as + * enclosed in the operational domain. No simulation is performed on `sp`. If `sp` is not contained in the inferred + * operational domain, it does not mean that `sp` is definitely non-operational. It could still appear in the + * regular operational domain with either status. + * + * This function is used by the contour tracing algorithm. + * + * @param sp Step point to check for inferred operational status. + * @return `true` iff `sp` is contained in `inferred_op_domain`. + */ + [[nodiscard]] inline bool is_step_point_inferred_operational(const step_point& sp) noexcept + { + return inferred_op_domain.count(sp) > 0; + } /** * Generates unique random `step_points` in the stored parameter range. The number of generated points is at most * equal to `samples`. @@ -782,7 +818,7 @@ class operational_domain_impl } // container for the random samples - std::set step_point_samples{}; + phmap::btree_set step_point_samples{}; for (std::size_t i = 0; i < samples; ++i) { @@ -1050,6 +1086,87 @@ class operational_domain_impl return neighbors; } + /** + * Given a starting point, this function marks all points that are enclosed by the operational domain contour as + * 'inferred operational'. This assumes that the operational domain does not have holes. To the best of the author's + * knowledge, at the time of writing this code, there exists no proof that operational domains are always + * continuous, i.e., hole-free. Marking points as 'inferred operational' can be useful to avoid recomputation in, + * e.g., contour tracing if an operational domain with multiple islands is investigated. + * + * The function starts at the given starting point and performs flood fill to mark all points that are reachable + * from the starting point until it encounters the non-operational edges. + * + * Note that no physical simulation is conducted by this function! + * + * @param starting_point Step point at which to start the inference. If `starting_point` is non-operational, this + * function might invoke undefined behavior. + */ + void infer_operational_status_in_enclosing_contour(const step_point& starting_point) noexcept + { + assert(num_dimensions == 2 && "This function is only supported for two dimensions"); + assert(is_step_point_operational(starting_point) == operational_status::OPERATIONAL && + "starting_point must be within the operational domain"); + + // a queue of (x, y) dimension step points to be marked as inferred operational + std::queue queue{}; + + // a utility function that adds the adjacent points to the queue for further evaluation + const auto queue_next_points = [this, &queue](const step_point& sp) noexcept + { + for (const auto& m : moore_neighborhood_2d(sp)) + { + // if the point has already been inferred as operational, continue with the next + if (is_step_point_inferred_operational(m)) + { + continue; + } + + // if the point has already been sampled + if (const auto operational_status = has_already_been_sampled(m); operational_status.has_value()) + { + // and found to be non-operational, continue with the next + if (operational_status.value() == operational_status::NON_OPERATIONAL) + { + continue; + } + } + + // otherwise, it is either found operational or can be inferred as such + queue.push(m); + inferred_op_domain.insert(m); + } + }; + + // if the starting point has not already been inferred as operational + if (is_step_point_inferred_operational(starting_point)) + { + // mark the starting point as inferred operational + inferred_op_domain.insert(starting_point); + + // add the starting point's neighbors to the queue + queue_next_points(starting_point); + } + + // for each point in the queue + while (!queue.empty()) + { + // fetch the step point and remove it from the queue + const auto sp = queue.front(); + queue.pop(); + + // if the point is known to be non-operational continue with the next + if (const auto operational_status = has_already_been_sampled(sp); operational_status.has_value()) + { + if (operational_status.value() == operational_status::NON_OPERATIONAL) + { + continue; + } + } + + // otherwise (operational or unknown), queue its neighbors + queue_next_points(sp); + } + } /** * Helper function that writes the the statistics of the operational domain computation to the statistics object. * Due to data races that can occur during the computation, each value is temporarily held in an atomic variable and From 7a39e22b058e3d2c1cf91236187aadaedea45a30 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Fri, 19 Jul 2024 16:11:38 +0200 Subject: [PATCH 24/95] :alembic: Added an operational domain computation experiment script for the Bestagon gate library --- .../operational_domain_bestagon.cpp | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 experiments/operational_domain/operational_domain_bestagon.cpp diff --git a/experiments/operational_domain/operational_domain_bestagon.cpp b/experiments/operational_domain/operational_domain_bestagon.cpp new file mode 100644 index 000000000..4d9d2308c --- /dev/null +++ b/experiments/operational_domain/operational_domain_bestagon.cpp @@ -0,0 +1,213 @@ +// +// Created by marcel on 08.08.23. +// + +#include "fiction_experiments.hpp" // experiment class + +#include // operational domain computation algorithms +#include // SiDB simulation engines +#include // SiDB simulation parameters +#include // reader for SiDB layouts +#include // writer for operational domains +#include // pre-defined types suitable for the FCN domain +#include // truth tables helper functions + +#include // output formatting +#include // stopwatch for time measurement + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace fiction; + +int main() // NOLINT +{ + experiments::experiment + opdomain_exp{ + "Operational Domain Bestagon", + "Name", + "#SiDBs", // Benchmark + "#Samples (GS)", + "op. (GS)", + "sim calls (GS)", + "t in s (GS)", // Grid Search + "#Samples (RS)", + "op. (RS)", + "sim calls (RS)", + "t in s (RS)", // Random Sampling + "#Samples (FF)", + "op. (FF)", + "sim calls (FF)", + "t in s (FF)", // Flood Fill + "#Samples (CT)", + "op. (CT)", + "sim calls (CT)", + "t in s (CT)" // Contour Tracing + }; + + // simulation parameters + sidb_simulation_parameters sim_params{}; + sim_params.base = 2; + sim_params.mu_minus = -0.32; + + // operational domain parameters + operational_domain_params op_domain_params{}; + op_domain_params.simulation_parameters = sim_params; + op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; + op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, + {operational_domain::sweep_parameter::LAMBDA_TF}}; + op_domain_params.sweep_dimensions[0].min = 1.0; + op_domain_params.sweep_dimensions[0].max = 10.0; + op_domain_params.sweep_dimensions[0].step = 0.05; + op_domain_params.sweep_dimensions[1].min = 1.0; + op_domain_params.sweep_dimensions[1].max = 10.0; + op_domain_params.sweep_dimensions[1].step = 0.05; + + // write operational domain parameters + const write_operational_domain_params write_op_domain_params{"1", "0"}; + + static const std::string folder = fmt::format("{}bestagon_gates_type_tags/", EXPERIMENTS_PATH); + + static const std::array>, 10> gates = { + std::make_pair("and", std::vector{create_and_tt()}), + std::make_pair("nand", std::vector{create_nand_tt()}), + std::make_pair("nor", std::vector{create_nor_tt()}), + std::make_pair("xnor", std::vector{create_xnor_tt()}), + std::make_pair("xor", std::vector{create_xor_tt()}), + std::make_pair("or", std::vector{create_or_tt()}), + std::make_pair("wire", std::vector{create_id_tt()}), + std::make_pair("wire_diag", std::vector{create_id_tt()}), + std::make_pair("inv", std::vector{create_not_tt()}), + std::make_pair("inv_diag", std::vector{create_not_tt()})}; + + // total number of samples + static std::size_t total_samples_gs = 0; + static std::size_t total_samples_rs = 0; + static std::size_t total_samples_ff = 0; + static std::size_t total_samples_ct = 0; + + // total number of simulator calls + static std::size_t total_sim_calls_gs = 0; + static std::size_t total_sim_calls_rs = 0; + static std::size_t total_sim_calls_ff = 0; + static std::size_t total_sim_calls_ct = 0; + + for (const auto& [gate, truth_table] : gates) + { + for (const auto& file : std::filesystem::directory_iterator(fmt::format("{}{}", folder, gate))) + { + const auto& benchmark = file.path(); + + std::cout << benchmark << std::endl; + + auto lyt = read_sqd_layout(benchmark.string(), gate); + + // operational domain stats + operational_domain_stats op_domain_stats_gs{}; + operational_domain_stats op_domain_stats_rs{}; + operational_domain_stats op_domain_stats_ff{}; + operational_domain_stats op_domain_stats_ct{}; + + // compute the operational domains + const auto op_domain_gs = + operational_domain_grid_search(lyt, truth_table, op_domain_params, &op_domain_stats_gs); + const auto op_domain_rs = + operational_domain_random_sampling(lyt, truth_table, 2500, op_domain_params, &op_domain_stats_rs); + const auto op_domain_ff = + operational_domain_flood_fill(lyt, truth_table, 250, op_domain_params, &op_domain_stats_ff); + const auto op_domain_ct = + operational_domain_contour_tracing(lyt, truth_table, 100, op_domain_params, &op_domain_stats_ct); + + // write the operational domains to a CSV file + write_operational_domain(op_domain_gs, + fmt::format("{}operational_domain_grid_search_bestagon_{}.csv", folder, gate), + write_op_domain_params); + write_operational_domain(op_domain_rs, + fmt::format("{}operational_domain_random_sampling_bestagon_{}.csv", folder, gate), + write_op_domain_params); + write_operational_domain(op_domain_ff, + fmt::format("{}operational_domain_flood_fill_bestagon_{}.csv", folder, gate), + write_op_domain_params); + write_operational_domain(op_domain_ct, + fmt::format("{}operational_domain_contour_tracing_bestagon_{}.csv", folder, gate), + write_op_domain_params); + + // update the total number of samples + total_samples_gs += op_domain_stats_gs.num_evaluated_parameter_combinations; + total_samples_rs += op_domain_stats_rs.num_evaluated_parameter_combinations; + total_samples_ff += op_domain_stats_ff.num_evaluated_parameter_combinations; + total_samples_ct += op_domain_stats_ct.num_evaluated_parameter_combinations; + + // update the total number of simulator calls + total_sim_calls_gs += op_domain_stats_gs.num_simulator_invocations; + total_sim_calls_rs += op_domain_stats_rs.num_simulator_invocations; + total_sim_calls_ff += op_domain_stats_ff.num_simulator_invocations; + total_sim_calls_ct += op_domain_stats_ct.num_simulator_invocations; + + // compute the operational percentages + const auto operational_percentage_gs = + static_cast(op_domain_stats_gs.num_operational_parameter_combinations) / + static_cast(op_domain_stats_gs.num_evaluated_parameter_combinations); + const auto operational_percentage_rs = + static_cast(op_domain_stats_rs.num_operational_parameter_combinations) / + static_cast(op_domain_stats_rs.num_evaluated_parameter_combinations); + const auto operational_percentage_ff = + static_cast(op_domain_stats_ff.num_operational_parameter_combinations) / + static_cast(op_domain_stats_ff.num_evaluated_parameter_combinations); + const auto operational_percentage_ct = + static_cast(op_domain_stats_ct.num_operational_parameter_combinations) / + static_cast(op_domain_stats_ct.num_evaluated_parameter_combinations); + + opdomain_exp( + // Benchmark + benchmark.string(), lyt.num_cells(), + + // Grid Search + op_domain_stats_gs.num_evaluated_parameter_combinations, operational_percentage_gs, + op_domain_stats_gs.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_gs.time_total), + + // Random Sampling + op_domain_stats_rs.num_evaluated_parameter_combinations, operational_percentage_rs, + op_domain_stats_rs.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_rs.time_total), + + // Flood Fill + op_domain_stats_ff.num_evaluated_parameter_combinations, operational_percentage_ff, + op_domain_stats_ff.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_ff.time_total), + + // Contour Tracing + op_domain_stats_ct.num_evaluated_parameter_combinations, operational_percentage_ct, + op_domain_stats_ct.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_ct.time_total)); + } + + opdomain_exp.save(); + opdomain_exp.table(); + } + + // log the total number of samples and simulator calls + opdomain_exp( + // Benchmark + "Total", 0, + + // Grid Search + total_samples_gs, 0.0, total_sim_calls_gs, 0.0, + + // Random Sampling + total_samples_rs, 0.0, total_sim_calls_rs, 0.0, + + // Flood Fill + total_samples_ff, 0.0, total_sim_calls_ff, 0.0, + + // Contour Tracing + total_samples_ct, 0.0, total_sim_calls_ct, 0.0); + + opdomain_exp.save(); + + return EXIT_SUCCESS; +} From 9cef201b66ccaa496ec46c77573c2cfecac5e243 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 23 Jul 2024 12:25:09 +0200 Subject: [PATCH 25/95] :alembic: Added 3D versions of the operational domain computation experiment scripts and added total runtime tracking --- .../operational_domain_3d_bestagon.cpp | 208 ++++++++++++++++++ .../operational_domain_3d_siqad.cpp | 202 +++++++++++++++++ .../operational_domain_bestagon.cpp | 27 ++- .../operational_domain_siqad.cpp | 26 ++- .../simulation/sidb/operational_domain.hpp | 2 +- 5 files changed, 454 insertions(+), 11 deletions(-) create mode 100644 experiments/operational_domain/operational_domain_3d_bestagon.cpp create mode 100644 experiments/operational_domain/operational_domain_3d_siqad.cpp diff --git a/experiments/operational_domain/operational_domain_3d_bestagon.cpp b/experiments/operational_domain/operational_domain_3d_bestagon.cpp new file mode 100644 index 000000000..1b1c942a5 --- /dev/null +++ b/experiments/operational_domain/operational_domain_3d_bestagon.cpp @@ -0,0 +1,208 @@ +// +// Created by marcel on 08.08.23. +// + +#include "fiction_experiments.hpp" // experiment class + +#include // operational domain computation algorithms +#include // SiDB simulation engines +#include // SiDB simulation parameters +#include // reader for SiDB layouts +#include // writer for operational domains +#include // pre-defined types suitable for the FCN domain +#include // truth tables helper functions + +#include // output formatting +#include // stopwatch for time measurement + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace fiction; + +int main() // NOLINT +{ + experiments::experiment + opdomain_exp{ + "Operational Domain Bestagon", + "Name", + "#SiDBs", // Benchmark + "#Samples (GS)", + "op. (GS)", + "sim calls (GS)", + "t in s (GS)", // Grid Search + "#Samples (RS)", + "op. (RS)", + "sim calls (RS)", + "t in s (RS)", // Random Sampling + "#Samples (FF)", + "op. (FF)", + "sim calls (FF)", + "t in s (FF)" // Flood Fill + }; + + // simulation parameters + sidb_simulation_parameters sim_params{}; + sim_params.base = 2; + sim_params.mu_minus = -0.32; + + // operational domain parameters + operational_domain_params op_domain_params{}; + op_domain_params.simulation_parameters = sim_params; + op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; + op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, + {operational_domain::sweep_parameter::LAMBDA_TF}, + {operational_domain::sweep_parameter::MU_MINUS}}; + op_domain_params.sweep_dimensions[0].min = 1.0; + op_domain_params.sweep_dimensions[0].max = 10.0; + op_domain_params.sweep_dimensions[0].step = 0.05; + op_domain_params.sweep_dimensions[1].min = 1.0; + op_domain_params.sweep_dimensions[1].max = 10.0; + op_domain_params.sweep_dimensions[1].step = 0.05; + op_domain_params.sweep_dimensions[2].min = -0.50; + op_domain_params.sweep_dimensions[2].max = -0.10; + op_domain_params.sweep_dimensions[2].step = 0.01; + + // write operational domain parameters + const write_operational_domain_params write_op_domain_params{"1", "0"}; + + static const std::string folder = fmt::format("{}bestagon_gates_type_tags/", EXPERIMENTS_PATH); + + static const std::array>, 10> gates = { + std::make_pair("and", std::vector{create_and_tt()}), + std::make_pair("nand", std::vector{create_nand_tt()}), + std::make_pair("nor", std::vector{create_nor_tt()}), + std::make_pair("xnor", std::vector{create_xnor_tt()}), + std::make_pair("xor", std::vector{create_xor_tt()}), + std::make_pair("or", std::vector{create_or_tt()}), + std::make_pair("wire", std::vector{create_id_tt()}), + std::make_pair("wire_diag", std::vector{create_id_tt()}), + std::make_pair("inv", std::vector{create_not_tt()}), + std::make_pair("inv_diag", std::vector{create_not_tt()})}; + + // total number of samples + static std::size_t total_samples_gs = 0; + static std::size_t total_samples_rs = 0; + static std::size_t total_samples_ff = 0; + + // total number of simulator calls + static std::size_t total_sim_calls_gs = 0; + static std::size_t total_sim_calls_rs = 0; + static std::size_t total_sim_calls_ff = 0; + + // total runtime + static double total_runtime_gs = 0.0; + static double total_runtime_rs = 0.0; + static double total_runtime_ff = 0.0; + + for (const auto& [gate, truth_table] : gates) + { + for (const auto& file : std::filesystem::directory_iterator(fmt::format("{}{}", folder, gate))) + { + const auto& benchmark = file.path(); + + std::cout << benchmark << std::endl; + + auto lyt = read_sqd_layout(benchmark.string(), gate); + + // operational domain stats + operational_domain_stats op_domain_stats_gs{}; + operational_domain_stats op_domain_stats_rs{}; + operational_domain_stats op_domain_stats_ff{}; + + // compute the operational domains + const auto op_domain_gs = + operational_domain_grid_search(lyt, truth_table, op_domain_params, &op_domain_stats_gs); + const auto op_domain_rs = + operational_domain_random_sampling(lyt, truth_table, 2500, op_domain_params, &op_domain_stats_rs); + const auto op_domain_ff = + operational_domain_flood_fill(lyt, truth_table, 250, op_domain_params, &op_domain_stats_ff); + + // write the operational domains to a CSV file + write_operational_domain(op_domain_gs, + fmt::format("{}operational_domain_grid_search_3d_bestagon_{}.csv", folder, gate), + write_op_domain_params); + write_operational_domain( + op_domain_rs, fmt::format("{}operational_domain_random_sampling_3d_bestagon_{}.csv", folder, gate), + write_op_domain_params); + write_operational_domain(op_domain_ff, + fmt::format("{}operational_domain_flood_fill_3d_bestagon_{}.csv", folder, gate), + write_op_domain_params); + + // update the total number of samples + total_samples_gs += op_domain_stats_gs.num_evaluated_parameter_combinations; + total_samples_rs += op_domain_stats_rs.num_evaluated_parameter_combinations; + total_samples_ff += op_domain_stats_ff.num_evaluated_parameter_combinations; + + // update the total number of simulator calls + total_sim_calls_gs += op_domain_stats_gs.num_simulator_invocations; + total_sim_calls_rs += op_domain_stats_rs.num_simulator_invocations; + total_sim_calls_ff += op_domain_stats_ff.num_simulator_invocations; + + // update the total runtime + total_runtime_gs += mockturtle::to_seconds(op_domain_stats_gs.time_total); + total_runtime_rs += mockturtle::to_seconds(op_domain_stats_rs.time_total); + total_runtime_ff += mockturtle::to_seconds(op_domain_stats_ff.time_total); + + // compute the operational percentages + const auto operational_percentage_gs = + static_cast(op_domain_stats_gs.num_operational_parameter_combinations) / + static_cast(op_domain_stats_gs.num_evaluated_parameter_combinations); + const auto operational_percentage_rs = + static_cast(op_domain_stats_rs.num_operational_parameter_combinations) / + static_cast(op_domain_stats_rs.num_evaluated_parameter_combinations); + const auto operational_percentage_ff = + static_cast(op_domain_stats_ff.num_operational_parameter_combinations) / + static_cast(op_domain_stats_ff.num_evaluated_parameter_combinations); + + opdomain_exp( + // Benchmark + benchmark.string(), lyt.num_cells(), + + // Grid Search + op_domain_stats_gs.num_evaluated_parameter_combinations, operational_percentage_gs, + op_domain_stats_gs.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_gs.time_total), + + // Random Sampling + op_domain_stats_rs.num_evaluated_parameter_combinations, operational_percentage_rs, + op_domain_stats_rs.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_rs.time_total), + + // Flood Fill + op_domain_stats_ff.num_evaluated_parameter_combinations, operational_percentage_ff, + op_domain_stats_ff.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_ff.time_total) + + ); + } + + opdomain_exp.save(); + opdomain_exp.table(); + } + + // log the total number of samples and simulator calls + opdomain_exp( + // Benchmark + "Total", 0, + + // Grid Search + total_samples_gs, 0.0, total_sim_calls_gs, total_runtime_gs, + + // Random Sampling + total_samples_rs, 0.0, total_sim_calls_rs, total_runtime_rs, + + // Flood Fill + total_samples_ff, 0.0, total_sim_calls_ff, total_runtime_ff + + ); + + opdomain_exp.save(); + opdomain_exp.table(); + + return EXIT_SUCCESS; +} diff --git a/experiments/operational_domain/operational_domain_3d_siqad.cpp b/experiments/operational_domain/operational_domain_3d_siqad.cpp new file mode 100644 index 000000000..19e2706c8 --- /dev/null +++ b/experiments/operational_domain/operational_domain_3d_siqad.cpp @@ -0,0 +1,202 @@ +// +// Created by marcel on 22.07.24. +// + +#include "fiction_experiments.hpp" // experiment class + +#include // operational domain computation algorithms +#include // SiDB simulation engines +#include // SiDB simulation parameters +#include // reader for SiDB layouts +#include // writer for operational domains +#include // pre-defined types suitable for the FCN domain +#include // truth tables helper functions + +#include // string formatting +#include // stopwatch for measuring time + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace fiction; + +int main() // NOLINT +{ + experiments::experiment + opdomain_exp{ + "Operational Domain SiQAD", + "Name", + "#SiDBs", // Benchmark + "#Samples (GS)", + "op. (GS)", + "sim calls (GS)", + "t in s (GS)", // Grid Search + "#Samples (RS)", + "op. (RS)", + "sim calls (RS)", + "t in s (RS)", // Random Sampling + "#Samples (FF)", + "op. (FF)", + "sim calls (FF)", + "t in s (FF)" // Flood Fill + }; + + // simulation parameters + sidb_simulation_parameters sim_params{}; + sim_params.base = 2; + sim_params.mu_minus = -0.28; + + // operational domain parameters + operational_domain_params op_domain_params{}; + op_domain_params.simulation_parameters = sim_params; + op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; + op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, + {operational_domain::sweep_parameter::LAMBDA_TF}, + {operational_domain::sweep_parameter::MU_MINUS}}; + op_domain_params.sweep_dimensions[0].min = 1.0; + op_domain_params.sweep_dimensions[0].max = 10.0; + op_domain_params.sweep_dimensions[0].step = 0.05; + op_domain_params.sweep_dimensions[1].min = 1.0; + op_domain_params.sweep_dimensions[1].max = 10.0; + op_domain_params.sweep_dimensions[1].step = 0.05; + op_domain_params.sweep_dimensions[2].min = -0.50; + op_domain_params.sweep_dimensions[2].max = -0.10; + op_domain_params.sweep_dimensions[2].step = 0.01; + + // write operational domain parameters + static const write_operational_domain_params write_op_domain_params{"1", "0"}; + + static const std::string folder = fmt::format("{}siqad_gates_type_tags/", EXPERIMENTS_PATH); + + static const std::array>, 5> gates = { + std::make_pair("and", std::vector{create_and_tt()}), + std::make_pair("nand", std::vector{create_nand_tt()}), + std::make_pair("xnor", std::vector{create_xnor_tt()}), + std::make_pair("xor", std::vector{create_xor_tt()}), std::make_pair("or", std::vector{create_or_tt()})}; + + // total number of samples + static std::size_t total_samples_gs = 0; + static std::size_t total_samples_rs = 0; + static std::size_t total_samples_ff = 0; + + // total number of simulator calls + static std::size_t total_sim_calls_gs = 0; + static std::size_t total_sim_calls_rs = 0; + static std::size_t total_sim_calls_ff = 0; + + // total runtime + static double total_runtime_gs = 0.0; + static double total_runtime_rs = 0.0; + static double total_runtime_ff = 0.0; + + for (const auto& [gate, truth_table] : gates) + { + for (const auto& file : std::filesystem::directory_iterator(fmt::format("{}{}", folder, gate))) + { + const auto& benchmark = file.path(); + + std::cout << benchmark << std::endl; + + const auto lyt = read_sqd_layout(benchmark.string(), gate); + + // operational domain stats + operational_domain_stats op_domain_stats_gs{}; + operational_domain_stats op_domain_stats_rs{}; + operational_domain_stats op_domain_stats_ff{}; + + // compute the operational domains + const auto op_domain_gs = + operational_domain_grid_search(lyt, truth_table, op_domain_params, &op_domain_stats_gs); + const auto op_domain_rs = + operational_domain_random_sampling(lyt, truth_table, 2500, op_domain_params, &op_domain_stats_rs); + const auto op_domain_ff = + operational_domain_flood_fill(lyt, truth_table, 250, op_domain_params, &op_domain_stats_ff); + + // write the operational domains to a CSV file + write_operational_domain(op_domain_gs, + fmt::format("{}operational_domain_grid_search_3d_siqad_{}.csv", folder, gate), + write_op_domain_params); + write_operational_domain(op_domain_rs, + fmt::format("{}operational_domain_random_sampling_3d_siqad_{}.csv", folder, gate), + write_op_domain_params); + write_operational_domain(op_domain_ff, + fmt::format("{}operational_domain_flood_fill_3d_siqad_{}.csv", folder, gate), + write_op_domain_params); + + // update the total number of samples + total_samples_gs += op_domain_stats_gs.num_evaluated_parameter_combinations; + total_samples_rs += op_domain_stats_rs.num_evaluated_parameter_combinations; + total_samples_ff += op_domain_stats_ff.num_evaluated_parameter_combinations; + + // update the total number of simulator calls + total_sim_calls_gs += op_domain_stats_gs.num_simulator_invocations; + total_sim_calls_rs += op_domain_stats_rs.num_simulator_invocations; + total_sim_calls_ff += op_domain_stats_ff.num_simulator_invocations; + + // update the total runtime + total_runtime_gs += mockturtle::to_seconds(op_domain_stats_gs.time_total); + total_runtime_rs += mockturtle::to_seconds(op_domain_stats_rs.time_total); + total_runtime_ff += mockturtle::to_seconds(op_domain_stats_ff.time_total); + + // compute the operational percentages + const auto operational_percentage_gs = + static_cast(op_domain_stats_gs.num_operational_parameter_combinations) / + static_cast(op_domain_stats_gs.num_evaluated_parameter_combinations); + const auto operational_percentage_rs = + static_cast(op_domain_stats_rs.num_operational_parameter_combinations) / + static_cast(op_domain_stats_rs.num_evaluated_parameter_combinations); + const auto operational_percentage_ff = + static_cast(op_domain_stats_ff.num_operational_parameter_combinations) / + static_cast(op_domain_stats_ff.num_evaluated_parameter_combinations); + + opdomain_exp( + // Benchmark + benchmark.string(), lyt.num_cells(), + + // Grid Search + op_domain_stats_gs.num_evaluated_parameter_combinations, operational_percentage_gs, + op_domain_stats_gs.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_gs.time_total), + + // Random Sampling + op_domain_stats_rs.num_evaluated_parameter_combinations, operational_percentage_rs, + op_domain_stats_rs.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_rs.time_total), + + // Flood Fill + op_domain_stats_ff.num_evaluated_parameter_combinations, operational_percentage_ff, + op_domain_stats_ff.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_ff.time_total) + + ); + } + + opdomain_exp.save(); + opdomain_exp.table(); + } + + // log the total number of samples and simulator calls + opdomain_exp( + // Benchmark + "Total", 0, + + // Grid Search + total_samples_gs, 0.0, total_sim_calls_gs, total_runtime_gs, + + // Random Sampling + total_samples_rs, 0.0, total_sim_calls_rs, total_runtime_rs, + + // Flood Fill + total_samples_ff, 0.0, total_sim_calls_ff, total_runtime_ff + + ); + + opdomain_exp.save(); + opdomain_exp.table(); + + return EXIT_SUCCESS; +} diff --git a/experiments/operational_domain/operational_domain_bestagon.cpp b/experiments/operational_domain/operational_domain_bestagon.cpp index 4d9d2308c..27ad014b5 100644 --- a/experiments/operational_domain/operational_domain_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_bestagon.cpp @@ -99,6 +99,12 @@ int main() // NOLINT static std::size_t total_sim_calls_ff = 0; static std::size_t total_sim_calls_ct = 0; + // total runtime + static double total_runtime_gs = 0.0; + static double total_runtime_rs = 0.0; + static double total_runtime_ff = 0.0; + static double total_runtime_ct = 0.0; + for (const auto& [gate, truth_table] : gates) { for (const auto& file : std::filesystem::directory_iterator(fmt::format("{}{}", folder, gate))) @@ -151,6 +157,12 @@ int main() // NOLINT total_sim_calls_ff += op_domain_stats_ff.num_simulator_invocations; total_sim_calls_ct += op_domain_stats_ct.num_simulator_invocations; + // update the total runtime + total_runtime_gs += mockturtle::to_seconds(op_domain_stats_gs.time_total); + total_runtime_rs += mockturtle::to_seconds(op_domain_stats_rs.time_total); + total_runtime_ff += mockturtle::to_seconds(op_domain_stats_ff.time_total); + total_runtime_ct += mockturtle::to_seconds(op_domain_stats_ct.time_total); + // compute the operational percentages const auto operational_percentage_gs = static_cast(op_domain_stats_gs.num_operational_parameter_combinations) / @@ -183,7 +195,9 @@ int main() // NOLINT // Contour Tracing op_domain_stats_ct.num_evaluated_parameter_combinations, operational_percentage_ct, - op_domain_stats_ct.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_ct.time_total)); + op_domain_stats_ct.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_ct.time_total) + + ); } opdomain_exp.save(); @@ -196,18 +210,21 @@ int main() // NOLINT "Total", 0, // Grid Search - total_samples_gs, 0.0, total_sim_calls_gs, 0.0, + total_samples_gs, 0.0, total_sim_calls_gs, total_runtime_gs, // Random Sampling - total_samples_rs, 0.0, total_sim_calls_rs, 0.0, + total_samples_rs, 0.0, total_sim_calls_rs, total_runtime_rs, // Flood Fill - total_samples_ff, 0.0, total_sim_calls_ff, 0.0, + total_samples_ff, 0.0, total_sim_calls_ff, total_runtime_ff, // Contour Tracing - total_samples_ct, 0.0, total_sim_calls_ct, 0.0); + total_samples_ct, 0.0, total_sim_calls_ct, total_runtime_ct + + ); opdomain_exp.save(); + opdomain_exp.table(); return EXIT_SUCCESS; } diff --git a/experiments/operational_domain/operational_domain_siqad.cpp b/experiments/operational_domain/operational_domain_siqad.cpp index 95f5fe40b..40f765226 100644 --- a/experiments/operational_domain/operational_domain_siqad.cpp +++ b/experiments/operational_domain/operational_domain_siqad.cpp @@ -93,6 +93,12 @@ int main() // NOLINT static std::size_t total_sim_calls_ff = 0; static std::size_t total_sim_calls_ct = 0; + // total runtime + static double total_runtime_gs = 0.0; + static double total_runtime_rs = 0.0; + static double total_runtime_ff = 0.0; + static double total_runtime_ct = 0.0; + for (const auto& [gate, truth_table] : gates) { for (const auto& file : std::filesystem::directory_iterator(fmt::format("{}{}", folder, gate))) @@ -145,6 +151,12 @@ int main() // NOLINT total_sim_calls_ff += op_domain_stats_ff.num_simulator_invocations; total_sim_calls_ct += op_domain_stats_ct.num_simulator_invocations; + // update the total runtime + total_runtime_gs += mockturtle::to_seconds(op_domain_stats_gs.time_total); + total_runtime_rs += mockturtle::to_seconds(op_domain_stats_rs.time_total); + total_runtime_ff += mockturtle::to_seconds(op_domain_stats_ff.time_total); + total_runtime_ct += mockturtle::to_seconds(op_domain_stats_ct.time_total); + // compute the operational percentages const auto operational_percentage_gs = static_cast(op_domain_stats_gs.num_operational_parameter_combinations) / @@ -177,7 +189,9 @@ int main() // NOLINT // Contour Tracing op_domain_stats_ct.num_evaluated_parameter_combinations, operational_percentage_ct, - op_domain_stats_ct.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_ct.time_total)); + op_domain_stats_ct.num_simulator_invocations, mockturtle::to_seconds(op_domain_stats_ct.time_total) + + ); } opdomain_exp.save(); @@ -190,16 +204,18 @@ int main() // NOLINT "Total", 0, // Grid Search - total_samples_gs, 0.0, total_sim_calls_gs, 0.0, + total_samples_gs, 0.0, total_sim_calls_gs, total_runtime_gs, // Random Sampling - total_samples_rs, 0.0, total_sim_calls_rs, 0.0, + total_samples_rs, 0.0, total_sim_calls_rs, total_runtime_rs, // Flood Fill - total_samples_ff, 0.0, total_sim_calls_ff, 0.0, + total_samples_ff, 0.0, total_sim_calls_ff, total_runtime_ff, // Contour Tracing - total_samples_ct, 0.0, total_sim_calls_ct, 0.0); + total_samples_ct, 0.0, total_sim_calls_ct, total_runtime_ct + + ); opdomain_exp.save(); opdomain_exp.table(); diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 6f42a6bee..448366e21 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -256,7 +256,7 @@ class operational_domain_impl std::iota(indices[d].begin(), indices[d].end(), 0ul); // if the value of the parameter is greater than params.max after num_x_steps() steps, this value is - // ignored in the operational domain calculation. + // ignored in the operational domain calculation if ((params.sweep_dimensions[d].min + static_cast(indices[d].size() - 1) * params.sweep_dimensions[d].step) - params.sweep_dimensions[d].max > From 4fa155b43e46cfe6eb4151585934ba1a5fbaffc4 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 23 Jul 2024 10:26:17 +0000 Subject: [PATCH 26/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 49 ++++++++++++++++--- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index fa9e014af..8e37da3bb 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5807,6 +5807,46 @@ Parameter ``sp``: static const char *__doc_fiction_detail_operational_domain_impl_indices = R"doc(Dimension steps.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_infer_operational_status_in_enclosing_contour = +R"doc(Given a starting point, this function marks all points that are +enclosed by the operational domain contour as 'inferred operational'. +This assumes that the operational domain does not have holes. To the +best of the author's knowledge, at the time of writing this code, +there exists no proof that operational domains are always continuous, +i.e., hole-free. Marking points as 'inferred operational' can be +useful to avoid recomputation in, e.g., contour tracing if an +operational domain with multiple islands is investigated. + +The function starts at the given starting point and performs flood +fill to mark all points that are reachable from the starting point +until it encounters the non-operational edges. + +Note that no physical simulation is conducted by this function! + +Parameter ``starting_point``: + Step point at which to start the inference. If `starting_point` is + non-operational, this function might invoke undefined behavior.)doc"; + +static const char *__doc_fiction_detail_operational_domain_impl_inferred_op_domain = +R"doc(All the points inferred (assumed) to be operational but not actually +simulated.)doc"; + +static const char *__doc_fiction_detail_operational_domain_impl_is_step_point_inferred_operational = +R"doc(Checks whether the given step point is part of the inferred +operational domain. If it is, the point is marked as enclosed in the +operational domain. No simulation is performed on `sp`. If `sp` is not +contained in the inferred operational domain, it does not mean that +`sp` is definitely non-operational. It could still appear in the +regular operational domain with either status. + +This function is used by the contour tracing algorithm. + +Parameter ``sp``: + Step point to check for inferred operational status. + +Returns: + `true` iff `sp` is contained in `inferred_op_domain`.)doc"; + static const char *__doc_fiction_detail_operational_domain_impl_is_step_point_operational = R"doc(Logs and returns the operational status at the given point `sp = (d1, ..., dn)`. If the point has already been sampled, it returns the @@ -5939,14 +5979,9 @@ Parameter ``step_points``: static const char *__doc_fiction_detail_operational_domain_impl_stats = R"doc(The statistics of the operational domain computation.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_step_point = -R"doc(A step point represents a point in the x and y dimension from 0 to the -maximum number of steps. A step point does not hold the actual -parameter values, but the step values in the x and y dimension, -respectively. +static const char *__doc_fiction_detail_operational_domain_impl_step_point = R"doc(Forward-declare step_point.)doc"; -See `operational_domain::parameter_point` for a point that holds the -actual parameter values.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_step_point_2 = R"doc(Forward-declare step_point.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_step_point_operator_eq = R"doc(Equality operator. From 9c9d5add90c9be00afde3e2c5b444b3681016cc4 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 23 Jul 2024 14:41:37 +0200 Subject: [PATCH 27/95] :sparkles: Added a flag to `write_operational_domain` to skip the writing of non-operational samples to reduce the resulting CSV file --- .../fiction/io/write_operational_domain.hpp | 12 +++++++ test/io/write_operational_domain.cpp | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/include/fiction/io/write_operational_domain.hpp b/include/fiction/io/write_operational_domain.hpp index 175f6ec68..85102ba4b 100644 --- a/include/fiction/io/write_operational_domain.hpp +++ b/include/fiction/io/write_operational_domain.hpp @@ -31,6 +31,12 @@ struct write_operational_domain_params * The tag used to represent the non-operational value of a parameter set. */ std::string_view non_operational_tag = "0"; + /** + * Whether to write non-operational samples to the CSV file. If set to `false`, only operational samples are + * written. This yields a significantly smaller CSV file. It is recommended to set this option for 3D plots because + * the non-operational samples would shadow the operational samples anyway. + */ + bool write_non_operational_samples = true; }; namespace detail @@ -119,6 +125,12 @@ inline void write_operational_domain(const operational_domain& opdom, std::ostre for (const auto& [sim_param, op_val] : opdom.operational_values) { + // skip non-operational samples if the respective flag is set + if (!params.write_non_operational_samples && op_val == operational_status::NON_OPERATIONAL) + { + continue; + } + const auto tag = op_val == operational_status::OPERATIONAL ? params.operational_tag : params.non_operational_tag; diff --git a/test/io/write_operational_domain.cpp b/test/io/write_operational_domain.cpp index 4053fdab7..c2701973c 100644 --- a/test/io/write_operational_domain.cpp +++ b/test/io/write_operational_domain.cpp @@ -88,6 +88,24 @@ TEST_CASE("Write simple operational domain", "[write-operational-domain]") CHECK(expected.find(line) != expected.end()); } } + + SECTION("skip non-operational samples") + { + write_operational_domain_params params{}; + params.write_non_operational_samples = false; + + std::set expected{"epsilon_r,lambda_tf,operational status", "0,0,1"}; + + write_operational_domain(opdom, os, params); + const auto os_str = os.str(); + + std::istringstream is{os_str}; + + for (std::string line{}; std::getline(is, line);) + { + CHECK(expected.find(line) != expected.end()); + } + } } TEST_CASE("Write operational domain with floating-point parameter values", "[write-operational-domain]") @@ -137,4 +155,22 @@ TEST_CASE("Write operational domain with floating-point parameter values", "[wri CHECK(expected.find(line) != expected.end()); } } + + SECTION("skip non-operational samples") + { + write_operational_domain_params params{}; + params.write_non_operational_samples = false; + + std::set expected{"epsilon_r,lambda_tf,operational status", "0.1,0.2,1", "1.2,1.4,1"}; + + write_operational_domain(opdom, os, params); + const auto os_str = os.str(); + + std::istringstream is{os_str}; + + for (std::string line{}; std::getline(is, line);) + { + CHECK(expected.find(line) != expected.end()); + } + } } From 413ef1c84a6463986d41c3179eb82650b168a5a8 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 23 Jul 2024 12:42:38 +0000 Subject: [PATCH 28/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../include/pyfiction/pybind11_mkdoc_docstrings.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 8e37da3bb..828e5eab6 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -15592,6 +15592,13 @@ set.)doc"; static const char *__doc_fiction_write_operational_domain_params_operational_tag = R"doc(The tag used to represent the operational value of a parameter set.)doc"; +static const char *__doc_fiction_write_operational_domain_params_write_non_operational_samples = +R"doc(Whether to write non-operational samples to the CSV file. If set to +`false`, only operational samples are written. This yields a +significantly smaller CSV file. It is recommended to set this option +for 3D plots because the non-operational samples would shadow the +operational samples anyway.)doc"; + static const char *__doc_fiction_write_qca_layout = R"doc(Writes a cell-level QCA layout to a qca file that is used by QCADesigner (https://waluslab.ece.ubc.ca/qcadesigner/), a physical From 6a0fd278ff8829d18268275661503fd9d5c1291f Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 23 Jul 2024 18:46:22 +0200 Subject: [PATCH 29/95] :zap: Performance improvements by reserving vector space prior to assignment --- .../algorithms/simulation/sidb/operational_domain.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 448366e21..19f487c52 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -290,6 +290,8 @@ class operational_domain_impl for (const auto& dimension : indices) { std::vector expanded_products{}; + expanded_products.reserve(all_step_points.size() * dimension.size()); + for (const auto& product : all_step_points) { for (const auto& element : dimension) @@ -643,7 +645,9 @@ class operational_domain_impl */ [[nodiscard]] step_point to_step_point(const operational_domain::parameter_point& pp) const noexcept { - std::vector step_values; + std::vector step_values{}; + step_values.reserve(num_dimensions); + for (auto d = 0u; d < num_dimensions; ++d) { const auto it = std::lower_bound(values[d].cbegin(), values[d].cend(), pp.parameters[d]); From 328d4cd6c0f718bef0b96056f0c3181e78761bb7 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 29 Jul 2024 12:29:28 +0200 Subject: [PATCH 30/95] :art: Minor consistency fixes --- include/fiction/algorithms/simulation/sidb/is_operational.hpp | 3 +++ .../fiction/algorithms/simulation/sidb/operational_domain.hpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/fiction/algorithms/simulation/sidb/is_operational.hpp b/include/fiction/algorithms/simulation/sidb/is_operational.hpp index 2b97b096f..47afbbfae 100644 --- a/include/fiction/algorithms/simulation/sidb/is_operational.hpp +++ b/include/fiction/algorithms/simulation/sidb/is_operational.hpp @@ -32,6 +32,7 @@ namespace fiction { + /** * Possible operational status of a layout. */ @@ -46,6 +47,7 @@ enum class operational_status : uint8_t */ NON_OPERATIONAL }; + /** * Parameters for the `is_operational` algorithm. */ @@ -312,6 +314,7 @@ class is_operational_impl physical_simulation_of_layout(const bdl_input_iterator& bdl_iterator) noexcept { assert(parameters.simulation_parameters.base == 2 && "base number is set to 3"); + if (parameters.sim_engine == sidb_simulation_engine::EXGS) { // perform an exhaustive ground state simulation diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 19f487c52..f2d569108 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -684,7 +684,7 @@ class operational_domain_impl inline void set_dimension_value(sidb_simulation_parameters& sim_parameters, const double val, const std::size_t dim) const noexcept { - const operational_domain::sweep_parameter sweep_parameter = op_domain.dimensions[dim]; + const operational_domain::sweep_parameter sweep_parameter = params.sweep_dimensions[dim].dimension; switch (sweep_parameter) { From 4d097611a618df66d5c28ee299d585903137f46e Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 29 Jul 2024 12:35:16 +0200 Subject: [PATCH 31/95] :alembic: Small 3D operational domain experiment adjustments --- .../operational_domain/operational_domain_3d_bestagon.cpp | 6 +++--- .../operational_domain/operational_domain_3d_siqad.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/experiments/operational_domain/operational_domain_3d_bestagon.cpp b/experiments/operational_domain/operational_domain_3d_bestagon.cpp index 1b1c942a5..1d44e65dc 100644 --- a/experiments/operational_domain/operational_domain_3d_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_3d_bestagon.cpp @@ -31,7 +31,7 @@ int main() // NOLINT experiments::experiment opdomain_exp{ - "Operational Domain Bestagon", + "Operational Domain Bestagon 3D", "Name", "#SiDBs", // Benchmark "#Samples (GS)", @@ -68,10 +68,10 @@ int main() // NOLINT op_domain_params.sweep_dimensions[1].step = 0.05; op_domain_params.sweep_dimensions[2].min = -0.50; op_domain_params.sweep_dimensions[2].max = -0.10; - op_domain_params.sweep_dimensions[2].step = 0.01; + op_domain_params.sweep_dimensions[2].step = 0.005; // write operational domain parameters - const write_operational_domain_params write_op_domain_params{"1", "0"}; + const write_operational_domain_params write_op_domain_params{"1", "0", false}; static const std::string folder = fmt::format("{}bestagon_gates_type_tags/", EXPERIMENTS_PATH); diff --git a/experiments/operational_domain/operational_domain_3d_siqad.cpp b/experiments/operational_domain/operational_domain_3d_siqad.cpp index 19e2706c8..8bfedb724 100644 --- a/experiments/operational_domain/operational_domain_3d_siqad.cpp +++ b/experiments/operational_domain/operational_domain_3d_siqad.cpp @@ -31,7 +31,7 @@ int main() // NOLINT experiments::experiment opdomain_exp{ - "Operational Domain SiQAD", + "Operational Domain SiQAD 3D", "Name", "#SiDBs", // Benchmark "#Samples (GS)", @@ -68,10 +68,10 @@ int main() // NOLINT op_domain_params.sweep_dimensions[1].step = 0.05; op_domain_params.sweep_dimensions[2].min = -0.50; op_domain_params.sweep_dimensions[2].max = -0.10; - op_domain_params.sweep_dimensions[2].step = 0.01; + op_domain_params.sweep_dimensions[2].step = 0.005; // write operational domain parameters - static const write_operational_domain_params write_op_domain_params{"1", "0"}; + static const write_operational_domain_params write_op_domain_params{"1", "0", false}; static const std::string folder = fmt::format("{}siqad_gates_type_tags/", EXPERIMENTS_PATH); From 9e08578ab133f82d514b4bba23c97f3f0d1deb7e Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 29 Jul 2024 15:11:28 +0200 Subject: [PATCH 32/95] :alembic: Increased number of random samples --- .../operational_domain/operational_domain_3d_bestagon.cpp | 4 ++-- .../operational_domain/operational_domain_3d_siqad.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/experiments/operational_domain/operational_domain_3d_bestagon.cpp b/experiments/operational_domain/operational_domain_3d_bestagon.cpp index 1d44e65dc..3a9c06a98 100644 --- a/experiments/operational_domain/operational_domain_3d_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_3d_bestagon.cpp @@ -121,9 +121,9 @@ int main() // NOLINT const auto op_domain_gs = operational_domain_grid_search(lyt, truth_table, op_domain_params, &op_domain_stats_gs); const auto op_domain_rs = - operational_domain_random_sampling(lyt, truth_table, 2500, op_domain_params, &op_domain_stats_rs); + operational_domain_random_sampling(lyt, truth_table, 10000, op_domain_params, &op_domain_stats_rs); const auto op_domain_ff = - operational_domain_flood_fill(lyt, truth_table, 250, op_domain_params, &op_domain_stats_ff); + operational_domain_flood_fill(lyt, truth_table, 1000, op_domain_params, &op_domain_stats_ff); // write the operational domains to a CSV file write_operational_domain(op_domain_gs, diff --git a/experiments/operational_domain/operational_domain_3d_siqad.cpp b/experiments/operational_domain/operational_domain_3d_siqad.cpp index 8bfedb724..b5142cda4 100644 --- a/experiments/operational_domain/operational_domain_3d_siqad.cpp +++ b/experiments/operational_domain/operational_domain_3d_siqad.cpp @@ -115,9 +115,9 @@ int main() // NOLINT const auto op_domain_gs = operational_domain_grid_search(lyt, truth_table, op_domain_params, &op_domain_stats_gs); const auto op_domain_rs = - operational_domain_random_sampling(lyt, truth_table, 2500, op_domain_params, &op_domain_stats_rs); + operational_domain_random_sampling(lyt, truth_table, 10000, op_domain_params, &op_domain_stats_rs); const auto op_domain_ff = - operational_domain_flood_fill(lyt, truth_table, 250, op_domain_params, &op_domain_stats_ff); + operational_domain_flood_fill(lyt, truth_table, 1000, op_domain_params, &op_domain_stats_ff); // write the operational domains to a CSV file write_operational_domain(op_domain_gs, From e1c1bd40fddb1fd758d9dd8ec62508241c8ff2fa Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 29 Jul 2024 18:43:41 +0200 Subject: [PATCH 33/95] :alembic: Increased resolution for 3D operational domain experiments --- .../operational_domain/operational_domain_3d_bestagon.cpp | 6 +++--- .../operational_domain/operational_domain_3d_siqad.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/experiments/operational_domain/operational_domain_3d_bestagon.cpp b/experiments/operational_domain/operational_domain_3d_bestagon.cpp index 3a9c06a98..6d36f78af 100644 --- a/experiments/operational_domain/operational_domain_3d_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_3d_bestagon.cpp @@ -68,7 +68,7 @@ int main() // NOLINT op_domain_params.sweep_dimensions[1].step = 0.05; op_domain_params.sweep_dimensions[2].min = -0.50; op_domain_params.sweep_dimensions[2].max = -0.10; - op_domain_params.sweep_dimensions[2].step = 0.005; + op_domain_params.sweep_dimensions[2].step = 0.0025; // write operational domain parameters const write_operational_domain_params write_op_domain_params{"1", "0", false}; @@ -121,9 +121,9 @@ int main() // NOLINT const auto op_domain_gs = operational_domain_grid_search(lyt, truth_table, op_domain_params, &op_domain_stats_gs); const auto op_domain_rs = - operational_domain_random_sampling(lyt, truth_table, 10000, op_domain_params, &op_domain_stats_rs); + operational_domain_random_sampling(lyt, truth_table, 20000, op_domain_params, &op_domain_stats_rs); const auto op_domain_ff = - operational_domain_flood_fill(lyt, truth_table, 1000, op_domain_params, &op_domain_stats_ff); + operational_domain_flood_fill(lyt, truth_table, 2000, op_domain_params, &op_domain_stats_ff); // write the operational domains to a CSV file write_operational_domain(op_domain_gs, diff --git a/experiments/operational_domain/operational_domain_3d_siqad.cpp b/experiments/operational_domain/operational_domain_3d_siqad.cpp index b5142cda4..c55390b39 100644 --- a/experiments/operational_domain/operational_domain_3d_siqad.cpp +++ b/experiments/operational_domain/operational_domain_3d_siqad.cpp @@ -68,7 +68,7 @@ int main() // NOLINT op_domain_params.sweep_dimensions[1].step = 0.05; op_domain_params.sweep_dimensions[2].min = -0.50; op_domain_params.sweep_dimensions[2].max = -0.10; - op_domain_params.sweep_dimensions[2].step = 0.005; + op_domain_params.sweep_dimensions[2].step = 0.0025; // write operational domain parameters static const write_operational_domain_params write_op_domain_params{"1", "0", false}; @@ -115,9 +115,9 @@ int main() // NOLINT const auto op_domain_gs = operational_domain_grid_search(lyt, truth_table, op_domain_params, &op_domain_stats_gs); const auto op_domain_rs = - operational_domain_random_sampling(lyt, truth_table, 10000, op_domain_params, &op_domain_stats_rs); + operational_domain_random_sampling(lyt, truth_table, 20000, op_domain_params, &op_domain_stats_rs); const auto op_domain_ff = - operational_domain_flood_fill(lyt, truth_table, 1000, op_domain_params, &op_domain_stats_ff); + operational_domain_flood_fill(lyt, truth_table, 2000, op_domain_params, &op_domain_stats_ff); // write the operational domains to a CSV file write_operational_domain(op_domain_gs, From 1aefb17520fe00827e2c0fbda7e14c55617706b8 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 8 Aug 2024 16:03:30 +0200 Subject: [PATCH 34/95] :zap: Improved load-balancing in multithreaded grid search-based operational domain computation, which increases performance --- .../simulation/sidb/operational_domain.hpp | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index f2d569108..67878ae6f 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -285,7 +285,7 @@ class operational_domain_impl { mockturtle::stopwatch stop{stats.time_total}; - // generate all possible step point combinations via the cartesian product + // generate all possible step point combinations via the Cartesian product of all dimensions std::vector all_step_points{step_point{}}; for (const auto& dimension : indices) { @@ -304,6 +304,13 @@ class operational_domain_impl all_step_points = expanded_products; } + // shuffle the step points to simulate in random order. This helps with load-balancing since + // operational/non-operational points are usually clustered. However, non-operational points can be simulated + // faster on average because of the early termination condition. Thus, threads that mainly simulate + // non-operational points will finish earlier and will be idle while other threads are still simulating the more + // expensive operational points + std::shuffle(all_step_points.begin(), all_step_points.end(), std::mt19937_64{std::random_device{}()}); + simulate_operational_status_in_parallel(all_step_points); log_stats(); @@ -797,7 +804,7 @@ class operational_domain_impl * @param sp Step point to check for inferred operational status. * @return `true` iff `sp` is contained in `inferred_op_domain`. */ - [[nodiscard]] inline bool is_step_point_inferred_operational(const step_point& sp) noexcept + [[nodiscard]] inline bool is_step_point_inferred_operational(const step_point& sp) const noexcept { return inferred_op_domain.count(sp) > 0; } @@ -808,7 +815,7 @@ class operational_domain_impl * @param samples Maximum number of random `step_point`s to generate. * @return A vector of unique random `step_point`s in the stored parameter range of size at most equal to `samples`. */ - [[nodiscard]] std::vector generate_random_step_points(const std::size_t samples) noexcept + [[nodiscard]] std::vector generate_random_step_points(const std::size_t samples) const noexcept { static std::mt19937_64 generator{std::random_device{}()}; @@ -844,9 +851,14 @@ class operational_domain_impl * Simulates the operational status of the given points in parallel. It divides the work among multiple threads to * speed up the computation. * + * @note The distribution of the work among threads is a simple slice-based approach. If your step points are + * ordered, consider shuffling the vector first for better load balancing. Otherwise, some threads might finish + * early if they got assigned a larger slice with mainly non-operational samples, which are faster to compute due to + * the early termination condition. + * * @param step_points A vector of step points for which the operational status is to be simulated. */ - void simulate_operational_status_in_parallel(const std::vector& step_points) + void simulate_operational_status_in_parallel(const std::vector& step_points) noexcept { // calculate the size of each slice const auto slice_size = (step_points.size() + num_threads - 1) / num_threads; @@ -896,7 +908,7 @@ class operational_domain_impl * @param samples Maximum number of samples to take. Works as a timeout. * @return The first operational step point, if any could be found, `std::nullopt` otherwise. */ - [[nodiscard]] std::optional + [[maybe_unused]] [[nodiscard]] std::optional find_operational_step_point_via_random_sampling(const std::size_t samples) noexcept { for (const auto& sample_step_point : generate_random_step_points(samples)) From 57506f2a7d2d939055061ce8787d00c8932af9be Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 8 Aug 2024 14:05:14 +0000 Subject: [PATCH 35/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../include/pyfiction/pybind11_mkdoc_docstrings.hpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 828e5eab6..961595d6f 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5973,6 +5973,13 @@ static const char *__doc_fiction_detail_operational_domain_impl_simulate_operati R"doc(Simulates the operational status of the given points in parallel. It divides the work among multiple threads to speed up the computation. +@note The distribution of the work among threads is a simple slice- +based approach. If your step points are ordered, consider shuffling +the vector first for better load balancing. Otherwise, some threads +might finish early if they got assigned a larger slice with mainly +non-operational samples, which are faster to compute due to the early +termination condition. + Parameter ``step_points``: A vector of step points for which the operational status is to be simulated.)doc"; From dfa15d6cfbce6b99ce145558f48e479b84ce0064 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 8 Aug 2024 16:15:17 +0200 Subject: [PATCH 36/95] :pencil2: Fixed a typo --- .../pyfiction/include/pyfiction/layouts/cartesian_layout.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp b/bindings/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp index c465ee2a8..e0b6f9040 100644 --- a/bindings/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp +++ b/bindings/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp @@ -24,7 +24,7 @@ inline void cartesian_layout(pybind11::module& m) namespace py = pybind11; using namespace pybind11::literals; - /**ü + /** * Cartesian layout. */ py::class_(m, "cartesian_layout", DOC(fiction_cartesian_layout_overridden)) From b3e3ad856bd23b3db6f6c6ec02f81280ef48fd4e Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 8 Aug 2024 16:22:35 +0200 Subject: [PATCH 37/95] :memo: Fixed a docstring ambiguity --- .../fiction/algorithms/simulation/sidb/operational_domain.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 67878ae6f..b648f0911 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -853,8 +853,8 @@ class operational_domain_impl * * @note The distribution of the work among threads is a simple slice-based approach. If your step points are * ordered, consider shuffling the vector first for better load balancing. Otherwise, some threads might finish - * early if they got assigned a larger slice with mainly non-operational samples, which are faster to compute due to - * the early termination condition. + * early if they got assigned a slice with mainly non-operational samples, which are faster to compute due to the + * early termination condition. * * @param step_points A vector of step points for which the operational status is to be simulated. */ From fd2f179f1160356a253d3ef8854b0cb0d290cfa3 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 8 Aug 2024 14:23:34 +0000 Subject: [PATCH 38/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 961595d6f..8d12cf9ab 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5976,8 +5976,8 @@ divides the work among multiple threads to speed up the computation. @note The distribution of the work among threads is a simple slice- based approach. If your step points are ordered, consider shuffling the vector first for better load balancing. Otherwise, some threads -might finish early if they got assigned a larger slice with mainly -non-operational samples, which are faster to compute due to the early +might finish early if they got assigned a slice with mainly non- +operational samples, which are faster to compute due to the early termination condition. Parameter ``step_points``: From 18940709b1b5015c22018f18fd20ee3ac2288c47 Mon Sep 17 00:00:00 2001 From: Drewniok Date: Thu, 8 Aug 2024 17:55:42 +0200 Subject: [PATCH 39/95] :twisted_rightwards_arrows: conduct merge. Python bindings are not updated yet. --- .../simulation/sidb/operational_domain.hpp | 90 ++++++++++++++++--- .../determine_physically_valid_parameters.cpp | 44 ++++----- .../simulation/sidb/operational_domain.cpp | 36 +++----- 3 files changed, 106 insertions(+), 64 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 31f8e0a48..9d70e5327 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -163,7 +163,20 @@ struct operational_domain { return it->second; } - throw std::out_of_range(fmt::format("({},{}) not found in the operational domain", pp.x, pp.y).c_str()); + // Create a stringstream to hold the string representation + std::stringstream ss; + + // Iterate over the vector and add elements to the stringstream + for (std::size_t i = 0; i < pp.parameters.size(); ++i) + { + ss << pp.parameters[i]; + // Add a separator (e.g., comma) between elements + if (i != pp.parameters.size() - 1) + { + ss << ", "; + } + } + throw std::out_of_range(fmt::format("{} not found in the operational domain", ss.str()).c_str()); } }; /** @@ -174,7 +187,7 @@ struct operational_domain_value_range /** * The sweep parameter of the dimension. */ - operational_domain::sweep_parameter dimension; + sweep_parameter dimension; /** * The minimum value of the dimension sweep. */ @@ -339,6 +352,54 @@ class operational_domain_impl } } } + /** + * Additional Constructor. Initializes the layout, the parameters and the statistics. + * + * @param lyt SiDB cell-level layout to be evaluated. + * @param ps Parameters for the operational domain computation. + * @param st Statistics of the process. + */ + operational_domain_impl(const Lyt& lyt, const operational_domain_params& ps, operational_domain_stats& st) noexcept + : + layout{lyt}, + truth_table{std::vector{}}, + params{ps}, + stats{st}, + num_dimensions{params.sweep_dimensions.size()} + { + op_domain.dimensions.reserve(num_dimensions); + + indices.reserve(num_dimensions); + values.reserve(num_dimensions); + + for (auto d = 0u; d < num_dimensions; ++d) + { + op_domain.dimensions.push_back(params.sweep_dimensions[d].dimension); + + // generate the step points for the dimension + indices.push_back(std::vector(num_steps(d) + 1)); + std::iota(indices[d].begin(), indices[d].end(), 0ul); + + // if the value of the parameter is greater than params.max after num_x_steps() steps, this value is + // ignored in the operational domain calculation + if ((params.sweep_dimensions[d].min + + static_cast(indices[d].size() - 1) * params.sweep_dimensions[d].step) - + params.sweep_dimensions[d].max > + physical_constants::POP_STABILITY_ERR) + { + indices[d].pop_back(); + } + + values.emplace_back(); + + // generate the values for the dimension + for (const auto i : indices[d]) + { + values[d].push_back(params.sweep_dimensions[d].min + + static_cast(i) * params.sweep_dimensions[d].step); + } + } + } /** * Performs a grid search over the specified parameter ranges with the specified step sizes. The grid search always * has quadratic complexity. The operational status is computed for each parameter combination. @@ -598,14 +659,11 @@ class operational_domain_impl mockturtle::stopwatch stop{stats.time_total}; + // TODO needs to be fixed // step points are analyzed sequentially because the CDS is updated for each step point, so parallelizing may // result in unexpected behavior. - std::for_each(x_indices.cbegin(), x_indices.cend(), - [this, &lyt](const auto x) - { - std::for_each(y_indices.cbegin(), y_indices.cend(), - [this, &lyt, x](const auto y) { is_step_point_suitable(lyt, {x, y}); }); - }); + std::for_each(indices.cbegin(), indices.cend(), + [this, &lyt](const auto id) { is_step_point_suitable(lyt, step_point{id}); }); sidb_simulation_parameters simulation_parameters = params.simulation_parameters; @@ -617,8 +675,9 @@ class operational_domain_impl { continue; } - set_x_dimension_value(simulation_parameters, param_point.x); - set_y_dimension_value(simulation_parameters, param_point.y); + + set_dimension_value(simulation_parameters, param_point.parameters[0], 0); + set_dimension_value(simulation_parameters, param_point.parameters[1], 1); auto sim_results = sidb_simulation_result{}; @@ -944,6 +1003,7 @@ class operational_domain_impl * @param sp Step point to be investigated. * @return The operational status of the layout under the given simulation parameters. */ + // TODO needs some rewrite operational_status is_step_point_suitable(Lyt& lyt, const step_point& sp) noexcept { // if the point has already been sampled, return the stored operational status @@ -973,8 +1033,8 @@ class operational_domain_impl ++num_evaluated_parameter_combinations; sidb_simulation_parameters sim_params = params.simulation_parameters; - set_x_dimension_value(sim_params, param_point.x); - set_y_dimension_value(sim_params, param_point.y); + set_dimension_value(sim_params, param_point.parameters[0], 0); + set_dimension_value(sim_params, param_point.parameters[1], 1); lyt.assign_physical_parameters(sim_params); @@ -1536,7 +1596,8 @@ operational_domain_flood_fill(const Lyt& lyt, const std::vector& spec, const } operational_domain_stats st{}; - detail::operational_domain_impl p{lyt, spec, params, st}; + detail::operational_domain_impl> p{lyt, spec, + params, st}; const auto result = p.flood_fill(samples); @@ -1596,7 +1657,8 @@ operational_domain_contour_tracing(const Lyt& lyt, const std::vector& spec, } operational_domain_stats st{}; - detail::operational_domain_impl p{lyt, spec, params, st}; + detail::operational_domain_impl> p{lyt, spec, + params, st}; const auto result = p.contour_tracing(samples); diff --git a/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp b/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp index 10c797041..0b593e3ff 100644 --- a/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp +++ b/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -41,19 +42,14 @@ TEST_CASE("Determine physical parameters for CDS of SiQAD Y-shaped AND gate, 10 operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; - op_domain_params.x_dimension = sweep_parameter::EPSILON_R; - op_domain_params.x_min = 4.1; - op_domain_params.x_max = 6.0; - op_domain_params.x_step = 0.1; - op_domain_params.y_dimension = sweep_parameter::LAMBDA_TF; - op_domain_params.y_min = 4.1; - op_domain_params.y_max = 6.0; - op_domain_params.y_step = 0.1; + + op_domain_params.sweep_dimensions = {operational_domain_value_range{sweep_parameter::EPSILON_R, 4.1, 6.0, 0.1}, + operational_domain_value_range{sweep_parameter::LAMBDA_TF, 4.1, 6.0, 0.1}}; SECTION("Using the typical ground state as given CDS") { - op_domain_params.x_step = 0.3; - op_domain_params.y_step = 0.3; + op_domain_params.sweep_dimensions[0].step = 0.3; + op_domain_params.sweep_dimensions[1].step = 0.3; cds.assign_charge_state({-2, -1, 1}, sidb_charge_state::NEGATIVE); cds.assign_charge_state({0, 0, 1}, sidb_charge_state::NEUTRAL); @@ -91,13 +87,13 @@ TEST_CASE("Determine physical parameters for CDS of SiQAD Y-shaped AND gate, 10 const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); CHECK(valid_parameters.operational_values.size() == 98); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{5.9, 5.5}) + CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.9, 5.5}}) ->second == 1); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{5.8, 4.4}) + CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}) ->second == 0); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{5.8, 4.4}) + CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}) ->second == 0); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{6.0, 6.0}) + CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{6.0, 6.0}}) ->second == 1); } } @@ -118,14 +114,8 @@ TEST_CASE( operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; - op_domain_params.x_dimension = sweep_parameter::EPSILON_R; - op_domain_params.x_min = 5.0; - op_domain_params.x_max = 5.9; - op_domain_params.x_step = 0.1; - op_domain_params.y_dimension = sweep_parameter::LAMBDA_TF; - op_domain_params.y_min = 5.0; - op_domain_params.y_max = 5.9; - op_domain_params.y_step = 0.1; + op_domain_params.sweep_dimensions = {operational_domain_value_range{sweep_parameter::EPSILON_R, 5.0, 5.9, 0.1}, + operational_domain_value_range{sweep_parameter::LAMBDA_TF, 5.0, 5.9, 0.1}}; SECTION("Using the ground state of default physical parameters as given CDS") { @@ -161,14 +151,14 @@ TEST_CASE( cds.update_after_charge_change(); const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); - CHECK(valid_parameters.operational_values.size() == 100); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{5.6, 5.0}) + REQUIRE(valid_parameters.operational_values.size() == 100); + CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.6, 5.0}}) ->second == 0); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{5.0, 5.9}) + CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.0, 5.9}}) ->second == 2); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{5.4, 5.3}) + CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.4, 5.3}}) ->second == 1); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{5.8, 5.3}) + CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.8, 5.3}}) ->second == 0); } } diff --git a/test/algorithms/simulation/sidb/operational_domain.cpp b/test/algorithms/simulation/sidb/operational_domain.cpp index ff0dca8a3..090fdfe1d 100644 --- a/test/algorithms/simulation/sidb/operational_domain.cpp +++ b/test/algorithms/simulation/sidb/operational_domain.cpp @@ -23,9 +23,9 @@ using namespace fiction; -void check_op_domain_params_and_operational_status(const operational_domain& op_domain, - const operational_domain_params& params, - const std::optional& status) noexcept +void check_op_domain_params_and_operational_status( + const operational_domain& op_domain, const operational_domain_params& params, + const std::optional& status) noexcept { REQUIRE(params.sweep_dimensions.size() == op_domain.dimensions.size()); @@ -84,8 +84,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; - op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, - {sweep_parameter::LAMBDA_TF}}; + op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; operational_domain_stats op_domain_stats{}; @@ -120,8 +119,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); @@ -162,8 +160,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); @@ -204,8 +201,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.32, -0.32, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); @@ -359,8 +355,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); @@ -401,8 +396,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); @@ -443,8 +437,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.35, -0.29, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); @@ -516,8 +509,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); @@ -558,8 +550,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); @@ -600,8 +591,7 @@ TEST_CASE("BDL wire operational domain computation", "[operational-domain]") SECTION("3-dimensional") { - const auto z_dimension = - operational_domain_value_range{operational_domain::sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; + const auto z_dimension = operational_domain_value_range{sweep_parameter::MU_MINUS, -0.14, -0.10, 0.01}; op_domain_params.sweep_dimensions.push_back(z_dimension); From 78de1d0934446064541243cb277edd2a78e88c93 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:56:01 +0000 Subject: [PATCH 40/95] =?UTF-8?q?=F0=9F=8E=A8=20Incorporated=20pre-commit?= =?UTF-8?q?=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simulation/sidb/operational_domain.hpp | 40 +++++++++---------- test/io/write_operational_domain.cpp | 9 ++--- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 9d70e5327..720721b5d 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -35,9 +35,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -51,44 +51,44 @@ namespace fiction struct parameter_point { /** - * Default constructor. + * Default constructor. */ parameter_point() = default; /** - * Standard constructor. - * - * @param values Parameter values for each dimension. + * Standard constructor. + * + * @param values Parameter values for each dimension. */ explicit parameter_point(const std::vector& values) : parameters(values) {} /** - * Parameter values for each dimension. + * Parameter values for each dimension. */ std::vector parameters; /** - * Equality operator. - * - * @param other Other parameter point to compare with. - * @return `true` if the parameter points are equal. + * Equality operator. + * + * @param other Other parameter point to compare with. + * @return `true` if the parameter points are equal. */ bool operator==(const parameter_point& other) const noexcept { return parameters == other.parameters; } /** - * Inequality operator. - * - * @param other Other parameter point to compare with. - * @return `true` if the parameter points are not equal. + * Inequality operator. + * + * @param other Other parameter point to compare with. + * @return `true` if the parameter points are not equal. */ bool operator!=(const parameter_point& other) const noexcept { return !(*this == other); } /** - * Support for structured bindings. - * - * @tparam I Index of the parameter value to be returned. - * @return The parameter value at the specified index. + * Support for structured bindings. + * + * @tparam I Index of the parameter value to be returned. + * @return The parameter value at the specified index. */ template auto get() const @@ -1595,7 +1595,7 @@ operational_domain_flood_fill(const Lyt& lyt, const std::vector& spec, const throw std::runtime_error("Flood fill is only applicable to 2 or 3 dimensions"); } - operational_domain_stats st{}; + operational_domain_stats st{}; detail::operational_domain_impl> p{lyt, spec, params, st}; @@ -1656,7 +1656,7 @@ operational_domain_contour_tracing(const Lyt& lyt, const std::vector& spec, throw std::runtime_error("Contour tracing is only applicable to exactly 2 dimensions"); } - operational_domain_stats st{}; + operational_domain_stats st{}; detail::operational_domain_impl> p{lyt, spec, params, st}; diff --git a/test/io/write_operational_domain.cpp b/test/io/write_operational_domain.cpp index 12fd6d647..8ba0cced8 100644 --- a/test/io/write_operational_domain.cpp +++ b/test/io/write_operational_domain.cpp @@ -115,11 +115,10 @@ TEST_CASE("Write operational domain with floating-point parameter values", "[wri opdom.dimensions.push_back(sweep_parameter::EPSILON_R); opdom.dimensions.push_back(sweep_parameter::LAMBDA_TF); - opdom.operational_values = { - {parameter_point{{0.1, 0.2}}, operational_status::OPERATIONAL}, - {parameter_point{{0.3, 0.4}}, operational_status::NON_OPERATIONAL}, - {parameter_point{{1.2, 1.4}}, operational_status::OPERATIONAL}, - {parameter_point{{2.4, 5.75}}, operational_status::NON_OPERATIONAL}}; + opdom.operational_values = {{parameter_point{{0.1, 0.2}}, operational_status::OPERATIONAL}, + {parameter_point{{0.3, 0.4}}, operational_status::NON_OPERATIONAL}, + {parameter_point{{1.2, 1.4}}, operational_status::OPERATIONAL}, + {parameter_point{{2.4, 5.75}}, operational_status::NON_OPERATIONAL}}; std::ostringstream os{}; From acfd1e0699bd71d73eea5d4b444c293653d47f10 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 8 Aug 2024 15:56:49 +0000 Subject: [PATCH 41/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 122 +++++------------- 1 file changed, 33 insertions(+), 89 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 753d21886..d45b1f5cd 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -171,10 +171,6 @@ Parameter ``cell_nw``: Parameter ``cell_se``: The southeast cell defining the ending point of the area. -Parameter ``obstructed_cell``: - Optional cell which is obstructed and therefore not included in - the returned vector. - Returns: A vector containing all cells within the specified area.)doc"; @@ -4137,7 +4133,10 @@ positions of the first SiDB due to the allowed/possible displacements.)doc"; static const char *__doc_fiction_detail_displacement_robustness_domain_impl_calculate_all_possible_displacements_for_each_sidb = R"doc(This function calculates all permitted displacements for each SiDB -based on the specified allowed displacements.)doc"; +based on the specified allowed displacements. + +Returns: + A vector containing all possible displacements for each SiDB.)doc"; static const char *__doc_fiction_detail_displacement_robustness_domain_impl_determine_propability_of_fabricating_operational_gate = R"doc(The manufacturing error rate is highly dependent on the speed of the @@ -4179,13 +4178,14 @@ Parameter ``ps``: Parameter ``st``: Statistics related to the displacement robustness computation.)doc"; -static const char *__doc_fiction_detail_displacement_robustness_domain_impl_generate_combinations = +static const char *__doc_fiction_detail_displacement_robustness_domain_impl_generate_all_possible_combinations_of_displacements = R"doc(This is a helper function, which recursively generates combinations of SiDB displacements for all SiDBs based on the provided vector of displacement vectors. Parameter ``result``: - The vector to store the generated combinations. + The vector to store the generated combinations. The first element + describes the SiDBs of the first displaced layout. Parameter ``current_combination``: The current combination being constructed. @@ -7606,16 +7606,6 @@ static const char *__doc_fiction_determine_vertex_coloring_stats_duration = R"do static const char *__doc_fiction_determine_vertex_coloring_stats_most_frequent_color = R"doc(The color that appeared the most.)doc"; -static const char *__doc_fiction_dimer_displacement_policy = R"doc(Specifies the allowed displacement range options for SiDB placement.)doc"; - -static const char *__doc_fiction_dimer_displacement_policy_ALLOW_OTHER_DIMER = -R"doc(In this mode, SiDBs are allowed to be displaced from the original -dimer to any other dimer within the layout.)doc"; - -static const char *__doc_fiction_dimer_displacement_policy_STAY_ON_ORIGINAL_DIMER = -R"doc(In this mode, any displacement of SiDBs must remain within the -boundaries of the initial dimer they are placed on.)doc"; - static const char *__doc_fiction_displacement_robustness_domain = R"doc(During fabrication, SiDBs may not align precisely with their intended atomic positions, resulting in displacement. This means that an SiDB @@ -7636,13 +7626,25 @@ R"doc(Parameters for the `determine_displacement_robustness_domain` and `determine_propability_of_fabricating_operational_gate` algorithms. Parameter ``CellType``: - cell type.)doc"; + SiDB layout cell type.)doc"; static const char *__doc_fiction_displacement_robustness_domain_params_analysis_mode = R"doc(This parameter defines the mode of the displacement. If `EXHAUSTIVE`, all possible displacements are analyzed. Otherwise, a certain amount of all possible displacements is analyzed randomly.)doc"; +static const char *__doc_fiction_displacement_robustness_domain_params_dimer_displacement_policy = +R"doc(Specifies the allowed displacement range options for SiDB fabrication +simulation.)doc"; + +static const char *__doc_fiction_displacement_robustness_domain_params_dimer_displacement_policy_ALLOW_OTHER_DIMER = +R"doc(In this mode, SiDBs are allowed to be displaced from the original +dimer to any other dimer within the layout.)doc"; + +static const char *__doc_fiction_displacement_robustness_domain_params_dimer_displacement_policy_STAY_ON_ORIGINAL_DIMER = +R"doc(In this mode, any displacement of SiDBs must remain within the +boundaries of the initial dimer they are placed on.)doc"; + static const char *__doc_fiction_displacement_robustness_domain_params_dimer_policy = R"doc(This flag controls whether the displacement in the y-direction can lead to changes in the Si dimer.)doc"; @@ -12511,52 +12513,9 @@ Parameter ``stats``: The operational domain of the layout.)doc"; static const char *__doc_fiction_operational_domain_operational_values = -R"doc(The operational status of the layout for each specified parameter -combination. This constitutes the operational domain. The key of the -map is the parameter point, which holds the parameter values in the x -and y dimension. The operational status is stored as the value of the -map.)doc"; - -static const char *__doc_fiction_operational_domain_parameter_point = -R"doc(The parameter point holds parameter values in an arbitrary number of -dimensions.)doc"; - -static const char *__doc_fiction_operational_domain_parameter_point_get = -R"doc(Support for structured bindings. - -Template parameter ``I``: - Index of the parameter value to be returned. - -Returns: - The parameter value at the specified index.)doc"; - -static const char *__doc_fiction_operational_domain_parameter_point_operator_eq = -R"doc(Equality operator. - -Parameter ``other``: - Other parameter point to compare with. - -Returns: - `true` if the parameter points are equal.)doc"; - -static const char *__doc_fiction_operational_domain_parameter_point_operator_ne = -R"doc(Inequality operator. - -Parameter ``other``: - Other parameter point to compare with. - -Returns: - `true` if the parameter points are not equal.)doc"; - -static const char *__doc_fiction_operational_domain_parameter_point_parameter_point = R"doc(Default constructor.)doc"; - -static const char *__doc_fiction_operational_domain_parameter_point_parameter_point_2 = -R"doc(Standard constructor. - -Parameter ``values``: - Parameter values for each dimension.)doc"; - -static const char *__doc_fiction_operational_domain_parameter_point_parameters = R"doc(Parameter values for each dimension.)doc"; +R"doc(This can store different information depending on the use case. If the +operational domain is simulated for different physical parameters, the +parameters are stored with the corresponding operating status.)doc"; static const char *__doc_fiction_operational_domain_params = R"doc(Parameters for the operational domain computation. The parameters are @@ -12641,14 +12600,6 @@ static const char *__doc_fiction_operational_domain_stats_num_operational_parame static const char *__doc_fiction_operational_domain_stats_num_simulator_invocations = R"doc(Number of simulator invocations.)doc"; -static const char *__doc_fiction_operational_domain_sweep_parameter = R"doc(Possible sweep parameters for the operational domain computation.)doc"; - -static const char *__doc_fiction_operational_domain_sweep_parameter_EPSILON_R = R"doc(The relative permittivity of the dielectric material.)doc"; - -static const char *__doc_fiction_operational_domain_sweep_parameter_LAMBDA_TF = R"doc(The Thomas-Fermi screening length.)doc"; - -static const char *__doc_fiction_operational_domain_sweep_parameter_MU_MINUS = R"doc(The energy transition level.)doc"; - static const char *__doc_fiction_operational_domain_value_range = R"doc(A range of values for a dimension sweep. The range is defined by a minimum value, a maximum value and a step size.)doc"; @@ -12864,41 +12815,32 @@ Template parameter ``I``: The parameter value at the specified index.)doc"; static const char *__doc_fiction_parameter_point_operator_eq = -R"doc(Equality operator. Checks if this parameter point is equal to another -point within a specified tolerance. The tolerance is defined by -`physical_constants::POP_STABILITY_ERR`. +R"doc(Equality operator. Parameter ``other``: Other parameter point to compare with. Returns: - `true` iff the parameter points are equal.)doc"; + `true` if the parameter points are equal.)doc"; static const char *__doc_fiction_parameter_point_operator_ne = -R"doc(Inequality operator. Checks if this parameter point is unequal to -another point within a specified tolerance. The tolerance is defined -by `physical_constants::POP_STABILITY_ERR`. +R"doc(Inequality operator. Parameter ``other``: Other parameter point to compare with. Returns: - `true` iff the parameter points are not equal.)doc"; + `true` if the parameter points are not equal.)doc"; -static const char *__doc_fiction_parameter_point_parameter_point = R"doc(Standard default constructor.)doc"; +static const char *__doc_fiction_parameter_point_parameter_point = R"doc(Default constructor.)doc"; static const char *__doc_fiction_parameter_point_parameter_point_2 = R"doc(Standard constructor. -Parameter ``x_val``: - X dimension parameter value. - -Parameter ``y_val``: - Y dimension parameter value.)doc"; - -static const char *__doc_fiction_parameter_point_x = R"doc(X dimension parameter value.)doc"; +Parameter ``values``: + Parameter values for each dimension.)doc"; -static const char *__doc_fiction_parameter_point_y = R"doc(Y dimension parameter value.)doc"; +static const char *__doc_fiction_parameter_point_parameters = R"doc(Parameter values for each dimension.)doc"; static const char *__doc_fiction_path_collection = R"doc(An ordered collection of multiple paths in a layout. @@ -16460,6 +16402,8 @@ static const char *__doc_std_hash_operator_call_6 = R"doc()doc"; static const char *__doc_std_iterator_traits = R"doc()doc"; +static const char *__doc_std_tuple_size = R"doc()doc"; + #if defined(__GNUG__) #pragma GCC diagnostic pop #endif From 8ec2bc43257d8661b245ce56c4bc25ad8d2047fb Mon Sep 17 00:00:00 2001 From: Drewniok Date: Thu, 8 Aug 2024 18:28:53 +0200 Subject: [PATCH 42/95] :twisted_rightwards_arrows: adjust some python APIs --- .../determine_physically_valid_parameters.hpp | 8 +--- .../simulation/sidb/operational_domain.hpp | 42 +++++++------------ 2 files changed, 16 insertions(+), 34 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/determine_physically_valid_parameters.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/determine_physically_valid_parameters.hpp index e1fca7e3d..0cff96e1c 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/determine_physically_valid_parameters.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/determine_physically_valid_parameters.hpp @@ -38,13 +38,9 @@ inline void determine_physically_valid_parameters(pybind11::module& m) py::class_>(m, "physically_valid_parameters_domain", DOC(fiction_operational_domain)) + // todo add docu .def(py::init<>()) - .def_readwrite("x_dimension_parameter", - &fiction::operational_domain::x_dimension, - DOC(fiction_operational_domain_x_dimension)) - .def_readwrite("y_dimension_parameter", - &fiction::operational_domain::y_dimension, - DOC(fiction_operational_domain_y_dimension)) + .def_readwrite("dimensions", &fiction::operational_domain::dimensions) .def( "get_excited_state_number_for_parameter", diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp index 59681800c..ba046f42b 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp @@ -60,9 +60,8 @@ inline void operational_domain(pybind11::module& m) py::class_(m, "parameter_point", DOC(fiction_parameter_point)) .def(py::init<>()) - .def(py::init(), "x_val"_a, "y_val"_a) - .def_readwrite("x", &fiction::parameter_point::x, DOC(fiction_parameter_point_x)) - .def_readwrite("y", &fiction::parameter_point::y, DOC(fiction_parameter_point_y)) + .def(py::init>(), "values"_a) + .def_readwrite("parameters", &fiction::parameter_point::parameters, DOC(fiction_parameter_point_x)) .def(py::self == py::self, "other"_a, DOC(fiction_parameter_point_operator_eq)) .def(py::self != py::self, "other"_a, DOC(fiction_parameter_point_operator_ne)) @@ -75,17 +74,21 @@ inline void operational_domain(pybind11::module& m) py::class_>( m, "operational_domain", DOC(fiction_operational_domain)) .def(py::init<>()) - .def_readwrite("x_dimension", - &fiction::operational_domain::x_dimension, - DOC(fiction_operational_domain_x_dimension)) - .def_readwrite("y_dimension", - &fiction::operational_domain::y_dimension, - DOC(fiction_operational_domain_y_dimension)) + .def_readwrite("dimensions", + &fiction::operational_domain::dimensions) .def_readwrite( "operational_values", &fiction::operational_domain::operational_values, DOC(fiction_operational_domain_operational_values)); + // add docu + py::class_(m, "operational_domain_value_range") + .def(py::init<>()) + .def_readwrite("dimension", &fiction::operational_domain_value_range::dimension) + .def_readwrite("min", &fiction::operational_domain_value_range::min) + .def_readwrite("max", &fiction::operational_domain_value_range::max) + .def_readwrite("step", &fiction::operational_domain_value_range::step); + py::class_(m, "operational_domain_params", DOC(fiction_operational_domain_params)) .def(py::init<>()) @@ -93,26 +96,9 @@ inline void operational_domain(pybind11::module& m) DOC(fiction_operational_domain_params_simulation_parameters)) .def_readwrite("sim_engine", &fiction::operational_domain_params::sim_engine, DOC(fiction_operational_domain_params_sim_engine)) - .def_readwrite("x_dimension", &fiction::operational_domain_params::x_dimension, - DOC(fiction_operational_domain_params_x_dimension)) - .def_readwrite("x_min", &fiction::operational_domain_params::x_min, - DOC(fiction_operational_domain_params_x_min)) - .def_readwrite("x_max", &fiction::operational_domain_params::x_max, - DOC(fiction_operational_domain_params_x_max)) - .def_readwrite("x_step", &fiction::operational_domain_params::x_step, - DOC(fiction_operational_domain_params_x_step)) - .def_readwrite("y_dimension", &fiction::operational_domain_params::y_dimension, - DOC(fiction_operational_domain_params_y_dimension)) - .def_readwrite("y_min", &fiction::operational_domain_params::y_min, - DOC(fiction_operational_domain_params_y_min)) - .def_readwrite("y_max", &fiction::operational_domain_params::y_max, - DOC(fiction_operational_domain_params_y_max)) - .def_readwrite("y_step", &fiction::operational_domain_params::y_step, - DOC(fiction_operational_domain_params_y_step)) + .def_readwrite("sweep_dimensions", &fiction::operational_domain_params::sweep_dimensions) .def_readwrite("bdl_params", &fiction::operational_domain_params::bdl_params, - DOC(fiction_operational_domain_params_bdl_params)) - - ; + DOC(fiction_operational_domain_params_bdl_params)); py::class_(m, "operational_domain_stats", DOC(fiction_operational_domain_stats)) .def(py::init<>()) From 416c2707a573bad1ca4e53fa9a4a83bb697e6683 Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 09:24:31 +0200 Subject: [PATCH 43/95] :art: small adjustments after merge. --- .../simulation/sidb/operational_domain.hpp | 3 +- cli/cmd/simulation/opdom.hpp | 59 ++++++++++++------- .../operational_domain_3d_siqad.cpp | 6 +- .../operational_domain_bestagon.cpp | 4 +- .../operational_domain_siqad.cpp | 8 +-- .../sidb/displacement_robustness_domain.hpp | 34 +---------- .../simulation/sidb/operational_domain.hpp | 48 ++++++++++++--- include/fiction/utils/math_utils.hpp | 56 ++++++++++++++++++ 8 files changed, 145 insertions(+), 73 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp index ba046f42b..e1028da4c 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp @@ -15,6 +15,7 @@ #include #include +#include namespace pyfiction { @@ -61,7 +62,7 @@ inline void operational_domain(pybind11::module& m) py::class_(m, "parameter_point", DOC(fiction_parameter_point)) .def(py::init<>()) .def(py::init>(), "values"_a) - .def_readwrite("parameters", &fiction::parameter_point::parameters, DOC(fiction_parameter_point_x)) + .def_readwrite("parameters", &fiction::parameter_point::parameters, DOC(fiction_parameter_point)) .def(py::self == py::self, "other"_a, DOC(fiction_parameter_point_operator_eq)) .def(py::self != py::self, "other"_a, DOC(fiction_parameter_point_operator_ne)) diff --git a/cli/cmd/simulation/opdom.hpp b/cli/cmd/simulation/opdom.hpp index 72e099099..78e000d41 100644 --- a/cli/cmd/simulation/opdom.hpp +++ b/cli/cmd/simulation/opdom.hpp @@ -64,13 +64,17 @@ class opdom_command : public command add_option("--x_sweep", x_sweep, "Sweep parameter of the x dimension [epsilon_r, lambda_tf, mu_minus]", true); add_option("--y_sweep", y_sweep, "Sweep parameter of the y dimension [epsilon_r, lambda_tf, mu_minus]", true); - - add_option("--x_min", params.x_min, "Minimum value of the x dimension sweep", true); - add_option("--x_max", params.x_max, "Maximum value of the x dimension sweep", true); - add_option("--x_step", params.x_step, "Step size of the x dimension sweep", true); - add_option("--y_min", params.y_min, "Minimum value of the y dimension sweep", true); - add_option("--y_max", params.y_max, "Maximum value of the y dimension sweep", true); - add_option("--y_step", params.y_step, "Step size of the y dimension sweep", true); + add_option("--z_sweep", z_sweep, "Sweep parameter of the z dimension [epsilon_r, lambda_tf, mu_minus]", true); + + add_option("--x_min", params.sweep_dimensions[0].min, "Minimum value of the x dimension sweep", true); + add_option("--x_max", params.sweep_dimensions[0].max, "Maximum value of the x dimension sweep", true); + add_option("--x_step", params.sweep_dimensions[0].step, "Step size of the x dimension sweep", true); + add_option("--y_min", params.sweep_dimensions[1].min, "Minimum value of the y dimension sweep", true); + add_option("--y_max", params.sweep_dimensions[1].max, "Maximum value of the y dimension sweep", true); + add_option("--y_step", params.sweep_dimensions[1].step, "Step size of the y dimension sweep", true); + add_option("--z_min", params.sweep_dimensions[2].min, "Minimum value of the y dimension sweep", true); + add_option("--z_max", params.sweep_dimensions[2].max, "Maximum value of the y dimension sweep", true); + add_option("--z_step", params.sweep_dimensions[2].step, "Step size of the y dimension sweep", true); } protected: @@ -97,15 +101,10 @@ class opdom_command : public command } // check for valid x and y parameter bounds - if (params.x_min >= params.x_max) + for (const auto &dim : params.sweep_dimensions) + if (dim.min >= dim.max) { - env->out() << "[e] x_min must be smaller than x_max" << std::endl; - reset_params(); - return; - } - if (params.y_min >= params.y_max) - { - env->out() << "[e] y_min must be smaller than y_max" << std::endl; + env->out() << "[e] min must be smaller than max" << std::endl; reset_params(); return; } @@ -180,29 +179,43 @@ class opdom_command : public command // assign x sweep parameters if (x_sweep == "epsilon_r") { - params.x_dimension = fiction::sweep_parameter::EPSILON_R; + params.sweep_dimensions[0].dimension = fiction::sweep_parameter::EPSILON_R; } else if (x_sweep == "lambda_tf") { - params.x_dimension = fiction::sweep_parameter::LAMBDA_TF; + params.sweep_dimensions[0].dimension = fiction::sweep_parameter::LAMBDA_TF; } else if (x_sweep == "mu_minus") { - params.x_dimension = fiction::sweep_parameter::MU_MINUS; + params.sweep_dimensions[0].dimension = fiction::sweep_parameter::MU_MINUS; } // assign y sweep parameters if (y_sweep == "epsilon_r") { - params.y_dimension = fiction::sweep_parameter::EPSILON_R; + params.sweep_dimensions[1].dimension = fiction::sweep_parameter::EPSILON_R; } else if (y_sweep == "lambda_tf") { - params.y_dimension = fiction::sweep_parameter::LAMBDA_TF; + params.sweep_dimensions[1].dimension = fiction::sweep_parameter::LAMBDA_TF; } else if (y_sweep == "mu_minus") { - params.y_dimension = fiction::sweep_parameter::MU_MINUS; + params.sweep_dimensions[1].dimension = fiction::sweep_parameter::MU_MINUS; + } + + // assign z sweep parameters + if (z_sweep == "epsilon_r") + { + params.sweep_dimensions[2].dimension = fiction::sweep_parameter::EPSILON_R; + } + else if (z_sweep == "lambda_tf") + { + params.sweep_dimensions[2].dimension = fiction::sweep_parameter::LAMBDA_TF; + } + else if (z_sweep == "mu_minus") + { + params.sweep_dimensions[2].dimension = fiction::sweep_parameter::MU_MINUS; } const auto get_name = [](auto&& lyt_ptr) -> std::string { return fiction::get_name(*lyt_ptr); }; @@ -285,6 +298,10 @@ class opdom_command : public command * User input for the y dimension sweep parameter. */ std::string y_sweep{}; + /** + * User input for the z dimension sweep parameter. + */ + std::string z_sweep{}; /** * CSV filename to write the operational domain to. */ diff --git a/experiments/operational_domain/operational_domain_3d_siqad.cpp b/experiments/operational_domain/operational_domain_3d_siqad.cpp index c55390b39..dcb50388b 100644 --- a/experiments/operational_domain/operational_domain_3d_siqad.cpp +++ b/experiments/operational_domain/operational_domain_3d_siqad.cpp @@ -57,9 +57,9 @@ int main() // NOLINT operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, - {operational_domain::sweep_parameter::LAMBDA_TF}, - {operational_domain::sweep_parameter::MU_MINUS}}; + op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}, + {sweep_parameter::MU_MINUS}}; op_domain_params.sweep_dimensions[0].min = 1.0; op_domain_params.sweep_dimensions[0].max = 10.0; op_domain_params.sweep_dimensions[0].step = 0.05; diff --git a/experiments/operational_domain/operational_domain_bestagon.cpp b/experiments/operational_domain/operational_domain_bestagon.cpp index 27ad014b5..45fa03465 100644 --- a/experiments/operational_domain/operational_domain_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_bestagon.cpp @@ -61,8 +61,8 @@ int main() // NOLINT operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, - {operational_domain::sweep_parameter::LAMBDA_TF}}; + op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}}; op_domain_params.sweep_dimensions[0].min = 1.0; op_domain_params.sweep_dimensions[0].max = 10.0; op_domain_params.sweep_dimensions[0].step = 0.05; diff --git a/experiments/operational_domain/operational_domain_siqad.cpp b/experiments/operational_domain/operational_domain_siqad.cpp index 40f765226..e87967c80 100644 --- a/experiments/operational_domain/operational_domain_siqad.cpp +++ b/experiments/operational_domain/operational_domain_siqad.cpp @@ -61,8 +61,8 @@ int main() // NOLINT operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, - {operational_domain::sweep_parameter::LAMBDA_TF}}; + op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}}; op_domain_params.sweep_dimensions[0].min = 1.0; op_domain_params.sweep_dimensions[0].max = 10.0; op_domain_params.sweep_dimensions[0].step = 0.05; @@ -195,7 +195,7 @@ int main() // NOLINT } opdomain_exp.save(); - opdomain_exp.table(); + //opdomain_exp.table(); } // log the total number of samples and simulator calls @@ -218,7 +218,7 @@ int main() // NOLINT ); opdomain_exp.save(); - opdomain_exp.table(); + //opdomain_exp.table(); return EXIT_SUCCESS; } diff --git a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp index a3b457298..92aaf8e92 100644 --- a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp @@ -484,36 +484,6 @@ class displacement_robustness_domain_impl return all_possible_sidb_misplacements; } - /** - * This is a helper function, which recursively generates combinations of SiDB displacements for all SiDBs - * based on the provided vector of displacement vectors. - * - * @param result The vector to store the generated combinations. The first element describes the SiDBs of the first - * displaced layout. - * @param current_combination The current combination being constructed. - * @param cell_index The current cell_index in the vector of displacement vectors. - */ - void generate_all_possible_combinations_of_displacements(std::vector>>& result, - std::vector>& current_combination, - const std::size_t cell_index) noexcept - { - if (cell_index == all_possible_sidb_displacements.size()) - { - result.push_back(current_combination); - return; - } - - // Recursively generate combinations for each cell in the current displacement vector - for (const auto& c : all_possible_sidb_displacements[cell_index]) - { - // Add current cell to the combination - current_combination.push_back(c); - // Recursively generate next combinations - generate_all_possible_combinations_of_displacements(result, current_combination, cell_index + 1); - // Backtrack: remove current cell to explore other combinations - current_combination.pop_back(); - } - } /** * This function generates all SiDB layouts with displacements based on the original layout. * It filters out layouts where two or more SiDBs would be on the same spot due to displacement. @@ -522,9 +492,7 @@ class displacement_robustness_domain_impl */ [[nodiscard]] std::vector generate_valid_displaced_sidb_layouts() noexcept { - std::vector>> all_possible_sidb_displacement{}; - std::vector> current_combination{}; - generate_all_possible_combinations_of_displacements(all_possible_sidb_displacement, current_combination, 0); + auto all_possible_sidb_displacement = generateAllCombinations(all_possible_sidb_displacements); std::shuffle(all_possible_sidb_displacement.begin(), all_possible_sidb_displacement.end(), generator); diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 720721b5d..da3d0b55c 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -70,9 +70,30 @@ struct parameter_point * @param other Other parameter point to compare with. * @return `true` if the parameter points are equal. */ - bool operator==(const parameter_point& other) const noexcept - { - return parameters == other.parameters; + /** + * Equality operator. Checks if this parameter point is equal to another point within a specified tolerance. + * The tolerance is defined by `physical_constants::POP_STABILITY_ERR`. + * + * @param other Other parameter point to compare with. + * @return `true` iff the parameter points are equal. + */ + [[nodiscard]] bool operator==(const parameter_point& other) const noexcept { + // Check if sizes are equal + if (parameters.size() != other.parameters.size()) { + return false; + } + + // Define tolerance for comparison + constexpr auto tolerance = physical_constants::POP_STABILITY_ERR; + + // Compare each element with tolerance + for (std::size_t i = 0; i < parameters.size(); ++i) { + if (std::abs(parameters[i] - other.parameters[i]) > tolerance) { + return false; + } + } + + return true; } /** * Inequality operator. @@ -662,8 +683,12 @@ class operational_domain_impl // TODO needs to be fixed // step points are analyzed sequentially because the CDS is updated for each step point, so parallelizing may // result in unexpected behavior. - std::for_each(indices.cbegin(), indices.cend(), - [this, &lyt](const auto id) { is_step_point_suitable(lyt, step_point{id}); }); + const auto all_indice_combinations = generateAllCombinations(indices); + + std::for_each(all_indice_combinations.cbegin(), all_indice_combinations.cend(), + [this, &lyt](const auto id) { + is_step_point_suitable(lyt, step_point{id}); + }); sidb_simulation_parameters simulation_parameters = params.simulation_parameters; @@ -676,8 +701,10 @@ class operational_domain_impl continue; } - set_dimension_value(simulation_parameters, param_point.parameters[0], 0); - set_dimension_value(simulation_parameters, param_point.parameters[1], 1); + for (auto d = 0u; d < num_dimensions; ++d) + { + set_dimension_value(simulation_parameters, param_point.parameters[d], d); + } auto sim_results = sidb_simulation_result{}; @@ -1033,8 +1060,11 @@ class operational_domain_impl ++num_evaluated_parameter_combinations; sidb_simulation_parameters sim_params = params.simulation_parameters; - set_dimension_value(sim_params, param_point.parameters[0], 0); - set_dimension_value(sim_params, param_point.parameters[1], 1); + + for (auto d = 0u; d < num_dimensions; ++d) + { + set_dimension_value(sim_params, param_point.parameters[d], d); + } lyt.assign_physical_parameters(sim_params); diff --git a/include/fiction/utils/math_utils.hpp b/include/fiction/utils/math_utils.hpp index 83ed3bd9f..098afca75 100644 --- a/include/fiction/utils/math_utils.hpp +++ b/include/fiction/utils/math_utils.hpp @@ -118,6 +118,62 @@ determine_all_combinations_of_distributing_k_entities_on_n_positions(const std:: return all_combinations; } +/** + * This function traverses through each vector in the `indices` and builds combinations by + * taking one element from each vector. The generated combinations are stored in the `result` vector. + * + * @tparam VectorDataType The type of elements stored in the input vectors. + * @param indices A vector of vectors from which combinations are generated. + * @param currentCombination A vector that holds the current combination being generated. + * @param depth The current recursion depth, which corresponds to the index of the vector in `indices`. + * @param result A reference to a vector where the generated combinations are stored. + */ +template +void generateCombinations(const std::vector>& indices, + std::vector& currentCombination, const std::size_t depth, + std::vector>& result) +{ + if (depth == indices.size()) + { + // Store the current combination in the result vector + result.push_back(currentCombination); + return; + } + + // Iterate over each element in the current vector + for (std::size_t i = 0; i < indices[depth].size(); ++i) + { + currentCombination[depth] = indices[depth][i]; + generateCombinations(indices, currentCombination, depth + 1, result); + } +} + +/** + * This function initializes the necessary data structures and calls the recursive + * `generateCombinations` function to generate and return all possible combinations + * where one element is taken from each vector in the input `indices`. + * + * @tparam VectorDataType The type of elements stored in the input vectors. + * @param indices A vector of vectors from which combinations are generated. + * @return A vector containing all possible combinations generated from the input `indices`. + */ +template +[[nodiscard]] inline std::vector> +generateAllCombinations(const std::vector>& indices) +{ + std::vector> result; // Vector to store all combinations + + if (indices.empty()) + { + return result; // Handle empty input + } + + std::vector currentCombination(indices.size()); + generateCombinations(indices, currentCombination, 0, result); + + return result; +} + } // namespace fiction #endif // FICTION_MATH_UTILS_HPP From 4eb4a5f7e655dee2cb040e0b488a75a9d663cf34 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 9 Aug 2024 07:25:30 +0000 Subject: [PATCH 44/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 65 ++++++++++++++----- 1 file changed, 49 insertions(+), 16 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index d45b1f5cd..542701f49 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -4178,21 +4178,6 @@ Parameter ``ps``: Parameter ``st``: Statistics related to the displacement robustness computation.)doc"; -static const char *__doc_fiction_detail_displacement_robustness_domain_impl_generate_all_possible_combinations_of_displacements = -R"doc(This is a helper function, which recursively generates combinations of -SiDB displacements for all SiDBs based on the provided vector of -displacement vectors. - -Parameter ``result``: - The vector to store the generated combinations. The first element - describes the SiDBs of the first displaced layout. - -Parameter ``current_combination``: - The current combination being constructed. - -Parameter ``cell_index``: - The current cell_index in the vector of displacement vectors.)doc"; - static const char *__doc_fiction_detail_displacement_robustness_domain_impl_generate_valid_displaced_sidb_layouts = R"doc(This function generates all SiDB layouts with displacements based on the original layout. It filters out layouts where two or more SiDBs @@ -9854,6 +9839,44 @@ static const char *__doc_fiction_gate_level_layout_value = R"doc()doc"; static const char *__doc_fiction_gate_level_layout_visited = R"doc()doc"; +static const char *__doc_fiction_generateAllCombinations = +R"doc(This function initializes the necessary data structures and calls the +recursive `generateCombinations` function to generate and return all +possible combinations where one element is taken from each vector in +the input `indices`. + +Template parameter ``VectorDataType``: + The type of elements stored in the input vectors. + +Parameter ``indices``: + A vector of vectors from which combinations are generated. + +Returns: + A vector containing all possible combinations generated from the + input `indices`.)doc"; + +static const char *__doc_fiction_generateCombinations = +R"doc(This function traverses through each vector in the `indices` and +builds combinations by taking one element from each vector. The +generated combinations are stored in the `result` vector. + +Template parameter ``VectorDataType``: + The type of elements stored in the input vectors. + +Parameter ``indices``: + A vector of vectors from which combinations are generated. + +Parameter ``currentCombination``: + A vector that holds the current combination being generated. + +Parameter ``depth``: + The current recursion depth, which corresponds to the index of the + vector in `indices`. + +Parameter ``result``: + A reference to a vector where the generated combinations are + stored.)doc"; + static const char *__doc_fiction_generate_edge_intersection_graph = R"doc(Creates an edge intersection graph of all paths that satisfy a given list of routing objectives. That is, this function generates an @@ -12821,7 +12844,17 @@ Parameter ``other``: Other parameter point to compare with. Returns: - `true` if the parameter points are equal.)doc"; + `true` if the parameter points are equal. + +Equality operator. Checks if this parameter point is equal to another +point within a specified tolerance. The tolerance is defined by +`physical_constants::POP_STABILITY_ERR`. + +Parameter ``other``: + Other parameter point to compare with. + +Returns: + `true` iff the parameter points are equal.)doc"; static const char *__doc_fiction_parameter_point_operator_ne = R"doc(Inequality operator. From 6c3699a55e99d17fa8040fc13e6a421f13ac1924 Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 09:30:43 +0200 Subject: [PATCH 45/95] :arrow_up: use submodule versions from main. --- libs/mockturtle | 2 +- libs/pybind11 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/mockturtle b/libs/mockturtle index a53457382..924c277bc 160000 --- a/libs/mockturtle +++ b/libs/mockturtle @@ -1 +1 @@ -Subproject commit a53457382e0d3c6658758466aae0222f61827092 +Subproject commit 924c277bc01900c9dc6d56fb6f2f4d100cab0806 diff --git a/libs/pybind11 b/libs/pybind11 index 8e7307f06..916778df4 160000 --- a/libs/pybind11 +++ b/libs/pybind11 @@ -1 +1 @@ -Subproject commit 8e7307f0699726c29f5bdc2c177dd55b6b330061 +Subproject commit 916778df48dc1c05b359ac74303ed18e5104799b From aeeed65af6bca8d386fbe4e42d25baf21ab04308 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 07:31:01 +0000 Subject: [PATCH 46/95] =?UTF-8?q?=F0=9F=8E=A8=20Incorporated=20pre-commit?= =?UTF-8?q?=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/cmd/simulation/opdom.hpp | 14 +++++++------- .../operational_domain_bestagon.cpp | 3 +-- .../operational_domain_siqad.cpp | 7 +++---- .../simulation/sidb/operational_domain.hpp | 16 +++++++++------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/cli/cmd/simulation/opdom.hpp b/cli/cmd/simulation/opdom.hpp index 78e000d41..22969bc04 100644 --- a/cli/cmd/simulation/opdom.hpp +++ b/cli/cmd/simulation/opdom.hpp @@ -101,13 +101,13 @@ class opdom_command : public command } // check for valid x and y parameter bounds - for (const auto &dim : params.sweep_dimensions) - if (dim.min >= dim.max) - { - env->out() << "[e] min must be smaller than max" << std::endl; - reset_params(); - return; - } + for (const auto& dim : params.sweep_dimensions) + if (dim.min >= dim.max) + { + env->out() << "[e] min must be smaller than max" << std::endl; + reset_params(); + return; + } // make sure that at most one algorithm is selected const std::array algorithm_selections = {is_set("random_sampling"), is_set("flood_fill"), diff --git a/experiments/operational_domain/operational_domain_bestagon.cpp b/experiments/operational_domain/operational_domain_bestagon.cpp index 45fa03465..e4e8fa173 100644 --- a/experiments/operational_domain/operational_domain_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_bestagon.cpp @@ -61,8 +61,7 @@ int main() // NOLINT operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, - {sweep_parameter::LAMBDA_TF}}; + op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; op_domain_params.sweep_dimensions[0].min = 1.0; op_domain_params.sweep_dimensions[0].max = 10.0; op_domain_params.sweep_dimensions[0].step = 0.05; diff --git a/experiments/operational_domain/operational_domain_siqad.cpp b/experiments/operational_domain/operational_domain_siqad.cpp index e87967c80..f90b9779e 100644 --- a/experiments/operational_domain/operational_domain_siqad.cpp +++ b/experiments/operational_domain/operational_domain_siqad.cpp @@ -61,8 +61,7 @@ int main() // NOLINT operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, - {sweep_parameter::LAMBDA_TF}}; + op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; op_domain_params.sweep_dimensions[0].min = 1.0; op_domain_params.sweep_dimensions[0].max = 10.0; op_domain_params.sweep_dimensions[0].step = 0.05; @@ -195,7 +194,7 @@ int main() // NOLINT } opdomain_exp.save(); - //opdomain_exp.table(); + // opdomain_exp.table(); } // log the total number of samples and simulator calls @@ -218,7 +217,7 @@ int main() // NOLINT ); opdomain_exp.save(); - //opdomain_exp.table(); + // opdomain_exp.table(); return EXIT_SUCCESS; } diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index da3d0b55c..7a03de9e2 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -77,9 +77,11 @@ struct parameter_point * @param other Other parameter point to compare with. * @return `true` iff the parameter points are equal. */ - [[nodiscard]] bool operator==(const parameter_point& other) const noexcept { + [[nodiscard]] bool operator==(const parameter_point& other) const noexcept + { // Check if sizes are equal - if (parameters.size() != other.parameters.size()) { + if (parameters.size() != other.parameters.size()) + { return false; } @@ -87,8 +89,10 @@ struct parameter_point constexpr auto tolerance = physical_constants::POP_STABILITY_ERR; // Compare each element with tolerance - for (std::size_t i = 0; i < parameters.size(); ++i) { - if (std::abs(parameters[i] - other.parameters[i]) > tolerance) { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + if (std::abs(parameters[i] - other.parameters[i]) > tolerance) + { return false; } } @@ -686,9 +690,7 @@ class operational_domain_impl const auto all_indice_combinations = generateAllCombinations(indices); std::for_each(all_indice_combinations.cbegin(), all_indice_combinations.cend(), - [this, &lyt](const auto id) { - is_step_point_suitable(lyt, step_point{id}); - }); + [this, &lyt](const auto id) { is_step_point_suitable(lyt, step_point{id}); }); sidb_simulation_parameters simulation_parameters = params.simulation_parameters; From d807dc8dcf384bdd920a58d7e62bdb83590b840c Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 10:24:51 +0200 Subject: [PATCH 47/95] :art: small fix of experiments after merge. --- .../operational_domain/operational_domain_3d_bestagon.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/experiments/operational_domain/operational_domain_3d_bestagon.cpp b/experiments/operational_domain/operational_domain_3d_bestagon.cpp index 6d36f78af..bcc8bc612 100644 --- a/experiments/operational_domain/operational_domain_3d_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_3d_bestagon.cpp @@ -57,9 +57,9 @@ int main() // NOLINT operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; op_domain_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.sweep_dimensions = {{operational_domain::sweep_parameter::EPSILON_R}, - {operational_domain::sweep_parameter::LAMBDA_TF}, - {operational_domain::sweep_parameter::MU_MINUS}}; + op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}, + {sweep_parameter::MU_MINUS}}; op_domain_params.sweep_dimensions[0].min = 1.0; op_domain_params.sweep_dimensions[0].max = 10.0; op_domain_params.sweep_dimensions[0].step = 0.05; From dceca212798652779feeea405866e7dd2a9352fa Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 13:34:31 +0200 Subject: [PATCH 48/95] :snake: adjust python binding after merge --- .../simulation/sidb/operational_domain.hpp | 1 + ...t_determine_physically_valid_parameters.py | 12 ++-- .../sidb/test_operational_domain.py | 22 ++---- .../simulation/sidb/operational_domain.hpp | 71 ++++++++++++------- 4 files changed, 60 insertions(+), 46 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp index e1028da4c..19f3999e3 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp @@ -85,6 +85,7 @@ inline void operational_domain(pybind11::module& m) // add docu py::class_(m, "operational_domain_value_range") .def(py::init<>()) + .def(py::init(), "dimension"_a, "min"_a, "max"_a, "step"_a) .def_readwrite("dimension", &fiction::operational_domain_value_range::dimension) .def_readwrite("min", &fiction::operational_domain_value_range::min) .def_readwrite("max", &fiction::operational_domain_value_range::max) diff --git a/bindings/pyfiction/test/algorithms/simulation/sidb/test_determine_physically_valid_parameters.py b/bindings/pyfiction/test/algorithms/simulation/sidb/test_determine_physically_valid_parameters.py index dff892a16..327bb86a6 100644 --- a/bindings/pyfiction/test/algorithms/simulation/sidb/test_determine_physically_valid_parameters.py +++ b/bindings/pyfiction/test/algorithms/simulation/sidb/test_determine_physically_valid_parameters.py @@ -12,16 +12,16 @@ def test_one_DB_100_lattice(self): valid_parameters = determine_physically_valid_parameters(cds) - self.assertEqual(valid_parameters.get_excited_state_number_for_parameter(parameter_point(5, 5)), + self.assertEqual(valid_parameters.get_excited_state_number_for_parameter(parameter_point([5, 5])), 0) self.assertEqual( - valid_parameters.get_excited_state_number_for_parameter(parameter_point(5.1, 5.1)), + valid_parameters.get_excited_state_number_for_parameter(parameter_point([5.1, 5.1])), 0) # Testing for an invalid parameter point that raises an exception with self.assertRaises(ValueError): - valid_parameters.get_excited_state_number_for_parameter(parameter_point(15, 15)) + valid_parameters.get_excited_state_number_for_parameter(parameter_point([15, 15])) def test_one_DB_111_lattice(self): @@ -31,16 +31,16 @@ def test_one_DB_111_lattice(self): valid_parameters = determine_physically_valid_parameters(cds) - self.assertEqual(valid_parameters.get_excited_state_number_for_parameter(parameter_point(5, 5)), + self.assertEqual(valid_parameters.get_excited_state_number_for_parameter(parameter_point([5, 5])), 0) self.assertEqual( - valid_parameters.get_excited_state_number_for_parameter(parameter_point(5.1, 5.1)), + valid_parameters.get_excited_state_number_for_parameter(parameter_point([5.1, 5.1])), 0) # Testing for an invalid parameter point that raises an exception with self.assertRaises(ValueError): - valid_parameters.get_excited_state_number_for_parameter(parameter_point(15, 15)) + valid_parameters.get_excited_state_number_for_parameter(parameter_point([15, 15])) if __name__ == '__main__': diff --git a/bindings/pyfiction/test/algorithms/simulation/sidb/test_operational_domain.py b/bindings/pyfiction/test/algorithms/simulation/sidb/test_operational_domain.py index d9a35d9e8..acc34fb21 100644 --- a/bindings/pyfiction/test/algorithms/simulation/sidb/test_operational_domain.py +++ b/bindings/pyfiction/test/algorithms/simulation/sidb/test_operational_domain.py @@ -13,14 +13,9 @@ def test_xor_gate_100_lattice(self): params = operational_domain_params() params.sim_engine = sidb_simulation_engine.QUICKEXACT params.simulation_parameters.base = 2 - params.x_dimension = sweep_parameter.EPSILON_R - params.y_dimension = sweep_parameter.LAMBDA_TF - params.x_min = 5.55 - params.x_max = 5.65 - params.y_min = 4.95 - params.y_max = 5.05 - params.x_step = 0.01 - params.y_step = 0.01 + + params.sweep_dimensions = [operational_domain_value_range(sweep_parameter.EPSILON_R, 5.55, 5.65, 0.01), + operational_domain_value_range(sweep_parameter.LAMBDA_TF, 4.95, 5.05, 0.01)] stats_grid = operational_domain_stats() opdomain = operational_domain_grid_search(lyt, [create_xor_tt()], params, stats_grid) @@ -45,14 +40,9 @@ def test_and_gate_111_lattice(self): params.sim_engine = sidb_simulation_engine.QUICKEXACT params.simulation_parameters.base = 2 - params.x_dimension = sweep_parameter.EPSILON_R - params.y_dimension = sweep_parameter.LAMBDA_TF - params.x_min = 5.60 - params.x_max = 5.64 - params.x_step = 0.01 - params.y_min = 5.00 - params.y_max = 5.01 - params.y_step = 0.01 + + params.sweep_dimensions = [operational_domain_value_range(sweep_parameter.EPSILON_R, 5.60, 5.64, 0.01), + operational_domain_value_range(sweep_parameter.LAMBDA_TF, 5.00, 5.01, 0.01)]; stats_grid = operational_domain_stats() opdomain = operational_domain_grid_search(lyt, [create_and_tt()], params, stats_grid) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 7a03de9e2..e156ce524 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -425,16 +425,10 @@ class operational_domain_impl } } } - /** - * Performs a grid search over the specified parameter ranges with the specified step sizes. The grid search always - * has quadratic complexity. The operational status is computed for each parameter combination. - * - * @return The operational domain of the layout. - */ - [[nodiscard]] operational_domain grid_search() noexcept - { - mockturtle::stopwatch stop{stats.time_total}; + // todo add docstring + auto determine_step_points_grid() noexcept + { // generate all possible step point combinations via the Cartesian product of all dimensions std::vector all_step_points{step_point{}}; for (const auto& dimension : indices) @@ -453,6 +447,19 @@ class operational_domain_impl } all_step_points = expanded_products; } + return all_step_points; + } + /** + * Performs a grid search over the specified parameter ranges with the specified step sizes. The grid search always + * has quadratic complexity. The operational status is computed for each parameter combination. + * + * @return The operational domain of the layout. + */ + [[nodiscard]] operational_domain grid_search() noexcept + { + mockturtle::stopwatch stop{stats.time_total}; + + auto all_step_points = determine_step_points_grid(); // shuffle the step points to simulate in random order. This helps with load-balancing since // operational/non-operational points are usually clustered. However, non-operational points can be simulated @@ -684,13 +691,10 @@ class operational_domain_impl mockturtle::stopwatch stop{stats.time_total}; - // TODO needs to be fixed - // step points are analyzed sequentially because the CDS is updated for each step point, so parallelizing may - // result in unexpected behavior. - const auto all_indice_combinations = generateAllCombinations(indices); + const auto all_step_points = determine_step_points_grid(); - std::for_each(all_indice_combinations.cbegin(), all_indice_combinations.cend(), - [this, &lyt](const auto id) { is_step_point_suitable(lyt, step_point{id}); }); + std::for_each(all_step_points.cbegin(), all_step_points.cend(), + [this, &lyt](const auto& sp) { is_step_point_suitable(lyt, sp); }); sidb_simulation_parameters simulation_parameters = params.simulation_parameters; @@ -805,7 +809,8 @@ class operational_domain_impl /** * Number of available hardware threads. */ - const std::size_t num_threads{std::thread::hardware_concurrency()}; + // TODO fix issue with multithreading + const std::size_t num_threads{1}; /** * A step point represents a point in the x and y dimension from 0 to the maximum number of steps. A step point does * not hold the actual parameter values, but the step values in the x and y dimension, respectively. @@ -980,41 +985,59 @@ class operational_domain_impl */ operational_status is_step_point_operational(const step_point& sp) noexcept { - // if the point has already been sampled, return the stored operational status - if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) + // todo analyse thread issue + std::mutex mutex_to_protect_member_variables{}; // Lock the mutex + { - return *op_value; + const std::lock_guard lock{mutex_to_protect_member_variables}; + // if the point has already been sampled, return the stored operational status + if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) + { + return *op_value; + } } // fetch the x and y dimension values const auto param_point = to_parameter_point(sp); - const auto operational = [this, ¶m_point]() + const auto operational = [this, ¶m_point, &mutex_to_protect_member_variables]() { + const std::lock_guard lock{mutex_to_protect_member_variables}; + op_domain.operational_values[param_point] = operational_status::OPERATIONAL; return operational_status::OPERATIONAL; }; - const auto non_operational = [this, ¶m_point]() + const auto non_operational = [this, ¶m_point, &mutex_to_protect_member_variables]() { + const std::lock_guard lock{mutex_to_protect_member_variables}; + op_domain.operational_values[param_point] = operational_status::NON_OPERATIONAL; return operational_status::NON_OPERATIONAL; }; - // increment the number of evaluated parameter combinations - ++num_evaluated_parameter_combinations; + { + const std::lock_guard lock{mutex_to_protect_member_variables}; + // increment the number of evaluated parameter combinations + ++num_evaluated_parameter_combinations; + } sidb_simulation_parameters sim_params = params.simulation_parameters; + for (auto d = 0u; d < num_dimensions; ++d) { + const std::lock_guard lock{mutex_to_protect_member_variables}; set_dimension_value(sim_params, values[d][sp.step_values[d]], d); } const auto& [status, sim_calls] = is_operational(layout, truth_table, is_operational_params{sim_params, params.sim_engine}); - num_simulator_invocations += sim_calls; + { + const std::lock_guard lock{mutex_to_protect_member_variables}; + num_simulator_invocations += sim_calls; + } if (status == operational_status::NON_OPERATIONAL) { From 48eeb086f612f467324da889185858203b9d0811 Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 14:11:18 +0200 Subject: [PATCH 49/95] :bug: use mutex to avoid race conditions. --- .../simulation/sidb/operational_domain.hpp | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index e156ce524..7457e729d 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -31,11 +31,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -810,7 +812,7 @@ class operational_domain_impl * Number of available hardware threads. */ // TODO fix issue with multithreading - const std::size_t num_threads{1}; + const std::size_t num_threads{std::thread::hardware_concurrency()}; /** * A step point represents a point in the x and y dimension from 0 to the maximum number of steps. A step point does * not hold the actual parameter values, but the step values in the x and y dimension, respectively. @@ -985,42 +987,34 @@ class operational_domain_impl */ operational_status is_step_point_operational(const step_point& sp) noexcept { - // todo analyse thread issue - std::mutex mutex_to_protect_member_variables{}; // Lock the mutex + static std::mutex mutex_to_protect_member_variables; { const std::lock_guard lock{mutex_to_protect_member_variables}; - // if the point has already been sampled, return the stored operational status if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) { return *op_value; } } - // fetch the x and y dimension values const auto param_point = to_parameter_point(sp); - const auto operational = [this, ¶m_point, &mutex_to_protect_member_variables]() + const auto operational = [this, ¶m_point]() { - const std::lock_guard lock{mutex_to_protect_member_variables}; - + const std::lock_guard lock(mutex_to_protect_member_variables); op_domain.operational_values[param_point] = operational_status::OPERATIONAL; - return operational_status::OPERATIONAL; }; - const auto non_operational = [this, ¶m_point, &mutex_to_protect_member_variables]() + const auto non_operational = [this, ¶m_point]() { - const std::lock_guard lock{mutex_to_protect_member_variables}; - + const std::lock_guard lock(mutex_to_protect_member_variables); op_domain.operational_values[param_point] = operational_status::NON_OPERATIONAL; - return operational_status::NON_OPERATIONAL; }; { - const std::lock_guard lock{mutex_to_protect_member_variables}; - // increment the number of evaluated parameter combinations + const std::lock_guard lock(mutex_to_protect_member_variables); ++num_evaluated_parameter_combinations; } @@ -1028,14 +1022,14 @@ class operational_domain_impl for (auto d = 0u; d < num_dimensions; ++d) { - const std::lock_guard lock{mutex_to_protect_member_variables}; - set_dimension_value(sim_params, values[d][sp.step_values[d]], d); + set_dimension_value(sim_params, values[d][sp.step_values[d]], d); // lock not needed here } const auto& [status, sim_calls] = is_operational(layout, truth_table, is_operational_params{sim_params, params.sim_engine}); + { - const std::lock_guard lock{mutex_to_protect_member_variables}; + const std::lock_guard lock(mutex_to_protect_member_variables); num_simulator_invocations += sim_calls; } @@ -1044,7 +1038,6 @@ class operational_domain_impl return non_operational(); } - // if we made it here, the layout is operational return operational(); } /** From 0344a19900723ef21a7bae91d8aeb85e1977e7ea Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 9 Aug 2024 12:53:52 +0000 Subject: [PATCH 50/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 542701f49..1261cf5f0 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -5836,6 +5836,8 @@ Parameter ``samples``: Returns: The (partial) operational domain of the layout.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_determine_step_points_grid = R"doc()doc"; + static const char *__doc_fiction_detail_operational_domain_impl_find_operational_contour_step_point = R"doc(Finds a boundary starting point for the contour tracing algorithm. This function starts at the given starting point and moves towards the From 1dd55f3fe40083525bcae730f095257f20c3e85f Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 14:59:46 +0200 Subject: [PATCH 51/95] :thread: use multithreading for grid_search_for_physically_valid_parameters --- .../sidb/displacement_robustness_domain.hpp | 2 +- .../simulation/sidb/operational_domain.hpp | 97 ++++++++++++------- include/fiction/utils/math_utils.hpp | 71 +++++--------- 3 files changed, 88 insertions(+), 82 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp index 92aaf8e92..60ad5ff4a 100644 --- a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp @@ -492,7 +492,7 @@ class displacement_robustness_domain_impl */ [[nodiscard]] std::vector generate_valid_displaced_sidb_layouts() noexcept { - auto all_possible_sidb_displacement = generateAllCombinations(all_possible_sidb_displacements); + auto all_possible_sidb_displacement = compute_cartesian_combinations(all_possible_sidb_displacements); std::shuffle(all_possible_sidb_displacement.begin(), all_possible_sidb_displacement.end(), generator); diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 7457e729d..580390e30 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -428,29 +427,6 @@ class operational_domain_impl } } - // todo add docstring - auto determine_step_points_grid() noexcept - { - // generate all possible step point combinations via the Cartesian product of all dimensions - std::vector all_step_points{step_point{}}; - for (const auto& dimension : indices) - { - std::vector expanded_products{}; - expanded_products.reserve(all_step_points.size() * dimension.size()); - - for (const auto& product : all_step_points) - { - for (const auto& element : dimension) - { - step_point new_product = product; - new_product.step_values.push_back(element); - expanded_products.push_back(new_product); - } - } - all_step_points = expanded_products; - } - return all_step_points; - } /** * Performs a grid search over the specified parameter ranges with the specified step sizes. The grid search always * has quadratic complexity. The operational status is computed for each parameter combination. @@ -461,7 +437,14 @@ class operational_domain_impl { mockturtle::stopwatch stop{stats.time_total}; - auto all_step_points = determine_step_points_grid(); + auto all_index_combination = compute_cartesian_combinations(indices); + std::vector all_step_points{}; + all_step_points.reserve(all_index_combination.size()); + + for (const auto& comb : all_index_combination) + { + all_step_points.push_back(step_point{comb}); + } // shuffle the step points to simulate in random order. This helps with load-balancing since // operational/non-operational points are usually clustered. However, non-operational points can be simulated @@ -693,10 +676,44 @@ class operational_domain_impl mockturtle::stopwatch stop{stats.time_total}; - const auto all_step_points = determine_step_points_grid(); + const auto all_step_points = compute_cartesian_combinations(indices); + + // calculate the size of each slice + const auto slice_size = (all_step_points.size() + num_threads - 1) / num_threads; + + std::vector threads{}; + threads.reserve(num_threads); + + // launch threads, each with its own slice of random step points + for (auto i = 0ul; i < num_threads; ++i) + { + const auto start = i * slice_size; + const auto end = std::min(start + slice_size, all_step_points.size()); - std::for_each(all_step_points.cbegin(), all_step_points.cend(), - [this, &lyt](const auto& sp) { is_step_point_suitable(lyt, sp); }); + if (start >= end) + { + break; // no more work to distribute + } + + threads.emplace_back( + [this, &lyt, start, end, &all_step_points] + { + for (auto it = all_step_points.cbegin() + static_cast(start); + it != all_step_points.cbegin() + static_cast(end); ++it) + { + is_step_point_suitable(lyt, step_point{*it}); + } + }); + } + + // wait for all threads to complete + for (auto& thread : threads) + { + if (thread.joinable()) + { + thread.join(); + } + } sidb_simulation_parameters simulation_parameters = params.simulation_parameters; @@ -811,7 +828,6 @@ class operational_domain_impl /** * Number of available hardware threads. */ - // TODO fix issue with multithreading const std::size_t num_threads{std::thread::hardware_concurrency()}; /** * A step point represents a point in the x and y dimension from 0 to the maximum number of steps. A step point does @@ -1048,13 +1064,17 @@ class operational_domain_impl * @param sp Step point to be investigated. * @return The operational status of the layout under the given simulation parameters. */ - // TODO needs some rewrite - operational_status is_step_point_suitable(Lyt& lyt, const step_point& sp) noexcept + operational_status is_step_point_suitable(Lyt lyt, const step_point& sp) noexcept { - // if the point has already been sampled, return the stored operational status - if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) + static std::mutex mutex_to_protect_member_variables; + { - return *op_value; + const std::lock_guard lock{mutex_to_protect_member_variables}; + // if the point has already been sampled, return the stored operational status + if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) + { + return *op_value; + } } // fetch the x and y dimension values @@ -1062,6 +1082,7 @@ class operational_domain_impl const auto operational = [this, ¶m_point]() { + const std::lock_guard lock(mutex_to_protect_member_variables); op_domain.operational_values[param_point] = operational_status::OPERATIONAL; return operational_status::OPERATIONAL; @@ -1069,13 +1090,17 @@ class operational_domain_impl const auto non_operational = [this, ¶m_point]() { + const std::lock_guard lock(mutex_to_protect_member_variables); op_domain.operational_values[param_point] = operational_status::NON_OPERATIONAL; return operational_status::NON_OPERATIONAL; }; - // increment the number of evaluated parameter combinations - ++num_evaluated_parameter_combinations; + { + const std::lock_guard lock(mutex_to_protect_member_variables); + // increment the number of evaluated parameter combinations + ++num_evaluated_parameter_combinations; + } sidb_simulation_parameters sim_params = params.simulation_parameters; diff --git a/include/fiction/utils/math_utils.hpp b/include/fiction/utils/math_utils.hpp index 098afca75..3759196fe 100644 --- a/include/fiction/utils/math_utils.hpp +++ b/include/fiction/utils/math_utils.hpp @@ -117,61 +117,42 @@ determine_all_combinations_of_distributing_k_entities_on_n_positions(const std:: return all_combinations; } - /** - * This function traverses through each vector in the `indices` and builds combinations by - * taking one element from each vector. The generated combinations are stored in the `result` vector. + * This function computes the Cartesian product of a list of vectors. Each vector in the input list + * represents a dimension, and the function produces all possible combinations where each combination + * consists of one element from each dimension vector. * - * @tparam VectorDataType The type of elements stored in the input vectors. - * @param indices A vector of vectors from which combinations are generated. - * @param currentCombination A vector that holds the current combination being generated. - * @param depth The current recursion depth, which corresponds to the index of the vector in `indices`. - * @param result A reference to a vector where the generated combinations are stored. - */ -template -void generateCombinations(const std::vector>& indices, - std::vector& currentCombination, const std::size_t depth, - std::vector>& result) -{ - if (depth == indices.size()) - { - // Store the current combination in the result vector - result.push_back(currentCombination); - return; - } - - // Iterate over each element in the current vector - for (std::size_t i = 0; i < indices[depth].size(); ++i) - { - currentCombination[depth] = indices[depth][i]; - generateCombinations(indices, currentCombination, depth + 1, result); - } -} - -/** - * This function initializes the necessary data structures and calls the recursive - * `generateCombinations` function to generate and return all possible combinations - * where one element is taken from each vector in the input `indices`. - * - * @tparam VectorDataType The type of elements stored in the input vectors. - * @param indices A vector of vectors from which combinations are generated. - * @return A vector containing all possible combinations generated from the input `indices`. + * @tparam VectorDataType The type of elements in the vectors. + * @param indices A vector of vectors, where each inner vector represents a dimension. The function + * generates combinations using one element from each dimension vector. + * @return A vector of vectors, where each inner vector represents a combination of elements, + * one from each dimension. The total number of combinations is the product of the sizes + * of the input vectors. */ template [[nodiscard]] inline std::vector> -generateAllCombinations(const std::vector>& indices) +compute_cartesian_combinations(const std::vector>& indices) noexcept { - std::vector> result; // Vector to store all combinations + std::vector> all_combinations{{}}; - if (indices.empty()) + for (const auto& dimension : indices) { - return result; // Handle empty input - } + std::vector> expanded_products{}; + expanded_products.reserve(all_combinations.size() * dimension.size()); - std::vector currentCombination(indices.size()); - generateCombinations(indices, currentCombination, 0, result); + for (const auto& product : all_combinations) + { + for (const auto& element : dimension) + { + std::vector new_product = product; + new_product.push_back(element); + expanded_products.push_back(new_product); + } + } + all_combinations = expanded_products; + } - return result; + return all_combinations; // Return the final list of combinations } } // namespace fiction From ab279a1af49d900533059bd0b99f8ac9316daf07 Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 15:16:24 +0200 Subject: [PATCH 52/95] :memo: fix docu. --- .../simulation/sidb/operational_domain.hpp | 22 ++++++++++++------- docs/algorithms/sidb_simulation.rst | 2 ++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp index 19f3999e3..fd7cacdea 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp @@ -60,8 +60,8 @@ inline void operational_domain(pybind11::module& m) ; py::class_(m, "parameter_point", DOC(fiction_parameter_point)) - .def(py::init<>()) - .def(py::init>(), "values"_a) + .def(py::init<>(), DOC(fiction_parameter_point_parameter_point)) + .def(py::init>(), "values"_a, DOC(fiction_parameter_point_parameter_point_2)) .def_readwrite("parameters", &fiction::parameter_point::parameters, DOC(fiction_parameter_point)) .def(py::self == py::self, "other"_a, DOC(fiction_parameter_point_operator_eq)) @@ -76,20 +76,26 @@ inline void operational_domain(pybind11::module& m) m, "operational_domain", DOC(fiction_operational_domain)) .def(py::init<>()) .def_readwrite("dimensions", - &fiction::operational_domain::dimensions) + &fiction::operational_domain::dimensions, + DOC()) .def_readwrite( "operational_values", &fiction::operational_domain::operational_values, DOC(fiction_operational_domain_operational_values)); // add docu - py::class_(m, "operational_domain_value_range") + py::class_(m, "operational_domain_value_range", + DOC(fiction_operational_domain_value_range)) .def(py::init<>()) .def(py::init(), "dimension"_a, "min"_a, "max"_a, "step"_a) - .def_readwrite("dimension", &fiction::operational_domain_value_range::dimension) - .def_readwrite("min", &fiction::operational_domain_value_range::min) - .def_readwrite("max", &fiction::operational_domain_value_range::max) - .def_readwrite("step", &fiction::operational_domain_value_range::step); + .def_readwrite("dimension", &fiction::operational_domain_value_range::dimension, + DOC(fiction_operational_domain_value_range_dimension)) + .def_readwrite("min", &fiction::operational_domain_value_range::min, + DOC(fiction_operational_domain_value_range_dimension)) + .def_readwrite("max", &fiction::operational_domain_value_range::max, + DOC(fiction_operational_domain_value_range_max)) + .def_readwrite("step", &fiction::operational_domain_value_range::step, + DOC(fiction_operational_domain_value_range_step)); py::class_(m, "operational_domain_params", DOC(fiction_operational_domain_params)) diff --git a/docs/algorithms/sidb_simulation.rst b/docs/algorithms/sidb_simulation.rst index 6b6170c1f..95c6a399a 100644 --- a/docs/algorithms/sidb_simulation.rst +++ b/docs/algorithms/sidb_simulation.rst @@ -264,6 +264,8 @@ Operational Domain Computation :members: .. autoclass:: mnt.pyfiction.operational_domain :members: + .. autoclass:: mnt.pyfiction.operational_domain_value_range + :members: .. autoclass:: mnt.pyfiction.operational_domain_params :members: .. autoclass:: mnt.pyfiction.operational_domain_stats From 42c9564eabf8c28b8ec54a85f16f005432d0f09e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 9 Aug 2024 13:17:15 +0000 Subject: [PATCH 53/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 59 ++++++------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 1261cf5f0..fe79908d3 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -2340,6 +2340,25 @@ Parameter ``n``: Returns: Columnar clocking scheme.)doc"; +static const char *__doc_fiction_compute_cartesian_combinations = +R"doc(This function computes the Cartesian product of a list of vectors. +Each vector in the input list represents a dimension, and the function +produces all possible combinations where each combination consists of +one element from each dimension vector. + +Template parameter ``VectorDataType``: + The type of elements in the vectors. + +Parameter ``indices``: + A vector of vectors, where each inner vector represents a + dimension. The function generates combinations using one element + from each dimension vector. + +Returns: + A vector of vectors, where each inner vector represents a + combination of elements, one from each dimension. The total number + of combinations is the product of the sizes of the input vectors.)doc"; + static const char *__doc_fiction_convert_array = R"doc(Converts an array of size `N` and type `T` to an array of size `N` and type `ElementType` by applying `static_cast` at compile time. @@ -5836,8 +5855,6 @@ Parameter ``samples``: Returns: The (partial) operational domain of the layout.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_determine_step_points_grid = R"doc()doc"; - static const char *__doc_fiction_detail_operational_domain_impl_find_operational_contour_step_point = R"doc(Finds a boundary starting point for the contour tracing algorithm. This function starts at the given starting point and moves towards the @@ -9841,44 +9858,6 @@ static const char *__doc_fiction_gate_level_layout_value = R"doc()doc"; static const char *__doc_fiction_gate_level_layout_visited = R"doc()doc"; -static const char *__doc_fiction_generateAllCombinations = -R"doc(This function initializes the necessary data structures and calls the -recursive `generateCombinations` function to generate and return all -possible combinations where one element is taken from each vector in -the input `indices`. - -Template parameter ``VectorDataType``: - The type of elements stored in the input vectors. - -Parameter ``indices``: - A vector of vectors from which combinations are generated. - -Returns: - A vector containing all possible combinations generated from the - input `indices`.)doc"; - -static const char *__doc_fiction_generateCombinations = -R"doc(This function traverses through each vector in the `indices` and -builds combinations by taking one element from each vector. The -generated combinations are stored in the `result` vector. - -Template parameter ``VectorDataType``: - The type of elements stored in the input vectors. - -Parameter ``indices``: - A vector of vectors from which combinations are generated. - -Parameter ``currentCombination``: - A vector that holds the current combination being generated. - -Parameter ``depth``: - The current recursion depth, which corresponds to the index of the - vector in `indices`. - -Parameter ``result``: - A reference to a vector where the generated combinations are - stored.)doc"; - static const char *__doc_fiction_generate_edge_intersection_graph = R"doc(Creates an edge intersection graph of all paths that satisfy a given list of routing objectives. That is, this function generates an From 32fd1c77252575f166ac89eb157b8035535de8cf Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 15:22:22 +0200 Subject: [PATCH 54/95] :memo: small fix. --- .../simulation/sidb/operational_domain.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 580390e30..f1fcb680f 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -196,7 +196,7 @@ struct operational_domain for (std::size_t i = 0; i < pp.parameters.size(); ++i) { ss << pp.parameters[i]; - // Add a separator (e.g., comma) between elements + if (i != pp.parameters.size() - 1) { ss << ", "; @@ -437,14 +437,13 @@ class operational_domain_impl { mockturtle::stopwatch stop{stats.time_total}; - auto all_index_combination = compute_cartesian_combinations(indices); - std::vector all_step_points{}; + const auto all_index_combination = compute_cartesian_combinations(indices); + + std::vector all_step_points; all_step_points.reserve(all_index_combination.size()); - for (const auto& comb : all_index_combination) - { - all_step_points.push_back(step_point{comb}); - } + std::transform(all_index_combination.begin(), all_index_combination.end(), std::back_inserter(all_step_points), + [](const auto& comb) { return step_point{comb}; }); // shuffle the step points to simulate in random order. This helps with load-balancing since // operational/non-operational points are usually clustered. However, non-operational points can be simulated From 5112815cf559172b273805783a17a865bd5d20c7 Mon Sep 17 00:00:00 2001 From: Drewniok Date: Fri, 9 Aug 2024 15:41:30 +0200 Subject: [PATCH 55/95] :memo: fix missing doc-label. --- .../pyfiction/algorithms/simulation/sidb/operational_domain.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp index fd7cacdea..e18088750 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp @@ -77,7 +77,7 @@ inline void operational_domain(pybind11::module& m) .def(py::init<>()) .def_readwrite("dimensions", &fiction::operational_domain::dimensions, - DOC()) + DOC(fiction_operational_domain_dimensions)) .def_readwrite( "operational_values", &fiction::operational_domain::operational_values, From 73fecfef75d2e589b07d7cf25b73f0b39a514655 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 9 Aug 2024 14:25:43 +0000 Subject: [PATCH 56/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 9086fa9f7..9894c46ec 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -4197,21 +4197,6 @@ Parameter ``ps``: Parameter ``st``: Statistics related to the displacement robustness computation.)doc"; -static const char *__doc_fiction_detail_displacement_robustness_domain_impl_generate_all_possible_combinations_of_displacements = -R"doc(This is a helper function, which recursively generates combinations of -SiDB displacements for all SiDBs based on the provided vector of -displacement vectors. - -Parameter ``result``: - The vector to store the generated combinations. The first element - describes the SiDBs of the first displaced layout. - -Parameter ``current_combination``: - The current combination being constructed. - -Parameter ``cell_index``: - The current cell_index in the vector of displacement vectors.)doc"; - static const char *__doc_fiction_detail_displacement_robustness_domain_impl_generate_valid_displaced_sidb_layouts = R"doc(This function generates all SiDB layouts with displacements based on the original layout. It filters out layouts where two or more SiDBs From fd429fe83e0b865758fc18d5c7e9fe458be6b96a Mon Sep 17 00:00:00 2001 From: Drewniok Date: Sun, 11 Aug 2024 18:12:33 +0200 Subject: [PATCH 57/95] :white_check_mark: unit test for math utils function. --- include/fiction/utils/math_utils.hpp | 5 + test/utils/math_utils.cpp | 146 +++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/include/fiction/utils/math_utils.hpp b/include/fiction/utils/math_utils.hpp index 3759196fe..56ef7327d 100644 --- a/include/fiction/utils/math_utils.hpp +++ b/include/fiction/utils/math_utils.hpp @@ -92,6 +92,11 @@ T integral_abs(const T n) noexcept [[nodiscard]] inline std::vector> determine_all_combinations_of_distributing_k_entities_on_n_positions(const std::size_t k, const std::size_t n) noexcept { + // Handle a special case + if (k > n) + { + return {}; + } std::vector> all_combinations{}; all_combinations.reserve(binomial_coefficient(n, k)); diff --git a/test/utils/math_utils.cpp b/test/utils/math_utils.cpp index b08dcf00e..99b243b66 100644 --- a/test/utils/math_utils.cpp +++ b/test/utils/math_utils.cpp @@ -112,3 +112,149 @@ TEST_CASE("Binomial Coefficient Tests") REQUIRE(result == 126410606437752); // C(50, 25) = 126,410,606,437,752 } } + +TEST_CASE("Test the computation of the cartesian combinations", "[compute_cartesian_combinations]") +{ + SECTION("Single dimension") + { + const std::vector> input{{1, 2, 3}}; + const std::vector> expected{{1}, {2}, {3}}; + + auto result = compute_cartesian_combinations(input); + + REQUIRE(result == expected); + } + + SECTION("Two dimensions") + { + const std::vector> input{{1, 2}, {3, 4}}; + const std::vector> expected{{1, 3}, {1, 4}, {2, 3}, {2, 4}}; + + auto result = compute_cartesian_combinations(input); + + REQUIRE(result == expected); + } + + SECTION("Three dimensions") + { + const std::vector> input{{1, 2}, {3, 4}, {5, 6}}; + const std::vector> expected{{1, 3, 5}, {1, 3, 6}, {1, 4, 5}, {1, 4, 6}, + {2, 3, 5}, {2, 3, 6}, {2, 4, 5}, {2, 4, 6}}; + + auto result = compute_cartesian_combinations(input); + + REQUIRE(result == expected); + } + + SECTION("Empty input") + { + const std::vector> input{}; + const std::vector> expected{{}}; + + auto result = compute_cartesian_combinations(input); + + REQUIRE(result == expected); + } + + SECTION("Empty dimension") + { + const std::vector> input{{1, 2}, {}}; + const std::vector> expected{}; + + auto result = compute_cartesian_combinations(input); + + REQUIRE(result == expected); + } + + SECTION("Mixed types") + { + const std::vector> input{{"a", "b"}, {"x", "y"}}; + const std::vector> expected{{"a", "x"}, {"a", "y"}, {"b", "x"}, {"b", "y"}}; + + auto result = compute_cartesian_combinations(input); + + REQUIRE(result == expected); + } +} + +TEST_CASE("Test the determination of all combinations of distributing k entities on n positions", + "[determine_all_combinations_of_distributing_k_entities_on_n_positions]") +{ + SECTION("k = 0, n = 0") + { + const std::size_t k = 0; + const std::size_t n = 0; + const std::vector> expected{{}}; + + auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); + + REQUIRE(result == expected); + } + + SECTION("k = 1, n = 1") + { + const std::size_t k = 1; + const std::size_t n = 1; + const std::vector> expected{{0}}; + + auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); + + REQUIRE(result == expected); + } + + SECTION("k = 2, n = 3") + { + const std::size_t k = 2; + const std::size_t n = 3; + const std::vector> expected{{0, 1}, {0, 2}, {1, 2}}; + + auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); + + REQUIRE(result == expected); + } + + SECTION("k = 3, n = 5") + { + const std::size_t k = 3; + const std::size_t n = 5; + const std::vector> expected{{0, 1, 2}, {0, 1, 3}, {0, 1, 4}, {0, 2, 3}, {0, 2, 4}, + {0, 3, 4}, {1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4}}; + + auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); + + REQUIRE(result == expected); + } + + SECTION("k = 0, n = 5") + { + const std::size_t k = 0; + const std::size_t n = 5; + const std::vector> expected{{}}; + + auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); + + REQUIRE(result == expected); + } + + SECTION("k = 5, n = 5") + { + const std::size_t k = 5; + const std::size_t n = 5; + const std::vector> expected{{0, 1, 2, 3, 4}}; + + auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); + + REQUIRE(result == expected); + } + + SECTION("k > n (invalid case)") + { + const std::size_t k = 6; + const std::size_t n = 5; + const std::vector> expected{}; + + auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); + + REQUIRE(result == expected); + } +} From 8d0c22fc548eacd27fb7e84c893691fb823ed073 Mon Sep 17 00:00:00 2001 From: Drewniok Date: Sun, 11 Aug 2024 19:18:35 +0200 Subject: [PATCH 58/95] :white_check_mark: add unit tests. --- .../determine_physically_valid_parameters.cpp | 69 +++++++++++++++++-- test/utils/math_utils.cpp | 3 + 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp b/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp index 0b593e3ff..befbe178a 100644 --- a/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp +++ b/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp @@ -102,23 +102,24 @@ TEST_CASE( "Determine physical parameters for CDS (default physical parameters) of Bestagon AND gate, 10 input combination", "[determine-physically-valid-parameters], [quality]") { - auto lyt = blueprints::bestagon_and_gate(); + auto bestagon_and = blueprints::bestagon_and_gate(); - lyt.assign_cell_type({36, 1, 0}, sidb_cell_clk_lyt_siqad::cell_type::EMPTY); - lyt.assign_cell_type({0, 0, 0}, sidb_cell_clk_lyt_siqad::cell_type::EMPTY); + bestagon_and.assign_cell_type({36, 1, 0}, sidb_cell_clk_lyt_siqad::cell_type::EMPTY); + bestagon_and.assign_cell_type({0, 0, 0}, sidb_cell_clk_lyt_siqad::cell_type::EMPTY); sidb_simulation_parameters sim_params{}; sim_params.base = 2; - charge_distribution_surface cds{lyt, sim_params}; + charge_distribution_surface cds{bestagon_and, sim_params}; operational_domain_params op_domain_params{}; op_domain_params.simulation_parameters = sim_params; - op_domain_params.sweep_dimensions = {operational_domain_value_range{sweep_parameter::EPSILON_R, 5.0, 5.9, 0.1}, - operational_domain_value_range{sweep_parameter::LAMBDA_TF, 5.0, 5.9, 0.1}}; - SECTION("Using the ground state of default physical parameters as given CDS") + SECTION("Using the ground state of default physical parameters as given CDS, two dimensional sweep") { + op_domain_params.sweep_dimensions = {operational_domain_value_range{sweep_parameter::EPSILON_R, 5.0, 5.9, 0.1}, + operational_domain_value_range{sweep_parameter::LAMBDA_TF, 5.0, 5.9, 0.1}}; + cds.assign_charge_state({38, 0, 0}, sidb_charge_state::NEGATIVE); cds.assign_charge_state({2, 1, 0}, sidb_charge_state::NEGATIVE); @@ -161,4 +162,58 @@ TEST_CASE( CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.8, 5.3}}) ->second == 0); } + + SECTION("Using the ground state of default physical parameters as given CDS, three dimensional sweep") + { + op_domain_params.sweep_dimensions = { + operational_domain_value_range{sweep_parameter::EPSILON_R, 5.5, 5.7, 0.1}, + operational_domain_value_range{sweep_parameter::LAMBDA_TF, 5.0, 5.2, 0.1}, + operational_domain_value_range{sweep_parameter::MU_MINUS, -0.33, -0.31, 0.01}}; + + cds.assign_charge_state({38, 0, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({2, 1, 0}, sidb_charge_state::NEGATIVE); + + cds.assign_charge_state({6, 2, 0}, sidb_charge_state::NEUTRAL); + cds.assign_charge_state({32, 2, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({8, 3, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({30, 3, 0}, sidb_charge_state::NEUTRAL); + + cds.assign_charge_state({12, 4, 0}, sidb_charge_state::NEUTRAL); + cds.assign_charge_state({26, 4, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({14, 5, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({24, 5, 0}, sidb_charge_state::NEUTRAL); + + cds.assign_charge_state({19, 8, 0}, sidb_charge_state::NEUTRAL); + cds.assign_charge_state({18, 9, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({23, 9, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({18, 11, 1}, sidb_charge_state::NEUTRAL); + + cds.assign_charge_state({19, 13, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({20, 14, 0}, sidb_charge_state::NEUTRAL); + + cds.assign_charge_state({24, 15, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({26, 16, 0}, sidb_charge_state::NEUTRAL); + + cds.assign_charge_state({30, 17, 0}, sidb_charge_state::NEGATIVE); + cds.assign_charge_state({32, 18, 0}, sidb_charge_state::NEUTRAL); + + cds.assign_charge_state({36, 19, 0}, sidb_charge_state::NEGATIVE); + + cds.update_after_charge_change(); + + const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); + REQUIRE(valid_parameters.operational_values.size() == 27); + CHECK( + find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.32}}) + ->second == 0); + CHECK( + find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.33}}) + ->second == 0); + CHECK( + find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.31}}) + ->second == 1); + CHECK( + find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.7, 5.2, -0.33}}) + ->second == 0); + } } diff --git a/test/utils/math_utils.cpp b/test/utils/math_utils.cpp index 99b243b66..c9ea0d500 100644 --- a/test/utils/math_utils.cpp +++ b/test/utils/math_utils.cpp @@ -6,6 +6,9 @@ #include +#include +#include + using namespace fiction; TEST_CASE("round_to_n_decimal_places should round an input number to n decimal places", "[round_to_n_decimal_places]") From c444c723d47d71abbcb41dd2e8146f4a116ad996 Mon Sep 17 00:00:00 2001 From: Drewniok Date: Mon, 12 Aug 2024 06:59:01 +0200 Subject: [PATCH 59/95] :white_check_mark: add test for parameter point. --- .../simulation/sidb/operational_domain.cpp | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/test/algorithms/simulation/sidb/operational_domain.cpp b/test/algorithms/simulation/sidb/operational_domain.cpp index 090fdfe1d..58dae3b06 100644 --- a/test/algorithms/simulation/sidb/operational_domain.cpp +++ b/test/algorithms/simulation/sidb/operational_domain.cpp @@ -56,6 +56,50 @@ void check_op_domain_params_and_operational_status( } } +TEST_CASE("Test parameter point", "[operational-domain]") +{ + // Test default constructor + parameter_point p_default; + REQUIRE(p_default.parameters.empty()); + + // Test parameterized constructor + std::vector values = {1.0, 2.0, 3.0}; + parameter_point p_param(values); + REQUIRE(p_param.parameters == values); + + // Test equality operator + parameter_point p1({1.0, 2.0, 3.0}); + parameter_point p2({1.0, 2.0, 3.0}); + parameter_point p3({1.0, 2.0, 3.0000001}); + + SECTION("Equality operator - exact equality") + { + REQUIRE(p1 == p2); + } + + SECTION("Equality operator - within tolerance") + { + REQUIRE(p1 == p3); + } + + // Test inequality operator + parameter_point p4({1.0, 2.0, 3.1}); + REQUIRE(p1 != p4); + + // Test structured bindings (get() method) + SECTION("Structured bindings - valid index") + { + REQUIRE(p1.get<0>() == 1.0); + REQUIRE(p1.get<1>() == 2.0); + REQUIRE(p1.get<2>() == 3.0); + } + + SECTION("Structured bindings - invalid index") + { + REQUIRE_THROWS_AS(p1.get<3>(), std::out_of_range); + } +} + TEST_CASE("BDL wire operational domain computation", "[operational-domain]") { using layout = sidb_cell_clk_lyt_siqad; From 24549baa3815bbe57eaf4491a0ae8e5f2855e14e Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 13 Aug 2024 17:21:43 +0200 Subject: [PATCH 60/95] :art: Improved consistency in naming, docstrings, formatting, etc. --- docs/utils/utils.rst | 2 + .../sidb/displacement_robustness_domain.hpp | 2 +- .../simulation/sidb/operational_domain.hpp | 39 ++++++++++++------- include/fiction/utils/math_utils.hpp | 25 ++++++------ test/utils/math_utils.cpp | 14 +++---- 5 files changed, 48 insertions(+), 34 deletions(-) diff --git a/docs/utils/utils.rst b/docs/utils/utils.rst index 8c908a105..68eec0c44 100644 --- a/docs/utils/utils.rst +++ b/docs/utils/utils.rst @@ -277,6 +277,8 @@ Math Utils .. doxygenfunction:: fiction::integral_abs .. doxygenfunction:: fiction::binomial_coefficient .. doxygenfunction:: fiction::determine_all_combinations_of_distributing_k_entities_on_n_positions +.. doxygenfunction:: fiction::cartesian_combinations + ``phmap`` --------- diff --git a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp index 60ad5ff4a..e22b18e43 100644 --- a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp @@ -492,7 +492,7 @@ class displacement_robustness_domain_impl */ [[nodiscard]] std::vector generate_valid_displaced_sidb_layouts() noexcept { - auto all_possible_sidb_displacement = compute_cartesian_combinations(all_possible_sidb_displacements); + auto all_possible_sidb_displacement = cartesian_combinations(all_possible_sidb_displacements); std::shuffle(all_possible_sidb_displacement.begin(), all_possible_sidb_displacement.end(), generator); diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index f1fcb680f..0be8eebc4 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -16,6 +16,7 @@ #include "fiction/technology/physical_constants.hpp" #include "fiction/traits.hpp" #include "fiction/utils/hash.hpp" +#include "fiction/utils/math_utils.hpp" #include "fiction/utils/phmap_utils.hpp" #include @@ -189,10 +190,11 @@ struct operational_domain { return it->second; } - // Create a stringstream to hold the string representation + + // Create a string stream to hold the string representation std::stringstream ss; - // Iterate over the vector and add elements to the stringstream + // Iterate over the vector and add elements to the string stream for (std::size_t i = 0; i < pp.parameters.size(); ++i) { ss << pp.parameters[i]; @@ -202,6 +204,7 @@ struct operational_domain ss << ", "; } } + throw std::out_of_range(fmt::format("{} not found in the operational domain", ss.str()).c_str()); } }; @@ -245,9 +248,9 @@ find_parameter_point_with_tolerance(const MapType& map, const typename MapType:: return std::find_if(map.cbegin(), map.cend(), [&key](const auto& pair) { return pair.first == key; }); } /** - * This function searches for a floating-point value specified by the `key` in the provided map `map`, - * applying a tolerance specified by `fiction::physical_constants::POP_STABILITY_ERR`. - * Each key in the map is compared to the specified key within this tolerance. + * This function searches for a floating-point value specified by the `key` in the provided map `map`, applying a + * tolerance specified by `fiction::physical_constants::POP_STABILITY_ERR`. Each key in the map is compared to the + * specified key within this tolerance. * * @tparam MapType The type of the map containing parameter points as keys. * @param map The map containing parameter points as keys and associated values. @@ -322,7 +325,7 @@ struct operational_domain_stats namespace detail { -template +template class operational_domain_impl { public: @@ -437,7 +440,7 @@ class operational_domain_impl { mockturtle::stopwatch stop{stats.time_total}; - const auto all_index_combination = compute_cartesian_combinations(indices); + const auto all_index_combination = cartesian_combinations(indices); std::vector all_step_points; all_step_points.reserve(all_index_combination.size()); @@ -661,9 +664,9 @@ class operational_domain_impl return op_domain; } /** - * Performs a grid search over the specified parameter ranges. For each physical - * parameter combination found for which the given CDS is physically valid, it is determined whether the CDS is the - * ground state or the n-th excited state. + * Performs a grid search over the specified parameter ranges. For each physical parameter combination found for + * which the given CDS is physically valid, it is determined whether the CDS is the ground state or the n-th excited + * state. * * @param lyt SiDB cell-level layout that is simulated and compared to the given CDS. * @return All physically valid physical parameters and the excited state number. @@ -675,7 +678,7 @@ class operational_domain_impl mockturtle::stopwatch stop{stats.time_total}; - const auto all_step_points = compute_cartesian_combinations(indices); + const auto all_step_points = cartesian_combinations(indices); // calculate the size of each slice const auto slice_size = (all_step_points.size() + num_threads - 1) / num_threads; @@ -718,7 +721,7 @@ class operational_domain_impl for (const auto& [param_point, status] : op_domain.operational_values) { - if constexpr (std::is_same_v>) + if constexpr (std::is_same_v>) { if (status == operational_status::NON_OPERATIONAL) { @@ -757,13 +760,16 @@ class operational_domain_impl } const auto energy_dist = energy_distribution(sim_results.charge_distributions); + lyt.assign_physical_parameters(simulation_parameters); const auto position = find_key_with_tolerance(energy_dist, lyt.get_system_energy()); + if (position == energy_dist.cend()) { continue; } - const auto excited_state_number = std::distance(energy_dist.begin(), position); + + const auto excited_state_number = std::distance(energy_dist.cbegin(), position); suitable_params_domain.operational_values.emplace(param_point, excited_state_number); } } @@ -807,7 +813,7 @@ class operational_domain_impl /** * The operational domain of the layout. */ - OPDomain op_domain{}; + OpDomain op_domain{}; /** * Forward-declare step_point. */ @@ -1286,7 +1292,7 @@ class operational_domain_impl } } - // if no boundary point was found, the operational area extends outside the parameter range + // if no boundary point was found, the operational area extends outside the parameter range; // return the latest operational point return latest_operational_point; } @@ -1746,16 +1752,19 @@ operational_domain_contour_tracing(const Lyt& lyt, const std::vector& spec, namespace std { + // make `operational_domain::parameter_point` compatible with `std::integral_constant` template <> struct tuple_size : std::integral_constant {}; + // make `operational_domain::parameter_point` compatible with `std::tuple_element` template struct tuple_element { using type = double; }; + // make `operational_domain::parameter_point` compatible with `std::hash` template <> struct hash diff --git a/include/fiction/utils/math_utils.hpp b/include/fiction/utils/math_utils.hpp index 56ef7327d..22ecf124e 100644 --- a/include/fiction/utils/math_utils.hpp +++ b/include/fiction/utils/math_utils.hpp @@ -26,14 +26,13 @@ namespace fiction * @return The number rounded to n decimal places. */ template -T round_to_n_decimal_places(const T number, const uint64_t n) noexcept +[[nodiscard]] inline T round_to_n_decimal_places(const T number, const uint64_t n) noexcept { static_assert(std::is_arithmetic_v, "T is not a number type"); const auto factor = std::pow(10.0, static_cast(n)); return static_cast(std::round(static_cast(number) * factor) / factor); } - /** * Takes the absolute value of an integral number if it is signed, and otherwise computes the identity. This avoids a * compiler warning when taking the absolute value of an unsigned number. @@ -42,7 +41,7 @@ T round_to_n_decimal_places(const T number, const uint64_t n) noexcept * @return |n|. */ template -T integral_abs(const T n) noexcept +[[nodiscard]] inline T integral_abs(const T n) noexcept { static_assert(std::is_integral_v, "T is not an integral number type"); @@ -53,7 +52,6 @@ T integral_abs(const T n) noexcept return static_cast(std::abs(static_cast(n))); // needed to solve ambiguity of std::abs } - /** * Calculates the binomial coefficient \f$\binom{n}{k}\f$. * @@ -67,15 +65,19 @@ T integral_abs(const T n) noexcept { return 0; } + uint64_t result = 1; + if (2 * k > n) { k = n - k; } + for (uint64_t i = 1; i <= k; i++) { result = result * (n + 1 - i) / i; } + return result; } @@ -97,6 +99,7 @@ determine_all_combinations_of_distributing_k_entities_on_n_positions(const std:: { return {}; } + std::vector> all_combinations{}; all_combinations.reserve(binomial_coefficient(n, k)); @@ -128,19 +131,19 @@ determine_all_combinations_of_distributing_k_entities_on_n_positions(const std:: * consists of one element from each dimension vector. * * @tparam VectorDataType The type of elements in the vectors. - * @param indices A vector of vectors, where each inner vector represents a dimension. The function - * generates combinations using one element from each dimension vector. - * @return A vector of vectors, where each inner vector represents a combination of elements, - * one from each dimension. The total number of combinations is the product of the sizes - * of the input vectors. + * @param sets The sets to compute the Cartesian product for. In this implementation, a vector of vectors is utilized + * for efficiency. Each inner vector represents one dimension. The function generates combinations using one element + * from each dimension vector. + * @return A vector of vectors, where each inner vector represents a combination of elements, one from each dimension. + * The total number of combinations is the product of the sizes of the input vectors. */ template [[nodiscard]] inline std::vector> -compute_cartesian_combinations(const std::vector>& indices) noexcept +cartesian_combinations(const std::vector>& sets) noexcept { std::vector> all_combinations{{}}; - for (const auto& dimension : indices) + for (const auto& dimension : sets) { std::vector> expanded_products{}; expanded_products.reserve(all_combinations.size() * dimension.size()); diff --git a/test/utils/math_utils.cpp b/test/utils/math_utils.cpp index c9ea0d500..c52517c0e 100644 --- a/test/utils/math_utils.cpp +++ b/test/utils/math_utils.cpp @@ -116,14 +116,14 @@ TEST_CASE("Binomial Coefficient Tests") } } -TEST_CASE("Test the computation of the cartesian combinations", "[compute_cartesian_combinations]") +TEST_CASE("Test the computation of the cartesian combinations", "[cartesian_combinations]") { SECTION("Single dimension") { const std::vector> input{{1, 2, 3}}; const std::vector> expected{{1}, {2}, {3}}; - auto result = compute_cartesian_combinations(input); + auto result = cartesian_combinations(input); REQUIRE(result == expected); } @@ -133,7 +133,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[compute_cartes const std::vector> input{{1, 2}, {3, 4}}; const std::vector> expected{{1, 3}, {1, 4}, {2, 3}, {2, 4}}; - auto result = compute_cartesian_combinations(input); + auto result = cartesian_combinations(input); REQUIRE(result == expected); } @@ -144,7 +144,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[compute_cartes const std::vector> expected{{1, 3, 5}, {1, 3, 6}, {1, 4, 5}, {1, 4, 6}, {2, 3, 5}, {2, 3, 6}, {2, 4, 5}, {2, 4, 6}}; - auto result = compute_cartesian_combinations(input); + auto result = cartesian_combinations(input); REQUIRE(result == expected); } @@ -154,7 +154,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[compute_cartes const std::vector> input{}; const std::vector> expected{{}}; - auto result = compute_cartesian_combinations(input); + auto result = cartesian_combinations(input); REQUIRE(result == expected); } @@ -164,7 +164,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[compute_cartes const std::vector> input{{1, 2}, {}}; const std::vector> expected{}; - auto result = compute_cartesian_combinations(input); + auto result = cartesian_combinations(input); REQUIRE(result == expected); } @@ -174,7 +174,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[compute_cartes const std::vector> input{{"a", "b"}, {"x", "y"}}; const std::vector> expected{{"a", "x"}, {"a", "y"}, {"b", "x"}, {"b", "y"}}; - auto result = compute_cartesian_combinations(input); + auto result = cartesian_combinations(input); REQUIRE(result == expected); } From ee14b1a3dc65f143f465e29442a979aa0f65dee7 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 13 Aug 2024 15:23:12 +0000 Subject: [PATCH 61/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 9894c46ec..346da61e5 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -825,6 +825,26 @@ Parameter ``sim_params``: Physical parameters used to determine whether positively charged SiDBs can occur.)doc"; +static const char *__doc_fiction_cartesian_combinations = +R"doc(This function computes the Cartesian product of a list of vectors. +Each vector in the input list represents a dimension, and the function +produces all possible combinations where each combination consists of +one element from each dimension vector. + +Template parameter ``VectorDataType``: + The type of elements in the vectors. + +Parameter ``sets``: + The sets to compute the Cartesian product for. In this + implementation, a vector of vectors is utilized for efficiency. + Each inner vector represents one dimension. The function generates + combinations using one element from each dimension vector. + +Returns: + A vector of vectors, where each inner vector represents a + combination of elements, one from each dimension. The total number + of combinations is the product of the sizes of the input vectors.)doc"; + static const char *__doc_fiction_cartesian_layout = R"doc(A layout type that utilizes offset coordinates to represent a Cartesian grid. Its faces are organized in the following way: @@ -2340,25 +2360,6 @@ Parameter ``n``: Returns: Columnar clocking scheme.)doc"; -static const char *__doc_fiction_compute_cartesian_combinations = -R"doc(This function computes the Cartesian product of a list of vectors. -Each vector in the input list represents a dimension, and the function -produces all possible combinations where each combination consists of -one element from each dimension vector. - -Template parameter ``VectorDataType``: - The type of elements in the vectors. - -Parameter ``indices``: - A vector of vectors, where each inner vector represents a - dimension. The function generates combinations using one element - from each dimension vector. - -Returns: - A vector of vectors, where each inner vector represents a - combination of elements, one from each dimension. The total number - of combinations is the product of the sizes of the input vectors.)doc"; - static const char *__doc_fiction_convert_array = R"doc(Converts an array of size `N` and type `T` to an array of size `N` and type `ElementType` by applying `static_cast` at compile time. From 2b26f38c14240bd2f55d721f2e842923a04fe36a Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 13 Aug 2024 17:33:31 +0200 Subject: [PATCH 62/95] :art: Remove unnecessary lock guards --- .../simulation/sidb/operational_domain.hpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 0be8eebc4..0a475bf40 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -1020,24 +1020,21 @@ class operational_domain_impl const auto param_point = to_parameter_point(sp); - const auto operational = [this, ¶m_point]() + const auto operational = [this, ¶m_point]() noexcept { const std::lock_guard lock(mutex_to_protect_member_variables); op_domain.operational_values[param_point] = operational_status::OPERATIONAL; return operational_status::OPERATIONAL; }; - const auto non_operational = [this, ¶m_point]() + const auto non_operational = [this, ¶m_point]() noexcept { const std::lock_guard lock(mutex_to_protect_member_variables); op_domain.operational_values[param_point] = operational_status::NON_OPERATIONAL; return operational_status::NON_OPERATIONAL; }; - { - const std::lock_guard lock(mutex_to_protect_member_variables); - ++num_evaluated_parameter_combinations; - } + ++num_evaluated_parameter_combinations; sidb_simulation_parameters sim_params = params.simulation_parameters; @@ -1049,10 +1046,7 @@ class operational_domain_impl const auto& [status, sim_calls] = is_operational(layout, truth_table, is_operational_params{sim_params, params.sim_engine}); - { - const std::lock_guard lock(mutex_to_protect_member_variables); - num_simulator_invocations += sim_calls; - } + num_simulator_invocations += sim_calls; if (status == operational_status::NON_OPERATIONAL) { From 1cb096e4f30378a5a98d749266195573225e4d38 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 13 Aug 2024 19:09:50 +0200 Subject: [PATCH 63/95] :art: Remove unnecessary lock guards --- .../algorithms/simulation/sidb/operational_domain.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 0a475bf40..17c928c4b 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -1012,6 +1012,7 @@ class operational_domain_impl { const std::lock_guard lock{mutex_to_protect_member_variables}; + if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) { return *op_value; @@ -1069,6 +1070,7 @@ class operational_domain_impl { const std::lock_guard lock{mutex_to_protect_member_variables}; + // if the point has already been sampled, return the stored operational status if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) { @@ -1095,11 +1097,8 @@ class operational_domain_impl return operational_status::NON_OPERATIONAL; }; - { - const std::lock_guard lock(mutex_to_protect_member_variables); - // increment the number of evaluated parameter combinations - ++num_evaluated_parameter_combinations; - } + // increment the number of evaluated parameter combinations + ++num_evaluated_parameter_combinations; sidb_simulation_parameters sim_params = params.simulation_parameters; From b5b22be98901dc80215a3f4d77ff7c6e48956101 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 13 Aug 2024 19:28:22 +0200 Subject: [PATCH 64/95] :thread: Thread-safe value-retrieval from std::atomic types --- .../simulation/sidb/operational_domain.hpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 17c928c4b..cb05623c2 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -1023,15 +1023,15 @@ class operational_domain_impl const auto operational = [this, ¶m_point]() noexcept { - const std::lock_guard lock(mutex_to_protect_member_variables); - op_domain.operational_values[param_point] = operational_status::OPERATIONAL; + op_domain.operational_values.try_emplace(param_point, operational_status::OPERATIONAL); + return operational_status::OPERATIONAL; }; const auto non_operational = [this, ¶m_point]() noexcept { - const std::lock_guard lock(mutex_to_protect_member_variables); - op_domain.operational_values[param_point] = operational_status::NON_OPERATIONAL; + op_domain.operational_values.try_emplace(param_point, operational_status::NON_OPERATIONAL); + return operational_status::NON_OPERATIONAL; }; @@ -1083,16 +1083,14 @@ class operational_domain_impl const auto operational = [this, ¶m_point]() { - const std::lock_guard lock(mutex_to_protect_member_variables); - op_domain.operational_values[param_point] = operational_status::OPERATIONAL; + op_domain.operational_values.try_emplace(param_point, operational_status::OPERATIONAL); return operational_status::OPERATIONAL; }; const auto non_operational = [this, ¶m_point]() { - const std::lock_guard lock(mutex_to_protect_member_variables); - op_domain.operational_values[param_point] = operational_status::NON_OPERATIONAL; + op_domain.operational_values.try_emplace(param_point, operational_status::NON_OPERATIONAL); return operational_status::NON_OPERATIONAL; }; @@ -1514,8 +1512,8 @@ class operational_domain_impl */ void log_stats() const noexcept { - stats.num_simulator_invocations = num_simulator_invocations; - stats.num_evaluated_parameter_combinations = num_evaluated_parameter_combinations; + stats.num_simulator_invocations = num_simulator_invocations.load(); + stats.num_evaluated_parameter_combinations = num_evaluated_parameter_combinations.load(); for (const auto& [param_point, status] : op_domain.operational_values) { From 64c946da6ca68221f2fd61d5c70dbfccfba804e0 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 14 Aug 2024 14:22:13 +0200 Subject: [PATCH 65/95] :art: Minor consistency fixes --- .../simulation/sidb/operational_domain.hpp | 17 ++++++----------- include/fiction/utils/phmap_utils.hpp | 1 + 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index cb05623c2..4a3ff2c09 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -65,13 +65,7 @@ struct parameter_point /** * Parameter values for each dimension. */ - std::vector parameters; - /** - * Equality operator. - * - * @param other Other parameter point to compare with. - * @return `true` if the parameter points are equal. - */ + std::vector parameters{}; /** * Equality operator. Checks if this parameter point is equal to another point within a specified tolerance. * The tolerance is defined by `physical_constants::POP_STABILITY_ERR`. @@ -231,8 +225,7 @@ struct operational_domain_value_range double step{0.1}; }; /** - * This function searches for a parameter point, specified by the `key`, in the provided map - * `map` with tolerance. + * This function searches for a parameter point, specified by the `key`, in the provided map `map` with tolerance. * * @tparam MapType The type of the map containing parameter points as keys. * @param map The map containing parameter points as keys and associated values. @@ -262,9 +255,12 @@ template const typename MapType::key_type& key) { static_assert(std::is_floating_point_v, "Map key type must be floating-point"); + constexpr double tolerance = physical_constants::POP_STABILITY_ERR; + auto compare_keys = [&key, &tolerance](const auto& pair) { return std::abs(pair.first - key) < tolerance; }; - return std::find_if(map.begin(), map.end(), compare_keys); + + return std::find_if(map.cbegin(), map.cend(), compare_keys); } /** * Parameters for the operational domain computation. The parameters are used across the different operational domain @@ -429,7 +425,6 @@ class operational_domain_impl } } } - /** * Performs a grid search over the specified parameter ranges with the specified step sizes. The grid search always * has quadratic complexity. The operational status is computed for each parameter combination. diff --git a/include/fiction/utils/phmap_utils.hpp b/include/fiction/utils/phmap_utils.hpp index 2c16a908e..cf3aadec0 100644 --- a/include/fiction/utils/phmap_utils.hpp +++ b/include/fiction/utils/phmap_utils.hpp @@ -6,6 +6,7 @@ #define FICTION_PHMAP_UTILS_HPP #include +#include #include #include From 5283a0753aedc433a8f592eb803b7bddf132c3c0 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 14 Aug 2024 14:22:51 +0200 Subject: [PATCH 66/95] :thread: Switched std::mutex to std::shared_mutex for parallel read access --- .../simulation/sidb/operational_domain.hpp | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 4a3ff2c09..802f54252 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -32,11 +32,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -809,6 +809,10 @@ class operational_domain_impl * The operational domain of the layout. */ OpDomain op_domain{}; + /** + * A shared mutex for unlimited read access but restricted write access to the operational domain. + */ + std::shared_mutex read_write_op_domain_mutex{}; /** * Forward-declare step_point. */ @@ -1003,10 +1007,9 @@ class operational_domain_impl */ operational_status is_step_point_operational(const step_point& sp) noexcept { - static std::mutex mutex_to_protect_member_variables; - { - const std::lock_guard lock{mutex_to_protect_member_variables}; + // shared read access + const std::shared_lock lock{read_write_op_domain_mutex}; if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) { @@ -1018,6 +1021,9 @@ class operational_domain_impl const auto operational = [this, ¶m_point]() noexcept { + // unique write access + const std::unique_lock lock{read_write_op_domain_mutex}; + op_domain.operational_values.try_emplace(param_point, operational_status::OPERATIONAL); return operational_status::OPERATIONAL; @@ -1025,6 +1031,9 @@ class operational_domain_impl const auto non_operational = [this, ¶m_point]() noexcept { + // unique write access + const std::unique_lock lock{read_write_op_domain_mutex}; + op_domain.operational_values.try_emplace(param_point, operational_status::NON_OPERATIONAL); return operational_status::NON_OPERATIONAL; @@ -1061,10 +1070,9 @@ class operational_domain_impl */ operational_status is_step_point_suitable(Lyt lyt, const step_point& sp) noexcept { - static std::mutex mutex_to_protect_member_variables; - { - const std::lock_guard lock{mutex_to_protect_member_variables}; + // shared read access + const std::shared_lock lock{read_write_op_domain_mutex}; // if the point has already been sampled, return the stored operational status if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) @@ -1078,6 +1086,9 @@ class operational_domain_impl const auto operational = [this, ¶m_point]() { + // unique write access + const std::unique_lock lock{read_write_op_domain_mutex}; + op_domain.operational_values.try_emplace(param_point, operational_status::OPERATIONAL); return operational_status::OPERATIONAL; @@ -1085,6 +1096,9 @@ class operational_domain_impl const auto non_operational = [this, ¶m_point]() { + // unique write access + const std::unique_lock lock{read_write_op_domain_mutex}; + op_domain.operational_values.try_emplace(param_point, operational_status::NON_OPERATIONAL); return operational_status::NON_OPERATIONAL; From 9c0dc56911460691a6e61f7d64cb1ef420517a85 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 14 Aug 2024 12:58:35 +0000 Subject: [PATCH 67/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 346da61e5..aff4e2f1e 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -6436,6 +6436,10 @@ Parameter ``samples``: Returns: The (partial) operational domain of the layout.)doc"; +static const char *__doc_fiction_detail_operational_domain_impl_read_write_op_domain_mutex = +R"doc(A shared mutex for unlimited read access but restricted write access +to the operational domain.)doc"; + static const char *__doc_fiction_detail_operational_domain_impl_set_dimension_value = R"doc(Helper function that sets the value of a sweep dimension in the simulation parameters. @@ -13358,15 +13362,7 @@ Template parameter ``I``: The parameter value at the specified index.)doc"; static const char *__doc_fiction_parameter_point_operator_eq = -R"doc(Equality operator. - -Parameter ``other``: - Other parameter point to compare with. - -Returns: - `true` if the parameter points are equal. - -Equality operator. Checks if this parameter point is equal to another +R"doc(Equality operator. Checks if this parameter point is equal to another point within a specified tolerance. The tolerance is defined by `physical_constants::POP_STABILITY_ERR`. From 58c5de2a20d93b283b5d1828e3201b4d367a6135 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 14 Aug 2024 16:37:10 +0200 Subject: [PATCH 68/95] :thread: Removed the need for manual mutexes and locks in operational domain computation --- docs/algorithms/sidb_simulation.rst | 2 +- .../determine_physically_valid_parameters.hpp | 11 +-- .../simulation/sidb/operational_domain.hpp | 78 +++++++----------- .../determine_physically_valid_parameters.cpp | 81 ++++++++++++------- 4 files changed, 88 insertions(+), 84 deletions(-) diff --git a/docs/algorithms/sidb_simulation.rst b/docs/algorithms/sidb_simulation.rst index 95c6a399a..dd35c7ce5 100644 --- a/docs/algorithms/sidb_simulation.rst +++ b/docs/algorithms/sidb_simulation.rst @@ -238,7 +238,7 @@ Operational Domain Computation .. doxygenenum:: fiction::sweep_parameter .. doxygenstruct:: fiction::operational_domain :members: - .. doxygenfunction:: fiction::find_parameter_point_with_tolerance + .. doxygenfunction:: fiction::contains_parameter_point .. doxygenfunction:: fiction::find_key_with_tolerance .. doxygenstruct:: fiction::operational_domain_params :members: diff --git a/include/fiction/algorithms/simulation/sidb/determine_physically_valid_parameters.hpp b/include/fiction/algorithms/simulation/sidb/determine_physically_valid_parameters.hpp index 3d85a291b..173ad7000 100644 --- a/include/fiction/algorithms/simulation/sidb/determine_physically_valid_parameters.hpp +++ b/include/fiction/algorithms/simulation/sidb/determine_physically_valid_parameters.hpp @@ -30,8 +30,8 @@ namespace fiction * @tparam Lyt The charge distribution surface type. * @param cds The charge distribution surface for which physical parameters are to be determined. * @param params Operational domain parameters. - * @return Physically valid parameters with the corresponding excited state number of the given cds for each parameter - * point. + * @return Physically valid parameters with the corresponding excited state number of the given charge distribution + * surface for each parameter point. */ template [[nodiscard]] operational_domain @@ -41,9 +41,10 @@ determine_physically_valid_parameters(Lyt& cds, const operational_domain_params& static_assert(has_sidb_technology_v, "Lyt is not an SiDB layout"); static_assert(is_charge_distribution_surface_v, "Lyt is not a charge distribution surface"); - operational_domain_stats st{}; - detail::operational_domain_impl> p{cds, params, - st}; + operational_domain_stats st{}; + + using op_domain = operational_domain; + detail::operational_domain_impl p{cds, params, st}; const auto result = p.grid_search_for_physically_valid_parameters(cds); diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 802f54252..e82a7c684 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -87,7 +86,7 @@ struct parameter_point // Compare each element with tolerance for (std::size_t i = 0; i < parameters.size(); ++i) { - if (std::abs(parameters[i] - other.parameters[i]) > tolerance) + if (std::fabs(parameters[i] - other.parameters[i]) >= tolerance) { return false; } @@ -179,10 +178,9 @@ struct operational_domain */ [[nodiscard]] uint64_t get_value(const parameter_point& pp) const { - if (const auto it = find_parameter_point_with_tolerance(operational_values, pp); - it != operational_values.cend()) + if (const auto v = contains_parameter_point(operational_values, pp); v.has_value()) { - return it->second; + return v.value().second; } // Create a string stream to hold the string representation @@ -225,20 +223,26 @@ struct operational_domain_value_range double step{0.1}; }; /** - * This function searches for a parameter point, specified by the `key`, in the provided map `map` with tolerance. + * This function checks for the containment of a parameter point, specified by `key`, in the provided map `map`. If the + * parameter point is found in the map, the associated `MapType::value_type` is returned. Otherwise, `std::nullopt` is + * returned. * * @tparam MapType The type of the map containing parameter points as keys. - * @param map The map containing parameter points as keys and associated values. - * @param key The parameter point to search for in the map. - * @return An iterator to the found parameter point in the map, or `map.cend()` if not found. + * @param map The map in which to search for `key`. + * @param key The parameter point to search for in `map`. + * @return The associated `MapType::value_type` of `key` in `map`, or `std::nullopt` if `key` is not contained in `map`. */ template -[[maybe_unused]] static typename MapType::const_iterator -find_parameter_point_with_tolerance(const MapType& map, const typename MapType::key_type& key) +[[maybe_unused]] static std::optional +contains_parameter_point(const MapType& map, const typename MapType::key_type& key) { static_assert(std::is_same_v, "Map key type must be parameter_point"); - return std::find_if(map.cbegin(), map.cend(), [&key](const auto& pair) { return pair.first == key; }); + std::optional result = std::nullopt; + + map.if_contains(key, [&result](const typename MapType::value_type& v) { result.emplace(v); }); + + return result; } /** * This function searches for a floating-point value specified by the `key` in the provided map `map`, applying a @@ -809,10 +813,6 @@ class operational_domain_impl * The operational domain of the layout. */ OpDomain op_domain{}; - /** - * A shared mutex for unlimited read access but restricted write access to the operational domain. - */ - std::shared_mutex read_write_op_domain_mutex{}; /** * Forward-declare step_point. */ @@ -985,10 +985,10 @@ class operational_domain_impl */ [[nodiscard]] inline std::optional has_already_been_sampled(const step_point& sp) const noexcept { - if (const auto it = find_parameter_point_with_tolerance(op_domain.operational_values, to_parameter_point(sp)); - it != op_domain.operational_values.cend()) + if (const auto v = contains_parameter_point(op_domain.operational_values, to_parameter_point(sp)); + v.has_value()) { - return it->second; + return v.value().second; } return std::nullopt; @@ -1007,23 +1007,15 @@ class operational_domain_impl */ operational_status is_step_point_operational(const step_point& sp) noexcept { + if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) { - // shared read access - const std::shared_lock lock{read_write_op_domain_mutex}; - - if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) - { - return *op_value; - } + return *op_value; } const auto param_point = to_parameter_point(sp); const auto operational = [this, ¶m_point]() noexcept { - // unique write access - const std::unique_lock lock{read_write_op_domain_mutex}; - op_domain.operational_values.try_emplace(param_point, operational_status::OPERATIONAL); return operational_status::OPERATIONAL; @@ -1031,9 +1023,6 @@ class operational_domain_impl const auto non_operational = [this, ¶m_point]() noexcept { - // unique write access - const std::unique_lock lock{read_write_op_domain_mutex}; - op_domain.operational_values.try_emplace(param_point, operational_status::NON_OPERATIONAL); return operational_status::NON_OPERATIONAL; @@ -1045,7 +1034,7 @@ class operational_domain_impl for (auto d = 0u; d < num_dimensions; ++d) { - set_dimension_value(sim_params, values[d][sp.step_values[d]], d); // lock not needed here + set_dimension_value(sim_params, values[d][sp.step_values[d]], d); } const auto& [status, sim_calls] = @@ -1070,15 +1059,10 @@ class operational_domain_impl */ operational_status is_step_point_suitable(Lyt lyt, const step_point& sp) noexcept { + // if the point has already been sampled, return the stored operational status + if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) { - // shared read access - const std::shared_lock lock{read_write_op_domain_mutex}; - - // if the point has already been sampled, return the stored operational status - if (const auto op_value = has_already_been_sampled(sp); op_value.has_value()) - { - return *op_value; - } + return *op_value; } // fetch the x and y dimension values @@ -1086,9 +1070,6 @@ class operational_domain_impl const auto operational = [this, ¶m_point]() { - // unique write access - const std::unique_lock lock{read_write_op_domain_mutex}; - op_domain.operational_values.try_emplace(param_point, operational_status::OPERATIONAL); return operational_status::OPERATIONAL; @@ -1096,9 +1077,6 @@ class operational_domain_impl const auto non_operational = [this, ¶m_point]() { - // unique write access - const std::unique_lock lock{read_write_op_domain_mutex}; - op_domain.operational_values.try_emplace(param_point, operational_status::NON_OPERATIONAL); return operational_status::NON_OPERATIONAL; @@ -1769,12 +1747,16 @@ struct tuple_element template <> struct hash { + // tolerance for double hashing + static constexpr auto tolerance = fiction::physical_constants::POP_STABILITY_ERR; + size_t operator()(const fiction::parameter_point& p) const noexcept { size_t h = 0; for (const auto& d : p.parameters) { - fiction::hash_combine(h, d); + // hash the double values with tolerance + fiction::hash_combine(h, static_cast(d / tolerance)); } return h; diff --git a/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp b/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp index befbe178a..655a9ad47 100644 --- a/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp +++ b/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp @@ -10,12 +10,10 @@ #include #include #include -#include #include #include #include #include -#include using namespace fiction; @@ -87,14 +85,22 @@ TEST_CASE("Determine physical parameters for CDS of SiQAD Y-shaped AND gate, 10 const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); CHECK(valid_parameters.operational_values.size() == 98); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.9, 5.5}}) - ->second == 1); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}) - ->second == 0); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}) - ->second == 0); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{6.0, 6.0}}) - ->second == 1); + + const auto p1 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.9, 5.5}}); + REQUIRE(p1.has_value()); + CHECK(p1->second == 1); + + const auto p2 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}); + REQUIRE(p2.has_value()); + CHECK(p2->second == 0); + + const auto p3 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}); + REQUIRE(p3.has_value()); + CHECK(p3->second == 0); + + const auto p4 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{6.0, 6.0}}); + REQUIRE(p4.has_value()); + CHECK(p4->second == 1); } } @@ -153,14 +159,22 @@ TEST_CASE( const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); REQUIRE(valid_parameters.operational_values.size() == 100); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.6, 5.0}}) - ->second == 0); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.0, 5.9}}) - ->second == 2); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.4, 5.3}}) - ->second == 1); - CHECK(find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.8, 5.3}}) - ->second == 0); + + const auto p1 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0}}); + REQUIRE(p1.has_value()); + CHECK(p1->second == 0); + + const auto p2 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.0, 5.9}}); + REQUIRE(p2.has_value()); + CHECK(p2->second == 2); + + const auto p3 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.4, 5.3}}); + REQUIRE(p3.has_value()); + CHECK(p3->second == 1); + + const auto p4 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 5.3}}); + REQUIRE(p4.has_value()); + CHECK(p4->second == 0); } SECTION("Using the ground state of default physical parameters as given CDS, three dimensional sweep") @@ -203,17 +217,24 @@ TEST_CASE( const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); REQUIRE(valid_parameters.operational_values.size() == 27); - CHECK( - find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.32}}) - ->second == 0); - CHECK( - find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.33}}) - ->second == 0); - CHECK( - find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.31}}) - ->second == 1); - CHECK( - find_parameter_point_with_tolerance(valid_parameters.operational_values, parameter_point{{5.7, 5.2, -0.33}}) - ->second == 0); + const auto p1 = + contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.32}}); + REQUIRE(p1.has_value()); + CHECK(p1->second == 0); + + const auto p2 = + contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.33}}); + REQUIRE(p2.has_value()); + CHECK(p2->second == 0); + + const auto p3 = + contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.31}}); + REQUIRE(p3.has_value()); + CHECK(p3->second == 1); + + const auto p4 = + contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.7, 5.2, -0.33}}); + REQUIRE(p4.has_value()); + CHECK(p4->second == 0); } } From 8706b664a42dba5b199aaa26223da2e9fc19a4eb Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 14 Aug 2024 16:26:39 +0000 Subject: [PATCH 69/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index aff4e2f1e..729feb2a5 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -2360,6 +2360,25 @@ Parameter ``n``: Returns: Columnar clocking scheme.)doc"; +static const char *__doc_fiction_contains_parameter_point = +R"doc(This function checks for the containment of a parameter point, +specified by `key`, in the provided map `map`. If the parameter point +is found in the map, the associated `MapType::value_type` is returned. +Otherwise, `std::nullopt` is returned. + +Template parameter ``MapType``: + The type of the map containing parameter points as keys. + +Parameter ``map``: + The map in which to search for `key`. + +Parameter ``key``: + The parameter point to search for in `map`. + +Returns: + The associated `MapType::value_type` of `key` in `map`, or + `std::nullopt` if `key` is not contained in `map`.)doc"; + static const char *__doc_fiction_convert_array = R"doc(Converts an array of size `N` and type `T` to an array of size `N` and type `ElementType` by applying `static_cast` at compile time. @@ -6436,10 +6455,6 @@ Parameter ``samples``: Returns: The (partial) operational domain of the layout.)doc"; -static const char *__doc_fiction_detail_operational_domain_impl_read_write_op_domain_mutex = -R"doc(A shared mutex for unlimited read access but restricted write access -to the operational domain.)doc"; - static const char *__doc_fiction_detail_operational_domain_impl_set_dimension_value = R"doc(Helper function that sets the value of a sweep dimension in the simulation parameters. @@ -7935,7 +7950,8 @@ Parameter ``params``: Returns: Physically valid parameters with the corresponding excited state - number of the given cds for each parameter point.)doc"; + number of the given charge distribution surface for each parameter + point.)doc"; static const char *__doc_fiction_determine_propability_of_fabricating_operational_gate = R"doc(During fabrication, SiDBs may not align precisely with their intended @@ -9081,23 +9097,6 @@ R"doc(This function searches for a floating-point value specified by the `fiction::physical_constants::POP_STABILITY_ERR`. Each key in the map is compared to the specified key within this tolerance. -Template parameter ``MapType``: - The type of the map containing parameter points as keys. - -Parameter ``map``: - The map containing parameter points as keys and associated values. - -Parameter ``key``: - The parameter point to search for in the map. - -Returns: - An iterator to the found parameter point in the map, or - `map.cend()` if not found.)doc"; - -static const char *__doc_fiction_find_parameter_point_with_tolerance = -R"doc(This function searches for a parameter point, specified by the `key`, -in the provided map `map` with tolerance. - Template parameter ``MapType``: The type of the map containing parameter points as keys. From d2e13b0747ce752b06abaaafbc52fe3e4aaa2ab1 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 15:05:40 +0200 Subject: [PATCH 70/95] :children_crossing: Added sweep parameter validity checks --- cli/cmd/simulation/opdom.hpp | 46 +++++--- .../simulation/sidb/operational_domain.hpp | 45 +++++++- .../simulation/sidb/operational_domain.cpp | 101 ++++++++++++++++++ 3 files changed, 176 insertions(+), 16 deletions(-) diff --git a/cli/cmd/simulation/opdom.hpp b/cli/cmd/simulation/opdom.hpp index 22969bc04..cfdfeae29 100644 --- a/cli/cmd/simulation/opdom.hpp +++ b/cli/cmd/simulation/opdom.hpp @@ -239,25 +239,38 @@ class opdom_command : public command params.simulation_parameters = simulation_params; - if (is_set("random_sampling")) + try { - op_domain = fiction::operational_domain_random_sampling(*lyt_ptr, std::vector{*tt_ptr}, - num_random_samples, params, &stats); + if (is_set("random_sampling")) + { + op_domain = fiction::operational_domain_random_sampling( + *lyt_ptr, std::vector{*tt_ptr}, num_random_samples, params, &stats); + } + else if (is_set("flood_fill")) + { + op_domain = fiction::operational_domain_flood_fill(*lyt_ptr, std::vector{*tt_ptr}, + num_random_samples, params, &stats); + } + else if (is_set("contour_tracing")) + { + op_domain = fiction::operational_domain_contour_tracing( + *lyt_ptr, std::vector{*tt_ptr}, num_random_samples, params, &stats); + } + else + { + op_domain = fiction::operational_domain_grid_search(*lyt_ptr, std::vector{*tt_ptr}, + params, &stats); + } } - else if (is_set("flood_fill")) + catch (std::exception& e) { - op_domain = fiction::operational_domain_flood_fill(*lyt_ptr, std::vector{*tt_ptr}, - num_random_samples, params, &stats); - } - else if (is_set("contour_tracing")) - { - op_domain = fiction::operational_domain_contour_tracing(*lyt_ptr, std::vector{*tt_ptr}, - num_random_samples, params, &stats); + env->out() << fmt::format("[e] {}", e.what()) << std::endl; + return; } - else + catch (..) { - op_domain = fiction::operational_domain_grid_search(*lyt_ptr, std::vector{*tt_ptr}, - params, &stats); + env->out() << "[e] an unknown error occurred during operational domain computation" << std::endl; + return; } } else @@ -317,6 +330,7 @@ class opdom_command : public command void write_op_domain() const { static const fiction::write_operational_domain_params write_opdom_params{"1", "0"}; + try { fiction::write_operational_domain(op_domain, filename, write_opdom_params); @@ -325,6 +339,10 @@ class opdom_command : public command { env->out() << fmt::format("[e] {}", e.what()) << std::endl; } + catch (...) + { + env->out() << "[e] an unknown error occurred while writing the operational domain data" << std::endl; + } } /** * Logs the resulting information in a log file. diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index e82a7c684..7bbcfe6ce 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -325,6 +325,27 @@ struct operational_domain_stats namespace detail { +/** + * This function validates the given sweep parameters for the operational domain computation. It checks if the minimum + * value of any sweep dimension is larger than the corresponding maximum value. If this is the case, an + * `std::invalid_argument` is thrown. + * + * @param params The operational domain parameters to validate. + */ +void validate_sweep_parameters(const operational_domain_params& params) +{ + for (auto d = 0u; d < params.sweep_dimensions.size(); ++d) + { + if (params.sweep_dimensions[d].max < params.sweep_dimensions[d].min) + { + throw std::invalid_argument( + fmt::format("Invalid sweep dimension: 'max' value is smaller than 'min' value for " + "dimension {}", + d)); + } + } +} + template class operational_domain_impl { @@ -1531,6 +1552,8 @@ class operational_domain_impl * state simulations, where \f$n\f$ is the number of inputs of the layout. Each exact ground state simulation has * exponential complexity in of itself. Therefore, the algorithm is only feasible for small layouts with few inputs. * + * This function may throw an `std::invalid_argument` exception if the given sweep parameters are invalid. + * * @tparam Lyt SiDB cell-level layout type. * @tparam TT Truth table type. * @param lyt Layout to compute the operational domain for. @@ -1549,6 +1572,9 @@ operational_domain_grid_search(const Lyt& lyt, const std::vector& spec, static_assert(has_sidb_technology_v, "Lyt is not an SiDB layout"); static_assert(kitty::is_truth_table::value, "TT is not a truth table"); + // this may throw an `std::invalid_argument` exception + detail::validate_sweep_parameters(params); + operational_domain_stats st{}; detail::operational_domain_impl> p{lyt, spec, params, st}; @@ -1574,6 +1600,8 @@ operational_domain_grid_search(const Lyt& lyt, const std::vector& spec, * ground state simulations, where \f$n\f$ is the number of inputs of the layout. Each exact ground state simulation * has exponential complexity in of itself. Therefore, the algorithm is only feasible for small layouts with few inputs. * + * This function may throw an `std::invalid_argument` exception if the given sweep parameters are invalid. + * * @tparam Lyt SiDB cell-level layout type. * @tparam TT Truth table type. * @param lyt Layout to compute the operational domain for. @@ -1593,6 +1621,9 @@ operational_domain_random_sampling(const Lyt& lyt, const std::vector& spec, static_assert(has_sidb_technology_v, "Lyt is not an SiDB layout"); static_assert(kitty::is_truth_table::value, "TT is not a truth table"); + // this may throw an `std::invalid_argument` exception + detail::validate_sweep_parameters(params); + operational_domain_stats st{}; detail::operational_domain_impl> p{lyt, spec, params, st}; @@ -1628,6 +1659,8 @@ operational_domain_random_sampling(const Lyt& lyt, const std::vector& spec, * Computation in Silicon Dangling Bond Logic\" by M. Walter, J. Drewniok, S. S. H. Ng, K. Walus, and R. Wille in * NANOARCH 2023. * + * This function may throw an `std::invalid_argument` exception if the given sweep parameters are invalid. + * * @tparam Lyt SiDB cell-level layout type. * @tparam TT Truth table type. * @param lyt Layout to compute the operational domain for. @@ -1648,9 +1681,12 @@ operational_domain_flood_fill(const Lyt& lyt, const std::vector& spec, const if (params.sweep_dimensions.size() != 2 && params.sweep_dimensions.size() != 3) { - throw std::runtime_error("Flood fill is only applicable to 2 or 3 dimensions"); + throw std::invalid_argument("Flood fill is only applicable to 2 or 3 dimensions"); } + // this may throw an `std::invalid_argument` exception + detail::validate_sweep_parameters(params); + operational_domain_stats st{}; detail::operational_domain_impl> p{lyt, spec, params, st}; @@ -1688,6 +1724,8 @@ operational_domain_flood_fill(const Lyt& lyt, const std::vector& spec, const * Computation in Silicon Dangling Bond Logic\" by M. Walter, J. Drewniok, S. S. H. Ng, K. Walus, and R. Wille in * NANOARCH 2023. * + * This function may throw an `std::invalid_argument` exception if the given sweep parameters are invalid. + * * @tparam Lyt SiDB cell-level layout type. * @tparam TT Truth table type. * @param lyt Layout to compute the operational domain for. @@ -1709,9 +1747,12 @@ operational_domain_contour_tracing(const Lyt& lyt, const std::vector& spec, if (params.sweep_dimensions.size() != 2) { - throw std::runtime_error("Contour tracing is only applicable to exactly 2 dimensions"); + throw std::invalid_argument("Contour tracing is only applicable to exactly 2 dimensions"); } + // this may throw an `std::invalid_argument` exception + detail::validate_sweep_parameters(params); + operational_domain_stats st{}; detail::operational_domain_impl> p{lyt, spec, params, st}; diff --git a/test/algorithms/simulation/sidb/operational_domain.cpp b/test/algorithms/simulation/sidb/operational_domain.cpp index 58dae3b06..2645fd752 100644 --- a/test/algorithms/simulation/sidb/operational_domain.cpp +++ b/test/algorithms/simulation/sidb/operational_domain.cpp @@ -100,6 +100,107 @@ TEST_CASE("Test parameter point", "[operational-domain]") } } +TEST_CASE("Error handling of operational domain algorithms", "[operational-domain]") +{ + const sidb_100_cell_clk_lyt_siqad lat{sidb_cell_clk_lyt_siqad{}}; // empty layout + + SECTION("invalid number of dimensions") + { + operational_domain_params zero_dimensional_params{}; + operational_domain_params one_dimensional_params{}; + operational_domain_params three_dimensional_params{}; + operational_domain_params four_dimensional_params{}; + + // 0-dimensional + zero_dimensional_params.sweep_dimensions = {}; + + // 1-dimensional + one_dimensional_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}}; + + // 3-dimensional + three_dimensional_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}, + {sweep_parameter::MU_MINUS}}; + + // 4-dimensional + four_dimensional_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}, + {sweep_parameter::MU_MINUS}, + {sweep_parameter::EPSILON_R}}; + + SECTION("flood_fill") + { + // flood fill operates on 2-dimensional and 3-dimensional parameter spaces + for (const auto& params : {zero_dimensional_params, one_dimensional_params, four_dimensional_params}) + { + CHECK_THROWS_AS(operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 1, params), + std::invalid_argument); + } + } + SECTION("contour_tracing") + { + // contour tracing operates only on 2-dimensional parameter spaces + for (const auto& params : + {zero_dimensional_params, one_dimensional_params, three_dimensional_params, four_dimensional_params}) + { + CHECK_THROWS_AS(operational_domain_contour_tracing(lat, std::vector{create_id_tt()}, 1, params), + std::invalid_argument); + } + } + } + + SECTION("invalid sweep dimensions") + { + operational_domain_params invalid_params_1{}; + operational_domain_params invalid_params_2{}; + operational_domain_params invalid_params_3{}; + + // 1-dimensional with invalid min/max on 1st dimension + invalid_params_1.sweep_dimensions = {{sweep_parameter::EPSILON_R}}; + invalid_params_1.sweep_dimensions[0].min = 10.0; + invalid_params_1.sweep_dimensions[0].max = 1.0; + invalid_params_1.sweep_dimensions[0].step = 0.1; + + // 2-dimensional with invalid min/max on 2nd dimension + invalid_params_2.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; + invalid_params_2.sweep_dimensions[1].min = 5.5; + invalid_params_2.sweep_dimensions[1].max = 5.4; + invalid_params_2.sweep_dimensions[1].step = 0.1; + + // 3-dimensional with invalid min/max on 3rd dimension + invalid_params_3.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}, + {sweep_parameter::MU_MINUS}}; + invalid_params_3.sweep_dimensions[2].min = -0.4; + invalid_params_3.sweep_dimensions[2].max = -0.5; + invalid_params_3.sweep_dimensions[2].step = 0.01; + + for (const auto& params : {invalid_params_1, invalid_params_2, invalid_params_3}) + { + SECTION("grid_search") + { + CHECK_THROWS_AS(operational_domain_grid_search(lat, std::vector{create_id_tt()}, params), + std::invalid_argument); + } + SECTION("random_sampling") + { + CHECK_THROWS_AS(operational_domain_random_sampling(lat, std::vector{create_id_tt()}, 100, params), + std::invalid_argument); + } + SECTION("flood_fill") + { + CHECK_THROWS_AS(operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 1, params), + std::invalid_argument); + } + SECTION("contour_tracing") + { + CHECK_THROWS_AS(operational_domain_contour_tracing(lat, std::vector{create_id_tt()}, 1, params), + std::invalid_argument); + } + } + } +} + TEST_CASE("BDL wire operational domain computation", "[operational-domain]") { using layout = sidb_cell_clk_lyt_siqad; From 59c989a5af6e7c7115920de5d708dc270390736c Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:21:33 +0200 Subject: [PATCH 71/95] :bug: Fixed operational domain z-dimension handling in the CLI's `opdom` command --- cli/cmd/simulation/opdom.hpp | 192 ++++++++++++++++++++++------------- 1 file changed, 122 insertions(+), 70 deletions(-) diff --git a/cli/cmd/simulation/opdom.hpp b/cli/cmd/simulation/opdom.hpp index cfdfeae29..90b066805 100644 --- a/cli/cmd/simulation/opdom.hpp +++ b/cli/cmd/simulation/opdom.hpp @@ -6,6 +6,7 @@ #define FICTION_CMD_OPDOM_HPP #include +#include #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -52,8 +54,7 @@ class opdom_command : public command add_option("--flood_fill,-f", num_random_samples, "Use flood fill instead of grid search with this many initial random samples"); add_option("--contour_tracing,-c", num_random_samples, - "Use contour tracing instead of grid search with up to this many random " - "samples"); + "Use contour tracing instead of grid search with this many random samples"); add_option("filename", filename, "CSV filename to write the operational domain to")->required(); @@ -62,9 +63,12 @@ class opdom_command : public command add_option("--lambda_tf,-l", simulation_params.lambda_tf, "Thomas-Fermi screening distance (unit: nm)", true); add_option("--mu_minus,-m", simulation_params.mu_minus, "Energy transition level (0/-) (unit: eV)", true); - add_option("--x_sweep", x_sweep, "Sweep parameter of the x dimension [epsilon_r, lambda_tf, mu_minus]", true); - add_option("--y_sweep", y_sweep, "Sweep parameter of the y dimension [epsilon_r, lambda_tf, mu_minus]", true); - add_option("--z_sweep", z_sweep, "Sweep parameter of the z dimension [epsilon_r, lambda_tf, mu_minus]", true); + add_option("--x_sweep,-x", x_sweep, "Sweep parameter of the x dimension [epsilon_r, lambda_tf, mu_minus]", + true); + add_option("--y_sweep,-y", y_sweep, "Sweep parameter of the y dimension [epsilon_r, lambda_tf, mu_minus]", + true); + add_option("--z_sweep,-z", z_sweep, + "Sweep parameter of the z dimension (optional) [epsilon_r, lambda_tf, mu_minus]"); add_option("--x_min", params.sweep_dimensions[0].min, "Minimum value of the x dimension sweep", true); add_option("--x_max", params.sweep_dimensions[0].max, "Maximum value of the x dimension sweep", true); @@ -72,9 +76,9 @@ class opdom_command : public command add_option("--y_min", params.sweep_dimensions[1].min, "Minimum value of the y dimension sweep", true); add_option("--y_max", params.sweep_dimensions[1].max, "Maximum value of the y dimension sweep", true); add_option("--y_step", params.sweep_dimensions[1].step, "Step size of the y dimension sweep", true); - add_option("--z_min", params.sweep_dimensions[2].min, "Minimum value of the y dimension sweep", true); - add_option("--z_max", params.sweep_dimensions[2].max, "Maximum value of the y dimension sweep", true); - add_option("--z_step", params.sweep_dimensions[2].step, "Step size of the y dimension sweep", true); + add_option("--z_min", params.sweep_dimensions[2].min, "Minimum value of the z dimension sweep"); + add_option("--z_max", params.sweep_dimensions[2].max, "Maximum value of the z dimension sweep"); + add_option("--z_step", params.sweep_dimensions[2].step, "Step size of the z dimension sweep"); } protected: @@ -87,6 +91,26 @@ class opdom_command : public command op_domain = {}; stats = {}; + auto& cs = store(); + + // error case: empty cell layout store + if (cs.empty()) + { + env->out() << "[w] no cell layout in store" << std::endl; + reset_params(); + return; + } + + auto& ts = store(); + + // error case: empty truth table store + if (ts.empty()) + { + env->out() << "[w] no truth table in store" << std::endl; + reset_params(); + return; + } + if (simulation_params.epsilon_r <= 0) { env->out() << "[e] epsilon_r must be positive" << std::endl; @@ -100,15 +124,6 @@ class opdom_command : public command return; } - // check for valid x and y parameter bounds - for (const auto& dim : params.sweep_dimensions) - if (dim.min >= dim.max) - { - env->out() << "[e] min must be smaller than max" << std::endl; - reset_params(); - return; - } - // make sure that at most one algorithm is selected const std::array algorithm_selections = {is_set("random_sampling"), is_set("flood_fill"), is_set("contour_tracing")}; @@ -119,55 +134,55 @@ class opdom_command : public command return; } - auto& cs = store(); - - // error case: empty cell layout store - if (cs.empty()) + // make sure that z is not set if y is not, and that y is not set if x is not + if (is_set("z_sweep") && !is_set("y_sweep")) { - env->out() << "[w] no cell layout in store" << std::endl; + env->out() << "[e] z sweep parameter cannot be set if y sweep parameter is not set" << std::endl; + reset_params(); + return; + } + if (is_set("y_sweep") && !is_set("x_sweep")) + { + env->out() << "[e] y sweep parameter cannot be set if x sweep parameter is not set" << std::endl; reset_params(); return; } - auto& ts = store(); + // overwrite the sweeps with their respective lower-case string representations + std::transform(x_sweep.begin(), x_sweep.end(), x_sweep.begin(), ::tolower); + std::transform(y_sweep.begin(), y_sweep.end(), y_sweep.begin(), ::tolower); + std::transform(z_sweep.begin(), z_sweep.end(), z_sweep.begin(), ::tolower); - // error case: empty truth table store - if (ts.empty()) + static constexpr const std::array valid_sweep_params = {"epsilon_r", "lambda_tf", "mu_minus"}; + + // check if x sweep parameter is valid + if (std::find(valid_sweep_params.cbegin(), valid_sweep_params.cend(), x_sweep) == valid_sweep_params.cend()) { - env->out() << "[w] no truth table in store" << std::endl; + env->out() << "[e] invalid x sweep parameter \"" << x_sweep + << "\". Has to be one of [epsilon_r, lambda_tf, " + "mu_minus]" + << std::endl; reset_params(); return; } - // default sweep parameters - if (x_sweep.empty() && y_sweep.empty()) + // check if y sweep parameter is valid + if (std::find(valid_sweep_params.cbegin(), valid_sweep_params.cend(), y_sweep) == valid_sweep_params.cend()) { - x_sweep = "epsilon_r"; - y_sweep = "lambda_tf"; + env->out() << "[e] invalid y sweep parameter \"" << y_sweep + << "\". Has to be one of [epsilon_r, lambda_tf, " + "mu_minus]" + << std::endl; + reset_params(); + return; } - else - { - // overwrite x and y sweep with their respective lower-case string representations - std::transform(x_sweep.begin(), x_sweep.end(), x_sweep.begin(), ::tolower); - std::transform(y_sweep.begin(), y_sweep.end(), y_sweep.begin(), ::tolower); - - static constexpr const std::array valid_sweep_params = {"epsilon_r", "lambda_tf", "mu_minus"}; - - // check if x sweep parameter is valid - if (std::find(valid_sweep_params.cbegin(), valid_sweep_params.cend(), x_sweep) == valid_sweep_params.cend()) - { - env->out() << "[e] invalid x sweep parameter \"" << x_sweep - << "\". Has to be one of [epsilon_r, lambda_tf, " - "mu_minus]" - << std::endl; - reset_params(); - return; - } - // check if y sweep parameter is valid - if (std::find(valid_sweep_params.cbegin(), valid_sweep_params.cend(), y_sweep) == valid_sweep_params.cend()) + // check if z sweep parameter is valid if set + if (is_set("z_sweep")) + { + if (std::find(valid_sweep_params.cbegin(), valid_sweep_params.cend(), z_sweep) == valid_sweep_params.cend()) { - env->out() << "[e] invalid y sweep parameter \"" << y_sweep + env->out() << "[e] invalid z sweep parameter \"" << z_sweep << "\". Has to be one of [epsilon_r, lambda_tf, " "mu_minus]" << std::endl; @@ -204,18 +219,26 @@ class opdom_command : public command params.sweep_dimensions[1].dimension = fiction::sweep_parameter::MU_MINUS; } - // assign z sweep parameters - if (z_sweep == "epsilon_r") - { - params.sweep_dimensions[2].dimension = fiction::sweep_parameter::EPSILON_R; - } - else if (z_sweep == "lambda_tf") + if (is_set("z_sweep")) { - params.sweep_dimensions[2].dimension = fiction::sweep_parameter::LAMBDA_TF; + // assign z sweep parameters + if (z_sweep == "epsilon_r") + { + params.sweep_dimensions[2].dimension = fiction::sweep_parameter::EPSILON_R; + } + else if (z_sweep == "lambda_tf") + { + params.sweep_dimensions[2].dimension = fiction::sweep_parameter::LAMBDA_TF; + } + else if (z_sweep == "mu_minus") + { + params.sweep_dimensions[2].dimension = fiction::sweep_parameter::MU_MINUS; + } } - else if (z_sweep == "mu_minus") + else { - params.sweep_dimensions[2].dimension = fiction::sweep_parameter::MU_MINUS; + // remove z sweep parameter if not set + params.sweep_dimensions.pop_back(); } const auto get_name = [](auto&& lyt_ptr) -> std::string { return fiction::get_name(*lyt_ptr); }; @@ -234,6 +257,7 @@ class opdom_command : public command "Boolean function", get_name(lyt_ptr)) << std::endl; + reset_params(); return; } @@ -262,20 +286,24 @@ class opdom_command : public command params, &stats); } } - catch (std::exception& e) + catch (std::invalid_argument& e) { env->out() << fmt::format("[e] {}", e.what()) << std::endl; + reset_params(); return; } - catch (..) + catch (...) { env->out() << "[e] an unknown error occurred during operational domain computation" << std::endl; + reset_params(); return; } } else { env->out() << fmt::format("[e] {} is not an SiDB layout", get_name(lyt_ptr)) << std::endl; + reset_params(); + return; } }; @@ -294,7 +322,12 @@ class opdom_command : public command /** * Operational domain parameters. */ - fiction::operational_domain_params params{}; + fiction::operational_domain_params params{simulation_params, fiction::sidb_simulation_engine::QUICKEXACT, + std::vector{{ + {fiction::sweep_parameter::EPSILON_R, 1.0, 10.0, 0.1}, + {fiction::sweep_parameter::LAMBDA_TF, 1.0, 10.0, 0.1}, + {fiction::sweep_parameter::MU_MINUS, -0.50, -0.10, 0.025}, + }}}; /** * Operational domain stats. */ @@ -306,11 +339,11 @@ class opdom_command : public command /** * User input for the x dimension sweep parameter. */ - std::string x_sweep{}; + std::string x_sweep{"epsilon_r"}; /** * User input for the y dimension sweep parameter. */ - std::string y_sweep{}; + std::string y_sweep{"lambda_tf"}; /** * User input for the z dimension sweep parameter. */ @@ -327,10 +360,17 @@ class opdom_command : public command /** * Writes the operational domain to the specified CSV file. */ - void write_op_domain() const + void write_op_domain() { static const fiction::write_operational_domain_params write_opdom_params{"1", "0"}; + // if the operational domain call was unsuccessful, do not attempt writing anything + if (op_domain.operational_values.empty()) + { + reset_params(); + return; + } + try { fiction::write_operational_domain(op_domain, filename, write_opdom_params); @@ -338,10 +378,14 @@ class opdom_command : public command catch (const std::exception& e) { env->out() << fmt::format("[e] {}", e.what()) << std::endl; + reset_params(); + return; } catch (...) { env->out() << "[e] an unknown error occurred while writing the operational domain data" << std::endl; + reset_params(); + return; } } /** @@ -365,10 +409,18 @@ class opdom_command : public command void reset_params() { simulation_params = fiction::sidb_simulation_parameters{2, -0.32, 5.6, 5.0}; - params = {}; - x_sweep = {}; - y_sweep = {}; - filename = {}; + + params.simulation_parameters = simulation_params; + params.sweep_dimensions = std::vector{ + {fiction::sweep_parameter::EPSILON_R, 1.0, 10.0, 0.1}, + {fiction::sweep_parameter::LAMBDA_TF, 1.0, 10.0, 0.1}, + {fiction::sweep_parameter::MU_MINUS, -0.50, -0.10, 0.025}, + }; + + x_sweep = "epsilon_r"; + y_sweep = "lambda_tf"; + z_sweep = ""; + filename = ""; } }; From 088bee2974880535418b21b06d056e5daf2a391b Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:24:30 +0200 Subject: [PATCH 72/95] :bug: Fixed command `tt`'s truth table string parsing --- cli/cmd/io/tt.hpp | 10 +++++----- docs/cli.rst | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cli/cmd/io/tt.hpp b/cli/cmd/io/tt.hpp index 3ac3af028..6eeaadaf5 100644 --- a/cli/cmd/io/tt.hpp +++ b/cli/cmd/io/tt.hpp @@ -41,7 +41,7 @@ class tt_command : public command "table must fit the largest variable in the expression, e.g., if c is the largest " "variable, then the truth table have at least three variables.") { - add_option("table", table, "Truth table (prefix with 0x to parse as hexadecimal)"); + add_option("--table,-t", table, "Truth table (prefix with 0x to parse as hexadecimal)"); add_option("--expression,-e", expression, "Creates truth table from expression"); add_option("--random,-r", random_vars, "Creates a random truth table over variables"); } @@ -54,19 +54,19 @@ class tt_command : public command { if (is_set("table") && is_set("expression")) { - env->out() << "[w] 'table' and 'expression' cannot be set at the same time" << std::endl; + env->out() << "[e] 'table' and 'expression' cannot be set at the same time" << std::endl; reset_flags(); return; } if (is_set("table") && is_set("random")) { - env->out() << "[w] 'table' and 'random' cannot be set at the same time" << std::endl; + env->out() << "[e] 'table' and 'random' cannot be set at the same time" << std::endl; reset_flags(); return; } if (is_set("expression") && is_set("random")) { - env->out() << "[w] 'expression' and 'random' cannot be set at the same time" << std::endl; + env->out() << "[e] 'expression' and 'random' cannot be set at the same time" << std::endl; reset_flags(); return; } @@ -140,7 +140,7 @@ class tt_command : public command } else { - env->out() << "[w] no truth table generation approach specified" << std::endl; + env->out() << "[e] no truth table generation approach specified" << std::endl; } reset_flags(); diff --git a/docs/cli.rst b/docs/cli.rst index f9862c765..0c91e385a 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -75,8 +75,8 @@ Truth tables ############ The ``truth_table`` store (``-t``) can hold logic descriptions in binary format as implemented in the ``kitty`` library -by Mathias Soeken. These can either be loaded via command ``tt`` by specifying a bit/hex string or a Boolean expression, -or be obtained by :ref:`simulating` a ``network`` or ``gate_layout`` via command +by Mathias Soeken. These can either be loaded via command ``tt`` by specifying a bit/hex string (``-t``) or a Boolean +expression (``-e``), or be obtained by :ref:`simulating` a ``network`` or ``gate_layout`` via command ``simulate``. Generating a ``truth_table`` from an expression uses the following syntax (from the `kitty documentation `_): @@ -87,7 +87,7 @@ if-then-else, or ``!{!a!b}`` to describe the application of De Morgan's law to ` fit the largest variable in the expression, e.g., if ``c`` is the largest variable, then the truth table has at least three variables. -Alternatively, ``tt 0110`` or ``tt 0xaffe`` generate a ``truth_table`` from bit/hex strings. +For example, ``tt -t 0110`` and ``tt -t 0xaffe`` generate a ``truth_table`` from bit and hex strings, respectively. Logic synthesis ############### From 0fe136fb9727b841692ba037c380e5f85553b9cb Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:28:20 +0200 Subject: [PATCH 73/95] :memo: Added documentation on the new `opdom` CLI functionality --- docs/cli.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/cli.rst b/docs/cli.rst index 0c91e385a..22f1c583a 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -364,8 +364,9 @@ processed by other tools. The parameter space to sweep over can be specified by the user via the flags - ``--x_sweep`` - ``--y_sweep`` +- ``--z_sweep`` which have to be either ``epsilon_r``, ``lambda_tf``, or ``mu_minus``. The default is ``epsilon_r`` for ``--x_sweep`` and -``lambda_tf`` for ``--y_sweep``. +``lambda_tf`` for ``--y_sweep``, with ``--z_sweep`` being an optional third sweep dimension. Additionally, min, max, and step size values can be specified for each parameter using the flags - ``--x_min`` @@ -374,7 +375,12 @@ Additionally, min, max, and step size values can be specified for each parameter - ``--y_min`` - ``--y_max`` - ``--y_step`` -respectively. The default values are 1, 10, and 0.1 on both axis, for min, max, and step, respectively. +- ``--z_min`` +- ``--z_max`` +- ``--z_step`` +respectively. The default values are 1, 10, and 0.1 on x and y axis, for min, max, and step, respectively. The z axis +is not used by default. However, if ``--z_sweep`` is specified, the default values are -0.5, -0.1, and 0.025 for min, max, +and step, respectively, assuming z to be used for ``mu_minus``. By default, grid search is applied to explore the operational domain. The algorithm can be changed by specifying one of the following options: From 1a7eca27949b7601e51e5fd92e3f3ad159de7f64 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:29:00 +0200 Subject: [PATCH 74/95] :memo: Updated the operational domain docstrings for flood fill and contour tracing in accordance with the latest changes --- .../simulation/sidb/operational_domain.hpp | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 7bbcfe6ce..e056073e3 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -1644,9 +1644,9 @@ operational_domain_random_sampling(const Lyt& lyt, const std::vector& spec, * inputs of the truth table. * * This algorithm first uses random sampling to find several operational points within the parameter range. From there, - * it employs the "flood fill" algorithm to explore the operational domain. The algorithm is guaranteed to find all - * operational areas in their entirety if the initial random sampling found at least one operational point within them. - * Thereby, this algorithm works for disconnected operational domains. + * it employs the "flood fill" algorithm to explore the operational domain. The algorithm is guaranteed to determine all + * operational "islands" in their entirety if the initial random sampling found at least one operational point within + * them. Thereby, this algorithm works for disconnected operational domains. * * It performs `samples` uniformly-distributed random samples within the parameter range. From there, it performs * another number of samples equal to the number of points within the operational domain plus the first non-operational @@ -1706,15 +1706,16 @@ operational_domain_flood_fill(const Lyt& lyt, const std::vector& spec, const * implementing the given truth table. The input BDL pairs of the layout are assumed to be in the same order as the * inputs of the truth table. * - * This algorithm first uses random sampling to find a single operational point within the parameter range. From there, + * This algorithm first uses random sampling to find a set of operational point within the parameter range. From there, * it traverses outwards to find the edge of the operational area and performs Moore neighborhood contour tracing to - * explore the contour of the operational domain. If the operational domain is connected, the algorithm is guaranteed to - * find the contours of the entire operational domain within the parameter range if the initial random sampling found an - * operational point. + * explore the contour of the operational domain. This is repeated for all initially sampled points that do not lie + * within a contour. The algorithm is guaranteed to determine the contours of all operational "islands" if the initial + * random sampling found at least one operational point within them. Thereby, this algorithm works for disconnected + * operational domains. * - * It performs up to `samples` uniformly-distributed random samples within the parameter range until an operational - * point is found. From there, it performs another number of samples equal to the distance to an edge of the operational - * area. Finally, it performs up to 8 samples for each contour point (however, the actual number is usually much lower). + * It performs `samples` uniformly-distributed random samples within the parameter range. For each thusly discovered + * operational island, it performs another number of samples equal to the distance to an edge of each operational + * area. Finally, it performs up to 8 samples for each contour point (however, the actual number is usually lower). * For each sample, the algorithm performs one operational check on the layout, where each operational check consists of * up to \f$2^n\f$ exact ground state simulations, where \f$n\f$ is the number of inputs of the layout. Each exact * ground state simulation has exponential complexity in of itself. Therefore, the algorithm is only feasible for small From 19ffd5bb8c82b536d6358137b3a0812152a61bf2 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:35:48 +0200 Subject: [PATCH 75/95] :children_crossing: Added checks for step size values (negative, 0) to operational domain computation --- .../simulation/sidb/operational_domain.hpp | 5 + .../simulation/sidb/operational_domain.cpp | 126 +++++++++++++----- 2 files changed, 94 insertions(+), 37 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index e056073e3..4c761ce6e 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -343,6 +343,11 @@ void validate_sweep_parameters(const operational_domain_params& params) "dimension {}", d)); } + if (params.sweep_dimensions[d].step <= 0.0) + { + throw std::invalid_argument( + fmt::format("Invalid sweep dimension: 'step' size is negative or 0 for dimension {}", d)); + } } } diff --git a/test/algorithms/simulation/sidb/operational_domain.cpp b/test/algorithms/simulation/sidb/operational_domain.cpp index 2645fd752..ffff0b130 100644 --- a/test/algorithms/simulation/sidb/operational_domain.cpp +++ b/test/algorithms/simulation/sidb/operational_domain.cpp @@ -155,47 +155,99 @@ TEST_CASE("Error handling of operational domain algorithms", "[operational-domai operational_domain_params invalid_params_2{}; operational_domain_params invalid_params_3{}; - // 1-dimensional with invalid min/max on 1st dimension - invalid_params_1.sweep_dimensions = {{sweep_parameter::EPSILON_R}}; - invalid_params_1.sweep_dimensions[0].min = 10.0; - invalid_params_1.sweep_dimensions[0].max = 1.0; - invalid_params_1.sweep_dimensions[0].step = 0.1; - - // 2-dimensional with invalid min/max on 2nd dimension - invalid_params_2.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; - invalid_params_2.sweep_dimensions[1].min = 5.5; - invalid_params_2.sweep_dimensions[1].max = 5.4; - invalid_params_2.sweep_dimensions[1].step = 0.1; - - // 3-dimensional with invalid min/max on 3rd dimension - invalid_params_3.sweep_dimensions = {{sweep_parameter::EPSILON_R}, - {sweep_parameter::LAMBDA_TF}, - {sweep_parameter::MU_MINUS}}; - invalid_params_3.sweep_dimensions[2].min = -0.4; - invalid_params_3.sweep_dimensions[2].max = -0.5; - invalid_params_3.sweep_dimensions[2].step = 0.01; - - for (const auto& params : {invalid_params_1, invalid_params_2, invalid_params_3}) + SECTION("min/max mismatch") { - SECTION("grid_search") - { - CHECK_THROWS_AS(operational_domain_grid_search(lat, std::vector{create_id_tt()}, params), - std::invalid_argument); - } - SECTION("random_sampling") - { - CHECK_THROWS_AS(operational_domain_random_sampling(lat, std::vector{create_id_tt()}, 100, params), - std::invalid_argument); - } - SECTION("flood_fill") + // 1-dimensional with invalid min/max on 1st dimension + invalid_params_1.sweep_dimensions = {{sweep_parameter::EPSILON_R}}; + invalid_params_1.sweep_dimensions[0].min = 10.0; + invalid_params_1.sweep_dimensions[0].max = 1.0; + invalid_params_1.sweep_dimensions[0].step = 0.1; + + // 2-dimensional with invalid min/max on 2nd dimension + invalid_params_2.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; + invalid_params_2.sweep_dimensions[1].min = 5.5; + invalid_params_2.sweep_dimensions[1].max = 5.4; + invalid_params_2.sweep_dimensions[1].step = 0.1; + + // 3-dimensional with invalid min/max on 3rd dimension + invalid_params_3.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}, + {sweep_parameter::MU_MINUS}}; + invalid_params_3.sweep_dimensions[2].min = -0.4; + invalid_params_3.sweep_dimensions[2].max = -0.5; + invalid_params_3.sweep_dimensions[2].step = 0.01; + + for (const auto& params : {invalid_params_1, invalid_params_2, invalid_params_3}) { - CHECK_THROWS_AS(operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 1, params), - std::invalid_argument); + SECTION("grid_search") + { + CHECK_THROWS_AS(operational_domain_grid_search(lat, std::vector{create_id_tt()}, params), + std::invalid_argument); + } + SECTION("random_sampling") + { + CHECK_THROWS_AS( + operational_domain_random_sampling(lat, std::vector{create_id_tt()}, 100, params), + std::invalid_argument); + } + SECTION("flood_fill") + { + CHECK_THROWS_AS(operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 1, params), + std::invalid_argument); + } + SECTION("contour_tracing") + { + CHECK_THROWS_AS(operational_domain_contour_tracing(lat, std::vector{create_id_tt()}, 1, params), + std::invalid_argument); + } } - SECTION("contour_tracing") + } + + SECTION("negative step size") + { + // 1-dimensional with negative step size on 1st dimension + invalid_params_1.sweep_dimensions = {{sweep_parameter::EPSILON_R}}; + invalid_params_1.sweep_dimensions[0].min = 1.0; + invalid_params_1.sweep_dimensions[0].max = 10.0; + invalid_params_1.sweep_dimensions[0].step = -0.5; + + // 2-dimensional with negative step size on 2nd dimension + invalid_params_2.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; + invalid_params_2.sweep_dimensions[1].min = 5.5; + invalid_params_2.sweep_dimensions[1].max = 5.6; + invalid_params_2.sweep_dimensions[1].step = -0.1; + + // 3-dimensional with negative step size on 3rd dimension + invalid_params_3.sweep_dimensions = {{sweep_parameter::EPSILON_R}, + {sweep_parameter::LAMBDA_TF}, + {sweep_parameter::MU_MINUS}}; + invalid_params_3.sweep_dimensions[2].min = -0.4; + invalid_params_3.sweep_dimensions[2].max = -0.5; + invalid_params_3.sweep_dimensions[2].step = -0.01; + + for (const auto& params : {invalid_params_1, invalid_params_2, invalid_params_3}) { - CHECK_THROWS_AS(operational_domain_contour_tracing(lat, std::vector{create_id_tt()}, 1, params), - std::invalid_argument); + SECTION("grid_search") + { + CHECK_THROWS_AS(operational_domain_grid_search(lat, std::vector{create_id_tt()}, params), + std::invalid_argument); + } + SECTION("random_sampling") + { + CHECK_THROWS_AS( + operational_domain_random_sampling(lat, std::vector{create_id_tt()}, 100, params), + std::invalid_argument); + } + SECTION("flood_fill") + { + CHECK_THROWS_AS(operational_domain_flood_fill(lat, std::vector{create_id_tt()}, 1, params), + std::invalid_argument); + } + SECTION("contour_tracing") + { + CHECK_THROWS_AS(operational_domain_contour_tracing(lat, std::vector{create_id_tt()}, 1, params), + std::invalid_argument); + } } } } From 760f425729821ceb3310ee47b8cab0528a1d7c13 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:37:40 +0200 Subject: [PATCH 76/95] :memo: Clarified docstring --- .../algorithms/simulation/sidb/operational_domain.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 4c761ce6e..8b413d28a 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -327,8 +327,10 @@ namespace detail /** * This function validates the given sweep parameters for the operational domain computation. It checks if the minimum - * value of any sweep dimension is larger than the corresponding maximum value. If this is the case, an - * `std::invalid_argument` is thrown. + * value of any sweep dimension is larger than the corresponding maximum value. Additionally, it checks if the step size + * of any sweep dimension is negative or zero. + * + * If any of this is the case, an `std::invalid_argument` is thrown. * * @param params The operational domain parameters to validate. */ From 8abc94aa1b48b2361ab4c8e03758222a644a9e2c Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:44:23 +0200 Subject: [PATCH 77/95] :memo: Fixed a documentation copy-paste bug --- .../algorithms/simulation/sidb/operational_domain.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 8b413d28a..16bfdad51 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -1379,13 +1379,13 @@ class operational_domain_impl return neighbors; }; /** - * Returns the 3D Moore neighborhood of the step point at `sp = (x, y)`. The 3D Moore neighborhood is the set of all - * points that are adjacent to `(x, y)` in the 3D space including the diagonals. Thereby, the 3D Moore neighborhood - * contains up to 26 points as points outside of the parameter range are not gathered. The points are returned in - * no particular order. + * Returns the 3D Moore neighborhood of the step point at `sp = (x, y, z)`. The 3D Moore neighborhood is the set of + * all points that are adjacent to `(x, y, z)` in the 3D space including the diagonals. Thereby, the 3D Moore + * neighborhood contains up to 26 points as points outside of the parameter range are not gathered. The points are + * returned in no particular order. * * @param sp Step point to get the 3D Moore neighborhood of. - * @return The 3D Moore neighborhood of the step point at `sp = (x, y)`. + * @return The 3D Moore neighborhood of the step point at `sp = (x, y, z)`. */ [[nodiscard]] std::vector moore_neighborhood_3d(const step_point& sp) const noexcept { From 3debb9198941c6226a4bd1a8954a17a6ea7bba39 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:46:59 +0200 Subject: [PATCH 78/95] :art: `const`ness and include cleanup --- .../simulation/sidb/operational_domain.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/test/algorithms/simulation/sidb/operational_domain.cpp b/test/algorithms/simulation/sidb/operational_domain.cpp index ffff0b130..f1bd44ade 100644 --- a/test/algorithms/simulation/sidb/operational_domain.cpp +++ b/test/algorithms/simulation/sidb/operational_domain.cpp @@ -4,7 +4,6 @@ #include -#include "fiction/layouts/coordinates.hpp" #include "utils/blueprints/layout_blueprints.hpp" #include @@ -13,12 +12,12 @@ #include #include #include -#include #include #include #include +#include #include using namespace fiction; @@ -59,18 +58,18 @@ void check_op_domain_params_and_operational_status( TEST_CASE("Test parameter point", "[operational-domain]") { // Test default constructor - parameter_point p_default; + const parameter_point p_default; REQUIRE(p_default.parameters.empty()); // Test parameterized constructor - std::vector values = {1.0, 2.0, 3.0}; - parameter_point p_param(values); + const std::vector values = {1.0, 2.0, 3.0}; + const parameter_point p_param(values); REQUIRE(p_param.parameters == values); // Test equality operator - parameter_point p1({1.0, 2.0, 3.0}); - parameter_point p2({1.0, 2.0, 3.0}); - parameter_point p3({1.0, 2.0, 3.0000001}); + const parameter_point p1({1.0, 2.0, 3.0}); + const parameter_point p2({1.0, 2.0, 3.0}); + const parameter_point p3({1.0, 2.0, 3.0000001}); SECTION("Equality operator - exact equality") { @@ -83,7 +82,7 @@ TEST_CASE("Test parameter point", "[operational-domain]") } // Test inequality operator - parameter_point p4({1.0, 2.0, 3.1}); + const parameter_point p4({1.0, 2.0, 3.1}); REQUIRE(p1 != p4); // Test structured bindings (get() method) From 3fc8b947599c7ee4c215614378b1fea85b55c3e8 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 18:49:59 +0200 Subject: [PATCH 79/95] :memo: Fixed header date in experiment script --- .../operational_domain/operational_domain_3d_bestagon.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/experiments/operational_domain/operational_domain_3d_bestagon.cpp b/experiments/operational_domain/operational_domain_3d_bestagon.cpp index bcc8bc612..4b1380ba5 100644 --- a/experiments/operational_domain/operational_domain_3d_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_3d_bestagon.cpp @@ -1,5 +1,5 @@ // -// Created by marcel on 08.08.23. +// Created by marcel on 22.07.23. // #include "fiction_experiments.hpp" // experiment class From 06128a2ba302b32fb0ec1f21e6ba71312221e7bb Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 19 Aug 2024 16:51:00 +0000 Subject: [PATCH 80/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 83 ++++++++++++------- 1 file changed, 54 insertions(+), 29 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index a4773cfc7..9b02fff9f 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -6571,18 +6571,18 @@ Parameter ``sp``: The 2D Moore neighborhood of the step point at `sp = (x, y)`.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_moore_neighborhood_3d = -R"doc(Returns the 3D Moore neighborhood of the step point at `sp = (x, y)`. -The 3D Moore neighborhood is the set of all points that are adjacent -to `(x, y)` in the 3D space including the diagonals. Thereby, the 3D -Moore neighborhood contains up to 26 points as points outside of the -parameter range are not gathered. The points are returned in no -particular order. +R"doc(Returns the 3D Moore neighborhood of the step point at `sp = (x, y, +z)`. The 3D Moore neighborhood is the set of all points that are +adjacent to `(x, y, z)` in the 3D space including the diagonals. +Thereby, the 3D Moore neighborhood contains up to 26 points as points +outside of the parameter range are not gathered. The points are +returned in no particular order. Parameter ``sp``: Step point to get the 3D Moore neighborhood of. Returns: - The 3D Moore neighborhood of the step point at `sp = (x, y)`.)doc"; + The 3D Moore neighborhood of the step point at `sp = (x, y, z)`.)doc"; static const char *__doc_fiction_detail_operational_domain_impl_num_dimensions = R"doc(The number of dimensions.)doc"; @@ -7478,6 +7478,18 @@ Parameter ``to_delete``: Reference to the to-delete list to be updated with new coordinates.)doc"; +static const char *__doc_fiction_detail_validate_sweep_parameters = +R"doc(This function validates the given sweep parameters for the operational +domain computation. It checks if the minimum value of any sweep +dimension is larger than the corresponding maximum value. +Additionally, it checks if the step size of any sweep dimension is +negative or zero. + +If any of this is the case, an `std::invalid_argument` is thrown. + +Parameter ``params``: + The operational domain parameters to validate.)doc"; + static const char *__doc_fiction_detail_wire_east = R"doc()doc"; static const char *__doc_fiction_detail_wire_south = R"doc()doc"; @@ -13260,32 +13272,36 @@ defined as the layout implementing the given truth table. The input BDL pairs of the layout are assumed to be in the same order as the inputs of the truth table. -This algorithm first uses random sampling to find a single operational +This algorithm first uses random sampling to find a set of operational point within the parameter range. From there, it traverses outwards to find the edge of the operational area and performs Moore neighborhood -contour tracing to explore the contour of the operational domain. If -the operational domain is connected, the algorithm is guaranteed to -find the contours of the entire operational domain within the -parameter range if the initial random sampling found an operational -point. - -It performs up to `samples` uniformly-distributed random samples -within the parameter range until an operational point is found. From -there, it performs another number of samples equal to the distance to -an edge of the operational area. Finally, it performs up to 8 samples -for each contour point (however, the actual number is usually much -lower). For each sample, the algorithm performs one operational check -on the layout, where each operational check consists of up to -:math:`2^n` exact ground state simulations, where :math:`n` is the -number of inputs of the layout. Each exact ground state simulation has -exponential complexity in of itself. Therefore, the algorithm is only -feasible for small layouts with few inputs. +contour tracing to explore the contour of the operational domain. This +is repeated for all initially sampled points that do not lie within a +contour. The algorithm is guaranteed to determine the contours of all +operational "islands" if the initial random sampling found at least +one operational point within them. Thereby, this algorithm works for +disconnected operational domains. + +It performs `samples` uniformly-distributed random samples within the +parameter range. For each thusly discovered operational island, it +performs another number of samples equal to the distance to an edge of +each operational area. Finally, it performs up to 8 samples for each +contour point (however, the actual number is usually lower). For each +sample, the algorithm performs one operational check on the layout, +where each operational check consists of up to :math:`2^n` exact +ground state simulations, where :math:`n` is the number of inputs of +the layout. Each exact ground state simulation has exponential +complexity in of itself. Therefore, the algorithm is only feasible for +small layouts with few inputs. This flavor of operational domain computation was proposed in \"Reducing the Complexity of Operational Domain Computation in Silicon Dangling Bond Logic\" by M. Walter, J. Drewniok, S. S. H. Ng, K. Walus, and R. Wille in NANOARCH 2023. +This function may throw an `std::invalid_argument` exception if the +given sweep parameters are invalid. + Template parameter ``Lyt``: SiDB cell-level layout type. @@ -13326,10 +13342,10 @@ inputs of the truth table. This algorithm first uses random sampling to find several operational points within the parameter range. From there, it employs the "flood fill" algorithm to explore the operational domain. The algorithm is -guaranteed to find all operational areas in their entirety if the -initial random sampling found at least one operational point within -them. Thereby, this algorithm works for disconnected operational -domains. +guaranteed to determine all operational "islands" in their entirety if +the initial random sampling found at least one operational point +within them. Thereby, this algorithm works for disconnected +operational domains. It performs `samples` uniformly-distributed random samples within the parameter range. From there, it performs another number of samples @@ -13347,6 +13363,9 @@ This flavor of operational domain computation was proposed in Dangling Bond Logic\" by M. Walter, J. Drewniok, S. S. H. Ng, K. Walus, and R. Wille in NANOARCH 2023. +This function may throw an `std::invalid_argument` exception if the +given sweep parameters are invalid. + Template parameter ``Lyt``: SiDB cell-level layout type. @@ -13404,6 +13423,9 @@ Each exact ground state simulation has exponential complexity in of itself. Therefore, the algorithm is only feasible for small layouts with few inputs. +This function may throw an `std::invalid_argument` exception if the +given sweep parameters are invalid. + Template parameter ``Lyt``: SiDB cell-level layout type. @@ -13473,6 +13495,9 @@ inputs of the layout. Each exact ground state simulation has exponential complexity in of itself. Therefore, the algorithm is only feasible for small layouts with few inputs. +This function may throw an `std::invalid_argument` exception if the +given sweep parameters are invalid. + Template parameter ``Lyt``: SiDB cell-level layout type. From 3d14d54430bff405387b6552cc5fbff333ea6f71 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 19:21:21 +0200 Subject: [PATCH 81/95] :bug: Fixed return value of `operational_domain::get_value` --- .../algorithms/simulation/sidb/operational_domain.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 16bfdad51..47c06d878 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -169,14 +169,14 @@ struct operational_domain */ locked_parallel_flat_hash_map operational_values{}; /** - * This function retrieves the value associated with the provided parameter point - * from the operational domain. If the parameter point is found in the domain, - * its corresponding value is returned. Otherwise, a runtime error is thrown. + * This function retrieves the value associated with the provided parameter point from the operational domain. If + * the parameter point is found in the domain, its corresponding value is returned. Otherwise, `std::out_of_range` + * is thrown. * * @param pp The parameter point to look up. * @return The value associated with the parameter point. */ - [[nodiscard]] uint64_t get_value(const parameter_point& pp) const + [[nodiscard]] Value get_value(const parameter_point& pp) const { if (const auto v = contains_parameter_point(operational_values, pp); v.has_value()) { From 535733895529bb14a176b503fa00a1f5d6d04153 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 19:21:47 +0200 Subject: [PATCH 82/95] :snake: Updated pyfiction docstrings with regard to operational domain computation changes --- .../simulation/sidb/operational_domain.hpp | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp index e18088750..1d05bfa56 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp @@ -8,6 +8,7 @@ #include "pyfiction/documentation.hpp" #include "pyfiction/types.hpp" +#include #include #include @@ -52,13 +53,6 @@ inline void operational_domain(pybind11::module& m) namespace py = pybind11; using namespace pybind11::literals; - py::enum_(m, "sweep_parameter", DOC(fiction_sweep_parameter)) - .value("EPSILON_R", fiction::sweep_parameter::EPSILON_R, DOC(fiction_sweep_parameter_EPSILON_R)) - .value("LAMBDA_TF", fiction::sweep_parameter::LAMBDA_TF, DOC(fiction_sweep_parameter_LAMBDA_TF)) - .value("MU_MINUS", fiction::sweep_parameter::MU_MINUS, DOC(fiction_sweep_parameter_MU_MINUS)) - - ; - py::class_(m, "parameter_point", DOC(fiction_parameter_point)) .def(py::init<>(), DOC(fiction_parameter_point_parameter_point)) .def(py::init>(), "values"_a, DOC(fiction_parameter_point_parameter_point_2)) @@ -72,6 +66,13 @@ inline void operational_domain(pybind11::module& m) ; + py::enum_(m, "sweep_parameter", DOC(fiction_sweep_parameter)) + .value("EPSILON_R", fiction::sweep_parameter::EPSILON_R, DOC(fiction_sweep_parameter_EPSILON_R)) + .value("LAMBDA_TF", fiction::sweep_parameter::LAMBDA_TF, DOC(fiction_sweep_parameter_LAMBDA_TF)) + .value("MU_MINUS", fiction::sweep_parameter::MU_MINUS, DOC(fiction_sweep_parameter_MU_MINUS)) + + ; + py::class_>( m, "operational_domain", DOC(fiction_operational_domain)) .def(py::init<>()) @@ -81,12 +82,17 @@ inline void operational_domain(pybind11::module& m) .def_readwrite( "operational_values", &fiction::operational_domain::operational_values, - DOC(fiction_operational_domain_operational_values)); + DOC(fiction_operational_domain_operational_values)) + + .def("get_value", + &fiction::operational_domain::get_value, "point"_a, + DOC(fiction_operational_domain_get_value)) + + ; - // add docu py::class_(m, "operational_domain_value_range", DOC(fiction_operational_domain_value_range)) - .def(py::init<>()) + .def(py::init(), "dimension"_a) .def(py::init(), "dimension"_a, "min"_a, "max"_a, "step"_a) .def_readwrite("dimension", &fiction::operational_domain_value_range::dimension, DOC(fiction_operational_domain_value_range_dimension)) @@ -95,7 +101,9 @@ inline void operational_domain(pybind11::module& m) .def_readwrite("max", &fiction::operational_domain_value_range::max, DOC(fiction_operational_domain_value_range_max)) .def_readwrite("step", &fiction::operational_domain_value_range::step, - DOC(fiction_operational_domain_value_range_step)); + DOC(fiction_operational_domain_value_range_step)) + + ; py::class_(m, "operational_domain_params", DOC(fiction_operational_domain_params)) @@ -106,23 +114,27 @@ inline void operational_domain(pybind11::module& m) DOC(fiction_operational_domain_params_sim_engine)) .def_readwrite("sweep_dimensions", &fiction::operational_domain_params::sweep_dimensions) .def_readwrite("bdl_params", &fiction::operational_domain_params::bdl_params, - DOC(fiction_operational_domain_params_bdl_params)); + DOC(fiction_operational_domain_params_bdl_params)) + + ; py::class_(m, "operational_domain_stats", DOC(fiction_operational_domain_stats)) .def(py::init<>()) - .def_readwrite("time_total", &fiction::operational_domain_stats::time_total, - DOC(fiction_operational_domain_stats_duration)) - .def_readwrite("num_simulator_invocations", &fiction::operational_domain_stats::num_simulator_invocations, - DOC(fiction_operational_domain_stats_num_simulator_invocations)) - .def_readwrite("num_evaluated_parameter_combinations", - &fiction::operational_domain_stats::num_evaluated_parameter_combinations, - DOC(fiction_operational_domain_stats_num_evaluated_parameter_combinations)) - .def_readwrite("num_operational_parameter_combinations", - &fiction::operational_domain_stats::num_operational_parameter_combinations, - DOC(fiction_operational_domain_stats_num_operational_parameter_combinations)) - .def_readwrite("num_non_operational_parameter_combinations", - &fiction::operational_domain_stats::num_non_operational_parameter_combinations, - DOC(fiction_operational_domain_stats_num_non_operational_parameter_combinations)); + .def_readonly("time_total", &fiction::operational_domain_stats::time_total, + DOC(fiction_operational_domain_stats_duration)) + .def_readonly("num_simulator_invocations", &fiction::operational_domain_stats::num_simulator_invocations, + DOC(fiction_operational_domain_stats_num_simulator_invocations)) + .def_readonly("num_evaluated_parameter_combinations", + &fiction::operational_domain_stats::num_evaluated_parameter_combinations, + DOC(fiction_operational_domain_stats_num_evaluated_parameter_combinations)) + .def_readonly("num_operational_parameter_combinations", + &fiction::operational_domain_stats::num_operational_parameter_combinations, + DOC(fiction_operational_domain_stats_num_operational_parameter_combinations)) + .def_readonly("num_non_operational_parameter_combinations", + &fiction::operational_domain_stats::num_non_operational_parameter_combinations, + DOC(fiction_operational_domain_stats_num_non_operational_parameter_combinations)) + + ; // NOTE be careful with the order of the following calls! Python will resolve the first matching overload! From 2b9f60fa6231ddd740ae4301f38b6d603dd95614 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 19 Aug 2024 17:22:51 +0000 Subject: [PATCH 83/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 9b02fff9f..4c71cad7c 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -13394,8 +13394,8 @@ Parameter ``stats``: static const char *__doc_fiction_operational_domain_get_value = R"doc(This function retrieves the value associated with the provided parameter point from the operational domain. If the parameter point is -found in the domain, its corresponding value is returned. Otherwise, a -runtime error is thrown. +found in the domain, its corresponding value is returned. Otherwise, +`std::out_of_range` is thrown. Parameter ``pp``: The parameter point to look up. From 278cf4b5bd651cac575ec10a6b9973a2966a3d36 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 19:23:05 +0200 Subject: [PATCH 84/95] :memo: Fixed Python documentation for `bdl_input_iterator` --- docs/algorithms/iterators.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/algorithms/iterators.rst b/docs/algorithms/iterators.rst index 0d590dddf..52422782f 100644 --- a/docs/algorithms/iterators.rst +++ b/docs/algorithms/iterators.rst @@ -27,5 +27,7 @@ BDL Input Iterator :members: .. tab:: Python - .. autoclass:: mnt.pyfiction.bdl_input_iterator + .. autoclass:: mnt.pyfiction.bdl_input_iterator_100 + :members: + .. autoclass:: mnt.pyfiction.bdl_input_iterator_111 :members: From 193e273a9b09729d82f26a1234ad7c88b02d4b96 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 19:26:31 +0200 Subject: [PATCH 85/95] :art: Removed unused include --- .../pyfiction/algorithms/simulation/sidb/operational_domain.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp index 1d05bfa56..a4906e860 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp @@ -15,7 +15,6 @@ #include #include -#include #include namespace pyfiction From 05ff17e55906225a71be649085022c16dab7c21a Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 19:30:18 +0200 Subject: [PATCH 86/95] :art: Moved `contains_parameter_point` and `find_key_with_tolerance` to the `detail` namespace --- docs/algorithms/sidb_simulation.rst | 2 - .../simulation/sidb/operational_domain.hpp | 88 +++++++++---------- 2 files changed, 44 insertions(+), 46 deletions(-) diff --git a/docs/algorithms/sidb_simulation.rst b/docs/algorithms/sidb_simulation.rst index dd35c7ce5..c11b532bb 100644 --- a/docs/algorithms/sidb_simulation.rst +++ b/docs/algorithms/sidb_simulation.rst @@ -238,8 +238,6 @@ Operational Domain Computation .. doxygenenum:: fiction::sweep_parameter .. doxygenstruct:: fiction::operational_domain :members: - .. doxygenfunction:: fiction::contains_parameter_point - .. doxygenfunction:: fiction::find_key_with_tolerance .. doxygenstruct:: fiction::operational_domain_params :members: .. doxygenstruct:: fiction::operational_domain_stats diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 47c06d878..b231aac87 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -222,50 +222,6 @@ struct operational_domain_value_range */ double step{0.1}; }; -/** - * This function checks for the containment of a parameter point, specified by `key`, in the provided map `map`. If the - * parameter point is found in the map, the associated `MapType::value_type` is returned. Otherwise, `std::nullopt` is - * returned. - * - * @tparam MapType The type of the map containing parameter points as keys. - * @param map The map in which to search for `key`. - * @param key The parameter point to search for in `map`. - * @return The associated `MapType::value_type` of `key` in `map`, or `std::nullopt` if `key` is not contained in `map`. - */ -template -[[maybe_unused]] static std::optional -contains_parameter_point(const MapType& map, const typename MapType::key_type& key) -{ - static_assert(std::is_same_v, "Map key type must be parameter_point"); - - std::optional result = std::nullopt; - - map.if_contains(key, [&result](const typename MapType::value_type& v) { result.emplace(v); }); - - return result; -} -/** - * This function searches for a floating-point value specified by the `key` in the provided map `map`, applying a - * tolerance specified by `fiction::physical_constants::POP_STABILITY_ERR`. Each key in the map is compared to the - * specified key within this tolerance. - * - * @tparam MapType The type of the map containing parameter points as keys. - * @param map The map containing parameter points as keys and associated values. - * @param key The parameter point to search for in the map. - * @return An iterator to the found parameter point in the map, or `map.cend()` if not found. - */ -template -[[maybe_unused]] static typename MapType::const_iterator find_key_with_tolerance(const MapType& map, - const typename MapType::key_type& key) -{ - static_assert(std::is_floating_point_v, "Map key type must be floating-point"); - - constexpr double tolerance = physical_constants::POP_STABILITY_ERR; - - auto compare_keys = [&key, &tolerance](const auto& pair) { return std::abs(pair.first - key) < tolerance; }; - - return std::find_if(map.cbegin(), map.cend(), compare_keys); -} /** * Parameters for the operational domain computation. The parameters are used across the different operational domain * computation algorithms. @@ -352,6 +308,50 @@ void validate_sweep_parameters(const operational_domain_params& params) } } } +/** + * This function checks for the containment of a parameter point, specified by `key`, in the provided map `map`. If the + * parameter point is found in the map, the associated `MapType::value_type` is returned. Otherwise, `std::nullopt` is + * returned. + * + * @tparam MapType The type of the map containing parameter points as keys. + * @param map The map in which to search for `key`. + * @param key The parameter point to search for in `map`. + * @return The associated `MapType::value_type` of `key` in `map`, or `std::nullopt` if `key` is not contained in `map`. + */ +template +[[maybe_unused]] static std::optional +contains_parameter_point(const MapType& map, const typename MapType::key_type& key) +{ + static_assert(std::is_same_v, "Map key type must be parameter_point"); + + std::optional result = std::nullopt; + + map.if_contains(key, [&result](const typename MapType::value_type& v) { result.emplace(v); }); + + return result; +} +/** + * This function searches for a floating-point value specified by the `key` in the provided map `map`, applying a + * tolerance specified by `fiction::physical_constants::POP_STABILITY_ERR`. Each key in the map is compared to the + * specified key within this tolerance. + * + * @tparam MapType The type of the map containing parameter points as keys. + * @param map The map containing parameter points as keys and associated values. + * @param key The parameter point to search for in the map. + * @return An iterator to the found parameter point in the map, or `map.cend()` if not found. + */ +template +[[maybe_unused]] static typename MapType::const_iterator find_key_with_tolerance(const MapType& map, + const typename MapType::key_type& key) +{ + static_assert(std::is_floating_point_v, "Map key type must be floating-point"); + + constexpr double tolerance = physical_constants::POP_STABILITY_ERR; + + auto compare_keys = [&key, &tolerance](const auto& pair) { return std::abs(pair.first - key) < tolerance; }; + + return std::find_if(map.cbegin(), map.cend(), compare_keys); +} template class operational_domain_impl From e1f608a96d0de43790ca0a7823aabbae947c34ad Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 19 Aug 2024 17:31:33 +0000 Subject: [PATCH 87/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 76 +++++++++---------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 4c71cad7c..69a91d7c7 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -2412,25 +2412,6 @@ Parameter ``n``: Returns: Columnar clocking scheme.)doc"; -static const char *__doc_fiction_contains_parameter_point = -R"doc(This function checks for the containment of a parameter point, -specified by `key`, in the provided map `map`. If the parameter point -is found in the map, the associated `MapType::value_type` is returned. -Otherwise, `std::nullopt` is returned. - -Template parameter ``MapType``: - The type of the map containing parameter points as keys. - -Parameter ``map``: - The map in which to search for `key`. - -Parameter ``key``: - The parameter point to search for in `map`. - -Returns: - The associated `MapType::value_type` of `key` in `map`, or - `std::nullopt` if `key` is not contained in `map`.)doc"; - static const char *__doc_fiction_convert_array = R"doc(Converts an array of size `N` and type `T` to an array of size `N` and type `ElementType` by applying `static_cast` at compile time. @@ -3998,6 +3979,25 @@ static const char *__doc_fiction_detail_connect_and_place = R"doc()doc"; static const char *__doc_fiction_detail_connect_and_place_2 = R"doc()doc"; +static const char *__doc_fiction_detail_contains_parameter_point = +R"doc(This function checks for the containment of a parameter point, +specified by `key`, in the provided map `map`. If the parameter point +is found in the map, the associated `MapType::value_type` is returned. +Otherwise, `std::nullopt` is returned. + +Template parameter ``MapType``: + The type of the map containing parameter points as keys. + +Parameter ``map``: + The map in which to search for `key`. + +Parameter ``key``: + The parameter point to search for in `map`. + +Returns: + The associated `MapType::value_type` of `key` in `map`, or + `std::nullopt` if `key` is not contained in `map`.)doc"; + static const char *__doc_fiction_detail_convert_array = R"doc(Based on https://stackoverflow.com/questions/57756557/initializing-a- stdarray-with-a-constant-value)doc"; @@ -5279,6 +5279,25 @@ static const char *__doc_fiction_detail_fanout_substitution_impl_ps = R"doc()doc static const char *__doc_fiction_detail_fanout_substitution_impl_run = R"doc()doc"; +static const char *__doc_fiction_detail_find_key_with_tolerance = +R"doc(This function searches for a floating-point value specified by the +`key` in the provided map `map`, applying a tolerance specified by +`fiction::physical_constants::POP_STABILITY_ERR`. Each key in the map +is compared to the specified key within this tolerance. + +Template parameter ``MapType``: + The type of the map containing parameter points as keys. + +Parameter ``map``: + The map containing parameter points as keys and associated values. + +Parameter ``key``: + The parameter point to search for in the map. + +Returns: + An iterator to the found parameter point in the map, or + `map.cend()` if not found.)doc"; + static const char *__doc_fiction_detail_fix_wires = R"doc(Utility function to move wires that cross over empty tiles down one layer. This can happen if the wiring of a gate is deleted. @@ -9298,25 +9317,6 @@ Parameter ``s_last``: first 2-element sub-sequence shared between the two ranges, or `last` if no such shared sub-sequence exists.)doc"; -static const char *__doc_fiction_find_key_with_tolerance = -R"doc(This function searches for a floating-point value specified by the -`key` in the provided map `map`, applying a tolerance specified by -`fiction::physical_constants::POP_STABILITY_ERR`. Each key in the map -is compared to the specified key within this tolerance. - -Template parameter ``MapType``: - The type of the map containing parameter points as keys. - -Parameter ``map``: - The map containing parameter points as keys and associated values. - -Parameter ``key``: - The parameter point to search for in the map. - -Returns: - An iterator to the found parameter point in the map, or - `map.cend()` if not found.)doc"; - static const char *__doc_fiction_flat_top_hex = R"doc(\verbatim _____ / \ / \ \ / \_____/ \endverbatim)doc"; static const char *__doc_fiction_foreach_edge = From bfb576579cdbaf516ad5e9b4e7188724d7333471 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 19:43:53 +0200 Subject: [PATCH 88/95] :bug: Added missing forward-declaration to fix compiler error --- .../simulation/sidb/operational_domain.hpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index b231aac87..18f95f3b6 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -139,7 +139,15 @@ enum class sweep_parameter : uint8_t */ MU_MINUS }; - +namespace detail +{ +/** + * Forward-declaration for `operational_domain`. + */ +template +std::optional contains_parameter_point(const MapType& map, + const typename MapType::key_type& key); +} // namespace detail /** * An operational domain is a set of simulation parameter values for which a given SiDB layout is logically operational. * This means that a layout is deemed operational if the layout's ground state corresponds with a given Boolean function @@ -178,7 +186,7 @@ struct operational_domain */ [[nodiscard]] Value get_value(const parameter_point& pp) const { - if (const auto v = contains_parameter_point(operational_values, pp); v.has_value()) + if (const auto v = detail::contains_parameter_point(operational_values, pp); v.has_value()) { return v.value().second; } @@ -319,8 +327,8 @@ void validate_sweep_parameters(const operational_domain_params& params) * @return The associated `MapType::value_type` of `key` in `map`, or `std::nullopt` if `key` is not contained in `map`. */ template -[[maybe_unused]] static std::optional -contains_parameter_point(const MapType& map, const typename MapType::key_type& key) +std::optional contains_parameter_point(const MapType& map, + const typename MapType::key_type& key) { static_assert(std::is_same_v, "Map key type must be parameter_point"); @@ -341,8 +349,7 @@ contains_parameter_point(const MapType& map, const typename MapType::key_type& k * @return An iterator to the found parameter point in the map, or `map.cend()` if not found. */ template -[[maybe_unused]] static typename MapType::const_iterator find_key_with_tolerance(const MapType& map, - const typename MapType::key_type& key) +typename MapType::const_iterator find_key_with_tolerance(const MapType& map, const typename MapType::key_type& key) { static_assert(std::is_floating_point_v, "Map key type must be floating-point"); From 3eb8e38cf18dfad2eeef4153cf9d073c68ffbd5b Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Mon, 19 Aug 2024 17:44:49 +0000 Subject: [PATCH 89/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 69a91d7c7..8301bf82b 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -3979,7 +3979,9 @@ static const char *__doc_fiction_detail_connect_and_place = R"doc()doc"; static const char *__doc_fiction_detail_connect_and_place_2 = R"doc()doc"; -static const char *__doc_fiction_detail_contains_parameter_point = +static const char *__doc_fiction_detail_contains_parameter_point = R"doc(Forward-declaration for `operational_domain`.)doc"; + +static const char *__doc_fiction_detail_contains_parameter_point_2 = R"doc(This function checks for the containment of a parameter point, specified by `key`, in the provided map `map`. If the parameter point is found in the map, the associated `MapType::value_type` is returned. From 91f95dea03ace17c50dda20d474a34c344e4858d Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Mon, 19 Aug 2024 23:42:50 +0200 Subject: [PATCH 90/95] :bug: Fixed compiler error in `determine_physically_valid_parameters` --- .../determine_physically_valid_parameters.cpp | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp b/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp index 655a9ad47..78663567f 100644 --- a/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp +++ b/test/algorithms/simulation/sidb/determine_physically_valid_parameters.cpp @@ -86,19 +86,23 @@ TEST_CASE("Determine physical parameters for CDS of SiQAD Y-shaped AND gate, 10 const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); CHECK(valid_parameters.operational_values.size() == 98); - const auto p1 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.9, 5.5}}); + const auto p1 = + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.9, 5.5}}); REQUIRE(p1.has_value()); CHECK(p1->second == 1); - const auto p2 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}); + const auto p2 = + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}); REQUIRE(p2.has_value()); CHECK(p2->second == 0); - const auto p3 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}); + const auto p3 = + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 4.4}}); REQUIRE(p3.has_value()); CHECK(p3->second == 0); - const auto p4 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{6.0, 6.0}}); + const auto p4 = + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{6.0, 6.0}}); REQUIRE(p4.has_value()); CHECK(p4->second == 1); } @@ -160,19 +164,23 @@ TEST_CASE( const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); REQUIRE(valid_parameters.operational_values.size() == 100); - const auto p1 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0}}); + const auto p1 = + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0}}); REQUIRE(p1.has_value()); CHECK(p1->second == 0); - const auto p2 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.0, 5.9}}); + const auto p2 = + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.0, 5.9}}); REQUIRE(p2.has_value()); CHECK(p2->second == 2); - const auto p3 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.4, 5.3}}); + const auto p3 = + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.4, 5.3}}); REQUIRE(p3.has_value()); CHECK(p3->second == 1); - const auto p4 = contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 5.3}}); + const auto p4 = + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.8, 5.3}}); REQUIRE(p4.has_value()); CHECK(p4->second == 0); } @@ -218,22 +226,22 @@ TEST_CASE( const auto valid_parameters = determine_physically_valid_parameters(cds, op_domain_params); REQUIRE(valid_parameters.operational_values.size() == 27); const auto p1 = - contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.32}}); + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.32}}); REQUIRE(p1.has_value()); CHECK(p1->second == 0); const auto p2 = - contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.33}}); + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.33}}); REQUIRE(p2.has_value()); CHECK(p2->second == 0); const auto p3 = - contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.31}}); + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.6, 5.0, -0.31}}); REQUIRE(p3.has_value()); CHECK(p3->second == 1); const auto p4 = - contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.7, 5.2, -0.33}}); + detail::contains_parameter_point(valid_parameters.operational_values, parameter_point{{5.7, 5.2, -0.33}}); REQUIRE(p4.has_value()); CHECK(p4->second == 0); } From 4da7e0bdb92f85cf717e22b37383024ac47bc3e1 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 20 Aug 2024 12:21:09 +0200 Subject: [PATCH 91/95] :art: Incorporated Jan's feedback --- .../simulation/sidb/operational_domain.hpp | 3 +- cli/cmd/simulation/opdom.hpp | 33 ++++++++++++++++++- .../operational_domain_3d_bestagon.cpp | 7 ++-- .../operational_domain_3d_siqad.cpp | 5 ++- .../operational_domain_bestagon.cpp | 5 ++- .../operational_domain_siqad.cpp | 5 ++- .../simulation/sidb/operational_domain.hpp | 25 +++++++------- .../fiction/io/write_operational_domain.hpp | 26 ++++++++++++--- test/io/write_operational_domain.cpp | 4 +-- 9 files changed, 87 insertions(+), 26 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp index a4906e860..3a85fae52 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/operational_domain.hpp @@ -111,7 +111,8 @@ inline void operational_domain(pybind11::module& m) DOC(fiction_operational_domain_params_simulation_parameters)) .def_readwrite("sim_engine", &fiction::operational_domain_params::sim_engine, DOC(fiction_operational_domain_params_sim_engine)) - .def_readwrite("sweep_dimensions", &fiction::operational_domain_params::sweep_dimensions) + .def_readwrite("sweep_dimensions", &fiction::operational_domain_params::sweep_dimensions, + DOC(fiction_operational_domain_params_sweep_dimensions)) .def_readwrite("bdl_params", &fiction::operational_domain_params::bdl_params, DOC(fiction_operational_domain_params_bdl_params)) diff --git a/cli/cmd/simulation/opdom.hpp b/cli/cmd/simulation/opdom.hpp index 90b066805..6905e2068 100644 --- a/cli/cmd/simulation/opdom.hpp +++ b/cli/cmd/simulation/opdom.hpp @@ -31,7 +31,22 @@ namespace alice { /** + * Executes operational domain computation for the current SiDB cell-level layout in store. The operational domain is a + * set of simulation parameter values for which a given SiDB layout is logically operational. This means that a layout + * is deemed operational if the layout's ground state corresponds with a given Boolean function at the layout's outputs + * for all possible input combinations. * + * The computation comes in different flavors: + * - Grid search: Evaluates all possible parameter combinations within the specified ranges. + * - Random sampling: Evaluates a specified number of random parameter combinations. + * - Flood fill: Evaluates a specified number of random parameter combinations and then performs a flood fill to find + * the operational domain. + * - Contour tracing: Evaluates a specified number of random parameter combinations and then performs contour tracing + * to find the edges of the operational domain. + * + * The operational domain is written to a CSV file, which can be used for further analysis or visualization. + * + * For more information, see algorithms/simulation/sidb/operational_domain.hpp. */ class opdom_command : public command { @@ -57,6 +72,9 @@ class opdom_command : public command "Use contour tracing instead of grid search with this many random samples"); add_option("filename", filename, "CSV filename to write the operational domain to")->required(); + add_flag( + "--omit_non_op_samples,-o", omit_non_operational_samples, + "Omit non-operational samples in the CSV file to reduce file size and increase visibility in 3D plots"); add_option("--epsilon_r,-e", simulation_params.epsilon_r, "Electric permittivity of the substrate (unit-less)", true); @@ -352,6 +370,10 @@ class opdom_command : public command * CSV filename to write the operational domain to. */ std::string filename{}; + /** + * Flag to omit non-operational samples. + */ + bool omit_non_operational_samples = false; /** * The operational domain. */ @@ -362,7 +384,14 @@ class opdom_command : public command */ void write_op_domain() { - static const fiction::write_operational_domain_params write_opdom_params{"1", "0"}; + // set up parameters + fiction::write_operational_domain_params write_opdom_params{}; + write_opdom_params.non_operational_tag = "0"; + write_opdom_params.operational_tag = "1"; + write_opdom_params.writing_mode = + omit_non_operational_samples ? + fiction::write_operational_domain_params::sample_writing_mode::OPERATIONAL_ONLY : + fiction::write_operational_domain_params::sample_writing_mode::ALL_SAMPLES; // if the operational domain call was unsuccessful, do not attempt writing anything if (op_domain.operational_values.empty()) @@ -421,6 +450,8 @@ class opdom_command : public command y_sweep = "lambda_tf"; z_sweep = ""; filename = ""; + + omit_non_operational_samples = false; } }; diff --git a/experiments/operational_domain/operational_domain_3d_bestagon.cpp b/experiments/operational_domain/operational_domain_3d_bestagon.cpp index 4b1380ba5..62ce3696c 100644 --- a/experiments/operational_domain/operational_domain_3d_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_3d_bestagon.cpp @@ -1,5 +1,5 @@ // -// Created by marcel on 22.07.23. +// Created by marcel on 22.07.24. // #include "fiction_experiments.hpp" // experiment class @@ -71,7 +71,10 @@ int main() // NOLINT op_domain_params.sweep_dimensions[2].step = 0.0025; // write operational domain parameters - const write_operational_domain_params write_op_domain_params{"1", "0", false}; + write_operational_domain_params write_op_domain_params{}; + write_op_domain_params.non_operational_tag = "0"; + write_op_domain_params.operational_tag = "1"; + write_op_domain_params.writing_mode = write_operational_domain_params::sample_writing_mode::OPERATIONAL_ONLY; static const std::string folder = fmt::format("{}bestagon_gates_type_tags/", EXPERIMENTS_PATH); diff --git a/experiments/operational_domain/operational_domain_3d_siqad.cpp b/experiments/operational_domain/operational_domain_3d_siqad.cpp index dcb50388b..80a0db0e1 100644 --- a/experiments/operational_domain/operational_domain_3d_siqad.cpp +++ b/experiments/operational_domain/operational_domain_3d_siqad.cpp @@ -71,7 +71,10 @@ int main() // NOLINT op_domain_params.sweep_dimensions[2].step = 0.0025; // write operational domain parameters - static const write_operational_domain_params write_op_domain_params{"1", "0", false}; + write_operational_domain_params write_op_domain_params{}; + write_op_domain_params.non_operational_tag = "0"; + write_op_domain_params.operational_tag = "1"; + write_op_domain_params.writing_mode = write_operational_domain_params::sample_writing_mode::OPERATIONAL_ONLY; static const std::string folder = fmt::format("{}siqad_gates_type_tags/", EXPERIMENTS_PATH); diff --git a/experiments/operational_domain/operational_domain_bestagon.cpp b/experiments/operational_domain/operational_domain_bestagon.cpp index e4e8fa173..767b2489b 100644 --- a/experiments/operational_domain/operational_domain_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_bestagon.cpp @@ -70,7 +70,10 @@ int main() // NOLINT op_domain_params.sweep_dimensions[1].step = 0.05; // write operational domain parameters - const write_operational_domain_params write_op_domain_params{"1", "0"}; + write_operational_domain_params write_op_domain_params{}; + write_op_domain_params.non_operational_tag = "0"; + write_op_domain_params.operational_tag = "1"; + write_op_domain_params.writing_mode = write_operational_domain_params::sample_writing_mode::ALL_SAMPLES; static const std::string folder = fmt::format("{}bestagon_gates_type_tags/", EXPERIMENTS_PATH); diff --git a/experiments/operational_domain/operational_domain_siqad.cpp b/experiments/operational_domain/operational_domain_siqad.cpp index f90b9779e..ab7f50488 100644 --- a/experiments/operational_domain/operational_domain_siqad.cpp +++ b/experiments/operational_domain/operational_domain_siqad.cpp @@ -70,7 +70,10 @@ int main() // NOLINT op_domain_params.sweep_dimensions[1].step = 0.05; // write operational domain parameters - static const write_operational_domain_params write_op_domain_params{"1", "0"}; + write_operational_domain_params write_op_domain_params{}; + write_op_domain_params.non_operational_tag = "0"; + write_op_domain_params.operational_tag = "1"; + write_op_domain_params.writing_mode = write_operational_domain_params::sample_writing_mode::ALL_SAMPLES; static const std::string folder = fmt::format("{}siqad_gates_type_tags/", EXPERIMENTS_PATH); diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 18f95f3b6..c85a90e39 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -474,13 +474,13 @@ class operational_domain_impl { mockturtle::stopwatch stop{stats.time_total}; - const auto all_index_combination = cartesian_combinations(indices); + const auto all_index_combinations = cartesian_combinations(indices); - std::vector all_step_points; - all_step_points.reserve(all_index_combination.size()); + std::vector all_step_points{}; + all_step_points.reserve(all_index_combinations.size()); - std::transform(all_index_combination.begin(), all_index_combination.end(), std::back_inserter(all_step_points), - [](const auto& comb) { return step_point{comb}; }); + std::transform(all_index_combinations.cbegin(), all_index_combinations.cend(), + std::back_inserter(all_step_points), [](const auto& comb) noexcept { return step_point{comb}; }); // shuffle the step points to simulate in random order. This helps with load-balancing since // operational/non-operational points are usually clustered. However, non-operational points can be simulated @@ -712,10 +712,11 @@ class operational_domain_impl mockturtle::stopwatch stop{stats.time_total}; - const auto all_step_points = cartesian_combinations(indices); + // Cartesian product of all step point indices + const auto all_index_combinations = cartesian_combinations(indices); // calculate the size of each slice - const auto slice_size = (all_step_points.size() + num_threads - 1) / num_threads; + const auto slice_size = (all_index_combinations.size() + num_threads - 1) / num_threads; std::vector threads{}; threads.reserve(num_threads); @@ -724,7 +725,7 @@ class operational_domain_impl for (auto i = 0ul; i < num_threads; ++i) { const auto start = i * slice_size; - const auto end = std::min(start + slice_size, all_step_points.size()); + const auto end = std::min(start + slice_size, all_index_combinations.size()); if (start >= end) { @@ -732,12 +733,12 @@ class operational_domain_impl } threads.emplace_back( - [this, &lyt, start, end, &all_step_points] + [this, &lyt, start, end, &all_index_combinations] { - for (auto it = all_step_points.cbegin() + static_cast(start); - it != all_step_points.cbegin() + static_cast(end); ++it) + for (auto it = all_index_combinations.cbegin() + static_cast(start); + it != all_index_combinations.cbegin() + static_cast(end); ++it) { - is_step_point_suitable(lyt, step_point{*it}); + is_step_point_suitable(lyt, step_point{*it}); // construct a step_point } }); } diff --git a/include/fiction/io/write_operational_domain.hpp b/include/fiction/io/write_operational_domain.hpp index b0585b130..5d80c42a7 100644 --- a/include/fiction/io/write_operational_domain.hpp +++ b/include/fiction/io/write_operational_domain.hpp @@ -9,6 +9,7 @@ #include "fiction/algorithms/simulation/sidb/operational_domain.hpp" #include "fiction/io/csv_writer.hpp" +#include #include #include #include @@ -23,6 +24,20 @@ namespace fiction */ struct write_operational_domain_params { + /** + * Mode selector for writing samples to file. + */ + enum class sample_writing_mode : uint8_t + { + /** + * Write all samples, including non-operational ones. This may lead to large file sizes. + */ + ALL_SAMPLES, + /** + * Write operational samples only. This can drastically reduce file size and help with visibility in 3D plots. + */ + OPERATIONAL_ONLY + }; /** * The tag used to represent the operational value of a parameter set. */ @@ -32,11 +47,11 @@ struct write_operational_domain_params */ std::string_view non_operational_tag = "0"; /** - * Whether to write non-operational samples to the CSV file. If set to `false`, only operational samples are - * written. This yields a significantly smaller CSV file. It is recommended to set this option for 3D plots because - * the non-operational samples would shadow the operational samples anyway. + * Whether to write non-operational samples to the CSV file. If set to `OPERATIONAL_ONLY`, operational samples are + * written exclusively. This yields a significantly smaller CSV file. It is recommended to set this option for 3D + * plots because the non-operational samples would shadow the operational samples anyway. */ - bool write_non_operational_samples = true; + sample_writing_mode writing_mode = sample_writing_mode::ALL_SAMPLES; }; namespace detail @@ -125,7 +140,8 @@ inline void write_operational_domain(const operational_domain expected{"epsilon_r,lambda_tf,operational status", "0,0,1"}; @@ -158,7 +158,7 @@ TEST_CASE("Write operational domain with floating-point parameter values", "[wri SECTION("skip non-operational samples") { write_operational_domain_params params{}; - params.write_non_operational_samples = false; + params.writing_mode = write_operational_domain_params::sample_writing_mode::OPERATIONAL_ONLY; std::set expected{"epsilon_r,lambda_tf,operational status", "0.1,0.2,1", "1.2,1.4,1"}; From b69819c8f7bdbafa58d2f649a4c9af0ce62d86a1 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 20 Aug 2024 13:36:55 +0200 Subject: [PATCH 92/95] :art: Restructured code in an effort to circumvent the alice bug that doesn't reset the CLI parameters properly --- cli/cmd/simulation/opdom.hpp | 81 +++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/cli/cmd/simulation/opdom.hpp b/cli/cmd/simulation/opdom.hpp index 6905e2068..6a03115fe 100644 --- a/cli/cmd/simulation/opdom.hpp +++ b/cli/cmd/simulation/opdom.hpp @@ -88,15 +88,15 @@ class opdom_command : public command add_option("--z_sweep,-z", z_sweep, "Sweep parameter of the z dimension (optional) [epsilon_r, lambda_tf, mu_minus]"); - add_option("--x_min", params.sweep_dimensions[0].min, "Minimum value of the x dimension sweep", true); - add_option("--x_max", params.sweep_dimensions[0].max, "Maximum value of the x dimension sweep", true); - add_option("--x_step", params.sweep_dimensions[0].step, "Step size of the x dimension sweep", true); - add_option("--y_min", params.sweep_dimensions[1].min, "Minimum value of the y dimension sweep", true); - add_option("--y_max", params.sweep_dimensions[1].max, "Maximum value of the y dimension sweep", true); - add_option("--y_step", params.sweep_dimensions[1].step, "Step size of the y dimension sweep", true); - add_option("--z_min", params.sweep_dimensions[2].min, "Minimum value of the z dimension sweep"); - add_option("--z_max", params.sweep_dimensions[2].max, "Maximum value of the z dimension sweep"); - add_option("--z_step", params.sweep_dimensions[2].step, "Step size of the z dimension sweep"); + add_option("--x_min", sweep_dimensions[0].min, "Minimum value of the x dimension sweep", true); + add_option("--x_max", sweep_dimensions[0].max, "Maximum value of the x dimension sweep", true); + add_option("--x_step", sweep_dimensions[0].step, "Step size of the x dimension sweep", true); + add_option("--y_min", sweep_dimensions[1].min, "Minimum value of the y dimension sweep", true); + add_option("--y_max", sweep_dimensions[1].max, "Maximum value of the y dimension sweep", true); + add_option("--y_step", sweep_dimensions[1].step, "Step size of the y dimension sweep", true); + add_option("--z_min", sweep_dimensions[2].min, "Minimum value of the z dimension sweep"); + add_option("--z_max", sweep_dimensions[2].max, "Maximum value of the z dimension sweep"); + add_option("--z_step", sweep_dimensions[2].step, "Step size of the z dimension sweep"); } protected: @@ -212,29 +212,29 @@ class opdom_command : public command // assign x sweep parameters if (x_sweep == "epsilon_r") { - params.sweep_dimensions[0].dimension = fiction::sweep_parameter::EPSILON_R; + sweep_dimensions[0].dimension = fiction::sweep_parameter::EPSILON_R; } else if (x_sweep == "lambda_tf") { - params.sweep_dimensions[0].dimension = fiction::sweep_parameter::LAMBDA_TF; + sweep_dimensions[0].dimension = fiction::sweep_parameter::LAMBDA_TF; } else if (x_sweep == "mu_minus") { - params.sweep_dimensions[0].dimension = fiction::sweep_parameter::MU_MINUS; + sweep_dimensions[0].dimension = fiction::sweep_parameter::MU_MINUS; } // assign y sweep parameters if (y_sweep == "epsilon_r") { - params.sweep_dimensions[1].dimension = fiction::sweep_parameter::EPSILON_R; + sweep_dimensions[1].dimension = fiction::sweep_parameter::EPSILON_R; } else if (y_sweep == "lambda_tf") { - params.sweep_dimensions[1].dimension = fiction::sweep_parameter::LAMBDA_TF; + sweep_dimensions[1].dimension = fiction::sweep_parameter::LAMBDA_TF; } else if (y_sweep == "mu_minus") { - params.sweep_dimensions[1].dimension = fiction::sweep_parameter::MU_MINUS; + sweep_dimensions[1].dimension = fiction::sweep_parameter::MU_MINUS; } if (is_set("z_sweep")) @@ -242,21 +242,21 @@ class opdom_command : public command // assign z sweep parameters if (z_sweep == "epsilon_r") { - params.sweep_dimensions[2].dimension = fiction::sweep_parameter::EPSILON_R; + sweep_dimensions[2].dimension = fiction::sweep_parameter::EPSILON_R; } else if (z_sweep == "lambda_tf") { - params.sweep_dimensions[2].dimension = fiction::sweep_parameter::LAMBDA_TF; + sweep_dimensions[2].dimension = fiction::sweep_parameter::LAMBDA_TF; } else if (z_sweep == "mu_minus") { - params.sweep_dimensions[2].dimension = fiction::sweep_parameter::MU_MINUS; + sweep_dimensions[2].dimension = fiction::sweep_parameter::MU_MINUS; } } else { // remove z sweep parameter if not set - params.sweep_dimensions.pop_back(); + sweep_dimensions.pop_back(); } const auto get_name = [](auto&& lyt_ptr) -> std::string { return fiction::get_name(*lyt_ptr); }; @@ -271,7 +271,7 @@ class opdom_command : public command { if (lyt_ptr->num_pis() == 0 || lyt_ptr->num_pos() == 0) { - env->out() << fmt::format("[e] {} requires primary input and output cells to simulate its " + env->out() << fmt::format("[e] '{}' requires primary input and output cells to simulate its " "Boolean function", get_name(lyt_ptr)) << std::endl; @@ -279,7 +279,10 @@ class opdom_command : public command return; } + // set parameters params.simulation_parameters = simulation_params; + params.sim_engine = fiction::sidb_simulation_engine::QUICKEXACT; + params.sweep_dimensions = sweep_dimensions; try { @@ -334,18 +337,20 @@ class opdom_command : public command private: /** - * Physical parameters for the simulation. + * Default physical parameters for the simulation. */ fiction::sidb_simulation_parameters simulation_params{2, -0.32, 5.6, 5.0}; + /** + * Default value ranges for sweeping. + */ + std::vector sweep_dimensions{ + {fiction::sweep_parameter::EPSILON_R, 1.0, 10.0, 0.1}, + {fiction::sweep_parameter::LAMBDA_TF, 1.0, 10.0, 0.1}, + {fiction::sweep_parameter::MU_MINUS, -0.50, -0.10, 0.025}}; /** * Operational domain parameters. */ - fiction::operational_domain_params params{simulation_params, fiction::sidb_simulation_engine::QUICKEXACT, - std::vector{{ - {fiction::sweep_parameter::EPSILON_R, 1.0, 10.0, 0.1}, - {fiction::sweep_parameter::LAMBDA_TF, 1.0, 10.0, 0.1}, - {fiction::sweep_parameter::MU_MINUS, -0.50, -0.10, 0.025}, - }}}; + fiction::operational_domain_params params{}; /** * Operational domain stats. */ @@ -384,6 +389,13 @@ class opdom_command : public command */ void write_op_domain() { + // if the operational domain call was unsuccessful, do not attempt writing anything + if (op_domain.operational_values.empty()) + { + reset_params(); + return; + } + // set up parameters fiction::write_operational_domain_params write_opdom_params{}; write_opdom_params.non_operational_tag = "0"; @@ -393,13 +405,6 @@ class opdom_command : public command fiction::write_operational_domain_params::sample_writing_mode::OPERATIONAL_ONLY : fiction::write_operational_domain_params::sample_writing_mode::ALL_SAMPLES; - // if the operational domain call was unsuccessful, do not attempt writing anything - if (op_domain.operational_values.empty()) - { - reset_params(); - return; - } - try { fiction::write_operational_domain(op_domain, filename, write_opdom_params); @@ -438,13 +443,11 @@ class opdom_command : public command void reset_params() { simulation_params = fiction::sidb_simulation_parameters{2, -0.32, 5.6, 5.0}; - - params.simulation_parameters = simulation_params; - params.sweep_dimensions = std::vector{ + sweep_dimensions = std::vector{ {fiction::sweep_parameter::EPSILON_R, 1.0, 10.0, 0.1}, {fiction::sweep_parameter::LAMBDA_TF, 1.0, 10.0, 0.1}, - {fiction::sweep_parameter::MU_MINUS, -0.50, -0.10, 0.025}, - }; + {fiction::sweep_parameter::MU_MINUS, -0.50, -0.10, 0.025}}; + params = {}; x_sweep = "epsilon_r"; y_sweep = "lambda_tf"; From dd887946613699f43ed68c4582afaf25c70b353b Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 20 Aug 2024 13:39:31 +0200 Subject: [PATCH 93/95] :memo: Mentioned CLI bug in docstring --- cli/cmd/simulation/opdom.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cli/cmd/simulation/opdom.hpp b/cli/cmd/simulation/opdom.hpp index 6a03115fe..58fac97f8 100644 --- a/cli/cmd/simulation/opdom.hpp +++ b/cli/cmd/simulation/opdom.hpp @@ -47,6 +47,10 @@ namespace alice * The operational domain is written to a CSV file, which can be used for further analysis or visualization. * * For more information, see algorithms/simulation/sidb/operational_domain.hpp. + * + * BUG: Currently, the manual parameter reset (which is necessary due to an alice issue) triggers a different alice + * problem: data is not read from the CLI properly after the manual reset. This causes error messages to be displayed + * only once even if the same misconfigured command is executed twice in a row. */ class opdom_command : public command { From 080d9bbd4484ee4d762a442a991d94920d8f4efb Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Tue, 20 Aug 2024 11:40:27 +0000 Subject: [PATCH 94/95] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 8301bf82b..3726feccb 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -17210,12 +17210,22 @@ set.)doc"; static const char *__doc_fiction_write_operational_domain_params_operational_tag = R"doc(The tag used to represent the operational value of a parameter set.)doc"; -static const char *__doc_fiction_write_operational_domain_params_write_non_operational_samples = +static const char *__doc_fiction_write_operational_domain_params_sample_writing_mode = R"doc(Mode selector for writing samples to file.)doc"; + +static const char *__doc_fiction_write_operational_domain_params_sample_writing_mode_ALL_SAMPLES = +R"doc(Write all samples, including non-operational ones. This may lead to +large file sizes.)doc"; + +static const char *__doc_fiction_write_operational_domain_params_sample_writing_mode_OPERATIONAL_ONLY = +R"doc(Write operational samples only. This can drastically reduce file size +and help with visibility in 3D plots.)doc"; + +static const char *__doc_fiction_write_operational_domain_params_writing_mode = R"doc(Whether to write non-operational samples to the CSV file. If set to -`false`, only operational samples are written. This yields a -significantly smaller CSV file. It is recommended to set this option -for 3D plots because the non-operational samples would shadow the -operational samples anyway.)doc"; +`OPERATIONAL_ONLY`, operational samples are written exclusively. This +yields a significantly smaller CSV file. It is recommended to set this +option for 3D plots because the non-operational samples would shadow +the operational samples anyway.)doc"; static const char *__doc_fiction_write_qca_layout = R"doc(Writes a cell-level QCA layout to a qca file that is used by From 780e80fa759f339a9805674401b89ef0f0bd861b Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 20 Aug 2024 19:47:46 +0200 Subject: [PATCH 95/95] :snake: Added `sample_writing_mode` to `write_operational_domain`'s Python bindings --- .../pyfiction/inout/write_operational_domain.hpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bindings/pyfiction/include/pyfiction/inout/write_operational_domain.hpp b/bindings/pyfiction/include/pyfiction/inout/write_operational_domain.hpp index dd21aa52e..5000afbd4 100644 --- a/bindings/pyfiction/include/pyfiction/inout/write_operational_domain.hpp +++ b/bindings/pyfiction/include/pyfiction/inout/write_operational_domain.hpp @@ -20,6 +20,15 @@ inline void write_operational_domain(pybind11::module& m) namespace py = pybind11; using namespace py::literals; + py::enum_( + m, "sample_writing_mode", DOC(fiction_write_operational_domain_params_sample_writing_mode)) + .value("ALL_SAMPLES", fiction::write_operational_domain_params::sample_writing_mode::ALL_SAMPLES, + DOC(fiction_write_operational_domain_params_sample_writing_mode_ALL_SAMPLES)) + .value("OPERATIONAL_ONLY", fiction::write_operational_domain_params::sample_writing_mode::OPERATIONAL_ONLY, + DOC(fiction_write_operational_domain_params_sample_writing_mode_OPERATIONAL_ONLY)) + + ; + py::class_(m, "write_operational_domain_params", DOC(fiction_write_operational_domain_params)) .def(py::init<>()) @@ -27,6 +36,8 @@ inline void write_operational_domain(pybind11::module& m) DOC(fiction_write_operational_domain_params_operational_tag)) .def_readwrite("non_operational_tag", &fiction::write_operational_domain_params::non_operational_tag, DOC(fiction_write_operational_domain_params_non_operational_tag)) + .def_readwrite("writing_mode", &fiction::write_operational_domain_params::writing_mode, + DOC(fiction_write_operational_domain_params_writing_mode)) ;