Source code for FuzzySystem.membership_function

# Copyright (c) 2020 Raul Navarro-Almanza,
#   Universidad Autónoma de Baja California
#
# SPDX-License-Identifier: MIT
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT

import matplotlib.pyplot as plt
import numpy as np

from FuzzySystem import config


[docs]def divide(x, y): '''Perform deviation with clip value [, MAX float] :param x: value x :param y: value y :return: x/y, if y equals 0, then return the biggest float value ''' if y == 0: return float('inf') else: return x / y
[docs]class MembershipFunction: '''Abstract class to define a Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Membership Function' '''Default reference name''' def __init__(self, params, universe=None, name=None, complement=False): self.__complement = complement self.params = params if name is not None: self.name = name if universe is not None: self.universe = universe elif self.params is not None: self.universe = [self.params[0], self.params[-1]] else: self.universe = [-10, 10]
[docs] def eval(self, x): ''' Evaluates the membership function given a input x :param x: input :type x: number, list. :return: resulted value(s) of the evaluation ''' if self.__complement: return 1 - self.compute(x) else: return self.compute(x)
[docs] def compute(self, x): '''Perform the evaluation of the membership function :param x: Input :type x: number, list, numpy array :return: evaluation result ''' pass
[docs] def complement(self): '''Performs the complement evaluation to the membership function :return: self ''' self.__complement = not self.__complement return self
@property def area(self): '''Calculates the area of the membership function :return: (float) area ''' pass @property def centroid(self): '''Calculates the centroid of the membership function :return: (float) centroid ''' pass @property def spread(self): '''Calculates the spread of the membership function :return: (float) spread ''' pass
[docs] def set_params(self, params): '''Set the new parameters to design the membership function :param params: list of membership function design parameters ''' pass
[docs] def show(self, points=config.default_points, axes=None, fmt='-', kwargs={}): '''Plots the membership function :param points: number of points to evaluate the membership function :param axes: for external plotting. :type axes: plt.axes :param fmt: style format of the line :param kwargs: additional values for plt ''' u = np.linspace(self.universe[0], self.universe[1], num=points, endpoint=True, retstep=False, dtype=None) c = [self.eval(e) for e in u] if not axes: fig, ax = plt.subplots() else: ax = axes ax.plot(u, c, fmt, label=self.name, **kwargs) ax.legend(loc='best', fontsize='x-large', fancybox=True, framealpha=0.5) ax.grid() if self.__complement: plt.title("complement of {}".format(self.name)) else: plt.title(self.name) if not axes: plt.show()
def __str__(self): return "class: {0} params: {1}".format(self.__class__.__name__, self.params)
[docs]class Trimf(MembershipFunction): '''Class to define a Triangular Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Triangular mf' def __init__(self, params, universe=None, name=None, complement=False): self.set_params(params) super().__init__(params, universe, name, complement)
[docs] def compute(self, x): return np.maximum( np.minimum((x - self.a) / (self.b - self.a), (self.c - x) / (self.c - self.b)), 0)
[docs] def area(self): return (self.c - self.a) / 2.0
[docs] def centroid(self): return (self.a + self.b + self.c) / 3.0
@property def spread(self): return self.c - self.a
[docs] def set_params(self, params): self.a = params[0] self.b = params[1] self.c = params[2]
[docs]class Gaussmf(MembershipFunction): '''Class to define a Gaussian Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Gaussian mf' def __init__(self, params, universe=None, name=None, complement=False): self.set_params(params) super().__init__(params, universe, name, complement)
[docs] def compute(self, x): return np.exp(-1 * (x - self.c) ** 2 / (2.0 * self.sigma ** 2))
[docs] def area(self): return self.sigma * np.sqrt(2.0 * np.pi)
[docs] def centroid(self): return self.c
@property def spread(self): return self.sigma
[docs] def set_params(self, params): self.sigma = params[0] self.c = params[1]
[docs]class Logmf(MembershipFunction): '''Class to define a Logistic Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Logistic mf' def __init__(self, params, universe=None, name=None, complement=False): self.set_params(params) super().__init__(params, universe, name, complement)
[docs] def compute(self, x): return 2. / (1 + np.exp(((x - self.c) / self.a) ** 2))
@property def spread(self): return self.a
[docs] def set_params(self, params): self.a = params[0] self.c = params[1]
[docs]class Tanhmf(MembershipFunction): '''Class to define a Tanh Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Tanh mf' def __init__(self, params, universe=None, name=None, complement=False): self.set_params(params) super().__init__(params, universe, name, complement)
[docs] def compute(self, x): y = 1 + np.tanh(-1 * ((x - self.c) / self.a) ** 2) return y
@property def spread(self): return self.a
[docs] def set_params(self, params): self.a = params[0] self.c = params[1]
[docs]class Sigmoidmf(MembershipFunction): '''Class to define a Sigmoid Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Sigmoid mf' def __init__(self, params, universe=None, name=None, complement=False): self.set_params(params) super().__init__(params, universe, name, complement)
[docs] def compute(self, x): y = 1. / (1 + np.exp(-self.a * (x - self.c))) return y
@property def spread(self): return self.a
[docs] def set_params(self, params): self.a = params[0] self.c = params[1]
[docs]class Cauchymf(MembershipFunction): '''Class to define a Caouchy Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Cauchy mf' def __init__(self, params, universe=None, name=None, complement=False): self.set_params(params) super().__init__(params, universe, name, complement)
[docs] def compute(self, x): y = 1. / (1 + ((x - self.c) / self.a) ** 2) return y
@property def spread(self): return self.a
[docs] def set_params(self, params): self.a = params[0] self.c = params[1]
[docs]class Trapmf(MembershipFunction): '''Class to define a Trapezoidal Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Trapezoidal mf' def __init__(self, params, universe=None, name=None, complement=False): self.set_params(params) super().__init__(params, universe, name, complement)
[docs] def compute(self, x): if isinstance(x, ( list, np.ndarray, )): return np.array([ max( min(divide((xi - self.a), float(self.b - self.a)), 1, divide((self.d - xi), float(self.d - self.c))), 0) for xi in x ]) else: return max( min(divide((x - self.a), float(self.b - self.a)), 1, divide((self.d - x), float(self.d - self.c))), 0)
@property def spread(self): return self.d - self.a
[docs] def area(self): return (self.d - self.a + self.c - self.b) / 2.0
[docs] def centroid(self): return (self.d**2 + self.c * self.d + self.c**2 - self.a**2 - self.a * self.b - self.b**2) / (3 * ( (self.d - self.a + self.c - self.b)))
[docs] def set_params(self, params): self.a = params[0] self.b = params[1] self.c = params[2] self.d = params[3]
[docs]class GBellmf(MembershipFunction): '''Class to define a Generalized Gaussian Bell Membership Function :param params: List of design values of the membership function :param universe: Range of domain limits :param name: Name of the membership function :param complement: If is True, the complement evaluation is performed ''' name = 'Generalized Bell mf' def __init__(self, params, universe=None, name=None, complement=False): self.set_params(params) super().__init__(params, universe, name, complement)
[docs] def compute(self, x): tmp = ((x - self.c) / self.a) ** 2 if tmp == 0 and self.b == 0: y = 0.5 elif tmp == 0 and self.b < 0: y = 0 else: tmp = tmp**self.b y = 1. / (1 + tmp) return y
@property def spread(self): return self.a
[docs] def set_params(self, params): self.a = params[0] self.b = params[1] self.c = params[2]