diff --git a/bindings/mnt/pyfiction/__init__.py b/bindings/mnt/pyfiction/__init__.py index d6cc9b8cde..84e55b95c2 100644 --- a/bindings/mnt/pyfiction/__init__.py +++ b/bindings/mnt/pyfiction/__init__.py @@ -116,8 +116,12 @@ defect_extent, dependent_cell_mode, design_sidb_gates, - design_sidb_gates_mode, - design_sidb_gates_params, + design_sidb_gates_mode_100, + design_sidb_gates_mode_111, + design_sidb_gates_params_100, + design_sidb_gates_params_111, + design_sidb_gates_params_termination_condition_100, + design_sidb_gates_params_termination_condition_111, detect_bdl_pairs, detect_bdl_pairs_params, detect_bdl_wires_100, @@ -190,6 +194,7 @@ is_neutrally_charged_defect, is_operational, is_operational_params, + is_operational_params_termination_condition, is_positively_charged_defect, kink_induced_non_operational_input_patterns, manhattan_distance, @@ -207,7 +212,12 @@ offset_coordinate, offset_volume, operational_analysis_strategy, - operational_condition, + operational_assessment_100, + operational_assessment_111, + operational_assessment_for_input_100, + operational_assessment_for_input_111, + operational_condition_kinks, + operational_condition_positive_charges, operational_domain, operational_domain_contour_tracing, operational_domain_flood_fill, @@ -279,6 +289,7 @@ sign_to_charge_state, ### logic simulate, + simulation_results_mode, siqad_area, siqad_coordinate, siqad_volume, @@ -432,8 +443,12 @@ "defect_extent", "dependent_cell_mode", "design_sidb_gates", - "design_sidb_gates_mode", - "design_sidb_gates_params", + "design_sidb_gates_mode_100", + "design_sidb_gates_mode_111", + "design_sidb_gates_params_100", + "design_sidb_gates_params_111", + "design_sidb_gates_params_termination_condition_100", + "design_sidb_gates_params_termination_condition_111", "detect_bdl_pairs", "detect_bdl_pairs_params", "detect_bdl_wires_100", @@ -506,6 +521,7 @@ "is_neutrally_charged_defect", "is_operational", "is_operational_params", + "is_operational_params_termination_condition", "is_positively_charged_defect", "kink_induced_non_operational_input_patterns", "manhattan_distance", @@ -523,7 +539,12 @@ "offset_coordinate", "offset_volume", "operational_analysis_strategy", - "operational_condition", + "operational_assessment_100", + "operational_assessment_111", + "operational_assessment_for_input_100", + "operational_assessment_for_input_111", + "operational_condition_kinks", + "operational_condition_positive_charges", "operational_domain", "operational_domain_contour_tracing", "operational_domain_flood_fill", @@ -595,6 +616,7 @@ "sign_to_charge_state", ### logic "simulate", + "simulation_results_mode", "siqad_area", "siqad_coordinate", "siqad_volume", diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/design_sidb_gates.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/design_sidb_gates.hpp index 3f41dbfa9b..ec0df96a8f 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/design_sidb_gates.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/design_sidb_gates.hpp @@ -10,8 +10,11 @@ #include #include +#include #include +#include + namespace pyfiction { @@ -24,57 +27,101 @@ void design_sidb_gates(pybind11::module& m) namespace py = pybind11; m.def("design_sidb_gates", &fiction::design_sidb_gates, py::arg("skeleton"), py::arg("spec"), - py::arg("params") = fiction::design_sidb_gates_params>{}, py::arg("stats") = nullptr, + py::arg("params") = fiction::design_sidb_gates_params{}, py::arg("stats") = nullptr, DOC(fiction_design_sidb_gates)); } -} // namespace detail - -inline void design_sidb_gates(pybind11::module& m) +template +void design_sidb_gates_params(pybind11::module& m, const std::string& lattice = "") { namespace py = pybind11; - py::class_(m, "design_sidb_gates_stats", DOC(fiction_design_sidb_gates_stats)) - .def(py::init<>()) - .def("__repr__", - [](const fiction::design_sidb_gates_stats& stats) - { - std::stringstream stream{}; - stats.report(stream); - return stream.str(); - }); + // TODO: it seems unnecessary to define these selector types for each lattice /** * Design approach selector type. */ - pybind11::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, + py::enum_::design_sidb_gates_mode>( + m, fmt::format("design_sidb_gates_mode{}", lattice).c_str(), + DOC(fiction_design_sidb_gates_params_design_sidb_gates_mode)) + .value("QUICKCELL", fiction::design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, DOC(fiction_design_sidb_gates_params_design_sidb_gates_mode_QUICKCELL)) - .value("AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER", - fiction::design_sidb_gates_params< - fiction::offset::ucoord_t>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + .value("EXHAUSTIVE_GATE_DESIGNER", + fiction::design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, DOC(fiction_design_sidb_gates_params_design_sidb_gates_mode_QUICKCELL)) - .value("RANDOM", fiction::design_sidb_gates_params::design_sidb_gates_mode::RANDOM, + .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, fmt::format("design_sidb_gates_params_termination_condition{}", lattice).c_str(), + 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::termination_condition::ALL_COMBINATIONS_ENUMERATED, + DOC(fiction_design_sidb_gates_params_termination_condition_ALL_COMBINATIONS_ENUMERATED)); + /** * Parameters. */ - py::class_>(m, "design_sidb_gates_params", - DOC(fiction_design_sidb_gates_params)) + py::class_>(m, fmt::format("design_sidb_gates_params{}", lattice).c_str(), + DOC(fiction_design_sidb_gates_params)) .def(py::init<>()) - .def_readwrite("operational_params", - &fiction::design_sidb_gates_params::operational_params, + .def_readwrite("operational_params", &fiction::design_sidb_gates_params::operational_params, DOC(fiction_design_sidb_gates_params_operational_params)) - .def_readwrite("design_mode", &fiction::design_sidb_gates_params::design_mode, + .def_readwrite("design_mode", &fiction::design_sidb_gates_params::design_mode, DOC(fiction_design_sidb_gates_params_design_mode)) - .def_readwrite("canvas", &fiction::design_sidb_gates_params::canvas, - 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)); + .def_readwrite("canvas", &fiction::design_sidb_gates_params::canvas, + DOC(fiction_design_sidb_gates_params_canvas_overridden)) + .def_readwrite("number_of_sidbs", &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)); +} + +} // namespace detail + +inline void design_sidb_gates(pybind11::module& m) +{ + namespace py = pybind11; + + // stats are defined to be read-only + + py::class_(m, "design_sidb_gates_stats", DOC(fiction_design_sidb_gates_stats)) + .def(py::init<>()) + .def_readonly("time_total", &fiction::design_sidb_gates_stats::time_total, + DOC(fiction_design_sidb_gates_stats_time_total_overridden)) + .def_readonly("pruning_total", &fiction::design_sidb_gates_stats::pruning_total, + DOC(fiction_design_sidb_gates_stats_pruning_total_overridden)) + .def_readonly("sim_engine", &fiction::design_sidb_gates_stats::sim_engine, + DOC(fiction_design_sidb_gates_stats_sim_engine)) + .def_readonly("number_of_layouts", &fiction::design_sidb_gates_stats::number_of_layouts, + DOC(fiction_design_sidb_gates_stats_number_of_layouts)) + .def_readonly("number_of_layouts_after_first_pruning", + &fiction::design_sidb_gates_stats::number_of_layouts_after_first_pruning, + DOC(fiction_design_sidb_gates_stats_number_of_layouts_after_first_pruning)) + .def_readonly("number_of_layouts_after_second_pruning", + &fiction::design_sidb_gates_stats::number_of_layouts_after_second_pruning, + DOC(fiction_design_sidb_gates_stats_number_of_layouts_after_second_pruning)) + .def_readonly("number_of_layouts_after_third_pruning", + &fiction::design_sidb_gates_stats::number_of_layouts_after_third_pruning, + DOC(fiction_design_sidb_gates_stats_number_of_layouts_after_third_pruning)) + .def("__repr__", + [](const fiction::design_sidb_gates_stats& stats) + { + std::stringstream stream{}; + stats.report(stream); + return stream.str(); + }); + + detail::design_sidb_gates_params(m, "_100"); + detail::design_sidb_gates_params(m, "_111"); detail::design_sidb_gates(m); detail::design_sidb_gates(m); diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/exact.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/exact.hpp index 28ff8f24df..0f10615663 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/exact.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/exact.hpp @@ -26,7 +26,6 @@ namespace pyfiction inline void exact(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::enum_(m, "technology_constraints", DOC(fiction_technology_constraints)) .value("NONE", fiction::technology_constraints::NONE, DOC(fiction_technology_constraints_NONE)) diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/graph_oriented_layout_design.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/graph_oriented_layout_design.hpp index ceca6f7036..3a7e4a50d1 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/graph_oriented_layout_design.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/graph_oriented_layout_design.hpp @@ -25,7 +25,6 @@ namespace pyfiction inline void graph_oriented_layout_design(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::enum_( m, "gold_effort_mode", DOC(fiction_graph_oriented_layout_design_params_effort_mode)) diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/orthogonal.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/orthogonal.hpp index 4fac19f3c5..da80a40a45 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/orthogonal.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/orthogonal.hpp @@ -24,7 +24,6 @@ namespace pyfiction inline void orthogonal(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, "orthogonal_params", DOC(fiction_orthogonal_physical_design_params)) diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp index fb892f8529..fe52c30c08 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/post_layout_optimization.hpp @@ -21,7 +21,6 @@ namespace pyfiction inline void post_layout_optimization(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, "post_layout_optimization_params", DOC(fiction_post_layout_optimization_params)) diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/wiring_reduction.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/wiring_reduction.hpp index 3496a91843..fb2ab374eb 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/wiring_reduction.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/physical_design/wiring_reduction.hpp @@ -21,7 +21,6 @@ namespace pyfiction inline void wiring_reduction(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, "wiring_reduction_params", DOC(fiction_wiring_reduction_params)) .def(py::init<>()) diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp index 1113de6ee2..d043c3c91f 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp @@ -11,10 +11,12 @@ #include #include +#include #include #include #include +#include #include namespace pyfiction @@ -83,6 +85,36 @@ void is_operational(pybind11::module& m) py::arg("canvas_lyt") = std::nullopt, DOC(fiction_is_kink_induced_non_operational_2)); } +template +void operational_assessment(pybind11::module& m, const std::string& lattice = "") +{ + namespace py = pybind11; + + // operational assessments are defined to be read-only + + py::class_::operational_assessment_for_input>( + m, fmt::format("operational_assessment_for_input{}", lattice).c_str(), + DOC(fiction_operational_assessment_operational_assessment_for_input)) + .def(py::init(), py::arg(" op_status"), + DOC(fiction_operational_assessment_operational_assessment_for_input_operational_assessment_for_input)) + .def_readonly("status", &fiction::operational_assessment::operational_assessment_for_input::status, + DOC(fiction_operational_assessment_operational_assessment_for_input_status)) + .def_readonly("simulation_results", + &fiction::operational_assessment::operational_assessment_for_input::simulation_results, + DOC(fiction_operational_assessment_operational_assessment_for_input_simulation_results)); + + py::class_>(m, fmt::format("operational_assessment{}", lattice).c_str(), + DOC(fiction_operational_assessment)) + .def(py::init(), py::arg("op_status"), + DOC(fiction_operational_assessment_operational_assessment)) + .def_readonly("status", &fiction::operational_assessment::status, + DOC(fiction_operational_assessment_status)) + .def_readonly("assessment_per_input", &fiction::operational_assessment::assessment_per_input, + DOC(fiction_operational_assessment_assessment_per_input)) + .def_readonly("simulator_invocations", &fiction::operational_assessment::simulator_invocations, + DOC(fiction_operational_assessment_simulator_invocations)); +} + } // namespace detail inline void is_operational(pybind11::module& m) @@ -94,12 +126,22 @@ inline void is_operational(pybind11::module& m) .value("NON_OPERATIONAL", fiction::operational_status::NON_OPERATIONAL, DOC(fiction_operational_status_NON_OPERATIONAL)); - py::enum_( - m, "operational_condition", DOC(fiction_is_operational_params_operational_condition)) - .value("TOLERATE_KINKS", fiction::is_operational_params::operational_condition::TOLERATE_KINKS, - DOC(fiction_is_operational_params_operational_condition_TOLERATE_KINKS)) - .value("REJECT_KINKS", fiction::is_operational_params::operational_condition::REJECT_KINKS, - DOC(fiction_is_operational_params_operational_condition_REJECT_KINKS)); + py::enum_( + m, "operational_condition_kinks", DOC(fiction_is_operational_params_operational_condition_kinks)) + .value("TOLERATE_KINKS", fiction::is_operational_params::operational_condition_kinks::TOLERATE_KINKS, + DOC(fiction_is_operational_params_operational_condition_kinks_TOLERATE_KINKS)) + .value("REJECT_KINKS", fiction::is_operational_params::operational_condition_kinks::REJECT_KINKS, + DOC(fiction_is_operational_params_operational_condition_kinks_REJECT_KINKS)); + + py::enum_( + m, "operational_condition_positive_charges", + DOC(fiction_is_operational_params_operational_condition_positive_charges)) + .value("REJECT_POSITIVE_CHARGES", + fiction::is_operational_params::operational_condition_positive_charges::REJECT_POSITIVE_CHARGES, + DOC(fiction_is_operational_params_operational_condition_positive_charges_REJECT_POSITIVE_CHARGES)) + .value("TOLERATE_POSITIVE_CHARGES", + fiction::is_operational_params::operational_condition_positive_charges::TOLERATE_POSITIVE_CHARGES, + DOC(fiction_is_operational_params_operational_condition_positive_charges_TOLERATE_POSITIVE_CHARGES)); py::enum_( m, "operational_analysis_strategy", DOC(fiction_is_operational_params_operational_analysis_strategy)) @@ -111,6 +153,24 @@ inline void is_operational(pybind11::module& m) fiction::is_operational_params::operational_analysis_strategy::FILTER_THEN_SIMULATION, DOC(fiction_is_operational_params_operational_analysis_strategy_FILTER_THEN_SIMULATION)); + py::enum_( + m, "is_operational_params_termination_condition", DOC(fiction_is_operational_params_termination_condition)) + .value("ON_FIRST_NON_OPERATIONAL", + fiction::is_operational_params::termination_condition::ON_FIRST_NON_OPERATIONAL, + DOC(fiction_is_operational_params_termination_condition_ON_FIRST_NON_OPERATIONAL)) + .value("ALL_INPUT_COMBINATIONS_ASSESSED", + fiction::is_operational_params::termination_condition::ALL_INPUT_COMBINATIONS_ASSESSED, + DOC(fiction_is_operational_params_termination_condition_ALL_INPUT_COMBINATIONS_ASSESSED)); + + 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, @@ -119,13 +179,22 @@ inline void is_operational(pybind11::module& m) DOC(fiction_is_operational_params_sim_engine)) .def_readwrite("input_bdl_iterator_params", &fiction::is_operational_params::input_bdl_iterator_params, DOC(fiction_is_operational_params_input_bdl_iterator_params)) - .def_readwrite("op_condition", &fiction::is_operational_params::op_condition, - DOC(fiction_is_operational_params_op_condition)) + .def_readwrite("op_condition_kinks", &fiction::is_operational_params::op_condition_kinks, + DOC(fiction_is_operational_params_op_condition_kinks)) + .def_readwrite("op_condition_positive_charges", &fiction::is_operational_params::op_condition_positive_charges, + DOC(fiction_is_operational_params_op_condition_positive_charges)) .def_readwrite("strategy_to_analyze_operational_status", &fiction::is_operational_params::strategy_to_analyze_operational_status, - DOC(fiction_is_operational_params_strategy_to_analyze_operational_status)); + DOC(fiction_is_operational_params_strategy_to_analyze_operational_status)) + .def_readwrite("termination_condition", &fiction::is_operational_params::termination_cond, + DOC(fiction_is_operational_params_termination_condition)) + .def_readwrite("simulation_results_retention", &fiction::is_operational_params::simulation_results_retention, + DOC(fiction_is_operational_params_simulation_results_retention)); // NOTE be careful with the order of the following calls! Python will resolve the first matching overload! + detail::operational_assessment(m, "_100"); + detail::operational_assessment(m, "_111"); + detail::is_operational(m); detail::is_operational(m); } diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_parameters.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_parameters.hpp index 815b579e1e..3e309b4d4e 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_parameters.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_parameters.hpp @@ -22,7 +22,6 @@ namespace pyfiction inline void sidb_simulation_parameters(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, "sidb_simulation_parameters", DOC(fiction_sidb_simulation_parameters)) diff --git a/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_result.hpp b/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_result.hpp index b5ed86ec3d..bc6244afb0 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_result.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/algorithms/simulation/sidb/sidb_simulation_result.hpp @@ -26,7 +26,6 @@ template void sidb_simulation_result(pybind11::module& m, const std::string& lattice = "") { namespace py = pybind11; - namespace py = pybind11; py::class_>(m, fmt::format("sidb_simulation_result{}", lattice).c_str(), DOC(fiction_sidb_simulation_result)) diff --git a/bindings/mnt/pyfiction/include/pyfiction/documentation.hpp b/bindings/mnt/pyfiction/include/pyfiction/documentation.hpp index 821faa4cb5..debe1c0d68 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/documentation.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/documentation.hpp @@ -92,4 +92,13 @@ empty layout coordinates. Returns: The minimum and maximum enclosing coordinate in the associated layout.)doc"; +static const char* __doc_fiction_design_sidb_gates_params_canvas_overridden = + R"doc(Canvas spanned by the northwest and southeast cell.)doc"; + +static const char* __doc_fiction_design_sidb_gates_stats_pruning_total_overridden = + R"doc(The total runtime of the process.)doc"; + +static const char* __doc_fiction_design_sidb_gates_stats_time_total_overridden = + R"doc(The total runtime of the SiDB gate design process.)doc"; + #endif // FICTION_DOCSTRINGS_HPP diff --git a/bindings/mnt/pyfiction/include/pyfiction/inout/write_qca_layout.hpp b/bindings/mnt/pyfiction/include/pyfiction/inout/write_qca_layout.hpp index 296a7c84c2..38403ea976 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/inout/write_qca_layout.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/inout/write_qca_layout.hpp @@ -20,7 +20,6 @@ namespace pyfiction inline void write_qca_layout(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, "write_qca_layout_params", DOC(fiction_write_qca_layout_params)) .def(py::init<>()) diff --git a/bindings/mnt/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp b/bindings/mnt/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp index 0e9b9c1a45..61cd0573a4 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/layouts/cartesian_layout.hpp @@ -23,7 +23,6 @@ namespace pyfiction inline void cartesian_layout(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; /** * Cartesian layout. diff --git a/bindings/mnt/pyfiction/include/pyfiction/layouts/coordinates.hpp b/bindings/mnt/pyfiction/include/pyfiction/layouts/coordinates.hpp index 360e9896b5..06140ed438 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/layouts/coordinates.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/layouts/coordinates.hpp @@ -32,7 +32,6 @@ namespace pyfiction inline void offset_coordinate(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, "offset_coordinate", DOC(fiction_offset_ucoord_t)) .def(py::init<>(), DOC(fiction_offset_ucoord_t_ucoord_t)) @@ -93,7 +92,6 @@ inline void offset_coordinate(pybind11::module& m) inline void cube_coordinate(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, "cube_coordinate", DOC(fiction_cube_coord_t)) .def(py::init<>(), DOC(fiction_cube_coord_t_coord_t)) @@ -150,7 +148,6 @@ inline void cube_coordinate(pybind11::module& m) inline void siqad_coordinate(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, "siqad_coordinate", DOC(fiction_siqad_coord_t)) .def(py::init<>(), DOC(fiction_siqad_coord_t_coord_t)) diff --git a/bindings/mnt/pyfiction/include/pyfiction/layouts/gate_level_layout.hpp b/bindings/mnt/pyfiction/include/pyfiction/layouts/gate_level_layout.hpp index 2ee16d208e..dda4972343 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/layouts/gate_level_layout.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/layouts/gate_level_layout.hpp @@ -29,7 +29,6 @@ template void gate_level_layout(pybind11::module& m, const std::string& topology) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, fmt::format("{}_gate_layout", topology).c_str(), DOC(fiction_gate_level_layout)) .def(py::init<>()) diff --git a/bindings/mnt/pyfiction/include/pyfiction/layouts/hexagonal_layout.hpp b/bindings/mnt/pyfiction/include/pyfiction/layouts/hexagonal_layout.hpp index 2ca20d37b1..d36e872f4d 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/layouts/hexagonal_layout.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/layouts/hexagonal_layout.hpp @@ -22,7 +22,6 @@ namespace pyfiction inline void hexagonal_layout(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; /** * Hexagonal layout. diff --git a/bindings/mnt/pyfiction/include/pyfiction/layouts/obstruction_layout.hpp b/bindings/mnt/pyfiction/include/pyfiction/layouts/obstruction_layout.hpp index b846f1be6d..694fc00699 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/layouts/obstruction_layout.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/layouts/obstruction_layout.hpp @@ -22,7 +22,6 @@ template void obstruction_layout(pybind11::module& m, const std::string& topology) { namespace py = pybind11; - namespace py = pybind11; py::class_(m, fmt::format("{}_obstruction_layout", topology).c_str(), DOC(fiction_obstruction_layout)) diff --git a/bindings/mnt/pyfiction/include/pyfiction/layouts/shifted_cartesian_layout.hpp b/bindings/mnt/pyfiction/include/pyfiction/layouts/shifted_cartesian_layout.hpp index e8a19f2379..f7d81beffc 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/layouts/shifted_cartesian_layout.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/layouts/shifted_cartesian_layout.hpp @@ -23,7 +23,6 @@ namespace pyfiction inline void shifted_cartesian_layout(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; /** * Shifted Cartesian layout. diff --git a/bindings/mnt/pyfiction/include/pyfiction/networks/logic_networks.hpp b/bindings/mnt/pyfiction/include/pyfiction/networks/logic_networks.hpp index 65a100012f..fb10fe4c0c 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/networks/logic_networks.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/networks/logic_networks.hpp @@ -34,7 +34,6 @@ template void network(pybind11::module& m, const std::string& network_name) { namespace py = pybind11; - namespace py = pybind11; /** * Network node. diff --git a/bindings/mnt/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/mnt/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index a88acb1222..3f911bfa6e 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -3017,6 +3017,26 @@ Parameter ``n``: Returns: Columnar clocking scheme.)doc"; +static const char *__doc_fiction_compare_by_average_ground_state_isolation = R"doc()doc"; + +static const char *__doc_fiction_compare_by_average_ground_state_isolation_average_ground_state_isolation_over_all_inputs = R"doc()doc"; + +static const char *__doc_fiction_compare_by_average_ground_state_isolation_compare_by_average_ground_state_isolation = R"doc()doc"; + +static const char *__doc_fiction_compare_by_average_ground_state_isolation_equals = R"doc()doc"; + +static const char *__doc_fiction_compare_by_average_ground_state_isolation_operator_call = R"doc()doc"; + +static const char *__doc_fiction_compare_by_minimum_ground_state_isolation = R"doc()doc"; + +static const char *__doc_fiction_compare_by_minimum_ground_state_isolation_compare_by_minimum_ground_state_isolation = R"doc()doc"; + +static const char *__doc_fiction_compare_by_minimum_ground_state_isolation_equals = R"doc()doc"; + +static const char *__doc_fiction_compare_by_minimum_ground_state_isolation_minimum_ground_state_isolation_over_all_inputs = R"doc()doc"; + +static const char *__doc_fiction_compare_by_minimum_ground_state_isolation_operator_call = R"doc()doc"; + static const char *__doc_fiction_convert_array = R"doc(Converts an array of size `N` and type `T` to an array of size `N` and type `ElementType` by applying `static_cast` at compile time. @@ -4542,16 +4562,14 @@ Parameter ``stats``: static const char *__doc_fiction_design_sidb_gates_params = R"doc(This struct contains parameters and settings to design SiDB gates. -Template parameter ``CellType``: - Cell type.)doc"; - -static const char *__doc_fiction_design_sidb_gates_params_canvas = R"doc(Canvas spanned by the northwest and southeast cell.)doc"; +Template parameter ``Lyt``: + SiDB cell-level layout type.)doc"; static const char *__doc_fiction_design_sidb_gates_params_design_mode = R"doc(Gate design mode.)doc"; static const char *__doc_fiction_design_sidb_gates_params_design_sidb_gates_mode = R"doc(Selector for the available design approaches.)doc"; -static const char *__doc_fiction_design_sidb_gates_params_design_sidb_gates_mode_AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER = R"doc(Gates are designed by using the *Automatic Exhaustive Gate Designer*.)doc"; +static const char *__doc_fiction_design_sidb_gates_params_design_sidb_gates_mode_EXHAUSTIVE_GATE_DESIGNER = R"doc(Gates are designed by using the *Automatic Exhaustive Gate Designer*.)doc"; static const char *__doc_fiction_design_sidb_gates_params_design_sidb_gates_mode_QUICKCELL = R"doc(Gates are designed by using *QuickCell*.)doc"; @@ -4561,6 +4579,12 @@ 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_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. @@ -4582,7 +4606,7 @@ within the canvas are enumerated.)doc"; static const char *__doc_fiction_design_sidb_gates_stats = R"doc(Statistics for the design of SiDB gates.)doc"; -static const char *__doc_fiction_design_sidb_gates_stats_duration = R"doc(The total runtime of SiDB gate design process.)doc"; +static const char *__doc_fiction_design_sidb_gates_stats_duration = R"doc(The total runtime of the SiDB gate design process.)doc"; static const char *__doc_fiction_design_sidb_gates_stats_number_of_layouts = R"doc(The number of all possible layouts.)doc"; @@ -4610,6 +4634,101 @@ static const char *__doc_fiction_design_sidb_gates_stats_sim_engine = R"doc(The simulation engine to be used for the operational domain computation.)doc"; +static const char *__doc_fiction_designed_sidb_gate_comparator = +R"doc(A designed SiDB gate comparator is used to compare two designed SiDB +gates. It offers an equality comparison, of which the sensitivity +depends on the `sensitivity` parameter given to the comparator, and a +strict comparator. These ingredients allow a chaining of comparators, +in which the result of the strict comparison is returned of the first +comparator in the chain that judges that the two designed SiDB gates +to compare are not equal, as determined by its respective sensitivity +parameter. + +Template parameter ``Lyt``: + SiDB cell-level layout.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_designed_sidb_gate_comparator = R"doc(The default no-arguments constructor is deleted.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_designed_sidb_gate_comparator_2 = +R"doc(Standard constructor. + +Parameter ``sens``: + Determines the sensitivity of the equality comparison.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_designed_sidb_gate_comparator_3 = +R"doc(Copy constructor. + +Parameter ``other``: + Other comparator to copy.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_designed_sidb_gate_comparator_4 = +R"doc(Move constructor. + +Parameter ``other``: + Other comparator to move to this one.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_equals = +R"doc(Each designed SiDB gate comparator must implement an equality +comparison. + +Parameter ``lhs``: + Left hand side argument. + +Parameter ``rhs``: + Right hand side argument. + +Returns: + `lhs = rhs`)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_operator_assign = +R"doc(Copy assignment operator. + +Parameter ``other``: + Other comparator to copy.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_operator_assign_2 = +R"doc(Move assignment operator. + +Parameter ``other``: + Other comparator to move to this one.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_operator_call = +R"doc(Each designed SiDB gate comparator must implement a strict comparator. + +Parameter ``lhs``: + Left hand side argument. + +Parameter ``rhs``: + Right hand side argument. + +Returns: + `lhs < rhs`)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_sensitivity = +R"doc(Each designed SiDB gate comparator depends on a sensitivity parameter, +which determines the sensitivity of the equality comparison.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_sidb_gate_design = +R"doc(This struct is used to pair a gate design with its respective +simulation results per input.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_sidb_gate_design_gate_design = R"doc(The designed SiDB gate layout.)doc"; + +static const char *__doc_fiction_designed_sidb_gate_comparator_sidb_gate_design_simulation_results_per_input = R"doc(The respectively associated simulation results per input.)doc"; + +static const char *__doc_fiction_designed_sidb_gates = +R"doc(This struct is used to store designed gate layouts, optionally along +with their respective simulation results for each input. + +Template parameter ``Lyt``: + SiDB cell-level layout)doc"; + +static const char *__doc_fiction_designed_sidb_gates_gate_layouts = R"doc(The designed SiDB gate layouts are stored here.)doc"; + +static const char *__doc_fiction_designed_sidb_gates_simulation_results = +R"doc(Optionally, the respectively associated simulation results for each +input are stored here.)doc"; + static const char *__doc_fiction_detail_a_star_impl = R"doc()doc"; static const char *__doc_fiction_detail_a_star_impl_a_star_impl = R"doc()doc"; @@ -5851,8 +5970,6 @@ Parameter ``to_delete``: static const char *__doc_fiction_detail_design_sidb_gates_impl = R"doc()doc"; -static const char *__doc_fiction_detail_design_sidb_gates_impl_all_canvas_layouts = R"doc(All Canvas SiDB layout (without I/O pins).)doc"; - static const char *__doc_fiction_detail_design_sidb_gates_impl_all_sidbs_in_canvas = R"doc(All cells within the canvas.)doc"; static const char *__doc_fiction_detail_design_sidb_gates_impl_convert_canvas_cell_indices_to_layout = @@ -5864,6 +5981,15 @@ Parameter ``cell_indices``: Returns: An SiDB cell-level layout consisting of canvas SidBs.)doc"; +static const char *__doc_fiction_detail_design_sidb_gates_impl_create_all_possible_canvas_layouts = +R"doc(This function calculates all combinations of distributing a given +number of SiDBs across a specified number of positions in the canvas. +Each combination is then used to create a gate layout candidate. + +Returns: + A vector containing all possible gate layouts generated from the + combinations.)doc"; + static const char *__doc_fiction_detail_design_sidb_gates_impl_design_sidb_gates_impl = R"doc(This constructor initializes an instance of the *SiDB Gate Designer* implementation with the provided skeleton layout and configuration @@ -5882,14 +6008,7 @@ Parameter ``ps``: Parameter ``st``: Statistics for the gate design process.)doc"; -static const char *__doc_fiction_detail_design_sidb_gates_impl_determine_all_possible_canvas_layouts = -R"doc(This function calculates all combinations of distributing a given -number of SiDBs across a specified number of positions in the canvas. -Each combination is then used to create a gate layout candidate. - -Returns: - A vector containing all possible gate layouts generated from the - combinations.)doc"; +static const char *__doc_fiction_detail_design_sidb_gates_impl_extract_gate_designs = R"doc()doc"; static const char *__doc_fiction_detail_design_sidb_gates_impl_input_bdl_wires = R"doc(Input BDL wires.)doc"; @@ -5909,8 +6028,8 @@ static const char *__doc_fiction_detail_design_sidb_gates_impl_output_bdl_wires static const char *__doc_fiction_detail_design_sidb_gates_impl_params = R"doc(Parameters for the *SiDB Gate Designer*.)doc"; -static const char *__doc_fiction_detail_design_sidb_gates_impl_run_automatic_exhaustive_gate_designer = -R"doc(Design gates by using the *Automatic Exhaustive Gate Desginer*. This +static const char *__doc_fiction_detail_design_sidb_gates_impl_run_exhaustive_gate_designer = +R"doc(Design gates by using the *Automatic Exhaustive Gate Designer*. This algorithm was proposed in \"Minimal Design of SiDB Gates: An Optimal Basis for Circuits Based on Silicon Dangling Bonds\" by J. Drewniok, M. Walter, and R. Wille in NANOARCH 2023 @@ -5950,22 +6069,23 @@ parameters. The design process is parallelized to improve performance. Returns: A vector of designed SiDB gate layouts.)doc"; +static const char *__doc_fiction_detail_design_sidb_gates_impl_set_operational_params_accordingly = +R"doc(This function makes sure that underlying parameters for +`is_operational` are set according to the given parameters for +`design_sidb_gates`. + +Parameter ``params``: + The given parameters for `design_sidb_gates`. + +Returns: + The same parameters, but now the underlying parameters for + `is_operational` are adjusted 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. It defines input and output wires.)doc"; -static const char *__doc_fiction_detail_design_sidb_gates_impl_skeleton_layout_with_canvas_sidbs = -R"doc(This function adds SiDBs (given by indices) to the skeleton layout -that is returned afterwards. - -Parameter ``cell_indices``: - A vector of indices of cells to be added to the skeleton layout. - -Returns: - 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_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"; @@ -7341,6 +7461,8 @@ static const char *__doc_fiction_detail_generate_edge_intersection_graph_impl_ps static const char *__doc_fiction_detail_generate_edge_intersection_graph_impl_run = R"doc()doc"; +static const char *__doc_fiction_detail_get_ground_state_isolation = R"doc()doc"; + static const char *__doc_fiction_detail_get_offset = R"doc(Utility function to calculate the offset that has to be subtracted from any x-coordinate on the hexagonal layout. @@ -8290,8 +8412,6 @@ Parameter ``current_input_index``: `true` if any output wire contains a kink (i.e., an unexpected charge state), `false` otherwise.)doc"; -static const char *__doc_fiction_detail_is_operational_impl_dependent_cell = R"doc(Dependent cell of the canvas SiDBs.)doc"; - static const char *__doc_fiction_detail_is_operational_impl_determine_non_operational_input_patterns_and_non_operationality_reason = R"doc(Determines the input combinations for which the layout is non- operational and the reason why the layout is non-operational. @@ -8313,6 +8433,9 @@ Parameter ``ground_state``: Parameter ``bdl``: BDL pair to be evaluated. +Parameter ``port``: + Port direction where the BDL pair to be evaluated is. + Returns: `true` if `1` is encoded, `false` otherwise.)doc"; @@ -8326,14 +8449,11 @@ Parameter ``ground_state``: Parameter ``bdl``: BDL pair to be evaluated. -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. +Parameter ``port``: + Port direction where the BDL pair to be evaluated is. Returns: - The number of simulator invocations.)doc"; + `true` if `0` is encoded, `false` otherwise.)doc"; static const char *__doc_fiction_detail_is_operational_impl_input_bdl_wires = R"doc(Input BDL wires.)doc"; @@ -8372,18 +8492,9 @@ identify and discard SiDB layouts that do not satisfy physical model constraints under the I/O pin conditions required for the desired Boolean function, and (3) detecting I/O signal instability. -Template parameter ``ChargeLyt``: - The charge distribution surface layout type. - Parameter ``input_pattern``: The current input pattern. -Parameter ``cds_canvas``: - The charge distribution of the canvas layout. - -Parameter ``dependent_cell``: - A dependent-cell of the canvas SiDBs. - Returns: A `layout_invalidity_reason` object indicating why the layout is non-operational; or `std::nullopt` if it could not certainly be @@ -8395,7 +8506,7 @@ R"doc(Constructor to initialize the algorithm with a layout and parameters. Parameter ``lyt``: The SiDB cell-level layout to be checked. -Parameter ``spec``: +Parameter ``tt``: Expected Boolean function of the layout given as a multi-output truth table. @@ -8434,7 +8545,7 @@ input and output wires, and a canvas layout. Parameter ``lyt``: The SiDB cell-level layout to be checked. -Parameter ``spec``: +Parameter ``tt``: Expected Boolean function of the layout given as a multi-output truth table. @@ -8456,12 +8567,15 @@ R"doc(Constructor to initialize the algorithm with a layout and parameters. Parameter ``lyt``: The SiDB cell-level layout to be checked. -Parameter ``spec``: +Parameter ``tt``: Expected Boolean function of the layout given as a multi-output truth table. Parameter ``params``: - Parameters for the `is_operational` algorithm.)doc"; + Parameters for the `is_operational` algorithm. + +Parameter ``c_lyt``: + Canvas layout.)doc"; static const char *__doc_fiction_detail_is_operational_impl_is_physical_validity_feasible = R"doc(This function determines if there is a charge distribution of the @@ -8532,8 +8646,6 @@ Parameter ``output_wire_index``: The index representing the current input pattern of the output wire.)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_truth_table = R"doc(The specification of the layout.)doc"; static const char *__doc_fiction_detail_is_operational_impl_verify_logic_match_of_cds = @@ -15703,9 +15815,9 @@ Parameter ``params``: Parameters for the `is_operational` algorithm. Returns: - A pair containing the operational status of the SiDB layout - (either `OPERATIONAL` or `NON_OPERATIONAL`) and the number of - input combinations tested.)doc"; + A datatype containing the operational status of the gate-level + layout (either `OPERATIONAL` or `NON_OPERATIONAL`) along with + auxiliary statistics.)doc"; static const char *__doc_fiction_is_operational_2 = R"doc(Determine the operational status of an SiDB layout. @@ -15741,42 +15853,33 @@ Parameter ``canvas_lyt``: Optional canvas layout. Returns: - A pair containing the operational status of the SiDB layout - (either `OPERATIONAL` or `NON_OPERATIONAL`) and the number of - input combinations tested.)doc"; + A datatype containing the operational status of the gate-level + layout (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 = +static const char *__doc_fiction_is_operational_params_op_condition_kinks = R"doc(Condition to decide whether a layout is operational or non- -operational.)doc"; +operational, relating to kinks.)doc"; + +static const char *__doc_fiction_is_operational_params_op_condition_positive_charges = +R"doc(Condition to decide whether a layout is operational or non- +operational, relating to kinks.)doc"; static const char *__doc_fiction_is_operational_params_operational_analysis_strategy = R"doc(Simulation method to determine if the layout is operational or non- -operational. There are three possible strategies: - -- `SIMULATION_ONLY`: This setting does not apply any filtering -strategies to determine if the layout is operational. Instead, it -relies solely on physical simulation to make this determination. - -`FILTER_ONLY`: This setting does only apply filtering strategies to -determine if the layout is non-operational. If the layout passes all -filtering strategies, it is considered operational. This is only an -approximation. It may be possible that the layout is non-operational, -but the filtering strategies do not detect it. - -`FILTER_THEN_SIMULATION`: Before a physical simulation is conducted, -the algorithm checks if filtering strategies have detected whether the -layout is non-operational. This only provides any runtime benefits if -kinks are rejected.)doc"; +operational.)doc"; static const char *__doc_fiction_is_operational_params_operational_analysis_strategy_FILTER_ONLY = R"doc(Apply filtering exclusively to determine whether the layout is non- operational. If the layout passes all filter steps, it is considered operational. -@note This is an extremely fast approximation that may sometimes lead -to false positives.)doc"; +@note This is an extremely fast approximation that may lead to false +positives.)doc"; static const char *__doc_fiction_is_operational_params_operational_analysis_strategy_FILTER_THEN_SIMULATION = R"doc(Before a physical simulation is conducted, the algorithm checks if @@ -15787,18 +15890,30 @@ static const char *__doc_fiction_is_operational_params_operational_analysis_stra R"doc(Do not apply filter strategies to determine whether the layout is operational. Instead, rely solely on physical simulation.)doc"; -static const char *__doc_fiction_is_operational_params_operational_condition = +static const char *__doc_fiction_is_operational_params_operational_condition_kinks = R"doc(Condition to decide whether a layout is operational or non- -operational.)doc"; +operational, relating to kinks.)doc"; -static const char *__doc_fiction_is_operational_params_operational_condition_REJECT_KINKS = +static const char *__doc_fiction_is_operational_params_operational_condition_kinks_REJECT_KINKS = R"doc(The I/O pins are not allowed to show kinks. If kinks exist, the layout is considered as non-operational.)doc"; -static const char *__doc_fiction_is_operational_params_operational_condition_TOLERATE_KINKS = +static const char *__doc_fiction_is_operational_params_operational_condition_kinks_TOLERATE_KINKS = R"doc(Even if the I/O pins show kinks, the layout is still considered as operational.)doc"; +static const char *__doc_fiction_is_operational_params_operational_condition_positive_charges = +R"doc(Condition to decide whether a layout is operational or non- +operational, relating to positive charges.)doc"; + +static const char *__doc_fiction_is_operational_params_operational_condition_positive_charges_REJECT_POSITIVE_CHARGES = +R"doc(Positive charges may not be able to occur. In the case of the converse +being true, the layout is considered as non-operational.)doc"; + +static const char *__doc_fiction_is_operational_params_operational_condition_positive_charges_TOLERATE_POSITIVE_CHARGES = +R"doc(Even if positive charges can occur, the layout is still considered as +operational.)doc"; + static const char *__doc_fiction_is_operational_params_sim_engine = R"doc(The simulation engine to be used for the operational domain computation.)doc"; @@ -15807,10 +15922,39 @@ 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_operational_params_strategy_to_analyze_operational_status = R"doc(Strategy to determine whether a layout is operational or non- operational.)doc"; +static const char *__doc_fiction_is_operational_params_termination_cond = +R"doc(Condition to decide when to terminate the assessment of the +operational status of the given layout.)doc"; + +static const char *__doc_fiction_is_operational_params_termination_condition = +R"doc(The termination condition for assessment of the operational status of +the given layout.)doc"; + +static const char *__doc_fiction_is_operational_params_termination_condition_ALL_INPUT_COMBINATIONS_ASSESSED = R"doc(The operational status is assessed for all input combinations.)doc"; + +static const char *__doc_fiction_is_operational_params_termination_condition_ON_FIRST_NON_OPERATIONAL = +R"doc(The assessment for the given layout terminates either when it is found +to be operational for all input combinations, or an input combination +is found for which the layout is not operational.)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. @@ -16087,7 +16231,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. @@ -16105,7 +16249,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. @@ -16632,6 +16776,51 @@ Parameter ``n``: Returns: Irregular clocking scheme.)doc"; +static const char *__doc_fiction_operational_assessment = +R"doc(This struct is used to collect results from the operational status +assessment. + +Template parameter ``Lyt``: + SiDB cell-level layout type.)doc"; + +static const char *__doc_fiction_operational_assessment_assessment_per_input = +R"doc(When the termination condition is set to +`ALL_INPUT_COMBINATIONS_ASSESSED`, the operational status for each +respective input combination is stored here, sorted by their binary +representation. When the simulation retention is set to +`KEEP_SIMULATION_RESULTS`, this optional structure is also populated.)doc"; + +static const char *__doc_fiction_operational_assessment_extract_simulation_results_per_input = +R"doc(Extracts the simulation results contained in this operational +assessment through moves. + +Returns: + A vector containing the simulation results for each respective + input that was assessed.)doc"; + +static const char *__doc_fiction_operational_assessment_operational_assessment = R"doc(Standard constructor that only sets the operational status.)doc"; + +static const char *__doc_fiction_operational_assessment_operational_assessment_for_input = +R"doc(This struct collects the information for a specific input combination +that was obtained during the assessment.)doc"; + +static const char *__doc_fiction_operational_assessment_operational_assessment_for_input_operational_assessment_for_input = R"doc(Standard constructor that only sets the operational status.)doc"; + +static const char *__doc_fiction_operational_assessment_operational_assessment_for_input_simulation_results = +R"doc(The charge distributions obtained for one input combination that was +tested.)doc"; + +static const char *__doc_fiction_operational_assessment_operational_assessment_for_input_status = +R"doc(The assessed operational status of the given layout under one input +combination.)doc"; + +static const char *__doc_fiction_operational_assessment_simulator_invocations = R"doc(The number of input combinations tested.)doc"; + +static const char *__doc_fiction_operational_assessment_status = +R"doc(The assessed operational status of the given layout. The status +`OPERATIONAL` is given if and only the layout is operational under all +input combinations.)doc"; + static const char *__doc_fiction_operational_domain = R"doc(An operational domain is a set of simulation parameter values for which a given SiDB layout is logically operational. This means that a @@ -17006,7 +17195,7 @@ Parameter ``spec``: Vector of truth table specifications. Parameter ``params``: - Parameters to simulate if a input combination is operational. + Parameters to simulate if an input combination is operational. Returns: The count of operational input combinations.)doc"; @@ -17028,7 +17217,7 @@ Parameter ``spec``: Vector of truth table specifications. Parameter ``params``: - Parameters to simulate if a input combination is operational. + Parameters to simulate if an input combination is operational. Parameter ``input_bdl_wire``: Optional BDL input wires of lyt. @@ -17048,6 +17237,29 @@ 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_order_designed_sidb_gates = +R"doc(The designed SiDB gates are ordered inplace according to the given +ordering recipe. Comparators that occur earlier in the recipe have a +higher precedence. Two designed gates are compared using the recipe as +follows: iterating through the comparators in the order of precedence, +the `equals` function is invoked. When the current comparator judges +the two gate implementations to be equal, we move on to the next +comparator. This proceeds until one comparator judges non-equality, in +which case `operator()` is invoked, which implements `<`. If all +comparators judge the two gate implementations to be equal, +`operator()` is invoked on the last in the recipe. + +Template parameter ``Lyt``: + SiDB cell-level layout. + +Parameter ``recipe``: + A list of comparators that compose a recipe for determining an + ordering of the designed SiDB gates. + +Parameter ``designed_gates``: + The gates that were designed that are to be ordered by the given + ordering recipe.)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 @@ -19800,9 +20012,9 @@ skeleton (i.e., the pre-defined input and output wires) are hexagonal in shape.)doc"; static const char *__doc_fiction_sidb_on_the_fly_gate_library_add_defect_to_skeleton = -R"doc(This function takes a defect surface and a skeleton skeleton and adds -defects from the surrounding area to the skeleton. The defects within -a specified distance from the center cell are taken into account. The +R"doc(This function takes a defect surface and a skeleton and adds defects +from the surrounding area to the skeleton. The defects within a +specified distance from the center cell are taken into account. The resulting skeleton with added defects is returned. Template parameter ``CellLyt``: diff --git a/bindings/mnt/pyfiction/include/pyfiction/technology/sidb_lattice.hpp b/bindings/mnt/pyfiction/include/pyfiction/technology/sidb_lattice.hpp index 4fc8c310d1..6f96e1efeb 100644 --- a/bindings/mnt/pyfiction/include/pyfiction/technology/sidb_lattice.hpp +++ b/bindings/mnt/pyfiction/include/pyfiction/technology/sidb_lattice.hpp @@ -32,7 +32,6 @@ template void sidb_lattice_cell_level_layout(pybind11::module& m) { namespace py = pybind11; - namespace py = pybind11; // fetch technology name auto orientation = std::string{fiction::sidb_lattice_name}; diff --git a/bindings/mnt/pyfiction/test/algorithms/physical_design/test_design_sidb_gates.py b/bindings/mnt/pyfiction/test/algorithms/physical_design/test_design_sidb_gates.py index 9e525d7c53..6098aa29dd 100644 --- a/bindings/mnt/pyfiction/test/algorithms/physical_design/test_design_sidb_gates.py +++ b/bindings/mnt/pyfiction/test/algorithms/physical_design/test_design_sidb_gates.py @@ -4,9 +4,11 @@ create_and_tt, create_nor_tt, design_sidb_gates, - design_sidb_gates_mode, - design_sidb_gates_params, - operational_condition, + design_sidb_gates_mode_100, + design_sidb_gates_mode_111, + design_sidb_gates_params_100, + design_sidb_gates_params_111, + operational_condition_kinks, sidb_100_lattice, sidb_111_lattice, sidb_simulation_engine, @@ -35,10 +37,10 @@ def test_siqad_and_gate_skeleton_100(self): layout.assign_cell_type((10, 19), sidb_technology.cell_type.NORMAL) - params = design_sidb_gates_params() + params = design_sidb_gates_params_100() params.operational_params.simulation_parameters.base = 2 params.operational_params.simulation_parameters.mu_minus = -0.28 - params.design_mode = design_sidb_gates_mode.AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER + params.design_mode = design_sidb_gates_mode_100.EXHAUSTIVE_GATE_DESIGNER params.canvas = [(4, 8), (14, 11)] params.number_of_sidbs = 1 params.operational_params.sim_engine = sidb_simulation_engine.QUICKEXACT @@ -81,14 +83,14 @@ def test_nor_gate_111(self): layout.assign_cell_type((23, 59), sidb_technology.cell_type.NORMAL) - params = design_sidb_gates_params() + params = design_sidb_gates_params_111() params.operational_params.simulation_parameters.base = 2 params.operational_params.simulation_parameters.mu_minus = -0.32 - params.design_mode = design_sidb_gates_mode.AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER + params.design_mode = design_sidb_gates_mode_111.EXHAUSTIVE_GATE_DESIGNER params.canvas = [(10, 22), (14, 34)] params.number_of_sidbs = 3 params.operational_params.sim_engine = sidb_simulation_engine.QUICKEXACT - params.operational_params.op_condition = operational_condition.REJECT_KINKS + params.operational_params.op_condition_kinks = operational_condition_kinks.REJECT_KINKS self.assertEqual(params.operational_params.simulation_parameters.mu_minus, -0.32) self.assertEqual(params.number_of_sidbs, 3) @@ -99,7 +101,7 @@ def test_nor_gate_111(self): self.assertEqual(len(designed_gates), 44) # tolerate kink states - params.operational_params.op_condition = operational_condition.TOLERATE_KINKS + params.operational_params.op_condition_kinks = operational_condition_kinks.TOLERATE_KINKS designed_gates = design_sidb_gates(layout, [create_nor_tt()], params) self.assertEqual(len(designed_gates), 175) @@ -132,10 +134,10 @@ def test_nor_gate_111_quickcell(self): layout.assign_cell_type((23, 59), sidb_technology.cell_type.NORMAL) - params = design_sidb_gates_params() + params = design_sidb_gates_params_111() params.operational_params.simulation_parameters.base = 2 params.operational_params.simulation_parameters.mu_minus = -0.32 - params.design_mode = design_sidb_gates_mode.AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER + params.design_mode = design_sidb_gates_mode_111.EXHAUSTIVE_GATE_DESIGNER params.canvas = [(10, 26), (14, 34)] params.number_of_sidbs = 3 diff --git a/bindings/mnt/pyfiction/test/algorithms/simulation/sidb/test_is_operational.py b/bindings/mnt/pyfiction/test/algorithms/simulation/sidb/test_is_operational.py index 51e8471258..2a2671ad9f 100644 --- a/bindings/mnt/pyfiction/test/algorithms/simulation/sidb/test_is_operational.py +++ b/bindings/mnt/pyfiction/test/algorithms/simulation/sidb/test_is_operational.py @@ -11,7 +11,7 @@ is_operational_params, kink_induced_non_operational_input_patterns, operational_analysis_strategy, - operational_condition, + operational_condition_kinks, operational_input_patterns, operational_status, read_sqd_layout_100, @@ -48,32 +48,28 @@ def test_is_operational(self): params = is_operational_params() params.simulation_parameters = sidb_simulation_parameters(2, -0.28) - [op_status, _evaluated_input_combinations] = is_operational(lyt, [create_and_tt()], params) + assessment_results = is_operational(lyt, [create_and_tt()], params) - self.assertEqual(op_status, operational_status.OPERATIONAL) + self.assertEqual(assessment_results.status, operational_status.OPERATIONAL) params.simulation_parameters = sidb_simulation_parameters(2, -0.1) - [op_status, _evaluated_input_combinations] = is_operational(lyt, [create_and_tt()], params) + assessment_results = is_operational(lyt, [create_and_tt()], params) - self.assertEqual(op_status, operational_status.NON_OPERATIONAL) + self.assertEqual(assessment_results.status, operational_status.NON_OPERATIONAL) # pre-determined I/O pins output_bdl_wires = detect_bdl_wires_100(lyt, detect_bdl_wires_params(), bdl_wire_selection.OUTPUT) input_bdl_wires = detect_bdl_wires_100(lyt, detect_bdl_wires_params(), bdl_wire_selection.INPUT) - [op_status, _evaluated_input_combinations] = is_operational( - lyt, [create_and_tt()], params, input_bdl_wires, output_bdl_wires - ) - self.assertEqual(op_status, operational_status.NON_OPERATIONAL) + assessment_results = is_operational(lyt, [create_and_tt()], params, input_bdl_wires, output_bdl_wires) + self.assertEqual(assessment_results.status, operational_status.NON_OPERATIONAL) # pre-determined I/O pins and canvas layout canvas_lyt = sidb_100_lattice() canvas_lyt.assign_cell_type((4, 5), sidb_technology.cell_type.LOGIC) canvas_lyt.assign_cell_type((6, 7), sidb_technology.cell_type.LOGIC) - [op_status, _evaluated_input_combinations] = is_operational( - lyt, [create_and_tt()], params, input_bdl_wires, output_bdl_wires - ) - self.assertEqual(op_status, operational_status.NON_OPERATIONAL) + assessment_results = is_operational(lyt, [create_and_tt()], params, input_bdl_wires, output_bdl_wires) + self.assertEqual(assessment_results.status, operational_status.NON_OPERATIONAL) def test_and_gate_kinks(self): lyt = read_sqd_layout_100(dir_path + "/../../../resources/AND_mu_032_kinks.sqd") @@ -81,15 +77,15 @@ def test_and_gate_kinks(self): params = is_operational_params() params.simulation_parameters = sidb_simulation_parameters(2, -0.32) - [op_status, _evaluated_input_combinations] = is_operational(lyt, [create_and_tt()], params) + assessment_results = is_operational(lyt, [create_and_tt()], params) - self.assertEqual(op_status, operational_status.OPERATIONAL) + self.assertEqual(assessment_results.status, operational_status.OPERATIONAL) - params.op_condition = operational_condition.REJECT_KINKS + params.op_condition_kinks = operational_condition_kinks.REJECT_KINKS - [op_status, _evaluated_input_combinations] = is_operational(lyt, [create_and_tt()], params) + assessment_results = is_operational(lyt, [create_and_tt()], params) - self.assertEqual(op_status, operational_status.NON_OPERATIONAL) + self.assertEqual(assessment_results.status, operational_status.NON_OPERATIONAL) def test_and_gate_non_operational_due_to_kinks(self): lyt = read_sqd_layout_100(dir_path + "/../../../resources/AND_mu_032_kinks.sqd") @@ -117,31 +113,31 @@ def test_and_gate_111_lattice_11_input_pattern(self): params = is_operational_params() params.simulation_parameters = sidb_simulation_parameters(2, -0.32) - [op_status, _evaluated_input_combinations] = is_operational(lyt, [create_and_tt()], params) + assessment_results = is_operational(lyt, [create_and_tt()], params) - self.assertEqual(op_status, operational_status.OPERATIONAL) + self.assertEqual(assessment_results.status, operational_status.OPERATIONAL) params.simulation_parameters = sidb_simulation_parameters(2, -0.1) self.assertEqual(params.simulation_parameters.mu_minus, -0.1) - [op_status, _evaluated_input_combinations] = is_operational(lyt, [create_and_tt()], params) + assessment_results = is_operational(lyt, [create_and_tt()], params) - self.assertEqual(op_status, operational_status.NON_OPERATIONAL) + self.assertEqual(assessment_results.status, operational_status.NON_OPERATIONAL) # filer only params.strategy_to_analyze_operational_status = operational_analysis_strategy.FILTER_ONLY self.assertEqual(params.strategy_to_analyze_operational_status, operational_analysis_strategy.FILTER_ONLY) - [op_status, _evaluated_input_combinations] = is_operational(lyt, [create_and_tt()], params) - self.assertEqual(op_status, operational_status.NON_OPERATIONAL) + assessment_results = is_operational(lyt, [create_and_tt()], params) + self.assertEqual(assessment_results.status, operational_status.NON_OPERATIONAL) # filer then simulation params.strategy_to_analyze_operational_status = operational_analysis_strategy.FILTER_THEN_SIMULATION self.assertEqual( params.strategy_to_analyze_operational_status, operational_analysis_strategy.FILTER_THEN_SIMULATION ) - [op_status, _evaluated_input_combinations] = is_operational(lyt, [create_and_tt()], params) - self.assertEqual(op_status, operational_status.NON_OPERATIONAL) + assessment_results = is_operational(lyt, [create_and_tt()], params) + self.assertEqual(assessment_results.status, operational_status.NON_OPERATIONAL) def test_and_gate_111_lattice_operational_input_pattern(self): lyt = read_sqd_layout_111(dir_path + "/../../../resources/AND_mu_032_111_surface.sqd") diff --git a/experiments/operational_domain/operational_domain_bestagon.cpp b/experiments/operational_domain/operational_domain_bestagon.cpp index b2affe84d9..b2cc96bcdd 100644 --- a/experiments/operational_domain/operational_domain_bestagon.cpp +++ b/experiments/operational_domain/operational_domain_bestagon.cpp @@ -62,7 +62,8 @@ int main() // NOLINT op_domain_params.operational_params.simulation_parameters = sim_params; op_domain_params.operational_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.operational_params.op_condition = is_operational_params::operational_condition::TOLERATE_KINKS; + op_domain_params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::TOLERATE_KINKS; op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; op_domain_params.sweep_dimensions[0].min = 1.0; diff --git a/experiments/operational_domain/operational_domain_bestagon_exact_vs_sketch.cpp b/experiments/operational_domain/operational_domain_bestagon_exact_vs_sketch.cpp index c00e68e9ac..51010522b4 100644 --- a/experiments/operational_domain/operational_domain_bestagon_exact_vs_sketch.cpp +++ b/experiments/operational_domain/operational_domain_bestagon_exact_vs_sketch.cpp @@ -52,7 +52,8 @@ int main() // NOLINT op_domain_params.operational_params.simulation_parameters = sim_params; op_domain_params.operational_params.sim_engine = sidb_simulation_engine::QUICKEXACT; - op_domain_params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + op_domain_params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; op_domain_params.sweep_dimensions[0].min = 1.0; diff --git a/experiments/physical_design_with_on_the_fly_gate_design/physical_design_with_on_the_fly_gate_design.cpp b/experiments/physical_design_with_on_the_fly_gate_design/physical_design_with_on_the_fly_gate_design.cpp index 065d5371ef..f86e83cc19 100644 --- a/experiments/physical_design_with_on_the_fly_gate_design/physical_design_with_on_the_fly_gate_design.cpp +++ b/experiments/physical_design_with_on_the_fly_gate_design/physical_design_with_on_the_fly_gate_design.cpp @@ -48,15 +48,15 @@ int main() // NOLINT using gate_lyt = fiction::hex_even_row_gate_clk_lyt; using cell_lyt = fiction::sidb_cell_clk_lyt_cube; - fiction::design_sidb_gates_params> design_gate_params{}; + fiction::design_sidb_gates_params> design_gate_params{}; design_gate_params.operational_params.simulation_parameters = fiction::sidb_simulation_parameters{2, -0.32}; // needs to be changed if a different skeleton is used. design_gate_params.canvas = {{24, 17}, {34, 28}}; design_gate_params.number_of_sidbs = 3; design_gate_params.operational_params.sim_engine = fiction::sidb_simulation_engine::QUICKEXACT; - design_gate_params.termination_cond = - fiction::design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION; + design_gate_params.termination_cond = fiction::design_sidb_gates_params< + fiction::sidb_defect_surface>::termination_condition::AFTER_FIRST_SOLUTION; // save atomic defects which their respective physical parameters as experimentally determined by T. R. Huff, T. // Dienel, M. Rashidi, R. Achal, L. Livadaru, J. Croshaw, and R. A. Wolkow, "Electrostatic landscape of a diff --git a/experiments/quickcell/quickcell_3_input.cpp b/experiments/quickcell/quickcell_3_input.cpp index 971f66bc47..f59f4cdfc5 100644 --- a/experiments/quickcell/quickcell_3_input.cpp +++ b/experiments/quickcell/quickcell_3_input.cpp @@ -70,11 +70,11 @@ int main() // NOLINT const auto skeleton_two = read_sqd_layout(fmt::format("{}/{}", folder, "3_in_1_out_skeleton_two.sqd")); - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.31}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{detect_bdl_wires_params{3.0}}, - is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, {{22, 6, 0}, {32, 12, 0}}, 4}; diff --git a/experiments/quickcell/quickcell_rectangular_gate_library.cpp b/experiments/quickcell/quickcell_rectangular_gate_library.cpp index fdba10261f..7f04748b5a 100644 --- a/experiments/quickcell/quickcell_rectangular_gate_library.cpp +++ b/experiments/quickcell/quickcell_rectangular_gate_library.cpp @@ -92,11 +92,11 @@ int main() // NOLINT constexpr auto num_canvas_sidbs = 3u; constexpr auto num_canvas_sidbs_2_input_2_output = 4u; - design_sidb_gates_params> params{ + design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{{3}}, - is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, {{18, 9, 0}, {26, 13, 0}}, num_canvas_sidbs}; diff --git a/experiments/quickcell/quickcell_vs_automatic_exhaustive_2_input.cpp b/experiments/quickcell/quickcell_vs_automatic_exhaustive_2_input.cpp index 12893f92b8..4f09bb74a1 100644 --- a/experiments/quickcell/quickcell_vs_automatic_exhaustive_2_input.cpp +++ b/experiments/quickcell/quickcell_vs_automatic_exhaustive_2_input.cpp @@ -77,27 +77,27 @@ int main() // NOLINT const auto skeleton_two_input_two_output = read_sqd_layout(fmt::format("{}/{}", folder, "skeleton_hex_inputsdbp_2i2o.sqd")); - design_sidb_gates_params> params_1_in_1_out_straight{ + design_sidb_gates_params params_1_in_1_out_straight{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{}, is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params< - fiction::cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + bdl_input_iterator_params{}, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{9, 6, 0}, {21, 14, 0}}, 3}; - design_sidb_gates_params> params_2_in_1_out{ + design_sidb_gates_params params_2_in_1_out{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{}, is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params< - fiction::cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + bdl_input_iterator_params{}, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{14, 6, 0}, {24, 10, 0}}, 3}; - design_sidb_gates_params> params_2_in_2_out{ + design_sidb_gates_params params_2_in_2_out{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{}, is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params< - fiction::cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + bdl_input_iterator_params{}, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{14, 6, 0}, {24, 14, 0}}, 3}; @@ -106,50 +106,51 @@ int main() // NOLINT for (const auto& [truth_table, gate_name] : truth_tables_and_names) { - design_sidb_gates_stats stats_automatic_exhaustive_design{}; + design_sidb_gates_stats stats_exhaustive_design{}; - std::vector automatic_exhaustive_design{}; + std::vector exhaustive_design{}; - params_2_in_1_out.design_mode = design_sidb_gates_params< - fiction::cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER; - params_2_in_1_out.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; - params_2_in_2_out.design_mode = design_sidb_gates_params< - fiction::cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER; - params_2_in_2_out.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params_2_in_1_out.design_mode = + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER; + params_2_in_1_out.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; + params_2_in_2_out.design_mode = + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER; + params_2_in_2_out.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; - params_1_in_1_out_straight.design_mode = design_sidb_gates_params< - fiction::cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER; - params_1_in_1_out_straight.operational_params.op_condition = - is_operational_params::operational_condition::REJECT_KINKS; + params_1_in_1_out_straight.design_mode = + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER; + params_1_in_1_out_straight.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; if (gate_name == "cx" || gate_name == "ha" || gate_name == "hourglass") { - automatic_exhaustive_design = design_sidb_gates(skeleton_two_input_two_output, truth_table, - params_2_in_2_out, &stats_automatic_exhaustive_design); + exhaustive_design = design_sidb_gates(skeleton_two_input_two_output, truth_table, params_2_in_2_out, + &stats_exhaustive_design); } else if (gate_name == "wire" || gate_name == "inv") { - automatic_exhaustive_design = - design_sidb_gates(skeleton_one_input_one_output_straight, truth_table, params_1_in_1_out_straight, - &stats_automatic_exhaustive_design); + exhaustive_design = design_sidb_gates(skeleton_one_input_one_output_straight, truth_table, + params_1_in_1_out_straight, &stats_exhaustive_design); } else { - automatic_exhaustive_design = design_sidb_gates(skeleton_one_input_two_output, truth_table, - params_2_in_1_out, &stats_automatic_exhaustive_design); + exhaustive_design = design_sidb_gates(skeleton_one_input_two_output, truth_table, params_2_in_1_out, + &stats_exhaustive_design); } std::vector quickcell_design{}; design_sidb_gates_stats stats_quickcell{}; params_2_in_1_out.design_mode = - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL; + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL; params_2_in_2_out.design_mode = - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL; + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL; params_1_in_1_out_straight.design_mode = - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL; + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL; if (gate_name == "cx" || gate_name == "ha" || gate_name == "hourglass") { @@ -167,19 +168,18 @@ int main() // NOLINT design_sidb_gates(skeleton_one_input_two_output, truth_table, params_2_in_1_out, &stats_quickcell); } - const auto runtime_automatic_exhaustive_design = - mockturtle::to_seconds(stats_automatic_exhaustive_design.time_total); - const auto runtime_quickcell = mockturtle::to_seconds(stats_quickcell.time_total); + const auto runtime_exhaustive_design = mockturtle::to_seconds(stats_exhaustive_design.time_total); + const auto runtime_quickcell = mockturtle::to_seconds(stats_quickcell.time_total); - sum_exhaustive_runtime += runtime_automatic_exhaustive_design; + sum_exhaustive_runtime += runtime_exhaustive_design; sum_quickcell_runtime += runtime_quickcell; - const auto time_reduction = runtime_automatic_exhaustive_design / runtime_quickcell; + const auto time_reduction = runtime_exhaustive_design / runtime_quickcell; const auto total_number_of_layout = stats_quickcell.number_of_layouts; - simulation_exp(gate_name, total_number_of_layout, runtime_automatic_exhaustive_design, - automatic_exhaustive_design.size(), quickcell_design.size(), runtime_quickcell, time_reduction, + simulation_exp(gate_name, total_number_of_layout, runtime_exhaustive_design, exhaustive_design.size(), + quickcell_design.size(), runtime_quickcell, time_reduction, stats_quickcell.number_of_layouts_after_first_pruning, static_cast(stats_quickcell.number_of_layouts_after_first_pruning) / static_cast(total_number_of_layout) * 100, diff --git a/experiments/quicktrace/quicktrace_vs_grid_search_new_gates.cpp b/experiments/quicktrace/quicktrace_vs_grid_search_new_gates.cpp index 9a2571dafb..579221b88b 100644 --- a/experiments/quicktrace/quicktrace_vs_grid_search_new_gates.cpp +++ b/experiments/quicktrace/quicktrace_vs_grid_search_new_gates.cpp @@ -42,10 +42,9 @@ int main() // NOLINT auto lyt = read_sqd_layout( fmt::format("{}/gate_skeletons/skeleton_bestagons_with_tags/skeleton_hex_inputsdbp_2i1o.sqd", folder)); - const design_sidb_gates_params> params_2_in_1_out{ + const design_sidb_gates_params params_2_in_1_out{ is_operational_params{sidb_simulation_parameters{2, -0.32}}, - design_sidb_gates_params< - cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{14, 12, 0}, {24, 23, 0}}, 3}; @@ -53,10 +52,10 @@ int main() // NOLINT const is_operational_params is_op_params{sidb_sim}; // for this experiment, we use a stray SiDB defect - const auto stray_db = fiction::sidb_defect{fiction::sidb_defect_type::DB, -1, 4.1, 1.8}; - // const auto si_vacancy = fiction::sidb_defect{fiction::sidb_defect_type::SI_VACANCY, -1, 10.6, 5.9}; + const auto stray_db = sidb_defect{sidb_defect_type::DB, -1, 4.1, 1.8}; + // const auto si_vacancy = sidb_defect{sidb_defect_type::SI_VACANCY, -1, 10.6, 5.9}; - defect_influence_params> params{}; + defect_influence_params> params{}; params.additional_scanning_area = {100, 1000}; params.defect = stray_db; params.operational_params = is_op_params; diff --git a/experiments/sidb_simulation/temperature/critical_temperature_simulation_bestagon.cpp b/experiments/sidb_simulation/temperature/critical_temperature_simulation_bestagon.cpp index f6136dfacb..c7d985859b 100644 --- a/experiments/sidb_simulation/temperature/critical_temperature_simulation_bestagon.cpp +++ b/experiments/sidb_simulation/temperature/critical_temperature_simulation_bestagon.cpp @@ -47,7 +47,7 @@ int main() // NOLINT std::make_pair("wire", std::vector{create_id_tt()})}; const sidb_simulation_parameters sim_params{2, -0.32}; - const critical_temperature_params ct_params{sim_params}; + const critical_temperature_params ct_params{{sim_params}}; for (const auto& [gate, truth_table] : gates) { diff --git a/experiments/sidb_simulation/temperature/critical_temperature_simulation_siqad.cpp b/experiments/sidb_simulation/temperature/critical_temperature_simulation_siqad.cpp index 560ec7502a..583b736012 100644 --- a/experiments/sidb_simulation/temperature/critical_temperature_simulation_siqad.cpp +++ b/experiments/sidb_simulation/temperature/critical_temperature_simulation_siqad.cpp @@ -38,8 +38,8 @@ int main() // NOLINT std::make_pair("xnor", std::vector{create_xnor_tt()}), std::make_pair("xor", std::vector{create_xor_tt()}), std::make_pair("or", std::vector{create_or_tt()})}; - const sidb_simulation_parameters sim_params{2, -0.28}; - critical_temperature_params ct_params{sim_params}; + constexpr sidb_simulation_parameters sim_params{2, -0.28}; + critical_temperature_params ct_params{{sim_params}}; // this is how the gates are presented and simulated in "SiQAD: A Design and Simulation Tool for Atomic Silicon // Quantum Dot Circuits\" by Samuel Sze Hang Ng, Jacob Retallick, Hsi Nien Chiu, Robert Lupoiu, Lucian Livadaru, diff --git a/include/fiction/algorithms/physical_design/compare_designed_sidb_gates.hpp b/include/fiction/algorithms/physical_design/compare_designed_sidb_gates.hpp new file mode 100644 index 0000000000..8cde828220 --- /dev/null +++ b/include/fiction/algorithms/physical_design/compare_designed_sidb_gates.hpp @@ -0,0 +1,198 @@ +// +// Created by Willem Lambooy on 05/02/2025. +// + +#ifndef COMPARE_DESIGNED_SIDB_GATES_HPP +#define COMPARE_DESIGNED_SIDB_GATES_HPP + +#include "fiction/technology/charge_distribution_surface.hpp" + +#include +#include +#include +#include +#include + +namespace fiction +{ + +/** + * This struct is used to store designed gate layouts, optionally along with their respective simulation results for + * each input. + * + * @tparam Lyt SiDB cell-level layout + */ +template +struct designed_sidb_gates +{ + /** + * Simulation results per input is a vector of simulation results (which is a vector of charge distribution + * surfaces) that occur in the order of the bit representation of the respectively associated inputs. + */ + using simulation_results_per_input = std::vector>>; + /** + * The designed SiDB gate layouts are stored here. + */ + std::vector gate_layouts; + /** + * Optionally, the respectively associated simulation results for each input are stored here. + */ + std::optional> simulation_results; +}; +/** + * A designed SiDB gate comparator is used to compare two designed SiDB gates. It offers an equality comparison, of + * which the sensitivity depends on the `sensitivity` parameter given to the comparator, and a strict comparator. These + * ingredients allow a chaining of comparators, in which the result of the strict comparison is returned of the first + * comparator in the chain that judges that the two designed SiDB gates to compare are not equal, as determined by its + * respective sensitivity parameter. + * + * @tparam Lyt SiDB cell-level layout. + */ +template +class designed_sidb_gate_comparator +{ + public: + /** + * This struct is used to pair a gate design with its respective simulation results per input. + */ + struct sidb_gate_design + { + /** + * The designed SiDB gate layout. + */ + Lyt gate_design; + /** + * The respectively associated simulation results per input. + */ + typename designed_sidb_gates::simulation_results_per_input simulation_results_per_input; + }; + /** + * The default no-arguments constructor is deleted. + */ + explicit designed_sidb_gate_comparator() = delete; + /** + * Destructor. + */ + virtual ~designed_sidb_gate_comparator() noexcept = default; + /** + * Standard constructor. + * + * @param sens Determines the sensitivity of the equality comparison. + */ + explicit designed_sidb_gate_comparator(const double sens) noexcept : sensitivity{sens} + { + assert(sensitivity >= 0.0 && "The given sensitivity is negative."); + } + /** + * Copy constructor. + * + * @param other Other comparator to copy. + */ + designed_sidb_gate_comparator(const designed_sidb_gate_comparator& other) noexcept = default; + /** + * Move constructor. + * + * @param other Other comparator to move to this one. + */ + designed_sidb_gate_comparator(designed_sidb_gate_comparator&& other) noexcept = default; + /** + * Copy assignment operator. + * + * @param other Other comparator to copy. + */ + designed_sidb_gate_comparator& operator=(const designed_sidb_gate_comparator& other) noexcept = default; + /** + * Move assignment operator. + * + * @param other Other comparator to move to this one. + */ + designed_sidb_gate_comparator& operator=(designed_sidb_gate_comparator&& other) noexcept = default; + /** + * Each designed SiDB gate comparator must implement a strict comparator. + * + * @param lhs Left hand side argument. + * @param rhs Right hand side argument. + * @return `lhs < rhs` + */ + [[nodiscard]] virtual bool operator()(const sidb_gate_design& lhs, const sidb_gate_design& rhs) const noexcept = 0; + /** + * Each designed SiDB gate comparator must implement an equality comparison. + * + * @param lhs Left hand side argument. + * @param rhs Right hand side argument. + * @return `lhs = rhs` + */ + [[nodiscard]] virtual bool equals(const sidb_gate_design& lhs, const sidb_gate_design& rhs) const noexcept = 0; + + protected: + /** + * Each designed SiDB gate comparator depends on a sensitivity parameter, which determines the sensitivity of the + * equality comparison. + */ + double sensitivity; +}; +/** + * An ordering recipe for designed SiDB gates is a vector of pointers to designed SiDB gate comparators. Pointers are + * used to prevent slicing. + * + * @tparam Lyt SiDB cell-level layout. + */ +template +using designed_sidb_gates_ordering_recipe = std::vector>>; +/** + * The designed SiDB gates are ordered inplace according to the given ordering recipe. Comparators that occur earlier in + * the recipe have a higher precedence. Two designed gates are compared using the recipe as follows: iterating through + * the comparators in the order of precedence, the `equals` function is invoked. When the current comparator judges the + * two gate implementations to be equal, we move on to the next comparator. This proceeds until one comparator judges + * non-equality, in which case `operator()` is invoked, which implements `<`. If all comparators judge the two gate + * implementations to be equal, `operator()` is invoked on the last in the recipe. + * + * @tparam Lyt SiDB cell-level layout. + * @param recipe A list of comparators that compose a recipe for determining an ordering of the designed SiDB gates. + * @param designed_gates The gates that were designed that are to be ordered by the given ordering recipe. + */ +template +void order_designed_sidb_gates(const designed_sidb_gates_ordering_recipe& recipe, + designed_sidb_gates& designed_gates) noexcept +{ + assert(designed_gates.simulation_results.has_value() && + "Simulation results must be available for gate design ordering"); + + std::vector::sidb_gate_design> gate_designs_for_assessment{}; + gate_designs_for_assessment.reserve(designed_gates.gate_layouts.size()); + + // pair the gate layouts with the associated simulation results using move + for (uint64_t i = 0; i < designed_gates.gate_layouts.size(); ++i) + { + gate_designs_for_assessment.emplace_back(typename designed_sidb_gate_comparator::sidb_gate_design{ + std::move(designed_gates.gate_layouts.at(i)), std::move(designed_gates.simulation_results.value().at(i))}); + } + + // clear the gate_layouts vector so that we may reenter the elements in order later + designed_gates.gate_layouts.clear(); + + // perform ordering procedure using the given recipe + std::sort(gate_designs_for_assessment.begin(), gate_designs_for_assessment.end(), + [&](const auto& lhs, const auto& rhs) noexcept + { + for (uint64_t i = 0; i < recipe.size() - 1; ++i) + { + if (!recipe.at(i)->equals(lhs, rhs)) + { + return (*recipe.at(i))(lhs, rhs); + } + } + + return (*recipe.at(recipe.size() - 1))(lhs, rhs); + }); + + // put the designed gate layouts back in order + for (auto&& [gate_design, _] : gate_designs_for_assessment) + { + designed_gates.gate_layouts.emplace_back(std::move(gate_design)); + } +} + +} // namespace fiction + +#endif // COMPARE_DESIGNED_SIDB_GATES_HPP diff --git a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp index 15953ddf5f..12e2e7f8f0 100644 --- a/include/fiction/algorithms/physical_design/design_sidb_gates.hpp +++ b/include/fiction/algorithms/physical_design/design_sidb_gates.hpp @@ -6,34 +6,31 @@ #define FICTION_DESIGN_SIDB_GATES_HPP #include "fiction/algorithms/iter/bdl_input_iterator.hpp" +#include "fiction/algorithms/physical_design/compare_designed_sidb_gates.hpp" #include "fiction/algorithms/simulation/sidb/detect_bdl_wires.hpp" #include "fiction/algorithms/simulation/sidb/is_operational.hpp" #include "fiction/algorithms/simulation/sidb/random_sidb_layout_generator.hpp" #include "fiction/algorithms/simulation/sidb/sidb_simulation_engine.hpp" -#include "fiction/technology/cell_ports.hpp" #include "fiction/technology/cell_technologies.hpp" -#include "fiction/technology/charge_distribution_surface.hpp" -#include "fiction/technology/sidb_charge_state.hpp" #include "fiction/technology/sidb_defects.hpp" #include "fiction/traits.hpp" #include "fiction/utils/layout_utils.hpp" #include "fiction/utils/math_utils.hpp" #include -#include #include #include #include #include #include +#include #include -#include #include #include +#include #include #include -#include #include #include @@ -43,26 +40,12 @@ namespace fiction /** * This struct contains parameters and settings to design SiDB gates. * - * @tparam CellType Cell type. + * @tparam Lyt SiDB cell-level layout type. * */ -template +template struct design_sidb_gates_params { - /** - * Selector for the different termination conditions for the SiDB gate design process. - */ - enum class termination_condition : uint8_t - { - /** - * The design process is terminated as soon as the first valid SiDB gate design is found. - */ - AFTER_FIRST_SOLUTION, - /** - * The design process ends after all possible combinations of SiDBs within the canvas are enumerated. - */ - ALL_COMBINATIONS_ENUMERATED - }; /** * Selector for the available design approaches. */ @@ -75,12 +58,26 @@ struct design_sidb_gates_params /** * Gates are designed by using the *Automatic Exhaustive Gate Designer*. */ - AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + EXHAUSTIVE_GATE_DESIGNER, /** * Gate layouts are designed randomly. */ RANDOM }; + /** + * Selector for the different termination conditions for the SiDB gate design process. + */ + enum class termination_condition : uint8_t + { + /** + * The design process is terminated as soon as the first valid SiDB gate design is found. + */ + AFTER_FIRST_SOLUTION, + /** + * The design process ends after all possible combinations of SiDBs within the canvas are enumerated. + */ + ALL_COMBINATIONS_ENUMERATED + }; /** * Parameters for the `is_operational` function. */ @@ -88,11 +85,11 @@ struct design_sidb_gates_params /** * Gate design mode. */ - design_sidb_gates_mode design_mode = design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER; + design_sidb_gates_mode design_mode = design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER; /** * Canvas spanned by the northwest and southeast cell. */ - std::pair canvas{}; + std::pair, cell> canvas{}; /** * Number of SiDBs placed in the canvas to create a working gate. */ @@ -103,15 +100,20 @@ 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. + */ + designed_sidb_gates_ordering_recipe post_design_process{}; }; - /** * Statistics for the design of SiDB gates. */ struct design_sidb_gates_stats { /** - * The total runtime of SiDB gate design process. + * The total runtime of the SiDB gate design process. */ mockturtle::stopwatch<>::duration time_total{0}; /** @@ -167,11 +169,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, const design_sidb_gates_params& ps, + design_sidb_gates_stats& st) : skeleton_layout{skeleton}, truth_table{spec}, - params{ps}, + params{set_operational_params_accordingly(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, @@ -181,15 +183,13 @@ class design_sidb_gates_impl params.operational_params.input_bdl_iterator_params.bdl_wire_params, bdl_wire_selection::OUTPUT)}, number_of_input_wires{input_bdl_wires.size()}, - number_of_output_wires{output_bdl_wires.size()}, - all_canvas_layouts{determine_all_possible_canvas_layouts()} + number_of_output_wires{output_bdl_wires.size()} { - stats.number_of_layouts = all_canvas_layouts.size(); + stats.number_of_layouts = binomial_coefficient(all_sidbs_in_canvas.size(), params.number_of_sidbs); stats.sim_engine = params.operational_params.sim_engine; } - /** - * Design gates by using the *Automatic Exhaustive Gate Desginer*. This algorithm was proposed in \"Minimal + * Design gates by using the *Automatic Exhaustive Gate Designer*. This algorithm was proposed in \"Minimal * Design of SiDB Gates: An Optimal Basis for Circuits Based on Silicon Dangling Bonds\" by J. Drewniok, M. Walter, * and R. Wille in NANOARCH 2023 (https://dl.acm.org/doi/10.1145/3611315.3633241). * @@ -198,65 +198,34 @@ class design_sidb_gates_impl * * @return A vector of designed SiDB gate layouts. */ - [[nodiscard]] std::vector run_automatic_exhaustive_gate_designer() const noexcept + [[nodiscard]] std::vector run_exhaustive_gate_designer() const noexcept { - mockturtle::stopwatch stop{stats.time_total}; - - 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 = {}; - - if (all_combinations.empty()) + if (stats.number_of_layouts == 0) { - return designed_gate_layouts; + return std::vector{}; } - std::unordered_set> sidbs_affected_by_defects = {}; - - // used to collect all SiDBs that are affected due to neutrally charged defects. - if constexpr (has_get_sidb_defect_v) - { - sidbs_affected_by_defects = skeleton_layout.all_affected_sidbs(std::make_pair(0, 0)); - } - - std::mutex mutex_to_protect_designed_gate_layouts{}; + const std::vector& all_canvas_layouts = create_all_possible_canvas_layouts(); - std::atomic solution_found = false; + std::vector gate_candidates{}; + gate_candidates.reserve(all_canvas_layouts.size()); - // Shuffle the combinations before dividing them among threads - std::shuffle(all_combinations.begin(), all_combinations.end(), - std::default_random_engine(std::random_device{}())); + std::mutex mutex_to_protect_gate_candidates{}; // used to control access to shared resources - 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 + // The canvas layouts are to be inserted in the skeleton to create all gate candidates; this is done in parallel + auto insert_canvas_sidbs = [&](const Lyt& canvas_lyt) { - // canvas SiDBs are added to the skeleton - const auto layout_with_added_cells = skeleton_layout_with_canvas_sidbs(combination); + Lyt gate_candidate = skeleton_layout.clone(); - if (const auto [status, sim_calls] = is_operational( - layout_with_added_cells, truth_table, params.operational_params, input_bdl_wires, output_bdl_wires); - status == operational_status::OPERATIONAL) - { - { - const std::lock_guard lock_vector{mutex_to_protect_designed_gate_layouts}; - designed_gate_layouts.push_back(layout_with_added_cells); - } + canvas_lyt.foreach_cell([&gate_candidate](const auto& c) + { gate_candidate.assign_cell_type(c, Lyt::technology::cell_type::LOGIC); }); - solution_found = true; - } - - if (solution_found && (params.termination_cond == - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION)) - { - return; - } + const std::lock_guard lock{mutex_to_protect_gate_candidates}; + gate_candidates.emplace_back(gate_candidate); }; - const std::size_t num_threads = std::min(number_of_threads, all_combinations.size()); - - const std::size_t chunk_size = (all_combinations.size() + num_threads - 1) / num_threads; // Ceiling division + const std::size_t num_threads = std::min(number_of_threads, all_canvas_layouts.size()); + const std::size_t chunk_size = (all_canvas_layouts.size() + num_threads - 1) / num_threads; std::vector threads{}; threads.reserve(num_threads); @@ -264,21 +233,14 @@ class design_sidb_gates_impl for (std::size_t i = 0; i < num_threads; ++i) { threads.emplace_back( - [i, chunk_size, &all_combinations, &add_combination_to_layout_and_check_operation, &solution_found, - this]() + [i, chunk_size, &insert_canvas_sidbs, &all_canvas_layouts] { const std::size_t start_index = i * chunk_size; - const std::size_t end_index = std::min(start_index + chunk_size, all_combinations.size()); + const std::size_t end_index = std::min(start_index + chunk_size, all_canvas_layouts.size()); for (std::size_t j = start_index; j < end_index; ++j) { - if (solution_found && - (params.termination_cond == - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION)) - { - return; - } - add_combination_to_layout_and_check_operation(all_combinations[j]); + insert_canvas_sidbs(all_canvas_layouts.at(j)); } }); } @@ -291,7 +253,38 @@ class design_sidb_gates_impl } } - return designed_gate_layouts; + return extract_gate_designs(gate_candidates); + } + /** + * Design Standard Cells/gates by using the *QuickCell* algorithm. + * + * @return A vector of designed SiDB gate layouts. + */ + [[nodiscard]] std::vector run_quickcell() noexcept + { + mockturtle::stopwatch stop{stats.time_total}; + + if (stats.number_of_layouts == 0) + { + return std::vector{}; + } + + std::vector gate_candidates{}; + gate_candidates.reserve(stats.number_of_layouts); + + { + mockturtle::stopwatch stop_pruning{stats.pruning_total}; + gate_candidates = run_pruning(); + } + + stats.number_of_layouts_after_first_pruning = + stats.number_of_layouts - number_of_discarded_layouts_at_first_pruning.load(); + stats.number_of_layouts_after_second_pruning = + stats.number_of_layouts_after_first_pruning - number_of_discarded_layouts_at_second_pruning.load(); + stats.number_of_layouts_after_third_pruning = + stats.number_of_layouts_after_second_pruning - number_of_discarded_layouts_at_third_pruning.load(); + + return extract_gate_designs(gate_candidates); } /** * Design gates randomly and in parallel. @@ -311,16 +304,14 @@ class design_sidb_gates_impl params.canvas, params.number_of_sidbs, generate_random_sidb_layout_params>::positive_charges::ALLOWED}; - const auto num_threads = std::min(number_of_threads, all_canvas_layouts.size()); - std::vector threads{}; - threads.reserve(num_threads); + threads.reserve(number_of_threads); std::mutex mutex_to_protect_designed_gate_layouts{}; // used to control access to shared resources std::atomic gate_layout_is_found(false); - for (uint64_t z = 0u; z < num_threads; z++) + for (uint64_t z = 0u; z < number_of_threads; z++) { threads.emplace_back( [this, &gate_layout_is_found, &mutex_to_protect_designed_gate_layouts, ¶meter, @@ -348,10 +339,10 @@ class design_sidb_gates_impl }); } - if (const auto [status, sim_calls] = + if (const operational_assessment& assessment_results = is_operational(result_lyt.value(), truth_table, params.operational_params, input_bdl_wires, output_bdl_wires); - status == operational_status::OPERATIONAL) + assessment_results.status == operational_status::OPERATIONAL) { const std::lock_guard lock{mutex_to_protect_designed_gate_layouts}; @@ -386,96 +377,132 @@ class design_sidb_gates_impl return randomly_designed_gate_layouts; } + private: /** - * Design Standard Cells/gates by using the *QuickCell* algorithm. - * - * @return A vector of designed SiDB gate layouts. + * The skeleton layout serves as a starting layout to which SiDBs are added to create unique SiDB layouts and, if + * possible, working gates. It defines input and output wires. */ - [[nodiscard]] std::vector run_quickcell() noexcept + const Lyt skeleton_layout; + /** + * Truth table of the given gate. + */ + const std::vector truth_table{}; + /** + * Parameters for the *SiDB Gate Designer*. + */ + const design_sidb_gates_params params; + /** + * All cells within the canvas. + */ + const std::vector all_sidbs_in_canvas{}; + /** + * The statistics of the gate design. + */ + design_sidb_gates_stats& stats; + /** + * Input BDL wires. + */ + const std::vector> input_bdl_wires{}; + /** + * Output BDL wires. + */ + const std::vector> output_bdl_wires{}; + /** + * Number of input BDL wires. + */ + const std::size_t number_of_input_wires{}; + /** + * Number of output BDL wires. + */ + const std::size_t number_of_output_wires{}; + /** + * Number of discarded layouts at first pruning. + */ + std::atomic number_of_discarded_layouts_at_first_pruning{0}; + /** + * Number of discarded layouts at second pruning. + */ + std::atomic number_of_discarded_layouts_at_second_pruning{0}; + /** + * Number of discarded layouts at third pruning. + */ + std::atomic number_of_discarded_layouts_at_third_pruning{0}; + /** + * Number of threads to be used for the design process. + */ + std::size_t number_of_threads{std::thread::hardware_concurrency()}; + + [[nodiscard]] std::vector extract_gate_designs(std::vector& gate_candidates) const noexcept { mockturtle::stopwatch stop{stats.time_total}; - std::vector gate_candidates{}; - gate_candidates.reserve(all_canvas_layouts.size()); - + if (gate_candidates.empty()) { - mockturtle::stopwatch stop_pruning{stats.pruning_total}; - gate_candidates = run_pruning(); + return std::vector{}; } - stats.number_of_layouts_after_first_pruning = - all_canvas_layouts.size() - number_of_discarded_layouts_at_first_pruning.load(); - stats.number_of_layouts_after_second_pruning = - stats.number_of_layouts_after_first_pruning - number_of_discarded_layouts_at_second_pruning.load(); - stats.number_of_layouts_after_third_pruning = - stats.number_of_layouts_after_second_pruning - number_of_discarded_layouts_at_third_pruning.load(); + designed_sidb_gates designed_gate_layouts{}; - std::vector gate_layouts{}; - gate_layouts.reserve(gate_candidates.size()); - - if (gate_candidates.empty()) + if (!params.post_design_process.empty()) { - return gate_layouts; + designed_gate_layouts.simulation_results = + std::make_optional::simulation_results_per_input>>(); } - std::mutex mutex_to_protect_gate_designs{}; - - gate_layouts.reserve(gate_candidates.size()); - - const std::size_t num_threads = std::min(number_of_threads, gate_candidates.size()); - - const std::size_t chunk_size = (gate_candidates.size() + num_threads - 1) / num_threads; // Ceiling division - - std::vector threads; - threads.reserve(num_threads); + std::mutex mutex_to_protect_designed_gate_layouts{}; - std::atomic gate_design_found = false; + std::atomic solution_found = false; - const auto check_operational_status = - [this, &gate_layouts, &mutex_to_protect_gate_designs, &gate_design_found](const auto& candidate) noexcept + const auto add_combination_to_layout_and_check_operation = [this, &mutex_to_protect_designed_gate_layouts, + &designed_gate_layouts, + &solution_found](Lyt&& candidate) noexcept { - // Early exit if a solution is found and only the first solution is required - if (gate_design_found && (params.termination_cond == - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION)) + if (const operational_assessment& assessment_results = is_operational( + candidate, truth_table, params.operational_params, input_bdl_wires, output_bdl_wires); + assessment_results.status == operational_status::OPERATIONAL) { - return; - } + { + const std::lock_guard lock_vector{mutex_to_protect_designed_gate_layouts}; - // pruning was already conducted above. Hence, SIMULATION_ONLY is chosen. - params.operational_params.strategy_to_analyze_operational_status = - is_operational_params::operational_analysis_strategy::SIMULATION_ONLY; + designed_gate_layouts.gate_layouts.emplace_back(std::move(candidate)); - if (const auto [status, sim_calls] = is_operational(candidate, truth_table, params.operational_params, - input_bdl_wires, output_bdl_wires); - status == operational_status::OPERATIONAL) - { - // Lock and update shared resources - { - const std::lock_guard lock{mutex_to_protect_gate_designs}; - gate_layouts.push_back(candidate); + if (designed_gate_layouts.simulation_results.has_value()) + { + designed_gate_layouts.simulation_results.value().push_back( + assessment_results.extract_simulation_results_per_input()); + } } - gate_design_found = true; // Notify all threads that a solution has been found + + solution_found = true; } }; + const std::size_t num_threads = std::min(number_of_threads, gate_candidates.size()); + + const std::size_t chunk_size = (gate_candidates.size() + num_threads - 1) / num_threads; // Ceiling division + + std::vector threads{}; + threads.reserve(num_threads); + for (std::size_t i = 0; i < num_threads; ++i) { threads.emplace_back( - [this, i, chunk_size, &gate_candidates, &check_operational_status, &gate_design_found]() + [this, i, chunk_size, &gate_candidates, &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, gate_candidates.size()); for (std::size_t j = start_index; j < end_index; ++j) { - if (gate_design_found && + if (solution_found && (params.termination_cond == - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION)) + design_sidb_gates_params::termination_condition::AFTER_FIRST_SOLUTION)) { return; } - check_operational_status(gate_candidates[j]); + add_combination_to_layout_and_check_operation(std::move(gate_candidates[j])); } }); } @@ -488,67 +515,13 @@ class design_sidb_gates_impl } } - return gate_layouts; - } + if (!params.post_design_process.empty() && designed_gate_layouts.gate_layouts.size() > 1) + { + order_designed_sidb_gates(params.post_design_process, designed_gate_layouts); + } - private: - /** - * The skeleton layout serves as a starting layout to which SiDBs are added to create unique SiDB layouts and, if - * possible, working gates. It defines input and output wires. - */ - const Lyt skeleton_layout; - /** - * Truth table of the given gate. - */ - const std::vector truth_table; - /** - * Parameters for the *SiDB Gate Designer*. - */ - design_sidb_gates_params> params; - /** - * All cells within the canvas. - */ - std::vector all_sidbs_in_canvas; - /** - * The statistics of the gate design. - */ - design_sidb_gates_stats& stats; - /** - * Input BDL wires. - */ - const std::vector> input_bdl_wires; - /** - * Output BDL wires. - */ - const std::vector> output_bdl_wires; - /** - * Number of input BDL wires. - */ - const std::size_t number_of_input_wires; - /** - * Number of output BDL wires. - */ - const std::size_t number_of_output_wires; - /** - * All Canvas SiDB layout (without I/O pins). - */ - const std::vector all_canvas_layouts{}; - /** - * Number of discarded layouts at first pruning. - */ - std::atomic number_of_discarded_layouts_at_first_pruning{0}; - /** - * Number of discarded layouts at second pruning. - */ - std::atomic number_of_discarded_layouts_at_second_pruning{0}; - /** - * Number of discarded layouts at third pruning. - */ - std::atomic number_of_discarded_layouts_at_third_pruning{0}; - /** - * Number of threads to be used for the design process. - */ - std::size_t number_of_threads{std::thread::hardware_concurrency()}; + return designed_gate_layouts.gate_layouts; + } /** * This function processes each layout to determine if it represents a valid gate implementation or if it can be * pruned by using three distinct physically-informed pruning steps. It leverages multi-threading to accelerate the @@ -558,63 +531,54 @@ class design_sidb_gates_impl */ [[nodiscard]] std::vector run_pruning() noexcept { - std::vector gate_candidate = {}; + std::vector gate_candidates = {}; - if (all_canvas_layouts.empty()) + if (stats.number_of_layouts == 0) { - return gate_candidate; + return gate_candidates; } + gate_candidates.reserve(stats.number_of_layouts); + std::mutex mutex_to_protect_gate_candidates{}; // used to control access to shared resources + const std::vector& all_canvas_layouts = create_all_possible_canvas_layouts(); + // Function to check validity and add layout to all_designs auto conduct_pruning_steps = [&](const Lyt& canvas_lyt) { - auto current_layout = skeleton_layout.clone(); - - cell dependent_cell{}; + Lyt current_layout = skeleton_layout.clone(); - canvas_lyt.foreach_cell( - [¤t_layout, &dependent_cell](const auto& c) - { - current_layout.assign_cell_type(c, Lyt::technology::cell_type::LOGIC); - dependent_cell = c; - }); - - charge_distribution_surface cds_canvas{canvas_lyt, params.operational_params.simulation_parameters, - sidb_charge_state::NEGATIVE, - cds_configuration::CHARGE_LOCATION_ONLY}; - - cds_canvas.assign_dependent_cell(dependent_cell); + canvas_lyt.foreach_cell([¤t_layout](const auto& c) + { current_layout.assign_cell_type(c, Lyt::technology::cell_type::LOGIC); }); auto bii = bdl_input_iterator{current_layout, params.operational_params.input_bdl_iterator_params, input_bdl_wires}; - detail::is_operational_impl is_operational_impl{ + is_operational_impl is_operational_impl{ current_layout, truth_table, params.operational_params, input_bdl_wires, output_bdl_wires, canvas_lyt}; for (auto i = 0u; i < truth_table.front().num_bits(); ++i, ++bii) { - const auto reason_for_filtering = - is_operational_impl.is_layout_invalid(bii.get_current_input_index(), cds_canvas); - - if (reason_for_filtering.has_value()) + if (const auto reason_for_filtering = + is_operational_impl.is_layout_invalid(bii.get_current_input_index()); + reason_for_filtering.has_value()) { switch (reason_for_filtering.value()) { - case detail::layout_invalidity_reason::POTENTIAL_POSITIVE_CHARGES: + case layout_invalidity_reason::POTENTIAL_POSITIVE_CHARGES: { - number_of_discarded_layouts_at_first_pruning++; + ++number_of_discarded_layouts_at_first_pruning; break; } - case detail::layout_invalidity_reason::PHYSICAL_INFEASIBILITY: + case layout_invalidity_reason::PHYSICAL_INFEASIBILITY: { - number_of_discarded_layouts_at_second_pruning++; + ++number_of_discarded_layouts_at_second_pruning; break; } - case detail::layout_invalidity_reason::IO_INSTABILITY: + case layout_invalidity_reason::IO_INSTABILITY: { - number_of_discarded_layouts_at_third_pruning++; + ++number_of_discarded_layouts_at_third_pruning; break; } default: @@ -627,13 +591,11 @@ class design_sidb_gates_impl } const std::lock_guard lock{mutex_to_protect_gate_candidates}; - gate_candidate.push_back(current_layout); + gate_candidates.emplace_back(current_layout); }; - gate_candidate.reserve(all_canvas_layouts.size()); - - const std::size_t num_threads = std::min(number_of_threads, all_canvas_layouts.size()); - const std::size_t chunk_size = (all_canvas_layouts.size() + num_threads - 1) / num_threads; + const std::size_t num_threads = std::min(number_of_threads, stats.number_of_layouts); + const std::size_t chunk_size = (stats.number_of_layouts + num_threads - 1) / num_threads; std::vector threads{}; threads.reserve(num_threads); @@ -641,14 +603,14 @@ class design_sidb_gates_impl for (std::size_t i = 0; i < num_threads; ++i) { threads.emplace_back( - [i, chunk_size, this, &conduct_pruning_steps]() + [i, chunk_size, &conduct_pruning_steps, &all_canvas_layouts] { const std::size_t start_index = i * chunk_size; const std::size_t end_index = std::min(start_index + chunk_size, all_canvas_layouts.size()); for (std::size_t j = start_index; j < end_index; ++j) { - conduct_pruning_steps(all_canvas_layouts[j]); + conduct_pruning_steps(all_canvas_layouts.at(j)); } }); } @@ -661,7 +623,7 @@ class design_sidb_gates_impl } } - return gate_candidate; + return gate_candidates; } /** * This function calculates all combinations of distributing a given number of SiDBs across a specified number of @@ -669,18 +631,18 @@ class design_sidb_gates_impl * * @return A vector containing all possible gate layouts generated from the combinations. */ - [[nodiscard]] std::vector determine_all_possible_canvas_layouts() const noexcept + [[nodiscard]] std::vector create_all_possible_canvas_layouts() const noexcept { const 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 = {}; - designed_gate_layouts.reserve(all_combinations.size()); + std::vector all_canvas_layouts = {}; + all_canvas_layouts.reserve(all_combinations.size()); - const auto add_cell_combination_to_layout = [this, &designed_gate_layouts](const auto& combination) noexcept + const auto add_cell_combination_to_layout = [this, &all_canvas_layouts](const auto& combination) noexcept { const auto layout_with_added_cells = convert_canvas_cell_indices_to_layout(combination); - designed_gate_layouts.push_back(layout_with_added_cells); + all_canvas_layouts.emplace_back(layout_with_added_cells); }; for (const auto& combination : all_combinations) @@ -688,29 +650,10 @@ class design_sidb_gates_impl add_cell_combination_to_layout(combination); } - return designed_gate_layouts; - } - /** - * This function adds SiDBs (given by indices) to the skeleton layout that is returned afterwards. - * - * @param cell_indices A vector of indices of cells to be added to the skeleton layout. - * @return A copy of the original layout (`skeleton_layout`) with SiDB cells added at specified indices. - */ - [[nodiscard]] Lyt skeleton_layout_with_canvas_sidbs(const std::vector& cell_indices) const noexcept - { - Lyt lyt_copy{skeleton_layout.clone()}; - - for (const auto i : cell_indices) - { - assert(i < all_sidbs_in_canvas.size() && "cell indices are out-of-range"); + // Shuffle all canvas layouts to distribute thread load when extracting gate layouts later + std::shuffle(all_canvas_layouts.begin(), all_canvas_layouts.end(), std::mt19937_64{std::random_device{}()}); - if (lyt_copy.get_cell_type(all_sidbs_in_canvas[i]) == sidb_technology::cell_type::EMPTY) - { - lyt_copy.assign_cell_type(all_sidbs_in_canvas[i], sidb_technology::cell_type::LOGIC); - } - } - - return lyt_copy; + return all_canvas_layouts; } /** * This function generates canvas SiDb layouts. @@ -729,12 +672,12 @@ class design_sidb_gates_impl // SiDBs cannot be placed on positions which are already occupied by atomic defects. if constexpr (is_sidb_defect_surface_v) { - if (skeleton_layout.get_sidb_defect(all_sidbs_in_canvas[i]).type != sidb_defect_type::NONE) + if (skeleton_layout.get_sidb_defect(all_sidbs_in_canvas.at(i)).type != sidb_defect_type::NONE) { continue; } } - lyt.assign_cell_type(all_sidbs_in_canvas[i], sidb_technology::cell_type::LOGIC); + lyt.assign_cell_type(all_sidbs_in_canvas.at(i), sidb_technology::cell_type::LOGIC); } // the skeleton can already exhibit some canvas SiDBs (partially filled canvas) @@ -749,6 +692,32 @@ class design_sidb_gates_impl return lyt; } + /** + * This function makes sure that underlying parameters for `is_operational` are set according to the given + * parameters for `design_sidb_gates`. + * + * @param params The given parameters for `design_sidb_gates`. + * @return The same parameters, but now the underlying parameters for `is_operational` are adjusted accordingly. + */ + static design_sidb_gates_params + set_operational_params_accordingly(const design_sidb_gates_params& params) noexcept + { + design_sidb_gates_params new_params{params}; + + if (!new_params.post_design_process.empty()) + { + new_params.operational_params.simulation_results_retention = + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS; + } + + if (new_params.design_mode == design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL) + { + new_params.operational_params.strategy_to_analyze_operational_status = + is_operational_params::operational_analysis_strategy::SIMULATION_ONLY; + } + + return new_params; + } }; } // namespace detail @@ -784,8 +753,8 @@ class design_sidb_gates_impl */ template [[nodiscard]] std::vector design_sidb_gates(const Lyt& skeleton, const std::vector& spec, - const design_sidb_gates_params>& params = {}, - design_sidb_gates_stats* stats = nullptr) noexcept + const design_sidb_gates_params& params = {}, + design_sidb_gates_stats* stats = 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"); @@ -805,13 +774,12 @@ template std::vector result{}; - if (params.design_mode == - design_sidb_gates_params>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER) + if (params.design_mode == design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER) { - result = p.run_automatic_exhaustive_gate_designer(); + result = p.run_exhaustive_gate_designer(); } - else if (params.design_mode == design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL) + else if (params.design_mode == design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL) { result = p.run_quickcell(); } diff --git a/include/fiction/algorithms/physical_design/exact.hpp b/include/fiction/algorithms/physical_design/exact.hpp index 7c6ea807b3..ae7599d3bc 100644 --- a/include/fiction/algorithms/physical_design/exact.hpp +++ b/include/fiction/algorithms/physical_design/exact.hpp @@ -853,7 +853,7 @@ class exact_impl z3::expr_vector eq{*ctx}; for (int i = 1; static_cast(i) < v.size(); ++i) { - eq.push_back(v[static_cast(i - 1)] == v[static_cast(i)]); + eq.push_back(v[i - 1] == v[i]); } return z3::mk_and(eq); diff --git a/include/fiction/algorithms/simulation/sidb/calculate_energy_and_state_type.hpp b/include/fiction/algorithms/simulation/sidb/calculate_energy_and_state_type.hpp index 6b2ebcf6ed..747e11729c 100644 --- a/include/fiction/algorithms/simulation/sidb/calculate_energy_and_state_type.hpp +++ b/include/fiction/algorithms/simulation/sidb/calculate_energy_and_state_type.hpp @@ -137,7 +137,7 @@ template bool correct_output = true; is_operational_params params{}; - params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; const auto operational_status = verify_logic_match(valid_layout, params, spec, input_index, input_bdl_wires, output_bdl_wires); diff --git a/include/fiction/algorithms/simulation/sidb/compare_by_ground_state_isolation.hpp b/include/fiction/algorithms/simulation/sidb/compare_by_ground_state_isolation.hpp new file mode 100644 index 0000000000..cb829be261 --- /dev/null +++ b/include/fiction/algorithms/simulation/sidb/compare_by_ground_state_isolation.hpp @@ -0,0 +1,237 @@ +// +// Created by Willem Lambooy on 05/02/2025. +// + +#ifndef COMPARE_BY_GROUND_STATE_ISOLATION +#define COMPARE_BY_GROUND_STATE_ISOLATION + +#include "fiction/algorithms/physical_design/compare_designed_sidb_gates.hpp" +#include "fiction/technology/charge_distribution_surface.hpp" + +#include + +#include +#include +#include +#include +#include +#include + +namespace fiction +{ + +namespace detail +{ + +template +[[nodiscard]] double get_ground_state_isolation(const std::vector>& sim_res) noexcept +{ + if (sim_res.size() == 1) + { + return std::numeric_limits::infinity(); + } + + phmap::btree_set system_energies{}; + + for (const charge_distribution_surface& cds : sim_res) + { + system_energies.insert(cds.get_system_energy()); + } + + return *system_energies.cbegin() - *std::next(system_energies.cbegin(), 1); +} + +} // namespace detail + +template +class compare_by_minimum_ground_state_isolation final : public designed_sidb_gate_comparator +{ + public: + using typename designed_sidb_gate_comparator::sidb_gate_design; + + explicit compare_by_minimum_ground_state_isolation( + const double sens = std::numeric_limits::epsilon()) noexcept : + designed_sidb_gate_comparator{sens} + {} + + [[nodiscard]] bool operator()(const sidb_gate_design& lhs, const sidb_gate_design& rhs) const noexcept override + { + return minimum_ground_state_isolation_over_all_inputs(lhs) < + minimum_ground_state_isolation_over_all_inputs(rhs); + } + + [[nodiscard]] bool equals(const sidb_gate_design& lhs, const sidb_gate_design& rhs) const noexcept override + { + return std::abs(minimum_ground_state_isolation_over_all_inputs(lhs) - + minimum_ground_state_isolation_over_all_inputs(rhs)) < this->sensitivity; + } + + private: + [[nodiscard]] double + minimum_ground_state_isolation_over_all_inputs(const sidb_gate_design& gate_design) const noexcept + { + std::vector ground_state_isolations{}; + ground_state_isolations.reserve(gate_design.simulation_results_per_input.size()); + + std::transform(gate_design.simulation_results_per_input.cbegin(), + gate_design.simulation_results_per_input.cend(), std::back_inserter(ground_state_isolations), + [](const auto& sim_res) { return detail::get_ground_state_isolation(sim_res); }); + + return *std::min_element(ground_state_isolations.cbegin(), ground_state_isolations.cend()); + } +}; + +template +class compare_by_average_ground_state_isolation final : public designed_sidb_gate_comparator +{ + public: + using typename designed_sidb_gate_comparator::sidb_gate_design; + + explicit compare_by_average_ground_state_isolation( + const double sens = std::numeric_limits::epsilon()) noexcept : + designed_sidb_gate_comparator{sens} + {} + + [[nodiscard]] bool operator()(const sidb_gate_design& lhs, const sidb_gate_design& rhs) const noexcept override + { + return average_ground_state_isolation_over_all_inputs(lhs) < + average_ground_state_isolation_over_all_inputs(rhs); + } + + [[nodiscard]] bool equals(const sidb_gate_design& lhs, const sidb_gate_design& rhs) const noexcept override + { + return std::abs(average_ground_state_isolation_over_all_inputs(lhs) - + average_ground_state_isolation_over_all_inputs(rhs)) < this->sensitivity; + } + + private: + [[nodiscard]] double + average_ground_state_isolation_over_all_inputs(const sidb_gate_design& gate_design) const noexcept + { + uint64_t count = 0; + + double accumulated_ground_state_isolation = 0.0; + + for (const auto& sim_res : gate_design.simulation_results_per_input) + { + if (sim_res.size() == 1) + { + continue; + } + + accumulated_ground_state_isolation += detail::get_ground_state_isolation(sim_res); + + ++count; + } + + return accumulated_ground_state_isolation / static_cast(count); + } +}; + +} // namespace fiction + +#endif // COMPARE_BY_GROUND_STATE_ISOLATION + +// +// /** +// * 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. When the minima are equal for two designed gate layouts, the average +// * energetic gap over each input is taken as a tiebreaker. +// * +// * @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 (uint64_t 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 +// { +// std::vector ground_state_isolations{}; +// std::transform(res_per_input.cbegin(), res_per_input.cend(), std::back_inserter(ground_state_isolations), +// get_ground_state_isolation); +// return *std::min_element(ground_state_isolations.cbegin(), ground_state_isolations.cend()); +// }; +// +// 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, +// &average_ground_state_isolation_for_all_inputs](const auto& lhs, const auto& rhs) noexcept +// { +// 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 +// for (auto& pair : pairs) +// { +// designed_gate_layouts.emplace_back(pair.first); +// } +// } diff --git a/include/fiction/algorithms/simulation/sidb/critical_temperature.hpp b/include/fiction/algorithms/simulation/sidb/critical_temperature.hpp index dfadf02ac6..c44bd5e4e8 100644 --- a/include/fiction/algorithms/simulation/sidb/critical_temperature.hpp +++ b/include/fiction/algorithms/simulation/sidb/critical_temperature.hpp @@ -162,7 +162,8 @@ class critical_temperature_impl auto input_bdl_wires = std::vector>{}; auto output_bdl_wires = std::vector>{}; - if (params.operational_params.op_condition == is_operational_params::operational_condition::REJECT_KINKS) + if (params.operational_params.op_condition_kinks == + is_operational_params::operational_condition_kinks::REJECT_KINKS) { input_bdl_wires = detect_bdl_wires(layout, params.operational_params.input_bdl_iterator_params.bdl_wire_params, @@ -197,8 +198,8 @@ class critical_temperature_impl sidb_energy_and_state_type energy_state_type{}; - if (params.operational_params.op_condition == - is_operational_params::operational_condition::REJECT_KINKS) + if (params.operational_params.op_condition_kinks == + is_operational_params::operational_condition_kinks::REJECT_KINKS) { energy_state_type = calculate_energy_and_state_type_with_kinks_rejected( distribution, sim_result.charge_distributions, spec, i, input_bdl_wires, output_bdl_wires); diff --git a/include/fiction/algorithms/simulation/sidb/defect_influence.hpp b/include/fiction/algorithms/simulation/sidb/defect_influence.hpp index 445c262ea9..3c0646ddf1 100644 --- a/include/fiction/algorithms/simulation/sidb/defect_influence.hpp +++ b/include/fiction/algorithms/simulation/sidb/defect_influence.hpp @@ -569,8 +569,8 @@ class defect_influence_impl { if (params.influence_def == defect_influence_params>::influence_definition::OPERATIONALITY_CHANGE) { - const auto [status, result] = is_operational(lyt_copy, spec.value(), params.operational_params); - if (status == operational_status::OPERATIONAL) + if (const auto& assessment_results = is_operational(lyt_copy, spec.value(), params.operational_params); + assessment_results.status == operational_status::OPERATIONAL) { lyt_copy.assign_sidb_defect(defect_cell, sidb_defect{sidb_defect_type::NONE}); return non_influential(); diff --git a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp index 3d19ae0a9e..da24d221a7 100644 --- a/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/displacement_robustness_domain.hpp @@ -159,9 +159,9 @@ class displacement_robustness_domain_impl truth_table{spec}, generator(rd()) { - assert( - (is_operational(layout, truth_table, params.operational_params).first == operational_status::OPERATIONAL) && - "The given layout is not a valid SiDB layout for the given Boolean function"); + assert((is_operational(layout, truth_table, params.operational_params).status == + operational_status::OPERATIONAL) && + "The given layout is not a valid SiDB layout for the given Boolean function"); if (params.analysis_mode == displacement_robustness_domain_params>::displacement_analysis_mode::RANDOM) @@ -204,7 +204,7 @@ class displacement_robustness_domain_impl const auto op_status = is_operational(lyt, truth_table, params.operational_params); { const std::lock_guard lock_domain{mutex_to_protect_displacement_robustness_domain}; - update_displacement_robustness_domain(domain, lyt, op_status.first); + update_displacement_robustness_domain(domain, lyt, op_status.status); } }; diff --git a/include/fiction/algorithms/simulation/sidb/is_operational.hpp b/include/fiction/algorithms/simulation/sidb/is_operational.hpp index cf48bc2b21..18a52bf10f 100644 --- a/include/fiction/algorithms/simulation/sidb/is_operational.hpp +++ b/include/fiction/algorithms/simulation/sidb/is_operational.hpp @@ -62,9 +62,9 @@ enum class operational_status : uint8_t struct is_operational_params { /** - * Condition to decide whether a layout is operational or non-operational. + * Condition to decide whether a layout is operational or non-operational, relating to kinks. */ - enum class operational_condition : uint8_t + enum class operational_condition_kinks : uint8_t { /** * Even if the I/O pins show kinks, the layout is still considered as operational. @@ -75,20 +75,23 @@ struct is_operational_params */ REJECT_KINKS }; - /** - * Simulation method to determine if the layout is operational or non-operational. There are three possible - * strategies: - * - * - `SIMULATION_ONLY`: This setting does not apply any filtering strategies to determine if the layout is - * operational. Instead, it relies solely on physical simulation to make this determination. - * - `FILTER_ONLY`: This setting does only apply filtering strategies to determine if the layout is - * non-operational. If the layout passes all filtering strategies, it is considered operational. This is only an - * approximation. It may be possible that the layout is non-operational, but the filtering strategies do not detect - * it. - * - `FILTER_THEN_SIMULATION`: Before a physical simulation is conducted, the algorithm checks if filtering - * strategies have detected whether the layout is non-operational. This only provides any runtime benefits if kinks - * are rejected. + * Condition to decide whether a layout is operational or non-operational, relating to positive charges. + */ + enum class operational_condition_positive_charges : uint8_t + { + /** + * Positive charges may not be able to occur. In the case of the converse being true, the layout is considered + * as non-operational. + */ + REJECT_POSITIVE_CHARGES, + /** + * Even if positive charges can occur, the layout is still considered as operational. + */ + TOLERATE_POSITIVE_CHARGES, + }; + /** + * Simulation method to determine if the layout is operational or non-operational. */ enum class operational_analysis_strategy : uint8_t { @@ -101,7 +104,7 @@ struct is_operational_params * Apply filtering exclusively to determine whether the layout is non-operational. If the layout * passes all filter steps, it is considered operational. * - * @note This is an extremely fast approximation that may sometimes lead to false positives. + * @note This is an extremely fast approximation that may lead to false positives. */ FILTER_ONLY, /** @@ -110,6 +113,35 @@ struct is_operational_params */ FILTER_THEN_SIMULATION }; + /** + * The termination condition for assessment of the operational status of the given layout. + */ + enum class termination_condition : uint8_t + { + /** + * The assessment for the given layout terminates either when it is found to be operational for all input + * combinations, or an input combination is found for which the layout is not operational. + */ + ON_FIRST_NON_OPERATIONAL, + /** + * The operational status is assessed for all input combinations. + */ + ALL_INPUT_COMBINATIONS_ASSESSED + }; + /** + * 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. */ @@ -123,14 +155,96 @@ struct is_operational_params */ bdl_input_iterator_params input_bdl_iterator_params{}; /** - * Condition to decide whether a layout is operational or non-operational. + * Condition to decide whether a layout is operational or non-operational, relating to kinks. + */ + operational_condition_kinks op_condition_kinks = operational_condition_kinks::TOLERATE_KINKS; + /** + * Condition to decide whether a layout is operational or non-operational, relating to kinks. */ - operational_condition op_condition = operational_condition::TOLERATE_KINKS; + operational_condition_positive_charges op_condition_positive_charges = + operational_condition_positive_charges::REJECT_POSITIVE_CHARGES; /** * Strategy to determine whether a layout is operational or non-operational. */ operational_analysis_strategy strategy_to_analyze_operational_status = operational_analysis_strategy::SIMULATION_ONLY; + /** + * Condition to decide when to terminate the assessment of the operational status of the given layout. + */ + termination_condition termination_cond = termination_condition::ON_FIRST_NON_OPERATIONAL; + /** + * 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 results from the operational status assessment. + * + * @tparam Lyt SiDB cell-level layout type. + */ +template +struct operational_assessment +{ + /** + * This struct collects the information for a specific input combination that was obtained during the assessment. + */ + struct operational_assessment_for_input + { + /** + * Standard constructor that only sets the operational status. + */ + explicit operational_assessment_for_input(const operational_status op_status) noexcept : status{op_status} {} + /** + * The assessed operational status of the given layout under one input combination. + */ + operational_status status; + /** + * The charge distributions obtained for one input combination that was tested. + */ + std::optional>> simulation_results{}; + }; + /** + * Standard constructor that only sets the operational status. + */ + explicit operational_assessment(const operational_status op_status) noexcept : status{op_status} {} + /** + * The assessed operational status of the given layout. The status `OPERATIONAL` is given if and only the layout is + * operational under all input combinations. + */ + operational_status status; + /** + * When the termination condition is set to `ALL_INPUT_COMBINATIONS_ASSESSED`, the operational status for each + * respective input combination is stored here, sorted by their binary representation. When the simulation retention + * is set to `KEEP_SIMULATION_RESULTS`, this optional structure is also populated. + */ + std::optional> assessment_per_input{}; + /** + * The number of input combinations tested. + */ + std::size_t simulator_invocations{0}; + /** + * Extracts the simulation results contained in this operational assessment through moves. + * + * @return A vector containing the simulation results for each respective input that was assessed. + */ + std::vector>> extract_simulation_results_per_input() const noexcept + { + assert(assessment_per_input.has_value() && "Assessment results per input are not present."); + assert(!assessment_per_input.value().empty() && "No input combinations were assessed."); + assert(assessment_per_input.value().front().simulation_results.has_value() && + "Simulation results were not retained during assessment."); + + std::vector>> simulation_results_per_input{}; + simulation_results_per_input.reserve(assessment_per_input.value().size()); + + for (operational_assessment_for_input assessment : assessment_per_input.value()) + { + simulation_results_per_input.push_back(std::move(assessment.simulation_results.value())); + } + + return simulation_results_per_input; + } }; namespace detail @@ -193,7 +307,7 @@ class is_operational_impl * Constructor to initialize the algorithm with a layout and parameters. * * @param lyt The SiDB cell-level layout to be checked. - * @param spec Expected Boolean function of the layout given as a multi-output truth table. + * @param tt Expected Boolean function of the layout given as a multi-output truth table. * @param params Parameters for the `is_operational` algorithm. */ is_operational_impl(const Lyt& lyt, const std::vector& tt, const is_operational_params& params) : @@ -236,12 +350,11 @@ class is_operational_impl number_of_output_wires{output_bdl_wires.size()}, number_of_input_wires{input_bdl_wires.size()} {} - /** * Constructor to initialize the algorithm with a layout, parameters, input and output wires, and a canvas layout. * * @param lyt The SiDB cell-level layout to be checked. - * @param spec Expected Boolean function of the layout given as a multi-output truth table. + * @param tt Expected Boolean function of the layout given as a multi-output truth table. * @param params Parameters for the `is_operational` algorithm. * @param input_wires BDL input wires of lyt. * @param output_wires BDL output wires of lyt. @@ -262,25 +375,19 @@ class is_operational_impl number_of_input_wires{input_bdl_wires.size()}, canvas_lyt{c_lyt} { - if (params.op_condition == is_operational_params::operational_condition::TOLERATE_KINKS) + if (params.op_condition_kinks == is_operational_params::operational_condition_kinks::TOLERATE_KINKS) { output_bdl_pairs = detect_bdl_pairs(layout, sidb_technology::cell_type::OUTPUT, params.input_bdl_iterator_params.bdl_wire_params.bdl_pairs_params); } - canvas_lyt.foreach_cell( - [this](const auto& c) - { - dependent_cell = c; - return false; - }); } - /** * Constructor to initialize the algorithm with a layout and parameters. * * @param lyt The SiDB cell-level layout to be checked. - * @param spec Expected Boolean function of the layout given as a multi-output truth table. + * @param tt Expected Boolean function of the layout given as a multi-output truth table. * @param params Parameters for the `is_operational` algorithm. + * @param c_lyt Canvas layout. */ is_operational_impl(const Lyt& lyt, const std::vector& tt, const is_operational_params& params, const Lyt& c_lyt) : @@ -298,7 +405,6 @@ class is_operational_impl number_of_input_wires{input_bdl_wires.size()}, canvas_lyt{c_lyt} {} - /** * This function evaluates whether the given layout is invalid, i.e., it cannot implement the given Boolean * function. This is done in three separate filtering steps: (1) discarding SiDB layouts with @@ -306,46 +412,34 @@ class is_operational_impl * do not satisfy physical model constraints under the I/O pin conditions required for the desired Boolean function, * and (3) detecting I/O signal instability. * - * @tparam ChargeLyt The charge distribution surface layout type. * @param input_pattern The current input pattern. - * @param cds_canvas The charge distribution of the canvas layout. - * @param dependent_cell A dependent-cell of the canvas SiDBs. * @return A `layout_invalidity_reason` object indicating why the layout is non-operational; or `std::nullopt` if it * could not certainly be determined to be in fact non-operational. */ - template - [[nodiscard]] std::optional is_layout_invalid(const uint64_t input_pattern, - ChargeLyt& cds_canvas) noexcept + [[nodiscard]] std::optional is_layout_invalid(const uint64_t input_pattern) noexcept { - static_assert(is_charge_distribution_surface_v, "ChargeLyt is not a charge distribution surface"); - bii = input_pattern; - ChargeLyt cds_layout{*bii}; + charge_distribution_surface cds_layout{*bii}; cds_layout.assign_all_charge_states(sidb_charge_state::NEGATIVE); cds_layout.assign_physical_parameters(parameters.simulation_parameters); - if (can_positive_charges_occur(cds_layout, parameters.simulation_parameters)) + if (parameters.op_condition_positive_charges == + is_operational_params::operational_condition_positive_charges::REJECT_POSITIVE_CHARGES && + can_positive_charges_occur(cds_layout, parameters.simulation_parameters)) { return layout_invalidity_reason::POTENTIAL_POSITIVE_CHARGES; } - cds_layout.assign_dependent_cell(dependent_cell); - cds_canvas.assign_dependent_cell(dependent_cell); - const auto input_index = bii.get_current_input_index(); set_charge_distribution_of_input_pins(cds_layout, bii.get_current_input_index()); set_charge_distribution_of_output_pins(cds_layout, evaluate_output(truth_table, input_index)); - const auto physical_validity = is_physical_validity_feasible(cds_layout); - - if (physical_validity.has_value()) + if (const auto physical_validity = is_physical_validity_feasible(cds_layout); physical_validity.has_value()) { - const auto output_index = evaluate_output(truth_table, input_index); - - if (is_io_signal_unstable(cds_layout, truth_table.front().num_bits(), input_index, output_index, - physical_validity.value())) + if (const auto output_index = evaluate_output(truth_table, input_index); is_io_signal_unstable( + cds_layout, truth_table.front().num_bits(), input_index, output_index, physical_validity.value())) { return layout_invalidity_reason::IO_INSTABILITY; }; @@ -355,7 +449,6 @@ class is_operational_impl return layout_invalidity_reason::PHYSICAL_INFEASIBILITY; } - /** * Run the `is_operational` algorithm. * @@ -365,18 +458,11 @@ class is_operational_impl * @return Pair with the first element indicating the operational status (either `OPERATIONAL` or `NON_OPERATIONAL`) * and the second element indicating the reason if it is non-operational. */ - [[nodiscard]] std::pair run() noexcept + [[nodiscard]] std::pair, non_operationality_reason> run() noexcept { - bool at_least_one_layout_is_kink_induced_non_operational = false; - if (!canvas_lyt.is_empty()) { - charge_distribution_surface cds_canvas{canvas_lyt}; - - cds_canvas.assign_dependent_cell(dependent_cell); - cds_canvas.assign_physical_parameters(parameters.simulation_parameters); - - if ((parameters.op_condition == is_operational_params::operational_condition::REJECT_KINKS && + if ((parameters.op_condition_kinks == is_operational_params::operational_condition_kinks::REJECT_KINKS && parameters.strategy_to_analyze_operational_status == is_operational_params::operational_analysis_strategy::FILTER_THEN_SIMULATION) || parameters.strategy_to_analyze_operational_status == @@ -385,9 +471,10 @@ class is_operational_impl // number of different input combinations for (auto i = 0u; i < truth_table.front().num_bits(); ++i, ++bii) { - if (is_layout_invalid(bii.get_current_input_index(), cds_canvas)) + if (is_layout_invalid(bii.get_current_input_index())) { - return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; + return {operational_assessment{operational_status::NON_OPERATIONAL}, + non_operationality_reason::LOGIC_MISMATCH}; } } } @@ -399,62 +486,166 @@ class is_operational_impl is_operational_params::operational_analysis_strategy::FILTER_ONLY && !canvas_lyt.is_empty()) { - return {operational_status::OPERATIONAL, non_operationality_reason::NONE}; + return {operational_assessment{operational_status::OPERATIONAL}, non_operationality_reason::NONE}; } - if (parameters.strategy_to_analyze_operational_status == - is_operational_params::operational_analysis_strategy::SIMULATION_ONLY || - parameters.strategy_to_analyze_operational_status == - is_operational_params::operational_analysis_strategy::FILTER_THEN_SIMULATION || - canvas_lyt.is_empty()) + if (parameters.strategy_to_analyze_operational_status != + is_operational_params::operational_analysis_strategy::SIMULATION_ONLY && + parameters.strategy_to_analyze_operational_status != + is_operational_params::operational_analysis_strategy::FILTER_THEN_SIMULATION && + !canvas_lyt.is_empty()) + { + return {operational_assessment{operational_status::OPERATIONAL}, non_operationality_reason::NONE}; + } + + operational_assessment assessment_results{operational_status::OPERATIONAL}; + + // when `termination_condition::ALL_INPUT_COMBINATIONS_ASSESSED` is set, the results of the operational status + // assessment are also stored for each input separately + std::vector::operational_assessment_for_input> + assessment_results_per_input{}; + if (parameters.termination_cond == + is_operational_params::termination_condition::ALL_INPUT_COMBINATIONS_ASSESSED) + { + assessment_results_per_input.reserve(truth_table.front().num_bits()); + } + + // 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()); + } + + bii = 0; + // number of different input combinations + for (auto i = 0u; i < truth_table.front().num_bits(); ++i, ++bii) { - bii = 0; - // number of different input combinations - for (auto i = 0u; i < truth_table.front().num_bits(); ++i, ++bii) + typename operational_assessment::operational_assessment_for_input + assessment_results_for_this_input_combination{operational_status::OPERATIONAL}; + + // if positively charged SiDBs can occur, the SiDB layout is considered as non-operational + if (parameters.op_condition_positive_charges == + is_operational_params::operational_condition_positive_charges::REJECT_POSITIVE_CHARGES && + can_positive_charges_occur(*bii, parameters.simulation_parameters)) { - // if positively charged SiDBs can occur, the SiDB layout is considered as non-operational - if (can_positive_charges_occur(*bii, parameters.simulation_parameters)) + assessment_results.status = operational_status::NON_OPERATIONAL; + + if (parameters.termination_cond == + is_operational_params::termination_condition::ON_FIRST_NON_OPERATIONAL) { - return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; + return {assessment_results, non_operationality_reason::LOGIC_MISMATCH}; } - ++simulator_invocations; - // performs physical simulation of a given SiDB layout at a given input combination - const auto simulation_results = physical_simulation_of_layout(bii); + // all input combinations are assessed + + assessment_results_for_this_input_combination.status = operational_status::NON_OPERATIONAL; + + assessment_results_per_input.push_back(std::move(assessment_results_for_this_input_combination)); + + continue; + } + + ++assessment_results.simulator_invocations; + + // performs physical simulation of a given SiDB layout at a given input combination + const auto simulation_results = physical_simulation_of_layout(bii); + + // if no physically valid charge distributions were found, the layout is non-operational + if (simulation_results.charge_distributions.empty()) + { + assessment_results.status = operational_status::NON_OPERATIONAL; - // if no physically valid charge distributions were found, the layout is non-operational - if (simulation_results.charge_distributions.empty()) + if (parameters.termination_cond == + is_operational_params::termination_condition::ON_FIRST_NON_OPERATIONAL) { - return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; + return {assessment_results, non_operationality_reason::LOGIC_MISMATCH}; } - const auto ground_states = groundstate_from_simulation_result(simulation_results); + // all input combinations are assessed + + assessment_results_for_this_input_combination.status = operational_status::NON_OPERATIONAL; + + assessment_results_for_this_input_combination.simulation_results.emplace(); + + assessment_results_per_input.push_back(std::move(assessment_results_for_this_input_combination)); + + continue; + } + + const auto ground_states = groundstate_from_simulation_result(simulation_results); - for (const auto& gs : ground_states) + for (const auto& gs : ground_states) + { + const auto [op_status, non_op_reason] = verify_logic_match_of_cds(gs, i); + + if (op_status == operational_status::OPERATIONAL) { - const auto [op_status, non_op_reason] = verify_logic_match_of_cds(gs, i); - if (op_status == operational_status::NON_OPERATIONAL && - non_op_reason == non_operationality_reason::LOGIC_MISMATCH) + continue; + } + + // op_status == operation_status::NON_OPERATIONAL + + assessment_results.status = operational_status::NON_OPERATIONAL; + + if (parameters.termination_cond == + is_operational_params::termination_condition::ON_FIRST_NON_OPERATIONAL) + { + if (non_op_reason == non_operationality_reason::LOGIC_MISMATCH) { - return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; + return {assessment_results, non_operationality_reason::LOGIC_MISMATCH}; } - if (op_status == operational_status::NON_OPERATIONAL && - non_op_reason == non_operationality_reason::KINKS && - parameters.op_condition == is_operational_params::operational_condition::REJECT_KINKS) + + if (non_op_reason == non_operationality_reason::KINKS && + parameters.op_condition_kinks == + is_operational_params::operational_condition_kinks::REJECT_KINKS) { - return {operational_status::NON_OPERATIONAL, non_operationality_reason::KINKS}; + return {assessment_results, non_operationality_reason::KINKS}; } } + + // all input combinations are assessed + + assessment_results_for_this_input_combination.status = operational_status::NON_OPERATIONAL; + } + + // store the assessment results for this input combination when the termination condition is set to + // `termination_condition::ALL_INPUT_COMBINATION_ASSESSED` or the simulation result retention is set to + // `simulation_results_mode::KEEP_SIMULATION_RESULTS` + if (parameters.termination_cond == + is_operational_params::termination_condition::ALL_INPUT_COMBINATIONS_ASSESSED || + parameters.simulation_results_retention == + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS) + { + // 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) + { + assessment_results_for_this_input_combination.simulation_results = + std::move(simulation_results.charge_distributions); + } + + assessment_results_per_input.push_back(std::move(assessment_results_for_this_input_combination)); } } - if (at_least_one_layout_is_kink_induced_non_operational) + // store the assessment results for all input combinations when the termination condition is set to + // `termination_condition::ALL_INPUT_COMBINATION_ASSESSED` or the simulation result retention is set to + // `simulation_results_mode::KEEP_SIMULATION_RESULTS` + if (parameters.termination_cond == + is_operational_params::termination_condition::ALL_INPUT_COMBINATIONS_ASSESSED || + parameters.simulation_results_retention == + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS) { - return {operational_status::NON_OPERATIONAL, non_operationality_reason::KINKS}; + assessment_results.assessment_per_input = std::move(assessment_results_per_input); } - // if we made it here, the layout is operational - return {operational_status::OPERATIONAL, non_operationality_reason::NONE}; + // note: when all input combinations are assessed per termination condition, the assessment can yield the layout + // is non-operational, yet we do not give a reason + return {assessment_results, non_operationality_reason::NONE}; } /** * Checks if the given charge distribution correctly encodes the expected logic for the given input pattern, @@ -480,7 +671,9 @@ class is_operational_impl auto non_operational_reason = non_operationality_reason::LOGIC_MISMATCH; // if positively charged SiDBs can occur, the SiDB layout is considered as non-operational - if (can_positive_charges_occur(given_cds, parameters.simulation_parameters)) + if (parameters.op_condition_positive_charges == + is_operational_params::operational_condition_positive_charges::REJECT_POSITIVE_CHARGES && + can_positive_charges_occur(given_cds, parameters.simulation_parameters)) { return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; } @@ -517,7 +710,7 @@ class is_operational_impl } } - if (parameters.op_condition == is_operational_params::operational_condition::REJECT_KINKS) + if (parameters.op_condition_kinks == is_operational_params::operational_condition_kinks::REJECT_KINKS) { assert(!input_bdl_wires.empty() && "No input wires provided."); assert(!output_bdl_wires.empty() && "No output wires provided."); @@ -553,16 +746,16 @@ class is_operational_impl assert((truth_table.size() == output_bdl_wires.size()) && "Number of truth tables and output BDL pairs does not match"); - std::vector> + std::vector> non_operational_input_pattern_and_non_operationality_reason{}; // 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)) + if (parameters.op_condition_positive_charges == + is_operational_params::operational_condition_positive_charges::REJECT_POSITIVE_CHARGES && + can_positive_charges_occur(*bii, parameters.simulation_parameters)) { continue; } @@ -591,16 +784,6 @@ class is_operational_impl // if we made it here, the layout is operational return non_operational_input_pattern_and_non_operationality_reason; } - /** - * Returns the total number of simulator invocations. - * - * @return The number of simulator invocations. - */ - [[nodiscard]] std::size_t get_number_of_simulator_invocations() const noexcept - { - return simulator_invocations; - } - /** * This function determines if there is a charge distribution of the canvas SiDBs for which the charge distribution * of the whole layout is physically valid. @@ -612,6 +795,20 @@ class is_operational_impl [[nodiscard]] std::optional is_physical_validity_feasible(charge_distribution_surface& cds_layout) const noexcept { + if (canvas_lyt.num_cells() == 0) + { + cds_layout.update_after_charge_change(dependent_cell_mode::FIXED, + energy_calculation::KEEP_OLD_ENERGY_VALUE); + + if (cds_layout.is_physically_valid()) + { + cds_layout.recompute_system_energy(); + return cds_layout.get_system_energy(); + } + + return std::nullopt; + } + auto min_energy = std::numeric_limits::infinity(); uint64_t canvas_charge_index = 0; @@ -619,7 +816,8 @@ class is_operational_impl charge_distribution_surface cds_canvas_copy{canvas_lyt}; cds_canvas_copy.assign_base_number(2); cds_canvas_copy.assign_charge_index(canvas_charge_index); - cds_canvas_copy.assign_dependent_cell(dependent_cell); + cds_canvas_copy.assign_dependent_cell(cds_canvas_copy.get_sidb_order().front()); + cds_layout.assign_dependent_cell(cds_canvas_copy.get_sidb_order().front()); const auto max_index = cds_canvas_copy.get_max_charge_index(); @@ -866,9 +1064,8 @@ class is_operational_impl set_charge_distribution_of_input_pins(cds_layout, kink_states_input); set_charge_distribution_of_output_pins(cds_layout, output_wire_index); - const auto physical_validity = is_physical_validity_feasible(cds_layout); - - if (physical_validity.has_value()) + if (const auto physical_validity = is_physical_validity_feasible(cds_layout); + physical_validity.has_value()) { if (physical_validity.value() + constants::ERROR_MARGIN < minimal_energy_of_physically_valid_layout) { @@ -910,11 +1107,6 @@ class is_operational_impl * Output BDL wires. */ std::vector> output_bdl_wires; - /** - * Number of simulator invocations. - */ - std::size_t simulator_invocations{0}; - /** * Number of output BDL wires. */ @@ -927,10 +1119,6 @@ class is_operational_impl * Layout consisting of all canvas SiDBs. */ Lyt canvas_lyt{}; - /** - * Dependent cell of the canvas SiDBs. - */ - cell dependent_cell{}; /** * This function conducts physical simulation of the given SiDB layout. * The simulation results are stored in the `sim_result` variable. @@ -1055,6 +1243,7 @@ class is_operational_impl * * @param ground_state The ground state charge distribution surface. * @param bdl BDL pair to be evaluated. + * @param port Port direction where the BDL pair to be evaluated is. * @return `true` if `0` is encoded, `false` otherwise. */ [[nodiscard]] bool encodes_bit_zero(const charge_distribution_surface& ground_state, @@ -1074,6 +1263,7 @@ class is_operational_impl * * @param ground_state The ground state charge distribution surface. * @param bdl BDL pair to be evaluated. + * @param port Port direction where the BDL pair to be evaluated is. * @return `true` if `1` is encoded, `false` otherwise. */ [[nodiscard]] bool encodes_bit_one(const charge_distribution_surface& ground_state, @@ -1104,12 +1294,12 @@ class is_operational_impl * @param lyt The SiDB cell-level layout to be checked. * @param spec Expected Boolean function of the layout given as a multi-output truth table. * @param params Parameters for the `is_operational` algorithm. - * @return A pair containing the operational status of the SiDB layout (either `OPERATIONAL` or `NON_OPERATIONAL`) and - * the number of input combinations tested. + * @return A datatype containing the operational status of the gate-level layout (either `OPERATIONAL` or `NON_OPERATIONAL`) + * along with auxiliary statistics. */ template -[[nodiscard]] std::pair -is_operational(const Lyt& lyt, const std::vector& spec, const is_operational_params& params = {}) noexcept +[[nodiscard]] operational_assessment is_operational(const Lyt& lyt, const std::vector& spec, + const is_operational_params& params = {}) 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"); @@ -1125,11 +1315,10 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational detail::is_operational_impl p{lyt, spec, params}; - const auto [status, _] = p.run(); + const auto [assessment_result, _] = p.run(); - return {status, p.get_number_of_simulator_invocations()}; + return assessment_result; } - /** * Determine the operational status of an SiDB layout. * @@ -1145,11 +1334,11 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational * @param input_bdl_wire Optional BDL input wires of lyt. * @param output_bdl_wire Optional BDL output wires of lyt. * @param canvas_lyt Optional canvas layout. - * @return A pair containing the operational status of the SiDB layout (either `OPERATIONAL` or `NON_OPERATIONAL`) and - * the number of input combinations tested. + * @return A datatype containing the operational status of the gate-level layout (either `OPERATIONAL` or `NON_OPERATIONAL`) + * along with auxiliary statistics. */ template -[[nodiscard]] std::pair +[[nodiscard]] operational_assessment is_operational(const Lyt& lyt, const std::vector& spec, const is_operational_params& params, const std::vector>& input_bdl_wire, const std::vector>& output_bdl_wire, const std::optional& canvas_lyt = std::nullopt) noexcept @@ -1170,14 +1359,12 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational { detail::is_operational_impl p{lyt, spec, params, input_bdl_wire, output_bdl_wire, canvas_lyt.value()}; - const auto [status, _] = p.run(); + const auto [assessment_result, _] = p.run(); - return {status, p.get_number_of_simulator_invocations()}; + return assessment_result; } - const auto logic_cells = lyt.get_cells_by_type(technology::cell_type::LOGIC); - - if (!logic_cells.empty()) + if (const auto logic_cells = lyt.get_cells_by_type(technology::cell_type::LOGIC); !logic_cells.empty()) { Lyt c_lyt{}; @@ -1188,16 +1375,16 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational detail::is_operational_impl p{lyt, spec, params, input_bdl_wire, output_bdl_wire, c_lyt}; - const auto [status, _] = p.run(); + const auto [assessment_result, _] = p.run(); - return {status, p.get_number_of_simulator_invocations()}; + return assessment_result; } detail::is_operational_impl p{lyt, spec, params, input_bdl_wire, output_bdl_wire}; - const auto [status, _] = p.run(); + const auto [assessment_result, _] = p.run(); - return {status, p.get_number_of_simulator_invocations()}; + return assessment_result; } /** * This function determines the input combinations for which the layout is operational. @@ -1206,7 +1393,7 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational * @tparam TT Type of the truth table. * @param lyt The SiDB layout. * @param spec Vector of truth table specifications. - * @param params Parameters to simulate if a input combination is operational. + * @param params Parameters to simulate if an input combination is operational. * @return The count of operational input combinations. */ template @@ -1252,7 +1439,7 @@ template * @tparam TT Type of the truth table. * @param lyt The SiDB layout. * @param spec Vector of truth table specifications. - * @param params Parameters to simulate if a input combination is operational. + * @param params Parameters to simulate if an input combination is operational. * @param input_bdl_wire Optional BDL input wires of lyt. * @param output_bdl_wire Optional BDL output wires of lyt. * @param canvas_lyt Optional canvas layout. @@ -1320,7 +1507,6 @@ operational_input_patterns(const Lyt& lyt, const std::vector& spec, const is return input_patterns; } - /** * This function determines all input combinations for which kinks induce the SiDB layout to become non-operational. * This means that the layout is operational if kinks would be accepted. @@ -1354,7 +1540,7 @@ kink_induced_non_operational_input_patterns(const Lyt& lyt, const std::vector p{lyt, spec, params_with_rejecting_kinks}; @@ -1410,7 +1596,7 @@ template is_operational_params params_with_rejecting_kinks = params; - params_with_rejecting_kinks.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params_with_rejecting_kinks.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; if (canvas_lyt.has_value()) { @@ -1482,13 +1668,13 @@ template { return a.num_vars() != b.num_vars(); }) == spec.cend()); is_operational_params params_with_rejecting_kinks = params; - params_with_rejecting_kinks.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params_with_rejecting_kinks.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; detail::is_operational_impl p{lyt, spec, params_with_rejecting_kinks}; - const auto [op_status, non_op_reason] = p.run(); + const auto [assessment_result, non_op_reason] = p.run(); - return op_status == operational_status::NON_OPERATIONAL && + return assessment_result.status == operational_status::NON_OPERATIONAL && non_op_reason == detail::non_operationality_reason::KINKS; } @@ -1530,24 +1716,24 @@ template { return a.num_vars() != b.num_vars(); }) == spec.cend()); is_operational_params params_with_rejecting_kinks = params; - params_with_rejecting_kinks.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params_with_rejecting_kinks.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; if (canvas_lyt.has_value()) { detail::is_operational_impl p{ lyt, spec, params_with_rejecting_kinks, input_bdl_wire, output_bdl_wire, canvas_lyt.value()}; - const auto [op_status, non_op_reason] = p.run(); + const auto [assessment_result, non_op_reason] = p.run(); - return op_status == operational_status::NON_OPERATIONAL && + return assessment_result.status == operational_status::NON_OPERATIONAL && non_op_reason == detail::non_operationality_reason::KINKS; } detail::is_operational_impl p{lyt, spec, params_with_rejecting_kinks, input_bdl_wire, output_bdl_wire}; - const auto [op_status, non_op_reason] = p.run(); + const auto [assessment_result, non_op_reason] = p.run(); - return op_status == operational_status::NON_OPERATIONAL && + return assessment_result.status == operational_status::NON_OPERATIONAL && non_op_reason == detail::non_operationality_reason::KINKS; } /** diff --git a/include/fiction/algorithms/simulation/sidb/minimum_energy.hpp b/include/fiction/algorithms/simulation/sidb/minimum_energy.hpp index 03fffee459..74c6cdfb75 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. */ diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 268e28bb3e..f36dc4ea32 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -1141,12 +1141,12 @@ 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, - input_bdl_wires, output_bdl_wires, std::optional{canvas_lyt}); + const auto& assessment_results = is_operational(layout, truth_table, op_params_set_dimension_values, + input_bdl_wires, output_bdl_wires, std::optional{canvas_lyt}); - num_simulator_invocations += sim_calls; + num_simulator_invocations += assessment_results.simulator_invocations; - if (status == operational_status::NON_OPERATIONAL) + if (assessment_results.status == operational_status::NON_OPERATIONAL) { return non_operational(); } diff --git a/include/fiction/technology/charge_distribution_surface.hpp b/include/fiction/technology/charge_distribution_surface.hpp index 1610e58670..a2c095197b 100644 --- a/include/fiction/technology/charge_distribution_surface.hpp +++ b/include/fiction/technology/charge_distribution_surface.hpp @@ -1380,12 +1380,7 @@ class charge_distribution_surface : public Lyt strg->dependent_cell_in_sub_layout = false; // check if all SiDBs are negatively charged - this->foreach_cell( - [this]([[maybe_unused]] const auto& c) - { - assert(this->get_charge_state(c) == sidb_charge_state::NEGATIVE && - "All SiDBs have to be negatively charged"); - }); + assert(this->num_negative_sidbs() == this->num_cells() && "All SiDBs have to be negatively charged"); // Each SiDB is checked to see if the local electrostatic potential is high enough // to cause a positively charged SiDB diff --git a/include/fiction/technology/sidb_cluster_hierarchy.hpp b/include/fiction/technology/sidb_cluster_hierarchy.hpp index 7b0cc6d701..64c22e19e4 100644 --- a/include/fiction/technology/sidb_cluster_hierarchy.hpp +++ b/include/fiction/technology/sidb_cluster_hierarchy.hpp @@ -1155,7 +1155,7 @@ struct sidb_cluster * @param pst Projector state of which the corresponding compositions are requested. * @return The compositions associated with the multiset charge configuration of the projecting cluster. */ -[[nodiscard]] static const std::vector& +[[nodiscard]] static inline const std::vector& get_projector_state_compositions(const sidb_cluster_projector_state& pst) noexcept { return std::ref(pst.cluster->charge_space.find(sidb_cluster_charge_state{pst.multiset_conf})->compositions); @@ -1219,7 +1219,8 @@ to_unique_sidb_cluster(const uint64_t total_sidbs, const sidb_binary_cluster_hie * @param n A node from a binary cluster hierarchy, as for instance returned by parsing ALGLIB's result. * @return A uniquely identified node in a decorated cluster hierarchy that follows the "general tree" structure. */ -[[nodiscard]] static sidb_cluster_ptr to_sidb_cluster(const sidb_binary_cluster_hierarchy_node& n) noexcept +[[nodiscard]] [[maybe_unused]] static sidb_cluster_ptr +to_sidb_cluster(const sidb_binary_cluster_hierarchy_node& n) noexcept { uint64_t uid = n.c.size(); diff --git a/include/fiction/technology/sidb_on_the_fly_gate_library.hpp b/include/fiction/technology/sidb_on_the_fly_gate_library.hpp index 091dd1d8c5..905ff682be 100644 --- a/include/fiction/technology/sidb_on_the_fly_gate_library.hpp +++ b/include/fiction/technology/sidb_on_the_fly_gate_library.hpp @@ -109,7 +109,7 @@ struct sidb_on_the_fly_gate_library_params /** * This struct holds parameters to design SiDB gates. */ - design_sidb_gates_params> design_gate_params{}; + design_sidb_gates_params> design_gate_params{}; /** * This variable defines the number of canvas SiDBs dedicated to complex gates, such as crossing, double wire, * and half-adder. @@ -416,12 +416,11 @@ class sidb_on_the_fly_gate_library : public fcn_gate_library(status == operational_status::OPERATIONAL); } /** @@ -601,7 +600,7 @@ class sidb_on_the_fly_gate_library : public fcn_gate_library -[[nodiscard]] inline std::vector +[[nodiscard]] std::vector all_coordinates_in_spanned_area(const CoordinateType& cell_first_corner, const CoordinateType& cell_second_corner) noexcept { @@ -632,10 +632,10 @@ all_coordinates_in_spanned_area(const CoordinateType& cell_first_corner, auto cell_first_corner_cube = siqad::to_fiction_coord(cell_first_corner); auto cell_second_corner_cube = siqad::to_fiction_coord(cell_second_corner); - cube::coord_t nw_cell{std::min(cell_first_corner_cube.x, cell_second_corner_cube.x), - std::min(cell_first_corner_cube.y, cell_second_corner_cube.y)}; - cube::coord_t se_cell{std::max(cell_first_corner_cube.x, cell_second_corner_cube.x), - std::max(cell_first_corner_cube.y, cell_second_corner_cube.y)}; + const cube::coord_t nw_cell{std::min(cell_first_corner_cube.x, cell_second_corner_cube.x), + std::min(cell_first_corner_cube.y, cell_second_corner_cube.y)}; + const cube::coord_t se_cell{std::max(cell_first_corner_cube.x, cell_second_corner_cube.x), + std::max(cell_first_corner_cube.y, cell_second_corner_cube.y)}; const auto total_cell_count = static_cast(std::abs(nw_cell.x - se_cell.x) + 1) * static_cast(std::abs(nw_cell.y - se_cell.y) + 1); @@ -713,7 +713,7 @@ all_coordinates_in_spanned_area(const CoordinateType& cell_first_corner, * @return `true` if the layouts are identical, `false` otherwise. */ template -[[nodiscard]] inline bool are_cell_layouts_identical(const Lyt& first_lyt, const Lyt& second_lyt) noexcept +[[nodiscard]] bool are_cell_layouts_identical(const Lyt& first_lyt, const Lyt& second_lyt) noexcept { static_assert(is_cell_level_layout_v, "Lyt is not a cell-level layout"); diff --git a/include/fiction/utils/math_utils.hpp b/include/fiction/utils/math_utils.hpp index 6c396edea4..ecab5c24b6 100644 --- a/include/fiction/utils/math_utils.hpp +++ b/include/fiction/utils/math_utils.hpp @@ -101,13 +101,13 @@ determine_all_combinations_of_distributing_k_entities_on_n_positions(const std:: return {}; } - std::vector> all_combinations{}; - if (k == 0) { - return all_combinations; + return {{}}; } + std::vector> all_combinations{}; + all_combinations.reserve(binomial_coefficient(n, k)); std::vector numbers(n); diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index 2a87f6dd66..55ae33adbc 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -125,7 +125,7 @@ endif () # Enable the usage of ALGLIB by the ALGLIB Project option(FICTION_ALGLIB "Automatically download, include, and utilize ALGLIB by the ALGLIB project.") if (FICTION_ALGLIB) - message(STATUS "Usage of the Z3 solver was enabled.") + message(STATUS "Usage of ALGLIB was enabled.") # Compile definition to guard include files target_compile_definitions(libfiction INTERFACE FICTION_ALGLIB_ENABLED) diff --git a/test/algorithms/physical_design/design_sidb_gates.cpp b/test/algorithms/physical_design/design_sidb_gates.cpp index 74e337a38c..1587842517 100644 --- a/test/algorithms/physical_design/design_sidb_gates.cpp +++ b/test/algorithms/physical_design/design_sidb_gates.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -24,6 +25,7 @@ #include +#include #include #include @@ -34,10 +36,11 @@ TEST_CASE("Design AND gate with skeleton, where one input wire and the output wi { const auto lyt = blueprints::two_input_one_output_skeleton_west_west(); - design_sidb_gates_params> params{ + design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.31}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{}, is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL, + bdl_input_iterator_params{}, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, {{27, 6, 0}, {30, 8, 0}}, 3}; @@ -48,7 +51,7 @@ TEST_CASE("Design AND gate with skeleton, where one input wire and the output wi design_sidb_gates(lyt, std::vector{create_and_tt()}, params, &design_gates_stats); REQUIRE(found_gate_layouts.size() == 10); const auto& first_gate = found_gate_layouts.front(); - CHECK(is_operational(first_gate, std::vector{create_and_tt()}, params.operational_params).first == + CHECK(is_operational(first_gate, std::vector{create_and_tt()}, params.operational_params).status == operational_status::OPERATIONAL); CHECK(design_gates_stats.number_of_layouts == 1140); @@ -60,13 +63,13 @@ TEST_CASE("Design AND gate with skeleton, where one input wire and the output wi SECTION("Automatic Exhaustive Gate Designer") { - params.design_mode = design_sidb_gates_params< - cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER; + params.design_mode = + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER; const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_and_tt()}, params); REQUIRE(found_gate_layouts.size() == 10); const auto& first_gate = found_gate_layouts.front(); - CHECK(is_operational(first_gate, std::vector{create_and_tt()}, params.operational_params).first == + CHECK(is_operational(first_gate, std::vector{create_and_tt()}, params.operational_params).status == operational_status::OPERATIONAL); } } @@ -103,9 +106,9 @@ TEST_CASE("Use SiQAD XNOR skeleton and generate SiQAD XNOR gate, exhaustive", "[ SECTION("One cell in canvas") { - const auto params = design_sidb_gates_params>{ + 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, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{10, 4, 0}, {10, 4, 0}}, 1}; @@ -117,9 +120,9 @@ TEST_CASE("Use SiQAD XNOR skeleton and generate SiQAD XNOR gate, exhaustive", "[ // using cube coordinates const auto lyt_in_cube_coord = convert_layout_to_fiction_coordinates(lyt); - const design_sidb_gates_params> params_cube{ + const design_sidb_gates_params params_cube{ 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, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {siqad::to_fiction_coord(siqad::coord_t{10, 4, 0}), siqad::to_fiction_coord(siqad::coord_t{10, 4, 0})}, 1}; @@ -134,9 +137,9 @@ TEST_CASE("Use SiQAD XNOR skeleton and generate SiQAD XNOR gate, exhaustive", "[ // using offset coordinates const auto lyt_in_offset_coord = convert_layout_to_fiction_coordinates(lyt); - const design_sidb_gates_params> params_offset{ + const design_sidb_gates_params params_offset{ 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, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {siqad::to_fiction_coord(siqad::coord_t{10, 4, 0}), siqad::to_fiction_coord(siqad::coord_t{10, 4, 0})}, 1}; @@ -151,25 +154,25 @@ TEST_CASE("Use SiQAD XNOR skeleton and generate SiQAD XNOR gate, exhaustive", "[ } SECTION("Four cells in canvas, design all gates with one SiDB in the canvas") { - const auto params = design_sidb_gates_params>{ + 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, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{10, 4, 0}, {13, 4, 0}}, 1}; 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 process is terminated after first solution is found (one SiDB in the " "canvas), QuickExact") { - const auto params = design_sidb_gates_params>{ + 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, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{10, 4, 0}, {10, 4, 0}}, 1, - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION}; + design_sidb_gates_params::termination_condition::AFTER_FIRST_SOLUTION}; design_sidb_gates_stats stats{}; @@ -184,12 +187,12 @@ TEST_CASE("Use SiQAD XNOR skeleton and generate SiQAD XNOR gate, exhaustive", "[ SECTION("Four cells in canvas, design process is terminated after first solution is found (one SiDB in the " "canvas), QuickSim") { - const auto params = design_sidb_gates_params>{ + const auto params = design_sidb_gates_params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKSIM}, - design_sidb_gates_params>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{10, 4, 0}, {10, 4, 0}}, 1, - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION}; + design_sidb_gates_params::termination_condition::AFTER_FIRST_SOLUTION}; design_sidb_gates_stats stats{}; @@ -201,6 +204,66 @@ 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 " + "(Automatic Exhaustive Gate Designer)") + { + 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::EXHAUSTIVE_GATE_DESIGNER, + {{10, 4, 0}, {13, 4, 0}}, + 1, + design_sidb_gates_params::termination_condition::ALL_COMBINATIONS_ENUMERATED, + {std::make_shared>(), + std::make_shared>()}}; + + 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({10, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[1].get_cell_type({11, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[2].get_cell_type({12, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[3].get_cell_type({13, 4, 0}) == siqad_layout::technology::LOGIC); + } + SECTION("Four cells in canvas, design all gates with one SiDB in the canvas and sort by ground state isolation " + "(QuickCell)") + { + 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::QUICKCELL, + {{10, 4, 0}, {13, 4, 0}}, + 1, + design_sidb_gates_params::termination_condition::ALL_COMBINATIONS_ENUMERATED, + {std::make_unique>(), + std::make_unique>()}}; + + 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({10, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[1].get_cell_type({11, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[2].get_cell_type({12, 4, 0}) == siqad_layout::technology::LOGIC); + CHECK(found_gate_layouts[3].get_cell_type({13, 4, 0}) == siqad_layout::technology::LOGIC); + } + SECTION("no canvas") + { + auto params = design_sidb_gates_params{}; + design_sidb_gates_stats design_gates_stats_exhaustive{}; + params.canvas = {{10, 4, 0}, {10, 4, 0}}; + params.number_of_sidbs = 0; + params.design_mode = + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER; + const auto found_gate_layouts_exhaustive = + design_sidb_gates(lyt, std::vector{create_xnor_tt()}, params, &design_gates_stats_exhaustive); + CHECK(found_gate_layouts_exhaustive.empty()); + CHECK(design_gates_stats_exhaustive.number_of_layouts == 1); + + design_sidb_gates_stats design_gates_stats_quickcell{}; + params.design_mode = design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL; + const auto found_gate_layouts_quickcell = + design_sidb_gates(lyt, std::vector{create_xnor_tt()}, params, &design_gates_stats_quickcell); + CHECK(found_gate_layouts_quickcell.empty()); + CHECK(design_gates_stats_quickcell.number_of_layouts == 1); + } } TEST_CASE("Use SiQAD's AND gate skeleton to generate all possible AND gates", "[design-sidb-gates]") @@ -224,12 +287,11 @@ TEST_CASE("Use SiQAD's AND gate skeleton to generate all possible AND gates", "[ lyt.assign_cell_type({10, 9, 1}, sidb_technology::cell_type::NORMAL); - design_sidb_gates_params> params{ + design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::EXGS, {detect_bdl_wires_params{2.0}}}, - design_sidb_gates_params< - cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{4, 4, 0}, {14, 5, 1}}, 1}; @@ -241,22 +303,51 @@ TEST_CASE("Use SiQAD's AND gate skeleton to generate all possible AND gates", "[ SECTION("Random Generation") { - params.design_mode = - design_sidb_gates_params>::design_sidb_gates_mode::RANDOM; + params.design_mode = design_sidb_gates_params::design_sidb_gates_mode::RANDOM; const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_and_tt()}, params); CHECK(!found_gate_layouts.empty()); } SECTION("no canvas") { + design_sidb_gates_stats design_gates_stats_exhaustive{}; params.canvas = {{4, 4, 0}, {4, 4, 0}}; params.number_of_sidbs = 0; - params.design_mode = design_sidb_gates_params< - cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER; - const auto found_gate_layouts_exhaustive = design_sidb_gates(lyt, std::vector{create_and_tt()}, params); - CHECK(found_gate_layouts_exhaustive.empty()); params.design_mode = - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL; + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER; + const auto found_gate_layouts_exhaustive = + design_sidb_gates(lyt, std::vector{create_and_tt()}, params, &design_gates_stats_exhaustive); + REQUIRE(found_gate_layouts_exhaustive.size() == 1); + const auto& first_gate_exhaustive = found_gate_layouts_exhaustive.front(); + CHECK( + is_operational(first_gate_exhaustive, std::vector{create_and_tt()}, params.operational_params).status == + operational_status::OPERATIONAL); + CHECK(design_gates_stats_exhaustive.number_of_layouts == 1); + + design_sidb_gates_stats design_gates_stats_quickcell{}; + params.design_mode = design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL; + const auto found_gate_layouts_quickcell = + design_sidb_gates(lyt, std::vector{create_and_tt()}, params, &design_gates_stats_quickcell); + REQUIRE(found_gate_layouts_quickcell.size() == 1); + const auto& first_gate_quickcell = found_gate_layouts_exhaustive.front(); + CHECK( + is_operational(first_gate_quickcell, std::vector{create_and_tt()}, params.operational_params).status == + operational_status::OPERATIONAL); + CHECK(design_gates_stats_quickcell.number_of_layouts == 1); + } + + SECTION("more SiDBs than canvas positions") + { + design_sidb_gates_stats design_gates_stats{}; + params.canvas = {{4, 4, 0}, {4, 4, 0}}; + params.number_of_sidbs = 2; + params.design_mode = + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER; + const auto found_gate_layouts_exhaustive = + design_sidb_gates(lyt, std::vector{create_and_tt()}, params, &design_gates_stats); + CHECK(found_gate_layouts_exhaustive.empty()); + CHECK(design_gates_stats.number_of_layouts == 0); + params.design_mode = design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL; const auto found_gate_layouts_quickcell = design_sidb_gates(lyt, std::vector{create_and_tt()}, params); CHECK(found_gate_layouts_quickcell.empty()); } @@ -300,10 +391,9 @@ TEST_CASE("Use FO2 Bestagon gate without SiDB at {17, 11, 0} and generate origin SECTION("generate original FO2") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, - design_sidb_gates_params< - cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{17, 11, 0}, {17, 11, 0}}, 1}; @@ -319,10 +409,10 @@ TEST_CASE("Use FO2 Bestagon gate without SiDB at {17, 11, 0} and generate origin SECTION("replace the output perturbers by equivalent negatively charged defects") { - design_sidb_gates_params> params{ + design_sidb_gates_params> params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, design_sidb_gates_params< - cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + sidb_defect_surface>::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{17, 11, 0}, {17, 11, 0}}, 1}; @@ -348,8 +438,8 @@ TEST_CASE("Use FO2 Bestagon gate without SiDB at {17, 11, 0} and generate origin CHECK(found_gate_layouts_exhaustive[0].get_cell_type({17, 11, 0}) == sidb_100_cell_clk_lyt_siqad::cell_type::LOGIC); - params.design_mode = - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL; + params.design_mode = design_sidb_gates_params< + sidb_defect_surface>::design_sidb_gates_mode::QUICKCELL; const auto found_gate_layouts_quickcell = design_sidb_gates(defect_layout, std::vector{create_fan_out_tt()}, params); @@ -362,15 +452,15 @@ TEST_CASE("Use FO2 Bestagon gate without SiDB at {17, 11, 0} and generate origin TEST_CASE("Design AND Bestagon shaped gate", "[design-sidb-gates]") { - const auto lyt = blueprints::two_input_one_output_bestagon_skeleton(); + const auto lyt = blueprints::two_input_one_output_bestagon_skeleton(); SECTION("Random Generation") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, - is_operational_params::operational_condition::TOLERATE_KINKS}, - design_sidb_gates_params>::design_sidb_gates_mode::RANDOM, + is_operational_params::operational_condition_kinks::TOLERATE_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::RANDOM, {{14, 6, 0}, {24, 12, 0}}, 3}; @@ -383,11 +473,11 @@ TEST_CASE("Design AND Bestagon shaped gate", "[design-sidb-gates]") { sidb_defect_surface defect_layout{lyt}; - design_sidb_gates_params> params{ + design_sidb_gates_params> params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, - is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params>::design_sidb_gates_mode::RANDOM, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params>::design_sidb_gates_mode::RANDOM, {{18, 8, 1}, {22, 12, 0}}, 2}; @@ -403,8 +493,8 @@ TEST_CASE("Design AND Bestagon shaped gate", "[design-sidb-gates]") found_gate_layouts.front().foreach_cell([](const auto& cell) { CHECK(cell != siqad::coord_t{16, 10, 0}); }); - params.design_mode = - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL; + params.design_mode = design_sidb_gates_params< + sidb_defect_surface>::design_sidb_gates_mode::QUICKCELL; const auto found_gate_layouts_quickcell = design_sidb_gates(defect_layout, std::vector{create_and_tt()}, params); REQUIRE(!found_gate_layouts_quickcell.empty()); @@ -432,9 +522,9 @@ TEST_CASE("Design NOR Bestagon shaped gate on H-Si 111", "[design-sidb-gates]") SECTION("Random Generation") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, - design_sidb_gates_params>::design_sidb_gates_mode::RANDOM, + design_sidb_gates_params::design_sidb_gates_mode::RANDOM, {{10, 11, 0}, {14, 15, 0}}, 3}; @@ -445,10 +535,9 @@ TEST_CASE("Design NOR Bestagon shaped gate on H-Si 111", "[design-sidb-gates]") SECTION("Exhaustive Generation, allowing kinks") { - design_sidb_gates_params> params{ + design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, - design_sidb_gates_params< - cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{10, 13, 0}, {14, 17, 0}}, 3}; // to save runtime in the CI, this test is only run in RELEASE mode @@ -463,8 +552,8 @@ TEST_CASE("Design NOR Bestagon shaped gate on H-Si 111", "[design-sidb-gates]") SECTION("terminate after first solution is found") { - params.termination_cond = design_sidb_gates_params< - cell>::termination_condition::AFTER_FIRST_SOLUTION; + params.termination_cond = + design_sidb_gates_params::termination_condition::AFTER_FIRST_SOLUTION; const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_nor_tt()}, params); REQUIRE(found_gate_layouts.size() <= std::thread::hardware_concurrency()); CHECK(found_gate_layouts.front().num_cells() == lyt.num_cells() + 3); @@ -475,12 +564,11 @@ TEST_CASE("Design NOR Bestagon shaped gate on H-Si 111", "[design-sidb-gates]") #ifdef NDEBUG SECTION("Exhaustive Generation, forbidding kinks") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, - is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params< - cell>::design_sidb_gates_mode::AUTOMATIC_EXHAUSTIVE_GATE_DESIGNER, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::EXHAUSTIVE_GATE_DESIGNER, {{10, 13, 0}, {15, 17, 0}}, 3}; @@ -492,10 +580,10 @@ TEST_CASE("Design NOR Bestagon shaped gate on H-Si 111", "[design-sidb-gates]") SECTION("Exhaustive Generation, QuickCell") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}}, - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, {{10, 13, 0}, {15, 17, 0}}, 3}; @@ -505,13 +593,13 @@ TEST_CASE("Design NOR Bestagon shaped gate on H-Si 111", "[design-sidb-gates]") } SECTION("Stop after first gate design is finished, QuickCell") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}}, - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, {{8, 13, 0}, {17, 17, 0}}, 3, - design_sidb_gates_params>::termination_condition::AFTER_FIRST_SOLUTION}; + design_sidb_gates_params::termination_condition::AFTER_FIRST_SOLUTION}; const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_nor_tt()}, params); REQUIRE(found_gate_layouts.size() <= std::thread::hardware_concurrency()); @@ -527,10 +615,10 @@ TEST_CASE("Design Bestagon shaped CX gate with QuickCell", "[design-sidb-gates]" SECTION("Exhaustive Generation, QuickCell") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}}, - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, {{16, 8, 0}, {22, 14, 0}}, 3}; @@ -547,10 +635,10 @@ TEST_CASE("Design Bestagon shaped CX gate with QuickCell (flipped)", "[design-si SECTION("Exhaustive Generation, QuickCell") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}}, - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, {{16, 7, 0}, {22, 15, 0}}, 3}; @@ -566,18 +654,18 @@ TEST_CASE("Design AND gate with input left and output top-right with QuickCell ( SECTION("Exhaustive Generation, QuickCell") { - const design_sidb_gates_params> params{ + const design_sidb_gates_params params{ is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, - is_operational_params::operational_condition::REJECT_KINKS}, - design_sidb_gates_params>::design_sidb_gates_mode::QUICKCELL, + is_operational_params::operational_condition_kinks::REJECT_KINKS}, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, {{17, 5, 0}, {24, 8, 0}}, 3}; const auto found_gate_layouts = design_sidb_gates(lyt, std::vector{create_and_tt()}, params); REQUIRE(found_gate_layouts.size() == 234); const auto& first_gate = found_gate_layouts.front(); - CHECK(is_operational(first_gate, std::vector{create_and_tt()}, params.operational_params).first == + CHECK(is_operational(first_gate, std::vector{create_and_tt()}, params.operational_params).status == operational_status::OPERATIONAL); } } diff --git a/test/algorithms/simulation/sidb/critical_temperature.cpp b/test/algorithms/simulation/sidb/critical_temperature.cpp index ca43acd1f5..fc7867fc47 100644 --- a/test/algorithms/simulation/sidb/critical_temperature.cpp +++ b/test/algorithms/simulation/sidb/critical_temperature.cpp @@ -306,7 +306,8 @@ TEMPLATE_TEST_CASE("Test critical_temperature function", "[critical-temperature] } SECTION("Kinks are not allowed") { - params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; params.operational_params.input_bdl_iterator_params.bdl_wire_params.threshold_bdl_interdistance = 2.5; const auto ct_qe = critical_temperature_gate_based(lyt, std::vector{create_and_tt()}, params, &critical_stats); @@ -446,7 +447,8 @@ TEMPLATE_TEST_CASE("Test critical_temperature function", "[critical-temperature] } SECTION("Kinks are not allowed") { - params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; const auto ct_qe = critical_temperature_gate_based(lyt, std::vector{create_fan_out_tt()}, params, &critical_stats); @@ -553,7 +555,8 @@ TEMPLATE_TEST_CASE("Test critical_temperature function", "[critical-temperature] } SECTION("Kinks are not allowed") { - params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; const auto ct_qe = critical_temperature_gate_based(lyt, std::vector{create_or_tt()}, params, &critical_stats); @@ -970,7 +973,7 @@ TEMPLATE_TEST_CASE("Critical temperature of Bestagon double wire, QuickExact", " } SECTION("Kinks are not allowed") { - params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params.operational_params.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; const auto ct_qe = critical_temperature_gate_based(lyt_double_wire_gate, create_double_wire_tt(), params, &critical_stats); @@ -1032,7 +1035,7 @@ TEMPLATE_TEST_CASE("Critical temperature of Bestagon half adder gate, QuickExact } SECTION("Kinks are not allowed") { - params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params.operational_params.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; const auto ct_qe = critical_temperature_gate_based(lyt_half_adder_gate, create_half_adder_tt(), params, &critical_stats); diff --git a/test/algorithms/simulation/sidb/is_operational.cpp b/test/algorithms/simulation/sidb/is_operational.cpp index 2c34f349b5..1ce28426a4 100644 --- a/test/algorithms/simulation/sidb/is_operational.cpp +++ b/test/algorithms/simulation/sidb/is_operational.cpp @@ -32,22 +32,95 @@ TEST_CASE("SiQAD OR gate", "[is-operational]") const sidb_100_cell_clk_lyt_siqad lat{or_gate}; auto op_params = is_operational_params{ - sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, + sidb_simulation_parameters{2, -0.32}, + sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{detect_bdl_wires_params{1.5}, bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, - is_operational_params::operational_condition::TOLERATE_KINKS}; + is_operational_params::operational_condition_kinks::TOLERATE_KINKS, + {}, + {}, + is_operational_params::termination_condition::ALL_INPUT_COMBINATIONS_ASSESSED, + is_operational_params::simulation_results_mode::KEEP_SIMULATION_RESULTS}; + + SECTION( + "determine if layout is operational, tolerate kinks, assess all input combinations and keep simulation results") + { + const auto assessment_results = is_operational(lat, std::vector{create_or_tt()}, op_params); + CHECK(assessment_results.status == operational_status::OPERATIONAL); + REQUIRE(assessment_results.assessment_per_input.has_value()); + REQUIRE(!assessment_results.assessment_per_input.value().empty()); + CHECK(assessment_results.assessment_per_input.value().front().simulation_results.has_value()); + } + + // from now on, we will discard simulation results + op_params.simulation_results_retention = is_operational_params::simulation_results_mode::DISCARD_SIMULATION_RESULTS; + + SECTION("determine if layout is operational, tolerate kinks, assess all input combinations and discard simulation " + "results") + { + const auto assessment_results = is_operational(lat, std::vector{create_or_tt()}, op_params); + CHECK(assessment_results.status == operational_status::OPERATIONAL); + REQUIRE(assessment_results.assessment_per_input.has_value()); + REQUIRE(assessment_results.assessment_per_input.value().size() == 4); + for (uint64_t i = 0; i < 4; ++i) + { + CHECK(assessment_results.assessment_per_input.value().at(i).status == operational_status::OPERATIONAL); + CHECK(!assessment_results.assessment_per_input.value().at(i).simulation_results.has_value()); + } + + const auto assessment_results_and = is_operational(lat, std::vector{create_and_tt()}, op_params); + CHECK(assessment_results_and.status == operational_status::NON_OPERATIONAL); + REQUIRE(assessment_results_and.assessment_per_input.has_value()); + REQUIRE(assessment_results_and.assessment_per_input.value().size() == 4); + CHECK(assessment_results_and.assessment_per_input.value().at(0).status == operational_status::OPERATIONAL); + CHECK(assessment_results_and.assessment_per_input.value().at(1).status == operational_status::NON_OPERATIONAL); + CHECK(assessment_results_and.assessment_per_input.value().at(2).status == operational_status::NON_OPERATIONAL); + CHECK(assessment_results_and.assessment_per_input.value().at(3).status == operational_status::OPERATIONAL); + } - SECTION("determine if layout is operational, tolerate kinks") + SECTION("determine if layout is operational under non-realistic physical parameters, assess all input combinations") { - CHECK(is_operational(lat, std::vector{create_or_tt()}, op_params).first == operational_status::OPERATIONAL); + const auto check_for_non_operationality = [&lat, &op_params] + { + const auto assessment_results = is_operational(lat, std::vector{create_or_tt()}, op_params); + CHECK(assessment_results.status == operational_status::NON_OPERATIONAL); + REQUIRE(assessment_results.assessment_per_input.has_value()); + REQUIRE(assessment_results.assessment_per_input.value().size() == 4); + for (uint64_t i = 0; i < 4; ++i) + { + CHECK(assessment_results.assessment_per_input.value().at(i).status == + operational_status::NON_OPERATIONAL); + } + }; + + op_params.simulation_parameters.epsilon_r = 1.0e-3; + check_for_non_operationality(); + + op_params.op_condition_positive_charges = + is_operational_params::operational_condition_positive_charges::TOLERATE_POSITIVE_CHARGES; + check_for_non_operationality(); + + op_params.op_condition_positive_charges = + is_operational_params::operational_condition_positive_charges::REJECT_POSITIVE_CHARGES; + op_params.simulation_parameters.epsilon_r = 5.6; + } + + // from now on, we will terminate when the first non-operational input combination is found + op_params.termination_cond = is_operational_params::termination_condition::ON_FIRST_NON_OPERATIONAL; + + SECTION("determine if layout is operational, tolerate kinks and terminate on first non-operational assessment") + { + const auto assessment_results = is_operational(lat, std::vector{create_or_tt()}, op_params); + CHECK(assessment_results.status == operational_status::OPERATIONAL); + CHECK(!assessment_results.assessment_per_input.has_value()); } // from now on, we will reject kinks - op_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + op_params.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; - SECTION("determine if layout is operational, accept kinks") + SECTION("determine if layout is operational, reject kinks") { - CHECK(is_operational(lat, std::vector{create_and_tt()}, op_params).first == + CHECK(is_operational(lat, std::vector{create_and_tt()}, op_params).status == operational_status::NON_OPERATIONAL); } @@ -70,7 +143,7 @@ TEST_CASE("SiQAD OR gate", "[is-operational]") SECTION("use pre-determined I/O pins") { - CHECK(is_operational(lat, std::vector{create_and_tt()}, op_params, input_wires, output_wires).first == + CHECK(is_operational(lat, std::vector{create_and_tt()}, op_params, input_wires, output_wires).status == operational_status::NON_OPERATIONAL); } @@ -87,8 +160,9 @@ TEST_CASE("SiQAD OR gate", "[is-operational]") CHECK(kink_induced_non_operational_input_pattern.size() == 1); - op_params.op_condition = is_operational_params::operational_condition::TOLERATE_KINKS; - CHECK(is_operational(lat, std::vector{create_or_tt()}, op_params).first == operational_status::OPERATIONAL); + op_params.op_condition_kinks = is_operational_params::operational_condition_kinks::TOLERATE_KINKS; + CHECK(is_operational(lat, std::vector{create_or_tt()}, op_params).status == + operational_status::OPERATIONAL); } } @@ -99,22 +173,26 @@ TEST_CASE("SiQAD NAND gate", "[is-operational]") const sidb_100_cell_clk_lyt_siqad lat{nand_gate}; auto op_params = is_operational_params{ - sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, + 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}, - is_operational_params::operational_condition::REJECT_KINKS, - is_operational_params::operational_analysis_strategy::FILTER_THEN_SIMULATION}; + is_operational_params::operational_condition_kinks::REJECT_KINKS, + {}, + is_operational_params::operational_analysis_strategy::FILTER_THEN_SIMULATION, + {}, + {}}; SECTION("Pruning and simulation") { - CHECK(is_operational(lat, std::vector{create_nand_tt()}, op_params).first == + CHECK(is_operational(lat, std::vector{create_nand_tt()}, op_params).status == operational_status::OPERATIONAL); } SECTION("only pruning") { op_params.strategy_to_analyze_operational_status = is_operational_params::operational_analysis_strategy::FILTER_ONLY; - CHECK(is_operational(lat, std::vector{create_nand_tt()}, op_params).first == + CHECK(is_operational(lat, std::vector{create_nand_tt()}, op_params).status == operational_status::OPERATIONAL); } @@ -129,7 +207,7 @@ TEST_CASE("SiQAD NAND gate", "[is-operational]") { CHECK(is_operational(lat, std::vector{create_nand_tt()}, op_params, input_wires, output_wires, std::optional{canvas_lyt}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); } } @@ -160,10 +238,10 @@ TEST_CASE("SiQAD's AND gate with input BDL pairs of different size", "[is-operat CHECK(is_operational(lat, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.28}}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK(is_operational(lat, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.1}}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } TEST_CASE("Bestagon FO2 gate", "[is-operational]") @@ -175,11 +253,11 @@ TEST_CASE("Bestagon FO2 gate", "[is-operational]") CHECK(is_operational( lyt, std::vector{create_fan_out_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK(is_operational( lyt, std::vector{create_fan_out_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } SECTION("using QuickSim") @@ -187,11 +265,11 @@ TEST_CASE("Bestagon FO2 gate", "[is-operational]") CHECK(is_operational( lyt, std::vector{create_fan_out_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKSIM}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK(is_operational( lyt, std::vector{create_fan_out_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKSIM}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } #if (FICTION_ALGLIB_ENABLED) @@ -201,11 +279,11 @@ TEST_CASE("Bestagon FO2 gate", "[is-operational]") CHECK(is_operational( lyt, std::vector{create_fan_out_tt()}, is_operational_params{sidb_simulation_parameters{3, -0.32}, sidb_simulation_engine::CLUSTERCOMPLETE}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK(is_operational( lyt, std::vector{create_fan_out_tt()}, is_operational_params{sidb_simulation_parameters{3, -0.30}, sidb_simulation_engine::CLUSTERCOMPLETE}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } #endif // FICTION_ALGLIB_ENABLED @@ -222,11 +300,11 @@ TEST_CASE("Bestagon CROSSING gate", "[is-operational]") CHECK( is_operational(lat, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK( is_operational(lat, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } TEST_CASE("Bestagon AND gate", "[is-operational]") @@ -242,11 +320,11 @@ TEST_CASE("Bestagon AND gate", "[is-operational]") CHECK(is_operational( lyt, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK(is_operational( lyt, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } SECTION("With defects") { @@ -254,30 +332,30 @@ TEST_CASE("Bestagon AND gate", "[is-operational]") sidb_defect{sidb_defect_type::UNKNOWN, -1, params.epsilon_r, params.lambda_tf}); CHECK(is_operational(lyt, std::vector{create_and_tt()}, is_operational_params{params, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); // move defect one to the right lyt.move_sidb_defect({3, 16, 1}, {4, 16, 1}); CHECK(is_operational(lyt, std::vector{create_and_tt()}, is_operational_params{params, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); // move defect one to the right lyt.move_sidb_defect({4, 16, 1}, {5, 16, 1}); CHECK(is_operational(lyt, std::vector{create_and_tt()}, is_operational_params{params, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } SECTION("Check operation for different values of mu") { CHECK(is_operational( lyt, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK(is_operational( lyt, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } SECTION("Count the number of non-operational input combinations, accepting kinks") { @@ -319,7 +397,7 @@ TEST_CASE("Not working diagonal Wire", "[is-operational]") CHECK( is_operational(lat, std::vector{create_id_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } TEMPLATE_TEST_CASE("AND gate on the H-Si(111)-1x1 surface", "[is-operational]", sidb_111_cell_clk_lyt_siqad, @@ -366,15 +444,15 @@ TEST_CASE( { CHECK(is_operational(lyt, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); } SECTION("reject kink states") { CHECK(is_operational(lyt, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, - is_operational_params::operational_condition::REJECT_KINKS}) - .first == operational_status::NON_OPERATIONAL); + is_operational_params::operational_condition_kinks::REJECT_KINKS}) + .status == operational_status::NON_OPERATIONAL); } SECTION("check if is_kink_induced_non_operational returns true") { @@ -383,7 +461,7 @@ TEST_CASE( lyt, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, - is_operational_params::operational_condition::TOLERATE_KINKS})); + is_operational_params::operational_condition_kinks::TOLERATE_KINKS})); } SECTION("check input patterns for which kinks induce the layout to become non-operational") @@ -392,7 +470,7 @@ TEST_CASE( lyt, std::vector{create_and_tt()}, is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, - is_operational_params::operational_condition::TOLERATE_KINKS}) == + is_operational_params::operational_condition_kinks::TOLERATE_KINKS}) == std::set{1, 2}); } } @@ -426,7 +504,7 @@ TEST_CASE("BDL wire", "[is-operational]") const is_operational_params params{sim_params}; - CHECK(is_operational(lyt, std::vector{create_id_tt()}, params).first == operational_status::OPERATIONAL); + CHECK(is_operational(lyt, std::vector{create_id_tt()}, params).status == operational_status::OPERATIONAL); } TEST_CASE("Special wire that cannot be pruned, but is non-operational when kinks are rejected", "[is-operational]") @@ -464,21 +542,21 @@ TEST_CASE("Special wire that cannot be pruned, but is non-operational when kinks SECTION("Rejecting Kinks") { - params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + params.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; params.strategy_to_analyze_operational_status = is_operational_params::operational_analysis_strategy::FILTER_THEN_SIMULATION; - CHECK(is_operational(lyt, std::vector{create_id_tt()}, params).first == + CHECK(is_operational(lyt, std::vector{create_id_tt()}, params).status == operational_status::NON_OPERATIONAL); } SECTION("Only conducting pruning and tolerating kinks") { - params.op_condition = is_operational_params::operational_condition::TOLERATE_KINKS; + params.op_condition_kinks = is_operational_params::operational_condition_kinks::TOLERATE_KINKS; params.strategy_to_analyze_operational_status = is_operational_params::operational_analysis_strategy::FILTER_ONLY; - CHECK(is_operational(lyt, std::vector{create_id_tt()}, params).first == + CHECK(is_operational(lyt, std::vector{create_id_tt()}, params).status == operational_status::NON_OPERATIONAL); } } @@ -492,20 +570,22 @@ TEST_CASE("flipped CX bestagon gate", "[is-operational]") CHECK(is_operational(lyt, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, - is_operational_params::operational_condition::REJECT_KINKS}) - .first == operational_status::OPERATIONAL); + is_operational_params::operational_condition_kinks::REJECT_KINKS}) + .status == operational_status::OPERATIONAL); const auto kink_induced_non_operational_input_pattern = kink_induced_non_operational_input_patterns( lyt, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{}, is_operational_params::operational_condition::REJECT_KINKS}); + bdl_input_iterator_params{}, + is_operational_params::operational_condition_kinks::REJECT_KINKS}); CHECK(kink_induced_non_operational_input_pattern.empty()); const auto kink_induced_non_operational = is_kink_induced_non_operational( lyt, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{}, is_operational_params::operational_condition::REJECT_KINKS}); + bdl_input_iterator_params{}, + is_operational_params::operational_condition_kinks::REJECT_KINKS}); CHECK(!kink_induced_non_operational); } @@ -523,11 +603,11 @@ TEST_CASE("is operational check for Bestagon CX gate", "[is-operational], [quali CHECK(is_operational( lat, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK(is_operational( lat, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } SECTION("using predetermined wires") @@ -539,12 +619,12 @@ TEST_CASE("is operational check for Bestagon CX gate", "[is-operational], [quali lat, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, input_bdl_wires, output_bdl_wires) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK(is_operational( lat, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}, input_bdl_wires, output_bdl_wires) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); CHECK(!is_kink_induced_non_operational( lat, create_crossing_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}, @@ -560,7 +640,7 @@ TEST_CASE("is operational check for Bestagon CX gate", "[is-operational], [quali op_params.strategy_to_analyze_operational_status = is_operational_params::operational_analysis_strategy::FILTER_ONLY; - CHECK(is_operational(lat, create_crossing_wire_tt(), op_params, input_bdl_wires, output_bdl_wires).first == + CHECK(is_operational(lat, create_crossing_wire_tt(), op_params, input_bdl_wires, output_bdl_wires).status == operational_status::OPERATIONAL); } } @@ -576,11 +656,11 @@ TEST_CASE("is operational check for Bestagon double wire", "[is-operational], [q CHECK( is_operational(lat, create_double_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK( is_operational(lat, create_double_wire_tt(), is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } TEST_CASE("is operational check for Bestagon half adder", "[is-operational], [quality]") @@ -594,10 +674,10 @@ TEST_CASE("is operational check for Bestagon half adder", "[is-operational], [qu CHECK( is_operational(lat, create_half_adder_tt(), is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::OPERATIONAL); + .status == operational_status::OPERATIONAL); CHECK( is_operational(lat, create_half_adder_tt(), is_operational_params{sidb_simulation_parameters{2, -0.25}, sidb_simulation_engine::QUICKEXACT}) - .first == operational_status::NON_OPERATIONAL); + .status == operational_status::NON_OPERATIONAL); } #endif diff --git a/test/algorithms/simulation/sidb/operational_domain.cpp b/test/algorithms/simulation/sidb/operational_domain.cpp index 39b32a9a58..4505046bc2 100644 --- a/test/algorithms/simulation/sidb/operational_domain.cpp +++ b/test/algorithms/simulation/sidb/operational_domain.cpp @@ -1343,7 +1343,8 @@ TEMPLATE_TEST_CASE("AND gate with Bestagon shape and kink states at default phys SECTION("grid_search, reject kinks") { - op_domain_params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + op_domain_params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; const auto op_domain = operational_domain_grid_search(layout, std::vector{create_and_tt()}, op_domain_params, &op_domain_stats); @@ -1372,7 +1373,8 @@ TEMPLATE_TEST_CASE("Grid search to determine the operational domain. The operati op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R, 4.0, 6.0, 0.4}, {sweep_parameter::LAMBDA_TF, 4.0, 6.0, 0.4}}; - op_domain_params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + op_domain_params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; operational_domain_stats op_domain_stats{}; diff --git a/test/algorithms/simulation/sidb/operational_domain_ratio.cpp b/test/algorithms/simulation/sidb/operational_domain_ratio.cpp index 65c327b99f..69a9658390 100644 --- a/test/algorithms/simulation/sidb/operational_domain_ratio.cpp +++ b/test/algorithms/simulation/sidb/operational_domain_ratio.cpp @@ -109,7 +109,8 @@ TEST_CASE("SiQAD NAND gate", "[compute-operational-ratio]") op_domain_params.sweep_dimensions = {{sweep_parameter::EPSILON_R}, {sweep_parameter::LAMBDA_TF}}; op_domain_params.operational_params.strategy_to_analyze_operational_status = is_operational_params::operational_analysis_strategy::FILTER_THEN_SIMULATION; - op_domain_params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + op_domain_params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; op_domain_params.operational_params.input_bdl_iterator_params.bdl_wire_params.threshold_bdl_interdistance = 1.5; // set x-dimension @@ -182,7 +183,8 @@ TEST_CASE("Bestagon AND gate", "[compute-operational-ratio]") SECTION("semi-operational domain, reject kinks") { op_domain_params.sweep_dimensions.push_back(z_dimension); - op_domain_params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + op_domain_params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; const operational_domain_ratio_params op_ratio_params{op_domain_params}; @@ -197,7 +199,8 @@ TEST_CASE("Bestagon AND gate", "[compute-operational-ratio]") "semi-operational domain, reject kinks, only pruning is used to determine the operational status of the layout") { op_domain_params.sweep_dimensions.push_back(z_dimension); - op_domain_params.operational_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + op_domain_params.operational_params.op_condition_kinks = + is_operational_params::operational_condition_kinks::REJECT_KINKS; op_domain_params.operational_params.strategy_to_analyze_operational_status = is_operational_params::operational_analysis_strategy::FILTER_ONLY; diff --git a/test/algorithms/simulation/sidb/verify_logic_match.cpp b/test/algorithms/simulation/sidb/verify_logic_match.cpp index 4d942f6e09..ae6ac5c0a8 100644 --- a/test/algorithms/simulation/sidb/verify_logic_match.cpp +++ b/test/algorithms/simulation/sidb/verify_logic_match.cpp @@ -110,7 +110,7 @@ TEST_CASE("AND gate mirrored on the x-axis on the H-Si 111 surface", REQUIRE(!gs.empty()); is_operational_params op_params{}; - op_params.op_condition = is_operational_params::operational_condition::REJECT_KINKS; + op_params.op_condition_kinks = is_operational_params::operational_condition_kinks::REJECT_KINKS; SECTION("Correct index") { diff --git a/test/benchmark/sidb_logic.cpp b/test/benchmark/sidb_logic.cpp new file mode 100644 index 0000000000..7f3b5b89b0 --- /dev/null +++ b/test/benchmark/sidb_logic.cpp @@ -0,0 +1,485 @@ +// +// Created by Willem Lambooy on 19/02/2025. +// + +#include +#include + +#include "../utils/blueprints/layout_blueprints.hpp" + +#include +#include +#include +#include + +using namespace fiction; + +using lattice = sidb_100_cell_clk_lyt; +using lattice_siqad = sidb_100_cell_clk_lyt_siqad; + +TEST_CASE("Benchmark operational assessment using exact engines", "[benchmark]") +{ + + const auto lyt_ha = convert_layout_to_fiction_coordinates(blueprints::bestagon_ha()); + const auto lyt_cx = convert_layout_to_fiction_coordinates(blueprints::bestagon_crossing()); + + is_operational_params operational_params_qe{sidb_simulation_parameters{2, -0.32}, + sidb_simulation_engine::QUICKEXACT}; + +#if (FICTION_ALGLIB_ENABLED) + is_operational_params operational_params_cc{sidb_simulation_parameters{2, -0.32}, + sidb_simulation_engine::CLUSTERCOMPLETE}; +#endif // FICTION_ALGLIB_ENABLED + + SECTION("Bestagon half adder, filter only") + { + BENCHMARK("QuickExact") + { + return is_operational(lyt_ha, create_half_adder_tt(), operational_params_qe); + }; + +#if (FICTION_ALGLIB_ENABLED) + BENCHMARK("ClusterComplete") + { + return is_operational(lyt_ha, create_half_adder_tt(), operational_params_cc); + }; +#endif // FICTION_ALGLIB_ENABLED + } + + SECTION("Bestagon half adder, filter then simulation") + { + BENCHMARK("QuickExact") + { + return is_operational(lyt_ha, create_half_adder_tt(), operational_params_qe); + }; + +#if (FICTION_ALGLIB_ENABLED) + BENCHMARK("ClusterComplete") + { + return is_operational(lyt_ha, create_half_adder_tt(), operational_params_cc); + }; +#endif // FICTION_ALGLIB_ENABLED + } + + SECTION("Bestagon half adder, simulation only") + { + BENCHMARK("QuickExact") + { + return is_operational(lyt_ha, create_half_adder_tt(), operational_params_qe); + }; + +#if (FICTION_ALGLIB_ENABLED) + BENCHMARK("ClusterComplete") + { + return is_operational(lyt_ha, create_half_adder_tt(), operational_params_cc); + }; +#endif // FICTION_ALGLIB_ENABLED + } + + SECTION("Bestagon crossing, filter only") + { + BENCHMARK("QuickExact") + { + return is_operational(lyt_cx, create_crossing_wire_tt(), operational_params_qe); + }; + +#if (FICTION_ALGLIB_ENABLED) + BENCHMARK("ClusterComplete") + { + return is_operational(lyt_cx, create_crossing_wire_tt(), operational_params_cc); + }; +#endif // FICTION_ALGLIB_ENABLED + } + + SECTION("Bestagon crossing, filter then simulation") + { + BENCHMARK("QuickExact") + { + return is_operational(lyt_cx, create_crossing_wire_tt(), operational_params_qe); + }; + +#if (FICTION_ALGLIB_ENABLED) + BENCHMARK("ClusterComplete") + { + return is_operational(lyt_cx, create_crossing_wire_tt(), operational_params_cc); + }; +#endif // FICTION_ALGLIB_ENABLED + } + + SECTION("Bestagon crossing, simulation only") + { + BENCHMARK("QuickExact") + { + return is_operational(lyt_cx, create_crossing_wire_tt(), operational_params_qe); + }; + +#if (FICTION_ALGLIB_ENABLED) + BENCHMARK("ClusterComplete") + { + return is_operational(lyt_cx, create_crossing_wire_tt(), operational_params_cc); + }; +#endif // FICTION_ALGLIB_ENABLED + } +} + +TEST_CASE("Benchmark exact design using QuickCell", "[benchmark]") +{ + const auto lyt = convert_layout_to_fiction_coordinates( + blueprints::two_input_two_output_bestagon_skeleton()); + + design_sidb_gates_params design_gate_params_qe{ + is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT}, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, + {{16, 8, 0}, {22, 14, 0}}, + 3}; + +#if (FICTION_ALGLIB_ENABLED) + design_sidb_gates_params design_gate_params_cc{ + is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::CLUSTERCOMPLETE}, + design_sidb_gates_params::design_sidb_gates_mode::QUICKCELL, + {{16, 8, 0}, {22, 14, 0}}, + 3}; +#endif // FICTION_ALGLIB_ENABLED + + SECTION("Bestagon half adder") + { + BENCHMARK("QuickExact") + { + return design_sidb_gates(lyt, std::vector{create_half_adder_tt()}, design_gate_params_qe); + }; + +#if (FICTION_ALGLIB_ENABLED) + BENCHMARK("ClusterComplete") + { + return design_sidb_gates(lyt, std::vector{create_half_adder_tt()}, design_gate_params_cc); + }; +#endif // FICTION_ALGLIB_ENABLED + } + + SECTION("Bestagon crossing") + { + BENCHMARK("QuickExact") + { + return design_sidb_gates(lyt, std::vector{create_crossing_wire_tt()}, design_gate_params_qe); + }; + +#if (FICTION_ALGLIB_ENABLED) + BENCHMARK("ClusterComplete") + { + return design_sidb_gates(lyt, std::vector{create_crossing_wire_tt()}, design_gate_params_cc); + }; +#endif // FICTION_ALGLIB_ENABLED + } +} + +// AMD Ryzen Threadripper PRO 5955X, Ubuntu 20.04, Ubuntu clang version 18.1.3 (19.02.2025) +// +// +// BEFORE #552 (-DFICTION_ENABLE_JEMALLOC=ON) ================================== +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon half adder, filter only +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 3.61372 s +// 36.1154 ms 36.0746 ms 36.1633 ms +// 225.865 us 192.438 us 276.626 us +// +// ClusterComplete 100 1 20.042 s +// 48.413 ms 41.4015 ms 58.1081 ms +// 41.6985 ms 32.7763 ms 54.8126 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon half adder, filter then simulation +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 3.65567 s +// 36.848 ms 36.7097 ms 36.985 ms +// 702.456 us 652.708 us 760.232 us +// +// ClusterComplete 100 1 5.71742 s +// 52.0939 ms 42.4464 ms 65.7572 ms +// 57.9337 ms 44.4928 ms 74.7396 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon half adder, simulation only +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 3.64339 s +// 36.5662 ms 36.4448 ms 36.6976 ms +// 646.176 us 592.023 us 703.154 us +// +// ClusterComplete 100 1 7.97753 s +// 73.4741 ms 58.6144 ms 99.1509 ms +// 97.0133 ms 63.7442 ms 149.867 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon crossing, filter only +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 29.6623 s +// 302.549 ms 301.342 ms 304.089 ms +// 6.91644 ms 5.68371 ms 8.01302 ms +// +// ClusterComplete 100 1 5.42756 s +// 52.2006 ms 43.9063 ms 68.0955 ms +// 56.4932 ms 35.8826 ms 103.684 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon crossing, filter then simulation +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 30.6831 s +// 299.977 ms 299.57 ms 300.65 ms +// 2.61126 ms 1.82812 ms 4.39419 ms +// +// ClusterComplete 100 1 11.2909 s +// 38.2897 ms 32.5868 ms 47.593 ms +// 36.3324 ms 25.8208 ms 59.0547 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon crossing, simulation only +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 29.9357 s +// 301.806 ms 300.921 ms 303.025 ms +// 5.23905 ms 3.98772 ms 6.54099 ms +// +// ClusterComplete 100 1 5.55833 s +// 49.1383 ms 41.3757 ms 59.5775 ms +// 45.8248 ms 36.1941 ms 57.3929 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark exact design using QuickCell +// Bestagon half adder +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 10.9851 s +// 102.632 ms 102.234 ms 103.064 ms +// 2.12151 ms 1.85788 ms 2.52999 ms +// +// ClusterComplete 100 1 10.1796 s +// 103.164 ms 102.743 ms 103.617 ms +// 2.2432 ms 1.95342 ms 2.65687 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark exact design using QuickCell +// Bestagon crossing +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 10.782 s +// 103.754 ms 103.333 ms 104.233 ms +// 2.28478 ms 1.97222 ms 2.74259 ms +// +// ClusterComplete 100 1 10.8237 s +// 104.066 ms 103.655 ms 104.505 ms +// 2.16288 ms 1.90859 ms 2.49953 ms +// +// +// +// AFTER #552 (-DFICTION_ENABLE_JEMALLOC=ON) =================================== +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon half adder, filter only +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 3.58351 s +// 35.7141 ms 35.6905 ms 35.7399 ms +// 125.743 us 109.463 us 146.677 us +// +// ClusterComplete 100 1 5.39978 s +// 61.0824 ms 51.1992 ms 74.6826 ms +// 58.576 ms 46.6999 ms 80.838 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon half adder, filter then simulation +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 3.57956 s +// 35.6716 ms 35.6494 ms 35.6971 ms +// 121.081 us 104.599 us 140.825 us +// +// ClusterComplete 100 1 2.89808 s +// 57.2165 ms 47.1633 ms 71.0956 ms +// 59.7114 ms 46.5993 ms 76.3067 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon half adder, simulation only +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 3.58077 s +// 35.7433 ms 35.7033 ms 35.8556 ms +// 314.086 us 141.496 us 673.349 us +// +// ClusterComplete 100 1 8.95055 s +// 60.249 ms 50.3837 ms 74.4514 ms +// 59.66 ms 45.9172 ms 81.7567 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon crossing, filter only +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 29.6191 s +// 298.495 ms 297.799 ms 299.994 ms +// 4.99546 ms 2.35073 ms 8.36629 ms +// +// ClusterComplete 100 1 6.25514 s +// 54.3169 ms 44.2527 ms 69.1531 ms +// 61.4579 ms 46.4648 ms 83.323 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon crossing, filter then simulation +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 29.6573 s +// 299.916 ms 298.689 ms 301.854 ms +// 7.7258 ms 5.34909 ms 10.4406 ms +// +// ClusterComplete 100 1 5.44163 s +// 48.5948 ms 41.1548 ms 59.3492 ms +// 45.2397 ms 34.6753 ms 63.186 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark operational assessment using exact engines +// Bestagon crossing, simulation only +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 29.6576 s +// 296.978 ms 296.867 ms 297.113 ms +// 622.364 us 524.333 us 787.205 us +// +// ClusterComplete 100 1 2.7908 s +// 46.4762 ms 39.9876 ms 58.5954 ms +// 43.5899 ms 25.3335 ms 70.2295 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark exact design using QuickCell +// Bestagon half adder +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 11.1668 s +// 102.741 ms 102.353 ms 103.152 ms +// 2.03127 ms 1.803 ms 2.31067 ms +// +// ClusterComplete 100 1 10.2805 s +// 102.878 ms 102.542 ms 103.256 ms +// 1.81781 ms 1.58851 ms 2.13815 ms +// +// +// ------------------------------------------------------------------------------- +// Benchmark exact design using QuickCell +// Bestagon crossing +// ------------------------------------------------------------------------------- +// ............................................................................... +// +// benchmark name samples iterations est run time +// mean low mean high mean +// std dev low std dev high std dev +// ------------------------------------------------------------------------------- +// QuickExact 100 1 10.7396 s +// 103.523 ms 103.151 ms 103.933 ms +// 1.99474 ms 1.72231 ms 2.46009 ms +// +// ClusterComplete 100 1 10.6287 s +// 103.967 ms 103.558 ms 104.48 ms +// 2.32589 ms 1.85219 ms 3.14282 ms diff --git a/test/utils/math_utils.cpp b/test/utils/math_utils.cpp index c2890c6bff..8b2807c01e 100644 --- a/test/utils/math_utils.cpp +++ b/test/utils/math_utils.cpp @@ -66,54 +66,54 @@ TEST_CASE("Binomial Coefficient Tests") SECTION("C(5, 2)") { const uint64_t result = binomial_coefficient(5, 2); - REQUIRE(result == 10); // C(5, 2) = 10 + CHECK(result == 10); // C(5, 2) = 10 } SECTION("C(10, 3)") { const uint64_t result = binomial_coefficient(10, 3); - REQUIRE(result == 120); // C(10, 3) = 120 + CHECK(result == 120); // C(10, 3) = 120 } SECTION("C(0, 0)") { const uint64_t result = binomial_coefficient(0, 0); - REQUIRE(result == 1); // C(0, 0) = 1 + CHECK(result == 1); // C(0, 0) = 1 } SECTION("C(8, 8)") { const uint64_t result = binomial_coefficient(8, 8); - REQUIRE(result == 1); // C(8, 8) = 1 + CHECK(result == 1); // C(8, 8) = 1 } SECTION("C(7, 10)") { const uint64_t result = binomial_coefficient(7, 10); - REQUIRE(result == 0); // C(7, 10) = 0 (k > n) + CHECK(result == 0); // C(7, 10) = 0 (k > n) } SECTION("C(15, 7)") { const uint64_t result = binomial_coefficient(15, 7); - REQUIRE(result == 6435); // C(15, 7) = 6435 + CHECK(result == 6435); // C(15, 7) = 6435 } SECTION("C(20, 10)") { const uint64_t result = binomial_coefficient(20, 10); - REQUIRE(result == 184756); // C(20, 10) = 184,756 + CHECK(result == 184756); // C(20, 10) = 184,756 } SECTION("C(30, 15)") { const uint64_t result = binomial_coefficient(30, 15); - REQUIRE(result == 155117520); // C(30, 15) = 155,117,520 + CHECK(result == 155117520); // C(30, 15) = 155,117,520 } SECTION("C(50, 25)") { const uint64_t result = binomial_coefficient(50, 25); - REQUIRE(result == 126410606437752); // C(50, 25) = 126,410,606,437,752 + CHECK(result == 126410606437752); // C(50, 25) = 126,410,606,437,752 } } @@ -126,7 +126,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[cartesian_comb auto result = cartesian_combinations(input); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("Two dimensions") @@ -136,7 +136,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[cartesian_comb auto result = cartesian_combinations(input); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("Three dimensions") @@ -147,7 +147,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[cartesian_comb auto result = cartesian_combinations(input); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("Empty input") @@ -157,7 +157,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[cartesian_comb auto result = cartesian_combinations(input); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("Empty dimension") @@ -167,7 +167,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[cartesian_comb auto result = cartesian_combinations(input); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("Mixed types") @@ -177,7 +177,7 @@ TEST_CASE("Test the computation of the cartesian combinations", "[cartesian_comb auto result = cartesian_combinations(input); - REQUIRE(result == expected); + CHECK(result == expected); } } @@ -188,11 +188,11 @@ TEST_CASE("Test the determination of all combinations of distributing k entities { const std::size_t k = 0; const std::size_t n = 0; - const std::vector> expected{}; + const std::vector> expected{{}}; auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("k = 1, n = 1") @@ -203,7 +203,7 @@ TEST_CASE("Test the determination of all combinations of distributing k entities auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("k = 2, n = 3") @@ -214,7 +214,7 @@ TEST_CASE("Test the determination of all combinations of distributing k entities auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("k = 3, n = 5") @@ -226,18 +226,18 @@ TEST_CASE("Test the determination of all combinations of distributing k entities auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("k = 0, n = 5") { const std::size_t k = 0; const std::size_t n = 5; - const std::vector> expected{}; + const std::vector> expected{{}}; auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("k = 5, n = 5") @@ -248,7 +248,7 @@ TEST_CASE("Test the determination of all combinations of distributing k entities auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); - REQUIRE(result == expected); + CHECK(result == expected); } SECTION("k > n (invalid case)") @@ -259,34 +259,35 @@ TEST_CASE("Test the determination of all combinations of distributing k entities auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(k, n); - REQUIRE(result == expected); + CHECK(result == expected); } } TEST_CASE("Zero entities", "[determine-all-combinations-of-distributing-k-entities-on-n-positions]") { const auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(0, 5); - REQUIRE(result.empty()); + REQUIRE(result.size() == 1); + CHECK(result.front().empty()); } TEST_CASE("More entities than positions", "[determine-all-combinations-of-distributing-k-entities-on-n-positions]") { const auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(5, 3); - REQUIRE(result.empty()); + CHECK(result.empty()); } TEST_CASE("Equal entities and positions", "[determine-all-combinations-of-distributing-k-entities-on-n-positions]") { const auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(3, 3); REQUIRE(result.size() == 1); - REQUIRE(result[0] == std::vector{0, 1, 2}); + CHECK(result[0] == std::vector{0, 1, 2}); } TEST_CASE("Less entities than positions", "[determine-all-combinations-of-distributing-k-entities-on-n-positions]") { const auto result = determine_all_combinations_of_distributing_k_entities_on_n_positions(2, 3); REQUIRE(result.size() == 3); - REQUIRE(result[0] == std::vector{0, 1}); - REQUIRE(result[1] == std::vector{0, 2}); - REQUIRE(result[2] == std::vector{1, 2}); + CHECK(result[0] == std::vector{0, 1}); + CHECK(result[1] == std::vector{0, 2}); + CHECK(result[2] == std::vector{1, 2}); }