BayesNet/sample/main.cc

251 lines
8.0 KiB
C++

#include <iostream>
#include <string>
#include <torch/torch.h>
#include <thread>
#include <getopt.h>
#include "ArffFiles.h"
#include "Network.h"
#include "Metrics.hpp"
#include "CPPFImdlp.h"
using namespace std;
const string PATH = "data/";
/* print a description of all supported options */
void usage(const char* path)
{
/* take only the last portion of the path */
const char* basename = strrchr(path, '/');
basename = basename ? basename + 1 : path;
cout << "usage: " << basename << "[OPTION]" << endl;
cout << " -h, --help\t\t Print this help and exit." << endl;
cout
<< " -f, --file[=FILENAME]\t {diabetes, glass, iris, kdd_JapaneseVowels, letter, liver-disorders, mfeat-factors}."
<< endl;
cout << " -p, --path[=FILENAME]\t folder where the data files are located, default " << PATH << endl;
cout << " -n, --net=[FILENAME]\t default=file parameter value" << endl;
}
tuple<string, string, string> parse_arguments(int argc, char** argv)
{
string file_name;
string network_name;
string path = PATH;
const vector<struct option> long_options = {
{"help", no_argument, nullptr, 'h'},
{"file", required_argument, nullptr, 'f'},
{"path", required_argument, nullptr, 'p'},
{"net", required_argument, nullptr, 'n'},
{nullptr, no_argument, nullptr, 0}
};
while (true) {
const auto c = getopt_long(argc, argv, "hf:p:n:", long_options.data(), nullptr);
if (c == -1)
break;
switch (c) {
case 'h':
usage(argv[0]);
exit(0);
case 'f':
file_name = string(optarg);
break;
case 'n':
network_name = string(optarg);
break;
case 'p':
path = optarg;
if (path.back() != '/')
path += '/';
break;
case '?':
usage(argv[0]);
exit(1);
default:
abort();
}
}
if (file_name.empty()) {
usage(argv[0]);
exit(1);
}
if (network_name.empty()) {
network_name = file_name;
}
return make_tuple(file_name, path, network_name);
}
pair<vector<mdlp::labels_t>, map<string, int>> discretize(vector<mdlp::samples_t>& X, mdlp::labels_t& y, vector<string> features)
{
vector<mdlp::labels_t>Xd;
map<string, int> maxes;
auto fimdlp = mdlp::CPPFImdlp();
for (int i = 0; i < X.size(); i++) {
fimdlp.fit(X[i], y);
mdlp::labels_t& xd = fimdlp.transform(X[i]);
maxes[features[i]] = *max_element(xd.begin(), xd.end()) + 1;
Xd.push_back(xd);
}
return { Xd, maxes };
}
void showNodesInfo(bayesnet::Network& network, string className)
{
cout << "Nodes:" << endl;
for (auto [name, item] : network.getNodes()) {
cout << "*" << item->getName() << " States -> " << item->getNumStates() << endl;
cout << "-Parents:";
for (auto parent : item->getParents()) {
cout << " " << parent->getName();
}
cout << endl;
cout << "-Children:";
for (auto child : item->getChildren()) {
cout << " " << child->getName();
}
cout << endl;
}
}
void showCPDS(bayesnet::Network& network)
{
cout << "CPDs:" << endl;
auto nodes = network.getNodes();
for (auto it = nodes.begin(); it != nodes.end(); it++) {
cout << "* Name: " << it->first << " " << it->second->getName() << " -> " << it->second->getNumStates() << endl;
cout << "Parents: ";
for (auto parent : it->second->getParents()) {
cout << parent->getName() << " -> " << parent->getNumStates() << ", ";
}
cout << endl;
auto cpd = it->second->getCPT();
cout << cpd << endl;
}
}
bool file_exists(const std::string& name)
{
if (FILE* file = fopen(name.c_str(), "r")) {
fclose(file);
return true;
} else {
return false;
}
}
pair<string, string> get_options(int argc, char** argv)
{
map<string, bool> datasets = {
{"diabetes", true},
{"ecoli", true},
{"glass", true},
{"iris", true},
{"kdd_JapaneseVowels", false},
{"letter", true},
{"liver-disorders", true},
{"mfeat-factors", true},
};
string file_name;
string path;
string network_name;
tie(file_name, path, network_name) = parse_arguments(argc, argv);
if (datasets.find(file_name) == datasets.end()) {
cout << "Invalid file name: " << file_name << endl;
usage(argv[0]);
exit(1);
}
file_name = path + file_name + ".arff";
if (!file_exists(file_name)) {
cout << "Data File " << file_name << " does not exist" << endl;
usage(argv[0]);
exit(1);
}
network_name = path + network_name + ".net";
if (!file_exists(network_name)) {
cout << "Network File " << network_name << " does not exist" << endl;
usage(argv[0]);
exit(1);
}
return { file_name, network_name };
}
void build_network(bayesnet::Network& network, string network_name, map<string, int> maxes)
{
ifstream file(network_name);
string line;
while (getline(file, line)) {
if (line[0] == '#') {
continue;
}
istringstream iss(line);
string parent, child;
if (!(iss >> parent >> child)) {
break;
}
network.addNode(parent, maxes[parent]);
network.addNode(child, maxes[child]);
network.addEdge(parent, child);
}
file.close();
}
int main(int argc, char** argv)
{
string file_name, network_name;
tie(file_name, network_name) = get_options(argc, argv);
auto handler = ArffFiles();
handler.load(file_name);
// Get Dataset X, y
vector<mdlp::samples_t>& X = handler.getX();
mdlp::labels_t& y = handler.getY();
// Get className & Features
auto className = handler.getClassName();
vector<string> features;
for (auto feature : handler.getAttributes()) {
features.push_back(feature.first);
}
// Discretize Dataset
vector<mdlp::labels_t> Xd;
map<string, int> maxes;
tie(Xd, maxes) = discretize(X, y, features);
maxes[className] = *max_element(y.begin(), y.end()) + 1;
cout << "Features: ";
for (auto feature : features) {
cout << "[" << feature << "] ";
}
cout << endl;
cout << "Class name: " << className << endl;
// Build Network
auto network = bayesnet::Network(1.0);
build_network(network, network_name, maxes);
network.fit(Xd, y, features, className);
cout << "Hello, Bayesian Networks!" << endl;
showNodesInfo(network, className);
//showCPDS(network);
cout << "Score: " << network.score(Xd, y) << endl;
cout << "PyTorch version: " << TORCH_VERSION << endl;
cout << "BayesNet version: " << network.version() << endl;
unsigned int nthreads = std::thread::hardware_concurrency();
cout << "Computer has " << nthreads << " cores." << endl;
cout << "****************** First ******************" << endl;
auto metrics = bayesnet::Metrics(network.getSamples(), features, className, network.getClassNumStates());
cout << "conditionalEdgeWeight " << endl;
auto conditional = metrics.conditionalEdgeWeights();
cout << conditional << endl;
long m = features.size() + 1;
auto matrix = torch::from_blob(conditional.data(), { m, m });
cout << matrix << endl;
cout << "****************** Second ******************" << endl;
auto metrics2 = bayesnet::Metrics(Xd, y, features, className, network.getClassNumStates());
cout << "conditionalEdgeWeight " << endl;
auto conditional2 = metrics2.conditionalEdgeWeights();
cout << conditional2 << endl;
long m2 = features.size() + 1;
auto matrix2 = torch::from_blob(conditional2.data(), { m, m });
cout << matrix2 << endl;
return 0;
}