Merge remote-tracking branch 'origin/master' into rename-go-util

This commit is contained in:
Ryan Curtin
2020-08-05 18:41:13 -04:00
51 changed files with 4521 additions and 2638 deletions
+5
View File
@@ -11,6 +11,11 @@
* Additional functionality for the ARFF loader (#2486); use case sensitive
categories (#2516).
* Add `bayesian_linear_regression` binding for the command-line, Python,
Julia, and Go. Also called "Bayesian Ridge", this is equivalent to a
version of linear regression where the regularization parameter is
automatically tuned (#2030).
### mlpack 3.3.2
###### 2020-06-18
* Added Noisy DQN to q_networks (#2446).
+9 -5
View File
@@ -94,7 +94,7 @@ copy "mlpack/tests/data/german.csv" and paste into a new "data" folder in your p
mat dataset;
bool loaded = mlpack::data::Load("data/german.csv", dataset);
if (!loaded)
return -1;
return -1;
@endcode
Then we need to extract the labels from the last dimension of the dataset and remove the
@@ -121,7 +121,7 @@ const size_t numTrees = 10;
RandomForest<GiniGain, RandomDimensionSelect> rf;
rf = RandomForest<GiniGain, RandomDimensionSelect>(dataset, labels,
numClasses, numTrees, minimumLeafSize);
numClasses, numTrees, minimumLeafSize);
@endcode
Now that the training is completed, we quickly compute the training accuracy:
@@ -143,7 +143,7 @@ to assess the quality of the trained model.
@code
const size_t k = 10;
KFoldCV<RandomForest<GiniGain, RandomDimensionSelect>, Accuracy> cv(k,
dataset, labels, numClasses);
dataset, labels, numClasses);
double cvAcc = cv.Evaluate(numTrees, minimumLeafSize);
cout << "\nKFoldCV Accuracy: " << cvAcc;
@endcode
@@ -188,12 +188,16 @@ Finally, the ultimate goal is to classify a new sample using the previously trai
Random Forest classifier provides both predictions and probabilities, we obtain both.
@code
mat sample("2 12 2 13 1 2 2 1 3 24 3 1 1 1 1 1 0 1 0 1 0 0 0");
// Create a test sample containing only one point. Because Armadillo is
// column-major, this matrix has one column (one point) and the number of rows
// is equal to the dimensionality of the point (23).
mat sample("2; 12; 2; 13; 1; 2; 2; 1; 3; 24; 3; 1; 1; 1; 1; 1; 0; 1; 0; 1;"
" 0; 0; 0");
mat probabilities;
rf.Classify(sample, predictions, probabilities);
u64 result = predictions.at(0);
cout << "\nClassification result: " << result << " , Probabilities: " <<
probabilities.at(0) << "/" << probabilities.at(1);
probabilities.at(0) << "/" << probabilities.at(1);
@endcode
@section sample_app_conclussion Final thoughts
+2
View File
@@ -1,6 +1,8 @@
# Define the files we need to compile.
# Anything not in this list will not be compiled into mlpack.
set(SOURCES
bleu.hpp
bleu_impl.hpp
ip_metric.hpp
ip_metric_impl.hpp
iou_metric.hpp
+169
View File
@@ -0,0 +1,169 @@
/**
* @file core/metrics/bleu.hpp
* @author Mrityunjay Tripathi
*
* Definition of BLEU class.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_CORE_METRICS_BLEU_HPP
#define MLPACK_CORE_METRICS_BLEU_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace metric {
/**
* BLEU, or the Bilingual Evaluation Understudy, is an algorithm for evaluating
* the quality of text which has been machine translated from one natural
* language to another. It can also be used to evaluate text generated for a
* suite of natural language processing tasks.
*
* The BLEU score is calculated using the following formula:
*
* \f{eqnarray*}{
* \text{B} &=& bp \cdot \exp \left(\sum_{n=1}^{N} w \log p_n \right) \\
* \text{where,} \\
* bp &=& \text{brevity penalty} =
* \begin{cases}
* 1 & \text{if ratio} > 1 \\
* \exp \left(1-\frac{1}{ratio}\right) & \text{otherwise}
* \end{cases} \\
* p_n &=& \text{modified precision for n-gram,} \\
* w &=& \frac {1}{maxOrder}, \\
* ratio &=& \text{translation to reference length ratio,} \\
* maxOrder &=& \text{maximum length of tokens in n-grams.}
* \f}
*
* The value of BLEU Score lies in between 0 and 1.
*
* @tparam ElemType Type of the quantities in BLEU, e.g. (long double,
* double, float).
* @tparam PrecisionType Container type for precision for corresponding order.
* e.g. (std::vector<float>, std::vector<double>, or any such boost or
* armadillo container).
*/
template <typename ElemType = float,
typename PrecisionType = std::vector<ElemType>
>
class BLEU
{
public:
/**
* Create an instance of BLEU class.
*
* @param maxOrder The maximum length of tokens in n-grams.
*/
BLEU(const size_t maxOrder = 4);
/**
* Computes the BLEU Score.
*
* @tparam ReferenceCorpusType Type of reference corpus.
* @tparam TranslationCorpusType Type of translation corpus.
* @param referenceCorpus It is an array of various references or documents.
* So, the \f$ referenceCorpus = \{reference_1, reference_2, \ldots \} \f$
* and each reference is an array of paragraphs. So,
* \f$ reference_i = \{paragraph_1, paragraph_2, \ldots \} \f$
* and then each paragraph is an array of tokenized words/string. Like,
* \f$ paragraph_i = \{word_1, word_2, \ldots \} \f$.
* For ex.
* ```
* refCorpus = {{{"this", "is", "paragraph", "1", "from", "document", "1"},
* {"this", "is", "paragraph", "2", "from", "document", "1"}},
*
* {{"this", "is", "paragraph", "1", "from", "document", "2"},
* {"this", "is", "paragraph", "2", "from", "document", "2"}}}
* ```
* @param translationCorpus It is an array of paragraphs which has been
* machine translated or generated for any natural language processing task.
* Like, \f$ translationCorpus = \{paragraph_1, paragraph_2, \ldots \} \f$.
* And then, each paragraph is an array of words. The ith paragraph from the
* corpus is \f$ paragraph_i = \{word_1, word_2, \ldots \} \f$.
* For ex.
* ```
* transCorpus = {{"this", "is", "generated", "paragraph", "1"},
* {"this", "is", "generated", "paragraph", "2"}}
* ```
* @param smooth Whether or not to apply Lin et al. 2004 smoothing.
* @return The Evaluate method returns the BLEU Score. This method also
* calculates other BLEU metrics (brevity penalty, translation length, reference
* length, ratio and precisions) which can be accessed by their corresponding
* accessor methods.
*/
template <typename ReferenceCorpusType, typename TranslationCorpusType>
ElemType Evaluate(const ReferenceCorpusType& referenceCorpus,
const TranslationCorpusType& translationCorpus,
const bool smooth = false);
//! Serialize the metric.
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */);
//! Get the value of maximum length of tokens in n-grams.
size_t MaxOrder() const { return maxOrder; }
//! Modify the value of maximum length of tokens in n-grams.
size_t& MaxOrder() { return maxOrder; }
//! Get the BLEU Score.
ElemType BLEUScore() const { return bleuScore; }
//! Get the brevity penalty.
ElemType BrevityPenalty() const { return brevityPenalty; }
//! Get the value of translation length.
size_t TranslationLength() const { return translationLength; }
//! Get the value of reference length.
size_t ReferenceLength() const { return referenceLength; }
//! Get the ratio of translation to reference length ratio.
ElemType Ratio() const { return ratio; }
//! Get the precisions for corresponding order.
PrecisionType const& Precisions() const { return precisions; }
private:
/**
* Extracts all the n-grams.
*
* @tparam WordVector Type of the tokenized vector.
* @param segment Tokenized sequence represented in form of vector.
*/
template <typename WordVector>
std::map<WordVector, size_t> GetNGrams(const WordVector& segment);
//! Locally-stored value of maximum length of tokens in n-grams.
size_t maxOrder;
//! Locally-stored BLEU score.
ElemType bleuScore;
//! Locally-stored brevity penalty. It is a penalty for short machine
//! translation.
ElemType brevityPenalty;
//! Locally-stored translation length.
size_t translationLength;
//! Locally-stored reference length.
size_t referenceLength;
//! Locally-stored translation to reference length ratio.
ElemType ratio;
//! Locally stored precision for corresponding order.
PrecisionType precisions;
};
} // namespace metric
} // namespace mlpack
// Include implementation.
#include "bleu_impl.hpp"
#endif
+200
View File
@@ -0,0 +1,200 @@
/**
* @file core/metrics/bleu_impl.hpp
* @author Mrityunjay Tripathi
*
* Implementation of BLEU class.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_CORE_METRICS_BLEU_IMPL_HPP
#define MLPACK_CORE_METRICS_BLEU_IMPL_HPP
// In case it hasn't been included.
#include "bleu.hpp"
namespace mlpack {
namespace metric {
template <typename ElemType, typename PrecisionType>
BLEU<ElemType, PrecisionType>::BLEU(const size_t maxOrder) :
maxOrder(maxOrder),
translationLength(0),
referenceLength(0)
{
// Nothing to do here.
}
template <typename ElemType, typename PrecisionType>
template <typename WordVector>
std::map<WordVector, size_t> BLEU<ElemType, PrecisionType>::GetNGrams(
const WordVector& segment)
{
std::map<WordVector, size_t> ngramsCount;
for (size_t order = 1; order < maxOrder + 1; ++order)
{
for (size_t i = 0; i + order < segment.size() + 1; ++i)
{
WordVector seq = WordVector(segment.cbegin() + i,
segment.cbegin() + i + order);
ngramsCount[seq]++;
}
}
return ngramsCount;
}
template <typename ElemType, typename PrecisionType>
template <typename ReferenceCorpusType, typename TranslationCorpusType>
ElemType BLEU<ElemType, PrecisionType>::Evaluate(
const ReferenceCorpusType& referenceCorpus,
const TranslationCorpusType& translationCorpus,
const bool smooth)
{
// WordVector is a string container type.
// Also, TranslationCorpusType is an array of such containers.
typedef typename TranslationCorpusType::value_type WordVector;
// matchesByOrder: It catches how many times sequence of a particular order
// is encountered in both reference corpus and translation corpus.
std::vector<size_t> matchesByOrder(maxOrder, 0);
// possibleMatchesByOrder: It tracks how many possible matches can be in the
// translation corpus.
std::vector<size_t> possibleMatchesByOrder(maxOrder, 0);
// referenceLength: It is the sum of minimum length of the paragraph from
// various documents.
// translationLength: It is the sum of length of each paragraphs.
referenceLength = 0, translationLength = 0;
auto refIt = referenceCorpus.cbegin();
auto trIt = translationCorpus.cbegin();
for (; refIt != referenceCorpus.cend() && trIt != translationCorpus.cend();
++refIt, ++trIt)
{
size_t min = std::numeric_limits<size_t>::max();
for (const auto& t : *refIt)
{
if (min > t.size())
{
min = t.size();
}
}
if (min == std::numeric_limits<size_t>::max())
min = 0;
referenceLength += min;
translationLength += trIt->size();
// mergedRefNGramCounts: It accumulates all the similar n-grams from
// various references or documents, so that there is no repetition of
// any key (sequence of order n).
std::map<WordVector, size_t> mergedRefNGramCounts;
for (const auto& t : *refIt)
{
// ngram: It holds the n-grams of each document/reference.
const std::map<WordVector, size_t> ngrams = GetNGrams(t);
for (auto it = ngrams.cbegin(); it != ngrams.cend(); ++it)
{
mergedRefNGramCounts[it->first] = std::max(it->second,
mergedRefNGramCounts[it->first]);
}
}
// translationNGramCounts: It extracts the n-grams of the generated text
// sequence.
const std::map<WordVector, size_t> translationNGramCounts
= GetNGrams(*trIt);
// overlap: It holds those keys (sequence of order n) which are common to
// reference corpus and translation corpus.
std::map<WordVector, size_t> overlap;
for (auto it = translationNGramCounts.cbegin();
it != translationNGramCounts.cend();
++it)
{
auto mergedIt = mergedRefNGramCounts.find(it->first);
if (mergedIt != mergedRefNGramCounts.end())
{
// If the key (sequence of order n) is present in both translation
// corpus as well as reference corpus, then the minimum number of
// counts it has occurred in any is considered.
overlap[it->first] = std::min(mergedIt->second, it->second);
}
}
for (auto it = overlap.cbegin(); it != overlap.cend(); ++it)
{
matchesByOrder[it->first.size() - 1] += it->second;
}
for (size_t order = 1; order < maxOrder + 1; ++order)
{
if (order < trIt->size() + 1)
possibleMatchesByOrder[order - 1] += trIt->size() - order + 1;
}
}
precisions = PrecisionType(maxOrder, 0.0);
if (smooth)
{
for (size_t i = 0; i < maxOrder; ++i)
{
precisions[i]
= (matchesByOrder[i] + 1.0) / (possibleMatchesByOrder[i] + 1.0);
}
}
else
{
for (size_t i = 0; i < maxOrder; ++i)
{
if (possibleMatchesByOrder[i] > 0)
precisions[i] = ElemType(matchesByOrder[i]) / possibleMatchesByOrder[i];
else
precisions[i] = 0.0;
}
}
ElemType minPrecision = std::numeric_limits<ElemType>::max();
for (size_t i = 0; i < maxOrder; ++i)
{
if (minPrecision > precisions[i])
minPrecision = precisions[i];
}
ElemType geometricMean;
if (minPrecision > 0)
{
ElemType pLogSum = 0.0;
for (const auto& t : precisions)
{
pLogSum += (1.0 / maxOrder) * std::log(t);
}
geometricMean = std::exp(pLogSum);
}
else
geometricMean = 0.0;
ratio = ElemType(translationLength) / referenceLength;
brevityPenalty = (ratio > 1.0) ? 1.0 : std::exp(1.0 - 1.0 / ratio);
bleuScore = geometricMean * brevityPenalty;
return bleuScore;
}
template <typename ElemType, typename PrecisionType>
template <typename Archive>
void BLEU<ElemType, PrecisionType>::serialize(
Archive& ar,
const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(maxOrder);
}
} // namespace metric
} // namespace mlpack
#endif
+1
View File
@@ -6,6 +6,7 @@ set(DIRS
ann
approx_kfn
bias_svd
bayesian_linear_regression
block_krylov_svd
cf
dbscan
+2 -8
View File
@@ -39,7 +39,7 @@ FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::FFN(
height(0),
reset(false),
numFunctions(0),
deterministic(true)
deterministic(false)
{
/* Nothing to do here. */
}
@@ -60,7 +60,7 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::ResetData(
numFunctions = responses.n_cols;
this->predictors = std::move(predictors);
this->responses = std::move(responses);
this->deterministic = true;
this->deterministic = false;
ResetDeterministic();
if (!reset)
@@ -158,12 +158,6 @@ void FFN<OutputLayerType, InitializationRuleType, CustomLayers...>::Forward(
if (parameter.is_empty())
ResetParameters();
if (!deterministic)
{
deterministic = true;
ResetDeterministic();
}
Forward(inputs);
results = boost::apply_visitor(outputParameterVisitor, network.back());
}
+22 -17
View File
@@ -17,11 +17,17 @@
#include <mlpack/methods/ann/layer/layer_traits.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
namespace ann /* Artificial Neural Network. */ {
/**
* Implementation of the Lookup class. The Lookup class is a particular
* convolution, where the width of the convolution is 1.
* The Lookup class stores word embeddings and retrieves them using tokens. The
* Lookup layer is always the first layer of the network. The input to the
* Lookup class is a matrix of shape (sequenceLength, batchSize). The matrix
* consists of tokens which are used to lookup the table (i.e. weights) to find
* the embeddings of those tokens.
*
* The input shape : (sequenceLength, batchSize).
* The output shape : (sequenceLength * embeddingSize, batchSize).
*
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
@@ -36,13 +42,12 @@ class Lookup
{
public:
/**
* Create the Lookup object using the specified number of input and output
* units.
* Create the Lookup object using the specified vocabulary and embedding size.
*
* @param inSize The number of input units.
* @param outSize The number of output units.
* @param vocabSize The size of the vocabulary.
* @param embeddingSize The length of each embedding vector.
*/
Lookup(const size_t inSize = 0, const size_t outSize = 0);
Lookup(const size_t vocabSize = 0, const size_t embeddingSize = 0);
/**
* Ordinary feed forward pass of a neural network, evaluating the function
@@ -68,7 +73,7 @@ class Lookup
const arma::Mat<eT>& gy,
arma::Mat<eT>& g);
/*
/**
* Calculate the gradient using the output delta and the input activation.
*
* @param input The input parameter used for calculating the gradient.
@@ -100,11 +105,11 @@ class Lookup
//! Modify the gradient.
OutputDataType& Gradient() { return gradient; }
//! Get the number of input units.
size_t InSize() const { return inSize; }
//! Get the size of the vocabulary.
size_t VocabSize() const { return vocabSize; }
//! Get the number of output units.
size_t OutSize() const { return outSize; }
//! Get the length of each embedding vector.
size_t EmbeddingSize() const { return embeddingSize; }
/**
* Serialize the layer
@@ -113,11 +118,11 @@ class Lookup
void serialize(Archive& ar, const unsigned int /* version */);
private:
//! Locally-stored number of input units.
size_t inSize;
//! Locally-stored size of the vocabulary.
size_t vocabSize;
//! Locally-stored number of output units.
size_t outSize;
//! Locally-stored length of each embedding vector.
size_t embeddingSize;
//! Locally-stored weight object.
OutputDataType weights;
+43 -13
View File
@@ -21,12 +21,12 @@ namespace ann /** Artificial Neural Network. */ {
template <typename InputDataType, typename OutputDataType>
Lookup<InputDataType, OutputDataType>::Lookup(
const size_t inSize,
const size_t outSize) :
inSize(inSize),
outSize(outSize)
const size_t vocabSize,
const size_t embeddingSize) :
vocabSize(vocabSize),
embeddingSize(embeddingSize)
{
weights.set_size(outSize, inSize);
weights.set_size(vocabSize, embeddingSize);
}
template<typename InputDataType, typename OutputDataType>
@@ -34,17 +34,30 @@ template<typename eT>
void Lookup<InputDataType, OutputDataType>::Forward(
const arma::Mat<eT>& input, arma::Mat<eT>& output)
{
output = weights.cols(arma::conv_to<arma::uvec>::from(input) - 1);
const size_t seqLength = input.n_rows;
const size_t batchSize = input.n_cols;
output.set_size(seqLength * embeddingSize, batchSize);
for (size_t i = 0; i < batchSize; ++i)
{
//! ith column of output is a vectorized form of a matrix of shape
//! (seqLength, embeddingSize) selected as a combination of rows from the
//! weights. The MultiheadAttention class requires this particular ordering
//! of matrix dimensions.
output.col(i) = arma::vectorise(weights.rows(
arma::conv_to<arma::uvec>::from(input.col(i)) - 1));
}
}
template<typename InputDataType, typename OutputDataType>
template<typename eT>
void Lookup<InputDataType, OutputDataType>::Backward(
const arma::Mat<eT>& /* input */,
const arma::Mat<eT>& gy,
arma::Mat<eT>& g)
const arma::Mat<eT>& /* gy */,
arma::Mat<eT>& /* g */)
{
g = gy;
Log::Fatal << "Lookup cannot be used as an intermediate layer." << std::endl;
}
template<typename InputDataType, typename OutputDataType>
@@ -54,8 +67,20 @@ void Lookup<InputDataType, OutputDataType>::Gradient(
const arma::Mat<eT>& error,
arma::Mat<eT>& gradient)
{
gradient = arma::zeros<arma::Mat<eT> >(weights.n_rows, weights.n_cols);
gradient.cols(arma::conv_to<arma::uvec>::from(input) - 1) = error;
const size_t seqLength = input.n_rows;
const size_t batchSize = input.n_cols;
arma::Cube<eT> errorTemp(const_cast<arma::Mat<eT>&>(error).memptr(),
seqLength, embeddingSize, batchSize, false, false);
gradient.set_size(arma::size(weights));
gradient.zeros();
for (size_t i = 0; i < batchSize; ++i)
{
gradient.rows(arma::conv_to<arma::uvec>::from(input.col(i)) - 1)
+= errorTemp.slice(i);
}
}
template<typename InputDataType, typename OutputDataType>
@@ -63,8 +88,13 @@ template<typename Archive>
void Lookup<InputDataType, OutputDataType>::serialize(
Archive& ar, const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(inSize);
ar & BOOST_SERIALIZATION_NVP(outSize);
ar & BOOST_SERIALIZATION_NVP(vocabSize);
ar & BOOST_SERIALIZATION_NVP(embeddingSize);
// This is inefficient, but we have to allocate this memory so that
// WeightSetVisitor gets the right size.
if (Archive::is_loading::value)
weights.set_size(vocabSize, embeddingSize);
}
} // namespace ann
@@ -33,6 +33,8 @@ set(SOURCES
reconstruction_loss_impl.hpp
sigmoid_cross_entropy_error.hpp
sigmoid_cross_entropy_error_impl.hpp
soft_margin_loss.hpp
soft_margin_loss_impl.hpp
hinge_embedding_loss.hpp
hinge_embedding_loss_impl.hpp
empty_loss.hpp
@@ -0,0 +1,100 @@
/**
* @file methods/ann/loss_functions/soft_margin_loss.hpp
* @author Anjishnu Mukherjee
*
* Definition of the Soft Margin Loss function.
*
* It is a criterion that optimizes a two-class classification logistic loss,
* between input x and target y, both having the same shape, with the target
* containing only the values 1 or -1.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_ANN_LOSS_FUNCTION_SOFT_MARGIN_LOSS_HPP
#define MLPACK_ANN_LOSS_FUNCTION_SOFT_MARGIN_LOSS_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace ann /** Artificial Neural Network. */ {
/**
* @tparam InputDataType Type of the input data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
* @tparam OutputDataType Type of the output data (arma::colvec, arma::mat,
* arma::sp_mat or arma::cube).
*/
template <
typename InputDataType = arma::mat,
typename OutputDataType = arma::mat
>
class SoftMarginLoss
{
public:
/**
* Create the SoftMarginLoss object.
*
* @param reduction Specifies the reduction to apply to the output. If false,
* 'mean' reduction is used, where sum of the output will be
* divided by the number of elements in the output. If
* true, 'sum' reduction is used and the output will be
* summed. It is set to true by default.
*/
SoftMarginLoss(const bool reduction = true);
/**
* Computes the Soft Margin Loss function.
*
* @param input Input data used for evaluating the specified function.
* @param target The target vector with same shape as input.
*/
template<typename InputType, typename TargetType>
typename InputType::elem_type Forward(const InputType& input,
const TargetType& target);
/**
* Ordinary feed backward pass of a neural network.
*
* @param input The propagated input activation.
* @param target The target vector.
* @param output The calculated error.
*/
template<typename InputType, typename TargetType, typename OutputType>
void Backward(const InputType& input,
const TargetType& target,
OutputType& output);
//! Get the output parameter.
OutputDataType& OutputParameter() const { return outputParameter; }
//! Modify the output parameter.
OutputDataType& OutputParameter() { return outputParameter; }
//! Get the type of reduction used.
bool Reduction() const { return reduction; }
//! Modify the type of reduction used.
bool& Reduction() { return reduction; }
/**
* Serialize the layer.
*/
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */);
private:
//! Locally-stored output parameter object.
OutputDataType outputParameter;
//! The boolean value that tells if reduction is sum or mean.
bool reduction;
}; // class SoftMarginLoss
} // namespace ann
} // namespace mlpack
// include implementation.
#include "soft_margin_loss_impl.hpp"
#endif
@@ -0,0 +1,72 @@
/**
* @file methods/ann/loss_functions/soft_margin_loss_impl.hpp
* @author Anjishnu Mukherjee
*
* Implementation of the Soft Margin Loss function.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_METHODS_ANN_LOSS_FUNCTION_SOFT_MARGIN_LOSS_IMPL_HPP
#define MLPACK_METHODS_ANN_LOSS_FUNCTION_SOFT_MARGIN_LOSS_IMPL_HPP
// In case it hasn't been included.
#include "soft_margin_loss.hpp"
namespace mlpack {
namespace ann /** Artifical Neural Network. */ {
template<typename InputDataType, typename OutputDataType>
SoftMarginLoss<InputDataType, OutputDataType>::
SoftMarginLoss(const bool reduction) : reduction(reduction)
{
// Nothing to do here.
}
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename TargetType>
typename InputType::elem_type
SoftMarginLoss<InputDataType, OutputDataType>::Forward(
const InputType& input, const TargetType& target)
{
InputType loss = arma::log(1 + arma::exp(-target % input));
typename InputType::elem_type lossSum = arma::accu(loss);
if (reduction)
return lossSum;
return lossSum / input.n_elem;
}
template<typename InputDataType, typename OutputDataType>
template<typename InputType, typename TargetType, typename OutputType>
void SoftMarginLoss<InputDataType, OutputDataType>::Backward(
const InputType& input,
const TargetType& target,
OutputType& output)
{
output.set_size(size(input));
InputType temp = arma::exp(-target % input);
InputType numerator = -target % temp;
InputType denominator = 1 + temp;
output = numerator / denominator;
if (!reduction)
output = output / input.n_elem;
}
template<typename InputDataType, typename OutputDataType>
template<typename Archive>
void SoftMarginLoss<InputDataType, OutputDataType>::serialize(
Archive& ar,
const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(reduction);
}
} // namespace ann
} // namespace mlpack
#endif
@@ -0,0 +1,21 @@
# Define the files we need to compile
# Anything not in this list will not be compiled into the output library
set(SOURCES
bayesian_linear_regression.hpp
bayesian_linear_regression_impl.hpp
bayesian_linear_regression.cpp
)
# add directory name to sources
set(DIR_SRCS)
foreach(file ${SOURCES})
set(DIR_SRCS ${DIR_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/${file})
endforeach()
# append sources (with directory name) to list of all mlpack sources (used at the parent scope)
set(MLPACK_SRCS ${MLPACK_SRCS} ${DIR_SRCS} PARENT_SCOPE)
add_cli_executable(bayesian_linear_regression)
add_python_binding(bayesian_linear_regression)
add_julia_binding(bayesian_linear_regression)
add_go_binding(bayesian_linear_regression)
add_markdown_docs(bayesian_linear_regression "cli;python;julia;go" "regression")
@@ -0,0 +1,188 @@
/**
* @file methods/bayesian_linear_regression/bayesian_linear_regression.cpp
* @author Clement Mercier
*
* Implementation of Bayesian linear regression.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include "bayesian_linear_regression.hpp"
#include <mlpack/core/util/log.hpp>
#include <mlpack/core/util/timers.hpp>
using namespace mlpack;
using namespace mlpack::regression;
BayesianLinearRegression::BayesianLinearRegression(const bool centerData,
const bool scaleData,
const size_t nIterMax,
const double tol) :
centerData(centerData),
scaleData(scaleData),
nIterMax(nIterMax),
tol(tol),
responsesOffset(0.0),
alpha(0.0),
beta(0.0),
gamma(0.0)
{/* Nothing to do */}
double BayesianLinearRegression::Train(const arma::mat& data,
const arma::rowvec& responses)
{
Timer::Start("bayesian_linear_regression");
arma::mat phi;
arma::rowvec t;
arma::colvec eigVal;
arma::mat eigVec;
// Preprocess the data. Center and scale.
responsesOffset = CenterScaleData(data, responses, phi, t);
if (!arma::eig_sym(eigVal, eigVec, arma::symmatu(phi * phi.t())))
{
Log::Fatal << "BayesianLinearRegression::Train(): Eigendecomposition "
<< "of covariance failed!" << std::endl;
}
// Compute this quantities once and for all.
const arma::mat eigVecInv = inv(eigVec);
const arma::colvec eigVecInvPhitT = eigVecInv * phi * t.t();
// Initialize the hyperparameters and begin with an infinitely broad prior.
alpha = 1e-6;
beta = 1 / (var(t, 1) * 0.1);
unsigned short i = 0;
double deltaAlpha = 1.0, deltaBeta = 1.0, crit = 1.0;
while ((crit > tol) && (i < nIterMax))
{
deltaAlpha = -alpha;
deltaBeta = -beta;
// Update the solution.
omega = eigVec * diagmat(1 / (eigVal + (alpha / beta))) * eigVecInvPhitT;
// Update alpha.
gamma = sum(eigVal / (alpha / beta + eigVal));
alpha = gamma / dot(omega, omega);
// Update beta.
const arma::rowvec temp = t - omega.t() * phi;
beta = (data.n_cols - gamma) / dot(temp, temp);
// Compute the stopping criterion.
deltaAlpha += alpha;
deltaBeta += beta;
crit = std::abs(deltaAlpha / alpha + deltaBeta / beta);
i++;
}
// Compute the covariance matrix for the uncertainties later.
matCovariance = eigVec * diagmat(1 / (beta * eigVal + alpha)) * eigVecInv;
Timer::Stop("bayesian_linear_regression");
return RMSE(data, responses);
}
void BayesianLinearRegression::Predict(const arma::mat& points,
arma::rowvec& predictions) const
{
// Center and scale the points before applying the model.
arma::mat matX;
CenterScaleDataPred(points, matX);
predictions = omega.t() * matX + responsesOffset;
}
void BayesianLinearRegression::Predict(const arma::mat& points,
arma::rowvec& predictions,
arma::rowvec& std) const
{
// Center and scale the points before applying the model.
arma::mat matX;
CenterScaleDataPred(points, matX);
predictions = omega.t() * matX + responsesOffset;
// Compute the standard deviation for each point.
std = sqrt(Variance() + sum(matX % (matCovariance * matX), 0));
}
double BayesianLinearRegression::RMSE(const arma::mat& data,
const arma::rowvec& responses) const
{
arma::rowvec predictions;
Predict(data, predictions);
return sqrt(mean(square(responses - predictions)));
}
double BayesianLinearRegression::CenterScaleData(const arma::mat& data,
const arma::rowvec& responses,
arma::mat& dataProc,
arma::rowvec& responsesProc)
{
if (!centerData && !scaleData)
{
dataProc = arma::mat(const_cast<double*>(data.memptr()), data.n_rows,
data.n_cols, false, true);
responsesProc = arma::rowvec(const_cast<double*>(responses.memptr()),
responses.n_elem, false,
true);
}
else if (centerData && !scaleData)
{
dataOffset = mean(data, 1);
responsesOffset = mean(responses);
dataProc = data.each_col() - dataOffset;
responsesProc = responses - responsesOffset;
}
else if (!centerData && scaleData)
{
dataScale = stddev(data, 0, 1);
dataProc = data.each_col() / dataScale;
responsesProc = arma::rowvec(const_cast<double*>(responses.memptr()),
responses.n_elem, false,
true);
}
else
{
dataOffset = mean(data, 1);
dataScale = stddev(data, 0, 1);
responsesOffset = mean(responses);
dataProc = (data.each_col() - dataOffset).each_col() / dataScale;
responsesProc = responses - responsesOffset;
}
return responsesOffset;
}
void BayesianLinearRegression::CenterScaleDataPred(
const arma::mat& data,
arma::mat& dataProc) const
{
if (!centerData && !scaleData)
{
dataProc = arma::mat(const_cast<double*>(data.memptr()), data.n_rows,
data.n_cols, false, true);
}
else if (centerData && !scaleData)
{
dataProc = data.each_col() - dataOffset;
}
else if (!centerData && scaleData)
{
dataProc = data.each_col() / dataScale;
}
else
{
dataProc = (data.each_col() - dataOffset).each_col() / dataScale;
}
}
@@ -0,0 +1,285 @@
/**
* @file methods/bayesian_linear_regression/bayesian_linear_regression.hpp
* @author Clement Mercier
*
* Definition of the BayesianRidge class, which performs the
* bayesian linear regression. According to the armadillo standards,
* all the functions consider data in column-major format.
**/
#ifndef MLPACK_METHODS_BAYESIAN_LINEAR_REGRESSION_HPP
#define MLPACK_METHODS_BAYESIAN_LINEAR_REGRESSION_HPP
#include <mlpack/prereqs.hpp>
namespace mlpack {
namespace regression {
/**
* A Bayesian approach to the maximum likelihood estimation of the parameters
* \f$ \omega \f$ of the linear regression model. The Complexity is governed by
* the addition of a gaussian isotropic prior of precision \f$ \alpha \f$ over
* \f$ \omega \f$:
*
* \f[
* p(\omega|\alpha) = \mathcal{N}(\omega|0, \alpha^{-1}I)
* \f]
*
* The optimization procedure calculates the posterior distribution of
* \f$ \omega \f$ knowing the data by maximizing an approximation of the log
* marginal likelihood derived from a type II maximum likelihood approximation.
* The determination of \f$ alpha \f$ and of the noise precision \f$ beta \f$
* is part of the optimization process, leading to an automatic determination of
* w. The model being entirely based on probabilty distributions, uncertainties
* are available and easly computed for both the parameters and the predictions.
*
* The advantage over linear regression and ridge regression is that the
* regularization is determined from all the training data alone without any
* require to an hold out method.
*
* The code below is an implementation of the maximization of the evidence
* function described in the section 3.5.2 of the C.Bishop book, Pattern
* Recognition and Machine Learning.
*
* @code
* @article{MacKay91bayesianinterpolation,
* author = {David J.C. MacKay},
* title = {Bayesian Interpolation},
* journal = {NEURAL COMPUTATION},
* year = {1991},
* volume = {4},
* pages = {415--447}
* }
* @endcode
*
* @code
* @book{Bishop:2006:PRM:1162264,
* author = {Bishop, Christopher M.},
* title = {Pattern Recognition and Machine Learning (Information Science
* and Statistics)},
* chapter = {3}
* year = {2006},
* isbn = {0387310738},
* publisher = {Springer-Verlag},
* address = {Berlin, Heidelberg},
* }
* @endcode
*
* Example of use:
*
* @code
* arma::mat xTrain; // Train data matrix. Column-major.
* arma::rowvec yTrain; // Train target values.
* // Train the model. Regularization strength is optimally tunned with the
* // training data alone by applying the Train method.
* BayesianLinearRegression estimator(); // Instanciate the estimator with default option.
* estimator.Train(xTrain, yTrain);
* // Prediction on test points.
* arma::mat xTest; // Test data matrix. Column-major.
* arma::rowvec predictions;
* estimator.Predict(xTest, prediction);
* arma::rowvec yTest; // Test target values.
* estimator.RMSE(xTest, yTest); // Evaluate using the RMSE score.
* // Compute the standard deviations of the predictions.
* arma::rowvec stds;
* estimator.Predict(xTest, responses, stds)
* @endcode
*/
class BayesianLinearRegression
{
public:
/**
* Set the parameters of Bayesian Ridge regression object. The
* regularization parameter is automatically set to its optimal value by
* maximization of the marginal likelihood.
*
* @param centerData Whether or not center the data according to the
* examples.
* @param scaleData Whether or not scale the data according to the
* standard deviation of each feature.
* @param nIterMax Maximum number of iterations for convergency.
* @param tol Level from which the solution is considered sufficientlly
* stable.
*/
BayesianLinearRegression(const bool centerData = true,
const bool scaleData = false,
const size_t nIterMax = 50,
const double tol = 1e-4);
/**
* Run BayesianLinearRegression. The input matrix (like all mlpack matrices) should be
* column-major -- each column is an observation and each row is a dimension.
*
* @param data Column-major input data, dim(P, N).
* @param responses A vector of targets, dim(N).
* @return Root mean squared error.
*/
double Train(const arma::mat& data,
const arma::rowvec& responses);
/**
* Predict \f$y_{i}\f$ for each data point in the given data matrix using the
* currently-trained Bayesian Ridge model.
*
* @param points The data points to apply the model.
* @param predictions y, Contains the predicted values on completion.
* @return Root mean squared error computed on the train set.
*/
void Predict(const arma::mat& points,
arma::rowvec& predictions) const;
/**
* Predict \f$y_{i}\f$ and the standard deviation of the predictive posterior
* distribution for each data point in the given data matrix, using the
* currently-trained Bayesian Ridge estimator.
*
* @param points The data point to apply the model.
* @param predictions Vector which will contain calculated values on completion.
* @param std Standard deviations of the predictions.
*/
void Predict(const arma::mat& points,
arma::rowvec& predictions,
arma::rowvec& std) const;
/**
* Compute the Root Mean Square Error between the predictions returned by the
* model and the true responses.
*
* @param data Data points to predict
* @param responses A vector of targets.
* @return Root mean squared error.
**/
double RMSE(const arma::mat& data,
const arma::rowvec& responses) const;
/**
* Get the solution vector.
*
* @return omega Solution vector.
*/
const arma::colvec& Omega() const { return omega; }
/**
* Get the precision (or inverse variance) of the gaussian prior. Train()
* must be called before.
*
* @return \f$ \alpha \f$
*/
double Alpha() const { return alpha; }
/**
* Get the precision (or inverse variance) beta of the model. Train() must be
* called before.
*
* @return \f$ \beta \f$
*/
double Beta() const { return beta; }
/**
* Get the estimated variance. Train() must be called before.
*
* @return 1.0 / \f$ \beta \f$
*/
double Variance() const { return 1.0 / Beta(); }
/**
* Get the mean vector computed on the features over the training points.
*
* @return responsesOffset
*/
const arma::colvec& DataOffset() const { return dataOffset; }
/**
* Get the vector of standard deviations computed on the features over the
* training points.
*
* @return dataOffset
*/
const arma::colvec& DataScale() const { return dataScale; }
/**
* Get the mean value of the train responses.
*
* @return responsesOffset
*/
double ResponsesOffset() const { return responsesOffset; }
/**
* Serialize the BayesianLinearRegression model.
**/
template<typename Archive>
void serialize(Archive& ar, const unsigned int /* version */);
private:
//! Center the data if true.
bool centerData;
//! Scale the data by standard deviations if true.
bool scaleData;
//! Maximum number of iterations for convergency.
size_t nIterMax;
//! Level from which the solution is considered sufficientlly stable.
double tol;
//! Mean vector computed over the points.
arma::colvec dataOffset;
//! Std vector computed over the points.
arma::colvec dataScale;
//! Mean of the response vector computed over the points.
double responsesOffset;
//! Precision of the prior pdf (gaussian).
double alpha;
//! Noise inverse variance.
double beta;
//! Effective number of parameters.
double gamma;
//! Solution vector
arma::colvec omega;
//! Covariance matrix of the solution vector omega.
arma::mat matCovariance;
/**
* Center and scale the data accordind to centerData and scaleData.
* Allows future modifications of new points.
*
* @param data Design matrix in column-major format, dim(P, N).
* @param responses A vector of targets.
* @param dataProc Data processed, dim(P, N).
* @param responsesProc Responses processed, dim(N).
* @return reponsesOffset Mean of responses.
*/
double CenterScaleData(const arma::mat& data,
const arma::rowvec& responses,
arma::mat& dataProc,
arma::rowvec& responsesProc);
/**
* Center and scale the points before prediction.
*
* @param data Design matrix in column-major format, dim(P, N).
* @param dataProc Data processed, dim(P, N).
*/
void CenterScaleDataPred(const arma::mat& data,
arma::mat& dataProc) const;
};
} // namespace regression
} // namespace mlpack
// Include implementation of serialize.
#include "bayesian_linear_regression_impl.hpp"
#endif
@@ -0,0 +1,44 @@
/**
* @file methods/bayesian_linear_regression/bayesian_linear_regression_impl.hpp
* @author Clement Mercier
*
* Implementation of templated BayesianLinearRegression functions.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#ifndef MLPACK_METHODS_BAYESIAN_LINEAR_REGRESSION_IMPL_HPP
#define MLPACK_METHODS_BAYESIAN_LINEAR_REGRESSION_IMPL_HPP
#include "bayesian_linear_regression.hpp"
namespace mlpack {
namespace regression {
/**
* Serialize the Bayesian linear regression model.
*/
template<typename Archive>
void BayesianLinearRegression::serialize(Archive& ar,
const unsigned int /* version */)
{
ar & BOOST_SERIALIZATION_NVP(centerData);
ar & BOOST_SERIALIZATION_NVP(scaleData);
ar & BOOST_SERIALIZATION_NVP(nIterMax);
ar & BOOST_SERIALIZATION_NVP(tol);
ar & BOOST_SERIALIZATION_NVP(dataOffset);
ar & BOOST_SERIALIZATION_NVP(dataScale);
ar & BOOST_SERIALIZATION_NVP(responsesOffset);
ar & BOOST_SERIALIZATION_NVP(alpha);
ar & BOOST_SERIALIZATION_NVP(beta);
ar & BOOST_SERIALIZATION_NVP(gamma);
ar & BOOST_SERIALIZATION_NVP(omega);
ar & BOOST_SERIALIZATION_NVP(matCovariance);
}
} // namespace regression
} // namespace mlpack
#endif
@@ -0,0 +1,199 @@
/**
* @file methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp
* @author Clement Mercier
*
* Executable for BayesianLinearRegression.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <mlpack/prereqs.hpp>
#include <mlpack/core/util/io.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include "bayesian_linear_regression.hpp"
using namespace arma;
using namespace std;
using namespace mlpack;
using namespace mlpack::regression;
using namespace mlpack::util;
PROGRAM_INFO("BayesianLinearRegression",
// Short description.
"An implementation of the bayesian linear regression.",
// Long description.
"An implementation of the bayesian linear regression."
"\n"
"This model is a probabilistic view and implementation of the linear "
"regression. The final solution is obtained by computing a posterior "
"distribution from gaussian likelihood and a zero mean gaussian isotropic "
" prior distribution on the solution. "
"\n"
"Optimization is AUTOMATIC and does not require cross validation. "
"The optimization is performed by maximization of the evidence function. "
"Parameters are tuned during the maximization of the marginal likelihood. "
"This procedure includes the Ockham's razor that penalizes over complex "
"solutions. "
"\n\n"
"This program is able to train a Bayesian linear regression model or load "
"a model from file, output regression predictions for a test set, and save "
"the trained model to a file."
"\n\n"
"To train a BayesianLinearRegression model, the " +
PRINT_PARAM_STRING("input") + " and " + PRINT_PARAM_STRING("responses") +
"parameters must be given. The " + PRINT_PARAM_STRING("center") +
"and " + PRINT_PARAM_STRING("scale") + " parameters control the "
"centering and the normalizing options. A trained model can be saved with "
"the " + PRINT_PARAM_STRING("output_model") + ". If no training is desired "
"at all, a model can be passed via the " +
PRINT_PARAM_STRING("input_model") + " parameter."
"\n\n"
"The program can also provide predictions for test data using either the "
"trained model or the given input model. Test points can be specified "
"with the " + PRINT_PARAM_STRING("test") + " parameter. Predicted "
"responses to the test points can be saved with the " +
PRINT_PARAM_STRING("predictions") + " output parameter. The "
"corresponding standard deviation can be save by precising the " +
PRINT_PARAM_STRING("stds") + " parameter."
"\n\n"
"For example, the following command trains a model on the data " +
PRINT_DATASET("data") + " and responses " + PRINT_DATASET("responses") +
"with center set to true and scale set to false (so, Bayesian "
"linear regression is being solved, and then the model is saved to " +
PRINT_MODEL("bayesian_linear_regression_model") + ":"
"\n\n" +
PRINT_CALL("bayesian_linear_regression", "input", "data", "responses",
"responses", "center", 1, "scale", 0, "output_model",
"bayesian_linear_regression_model") +
"\n\n"
"The following command uses the " +
PRINT_MODEL("bayesian_linear_regression_model") + " to provide predicted " +
" responses for the data " + PRINT_DATASET("test") + " and save those " +
" responses to " + PRINT_DATASET("test_predictions") + ": "
"\n\n" +
PRINT_CALL("bayesian_linear_regression", "input_model",
"bayesian_linear_regression_model", "test", "test",
"predictions", "test_predictions") +
"\n\n"
"Because the estimator computes a predictive distribution instead of "
"simple point estimate, the " + PRINT_PARAM_STRING("stds") + " parameter "
"allows to save the prediction uncertainties: "
"\n\n" +
PRINT_CALL("bayesian_linear_regression", "input_model",
"bayesian_linear_regression_model", "test", "test",
"predictions", "test_predictions", "stds", "stds"),
SEE_ALSO("Bayesian Interpolation",
"https://authors.library.caltech.edu/13792/1/MACnc92a.pdf"),
SEE_ALSO("Bayesian Linear Regression, Section 3.3",
"MLA Bishop, Christopher M. Pattern Recognition and Machine "
"Learning. New York :Springer, 2006, section 3.3."),
SEE_ALSO("mlpack::regression::BayesianLinearRegression C++ class "
"documentation",
"@doxygen/classmlpack_1_1regression_1_1BayesianLinearRegression.html"));
PARAM_MATRIX_IN("input", "Matrix of covariates (X).", "i");
PARAM_ROW_IN("responses", "Matrix of responses/observations (y).", "r");
PARAM_MODEL_IN(BayesianLinearRegression, "input_model", "Trained "
"BayesianLinearRegression model to use.", "m");
PARAM_MODEL_OUT(BayesianLinearRegression, "output_model", "Output "
"BayesianLinearRegression model.", "M");
PARAM_MATRIX_IN("test", "Matrix containing points to regress on (test "
"points).", "t");
PARAM_MATRIX_OUT("predictions", "If --test_file is specified, this "
"file is where the predicted responses will be saved.", "o");
PARAM_MATRIX_OUT("stds", "If specified, this is where the standard deviations "
"of the predictive distribution will be saved.", "u");
PARAM_FLAG("center", "Center the data and fit the intercept if enabled.", "c");
PARAM_FLAG("scale", "Scale each feature by their standard deviations if "
"enabled.", "s");
static void mlpackMain()
{
bool center = IO::GetParam<bool>("center");
bool scale = IO::GetParam<bool>("scale");
// Check parameters -- make sure everything given makes sense.
RequireOnlyOnePassed({"input", "input_model"}, true);
if (IO::HasParam("input"))
{
RequireOnlyOnePassed({"responses"}, true, "if input data is specified, "
"responses must also be specified");
}
ReportIgnoredParam({{"input", false }}, "responses");
RequireAtLeastOnePassed({"predictions", "output_model", "stds"}, false,
"no results will be saved");
// Ignore out_predictions unless test is specified.
ReportIgnoredParam({{"test", false}}, "predictions");
BayesianLinearRegression* bayesLinReg;
if (IO::HasParam("input"))
{
Log::Info << "input detected " << std::endl;
// Initialize the object.
bayesLinReg = new BayesianLinearRegression(center, scale);
// Load covariates. We can avoid LARS transposing our data by choosing to
// not transpose this data (that's why we used PARAM_TMATRIX_IN).
mat matX = std::move(IO::GetParam<arma::mat>("input"));
// Load responses. The responses should be a one-dimensional vector, and it
// seems more likely that these will be stored with one response per line
// (one per row). So we should not transpose upon loading.
arma::rowvec responses = std::move(
IO::GetParam<arma::rowvec>("responses"));
if (responses.n_elem != matX.n_cols)
{
delete bayesLinReg;
Log::Fatal << "Number of responses must be equal to number of rows of X!"
<< endl;
}
arma::rowvec predictionsTrain;
// The Train method is ready to take data in column-major format.
bayesLinReg->Train(matX, responses);
}
else // We must have --input_model_file.
{
bayesLinReg = IO::GetParam<BayesianLinearRegression*>("input_model");
}
if (IO::HasParam("test"))
{
Log::Info << "Regressing on test points." << endl;
// Load test points.
mat testPoints = std::move(IO::GetParam<arma::mat>("test"));
arma::rowvec predictions;
if (IO::HasParam("stds"))
{
arma::rowvec std;
bayesLinReg->Predict(testPoints, predictions, std);
// Save the standard deviation of the test points (one per line).
IO::GetParam<arma::mat>("stds") = std::move(std);
}
else
{
bayesLinReg->Predict(testPoints, predictions);
}
// Save test predictions (one per line).
IO::GetParam<arma::mat>("predictions") = std::move(predictions);
}
IO::GetParam<BayesianLinearRegression*>("output_model") = bayesLinReg;
}
@@ -38,13 +38,17 @@ using namespace mlpack::ann;
* }
* @endcode
*
* @tparam OutputLayerType The output layer type of the network.
* @tparam InitType The initialization type used for the network.
* @tparam CompleteNetworkType The type of network used for full dueling dqn.
* @tparam FeatureNetworkType The type of network used for feature network.
* @tparam AdvantageNetworkType The type of network used for advantage network.
* @tparam ValueNetworkType The type of network used for value network.
*/
template <
typename CompleteNetworkType = FFN<EmptyLoss<>, GaussianInitialization>,
typename OutputLayerType = EmptyLoss<>,
typename InitType = GaussianInitialization,
typename CompleteNetworkType = FFN<OutputLayerType, InitType>,
typename FeatureNetworkType = Sequential<>,
typename AdvantageNetworkType = Sequential<>,
typename ValueNetworkType = Sequential<>
@@ -75,13 +79,17 @@ class DuelingDQN
* @param h2 Number of neurons in hiddenlayer-2.
* @param outputDim Number of neurons in output layer.
* @param isNoisy Specifies whether the network needs to be of type noisy.
* @param init Specifies the initialization rule for the network.
* @param outputLayer Specifies the output layer type for network.
*/
DuelingDQN(const int inputDim,
const int h1,
const int h2,
const int outputDim,
const bool isNoisy = false):
completeNetwork(EmptyLoss<>(), GaussianInitialization(0, 0.001)),
const bool isNoisy = false,
InitType init = InitType(),
OutputLayerType outputLayer = OutputLayerType()):
completeNetwork(outputLayer, init),
isNoisy(isNoisy)
{
featureNetwork = new Sequential<>();
@@ -125,13 +133,21 @@ class DuelingDQN
this->ResetParameters();
}
DuelingDQN(FeatureNetworkType featureNetwork,
AdvantageNetworkType advantageNetwork,
ValueNetworkType valueNetwork,
/**
* Construct an instance of DuelingDQN class from a pre-constructed network.
*
* @param featureNetwork The feature network to be used by DuelingDQN class.
* @param advantageNetwork The advantage network to be used by DuelingDQN class.
* @param valueNetwork The value network to be used by DuelingDQN class.
* @param isNoisy Specifies whether the network needs to be of type noisy.
*/
DuelingDQN(FeatureNetworkType& featureNetwork,
AdvantageNetworkType& advantageNetwork,
ValueNetworkType& valueNetwork,
const bool isNoisy = false):
featureNetwork(std::move(featureNetwork)),
advantageNetwork(std::move(advantageNetwork)),
valueNetwork(std::move(valueNetwork)),
featureNetwork(featureNetwork),
advantageNetwork(advantageNetwork),
valueNetwork(valueNetwork),
isNoisy(isNoisy)
{
concat = new Concat<>(true);
@@ -24,10 +24,15 @@ namespace rl {
using namespace mlpack::ann;
/**
* @tparam OutputLayerType The output layer type of the network.
* @tparam InitType The initialization type used for the network.
* @tparam NetworkType The type of network used for simple dqn.
*/
template <typename NetworkType = FFN<MeanSquaredError<>,
GaussianInitialization>>
template<
typename OutputLayerType = MeanSquaredError<>,
typename InitType = GaussianInitialization,
typename NetworkType = FFN<OutputLayerType, InitType>
>
class SimpleDQN
{
public:
@@ -45,13 +50,17 @@ class SimpleDQN
* @param h2 Number of neurons in hiddenlayer-2.
* @param outputDim Number of neurons in output layer.
* @param isNoisy Specifies whether the network needs to be of type noisy.
* @param init Specifies the initialization rule for the network.
* @param outputLayer Specifies the output layer type for network.
*/
SimpleDQN(const int inputDim,
const int h1,
const int h2,
const int outputDim,
const bool isNoisy = false):
network(MeanSquaredError<>(), GaussianInitialization(0, 0.001)),
const bool isNoisy = false,
InitType init = InitType(),
OutputLayerType outputLayer = OutputLayerType()):
network(outputLayer, init),
isNoisy(isNoisy)
{
network.Add(new Linear<>(inputDim, h1));
@@ -72,8 +81,14 @@ class SimpleDQN
}
}
SimpleDQN(NetworkType network, const bool isNoisy = false):
network(std::move(network)),
/**
* Construct an instance of SimpleDQN class from a pre-constructed network.
*
* @param network The network to be used by SimpleDQN class.
* @param isNoisy Specifies whether the network needs to be of type noisy.
*/
SimpleDQN(NetworkType& network, const bool isNoisy = false):
network(network),
isNoisy(isNoisy)
{ /* Nothing to do here. */ }
+28 -29
View File
@@ -1,19 +1,10 @@
# mlpack test executable.
add_executable(mlpack_test
akfn_test.cpp
aknn_test.cpp
ann_dist_test.cpp
ann_layer_test.cpp
ann_regularizer_test.cpp
ann_test_tools.hpp
ann_visitor_test.cpp
arma_extend_test.cpp
armadillo_svd_test.cpp
async_learning_test.cpp
augmented_rnns_tasks_test.cpp
bias_svd_test.cpp
binarize_test.cpp
block_krylov_svd_test.cpp
bayesian_linear_regression_test.cpp
callback_test.cpp
cf_test.cpp
cli_binding_test.cpp
@@ -22,8 +13,6 @@ add_executable(mlpack_test
cv_test.cpp
dbscan_test.cpp
dcgan_test.cpp
decision_stump_test.cpp
decision_tree_test.cpp
det_test.cpp
distribution_test.cpp
drusilla_select_test.cpp
@@ -43,9 +32,7 @@ add_executable(mlpack_test
kernel_pca_test.cpp
kernel_test.cpp
kernel_traits_test.cpp
kfn_test.cpp
kmeans_test.cpp
knn_test.cpp
krann_search_test.cpp
ksinit_test.cpp
lars_test.cpp
@@ -53,7 +40,6 @@ add_executable(mlpack_test
lin_alg_test.cpp
linear_svm_test.cpp
lmnn_test.cpp
load_save_test.cpp
local_coordinate_coding_test.cpp
log_test.cpp
logistic_regression_test.cpp
@@ -77,16 +63,13 @@ add_executable(mlpack_test
python_binding_test.cpp
q_learning_test.cpp
qdafn_test.cpp
quic_svd_test.cpp
radical_test.cpp
random_forest_test.cpp
random_test.cpp
randomized_svd_test.cpp
range_search_test.cpp
rbm_network_test.cpp
rectangle_tree_test.cpp
recurrent_network_test.cpp
regularized_svd_test.cpp
reward_clipping_test.cpp
rl_components_test.cpp
scaling_test.cpp
@@ -101,9 +84,6 @@ add_executable(mlpack_test
split_data_test.cpp
string_encoding_test.cpp
sumtree_test.cpp
svd_batch_test.cpp
svd_incremental_test.cpp
svdplusplus_test.cpp
termination_policy_test.cpp
test_function_tools.hpp
test_tools.hpp
@@ -114,11 +94,9 @@ add_executable(mlpack_test
union_find_test.cpp
vantage_point_tree_test.cpp
wgan_test.cpp
main_tests/approx_kfn_test.cpp
main_tests/bayesian_linear_regression_test.cpp
main_tests/cf_test.cpp
main_tests/dbscan_test.cpp
main_tests/decision_stump_test.cpp
main_tests/decision_tree_test.cpp
main_tests/det_test.cpp
main_tests/emst_test.cpp
main_tests/fastmks_test.cpp
@@ -133,9 +111,7 @@ add_executable(mlpack_test
main_tests/hoeffding_tree_test.cpp
main_tests/kde_test.cpp
main_tests/kernel_pca_test.cpp
main_tests/kfn_test.cpp
main_tests/kmeans_test.cpp
main_tests/knn_test.cpp
main_tests/krann_test.cpp
main_tests/linear_svm_test.cpp
main_tests/lmnn_test.cpp
@@ -162,17 +138,43 @@ add_executable(mlpack_test
add_executable(mlpack_catch_test
activation_functions_test.cpp
adaboost_test.cpp
akfn_test.cpp
aknn_test.cpp
ann_dist_test.cpp
ann_layer_test.cpp
ann_regularizer_test.cpp
ann_test_tools.hpp
ann_visitor_test.cpp
armadillo_svd_test.cpp
bias_svd_test.cpp
block_krylov_svd_test.cpp
convolutional_network_test.cpp
convolution_test.cpp
decision_stump_test.cpp
decision_tree_test.cpp
image_load_test.cpp
kfn_test.cpp
knn_test.cpp
linear_regression_test.cpp
load_save_test.cpp
main.cpp
serialization_catch.cpp
serialization_catch.hpp
softmax_regression_test.cpp
quic_svd_test.cpp
randomized_svd_test.cpp
regularized_svd_test.cpp
svd_batch_test.cpp
svd_incremental_test.cpp
svdplusplus_test.cpp
test_catch_tools.hpp
main_tests/adaboost_test.cpp
main_tests/approx_kfn_test.cpp
main_tests/decision_stump_test.cpp
main_tests/decision_tree_test.cpp
main_tests/image_converter_test.cpp
main_tests/kfn_test.cpp
main_tests/knn_test.cpp
main_tests/linear_regression_test.cpp
main_tests/softmax_regression_test.cpp
main_tests/test_helper.hpp
@@ -223,10 +225,7 @@ add_custom_command(TARGET mlpack_test
# The list of long running parallel tests
set(parallel_tests
"ANNLayerTest;"
"AsyncLearningTest;"
"SVDIncrementalTest;"
"SVDBatchTest;"
"LocalCoordinateCodingTest;"
"FeedForwardNetworkTest;"
"RecurrentNetworkTest;"
+12 -15
View File
@@ -11,8 +11,8 @@
#include <mlpack/core.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
#include <mlpack/core/tree/cover_tree.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "test_catch_tools.hpp"
#include "catch.hpp"
using namespace mlpack;
using namespace mlpack::neighbor;
@@ -20,20 +20,18 @@ using namespace mlpack::tree;
using namespace mlpack::metric;
using namespace mlpack::bound;
BOOST_AUTO_TEST_SUITE(AKFNTest);
/**
* Test the dual-tree furthest-neighbors method with different values for
* epsilon. This uses both a query and reference dataset.
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(ApproxVsExact1)
TEST_CASE("AKFNApproxVsExact1", "[AKFNTest]")
{
arma::mat dataset;
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KFN exact(dataset);
arma::Mat<size_t> neighborsExact;
@@ -81,12 +79,12 @@ BOOST_AUTO_TEST_CASE(ApproxVsExact1)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(ApproxVsExact2)
TEST_CASE("AKFNApproxVsExact2", "[AKFNTest]")
{
arma::mat dataset;
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KFN exact(dataset);
arma::Mat<size_t> neighborsExact;
@@ -108,12 +106,12 @@ BOOST_AUTO_TEST_CASE(ApproxVsExact2)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(SingleTreeVsExact)
TEST_CASE("AKFNSingleTreeVsExact", "[AKFNTest]")
{
arma::mat dataset;
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KFN exact(dataset);
arma::Mat<size_t> neighborsExact;
@@ -135,7 +133,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeVsExact)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(SingleCoverTreeTest)
TEST_CASE("AKFNSingleCoverTreeTest", "[AKFNTest]")
{
arma::mat dataset;
dataset.randu(75, 1000); // 75 dimensional, 1000 points.
@@ -165,7 +163,7 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(DualCoverTreeTest)
TEST_CASE("AKFNDualCoverTreeTest", "[AKFNTest]")
{
arma::mat dataset;
data::Load("test_data_3_1000.csv", dataset);
@@ -195,7 +193,7 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(SingleBallTreeTest)
TEST_CASE("AKFNSingleBallTreeTest", "[AKFNTest]")
{
arma::mat dataset;
dataset.randu(75, 1000); // 75 dimensional, 1000 points.
@@ -222,7 +220,7 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(DualBallTreeTest)
TEST_CASE("AKFNDualBallTreeTest", "[AKFNTest]")
{
arma::mat dataset;
data::Load("test_data_3_1000.csv", dataset);
@@ -242,4 +240,3 @@ BOOST_AUTO_TEST_CASE(DualBallTreeTest)
REQUIRE_RELATIVE_ERR(distancesBallTree(i), distancesExact(i), 0.05);
}
BOOST_AUTO_TEST_SUITE_END();
+28 -32
View File
@@ -14,8 +14,8 @@
#include <mlpack/methods/neighbor_search/ns_model.hpp>
#include <mlpack/core/tree/cover_tree.hpp>
#include <mlpack/core/tree/example_tree.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "test_catch_tools.hpp"
#include "catch.hpp"
using namespace mlpack;
using namespace mlpack::neighbor;
@@ -23,20 +23,18 @@ using namespace mlpack::tree;
using namespace mlpack::metric;
using namespace mlpack::bound;
BOOST_AUTO_TEST_SUITE(AKNNTest);
/**
* Test the dual-tree nearest-neighbors method with different values for
* epsilon. This uses both a query and reference dataset.
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(ApproxVsExact1)
TEST_CASE("AKNNApproxVsExact1", "[AKNNTest]")
{
arma::mat dataset;
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KNN exact(dataset);
arma::Mat<size_t> neighborsExact;
@@ -84,12 +82,12 @@ BOOST_AUTO_TEST_CASE(ApproxVsExact1)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(ApproxVsExact2)
TEST_CASE("AKNNApproxVsExact2", "[AKNNTest]")
{
arma::mat dataset;
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KNN exact(dataset);
arma::Mat<size_t> neighborsExact;
@@ -111,12 +109,12 @@ BOOST_AUTO_TEST_CASE(ApproxVsExact2)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(SingleTreeApproxVsExact)
TEST_CASE("AKNNSingleTreeApproxVsExact", "[AKNNTest]")
{
arma::mat dataset;
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KNN exact(dataset);
arma::Mat<size_t> neighborsExact;
@@ -138,7 +136,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeApproxVsExact)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(SingleCoverTreeTest)
TEST_CASE("AKNNSingleCoverTreeTest", "[AKNNTest]")
{
arma::mat dataset;
dataset.randu(75, 1000); // 75 dimensional, 1000 points.
@@ -168,7 +166,7 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(DualCoverTreeTest)
TEST_CASE("AKNNDualCoverTreeTest", "[AKNNTest]")
{
arma::mat dataset;
data::Load("test_data_3_1000.csv", dataset);
@@ -195,7 +193,7 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(SingleBallTreeTest)
TEST_CASE("AKNNSingleBallTreeTest", "[AKNNTest]")
{
arma::mat dataset;
dataset.randu(50, 300); // 50 dimensional, 300 points.
@@ -222,7 +220,7 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(DualBallTreeTest)
TEST_CASE("AKNNDualBallTreeTest", "[AKNNTest]")
{
arma::mat dataset;
data::Load("test_data_3_1000.csv", dataset);
@@ -249,7 +247,7 @@ BOOST_AUTO_TEST_CASE(DualBallTreeTest)
*
* Errors are produced if the results are not according to relative error.
*/
BOOST_AUTO_TEST_CASE(SingleSpillTreeTest)
TEST_CASE("AKNNSingleSpillTreeTest", "[AKNNTest]")
{
arma::mat dataset;
dataset.randu(50, 300); // 50 dimensional, 300 points.
@@ -286,7 +284,7 @@ BOOST_AUTO_TEST_CASE(SingleSpillTreeTest)
/**
* Make sure sparse nearest neighbors works with kd trees.
*/
BOOST_AUTO_TEST_CASE(SparseKNNKDTreeTest)
TEST_CASE("AKNNSparseKNNKDTreeTest", "[AKNNTest]")
{
// The dimensionality of these datasets must be high so that the probability
// of a completely empty point is very low. In this case, with dimensionality
@@ -321,7 +319,7 @@ BOOST_AUTO_TEST_CASE(SparseKNNKDTreeTest)
* Ensure that we can build an NSModel<NearestNeighborSearch> and get correct
* results.
*/
BOOST_AUTO_TEST_CASE(KNNModelTest)
TEST_CASE("AKNNModelTest", "[AKNNTest]")
{
typedef NSModel<NearestNeighborSort> KNNModel;
@@ -385,12 +383,12 @@ BOOST_AUTO_TEST_CASE(KNNModelTest)
models[i].Search(std::move(queryCopy), 3, neighborsApprox,
distancesApprox);
BOOST_REQUIRE_EQUAL(neighborsApprox.n_rows, neighborsExact.n_rows);
BOOST_REQUIRE_EQUAL(neighborsApprox.n_cols, neighborsExact.n_cols);
BOOST_REQUIRE_EQUAL(neighborsApprox.n_elem, neighborsExact.n_elem);
BOOST_REQUIRE_EQUAL(distancesApprox.n_rows, distancesExact.n_rows);
BOOST_REQUIRE_EQUAL(distancesApprox.n_cols, distancesExact.n_cols);
BOOST_REQUIRE_EQUAL(distancesApprox.n_elem, distancesExact.n_elem);
REQUIRE(neighborsApprox.n_rows == neighborsExact.n_rows);
REQUIRE(neighborsApprox.n_cols == neighborsExact.n_cols);
REQUIRE(neighborsApprox.n_elem == neighborsExact.n_elem);
REQUIRE(distancesApprox.n_rows == distancesExact.n_rows);
REQUIRE(distancesApprox.n_cols == distancesExact.n_cols);
REQUIRE(distancesApprox.n_elem == distancesExact.n_elem);
for (size_t k = 0; k < distancesApprox.n_elem; ++k)
REQUIRE_RELATIVE_ERR(distancesApprox[k], distancesExact[k], 0.05);
}
@@ -401,7 +399,7 @@ BOOST_AUTO_TEST_CASE(KNNModelTest)
* Ensure that we can build an NSModel<NearestNeighborSearch> and get correct
* results, in the case where the reference set is the same as the query set.
*/
BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest)
TEST_CASE("AKNNModelMonochromaticTest", "[AKNNTest]")
{
typedef NSModel<NearestNeighborSort> KNNModel;
@@ -460,16 +458,14 @@ BOOST_AUTO_TEST_CASE(KNNModelMonochromaticTest)
models[i].Search(3, neighborsApprox, distancesApprox);
BOOST_REQUIRE_EQUAL(neighborsApprox.n_rows, neighborsExact.n_rows);
BOOST_REQUIRE_EQUAL(neighborsApprox.n_cols, neighborsExact.n_cols);
BOOST_REQUIRE_EQUAL(neighborsApprox.n_elem, neighborsExact.n_elem);
BOOST_REQUIRE_EQUAL(distancesApprox.n_rows, distancesExact.n_rows);
BOOST_REQUIRE_EQUAL(distancesApprox.n_cols, distancesExact.n_cols);
BOOST_REQUIRE_EQUAL(distancesApprox.n_elem, distancesExact.n_elem);
REQUIRE(neighborsApprox.n_rows == neighborsExact.n_rows);
REQUIRE(neighborsApprox.n_cols == neighborsExact.n_cols);
REQUIRE(neighborsApprox.n_elem == neighborsExact.n_elem);
REQUIRE(distancesApprox.n_rows == distancesExact.n_rows);
REQUIRE(distancesApprox.n_cols == distancesExact.n_cols);
REQUIRE(distancesApprox.n_elem == distancesExact.n_elem);
for (size_t k = 0; k < distancesApprox.n_elem; ++k)
REQUIRE_RELATIVE_ERR(distancesApprox[k], distancesExact[k], 0.05);
}
}
}
BOOST_AUTO_TEST_SUITE_END();
+24 -33
View File
@@ -16,20 +16,18 @@
#include <mlpack/methods/ann/dists/normal_distribution.hpp>
#include <mlpack/methods/ann/init_rules/random_init.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "catch.hpp"
#include "test_catch_tools.hpp"
#include <mlpack/methods/ann/activation_functions/logistic_function.hpp>
using namespace mlpack;
using namespace mlpack::ann;
BOOST_AUTO_TEST_SUITE(ANNDistTest);
/**
* Simple bernoulli distribution module test.
*/
BOOST_AUTO_TEST_CASE(SimpleBernoulliDistributionTest)
TEST_CASE("SimpleBernoulliDistributionTest", "[ANNDistTest]")
{
arma::mat param = arma::mat("1 1 0");
BernoulliDistribution<> module(param, false);
@@ -43,7 +41,7 @@ BOOST_AUTO_TEST_CASE(SimpleBernoulliDistributionTest)
/**
* Jacobian bernoulli distribution module test when we don't apply logistic.
*/
BOOST_AUTO_TEST_CASE(JacobianBernoulliDistributionTest)
TEST_CASE("JacobianBernoulliDistributionTest", "[ANNDistTest]")
{
for (size_t i = 0; i < 5; ++i)
{
@@ -78,15 +76,14 @@ BOOST_AUTO_TEST_CASE(JacobianBernoulliDistributionTest)
}
module.LogProbBackward(target, jacobianB);
BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))),
1e-5);
REQUIRE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))) <= 1e-5);
}
}
/**
* Jacobian bernoulli distribution module test when we apply logistic.
*/
BOOST_AUTO_TEST_CASE(JacobianBernoulliDistributionLogisticTest)
TEST_CASE("JacobianBernoulliDistributionLogisticTest", "[ANNDistTest]")
{
for (size_t i = 0; i < 5; ++i)
{
@@ -124,15 +121,14 @@ BOOST_AUTO_TEST_CASE(JacobianBernoulliDistributionLogisticTest)
}
module.LogProbBackward(target, jacobianB);
BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))),
3e-5);
REQUIRE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))) <= 3e-5);
}
}
/**
* Normal Distribution module test.
*/
BOOST_AUTO_TEST_CASE(NormalDistributionTest)
TEST_CASE("NormalDistributionTest", "[ANNDistTest]")
{
arma::vec mu = {1.1, 1.2, 1.5, 1.7};
arma::vec sigma = {0.1, 0.11, 0.5, 0.23};
@@ -145,29 +141,29 @@ BOOST_AUTO_TEST_CASE(NormalDistributionTest)
normalDist.LogProbability(x, prob);
// Testing output of log probability for some random mu, sigma and x.
BOOST_REQUIRE_CLOSE(prob[0], 1.2586464, 1e-3);
BOOST_REQUIRE_CLOSE(prob[1], 0.8751131, 1e-3);
BOOST_REQUIRE_CLOSE(prob[2], -0.30579138, 1e-3);
BOOST_REQUIRE_CLOSE(prob[3], -5.498411, 1e-3);
REQUIRE(prob[0] == Approx(1.2586464).epsilon(1e-5));
REQUIRE(prob[1] == Approx(0.8751131).epsilon(1e-5));
REQUIRE(prob[2] == Approx(-0.30579138).epsilon(1e-5));
REQUIRE(prob[3] == Approx(-5.498411).epsilon(1e-5));
arma::vec dmu, dsigma;
normalDist.ProbBackward(x, dmu, dsigma);
// Testing output of dmu and dsigma for some random mu, sigma and x.
BOOST_REQUIRE_CLOSE(dmu[0], -17.603287, 1e-3);
BOOST_REQUIRE_CLOSE(dsigma[0], -26.40487, 1e-3);
BOOST_REQUIRE_CLOSE(dmu[1], -19.827663, 1e-3);
BOOST_REQUIRE_CLOSE(dsigma[1], -3.7852707, 1e-3);
BOOST_REQUIRE_CLOSE(dmu[2], 0.5892323, 1e-3);
BOOST_REQUIRE_CLOSE(dsigma[2], -1.2373875, 1e-3);
BOOST_REQUIRE_CLOSE(dmu[3], 0.061901994, 1e-3);
BOOST_REQUIRE_CLOSE(dsigma[3], 0.19751444, 1e-3);
REQUIRE(dmu[0] == Approx(-17.603287).epsilon(1e-5));
REQUIRE(dsigma[0] == Approx(-26.40487).epsilon(1e-5));
REQUIRE(dmu[1] == Approx(-19.827663).epsilon(1e-5));
REQUIRE(dsigma[1] == Approx(-3.7852707).epsilon(1e-5));
REQUIRE(dmu[2] == Approx(0.5892323).epsilon(1e-5));
REQUIRE(dsigma[2] == Approx(-1.2373875).epsilon(1e-5));
REQUIRE(dmu[3] == Approx(0.061901994).epsilon(1e-5));
REQUIRE(dsigma[3] == Approx(0.19751444).epsilon(1e-5));
}
/**
* Jacobian Normal Distribution module test for mean.
*/
BOOST_AUTO_TEST_CASE(JacobianNormalDistributionMeanTest)
TEST_CASE("JacobianNormalDistributionMeanTest", "[ANNDistTest]")
{
for (size_t i = 0; i < 5; i++)
{
@@ -226,15 +222,14 @@ BOOST_AUTO_TEST_CASE(JacobianNormalDistributionMeanTest)
jacobianB.col(k) = deltaMu % deriv;
}
BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))),
5e-3);
REQUIRE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))) <= 5e-3);
}
}
/**
* Jacobian Normal Distribution module test for standard deviation.
*/
BOOST_AUTO_TEST_CASE(JacobianNormalDistributionStandardDeviationTest)
TEST_CASE("JacobianNormalDistributionStandardDeviationTest", "[ANNDistTest]")
{
for (size_t i = 0; i < 5; i++)
{
@@ -293,10 +288,6 @@ BOOST_AUTO_TEST_CASE(JacobianNormalDistributionStandardDeviationTest)
jacobianB.col(k) = deltaSigma % deriv;
}
BOOST_REQUIRE_LE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))),
5e-3);
REQUIRE(arma::max(arma::max(arma::abs(jacobianA - jacobianB))) <= 5e-3);
}
}
BOOST_AUTO_TEST_SUITE_END();
File diff suppressed because it is too large Load Diff
+8 -12
View File
@@ -16,16 +16,14 @@
#include <mlpack/methods/ann/init_rules/random_init.hpp>
#include <mlpack/methods/ann/regularizer/regularizer.hpp>
#include <boost/test/unit_test.hpp>
#include "catch.hpp"
#include "ann_test_tools.hpp"
#include "serialization.hpp"
#include "serialization_catch.hpp"
using namespace mlpack;
using namespace mlpack::ann;
BOOST_AUTO_TEST_SUITE(ANNRegularizerTest);
BOOST_AUTO_TEST_CASE(GradientL1RegularizerTest)
TEST_CASE("GradientL1RegularizerTest", "[ANNRegularizerTest]")
{
// Add function gradient instantiation.
struct GradientFunction
@@ -51,10 +49,10 @@ BOOST_AUTO_TEST_CASE(GradientL1RegularizerTest)
L1Regularizer reg;
} function;
BOOST_REQUIRE_LE(CheckRegularizerGradient(function), 1e-4);
REQUIRE(CheckRegularizerGradient(function) <= 1e-4);
}
BOOST_AUTO_TEST_CASE(GradientL2RegularizerTest)
TEST_CASE("GradientL2RegularizerTest", "[ANNRegularizerTest]")
{
// Add function gradient instantiation.
struct GradientFunction
@@ -80,10 +78,10 @@ BOOST_AUTO_TEST_CASE(GradientL2RegularizerTest)
L2Regularizer reg;
} function;
BOOST_REQUIRE_LE(CheckRegularizerGradient(function), 1e-4);
REQUIRE(CheckRegularizerGradient(function) <= 1e-4);
}
BOOST_AUTO_TEST_CASE(GradientOrthogonalRegularizerTest)
TEST_CASE("GradientOrthogonalRegularizerTest", "[ANNRegularizerTest]")
{
// Add function gradient instantiation.
struct GradientFunction
@@ -111,7 +109,5 @@ BOOST_AUTO_TEST_CASE(GradientOrthogonalRegularizerTest)
OrthogonalRegularizer reg;
} function;
BOOST_REQUIRE_LE(CheckRegularizerGradient(function), 1e-4);
REQUIRE(CheckRegularizerGradient(function) <= 1e-4);
}
BOOST_AUTO_TEST_SUITE_END();
+5 -9
View File
@@ -15,18 +15,16 @@
#include <mlpack/methods/ann/visitor/weight_set_visitor.hpp>
#include <mlpack/methods/ann/visitor/reset_visitor.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "catch.hpp"
#include "test_catch_tools.hpp"
using namespace mlpack;
using namespace mlpack::ann;
BOOST_AUTO_TEST_SUITE(ANNVisitorTest);
/**
* Test that the BiasSetVisitor works properly.
*/
BOOST_AUTO_TEST_CASE(BiasSetVisitorTest)
TEST_CASE("BiasSetVisitorTest", "[ANNVisitorTest]")
{
LayerTypes<> linear = new Linear<>(10, 10);
@@ -43,16 +41,14 @@ BOOST_AUTO_TEST_CASE(BiasSetVisitorTest)
size_t biasSize = boost::apply_visitor(BiasSetVisitor(weight, 0), linear);
BOOST_REQUIRE_EQUAL(biasSize, 10);
REQUIRE(biasSize == 10);
arma::mat input(10, 1), output;
input.randu();
boost::apply_visitor(ForwardVisitor(input, output), linear);
BOOST_REQUIRE_EQUAL(arma::accu(output), 55);
REQUIRE(arma::accu(output) == 55);
boost::apply_visitor(DeleteVisitor(), linear);
}
BOOST_AUTO_TEST_SUITE_END();
+16 -17
View File
@@ -1,10 +1,17 @@
/**
* @file tests/armadillo_svd_test.cpp
*
* Test armadillo SVD.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <mlpack/core.hpp>
#include <mlpack/methods/cf/svd_wrapper.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
BOOST_AUTO_TEST_SUITE(ArmadilloSVDTest);
#include "catch.hpp"
using namespace std;
using namespace mlpack;
@@ -13,13 +20,8 @@ using namespace arma;
/**
* Test armadillo SVD for normal factorization
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
BOOST_AUTO_TEST_CASE(ArmadilloSVDNormalFactorizationTest)
TEST_CASE("ArmadilloSVDNormalFactorizationTest", "[ArmadilloSVDTest]")
{
mat test = randu<mat>(20, 20);
@@ -27,18 +29,18 @@ BOOST_AUTO_TEST_CASE(ArmadilloSVDNormalFactorizationTest)
arma::mat W, H, sigma;
double result = svd.Apply(test, W, sigma, H);
BOOST_REQUIRE_LT(result, 0.01);
REQUIRE(result < 0.01);
test = randu<mat>(50, 50);
result = svd.Apply(test, W, sigma, H);
BOOST_REQUIRE_LT(result, 0.01);
REQUIRE(result < 0.01);
}
/**
* Test armadillo SVD for low rank matrix factorization
*/
BOOST_AUTO_TEST_CASE(ArmadilloSVDLowRankFactorizationTest)
TEST_CASE("ArmadilloSVDLowRankFactorizationTest", "[ArmadilloSVDTest]")
{
mat W_t = randu<mat>(30, 3);
mat H_t = randu<mat>(3, 40);
@@ -50,8 +52,5 @@ BOOST_AUTO_TEST_CASE(ArmadilloSVDLowRankFactorizationTest)
arma::mat W, H;
double result = svd.Apply(test, 3, W, H);
BOOST_REQUIRE_LT(result, 0.01);
REQUIRE(result < 0.01);
}
BOOST_AUTO_TEST_SUITE_END();
@@ -0,0 +1,194 @@
/**
* @file tests/bayesian_linear_regression_test.cpp
* @author Clement Mercier
*
* Test for BayesianLinearRegression.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <mlpack/core/data/load.hpp>
#include <mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp>
#include <mlpack/methods/linear_regression/linear_regression.hpp>
#include <boost/test/unit_test.hpp>
using namespace mlpack::regression;
using namespace mlpack::data;
BOOST_AUTO_TEST_SUITE(BayesianLinearRegressionTest);
void GenerateProblem(arma::mat& matX,
arma::rowvec& y,
size_t nPoints,
size_t nDims,
float sigma = 0.0)
{
matX = arma::randn(nDims, nPoints);
arma::colvec omega = arma::randn(nDims);
// Compute y and add noise.
y = omega.t() * matX + arma::randn(nPoints).t() * sigma;
}
// Ensure that predictions are close enough to the target
// for a free noise dataset.
BOOST_AUTO_TEST_CASE(BayesianLinearRegressionRegressionTest)
{
arma::mat matX;
arma::rowvec y, predictions;
GenerateProblem(matX, y, 200, 10);
// Instanciate and train the estimator.
BayesianLinearRegression estimator(true);
estimator.Train(matX, y);
estimator.Predict(matX, predictions);
// Check the predictions are close enough to the targets in a free noise case.
for (size_t i = 0; i < y.size(); i++)
BOOST_REQUIRE_CLOSE(predictions[i], y[i], 1e-6);
// Check that the estimated variance is zero.
BOOST_REQUIRE_SMALL(estimator.Variance(), 1e-6);
}
// Verify centerData and scaleData equal false do not affect the solution.
BOOST_AUTO_TEST_CASE(TestCenter0ScaleData0)
{
arma::mat matX;
arma::rowvec y;
size_t nDims = 30, nPoints = 100;
GenerateProblem(matX, y, nPoints, nDims, 0.5);
BayesianLinearRegression estimator(false, false);
estimator.Train(matX, y);
// Check dataOffset is empty.
BOOST_REQUIRE(estimator.DataOffset().n_elem == 0);
// To be neutral responseOffset must be 0.
BOOST_REQUIRE(estimator.ResponsesOffset() == 0);
// Check dataScale is empty.
BOOST_REQUIRE(estimator.DataScale().n_elem == 0);
}
// Verify that centering and normalization are correct.
BOOST_AUTO_TEST_CASE(TestCenterDataTrueScaleDataTrue)
{
arma::mat matX;
arma::rowvec y;
size_t nDims = 5, nPoints = 100;
GenerateProblem(matX, y, nPoints, nDims, 0.5);
BayesianLinearRegression estimator(true, true);
estimator.Train(matX, y);
arma::colvec xMean = arma::mean(matX, 1);
arma::colvec xStd = arma::stddev(matX, 0, 1);
double yMean = arma::mean(y);
BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataOffset() - xMean)), 1e-6);
BOOST_REQUIRE_SMALL((double) abs(sum(estimator.DataScale() - xStd)), 1e-6);
BOOST_REQUIRE_CLOSE(estimator.ResponsesOffset(), yMean, 1e-6);
}
// Make sure a model with center ans scale option set is different than a model
// without it set.
BOOST_AUTO_TEST_CASE(OptionsMakeModelDifferent)
{
arma::mat matX;
arma::rowvec y;
size_t nDims = 10, nPoints = 100;
GenerateProblem(matX, y, nPoints, nDims, 0.5);
BayesianLinearRegression blr(false, false), blrC(true, false),
blrCS(true, true);
blr.Train(matX, y);
blrC.Train(matX, y);
blrCS.Train(matX, y);
for (size_t i = 0; i < nDims; ++i)
BOOST_REQUIRE((blr.Omega()(i) != blrC.Omega()(i)) &&
(blr.Omega()(i) != blrCS.Omega()(i)) &&
(blrC.Omega()(i) != blrCS.Omega()(i)));
}
// Check that Train() does not fail with two colinear vectors.
BOOST_AUTO_TEST_CASE(SingularMatix)
{
arma::mat matX;
arma::rowvec y;
GenerateProblem(matX, y, 200, 10);
// Now the first and the second rows are indentical.
matX.row(1) = matX.row(0);
BayesianLinearRegression estimator;
estimator.Train(matX, y);
}
// Check that std are well computed/coherent. At least higher than the
// estimated predictive variance.
BOOST_AUTO_TEST_CASE(PredictiveUncertainties)
{
arma::mat matX;
arma::rowvec y;
GenerateProblem(matX, y, 100, 10, 1);
BayesianLinearRegression estimator(true, true);
estimator.Train(matX, y);
arma::rowvec responses, std;
estimator.Predict(matX, responses, std);
const double estStd = sqrt(estimator.Variance());
for (size_t i = 0; i < matX.n_cols; i++)
BOOST_REQUIRE_GT(std[i], estStd);
// Check that the estimated variance is close to 1.
BOOST_REQUIRE_CLOSE(estStd, 1, 30);
}
// Check the solution is equal to the classical ridge.
BOOST_AUTO_TEST_CASE(EqualtoRidge)
{
arma::mat matX;
arma::rowvec y, blrPred, ridgePred;
size_t trial = 0;
for ( ; trial < 3; ++trial)
{
GenerateProblem(matX, y, 100, 10, 1);
BayesianLinearRegression blr(false, false);
blr.Train(matX, y);
LinearRegression ridge(matX, y, blr.Alpha() / blr.Beta(), false);
blr.Predict(matX, blrPred);
ridge.Predict(matX, ridgePred);
// If the predictions seem far off, just try again.
if (arma::norm(blrPred - ridgePred) > 1e-5)
continue;
// Check the predictions are close enough between ridge and our blr.
for (size_t i = 0; i < y.size(); ++i)
BOOST_REQUIRE_CLOSE(blrPred[i], ridgePred[i], 1);
// Exit once a test case has completed.
break;
}
BOOST_REQUIRE_LT(trial, 3);
}
BOOST_AUTO_TEST_SUITE_END();
+24 -29
View File
@@ -15,15 +15,12 @@
#include <ensmallen.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "catch.hpp"
using namespace mlpack;
using namespace mlpack::svd;
BOOST_AUTO_TEST_SUITE(BiasSVDTest);
BOOST_AUTO_TEST_CASE(BiasSVDFunctionRandomEvaluate)
TEST_CASE("BiasSVDFunctionRandomEvaluate", "[BiasSVDTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -69,11 +66,11 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionRandomEvaluate)
}
// Compare calculated cost and value obtained using Evaluate().
BOOST_REQUIRE_CLOSE(cost, biasSVDFunc.Evaluate(parameters), 1e-5);
REQUIRE(cost == Approx(biasSVDFunc.Evaluate(parameters)).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(BiasSVDFunctionRegularizationEvaluate)
TEST_CASE("BiasSVDFunctionRegularizationEvaluate", "[BiasSVDTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -123,14 +120,14 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionRegularizationEvaluate)
// Cost with regularization should be close to the sum of cost without
// regularization and the regularization terms.
BOOST_REQUIRE_CLOSE(biasSVDFuncNoReg.Evaluate(parameters) + smallRegTerm,
biasSVDFuncSmallReg.Evaluate(parameters), 1e-5);
BOOST_REQUIRE_CLOSE(biasSVDFuncNoReg.Evaluate(parameters) + bigRegTerm,
biasSVDFuncBigReg.Evaluate(parameters), 1e-5);
REQUIRE(biasSVDFuncNoReg.Evaluate(parameters) + smallRegTerm ==
Approx(biasSVDFuncSmallReg.Evaluate(parameters)).epsilon(1e-7));
REQUIRE(biasSVDFuncNoReg.Evaluate(parameters) + bigRegTerm ==
Approx(biasSVDFuncBigReg.Evaluate(parameters)).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(BiasSVDFunctionGradient)
TEST_CASE("BiasSVDFunctionGradient", "[BiasSVDTest]")
{
// Define useful constants.
const size_t numUsers = 50;
@@ -189,19 +186,19 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionGradient)
// Compare numerical and backpropagation gradient values.
if (std::abs(gradient1(i, j)) <= 1e-6)
BOOST_REQUIRE_SMALL(numGradient1, 1e-5);
REQUIRE(numGradient1 == Approx(0.0).margin(1e-5));
else
BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 0.02);
REQUIRE(numGradient1 == Approx(gradient1(i, j)).epsilon(0.0002));
if (std::abs(gradient2(i, j)) <= 1e-6)
BOOST_REQUIRE_SMALL(numGradient2, 1e-5);
REQUIRE(numGradient2 == Approx(0.0).margin(1e-5));
else
BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 0.02);
REQUIRE(numGradient2 == Approx(gradient2(i, j)).epsilon(0.0002));
}
}
}
BOOST_AUTO_TEST_CASE(BiasSVDOutputSizeTest)
TEST_CASE("BiasSVDOutputSizeTest", "[BiasSVDTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -230,15 +227,15 @@ BOOST_AUTO_TEST_CASE(BiasSVDOutputSizeTest)
biasSVD.Apply(data, rank, itemLatent, userLatent, itemBias, userBias);
// Check the size of outputs.
BOOST_REQUIRE_EQUAL(itemLatent.n_rows, numItems);
BOOST_REQUIRE_EQUAL(itemLatent.n_cols, rank);
BOOST_REQUIRE_EQUAL(userLatent.n_rows, rank);
BOOST_REQUIRE_EQUAL(userLatent.n_cols, numUsers);
BOOST_REQUIRE_EQUAL(itemBias.n_elem, numItems);
BOOST_REQUIRE_EQUAL(userBias.n_elem, numUsers);
REQUIRE(itemLatent.n_rows == numItems);
REQUIRE(itemLatent.n_cols == rank);
REQUIRE(userLatent.n_rows == rank);
REQUIRE(userLatent.n_cols == numUsers);
REQUIRE(itemBias.n_elem == numItems);
REQUIRE(userBias.n_elem == numUsers);
}
BOOST_AUTO_TEST_CASE(BiasSVDFunctionOptimize)
TEST_CASE("BiasSVDFunctionOptimize", "[BiasSVDTest]")
{
// Define useful constants.
const size_t numUsers = 50;
@@ -299,7 +296,7 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionOptimize)
arma::norm(data, "frob");
// Relative error should be small.
BOOST_REQUIRE_SMALL(relativeError, 1e-2);
REQUIRE(relativeError == Approx(0.0).margin(1e-2));
}
// The test is only compiled if the user has specified OpenMP to be
@@ -307,7 +304,7 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionOptimize)
#ifdef HAS_OPENMP
// Test Bias SVD with parallel SGD.
BOOST_AUTO_TEST_CASE(BiasSVDFunctionParallelOptimize)
TEST_CASE("BiasSVDFunctionParallelOptimize", "[BiasSVDTest]")
{
// Define useful constants.
const size_t numUsers = 50;
@@ -374,9 +371,7 @@ BOOST_AUTO_TEST_CASE(BiasSVDFunctionParallelOptimize)
arma::norm(data, "frob");
// Relative error should be small.
BOOST_REQUIRE_SMALL(relativeError, 1e-2);
REQUIRE(relativeError == Approx(0.0).margin(1e-2));
}
#endif
BOOST_AUTO_TEST_SUITE_END();
+7 -11
View File
@@ -13,10 +13,7 @@
#include <mlpack/core.hpp>
#include <mlpack/methods/block_krylov_svd/randomized_block_krylov_svd.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
BOOST_AUTO_TEST_SUITE(BlockKrylovSVDTest);
#include "catch.hpp"
using namespace mlpack;
@@ -48,7 +45,8 @@ void CreateNoisyLowRankMatrix(arma::mat& data,
* The reconstruction and sigular value error of the obtained SVD should be
* small.
*/
BOOST_AUTO_TEST_CASE(RandomizedBlockKrylovSVDReconstructionError)
TEST_CASE("RandomizedBlockKrylovSVDReconstructionError",
"[BlockKrylovSVDTest]")
{
arma::mat U = arma::randn<arma::mat>(3, 20);
arma::mat V = arma::randn<arma::mat>(10, 3);
@@ -78,20 +76,20 @@ BOOST_AUTO_TEST_CASE(RandomizedBlockKrylovSVDReconstructionError)
// The sigular value error should be small.
double error = arma::norm(s2 - s3, "frob") / arma::norm(s2, "frob");
BOOST_REQUIRE_SMALL(error, 1e-5);
REQUIRE(error == Approx(0.0).margin(1e-5));
arma::mat reconstruct = U2 * arma::diagmat(s2) * V2.t();
// The relative reconstruction error should be small.
error = arma::norm(centeredData - reconstruct, "frob") /
arma::norm(centeredData, "frob");
BOOST_REQUIRE_SMALL(error, 1e-5);
REQUIRE(error == Approx(0.0).margin(1e-7));
}
/*
* Check if the method can handle noisy matrices.
*/
BOOST_AUTO_TEST_CASE(RandomizedBlockKrylovSVDNoisyLowRankTest)
TEST_CASE("RandomizedBlockKrylovSVDNoisyLowRankTest", "[BlockKrylovSVDTest]")
{
arma::mat data;
CreateNoisyLowRankMatrix(data, 200, 1000, 5, 0.5);
@@ -106,7 +104,5 @@ BOOST_AUTO_TEST_CASE(RandomizedBlockKrylovSVDNoisyLowRankTest)
svd::RandomizedBlockKrylovSVD rSVDB(data, U2, s2, V2, 10, rank, 20);
double error = arma::max(arma::abs(s1.subvec(0, rank) - s2.subvec(0, rank)));
BOOST_REQUIRE_SMALL(error, 1e-2);
REQUIRE(error == Approx(0.0).margin(1e-4));
}
BOOST_AUTO_TEST_SUITE_END();
+53 -58
View File
@@ -12,22 +12,19 @@
#include <mlpack/core.hpp>
#include <mlpack/methods/decision_stump/decision_stump.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "catch.hpp"
using namespace mlpack;
using namespace mlpack::decision_stump;
using namespace arma;
using namespace mlpack::distribution;
BOOST_AUTO_TEST_SUITE(DecisionStumpTest);
/**
* This tests handles the case wherein only one class exists in the input
* labels. It checks whether the only class supplied was the only class
* predicted.
*/
BOOST_AUTO_TEST_CASE(OneClass)
TEST_CASE("OneClass", "[DecisionStumpTest]")
{
const size_t numClasses = 2;
const size_t inpBucketSize = 6;
@@ -50,7 +47,7 @@ BOOST_AUTO_TEST_CASE(OneClass)
ds.Classify(testingData, predictedLabels);
for (size_t i = 0; i < predictedLabels.size(); ++i)
BOOST_CHECK_EQUAL(predictedLabels(i), 1);
REQUIRE(predictedLabels(i) == 1);
}
/**
@@ -58,7 +55,7 @@ BOOST_AUTO_TEST_CASE(OneClass)
* correct value of the splitting column value. This test is for an
* inpBucketSize of 4 and the correct value of the splitting dimension is 0.
*/
BOOST_AUTO_TEST_CASE(CorrectDimensionChosen)
TEST_CASE("CorrectDimensionChosen", "[DecisionStumpTest]")
{
const size_t numClasses = 2;
const size_t inpBucketSize = 4;
@@ -84,7 +81,7 @@ BOOST_AUTO_TEST_CASE(CorrectDimensionChosen)
// Only need to check the value of the splitting column, no need of
// classification.
BOOST_CHECK_EQUAL(ds.SplitDimension(), 0);
REQUIRE(ds.SplitDimension() == 0);
}
/**
@@ -93,7 +90,7 @@ BOOST_AUTO_TEST_CASE(CorrectDimensionChosen)
* if testinput > 0 - class 1
* An almost perfect split on zero.
*/
BOOST_AUTO_TEST_CASE(PerfectSplitOnZero)
TEST_CASE("PerfectSplitOnZero", "[DecisionStumpTest]")
{
const size_t numClasses = 2;
const size_t inpBucketSize = 2;
@@ -113,18 +110,18 @@ BOOST_AUTO_TEST_CASE(PerfectSplitOnZero)
Row<size_t> predictedLabels;
ds.Classify(testingData, predictedLabels);
BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 1), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 2), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 3), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 4), 1);
REQUIRE(predictedLabels(0, 0) == 0);
REQUIRE(predictedLabels(0, 1) == 1);
REQUIRE(predictedLabels(0, 2) == 0);
REQUIRE(predictedLabels(0, 3) == 0);
REQUIRE(predictedLabels(0, 4) == 1);
}
/**
* This tests the binning function for the case when a dataset with cardinality
* of input < inpBucketSize is provided.
*/
BOOST_AUTO_TEST_CASE(BinningTesting)
TEST_CASE("BinningTesting", "[DecisionStumpTest]")
{
const size_t numClasses = 2;
const size_t inpBucketSize = 10;
@@ -144,7 +141,7 @@ BOOST_AUTO_TEST_CASE(BinningTesting)
Row<size_t> predictedLabels;
ds.Classify(testingData, predictedLabels);
BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0);
REQUIRE(predictedLabels(0, 0) == 0);
}
/**
@@ -152,7 +149,7 @@ BOOST_AUTO_TEST_CASE(BinningTesting)
* provided. It tests for a perfect split due to the non-overlapping nature of
* the input classes.
*/
BOOST_AUTO_TEST_CASE(PerfectMultiClassSplit)
TEST_CASE("PerfectMultiClassSplit", "[DecisionStumpTest]")
{
const size_t numClasses = 4;
const size_t inpBucketSize = 3;
@@ -174,10 +171,10 @@ BOOST_AUTO_TEST_CASE(PerfectMultiClassSplit)
Row<size_t> predictedLabels;
ds.Classify(testingData, predictedLabels);
BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 1), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 2), 2);
BOOST_CHECK_EQUAL(predictedLabels(0, 3), 3);
REQUIRE(predictedLabels(0, 0) == 0);
REQUIRE(predictedLabels(0, 1) == 1);
REQUIRE(predictedLabels(0, 2) == 2);
REQUIRE(predictedLabels(0, 3) == 3);
}
/**
@@ -186,7 +183,7 @@ BOOST_AUTO_TEST_CASE(PerfectMultiClassSplit)
* with a reasonable amount of error due to the overlapping nature of input
* classes.
*/
BOOST_AUTO_TEST_CASE(MultiClassSplit)
TEST_CASE("MultiClassSplit", "[DecisionStumpTest]")
{
const size_t numClasses = 3;
const size_t inpBucketSize = 3;
@@ -209,21 +206,21 @@ BOOST_AUTO_TEST_CASE(MultiClassSplit)
Row<size_t> predictedLabels;
ds.Classify(testingData, predictedLabels);
BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 1), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 2), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 3), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 4), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 5), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 6), 2);
BOOST_CHECK_EQUAL(predictedLabels(0, 7), 2);
REQUIRE(predictedLabels(0, 0) == 0);
REQUIRE(predictedLabels(0, 1) == 0);
REQUIRE(predictedLabels(0, 2) == 1);
REQUIRE(predictedLabels(0, 3) == 1);
REQUIRE(predictedLabels(0, 4) == 1);
REQUIRE(predictedLabels(0, 5) == 1);
REQUIRE(predictedLabels(0, 6) == 2);
REQUIRE(predictedLabels(0, 7) == 2);
}
/**
* This tests that the decision stump can learn a good split on a dataset with
* four dimensions that have progressing levels of separation.
*/
BOOST_AUTO_TEST_CASE(DimensionSelectionTest)
TEST_CASE("DimensionSelectionTest", "[DecisionStumpTest]")
{
const size_t numClasses = 2;
const size_t inpBucketSize = 2500;
@@ -299,16 +296,16 @@ BOOST_AUTO_TEST_CASE(DimensionSelectionTest)
DecisionStump<> ds(dataset, labels, numClasses, inpBucketSize);
// Make sure it split on the dimension that is most separable.
BOOST_CHECK_EQUAL(ds.SplitDimension(), 1);
REQUIRE(ds.SplitDimension() == 1);
// Make sure every bin below -1 classifies as label 0, and every bin above 1
// classifies as label 1 (What happens in [-1, 1] isn't that big a deal.).
for (size_t i = 0; i < ds.Split().n_elem; ++i)
{
if (ds.Split()[i] <= -3.0)
BOOST_CHECK_EQUAL(ds.BinLabels()[i], 0);
REQUIRE(ds.BinLabels()[i] == 0);
else if (ds.Split()[i] >= 3.0)
BOOST_CHECK_EQUAL(ds.BinLabels()[i], 1);
REQUIRE(ds.BinLabels()[i] == 1);
}
}
@@ -316,7 +313,7 @@ BOOST_AUTO_TEST_CASE(DimensionSelectionTest)
* Ensure that the default constructor works and that it classifies things as 0
* always.
*/
BOOST_AUTO_TEST_CASE(EmptyConstructorTest)
TEST_CASE("EmptyConstructorTest", "[DecisionStumpTest]")
{
DecisionStump<> d;
@@ -326,7 +323,7 @@ BOOST_AUTO_TEST_CASE(EmptyConstructorTest)
d.Classify(data, labels);
for (size_t i = 0; i < 10; ++i)
BOOST_REQUIRE_EQUAL(labels[i], 0);
REQUIRE(labels[i] == 0);
// Now train on another dataset and make sure something kind of makes sense.
mat trainingData;
@@ -347,21 +344,21 @@ BOOST_AUTO_TEST_CASE(EmptyConstructorTest)
Row<size_t> predictedLabels(testingData.n_cols);
ds.Classify(testingData, predictedLabels);
BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 1), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 2), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 3), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 4), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 5), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 6), 2);
BOOST_CHECK_EQUAL(predictedLabels(0, 7), 2);
REQUIRE(predictedLabels(0, 0) == 0);
REQUIRE(predictedLabels(0, 1) == 0);
REQUIRE(predictedLabels(0, 2) == 1);
REQUIRE(predictedLabels(0, 3) == 1);
REQUIRE(predictedLabels(0, 4) == 1);
REQUIRE(predictedLabels(0, 5) == 1);
REQUIRE(predictedLabels(0, 6) == 2);
REQUIRE(predictedLabels(0, 7) == 2);
}
/**
* Ensure that a matrix holding ints can be trained. The bigger issue here is
* just compilation.
*/
BOOST_AUTO_TEST_CASE(IntTest)
TEST_CASE("IntTest", "[DecisionStumpTest]")
{
// Train on a dataset and make sure something kind of makes sense.
imat trainingData;
@@ -381,20 +378,20 @@ BOOST_AUTO_TEST_CASE(IntTest)
arma::Row<size_t> predictedLabels;
ds.Classify(testingData, predictedLabels);
BOOST_CHECK_EQUAL(predictedLabels(0, 0), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 1), 0);
BOOST_CHECK_EQUAL(predictedLabels(0, 2), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 3), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 4), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 5), 1);
BOOST_CHECK_EQUAL(predictedLabels(0, 6), 2);
BOOST_CHECK_EQUAL(predictedLabels(0, 7), 2);
REQUIRE(predictedLabels(0, 0) == 0);
REQUIRE(predictedLabels(0, 1) == 0);
REQUIRE(predictedLabels(0, 2) == 1);
REQUIRE(predictedLabels(0, 3) == 1);
REQUIRE(predictedLabels(0, 4) == 1);
REQUIRE(predictedLabels(0, 5) == 1);
REQUIRE(predictedLabels(0, 6) == 2);
REQUIRE(predictedLabels(0, 7) == 2);
}
/**
* Test that DecisionStump::Train() returns finite gain.
*/
BOOST_AUTO_TEST_CASE(DecisionStumpTrainReturnEntropy)
TEST_CASE("DecisionStumpTrainReturnEntropy", "[DecisionStumpTest]")
{
const size_t numClasses = 2;
const size_t inpBucketSize = 2;
@@ -413,14 +410,12 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTrainReturnEntropy)
double gain = ds.Train(trainingData, labelsIn.row(0), numClasses,
inpBucketSize);
BOOST_REQUIRE_EQUAL(std::isfinite(gain), true);
REQUIRE(std::isfinite(gain) == true);
// Train decision stump with weights.
DecisionStump<> wds;
gain = wds.Train(trainingData, labelsIn.row(0), weights, numClasses,
inpBucketSize);
BOOST_REQUIRE_EQUAL(std::isfinite(gain), true);
REQUIRE(std::isfinite(gain) == true);
}
BOOST_AUTO_TEST_SUITE_END();
+179 -175
View File
@@ -16,8 +16,7 @@
#include <mlpack/methods/decision_tree/random_dimension_select.hpp>
#include <mlpack/methods/decision_tree/multiple_random_dimension_select.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "catch.hpp"
#include "serialization.hpp"
#include "mock_categorical_data.hpp"
@@ -25,12 +24,10 @@ using namespace mlpack;
using namespace mlpack::tree;
using namespace mlpack::distribution;
BOOST_AUTO_TEST_SUITE(DecisionTreeTest);
/**
* Make sure the Gini gain is zero when the labels are perfect.
*/
BOOST_AUTO_TEST_CASE(GiniGainPerfectTest)
TEST_CASE("GiniGainPerfectTest", "[DecisionTreeTest]")
{
arma::rowvec weights(10, arma::fill::ones);
arma::Row<size_t> labels;
@@ -38,14 +35,17 @@ BOOST_AUTO_TEST_CASE(GiniGainPerfectTest)
// Test that it's perfect regardless of number of classes.
for (size_t c = 1; c < 10; ++c)
BOOST_REQUIRE_SMALL(GiniGain::Evaluate<false>(labels, c, weights), 1e-5);
{
REQUIRE(GiniGain::Evaluate<false>(labels, c, weights) ==
Approx(0.0).margin(1e-5));
}
}
/**
* Make sure the Gini gain is -0.5 when the class split between two classes
* is even.
*/
BOOST_AUTO_TEST_CASE(GiniGainEvenSplitTest)
TEST_CASE("GiniGainEvenSplitTest", "[DecisionTreeTest]")
{
arma::rowvec weights = arma::ones<arma::rowvec>(10);
arma::Row<size_t> labels(10);
@@ -57,35 +57,41 @@ BOOST_AUTO_TEST_CASE(GiniGainEvenSplitTest)
// Test that it's -0.5 regardless of the number of classes.
for (size_t c = 2; c < 10; ++c)
{
BOOST_REQUIRE_CLOSE(
GiniGain::Evaluate<false>(labels, c, weights), -0.5, 1e-5);
REQUIRE(GiniGain::Evaluate<false>(labels, c, weights) ==
Approx(-0.5).epsilon(1e-7));
double weightedGain = GiniGain::Evaluate<true>(labels, c, weights);
// The weighted gain should stay the same with unweight one
BOOST_REQUIRE_EQUAL(
GiniGain::Evaluate<false>(labels, c, weights), weightedGain);
REQUIRE(GiniGain::Evaluate<false>(labels, c, weights) == weightedGain);
}
}
/**
* The Gini gain of an empty vector is 0.
*/
BOOST_AUTO_TEST_CASE(GiniGainEmptyTest)
TEST_CASE("GiniGainEmptyTest", "[DecisionTreeTest]")
{
arma::rowvec weights = arma::ones<arma::rowvec>(10);
// Test across some numbers of classes.
arma::Row<size_t> labels;
for (size_t c = 1; c < 10; ++c)
BOOST_REQUIRE_SMALL(GiniGain::Evaluate<false>(labels, c, weights), 1e-5);
{
REQUIRE(GiniGain::Evaluate<false>(labels, c, weights) ==
Approx(0.0).margin(1e-5));
}
for (size_t c = 1; c < 10; ++c)
BOOST_REQUIRE_SMALL(GiniGain::Evaluate<true>(labels, c, weights), 1e-5);
{
REQUIRE(GiniGain::Evaluate<true>(labels, c, weights) ==
Approx(0.0).margin(1e-5));
}
}
/**
* The Gini gain is -(1 - 1/k) for k classes evenly split.
*/
BOOST_AUTO_TEST_CASE(GiniGainEvenSplitManyClassTest)
TEST_CASE("GiniGainEvenSplitManyClassTest", "[DecisionTreeTest]")
{
// Try with many different classes.
for (size_t c = 2; c < 30; ++c)
@@ -99,17 +105,17 @@ BOOST_AUTO_TEST_CASE(GiniGainEvenSplitManyClassTest)
}
// Calculate Gini gain and make sure it is correct.
BOOST_REQUIRE_CLOSE(GiniGain::Evaluate<false>(labels, c, weights),
-(1.0 - 1.0 / c), 1e-5);
BOOST_REQUIRE_CLOSE(GiniGain::Evaluate<true>(labels, c, weights),
-(1.0 - 1.0 / c), 1e-5);
REQUIRE(GiniGain::Evaluate<false>(labels, c, weights) ==
Approx(-(1.0 - 1.0 / c)).epsilon(1e-7));
REQUIRE(GiniGain::Evaluate<true>(labels, c, weights) ==
Approx(-(1.0 - 1.0 / c)).epsilon(1e-7));
}
}
/**
* The Gini gain should not be sensitive to the number of points.
*/
BOOST_AUTO_TEST_CASE(GiniGainManyPoints)
TEST_CASE("GiniGainManyPoints", "[DecisionTreeTest]")
{
for (size_t i = 1; i < 20; ++i)
{
@@ -121,11 +127,10 @@ BOOST_AUTO_TEST_CASE(GiniGainManyPoints)
labels[j] = 0;
for (size_t j = numPoints / 2; j < numPoints; ++j)
labels[j] = 1;
BOOST_REQUIRE_CLOSE(GiniGain::Evaluate<false>(labels, 2, weights), -0.5,
1e-5);
BOOST_REQUIRE_CLOSE(GiniGain::Evaluate<true>(labels, 2, weights), -0.5,
1e-5);
REQUIRE(GiniGain::Evaluate<false>(labels, 2, weights) ==
Approx(-0.5).epsilon(1e-7));
REQUIRE(GiniGain::Evaluate<true>(labels, 2, weights) ==
Approx(-0.5).epsilon(1e-7));
}
}
@@ -133,7 +138,7 @@ BOOST_AUTO_TEST_CASE(GiniGainManyPoints)
/**
* To make sure the Gini gain can been cacluate proporately with weight.
*/
BOOST_AUTO_TEST_CASE(GiniGainWithWeight)
TEST_CASE("GiniGainWithWeight", "[DecisionTreeTest]")
{
arma::Row<size_t> labels(10);
arma::rowvec weights(10);
@@ -148,14 +153,14 @@ BOOST_AUTO_TEST_CASE(GiniGainWithWeight)
weights[i] = 0.7;
}
BOOST_REQUIRE_CLOSE(
GiniGain::Evaluate<true>(labels, 2, weights), -0.42, 1e-5);
REQUIRE(GiniGain::Evaluate<true>(labels, 2, weights) ==
Approx(-0.42).epsilon(1e-7));
}
/**
* The information gain should be zero when the labels are perfect.
*/
BOOST_AUTO_TEST_CASE(InformationGainPerfectTest)
TEST_CASE("InformationGainPerfectTest", "[DecisionTreeTest]")
{
arma::rowvec weights;
arma::Row<size_t> labels;
@@ -164,15 +169,15 @@ BOOST_AUTO_TEST_CASE(InformationGainPerfectTest)
// Test that it's perfect regardless of number of classes.
for (size_t c = 1; c < 10; ++c)
{
BOOST_REQUIRE_SMALL(
InformationGain::Evaluate<false>(labels, c, weights), 1e-5);
REQUIRE(InformationGain::Evaluate<false>(labels, c, weights) ==
Approx(0.0).margin(1e-5));
}
}
/**
* If we have an even split, the information gain should be -1.
*/
BOOST_AUTO_TEST_CASE(InformationGainEvenSplitTest)
TEST_CASE("InformationGainEvenSplitTest", "[DecisionTreeTest]")
{
arma::Row<size_t> labels(10);
arma::rowvec weights(10);
@@ -186,33 +191,33 @@ BOOST_AUTO_TEST_CASE(InformationGainEvenSplitTest)
for (size_t c = 2; c < 10; ++c)
{
// Weighted and unweighted result should be the same.
BOOST_REQUIRE_CLOSE(InformationGain::Evaluate<false>(labels, c, weights),
-1.0, 1e-5);
BOOST_REQUIRE_CLOSE(InformationGain::Evaluate<true>(labels, c, weights),
-1.0, 1e-5);
REQUIRE(InformationGain::Evaluate<false>(labels, c, weights) ==
Approx(-1.0).epsilon(1e-7));
REQUIRE(InformationGain::Evaluate<true>(labels, c, weights) ==
Approx(-1.0).epsilon(1e-7));
}
}
/**
* The information gain of an empty vector is 0.
*/
BOOST_AUTO_TEST_CASE(InformationGainEmptyTest)
TEST_CASE("InformationGainEmptyTest", "[DecisionTreeTest]")
{
arma::Row<size_t> labels;
arma::rowvec weights = arma::ones<arma::rowvec>(10);
for (size_t c = 1; c < 10; ++c)
{
BOOST_REQUIRE_SMALL(InformationGain::Evaluate<false>(labels, c, weights),
1e-5);
BOOST_REQUIRE_SMALL(InformationGain::Evaluate<true>(labels, c, weights),
1e-5);
REQUIRE(InformationGain::Evaluate<false>(labels, c, weights) ==
Approx(0.0).margin(1e-5));
REQUIRE(InformationGain::Evaluate<true>(labels, c, weights) ==
Approx(0.0).margin(1e-5));
}
}
/**
* The information gain is log2(1/k) when splitting equal classes.
*/
BOOST_AUTO_TEST_CASE(InformationGainEvenSplitManyClassTest)
TEST_CASE("InformationGainEvenSplitManyClassTest", "[DecisionTreeTest]")
{
arma::rowvec weights;
// Try with many different numbers of classes.
@@ -223,15 +228,15 @@ BOOST_AUTO_TEST_CASE(InformationGainEvenSplitManyClassTest)
labels[i] = i;
// Calculate information gain and make sure it is correct.
BOOST_REQUIRE_CLOSE(InformationGain::Evaluate<false>(labels, c, weights),
std::log2(1.0 / c), 1e-5);
REQUIRE(InformationGain::Evaluate<false>(labels, c, weights) ==
Approx(std::log2(1.0 / c)).epsilon(1e-7));
}
}
/**
* Test the information gain with weighted labels
*/
BOOST_AUTO_TEST_CASE(InformationWithWeight)
TEST_CASE("InformationWithWeight", "[DecisionTreeTest]")
{
arma::Row<size_t> labels(10);
arma::rowvec weights("1 1 1 1 1 0 0 0 0 0");
@@ -242,15 +247,15 @@ BOOST_AUTO_TEST_CASE(InformationWithWeight)
// Zero is not a good result as gain, but we just need to prove
// cacluation works.
BOOST_REQUIRE_CLOSE(
InformationGain::Evaluate<true>(labels, 2, weights), 0, 1e-5);
REQUIRE(InformationGain::Evaluate<true>(labels, 2, weights) ==
Approx(0).epsilon(1e-7));
}
/**
* The information gain should not be sensitive to the number of points.
*/
BOOST_AUTO_TEST_CASE(InformationGainManyPoints)
TEST_CASE("InformationGainManyPoints", "[DecisionTreeTest]")
{
for (size_t i = 1; i < 20; ++i)
{
@@ -262,12 +267,13 @@ BOOST_AUTO_TEST_CASE(InformationGainManyPoints)
for (size_t j = numPoints / 2; j < numPoints; ++j)
labels[j] = 1;
BOOST_REQUIRE_CLOSE(InformationGain::Evaluate<false>(labels, 2, weights),
-1.0, 1e-5);
REQUIRE(InformationGain::Evaluate<false>(labels, 2, weights) ==
Approx(-1.0).epsilon(1e-7));
// It should make no difference between a weighted and unweighted
// calculation.
BOOST_REQUIRE_CLOSE(InformationGain::Evaluate<true>(labels, 2, weights),
-1.0, 1e-5);
REQUIRE(InformationGain::Evaluate<true>(labels, 2, weights) ==
Approx(-1.0).epsilon(1e-7));
}
}
@@ -275,7 +281,7 @@ BOOST_AUTO_TEST_CASE(InformationGainManyPoints)
* Check that the BestBinaryNumericSplit will split on an obviously splittable
* dimension.
*/
BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitSimpleSplitTest)
TEST_CASE("BestBinaryNumericSplitSimpleSplitTest", "[DecisionTreeTest]")
{
arma::vec values("0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0");
arma::Row<size_t> labels("0 0 0 0 0 1 1 1 1 1 1");
@@ -295,26 +301,26 @@ BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitSimpleSplitTest)
labels, 2, weights, 3, 1e-7, classProbabilities, aux);
// Make sure that a split was made.
BOOST_REQUIRE_GT(gain, bestGain);
REQUIRE(gain > bestGain);
// Make sure weight works and is not different than the unweighted one.
BOOST_REQUIRE_EQUAL(gain, weightedGain);
REQUIRE(gain == weightedGain);
// The split is perfect, so we should be able to accomplish a gain of 0.
BOOST_REQUIRE_SMALL(gain, 1e-5);
REQUIRE(gain == Approx(0.0).margin(1e-7));
// The class probabilities, for this split, hold the splitting point, which
// should be between 4 and 5.
BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 1);
BOOST_REQUIRE_GT(classProbabilities[0], 0.4);
BOOST_REQUIRE_LT(classProbabilities[0], 0.5);
REQUIRE(classProbabilities.n_elem == 1);
REQUIRE(classProbabilities[0] > 0.4);
REQUIRE(classProbabilities[0] < 0.5);
}
/**
* Check that the BestBinaryNumericSplit won't split if not enough points are
* given.
*/
BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitMinSamplesTest)
TEST_CASE("BestBinaryNumericSplitMinSamplesTest", "[DecisionTreeTest]")
{
arma::vec values("0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0");
arma::Row<size_t> labels("0 0 0 0 0 1 1 1 1 1 1");
@@ -334,16 +340,16 @@ BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitMinSamplesTest)
labels, 2, weights, 8, 1e-7, classProbabilities, aux);
// Make sure that no split was made.
BOOST_REQUIRE_EQUAL(gain, DBL_MAX);
BOOST_REQUIRE_EQUAL(gain, weightedGain);
BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 0);
REQUIRE(gain == DBL_MAX);
REQUIRE(gain == weightedGain);
REQUIRE(classProbabilities.n_elem == 0);
}
/**
* Check that the BestBinaryNumericSplit doesn't split a dimension that gives no
* gain.
*/
BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitNoGainTest)
TEST_CASE("BestBinaryNumericSplitNoGainTest", "[DecisionTreeTest]")
{
arma::vec values(100);
arma::Row<size_t> labels(100);
@@ -366,15 +372,15 @@ BOOST_AUTO_TEST_CASE(BestBinaryNumericSplitNoGainTest)
aux);
// Make sure there was no split.
BOOST_REQUIRE_EQUAL(gain, DBL_MAX);
BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 0);
REQUIRE(gain == DBL_MAX);
REQUIRE(classProbabilities.n_elem == 0);
}
/**
* Check that the AllCategoricalSplit will split when the split is obviously
* better.
*/
BOOST_AUTO_TEST_CASE(AllCategoricalSplitSimpleSplitTest)
TEST_CASE("AllCategoricalSplitSimpleSplitTest", "[DecisionTreeTest]")
{
arma::vec values("0 0 0 1 1 1 2 2 2 3 3 3");
arma::Row<size_t> labels("0 0 0 2 2 2 1 1 1 2 2 2");
@@ -394,23 +400,23 @@ BOOST_AUTO_TEST_CASE(AllCategoricalSplitSimpleSplitTest)
labels, 3, weights, 3, 1e-7, classProbabilities, aux);
// Make sure that a split was made.
BOOST_REQUIRE_GT(gain, bestGain);
REQUIRE(gain > bestGain);
// Since the split is perfect, make sure the new gain is 0.
BOOST_REQUIRE_SMALL(gain, 1e-5);
REQUIRE(gain == Approx(0.0).margin(1e-7));
BOOST_REQUIRE_EQUAL(gain, weightedGain);
REQUIRE(gain == weightedGain);
// Make sure the class probabilities now hold the number of children.
BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 1);
BOOST_REQUIRE_EQUAL((size_t) classProbabilities[0], 4);
REQUIRE(classProbabilities.n_elem == 1);
REQUIRE((size_t) classProbabilities[0] == 4);
}
/**
* Make sure that AllCategoricalSplit respects the minimum number of samples
* required to split.
*/
BOOST_AUTO_TEST_CASE(AllCategoricalSplitMinSamplesTest)
TEST_CASE("AllCategoricalSplitMinSamplesTest", "[DecisionTreeTest]")
{
arma::vec values("0 0 0 1 1 1 2 2 2 3 3 3");
arma::Row<size_t> labels("0 0 0 2 2 2 1 1 1 2 2 2");
@@ -427,14 +433,14 @@ BOOST_AUTO_TEST_CASE(AllCategoricalSplitMinSamplesTest)
aux);
// Make sure it's not split.
BOOST_REQUIRE_EQUAL(gain, DBL_MAX);
BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 0);
REQUIRE(gain == DBL_MAX);
REQUIRE(classProbabilities.n_elem == 0);
}
/**
* Check that no split is made when it doesn't get us anything.
*/
BOOST_AUTO_TEST_CASE(AllCategoricalSplitNoGainTest)
TEST_CASE("AllCategoricalSplitNoGainTest", "[DecisionTreeTest]")
{
arma::vec values(300);
arma::Row<size_t> labels(300);
@@ -463,16 +469,16 @@ BOOST_AUTO_TEST_CASE(AllCategoricalSplitNoGainTest)
labels, 3, weights, 10, 1e-7, classProbabilities, aux);
// Make sure that there was no split.
BOOST_REQUIRE_EQUAL(gain, DBL_MAX);
BOOST_REQUIRE_EQUAL(gain, weightedGain);
BOOST_REQUIRE_EQUAL(classProbabilities.n_elem, 0);
REQUIRE(gain == DBL_MAX);
REQUIRE(gain == weightedGain);
REQUIRE(classProbabilities.n_elem == 0);
}
/**
* A basic construction of the decision tree---ensure that we can create the
* tree and that it split at least once.
*/
BOOST_AUTO_TEST_CASE(BasicConstructionTest)
TEST_CASE("BasicConstructionTest", "[DecisionTreeTest]")
{
arma::mat dataset(10, 100, arma::fill::randu);
arma::Row<size_t> labels(100);
@@ -491,13 +497,13 @@ BOOST_AUTO_TEST_CASE(BasicConstructionTest)
DecisionTree<> d(dataset, labels, 2, 10);
// Now require that we have some children.
BOOST_REQUIRE_GT(d.NumChildren(), 0);
REQUIRE(d.NumChildren() > 0);
}
/**
* Construct a tree with weighted labels.
*/
BOOST_AUTO_TEST_CASE(BasicConstructionTestWithWeight)
TEST_CASE("BasicConstructionTestWithWeight", "[DecisionTreeTest]")
{
arma::mat dataset(10, 100, arma::fill::randu);
arma::Row<size_t> labels(100);
@@ -519,15 +525,15 @@ BOOST_AUTO_TEST_CASE(BasicConstructionTestWithWeight)
DecisionTree<> d(dataset, labels, 2, 10);
// Now require that we have some children.
BOOST_REQUIRE_GT(wd.NumChildren(), 0);
BOOST_REQUIRE_EQUAL(wd.NumChildren(), d.NumChildren());
REQUIRE(wd.NumChildren() > 0);
REQUIRE(wd.NumChildren() == d.NumChildren());
}
/**
* Construct the decision tree on numeric data only and see that we can fit it
* exactly and achieve perfect performance on the training set.
*/
BOOST_AUTO_TEST_CASE(PerfectTrainingSet)
TEST_CASE("PerfectTrainingSet", "[DecisionTreeTest]")
{
arma::mat dataset(10, 100, arma::fill::randu);
arma::Row<size_t> labels(100);
@@ -551,14 +557,14 @@ BOOST_AUTO_TEST_CASE(PerfectTrainingSet)
arma::vec probabilities;
d.Classify(dataset.col(i), prediction, probabilities);
BOOST_REQUIRE_EQUAL(prediction, labels[i]);
BOOST_REQUIRE_EQUAL(probabilities.n_elem, 2);
REQUIRE(prediction == labels[i]);
REQUIRE(probabilities.n_elem == 2);
for (size_t j = 0; j < 2; ++j)
{
if (labels[i] == j)
BOOST_REQUIRE_CLOSE(probabilities[j], 1.0, 1e-5);
REQUIRE(probabilities[j] == Approx(1.0).epsilon(1e-7));
else
BOOST_REQUIRE_SMALL(probabilities[j], 1e-5);
REQUIRE(probabilities[j] == Approx(0.0).margin(1e-5));
}
}
}
@@ -566,7 +572,7 @@ BOOST_AUTO_TEST_CASE(PerfectTrainingSet)
/**
* Construct the decision tree with weighted labels
*/
BOOST_AUTO_TEST_CASE(PerfectTrainingSetWithWeight)
TEST_CASE("PerfectTrainingSetWithWeight", "[DecisionTreeTest]")
{
// Completely random dataset with no structure.
arma::mat dataset(10, 100, arma::fill::randu);
@@ -594,14 +600,14 @@ BOOST_AUTO_TEST_CASE(PerfectTrainingSetWithWeight)
arma::vec probabilities;
d.Classify(dataset.col(i), prediction, probabilities);
BOOST_REQUIRE_EQUAL(prediction, labels[i]);
BOOST_REQUIRE_EQUAL(probabilities.n_elem, 2);
REQUIRE(prediction == labels[i]);
REQUIRE(probabilities.n_elem == 2);
for (size_t j = 0; j < 2; ++j)
{
if (labels[i] == j)
BOOST_REQUIRE_CLOSE(probabilities[j], 1.0, 1e-5);
REQUIRE(probabilities[j] == Approx(1.0).epsilon(1e-7));
else
BOOST_REQUIRE_SMALL(probabilities[j], 1e-5);
REQUIRE(probabilities[j] == Approx(0.0).margin(1e-5));
}
}
}
@@ -610,7 +616,7 @@ BOOST_AUTO_TEST_CASE(PerfectTrainingSetWithWeight)
/**
* Make sure class probabilities are computed correctly in the root node.
*/
BOOST_AUTO_TEST_CASE(ClassProbabilityTest)
TEST_CASE("ClassProbabilityTest", "[DecisionTreeTest]")
{
arma::mat dataset(5, 100, arma::fill::randu);
arma::Row<size_t> labels(100);
@@ -623,30 +629,30 @@ BOOST_AUTO_TEST_CASE(ClassProbabilityTest)
// Create a decision tree that can't split.
DecisionTree<> d(dataset, labels, 2, 1000);
BOOST_REQUIRE_EQUAL(d.NumChildren(), 0);
REQUIRE(d.NumChildren() == 0);
// Estimate a point's probabilities.
arma::vec probabilities;
size_t prediction;
d.Classify(dataset.col(0), prediction, probabilities);
BOOST_REQUIRE_EQUAL(probabilities.n_elem, 2);
BOOST_REQUIRE_CLOSE(probabilities[0], 0.5, 1e-5);
BOOST_REQUIRE_CLOSE(probabilities[1], 0.5, 1e-5);
REQUIRE(probabilities.n_elem == 2);
REQUIRE(probabilities[0] == Approx(0.5).epsilon(1e-7));
REQUIRE(probabilities[1] == Approx(0.5).epsilon(1e-7));
}
/**
* Test that the decision tree generalizes reasonably.
*/
BOOST_AUTO_TEST_CASE(SimpleGeneralizationTest)
TEST_CASE("SimpleGeneralizationTest", "[DecisionTreeTest]")
{
arma::mat inputData;
if (!data::Load("vc2.csv", inputData))
BOOST_FAIL("Cannot load test dataset vc2.csv!");
FAIL("Cannot load test dataset vc2.csv!");
arma::Row<size_t> labels;
if (!data::Load("vc2_labels.txt", labels))
BOOST_FAIL("Cannot load labels for vc2_labels.txt");
FAIL("Cannot load labels for vc2_labels.txt");
// Initialize an all-ones weight matrix.
arma::rowvec weights(labels.n_cols, arma::fill::ones);
@@ -658,17 +664,17 @@ BOOST_AUTO_TEST_CASE(SimpleGeneralizationTest)
// Load testing data.
arma::mat testData;
if (!data::Load("vc2_test.csv", testData))
BOOST_FAIL("Cannot load test dataset vc2_test.csv!");
FAIL("Cannot load test dataset vc2_test.csv!");
arma::Mat<size_t> trueTestLabels;
if (!data::Load("vc2_test_labels.txt", trueTestLabels))
BOOST_FAIL("Cannot load labels for vc2_test_labels.txt");
FAIL("Cannot load labels for vc2_test_labels.txt");
// Get the predicted test labels.
arma::Row<size_t> predictions;
d.Classify(testData, predictions);
BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols);
REQUIRE(predictions.n_elem == testData.n_cols);
// Figure out the accuracy.
double correct = 0.0;
@@ -677,13 +683,13 @@ BOOST_AUTO_TEST_CASE(SimpleGeneralizationTest)
++correct;
correct /= predictions.n_elem;
BOOST_REQUIRE_GT(correct, 0.75);
REQUIRE(correct > 0.75);
// reset the prediction
predictions.zeros();
wd.Classify(testData, predictions);
BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols);
REQUIRE(predictions.n_elem == testData.n_cols);
// Figure out the accuracy.
double wdcorrect = 0.0;
@@ -692,13 +698,13 @@ BOOST_AUTO_TEST_CASE(SimpleGeneralizationTest)
++wdcorrect;
wdcorrect /= predictions.n_elem;
BOOST_REQUIRE_GT(wdcorrect, 0.75);
REQUIRE(wdcorrect > 0.75);
}
/**
* Test that we can build a decision tree on a simple categorical dataset.
*/
BOOST_AUTO_TEST_CASE(CategoricalBuildTest)
TEST_CASE("CategoricalBuildTest", "[DecisionTreeTest]")
{
arma::mat d;
arma::Row<size_t> l;
@@ -718,7 +724,7 @@ BOOST_AUTO_TEST_CASE(CategoricalBuildTest)
arma::Row<size_t> predictions;
tree.Classify(testData, predictions);
BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols);
REQUIRE(predictions.n_elem == testData.n_cols);
size_t correct = 0;
for (size_t i = 0; i < testData.n_cols; ++i)
if (testLabels[i] == predictions[i])
@@ -726,14 +732,14 @@ BOOST_AUTO_TEST_CASE(CategoricalBuildTest)
// Make sure we got at least 70% accuracy.
const double correctPct = double(correct) / double(testData.n_cols);
BOOST_REQUIRE_GT(correctPct, 0.70);
REQUIRE(correctPct > 0.70);
}
/**
* Test that we can build a decision tree with weights on a simple categorical
* dataset.
*/
BOOST_AUTO_TEST_CASE(CategoricalBuildTestWithWeight)
TEST_CASE("CategoricalBuildTestWithWeight", "[DecisionTreeTest]")
{
arma::mat d;
arma::Row<size_t> l;
@@ -756,7 +762,7 @@ BOOST_AUTO_TEST_CASE(CategoricalBuildTestWithWeight)
arma::Row<size_t> predictions;
tree.Classify(testData, predictions);
BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols);
REQUIRE(predictions.n_elem == testData.n_cols);
size_t correct = 0;
for (size_t i = 0; i < testData.n_cols; ++i)
if (testLabels[i] == predictions[i])
@@ -764,13 +770,13 @@ BOOST_AUTO_TEST_CASE(CategoricalBuildTestWithWeight)
// Make sure we got at least 70% accuracy.
const double correctPct = double(correct) / double(testData.n_cols);
BOOST_REQUIRE_GT(correctPct, 0.70);
REQUIRE(correctPct > 0.70);
}
/**
* Make sure that when we ask for a decision stump, we get one.
*/
BOOST_AUTO_TEST_CASE(DecisionStumpTest)
TEST_CASE("DecisionStumpTest", "[DecisionTreeTest]")
{
// Use a random dataset.
arma::mat dataset(10, 1000, arma::fill::randu);
@@ -783,10 +789,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTest)
AllDimensionSelect, double, true> stump(dataset, labels, 3, 1);
// Check that it has children.
BOOST_REQUIRE_EQUAL(stump.NumChildren(), 2);
REQUIRE(stump.NumChildren() == 2);
// Check that its children doesn't have children.
BOOST_REQUIRE_EQUAL(stump.Child(0).NumChildren(), 0);
BOOST_REQUIRE_EQUAL(stump.Child(1).NumChildren(), 0);
REQUIRE(stump.Child(0).NumChildren() == 0);
REQUIRE(stump.Child(1).NumChildren() == 0);
}
/**
@@ -794,7 +800,7 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTest)
* low-weighted data is random noise), and that the tree still builds correctly
* enough to get good results.
*/
BOOST_AUTO_TEST_CASE(WeightedDecisionTreeTest)
TEST_CASE("WeightedDecisionTreeTest", "[DecisionTreeTest]")
{
arma::mat dataset;
arma::Row<size_t> labels;
@@ -830,7 +836,7 @@ BOOST_AUTO_TEST_CASE(WeightedDecisionTreeTest)
arma::Row<size_t> predictions;
d.Classify(testData, predictions);
BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols);
REQUIRE(predictions.n_elem == testData.n_cols);
// Figure out the accuracy.
double correct = 0.0;
@@ -839,13 +845,13 @@ BOOST_AUTO_TEST_CASE(WeightedDecisionTreeTest)
++correct;
correct /= predictions.n_elem;
BOOST_REQUIRE_GT(correct, 0.75);
REQUIRE(correct > 0.75);
}
/**
* Test that we can build a decision tree on a simple categorical dataset using
* weights, with low-weight noise added.
*/
BOOST_AUTO_TEST_CASE(CategoricalWeightedBuildTest)
TEST_CASE("CategoricalWeightedBuildTest", "[DecisionTreeTest]")
{
arma::mat d;
arma::Row<size_t> l;
@@ -887,7 +893,7 @@ BOOST_AUTO_TEST_CASE(CategoricalWeightedBuildTest)
arma::Row<size_t> predictions;
tree.Classify(testData, predictions);
BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols);
REQUIRE(predictions.n_elem == testData.n_cols);
size_t correct = 0;
for (size_t i = 0; i < testData.n_cols; ++i)
if (testLabels[i] == predictions[i])
@@ -895,7 +901,7 @@ BOOST_AUTO_TEST_CASE(CategoricalWeightedBuildTest)
// Make sure we got at least 70% accuracy.
const double correctPct = double(correct) / double(testData.n_cols);
BOOST_REQUIRE_GT(correctPct, 0.70);
REQUIRE(correctPct > 0.70);
}
/**
@@ -903,7 +909,7 @@ BOOST_AUTO_TEST_CASE(CategoricalWeightedBuildTest)
* low-weighted data is random noise) with information gain, and that the tree
* still builds correctly enough to get good results.
*/
BOOST_AUTO_TEST_CASE(WeightedDecisionTreeInformationGainTest)
TEST_CASE("WeightedDecisionTreeInformationGainTest", "[DecisionTreeTest]")
{
arma::mat dataset;
arma::Row<size_t> labels;
@@ -939,7 +945,7 @@ BOOST_AUTO_TEST_CASE(WeightedDecisionTreeInformationGainTest)
arma::Row<size_t> predictions;
d.Classify(testData, predictions);
BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols);
REQUIRE(predictions.n_elem == testData.n_cols);
// Figure out the accuracy.
double correct = 0.0;
@@ -948,13 +954,13 @@ BOOST_AUTO_TEST_CASE(WeightedDecisionTreeInformationGainTest)
++correct;
correct /= predictions.n_elem;
BOOST_REQUIRE_GT(correct, 0.75);
REQUIRE(correct > 0.75);
}
/**
* Test that we can build a decision tree using information gain on a simple
* categorical dataset using weights, with low-weight noise added.
*/
BOOST_AUTO_TEST_CASE(CategoricalInformationGainWeightedBuildTest)
TEST_CASE("CategoricalInformationGainWeightedBuildTest", "[DecisionTreeTest]")
{
arma::mat d;
arma::Row<size_t> l;
@@ -996,7 +1002,7 @@ BOOST_AUTO_TEST_CASE(CategoricalInformationGainWeightedBuildTest)
arma::Row<size_t> predictions;
tree.Classify(testData, predictions);
BOOST_REQUIRE_EQUAL(predictions.n_elem, testData.n_cols);
REQUIRE(predictions.n_elem == testData.n_cols);
size_t correct = 0;
for (size_t i = 0; i < testData.n_cols; ++i)
if (testLabels[i] == predictions[i])
@@ -1004,27 +1010,27 @@ BOOST_AUTO_TEST_CASE(CategoricalInformationGainWeightedBuildTest)
// Make sure we got at least 70% accuracy.
const double correctPct = double(correct) / double(testData.n_cols);
BOOST_REQUIRE_GT(correctPct, 0.70);
REQUIRE(correctPct > 0.70);
}
/**
* Make sure that the random dimension selector only has one element.
*/
BOOST_AUTO_TEST_CASE(RandomDimensionSelectTest)
TEST_CASE("RandomDimensionSelectTest", "[DecisionTreeTest]")
{
RandomDimensionSelect r;
r.Dimensions() = 10;
BOOST_REQUIRE_LT(r.Begin(), 10);
BOOST_REQUIRE_EQUAL(r.Next(), r.End());
BOOST_REQUIRE_EQUAL(r.Next(), r.End());
BOOST_REQUIRE_EQUAL(r.Next(), r.End());
REQUIRE(r.Begin() < 10);
REQUIRE(r.Next() == r.End());
REQUIRE(r.Next() == r.End());
REQUIRE(r.Next() == r.End());
}
/**
* Make sure that the random dimension selector selects different values.
*/
BOOST_AUTO_TEST_CASE(RandomDimensionSelectRandomTest)
TEST_CASE("RandomDimensionSelectRandomTest", "[DecisionTreeTest]")
{
// We'll check that 4 values are not all the same.
RandomDimensionSelect r1, r2, r3, r4;
@@ -1033,33 +1039,33 @@ BOOST_AUTO_TEST_CASE(RandomDimensionSelectRandomTest)
r3.Dimensions() = 100000;
r4.Dimensions() = 100000;
BOOST_REQUIRE((r1.Begin() != r2.Begin()) ||
(r1.Begin() != r3.Begin()) ||
(r1.Begin() != r4.Begin()));
REQUIRE(((r1.Begin() != r2.Begin()) ||
(r1.Begin() != r3.Begin()) ||
(r1.Begin() != r4.Begin())));
}
/**
* Make sure that the multiple random dimension select only has the right number
* of elements.
*/
BOOST_AUTO_TEST_CASE(MultipleRandomDimensionSelectTest)
TEST_CASE("MultipleRandomDimensionSelectTest", "[DecisionTreeTest]")
{
MultipleRandomDimensionSelect r(5);
r.Dimensions() = 10;
// Make sure we get five elements.
BOOST_REQUIRE_LT(r.Begin(), 10);
BOOST_REQUIRE_LT(r.Next(), 10);
BOOST_REQUIRE_LT(r.Next(), 10);
BOOST_REQUIRE_LT(r.Next(), 10);
BOOST_REQUIRE_LT(r.Next(), 10);
BOOST_REQUIRE_EQUAL(r.Next(), r.End());
REQUIRE(r.Begin() < 10);
REQUIRE(r.Next() < 10);
REQUIRE(r.Next() < 10);
REQUIRE(r.Next() < 10);
REQUIRE(r.Next() < 10);
REQUIRE(r.Next() == r.End());
}
/**
* Make sure we get every element from the distribution.
*/
BOOST_AUTO_TEST_CASE(MultipleRandomDimensionAllSelectTest)
TEST_CASE("MultipleRandomDimensionAllSelectTest", "[DecisionTreeTest]")
{
MultipleRandomDimensionSelect r(3);
r.Dimensions() = 3;
@@ -1071,24 +1077,24 @@ BOOST_AUTO_TEST_CASE(MultipleRandomDimensionAllSelectTest)
found[r.Next()] = true;
found[r.Next()] = true;
BOOST_REQUIRE_EQUAL(found[0], true);
BOOST_REQUIRE_EQUAL(found[1], true);
BOOST_REQUIRE_EQUAL(found[2], true);
REQUIRE(found[0] == true);
REQUIRE(found[1] == true);
REQUIRE(found[2] == true);
}
/**
* Make sure the right number of classes is returned for an empty tree (1).
*/
BOOST_AUTO_TEST_CASE(NumClassesEmptyTreeTest)
TEST_CASE("NumClassesEmptyTreeTest", "[DecisionTreeTest]")
{
DecisionTree<> dt;
BOOST_REQUIRE_EQUAL(dt.NumClasses(), 1);
REQUIRE(dt.NumClasses() == 1);
}
/**
* Make sure the right number of classes is returned for a nonempty tree.
*/
BOOST_AUTO_TEST_CASE(NumClassesTest)
TEST_CASE("NumClassesTest", "[DecisionTreeTest]")
{
// Load a dataset to train with.
arma::mat dataset;
@@ -1098,13 +1104,13 @@ BOOST_AUTO_TEST_CASE(NumClassesTest)
DecisionTree<> dt(dataset, labels, 3);
BOOST_REQUIRE_EQUAL(dt.NumClasses(), 3);
REQUIRE(dt.NumClasses() == 3);
}
/*
* Test that we can pass const data into DecisionTree constructors.
*/
BOOST_AUTO_TEST_CASE(ConstDataTest)
TEST_CASE("ConstDataTest", "[DecisionTreeTest]")
{
arma::mat data;
arma::Row<size_t> labels;
@@ -1127,7 +1133,7 @@ BOOST_AUTO_TEST_CASE(ConstDataTest)
* Construct the decision tree with splitting only if gain is more than
* threshold.
*/
BOOST_AUTO_TEST_CASE(RegularisedDecisionTree)
TEST_CASE("RegularisedDecisionTree", "[DecisionTreeTest]")
{
// Completely random dataset with no structure.
arma::mat dataset(10, 1000, arma::fill::randu);
@@ -1157,17 +1163,17 @@ BOOST_AUTO_TEST_CASE(RegularisedDecisionTree)
if (prediction != predictionsregularised)
count++;
BOOST_REQUIRE_EQUAL(probabilities.n_elem, 3);
BOOST_REQUIRE_EQUAL(probabilitiesRegularised.n_elem, 3);
REQUIRE(probabilities.n_elem == 3);
REQUIRE(probabilitiesRegularised.n_elem == 3);
}
BOOST_REQUIRE_GT(count, 0);
REQUIRE(count > 0);
}
/**
* Test that DecisionTree::Train() returns finite entropy on numeric dataset.
*/
BOOST_AUTO_TEST_CASE(DecisionTreeNumericTrainReturnEntropy)
TEST_CASE("DecisionTreeNumericTrainReturnEntropy", "[DecisionTreeTest]")
{
arma::mat dataset(10, 1000, arma::fill::randu);
arma::Row<size_t> labels(1000);
@@ -1181,20 +1187,20 @@ BOOST_AUTO_TEST_CASE(DecisionTreeNumericTrainReturnEntropy)
DecisionTree<> d(3);
double entropy = d.Train(dataset, labels, 3, 50);
BOOST_REQUIRE_EQUAL(std::isfinite(entropy), true);
REQUIRE(std::isfinite(entropy) == true);
// Train a tree with weights on numeric dataset.
DecisionTree<> wd(3);
entropy = wd.Train(dataset, labels, 3, weights, 50);
BOOST_REQUIRE_EQUAL(std::isfinite(entropy), true);
REQUIRE(std::isfinite(entropy) == true);
}
/**
* Test that DecisionTree::Train() returns finite entropy on categorical
* dataset.
*/
BOOST_AUTO_TEST_CASE(DecisionTreeCategoricalTrainReturnEntropy)
TEST_CASE("DecisionTreeCategoricalTrainReturnEntropy", "[DecisionTreeTest]")
{
arma::mat d;
arma::Row<size_t> l;
@@ -1207,19 +1213,19 @@ BOOST_AUTO_TEST_CASE(DecisionTreeCategoricalTrainReturnEntropy)
DecisionTree<> dtree(5);
double entropy = dtree.Train(d, di, l, 5, 10);
BOOST_REQUIRE_EQUAL(std::isfinite(entropy), true);
REQUIRE(std::isfinite(entropy) == true);
// Train a tree with weights on categorical dataset.
DecisionTree<> wdtree(5);
entropy = wdtree.Train(d, di, l, 5, weights, 10);
BOOST_REQUIRE_EQUAL(std::isfinite(entropy), true);
REQUIRE(std::isfinite(entropy) == true);
}
/**
* Make sure different maximum depth values give different numbers of children.
*/
BOOST_AUTO_TEST_CASE(DifferentMaximumDepthTest)
TEST_CASE("DifferentMaximumDepthTest", "[DecisionTreeTest]")
{
arma::mat dataset;
arma::Row<size_t> labels;
@@ -1233,17 +1239,15 @@ BOOST_AUTO_TEST_CASE(DifferentMaximumDepthTest)
DecisionTree<> d2(dataset, labels, 3, 10, 1e-7);
// Now require that we have zero children.
BOOST_REQUIRE_EQUAL(d.NumChildren(), 0);
REQUIRE(d.NumChildren() == 0);
// Now require that we have two children.
BOOST_REQUIRE_EQUAL(d1.NumChildren(), 2);
BOOST_REQUIRE_EQUAL(d1.Child(0).NumChildren(), 0);
BOOST_REQUIRE_EQUAL(d1.Child(1).NumChildren(), 0);
REQUIRE(d1.NumChildren() == 2);
REQUIRE(d1.Child(0).NumChildren() == 0);
REQUIRE(d1.Child(1).NumChildren() == 0);
// Now require that we have two children.
BOOST_REQUIRE_EQUAL(d2.NumChildren(), 2);
BOOST_REQUIRE_EQUAL(d2.Child(0).NumChildren(), 2);
BOOST_REQUIRE_EQUAL(d2.Child(1).NumChildren(), 2);
REQUIRE(d2.NumChildren() == 2);
REQUIRE(d2.Child(0).NumChildren() == 2);
REQUIRE(d2.Child(1).NumChildren() == 2);
}
BOOST_AUTO_TEST_SUITE_END();
+247 -251
View File
@@ -11,8 +11,8 @@
#include <mlpack/core.hpp>
#include <mlpack/methods/neighbor_search/neighbor_search.hpp>
#include <mlpack/core/tree/cover_tree.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "test_catch_tools.hpp"
#include "catch.hpp"
using namespace mlpack;
using namespace mlpack::neighbor;
@@ -20,8 +20,6 @@ using namespace mlpack::tree;
using namespace mlpack::metric;
using namespace mlpack::bound;
BOOST_AUTO_TEST_SUITE(KFNTest);
/**
* Simple furthest-neighbors test with small, synthetic dataset. This is an
* exhaustive test, which checks that each method for performing the calculation
@@ -30,7 +28,7 @@ BOOST_AUTO_TEST_SUITE(KFNTest);
* is in one dimension for simplicity -- the correct functionality of distance
* functions is not tested here.
*/
BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest)
TEST_CASE("KFNExhaustiveSyntheticTest", "[KFNTest]")
{
// Set up our data.
arma::mat data(1, 11);
@@ -82,246 +80,246 @@ BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest)
// readability.
// Neighbors of point 0.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[0]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[0]), 0.10, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[0]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[0]), 0.27, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[0]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[0]), 0.30, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[0]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[0]), 0.40, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[0]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[0]), 0.85, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[0]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[0]), 0.95, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[0]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[0]), 1.20, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[0]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[0]), 1.35, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[0]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[0]), 2.05, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[0]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[0]), 5.00, 1e-5);
REQUIRE(neighbors(9, newFromOld[0]) == newFromOld[2]);
REQUIRE(distances(9, newFromOld[0]) == Approx(0.10).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[0]) == newFromOld[5]);
REQUIRE(distances(8, newFromOld[0]) == Approx(0.27).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[0]) == newFromOld[1]);
REQUIRE(distances(7, newFromOld[0]) == Approx(0.30).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[0]) == newFromOld[8]);
REQUIRE(distances(6, newFromOld[0]) == Approx(0.40).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[0]) == newFromOld[9]);
REQUIRE(distances(5, newFromOld[0]) == Approx(0.85).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[0]) == newFromOld[10]);
REQUIRE(distances(4, newFromOld[0]) == Approx(0.95).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[0]) == newFromOld[3]);
REQUIRE(distances(3, newFromOld[0]) == Approx(1.20).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[0]) == newFromOld[7]);
REQUIRE(distances(2, newFromOld[0]) == Approx(1.35).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[0]) == newFromOld[6]);
REQUIRE(distances(1, newFromOld[0]) == Approx(2.05).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[0]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[0]) == Approx(5.00).epsilon(1e-7));
// Neighbors of point 1.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[1]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[1]), 0.10, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[1]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[1]), 0.20, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[1]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[1]), 0.30, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[1]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[1]), 0.55, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[1]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[1]), 0.57, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[1]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[1]), 0.65, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[1]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[1]), 0.90, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[1]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[1]), 1.65, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[1]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[1]), 2.35, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[1]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[1]), 4.70, 1e-5);
REQUIRE(neighbors(9, newFromOld[1]) == newFromOld[8]);
REQUIRE(distances(9, newFromOld[1]) == Approx(0.10).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[1]) == newFromOld[2]);
REQUIRE(distances(8, newFromOld[1]) == Approx(0.20).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[1]) == newFromOld[0]);
REQUIRE(distances(7, newFromOld[1]) == Approx(0.30).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[1]) == newFromOld[9]);
REQUIRE(distances(6, newFromOld[1]) == Approx(0.55).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[1]) == newFromOld[5]);
REQUIRE(distances(5, newFromOld[1]) == Approx(0.57).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[1]) == newFromOld[10]);
REQUIRE(distances(4, newFromOld[1]) == Approx(0.65).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[1]) == newFromOld[3]);
REQUIRE(distances(3, newFromOld[1]) == Approx(0.90).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[1]) == newFromOld[7]);
REQUIRE(distances(2, newFromOld[1]) == Approx(1.65).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[1]) == newFromOld[6]);
REQUIRE(distances(1, newFromOld[1]) == Approx(2.35).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[1]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[1]) == Approx(4.70).epsilon(1e-7));
// Neighbors of point 2.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[2]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[2]), 0.10, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[2]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[2]), 0.20, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[2]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[2]), 0.30, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[2]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[2]), 0.37, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[2]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[2]), 0.75, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[2]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[2]), 0.85, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[2]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[2]), 1.10, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[2]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[2]), 1.45, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[2]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[2]), 2.15, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[2]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[2]), 4.90, 1e-5);
REQUIRE(neighbors(9, newFromOld[2]) == newFromOld[0]);
REQUIRE(distances(9, newFromOld[2]) == Approx(0.10).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[2]) == newFromOld[1]);
REQUIRE(distances(8, newFromOld[2]) == Approx(0.20).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[2]) == newFromOld[8]);
REQUIRE(distances(7, newFromOld[2]) == Approx(0.30).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[2]) == newFromOld[5]);
REQUIRE(distances(6, newFromOld[2]) == Approx(0.37).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[2]) == newFromOld[9]);
REQUIRE(distances(5, newFromOld[2]) == Approx(0.75).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[2]) == newFromOld[10]);
REQUIRE(distances(4, newFromOld[2]) == Approx(0.85).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[2]) == newFromOld[3]);
REQUIRE(distances(3, newFromOld[2]) == Approx(1.10).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[2]) == newFromOld[7]);
REQUIRE(distances(2, newFromOld[2]) == Approx(1.45).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[2]) == newFromOld[6]);
REQUIRE(distances(1, newFromOld[2]) == Approx(2.15).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[2]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[2]) == Approx(4.90).epsilon(1e-7));
// Neighbors of point 3.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[3]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[3]), 0.25, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[3]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[3]), 0.35, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[3]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[3]), 0.80, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[3]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[3]), 0.90, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[3]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[3]), 1.10, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[3]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[3]), 1.20, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[3]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[3]), 1.47, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[3]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[3]), 2.55, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[3]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[3]), 3.25, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[3]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[3]), 3.80, 1e-5);
REQUIRE(neighbors(9, newFromOld[3]) == newFromOld[10]);
REQUIRE(distances(9, newFromOld[3]) == Approx(0.25).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[3]) == newFromOld[9]);
REQUIRE(distances(8, newFromOld[3]) == Approx(0.35).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[3]) == newFromOld[8]);
REQUIRE(distances(7, newFromOld[3]) == Approx(0.80).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[3]) == newFromOld[1]);
REQUIRE(distances(6, newFromOld[3]) == Approx(0.90).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[3]) == newFromOld[2]);
REQUIRE(distances(5, newFromOld[3]) == Approx(1.10).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[3]) == newFromOld[0]);
REQUIRE(distances(4, newFromOld[3]) == Approx(1.20).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[3]) == newFromOld[5]);
REQUIRE(distances(3, newFromOld[3]) == Approx(1.47).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[3]) == newFromOld[7]);
REQUIRE(distances(2, newFromOld[3]) == Approx(2.55).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[3]) == newFromOld[6]);
REQUIRE(distances(1, newFromOld[3]) == Approx(3.25).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[3]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[3]) == Approx(3.80).epsilon(1e-7));
// Neighbors of point 4.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[4]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[4]), 3.80, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[4]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[4]), 4.05, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[4]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[4]), 4.15, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[4]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[4]), 4.60, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[4]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[4]), 4.70, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[4]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[4]), 4.90, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[4]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[4]), 5.00, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[4]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[4]), 5.27, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[4]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[4]), 6.35, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[4]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[4]), 7.05, 1e-5);
REQUIRE(neighbors(9, newFromOld[4]) == newFromOld[3]);
REQUIRE(distances(9, newFromOld[4]) == Approx(3.80).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[4]) == newFromOld[10]);
REQUIRE(distances(8, newFromOld[4]) == Approx(4.05).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[4]) == newFromOld[9]);
REQUIRE(distances(7, newFromOld[4]) == Approx(4.15).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[4]) == newFromOld[8]);
REQUIRE(distances(6, newFromOld[4]) == Approx(4.60).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[4]) == newFromOld[1]);
REQUIRE(distances(5, newFromOld[4]) == Approx(4.70).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[4]) == newFromOld[2]);
REQUIRE(distances(4, newFromOld[4]) == Approx(4.90).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[4]) == newFromOld[0]);
REQUIRE(distances(3, newFromOld[4]) == Approx(5.00).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[4]) == newFromOld[5]);
REQUIRE(distances(2, newFromOld[4]) == Approx(5.27).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[4]) == newFromOld[7]);
REQUIRE(distances(1, newFromOld[4]) == Approx(6.35).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[4]) == newFromOld[6]);
REQUIRE(distances(0, newFromOld[4]) == Approx(7.05).epsilon(1e-7));
// Neighbors of point 5.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[5]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[5]), 0.27, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[5]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[5]), 0.37, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[5]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[5]), 0.57, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[5]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[5]), 0.67, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[5]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[5]), 1.08, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[5]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[5]), 1.12, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[5]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[5]), 1.22, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[5]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[5]), 1.47, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[5]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[5]), 1.78, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[5]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[5]), 5.27, 1e-5);
REQUIRE(neighbors(9, newFromOld[5]) == newFromOld[0]);
REQUIRE(distances(9, newFromOld[5]) == Approx(0.27).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[5]) == newFromOld[2]);
REQUIRE(distances(8, newFromOld[5]) == Approx(0.37).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[5]) == newFromOld[1]);
REQUIRE(distances(7, newFromOld[5]) == Approx(0.57).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[5]) == newFromOld[8]);
REQUIRE(distances(6, newFromOld[5]) == Approx(0.67).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[5]) == newFromOld[7]);
REQUIRE(distances(5, newFromOld[5]) == Approx(1.08).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[5]) == newFromOld[9]);
REQUIRE(distances(4, newFromOld[5]) == Approx(1.12).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[5]) == newFromOld[10]);
REQUIRE(distances(3, newFromOld[5]) == Approx(1.22).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[5]) == newFromOld[3]);
REQUIRE(distances(2, newFromOld[5]) == Approx(1.47).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[5]) == newFromOld[6]);
REQUIRE(distances(1, newFromOld[5]) == Approx(1.78).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[5]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[5]) == Approx(5.27).epsilon(1e-7));
// Neighbors of point 6.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[6]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[6]), 0.70, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[6]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[6]), 1.78, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[6]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[6]), 2.05, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[6]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[6]), 2.15, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[6]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[6]), 2.35, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[6]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[6]), 2.45, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[6]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[6]), 2.90, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[6]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[6]), 3.00, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[6]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[6]), 3.25, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[6]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[6]), 7.05, 1e-5);
REQUIRE(neighbors(9, newFromOld[6]) == newFromOld[7]);
REQUIRE(distances(9, newFromOld[6]) == Approx(0.70).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[6]) == newFromOld[5]);
REQUIRE(distances(8, newFromOld[6]) == Approx(1.78).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[6]) == newFromOld[0]);
REQUIRE(distances(7, newFromOld[6]) == Approx(2.05).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[6]) == newFromOld[2]);
REQUIRE(distances(6, newFromOld[6]) == Approx(2.15).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[6]) == newFromOld[1]);
REQUIRE(distances(5, newFromOld[6]) == Approx(2.35).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[6]) == newFromOld[8]);
REQUIRE(distances(4, newFromOld[6]) == Approx(2.45).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[6]) == newFromOld[9]);
REQUIRE(distances(3, newFromOld[6]) == Approx(2.90).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[6]) == newFromOld[10]);
REQUIRE(distances(2, newFromOld[6]) == Approx(3.00).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[6]) == newFromOld[3]);
REQUIRE(distances(1, newFromOld[6]) == Approx(3.25).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[6]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[6]) == Approx(7.05).epsilon(1e-7));
// Neighbors of point 7.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[7]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[7]), 0.70, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[7]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[7]), 1.08, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[7]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[7]), 1.35, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[7]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[7]), 1.45, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[7]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[7]), 1.65, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[7]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[7]), 1.75, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[7]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[7]), 2.20, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[7]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[7]), 2.30, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[7]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[7]), 2.55, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[7]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[7]), 6.35, 1e-5);
REQUIRE(neighbors(9, newFromOld[7]) == newFromOld[6]);
REQUIRE(distances(9, newFromOld[7]) == Approx(0.70).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[7]) == newFromOld[5]);
REQUIRE(distances(8, newFromOld[7]) == Approx(1.08).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[7]) == newFromOld[0]);
REQUIRE(distances(7, newFromOld[7]) == Approx(1.35).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[7]) == newFromOld[2]);
REQUIRE(distances(6, newFromOld[7]) == Approx(1.45).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[7]) == newFromOld[1]);
REQUIRE(distances(5, newFromOld[7]) == Approx(1.65).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[7]) == newFromOld[8]);
REQUIRE(distances(4, newFromOld[7]) == Approx(1.75).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[7]) == newFromOld[9]);
REQUIRE(distances(3, newFromOld[7]) == Approx(2.20).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[7]) == newFromOld[10]);
REQUIRE(distances(2, newFromOld[7]) == Approx(2.30).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[7]) == newFromOld[3]);
REQUIRE(distances(1, newFromOld[7]) == Approx(2.55).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[7]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[7]) == Approx(6.35).epsilon(1e-7));
// Neighbors of point 8.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[8]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[8]), 0.10, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[8]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[8]), 0.30, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[8]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[8]), 0.40, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[8]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[8]), 0.45, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[8]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[8]), 0.55, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[8]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[8]), 0.67, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[8]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[8]), 0.80, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[8]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[8]), 1.75, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[8]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[8]), 2.45, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[8]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[8]), 4.60, 1e-5);
REQUIRE(neighbors(9, newFromOld[8]) == newFromOld[1]);
REQUIRE(distances(9, newFromOld[8]) == Approx(0.10).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[8]) == newFromOld[2]);
REQUIRE(distances(8, newFromOld[8]) == Approx(0.30).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[8]) == newFromOld[0]);
REQUIRE(distances(7, newFromOld[8]) == Approx(0.40).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[8]) == newFromOld[9]);
REQUIRE(distances(6, newFromOld[8]) == Approx(0.45).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[8]) == newFromOld[10]);
REQUIRE(distances(5, newFromOld[8]) == Approx(0.55).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[8]) == newFromOld[5]);
REQUIRE(distances(4, newFromOld[8]) == Approx(0.67).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[8]) == newFromOld[3]);
REQUIRE(distances(3, newFromOld[8]) == Approx(0.80).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[8]) == newFromOld[7]);
REQUIRE(distances(2, newFromOld[8]) == Approx(1.75).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[8]) == newFromOld[6]);
REQUIRE(distances(1, newFromOld[8]) == Approx(2.45).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[8]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[8]) == Approx(4.60).epsilon(1e-7));
// Neighbors of point 9.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[9]), newFromOld[10]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[9]), 0.10, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[9]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[9]), 0.35, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[9]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[9]), 0.45, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[9]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[9]), 0.55, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[9]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[9]), 0.75, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[9]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[9]), 0.85, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[9]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[9]), 1.12, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[9]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[9]), 2.20, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[9]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[9]), 2.90, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[9]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[9]), 4.15, 1e-5);
REQUIRE(neighbors(9, newFromOld[9]) == newFromOld[10]);
REQUIRE(distances(9, newFromOld[9]) == Approx(0.10).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[9]) == newFromOld[3]);
REQUIRE(distances(8, newFromOld[9]) == Approx(0.35).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[9]) == newFromOld[8]);
REQUIRE(distances(7, newFromOld[9]) == Approx(0.45).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[9]) == newFromOld[1]);
REQUIRE(distances(6, newFromOld[9]) == Approx(0.55).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[9]) == newFromOld[2]);
REQUIRE(distances(5, newFromOld[9]) == Approx(0.75).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[9]) == newFromOld[0]);
REQUIRE(distances(4, newFromOld[9]) == Approx(0.85).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[9]) == newFromOld[5]);
REQUIRE(distances(3, newFromOld[9]) == Approx(1.12).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[9]) == newFromOld[7]);
REQUIRE(distances(2, newFromOld[9]) == Approx(2.20).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[9]) == newFromOld[6]);
REQUIRE(distances(1, newFromOld[9]) == Approx(2.90).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[9]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[9]) == Approx(4.15).epsilon(1e-7));
// Neighbors of point 10.
BOOST_REQUIRE_EQUAL(neighbors(9, newFromOld[10]), newFromOld[9]);
BOOST_REQUIRE_CLOSE(distances(9, newFromOld[10]), 0.10, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(8, newFromOld[10]), newFromOld[3]);
BOOST_REQUIRE_CLOSE(distances(8, newFromOld[10]), 0.25, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(7, newFromOld[10]), newFromOld[8]);
BOOST_REQUIRE_CLOSE(distances(7, newFromOld[10]), 0.55, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(6, newFromOld[10]), newFromOld[1]);
BOOST_REQUIRE_CLOSE(distances(6, newFromOld[10]), 0.65, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(5, newFromOld[10]), newFromOld[2]);
BOOST_REQUIRE_CLOSE(distances(5, newFromOld[10]), 0.85, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(4, newFromOld[10]), newFromOld[0]);
BOOST_REQUIRE_CLOSE(distances(4, newFromOld[10]), 0.95, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(3, newFromOld[10]), newFromOld[5]);
BOOST_REQUIRE_CLOSE(distances(3, newFromOld[10]), 1.22, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(2, newFromOld[10]), newFromOld[7]);
BOOST_REQUIRE_CLOSE(distances(2, newFromOld[10]), 2.30, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(1, newFromOld[10]), newFromOld[6]);
BOOST_REQUIRE_CLOSE(distances(1, newFromOld[10]), 3.00, 1e-5);
BOOST_REQUIRE_EQUAL(neighbors(0, newFromOld[10]), newFromOld[4]);
BOOST_REQUIRE_CLOSE(distances(0, newFromOld[10]), 4.05, 1e-5);
REQUIRE(neighbors(9, newFromOld[10]) == newFromOld[9]);
REQUIRE(distances(9, newFromOld[10]) == Approx(0.10).epsilon(1e-7));
REQUIRE(neighbors(8, newFromOld[10]) == newFromOld[3]);
REQUIRE(distances(8, newFromOld[10]) == Approx(0.25).epsilon(1e-7));
REQUIRE(neighbors(7, newFromOld[10]) == newFromOld[8]);
REQUIRE(distances(7, newFromOld[10]) == Approx(0.55).epsilon(1e-7));
REQUIRE(neighbors(6, newFromOld[10]) == newFromOld[1]);
REQUIRE(distances(6, newFromOld[10]) == Approx(0.65).epsilon(1e-7));
REQUIRE(neighbors(5, newFromOld[10]) == newFromOld[2]);
REQUIRE(distances(5, newFromOld[10]) == Approx(0.85).epsilon(1e-7));
REQUIRE(neighbors(4, newFromOld[10]) == newFromOld[0]);
REQUIRE(distances(4, newFromOld[10]) == Approx(0.95).epsilon(1e-7));
REQUIRE(neighbors(3, newFromOld[10]) == newFromOld[5]);
REQUIRE(distances(3, newFromOld[10]) == Approx(1.22).epsilon(1e-7));
REQUIRE(neighbors(2, newFromOld[10]) == newFromOld[7]);
REQUIRE(distances(2, newFromOld[10]) == Approx(2.30).epsilon(1e-7));
REQUIRE(neighbors(1, newFromOld[10]) == newFromOld[6]);
REQUIRE(distances(1, newFromOld[10]) == Approx(3.00).epsilon(1e-7));
REQUIRE(neighbors(0, newFromOld[10]) == newFromOld[4]);
REQUIRE(distances(0, newFromOld[10]) == Approx(4.05).epsilon(1e-7));
}
}
@@ -331,13 +329,13 @@ BOOST_AUTO_TEST_CASE(ExhaustiveSyntheticTest)
*
* Errors are produced if the results are not identical.
*/
BOOST_AUTO_TEST_CASE(DualTreeVsNaive1)
TEST_CASE("KFNDualTreeVsNaive1", "[KFNTest]")
{
arma::mat dataset;
// Hard-coded filename: bad?
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KFN kfn(dataset);
@@ -353,8 +351,8 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive1)
for (size_t i = 0; i < neighborsTree.n_elem; ++i)
{
BOOST_REQUIRE(neighborsTree[i] == neighborsNaive[i]);
BOOST_REQUIRE_CLOSE(distancesTree[i], distancesNaive[i], 1e-5);
REQUIRE(neighborsTree[i] == neighborsNaive[i]);
REQUIRE(distancesTree[i] == Approx(distancesNaive[i]).epsilon(1e-7));
}
}
@@ -364,14 +362,14 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive1)
*
* Errors are produced if the results are not identical.
*/
BOOST_AUTO_TEST_CASE(DualTreeVsNaive2)
TEST_CASE("KFNDualTreeVsNaive2", "[KFNTest]")
{
arma::mat dataset;
// Hard-coded filename: bad?
// Code duplication: also bad!
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KFN kfn(dataset);
@@ -387,8 +385,8 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive2)
for (size_t i = 0; i < neighborsTree.n_elem; ++i)
{
BOOST_REQUIRE_EQUAL(neighborsTree[i], neighborsNaive[i]);
BOOST_REQUIRE_CLOSE(distancesTree[i], distancesNaive[i], 1e-5);
REQUIRE(neighborsTree[i] == neighborsNaive[i]);
REQUIRE(distancesTree[i] == Approx(distancesNaive[i]).epsilon(1e-7));
}
}
@@ -398,14 +396,14 @@ BOOST_AUTO_TEST_CASE(DualTreeVsNaive2)
*
* Errors are produced if the results are not identical.
*/
BOOST_AUTO_TEST_CASE(SingleTreeVsNaive)
TEST_CASE("KFNSingleTreeVsNaive", "[KFNTest]")
{
arma::mat dataset;
// Hard-coded filename: bad!
// Code duplication: also bad!
if (!data::Load("test_data_3_1000.csv", dataset))
BOOST_FAIL("Cannot load test dataset test_data_3_1000.csv!");
FAIL("Cannot load test dataset test_data_3_1000.csv!");
KFN kfn(dataset, SINGLE_TREE_MODE);
@@ -421,8 +419,8 @@ BOOST_AUTO_TEST_CASE(SingleTreeVsNaive)
for (size_t i = 0; i < neighborsTree.n_elem; ++i)
{
BOOST_REQUIRE_EQUAL(neighborsTree[i], neighborsNaive[i]);
BOOST_REQUIRE_CLOSE(distancesTree[i], distancesNaive[i], 1e-5);
REQUIRE(neighborsTree[i] == neighborsNaive[i]);
REQUIRE(distancesTree[i] == Approx(distancesNaive[i]).epsilon(1e-7));
}
}
@@ -432,7 +430,7 @@ BOOST_AUTO_TEST_CASE(SingleTreeVsNaive)
*
* Errors are produced if the results are not identical.
*/
BOOST_AUTO_TEST_CASE(SingleCoverTreeTest)
TEST_CASE("KFNSingleCoverTreeTest", "[KFNTest]")
{
arma::mat data;
data.randu(75, 1000); // 75 dimensional, 1000 points.
@@ -456,8 +454,8 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest)
for (size_t i = 0; i < coverTreeNeighbors.n_elem; ++i)
{
BOOST_REQUIRE_EQUAL(coverTreeNeighbors[i], naiveNeighbors[i]);
BOOST_REQUIRE_CLOSE(coverTreeDistances[i], naiveDistances[i], 1e-5);
REQUIRE(coverTreeNeighbors[i] == naiveNeighbors[i]);
REQUIRE(coverTreeDistances[i] == Approx(naiveDistances[i]).epsilon(1e-7));
}
}
@@ -465,7 +463,7 @@ BOOST_AUTO_TEST_CASE(SingleCoverTreeTest)
* Test the cover tree dual-tree furthest neighbors method against the naive
* method.
*/
BOOST_AUTO_TEST_CASE(DualCoverTreeTest)
TEST_CASE("KFNDualCoverTreeTest", "[KFNTest]")
{
arma::mat dataset;
data::Load("test_data_3_1000.csv", dataset);
@@ -490,8 +488,8 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest)
for (size_t i = 0; i < coverNeighbors.n_elem; ++i)
{
BOOST_REQUIRE_EQUAL(coverNeighbors(i), kdNeighbors(i));
BOOST_REQUIRE_CLOSE(coverDistances(i), kdDistances(i), 1e-5);
REQUIRE(coverNeighbors(i) == kdNeighbors(i));
REQUIRE(coverDistances(i) == Approx(kdDistances(i)).epsilon(1e-7));
}
}
@@ -501,7 +499,7 @@ BOOST_AUTO_TEST_CASE(DualCoverTreeTest)
*
* Errors are produced if the results are not identical.
*/
BOOST_AUTO_TEST_CASE(SingleBallTreeTest)
TEST_CASE("KFNSingleBallTreeTest", "[KFNTest]")
{
arma::mat data;
data.randu(75, 1000); // 75 dimensional, 1000 points.
@@ -528,8 +526,8 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest)
for (size_t i = 0; i < ballTreeNeighbors.n_elem; ++i)
{
BOOST_REQUIRE_EQUAL(ballTreeNeighbors[i], naiveNeighbors[i]);
BOOST_REQUIRE_CLOSE(ballTreeDistances[i], naiveDistances[i], 1e-5);
REQUIRE(ballTreeNeighbors[i] == naiveNeighbors[i]);
REQUIRE(ballTreeDistances[i] == Approx(naiveDistances[i]).epsilon(1e-7));
}
}
@@ -537,7 +535,7 @@ BOOST_AUTO_TEST_CASE(SingleBallTreeTest)
* Test the ball tree dual-tree furthest neighbors method against the naive
* method.
*/
BOOST_AUTO_TEST_CASE(DualBallTreeTest)
TEST_CASE("KFNDualBallTreeTest", "[KFNTest]")
{
arma::mat dataset;
data::Load("test_data_3_1000.csv", dataset);
@@ -557,9 +555,7 @@ BOOST_AUTO_TEST_CASE(DualBallTreeTest)
for (size_t i = 0; i < ballNeighbors.n_elem; ++i)
{
BOOST_REQUIRE_EQUAL(ballNeighbors(i), kdNeighbors(i));
BOOST_REQUIRE_CLOSE(ballDistances(i), kdDistances(i), 1e-5);
REQUIRE(ballNeighbors(i) == kdNeighbors(i));
REQUIRE(ballDistances(i) == Approx(kdDistances(i)).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_SUITE_END();
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+56
View File
@@ -31,6 +31,7 @@
#include <mlpack/methods/ann/loss_functions/hinge_embedding_loss.hpp>
#include <mlpack/methods/ann/loss_functions/cosine_embedding_loss.hpp>
#include <mlpack/methods/ann/loss_functions/l1_loss.hpp>
#include <mlpack/methods/ann/loss_functions/soft_margin_loss.hpp>
#include <mlpack/methods/ann/init_rules/nguyen_widrow_init.hpp>
#include <mlpack/methods/ann/ffn.hpp>
@@ -816,4 +817,59 @@ BOOST_AUTO_TEST_CASE(MarginRankingLossTest)
"-0.753830 1.336900 0.000000 0.000000 -0.207000 0.328810"), 1e-6);
}
/**
* Simple test for the Softmargin Loss function.
*/
BOOST_AUTO_TEST_CASE(SoftMarginLossTest)
{
arma::mat input, target, output, expectedOutput;
double loss;
SoftMarginLoss<> module1;
SoftMarginLoss<> module2(false);
input = arma::mat("0.1778 0.0957 0.1397 0.1203 0.2403 0.1925 -0.2264 -0.3400 "
"-0.3336");
target = arma::mat("1 1 -1 1 -1 1 -1 1 1");
input.reshape(3, 3);
target.reshape(3, 3);
// Test for sum reduction.
// Calculated using torch.nn.SoftMarginLoss(reduction='sum').
expectedOutput = arma::mat("-0.4557 -0.4761 0.5349 -0.4700 0.5598 -0.4520 "
"0.4436 -0.5842 -0.5826");
expectedOutput.reshape(3, 3);
// Test the Forward function. Loss should be 6.41456.
// Value calculated using torch.nn.SoftMarginLoss(reduction='sum').
loss = module1.Forward(input, target);
BOOST_REQUIRE_CLOSE(loss, 6.41456, 1e-3);
// Test the Backward function.
module1.Backward(input, target, output);
BOOST_REQUIRE_CLOSE(arma::as_scalar(arma::accu(output)), -1.48227, 1e-3);
BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows);
BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols);
CheckMatrices(output, expectedOutput, 0.1);
// Test for mean reduction.
// Calculated using torch.nn.SoftMarginLoss(reduction='mean').
expectedOutput = arma::mat("-0.0506 -0.0529 0.0594 -0.0522 0.0622 -0.0502 "
"0.0493 -0.0649 -0.0647");
expectedOutput.reshape(3, 3);
// Test the Forward function. Loss should be 0.712729.
// Value calculated using torch.nn.SoftMarginLoss(reduction='mean').
loss = module2.Forward(input, target);
BOOST_REQUIRE_CLOSE(loss, 0.712729, 1e-3);
// Test the Backward function.
module2.Backward(input, target, output);
BOOST_REQUIRE_CLOSE(arma::as_scalar(arma::accu(output)), -0.164697, 1e-3);
BOOST_REQUIRE_EQUAL(output.n_rows, input.n_rows);
BOOST_REQUIRE_EQUAL(output.n_cols, input.n_cols);
CheckMatrices(output, expectedOutput, 0.1);
}
BOOST_AUTO_TEST_SUITE_END();
+42 -33
View File
@@ -19,8 +19,8 @@ static const std::string testName = "ApproxK-FurthestNeighbors";
#include "test_helper.hpp"
#include <mlpack/methods/approx_kfn/approx_kfn_main.cpp>
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
#include "../catch.hpp"
#include "../test_catch_tools.hpp"
using namespace mlpack;
@@ -41,12 +41,11 @@ struct ApproxKFNTestFixture
}
};
BOOST_FIXTURE_TEST_SUITE(ApproxKFNMainTest, ApproxKFNTestFixture);
/**
* Check that we can't specify both a reference set and an input model.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNRefModelTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNRefModelTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -61,14 +60,15 @@ BOOST_AUTO_TEST_CASE(ApproxKFNRefModelTest)
// Input pre-trained model.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check that we can't specify an invalid k.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNInvalidKTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNInvalidKTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(ApproxKFNInvalidKTest)
SetInputParam("k", (int) 81); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -86,7 +86,8 @@ BOOST_AUTO_TEST_CASE(ApproxKFNInvalidKTest)
* Make sure that the dimensions of neighbors and distances is correct given a
* value of k.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNOutputDimensionTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNOutputDimensionTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -98,18 +99,19 @@ BOOST_AUTO_TEST_CASE(ApproxKFNOutputDimensionTest)
mlpackMain();
// Check the neighbors matrix has 10 points for each of the 80 input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Mat<size_t>>("neighbors").n_rows, 10);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Mat<size_t>>("neighbors").n_cols, 80);
REQUIRE(IO::GetParam<arma::Mat<size_t>>("neighbors").n_rows == 10);
REQUIRE(IO::GetParam<arma::Mat<size_t>>("neighbors").n_cols == 80);
// Check the distances matrix has 10 points for each of the 80 input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("distances").n_rows, 10);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("distances").n_cols, 80);
REQUIRE(IO::GetParam<arma::mat>("distances").n_rows == 10);
REQUIRE(IO::GetParam<arma::mat>("distances").n_cols == 80);
}
/**
* Check that we can't specify an invalid algorithm.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNInvalidAlgorithmTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNInvalidAlgorithmTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -118,14 +120,15 @@ BOOST_AUTO_TEST_CASE(ApproxKFNInvalidAlgorithmTest)
SetInputParam("algorithm", (string) "any_algo"); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check that we can't specify num_projections as zero.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNZeroNumProjTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNZeroNumProjTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -135,14 +138,15 @@ BOOST_AUTO_TEST_CASE(ApproxKFNZeroNumProjTest)
SetInputParam("num_projections", (int) 0); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check that we can't specify num_projections as negative.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNNegativeNumProjTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNNegativeNumProjTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -152,14 +156,15 @@ BOOST_AUTO_TEST_CASE(ApproxKFNNegativeNumProjTest)
SetInputParam("num_projections", (int) -5); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check that we can't specify num_tables as zero.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNZeroNumTablesTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNZeroNumTablesTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -169,14 +174,15 @@ BOOST_AUTO_TEST_CASE(ApproxKFNZeroNumTablesTest)
SetInputParam("num_tables", (int) 0); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check that we can't specify num_tables as negative.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNNegativeNumTablesTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNNegativeNumTablesTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -186,14 +192,15 @@ BOOST_AUTO_TEST_CASE(ApproxKFNNegativeNumTablesTest)
SetInputParam("num_tables", (int) -5); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Ensuring that a saved model can be loaded and used again correctly.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNModelReuseTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNModelReuseTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -236,7 +243,8 @@ BOOST_AUTO_TEST_CASE(ApproxKFNModelReuseTest)
/**
* Ensuring that num_tables has some effects on output.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNNumTablesChangeTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNNumTablesChangeTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -285,7 +293,8 @@ BOOST_AUTO_TEST_CASE(ApproxKFNNumTablesChangeTest)
/**
* Ensuring that num_projections has some effects on output.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNNumProjectionsChangeTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNNumProjectionsChangeTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -333,7 +342,8 @@ BOOST_AUTO_TEST_CASE(ApproxKFNNumProjectionsChangeTest)
/**
* Make sure that the dimensions of the exact distances matrix are correct.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNExactDistDimensionTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNExactDistDimensionTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(2, 80); // 80 points in 2 dimensions.
@@ -351,15 +361,16 @@ BOOST_AUTO_TEST_CASE(ApproxKFNExactDistDimensionTest)
SetInputParam("exact_distances", std::move(exactDistances));
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Make sure that the two strategie (Drusilla Select and QDAFN) output different
* results.
* Make sure that the two strategie (Drusilla Select and QDAFN) output
* different results.
*/
BOOST_AUTO_TEST_CASE(ApproxKFNDifferentAlgoTest)
TEST_CASE_METHOD(ApproxKFNTestFixture, "ApproxKFNDifferentAlgoTest",
"[ApproxKFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(6, 100); // 100 points in 6 dimensions.
@@ -402,5 +413,3 @@ BOOST_AUTO_TEST_CASE(ApproxKFNDifferentAlgoTest)
CheckMatricesNotEqual(firstOutputDistances, secondOutputDistances);
CheckMatricesNotEqual(firstOutputNeighbors, secondOutputNeighbors);
}
BOOST_AUTO_TEST_SUITE_END();
@@ -0,0 +1,143 @@
/**
* @file tests/main_tests/bayesian_linear_regression_test.cpp
* @author Clement Mercier
*
* Test mlpackMain() of bayesian_linear_regression_main.cpp.
*
* mlpack is free software; you may redistribute it and/or modify it under the
* terms of the 3-clause BSD license. You should have received a copy of the
* 3-clause BSD license along with mlpack. If not, see
* http://www.opensource.org/licenses/BSD-3-Clause for more information.
*/
#include <string>
#define BINDING_TYPE BINDING_TYPE_TEST
static const std::string testName = "BayesianLinearRegression";
#include <mlpack/core.hpp>
#include <mlpack/core/util/mlpack_main.hpp>
#include "test_helper.hpp"
#include <mlpack/methods/bayesian_linear_regression/bayesian_linear_regression_main.cpp>
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
using namespace mlpack;
struct BRTestFixture
{
public:
BRTestFixture()
{
// Cache in the options for this program.
IO::RestoreSettings(testName);
}
~BRTestFixture()
{
// Clear the settings.
bindings::tests::CleanMemory();
IO::ClearSettings();
}
};
BOOST_FIXTURE_TEST_SUITE(BayesianLinearRegressionMainTest, BRTestFixture);
/**
* Check the center and scale options.
*/
BOOST_AUTO_TEST_CASE(BRCenter0Scale0)
{
int n = 50, m = 4;
arma::mat matX = arma::randu<arma::mat>(m, n);
arma::rowvec omega = arma::randu<arma::rowvec>(m);
arma::rowvec y = omega * matX;
SetInputParam("input", std::move(matX));
SetInputParam("responses", std::move(y));
SetInputParam("center", false);
mlpackMain();
BayesianLinearRegression* estimator =
IO::GetParam<BayesianLinearRegression*>("output_model");
BOOST_REQUIRE(estimator->DataOffset().n_elem == 0);
BOOST_REQUIRE(estimator->DataScale().n_elem == 0);
}
/**
* Check predictions of saved model and in code model are equal.
*/
BOOST_AUTO_TEST_CASE(BayesianLinearRegressionSavedEqualCode)
{
int n = 10, m = 4;
arma::mat matX = arma::randu<arma::mat>(m, n);
arma::mat matXtest = arma::randu<arma::mat>(m, 2 * n);
const arma::rowvec omega = arma::randu<arma::rowvec>(m);
arma::rowvec y = omega * matX;
BayesianLinearRegression model;
model.Train(matX, y);
arma::rowvec responses;
model.Predict(matXtest, responses);
SetInputParam("input", std::move(matX));
SetInputParam("responses", std::move(y));
mlpackMain();
IO::GetSingleton().Parameters()["input"].wasPassed = false;
IO::GetSingleton().Parameters()["responses"].wasPassed = false;
SetInputParam("input_model",
IO::GetParam<BayesianLinearRegression*>("output_model"));
SetInputParam("test", std::move(matXtest));
mlpackMain();
arma::mat ytest = std::move(responses);
// Check that initial output and output using saved model are same.
CheckMatrices(ytest, IO::GetParam<arma::mat>("predictions"));
}
/**
* Check a crash happens if neither input or input_model are specified.
* Check a crash happens if both input and input_model are specified.
*/
BOOST_AUTO_TEST_CASE(CheckParamsPassed)
{
int n = 10, m = 4;
arma::mat matX = arma::randu<arma::mat>(m, n);
arma::mat matXtest = arma::randu<arma::mat>(m, 2 * n);
const arma::rowvec omega = arma::randu<arma::rowvec>(m);
arma::rowvec y = omega * matX;
BayesianLinearRegression model;
model.Train(matX, y);
arma::rowvec responses;
model.Predict(matXtest, responses);
// Check that std::runtime_error is thrown if neither input or input_model
// is specified.
SetInputParam("responses", std::move(y));
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
// Continue only with input passed.
SetInputParam("input", std::move(matX));
mlpackMain();
// Now pass the previous trained model and one input matrix at the same time.
// An error should occur.
SetInputParam("input", std::move(matX));
SetInputParam("input_model",
IO::GetParam<BayesianLinearRegression*>("output_model"));
SetInputParam("test", std::move(matXtest));
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
}
BOOST_AUTO_TEST_SUITE_END();
@@ -18,8 +18,8 @@ static const std::string testName = "DecisionStump";
#include <mlpack/methods/decision_stump/decision_stump_main.cpp>
#include "test_helper.hpp"
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
#include "../test_catch_tools.hpp"
#include "../catch.hpp"
using namespace mlpack;
@@ -40,17 +40,16 @@ struct DecisionStumpTestFixture
}
};
BOOST_FIXTURE_TEST_SUITE(DecisionStumpMainTest, DecisionStumpTestFixture);
/**
* Ensure that we get desired dimensions when both training
* data and labels are passed.
*/
BOOST_AUTO_TEST_CASE(DecisionStumpOutputDimensionTest)
TEST_CASE_METHOD(DecisionStumpTestFixture, "DecisionStumpOutputDimensionTest",
"[DecisionStumpMainTest][BindingTests]")
{
arma::mat inputData;
if (!data::Load("trainSet.csv", inputData))
BOOST_FAIL("Cannot load train dataset trainSet.csv!");
FAIL("Cannot load train dataset trainSet.csv!");
// Get the labels out.
arma::Row<size_t> labels(inputData.n_cols);
@@ -62,7 +61,7 @@ BOOST_AUTO_TEST_CASE(DecisionStumpOutputDimensionTest)
arma::mat testData;
if (!data::Load("testSet.csv", testData))
BOOST_FAIL("Cannot load test dataset testSet.csv!");
FAIL("Cannot load test dataset testSet.csv!");
// Delete the last row containing labels from test dataset.
testData.shed_row(testData.n_rows - 1);
@@ -79,12 +78,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpOutputDimensionTest)
mlpackMain();
// Check that number of output points are equal to number of input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_cols,
testSize);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_cols == testSize);
// Check prediction have only single row.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_rows,
1);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_rows == 1);
}
/**
@@ -92,12 +89,14 @@ BOOST_AUTO_TEST_CASE(DecisionStumpOutputDimensionTest)
* when labels are not passed specifically and results
* are same from both label and labeless models.
*/
BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest)
TEST_CASE_METHOD(DecisionStumpTestFixture,
"DecisionStumpLabelsLessDimensionTest",
"[DecisionStumpMainTest][BindingTests]")
{
// Train DS without providing labels.
arma::mat inputData;
if (!data::Load("trainSet.csv", inputData))
BOOST_FAIL("Cannot load train dataset trainSet.csv!");
FAIL("Cannot load train dataset trainSet.csv!");
// Get the labels out.
arma::Row<size_t> labels(inputData.n_cols);
@@ -106,7 +105,7 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest)
arma::mat testData;
if (!data::Load("testSet.csv", testData))
BOOST_FAIL("Cannot load test dataset testSet.csv!");
FAIL("Cannot load test dataset testSet.csv!");
// Delete the last row containing labels from test dataset.
testData.shed_row(testData.n_rows - 1);
@@ -122,12 +121,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest)
mlpackMain();
// Check that number of output points are equal to number of input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_cols,
testSize);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_cols == testSize);
// Check prediction have only single row.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_rows,
1);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_rows == 1);
// Reset data passed.
IO::GetSingleton().Parameters()["training"].wasPassed = false;
@@ -154,12 +151,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest)
mlpackMain();
// Check that number of output points are equal to number of input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_cols,
testSize);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_cols == testSize);
// Check prediction have only single row.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_rows,
1);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_rows == 1);
// Check that initial output and final output matrix
// from two models are same.
@@ -169,15 +164,16 @@ BOOST_AUTO_TEST_CASE(DecisionStumpLabelsLessDimensionTest)
/**
* Ensure that saved model can be used again.
*/
BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest)
TEST_CASE_METHOD(DecisionStumpTestFixture, "DecisionStumpModelReuseTest",
"[DecisionStumpMainTest][BindingTests]")
{
arma::mat inputData;
if (!data::Load("trainSet.csv", inputData))
BOOST_FAIL("Cannot load train dataset trainSet.csv!");
FAIL("Cannot load train dataset trainSet.csv!");
arma::mat testData;
if (!data::Load("testSet.csv", testData))
BOOST_FAIL("Cannot load test dataset testSet.csv!");
FAIL("Cannot load test dataset testSet.csv!");
// Delete the last row containing labels from test dataset.
testData.shed_row(testData.n_rows - 1);
@@ -207,12 +203,10 @@ BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest)
mlpackMain();
// Check that number of output points are equal to number of input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_cols,
testSize);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_cols == testSize);
// Check predictions have only single row.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_rows,
1);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_rows == 1);
// Check that initial predictions and final predicitons matrix
// using saved model are same.
@@ -222,29 +216,31 @@ BOOST_AUTO_TEST_CASE(DecisionStumpModelReuseTest)
/**
* Ensure that bucket_size is always positive.
*/
BOOST_AUTO_TEST_CASE(DecisionStumpBucketSizeTest)
TEST_CASE_METHOD(DecisionStumpTestFixture, "DecisionStumpBucketSizeTest",
"[DecisionStumpMainTest][BindingTests]")
{
arma::mat inputData;
if (!data::Load("trainSet.csv", inputData))
BOOST_FAIL("Cannot load train dataset trainSet.csv!");
FAIL("Cannot load train dataset trainSet.csv!");
// Input training data.
SetInputParam("training", std::move(inputData));
SetInputParam("bucket_size", (int) 0);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Make sure only one of training data or pre-trained model is passed.
*/
BOOST_AUTO_TEST_CASE(DecisionStumpTrainingVerTest)
TEST_CASE_METHOD(DecisionStumpTestFixture, "DecisionStumpTrainingVerTest",
"[DecisionStumpMainTest][BindingTests]")
{
arma::mat inputData;
if (!data::Load("trainSet.csv", inputData))
BOOST_FAIL("Cannot load train dataset trainSet.csv!");
FAIL("Cannot load train dataset trainSet.csv!");
// Input training data.
SetInputParam("training", std::move(inputData));
@@ -256,8 +252,6 @@ BOOST_AUTO_TEST_CASE(DecisionStumpTrainingVerTest)
std::move(IO::GetParam<DSModel*>("output_model")));
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
BOOST_AUTO_TEST_SUITE_END();
@@ -18,8 +18,8 @@ static const std::string testName = "DecisionTree";
#include <mlpack/methods/decision_tree/decision_tree_main.cpp>
#include "test_helper.hpp"
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
#include "../test_catch_tools.hpp"
#include "../catch.hpp"
using namespace mlpack;
using namespace data;
@@ -47,30 +47,28 @@ void ResetDTSettings()
IO::RestoreSettings(testName);
}
BOOST_FIXTURE_TEST_SUITE(DecisionTreeMainTest,
DecisionTreeTestFixture);
/**
* Check that number of output points and
* number of input points are equal.
*/
BOOST_AUTO_TEST_CASE(DecisionTreeOutputDimensionTest)
TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionTreeOutputDimensionTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("vc2.csv", inputData, info))
BOOST_FAIL("Cannot load train dataset vc2.csv!");
FAIL("Cannot load train dataset vc2.csv!");
arma::Row<size_t> labels;
if (!data::Load("vc2_labels.txt", labels))
BOOST_FAIL("Cannot load labels for vc2_labels.txt");
FAIL("Cannot load labels for vc2_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
arma::mat testData;
if (!data::Load("vc2_test.csv", testData, info))
BOOST_FAIL("Cannot load test dataset vc2.csv!");
FAIL("Cannot load test dataset vc2.csv!");
size_t testSize = testData.n_cols;
@@ -85,39 +83,38 @@ BOOST_AUTO_TEST_CASE(DecisionTreeOutputDimensionTest)
mlpackMain();
// Check that number of output points are equal to number of input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_cols,
testSize);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("probabilities").n_cols,
testSize);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_cols == testSize);
REQUIRE(IO::GetParam<arma::mat>("probabilities").n_cols == testSize);
// Check number of output rows equals number of classes in case of
// probabilities and 1 for predictions.
BOOST_REQUIRE_EQUAL(
IO::GetParam<arma::Row<size_t>>("predictions").n_rows, 1);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("probabilities").n_rows, 3);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_rows == 1);
REQUIRE(IO::GetParam<arma::mat>("probabilities").n_rows == 3);
}
/**
* Check that number of output points and number
* of input points are equal for categorical dataset.
*/
BOOST_AUTO_TEST_CASE(DecisionTreeCategoricalOutputDimensionTest)
TEST_CASE_METHOD(DecisionTreeTestFixture,
"DecisionTreeCategoricalOutputDimensionTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("braziltourism.arff", inputData, info))
BOOST_FAIL("Cannot load train dataset braziltourism.arff!");
FAIL("Cannot load train dataset braziltourism.arff!");
arma::Row<size_t> labels;
if (!data::Load("braziltourism_labels.txt", labels))
BOOST_FAIL("Cannot load labels for braziltourism_labels.txt");
FAIL("Cannot load labels for braziltourism_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
arma::mat testData;
if (!data::Load("braziltourism_test.arff", testData, info))
BOOST_FAIL("Cannot load test dataset braziltourism_test.arff!");
FAIL("Cannot load test dataset braziltourism_test.arff!");
size_t testSize = testData.n_cols;
@@ -132,31 +129,29 @@ BOOST_AUTO_TEST_CASE(DecisionTreeCategoricalOutputDimensionTest)
mlpackMain();
// Check that number of output points are equal to number of input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_cols,
testSize);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("probabilities").n_cols,
testSize);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_cols == testSize);
REQUIRE(IO::GetParam<arma::mat>("probabilities").n_cols == testSize);
// Check number of output rows equals number of classes in case of
// probabilities and 1 for predictions.
BOOST_REQUIRE_EQUAL(
IO::GetParam<arma::Row<size_t>>("predictions").n_rows, 1);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("probabilities").n_rows, 6);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_rows == 1);
REQUIRE(IO::GetParam<arma::mat>("probabilities").n_rows == 6);
}
/**
* Make sure minimum leaf size is always a non-negative number.
*/
BOOST_AUTO_TEST_CASE(DecisionTreeMinimumLeafSizeTest)
TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionTreeMinimumLeafSizeTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("braziltourism.arff", inputData, info))
BOOST_FAIL("Cannot load train dataset braziltourism.arff!");
FAIL("Cannot load train dataset braziltourism.arff!");
arma::Row<size_t> labels;
if (!data::Load("braziltourism_labels.txt", labels))
BOOST_FAIL("Cannot load labels for braziltourism_labels.txt");
FAIL("Cannot load labels for braziltourism_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
@@ -169,23 +164,25 @@ BOOST_AUTO_TEST_CASE(DecisionTreeMinimumLeafSizeTest)
SetInputParam("minimum_leaf_size", (int) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Make sure maximum depth is always a non-negative number.
*/
BOOST_AUTO_TEST_CASE(DecisionTreeNonNegativeMaximumDepthTest)
TEST_CASE_METHOD(DecisionTreeTestFixture,
"DecisionTreeNonNegativeMaximumDepthTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("braziltourism.arff", inputData, info))
BOOST_FAIL("Cannot load train dataset braziltourism.arff!");
FAIL("Cannot load train dataset braziltourism.arff!");
arma::Row<size_t> labels;
if (!data::Load("braziltourism_labels.txt", labels))
BOOST_FAIL("Cannot load labels for braziltourism_labels.txt");
FAIL("Cannot load labels for braziltourism_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
@@ -198,23 +195,24 @@ BOOST_AUTO_TEST_CASE(DecisionTreeNonNegativeMaximumDepthTest)
SetInputParam("maximum_depth", (int) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Make sure minimum gain split is always a fraction in range [0,1].
*/
BOOST_AUTO_TEST_CASE(DecisionMinimumGainSplitTest)
TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionMinimumGainSplitTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("braziltourism.arff", inputData, info))
BOOST_FAIL("Cannot load train dataset braziltourism.arff!");
FAIL("Cannot load train dataset braziltourism.arff!");
arma::Row<size_t> labels;
if (!data::Load("braziltourism_labels.txt", labels))
BOOST_FAIL("Cannot load labels for braziltourism_labels.txt");
FAIL("Cannot load labels for braziltourism_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
@@ -227,23 +225,24 @@ BOOST_AUTO_TEST_CASE(DecisionMinimumGainSplitTest)
SetInputParam("minimum_gain_split", 1.5); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Make sure minimum gain split produces regularised tree.
*/
BOOST_AUTO_TEST_CASE(DecisionRegularisationTest)
TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionRegularisationTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("braziltourism.arff", inputData, info))
BOOST_FAIL("Cannot load train dataset braziltourism.arff!");
FAIL("Cannot load train dataset braziltourism.arff!");
arma::Row<size_t> labels;
if (!data::Load("braziltourism_labels.txt", labels))
BOOST_FAIL("Cannot load labels for braziltourism_labels.txt");
FAIL("Cannot load labels for braziltourism_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
@@ -277,36 +276,37 @@ BOOST_AUTO_TEST_CASE(DecisionRegularisationTest)
predRegularised = std::move(IO::GetParam<arma::Row<size_t>>("predictions"));
size_t count = 0;
BOOST_REQUIRE_EQUAL(pred.n_elem, predRegularised.n_elem);
REQUIRE(pred.n_elem == predRegularised.n_elem);
for (size_t i = 0; i < pred.n_elem; ++i)
{
if (pred[i] != predRegularised[i])
count++;
}
BOOST_REQUIRE_GT(count, 0);
REQUIRE(count > 0);
}
/**
* Ensure that saved model can be used again.
*/
BOOST_AUTO_TEST_CASE(DecisionModelReuseTest)
TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionModelReuseTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("vc2.csv", inputData, info))
BOOST_FAIL("Cannot load train dataset vc2.csv!");
FAIL("Cannot load train dataset vc2.csv!");
arma::Row<size_t> labels;
if (!data::Load("vc2_labels.txt", labels))
BOOST_FAIL("Cannot load labels for vc2_labels.txt");
FAIL("Cannot load labels for vc2_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
arma::mat testData;
if (!data::Load("vc2_test.csv", testData, info))
BOOST_FAIL("Cannot load test dataset vc2.csv!");
FAIL("Cannot load test dataset vc2.csv!");
size_t testSize = testData.n_cols;
@@ -339,16 +339,13 @@ BOOST_AUTO_TEST_CASE(DecisionModelReuseTest)
mlpackMain();
// Check that number of output points are equal to number of input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_cols,
testSize);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("probabilities").n_cols,
testSize);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_cols == testSize);
REQUIRE(IO::GetParam<arma::mat>("probabilities").n_cols == testSize);
// Check number of output rows equals number of classes in case of
// probabilities and 1 for predicitions.
BOOST_REQUIRE_EQUAL(
IO::GetParam<arma::Row<size_t>>("predictions").n_rows, 1);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("probabilities").n_rows, 3);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_rows == 1);
REQUIRE(IO::GetParam<arma::mat>("probabilities").n_rows == 3);
// Check that initial predictions and predictions using saved model are same.
CheckMatrices(predictions, IO::GetParam<arma::Row<size_t>>("predictions"));
@@ -358,16 +355,17 @@ BOOST_AUTO_TEST_CASE(DecisionModelReuseTest)
/**
* Make sure only one of training data or pre-trained model is passed.
*/
BOOST_AUTO_TEST_CASE(DecisionTreeTrainingVerTest)
TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionTreeTrainingVerTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("vc2.csv", inputData, info))
BOOST_FAIL("Cannot load train dataset vc2.csv!");
FAIL("Cannot load train dataset vc2.csv!");
arma::Row<size_t> labels;
if (!data::Load("vc2_labels.txt", labels))
BOOST_FAIL("Cannot load labels for vc2_labels.txt");
FAIL("Cannot load labels for vc2_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
@@ -388,30 +386,31 @@ BOOST_AUTO_TEST_CASE(DecisionTreeTrainingVerTest)
SetInputParam("input_model", model);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Ensure that saved model trained on categorical dataset can be used again.
*/
BOOST_AUTO_TEST_CASE(DecisionModelCategoricalReuseTest)
TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionModelCategoricalReuseTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("braziltourism.arff", inputData, info))
BOOST_FAIL("Cannot load train dataset braziltourism.arff!");
FAIL("Cannot load train dataset braziltourism.arff!");
arma::Row<size_t> labels;
if (!data::Load("braziltourism_labels.txt", labels))
BOOST_FAIL("Cannot load labels for braziltourism_labels.txt");
FAIL("Cannot load labels for braziltourism_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
arma::mat testData;
if (!data::Load("braziltourism_test.arff", testData, info))
BOOST_FAIL("Cannot load test dataset braziltourism_test.arff!");
FAIL("Cannot load test dataset braziltourism_test.arff!");
size_t testSize = testData.n_cols;
@@ -448,16 +447,13 @@ BOOST_AUTO_TEST_CASE(DecisionModelCategoricalReuseTest)
mlpackMain();
// Check that number of output points are equal to number of input points.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Row<size_t>>("predictions").n_cols,
testSize);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("probabilities").n_cols,
testSize);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_cols == testSize);
REQUIRE(IO::GetParam<arma::mat>("probabilities").n_cols == testSize);
// Check number of output rows equals number of classes in case of
// probabilities and 1 for predicitions.
BOOST_REQUIRE_EQUAL(
IO::GetParam<arma::Row<size_t>>("predictions").n_rows, 1);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("probabilities").n_rows, 6);
REQUIRE(IO::GetParam<arma::Row<size_t>>("predictions").n_rows == 1);
REQUIRE(IO::GetParam<arma::mat>("probabilities").n_rows == 6);
// Check that initial predictions and predictions using saved model are same.
CheckMatrices(predictions, IO::GetParam<arma::Row<size_t>>("predictions"));
@@ -467,23 +463,24 @@ BOOST_AUTO_TEST_CASE(DecisionModelCategoricalReuseTest)
/**
* Check that different maximum depths give different results.
*/
BOOST_AUTO_TEST_CASE(DecisionTreeMaximumDepthTest)
TEST_CASE_METHOD(DecisionTreeTestFixture, "DecisionTreeMaximumDepthTest",
"[DecisionTreeMainTest][BindingTests]")
{
arma::mat inputData;
DatasetInfo info;
if (!data::Load("vc2.csv", inputData, info))
BOOST_FAIL("Cannot load train dataset vc2.csv!");
FAIL("Cannot load train dataset vc2.csv!");
arma::Row<size_t> labels;
if (!data::Load("vc2_labels.txt", labels))
BOOST_FAIL("Cannot load labels for vc2_labels.txt");
FAIL("Cannot load labels for vc2_labels.txt");
// Initialize an all-ones weight matrix.
arma::mat weights(1, labels.n_cols, arma::fill::ones);
arma::mat testData;
if (!data::Load("vc2_test.csv", testData, info))
BOOST_FAIL("Cannot load test dataset vc2.csv!");
FAIL("Cannot load test dataset vc2.csv!");
// Input training data.
SetInputParam("training", std::make_tuple(info, inputData));
@@ -516,5 +513,3 @@ BOOST_AUTO_TEST_CASE(DecisionTreeMaximumDepthTest)
CheckMatricesNotEqual(predictions,
IO::GetParam<arma::Row<size_t>>("predictions"));
}
BOOST_AUTO_TEST_SUITE_END();
+63 -55
View File
@@ -20,8 +20,8 @@ static const std::string testName = "K-FurthestNeighborsSearch";
#include "test_helper.hpp"
#include <mlpack/methods/neighbor_search/kfn_main.cpp>
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
#include "../test_catch_tools.hpp"
#include "../catch.hpp"
using namespace mlpack;
@@ -42,13 +42,12 @@ struct KFNTestFixture
}
};
BOOST_FIXTURE_TEST_SUITE(KFNMainTest, KFNTestFixture);
/*
* Check that we can't provide reference and query matrices
* with different dimensions.
*/
BOOST_AUTO_TEST_CASE(KFNEqualDimensionTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNEqualDimensionTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -65,7 +64,7 @@ BOOST_AUTO_TEST_CASE(KFNEqualDimensionTest)
SetInputParam("k", (int) 10);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -73,7 +72,8 @@ BOOST_AUTO_TEST_CASE(KFNEqualDimensionTest)
* Check that we can't specify an invalid k when only reference
* matrix is given.
*/
BOOST_AUTO_TEST_CASE(KFNInvalidKTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidKTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKTest)
SetInputParam("k", (int) 101);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
delete IO::GetParam<KFNModel*>("output_model");
IO::GetParam<KFNModel*>("output_model") = NULL;
@@ -94,7 +94,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKTest)
// SetInputParam("reference", referenceData);
// SetInputParam("k", (int) 0); // Invalid.
// BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
// REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
// IO::GetSingleton().Parameters()["reference"].wasPassed = false;
// IO::GetSingleton().Parameters()["k"].wasPassed = false;
@@ -102,7 +102,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKTest)
SetInputParam("reference", std::move(referenceData));
SetInputParam("k", (int) -1); // Invalid.
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -110,7 +110,8 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKTest)
* Check that we can't specify an invalid k when both reference
* and query matrices are given.
*/
BOOST_AUTO_TEST_CASE(KFNInvalidKQueryDataTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidKQueryDataTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -124,14 +125,15 @@ BOOST_AUTO_TEST_CASE(KFNInvalidKQueryDataTest)
SetInputParam("k", (int) 101);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check that we can't specify a negative leaf size.
*/
BOOST_AUTO_TEST_CASE(KFNLeafSizeTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNLeafSizeTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -141,14 +143,15 @@ BOOST_AUTO_TEST_CASE(KFNLeafSizeTest)
SetInputParam("leaf_size", (int) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass both input_model and reference matrix.
*/
BOOST_AUTO_TEST_CASE(KFNRefModelTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNRefModelTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -164,14 +167,15 @@ BOOST_AUTO_TEST_CASE(KFNRefModelTest)
std::move(IO::GetParam<KFNModel*>("output_model")));
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid tree type.
*/
BOOST_AUTO_TEST_CASE(KFNInvalidTreeTypeTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidTreeTypeTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -182,14 +186,15 @@ BOOST_AUTO_TEST_CASE(KFNInvalidTreeTypeTest)
SetInputParam("tree_type", (string) "min-rp"); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid algorithm.
*/
BOOST_AUTO_TEST_CASE(KFNInvalidAlgoTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidAlgoTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -200,14 +205,15 @@ BOOST_AUTO_TEST_CASE(KFNInvalidAlgoTest)
SetInputParam("algorithm", (string) "triple_tree"); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid value of epsilon.
*/
BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidEpsilonTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -218,7 +224,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest)
SetInputParam("epsilon", (double) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
IO::GetSingleton().Parameters()["reference"].wasPassed = false;
IO::GetSingleton().Parameters()["epsilon"].wasPassed = false;
@@ -226,7 +232,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest)
SetInputParam("reference", std::move(referenceData));
SetInputParam("epsilon", (double) 2); // Invalid.
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
IO::GetSingleton().Parameters()["reference"].wasPassed = false;
IO::GetSingleton().Parameters()["epsilon"].wasPassed = false;
@@ -234,14 +240,15 @@ BOOST_AUTO_TEST_CASE(KFNInvalidEpsilonTest)
SetInputParam("reference", std::move(referenceData));
SetInputParam("epsilon", (double) 1); // Invalid.
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid value of percentage.
*/
BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNInvalidPercentageTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -252,7 +259,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest)
SetInputParam("percentage", (double) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
IO::GetSingleton().Parameters()["reference"].wasPassed = false;
IO::GetSingleton().Parameters()["percentage"].wasPassed = false;
@@ -260,7 +267,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest)
SetInputParam("reference", std::move(referenceData));
SetInputParam("percentage", (double) 0); // Invalid.
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
IO::GetSingleton().Parameters()["reference"].wasPassed = false;
IO::GetSingleton().Parameters()["epsilon"].wasPassed = false;
@@ -268,7 +275,7 @@ BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest)
SetInputParam("reference", std::move(referenceData));
SetInputParam("percentage", (double) 2); // Invalid.
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -276,7 +283,8 @@ BOOST_AUTO_TEST_CASE(KFNInvalidPercentageTest)
* Make sure that dimensions of the neighbors and distances
* matrices are correct given a value of k.
*/
BOOST_AUTO_TEST_CASE(KFNOutputDimensionTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNOutputDimensionTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -288,20 +296,19 @@ BOOST_AUTO_TEST_CASE(KFNOutputDimensionTest)
mlpackMain();
// Check the neighbors matrix has 4 points for each input point.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Mat<size_t>>
("neighbors").n_rows, 10);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Mat<size_t>>
("neighbors").n_cols, 100);
REQUIRE(IO::GetParam<arma::Mat<size_t>>("neighbors").n_rows == 10);
REQUIRE(IO::GetParam<arma::Mat<size_t>>("neighbors").n_cols == 100);
// Check the distances matrix has 4 points for each input point.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("distances").n_rows, 10);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("distances").n_cols, 100);
REQUIRE(IO::GetParam<arma::mat>("distances").n_rows == 10);
REQUIRE(IO::GetParam<arma::mat>("distances").n_cols == 100);
}
/**
* Ensure that saved model can be used again.
*/
BOOST_AUTO_TEST_CASE(KFNModelReuseTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNModelReuseTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -344,7 +351,8 @@ BOOST_AUTO_TEST_CASE(KFNModelReuseTest)
* Ensure that changing the value of epsilon gives us different
* approximate KFN results.
*/
BOOST_AUTO_TEST_CASE(KFNDifferentEpsilonTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNDifferentEpsilonTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 1000); // 1000 points in 3 dimensions.
@@ -381,7 +389,8 @@ BOOST_AUTO_TEST_CASE(KFNDifferentEpsilonTest)
* Ensure that changing the value of percentage gives us different
* approximate KFN results.
*/
BOOST_AUTO_TEST_CASE(KFNDifferentPercentageTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNDifferentPercentageTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 1000); // 1000 points in 3 dimensions.
@@ -418,7 +427,8 @@ BOOST_AUTO_TEST_CASE(KFNDifferentPercentageTest)
* Ensure that we get different results on running twice in greedy
* search mode when random_basis is specified.
*/
BOOST_AUTO_TEST_CASE(KFNRandomBasisTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNRandomBasisTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 1000); // 1000 points in 3 dimensions.
@@ -434,8 +444,7 @@ BOOST_AUTO_TEST_CASE(KFNRandomBasisTest)
arma::mat distances;
neighbors = std::move(IO::GetParam<arma::Mat<size_t>>("neighbors"));
distances = std::move(IO::GetParam<arma::mat>("distances"));
BOOST_REQUIRE_EQUAL(IO::GetParam<KFNModel*>("output_model")->RandomBasis(),
true);
REQUIRE(IO::GetParam<KFNModel*>("output_model")->RandomBasis() == true);
bindings::tests::CleanMemory();
@@ -448,15 +457,15 @@ BOOST_AUTO_TEST_CASE(KFNRandomBasisTest)
CheckMatrices(neighbors, IO::GetParam<arma::Mat<size_t>>("neighbors"));
CheckMatrices(distances, IO::GetParam<arma::mat>("distances"));
BOOST_REQUIRE_EQUAL(IO::GetParam<KFNModel*>("output_model")->RandomBasis(),
false);
REQUIRE(IO::GetParam<KFNModel*>("output_model")->RandomBasis() == false);
}
/*
* Ensure that the program runs successfully when we pass true_neighbors
* and/or true_distances and fails when those matrices have the wrong shape.
*/
BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNTrueNeighborDistanceTest",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -480,7 +489,7 @@ BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest)
SetInputParam("true_distances", distances);
SetInputParam("epsilon", (double) 0.5);
BOOST_REQUIRE_NO_THROW(mlpackMain());
REQUIRE_NOTHROW(mlpackMain());
// True output matrices have incorrect shape.
arma::Mat<size_t> dummyNeighbors;
@@ -500,7 +509,7 @@ BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest)
SetInputParam("true_distances", std::move(dummyDistances));
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -508,7 +517,8 @@ BOOST_AUTO_TEST_CASE(KFNTrueNeighborDistanceTest)
* Ensure that different search algorithms give same result.
* We do not consider greedy because it is an approximate algorithm.
*/
BOOST_AUTO_TEST_CASE(KFNAllAlgorithmsTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNAllAlgorithmsTest",
"[KFNMainTest][BindingTests]")
{
string algorithms[] = {"dual_tree", "naive", "single_tree"};
const int nofalgorithms = 3;
@@ -566,7 +576,8 @@ BOOST_AUTO_TEST_CASE(KFNAllAlgorithmsTest)
/*
* Ensure that different tree types give same result.
*/
BOOST_AUTO_TEST_CASE(KFNAllTreeTypesTest)
TEST_CASE_METHOD(KFNTestFixture, "KFNAllTreeTypesTest",
"[KFNMainTest][BindingTests]")
{
string treetypes[] = {"kd", "vp", "rp", "max-rp", "ub", "cover", "r",
"r-star", "x", "ball", "hilbert-r", "r-plus", "r-plus-plus",
@@ -626,7 +637,8 @@ BOOST_AUTO_TEST_CASE(KFNAllTreeTypesTest)
/**
* Ensure that different leaf sizes give different results.
*/
BOOST_AUTO_TEST_CASE(KFNDifferentLeafSizes)
TEST_CASE_METHOD(KFNTestFixture, "KFNDifferentLeafSizes",
"[KFNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -638,8 +650,7 @@ BOOST_AUTO_TEST_CASE(KFNDifferentLeafSizes)
mlpackMain();
BOOST_CHECK_EQUAL(IO::GetParam<KFNModel*>("output_model")->LeafSize(),
(int) 1);
REQUIRE(IO::GetParam<KFNModel*>("output_model")->LeafSize() == (int) 1);
bindings::tests::CleanMemory();
@@ -655,8 +666,5 @@ BOOST_AUTO_TEST_CASE(KFNDifferentLeafSizes)
// Check that initial output matrices and the output matrices using
// saved model are equal.
BOOST_CHECK_EQUAL(IO::GetParam<KFNModel*>("output_model")->LeafSize(),
(int) 10);
REQUIRE(IO::GetParam<KFNModel*>("output_model")->LeafSize() == (int) 10);
}
BOOST_AUTO_TEST_SUITE_END();
+64 -53
View File
@@ -20,8 +20,8 @@ static const std::string testName = "K-NearestNeighborsSearch";
#include "test_helper.hpp"
#include <mlpack/methods/neighbor_search/knn_main.cpp>
#include <boost/test/unit_test.hpp>
#include "../test_tools.hpp"
#include "../test_catch_tools.hpp"
#include "../catch.hpp"
using namespace mlpack;
@@ -42,13 +42,12 @@ struct KNNTestFixture
}
};
BOOST_FIXTURE_TEST_SUITE(KNNMainTest, KNNTestFixture);
/*
* Check that we can't provide reference and query matrices
* with different dimensions.
*/
BOOST_AUTO_TEST_CASE(KNNEqualDimensionTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNEqualDimensionTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -65,7 +64,7 @@ BOOST_AUTO_TEST_CASE(KNNEqualDimensionTest)
SetInputParam("k", (int) 10);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -73,7 +72,8 @@ BOOST_AUTO_TEST_CASE(KNNEqualDimensionTest)
* Check that we can't specify an invalid k when only reference
* matrix is given.
*/
BOOST_AUTO_TEST_CASE(KNNInvalidKTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidKTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -83,7 +83,7 @@ BOOST_AUTO_TEST_CASE(KNNInvalidKTest)
SetInputParam("k", (int) 101);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
IO::GetSingleton().Parameters()["reference"].wasPassed = false;
IO::GetSingleton().Parameters()["k"].wasPassed = false;
@@ -91,7 +91,7 @@ BOOST_AUTO_TEST_CASE(KNNInvalidKTest)
SetInputParam("reference", std::move(referenceData));
SetInputParam("k", (int) -1); // Invalid.
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -99,7 +99,8 @@ BOOST_AUTO_TEST_CASE(KNNInvalidKTest)
* Check that we can't specify an invalid k when both reference
* and query matrices are given.
*/
BOOST_AUTO_TEST_CASE(KNNInvalidKQueryDataTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidKQueryDataTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -113,14 +114,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidKQueryDataTest)
SetInputParam("k", (int) 101);
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/**
* Check that we can't specify a negative leaf size.
*/
BOOST_AUTO_TEST_CASE(KNNLeafSizeTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNLeafSizeTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -130,14 +132,15 @@ BOOST_AUTO_TEST_CASE(KNNLeafSizeTest)
SetInputParam("leaf_size", (int) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass both input_model and reference matrix.
*/
BOOST_AUTO_TEST_CASE(KNNRefModelTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNRefModelTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -153,14 +156,15 @@ BOOST_AUTO_TEST_CASE(KNNRefModelTest)
std::move(IO::GetParam<KNNModel*>("output_model")));
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid tree type.
*/
BOOST_AUTO_TEST_CASE(KNNInvalidTreeTypeTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidTreeTypeTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -171,14 +175,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidTreeTypeTest)
SetInputParam("tree_type", (string) "min-rp"); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid algorithm.
*/
BOOST_AUTO_TEST_CASE(KNNInvalidAlgoTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidAlgoTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -189,14 +194,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidAlgoTest)
SetInputParam("algorithm", (string) "triple_tree"); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid value of epsilon.
*/
BOOST_AUTO_TEST_CASE(KNNInvalidEpsilonTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidEpsilonTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -207,14 +213,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidEpsilonTest)
SetInputParam("epsilon", (double) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid value of tau.
*/
BOOST_AUTO_TEST_CASE(KNNInvalidTauTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidTauTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -225,14 +232,15 @@ BOOST_AUTO_TEST_CASE(KNNInvalidTauTest)
SetInputParam("tau", (double) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
/*
* Check that we can't pass an invalid value of rho.
*/
BOOST_AUTO_TEST_CASE(KNNInvalidRhoTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNInvalidRhoTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -245,7 +253,7 @@ BOOST_AUTO_TEST_CASE(KNNInvalidRhoTest)
SetInputParam("rho", (double) -1); // Invalid.
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
// Reset passed parameters.
IO::GetSingleton().Parameters()["reference"].wasPassed = false;
@@ -254,7 +262,7 @@ BOOST_AUTO_TEST_CASE(KNNInvalidRhoTest)
SetInputParam("reference", std::move(referenceData));
SetInputParam("rho", (double) 1.5); // Invalid.
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -262,7 +270,8 @@ BOOST_AUTO_TEST_CASE(KNNInvalidRhoTest)
* Make sure that dimensions of the neighbors and distances matrices are correct
* given a value of k.
*/
BOOST_AUTO_TEST_CASE(KNNOutputDimensionTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNOutputDimensionTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -274,20 +283,19 @@ BOOST_AUTO_TEST_CASE(KNNOutputDimensionTest)
mlpackMain();
// Check the neighbors matrix has 10 points for each input point.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Mat<size_t>>
("neighbors").n_rows, 10);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::Mat<size_t>>
("neighbors").n_cols, 100);
REQUIRE(IO::GetParam<arma::Mat<size_t>>("neighbors").n_rows == 10);
REQUIRE(IO::GetParam<arma::Mat<size_t>>("neighbors").n_cols == 100);
// Check the distances matrix has 10 points for each input point.
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("distances").n_rows, 10);
BOOST_REQUIRE_EQUAL(IO::GetParam<arma::mat>("distances").n_cols, 100);
REQUIRE(IO::GetParam<arma::mat>("distances").n_rows == 10);
REQUIRE(IO::GetParam<arma::mat>("distances").n_cols == 100);
}
/**
* Ensure that saved model can be used again.
*/
BOOST_AUTO_TEST_CASE(KNNModelReuseTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNModelReuseTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -329,7 +337,8 @@ BOOST_AUTO_TEST_CASE(KNNModelReuseTest)
* Ensure that changing the value of tau gives us different greedy
* spill tree results.
*/
BOOST_AUTO_TEST_CASE(KNNDifferentTauTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNDifferentTauTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(6, 1000); // 1000 points in 6 dimensions.
@@ -368,7 +377,8 @@ BOOST_AUTO_TEST_CASE(KNNDifferentTauTest)
* Ensure that changing the value of rho gives us different greedy
* spill tree results.
*/
BOOST_AUTO_TEST_CASE(KNNDifferentRhoTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNDifferentRhoTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 1000); // 1000 points in 3 dimensions.
@@ -408,7 +418,8 @@ BOOST_AUTO_TEST_CASE(KNNDifferentRhoTest)
* Ensure that changing the value of epslion gives us different
* approximate KNN results.
*/
BOOST_AUTO_TEST_CASE(KNNDifferentEpsilonTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNDifferentEpsilonTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 1000); // 1000 points in 3 dimensions.
@@ -445,7 +456,8 @@ BOOST_AUTO_TEST_CASE(KNNDifferentEpsilonTest)
* Ensure that we get same results on running twice in dual-tree mode
* search mode when random_basis is specified.
*/
BOOST_AUTO_TEST_CASE(KNNRandomBasisTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNRandomBasisTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 1000); // 1000 points in 3 dimensions.
@@ -462,8 +474,7 @@ BOOST_AUTO_TEST_CASE(KNNRandomBasisTest)
arma::mat distances;
neighbors = std::move(IO::GetParam<arma::Mat<size_t>>("neighbors"));
distances = std::move(IO::GetParam<arma::mat>("distances"));
BOOST_REQUIRE_EQUAL(IO::GetParam<KNNModel*>("output_model")->RandomBasis(),
true);
REQUIRE(IO::GetParam<KNNModel*>("output_model")->RandomBasis() == true);
bindings::tests::CleanMemory();
@@ -476,15 +487,15 @@ BOOST_AUTO_TEST_CASE(KNNRandomBasisTest)
CheckMatrices(neighbors, IO::GetParam<arma::Mat<size_t>>("neighbors"));
CheckMatrices(distances, IO::GetParam<arma::mat>("distances"));
BOOST_REQUIRE_EQUAL(IO::GetParam<KNNModel*>("output_model")->RandomBasis(),
false);
REQUIRE(IO::GetParam<KNNModel*>("output_model")->RandomBasis() == false);
}
/*
* Ensure that the program runs successfully when we pass true_neighbors
* and/or true_distances and fails when those matrices have the wrong shape.
*/
BOOST_AUTO_TEST_CASE(KNNTrueNeighborDistanceTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNTrueNeighborDistanceTest",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -509,7 +520,7 @@ BOOST_AUTO_TEST_CASE(KNNTrueNeighborDistanceTest)
SetInputParam("true_distances", distances);
SetInputParam("epsilon", (double) 0.5);
BOOST_REQUIRE_NO_THROW(mlpackMain());
REQUIRE_NOTHROW(mlpackMain());
// True output matrices have incorrect shape.
arma::Mat<size_t> dummyNeighbors;
@@ -526,7 +537,7 @@ BOOST_AUTO_TEST_CASE(KNNTrueNeighborDistanceTest)
SetInputParam("true_distances", std::move(dummyDistances));
Log::Fatal.ignoreInput = true;
BOOST_REQUIRE_THROW(mlpackMain(), std::runtime_error);
REQUIRE_THROWS_AS(mlpackMain(), std::runtime_error);
Log::Fatal.ignoreInput = false;
}
@@ -534,7 +545,8 @@ BOOST_AUTO_TEST_CASE(KNNTrueNeighborDistanceTest)
* Ensure that different search algorithms give same result.
* We do not consider greedy because it is an approximate algorithm.
*/
BOOST_AUTO_TEST_CASE(KNNAllAlgorithmsTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNAllAlgorithmsTest",
"[KNNMainTest][BindingTests]")
{
string algorithms[] = {"dual_tree", "naive", "single_tree"};
const int nofalgorithms = 3;
@@ -592,7 +604,8 @@ BOOST_AUTO_TEST_CASE(KNNAllAlgorithmsTest)
/*
* Ensure that different tree types give same result.
*/
BOOST_AUTO_TEST_CASE(KNNAllTreeTypesTest)
TEST_CASE_METHOD(KNNTestFixture, "KNNAllTreeTypesTest",
"[KNNMainTest][BindingTests]")
{
// Not including spill for now.
string treetypes[] = {"kd", "vp", "rp", "max-rp", "ub", "cover", "r",
@@ -653,7 +666,8 @@ BOOST_AUTO_TEST_CASE(KNNAllTreeTypesTest)
/**
* Ensure that different leaf sizes give different results.
*/
BOOST_AUTO_TEST_CASE(KNNDifferentLeafSizes)
TEST_CASE_METHOD(KNNTestFixture, "KNNDifferentLeafSizes",
"[KNNMainTest][BindingTests]")
{
arma::mat referenceData;
referenceData.randu(3, 100); // 100 points in 3 dimensions.
@@ -680,10 +694,7 @@ BOOST_AUTO_TEST_CASE(KNNDifferentLeafSizes)
// Check that initial output matrices and the output matrices using
// saved model are equal.
BOOST_CHECK_EQUAL(output_model->LeafSize(), (int) 1);
BOOST_CHECK_EQUAL(IO::GetParam<KNNModel*>("output_model")->LeafSize(),
(int) 10);
REQUIRE(output_model->LeafSize() == (int) 1);
REQUIRE(IO::GetParam<KNNModel*>("output_model")->LeafSize() == (int) 10);
delete output_model;
}
BOOST_AUTO_TEST_SUITE_END();
+60 -1
View File
@@ -13,12 +13,13 @@
#include <boost/test/unit_test.hpp>
#include <mlpack/core/metrics/iou_metric.hpp>
#include <mlpack/core/metrics/non_maximal_supression.hpp>
#include <mlpack/core/metrics/bleu.hpp>
#include "test_tools.hpp"
using namespace std;
using namespace mlpack::metric;
BOOST_AUTO_TEST_SUITE(LMetricTest);
BOOST_AUTO_TEST_SUITE(MetricTest);
/**
* Simple test for L-1 metric.
@@ -301,4 +302,62 @@ BOOST_AUTO_TEST_CASE(NMSMetricTest)
CheckMatrices(desiredBoundingBox, selectedBoundingBox);
}
/**
*
*/
BOOST_AUTO_TEST_CASE(BLEUScoreTest)
{
typedef typename std::vector<std::string> WordVector;
std::vector<std::vector<WordVector>> referenceCorpus
= {{{"this", "is", "my", "house"},
{"this", "is", "my", "car"},
{"this", "is", "my", "bike"}},
{{"this", "is", "my", "table"},
{"this", "is", "my", "chair"},
{"this", "is", "my", "laptop"}},
{{"this", "is", "my", "table"},
{"this", "is", "your", "car"},
{"this", "is", "my", "notebook"}}};
std::vector<WordVector> translationCorpus
= {{"this", "is", "my", "book"},
{"this", "is", "your", "car"},
{"this", "is", "my", "watch"}};
BLEU<> bleu(4);
//! We are not using smoothing function here.
bleu.Evaluate(referenceCorpus, translationCorpus);
BOOST_REQUIRE_CLOSE_FRACTION(bleu.BLEUScore(), 0.0, 1e-05);
BOOST_REQUIRE_EQUAL(bleu.BrevityPenalty(), 1.0);
BOOST_REQUIRE_EQUAL(bleu.Ratio(), 1.0);
BOOST_REQUIRE_EQUAL(bleu.TranslationLength(), 12);
BOOST_REQUIRE_EQUAL(bleu.ReferenceLength(), 12);
std::vector<float> expectedPrecision = {0.666666f, 0.5555555f,
0.3333333f, 0.0f};
for (size_t i = 0; i < bleu.Precisions().size(); ++i)
{
BOOST_REQUIRE_CLOSE_FRACTION(bleu.Precisions()[i],
expectedPrecision[i], 1e-04);
}
//! We will use smoothing function here by setting smooth to true.
bleu.Evaluate(referenceCorpus, translationCorpus, true);
BOOST_REQUIRE_CLOSE_FRACTION(bleu.BLEUScore(), 0.459307, 1e-05);
BOOST_REQUIRE_EQUAL(bleu.BrevityPenalty(), 1.0);
BOOST_REQUIRE_EQUAL(bleu.Ratio(), 1.0);
BOOST_REQUIRE_EQUAL(bleu.TranslationLength(), 12);
BOOST_REQUIRE_EQUAL(bleu.ReferenceLength(), 12);
expectedPrecision = {0.692308f, 0.6f, 0.428571f, 0.25f};
for (size_t i = 0; i < bleu.Precisions().size(); ++i)
{
BOOST_REQUIRE_CLOSE_FRACTION(bleu.Precisions()[i],
expectedPrecision[i], 1e-04);
}
}
BOOST_AUTO_TEST_SUITE_END();
+6 -11
View File
@@ -13,17 +13,14 @@
#include <mlpack/core.hpp>
#include <mlpack/methods/quic_svd/quic_svd.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
BOOST_AUTO_TEST_SUITE(QUICSVDTest);
#include "catch.hpp"
using namespace mlpack;
/**
* The reconstruction error of the obtained SVD should be small.
*/
BOOST_AUTO_TEST_CASE(QUICSVDReconstructionError)
TEST_CASE("QUICSVDReconstructionError", "[QUICSVDTest]")
{
// Load the dataset.
arma::mat dataset;
@@ -49,13 +46,13 @@ BOOST_AUTO_TEST_CASE(QUICSVDReconstructionError)
++successes;
}
BOOST_REQUIRE_GT(successes, 0);
REQUIRE(successes > 0);
}
/**
* The singular value error of the obtained SVD should be small.
*/
BOOST_AUTO_TEST_CASE(QUICSVDSingularValueError)
TEST_CASE("QUICSVDSingularValueError", "[QUICSVDTest]")
{
arma::mat U = arma::randn<arma::mat>(3, 20);
arma::mat V = arma::randn<arma::mat>(10, 3);
@@ -80,10 +77,10 @@ BOOST_AUTO_TEST_CASE(QUICSVDSingularValueError)
// The sigular value error should be small.
double error = arma::norm(s1 - s3);
BOOST_REQUIRE_SMALL(error, 0.1);
REQUIRE(error == Approx(0.0).margin(0.1));
}
BOOST_AUTO_TEST_CASE(QUICSVDSameDimensionTest)
TEST_CASE("QUICSVDSameDimensionTest", "[QUICSVDTest]")
{
arma::mat dataset = arma::randn<arma::mat>(10, 10);
@@ -91,5 +88,3 @@ BOOST_AUTO_TEST_CASE(QUICSVDSameDimensionTest)
arma::mat u, v, sigma;
svd::QUIC_SVD quicsvd(dataset, u, v, sigma);
}
BOOST_AUTO_TEST_SUITE_END();
+4 -9
View File
@@ -13,10 +13,7 @@
#include <mlpack/core.hpp>
#include <mlpack/methods/randomized_svd/randomized_svd.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
BOOST_AUTO_TEST_SUITE(RandomizedSVDTest);
#include "catch.hpp"
using namespace mlpack;
@@ -24,7 +21,7 @@ using namespace mlpack;
* The reconstruction and sigular value error of the obtained SVD should be
* small.
*/
BOOST_AUTO_TEST_CASE(RandomizedSVDReconstructionError)
TEST_CASE("RandomizedSVDReconstructionError", "[RandomizedSVDTest]")
{
arma::mat U = arma::randn<arma::mat>(3, 20);
arma::mat V = arma::randn<arma::mat>(10, 3);
@@ -54,14 +51,12 @@ BOOST_AUTO_TEST_CASE(RandomizedSVDReconstructionError)
// The sigular value error should be small.
double error = arma::norm(s2 - s3, "frob") / arma::norm(s2, "frob");
BOOST_REQUIRE_SMALL(error, 1e-5);
REQUIRE(error == Approx(0.0).margin(1e-5));
arma::mat reconstruct = U2 * arma::diagmat(s2) * V2.t();
// The relative reconstruction error should be small.
error = arma::norm(centeredData - reconstruct, "frob") /
arma::norm(centeredData, "frob");
BOOST_REQUIRE_SMALL(error, 1e-5);
REQUIRE(error == Approx(0.0).margin(1e-5));
}
BOOST_AUTO_TEST_SUITE_END();
+18 -22
View File
@@ -14,16 +14,13 @@
#include <ensmallen.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "catch.hpp"
using namespace mlpack;
using namespace mlpack::svd;
using namespace ens;
BOOST_AUTO_TEST_SUITE(RegularizedSVDTest);
BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRandomEvaluate)
TEST_CASE("RegularizedSVDFunctionRandomEvaluate", "[RegularizedSVDTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -66,11 +63,12 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRandomEvaluate)
}
// Compare calculated cost and value obtained using Evaluate().
BOOST_REQUIRE_CLOSE(cost, rSVDFunc.Evaluate(parameters), 1e-5);
REQUIRE(cost == Approx(rSVDFunc.Evaluate(parameters)).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRegularizationEvaluate)
TEST_CASE("RegularizedSVDFunctionRegularizationEvaluate",
"[RegularizedSVDTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -119,14 +117,14 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionRegularizationEvaluate)
// Cost with regularization should be close to the sum of cost without
// regularization and the regularization terms.
BOOST_REQUIRE_CLOSE(rSVDFuncNoReg.Evaluate(parameters) + smallRegTerm,
rSVDFuncSmallReg.Evaluate(parameters), 1e-5);
BOOST_REQUIRE_CLOSE(rSVDFuncNoReg.Evaluate(parameters) + bigRegTerm,
rSVDFuncBigReg.Evaluate(parameters), 1e-5);
REQUIRE(rSVDFuncNoReg.Evaluate(parameters) + smallRegTerm ==
Approx(rSVDFuncSmallReg.Evaluate(parameters)).epsilon(1e-7));
REQUIRE(rSVDFuncNoReg.Evaluate(parameters) + bigRegTerm ==
Approx(rSVDFuncBigReg.Evaluate(parameters)).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionGradient)
TEST_CASE("RegularizedSVDFunctionGradient", "[RegularizedSVDTest]")
{
// Define useful constants.
const size_t numUsers = 50;
@@ -185,19 +183,19 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionGradient)
// Compare numerical and backpropagation gradient values.
if (std::abs(gradient1(i, j)) <= 1e-6)
BOOST_REQUIRE_SMALL(numGradient1, 1e-5);
REQUIRE(numGradient1 == Approx(0.0).margin(1e-5));
else
BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 0.02);
REQUIRE(numGradient1 == Approx(gradient1(i, j)).epsilon(0.0002));
if (std::abs(gradient2(i, j)) <= 1e-6)
BOOST_REQUIRE_SMALL(numGradient2, 1e-5);
REQUIRE(numGradient2 == Approx(0.0).margin(1e-5));
else
BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 0.02);
REQUIRE(numGradient2 == Approx(gradient2(i, j)).epsilon(0.0002));
}
}
}
BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimize)
TEST_CASE("RegularizedSVDFunctionOptimize", "[RegularizedSVDTest]")
{
// Define useful constants.
const size_t numUsers = 50;
@@ -248,7 +246,7 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimize)
arma::norm(data, "frob");
// Relative error should be small.
BOOST_REQUIRE_SMALL(relativeError, 1e-2);
REQUIRE(relativeError == Approx(0.0).margin(1e-2));
}
// The test is only compiled if the user has specified OpenMP to be
@@ -256,7 +254,7 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimize)
#ifdef HAS_OPENMP
// Test Regularized SVD with parallel SGD.
BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimizeHOGWILD)
TEST_CASE("RegularizedSVDFunctionOptimizeHOGWILD", "[RegularizedSVDTest]")
{
// Define useful constants.
const size_t numUsers = 50;
@@ -313,9 +311,7 @@ BOOST_AUTO_TEST_CASE(RegularizedSVDFunctionOptimizeHOGWILD)
arma::norm(data, "frob");
// Relative error should be small.
BOOST_REQUIRE_SMALL(relativeError, 1e-2);
REQUIRE(relativeError == Approx(0.0).margin(1e-2));
}
#endif
BOOST_AUTO_TEST_SUITE_END();
+31
View File
@@ -39,6 +39,7 @@
#include <mlpack/methods/lsh/lsh_search.hpp>
#include <mlpack/methods/decision_stump/decision_stump.hpp>
#include <mlpack/methods/lars/lars.hpp>
#include <mlpack/methods/bayesian_linear_regression/bayesian_linear_regression.hpp>
#include <mlpack/methods/ann/rbm/rbm.hpp>
#include <mlpack/methods/ann/init_rules/gaussian_init.hpp>
@@ -1602,4 +1603,34 @@ BOOST_AUTO_TEST_CASE(ssRBMTest)
CheckMatrices(Rbm.Weight(), RbmBinary.Weight());
}
// Make sure serialization works for BayesianLinearRegression.
BOOST_AUTO_TEST_CASE(BayesianLinearRegressionTest)
{
using namespace mlpack::regression;
// Create a dataset.
arma::mat matX = arma::randn(75, 250);
arma::vec omega = arma::randn(75, 1);
arma::rowvec y = omega.t() * matX;
BayesianLinearRegression blr(false, false);
blr.Train(matX, y);
arma::vec omegaOpt = blr.Omega();
// Now, serialize.
BayesianLinearRegression xmlBlr(false, false), binaryBlr(false, false),
textBlr(false, false);
SerializeObjectAll(blr, xmlBlr, binaryBlr, textBlr);
// Now, check that predictions are the same.
arma::rowvec pred, xmlPred, textPred, binaryPred;
blr.Predict(matX, pred);
xmlBlr.Predict(matX, xmlPred);
textBlr.Predict(matX, textPred);
binaryBlr.Predict(matX, binaryPred);
CheckMatrices(pred, xmlPred, textPred, binaryPred);
}
BOOST_AUTO_TEST_SUITE_END();
+11 -15
View File
@@ -17,10 +17,7 @@
#include <mlpack/methods/amf/termination_policies/validation_rmse_termination.hpp>
#include <mlpack/methods/amf/termination_policies/simple_tolerance_termination.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
BOOST_AUTO_TEST_SUITE(SVDBatchTest);
#include "catch.hpp"
using namespace std;
using namespace mlpack;
@@ -30,7 +27,7 @@ using namespace arma;
/**
* Make sure the SVD Batch lerning is converging.
*/
BOOST_AUTO_TEST_CASE(SVDBatchConvergenceElementTest)
TEST_CASE("SVDBatchConvergenceElementTest", "[SVDBatchTest]")
{
sp_mat data;
data.sprandn(100, 100, 0.2);
@@ -40,8 +37,8 @@ BOOST_AUTO_TEST_CASE(SVDBatchConvergenceElementTest)
mat m1, m2;
amf.Apply(data, 2, m1, m2);
BOOST_REQUIRE_NE(amf.TerminationPolicy().Iteration(),
amf.TerminationPolicy().MaxIterations());
REQUIRE(amf.TerminationPolicy().Iteration() !=
amf.TerminationPolicy().MaxIterations());
}
//! This is used to ensure we start from the same initial point.
@@ -70,7 +67,7 @@ class SpecificRandomInitialization
/**
* Make sure the momentum is working okay.
*/
BOOST_AUTO_TEST_CASE(SVDBatchMomentumTest)
TEST_CASE("SVDBatchMomentumTest", "[SVDBatchTest]")
{
mat dataset;
data::Load("GroupLensSmall.csv", dataset);
@@ -111,13 +108,13 @@ BOOST_AUTO_TEST_CASE(SVDBatchMomentumTest)
const double momentumRMSE = amf2.Apply(cleanedData, 2, m1, m2);
BOOST_REQUIRE_LE(momentumRMSE, regularRMSE + 0.1);
REQUIRE(momentumRMSE <= regularRMSE + 0.1);
}
/**
* Make sure the regularization is working okay.
*/
BOOST_AUTO_TEST_CASE(SVDBatchRegularizationTest)
TEST_CASE("SVDBatchRegularizationTest", "[SVDBatchTest]")
{
mat dataset;
data::Load("GroupLensSmall.csv", dataset);
@@ -158,13 +155,13 @@ BOOST_AUTO_TEST_CASE(SVDBatchRegularizationTest)
double momentumRMSE = amf2.Apply(cleanedData, 2, m1, m2);
BOOST_REQUIRE_LE(momentumRMSE, regularRMSE + 0.05);
REQUIRE(momentumRMSE <= regularRMSE + 0.05);
}
/**
* Make sure the SVD can factorize matrices with negative entries.
*/
BOOST_AUTO_TEST_CASE(SVDBatchNegativeElementTest)
TEST_CASE("SVDBatchNegativeElementTest", "[SVDBatchTest]")
{
// Create two 5x3 matrices that we should be able to recover.
mat testLeft;
@@ -189,7 +186,6 @@ BOOST_AUTO_TEST_CASE(SVDBatchNegativeElementTest)
arma::mat result = m1 * m2;
// 6.5% tolerance on the norm.
BOOST_REQUIRE_CLOSE(arma::norm(test, "fro"), arma::norm(result, "fro"), 9.0);
REQUIRE(arma::norm(test, "fro") ==
Approx(arma::norm(result, "fro")).epsilon(0.09));
}
BOOST_AUTO_TEST_SUITE_END();
+9 -14
View File
@@ -20,10 +20,7 @@
#include <mlpack/methods/amf/termination_policies/simple_tolerance_termination.hpp>
#include <mlpack/methods/amf/termination_policies/validation_rmse_termination.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
BOOST_AUTO_TEST_SUITE(SVDIncrementalTest);
#include "catch.hpp"
using namespace std;
using namespace mlpack;
@@ -33,7 +30,7 @@ using namespace arma;
/**
* Test for convergence of incomplete incremenal learning.
*/
BOOST_AUTO_TEST_CASE(SVDIncompleteIncrementalConvergenceTest)
TEST_CASE("SVDIncompleteIncrementalConvergenceTest", "[SVDIncrementalTest]")
{
sp_mat data;
data.sprandn(100, 100, 0.2);
@@ -48,14 +45,14 @@ BOOST_AUTO_TEST_CASE(SVDIncompleteIncrementalConvergenceTest)
mat m1, m2;
amf.Apply(data, 2, m1, m2);
BOOST_REQUIRE_NE(amf.TerminationPolicy().Iteration(),
amf.TerminationPolicy().MaxIterations());
REQUIRE(amf.TerminationPolicy().Iteration() !=
amf.TerminationPolicy().MaxIterations());
}
/**
* Test for convergence of complete incremenal learning
*/
BOOST_AUTO_TEST_CASE(SVDCompleteIncrementalConvergenceTest)
TEST_CASE("SVDCompleteIncrementalConvergenceTest", "[SVDIncrementalTest]")
{
sp_mat data;
data.sprandn(100, 100, 0.2);
@@ -71,8 +68,8 @@ BOOST_AUTO_TEST_CASE(SVDCompleteIncrementalConvergenceTest)
mat m1, m2;
amf.Apply(data, 2, m1, m2);
BOOST_REQUIRE_NE(amf.TerminationPolicy().Iteration(),
amf.TerminationPolicy().MaxIterations());
REQUIRE(amf.TerminationPolicy().Iteration() !=
amf.TerminationPolicy().MaxIterations());
}
//! This is used to ensure we start from the same initial point.
@@ -98,7 +95,7 @@ class SpecificRandomInitialization
arma::mat H;
};
BOOST_AUTO_TEST_CASE(SVDIncompleteIncrementalRegularizationTest)
TEST_CASE("SVDIncompleteIncrementalRegularizationTest", "[SVDIncrementalTest]")
{
mat dataset;
data::Load("GroupLensSmall.csv", dataset);
@@ -143,7 +140,5 @@ BOOST_AUTO_TEST_CASE(SVDIncompleteIncrementalRegularizationTest)
mat m3, m4;
double regularizedRMSE = amf2.Apply(cleanedData2, 2, m3, m4);
BOOST_REQUIRE_LT(regularizedRMSE, regularRMSE + 0.105);
REQUIRE(regularizedRMSE < regularRMSE + 0.105);
}
BOOST_AUTO_TEST_SUITE_END();
+31 -36
View File
@@ -15,15 +15,12 @@
#include <ensmallen.hpp>
#include <boost/test/unit_test.hpp>
#include "test_tools.hpp"
#include "catch.hpp"
using namespace mlpack;
using namespace mlpack::svd;
BOOST_AUTO_TEST_SUITE(SVDPlusPlusTest);
BOOST_AUTO_TEST_CASE(SVDPlusPlusEvaluate)
TEST_CASE("SVDPlusPlusEvaluate", "[SVDPlusPlusTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -89,11 +86,11 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusEvaluate)
}
// Compare calculated cost and value obtained using Evaluate().
BOOST_REQUIRE_CLOSE(cost, svdPPFunc.Evaluate(parameters), 1e-5);
REQUIRE(cost == Approx(svdPPFunc.Evaluate(parameters)).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionRegularizationEvaluate)
TEST_CASE("SVDPlusPlusFunctionRegularizationEvaluate", "[SVDPlusPlusTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -173,14 +170,14 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionRegularizationEvaluate)
// Cost with regularization should be close to the sum of cost without
// regularization and the regularization terms.
BOOST_REQUIRE_CLOSE(svdPPFuncNoReg.Evaluate(parameters) + smallRegTerm,
svdPPFuncSmallReg.Evaluate(parameters), 1e-5);
BOOST_REQUIRE_CLOSE(svdPPFuncNoReg.Evaluate(parameters) + bigRegTerm,
svdPPFuncBigReg.Evaluate(parameters), 1e-5);
REQUIRE(svdPPFuncNoReg.Evaluate(parameters) + smallRegTerm ==
Approx(svdPPFuncSmallReg.Evaluate(parameters)).epsilon(1e-7));
REQUIRE(svdPPFuncNoReg.Evaluate(parameters) + bigRegTerm ==
Approx(svdPPFuncBigReg.Evaluate(parameters)).epsilon(1e-7));
}
}
BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionGradient)
TEST_CASE("SVDPlusPlusFunctionGradient", "[SVDPlusPlusTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -242,19 +239,19 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionGradient)
// Compare numerical and backpropagation gradient values.
if (std::abs(gradient1(i, j)) <= 1e-6)
BOOST_REQUIRE_SMALL(numGradient1, 1e-5);
REQUIRE(numGradient1 == Approx(0.0).margin(1e-5));
else
BOOST_REQUIRE_CLOSE(numGradient1, gradient1(i, j), 0.02);
REQUIRE(numGradient1 == Approx(gradient1(i, j)).epsilon(0.0002));
if (std::abs(gradient2(i, j)) <= 1e-6)
BOOST_REQUIRE_SMALL(numGradient2, 1e-5);
REQUIRE(numGradient2 == Approx(0.0).margin(1e-5));
else
BOOST_REQUIRE_CLOSE(numGradient2, gradient2(i, j), 0.02);
REQUIRE(numGradient2 == Approx(gradient2(i, j)).epsilon(0.0002));
}
}
}
BOOST_AUTO_TEST_CASE(SVDplusPlusOutputSizeTest)
TEST_CASE("SVDplusPlusOutputSizeTest", "[SVDPlusPlusTest]")
{
// Load small GroupLens dataset.
arma::mat data;
@@ -277,17 +274,17 @@ BOOST_AUTO_TEST_CASE(SVDplusPlusOutputSizeTest)
itemImplicit);
// Check the size of outputs.
BOOST_REQUIRE_EQUAL(itemLatent.n_rows, numItems);
BOOST_REQUIRE_EQUAL(itemLatent.n_cols, rank);
BOOST_REQUIRE_EQUAL(userLatent.n_rows, rank);
BOOST_REQUIRE_EQUAL(userLatent.n_cols, numUsers);
BOOST_REQUIRE_EQUAL(itemBias.n_elem, numItems);
BOOST_REQUIRE_EQUAL(userBias.n_elem, numUsers);
BOOST_REQUIRE_EQUAL(itemImplicit.n_rows, rank);
BOOST_REQUIRE_EQUAL(itemImplicit.n_cols, numItems);
REQUIRE(itemLatent.n_rows == numItems);
REQUIRE(itemLatent.n_cols == rank);
REQUIRE(userLatent.n_rows == rank);
REQUIRE(userLatent.n_cols == numUsers);
REQUIRE(itemBias.n_elem == numItems);
REQUIRE(userBias.n_elem == numUsers);
REQUIRE(itemImplicit.n_rows == rank);
REQUIRE(itemImplicit.n_cols == numItems);
}
BOOST_AUTO_TEST_CASE(SVDPlusPlusCleanDataTest)
TEST_CASE("SVDPlusPlusCleanDataTest", "[SVDPlusPlusTest]")
{
// Load small GroupLens dataset.
arma::mat data;
@@ -320,21 +317,21 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusCleanDataTest)
SVDPlusPlus<>::CleanData(implicitData, cleanedData, data);
// Make sure cleanedData has correct size.
BOOST_REQUIRE_EQUAL(cleanedData.n_rows, numItems);
BOOST_REQUIRE_EQUAL(cleanedData.n_cols, numUsers);
REQUIRE(cleanedData.n_rows == numItems);
REQUIRE(cleanedData.n_cols == numUsers);
// Make sure cleanedData has correct number of implicit data.
BOOST_REQUIRE_EQUAL(cleanedData.n_nonzero, implicitData.n_cols);
REQUIRE(cleanedData.n_nonzero == implicitData.n_cols);
// Make sure all implicitData are in cleanedData.
for (size_t i = 0; i < implicitData.n_cols; ++i)
{
double value = cleanedData(implicitData(1, i), implicitData(0, i));
BOOST_REQUIRE_GT(std::fabs(value), 0);
REQUIRE(std::fabs(value) > 0);
}
}
BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionOptimize)
TEST_CASE("SVDPlusPlusFunctionOptimize", "[SVDPlusPlusTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -433,7 +430,7 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionOptimize)
arma::norm(data, "frob");
// Relative error should be small.
BOOST_REQUIRE_SMALL(relativeError, 1e-2);
REQUIRE(relativeError == Approx(0.0).margin(1e-2));
}
// The test is only compiled if the user has specified OpenMP to be
@@ -441,7 +438,7 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionOptimize)
#ifdef HAS_OPENMP
// Test SVDPlusPlus with parallel SGD.
BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionParallelOptimize)
TEST_CASE("SVDPlusPlusFunctionParallelOptimize", "[SVDPlusPlusTest]")
{
// Define useful constants.
const size_t numUsers = 100;
@@ -547,9 +544,7 @@ BOOST_AUTO_TEST_CASE(SVDPlusPlusFunctionParallelOptimize)
arma::norm(data, "frob");
// Relative error should be small.
BOOST_REQUIRE_SMALL(relativeError, 1e-2);
REQUIRE(relativeError == Approx(0.0).margin(1e-2));
}
#endif
BOOST_AUTO_TEST_SUITE_END();
+2 -2
View File
@@ -33,7 +33,7 @@ inline void CheckMatrices(const arma::mat& a,
for (size_t i = 0; i < a.n_elem; ++i)
{
if (std::abs(a[i]) < tolerance / 2)
REQUIRE(b[i] == Approx(0.0).margin(tolerance / 200));
REQUIRE(b[i] == Approx(0.0).margin(tolerance / 2));
else
REQUIRE(a[i] == Approx(b[i]).epsilon(tolerance / 100));
}
@@ -62,7 +62,7 @@ inline void CheckMatrices(const arma::cube& a,
for (size_t i = 0; i < a.n_elem; ++i)
{
if (std::abs(a[i]) < tolerance / 2)
REQUIRE(b[i] == Approx(0.0).margin(tolerance / 200));
REQUIRE(b[i] == Approx(0.0).margin(tolerance / 2));
else
REQUIRE(a[i] == Approx(b[i]).epsilon(tolerance / 100));
}