private static UncertainValue Integrate_MonteCarlo(MultiFunctor f, CoordinateTransform[] map, IList <Interval> box, EvaluationSettings 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); // 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; } } throw new NonconvergenceException(); }
private static UncertainValue Integrate_MonteCarlo(MultiFunctor f, CoordinateTransform[] map, IList<Interval> box, EvaluationSettings 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); // 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; } } throw new NonconvergenceException(); }