diff options
Diffstat (limited to 'fuzzylite/src/imex/FldExporter.cpp')
-rw-r--r-- | fuzzylite/src/imex/FldExporter.cpp | 246 |
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"; |