private static ITimeSeriesPrognosisSolution CreateAutoRegressiveSolution(ITimeSeriesPrognosisProblemData problemData, int timeOffset, out double rmsError, out double cvRmsError)
        {
            string targetVariable = problemData.TargetVariable;

            double[,] inputMatrix = new double[problemData.TrainingPartition.Size, timeOffset + 1];
            var targetValues = problemData.Dataset.GetDoubleValues(targetVariable).ToList();

            for (int i = 0, row = problemData.TrainingPartition.Start; i < problemData.TrainingPartition.Size; i++, row++)
            {
                for (int col = 0; col < timeOffset; col++)
                {
                    inputMatrix[i, col] = targetValues[row - col - 1];
                }
            }
            // set target values in last column
            for (int i = 0; i < inputMatrix.GetLength(0); i++)
            {
                inputMatrix[i, timeOffset] = targetValues[i + problemData.TrainingPartition.Start];
            }

            if (inputMatrix.Cast <double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
            {
                throw new NotSupportedException("Linear regression does not support NaN or infinity values in the input dataset.");
            }


            alglib.linearmodel lm = new alglib.linearmodel();
            alglib.lrreport    ar = new alglib.lrreport();
            int nRows             = inputMatrix.GetLength(0);
            int nFeatures         = inputMatrix.GetLength(1) - 1;

            double[] coefficients = new double[nFeatures + 1]; // last coefficient is for the constant

            int retVal = 1;

            alglib.lrbuild(inputMatrix, nRows, nFeatures, out retVal, out lm, out ar);
            if (retVal != 1)
            {
                throw new ArgumentException("Error in calculation of linear regression solution");
            }
            rmsError   = ar.rmserror;
            cvRmsError = ar.cvrmserror;

            alglib.lrunpack(lm, out coefficients, out nFeatures);

            var tree = LinearModelToTreeConverter.CreateTree(
                variableNames: Enumerable.Repeat(problemData.TargetVariable, nFeatures).ToArray(),
                lags: Enumerable.Range(0, timeOffset).Select(i => (i + 1) * -1).ToArray(),
                coefficients: coefficients.Take(nFeatures).ToArray(),
                @const: coefficients[nFeatures]
                );

            var interpreter = new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter(problemData.TargetVariable);
            var model       = new SymbolicTimeSeriesPrognosisModel(problemData.TargetVariable, tree, interpreter);
            var solution    = model.CreateTimeSeriesPrognosisSolution((ITimeSeriesPrognosisProblemData)problemData.Clone());

            return(solution);
        }
        private static ITimeSeriesPrognosisSolution CreateAutoRegressiveSolution(ITimeSeriesPrognosisProblemData problemData, int timeOffset, out double rmsError, out double cvRmsError)
        {
            string targetVariable = problemData.TargetVariable;

            double[,] inputMatrix = new double[problemData.TrainingPartition.Size, timeOffset + 1];
            var targetValues = problemData.Dataset.GetDoubleValues(targetVariable).ToList();

            for (int i = 0, row = problemData.TrainingPartition.Start; i < problemData.TrainingPartition.Size; i++, row++)
            {
                for (int col = 0; col < timeOffset; col++)
                {
                    inputMatrix[i, col] = targetValues[row - col - 1];
                }
            }
            // set target values in last column
            for (int i = 0; i < inputMatrix.GetLength(0); i++)
            {
                inputMatrix[i, timeOffset] = targetValues[i + problemData.TrainingPartition.Start];
            }

            if (inputMatrix.Cast <double>().Any(x => double.IsNaN(x) || double.IsInfinity(x)))
            {
                throw new NotSupportedException("Linear regression does not support NaN or infinity values in the input dataset.");
            }


            alglib.linearmodel lm = new alglib.linearmodel();
            alglib.lrreport    ar = new alglib.lrreport();
            int nRows             = inputMatrix.GetLength(0);
            int nFeatures         = inputMatrix.GetLength(1) - 1;

            double[] coefficients = new double[nFeatures + 1]; // last coefficient is for the constant

            int retVal = 1;

            alglib.lrbuild(inputMatrix, nRows, nFeatures, out retVal, out lm, out ar);
            if (retVal != 1)
            {
                throw new ArgumentException("Error in calculation of linear regression solution");
            }
            rmsError   = ar.rmserror;
            cvRmsError = ar.cvrmserror;

            alglib.lrunpack(lm, out coefficients, out nFeatures);


            ISymbolicExpressionTree     tree      = new SymbolicExpressionTree(new ProgramRootSymbol().CreateTreeNode());
            ISymbolicExpressionTreeNode startNode = new StartSymbol().CreateTreeNode();

            tree.Root.AddSubtree(startNode);
            ISymbolicExpressionTreeNode addition = new Addition().CreateTreeNode();

            startNode.AddSubtree(addition);

            for (int i = 0; i < timeOffset; i++)
            {
                LaggedVariableTreeNode node = (LaggedVariableTreeNode) new LaggedVariable().CreateTreeNode();
                node.VariableName = targetVariable;
                node.Weight       = coefficients[i];
                node.Lag          = (i + 1) * -1;
                addition.AddSubtree(node);
            }

            ConstantTreeNode cNode = (ConstantTreeNode) new Constant().CreateTreeNode();

            cNode.Value = coefficients[coefficients.Length - 1];
            addition.AddSubtree(cNode);

            var interpreter = new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter(problemData.TargetVariable);
            var model       = new SymbolicTimeSeriesPrognosisModel(problemData.TargetVariable, tree, interpreter);
            var solution    = model.CreateTimeSeriesPrognosisSolution((ITimeSeriesPrognosisProblemData)problemData.Clone());

            return(solution);
        }