protected static void CalculateWithScaling(IEnumerable <double> targetValues, IEnumerable <double> estimatedValues,
                                                   double lowerEstimationLimit, double upperEstimationLimit,
                                                   IOnlineCalculator calculator, int maxRows)
        {
            if (cache == null || cache.Length < maxRows)
            {
                cache = new double[maxRows];
            }

            // calculate linear scaling
            int i = 0;
            var linearScalingCalculator   = new OnlineLinearScalingParameterCalculator();
            var targetValuesEnumerator    = targetValues.GetEnumerator();
            var estimatedValuesEnumerator = estimatedValues.GetEnumerator();

            while (targetValuesEnumerator.MoveNext() & estimatedValuesEnumerator.MoveNext())
            {
                double target    = targetValuesEnumerator.Current;
                double estimated = estimatedValuesEnumerator.Current;
                cache[i] = estimated;
                if (!double.IsNaN(estimated) && !double.IsInfinity(estimated))
                {
                    linearScalingCalculator.Add(estimated, target);
                }
                i++;
            }
            if (linearScalingCalculator.ErrorState == OnlineCalculatorError.None && (targetValuesEnumerator.MoveNext() || estimatedValuesEnumerator.MoveNext()))
            {
                throw new ArgumentException("Number of elements in target and estimated values enumeration do not match.");
            }

            double alpha = linearScalingCalculator.Alpha;
            double beta  = linearScalingCalculator.Beta;

            if (linearScalingCalculator.ErrorState != OnlineCalculatorError.None)
            {
                alpha = 0.0;
                beta  = 1.0;
            }

            //calculate the quality by using the passed online calculator
            targetValuesEnumerator = targetValues.GetEnumerator();
            var scaledBoundedEstimatedValuesEnumerator = Enumerable.Range(0, i).Select(x => cache[x] * beta + alpha)
                                                         .LimitToRange(lowerEstimationLimit, upperEstimationLimit).GetEnumerator();

            while (targetValuesEnumerator.MoveNext() & scaledBoundedEstimatedValuesEnumerator.MoveNext())
            {
                calculator.Add(targetValuesEnumerator.Current, scaledBoundedEstimatedValuesEnumerator.Current);
            }
        }
        protected override IEnumerable <IRegressionSolution> CreateBaselineSolutions()
        {
            foreach (var sol in base.CreateBaselineSolutions())
            {
                yield return(sol);
            }

            IEnumerable <double> trainingStartValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices.Select(r => r - 1).Where(r => r > 0)).ToList();
            //AR1 model
            double alpha, beta;
            OnlineCalculatorError errorState;

            OnlineLinearScalingParameterCalculator.Calculate(ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices.Where(x => x > 0)), trainingStartValues, out alpha, out beta, out errorState);
            var ar1Solution = new TimeSeriesPrognosisAutoRegressiveModel(ProblemData.TargetVariable, new double[] { beta }, alpha).CreateTimeSeriesPrognosisSolution(ProblemData);

            ar1Solution.Name = "AR(1)";
            yield return(ar1Solution);
        }
    protected void Scale(IDataAnalysisProblemData problemData, string targetVariable) {
      var dataset = problemData.Dataset;
      var rows = problemData.TrainingIndices;
      var estimatedValues = Interpreter.GetSymbolicExpressionTreeValues(SymbolicExpressionTree, dataset, rows);
      var targetValues = dataset.GetDoubleValues(targetVariable, rows);

      var linearScalingCalculator = new OnlineLinearScalingParameterCalculator();
      var targetValuesEnumerator = targetValues.GetEnumerator();
      var estimatedValuesEnumerator = estimatedValues.GetEnumerator();
      while (targetValuesEnumerator.MoveNext() & estimatedValuesEnumerator.MoveNext()) {
        double target = targetValuesEnumerator.Current;
        double estimated = estimatedValuesEnumerator.Current;
        if (!double.IsNaN(estimated) && !double.IsInfinity(estimated))
          linearScalingCalculator.Add(estimated, target);
      }
      if (linearScalingCalculator.ErrorState == OnlineCalculatorError.None && (targetValuesEnumerator.MoveNext() || estimatedValuesEnumerator.MoveNext()))
        throw new ArgumentException("Number of elements in target and estimated values enumeration do not match.");

      double alpha = linearScalingCalculator.Alpha;
      double beta = linearScalingCalculator.Beta;
      if (linearScalingCalculator.ErrorState != OnlineCalculatorError.None) return;

      ConstantTreeNode alphaTreeNode = null;
      ConstantTreeNode betaTreeNode = null;
      // check if model has been scaled previously by analyzing the structure of the tree
      var startNode = SymbolicExpressionTree.Root.GetSubtree(0);
      if (startNode.GetSubtree(0).Symbol is Addition) {
        var addNode = startNode.GetSubtree(0);
        if (addNode.SubtreeCount == 2 && addNode.GetSubtree(0).Symbol is Multiplication && addNode.GetSubtree(1).Symbol is Constant) {
          alphaTreeNode = addNode.GetSubtree(1) as ConstantTreeNode;
          var mulNode = addNode.GetSubtree(0);
          if (mulNode.SubtreeCount == 2 && mulNode.GetSubtree(1).Symbol is Constant) {
            betaTreeNode = mulNode.GetSubtree(1) as ConstantTreeNode;
          }
        }
      }
      // if tree structure matches the structure necessary for linear scaling then reuse the existing tree nodes
      if (alphaTreeNode != null && betaTreeNode != null) {
        betaTreeNode.Value *= beta;
        alphaTreeNode.Value *= beta;
        alphaTreeNode.Value += alpha;
      } else {
        var mainBranch = startNode.GetSubtree(0);
        startNode.RemoveSubtree(0);
        var scaledMainBranch = MakeSum(MakeProduct(mainBranch, beta), alpha);
        startNode.AddSubtree(scaledMainBranch);
      }
    }
        protected void Scale(IDataAnalysisProblemData problemData, string targetVariable)
        {
            var dataset         = problemData.Dataset;
            var rows            = problemData.TrainingIndices;
            var estimatedValues = Interpreter.GetSymbolicExpressionTreeValues(SymbolicExpressionTree, dataset, rows);
            var targetValues    = dataset.GetDoubleValues(targetVariable, rows);

            var linearScalingCalculator   = new OnlineLinearScalingParameterCalculator();
            var targetValuesEnumerator    = targetValues.GetEnumerator();
            var estimatedValuesEnumerator = estimatedValues.GetEnumerator();

            while (targetValuesEnumerator.MoveNext() & estimatedValuesEnumerator.MoveNext())
            {
                double target    = targetValuesEnumerator.Current;
                double estimated = estimatedValuesEnumerator.Current;
                if (!double.IsNaN(estimated) && !double.IsInfinity(estimated))
                {
                    linearScalingCalculator.Add(estimated, target);
                }
            }
            if (linearScalingCalculator.ErrorState == OnlineCalculatorError.None && (targetValuesEnumerator.MoveNext() || estimatedValuesEnumerator.MoveNext()))
            {
                throw new ArgumentException("Number of elements in target and estimated values enumeration do not match.");
            }

            double alpha = linearScalingCalculator.Alpha;
            double beta  = linearScalingCalculator.Beta;

            if (linearScalingCalculator.ErrorState != OnlineCalculatorError.None)
            {
                return;
            }

            ConstantTreeNode alphaTreeNode = null;
            ConstantTreeNode betaTreeNode  = null;
            // check if model has been scaled previously by analyzing the structure of the tree
            var startNode = SymbolicExpressionTree.Root.GetSubtree(0);

            if (startNode.GetSubtree(0).Symbol is Addition)
            {
                var addNode = startNode.GetSubtree(0);
                if (addNode.SubtreeCount == 2 && addNode.GetSubtree(0).Symbol is Multiplication && addNode.GetSubtree(1).Symbol is Constant)
                {
                    alphaTreeNode = addNode.GetSubtree(1) as ConstantTreeNode;
                    var mulNode = addNode.GetSubtree(0);
                    if (mulNode.SubtreeCount == 2 && mulNode.GetSubtree(1).Symbol is Constant)
                    {
                        betaTreeNode = mulNode.GetSubtree(1) as ConstantTreeNode;
                    }
                }
            }
            // if tree structure matches the structure necessary for linear scaling then reuse the existing tree nodes
            if (alphaTreeNode != null && betaTreeNode != null)
            {
                betaTreeNode.Value  *= beta;
                alphaTreeNode.Value *= beta;
                alphaTreeNode.Value += alpha;
            }
            else
            {
                var mainBranch = startNode.GetSubtree(0);
                startNode.RemoveSubtree(0);
                var scaledMainBranch = MakeSum(MakeProduct(mainBranch, beta), alpha);
                startNode.AddSubtree(scaledMainBranch);
            }
        }