Library contains some routines for work with fuzzy logic operators, fuzzy datasets and fuzzy scales.
Index:
You can install FuzzyRoutines using pip:
pip install fuzzyroutines [--upgrade] [--pre]
or using setuptools to build local version:
git clone https://github.com/devopshq/FuzzyRoutines.git
cd FuzzyRoutines
python setup.py install
After installing you can check the version of the FuzzyRoutines library:
pip show fuzzyroutines
You can see and run Example.py script:
cd fuzzyroutines
python Examples.py
Example.py contains some examples of working with fuzzy library. Just copying and run examples below. Do not forget to import FuzzyRoutines module before use:
from fuzzyroutines.FuzzyRoutines import *
Work with membership functions
Usage of some membership functions:
mjuPars = {'a': 7, 'b': 4, 'c': 0} # hyperbolic params example
funct = MFunction(userFunc='hyperbolic', **mjuPars) # creating instance of hyperbolic function
print('Printing Membership function with parameters: ', funct)
mjuPars = {'a': 0, 'b': 0.3, 'c': 0.4} # bell params example
funct = MFunction(userFunc='bell', **mjuPars) # creating instance of bell function
print('Printing Membership function with parameters: ', funct)
mjuPars = {'a': 0, 'b': 1} # parabolic params example
funct = MFunction(userFunc='parabolic', **mjuPars) # creating instance of parabolic function
print('Printing Membership function with parameters: ', funct)
mjuPars = {'a': 0.2, 'b': 0.8, 'c': 0.7} # triangle params example
funct = MFunction(userFunc='triangle', **mjuPars) # creating instance of triangle function
print('Printing Membership function with parameters: ', funct)
mjuPars = {'a': 0.5, 'b': 0.15} # exponential params example
funct = MFunction(userFunc='exponential', **mjuPars) # creating instance of exponential function
print('Printing Membership function with parameters: ', funct)
mjuPars = {'a': 15, 'b': 0.5} # sigmoidal params example
funct = MFunction(userFunc='sigmoidal', **mjuPars) # creating instance of sigmoidal function
print('Printing Membership function with parameters: ', funct)
funct = MFunction(userFunc='desirability') # creating instance of desirability function without parameters
print('Printing Membership function with parameters: ', funct)
mjuPars = {'a': 0.1, 'b': 1, 'c': 0.5, 'd': 0.8} # trapezium params example
funct = MFunction(userFunc='trapezium', **mjuPars) # creating instance of trapezium function
print('Printing Membership function with parameters: ', funct)
Output:
Printing Membership function with parameters: Hyperbolic(x, {"a": 7, "b": 4, "c": 0})
Printing Membership function with parameters: Bell(x, {"a": 0, "b": 0.3, "c": 0.4})
Printing Membership function with parameters: Parabolic(x, {"a": 0, "b": 1})
Printing Membership function with parameters: Triangle(x, {"a": 0.2, "b": 0.8, "c": 0.7})
Printing Membership function with parameters: Exponential(x, {"a": 0.5, "b": 0.15})
Printing Membership function with parameters: Sigmoidal(x, {"a": 15, "b": 0.5})
Printing Membership function with parameters: Desirability(y)
Printing Membership function with parameters: Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8})
Calculating Trapezium function's values in [0, 1]:
xPar = 0
for i in range(0, 10, 1):
xPar = (xPar + i) / 10
res = funct.mju(xPar) # calculate one value of MF with given parameters
print('x = {:.1f}, {} = {:1.4f}'.format(xPar, funct, res))
Output:
x = 0.0, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 0.0000
x = 0.1, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 0.0000
x = 0.2, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 0.2750
x = 0.3, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 0.5525
x = 0.4, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 0.8302
x = 0.5, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 1.0000
x = 0.7, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 1.0000
x = 0.8, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 1.0000
x = 0.9, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 0.6173
x = 1.0, Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}) = 0.0617
fuzzySet = FuzzySet(funct, (0., 1.)) # creating fuzzy set A = <mju_funct, support_set>
print('Printing fuzzy set after init and before changes:', fuzzySet)
print('Defuz({}) = {:1.2f}'.format(fuzzySet.name, fuzzySet.Defuz()))
changedMjuPars = copy.deepcopy(mjuPars) # change parameters of membership function with deepcopy example:
changedMjuPars['a'] = 0
changedMjuPars['b'] = 1
changedSupportSet = (0.5, 1) # change support set
fuzzySet.name = 'Changed fuzzy set'
fuzzySet.mFunction.parameters = changedMjuPars
fuzzySet.supportSet = changedSupportSet
print('New membership function with parameters: ', fuzzySet.mFunction)
print('New support set: ', fuzzySet.supportSet)
print('New value of Defuz({}) = {:1.2f}'.format(fuzzySet.name, fuzzySet.Defuz()))
print('Printing fuzzy set after changes:', fuzzySet)
Output:
Printing fuzzy set after init and before changes: FuzzySet = <Trapezium(x, {"a": 0.1, "b": 1, "c": 0.5, "d": 0.8}), [0.0, 1.0]>
Defuz(FuzzySet) = 0.59
New membership function with parameters: Trapezium(x, {"a": 0, "b": 1, "c": 0.5, "d": 0.8})
New support set: (0.5, 1)
New value of Defuz(Changed fuzzy set) = 0.59
Printing fuzzy set after changes: Changed fuzzy set = <Trapezium(x, {"a": 0, "b": 1, "c": 0.5, "d": 0.8}), [0.5, 1]>
Fuzzy scale is an ordered set of linguistic variables that looks like this:
S = [{'name': 'name_1', 'fSet': fuzzySet_1}, {'name': 'name_2', 'fSet': fuzzySet_2}, ...]
where name is a linguistic name of fuzzy set, fSet is a user define fuzzy set of FuzzySet type.
scale = FuzzyScale() # intialize new fuzzy scale with default levels
print('Printing default fuzzy scale in human-readable:', scale)
print('Defuz() of all default levels:')
for item in scale.levels:
print('Defuz({}) = {:1.2f}'.format(item['name'], item['fSet'].Defuz()))
Output:
Printing default fuzzy scale in human-readable: DefaultScale = {Min, Med, High}
Minimum = <Hyperbolic(x, {"a": 7, "b": 4, "c": 0}), [0.0, 1.0]>
Medium = <Bell(x, {"a": 0.35, "b": 0.5, "c": 0.6}), [0.0, 1.0]>
High = <Triangle(x, {"a": 0.7, "b": 1, "c": 1}), [0.0, 1.0]>
Defuz() of all default levels:
Defuz(Min) = 0.10
Defuz(Med) = 0.55
Defuz(High) = 0.90
Add new fuzzy levels:
print('Define some new levels:')
minFunct = MFunction('hyperbolic', **{'a': 2, 'b': 20, 'c': 0})
levelMin = FuzzySet(membershipFunction=minFunct, supportSet=(0., 0.5), linguisticName='min')
print('Printing Level 1 in human-readable:', levelMin)
medFunct = MFunction('bell', **{'a': 0.4, 'b': 0.55, 'c': 0.7})
levelMed = FuzzySet(membershipFunction=medFunct, supportSet=(0.25, 0.75), linguisticName='med')
print('Printing Level 2 in human-readable:', levelMed)
maxFunct = MFunction('triangle', **{'a': 0.65, 'b': 1, 'c': 1})
levelMax = FuzzySet(membershipFunction=maxFunct, supportSet=(0.7, 1.), linguisticName='max')
print('Printing Level 3 in human-readable:', levelMax)
Output:
Define some new levels:
Printing Level 1 in human-readable: min = <Hyperbolic(x, {"a": 2, "b": 20, "c": 0}), [0.0, 0.5]>
Printing Level 2 in human-readable: med = <Bell(x, {"a": 0.4, "b": 0.55, "c": 0.7}), [0.25, 0.75]>
Printing Level 3 in human-readable: max = <Triangle(x, {"a": 0.65, "b": 1, "c": 1}), [0.7, 1.0]>
Change scale levels:
scale.name = 'New Scale'
scale.levels = [{'name': levelMin.name, 'fSet': levelMin}, {'name': levelMed.name, 'fSet': levelMed},
{'name': levelMax.name, 'fSet': levelMax}] # add new ordered set of linguistic variables into scale
print('Changed List of levels as objects:', scale.levels)
print('Printing changed fuzzy scale in human-readable:', scale)
print('Defuz() of all New Scale levels:')
for item in scale.levels:
print('Defuz({}) = {:1.2f}'.format(item['name'], item['fSet'].Defuz()))
Output:
Changed List of levels as objects: [{'name': 'min', 'fSet': <fuzzyroutines.FuzzyRoutines.FuzzySet object at 0x000001AECB3F17B8>}, {'name': 'med', 'fSet': <fuzzyroutines.FuzzyRoutines.FuzzySet object at 0x000001AECB337D68>}, {'name': 'max', 'fSet': <fuzzyroutines.FuzzyRoutines.FuzzySet object at 0x000001AECB3F18D0>}]
Printing changed fuzzy scale in human-readable: New Scale = {min, med, max}
min = <Hyperbolic(x, {"a": 2, "b": 20, "c": 0}), [0.0, 0.5]>
med = <Bell(x, {"a": 0.4, "b": 0.55, "c": 0.7}), [0.25, 0.75]>
max = <Triangle(x, {"a": 0.65, "b": 1, "c": 1}), [0.7, 1.0]>
Defuz() of all New Scale levels:
Defuz(min) = 0.24
Defuz(med) = 0.61
Defuz(max) = 0.89
Work with Universal Fuzzy Scale
Universal fuzzy scales S_f = {Min, Low, Med, High, Max} pre-defined in UniversalFuzzyScale() class.
uniFScale = UniversalFuzzyScale()
print('Levels of Universal Fuzzy Scale:', uniFScale.levels)
print('Printing scale:', uniFScale)
print('Defuz() of all Universal Fuzzy Scale levels:')
for item in uniFScale.levels:
print('Defuz({}) = {:1.2f}'.format(item['name'], item['fSet'].Defuz()))
Output:
Levels of Universal Fuzzy Scale: [{'name': 'Min', 'fSet': <fuzzyroutines.FuzzyRoutines.FuzzySet object at 0x000001AECB34F7B8>}, {'name': 'Low', 'fSet': <fuzzyroutines.FuzzyRoutines.FuzzySet object at 0x000001AECB34F198>}, {'name': 'Med', 'fSet': <fuzzyroutines.FuzzyRoutines.FuzzySet object at 0x000001AECB34F048>}, {'name': 'High', 'fSet': <fuzzyroutines.FuzzyRoutines.FuzzySet object at 0x000001AECB34F0F0>}, {'name': 'Max', 'fSet': <fuzzyroutines.FuzzyRoutines.FuzzySet object at 0x000001AECB34F710>}]
Printing scale: FuzzyScale = {Min, Low, Med, High, Max}
Min = <Hyperbolic(x, {"a": 8, "b": 20, "c": 0}), [0.0, 0.23]>
Low = <Bell(x, {"a": 0.17, "b": 0.23, "c": 0.34}), [0.17, 0.4]>
Med = <Bell(x, {"a": 0.34, "b": 0.4, "c": 0.6}), [0.34, 0.66]>
High = <Bell(x, {"a": 0.6, "b": 0.66, "c": 0.77}), [0.6, 0.83]>
Max = <Parabolic(x, {"a": 0.77, "b": 0.95}), [0.77, 1.0]>
Defuz() of all Universal Fuzzy Scale levels:
Defuz(Min) = 0.06
Defuz(Low) = 0.29
Defuz(Med) = 0.50
Defuz(High) = 0.71
Defuz(Max) = 0.93
Use Fuzzy() function to looking for level on Fuzzy Scale:
xPar = 0
for i in range(0, 10, 1):
xPar = (xPar + i) / 10
res = uniFScale.Fuzzy(xPar) # calculate fuzzy level for some real values
print('Fuzzy({:1.1f}, {}) = {}, {}'.format(xPar, uniFScale.name, res['name'], res['fSet']))
Output:
Fuzzy(0.0, FuzzyScale) = Min, Min = <Hyperbolic(x, {"a": 8, "b": 20, "c": 0}), [0.0, 0.23]>
Fuzzy(0.1, FuzzyScale) = Min, Min = <Hyperbolic(x, {"a": 8, "b": 20, "c": 0}), [0.0, 0.23]>
Fuzzy(0.2, FuzzyScale) = Low, Low = <Bell(x, {"a": 0.17, "b": 0.23, "c": 0.34}), [0.17, 0.4]>
Fuzzy(0.3, FuzzyScale) = Low, Low = <Bell(x, {"a": 0.17, "b": 0.23, "c": 0.34}), [0.17, 0.4]>
Fuzzy(0.4, FuzzyScale) = Med, Med = <Bell(x, {"a": 0.34, "b": 0.4, "c": 0.6}), [0.34, 0.66]>
Fuzzy(0.5, FuzzyScale) = Med, Med = <Bell(x, {"a": 0.34, "b": 0.4, "c": 0.6}), [0.34, 0.66]>
Fuzzy(0.7, FuzzyScale) = High, High = <Bell(x, {"a": 0.6, "b": 0.66, "c": 0.77}), [0.6, 0.83]>
Fuzzy(0.8, FuzzyScale) = High, High = <Bell(x, {"a": 0.6, "b": 0.66, "c": 0.77}), [0.6, 0.83]>
Fuzzy(0.9, FuzzyScale) = Max, Max = <Parabolic(x, {"a": 0.77, "b": 0.95}), [0.77, 1.0]>
Fuzzy(1.0, FuzzyScale) = Max, Max = <Parabolic(x, {"a": 0.77, "b": 0.95}), [0.77, 1.0]>
Finding fuzzy level using GetLevelByName() function with exact matching:
print('Finding level by name with exact matching:')
res = uniFScale.GetLevelByName('Min')
print('GetLevelByName(Min, {}) = {}, {}'.format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
res = uniFScale.GetLevelByName('High')
print('GetLevelByName(High, {}) = {}, {}'.format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
res = uniFScale.GetLevelByName('max')
print('GetLevelByName(max, {}) = {}, {}'.format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
Output:
Finding level by name with exact matching:
GetLevelByName(Min, FuzzyScale) = Min, Min = <Hyperbolic(x, {"a": 8, "b": 20, "c": 0}), [0.0, 0.23]>
GetLevelByName(High, FuzzyScale) = High, High = <Bell(x, {"a": 0.6, "b": 0.66, "c": 0.77}), [0.6, 0.83]>
GetLevelByName(max, FuzzyScale) = None, None
Finding fuzzy level using GetLevelByName() function without exact matching:
print('Finding level by name without exact matching:')
res = uniFScale.GetLevelByName('mIn', exactMatching=False)
print("GetLevelByName('mIn', {}) = {}, {}".format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
res = uniFScale.GetLevelByName('max', exactMatching=False)
print("GetLevelByName('max', {}) = {}, {}".format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
res = uniFScale.GetLevelByName('Hig', exactMatching=False)
print("GetLevelByName('Hig', {}) = {}, {}".format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
res = uniFScale.GetLevelByName('LOw', exactMatching=False)
print("GetLevelByName('LOw', {}) = {}, {}".format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
res = uniFScale.GetLevelByName('eD', exactMatching=False)
print("GetLevelByName('eD', {}) = {}, {}".format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
res = uniFScale.GetLevelByName('Highest', exactMatching=False)
print("GetLevelByName('Highest', {}) = {}, {}".format(uniFScale.name, res['name'] if res else 'None', res['fSet'] if res else 'None'))
Output:
Finding level by name without exact matching:
GetLevelByName('mIn', FuzzyScale) = Min, Min = <Hyperbolic(x, {"a": 8, "b": 20, "c": 0}), [0.0, 0.23]>
GetLevelByName('max', FuzzyScale) = Max, Max = <Parabolic(x, {"a": 0.77, "b": 0.95}), [0.77, 1.0]>
GetLevelByName('Hig', FuzzyScale) = None, None
GetLevelByName('LOw', FuzzyScale) = Low, Low = <Bell(x, {"a": 0.17, "b": 0.23, "c": 0.34}), [0.17, 0.4]>
GetLevelByName('eD', FuzzyScale) = None, None
GetLevelByName('Highest', FuzzyScale) = None, None
Work with fuzzy logic operators
Checks that number is in [0, 1]:
print('IsCorrectFuzzyNumberValue(0.5) =', IsCorrectFuzzyNumberValue(0.5))
print('IsCorrectFuzzyNumberValue(1.1) =', IsCorrectFuzzyNumberValue(1.1))
Output:
IsCorrectFuzzyNumberValue(0.5) = True
IsCorrectFuzzyNumberValue(1.1) = False
Calculates result of fuzzy NOT, fuzzy NOT with alpha parameter and parabolic fuzzy NOT operations:
print('FNOT(0.25) =', FuzzyNOT(0.25))
print('FNOT(0.25, alpha=0.25) =', FuzzyNOT(0.25, alpha=0.25))
print('FNOT(0.25, alpha=0.75) =', FuzzyNOT(0.25, alpha=0.75))
print('FNOT(0.25, alpha=1) =', FuzzyNOT(0.25, alpha=1))
print('FNOTParabolic(0.25, alpha=0.25) =', FuzzyNOTParabolic(0.25, alpha=0.25))
print('FNOTParabolic(0.25, alpha=0.75) =', FuzzyNOTParabolic(0.25, alpha=0.75))
Output:
FNOT(0.25) = 0.75
FNOT(0.25, alpha=0.25) = 0.25
FNOT(0.25, alpha=0.75) = 0.9166666666666666
FNOT(0.25, alpha=1) = 1.0
FNOTParabolic(0.25, alpha=0.25) = 0.25000000000000017
FNOTParabolic(0.25, alpha=0.75) = 0.9820000000000008
Calculates result of fuzzy AND/OR operations:
print('FuzzyAND(0.25, 0.5) =', FuzzyAND(0.25, 0.5))
print('FuzzyOR(0.25, 0.5) =', FuzzyOR(0.25, 0.5))
Output:
FuzzyAND(0.25, 0.5) = 0.25
FuzzyOR(0.25, 0.5) = 0.5
Calculates result of T-Norm operations, where T-Norm is one of conjunctive operators - logic, algebraic, boundary, drastic:
print("TNorm(0.25, 0.5, 'logic') =", TNorm(0.25, 0.5, normType='logic'))
print("TNorm(0.25, 0.5, 'algebraic') =", TNorm(0.25, 0.5, normType='algebraic'))
print("TNorm(0.25, 0.5, 'boundary') =", TNorm(0.25, 0.5, normType='boundary'))
print("TNorm(0.25, 0.5, 'drastic') =", TNorm(0.25, 0.5, normType='drastic'))
Output:
TNorm(0.25, 0.5, 'logic') = 0.25
TNorm(0.25, 0.5, 'algebraic') = 0.125
TNorm(0.25, 0.5, 'boundary') = 0
TNorm(0.25, 0.5, 'drastic') = 0
Calculates result of S-coNorm operations, where S-coNorm is one of disjunctive operators - logic, algebraic, boundary, drastic:
print("SCoNorm(0.25, 0.5, 'logic') =", SCoNorm(0.25, 0.5, normType='logic'))
print("SCoNorm(0.25, 0.5, 'algebraic') =", SCoNorm(0.25, 0.5, normType='algebraic'))
print("SCoNorm(0.25, 0.5, 'boundary') =", SCoNorm(0.25, 0.5, normType='boundary'))
print("SCoNorm(0.25, 0.5, 'drastic') =", SCoNorm(0.25, 0.5, normType='drastic'))
Output:
SCoNorm(0.25, 0.5, 'logic') = 0.5
SCoNorm(0.25, 0.5, 'algebraic') = 0.625
SCoNorm(0.25, 0.5, 'boundary') = 0.75
SCoNorm(0.25, 0.5, 'drastic') = 1
Calculates result of T-Norm operations for N numbers, N > 2:
print("TNormCompose(0.25, 0.5, 0.75, 'logic') =", TNormCompose(0.25, 0.5, 0.75, normType='logic'))
print("TNormCompose(0.25, 0.5, 0.75, 'algebraic') =", TNormCompose(0.25, 0.5, 0.75, normType='algebraic'))
print("TNormCompose(0.25, 0.5, 0.75, 'boundary') =", TNormCompose(0.25, 0.5, 0.75, normType='boundary'))
print("TNormCompose(0.25, 0.5, 0.75, 'drastic') =", TNormCompose(0.25, 0.5, 0.75, normType='drastic'))
Output:
TNormCompose(0.25, 0.5, 0.75, 'logic') = 0.25
TNormCompose(0.25, 0.5, 0.75, 'algebraic') = 0.09375
TNormCompose(0.25, 0.5, 0.75, 'boundary') = 0
TNormCompose(0.25, 0.5, 0.75, 'drastic') = 0
Calculates result of S-coNorm operations for N numbers, N > 2:
print("SCoNormCompose(0.25, 0.5, 0.75, 'logic') =", SCoNormCompose(0.25, 0.5, 0.75, normType='logic'))
print("SCoNormCompose(0.25, 0.5, 0.75, 'algebraic') =", SCoNormCompose(0.25, 0.5, 0.75, normType='algebraic'))
print("SCoNormCompose(0.25, 0.5, 0.75, 'boundary') =", SCoNormCompose(0.25, 0.5, 0.75, normType='boundary'))
print("SCoNormCompose(0.25, 0.5, 0.75, 'drastic') =", SCoNormCompose(0.25, 0.5, 0.75, normType='drastic'))
Output:
SCoNormCompose(0.25, 0.5, 0.75, 'logic') = 0.75
SCoNormCompose(0.25, 0.5, 0.75, 'algebraic') = 0.90625
SCoNormCompose(0.25, 0.5, 0.75, 'boundary') = 1
SCoNormCompose(0.25, 0.5, 0.75, 'drastic') = 1
Converting some strings to range of sorted unique numbers with DiapasonParser():
print("Converting some strings to range of sorted unique numbers:")
print('String "1,5" converted to:', DiapasonParser("1,5"))
print('String "1-5" converted to:', DiapasonParser("1-5"))
print('String "8-10, 1-5, 6" converted to:', DiapasonParser("8-10, 1-5, 6"))
print('String "11, 11, 12, 12, 1-5, 3-7" converted to:', DiapasonParser("11, 12, 1-5, 3-7"))
Output:
Converting some strings to range of sorted unique numbers:
String "1,5" converted to: [1, 5]
String "1-5" converted to: [1, 2, 3, 4, 5]
String "8-10, 1-5, 6" converted to: [1, 2, 3, 4, 5, 6, 8, 9, 10]
String "11, 11, 12, 12, 1-5, 3-7" converted to: [1, 2, 3, 4, 5, 6, 7, 11, 12]