Skip to content

Commit 77405cc

Browse files
authored
Time constraint (#22)
## Changes * `PostTagSearcher` now correctly uses the time constraint parameter. * `ConclusionReason` will either be `TimeConstraintExceeded` or `NotEvaluated` based on whether the time constraint was reached before or during the evaluation of a particular init. ## Comments * Checkpoints #21 should be merged first. * The time constraint will be exceeded slightly because results need to be collected. ## Examples * The first result of the following concludes with reason `TimeConstraintExceeded`: ```c++ PostTagSearcher::EvaluationParameters parameters; parameters.groupTimeConstraintNs = 100000000; // 0.1 seconds const auto result = PostTagSearcher().evaluateRange( 64, 1473593303835332608, 1473593303835332609, parameters); ``` * The other two results are `NotEvaluated` for now, but that can change after parallelization is implemented.
1 parent 9c0122b commit 77405cc

5 files changed

Lines changed: 70 additions & 6 deletions

File tree

libPostTagSystem/PostTagHistory.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
#include <algorithm>
44
#include <array>
5+
#include <chrono>
6+
#include <cmath>
57
#include <limits>
68
#include <memory>
79
#include <queue>
@@ -56,6 +58,15 @@ class PostTagHistory::Implementation {
5658
const std::vector<TagState>& inits,
5759
const EvaluationLimits& limits,
5860
const CheckpointSpec& checkpointSpec) {
61+
const auto startClock = std::chrono::steady_clock::now();
62+
std::chrono::steady_clock::time_point endClock;
63+
64+
if (std::chrono::nanoseconds(limits.maxTimeNs) > std::chrono::steady_clock::time_point::max() - startClock) {
65+
endClock = std::chrono::steady_clock::time_point::max();
66+
} else {
67+
endClock = startClock + std::chrono::nanoseconds(limits.maxTimeNs);
68+
}
69+
5970
const ChunkEvaluationTable chunkEvaluationTable = createChunkEvaluationTable(rule);
6071
if (limits.maxEventCount % chunkEvaluationTable.eventsAtOnce != 0) {
6172
return std::vector<EvaluationResult>(
@@ -77,6 +88,7 @@ class PostTagHistory::Implementation {
7788
&conclusionReason,
7889
&maxIntermediateTapeLength,
7990
limits,
91+
endClock,
8092
explicitCheckpointsTrie,
8193
checkpointSpec.flags);
8294
results.push_back(
@@ -166,12 +178,22 @@ class PostTagHistory::Implementation {
166178
ConclusionReason* conclusionReason,
167179
uint64_t* maxIntermediateTapeLength,
168180
const EvaluationLimits& limits,
181+
std::chrono::time_point<std::chrono::steady_clock> endClock,
169182
const CheckpointsTrie& explicitCheckpoints,
170183
const CheckpointSpecFlags& checkpointFlags) {
184+
if (std::chrono::steady_clock::now() > endClock) {
185+
*conclusionReason = ConclusionReason::NotEvaluated;
186+
return 0;
187+
}
171188
CheckpointsTrie automaticCheckpoints;
172189
uint64_t eventCount;
190+
constexpr int eventsPerClockCheck = 1000;
173191
for (eventCount = 0; eventCount < limits.maxEventCount && state->chunks.size() > 1;
174192
eventCount += evaluationTable.eventsAtOnce) {
193+
if (eventCount % eventsPerClockCheck == 0 && std::chrono::steady_clock::now() > endClock) {
194+
*conclusionReason = ConclusionReason::TimeConstraintExceeded;
195+
return eventCount;
196+
}
175197
if (*maxIntermediateTapeLength > limits.maxTapeLength) {
176198
*conclusionReason = ConclusionReason::MaxTapeLengthExceeded;
177199
return eventCount;

libPostTagSystem/PostTagHistory.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ class PostTagHistory {
1616
ReachedExplicitCheckpoint,
1717
ReachedAutomaticCheckpoint,
1818
MaxEventCountExceeded,
19-
MaxTapeLengthExceeded
19+
MaxTapeLengthExceeded,
20+
TimeConstraintExceeded,
21+
NotEvaluated
2022
};
2123

2224
struct EvaluationResult {
@@ -40,7 +42,7 @@ class PostTagHistory {
4042
struct EvaluationLimits {
4143
uint64_t maxEventCount = std::numeric_limits<uint64_t>::max() - 7;
4244
uint64_t maxTapeLength = std::numeric_limits<uint64_t>::max();
43-
uint64_t maxTimeNs = std::numeric_limits<uint64_t>::max();
45+
int64_t maxTimeNs = std::numeric_limits<int64_t>::max();
4446

4547
EvaluationLimits() = default;
4648
explicit EvaluationLimits(uint64_t maxEventCountInput) : maxEventCount(maxEventCountInput) {}

libPostTagSystem/PostTagSearcher.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,13 @@ class PostTagSearcher::Implementation {
3636

3737
std::vector<EvaluationResult> evaluateGroup(const std::vector<TagState>& states,
3838
const EvaluationParameters& parameters) {
39-
// TODO(maxitg): Implement groupTimeConstraintNs parameter
40-
4139
std::vector<EvaluationResult> results;
4240
results.reserve(states.size());
4341
PostTagHistory evaluator;
4442
PostTagHistory::EvaluationLimits limits;
4543
limits.maxEventCount = parameters.maxEventCount;
4644
limits.maxTapeLength = parameters.maxTapeLength;
45+
limits.maxTimeNs = parameters.groupTimeConstraintNs;
4746
const auto singleInitResults =
4847
evaluator.evaluate(PostTagHistory::NamedRule::Post, states, limits, {parameters.checkpoints, {true}});
4948
for (size_t initIndex = 0; initIndex < states.size(); ++initIndex) {
@@ -70,10 +69,20 @@ class PostTagSearcher::Implementation {
7069
result.conclusionReason = ConclusionReason::MaxEventCountExceeded;
7170
break;
7271

72+
case PostTagHistory::ConclusionReason::TimeConstraintExceeded:
73+
result.conclusionReason = ConclusionReason::TimeConstraintExceeded;
74+
break;
75+
76+
case PostTagHistory::ConclusionReason::NotEvaluated:
77+
result.conclusionReason = ConclusionReason::NotEvaluated;
78+
break;
79+
7380
default:
7481
result.conclusionReason = ConclusionReason::InvalidInput;
7582
}
76-
results.push_back(result);
83+
if (result.conclusionReason != ConclusionReason::NotEvaluated || parameters.includeUnevaluatedStates) {
84+
results.push_back(result);
85+
}
7786
}
7887
return results;
7988
}

libPostTagSystem/PostTagSearcher.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@ class PostTagSearcher {
4545
// If the time constraint is exceeded the current EvaluationResult and all the remaining ones will have
4646
// TimeConstraintExceeded conclusion reason. The aborted evaluations will have EvaluationResult filled in with
4747
// values obtained so far. The remaining ones will be filled with zeros.
48-
uint64_t groupTimeConstraintNs = std::numeric_limits<uint64_t>::max();
48+
int64_t groupTimeConstraintNs = std::numeric_limits<int64_t>::max();
4949
Checkpoints checkpoints = {};
50+
bool includeUnevaluatedStates = false;
5051
};
5152

5253
// The functions below use two tries. One for the input checkpoints which is shared among all of them. The other trie

libPostTagSystem/test/PostTagSearcher_test.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,34 @@ TEST(PostTagSearcher, checkpoints) {
119119
compareResults(TagState(20, 123, 0), result[0], PostTagHistory::EvaluationLimits(), parameters.checkpoints);
120120
compareResults(TagState(20, 124, 0), result[3], PostTagHistory::EvaluationLimits(), parameters.checkpoints);
121121
}
122+
123+
TEST(PostTagSearcher, zeroTimeConstraint) {
124+
PostTagSearcher searcher;
125+
PostTagSearcher::EvaluationParameters parameters;
126+
parameters.groupTimeConstraintNs = 0;
127+
parameters.includeUnevaluatedStates = true;
128+
const auto result = searcher.evaluateRange(20, 123, 124, parameters);
129+
ASSERT_EQ(result.size(), 3);
130+
ASSERT_EQ(result[0].conclusionReason, PostTagSearcher::ConclusionReason::NotEvaluated);
131+
}
132+
133+
TEST(PostTagSearcher, includeUnevaluatedStates) {
134+
PostTagSearcher searcher;
135+
PostTagSearcher::EvaluationParameters parameters;
136+
parameters.groupTimeConstraintNs = 0;
137+
parameters.includeUnevaluatedStates = false;
138+
const auto result = searcher.evaluateRange(20, 123, 124, parameters);
139+
ASSERT_EQ(result.size(), 0);
140+
}
141+
142+
TEST(PostTagSearcher, smallTimeConstraint) {
143+
PostTagSearcher searcher;
144+
PostTagSearcher::EvaluationParameters parameters;
145+
parameters.groupTimeConstraintNs = 100000000; // 0.1 seconds
146+
parameters.includeUnevaluatedStates = true;
147+
// The following init takes ~4 seconds to terminate
148+
const auto result = searcher.evaluateRange(64, 1473593303835332608, 1473593303835332609, parameters);
149+
ASSERT_EQ(result.size(), 3);
150+
ASSERT_EQ(result[0].conclusionReason, PostTagSearcher::ConclusionReason::TimeConstraintExceeded);
151+
}
122152
} // namespace PostTagSystem

0 commit comments

Comments
 (0)