Source code for FuzzySystem.defuzzifier

# 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

from FuzzySystem import config
import numpy as np
#import matplotlib.pyplot as plt
#import itertools
#import logging, sys
from FuzzySystem.output import Output

output_toDict = Output.output_toDict


[docs]class Defuzzifier: '''Abstract class to design defuzzifiers :param output: [Output] an output resulted of the implication process :param universe: [list] range of the domain limits [min, max] :param samples: [int] number of samples used to calculate the defuzzification :param nout: [int] index of the output to defuzzify :param multiple_instances: [bool] flag to define if the Output corresponds to multiple outputs ''' name = "Defuzzifier" def __init__(self, output, universe=None, samples=config.default_points, nout=0, multiple_instances=True): self.nout = nout self.multiple_instances = False if isinstance(output, (Output,)) or 'Output' in str(output.__class__): self.multiple_instances = output.multiple_outputs and multiple_instances self.output = output.fuzzysets elif isinstance(output, ( list, dict, np.ndarray, )): self.multiple_instances = False self.output = output else: raise Exception( "Output must be a List of rules' output or an Output object") self.universe = universe self.samples = samples self.G = None
[docs] def eval(self): '''Performs the defuzzification process :return: the crisp value ''' if self.multiple_instances: return [self.compute(e) for e in self.output] else: return self.compute(self.output)
[docs] def compute(self, fs): '''abstract method. Performs the defuzzification process :param fs: [firing strength] firing strength values :return: crisp values ''' pass
[docs]class TSKDefuzzifier: '''A class to perform the weighted average of the function outputs :param output: [Output] the output object to perform the defuzzification ''' name = "TSK Defuzzifier" '''Default reference name''' def __init__(self, output): self.multiple_instances = False if isinstance(output, (Output,)): if output.type == 'Sugeno': self.g = output.get_array() self.fs = output.firing_strength else: raise Exception("Output must be result of TSK Consequents") else: raise Exception( "Output must be a List of rules' output or an Output object")
[docs] def eval(self): '''Evaluates and computes de crisp value :return: output crisp value ''' return self.compute()
def compute(self): '''Performs the weighted average between firing strength and output functions :meta private: :return: output crisp value ''' self.g = np.array(self.g) self.fs = np.array(self.fs) fs_ = self.fs / self.fs.sum(axis=0) return np.sum(self.g * fs_, axis=0)
# return np.sum(self.fs * self.g) / np.sum(self.fs) class Aggregator: '''Class for output aggregation through the maximum :meta private: ''' def __init__(self, fuzzySets): self.fuzzySets = fuzzySets def getSet(self, samples=config.default_points): universe = np.linspace(self.fuzzySets[0].universe[0], self.fuzzySets[0].universe[1], samples) agre_set = np.zeros([len(self.fuzzySets), len(universe)]) for i, o in enumerate(self.fuzzySets): agre_set[i:] = o.eval(universe) return np.max(agre_set, axis=0), universe
[docs]class Centroid(Defuzzifier): '''A class for Centroid method defuzzification''' name = "Centroid" """Defaulf reference name"""
[docs] def compute(self, fs): self.G = {} for name, output_array in fs.items(): m, u = Aggregator(output_array).getSet(self.samples) a = np.dot(m.T, u) b = np.sum(m) self.G[name] = np.divide(a, b, out=np.zeros_like(a), where=b != 0) return self.G
[docs]class Heights(Defuzzifier): '''A class for Heights method defuzzification''' name = "Heights" '''Default reference name'''
[docs] def compute(self, fs): self.G = {} for name, output_array in fs.items(): y_h = np.array([]) m_b = np.array([]) if self.universe is None: self.universe = np.linspace(output_array[0].universe[0], output_array[0].universe[1], self.samples) for g in output_array: t = np.array(g.eval(self.universe)) y = np.mean(self.universe[t == np.max(t)]) y_h = np.append(y_h, y) m_b = np.append(m_b, g.eval(y)) a = np.dot(y_h.T, m_b) b = np.sum(m_b) self.G[name] = np.divide(a, b, out=np.zeros_like(a), where=b != 0) return self.G
[docs]class CenterOfSets(Defuzzifier): '''A class for Center of Sets method defuzzification''' name = "Center of Sets" '''Default reference name'''
[docs] def compute(self, fs): self.G = {} for name, output_array in fs.items(): y_cos = np.array([]) fs = np.array([]) for g in output_array: d = {} d[name] = [g] c = Centroid(d, samples=self.samples) c = c.eval() y_cos = np.append(y_cos, list(c.values())[0]) fs = np.append(fs, g.firing_strength) a = np.dot(y_cos.T, fs) b = np.sum(fs) self.G[name] = np.divide(a, b, out=np.zeros_like(a), where=b != 0) return self.G
[docs]class MeanOfMaximum(Defuzzifier): '''A class for Mean of Maximum method defuzzification''' name = "Mean Of Maximum" '''Default reference name'''
[docs] def compute(self, fs): self.G = {} for name, output_array in fs.items(): m, u = Aggregator(output_array).getSet(self.samples) argmax = u[m == np.max(m)] self.G[name] = np.sum(argmax) / len(argmax) return self.G
[docs]class ModifiedHeights(Defuzzifier): '''A class for Modified Heights method defuzzification''' name = "Modified Heights" '''Default reference name'''
[docs] def compute(self, fs): self.G = {} for name, output_array in fs.items(): y_h = np.array([]) m_b = np.array([]) if self.universe is None: self.universe = np.linspace(output_array[0].universe[0], output_array[0].universe[1], self.samples) for g in output_array: t = np.array(g.eval(self.universe)) y = np.mean(self.universe[t == np.max(t)]) y_h = np.append(y_h, y) m_b = np.append(m_b, np.divide(g.eval(y), g.mf.spread**2)) a = np.dot(y_h.T, m_b) b = np.sum(m_b) self.G[name] = np.divide(a, b, out=np.zeros_like(a), where=b != 0) return self.G
[docs]class LastOfMaximum(Defuzzifier): '''A class for Last of Maximum method defuzzification''' name = "Least Of Maximum" '''Default reference name'''
[docs] def compute(self, fs): self.G = {} for name, output_array in fs.items(): m, u = Aggregator(output_array).getSet(self.samples) argmax = u[m == np.max(m)] self.G[name] = np.max(argmax) return self.G
[docs]class FirstOfMaximum(Defuzzifier): '''A class for First of Maximum method defuzzification''' name = "First Of Maximum" '''Default reference name'''
[docs] def compute(self, fs): self.G = {} for name, output_array in fs.items(): m, u = Aggregator(output_array).getSet(self.samples) argmax = u[m == np.max(m)] self.G[name] = np.min(argmax) return self.G