Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 58 additions & 30 deletions libPostTagSystem/PostTagHistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,41 @@ class PostTagHistory::Implementation {
const TagState& init,
const EvaluationLimits& limits,
const CheckpointSpec& checkpointSpec) {
return evaluate(rule, std::vector<TagState>({init}), limits, checkpointSpec).front();
}

std::vector<EvaluationResult> evaluate(const NamedRule& rule,
const std::vector<TagState>& inits,
const EvaluationLimits& limits,
const CheckpointSpec& checkpointSpec) {
const ChunkEvaluationTable chunkEvaluationTable = createChunkEvaluationTable(rule);
if (limits.maxEventCount % chunkEvaluationTable.eventsAtOnce != 0) {
return {ConclusionReason::InvalidInput, {{}, std::numeric_limits<uint8_t>::max()}, 0, 0};
return std::vector<EvaluationResult>(
inits.size(), {ConclusionReason::InvalidInput, {{}, std::numeric_limits<uint8_t>::max()}, 0, 0});
}
auto chunkedState = toChunkedState(init);
CheckpointsTrie checkpointsTrie;
CheckpointsTrie explicitCheckpointsTrie;
for (const auto& checkpoint : checkpointSpec.states) {
checkpointsTrie.insert(toChunkedState(checkpoint));
explicitCheckpointsTrie.insert(toChunkedState(checkpoint));
}
uint64_t maxIntermediateTapeLength = tapeLength(chunkedState);
ConclusionReason conclusionReason;
const auto eventCount = evaluate(chunkEvaluationTable,
&chunkedState,
&conclusionReason,
&maxIntermediateTapeLength,
limits,
&checkpointsTrie,
checkpointSpec.flags);
return {conclusionReason, fromChunkedStateDestructively(&chunkedState), eventCount, maxIntermediateTapeLength};

std::vector<EvaluationResult> results;
results.reserve(inits.size());
for (const auto& init : inits) {
auto chunkedState = toChunkedState(init);
uint64_t maxIntermediateTapeLength = tapeLength(chunkedState);
ConclusionReason conclusionReason;
const auto eventCount = evaluate(chunkEvaluationTable,
&chunkedState,
&conclusionReason,
&maxIntermediateTapeLength,
limits,
explicitCheckpointsTrie,
checkpointSpec.flags);
results.push_back(
{conclusionReason, fromChunkedStateDestructively(&chunkedState), eventCount, maxIntermediateTapeLength});
}

return results;
}

private:
Expand All @@ -79,7 +95,7 @@ class PostTagHistory::Implementation {
return foundTable->second;
}

ChunkEvaluationTable createChunkEvaluationTable(const ChunkedRule& rule) {
static ChunkEvaluationTable createChunkEvaluationTable(const ChunkedRule& rule) {
ChunkEvaluationTable table;
table.eventsAtOnce = 8 / rule.inputLength;
table.phaseCount = rule.phaseCount;
Expand All @@ -94,7 +110,7 @@ class PostTagHistory::Implementation {
return table;
}

ChunkOutput createChunkOutput(const ChunkedRule& rule, const uint8_t inputTape, const uint8_t inputPhase) const {
static ChunkOutput createChunkOutput(const ChunkedRule& rule, const uint8_t inputTape, const uint8_t inputPhase) {
uint16_t output = 0;
uint8_t outputSize = 0;
auto phase = inputPhase;
Expand All @@ -110,7 +126,7 @@ class PostTagHistory::Implementation {
return {output, outputSize, phase};
}

ChunkedState toChunkedState(const TagState& state) const {
static ChunkedState toChunkedState(const TagState& state) {
ChunkedState result;
for (size_t i = 0; i < state.tape.size(); ++i) {
if (i % 8 == 0) result.chunks.push_back(0);
Expand All @@ -123,7 +139,7 @@ class PostTagHistory::Implementation {
return result;
}

TagState fromChunkedStateDestructively(ChunkedState* chunkedState) const {
static TagState fromChunkedStateDestructively(ChunkedState* chunkedState) {
std::vector<bool> tape;
if (chunkedState->chunks.size()) {
tape.reserve(8 * (chunkedState->chunks.size() - 1) + chunkedState->lastChunkSize);
Expand All @@ -145,26 +161,31 @@ class PostTagHistory::Implementation {
}
}

uint64_t evaluate(const ChunkEvaluationTable& evaluationTable,
ChunkedState* state,
ConclusionReason* conclusionReason,
uint64_t* maxIntermediateTapeLength,
const EvaluationLimits& limits,
CheckpointsTrie* checkpoints,
const CheckpointSpecFlags& checkpointFlags) const {
static uint64_t evaluate(const ChunkEvaluationTable& evaluationTable,
ChunkedState* state,
ConclusionReason* conclusionReason,
uint64_t* maxIntermediateTapeLength,
const EvaluationLimits& limits,
const CheckpointsTrie& explicitCheckpoints,
const CheckpointSpecFlags& checkpointFlags) {
CheckpointsTrie automaticCheckpoints;
uint64_t eventCount;
for (eventCount = 0; eventCount < limits.maxEventCount && state->chunks.size() > 1;
eventCount += evaluationTable.eventsAtOnce) {
if (*maxIntermediateTapeLength > limits.maxTapeLength) {
*conclusionReason = ConclusionReason::MaxTapeLengthExceeded;
return eventCount;
}
if (checkpoints->contains(*state)) {
*conclusionReason = ConclusionReason::ReachedCheckpoint;
if (explicitCheckpoints.contains(*state)) {
*conclusionReason = ConclusionReason::ReachedExplicitCheckpoint;
return eventCount;
}
if (automaticCheckpoints.contains(*state)) {
*conclusionReason = ConclusionReason::ReachedAutomaticCheckpoint;
return eventCount;
}
if (checkpointFlags.powerOfTwoEventCounts && !isPowerOfTwo(eventCount)) {
checkpoints->insert(*state);
automaticCheckpoints.insert(*state);
}
evaluateOnce(evaluationTable, state);
*maxIntermediateTapeLength = std::max(*maxIntermediateTapeLength, tapeLength(*state));
Expand All @@ -179,11 +200,11 @@ class PostTagHistory::Implementation {

static inline bool isPowerOfTwo(const uint64_t number) { return number & (number - 1); }

uint64_t tapeLength(const ChunkedState& state) const {
static uint64_t tapeLength(const ChunkedState& state) {
return std::max(0, static_cast<int>(state.chunks.size()) - 1) * 8 + state.lastChunkSize;
}

void evaluateOnce(const ChunkEvaluationTable& evaluationTable, ChunkedState* state) const {
static void evaluateOnce(const ChunkEvaluationTable& evaluationTable, ChunkedState* state) {
const auto nextChunkIndex = evaluationTable.phaseCount * state->chunks.front() + state->phase;
const auto& chunkOutput = evaluationTable.outputs[nextChunkIndex];
state->chunks.pop_front();
Expand Down Expand Up @@ -217,4 +238,11 @@ PostTagHistory::EvaluationResult PostTagHistory::evaluate(const NamedRule& rule,
const CheckpointSpec& checkpoints) {
return implementation_->evaluate(rule, init, limits, checkpoints);
}

std::vector<PostTagHistory::EvaluationResult> PostTagHistory::evaluate(const NamedRule& rule,
const std::vector<TagState>& inits,
const EvaluationLimits& limits,
const CheckpointSpec& checkpoints) {
return implementation_->evaluate(rule, inits, limits, checkpoints);
}
} // namespace PostTagSystem
8 changes: 7 additions & 1 deletion libPostTagSystem/PostTagHistory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class PostTagHistory {
enum class ConclusionReason {
InvalidInput,
Terminated,
ReachedCheckpoint,
ReachedExplicitCheckpoint,
ReachedAutomaticCheckpoint,
MaxEventCountExceeded,
MaxTapeLengthExceeded
};
Expand Down Expand Up @@ -51,6 +52,11 @@ class PostTagHistory {
const EvaluationLimits& limits,
const CheckpointSpec& checkpointSpec = CheckpointSpec());

std::vector<EvaluationResult> evaluate(const NamedRule& rule,
const std::vector<TagState>& inits,
const EvaluationLimits& limits,
const CheckpointSpec& checkpointSpec = CheckpointSpec());

private:
class Implementation;
std::shared_ptr<Implementation> implementation_;
Expand Down
24 changes: 14 additions & 10 deletions libPostTagSystem/PostTagSearcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,35 @@ class PostTagSearcher::Implementation {
std::vector<EvaluationResult> evaluateGroup(const std::vector<TagState>& states,
const EvaluationParameters& parameters) {
// TODO(maxitg): Implement groupTimeConstraintNs parameter
// TODO(maxitg): Implement checkpoints parameter

std::vector<EvaluationResult> results;
results.reserve(states.size());
PostTagHistory evaluator;
PostTagHistory::EvaluationLimits limits;
limits.maxEventCount = parameters.maxEventCount;
limits.maxTapeLength = parameters.maxTapeLength;
for (const auto& init : states) {
const auto singleInitResult = evaluator.evaluate(PostTagHistory::NamedRule::Post, init, limits, {{}, {true}});
const auto singleInitResults =
evaluator.evaluate(PostTagHistory::NamedRule::Post, states, limits, {parameters.checkpoints, {true}});
for (size_t initIndex = 0; initIndex < states.size(); ++initIndex) {
EvaluationResult result;
result.eventCount = singleInitResult.eventCount;
result.maxTapeLength = singleInitResult.maxIntermediateTapeLength;
result.finalTapeLength = singleInitResult.finalState.tape.size();
result.initialState = init;
result.finalState = singleInitResult.finalState;
switch (singleInitResult.conclusionReason) {
result.eventCount = singleInitResults[initIndex].eventCount;
result.maxTapeLength = singleInitResults[initIndex].maxIntermediateTapeLength;
result.finalTapeLength = singleInitResults[initIndex].finalState.tape.size();
result.initialState = states[initIndex];
result.finalState = singleInitResults[initIndex].finalState;
switch (singleInitResults[initIndex].conclusionReason) {
case PostTagHistory::ConclusionReason::Terminated:
result.conclusionReason = ConclusionReason::Terminated;
break;

case PostTagHistory::ConclusionReason::ReachedCheckpoint:
case PostTagHistory::ConclusionReason::ReachedAutomaticCheckpoint:
result.conclusionReason = ConclusionReason::ReachedCycle;
break;

case PostTagHistory::ConclusionReason::ReachedExplicitCheckpoint:
result.conclusionReason = ConclusionReason::ReachedKnownCheckpoint;
break;

case PostTagHistory::ConclusionReason::MaxEventCountExceeded:
result.conclusionReason = ConclusionReason::MaxEventCountExceeded;
break;
Expand Down
28 changes: 22 additions & 6 deletions libPostTagSystem/test/PostTagSearcher_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,20 @@ TEST(PostTagSearcher, emptyCases) {

void compareResults(const TagState& init,
const PostTagSearcher::EvaluationResult& result,
uint64_t eventLimit = std::numeric_limits<uint64_t>::max() - 7) {
const PostTagHistory::EvaluationLimits& limits = PostTagHistory::EvaluationLimits(),
const std::vector<TagState>& checkpoints = {}) {
PostTagHistory singleHistoryEvaluator;
const auto singleResult = singleHistoryEvaluator.evaluate(
PostTagHistory::NamedRule::Post, init, PostTagHistory::EvaluationLimits(eventLimit), {{}, {true}});
const auto singleResult =
singleHistoryEvaluator.evaluate(PostTagHistory::NamedRule::Post, init, limits, {checkpoints, {true}});

if (singleResult.conclusionReason == PostTagHistory::ConclusionReason::InvalidInput) {
ASSERT_EQ(result.conclusionReason, PostTagSearcher::ConclusionReason::InvalidInput);
} else if (singleResult.conclusionReason == PostTagHistory::ConclusionReason::Terminated) {
ASSERT_EQ(result.conclusionReason, PostTagSearcher::ConclusionReason::Terminated);
} else if (singleResult.conclusionReason == PostTagHistory::ConclusionReason::ReachedCheckpoint) {
} else if (singleResult.conclusionReason == PostTagHistory::ConclusionReason::ReachedAutomaticCheckpoint) {
ASSERT_EQ(result.conclusionReason, PostTagSearcher::ConclusionReason::ReachedCycle);
} else if (singleResult.conclusionReason == PostTagHistory::ConclusionReason::ReachedExplicitCheckpoint) {
ASSERT_EQ(result.conclusionReason, PostTagSearcher::ConclusionReason::ReachedKnownCheckpoint);
} else if (singleResult.conclusionReason == PostTagHistory::ConclusionReason::MaxEventCountExceeded) {
ASSERT_EQ(result.conclusionReason, PostTagSearcher::ConclusionReason::MaxEventCountExceeded);
}
Expand Down Expand Up @@ -100,7 +103,20 @@ TEST(PostTagSearcher, eventLimit) {
{{0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1}, 0}, {{0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1}, 2}, parameters);
ASSERT_EQ(result.size(), 2);

compareResults(TagState({0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1}, 0), result[0], 104);
compareResults(TagState({0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1}, 1), result[1], 104);
compareResults(
TagState({0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1}, 0), result[0], PostTagHistory::EvaluationLimits(104));
compareResults(
TagState({0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1}, 1), result[1], PostTagHistory::EvaluationLimits(104));
}

TEST(PostTagSearcher, checkpoints) {
PostTagSearcher searcher;
PostTagSearcher::EvaluationParameters parameters;
parameters.checkpoints = {{{0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0}, 2}};
const auto result = searcher.evaluateRange(20, 123, 125, parameters);
ASSERT_EQ(result.size(), 6);

compareResults(TagState(20, 123, 0), result[0], PostTagHistory::EvaluationLimits(), parameters.checkpoints);
compareResults(TagState(20, 124, 0), result[3], PostTagHistory::EvaluationLimits(), parameters.checkpoints);
}
} // namespace PostTagSystem