Monte Carlo İntegrali Alan Hesabı

Bir eğrinin altında yer alan alanı istatiksel bir yöntemle hesaplamak için Monte Carlo integral algoritması kullanılabilir. Bu algoritma ile, rasgele üretilen N adet noktanın kaç tanesinin fonksiyon eğrisinin altında yer aldığına bakılır. Rasgele seçilen noktaların yüzde kaçının eğri altında yer aldığına bakılarak, yaklaşık olarak alan hesabı yapılabilir.

Algoritma adımları aşağıdaki şekilde sıralanabilir:

  • Fonksiyonun verilen aralıktaki tüm değerlerini içine alacak şekilde bir dikdörtgen belirlenir.
  • Bu dörtgen içerisinde, N adet nokta rastgele olarak oluşturulur.
  • Bu noktaların ne kadarının, fonksiyonun belirlediği alanın altında olduğuna bakılır.
  • N değerinin, eğri altında olan nokta sayısına oranı, bize yaklaşık olarak, dikdörtgenin alanın fonksiyon eğrisi alanına oranını verecektir.

Aşağıda, Monte Carlo algoritmasının C# dilinde yazılmış kaynak kodu yer almaktadır.

using System;

namespace SG.Algoritma
{
    partial class MonteCarlo
    {
        // Deneme adet
        public uint N { get; set; }

        public MonteCarlo(uint n)
        {
            if (n == 0)
            {
                throw new ArgumentException(nameof(N));
            }

            this.N = n;
        }

        /// <summary>
        /// Verilen fonksiyon eğrisinin altında bulunan alan hesaplanıyor.
        /// </summary>
        /// <param name="func">Fonksiyon</param>
        /// <param name="x1">X ekseni üzerinde, aralık başlangıcı</param>
        /// <param name="x2">Aralık bitiş</param>
        public double CalculateArea(Func<double, double> func, double x1, double x2)
        {
            // Verilen aralıkta, fonksiyonun aldığı minimum ve maksimum değerler
            double min;
            double max;

            // Fonksiyonun minimum ve maksimum değeri hesaplanıyor
            this.CalculateMinMaxValue(func, x1, x2, out min, out max);

            // Denemelerden kaç tanesi, fonksiyon eğrisinin altında
            var hit = 0;

            // Rasgele sayı üretici
            var rand = new Random();

            // N adet dememe yap
            for (int i = 0; i < this.N; i++)
            {
                // Dikdörtgen içerisinde rasgele bir nokta üret
                var x = x1 + (x2 - x1) * rand.NextDouble();
                var y = min + (max - min) * rand.NextDouble();

                // Rasgele seçilen nokta ve fonksiyonun değeri, eğrinin aynı tarafındaysa. (İki negatif sayının çarpımı pozitiftir)
                if (func(x) * y > 0)
                {
                    // Fonksiyon değeri pozitifse
                    if (func(x) > 0)
                    {
                        // Rasgele üretilen y değeri fonsiyon eğrisinin altındaysa
                        if (func(x) > y) hit++;
                    }
                    else
                    {
                        // Rasgele üretilen y değeri fonsiyon eğrisinin üstündeyse
                        if (y < 0 && func(x) < y) hit++;
                    }
                }
            }

            var areaRectangle = Math.Abs(x2 - x1) * (max - min);

            // Seçilen rasgelen noktaların yüzde hit / N kadarı dikdörtgenin içerisinde.
            // Noktaların yüzde kaçının dikdörtgen içerisinde olduğuna bakılarak alan hesabı yapılıyor.

            return areaRectangle * (double)hit / this.N;
        }

        /// <summary>
        /// Verilen aralıkta, fornksiyonun minimum ve maksimum değerleri hesaplanıyor.
        /// </summary>
        /// <param name="func">Fonksiyon</param>
        /// <param name="x1">Aralık başlangıç</param>
        /// <param name="x2">Aralık bitiş</param>
        /// <param name="min">Hesaplanan minimum değer</param>
        /// <param name="max">Hesaplanan maksimum değer</param>
        private void CalculateMinMaxValue(Func<double, double> func, double x1, double x2, out double min, out double max)
        {
            min = double.MaxValue;
            max = double.MinValue;

            // Aralık N parçaya bölünüyor.
            var h = (x2 - x1) / this.N;

            // Verilen aralıkta, N adet nokta için, her bir noktanın fonksiyon değeri hesaplanıyor.
            for (int i = 0; i <= this.N; i++)
            {
                var x = x1 + i * h;
                var y = func(x);

                if (y < min) min = y;
                if (y > max) max = y;
            }
        }
    }
}

Monte Carlo alan hesabı algoritması ile, istediğiniz fonksiyon grafiği altında yer alan bölgenin alanını çok rahat bir şekilde hesaplayabiliriz. Fonksiyonun ne kadar karmaşık olduğunu bir önemi yok. Örneğin f(x) = x - sin(x) - 1 fonksiyon eğrisinin x ekseni {0,3} aralığındaki alanı hesaplamak için, alan hesaplama metodunu aşağıdaki gibi çalıştırabiliriz.

var mc = new MonteCarlo(1000);
var area = mc.CalculateArea(x => x - Math.Sin(x) - 1, 0, 3);

Bu durumda aşağıdaki eğri altında yer alan alan yaklaşık olarak hesaplanacaktır. Daha hassas bir hesaplamak için N değerinin artırılması gerekmektedir.

Monte Carlo Integration

Aynı algoritmada yapılacak küçük bir değişiklikle, fonksiyonun integral değeri de rahatlıkla hesaplanabilir. İntegral hesabında, pozitif alanlardan negatif alanlar çıkarılacağı için, bu alanlara düşen noktalar ayrı ayrı sayılır.

Etiketler:  C#