summaryrefslogtreecommitdiff
path: root/fuzzylite/fl/term/Function.h
blob: 14e3427efa8bf68cd686eea470a61e2307e59478 (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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
/*
 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.
 */

#ifndef FL_FUNCTION_H
#define FL_FUNCTION_H

#include "fl/term/Term.h"

#include <map>
#include <string>

namespace fl {

    class Engine;

    /**
      The Function class is a polynomial Term that represents a generic
      function @f$ f : x \mapsto f(x) @f$. Every Function object has a public
      key-value map, namely Function::variables, that links variable names to
      fl::scalar values, which are utilized to replace the variable names for
      their respective values in the given formula whenever the function
      @f$f@f$ is evaluated. Specifically, when the method
      Function::membership() is called, the name and value of the variable
      @f$x@f$ are automatically loaded into the map. Furthermore, if an Engine
      is given, the names of its InputVariable%s and OutputVariable%s will also
      be automatically loaded into the map linking to their respective input
      values and (previously defuzzified) output values. The
      Function::variables need to be manually loaded whenever variables other
      than @f$x@f$, input variables, and output variables, are expressed in the
      given formula, always having in mind that (a) the map replaces existing
      keys, and (b) the variable @f$x@f$, and input variables and output
      variables of an engine will automatically be replaced and will also take
      precedence over previously loaded variables.

      Besides the use of Function as a linguistic Term, it is also utilized to
      convert the text of the Antecedent of a Rule, expressed in infix
      notation, into postfix notation.


      @author Juan Rada-Vilela, Ph.D.
      @see Term
      @see Variable
      @see FunctionFactory
      @see Antecedent::load()
      @since 4.0
     */
    class FL_API Function : public Term {
    public:
        typedef scalar(*Unary)(scalar);
        typedef scalar(*Binary)(scalar, scalar);

        /**
          The Element class represents a single element in a formula, be that
          either a function or an operator. If the Element represents a
          function, the function can be Unary or Binary, that is, the function
          take one or two parameters (respectively). Else, if the Element
          represents an operator, the parameters to be defined are its `arity`,
          its `precedence`, and its `associativity`.
         */
        struct FL_API Element {

            /**
              Determines the type of the element
             */
            enum Type {
                Operator, Function
            };
            /**Name of the element*/
            std::string name;
            /**Description of the element*/
            std::string description;
            /**Type of the element*/
            Type type;
            /**Pointer to unary method*/
            Unary unary;
            /**Pointer to binary method*/
            Binary binary;
            /**Number of operands required*/
            int arity;
            /**Precedence of the element: clarifies which procedures should be
              performed first in a given mathematical expression
              (https://en.wikipedia.org/wiki/Order_of_operations)*/
            int precedence;
            /**Associativity of the element: determines how operators of the
              same precedence are grouped in the absence of parentheses
              (https://en.wikipedia.org/wiki/Operator_associativity)*/
            int associativity;
            Element(const std::string& name, const std::string& description, Type type);
            Element(const std::string& name, const std::string& description,
                    Type type, Unary unary, int precedence = 0, int associativity = -1);
            Element(const std::string& name, const std::string& description,
                    Type type, Binary binary, int precedence = 0, int associativity = -1);
            virtual ~Element();
            FL_DEFAULT_COPY_AND_MOVE(Element)

            /**
              Indicates whether the element is a Type::Operator
              @return whether the element is a Type::Operator
             */
            virtual bool isOperator() const;
            /**
              Indicates whether the element is a Type::Function
              @return whether the element is a Type::Function
             */
            virtual bool isFunction() const;
            /**
              Clones the element
              @return a clone of the element
             */
            virtual Element* clone() const;

            /**
              Returns a description of the element and its members
              @return a description of the element and its members
             */
            virtual std::string toString() const;

        };

        /**
          The Node class structures a binary tree by storing pointers to a left
          Node and a right Node, and storing its content as a
          Function::Element, the name of an InputVariable or OutputVariable, or
          a constant value.
         */
        struct FL_API Node {
            /**The node takes an operation or a function*/
            FL_unique_ptr<Element> element;
            /**The node can have an expression tree on the left*/
            FL_unique_ptr<Node> left;
            /**The node can have an expression tree on the right*/
            FL_unique_ptr<Node> right;
            /**The node can refer to a variable by name*/
            std::string variable;
            /**The node can take an arbitrary floating-point value*/
            scalar value;

            explicit Node(Element* element, Node* left = fl::null, Node* right = fl::null);
            explicit Node(const std::string& variable);
            explicit Node(scalar value);
            Node(const Node& source);
            Node& operator=(const Node& rhs);
            virtual ~Node();
            FL_DEFAULT_MOVE(Node)

            /**
              Evaluates the node and substitutes the variables therein for the
              values passed in the map. The expression tree is evaluated
              recursively.

              @param variables is a map of substitutions of variable names for
              fl::scalar%s

              @return a fl::scalar indicating the result of the evaluation of
              the node
             */
            virtual scalar evaluate(const std::map<std::string, scalar>*
                    variables = fl::null) const;

            /**
             Computes the size of the subtree under the given node. The complexity
             of calling this method is O(n).
             @param node is the root of the subtree, which is this node if
             fl::null is given
             @return the size of the subtree under the given node
             */
            virtual std::size_t treeSize(const Node* node = fl::null) const;

            /**
             Computes the size of the subtree under the given node whose elements
             are of the given type. The complexity of calling this method is O(n).
             @param type is the type of elements to account for
             @param node is the root of the subtree, which is this node if
             fl::null is given
             @return
             */
            virtual std::size_t treeSize(Element::Type type,
                    const Node* node = fl::null) const;

            /**
              Creates a clone of the node.
              @return a clone of the node
             */
            virtual Node* clone() const;

            /**
              Returns a string with the name of the element, the name of the
              variable, or the constant value, accordingly.
              @return a string with the name of the element, the name of the
              variable, or the constant value, accordingly.
             */
            virtual std::string toString() const;
            /**
              Returns a prefix representation of the expression tree under the
              given node
              @param node is the node to start the prefix representation from.
              If the node is `fl::null`, then the starting point is `this` node
              @return a prefix representation of the expression tree under the
              given node
             */
            virtual std::string toPrefix(const Node* node = fl::null) const;
            /**
              Returns an infix representation of the expression tree under the
              given node
              @param node is the node to start the infix representation from.
              If the node is `fl::null`, then the starting point is `this` node
              @return an infix representation of the expression tree under the
              given node
             */
            virtual std::string toInfix(const Node* node = fl::null) const;
            /**
              Returns a postfix representation of the expression tree under the
              given node
              @param node is the node to start the postfix representation from.
              If the node is `fl::null`, then the starting point is `this` node
              @return a postfix representation of the expression tree under the
              given node
             */
            virtual std::string toPostfix(const Node* node = fl::null) const;
        private:
            void copyFrom(const Node& source);
        };




        /******************************
         * Term
         ******************************/

    private:
        FL_unique_ptr<Node> _root;
        std::string _formula;
        const Engine* _engine;
    public:
        /**A map of variables and substitution values**/
        mutable std::map<std::string, scalar> variables;
        explicit Function(const std::string& name = "",
                const std::string& formula = "", const Engine* engine = fl::null);
        Function(const Function& other);
        Function& operator=(const Function& other);
        virtual ~Function() FL_IOVERRIDE;
        FL_DEFAULT_MOVE(Function)

        /**
          Creates a Function term with the given parameters
          @param name is the name of the term
          @param formula is the formula defining the membership function
          @param engine is the engine to which the Function can have access
          @return a Function term configured with the given parameters
          @throws fl::Exception if the formula has a syntax error
         */
        static Function* create(const std::string& name,
                const std::string& formula,
                const Engine* engine = fl::null);

        virtual Complexity complexity() const FL_IOVERRIDE;

        /**
          Computes the membership function value of @f$x@f$ at the root node.
          If the engine has been set, the current values of the input variables
          and output variables are added to the map of Function::variables. In
          addition, the variable @f$x@f$ will also be added to the map.
          @param x
          @return the membership function value of @f$x@f$ at the root node
         */
        virtual scalar membership(scalar x) const FL_IOVERRIDE;

        /**
          Computes the function value of this term using the given map of
          variable substitutions.
          @param variables is a map of substitution variables
          @return the function value of this term using the given map of
          variable substitutions.
         */
        virtual scalar evaluate(const std::map<std::string, scalar>* variables = fl::null) const;

        virtual std::string className() const FL_IOVERRIDE;
        /**
          Returns the parameters of the term as `formula`
          @return `formula`
         */
        virtual std::string parameters() const FL_IOVERRIDE;
        /**
          Configures the term with the parameters given as `formula`
          @param parameters as `formula`
         */
        virtual void configure(const std::string& parameters) FL_IOVERRIDE;

        /**
          Sets the formula of the function
          @param formula is the formula of the function
         */
        virtual void setFormula(const std::string& formula);
        /**
          Gets the formula of the function
          @return the formula of the function
         */
        virtual std::string getFormula() const;

        /**
          Sets the engine to which the formula can refer
          @param engine is the engine to which the formula can refer
         */
        virtual void setEngine(const Engine* engine);
        /**
          Gets the engine to which the formula can refer
          @return the engine to which the formula can refer
         */
        virtual const Engine* getEngine() const;

        /**
          Gets the root node of the expression tree defining the Function. The
          root is `fl::null` if the formula has not been loaded.
          @return the root node of the expression tree defining the Function,
          or `fl::null` if the formula has not been loaded
         */
        virtual Node* root() const;

        /**
          Indicates whether the formula is loaded
          @return whether the formula is loaded
         */
        virtual bool isLoaded() const;
        /**
          Unloads the formula and resets the map of substitution variables.
         */
        virtual void unload();
        /**
          Loads the current formula expressed in infix notation
         */
        virtual void load();
        /**
          Loads the given formula expressed in infix notation
          @param formula is the right-hand side of a mathematical equation
          @throws fl::Exception if the formula has syntax errors
         */
        virtual void load(const std::string& formula);
        /**
          Loads the given formula expressed in infix notation, and sets the
          engine holding the variables to which the formula refers.
          @param formula is the right-hand side of a mathematical equation
          expressed in infix notation
          @param engine is the engine to which the formula can refer
          @throws fl::Exception if the formula has syntax errors
         */
        virtual void load(const std::string& formula, const Engine* engine);
        /**
          Creates a node representing a binary expression tree from the given formula
          @param formula is the right-hand side of a mathematical equation
          expressed in infix notation
          @return a node representing a binary expression tree from the given formula
          @throws fl::Exception if the formula has syntax errors
         */
        virtual Node* parse(const std::string& formula);

        /**
          Translates the given formula to postfix notation
          @param formula is the right-hand side of a mathematical equation
          expressed in infix notation
          @return the formula represented in postfix notation
          @throws fl::Exception if the formula has syntax errors
         */
        virtual std::string toPostfix(const std::string& formula) const;

        /**
          Adds spaces to the formula to separate parentheses, commas and
          function operators such that these are treated as tokens when parsing
          the function.
          @param formula is the right-hand side of a mathematical equation
          expressed in infix notation
          @return the formula with spaces before and after parentheses, commas
          and function operators
         */
        virtual std::string space(const std::string& formula) const;

        virtual void updateReference(const Engine* engine) FL_IOVERRIDE;

        virtual Function* clone() const FL_IOVERRIDE;

        static Term* constructor();

    };
}
#endif  /* FL_FUNCTION_H */