Skip to content

Commit

Permalink
Fixing bugs and setting up tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Krulis committed May 25, 2018
1 parent 45ca73d commit 244e8c0
Show file tree
Hide file tree
Showing 15 changed files with 351 additions and 61 deletions.
8 changes: 7 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,19 @@ before_install:
- rm -rf isolate
# Install coveralls uploader
- pip install --user cpp-coveralls

# Install bats testing suite
- sudo add-apt-repository ppa:duggan/bats --yes
- sudo apt-get update -qq
- sudo apt-get install -qq bats

script:
- mkdir build
- cd build
- cmake ..
- make
- ctest -E tool_ --output-on-failure
- cd ./judges/recodex_token_judge
- bats ../../../judges/recodex_token_judge/tests

after_success:
- ctest -R tool_ --output-on-failure || true
Expand Down
96 changes: 95 additions & 1 deletion judges/recodex_token_judge/bpplib/algo/lcs.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Author: Martin Krulis <krulis@ksi.mff.cuni.cz>
* Last Modification: 14.5.2018
* Last Modification: 24.5.2018
* License: CC 3.0 BY-NC (http://creativecommons.org/)
*/
#ifndef BPPLIB_ALGO_LCS_HPP
Expand Down Expand Up @@ -61,6 +61,100 @@ namespace bpp
}
);
}



/**
* Implements a longes common subsequence algorithm, which founds only the length of the LCS itself.
* \tparam RES The result type (must be an integral type).
* \tparam CONTAINER Class holding the sequence. The class must have size() method
* and the comparator must be able to get values from the container based on their indices.
* \tparma COMPARATOR Comparator class holds a static method compare(seq1, i1, seq2, i2) -> bool.
* I.e., the comparator is also responsible for fetching values from the seq. containers.
*/
template<typename IDX = std::size_t, class CONTAINER, typename COMPARATOR>
void longest_common_subsequence(const CONTAINER &sequence1, const CONTAINER &sequence2,
std::vector<std::pair<IDX, IDX>> &common, COMPARATOR comparator)
{
struct Node {
std::pair<IDX, IDX> previous;
IDX length;
bool match;
};

common.clear();
if (sequence1.size() == 0 || sequence2.size() == 0) return;

const std::size_t size1 = sequence1.size();
const std::size_t size2 = sequence2.size();

// Prepare vector representing the LCS matrix ...
std::vector<Node> matrix((size1 + 1) * (size2 + 1));
for (std::size_t i = 0; i < size1; ++i) {
matrix[i + 1].previous.first = 1;
}
for (std::size_t i = 0; i < size2; ++i) {
matrix[(i + 1)*(size1 + 1)].previous.second = 1;
}

// Fill in the LCS matrix by dynamic programming
std::size_t i = size1 + 2; // current position in matrix (i == (c+1)*(size1+1) + (r+1))
for (std::size_t r = 0; r < size2; ++r) { // iterate over rows
for (std::size_t c = 0; c < size1; ++c) { // iterate over cols
matrix[i].match = comparator(sequence1, c, sequence2, r);

if (matrix[i].match) {
// Matching tokens should prolong the sequence...
matrix[i].length = matrix[i - size1 - 2].length + 1;
matrix[i].previous.first = 1;
matrix[i].previous.second = 1;
}
else {
IDX leftLength = matrix[i - 1].length;
IDX upperLength = matrix[i - size1 - 1].length;
if (leftLength >= upperLength) {
matrix[i].previous.first = 1;
matrix[i].length = leftLength;
}
else {
matrix[i].previous.second = 1;
matrix[i].length = upperLength;
}
}
++i;
}
++i; // skip the first (padding) column
}

// Collect the result path from the matrix...
std::size_t c = size1;
std::size_t r = size2;
while (c > 0 && r > 0) {
const Node &node = matrix[r * (size1 + 1) + c];
if (node.match) {
common.push_back(std::make_pair<IDX, IDX>(c - 1, r - 1));
}

c -= node.previous.first;
r -= node.previous.second;
}

// Fix the result (since it was callected backwards)...
std::reverse(common.begin(), common.end());
}


// Only an overload that uses default comparator.
template<typename IDX = std::size_t, class CONTAINER>
void longest_common_subsequence(const CONTAINER &sequence1, const CONTAINER &sequence2, std::vector<std::pair<IDX, IDX>> &common)
{
longest_common_subsequence<IDX>(sequence1, sequence2, common,
[](const CONTAINER &seq1, std::size_t i1, const CONTAINER &seq2, std::size_t i2) -> bool {
return seq1[i1] == seq2[i2];
});
}


}

#endif
12 changes: 11 additions & 1 deletion judges/recodex_token_judge/bpplib/cli/logger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class Logger
Logger& write(const T& data)
{
mAccumulator << data;
mAccumulatorSize = mAccumulator.tellp();
mAccumulatorSize = (std::size_t)mAccumulator.tellp();
return *this;
}

Expand Down Expand Up @@ -209,6 +209,16 @@ class Logger
}


/**
* Check whether the size of the log (for selected severity and above) is full (exceeds the size restriction).
* \param severity Applied severiry level. Only messages with this level and above are counted.
*/
bool isFull(LogSeverity severity = LogSeverity::ANY) const
{
return mMaxLength <= size(severity);
}


/**
* Empty the log, discard all data.
*/
Expand Down
44 changes: 29 additions & 15 deletions judges/recodex_token_judge/comparator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ template <typename STRING> bool try_get_int(const STRING &str, long int &res)
{
char *end;
res = std::strtol(str.c_str(), &end, 10);
return (end - str.c_str() == str.length());
return (end - str.c_str() == (int)str.length());
}


Expand All @@ -38,7 +38,7 @@ template <typename STRING> bool try_get_double(const STRING &str, double &res)
{
char *end;
res = std::strtod(str.c_str(), &end);
return (end - str.c_str() == str.length());
return (end - str.c_str() == (int)str.length());
}


Expand Down Expand Up @@ -212,15 +212,14 @@ template <typename CHAR = char, typename OFFSET = std::uint32_t, typename RESULT
TokenComparator<CHAR, OFFSET> &mTokenComparator; ///< Token comparator used for comparing tokens on the lines.
bool mShuffledTokens; ///< Whether the tokens on each line may be in arbitrary order.

// static result_t computeResult(std::size_t errors, std::size_t total)
//{
// double res = (double) std::numeric_limits<result_t>::max() * (double) errors / (double) total;
// return (result_t) std::round(res);
//}


/**
*
* Log one error of unordered token comparisson (a token is superfluous or missing).
* \tparam T Type of the token value.
* \param value The value to be logged.
* \param diff The difference (how many times the token was recorded or expected).
* If lower than zero, token was missing, otherwise the token is supefluous.
* \param line The index of the line where the error occured.
* \param caption Additional caption describing the type of the token in the log (e.g., 'token', 'int', ...).
*/
template <typename T>
void logError(const T &value, int diff, offset_t line, const std::string &caption = "token") const
Expand Down Expand Up @@ -248,15 +247,20 @@ template <typename CHAR = char, typename OFFSET = std::uint32_t, typename RESULT


/**
*
* Perform verification of map of valued from the unordered comparisson and log all errors.
* \tparam T Type of the token value.
* \tparam LOGGING If false, the check is performed silently. Otherwise, the errors are logged using bpp::log().
* \param mapValues The the map of values and their diffs to be checked.
* \param line The index of the line where the error occured.
* \param caption Additional caption describing the type of the token in the log (e.g., 'token', 'int', ...).
*/
template <typename T, bool LOGGING>
result_t checkMapValues(
const std::map<T, int> &mapValues, offset_t line, const std::string &caption = "token") const
{
result_t errorCount = 0;
for (auto &&it : mapValues) {
if (it.second != 0) ++errorCount;
errorCount += std::abs(it.second);
if (LOGGING) {
logError(it.first, it.second, line, caption);
}
Expand All @@ -266,7 +270,11 @@ template <typename CHAR = char, typename OFFSET = std::uint32_t, typename RESULT


/**
*
* Perform the unordered comparisson (the tokens on line may be in any order).
* \tparam LOGGING If false, the check is performed silently. Otherwise, the errors are logged using bpp::log().
* \param line1 The first line (correct) passed from the reader.
* \param line2 The second line (result) passed from the reader.
* \return Number of errors (i.e., 0 == lines match completely).
*/
template <bool LOGGING = false> result_t compareUnordered(const line_t &line1, const line_t &line2) const
{
Expand Down Expand Up @@ -323,6 +331,9 @@ template <typename CHAR = char, typename OFFSET = std::uint32_t, typename RESULT
/**
* Apply LCS algorithm to find the best matching between the two lines
* and determine the error as the number of tokens not present in the common subequence.
* \tparam LOGGING If false, the check is performed silently. Otherwise, the errors are logged using bpp::log().
* \param line1 The first line (correct) passed from the reader.
* \param line2 The second line (result) passed from the reader.
* \return Number of errors (i.e., 0 == lines match completely).
*/
template <bool LOGGING = false> result_t compareOrdered(const line_t &line1, const line_t &line2) const
Expand All @@ -334,11 +345,14 @@ template <typename CHAR = char, typename OFFSET = std::uint32_t, typename RESULT
line1.getToken(i1), line1[i1].length(), line2.getToken(i2), line2[i2].length());
});

if (LOGGING) {
result_t res = (result_t)(line1.size() - lcs + line2.size() - lcs);
if (LOGGING && res) {
// TODO
bpp::log().error() << "-" << line1.lineNumber() << ": " << line1.getRawLineAsString();
bpp::log().error() << "+" << line2.lineNumber() << ": " << line2.getRawLineAsString();
}

return (result_t)(lcs - line1.size() + lcs - line2.size());
return res;
}


Expand Down
Loading

0 comments on commit 244e8c0

Please sign in to comment.