901 lines
25 KiB
Python
901 lines
25 KiB
Python
"""
|
|
fuzzy_ops.py : Package of general operations on fuzzy sets, fuzzy membership
|
|
functions, and their associated universe variables.
|
|
"""
|
|
|
|
from __future__ import division, print_function
|
|
import numpy as np
|
|
|
|
|
|
def cartadd(x, y):
|
|
"""
|
|
Cartesian addition of fuzzy membership vectors using the algebraic method.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1D array or iterable
|
|
First fuzzy membership vector, of length M.
|
|
y : 1D array or iterable
|
|
Second fuzzy membership vector, of length N.
|
|
|
|
Returns
|
|
-------
|
|
z : 2D array
|
|
Cartesian addition of ``x`` and ``y``, of shape (M, N).
|
|
|
|
"""
|
|
# Ensure rank-1 input
|
|
x, y = np.asarray(x).ravel(), np.asarray(y).ravel()
|
|
b, a = np.meshgrid(y, x, sparse=True)
|
|
return a + b
|
|
|
|
|
|
def cartprod(x, y):
|
|
"""
|
|
Cartesian product of two fuzzy membership vectors. Uses ``min()``.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1D array or iterable
|
|
First fuzzy membership vector, of length M.
|
|
y : 1D array or iterable
|
|
Second fuzzy membership vector, of length N.
|
|
|
|
Returns
|
|
-------
|
|
z : 2D array
|
|
Cartesian product of ``x`` and ``y``, of shape (M, N).
|
|
|
|
"""
|
|
# Ensure rank-1 input
|
|
x, y = np.asarray(x).ravel(), np.asarray(y).ravel()
|
|
b, a = np.meshgrid(y, x, sparse=True)
|
|
return np.fmin(a, b)
|
|
|
|
|
|
def classic_relation(a, b):
|
|
"""
|
|
Determine the classic relation matrix, ``R``, between two fuzzy sets.
|
|
|
|
Parameters
|
|
----------
|
|
a : 1D array or iterable
|
|
First fuzzy membership vector, of length M.
|
|
b : 1D array or iterable
|
|
Second fuzzy membership vector, of length N.
|
|
|
|
Returns
|
|
-------
|
|
R : 2D array
|
|
Classic relation matrix between ``a`` and ``b``, shape (M, N)
|
|
|
|
Notes
|
|
-----
|
|
The classic relation is defined as::
|
|
|
|
r = [a x b] U [(1 - a) x ones(1, N)],
|
|
|
|
where ``x`` represents a cartesian product and ``N`` is len(``b``).
|
|
|
|
"""
|
|
a = np.asarray(a)
|
|
return np.fmax(cartprod(a, b), cartprod(1 - a, np.ones_like(b)))
|
|
|
|
|
|
def contrast(arr, amount=0.2, split=0.5, normalize=True):
|
|
"""
|
|
General contrast booster or diffuser of normalized array-like data.
|
|
|
|
Parameters
|
|
----------
|
|
arr : ndarray
|
|
Input array (of floats on range [0, 1] if ``normalize=False``). If
|
|
values exist outside this range, with ``normalize=True`` the image
|
|
will be normalized for calculation.
|
|
amount : float or length-2 iterable of floats
|
|
Controls the exponential contrast mechanism for values above and below
|
|
``split`` in ``I``. If positive, the curve provides added contrast;
|
|
if negative, the curve provides reduced contrast.
|
|
|
|
If provided as a lenth-2 iterable of floats, they control the regions
|
|
(below, above) ``split`` separately.
|
|
split : float
|
|
Positive scalar, on range [0, 1], determining the midpoint of the
|
|
exponential contrast. Default of 0.5 is reasonable for well-exposed
|
|
images.
|
|
normalize : bool, default True
|
|
Controls normalization to the range [0, 1].
|
|
|
|
Returns
|
|
-------
|
|
focused : ndarray
|
|
Contrast adjusted, normalized, floating-point image on range [0, 1].
|
|
|
|
Notes
|
|
-----
|
|
The result of this algorithm is like applying a Curves adjustment in the
|
|
GIMP or Photoshop.
|
|
|
|
Algorithm for curves adjustment at a given pixel, x, is given by::
|
|
|
|
| split * (x/split)^below, 0 <= x <= split
|
|
y(x) = |
|
|
| 1 - (1-split) * ((1-x) / (1-split))^above, split < x <= 1.0
|
|
|
|
See Also
|
|
--------
|
|
skfuzzy.fuzzymath.sigmoid
|
|
|
|
"""
|
|
# Ensure scalars are floats, to avoid truncating division in Python 2.x
|
|
split = float(split)
|
|
im = arr.astype(float)
|
|
amount_ = np.asarray(amount, dtype=np.float64).ravel()
|
|
|
|
if len(amount_) == 1:
|
|
# One argument -> Equal amount applied on either side of `split`
|
|
above = below = amount_[0]
|
|
else:
|
|
# Two arguments -> Control contrast separately in light/dark regions
|
|
below = amount_[0]
|
|
above = amount_[1]
|
|
|
|
# Normalize if required
|
|
if im.max() > 1. and normalize is True:
|
|
ma = float(im.max())
|
|
im /= float(im.max())
|
|
else:
|
|
ma = 1.
|
|
|
|
focused = np.zeros_like(im, dtype=np.float64)
|
|
|
|
# Simplified array-wise algorithm using fancy indexing rather than looping
|
|
focused[im <= split] = split * (im[im <= split] / split) ** below
|
|
focused[im > split] = (1 - (1. - split) *
|
|
((1 - im[im > split]) / (1. - split)) ** above)
|
|
|
|
# Reapply multiplicative factor
|
|
return focused * ma
|
|
|
|
|
|
def fuzzy_op(x, a, y, b, op):
|
|
"""Operation of two fuzzy sets.
|
|
|
|
Operate fuzzy set ``a`` with fuzzy set ``b``,
|
|
using +, * or any other binary operator.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array, length N
|
|
Universe variable for fuzzy set ``a``.
|
|
a : 1d array, length N
|
|
Fuzzy set for universe ``x``.
|
|
y : 1d array, length M
|
|
Universe variable for fuzzy set ``b``.
|
|
b : 1d array, length M
|
|
Fuzzy set for universe ``y``.
|
|
op: Function, pointwise binary operator on two matrices
|
|
(pointwise version of) +, -, *, /, min, max etc.
|
|
|
|
Returns
|
|
-------
|
|
z : 1d array
|
|
Output variable.
|
|
mfz : 1d array
|
|
Fuzzy membership set for variable ``z``.
|
|
|
|
Notes
|
|
-----
|
|
Uses Zadeh's Extension Principle as described in Ross, Fuzzy Logic with
|
|
Engineering Applications (2010), pp. 414, Eq. 12.17.
|
|
|
|
If these results are unexpected and your membership functions are convex,
|
|
consider trying the ``skfuzzy.dsw_*`` functions for fuzzy mathematics
|
|
using interval arithmetic via the restricted Dong, Shah, and Wong method.
|
|
|
|
"""
|
|
# a and x, and b and y, are formed into (MxN) matrices. The former has
|
|
# identical rows; the latter identical identical columns.
|
|
|
|
yy, xx = np.meshgrid(y, x, sparse=True) # consider broadcasting rules
|
|
bb, aa = np.meshgrid(b, a, sparse=True)
|
|
|
|
# Do the operation
|
|
zz = op(xx, yy).ravel()
|
|
zz_index = np.argsort(zz)
|
|
zz = np.sort(zz)
|
|
|
|
# Array min() operation
|
|
c = np.fmin(aa, bb).ravel()
|
|
c = c[zz_index]
|
|
|
|
# Initialize loop
|
|
z, mfz = np.zeros(0), np.zeros(0)
|
|
idx = 0
|
|
|
|
for _ in range(len(c)):
|
|
index = np.nonzero(zz == zz[idx])[0]
|
|
z = np.hstack((z, zz[idx]))
|
|
mfz = np.hstack((mfz, c[index].max()))
|
|
idx = index[-1] + 1
|
|
if idx >= len(zz):
|
|
break
|
|
|
|
return z, mfz
|
|
|
|
def fuzzy_add(x, a, y, b):
|
|
"""
|
|
Add fuzzy set ``a`` to fuzzy set ``b``.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array, length N
|
|
Universe variable for fuzzy set ``a``.
|
|
a : 1d array, length N
|
|
Fuzzy set for universe ``x``.
|
|
y : 1d array, length M
|
|
Universe variable for fuzzy set ``b``.
|
|
b : 1d array, length M
|
|
Fuzzy set for universe ``y``.
|
|
|
|
Returns
|
|
-------
|
|
z : 1d array
|
|
Output variable.
|
|
mfz : 1d array
|
|
Fuzzy membership set for variable ``z``.
|
|
|
|
Notes
|
|
-----
|
|
Uses Zadeh's Extension Principle as described in Ross, Fuzzy Logic with
|
|
Engineering Applications (2010), pp. 414, Eq. 12.17.
|
|
|
|
If these results are unexpected and your membership functions are convex,
|
|
consider trying the ``skfuzzy.dsw_*`` functions for fuzzy mathematics
|
|
using interval arithmetic via the restricted Dong, Shah, and Wong method.
|
|
|
|
"""
|
|
return fuzzy_op(x, a, y, b, op=np.add)
|
|
|
|
|
|
def fuzzy_compare(q):
|
|
"""
|
|
Determine the comparison matrix, ``c``, based on the fuzzy pairwise
|
|
comparison matrix, ``q``, using Shimura's special relativity formula.
|
|
|
|
Parameters
|
|
----------
|
|
q : 2d array, (N, N)
|
|
Fuzzy pairwise comparison matrix.
|
|
|
|
Returns
|
|
-------
|
|
c : 2d array, (N, N)
|
|
Comparison matrix.
|
|
|
|
"""
|
|
return q.T / np.fmax(q, q.T).astype(np.float)
|
|
|
|
|
|
def fuzzy_div(x, a, y, b):
|
|
"""
|
|
Divide fuzzy set ``b`` into fuzzy set ``a``.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array, length N
|
|
Universe variable for fuzzy set ``a``.
|
|
a : 1d array, length N
|
|
Fuzzy set for universe ``x``.
|
|
y : 1d array, length M (excluding zero array)
|
|
Universe variable for fuzzy set ``b``.
|
|
b : 1d array, length M
|
|
Fuzzy set for universe ``y``.
|
|
|
|
Returns
|
|
-------
|
|
z : 1d array
|
|
Output variable.
|
|
mfz : 1d array
|
|
Fuzzy membership set for variable z.
|
|
|
|
Notes
|
|
-----
|
|
Uses Zadeh's Extension Principle from Ross, Fuzzy Logic w/Engineering
|
|
Applications, (2010), pp.414, Eq. 12.17.
|
|
|
|
If these results are unexpected and your membership functions are convex,
|
|
consider trying the ``skfuzzy.dsw_*`` functions for fuzzy mathematics
|
|
using interval arithmetic via the restricted Dong, Shah, and Wong method.
|
|
|
|
"""
|
|
# a and x, and b and y, are formed into (MxN) matrices. The former has
|
|
# identical rows; the latter identical identical columns.
|
|
if np.all(np.asarray(y) == 0):
|
|
Warning('The 0 value(s) will never be used in the calculation!')
|
|
index = np.where(y == 0)[0]
|
|
np.delete(y, index)
|
|
np.delete(b, index)
|
|
return fuzzy_op(x, a, y, b, op=np.divide)
|
|
|
|
|
|
def fuzzy_min(x, a, y, b):
|
|
"""
|
|
Find minimum between fuzzy set ``a`` fuzzy set ``b``.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array, length N
|
|
Universe variable for fuzzy set ``a``.
|
|
a : 1d array, length N
|
|
Fuzzy set for universe ``x``.
|
|
y : 1d array, length M
|
|
Universe variable for fuzzy set ``b``.
|
|
b : 1d array, length M
|
|
Fuzzy set for universe ``y``.
|
|
|
|
Returns
|
|
-------
|
|
z : 1d array
|
|
Output variable.
|
|
mfz : 1d array
|
|
Fuzzy membership set for variable z.
|
|
|
|
Notes
|
|
-----
|
|
Uses Zadeh's Extension Principle from Ross, Fuzzy Logic w/Engineering
|
|
Applications, (2010), pp.414, Eq. 12.17.
|
|
|
|
If these results are unexpected and your membership functions are convex,
|
|
consider trying the ``skfuzzy.dsw_*`` functions for fuzzy mathematics
|
|
using interval arithmetic via the restricted Dong, Shah, and Wong method.
|
|
|
|
"""
|
|
return fuzzy_op(x, a, y, b, op=np.fmin)
|
|
|
|
|
|
def fuzzy_mult(x, a, y, b):
|
|
"""
|
|
Multiplies fuzzy set ``a`` and fuzzy set ``b``.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array, length N
|
|
Universe variable for fuzzy set ``a``.
|
|
A : 1d array, length N
|
|
Fuzzy set for universe ``x``.
|
|
y : 1d array, length M
|
|
Universe variable for fuzzy set ``b``.
|
|
b : 1d array, length M
|
|
Fuzzy set for universe ``y``.
|
|
|
|
Returns
|
|
-------
|
|
z : 1d array
|
|
Output variable.
|
|
mfz : 1d array
|
|
Fuzzy membership set for variable z.
|
|
|
|
Notes
|
|
-----
|
|
Uses Zadeh's Extension Principle from Ross, Fuzzy Logic w/Engineering
|
|
Applications, (2010), pp.414, Eq. 12.17.
|
|
|
|
If these results are unexpected and your membership functions are convex,
|
|
consider trying the ``skfuzzy.dsw_*`` functions for fuzzy mathematics
|
|
using interval arithmetic via the restricted Dong, Shah, and Wong method.
|
|
|
|
"""
|
|
return fuzzy_op(x, a, y, b, op=np.multiply)
|
|
|
|
|
|
def fuzzy_sub(x, a, y, b):
|
|
"""
|
|
Subtract fuzzy set ``b`` from fuzzy set ``a``.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array, length N
|
|
Universe variable for fuzzy set ``a``.
|
|
A : 1d array, length N
|
|
Fuzzy set for universe ``x``.
|
|
y : 1d array, length M
|
|
Universe variable for fuzzy set ``b``.
|
|
b : 1d array, length M
|
|
Fuzzy set for universe ``y``.
|
|
|
|
Returns
|
|
-------
|
|
z : 1d array
|
|
Output variable.
|
|
mfz : 1d array
|
|
Fuzzy membership set for variable z.
|
|
|
|
Notes
|
|
-----
|
|
Uses Zadeh's Extension Principle from Ross, Fuzzy Logic w/Engineering
|
|
Applications, (2010), pp.414, Eq. 12.17.
|
|
|
|
If these results are unexpected and your membership functions are convex,
|
|
consider trying the ``skfuzzy.dsw_*`` functions for fuzzy mathematics
|
|
using interval arithmetic via the restricted Dong, Shah, and Wong method.
|
|
|
|
"""
|
|
return fuzzy_op(x, a, y, b, op=np.subtract)
|
|
|
|
|
|
def inner_product(a, b):
|
|
"""
|
|
Inner product (dot product) of two fuzzy sets.
|
|
|
|
Parameters
|
|
----------
|
|
a : 1d array or iterable
|
|
Fuzzy membership function.
|
|
b : 1d array or iterable
|
|
Fuzzy membership function.
|
|
|
|
Returns
|
|
-------
|
|
y : float
|
|
Fuzzy inner product value, on range [0, 1]
|
|
|
|
"""
|
|
return np.max(np.fmin(np.r_[a], np.r_[b]))
|
|
|
|
|
|
def interp10(x):
|
|
"""
|
|
Utility function which conducts linear interpolation of any rank-1 array.
|
|
Result will have 10x resolution.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array, length N
|
|
Input array to be interpolated.
|
|
|
|
Returns
|
|
-------
|
|
y : 1d array, length 10 * N + 1
|
|
Linearly interpolated output.
|
|
|
|
"""
|
|
L = len(x)
|
|
return np.interp(np.r_[0:L - 0.9:0.1], range(L), x)
|
|
|
|
|
|
def maxmin_composition(s, r):
|
|
"""
|
|
The max-min composition ``t`` of two fuzzy relation matrices.
|
|
|
|
Parameters
|
|
----------
|
|
s : 2d array, (M, N)
|
|
Fuzzy relation matrix #1.
|
|
r : 2d array, (N, P)
|
|
Fuzzy relation matrix #2.
|
|
|
|
Returns
|
|
-------
|
|
T ; 2d array, (M, P)
|
|
Max-min composition, defined by ``T = s o r``.
|
|
|
|
"""
|
|
if s.ndim < 2:
|
|
s = np.atleast_2d(s)
|
|
if r.ndim < 2:
|
|
r = np.atleast_2d(r).T
|
|
m = s.shape[0]
|
|
p = r.shape[1]
|
|
t = np.zeros((m, p))
|
|
|
|
for pp in range(p):
|
|
for mm in range(m):
|
|
t[mm, pp] = (np.fmin(s[mm, :], r[:, pp].T)).max()
|
|
|
|
return t
|
|
|
|
|
|
def maxprod_composition(s, r):
|
|
"""
|
|
The max-product composition ``t`` of two fuzzy relation matrices.
|
|
|
|
Parameters
|
|
----------
|
|
s : 2d array, (M, N)
|
|
Fuzzy relation matrix #1.
|
|
r : 2d array, (N, P)
|
|
Fuzzy relation matrix #2.
|
|
|
|
Returns
|
|
-------
|
|
t : 2d array, (M, P)
|
|
Max-product composition matrix.
|
|
|
|
"""
|
|
if s.ndim < 2:
|
|
s = np.atleast_2d(s)
|
|
if r.ndim < 2:
|
|
r = np.atleast_2d(r).T
|
|
m = s.shape[0]
|
|
p = r.shape[1]
|
|
t = np.zeros((m, p))
|
|
|
|
for mm in range(m):
|
|
for pp in range(p):
|
|
t[mm, pp] = (s[mm, :] * r[:, pp].T).max()
|
|
|
|
return t
|
|
|
|
|
|
def interp_membership(x, xmf, xx, zero_outside_x=True):
|
|
"""
|
|
Find the degree of membership ``u(xx)`` for a given value of ``x = xx``.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array
|
|
Independent discrete variable vector.
|
|
xmf : 1d array
|
|
Fuzzy membership function for ``x``. Same length as ``x``.
|
|
xx : float or array of floats
|
|
Value(s) on universe ``x`` where the interpolated membership is
|
|
desired.
|
|
zero_outside_x : bool, optional
|
|
Defines the behavior if ``xx`` contains value(s) which are outside the
|
|
universe range as defined by ``x``. If `True` (default), all
|
|
extrapolated values will be zero. If `False`, the first or last value
|
|
in ``x`` will be what is returned to the left or right of the range,
|
|
respectively.
|
|
|
|
Returns
|
|
-------
|
|
xxmf : float or array of floats
|
|
Membership function value at ``xx``, ``u(xx)``. If ``xx`` is a single
|
|
value, this will be a single value; if it is an array or iterable the
|
|
result will be returned as a NumPy array of like shape.
|
|
|
|
Notes
|
|
-----
|
|
For use in Fuzzy Logic, where an interpolated discrete membership function
|
|
u(x) for discrete values of x on the universe of ``x`` is given. Then,
|
|
consider a new value x = xx, which does not correspond to any discrete
|
|
values of ``x``. This function computes the membership value ``u(xx)``
|
|
corresponding to the value ``xx`` using linear interpolation.
|
|
|
|
"""
|
|
# Not much beats NumPy's built-in interpolation
|
|
if not zero_outside_x:
|
|
kwargs = (None, None)
|
|
else:
|
|
kwargs = (0.0, 0.0)
|
|
return np.interp(xx, x, xmf, left=kwargs[0], right=kwargs[1])
|
|
|
|
|
|
def interp_universe(x, xmf, y):
|
|
"""
|
|
Find interpolated universe value(s) for a given fuzzy membership value.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array
|
|
Independent discrete variable vector.
|
|
xmf : 1d array
|
|
Fuzzy membership function for ``x``. Same length as ``x``.
|
|
y : float
|
|
Specific fuzzy membership value.
|
|
|
|
Returns
|
|
-------
|
|
xx : list
|
|
List of discrete singleton values on universe ``x`` whose
|
|
membership function value is y, ``u(xx[i])==y``.
|
|
If there are not points xx[i] such that ``u(xx[i])==y``
|
|
it returns an empty list.
|
|
|
|
Notes
|
|
-----
|
|
For use in Fuzzy Logic, where a membership function level ``y`` is given.
|
|
Consider there is some value (or set of values) ``xx`` for which
|
|
``u(xx) == y`` is true, though ``xx`` may not correspond to any discrete
|
|
values on ``x``. This function computes the value (or values) of ``xx``
|
|
such that ``u(xx) == y`` using linear interpolation.
|
|
|
|
"""
|
|
# Special case required or zero-level cut does not work with faster method
|
|
if y == 0.:
|
|
idx = np.where(np.diff(xmf > y))[0]
|
|
else:
|
|
idx = np.where(np.diff(xmf >= y))[0]
|
|
xx = x[idx] + (y-xmf[idx]) * (x[idx+1]-x[idx]) / (xmf[idx+1]-xmf[idx])
|
|
|
|
# The above method is fast, but duplicates point values where
|
|
# y == peak of a membership function. Ducking briefly into a set
|
|
# elimniates this. Benchmarked multiple ways; this is by far the fastest.
|
|
# Speed penalty approximately 10%, worth it.
|
|
return [n for n in set(xx.tolist())]
|
|
|
|
|
|
def _interp_universe_fast(x, xmf, y):
|
|
"""
|
|
Find interpolated universe value(s) for a given fuzzy membership value.
|
|
|
|
Fast version, with possible duplication.
|
|
|
|
Parameters
|
|
----------
|
|
x : 1d array
|
|
Independent discrete variable vector.
|
|
xmf : 1d array
|
|
Fuzzy membership function for ``x``. Same length as ``x``.
|
|
y : float
|
|
Specific fuzzy membership value.
|
|
|
|
Returns
|
|
-------
|
|
xx : list
|
|
List of discrete singleton values on universe ``x`` whose
|
|
membership function value is y, ``u(xx[i])==y``.
|
|
If there are not points xx[i] such that ``u(xx[i])==y``
|
|
it returns an empty list.
|
|
|
|
Notes
|
|
-----
|
|
For use in Fuzzy Logic, where a membership function level ``y`` is given.
|
|
Consider there is some value (or set of values) ``xx`` for which
|
|
``u(xx) == y`` is true, though ``xx`` may not correspond to any discrete
|
|
values on ``x``. This function computes the value (or values) of ``xx``
|
|
such that ``u(xx) == y`` using linear interpolation.
|
|
"""
|
|
# Special case required or zero-level cut does not work with faster method
|
|
if y == 0.:
|
|
idx = np.where(np.diff(xmf > y))[0]
|
|
else:
|
|
idx = np.where(np.diff(xmf >= y))[0]
|
|
|
|
# This method is fast, but duplicates point values where
|
|
# y == peak of a membership function.
|
|
return x[idx] + (y-xmf[idx]) * (x[idx+1]-x[idx]) / (xmf[idx+1]-xmf[idx])
|
|
|
|
|
|
def modus_ponens(a, b, ap, c=None):
|
|
"""
|
|
Generalized *modus ponens* deduction to make approximate reasoning in a
|
|
rules-base system.
|
|
|
|
Parameters
|
|
----------
|
|
a : 1d array
|
|
Fuzzy set ``a`` on universe ``x``
|
|
b : 1d array
|
|
Fuzzy set ``b`` on universe ``y``
|
|
ap : 1d array
|
|
New fuzzy fact a' (a prime, not transpose)
|
|
c : 1d array, OPTIONAL
|
|
Keyword argument representing fuzzy set ``c`` on universe ``y``.
|
|
Default = None, which will use ``np.ones()`` instead.
|
|
|
|
Returns
|
|
-------
|
|
R : 2d array
|
|
Full fuzzy relation.
|
|
bp : 1d array
|
|
Fuzzy conclusion b' (b prime)
|
|
|
|
"""
|
|
if c is None:
|
|
c = np.ones_like(b)
|
|
r = np.fmax(cartprod(a, b), cartprod(1 - a, c))
|
|
bp = maxmin_composition(ap, r)
|
|
return r, bp.squeeze()
|
|
|
|
|
|
def outer_product(a, b):
|
|
"""
|
|
Outer product of two fuzzy sets.
|
|
|
|
Parameters
|
|
----------
|
|
a : 1d array or iterable
|
|
Fuzzy membership function.
|
|
b : 1d array or iterable
|
|
Fuzzy membership function.
|
|
|
|
Returns
|
|
-------
|
|
y : float
|
|
Fuzzy outer product value, on range [0, 1]
|
|
|
|
"""
|
|
return np.min(np.fmax(np.r_[a], np.r_[b]))
|
|
|
|
|
|
def relation_min(a, b):
|
|
"""
|
|
Determine fuzzy relation matrix ``R`` using Mamdani implication for the
|
|
fuzzy antecedent ``a`` and consequent ``b`` inputs.
|
|
|
|
Parameters
|
|
----------
|
|
a : 1d array
|
|
Fuzzy antecedent variable of length M.
|
|
b : 1d array
|
|
Fuzzy consequent variable of length N.
|
|
|
|
Returns
|
|
-------
|
|
R : 2d array
|
|
Fuzzy relation between ``a`` and ``b``, of shape (M, N).
|
|
|
|
"""
|
|
bb, aa = np.meshgrid(b, a, sparse=True)
|
|
return np.fmin(aa, bb)
|
|
|
|
|
|
def relation_product(a, b):
|
|
"""
|
|
Determine the fuzzy relation matrix, ``R``, using product implication for
|
|
the fuzzy antecedent ``a`` and the fuzzy consequent ``b``.
|
|
|
|
Parameters
|
|
----------
|
|
a : 1d array
|
|
Fuzzy antecedent variable of length M.
|
|
b : 1d array
|
|
Fuzzy consequent variable of length N.
|
|
|
|
Returns
|
|
-------
|
|
R : 2d array
|
|
Fuzzy relation between ``a`` and ``b``, of shape (M, N).
|
|
|
|
"""
|
|
bb, aa = np.meshgrid(b, a, sparse=True)
|
|
return aa * bb
|
|
|
|
|
|
def fuzzy_similarity(ai, b, mode='min'):
|
|
"""
|
|
The fuzzy similarity between set ``ai`` and observation set ``b``.
|
|
|
|
Parameters
|
|
----------
|
|
ai : 1d array
|
|
Fuzzy membership function of set ``ai``.
|
|
b : 1d array
|
|
Fuzzy membership function of set ``b``.
|
|
mode : string
|
|
Controls the method of similarity calculation.
|
|
* ``'min'`` : Computed by array minimum operation.
|
|
* ``'avg'`` : Computed by taking the array average.
|
|
|
|
Returns
|
|
-------
|
|
s : float
|
|
Fuzzy similarity.
|
|
|
|
"""
|
|
if 'min' in mode.lower():
|
|
return min(inner_product(ai, b), 1 - outer_product(ai, b))
|
|
else:
|
|
return (inner_product(ai, b) + (1 - outer_product(ai, b))) / 2.
|
|
|
|
|
|
def partial_dmf(x, mf_name, mf_parameter_dict, partial_parameter):
|
|
"""
|
|
Calculate the *partial derivative* of a specified membership function.
|
|
|
|
Parameters
|
|
----------
|
|
x : float
|
|
input variable.
|
|
mf_name : string
|
|
Membership function name as a string. The following are supported:
|
|
* ``'gaussmf'`` : parameters ``'sigma'`` or ``'mean'``
|
|
* ``'gbellmf'`` : parameters ``'a'``, ``'b'``, or ``'c'``
|
|
* ``'sigmf'`` : parameters ``'b'`` or ``'c'``
|
|
mf_parameter_dict : dict
|
|
A dictionary of ``{param : key-value, ...}`` pairs for a particular
|
|
membership function as defined above.
|
|
partial_parameter : string
|
|
Name of the parameter against which we take the partial derivative.
|
|
|
|
Returns
|
|
-------
|
|
d : float
|
|
Partial derivative of the membership function with respect to the
|
|
chosen parameter, at input point ``x``.
|
|
|
|
Notes
|
|
-----
|
|
Partial derivatives of fuzzy membership functions are only meaningful for
|
|
continuous functions. Triangular, trapezoidal designs have no partial
|
|
derivatives to calculate. The following
|
|
"""
|
|
|
|
if mf_name == 'gaussmf':
|
|
|
|
sigma = mf_parameter_dict['sigma']
|
|
mean = mf_parameter_dict['mean']
|
|
|
|
if partial_parameter == 'sigma':
|
|
result = ((2. / sigma**3) *
|
|
np.exp(-(((x - mean)**2) / (sigma)**2)) * (x - mean)**2)
|
|
elif partial_parameter == 'mean':
|
|
result = ((2. / sigma**2) *
|
|
np.exp(-(((x - mean)**2) / (sigma)**2)) * (x - mean))
|
|
|
|
elif mf_name == 'gbellmf':
|
|
|
|
a = mf_parameter_dict['a']
|
|
b = mf_parameter_dict['b']
|
|
c = mf_parameter_dict['c']
|
|
|
|
# Partial result for speed and conciseness in derived eqs below
|
|
d = np.abs((c - x) / a)
|
|
|
|
if partial_parameter == 'a':
|
|
result = ((2. * b * (c - x)**2.) * d**((2 * b) - 2) /
|
|
(a**3. * (d**(2. * b) + 1)**2.))
|
|
|
|
elif partial_parameter == 'b':
|
|
result = (-1 * (2 * d**(2. * b) * np.log(d)) /
|
|
((d**(2. * b) + 1)**2.))
|
|
|
|
elif partial_parameter == 'c':
|
|
result = ((2. * b * (x - c) * d**((2. * b) - 2)) /
|
|
(a**2. * (d**(2. * b) + 1)**2.))
|
|
|
|
elif mf_name == 'sigmf':
|
|
|
|
b = mf_parameter_dict['b']
|
|
c = mf_parameter_dict['c']
|
|
|
|
if partial_parameter == 'b':
|
|
# Partial result for speed and conciseness
|
|
d = np.exp(c * (b + x))
|
|
result = -1 * (c * d) / (np.exp(b * c) + np.exp(c * x))**2.
|
|
|
|
elif partial_parameter == 'c':
|
|
# Partial result for speed and conciseness
|
|
d = np.exp(c * (x - b))
|
|
result = ((x - b) * d) / (d + 1)**2.
|
|
|
|
return result
|
|
|
|
|
|
def sigmoid(x, power, split=0.5):
|
|
"""
|
|
Intensify grayscale values in an array using a sigmoid function.
|
|
|
|
Parameters
|
|
----------
|
|
x : ndarray
|
|
Input vector or image array. Should be pre-normalized to range [0, 1]
|
|
p : float
|
|
Power of the intensification (p > 0). Experiment with small, decimal
|
|
values and increase as necessary.
|
|
split : float
|
|
Threshold for intensification. Values above ``split`` will be
|
|
intensified, while values below `split` will be deintensified. Note
|
|
range for ``split`` is (0, 1). Default of 0.5 is reasonable for many
|
|
well-exposed images.
|
|
|
|
Returns
|
|
-------
|
|
y : ndarray, same size as x
|
|
Output vector or image with contrast adjusted.
|
|
|
|
Notes
|
|
-----
|
|
The sigmoid used herein is defined as::
|
|
|
|
y = 1 / (1 + exp(- exp(- power * (x-split))))
|
|
|
|
See Also
|
|
--------
|
|
skfuzzy.fuzzymath.contrast
|
|
"""
|
|
|
|
return 1. / (1. + np.exp(- power * (x - split)))
|