1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-20 20:23:03 +02:00
vcmi/AI/FuzzyLite/FuzzyEngine.cpp
DjWarmonger 486cd4b001 - Fixed (common) issue when AI found neutral stacks infinitely strong
- Fixed non-fuzzy performance of some functions. Now AI really considers all options and uses multiple heroes, who don't spend their time wandering a lot.
2014-02-05 18:45:51 +00:00

333 lines
10 KiB
C++

/* Copyright 2010 Juan Rada-Vilela
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "FuzzyEngine.h"
#include "MamdaniRule.h"
#include "FuzzyExceptions.h"
#include "defs.h"
#include "StrOp.h"
#include "TriangularTerm.h"
#include "ShoulderTerm.h"
#include <iosfwd>
#include "FuzzyException.h"
namespace fl {
FuzzyEngine::FuzzyEngine() : _name(""),
_fuzzy_op(&FuzzyOperator::DefaultFuzzyOperator()),
_hedge_set(new HedgeSet) {
}
FuzzyEngine::FuzzyEngine(const std::string& name) : _name(name),
_fuzzy_op(&FuzzyOperator::DefaultFuzzyOperator()),
_hedge_set(new HedgeSet) {
}
FuzzyEngine::FuzzyEngine(const std::string& name, FuzzyOperator& fuzzy_operator) : _name(name),
_fuzzy_op(&fuzzy_operator),
_hedge_set(new HedgeSet) {
}
FuzzyEngine::~FuzzyEngine() {
reset();
delete _hedge_set;
}
void FuzzyEngine::setName(const std::string& name) {
this->_name = name;
}
std::string FuzzyEngine::name() const {
return this->_name;
}
void FuzzyEngine::process(bool clear) {
if (clear) {
for (int i = 0; i < numberOfOutputLVars(); ++i) {
outputLVar(i)->output().clear();
}
}
for (int i = 0; i < numberOfRuleBlocks(); ++i) {
ruleBlock(i)->fireRules();
}
}
void FuzzyEngine::process(int ruleblock, bool clear) {
if (clear) {
for (int i = 0; i < numberOfOutputLVars(); ++i) {
outputLVar(i)->output().clear();
}
}
ruleBlock(ruleblock)->fireRules();
}
void FuzzyEngine::reset() {
for (int i = numberOfRuleBlocks() - 1; i >= 0; --i) {
delete removeRuleBlock(i);
}
for (int i = numberOfInputLVars() - 1; i >= 0; --i) {
delete removeInputLVar(i);
}
for (int i = numberOfOutputLVars() - 1; i >= 0; --i) {
delete removeOutputLVar(i);
}
for (int i = hedgeSet().numberOfHedges() - 1; i >= 0; --i) {
delete hedgeSet().remove(i);
}
}
void FuzzyEngine::addInputLVar(InputLVar* lvar) {
_input_lvars.push_back(lvar);
}
InputLVar* FuzzyEngine::inputLVar(int index) const {
return _input_lvars[index];
}
InputLVar* FuzzyEngine::inputLVar(const std::string& name) const {
for (int i = 0; i < numberOfInputLVars(); ++i) {
if (inputLVar(i)->name() == name) {
return inputLVar(i);
}
}
return NULL;
}
InputLVar* FuzzyEngine::removeInputLVar(int index) {
InputLVar* result = inputLVar(index);
_input_lvars.erase(_input_lvars.begin() + index);
return result;
}
InputLVar* FuzzyEngine::removeInputLVar(const std::string& name) {
int index = indexOfInputLVar(name);
return index == -1 ? NULL : removeInputLVar(index);
}
int FuzzyEngine::indexOfInputLVar(const std::string& name) const {
for (int i = 0; i < numberOfInputLVars(); ++i) {
if (inputLVar(i)->name() == name) {
return i;
}
}
return -1;
}
int FuzzyEngine::numberOfInputLVars() const {
return _input_lvars.size();
}
void FuzzyEngine::addOutputLVar(OutputLVar* lvar) {
_output_lvars.push_back(lvar);
}
OutputLVar* FuzzyEngine::outputLVar(int index) const {
return _output_lvars[index];
}
OutputLVar* FuzzyEngine::outputLVar(const std::string& name) const {
for (int i = 0; i < numberOfOutputLVars(); ++i) {
if (outputLVar(i)->name() == name) {
return outputLVar(i);
}
}
return NULL;
}
OutputLVar* FuzzyEngine::removeOutputLVar(int index) {
OutputLVar* result = outputLVar(index);
_output_lvars.erase(_output_lvars.begin() + index);
return result;
}
OutputLVar* FuzzyEngine::removeOutputLVar(const std::string& name) {
int index = indexOfOutputLVar(name);
return index == -1 ? NULL : removeOutputLVar(index);
}
int FuzzyEngine::indexOfOutputLVar(const std::string& name) const {
for (int i = 0; i < numberOfOutputLVars(); ++i) {
if (outputLVar(i)->name() == name) {
return i;
}
}
return -1;
}
int FuzzyEngine::numberOfOutputLVars() const {
return _output_lvars.size();
}
HedgeSet& FuzzyEngine::hedgeSet() const {
return *this->_hedge_set;
}
void FuzzyEngine::setFuzzyOperator(FuzzyOperator& fuzzy_operator) {
this->_fuzzy_op = &fuzzy_operator;
}
FL_INLINE FuzzyOperator& FuzzyEngine::fuzzyOperator() const {
return *this->_fuzzy_op;
}
//RULES
void FuzzyEngine::addRuleBlock(RuleBlock* ruleblock) {
this->_rule_blocks.push_back(ruleblock);
}
RuleBlock* FuzzyEngine::removeRuleBlock(int index) {
RuleBlock* result = ruleBlock(index);
this->_rule_blocks.erase(this->_rule_blocks.begin() + index);
return result;
}
RuleBlock* FuzzyEngine::ruleBlock(int index) const {
return this->_rule_blocks[index];
}
RuleBlock* FuzzyEngine::ruleBlock(const std::string& name) const {
for (int i = 0; i < numberOfRuleBlocks(); ++i) {
if (ruleBlock(i)->name() == name) {
return ruleBlock(i);
}
}
return NULL;
}
int FuzzyEngine::numberOfRuleBlocks() const {
return this->_rule_blocks.size();
}
FL_INLINE void FuzzyEngine::setInput(const std::string& input_lvar, flScalar value) {
InputLVar* input = inputLVar(input_lvar);
if (!input) {
throw InvalidArgumentException(FL_AT, "Input variable <" + input_lvar + "> not registered in fuzzy engine");
}
input->setInput(value);
}
FL_INLINE flScalar FuzzyEngine::output(const std::string& output_lvar) const {
OutputLVar* output = outputLVar(output_lvar);
if (!output) {
throw InvalidArgumentException(FL_AT, "Output variable <" + output_lvar + "> not registered in fuzzy engine");
}
return output->output().defuzzify();
}
std::string FuzzyEngine::fuzzyOutput(const std::string& output_lvar) const {
flScalar defuzzified = output(output_lvar);
OutputLVar* output = outputLVar(output_lvar);
if (!output) {
throw InvalidArgumentException(FL_AT, "Output variable <" + output_lvar + "> not registered in fuzzy engine");
}
return output->fuzzify(defuzzified);
}
// void FuzzyEngine::fromString(const std::string& fcl) {
//
// enum eState {
// WAITING = 0, VAR_INPUT, FUZZIFY, DEFUZZIFY, RULE_BLOCK,
// };
// eState state = WAITING;
// std::string line;
// std::string token;
// std::istringstream is(fcl);
// std::string current_name;
// while (!is.eof()) {
// std::getline(is, line);
// StrOp::FindReplace(line, "(", " ( ");
// StrOp::FindReplace(line, ")", " ) ");
// while (StrOp::FindReplace(line, " ", " ") > 0) {
// //do nothing;
// }
// std::vector<std::string> tokens = StrOp::Tokenize(line, " ");
// if (tokens.size() == 0) continue;
// InputLVar* input = NULL;
// OutputLVar* output = NULL;
// switch (state) {
// case WAITING:
// current_name = tokens.size() > 0 ? tokens[1] : "";
// if (tokens[0] == "FUNCTION_BLOCK") setName(current_name);
// else if (tokens[0] == "VAR_INPUT") state = VAR_INPUT;
// else if (tokens[0] == "FUZZIFY") state = FUZZIFY;
// else if (tokens[0] == "DEFUZZIFY") state = DEFUZZIFY;
// else if (tokens[0] == "RULEBLOCK") state = RULE_BLOCK;
// break;
// case VAR_INPUT:
// if (tokens[0] == "END_VAR") state = WAITING;
// else addInputLVar(new InputLVar(tokens[0]));
// break;
// case FUZZIFY:
// if (tokens[0] == "TERM") {
// input = inputLVar(current_name);
// ParsingException::Assert(FL_AT, input, "Input <" << current_name << "> not registered");
//
// } else if (tokens[0] == "END_FUZZIFY") state = WAITING;
// break;
// case DEFUZZIFY:
// case RULE_BLOCK:
// }
// }
// }
std::string FuzzyEngine::toString() const {
std::stringstream ss;
ss << "FUNCTION_BLOCK " << name() << "\n\n";
ss << "VAR_INPUT\n";
for (int i = 0; i < numberOfInputLVars(); ++i) {
ss << inputLVar(i)->name() << ": REAL;\n";
}
ss << "END_VAR\n\n";
for (int i = 0; i < numberOfInputLVars(); ++i) {
ss << "FUZZIFY " << inputLVar(i)->name() << "\n";
for (int j = 0; j < inputLVar(i)->numberOfTerms(); ++j) {
ss << inputLVar(i)->term(j)->toString() << ";\n";
}
ss << "END_FUZZIFY\n\n";
}
ss << "VAR_OUTPUT\n";
for (int i = 0; i < numberOfOutputLVars(); ++i) {
ss << outputLVar(i)->name() << ": REAL\n";
}
ss << "END_VAR\n\n";
for (int i = 0; i < numberOfOutputLVars(); ++i) {
ss << "DEFUZZIFY " << outputLVar(i)->name() << "\n";
for (int j = 0; j < outputLVar(i)->numberOfTerms(); ++j) {
ss << outputLVar(i)->term(j)->toString() << ";\n";
}
ss << "END_DEFUZZIFY\n\n";
}
for (int i = 0; i < numberOfRuleBlocks(); ++i) {
ss << "Block " << i << " " << ruleBlock(i)->toString() << "\n\n";
}
ss << "END_FUNCTION_BLOCK";
return ss.str();
}
}