Source code for FuzzySystem.fuzzyset

# 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
from FuzzySystem.nonsingleton import NonSingleton
from FuzzySystem.fuzzy_operations import intersection


[docs]class FuzzySet: ''' A class for modeling Fuzzy Sets :param name: label assigned to the fuzzy set :type name: str :param mf: membership function to associate with the linguistic value :type mf: MembershipFunction :param fs_operator: firing strength operator. "min" or "prod" :type fs_operator: str ''' def __init__(self, name, mf, fs_operator='min'): self.name = name self.mf = mf self.firing_strength = None self.fs_operator = fs_operator @property def universe(self): '''Universe range, [min, max]''' return self.mf.universe @universe.setter def universe(self, value): self.mf.universe = value
[docs] def eval(self, x, fs_operator=None): '''Evaluate the fuzzy set given an input :param x: inputs values :type x: list, numpy array, dictionary or pandas data frame :param fs_operator: firing strength operator. "min" or "prod" :type fs_operator: str :returns: The membership function evaluation ''' if not (fs_operator is None): self.fs_operator = fs_operator if isinstance(x, (NonSingleton,)): fuzzy_ns_values = intersection(self.eval(x.values), x.eval(), type=self.fs_operator) argmax = x.values[fuzzy_ns_values.argmax()] x = argmax if isinstance(x, ( list, np.ndarray, )): if self.firing_strength is not None: if self.fs_operator == 'min': return [ min(self.mf.eval(i), self.firing_strength) for i in x ] elif self.fs_operator == 'prod': return [ xi * self.firing_strength for xi in self.mf.eval(x) ] else: raise Exception( "Firing strength operator must be either 'min' or 'prod', get {}" .format(self.fs_operator)) else: return self.mf.eval(x) else: if self.firing_strength is not None: if self.fs_operator == 'min': return [min(self.mf.eval(x), self.firing_strength)] elif self.fs_operator == 'prod': return [x * self.firing_strength] else: raise Exception( "Firing strength operator must be either 'min' or 'prod'" ) return self.mf.eval(x)
def __call__(self, x): return self.eval(x)
[docs] def cut(self, firing_strength, and_op=None): '''Establishes a firing strength value :param firing_strength: value in [0,1] :type firing_strength: float :param and_op: conjunction operation. "min" or "prod" :type and_op: str :return: self ''' self.firing_strength = firing_strength self.fs_operator = and_op return self
def __str__(self): info = "\nname: {0}\nmembership function: {1}\nparams: {2} \nfiring strength:{3}\n" return info.format(self.name, self.mf.name, self.mf.params, self.firing_strength)
[docs] def complement(self): '''Performs the complement operation to the fuzzy set :return: self ''' self.mf.complement() return self
[docs] def show(self, points=config.default_points, axes=None): ''' Plots the fuzzy set's membership function :param points: number of samples to evaluate the membership function :type points: int :param axes: for outside plotting :type axes: plt.axes ''' u = np.linspace(self.mf.universe[0], self.mf.universe[1], num=points, endpoint=True, retstep=False, dtype=None) c = self.eval(u) if not axes: _, ax = plt.subplots() else: ax = axes plt.title('Fuzzy Set') ax.plot(u, c, '-', label=self.name) if self.firing_strength is not None: _fs = self.firing_strength self.firing_strength = None ax.plot(u, self.eval(u), '--', label="{} {}".format("original", self.name), alpha=0.4) self.firing_strength = _fs del _fs ax.axhline(self.firing_strength, color='black', lw=2, alpha=.5) ax.legend(loc='best', fontsize='x-large', fancybox=True, framealpha=0.5) ax.grid() if not axes: plt.show()