From e2846f7e53f591ac1627685dd35e4a8e3668656c Mon Sep 17 00:00:00 2001 From: wlambooy Date: Mon, 28 Oct 2024 18:58:59 +0100 Subject: [PATCH 01/10] :bug: the `AFTER_FIRST_SOLUTION` mode now actually terminates after the first operational gate is designed --- .../physical_design/design_sidb_gates.hpp | 25 +++++++++++++------ .../physical_design/design_sidb_gates.cpp | 21 +++++++++++++--- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp index ccaa20785..a9d85a7ff 100644 --- a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp +++ b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp @@ -225,17 +225,20 @@ class design_sidb_gates_impl { { const std::lock_guard lock_vector{mutex_to_protect_designed_gate_layouts}; + + // ensure only one designed gate is returned when AFTER_FIRST_SOLUTION is the termination condition + if (params.termination_cond == + design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION && + solution_found) + { + return; + } + designed_gate_layouts.push_back(layout_with_added_cells); } solution_found = true; } - - if (solution_found && (params.termination_cond == - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION)) - { - return; - } }; const std::size_t number_of_used_threads = @@ -250,13 +253,21 @@ class design_sidb_gates_impl for (std::size_t i = 0; i < number_of_used_threads; ++i) { threads.emplace_back( - [i, chunk_size, &all_combinations, &add_combination_to_layout_and_check_operation]() + [this, i, chunk_size, &all_combinations, &add_combination_to_layout_and_check_operation, + &solution_found]() { const std::size_t start_index = i * chunk_size; const std::size_t end_index = std::min(start_index + chunk_size, all_combinations.size()); for (std::size_t j = start_index; j < end_index; ++j) { + if (params.termination_cond == + design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION && + solution_found) + { + return; + } + add_combination_to_layout_and_check_operation(all_combinations[j]); } }); diff --git a/test/algorithms/physical_design/design_sidb_gates.cpp b/test/algorithms/physical_design/design_sidb_gates.cpp index 648cf08f1..519f3d653 100644 --- a/test/algorithms/physical_design/design_sidb_gates.cpp +++ b/test/algorithms/physical_design/design_sidb_gates.cpp @@ -116,7 +116,20 @@ TEST_CASE("Use SiQAD XNOR skeleton and generate SiQAD XNOR gate, exhaustive", "[ const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_xnor_tt()}, params); - REQUIRE(found_gate_layouts.size() == 4); + CHECK(found_gate_layouts.size() == 4); + } + SECTION("Four cells in canvas, design one gate with one SiDB in the canvas (terminate on first found)") + { + const auto params = design_sidb_gates_params>{ + is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, + design_sidb_gates_params>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + {{10, 4, 0}, {13, 4, 0}}, + 1, + design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION}; + + const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_xnor_tt()}, params); + + CHECK(found_gate_layouts.size() == 1); } SECTION("Four cells in canvas, design process is terminated after first solution is found (one SiDB in the " "canvas), QuickExact") @@ -366,8 +379,10 @@ TEST_CASE("Design AND Bestagon shaped gate", "[design-sidb-gates]") CHECK(found_gate_layouts_quickcell.front().num_defects() == 1); CHECK(found_gate_layouts_quickcell.front().num_cells() == lyt.num_cells() + 2); - found_gate_layouts_quickcell.front().foreach_cell([](const auto& cell) - { CHECK(cell != siqad::coord_t{16, 10, 0}); }); + found_gate_layouts_quickcell.front().foreach_cell( + [](const auto& cell) { + CHECK(cell != siqad::coord_t{16, 10, 0}); + }); } } From 108bb4072034b937156edb615e37851d1c019b1c Mon Sep 17 00:00:00 2001 From: wlambooy Date: Mon, 28 Oct 2024 21:44:32 +0100 Subject: [PATCH 02/10] :zap: operational status assessment can now return the simulation results that certified the status `OPERATIONAL` --- .../simulation/sidb/is_operational.hpp | 24 ++++- .../physical_design/design_sidb_gates.hpp | 2 +- .../simulation/sidb/is_operational.hpp | 98 +++++++++++++++---- .../simulation/sidb/operational_domain.hpp | 4 +- .../simulation/sidb/is_operational.cpp | 58 ++++++++--- 5 files changed, 147 insertions(+), 39 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp index b9ceff4bf..dd601491d 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp @@ -22,7 +22,7 @@ namespace detail { template -void is_operational(pybind11::module& m) +void is_operational(pybind11::module& m, const std::string& lattice = "") { using namespace pybind11::literals; @@ -32,6 +32,15 @@ void is_operational(pybind11::module& m) m.def("operational_input_patterns", &fiction::operational_input_patterns, "lyt"_a, "spec"_a, "params"_a = fiction::is_operational_params{}, DOC(fiction_operational_input_patterns)); + + pybind11::class_>( + m, fmt::format("sidb_simulation_result{}", lattice).c_str(), DOC(fiction_operational_status_assessment_stats)) + .def(pybind11::init<>()) + .def_readwrite("simulation_results", &fiction::operational_status_assessment_stats::simulation_results, + DOC(fiction_operational_status_assessment_stats_simulation_results)) + .def_readwrite("number_of_simulator_invocations", + &fiction::operational_status_assessment_stats::number_of_simulator_invocations, + DOC(fiction_operational_status_assessment_stats_number_of_simulator_invocations)); } } // namespace detail @@ -51,6 +60,15 @@ inline void is_operational(pybind11::module& m) .value("REJECT_KINKS", fiction::operational_condition::REJECT_KINKS, DOC(fiction_operational_condition_REJECT_KINKS)); + py::enum_( + m, "simulation_results_mode", DOC(fiction_is_operational_params_simulation_results_mode)) + .value("KEEP_SIMULATION_RESULTS", + fiction::is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS, + DOC(fiction_is_operational_params_simulation_results_mode_KEEP_SIMULATION_RESULTS)) + .value("DISCARD_SIMULATION_RESULTS", + fiction::is_operational_params::simulation_results_mode::DISCARD_SIMULATION_RESULTS, + DOC(fiction_is_operational_params_simulation_results_mode_DISCARD_SIMULATION_RESULTS)); + py::class_(m, "is_operational_params", DOC(fiction_is_operational_params)) .def(py::init<>()) .def_readwrite("simulation_parameters", &fiction::is_operational_params::simulation_parameters, @@ -63,8 +81,8 @@ inline void is_operational(pybind11::module& m) DOC(fiction_is_operational_params_op_condition)); // NOTE be careful with the order of the following calls! Python will resolve the first matching overload! - detail::is_operational(m); - detail::is_operational(m); + detail::is_operational(m, "_100"); + detail::is_operational(m, "_111"); } } // namespace pyfiction diff --git a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp index a9d85a7ff..9eb03e1d3 100644 --- a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp +++ b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp @@ -218,7 +218,7 @@ class design_sidb_gates_impl // canvas SiDBs are added to the skeleton const auto layout_with_added_cells = skeleton_layout_with_canvas_sidbs(combination); - if (const auto [status, sim_calls] = + if (const auto [status, aux_stats] = is_operational(layout_with_added_cells, truth_table, params.operational_params, std::optional{input_bdl_wires}, std::optional{output_bdl_wires}); status == operational_status::OPERATIONAL) diff --git a/include/fiction/algorithms/simulation/sidb/is_operational.hpp b/include/fiction/algorithms/simulation/sidb/is_operational.hpp index 41fcdecd3..abb465e35 100644 --- a/include/fiction/algorithms/simulation/sidb/is_operational.hpp +++ b/include/fiction/algorithms/simulation/sidb/is_operational.hpp @@ -73,6 +73,20 @@ enum class operational_condition : uint8_t */ struct is_operational_params { + /** + * Selector for the different ways to handle obtained simulation results. + */ + enum class simulation_results_mode : uint8_t + { + /** + * The simulation results for each input pattern are returned for operational gates. + */ + KEEP_SIMULATION_RESULTS, + /** + * The simulation results are discarded after the operational status was assessed. + */ + DISCARD_SIMULATION_RESULTS + }; /** * The simulation parameters for the physical simulation of the ground state. */ @@ -86,9 +100,37 @@ struct is_operational_params */ bdl_input_iterator_params input_bdl_iterator_params{}; /** - * Condition which is used to decide if a layout is `operational` or `non-operational`. + * Condition that is used to decide if a layout is `operational` or `non-operational`. */ operational_condition op_condition = operational_condition::TOLERATE_KINKS; + /** + * Simulation results that are used to certify the status `OPERATIONAL` are not kept by default. + */ + simulation_results_mode simulation_results_retention = simulation_results_mode::DISCARD_SIMULATION_RESULTS; +}; + +/** + * This struct is used to collect auxiliary results from the operational status assessment. + * + * @tparam SiDB cell-level layout type. + */ +template +struct operational_status_assessment_stats +{ + /** + * Simulation results for each input are only kept when the simulation results retention is set to + * `simulation_results_mode::KEEP_SIMULATION_RESULTS`. + */ + using simulation_results_per_input = std::optional>>>; + /** + * The charge distributions obtained for each input combination tested, sorted by the binary representation of the + * respectively associated input combinations. + */ + simulation_results_per_input simulation_results; + /** + * The number of input combinations tested. + */ + std::size_t number_of_simulator_invocations{0}; }; namespace detail @@ -163,10 +205,19 @@ class is_operational_impl assert((truth_table.size() == output_bdl_pairs.size()) && "Number of truth tables and output BDL pairs does not match"); + // when `simulation_results_mode::KEEP_SIMULATION_RESULTS` is set, the simulation results must be collected for + // each input combination + std::vector>> sim_res_per_input{}; + if (parameters.simulation_results_retention == + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS) + { + sim_res_per_input.reserve(truth_table.front().num_bits()); + } + // number of different input combinations for (auto i = 0u; i < truth_table.front().num_bits(); ++i, ++bii) { - ++simulator_invocations; + ++stats.number_of_simulator_invocations; // if positively charged SiDBs can occur, the SiDB layout is considered as non-operational if (can_positive_charges_occur(*bii, parameters.simulation_parameters)) @@ -226,6 +277,21 @@ class is_operational_impl } } } + + // save simulation results when the simulation result retention is set to + // `simulation_results_mode::KEEP_SIMULATION_RESULTS` + if (parameters.simulation_results_retention == + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS) + { + sim_res_per_input.emplace_back(std::move(simulation_results.charge_distributions)); + } + } + + // only when the layout is operational, the simulation results may be kept + if (parameters.simulation_results_retention == + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS) + { + stats.simulation_results.emplace(std::move(sim_res_per_input)); } // if we made it here, the layout is operational @@ -247,8 +313,6 @@ class is_operational_impl // number of different input combinations for (auto i = 0u; i < truth_table.front().num_bits(); ++i, ++bii) { - ++simulator_invocations; - // if positively charged SiDBs can occur, the SiDB layout is considered as non-operational if (can_positive_charges_occur(*bii, parameters.simulation_parameters)) { @@ -269,8 +333,8 @@ class is_operational_impl simulation_results.charge_distributions.cbegin(), simulation_results.charge_distributions.cend(), [](const auto& lhs, const auto& rhs) { return lhs.get_system_energy() < rhs.get_system_energy(); }); - // ground state is degenerate - if ((energy_distribution(simulation_results.charge_distributions).cbegin()->second) > 1) + // if the ground state is degenerate, the layout is considered non-operational + if (energy_distribution(simulation_results.charge_distributions).cbegin()->second > 1) { continue; } @@ -317,13 +381,13 @@ class is_operational_impl return operational_inputs; } /** - * Returns the total number of simulator invocations. + * Returns auxiliary results from the operational status assessment, including the number of simulator invocations. * - * @return The number of simulator invocations. + * @return Auxiliary results from the operational status assessment. */ - [[nodiscard]] std::size_t get_number_of_simulator_invocations() const noexcept + [[nodiscard]] operational_status_assessment_stats get_operational_status_assessment_stats() const noexcept { - return simulator_invocations; + return stats; } private: @@ -356,9 +420,9 @@ class is_operational_impl */ std::vector> output_bdl_wires; /** - * Number of simulator invocations. + * Auxiliary results from the operational status assessment, including the number of simulator invocations. */ - std::size_t simulator_invocations{0}; + operational_status_assessment_stats stats; /** * This function conducts physical simulation of the given layout (gate layout with certain input combination). The * simulation results are stored in the `sim_result` variable. @@ -576,11 +640,11 @@ class is_operational_impl * @param input_bdl_wire Optional BDL input wires of lyt. * @param output_bdl_wire Optional BDL output wires of lyt. * @param input_bdl_wire_direction Optional BDL input wire directions of lyt. - * @return A pair containing the operational status of the gate layout (either `OPERATIONAL` or `NON_OPERATIONAL`) and - * the number of input combinations tested. + * @return A pair containing the operational status of the gate layout (either `OPERATIONAL` or `NON_OPERATIONAL`) along + * with auxiliary statistics. */ template -[[nodiscard]] std::pair +[[nodiscard]] std::pair> is_operational(const Lyt& lyt, const std::vector& spec, const is_operational_params& params = {}, const std::optional>>& input_bdl_wire = std::nullopt, const std::optional>>& output_bdl_wire = std::nullopt) @@ -601,12 +665,12 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational { detail::is_operational_impl p{lyt, spec, params, input_bdl_wire.value(), output_bdl_wire.value()}; - return {p.run(), p.get_number_of_simulator_invocations()}; + return {p.run(), p.get_operational_status_assessment_stats()}; } detail::is_operational_impl p{lyt, spec, params}; - return {p.run(), p.get_number_of_simulator_invocations()}; + return {p.run(), p.get_operational_status_assessment_stats()}; } /** * This function determines the input combinations for which the SiDB-based logic, represented by the diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 8f502dc33..5fd79c035 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -1085,9 +1085,9 @@ class operational_domain_impl auto op_params_set_dimension_values = params.operational_params; op_params_set_dimension_values.simulation_parameters = sim_params; - const auto& [status, sim_calls] = is_operational(layout, truth_table, op_params_set_dimension_values); + const auto& [status, aux_stats] = is_operational(layout, truth_table, op_params_set_dimension_values); - num_simulator_invocations += sim_calls; + num_simulator_invocations += aux_stats.number_of_simulator_invocations; if (status == operational_status::NON_OPERATIONAL) { diff --git a/test/algorithms/simulation/sidb/is_operational.cpp b/test/algorithms/simulation/sidb/is_operational.cpp index e1db240e5..ec4c92435 100644 --- a/test/algorithms/simulation/sidb/is_operational.cpp +++ b/test/algorithms/simulation/sidb/is_operational.cpp @@ -27,23 +27,49 @@ TEST_CASE("SiQAD OR gate", "[is-operational]") const sidb_100_cell_clk_lyt_siqad lat{layout_or_gate}; - CHECK(is_operational( - lat, std::vector{create_or_tt()}, - is_operational_params{sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{ - detect_bdl_wires_params{1.5}, - bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, - operational_condition::REJECT_KINKS}) - .first == operational_status::NON_OPERATIONAL); + SECTION("Reject kinks and keep simulation results") + { - CHECK(is_operational( - lat, std::vector{create_or_tt()}, - is_operational_params{sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{ - detect_bdl_wires_params{1.5}, - bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, - operational_condition::TOLERATE_KINKS}) - .first == operational_status::OPERATIONAL); + const auto p_no = is_operational( + lat, std::vector{create_or_tt()}, + is_operational_params{sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, + bdl_input_iterator_params{ + detect_bdl_wires_params{1.5}, + bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, + operational_condition::REJECT_KINKS, + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS}); + CHECK(p_no.first == operational_status::NON_OPERATIONAL); + CHECK(!p_no.second.simulation_results.has_value()); + } + + SECTION("Tolerate kinks and keep simulation results") + { + const auto p_o = is_operational( + lat, std::vector{create_or_tt()}, + is_operational_params{sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, + bdl_input_iterator_params{ + detect_bdl_wires_params{1.5}, + bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, + operational_condition::TOLERATE_KINKS, + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS}); + CHECK(p_o.first == operational_status::OPERATIONAL); + REQUIRE(p_o.second.simulation_results.has_value()); + CHECK(p_o.second.simulation_results.value().size() == 4); + } + + SECTION("Tolerate kinks and discard simulation results") + { + const auto p_o2 = is_operational( + lat, std::vector{create_or_tt()}, + is_operational_params{sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, + bdl_input_iterator_params{ + detect_bdl_wires_params{1.5}, + bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, + operational_condition::TOLERATE_KINKS, + is_operational_params::simulation_results_mode::DISCARD_SIMULATION_RESULTS}); + CHECK(p_o2.first == operational_status::OPERATIONAL); + CHECK(!p_o2.second.simulation_results.has_value()); + } } TEST_CASE("SiQAD's AND gate with input BDL pairs of different size", "[is-operational]") From 3424cecac4af4509485a8984ebe96bf8057066dd Mon Sep 17 00:00:00 2001 From: wlambooy Date: Mon, 28 Oct 2024 22:22:42 +0100 Subject: [PATCH 03/10] :pencil2: typo --- include/fiction/algorithms/simulation/sidb/minimum_energy.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fiction/algorithms/simulation/sidb/minimum_energy.hpp b/include/fiction/algorithms/simulation/sidb/minimum_energy.hpp index 03fffee45..74c6cdfb7 100644 --- a/include/fiction/algorithms/simulation/sidb/minimum_energy.hpp +++ b/include/fiction/algorithms/simulation/sidb/minimum_energy.hpp @@ -19,7 +19,7 @@ namespace fiction * returned. * * @tparam InputIt Must meet the requirements of `LegacyInputIterator`. - * @param first Begin of the range to examime. + * @param first Begin of the range to examine. * @param last End of the range to examine. * @return Value of the minimum energy found in the input range (unit: eV), or infinity if the range is empty. */ @@ -43,7 +43,7 @@ template * `charge_distribution_surface` objects. If the range is empty, `last` is returned. * * @tparam InputIt Must meet the requirements of `LegacyInputIterator`. - * @param first Begin of the range to examime. + * @param first Begin of the range to examine. * @param last End of the range to examine. * @return Iterator to the minimum energy charge distribution found in the input range, or `last` if the range is empty. */ From 8ec3abdc635443b0beb9425261b4871468e624bd Mon Sep 17 00:00:00 2001 From: wlambooy Date: Tue, 29 Oct 2024 01:00:06 +0100 Subject: [PATCH 04/10] :sparkles: Exhaustive SiDB design can now sort on ground state isolation --- .../physical_design/design_sidb_gates.hpp | 36 +++- .../physical_design/design_sidb_gates.hpp | 187 +++++++++++++++--- 2 files changed, 195 insertions(+), 28 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/design_sidb_gates.hpp b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/design_sidb_gates.hpp index 195a73cf7..d48de5502 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/physical_design/design_sidb_gates.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/physical_design/design_sidb_gates.hpp @@ -48,7 +48,7 @@ inline void design_sidb_gates(pybind11::module& m) /** * Design approach selector type. */ - pybind11::enum_::design_sidb_gates_mode>( + py::enum_::design_sidb_gates_mode>( m, "design_sidb_gates_mode", DOC(fiction_design_sidb_gates_params_design_sidb_gates_mode)) .value("QUICKCELL", fiction::design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, @@ -60,6 +60,32 @@ inline void design_sidb_gates(pybind11::module& m) .value("RANDOM", fiction::design_sidb_gates_params::design_sidb_gates_mode::RANDOM, DOC(fiction_design_sidb_gates_params_design_sidb_gates_mode_RANDOM)); + /** + * Termination condition selector type. + */ + py::enum_::termination_condition>( + m, "termination_condition", DOC(fiction_design_sidb_gates_params_termination_condition)) + .value( + "AFTER_FIRST_SOLUTION", + fiction::design_sidb_gates_params::termination_condition::AFTER_FIRST_SOLUTION, + DOC(fiction_design_sidb_gates_params_termination_condition_AFTER_FIRST_SOLUTION)) + .value("ALL_COMBINATIONS_ENUMERATED", + fiction::design_sidb_gates_params< + fiction::offset::ucoord_t>::termination_condition::ALL_COMBINATIONS_ENUMERATED, + DOC(fiction_design_sidb_gates_params_termination_condition_ALL_COMBINATIONS_ENUMERATED)); + + /** + * Post-design processes selector type. + */ + py::enum_::post_design_mode>( + m, "post_design_mode", DOC(fiction_design_sidb_gates_params_post_design_mode)) + .value("DO_NOTHING", fiction::design_sidb_gates_params::post_design_mode::DO_NOTHING, + DOC(fiction_design_sidb_gates_params_post_design_mode_DO_NOTHING)) + .value("PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES", + fiction::design_sidb_gates_params< + fiction::offset::ucoord_t>::post_design_mode::PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES, + DOC(fiction_design_sidb_gates_params_post_design_mode_PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES)); + /** * Parameters. */ @@ -75,7 +101,13 @@ inline void design_sidb_gates(pybind11::module& m) DOC(fiction_design_sidb_gates_params_canvas)) .def_readwrite("number_of_sidbs", &fiction::design_sidb_gates_params::number_of_sidbs, - DOC(fiction_design_sidb_gates_params_number_of_sidbs)); + DOC(fiction_design_sidb_gates_params_number_of_sidbs)) + .def_readwrite("termination_cond", + &fiction::design_sidb_gates_params::termination_cond, + DOC(fiction_design_sidb_gates_params_termination_cond)) + .def_readwrite("post_design_process", + &fiction::design_sidb_gates_params::post_design_process, + DOC(fiction_design_sidb_gates_params_post_design_process)); detail::design_sidb_gates(m); detail::design_sidb_gates(m); diff --git a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp index 9eb03e1d3..ee3a25168 100644 --- a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp +++ b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp @@ -54,6 +54,24 @@ namespace fiction template struct design_sidb_gates_params { + /** + * Selector for the available design approaches. + */ + enum class design_sidb_gates_mode : uint8_t + { + /** + * Gates are designed by using *QuickCell*. + */ + QUICKCELL, + /** + * Gates are designed by using the *Automatic Exhaustive Gate Designer*. + */ + AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + /** + * Gate layouts are designed randomly. + */ + RANDOM + }; /** * Selector for the different termination conditions for the SiDB gate design process. */ @@ -69,22 +87,18 @@ struct design_sidb_gates_params ALL_COMBINATIONS_ENUMERATED }; /** - * Selector for the available design approaches. + * Selector for the available post-design processes. */ - enum class design_sidb_gates_mode : uint8_t + enum class post_design_mode : uint8_t { /** - * Gates are designed by using *QuickCell*. - */ - QUICKCELL, - /** - * Gates are designed by using the *Automatic Exhaustive Gate Designer*. + * No post-design operation is performed. */ - AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + DO_NOTHING, /** - * Gate layouts are designed randomly. + * The designed gates are sorted by how energetically isolated the ground state is from the first excited state. */ - RANDOM + PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES }; /** * Parameters for the `is_operational` function. @@ -108,6 +122,12 @@ struct design_sidb_gates_params * @note This parameter has no effect unless the gate design is exhaustive. */ termination_condition termination_cond = termination_condition::ALL_COMBINATIONS_ENUMERATED; + /** + * After the design process, the returned gates are not sorted. + * + * @note This parameter has no effect unless the gate design is exhaustive and all combinations are enumerated. + */ + post_design_mode post_design_process = post_design_mode::DO_NOTHING; }; /** @@ -151,11 +171,11 @@ class design_sidb_gates_impl * @param ps Parameters and settings for the gate designer. * @param st Statistics for the gate design process. */ - design_sidb_gates_impl(const Lyt& skeleton, const std::vector& spec, - const design_sidb_gates_params>& ps, design_sidb_gates_stats& st) : + design_sidb_gates_impl(const Lyt& skeleton, const std::vector& spec, design_sidb_gates_params> ps, + design_sidb_gates_stats& st) : skeleton_layout{skeleton}, truth_table{spec}, - params{ps}, + params{set_simulation_results_retention_accordingly(std::move(ps))}, all_sidbs_in_canvas{all_coordinates_in_spanned_area(params.canvas.first, params.canvas.second)}, stats{st}, input_bdl_wires{detect_bdl_wires(skeleton_layout, @@ -179,7 +199,8 @@ class design_sidb_gates_impl * This function adds each cell combination to the given skeleton, and determines whether the layout is operational * based on the specified parameters. The design process is parallelized to improve performance. * - * @return A vector of designed SiDB gate layouts. + * @return A vector of designed SiDB gate layouts, along with simulation results when the post-design process is set + * to `post_design_mode::PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES`. */ [[nodiscard]] std::vector run_automatic_exhaustive_gate_designer() const noexcept { @@ -188,13 +209,23 @@ class design_sidb_gates_impl auto all_combinations = determine_all_combinations_of_distributing_k_entities_on_n_positions( params.number_of_sidbs, static_cast(all_sidbs_in_canvas.size())); - std::vector designed_gate_layouts = {}; + std::vector designed_gate_layouts{}; if (all_combinations.empty()) { return designed_gate_layouts; } + std::optional>>>> + sim_results_per_input_for_each_gate_design{}; + + if (params.post_design_process == + design_sidb_gates_params>::post_design_mode::PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES) + { + sim_results_per_input_for_each_gate_design = + std::make_optional>>>>(); + } + std::unordered_set> sidbs_affected_by_defects = {}; // used to collect all SiDBs that are affected due to neutrally charged defects. @@ -211,9 +242,9 @@ class design_sidb_gates_impl std::shuffle(all_combinations.begin(), all_combinations.end(), std::default_random_engine(std::random_device{}())); - const auto add_combination_to_layout_and_check_operation = [this, &mutex_to_protect_designed_gate_layouts, - &designed_gate_layouts, - &solution_found](const auto& combination) noexcept + const auto add_combination_to_layout_and_check_operation = + [this, &mutex_to_protect_designed_gate_layouts, &designed_gate_layouts, + &sim_results_per_input_for_each_gate_design, &solution_found](const auto& combination) noexcept { // canvas SiDBs are added to the skeleton const auto layout_with_added_cells = skeleton_layout_with_canvas_sidbs(combination); @@ -228,13 +259,19 @@ class design_sidb_gates_impl // ensure only one designed gate is returned when AFTER_FIRST_SOLUTION is the termination condition if (params.termination_cond == - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION && - solution_found) + design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION && + solution_found) { return; } - designed_gate_layouts.push_back(layout_with_added_cells); + designed_gate_layouts.emplace_back(layout_with_added_cells); + + if (sim_results_per_input_for_each_gate_design.has_value()) + { + sim_results_per_input_for_each_gate_design.value().emplace_back( + std::move(aux_stats.simulation_results.value())); + } } solution_found = true; @@ -281,6 +318,14 @@ class design_sidb_gates_impl } } + if (params.post_design_process == + design_sidb_gates_params>::post_design_mode::PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES && + designed_gate_layouts.size() > 1) + { + sort_designed_gate_layouts_by_ground_state_isolation( + designed_gate_layouts, std::move(sim_results_per_input_for_each_gate_design.value())); + } + return designed_gate_layouts; } /** @@ -328,7 +373,7 @@ class design_sidb_gates_impl } }); } - if (const auto [status, sim_calls] = + if (const auto [status, aux_stats] = is_operational(result_lyt, truth_table, params.operational_params, std::optional{input_bdl_wires}, std::optional{output_bdl_wires}); status == operational_status::OPERATIONAL) @@ -405,7 +450,7 @@ class design_sidb_gates_impl { return; } - if (const auto [status, sim_calls] = + if (const auto [status, aux_stats] = is_operational(candidate, truth_table, params.operational_params, std::optional{input_bdl_wires}, std::optional{output_bdl_wires}); status == operational_status::OPERATIONAL) @@ -465,7 +510,7 @@ class design_sidb_gates_impl /** * Parameters for the *SiDB Gate Designer*. */ - const design_sidb_gates_params>& params; + const design_sidb_gates_params> params; /** * All cells within the canvas. */ @@ -758,8 +803,7 @@ class design_sidb_gates_impl while (cds_canvas.get_charge_index_and_base().first <= cds_canvas.get_max_charge_index()) { cds_canvas.foreach_cell( - [&](const auto& c) - { + [&](const auto& c) { cds_layout.assign_charge_state(c, cds_canvas.get_charge_state(c), charge_index_mode::KEEP_CHARGE_INDEX); }); @@ -1060,6 +1104,97 @@ class design_sidb_gates_impl return lyt; } + + /** + * This function makes sure that the underlying parameters for `is_operational` allow simulation results to be used + * when the given parameter set indicates the use for it. + * + * @params Parameters and settings for the gate designer. + * @return Parameters and settings for the gate designer for which the simulation results retention of the + * underlying parameter for operational status assessment is set accordingly. + */ + [[nodiscard]] static design_sidb_gates_params> + set_simulation_results_retention_accordingly(const design_sidb_gates_params>& params) noexcept + { + design_sidb_gates_params> ps{params}; + + if (params.post_design_process == design_sidb_gates_params>::post_design_mode::DO_NOTHING) + { + return ps; + } + + ps.operational_params.simulation_results_retention = + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS; + + return ps; + } + + /** + * Performs a sorting operation on the designed gate layouts, preferring those for which the energetic gap between + * the ground state and the first excited state is larger. For each designed gate layout, the minimum energetic gap + * is taken over each input. + * + * @param designed_gate_layouts A vector of designed gate layouts to sort in place. + * @param sim_results_per_input_for_each_gate_design The simulation results for each input of each designed gate + * layout. + */ + void sort_designed_gate_layouts_by_ground_state_isolation( + std::vector& designed_gate_layouts, std::vector>>> + sim_results_per_input_for_each_gate_design) const noexcept + { + // pair the two input vectors + std::vector>>>> pairs{}; + pairs.reserve(designed_gate_layouts.size()); + + for (auto i = 0; i < designed_gate_layouts.size(); ++i) + { + pairs.emplace_back(std::move(designed_gate_layouts.at(i)), + std::move(sim_results_per_input_for_each_gate_design.at(i))); + } + + // clear the designed_gate_layouts vector so that we may reenter the elements in order later + designed_gate_layouts.clear(); + + // sort all individual simulation results by system energy + for (auto& pair : pairs) + { + for (std::vector>& sim_res : pair.second) + { + std::sort(sim_res.begin(), sim_res.end(), [](const auto& cds1, const auto& cds2) noexcept + { return cds1.get_system_energy() < cds2.get_system_energy(); }); + } + } + + const auto get_ground_state_isolation = + [&](const std::vector>& sim_res) noexcept + { + return sim_res.size() == 1 ? std::numeric_limits::infinity() : + sim_res.at(1).get_system_energy() - sim_res.at(0).get_system_energy(); + }; + + const auto minimum_ground_state_isolation_for_all_inputs = + [&get_ground_state_isolation]( + const std::vector>>& res_per_input) noexcept + { + return std::min_element(res_per_input.cbegin(), res_per_input.cend(), + [&get_ground_state_isolation](const auto& lhs, const auto& rhs) noexcept + { return get_ground_state_isolation(lhs) < get_ground_state_isolation(rhs); }); + }; + + // sort the pairs by minimum ground state isolation for each input + std::sort(pairs.begin(), pairs.end(), + [&minimum_ground_state_isolation_for_all_inputs](const auto& lhs, const auto& rhs) noexcept + { + return minimum_ground_state_isolation_for_all_inputs(lhs.second) < + minimum_ground_state_isolation_for_all_inputs(rhs.second); + }); + + // put the designed gate layouts back in the sorted order + for (auto& pair : pairs) + { + designed_gate_layouts.emplace_back(pair.first); + } + } }; } // namespace detail From d914aa04e0c7b96d1b4f820100ff6fde62c9c1f2 Mon Sep 17 00:00:00 2001 From: wlambooy Date: Wed, 30 Oct 2024 13:58:13 +0100 Subject: [PATCH 05/10] :white_check_mark: Removed redundant test --- .../physical_design/design_sidb_gates.cpp | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/test/algorithms/physical_design/design_sidb_gates.cpp b/test/algorithms/physical_design/design_sidb_gates.cpp index 39f3f41c7..f22c65059 100644 --- a/test/algorithms/physical_design/design_sidb_gates.cpp +++ b/test/algorithms/physical_design/design_sidb_gates.cpp @@ -118,19 +118,6 @@ TEST_CASE("Use SiQAD XNOR skeleton and generate SiQAD XNOR gate, exhaustive", "[ CHECK(found_gate_layouts.size() == 4); } - SECTION("Four cells in canvas, design one gate with one SiDB in the canvas (terminate on first found)") - { - const auto params = design_sidb_gates_params>{ - is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, - design_sidb_gates_params>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, - {{10, 4, 0}, {13, 4, 0}}, - 1, - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION}; - - const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_xnor_tt()}, params); - - CHECK(found_gate_layouts.size() == 1); - } SECTION("Four cells in canvas, design process is terminated after first solution is found (one SiDB in the " "canvas), QuickExact") { From 32db7bc2655a5f4a74888c1e9ed872672feec517 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 30 Oct 2024 12:59:37 +0000 Subject: [PATCH 06/10] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../pyfiction/pybind11_mkdoc_docstrings.hpp | 91 +++++++++++++++++-- 1 file changed, 81 insertions(+), 10 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index f7c9ee4ee..b25a1df7c 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -3816,6 +3816,20 @@ static const char *__doc_fiction_design_sidb_gates_params_number_of_sidbs = R"do static const char *__doc_fiction_design_sidb_gates_params_operational_params = R"doc(Parameters for the `is_operational` function.)doc"; +static const char *__doc_fiction_design_sidb_gates_params_post_design_mode = R"doc(Selector for the available post-design processes.)doc"; + +static const char *__doc_fiction_design_sidb_gates_params_post_design_mode_DO_NOTHING = R"doc(No post-design operation is performed.)doc"; + +static const char *__doc_fiction_design_sidb_gates_params_post_design_mode_PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES = +R"doc(The designed gates are sorted by how energetically isolated the ground +state is from the first excited state.)doc"; + +static const char *__doc_fiction_design_sidb_gates_params_post_design_process = +R"doc(After the design process, the returned gates are not sorted. + +@note This parameter has no effect unless the gate design is +exhaustive and all combinations are enumerated.)doc"; + static const char *__doc_fiction_design_sidb_gates_params_termination_cond = R"doc(The design process is terminated after a valid SiDB gate design is found. @@ -4803,6 +4817,19 @@ Parameter ``layout``: Parameter ``input_index``: The index representing the current input pattern.)doc"; +static const char *__doc_fiction_detail_design_sidb_gates_impl_set_simulation_results_retention_accordingly = +R"doc(This function makes sure that the underlying parameters for +`is_operational` allow simulation results to be used when the given +parameter set indicates the use for it. + +Parameter ``Parameters``: + and settings for the gate designer. + +Returns: + Parameters and settings for the gate designer for which the + simulation results retention of the underlying parameter for + operational status assessment is set accordingly.)doc"; + static const char *__doc_fiction_detail_design_sidb_gates_impl_skeleton_layout = R"doc(The skeleton layout serves as a starting layout to which SiDBs are added to create unique SiDB layouts and, if possible, working gates. @@ -4819,6 +4846,19 @@ Parameter ``cell_indices``: A copy of the original layout (`skeleton_layout`) with SiDB cells added at specified indices.)doc"; +static const char *__doc_fiction_detail_design_sidb_gates_impl_sort_designed_gate_layouts_by_ground_state_isolation = +R"doc(Performs a sorting operation on the designed gate layouts, preferring +those for which the energetic gap between the ground state and the +first excited state is larger. For each designed gate layout, the +minimum energetic gap is taken over each input. + +Parameter ``designed_gate_layouts``: + A vector of designed gate layouts to sort in place. + +Parameter ``sim_results_per_input_for_each_gate_design``: + The simulation results for each input of each designed gate + layout.)doc"; + static const char *__doc_fiction_detail_design_sidb_gates_impl_stats = R"doc(The statistics of the gate design.)doc"; static const char *__doc_fiction_detail_design_sidb_gates_impl_truth_table = R"doc(Truth table of the given gate.)doc"; @@ -6823,11 +6863,12 @@ Parameter ``bdl``: Returns: `true` if `0` is encoded, `false` otherwise.)doc"; -static const char *__doc_fiction_detail_is_operational_impl_get_number_of_simulator_invocations = -R"doc(Returns the total number of simulator invocations. +static const char *__doc_fiction_detail_is_operational_impl_get_operational_status_assessment_stats = +R"doc(Returns auxiliary results from the operational status assessment, +including the number of simulator invocations. Returns: - The number of simulator invocations.)doc"; + Auxiliary results from the operational status assessment.)doc"; static const char *__doc_fiction_detail_is_operational_impl_input_bdl_wires = R"doc(Input BDL wires.)doc"; @@ -6897,7 +6938,9 @@ the gate layout and parameters provided during initialization. The operational status of the gate layout (either `OPERATIONAL` or `NON_OPERATIONAL`).)doc"; -static const char *__doc_fiction_detail_is_operational_impl_simulator_invocations = R"doc(Number of simulator invocations.)doc"; +static const char *__doc_fiction_detail_is_operational_impl_stats = +R"doc(Auxiliary results from the operational status assessment, including +the number of simulator invocations.)doc"; static const char *__doc_fiction_detail_is_operational_impl_truth_table = R"doc(The specification of the layout.)doc"; @@ -13610,16 +13653,16 @@ Parameter ``input_bdl_wire_direction``: Returns: A pair containing the operational status of the gate layout - (either `OPERATIONAL` or `NON_OPERATIONAL`) and the number of - input combinations tested.)doc"; + (either `OPERATIONAL` or `NON_OPERATIONAL`) along with auxiliary + statistics.)doc"; static const char *__doc_fiction_is_operational_params = R"doc(Parameters for the `is_operational` algorithm.)doc"; static const char *__doc_fiction_is_operational_params_input_bdl_iterator_params = R"doc(Parameters for the BDL input iterator.)doc"; static const char *__doc_fiction_is_operational_params_op_condition = -R"doc(Condition which is used to decide if a layout is `operational` or -`non-operational`.)doc"; +R"doc(Condition that is used to decide if a layout is `operational` or `non- +operational`.)doc"; static const char *__doc_fiction_is_operational_params_sim_engine = R"doc(The simulation engine to be used for the operational domain @@ -13629,6 +13672,20 @@ static const char *__doc_fiction_is_operational_params_simulation_parameters = R"doc(The simulation parameters for the physical simulation of the ground state.)doc"; +static const char *__doc_fiction_is_operational_params_simulation_results_mode = R"doc(Selector for the different ways to handle obtained simulation results.)doc"; + +static const char *__doc_fiction_is_operational_params_simulation_results_mode_DISCARD_SIMULATION_RESULTS = +R"doc(The simulation results are discarded after the operational status was +assessed.)doc"; + +static const char *__doc_fiction_is_operational_params_simulation_results_mode_KEEP_SIMULATION_RESULTS = +R"doc(The simulation results for each input pattern are returned for +operational gates.)doc"; + +static const char *__doc_fiction_is_operational_params_simulation_results_retention = +R"doc(Simulation results that are used to certify the status `OPERATIONAL` +are not kept by default.)doc"; + static const char *__doc_fiction_is_positively_charged_defect = R"doc(Checks whether the given defect has a positive charge value assigned to it. This function is irrespective of the associated defect type. @@ -13877,7 +13934,7 @@ Template parameter ``InputIt``: Must meet the requirements of `LegacyInputIterator`. Parameter ``first``: - Begin of the range to examime. + Begin of the range to examine. Parameter ``last``: End of the range to examine. @@ -13895,7 +13952,7 @@ Template parameter ``InputIt``: Must meet the requirements of `LegacyInputIterator`. Parameter ``first``: - Begin of the range to examime. + Begin of the range to examine. Parameter ``last``: End of the range to examine. @@ -14717,6 +14774,20 @@ static const char *__doc_fiction_operational_status_NON_OPERATIONAL = R"doc(The static const char *__doc_fiction_operational_status_OPERATIONAL = R"doc(The layout is operational.)doc"; +static const char *__doc_fiction_operational_status_assessment_stats = +R"doc(This struct is used to collect auxiliary results from the operational +status assessment. + +Template parameter ``SiDB``: + cell-level layout type.)doc"; + +static const char *__doc_fiction_operational_status_assessment_stats_number_of_simulator_invocations = R"doc(The number of input combinations tested.)doc"; + +static const char *__doc_fiction_operational_status_assessment_stats_simulation_results = +R"doc(The charge distributions obtained for each input combination tested, +sorted by the binary representation of the respectively associated +input combinations.)doc"; + static const char *__doc_fiction_orthogonal = R"doc(A scalable placement & routing approach based on orthogonal graph drawing as originally proposed in \"Scalable Design for Field-coupled From 1a4c2d0b5288b8284c69936d836040688c972bc2 Mon Sep 17 00:00:00 2001 From: wlambooy Date: Wed, 30 Oct 2024 14:45:34 +0100 Subject: [PATCH 07/10] :sparkles: Added average ground state isolation as tie-breaker --- .../physical_design/design_sidb_gates.hpp | 50 +++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp index c1da6026c..4d76b513f 100644 --- a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp +++ b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp @@ -793,8 +793,7 @@ class design_sidb_gates_impl while (cds_canvas.get_charge_index_and_base().first <= cds_canvas.get_max_charge_index()) { cds_canvas.foreach_cell( - [&](const auto& c) - { + [&](const auto& c) { cds_layout.assign_charge_state(c, cds_canvas.get_charge_state(c), charge_index_mode::KEEP_CHARGE_INDEX); }); @@ -1121,9 +1120,9 @@ class design_sidb_gates_impl } /** - * Performs a sorting operation on the designed gate layouts, preferring those for which the energetic gap between - * the ground state and the first excited state is larger. For each designed gate layout, the minimum energetic gap - * is taken over each input. + * Performs a sorting operation on the designed gate layouts, putting those in front for which the energetic gap + * between the ground state and the first excited state is larger. For each designed gate layout, the minimum + * energetic gap is taken over each input. * * @param designed_gate_layouts A vector of designed gate layouts to sort in place. * @param sim_results_per_input_for_each_gate_design The simulation results for each input of each designed gate @@ -1160,7 +1159,7 @@ class design_sidb_gates_impl [&](const std::vector>& sim_res) noexcept { return sim_res.size() == 1 ? std::numeric_limits::infinity() : - sim_res.at(1).get_system_energy() - sim_res.at(0).get_system_energy(); + sim_res.at(1).get_system_energy() - sim_res.at(0).get_system_energy(); }; const auto minimum_ground_state_isolation_for_all_inputs = @@ -1172,12 +1171,45 @@ class design_sidb_gates_impl { return get_ground_state_isolation(lhs) < get_ground_state_isolation(rhs); }); }; + const auto average_ground_state_isolation_for_all_inputs = + [&get_ground_state_isolation]( + const std::vector>>& res_per_input) noexcept + { + uint64_t count = 0; + + double accumulated_ground_state_isolation = 0.0; + + for (const auto& sim_res : res_per_input) + { + if (sim_res.size() == 1) + { + continue; + } + + accumulated_ground_state_isolation += get_ground_state_isolation(sim_res); + + ++count; + } + + return accumulated_ground_state_isolation / static_cast(count); + }; + // sort the pairs by minimum ground state isolation for each input std::sort(pairs.begin(), pairs.end(), - [&minimum_ground_state_isolation_for_all_inputs](const auto& lhs, const auto& rhs) noexcept + [&minimum_ground_state_isolation_for_all_inputs, + &average_ground_state_isolation_for_all_inputs](const auto& lhs, const auto& rhs) noexcept { - return minimum_ground_state_isolation_for_all_inputs(lhs.second) < - minimum_ground_state_isolation_for_all_inputs(rhs.second); + const double diff = minimum_ground_state_isolation_for_all_inputs(lhs.second) - + minimum_ground_state_isolation_for_all_inputs(rhs.second); + + // when minima are equal, take the average + if (std::abs(diff) < std::numeric_limits::epsilon()) + { + return average_ground_state_isolation_for_all_inputs(lhs.second) > + average_ground_state_isolation_for_all_inputs(rhs.second); + } + + return diff > 0.0; }); // put the designed gate layouts back in the sorted order From 92045d6dc788abb37e628e548144db72c77a581d Mon Sep 17 00:00:00 2001 From: wlambooy Date: Wed, 30 Oct 2024 14:45:48 +0100 Subject: [PATCH 08/10] :white_check_mark: Added test --- .../physical_design/design_sidb_gates.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/algorithms/physical_design/design_sidb_gates.cpp b/test/algorithms/physical_design/design_sidb_gates.cpp index f22c65059..26810fb17 100644 --- a/test/algorithms/physical_design/design_sidb_gates.cpp +++ b/test/algorithms/physical_design/design_sidb_gates.cpp @@ -158,6 +158,25 @@ TEST_CASE("Use SiQAD XNOR skeleton and generate SiQAD XNOR gate, exhaustive", "[ CHECK(mockturtle::to_seconds(stats.time_total) > 0.0); CHECK(stats.sim_engine == sidb_simulation_engine::QUICKSIM); } + SECTION("Four cells in canvas, design all gates with one SiDB in the canvas and sort by ground state isolation") + { + const auto params = design_sidb_gates_params>{ + is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, + design_sidb_gates_params>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + {{10, 4, 0}, {13, 4, 0}}, + 1, + design_sidb_gates_params>::termination_condition::ALL_COMBINATIONS_ENUMERATED, + design_sidb_gates_params< + cell>::post_design_mode::PREFER_ENERGETICALLY_ISOLATED_GROUND_STATES}; + + const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_xnor_tt()}, params); + + REQUIRE(found_gate_layouts.size() == 4); + CHECK(found_gate_layouts[0].get_cell_type({11, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[1].get_cell_type({13, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[2].get_cell_type({10, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[3].get_cell_type({12, 4, 0}) == siqad_layout::technology::LOGIC); + } } TEST_CASE("Use SiQAD's AND gate skeleton to generate all possible AND gates", "[design-sidb-gates]") From 1a8cecd7dea57741879331635db93df42c57778e Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 30 Oct 2024 13:46:37 +0000 Subject: [PATCH 09/10] :memo: Update pyfiction docstrings Signed-off-by: GitHub Actions --- .../include/pyfiction/pybind11_mkdoc_docstrings.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index b25a1df7c..fe4c395bd 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -4847,10 +4847,10 @@ Parameter ``cell_indices``: added at specified indices.)doc"; static const char *__doc_fiction_detail_design_sidb_gates_impl_sort_designed_gate_layouts_by_ground_state_isolation = -R"doc(Performs a sorting operation on the designed gate layouts, preferring -those for which the energetic gap between the ground state and the -first excited state is larger. For each designed gate layout, the -minimum energetic gap is taken over each input. +R"doc(Performs a sorting operation on the designed gate layouts, putting +those in front for which the energetic gap between the ground state +and the first excited state is larger. For each designed gate layout, +the minimum energetic gap is taken over each input. Parameter ``designed_gate_layouts``: A vector of designed gate layouts to sort in place. From 19ec6a7dcb86d3e4b9e982b8d5b1b520cf62a6c0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 13:53:21 +0000 Subject: [PATCH 10/10] =?UTF-8?q?=F0=9F=8E=A8=20Incorporated=20pre-commit?= =?UTF-8?q?=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../algorithms/physical_design/design_sidb_gates.hpp | 3 ++- test/algorithms/physical_design/design_sidb_gates.cpp | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp index 4d76b513f..f2e32ee08 100644 --- a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp +++ b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp @@ -793,7 +793,8 @@ class design_sidb_gates_impl while (cds_canvas.get_charge_index_and_base().first <= cds_canvas.get_max_charge_index()) { cds_canvas.foreach_cell( - [&](const auto& c) { + [&](const auto& c) + { cds_layout.assign_charge_state(c, cds_canvas.get_charge_state(c), charge_index_mode::KEEP_CHARGE_INDEX); }); diff --git a/test/algorithms/physical_design/design_sidb_gates.cpp b/test/algorithms/physical_design/design_sidb_gates.cpp index 26810fb17..557e0e87b 100644 --- a/test/algorithms/physical_design/design_sidb_gates.cpp +++ b/test/algorithms/physical_design/design_sidb_gates.cpp @@ -385,10 +385,8 @@ TEST_CASE("Design AND Bestagon shaped gate", "[design-sidb-gates]") CHECK(found_gate_layouts_quickcell.front().num_defects() == 1); CHECK(found_gate_layouts_quickcell.front().num_cells() == lyt.num_cells() + 2); - found_gate_layouts_quickcell.front().foreach_cell( - [](const auto& cell) { - CHECK(cell != siqad::coord_t{16, 10, 0}); - }); + found_gate_layouts_quickcell.front().foreach_cell([](const auto& cell) + { CHECK(cell != siqad::coord_t{16, 10, 0}); }); } }