/// <summary>
        /// Train a new decision forest given some training data and a training
        /// problem described by an instance of the ITrainingContext interface.
        /// </summary>
        /// <param name="random">Random number generator.</param>
        /// <param name="parameters">Training parameters.</param>
        /// <param name="maxThreads">The maximum number of threads to use.</param>
        /// <param name="context">An ITrainingContext instance describing
        /// the training problem, e.g. classification, density estimation, etc. </param>
        /// <param name="data">The training data.</param>
        /// <returns>A new decision forest.</returns>
        public static Forest <F, S> TrainForest(
            Random random,
            TrainingParameters parameters,
            ITrainingContext <F, S> context,
            int maxThreads,
            IDataPointCollection data,
            ProgressWriter progress = null)
        {
            if (progress == null)
            {
                progress = new ProgressWriter(parameters.Verbose?Verbosity.Verbose:Verbosity.Interest, Console.Out);
            }

            Forest <F, S> forest = new Forest <F, S>();

            for (int t = 0; t < parameters.NumberOfTrees; t++)
            {
                progress.Write(Verbosity.Interest, "\rTraining tree {0}...", t);

                Tree <F, S> tree = ParallelTreeTrainer <F, S> .TrainTree(random, context, parameters, maxThreads, data, progress);

                forest.AddTree(tree);
            }
            progress.WriteLine(Verbosity.Interest, "\rTrained {0} trees.         ", parameters.NumberOfTrees);

            return(forest);
        }