# Source code for pyFTS.common.flrg

    import numpy as np

    class FLRG(object):
        """
        Fuzzy Logical Relationship Group

        Group a set of FLR's with the same LHS. Represents the temporal patterns for time t+1 (the RHS fuzzy sets)
        when the LHS pattern is identified on time t.
        """

        def __init__(self, order, **kwargs):
            self.LHS = None
            """Left Hand Side of the rule"""
            self.RHS = None
            """Right Hand Side of the rule"""
            self.order = order
            """Number of lags on LHS"""
            self.midpoint = None
            self.lower = None
            self.upper = None
            self.key = None

        def append_rhs(self, set, **kwargs):
            pass

        def get_key(self):
            """Returns a unique identifier for this FLRG"""
            if self.key is None:
                if isinstance(self.LHS, (list, set)):
                    names = [c for c in self.LHS]
                elif isinstance(self.LHS, dict):
                    names = [self.LHS[k] for k in self.LHS.keys()]
                else:
                    names = [self.LHS]

                self.key = ""

                for n in names:
                    if len(self.key) > 0:
                        self.key += ","
                    self.key += n
            return self.key

        def get_membership(self, data, sets):
            """
            Returns the membership value of the FLRG for the input data

            :param data: input data
            :param sets: fuzzy sets
            :return: the membership value
            """
            ret = 0.0
            if isinstance(self.LHS, (list, set)):
                if len(self.LHS) == len(data):
                    ret = np.nanmin([sets[self.LHS[ct]].membership(dat) for ct, dat in enumerate(data)])
            else:
                ret = sets[self.LHS].membership(data)
            return ret

        def get_midpoint(self, sets):
            """
            Returns the midpoint value for the RHS fuzzy sets

            :param sets: fuzzy sets
            :return: the midpoint value
            """
            if self.midpoint is None:
                self.midpoint = np.nanmean(self.get_midpoints(sets))
            return self.midpoint

        def get_midpoints(self, sets):
            if isinstance(self.RHS, (list, set)):
                return np.array([sets[s].centroid for s in self.RHS])
            elif isinstance(self.RHS, dict):
                return np.array([sets[s].centroid for s in self.RHS.keys()])

        def get_lower(self, sets):
            """
            Returns the lower bound value for the RHS fuzzy sets

            :param sets: fuzzy sets
            :return: lower bound value
            """
            if self.lower is None:
                if isinstance(self.RHS, list):
                    self.lower = min([sets[rhs].lower for rhs in self.RHS])
                elif isinstance(self.RHS, dict):
                    self.lower = min([sets[self.RHS[s]].lower for s in self.RHS.keys()])
            return self.lower

        def get_upper(self, sets):
            """
            Returns the upper bound value for the RHS fuzzy sets

            :param sets: fuzzy sets
            :return: upper bound value
            """
            if self.upper is None:
                if isinstance(self.RHS, list):
                    self.upper = max([sets[rhs].upper for rhs in self.RHS])
                elif isinstance(self.RHS, dict):
                    self.upper = max([sets[self.RHS[s]].upper for s in self.RHS.keys()])
            return self.upper

        def __len__(self):
            return len(self.RHS)

        def reset_calculated_values(self):
            self.midpoint = None
            self.upper = None
            self.lower = None