diff --git a/arbor/cable_cell_param.cpp b/arbor/cable_cell_param.cpp index bc7e26152b127f40b26f15514b5669fc36c6ea4c..d1e491ece8534bc0fa314b78950ddfa23a2042a8 100644 --- a/arbor/cable_cell_param.cpp +++ b/arbor/cable_cell_param.cpp @@ -50,10 +50,6 @@ void check_global_properties(const cable_cell_global_properties& G) { } } } - util::optional<double> init_membrane_potential; // [mV] - util::optional<double> temperature_K; // [K] - util::optional<double> axial_resistivity; // [Ω·cm] - util::optional<double> membrane_capacitance; // [F/m²] cable_cell_parameter_set neuron_parameter_defaults = { // initial membrane potential [mV] @@ -108,7 +104,7 @@ locset cv_policy_max_extent::cv_boundary_points(const cable_cell& cell) const { ++bidx; } - return std::accumulate(points.begin(), points.end(), ls::nil(), [](auto& l, auto& p) { return join(l, ls::location(p)); }); + return points; } locset cv_policy_fixed_per_branch::cv_boundary_points(const cable_cell& cell) const { @@ -140,7 +136,7 @@ locset cv_policy_fixed_per_branch::cv_boundary_points(const cable_cell& cell) co ++bidx; } - return std::accumulate(points.begin(), points.end(), ls::nil(), [](auto& l, auto& p) { return join(l, ls::location(p)); }); + return points; } } // namespace arb diff --git a/arbor/include/arbor/morph/locset.hpp b/arbor/include/arbor/morph/locset.hpp index 1ca7e066f8bb5a294971ecd94675d30e5246a87b..da2688ec57e41234d9d0ac08c6515842caa7fa6f 100644 --- a/arbor/include/arbor/morph/locset.hpp +++ b/arbor/include/arbor/morph/locset.hpp @@ -16,11 +16,12 @@ namespace arb { struct mprovider; class locset; +class locset_tag {}; class locset { public: template <typename Impl, - typename X=std::enable_if_t<!std::is_same<std::decay_t<Impl>, locset>::value>> + typename = std::enable_if_t<std::is_base_of<locset_tag, std::decay_t<Impl>>::value>> explicit locset(Impl&& impl): impl_(new wrap<Impl>(std::forward<Impl>(impl))) {} @@ -41,15 +42,16 @@ public: // The default constructor creates an empty "nil" set. locset(); - // Construct an explicit location set with a single location. + // Implicity convert mlocation and mlocation_lists to locsets. locset(mlocation other); + locset(const mlocation_list& other); // Implicitly convert string to named locset expression. locset(std::string label); locset(const char* label); template <typename Impl, - typename X=std::enable_if_t<!std::is_same<std::decay_t<Impl>, locset>::value>> + typename = std::enable_if_t<std::is_base_of<locset_tag, std::decay_t<Impl>>::value>> locset& operator=(Impl&& other) { impl_ = new wrap<Impl>(std::forward<Impl>(other)); return *this; @@ -119,7 +121,7 @@ private: namespace ls { // Explicit location on morphology. -locset location(mlocation); +locset location(msize_t branch, double pos); // Location of a sample. locset sample(msize_t); diff --git a/arbor/include/arbor/morph/region.hpp b/arbor/include/arbor/morph/region.hpp index 9173bd27b1450c59e9203a033c53a4dd54a18c7c..bd049fd68225f314ca2d92e1cf1e0bce33a774d1 100644 --- a/arbor/include/arbor/morph/region.hpp +++ b/arbor/include/arbor/morph/region.hpp @@ -14,11 +14,12 @@ namespace arb { struct mprovider; +struct region_tag {}; class region { public: template <typename Impl, - typename X=std::enable_if_t<!std::is_same<std::decay_t<Impl>, region>::value>> + typename = std::enable_if_t<std::is_base_of<region_tag, std::decay_t<Impl>>::value>> explicit region(Impl&& impl): impl_(new wrap<Impl>(std::forward<Impl>(impl))) {} @@ -40,7 +41,7 @@ public: } template <typename Impl, - typename X=std::enable_if_t<!std::is_same<std::decay_t<Impl>, region>::value>> + typename = std::enable_if_t<std::is_base_of<region_tag, std::decay_t<Impl>>::value>> region& operator=(Impl&& other) { impl_ = new wrap<Impl>(std::forward<Impl>(other)); return *this; @@ -52,6 +53,10 @@ public: return *this; } + // Implicit conversion from mcable or mcable_list. + region(mcable); + region(const mcable_list&); + // Implicitly convert string to named region expression. region(std::string label); region(const char* label); @@ -133,9 +138,10 @@ region named(std::string); } // namespace reg -// union of two regions +// Union of two regions. region join(region, region); -// intersection of two regions + +// Intersection of two regions. region intersect(region, region); } // namespace arb diff --git a/arbor/morph/locset.cpp b/arbor/morph/locset.cpp index 3fa6ea893bd1f9ee7b42e004d9a1d1ed1e75c0ee..715ddcc0e3b3dcb866cde30dcd2ddd53e282c3e6 100644 --- a/arbor/morph/locset.cpp +++ b/arbor/morph/locset.cpp @@ -23,7 +23,7 @@ void assert_valid(mlocation x) { // Empty locset. -struct nil_ {}; +struct nil_: locset_tag {}; locset nil() { return locset{nil_{}}; @@ -39,11 +39,13 @@ std::ostream& operator<<(std::ostream& o, const nil_& x) { // An explicit location. -struct location_ { +struct location_: locset_tag { + explicit location_(mlocation loc): loc(loc) {} mlocation loc; }; -locset location(mlocation loc) { +locset location(msize_t branch, double pos) { + mlocation loc{branch, pos}; assert_valid(loc); return locset{location_{loc}}; } @@ -63,7 +65,8 @@ std::ostream& operator<<(std::ostream& o, const location_& x) { // Location corresponding to a sample id. -struct sample_ { +struct sample_: locset_tag { + explicit sample_(msize_t index): index(index) {} msize_t index; }; @@ -81,7 +84,7 @@ std::ostream& operator<<(std::ostream& o, const sample_& x) { // Set of terminal points (most distal points). -struct terminal_ {}; +struct terminal_: locset_tag {}; locset terminal() { return locset{terminal_{}}; @@ -101,7 +104,7 @@ std::ostream& operator<<(std::ostream& o, const terminal_& x) { // Root location (most proximal point). -struct root_ {}; +struct root_: locset_tag {}; locset root() { return locset{root_{}}; @@ -117,7 +120,8 @@ std::ostream& operator<<(std::ostream& o, const root_& x) { // Named locset. -struct named_ { +struct named_: locset_tag { + explicit named_(std::string name): name(std::move(name)) {} std::string name; }; @@ -136,7 +140,7 @@ std::ostream& operator<<(std::ostream& o, const named_& x) { // Intersection of two point sets. -struct land { +struct land: locset_tag { locset lhs; locset rhs; land(locset lhs, locset rhs): lhs(std::move(lhs)), rhs(std::move(rhs)) {} @@ -152,7 +156,7 @@ std::ostream& operator<<(std::ostream& o, const land& x) { // Union of two point sets. -struct lor { +struct lor: locset_tag { locset lhs; locset rhs; lor(locset lhs, locset rhs): lhs(std::move(lhs)), rhs(std::move(rhs)) {} @@ -168,7 +172,7 @@ std::ostream& operator<<(std::ostream& o, const lor& x) { // Sum of two point sets. -struct lsum { +struct lsum: locset_tag { locset lhs; locset rhs; lsum(locset lhs, locset rhs): lhs(std::move(lhs)), rhs(std::move(rhs)) {} @@ -200,12 +204,19 @@ locset sum(locset lhs, locset rhs) { return locset(ls::lsum(std::move(lhs), std::move(rhs))); } +// Implicit constructors. + locset::locset() { *this = ls::nil(); } locset::locset(mlocation loc) { - *this = ls::location(loc); + *this = ls::location(loc.branch, loc.pos); +} + +locset::locset(const mlocation_list& ll) { + *this = std::accumulate(ll.begin(), ll.end(), ls::nil(), + [](auto& ls, auto& p) { return sum(ls, locset(p)); }); } locset::locset(std::string name) { @@ -216,5 +227,4 @@ locset::locset(const char* name) { *this = ls::named(name); } - } // namespace arb diff --git a/arbor/morph/region.cpp b/arbor/morph/region.cpp index cb68726f69ddccd16a7f59c8717e465d3cc4ba89..3db12f50fb317606054a817f66befb99ca12446f 100644 --- a/arbor/morph/region.cpp +++ b/arbor/morph/region.cpp @@ -173,7 +173,7 @@ mcable_list remove_covered_points(mcable_list cables, const morphology& m) { // Empty region. -struct nil_ {}; +struct nil_: region_tag {}; region nil() { return region{nil_{}}; @@ -190,7 +190,8 @@ std::ostream& operator<<(std::ostream& o, const nil_& x) { // Explicit cable section. -struct cable_ { +struct cable_: region_tag { + explicit cable_(mcable c): cable(std::move(c)) {} mcable cable; }; @@ -220,7 +221,8 @@ std::ostream& operator<<(std::ostream& o, const cable_& c) { // Region with all segments with the same numeric tag. -struct tagged_ { +struct tagged_: region_tag { + explicit tagged_(int tag): tag(tag) {} int tag; }; @@ -284,7 +286,7 @@ std::ostream& operator<<(std::ostream& o, const tagged_& t) { // Region comprising whole morphology. -struct all_ {}; +struct all_: region_tag {}; region all() { return region(all_{}); @@ -307,7 +309,8 @@ std::ostream& operator<<(std::ostream& o, const all_& t) { // Named region. -struct named_ { +struct named_: region_tag { + explicit named_(std::string name): name(std::move(name)) {} std::string name; }; @@ -326,7 +329,7 @@ std::ostream& operator<<(std::ostream& o, const named_& x) { // Intersection of two regions. -struct reg_and { +struct reg_and: region_tag { region lhs; region rhs; reg_and(region lhs, region rhs): lhs(std::move(lhs)), rhs(std::move(rhs)) {} @@ -373,7 +376,7 @@ std::ostream& operator<<(std::ostream& o, const reg_and& x) { // Union of two regions. -struct reg_or { +struct reg_or: region_tag { region lhs; region rhs; reg_or(region lhs, region rhs): lhs(std::move(lhs)), rhs(std::move(rhs)) {} @@ -412,6 +415,8 @@ region::region() { *this = reg::nil(); } +// Implicit constructors/converters. + region::region(std::string label) { *this = reg::named(std::move(label)); } @@ -420,4 +425,13 @@ region::region(const char* label) { *this = reg::named(label); } +region::region(mcable c) { + *this = reg::cable(c.branch, c.prox_pos, c.dist_pos); +} + +region::region(const mcable_list& cl) { + *this = std::accumulate(cl.begin(), cl.end(), reg::nil(), + [](auto& rg, auto& p) { return join(rg, region(p)); }); +} + } // namespace arb diff --git a/test/unit/test_cv_policy.cpp b/test/unit/test_cv_policy.cpp index aa11e16782001a8dc4bfcbc496f26a1ab366a2f1..1f42c41f72fa7b17b654f4950405fd61789ad45e 100644 --- a/test/unit/test_cv_policy.cpp +++ b/test/unit/test_cv_policy.cpp @@ -51,15 +51,7 @@ namespace { template <typename... A> locset as_locset(mlocation head, A... tail) { - return join(ls::location(head), ls::location(tail)...); - } - - template <typename Seq> - locset as_locset(const Seq& seq) { - using std::begin; - using std::end; - return std::accumulate(begin(seq), end(seq), ls::nil(), - [](locset ls, const mlocation& p) { return join(std::move(ls), ls::location(p)); }); + return join(locset(head), locset(tail)...); } } diff --git a/test/unit/test_morph_expr.cpp b/test/unit/test_morph_expr.cpp index 96cfae6e646f6d31a4c56c5c1e59844671c27576..60d104e992458d8b64e0ad760c0f0e17b4d3317f 100644 --- a/test/unit/test_morph_expr.cpp +++ b/test/unit/test_morph_expr.cpp @@ -92,7 +92,7 @@ TEST(locset, expr_repn) { auto root = ls::root(); auto term = ls::terminal(); auto samp = ls::sample(42); - auto loc = ls::location({2, 0.5}); + auto loc = ls::location(2, 0.5); EXPECT_EQ(to_string(root), "(root)"); EXPECT_EQ(to_string(term), "(terminal)"); @@ -103,14 +103,14 @@ TEST(locset, expr_repn) { EXPECT_EQ(to_string(loc), "(location 2 0.5)"); } -TEST(region, invalid_mlocation) { +TEST(locset, invalid_mlocation) { // Location positions have to be in the range [0,1]. - EXPECT_NO_THROW(ls::location({123, 0.0})); - EXPECT_NO_THROW(ls::location({123, 0.02})); - EXPECT_NO_THROW(ls::location({123, 1.0})); + EXPECT_NO_THROW(ls::location(123, 0.0)); + EXPECT_NO_THROW(ls::location(123, 0.02)); + EXPECT_NO_THROW(ls::location(123, 1.0)); - EXPECT_THROW(ls::location({0, 1.5}), invalid_mlocation); - EXPECT_THROW(ls::location({unsigned(-1), 0.}), invalid_mlocation); + EXPECT_THROW(ls::location(0, 1.5), invalid_mlocation); + EXPECT_THROW(ls::location(unsigned(-1), 0.), invalid_mlocation); } // Name evaluation (thingify) tests: @@ -204,13 +204,14 @@ TEST(locset, thingify) { auto root = ls::root(); auto term = ls::terminal(); auto samp = ls::sample(4); - auto midb2 = ls::location({2, 0.5}); - auto midb1 = ls::location({1, 0.5}); - auto begb0 = ls::location({0, 0}); - auto begb1 = ls::location({1, 0}); - auto begb2 = ls::location({2, 0}); - auto begb3 = ls::location({3, 0}); - auto begb4 = ls::location({4, 0}); + auto midb2 = ls::location(2, 0.5); + auto midb1 = ls::location(1, 0.5); + auto begb0 = ls::location(0, 0); + auto begb1 = ls::location(1, 0); + auto begb2 = ls::location(2, 0); + auto begb3 = ls::location(3, 0); + auto begb4 = ls::location(4, 0); + auto multi = sum(begb3, midb2, midb1, midb2); // Eight samples // @@ -245,6 +246,11 @@ TEST(locset, thingify) { EXPECT_EQ(thingify(begb2, mp), (ll{{2,0}})); EXPECT_EQ(thingify(begb3, mp), (ll{{3,0}})); EXPECT_EQ(thingify(begb4, mp), (ll{{4,0}})); + + // Check round-trip of implicit locset conversions. + // (Use a locset which is non-trivially a multiset in order to + // test the fold in the constructor.) + EXPECT_EQ(thingify(multi, mp), thingify(locset(thingify(multi, mp)), mp)); } { mprovider mp(morphology(sm, false)); @@ -315,6 +321,10 @@ TEST(region, thingify) { EXPECT_TRUE(cablelist_eq(thingify(join(h1, t1), mp), (cl{{0, 0, 0.7}}))); EXPECT_TRUE(cablelist_eq(thingify(join(h1, t2), mp), (cl{{0, 0, 0.5}, {0, 0.7, 1}}))); EXPECT_TRUE(cablelist_eq(thingify(intersect(h2, t1), mp), (cl{{0, 0.5, 0.7}}))); + + // Check round-trip of implicit region conversions. + EXPECT_EQ((mcable_list{{0, 0.3, 0.6}}), thingify(region(mcable{0, 0.3, 0.6}), mp)); + EXPECT_TRUE(cablelist_eq(t2_, thingify(region(t2_), mp))); }