forked from jfpower/fcl-for-scikit-fuzzy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
extramf.py
205 lines (166 loc) · 6.7 KB
/
extramf.py
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
# -*- coding: utf-8 -*-
"""
Some extra membership functions to augment those in skfuzzy.membership
@author: [email protected] Created on Fri Jul 27 16:10:03 2018
"""
from collections import OrderedDict
import numpy as np
import skfuzzy
import skfuzzy.membership as skmemb
import scipy.interpolate as interp
def singletonmf(x, xpt):
''' Find which x-val is nearest the given point, and set it to 1'''
mf = np.zeros(len(x))
diffs = np.abs(x - xpt)
idx = np.nonzero(diffs == diffs.min())[0][0]
mf[idx] = 1
return mf
def pointsetmf(x, pointset, method='linear'):
'''Interpolate from a point-set using the chosen interpolation method'''
# Make sure we're in ascending order first:
pointset = sorted(pointset, key=lambda p: p[0])
x_min, x_max = x[0], x[-1]
# Lead on left from y=0, unless otherwise specified:
if pointset[0][0] > x_min:
pointset = [(x_min, 0)] + pointset
# Trail on right from last given y value
if pointset[-1][0] < x_max:
pointset = pointset + [(x_max, pointset[-1][1])]
px, py = [p[0] for p in pointset], [p[1] for p in pointset]
if method == 'linear':
f = interp.interp1d(px, py)
elif method == 'lagrange':
f = interp.lagrange(px, py)
elif method == 'spline':
f = interp.make_interp_spline(px, py)
elif method == 'cubic':
f = interp.CubicSpline(px, py, bc_type='natural')
# Sometimes interpoliation can go outside the bounds:
return np.clip(f(x), 0, 1)
def gaussprod(x, mean1, sigma1, mean2, sigma2):
'''Ensure the means are in correct order before calling gauss2mf'''
if mean1 > mean2:
mean1, sigma1, mean2, sigma2 = mean2, sigma2, mean1, sigma1
return skmemb.gauss2mf(x, mean1, sigma1, mean2, sigma2)
def rectanglemf(x, a, b):
'''Zero before and after given end points, one in between them'''
mf = np.ones(len(x))
mf[np.nonzero(x < a)] = 0
mf[np.nonzero(x > b)] = 0
return mf
def leftlinearmf(x, a, b):
'''One to the left, zero to the right, slope down in-between'''
mf = np.ones(len(x))
midpts = np.nonzero(np.logical_and(a < x, x < b))
mf[midpts] = (((b - x[midpts]) / (b - a)))
mf[np.nonzero(x >= b)] = 0
return mf
def rightlinearmf(x, a, b):
'''Zero to the left, one to the right, slope up in-between'''
mf = np.zeros(len(x))
midpts = np.nonzero(np.logical_and(a < x, x < b))
mf[midpts] = 1 - (((b - x[midpts]) / (b - a)))
mf[np.nonzero(x >= b)] = 1
return mf
def rampmf(x, a, b):
'''A line from a up/down to b (depending on the order of a and b)'''
if a < b:
return rightlinearmf(x, a, b)
elif a > b:
return leftlinearmf(x, b, a)
else: # a == b
return np.zeros(len(x))
def cosinemf(x, center, width):
'''A cosine curve distributed about the center with the given width'''
mf = np.zeros(len(x))
# Only plot the curve within the given width either side the center:
midpts = np.nonzero(np.logical_and(center - 0.5 * width <= x,
x <= center + 0.5 * width))
to_angle = 2.0 * np.pi / width
mf[midpts] = (0.5 * (1.0 + np.cos(to_angle * (x[midpts] - center))))
return mf
def concavemf(x, infl, end):
'''A curve rising/falling to end point, bent according to inflexion pt'''
mf = np.ones(len(x))
if infl <= end: # Concave increasing
incpts = np.nonzero(x < end)
mf[incpts] = (end - infl) / (2.0 * end - infl - x[incpts])
else: # Concave decreasing
decpts = np.nonzero(x > end)
mf[decpts] = (infl - end) / (infl - 2.0 * end + x[decpts])
return mf
def leftgaussmf(x, mean, sigma):
''' Like Gaussian, but always 1 when <= mean (so, slopes down only)'''
mf = skmemb.gaussmf(x, mean, sigma)
mf[np.nonzero(x <= mean)] = 1
return mf
def rightgaussmf(x, mean, sigma):
''' Like Gaussian, but always 1 when >= mean (so, slopes up only)'''
mf = skmemb.gaussmf(x, mean, sigma)
mf[np.nonzero(x >= mean)] = 1
return mf
def spikemf(x, center, width):
'''A symmetrical curved (exp) spike centered at the given location'''
return np.exp(-np.abs(10.0 / width * (x - center)))
def jfl_sigmf(x, gain, center):
'''Like sigmf, but jFuzzyLogic supplies parameters in a different order'''
return skmemb.sigmf(x, center, gain)
def fl_bellmf(x, center, width, slope):
'''Like gbellmf, but fuzzylite supplies parameters in a different order'''
return skmemb.gbellmf(x, width, slope, center)
# ### Sanity check: plot some examples of the membership functions
import matplotlib.pyplot as plt
def visualise_all(x, y_list, titles, ncols=3):
'''
Just display the given plot-data on a grid of separate graphs.
Also show the centroid as a vertical red line.
'''
nrows = np.int(np.ceil(len(y_list) / ncols))
fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=(8, 9))
fig.tight_layout()
fig.subplots_adjust(bottom=-.25)
for i, p in enumerate(y_list):
r, c = divmod(i, ncols)
axes[r][c].plot(x, p)
cog = skfuzzy.centroid(x, p)
axes[r][c].axvline(x=cog, color='red', linestyle='--')
axes[r][c].set_title(titles[i])
axes[r][c].set_ylim([-0.05, 1.05]) # so all have the same (0,1) y-axis
def _plot_mf_for(x):
'''Given the x-values, plot a series of example membership functions'''
tests = OrderedDict([
# Gaussians:
('gauss', skmemb.gaussmf(x, 50, 10)),
('left gauss', leftgaussmf(x, 50, 10)),
('right gauss', rightgaussmf(x, 50, 10)),
# Triangles:
('triangular', skmemb.trimf(x, [25, 50, 75])),
('left linear', leftlinearmf(x, 25, 75)),
('right linear', rightlinearmf(x, 25, 75)),
# fuzzylite:
('cosine', cosinemf(x, 50, 50)),
('inc concave', concavemf(x, 50, 75)),
('dec concave', concavemf(x, 50, 25)),
('spike', spikemf(x, 50, 50)),
('inc ramp', rampmf(x, 25, 75)),
('dec ramp', rampmf(x, 75, 25)),
# Rectangle-ish
('trapezoid', skmemb.trapmf(x, [20, 40, 60, 80])),
('rectangle', rectanglemf(x, 25, 75)),
('singleton', singletonmf(x, 50)),
])
# Example point sets:
ps_tests = [
[(40, 0.5), (60, 1)],
[(10, 0.5), (25, 0.25), (40, 0.75), (80, .5)],
[(0, 1), (40, 0.25), (50, .5), (99, 0)]
]
# Now try some interpolation methods on these:
for method in ['linear', 'lagrange', 'spline', 'cubic']:
tests.update([('{} ex{}'.format(method, i), pointsetmf(x, ps, method))
for i, ps in enumerate(ps_tests)])
return tests
if __name__ == '__main__':
x = np.arange(0, 100)
plots = _plot_mf_for(x)
visualise_all(x, plots.values(), list(plots.keys()))