/* 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/Operation.h" #include "fl/defuzzifier/Defuzzifier.h" #include "fl/norm/Norm.h" #include "fl/norm/SNorm.h" #include "fl/norm/TNorm.h" #include #include #include #include namespace fl { template T Operation::min(T a, T b) { if (isNaN(a)) return b; if (isNaN(b)) return a; return a < b ? a : b; } template FL_API scalar Operation::min(scalar a, scalar b); template FL_API int Operation::min(int a, int b); template T Operation::max(T a, T b) { if (isNaN(a)) return b; if (isNaN(b)) return a; return a > b ? a : b; } template FL_API scalar Operation::max(scalar a, scalar b); template FL_API int Operation::max(int a, int b); template T Operation::bound(T x, T min, T max) { if (isGt(x, max)) return max; if (isLt(x, min)) return min; return x; } template FL_API scalar Operation::bound(scalar x, scalar min, scalar max); template FL_API int Operation::bound(int x, int min, int max); template bool Operation::in(T x, T min, T max, bool geq, bool leq) { bool left = geq ? isGE(x, min) : isGt(x, min); bool right = leq ? isLE(x, max) : isLt(x, max); return (left and right); } template FL_API bool Operation::in(scalar x, scalar min, scalar max, bool geq, bool leq); template FL_API bool Operation::in(int x, int min, int max, bool geq, bool leq); template bool Operation::isInf(T x) { return std::abs(x) == fl::inf; } template FL_API bool Operation::isInf(int x); template FL_API bool Operation::isInf(scalar x); template bool Operation::isNaN(T x) { return not (x == x); } template FL_API bool Operation::isNaN(int x); template FL_API bool Operation::isNaN(scalar x); template bool Operation::isFinite(T x) { return not (isNaN(x) or isInf(x)); } template FL_API bool Operation::isFinite(int x); template FL_API bool Operation::isFinite(scalar x); bool Operation::isLt(scalar a, scalar b, scalar macheps) { return not isEq(a, b, macheps) and a < b; } bool Operation::isLE(scalar a, scalar b, scalar macheps) { return isEq(a, b, macheps) or a < b; } bool Operation::isEq(scalar a, scalar b, scalar macheps) { return a == b or std::fabs(a - b) < macheps or (isNaN(a) and isNaN(b)); } bool Operation::isGt(scalar a, scalar b, scalar macheps) { return not isEq(a, b, macheps) and a > b; } bool Operation::isGE(scalar a, scalar b, scalar macheps) { return isEq(a, b, macheps) or a > b; } scalar Operation::scale(scalar x, scalar fromMin, scalar fromMax, scalar toMin, scalar toMax, bool bounded) { scalar result = (toMax - toMin) / (fromMax - fromMin) * (x - fromMin) + toMin; return bounded ? fl::Op::bound(result, toMin, toMax) : result; } scalar Operation::add(scalar a, scalar b) { return a + b; } scalar Operation::subtract(scalar a, scalar b) { return a - b; } scalar Operation::multiply(scalar a, scalar b) { return a * b; } scalar Operation::divide(scalar a, scalar b) { return a / b; } scalar Operation::modulo(scalar a, scalar b) { return fmod(a, b); } scalar Operation::logicalAnd(scalar a, scalar b) { return (isEq(a, 1.0) and isEq(b, 1.0)) ? 1.0 : 0.0; } scalar Operation::logicalOr(scalar a, scalar b) { return (isEq(a, 1.0) or isEq(b, 1.0)) ? 1.0 : 0.0; } scalar Operation::logicalNot(scalar a) { return isEq(a, 1.0) ? 0.0 : 1.0; } scalar Operation::negate(scalar a) { return -a; } scalar Operation::round(scalar x) { return (x > 0.0) ? std::floor(x + 0.5) : std::ceil(x - 0.5); } scalar Operation::gt(scalar a, scalar b) { return isGt(a, b); } scalar Operation::ge(scalar a, scalar b) { return isGE(a, b); } scalar Operation::eq(scalar a, scalar b) { return isEq(a, b); } scalar Operation::neq(scalar a, scalar b) { return not isEq(a, b); } scalar Operation::le(scalar a, scalar b) { return isLE(a, b); } scalar Operation::lt(scalar a, scalar b) { return isLt(a, b); } bool Operation::increment(std::vector& x, std::vector& min, std::vector& max) { return increment(x, (int) x.size() - 1, min, max); } bool Operation::increment(std::vector& x, int position, std::vector& min, std::vector& max) { if (x.empty() or position < 0) return true; bool overflow = false; if (x.at(position) < max.at(position)) { ++x.at(position); } else { overflow = (position == 0); x.at(position) = min.at(position); --position; if (position >= 0) { overflow = increment(x, position, min, max); } } return overflow; } double Operation::mean(const std::vector& x) { if (x.size() == 0) return fl::nan; scalar sum = 0.0; for (std::size_t i = 0; i < x.size(); ++i) sum += x.at(i); return sum / x.size(); } double Operation::standardDeviation(const std::vector& x) { if (x.size() <= 1) return 0.0; return standardDeviation(x, mean(x)); } double Operation::standardDeviation(const std::vector& x, scalar mean) { if (x.size() <= 1) return 0.0; return std::sqrt(variance(x, mean)); } double Operation::variance(const std::vector& x) { if (x.size() <= 1) return 0.0; return variance(x, mean(x)); } double Operation::variance(const std::vector& x, scalar mean) { if (x.size() <= 1) return 0.0; scalar result = 0; for (std::size_t i = 0; i < x.size(); ++i) { result += (x.at(i) - mean) * (x.at(i) - mean); } result /= -1 + x.size(); return result; } //Text Operations: std::string Operation::validName(const std::string& name) { if (trim(name).empty()) return "unnamed"; std::ostringstream ss; for (std::size_t i = 0; i < name.length(); ++i) { char c = name[i]; if (c == '_' or c == '.' or isalnum(c)) { ss << c; } } return ss.str(); } int Operation::isValidForName(int character) { return character == '_' or character == '.' or isalnum(character); } std::string Operation::findReplace(const std::string& str, const std::string& find, const std::string& replace, bool replaceAll) { std::ostringstream result; std::size_t fromIndex = 0, nextIndex; do { nextIndex = str.find(find, fromIndex); result << str.substr(fromIndex, nextIndex - fromIndex); if (nextIndex != std::string::npos) result << replace; fromIndex = nextIndex + find.size(); } while (replaceAll and nextIndex != std::string::npos); return result.str(); } std::vector Operation::split(const std::string& str, const std::string& delimiter, bool ignoreEmpty) { std::vector result; if (str.empty() or delimiter.empty()) { result.push_back(str); return result; } std::string::const_iterator position = str.begin(), next = str.begin(); while (next != str.end()) { next = std::search(position, str.end(), delimiter.begin(), delimiter.end()); std::string token(position, next); if (not (token.empty() and ignoreEmpty)) { result.push_back(token); } if (next != str.end()) { position = next + delimiter.size(); } } return result; } std::string Operation::trim(const std::string& text) { if (text.empty()) return text; if (not (std::isspace(text.at(0)) or std::isspace(text.at(text.size() - 1)))) return text; int start = 0, end = text.size() - 1; while (start <= end and std::isspace(text.at(start))) { ++start; } while (end >= start and std::isspace(text.at(end))) { --end; } int length = end - start + 1; if (length <= 0) return ""; return text.substr(start, length); } std::string Operation::format(const std::string& text, int matchesChar(int), const std::string& replacement) { std::ostringstream ss; std::string::const_iterator it = text.begin(); while (it != text.end()) { if (matchesChar(*it)) { ss << *it; } else { ss << replacement; } ++it; } return ss.str(); } scalar Operation::toScalar(const std::string& x) { std::istringstream iss(x); scalar result; iss >> result; char strict; if (not (iss.fail() or iss.get(strict))) return result; std::ostringstream nan, pInf, nInf; nan << fl::nan; pInf << fl::inf; nInf << (-fl::inf); if (x == nan.str() or x == "nan") return fl::nan; if (x == pInf.str() or x == "inf") return fl::inf; if (x == nInf.str() or x == "-inf") return -fl::inf; std::ostringstream ex; ex << "[conversion error] from <" << x << "> to scalar"; throw fl::Exception(ex.str(), FL_AT); } scalar Operation::toScalar(const std::string& x, scalar alternative) FL_INOEXCEPT { std::istringstream iss(x); scalar result; iss >> result; char strict; if (not (iss.fail() or iss.get(strict))) return result; std::ostringstream nan, pInf, nInf; nan << fl::nan; pInf << fl::inf; nInf << (-fl::inf); if (x == nan.str() or x == "nan") return fl::nan; if (x == pInf.str() or x == "inf") return fl::inf; if (x == nInf.str() or x == "-inf") return -fl::inf; return alternative; } bool Operation::isNumeric(const std::string& x) { try { fl::Op::toScalar(x); return true; } catch (std::exception& ex) { (void) ex; return false; } } template std::string Operation::str(T x, int decimals) { std::ostringstream ss; ss << std::setprecision(decimals) << std::fixed; if (fl::Op::isNaN(x)) { ss << "nan"; } else if (fl::Op::isInf(x)) { ss << (fl::Op::isLt(x, 0.0) ? "-inf" : "inf"); } else if (fl::Op::isEq(x, 0.0)) { ss << 0.0; } else ss << x; return ss.str(); } template FL_API std::string Operation::str(int x, int precision); template FL_API std::string Operation::str(scalar x, int precision); template <> FL_API std::string Operation::str(const std::string& x, int precision) { (void) precision; return x; } template std::string Operation::join(const std::vector& x, const std::string& separator) { std::ostringstream ss; for (std::size_t i = 0; i < x.size(); ++i) { ss << str(x.at(i)); if (i + 1 < x.size()) ss << separator; } return ss.str(); } template FL_API std::string Operation::join(const std::vector& x, const std::string& separator); template FL_API std::string Operation::join(const std::vector& x, const std::string& separator); template <> FL_API std::string Operation::join(const std::vector& x, const std::string& separator) { std::ostringstream ss; for (std::size_t i = 0; i < x.size(); ++i) { ss << x.at(i); if (i + 1 < x.size()) ss << separator; } return ss.str(); } template std::string Operation::join(int items, const std::string& separator, T first, ...) { std::ostringstream ss; ss << str(first); if (items > 1) ss << separator; va_list args; va_start(args, first); for (int i = 0; i < items - 1; ++i) { ss << str(va_arg(args, T)); if (i + 1 < items - 1) ss << separator; } va_end(args); return ss.str(); } template FL_API std::string Operation::join(int items, const std::string& separator, int first, ...); template FL_API std::string Operation::join(int items, const std::string& separator, double first, ...); template <> FL_API std::string Operation::join(int items, const std::string& separator, float first, ...) { std::ostringstream ss; ss << str(first); if (items > 1) ss << separator; va_list args; va_start(args, first); for (int i = 0; i < items - 1; ++i) { ss << str(va_arg(args, double)); //automatic promotion if (i + 1 < items - 1) ss << separator; } va_end(args); return ss.str(); } template <> FL_API std::string Operation::join(int items, const std::string& separator, const char* first, ...) { std::ostringstream ss; ss << first; if (items > 1) ss << separator; va_list args; va_start(args, first); for (int i = 0; i < items - 1; ++i) { ss << va_arg(args, const char*); if (i + 1 < items - 1) ss << separator; } va_end(args); return ss.str(); } }