• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

paulmthompson / WhiskerToolbox / 17846711083

19 Sep 2025 02:28AM UTC coverage: 72.02% (+0.08%) from 71.942%
17846711083

push

github

paulmthompson
event in interval computer works with entity ids

259 of 280 new or added lines in 6 files covered. (92.5%)

268 existing lines in 17 files now uncovered.

40247 of 55883 relevant lines covered (72.02%)

1227.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.41
/src/DataManager/utils/TableView/computers/EventInIntervalComputer.cpp
1
#include "EventInIntervalComputer.h"
2

3
#include "utils/TableView/interfaces/IEventSource.h"
4

5
#include <algorithm>
6
#include <stdexcept>
7

8
/**
9
 * @brief Finds events within a specific interval using binary search.
10
 * 
11
 * This private helper method efficiently locates all events that fall within
12
 * the specified interval using binary search algorithms. It assumes the events
13
 * are sorted in ascending order for optimal performance.
14
 * 
15
 * @param events Span of all events, must be sorted in ascending order
16
 * @param startIdx Start index of the interval (inclusive)
17
 * @param endIdx End index of the interval (inclusive)
18
 * @return Vector of TimeFrameIndex values representing events within the interval
19
 * 
20
 * @pre @p events is sorted in ascending order
21
 * @pre @p startIdx <= @p endIdx
22
 * 
23
 * @post Result contains only events where startIdx <= event <= endIdx
24
 * @post Result is sorted in ascending order
25
 * 
26
 * @note Time complexity: O(log n) where n is the number of events
27
 */
28
template<typename T>
29
auto EventInIntervalComputer<T>::findEventsInInterval(std::span<TimeFrameIndex const> events,
30
                                                      TimeFrameIndex startIdx,
31
                                                      TimeFrameIndex endIdx) const -> std::vector<TimeFrameIndex> {
32
    std::vector<TimeFrameIndex> result;
33

34
    // Use binary search to find the range of events within the interval
35
    auto startIt = std::lower_bound(events.begin(), events.end(), startIdx);
36
    auto endIt = std::upper_bound(events.begin(), events.end(), endIdx);
37

38
    // Copy events within the interval
39
    result.reserve(static_cast<size_t>(std::distance(startIt, endIt)));
40
    result.assign(startIt, endIt);
41

42
    return result;
43
}
44

45
/**
46
 * @brief Template specialization for bool (Presence operation).
47
 * 
48
 * Computes whether any events exist within each interval of the execution plan.
49
 * Returns a boolean vector where each element indicates the presence (true) or
50
 * absence (false) of events in the corresponding interval.
51
 * 
52
 * This specialization is optimized for detecting event occurrence patterns and
53
 * is commonly used for binary classification of time intervals based on event
54
 * presence.
55
 * 
56
 * @param plan The execution plan containing interval boundaries and time frame
57
 * @return Vector of boolean values indicating event presence in each interval
58
 * 
59
 * @pre @p m_operation == EventOperation::Presence
60
 * @pre @p plan contains valid intervals and non-null time frame
61
 * 
62
 * @post Result vector size equals plan.getIntervals().size()
63
 * @post Each result is true if any events exist in the corresponding interval, false otherwise
64
 * 
65
 * @throws std::runtime_error if operation type doesn't match EventOperation::Presence
66
 */
67
template<>
68
auto EventInIntervalComputer<bool>::compute(ExecutionPlan const & plan) const -> std::vector<bool> {
50✔
69
    if (m_operation != EventOperation::Presence) {
50✔
70
        throw std::runtime_error("EventInIntervalComputer<bool> can only be used with EventOperation::Presence");
1✔
71
    }
72

73
    auto intervals = plan.getIntervals();
49✔
74
    auto destinationTimeFrame = plan.getTimeFrame();
49✔
75

76
    std::vector<bool> results;
49✔
77
    results.reserve(intervals.size());
49✔
78

79
    for (auto const & interval: intervals) {
2,345✔
80

81
        auto events = m_source->getDataInRange(interval.start, interval.end, destinationTimeFrame.get());
2,296✔
82

83
        results.push_back(!events.empty());
2,296✔
84
    }
2,296✔
85

86
    return results;
49✔
87
}
49✔
88

89
/**
90
 * @brief Template specialization for int (Count operation).
91
 * 
92
 * Computes the number of events within each interval of the execution plan.
93
 * Returns an integer vector where each element represents the count of events
94
 * in the corresponding interval.
95
 * 
96
 * This specialization is useful for quantifying event frequency and density
97
 * across different time periods, commonly used in spike rate analysis and
98
 * event frequency studies.
99
 * 
100
 * @param plan The execution plan containing interval boundaries and time frame
101
 * @return Vector of integer values representing event counts in each interval
102
 * 
103
 * @pre @p m_operation == EventOperation::Count
104
 * @pre @p plan contains valid intervals and non-null time frame
105
 * 
106
 * @post Result vector size equals plan.getIntervals().size()
107
 * @post Each result is the number of events in the corresponding interval (>= 0)
108
 * 
109
 * @throws std::runtime_error if operation type doesn't match EventOperation::Count
110
 */
111
template<>
112
auto EventInIntervalComputer<int>::compute(ExecutionPlan const & plan) const -> std::vector<int> {
51✔
113
    if (m_operation != EventOperation::Count) {
51✔
114
        throw std::runtime_error("EventInIntervalComputer<int> can only be used with EventOperation::Count");
1✔
115
    }
116

117
    auto intervals = plan.getIntervals();
50✔
118
    auto destinationTimeFrame = plan.getTimeFrame();
50✔
119

120
    std::vector<int> results;
50✔
121
    results.reserve(intervals.size());
50✔
122

123
    for (auto const & interval: intervals) {
2,345✔
124

125
        auto events = m_source->getDataInRange(interval.start, interval.end, destinationTimeFrame.get());
2,295✔
126

127
        results.push_back(static_cast<int>(events.size()));
2,295✔
128
    }
2,295✔
129

130
    return results;
50✔
131
}
50✔
132

133
/**
134
 * @brief Template specialization for std::vector<float> (Gather operations).
135
 * 
136
 * Computes the actual event times within each interval of the execution plan.
137
 * Returns a vector of float vectors where each inner vector contains the
138
 * event times that occurred within the corresponding interval.
139
 * 
140
 * This specialization supports two modes:
141
 * - EventOperation::Gather: Returns absolute event times within each interval
142
 * - EventOperation::Gather_Center: Returns event times relative to interval center
143
 * 
144
 * This is particularly useful for detailed event analysis, spike timing studies,
145
 * and when the exact timing of events within intervals is required.
146
 * 
147
 * @param plan The execution plan containing interval boundaries and time frame
148
 * @return Vector of float vectors, each containing event times within the corresponding interval
149
 * 
150
 * @pre @p m_operation == EventOperation::Gather || m_operation == EventOperation::Gather_Center
151
 * @pre @p plan contains valid intervals and non-null time frame
152
 * @pre Source and destination time frames are compatible
153
 * 
154
 * @post Result vector size equals plan.getIntervals().size()
155
 * @post For Gather operation: each inner vector contains absolute event times within the interval
156
 * @post For Gather_Center operation: each inner vector contains event times relative to interval center
157
 * @post Each inner vector is sorted in ascending order
158
 * 
159
 * @throws std::runtime_error if operation type doesn't match EventOperation::Gather or EventOperation::Gather_Center
160
 * @throws std::runtime_error if source and destination time frames are incompatible
161
 */
162
template<>
163
auto EventInIntervalComputer<std::vector<float>>::compute(ExecutionPlan const & plan) const -> std::vector<std::vector<float>> {
15✔
164
    if (m_operation != EventOperation::Gather && m_operation != EventOperation::Gather_Center) {
15✔
165
        throw std::runtime_error("EventInIntervalComputer<std::vector<TimeFrameIndex>> can only be used with EventOperation::Gather");
1✔
166
    }
167

168
    auto intervals = plan.getIntervals();
14✔
169
    auto destinationTimeFrame = plan.getTimeFrame();
14✔
170
    auto sourceTimeFrame = m_source->getTimeFrame();
14✔
171

172
    std::vector<std::vector<float>> results;
14✔
173
    results.reserve(intervals.size());
14✔
174

175
    for (auto const & interval: intervals) {
57✔
176

177
        auto events = m_source->getDataInRange(interval.start, interval.end, destinationTimeFrame.get());
43✔
178

179
        if (m_operation == EventOperation::Gather_Center) {
43✔
180
            auto center = (interval.start + interval.end).getValue() / 2;
6✔
181
            auto center_time_value = destinationTimeFrame->getTimeAtIndex(TimeFrameIndex(center));
6✔
182
            auto source_time_index = sourceTimeFrame->getIndexAtTime(static_cast<float>(center_time_value));
6✔
183
            for (auto & event: events) {
21✔
184
                event = event - static_cast<float>(source_time_index.getValue());
15✔
185
            }
186
        }
187

188
        results.push_back(std::move(events));
43✔
189
    }
43✔
190

191
    return results;
14✔
192
}
14✔
193

194
/**
195
 * @brief Computes all EntityIDs for the column.
196
 * 
197
 * For Gather and Gather_Center operations, this returns a vector of vectors where each
198
 * inner vector contains the EntityIDs of all events that fall within the corresponding interval.
199
 * For other operations, returns std::monostate (no EntityIDs).
200
 * 
201
 * @param plan The execution plan containing interval boundaries and destination time frame.
202
 * @return ColumnEntityIds variant containing the EntityIDs for this column.
203
 */
204
template<typename T>
205
ColumnEntityIds EventInIntervalComputer<T>::computeColumnEntityIds(ExecutionPlan const & plan) const {
11✔
206
    // Only provide EntityIDs for Gather and Gather_Center operations
207
    if (m_operation != EventOperation::Gather && m_operation != EventOperation::Gather_Center) {
11✔
NEW
208
        return std::monostate{};
×
209
    }
210

211
    auto const & intervals = plan.getIntervals();
11✔
212
    auto destinationTimeFrame = plan.getTimeFrame();
11✔
213

214
    std::vector<std::vector<EntityId>> results;
11✔
215
    results.reserve(intervals.size());
11✔
216

217
    // For each interval, collect EntityIDs of events that fall within it
218
    for (auto const & interval : intervals) {
93✔
219
        auto events_with_indices = m_source->getDataInRangeWithIndices(interval.start, interval.end, destinationTimeFrame.get());
41✔
220
        
221
        std::vector<EntityId> interval_entity_ids;
41✔
222
        interval_entity_ids.reserve(events_with_indices.size());
41✔
223

224
        // Extract EntityIDs using the source indices
225
        for (auto const & [event_value, source_index] : events_with_indices) {
134✔
226
            (void)event_value; // Suppress unused variable warning
227
            if (auto entityId = m_source->getEntityIdAt(source_index); entityId != 0) {
93✔
228
                interval_entity_ids.push_back(entityId);
93✔
229
            }
230
        }
231

232
        results.push_back(std::move(interval_entity_ids));
41✔
233
    }
234

235
    return results;
11✔
236
}
11✔
237

238
template ColumnEntityIds EventInIntervalComputer<bool>::computeColumnEntityIds(ExecutionPlan const & plan) const;
239
template ColumnEntityIds EventInIntervalComputer<int>::computeColumnEntityIds(ExecutionPlan const & plan) const;
240
template ColumnEntityIds EventInIntervalComputer<std::vector<float>>::computeColumnEntityIds(ExecutionPlan const & plan) const;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc