/*
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();
}
}