From b3879993ef3a6d7a547eaebf3a3bfd196a563400 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Mon, 20 Nov 2023 11:11:57 +0100 Subject: [PATCH 01/47] add sparse iteration to code base Signed-off-by: Martijn Govers --- .../math_solver/sparse_iteration.hpp | 231 ++++++++++++++++++ tests/cpp_unit_tests/CMakeLists.txt | 1 + .../cpp_unit_tests/test_sparse_iteration.cpp | 57 +++++ 3 files changed, 289 insertions(+) create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp create mode 100644 tests/cpp_unit_tests/test_sparse_iteration.cpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp new file mode 100644 index 000000000..b91ae4bf6 --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp @@ -0,0 +1,231 @@ +// SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once +#ifndef POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ITERATION_HPP +#define POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ITERATION_HPP + +#include "../power_grid_model.hpp" + +#include // remove and remove_if +#include +#include +#include +#include +#include + +namespace power_grid_model::math_solver { + +void rmElemVectPair(ID& u, std::vector>& dgd) { + ID i = 0; + while (i < dgd.size()) + if (dgd[i].first == u) { + dgd.erase(dgd.begin() + i); + break; + } else + i++; +} + +void setElemVectPair(ID& u, ID v, std::vector>& dgd) { + ID i = 0; + while (i < dgd.size()) { + if (dgd[i].first == u) { + dgd[i].second = v; + break; + } else { + i++; + } + } +} + +std::vector adj(ID& u, std::map>& d) { + std::vector l; + + for (const auto& it : d) { + if (it.first == u) + l.insert(l.end(), it.second.begin(), it.second.end()); + + if (find(it.second.begin(), it.second.end(), u) != it.second.end()) { + std::vector v{it.first}; + l.insert(l.end(), v.begin(), v.end()); + } + } + + return l; +} + +bool cmpFirts(std::pair& a, std::pair& b) { return a.first < b.first; } + +std::vector>>> compSizeDegreesGraph(std::map>& d) { + std::vector> dd; + std::vector v; + ID n = 0; + + for (const auto& it : d) { + ID k = it.first; + if (find(v.begin(), v.end(), k) == v.end()) { + std::vector vk{k}; + v.insert(v.end(), vk.begin(), vk.end()); + n += 1; + dd.push_back({k, adj(k, d).size()}); + } + for (const ID& el : it.second) { + ID e = el; + if (find(v.begin(), v.end(), e) == v.end()) { + std::vector ve{e}; + v.insert(v.end(), ve.begin(), ve.end()); + n += 1; + dd.push_back({e, adj(e, d).size()}); + } + } + } + + sort(dd.begin(), dd.end(), cmpFirts); + + return {{n, dd}}; +} + +std::vector, std::vector>> checkIndistguishable(ID& u, std::map>& d) { + std::vector l, rl, lu, lv, vu{u}, vv; + l = adj(u, d); + lu = l; + lu.insert(lu.end(), vu.begin(), vu.end()); + + for (auto& v : l) { + lv = adj(v, d); + vv = {v}; + lv.insert(lv.end(), vv.begin(), vv.end()); + sort(lu.begin(), lu.end()); + sort(lv.begin(), lv.end()); + if (lu == lv) { + rl.insert(rl.end(), vv.begin(), vv.end()); + } + } + + return {{l, rl}}; +} + +std::map> makeClique(std::vector& l) { + std::map> d; + ID b = l.size() - 1; + + for (int i = 0; i < b; i++) { + ID index = i + 1; + auto start = l.begin() + index; + std::vector sl(l.size() - index); + copy(start, l.end(), sl.begin()); + d[l[i]] = sl; + } + + return d; +} + +bool inGraph(std::vector& e, std::map>& d) { + bool t1 = (d.find(e[0]) != d.end()) and (find(d[e[0]].begin(), d[e[0]].end(), e[1]) != d[e[0]].end()); + bool t2 = (d.find(e[1]) != d.end()) and (find(d[e[1]].begin(), d[e[1]].end(), e[0]) != d[e[1]].end()); + + return (t1 || t2); +} + +std::vector rmvVerticesUpdateDegrees(ID& u, std::map>& d, std::vector>& dgd, + std::vector>& fills) { + std::vector, std::vector>> nbsrl = checkIndistguishable(u, d); + std::vector& nbs = nbsrl[0].first; + std::vector& rl = nbsrl[0].second; + std::vector alpha = rl, vu{u}; + std::map> dd; + + rl.insert(rl.begin(), vu.begin(), vu.end()); + + for (auto& uu : rl) { + if (uu != u) + nbs.erase(remove(nbs.begin(), nbs.end(), uu), nbs.end()); + + rmElemVectPair(uu, dgd); + std::vector el; + for (auto& it : d) { + it.second.erase(remove(it.second.begin(), it.second.end(), uu), it.second.end()); + if (it.second.empty()) { + ID k = it.first; + std::vector vk{k}; + el.insert(el.end(), vk.begin(), vk.end()); + } + } + + std::vector vuu{uu}; + el.insert(el.end(), vuu.begin(), vuu.end()); + + for (auto& it : el) + d.erase(it); + } + + dd = makeClique(nbs); + + for (auto& it : dd) { + ID k = it.first; + for (const ID& e : it.second) { + std::vector t{k, e}; + if (not inGraph(t, d)) { + if (d.find(k) != d.end()) { + std::vector ve{e}; + d[k].insert(d[k].end(), ve.begin(), ve.end()); + fills.push_back({k, e}); + } else if (d.find(e) != d.end()) { + std::vector vk{k}; + d[e].insert(d[e].end(), vk.begin(), vk.end()); + fills.push_back({e, k}); + } else { + std::vector ve{e}; + d[k].insert(d[k].end(), ve.begin(), ve.end()); + fills.push_back({k, e}); + } + } + } + } + + for (auto& e : nbs) { + setElemVectPair(e, adj(e, d).size(), dgd); + } + + return alpha; +} + +std::vector, std::vector>>> +minimumDegreeAlgorithm(std::map>& d) { + std::vector>>> data = compSizeDegreesGraph(d); + ID& n = data[0].first; + std::vector>& dgd = data[0].second; + std::vector alpha; + std::vector> fills; + std::vector, std::vector>>> alpha_fills; + + for (int k = 0; k < n; k++) { + ID u = get<0>(*min_element(begin(dgd), end(dgd), [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); + std::vector vu{u}; + alpha.insert(alpha.end(), vu.begin(), vu.end()); + if ((d.size() == 1) and d.begin()->second.size() == 1) { + ID a = d.begin()->first; + ID b = d.begin()->second[0]; + if (alpha.back() == a) { + std::vector vb{b}; + alpha.insert(alpha.end(), vb.begin(), vb.end()); + } else { + std::vector va{a}; + alpha.insert(alpha.end(), va.begin(), va.end()); + } + break; + } else { + std::vector va = rmvVerticesUpdateDegrees(u, d, dgd, fills); + alpha.insert(alpha.end(), va.begin(), va.end()); + if (d.empty()) { + break; + } + } + } + alpha_fills = {{alpha, fills}}; + return alpha_fills; +} +} // namespace power_grid_model::math_solver + +#endif diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt index aa270ec72..5b358fc75 100644 --- a/tests/cpp_unit_tests/CMakeLists.txt +++ b/tests/cpp_unit_tests/CMakeLists.txt @@ -18,6 +18,7 @@ set(PROJECT_SOURCES "test_shunt.cpp" "test_transformer.cpp" "test_sparse_lu_solver.cpp" + "test_sparse_iteration.cpp" "test_y_bus.cpp" "test_math_solver.cpp" "test_measured_values.cpp" diff --git a/tests/cpp_unit_tests/test_sparse_iteration.cpp b/tests/cpp_unit_tests/test_sparse_iteration.cpp new file mode 100644 index 000000000..8a72f4af0 --- /dev/null +++ b/tests/cpp_unit_tests/test_sparse_iteration.cpp @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include + +#include + +namespace { +namespace solver = power_grid_model::math_solver; +using namespace power_grid_model; + +void printVectPair(std::vector>& d) { + for (const auto& it : d) { + std::cout << it.first << ": " << it.second << std::endl; + } +} + +void printMap(std::map>& d) { + for (const auto& it : d) { + std::cout << it.first << ": "; + for (const ID& el : it.second) { + std::cout << el << " "; + } + std::cout << std::endl; + } +} + +void show(std::vector const& input) { + for (auto const& i : input) + std::cout << i << ", "; + std::cout << std::endl; +} +} // namespace + +TEST_CASE("Test sparse iteration") { + std::map> graph{{0, {3, 5}}, {1, {4, 5, 8}}, {2, {4, 5, 6}}, {3, {6, 7}}, + {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; + + auto start = std::chrono::high_resolution_clock::now(); + std::vector, std::vector>>> alpha_fills = + solver::minimumDegreeAlgorithm(graph); + auto stop = std::chrono::high_resolution_clock::now(); + + auto duration = duration_cast(stop - start); + float seconds = duration.count() / 1000000.0; + /* + std::cout << "Time taken by function: " + << duration.count() << " microseconds" << std::endl; + */ + std::cout << "Time taken by function: " << seconds << " seconds" << std::endl; + + show(alpha_fills[0].first); + printVectPair(alpha_fills[0].second); +} From bf05a4d9d08ffcc50bff1b0acf51a0f5d18eb505 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Mon, 20 Nov 2023 11:22:39 +0100 Subject: [PATCH 02/47] fix naming conventions Signed-off-by: Martijn Govers --- .../math_solver/sparse_iteration.hpp | 50 ++++++++++--------- .../cpp_unit_tests/test_sparse_iteration.cpp | 23 +++------ 2 files changed, 34 insertions(+), 39 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp index b91ae4bf6..ab13eac21 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp @@ -17,17 +17,20 @@ namespace power_grid_model::math_solver { -void rmElemVectPair(ID& u, std::vector>& dgd) { +namespace detail { +void remove_element_vector_pair(ID& u, std::vector>& dgd) { ID i = 0; - while (i < dgd.size()) + while (i < dgd.size()) { if (dgd[i].first == u) { dgd.erase(dgd.begin() + i); break; - } else + } else { i++; + } + } } -void setElemVectPair(ID& u, ID v, std::vector>& dgd) { +void set_element_vector_pair(ID& u, ID v, std::vector>& dgd) { ID i = 0; while (i < dgd.size()) { if (dgd[i].first == u) { @@ -55,9 +58,9 @@ std::vector adj(ID& u, std::map>& d) { return l; } -bool cmpFirts(std::pair& a, std::pair& b) { return a.first < b.first; } +bool compair_ids(std::pair& a, std::pair& b) { return a.first < b.first; } -std::vector>>> compSizeDegreesGraph(std::map>& d) { +std::vector>>> comp_size_degrees_graph(std::map>& d) { std::vector> dd; std::vector v; ID n = 0; @@ -81,12 +84,13 @@ std::vector>>> compSizeDegreesGraph( } } - sort(dd.begin(), dd.end(), cmpFirts); + sort(dd.begin(), dd.end()); return {{n, dd}}; } -std::vector, std::vector>> checkIndistguishable(ID& u, std::map>& d) { +std::vector, std::vector>> check_indistguishable(ID& u, + std::map>& d) { std::vector l, rl, lu, lv, vu{u}, vv; l = adj(u, d); lu = l; @@ -106,7 +110,7 @@ std::vector, std::vector>> checkIndistguishable(ID return {{l, rl}}; } -std::map> makeClique(std::vector& l) { +std::map> make_clique(std::vector& l) { std::map> d; ID b = l.size() - 1; @@ -121,16 +125,17 @@ std::map> makeClique(std::vector& l) { return d; } -bool inGraph(std::vector& e, std::map>& d) { +bool in_graph(std::vector& e, std::map>& d) { bool t1 = (d.find(e[0]) != d.end()) and (find(d[e[0]].begin(), d[e[0]].end(), e[1]) != d[e[0]].end()); bool t2 = (d.find(e[1]) != d.end()) and (find(d[e[1]].begin(), d[e[1]].end(), e[0]) != d[e[1]].end()); return (t1 || t2); } -std::vector rmvVerticesUpdateDegrees(ID& u, std::map>& d, std::vector>& dgd, - std::vector>& fills) { - std::vector, std::vector>> nbsrl = checkIndistguishable(u, d); +std::vector remove_vertices_update_degrees(ID& u, std::map>& d, + std::vector>& dgd, + std::vector>& fills) { + std::vector, std::vector>> nbsrl = check_indistguishable(u, d); std::vector& nbs = nbsrl[0].first; std::vector& rl = nbsrl[0].second; std::vector alpha = rl, vu{u}; @@ -142,7 +147,7 @@ std::vector rmvVerticesUpdateDegrees(ID& u, std::map>& d if (uu != u) nbs.erase(remove(nbs.begin(), nbs.end(), uu), nbs.end()); - rmElemVectPair(uu, dgd); + remove_element_vector_pair(uu, dgd); std::vector el; for (auto& it : d) { it.second.erase(remove(it.second.begin(), it.second.end(), uu), it.second.end()); @@ -160,13 +165,13 @@ std::vector rmvVerticesUpdateDegrees(ID& u, std::map>& d d.erase(it); } - dd = makeClique(nbs); + dd = make_clique(nbs); for (auto& it : dd) { ID k = it.first; for (const ID& e : it.second) { std::vector t{k, e}; - if (not inGraph(t, d)) { + if (not in_graph(t, d)) { if (d.find(k) != d.end()) { std::vector ve{e}; d[k].insert(d[k].end(), ve.begin(), ve.end()); @@ -185,20 +190,20 @@ std::vector rmvVerticesUpdateDegrees(ID& u, std::map>& d } for (auto& e : nbs) { - setElemVectPair(e, adj(e, d).size(), dgd); + set_element_vector_pair(e, adj(e, d).size(), dgd); } return alpha; } +} // namespace detail std::vector, std::vector>>> -minimumDegreeAlgorithm(std::map>& d) { - std::vector>>> data = compSizeDegreesGraph(d); +minimum_degree_ordering(std::map>& d) { + std::vector>>> data = detail::comp_size_degrees_graph(d); ID& n = data[0].first; std::vector>& dgd = data[0].second; std::vector alpha; std::vector> fills; - std::vector, std::vector>>> alpha_fills; for (int k = 0; k < n; k++) { ID u = get<0>(*min_element(begin(dgd), end(dgd), [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); @@ -216,15 +221,14 @@ minimumDegreeAlgorithm(std::map>& d) { } break; } else { - std::vector va = rmvVerticesUpdateDegrees(u, d, dgd, fills); + std::vector va = detail::remove_vertices_update_degrees(u, d, dgd, fills); alpha.insert(alpha.end(), va.begin(), va.end()); if (d.empty()) { break; } } } - alpha_fills = {{alpha, fills}}; - return alpha_fills; + return {{alpha, fills}}; } } // namespace power_grid_model::math_solver diff --git a/tests/cpp_unit_tests/test_sparse_iteration.cpp b/tests/cpp_unit_tests/test_sparse_iteration.cpp index 8a72f4af0..8e80d7843 100644 --- a/tests/cpp_unit_tests/test_sparse_iteration.cpp +++ b/tests/cpp_unit_tests/test_sparse_iteration.cpp @@ -12,25 +12,16 @@ namespace { namespace solver = power_grid_model::math_solver; using namespace power_grid_model; -void printVectPair(std::vector>& d) { +void print_vector_pair(std::vector>& d) { for (const auto& it : d) { std::cout << it.first << ": " << it.second << std::endl; } } -void printMap(std::map>& d) { - for (const auto& it : d) { - std::cout << it.first << ": "; - for (const ID& el : it.second) { - std::cout << el << " "; - } - std::cout << std::endl; - } -} - -void show(std::vector const& input) { - for (auto const& i : input) +void print_vector(std::vector const& input) { + for (auto const& i : input) { std::cout << i << ", "; + } std::cout << std::endl; } } // namespace @@ -41,7 +32,7 @@ TEST_CASE("Test sparse iteration") { auto start = std::chrono::high_resolution_clock::now(); std::vector, std::vector>>> alpha_fills = - solver::minimumDegreeAlgorithm(graph); + solver::minimum_degree_ordering(graph); auto stop = std::chrono::high_resolution_clock::now(); auto duration = duration_cast(stop - start); @@ -52,6 +43,6 @@ TEST_CASE("Test sparse iteration") { */ std::cout << "Time taken by function: " << seconds << " seconds" << std::endl; - show(alpha_fills[0].first); - printVectPair(alpha_fills[0].second); + print_vector(alpha_fills[0].first); + print_vector_pair(alpha_fills[0].second); } From d970f42aa2174d5e6cbdcac40857c8d61bb5f6e2 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 22 Nov 2023 09:05:21 +0100 Subject: [PATCH 03/47] different location Signed-off-by: Martijn Govers --- ...arse_iteration.hpp => sparse_ordening.hpp} | 7 ++- tests/cpp_unit_tests/CMakeLists.txt | 2 +- .../cpp_unit_tests/test_sparse_iteration.cpp | 48 ----------------- tests/cpp_unit_tests/test_sparse_ordening.cpp | 52 +++++++++++++++++++ 4 files changed, 56 insertions(+), 53 deletions(-) rename power_grid_model_c/power_grid_model/include/power_grid_model/{math_solver/sparse_iteration.hpp => sparse_ordening.hpp} (98%) delete mode 100644 tests/cpp_unit_tests/test_sparse_iteration.cpp create mode 100644 tests/cpp_unit_tests/test_sparse_ordening.cpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp similarity index 98% rename from power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp rename to power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index ab13eac21..a476a0a57 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/sparse_iteration.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -6,16 +6,15 @@ #ifndef POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ITERATION_HPP #define POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ITERATION_HPP -#include "../power_grid_model.hpp" +#include "power_grid_model.hpp" #include // remove and remove_if -#include #include #include #include #include -namespace power_grid_model::math_solver { +namespace power_grid_model { namespace detail { void remove_element_vector_pair(ID& u, std::vector>& dgd) { @@ -230,6 +229,6 @@ minimum_degree_ordering(std::map>& d) { } return {{alpha, fills}}; } -} // namespace power_grid_model::math_solver +} // namespace power_grid_model #endif diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt index 5b358fc75..2c05a5c43 100644 --- a/tests/cpp_unit_tests/CMakeLists.txt +++ b/tests/cpp_unit_tests/CMakeLists.txt @@ -18,11 +18,11 @@ set(PROJECT_SOURCES "test_shunt.cpp" "test_transformer.cpp" "test_sparse_lu_solver.cpp" - "test_sparse_iteration.cpp" "test_y_bus.cpp" "test_math_solver.cpp" "test_measured_values.cpp" "test_topology.cpp" + "test_sparse_ordening.cpp" "test_grouped_index_vector.cpp" "test_container.cpp" "test_sparse_mapping.cpp" diff --git a/tests/cpp_unit_tests/test_sparse_iteration.cpp b/tests/cpp_unit_tests/test_sparse_iteration.cpp deleted file mode 100644 index 8e80d7843..000000000 --- a/tests/cpp_unit_tests/test_sparse_iteration.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project -// -// SPDX-License-Identifier: MPL-2.0 - -#include - -#include - -#include - -namespace { -namespace solver = power_grid_model::math_solver; -using namespace power_grid_model; - -void print_vector_pair(std::vector>& d) { - for (const auto& it : d) { - std::cout << it.first << ": " << it.second << std::endl; - } -} - -void print_vector(std::vector const& input) { - for (auto const& i : input) { - std::cout << i << ", "; - } - std::cout << std::endl; -} -} // namespace - -TEST_CASE("Test sparse iteration") { - std::map> graph{{0, {3, 5}}, {1, {4, 5, 8}}, {2, {4, 5, 6}}, {3, {6, 7}}, - {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; - - auto start = std::chrono::high_resolution_clock::now(); - std::vector, std::vector>>> alpha_fills = - solver::minimum_degree_ordering(graph); - auto stop = std::chrono::high_resolution_clock::now(); - - auto duration = duration_cast(stop - start); - float seconds = duration.count() / 1000000.0; - /* - std::cout << "Time taken by function: " - << duration.count() << " microseconds" << std::endl; - */ - std::cout << "Time taken by function: " << seconds << " seconds" << std::endl; - - print_vector(alpha_fills[0].first); - print_vector_pair(alpha_fills[0].second); -} diff --git a/tests/cpp_unit_tests/test_sparse_ordening.cpp b/tests/cpp_unit_tests/test_sparse_ordening.cpp new file mode 100644 index 000000000..0cf1c9edb --- /dev/null +++ b/tests/cpp_unit_tests/test_sparse_ordening.cpp @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include + +#include +#include +#include + +namespace { +using namespace power_grid_model; + +auto to_string(std::vector> const& d) { + std::stringstream sstr; + sstr << "{"; + for (const auto& it : d) { + sstr << it.first << ": " << it.second << ", "; + } + sstr << "}"; + return sstr.str(); +} + +auto to_string(std::vector const& input) { + std::stringstream sstr; + for (auto const& i : input) { + sstr << i << ", "; + } + return sstr.str(); +} +} // namespace + +TEST_CASE("Test sparse ordening") { + SUBCASE("minimum_degree_ordening") { + std::map> graph{{0, {3, 5}}, {1, {4, 5, 8}}, {2, {4, 5, 6}}, {3, {6, 7}}, + {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; + + auto const start = std::chrono::high_resolution_clock::now(); + std::vector, std::vector>>> const alpha_fills = + minimum_degree_ordering(graph); + auto const stop = std::chrono::high_resolution_clock::now(); + + auto const duration = duration_cast(stop - start); + std::cout << "Time taken by function: " << duration.count() << " microseconds" + << "\n"; + + std::cout << to_string(alpha_fills[0].first) << "\n"; + std::cout << to_string(alpha_fills[0].second) << "\n"; + } +} From e97d59444161d6c2f458da952d17a1d0b4fed9f1 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 22 Nov 2023 09:17:20 +0100 Subject: [PATCH 04/47] use doctest instead of raw print Signed-off-by: Martijn Govers --- tests/cpp_unit_tests/test_sparse_ordening.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cpp_unit_tests/test_sparse_ordening.cpp b/tests/cpp_unit_tests/test_sparse_ordening.cpp index 0cf1c9edb..38ec6faad 100644 --- a/tests/cpp_unit_tests/test_sparse_ordening.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordening.cpp @@ -46,7 +46,7 @@ TEST_CASE("Test sparse ordening") { std::cout << "Time taken by function: " << duration.count() << " microseconds" << "\n"; - std::cout << to_string(alpha_fills[0].first) << "\n"; - std::cout << to_string(alpha_fills[0].second) << "\n"; + CHECK(alpha_fills[0].first == std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + CHECK(alpha_fills[0].second == std::vector>{{3, 5}, {4, 5}, {8, 5}, {6, 5}, {7, 5}}); } } From fbfe02d1292ed3d7dd8f3a2b7d0f4a164721a3c5 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 22 Nov 2023 09:28:52 +0100 Subject: [PATCH 05/47] remove deprecated Signed-off-by: Martijn Govers --- .../include/power_grid_model/topology.hpp | 2 +- tests/cpp_unit_tests/test_sparse_ordening.cpp | 22 ++----------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index eeba049c0..eff687bbc 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -701,7 +701,7 @@ class Topology { {comp_topo_.power_sensor_object_idx, comp_coup_.node}, comp_coup_.power_sensor, [this](Idx i) { return comp_topo_.power_sensor_terminal_type[i] == MeasuredTerminalType::node; }); } -}; // namespace power_grid_model +}; } // namespace power_grid_model diff --git a/tests/cpp_unit_tests/test_sparse_ordening.cpp b/tests/cpp_unit_tests/test_sparse_ordening.cpp index 38ec6faad..4862ab14f 100644 --- a/tests/cpp_unit_tests/test_sparse_ordening.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordening.cpp @@ -11,25 +11,7 @@ #include namespace { -using namespace power_grid_model; - -auto to_string(std::vector> const& d) { - std::stringstream sstr; - sstr << "{"; - for (const auto& it : d) { - sstr << it.first << ": " << it.second << ", "; - } - sstr << "}"; - return sstr.str(); -} - -auto to_string(std::vector const& input) { - std::stringstream sstr; - for (auto const& i : input) { - sstr << i << ", "; - } - return sstr.str(); -} +using power_grid_model::ID; } // namespace TEST_CASE("Test sparse ordening") { @@ -39,7 +21,7 @@ TEST_CASE("Test sparse ordening") { auto const start = std::chrono::high_resolution_clock::now(); std::vector, std::vector>>> const alpha_fills = - minimum_degree_ordering(graph); + power_grid_model::minimum_degree_ordering(graph); auto const stop = std::chrono::high_resolution_clock::now(); auto const duration = duration_cast(stop - start); From 3d5b74b4600cd0129d116865670d54ac82b7cda7 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 22 Nov 2023 09:52:28 +0100 Subject: [PATCH 06/47] remove redundant vector Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 5 +- .../include/power_grid_model/topology.hpp | 93 +------------------ tests/cpp_unit_tests/test_sparse_ordening.cpp | 6 +- 3 files changed, 7 insertions(+), 97 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index a476a0a57..1cace56ae 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -196,8 +196,7 @@ std::vector remove_vertices_update_degrees(ID& u, std::map, std::vector>>> -minimum_degree_ordering(std::map>& d) { +std::pair, std::vector>> minimum_degree_ordering(std::map>& d) { std::vector>>> data = detail::comp_size_degrees_graph(d); ID& n = data[0].first; std::vector>& dgd = data[0].second; @@ -227,7 +226,7 @@ minimum_degree_ordering(std::map>& d) { } } } - return {{alpha, fills}}; + return {alpha, fills}; } } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index eff687bbc..95c4fdbe6 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -310,97 +310,8 @@ class Topology { } // assign temporary bus number as increasing from 0, 1, 2, ..., n_cycle_node - 1 - for (GraphIdx i = 0; i != n_cycle_node; ++i) { - node_status_[cyclic_node[i]] = static_cast(i); - } - // build graph lambda - auto const build_graph = [&](ReorderGraph& g) { - // add edges - for (GraphIdx i = 0; i != n_cycle_node; ++i) { - // loop all edges of vertex i - auto const global_i = static_cast(cyclic_node[i]); - BGL_FORALL_ADJ(global_i, global_j, global_graph_, GlobalGraph) { - // skip if j is not part of cyclic sub graph - if (node_status_[global_j] == -1) { - continue; - } - auto const j = static_cast(node_status_[global_j]); - if (!boost::edge(i, j, g).second) { - boost::add_edge(i, j, g); - } - } - } - }; - ReorderGraph meshed_graph{n_cycle_node}; - build_graph(meshed_graph); - // start minimum degree ordering - std::vector> perm(n_cycle_node); - std::vector> inverse_perm(n_cycle_node); - std::vector> degree(n_cycle_node); - std::vector> supernode_sizes(n_cycle_node, 1); - boost::vec_adj_list_vertex_id_map> const id{}; - int const delta = 0; - boost::minimum_degree_ordering(meshed_graph, boost::make_iterator_property_map(degree.begin(), id), - boost::make_iterator_property_map(inverse_perm.begin(), id), - boost::make_iterator_property_map(perm.begin(), id), - boost::make_iterator_property_map(supernode_sizes.begin(), id), delta, id); - // re-order cyclic node - std::vector const cyclic_node_copy{cyclic_node}; - for (GraphIdx i = 0; i != n_cycle_node; ++i) { - cyclic_node[i] = cyclic_node_copy[perm[i]]; - } - // copy back to dfs node - std::copy(cyclic_node.cbegin(), cyclic_node.cend(), std::back_inserter(dfs_node)); - - // analyze and record fill-ins - // re-assign temporary bus number as increasing from 0, 1, 2, ..., n_cycle_node - 1 - for (GraphIdx i = 0; i != n_cycle_node; ++i) { - node_status_[cyclic_node[i]] = static_cast(i); - } - // re-build graph with reordered cyclic node - meshed_graph.clear(); - meshed_graph = ReorderGraph{n_cycle_node}; - build_graph(meshed_graph); - // begin to remove vertices from graph, create fill-ins - BGL_FORALL_VERTICES(i, meshed_graph, ReorderGraph) { - // double loop to loop all pairs of adjacent vertices - BGL_FORALL_ADJ(i, j1, meshed_graph, ReorderGraph) { - // skip for already removed vertices - if (j1 < i) { - continue; - } - BGL_FORALL_ADJ(i, j2, meshed_graph, ReorderGraph) { - // no self edges - assert(i != j1); - assert(i != j2); - // skip for already removed vertices - if (j2 < i) { - continue; - } - // only keep pair with j1 < j2 - if (j1 >= j2) { - continue; - } - // if edge j1 -> j2 does not already exists - // it is a fill-in - if (!boost::edge(j1, j2, meshed_graph).second) { - // anti edge should also not exist - assert(!boost::edge(j2, j1, meshed_graph).second); - // add both edges to the graph - boost::add_edge(j1, j2, meshed_graph); - boost::add_edge(j2, j1, meshed_graph); - // add to fill-in - fill_in.push_back({static_cast(j1), static_cast(j2)}); - } - } - } - } - // offset fill-in indices by n_node - n_cycle_node - auto const offset = static_cast(dfs_node.size() - n_cycle_node); - std::for_each(fill_in.begin(), fill_in.end(), [offset](BranchIdx& b) { - b[0] += offset; - b[1] += offset; - }); + // TODO(mgovers): fill node_status_ + // TODO(mgovers): construct fill_in return fill_in; } diff --git a/tests/cpp_unit_tests/test_sparse_ordening.cpp b/tests/cpp_unit_tests/test_sparse_ordening.cpp index 4862ab14f..50526e667 100644 --- a/tests/cpp_unit_tests/test_sparse_ordening.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordening.cpp @@ -20,7 +20,7 @@ TEST_CASE("Test sparse ordening") { {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; auto const start = std::chrono::high_resolution_clock::now(); - std::vector, std::vector>>> const alpha_fills = + std::pair, std::vector>> const alpha_fills = power_grid_model::minimum_degree_ordering(graph); auto const stop = std::chrono::high_resolution_clock::now(); @@ -28,7 +28,7 @@ TEST_CASE("Test sparse ordening") { std::cout << "Time taken by function: " << duration.count() << " microseconds" << "\n"; - CHECK(alpha_fills[0].first == std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); - CHECK(alpha_fills[0].second == std::vector>{{3, 5}, {4, 5}, {8, 5}, {6, 5}, {7, 5}}); + CHECK(alpha_fills.first == std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + CHECK(alpha_fills.second == std::vector>{{3, 5}, {4, 5}, {8, 5}, {6, 5}, {7, 5}}); } } From 6bb3c49a4289021a5d5dad7a6cc3dee784dde769 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 22 Nov 2023 10:53:19 +0100 Subject: [PATCH 07/47] call minimum degree ordening from topology Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 138 ++++++++++-------- .../include/power_grid_model/topology.hpp | 21 ++- tests/cpp_unit_tests/test_sparse_ordening.cpp | 12 +- 3 files changed, 99 insertions(+), 72 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index 1cace56ae..1d11f404e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 #pragma once -#ifndef POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ITERATION_HPP -#define POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ITERATION_HPP +#ifndef POWER_GRIdx_MODEL_MATH_SOLVER_SPARSE_ORDENING_HPP +#define POWER_GRIdx_MODEL_MATH_SOLVER_SPARSE_ORDENING_HPP #include "power_grid_model.hpp" @@ -17,8 +17,8 @@ namespace power_grid_model { namespace detail { -void remove_element_vector_pair(ID& u, std::vector>& dgd) { - ID i = 0; +inline void remove_element_vector_pair(Idx& u, std::vector>& dgd) { + Idx i = 0; while (i < dgd.size()) { if (dgd[i].first == u) { dgd.erase(dgd.begin() + i); @@ -29,8 +29,8 @@ void remove_element_vector_pair(ID& u, std::vector>& dgd) { } } -void set_element_vector_pair(ID& u, ID v, std::vector>& dgd) { - ID i = 0; +inline void set_element_vector_pair(Idx& u, Idx v, std::vector>& dgd) { + Idx i = 0; while (i < dgd.size()) { if (dgd[i].first == u) { dgd[i].second = v; @@ -41,15 +41,15 @@ void set_element_vector_pair(ID& u, ID v, std::vector>& dgd) { } } -std::vector adj(ID& u, std::map>& d) { - std::vector l; +inline std::vector adj(Idx& u, std::map>& d) { + std::vector l; for (const auto& it : d) { if (it.first == u) l.insert(l.end(), it.second.begin(), it.second.end()); if (find(it.second.begin(), it.second.end(), u) != it.second.end()) { - std::vector v{it.first}; + std::vector v{it.first}; l.insert(l.end(), v.begin(), v.end()); } } @@ -57,25 +57,26 @@ std::vector adj(ID& u, std::map>& d) { return l; } -bool compair_ids(std::pair& a, std::pair& b) { return a.first < b.first; } +inline bool compair_ids(std::pair& a, std::pair& b) { return a.first < b.first; } -std::vector>>> comp_size_degrees_graph(std::map>& d) { - std::vector> dd; - std::vector v; - ID n = 0; +inline std::vector>>> +comp_size_degrees_graph(std::map>& d) { + std::vector> dd; + std::vector v; + Idx n = 0; for (const auto& it : d) { - ID k = it.first; + Idx k = it.first; if (find(v.begin(), v.end(), k) == v.end()) { - std::vector vk{k}; + std::vector vk{k}; v.insert(v.end(), vk.begin(), vk.end()); n += 1; dd.push_back({k, adj(k, d).size()}); } - for (const ID& el : it.second) { - ID e = el; + for (const Idx& el : it.second) { + Idx e = el; if (find(v.begin(), v.end(), e) == v.end()) { - std::vector ve{e}; + std::vector ve{e}; v.insert(v.end(), ve.begin(), ve.end()); n += 1; dd.push_back({e, adj(e, d).size()}); @@ -88,9 +89,9 @@ std::vector>>> comp_size_degrees_gra return {{n, dd}}; } -std::vector, std::vector>> check_indistguishable(ID& u, - std::map>& d) { - std::vector l, rl, lu, lv, vu{u}, vv; +inline std::vector, std::vector>> +check_indistguishable(Idx& u, std::map>& d) { + std::vector l, rl, lu, lv, vu{u}, vv; l = adj(u, d); lu = l; lu.insert(lu.end(), vu.begin(), vu.end()); @@ -109,14 +110,14 @@ std::vector, std::vector>> check_indistguishable(I return {{l, rl}}; } -std::map> make_clique(std::vector& l) { - std::map> d; - ID b = l.size() - 1; +inline std::map> make_clique(std::vector& l) { + std::map> d; + Idx b = l.size() - 1; for (int i = 0; i < b; i++) { - ID index = i + 1; + Idx index = i + 1; auto start = l.begin() + index; - std::vector sl(l.size() - index); + std::vector sl(l.size() - index); copy(start, l.end(), sl.begin()); d[l[i]] = sl; } @@ -124,21 +125,28 @@ std::map> make_clique(std::vector& l) { return d; } -bool in_graph(std::vector& e, std::map>& d) { - bool t1 = (d.find(e[0]) != d.end()) and (find(d[e[0]].begin(), d[e[0]].end(), e[1]) != d[e[0]].end()); - bool t2 = (d.find(e[1]) != d.end()) and (find(d[e[1]].begin(), d[e[1]].end(), e[0]) != d[e[1]].end()); - - return (t1 || t2); +inline bool in_graph(std::pair const& e, std::map> const& d) { + if (auto edges_it = d.find(e.first); edges_it != d.cend()) { + if (std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) { + return true; + } + } + if (auto edges_it = d.find(e.second); edges_it != d.cend()) { + if (std::ranges::find(edges_it->second, e.first) != edges_it->second.cend()) { + return true; + } + } + return false; } -std::vector remove_vertices_update_degrees(ID& u, std::map>& d, - std::vector>& dgd, - std::vector>& fills) { - std::vector, std::vector>> nbsrl = check_indistguishable(u, d); - std::vector& nbs = nbsrl[0].first; - std::vector& rl = nbsrl[0].second; - std::vector alpha = rl, vu{u}; - std::map> dd; +inline std::vector remove_vertices_update_degrees(Idx& u, std::map>& d, + std::vector>& dgd, + std::vector>& fills) { + std::vector, std::vector>> nbsrl = check_indistguishable(u, d); + std::vector& nbs = nbsrl[0].first; + std::vector& rl = nbsrl[0].second; + std::vector alpha = rl, vu{u}; + std::map> dd; rl.insert(rl.begin(), vu.begin(), vu.end()); @@ -147,17 +155,17 @@ std::vector remove_vertices_update_degrees(ID& u, std::map el; + std::vector el; for (auto& it : d) { it.second.erase(remove(it.second.begin(), it.second.end(), uu), it.second.end()); if (it.second.empty()) { - ID k = it.first; - std::vector vk{k}; + Idx k = it.first; + std::vector vk{k}; el.insert(el.end(), vk.begin(), vk.end()); } } - std::vector vuu{uu}; + std::vector vuu{uu}; el.insert(el.end(), vuu.begin(), vuu.end()); for (auto& it : el) @@ -167,20 +175,20 @@ std::vector remove_vertices_update_degrees(ID& u, std::map t{k, e}; - if (not in_graph(t, d)) { + Idx k = it.first; + for (const Idx& e : it.second) { + std::pair t{k, e}; + if (!in_graph(t, d)) { if (d.find(k) != d.end()) { - std::vector ve{e}; + std::vector ve{e}; d[k].insert(d[k].end(), ve.begin(), ve.end()); fills.push_back({k, e}); } else if (d.find(e) != d.end()) { - std::vector vk{k}; + std::vector vk{k}; d[e].insert(d[e].end(), vk.begin(), vk.end()); fills.push_back({e, k}); } else { - std::vector ve{e}; + std::vector ve{e}; d[k].insert(d[k].end(), ve.begin(), ve.end()); fills.push_back({k, e}); } @@ -196,30 +204,32 @@ std::vector remove_vertices_update_degrees(ID& u, std::map, std::vector>> minimum_degree_ordering(std::map>& d) { - std::vector>>> data = detail::comp_size_degrees_graph(d); - ID& n = data[0].first; - std::vector>& dgd = data[0].second; - std::vector alpha; - std::vector> fills; +inline std::pair, std::vector>> +minimum_degree_ordering(std::map>& d) { + std::vector>>> data = detail::comp_size_degrees_graph(d); + Idx& n = data[0].first; + std::vector>& dgd = data[0].second; + std::vector alpha; + std::vector> fills; for (int k = 0; k < n; k++) { - ID u = get<0>(*min_element(begin(dgd), end(dgd), [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); - std::vector vu{u}; + Idx u = + get<0>(*min_element(begin(dgd), end(dgd), [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); + std::vector vu{u}; alpha.insert(alpha.end(), vu.begin(), vu.end()); if ((d.size() == 1) and d.begin()->second.size() == 1) { - ID a = d.begin()->first; - ID b = d.begin()->second[0]; + Idx a = d.begin()->first; + Idx b = d.begin()->second[0]; if (alpha.back() == a) { - std::vector vb{b}; + std::vector vb{b}; alpha.insert(alpha.end(), vb.begin(), vb.end()); } else { - std::vector va{a}; + std::vector va{a}; alpha.insert(alpha.end(), va.begin(), va.end()); } break; } else { - std::vector va = detail::remove_vertices_update_degrees(u, d, dgd, fills); + std::vector va = detail::remove_vertices_update_degrees(u, d, dgd, fills); alpha.insert(alpha.end(), va.begin(), va.end()); if (d.empty()) { break; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 95c4fdbe6..d85e52cde 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -11,6 +11,7 @@ #include "exception.hpp" #include "power_grid_model.hpp" #include "sparse_mapping.hpp" +#include "sparse_ordening.hpp" #include #include @@ -310,8 +311,24 @@ class Topology { } // assign temporary bus number as increasing from 0, 1, 2, ..., n_cycle_node - 1 - // TODO(mgovers): fill node_status_ - // TODO(mgovers): construct fill_in + std::map> unique_nearest_neighbours; + for (Idx node_idx : dfs_node) { + unique_nearest_neighbours[node_idx] = {}; + } + for (auto const& edge : back_edges) { + auto const from{static_cast(edge.first)}; + auto const to{static_cast(edge.second)}; + if (!detail::in_graph(std::pair{from, to}, unique_nearest_neighbours)) { + unique_nearest_neighbours[from].push_back(to); + } + } + + auto alpha_fills = minimum_degree_ordering(unique_nearest_neighbours); + + // TODO(mgovers): set node_status_ + // TODO(mgovers): fill dfs_node = dfs_node[alpha_fills.first] + // TODO(mgovers): construct fill_in = alpha_fills.second + return fill_in; } diff --git a/tests/cpp_unit_tests/test_sparse_ordening.cpp b/tests/cpp_unit_tests/test_sparse_ordening.cpp index 50526e667..5b668ce15 100644 --- a/tests/cpp_unit_tests/test_sparse_ordening.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordening.cpp @@ -11,16 +11,16 @@ #include namespace { -using power_grid_model::ID; +using power_grid_model::Idx; } // namespace TEST_CASE("Test sparse ordening") { SUBCASE("minimum_degree_ordening") { - std::map> graph{{0, {3, 5}}, {1, {4, 5, 8}}, {2, {4, 5, 6}}, {3, {6, 7}}, - {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; + std::map> graph{{0, {3, 5}}, {1, {4, 5, 8}}, {2, {4, 5, 6}}, {3, {6, 7}}, + {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; auto const start = std::chrono::high_resolution_clock::now(); - std::pair, std::vector>> const alpha_fills = + std::pair, std::vector>> const alpha_fills = power_grid_model::minimum_degree_ordering(graph); auto const stop = std::chrono::high_resolution_clock::now(); @@ -28,7 +28,7 @@ TEST_CASE("Test sparse ordening") { std::cout << "Time taken by function: " << duration.count() << " microseconds" << "\n"; - CHECK(alpha_fills.first == std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); - CHECK(alpha_fills.second == std::vector>{{3, 5}, {4, 5}, {8, 5}, {6, 5}, {7, 5}}); + CHECK(alpha_fills.first == std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + CHECK(alpha_fills.second == std::vector>{{3, 5}, {4, 5}, {8, 5}, {6, 5}, {7, 5}}); } } From 1a4b122732449e2cf94041fe4ef92908870e18de Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Mon, 27 Nov 2023 14:02:08 +0100 Subject: [PATCH 08/47] switch to new min degree algorithm Signed-off-by: Martijn Govers --- .../include/power_grid_model/topology.hpp | 113 ++++++++++++----- tests/cpp_unit_tests/test_topology.cpp | 116 +++++++++++++----- 2 files changed, 162 insertions(+), 67 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index d85e52cde..a193f1e4e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -19,6 +19,8 @@ #include #include +#include + // build topology of the grid // divide grid into several math models // start search from a source @@ -279,55 +281,100 @@ class Topology { // return list of fill-ins when factorize the matrix std::vector reorder_node(std::vector& dfs_node, std::vector> const& back_edges) { - std::vector fill_in; - // make a copy and clear current vector - std::vector const dfs_node_copy(dfs_node); - dfs_node.clear(); - - // loop all back edges assign all nodes before the back edges as inside cycle - for (auto const& back_edge : back_edges) { - GraphIdx node_in_cycle = back_edge.first; - // loop back from source in the predecessor tree - // stop if it is already marked as in cycle - while (node_status_[node_in_cycle] != -2) { - // assign cycle status and go to predecessor - node_status_[node_in_cycle] = -2; - node_in_cycle = predecessors_[node_in_cycle]; - } - } - - // copy all the far-end non-cyclic node, in reverse order - std::copy_if(dfs_node_copy.crbegin(), dfs_node_copy.crend(), std::back_inserter(dfs_node), - [this](Idx x) { return node_status_[x] == -1; }); - // copy all cyclic node - std::vector cyclic_node; - std::copy_if(dfs_node_copy.cbegin(), dfs_node_copy.cend(), std::back_inserter(cyclic_node), - [this](Idx x) { return node_status_[x] == -2; }); - GraphIdx const n_cycle_node = cyclic_node.size(); - // reorder does not make sense if number of cyclic nodes in a sub graph is smaller than 4 - if (n_cycle_node < 4) { - std::copy(cyclic_node.crbegin(), cyclic_node.crend(), std::back_inserter(dfs_node)); - return fill_in; - } - + // std::vector fill_in; + // // make a copy and clear current vector + // std::vector const dfs_node_copy(dfs_node); + // dfs_node.clear(); + + // // loop all back edges assign all nodes before the back edges as inside cycle + // for (auto const& back_edge : back_edges) { + // GraphIdx node_in_cycle = back_edge.first; + + // // loop back from source in the predecessor tree + // // stop if it is already marked as in cycle + // while (node_status_[node_in_cycle] != -2) { + // // assign cycle status and go to predecessor + // node_status_[node_in_cycle] = -2; + // node_in_cycle = predecessors_[node_in_cycle]; + // } + // } + + // // copy all the far-end non-cyclic node, in reverse order + // std::copy_if(dfs_node_copy.crbegin(), dfs_node_copy.crend(), std::back_inserter(dfs_node), + // [this](Idx x) { return node_status_[x] == -1; }); + // // copy all cyclic node + // std::vector cyclic_node; + // std::copy_if(dfs_node_copy.cbegin(), dfs_node_copy.cend(), std::back_inserter(cyclic_node), + // [this](Idx x) { return node_status_[x] == -2; }); + // GraphIdx const n_cycle_node = cyclic_node.size(); + // // reorder does not make sense if number of cyclic nodes in a sub graph is smaller than 4 + // if (n_cycle_node < 4) { + // std::copy(cyclic_node.crbegin(), cyclic_node.crend(), std::back_inserter(dfs_node)); + // return fill_in; + // } + // for (GraphIdx i = 0; i != n_cycle_node; ++i) { + // node_status_[cyclic_node[i]] = static_cast(i); + // } + + // // build graph lambda + // auto const build_graph = [&](ReorderGraph& g) { + // // add edges + // for (GraphIdx i = 0; i != n_cycle_node; ++i) { + // // loop all edges of vertex i + // auto const global_i = static_cast(cyclic_node[i]); + // BGL_FORALL_ADJ(global_i, global_j, global_graph_, GlobalGraph) { + // // skip if j is not part of cyclic sub graph + // if (node_status_[global_j] == -1) { + // continue; + // } + // auto const j = static_cast(node_status_[global_j]); + // if (!boost::edge(i, j, g).second) { + // boost::add_edge(i, j, g); + // } + // } + // } + // }; // assign temporary bus number as increasing from 0, 1, 2, ..., n_cycle_node - 1 std::map> unique_nearest_neighbours; for (Idx node_idx : dfs_node) { - unique_nearest_neighbours[node_idx] = {}; + auto predecessor = static_cast(predecessors_[node_idx]); + std::cout << node_idx << ": predecessor = " << predecessor << "\n"; + if (predecessor != node_idx) { + unique_nearest_neighbours[node_idx] = {predecessor}; + } } + std::cout << std::endl; for (auto const& edge : back_edges) { auto const from{static_cast(edge.first)}; auto const to{static_cast(edge.second)}; + std::cout << "back edge: " << from << ", " << to; if (!detail::in_graph(std::pair{from, to}, unique_nearest_neighbours)) { + std::cout << " (new)"; unique_nearest_neighbours[from].push_back(to); } + std::cout << "\n"; + } + std::cout << std::endl; + + for (auto const& [node, neighbours] : unique_nearest_neighbours) { + std::cout << "node: " << node << ", adjacent = ["; + for (auto neighbour : neighbours) { + std::cout << neighbour << ", "; + } + std::cout << "]\n"; } + std::cout << std::endl; - auto alpha_fills = minimum_degree_ordering(unique_nearest_neighbours); + auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); // TODO(mgovers): set node_status_ // TODO(mgovers): fill dfs_node = dfs_node[alpha_fills.first] // TODO(mgovers): construct fill_in = alpha_fills.second + std::vector fill_in; + for (auto [from, to] : fills) { + fill_in.push_back({reordered[from], reordered[to]}); + } + dfs_node = std::move(reordered); return fill_in; } diff --git a/tests/cpp_unit_tests/test_topology.cpp b/tests/cpp_unit_tests/test_topology.cpp index 2085c2222..d466f4349 100644 --- a/tests/cpp_unit_tests/test_topology.cpp +++ b/tests/cpp_unit_tests/test_topology.cpp @@ -324,41 +324,89 @@ TEST_CASE("Test topology") { } TEST_CASE("Test cycle reorder") { - // component topology - ComponentTopology comp_topo{}; - comp_topo.n_node = 7; - comp_topo.branch_node_idx = { - {0, 1}, // 0 - {1, 2}, // 1 - {2, 3}, // 2 - {3, 4}, // 3 - {4, 5}, // 4 - {0, 5}, // 5 - {1, 4}, // 6 - {6, 0}, // 7 - {6, 2}, // 8 - {5, 1}, // 9 - {3, 1}, // 10 - {6, 1}, // 11 - {2, 1}, // 12 - }; - comp_topo.source_node_idx = {0}; - // component connection - ComponentConnections comp_conn{}; - comp_conn.branch_connected = std::vector(13, {1, 1}); - comp_conn.branch_phase_shift = std::vector(13, 0.0); - comp_conn.source_connected = {1}; - // result - TopologicalComponentToMathCoupling comp_coup_ref{}; - comp_coup_ref.node = {{0, 3}, {0, 5}, {0, 4}, {0, 2}, {0, 6}, {0, 1}, {0, 0}}; - std::vector const fill_in_ref{{3, 4}, {3, 6}, {4, 6}}; + SUBCASE("9 nodes") { + // { + // 0: [3, 5], + // 1: [4, 5, 8], + // 2: [4, 5, 6], + // 3: [6, 7], + // 4: [6, 8], + // 6: [7, 8, 9], + // 7: [8, 9], + // 8: [9] + // } - Topology topo{comp_topo, comp_conn}; - auto pair = topo.build_topology(); - auto const& topo_comp_coup = *pair.second; - auto const& math_topo = *pair.first[0]; - CHECK(topo_comp_coup.node == comp_coup_ref.node); - CHECK(math_topo.fill_in == fill_in_ref); + // component topology + ComponentTopology comp_topo{}; + comp_topo.n_node = 10; + comp_topo.branch_node_idx = { + {0, 3}, {0, 5}, {1, 4}, {1, 5}, {1, 8}, {2, 4}, {2, 5}, {2, 6}, {3, 6}, + {3, 7}, {4, 6}, {4, 8}, {6, 7}, {6, 8}, {6, 9}, {7, 8}, {7, 9}, {8, 9}, + }; + comp_topo.source_node_idx = {0}; + // component connection + ComponentConnections comp_conn{}; + comp_conn.branch_connected = std::vector(18, {1, 1}); + comp_conn.branch_phase_shift = std::vector(18, 0.0); + comp_conn.source_connected = {1}; + // result + TopologicalComponentToMathCoupling comp_coup_ref{}; + comp_coup_ref.node = {{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}}; + std::vector const fill_in_ref{{5, 3}, {4, 5}, {5, 8}, {6, 5}, {5, 7}}; + + Topology topo{comp_topo, comp_conn}; + auto pair = topo.build_topology(); + auto const& topo_comp_coup = *pair.second; + auto const& math_topo = *pair.first[0]; + CHECK(topo_comp_coup.node == comp_coup_ref.node); + CHECK(math_topo.fill_in == fill_in_ref); + } + + SUBCASE("7 nodes") { + // { + // 0: [1, 5, 6], + // 1: [2, 4, 5, 3, 6], + // 2: [3, 6] + // 3: [4], + // 4: [5], + // } + + // component topology + ComponentTopology comp_topo{}; + comp_topo.n_node = 7; + comp_topo.branch_node_idx = { + {0, 1}, // 0 + {1, 2}, // 1 + {2, 3}, // 2 + {3, 4}, // 3 + {4, 5}, // 4 + {0, 5}, // 5 + {1, 4}, // 6 + {6, 0}, // 7 + {6, 2}, // 8 + {5, 1}, // 9 + {3, 1}, // 10 + {6, 1}, // 11 + {2, 1}, // 12 + }; + comp_topo.source_node_idx = {0}; + // component connection + ComponentConnections comp_conn{}; + comp_conn.branch_connected = std::vector(13, {1, 1}); + comp_conn.branch_phase_shift = std::vector(13, 0.0); + comp_conn.source_connected = {1}; + // result + TopologicalComponentToMathCoupling comp_coup_ref{}; + comp_coup_ref.node = {{0, 0}, {0, 3}, {0, 1}, {0, 2}, {0, 4}, {0, 5}, {0, 6}}; + std::vector const fill_in_ref{{5, 6}, {1, 6}, {6, 4}}; + + Topology topo{comp_topo, comp_conn}; + auto pair = topo.build_topology(); + auto const& topo_comp_coup = *pair.second; + auto const& math_topo = *pair.first[0]; + CHECK(topo_comp_coup.node == comp_coup_ref.node); + CHECK(math_topo.fill_in == fill_in_ref); + } } } // namespace power_grid_model \ No newline at end of file From ef9ae2942910abbfec69c667b71c10ef0a1735c2 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Fri, 1 Dec 2023 15:40:36 +0100 Subject: [PATCH 09/47] attempt to fix permutations Signed-off-by: Martijn Govers --- .../power_grid_model/math_solver/y_bus.hpp | 9 ++ .../include/power_grid_model/topology.hpp | 94 +++++++++++-------- tests/cpp_unit_tests/test_topology.cpp | 4 +- .../cpp_validation_tests/test_validation.cpp | 15 +-- 4 files changed, 77 insertions(+), 45 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp index 9ca9b702b..7f7191db0 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp @@ -11,6 +11,8 @@ #include "../sparse_mapping.hpp" #include "../three_phase_tensor.hpp" +#include // TODO(mgovers) remove + namespace power_grid_model { // hide implementation in inside namespace @@ -152,6 +154,13 @@ struct YBusStructure { y_bus_element.push_back(m.element); } } + for (size_t idx = 0; idx < vec_map_element.size(); ++idx) { + auto const& m = vec_map_element[idx]; + std::cout << "idx = " << idx << ", pos = [" << m.pos.first << ", " << m.pos.second + << "], element = {element_type = " << static_cast(m.element.element_type) + << ", idx = " << m.element.idx << "}\n"; + } + std::cout << std::endl; // iterate the whole element include fill-in for (auto it_element = vec_map_element.cbegin(); it_element != vec_map_element.cend(); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index a193f1e4e..cd68aec48 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -281,37 +281,37 @@ class Topology { // return list of fill-ins when factorize the matrix std::vector reorder_node(std::vector& dfs_node, std::vector> const& back_edges) { - // std::vector fill_in; - // // make a copy and clear current vector - // std::vector const dfs_node_copy(dfs_node); - // dfs_node.clear(); - - // // loop all back edges assign all nodes before the back edges as inside cycle - // for (auto const& back_edge : back_edges) { - // GraphIdx node_in_cycle = back_edge.first; - - // // loop back from source in the predecessor tree - // // stop if it is already marked as in cycle - // while (node_status_[node_in_cycle] != -2) { - // // assign cycle status and go to predecessor - // node_status_[node_in_cycle] = -2; - // node_in_cycle = predecessors_[node_in_cycle]; - // } - // } + std::vector fill_in; + // make a copy and clear current vector + std::vector const dfs_node_copy(dfs_node); + dfs_node.clear(); + + // loop all back edges assign all nodes before the back edges as inside cycle + for (auto const& back_edge : back_edges) { + GraphIdx node_in_cycle = back_edge.first; + + // loop back from source in the predecessor tree + // stop if it is already marked as in cycle + while (node_status_[node_in_cycle] != -2) { + // assign cycle status and go to predecessor + node_status_[node_in_cycle] = -2; + node_in_cycle = predecessors_[node_in_cycle]; + } + } - // // copy all the far-end non-cyclic node, in reverse order - // std::copy_if(dfs_node_copy.crbegin(), dfs_node_copy.crend(), std::back_inserter(dfs_node), - // [this](Idx x) { return node_status_[x] == -1; }); - // // copy all cyclic node - // std::vector cyclic_node; - // std::copy_if(dfs_node_copy.cbegin(), dfs_node_copy.cend(), std::back_inserter(cyclic_node), - // [this](Idx x) { return node_status_[x] == -2; }); - // GraphIdx const n_cycle_node = cyclic_node.size(); - // // reorder does not make sense if number of cyclic nodes in a sub graph is smaller than 4 - // if (n_cycle_node < 4) { - // std::copy(cyclic_node.crbegin(), cyclic_node.crend(), std::back_inserter(dfs_node)); - // return fill_in; - // } + // copy all the far-end non-cyclic node, in reverse order + std::copy_if(dfs_node_copy.crbegin(), dfs_node_copy.crend(), std::back_inserter(dfs_node), + [this](Idx x) { return node_status_[x] == -1; }); + // copy all cyclic node + std::vector cyclic_node; + std::copy_if(dfs_node_copy.cbegin(), dfs_node_copy.cend(), std::back_inserter(cyclic_node), + [this](Idx x) { return node_status_[x] == -2; }); + GraphIdx const n_cycle_node = cyclic_node.size(); + // reorder does not make sense if number of cyclic nodes in a sub graph is smaller than 4 + if (n_cycle_node < 4) { + std::copy(cyclic_node.crbegin(), cyclic_node.crend(), std::back_inserter(dfs_node)); + return fill_in; + } // for (GraphIdx i = 0; i != n_cycle_node; ++i) { // node_status_[cyclic_node[i]] = static_cast(i); // } @@ -336,7 +336,7 @@ class Topology { // }; // assign temporary bus number as increasing from 0, 1, 2, ..., n_cycle_node - 1 std::map> unique_nearest_neighbours; - for (Idx node_idx : dfs_node) { + for (Idx node_idx : cyclic_node) { auto predecessor = static_cast(predecessors_[node_idx]); std::cout << node_idx << ": predecessor = " << predecessor << "\n"; if (predecessor != node_idx) { @@ -367,14 +367,33 @@ class Topology { auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); - // TODO(mgovers): set node_status_ - // TODO(mgovers): fill dfs_node = dfs_node[alpha_fills.first] - // TODO(mgovers): construct fill_in = alpha_fills.second - std::vector fill_in; + std::ranges::transform(reordered, std::back_inserter(dfs_node), + [&cyclic_node](Idx idx) { return cyclic_node[idx]; }); + + // TODO(mgovers): make this more efficient + auto const permuted_node_idx = [&dfs_node](Idx node_idx) { + return static_cast(std::distance(dfs_node.begin(), std::ranges::find(dfs_node, node_idx))); + }; + + for (auto [from, to] : fills) { + auto from_reordered = permuted_node_idx(reordered[from]); + auto to_reordered = permuted_node_idx(reordered[to]); + fill_in.push_back({from_reordered, to_reordered}); + } + + std::cout << "reordered: ["; + for (auto n : reordered) { + std::cout << n << ", "; + } + std::cout << "]\nfill_in (before reordening) : ["; for (auto [from, to] : fills) { - fill_in.push_back({reordered[from], reordered[to]}); + std::cout << "(" << from << ", " << to << "), "; + } + std::cout << "]\nfill_in (reordered) : ["; + for (auto [from, to] : fill_in) { + std::cout << "(" << from << ", " << to << "), "; } - dfs_node = std::move(reordered); + std::cout << "\n" << std::endl; return fill_in; } @@ -395,6 +414,7 @@ class Topology { Idx2D const i_math = comp_coup_.node[i]; Idx2D const j_math = comp_coup_.node[j]; Idx const math_group = [&]() { + // TODO(mgovers): rewrite Idx group = -1; if (i_status != 0 && i_math.group != -1) { group = i_math.group; diff --git a/tests/cpp_unit_tests/test_topology.cpp b/tests/cpp_unit_tests/test_topology.cpp index d466f4349..bd5f2e4ce 100644 --- a/tests/cpp_unit_tests/test_topology.cpp +++ b/tests/cpp_unit_tests/test_topology.cpp @@ -352,7 +352,7 @@ TEST_CASE("Test cycle reorder") { // result TopologicalComponentToMathCoupling comp_coup_ref{}; comp_coup_ref.node = {{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}}; - std::vector const fill_in_ref{{5, 3}, {4, 5}, {5, 8}, {6, 5}, {5, 7}}; + std::vector const fill_in_ref{{3, 5}, {4, 5}, {5, 8}, {5, 6}, {5, 7}}; Topology topo{comp_topo, comp_conn}; auto pair = topo.build_topology(); @@ -398,7 +398,7 @@ TEST_CASE("Test cycle reorder") { // result TopologicalComponentToMathCoupling comp_coup_ref{}; comp_coup_ref.node = {{0, 0}, {0, 3}, {0, 1}, {0, 2}, {0, 4}, {0, 5}, {0, 6}}; - std::vector const fill_in_ref{{5, 6}, {1, 6}, {6, 4}}; + std::vector const fill_in_ref{{5, 6}, {3, 6}, {4, 6}}; Topology topo{comp_topo, comp_conn}; auto pair = topo.build_topology(); diff --git a/tests/cpp_validation_tests/test_validation.cpp b/tests/cpp_validation_tests/test_validation.cpp index 6b61a33c7..ee8e5a8c6 100644 --- a/tests/cpp_validation_tests/test_validation.cpp +++ b/tests/cpp_validation_tests/test_validation.cpp @@ -592,12 +592,15 @@ TEST_CASE("Validation test single") { TEST_CASE("Validation test batch") { std::vector const& all_cases = get_all_batch_cases(); for (CaseParam const& param : all_cases) { - SUBCASE(param.case_name.c_str()) { - try { - validate_batch_case(param); - } catch (std::exception& e) { - auto const msg = std::string("Unexpected exception with message: ") + e.what(); - FAIL_CHECK(msg); + if (param.case_name == + "power_flow/pandapower/networks/asymmetric/distribution-case-asym-newton_raphson_batch") { + SUBCASE(param.case_name.c_str()) { + try { + validate_batch_case(param); + } catch (std::exception& e) { + auto const msg = std::string("Unexpected exception with message: ") + e.what(); + FAIL_CHECK(msg); + } } } } From 0d8fe104d0de1cf746311ead0e241ccf3bff4630 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 13 Dec 2023 08:26:22 +0100 Subject: [PATCH 10/47] more debug Signed-off-by: Martijn Govers --- .../include/power_grid_model/topology.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index cd68aec48..bb6a32381 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -381,10 +381,14 @@ class Topology { fill_in.push_back({from_reordered, to_reordered}); } - std::cout << "reordered: ["; + std::cout << "reordered (before permutation): ["; for (auto n : reordered) { std::cout << n << ", "; } + std::cout << "]\nreordered (after permutation): ["; + for (auto n : dfs_node) { + std::cout << n << ", "; + } std::cout << "]\nfill_in (before reordening) : ["; for (auto [from, to] : fills) { std::cout << "(" << from << ", " << to << "), "; @@ -393,7 +397,7 @@ class Topology { for (auto [from, to] : fill_in) { std::cout << "(" << from << ", " << to << "), "; } - std::cout << "\n" << std::endl; + std::cout << "]\n" << std::endl; return fill_in; } From d2c7514327d3341eb074f513dfb3257aebac81ad Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Fri, 15 Dec 2023 08:32:44 +0100 Subject: [PATCH 11/47] fix last remaining issue Signed-off-by: Martijn Govers --- .../include/power_grid_model/topology.hpp | 4 +- tests/cpp_unit_tests/test_topology.cpp | 70 +++++++++---------- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index bb6a32381..9a0073fea 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -366,9 +366,7 @@ class Topology { std::cout << std::endl; auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); - - std::ranges::transform(reordered, std::back_inserter(dfs_node), - [&cyclic_node](Idx idx) { return cyclic_node[idx]; }); + std::ranges::copy(reordered, std::back_inserter(dfs_node)); // TODO(mgovers): make this more efficient auto const permuted_node_idx = [&dfs_node](Idx node_idx) { diff --git a/tests/cpp_unit_tests/test_topology.cpp b/tests/cpp_unit_tests/test_topology.cpp index bd5f2e4ce..ab9959ce4 100644 --- a/tests/cpp_unit_tests/test_topology.cpp +++ b/tests/cpp_unit_tests/test_topology.cpp @@ -6,8 +6,6 @@ #include -#include - /* * [0] = Node / Bus * --0--> = Branch (from --id--> to) @@ -178,10 +176,10 @@ TEST_CASE("Test topology") { // result TopologicalComponentToMathCoupling comp_coup_ref{}; comp_coup_ref.node = { // 0 1 2 3 - {0, 4}, // Topological node 0 has become node 4 in mathematical model (group) 0 + {0, 1}, // Topological node 0 has become node 4 in mathematical model (group) 0 {0, 2}, {0, 0}, - {0, 1}, + {0, 3}, // 4 5 6 {1, 2}, // Topological node 4 has become node 2 in mathematical model (group) 1 {1, 3}, @@ -194,7 +192,7 @@ TEST_CASE("Test topology") { {-1, -1}, {-1, -1}, // b0, b1, b2 - {0, 3}, // Branch3 b0 is replaced by a virtual node 3, in mathematical model 0 + {0, 4}, // Branch3 b0 is replaced by a virtual node 3, in mathematical model 0 {-1, -1}, {1, 1}}; comp_coup_ref.source = { @@ -218,9 +216,9 @@ TEST_CASE("Test topology") { {-1, {-1, -1, -1}}, // b1 {1, {2, 3, 4}}, // b2 }; - comp_coup_ref.load_gen = {{0, 1}, {-1, -1}, {1, 0}, {0, 0}}; + comp_coup_ref.load_gen = {{0, 0}, {-1, -1}, {1, 0}, {0, 1}}; comp_coup_ref.shunt = {{0, 0}, {1, 0}, {-1, -1}}; - comp_coup_ref.voltage_sensor = {{0, 0}, {0, 3}, {0, 1}, {0, 2}, {1, 0}, {-1, -1}}; + comp_coup_ref.voltage_sensor = {{0, 0}, {0, 2}, {0, 1}, {0, 3}, {1, 0}, {-1, -1}}; comp_coup_ref.power_sensor = { {0, 0}, // 0 branch_from {1, 0}, // 1 source @@ -244,43 +242,41 @@ TEST_CASE("Test topology") { // Sub graph / math model 0 MathModelTopology math0; - math0.slack_bus_ = 4; - math0.sources_per_bus = {from_sparse, {0, 0, 0, 0, 0, 1}}; - math0.branch_bus_idx = {{4, 2}, {4, 1}, {1, -1}, {-1, 0}, {2, 3}, {1, 3}, {0, 3}}; - math0.phase_shift = {0.0, -1.0, 0.0, 0.0, 0.0}; - math0.load_gens_per_bus = {from_sparse, {0, 0, 0, 1, 1, 2}}; - math0.load_gen_type = {LoadGenType::const_y, LoadGenType::const_pq}; - math0.shunts_per_bus = {from_sparse, {0, 0, 1, 1, 1, 1}}; - math0.voltage_sensors_per_bus = {from_sparse, {0, 2, 3, 4, 4, 4}}; - math0.power_sensors_per_bus = {from_sparse, {0, 0, 0, 0, 0, 0}}; - math0.power_sensors_per_source = {from_sparse, {0, 0}}; - math0.power_sensors_per_shunt = {from_sparse, {0, 0}}; - math0.power_sensors_per_load_gen = {from_sparse, {0, 1, 1}}; - math0.power_sensors_per_branch_from = {from_sparse, {0, 0, 2, 2, 2, 3, 4, 5}}; + math0.slack_bus_ = 1; + math0.sources_per_bus = {from_dense, {1}, 5}; + math0.branch_bus_idx = {{1, 2}, {1, 3}, {3, -1}, {-1, 0}, {2, 4}, {3, 4}, {0, 4}}; + math0.phase_shift = {0.0, 0.0, 0.0, -1.0, 0.0}; + math0.load_gens_per_bus = {from_dense, {1, 2}, 5}; + math0.load_gen_type = {LoadGenType::const_pq, LoadGenType::const_y}; + math0.shunts_per_bus = {from_dense, {3}, 5}; + math0.voltage_sensors_per_bus = {from_dense, {0, 0, 2, 3}, 5}; + math0.power_sensors_per_bus = {from_dense, {}, 5}; + math0.power_sensors_per_source = {from_dense, {}, 1}; + math0.power_sensors_per_shunt = {from_dense, {}, 1}; + math0.power_sensors_per_load_gen = {from_dense, {1}, 2}; + math0.power_sensors_per_branch_from = {from_dense, {1, 1, 4, 5, 6}, 7}; // 7 branches, 3 branch-to power sensors // sensor 0 is connected to branch 0 // sensor 1 and 2 are connected to branch 1 - math0.power_sensors_per_branch_to = {from_sparse, {0, 1, 3, 3, 3, 3, 3, 3}}; - math0.fill_in = {{3, 4}}; + math0.power_sensors_per_branch_to = {from_dense, {0, 1, 1}, 7}; + math0.fill_in = {{4, 2}}; // Sub graph / math model 1 MathModelTopology math1; math1.slack_bus_ = 3; - math1.sources_per_bus = {from_sparse, {0, 0, 0, 0, 1}}; - math1.branch_bus_idx = { - {3, 2}, {2, 3}, {-1, 1}, {0, 1}, {3, 1}, - }; + math1.sources_per_bus = {from_dense, {3}, 4}; + math1.branch_bus_idx = {{3, 2}, {2, 3}, {-1, 1}, {0, 1}, {3, 1}}; math1.phase_shift = {0, 0, 0, 0}; - math1.load_gens_per_bus = {from_sparse, {0, 0, 0, 0, 1}}; + math1.load_gens_per_bus = {from_dense, {3}, 4}; math1.load_gen_type = {LoadGenType::const_i}; - math1.shunts_per_bus = {from_sparse, {0, 1, 1, 1, 1}}; - math1.voltage_sensors_per_bus = {from_sparse, {0, 0, 0, 0, 1}}; - math1.power_sensors_per_bus = {from_sparse, {0, 0, 0, 0, 1}}; - math1.power_sensors_per_source = {from_sparse, {0, 2}}; - math1.power_sensors_per_shunt = {from_sparse, {0, 2}}; - math1.power_sensors_per_load_gen = {from_sparse, {0, 2}}; - math1.power_sensors_per_branch_from = {from_sparse, {0, 0, 0, 0, 0, 0}}; - math1.power_sensors_per_branch_to = {from_sparse, {0, 0, 0, 0, 0, 0}}; + math1.shunts_per_bus = {from_dense, {0}, 4}; + math1.voltage_sensors_per_bus = {from_dense, {3}, 4}; + math1.power_sensors_per_bus = {from_dense, {3}, 4}; + math1.power_sensors_per_source = {from_dense, {0, 0}, 1}; + math1.power_sensors_per_shunt = {from_dense, {0, 0}, 1}; + math1.power_sensors_per_load_gen = {from_dense, {0, 0}, 1}; + math1.power_sensors_per_branch_from = {from_dense, {}, 5}; + math1.power_sensors_per_branch_to = {from_dense, {}, 5}; std::vector math_topology_ref = {math0, math1}; @@ -352,7 +348,7 @@ TEST_CASE("Test cycle reorder") { // result TopologicalComponentToMathCoupling comp_coup_ref{}; comp_coup_ref.node = {{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}}; - std::vector const fill_in_ref{{3, 5}, {4, 5}, {5, 8}, {5, 6}, {5, 7}}; + std::vector const fill_in_ref{{5, 3}, {4, 5}, {5, 8}, {6, 5}, {5, 7}}; Topology topo{comp_topo, comp_conn}; auto pair = topo.build_topology(); @@ -398,7 +394,7 @@ TEST_CASE("Test cycle reorder") { // result TopologicalComponentToMathCoupling comp_coup_ref{}; comp_coup_ref.node = {{0, 0}, {0, 3}, {0, 1}, {0, 2}, {0, 4}, {0, 5}, {0, 6}}; - std::vector const fill_in_ref{{5, 6}, {3, 6}, {4, 6}}; + std::vector const fill_in_ref{{5, 6}, {3, 6}, {6, 4}}; Topology topo{comp_topo, comp_conn}; auto pair = topo.build_topology(); From 15846b5d7a96f98b3496f67a8469b7d0ede34e50 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Fri, 15 Dec 2023 08:34:58 +0100 Subject: [PATCH 12/47] remove logging Signed-off-by: Martijn Govers --- .../include/power_grid_model/topology.hpp | 59 +------------------ 1 file changed, 1 insertion(+), 58 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 9a0073fea..cc7fc5bf2 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -19,8 +19,6 @@ #include #include -#include - // build topology of the grid // divide grid into several math models // start search from a source @@ -312,58 +310,21 @@ class Topology { std::copy(cyclic_node.crbegin(), cyclic_node.crend(), std::back_inserter(dfs_node)); return fill_in; } - // for (GraphIdx i = 0; i != n_cycle_node; ++i) { - // node_status_[cyclic_node[i]] = static_cast(i); - // } - - // // build graph lambda - // auto const build_graph = [&](ReorderGraph& g) { - // // add edges - // for (GraphIdx i = 0; i != n_cycle_node; ++i) { - // // loop all edges of vertex i - // auto const global_i = static_cast(cyclic_node[i]); - // BGL_FORALL_ADJ(global_i, global_j, global_graph_, GlobalGraph) { - // // skip if j is not part of cyclic sub graph - // if (node_status_[global_j] == -1) { - // continue; - // } - // auto const j = static_cast(node_status_[global_j]); - // if (!boost::edge(i, j, g).second) { - // boost::add_edge(i, j, g); - // } - // } - // } - // }; - // assign temporary bus number as increasing from 0, 1, 2, ..., n_cycle_node - 1 + std::map> unique_nearest_neighbours; for (Idx node_idx : cyclic_node) { auto predecessor = static_cast(predecessors_[node_idx]); - std::cout << node_idx << ": predecessor = " << predecessor << "\n"; if (predecessor != node_idx) { unique_nearest_neighbours[node_idx] = {predecessor}; } } - std::cout << std::endl; for (auto const& edge : back_edges) { auto const from{static_cast(edge.first)}; auto const to{static_cast(edge.second)}; - std::cout << "back edge: " << from << ", " << to; if (!detail::in_graph(std::pair{from, to}, unique_nearest_neighbours)) { - std::cout << " (new)"; unique_nearest_neighbours[from].push_back(to); } - std::cout << "\n"; - } - std::cout << std::endl; - - for (auto const& [node, neighbours] : unique_nearest_neighbours) { - std::cout << "node: " << node << ", adjacent = ["; - for (auto neighbour : neighbours) { - std::cout << neighbour << ", "; - } - std::cout << "]\n"; } - std::cout << std::endl; auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); std::ranges::copy(reordered, std::back_inserter(dfs_node)); @@ -379,24 +340,6 @@ class Topology { fill_in.push_back({from_reordered, to_reordered}); } - std::cout << "reordered (before permutation): ["; - for (auto n : reordered) { - std::cout << n << ", "; - } - std::cout << "]\nreordered (after permutation): ["; - for (auto n : dfs_node) { - std::cout << n << ", "; - } - std::cout << "]\nfill_in (before reordening) : ["; - for (auto [from, to] : fills) { - std::cout << "(" << from << ", " << to << "), "; - } - std::cout << "]\nfill_in (reordered) : ["; - for (auto [from, to] : fill_in) { - std::cout << "(" << from << ", " << to << "), "; - } - std::cout << "]\n" << std::endl; - return fill_in; } From ed9f48327dc0c00cabeda7aad19d6ad453ca3821 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 2 Jan 2024 14:19:32 +0100 Subject: [PATCH 13/47] remove bad import Signed-off-by: Martijn Govers --- .../include/power_grid_model/math_solver/y_bus.hpp | 2 -- .../include/power_grid_model/sparse_ordening.hpp | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp index 2cb2b2ada..b81eedbf6 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/math_solver/y_bus.hpp @@ -10,8 +10,6 @@ #include "../power_grid_model.hpp" #include "../three_phase_tensor.hpp" -#include // TODO(mgovers) remove - namespace power_grid_model { // hide implementation in inside namespace diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index 1d11f404e..4d9550c4c 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 #pragma once -#ifndef POWER_GRIdx_MODEL_MATH_SOLVER_SPARSE_ORDENING_HPP -#define POWER_GRIdx_MODEL_MATH_SOLVER_SPARSE_ORDENING_HPP +#ifndef POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ORDENING_HPP +#define POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ORDENING_HPP #include "power_grid_model.hpp" From 632798ea58f6314504784b6c1f0cbb6a5bf77a4d Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 2 Jan 2024 15:59:59 +0100 Subject: [PATCH 14/47] major cleanup minimum degree ordening Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 140 ++++++++---------- 1 file changed, 58 insertions(+), 82 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index 4d9550c4c..1730d9fdc 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -17,27 +17,13 @@ namespace power_grid_model { namespace detail { -inline void remove_element_vector_pair(Idx& u, std::vector>& dgd) { - Idx i = 0; - while (i < dgd.size()) { - if (dgd[i].first == u) { - dgd.erase(dgd.begin() + i); - break; - } else { - i++; - } - } +inline void remove_element_vector_pair(Idx u, std::vector>& dgd) { + std::erase_if(dgd, [u](auto const& v) { return v.first == u; }); } -inline void set_element_vector_pair(Idx& u, Idx v, std::vector>& dgd) { - Idx i = 0; - while (i < dgd.size()) { - if (dgd[i].first == u) { - dgd[i].second = v; - break; - } else { - i++; - } +inline void set_element_vector_pair(Idx u, Idx v, std::vector>& dgd) { + if (auto it = std::ranges::find_if(dgd, [u](auto const& value) { return value.first == u; }); it != dgd.end()) { + it->second = v; } } @@ -45,20 +31,18 @@ inline std::vector adj(Idx& u, std::map>& d) { std::vector l; for (const auto& it : d) { - if (it.first == u) - l.insert(l.end(), it.second.begin(), it.second.end()); + if (it.first == u) { + l.insert(l.end(), it.second.cbegin(), it.second.cend()); + } - if (find(it.second.begin(), it.second.end(), u) != it.second.end()) { - std::vector v{it.first}; - l.insert(l.end(), v.begin(), v.end()); + if (std::ranges::find(it.second, u) != it.second.cend()) { + l.push_back(it.first); } } return l; } -inline bool compair_ids(std::pair& a, std::pair& b) { return a.first < b.first; } - inline std::vector>>> comp_size_degrees_graph(std::map>& d) { std::vector> dd; @@ -67,64 +51,60 @@ comp_size_degrees_graph(std::map>& d) { for (const auto& it : d) { Idx k = it.first; - if (find(v.begin(), v.end(), k) == v.end()) { - std::vector vk{k}; - v.insert(v.end(), vk.begin(), vk.end()); - n += 1; - dd.push_back({k, adj(k, d).size()}); + if (std::ranges::find(v, k) == v.end()) { + ++n; + v.push_back(k); + dd.emplace_back(k, adj(k, d).size()); } for (const Idx& el : it.second) { Idx e = el; if (find(v.begin(), v.end(), e) == v.end()) { - std::vector ve{e}; - v.insert(v.end(), ve.begin(), ve.end()); - n += 1; - dd.push_back({e, adj(e, d).size()}); + ++n; + v.push_back(e); + dd.emplace_back(e, adj(e, d).size()); } } } - sort(dd.begin(), dd.end()); + std::ranges::sort(dd); return {{n, dd}}; } +inline std::map> make_clique(std::vector& l) { + std::map> d; + + for (Idx i = 0; i < static_cast(l.size()) - 1; i++) { + Idx const idx = i + 1; + std::vector sl(l.size() - idx); + std::copy(l.begin() + idx, l.end(), sl.begin()); + d[l[i]] = sl; + } + + return d; +} + inline std::vector, std::vector>> check_indistguishable(Idx& u, std::map>& d) { - std::vector l, rl, lu, lv, vu{u}, vv; - l = adj(u, d); - lu = l; - lu.insert(lu.end(), vu.begin(), vu.end()); + std::vector rl; + + auto l = adj(u, d); + auto lu = l; + lu.push_back(u); for (auto& v : l) { - lv = adj(v, d); - vv = {v}; - lv.insert(lv.end(), vv.begin(), vv.end()); - sort(lu.begin(), lu.end()); - sort(lv.begin(), lv.end()); + auto lv = adj(v, d); + lv.push_back(v); + std::ranges::sort(lu); + std::ranges::sort(lv); if (lu == lv) { - rl.insert(rl.end(), vv.begin(), vv.end()); + rl.push_back(v); } } return {{l, rl}}; } -inline std::map> make_clique(std::vector& l) { - std::map> d; - Idx b = l.size() - 1; - - for (int i = 0; i < b; i++) { - Idx index = i + 1; - auto start = l.begin() + index; - std::vector sl(l.size() - index); - copy(start, l.end(), sl.begin()); - d[l[i]] = sl; - } - - return d; -} - inline bool in_graph(std::pair const& e, std::map> const& d) { if (auto edges_it = d.find(e.first); edges_it != d.cend()) { if (std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) { @@ -145,31 +125,30 @@ inline std::vector remove_vertices_update_degrees(Idx& u, std::map, std::vector>> nbsrl = check_indistguishable(u, d); std::vector& nbs = nbsrl[0].first; std::vector& rl = nbsrl[0].second; - std::vector alpha = rl, vu{u}; + std::vector alpha = rl; std::map> dd; - rl.insert(rl.begin(), vu.begin(), vu.end()); + rl.push_back(u); - for (auto& uu : rl) { - if (uu != u) - nbs.erase(remove(nbs.begin(), nbs.end(), uu), nbs.end()); + for (auto uu : rl) { + if (uu != u) { + std::erase(nbs, uu); + } remove_element_vector_pair(uu, dgd); std::vector el; for (auto& it : d) { - it.second.erase(remove(it.second.begin(), it.second.end(), uu), it.second.end()); + std::erase(it.second, uu); if (it.second.empty()) { - Idx k = it.first; - std::vector vk{k}; - el.insert(el.end(), vk.begin(), vk.end()); + el.push_back(it.first); } } - std::vector vuu{uu}; - el.insert(el.end(), vuu.begin(), vuu.end()); + el.push_back(uu); - for (auto& it : el) + for (auto& it : el) { d.erase(it); + } } dd = make_clique(nbs); @@ -180,17 +159,14 @@ inline std::vector remove_vertices_update_degrees(Idx& u, std::map t{k, e}; if (!in_graph(t, d)) { if (d.find(k) != d.end()) { - std::vector ve{e}; - d[k].insert(d[k].end(), ve.begin(), ve.end()); - fills.push_back({k, e}); + d[k].push_back(e); + fills.emplace_back(k, e); } else if (d.find(e) != d.end()) { - std::vector vk{k}; - d[e].insert(d[e].end(), vk.begin(), vk.end()); - fills.push_back({e, k}); + d[e].push_back(k); + fills.emplace_back(e, k); } else { - std::vector ve{e}; - d[k].insert(d[k].end(), ve.begin(), ve.end()); - fills.push_back({k, e}); + d[k].push_back(e); + fills.emplace_back(k, e); } } } From 9de4a4435d226cd0a901e4e08576b19945df1389 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 2 Jan 2024 16:09:26 +0100 Subject: [PATCH 15/47] more cleanup Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 31 +++++++------------ 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index 1730d9fdc..e78433ca9 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -182,31 +182,22 @@ inline std::vector remove_vertices_update_degrees(Idx& u, std::map, std::vector>> minimum_degree_ordering(std::map>& d) { - std::vector>>> data = detail::comp_size_degrees_graph(d); - Idx& n = data[0].first; - std::vector>& dgd = data[0].second; + auto data = detail::comp_size_degrees_graph(d); + auto& [n, dgd] = data[0]; + std::vector alpha; std::vector> fills; - for (int k = 0; k < n; k++) { - Idx u = - get<0>(*min_element(begin(dgd), end(dgd), [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); - std::vector vu{u}; - alpha.insert(alpha.end(), vu.begin(), vu.end()); - if ((d.size() == 1) and d.begin()->second.size() == 1) { - Idx a = d.begin()->first; - Idx b = d.begin()->second[0]; - if (alpha.back() == a) { - std::vector vb{b}; - alpha.insert(alpha.end(), vb.begin(), vb.end()); - } else { - std::vector va{a}; - alpha.insert(alpha.end(), va.begin(), va.end()); - } + for (Idx k = 0; k < n; k++) { + Idx u = get<0>(*std::ranges::min_element(dgd, [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); + alpha.push_back(u); + if ((d.size() == 1) && d.begin()->second.size() == 1) { + Idx const a = d.begin()->first; + Idx const b = d.begin()->second[0]; + alpha.push_back(alpha.back() == a ? b : a); break; } else { - std::vector va = detail::remove_vertices_update_degrees(u, d, dgd, fills); - alpha.insert(alpha.end(), va.begin(), va.end()); + std::ranges::copy(detail::remove_vertices_update_degrees(u, d, dgd, fills), std::back_inserter(alpha)); if (d.empty()) { break; } From 6f3e9b5b003b247280911f6d956aa028f740ff51 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 2 Jan 2024 16:15:38 +0100 Subject: [PATCH 16/47] more improvements Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index e78433ca9..38381cf93 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -27,8 +27,8 @@ inline void set_element_vector_pair(Idx u, Idx v, std::vector adj(Idx& u, std::map>& d) { - std::vector l; +inline IdxVector adj(Idx& u, std::map& d) { + IdxVector l; for (const auto& it : d) { if (it.first == u) { @@ -44,9 +44,9 @@ inline std::vector adj(Idx& u, std::map>& d) { } inline std::vector>>> -comp_size_degrees_graph(std::map>& d) { +comp_size_degrees_graph(std::map& d) { std::vector> dd; - std::vector v; + IdxVector v; Idx n = 0; for (const auto& it : d) { @@ -71,12 +71,12 @@ comp_size_degrees_graph(std::map>& d) { return {{n, dd}}; } -inline std::map> make_clique(std::vector& l) { - std::map> d; +inline std::map make_clique(IdxVector& l) { + std::map d; for (Idx i = 0; i < static_cast(l.size()) - 1; i++) { Idx const idx = i + 1; - std::vector sl(l.size() - idx); + IdxVector sl(l.size() - idx); std::copy(l.begin() + idx, l.end(), sl.begin()); d[l[i]] = sl; } @@ -84,9 +84,8 @@ inline std::map> make_clique(std::vector& l) { return d; } -inline std::vector, std::vector>> -check_indistguishable(Idx& u, std::map>& d) { - std::vector rl; +inline std::vector> check_indistguishable(Idx& u, std::map& d) { + IdxVector rl; auto l = adj(u, d); auto lu = l; @@ -105,7 +104,7 @@ check_indistguishable(Idx& u, std::map>& d) { return {{l, rl}}; } -inline bool in_graph(std::pair const& e, std::map> const& d) { +inline bool in_graph(std::pair const& e, std::map const& d) { if (auto edges_it = d.find(e.first); edges_it != d.cend()) { if (std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) { return true; @@ -119,14 +118,13 @@ inline bool in_graph(std::pair const& e, std::map remove_vertices_update_degrees(Idx& u, std::map>& d, - std::vector>& dgd, - std::vector>& fills) { - std::vector, std::vector>> nbsrl = check_indistguishable(u, d); - std::vector& nbs = nbsrl[0].first; - std::vector& rl = nbsrl[0].second; - std::vector alpha = rl; - std::map> dd; +inline IdxVector remove_vertices_update_degrees(Idx& u, std::map& d, + std::vector>& dgd, + std::vector>& fills) { + std::vector> nbsrl = check_indistguishable(u, d); + auto& [nbs, rl] = nbsrl[0]; + IdxVector alpha = rl; + std::map dd; rl.push_back(u); @@ -136,7 +134,7 @@ inline std::vector remove_vertices_update_degrees(Idx& u, std::map el; + IdxVector el; for (auto& it : d) { std::erase(it.second, uu); if (it.second.empty()) { @@ -158,15 +156,12 @@ inline std::vector remove_vertices_update_degrees(Idx& u, std::map t{k, e}; if (!in_graph(t, d)) { - if (d.find(k) != d.end()) { + if (d.find(k) != d.end() || d.find(e) == d.end()) { d[k].push_back(e); fills.emplace_back(k, e); - } else if (d.find(e) != d.end()) { + } else { d[e].push_back(k); fills.emplace_back(e, k); - } else { - d[k].push_back(e); - fills.emplace_back(k, e); } } } @@ -180,12 +175,11 @@ inline std::vector remove_vertices_update_degrees(Idx& u, std::map, std::vector>> -minimum_degree_ordering(std::map>& d) { +inline std::pair>> minimum_degree_ordering(std::map& d) { auto data = detail::comp_size_degrees_graph(d); auto& [n, dgd] = data[0]; - std::vector alpha; + IdxVector alpha; std::vector> fills; for (Idx k = 0; k < n; k++) { From 0c0c6673044a2c228d9e80fa21c655efa79231f6 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 2 Jan 2024 16:18:33 +0100 Subject: [PATCH 17/47] minor Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordening.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index 38381cf93..fbfb28e67 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -78,7 +78,7 @@ inline std::map make_clique(IdxVector& l) { Idx const idx = i + 1; IdxVector sl(l.size() - idx); std::copy(l.begin() + idx, l.end(), sl.begin()); - d[l[i]] = sl; + d[l[i]] = std::move(sl); } return d; From f1e992311dae32a8965301f1347a9d2bc379055f Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 30 Jan 2024 15:21:41 +0100 Subject: [PATCH 18/47] update licenses of new files Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordening.hpp | 2 +- tests/cpp_unit_tests/test_sparse_ordening.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index fbfb28e67..a71c05991 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project // // SPDX-License-Identifier: MPL-2.0 diff --git a/tests/cpp_unit_tests/test_sparse_ordening.cpp b/tests/cpp_unit_tests/test_sparse_ordening.cpp index 5b668ce15..d0c0bef8f 100644 --- a/tests/cpp_unit_tests/test_sparse_ordening.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordening.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project // // SPDX-License-Identifier: MPL-2.0 From 7c78624092541456568c6952704fa0d8e9cd59cc Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Thu, 1 Feb 2024 09:52:13 +0100 Subject: [PATCH 19/47] fix clang tidy Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordening.hpp | 15 +++++++-------- .../include/power_grid_model/topology.hpp | 2 +- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index a71c05991..b176eb095 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -152,9 +152,9 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map dd = make_clique(nbs); for (auto& it : dd) { - Idx k = it.first; + Idx const k = it.first; for (const Idx& e : it.second) { - std::pair t{k, e}; + std::pair const t{k, e}; if (!in_graph(t, d)) { if (d.find(k) != d.end() || d.find(e) == d.end()) { d[k].push_back(e); @@ -168,7 +168,7 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map } for (auto& e : nbs) { - set_element_vector_pair(e, adj(e, d).size(), dgd); + set_element_vector_pair(e, static_cast(adj(e, d).size()), dgd); } return alpha; @@ -190,11 +190,10 @@ inline std::pair>> minimum_degree_ord Idx const b = d.begin()->second[0]; alpha.push_back(alpha.back() == a ? b : a); break; - } else { - std::ranges::copy(detail::remove_vertices_update_degrees(u, d, dgd, fills), std::back_inserter(alpha)); - if (d.empty()) { - break; - } + } + std::ranges::copy(detail::remove_vertices_update_degrees(u, d, dgd, fills), std::back_inserter(alpha)); + if (d.empty()) { + break; } } return {alpha, fills}; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 0df50f947..d098a8e81 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -312,7 +312,7 @@ class Topology { } std::map> unique_nearest_neighbours; - for (Idx node_idx : cyclic_node) { + for (Idx const node_idx : cyclic_node) { auto predecessor = static_cast(predecessors_[node_idx]); if (predecessor != node_idx) { unique_nearest_neighbours[node_idx] = {predecessor}; From d2b198a0aa9bdbd9df084cf57d9e3985969854f6 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 11:45:04 +0100 Subject: [PATCH 20/47] resolve code smells - part 1 Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index b176eb095..f65d44e5e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -27,16 +27,14 @@ inline void set_element_vector_pair(Idx u, Idx v, std::vector& d) { +inline IdxVector adj(Idx const& u, std::map const& d) { IdxVector l; - for (const auto& it : d) { - if (it.first == u) { - l.insert(l.end(), it.second.cbegin(), it.second.cend()); - } - - if (std::ranges::find(it.second, u) != it.second.cend()) { - l.push_back(it.first); + for (const auto& [k, adjacent] : d) { + if (k == u) { + l.insert(l.end(), adjacent.cbegin(), adjacent.cend()); + } else if (std::ranges::find(adjacent, u) != adjacent.cend()) { + l.push_back(k); } } @@ -49,15 +47,13 @@ comp_size_degrees_graph(std::map& d) { IdxVector v; Idx n = 0; - for (const auto& it : d) { - Idx k = it.first; + for (const auto& [k, adjacent] : d) { if (std::ranges::find(v, k) == v.end()) { ++n; v.push_back(k); dd.emplace_back(k, adj(k, d).size()); } - for (const Idx& el : it.second) { - Idx e = el; + for (const Idx& e : adjacent) { if (find(v.begin(), v.end(), e) == v.end()) { ++n; v.push_back(e); @@ -105,15 +101,13 @@ inline std::vector> check_indistguishable(Idx& u } inline bool in_graph(std::pair const& e, std::map const& d) { - if (auto edges_it = d.find(e.first); edges_it != d.cend()) { - if (std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) { - return true; - } + if (auto edges_it = d.find(e.first); + edges_it != d.cend() && std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) { + return true; } - if (auto edges_it = d.find(e.second); edges_it != d.cend()) { - if (std::ranges::find(edges_it->second, e.first) != edges_it->second.cend()) { - return true; - } + if (auto edges_it = d.find(e.second); + edges_it != d.cend() && std::ranges::find(edges_it->second, e.first) != edges_it->second.cend()) { + return true; } return false; } @@ -135,26 +129,25 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map remove_element_vector_pair(uu, dgd); IdxVector el; - for (auto& it : d) { - std::erase(it.second, uu); - if (it.second.empty()) { - el.push_back(it.first); + for (auto& [e, adjacent] : d) { + std::erase(adjacent, uu); + if (adjacent.empty()) { + el.push_back(e); } } el.push_back(uu); - for (auto& it : el) { + for (auto const& it : el) { d.erase(it); } } dd = make_clique(nbs); - for (auto& it : dd) { - Idx const k = it.first; - for (const Idx& e : it.second) { - std::pair const t{k, e}; + for (auto const& [k, adjacent] : dd) { + for (Idx e : adjacent) { + std::pair const t{k, e}; if (!in_graph(t, d)) { if (d.find(k) != d.end() || d.find(e) == d.end()) { d[k].push_back(e); From 6c4e36c37e1c0318e7f4eae487199e55b98c7d08 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 13:19:40 +0100 Subject: [PATCH 21/47] resolve sonar cloud Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 33 ++++++++++--------- .../include/power_grid_model/topology.hpp | 12 +++---- tests/cpp_unit_tests/test_sparse_ordening.cpp | 10 +++--- tests/cpp_unit_tests/test_topology.cpp | 7 ++-- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index f65d44e5e..a66d8879e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -143,18 +143,24 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map } } - dd = make_clique(nbs); + dd = make_clique(nbs); // TODO check data type + + auto const add_element = [&fills](Idx from, Idx to, IdxVector& from_adjacent) { + from_adjacent.push_back(to); + fills.emplace_back(from, to); + }; for (auto const& [k, adjacent] : dd) { + auto it = d.find(k); for (Idx e : adjacent) { - std::pair const t{k, e}; - if (!in_graph(t, d)) { - if (d.find(k) != d.end() || d.find(e) == d.end()) { - d[k].push_back(e); - fills.emplace_back(k, e); + if (!in_graph(std::make_pair(k, e), d)) { + if (it != d.end()) { + add_element(k, e, it->second); + } + if (auto e_it = d.find(e); e_it != d.end()) { + add_element(e, k, e_it->second); } else { - d[e].push_back(k); - fills.emplace_back(e, k); + add_element(k, e, it->second); } } } @@ -175,19 +181,16 @@ inline std::pair>> minimum_degree_ord IdxVector alpha; std::vector> fills; - for (Idx k = 0; k < n; k++) { + for (Idx k = 0; k < n && !d.empty(); k++) { Idx u = get<0>(*std::ranges::min_element(dgd, [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); alpha.push_back(u); if ((d.size() == 1) && d.begin()->second.size() == 1) { - Idx const a = d.begin()->first; - Idx const b = d.begin()->second[0]; - alpha.push_back(alpha.back() == a ? b : a); + Idx const from = d.begin()->first; + Idx const to = d.begin()->second[0]; + alpha.push_back(alpha.back() == from ? to : from); break; } std::ranges::copy(detail::remove_vertices_update_degrees(u, d, dgd, fills), std::back_inserter(alpha)); - if (d.empty()) { - break; - } } return {alpha, fills}; } diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 273d4c751..61d5b8f53 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -304,9 +304,9 @@ class Topology { std::vector cyclic_node; std::copy_if(dfs_node_copy.cbegin(), dfs_node_copy.cend(), std::back_inserter(cyclic_node), [this](Idx x) { return node_status_[x] == -2; }); - GraphIdx const n_cycle_node = cyclic_node.size(); + // reorder does not make sense if number of cyclic nodes in a sub graph is smaller than 4 - if (n_cycle_node < 4) { + if (cyclic_node.size() < 4) { std::copy(cyclic_node.crbegin(), cyclic_node.crend(), std::back_inserter(dfs_node)); return fill_in; } @@ -318,9 +318,9 @@ class Topology { unique_nearest_neighbours[node_idx] = {predecessor}; } } - for (auto const& edge : back_edges) { - auto const from{static_cast(edge.first)}; - auto const to{static_cast(edge.second)}; + for (auto const& [from_node, to_node] : back_edges) { + auto const from{static_cast(from_node)}; + auto const to{static_cast(to_node)}; if (!detail::in_graph(std::pair{from, to}, unique_nearest_neighbours)) { unique_nearest_neighbours[from].push_back(to); } @@ -331,7 +331,7 @@ class Topology { // TODO(mgovers): make this more efficient auto const permuted_node_idx = [&dfs_node](Idx node_idx) { - return static_cast(std::distance(dfs_node.begin(), std::ranges::find(dfs_node, node_idx))); + return narrow_cast(std::distance(dfs_node.begin(), std::ranges::find(dfs_node, node_idx))); }; for (auto [from, to] : fills) { diff --git a/tests/cpp_unit_tests/test_sparse_ordening.cpp b/tests/cpp_unit_tests/test_sparse_ordening.cpp index d0c0bef8f..cdd61ded0 100644 --- a/tests/cpp_unit_tests/test_sparse_ordening.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordening.cpp @@ -20,15 +20,13 @@ TEST_CASE("Test sparse ordening") { {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; auto const start = std::chrono::high_resolution_clock::now(); - std::pair, std::vector>> const alpha_fills = - power_grid_model::minimum_degree_ordering(graph); + auto const [alpha, fills] = power_grid_model::minimum_degree_ordering(graph); auto const stop = std::chrono::high_resolution_clock::now(); auto const duration = duration_cast(stop - start); - std::cout << "Time taken by function: " << duration.count() << " microseconds" - << "\n"; + std::cout << "Time taken by function: " << duration.count() << " microseconds\n"; - CHECK(alpha_fills.first == std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); - CHECK(alpha_fills.second == std::vector>{{3, 5}, {4, 5}, {8, 5}, {6, 5}, {7, 5}}); + CHECK(alpha == std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); + CHECK(fills == std::vector>{{3, 5}, {4, 5}, {8, 5}, {6, 5}, {7, 5}}); } } diff --git a/tests/cpp_unit_tests/test_topology.cpp b/tests/cpp_unit_tests/test_topology.cpp index a7e53af1e..70592def9 100644 --- a/tests/cpp_unit_tests/test_topology.cpp +++ b/tests/cpp_unit_tests/test_topology.cpp @@ -282,9 +282,10 @@ TEST_CASE("Test topology") { SUBCASE("Test topology result") { Topology topo{comp_topo, comp_conn}; - auto pair = topo.build_topology(); - auto const& math_topology = pair.first; - auto const& topo_comp_coup = *pair.second; + auto const [math_topology, topo_comp_coup_ptr] = topo.build_topology(); + + REQUIRE(topo_comp_coup_ptr != nullptr); + auto const& topo_comp_coup = *topo_comp_coup_ptr; CHECK(math_topology.size() == 2); // test component coupling From d65b929d16d4b49e3285e02a399def9195ad1364 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 13:28:13 +0100 Subject: [PATCH 22/47] resolve sonar cloud Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordening.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index a66d8879e..dde4440a2 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -156,10 +156,10 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map if (!in_graph(std::make_pair(k, e), d)) { if (it != d.end()) { add_element(k, e, it->second); - } - if (auto e_it = d.find(e); e_it != d.end()) { + } else if (auto e_it = d.find(e); e_it != d.end()) { add_element(e, k, e_it->second); } else { + std::tie(it, std::ignore) = d.emplace(std::make_pair(k, IdxVector{})); add_element(k, e, it->second); } } From 0d645268e01102e717b5d807b93514ba11fda31a Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 13:36:47 +0100 Subject: [PATCH 23/47] fix compilation Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index dde4440a2..b04602522 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -145,22 +145,16 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map dd = make_clique(nbs); // TODO check data type - auto const add_element = [&fills](Idx from, Idx to, IdxVector& from_adjacent) { - from_adjacent.push_back(to); - fills.emplace_back(from, to); - }; - for (auto const& [k, adjacent] : dd) { - auto it = d.find(k); for (Idx e : adjacent) { - if (!in_graph(std::make_pair(k, e), d)) { - if (it != d.end()) { - add_element(k, e, it->second); - } else if (auto e_it = d.find(e); e_it != d.end()) { - add_element(e, k, e_it->second); + std::pair const t{k, e}; + if (!in_graph(t, d)) { + if (d.contains(k) || !d.contains(e)) { + d[k].push_back(e); + fills.emplace_back(k, e); } else { - std::tie(it, std::ignore) = d.emplace(std::make_pair(k, IdxVector{})); - add_element(k, e, it->second); + d[e].push_back(k); + fills.emplace_back(e, k); } } } From 8b03643f69f0bce64e8edd335d608ab5468d3198 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 13:40:17 +0100 Subject: [PATCH 24/47] more efficient implementation Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index b04602522..dde4440a2 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -145,16 +145,22 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map dd = make_clique(nbs); // TODO check data type + auto const add_element = [&fills](Idx from, Idx to, IdxVector& from_adjacent) { + from_adjacent.push_back(to); + fills.emplace_back(from, to); + }; + for (auto const& [k, adjacent] : dd) { + auto it = d.find(k); for (Idx e : adjacent) { - std::pair const t{k, e}; - if (!in_graph(t, d)) { - if (d.contains(k) || !d.contains(e)) { - d[k].push_back(e); - fills.emplace_back(k, e); + if (!in_graph(std::make_pair(k, e), d)) { + if (it != d.end()) { + add_element(k, e, it->second); + } else if (auto e_it = d.find(e); e_it != d.end()) { + add_element(e, k, e_it->second); } else { - d[e].push_back(k); - fills.emplace_back(e, k); + std::tie(it, std::ignore) = d.emplace(std::make_pair(k, IdxVector{})); + add_element(k, e, it->second); } } } From a3de21ddf7738ea0f7fc6477c7bbd42cd210437b Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 13:54:56 +0100 Subject: [PATCH 25/47] fix clang tidy Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordening.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index dde4440a2..3d0a040fc 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -152,14 +152,14 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map for (auto const& [k, adjacent] : dd) { auto it = d.find(k); - for (Idx e : adjacent) { + for (Idx const e : adjacent) { if (!in_graph(std::make_pair(k, e), d)) { if (it != d.end()) { add_element(k, e, it->second); } else if (auto e_it = d.find(e); e_it != d.end()) { add_element(e, k, e_it->second); } else { - std::tie(it, std::ignore) = d.emplace(std::make_pair(k, IdxVector{})); + std::tie(it, std::ignore) = d.try_emplace(k); add_element(k, e, it->second); } } From 2b3804901d92762c2ef0eb0e688b9940caabe05d Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 14:11:07 +0100 Subject: [PATCH 26/47] resolve sonar cloud Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index 3d0a040fc..d8cc1dbff 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -42,19 +42,19 @@ inline IdxVector adj(Idx const& u, std::map const& d) { } inline std::vector>>> -comp_size_degrees_graph(std::map& d) { +comp_size_degrees_graph(std::map const& d) { std::vector> dd; IdxVector v; Idx n = 0; for (const auto& [k, adjacent] : d) { - if (std::ranges::find(v, k) == v.end()) { + if (std::ranges::contains(v, k)) { ++n; v.push_back(k); dd.emplace_back(k, adj(k, d).size()); } for (const Idx& e : adjacent) { - if (find(v.begin(), v.end(), e) == v.end()) { + if (std::ranges::contains(v, e)) { ++n; v.push_back(e); dd.emplace_back(e, adj(e, d).size()); @@ -80,14 +80,15 @@ inline std::map make_clique(IdxVector& l) { return d; } -inline std::vector> check_indistguishable(Idx& u, std::map& d) { +inline std::vector> check_indistguishable(Idx const& u, + std::map const& d) { IdxVector rl; auto l = adj(u, d); auto lu = l; lu.push_back(u); - for (auto& v : l) { + for (auto const& v : l) { auto lv = adj(v, d); lv.push_back(v); std::ranges::sort(lu); @@ -166,7 +167,7 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map } } - for (auto& e : nbs) { + for (auto const& e : nbs) { set_element_vector_pair(e, static_cast(adj(e, d).size()), dgd); } @@ -181,7 +182,7 @@ inline std::pair>> minimum_degree_ord IdxVector alpha; std::vector> fills; - for (Idx k = 0; k < n && !d.empty(); k++) { + for (Idx k = 0; k < n; ++k) { Idx u = get<0>(*std::ranges::min_element(dgd, [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); alpha.push_back(u); if ((d.size() == 1) && d.begin()->second.size() == 1) { @@ -191,6 +192,9 @@ inline std::pair>> minimum_degree_ord break; } std::ranges::copy(detail::remove_vertices_update_degrees(u, d, dgd, fills), std::back_inserter(alpha)); + if (d.empty()) { + break; + } } return {alpha, fills}; } From 6549be4189333ccaf63d4fde5ebd114aafecdcd6 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 14:17:23 +0100 Subject: [PATCH 27/47] fix Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordening.hpp | 4 ++-- .../include/power_grid_model/topology.hpp | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index d8cc1dbff..f4810ecc7 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -48,13 +48,13 @@ comp_size_degrees_graph(std::map const& d) { Idx n = 0; for (const auto& [k, adjacent] : d) { - if (std::ranges::contains(v, k)) { + if (std::ranges::find(v, k) == v.end()) { ++n; v.push_back(k); dd.emplace_back(k, adj(k, d).size()); } for (const Idx& e : adjacent) { - if (std::ranges::contains(v, e)) { + if (std::ranges::find(v, e) == v.end()) { ++n; v.push_back(e); dd.emplace_back(e, adj(e, d).size()); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 61d5b8f53..ffb837080 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -329,7 +329,6 @@ class Topology { auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); std::ranges::copy(reordered, std::back_inserter(dfs_node)); - // TODO(mgovers): make this more efficient auto const permuted_node_idx = [&dfs_node](Idx node_idx) { return narrow_cast(std::distance(dfs_node.begin(), std::ranges::find(dfs_node, node_idx))); }; @@ -359,15 +358,13 @@ class Topology { Idx2D const i_math = comp_coup_.node[i]; Idx2D const j_math = comp_coup_.node[j]; Idx const math_group = [&]() { - // TODO(mgovers): rewrite - Idx group = -1; if (i_status != 0 && i_math.group != -1) { - group = i_math.group; + return i_math.group; } if (j_status != 0 && j_math.group != -1) { - group = j_math.group; + return j_math.group; } - return group; + return Idx{-1}; }(); // skip if no math model connected if (math_group == -1) { From a207fec8eff44e3118b7dc8ad770eeebd616e9d8 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 15:57:01 +0100 Subject: [PATCH 28/47] fix more code smells Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index f4810ecc7..0460aa69a 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -9,8 +9,8 @@ #include "power_grid_model.hpp" #include // remove and remove_if -#include #include +#include #include #include @@ -27,7 +27,7 @@ inline void set_element_vector_pair(Idx u, Idx v, std::vector const& d) { +inline IdxVector adj(Idx const u, std::unordered_map const& d) { IdxVector l; for (const auto& [k, adjacent] : d) { @@ -42,18 +42,18 @@ inline IdxVector adj(Idx const& u, std::map const& d) { } inline std::vector>>> -comp_size_degrees_graph(std::map const& d) { +comp_size_degrees_graph(std::unordered_map const& d) { std::vector> dd; IdxVector v; Idx n = 0; - for (const auto& [k, adjacent] : d) { + for (auto const& [k, adjacent] : d) { if (std::ranges::find(v, k) == v.end()) { ++n; v.push_back(k); dd.emplace_back(k, adj(k, d).size()); } - for (const Idx& e : adjacent) { + for (Idx e : adjacent) { if (std::ranges::find(v, e) == v.end()) { ++n; v.push_back(e); @@ -67,8 +67,8 @@ comp_size_degrees_graph(std::map const& d) { return {{n, dd}}; } -inline std::map make_clique(IdxVector& l) { - std::map d; +inline std::unordered_map make_clique(IdxVector& l) { + std::unordered_map d; for (Idx i = 0; i < static_cast(l.size()) - 1; i++) { Idx const idx = i + 1; @@ -80,8 +80,8 @@ inline std::map make_clique(IdxVector& l) { return d; } -inline std::vector> check_indistguishable(Idx const& u, - std::map const& d) { +inline std::vector> check_indistguishable(Idx const u, + std::unordered_map const& d) { IdxVector rl; auto l = adj(u, d); @@ -101,7 +101,7 @@ inline std::vector> check_indistguishable(Idx co return {{l, rl}}; } -inline bool in_graph(std::pair const& e, std::map const& d) { +inline bool in_graph(std::pair const& e, std::unordered_map const& d) { if (auto edges_it = d.find(e.first); edges_it != d.cend() && std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) { return true; @@ -113,13 +113,13 @@ inline bool in_graph(std::pair const& e, std::map cons return false; } -inline IdxVector remove_vertices_update_degrees(Idx& u, std::map& d, +inline IdxVector remove_vertices_update_degrees(Idx const u, std::unordered_map& d, std::vector>& dgd, std::vector>& fills) { std::vector> nbsrl = check_indistguishable(u, d); auto& [nbs, rl] = nbsrl[0]; IdxVector alpha = rl; - std::map dd; + std::unordered_map dd; rl.push_back(u); @@ -175,7 +175,8 @@ inline IdxVector remove_vertices_update_degrees(Idx& u, std::map } } // namespace detail -inline std::pair>> minimum_degree_ordering(std::map& d) { +inline std::pair>> +minimum_degree_ordering(std::unordered_map& d) { auto data = detail::comp_size_degrees_graph(d); auto& [n, dgd] = data[0]; @@ -189,11 +190,11 @@ inline std::pair>> minimum_degree_ord Idx const from = d.begin()->first; Idx const to = d.begin()->second[0]; alpha.push_back(alpha.back() == from ? to : from); - break; + return {alpha, fills}; } std::ranges::copy(detail::remove_vertices_update_degrees(u, d, dgd, fills), std::back_inserter(alpha)); if (d.empty()) { - break; + return {alpha, fills}; } } return {alpha, fills}; From f1000b7c37698d81af5627913737b5282f245689 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 16:00:17 +0100 Subject: [PATCH 29/47] fix Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordening.hpp | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index 0460aa69a..f2d09b6cb 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -9,8 +9,8 @@ #include "power_grid_model.hpp" #include // remove and remove_if +#include #include -#include #include #include @@ -27,7 +27,7 @@ inline void set_element_vector_pair(Idx u, Idx v, std::vector const& d) { +inline IdxVector adj(Idx const u, std::map const& d) { IdxVector l; for (const auto& [k, adjacent] : d) { @@ -42,7 +42,7 @@ inline IdxVector adj(Idx const u, std::unordered_map const& d) { } inline std::vector>>> -comp_size_degrees_graph(std::unordered_map const& d) { +comp_size_degrees_graph(std::map const& d) { std::vector> dd; IdxVector v; Idx n = 0; @@ -67,8 +67,8 @@ comp_size_degrees_graph(std::unordered_map const& d) { return {{n, dd}}; } -inline std::unordered_map make_clique(IdxVector& l) { - std::unordered_map d; +inline std::map make_clique(IdxVector& l) { + std::map d; for (Idx i = 0; i < static_cast(l.size()) - 1; i++) { Idx const idx = i + 1; @@ -81,7 +81,7 @@ inline std::unordered_map make_clique(IdxVector& l) { } inline std::vector> check_indistguishable(Idx const u, - std::unordered_map const& d) { + std::map const& d) { IdxVector rl; auto l = adj(u, d); @@ -101,7 +101,7 @@ inline std::vector> check_indistguishable(Idx co return {{l, rl}}; } -inline bool in_graph(std::pair const& e, std::unordered_map const& d) { +inline bool in_graph(std::pair const& e, std::map const& d) { if (auto edges_it = d.find(e.first); edges_it != d.cend() && std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) { return true; @@ -113,13 +113,13 @@ inline bool in_graph(std::pair const& e, std::unordered_map& d, +inline IdxVector remove_vertices_update_degrees(Idx const u, std::map& d, std::vector>& dgd, std::vector>& fills) { std::vector> nbsrl = check_indistguishable(u, d); auto& [nbs, rl] = nbsrl[0]; IdxVector alpha = rl; - std::unordered_map dd; + std::map dd; rl.push_back(u); @@ -175,8 +175,7 @@ inline IdxVector remove_vertices_update_degrees(Idx const u, std::unordered_map< } } // namespace detail -inline std::pair>> -minimum_degree_ordering(std::unordered_map& d) { +inline std::pair>> minimum_degree_ordering(std::map& d) { auto data = detail::comp_size_degrees_graph(d); auto& [n, dgd] = data[0]; From 4ad908421f6d8292830fbd9ce663f133423a1fc8 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 14 Feb 2024 16:09:31 +0100 Subject: [PATCH 30/47] clang-tidy Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordening.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp index f2d09b6cb..25bc36804 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp @@ -53,7 +53,7 @@ comp_size_degrees_graph(std::map const& d) { v.push_back(k); dd.emplace_back(k, adj(k, d).size()); } - for (Idx e : adjacent) { + for (Idx const e : adjacent) { if (std::ranges::find(v, e) == v.end()) { ++n; v.push_back(e); @@ -183,7 +183,8 @@ inline std::pair>> minimum_degree_ord std::vector> fills; for (Idx k = 0; k < n; ++k) { - Idx u = get<0>(*std::ranges::min_element(dgd, [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); + Idx const u = + get<0>(*std::ranges::min_element(dgd, [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); alpha.push_back(u); if ((d.size() == 1) && d.begin()->second.size() == 1) { Idx const from = d.begin()->first; From 01ea81e4f6e9853f0259b9f65149e3c32d548e92 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Thu, 15 Feb 2024 15:33:29 +0100 Subject: [PATCH 31/47] rename sparse ordening -> sparse ordering Signed-off-by: Martijn Govers --- .../{sparse_ordening.hpp => sparse_ordering.hpp} | 4 ++-- .../power_grid_model/include/power_grid_model/topology.hpp | 2 +- tests/cpp_unit_tests/CMakeLists.txt | 2 +- .../{test_sparse_ordening.cpp => test_sparse_ordering.cpp} | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) rename power_grid_model_c/power_grid_model/include/power_grid_model/{sparse_ordening.hpp => sparse_ordering.hpp} (98%) rename tests/cpp_unit_tests/{test_sparse_ordening.cpp => test_sparse_ordering.cpp} (89%) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp similarity index 98% rename from power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp rename to power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index 25bc36804..683369cda 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordening.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -3,8 +3,8 @@ // SPDX-License-Identifier: MPL-2.0 #pragma once -#ifndef POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ORDENING_HPP -#define POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ORDENING_HPP +#ifndef POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ORDERING_HPP +#define POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ORDERING_HPP #include "power_grid_model.hpp" diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index ffb837080..cb99d0843 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -11,7 +11,7 @@ #include "exception.hpp" #include "index_mapping.hpp" #include "power_grid_model.hpp" -#include "sparse_ordening.hpp" +#include "sparse_ordering.hpp" #include #include diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt index 4fe97b532..db2fcacd9 100644 --- a/tests/cpp_unit_tests/CMakeLists.txt +++ b/tests/cpp_unit_tests/CMakeLists.txt @@ -25,7 +25,7 @@ set(PROJECT_SOURCES "test_math_solver.cpp" "test_measured_values.cpp" "test_topology.cpp" - "test_sparse_ordening.cpp" + "test_sparse_ordering.cpp" "test_grouped_index_vector.cpp" "test_container.cpp" "test_index_mapping.cpp" diff --git a/tests/cpp_unit_tests/test_sparse_ordening.cpp b/tests/cpp_unit_tests/test_sparse_ordering.cpp similarity index 89% rename from tests/cpp_unit_tests/test_sparse_ordening.cpp rename to tests/cpp_unit_tests/test_sparse_ordering.cpp index cdd61ded0..d88328ff6 100644 --- a/tests/cpp_unit_tests/test_sparse_ordening.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordering.cpp @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MPL-2.0 -#include +#include #include @@ -14,8 +14,8 @@ namespace { using power_grid_model::Idx; } // namespace -TEST_CASE("Test sparse ordening") { - SUBCASE("minimum_degree_ordening") { +TEST_CASE("Test sparse ordering") { + SUBCASE("minimum_degree_ordering") { std::map> graph{{0, {3, 5}}, {1, {4, 5, 8}}, {2, {4, 5, 6}}, {3, {6, 7}}, {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; From 26ca1bf07eecd59fc2df752bcea0e40750fe512d Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Fri, 16 Feb 2024 17:32:26 +0100 Subject: [PATCH 32/47] remove test code Signed-off-by: Martijn Govers --- tests/cpp_validation_tests/test_validation.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/cpp_validation_tests/test_validation.cpp b/tests/cpp_validation_tests/test_validation.cpp index 6d55a01b8..84bfb798a 100644 --- a/tests/cpp_validation_tests/test_validation.cpp +++ b/tests/cpp_validation_tests/test_validation.cpp @@ -608,15 +608,14 @@ TEST_CASE("Validation test single") { TEST_CASE("Validation test batch") { std::vector const& all_cases = get_all_batch_cases(); for (CaseParam const& param : all_cases) { - if (param.case_name == - "power_flow/pandapower/networks/asymmetric/distribution-case-asym-newton_raphson_batch") { - SUBCASE(param.case_name.c_str()) { - try { - validate_batch_case(param); - } catch (std::exception& e) { - auto const msg = std::string("Unexpected exception with message: ") + e.what(); - FAIL_CHECK(msg); - } + SUBCASE(param.case_name.c_str()) { + try { + validate_batch_case(param); + } catch (std::exception& e) { + using namespace std::string_literals; + + auto const msg = "Unexpected exception with message: "s + e.what(); + FAIL_CHECK(msg); } } } From 9fd6e9fecf759fd0a965ad710f866f3ee621145a Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 20 Feb 2024 09:21:44 +0100 Subject: [PATCH 33/47] [skip ci] minor Signed-off-by: Martijn Govers --- tests/cpp_validation_tests/test_validation.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/cpp_validation_tests/test_validation.cpp b/tests/cpp_validation_tests/test_validation.cpp index 84bfb798a..486d9a253 100644 --- a/tests/cpp_validation_tests/test_validation.cpp +++ b/tests/cpp_validation_tests/test_validation.cpp @@ -598,7 +598,9 @@ TEST_CASE("Validation test single") { try { validate_single_case(param); } catch (std::exception& e) { - auto const msg = std::string("Unexpected exception with message: ") + e.what(); + using namespace std::string_literals; + + auto const msg = "Unexpected exception with message: "s + e.what(); FAIL_CHECK(msg); } } From 9caf62d6255407b0212f32dd87b9b2565173b78b Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 13 Mar 2024 18:09:20 +0100 Subject: [PATCH 34/47] minor fix Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordering.hpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index 683369cda..4ffbe9866 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -3,14 +3,11 @@ // SPDX-License-Identifier: MPL-2.0 #pragma once -#ifndef POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ORDERING_HPP -#define POWER_GRID_MODEL_MATH_SOLVER_SPARSE_ORDERING_HPP -#include "power_grid_model.hpp" +#include "common/common.hpp" -#include // remove and remove_if +#include #include -#include #include #include @@ -200,5 +197,3 @@ inline std::pair>> minimum_degree_ord return {alpha, fills}; } } // namespace power_grid_model - -#endif From feb075546db826f604b0c79449b4107911d48f72 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Thu, 14 Mar 2024 07:55:10 +0100 Subject: [PATCH 35/47] fix benchmark Signed-off-by: Martijn Govers --- .../include/power_grid_model/topology.hpp | 12 +++++++----- tests/cpp_unit_tests/test_topology.cpp | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 666203cba..f62b31853 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -325,15 +325,17 @@ class Topology { } auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); - std::ranges::copy(reordered, std::back_inserter(dfs_node)); - auto const permuted_node_idx = [&dfs_node](Idx node_idx) { - return narrow_cast(std::distance(dfs_node.begin(), std::ranges::find(dfs_node, node_idx))); + const auto n_non_cyclic_nodes = static_cast(dfs_node.size()); + auto const permuted_node_idx = [n_non_cyclic_nodes, &reordered](Idx node_idx) { + return n_non_cyclic_nodes + + narrow_cast(std::distance(reordered.begin(), std::ranges::find(reordered, node_idx))); }; + std::ranges::copy(reordered, std::back_inserter(dfs_node)); for (auto [from, to] : fills) { - auto from_reordered = permuted_node_idx(reordered[from]); - auto to_reordered = permuted_node_idx(reordered[to]); + auto from_reordered = permuted_node_idx(from); + auto to_reordered = permuted_node_idx(to); fill_in.push_back({from_reordered, to_reordered}); } diff --git a/tests/cpp_unit_tests/test_topology.cpp b/tests/cpp_unit_tests/test_topology.cpp index 70592def9..4b707415a 100644 --- a/tests/cpp_unit_tests/test_topology.cpp +++ b/tests/cpp_unit_tests/test_topology.cpp @@ -259,7 +259,7 @@ TEST_CASE("Test topology") { // sensor 0 is connected to branch 0 // sensor 1 and 2 are connected to branch 1 math0.power_sensors_per_branch_to = {from_dense, {0, 1, 1}, 7}; - math0.fill_in = {{4, 2}}; + math0.fill_in = {{3, 2}}; // Sub graph / math model 1 MathModelTopology math1; @@ -395,7 +395,7 @@ TEST_CASE("Test cycle reorder") { // result TopologicalComponentToMathCoupling comp_coup_ref{}; comp_coup_ref.node = {{0, 0}, {0, 3}, {0, 1}, {0, 2}, {0, 4}, {0, 5}, {0, 6}}; - std::vector const fill_in_ref{{5, 6}, {3, 6}, {6, 4}}; + std::vector const fill_in_ref{{5, 6}, {2, 6}, {6, 4}}; Topology topo{comp_topo, comp_conn}; auto pair = topo.build_topology(); From f9d42163f5e8654c658184997a5595bafc006453 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Fri, 22 Mar 2024 08:27:25 +0100 Subject: [PATCH 36/47] capturing structured bindings will be supported starting Clang16 Signed-off-by: Martijn Govers --- .../power_grid_model/include/power_grid_model/topology.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index f62b31853..78dac0fa3 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -327,7 +327,7 @@ class Topology { auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); const auto n_non_cyclic_nodes = static_cast(dfs_node.size()); - auto const permuted_node_idx = [n_non_cyclic_nodes, &reordered](Idx node_idx) { + auto const permuted_node_idx = [n_non_cyclic_nodes, &reordered = reordered](Idx node_idx) { return n_non_cyclic_nodes + narrow_cast(std::distance(reordered.begin(), std::ranges::find(reordered, node_idx))); }; From d6293a351be427095c87505c435f42bee02c7a84 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Fri, 22 Mar 2024 08:42:44 +0100 Subject: [PATCH 37/47] fix sonar cloud Signed-off-by: Martijn Govers --- .../power_grid_model/include/power_grid_model/topology.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 78dac0fa3..ac30029af 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -327,9 +327,9 @@ class Topology { auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); const auto n_non_cyclic_nodes = static_cast(dfs_node.size()); - auto const permuted_node_idx = [n_non_cyclic_nodes, &reordered = reordered](Idx node_idx) { + auto const permuted_node_idx = [n_non_cyclic_nodes, &reordered_ = reordered](Idx node_idx) { return n_non_cyclic_nodes + - narrow_cast(std::distance(reordered.begin(), std::ranges::find(reordered, node_idx))); + narrow_cast(std::distance(reordered_.begin(), std::ranges::find(reordered_, node_idx))); }; std::ranges::copy(reordered, std::back_inserter(dfs_node)); From 49b87a047d446c99b50303017ce095490295e3e9 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Mon, 17 Jun 2024 14:20:24 +0200 Subject: [PATCH 38/47] minor fix to the fictional grid Signed-off-by: Martijn Govers --- tests/benchmark_cpp/fictional_grid_generator.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/benchmark_cpp/fictional_grid_generator.hpp b/tests/benchmark_cpp/fictional_grid_generator.hpp index 25da2beb7..60393a010 100644 --- a/tests/benchmark_cpp/fictional_grid_generator.hpp +++ b/tests/benchmark_cpp/fictional_grid_generator.hpp @@ -116,7 +116,9 @@ class FictionalGridGenerator { option_.n_mv_feeder = option_.n_lv_grid / option_.n_node_per_mv_feeder + 1; } total_mv_connection = option_.n_mv_feeder * option_.n_node_per_mv_feeder; - option_.ratio_lv_grid = static_cast(option_.n_lv_grid) / static_cast(total_mv_connection); + option_.ratio_lv_grid = total_mv_connection > 0 + ? static_cast(option_.n_lv_grid) / static_cast(total_mv_connection) + : 1.0; // each mv feeder 10 MVA, each transformer 60 MVA, scaled up by 10% option_.n_parallel_hv_mv_transformer = static_cast(static_cast(option.n_mv_feeder) * 10.0 * 1.1 / 60.0) + 1; From d38417b864a8c744e0cd4e17f1b8a68f72e46fe0 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Mon, 17 Jun 2024 15:22:14 +0200 Subject: [PATCH 39/47] remove TODO Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordering.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index 4ffbe9866..6ed1703e6 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -141,7 +141,7 @@ inline IdxVector remove_vertices_update_degrees(Idx const u, std::map Date: Tue, 18 Jun 2024 12:05:39 +0200 Subject: [PATCH 40/47] minor Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordering.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index 6ed1703e6..49f837757 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -84,11 +84,11 @@ inline std::vector> check_indistguishable(Idx co auto l = adj(u, d); auto lu = l; lu.push_back(u); + std::ranges::sort(lu); for (auto const& v : l) { auto lv = adj(v, d); lv.push_back(v); - std::ranges::sort(lu); std::ranges::sort(lv); if (lu == lv) { rl.push_back(v); From b38e813a4d084bd444d9a6c2ee8de54214d1472f Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 18 Jun 2024 14:07:42 +0200 Subject: [PATCH 41/47] minor improvements Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordering.hpp | 2 +- .../power_grid_model/include/power_grid_model/topology.hpp | 3 +-- tests/cpp_unit_tests/test_sparse_ordering.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index 49f837757..8d47463f0 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -172,7 +172,7 @@ inline IdxVector remove_vertices_update_degrees(Idx const u, std::map>> minimum_degree_ordering(std::map& d) { +inline std::pair>> minimum_degree_ordering(std::map d) { auto data = detail::comp_size_degrees_graph(d); auto& [n, dgd] = data[0]; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index ac30029af..88b82af6c 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -15,7 +15,6 @@ #include #include #include -#include // build topology of the grid // divide grid into several math models @@ -324,7 +323,7 @@ class Topology { } } - auto [reordered, fills] = minimum_degree_ordering(unique_nearest_neighbours); + auto [reordered, fills] = minimum_degree_ordering(std::move(unique_nearest_neighbours)); const auto n_non_cyclic_nodes = static_cast(dfs_node.size()); auto const permuted_node_idx = [n_non_cyclic_nodes, &reordered_ = reordered](Idx node_idx) { diff --git a/tests/cpp_unit_tests/test_sparse_ordering.cpp b/tests/cpp_unit_tests/test_sparse_ordering.cpp index d88328ff6..16c81eb43 100644 --- a/tests/cpp_unit_tests/test_sparse_ordering.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordering.cpp @@ -20,7 +20,7 @@ TEST_CASE("Test sparse ordering") { {4, {6, 8}}, {6, {7, 8, 9}}, {7, {8, 9}}, {8, {9}}}; auto const start = std::chrono::high_resolution_clock::now(); - auto const [alpha, fills] = power_grid_model::minimum_degree_ordering(graph); + auto const [alpha, fills] = power_grid_model::minimum_degree_ordering(std::move(graph)); auto const stop = std::chrono::high_resolution_clock::now(); auto const duration = duration_cast(stop - start); From c97877470b46ab10705e5f2888b6755aaef2cfb3 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 18 Jun 2024 16:14:48 +0200 Subject: [PATCH 42/47] significant improvements to sparse ordering Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordering.hpp | 89 ++++++++----------- tests/benchmark_cpp/benchmark.cpp | 70 +++++++-------- tests/cpp_unit_tests/test_sparse_ordering.cpp | 2 +- tests/cpp_unit_tests/test_topology.cpp | 18 ++-- 4 files changed, 83 insertions(+), 96 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index 8d47463f0..ff847d6b2 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -7,6 +7,7 @@ #include "common/common.hpp" #include +#include #include #include #include @@ -14,63 +15,47 @@ namespace power_grid_model { namespace detail { -inline void remove_element_vector_pair(Idx u, std::vector>& dgd) { +inline void remove_element_degree(Idx u, std::vector>& dgd) { std::erase_if(dgd, [u](auto const& v) { return v.first == u; }); } -inline void set_element_vector_pair(Idx u, Idx v, std::vector>& dgd) { +inline void set_element_degree(Idx u, Idx degree, std::vector>& dgd) { if (auto it = std::ranges::find_if(dgd, [u](auto const& value) { return value.first == u; }); it != dgd.end()) { - it->second = v; + it->second = degree; } } -inline IdxVector adj(Idx const u, std::map const& d) { - IdxVector l; - - for (const auto& [k, adjacent] : d) { - if (k == u) { - l.insert(l.end(), adjacent.cbegin(), adjacent.cend()); - } else if (std::ranges::find(adjacent, u) != adjacent.cend()) { - l.push_back(k); - } +inline Idx num_adjacent(Idx const u, std::map const& d) { + if (auto it = d.find(u); it != d.end()) { + return static_cast(it->second.size()); } - - return l; + return 0; } +inline IdxVector const& adj(Idx const u, std::map const& d) { return d.at(u); } + inline std::vector>>> comp_size_degrees_graph(std::map const& d) { std::vector> dd; IdxVector v; - Idx n = 0; for (auto const& [k, adjacent] : d) { - if (std::ranges::find(v, k) == v.end()) { - ++n; - v.push_back(k); - dd.emplace_back(k, adj(k, d).size()); - } - for (Idx const e : adjacent) { - if (std::ranges::find(v, e) == v.end()) { - ++n; - v.push_back(e); - dd.emplace_back(e, adj(e, d).size()); - } - } + v.push_back(k); + dd.emplace_back(k, adjacent.size()); } std::ranges::sort(dd); - return {{n, dd}}; + return {{d.size(), dd}}; } inline std::map make_clique(IdxVector& l) { std::map d; - for (Idx i = 0; i < static_cast(l.size()) - 1; i++) { - Idx const idx = i + 1; - IdxVector sl(l.size() - idx); - std::copy(l.begin() + idx, l.end(), sl.begin()); + for (Idx i = 0; i < static_cast(l.size()); i++) { + IdxVector sl(l.size() - 1); + std::copy(l.begin(), l.begin() + i, sl.begin()); + std::copy(l.begin() + i + 1, l.end(), sl.begin() + i); d[l[i]] = std::move(sl); } @@ -103,10 +88,6 @@ inline bool in_graph(std::pair const& e, std::map cons edges_it != d.cend() && std::ranges::find(edges_it->second, e.second) != edges_it->second.cend()) { return true; } - if (auto edges_it = d.find(e.second); - edges_it != d.cend() && std::ranges::find(edges_it->second, e.first) != edges_it->second.cend()) { - return true; - } return false; } @@ -125,7 +106,7 @@ inline IdxVector remove_vertices_update_degrees(Idx const u, std::mapsecond); - } else if (auto e_it = d.find(e); e_it != d.end()) { - add_element(e, k, e_it->second); - } else { + if (it == d.end()) { std::tie(it, std::ignore) = d.try_emplace(k); - add_element(k, e, it->second); } + it->second.push_back(e); + d[e].push_back(k); + fills.emplace_back(k, e); } } } for (auto const& e : nbs) { - set_element_vector_pair(e, static_cast(adj(e, d).size()), dgd); + set_element_degree(e, num_adjacent(e, d), dgd); } return alpha; } } // namespace detail -inline std::pair>> minimum_degree_ordering(std::map d) { +inline std::pair>> minimum_degree_ordering(std::map d_) { + // make symmetric + auto d = d_; + for (auto& [k, adjacent] : d_) { + for (auto a : adjacent) { + d[a].push_back(k); + } + } + for (auto& [k, adjacent] : d) { + std::ranges::sort(adjacent); + } + auto data = detail::comp_size_degrees_graph(d); auto& [n, dgd] = data[0]; @@ -183,7 +168,9 @@ inline std::pair>> minimum_degree_ord Idx const u = get<0>(*std::ranges::min_element(dgd, [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); alpha.push_back(u); - if ((d.size() == 1) && d.begin()->second.size() == 1) { + if (d.size() == 2) { + assert(d.begin()->second.size() == 1); + Idx const from = d.begin()->first; Idx const to = d.begin()->second[0]; alpha.push_back(alpha.back() == from ? to : from); diff --git a/tests/benchmark_cpp/benchmark.cpp b/tests/benchmark_cpp/benchmark.cpp index 9065a0d5d..748c11633 100644 --- a/tests/benchmark_cpp/benchmark.cpp +++ b/tests/benchmark_cpp/benchmark.cpp @@ -72,21 +72,21 @@ struct PowerGridBenchmark { run_pf(calculation_method, info); } print(info); - info.clear(); - { - std::cout << "\n*****Run without initialization*****\n"; - Timer const t_total(info, 0000, "Total"); - run_pf(calculation_method, info); - } - print(info); - - if (batch_size > 0) { - info.clear(); - std::cout << "\n*****Run with batch calculation*****\n"; - Timer const t_total(info, 0000, "Total"); - run_pf(calculation_method, info, batch_size, threading); - } - print(info); + // info.clear(); + // { + // std::cout << "\n*****Run without initialization*****\n"; + // Timer const t_total(info, 0000, "Total"); + // run_pf(calculation_method, info); + // } + // print(info); + + // if (batch_size > 0) { + // info.clear(); + // std::cout << "\n*****Run with batch calculation*****\n"; + // Timer const t_total(info, 0000, "Total"); + // run_pf(calculation_method, info, batch_size, threading); + // } + // print(info); std::cout << "\n\n"; } @@ -114,41 +114,41 @@ int main(int /* argc */, char** /* argv */) { power_grid_model::benchmark::PowerGridBenchmark benchmarker{}; power_grid_model::benchmark::Option option{}; -#ifndef NDEBUG - option.n_node_total_specified = 200; - option.n_mv_feeder = 3; - option.n_node_per_mv_feeder = 6; - option.n_lv_feeder = 2; - option.n_connection_per_lv_feeder = 4; - power_grid_model::Idx constexpr batch_size = 10; -#else - option.n_node_total_specified = 1500; +// #ifndef NDEBUG +// option.n_node_total_specified = 200; +// option.n_mv_feeder = 3; +// option.n_node_per_mv_feeder = 6; +// option.n_lv_feeder = 2; +// option.n_connection_per_lv_feeder = 4; +// power_grid_model::Idx constexpr batch_size = 10; +// #else + option.n_node_total_specified = 15000; option.n_mv_feeder = 20; option.n_node_per_mv_feeder = 10; option.n_lv_feeder = 10; option.n_connection_per_lv_feeder = 40; power_grid_model::Idx constexpr batch_size = 1000; -#endif +// #endif // radial option.has_mv_ring = false; option.has_lv_ring = false; - benchmarker.run_benchmark(option, newton_raphson, batch_size); - benchmarker.run_benchmark(option, newton_raphson, batch_size, 6); - benchmarker.run_benchmark(option, linear); - benchmarker.run_benchmark(option, iterative_current); - benchmarker.run_benchmark(option, newton_raphson); - benchmarker.run_benchmark(option, linear); + // benchmarker.run_benchmark(option, newton_raphson, batch_size); + // benchmarker.run_benchmark(option, newton_raphson, batch_size, 6); + // benchmarker.run_benchmark(option, linear); + // benchmarker.run_benchmark(option, iterative_current); + // benchmarker.run_benchmark(option, newton_raphson); + // benchmarker.run_benchmark(option, linear); // benchmarker.run_benchmark(option, iterative_current); // with meshed ring option.has_mv_ring = true; option.has_lv_ring = true; - benchmarker.run_benchmark(option, newton_raphson); + // benchmarker.run_benchmark(option, newton_raphson); benchmarker.run_benchmark(option, linear); - benchmarker.run_benchmark(option, iterative_current); - benchmarker.run_benchmark(option, newton_raphson); - benchmarker.run_benchmark(option, linear); + // benchmarker.run_benchmark(option, iterative_current); + // benchmarker.run_benchmark(option, newton_raphson); + // benchmarker.run_benchmark(option, linear); // benchmarker.run_benchmark(option, iterative_current); return 0; } diff --git a/tests/cpp_unit_tests/test_sparse_ordering.cpp b/tests/cpp_unit_tests/test_sparse_ordering.cpp index 16c81eb43..99c15fd91 100644 --- a/tests/cpp_unit_tests/test_sparse_ordering.cpp +++ b/tests/cpp_unit_tests/test_sparse_ordering.cpp @@ -27,6 +27,6 @@ TEST_CASE("Test sparse ordering") { std::cout << "Time taken by function: " << duration.count() << " microseconds\n"; CHECK(alpha == std::vector{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}); - CHECK(fills == std::vector>{{3, 5}, {4, 5}, {8, 5}, {6, 5}, {7, 5}}); + CHECK(fills == std::vector>{{3, 5}, {4, 5}, {5, 8}, {5, 6}, {5, 7}}); } } diff --git a/tests/cpp_unit_tests/test_topology.cpp b/tests/cpp_unit_tests/test_topology.cpp index 4b707415a..6a5e8e3a6 100644 --- a/tests/cpp_unit_tests/test_topology.cpp +++ b/tests/cpp_unit_tests/test_topology.cpp @@ -179,7 +179,7 @@ TEST_CASE("Test topology") { {0, 1}, // Topological node 0 has become node 4 in mathematical model (group) 0 {0, 2}, {0, 0}, - {0, 3}, + {0, 4}, // 4 5 6 {1, 2}, // Topological node 4 has become node 2 in mathematical model (group) 1 {1, 3}, @@ -192,7 +192,7 @@ TEST_CASE("Test topology") { {-1, -1}, {-1, -1}, // b0, b1, b2 - {0, 4}, // Branch3 b0 is replaced by a virtual node 3, in mathematical model 0 + {0, 3}, // Branch3 b0 is replaced by a virtual node 3, in mathematical model 0 {-1, -1}, {1, 1}}; comp_coup_ref.source = { @@ -244,12 +244,12 @@ TEST_CASE("Test topology") { MathModelTopology math0; math0.slack_bus = 1; math0.sources_per_bus = {from_dense, {1}, 5}; - math0.branch_bus_idx = {{1, 2}, {1, 3}, {3, -1}, {-1, 0}, {2, 4}, {3, 4}, {0, 4}}; - math0.phase_shift = {0.0, 0.0, 0.0, -1.0, 0.0}; + math0.branch_bus_idx = {{1, 2}, {1, 4}, {4, -1}, {-1, 0}, {2, 3}, {4, 3}, {0, 3}}; + math0.phase_shift = {0.0, 0.0, 0.0, 0.0, -1.0}; math0.load_gens_per_bus = {from_dense, {1, 2}, 5}; math0.load_gen_type = {LoadGenType::const_pq, LoadGenType::const_y}; - math0.shunts_per_bus = {from_dense, {3}, 5}; - math0.voltage_sensors_per_bus = {from_dense, {0, 0, 2, 3}, 5}; + math0.shunts_per_bus = {from_dense, {4}, 5}; + math0.voltage_sensors_per_bus = {from_dense, {0, 0, 2, 4}, 5}; math0.power_sensors_per_bus = {from_dense, {}, 5}; math0.power_sensors_per_source = {from_dense, {}, 1}; math0.power_sensors_per_shunt = {from_dense, {}, 1}; @@ -259,7 +259,7 @@ TEST_CASE("Test topology") { // sensor 0 is connected to branch 0 // sensor 1 and 2 are connected to branch 1 math0.power_sensors_per_branch_to = {from_dense, {0, 1, 1}, 7}; - math0.fill_in = {{3, 2}}; + math0.fill_in = {{2, 4}}; // Sub graph / math model 1 MathModelTopology math1; @@ -349,7 +349,7 @@ TEST_CASE("Test cycle reorder") { // result TopologicalComponentToMathCoupling comp_coup_ref{}; comp_coup_ref.node = {{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}}; - std::vector const fill_in_ref{{5, 3}, {4, 5}, {5, 8}, {6, 5}, {5, 7}}; + std::vector const fill_in_ref{{3, 5}, {4, 5}, {5, 8}, {5, 6}, {5, 7}}; Topology topo{comp_topo, comp_conn}; auto pair = topo.build_topology(); @@ -395,7 +395,7 @@ TEST_CASE("Test cycle reorder") { // result TopologicalComponentToMathCoupling comp_coup_ref{}; comp_coup_ref.node = {{0, 0}, {0, 3}, {0, 1}, {0, 2}, {0, 4}, {0, 5}, {0, 6}}; - std::vector const fill_in_ref{{5, 6}, {2, 6}, {6, 4}}; + std::vector const fill_in_ref{{5, 6}, {2, 6}, {4, 6}}; Topology topo{comp_topo, comp_conn}; auto pair = topo.build_topology(); From 36afc79db8cd04402db2c28c4cdd28ee7e3848f3 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 19 Jun 2024 10:47:57 +0200 Subject: [PATCH 43/47] major speedup in obtaining minimum degree vertex Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordering.hpp | 70 ++++++++++++++----- tests/benchmark_cpp/benchmark.cpp | 20 +++--- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index ff847d6b2..9c189e590 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -8,23 +8,59 @@ #include #include +#include #include +#include #include #include namespace power_grid_model { namespace detail { -inline void remove_element_degree(Idx u, std::vector>& dgd) { - std::erase_if(dgd, [u](auto const& v) { return v.first == u; }); -} +class DegreeLookup { + public: + void set(Idx u, Idx degree) { + if (auto it = vertex_to_degree.find(u); it != vertex_to_degree.end()) { + degrees_to_vertex[it->second].erase(u); + it->second = degree; + } else { + vertex_to_degree.try_emplace(u, degree); + } + degrees_to_vertex[degree].insert(u); + } -inline void set_element_degree(Idx u, Idx degree, std::vector>& dgd) { - if (auto it = std::ranges::find_if(dgd, [u](auto const& value) { return value.first == u; }); it != dgd.end()) { - it->second = degree; + void erase(Idx u) { + auto vertex_it = vertex_to_degree.find(u); + if (vertex_it == vertex_to_degree.end()) { + return; + } + Idx const degree = vertex_it->second; + vertex_to_degree.erase(vertex_it); + + if (auto degree_it = degrees_to_vertex.find(degree); degree_it != degrees_to_vertex.end()) { + degree_it->second.erase(u); + if (degree_it->second.empty()) { + degrees_to_vertex.erase(degree_it); + } + } } + + friend auto min_element(DegreeLookup const& dgd); + + private: + std::map> degrees_to_vertex; + std::map vertex_to_degree; +}; + +inline auto min_element(DegreeLookup const& dgd) { + Idx const vertex = *dgd.degrees_to_vertex.begin()->second.begin(); + return dgd.vertex_to_degree.find(vertex); } +inline void remove_element_degree(Idx u, DegreeLookup& dgd) { dgd.erase(u); } + +inline void set_element_degree(Idx u, Idx degree, DegreeLookup& dgd) { dgd.set(u, degree); } + inline Idx num_adjacent(Idx const u, std::map const& d) { if (auto it = d.find(u); it != d.end()) { return static_cast(it->second.size()); @@ -34,18 +70,15 @@ inline Idx num_adjacent(Idx const u, std::map const& d) { inline IdxVector const& adj(Idx const u, std::map const& d) { return d.at(u); } -inline std::vector>>> -comp_size_degrees_graph(std::map const& d) { - std::vector> dd; +inline std::vector> comp_size_degrees_graph(std::map const& d) { + DegreeLookup dd; IdxVector v; for (auto const& [k, adjacent] : d) { v.push_back(k); - dd.emplace_back(k, adjacent.size()); + set_element_degree(k, adjacent.size(), dd); } - std::ranges::sort(dd); - return {{d.size(), dd}}; } @@ -91,8 +124,7 @@ inline bool in_graph(std::pair const& e, std::map cons return false; } -inline IdxVector remove_vertices_update_degrees(Idx const u, std::map& d, - std::vector>& dgd, +inline IdxVector remove_vertices_update_degrees(Idx const u, std::map& d, DegreeLookup& dgd, std::vector>& fills) { std::vector> nbsrl = check_indistguishable(u, d); auto& [nbs, rl] = nbsrl[0]; @@ -108,9 +140,10 @@ inline IdxVector remove_vertices_update_degrees(Idx const u, std::map>> minimum_degree_ord std::vector> fills; for (Idx k = 0; k < n; ++k) { - Idx const u = - get<0>(*std::ranges::min_element(dgd, [](auto lhs, auto rhs) { return get<1>(lhs) < get<1>(rhs); })); + Idx const u = get<0>(*detail::min_element(dgd)); alpha.push_back(u); if (d.size() == 2) { assert(d.begin()->second.size() == 1); diff --git a/tests/benchmark_cpp/benchmark.cpp b/tests/benchmark_cpp/benchmark.cpp index 748c11633..62fbb6fb4 100644 --- a/tests/benchmark_cpp/benchmark.cpp +++ b/tests/benchmark_cpp/benchmark.cpp @@ -114,21 +114,21 @@ int main(int /* argc */, char** /* argv */) { power_grid_model::benchmark::PowerGridBenchmark benchmarker{}; power_grid_model::benchmark::Option option{}; -// #ifndef NDEBUG -// option.n_node_total_specified = 200; -// option.n_mv_feeder = 3; -// option.n_node_per_mv_feeder = 6; -// option.n_lv_feeder = 2; -// option.n_connection_per_lv_feeder = 4; -// power_grid_model::Idx constexpr batch_size = 10; -// #else - option.n_node_total_specified = 15000; + // #ifndef NDEBUG + // option.n_node_total_specified = 200; + // option.n_mv_feeder = 3; + // option.n_node_per_mv_feeder = 6; + // option.n_lv_feeder = 2; + // option.n_connection_per_lv_feeder = 4; + // power_grid_model::Idx constexpr batch_size = 10; + // #else + option.n_node_total_specified = 150000; option.n_mv_feeder = 20; option.n_node_per_mv_feeder = 10; option.n_lv_feeder = 10; option.n_connection_per_lv_feeder = 40; power_grid_model::Idx constexpr batch_size = 1000; -// #endif + // #endif // radial option.has_mv_ring = false; From 74b9d5299638cfa23bdaf022df0480be6f8329e4 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 19 Jun 2024 13:19:17 +0200 Subject: [PATCH 44/47] improve current most expensive step Signed-off-by: Martijn Govers --- .../power_grid_model/sparse_ordering.hpp | 17 ++++++++++------- .../include/power_grid_model/topology.hpp | 12 ++++++------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index 9c189e590..0b7c063d2 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -20,9 +20,9 @@ namespace detail { class DegreeLookup { public: void set(Idx u, Idx degree) { - if (auto it = vertex_to_degree.find(u); it != vertex_to_degree.end()) { - degrees_to_vertex[it->second].erase(u); - it->second = degree; + if (auto degree_it = vertex_to_degree.find(u); degree_it != vertex_to_degree.end()) { + remove_degree(u, degree_it->second); + degree_it->second = degree; } else { vertex_to_degree.try_emplace(u, degree); } @@ -36,7 +36,13 @@ class DegreeLookup { } Idx const degree = vertex_it->second; vertex_to_degree.erase(vertex_it); + remove_degree(u, degree); + } + + friend auto min_element(DegreeLookup const& dgd); + private: + void remove_degree(Idx u, Idx degree) { if (auto degree_it = degrees_to_vertex.find(degree); degree_it != degrees_to_vertex.end()) { degree_it->second.erase(u); if (degree_it->second.empty()) { @@ -45,11 +51,8 @@ class DegreeLookup { } } - friend auto min_element(DegreeLookup const& dgd); - - private: - std::map> degrees_to_vertex; std::map vertex_to_degree; + std::map> degrees_to_vertex; }; inline auto min_element(DegreeLookup const& dgd) { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp index 88b82af6c..f5d019796 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/topology.hpp @@ -326,15 +326,15 @@ class Topology { auto [reordered, fills] = minimum_degree_ordering(std::move(unique_nearest_neighbours)); const auto n_non_cyclic_nodes = static_cast(dfs_node.size()); - auto const permuted_node_idx = [n_non_cyclic_nodes, &reordered_ = reordered](Idx node_idx) { - return n_non_cyclic_nodes + - narrow_cast(std::distance(reordered_.begin(), std::ranges::find(reordered_, node_idx))); - }; + std::map permuted_node_indices; + for (Idx idx = 0; idx < static_cast(reordered.size()); ++idx) { + permuted_node_indices[reordered[idx]] = n_non_cyclic_nodes + idx; + } std::ranges::copy(reordered, std::back_inserter(dfs_node)); for (auto [from, to] : fills) { - auto from_reordered = permuted_node_idx(from); - auto to_reordered = permuted_node_idx(to); + auto from_reordered = permuted_node_indices[from]; + auto to_reordered = permuted_node_indices[to]; fill_in.push_back({from_reordered, to_reordered}); } From 986a29473a92298f498c7e16512a3164f3c90c4f Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 19 Jun 2024 14:51:39 +0200 Subject: [PATCH 45/47] fix ci Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordering.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index 0b7c063d2..baf66de88 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -79,7 +79,7 @@ inline std::vector> comp_size_degrees_graph(std::ma for (auto const& [k, adjacent] : d) { v.push_back(k); - set_element_degree(k, adjacent.size(), dd); + set_element_degree(k, static_cast(adjacent.size()), dd); } return {{d.size(), dd}}; @@ -182,16 +182,16 @@ inline IdxVector remove_vertices_update_degrees(Idx const u, std::map>> minimum_degree_ordering(std::map d_) { +inline std::pair>> minimum_degree_ordering(std::map d) { // make symmetric - auto d = d_; - for (auto& [k, adjacent] : d_) { + for (auto& [k, adjacent] : d) { for (auto a : adjacent) { d[a].push_back(k); } } for (auto& [k, adjacent] : d) { - std::ranges::sort(adjacent); + std::set const unique_sorted_adjacent{adjacent.begin(), adjacent.end()}; + adjacent = IdxVector{unique_sorted_adjacent.begin(), unique_sorted_adjacent.end()}; } auto data = detail::comp_size_degrees_graph(d); From cd55f73125817310e13ba257ab0adcf27511b093 Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 19 Jun 2024 15:00:11 +0200 Subject: [PATCH 46/47] fix Signed-off-by: Martijn Govers --- tests/benchmark_cpp/benchmark.cpp | 70 +++++++++++++++---------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/benchmark_cpp/benchmark.cpp b/tests/benchmark_cpp/benchmark.cpp index 62fbb6fb4..9065a0d5d 100644 --- a/tests/benchmark_cpp/benchmark.cpp +++ b/tests/benchmark_cpp/benchmark.cpp @@ -72,21 +72,21 @@ struct PowerGridBenchmark { run_pf(calculation_method, info); } print(info); - // info.clear(); - // { - // std::cout << "\n*****Run without initialization*****\n"; - // Timer const t_total(info, 0000, "Total"); - // run_pf(calculation_method, info); - // } - // print(info); - - // if (batch_size > 0) { - // info.clear(); - // std::cout << "\n*****Run with batch calculation*****\n"; - // Timer const t_total(info, 0000, "Total"); - // run_pf(calculation_method, info, batch_size, threading); - // } - // print(info); + info.clear(); + { + std::cout << "\n*****Run without initialization*****\n"; + Timer const t_total(info, 0000, "Total"); + run_pf(calculation_method, info); + } + print(info); + + if (batch_size > 0) { + info.clear(); + std::cout << "\n*****Run with batch calculation*****\n"; + Timer const t_total(info, 0000, "Total"); + run_pf(calculation_method, info, batch_size, threading); + } + print(info); std::cout << "\n\n"; } @@ -114,41 +114,41 @@ int main(int /* argc */, char** /* argv */) { power_grid_model::benchmark::PowerGridBenchmark benchmarker{}; power_grid_model::benchmark::Option option{}; - // #ifndef NDEBUG - // option.n_node_total_specified = 200; - // option.n_mv_feeder = 3; - // option.n_node_per_mv_feeder = 6; - // option.n_lv_feeder = 2; - // option.n_connection_per_lv_feeder = 4; - // power_grid_model::Idx constexpr batch_size = 10; - // #else - option.n_node_total_specified = 150000; +#ifndef NDEBUG + option.n_node_total_specified = 200; + option.n_mv_feeder = 3; + option.n_node_per_mv_feeder = 6; + option.n_lv_feeder = 2; + option.n_connection_per_lv_feeder = 4; + power_grid_model::Idx constexpr batch_size = 10; +#else + option.n_node_total_specified = 1500; option.n_mv_feeder = 20; option.n_node_per_mv_feeder = 10; option.n_lv_feeder = 10; option.n_connection_per_lv_feeder = 40; power_grid_model::Idx constexpr batch_size = 1000; - // #endif +#endif // radial option.has_mv_ring = false; option.has_lv_ring = false; - // benchmarker.run_benchmark(option, newton_raphson, batch_size); - // benchmarker.run_benchmark(option, newton_raphson, batch_size, 6); - // benchmarker.run_benchmark(option, linear); - // benchmarker.run_benchmark(option, iterative_current); - // benchmarker.run_benchmark(option, newton_raphson); - // benchmarker.run_benchmark(option, linear); + benchmarker.run_benchmark(option, newton_raphson, batch_size); + benchmarker.run_benchmark(option, newton_raphson, batch_size, 6); + benchmarker.run_benchmark(option, linear); + benchmarker.run_benchmark(option, iterative_current); + benchmarker.run_benchmark(option, newton_raphson); + benchmarker.run_benchmark(option, linear); // benchmarker.run_benchmark(option, iterative_current); // with meshed ring option.has_mv_ring = true; option.has_lv_ring = true; - // benchmarker.run_benchmark(option, newton_raphson); + benchmarker.run_benchmark(option, newton_raphson); benchmarker.run_benchmark(option, linear); - // benchmarker.run_benchmark(option, iterative_current); - // benchmarker.run_benchmark(option, newton_raphson); - // benchmarker.run_benchmark(option, linear); + benchmarker.run_benchmark(option, iterative_current); + benchmarker.run_benchmark(option, newton_raphson); + benchmarker.run_benchmark(option, linear); // benchmarker.run_benchmark(option, iterative_current); return 0; } From ca040d566b132bfa352e3bf2a250916e5056bb9f Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Wed, 19 Jun 2024 15:25:12 +0200 Subject: [PATCH 47/47] resolve sonar cloud Signed-off-by: Martijn Govers --- .../include/power_grid_model/sparse_ordering.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp index baf66de88..41c9622fd 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/sparse_ordering.hpp @@ -143,7 +143,7 @@ inline IdxVector remove_vertices_update_degrees(Idx const u, std::map>> minimum_degree_ordering(std::map d) { // make symmetric - for (auto& [k, adjacent] : d) { - for (auto a : adjacent) { - d[a].push_back(k); + for (auto const& [k, adjacent] : d) { + for (auto e : adjacent) { + d[e].push_back(k); } } for (auto& [k, adjacent] : d) {