Source code for FuzzySystem.fis

"""A python framework to build Fuzzy Inference Systems

Raul Navarro-Almanza<rnavarro@uabc.edu.mx>
"""

from FuzzySystem.fuzzyrule import TSKConsequent, Aggregation, FuzzyRule, Antecedent, Consequent
from FuzzySystem.output import Output
from FuzzySystem import config, fuzzyvariable


[docs]class FuzzyInferenceSystem: '''Class to perform the inference process using fuzzy logic :param rules: List of rules to conform the knowledge base :param points: Number of points to perform the evaluation :param inputs: dictionary of inputs :param outputs: dictionary of outputs :param and_op: Conjunction operator :param or_op: Union operator :param verbose: flag to print information ''' def __init__(self, rules, points=config.default_points, inputs=None, outputs=None, and_op='min', or_op='max', verbose=False): self.and_op = and_op self.or_op = or_op self.type = None self.all_inputs = inputs self.all_outputs = outputs self.rules = rules self.verbose = verbose if rules is not None: for r in rules: if isinstance(r.consequent, (TSKConsequent, )): if self.type == 'Mamdani': raise Exception( 'The FIS must has only one type of Consequent') else: self.type = 'Sugeno' elif isinstance(r.consequent, (Consequent, )): if self.type == 'Sugeno': raise Exception( 'The FIS must has only one type of Consequent') else: self.type = 'Mamdani' else: raise Exception('Not recognized consequent type: ', type(r.consequent)) self.points = points if rules: if isinstance(rules, (list, )): self.rules = rules else: self.rules = [rules]
[docs] def add_rule(self, rule): '''Add a rule to the existing knowledge base :param rule: The rule to append to the system :type rule: FuzzyRule ''' if isinstance(rule, (FuzzyRule,)): self.rules.append(rule)
[docs] def show_rules(self): '''Shows in natural language the knowledge base''' print("\nFuzzy System Rules:") for r in self.rules: print(str(r))
[docs] def eval(self, inputs, verbose=None): '''Evaluates the fuzzy inference system :param inputs: Inputs to evaluate. :type inputs: number, list, pandas data frame :param verbose: flog to print information :return: Output object that contains the fuzzy set of the evaluated consequent ''' if verbose is None: verbose = self.verbose from .utils import format_inputs inputs = format_inputs(inputs, inputs=self.inputs, verbose=verbose) return Output([ rule.eval( inputs, and_op=self.and_op, or_op=self.or_op, verbose=verbose) for rule in self.rules ], type=self.type)
@property def inputs(self): '''Dictionary with the system's inputs''' input = {} if self.all_inputs: for fvar in self.all_inputs: input[fvar.name] = fvar else: for rule in self.rules: input.update(rule.inputs) return input @property def outputs(self): '''Dictionary with the system's outputs''' output = {} if self.all_outputs: if isinstance(self.all_outputs, (fuzzyvariable.FuzzyVariable,)): output[self.all_outputs.name] = self.all_outputs elif isinstance(self.all_outputs[0], (fuzzyvariable.FuzzyVariable,)): for fvar in self.all_outputs: output[fvar.name] = fvar elif isinstance(self.all_outputs[0], (str,)): return self.all_outputs else: return output else: if self.rules: for rule in self.rules: output.update(rule.outputs) return output @property def matrix_rules(self): '''Matrix with the relationships between antecedents and consequent''' mat = [] for rule in self.rules: r_mat = [] if isinstance(rule.antecedent, ( list, Antecedent, )): if isinstance(rule.antecedent.propositions, (Aggregation,)): r_mat = rule.antecedent.propositions.get_tuples() else: for proposition in rule.antecedent.propositions: r_mat = r_mat + [proposition.get_tuple()] if isinstance(rule.consequent, ( list, Consequent, )): for proposition in rule.consequent.propositions: r_mat = r_mat + [proposition.get_tuple()] r_mat = r_mat + [("weight", rule.weight)] mat.append(r_mat) return mat
[docs] def get_matrix_rules(self, negatives=True): '''Generates the matrix with the associations in the rules :param negatives: If is True, the negated antecedents are multiplied by -1 :return: Matrix with the rule associations. ''' outputs_classes_id = {} for i, k in enumerate(self.outputs.keys()): fsets_names = [f.name for f in self.outputs[k].fuzzysets] outputs_classes_id[i] = dict( zip(fsets_names, range(1, len(fsets_names) + 1))) fuzzysets_id = {} for i, k in enumerate(self.inputs.keys()): fsets_names = [f.name for f in self.inputs[k].fuzzysets] fuzzysets_id[i] = dict( zip(fsets_names, range(1, len(fsets_names) + 1))) mrules = [] for r in self.matrix_rules: temp = [] d = dict(r) for i, k in enumerate(self.inputs.keys()): if k in d.keys(): # If the proposition has a complement operator over fuzzy set if "not " in d[k]: name = d[k].replace("not ", "") if negatives: temp = temp + [-fuzzysets_id[i][name]] else: temp = temp + [fuzzysets_id[i][name]] else: temp = temp + [fuzzysets_id[i][d[k]]] else: temp = temp + [0] # Adding weight rule to matrix_rules temp = temp + [d["weight"]] for i, o in enumerate(self.outputs.keys()): temp = temp + [outputs_classes_id[i][d[o]]] mrules.append(temp) return mrules
[docs] def get_structure(self): '''Create a json representation of the FIS structure :return: Dictionary with all the elements in the FIS ''' structure = {} # TODO: Add all compatible membership functions to the dictionary name_dict = {'Gaussian mf': 'gaussmf'} for k in self.inputs.keys(): structure[k] = [] structure[k] = structure[k] + [[ name_dict[f.mf.name], [f.name, f.mf.params, f.universe] ] for f in self.inputs[k].fuzzysets] output_list = [] output_structure = {} outputs = self.outputs if isinstance(outputs, (dict, )): for k in outputs.keys(): output_structure[k] = [] output_structure[k] = output_structure[k] + [[ name_dict[f.mf.name], [f.name, f.mf.params, f.universe] ] for f in self.outputs[k].fuzzysets] return {"inputs": structure, "outputs": output_structure} if isinstance(outputs, (list, )): output_list = outputs elif isinstance(outputs, (fuzzyvariable.FuzzyVariable,)): output_list = output_list + [[ name_dict[f.mf.name], [f.name, f.mf.params, f.universe] ] for f in outputs.fuzzysets] return {"inputs": structure, "outputs": output_list}