Module type2fuzzy.membership

type2fuzzy.membership

Membership modules including:
General Type-2 fuzzy Set.
Interval Type-2 Fuzzy Set.
Type-1 Fuzzy Set.
Z-Slice Type-2 Fuzzy Set.
Alpha-Cut Type-1 Fuzzy Set.
Crisp Sets.
Generation of Interval Type-2 Fuzzy Sets.
Generation of General Type-2 Fuzzy Sets.

Expand source code
"""
type2fuzzy.membership

Membership modules including:<br>
General Type-2 fuzzy Set.<br/>
Interval Type-2 Fuzzy Set.<br/>
Type-1 Fuzzy Set.<br/>
Z-Slice Type-2 Fuzzy Set.<br/>
Alpha-Cut Type-1 Fuzzy Set.<br/>
Crisp Sets.<br/>
Generation of Interval Type-2 Fuzzy Sets.<br/>
Generation of General Type-2 Fuzzy Sets.<br/>
"""

from type2fuzzy.membership.secondarymf import SecondaryMembershipFunction
from type2fuzzy.membership.secondarymf import Type1FuzzySet
from type2fuzzy.membership.generaltype2fuzzyset import GeneralType2FuzzySet
from type2fuzzy.membership.intervaltype2fuzzyset import IntervalType2FuzzySet
from type2fuzzy.membership.zslicetype2fuzzyset import ZSliceType2FuzzySet
from type2fuzzy.membership.crispset import CrispSet
from type2fuzzy.membership.alphacuttype1fuzzyset import AlphaCutType1FuzzySet
from type2fuzzy.membership.generate_gt2mf import generate_gt2set_horizontal
from type2fuzzy.membership.generate_it2fs import create_gaussian_fixed_sigma
from type2fuzzy.membership.generate_it2fs import create_gaussian_fixed_mean


__all__ = ['SecondaryMembershipFunction', 'GeneralType2FuzzySet', 
                        'Type1FuzzySet', 'IntervalType2FuzzySet', 'ZSliceType2FuzzySet', 
                        'CrispSet', 'AlphaCutType1FuzzySet', 'generate_gt2set_horizontal', 
                        'create_gaussian_fixed_sigma', 'create_gaussian_fixed_mean']

Sub-modules

type2fuzzy.membership.alphacuttype1fuzzyset
type2fuzzy.membership.crispset
type2fuzzy.membership.generaltype2fuzzyset
type2fuzzy.membership.generate_gt2mf

Creation, loading and represenation of general type 2 fuzzy sets

type2fuzzy.membership.generate_it2fs

generation of interval type 2 fuzzy sets

type2fuzzy.membership.intervaltype2fuzzyset
type2fuzzy.membership.secondarymf
type2fuzzy.membership.type1fuzzyset
type2fuzzy.membership.zslicetype2fuzzyset

Functions

def create_gaussian_fixed_mean(primary_domain, sigma1, sigma2, mean=1.0)

Creates an interval type-2 fuzzy set with fixed standard deviation and uncertain mean

Arguments:

primary_domain – list, elements of primary domain

sigma1 – lowest value of standard deviation

sigma2 – highest value of standard deviation

mean – mean , default 1

Returns:

interval_set – created interval type-2 fuzzy set

References:

Karnik, Nilesh N., and Jerry M. Mendel. "Introduction to type-2 fuzzy logic systems." 1998 IEEE International Conference on Fuzzy Systems Proceedings. IEEE World Congress on Computational Intelligence ( Cat. No. 98CH36228). Vol. 2. IEEE, 1998.

Expand source code
def create_gaussian_fixed_mean(primary_domain, sigma1, sigma2, mean=1.0):
        '''
        Creates an interval type-2 fuzzy set with fixed standard deviation and uncertain mean

        Arguments:
        ----------
        primary_domain -- list, elements of primary domain

        sigma1 -- lowest value of standard deviation

        sigma2 -- highest value of standard deviation

        mean -- mean , default 1

        Returns:
        --------
        interval_set -- created interval type-2 fuzzy set

        References:
        -----------
        Karnik, Nilesh N., and Jerry M. Mendel. 
        "Introduction to type-2 fuzzy logic systems." 
        1998 IEEE International Conference on Fuzzy Systems Proceedings.
        IEEE World Congress on Computational Intelligence (
        Cat. No. 98CH36228). Vol. 2. IEEE, 1998.
        '''
        # check that m1 is smaller than m2
        if sigma1 > sigma2:
                raise Exception('ERROR: m1 vaue must be smaller or equal to m2')
        
        interval_set = IntervalType2FuzzySet()
        u1 = 0
        u2 = 0

        for x in primary_domain:

                u1 = math.exp(-0.5*((x-float(mean))/sigma1)**2)
                u2 = math.exp(-0.5*((x-float(mean))/sigma2)**2)

                # add the element to the it2fs
                interval_set.add_element(x, CrispSet(min(u1, u2), max(u1, u2)))

        return interval_set
def create_gaussian_fixed_sigma(primary_domain, m1, m2, sigma=1.0)

Creates an interval type-2 fuzzy set with fixed standard deviation and uncertain mean

Arguments:

primary_domain – list, elements of primary domain

m1 – lowest value of mean

m2 – highest value of mean

sigma – standard deviation , default 1

Returns:

interval_set – created interval type-2 fuzzy set

References:

Karnik, Nilesh N., and Jerry M. Mendel. "Introduction to type-2 fuzzy logic systems." 1998 IEEE International Conference on Fuzzy Systems Proceedings. IEEE World Congress on Computational Intelligence ( Cat. No. 98CH36228). Vol. 2. IEEE, 1998.

Expand source code
def create_gaussian_fixed_sigma(primary_domain, m1, m2, sigma=1.0):
        '''
        Creates an interval type-2 fuzzy set with fixed standard deviation and uncertain mean

        Arguments:
        ----------
        primary_domain -- list, elements of primary domain

        m1 -- lowest value of mean

        m2 -- highest value of mean
        
        sigma -- standard deviation , default 1

        Returns:
        --------
        interval_set -- created interval type-2 fuzzy set

        References:
        -----------
        Karnik, Nilesh N., and Jerry M. Mendel. 
        "Introduction to type-2 fuzzy logic systems." 
        1998 IEEE International Conference on Fuzzy Systems Proceedings.
        IEEE World Congress on Computational Intelligence (
        Cat. No. 98CH36228). Vol. 2. IEEE, 1998.
        '''
        # check that m1 is smaller than m2
        if m1 > m2:
                raise Exception('ERROR: m1 vaue must be smaller or equal to m2')
        
        interval_set = IntervalType2FuzzySet()
        toggle_peak = False
        element = None

        for x in primary_domain:

                u1 = math.exp(-0.5*((x-float(m1))/sigma)**2)
                u2 = math.exp(-0.5*((x-float(m2))/sigma)**2)

                # once m1 has a value of 1 the plateu starts and ands when m2 reaches a value of 1
                if u1 == 1:
                        toggle_peak = True
                if u2 == 1:
                        toggle_peak = False

                if toggle_peak:
                        element = CrispSet(min(u1, u2), 1)
                else:
                        element = CrispSet(min(u1, u2), max(u1, u2))

                # add the element to the it2fs
                interval_set.add_element(x, element)

        return interval_set
def generate_gt2set_horizontal(primary_domain, secondary_domain, set_definition)

Experimemtal method for generating a type-2 fuzzy set from a pointwise definition where each point is a touple (x, u, delta_left, delta_right); where: x is the primary domain value of the point u is the secondary domain value of the point delta_left is the spread of the type 2 set to the left and delta_right is the spread to the right of the type 2 set such that a triangular funation is forment at u with values x-delta_left, x, x+delta_right

Parameters:

primary_domain – 1D array, data vector for primary domain secondary_domain – 1D array, data vector for secondary domain [0,1] point_set – 1D array, data for points that make up the type-2 set

Returns:

gt2fs – 2D array describing the type-2 set

Expand source code
def generate_gt2set_horizontal(primary_domain, secondary_domain, set_definition):
        '''
        Experimemtal method for generating a type-2 fuzzy set from a pointwise definition
        where each point is a touple (x, u, delta_left, delta_right); where:
        x is the primary domain value of the point
        u is the secondary domain value of the point
        delta_left is the spread of the type 2 set to the left and
        delta_right is the spread to the right of the type 2 set such that
        a triangular funation is forment at u with values x-delta_left, x, x+delta_right

        Parameters:
        -----------
        primary_domain -- 1D array, data vector for primary domain
        secondary_domain -- 1D array, data vector for secondary domain [0,1]
        point_set -- 1D array, data for points that make up the type-2 set

        Returns:
        -------
        gt2fs -- 2D array describing the type-2 set
        '''
        np.seterr(invalid='ignore')

        sec_dom_increment = secondary_domain[1] - secondary_domain[0]
        pri_dom_increment = primary_domain[1] - primary_domain[0]

        gt2fs = np.zeros([len(secondary_domain), len(primary_domain)])

        for idx in range(0, len(set_definition) - 1):

                start_point = set_definition[idx]
                end_point = set_definition[idx + 1]
                assert(_pri_dom_from_point(start_point) <= _pri_dom_from_point(end_point))

                pri_dom_pt_start = _pri_dom_from_point(start_point, pri_dom_increment)
                pri_dom_pt_end = _pri_dom_from_point(end_point, pri_dom_increment)

                deltaleft_pt_start = _deltaleft_from_point(start_point)
                deltaleft_pt_end = _deltaleft_from_point(end_point)
                deltaright_pt_start = _deltaright_from_point(start_point)
                deltaright_pt_end = _deltaright_from_point(end_point)

                sec_dom_pt_start = _sec_dom_from_point(start_point, sec_dom_increment)
                sec_dom_pt_end = _sec_dom_from_point(end_point, sec_dom_increment)

                # generation
                r_k = (primary_domain - pri_dom_pt_start) / (pri_dom_pt_end - pri_dom_pt_start)

                u_k = (r_k * (sec_dom_pt_end - sec_dom_pt_start)) + sec_dom_pt_start
                u_k = (np.round(u_k / sec_dom_increment)) * sec_dom_increment
                u_k_idx = (np.round(u_k / sec_dom_increment)).astype(int)

                left_limit_k = (r_k * (pri_dom_pt_end - deltaleft_pt_end - pri_dom_pt_start +
                                                        deltaleft_pt_start)) + (pri_dom_pt_start - deltaleft_pt_start)
                right_limit_k = (r_k * (pri_dom_pt_end + deltaright_pt_end - pri_dom_pt_start -
                                                                deltaright_pt_start)) + (pri_dom_pt_start + deltaright_pt_start)

                # filter the ones with acceptable secondary domain value
                filter_u = (u_k >= 0) & (u_k <= 1)
                filter_x = (primary_domain >= pri_dom_pt_start) & (primary_domain <= pri_dom_pt_end)
                _filter = filter_u & filter_x
                filter_idx = _filter.nonzero()[0]

                previous_index = None
                for index in filter_idx:
                        i = u_k_idx[index]
                        sec_grade = np.maximum(np.minimum((primary_domain - left_limit_k[index]) / (primary_domain[index] - left_limit_k[index]),
                                                                                (right_limit_k[index] - primary_domain) / (right_limit_k[index] - primary_domain[index])), 0)
                        gt2fs[i, :] = np.maximum(gt2fs[i, :], sec_grade)

                        # fill up missing portions between points
                        missing_range = []
                        if previous_index != None:
                                step = np.sign(u_k_idx[index] - u_k_idx[index-1])
                                if step != 0:
                                        missing_range = np.arange(
                                                u_k_idx[previous_index]+step, u_k_idx[index], step)
                                        gt2fs[missing_range, :] = np.maximum(
                                                gt2fs[missing_range, :], sec_grade)

                        previous_index = index

        return gt2fs

Classes

class AlphaCutType1FuzzySet

datastructure defining an alpha-slice type-1 fuzzy set is a dictionary having an crisp set for every alpha-cut such as: key: value of alpha-cut value: corresponding crisp set

Expand source code
class AlphaCutType1FuzzySet:

        def __init__(self):
                '''
                datastructure defining an alpha-slice type-1 fuzzy set 
                is a dictionary having an crisp set for every alpha-cut such as:
                key: value of alpha-cut
                value: corresponding crisp set
                '''
                self._set_definition={}
                self._empty = True

        def __getitem__(self, cut):
                return self._set_definition[cut]

        def alpha_slices(self):
                return self._set_definition.keys()

        @classmethod
        def from_type1fuzzyset(cls, t1fs, number_of_cuts):
                '''
                Converts a Type-1 Fuzzy Set into the union of slices

                Arguments:
                ----------
                t1fs -- Type1FuzzySet, the set to convert
                number_of_cuts -- the number of alpha slices
                '''
                
                at1fs = cls()
                
                delta = 1 / number_of_cuts
                precision = len(str(number_of_cuts))

                limits = None
                # TODO: go back to other version?
                #for cut in np.linspace(delta, 1, number_of_cuts):
                for cut in np.linspace(0, 1, number_of_cuts):
                        
                        cut = round(cut, precision)
                        limits = t1fs.alpha_cut(cut)
                        
                        if not limits.empty:
                                at1fs.add_element(cut, limits)
                
                return at1fs

        @property
        def empty(self):
                '''
                Return True if the set is empty
                '''
                return self._empty

        def add_element(self, alpha_cut, limits):
                '''
                '''
                if not limits.empty:
                        self._set_definition[alpha_cut] = limits
                        self._empty = False

        def cuts(self):
                '''
                returns the alpha-cuts that make this set
                '''
                return self._set_definition.keys()

        def __str__(self):
                '''
                returns a string representation of the alpha-cut type-1 fuzzy set in the form:
                
                alpha-cut_value_1: [left_limit_1, right_limit_1]
                ...
                alpha-cut_value_n: [left_limit_n, right_limit_n]

                '''
                representation = []
                for alpha_cut in self._set_definition.keys():
                        representation.append(f'{alpha_cut} : {self._set_definition[alpha_cut]}')
                
                return '\n'.join(representation)

        def __repr__(self):
                return f'{self.__class__.__name__}(str(self))'

Static methods

def from_type1fuzzyset(t1fs, number_of_cuts)

Converts a Type-1 Fuzzy Set into the union of slices

Arguments:

t1fs – Type1FuzzySet, the set to convert number_of_cuts – the number of alpha slices

Expand source code
@classmethod
def from_type1fuzzyset(cls, t1fs, number_of_cuts):
        '''
        Converts a Type-1 Fuzzy Set into the union of slices

        Arguments:
        ----------
        t1fs -- Type1FuzzySet, the set to convert
        number_of_cuts -- the number of alpha slices
        '''
        
        at1fs = cls()
        
        delta = 1 / number_of_cuts
        precision = len(str(number_of_cuts))

        limits = None
        # TODO: go back to other version?
        #for cut in np.linspace(delta, 1, number_of_cuts):
        for cut in np.linspace(0, 1, number_of_cuts):
                
                cut = round(cut, precision)
                limits = t1fs.alpha_cut(cut)
                
                if not limits.empty:
                        at1fs.add_element(cut, limits)
        
        return at1fs

Instance variables

var empty

Return True if the set is empty

Expand source code
@property
def empty(self):
        '''
        Return True if the set is empty
        '''
        return self._empty

Methods

def add_element(self, alpha_cut, limits)
Expand source code
def add_element(self, alpha_cut, limits):
        '''
        '''
        if not limits.empty:
                self._set_definition[alpha_cut] = limits
                self._empty = False
def alpha_slices(self)
Expand source code
def alpha_slices(self):
        return self._set_definition.keys()
def cuts(self)

returns the alpha-cuts that make this set

Expand source code
def cuts(self):
        '''
        returns the alpha-cuts that make this set
        '''
        return self._set_definition.keys()
class CrispSet (left_val=None, right_val=None)

Implements a Crisp set

Creates a crisp set. Initially the set is empty with left and right limit values set to None

Arguments:

left_val – float, the value of the left limit right_val – float, the value of the right limit

Raises:

Exception if both limits are not None and if the left limit is greater than the right limit

Expand source code
class CrispSet:
        '''
        Implements a Crisp set
        '''
        def __init__(self, left_val=None, right_val=None):
                '''
                Creates a crisp set. Initially the set is empty with left and right 
                limit values set to None

                Arguments:
                ----------
                left_val -- float, the value of the left limit
                right_val -- float, the value of the right limit

                Raises:
                -------
                Exception if both limits are not None and if the left limit is
                greater than the right limit
                '''
                self._empty = True
                self._left_val = None
                self._right_val = None
                self._precision = 5

                if (left_val != None) and (right_val != None):
                        if left_val > right_val:
                                raise Exception('ERROR: Incorrect crisp set limits. Left')
                        self._empty= False
                        self._left_val = left_val
                        self._right_val = right_val

        @property
        def empty(self):
                '''
                Returns True if the set is empty
                '''
                return self._empty

        @property
        def left(self):
                '''
                Returns the left limit of the set
                '''
                return self._left_val

        @left.setter
        def left(self, value):
                '''
                Sets the left limit of the set. Check is bot left and right limit and sets the 
                set as not empty if both are not None
                '''

                if (self.right != None) and value != None and value > self.right:
                        raise Exception('ERROR: invalid left value')

                self._left_val = value

                if (self._left_val != None) and (self._right_val != None):
                        self._empty= False

                if (self._left_val is None) and (self._right_val is None):
                        self._empty= True

        @property
        def right(self):
                '''
                Returns the right limit of the set
                '''
                return self._right_val

        @right.setter
        def right(self, value):
                '''
                Sets the right limit of the set. Check is bot left and right limit and sets the 
                set as not empty if both are not None
                '''
                
                if (self.left != None) and value != None and value < self.left:
                        raise Exception('ERROR: invalid left value')
                
                self._right_val = value
                
                if (self._left_val != None) and (self._right_val != None):
                        self._empty= False

                if (self._left_val is None) and (self._right_val is None):
                        self._empty= True

        @property
        def mid(self):
                '''
                Computes the mid point to the crisp set.
                
                Returns:
                --------
                mid_point -- float, the crisp set mid point

                Raises:
                -------
                Exception if the set is empty
                '''

                if self.left is None or self.right is None:
                        raise Exception('ERROR: Mid point cannot be found for this set.')

                if self._empty:
                        raise Exception('ERROR: Mid point cannot be found for an empty set.')
                
                mid_point = (self._left_val+self._right_val)/2
                return mid_point

        def union(self, crisp_set):

                self._left_val = min(self._left_val, crisp_set.left)
                self._right_val = max(self._right_val, crisp_set.right)

        def __str__(self):

                dec_places_formatter = '''%0.{}f'''.format(self._precision)
                representation = ''
                if self._left_val == self._right_val:
                        representation = f'[{ dec_places_formatter % self._left_val}]'
                else:
                        representation = f'[{ dec_places_formatter % self._left_val}, {dec_places_formatter % self._right_val}]'

                return representation

        def __repr__(self):
                return f'{self.__class__.__name__}({str(self)})'

Instance variables

var empty

Returns True if the set is empty

Expand source code
@property
def empty(self):
        '''
        Returns True if the set is empty
        '''
        return self._empty
var left

Returns the left limit of the set

Expand source code
@property
def left(self):
        '''
        Returns the left limit of the set
        '''
        return self._left_val
var mid

Computes the mid point to the crisp set.

Returns:

mid_point – float, the crisp set mid point

Raises:

Exception if the set is empty

Expand source code
@property
def mid(self):
        '''
        Computes the mid point to the crisp set.
        
        Returns:
        --------
        mid_point -- float, the crisp set mid point

        Raises:
        -------
        Exception if the set is empty
        '''

        if self.left is None or self.right is None:
                raise Exception('ERROR: Mid point cannot be found for this set.')

        if self._empty:
                raise Exception('ERROR: Mid point cannot be found for an empty set.')
        
        mid_point = (self._left_val+self._right_val)/2
        return mid_point
var right

Returns the right limit of the set

Expand source code
@property
def right(self):
        '''
        Returns the right limit of the set
        '''
        return self._right_val

Methods

def union(self, crisp_set)
Expand source code
def union(self, crisp_set):

        self._left_val = min(self._left_val, crisp_set.left)
        self._right_val = max(self._right_val, crisp_set.right)
class GeneralType2FuzzySet

An implementation of a general type 2 fuzzy set As a data structure, the general type-2 fuzzy set is represented by a dict of

The data structure, the general type-2 fuzzy set is represented by a dict of

Expand source code
class GeneralType2FuzzySet:
    '''
    An implementation of a general type 2 fuzzy set
    As a data structure, the general type-2 fuzzy set
    is represented by a dict of
    {primary_domain_val : secondary membership function object}
    '''

    def __init__(self):
        '''
        The data structure, the general type-2 fuzzy set
        is represented by a dict of
        {primary_domain_val : secondary membership function object}
        '''
        self.vertical_slices = {}
        self._precision = 4

    def __getitem__(self, primary_domain_val):
        '''
        For a given value of the primary domain,
        return the secondary membership function object

        Arguments:
        ----------
        primary_domain_val -- value of primary domain

        Returns:
        --------
        secondary_membership_function - smf object
        '''
        if primary_domain_val not in self.vertical_slices:
            raise Exception('Primary domain value of {} not in this set.'.format(primary_domain_val))

        return self.vertical_slices[primary_domain_val]

    def __eq__(self, value):

        current_primary_len = len(self.primary_domain())
        value_primary_len = len(value.primary_domain())
        union_primary_len = len(list(set(self.primary_domain()).union(value.primary_domain())))

        if current_primary_len != value_primary_len:
            return False 

        if union_primary_len != value_primary_len:
            return False

        for pri_domain in self.primary_domain():
            if self[pri_domain] != value[pri_domain]:
                return False

        return True

    def __str__(self):
        '''
        Returns a formal representation of the general type-2 fuzzy set in the form:
        '(a1/u1 + a2/u2 + ... + an/un)/x1 + ... + (b1/u1 + b2/u2 + ... + bn/un)/xn'

        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Arguments:
        ----------
        num_dec_places  -- number of decimal places

        Returns:
        --------
        set_representation -- string representation of gt2fs
        '''
        represented_slices = []
        dec_places_formatter = '''%0.{}f'''.format(self._precision)

        for primary_domain_val in self.primary_domain():
            sec_domains = list(self.vertical_slice(primary_domain_val).domain_elements())
            doms = list(self.vertical_slices[primary_domain_val].dom_elements())

            def slice_rep_creation(sec_domains, doms): return dec_places_formatter % (
                doms)+' / ' + dec_places_formatter % (sec_domains)

            m = map(slice_rep_creation, sec_domains, doms)

            slice_rep = ' + '.join(m)
            represented_slices.append('(' + slice_rep + ')')

        def f2(sec_domains, doms): return doms + ' / ' + dec_places_formatter % (sec_domains)
        m2 = map(f2, self.primary_domain(), represented_slices)
        set_representation = ' + '.join(m2)

        return set_representation

    def __repr__(self):
        return f'{self.__class__.__name__}({str(self)})'

    @classmethod
    def from_representation(cls, set_representation):
        '''
        Creates a general type-2 fuzzy set from a set representation of the form
        '(a1/u1 + a2/u2 + ... + an/un)/x1 + ... +(b1/u1 + b2/u2 + ... + bn/un)/xm'

        Reference:
        ---------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Definition of secondary grade - pg 119

        Arguments:
        ----------
        set_representation -- string, representation of the gt2fs

        Returns:
        --------
        gt2fs -- GeneralType2FuzzySet

        Raises:
        -------
        Exception -- if set_representation is empty, None or invalid
        '''
        if set_representation is None:
            raise Exception('Type-2 Set Representation cannot be null')
        if set_representation == '':
            raise Exception('Type-2 Set Representation cannot be empty')

        gt2fs = cls()

        try:
            # remove spaces, tabs returns,
            translation_table = dict.fromkeys(map(ord, ' \t\n\r'), None)
            set_representation = set_representation.translate(translation_table)

            # by splitting by +( we will get the secondary mfs
            # we would lose the initial ( of each mf except for the
            # first one - this will be removed lated
            sec_mfs_s = set_representation.split('+(')

            # so lets go through the membership functions
            for sec_mf in sec_mfs_s:
                # remove the leading '('
                # this will only happen in the first mf
                translation_table = dict.fromkeys(map(ord, '('), None)
                sec_mf = sec_mf.translate(translation_table)

                # we now split the secondary membership function from the
                # primary domain value
                vertical_slice_points_s, pri_dom_val_s = sec_mf.split(')/')

                # get the primary domain value and its corresponding
                # index
                primary_domain_val = float(pri_dom_val_s)

                # split by the '+' so that we will obtain the individual
                # dom / sec domain points
                points_s = vertical_slice_points_s.split('+')

                # we then examine each point to add them to the set
                for point_s in points_s:
                    # split by / so to obtain the dom and the sec domain value
                    sec_grade_val_s, sec_dom_val_s = point_s.split('/')

                    # get the secondary domain value and its corresponding
                    # index
                    secondary_domain_val = float(sec_dom_val_s)

                    sec_grade = float(sec_grade_val_s)
                    # add the point to the set
                    gt2fs.add_element(primary_domain_val, secondary_domain_val, sec_grade)
        except ValueError:
            raise Exception('Invalid set format')

        return gt2fs

    @classmethod
    def from_array(cls, primary_domain, secondary_domain, set_array):
        '''
        Creates a general type-2 fuzzy set from an array representation 
        of set where given is
        x -- a list containing the values of the primary domain
        u -- a list containing the values of the secondary domain
        set_array -- a 2D array where the rows map to the values of the u list
                                    the cols map to the values of the x list
                                    each value is the secondary grade value for
                                    the particular x / u combination
        

        Reference:
        ---------

        Arguments:
        ----------
        set_array -- 2D array containing the secondary grade values of the gt2fs
        x -- list containing the values of the primary domain
        u -- list containing the values of the secondary domain

        Returns:
        --------
        gt2fs -- GeneralType2FuzzySet

        Raises:
        -------
        Exception -- if there is a mismatch between the x, u and set_array dimensions
        '''
        set_array = np.array(set_array)

        # check that array sizes are correct
        (secondary_domain_size, primary_domain_size) = np.shape(set_array)

        if secondary_domain_size != len(secondary_domain):
            raise Exception('Secondary domain size mismatch')

        if primary_domain_size != len(primary_domain):
            raise Exception('Primary domain size mismatch')

        gt2fs = cls()

        # load all the elements in the array
        for pri_dom_val_idx, pri_dom_val in enumerate(primary_domain):
            for sec_dom_val_idx, sec_dom_val in enumerate(secondary_domain):
                gt2fs.add_element(pri_dom_val, sec_dom_val, set_array[sec_dom_val_idx][pri_dom_val_idx])

        return gt2fs

    @classmethod
    def load_file(cls, set_filename):
        '''
        Loads a general type-2 fuzzy set from a file. File must have the
        following format:
        '(a1/u1 + a2/u2 + ... + an/un)/x1 + (b1/u1 + b2/u2 + ... + bn/un)/xn'

        Reference:
        ---------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Definition of secondary grade - pg 119

        Arguments:
        ----------
        set_filename -- string, filename of the set

        Returns:
        --------
        gt2fs -- GeneralType2FuzzySet

        Raises:
        -------
        Exception -- if set_filename is empty, None or invalid
        '''
        representation = ''
        
        try:
            with open(set_filename, 'r') as file:
                representation = file.read()
        except IOError:
            raise Exception('Could not read file {}'.format(set_filename))
        
        gt2fs = cls()
        gt2fs = GeneralType2FuzzySet.from_representation(representation)

        return gt2fs

    @classmethod
    def from_horizontal_representation(cls, primary_domain, secondary_domain, set_def):
        '''
        Experimental method of representing a general type-2 fuzzy set by defining the
        spread at the points of piecewise type-1 parts.
        each point is a tuple (x, u, delta_left, delta_right); where:
        x is the primary domain value of the point
        u is the secondary domain value of the point
        delta_left is the spread of the type 2 set to the left and
        delta_right is the spread to the right of the type 2 set such that
        a triangular function is formed at u with values x-delta_left, x, x+delta_right

        Reference:
        ----------

        Arguments:
        ----------
        None

        Returns:
        --------
        gt2fs -- GeneralType2FuzzySet
        '''
        set_array = generate_gt2set_horizontal(primary_domain, secondary_domain, set_def)
        return GeneralType2FuzzySet.from_array(primary_domain, secondary_domain, set_array)

    def vertical_slice(self, primary_domain_val):
        '''
        For a given value of the primary domain, 
        returns a representation of the vertical slice
        in the form of a dict
        {secondary_domain : secondary_grade,  ... }

        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Arguments:
        ----------
        primary_domain_val -- value of primary domain

        Returns:
        --------
        vertical_slice - dict representing the values if the vertical slice
        '''
        return self[primary_domain_val]

    def save_file(self, set_filename, num_dec_places=4):
        '''
        Writes a formal representation of the general type-2 fuzzy set of the form:
        '(a1/u1 + a2/u2 + ... + an/un)/x1 + ... + (b1/u1 + b2/u2 + ... + bn/un)/xn'
        in a file

        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Arguments:
        ----------
        set_filename -- string containing the path of the file to be written
        num_dec_places -- number of decimal places used for secondary membership function, default 4

        Returns:
        --------
        None
        '''
        try:
            with open(set_filename, 'w') as fuzzy_file:
                fuzzy_file.write(self.__str__())
        except IOError:
            raise Exception('Unable to write file {}'.format(set_filename))

    def to_array_explicit(self):
        '''
        Transforms a General type 2 fuzzy set into a 2D array

        Arguments:
        ----------
        None

        Returns:
        --------
        primary_domain -- 1D array containing all the values in the primary domain
        secondary_domain -- 1D array containing all the values in the secondary domain
        set_array -- 2D array containing the degree of membership for the corresponding
                    primary/secondary combination
        '''

        # get all possible value of the secondary domain by a union with all the elements of
        # each vertical slice
        secondary_domain = []
        for primary_domain_val in self.vertical_slices:
            secondary_domain = list(set().union(secondary_domain, list(self[primary_domain_val].domain_elements())))

        secondary_domain.sort()

        # get all possible value of the primary domain
        primary_domain =  list(self.vertical_slices.keys())
        primary_domain.sort()

        # create an array to hold the dom
        set_array = np.zeros((len(secondary_domain), len(primary_domain)))

        for primary_domain_val in self.vertical_slices:
            pri_domain_idx = primary_domain.index(primary_domain_val)

            for sec_domain_val in self.vertical_slice(primary_domain_val).elements():
                sec_domain_idx = secondary_domain.index(sec_domain_val)

                set_array[sec_domain_idx, pri_domain_idx] = self.vertical_slice(primary_domain_val)[sec_domain_val]

        return primary_domain, secondary_domain, set_array

    def to_array_implicit(self, primary_domain, secondary_domain):
        '''
        Transforms a General type 2 fuzzy set into a 2D array but specifying the primary
        and secondary domain discrete values. The values of the set are thereby approximated 
        to these specified values

        Arguments:
        ----------
        primary_domain -- 1D array containing all the values in the primary domain
        secondary_domain -- 1D array containing all the values in the secondary domain

        Returns:
        --------
        set_array -- 2D array containing the degree of membership for the corresponding
                        primary/secondary combination
        '''

        # convert domain lists to numpy arrays
        primary_domain = np.array(primary_domain)
        secondary_domain = np.array(secondary_domain)
        
        # create resultant set
        set_array = np.zeros((len(secondary_domain), len(primary_domain)))

        # for each primary domain element, get closest element form list
        for primary_domain_val in self.vertical_slices:
            pri_dom_val_idx = np.argmin(np.abs(primary_domain - primary_domain_val))

            # for each secondary domain element, get closest element form list
            for sec_domain_val in self.vertical_slices[primary_domain_val]._elements:
                sec_dom_val_idx = np.argmin(np.abs(secondary_domain-sec_domain_val))

                # add set element in array
                set_array[sec_dom_val_idx, pri_dom_val_idx] = self.vertical_slice(primary_domain_val)[sec_domain_val]

        return set_array

    def primary_domain(self):
        '''
        The primary domain of this fuzzy set

        Arguments:
        ----------
        None

        Returns:
        --------
        primary_domain -- 1D array containing all the values in the primary domain
        '''
        primary_domain = list(self.vertical_slices.keys())
        return primary_domain

    def add_element(self, primary_domain_val, secondary_domain_val, secondary_grade):
        '''
        Adds a new element to the general type-2 fuzzy set. 
        Will not add the element if the secondary grade is 0
        Will raise and exception if secondary domain is <1 and >0
        or secondary grade is <1 and >0

        Arguments:
        ----------
        primary_domain_val -- float, value of the primary domain
        secondary_domain_val -- float, value of the secondary domain, must be <1 and >0
        secondary_grade -- float value of the secondary grade, must be <1 and >0

        Returns:
        --------
        None

        Raises:
        -------
        Exception if secondary domain is <1 and >0
        or secondary grade is <1 and >0
        '''
        # ignore if secondary grade = 0
        # if secondary_grade == 0:
        #       return
        
        # raise exception if secondary grade >1 or <0
        if secondary_grade > 1 or secondary_grade < 0:
            raise Exception('Invalid secondary grade value {} at x={} and u={}'.format(secondary_grade, primary_domain_val, secondary_domain_val))

        # raise exception if secondary domain >1 or <0
        if secondary_domain_val > 1 or secondary_domain_val < 0:
            raise Exception('Invalid secondary domain value {} at x={}'.format(secondary_domain_val, primary_domain_val))

        # if the primary domain exists just add the value of the smf
        # if not create a new smf to that primary domain value and
        # add that value
        if primary_domain_val in self.vertical_slices:
            self.vertical_slices[primary_domain_val].add_element(
                secondary_domain_val, secondary_grade)
        else:
            secondary_function = smf()
            secondary_function.add_element(secondary_domain_val, secondary_grade)
            self.vertical_slices[primary_domain_val] = secondary_function

    def add_membership_function(self, primary_domain_val, membership_function):
        '''
        Adds a membership function to the general type-2 fuzzy set. 
        uses the add_element() method and uses the checks implemented in
        that function
        
        Arguments:
        ----------
        primary_domain_val -- float, value of the primary domain
        membership_function -- TYpe1FuzzySet, membership function to be added

        Returns:
        --------
        None
        '''
        for secondary_domain_val in membership_function.domain_elements():
            self.add_element(primary_domain_val, secondary_domain_val, membership_function[secondary_domain_val])

    def footprint_of_uncertainty(self):
        '''
        For all values of x, return the limits of the values of u where 
        the secondary grade > 0

        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Arguments:
        ----------
        None
        
        Returns:
        --------
        footprint -- dict of primary domain element : (limits tuple)
        '''
        fou = {}

        for primary_domain_val in self.primary_domain():
            limits = self.vertical_slices[primary_domain_val].domain_limits()
            if not limits.empty:
                fou[primary_domain_val] = limits

        return fou

    def z_slice(self, slice_value):
        '''

        '''
        sliced_set = IntervalType2FuzzySet()

        for primary_domain_val in self.primary_domain():
            cut = self.vertical_slices[primary_domain_val].alpha_cut(slice_value)

            if not cut.empty:
                sliced_set.add_element(primary_domain_val, cut)

        return sliced_set

    def primary_membership(self, primary_domain_val):
        '''
        Returns the domain of the secondary membership function that is called the
        primary membership

        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Arguments:
        ----------
        None

        Returns:
        --------
        _primary_membership -- list containing the domain of the secondary function
                                at X = primary_domain_val
        '''
        if primary_domain_val not in self.vertical_slices:
            raise Exception('Primary domain value not in this set.')

        _primary_membership = self.vertical_slices[primary_domain_val].domain_elements()
        return _primary_membership

    def secondary_grade(self, primary_domain_val, secondary_domain_val):
        '''
        returns the amplitude of a secondary membership function,
        that is the secondary grade.
        
        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Arguments:
        ----------
        primary_domain_val -- float, value of primary domain
        secondary_domain_val -- float, value of secondary domain

        Returns:
        --------
        secondary_grade -- float, value of secondary grade
        '''

        if secondary_domain_val > 1 or secondary_domain_val < 0:
            raise Exception('Invalid secondary domain value')

        if primary_domain_val not in self.primary_domain():
            raise Exception('Invalid primary domain value')

        secondary_grade = self.vertical_slices[primary_domain_val].elements()[secondary_domain_val]
        return secondary_grade

    def embedded_type2_sets_count(self):
        '''
        returns the number of embedded type-2 fuzzy sets that can be 
        generated from this general type-2 fuzzy set.
        
        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Arguments:
        ----------
        None

        Returns:
        --------
        embedded_count -- float, number of et2fs
        '''
        count = 1
        for primary_domain_val in self.primary_domain():
            count = count * self.vertical_slice(primary_domain_val).element_count()
        
        return count

    def embedded_type2_sets(self):
        '''
        Lists all the type 2 embedded sets of this gt2fs.
        List will contain tuples in the form
        [(sec_grade_1, sec_domain_1, pri_domain_1), ... , (sec_grade_n, sec_domain_n, pri_domain_n)]

        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

        Arguments:
        ----------
        None

        Returns:
        --------
        results -- list, containing embedded type 2 sets

        '''
        set_array = []
        primary_domain, secondary_domain, set_array = self.to_array_explicit()

        # get an index array
        index_array = np.indices(set_array.shape)[0]

        # create a list with the number of non zero elements in each vertical slice
        # i.e. the number of non zero element in each column
        col_gen = [index_array[set_array[:, x] > 0, x] for x in range((set_array.shape)[1])]

        # the number of columns is the number of elements in the domain
        domain_index = range(0, (set_array.shape)[1])

        results = []
        # for every combination of the column elemnets create a type 2 embedded fuzzy set
        for t in itertools.product(*col_gen):
            embedded = list(map(lambda i: (set_array[t[i]][i], secondary_domain[t[i]], primary_domain[i]) , domain_index))
            results.append(embedded)

        return results

    def _format_slice(self, vertical_slice):
        x = list(vertical_slice.elements.keys())
        y = list(vertical_slice.elements.values())

        def f(x, y): return "%0.4f" % (y)+'/'+"%0.2f" % (x)
        m = map(f, x, y)
        slice_rep = ' + '.join(m)
        return slice_rep

    def union(self, gt2fs):
        
        resultant_gt2fs = GeneralType2FuzzySet()

        primary_domain_a = self.primary_domain()
        primary_domain_b = gt2fs.primary_domain()

        primary_domain_union = list(set().union(primary_domain_a, primary_domain_b))

        for primary_domain_element in primary_domain_union:
            if primary_domain_element not in primary_domain_a:
                resultant_gt2fs.add_membership_function(primary_domain_element, gt2fs[primary_domain_element])
            elif primary_domain_element not in primary_domain_b:
                resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element])
            else:
                resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element].join(gt2fs[primary_domain_element]))

        return resultant_gt2fs

    def intersection(self, gt2fs):
        '''
        intersection  
        '''
        resultant_gt2fs = GeneralType2FuzzySet()

        primary_domain_a = self.primary_domain()
        primary_domain_b = gt2fs.primary_domain()

        primary_domain_union = list(set().union(primary_domain_a, primary_domain_b))

        for primary_domain_element in primary_domain_union:
            if primary_domain_element not in primary_domain_a:
                resultant_gt2fs.add_membership_function(primary_domain_element, gt2fs[primary_domain_element])
            elif primary_domain_element not in primary_domain_b:
                resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element])
            else:
                resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element].meet(gt2fs[primary_domain_element]))

        return resultant_gt2fs

    def complement(self):
        '''
        finds the complement of a general type 2 fuzzy set 
        '''
        resultant_gt2fs = GeneralType2FuzzySet()

        for primary_domain_element in self.primary_domain():
                    resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element].negation())

        return resultant_gt2fs

Static methods

def from_array(primary_domain, secondary_domain, set_array)

Creates a general type-2 fuzzy set from an array representation of set where given is x – a list containing the values of the primary domain u – a list containing the values of the secondary domain set_array – a 2D array where the rows map to the values of the u list the cols map to the values of the x list each value is the secondary grade value for the particular x / u combination

Reference:

Arguments:

set_array – 2D array containing the secondary grade values of the gt2fs x – list containing the values of the primary domain u – list containing the values of the secondary domain

Returns:

gt2fs – GeneralType2FuzzySet

Raises:

Exception – if there is a mismatch between the x, u and set_array dimensions

Expand source code
@classmethod
def from_array(cls, primary_domain, secondary_domain, set_array):
    '''
    Creates a general type-2 fuzzy set from an array representation 
    of set where given is
    x -- a list containing the values of the primary domain
    u -- a list containing the values of the secondary domain
    set_array -- a 2D array where the rows map to the values of the u list
                                the cols map to the values of the x list
                                each value is the secondary grade value for
                                the particular x / u combination
    

    Reference:
    ---------

    Arguments:
    ----------
    set_array -- 2D array containing the secondary grade values of the gt2fs
    x -- list containing the values of the primary domain
    u -- list containing the values of the secondary domain

    Returns:
    --------
    gt2fs -- GeneralType2FuzzySet

    Raises:
    -------
    Exception -- if there is a mismatch between the x, u and set_array dimensions
    '''
    set_array = np.array(set_array)

    # check that array sizes are correct
    (secondary_domain_size, primary_domain_size) = np.shape(set_array)

    if secondary_domain_size != len(secondary_domain):
        raise Exception('Secondary domain size mismatch')

    if primary_domain_size != len(primary_domain):
        raise Exception('Primary domain size mismatch')

    gt2fs = cls()

    # load all the elements in the array
    for pri_dom_val_idx, pri_dom_val in enumerate(primary_domain):
        for sec_dom_val_idx, sec_dom_val in enumerate(secondary_domain):
            gt2fs.add_element(pri_dom_val, sec_dom_val, set_array[sec_dom_val_idx][pri_dom_val_idx])

    return gt2fs
def from_horizontal_representation(primary_domain, secondary_domain, set_def)

Experimental method of representing a general type-2 fuzzy set by defining the spread at the points of piecewise type-1 parts. each point is a tuple (x, u, delta_left, delta_right); where: x is the primary domain value of the point u is the secondary domain value of the point delta_left is the spread of the type 2 set to the left and delta_right is the spread to the right of the type 2 set such that a triangular function is formed at u with values x-delta_left, x, x+delta_right

Reference:

Arguments:

None

Returns:

gt2fs – GeneralType2FuzzySet

Expand source code
@classmethod
def from_horizontal_representation(cls, primary_domain, secondary_domain, set_def):
    '''
    Experimental method of representing a general type-2 fuzzy set by defining the
    spread at the points of piecewise type-1 parts.
    each point is a tuple (x, u, delta_left, delta_right); where:
    x is the primary domain value of the point
    u is the secondary domain value of the point
    delta_left is the spread of the type 2 set to the left and
    delta_right is the spread to the right of the type 2 set such that
    a triangular function is formed at u with values x-delta_left, x, x+delta_right

    Reference:
    ----------

    Arguments:
    ----------
    None

    Returns:
    --------
    gt2fs -- GeneralType2FuzzySet
    '''
    set_array = generate_gt2set_horizontal(primary_domain, secondary_domain, set_def)
    return GeneralType2FuzzySet.from_array(primary_domain, secondary_domain, set_array)
def from_representation(set_representation)

Creates a general type-2 fuzzy set from a set representation of the form '(a1/u1 + a2/u2 + … + an/un)/x1 + … +(b1/u1 + b2/u2 + … + bn/un)/xm'

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Definition of secondary grade - pg 119

Arguments:

set_representation – string, representation of the gt2fs

Returns:

gt2fs – GeneralType2FuzzySet

Raises:

Exception – if set_representation is empty, None or invalid

Expand source code
@classmethod
def from_representation(cls, set_representation):
    '''
    Creates a general type-2 fuzzy set from a set representation of the form
    '(a1/u1 + a2/u2 + ... + an/un)/x1 + ... +(b1/u1 + b2/u2 + ... + bn/un)/xm'

    Reference:
    ---------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Definition of secondary grade - pg 119

    Arguments:
    ----------
    set_representation -- string, representation of the gt2fs

    Returns:
    --------
    gt2fs -- GeneralType2FuzzySet

    Raises:
    -------
    Exception -- if set_representation is empty, None or invalid
    '''
    if set_representation is None:
        raise Exception('Type-2 Set Representation cannot be null')
    if set_representation == '':
        raise Exception('Type-2 Set Representation cannot be empty')

    gt2fs = cls()

    try:
        # remove spaces, tabs returns,
        translation_table = dict.fromkeys(map(ord, ' \t\n\r'), None)
        set_representation = set_representation.translate(translation_table)

        # by splitting by +( we will get the secondary mfs
        # we would lose the initial ( of each mf except for the
        # first one - this will be removed lated
        sec_mfs_s = set_representation.split('+(')

        # so lets go through the membership functions
        for sec_mf in sec_mfs_s:
            # remove the leading '('
            # this will only happen in the first mf
            translation_table = dict.fromkeys(map(ord, '('), None)
            sec_mf = sec_mf.translate(translation_table)

            # we now split the secondary membership function from the
            # primary domain value
            vertical_slice_points_s, pri_dom_val_s = sec_mf.split(')/')

            # get the primary domain value and its corresponding
            # index
            primary_domain_val = float(pri_dom_val_s)

            # split by the '+' so that we will obtain the individual
            # dom / sec domain points
            points_s = vertical_slice_points_s.split('+')

            # we then examine each point to add them to the set
            for point_s in points_s:
                # split by / so to obtain the dom and the sec domain value
                sec_grade_val_s, sec_dom_val_s = point_s.split('/')

                # get the secondary domain value and its corresponding
                # index
                secondary_domain_val = float(sec_dom_val_s)

                sec_grade = float(sec_grade_val_s)
                # add the point to the set
                gt2fs.add_element(primary_domain_val, secondary_domain_val, sec_grade)
    except ValueError:
        raise Exception('Invalid set format')

    return gt2fs
def load_file(set_filename)

Loads a general type-2 fuzzy set from a file. File must have the following format: '(a1/u1 + a2/u2 + … + an/un)/x1 + (b1/u1 + b2/u2 + … + bn/un)/xn'

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Definition of secondary grade - pg 119

Arguments:

set_filename – string, filename of the set

Returns:

gt2fs – GeneralType2FuzzySet

Raises:

Exception – if set_filename is empty, None or invalid

Expand source code
@classmethod
def load_file(cls, set_filename):
    '''
    Loads a general type-2 fuzzy set from a file. File must have the
    following format:
    '(a1/u1 + a2/u2 + ... + an/un)/x1 + (b1/u1 + b2/u2 + ... + bn/un)/xn'

    Reference:
    ---------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Definition of secondary grade - pg 119

    Arguments:
    ----------
    set_filename -- string, filename of the set

    Returns:
    --------
    gt2fs -- GeneralType2FuzzySet

    Raises:
    -------
    Exception -- if set_filename is empty, None or invalid
    '''
    representation = ''
    
    try:
        with open(set_filename, 'r') as file:
            representation = file.read()
    except IOError:
        raise Exception('Could not read file {}'.format(set_filename))
    
    gt2fs = cls()
    gt2fs = GeneralType2FuzzySet.from_representation(representation)

    return gt2fs

Methods

def add_element(self, primary_domain_val, secondary_domain_val, secondary_grade)

Adds a new element to the general type-2 fuzzy set. Will not add the element if the secondary grade is 0 Will raise and exception if secondary domain is <1 and >0 or secondary grade is <1 and >0

Arguments:

primary_domain_val – float, value of the primary domain secondary_domain_val – float, value of the secondary domain, must be <1 and >0 secondary_grade – float value of the secondary grade, must be <1 and >0

Returns:

None

Raises:

Exception if secondary domain is <1 and >0 or secondary grade is <1 and >0

Expand source code
def add_element(self, primary_domain_val, secondary_domain_val, secondary_grade):
    '''
    Adds a new element to the general type-2 fuzzy set. 
    Will not add the element if the secondary grade is 0
    Will raise and exception if secondary domain is <1 and >0
    or secondary grade is <1 and >0

    Arguments:
    ----------
    primary_domain_val -- float, value of the primary domain
    secondary_domain_val -- float, value of the secondary domain, must be <1 and >0
    secondary_grade -- float value of the secondary grade, must be <1 and >0

    Returns:
    --------
    None

    Raises:
    -------
    Exception if secondary domain is <1 and >0
    or secondary grade is <1 and >0
    '''
    # ignore if secondary grade = 0
    # if secondary_grade == 0:
    #       return
    
    # raise exception if secondary grade >1 or <0
    if secondary_grade > 1 or secondary_grade < 0:
        raise Exception('Invalid secondary grade value {} at x={} and u={}'.format(secondary_grade, primary_domain_val, secondary_domain_val))

    # raise exception if secondary domain >1 or <0
    if secondary_domain_val > 1 or secondary_domain_val < 0:
        raise Exception('Invalid secondary domain value {} at x={}'.format(secondary_domain_val, primary_domain_val))

    # if the primary domain exists just add the value of the smf
    # if not create a new smf to that primary domain value and
    # add that value
    if primary_domain_val in self.vertical_slices:
        self.vertical_slices[primary_domain_val].add_element(
            secondary_domain_val, secondary_grade)
    else:
        secondary_function = smf()
        secondary_function.add_element(secondary_domain_val, secondary_grade)
        self.vertical_slices[primary_domain_val] = secondary_function
def add_membership_function(self, primary_domain_val, membership_function)

Adds a membership function to the general type-2 fuzzy set. uses the add_element() method and uses the checks implemented in that function

Arguments:

primary_domain_val – float, value of the primary domain membership_function – TYpe1FuzzySet, membership function to be added

Returns:

None

Expand source code
def add_membership_function(self, primary_domain_val, membership_function):
    '''
    Adds a membership function to the general type-2 fuzzy set. 
    uses the add_element() method and uses the checks implemented in
    that function
    
    Arguments:
    ----------
    primary_domain_val -- float, value of the primary domain
    membership_function -- TYpe1FuzzySet, membership function to be added

    Returns:
    --------
    None
    '''
    for secondary_domain_val in membership_function.domain_elements():
        self.add_element(primary_domain_val, secondary_domain_val, membership_function[secondary_domain_val])
def complement(self)

finds the complement of a general type 2 fuzzy set

Expand source code
def complement(self):
    '''
    finds the complement of a general type 2 fuzzy set 
    '''
    resultant_gt2fs = GeneralType2FuzzySet()

    for primary_domain_element in self.primary_domain():
                resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element].negation())

    return resultant_gt2fs
def embedded_type2_sets(self)

Lists all the type 2 embedded sets of this gt2fs. List will contain tuples in the form [(sec_grade_1, sec_domain_1, pri_domain_1), … , (sec_grade_n, sec_domain_n, pri_domain_n)]

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Arguments:

None

Returns:

results – list, containing embedded type 2 sets

Expand source code
def embedded_type2_sets(self):
    '''
    Lists all the type 2 embedded sets of this gt2fs.
    List will contain tuples in the form
    [(sec_grade_1, sec_domain_1, pri_domain_1), ... , (sec_grade_n, sec_domain_n, pri_domain_n)]

    Reference:
    ----------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Arguments:
    ----------
    None

    Returns:
    --------
    results -- list, containing embedded type 2 sets

    '''
    set_array = []
    primary_domain, secondary_domain, set_array = self.to_array_explicit()

    # get an index array
    index_array = np.indices(set_array.shape)[0]

    # create a list with the number of non zero elements in each vertical slice
    # i.e. the number of non zero element in each column
    col_gen = [index_array[set_array[:, x] > 0, x] for x in range((set_array.shape)[1])]

    # the number of columns is the number of elements in the domain
    domain_index = range(0, (set_array.shape)[1])

    results = []
    # for every combination of the column elemnets create a type 2 embedded fuzzy set
    for t in itertools.product(*col_gen):
        embedded = list(map(lambda i: (set_array[t[i]][i], secondary_domain[t[i]], primary_domain[i]) , domain_index))
        results.append(embedded)

    return results
def embedded_type2_sets_count(self)

returns the number of embedded type-2 fuzzy sets that can be generated from this general type-2 fuzzy set.

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Arguments:

None

Returns:

embedded_count – float, number of et2fs

Expand source code
def embedded_type2_sets_count(self):
    '''
    returns the number of embedded type-2 fuzzy sets that can be 
    generated from this general type-2 fuzzy set.
    
    Reference:
    ----------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Arguments:
    ----------
    None

    Returns:
    --------
    embedded_count -- float, number of et2fs
    '''
    count = 1
    for primary_domain_val in self.primary_domain():
        count = count * self.vertical_slice(primary_domain_val).element_count()
    
    return count
def footprint_of_uncertainty(self)

For all values of x, return the limits of the values of u where the secondary grade > 0

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Arguments:

None

Returns:

footprint – dict of primary domain element : (limits tuple)

Expand source code
def footprint_of_uncertainty(self):
    '''
    For all values of x, return the limits of the values of u where 
    the secondary grade > 0

    Reference:
    ----------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Arguments:
    ----------
    None
    
    Returns:
    --------
    footprint -- dict of primary domain element : (limits tuple)
    '''
    fou = {}

    for primary_domain_val in self.primary_domain():
        limits = self.vertical_slices[primary_domain_val].domain_limits()
        if not limits.empty:
            fou[primary_domain_val] = limits

    return fou
def intersection(self, gt2fs)

intersection

Expand source code
def intersection(self, gt2fs):
    '''
    intersection  
    '''
    resultant_gt2fs = GeneralType2FuzzySet()

    primary_domain_a = self.primary_domain()
    primary_domain_b = gt2fs.primary_domain()

    primary_domain_union = list(set().union(primary_domain_a, primary_domain_b))

    for primary_domain_element in primary_domain_union:
        if primary_domain_element not in primary_domain_a:
            resultant_gt2fs.add_membership_function(primary_domain_element, gt2fs[primary_domain_element])
        elif primary_domain_element not in primary_domain_b:
            resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element])
        else:
            resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element].meet(gt2fs[primary_domain_element]))

    return resultant_gt2fs
def primary_domain(self)

The primary domain of this fuzzy set

Arguments:

None

Returns:

primary_domain – 1D array containing all the values in the primary domain

Expand source code
def primary_domain(self):
    '''
    The primary domain of this fuzzy set

    Arguments:
    ----------
    None

    Returns:
    --------
    primary_domain -- 1D array containing all the values in the primary domain
    '''
    primary_domain = list(self.vertical_slices.keys())
    return primary_domain
def primary_membership(self, primary_domain_val)

Returns the domain of the secondary membership function that is called the primary membership

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Arguments:

None

Returns:

_primary_membership – list containing the domain of the secondary function at X = primary_domain_val

Expand source code
def primary_membership(self, primary_domain_val):
    '''
    Returns the domain of the secondary membership function that is called the
    primary membership

    Reference:
    ----------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Arguments:
    ----------
    None

    Returns:
    --------
    _primary_membership -- list containing the domain of the secondary function
                            at X = primary_domain_val
    '''
    if primary_domain_val not in self.vertical_slices:
        raise Exception('Primary domain value not in this set.')

    _primary_membership = self.vertical_slices[primary_domain_val].domain_elements()
    return _primary_membership
def save_file(self, set_filename, num_dec_places=4)

Writes a formal representation of the general type-2 fuzzy set of the form: '(a1/u1 + a2/u2 + … + an/un)/x1 + … + (b1/u1 + b2/u2 + … + bn/un)/xn' in a file

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Arguments:

set_filename – string containing the path of the file to be written num_dec_places – number of decimal places used for secondary membership function, default 4

Returns:

None

Expand source code
def save_file(self, set_filename, num_dec_places=4):
    '''
    Writes a formal representation of the general type-2 fuzzy set of the form:
    '(a1/u1 + a2/u2 + ... + an/un)/x1 + ... + (b1/u1 + b2/u2 + ... + bn/un)/xn'
    in a file

    Reference:
    ----------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Arguments:
    ----------
    set_filename -- string containing the path of the file to be written
    num_dec_places -- number of decimal places used for secondary membership function, default 4

    Returns:
    --------
    None
    '''
    try:
        with open(set_filename, 'w') as fuzzy_file:
            fuzzy_file.write(self.__str__())
    except IOError:
        raise Exception('Unable to write file {}'.format(set_filename))
def secondary_grade(self, primary_domain_val, secondary_domain_val)

returns the amplitude of a secondary membership function, that is the secondary grade.

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Arguments:

primary_domain_val – float, value of primary domain secondary_domain_val – float, value of secondary domain

Returns:

secondary_grade – float, value of secondary grade

Expand source code
def secondary_grade(self, primary_domain_val, secondary_domain_val):
    '''
    returns the amplitude of a secondary membership function,
    that is the secondary grade.
    
    Reference:
    ----------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Arguments:
    ----------
    primary_domain_val -- float, value of primary domain
    secondary_domain_val -- float, value of secondary domain

    Returns:
    --------
    secondary_grade -- float, value of secondary grade
    '''

    if secondary_domain_val > 1 or secondary_domain_val < 0:
        raise Exception('Invalid secondary domain value')

    if primary_domain_val not in self.primary_domain():
        raise Exception('Invalid primary domain value')

    secondary_grade = self.vertical_slices[primary_domain_val].elements()[secondary_domain_val]
    return secondary_grade
def to_array_explicit(self)

Transforms a General type 2 fuzzy set into a 2D array

Arguments:

None

Returns:

primary_domain – 1D array containing all the values in the primary domain secondary_domain – 1D array containing all the values in the secondary domain set_array – 2D array containing the degree of membership for the corresponding primary/secondary combination

Expand source code
def to_array_explicit(self):
    '''
    Transforms a General type 2 fuzzy set into a 2D array

    Arguments:
    ----------
    None

    Returns:
    --------
    primary_domain -- 1D array containing all the values in the primary domain
    secondary_domain -- 1D array containing all the values in the secondary domain
    set_array -- 2D array containing the degree of membership for the corresponding
                primary/secondary combination
    '''

    # get all possible value of the secondary domain by a union with all the elements of
    # each vertical slice
    secondary_domain = []
    for primary_domain_val in self.vertical_slices:
        secondary_domain = list(set().union(secondary_domain, list(self[primary_domain_val].domain_elements())))

    secondary_domain.sort()

    # get all possible value of the primary domain
    primary_domain =  list(self.vertical_slices.keys())
    primary_domain.sort()

    # create an array to hold the dom
    set_array = np.zeros((len(secondary_domain), len(primary_domain)))

    for primary_domain_val in self.vertical_slices:
        pri_domain_idx = primary_domain.index(primary_domain_val)

        for sec_domain_val in self.vertical_slice(primary_domain_val).elements():
            sec_domain_idx = secondary_domain.index(sec_domain_val)

            set_array[sec_domain_idx, pri_domain_idx] = self.vertical_slice(primary_domain_val)[sec_domain_val]

    return primary_domain, secondary_domain, set_array
def to_array_implicit(self, primary_domain, secondary_domain)

Transforms a General type 2 fuzzy set into a 2D array but specifying the primary and secondary domain discrete values. The values of the set are thereby approximated to these specified values

Arguments:

primary_domain – 1D array containing all the values in the primary domain secondary_domain – 1D array containing all the values in the secondary domain

Returns:

set_array – 2D array containing the degree of membership for the corresponding primary/secondary combination

Expand source code
def to_array_implicit(self, primary_domain, secondary_domain):
    '''
    Transforms a General type 2 fuzzy set into a 2D array but specifying the primary
    and secondary domain discrete values. The values of the set are thereby approximated 
    to these specified values

    Arguments:
    ----------
    primary_domain -- 1D array containing all the values in the primary domain
    secondary_domain -- 1D array containing all the values in the secondary domain

    Returns:
    --------
    set_array -- 2D array containing the degree of membership for the corresponding
                    primary/secondary combination
    '''

    # convert domain lists to numpy arrays
    primary_domain = np.array(primary_domain)
    secondary_domain = np.array(secondary_domain)
    
    # create resultant set
    set_array = np.zeros((len(secondary_domain), len(primary_domain)))

    # for each primary domain element, get closest element form list
    for primary_domain_val in self.vertical_slices:
        pri_dom_val_idx = np.argmin(np.abs(primary_domain - primary_domain_val))

        # for each secondary domain element, get closest element form list
        for sec_domain_val in self.vertical_slices[primary_domain_val]._elements:
            sec_dom_val_idx = np.argmin(np.abs(secondary_domain-sec_domain_val))

            # add set element in array
            set_array[sec_dom_val_idx, pri_dom_val_idx] = self.vertical_slice(primary_domain_val)[sec_domain_val]

    return set_array
def union(self, gt2fs)
Expand source code
def union(self, gt2fs):
    
    resultant_gt2fs = GeneralType2FuzzySet()

    primary_domain_a = self.primary_domain()
    primary_domain_b = gt2fs.primary_domain()

    primary_domain_union = list(set().union(primary_domain_a, primary_domain_b))

    for primary_domain_element in primary_domain_union:
        if primary_domain_element not in primary_domain_a:
            resultant_gt2fs.add_membership_function(primary_domain_element, gt2fs[primary_domain_element])
        elif primary_domain_element not in primary_domain_b:
            resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element])
        else:
            resultant_gt2fs.add_membership_function(primary_domain_element, self[primary_domain_element].join(gt2fs[primary_domain_element]))

    return resultant_gt2fs
def vertical_slice(self, primary_domain_val)

For a given value of the primary domain, returns a representation of the vertical slice in the form of a dict

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

Arguments:

primary_domain_val – value of primary domain

Returns:

vertical_slice - dict representing the values if the vertical slice

Expand source code
def vertical_slice(self, primary_domain_val):
    '''
    For a given value of the primary domain, 
    returns a representation of the vertical slice
    in the form of a dict
    {secondary_domain : secondary_grade,  ... }

    Reference:
    ----------
    J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
    Trans. Fuzzy Systems, vol. 10, no. 2, pp. 117–127, Apr. 2002.

    Arguments:
    ----------
    primary_domain_val -- value of primary domain

    Returns:
    --------
    vertical_slice - dict representing the values if the vertical slice
    '''
    return self[primary_domain_val]
def z_slice(self, slice_value)
Expand source code
def z_slice(self, slice_value):
    '''

    '''
    sliced_set = IntervalType2FuzzySet()

    for primary_domain_val in self.primary_domain():
        cut = self.vertical_slices[primary_domain_val].alpha_cut(slice_value)

        if not cut.empty:
            sliced_set.add_element(primary_domain_val, cut)

    return sliced_set
class IntervalType2FuzzySet
Expand source code
class IntervalType2FuzzySet:

        def __init__(self):
                self._interval_set_elements = {}
                self._empty=True

        def __getitem__(self, primary_domain_val):
                '''
                For a given value of the primary domain, 
                return the crisp set

                Arguments:
                ----------
                primary_domain_val -- value of primary domain

                Returns:
                --------
                crisp_set - corresponding crisp set
                '''
                if primary_domain_val not in self._interval_set_elements:
                        raise Exception(f'Primary domain value of {primary_domain_val} not in this set.')

                return self._interval_set_elements[primary_domain_val]

        @property
        def empty(self):
                '''
                Returns True if set is empty
                '''
                return self._empty

        @ classmethod
        def from_general_type2_set(cls, gt2fs):
                '''
                Creates an Interval Type-2 Fuzzy Set from a General
                Type-2 Fuzzy Set

                Arguments:
                ----------
                gt2fs -- the general type-2 fuzzy set

                Returns:
                --------
                it2fs -- the resulting interval type-2 fuzzy set
                '''
                it2fs = cls()

                it2fs = gt2fs.z_slice(0)

                return it2fs

        @classmethod
        def from_representation(cls, set_representation):
                if set_representation == None:
                        raise Exception('Interval Type-2 Set Representation cannot be null')
                if set_representation == '':
                        raise Exception('Interval Type-2 Set Representation cannot be empty')

                it2fs = cls()

                try:
                        # remove spaces, tabs returns,
                        translation_table = dict.fromkeys(map(ord, ' \t\n\r'), None)
                        set_representation = set_representation.translate(translation_table)

                        # by splitting by '+' we will get the secondary mfs
                        sec_mfs_s = set_representation.split('+')

                        # so lets go through the membership functions
                        for sec_mf in sec_mfs_s:

                                # we now split the membership function from the
                                # primary domain value
                                vslice_points_s, pri_dom_val_s = sec_mf.split('/')

                                # get the primary domain value and its corresponding
                                # index
                                primary_domain_val = float(pri_dom_val_s)

                                # the vertical slice points is represnted by [left, right]
                                # remove the braces
                                translation_table = dict.fromkeys(map(ord, '[]'), None)
                                vslice_points_s = vslice_points_s.translate(translation_table)

                                # split by the '+' so that we will obtain the individual
                                # dom / sec domain points
                                left_s, right_s = vslice_points_s.split(',')

                                left = float(left_s)
                                right = float(right_s)

                                it2fs.add_element(primary_domain_val, CrispSet(left, right))
                except ValueError:
                        raise Exception('Invalid set format')

                return it2fs

        @classmethod
        def load_file(cls, set_filename):
                '''
                Loads a interval type-2 fuzzy set from a file. File must have the
                following format:
                '[l1, h1]/x1 + [l2, h2]/x2 + ... + [ln, hn]/xn'

                Reference:
                ---------

                Arguments:
                ----------
                set_filename -- string, filename of the set

                Returns:
                --------
                it2fs -- IntervalType2FuzzySet

                Raises:
                -------
                Exception -- if set_filename is empty, None or invalid
                '''
                representation = ''
                
                try:
                        with open(set_filename, 'r') as file:
                                representation = file.read()
                except IOError:
                        raise Exception('Could not read file {}'.format(set_filename))
                
                it2fs = cls()
                it2fs = IntervalType2FuzzySet.from_representation(representation)

                return it2fs

        @classmethod
        def from_hmf_lmf(cls, primary_domain, hmf, lmf):
                '''
                '''
                it2fs = cls()
                for idx, primary_domain_element in enumerate(primary_domain):
                        it2fs.add_element(primary_domain_element, CrispSet(lmf[idx], hmf[idx]))

                return it2fs

        def primary_domain(self):
                '''
                The primary domain of this fuzzy set

                Arguments:
                ----------
                None

                Returns:
                --------
                primary_domain -- list, containing all the values in the primary domain
                '''
                primary_domain = list(self._interval_set_elements.keys())
                return primary_domain

        def mid_domain_element(self):
                '''
                returns the middle domain element
                '''
                return self.primary_domain()[int(len(self.primary_domain())/2)]

        def __str__(self):
                '''
                Creates a string representation of the interval type 2 fuzzy set in the form:
                (lower_1, upper_1)/domain_1 + ... + (lower_n, upper_n)/domain_n
                '''
                set_representation_list = []

                for primary_domain_element in self.primary_domain():
                        set_representation_list.append(f'{self._interval_set_elements[primary_domain_element]}/{primary_domain_element}\n')

                set_representation = '+'.join(set_representation_list)

                return set_representation

        def __repr__(self):
                return f'{self.__class__.__name__}(str(self))'

        def add_element(self, primary_domain_val, crisp_set):
                '''
                adds a new element to the interval type 2 set
                if the set already contains a range at the domain value,
                the minimum left and the maximum right are selected.

                Arguments:
                ----------
                primary_domain_val -- float, value of the primary domain
                left_val -- the left (minimum) value
                right_val -- the right (maximum) value
                '''

                if crisp_set.empty:
                        return

                if primary_domain_val in self._interval_set_elements:
                        self._interval_set_elements[primary_domain_val].union(crisp_set)
                else:
                        self._interval_set_elements[primary_domain_val] = crisp_set

                if self._empty:
                        self._empty = False


        def lower_membership_function(self):

                umf = []

                for limits in self._interval_set_elements.values():
                        umf.append(limits.left)
                
                return umf

        def higher_membership_function(self):

                hmf = []

                for limits in self._interval_set_elements.values():
                        hmf.append(limits.right)
                
                return hmf

Static methods

def from_general_type2_set(gt2fs)

Creates an Interval Type-2 Fuzzy Set from a General Type-2 Fuzzy Set

Arguments:

gt2fs – the general type-2 fuzzy set

Returns:

it2fs – the resulting interval type-2 fuzzy set

Expand source code
@ classmethod
def from_general_type2_set(cls, gt2fs):
        '''
        Creates an Interval Type-2 Fuzzy Set from a General
        Type-2 Fuzzy Set

        Arguments:
        ----------
        gt2fs -- the general type-2 fuzzy set

        Returns:
        --------
        it2fs -- the resulting interval type-2 fuzzy set
        '''
        it2fs = cls()

        it2fs = gt2fs.z_slice(0)

        return it2fs
def from_hmf_lmf(primary_domain, hmf, lmf)
Expand source code
@classmethod
def from_hmf_lmf(cls, primary_domain, hmf, lmf):
        '''
        '''
        it2fs = cls()
        for idx, primary_domain_element in enumerate(primary_domain):
                it2fs.add_element(primary_domain_element, CrispSet(lmf[idx], hmf[idx]))

        return it2fs
def from_representation(set_representation)
Expand source code
@classmethod
def from_representation(cls, set_representation):
        if set_representation == None:
                raise Exception('Interval Type-2 Set Representation cannot be null')
        if set_representation == '':
                raise Exception('Interval Type-2 Set Representation cannot be empty')

        it2fs = cls()

        try:
                # remove spaces, tabs returns,
                translation_table = dict.fromkeys(map(ord, ' \t\n\r'), None)
                set_representation = set_representation.translate(translation_table)

                # by splitting by '+' we will get the secondary mfs
                sec_mfs_s = set_representation.split('+')

                # so lets go through the membership functions
                for sec_mf in sec_mfs_s:

                        # we now split the membership function from the
                        # primary domain value
                        vslice_points_s, pri_dom_val_s = sec_mf.split('/')

                        # get the primary domain value and its corresponding
                        # index
                        primary_domain_val = float(pri_dom_val_s)

                        # the vertical slice points is represnted by [left, right]
                        # remove the braces
                        translation_table = dict.fromkeys(map(ord, '[]'), None)
                        vslice_points_s = vslice_points_s.translate(translation_table)

                        # split by the '+' so that we will obtain the individual
                        # dom / sec domain points
                        left_s, right_s = vslice_points_s.split(',')

                        left = float(left_s)
                        right = float(right_s)

                        it2fs.add_element(primary_domain_val, CrispSet(left, right))
        except ValueError:
                raise Exception('Invalid set format')

        return it2fs
def load_file(set_filename)

Loads a interval type-2 fuzzy set from a file. File must have the following format: '[l1, h1]/x1 + [l2, h2]/x2 + … + [ln, hn]/xn'

Reference:

Arguments:

set_filename – string, filename of the set

Returns:

it2fs – IntervalType2FuzzySet

Raises:

Exception – if set_filename is empty, None or invalid

Expand source code
@classmethod
def load_file(cls, set_filename):
        '''
        Loads a interval type-2 fuzzy set from a file. File must have the
        following format:
        '[l1, h1]/x1 + [l2, h2]/x2 + ... + [ln, hn]/xn'

        Reference:
        ---------

        Arguments:
        ----------
        set_filename -- string, filename of the set

        Returns:
        --------
        it2fs -- IntervalType2FuzzySet

        Raises:
        -------
        Exception -- if set_filename is empty, None or invalid
        '''
        representation = ''
        
        try:
                with open(set_filename, 'r') as file:
                        representation = file.read()
        except IOError:
                raise Exception('Could not read file {}'.format(set_filename))
        
        it2fs = cls()
        it2fs = IntervalType2FuzzySet.from_representation(representation)

        return it2fs

Instance variables

var empty

Returns True if set is empty

Expand source code
@property
def empty(self):
        '''
        Returns True if set is empty
        '''
        return self._empty

Methods

def add_element(self, primary_domain_val, crisp_set)

adds a new element to the interval type 2 set if the set already contains a range at the domain value, the minimum left and the maximum right are selected.

Arguments:

primary_domain_val – float, value of the primary domain left_val – the left (minimum) value right_val – the right (maximum) value

Expand source code
def add_element(self, primary_domain_val, crisp_set):
        '''
        adds a new element to the interval type 2 set
        if the set already contains a range at the domain value,
        the minimum left and the maximum right are selected.

        Arguments:
        ----------
        primary_domain_val -- float, value of the primary domain
        left_val -- the left (minimum) value
        right_val -- the right (maximum) value
        '''

        if crisp_set.empty:
                return

        if primary_domain_val in self._interval_set_elements:
                self._interval_set_elements[primary_domain_val].union(crisp_set)
        else:
                self._interval_set_elements[primary_domain_val] = crisp_set

        if self._empty:
                self._empty = False
def higher_membership_function(self)
Expand source code
def higher_membership_function(self):

        hmf = []

        for limits in self._interval_set_elements.values():
                hmf.append(limits.right)
        
        return hmf
def lower_membership_function(self)
Expand source code
def lower_membership_function(self):

        umf = []

        for limits in self._interval_set_elements.values():
                umf.append(limits.left)
        
        return umf
def mid_domain_element(self)

returns the middle domain element

Expand source code
def mid_domain_element(self):
        '''
        returns the middle domain element
        '''
        return self.primary_domain()[int(len(self.primary_domain())/2)]
def primary_domain(self)

The primary domain of this fuzzy set

Arguments:

None

Returns:

primary_domain – list, containing all the values in the primary domain

Expand source code
def primary_domain(self):
        '''
        The primary domain of this fuzzy set

        Arguments:
        ----------
        None

        Returns:
        --------
        primary_domain -- list, containing all the values in the primary domain
        '''
        primary_domain = list(self._interval_set_elements.keys())
        return primary_domain
class SecondaryMembershipFunction

A secondary membership function is a vertical slice of mu(X=x, u)

Reference:

J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE Trans. Fuzzy Syst., vol. 10, no. 2, pp. 117–127, Apr. 2002.

Expand source code
class SecondaryMembershipFunction(Type1FuzzySet):
        '''
        A secondary membership function is a vertical slice of mu(X=x, u)

        Reference:
        ----------
        J. M. Mendel and R. I. B. John, “Type-2 fuzzy sets made simple,” IEEE
        Trans. Fuzzy Syst., vol. 10, no. 2, pp. 117–127, Apr. 2002.
        '''

        def __init__(self):
                        super().__init__()

Ancestors

Inherited members

class Type1FuzzySet

Reference:

Zadeh, Lotfi Asker. "The concept of a linguistic variable and its application to approximate reasoning—I." Information sciences 8.3 (1975): 199-249.

Expand source code
class Type1FuzzySet:
        '''
        Reference:
        ----------
        Zadeh, Lotfi Asker. "The concept of a linguistic variable and its 
        application to approximate reasoning—I." Information sciences 8.3 (1975): 199-249.

        '''
        def __init__(self):
                self._elements = {}
                self._empty = True
                self._precision = 3

        def __eq__(self, value):
                current_domain_len = len(self.domain_elements())
                value_domain_len = len(value.domain_elements())
                union_domain_len = len(list(set(self.domain_elements()).union(value.domain_elements())))

                if current_domain_len != value_domain_len:
                        return False

                if union_domain_len != value_domain_len:
                        return False

                current_dom_len = len(self.degree_of_membership())
                value_dom_len = len(value.degree_of_membership())
                union_dom_len = len(list(set(self.degree_of_membership()).union(value.degree_of_membership())))

                if current_dom_len != value_dom_len:
                        return False

                if union_dom_len != value_dom_len:
                        return False

                return True

        def __getitem__(self, x_val):
                '''
                For a given value of x, return the degree of membership

                Reference:
                ----------
                Zadeh, Lotfi Asker. "The concept of a linguistic variable and its 
                application to approximate reasoning—I." Information sciences 8.3 (1975): 199-249.

                Arguments:
                ----------
                x_val -- value of x 

                Returns:
                --------
                degree of membership -- float

                '''
                return self._elements[x_val]

        def __str__(self):

                set_elements = []
                dec_places_formatter = '''%0.{}f'''.format(self._precision)

                for domain_val, dom_val in self._elements.items():
                        set_elements.append(f'{dec_places_formatter % dom_val}/{dec_places_formatter % domain_val}')

                set_representation = ' + '.join(set_elements)

                return set_representation

        def __repr__(self):
                return f'{self.__class__.__name__}({str(self)})'

        @ classmethod
        def from_representation(cls, set_representation):
                '''
                Creates a type-1 fuzzy set from a set representation of the form
                'a1/u1 + a2/u2 + ... + an/un'

                Reference:
                ---------
                Zadeh, Lotfi Asker. "The concept of a linguistic variable and its 
                application to approximate reasoning—I." Information sciences 8.3 (1975): 199-249.

                Arguments:
                ----------
                set_representation -- string, representation of the t1fs

                Returns:
                --------
                t1fs -- Type-1 Fuzzy Set

                Raises:
                -------
                Exception -- if set_representation is empty, None or invalid
                '''
                if set_representation == None:
                        raise Exception('Type-1 Set Representation cannot be null')
                if set_representation == '':
                        raise Exception('Type-1 Set Representation cannot be empty')

                t1fs = cls()

                try:
                        # remove spaces, tabs returns,
                        translation_table = dict.fromkeys(map(ord, ' \t\n\r'), None)
                        set_representation = set_representation.translate(translation_table)

                        # by splitting by + we will get 
                        # the degree of memberships / domain combinations
                        set_elements = set_representation.split('+')

                        for element in set_elements:
                                # we now split the membership function from the
                                # primary domain value
                                dom_val, domain_val = element.split('/')
                                t1fs.add_element(float(domain_val), float(dom_val))

                except ValueError:
                        raise Exception('Invalid set type-1 format')

                return t1fs

        @ classmethod
        def from_alphacut_type1_set(cls, alphacut_set):
                
                t1fs = cls()
                for cut in alphacut_set.cuts():
                        limits = alphacut_set[cut]
                        t1fs.add_element(limits.left, cut)
                        t1fs.add_element(limits.right, cut)

                # sort dictionary with domain 
                # TODO. do this if required only
                domain_list = t1fs.domain_elements()
                domain_list.sort()
                new_elements = {}
                for domain_value in domain_list:
                        new_elements[domain_value] = t1fs._elements[domain_value]
                t1fs._elements = new_elements

                return t1fs

        @classmethod
        def create_triangular(cls, univ_low, univ_hi, univ_res, set_low, set_mid, set_hi):

                '''
                Creates a triangular type 1 fuzzy set in a defined universe of discourse
                The triangle is mage of three points; the low where the dom is 0, the mid where the
                dom is 1 and the high where the dom is 0

                References
                ----------
                Pedrycz, Witold, and Fernando Gomide. 
                An introduction to fuzzy sets: analysis and design. Mit Press, 1998.

                Arguments:
                ----------
                univ_low -- lower value of the universe of discourse
                univ_hi -- higher value of the universe of discourse
                univ_res -- resolution of the universe of discourse
                set_low -- sel low point, where dom is 0
                set_mid -- sel mid point, where dom is 1
                set_hi -- sel high point, where dom is 0

                Returns:
                --------
                The new type1 triangular fuzzy set
                '''

                if univ_hi <= univ_low:
                        raise Exception('Error in universe definition')
                if (set_hi < set_mid) or (set_mid < set_low):
                        raise Exception('Error in triangular set definition')

                t1fs = cls()

                precision = len(str(univ_res))
                domain_elements =  np.round(np.linspace(univ_low, univ_hi, univ_res), precision)

                idx = (np.abs(domain_elements - set_mid)).argmin()
                set_mid = domain_elements[idx]

                idx = (np.abs(domain_elements - set_low)).argmin()
                set_low = domain_elements[idx]

                idx = (np.abs(domain_elements - set_hi)).argmin()
                set_hi = domain_elements[idx]

                for domain_val in domain_elements:
                        # get the dom of the set at the point
                        dom = max(min((domain_val-set_low)/(set_mid-set_low), (set_hi-domain_val)/(set_hi-set_mid)), 0)

                        # idx = (np.abs(domain_elements - set_mid)).argmin()
                        # dom = domain_elements[idx]

                        t1fs.add_element(domain_val, dom)

                return t1fs

        @classmethod
        def create_triangular_ex(cls, primary_domain, a, b, c):

                '''
                Creates a triangular type 1 fuzzy set in a defined universe of discourse
                The triangle is mage of three points; the low where the dom is 0, the mid where the
                dom is 1 and the high where the dom is 0

                References
                ----------
                Pedrycz, Witold, and Fernando Gomide. 
                An introduction to fuzzy sets: analysis and design. Mit Press, 1998.

                Arguments:
                ----------

                a -- set low point, where dom is 0
                b -- set mid point, where dom is 1
                c -- set high point, where dom is 0

                Returns:
                --------
                The new type1 triangular fuzzy set
                '''
                if (c <= b) or (b <= a):
                        raise Exception('Error in triangular set definition')

                t1fs = cls()

                for x in primary_domain:
                        dom = max(min((x - a)/(b - a), (c - x)/(c - b)), 0)
                        t1fs.add_element(x, dom)

                return t1fs

        @staticmethod
        def adjust_value(val, val_array):
                idx = (np.abs(val_array - val)).argmin()
                return val_array[idx]

        @classmethod
        def create_trapezoidal(cls, domain, a, b, c, d):
                '''
                '''
                t1fs = cls()

                for domain_val in domain:
                        if domain_val > a and domain_val < d:
                                if b == a:
                                        dom = min(max((d-domain_val)/(d-c), 0), 1)
                                elif d==c:
                                        dom = min(max((domain_val-a)/(b-a), 0), 1)
                                else:
                                        dom = min(max(min((domain_val-a)/(b-a), (d-domain_val)/(d-c)), 0), 1)

                                t1fs.add_element(domain_val, dom)

                return t1fs

        @property
        def empty(self):
                '''
                True if the set is empty, i.e. there is no element with dom > 0
                '''
                return self._empty

        def elements(self):
                '''
                Returns a copy of the elements making up this t1fs in the form a dictionary

                Arguments:
                ----------

                Returns:
                --------
                elements - dict, containing domain:degree_of_membership pairs
                '''
                elements = self._elements
                return elements

        def element_count(self):
                return len(self._elements)

        def add_element(self, domain_val, dom_val):
                '''
                Adds a new element to the t1fs. If there is already an element at the stated
                domain value the maximum degree of membership value is kept

                Arguments:
                ----------
                domain_val -- float, the value of x
                degree_of_membership, float value between 0 and 1. The degree of membership
                '''
                if dom_val > 1:
                        raise ValueError('degree of membership must not be greater than 1, {} : {}'.format(domain_val, dom_val))

                if domain_val in self._elements:
                        self._elements[domain_val] = max(self._elements[domain_val], dom_val)
                else:
                        self._elements[domain_val] = dom_val
                        self._empty = False

        def domain_elements(self):
                '''
                Return a list of all the domain elements

                Returns:
                --------
                domain_vals -- list, containing all the values of the domain
                '''
                domain_vals = list(self._elements.keys())
                return domain_vals
        
        def dom_elements(self):
                '''
                Returns a list of all the doms in the set

                Returns:
                --------
                dom_vals -- list, containing all the values of the dom
                '''
                dom_vals = list(self._elements.values())
                return dom_vals

        def degree_of_membership(self):
                '''
                Return a list of all the degree of membership values

                Returns:
                --------
                doms -- list, containing all the values of the degree of membership values
                '''
                doms = list(self._elements.values())
                return doms

        def size(self):
                '''
                The size of the set

                Returns:
                --------
                set_size: int, the number of elements in the set
                '''
                set_size = len(self._elements)
                return set_size

        def domain_limits(self):
                '''
                Returns the domain limits of this t1fs

                Reference:
                ----------

                Arguments:
                ----------

                Returns:
                --------
                limits -- CrispSet containting the smallest an largest domain value
                '''
                limits = CrispSet(min(self._elements.keys()), max(self._elements.keys()))
                return limits
        
        def alpha_cut(self, alpha_val):

                if alpha_val == 0:
                        filter_idx = (np.array(self.degree_of_membership()) > 0).nonzero()[0]

                else:
                # create a filter of the degrees of membership that exceed the cut value
                        filter_idx = (np.array(self.degree_of_membership()) >= alpha_val).nonzero()[0]

                # appply the filter on the domain to get the values included in the alpha-cut
                cut = np.array(self.domain_elements())[filter_idx]

                limits = CrispSet()

                if len(cut>0):
                        limits.left = min(cut)
                        limits.right = max(cut)

                return limits

        def extend(self, func):

                resultant_set = Type1FuzzySet()

                for domain_val in self.domain_elements():
                        resultant_set.add_element(func(domain_val), self[domain_val])
                
                return resultant_set

        # operators
        def join(self, a_set):

                resultant_set = Type1FuzzySet()

                for domain_element in self.domain_elements():
                        for a_set_domain_element in a_set.domain_elements():
                                
                                resultant_set.add_element(max(domain_element, a_set_domain_element), 
                                                                                        min(self[domain_element], a_set[a_set_domain_element]))

                return resultant_set

        def meet(self, a_set):

                resultant_set = Type1FuzzySet()

                for domain_element in self.domain_elements():
                        for a_set_domain_element in a_set.domain_elements():
                                
                                resultant_set.add_element(min(domain_element, a_set_domain_element), 
                                                                                        min(self[domain_element], a_set[a_set_domain_element]))

                return resultant_set

        def negation(self):
                resultant_set = Type1FuzzySet()

                for domain_element in self.domain_elements():
                                resultant_set.add_element(1 - domain_element, 
                                                                                        self[domain_element])

                return resultant_set

        def union(self, other_smf):
                resultant_set = set.intersection(set(self._elements), set(other_smf._elements))

                resultant_smf = {}
                for  domain_val in resultant_set:
                        resultant_smf[domain_val] = max(self._elements[domain_val], other_smf.elements[domain_val])

                return resultant_smf

        def intersection(self, other_smf):
                '''
                '''
                resultant_set = set.intersection(set(self._elements), set(other_smf._elements))

                resultant_smf = {}
                for  domain_val in resultant_set:
                        resultant_smf[domain_val] = min(self._elements[domain_val], other_smf.elements[domain_val])

                return resultant_smf

Subclasses

Static methods

def adjust_value(val, val_array)
Expand source code
@staticmethod
def adjust_value(val, val_array):
        idx = (np.abs(val_array - val)).argmin()
        return val_array[idx]
def create_trapezoidal(domain, a, b, c, d)
Expand source code
@classmethod
def create_trapezoidal(cls, domain, a, b, c, d):
        '''
        '''
        t1fs = cls()

        for domain_val in domain:
                if domain_val > a and domain_val < d:
                        if b == a:
                                dom = min(max((d-domain_val)/(d-c), 0), 1)
                        elif d==c:
                                dom = min(max((domain_val-a)/(b-a), 0), 1)
                        else:
                                dom = min(max(min((domain_val-a)/(b-a), (d-domain_val)/(d-c)), 0), 1)

                        t1fs.add_element(domain_val, dom)

        return t1fs
def create_triangular(univ_low, univ_hi, univ_res, set_low, set_mid, set_hi)

Creates a triangular type 1 fuzzy set in a defined universe of discourse The triangle is mage of three points; the low where the dom is 0, the mid where the dom is 1 and the high where the dom is 0

References

Pedrycz, Witold, and Fernando Gomide. An introduction to fuzzy sets: analysis and design. Mit Press, 1998.

Arguments:

univ_low – lower value of the universe of discourse univ_hi – higher value of the universe of discourse univ_res – resolution of the universe of discourse set_low – sel low point, where dom is 0 set_mid – sel mid point, where dom is 1 set_hi – sel high point, where dom is 0

Returns:

The new type1 triangular fuzzy set

Expand source code
@classmethod
def create_triangular(cls, univ_low, univ_hi, univ_res, set_low, set_mid, set_hi):

        '''
        Creates a triangular type 1 fuzzy set in a defined universe of discourse
        The triangle is mage of three points; the low where the dom is 0, the mid where the
        dom is 1 and the high where the dom is 0

        References
        ----------
        Pedrycz, Witold, and Fernando Gomide. 
        An introduction to fuzzy sets: analysis and design. Mit Press, 1998.

        Arguments:
        ----------
        univ_low -- lower value of the universe of discourse
        univ_hi -- higher value of the universe of discourse
        univ_res -- resolution of the universe of discourse
        set_low -- sel low point, where dom is 0
        set_mid -- sel mid point, where dom is 1
        set_hi -- sel high point, where dom is 0

        Returns:
        --------
        The new type1 triangular fuzzy set
        '''

        if univ_hi <= univ_low:
                raise Exception('Error in universe definition')
        if (set_hi < set_mid) or (set_mid < set_low):
                raise Exception('Error in triangular set definition')

        t1fs = cls()

        precision = len(str(univ_res))
        domain_elements =  np.round(np.linspace(univ_low, univ_hi, univ_res), precision)

        idx = (np.abs(domain_elements - set_mid)).argmin()
        set_mid = domain_elements[idx]

        idx = (np.abs(domain_elements - set_low)).argmin()
        set_low = domain_elements[idx]

        idx = (np.abs(domain_elements - set_hi)).argmin()
        set_hi = domain_elements[idx]

        for domain_val in domain_elements:
                # get the dom of the set at the point
                dom = max(min((domain_val-set_low)/(set_mid-set_low), (set_hi-domain_val)/(set_hi-set_mid)), 0)

                # idx = (np.abs(domain_elements - set_mid)).argmin()
                # dom = domain_elements[idx]

                t1fs.add_element(domain_val, dom)

        return t1fs
def create_triangular_ex(primary_domain, a, b, c)

Creates a triangular type 1 fuzzy set in a defined universe of discourse The triangle is mage of three points; the low where the dom is 0, the mid where the dom is 1 and the high where the dom is 0

References

Pedrycz, Witold, and Fernando Gomide. An introduction to fuzzy sets: analysis and design. Mit Press, 1998.

Arguments:

a – set low point, where dom is 0 b – set mid point, where dom is 1 c – set high point, where dom is 0

Returns:

The new type1 triangular fuzzy set

Expand source code
@classmethod
def create_triangular_ex(cls, primary_domain, a, b, c):

        '''
        Creates a triangular type 1 fuzzy set in a defined universe of discourse
        The triangle is mage of three points; the low where the dom is 0, the mid where the
        dom is 1 and the high where the dom is 0

        References
        ----------
        Pedrycz, Witold, and Fernando Gomide. 
        An introduction to fuzzy sets: analysis and design. Mit Press, 1998.

        Arguments:
        ----------

        a -- set low point, where dom is 0
        b -- set mid point, where dom is 1
        c -- set high point, where dom is 0

        Returns:
        --------
        The new type1 triangular fuzzy set
        '''
        if (c <= b) or (b <= a):
                raise Exception('Error in triangular set definition')

        t1fs = cls()

        for x in primary_domain:
                dom = max(min((x - a)/(b - a), (c - x)/(c - b)), 0)
                t1fs.add_element(x, dom)

        return t1fs
def from_alphacut_type1_set(alphacut_set)
Expand source code
@ classmethod
def from_alphacut_type1_set(cls, alphacut_set):
        
        t1fs = cls()
        for cut in alphacut_set.cuts():
                limits = alphacut_set[cut]
                t1fs.add_element(limits.left, cut)
                t1fs.add_element(limits.right, cut)

        # sort dictionary with domain 
        # TODO. do this if required only
        domain_list = t1fs.domain_elements()
        domain_list.sort()
        new_elements = {}
        for domain_value in domain_list:
                new_elements[domain_value] = t1fs._elements[domain_value]
        t1fs._elements = new_elements

        return t1fs
def from_representation(set_representation)

Creates a type-1 fuzzy set from a set representation of the form 'a1/u1 + a2/u2 + … + an/un'

Reference:

Zadeh, Lotfi Asker. "The concept of a linguistic variable and its application to approximate reasoning—I." Information sciences 8.3 (1975): 199-249.

Arguments:

set_representation – string, representation of the t1fs

Returns:

t1fs – Type-1 Fuzzy Set

Raises:

Exception – if set_representation is empty, None or invalid

Expand source code
@ classmethod
def from_representation(cls, set_representation):
        '''
        Creates a type-1 fuzzy set from a set representation of the form
        'a1/u1 + a2/u2 + ... + an/un'

        Reference:
        ---------
        Zadeh, Lotfi Asker. "The concept of a linguistic variable and its 
        application to approximate reasoning—I." Information sciences 8.3 (1975): 199-249.

        Arguments:
        ----------
        set_representation -- string, representation of the t1fs

        Returns:
        --------
        t1fs -- Type-1 Fuzzy Set

        Raises:
        -------
        Exception -- if set_representation is empty, None or invalid
        '''
        if set_representation == None:
                raise Exception('Type-1 Set Representation cannot be null')
        if set_representation == '':
                raise Exception('Type-1 Set Representation cannot be empty')

        t1fs = cls()

        try:
                # remove spaces, tabs returns,
                translation_table = dict.fromkeys(map(ord, ' \t\n\r'), None)
                set_representation = set_representation.translate(translation_table)

                # by splitting by + we will get 
                # the degree of memberships / domain combinations
                set_elements = set_representation.split('+')

                for element in set_elements:
                        # we now split the membership function from the
                        # primary domain value
                        dom_val, domain_val = element.split('/')
                        t1fs.add_element(float(domain_val), float(dom_val))

        except ValueError:
                raise Exception('Invalid set type-1 format')

        return t1fs

Instance variables

var empty

True if the set is empty, i.e. there is no element with dom > 0

Expand source code
@property
def empty(self):
        '''
        True if the set is empty, i.e. there is no element with dom > 0
        '''
        return self._empty

Methods

def add_element(self, domain_val, dom_val)

Adds a new element to the t1fs. If there is already an element at the stated domain value the maximum degree of membership value is kept

Arguments:

domain_val – float, the value of x degree_of_membership, float value between 0 and 1. The degree of membership

Expand source code
def add_element(self, domain_val, dom_val):
        '''
        Adds a new element to the t1fs. If there is already an element at the stated
        domain value the maximum degree of membership value is kept

        Arguments:
        ----------
        domain_val -- float, the value of x
        degree_of_membership, float value between 0 and 1. The degree of membership
        '''
        if dom_val > 1:
                raise ValueError('degree of membership must not be greater than 1, {} : {}'.format(domain_val, dom_val))

        if domain_val in self._elements:
                self._elements[domain_val] = max(self._elements[domain_val], dom_val)
        else:
                self._elements[domain_val] = dom_val
                self._empty = False
def alpha_cut(self, alpha_val)
Expand source code
def alpha_cut(self, alpha_val):

        if alpha_val == 0:
                filter_idx = (np.array(self.degree_of_membership()) > 0).nonzero()[0]

        else:
        # create a filter of the degrees of membership that exceed the cut value
                filter_idx = (np.array(self.degree_of_membership()) >= alpha_val).nonzero()[0]

        # appply the filter on the domain to get the values included in the alpha-cut
        cut = np.array(self.domain_elements())[filter_idx]

        limits = CrispSet()

        if len(cut>0):
                limits.left = min(cut)
                limits.right = max(cut)

        return limits
def degree_of_membership(self)

Return a list of all the degree of membership values

Returns:

doms – list, containing all the values of the degree of membership values

Expand source code
def degree_of_membership(self):
        '''
        Return a list of all the degree of membership values

        Returns:
        --------
        doms -- list, containing all the values of the degree of membership values
        '''
        doms = list(self._elements.values())
        return doms
def dom_elements(self)

Returns a list of all the doms in the set

Returns:

dom_vals – list, containing all the values of the dom

Expand source code
def dom_elements(self):
        '''
        Returns a list of all the doms in the set

        Returns:
        --------
        dom_vals -- list, containing all the values of the dom
        '''
        dom_vals = list(self._elements.values())
        return dom_vals
def domain_elements(self)

Return a list of all the domain elements

Returns:

domain_vals – list, containing all the values of the domain

Expand source code
def domain_elements(self):
        '''
        Return a list of all the domain elements

        Returns:
        --------
        domain_vals -- list, containing all the values of the domain
        '''
        domain_vals = list(self._elements.keys())
        return domain_vals
def domain_limits(self)

Returns the domain limits of this t1fs

Reference:

Arguments:

Returns:

limits – CrispSet containting the smallest an largest domain value

Expand source code
def domain_limits(self):
        '''
        Returns the domain limits of this t1fs

        Reference:
        ----------

        Arguments:
        ----------

        Returns:
        --------
        limits -- CrispSet containting the smallest an largest domain value
        '''
        limits = CrispSet(min(self._elements.keys()), max(self._elements.keys()))
        return limits
def element_count(self)
Expand source code
def element_count(self):
        return len(self._elements)
def elements(self)

Returns a copy of the elements making up this t1fs in the form a dictionary

Arguments:

Returns:

elements - dict, containing domain:degree_of_membership pairs

Expand source code
def elements(self):
        '''
        Returns a copy of the elements making up this t1fs in the form a dictionary

        Arguments:
        ----------

        Returns:
        --------
        elements - dict, containing domain:degree_of_membership pairs
        '''
        elements = self._elements
        return elements
def extend(self, func)
Expand source code
def extend(self, func):

        resultant_set = Type1FuzzySet()

        for domain_val in self.domain_elements():
                resultant_set.add_element(func(domain_val), self[domain_val])
        
        return resultant_set
def intersection(self, other_smf)
Expand source code
def intersection(self, other_smf):
        '''
        '''
        resultant_set = set.intersection(set(self._elements), set(other_smf._elements))

        resultant_smf = {}
        for  domain_val in resultant_set:
                resultant_smf[domain_val] = min(self._elements[domain_val], other_smf.elements[domain_val])

        return resultant_smf
def join(self, a_set)
Expand source code
def join(self, a_set):

        resultant_set = Type1FuzzySet()

        for domain_element in self.domain_elements():
                for a_set_domain_element in a_set.domain_elements():
                        
                        resultant_set.add_element(max(domain_element, a_set_domain_element), 
                                                                                min(self[domain_element], a_set[a_set_domain_element]))

        return resultant_set
def meet(self, a_set)
Expand source code
def meet(self, a_set):

        resultant_set = Type1FuzzySet()

        for domain_element in self.domain_elements():
                for a_set_domain_element in a_set.domain_elements():
                        
                        resultant_set.add_element(min(domain_element, a_set_domain_element), 
                                                                                min(self[domain_element], a_set[a_set_domain_element]))

        return resultant_set
def negation(self)
Expand source code
def negation(self):
        resultant_set = Type1FuzzySet()

        for domain_element in self.domain_elements():
                        resultant_set.add_element(1 - domain_element, 
                                                                                self[domain_element])

        return resultant_set
def size(self)

The size of the set

Returns:

set_size: int, the number of elements in the set

Expand source code
def size(self):
        '''
        The size of the set

        Returns:
        --------
        set_size: int, the number of elements in the set
        '''
        set_size = len(self._elements)
        return set_size
def union(self, other_smf)
Expand source code
def union(self, other_smf):
        resultant_set = set.intersection(set(self._elements), set(other_smf._elements))

        resultant_smf = {}
        for  domain_val in resultant_set:
                resultant_smf[domain_val] = max(self._elements[domain_val], other_smf.elements[domain_val])

        return resultant_smf
class ZSliceType2FuzzySet

datastructure defining a z-slice type-2 fuzzy set is a dictionary having an interval type-2 fuzzy set for every z_value such as: key: value of z-slice value: corresponding interval typ2-2 fuzzy set

Expand source code
class ZSliceType2FuzzySet:

        def __init__(self):
                '''
                datastructure defining a z-slice type-2 fuzzy set is a dictionary having
                an interval type-2 fuzzy set for every z_value such as:
                key: value of z-slice
                value: corresponding interval typ2-2 fuzzy set
                '''
                self._z_slice_set_elements = {}
                self._empty = True

        @ classmethod
        def from_general_type2_set(cls, gt2fs, no_slices):
                
                zt2fs = cls()

                z_vals = np.linspace(0, 1, no_slices+1)

                for z_val in z_vals:
                        z_sliced_set =  gt2fs.z_slice(z_val)

                        if not z_sliced_set.empty:
                                zt2fs.add_element(z_val, z_sliced_set)# 
                                zt2fs._empty = False
                return zt2fs

        @property
        def empty(self):
                return self._empty

        def add_element(self, z_slice_val, z_sliced_set):
                self._z_slice_set_elements[z_slice_val] = z_sliced_set


        @staticmethod
        def adjust_value(val, val_array):
                val_array=np.array(val_array)
                idx = (np.abs(val_array - val)).argmin()
                return val_array[idx]

        def __getitem__(self, z_slice_val):
                '''
                For a given z-slice value, 
                return the corresponding interval type-2 fuzzy set

                Arguments:
                ----------
                z_slice_val -- value of z-slice

                Returns:
                --------
                it2fs - corresponding interval type-2 set
                '''
                if z_slice_val not in self.zslices():
                        raise Exception(f'z-slice value of {z_slice_val} not in this set.')

                z_slice_val = self.adjust_value(z_slice_val, self.zslices())

                return self._z_slice_set_elements[z_slice_val]

        def zslices(self):
                return list(self._z_slice_set_elements.keys())

        def __str__(self):
                '''

                '''
                representation = []

                for slice in self._z_slice_set_elements:
                        representation.append(f'slice {slice}:\n {self._z_slice_set_elements[slice]}')

                return '\n'.join(representation)
        
        def __repr__(self):
                return f'{self.__class__.__name__}(str(self))'

Static methods

def adjust_value(val, val_array)
Expand source code
@staticmethod
def adjust_value(val, val_array):
        val_array=np.array(val_array)
        idx = (np.abs(val_array - val)).argmin()
        return val_array[idx]
def from_general_type2_set(gt2fs, no_slices)
Expand source code
@ classmethod
def from_general_type2_set(cls, gt2fs, no_slices):
        
        zt2fs = cls()

        z_vals = np.linspace(0, 1, no_slices+1)

        for z_val in z_vals:
                z_sliced_set =  gt2fs.z_slice(z_val)

                if not z_sliced_set.empty:
                        zt2fs.add_element(z_val, z_sliced_set)# 
                        zt2fs._empty = False
        return zt2fs

Instance variables

var empty
Expand source code
@property
def empty(self):
        return self._empty

Methods

def add_element(self, z_slice_val, z_sliced_set)
Expand source code
def add_element(self, z_slice_val, z_sliced_set):
        self._z_slice_set_elements[z_slice_val] = z_sliced_set
def zslices(self)
Expand source code
def zslices(self):
        return list(self._z_slice_set_elements.keys())