/// <summary>
        ///   Creates a set of decision variables from input data.
        /// </summary>
        ///
        /// <param name="inputs">The input data.</param>
        ///
        /// <returns>An array of <see cref="DecisionVariable"/> objects
        /// initialized with the values from the codebook.</returns>
        ///
        public static DecisionVariable[] FromData(int[][] inputs)
        {
            int cols      = inputs.Columns();
            var variables = new DecisionVariable[cols];

            for (int i = 0; i < variables.Length; i++)
            {
                variables[i] = new DecisionVariable(i.ToString(), inputs.GetColumn(i).GetRange());
            }
            return(variables);
        }
        /// <summary>
        ///   Learns a model that can map the given inputs to the given outputs.
        /// </summary>
        ///
        /// <param name="x">The model inputs.</param>
        /// <param name="y">The desired outputs associated with each <paramref name="x">inputs</paramref>.</param>
        /// <param name="weights">The weight of importance for each input-output pair.</param>
        ///
        /// <returns>A model that has learned how to produce <paramref name="y"/> given <paramref name="x"/>.</returns>
        ///
        public RandomForest Learn(double[][] x, int[] y, double[] weights = null)
        {
            if (forest == null)
            {
                int classes = y.Max() + 1;
                this.forest = new RandomForest(NumberOfTrees, classes);
                if (this.attributes == null)
                {
                    this.attributes = DecisionVariable.FromData(x);
                }
                for (int i = 0; i < forest.Trees.Length; i++)
                {
                    forest.Trees[i] = new DecisionTree(attributes, classes);
                }
            }

            run(x, y);
            return(this.forest);
        }
        /// <summary>
        ///   Creates a set of decision variables from a <see cref="Codification"/> codebook.
        /// </summary>
        ///
        /// <param name="codebook">The codebook containing information about the variables.</param>
        /// <param name="columns">The columns to consider as decision variables.</param>
        ///
        /// <returns>An array of <see cref="DecisionVariable"/> objects
        /// initialized with the values from the codebook.</returns>
        ///
        public static DecisionVariable[] FromCodebook(Codification codebook, params string[] columns)
        {
            DecisionVariable[] variables = new DecisionVariable[columns.Length];

            for (int i = 0; i < variables.Length; i++)
            {
                string name = columns[i];

                Codification.Options col;

                if (codebook.Columns.TryGetValue(name, out col))
                {
                    variables[i] = new DecisionVariable(name, col.NumberOfSymbols);
                }
                else
                {
                    variables[i] = new DecisionVariable(name, DecisionVariableKind.Continuous);
                }
            }

            return(variables);
        }