Merge remote-tracking branch 'origin/master' into rename-go-util
This commit is contained in:
@@ -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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -6,6 +6,7 @@ set(DIRS
|
||||
ann
|
||||
approx_kfn
|
||||
bias_svd
|
||||
bayesian_linear_regression
|
||||
block_krylov_svd
|
||||
cf
|
||||
dbscan
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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. */ }
|
||||
|
||||
|
||||
@@ -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;"
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
+572
-465
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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();
|
||||
|
||||
+362
-366
File diff suppressed because it is too large
Load Diff
+710
-714
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user