mirror of
https://github.com/rmontanana/mdlp.git
synced 2025-08-15 15:35:55 +00:00
Initial commit
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -30,3 +30,7 @@
|
|||||||
*.exe
|
*.exe
|
||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
**/build
|
||||||
|
**/lcoverage
|
||||||
|
.idea
|
||||||
|
cmake-*
|
||||||
|
7
CMakeLists.txt
Normal file
7
CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.24)
|
||||||
|
project(mdlp)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
add_library(mdlp CPPFImdlp.cpp Metrics.cpp)
|
||||||
|
|
159
CPPFImdlp.cpp
Normal file
159
CPPFImdlp.cpp
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
#include <numeric>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <set>
|
||||||
|
#include "CPPFImdlp.h"
|
||||||
|
#include "Metrics.h"
|
||||||
|
|
||||||
|
namespace mdlp {
|
||||||
|
CPPFImdlp::CPPFImdlp(bool proposal):proposal(proposal), indices(indices_t()), X(samples_t()), y(labels_t()), metrics(Metrics(y, indices))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
CPPFImdlp::~CPPFImdlp()
|
||||||
|
= default;
|
||||||
|
|
||||||
|
CPPFImdlp& CPPFImdlp::fit(samples_t& X_, labels_t& y_)
|
||||||
|
{
|
||||||
|
X = X_;
|
||||||
|
y = y_;
|
||||||
|
cutPoints.clear();
|
||||||
|
if (X.size() != y.size()) {
|
||||||
|
throw invalid_argument("X and y must have the same size");
|
||||||
|
}
|
||||||
|
if (X.size() == 0 || y.size() == 0) {
|
||||||
|
throw invalid_argument("X and y must have at least one element");
|
||||||
|
}
|
||||||
|
indices = sortIndices(X_);
|
||||||
|
metrics.setData(y, indices);
|
||||||
|
if (proposal)
|
||||||
|
computeCutPointsProposal();
|
||||||
|
else
|
||||||
|
computeCutPoints(0, X.size());
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
void CPPFImdlp::computeCutPoints(size_t start, size_t end)
|
||||||
|
{
|
||||||
|
int cut;
|
||||||
|
if (end - start < 2)
|
||||||
|
return;
|
||||||
|
cut = getCandidate(start, end);
|
||||||
|
if (cut == -1 || !mdlp(start, cut, end)) {
|
||||||
|
// cut.value == -1 means that there is no candidate in the interval
|
||||||
|
// No boundary found, so we add both ends of the interval as cutpoints
|
||||||
|
// because they were selected by the algorithm before
|
||||||
|
if (start != 0)
|
||||||
|
cutPoints.push_back((X[indices[start]] + X[indices[start - 1]]) / 2);
|
||||||
|
if (end != X.size())
|
||||||
|
cutPoints.push_back((X[indices[end]] + X[indices[end - 1]]) / 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
computeCutPoints(start, cut);
|
||||||
|
computeCutPoints(cut, end);
|
||||||
|
}
|
||||||
|
void CPPFImdlp::computeCutPointsOriginal(size_t start, size_t end)
|
||||||
|
{
|
||||||
|
precision_t cut;
|
||||||
|
if (end - start < 2)
|
||||||
|
return;
|
||||||
|
cut = getCandidate(start, end);
|
||||||
|
if (cut == -1)
|
||||||
|
return;
|
||||||
|
if (mdlp(start, cut, end)) {
|
||||||
|
cutPoints.push_back((X[indices[cut]] + X[indices[cut - 1]]) / 2);
|
||||||
|
}
|
||||||
|
computeCutPointsOriginal(start, cut);
|
||||||
|
computeCutPointsOriginal(cut, end);
|
||||||
|
}
|
||||||
|
void CPPFImdlp::computeCutPointsProposal()
|
||||||
|
{
|
||||||
|
precision_t xPrev, xCur, xPivot, cutPoint;
|
||||||
|
int yPrev, yCur, yPivot;
|
||||||
|
size_t idx, numElements, start;
|
||||||
|
|
||||||
|
xCur = xPrev = X[indices[0]];
|
||||||
|
yCur = yPrev = y[indices[0]];
|
||||||
|
numElements = indices.size() - 1;
|
||||||
|
idx = start = 0;
|
||||||
|
while (idx < numElements) {
|
||||||
|
xPivot = xCur;
|
||||||
|
yPivot = yCur;
|
||||||
|
// Read the same values and check class changes
|
||||||
|
do {
|
||||||
|
idx++;
|
||||||
|
xCur = X[indices[idx]];
|
||||||
|
yCur = y[indices[idx]];
|
||||||
|
if (yCur != yPivot && xCur == xPivot) {
|
||||||
|
yPivot = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (idx < numElements && xCur == xPivot);
|
||||||
|
// Check if the class changed and there are more than 1 element
|
||||||
|
if ((idx - start > 1) && (yPivot == -1 || yPrev != yCur) && mdlp(start, idx, indices.size())) {
|
||||||
|
start = idx;
|
||||||
|
cutPoint = (xPrev + xCur) / 2;
|
||||||
|
cutPoints.push_back(cutPoint);
|
||||||
|
}
|
||||||
|
yPrev = yPivot;
|
||||||
|
xPrev = xPivot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
long int CPPFImdlp::getCandidate(size_t start, size_t end)
|
||||||
|
{
|
||||||
|
long int candidate = -1, elements = end - start;
|
||||||
|
precision_t entropy_left, entropy_right, minEntropy = numeric_limits<precision_t>::max();
|
||||||
|
for (auto idx = start + 1; idx < end; idx++) {
|
||||||
|
// Cutpoints are always on boudndaries
|
||||||
|
if (y[indices[idx]] == y[indices[idx - 1]])
|
||||||
|
continue;
|
||||||
|
entropy_left = precision_t(idx - start) / elements * metrics.entropy(start, idx);
|
||||||
|
entropy_right = precision_t(end - idx) / elements * metrics.entropy(idx, end);
|
||||||
|
if (entropy_left + entropy_right < minEntropy) {
|
||||||
|
minEntropy = entropy_left + entropy_right;
|
||||||
|
candidate = idx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
bool CPPFImdlp::mdlp(size_t start, size_t cut, size_t end)
|
||||||
|
{
|
||||||
|
int k, k1, k2;
|
||||||
|
precision_t ig, delta;
|
||||||
|
precision_t ent, ent1, ent2;
|
||||||
|
auto N = precision_t(end - start);
|
||||||
|
if (N < 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
k = metrics.computeNumClasses(start, end);
|
||||||
|
k1 = metrics.computeNumClasses(start, cut);
|
||||||
|
k2 = metrics.computeNumClasses(cut, end);
|
||||||
|
ent = metrics.entropy(start, end);
|
||||||
|
ent1 = metrics.entropy(start, cut);
|
||||||
|
ent2 = metrics.entropy(cut, end);
|
||||||
|
ig = metrics.informationGain(start, cut, end);
|
||||||
|
delta = log2(pow(3, precision_t(k)) - 2) -
|
||||||
|
(precision_t(k) * ent - precision_t(k1) * ent1 - precision_t(k2) * ent2);
|
||||||
|
precision_t term = 1 / N * (log2(N - 1) + delta);
|
||||||
|
return ig > term;
|
||||||
|
}
|
||||||
|
cutPoints_t CPPFImdlp::getCutPoints()
|
||||||
|
{
|
||||||
|
// Remove duplicates and sort
|
||||||
|
cutPoints_t output(cutPoints.size());
|
||||||
|
set<precision_t> s;
|
||||||
|
unsigned size = cutPoints.size();
|
||||||
|
for (unsigned i = 0; i < size; i++)
|
||||||
|
s.insert(cutPoints[i]);
|
||||||
|
output.assign(s.begin(), s.end());
|
||||||
|
sort(output.begin(), output.end());
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
// Argsort from https://stackoverflow.com/questions/1577475/c-sorting-and-keeping-track-of-indexes
|
||||||
|
indices_t CPPFImdlp::sortIndices(samples_t& X_)
|
||||||
|
{
|
||||||
|
indices_t idx(X_.size());
|
||||||
|
iota(idx.begin(), idx.end(), 0);
|
||||||
|
for (size_t i = 0; i < X_.size(); i++)
|
||||||
|
sort(idx.begin(), idx.end(), [&X_](size_t i1, size_t i2)
|
||||||
|
{ return X_[i1] < X_[i2]; });
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
}
|
33
CPPFImdlp.h
Normal file
33
CPPFImdlp.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef CPPFIMDLP_H
|
||||||
|
#define CPPFIMDLP_H
|
||||||
|
#include "typesFImdlp.h"
|
||||||
|
#include "Metrics.h"
|
||||||
|
#include <utility>
|
||||||
|
namespace mdlp {
|
||||||
|
class CPPFImdlp {
|
||||||
|
protected:
|
||||||
|
bool proposal;
|
||||||
|
indices_t indices; // sorted indices to use with X and y
|
||||||
|
samples_t X;
|
||||||
|
labels_t y;
|
||||||
|
Metrics metrics;
|
||||||
|
cutPoints_t cutPoints;
|
||||||
|
|
||||||
|
static indices_t sortIndices(samples_t&);
|
||||||
|
void computeCutPoints(size_t, size_t);
|
||||||
|
long int getCandidate(size_t, size_t);
|
||||||
|
bool mdlp(size_t, size_t, size_t);
|
||||||
|
|
||||||
|
// Original algorithm
|
||||||
|
void computeCutPointsOriginal(size_t, size_t);
|
||||||
|
bool goodCut(size_t, size_t, size_t);
|
||||||
|
void computeCutPointsProposal();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CPPFImdlp(bool);
|
||||||
|
~CPPFImdlp();
|
||||||
|
CPPFImdlp& fit(samples_t&, labels_t&);
|
||||||
|
samples_t getCutPoints();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
65
Metrics.cpp
Normal file
65
Metrics.cpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
#include "Metrics.h"
|
||||||
|
#include <set>
|
||||||
|
#include <cmath>
|
||||||
|
using namespace std;
|
||||||
|
namespace mdlp {
|
||||||
|
Metrics::Metrics(labels_t& y_, indices_t& indices_): y(y_), indices(indices_), numClasses(computeNumClasses(0, indices.size())), entropyCache(cacheEnt_t()), igCache(cacheIg_t())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
int Metrics::computeNumClasses(size_t start, size_t end)
|
||||||
|
{
|
||||||
|
set<int> nClasses;
|
||||||
|
for (auto i = start; i < end; ++i) {
|
||||||
|
nClasses.insert(y[indices[i]]);
|
||||||
|
}
|
||||||
|
return nClasses.size();
|
||||||
|
}
|
||||||
|
void Metrics::setData(labels_t& y_, indices_t& indices_)
|
||||||
|
{
|
||||||
|
indices = indices_;
|
||||||
|
y = y_;
|
||||||
|
numClasses = computeNumClasses(0, indices.size());
|
||||||
|
entropyCache.clear();
|
||||||
|
igCache.clear();
|
||||||
|
}
|
||||||
|
precision_t Metrics::entropy(size_t start, size_t end)
|
||||||
|
{
|
||||||
|
precision_t p, ventropy = 0;
|
||||||
|
int nElements = 0;
|
||||||
|
labels_t counts(numClasses + 1, 0);
|
||||||
|
if (end - start < 2)
|
||||||
|
return 0;
|
||||||
|
if (entropyCache.find(make_tuple(start, end)) != entropyCache.end()) {
|
||||||
|
return entropyCache[make_tuple(start, end)];
|
||||||
|
}
|
||||||
|
for (auto i = &indices[start]; i != &indices[end]; ++i) {
|
||||||
|
counts[y[*i]]++;
|
||||||
|
nElements++;
|
||||||
|
}
|
||||||
|
for (auto count : counts) {
|
||||||
|
if (count > 0) {
|
||||||
|
p = (precision_t)count / nElements;
|
||||||
|
ventropy -= p * log2(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entropyCache[make_tuple(start, end)] = ventropy;
|
||||||
|
return ventropy;
|
||||||
|
}
|
||||||
|
precision_t Metrics::informationGain(size_t start, size_t cut, size_t end)
|
||||||
|
{
|
||||||
|
precision_t iGain;
|
||||||
|
precision_t entropyInterval, entropyLeft, entropyRight;
|
||||||
|
int nElementsLeft = cut - start, nElementsRight = end - cut;
|
||||||
|
int nElements = end - start;
|
||||||
|
if (igCache.find(make_tuple(start, cut, end)) != igCache.end()) {
|
||||||
|
return igCache[make_tuple(start, cut, end)];
|
||||||
|
}
|
||||||
|
entropyInterval = entropy(start, end);
|
||||||
|
entropyLeft = entropy(start, cut);
|
||||||
|
entropyRight = entropy(cut, end);
|
||||||
|
iGain = entropyInterval - ((precision_t)nElementsLeft * entropyLeft + (precision_t)nElementsRight * entropyRight) / nElements;
|
||||||
|
igCache[make_tuple(start, cut, end)] = iGain;
|
||||||
|
return iGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
Metrics.h
Normal file
20
Metrics.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef CCMETRICS_H
|
||||||
|
#define CCMETRICS_H
|
||||||
|
#include "typesFImdlp.h"
|
||||||
|
namespace mdlp {
|
||||||
|
class Metrics {
|
||||||
|
protected:
|
||||||
|
labels_t& y;
|
||||||
|
indices_t& indices;
|
||||||
|
int numClasses;
|
||||||
|
cacheEnt_t entropyCache;
|
||||||
|
cacheIg_t igCache;
|
||||||
|
public:
|
||||||
|
Metrics(labels_t&, indices_t&);
|
||||||
|
void setData(labels_t&, indices_t&);
|
||||||
|
int computeNumClasses(size_t, size_t);
|
||||||
|
precision_t entropy(size_t, size_t);
|
||||||
|
precision_t informationGain(size_t, size_t, size_t);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
117
sample/ArffFiles.cpp
Normal file
117
sample/ArffFiles.cpp
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#include "ArffFiles.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <map>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
ArffFiles::ArffFiles()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
vector<string> ArffFiles::getLines()
|
||||||
|
{
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
unsigned long int ArffFiles::getSize()
|
||||||
|
{
|
||||||
|
return lines.size();
|
||||||
|
}
|
||||||
|
vector<tuple<string, string>> ArffFiles::getAttributes()
|
||||||
|
{
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
string ArffFiles::getClassName()
|
||||||
|
{
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
string ArffFiles::getClassType()
|
||||||
|
{
|
||||||
|
return classType;
|
||||||
|
}
|
||||||
|
vector<vector<float>>& ArffFiles::getX()
|
||||||
|
{
|
||||||
|
return X;
|
||||||
|
}
|
||||||
|
vector<int>& ArffFiles::getY()
|
||||||
|
{
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
void ArffFiles::load(string fileName, bool classLast)
|
||||||
|
{
|
||||||
|
ifstream file(fileName);
|
||||||
|
string keyword, attribute, type;
|
||||||
|
if (file.is_open()) {
|
||||||
|
string line;
|
||||||
|
while (getline(file, line)) {
|
||||||
|
if (line[0] == '%' || line.empty() || line == "\r" || line == " ") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line.find("@attribute") != string::npos || line.find("@ATTRIBUTE") != string::npos) {
|
||||||
|
stringstream ss(line);
|
||||||
|
ss >> keyword >> attribute >> type;
|
||||||
|
attributes.push_back(make_tuple(attribute, type));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (line[0] == '@') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lines.push_back(line);
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
if (attributes.empty())
|
||||||
|
throw invalid_argument("No attributes found");
|
||||||
|
if (classLast) {
|
||||||
|
className = get<0>(attributes.back());
|
||||||
|
classType = get<1>(attributes.back());
|
||||||
|
attributes.pop_back();
|
||||||
|
} else {
|
||||||
|
className = get<0>(attributes.front());
|
||||||
|
classType = get<1>(attributes.front());
|
||||||
|
attributes.erase(attributes.begin());
|
||||||
|
}
|
||||||
|
generateDataset(classLast);
|
||||||
|
} else
|
||||||
|
throw invalid_argument("Unable to open file");
|
||||||
|
}
|
||||||
|
void ArffFiles::generateDataset(bool classLast)
|
||||||
|
{
|
||||||
|
X = vector<vector<float>>(attributes.size(), vector<float>(lines.size()));
|
||||||
|
vector<string> yy = vector<string>(lines.size(), "");
|
||||||
|
int labelIndex = classLast ? attributes.size() : 0;
|
||||||
|
for (int i = 0; i < lines.size(); i++) {
|
||||||
|
stringstream ss(lines[i]);
|
||||||
|
string value;
|
||||||
|
int pos = 0, xIndex = 0;
|
||||||
|
while (getline(ss, value, ',')) {
|
||||||
|
if (pos++ == labelIndex) {
|
||||||
|
yy[i] = value;
|
||||||
|
} else {
|
||||||
|
X[xIndex++][i] = stof(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
y = factorize(yy);
|
||||||
|
}
|
||||||
|
string ArffFiles::trim(const string& source)
|
||||||
|
{
|
||||||
|
string s(source);
|
||||||
|
s.erase(0, s.find_first_not_of(" \n\r\t"));
|
||||||
|
s.erase(s.find_last_not_of(" \n\r\t") + 1);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
vector<int> ArffFiles::factorize(const vector<string>& labels_t)
|
||||||
|
{
|
||||||
|
vector<int> yy;
|
||||||
|
yy.reserve(labels_t.size());
|
||||||
|
map<string, int> labelMap;
|
||||||
|
int i = 0;
|
||||||
|
for (string label : labels_t) {
|
||||||
|
if (labelMap.find(label) == labelMap.end()) {
|
||||||
|
labelMap[label] = i++;
|
||||||
|
}
|
||||||
|
yy.push_back(labelMap[label]);
|
||||||
|
}
|
||||||
|
return yy;
|
||||||
|
}
|
28
sample/ArffFiles.h
Normal file
28
sample/ArffFiles.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef ARFFFILES_H
|
||||||
|
#define ARFFFILES_H
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <tuple>
|
||||||
|
using namespace std;
|
||||||
|
class ArffFiles {
|
||||||
|
private:
|
||||||
|
vector<string> lines;
|
||||||
|
vector<tuple<string, string>> attributes;
|
||||||
|
string className, classType;
|
||||||
|
vector<vector<float>> X;
|
||||||
|
vector<int> y;
|
||||||
|
void generateDataset(bool);
|
||||||
|
public:
|
||||||
|
ArffFiles();
|
||||||
|
void load(string, bool = true);
|
||||||
|
vector<string> getLines();
|
||||||
|
unsigned long int getSize();
|
||||||
|
string getClassName();
|
||||||
|
string getClassType();
|
||||||
|
string trim(const string&);
|
||||||
|
vector<vector<float>>& getX();
|
||||||
|
vector<int>& getY();
|
||||||
|
vector<tuple<string, string>> getAttributes();
|
||||||
|
vector<int> factorize(const vector<string>& labels_t);
|
||||||
|
};
|
||||||
|
#endif
|
6
sample/CMakeLists.txt
Normal file
6
sample/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.24)
|
||||||
|
project(main)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
add_executable(sample sample.cpp ArffFiles.cpp ../Metrics.cpp ../CPPFImdlp.cpp)
|
54
sample/sample.cpp
Normal file
54
sample/sample.cpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
#include "ArffFiles.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <iomanip>
|
||||||
|
#include "../CPPFImdlp.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
ArffFiles file;
|
||||||
|
vector<string> lines;
|
||||||
|
string path = "../../tests/datasets/";
|
||||||
|
map<string, bool > datasets = {
|
||||||
|
{"mfeat-factors", true},
|
||||||
|
{"iris", true},
|
||||||
|
{"letter", true},
|
||||||
|
{"kdd_JapaneseVowels", false}
|
||||||
|
};
|
||||||
|
if (argc != 2 || datasets.find(argv[1]) == datasets.end()) {
|
||||||
|
cout << "Usage: " << argv[0] << " {mfeat-factors, iris, letter, kdd_JapaneseVowels}" << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.load(path + argv[1] + ".arff", datasets[argv[1]]);
|
||||||
|
auto attributes = file.getAttributes();
|
||||||
|
int items = file.getSize();
|
||||||
|
cout << "Number of lines: " << items << endl;
|
||||||
|
cout << "Attributes: " << endl;
|
||||||
|
for (auto attribute : attributes) {
|
||||||
|
cout << "Name: " << get<0>(attribute) << " Type: " << get<1>(attribute) << endl;
|
||||||
|
}
|
||||||
|
cout << "Class name: " << file.getClassName() << endl;
|
||||||
|
cout << "Class type: " << file.getClassType() << endl;
|
||||||
|
cout << "Data: " << endl;
|
||||||
|
vector<vector<float>>& X = file.getX();
|
||||||
|
vector<int>& y = file.getY();
|
||||||
|
for (int i = 0; i < 50; i++) {
|
||||||
|
for (auto feature : X) {
|
||||||
|
cout << fixed << setprecision(1) << feature[i] << " ";
|
||||||
|
}
|
||||||
|
cout << y[i] << endl;
|
||||||
|
}
|
||||||
|
mdlp::CPPFImdlp test = mdlp::CPPFImdlp(false);
|
||||||
|
for (auto i = 0; i < attributes.size(); i++) {
|
||||||
|
cout << "Cut points for " << get<0>(attributes[i]) << endl;
|
||||||
|
cout << "--------------------------" << setprecision(3) << endl;
|
||||||
|
test.fit(X[i], y);
|
||||||
|
for (auto item : test.getCutPoints()) {
|
||||||
|
cout << item << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
2
tests/.gitignore
vendored
Normal file
2
tests/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
build
|
||||||
|
build/*
|
32
tests/CMakeLists.txt
Normal file
32
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.14)
|
||||||
|
project(FImdlp)
|
||||||
|
|
||||||
|
# GoogleTest requires at least C++14
|
||||||
|
set(CMAKE_CXX_STANDARD 14)
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
include_directories(${GTEST_INCLUDE_DIRS})
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
googletest
|
||||||
|
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||||
|
)
|
||||||
|
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||||
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
add_executable(Metrics_unittest ../Metrics.cpp Metrics_unittest.cpp)
|
||||||
|
add_executable(FImdlp_unittest ../CPPFImdlp.cpp ../Metrics.cpp FImdlp_unittest.cpp)
|
||||||
|
target_link_libraries(Metrics_unittest GTest::gtest_main)
|
||||||
|
target_link_libraries(FImdlp_unittest GTest::gtest_main)
|
||||||
|
target_compile_options(Metrics_unittest PRIVATE --coverage)
|
||||||
|
target_compile_options(FImdlp_unittest PRIVATE --coverage)
|
||||||
|
target_link_options(Metrics_unittest PRIVATE --coverage)
|
||||||
|
target_link_options(FImdlp_unittest PRIVATE --coverage)
|
||||||
|
|
||||||
|
include(GoogleTest)
|
||||||
|
gtest_discover_tests(Metrics_unittest)
|
||||||
|
gtest_discover_tests(FImdlp_unittest)
|
||||||
|
|
141
tests/FImdlp_unittest.cpp
Normal file
141
tests/FImdlp_unittest.cpp
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "../Metrics.h"
|
||||||
|
#include "../CPPFImdlp.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace mdlp {
|
||||||
|
class TestFImdlp : public CPPFImdlp, public testing::Test {
|
||||||
|
public:
|
||||||
|
precision_t precision = 0.000001;
|
||||||
|
|
||||||
|
TestFImdlp() : CPPFImdlp(false) {}
|
||||||
|
|
||||||
|
void SetUp() {
|
||||||
|
// 5.0, 5.1, 5.1, 5.1, 5.2, 5.3, 5.6, 5.7, 5.9, 6.0]
|
||||||
|
//(5.0, 1) (5.1, 1) (5.1, 2) (5.1, 2) (5.2, 1) (5.3, 1) (5.6, 2) (5.7, 1) (5.9, 2) (6.0, 2)
|
||||||
|
X = {5.7, 5.3, 5.2, 5.1, 5.0, 5.6, 5.1, 6.0, 5.1, 5.9};
|
||||||
|
y = {1, 1, 1, 1, 1, 2, 2, 2, 2, 2};
|
||||||
|
proposal = false;
|
||||||
|
fit(X, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setProposal(bool value) {
|
||||||
|
proposal = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// void initIndices()
|
||||||
|
// {
|
||||||
|
// indices = indices_t();
|
||||||
|
// }
|
||||||
|
void checkSortedVector() {
|
||||||
|
indices_t testSortedIndices = sortIndices(X);
|
||||||
|
precision_t prev = X[testSortedIndices[0]];
|
||||||
|
for (auto i = 0; i < X.size(); ++i) {
|
||||||
|
EXPECT_EQ(testSortedIndices[i], indices[i]);
|
||||||
|
EXPECT_LE(prev, X[testSortedIndices[i]]);
|
||||||
|
prev = X[testSortedIndices[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkCutPoints(cutPoints_t &expected) {
|
||||||
|
int expectedSize = expected.size();
|
||||||
|
EXPECT_EQ(cutPoints.size(), expectedSize);
|
||||||
|
for (auto i = 0; i < cutPoints.size(); i++) {
|
||||||
|
EXPECT_NEAR(cutPoints[i], expected[i], precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename A>
|
||||||
|
void checkVectors(std::vector<T, A> const &expected, std::vector<T, A> const &computed) {
|
||||||
|
EXPECT_EQ(expected.size(), computed.size());
|
||||||
|
ASSERT_EQ(expected.size(), computed.size());
|
||||||
|
for (auto i = 0; i < expected.size(); i++) {
|
||||||
|
EXPECT_NEAR(expected[i], computed[i],precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, FitErrorEmptyDataset) {
|
||||||
|
X = samples_t();
|
||||||
|
y = labels_t();
|
||||||
|
EXPECT_THROW(fit(X, y), std::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, FitErrorDifferentSize) {
|
||||||
|
X = {1, 2, 3};
|
||||||
|
y = {1, 2};
|
||||||
|
EXPECT_THROW(fit(X, y), std::invalid_argument);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, SortIndices) {
|
||||||
|
X = {5.7, 5.3, 5.2, 5.1, 5.0, 5.6, 5.1, 6.0, 5.1, 5.9};
|
||||||
|
indices = {4, 3, 6, 8, 2, 1, 5, 0, 9, 7};
|
||||||
|
checkSortedVector();
|
||||||
|
X = {5.77, 5.88, 5.99};
|
||||||
|
indices = {0, 1, 2};
|
||||||
|
checkSortedVector();
|
||||||
|
X = {5.33, 5.22, 5.11};
|
||||||
|
indices = {2, 1, 0};
|
||||||
|
checkSortedVector();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, TestDataset) {
|
||||||
|
proposal = false;
|
||||||
|
fit(X, y);
|
||||||
|
computeCutPointsOriginal(0, 10);
|
||||||
|
cutPoints_t expected = {5.6499996185302734};
|
||||||
|
vector<precision_t> computed = getCutPoints();
|
||||||
|
computed = getCutPoints();
|
||||||
|
int expectedSize = expected.size();
|
||||||
|
EXPECT_EQ(computed.size(), expected.size());
|
||||||
|
for (auto i = 0; i < expectedSize; i++) {
|
||||||
|
EXPECT_NEAR(computed[i], expected[i], precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, ComputeCutPointsOriginal) {
|
||||||
|
cutPoints_t expected = {5.65};
|
||||||
|
proposal = false;
|
||||||
|
computeCutPointsOriginal(0, 10);
|
||||||
|
checkCutPoints(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, ComputeCutPointsOriginalGCase) {
|
||||||
|
cutPoints_t expected;
|
||||||
|
proposal = false;
|
||||||
|
expected = {2};
|
||||||
|
samples_t X_ = {0, 1, 2, 2};
|
||||||
|
labels_t y_ = {1, 1, 1, 2};
|
||||||
|
fit(X_, y_);
|
||||||
|
checkCutPoints(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, ComputeCutPointsProposal) {
|
||||||
|
proposal = true;
|
||||||
|
cutPoints_t expected;
|
||||||
|
expected = {};
|
||||||
|
fit(X, y);
|
||||||
|
computeCutPointsProposal();
|
||||||
|
checkCutPoints(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, ComputeCutPointsProposalGCase) {
|
||||||
|
cutPoints_t expected;
|
||||||
|
expected = {1.5};
|
||||||
|
proposal = true;
|
||||||
|
samples_t X_ = {0, 1, 2, 2};
|
||||||
|
labels_t y_ = {1, 1, 1, 2};
|
||||||
|
fit(X_, y_);
|
||||||
|
checkCutPoints(expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestFImdlp, GetCutPoints) {
|
||||||
|
samples_t computed, expected = {5.65};
|
||||||
|
proposal = false;
|
||||||
|
computeCutPointsOriginal(0, 10);
|
||||||
|
computed = getCutPoints();
|
||||||
|
for (auto item: cutPoints)
|
||||||
|
cout << setprecision(6) << item << endl;
|
||||||
|
checkVectors(expected, computed);
|
||||||
|
}
|
||||||
|
}
|
43
tests/Metrics_unittest.cpp
Normal file
43
tests/Metrics_unittest.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "../Metrics.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace mdlp {
|
||||||
|
class TestMetrics: public Metrics, public testing::Test {
|
||||||
|
public:
|
||||||
|
labels_t y;
|
||||||
|
samples_t X;
|
||||||
|
indices_t indices;
|
||||||
|
precision_t precision = 0.000001;
|
||||||
|
|
||||||
|
TestMetrics(): Metrics(y, indices) {}
|
||||||
|
void SetUp()
|
||||||
|
{
|
||||||
|
y = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2 };
|
||||||
|
indices = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||||
|
setData(y, indices);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
TEST_F(TestMetrics, NumClasses)
|
||||||
|
{
|
||||||
|
y = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 1 };
|
||||||
|
EXPECT_EQ(1, computeNumClasses(4, 8));
|
||||||
|
EXPECT_EQ(2, computeNumClasses(0, 10));
|
||||||
|
EXPECT_EQ(2, computeNumClasses(8, 10));
|
||||||
|
}
|
||||||
|
TEST_F(TestMetrics, Entropy)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(1, entropy(0, 10));
|
||||||
|
EXPECT_EQ(0, entropy(0, 5));
|
||||||
|
y = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 1 };
|
||||||
|
setData(y, indices);
|
||||||
|
ASSERT_NEAR(0.468996, entropy(0, 10), precision);
|
||||||
|
}
|
||||||
|
TEST_F(TestMetrics, InformationGain)
|
||||||
|
{
|
||||||
|
ASSERT_NEAR(1, informationGain(0, 5, 10), precision);
|
||||||
|
y = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 1 };
|
||||||
|
setData(y, indices);
|
||||||
|
ASSERT_NEAR(0.108032, informationGain(0, 5, 10), precision);
|
||||||
|
}
|
||||||
|
}
|
4
tests/cover
Executable file
4
tests/cover
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
rm -fr lcoverage/*
|
||||||
|
lcov --capture --directory ./ --output-file lcoverage/main_coverage.info
|
||||||
|
genhtml lcoverage/main_coverage.info --output-directory lcoverage
|
||||||
|
open lcoverage/index.html
|
225
tests/datasets/iris.arff
Executable file
225
tests/datasets/iris.arff
Executable file
@@ -0,0 +1,225 @@
|
|||||||
|
% 1. Title: Iris Plants Database
|
||||||
|
%
|
||||||
|
% 2. Sources:
|
||||||
|
% (a) Creator: R.A. Fisher
|
||||||
|
% (b) Donor: Michael Marshall (MARSHALL%PLU@io.arc.nasa.gov)
|
||||||
|
% (c) Date: July, 1988
|
||||||
|
%
|
||||||
|
% 3. Past Usage:
|
||||||
|
% - Publications: too many to mention!!! Here are a few.
|
||||||
|
% 1. Fisher,R.A. "The use of multiple measurements in taxonomic problems"
|
||||||
|
% Annual Eugenics, 7, Part II, 179-188 (1936); also in "Contributions
|
||||||
|
% to Mathematical Statistics" (John Wiley, NY, 1950).
|
||||||
|
% 2. Duda,R.O., & Hart,P.E. (1973) Pattern Classification and Scene Analysis.
|
||||||
|
% (Q327.D83) John Wiley & Sons. ISBN 0-471-22361-1. See page 218.
|
||||||
|
% 3. Dasarathy, B.V. (1980) "Nosing Around the Neighborhood: A New System
|
||||||
|
% Structure and Classification Rule for Recognition in Partially Exposed
|
||||||
|
% Environments". IEEE Transactions on Pattern Analysis and Machine
|
||||||
|
% Intelligence, Vol. PAMI-2, No. 1, 67-71.
|
||||||
|
% -- Results:
|
||||||
|
% -- very low misclassification rates (0% for the setosa class)
|
||||||
|
% 4. Gates, G.W. (1972) "The Reduced Nearest Neighbor Rule". IEEE
|
||||||
|
% Transactions on Information Theory, May 1972, 431-433.
|
||||||
|
% -- Results:
|
||||||
|
% -- very low misclassification rates again
|
||||||
|
% 5. See also: 1988 MLC Proceedings, 54-64. Cheeseman et al's AUTOCLASS II
|
||||||
|
% conceptual clustering system finds 3 classes in the data.
|
||||||
|
%
|
||||||
|
% 4. Relevant Information:
|
||||||
|
% --- This is perhaps the best known database to be found in the pattern
|
||||||
|
% recognition literature. Fisher's paper is a classic in the field
|
||||||
|
% and is referenced frequently to this day. (See Duda & Hart, for
|
||||||
|
% example.) The data set contains 3 classes of 50 instances each,
|
||||||
|
% where each class refers to a type of iris plant. One class is
|
||||||
|
% linearly separable from the other 2; the latter are NOT linearly
|
||||||
|
% separable from each other.
|
||||||
|
% --- Predicted attribute: class of iris plant.
|
||||||
|
% --- This is an exceedingly simple domain.
|
||||||
|
%
|
||||||
|
% 5. Number of Instances: 150 (50 in each of three classes)
|
||||||
|
%
|
||||||
|
% 6. Number of Attributes: 4 numeric, predictive attributes and the class
|
||||||
|
%
|
||||||
|
% 7. Attribute Information:
|
||||||
|
% 1. sepal length in cm
|
||||||
|
% 2. sepal width in cm
|
||||||
|
% 3. petal length in cm
|
||||||
|
% 4. petal width in cm
|
||||||
|
% 5. class:
|
||||||
|
% -- Iris Setosa
|
||||||
|
% -- Iris Versicolour
|
||||||
|
% -- Iris Virginica
|
||||||
|
%
|
||||||
|
% 8. Missing Attribute Values: None
|
||||||
|
%
|
||||||
|
% Summary Statistics:
|
||||||
|
% Min Max Mean SD Class Correlation
|
||||||
|
% sepal length: 4.3 7.9 5.84 0.83 0.7826
|
||||||
|
% sepal width: 2.0 4.4 3.05 0.43 -0.4194
|
||||||
|
% petal length: 1.0 6.9 3.76 1.76 0.9490 (high!)
|
||||||
|
% petal width: 0.1 2.5 1.20 0.76 0.9565 (high!)
|
||||||
|
%
|
||||||
|
% 9. Class Distribution: 33.3% for each of 3 classes.
|
||||||
|
|
||||||
|
@RELATION iris
|
||||||
|
|
||||||
|
@ATTRIBUTE sepallength REAL
|
||||||
|
@ATTRIBUTE sepalwidth REAL
|
||||||
|
@ATTRIBUTE petallength REAL
|
||||||
|
@ATTRIBUTE petalwidth REAL
|
||||||
|
@ATTRIBUTE class {Iris-setosa,Iris-versicolor,Iris-virginica}
|
||||||
|
|
||||||
|
@DATA
|
||||||
|
5.1,3.5,1.4,0.2,Iris-setosa
|
||||||
|
4.9,3.0,1.4,0.2,Iris-setosa
|
||||||
|
4.7,3.2,1.3,0.2,Iris-setosa
|
||||||
|
4.6,3.1,1.5,0.2,Iris-setosa
|
||||||
|
5.0,3.6,1.4,0.2,Iris-setosa
|
||||||
|
5.4,3.9,1.7,0.4,Iris-setosa
|
||||||
|
4.6,3.4,1.4,0.3,Iris-setosa
|
||||||
|
5.0,3.4,1.5,0.2,Iris-setosa
|
||||||
|
4.4,2.9,1.4,0.2,Iris-setosa
|
||||||
|
4.9,3.1,1.5,0.1,Iris-setosa
|
||||||
|
5.4,3.7,1.5,0.2,Iris-setosa
|
||||||
|
4.8,3.4,1.6,0.2,Iris-setosa
|
||||||
|
4.8,3.0,1.4,0.1,Iris-setosa
|
||||||
|
4.3,3.0,1.1,0.1,Iris-setosa
|
||||||
|
5.8,4.0,1.2,0.2,Iris-setosa
|
||||||
|
5.7,4.4,1.5,0.4,Iris-setosa
|
||||||
|
5.4,3.9,1.3,0.4,Iris-setosa
|
||||||
|
5.1,3.5,1.4,0.3,Iris-setosa
|
||||||
|
5.7,3.8,1.7,0.3,Iris-setosa
|
||||||
|
5.1,3.8,1.5,0.3,Iris-setosa
|
||||||
|
5.4,3.4,1.7,0.2,Iris-setosa
|
||||||
|
5.1,3.7,1.5,0.4,Iris-setosa
|
||||||
|
4.6,3.6,1.0,0.2,Iris-setosa
|
||||||
|
5.1,3.3,1.7,0.5,Iris-setosa
|
||||||
|
4.8,3.4,1.9,0.2,Iris-setosa
|
||||||
|
5.0,3.0,1.6,0.2,Iris-setosa
|
||||||
|
5.0,3.4,1.6,0.4,Iris-setosa
|
||||||
|
5.2,3.5,1.5,0.2,Iris-setosa
|
||||||
|
5.2,3.4,1.4,0.2,Iris-setosa
|
||||||
|
4.7,3.2,1.6,0.2,Iris-setosa
|
||||||
|
4.8,3.1,1.6,0.2,Iris-setosa
|
||||||
|
5.4,3.4,1.5,0.4,Iris-setosa
|
||||||
|
5.2,4.1,1.5,0.1,Iris-setosa
|
||||||
|
5.5,4.2,1.4,0.2,Iris-setosa
|
||||||
|
4.9,3.1,1.5,0.1,Iris-setosa
|
||||||
|
5.0,3.2,1.2,0.2,Iris-setosa
|
||||||
|
5.5,3.5,1.3,0.2,Iris-setosa
|
||||||
|
4.9,3.1,1.5,0.1,Iris-setosa
|
||||||
|
4.4,3.0,1.3,0.2,Iris-setosa
|
||||||
|
5.1,3.4,1.5,0.2,Iris-setosa
|
||||||
|
5.0,3.5,1.3,0.3,Iris-setosa
|
||||||
|
4.5,2.3,1.3,0.3,Iris-setosa
|
||||||
|
4.4,3.2,1.3,0.2,Iris-setosa
|
||||||
|
5.0,3.5,1.6,0.6,Iris-setosa
|
||||||
|
5.1,3.8,1.9,0.4,Iris-setosa
|
||||||
|
4.8,3.0,1.4,0.3,Iris-setosa
|
||||||
|
5.1,3.8,1.6,0.2,Iris-setosa
|
||||||
|
4.6,3.2,1.4,0.2,Iris-setosa
|
||||||
|
5.3,3.7,1.5,0.2,Iris-setosa
|
||||||
|
5.0,3.3,1.4,0.2,Iris-setosa
|
||||||
|
7.0,3.2,4.7,1.4,Iris-versicolor
|
||||||
|
6.4,3.2,4.5,1.5,Iris-versicolor
|
||||||
|
6.9,3.1,4.9,1.5,Iris-versicolor
|
||||||
|
5.5,2.3,4.0,1.3,Iris-versicolor
|
||||||
|
6.5,2.8,4.6,1.5,Iris-versicolor
|
||||||
|
5.7,2.8,4.5,1.3,Iris-versicolor
|
||||||
|
6.3,3.3,4.7,1.6,Iris-versicolor
|
||||||
|
4.9,2.4,3.3,1.0,Iris-versicolor
|
||||||
|
6.6,2.9,4.6,1.3,Iris-versicolor
|
||||||
|
5.2,2.7,3.9,1.4,Iris-versicolor
|
||||||
|
5.0,2.0,3.5,1.0,Iris-versicolor
|
||||||
|
5.9,3.0,4.2,1.5,Iris-versicolor
|
||||||
|
6.0,2.2,4.0,1.0,Iris-versicolor
|
||||||
|
6.1,2.9,4.7,1.4,Iris-versicolor
|
||||||
|
5.6,2.9,3.6,1.3,Iris-versicolor
|
||||||
|
6.7,3.1,4.4,1.4,Iris-versicolor
|
||||||
|
5.6,3.0,4.5,1.5,Iris-versicolor
|
||||||
|
5.8,2.7,4.1,1.0,Iris-versicolor
|
||||||
|
6.2,2.2,4.5,1.5,Iris-versicolor
|
||||||
|
5.6,2.5,3.9,1.1,Iris-versicolor
|
||||||
|
5.9,3.2,4.8,1.8,Iris-versicolor
|
||||||
|
6.1,2.8,4.0,1.3,Iris-versicolor
|
||||||
|
6.3,2.5,4.9,1.5,Iris-versicolor
|
||||||
|
6.1,2.8,4.7,1.2,Iris-versicolor
|
||||||
|
6.4,2.9,4.3,1.3,Iris-versicolor
|
||||||
|
6.6,3.0,4.4,1.4,Iris-versicolor
|
||||||
|
6.8,2.8,4.8,1.4,Iris-versicolor
|
||||||
|
6.7,3.0,5.0,1.7,Iris-versicolor
|
||||||
|
6.0,2.9,4.5,1.5,Iris-versicolor
|
||||||
|
5.7,2.6,3.5,1.0,Iris-versicolor
|
||||||
|
5.5,2.4,3.8,1.1,Iris-versicolor
|
||||||
|
5.5,2.4,3.7,1.0,Iris-versicolor
|
||||||
|
5.8,2.7,3.9,1.2,Iris-versicolor
|
||||||
|
6.0,2.7,5.1,1.6,Iris-versicolor
|
||||||
|
5.4,3.0,4.5,1.5,Iris-versicolor
|
||||||
|
6.0,3.4,4.5,1.6,Iris-versicolor
|
||||||
|
6.7,3.1,4.7,1.5,Iris-versicolor
|
||||||
|
6.3,2.3,4.4,1.3,Iris-versicolor
|
||||||
|
5.6,3.0,4.1,1.3,Iris-versicolor
|
||||||
|
5.5,2.5,4.0,1.3,Iris-versicolor
|
||||||
|
5.5,2.6,4.4,1.2,Iris-versicolor
|
||||||
|
6.1,3.0,4.6,1.4,Iris-versicolor
|
||||||
|
5.8,2.6,4.0,1.2,Iris-versicolor
|
||||||
|
5.0,2.3,3.3,1.0,Iris-versicolor
|
||||||
|
5.6,2.7,4.2,1.3,Iris-versicolor
|
||||||
|
5.7,3.0,4.2,1.2,Iris-versicolor
|
||||||
|
5.7,2.9,4.2,1.3,Iris-versicolor
|
||||||
|
6.2,2.9,4.3,1.3,Iris-versicolor
|
||||||
|
5.1,2.5,3.0,1.1,Iris-versicolor
|
||||||
|
5.7,2.8,4.1,1.3,Iris-versicolor
|
||||||
|
6.3,3.3,6.0,2.5,Iris-virginica
|
||||||
|
5.8,2.7,5.1,1.9,Iris-virginica
|
||||||
|
7.1,3.0,5.9,2.1,Iris-virginica
|
||||||
|
6.3,2.9,5.6,1.8,Iris-virginica
|
||||||
|
6.5,3.0,5.8,2.2,Iris-virginica
|
||||||
|
7.6,3.0,6.6,2.1,Iris-virginica
|
||||||
|
4.9,2.5,4.5,1.7,Iris-virginica
|
||||||
|
7.3,2.9,6.3,1.8,Iris-virginica
|
||||||
|
6.7,2.5,5.8,1.8,Iris-virginica
|
||||||
|
7.2,3.6,6.1,2.5,Iris-virginica
|
||||||
|
6.5,3.2,5.1,2.0,Iris-virginica
|
||||||
|
6.4,2.7,5.3,1.9,Iris-virginica
|
||||||
|
6.8,3.0,5.5,2.1,Iris-virginica
|
||||||
|
5.7,2.5,5.0,2.0,Iris-virginica
|
||||||
|
5.8,2.8,5.1,2.4,Iris-virginica
|
||||||
|
6.4,3.2,5.3,2.3,Iris-virginica
|
||||||
|
6.5,3.0,5.5,1.8,Iris-virginica
|
||||||
|
7.7,3.8,6.7,2.2,Iris-virginica
|
||||||
|
7.7,2.6,6.9,2.3,Iris-virginica
|
||||||
|
6.0,2.2,5.0,1.5,Iris-virginica
|
||||||
|
6.9,3.2,5.7,2.3,Iris-virginica
|
||||||
|
5.6,2.8,4.9,2.0,Iris-virginica
|
||||||
|
7.7,2.8,6.7,2.0,Iris-virginica
|
||||||
|
6.3,2.7,4.9,1.8,Iris-virginica
|
||||||
|
6.7,3.3,5.7,2.1,Iris-virginica
|
||||||
|
7.2,3.2,6.0,1.8,Iris-virginica
|
||||||
|
6.2,2.8,4.8,1.8,Iris-virginica
|
||||||
|
6.1,3.0,4.9,1.8,Iris-virginica
|
||||||
|
6.4,2.8,5.6,2.1,Iris-virginica
|
||||||
|
7.2,3.0,5.8,1.6,Iris-virginica
|
||||||
|
7.4,2.8,6.1,1.9,Iris-virginica
|
||||||
|
7.9,3.8,6.4,2.0,Iris-virginica
|
||||||
|
6.4,2.8,5.6,2.2,Iris-virginica
|
||||||
|
6.3,2.8,5.1,1.5,Iris-virginica
|
||||||
|
6.1,2.6,5.6,1.4,Iris-virginica
|
||||||
|
7.7,3.0,6.1,2.3,Iris-virginica
|
||||||
|
6.3,3.4,5.6,2.4,Iris-virginica
|
||||||
|
6.4,3.1,5.5,1.8,Iris-virginica
|
||||||
|
6.0,3.0,4.8,1.8,Iris-virginica
|
||||||
|
6.9,3.1,5.4,2.1,Iris-virginica
|
||||||
|
6.7,3.1,5.6,2.4,Iris-virginica
|
||||||
|
6.9,3.1,5.1,2.3,Iris-virginica
|
||||||
|
5.8,2.7,5.1,1.9,Iris-virginica
|
||||||
|
6.8,3.2,5.9,2.3,Iris-virginica
|
||||||
|
6.7,3.3,5.7,2.5,Iris-virginica
|
||||||
|
6.7,3.0,5.2,2.3,Iris-virginica
|
||||||
|
6.3,2.5,5.0,1.9,Iris-virginica
|
||||||
|
6.5,3.0,5.2,2.0,Iris-virginica
|
||||||
|
6.2,3.4,5.4,2.3,Iris-virginica
|
||||||
|
5.9,3.0,5.1,1.8,Iris-virginica
|
||||||
|
%
|
||||||
|
%
|
||||||
|
%
|
10177
tests/datasets/kdd_JapaneseVowels.arff
Executable file
10177
tests/datasets/kdd_JapaneseVowels.arff
Executable file
File diff suppressed because it is too large
Load Diff
20191
tests/datasets/letter.arff
Executable file
20191
tests/datasets/letter.arff
Executable file
File diff suppressed because it is too large
Load Diff
2306
tests/datasets/mfeat-factors.arff
Executable file
2306
tests/datasets/mfeat-factors.arff
Executable file
File diff suppressed because it is too large
Load Diff
12
tests/test
Executable file
12
tests/test
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
cmake -S . -B build -Wno-dev
|
||||||
|
if test $? -ne 0; then
|
||||||
|
echo "Error in creating build commands."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cmake --build build
|
||||||
|
if test $? -ne 0; then
|
||||||
|
echo "Error in build command."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
cd build
|
||||||
|
ctest --output-on-failure
|
16
typesFImdlp.h
Normal file
16
typesFImdlp.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef TYPES_H
|
||||||
|
#define TYPES_H
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
namespace mdlp {
|
||||||
|
typedef float precision_t;
|
||||||
|
typedef vector<precision_t> samples_t;
|
||||||
|
typedef vector<int> labels_t;
|
||||||
|
typedef vector<size_t> indices_t;
|
||||||
|
typedef vector<precision_t> cutPoints_t;
|
||||||
|
typedef map<tuple<int, int>, precision_t> cacheEnt_t;
|
||||||
|
typedef map<tuple<int, int, int>, precision_t> cacheIg_t;
|
||||||
|
}
|
||||||
|
#endif
|
Reference in New Issue
Block a user