public static List<FuzzyVariable> Stretch(
            List<MeasurementWithResult> learningSet,
            DecisionMakerType1 originalDecisionMaker,
            VariableMFParam toStretch,
            BoundType boundType)
        {
            List<MeasurementWithResult> withResultsFromFs = (from measurement in learningSet
                select
                    new MeasurementWithResult
                    {
                        InputValues = new Dictionary<string, double>(measurement.InputValues),
                        OutputString = originalDecisionMaker.InferTerm(measurement.InputValues)
                    }).ToList();
            double multiplier = 1;
            int error = 0;
            bool canStretchMore = true;
            if (boundType == BoundType.Upper)
            {
                while (error == 0 && canStretchMore)
                {
                    multiplier += 0.001;
                    MamdaniFuzzySystem newFuzzySystem = UpdateParamsByMultiplier(
                        originalDecisionMaker,
                        multiplier,
                        toStretch,
                        out canStretchMore);
                    var updatedDecisionMaker = new DecisionMakerType1(newFuzzySystem, originalDecisionMaker.RulesDefinitions);
                    error = (from measurement in withResultsFromFs
                        where updatedDecisionMaker.InferTerm(measurement.InputValues) != measurement.OutputString
                        select measurement).Count();
                }

                multiplier -= 0.001;
                var finalFuzzySystem = UpdateParamsByMultiplier(
                    originalDecisionMaker,
                    multiplier,
                    toStretch,
                    out canStretchMore);
                return finalFuzzySystem.Input;
            }
            else
            {
                while (error == 0 && canStretchMore)
                {
                    multiplier -= 0.001;
                    MamdaniFuzzySystem newFuzzySystem = UpdateParamsByMultiplier(
                        originalDecisionMaker,
                        multiplier,
                        toStretch,
                        out canStretchMore);
                    var updatedDecisionMaker = new DecisionMakerType1(newFuzzySystem, originalDecisionMaker.RulesDefinitions);
                    error = (from measurement in withResultsFromFs
                        where updatedDecisionMaker.InferTerm(measurement.InputValues) != measurement.OutputString
                        select measurement).Count();
                }

                multiplier += 0.001;
                var finalFuzzySystem = UpdateParamsByMultiplier(
                    originalDecisionMaker,
                    multiplier,
                    toStretch,
                    out canStretchMore);
                return finalFuzzySystem.Input;
            }
        }
        private static MamdaniFuzzySystem UpdateParamsByMultiplier(
            DecisionMakerType1 originalDecisionMaker,
            double multiplier,
            VariableMFParam paramToUpdate,
            out bool canStretchMore)
        {
            canStretchMore = false;

            // Create empty fuzzy system
            MamdaniFuzzySystem newFs = new MamdaniFuzzySystem();

            // Create input and output variables for the system
            foreach (var inputVariable in originalDecisionMaker.fsWellEval.Input)
            {
                FuzzyVariable fsVariable = new FuzzyVariable(inputVariable.Name, inputVariable.Min, inputVariable.Max);
                foreach (var term in inputVariable.Terms)
                {
                    var mf = term.MembershipFunction as NormalMembershipFunction;
                    if (paramToUpdate == VariableMFParam.Mean)
                    {
                        if (mf != null && (mf.B * multiplier >= fsVariable.Min && mf.B * multiplier <= fsVariable.Max))
                        {
                            fsVariable.Terms.Add(
                                new FuzzyTerm(term.Name, new NormalMembershipFunction(mf.B * multiplier, mf.Sigma)));
                            canStretchMore = true;
                        }
                        else
                        {
                            if (mf != null)
                            {
                                fsVariable.Terms.Add(new FuzzyTerm(term.Name, new NormalMembershipFunction(mf.B, mf.Sigma)));
                                canStretchMore = false;
                            }
                        }
                    }

                    if (paramToUpdate == VariableMFParam.Deviation)
                    {
                        if (mf != null && (mf.Sigma * multiplier >= 0.001 && mf.Sigma * multiplier <= 10))
                        {
                            fsVariable.Terms.Add(
                                new FuzzyTerm(term.Name, new NormalMembershipFunction(mf.B, mf.Sigma * multiplier)));

                        }
                        else
                        {
                            if (mf != null)
                            {
                                fsVariable.Terms.Add(new FuzzyTerm(term.Name, new NormalMembershipFunction(mf.B, mf.Sigma)));

                            }
                        }
                    }

                    if (paramToUpdate == VariableMFParam.RuleWeight)
                    {
                        if (mf != null)
                        {
                            fsVariable.Terms.Add(new FuzzyTerm(term.Name, new NormalMembershipFunction(mf.B, mf.Sigma)));
                        }
                    }
                }

                newFs.Input.Add(fsVariable);
            }

            foreach (var outputVariable in originalDecisionMaker.fsWellEval.Output)
            {
                var newVariable = new FuzzyVariable(
                    outputVariable.Name,
                    outputVariable.Min,
                    outputVariable.Max,
                    outputVariable.Unit);
                newVariable.Terms.Clear();
                newVariable.Terms.AddRange(outputVariable.Terms);
                newFs.Output.Add(newVariable);
            }

            for (int i = 0; i < originalDecisionMaker.RulesDefinitions.Items.Count; i++)
            {
                MamdaniFuzzyRule newRule = newFs.ParseRule(originalDecisionMaker.RulesDefinitions.Items[i].Definition);
                double oldWeight = originalDecisionMaker.fsWellEval.Rules[i].Weight;
                if (paramToUpdate == VariableMFParam.RuleWeight)
                {
                    if (oldWeight * multiplier >= 0.001 && oldWeight * multiplier <= 1)
                    {
                        newRule.Weight = oldWeight * multiplier;
                    }
                }
                else
                {
                    newRule.Weight = oldWeight;
                }

                newFs.Rules.Add(newRule);
            }

            return newFs;
        }
        private void UpdateMemberships(List<FuzzyVariable> sourceVariables, VariableMFParam parameterToUpdate, BoundType boundType)
        {
            switch (parameterToUpdate)
            {
                case VariableMFParam.Mean:
                case VariableMFParam.Deviation:
                    foreach (var variable in inputVariables)
                    {
                        foreach (var type2term in variable.Terms)
                        {
                            var sourceTerm = sourceVariables.Find(v => v.Name == variable.Name).Terms.Find(t => t.Name == type2term.Name);
                            var mf = sourceTerm.MembershipFunction as NormalMembershipFunction;
                            if (boundType == BoundType.Lower)
                            {
                                type2term.LowerMembershipFunction = new NormalMembershipFunction(mf.B, mf.Sigma);
                            }
                            else
                            {
                                type2term.UpperMembershipFunction = new NormalMembershipFunction(mf.B, mf.Sigma);
                            }
                        }
                    }

                    break;
                case VariableMFParam.RuleWeight:
                    // todo
                    break;
            }
        }