Source code for zadeh.mparser

"""Matlab .fis-like parser"""
import re
import configparser

from . import sets, variables, domains, fis, rules

# For a general reference on the format cf:
# http://functionbay.com/documentation/onlinehelp/default.htm#!Documents/introductiontothefisfileformat.htm

# Aggregation method converter
_aggregation_methods = {"max": "max", "sum": "bsum", "probor": "psum"}

# Implication method converter
_implication_methods = {"min": "min", "prod": "prod"}

# OR method converter
_OR_methods = {"max": "max", "sum": "bsum", "probor": "psum"}
# Sum does not appear in the docs, but we don't mind adding

# AND method converter
_AND_methods = {"min": "min", "prod": "prod"}


[docs]def read_mfis(path, steps=100): """Parse a MATLABĀ® Fuzzy Inference System-like file""" config = configparser.ConfigParser(inline_comment_prefixes="%") config.read(path) num_inputs = int(config["System"]["numinputs"]) num_outputs = int(config["System"]["numoutputs"]) # Raise errors for non-supported options if num_outputs != 1: raise NotImplementedError("Only one output is supported") if config["System"]["Type"] != "'mamdani'": raise NotImplementedError("Type of inference not implemented") inputs = [parse_variable(config["Input%d" % i], steps) for i in range(1, num_inputs + 1)] output = parse_variable(config["Output1"], steps) rules_ = [parse_rule(*x, inputs, output) for x in config["Rules"].items()] defuzzification = config["System"]["DefuzzMethod"][1:-1] if defuzzification not in ["centroid", "bisector", "som", "mom", "lom"]: raise ValueError("Invalid defuzzification: %s" % defuzzification) aggregation = config["System"]["AggMethod"][1:-1] try: aggregation = _aggregation_methods[aggregation] except KeyError as e: raise ValueError("Invalid aggregation: %s" % aggregation) from e implication = config["System"]["ImpMethod"][1:-1] try: implication = _implication_methods[implication] except KeyError as e: raise ValueError("Invalid implication: %s" % implication) from e AND = config["System"]["AndMethod"][1:-1] try: AND = _AND_methods[AND] except KeyError as e: raise ValueError("Invalid AND method: %s" % AND) from e OR = config["System"]["OrMethod"][1:-1] try: OR = _OR_methods[OR] except KeyError as e: raise ValueError("Invalid OR method: %s" % OR) from e return fis.FIS(inputs, rules.FuzzyRuleSet(rules_), output, defuzzification=defuzzification, aggregation=aggregation, implication=implication, AND=AND, OR=OR)
[docs]def parse_variable(variable, steps=100): """ Parse a section defining a fuzzy variable Args: variable: Section of the file defining the variable. steps (int): The number of steps for FloatDomain. Returns: FuzzyVariable: A representation of the variable """ name = variable["Name"][1:-1] range_ = [float(x) for x in variable["Range"][1:-1].split()] mfs = [variable["MF%d" % j] for j in range(1, int(variable["NumMFs"]) + 1)] v = variables.FuzzyVariable(domains.FloatDomain(name, *range_, steps), dict([parse_mf(mf) for mf in mfs]) ) return v
# Mapping from Matlab MF to the equivalent FuzzySet class (ordered parameters must be equivalent as well) _direct_equivalence_sets = { "trimf": sets.TriangularFuzzySet, "trapmf": sets.TrapezoidalFuzzySet, "gaussmf": sets.GaussianFuzzySet, "gauss2mf": sets.Gaussian2FuzzySet, "sigmf": sets.SigmoidalFuzzySet, "psigmf": sets.SigmoidalProductFuzzySet, "dsigmf": sets.SigmoidalDifferenceFuzzySet, "smf": sets.SFuzzySet, "zmf": sets.ZFuzzySet, "pimf": sets.PiFuzzySet, }
[docs]def parse_mf(description): """ Parse a membership function Args: description (str): A line defining the membership function. Returns: FuzzySet: A fuzzy set defined by the membership function """ value_name, value_f, pars = re.match(r"'(.*)':'(.*)',\[(.*)\]", description).groups() pars = [float(x) for x in pars.split()] if value_f in _direct_equivalence_sets: return value_name, _direct_equivalence_sets[value_f](*pars) else: raise ValueError("Unknown membership function: %s" % value_f)
[docs]def parse_rule(rule, operation, inputs, output): """ Parse a line defining a fuzzy rule Args: rule (str): Line defining the rule operation (str): "1" for "and", "2" for "or" (file format meaning). inputs (list of FuzzyVariable): The ordered list of inputs. output (FuzzyVariable): The output of the system Returns: FuzzyRule: The description of the fuzzy rule """ input_values, target_value, weight = re.match(r"(.*), (.*) \((.*)\)", rule).groups() values = [int(x) for x in input_values.split()] weight = float(weight) target_value = int(target_value) # FIXME: The value position depends on the dict implementation preserving order lhs = [(rules.FuzzyValuation if v > 0 else rules.FuzzyNotValuation)(var, list(var.values)[abs(v) - 1]) for var, v in zip(inputs, values)] lhs = {"1": rules.FuzzyAnd, "2": rules.FuzzyOr}[operation](lhs) rhs = (rules.FuzzyValuation if target_value > 0 else rules.FuzzyNotValuation)(output, list(output.values)[ abs(target_value) - 1]) return rules.FuzzyRule(lhs, rhs, weight=weight)