summaryrefslogtreecommitdiff
path: root/fuzzylite/src/activation/Threshold.cpp
blob: cd1f034be9296a516ae1cd49c49cefe74a2ff2a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 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 FuzzyLite License included with the software.

 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/activation/Threshold.h"

#include "fl/rule/RuleBlock.h"
#include "fl/rule/Rule.h"
#include "fl/Operation.h"

namespace fl {

    Threshold::Threshold(Comparison comparison, scalar threshold) : Activation(),
    _comparison(comparison), _value(threshold) { }

    Threshold::Threshold(const std::string& comparison, scalar threshold) : Activation(),
    _comparison(parseComparison(comparison)), _value(threshold) { }

    Threshold::~Threshold() { }

    std::string Threshold::className() const {
        return "Threshold";
    }

    std::string Threshold::parameters() const {
        std::ostringstream ss;
        ss << comparisonOperator() << " " << Op::str(getValue());
        return ss.str();
    }

    void Threshold::configure(const std::string& parameters) {
        if (parameters.empty()) return;
        std::vector<std::string> values = Op::split(parameters, " ");
        std::size_t required = 2;
        if (values.size() < required) {
            std::ostringstream ex;
            ex << "[configuration error] activation <" << className() << ">"
                    << " requires <" << required << "> parameters";
            throw Exception(ex.str(), FL_AT);
        }
        setComparison(parseComparison(values.at(0)));
        setValue(Op::toScalar(values.at(1)));
    }

    void Threshold::setComparison(Comparison comparison) {
        this->_comparison = comparison;
    }

    Threshold::Comparison Threshold::getComparison() const {
        return this->_comparison;
    }

    std::string Threshold::comparisonOperator() const {
        return comparisonOperator(getComparison());
    }

    std::string Threshold::comparisonOperator(Comparison comparison) const {
        switch (comparison) {
            case LessThan: return "<";
            case LessThanOrEqualTo: return "<=";
            case EqualTo: return "==";
            case NotEqualTo: return "!=";
            case GreaterThanOrEqualTo: return ">=";
            case GreaterThan: return ">";
            default: return "?";
        }
    }

    std::vector<std::string> Threshold::availableComparisonOperators() const {
        std::vector<std::string> result;
        result.push_back("<");
        result.push_back("<=");
        result.push_back("==");
        result.push_back("!=");
        result.push_back(">=");
        result.push_back(">");
        return result;
    }

    Threshold::Comparison Threshold::parseComparison(const std::string& name) const {
        if (name == "<") return LessThan;
        if (name == "<=") return LessThanOrEqualTo;
        if (name == "==") return EqualTo;
        if (name == "!=") return NotEqualTo;
        if (name == ">=") return GreaterThanOrEqualTo;
        if (name == ">") return GreaterThan;
        throw Exception("[syntax error] invalid threshold type by name <" + name + ">", FL_AT);
    }

    void Threshold::setValue(scalar value) {
        this->_value = value;
    }

    scalar Threshold::getValue() const {
        return this->_value;
    }

    void Threshold::setThreshold(Comparison comparison, scalar threshold) {
        setComparison(comparison);
        setValue(threshold);
    }

    void Threshold::setThreshold(const std::string& comparison, scalar value) {
        setComparison(parseComparison(comparison));
        setValue(value);
    }

    bool Threshold::activatesWith(scalar activationDegree) const {
        switch (getComparison()) {
            case LessThan: return Op::isLt(activationDegree, getValue());
            case LessThanOrEqualTo: return Op::isLE(activationDegree, getValue());
            case EqualTo: return Op::isEq(activationDegree, getValue());
            case NotEqualTo: return not Op::isEq(activationDegree, getValue());
            case GreaterThanOrEqualTo: return Op::isGE(activationDegree, getValue());
            case GreaterThan: return Op::isGt(activationDegree, getValue());
            default: return false;
        }
    }

    Complexity Threshold::complexity(const RuleBlock* ruleBlock) const {
        Complexity result;
        for (std::size_t i = 0; i < ruleBlock->rules().size(); ++i) {
            result.comparison(2);
            result += ruleBlock->rules().at(i)->complexity(
                    ruleBlock->getConjunction(), ruleBlock->getDisjunction(),
                    ruleBlock->getImplication());
        }
        return result;
    }

    void Threshold::activate(RuleBlock* ruleBlock) {
        FL_DBG("Activation: " << className() << " " << parameters());
        const TNorm* conjunction = ruleBlock->getConjunction();
        const SNorm* disjunction = ruleBlock->getDisjunction();
        const TNorm* implication = ruleBlock->getImplication();

        for (std::size_t i = 0; i < ruleBlock->numberOfRules(); ++i) {
            Rule* rule = ruleBlock->getRule(i);
            rule->deactivate();
            if (rule->isLoaded()) {
                scalar activationDegree = rule->activateWith(conjunction, disjunction);
                if (activatesWith(activationDegree)) {
                    rule->trigger(implication);
                }
            }
        }
    }

    Threshold* Threshold::clone() const {
        return new Threshold(*this);
    }

    Activation* Threshold::constructor() {
        return new Threshold;
    }

}