/// <summary>
        /// Evaluate the provided black box against the function regression task,
        /// and return its fitness score.
        /// </summary>
        /// <param name="box">The black box to evaluate.</param>
        /// <returns>A new instance of <see cref="FitnessInfo"/>.</returns>
        public FitnessInfo Evaluate(IBlackBox <double> box)
        {
            // Probe the black box over the full range of the input parameter.
            _blackBoxProbe.Probe(box, _yArr);

            // Calc gradients.
            FuncRegressionUtils.CalcGradients(_paramSamplingInfo, _yArr, _gradientArr);

            // Calc y position mean squared error (MSE), and apply weighting.
            double yMse = MathSpanUtils.MeanSquaredDelta(_yArr, _yArrTarget);

            yMse *= _yMseWeight;

            // Calc gradient mean squared error.
            double gradientMse = MathSpanUtils.MeanSquaredDelta(_gradientArr, _gradientArrTarget);

            gradientMse *= _gradientMseWeight;

            // Calc fitness as the inverse of MSE (higher value is fitter).
            // Add a constant to avoid divide by zero, and to constrain the fitness range between bad and good solutions;
            // this allows the selection strategy to select solutions that are mediocre and therefore helps preserve diversity.
            double fitness = 20.0 / (yMse + gradientMse + 0.02);

            return(new FitnessInfo(fitness));
        }
        private static BlackBoxProbe CreateBlackBoxProbe(
            Func <double, double> fn,
            ParamSamplingInfo paramSamplingInfo)
        {
            // Determine the mid output value of the function (over the specified sample points) and a scaling factor
            // to apply the to neural network response for it to be able to recreate the function (because the neural net
            // output range is [0,1] when using the logistic function as the neuron activation function).
            FuncRegressionUtils.CalcFunctionMidAndScale(fn, paramSamplingInfo, out double mid, out double scale);

            return(new BlackBoxProbe(paramSamplingInfo, mid, scale));
        }
        /// <summary>
        /// Construct a new instance.
        /// </summary>
        /// <param name="fn">The target function.</param>
        /// <param name="paramSamplingInfo">Sampling (defines the x range and sampling density).</param>
        /// <param name="gradientMseWeight">The fitness weighting to assign to the gradient mean squared error (MSE) score.</param>
        public FuncRegressionEvaluationScheme(
            Func <double, double> fn,
            ParamSamplingInfo paramSamplingInfo,
            double gradientMseWeight)
        {
            _paramSamplingInfo = paramSamplingInfo;
            _gradientMseWeight = gradientMseWeight;

            // Alloc arrays.
            int sampleCount = _paramSamplingInfo.SampleResolution;

            _yArrTarget        = new double[sampleCount];
            _gradientArrTarget = new double[sampleCount];

            // Predetermine target responses.
            FuncRegressionUtils.Probe(fn, paramSamplingInfo, _yArrTarget);
            FuncRegressionUtils.CalcGradients(paramSamplingInfo, _yArrTarget, _gradientArrTarget);

            // Create blackbox probe.
            _blackBoxProbe = CreateBlackBoxProbe(fn, paramSamplingInfo);
        }