summaryrefslogtreecommitdiff
path: root/fuzzylite/src/imex/FldExporter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'fuzzylite/src/imex/FldExporter.cpp')
-rw-r--r--fuzzylite/src/imex/FldExporter.cpp246
1 files changed, 156 insertions, 90 deletions
diff --git a/fuzzylite/src/imex/FldExporter.cpp b/fuzzylite/src/imex/FldExporter.cpp
index 9064250..e25af1b 100644
--- a/fuzzylite/src/imex/FldExporter.cpp
+++ b/fuzzylite/src/imex/FldExporter.cpp
@@ -1,25 +1,17 @@
/*
- Author: Juan Rada-Vilela, Ph.D.
- Copyright (C) 2010-2014 FuzzyLite Limited
- All rights reserved
+ fuzzylite (R), a fuzzy logic control library in C++.
+ Copyright (C) 2010-2017 FuzzyLite Limited. All rights reserved.
+ Author: Juan Rada-Vilela, Ph.D. <jcrada@fuzzylite.com>
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.
+ the terms of the FuzzyLite License included with the software.
- 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 <http://www.gnu.org/licenses/>.
-
- fuzzyliteâ„¢ is a trademark of FuzzyLite Limited.
+ You should have received a copy of the FuzzyLite License along with
+ fuzzylite. If not, see <http://www.fuzzylite.com/license/>.
+ fuzzylite is a registered trademark of FuzzyLite Limited.
*/
#include "fl/imex/FldExporter.h"
@@ -30,20 +22,15 @@
#include "fl/variable/InputVariable.h"
#include "fl/variable/OutputVariable.h"
-#include <cmath>
#include <fstream>
-#include <vector>
namespace fl {
FldExporter::FldExporter(const std::string& separator) : Exporter(),
_separator(separator), _exportHeaders(true),
- _exportInputValues(true), _exportOutputValues(true) {
-
- }
+ _exportInputValues(true), _exportOutputValues(true) { }
- FldExporter::~FldExporter() {
- }
+ FldExporter::~FldExporter() { }
std::string FldExporter::name() const {
return "FldExporter";
@@ -84,156 +71,235 @@ namespace fl {
std::string FldExporter::header(const Engine* engine) const {
std::vector<std::string> result;
if (_exportInputValues) {
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
InputVariable* inputVariable = engine->getInputVariable(i);
- result.push_back("@InputVariable: " + inputVariable->getName() + ";");
+ result.push_back(inputVariable->getName());
}
}
if (_exportOutputValues) {
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
OutputVariable* outputVariable = engine->getOutputVariable(i);
- result.push_back("@OutputVariable: " + outputVariable->getName() + ";");
+ result.push_back(outputVariable->getName());
}
}
- return "#@Engine: " + engine->getName() + ";\n#" + Op::join(result, _separator);
+ return Op::join(result, _separator);
}
std::string FldExporter::toString(const Engine* engine) const {
- return toString(const_cast<Engine*> (engine), 1024);
+ return toString(const_cast<Engine*> (engine), 1024, AllVariables);
}
- std::string FldExporter::toString(Engine* engine, int maximumNumberOfResults) const {
- std::ostringstream result;
- write(engine, result, maximumNumberOfResults);
- return result.str();
+ std::string FldExporter::toString(Engine* engine, int values, ScopeOfValues scope) const {
+ return toString(engine, values, scope, engine->inputVariables());
}
- 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, int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const {
+ std::ostringstream result;
+ write(engine, result, values, scope, activeVariables);
+ return result.str();
}
- std::string FldExporter::toString(Engine* engine, const std::string& inputData) const {
+ std::string FldExporter::toString(Engine* engine, std::istream& reader) const {
std::ostringstream writer;
if (_exportHeaders) writer << header(engine) << "\n";
- std::istringstream reader(inputData);
std::string line;
+ int lineNumber = 0;
while (std::getline(reader, line)) {
+ ++lineNumber;
line = Op::trim(line);
- if (not line.empty() and line.at(0) == '#') continue; //comments are ignored, blank lines are retained
- std::vector<scalar> inputValues = parse(line);
- write(engine, writer, inputValues);
- writer.flush();
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
+
+ write(engine, writer, inputValues, engine->inputVariables());
}
return writer.str();
}
- void FldExporter::toFile(const std::string& path, Engine* engine, const std::string& inputData) const {
+ void FldExporter::toFile(const std::string& path, Engine* engine, int values, ScopeOfValues scope) const {
+ toFile(path, engine, values, scope, engine->inputVariables());
+ }
+
+ void FldExporter::toFile(const std::string& path, Engine* engine, int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) 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);
+ throw Exception("[file error] file <" + path + "> could not be created", FL_AT);
+ }
+ write(engine, writer, values, scope, activeVariables);
+ writer.close();
+ }
+
+ void FldExporter::toFile(const std::string& path, Engine* engine, std::istream& reader) const {
+ std::ofstream writer(path.c_str());
+ if (not writer.is_open()) {
+ throw Exception("[file error] file <" + path + "> could not be created", FL_AT);
}
if (_exportHeaders) writer << header(engine) << "\n";
- std::istringstream reader(inputData);
+
std::string line;
+ int lineNumber = 0;
while (std::getline(reader, line)) {
+ ++lineNumber;
line = Op::trim(line);
- if (not line.empty() and line.at(0) == '#') continue; //comments are ignored, blank lines are retained
- std::vector<scalar> inputValues = parse(line);
- write(engine, writer, inputValues);
- writer.flush();
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
+
+ write(engine, writer, inputValues, engine->inputVariables());
}
writer.close();
}
- std::vector<scalar> FldExporter::parse(const std::string& x) const {
+ std::vector<scalar> FldExporter::parse(const std::string& values) const {
std::vector<scalar> 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));
+ if (not (values.empty() or values.at(0) == '#')) {
+ inputValues = Op::toScalars(values);
}
return inputValues;
}
- void FldExporter::write(Engine* engine, std::ostream& writer, int maximum) const {
+ void FldExporter::write(Engine* engine, std::ostream& writer, int values, ScopeOfValues scope) const {
+ write(engine, writer, values, scope, engine->inputVariables());
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ int values, ScopeOfValues scope,
+ const std::vector<InputVariable*>& activeVariables) const {
if (_exportHeaders) writer << header(engine) << "\n";
- int resolution = -1 + (int) std::max(1.0, std::pow(
- maximum, 1.0 / engine->numberOfInputVariables()));
+ if (activeVariables.size() != engine->inputVariables().size()) {
+ std::ostringstream ex;
+ ex << "[exporter error] number of active variables "
+ "<" << activeVariables.size() << ">"
+ << "must match the number of input variables in the engine "
+ "<" << engine->inputVariables().size() << ">";
+ throw Exception(ex.str(), FL_AT);
+ }
+
+ int resolution;
+ if (scope == AllVariables)
+ resolution = -1 + (int) std::max(1.0, std::pow(
+ values, 1.0 / engine->numberOfInputVariables()));
+ else //if (scope == EachVariable)
+ resolution = values - 1;
+
std::vector<int> sampleValues, minSampleValues, maxSampleValues;
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfInputVariables(); ++i) {
sampleValues.push_back(0);
minSampleValues.push_back(0);
- maxSampleValues.push_back(resolution);
+ if (engine->inputVariables().at(i) == activeVariables.at(i))
+ maxSampleValues.push_back(resolution);
+ else maxSampleValues.push_back(0);
}
- engine->restart();
-
- bool overflow = false;
std::vector<scalar> inputValues(engine->numberOfInputVariables());
- while (not overflow) {
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ do {
+ for (std::size_t 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);
+ if (inputVariable == activeVariables.at(i)) {
+ inputValues.at(i) = inputVariable->getMinimum()
+ + sampleValues.at(i) * inputVariable->range() / std::max(1, resolution);
+ } else {
+ inputValues.at(i) = inputVariable->getValue();
+ }
}
- write(engine, writer, inputValues);
- overflow = Op::increment(sampleValues, minSampleValues, maxSampleValues);
- }
+ write(engine, writer, inputValues, activeVariables);
+ } while (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;
+ std::size_t lineNumber = 0;
while (std::getline(reader, line)) {
++lineNumber;
- std::vector<scalar> inputValues = parse(Op::trim(line));
+ line = Op::trim(line);
+ if (not line.empty() and line.at(0) == '#')
+ continue; //comments are ignored, blank lines are retained
+ std::vector<scalar> inputValues;
+ if (lineNumber == 1) { //automatic detection of header.
+ try {
+ inputValues = parse(line);
+ } catch (std::exception&) {
+ continue;
+ }
+ } else {
+ inputValues = parse(line);
+ }
try {
- write(engine, writer, inputValues);
- } catch (fl::Exception& ex) {
+ write(engine, writer, inputValues, engine->inputVariables());
+ } catch (Exception& ex) {
ex.append(" writing line <" + Op::str(lineNumber) + ">");
throw;
}
}
}
- void FldExporter::write(Engine* engine, std::ostream& writer, const std::vector<scalar>& inputValues) const {
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ const std::vector<scalar>& inputValues) const {
+ write(engine, writer, inputValues, engine->inputVariables());
+ }
+
+ void FldExporter::write(Engine* engine, std::ostream& writer,
+ const std::vector<scalar>& inputValues,
+ const std::vector<InputVariable*>& activeVariables) const {
if (inputValues.empty()) {
writer << "\n";
return;
}
- if (int(inputValues.size()) < engine->numberOfInputVariables()) {
+ if (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);
+ throw Exception(ex.str(), FL_AT);
+ }
+ if (activeVariables.size() != engine->inputVariables().size()) {
+ std::ostringstream ex;
+ ex << "[exporter error] number of active variables <" << activeVariables.size() << "> "
+ "must match the number of input variables in the engine <" << engine->inputVariables().size() << ">";
+ throw Exception(ex.str(), FL_AT);
}
- std::vector<std::string> values;
- for (int i = 0; i < engine->numberOfInputVariables(); ++i) {
+ std::vector<scalar> values;
+ for (std::size_t 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));
+ scalar inputValue;
+ if (inputVariable == activeVariables.at(i)) {
+ inputValue = inputValues.at(i);
+ } else {
+ inputValue = inputVariable->getValue();
+ }
+ inputVariable->setValue(inputValue);
+ if (_exportInputValues) values.push_back(inputValue);
}
engine->process();
- for (int i = 0; i < engine->numberOfOutputVariables(); ++i) {
+ for (std::size_t i = 0; i < engine->numberOfOutputVariables(); ++i) {
OutputVariable* outputVariable = engine->getOutputVariable(i);
- outputVariable->defuzzify();
if (_exportOutputValues)
- values.push_back(Op::str(outputVariable->getOutputValue()));
+ values.push_back(outputVariable->getValue());
}
writer << Op::join(values, _separator) << "\n";