Newton-Raphson Metodu ile Fonksiyon Kök Bulma

Newton-Raphson metodu, sayısal analizde, eşitlik köklerinin bulunmasında en yaygın kullanılan metotlardan birisidir. Başlangıç için tahmini bir kök değeri seçilerek, yapılan iterasyon sonucu gerçek kök değerine oldukça yakın bir değere ulaşılır.

Newton-Raphson

Newton-Raphson metodunun C# dilinde yazılmış kaynak kodu yer almaktadır.

public class NewtonRaphson
{
    public uint MaxIteration { get; set; } = 50;
    public double Epsilon { get; set; } = 0.000001;

    public double Solve(Func<double, double> f, Func<double, double> df, double initialGuess)
    {
        var xn = initialGuess;

        for (var i = 0; i < this.MaxIteration; i++)
        {
            var xn1 = xn - f.Invoke(xn) / df.Invoke(xn);

            if (Math.Abs(xn - xn1) < this.Epsilon)
            {
                return xn1;
            }

            xn = xn1;
        }

        return xn;
    }
}

Örneğin f(x) = x^2 - 2 fonksiyonun köklerini bulmak için, metodu aşağıdaki şekilde çağırabiliriz. Tahmini kök değeri olarak 1 seçilmiştir.

var solver = new NewtonRaphson();
var root = solver.Solve(x => x * x - 2, x => 2 * x, 1);

Benzer şekilde, f(x) = x - Cos(x) fonksiyonun köklerini bulmak için ise, metodu aşağıdaki şekilde çağırabiliriz. f(x) = 1 + Sin(x) fonksiyonun türevidir.

var solver = new NewtonRaphson();
var root = solver.Solve(x => x - Math.Cos(x), x => 1 + Math.Sin(x), 2);
Etiketler:  C#

Julia Fraktal Çizimi & C#

Fraktal; matematikte, çoğunlukla kendine benzeme özelliği gösteren karmaşık geometrik şekillerin ortak adıdır. En bilinen fraktal kümelerinden birisi olan Julia kümesinin C# ile oluşturulmuş hali aşağıdadır.

julia

using System.Drawing;
using System.Numerics;

namespace SG.Algoritma
{
    public class JuliaFractal
    {
        // Julia kümesinde, yarıçağı 2'den büyük her karmaşık sayı çemberi sonsuza götürmektedir.
        private const int MaxMagnitude = 2;

        // Maksimum iterasyon sayısı
        private const int MaxIterations = 1000;

        // Karmaşık sayı koordinat sisteminde, Julia kümesinin bölgesi.
        // Julia kümesinin sadece bir kısmını çizmek için farklı bir bölge verilebilir. 
        private static Complex AreaMin = new Complex(-2, -2);
        private static Complex AreaMax = new Complex(2, 2);

        private Complex C;

        public JuliaFractal(Complex c)
        {
            this.C = c;
        }

        /// <summary>
        /// Julia kümesi imajı oluşturuluyor
        /// </summary>
        /// <param name="dimension">Oluşacak imajın genişlik ve yükseklik değeri (Kare imaj oluşturulacak)</param>
        public Bitmap GenerateBitmap(int dimension)
        {
            return this.GenerateBitmap(dimension, JuliaFractal.AreaMin, JuliaFractal.AreaMax);
        }

        /// <summary>
        /// Julia kümesi imajı oluşturuluyor
        /// </summary>
        /// <param name="width">Oluşacak imajın genişliği. Yükseklik, çizilmek istenen bölgeyenin genişlik ve yükseklik değerlerine bakılarak belirlenecek.</param>
        /// <param name="areaMin">Karmaşık sayo kooordinat sisteminde, Julia kümesinin sadece belirli bir bölgeye karşılık düşen kısmı çizdirilmek istendiği zaman, bu bölgenin sol alt kösesi</param>
        /// <param name="areaMax">Sağ üst köşe</param>
        public Bitmap GenerateBitmap(int width, Complex areaMin, Complex areaMax)
        {
            var height = (int)(width * (areaMax - areaMin).Imaginary / (areaMax - areaMin).Real);

            // Boş bir bitmap oluştur
            var bitmap = new Bitmap(width, height);

            // Oluşturulacak imajın her piksel değerine karşılık düşen karmaşık sayı oluşturulacak.
            // Oluşturacağımız karmaşık sayıların, seçtiğimiz bölge içerisinde kalması gerekmektedir.

            var rScale = (areaMax - areaMin).Real / width;
            var iScale = (areaMax - areaMin).Imaginary / height;

            for (var x = 0; x < width; x++)
            {
                // Karmaşık sayısının real kısmı
                var real = areaMin.Real + x * rScale;

                for (var y = 0; y < height; y++)
                {
                    // Karmaşık sayısının imaginary kısmı
                    var imaginary = areaMin.Imaginary + y * iScale;

                    // Julia kümesi iterasyon değeri hesaplanıyor.
                    var iteration = this.CalculateIteration(new Complex(real, imaginary));

                    // Iterasyon değerine göre noktanın rengi ayarlanıyor.
                    bitmap.SetPixel(x, y, JuliaFractal.GetColor(iteration));
                }
            }

            return bitmap;
        }

        private int CalculateIteration(Complex z)
        {
            var iteration = 0;

            while (iteration < JuliaFractal.MaxIterations && z.Magnitude < JuliaFractal.MaxMagnitude)
            {
                z = z * z + this.C;
                iteration++;
            }

            return iteration;
        }

        /// <summary>
        /// // Iterasyona karşılık renk seçiliyor.
        /// </summary>
        private static Color GetColor(int iteration)
        {
            // Rasgele bir renk seçiliyor.
            // 256 tane rengin olduğu bir liste oluşturularak, listeden iteration % 256. renk de seçilebilir.
            // Ya da renk oluşturmak için farklı bir yöntem izlenebilir.

            return Color.FromArgb(0, iteration % 256, 0);
        }
    }
}

Julia kümesini fraktal resmini oluşturmak için, ilgili metot aşağıdaki şekilde çağrılabilir. Bu durumda en üstte yer alan resim oluşacaktır.

var fractal = new JuliaFractal(new Complex(0.285, 0.01));
var bitmap = fractal.GenerateBitmap(800);

bitmap.Save(@"D:\julia.png", ImageFormat.Png);

Julia fraktalının sadece belirli bir bölgesini çizdirmek için, ilgili metot aşağıdaki şekilde çağrılabilir. Böylece fraktalın istenilen bölgesi daha detaylı bir şekilde çizdirilebilir.

var bitmap = fractal.GenerateBitmap(800, new Complex(-0.85, 0.1), new Complex(-0.45, 0.37));

julia

Etiketler:  C#

Mandelbrot Fraktal Çizimi & C#

Fraktal; matematikte, çoğunlukla kendine benzeme özelliği gösteren karmaşık geometrik şekillerin ortak adıdır. En bilinen fraktal kümelerinden birisi olan Mandelbrot kümesinin C# ile oluşturulmuş hali aşağıdadır.

mandelbrot

using System;
using System.Drawing;
using System.Numerics;

namespace SG.Algoritma
{
    public class Fractal
    {
        // Mandelbort kümesinde, yarıçağı 2'den büyük her karmaşık sayı çemberi sonsuza götürmektedir.
        private const int MaxMagnitude = 2;

        // Maksimum iterasyon sayısı
        private const int MaxIterations = 1000;

        // Karmaşık sayı koordinat sisteminde, Mandelbort kümesinin bölgesi.
        // Mandelbort kümesinin sadece bir kısmını çizmek için farklı bir bölge verilebilir. 
        private static Complex AreaMin = new Complex(-2, -2);
        private static Complex AreaMax = new Complex(2, 2);

        /// <summary>
        /// Mandelbort kümesi imajı oluşturuluyor
        /// </summary>
        /// <param name="dimension">Oluşacak imajın genişlik ve yükseklik değeri (Kare imaj oluşturulacak)</param>
        public static Bitmap GenerateBitmap(int dimension)
        {
            return Fractal.GenerateBitmap(dimension, Fractal.AreaMin, Fractal.AreaMax);
        }

        /// <summary>
        /// Mandelbort kümesi imajı oluşturuluyor
        /// </summary>
        /// <param name="width">Oluşacak imajın genişliği. Yükseklik, çizilmek istenen bölgeyenin genişlik ve yükseklik değerlerine bakılarak belirlenecek.</param>
        /// <param name="areaMin">Karmaşık sayo kooordinat sisteminde, Mandelbort kümesinin sadece belirli bir bölgeye karşılık düşen kısmı çizdirilmek istendiği zaman, bu bölgenin sol alt kösesi</param>
        /// <param name="areaMax">Sağ üst köşe</param>
        public static Bitmap GenerateBitmap(int width, Complex areaMin, Complex areaMax)
        {
            var height = (int)(width * (areaMax - areaMin).Imaginary / (areaMax - areaMin).Real);

            // Boş bir bitmap oluştur
            var bitmap = new Bitmap(width, height);

            // Oluşturulacak imajın her piksel değerine karşılık düşen karmaşık sayı oluşturulacak.
            // Oluşturacağımız karmaşık sayıların, seçtiğimiz bölge içerisinde kalması gerekmektedir.
            
            var rScale = (areaMax - areaMin).Real / width;
            var iScale = (areaMax - areaMin).Imaginary / height;

            for (var x = 0; x < width; x++)
            {
                // Karmaşık sayısının real kısmı
                var real = areaMin.Real + x * rScale;

                for (var y = 0; y < height; y++)
                {
                    // Karmaşık sayısının imaginary kısmı
                    var imaginary = areaMin.Imaginary + y * iScale;

                    // Mandelbort kümesi iterasyon değeri hesaplanıyor.
                    var iteration = Fractal.CalculateIteration(new Complex(real, imaginary));

                    // Iterasyon değerine göre noktanın rengi ayarlanıyor.
                    bitmap.SetPixel(x, y, Fractal.GetColor(iteration));
                }
            }

            return bitmap;
        }

        private static int CalculateIteration(Complex c)
        {
            var z = new Complex();
            var iteration = 0;

            // MaxIterations adedince f(z) = z^2 + c işlemini uygula
            // İşlem sonucu Mandelbort kümesi içerisinde kalmaya devam ettiği sürece işlemi tekrarla
            while (iteration < Fractal.MaxIterations && z.Magnitude < Fractal.MaxMagnitude)
            {
                z = z * z + c;
                iteration++;
            }

            return iteration;
        }

        /// <summary>
        /// // Iterasyona karşılık renk seçiliyor.
        /// </summary>
        private static Color GetColor(int iteration)
        {
            // Rasgele bir renk seçiliyor.
            // 256 tane rengin olduğu bir liste oluşturularak, listeden iteration % 256. renk de seçilebilir.
            // Ya da, oluşan imajın tek renkten oluşmasını istiyorsak, Color.FromArgb(iteration % 256, 0, 0) rengi seçilebilir. Bu durumda kırmızı toplanda imaj oluşacaktır.

            return Color.FromArgb((iteration * iteration * iteration) % 256, (iteration * iteration) % 256, (iteration) % 256);
        }
    }
}

Mandelbrot kümesini fraktal resmini oluşturmak için, ilgili metot aşağıdaki şekilde çağrılabilir. Bu durumda en üstte yer alan resim oluşacaktır.

var bitmap = Fractal.GenerateBitmap(800);

bitmap.Save(@"D:\mandelbort.png", ImageFormat.Png);

Mandelbrot fraktalının sadece belirli bir bölgesini çizdirmek için, ilgili metot aşağıdaki şekilde çağrılabilir. Böylece fraktalın istenilen bölgesi daha detaylı bir şekilde çizdirilebilir.

var bitmap = Fractal.GenerateBitmap(800, new Complex(-0.4, -1.3), new Complex(0.1, -0.5));

mandelbrot

Etiketler:  C#

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#

Kategoriler

Algoritma (4), Cheat Sheet (2), İpucu (4), Kendime Not (1), Kitap (3), Kod (5), Proje (4), Veritabanı (3), Workshop (3)

Etiketler

C# (10) HTML (1) JavaScript (2) SQL (3)

İngilizce / Türkçe

İngilizce / Türkçe kelime listesi kendime not