Source code for FuzzySystem.matlab_importer

# 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.fis import FuzzyInferenceSystem
from FuzzySystem.fuzzyrule import FuzzyRule, Antecedent, Consequent
from FuzzySystem.fuzzyset import FuzzySet
from FuzzySystem.fuzzyvariable import FuzzyVariable
from FuzzySystem.membership_function import Trapmf, Trimf, Gaussmf, GBellmf, Sigmoidmf

"""
Membership functions in matlab: 
dsigmf, evalmf, gauss2mf, gaussmf,
gbellmf, mf2mf, pimf, psigmf, 
sigmf, smf, trapmf, trapmf, trimf, zmf
"""

MF_DICTIONARY = {
    'trapmf': Trapmf,
    'trimf': Trimf,
    'gaussmf': Gaussmf,
    'gbellmf': GBellmf,
    'sigmf': Sigmoidmf
}


def strip_array(array):
    ''':meta private:'''
    return [text.strip() for text in array if text.strip() != '']


def read_rules_matlab(file=None, txt=None):
    ''':meta private:'''
    rules_array = []
    if file is not None:
        with open(file, 'r') as f:
            for text in f:
                rules, conection = text.split(':')
                ant, con = rules.split(',')
                ants = strip_array(ant.split(' '))
                cons = strip_array(con.split(' '))
                weights = cons[-1].strip().replace('(', '').replace(')', '')
                cons = cons[:-1]
                conection = conection.strip()
                rules_array.append((ants, cons, weights, conection))
    elif txt is not None:
        for text in txt:
            rules, conection = text.split(':')
            ant, con = rules.split(',')
            ants = strip_array(ant.split(' '))
            cons = strip_array(con.split(' '))
            weights = cons[-1].strip().replace('(', '').replace(')', '')
            cons = cons[:-1]
            conection = conection.strip()
            rules_array.append((ants, cons, weights, conection))
    else:
        return None
    return rules_array


def import_rules_matlab(rules, fis_inputs, fis_outputs):
    ''':meta private:'''
    antecedent = []
    consequent = []
    fis_rules = None
    for i, rule in enumerate(rules):
        antecedent.append(Antecedent(conector='min'))
        consequent.append(Consequent())

        for j, a in enumerate(rule[0]):
            antecedent[i].add(fis_inputs[j][int(a) - 1])
        for j, c in enumerate(rule[1]):
            consequent[i].add(fis_outputs[j][int(c) - 1])

        fis_rules = []
        for i in range(len(antecedent)):
            fis_rules.append(
                FuzzyRule(antecedent=antecedent[i], consequent=consequent[i]))
    return fis_rules


def read_fis_file(file):
    ''':meta private:'''
    fis_config = {}
    i = 1
    sections = ['[System]', '[Input{}]', '[Output{}]', '[Rules]']
    with open(file, 'r') as f:
        line = f.readline()
        if line.strip() == sections[0]:
            fis_config['system'] = {}
            text = f.readline()
            while text.strip() != '':
                key, value = text.split("=")
                fis_config['system'][key] = value.strip().replace("'", '')
                text = f.readline()
        fis_config['system']['NumInputs'] = int(
            fis_config['system']['NumInputs'])
        inputs = fis_config['system']['NumInputs']
        fis_config['system']['NumOutputs'] = int(
            fis_config['system']['NumOutputs'])
        outputs = int(fis_config['system']['NumOutputs'])
        fis_config['inputs'] = []
        while i <= inputs:
            text = f.readline()
            while text.strip() != '':
                if text.strip() == sections[1].format(i):
                    temp = {}
                else:
                    key, value = text.strip().split('=')
                    if key == 'Range':
                        value = value.replace('[', '').replace(']', '')
                        #value = list(map(int,value.split(' ')))
                        value = list(map(float, value.split(' ')))
                        temp[key] = value
                    elif key == 'NumMFs':
                        temp[key] = int(value)
                    else:
                        temp[key] = value.strip().replace("'", '')
                text = f.readline()
            i = i + 1
            fis_config['inputs'].append(temp)
        i = 1
        fis_config['outputs'] = []
        while i <= outputs:
            text = f.readline()
            while text.strip() != '':
                if text.strip() == sections[2].format(i):
                    temp = {}
                else:
                    key, value = text.strip().split('=')
                    if key == 'Range':
                        value = value.replace('[', '').replace(']', '')
                        value = list(map(int, value.split(' ')))
                        temp[key] = value
                    elif key == 'NumMFs':
                        temp[key] = int(value)
                    else:
                        temp[key] = value.strip().replace("'", '')
                text = f.readline()
            i = i + 1
            fis_config['outputs'].append(temp)
        text = f.readline()
        if text.strip() == sections[3]:
            text = f.read()
            fis_config['rules'] = text.strip().split('\n')
    return fis_config


def parse_fis_file(conf):
    ''':meta private:'''
    for inp in range(0, int(conf['system']['NumInputs'])):
        num_mf = int(conf['inputs'][inp]['NumMFs'])
        fuzzy_sets = []
        for i in range(1, num_mf + 1):
            name_mf, params = conf['inputs'][inp]['MF' + str(i)].split(',')
            name, mf = name_mf.split(':')
            params = params.replace('[', '').replace(']', '')
            params = list(map(float, params.split(' ')))
            fuzzy_sets.append((name, mf, params))
            del conf['inputs'][inp]['MF' + str(i)]
        conf['inputs'][inp]['values'] = fuzzy_sets

    for inp in range(0, int(conf['system']['NumOutputs'])):
        num_mf = int(conf['outputs'][inp]['NumMFs'])
        fuzzy_sets = []
        for i in range(1, num_mf + 1):
            name_mf, params = conf['outputs'][inp]['MF' + str(i)].split(',')
            name, mf = name_mf.split(':')
            params = params.replace('[', '').replace(']', '')
            params = list(map(float, params.split(' ')))
            fuzzy_sets.append((name, mf, params))
            del conf['outputs'][inp]['MF' + str(i)]
        conf['outputs'][inp]['values'] = fuzzy_sets
    return conf


def get_io_fis(conf):
    ''':meta private:'''
    fis_input = []
    for input in conf['inputs']:
        fuzzy_sets = []
        for fs in input['values']:
            fuzzy_sets.append(FuzzySet(fs[0], MF_DICTIONARY[fs[1]](fs[2])))
        fis_input.append(
            FuzzyVariable(input['Name'], fuzzy_sets, universe=input['Range']))

    fis_output = []
    for output in conf['outputs']:
        fuzzy_sets = []
        for fs in output['values']:
            fuzzy_sets.append(FuzzySet(fs[0], MF_DICTIONARY[fs[1]](fs[2])))
        fis_output.append(
            FuzzyVariable(output['Name'], fuzzy_sets,
                          universe=output['Range']))
    return (fis_input, fis_output)


[docs]def import_fis_matlab(file): '''Function to import a matlab type fis file to create an FuzzySystem object :param file: [str] path to the file to import :return: [FuzzySystem] a FuzzySystem equivalent to the input fis configuration file ''' conf = read_fis_file(file) conf = parse_fis_file(conf) fis_input, fis_output = get_io_fis(conf) rules = read_rules_matlab(txt=conf['rules']) fis_rules = import_rules_matlab(rules, fis_input, fis_output) fis = FuzzyInferenceSystem(fis_rules, inputs=fis_input, outputs=fis_output) return fis