"""
generatemf.py: Library of standard fuzzy membership function generators.
"""
import numpy as np
def _nearest(x, y0):
"""
Finds the index of the sequence elemnt value x0 in `x` that is closest
to the provided value, `y0`.
Parameters
----------
x : 1d array
Input sequence.
y0 : float
Desired matching value.
Returns
-------
idx0 : int
Index of the nearest value `x0` in x; e.g. x[idx0] = x0.
x0 : float
Value in `x` which is closest to `y0`.
Notes
-----
This function does support extrapolation.
"""
# Distance map
d = np.abs(x - y0)
idx0 = np.nonzero(d == d.min())[0][0]
return idx0, x[idx0]
[docs]def dsigmf(x, b1, c1, b2, c2):
"""
Difference of two fuzzy sigmoid membership functions.
Parameters
----------
x : 1d array
Independent variable.
b1 : float
Midpoint of first sigmoid; f1(b1) = 0.5
c1 : float
Width and sign of first sigmoid.
b2 : float
Midpoint of second sigmoid; f2(b2) = 0.5
c2 : float
Width and sign of second sigmoid.
Returns
-------
y : 1d array
Generated sigmoid values, defined as
y = f1 - f2
f1(x) = 1 / (1. + exp[- c1 * (x - b1)])
f2(x) = 1 / (1. + exp[- c2 * (x - b2)])
"""
return sigmf(x, b1, c=c1) - sigmf(x, b2, c=c2)
[docs]def gaussmf(x, mean, sigma):
"""
Gaussian fuzzy membership function.
Parameters
----------
x : 1d array or iterable
Independent variable.
mean : float
Gaussian parameter for center (mean) value.
sigma : float
Gaussian parameter for standard deviation.
Returns
-------
y : 1d array
Gaussian membership function for x
"""
return np.exp(-((x - mean) ** 2.) / float(sigma) ** 2.)
[docs]def gauss2mf(x, mean1, sigma1, mean2, sigma2):
"""
Gaussian fuzzy membership function of two combined Gaussians.
Parameters
----------
x : 1d array or iterable
Independent variable.
mean1 : float
Gaussian parameter for center (mean) value of left-side Gaussian.
Note mean1 <= mean2 reqiured.
sigma1 : float
Standard deviation of left Gaussian.
mean2 : float
Gaussian parameter for center (mean) value of right-side Gaussian.
Note mean2 >= mean1 required.
sigma2 : float
Standard deviation of right Gaussian.
Returns
-------
y : 1d array
Membership function with left side up to `mean1` defined by the first
Gaussian, and the right side above `mean2` defined by the second.
In the range mean1 <= x <= mean2 the function has value = 1.
"""
assert mean1 <= mean2, 'mean1 <= mean2 is required. See docstring.'
y = np.ones(len(x))
idx1 = x <= mean1
idx2 = x > mean2
y[idx1] = gaussmf(x[idx1], mean1, sigma1)
y[idx2] = gaussmf(x[idx2], mean2, sigma2)
return y
[docs]def gbellmf(x, a, b, c):
"""
Generalized Bell function fuzzy membership generator.
Parameters
----------
x : 1d array
Independent variable.
a : float
Bell function parameter controlling width. See Note for definition.
b : float
Bell function parameter controlling center. See Note for definition.
c : float
Bell function parameter controlling slope. See Note for definition.
Returns
-------
y : 1d array
Generalized Bell fuzzy membership function.
Notes
-----
Definition of Generalized Bell function is:
y(x) = 1 / (1 + abs([x - c] / a) ** [2 * b])
"""
return 1. / (1. + np.abs((x - c) / a) ** (2 * b))
[docs]def piecemf(x, abc):
"""
Piecewise linear membership function (particularly used in FIRE filters).
Parameters
----------
x : 1d array
Independent variable vector.
abc : 1d array, length 3
Defines the piecewise function. Important: if abc = [a, b, c] then
a <= b <= c is REQUIRED!
Returns
-------
y : 1d array
Piecewise fuzzy membership function for x.
Notes
-----
Piecewise definition:
y = 0, min(x) <= x <= a
y = b(x - a)/c(b - a), a <= x <= b
y = x/c, b <= x <= c
"""
a, b, c = abc
if c != x.max():
c = x.max()
assert a <= b and b <= c, '`abc` requires a <= b <= c.'
n = len(x)
y = np.zeros(n)
idx0 = _nearest(x, 0)[0]
idxa = _nearest(x, a)[0]
idxb = _nearest(x, b)[0]
n = np.r_[0:n - idx0]
y[idx0 + n] = n / float(c)
y[idx0:idxa] = 0
m = np.r_[0:idxb - idxa]
y[idxa:idxb] = b * m / (float(c) * (b - a))
return y / y.max()
[docs]def pimf(x, a, b, c, d):
"""
Pi-function fuzzy membership generator.
Parameters
----------
x : 1d array
Independent variable.
a : float
Left 'foot', where the function begins to climb from zero.
b : float
Left 'ceiling', where the function levels off at 1.
c : float
Right 'ceiling', where the function begins falling from 1.
d : float
Right 'foot', where the function reattains zero.
Returns
-------
y : 1d array
Pi-function.
Notes
-----
This is equivalently a product of smf and zmf.
"""
y = np.ones(len(x))
assert a <= b and b <= c and c <= d, 'a <= b <= c <= d is required.'
idx = x <= a
y[idx] = 0
idx = np.logical_and(a <= x, x <= (a + b) / 2.)
y[idx] = 2. * ((x[idx] - a) / (b - a)) ** 2.
idx = np.logical_and((a + b) / 2. < x, x <= b)
y[idx] = 1 - 2. * ((x[idx] - b) / (b - a)) ** 2.
idx = np.logical_and(c <= x, x < (c + d) / 2.)
y[idx] = 1 - 2. * ((x[idx] - c) / (d - c)) ** 2.
idx = np.logical_and((c + d) / 2. <= x, x <= d)
y[idx] = 2. * ((x[idx] - d) / (d - c)) ** 2.
idx = x >= d
y[idx] = 0
return y
[docs]def psigmf(x, b1, c1, b2, c2):
"""
Product of two sigmoid membership functions.
Parameters
----------
x : 1d array
Data vector for independent variable.
b1 : float
Offset or bias for the first sigmoid. This is the center value of the
sigmoid, where it equals 1/2.
c1 : float
Controls 'width' of the first sigmoidal region about `b1` (magnitude),
and also which side of the function is open (sign). A positive value of
`c1` means the left side approaches zero while the right side
approaches one; a negative value of `c1` means the opposite.
b2 : float
Offset or bias for the second sigmoid. This is the center value of the
sigmoid, where it equals 1/2.
c2 : float
Controls 'width' of the second sigmoidal region about `b2` (magnitude),
and also which side of the function is open (sign). A positive value of
`c2` means the left side approaches zero while the right side
approaches one; a negative value of `c2` means the opposite.
Returns
-------
y : 1d array
Generated sigmoid values, defined as
y = f1(x) * f2(x)
f1(x) = 1 / (1. + exp[- c1 * (x - b1)])
f2(x) = 1 / (1. + exp[- c2 * (x - b2)])
Notes
-----
For a smoothed rect-like function, c2 < 0 < c1. For its inverse (zero in
middle, one at edges) c1 < 0 < c2.
"""
return sigmf(x, b1, c1) * sigmf(x, b2, c2)
def sigmoid(wx, b):
"""
Generates a sigmoid function.
Parameters
----------
wx : 2d array, (K, N)
Sum of the inner product of W and X, where W is a KxM data matrix
and X is a MxN weight matrix.
b : 1d array, length K
Bias or threshold.
Returns
-------
sigmoid : 2d array, (K, N)
Sigmoid function result.
"""
return 1. / (1. + np.exp(-(wx + np.dot(np.atleast_2d(b).T,
np.ones((1, wx.shape[1]))))))
[docs]def sigmf(x, b, c):
"""
The basic sigmoid membership function generator.
Parameters
----------
x : 1d array
Data vector for independent variable.
b : float
Offset or bias. This is the center value of the sigmoid, where it
equals 1/2.
c : float
Controls 'width' of the sigmoidal region about `b` (magnitude); also
which side of the function is open (sign). A positive value of `a`
means the left side approaches 0.0 while the right side approaches 1.;
a negative value of `c` means the opposite.
Returns
-------
y : 1d array
Generated sigmoid values, defined as y = 1 / (1. + exp[- c * (x - b)])
Notes
-----
These are the same values, provided separately and in the opposite order
compared to the publicly available MathWorks' Fuzzy Logic Toolbox
documentation. Pay close attention to above docstring!
"""
return 1. / (1. + np.exp(- c * (x - b)))
[docs]def smf(x, a, b):
"""
S-function fuzzy membership generator.
Parameters
----------
x : 1d array
Independent variable.
a : float
'foot', where the function begins to climb from zero.
b : float
'ceiling', where the function levels off at 1.
Returns
-------
y : 1d array
S-function.
Notes
-----
Named such because of its S-like shape.
"""
assert a <= b, 'a <= b is required.'
y = np.ones(len(x))
idx = x <= a
y[idx] = 0
idx = np.logical_and(a <= x, x <= (a + b) / 2.)
y[idx] = 2. * ((x[idx] - a) / (b - a)) ** 2.
idx = np.logical_and((a + b) / 2. <= x, x <= b)
y[idx] = 1 - 2. * ((x[idx] - b) / (b - a)) ** 2.
return y
[docs]def trapmf(x, abcd):
"""
Trapezoidal membership function generator.
Parameters
----------
x : 1d array
Independent variable.
abcd : 1d array, length 4
Four-element vector. Ensure a <= b <= c <= d.
Returns
-------
y : 1d array
Trapezoidal membership function.
"""
assert len(abcd) == 4, 'abcd parameter must have exactly four elements.'
a, b, c, d = np.r_[abcd]
assert a <= b and b <= c and c <= d, 'abcd requires the four elements \
a <= b <= c <= d.'
y = np.ones(len(x))
idx = np.nonzero(x <= b)[0]
y[idx] = trimf(x[idx], np.r_[a, b, b])
idx = np.nonzero(x >= c)[0]
y[idx] = trimf(x[idx], np.r_[c, c, d])
idx = np.nonzero(x < a)[0]
y[idx] = np.zeros(len(idx))
idx = np.nonzero(x > d)[0]
y[idx] = np.zeros(len(idx))
return y
[docs]def trimf(x, abc):
"""
Triangular membership function generator.
Parameters
----------
x : 1d array
Independent variable.
abc : 1d array, length 3
Three-element vector controlling shape of triangular function.
Requires a <= b <= c.
Returns
-------
y : 1d array
Triangular membership function.
"""
assert len(abc) == 3, 'abc parameter must have exactly three elements.'
a, b, c = np.r_[abc] # Zero-indexing in Python
assert a <= b and b <= c, 'abc requires the three elements a <= b <= c.'
y = np.zeros(len(x))
# Left side
if a != b:
idx = np.nonzero(np.logical_and(a < x, x < b))[0]
y[idx] = (x[idx] - a) / float(b - a)
# Right side
if b != c:
idx = np.nonzero(np.logical_and(b < x, x < c))[0]
y[idx] = (c - x[idx]) / float(c - b)
idx = np.nonzero(x == b)
y[idx] = 1
return y
[docs]def zmf(x, a, b):
"""
Z-function fuzzy membership generator.
Parameters
----------
x : 1d array
Independent variable.
a : float
'ceiling', where the function begins falling from 1.
b : float
'foot', where the function reattains zero.
Returns
-------
y : 1d array
Z-function.
Notes
-----
Named such because of its Z-like shape.
"""
assert a <= b, 'a <= b is required.'
y = np.ones(len(x))
idx = np.logical_and(a <= x, x < (a + b) / 2.)
y[idx] = 1 - 2. * ((x[idx] - a) / (b - a)) ** 2.
idx = np.logical_and((a + b) / 2. <= x, x <= b)
y[idx] = 2. * ((x[idx] - b) / (b - a)) ** 2.
idx = x >= b
y[idx] = 0
return y