Simpful: A User-Friendly Python Library for Fuzzy Logic
- 10.2991/ijcis.d.201012.002How to use a DOI?
- Decision support; Fuzzy logic; Fuzzy networks; Modeling and control; Open- source software; Python library
Many researchers have used fuzzy set theory and fuzzy logic in a variety of applications related to computer science and engineering, given the capability of fuzzy inference systems to deal with uncertainty, represent vague concepts, and connect human language to numerical data. In this work we propose Simpful, a general-purpose and user-friendly Python library designed to facilitate the definition, analysis, and interpretation of fuzzy inference systems. Simpful provides a lightweight Application Programming Interface that allows to intuitively define fuzzy sets and fuzzy rules, and to perform fuzzy inference. Worthy of note, in Simpful the fuzzy rules are specified by means of strings of text written in natural language. We provide here some practical examples to show that Simpful represents a valuable addition to the open-source software that supports fuzzy reasoning.
- © 2020 The Authors. Published by Atlantis Press B.V.
- Open Access
- This is an open access article distributed under the CC BY-NC 4.0 license (http://creativecommons.org/licenses/by-nc/4.0/).
Fuzzy set theory and fuzzy logic [1,2] are extensions of classic set theory and logic, which have been largely used in computer science and engineering. The ability of fuzzy inference systems (FISs)  to deal with uncertainty, represent vague concepts, and connect human language to numerical data, allowed fuzzy logic to be successfully exploited in different contexts [3,4], and in knowledge- or data-driven applications , as in the case of decision-making , modeling and control [7,8], classification, and regression problems [9–11].
The success of fuzzy reasoning led to the development of several methods and software tools involving fuzzy sets or FISs, usually aimed at specific applications . However, general-purpose software libraries and toolboxes capable of handling fuzzy sets and/or fuzzy logic are limited in number and scope, and they are often outdated or not open-source. Reasons for this shortcoming might be the difficulty in dealing with the complex objects required by fuzzy reasoning (i.e., fuzzy sets, fuzzy rules, and natural language), and the high number of existing types of FISs .
To overcome these limitations, here we propose Simpful, a user-friendly Python library designed to define FISs for any purpose. Simpful provides a lightweight Application Programming Interface (API) for fuzzy reasoning, including a set of classes and methods to intuitively define fuzzy sets and fuzzy rules, and to perform fuzzy inference. A noticeable feature of Simpful is that fuzzy rules can be constructed by means of strings of text written in natural language, thus simplifying the definition of fuzzy rule bases.
To show the usefulness and the advantages of Simpful, we provide three practical applications, related to the definition of a Mamdani and Takagi-Sugeno FIS for the tipping problem, a FIS for a clinical decision support system for septic patients, and a dynamic fuzzy model (DFM) of a biochemical system. The first two examples illustrate how Simpful can be used to easily define the membership functions and a fuzzy rule base, and how it embeds the execution of fuzzy inference. The third example shows how Simpful can be exploited to model and simulate the dynamics of complex systems [25,26], by creating fuzzy networks (FNs) , i.e., networks where nodes represent linguistic variables, and the connections between them represent interactions in the form of fuzzy rule outputs fed as variable inputs to a downstream linguistic variable. These networks can be defined with arbitrary topologies, including cycles and feedback loops, to describe the interactions existing in complex systems [27–30].
The paper is structured as follows: In Section 2 we provide a survey of the available software for the design of FISs, while in Section 3 we describe the implementation details of Simpful. In Section 4 we describe the three examples of application of Simpful. Finally, in Section 5 we draw some final remarks and provide insights on future developments of the library.
2. RELATED WORK
A detailed overview of the software tools that deal with fuzzy logic and fuzzy reasoning can be found in Ref. . In this section, we restrict our discussion to general-purpose software (see Table 1).
|FuzzyLite ||C++||2017||A collection of C++ libraries designed for fuzzy control, compatible with the FCL standard|
|FisPro ||C++||2019||A general-purpose software provided with a GUI, designed to facilitate the learning of fuzzy inference systems from data|
|Juzzy ||Java||2013||A Java based toolkit, implementing type-2 fuzzy reasoning|
|JFML ||Java||2018||A Java library implementing the FML standard|
|FuzzyR ||R||2019||An R toolkit, provided with a GUI, for the design of type-1 and type-2 fuzzy inference systems|
|Fuzzy Toolbox for Matlab ||Matlab||1994||General-purpose toolbox implemented in the Matlab environment|
|Fuzzy Logic Toolbox ||Matlab||2020||Commercially distributed toolbox, provided with a GUI and available inside the Matlab environment|
|PyFuzzy ||Python 2||2014||A Python 2 library, compatible with the FCL standard. The development of the library was discontinued and Python 2 is no longer officially supported. This library depends on the ANTLR 3 runtime|
|Fuzzylab ||Python 3||2019||Python library based on the Octave Fuzzy Logic Toolkit|
|Scikit-Fuzzy ||Python 3||2019||General-purpose API meant to work in the scipy stack, offering classes and methods to support the definition of fuzzy systems|
|Py4JFML ||Python 3||2019||A Python wrapper for the JFML java library|
Note: FIS, fuzzy inference system; FCL, Fuzzy Control Language; GUI, graphical user interface; FML, Fuzzy Markup Language; API, Application Programming Interface.
Software for the design of FISs.
Matlab is one of the most popular environments used to implement fuzzy logic tools . More recently, Mathworks has introduced a Fuzzy Logic Toolbox  that is still supported by the company, and offers a variety of functions to manage many systems involving fuzzy logic. Additional extensions and new software were also presented in the past (e.g., in Ref. ) to address the needs of different fuzzy logic communities. However, Matlab has the drawback of being commercially distributed only, thus open-source alternatives were developed by the scientific community. At present, most of these open-source software are designed for specific applications only, whereas others are often outdated or not continually maintained.
PyFuzzy  was the first general-purpose library to design FISs using the Python programming language (version 2.7). It is dependent on the ANTLR 3 runtime. PyFuzzy allows to manage all the entities needed to construct FISs and to create numerous types of fuzzy sets. It also supports the export and sharing of FISs by means of the Fuzzy Control Language (FCL) files. FCL files implement the old standard IEC 61131 (IEC61131-7) , which was designed for fuzzy control applications and remained for many years the only de facto standard to represent FISs. Despite its completeness, PyFuzzy is now outdated and not maintained anymore, and Python 2 is no longer officially supported.
To date, the software developed using Python 3 includes Scikit-Fuzzy  and Fuzzylab . Scikit-Fuzzy is a fuzzy logic API meant to work in the scipy stack , which offers functions and classes to support the modeling of fuzzy systems. Fuzzylab is a recently published Python 3 library, based on the Octave Fuzzy Logic Toolkit, designed for the creation of logic controllers. Both these libraries do not support the definition of custom membership functions (providing only pre-implemented shapes), nor Takagi-Sugeno inference systems of arbitrary order. At present, Scikit-Fuzzy supports only Mamdani inference, while Fuzzylab supports Mamdani and 0-order Takagi-Sugeno inference systems. Moreover, both libraries do not provide an interface close to natural language for the definition of FISs. For example, neither Fuzzylab nor Scikit-Fuzzy allow to define fuzzy rules as strings of text written in natural language. Fuzzylab employs a matrix that needs to be input by the user to define the full rule base. In its main API, Scikit-Fuzzy adopts the prefix notation (i.e., operators precede the operands) to define the antecedents of rules. A later developed API (designed to implement control systems) is also available, but it requires to manipulate linguistic variable objects and to index them by means of linguistic terms in order to define a fuzzy rule.
Most of the recent open-source software for fuzzy logic are aimed at machine learning, classification and regression analysis, or decision support systems. Among the most popular, one can find FuzzyR , a general-purpose toolkit for fuzzy reasoning, implemented in R and supporting type-1 and type-2 FISs; FuzzyLite , a collection of C++ libraries designed for fuzzy control; Fispro , a C++ software provided with a graphical user interface (GUI), designed for data-driven applications of FISs and their automatic learning from a dataset; Juzzy , a Java based toolkit for handling type-2 fuzzy sets, and JT2FIS , a Java class library for the definition of interval type-2 FISs. One of the most recent and interesting implementations in the fuzzy community is represented by the JFML library , the only open-source library (implemented in Java) incorporating the most recently developed standard for representing FISs, the IEEE 1855-2016 standard , which defines a new W3C eXtensible Markup Language named Fuzzy Markup Language (FML) . Notably, a Python wrapper for JFML was also released , allowing the definition of FML-compliant FISs by means of Python scripts and of the JFML library. However, it should be noted that this solution requires the Py4J framework , which is needed for the Python interpreter to dynamically access Java objects in a Java Virtual Machine.
An overview of the features supported by the abovementioned software for the design of FISs can be found in Table 2. Excluding the outdated and discontinued PyFuzzy, a general-purpose, open-source, and intuitive Python library is nowadays still missing, prompting the development of Simpful to overcome the limitations of the existing software.
|Name||Mamdani||Zero-order Takagi–Sugeno||First-order Takagi–Sugeno||Higher Order Takagi–Sugeno||Open Source|
|Fuzzy Toolbox for Matlab |
|Fuzzy Logic Toolbox |
Note: FIS, fuzzy inference system; FML, Fuzzy Markup Language.
Features supported by the available software for the design of FISs.
3. SOFTWARE DESCRIPTION
Definition of polygonal (e.g., vertex-based) and functional (e.g., sigmoidal, Gaussian, custom shaped) membership functions.
Definition of fuzzy rules as strings of text written in natural language.
Definition of arbitrarily complex fuzzy rules built with the logic operators AND, OR, NOT.
Simpful takes as input a human-readable representation of a FIS, consisting of a collection of fuzzy sets defined by membership functions, linguistic variables, fuzzy rules, and consequent outputs (specified as crisp values, arbitrary functions, or fuzzy sets). When this information is fed to Simpful's FuzzySystem object, the system automatically performs a recursive tokening and parsing of the antecedents of each rule (exploiting the parentheses as delimiters), in order to identify atomic clauses and functional operators (i.e., the logical connectors AND, OR, NOT). By using these components, Simpful builds executable representations of the antecedents of rules in the form of derivation trees (Figure 1): the nodes represent the functional operators (blue nodes), while the leaves denote linguistic variables and terms (green and red nodes, respectively). By providing the input values for the antecedents, Simpful can perform a fuzzy inference and eventually provides the final output values (Figure 2).
A fuzzy set can be defined by using the FuzzySet object either as an ordered list of points in a plane, or as an arbitrary function:
In the first case, the points are passed to the constructor using the argument points. For each point, the first coordinate corresponds to its value in the universe of discourse , while the second represents the degree of membership. This sequence of points ultimately identifies a polygon. Simpful joins each pair of consecutive points in the sequence to identify the membership function characterizing the fuzzy set. Simpful deals with input values that are outside the specified universe of discourse by extrapolating, using the closest point specified in the sequence. This also means Simpful supports the use of shouldered fuzzy sets.
In the second case, the user creates a FuzzySet object by passing a function pointer, using the argument function. This custom function should be in the form : , , mapping every element of the universe of discourse to a valid membership value. In case the codomain of the custom function provided by the user is not equal to the expected interval, Simpful automatically clamps it to . Simpful also provides a set of objects with preimplemented general-purpose parametric functions, namely: Gaussian (Gaussian_MF), inverted Gaussian (InvGaussian_MF), double Gaussian (DoubleGaussian_MF), sigmoid (Sigmoid_MF), inverted sigmoid (InvSigmoid_MF), triangular (Triangular_MF) and trapezoidal (Trapezoidal_MF). It is worth noting that all these objects are derived from the same abstract class, named MF_object: by providing an implementation of the virtual method _execute(), users can straightforwardly create arbitrarily complex fuzzy sets exploiting any custom function. In this case, the new method must accept an argument and must return a valid membership value.
The user is also required to associate a meaningful linguistic term with each fuzzy set. The defined fuzzy sets are then employed in the creation of specific LinguisticVariable objects, provided with their own names, as given by the user. If the fuzzy sets are specified by means of a sequence of points only, Simpful automatically identifies the boundaries of the universe of discourse by exploiting the minimum and the maximum value among the first coordinates of all the points that define all the fuzzy sets. On the contrary, if a fuzzy set is defined by means of custom functions, the user can specify a valid interval of values for the LinguisticVariable object, by using the optional argument universe_of_discourse. The definition of this interval is required in order to use the draw() method of the LinguisticVariable class, which can be exploited to plot the fuzzy sets, thus allowing for a rapid inspection and debugging of their implementation. Worthy of note, both point- and function-based fuzzy sets can be exploited simultaneously in the definition of a single linguistic variable. In order to facilitate its usage, Simpful also provides a AutoTriangle() class, which returns a LinguisticVariable object whose universe of discourse is subdivided in a user-defined number of normalized triangular fuzzy sets.
The fuzzy rules used for the inference must be defined by means of well-formed strings, written in natural language (Figure 1). The current version of Simpful supports the most common fuzzy operators AND, OR, NOT, defined as
NOT = .
OR = .
AND = .
Each rule must use the variables' names and linguistic terms that were defined in the LinguisticVariable objects.
In the case of Takagi–Sugeno systems, the consequent of rules must also use strings that are associated with the output crisp values or with the output functions defined by the user. In this case, the user has to define the functions exploited in the inference as follows:
0-order functions (i.e., constant functions) are defined as “output crisp values.”
For higher order Takagi–Sugeno systems, the user can define “output functions” as strings of text involving the linguistic variables. These functions are evaluated at runtime by exploiting the eval() function of Python, which parses the expression given as a string argument and executes it as a code within the program.
Output crisp values, output functions, and output fuzzy sets must have an associated meaningful and unique string to identify them, which will be exploited in the definition of the fuzzy rules.
Linguistic variables, fuzzy rules, output crisp values, output functions, and output fuzzy sets are added to a fuzzy system object, which implements the whole FIS. Given the input values for the variables appearing in the antecedents of the fuzzy rules, the methods implementing the Mamdani or Takagi–Sugeno inference can be called for one or more of the variables appearing in the consequent of fuzzy rules, in order to obtain their final output. As an alternative, the user can invoke the inference() method of the FuzzySystem class to let Simpful choose and use the most appropriate inference method (i.e., Mamdani or Takagi–Sugeno). As a matter of fact, during the initialization phase, Simpful analyzes the outputs of the model and automatically determines the class of the defined FIS. The results of the inference are returned to the user as key-value pairs inside a dictionary, where keys represent the names of the variables. Figure 2 shows a schematic overview of how to construct a fuzzy system object and how to perform inference in Simpful.
The source code of Simpful is available, under GPL license, on GitHub at the following URL: https://github.com/aresio/simpful. Simpful can be installed by using the PyPI facility: pip install simpful. The example code described in this work can be found on Code Ocean at the following URL: https://codeocean.com/capsule/2230971/tree.
4. ILLUSTRATIVE EXAMPLES
In this section we provide three examples, together with their corresponding Python code, to show the potential and the usage of Simpful.
4.1. Tipping Problem
The tipping problem consists in computing a fair tip (in terms of percentage of the overall bill), taking into account a restaurant's services. Listings 1 and 2 show two examples of Simpful code to define a FIS that calculates the tipping amount on the basis of two input variables, describing food and serving staff quality.
Listing 1 A Mamdani FIS for the tipping problem, defined in Simpful.
1 from simpful import *
3 # A simple fuzzy inference system for the tipping problem
4 # Create a fuzzy system object
5 FS = FuzzySystem()
7 # Define fuzzy sets and linguistic variables
8 S_1 = FuzzySet(function=Triangular_MF(a=0, b=0, c=5), term="poor")
9 S_2 = FuzzySet(function=Triangular_MF(a=0, b=5, c=10), term="good")
10 S_3 = FuzzySet(function=Triangular_MF(a=5, b=10, c=10), term="excellent")
11 FS.add_linguistic_variable("Service", LinguisticVariable([S_1, S_2, S_3], concept="Service quality", universe_of_discourse=[0,10]))
13 F_1 = FuzzySet(function=Triangular_MF(a=0, b=0, c=10), term="rancid")
14 F_2 = FuzzySet(function=Triangular_MF(a=0, b=10, c=10), term="delicious")
15 FS.add_linguistic_variable("Food", LinguisticVariable([F_1, F_2], concept="Food quality", universe_of_discourse=[0,10]))
17 # Define output fuzzy sets and linguistic variable
18 T_1 = FuzzySet(function=Triangular_MF(a=0, b=0, c=10), term="small")
19 T_2 = FuzzySet(function=Triangular_MF(a=0, b=10, c=20), term="average")
20 T_3 = FuzzySet(function=Trapezoidal_MF(a=10, b=20, c=25, d=25), term="generous")
21 FS.add_linguistic_variable("Tip", LinguisticVariable([T_1, T_2, T_3], universe_of_discourse=[0,25]))
23 # Define fuzzy rules
24 R1 = "IF (Service IS poor) OR (Food IS rancid) THEN (Tip IS small)"
25 R2 = "IF (Service IS good) THEN (Tip IS average)"
26 R3 = "IF (Service IS excellent) OR (Food IS delicious) THEN (Tip IS generous)"
27 FS.add_rules([R1, R2, R3])
29 # Set antecedents values
30 FS.set_variable("Service", 4)
31 FS.set_variable("Food", 8)
33 # Perform Mamdani inference and print output
Listing 2 A Takagi-Sugeno FIS for the tipping problem, defined in Simpful.
1 from simpful import *
3 # A simple fuzzy inference system for the tipping problem
4 # Create a fuzzy system object
5 FS = FuzzySystem()
7 # Define fuzzy sets and linguistic variables
8 S_1 = FuzzySet(points=[[0., 1.], [5., 0.]], term="poor")
9 S_2 = FuzzySet(points=[[0., 0.], [5., 1.], [10., 0.]], term="good")
10 S_3 = FuzzySet(points=[[5., 0.], [10., 1.]], term="excellent")
11 FS.add_linguistic_variable("Service", LinguisticVariable([S_1, S_2, S_3], concept="Service quality"))
13 F_1 = FuzzySet(points=[[0., 1.], [10., 0.]], term="rancid")
14 F_2 = FuzzySet(points=[[0., 0.], [10., 1.]], term="delicious")
15 FS.add_linguistic_variable("Food", LinguisticVariable([F_1, F_2], concept="Food quality"))
17 # Define output crisp values
18 FS.set_crisp_output_value("small", 5)
19 FS.set_crisp_output_value("average", 15)
21 # Define function for generous tip (food score + service score + 5%)
22 FS.set_output_function("generous", "Food+Service+5")
24 # Define fuzzy rules
25 R1 = "IF (Service IS poor) OR (Food IS rancid) THEN (Tip IS small)"
26 R2 = "IF (Service IS good) THEN (Tip IS average)"
27 R3 = "IF (Service IS excellent) OR (Food IS delicious) THEN (Tip IS generous)"
28 FS.add_rules([R1, R2, R3])
30 # Set antecedents values
31 FS.set_variable("Service", 4)
32 FS.set_variable("Food", 8)
34 # Perform Sugeno inference and print output
In Listing 1 the tipping problem is modeled as a Mamdani FIS. In line a fuzzy system object is created. The fuzzy sets and the linguistic variable “Service” are defined in lines to ; this variable contains three fuzzy sets, “poor,” “good,” and “excellent,” ranging from to . From line to the linguistic variable for food quality is defined, exploiting two fuzzy sets, “rancid” and “delicious.” The output variable “Tip” and its fuzzy sets are defined from line to . All fuzzy sets used in this example are triangular (hence the use of the preimplemented function Triangular_MF), except for the fuzzy set that denotes a “Generous” tip, which is an example of a trapezoidal set (Trapezoidal_MF). The resulting membership functions are visualized in Figure 3. The fuzzy rules are defined in lines to . Once the input values are set (lines and , where “Service” and “Food” quality scored 4 and 8 points, respectively), Mamdani fuzzy inference is performed (line ) to obtain the final tipping percentage, which is equal to in this example.
Listing 2 shows the definition of another FIS to solve the tipping problem, this time using a Takagi–Sugeno model. Again, the fuzzy system object is created in line . From line to the fuzzy sets for the input variables are defined. In this example, the fuzzy sets are defined as polygons, using an ordered list of points, instead of exploiting a pre-implemented membership function as in the previous example. However, the resulting fuzzy sets are the same as the sets used in the Mamdani FIS. The output crisp values for a “small” and “average” tip are set to and respectively in line and . The output value for a “generous” tip is a function (defined in line ) depending on the scores for service and food quality. In this example this is a linear function, but any arbitrary function can be handled by Simpful. The fuzzy rules are then defined in lines to . The input values are set in line and , and Takagi–Sugeno inference is performed in line . Given that “Service” and “Food” quality scored 4 and 8 points, the tipping percentage should be according to this example.
Finally, Figure 4 shows a comparison of the output surfaces produced by simpful and Scikit-Fuzzy. The response of the two libraries is identical, confirming the correctness of Simpful's fuzzy inference.
4.2. Clinical Decision Support for Sepsis
When a patient enters the intensive care unit (ICU) with symptoms of sepsis, clinicians must diagnose quickly and start treatment within an hour of admission. Clinical decision support systems aim at helping clinicians with these decisions by processing patient data, such as blood levels and symptoms, and giving suggestions for diagnosis or treatment plans.
In Listing 3, we provide a simplified clinical decision support model that calculates how likely it is the patient suffers from sepsis. First, the fuzzy system object is created in line . The fuzzy sets and their linguistic terms for the input variables are specified in lines to . In this example, the fuzzy sets are defined by using sigmoidal and Gaussian functions. Since these functions have as domain, it is not possible to automatically estimate the limits of the universe of discourse for plotting the membership functions with the draw() method. Therefore, the user has to explicitly set the universe of discourse by specifying the argument universe_of_discourse (lines , , and ). Please note that this (explicitly limited) universe of discourse is only used to plot the membership functions: the system still supports input values outside this range when inferring the output. In line , the plots for the membership functions of the first variable are generated (Figure 5).
Listing 3 A clinical decision support system to diagnose sepsis, implemented in Simpful.
1 from simpful import *
3 # A simple decision support model to diagnose sepsis in the ICU
4 # Create a fuzzy system object
5 FS = FuzzySystem()
7 # Define fuzzy sets for the variable PaO2
8 P1 = FuzzySet(function=Sigmoid_MF(c=40, a=0.1), term="low")
9 P2 = FuzzySet(function=InvSigmoid_MF(c=40, a=0.1), term="high")
10 LV1 = LinguisticVariable([P1,P2], concept="PaO2 level in blood", universe_of_discourse=[0,80])
11 FS.add_linguistic_variable("PaO2", LV1)
14 # Define fuzzy sets for the variable base excess
15 B1 = FuzzySet(function=Gaussian_MF(mu=0,sigma=1.25), term="normal")
16 LV2 = LinguisticVariable([B1], concept="Base excess of the blood", universe_of_discourse=[-10,10])
17 FS.add_linguistic_variable("BaseExcess", LV2)
20 # Define fuzzy sets for the variable trombocytes
21 T1 = FuzzySet(function=Sigmoid_MF(c=50, a=0.75), term="low")
22 T2 = FuzzySet(function=InvSigmoid_MF(c=50, a=0.75), term="high")
23 LV3 = LinguisticVariable([T1,T2], concept="Trombocytes in blood", universe_of_discourse=[0,100])
24 FS.add_linguistic_variable("Trombocytes", LV3)
27 # Define fuzzy sets for the variable creatinine
28 C1 = FuzzySet(function=Sigmoid_MF(c=300, a=0.2), term="low")
29 C2 = FuzzySet(function=InvSigmoid_MF(c=300, a=0.1), term="high")
30 LV4 = LinguisticVariable([C1,C2], concept="Creatinine in blood", universe_of_discourse=[0,600])
31 FS.add_linguistic_variable("Creatinine", LV4)
34 # Define the consequents
35 FS.set_crisp_output_value("low_probability", 1)
36 FS.set_crisp_output_value("high_probability", 99)
38 # Define the fuzzy rules
39 RULE1 = "IF (PaO2 IS low) AND (Trombocytes IS high) AND (Creatinine IS high) AND (BaseExcess IS normal) THEN (Sepsis IS low_probability)"
40 RULE2 = "IF (PaO2 IS high) AND (Trombocytes IS low) AND (Creatinine IS low) AND (NOT(BaseExcess IS normal)) THEN (Sepsis IS high_probability)"
42 # Add fuzzy rules to the fuzzy reasoner object
43 FS.add_rules([RULE1, RULE2])
45 # Set antecedent values
46 FS.set_variable("PaO2", 50)
47 FS.set_variable("BaseExcess", −1.5)
48 FS.set_variable("Trombocytes", 50)
49 FS.set_variable("Creatinine", 320)
51 # Perform Sugeno inference and print output
In lines to , the variable “base excess” is created by first specifying the fuzzy set describing physiological values (using the preimplemented Gaussian_MF function). This is the only fuzzy set for this linguistic variable, meaning that the fuzzy set for the abnormal values for the base excess is not explicitly modeled, but corresponds to the complement of the fuzzy set for normal values (note the NOT operator in second fuzzy rule, line ). The same results could be achieved by modeling the set of non-normal values explicitly, either using the InvGaussian_MF function, or splitting the universe of discourse in a low, medium, and high fuzzy set, and later connecting the low and high fuzzy set in the fuzzy rule through an OR operator. However, using the NOT operator simplifies the FIS and preserves its high levels of interpretability. The output crisp values “low_probability” and “high_probability,” referring to the probability that the patient is suffering from sepsis, are defined in lines and . The fuzzy rules are then defined and added to the fuzzy system object in lines to . Lines to provide example input values to the model, and fuzzy inference is performed in line to obtain the probability that the patient is suffering from sepsis which, in this example, is equal to .
The repressilator is a synthetic regulatory network consisting of three genes placed in a feedback loop, where the genetic product of each gene inhibits the expression of the next gene in the network (Figure 6). This simple system was designed to exhibit a stable oscillatory regime, studied by means of mechanistic modeling, and then implemented in vivo in the bacterium E. coli . Here, we provide a simple redefinition of the repressilator in terms of a DFM, to show how Simpful can also be applied for the fuzzy modeling of complex systems.
DFM is a formalism useful to analyze the emergent behavior of complex systems characterized by uncertainty . A DFM consists of a set of linguistic variables describing the components of the system, and a set of fuzzy rules providing a qualitative description of their interactions. A DFM can be considered as a FN , i.e., a network of interacting FISs. Thus, a FN can be depicted as a directed graph (as in Figure 6), where nodes represent linguistic variables, and arcs the presence of some fuzzy rules governing them.
The example code of the repressilator is given in Listing 4. In line a fuzzy system object is created. From line to , the three linguistic variables related to the three species constituting the repressilator are defined. All three species are characterized by a universe of discourse ranging from to (the default universe of discourse), and by the presence of two fuzzy sets, “low” and “high,” representing the quantity of each protein. Note that here the AutoTriangle() class is used (line ) in order to define a general linguistic variable characterized by symmetrical fuzzy sets covering the whole universe of discourse. In this example, a value of in the universe of discourse corresponds to the maximum quantity, while to the absence of the protein. Analogously, the output crisp values are defined in lines and , by setting “low” to and “high” to . Lines to contain the definition of the fuzzy rules, representing the negative feedbacks existing between the three genes.
Listing 4 A DFM of the repressilator model, implemented using Simpful.
1 from simpful import *
2 from copy import deepcopy
4 # A simple dynamic fuzzy model of the repressilator
5 # Create a fuzzy reasoner object
6 FS = FuzzySystem()
8 # Define fuzzy sets and linguistic variables
9 LV = AutoTriangle(2, terms=['low', 'high'])
10 FS.add_linguistic_variable("LacI", LV)
11 FS.add_linguistic_variable("TetR", LV)
12 FS.add_linguistic_variable("CI", LV)
14 # Define output crisp values
15 FS.set_crisp_output_value("low", 0.0)
16 FS.set_crisp_output_value("high", 1.0)
18 # Define fuzzy rules
19 RULES = 
20 RULES.append("IF (LacI IS low) THEN (TetR IS high)")
21RULES.append("IF (LacI IS high) THEN (TetR IS low)")
22 RULES.append("IF (TetR IS low) THEN (CI IS high)")
23 RULES.append("IF (TetR IS high) THEN (CI IS low)")
24 RULES.append("IF (CI IS low) THEN (LacI IS high)")
25 RULES.append("IF (CI IS high) THEN (LacI IS low)")
28 # Set antecedents values
29 FS.set_variable("LacI", 1.0)
30 FS.set_variable("TetR", 0.5)
31 FS.set_variable("CI", 0.0)
33 # Set simulation steps and save initial state
34 steps = 14
35 dynamics = 
38 # At each simulation step, perform Sugeno inference, update state and save the results
39 for i in range(steps):
40 new_values = FS.inference()
The initial state of the DFM is set in lines to , the number of simulation steps is defined in line , while the data structure containing the results of the simulation is initialized in lines and . Lines to contain the for loop in which the simulation is performed. In particular, the new state of the system is inferred in line , updated in line , and then stored in the previously defined data structure. Note that, in this example, we exploit the inference() method provided by the FuzzySystem object (see line 40).
The final output, i.e., the simulation of the system's dynamics, can be plotted as shown in Figure 7. Despite its simplicity and the lack of a precise kinetic parameterization, this model can reproduce the typical oscillatory dynamics of the three species, as shown in the original model .
Simpful is a novel library that addresses the need of having a lightweight, open-source, Python API to support the creation of readable FISs, based on either Mamdani or Takagi–Sugeno fuzzy reasoning. Users can define fuzzy sets as polygons (formalized as sequences of vertices), parametric functions (e.g., Gaussian and sigmoid), or even arbitrary custom functions in the universe of discourse/degree of membership space. Fuzzy rules are encoded as strings of text written in natural language, making FISs created in Simpful easier to read and to inspect compared to competitor libraries. To show its usage, we provided three examples: the definition of a FIS for the tipping problem, the definition of a clinical decision support system to diagnose sepsis, and the modeling and simulation of a complex biochemical system by means of a DFM. Thanks to its features, Simpful is a valuable addition to the open-source software that support fuzzy reasoning, and it is expected to highly facilitate the definition, analysis and interpretation of FISs in a wide variety of data- and knowledge-driven applications.
Simpful was employed to implement the FuzzX framework for the modeling and simulation of hybrid (qualitative and quantitative) systems . The porting of FUMOSO  to Simpful, currently in progress, will also promote the use of DFMs for the investigation of complex systems. Simpful is also employed within pyFUME , a novel Python package developed to estimate FISs automatically from data [44–47]. Moreover, Simpful can be readily integrated in computational intelligence methods that use Mamdani or Takagi–Sugeno inference, such as the class of global optimization meta-heuristics exploiting fuzzy reasoning for dynamic parameter adaptation [48,49].
In future releases, we plan to extend Simpful with support for additional fuzzy logic operators and other fuzzy inference methods (e.g., Tsukamoto , and AnYa  methods). In particular, we will add support for weighted fuzzy rules , type-2 FISs , and probabilistic fuzzy reasoning , the latter providing a means to combine the interpretability of FIS with the statistical properties of probabilistic systems. Finally, Simpful will support the FML format defined in the IEEE Std 1855-2016 , possibly by leveraging existing software (i.e., JFML and Py4JFML [17,24]), to facilitate the import, export, and sharing of the FISs defined within this library.
CONFLICTS OF INTEREST
The authors declare no conflicts of interest.
MSN conceived the idea of the library; SS and MSN designed and implemented the library; SS and CF conceived the usage examples, analyzed the results and performed comparisons with the other methods; SS, CF and MSN prepared and created the figures and wrote the first draft of the manuscript; PC, UK and DB critically reviewed and edited the manuscript; All authors read and approved its final version.
This work was partially funded by the SYSBIO/ISBE.IT Research Centre of Systems Biology.
Cite this article
TY - JOUR AU - Simone Spolaor AU - Caro Fuchs AU - Paolo Cazzaniga AU - Uzay Kaymak AU - Daniela Besozzi AU - Marco S. Nobile PY - 2020 DA - 2020/10/24 TI - Simpful: A User-Friendly Python Library for Fuzzy Logic JO - International Journal of Computational Intelligence Systems SP - 1687 EP - 1698 VL - 13 IS - 1 SN - 1875-6883 UR - https://doi.org/10.2991/ijcis.d.201012.002 DO - 10.2991/ijcis.d.201012.002 ID - Spolaor2020 ER -