diff --git a/src/fvm_multicell.hpp b/src/fvm_multicell.hpp index 72d22b25270bb1eb71a7a3307e39c2ad17bec62d..09e55a19f6efd8a2f0859e07673f7d345f3b2383 100644 --- a/src/fvm_multicell.hpp +++ b/src/fvm_multicell.hpp @@ -22,6 +22,7 @@ #include <util/debug.hpp> #include <util/meta.hpp> #include <util/partition.hpp> +#include <util/rangeutil.hpp> #include <util/span.hpp> #include <vector/include/Vector.hpp> @@ -67,7 +68,7 @@ public: void reset(); void deliver_event(target_handle h, value_type weight) { - mechanisms_[synapse_base_+h.first]->net_receive(h.second, weight); + mechanisms_[h.first]->net_receive(h.second, weight); } value_type detector_voltage(detector_handle h) const { @@ -300,6 +301,8 @@ void fvm_multicell<T, I>::initialize( Targets& target_handles, Probes& probe_handles) { + using util::assign_by; + using util::sort_by; using util::transform_view; using util::make_partition; using util::make_span; @@ -388,11 +391,7 @@ void fvm_multicell<T, I>::initialize( auto& map_entry = syn_mech_map[syn_mech_index]; size_type syn_comp = comp_ival.first+find_compartment_index(syn.location, graph); - size_type syn_index = map_entry.size(); map_entry.push_back(syn_comp); - - *target_hi++ = target_handle{syn_mech_index, syn_index}; - ++targets_count; } // normalize capacitance across cell @@ -434,11 +433,6 @@ void fvm_multicell<T, I>::initialize( } } - // confirm write-parameters were appropriately sized - EXPECTS(detectors_size==detectors_count); - EXPECTS(targets_size==targets_count); - EXPECTS(probes_size==probes_count); - // initalize matrix matrix_ = matrix_type(group_parent_index); @@ -461,12 +455,43 @@ void fvm_multicell<T, I>::initialize( synapse_base_ = mechanisms_.size(); for (const auto& syni: syn_mech_indices) { const auto& mech_name = syni.first; + size_type mech_index = mechanisms_.size(); + + auto comp_indices = syn_mech_map[syni.second]; + size_type n_indices = size(comp_indices); + + // sort indices but keep track of their original order for assigning + // target handles + + using index_pair = std::pair<cell_lid_type, size_type>; + auto compartment_index = [](index_pair x) { return x.first; }; + auto target_index = [](index_pair x) { return x.second; }; - auto mech = mechanism_catalogue::make(mech_name, voltage_, current_, syn_mech_map[syni.second]); + std::vector<index_pair> permute; + assign_by(permute, make_span(0u, n_indices), + [&](size_type i) { return index_pair(comp_indices[i], i); }); + + sort_by(permute, compartment_index); + assign_by(comp_indices, permute, compartment_index); + + // make target handles + std::vector<target_handle> handles(n_indices); + for (auto i: make_span(0u, n_indices)) { + handles[target_index(permute[i])] = {mech_index, i}; + } + target_hi = std::copy_n(std::begin(handles), n_indices, target_hi); + targets_count += n_indices; + + auto mech = mechanism_catalogue::make(mech_name, voltage_, current_, comp_indices); mech->set_areas(cv_areas_); mechanisms_.push_back(std::move(mech)); } + // confirm write-parameters were appropriately sized + EXPECTS(detectors_size==detectors_count); + EXPECTS(targets_size==targets_count); + EXPECTS(probes_size==probes_count); + // build the ion species for(auto ion : mechanisms::ion_kinds()) { // find the compartment indexes of all compartments that have a diff --git a/src/util/range.hpp b/src/util/range.hpp index df5625d0e6dc1e315e18d1e2e1a0e4b4ccecbd94..4fa8f25fe2650f126d9e1aac49716c9b08bf5e7a 100644 --- a/src/util/range.hpp +++ b/src/util/range.hpp @@ -152,60 +152,17 @@ range<U, V> make_range(const U& left, const V& right) { } template <typename Seq> -auto canonical_view(const Seq& s) -> +auto canonical_view(Seq& s) -> range<sentinel_iterator_t<decltype(std::begin(s)), decltype(std::end(s))>> { return {make_sentinel_iterator(std::begin(s), std::end(s)), make_sentinel_end(std::begin(s), std::end(s))}; } -/* - * Present a single item as a range - */ - -template <typename T> -range<T*> singleton_view(T& item) { - return {&item, &item+1}; -} - -template <typename T> -range<const T*> singleton_view(const T& item) { - return {&item, &item+1}; -} - -/* - * Range/container utility functions - */ - -template <typename Container, typename Seq> -Container& append(Container &c, const Seq& seq) { - auto canon = canonical_view(seq); - c.insert(c.end(), std::begin(canon), std::end(canon)); - return c; -} - -template <typename AssignableContainer, typename Seq> -AssignableContainer& assign(AssignableContainer& c, const Seq& seq) { - auto canon = canonical_view(seq); - c.assign(std::begin(canon), std::end(canon)); - return c; -} - template <typename Seq> -range<typename sequence_traits<Seq>::iterator_type, typename sequence_traits<Seq>::sentinel_type> -range_view(Seq& seq) { - return make_range(std::begin(seq), std::end(seq)); -} - -template < - typename Seq, - typename Iter = typename sequence_traits<Seq>::iterator_type, - typename Size = typename sequence_traits<Seq>::size_type -> -enable_if_t<is_forward_iterator<Iter>::value, range<Iter>> -subrange_view(Seq& seq, Size bi, Size ei) { - Iter b = std::next(std::begin(seq), bi); - Iter e = std::next(b, ei-bi); - return make_range(b, e); +auto canonical_view(const Seq& s) -> + range<sentinel_iterator_t<decltype(std::begin(s)), decltype(std::end(s))>> +{ + return {make_sentinel_iterator(std::begin(s), std::end(s)), make_sentinel_end(std::begin(s), std::end(s))}; } } // namespace util diff --git a/src/util/rangeutil.hpp b/src/util/rangeutil.hpp new file mode 100644 index 0000000000000000000000000000000000000000..95200b9c9a5b37c6a02bc236aa1d86bec8dac629 --- /dev/null +++ b/src/util/rangeutil.hpp @@ -0,0 +1,100 @@ +#pragma once + +/* + * Sequence and container utilities compatible + * with ranges. + */ + +#include <iterator> + +#include <util/meta.hpp> +#include <util/range.hpp> +#include <util/transform.hpp> + +namespace nest { +namespace mc { +namespace util { + +// Present a single item as a range + +template <typename T> +range<T*> singleton_view(T& item) { + return {&item, &item+1}; +} + +template <typename T> +range<const T*> singleton_view(const T& item) { + return {&item, &item+1}; +} + +// Non-owning views and subviews + +template <typename Seq> +range<typename sequence_traits<Seq>::iterator_type, typename sequence_traits<Seq>::sentinel_type> +range_view(Seq& seq) { + return make_range(std::begin(seq), std::end(seq)); +} + +template < + typename Seq, + typename Iter = typename sequence_traits<Seq>::iterator_type, + typename Size = typename sequence_traits<Seq>::size_type +> +enable_if_t<is_forward_iterator<Iter>::value, range<Iter>> +subrange_view(Seq& seq, Size bi, Size ei) { + Iter b = std::next(std::begin(seq), bi); + Iter e = std::next(b, ei-bi); + return make_range(b, e); +} + +// Append sequence to a container + +template <typename Container, typename Seq> +Container& append(Container &c, const Seq& seq) { + auto canon = canonical_view(seq); + c.insert(c.end(), std::begin(canon), std::end(canon)); + return c; +} + +// Assign sequence to a container + +template <typename AssignableContainer, typename Seq> +AssignableContainer& assign(AssignableContainer& c, const Seq& seq) { + auto canon = canonical_view(seq); + c.assign(std::begin(canon), std::end(canon)); + return c; +} + +// Assign sequence to a container with transform `proj` + +template <typename AssignableContainer, typename Seq, typename Proj> +AssignableContainer& assign_by(AssignableContainer& c, const Seq& seq, const Proj& proj) { + auto canon = canonical_view(transform_view(seq, proj)); + c.assign(std::begin(canon), std::end(canon)); + return c; +} + +// Sort in-place + +template <typename Seq> +void sort(Seq& seq) { + auto canon = canonical_view(seq); + std::sort(std::begin(canon), std::end(canon)); +} + +// Sort in-place by projection `proj` + +template <typename Seq, typename Proj> +void sort_by(Seq& seq, const Proj& proj) { + using value_type = typename sequence_traits<Seq>::value_type; + auto canon = canonical_view(seq); + + std::sort(std::begin(canon), std::end(canon), + [&proj](const value_type& a, const value_type& b) { + return proj(a) < proj(b); + }); +} + +} // namespace util +} // namespace mc +} // namespace nest diff --git a/src/util/sentinel.hpp b/src/util/sentinel.hpp index 8d08ecd41fe77f9c11ed08b8b539536792459c36..eebbfd2382359f388f84567701678713a177feee 100644 --- a/src/util/sentinel.hpp +++ b/src/util/sentinel.hpp @@ -179,6 +179,6 @@ sentinel_iterator_t<I, S> make_sentinel_end(const I& i, const S& s) { return sentinel_iterator_t<I, S>(s); } -} -} -} +} // namespace util +} // namespace mc +} // namespace nest diff --git a/tests/global_communication/test_mpi_gather_all.cpp b/tests/global_communication/test_mpi_gather_all.cpp index 50fbf4052da14b057c6ed003d51cfa8b13436e93..b5ecf73fa7088357e8bdbcc851d44f6f190d7b7b 100644 --- a/tests/global_communication/test_mpi_gather_all.cpp +++ b/tests/global_communication/test_mpi_gather_all.cpp @@ -7,7 +7,7 @@ #include <communication/mpi_global_policy.hpp> #include <communication/mpi.hpp> -#include <util/range.hpp> +#include <util/rangeutil.hpp> using namespace nest::mc; using namespace nest::mc::communication; diff --git a/tests/unit/test_cell_group.cpp b/tests/unit/test_cell_group.cpp index 9b3f6e6a0b13f7338558889e40e47d7fe7ed99c8..a18b9b881988dbadae86550c9649ca1c20146637 100644 --- a/tests/unit/test_cell_group.cpp +++ b/tests/unit/test_cell_group.cpp @@ -3,7 +3,7 @@ #include <cell_group.hpp> #include <common_types.hpp> #include <fvm_cell.hpp> -#include <util/range.hpp> +#include <util/rangeutil.hpp> #include "../test_common_cells.hpp" diff --git a/tests/unit/test_fvm.cpp b/tests/unit/test_fvm.cpp index 6d067182f972a0bc65147e8345f3043230d70d9a..45c038bf529f80e3339753662bf26e5a1762c168 100644 --- a/tests/unit/test_fvm.cpp +++ b/tests/unit/test_fvm.cpp @@ -5,7 +5,7 @@ #include <common_types.hpp> #include <cell.hpp> #include <fvm_cell.hpp> -#include <util/range.hpp> +#include <util/rangeutil.hpp> #include "../test_common_cells.hpp" #include "../test_util.hpp" diff --git a/tests/unit/test_fvm_multi.cpp b/tests/unit/test_fvm_multi.cpp index fbd4de99b91198128c6b3d0f0098f38f8440984d..df8356418705c51a865a9eb1cbcbf3ce5565c90e 100644 --- a/tests/unit/test_fvm_multi.cpp +++ b/tests/unit/test_fvm_multi.cpp @@ -5,7 +5,7 @@ #include <common_types.hpp> #include <cell.hpp> #include <fvm_multicell.hpp> -#include <util/range.hpp> +#include <util/rangeutil.hpp> #include "../test_util.hpp" #include "../test_common_cells.hpp" diff --git a/tests/unit/test_probe.cpp b/tests/unit/test_probe.cpp index cf7562c94fbf9ddcf33e16308d418dbdddd0ebf7..1a2d7f151fe7b347d154c709ddf14ea61e9b114a 100644 --- a/tests/unit/test_probe.cpp +++ b/tests/unit/test_probe.cpp @@ -3,7 +3,7 @@ #include <common_types.hpp> #include <cell.hpp> #include <fvm_cell.hpp> -#include <util/range.hpp> +#include <util/rangeutil.hpp> TEST(probe, instantiation) { diff --git a/tests/unit/test_range.cpp b/tests/unit/test_range.cpp index 118a4dc12393e74b74a62f84eee645d0399a490a..3cf2893e451c9674e85ba7ffa384a24e3a6eb6f5 100644 --- a/tests/unit/test_range.cpp +++ b/tests/unit/test_range.cpp @@ -14,6 +14,7 @@ #include <util/counter.hpp> #include <util/meta.hpp> #include <util/range.hpp> +#include <util/rangeutil.hpp> #include <util/sentinel.hpp> using namespace nest::mc; @@ -212,7 +213,6 @@ TYPED_TEST_P(counter_range, extreme_size) { auto range = util::make_range(l, r); EXPECT_FALSE(range.empty()); EXPECT_EQ(std::numeric_limits<unsigned_int_type>::max(), range.size()); - } @@ -226,7 +226,6 @@ TYPED_TEST_P(counter_range, size) { auto range = util::make_range(l, r); EXPECT_FALSE(range.empty()); EXPECT_EQ(6u, range.size()); - } TYPED_TEST_P(counter_range, at) { @@ -270,6 +269,36 @@ using signed_int_types = ::testing::Types<signed char, short, INSTANTIATE_TYPED_TEST_CASE_P(int_types, counter_range, int_types); +TEST(range, assign) { + const char *cstr = "howdy"; + std::string text = "pardner"; + + util::assign(text, util::make_range(cstr, null_terminated)); + EXPECT_EQ("howdy", text); + + const std::vector<char> vstr = {'x', 'y', 'z', 'z', 'y'}; + util::assign(text, vstr); + EXPECT_EQ("xyzzy", text); + + util::assign_by(text, vstr, + [](char c) { return c=='z'? '1': '0'; }); + EXPECT_EQ("00110", text); +} + +TEST(range, sort) { + char cstr[] = "howdy"; + + auto cstr_range = util::make_range(std::begin(cstr), null_terminated); + + // simple sort + util::sort(cstr_range); + EXPECT_EQ(std::string("dhowy"), cstr); + + // reverse sort by transform c to -c + util::sort_by(cstr_range, [](char c) { return -c; }); + EXPECT_EQ(std::string("ywohd"), cstr); +} + #ifdef WITH_TBB TEST(range, tbb_split) { diff --git a/tests/validation/validate_soma.cpp b/tests/validation/validate_soma.cpp index 8952ba30c93d5c7121fa09c6092e281d39564eb4..05ff783e37e987231dc5cc65e040119ffe7b3b9e 100644 --- a/tests/validation/validate_soma.cpp +++ b/tests/validation/validate_soma.cpp @@ -4,7 +4,7 @@ #include <common_types.hpp> #include <cell.hpp> #include <fvm_cell.hpp> -#include <util/range.hpp> +#include <util/rangeutil.hpp> #include "gtest.h" diff --git a/tests/validation/validate_synapses.cpp b/tests/validation/validate_synapses.cpp index d1de3df06945b33466ccbbc105d412196c0a5f0b..62b91841ab37fd626bde4a7cf6a2e03a096d1e90 100644 --- a/tests/validation/validate_synapses.cpp +++ b/tests/validation/validate_synapses.cpp @@ -8,7 +8,7 @@ #include <cell_group.hpp> #include <fvm_cell.hpp> #include <mechanism_interface.hpp> -#include <util/range.hpp> +#include <util/rangeutil.hpp> #include "gtest.h" #include "../test_util.hpp"