Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update topology to not necessarily go through sparse mapping #426

Merged
merged 37 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
a984196
add comments, add test, add wip on build_dense_mapping
Laurynas-Jagutis Nov 13, 2023
6316d18
Merge remote-tracking branch 'origin/main' into feature/update-topology
Laurynas-Jagutis Nov 13, 2023
a66b989
work in progress
Laurynas-Jagutis Nov 13, 2023
7ebe6f3
fix dense mapping indvector and reorder
Laurynas-Jagutis Nov 23, 2023
1830797
Merge remote-tracking branch 'origin/main' into feature/update-topology
Laurynas-Jagutis Nov 23, 2023
a63d8ec
fix narrowing conversion
Laurynas-Jagutis Nov 23, 2023
404c3a5
remove assertion
Laurynas-Jagutis Nov 23, 2023
ac073bb
comment out an assert
Laurynas-Jagutis Nov 23, 2023
7a3e00b
Merge branch 'main' into feature/update-topology
mgovers Nov 24, 2023
e77692c
update test, combine two loops
Laurynas-Jagutis Nov 24, 2023
3b0ae2e
Merge branch 'feature/update-topology' of https://github.com/PowerGri…
Laurynas-Jagutis Nov 24, 2023
dee666b
Merge remote-tracking branch 'origin/main' into feature/update-topology
Laurynas-Jagutis Nov 24, 2023
6dccb02
wip
Laurynas-Jagutis Nov 28, 2023
c924777
finished the new sorting, works well
Laurynas-Jagutis Nov 29, 2023
0984153
setup if statement, count operations
Laurynas-Jagutis Nov 30, 2023
2f89787
Merge remote-tracking branch 'origin/main' into feature/update-topology
Laurynas-Jagutis Nov 30, 2023
084e463
benchmarks
Laurynas-Jagutis Dec 7, 2023
0d6dcf8
Merge remote-tracking branch 'origin/main' into feature/update-topology
Laurynas-Jagutis Dec 7, 2023
a6404da
almost finished full script
Laurynas-Jagutis Dec 13, 2023
771a20f
finish script, obtain results
Laurynas-Jagutis Dec 14, 2023
601a344
reverse the idxvector
Laurynas-Jagutis Dec 15, 2023
43a1531
Merge remote-tracking branch 'origin/main' into feature/update-topology
Laurynas-Jagutis Dec 15, 2023
2c85fce
hardcode, remove benchmark, remove comments
Laurynas-Jagutis Dec 15, 2023
9dce76c
cast a value to Idx
Laurynas-Jagutis Dec 15, 2023
17e878d
possible fixes for failing checks
Laurynas-Jagutis Dec 15, 2023
70c876b
possible fixes for failing checks2
Laurynas-Jagutis Dec 15, 2023
3f39f43
create a test for comparison sort
Laurynas-Jagutis Dec 15, 2023
c3daedd
create a second test
Laurynas-Jagutis Dec 15, 2023
225a6a9
Merge branch 'main' into feature/update-topology
mgovers Dec 18, 2023
ab30c76
resolve comments
mgovers Dec 19, 2023
194195a
resolve remaining comments
mgovers Dec 19, 2023
aa36ef0
implement do not go via sparse when dense mapping
mgovers Dec 19, 2023
ed83f7f
cleanup
mgovers Dec 19, 2023
34b3644
fix
mgovers Dec 19, 2023
9393ab1
iota not correctly implemented in libc++/11
mgovers Dec 19, 2023
bbfda49
fix
mgovers Dec 19, 2023
1fa03ce
Merge branch 'main' into feature/update-topology
mgovers Dec 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include <boost/range/adaptor/indexed.hpp>
#include <boost/range/counting_range.hpp>

#include <ranges>

/*
A data-structure for iterating through the indptr, ie. sparse representation of data.
Indptr can be eg: [0, 3, 6, 7]
Expand All @@ -39,7 +41,7 @@ namespace detail {
inline auto sparse_encode(IdxVector const& element_groups, Idx num_groups) {
IdxVector result(num_groups + 1);
auto next_group = std::begin(element_groups);
for (Idx group = 0; group < num_groups; group++) {
for (auto const group : boost::counting_range(Idx{0}, num_groups)) {
next_group = std::upper_bound(next_group, std::end(element_groups), group);
result[group + 1] = std::distance(std::begin(element_groups), next_group);
}
Expand All @@ -48,7 +50,7 @@ inline auto sparse_encode(IdxVector const& element_groups, Idx num_groups) {

inline auto sparse_decode(IdxVector const& indptr) {
auto result = IdxVector(indptr.back());
for (Idx const group : boost::counting_range(Idx{}, static_cast<Idx>(indptr.size()) - 1)) {
for (Idx const group : boost::counting_range(Idx{0}, static_cast<Idx>(indptr.size()) - 1)) {
std::fill(std::begin(result) + indptr[group], std::begin(result) + indptr[group + 1], group);
}
return result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: 2022 Contributors to the Power Grid Model project <dynamic.grid.calculation@alliander.com>
//
// SPDX-License-Identifier: MPL-2.0

#pragma once
#ifndef POWER_GRID_MODEL_INDEX_MAPPING_HPP
#define POWER_GRID_MODEL_INDEX_MAPPING_HPP

#include "grouped_index_vector.hpp"
#include "power_grid_model.hpp"

#include <ranges>

namespace power_grid_model {

struct SparseIndexMapping {
IdxVector indptr;
IdxVector reorder;
};

/// Sparse mapping technique
///
/// using counting sort: https://en.wikipedia.org/wiki/Counting_sort
/// Given a input idx array: idx_B_in_A[...] to couple an array of A and an array of B,
/// i.e. idx_B_in_A[i_A] = j_B.
///
/// For entry i_A in the array, idx_B_in_A[i_A] is the idx of B which couples the A object #i_A.
///
/// This sparse mapping tries to build a CSC sparse matrix so that
/// only entry (i, idx_B_in_A[i_A] = j_B) is filled with the sequence of A, i.e. #i_A.
///
/// In CSC format, the entries are ordered by the idx of B
/// therefore, in indptr, each range indptr[j_B:j_B+1]
/// represents the entries of A where B object #j_B is coupled.
///
/// The indices array is not interesting here.
/// The data array is original index of A. We call it re-order array.
/// This can be used to reorder A objects by the coupling of B idx.
///
/// Example.
/// For original idx_B_in_A == [3, 5, 2, 1, 1, 2]
/// size of A is 6
/// size of B is 7
/// Result matrix
/// indptr = [0, 0, 2, 4, 5, 5, 6, 6]
/// data/reorder = [3, 4, 2, 5, 0, 1]
/// to read:
/// nothing coupled to B 0
/// A 3, 4 coupled to B 1
/// A 2, 5 coupled to B 2
/// A 0 coupled to B 3
/// nothing coupled to B 4
/// A 1 coupled to B 5
/// nothing coupled to B 6
inline SparseIndexMapping build_sparse_mapping(IdxVector const& idx_B_in_A, Idx const n_B) {
using SparseEntry = std::pair<Idx, Idx>;

auto const n_A = static_cast<Idx>(idx_B_in_A.size());

std::vector<SparseEntry> entries(n_A);
std::ranges::transform(idx_B_in_A, boost::counting_range(Idx{0}, static_cast<Idx>(idx_B_in_A.size())),
entries.begin(), [](Idx j_B, Idx i_A) {
return SparseEntry{i_A, j_B};
});

SparseIndexMapping sparse_mapping;
sparse_mapping.indptr.resize(n_B + 1);
sparse_mapping.reorder.resize(n_A);

IdxVector counter(n_B, 0);
for (auto const& entry : entries) {
++counter[entry.second];
}

std::inclusive_scan(counter.cbegin(), counter.cend(), sparse_mapping.indptr.begin() + 1);

std::copy(sparse_mapping.indptr.cbegin() + 1, sparse_mapping.indptr.cend(), counter.begin());

for (auto it_entry = entries.crbegin(); it_entry != entries.crend(); ++it_entry) {
sparse_mapping.reorder[--counter[it_entry->second]] = it_entry->first;
}

assert(sparse_mapping.indptr[0] == 0);
assert(sparse_mapping.indptr.back() == n_A);
return sparse_mapping;
}

struct DenseIndexMapping {
IdxVector indvector;
IdxVector reorder;
};

namespace detail {

inline auto build_dense_mapping_comparison_sort(IdxVector const& idx_B_in_A, Idx const /* n_B */) {
using DenseEntry = std::pair<Idx, Idx>;

std::vector<DenseEntry> mapping_to_from;
mapping_to_from.reserve(idx_B_in_A.size());
std::ranges::transform(idx_B_in_A, boost::counting_range(Idx{0}, static_cast<Idx>(idx_B_in_A.size())),
std::back_inserter(mapping_to_from), [](Idx value, Idx orig_idx) {
return std::pair{value, orig_idx};
});

std::ranges::sort(mapping_to_from);

DenseIndexMapping result;
result.indvector.reserve(mapping_to_from.size());
result.reorder.reserve(mapping_to_from.size());
std::ranges::transform(mapping_to_from, std::back_inserter(result.indvector),
[](DenseEntry const& to_from) { return to_from.first; });

std::ranges::transform(mapping_to_from, std::back_inserter(result.reorder),
[](DenseEntry const& to_from) { return to_from.second; });

return result;
}

inline auto build_dense_mapping_counting_sort(IdxVector const& idx_B_in_A, Idx const n_B) {
auto sparse_result = build_sparse_mapping(idx_B_in_A, n_B);

return DenseIndexMapping{.indvector = sparse_decode(sparse_result.indptr),
.reorder = std::move(sparse_result.reorder)};
}

} // namespace detail

inline DenseIndexMapping build_dense_mapping(IdxVector const& idx_B_in_A, Idx const n_B) {
constexpr auto relative_complexity_prefactor = 1.0;

auto const n_A_ = static_cast<double>(idx_B_in_A.size());
auto const n_B_ = static_cast<double>(n_B);

if (n_A_ + n_B_ < relative_complexity_prefactor * n_A_ * log(n_A_)) {
return detail::build_dense_mapping_counting_sort(idx_B_in_A, n_B);
}
return detail::build_dense_mapping_comparison_sort(idx_B_in_A, n_B);
}

} // namespace power_grid_model

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

#include "../calculation_parameters.hpp"
#include "../power_grid_model.hpp"
#include "../sparse_mapping.hpp"
#include "../three_phase_tensor.hpp"

namespace power_grid_model {
Expand Down

This file was deleted.