# Source code for pyFTS.models.chen

    """
    First Order Conventional Fuzzy Time Series by Chen (1996)

    S.-M. Chen, “Forecasting enrollments based on fuzzy time series,” Fuzzy Sets Syst., vol. 81, no. 3, pp. 311–319, 1996.
    """

    import numpy as np
    from pyFTS.common import FuzzySet, FLR, fts, flrg

    class ConventionalFLRG(flrg.FLRG):
        """First Order Conventional Fuzzy Logical Relationship Group"""
        def __init__(self, LHS, **kwargs):
            super(ConventionalFLRG, self).__init__(1, **kwargs)
            self.LHS = LHS
            self.RHS = set()

        def get_key(self, sets):
            return sets[self.LHS].name

        def append_rhs(self, c, **kwargs):
            self.RHS.add(c)

        def __str__(self):
            tmp = str(self.LHS) + " -> "
            tmp2 = ""
            for c in sorted(self.RHS, key=lambda s: s):
                if len(tmp2) > 0:
                    tmp2 = tmp2 + ","
                tmp2 = tmp2 + str(c)
            return tmp + tmp2

    class ConventionalFTS(fts.FTS):
        """Conventional Fuzzy Time Series"""
        def __init__(self, **kwargs):
            super(ConventionalFTS, self).__init__(order=1, **kwargs)
            self.name = "Conventional FTS"
            self.detail = "Chen"
            self.shortname = "CFTS"
            self.flrgs = {}

        def generate_flrg(self, flrs):
            for flr in flrs:
                if flr.LHS in self.flrgs:
                    self.flrgs[flr.LHS].append_rhs(flr.RHS)
                else:
                    self.flrgs[flr.LHS] = ConventionalFLRG(flr.LHS)
                    self.flrgs[flr.LHS].append_rhs(flr.RHS)

        def train(self, data, **kwargs):

            tmpdata = self.partitioner.fuzzyfy(data, method='maximum', mode='sets')
            flrs = FLR.generate_non_recurrent_flrs(tmpdata, steps=self.standard_horizon)
            self.generate_flrg(flrs)

        def forecast(self, ndata, **kwargs):

            explain = kwargs.get('explain',False)

            l = len(ndata) if not explain else 1

            ret = []

            for k in np.arange(0, l):

                actual = FuzzySet.get_maximum_membership_fuzzyset(ndata[k], self.partitioner.sets)

                if explain:
                    print("Fuzzyfication:\n\n {} -> {} \n".format(ndata[k], actual.name))

                if actual.name not in self.flrgs:
                    ret.append(actual.centroid)

                    if explain:
                        print("Rules:\n\n {} -> {} (Naïve)\t Midpoint: {}  \n\n".format(actual.name, actual.name,actual.centroid))

                else:
                    _flrg = self.flrgs[actual.name]

                    mp = _flrg.get_midpoint(self.partitioner.sets)

                    ret.append(mp)

                    if explain:
                        print("Rules:\n\n {} \t Midpoint: {} \n".format(str(_flrg), mp))

                        print("Deffuzyfied value: {} \n".format(mp))

            return ret