Skip to content

Commit 72a3304

Browse files
committed
fix asserts for debug builds
1 parent d367215 commit 72a3304

File tree

3 files changed

+43
-12
lines changed

3 files changed

+43
-12
lines changed

cpp/memilio/utils/index.h

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
#include "memilio/io/io.h"
2424
#include "memilio/utils/compiler_diagnostics.h"
25+
#include "memilio/utils/metaprogramming.h"
2526
#include "memilio/utils/type_safe.h"
2627

2728
#include <cstddef>
@@ -116,9 +117,10 @@ class MEMILIO_ENABLE_EBO Index<CategoryTag> : public TypeSafe<size_t, Index<Cate
116117
public:
117118
using TypeSafe<size_t, Index<CategoryTag>>::TypeSafe;
118119

119-
static size_t constexpr size = 1;
120+
static constexpr size_t size = 1;
121+
static constexpr bool has_duplicates = false;
120122

121-
static Index constexpr Zero()
123+
static constexpr Index Zero()
122124
{
123125
return Index((size_t)0);
124126
}
@@ -173,7 +175,8 @@ template <typename... CategoryTag>
173175
class Index
174176
{
175177
public:
176-
static size_t constexpr size = sizeof...(CategoryTag);
178+
static constexpr size_t size = sizeof...(CategoryTag);
179+
static constexpr bool has_duplicates = has_duplicates_v<CategoryTag...>;
177180

178181
static Index constexpr Zero()
179182
{
@@ -211,6 +214,25 @@ class Index
211214
return !(this == other);
212215
}
213216

217+
bool operator<(Index const& other) const
218+
{
219+
// use apply to unfold both tuples, then use a fold expression to evaluate a pairwise less
220+
return std::apply(
221+
[&other](auto&&... indices_) {
222+
return std::apply(
223+
[&](auto&&... other_indices_) {
224+
return ((indices_ < other_indices_) && ...);
225+
},
226+
other.indices);
227+
},
228+
indices);
229+
}
230+
231+
bool operator<=(Index const& other) const
232+
{
233+
return (*this == other) || (*this < other);
234+
}
235+
214236
/**
215237
* serialize this.
216238
* @see mio::serialize
@@ -372,9 +394,16 @@ inline Index<CategoryTags...> extend_index_impl(const Index<Subset...>& i, const
372394
* @return A (sub)index with the given categories and values from index.
373395
*/
374396
template <class SubIndex, class SuperIndex>
375-
SubIndex reduce_index(const SuperIndex& index)
397+
decltype(auto) reduce_index(const SuperIndex& index)
376398
{
377-
return details::reduce_index_impl(index, mio::Tag<SubIndex>{});
399+
if constexpr (SubIndex::size == 1 && std::is_base_of_v<Index<SubIndex>, SubIndex>) {
400+
// this case handles reducing from e.g. Index<AgeGroup, ...> directly to AgeGroup
401+
// the default case would instead reduce to Index<AgeGroup>, which may cause conversion errors
402+
return details::reduce_index_impl(index, mio::Tag<Index<SubIndex>>{});
403+
}
404+
else {
405+
return details::reduce_index_impl(index, mio::Tag<SubIndex>{});
406+
}
378407
}
379408

380409
template <class Enum, class SuperIndex>

cpp/models/smm/model.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class Model : public mio::CompartmentalModel<FP, Comp, mio::Populations<FP, Popu
5151
{
5252
using Base = mio::CompartmentalModel<FP, Comp, mio::Populations<FP, PopulationIndex<StatusT, RegionT>>,
5353
ParametersBase<FP, StatusT, RegionT>>;
54+
static_assert(!Base::Populations::Index::has_duplicates, "Do not use the same Index tag multiple times!");
5455

5556
public:
5657
using Status = StatusT;

cpp/models/smm/simulation.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ class Simulation
4141
{
4242
public:
4343
using Model = smm::Model<FP, Comp, Status, Region>;
44-
using Index = typename Model::Populations::Index;
4544

4645
/**
4746
* @brief Set up the simulation for a Stochastic Metapopulation Model.
@@ -60,12 +59,14 @@ class Simulation
6059
{
6160
assert(dt > 0);
6261
assert(m_waiting_times.size() > 0);
63-
assert(std::all_of(adoption_rates().begin(), adoption_rates().end(), [](auto&& r) {
64-
return static_cast<size_t>(r.region) < regions;
65-
}));
66-
assert(std::all_of(transition_rates().begin(), transition_rates().end(), [](auto&& r) {
67-
return static_cast<size_t>(r.from) < regions && static_cast<size_t>(r.to) < regions;
68-
}));
62+
assert(std::all_of(adoption_rates().begin(), adoption_rates().end(),
63+
[regions = reduce_index<Region>(model.populations.size())](auto&& r) {
64+
return r.region < regions;
65+
}));
66+
assert(std::all_of(transition_rates().begin(), transition_rates().end(),
67+
[regions = reduce_index<Region>(model.populations.size())](auto&& r) {
68+
return r.from < regions && r.to < regions;
69+
}));
6970
// initialize (internal) next event times by random values
7071
for (size_t i = 0; i < m_tp_next_event.size(); i++) {
7172
m_tp_next_event[i] += mio::ExponentialDistribution<FP>::get_instance()(m_model->get_rng(), 1.0);

0 commit comments

Comments
 (0)