/*
Author: Juan Rada-Vilela, Ph.D.
Copyright (C) 2010-2014 FuzzyLite Limited
All rights reserved
This file is part of fuzzylite.
fuzzylite is free software: you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option)
any later version.
fuzzylite is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
for more details.
You should have received a copy of the GNU Lesser General Public License
along with fuzzylite. If not, see .
fuzzyliteâ„¢ is a trademark of FuzzyLite Limited.
*/
#include "fl/imex/FldExporter.h"
#include "fl/Engine.h"
#include "fl/Operation.h"
#include "fl/variable/Variable.h"
#include "fl/variable/InputVariable.h"
#include "fl/variable/OutputVariable.h"
#include
#include
#include
namespace fl {
FldExporter::FldExporter(const std::string& separator) : Exporter(),
_separator(separator), _exportHeaders(true),
_exportInputValues(true), _exportOutputValues(true) {
}
FldExporter::~FldExporter() {
}
std::string FldExporter::name() const {
return "FldExporter";
}
void FldExporter::setSeparator(const std::string& separator) {
this->_separator = separator;
}
std::string FldExporter::getSeparator() const {
return this->_separator;
}
void FldExporter::setExportHeader(bool exportHeaders) {
this->_exportHeaders = exportHeaders;
}
bool FldExporter::exportsHeader() const {
return this->_exportHeaders;
}
void FldExporter::setExportInputValues(bool exportInputValues) {
this->_exportInputValues = exportInputValues;
}
bool FldExporter::exportsInputValues() const {
return this->_exportInputValues;
}
void FldExporter::setExportOutputValues(bool exportOutputValues) {
this->_exportOutputValues = exportOutputValues;
}
bool FldExporter::exportsOutputValues() const {
return this->_exportOutputValues;
}
std::string FldExporter::header(const Engine* engine) const {
std::vector result;
if (_exportInputValues) {
for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
InputVariable* inputVariable = engine->getInputVariable(i);
result.push_back("@InputVariable: " + inputVariable->getName() + ";");
}
}
if (_exportOutputValues) {
for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
OutputVariable* outputVariable = engine->getOutputVariable(i);
result.push_back("@OutputVariable: " + outputVariable->getName() + ";");
}
}
return "#@Engine: " + engine->getName() + ";\n#" + Op::join(result, _separator);
}
std::string FldExporter::toString(const Engine* engine) const {
return toString(const_cast (engine), 1024);
}
std::string FldExporter::toString(Engine* engine, int maximumNumberOfResults) const {
std::ostringstream result;
write(engine, result, maximumNumberOfResults);
return result.str();
}
void FldExporter::toFile(const std::string& path, Engine* engine, int maximumNumberOfResults) const {
std::ofstream writer(path.c_str());
if (not writer.is_open()) {
throw fl::Exception("[file error] file <" + path + "> could not be created", FL_AT);
}
write(engine, writer, maximumNumberOfResults);
writer.close();
}
std::string FldExporter::toString(Engine* engine, const std::string& inputData) const {
std::ostringstream writer;
if (_exportHeaders) writer << header(engine) << "\n";
std::istringstream reader(inputData);
std::string line;
while (std::getline(reader, line)) {
line = Op::trim(line);
if (not line.empty() and line.at(0) == '#') continue; //comments are ignored, blank lines are retained
std::vector inputValues = parse(line);
write(engine, writer, inputValues);
writer.flush();
}
return writer.str();
}
void FldExporter::toFile(const std::string& path, Engine* engine, const std::string& inputData) const {
std::ofstream writer(path.c_str());
if (not writer.is_open()) {
throw fl::Exception("[file error] file <" + path + "> could not be created", FL_AT);
}
if (_exportHeaders) writer << header(engine) << "\n";
std::istringstream reader(inputData);
std::string line;
while (std::getline(reader, line)) {
line = Op::trim(line);
if (not line.empty() and line.at(0) == '#') continue; //comments are ignored, blank lines are retained
std::vector inputValues = parse(line);
write(engine, writer, inputValues);
writer.flush();
}
writer.close();
}
std::vector FldExporter::parse(const std::string& x) const {
std::vector inputValues;
if (not (x.empty() or x.at(0) == '#')) {
std::istringstream tokenizer(x);
std::string token;
while (tokenizer >> token)
inputValues.push_back(fl::Op::toScalar(token));
}
return inputValues;
}
void FldExporter::write(Engine* engine, std::ostream& writer, int maximum) const {
if (_exportHeaders) writer << header(engine) << "\n";
int resolution = -1 + (int) std::max(1.0, std::pow(
maximum, 1.0 / engine->numberOfInputVariables()));
std::vector sampleValues, minSampleValues, maxSampleValues;
for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
sampleValues.push_back(0);
minSampleValues.push_back(0);
maxSampleValues.push_back(resolution);
}
engine->restart();
bool overflow = false;
std::vector inputValues(engine->numberOfInputVariables());
while (not overflow) {
for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
InputVariable* inputVariable = engine->getInputVariable(i);
inputValues.at(i) = inputVariable->getMinimum()
+ sampleValues.at(i) * inputVariable->range() / std::max(1, resolution);
}
write(engine, writer, inputValues);
overflow = Op::increment(sampleValues, minSampleValues, maxSampleValues);
}
}
void FldExporter::write(Engine* engine, std::ostream& writer, std::istream& reader) const {
if (_exportHeaders) writer << header(engine) << "\n";
engine->restart();
std::string line;
int lineNumber = 0;
while (std::getline(reader, line)) {
++lineNumber;
std::vector inputValues = parse(Op::trim(line));
try {
write(engine, writer, inputValues);
} catch (fl::Exception& ex) {
ex.append(" writing line <" + Op::str(lineNumber) + ">");
throw;
}
}
}
void FldExporter::write(Engine* engine, std::ostream& writer, const std::vector& inputValues) const {
if (inputValues.empty()) {
writer << "\n";
return;
}
if (int(inputValues.size()) < engine->numberOfInputVariables()) {
std::ostringstream ex;
ex << "[export error] engine has <" << engine->numberOfInputVariables() << "> "
"input variables, but input data provides <" << inputValues.size() << "> values";
throw fl::Exception(ex.str(), FL_AT);
}
std::vector values;
for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
InputVariable* inputVariable = engine->getInputVariable(i);
scalar inputValue = inputVariable->isEnabled() ? inputValues.at(i) : fl::nan;
inputVariable->setInputValue(inputValue);
if (_exportInputValues) values.push_back(Op::str(inputValue));
}
engine->process();
for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
OutputVariable* outputVariable = engine->getOutputVariable(i);
outputVariable->defuzzify();
if (_exportOutputValues)
values.push_back(Op::str(outputVariable->getOutputValue()));
}
writer << Op::join(values, _separator) << "\n";
}
FldExporter* FldExporter::clone() const {
return new FldExporter(*this);
}
}