diff --git a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp index b9ceff4bf..776013fe0 100644 --- a/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp +++ b/bindings/pyfiction/include/pyfiction/algorithms/simulation/sidb/is_operational.hpp @@ -13,7 +13,7 @@ #include #include -#include +#include namespace pyfiction { @@ -32,6 +32,14 @@ void is_operational(pybind11::module& m) m.def("operational_input_patterns", &fiction::operational_input_patterns, "lyt"_a, "spec"_a, "params"_a = fiction::is_operational_params{}, DOC(fiction_operational_input_patterns)); + + m.def("is_kink_induced_non_operational", &fiction::is_kink_induced_non_operational, "lyt"_a, "spec"_a, + "params"_a = fiction::is_operational_params{}, "input_bdl_wire"_a = std::nullopt, + "output_bdl_wire"_a = std::nullopt, DOC(fiction_is_kink_induced_non_operational)); + + m.def("kink_induced_non_operational_input_patterns", + &fiction::kink_induced_non_operational_input_patterns, "lyt"_a, "spec"_a, + "params"_a = fiction::is_operational_params{}, DOC(fiction_kink_induced_non_operational_input_patterns)); } } // namespace detail diff --git a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp index cb76816fe..240d30f7d 100644 --- a/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp +++ b/bindings/pyfiction/include/pyfiction/pybind11_mkdoc_docstrings.hpp @@ -6755,7 +6755,7 @@ Template parameter ``Lyt``: SiDB cell-level layout type. Template parameter ``TT``: - The type of the truth table specifying the gate behavior.)doc"; + Type of the truth table.)doc"; static const char *__doc_fiction_detail_is_operational_impl_bii = R"doc(Iterator that iterates over all possible input states.)doc"; @@ -6801,12 +6801,16 @@ 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_determine_operational_input_patterns = -R"doc(Determines the input combinations yielding the correct output. +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. Returns: - All inputs (e.g. 2-input Boolean function: 00 ^= 0; 10 ^= 2) for - which the correct output is computed.)doc"; + Vector of pairs where the first element of the pair is the input + pattern (e.g. 2-input Boolean function: 00 ^= 0; 10 ^= 2) for + which the layout is non-operational. The second entry indicates + the reason why the layout is non-operational + (`non_operationality_reason`) for the given input pattern.)doc"; static const char *__doc_fiction_detail_is_operational_impl_encodes_bit_one = R"doc(This function returns `true` if `1` is encoded in the charge state of @@ -6908,14 +6912,15 @@ This function executes the operational status checking algorithm for the gate layout and parameters provided during initialization. Returns: - The operational status of the gate layout (either `OPERATIONAL` or - `NON_OPERATIONAL`).)doc"; + 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.)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_verifiy_logic_match_of_cds = +static const char *__doc_fiction_detail_is_operational_impl_verify_logic_match_of_cds = R"doc(Checks if the given charge distribution correctly encodes the expected logic for the given input pattern, based on a provided truth table. @@ -6934,8 +6939,9 @@ Parameter ``input_pattern``: Input pattern represented by the position of perturbers. Returns: - Operational status indicating if the layout is `operational` or - `non-operational`.)doc"; + 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.)doc"; static const char *__doc_fiction_detail_jump_point_search_impl = R"doc()doc"; @@ -7188,6 +7194,14 @@ static const char *__doc_fiction_detail_new_gate_location_NONE = R"doc(Do not ch static const char *__doc_fiction_detail_new_gate_location_SRC = R"doc(Check if the source tile is empty.)doc"; +static const char *__doc_fiction_detail_non_operationality_reason = R"doc(Reason why a layout is non-operational.)doc"; + +static const char *__doc_fiction_detail_non_operationality_reason_KINKS = R"doc(Kinks induced the layout to become non-operational.)doc"; + +static const char *__doc_fiction_detail_non_operationality_reason_LOGIC_MISMATCH = R"doc(The layout is non-operational because of logic mismatch.)doc"; + +static const char *__doc_fiction_detail_non_operationality_reason_NONE = R"doc(No reason for non-operationality could be determined.)doc"; + static const char *__doc_fiction_detail_on_the_fly_circuit_design_impl = R"doc()doc"; static const char *__doc_fiction_detail_on_the_fly_circuit_design_impl_design_circuit_on_defective_surface = R"doc()doc"; @@ -13613,6 +13627,42 @@ Parameter ``exact_results``: static const char *__doc_fiction_is_hexagonal_layout = R"doc()doc"; +static const char *__doc_fiction_is_kink_induced_non_operational = +R"doc(This function determines if the layout is only considered as non- +operational because of kinks. This means that the layout would be +considered as operational, if kinks were accepted. + +@note "Kink induced non-operational" refers to the non-operational +status being exclusively caused by kinks with an otherwise correct +logic match. + +Template parameter ``Lyt``: + SiDB cell-level layout type. + +Template parameter ``TT``: + Type of the truth table. + +Parameter ``lyt``: + The SiDB cell-level layout to be checked. + +Parameter ``spec``: + Expected Boolean function of the layout given as a multi-output + truth table. + +Parameter ``params``: + Parameters for the `is_operational` algorithm. + +Parameter ``input_bdl_wire``: + Optional BDL input wires of lyt. + +Parameter ``output_bdl_wire``: + Optional BDL output wires of lyt. + +Returns: + Bool that indicates whether kinks induce the layout to become non- + operational. `true` if the layout is non-operational due to kinks, + `false` otherwise.)doc"; + static const char *__doc_fiction_is_linear_scheme = R"doc(Checks whether a given clocking scheme is registered as a cycle-free one. These currently are @@ -13675,7 +13725,7 @@ Template parameter ``Lyt``: SiDB cell-level layout type. Template parameter ``TT``: - The type of the truth table specifying the layout behavior. + Type of the truth table. Parameter ``lyt``: The SiDB cell-level layout to be checked. @@ -13693,9 +13743,6 @@ Parameter ``input_bdl_wire``: Parameter ``output_bdl_wire``: Optional BDL output wires of lyt. -Parameter ``input_bdl_wire_direction``: - Optional BDL input wire directions of lyt. - Returns: A pair containing the operational status of the gate layout (either `OPERATIONAL` or `NON_OPERATIONAL`) and the number of @@ -13706,8 +13753,8 @@ static const char *__doc_fiction_is_operational_params = R"doc(Parameters for th static const char *__doc_fiction_is_operational_params_input_bdl_iterator_params = R"doc(Parameters for the BDL input iterator.)doc"; static const char *__doc_fiction_is_operational_params_op_condition = -R"doc(Condition which is used to decide if a layout is `operational` or -`non-operational`.)doc"; +R"doc(Condition which is used to decide if a layout is operational or non- +operational.)doc"; static const char *__doc_fiction_is_operational_params_sim_engine = R"doc(The simulation engine to be used for the operational domain @@ -13846,6 +13893,34 @@ Parameter ``dist_fn``: The shortest loop-less path in `layout` from `objective.source` to `objective.target`.)doc"; +static const char *__doc_fiction_kink_induced_non_operational_input_patterns = +R"doc(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. + +@note "Kink induced non-operational" refers to the non-operational +status being exclusively caused by kinks with an otherwise correct +logic match. + +Template parameter ``Lyt``: + SiDB cell-level layout type. + +Template parameter ``TT``: + Type of the truth table. + +Parameter ``lyt``: + The SiDB layout. + +Parameter ``spec``: + Vector of truth table specifications. + +Parameter ``params``: + Parameters for the `is_operational` algorithm. + +Returns: + The input combinations where kinks induce the SiDB layout to + become non-operational.)doc"; + static const char *__doc_fiction_layout_coordinate_path = R"doc(A path in a layout defined as an ordered sequence of coordinates. @@ -14462,16 +14537,16 @@ Parameter ``n``: Irregular clocking scheme.)doc"; static const char *__doc_fiction_operational_condition = -R"doc(Condition which is used to decide if a layout is `operational` or -`non-operational`.)doc"; +R"doc(Condition which is used to decide if a layout is operational or non- +operational.)doc"; static const char *__doc_fiction_operational_condition_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"; +is considered as non-operational.)doc"; static const char *__doc_fiction_operational_condition_TOLERATE_KINKS = R"doc(Even if the I/O pins show kinks, the layout is still considered as -`operational`.)doc"; +operational.)doc"; static const char *__doc_fiction_operational_domain = R"doc(An operational domain is a set of simulation parameter values for @@ -14777,12 +14852,11 @@ static const char *__doc_fiction_operational_domain_value_range_min = R"doc(The static const char *__doc_fiction_operational_domain_value_range_step = R"doc(The step size of the dimension sweep.)doc"; static const char *__doc_fiction_operational_input_patterns = -R"doc(This function determines the input combinations for which the SiDB- -based logic, represented by the provided layout (`lyt`) and truth -table specifications (`spec`), produces the correct output. +R"doc(This function determines the input combinations for which the layout +is operational. Template parameter ``Lyt``: - Type of the cell-level layout. + SiDB cell-level layout type. Template parameter ``TT``: Type of the truth table. diff --git a/bindings/pyfiction/test/algorithms/simulation/sidb/test_is_operational.py b/bindings/pyfiction/test/algorithms/simulation/sidb/test_is_operational.py index 6a43b1408..8ebcc8347 100644 --- a/bindings/pyfiction/test/algorithms/simulation/sidb/test_is_operational.py +++ b/bindings/pyfiction/test/algorithms/simulation/sidb/test_is_operational.py @@ -5,7 +5,6 @@ dir_path = os.path.dirname(os.path.realpath(__file__)) class TestIsOperational(unittest.TestCase): - def test_is_operational(self): lyt = sidb_100_lattice() @@ -56,6 +55,29 @@ def test_and_gate_kinks(self): self.assertEqual(op_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") + + params = is_operational_params() + params.simulation_parameters = sidb_simulation_parameters(2, -0.32) + + result = is_kink_induced_non_operational(lyt, [create_and_tt()], params) + + self.assertTrue(result) + + def test_and_gate_non_operational_input_patterns_due_to_kinks(self): + + lyt = read_sqd_layout_100(dir_path + "/../../../resources/AND_mu_032_kinks.sqd") + + params = is_operational_params() + params.simulation_parameters = sidb_simulation_parameters(2, -0.32) + + non_operational_pattern_kinks = kink_induced_non_operational_input_patterns(lyt, [create_and_tt()], params) + + self.assertEqual(non_operational_pattern_kinks, {1, 2}) + def test_and_gate_111_lattice_11_input_pattern(self): lyt = read_sqd_layout_111(dir_path + "/../../../resources/AND_mu_032_111_surface.sqd") diff --git a/docs/algorithms/sidb_simulation.rst b/docs/algorithms/sidb_simulation.rst index 132f27051..4c3e9f30a 100644 --- a/docs/algorithms/sidb_simulation.rst +++ b/docs/algorithms/sidb_simulation.rst @@ -235,6 +235,8 @@ Operational Domain Computation :members: .. doxygenfunction:: fiction::is_operational .. doxygenfunction:: fiction::operational_input_patterns + .. doxygenfunction:: fiction::is_kink_induced_non_operational + .. doxygenfunction:: fiction::kink_induced_non_operational_input_patterns **Header:** ``fiction/algorithms/simulation/sidb/operational_domain.hpp`` @@ -274,6 +276,8 @@ Operational Domain Computation :members: .. autofunction:: mnt.pyfiction.is_operational .. autofunction:: mnt.pyfiction.operational_input_patterns + .. autofunction:: mnt.pyfiction.is_kink_induced_non_operational + .. autofunction:: mnt.pyfiction.kink_induced_non_operational_input_patterns .. autoclass:: mnt.pyfiction.sweep_parameter :members: diff --git a/docs/changelog.rst b/docs/changelog.rst index b35be9aca..f37809f98 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -12,6 +12,7 @@ Added ##### - Algorithms: - Simulation: + - Added option to determine if kinks induce layout to become non-operational - Kink control option for critical temperature simulation of SiDB layouts - Python bindings: - Support for Python 3.13 (including GIL-free multi-threading) diff --git a/include/fiction/algorithms/simulation/sidb/is_operational.hpp b/include/fiction/algorithms/simulation/sidb/is_operational.hpp index dc9035d62..2d1bd9150 100644 --- a/include/fiction/algorithms/simulation/sidb/is_operational.hpp +++ b/include/fiction/algorithms/simulation/sidb/is_operational.hpp @@ -10,7 +10,6 @@ #include "fiction/algorithms/simulation/sidb/detect_bdl_pairs.hpp" #include "fiction/algorithms/simulation/sidb/detect_bdl_wires.hpp" #include "fiction/algorithms/simulation/sidb/determine_groundstate_from_simulation_results.hpp" -#include "fiction/algorithms/simulation/sidb/energy_distribution.hpp" #include "fiction/algorithms/simulation/sidb/exhaustive_ground_state_simulation.hpp" #include "fiction/algorithms/simulation/sidb/quickexact.hpp" #include "fiction/algorithms/simulation/sidb/quicksim.hpp" @@ -54,16 +53,16 @@ enum class operational_status : uint8_t }; /** - * Condition which is used to decide if a layout is `operational` or `non-operational`. + * Condition which is used to decide if a layout is operational or non-operational. */ enum class operational_condition : uint8_t { /** - * Even if the I/O pins show kinks, the layout is still considered as `operational`. + * Even if the I/O pins show kinks, the layout is still considered as operational. */ TOLERATE_KINKS, /** - * The I/O pins are not allowed to show kinks. If kinks exist, the layout is considered as `non-operational`. + * The I/O pins are not allowed to show kinks. If kinks exist, the layout is considered as non-operational. */ REJECT_KINKS }; @@ -86,13 +85,33 @@ struct is_operational_params */ bdl_input_iterator_params input_bdl_iterator_params{}; /** - * Condition which is used to decide if a layout is `operational` or `non-operational`. + * Condition which is used to decide if a layout is operational or non-operational. */ operational_condition op_condition = operational_condition::TOLERATE_KINKS; }; namespace detail { + +/** + * Reason why a layout is non-operational. + */ +enum class non_operationality_reason : uint8_t +{ + /** + * Kinks induced the layout to become non-operational. + */ + KINKS, + /** + * The layout is non-operational because of logic mismatch. + */ + LOGIC_MISMATCH, + /** + * No reason for non-operationality could be determined. + */ + NONE, +}; + /** * Implementation of the `is_operational` algorithm for a given gate layout. * @@ -102,7 +121,7 @@ namespace detail * to expected outputs from a truth table. * * @tparam Lyt SiDB cell-level layout type. - * @tparam TT The type of the truth table specifying the gate behavior. + * @tparam TT Type of the truth table. */ template class is_operational_impl @@ -154,14 +173,17 @@ class is_operational_impl * This function executes the operational status checking algorithm for the gate layout * and parameters provided during initialization. * - * @return The operational status of the gate layout (either `OPERATIONAL` or `NON_OPERATIONAL`). + * @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]] operational_status run() noexcept + [[nodiscard]] std::pair run() noexcept { assert(!output_bdl_pairs.empty() && "No output cell provided."); assert((truth_table.size() == output_bdl_pairs.size()) && "Number of truth tables and output BDL pairs does not match"); + bool at_least_one_layout_is_kink_induced_non_operational = false; + // number of different input combinations for (auto i = 0u; i < truth_table.front().num_bits(); ++i, ++bii) { @@ -170,7 +192,7 @@ class is_operational_impl // if positively charged SiDBs can occur, the SiDB layout is considered as non-operational if (can_positive_charges_occur(*bii, parameters.simulation_parameters)) { - return operational_status::NON_OPERATIONAL; + return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; } // performs physical simulation of a given SiDB layout at a given input combination @@ -179,23 +201,35 @@ class is_operational_impl // if no physically valid charge distributions were found, the layout is non-operational if (simulation_results.charge_distributions.empty()) { - return operational_status::NON_OPERATIONAL; + return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; } const auto ground_states = determine_groundstate_from_simulation_results(simulation_results); for (const auto& gs : ground_states) { - const auto op_status = verifiy_logic_match_of_cds(gs, i); - if (op_status == operational_status::NON_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) + { + return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; + } + if (op_status == operational_status::NON_OPERATIONAL && + non_op_reason == non_operationality_reason::KINKS) { - return operational_status::NON_OPERATIONAL; + at_least_one_layout_is_kink_induced_non_operational = true; + continue; } } } + if (at_least_one_layout_is_kink_induced_non_operational) + { + return {operational_status::NON_OPERATIONAL, non_operationality_reason::KINKS}; + } + // if we made it here, the layout is operational - return operational_status::OPERATIONAL; + return {operational_status::OPERATIONAL, non_operationality_reason::NONE}; } /** * Checks if the given charge distribution correctly encodes the expected logic for the given input pattern, @@ -212,11 +246,14 @@ class is_operational_impl * * @param given_cds The charge distribution surface to be checked for operation. * @param input_pattern Input pattern represented by the position of perturbers. - * @return Operational status indicating if the layout is `operational` or `non-operational`. + * @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]] operational_status verifiy_logic_match_of_cds(const charge_distribution_surface& given_cds, - const uint64_t input_pattern) noexcept + [[nodiscard]] std::pair + verify_logic_match_of_cds(const charge_distribution_surface& given_cds, const uint64_t input_pattern) noexcept { + auto non_operational_reason = non_operationality_reason::LOGIC_MISMATCH; + assert(!output_bdl_pairs.empty() && "No output cell provided."); assert((truth_table.size() == output_bdl_pairs.size()) && "Number of truth tables and output BDL pairs does not match"); @@ -224,7 +261,7 @@ class is_operational_impl // if positively charged SiDBs can occur, the SiDB layout is considered as non-operational if (can_positive_charges_occur(given_cds, parameters.simulation_parameters)) { - return operational_status::NON_OPERATIONAL; + return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; } // fetch the charge states of the output BDL pair @@ -236,7 +273,7 @@ class is_operational_impl // if the output charge states are equal, the layout is not operational if (charge_state_output_lower == charge_state_output_upper) { - return operational_status::NON_OPERATIONAL; + return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; } // if the expected output is 1, the expected charge states are (upper, lower) = (0, -1) @@ -244,7 +281,7 @@ class is_operational_impl { if (!encodes_bit_one(given_cds, output_bdl_pairs[output], output_bdl_wires[output].port)) { - return operational_status::NON_OPERATIONAL; + return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; } } // if the expected output is 0, the expected charge states are (upper, lower) = (-1, 0) @@ -252,7 +289,7 @@ class is_operational_impl { if (!encodes_bit_zero(given_cds, output_bdl_pairs[output], output_bdl_wires[output].port)) { - return operational_status::NON_OPERATIONAL; + return {operational_status::NON_OPERATIONAL, non_operationality_reason::LOGIC_MISMATCH}; } } @@ -261,26 +298,36 @@ class is_operational_impl if (check_existence_of_kinks_in_input_wires(given_cds, input_pattern) || check_existence_of_kinks_in_output_wires(given_cds, input_pattern)) { - return operational_status::NON_OPERATIONAL; + non_operational_reason = non_operationality_reason::KINKS; } } } + if (non_operational_reason == non_operationality_reason::KINKS) + { + return {operational_status::NON_OPERATIONAL, non_operationality_reason::KINKS}; + } + // if we made it here, the layout is operational - return operational_status::OPERATIONAL; + return {operational_status::OPERATIONAL, non_operationality_reason::NONE}; } /** - * Determines the input combinations yielding the correct output. + * Determines the input combinations for which the layout is non-operational and the reason why the layout is + * non-operational. * - * @return All inputs (e.g. 2-input Boolean function: 00 ^= 0; 10 ^= 2) for which the correct output is computed. + * @return Vector of pairs where the first element of the pair is the input pattern (e.g. 2-input Boolean function: + * 00 ^= 0; 10 ^= 2) for which the layout is non-operational. The second entry indicates the reason why the + * layout is non-operational (`non_operationality_reason`) for the given input pattern. */ - [[nodiscard]] std::set determine_operational_input_patterns() noexcept + [[nodiscard]] std::vector> + determine_non_operational_input_patterns_and_non_operationality_reason() noexcept { assert(!output_bdl_pairs.empty() && "No output cell provided."); assert((truth_table.size() == output_bdl_pairs.size()) && "Number of truth tables and output BDL pairs does not match"); - std::set operational_inputs{}; + 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) @@ -302,57 +349,20 @@ class is_operational_impl continue; } - // find the ground state, which is the charge distribution with the lowest energy - const auto ground_state = std::min_element( - simulation_results.charge_distributions.cbegin(), simulation_results.charge_distributions.cend(), - [](const auto& lhs, const auto& rhs) { return lhs.get_system_energy() < rhs.get_system_energy(); }); - - // ground state is degenerate - if ((energy_distribution(simulation_results.charge_distributions).cbegin()->second) > 1) - { - continue; - } + const auto ground_states = determine_groundstate_from_simulation_results(simulation_results); - bool correct_output = true; - // fetch the charge states of the output BDL pair - for (auto output = 0u; output < output_bdl_pairs.size(); output++) + for (const auto& gs : ground_states) { - const auto charge_state_output_upper = ground_state->get_charge_state(output_bdl_pairs[output].upper); - const auto charge_state_output_lower = ground_state->get_charge_state(output_bdl_pairs[output].lower); - - // if the output charge states are equal, the layout is not operational - if (charge_state_output_lower == charge_state_output_upper) - { - correct_output = false; - break; - } - - // if the expected output is 1, the expected charge states are (upper, lower) = (0, -1) - if (kitty::get_bit(truth_table[output], i)) - { - if (!encodes_bit_one(*ground_state, output_bdl_pairs[output], output_bdl_wires[output].port)) - { - correct_output = false; - } - } - // if the expected output is 0, the expected charge states are (upper, lower) = (-1, 0) - else + const auto [op_status, non_op_reason] = verify_logic_match_of_cds(gs, i); + if (op_status == operational_status::NON_OPERATIONAL) { - if (!encodes_bit_zero(*ground_state, output_bdl_pairs[output], output_bdl_wires[output].port)) - { - correct_output = false; - } + non_operational_input_pattern_and_non_operationality_reason.emplace_back(i, non_op_reason); } } - - if (correct_output) - { - operational_inputs.insert(i); - } } // if we made it here, the layout is operational - return operational_inputs; + return non_operational_input_pattern_and_non_operationality_reason; } /** * Returns the total number of simulator invocations. @@ -369,10 +379,6 @@ class is_operational_impl * SiDB cell-level layout. */ const Lyt layout; - /** - * SiDB charge distribution surface. - */ - // const charge_distribution_surface cds; /** * The specification of the layout. */ @@ -402,8 +408,8 @@ class is_operational_impl */ std::size_t simulator_invocations{0}; /** - * This function conducts physical simulation of the given layout (gate layout with certain input combination). The - * simulation results are stored in the `sim_result` variable. + * This function conducts physical simulation of the given layout (gate layout with certain input combination). + * The simulation results are stored in the `sim_result` variable. * * @param bdl_iterator A reference to a BDL input iterator representing the gate layout at a given input * combination. The simulation is performed based on the configuration represented by the iterator. @@ -611,13 +617,12 @@ class is_operational_impl * combinations. * * @tparam Lyt SiDB cell-level layout type. - * @tparam TT The type of the truth table specifying the layout behavior. + * @tparam TT Type of the truth table. * @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. * @param input_bdl_wire Optional BDL input wires of lyt. * @param output_bdl_wire Optional BDL output wires of lyt. - * @param input_bdl_wire_direction Optional BDL input wire directions of lyt. * @return A pair containing the operational status of the gate layout (either `OPERATIONAL` or `NON_OPERATIONAL`) and * the number of input combinations tested. */ @@ -635,7 +640,7 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational assert(lyt.num_pos() > 0 && "lyt needs output cells"); assert(!spec.empty()); - // all elements in tts must have the same number of variables + // all elements in spec must have the same number of variables assert(std::adjacent_find(spec.cbegin(), spec.cend(), [](const auto& a, const auto& b) { return a.num_vars() != b.num_vars(); }) == spec.cend()); @@ -643,18 +648,21 @@ is_operational(const Lyt& lyt, const std::vector& spec, const is_operational { detail::is_operational_impl p{lyt, spec, params, input_bdl_wire.value(), output_bdl_wire.value()}; - return {p.run(), p.get_number_of_simulator_invocations()}; + const auto [status, _] = p.run(); + + return {status, p.get_number_of_simulator_invocations()}; } detail::is_operational_impl p{lyt, spec, params}; - return {p.run(), p.get_number_of_simulator_invocations()}; + const auto [status, _] = p.run(); + + return {status, p.get_number_of_simulator_invocations()}; } /** - * This function determines the input combinations for which the SiDB-based logic, represented by the - * provided layout (`lyt`) and truth table specifications (`spec`), produces the correct output. + * This function determines the input combinations for which the layout is operational. * - * @tparam Lyt Type of the cell-level layout. + * @tparam Lyt SiDB cell-level layout type. * @tparam TT Type of the truth table. * @param lyt The SiDB layout. * @param spec Vector of truth table specifications. @@ -673,13 +681,136 @@ template assert(lyt.num_pos() > 0 && "skeleton needs output cells"); assert(!spec.empty()); - // all elements in tts must have the same number of variables + // all elements in spec must have the same number of variables assert(std::adjacent_find(spec.cbegin(), spec.cend(), [](const auto& a, const auto& b) { return a.num_vars() != b.num_vars(); }) == spec.cend()); detail::is_operational_impl p{lyt, spec, params}; - return p.determine_operational_input_patterns(); + std::set input_patterns{}; + + // all possible input patterns + for (auto i = 0u; i < spec.front().num_bits(); ++i) + { + input_patterns.insert(i); + } + + const auto non_op_patterns_and_non_op_reason = + p.determine_non_operational_input_patterns_and_non_operationality_reason(); + + for (const auto& [input_pattern, _] : non_op_patterns_and_non_op_reason) + { + input_patterns.erase(input_pattern); + } + + 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. + * + * @note "Kink induced non-operational" refers to the non-operational status being exclusively caused by kinks with an + * otherwise correct logic match. + * + * @tparam Lyt SiDB cell-level layout type. + * @tparam TT Type of the truth table. + * @param lyt The SiDB layout. + * @param spec Vector of truth table specifications. + * @param params Parameters for the `is_operational` algorithm. + * @return The input combinations where kinks induce the SiDB layout to become non-operational. + */ +template +[[nodiscard]] std::set +kink_induced_non_operational_input_patterns(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"); + static_assert(kitty::is_truth_table::value, "TT is not a truth table"); + + assert(lyt.num_pis() > 0 && "skeleton needs input cells"); + assert(lyt.num_pos() > 0 && "skeleton needs output cells"); + + assert(!spec.empty()); + // all elements in tts must have the same number of variables + assert(std::adjacent_find(spec.cbegin(), spec.cend(), [](const auto& a, const auto& b) + { return a.num_vars() != b.num_vars(); }) == spec.cend()); + + is_operational_params params_with_rejecting_kinks = params; + params_with_rejecting_kinks.op_condition = operational_condition::REJECT_KINKS; + + detail::is_operational_impl p{lyt, spec, params_with_rejecting_kinks}; + + std::set kink_induced_non_op_patterns{}; + + const auto input_patterns_and_non_op_reason = + p.determine_non_operational_input_patterns_and_non_operationality_reason(); + + for (const auto& [input_pattern, status] : input_patterns_and_non_op_reason) + { + if (status == detail::non_operationality_reason::KINKS) + { + kink_induced_non_op_patterns.insert(input_pattern); + } + } + + return kink_induced_non_op_patterns; +} +/** + * This function determines if the layout is only considered as non-operational because of kinks. This means that + * the layout would be considered as operational, if kinks were accepted. + * + * @note "Kink induced non-operational" refers to the non-operational status being exclusively caused by kinks with an + * otherwise correct logic match. + * + * @tparam Lyt SiDB cell-level layout type. + * @tparam TT Type of the truth table. + * @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. + * @param input_bdl_wire Optional BDL input wires of lyt. + * @param output_bdl_wire Optional BDL output wires of lyt. + * @return Bool that indicates whether kinks induce the layout to become non-operational. `true` if the layout is + * non-operational due to kinks, `false` otherwise. + */ +template +[[nodiscard]] bool is_kink_induced_non_operational( + const Lyt& lyt, const std::vector& spec, const is_operational_params& params = {}, + const std::optional>>& input_bdl_wire = std::nullopt, + const std::optional>>& output_bdl_wire = std::nullopt) 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"); + static_assert(kitty::is_truth_table::value, "TT is not a truth table"); + + assert(lyt.num_pis() > 0 && "lyt needs input cells"); + assert(lyt.num_pos() > 0 && "lyt needs output cells"); + + assert(!spec.empty()); + // all elements in spec must have the same number of variables + assert(std::adjacent_find(spec.cbegin(), spec.cend(), [](const auto& a, const auto& b) + { return a.num_vars() != b.num_vars(); }) == spec.cend()); + + is_operational_params params_with_rejecting_kinks = params; + params_with_rejecting_kinks.op_condition = operational_condition::REJECT_KINKS; + + if (input_bdl_wire.has_value() && output_bdl_wire.has_value()) + { + detail::is_operational_impl p{lyt, spec, params_with_rejecting_kinks, input_bdl_wire.value(), + output_bdl_wire.value()}; + + const auto [op_status, non_op_reason] = p.run(); + + return op_status == operational_status::NON_OPERATIONAL && + non_op_reason == detail::non_operationality_reason::KINKS; + } + + detail::is_operational_impl p{lyt, spec, params_with_rejecting_kinks}; + + const auto [op_status, non_op_reason] = p.run(); + + return op_status == operational_status::NON_OPERATIONAL && + non_op_reason == detail::non_operationality_reason::KINKS; } } // namespace fiction diff --git a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp index 8f502dc33..cd93fbcda 100644 --- a/include/fiction/algorithms/simulation/sidb/operational_domain.hpp +++ b/include/fiction/algorithms/simulation/sidb/operational_domain.hpp @@ -5,6 +5,7 @@ #ifndef FICTION_OPERATIONAL_DOMAIN_HPP #define FICTION_OPERATIONAL_DOMAIN_HPP +#include "fiction/algorithms/simulation/sidb/energy_distribution.hpp" #include "fiction/algorithms/simulation/sidb/is_operational.hpp" #include "fiction/algorithms/simulation/sidb/quickexact.hpp" #include "fiction/algorithms/simulation/sidb/quicksim.hpp" diff --git a/include/fiction/algorithms/simulation/sidb/verify_logic_match.hpp b/include/fiction/algorithms/simulation/sidb/verify_logic_match.hpp index 78e33d86e..d2c538862 100644 --- a/include/fiction/algorithms/simulation/sidb/verify_logic_match.hpp +++ b/include/fiction/algorithms/simulation/sidb/verify_logic_match.hpp @@ -60,7 +60,9 @@ template detail::is_operational_impl p{cds, spec, params, input_wires, output_wires}; - return p.verifiy_logic_match_of_cds(cds, input_pattern); + const auto [op_status, _] = p.verify_logic_match_of_cds(cds, input_pattern); + + return op_status; } } // namespace fiction diff --git a/test/algorithms/simulation/sidb/is_operational.cpp b/test/algorithms/simulation/sidb/is_operational.cpp index e751bacbb..2556c9db9 100644 --- a/test/algorithms/simulation/sidb/is_operational.cpp +++ b/test/algorithms/simulation/sidb/is_operational.cpp @@ -27,23 +27,35 @@ TEST_CASE("SiQAD OR gate", "[is-operational]") const sidb_100_cell_clk_lyt_siqad lat{layout_or_gate}; - CHECK(is_operational( - lat, std::vector{create_or_tt()}, - is_operational_params{sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{ - detect_bdl_wires_params{1.5}, - bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, - operational_condition::REJECT_KINKS}) - .first == operational_status::NON_OPERATIONAL); + auto op_params = is_operational_params{ + sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, + bdl_input_iterator_params{detect_bdl_wires_params{1.5}, + bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, + operational_condition::REJECT_KINKS}; - CHECK(is_operational( - lat, std::vector{create_or_tt()}, - is_operational_params{sidb_simulation_parameters{2, -0.28}, sidb_simulation_engine::QUICKEXACT, - bdl_input_iterator_params{ - detect_bdl_wires_params{1.5}, - bdl_input_iterator_params::input_bdl_configuration::PERTURBER_ABSENCE_ENCODED}, - operational_condition::TOLERATE_KINKS}) - .first == operational_status::OPERATIONAL); + CHECK(is_operational(lat, std::vector{create_or_tt()}, op_params).first == operational_status::NON_OPERATIONAL); + + // determine if kinks induce layout to become non-operational. + const auto kink_induced_non_operational = + is_kink_induced_non_operational(lat, std::vector{create_or_tt()}, op_params); + CHECK(kink_induced_non_operational); + + const auto input_wires = detect_bdl_wires(lat, detect_bdl_wires_params{1.5}); + const auto output_wires = detect_bdl_wires(lat, detect_bdl_wires_params{1.5}); + + // determine if kinks induce layout to become non-operational. + const auto kink_induced_non_operational_predefined_wires = is_kink_induced_non_operational( + lat, std::vector{create_or_tt()}, op_params, std::optional{input_wires}, std::optional{output_wires}); + CHECK(kink_induced_non_operational_predefined_wires); + + // determine input patterns for which kinks induce layout to become non-operational. + const auto kink_induced_non_operational_input_pattern = + kink_induced_non_operational_input_patterns(lat, std::vector{create_or_tt()}, op_params); + + CHECK(kink_induced_non_operational_input_pattern.size() == 1); + + op_params.op_condition = operational_condition::TOLERATE_KINKS; + CHECK(is_operational(lat, std::vector{create_or_tt()}, op_params).first == operational_status::OPERATIONAL); } TEST_CASE("SiQAD's AND gate with input BDL pairs of different size", "[is-operational]") @@ -143,7 +155,7 @@ TEST_CASE("Bestagon AND gate", "[is-operational]") is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}) .first == operational_status::NON_OPERATIONAL); } - SECTION("Count the number of non-operational input combinations") + SECTION("Count the number of non-operational input combinations, accepting kinks") { const auto op_inputs = operational_input_patterns( lyt, std::vector{create_and_tt()}, @@ -219,7 +231,9 @@ TEMPLATE_TEST_CASE("AND gate on the H-Si(111)-1x1 surface", "[is-operational]", } } -TEST_CASE("AND gate with bestagon structure and kink state at right input wire for input 01", "[is-operational]") +TEST_CASE( + "AND gate with Bestagon structure and kink state on right input wire for input 01 and left input wire for input 10", + "[is-operational]") { const auto lyt = blueprints::and_gate_with_kink_states(); @@ -237,6 +251,23 @@ TEST_CASE("AND gate with bestagon structure and kink state at right input wire f operational_condition::REJECT_KINKS}) .first == operational_status::NON_OPERATIONAL); } + SECTION("check if is_kink_induced_non_operational returns true") + { + // check if the function works correctly even if the parameter is wrong (kinks are accepted). + CHECK(is_kink_induced_non_operational( + lyt, std::vector{create_and_tt()}, + is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, + bdl_input_iterator_params{}, operational_condition::TOLERATE_KINKS})); + } + + SECTION("check input patterns for which kinks induce the layout to become non-operational") + { + CHECK(kink_induced_non_operational_input_patterns( + lyt, std::vector{create_and_tt()}, + is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, + bdl_input_iterator_params{}, operational_condition::TOLERATE_KINKS}) == + std::set{1, 2}); + } } TEST_CASE("BDL wire", "[is-operational]") @@ -281,53 +312,25 @@ TEST_CASE("flipped CX bestagon gate", "[is-operational]") is_operational_params{sidb_simulation_parameters{2, -0.32}, sidb_simulation_engine::QUICKEXACT, bdl_input_iterator_params{}, operational_condition::REJECT_KINKS}) .first == operational_status::OPERATIONAL); -} - -TEST_CASE("is operational check for Bestagon CX gate", "[is-operational], [quality]") -{ - using layout = sidb_cell_clk_lyt_siqad; - - layout lyt{}; - - lyt.assign_cell_type({36, 1, 0}, sidb_technology::cell_type::INPUT); - lyt.assign_cell_type({2, 1, 0}, sidb_technology::cell_type::INPUT); - - lyt.assign_cell_type({0, 0, 0}, sidb_technology::cell_type::INPUT); - lyt.assign_cell_type({38, 0, 0}, sidb_technology::cell_type::INPUT); - - lyt.assign_cell_type({6, 2, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({20, 12, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({8, 3, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({14, 5, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({14, 11, 1}, sidb_technology::cell_type::NORMAL); - - lyt.assign_cell_type({12, 4, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({14, 15, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({26, 4, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({14, 9, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({24, 15, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({12, 16, 0}, sidb_technology::cell_type::NORMAL); - - lyt.assign_cell_type({18, 9, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({26, 16, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({24, 13, 1}, sidb_technology::cell_type::NORMAL); + 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{}, operational_condition::REJECT_KINKS}); - lyt.assign_cell_type({24, 5, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({30, 3, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({16, 13, 1}, sidb_technology::cell_type::NORMAL); + CHECK(kink_induced_non_operational_input_pattern.empty()); - lyt.assign_cell_type({32, 2, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({20, 8, 0}, sidb_technology::cell_type::NORMAL); + 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{}, operational_condition::REJECT_KINKS}); - lyt.assign_cell_type({30, 17, 0}, sidb_technology::cell_type::OUTPUT); - lyt.assign_cell_type({6, 18, 0}, sidb_technology::cell_type::OUTPUT); - - lyt.assign_cell_type({32, 18, 0}, sidb_technology::cell_type::OUTPUT); - lyt.assign_cell_type({8, 17, 0}, sidb_technology::cell_type::OUTPUT); + CHECK(!kink_induced_non_operational); +} - lyt.assign_cell_type({2, 19, 0}, sidb_technology::cell_type::NORMAL); - lyt.assign_cell_type({36, 19, 0}, sidb_technology::cell_type::NORMAL); +TEST_CASE("is operational check for Bestagon CX gate", "[is-operational], [quality]") +{ + const auto lyt = blueprints::bestagon_crossing(); CHECK(lyt.num_cells() == 29); @@ -360,6 +363,10 @@ TEST_CASE("is operational check for Bestagon CX gate", "[is-operational], [quali is_operational_params{sidb_simulation_parameters{2, -0.30}, sidb_simulation_engine::QUICKEXACT}, std::optional{input_bdl_wires}, std::optional{output_bdl_wires}) .first == 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}, + std::optional{input_bdl_wires}, std::optional{output_bdl_wires})); } }