From 8cbe5bc63d627ee17764f6c57d895e075a9df21d Mon Sep 17 00:00:00 2001 From: Jan Drewniok <97012901+Drewniok@users.noreply.github.com> Date: Wed, 21 Aug 2024 18:24:15 +0200 Subject: [PATCH 01/13] =?UTF-8?q?=E2=9C=A8=20Extended=20Time-to-Solution?= =?UTF-8?q?=20Function=20(#500)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :sparkles: add time-to-solution function. * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * :sparkles: small fix. * :snake: small changes and unit test. * 🎨 Incorporated pre-commit fixes * :art: small fixes. * :art: small fix. * :art: small renaming. * 🎨 Incorporated pre-commit fixes * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * :snake: update python * 🎨 Incorporated pre-commit fixes * :snake: small fix. * :snake: small fix. * :snake: small fix. * :art: integrate Marcel's feedback. * 🎨 Incorporated pre-commit fixes * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * :art: small fix. * 🎨 Incorporated pre-commit fixes * :art: small fix. * :art: small fix. * 🎨 Incorporated pre-commit fixes * :art: implement Marcel's comment. * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * :art: small fix. * 🎨 Incorporated pre-commit fixes * :art: add static_cast * 🎨 Incorporated pre-commit fixes --------- Signed-off-by: GitHub Actions Co-authored-by: GitHub Actions Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Marcel Walter --- .../sidb/sidb_simulation_engine.hpp | 11 +- .../simulation/sidb/time_to_solution.hpp | 9 +- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 100 +++++++++---- .../charge_distribution_surface.hpp | 21 ++- .../simulation/sidb/test_time_to_solution.py | 56 +++++++- docs/algorithms/sidb_simulation.rst | 6 +- docs/technology/simulation.rst | 1 + .../simulation/sidb/is_ground_state.hpp | 62 +++++--- .../algorithms/simulation/sidb/quickexact.hpp | 24 ++-- .../sidb/sidb_simulation_engine.hpp | 4 +- .../sidb/sidb_simulation_result.hpp | 2 +- .../simulation/sidb/time_to_solution.hpp | 104 +++++++++----- .../charge_distribution_surface.hpp | 126 ++++++++++------- ...he_groundstate_from_simulation_results.cpp | 13 +- .../simulation/sidb/is_ground_state.cpp | 132 ++++++++++++++++++ .../simulation/sidb/is_groundstate.cpp | 56 -------- .../simulation/sidb/time_to_solution.cpp | 114 ++++++++++----- .../charge_distribution_surface.cpp | 8 +- 18 files changed, 584 insertions(+), 265 deletions(-) create mode 100644 test/algorithms/simulation/sidb/is_ground_state.cpp delete mode 100644 test/algorithms/simulation/sidb/is_groundstate.cpp diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp index 90a1d9b69..c3f9c7e88 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp @@ -26,12 +26,11 @@ inline void sidb_simulation_engine(pybind11::module& m) ; - py::enum_(m, "exhaustive_sidb_simulation_engine", - DOC(fiction_exhaustive_sidb_simulation_engine)) - .value("EXGS", fiction::exhaustive_sidb_simulation_engine::EXGS, - DOC(fiction_exhaustive_sidb_simulation_engine_EXGS)) - .value("QUICKEXACT", fiction::exhaustive_sidb_simulation_engine::QUICKEXACT, - DOC(fiction_exhaustive_sidb_simulation_engine_QUICKEXACT)) + py::enum_(m, "exact_sidb_simulation_engine", + DOC(fiction_exact_sidb_simulation_engine)) + .value("EXGS", fiction::exact_sidb_simulation_engine::EXGS, DOC(fiction_exact_sidb_simulation_engine_EXGS)) + .value("QUICKEXACT", fiction::exact_sidb_simulation_engine::QUICKEXACT, + DOC(fiction_exact_sidb_simulation_engine_QUICKEXACT)) ; } diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/time_to_solution.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/time_to_solution.hpp index de12c1b00..fd737c478 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/time_to_solution.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/time_to_solution.hpp @@ -20,12 +20,15 @@ namespace detail { template -void time_to_solution(pybind11::module& m, const std::string& lattice = "") +void time_to_solution(pybind11::module& m) { using namespace pybind11::literals; m.def("time_to_solution", &fiction::time_to_solution, "lyt"_a, "quickim_params"_a, "tts_params"_a = fiction::time_to_solution_params{}, "ps"_a = nullptr, DOC(fiction_time_to_solution)); + m.def("time_to_solution_for_given_simulation_results", &fiction::time_to_solution_for_given_simulation_results, + "results_exact"_a, "results_heuristic"_a, "confidence_level"_a = 0.997, "ps"_a = nullptr, + DOC(fiction_time_to_solution_for_given_simulation_results)); } } // namespace detail @@ -54,8 +57,8 @@ inline void time_to_solution(pybind11::module& m) .def_readwrite("acc", &fiction::time_to_solution_stats::acc, DOC(fiction_time_to_solution_stats_acc)) .def_readwrite("mean_single_runtime", &fiction::time_to_solution_stats::mean_single_runtime, DOC(fiction_time_to_solution_stats_mean_single_runtime)) - .def_readwrite("single_runtime_exhaustive", &fiction::time_to_solution_stats::single_runtime_exhaustive, - DOC(fiction_time_to_solution_stats_single_runtime_exhaustive)) + .def_readwrite("single_runtime_exact", &fiction::time_to_solution_stats::single_runtime_exact, + DOC(fiction_time_to_solution_stats_single_runtime_exact)) .def_readwrite("algorithm", &fiction::time_to_solution_stats::algorithm, DOC(fiction_time_to_solution_stats_algorithm)) .def("report", &fiction::time_to_solution_stats::report, DOC(fiction_time_to_solution_stats_report)); diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 3726feccb..1f98fce8a 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -1914,6 +1914,18 @@ R"doc(The previous charge distribution is not used. Hence, the local electrostatic potential of the given charge distribution is calculated from scratch.)doc"; +static const char *__doc_fiction_charge_distribution_mode = +R"doc(An enumeration of modes for handling the charge distribution when +assigning a charge index to the charge distribution surface.)doc"; + +static const char *__doc_fiction_charge_distribution_mode_KEEP_CHARGE_DISTRIBUTION = +R"doc(The charge distribution is kept and is not updated after a charge +index is assigned to the charge distribution surface.)doc"; + +static const char *__doc_fiction_charge_distribution_mode_UPDATE_CHARGE_DISTRIBUTION = +R"doc(The charge distribution is updated after the charge index is assigned +to the charge distribution surface.)doc"; + static const char *__doc_fiction_charge_distribution_surface = R"doc()doc"; static const char *__doc_fiction_charge_distribution_surface_2 = R"doc()doc"; @@ -8910,6 +8922,17 @@ static const char *__doc_fiction_exact_physical_design_stats_x_size = R"doc()doc static const char *__doc_fiction_exact_physical_design_stats_y_size = R"doc()doc"; +static const char *__doc_fiction_exact_sidb_simulation_engine = R"doc(Selector exclusively for exact SiDB simulation engines.)doc"; + +static const char *__doc_fiction_exact_sidb_simulation_engine_EXGS = +R"doc(*Exhaustive Ground State Search* (EXGS) is an exact simulation engine +that always has exponential runtime.)doc"; + +static const char *__doc_fiction_exact_sidb_simulation_engine_QUICKEXACT = +R"doc(*QuickExact* is also an exact simulation engine that requires +exponential runtime, but it scales a lot better than ExGS due to its +effective search-space pruning.)doc"; + static const char *__doc_fiction_exact_with_blacklist = R"doc(The same as `exact` but with a black list of tiles that are not allowed to be used to a specified set of Boolean functions and their @@ -8973,17 +8996,6 @@ Parameter ``ps``: Returns: sidb_simulation_result is returned with all results.)doc"; -static const char *__doc_fiction_exhaustive_sidb_simulation_engine = R"doc(Selector exclusively for exhaustive SiDB simulation engines.)doc"; - -static const char *__doc_fiction_exhaustive_sidb_simulation_engine_EXGS = -R"doc(*Exhaustive Ground State Search* (EXGS) is an exact simulation engine -that always has exponential runtime.)doc"; - -static const char *__doc_fiction_exhaustive_sidb_simulation_engine_QUICKEXACT = -R"doc(*QuickExact* is also an exact simulation engine that requires -exponential runtime, but it scales a lot better than ExGS due to its -effective search-space pruning.)doc"; - static const char *__doc_fiction_extract_routing_objectives = R"doc(Extracts all routing objectives from the given layout. To this end, all routing paths in the layout are traversed, starting at each PI. @@ -12386,22 +12398,22 @@ Parameter ``ps``: static const char *__doc_fiction_is_gate_level_layout = R"doc()doc"; static const char *__doc_fiction_is_ground_state = -R"doc(This function checks if the ground state is found by the *QuickSim* -algorithm. +R"doc(This function checks if the elstrostatic ground state of an SiDB +layout is found by a heuristic for the physical simulation (e.g., +*QuickSim* or *SimAnneal*). Template parameter ``Lyt``: - Cell-level layout type. + SiDB cell-level layout type. Parameter ``heuristic_results``: - All found physically valid charge distribution surfaces obtained - by a heuristic algorithm. + Simulation results obtained from a heuristic physical simulation. -Parameter ``exhaustive_results``: - All valid charge distribution surfaces determined by ExGS. +Parameter ``exact_results``: + Simulation results obtained from an exact physical simulation. Returns: - Returns `true` if the relative difference between the lowest - energies of the two sets is less than :math:`0.00001`, `false` + Returns `true` if the ground state is contained in the simulation + result provided by the heuristic physical simulation. `false` otherwise.)doc"; static const char *__doc_fiction_is_hexagonal_layout = R"doc()doc"; @@ -15614,7 +15626,7 @@ algorithm, the physical parameters used in the simulation, and (optional) algorithm-specific named simulation parameters. Template parameter ``Lyt``: - Cell-level layout type.)doc"; + SiDB cell-level layout type.)doc"; static const char *__doc_fiction_sidb_simulation_result_additional_simulation_parameters = R"doc(Additional named simulation parameters. This is used to store @@ -16621,7 +16633,7 @@ R"doc(This function determines the time-to-solution (TTS) and the accuracy (acc) of the *QuickSim* algorithm. Template parameter ``Lyt``: - Cell-level layout type. + SiDB cell-level layout type. Parameter ``lyt``: Layout that is used for the simulation. @@ -16636,9 +16648,41 @@ Parameter ``ps``: Pointer to a struct where the results (time_to_solution, acc, single runtime) are stored.)doc"; +static const char *__doc_fiction_time_to_solution_for_given_simulation_results = +R"doc(This function calculates the Time-to-Solution (TTS) by analyzing the +simulation results of a heuristic algorithm in comparison to those of +an exact algorithm. It provides further statistical metrics, including +the accuracy of the heuristic algorithm, and individual runtimes. + +Template parameter ``Lyt``: + SiDB ell-level layout type. + +Parameter ``results_exact``: + Simulation results of the exact algorithm. + +Parameter ``results_heuristic``: + Simulation of the heuristic for which the TTS is determined. + +Parameter ``confidence_level``: + Confidence level for the TTS computation. The confidence level + represents the probability that the confidence interval calculated + from the simulation contains the true value. For example, a 95 % + (0.95) confidence level means that if the simulation were repeated + many times, approximately 95 out of 100 of the calculated + confidence intervals would contain the true value. + +Parameter ``ps``: + Pointer to a struct where the statistics of this function call + (time_to_solution, acc, single runtime) are to be stored.)doc"; + static const char *__doc_fiction_time_to_solution_params = R"doc()doc"; -static const char *__doc_fiction_time_to_solution_params_confidence_level = R"doc(Confidence level.)doc"; +static const char *__doc_fiction_time_to_solution_params_confidence_level = +R"doc(The confidence level represents the probability that the confidence +interval calculated from the simulation contains the true value. For +example, a 99.7 % (0.997) confidence level means that if the +simulation were repeated many times, approximately 997 out of 1000 of +the calculated confidence intervals would contain the true value.)doc"; static const char *__doc_fiction_time_to_solution_params_engine = R"doc(Exhaustive simulation algorithm used to simulate the ground state as @@ -16655,10 +16699,10 @@ the average single simulation runtime of *QuickSim*, the single runtime of the exact simulator used, and the number of valid charge configurations found by the exact algorithm.)doc"; -static const char *__doc_fiction_time_to_solution_stats_acc = R"doc(Accuracy of the simulation.)doc"; +static const char *__doc_fiction_time_to_solution_stats_acc = R"doc(Accuracy of the simulation in %.)doc"; static const char *__doc_fiction_time_to_solution_stats_algorithm = -R"doc(Exhaustive simulation algorithm used to simulate the ground state as +R"doc(Exact simulation algorithm used to simulate the ground state as reference.)doc"; static const char *__doc_fiction_time_to_solution_stats_mean_single_runtime = R"doc(Average single simulation runtime in seconds.)doc"; @@ -16669,9 +16713,9 @@ R"doc(Print the results to the given output stream. Parameter ``out``: Output stream.)doc"; -static const char *__doc_fiction_time_to_solution_stats_single_runtime_exhaustive = -R"doc(Single simulation runtime of the exhaustive ground state searcher in -seconds.)doc"; +static const char *__doc_fiction_time_to_solution_stats_single_runtime_exact = +R"doc(Single simulation runtime of the exact ground state simulation +algorithm.)doc"; static const char *__doc_fiction_time_to_solution_stats_time_to_solution = R"doc(Time-to-solution in seconds.)doc"; diff --git a/bindings/pyfiction/include/pyfiction/technology/charge_distribution_surface.hpp b/bindings/pyfiction/include/pyfiction/technology/charge_distribution_surface.hpp index b7072c17e..0921d7684 100644 --- a/bindings/pyfiction/include/pyfiction/technology/charge_distribution_surface.hpp +++ b/bindings/pyfiction/include/pyfiction/technology/charge_distribution_surface.hpp @@ -164,18 +164,17 @@ void charge_distribution_surface_layout(pybind11::module& m, const std::string& "increase_charge_index_by_one", [](py_cds& cds, fiction::dependent_cell_mode dependent_cell_fixed, fiction::energy_calculation recompute_system_energy, - fiction::charge_distribution_history consider_history, fiction::exhaustive_sidb_simulation_engine engine) - { + fiction::charge_distribution_history consider_history, fiction::exact_sidb_simulation_engine engine) { return cds.increase_charge_index_by_one(dependent_cell_fixed, recompute_system_energy, consider_history, engine); }, "dependent_cell_fixed"_a = fiction::dependent_cell_mode::FIXED, "recompute_system_energy"_a = fiction::energy_calculation::UPDATE_ENERGY, "consider_history"_a = fiction::charge_distribution_history::NEGLECT, - "engine"_a = fiction::exhaustive_sidb_simulation_engine::EXGS) + "engine"_a = fiction::exact_sidb_simulation_engine::EXGS) .def("get_max_charge_index", &py_cds::get_max_charge_index) - .def("assign_charge_index", &py_cds::assign_charge_index, "charge_index"_a) + .def("assign_charge_index", &py_cds::assign_charge_index, "charge_index"_a, "cdc"_a) .def("adjacent_search", &py_cds::adjacent_search, "alpha"_a, "negative_indices"_a) .def("assign_global_external_potential", &py_cds::assign_global_external_potential, "potential_value"_a, "dependent_cell"_a = fiction::dependent_cell_mode::FIXED) @@ -205,7 +204,7 @@ void charge_distribution_surface_layout(pybind11::module& m, const std::string& "dependent_cell_fixed"_a = fiction::dependent_cell_mode::FIXED, "recompute_system_energy"_a = fiction::energy_calculation::UPDATE_ENERGY, "consider_history"_a = fiction::charge_distribution_history::NEGLECT, - "engine"_a = fiction::exhaustive_sidb_simulation_engine::EXGS) + "engine"_a = fiction::exact_sidb_simulation_engine::EXGS) .def("assign_charge_index_by_gray_code", &py_cds::assign_charge_index_by_gray_code, "current_gray_code"_a, "previous_gray_code"_a, "dependent_cell"_a = fiction::dependent_cell_mode::FIXED, "energy_calc_mode"_a = fiction::energy_calculation::UPDATE_ENERGY, @@ -293,6 +292,18 @@ inline void charge_distribution_surfaces(pybind11::module& m) ; + /** + * Charge distribution mode. + */ + py::enum_(m, "charge_distribution_mode", py::module_local(), + DOC(fiction_charge_distribution_mode)) + .value("UPDATE_CHARGE_DISTRIBUTION", fiction::charge_distribution_mode::UPDATE_CHARGE_DISTRIBUTION, + DOC(fiction_charge_distribution_mode_UPDATE_CHARGE_DISTRIBUTION)) + .value("KEEP_CHARGE_DISTRIBUTION", fiction::charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION, + DOC(fiction_charge_distribution_mode_KEEP_CHARGE_DISTRIBUTION)) + + ; + /** * Charge index mode. */ 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 89157cac2..7f83c4d07 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 @@ -1,6 +1,6 @@ from mnt.pyfiction import * import unittest -import os +import math class TestTimeToSolution(unittest.TestCase): @@ -12,7 +12,7 @@ def test_one_sidb_100_lattice(self): quicksim_parameter.simulation_parameters = sidb_simulation_parameters(3, -0.3) tts_params = time_to_solution_params() - tts_params.engine = exhaustive_sidb_simulation_engine.QUICKEXACT + tts_params.engine = exact_sidb_simulation_engine.QUICKEXACT stats = time_to_solution_stats() cds = charge_distribution_surface_100(layout) @@ -31,7 +31,7 @@ def test_one_sidb_111_lattice(self): quicksim_parameter.simulation_parameters = sidb_simulation_parameters(3, -0.3) tts_params = time_to_solution_params() - tts_params.engine = exhaustive_sidb_simulation_engine.QUICKEXACT + tts_params.engine = exact_sidb_simulation_engine.QUICKEXACT stats = time_to_solution_stats() cds = charge_distribution_surface_111(layout) @@ -42,5 +42,55 @@ def test_one_sidb_111_lattice(self): self.assertGreater(stats.time_to_solution, 0.0) self.assertGreater(stats.mean_single_runtime, 0.0) + def test_time_to_solution_with_simulation_results(self): + layout = sidb_100_lattice((0, 0)) + + # Assign SiDBs to the layout + layout.assign_cell_type((0, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((1, 6, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((3, 6, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((5, 6, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((10, 6, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((15, 6, 0), sidb_technology.cell_type.NORMAL) + layout.assign_cell_type((18, 6, 0), sidb_technology.cell_type.NORMAL) + + # Define simulation parameters + params = sidb_simulation_parameters(2, -0.32) + quicksim_params_inst = quicksim_params() + quicksim_params_inst.simulation_parameters = params + + number_of_repetitions = 100 + simulation_results_quicksim = [] + + # Run the QuickSim simulations + for _ in range(number_of_repetitions): + simulation_results_quicksim.append(quicksim(layout, quicksim_params_inst)) + + quickexact_params_inst = quickexact_params() + quickexact_params_inst.simulation_parameters = params + quickexact_params_inst.base_number_detection = automatic_base_number_detection.OFF + self.assertEqual(quickexact_params_inst.simulation_parameters.mu_minus, -0.32) + self.assertEqual(quickexact_params_inst.base_number_detection, automatic_base_number_detection.OFF) + + # Run the QuickExact simulation + simulation_results_quickexact = quickexact(layout, quickexact_params_inst) + + # Calculate time-to-solution using the simulation results + st = time_to_solution_stats() + time_to_solution_for_given_simulation_results( + simulation_results_quickexact, simulation_results_quicksim, 0.997, st) + + self.assertGreater(st.time_to_solution, 0.0) + self.assertGreater(st.mean_single_runtime, 0.0) + + if st.acc == 100: + tts_calculated = st.mean_single_runtime + self.assertAlmostEqual(st.time_to_solution - tts_calculated, 0.0, delta=1e-6) + elif st.acc != 0.0: + # To avoid division by zero, ensure st.acc is not 1.0 + tts_calculated = (st.mean_single_runtime * math.log(1.0 - 0.997) / + math.log(1.0 - st.acc / 100)) + self.assertAlmostEqual(st.time_to_solution - tts_calculated, 0.0, delta=1e-6) + if __name__ == '__main__': unittest.main() diff --git a/docs/algorithms/sidb_simulation.rst b/docs/algorithms/sidb_simulation.rst index c11b532bb..6e17b8d43 100644 --- a/docs/algorithms/sidb_simulation.rst +++ b/docs/algorithms/sidb_simulation.rst @@ -89,12 +89,12 @@ Engine Selectors **Header:** ``fiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp`` .. doxygenenum:: fiction::sidb_simulation_engine - .. doxygenenum:: fiction::exhaustive_sidb_simulation_engine + .. doxygenenum:: fiction::exact_sidb_simulation_engine .. tab:: Python .. autoclass:: mnt.pyfiction.sidb_simulation_engine :members: - .. autoclass:: mnt.pyfiction.exhaustive_sidb_simulation_engine + .. autoclass:: mnt.pyfiction.exact_sidb_simulation_engine :members: @@ -187,6 +187,7 @@ Time-to-Solution (TTS) Statistics .. doxygenstruct:: fiction::time_to_solution_stats :members: .. doxygenfunction:: fiction::time_to_solution + .. doxygenfunction:: fiction::time_to_solution_for_given_simulation_results .. tab:: Python .. autoclass:: mnt.pyfiction.time_to_solution_params @@ -194,6 +195,7 @@ Time-to-Solution (TTS) Statistics .. autoclass:: mnt.pyfiction.time_to_solution_stats :members: .. autofunction:: mnt.pyfiction.time_to_solution + .. autofunction:: mnt.pyfiction.time_to_solution_for_given_simulation_results Random SiDB Layout Generator diff --git a/docs/technology/simulation.rst b/docs/technology/simulation.rst index 1699d9cb4..0806c33ad 100644 --- a/docs/technology/simulation.rst +++ b/docs/technology/simulation.rst @@ -39,6 +39,7 @@ distributions of the SiDBs. Charge distribution surfaces are returned by the SiD .. doxygenenum:: fiction::energy_calculation .. doxygenenum:: fiction::charge_distribution_history .. doxygenenum:: fiction::charge_index_recomputation + .. doxygenenum:: fiction::charge_distribution_mode .. doxygenenum:: fiction::charge_index_mode .. doxygenclass:: fiction::charge_distribution_surface :members: diff --git a/include/fiction/algorithms/simulation/sidb/is_ground_state.hpp b/include/fiction/algorithms/simulation/sidb/is_ground_state.hpp index 02448b788..c7360e783 100644 --- a/include/fiction/algorithms/simulation/sidb/is_ground_state.hpp +++ b/include/fiction/algorithms/simulation/sidb/is_ground_state.hpp @@ -5,45 +5,71 @@ #ifndef FICTION_IS_GROUND_STATE_HPP #define FICTION_IS_GROUND_STATE_HPP -#include "fiction/algorithms/simulation/sidb/minimum_energy.hpp" -#include "fiction/algorithms/simulation/sidb/quickexact.hpp" -#include "fiction/algorithms/simulation/sidb/quicksim.hpp" +#include "fiction/algorithms/simulation/sidb/determine_groundstate_from_simulation_results.hpp" #include "fiction/algorithms/simulation/sidb/sidb_simulation_result.hpp" #include "fiction/traits.hpp" -#include "fiction/utils/math_utils.hpp" -#include +#include +#include +#include namespace fiction { /** - * This function checks if the ground state is found by the *QuickSim* algorithm. + * This function checks if the elstrostatic ground state of an SiDB layout is found by a heuristic for the physical + * simulation (e.g., *QuickSim* or *SimAnneal*). * - * @tparam Lyt Cell-level layout type. - * @param heuristic_results All found physically valid charge distribution surfaces obtained by a heuristic algorithm. - * @param exhaustive_results All valid charge distribution surfaces determined by ExGS. - * @return Returns `true` if the relative difference between the lowest energies of the two sets is less than - * \f$0.00001\f$, `false` otherwise. + * @tparam Lyt SiDB cell-level layout type. + * @param heuristic_results Simulation results obtained from a heuristic physical simulation. + * @param exact_results Simulation results obtained from an exact physical simulation. + * @return Returns `true` if the ground state is contained in the simulation result provided by the heuristic physical + * simulation. `false` otherwise. */ template [[nodiscard]] bool is_ground_state(const sidb_simulation_result& heuristic_results, - const sidb_simulation_result& exhaustive_results) noexcept + const sidb_simulation_result& exact_results) noexcept { 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"); - if (exhaustive_results.charge_distributions.empty()) + if (exact_results.charge_distributions.empty()) { return false; } - const auto min_energy_exact = minimum_energy(exhaustive_results.charge_distributions.cbegin(), - exhaustive_results.charge_distributions.cend()); - const auto min_energy_heuristic = - minimum_energy(heuristic_results.charge_distributions.cbegin(), heuristic_results.charge_distributions.cend()); + const auto ground_state_charge_distributions_exact = determine_groundstate_from_simulation_results(exact_results); - return round_to_n_decimal_places(std::abs(min_energy_exact - min_energy_heuristic), 6) == 0; + const auto ground_state_charge_distributions_heuristic = + determine_groundstate_from_simulation_results(heuristic_results); + + assert(ground_state_charge_distributions_heuristic.size() <= ground_state_charge_distributions_exact.size() && + "The heuristic results must be less equal than the exact results."); + + if (ground_state_charge_distributions_exact.size() != ground_state_charge_distributions_heuristic.size()) + { + return false; + } + + std::unordered_set indices_ground_state_heuristic{}; + + // Collect all charge indices of the ground states simulated by the heuristic. + for (const auto& cds : ground_state_charge_distributions_heuristic) + { + indices_ground_state_heuristic.insert(cds.get_charge_index_and_base().first); + } + + // Check if the heuristic has found all ground states. + for (const auto& cds : ground_state_charge_distributions_exact) + { + if (indices_ground_state_heuristic.find(cds.get_charge_index_and_base().first) == + indices_ground_state_heuristic.cend()) + { + return false; + } + } + + return true; } } // namespace fiction diff --git a/include/fiction/algorithms/simulation/sidb/quickexact.hpp b/include/fiction/algorithms/simulation/sidb/quickexact.hpp index b1bba4861..97faef7f3 100644 --- a/include/fiction/algorithms/simulation/sidb/quickexact.hpp +++ b/include/fiction/algorithms/simulation/sidb/quickexact.hpp @@ -171,9 +171,9 @@ class quickexact_impl } charge_lyt.increase_charge_index_by_one( - dependent_cell_mode::VARIABLE); // "Variable" allows that the charge state of the dependent - // cell is automatically changed based on the new charge - // distribution. + dependent_cell_mode::VARIABLE); // `dependent_cell_mode::VARIABLE` allows that the charge state + // of the dependent cell is automatically changed based on the + // new charge distribution. } if (charge_lyt.is_physically_valid()) @@ -294,8 +294,8 @@ class quickexact_impl } // Update all local potentials, system energy, and physical validity. The flag is set to - // `VARIABLE` to allow the dependent cell to change its charge state based on the N-1 SiDBs to - // fulfill the local population stability at its position. + // `dependent_cell_mode::VARIABLE` to allow the dependent cell to change its charge state based on the N-1 SiDBs + // to fulfill the local population stability at its position. charge_layout.update_after_charge_change(dependent_cell_mode::VARIABLE); if constexpr (has_get_sidb_defect_v) @@ -406,9 +406,9 @@ class quickexact_impl charge_layout.increase_charge_index_of_sub_layout_by_one( dependent_cell_mode::VARIABLE, energy_calculation::KEEP_OLD_ENERGY_VALUE, charge_distribution_history::CONSIDER, - exhaustive_sidb_simulation_engine::QUICKEXACT); // "false" allows that the charge state of the - // dependent cell is automatically changed based on - // the new charge distribution. + exact_sidb_simulation_engine::QUICKEXACT); // `dependent_cell_mode::VARIABLE` allows that the + // charge state of the dependent cell is automatically + // changed based on the new charge distribution. } if (charge_layout.is_physically_valid()) @@ -433,9 +433,9 @@ class quickexact_impl charge_layout.increase_charge_index_by_one( dependent_cell_mode::VARIABLE, energy_calculation::KEEP_OLD_ENERGY_VALUE, charge_distribution_history::NEGLECT, - exhaustive_sidb_simulation_engine::QUICKEXACT); // "false" allows that the charge state of the - // dependent cell is automatically changed based on the - // new charge distribution. + exact_sidb_simulation_engine::QUICKEXACT); // `dependent_cell_mode::VARIABLE` allows that the charge + // state of the dependent cell is automatically changed + // based on the new charge distribution. } // charge configurations of the sublayout are iterated @@ -457,7 +457,7 @@ class quickexact_impl charge_layout.increase_charge_index_of_sub_layout_by_one( dependent_cell_mode::VARIABLE, energy_calculation::KEEP_OLD_ENERGY_VALUE, - charge_distribution_history::CONSIDER, exhaustive_sidb_simulation_engine::QUICKEXACT); + charge_distribution_history::CONSIDER, exact_sidb_simulation_engine::QUICKEXACT); } if (charge_layout.is_physically_valid()) diff --git a/include/fiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp b/include/fiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp index 717b7bdcd..90e06df30 100644 --- a/include/fiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp +++ b/include/fiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp @@ -29,9 +29,9 @@ enum class sidb_simulation_engine }; /** - * Selector exclusively for exhaustive SiDB simulation engines. + * Selector exclusively for exact SiDB simulation engines. */ -enum class exhaustive_sidb_simulation_engine +enum class exact_sidb_simulation_engine { /** * *Exhaustive Ground State Search* (EXGS) is an exact simulation engine that always has exponential runtime. diff --git a/include/fiction/algorithms/simulation/sidb/sidb_simulation_result.hpp b/include/fiction/algorithms/simulation/sidb/sidb_simulation_result.hpp index b1f0b30f9..ff737a540 100644 --- a/include/fiction/algorithms/simulation/sidb/sidb_simulation_result.hpp +++ b/include/fiction/algorithms/simulation/sidb/sidb_simulation_result.hpp @@ -22,7 +22,7 @@ namespace fiction * the total simulation runtime, the charge distributions determined by the algorithm, the physical parameters used in * the simulation, and (optional) algorithm-specific named simulation parameters. * - * @tparam Lyt Cell-level layout type. + * @tparam Lyt SiDB cell-level layout type. */ template struct sidb_simulation_result diff --git a/include/fiction/algorithms/simulation/sidb/time_to_solution.hpp b/include/fiction/algorithms/simulation/sidb/time_to_solution.hpp index 9737ff6be..9d1a90530 100644 --- a/include/fiction/algorithms/simulation/sidb/time_to_solution.hpp +++ b/include/fiction/algorithms/simulation/sidb/time_to_solution.hpp @@ -5,6 +5,7 @@ #ifndef FICTION_TIME_TO_SOLUTION_HPP #define FICTION_TIME_TO_SOLUTION_HPP +#include "fiction/algorithms/simulation/sidb/determine_groundstate_from_simulation_results.hpp" #include "fiction/algorithms/simulation/sidb/exhaustive_ground_state_simulation.hpp" #include "fiction/algorithms/simulation/sidb/is_ground_state.hpp" #include "fiction/algorithms/simulation/sidb/quickexact.hpp" @@ -15,13 +16,11 @@ #include -#include #include #include #include #include #include -#include #include #include @@ -33,14 +32,17 @@ struct time_to_solution_params /** * Exhaustive simulation algorithm used to simulate the ground state as reference. */ - exhaustive_sidb_simulation_engine engine = exhaustive_sidb_simulation_engine::QUICKEXACT; + exact_sidb_simulation_engine engine = exact_sidb_simulation_engine::QUICKEXACT; /** * Number of iterations of the heuristic algorithm used to determine the simulation accuracy (`repetitions = 100` * means that accuracy is precise to 1%). */ uint64_t repetitions = 100; /** - * Confidence level. + * The confidence level represents the probability that the confidence interval calculated from the simulation + * contains the true value. For example, a 99.7 % (0.997) confidence level means that if the simulation were + * repeated many times, approximately 997 out of 1000 of the calculated confidence intervals would contain the true + * value. */ double confidence_level = 0.997; }; @@ -57,7 +59,7 @@ struct time_to_solution_stats */ double time_to_solution{0}; /** - * Accuracy of the simulation. + * Accuracy of the simulation in %. */ double acc{}; /** @@ -65,11 +67,11 @@ struct time_to_solution_stats */ double mean_single_runtime{}; /** - * Single simulation runtime of the exhaustive ground state searcher in seconds. + * Single simulation runtime of the exact ground state simulation algorithm. */ - double single_runtime_exhaustive{}; + double single_runtime_exact{}; /** - * Exhaustive simulation algorithm used to simulate the ground state as reference. + * Exact simulation algorithm used to simulate the ground state as reference. */ std::string algorithm; /** @@ -79,14 +81,14 @@ struct time_to_solution_stats */ void report(std::ostream& out = std::cout) { - out << fmt::format("time_to_solution: {} \n acc: {} \n t_(s): {} \n t_exhaustive(s): {} \n exact alg.: {}\n", - time_to_solution, acc, mean_single_runtime, single_runtime_exhaustive, algorithm); + out << fmt::format("time_to_solution: {} \n acc: {} \n t[s]: {} \n t_exact[s]: {} \n exact alg.: {}\n", + time_to_solution, acc, mean_single_runtime, single_runtime_exact, algorithm); } }; /** * This function determines the time-to-solution (TTS) and the accuracy (acc) of the *QuickSim* algorithm. * - * @tparam Lyt Cell-level layout type. + * @tparam Lyt SiDB cell-level layout type. * @param lyt Layout that is used for the simulation. * @param quicksim_params Parameters required for the *QuickSim* algorithm. * @param tts_params Parameters used for the time-to-solution calculation. @@ -102,7 +104,7 @@ void time_to_solution(const Lyt& lyt, const quicksim_params& quicksim_params, time_to_solution_stats st{}; sidb_simulation_result simulation_result{}; - if (tts_params.engine == exhaustive_sidb_simulation_engine::QUICKEXACT) + if (tts_params.engine == exact_sidb_simulation_engine::QUICKEXACT) { const quickexact_params> params{quicksim_params.simulation_parameters}; st.algorithm = "QuickExact"; @@ -114,41 +116,71 @@ void time_to_solution(const Lyt& lyt, const quicksim_params& quicksim_params, simulation_result = exhaustive_ground_state_simulation(lyt, quicksim_params.simulation_parameters); } - st.single_runtime_exhaustive = mockturtle::to_seconds(simulation_result.simulation_runtime); - - std::size_t gs_count = 0; - std::vector time{}; - time.reserve(tts_params.repetitions); + std::vector> simulation_results_quicksim{}; + simulation_results_quicksim.reserve(tts_params.repetitions); for (auto i = 0u; i < tts_params.repetitions; ++i) { - sidb_simulation_result stats_quick{}; + simulation_results_quicksim.push_back(quicksim(lyt, quicksim_params)); + } - const auto t_start = std::chrono::high_resolution_clock::now(); + time_to_solution_for_given_simulation_results(simulation_result, simulation_results_quicksim, + tts_params.confidence_level, &st); + + if (ps) + { + *ps = st; + } +} - const auto simulation_results_quicksim = quicksim(lyt, quicksim_params); +/** + * This function calculates the Time-to-Solution (TTS) by analyzing the simulation results of a heuristic algorithm + * in comparison to those of an exact algorithm. It provides further statistical metrics, including the accuracy of the + * heuristic algorithm, and individual runtimes. + * + * @tparam Lyt SiDB ell-level layout type. + * @param results_exact Simulation results of the exact algorithm. + * @param results_heuristic Simulation of the heuristic for which the TTS is determined. + * @param confidence_level Confidence level for the TTS computation. The confidence level represents the probability + * that the confidence interval calculated from the simulation contains the true value. For example, a 95 % (0.95) + * confidence level means that if the simulation were repeated many times, approximately 95 out of 100 of the calculated + * confidence intervals would contain the true value. + * @param ps Pointer to a struct where the statistics of this function call (time_to_solution, acc, single runtime) are + * to be stored. + */ +template +void time_to_solution_for_given_simulation_results(const sidb_simulation_result& results_exact, + const std::vector>& results_heuristic, + const double confidence_level = 0.997, + time_to_solution_stats* ps = nullptr) noexcept +{ + 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"); - const auto t_end = std::chrono::high_resolution_clock::now(); - const auto elapsed = t_end - t_start; - const auto diff_first = std::chrono::duration(elapsed).count(); + time_to_solution_stats st{}; - time.push_back(diff_first); + auto total_runtime_heuristic = 0.0; + std::size_t gs_count = 0; - if (is_ground_state(simulation_results_quicksim, simulation_result)) + for (const auto& heuristic : results_heuristic) + { + if (is_ground_state(heuristic, results_exact)) { - gs_count += 1; + ++gs_count; } + total_runtime_heuristic += mockturtle::to_seconds(heuristic.simulation_runtime); } - const auto single_runtime = - std::accumulate(time.cbegin(), time.cend(), 0.0) / static_cast(tts_params.repetitions); - const auto acc = static_cast(gs_count) / static_cast(tts_params.repetitions); + const auto single_runtime_heuristic_average = + total_runtime_heuristic / static_cast(results_heuristic.size()); + + const auto acc = static_cast(gs_count) / static_cast(results_heuristic.size()); double tts = 0.0; if (acc == 1) { - tts = single_runtime; + tts = single_runtime_heuristic_average; } else if (acc == 0) { @@ -156,16 +188,18 @@ void time_to_solution(const Lyt& lyt, const quicksim_params& quicksim_params, } else { - tts = (single_runtime * std::log(1.0 - tts_params.confidence_level) / std::log(1.0 - acc)); + tts = (single_runtime_heuristic_average * std::log(1.0 - confidence_level) / std::log(1.0 - acc)); } - st.time_to_solution = tts; - st.acc = acc * 100; - st.mean_single_runtime = single_runtime; + st.single_runtime_exact = mockturtle::to_seconds(results_exact.simulation_runtime); + st.time_to_solution = tts; + st.acc = acc * 100; + st.mean_single_runtime = single_runtime_heuristic_average; if (ps) { - *ps = st; + st.algorithm = (*ps).algorithm; + *ps = st; } } diff --git a/include/fiction/technology/charge_distribution_surface.hpp b/include/fiction/technology/charge_distribution_surface.hpp index ccd81bb0e..7c39cc0dc 100644 --- a/include/fiction/technology/charge_distribution_surface.hpp +++ b/include/fiction/technology/charge_distribution_surface.hpp @@ -97,6 +97,23 @@ enum class charge_index_recomputation IGNORE_LEADING_ZEROES }; +/** + * An enumeration of modes for handling the charge distribution when assigning a charge index to the charge distribution + * surface. + */ +enum class charge_distribution_mode +{ + /** + * The charge distribution is updated after the charge index is assigned to the charge distribution surface. + */ + UPDATE_CHARGE_DISTRIBUTION, + /** + * The charge distribution is kept and is not updated after a charge index is assigned to the charge distribution + * surface. + */ + KEEP_CHARGE_DISTRIBUTION +}; + /** * An enumeration of modes for handling the charge index during charge state assignment. */ @@ -505,14 +522,7 @@ class charge_distribution_surface : public Lyt const auto dist = sidb_nm_distance(*this, c1, c); const auto pot = chargeless_potential_generated_by_defect_at_given_distance(dist, defect); - if (strg->defect_local_pot.empty()) - { - strg->defect_local_pot.insert(std::make_pair(c1, pot * static_cast(defect.charge))); - } - else - { - strg->defect_local_pot[c1] += pot * static_cast(defect.charge); - } + strg->defect_local_pot[c1] += pot * static_cast(defect.charge); }); this->update_after_charge_change(dependent_cell_mode::FIXED); @@ -770,8 +780,9 @@ class charge_distribution_surface : public Lyt * This function calculates the local electrostatic potential in Volt for each SiDB position, including external * electrostatic potentials (generated by electrodes, defects, etc.) (unit: V). * - * @param history_mode If set to NEGLECT, the local electrostatic is calculated from scratch, without using the - * results of the previous charge distribution. + * @param history_mode `charge_distribution_history::NEGLECT` if the information (local electrostatic energy) of the + * previous charge distribution is used to make the update more efficient, `charge_distribution_history::CONSIDER` + * otherwise. */ void update_local_potential( const charge_distribution_history history_mode = charge_distribution_history::NEGLECT) noexcept @@ -915,12 +926,12 @@ class charge_distribution_surface : public Lyt /** * The function updates the local potential (unit: Volt) and the system energy (unit: eV) after a charge change. * - * @param dep_cell dependent_cell_mode::FIXED if the state of the dependent cell should not change, - * dependent_cell_mode::VARIABLE if it should. - * @param energy_calculation_mode energy_calculation::UPDATE_ENERGY if the electrostatic potential energy should be - * updated, energy_calculation::KEEP_ENERGY otherwise. - * @param history_mode charge_distribution_history::NEGLECT if the information (local electrostatic energy) of the - * previous charge distribution is used to make the update more efficient, charge_distribution_history::CONSIDER + * @param dep_cell `dependent_cell_mode::FIXED` if the state of the dependent cell should not change, + * `dependent_cell_mode::VARIABLE` if it should. + * @param energy_calculation_mode `energy_calculation::UPDATE_ENERGY` if the electrostatic potential energy should + * be updated, `energy_calculation::KEEP_ENERGY` otherwise. + * @param history_mode `charge_distribution_history::NEGLECT` if the information (local electrostatic energy) of the + * previous charge distribution is used to make the update more efficient, `charge_distribution_history::CONSIDER` * otherwise. */ void update_after_charge_change( @@ -1151,26 +1162,25 @@ class charge_distribution_surface : public Lyt * If that's the case, it is increased by one and afterward, the charge configuration is updated by invoking the * `index_to_charge_distribution()` function. * - * @param dep_cell dependent_cell_mode::FIXED if the state of the dependent cell should not change, - * dependent_cell_mode::VARIABLE if it should. - * @param energy_calculation_mode energy_calculation::UPDATE_ENERGY if the electrostatic potential energy should be - * updated, energy_calculation::KEEP_ENERGY otherwise. - * @param history_mode charge_distribution_history::NEGLECT if the information (local electrostatic energy) of the - * previous charge distribution is used to make the update more efficient, charge_distribution_history::CONSIDER + * @param dep_cell `dependent_cell_mode::FIXED` if the state of the dependent cell should not change, + * `dependent_cell_mode::VARIABLE` if it should. + * @param energy_calculation_mode `energy_calculation::UPDATE_ENERGY` if the electrostatic potential energy should + * be updated, `energy_calculation::KEEP_ENERGY otherwise. + * @param history_mode `charge_distribution_history::NEGLECT` if the information (local electrostatic energy) of the + * previous charge distribution is used to make the update more efficient, `charge_distribution_history::CONSIDER` * otherwise. - * @param engine exhaustive_sidb_simulation_engine::EXGS if *ExGS* should be used, - * exhaustive_sidb_simulation_engine::QUICKEXACT for *QuickExact*. + * @param engine The simulation engine used. */ void increase_charge_index_by_one( - const dependent_cell_mode dep_cell = dependent_cell_mode::FIXED, - const energy_calculation energy_calculation_mode = energy_calculation::UPDATE_ENERGY, - const charge_distribution_history history_mode = charge_distribution_history::NEGLECT, - const exhaustive_sidb_simulation_engine engine = exhaustive_sidb_simulation_engine::EXGS) noexcept + const dependent_cell_mode dep_cell = dependent_cell_mode::FIXED, + const energy_calculation energy_calculation_mode = energy_calculation::UPDATE_ENERGY, + const charge_distribution_history history_mode = charge_distribution_history::NEGLECT, + const exact_sidb_simulation_engine engine = exact_sidb_simulation_engine::EXGS) noexcept { if (strg->charge_index_and_base.first < strg->max_charge_index) { strg->charge_index_and_base.first += 1; - if (engine == exhaustive_sidb_simulation_engine::QUICKEXACT) + if (engine == exact_sidb_simulation_engine::QUICKEXACT) { this->index_to_charge_distribution_for_quickexact_simulation(); } @@ -1195,12 +1205,19 @@ class charge_distribution_surface : public Lyt * according to the set charge index. * * @param charge_index charge index of the new charge distribution. + * @param cdc Setting to determine if the charge distribution should be updated after the charge index is assigned. */ - void assign_charge_index(const uint64_t charge_index) noexcept + void assign_charge_index( + const uint64_t charge_index, + const charge_distribution_mode cdc = charge_distribution_mode::UPDATE_CHARGE_DISTRIBUTION) noexcept { assert((charge_index <= strg->max_charge_index) && "charge index is too large"); strg->charge_index_and_base.first = charge_index; - this->index_to_charge_distribution(); + + if (cdc == charge_distribution_mode::UPDATE_CHARGE_DISTRIBUTION) + { + this->index_to_charge_distribution(); + } } /** * This function is used for the *QuickSim* algorithm (see quicksim.hpp). It gets a vector with indices representing @@ -1275,8 +1292,8 @@ class charge_distribution_surface : public Lyt * * @param potential_value Value of the global external electrostatic potential in Volt (e.g. -0.3). * Charge-transition levels are shifted by this value. - * @param dep_cell dependent_cell_mode::FIXED if the state of the dependent cell should not change, - * dependent_cell_mode::VARIABLE if it should. + * @param dep_cell `dependent_cell_mode::FIXED` if the state of the dependent cell should not change, + * `dependent_cell_mode::VARIABLE` if it should. */ void assign_global_external_potential(const double potential_value, dependent_cell_mode dep_cell = dependent_cell_mode::FIXED) noexcept @@ -1697,26 +1714,25 @@ class charge_distribution_surface : public Lyt /** * The charge index of the sublayout is increased by one and the charge distribution is updated correspondingly. * - * @param dependent_cell dependent_cell_mode::FIXED if the state of the dependent cell should not change, - * dependent_cell_mode::VARIABLE if it should. - * @param energy_calculation_mode energy_calculation::UPDATE_ENERGY if the electrostatic potential energy should be - * updated, energy_calculation::KEEP_ENERGY otherwise. - * @param history_mode charge_distribution_history::NEGLECT if the information (local electrostatic energy) of the - * previous charge distribution is used to make the update more efficient, charge_distribution_history::CONSIDER + * @param dependent_cell `dependent_cell_mode::FIXED` if the state of the dependent cell should not change, + * `dependent_cell_mode::VARIABLE` if it should. + * @param energy_calculation_mode `energy_calculation::UPDATE_ENERGY` if the electrostatic potential energy should + * be updated, `energy_calculation::KEEP_ENERGY` otherwise. + * @param history_mode `charge_distribution_history::NEGLECT` if the information (local electrostatic energy) of the + * previous charge distribution is used to make the update more efficient, `charge_distribution_history::CONSIDER` * otherwise. - * @param engine exhaustive_sidb_simulation_engine::EXGS if `ExGS``should be used, - * exhaustive_sidb_simulation_engine::QUICKEXACT for `QuickExact`. + * @param engine The simulation engine used. */ void increase_charge_index_of_sub_layout_by_one( - const dependent_cell_mode dependent_cell_fixed = dependent_cell_mode::FIXED, - const energy_calculation recompute_system_energy = energy_calculation::UPDATE_ENERGY, - const charge_distribution_history consider_history = charge_distribution_history::NEGLECT, - const exhaustive_sidb_simulation_engine engine = exhaustive_sidb_simulation_engine::QUICKEXACT) noexcept + const dependent_cell_mode dependent_cell_fixed = dependent_cell_mode::FIXED, + const energy_calculation recompute_system_energy = energy_calculation::UPDATE_ENERGY, + const charge_distribution_history consider_history = charge_distribution_history::NEGLECT, + const exact_sidb_simulation_engine engine = exact_sidb_simulation_engine::QUICKEXACT) noexcept { if (strg->charge_index_sublayout < strg->max_charge_index_sulayout) { strg->charge_index_sublayout += 1; - if (engine == exhaustive_sidb_simulation_engine::QUICKEXACT) + if (engine == exact_sidb_simulation_engine::QUICKEXACT) { this->index_to_charge_distribution_for_quickexact_simulation(); } @@ -1732,12 +1748,12 @@ class charge_distribution_surface : public Lyt * * @param current_gray_code Gray code in decimal representing the new charge distribution. * @param previous_gray_code Gray code in decimal representing the old charge distribution. - * @param dep_cell dependent_cell_mode::FIXED if the state of the dependent cell should not change, - * dependent_cell_mode::VARIABLE if it should. - * @param energy_calculation_mode energy_calculation::UPDATE_ENERGY if the electrostatic potential energy should be - * updated, energy_calculation::KEEP_ENERGY otherwise. - * @param history_mode charge_distribution_history::NEGLECT if the information (local electrostatic energy) of the - * previous charge distribution is used to make the update more efficient, charge_distribution_history::CONSIDER + * @param dep_cell `dependent_cell_mode::FIXED` if the state of the dependent cell should not change, + * `dependent_cell_mode::VARIABLE` if it should. + * @param energy_calculation_mode `energy_calculation::UPDATE_ENERGY` if the electrostatic potential energy should + * be updated, `energy_calculation::KEEP_ENERGY` otherwise. + * @param history_mode `charge_distribution_history::NEGLECT` if the information (local electrostatic energy) of the + * previous charge distribution is used to make the update more efficient, `charge_distribution_history::CONSIDER` * otherwise. */ void assign_charge_index_by_gray_code( @@ -1754,12 +1770,14 @@ class charge_distribution_surface : public Lyt } /** * Resets the charge index of the sublayout (cells of the layout that can also be positively charged). + * + * @param engine The simulation engine used. */ void reset_charge_index_sub_layout( - const exhaustive_sidb_simulation_engine engine = exhaustive_sidb_simulation_engine::QUICKEXACT) noexcept + const exact_sidb_simulation_engine engine = exact_sidb_simulation_engine::QUICKEXACT) noexcept { strg->charge_index_sublayout = 0; - if (engine == exhaustive_sidb_simulation_engine::QUICKEXACT) + if (engine == exact_sidb_simulation_engine::QUICKEXACT) { this->index_to_charge_distribution_for_quickexact_simulation(); } diff --git a/test/algorithms/simulation/sidb/determine_the_groundstate_from_simulation_results.cpp b/test/algorithms/simulation/sidb/determine_the_groundstate_from_simulation_results.cpp index a4d5a391f..107a7d489 100644 --- a/test/algorithms/simulation/sidb/determine_the_groundstate_from_simulation_results.cpp +++ b/test/algorithms/simulation/sidb/determine_the_groundstate_from_simulation_results.cpp @@ -28,7 +28,7 @@ TEST_CASE("Determine the groundstate from simulation results", "[determine-the-g lyt.assign_cell_type({5, 5}, lattice::cell_type::NORMAL); lyt.assign_cell_type({5, 6}, lattice::cell_type::NORMAL); - const charge_distribution_surface cds1{lyt}; + charge_distribution_surface cds1{lyt}; charge_distribution_surface cds2{lyt}; cds2.assign_all_charge_states(sidb_charge_state::NEUTRAL); @@ -42,6 +42,10 @@ TEST_CASE("Determine the groundstate from simulation results", "[determine-the-g CHECK(cds2.get_system_energy() < cds3.get_system_energy()); CHECK(cds2.get_system_energy() < cds1.get_system_energy()); + cds1.assign_charge_index(0, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + cds2.assign_charge_index(1, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + cds3.assign_charge_index(2, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + sidb_simulation_result results{}; results.charge_distributions = {cds1, cds2, cds3}; results.algorithm_name = "test"; @@ -71,7 +75,12 @@ TEST_CASE("Determine the groundstate from simulation results", "[determine-the-g cds3.update_after_charge_change(); // copy cds2 to check for degeneracy. - const charge_distribution_surface cds4{cds2}; + charge_distribution_surface cds4{cds2}; + + cds1.assign_charge_index(0, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + cds2.assign_charge_index(1, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + cds3.assign_charge_index(2, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + cds4.assign_charge_index(3, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); CHECK_THAT(cds2.get_system_energy() - cds1.get_system_energy(), Catch::Matchers::WithinAbs(0.0, 0.00001)); diff --git a/test/algorithms/simulation/sidb/is_ground_state.cpp b/test/algorithms/simulation/sidb/is_ground_state.cpp new file mode 100644 index 000000000..388eac732 --- /dev/null +++ b/test/algorithms/simulation/sidb/is_ground_state.cpp @@ -0,0 +1,132 @@ +// +// Created by Jan Drewniok on 02.02.23. +// + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace fiction; + +TEMPLATE_TEST_CASE("check if ground state is found", "[is-ground-state]", sidb_100_cell_clk_lyt_siqad) +{ + SECTION("degenerate ground state") + { + TestType lyt{}; + lyt.assign_cell_type({1, 3, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({3, 3, 0}, TestType::cell_type::NORMAL); + + charge_distribution_surface charge_layout_first{lyt}; + charge_distribution_surface charge_layout_second{lyt}; + + charge_layout_first.assign_charge_state({1, 3, 0}, sidb_charge_state::NEGATIVE); + charge_layout_first.assign_charge_state({3, 3, 0}, sidb_charge_state::NEUTRAL); + + // assign different charge index on purpose to see if the algorithm still works as desired + charge_layout_first.assign_charge_index(3, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + + sidb_simulation_result simulation_result_exhaustive{}; + simulation_result_exhaustive.charge_distributions.push_back(charge_layout_first); + + charge_layout_second.assign_charge_state({1, 3, 0}, sidb_charge_state::NEUTRAL); + charge_layout_second.assign_charge_state({3, 3, 0}, sidb_charge_state::NEGATIVE); + + // assign different charge index on purpose to see if the algorithm still works as desired + charge_layout_second.assign_charge_index(3, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + + simulation_result_exhaustive.charge_distributions.push_back(charge_layout_second); + + SECTION("heuristic only finds one ground state") + { + sidb_simulation_result simulation_result_heuristic{}; + simulation_result_heuristic.charge_distributions = {{charge_layout_first}}; + CHECK(!is_ground_state(simulation_result_heuristic, simulation_result_exhaustive)); + } + + SECTION("two idential ground states are stored in the simulation results") + { + simulation_result_exhaustive.charge_distributions = {{charge_layout_first, charge_layout_first}}; + sidb_simulation_result simulation_result_heuristic{}; + simulation_result_heuristic.charge_distributions = {{charge_layout_first}}; + CHECK(is_ground_state(simulation_result_heuristic, simulation_result_exhaustive)); + } + + SECTION("heuristic finds both ground states") + { + sidb_simulation_result simulation_result_heuristic{}; + simulation_result_heuristic.charge_distributions = simulation_result_exhaustive.charge_distributions; + simulation_result_heuristic.charge_distributions[0].assign_charge_index( + 0, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + simulation_result_heuristic.charge_distributions[1].assign_charge_index( + 1, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + CHECK(is_ground_state(simulation_result_heuristic, simulation_result_exhaustive)); + } + } + + SECTION("layout with no SiDB placed") + { + TestType lyt{}; + const charge_distribution_surface charge_layout{lyt}; + const sidb_simulation_parameters params{2, -0.32}; + const auto simulation_results_exgs = exhaustive_ground_state_simulation(charge_layout, params); + const quicksim_params quicksim_params{params}; + const auto simulation_results_quicksim = quicksim(charge_layout, quicksim_params); + + CHECK(!is_ground_state(simulation_results_exgs, simulation_results_quicksim)); + } + + SECTION("Layout with seven SiDBs placed, verify independence from charge index") + { + TestType lyt{}; + + lyt.assign_cell_type({1, 3, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({3, 3, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({4, 3, 0}, TestType::cell_type::NORMAL); + + lyt.assign_cell_type({6, 3, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({7, 3, 0}, TestType::cell_type::NORMAL); + + lyt.assign_cell_type({6, 10, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({7, 10, 0}, TestType::cell_type::NORMAL); + + const charge_distribution_surface charge_layout{lyt}; + const sidb_simulation_parameters params{2, -0.32}; + + auto simulation_results_exgs = exhaustive_ground_state_simulation(charge_layout, params); + + // assign different charge index on purpose to see if the algorithm still works as desired + for (auto& cds : simulation_results_exgs.charge_distributions) + { + cds.assign_charge_index(0, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + } + + for (auto& cds : simulation_results_exgs.charge_distributions) + { + CHECK(cds.get_charge_index_and_base().first == 0); + } + + const quicksim_params quicksim_params{params}; + auto simulation_results_quicksim = quicksim(charge_layout, quicksim_params); + + // assign different charge index on purpose to see if the algorithm still works as desired + for (auto& cds : simulation_results_quicksim.charge_distributions) + { + cds.assign_charge_index(0, charge_distribution_mode::KEEP_CHARGE_DISTRIBUTION); + } + + for (auto& cds : simulation_results_quicksim.charge_distributions) + { + CHECK(cds.get_charge_index_and_base().first == 0); + } + + CHECK(is_ground_state(simulation_results_exgs, simulation_results_quicksim)); + } +} diff --git a/test/algorithms/simulation/sidb/is_groundstate.cpp b/test/algorithms/simulation/sidb/is_groundstate.cpp deleted file mode 100644 index 1b4d06568..000000000 --- a/test/algorithms/simulation/sidb/is_groundstate.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// -// Created by Jan Drewniok on 02.02.23. -// - -#include - -#include -#include -#include -#include -#include -#include -#include - -using namespace fiction; - -TEMPLATE_TEST_CASE("check if ground state is found", "[is-ground-state]", sidb_100_cell_clk_lyt_siqad, - cds_sidb_100_cell_clk_lyt_siqad) -{ - SECTION("layout with no SiDB placed") - { - TestType lyt{}; - const charge_distribution_surface charge_layout{lyt}; - const sidb_simulation_parameters params{2, -0.32}; - const auto simulation_results_exgs = exhaustive_ground_state_simulation(charge_layout, params); - const quicksim_params quicksim_params{params}; - const auto simulation_results_quicksim = quicksim(charge_layout, quicksim_params); - - CHECK(!is_ground_state(simulation_results_exgs, simulation_results_quicksim)); - } - - SECTION("layout with seven SiDBs placed") - { - TestType lyt{}; - - lyt.assign_cell_type({1, 3, 0}, TestType::cell_type::NORMAL); - lyt.assign_cell_type({3, 3, 0}, TestType::cell_type::NORMAL); - lyt.assign_cell_type({4, 3, 0}, TestType::cell_type::NORMAL); - - lyt.assign_cell_type({6, 3, 0}, TestType::cell_type::NORMAL); - lyt.assign_cell_type({7, 3, 0}, TestType::cell_type::NORMAL); - - lyt.assign_cell_type({6, 10, 0}, TestType::cell_type::NORMAL); - lyt.assign_cell_type({7, 10, 0}, TestType::cell_type::NORMAL); - - const charge_distribution_surface charge_layout{lyt}; - const sidb_simulation_parameters params{2, -0.32}; - - const auto simulation_results_exgs = exhaustive_ground_state_simulation(charge_layout, params); - - const quicksim_params quicksim_params{params}; - const auto simulation_results_quicksim = quicksim(charge_layout, quicksim_params); - - CHECK(is_ground_state(simulation_results_exgs, simulation_results_quicksim)); - } -} diff --git a/test/algorithms/simulation/sidb/time_to_solution.cpp b/test/algorithms/simulation/sidb/time_to_solution.cpp index 518cabc3d..a05b87e4e 100644 --- a/test/algorithms/simulation/sidb/time_to_solution.cpp +++ b/test/algorithms/simulation/sidb/time_to_solution.cpp @@ -5,20 +5,26 @@ #include #include +#include #include #include #include +#include #include #include +#include #include #include +#include #include +#include using namespace fiction; -TEMPLATE_TEST_CASE("time to solution test", "[time-to-solution]", (sidb_100_cell_clk_lyt_siqad), - (cds_sidb_100_cell_clk_lyt_siqad)) +// Test 1: Basic time-to-solution test with different layout types +TEMPLATE_TEST_CASE("Basic time-to-solution test with varying layouts", "[time-to-solution]", + sidb_100_cell_clk_lyt_siqad, cds_sidb_100_cell_clk_lyt_siqad) { TestType lyt{}; @@ -27,7 +33,7 @@ TEMPLATE_TEST_CASE("time to solution test", "[time-to-solution]", (sidb_100_cell const sidb_simulation_parameters params{2, -0.30}; const quicksim_params quicksim_params{params}; time_to_solution_stats tts_stat_quickexact{}; - const time_to_solution_params tts_params_quickexact{exhaustive_sidb_simulation_engine::QUICKEXACT}; + const time_to_solution_params tts_params_quickexact{exact_sidb_simulation_engine::QUICKEXACT}; time_to_solution(lyt, quicksim_params, tts_params_quickexact, &tts_stat_quickexact); CHECK(tts_stat_quickexact.algorithm == "QuickExact"); @@ -37,7 +43,7 @@ TEMPLATE_TEST_CASE("time to solution test", "[time-to-solution]", (sidb_100_cell CHECK(tts_stat_quickexact.mean_single_runtime > 0.0); time_to_solution_stats tts_stat_exgs{}; - const time_to_solution_params tts_params_exgs{exhaustive_sidb_simulation_engine::EXGS}; + const time_to_solution_params tts_params_exgs{exact_sidb_simulation_engine::EXGS}; time_to_solution(lyt, quicksim_params, tts_params_exgs, &tts_stat_exgs); CHECK(tts_stat_exgs.algorithm == "ExGS"); @@ -59,7 +65,7 @@ TEMPLATE_TEST_CASE("time to solution test", "[time-to-solution]", (sidb_100_cell const sidb_simulation_parameters params{2, -0.30}; const quicksim_params quicksim_params{params}; - const time_to_solution_params tts_params_exgs{exhaustive_sidb_simulation_engine::EXGS}; + const time_to_solution_params tts_params_exgs{exact_sidb_simulation_engine::EXGS}; time_to_solution_stats tts_stat_exgs{}; time_to_solution(lyt, quicksim_params, tts_params_exgs, &tts_stat_exgs); @@ -68,7 +74,7 @@ TEMPLATE_TEST_CASE("time to solution test", "[time-to-solution]", (sidb_100_cell CHECK(tts_stat_exgs.mean_single_runtime > 0.0); time_to_solution_stats tts_stat_quickexact{}; - const time_to_solution_params tts_params{exhaustive_sidb_simulation_engine::QUICKEXACT}; + const time_to_solution_params tts_params{exact_sidb_simulation_engine::QUICKEXACT}; time_to_solution(lyt, quicksim_params, tts_params, &tts_stat_quickexact); REQUIRE(tts_stat_quickexact.acc == 100.0); @@ -76,28 +82,19 @@ TEMPLATE_TEST_CASE("time to solution test", "[time-to-solution]", (sidb_100_cell CHECK(tts_stat_quickexact.mean_single_runtime > 0.0); // calculate tts manually. - double tts_calculated = 0.0; + double tts_calculated = (tts_stat_quickexact.acc == 100) ? tts_stat_quickexact.mean_single_runtime : + (tts_stat_quickexact.mean_single_runtime * + std::log(1.0 - tts_params.confidence_level) / + std::log(1.0 - tts_stat_quickexact.acc)); - if (tts_stat_quickexact.acc == 100) - { - tts_calculated = tts_stat_quickexact.mean_single_runtime; - } - else - { - tts_calculated = (tts_stat_quickexact.mean_single_runtime * std::log(1.0 - tts_params.confidence_level) / - std::log(1.0 - tts_stat_quickexact.acc)); - } CHECK_THAT(tts_stat_quickexact.time_to_solution - tts_calculated, Catch::Matchers::WithinAbs(0.0, physical_constants::POP_STABILITY_ERR)); } } -TEMPLATE_TEST_CASE("time to solution test, using offset coordinates", "[time-to-solution]", - (cell_level_layout>>), - (charge_distribution_surface< - cell_level_layout>>>)) +// Test 2: Offset coordinates time-to-solution test +TEMPLATE_TEST_CASE("time-to-solution test with offset coordinates", "[time-to-solution]", cds_sidb_100_cell_clk_lyt) { - TestType lyt{}; SECTION("layout with seven SiDBs placed") @@ -105,42 +102,91 @@ TEMPLATE_TEST_CASE("time to solution test, using offset coordinates", "[time-to- lyt.assign_cell_type({1, 6, 0}, TestType::cell_type::NORMAL); lyt.assign_cell_type({3, 6, 0}, TestType::cell_type::NORMAL); lyt.assign_cell_type({5, 6, 0}, TestType::cell_type::NORMAL); - lyt.assign_cell_type({7, 6, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({7, 2, 0}, TestType::cell_type::NORMAL); lyt.assign_cell_type({10, 6, 0}, TestType::cell_type::NORMAL); - lyt.assign_cell_type({12, 6, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({18, 9, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({20, 9, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({3, 3, 0}, TestType::cell_type::NORMAL); - const sidb_simulation_parameters params{3, -0.32}; - const quicksim_params quicksim_params{params}; + const sidb_simulation_parameters params{2, -0.32}; + + quicksim_params quicksim_params{params}; + quicksim_params.iteration_steps = 10; - const time_to_solution_params tts_params_exgs{exhaustive_sidb_simulation_engine::EXGS}; + const time_to_solution_params tts_params_exgs{exact_sidb_simulation_engine::EXGS}; time_to_solution_stats tts_stat_exgs{}; time_to_solution(lyt, quicksim_params, tts_params_exgs, &tts_stat_exgs); - CHECK(tts_stat_exgs.acc == 100); CHECK(tts_stat_exgs.time_to_solution > 0.0); CHECK(tts_stat_exgs.mean_single_runtime > 0.0); time_to_solution_stats tts_stat_quickexact{}; - const time_to_solution_params tts_params{exhaustive_sidb_simulation_engine::QUICKEXACT}; + const time_to_solution_params tts_params{exact_sidb_simulation_engine::QUICKEXACT}; time_to_solution(lyt, quicksim_params, tts_params, &tts_stat_quickexact); - REQUIRE(tts_stat_quickexact.acc == 100); CHECK(tts_stat_quickexact.time_to_solution > 0.0); CHECK(tts_stat_quickexact.mean_single_runtime > 0.0); - // calculate tts manually. - double tts_calculated = 0.0; + auto tts_calculated = std::numeric_limits::max(); if (tts_stat_quickexact.acc == 100) { tts_calculated = tts_stat_quickexact.mean_single_runtime; + CHECK_THAT(tts_stat_quickexact.time_to_solution - tts_calculated, + Catch::Matchers::WithinAbs(0.0, physical_constants::POP_STABILITY_ERR)); } - else + else if (tts_stat_quickexact.acc != 0) { tts_calculated = (tts_stat_quickexact.mean_single_runtime * std::log(1.0 - tts_params.confidence_level) / - std::log(1.0 - tts_stat_quickexact.acc)); + std::log(1.0 - tts_stat_quickexact.acc / 100)); + CHECK_THAT(tts_stat_quickexact.time_to_solution - tts_calculated, + Catch::Matchers::WithinAbs(0.0, physical_constants::POP_STABILITY_ERR)); } - CHECK_THAT(tts_stat_quickexact.time_to_solution - tts_calculated, + } +} + +TEMPLATE_TEST_CASE("time-to-solution test with simulation results", "[time-to-solution]", sidb_100_cell_clk_lyt, + cds_sidb_100_cell_clk_lyt) +{ + TestType lyt{}; + + SECTION("layout with seven SiDBs placed") + { + lyt.assign_cell_type({1, 6, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({3, 6, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({5, 6, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({7, 6, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({10, 6, 0}, TestType::cell_type::NORMAL); + lyt.assign_cell_type({12, 6, 0}, TestType::cell_type::NORMAL); + + const sidb_simulation_parameters params{3, -0.32}; + const quicksim_params quicksim_params{params}; + + const std::size_t number_of_repetitions = 100; + std::vector> simulation_results_quicksim{}; + simulation_results_quicksim.reserve(number_of_repetitions); + + for (auto i = 0u; i < number_of_repetitions; i++) + { + simulation_results_quicksim.push_back(quicksim(lyt, quicksim_params)); + } + + const auto simulation_results_quickexact = + quickexact(lyt, quickexact_params>{quicksim_params.simulation_parameters}); + + time_to_solution_stats st{}; + time_to_solution_for_given_simulation_results(simulation_results_quickexact, simulation_results_quicksim, 0.997, + &st); + + REQUIRE(st.acc == 100); + CHECK(st.time_to_solution > 0.0); + CHECK(st.mean_single_runtime > 0.0); + + const auto tts_calculated = (st.acc == 100) ? + st.mean_single_runtime : + (st.mean_single_runtime * std::log(1.0 - 0.997) / std::log(1.0 - st.acc)); + + CHECK_THAT(st.time_to_solution - tts_calculated, Catch::Matchers::WithinAbs(0.0, physical_constants::POP_STABILITY_ERR)); } } diff --git a/test/technology/charge_distribution_surface.cpp b/test/technology/charge_distribution_surface.cpp index d7bbdbc8b..11b6755c7 100644 --- a/test/technology/charge_distribution_surface.cpp +++ b/test/technology/charge_distribution_surface.cpp @@ -139,7 +139,7 @@ TEMPLATE_TEST_CASE("Assign and delete charge states without defects", "[charge-d CHECK(charge_layout.get_charge_index_and_base().first == 0); charge_layout.increase_charge_index_by_one(dependent_cell_mode::FIXED, energy_calculation::UPDATE_ENERGY, charge_distribution_history::NEGLECT, - exhaustive_sidb_simulation_engine::EXGS); + exact_sidb_simulation_engine::EXGS); CHECK(charge_layout.get_charge_index_and_base().first == 1); CHECK(charge_layout.get_charge_state_by_index(0) == sidb_charge_state::NEGATIVE); CHECK(charge_layout.get_charge_state_by_index(1) == sidb_charge_state::NEGATIVE); @@ -156,7 +156,7 @@ TEMPLATE_TEST_CASE("Assign and delete charge states without defects", "[charge-d CHECK(charge_layout_quickexact.get_charge_index_and_base().first == 0); charge_layout_quickexact.increase_charge_index_by_one( dependent_cell_mode::FIXED, energy_calculation::UPDATE_ENERGY, charge_distribution_history::NEGLECT, - exhaustive_sidb_simulation_engine::QUICKEXACT); + exact_sidb_simulation_engine::QUICKEXACT); CHECK(charge_layout_quickexact.get_charge_index_and_base().first == 1); CHECK(charge_layout_quickexact.get_charge_state_by_index(0) == sidb_charge_state::NEGATIVE); CHECK(charge_layout_quickexact.get_charge_state_by_index(1) == sidb_charge_state::NEGATIVE); @@ -249,7 +249,7 @@ TEMPLATE_TEST_CASE("Assign and delete charge states without defects", "[charge-d CHECK(charge_layout.get_system_energy() < system_energy_maximum); CHECK(charge_layout.get_charge_index_of_sub_layout() == 8); - charge_layout.reset_charge_index_sub_layout(exhaustive_sidb_simulation_engine::EXGS); + charge_layout.reset_charge_index_sub_layout(exact_sidb_simulation_engine::EXGS); CHECK(charge_layout.get_charge_index_of_sub_layout() == 0); CHECK(charge_layout.get_charge_state({6, 5}) == sidb_charge_state::NEGATIVE); CHECK(charge_layout.get_charge_state({7, 5}) == sidb_charge_state::NEGATIVE); @@ -346,7 +346,7 @@ TEMPLATE_TEST_CASE("Assign and delete charge states without defects", "[charge-d charge_layout.increase_charge_index_of_sub_layout_by_one( dependent_cell_mode::FIXED, energy_calculation::UPDATE_ENERGY, charge_distribution_history::NEGLECT, - exhaustive_sidb_simulation_engine::EXGS); + exact_sidb_simulation_engine::EXGS); CHECK(charge_layout.get_charge_index_of_sub_layout() == 3); // set the charge index to zero and thereby, all siDBs to negatively charged. From b757052e388cfa40a061802cbf7ecbd388f472ad Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 21 Aug 2024 18:24:28 +0200 Subject: [PATCH 02/13] :bug: Fixed a RST documentation bug that prevented `exact` and `exact_with_blacklist` to be rendered properly (#506) --- docs/algorithms/exact.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/algorithms/exact.rst b/docs/algorithms/exact.rst index fcf0424e9..a6a23985d 100644 --- a/docs/algorithms/exact.rst +++ b/docs/algorithms/exact.rst @@ -14,10 +14,8 @@ network specifications under constraints. This approach finds exact results but :members: .. doxygenstruct:: fiction::exact_physical_design_stats :members: - .. doxygenfunction:: fiction::exact(const Ntk& ntk, const exact_physical_design_params& ps = {}, exact_physical_design_stats* pst = nullptr) - .. doxygenfunction:: exact_with_blacklist(const Ntk& ntk, const surface_black_list& black_list, - exact_physical_design_params ps = {}, - exact_physical_design_stats* pst = nullptr) + .. doxygenfunction:: fiction::exact(const Ntk& ntk, const exact_physical_design_params& ps = {}, exact_physical_design_stats *pst = nullptr) + .. doxygenfunction:: fiction::exact_with_blacklist(const Ntk& ntk, const surface_black_list& black_list, exact_physical_design_params ps = {}, exact_physical_design_stats* pst = nullptr) .. tab:: Python .. autoclass:: mnt.pyfiction.exact_params From 64fb20beeea724f578508b1daeb3b4c2e8de1ec7 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 22 Aug 2024 00:28:21 +0200 Subject: [PATCH 03/13] :bookmark: Bump version to 0.6.3 (#504) * :memo: Updated the CHANGELOG * :bookmark: Bump version to v0.6.3 * :memo: Updated CHANGELOG to include TTS --- CMakeLists.txt | 2 +- docs/changelog.rst | 33 +++++++++++++++++++++++++++++++++ docs/conf.py | 4 ++-- pyproject.toml | 2 +- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 67df85077..d4b4bc24d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) # Set the project name and version project( fiction - VERSION 0.6.2 + VERSION 0.6.3 DESCRIPTION "An open-source design automation framework for Field-coupled Nanotechnologies" HOMEPAGE_URL "https://github.com/cda-tum/fiction" diff --git a/docs/changelog.rst b/docs/changelog.rst index 733e198fa..23344b0b2 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file. The format is based on `Keep a Changelog `_. +v0.6.3 - 2024-08-21 +------------------- + +Added +##### +- Algorithms: + - Physical Design: + - Graph-Oriented Layout Design (GOLD) for 2DDWave-clocked Cartesian gate-level layouts to trade-off runtime vs. result quality (based on `this paper `_) + - Flag for planar post-layout optimization + - Flag for optimizing POs only in post-layout optimization + - Simulation: + - Defect-aware on-the-fly SiDB circuit design on defective H-Si surfaces (based on `this paper `_) + - Displacement robustness domain simulation for SiDB layouts + - Finding valid physical parameters for a given SiDB layout charge distribution + - Multi-dimensional operational domain computation for SiDB layouts + +Changed +####### +- Switched from execution policy-based multithreading to manual thread management in operational domain computation for platform-independence and better performance in the Python bindings +- Extended time-to-solution (TTS) calculation functions +- Add a warning when leak sanitizers are used with AppleClang since they are not supported +- Switched to new compiler and OS versions in the GitHub Actions workflows +- Updated all libraries to the latest versions + +Fixed +##### +- Utilizing tolerance to mitigate floating-point inaccuracies in operational domain computation +- Some bugs in post-layout optimization +- Corner case in ``ortho`` regarding multi-output nodes +- Enable relocation of all 2-input gates during post-layout optimization + + v0.6.2 - 2024-05-22 ------------------- @@ -19,6 +51,7 @@ Fixed - ``detect_bdl_pairs`` no longer require the ``_100`` or ``_111`` suffix - Minor inconsistencies + v0.6.1 - 2024-05-16 ------------------- diff --git a/docs/conf.py b/docs/conf.py index 0d172912c..6a0805b9e 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,9 +51,9 @@ # built documents. # # The short X.Y version. -version = 'v0.6.2' +version = 'v0.6.3' # The full version, including alpha/beta/rc tags. -release = 'v0.6.2' +release = 'v0.6.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index f16348060..3d0322509 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta" [project] name = "mnt.pyfiction" -version = "0.6.2" +version = "0.6.3" description = "Design Automation for Field-coupled Nanotechnologies" readme = "README.md" authors = [ From 269d4d267a3b31774795c8828ad6a13152719302 Mon Sep 17 00:00:00 2001 From: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:55:31 +0200 Subject: [PATCH 04/13] :bug: clang-tidy comments were not posted (#505) * Update clang-tidy-review-post.yml * Update clang-tidy-review.yml --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/clang-tidy-review.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/clang-tidy-review.yml b/.github/workflows/clang-tidy-review.yml index cbb464c2b..4ef258013 100644 --- a/.github/workflows/clang-tidy-review.yml +++ b/.github/workflows/clang-tidy-review.yml @@ -1,4 +1,4 @@ -name: 🚨 • Clang-Tidy Review +name: Clang-Tidy Review on: pull_request: From ab74363f824095e4419f62e200d0048c6d670c1e Mon Sep 17 00:00:00 2001 From: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:02:41 +0200 Subject: [PATCH 05/13] =?UTF-8?q?=F0=9F=93=9D=20Add=20`gold`=20to=20README?= =?UTF-8?q?=20and=20docs=20(#508)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update README.md * Update cli.rst * Apply suggestions from code review Co-authored-by: Marcel Walter Signed-off-by: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com> --------- Signed-off-by: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com> Co-authored-by: Marcel Walter --- README.md | 1 + docs/cli.rst | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/README.md b/README.md index 66e570b6d..0a6d97d24 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,7 @@ Among these algorithms are - OGD-based [scalable placement and routing](https://dl.acm.org/citation.cfm?id=3287705) - SAT-based [one-pass synthesis](https://ieeexplore.ieee.org/document/9371573) - SAT-based [multi-path routing](https://dl.acm.org/doi/10.1145/3565478.3572539) +- Graph-oriented [layout design](https://www.cda.cit.tum.de/files/eda/2024_ieee_nano_a_star_is_born.pdf) plus several path-finding algorithms that work on generic layouts: diff --git a/docs/cli.rst b/docs/cli.rst index 22f1c583a..36b4b732d 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -192,6 +192,20 @@ FCN circuit implementation of some specification under the provided parameters. The possible parameters are similar to the ones used for ``exact``. See ``onepass -h`` for a full list. +Graph-oriented layout design (``gold``) +####################################### + +Generates gate-level layouts from logic network specifications by spanning a search space graph where each placement event can be represented as a search space vertex characterized by a partial layout at that instance. Edges between a partial layout ``a`` and ``b`` exist iff a can be transformed into ``b`` via a single placement event. Similar to navigating through a maze, A*-search can be employed to discover a path from the starting vertex (the empty layout) to the exit of the maze (a layout with all gates placed). This approach is scalable but requires that the input network is restricted to a 3-graph. At the same time, the output layout will always be 2DDWave-clocked and is not always optimal. For more information, see +`the paper `_. + +Possible parameters: + +- Timeout (``-t``), in seconds. +- Number of expansions (``-n``) for each vertex in the search space graph, defaults to 4. +- High effort mode (``-e``), should be set if more runtime is available to find layouts with even less area, not set by default. +- Return first (``-r``), to return the first found layout, not set by default. +- Planar (``-p``), should be set to create layouts without crossings, not set by default. + Hexagonalization (``hex``) ########################## @@ -211,6 +225,7 @@ Possible parameters: - Number of maximum gate relocations (``-m``), should be set to 1 for layouts with more than 100000 tiles, defaults to the number of tiles in the layout. - Wiring reduction only (``-w``), should be set for layouts with more than 20000000 tiles, not set by default. +- Planar optimization (``-p``), should be set if during optimization, gates should only be relocated if the new wiring contains no crossings, not set by default. Design rule checking (``check``) -------------------------------- From b03282c9412647df67d3a7062c18efe5e629694d Mon Sep 17 00:00:00 2001 From: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com> Date: Thu, 22 Aug 2024 18:21:32 +0200 Subject: [PATCH 06/13] =?UTF-8?q?=F0=9F=9A=A8=20clang-tidy=20warnings=20(#?= =?UTF-8?q?507)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * clang-tidy suggestions * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * Update clang-tidy-review.yml * Update orthogonal.hpp * 🎨 Incorporated pre-commit fixes --------- Signed-off-by: GitHub Actions Co-authored-by: GitHub Actions Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .github/workflows/clang-tidy-review.yml | 2 +- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 14 ++++++++ .../graph_oriented_layout_design.hpp | 32 +++++++++++------- .../algorithms/physical_design/orthogonal.hpp | 33 ++----------------- .../graph_oriented_layout_design.cpp | 2 -- 5 files changed, 38 insertions(+), 45 deletions(-) diff --git a/.github/workflows/clang-tidy-review.yml b/.github/workflows/clang-tidy-review.yml index 4ef258013..31483f1ec 100644 --- a/.github/workflows/clang-tidy-review.yml +++ b/.github/workflows/clang-tidy-review.yml @@ -16,7 +16,7 @@ concurrency: jobs: clangtidy: runs-on: ubuntu-latest - name: Clang-Tidy + name: 🚨 Clang-Tidy steps: - name: Clone Repository diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 1f98fce8a..fce00223b 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -3971,6 +3971,20 @@ static const char *__doc_fiction_detail_color_routing_impl_pst = R"doc(Statistic static const char *__doc_fiction_detail_color_routing_impl_run = R"doc()doc"; +static const char *__doc_fiction_detail_coloring_container = R"doc()doc"; + +static const char *__doc_fiction_detail_coloring_container_color_east = R"doc()doc"; + +static const char *__doc_fiction_detail_coloring_container_color_ntk = R"doc()doc"; + +static const char *__doc_fiction_detail_coloring_container_color_null = R"doc()doc"; + +static const char *__doc_fiction_detail_coloring_container_color_south = R"doc()doc"; + +static const char *__doc_fiction_detail_coloring_container_coloring_container = R"doc()doc"; + +static const char *__doc_fiction_detail_coloring_container_opposite_color = R"doc()doc"; + static const char *__doc_fiction_detail_compare_gate_tiles = R"doc(Custom comparison function for sorting tiles based on the sum of their coordinates that breaks ties based on the x-coordinate. diff --git a/include/fiction/algorithms/physical_design/graph_oriented_layout_design.hpp b/include/fiction/algorithms/physical_design/graph_oriented_layout_design.hpp index 2fafe6e62..d8c538f2a 100644 --- a/include/fiction/algorithms/physical_design/graph_oriented_layout_design.hpp +++ b/include/fiction/algorithms/physical_design/graph_oriented_layout_design.hpp @@ -228,7 +228,7 @@ using node_dict_type = mockturtle::node_map, Ntk>; /** * This enum class indicates the allowed positions for PIs. */ -enum class pi_locations +enum class pi_locations : std::uint8_t { /** * Flag indicating if primary inputs (PIs) can be placed at the top. @@ -263,11 +263,11 @@ struct search_space_graph /** * The network associated with this search space graph. */ - tec_nt network{}; + tec_nt network; /** * Topological list of nodes to be placed in the layout. */ - std::vector> nodes_to_place{}; + std::vector> nodes_to_place; /** * Enum indicating if primary inputs (PIs) can be placed at the top or left. */ @@ -508,7 +508,7 @@ class topo_view_ci_to_co : public mockturtle::immutable_view if (this->visited(this->get_node(f)) != this->trav_id()) { not_visited = true; - }; + } }); if (not_visited) @@ -532,7 +532,7 @@ class topo_view_ci_to_co : public mockturtle::immutable_view * When checking for possible paths on a layout between two tiles SRC and DEST, one of them could also be the new tile * for the next gate to be placed and it therefore has to be checked if said tile is still empty */ -enum class new_gate_location +enum class new_gate_location : std::uint8_t { /** * Do not check any tiles. @@ -823,9 +823,21 @@ class graph_oriented_layout_design_impl } }; - const uint64_t max_iterations = (pi_locs == pi_locations::TOP_AND_LEFT) ? - std::max(layout.x(), layout.y()) : - ((pi_locs == pi_locations::TOP) ? layout.x() : layout.y()); + uint64_t max_iterations = 0; + + if (pi_locs == pi_locations::TOP_AND_LEFT) + { + max_iterations = std::max(layout.x(), layout.y()); + } + else if (pi_locs == pi_locations::TOP) + { + max_iterations = layout.x(); + } + else + { + max_iterations = layout.y(); + } + const uint64_t expansion_limit = (pi_locs == pi_locations::TOP_AND_LEFT) ? 2 * num_expansions : num_expansions; possible_positions.reserve(expansion_limit); @@ -1401,8 +1413,6 @@ class graph_oriented_layout_design_impl node_dict_type node2pos{ssg.network}; placement_info place_info{0ul, 0ul, node2pos, pi2node}; - bool found_solution = false; - coord_vec_type possible_positions{}; possible_positions.reserve(2 * ssg.num_expansions); @@ -1415,7 +1425,7 @@ class graph_oriented_layout_design_impl { const auto position = ssg.current_vertex[idx]; - found_solution = place_and_route(position, layout, ssg, place_info); + bool found_solution = place_and_route(position, layout, ssg, place_info); uint64_t area = 0ul; diff --git a/include/fiction/algorithms/physical_design/orthogonal.hpp b/include/fiction/algorithms/physical_design/orthogonal.hpp index c792353f1..88eb52c65 100644 --- a/include/fiction/algorithms/physical_design/orthogonal.hpp +++ b/include/fiction/algorithms/physical_design/orthogonal.hpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -63,36 +64,6 @@ struct orthogonal_physical_design_stats namespace detail { -/** - * Determine siblings of the given node. A sibling is a node that shares the same fan-in with n. - * @param n Node to consider. - * @return Siblings of n. - */ -template -std::vector> siblings(const Ntk& ntk, const mockturtle::node n) noexcept -{ - std::vector> sibs{}; - ntk.foreach_fanin(n, - [&ntk, &sibs, &n](const auto& fi) - { - // skip constants - if (const auto fin = ntk.get_node(fi); !ntk.is_constant(fin)) - { - ntk.foreach_fanout(fin, - [&ntk, &sibs, &n](const auto& fon) - { - // do not consider constants or n itself - if (!ntk.is_constant(fon) && (fon != n)) - { - sibs.push_back(fon); - } - }); - } - }); - - return sibs; -} - template struct coloring_container { @@ -104,7 +75,7 @@ struct coloring_container out_of_place_edge_color_view color_ntk; - const uint32_t color_null = 0ul, color_east, color_south; + uint32_t color_null = 0ul, color_east, color_south; [[nodiscard]] uint32_t opposite_color(const uint32_t c) const noexcept { diff --git a/test/algorithms/physical_design/graph_oriented_layout_design.cpp b/test/algorithms/physical_design/graph_oriented_layout_design.cpp index 1dda06fc2..edfdf2a91 100644 --- a/test/algorithms/physical_design/graph_oriented_layout_design.cpp +++ b/test/algorithms/physical_design/graph_oriented_layout_design.cpp @@ -23,8 +23,6 @@ #include #include -#include - using namespace fiction; template From 587e15c4e9c22eeb42b2f515424d0fe040838573 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 07:51:51 +0000 Subject: [PATCH 07/13] :arrow_up: Bump libs/pybind11 in the submodules group (#509) --- libs/pybind11 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/pybind11 b/libs/pybind11 index a1d00916b..c2291e597 160000 --- a/libs/pybind11 +++ b/libs/pybind11 @@ -1 +1 @@ -Subproject commit a1d00916b26b187e583f3bce39cd59c3b0652c32 +Subproject commit c2291e597ffe4fb028ae4ff97c5cd4fc20a8a7f9 From b10a2e4acd4d7ae2754a4bc3118c66c747a1afea Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Sat, 24 Aug 2024 20:11:38 +0200 Subject: [PATCH 08/13] :pencil2: Fixed a typo in robustness domain analysis (#511) * :pencil2: Fixed a typo * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --------- Signed-off-by: GitHub Actions Co-authored-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 6 ++--- docs/algorithms/sidb_simulation.rst | 2 +- .../sidb/displacement_robustness_domain.hpp | 8 +++---- .../sidb/displacement_robustness_domain.cpp | 24 +++++++++---------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index fce00223b..885751caa 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -4352,7 +4352,7 @@ 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 = +static const char *__doc_fiction_detail_displacement_robustness_domain_impl_determine_probability_of_fabricating_operational_gate = R"doc(The manufacturing error rate is highly dependent on the speed of the manufacturing process. Therefore, fast fabrication requires SiDB layouts with high displacement tolerance to ensure functionality in @@ -8207,7 +8207,7 @@ Parameter ``params``: number of the given charge distribution surface for each parameter point.)doc"; -static const char *__doc_fiction_determine_propability_of_fabricating_operational_gate = +static const char *__doc_fiction_determine_probability_of_fabricating_operational_gate = R"doc(During fabrication, SiDBs may not align precisely with their intended atomic positions, resulting in displacement. This means that an SiDB is fabricated close to the desired one, typically one or a few H-Si @@ -8355,7 +8355,7 @@ from applying a displacement to a given SiDB layout.)doc"; static const char *__doc_fiction_displacement_robustness_domain_params = R"doc(Parameters for the `determine_displacement_robustness_domain` and -`determine_propability_of_fabricating_operational_gate` algorithms. +`determine_probability_of_fabricating_operational_gate` algorithms. Parameter ``CellType``: SiDB layout cell type.)doc"; diff --git a/docs/algorithms/sidb_simulation.rst b/docs/algorithms/sidb_simulation.rst index 6e17b8d43..f1e6be0e1 100644 --- a/docs/algorithms/sidb_simulation.rst +++ b/docs/algorithms/sidb_simulation.rst @@ -305,7 +305,7 @@ Displacement Robustness Domain .. doxygenstruct:: fiction::displacement_robustness_domain_stats :members: .. doxygenfunction:: fiction::determine_displacement_robustness_domain - .. doxygenfunction:: fiction::determine_propability_of_fabricating_operational_gate + .. doxygenfunction:: fiction::determine_probability_of_fabricating_operational_gate .. tab:: Python .. autoclass:: mnt.pyfiction.displacement_analysis_mode diff --git a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp index e22b18e43..611f52e79 100644 --- a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp @@ -50,7 +50,7 @@ struct displacement_robustness_domain /** * Parameters for the `determine_displacement_robustness_domain` and - * `determine_propability_of_fabricating_operational_gate` algorithms. + * `determine_probability_of_fabricating_operational_gate` algorithms. * * @param CellType SiDB layout cell type. */ @@ -263,7 +263,7 @@ class displacement_robustness_domain_impl * SiDBs have a slight displacement. * @return Probability of fabricating a working SiDB gate implementation. */ - [[nodiscard]] double determine_propability_of_fabricating_operational_gate(double fabrication_error_rate) + [[nodiscard]] double determine_probability_of_fabricating_operational_gate(double fabrication_error_rate) { // The maximum error rate is 1.0. fabrication_error_rate = std::min(1.0, fabrication_error_rate); @@ -626,7 +626,7 @@ determine_displacement_robustness_domain(const Lyt& layout, const std::vector -[[nodiscard]] double determine_propability_of_fabricating_operational_gate( +[[nodiscard]] double determine_probability_of_fabricating_operational_gate( const Lyt& layout, const std::vector& spec, const displacement_robustness_domain_params>& params = {}, const double fabrication_error_rate = 1.0) { @@ -636,7 +636,7 @@ template displacement_robustness_domain_stats st{}; detail::displacement_robustness_domain_impl p{layout, spec, params, st}; - return p.determine_propability_of_fabricating_operational_gate(fabrication_error_rate); + return p.determine_probability_of_fabricating_operational_gate(fabrication_error_rate); } } // namespace fiction diff --git a/test/algorithms/simulation/sidb/displacement_robustness_domain.cpp b/test/algorithms/simulation/sidb/displacement_robustness_domain.cpp index 0028728a6..7374d7489 100644 --- a/test/algorithms/simulation/sidb/displacement_robustness_domain.cpp +++ b/test/algorithms/simulation/sidb/displacement_robustness_domain.cpp @@ -103,7 +103,7 @@ TEST_CASE("Determine the probability of fabricating an operational SiQAD Y-shape params.operational_params.bdl_params.minimum_distance = 0.2; const auto result = - determine_propability_of_fabricating_operational_gate(lyt, std::vector{create_and_tt()}, params, 0.3); + determine_probability_of_fabricating_operational_gate(lyt, std::vector{create_and_tt()}, params, 0.3); CHECK_THAT(result, Catch::Matchers::WithinAbs(0.83, 0.1)); } } @@ -126,7 +126,7 @@ TEST_CASE("Determine the probability of fabricating an operational Bestagon AND params.percentage_of_analyzed_displaced_layouts = 0.1; const auto result = - determine_propability_of_fabricating_operational_gate(lyt, std::vector{create_and_tt()}, params, 0.1); + determine_probability_of_fabricating_operational_gate(lyt, std::vector{create_and_tt()}, params, 0.1); CHECK(result >= -std::numeric_limits::epsilon()); } } @@ -150,7 +150,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL wire with // Each SiDB can show a displacement. const auto result = - determine_propability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 1.0); + determine_probability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 1.0); displacement_robustness_domain_stats stats{}; const auto result_displacement_domain = @@ -163,7 +163,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL wire with CHECK_THAT(result, Catch::Matchers::WithinAbs(0.625, physical_constants::POP_STABILITY_ERR)); const auto result_20_percent_error = - determine_propability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 0.2); + determine_probability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 0.2); CHECK(result_20_percent_error > result); } @@ -181,7 +181,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL wire with cell>::displacement_analysis_mode::EXHAUSTIVE; const auto result = - determine_propability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 0.2); + determine_probability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 0.2); CHECK_THAT(result, Catch::Matchers::WithinAbs(0.66666666666666, physical_constants::POP_STABILITY_ERR)); } @@ -194,7 +194,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL wire with params.operational_params.bdl_params.minimum_distance = 0.2; const auto result = - determine_propability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 0.0); + determine_probability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 0.0); CHECK_THAT(result, Catch::Matchers::WithinAbs(1.00, physical_constants::POP_STABILITY_ERR)); } @@ -207,7 +207,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL wire with params.operational_params.bdl_params.minimum_distance = 0.2; const auto result = - determine_propability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 0.0); + determine_probability_of_fabricating_operational_gate(lyt, std::vector{create_id_tt()}, params, 0.0); CHECK_THAT(result, Catch::Matchers::WithinAbs(1.0, physical_constants::POP_STABILITY_ERR)); } } @@ -232,7 +232,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL, offset c displacement_robustness_domain_params>::displacement_analysis_mode::EXHAUSTIVE; // Each SiDB can show a displacement. - const auto result = determine_propability_of_fabricating_operational_gate( + const auto result = determine_probability_of_fabricating_operational_gate( lyt_offset, std::vector{create_id_tt()}, params, 1.0); displacement_robustness_domain_stats stats{}; @@ -245,7 +245,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL, offset c CHECK_THAT(result, Catch::Matchers::WithinAbs(0.625, physical_constants::POP_STABILITY_ERR)); - const auto result_20_percent_error = determine_propability_of_fabricating_operational_gate( + const auto result_20_percent_error = determine_probability_of_fabricating_operational_gate( lyt_offset, std::vector{create_id_tt()}, params, 0.2); CHECK(result_20_percent_error > result); @@ -263,7 +263,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL, offset c params.analysis_mode = displacement_robustness_domain_params>::displacement_analysis_mode::EXHAUSTIVE; - const auto result_20_percent_error = determine_propability_of_fabricating_operational_gate( + const auto result_20_percent_error = determine_probability_of_fabricating_operational_gate( lyt_offset, std::vector{create_id_tt()}, params, 0.2); CHECK(result_20_percent_error < 1); } @@ -276,7 +276,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL, offset c params.operational_params.bdl_params.maximum_distance = 2.0; params.operational_params.bdl_params.minimum_distance = 0.2; - const auto result = determine_propability_of_fabricating_operational_gate( + const auto result = determine_probability_of_fabricating_operational_gate( lyt_offset, std::vector{create_id_tt()}, params, 0.0); CHECK_THAT(result, Catch::Matchers::WithinAbs(1.00, physical_constants::POP_STABILITY_ERR)); } @@ -289,7 +289,7 @@ TEST_CASE("Determine the probability of fabricating an operational BDL, offset c params.operational_params.bdl_params.maximum_distance = 2.0; params.operational_params.bdl_params.minimum_distance = 0.2; - const auto result = determine_propability_of_fabricating_operational_gate( + const auto result = determine_probability_of_fabricating_operational_gate( lyt_offset, std::vector{create_id_tt()}, params, 0.0); CHECK_THAT(result, Catch::Matchers::WithinAbs(1.0, physical_constants::POP_STABILITY_ERR)); } From fd1edcc7b2a5865ffb51704e5e53532da3fd15f5 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Tue, 27 Aug 2024 14:14:02 +0200 Subject: [PATCH 09/13] :sparkles: Squared Euclidean and Chebyshev distance functions (#512) * :sparkles: Added squared Euclidean distance and Chebyshev distance functions * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * :snake: Added Python bindings for the new distance functions * :memo: Added documentation for the new distance functions * :art: Added the `` header for `std::max` as pointed out by clang-tidy * :memo: Added a CHANGELOG entry --------- Signed-off-by: GitHub Actions Co-authored-by: GitHub Actions --- .../algorithms/path_finding/distance.hpp | 4 + .../pyfiction/pybind11_mkdoc_docstrings.hpp | 80 +++++++++ .../algorithms/path_finding/test_distance.py | 29 +++ docs/algorithms/path_finding.rst | 6 + docs/changelog.rst | 10 ++ .../algorithms/path_finding/distance.hpp | 79 ++++++++- test/algorithms/path_finding/distance.cpp | 165 +++++++++++++++++- 7 files changed, 371 insertions(+), 2 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/path_finding/distance.hpp b/bindings/pyfiction/include/pyfiction/algorithms/path_finding/distance.hpp index 44cea461b..3eb9bc36f 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/path_finding/distance.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/path_finding/distance.hpp @@ -27,8 +27,12 @@ void distance(pybind11::module& m) DOC(fiction_manhattan_distance)); m.def("euclidean_distance", &fiction::euclidean_distance, "layout"_a, "source"_a, "target"_a, DOC(fiction_euclidean_distance)); + m.def("squared_euclidean_distance", &fiction::squared_euclidean_distance, "layout"_a, "source"_a, "target"_a, + DOC(fiction_squared_euclidean_distance)); m.def("twoddwave_distance", &fiction::twoddwave_distance, "layout"_a, "source"_a, "target"_a, DOC(fiction_twoddwave_distance)); + m.def("chebyshev_distance", &fiction::chebyshev_distance, "layout"_a, "source"_a, "target"_a, + DOC(fiction_chebyshev_distance)); } } // namespace detail diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 885751caa..521039a27 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -1968,6 +1968,44 @@ Parameter ``cs``: Returns: Integer representing the SiDB's charge state.)doc"; +static const char *__doc_fiction_chebyshev_distance = +R"doc(The Chebyshev distance :math:`D` between two layout coordinates +:math:`(x_1, y_1)` and :math:`(x_2, y_2)` given by + +:math:`D = \max(|x_2 - x_1|, |y_2 - y_1|)` + +In contrast to the Manhattan distance, this function assumes the same +cost for diagonal moves as it does for horizontal and vertical ones. + +Template parameter ``Lyt``: + Coordinate layout type. + +Template parameter ``Dist``: + Integral type for the distance. + +Parameter ``lyt``: + Layout. + +Parameter ``source``: + Source coordinate. + +Parameter ``target``: + Target coordinate. + +Returns: + Chebyshev distance between `source` and `target`.)doc"; + +static const char *__doc_fiction_chebyshev_distance_functor = +R"doc(A pre-defined distance functor that uses the Chebyshev distance. + +Template parameter ``Lyt``: + Coordinate layout type. + +Template parameter ``Dist``: + Integral distance type.)doc"; + +static const char *__doc_fiction_chebyshev_distance_functor_chebyshev_distance_functor = R"doc()doc"; + static const char *__doc_fiction_check_simulation_results_for_equivalence = R"doc(This function compares two SiDB simulation results for equivalence. Two results are considered equivalent if they have the same number of @@ -16096,6 +16134,48 @@ static const char *__doc_fiction_sqd_parsing_error = R"doc(Exception thrown when static const char *__doc_fiction_sqd_parsing_error_sqd_parsing_error = R"doc()doc"; +static const char *__doc_fiction_squared_euclidean_distance = +R"doc(The squared Euclidean distance :math:`D` between two layout +coordinates :math:`(x_1, y_1)` and :math:`(x_2, y_2)` given by + +:math:`D = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}^2 = (x_1 - x_2)^2 + +(y_1 - y_2)^2` + +In contrast to the regular Euclidean distance, this function is +differentiable and can be used in optimization algorithms that require +gradients. Additionally, it is computationally cheaper by omitting the +square root operation. + +Template parameter ``Lyt``: + Coordinate layout type. + +Template parameter ``Dist``: + Integral type for the distance. + +Parameter ``lyt``: + Layout. + +Parameter ``source``: + Source coordinate. + +Parameter ``target``: + Target coordinate. + +Returns: + Squared euclidean distance between `source` and `target`.)doc"; + +static const char *__doc_fiction_squared_euclidean_distance_functor = +R"doc(A pre-defined distance functor that uses the squared Euclidean +distance. + +Template parameter ``Lyt``: + Coordinate layout type. + +Template parameter ``Dist``: + Integral distance type.)doc"; + +static const char *__doc_fiction_squared_euclidean_distance_functor_squared_euclidean_distance_functor = R"doc()doc"; + static const char *__doc_fiction_sweep_parameter = R"doc(Possible sweep parameters for the operational domain computation.)doc"; static const char *__doc_fiction_sweep_parameter_EPSILON_R = R"doc(The relative permittivity of the dielectric material.)doc"; diff --git a/bindings/pyfiction/test/algorithms/path_finding/test_distance.py b/bindings/pyfiction/test/algorithms/path_finding/test_distance.py index 4b5575498..4990939de 100644 --- a/bindings/pyfiction/test/algorithms/path_finding/test_distance.py +++ b/bindings/pyfiction/test/algorithms/path_finding/test_distance.py @@ -35,6 +35,20 @@ def test_euclidean(self): self.assertAlmostEqual(euclidean_distance(lyt, offset_coordinate(0, 0), offset_coordinate(4, 4)), 4 * 2 ** 0.5) + def test_squared_euclidean(self): + for lyt in [cartesian_layout((4, 4)), clocked_cartesian_layout((4, 4), "2DDWave"), + cartesian_gate_layout((4, 4), "2DDWave", "Layout"), shifted_cartesian_layout((4, 4)), + clocked_shifted_cartesian_layout((4, 4), "2DDWave"), + shifted_cartesian_gate_layout((4, 4), "2DDWave", "Layout"), hexagonal_layout((4, 4)), + clocked_hexagonal_layout((4, 4), "2DDWave"), hexagonal_gate_layout((4, 4), "2DDWave", "Layout")]: + self.assertEqual(squared_euclidean_distance(lyt, offset_coordinate(0, 0), offset_coordinate(0, 0)), 0) + self.assertEqual(squared_euclidean_distance(lyt, offset_coordinate(0, 0), offset_coordinate(1, 0)), 1) + self.assertEqual(squared_euclidean_distance(lyt, offset_coordinate(0, 0), offset_coordinate(0, 1)), 1) + self.assertEqual(squared_euclidean_distance(lyt, offset_coordinate(0, 0), offset_coordinate(1, 1)), 2) + self.assertEqual(squared_euclidean_distance(lyt, offset_coordinate(0, 0), offset_coordinate(2, 2)), 8) + self.assertEqual(squared_euclidean_distance(lyt, offset_coordinate(0, 0), offset_coordinate(3, 3)), 18) + self.assertEqual(squared_euclidean_distance(lyt, offset_coordinate(0, 0), offset_coordinate(4, 4)), 32) + def test_twoddwave(self): for lyt in [cartesian_layout((4, 4)), clocked_cartesian_layout((4, 4), "2DDWave"), cartesian_gate_layout((4, 4), "2DDWave", "Layout"), shifted_cartesian_layout((4, 4)), @@ -50,6 +64,21 @@ def test_twoddwave(self): self.assertEqual(twoddwave_distance(lyt, offset_coordinate(0, 0), offset_coordinate(3, 3)), 6) self.assertEqual(twoddwave_distance(lyt, offset_coordinate(0, 0), offset_coordinate(4, 4)), 8) + def test_chebyshev(self): + for lyt in [cartesian_layout((4, 4)), clocked_cartesian_layout((4, 4), "2DDWave"), + cartesian_gate_layout((4, 4), "2DDWave", "Layout"), shifted_cartesian_layout((4, 4)), + clocked_shifted_cartesian_layout((4, 4), "2DDWave"), + shifted_cartesian_gate_layout((4, 4), "2DDWave", "Layout"), + hexagonal_layout((4, 4)), clocked_hexagonal_layout((4, 4), "2DDWave"), + hexagonal_gate_layout((4, 4), "2DDWave", "Layout")]: + self.assertEqual(chebyshev_distance(lyt, offset_coordinate(0, 0), offset_coordinate(0, 0)), 0) + self.assertEqual(chebyshev_distance(lyt, offset_coordinate(0, 0), offset_coordinate(1, 0)), 1) + self.assertEqual(chebyshev_distance(lyt, offset_coordinate(0, 0), offset_coordinate(0, 1)), 1) + self.assertEqual(chebyshev_distance(lyt, offset_coordinate(0, 0), offset_coordinate(1, 1)), 1) + self.assertEqual(chebyshev_distance(lyt, offset_coordinate(0, 0), offset_coordinate(2, 2)), 2) + self.assertEqual(chebyshev_distance(lyt, offset_coordinate(0, 0), offset_coordinate(3, 3)), 3) + self.assertEqual(chebyshev_distance(lyt, offset_coordinate(0, 0), offset_coordinate(4, 4)), 4) + if __name__ == '__main__': unittest.main() diff --git a/docs/algorithms/path_finding.rst b/docs/algorithms/path_finding.rst index 147840cf9..55d9fd84c 100644 --- a/docs/algorithms/path_finding.rst +++ b/docs/algorithms/path_finding.rst @@ -9,18 +9,24 @@ Distance functions compute (an approximation for) the distance between two coord .. doxygenfunction:: fiction::manhattan_distance .. doxygenfunction:: fiction::euclidean_distance + .. doxygenfunction:: fiction::squared_euclidean_distance .. doxygenfunction:: fiction::twoddwave_distance + .. doxygenfunction:: fiction::chebyshev_distance .. doxygenclass:: fiction::distance_functor :members: .. doxygenclass:: fiction::manhattan_distance_functor .. doxygenclass:: fiction::euclidean_distance_functor + .. doxygenclass:: fiction::squared_euclidean_distance_functor .. doxygenclass:: fiction::twoddwave_distance_functor + .. doxygenclass:: fiction::chebyshev_distance_functor .. tab:: Python .. autofunction:: mnt.pyfiction.manhattan_distance .. autofunction:: mnt.pyfiction.euclidean_distance + .. autofunction:: mnt.pyfiction.squared_euclidean_distance .. autofunction:: mnt.pyfiction.twoddwave_distance + .. autofunction:: mnt.pyfiction.chebyshev_distance Distance Maps ------------- diff --git a/docs/changelog.rst b/docs/changelog.rst index 23344b0b2..10cd490bf 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on `Keep a Changelog `_. +Unreleased +---------- + +Added +##### +- Algorithms: + - Path-finding: + - Squared Euclidean distance function + - Chebyshev distance function + v0.6.3 - 2024-08-21 ------------------- diff --git a/include/fiction/algorithms/path_finding/distance.hpp b/include/fiction/algorithms/path_finding/distance.hpp index f5eafaa01..4f0c3e352 100644 --- a/include/fiction/algorithms/path_finding/distance.hpp +++ b/include/fiction/algorithms/path_finding/distance.hpp @@ -7,6 +7,7 @@ #include "fiction/traits.hpp" +#include #include #include #include @@ -62,11 +63,38 @@ template return static_cast(std::hypot(x, y)); } +/** + * The squared Euclidean distance \f$D\f$ between two layout coordinates \f$(x_1, y_1)\f$ and \f$(x_2, y_2)\f$ given by + * + * \f$D = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}^2 = (x_1 - x_2)^2 + (y_1 - y_2)^2\f$ + * + * In contrast to the regular Euclidean distance, this function is differentiable and can be used in optimization + * algorithms that require gradients. Additionally, it is computationally cheaper by omitting the square root operation. + * + * @tparam Lyt Coordinate layout type. + * @tparam Dist Integral type for the distance. + * @param lyt Layout. + * @param source Source coordinate. + * @param target Target coordinate. + * @return Squared euclidean distance between `source` and `target`. + */ +template +[[nodiscard]] constexpr Dist squared_euclidean_distance([[maybe_unused]] const Lyt& lyt, const coordinate& source, + const coordinate& target) noexcept +{ + static_assert(is_coordinate_layout_v, "Lyt is not a coordinate layout"); + static_assert(std::is_integral_v, "Dist is not an integral type"); + + const auto x = static_cast(source.x) - static_cast(target.x); + const auto y = static_cast(source.y) - static_cast(target.y); + + return static_cast(x * x + y * y); +} /** * The 2DDWave distance \f$D\f$ between two layout coordinates \f$s = (x_1, y_1)\f$ and \f$t = (x_2, y_2)\f$ given * by * - * \f$D = |x_1 - x_2| + |y_1 - y_2|\f$ iff \f$s \leq t\f$ and \f$\infty\f$, otherwise. + * \f$D = |x_1 - x_2| + |y_1 - y_2|\f$ iff \f$s \leq t\f$ and \f$\infty\f$, otherwise. * * Thereby, \f$s \leq t\f$ iff \f$x_1 \leq x_2\f$ and \f$y_1 \leq y_2\f$. * @@ -90,6 +118,31 @@ template return source.x <= target.x && source.y <= target.y ? manhattan_distance(lyt, source, target) : static_cast(std::numeric_limits::max()); } +/** + * The Chebyshev distance \f$D\f$ between two layout coordinates \f$(x_1, y_1)\f$ and \f$(x_2, y_2)\f$ given by + * + * \f$D = \max(|x_2 - x_1|, |y_2 - y_1|)\f$ + * + * In contrast to the Manhattan distance, this function assumes the same cost for diagonal moves as it does for + * horizontal and vertical ones. + * + * @tparam Lyt Coordinate layout type. + * @tparam Dist Integral type for the distance. + * @param lyt Layout. + * @param source Source coordinate. + * @param target Target coordinate. + * @return Chebyshev distance between `source` and `target`. + */ +template +[[nodiscard]] constexpr Dist chebyshev_distance([[maybe_unused]] const Lyt& lyt, const coordinate& source, + const coordinate& target) noexcept +{ + static_assert(is_coordinate_layout_v, "Lyt is not a coordinate layout"); + static_assert(std::is_integral_v, "Dist is not an integral type"); + + return static_cast(std::max(std::abs(static_cast(source.x) - static_cast(target.x)), + std::abs(static_cast(source.y) - static_cast(target.y)))); +} // NOLINTBEGIN(*-special-member-functions): virtual destructor is prudent @@ -167,6 +220,18 @@ class euclidean_distance_functor : public distance_functor public: euclidean_distance_functor() : distance_functor(&euclidean_distance) {} }; +/** + * A pre-defined distance functor that uses the squared Euclidean distance. + * + * @tparam Lyt Coordinate layout type. + * @tparam Dist Integral distance type. + */ +template +class squared_euclidean_distance_functor : public distance_functor +{ + public: + squared_euclidean_distance_functor() : distance_functor(&squared_euclidean_distance) {} +}; /** * A pre-defined distance functor that uses the 2DDWave distance. * @@ -179,6 +244,18 @@ class twoddwave_distance_functor : public distance_functor public: twoddwave_distance_functor() : distance_functor(&twoddwave_distance) {} }; +/** + * A pre-defined distance functor that uses the Chebyshev distance. + * + * @tparam Lyt Coordinate layout type. + * @tparam Dist Integral distance type. + */ +template +class chebyshev_distance_functor : public distance_functor +{ + public: + chebyshev_distance_functor() : distance_functor(&chebyshev_distance) {} +}; } // namespace fiction diff --git a/test/algorithms/path_finding/distance.cpp b/test/algorithms/path_finding/distance.cpp index 5fb653d27..dc5bddcf7 100644 --- a/test/algorithms/path_finding/distance.cpp +++ b/test/algorithms/path_finding/distance.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -213,6 +214,84 @@ TEST_CASE("Euclidean distance functor", "[distance]") } } +TEST_CASE("Squared Euclidean distance", "[distance]") +{ + SECTION("Unsigned Cartesian layout") + { + using cart_lyt = cartesian_layout; + + const cart_lyt layout{}; + + CHECK(squared_euclidean_distance(layout, {0, 0}, {0, 0}) == 0); + CHECK(squared_euclidean_distance(layout, {1, 1}, {1, 1}) == 0); + CHECK(squared_euclidean_distance(layout, {0, 0}, {0, 1}) == 1); + CHECK(squared_euclidean_distance(layout, {0, 0}, {1, 1}) == 2); + CHECK(squared_euclidean_distance(layout, {9, 1}, {6, 2}) == 10); + CHECK(squared_euclidean_distance(layout, {6, 2}, {0, 4}) == 40); + CHECK(squared_euclidean_distance(layout, {0, 4}, {9, 1}) == 90); + + // ignore z-axis + CHECK(squared_euclidean_distance(layout, {6, 2, 1}, {0, 4, 0}) == 40); + CHECK(squared_euclidean_distance(layout, {6, 2, 0}, {0, 4, 1}) == 40); + CHECK(squared_euclidean_distance(layout, {0, 4, 1}, {9, 1, 1}) == 90); + } + SECTION("Signed Cartesian layout") + { + using cart_lyt = cartesian_layout; + + const cart_lyt layout{}; + + CHECK(squared_euclidean_distance(layout, {0, 0}, {0, 0}) == 0); + CHECK(squared_euclidean_distance(layout, {1, 1}, {1, 1}) == 0); + CHECK(squared_euclidean_distance(layout, {0, 0}, {0, 1}) == 1); + CHECK(squared_euclidean_distance(layout, {0, 0}, {1, 1}) == 2); + CHECK(squared_euclidean_distance(layout, {9, 1}, {6, 2}) == 10); + CHECK(squared_euclidean_distance(layout, {6, 2}, {0, 4}) == 40); + CHECK(squared_euclidean_distance(layout, {0, 4}, {9, 1}) == 90); + } +} + +TEST_CASE("Squared Euclidean distance functor", "[distance]") +{ + SECTION("Unsigned Cartesian layout") + { + using cart_lyt = cartesian_layout; + + const cart_lyt layout{}; + + const squared_euclidean_distance_functor distance{}; + + CHECK(distance(layout, {0, 0}, {0, 0}) == 0); + CHECK(distance(layout, {1, 1}, {1, 1}) == 0); + CHECK(distance(layout, {0, 0}, {0, 1}) == 1); + CHECK(distance(layout, {0, 0}, {1, 1}) == 2); + CHECK(distance(layout, {9, 1}, {6, 2}) == 10); + CHECK(distance(layout, {6, 2}, {0, 4}) == 40); + CHECK(distance(layout, {0, 4}, {9, 1}) == 90); + + // ignore z-axis + CHECK(distance(layout, {6, 2, 1}, {0, 4, 0}) == 40); + CHECK(distance(layout, {6, 2, 0}, {0, 4, 1}) == 40); + CHECK(distance(layout, {0, 4, 1}, {9, 1, 1}) == 90); + } + SECTION("Signed Cartesian layout") + { + using cart_lyt = cartesian_layout; + + const cart_lyt layout{}; + + const squared_euclidean_distance_functor distance{}; + + CHECK(distance(layout, {0, 0}, {0, 0}) == 0); + CHECK(distance(layout, {1, 1}, {1, 1}) == 0); + CHECK(distance(layout, {0, 0}, {0, 1}) == 1); + CHECK(distance(layout, {0, 0}, {1, 1}) == 2); + CHECK(distance(layout, {9, 1}, {6, 2}) == 10); + CHECK(distance(layout, {6, 2}, {0, 4}) == 40); + CHECK(distance(layout, {0, 4}, {9, 1}) == 90); + } +} + TEST_CASE("2DDWave distance", "[distance]") { SECTION("Unsigned Cartesian layout") @@ -313,6 +392,90 @@ TEST_CASE("2DDWave distance functor", "[distance]") } } +TEST_CASE("Chebyshev distance", "[distance]") +{ + SECTION("Unsigned Cartesian layout") + { + using cart_lyt = cartesian_layout; + + const cart_lyt layout{}; + + CHECK(chebyshev_distance(layout, {0, 0}, {0, 0}) == 0); + CHECK(chebyshev_distance(layout, {1, 1}, {1, 1}) == 0); + CHECK(chebyshev_distance(layout, {0, 0}, {0, 1}) == 1); + CHECK(chebyshev_distance(layout, {0, 0}, {1, 1}) == 1); + CHECK(chebyshev_distance(layout, {1, 2}, {3, 3}) == 2); + CHECK(chebyshev_distance(layout, {0, 0}, {4, 4}) == 4); + CHECK(chebyshev_distance(layout, {4, 4}, {0, 0}) == 4); + CHECK(chebyshev_distance(layout, {2, 1}, {0, 2}) == 2); + CHECK(chebyshev_distance(layout, {1, 0}, {0, 1}) == 1); + + // ignore z-axis + CHECK(chebyshev_distance(layout, {0, 0, 1}, {8, 9, 0}) == 9); + CHECK(chebyshev_distance(layout, {0, 0, 1}, {8, 9, 1}) == 9); + } + SECTION("Signed Cartesian layout") + { + using cart_lyt = cartesian_layout; + + const cart_lyt layout{}; + + CHECK(chebyshev_distance(layout, {0, 0}, {0, 0}) == 0); + CHECK(chebyshev_distance(layout, {1, 1}, {1, 1}) == 0); + CHECK(chebyshev_distance(layout, {0, 0}, {0, 1}) == 1); + CHECK(chebyshev_distance(layout, {0, 0}, {1, 1}) == 1); + CHECK(chebyshev_distance(layout, {1, 2}, {3, 3}) == 2); + CHECK(chebyshev_distance(layout, {0, 0}, {4, 4}) == 4); + CHECK(chebyshev_distance(layout, {4, 4}, {0, 0}) == 4); + CHECK(chebyshev_distance(layout, {2, 1}, {0, 2}) == 2); + CHECK(chebyshev_distance(layout, {1, 0}, {0, 1}) == 1); + } +} + +TEST_CASE("Chebyshev distance functor", "[distance]") +{ + SECTION("Unsigned Cartesian layout") + { + using cart_lyt = cartesian_layout; + + const cart_lyt layout{}; + + const chebyshev_distance_functor distance{}; + + CHECK(distance(layout, {0, 0}, {0, 0}) == 0); + CHECK(distance(layout, {1, 1}, {1, 1}) == 0); + CHECK(distance(layout, {0, 0}, {0, 1}) == 1); + CHECK(distance(layout, {0, 0}, {1, 1}) == 1); + CHECK(distance(layout, {1, 2}, {3, 3}) == 2); + CHECK(distance(layout, {0, 0}, {4, 4}) == 4); + CHECK(distance(layout, {4, 4}, {0, 0}) == 4); + CHECK(distance(layout, {2, 1}, {0, 2}) == 2); + CHECK(distance(layout, {1, 0}, {0, 1}) == 1); + + // ignore z-axis + CHECK(distance(layout, {0, 0, 1}, {8, 9, 0}) == 9); + CHECK(distance(layout, {0, 0, 1}, {8, 9, 1}) == 9); + } + SECTION("Signed Cartesian layout") + { + using cart_lyt = cartesian_layout; + + const cart_lyt layout{}; + + const chebyshev_distance_functor distance{}; + + CHECK(distance(layout, {0, 0}, {0, 0}) == 0); + CHECK(distance(layout, {1, 1}, {1, 1}) == 0); + CHECK(distance(layout, {0, 0}, {0, 1}) == 1); + CHECK(distance(layout, {0, 0}, {1, 1}) == 1); + CHECK(distance(layout, {1, 2}, {3, 3}) == 2); + CHECK(distance(layout, {0, 0}, {4, 4}) == 4); + CHECK(distance(layout, {4, 4}, {0, 0}) == 4); + CHECK(distance(layout, {2, 1}, {0, 2}) == 2); + CHECK(distance(layout, {1, 0}, {0, 1}) == 1); + } +} + TEST_CASE("A* distance", "[distance]") { SECTION("Unsigned Cartesian layout") @@ -385,7 +548,7 @@ TEST_CASE("A* distance", "[distance]") } } -TEST_CASE("a_star distance functor", "[distance]") +TEST_CASE("A* distance functor", "[distance]") { SECTION("Unsigned Cartesian layout") { From 7a7eb32e9d83c2d6e8d5e36832a8ac8af4371c5f Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Wed, 28 Aug 2024 16:37:32 +0200 Subject: [PATCH 10/13] :memo: Fix a few oversights in the RTD documentation of SiDB simulation functionality (#513) * :memo: Added missing RTD documentation on `operational_domain_value_range` * :memo: Removed outdated `dimer_displacement_policy` enum from C++ RTD documentation and added missing `dimer_displacement_policy` to Python RTD documentation --- docs/algorithms/sidb_simulation.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/algorithms/sidb_simulation.rst b/docs/algorithms/sidb_simulation.rst index f1e6be0e1..bcd9a4abe 100644 --- a/docs/algorithms/sidb_simulation.rst +++ b/docs/algorithms/sidb_simulation.rst @@ -240,6 +240,8 @@ Operational Domain Computation .. doxygenenum:: fiction::sweep_parameter .. doxygenstruct:: fiction::operational_domain :members: + .. doxygenstruct:: fiction::operational_domain_value_range + :members: .. doxygenstruct:: fiction::operational_domain_params :members: .. doxygenstruct:: fiction::operational_domain_stats @@ -297,17 +299,18 @@ Displacement Robustness Domain .. tab:: C++ **Header:** ``fiction/algorithms/simulation/sidb/determine_displacement_robustness.hpp`` - .. doxygenenum:: fiction::dimer_displacement_policy - .. doxygenstruct:: fiction::displacement_robustness_domain - :members: .. doxygenstruct:: fiction::displacement_robustness_domain_params :members: .. doxygenstruct:: fiction::displacement_robustness_domain_stats :members: + .. doxygenstruct:: fiction::displacement_robustness_domain + :members: .. doxygenfunction:: fiction::determine_displacement_robustness_domain .. doxygenfunction:: fiction::determine_probability_of_fabricating_operational_gate .. tab:: Python + .. autoclass:: mnt.pyfiction.dimer_displacement_policy + :members: .. autoclass:: mnt.pyfiction.displacement_analysis_mode :members: .. autofunction:: mnt.pyfiction.displacement_robustness_domain_params From 4e9aea9d0930928b024c1f0d1b98265bc755dbcc Mon Sep 17 00:00:00 2001 From: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com> Date: Thu, 29 Aug 2024 20:28:01 +0200 Subject: [PATCH 11/13] =?UTF-8?q?=E2=9C=A8=20Track=20number=20of=20crossin?= =?UTF-8?q?gs=20(#514)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * track number of crossings * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * test movement of crossing * Update cli/stores.hpp Co-authored-by: Marcel Walter Signed-off-by: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com> * log crossings in physical design algorithms * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * track crossings in cli commands * align stats in bindings * fix errors * change to readonly * Update equivalence_checking.hpp * 🎨 Incorporated pre-commit fixes --------- Signed-off-by: GitHub Actions Signed-off-by: simon1hofmann <119581649+simon1hofmann@users.noreply.github.com> Co-authored-by: GitHub Actions Co-authored-by: Marcel Walter Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../technology_mapping.hpp | 6 +- .../algorithms/physical_design/exact.hpp | 15 +++++ .../graph_oriented_layout_design.hpp | 4 +- .../algorithms/physical_design/orthogonal.hpp | 14 ++++ .../post_layout_optimization.hpp | 10 +++ .../physical_design/wiring_reduction.hpp | 2 +- .../simulation/sidb/critical_temperature.hpp | 29 ++++++--- .../simulation/sidb/time_to_solution.hpp | 29 ++++++--- .../verification/equivalence_checking.hpp | 17 ++++- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 23 +++++++ cli/cmd/physical_design/exact.hpp | 1 + cli/cmd/physical_design/gold.hpp | 1 + cli/cmd/physical_design/onepass.hpp | 1 + cli/cmd/physical_design/ortho.hpp | 1 + cli/stores.hpp | 23 +++---- .../algorithms/physical_design/exact.hpp | 29 +++++---- .../graph_oriented_layout_design.hpp | 22 ++++--- .../physical_design/one_pass_synthesis.hpp | 20 +++--- .../algorithms/physical_design/orthogonal.hpp | 20 +++--- .../post_layout_optimization.hpp | 38 +++++++++-- .../simulation/sidb/time_to_solution.hpp | 2 +- include/fiction/layouts/gate_level_layout.hpp | 25 +++++++- test/layouts/gate_level_layout.cpp | 64 +++++++++++++++++++ 23 files changed, 309 insertions(+), 87 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/network_transformation/technology_mapping.hpp b/bindings/pyfiction/include/pyfiction/algorithms/network_transformation/technology_mapping.hpp index 705c56a84..2826944d2 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/network_transformation/technology_mapping.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/network_transformation/technology_mapping.hpp @@ -71,10 +71,10 @@ inline void technology_mapping(pybind11::module& m) py::class_(m, "technology_mapping_stats", DOC(fiction_technology_mapping_stats)) .def(py::init<>()) - + .def("__repr__", [](const fiction::technology_mapping_stats& stats) { return stats.report(); }) .def("report", &fiction::technology_mapping_stats::report, DOC(fiction_technology_mapping_stats_report)) - - ; + .def_readonly("mapper_stats", &fiction::technology_mapping_stats::mapper_stats, + DOC(fiction_technology_mapping_stats_mapper_stats)); m.def("and_or_not", &fiction::and_or_not, DOC(fiction_and_or_not)); diff --git a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/exact.hpp b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/exact.hpp index 8196a3914..8726dfa5a 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/exact.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/exact.hpp @@ -75,6 +75,21 @@ inline void exact(pybind11::module& m) stats.report(stream); return stream.str(); }) + .def("report", &fiction::exact_physical_design_stats::report, DOC(fiction_exact_physical_design_stats_report)) + .def_readonly("time_total", &fiction::exact_physical_design_stats::time_total, + DOC(fiction_exact_physical_design_stats_duration)) + .def_readonly("x_size", &fiction::exact_physical_design_stats::x_size, + DOC(fiction_exact_physical_design_stats_x_size)) + .def_readonly("y_size", &fiction::exact_physical_design_stats::y_size, + DOC(fiction_exact_physical_design_stats_y_size)) + .def_readonly("num_gates", &fiction::exact_physical_design_stats::num_gates, + DOC(fiction_exact_physical_design_stats_num_gates)) + .def_readonly("num_wires", &fiction::exact_physical_design_stats::num_wires, + DOC(fiction_exact_physical_design_stats_num_wires)) + .def_readonly("num_crossings", &fiction::exact_physical_design_stats::num_crossings, + DOC(fiction_exact_physical_design_stats_num_crossings)) + .def_readonly("num_aspect_ratios", &fiction::exact_physical_design_stats::num_aspect_ratios, + DOC(fiction_exact_physical_design_stats_num_aspect_ratios)) ; diff --git a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/graph_oriented_layout_design.hpp b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/graph_oriented_layout_design.hpp index db64acdce..e01e8baee 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/graph_oriented_layout_design.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/graph_oriented_layout_design.hpp @@ -64,8 +64,8 @@ inline void graph_oriented_layout_design(pybind11::module& m) DOC(fiction_graph_oriented_layout_design_stats_num_gates)) .def_readonly("num_wires", &fiction::graph_oriented_layout_design_stats::num_wires, DOC(fiction_graph_oriented_layout_design_stats_num_wires)) - - ; + .def_readonly("num_crossings", &fiction::graph_oriented_layout_design_stats::num_crossings, + DOC(fiction_graph_oriented_layout_design_stats_num_crossings)); m.def("graph_oriented_layout_design", &fiction::graph_oriented_layout_design, "network"_a, diff --git a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/orthogonal.hpp b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/orthogonal.hpp index f41ce3367..1fa37b81b 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/orthogonal.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/orthogonal.hpp @@ -42,6 +42,20 @@ inline void orthogonal(pybind11::module& m) stats.report(stream); return stream.str(); }) + .def("report", &fiction::orthogonal_physical_design_stats::report, + DOC(fiction_orthogonal_physical_design_stats_report)) + .def_readonly("time_total", &fiction::orthogonal_physical_design_stats::time_total, + DOC(fiction_orthogonal_physical_design_stats_duration)) + .def_readonly("x_size", &fiction::orthogonal_physical_design_stats::x_size, + DOC(fiction_orthogonal_physical_design_stats_x_size)) + .def_readonly("y_size", &fiction::orthogonal_physical_design_stats::y_size, + DOC(fiction_orthogonal_physical_design_stats_y_size)) + .def_readonly("num_gates", &fiction::orthogonal_physical_design_stats::num_gates, + DOC(fiction_orthogonal_physical_design_stats_num_gates)) + .def_readonly("num_wires", &fiction::orthogonal_physical_design_stats::num_wires, + DOC(fiction_orthogonal_physical_design_stats_num_wires)) + .def_readonly("num_crossings", &fiction::orthogonal_physical_design_stats::num_crossings, + DOC(fiction_orthogonal_physical_design_stats_num_crossings)) ; diff --git a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp index dea035853..0397c60d7 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp @@ -45,6 +45,8 @@ inline void post_layout_optimization(pybind11::module& m) stats.report(stream); return stream.str(); }) + .def("report", &fiction::post_layout_optimization_stats::report, + DOC(fiction_post_layout_optimization_stats_report)) .def_readonly("time_total", &fiction::post_layout_optimization_stats::time_total, DOC(fiction_post_layout_optimization_stats_duration)) .def_readonly("x_size_before", &fiction::post_layout_optimization_stats::x_size_before, @@ -57,6 +59,14 @@ inline void post_layout_optimization(pybind11::module& m) DOC(fiction_post_layout_optimization_stats_y_size_after)) .def_readonly("area_improvement", &fiction::post_layout_optimization_stats::area_improvement, DOC(fiction_post_layout_optimization_stats_area_improvement)) + .def_readonly("num_wires_before", &fiction::post_layout_optimization_stats::num_wires_before, + DOC(fiction_post_layout_optimization_stats_num_wires_before)) + .def_readonly("num_wires_after", &fiction::post_layout_optimization_stats::num_wires_after, + DOC(fiction_post_layout_optimization_stats_num_wires_after)) + .def_readonly("num_crossings_before", &fiction::post_layout_optimization_stats::num_crossings_before, + DOC(fiction_post_layout_optimization_stats_num_crossings_before)) + .def_readonly("num_crossings_after", &fiction::post_layout_optimization_stats::num_crossings_after, + DOC(fiction_post_layout_optimization_stats_num_crossings_after)) ; diff --git a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/wiring_reduction.hpp b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/wiring_reduction.hpp index db7597580..a9e17d22b 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/wiring_reduction.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/wiring_reduction.hpp @@ -32,7 +32,7 @@ inline void wiring_reduction(pybind11::module& m) stats.report(stream); return stream.str(); }) - + .def("report", &fiction::wiring_reduction_stats::report, DOC(fiction_wiring_reduction_stats_report)) .def_readonly("time_total", &fiction::wiring_reduction_stats::time_total, DOC(fiction_wiring_reduction_stats_duration)) .def_readonly("x_size_before", &fiction::wiring_reduction_stats::x_size_before, diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/critical_temperature.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/critical_temperature.hpp index 14c2c5ade..e2e60e8e2 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/critical_temperature.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/critical_temperature.hpp @@ -57,16 +57,25 @@ inline void critical_temperature(pybind11::module& m) py::class_(m, "critical_temperature_stats", DOC(fiction_critical_temperature_stats)) .def(py::init<>()) - .def_readwrite("algorithm_name", &fiction::critical_temperature_stats::algorithm_name, - DOC(fiction_critical_temperature_stats_algorithm_name)) - .def_readwrite("critical_temperature", &fiction::critical_temperature_stats::critical_temperature, - DOC(fiction_critical_temperature_stats_critical_temperature)) - .def_readwrite("num_valid_lyt", &fiction::critical_temperature_stats::num_valid_lyt, - DOC(fiction_critical_temperature_stats_num_valid_lyt)) - .def_readwrite("energy_between_ground_state_and_first_erroneous", - &fiction::critical_temperature_stats::energy_between_ground_state_and_first_erroneous, - DOC(fiction_critical_temperature_stats_energy_between_ground_state_and_first_erroneous)) - .def("report", &fiction::critical_temperature_stats::report, DOC(fiction_critical_temperature_stats_report)); + .def("__repr__", + [](const fiction::critical_temperature_stats& stats) + { + std::stringstream stream{}; + stats.report(stream); + return stream.str(); + }) + .def("report", &fiction::critical_temperature_stats::report, DOC(fiction_critical_temperature_stats_report)) + .def_readonly("algorithm_name", &fiction::critical_temperature_stats::algorithm_name, + DOC(fiction_critical_temperature_stats_algorithm_name)) + .def_readonly("critical_temperature", &fiction::critical_temperature_stats::critical_temperature, + DOC(fiction_critical_temperature_stats_critical_temperature)) + .def_readonly("num_valid_lyt", &fiction::critical_temperature_stats::num_valid_lyt, + DOC(fiction_critical_temperature_stats_num_valid_lyt)) + .def_readonly("energy_between_ground_state_and_first_erroneous", + &fiction::critical_temperature_stats::energy_between_ground_state_and_first_erroneous, + DOC(fiction_critical_temperature_stats_energy_between_ground_state_and_first_erroneous)) + + ; /** * Critical temperature parameters. diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/time_to_solution.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/time_to_solution.hpp index fd737c478..6581bc362 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/time_to_solution.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/time_to_solution.hpp @@ -52,16 +52,25 @@ inline void time_to_solution(pybind11::module& m) */ py::class_(m, "time_to_solution_stats", DOC(fiction_time_to_solution_stats)) .def(py::init<>()) - .def_readwrite("time_to_solution", &fiction::time_to_solution_stats::time_to_solution, - DOC(fiction_time_to_solution_stats_time_to_solution)) - .def_readwrite("acc", &fiction::time_to_solution_stats::acc, DOC(fiction_time_to_solution_stats_acc)) - .def_readwrite("mean_single_runtime", &fiction::time_to_solution_stats::mean_single_runtime, - DOC(fiction_time_to_solution_stats_mean_single_runtime)) - .def_readwrite("single_runtime_exact", &fiction::time_to_solution_stats::single_runtime_exact, - DOC(fiction_time_to_solution_stats_single_runtime_exact)) - .def_readwrite("algorithm", &fiction::time_to_solution_stats::algorithm, - DOC(fiction_time_to_solution_stats_algorithm)) - .def("report", &fiction::time_to_solution_stats::report, DOC(fiction_time_to_solution_stats_report)); + .def("__repr__", + [](const fiction::time_to_solution_stats& stats) + { + std::stringstream stream{}; + stats.report(stream); + return stream.str(); + }) + .def("report", &fiction::time_to_solution_stats::report, DOC(fiction_time_to_solution_stats_report)) + .def_readonly("time_to_solution", &fiction::time_to_solution_stats::time_to_solution, + DOC(fiction_time_to_solution_stats_time_to_solution)) + .def_readonly("acc", &fiction::time_to_solution_stats::acc, DOC(fiction_time_to_solution_stats_acc)) + .def_readonly("mean_single_runtime", &fiction::time_to_solution_stats::mean_single_runtime, + DOC(fiction_time_to_solution_stats_mean_single_runtime)) + .def_readonly("single_runtime_exact", &fiction::time_to_solution_stats::single_runtime_exact, + DOC(fiction_time_to_solution_stats_single_runtime_exact)) + .def_readonly("algorithm", &fiction::time_to_solution_stats::algorithm, + DOC(fiction_time_to_solution_stats_algorithm)) + + ; // NOTE be careful with the order of the following calls! Python will resolve the first matching overload! diff --git a/bindings/pyfiction/include/pyfiction/algorithms/verification/equivalence_checking.hpp b/bindings/pyfiction/include/pyfiction/algorithms/verification/equivalence_checking.hpp index bc339367a..5e6ecb7c3 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/verification/equivalence_checking.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/verification/equivalence_checking.hpp @@ -60,8 +60,21 @@ inline void equivalence_checking(pybind11::module& m) py::class_(m, "equivalence_checking_stats", DOC(fiction_equivalence_checking_stats)) .def(py::init<>()) - .def_readwrite("counter_example", &fiction::equivalence_checking_stats::counter_example, - DOC(fiction_equivalence_checking_stats_counter_example)) + .def_readonly("eq", &fiction::equivalence_checking_stats::eq, DOC(fiction_equivalence_checking_stats_eq)) + .def_readonly("tp_spec", &fiction::equivalence_checking_stats::tp_spec, + DOC(fiction_equivalence_checking_stats_tp_spec)) + .def_readonly("tp_impl", &fiction::equivalence_checking_stats::tp_impl, + DOC(fiction_equivalence_checking_stats_tp_impl)) + .def_readonly("tp_diff", &fiction::equivalence_checking_stats::tp_diff, + DOC(fiction_equivalence_checking_stats_tp_diff)) + .def_readonly("counter_example", &fiction::equivalence_checking_stats::counter_example, + DOC(fiction_equivalence_checking_stats_counter_example)) + .def_readonly("runtime", &fiction::equivalence_checking_stats::runtime, + DOC(fiction_equivalence_checking_stats_duration)) + .def_readonly("spec_drv_stats", &fiction::equivalence_checking_stats::spec_drv_stats, + DOC(fiction_equivalence_checking_stats_spec_drv_stats)) + .def_readonly("impl_drv_stats", &fiction::equivalence_checking_stats::impl_drv_stats, + DOC(fiction_equivalence_checking_stats_impl_drv_stats)) ; diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index 521039a27..b8fadcae4 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -8964,6 +8964,8 @@ static const char *__doc_fiction_exact_physical_design_stats_duration = R"doc()d static const char *__doc_fiction_exact_physical_design_stats_num_aspect_ratios = R"doc()doc"; +static const char *__doc_fiction_exact_physical_design_stats_num_crossings = R"doc()doc"; + static const char *__doc_fiction_exact_physical_design_stats_num_gates = R"doc()doc"; static const char *__doc_fiction_exact_physical_design_stats_num_wires = R"doc()doc"; @@ -9949,6 +9951,8 @@ static const char *__doc_fiction_gate_level_layout_gate_level_layout_storage_dat static const char *__doc_fiction_gate_level_layout_gate_level_layout_storage_data_node_tile_map = R"doc()doc"; +static const char *__doc_fiction_gate_level_layout_gate_level_layout_storage_data_num_crossings = R"doc()doc"; + static const char *__doc_fiction_gate_level_layout_gate_level_layout_storage_data_num_gates = R"doc()doc"; static const char *__doc_fiction_gate_level_layout_gate_level_layout_storage_data_num_wires = R"doc()doc"; @@ -10555,6 +10559,13 @@ static const char *__doc_fiction_gate_level_layout_num_cis = R"doc()doc"; static const char *__doc_fiction_gate_level_layout_num_cos = R"doc()doc"; +static const char *__doc_fiction_gate_level_layout_num_crossings = +R"doc(Returns the number of placed nodes in the layout that compute the +identity function and cross other nodes. + +Returns: + Number of crossings in the layout.)doc"; + static const char *__doc_fiction_gate_level_layout_num_gates = R"doc(Returns the number of placed nodes in the layout that do not compute the identity function. @@ -10938,6 +10949,8 @@ process.)doc"; static const char *__doc_fiction_graph_oriented_layout_design_stats_duration = R"doc(Runtime of the graph-oriented layout design process.)doc"; +static const char *__doc_fiction_graph_oriented_layout_design_stats_num_crossings = R"doc(Number of crossings.)doc"; + static const char *__doc_fiction_graph_oriented_layout_design_stats_num_gates = R"doc(Number of gates.)doc"; static const char *__doc_fiction_graph_oriented_layout_design_stats_num_wires = R"doc(Number of wires.)doc"; @@ -13711,6 +13724,8 @@ static const char *__doc_fiction_orthogonal_physical_design_stats = R"doc()doc"; static const char *__doc_fiction_orthogonal_physical_design_stats_duration = R"doc()doc"; +static const char *__doc_fiction_orthogonal_physical_design_stats_num_crossings = R"doc()doc"; + static const char *__doc_fiction_orthogonal_physical_design_stats_num_gates = R"doc()doc"; static const char *__doc_fiction_orthogonal_physical_design_stats_num_wires = R"doc()doc"; @@ -14126,6 +14141,14 @@ static const char *__doc_fiction_post_layout_optimization_stats_area_improvement static const char *__doc_fiction_post_layout_optimization_stats_duration = R"doc(Runtime of the post-layout optimization process.)doc"; +static const char *__doc_fiction_post_layout_optimization_stats_num_crossings_after = R"doc(Number of crossings after the post-layout optimization process.)doc"; + +static const char *__doc_fiction_post_layout_optimization_stats_num_crossings_before = R"doc(Number of crossings before the post-layout optimization process.)doc"; + +static const char *__doc_fiction_post_layout_optimization_stats_num_wires_after = R"doc(Number of wire segments after the post-layout optimization process.)doc"; + +static const char *__doc_fiction_post_layout_optimization_stats_num_wires_before = R"doc(Number of wire segments before the post-layout optimization process.)doc"; + static const char *__doc_fiction_post_layout_optimization_stats_report = R"doc(Reports the statistics to the given output stream. diff --git a/cli/cmd/physical_design/exact.hpp b/cli/cmd/physical_design/exact.hpp index 7196ca515..84f2c8607 100644 --- a/cli/cmd/physical_design/exact.hpp +++ b/cli/cmd/physical_design/exact.hpp @@ -159,6 +159,7 @@ class exact_command : public command {"runtime in seconds", mockturtle::to_seconds(st.time_total)}, {"number of gates", st.num_gates}, {"number of wires", st.num_wires}, + {"number of crossings", st.num_crossings}, {"layout", {{"x-size", st.x_size}, {"y-size", st.y_size}, {"area", st.x_size * st.y_size}}}}; } diff --git a/cli/cmd/physical_design/gold.hpp b/cli/cmd/physical_design/gold.hpp index 4202b58d8..29b82ccdf 100644 --- a/cli/cmd/physical_design/gold.hpp +++ b/cli/cmd/physical_design/gold.hpp @@ -90,6 +90,7 @@ class gold_command : public command {"runtime in seconds", mockturtle::to_seconds(st.time_total)}, {"number of gates", st.num_gates}, {"number of wires", st.num_wires}, + {"number of crossings", st.num_crossings}, {"layout", {{"x-size", st.x_size}, {"y-size", st.y_size}, {"area", st.x_size * st.y_size}}}}; } diff --git a/cli/cmd/physical_design/onepass.hpp b/cli/cmd/physical_design/onepass.hpp index 4721c5682..ba44f4bec 100644 --- a/cli/cmd/physical_design/onepass.hpp +++ b/cli/cmd/physical_design/onepass.hpp @@ -198,6 +198,7 @@ class onepass_command : public command {"runtime in seconds", mockturtle::to_seconds(st.time_total)}, {"number of gates", st.num_gates}, {"number of wires", st.num_wires}, + {"number of crossings", st.num_crossings}, {"layout", {{"x-size", st.x_size}, {"y-size", st.y_size}, {"area", st.x_size * st.y_size}}}}; } diff --git a/cli/cmd/physical_design/ortho.hpp b/cli/cmd/physical_design/ortho.hpp index 8c7963789..86ca86ded 100644 --- a/cli/cmd/physical_design/ortho.hpp +++ b/cli/cmd/physical_design/ortho.hpp @@ -109,6 +109,7 @@ class ortho_command : public command {"runtime in seconds", mockturtle::to_seconds(st.time_total)}, {"number of gates", st.num_gates}, {"number of wires", st.num_wires}, + {"number of crossings", st.num_crossings}, {"layout", {{"x-size", st.x_size}, {"y-size", st.y_size}, {"area", st.x_size * st.y_size}}}}; } diff --git a/cli/stores.hpp b/cli/stores.hpp index 5d24fdd09..f295ef8f0 100644 --- a/cli/stores.hpp +++ b/cli/stores.hpp @@ -185,10 +185,11 @@ ALICE_DESCRIBE_STORE(fiction::gate_layout_t, layout) const auto cp_tp = fiction::critical_path_length_and_throughput(*lyt_ptr); - return fmt::format("{} ({}) - {} × {}, I/O: {}/{}, gates: {}, wires: {}, CP: {}, TP: 1/{}, sync. elems.: {}", - lyt_ptr->get_layout_name(), lyt_ptr->get_clocking_scheme().name, lyt_ptr->x() + 1, - lyt_ptr->y() + 1, lyt_ptr->num_pis(), lyt_ptr->num_pos(), lyt_ptr->num_gates(), - lyt_ptr->num_wires(), cp_tp.critical_path_length, cp_tp.throughput, num_se); + return fmt::format( + "{} ({}) - {} × {}, I/O: {}/{}, gates: {}, wires: {}, crossings: {}, CP: {}, TP: 1/{}, sync. elems.: {}", + lyt_ptr->get_layout_name(), lyt_ptr->get_clocking_scheme().name, lyt_ptr->x() + 1, lyt_ptr->y() + 1, + lyt_ptr->num_pis(), lyt_ptr->num_pos(), lyt_ptr->num_gates(), lyt_ptr->num_wires(), + lyt_ptr->num_crossings(), cp_tp.critical_path_length, cp_tp.throughput, num_se); }; return std::visit(describe, layout); @@ -196,7 +197,6 @@ ALICE_DESCRIBE_STORE(fiction::gate_layout_t, layout) ALICE_PRINT_STORE_STATISTICS(fiction::gate_layout_t, os, layout) { - // TODO crossings const auto print_statistics = [&os](auto&& lyt_ptr) { using Lyt = typename std::decay_t::element_type; @@ -210,11 +210,12 @@ ALICE_PRINT_STORE_STATISTICS(fiction::gate_layout_t, os, layout) const auto cp_tp = fiction::critical_path_length_and_throughput(*lyt_ptr); - os << fmt::format( - "[i] {} ({}) - {} × {}, I/O: {}/{}, gates: {}, wires: {}, CP: {}, TP: 1/{}, sync. elems.: {}\n", - lyt_ptr->get_layout_name(), lyt_ptr->get_clocking_scheme().name, lyt_ptr->x() + 1, lyt_ptr->y() + 1, - lyt_ptr->num_pis(), lyt_ptr->num_pos(), lyt_ptr->num_gates(), lyt_ptr->num_wires(), - cp_tp.critical_path_length, cp_tp.throughput, num_se); + os << fmt::format("[i] {} ({}) - {} × {}, I/O: {}/{}, gates: {}, wires: {}, crossings: {}, CP: {}, TP: 1/{}, " + "sync. elems.: {}\n", + lyt_ptr->get_layout_name(), lyt_ptr->get_clocking_scheme().name, lyt_ptr->x() + 1, + lyt_ptr->y() + 1, lyt_ptr->num_pis(), lyt_ptr->num_pos(), lyt_ptr->num_gates(), + lyt_ptr->num_wires(), lyt_ptr->num_crossings(), cp_tp.critical_path_length, cp_tp.throughput, + num_se); }; std::visit(print_statistics, layout); @@ -242,9 +243,9 @@ ALICE_LOG_STORE_STATISTICS(fiction::gate_layout_t, layout) {"outputs", lyt_ptr->num_pos()}, {"gates", lyt_ptr->num_gates()}, {"wires", lyt_ptr->num_wires()}, + {"crossings", lyt_ptr->num_crossings()}, {"layout", {{"x-size", lyt_ptr->x() + 1}, {"y-size", lyt_ptr->y() + 1}, {"area", lyt_ptr->area()}}}, // {"free tiles", area - (gate_tiles + wire_tiles - crossings)}, // free tiles in ground layer - // {"crossings", crossings}, {"synchronization elements", num_se}, {"critical path", cp_tp.critical_path_length}, {"throughput", fmt::format("1/{}", cp_tp.throughput)}}; diff --git a/include/fiction/algorithms/physical_design/exact.hpp b/include/fiction/algorithms/physical_design/exact.hpp index 56f820f2c..28dfd5cbd 100644 --- a/include/fiction/algorithms/physical_design/exact.hpp +++ b/include/fiction/algorithms/physical_design/exact.hpp @@ -156,16 +156,17 @@ struct exact_physical_design_stats mockturtle::stopwatch<>::duration time_total{0}; uint64_t x_size{0ull}, y_size{0ull}; - uint64_t num_gates{0ull}, num_wires{0ull}; + uint64_t num_gates{0ull}, num_wires{0ull}, num_crossings{0ull}; uint32_t num_aspect_ratios{0ul}; void report(std::ostream& out = std::cout) const { - out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); - out << fmt::format("[i] layout size = {} × {}\n", x_size, y_size); - out << fmt::format("[i] num. gates = {}\n", num_gates); - out << fmt::format("[i] num. wires = {}\n", num_wires); + out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); + out << fmt::format("[i] layout size = {} × {}\n", x_size, y_size); + out << fmt::format("[i] num. gates = {}\n", num_gates); + out << fmt::format("[i] num. wires = {}\n", num_wires); + out << fmt::format("[i] num. crossings = {}\n", num_crossings); } }; @@ -3033,10 +3034,11 @@ class exact_impl if (result_aspect_ratio.has_value()) { // statistical information - pst.x_size = layout.x() + 1; - pst.y_size = layout.y() + 1; - pst.num_gates = layout.num_gates(); - pst.num_wires = layout.num_wires(); + pst.x_size = layout.x() + 1; + pst.y_size = layout.y() + 1; + pst.num_gates = layout.num_gates(); + pst.num_wires = layout.num_wires(); + pst.num_crossings = layout.num_crossings(); return layout; } @@ -3088,10 +3090,11 @@ class exact_impl if (sat) { // statistical information - pst.x_size = layout.x() + 1; - pst.y_size = layout.y() + 1; - pst.num_gates = layout.num_gates(); - pst.num_wires = layout.num_wires(); + pst.x_size = layout.x() + 1; + pst.y_size = layout.y() + 1; + pst.num_gates = layout.num_gates(); + pst.num_wires = layout.num_wires(); + pst.num_crossings = layout.num_crossings(); return layout; } diff --git a/include/fiction/algorithms/physical_design/graph_oriented_layout_design.hpp b/include/fiction/algorithms/physical_design/graph_oriented_layout_design.hpp index d8c538f2a..bdb9191e0 100644 --- a/include/fiction/algorithms/physical_design/graph_oriented_layout_design.hpp +++ b/include/fiction/algorithms/physical_design/graph_oriented_layout_design.hpp @@ -110,6 +110,10 @@ struct graph_oriented_layout_design_stats * Number of wires. */ uint64_t num_wires{0ull}; + /** + * Number of crossings. + */ + uint64_t num_crossings{0ull}; /** * Reports the statistics to the given output stream. * @@ -117,10 +121,11 @@ struct graph_oriented_layout_design_stats */ void report(std::ostream& out = std::cout) const { - out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); - out << fmt::format("[i] layout size = {} × {}\n", x_size, y_size); - out << fmt::format("[i] num. gates = {}\n", num_gates); - out << fmt::format("[i] num. wires = {}\n", num_wires); + out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); + out << fmt::format("[i] layout size = {} × {}\n", x_size, y_size); + out << fmt::format("[i] num. gates = {}\n", num_gates); + out << fmt::format("[i] num. wires = {}\n", num_wires); + out << fmt::format("[i] num. crossings = {}\n", num_crossings); } }; @@ -643,10 +648,11 @@ class graph_oriented_layout_design_impl restore_names(ssg.network, best_lyt); // statistical information - pst.x_size = best_lyt.x() + 1; - pst.y_size = best_lyt.y() + 1; - pst.num_gates = best_lyt.num_gates(); - pst.num_wires = best_lyt.num_wires(); + pst.x_size = best_lyt.x() + 1; + pst.y_size = best_lyt.y() + 1; + pst.num_gates = best_lyt.num_gates(); + pst.num_wires = best_lyt.num_wires(); + pst.num_crossings = best_lyt.num_crossings(); if (ps.return_first) { diff --git a/include/fiction/algorithms/physical_design/one_pass_synthesis.hpp b/include/fiction/algorithms/physical_design/one_pass_synthesis.hpp index b0bc3d1aa..0e9bbd252 100644 --- a/include/fiction/algorithms/physical_design/one_pass_synthesis.hpp +++ b/include/fiction/algorithms/physical_design/one_pass_synthesis.hpp @@ -124,14 +124,15 @@ struct one_pass_synthesis_stats mockturtle::stopwatch<>::duration time_total{0}; uint64_t x_size{0ull}, y_size{0ull}; - uint64_t num_gates{0ull}, num_wires{0ull}; + uint64_t num_gates{0ull}, num_wires{0ull}, num_crossings{0ull}; void report(std::ostream& out = std::cout) const { - out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); - out << fmt::format("[i] layout size = {} × {}\n", x_size, y_size); - out << fmt::format("[i] num. gates = {}\n", num_gates); - out << fmt::format("[i] num. wires = {}\n", num_wires); + out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); + out << fmt::format("[i] layout size = {} × {}\n", x_size, y_size); + out << fmt::format("[i] num. gates = {}\n", num_gates); + out << fmt::format("[i] num. wires = {}\n", num_wires); + out << fmt::format("[i] num. crossings = {}\n", num_crossings); } }; @@ -757,10 +758,11 @@ class one_pass_synthesis_impl if (sat) // solution found { // statistical information - pst.x_size = layout.x() + 1; - pst.y_size = layout.y() + 1; - pst.num_gates = layout.num_gates(); - pst.num_wires = layout.num_wires(); + pst.x_size = layout.x() + 1; + pst.y_size = layout.y() + 1; + pst.num_gates = layout.num_gates(); + pst.num_wires = layout.num_wires(); + pst.num_crossings = layout.num_crossings(); // restore layout name if constexpr (has_set_layout_name_v) diff --git a/include/fiction/algorithms/physical_design/orthogonal.hpp b/include/fiction/algorithms/physical_design/orthogonal.hpp index 88eb52c65..350c6e63c 100644 --- a/include/fiction/algorithms/physical_design/orthogonal.hpp +++ b/include/fiction/algorithms/physical_design/orthogonal.hpp @@ -50,14 +50,15 @@ struct orthogonal_physical_design_stats mockturtle::stopwatch<>::duration time_total{0}; uint64_t x_size{0ull}, y_size{0ull}; - uint64_t num_gates{0ull}, num_wires{0ull}; + uint64_t num_gates{0ull}, num_wires{0ull}, num_crossings{0ull}; void report(std::ostream& out = std::cout) const { - out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); - out << fmt::format("[i] layout size = {} × {}\n", x_size, y_size); - out << fmt::format("[i] num. gates = {}\n", num_gates); - out << fmt::format("[i] num. wires = {}\n", num_wires); + out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); + out << fmt::format("[i] layout size = {} × {}\n", x_size, y_size); + out << fmt::format("[i] num. gates = {}\n", num_gates); + out << fmt::format("[i] num. wires = {}\n", num_wires); + out << fmt::format("[i] num. crossings = {}\n", num_crossings); } }; @@ -620,10 +621,11 @@ class orthogonal_impl restore_names(ctn.color_ntk, layout, node2pos); // statistical information - pst.x_size = layout.x() + 1; - pst.y_size = layout.y() + 1; - pst.num_gates = layout.num_gates(); - pst.num_wires = layout.num_wires(); + pst.x_size = layout.x() + 1; + pst.y_size = layout.y() + 1; + pst.num_gates = layout.num_gates(); + pst.num_wires = layout.num_wires(); + pst.num_crossings = layout.num_crossings(); return layout; } diff --git a/include/fiction/algorithms/physical_design/post_layout_optimization.hpp b/include/fiction/algorithms/physical_design/post_layout_optimization.hpp index fbcec43c6..1b612c69b 100644 --- a/include/fiction/algorithms/physical_design/post_layout_optimization.hpp +++ b/include/fiction/algorithms/physical_design/post_layout_optimization.hpp @@ -83,6 +83,22 @@ struct post_layout_optimization_stats * Area reduction (in %) after the post-layout optimization process. */ double_t area_improvement{0ull}; + /** + * Number of wire segments before the post-layout optimization process. + */ + uint64_t num_wires_before{0ull}; + /** + * Number of wire segments after the post-layout optimization process. + */ + uint64_t num_wires_after{0ull}; + /** + * Number of crossings before the post-layout optimization process. + */ + uint64_t num_crossings_before{0ull}; + /** + * Number of crossings after the post-layout optimization process. + */ + uint64_t num_crossings_after{0ull}; /** * Reports the statistics to the given output stream. * @@ -90,10 +106,15 @@ struct post_layout_optimization_stats */ void report(std::ostream& out = std::cout) const { - out << fmt::format("[i] total time = {:.2f} secs\n", mockturtle::to_seconds(time_total)); - out << fmt::format("[i] layout size before optimization = {} × {}\n", x_size_before, y_size_before); - out << fmt::format("[i] layout size after optimization = {} × {}\n", x_size_after, y_size_after); - out << fmt::format("[i] area reduction = {}%\n", area_improvement); + out << fmt::format("[i] total time = {:.2f} secs\n", + mockturtle::to_seconds(time_total)); + out << fmt::format("[i] layout size before optimization = {} × {}\n", x_size_before, y_size_before); + out << fmt::format("[i] layout size after optimization = {} × {}\n", x_size_after, y_size_after); + out << fmt::format("[i] area reduction = {}%\n", area_improvement); + out << fmt::format("[i] num. wires before optimization = {}\n", num_wires_before); + out << fmt::format("[i] num. wires after optimization = {}\n", num_wires_after); + out << fmt::format("[i] num. crossings before optimization = {}\n", num_crossings_before); + out << fmt::format("[i] num. crossings after optimization = {}\n", num_crossings_after); } }; @@ -906,8 +927,10 @@ class post_layout_optimization_impl static_assert(is_cartesian_layout_v, "Lyt is not a Cartesian layout"); const mockturtle::stopwatch stop{pst.time_total}; - pst.x_size_before = plyt.x() + 1; - pst.y_size_before = plyt.y() + 1; + pst.x_size_before = plyt.x() + 1; + pst.y_size_before = plyt.y() + 1; + pst.num_wires_before = plyt.num_wires() - plyt.num_pis() - plyt.num_pos(); + pst.num_crossings_before = plyt.num_crossings(); uint64_t max_gate_relocations = ps.max_gate_relocations.value_or((plyt.x() + 1) * (plyt.y() + 1)); @@ -994,6 +1017,9 @@ class post_layout_optimization_impl static_cast(area_before - area_after) / static_cast(area_before) * 100.0; area_percentage_difference = std::round(area_percentage_difference * 100) / 100; pst.area_improvement = area_percentage_difference; + + pst.num_wires_after = plyt.num_wires() - plyt.num_pis() - plyt.num_pos(); + pst.num_crossings_after = plyt.num_crossings(); } private: diff --git a/include/fiction/algorithms/simulation/sidb/time_to_solution.hpp b/include/fiction/algorithms/simulation/sidb/time_to_solution.hpp index 9d1a90530..8813e2994 100644 --- a/include/fiction/algorithms/simulation/sidb/time_to_solution.hpp +++ b/include/fiction/algorithms/simulation/sidb/time_to_solution.hpp @@ -79,7 +79,7 @@ struct time_to_solution_stats * * @param out Output stream. */ - void report(std::ostream& out = std::cout) + void report(std::ostream& out = std::cout) const { out << fmt::format("time_to_solution: {} \n acc: {} \n t[s]: {} \n t_exact[s]: {} \n exact alg.: {}\n", time_to_solution, acc, mean_single_runtime, single_runtime_exact, algorithm); diff --git a/include/fiction/layouts/gate_level_layout.hpp b/include/fiction/layouts/gate_level_layout.hpp index 60b10ec1e..99f6fb5a6 100644 --- a/include/fiction/layouts/gate_level_layout.hpp +++ b/include/fiction/layouts/gate_level_layout.hpp @@ -99,8 +99,9 @@ class gate_level_layout : public ClockedLayout phmap::parallel_flat_hash_map node_tile_map{ {{static_cast(0ull), const0}, {static_cast(1ull), const1}}}; - uint32_t num_gates = 0ull; - uint32_t num_wires = 0ull; + uint32_t num_gates = 0ull; + uint32_t num_wires = 0ull; + uint32_t num_crossings = 0ull; uint32_t trav_id = 0ul; @@ -555,6 +556,15 @@ class gate_level_layout : public ClockedLayout { return strg->data.num_wires; } + /** + * Returns the number of placed nodes in the layout that compute the identity function and cross other nodes. + * + * @return Number of crossings in the layout. + */ + [[nodiscard]] auto num_crossings() const noexcept + { + return strg->data.num_crossings; + } /** * Checks whether there are no gates or wires assigned to the layout's coordinates. * @@ -755,6 +765,12 @@ class gate_level_layout : public ClockedLayout { strg->data.num_wires--; + // decrease crossing count + if (ClockedLayout::is_crossing_layer(t) && !is_empty_tile(ClockedLayout::below(t))) + { + strg->data.num_crossings--; + } + // find PO entry and remove it if present if (const auto po_it = std::find_if(strg->outputs.cbegin(), strg->outputs.cend(), @@ -1669,6 +1685,11 @@ class gate_level_layout : public ClockedLayout if (is_wire(n)) { strg->data.num_wires++; + + if (ClockedLayout::is_crossing_layer(t) && !is_empty_tile(ClockedLayout::below(t))) + { + strg->data.num_crossings++; + } } else // is gate { diff --git a/test/layouts/gate_level_layout.cpp b/test/layouts/gate_level_layout.cpp index 631abee81..a08c35aba 100644 --- a/test/layouts/gate_level_layout.cpp +++ b/test/layouts/gate_level_layout.cpp @@ -124,6 +124,7 @@ TEST_CASE("Creation and usage of primary inputs", "[gate-level-layout]") CHECK(layout.num_pis() == 1); CHECK(layout.num_gates() == 0); CHECK(layout.num_wires() == 1); + CHECK(layout.num_crossings() == 0); CHECK(std::is_same_v, gate_layout::signal>); @@ -135,6 +136,7 @@ TEST_CASE("Creation and usage of primary inputs", "[gate-level-layout]") CHECK(layout.num_pis() == 3); CHECK(layout.num_wires() == 3); + CHECK(layout.num_crossings() == 0); CHECK(layout.pi_at(0) == layout.get_node(a)); CHECK(layout.pi_at(1) == layout.get_node(b)); @@ -220,6 +222,7 @@ TEST_CASE("Creation and usage of primary outputs", "[gate-level-layout]") CHECK(layout.size() == 5); CHECK(layout.num_pos() == 2); CHECK(layout.num_wires() == 3); + CHECK(layout.num_crossings() == 0); CHECK(layout.po_at(0) == f1); CHECK(layout.po_at(1) == f2); @@ -331,6 +334,7 @@ TEST_CASE("Creation of unary operations", "[gate-level-layout]") CHECK(layout.size() == 5); CHECK(layout.num_gates() == 1); CHECK(layout.num_wires() == 2); + CHECK(layout.num_crossings() == 0); auto x2 = layout.create_pi("x2", {1, 1}); CHECK(layout.is_pi(layout.get_node(x2))); @@ -907,6 +911,7 @@ TEST_CASE("Gate-level layout properties", "[gate-level-layout]") CHECK(layout.num_pis() == 2); CHECK(layout.num_pos() == 2); CHECK(layout.num_gates() == 2); + CHECK(layout.num_crossings() == 0); CHECK(layout.fanin_size(layout.get_node(x1)) == 0); CHECK(layout.fanin_size(layout.get_node(x2)) == 0); CHECK(layout.fanin_size(layout.get_node(a1)) == 2); @@ -1038,6 +1043,7 @@ TEST_CASE("Crossings", "[gate-level-layout]") auto layout = blueprints::crossing_layout(); + CHECK(layout.num_crossings() == 1); CHECK(layout.fanout_size(layout.get_node({1, 1})) == 1); CHECK(layout.fanout_size(layout.get_node({2, 1})) == 1); CHECK(layout.fanout_size(layout.get_node({2, 1, 1})) == 1); @@ -1073,6 +1079,7 @@ TEST_CASE("Move nodes", "[gate-level-layout]") CHECK(layout.num_gates() == 2); CHECK(layout.num_wires() == 4); + CHECK(layout.num_crossings() == 0); auto and_node = layout.get_node({1, 0}); auto or_node = layout.get_node({2, 1}); @@ -1084,6 +1091,7 @@ TEST_CASE("Move nodes", "[gate-level-layout]") CHECK(layout.num_gates() == 2); CHECK(layout.num_wires() == 4); + CHECK(layout.num_crossings() == 0); // move AND where OR was layout.move_node(and_node, {2, 1}, @@ -1092,6 +1100,7 @@ TEST_CASE("Move nodes", "[gate-level-layout]") CHECK(layout.num_gates() == 2); CHECK(layout.num_wires() == 4); + CHECK(layout.num_crossings() == 0); // move OR where AND was layout.move_node(or_node, {1, 0}, @@ -1100,6 +1109,7 @@ TEST_CASE("Move nodes", "[gate-level-layout]") CHECK(layout.num_gates() == 2); CHECK(layout.num_wires() == 4); + CHECK(layout.num_crossings() == 0); CHECK(!layout.is_dead(and_node)); CHECK(!layout.is_dead(or_node)); @@ -1141,6 +1151,7 @@ TEST_CASE("Move nodes", "[gate-level-layout]") CHECK(layout.num_gates() == 2); CHECK(layout.num_wires() == 4); + CHECK(layout.num_crossings() == 0); // move PO @@ -1154,6 +1165,7 @@ TEST_CASE("Move nodes", "[gate-level-layout]") CHECK(layout.num_gates() == 2); CHECK(layout.num_wires() == 4); + CHECK(layout.num_crossings() == 0); // remove PO @@ -1165,6 +1177,30 @@ TEST_CASE("Move nodes", "[gate-level-layout]") CHECK(layout.num_gates() == 2); CHECK(layout.num_wires() == 3); // PO is gone now + CHECK(layout.num_crossings() == 0); +} + +TEST_CASE("Move crossing", "[gate-level-layout]") +{ + using gate_layout = gate_level_layout>>>; + + auto layout = blueprints::crossing_layout(); + + CHECK(layout.num_gates() == 2); + CHECK(layout.num_wires() == 9); + CHECK(layout.num_crossings() == 1); + CHECK(layout.num_pis() == 4); + CHECK(layout.num_pos() == 2); + + auto crossing = layout.get_node({2, 1, 1}); + + // move crossing to empty location + layout.move_node(crossing, {3, 0}, {}); + CHECK(layout.num_gates() == 2); + CHECK(layout.num_wires() == 9); + CHECK(layout.num_crossings() == 0); + CHECK(layout.num_pis() == 4); + CHECK(layout.num_pos() == 2); } TEST_CASE("Clear tiles", "[gate-level-layout]") @@ -1175,6 +1211,7 @@ TEST_CASE("Clear tiles", "[gate-level-layout]") REQUIRE(layout.num_gates() == 2); REQUIRE(layout.num_wires() == 4); + REQUIRE(layout.num_crossings() == 0); REQUIRE(layout.num_pis() == 2); REQUIRE(layout.num_pos() == 2); @@ -1183,6 +1220,7 @@ TEST_CASE("Clear tiles", "[gate-level-layout]") CHECK(!layout.is_gate_tile({1, 0})); CHECK(layout.num_gates() == 1); CHECK(layout.num_wires() == 4); + CHECK(layout.num_crossings() == 0); CHECK(layout.num_pis() == 2); CHECK(layout.num_pos() == 2); @@ -1191,6 +1229,7 @@ TEST_CASE("Clear tiles", "[gate-level-layout]") CHECK(!layout.is_gate_tile({2, 1})); CHECK(layout.num_gates() == 0); CHECK(layout.num_wires() == 4); + CHECK(layout.num_crossings() == 0); CHECK(layout.num_pis() == 2); CHECK(layout.num_pos() == 2); @@ -1200,6 +1239,7 @@ TEST_CASE("Clear tiles", "[gate-level-layout]") CHECK(!layout.is_pi_tile({2, 0})); CHECK(layout.num_gates() == 0); CHECK(layout.num_wires() == 3); + CHECK(layout.num_crossings() == 0); CHECK(layout.num_pis() == 2); CHECK(layout.num_pos() == 2); @@ -1209,10 +1249,34 @@ TEST_CASE("Clear tiles", "[gate-level-layout]") CHECK(!layout.is_po_tile({0, 0})); CHECK(layout.num_gates() == 0); CHECK(layout.num_wires() == 2); + CHECK(layout.num_crossings() == 0); CHECK(layout.num_pis() == 2); CHECK(layout.num_pos() == 1); } +TEST_CASE("Clear crossing", "[gate-level-layout]") +{ + using gate_layout = gate_level_layout>>>; + + auto layout = blueprints::crossing_layout(); + + REQUIRE(layout.num_gates() == 2); + REQUIRE(layout.num_wires() == 9); + REQUIRE(layout.num_crossings() == 1); + REQUIRE(layout.num_pis() == 4); + REQUIRE(layout.num_pos() == 2); + + layout.clear_tile({2, 1, 1}); + + CHECK(!layout.is_wire_tile({2, 1, 1})); + CHECK(layout.is_empty_tile({2, 1, 1})); + CHECK(layout.num_gates() == 2); + CHECK(layout.num_wires() == 8); + CHECK(layout.num_crossings() == 0); + CHECK(layout.num_pis() == 4); + CHECK(layout.num_pos() == 2); +} + TEST_CASE("Gate-level cardinal operations", "[gate-level-layout]") { using gate_layout = gate_level_layout>>>; From 2e8baecc0df8f14da95c59087403100868fdebd0 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Thu, 29 Aug 2024 23:46:51 +0200 Subject: [PATCH 12/13] :bug: Fixed disappearing clocking schemes when applying a gate library (#515) * :bug: Fixed clocking schemes disappearing when applying gate libraries * :art: Fixed some missing headers and outdated docstrings while at it because why not * :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions * :bug: Adjust bindings after API change due to parameter `const`ness * :bug: Account for coordinate type differences in `GateLyt` and `CellLyt` --------- Signed-off-by: GitHub Actions Co-authored-by: GitHub Actions --- .../pyfiction/inout/write_svg_layout.hpp | 2 +- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 50 ++++++++----------- cli/cmd/physical_design/ortho.hpp | 4 ++ .../physical_design/apply_gate_library.hpp | 15 ++++++ include/fiction/io/write_svg_layout.hpp | 42 ++++++++-------- include/fiction/layouts/clocked_layout.hpp | 8 +-- include/fiction/layouts/clocking_scheme.hpp | 1 + 7 files changed, 67 insertions(+), 55 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/inout/write_svg_layout.hpp b/bindings/pyfiction/include/pyfiction/inout/write_svg_layout.hpp index 8774dca67..1eef073c9 100644 --- a/bindings/pyfiction/include/pyfiction/inout/write_svg_layout.hpp +++ b/bindings/pyfiction/include/pyfiction/inout/write_svg_layout.hpp @@ -31,7 +31,7 @@ inline void write_svg_layout(pybind11::module& m) ; void (*write_svg_layout_function_pointer)(const py_qca_layout&, const std::string_view&, - fiction::write_qca_layout_svg_params) = + const fiction::write_qca_layout_svg_params&) = &fiction::write_qca_layout_svg; m.def("write_qca_layout_svg", write_svg_layout_function_pointer, "layout"_a, "filename"_a, diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index b8fadcae4..7e58d5067 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -2039,9 +2039,9 @@ Parameter ``lyt``: static const char *__doc_fiction_clocked_layout = R"doc(A layout type to layer on top of a coordinate layout, e.g., -cartesian_layout, hexagonal_layout, or tile_based_layout. This type -extends the layout by providing a notion of FCN clocking. To this end, -it utilizes a clocking scheme that assigns each coordinate in the +`cartesian_layout`, `hexagonal_layout`, or `tile_based_layout`. This +type extends the layout by providing a notion of FCN clocking. To this +end, it utilizes a clocking scheme that assigns each coordinate in the extended coordinate layout a clock number. These clock numbers can be manually overwritten if necessary. @@ -7852,36 +7852,23 @@ static const char *__doc_fiction_detail_write_qca_layout_impl_write_via_cells = static const char *__doc_fiction_detail_write_qca_layout_svg_impl = R"doc()doc"; static const char *__doc_fiction_detail_write_qca_layout_svg_impl_generate_cell_based_svg = -R"doc(Returns an SVG string representing the given cell-based clocked cell -layout +R"doc(Generates an SVG string representing the cell-based clocked cell +layout and appends it to the output stream.)doc"; -Parameter ``fcl``: - The cell layout to generate an SVG representation for. +static const char *__doc_fiction_detail_write_qca_layout_svg_impl_generate_description_color = +R"doc(Generates and returns a pair of strings representing the description +and color of the given cell. -Parameter ``simple``: - Flag to indicate that the SVG representation should be generated - with less details. Recommended for large layouts. +Parameter ``c``: + The cell for which to generate the description and color. Returns: - The SVG string containing a visual representation of the given - layout.)doc"; - -static const char *__doc_fiction_detail_write_qca_layout_svg_impl_generate_description_color = R"doc()doc"; + A pair of strings representing the description and color of the + given cell `c`.)doc"; static const char *__doc_fiction_detail_write_qca_layout_svg_impl_generate_tile_based_svg = -R"doc(Returns an SVG string representing the given tile-based clocked cell -layout. - -Parameter ``fcl``: - The cell layout to generate an SVG representation for. - -Parameter ``simple``: - Flag to indicate that the SVG representation should be generated - with less details. Recommended for large layouts. - -Returns: - The SVG string containing a visual representation of the given - layout.)doc"; +R"doc(Generates an SVG string representing the tile-based clocked cell +layout and appends it to the output stream.)doc"; static const char *__doc_fiction_detail_write_qca_layout_svg_impl_lyt = R"doc()doc"; @@ -7891,7 +7878,7 @@ static const char *__doc_fiction_detail_write_qca_layout_svg_impl_ps = R"doc()do static const char *__doc_fiction_detail_write_qca_layout_svg_impl_run = R"doc()doc"; -static const char *__doc_fiction_detail_write_qca_layout_svg_impl_write_qca_layout_svg_impl = R"doc()doc"; +static const char *__doc_fiction_detail_write_qca_layout_svg_impl_write_qca_layout_svg_impl = R"doc(Default constructor.)doc"; static const char *__doc_fiction_detail_write_qcc_layout_impl = R"doc()doc"; @@ -17440,7 +17427,8 @@ supported exclusively so far. The utilized color scheme is based on the standard scheme used in QCADesigner (https://waluslab.ece.ubc.ca/qcadesigner/). -May throw an unsupported_cell_type_exception. +May throw an `unsupported_cell_type_exception` if it encounters +unsupported cell types in the layout. Template parameter ``Lyt``: Cell-level QCA layout type. @@ -17463,7 +17451,9 @@ exclusively so far. The utilized color scheme is based on the standard scheme used in QCADesigner (https://waluslab.ece.ubc.ca/qcadesigner/). -May throw an unsupported_cell_type_exception. +May throw an `unsupported_cell_type_exception` if it encounters +unsupported cell types in the layout. May throw an +`std::ofstream::failure` if it cannot open the file. Template parameter ``Lyt``: Cell-level QCA layout type. diff --git a/cli/cmd/physical_design/ortho.hpp b/cli/cmd/physical_design/ortho.hpp index 86ca86ded..2ffc8ccb7 100644 --- a/cli/cmd/physical_design/ortho.hpp +++ b/cli/cmd/physical_design/ortho.hpp @@ -7,11 +7,15 @@ #include #include +#include +#include #include +#include #include #include +#include #include namespace alice diff --git a/include/fiction/algorithms/physical_design/apply_gate_library.hpp b/include/fiction/algorithms/physical_design/apply_gate_library.hpp index 7a0c411d4..542282681 100644 --- a/include/fiction/algorithms/physical_design/apply_gate_library.hpp +++ b/include/fiction/algorithms/physical_design/apply_gate_library.hpp @@ -46,6 +46,21 @@ class apply_gate_library_impl ((gate_lyt.y() + 1) * GateLibrary::gate_y_size()) - 1, gate_lyt.z()}); cell_lyt.set_tile_size_x(GateLibrary::gate_x_size()); cell_lyt.set_tile_size_y(GateLibrary::gate_y_size()); + + // if GateLyt and CellLyt are based on the same coordinate type, copy the clocking scheme over + if constexpr (std::is_same_v, coordinate>) + { + cell_lyt.replace_clocking_scheme(gate_lyt.get_clocking_scheme()); + } + // otherwise, try to find a matching clocking scheme (this will discard overwritten clock numbers) + else + { + if (const auto clk_scheme = get_clocking_scheme(gate_lyt.get_clocking_scheme().name); + clk_scheme.has_value()) + { + cell_lyt.replace_clocking_scheme(clk_scheme.value()); + } + } } /** diff --git a/include/fiction/io/write_svg_layout.hpp b/include/fiction/io/write_svg_layout.hpp index 39c35b701..9cc4794b3 100644 --- a/include/fiction/io/write_svg_layout.hpp +++ b/include/fiction/io/write_svg_layout.hpp @@ -13,10 +13,12 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -339,7 +341,10 @@ template class write_qca_layout_svg_impl { public: - write_qca_layout_svg_impl(const Lyt& layout, std::ostream& stream, write_qca_layout_svg_params p) : + /** + * Default constructor. + */ + write_qca_layout_svg_impl(const Lyt& layout, std::ostream& stream, const write_qca_layout_svg_params& p = {}) : lyt{layout}, os{stream}, ps{p} @@ -386,6 +391,12 @@ class write_qca_layout_svg_impl */ using coord_to_latch_mapping = std::unordered_map, svg_latch>; + /** + * Generates and returns a pair of strings representing the description and color of the given cell. + * + * @param c The cell for which to generate the description and color. + * @return A pair of strings representing the description and color of the given cell `c`. + */ std::pair generate_description_color(const cell& c) { std::string cell_description, cell_color{}; @@ -466,12 +477,7 @@ class write_qca_layout_svg_impl } /** - * Returns an SVG string representing the given cell-based clocked cell layout - * - * @param fcl The cell layout to generate an SVG representation for. - * @param simple Flag to indicate that the SVG representation should be generated with less details. Recommended - * for large layouts. - * @return The SVG string containing a visual representation of the given layout. + * Generates an SVG string representing the cell-based clocked cell layout and appends it to the output stream. */ void generate_cell_based_svg() { @@ -518,12 +524,7 @@ class write_qca_layout_svg_impl } /** - * Returns an SVG string representing the given tile-based clocked cell layout. - * - * @param fcl The cell layout to generate an SVG representation for. - * @param simple Flag to indicate that the SVG representation should be generated with less details. Recommended - * for large layouts. - * @return The SVG string containing a visual representation of the given layout. + * Generates an SVG string representing the tile-based clocked cell layout and appends it to the output stream. */ void generate_tile_based_svg() { @@ -539,9 +540,9 @@ class write_qca_layout_svg_impl // Used to determine the color of cells, tiles and text based on its clock zone static constexpr const std::array tile_colors{ - {svg::CLOCK_ZONE_1_TILE, svg::CLOCK_ZONE_2_TILE, svg::CLOCK_ZONE_3_TILE, svg::CLOCK_ZONE_4_TILE}}, - text_colors{ - {svg::CLOCK_ZONE_12_TEXT, svg::CLOCK_ZONE_12_TEXT, svg::CLOCK_ZONE_34_TEXT, svg::CLOCK_ZONE_34_TEXT}}; + {svg::CLOCK_ZONE_1_TILE, svg::CLOCK_ZONE_2_TILE, svg::CLOCK_ZONE_3_TILE, svg::CLOCK_ZONE_4_TILE}}; + static constexpr const std::array text_colors{ + {svg::CLOCK_ZONE_12_TEXT, svg::CLOCK_ZONE_12_TEXT, svg::CLOCK_ZONE_34_TEXT, svg::CLOCK_ZONE_34_TEXT}}; // Adds all non-empty cells from the layout to their correct tiles; it generates the "body" // of all the tile-descriptions to be used later @@ -723,7 +724,7 @@ class write_qca_layout_svg_impl * The utilized color scheme is based on the standard scheme used in QCADesigner * (https://waluslab.ece.ubc.ca/qcadesigner/). * - * May throw an unsupported_cell_type_exception. + * May throw an `unsupported_cell_type_exception` if it encounters unsupported cell types in the layout. * * @tparam Lyt Cell-level QCA layout type. * @param lyt The layout to be written. @@ -731,7 +732,7 @@ class write_qca_layout_svg_impl * @param ps Parameters. */ template -void write_qca_layout_svg(const Lyt& lyt, std::ostream& os, write_qca_layout_svg_params ps = {}) +void write_qca_layout_svg(const Lyt& lyt, std::ostream& os, const write_qca_layout_svg_params& ps = {}) { static_assert(is_cell_level_layout_v, "Lyt is not a cell-level layout"); static_assert(has_qca_technology_v, "Lyt must be a QCA layout"); @@ -748,7 +749,8 @@ void write_qca_layout_svg(const Lyt& lyt, std::ostream& os, write_qca_layout_svg * The utilized color scheme is based on the standard scheme used in QCADesigner * (https://waluslab.ece.ubc.ca/qcadesigner/). * - * May throw an unsupported_cell_type_exception. + * May throw an `unsupported_cell_type_exception` if it encounters unsupported cell types in the layout. May throw an + * `std::ofstream::failure` if it cannot open the file. * * @tparam Lyt Cell-level QCA layout type. * @param lyt The layout to be written. @@ -756,7 +758,7 @@ void write_qca_layout_svg(const Lyt& lyt, std::ostream& os, write_qca_layout_svg * @param ps Parameters. */ template -void write_qca_layout_svg(const Lyt& lyt, const std::string_view& filename, write_qca_layout_svg_params ps = {}) +void write_qca_layout_svg(const Lyt& lyt, const std::string_view& filename, const write_qca_layout_svg_params& ps = {}) { std::ofstream os{filename.data(), std::ofstream::out}; diff --git a/include/fiction/layouts/clocked_layout.hpp b/include/fiction/layouts/clocked_layout.hpp index 09d77f576..ff9b4064d 100644 --- a/include/fiction/layouts/clocked_layout.hpp +++ b/include/fiction/layouts/clocked_layout.hpp @@ -23,10 +23,10 @@ namespace fiction { /** - * A layout type to layer on top of a coordinate layout, e.g., cartesian_layout, hexagonal_layout, or tile_based_layout. - * This type extends the layout by providing a notion of FCN clocking. To this end, it utilizes a clocking scheme that - * assigns each coordinate in the extended coordinate layout a clock number. These clock numbers can be manually - * overwritten if necessary. + * A layout type to layer on top of a coordinate layout, e.g., `cartesian_layout`, `hexagonal_layout`, or + * `tile_based_layout`. This type extends the layout by providing a notion of FCN clocking. To this end, it utilizes a + * clocking scheme that assigns each coordinate in the extended coordinate layout a clock number. These clock numbers + * can be manually overwritten if necessary. * * In the context of this layout type, coordinates are renamed as clock zones. * diff --git a/include/fiction/layouts/clocking_scheme.hpp b/include/fiction/layouts/clocking_scheme.hpp index 8d10caff1..627fd50c3 100644 --- a/include/fiction/layouts/clocking_scheme.hpp +++ b/include/fiction/layouts/clocking_scheme.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include From c37da6202497267cb968843bbb7e9fa768aaeac8 Mon Sep 17 00:00:00 2001 From: Marcel Walter Date: Fri, 30 Aug 2024 08:35:05 +0200 Subject: [PATCH 13/13] :bookmark: Bump version to 0.6.4 (#516) * :bookmark: Bump version to 0.6.4 * :memo: Updated the CHANGELOG --- CMakeLists.txt | 2 +- docs/changelog.rst | 17 ++++++++++++++--- docs/conf.py | 4 ++-- pyproject.toml | 2 +- setup.py | 2 +- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d4b4bc24d..d5ef988e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ set(CMAKE_CXX_EXTENSIONS OFF) # Set the project name and version project( fiction - VERSION 0.6.3 + VERSION 0.6.4 DESCRIPTION "An open-source design automation framework for Field-coupled Nanotechnologies" HOMEPAGE_URL "https://github.com/cda-tum/fiction" diff --git a/docs/changelog.rst b/docs/changelog.rst index 10cd490bf..dd70cf459 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,8 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on `Keep a Changelog `_. -Unreleased ----------- +v0.6.4 - 2024-08-30 +------------------- Added ##### @@ -14,8 +14,19 @@ Added - Path-finding: - Squared Euclidean distance function - Chebyshev distance function +- Data structures: + - ``gate_level_layout`` now tracks its number of crossings +- CLI: + - ``ps -g`` and ``store -g`` now display the current ``gate_level_layout``'s number of crossings + +Fixed +##### +- Fixed disappearing clocking schemes when applying a gate library to a gate-level layout +- Fixed a few oversights in the RTD documentation of SiDB simulation functionality +- Fixed several typos and docstrings in the codebase +- Addressed some ``clang-tidy`` warnings -v0.6.3 - 2024-08-21 +v0.6.3 - 2024-08-22 ------------------- Added diff --git a/docs/conf.py b/docs/conf.py index 6a0805b9e..878f8583d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -51,9 +51,9 @@ # built documents. # # The short X.Y version. -version = 'v0.6.3' +version = 'v0.6.4' # The full version, including alpha/beta/rc tags. -release = 'v0.6.3' +release = 'v0.6.4' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/pyproject.toml b/pyproject.toml index 3d0322509..f07eeb8a2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta" [project] name = "mnt.pyfiction" -version = "0.6.3" +version = "0.6.4" description = "Design Automation for Field-coupled Nanotechnologies" readme = "README.md" authors = [ diff --git a/setup.py b/setup.py index ae7ae1521..8eaea3153 100644 --- a/setup.py +++ b/setup.py @@ -100,7 +100,7 @@ def build_extension(self, ext): setup( name='mnt.pyfiction', - version='0.6.2', + version='0.6.4', author='Marcel Walter', author_email='marcel.walter@tum.de', description='Design Automation for Field-coupled Nanotechnologies',