Exemplo n.º 1
0
        // the drivers

        private static IntegrationResult Integrate_Adaptive(IAdaptiveIntegrator integrator, IntegrationSettings settings)
        {
            Debug.Assert(integrator != null);
            Debug.Assert(settings != null);

            LinkedList <IAdaptiveIntegrator> list = new LinkedList <IAdaptiveIntegrator>();

            list.AddFirst(integrator);

            int n = integrator.EvaluationCount;

            while (true)
            {
                // go through the intervals, adding estimates (and errors)
                // and noting which contributes the most error
                // keep track of the total value and uncertainty
                UncertainValue vTotal = new UncertainValue();

                // keep track of which node contributes the most error
                LinkedListNode <IAdaptiveIntegrator> maxNode = null;
                double maxError = 0.0;

                LinkedListNode <IAdaptiveIntegrator> node = list.First;
                while (node != null)
                {
                    IAdaptiveIntegrator i = node.Value;

                    UncertainValue v = i.Estimate;
                    vTotal += v;

                    if (v.Uncertainty > maxError)
                    {
                        maxNode  = node;
                        maxError = v.Uncertainty;
                    }

                    node = node.Next;
                }

                // Inform listeners of our latest result.
                if (settings.Listener != null)
                {
                    settings.Listener(new IntegrationResult(vTotal, n, settings));
                }

                // if our error is small enough, return
                double tol = settings.ComputePrecision(vTotal.Value);
                if (vTotal.Uncertainty <= tol)
                {
                    // Don't claim uncertainty significantly less than tol.
                    if (vTotal.Uncertainty < tol / 2.0)
                    {
                        vTotal = new UncertainValue(vTotal.Value, tol / 2.0);
                    }
                    return(new IntegrationResult(vTotal, n, settings));
                }

                // if our evaluation count is too big, throw
                if (n > settings.EvaluationBudget)
                {
                    throw new NonconvergenceException();
                }

                // Subdivide the interval with the largest error
                IEnumerable <IAdaptiveIntegrator> divisions = maxNode.Value.Divide();
                foreach (IAdaptiveIntegrator division in divisions)
                {
                    list.AddBefore(maxNode, division);
                    n += division.EvaluationCount;
                }
                list.Remove(maxNode);
            }
        }
        private static UncertainValue Integrate_MonteCarlo(MultiFunctor f, CoordinateTransform[] map, IList <Interval> box, IntegrationSettings settings)
        {
            int d = box.Count;

            // Use a Sobol quasi-random sequence. This give us 1/N accuracy instead of 1/\sqrt{N} accuracy.
            //VectorGenerator g = new RandomVectorGenerator(d, new Random(314159265));
            VectorGenerator g = new SobolVectorGenerator(d);

            // Start with a trivial Lepage grid.
            // We will increase the grid size every few cycles.
            // My tests indicate that trying to increase every cycle or even every other cycle is too often.
            // This makes sense, because we have no reason to believe our new grid will be better until we
            // have substantially more evaluations per grid cell than we did for the previous grid.
            LePageGrid grid        = new LePageGrid(box, 1);
            int        refineCount = 0;

            // Start with a reasonable number of evaluations per cycle that increases with the dimension.
            int cycleCount = 8 * d;

            //double lastValue = Integrate_MonteCarlo_Cycle(f, map, g, grid, cycleCount);

            // Each cycle consists of three sets of evaluations.
            // At first I did this with just two set and used the difference between the two sets as an error estimate.
            // I found that it was pretty common for that difference to be low just by chance, causing error underestimatation.
            double value1 = Integrate_MonteCarlo_Cycle(f, map, g, grid, cycleCount);
            double value2 = Integrate_MonteCarlo_Cycle(f, map, g, grid, cycleCount);
            double value3 = Integrate_MonteCarlo_Cycle(f, map, g, grid, cycleCount);

            while (f.EvaluationCount < settings.EvaluationBudget)
            {
                // Take the largest deviation as the error.
                double value = (value1 + value2 + value3) / 3.0;
                double error = Math.Max(Math.Abs(value1 - value3), Math.Max(Math.Abs(value1 - value2), Math.Abs(value2 - value3)));
                Debug.WriteLine("{0} {1} {2}", f.EvaluationCount, value, error);

                if (settings.Listener != null)
                {
                    settings.Listener(new IntegrationResult(new UncertainValue(value, error), f.EvaluationCount, settings));
                }

                // Check for convergence.
                if ((error <= settings.AbsolutePrecision) || (error <= Math.Abs(value) * settings.RelativePrecision))
                {
                    return(new UncertainValue(value, error));
                }

                // Do more cycles. In order for new sets to be equal-sized, one of those must be at the current count and the next at twice that.
                double smallValue = Integrate_MonteCarlo_Cycle(f, map, g, grid, cycleCount);
                cycleCount *= 2;
                double bigValue = Integrate_MonteCarlo_Cycle(f, map, g, grid, cycleCount);

                // Combine all the cycles into new ones with twice the number of evaluations each.
                value1 = (value1 + value2) / 2.0;
                value2 = (value3 + smallValue) / 2.0;
                value3 = bigValue;

                //double currentValue = Integrate_MonteCarlo_Cycle(f, map, g, grid, cycleCount);
                //double error = Math.Abs(currentValue - lastValue);
                //double value = (currentValue + lastValue) / 2.0;



                //lastValue = value;

                // Increase the number of evaluations for the next cycle.
                //cycleCount *= 2;

                // Refine the grid for the next cycle.
                refineCount++;
                if (refineCount == 2)
                {
                    Debug.WriteLine("Replacing grid with {0} bins after {1} evaluations", grid.BinCount, grid.EvaluationCount);
                    grid        = grid.ComputeNewGrid(grid.BinCount * 2);
                    refineCount = 0;
                }

                if (f.EvaluationCount >= settings.EvaluationBudget)
                {
                    throw new NonconvergenceException();
                }
            }

            throw new NonconvergenceException();
        }