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#

Encrypt & Decrypt a String in C#

Encrypt and decrypt data using a symmetric key in C#.

Usage

var str = "String to be encrypted";
var password = "p@SSword";
var strEncryptred = Cipher.Encrypt(str, password);
var strDecrypted = Cipher.Decrypt(strEncryptred, password);

Encryption

Cipher class

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace SG.Algoritma
{
    public static class Cipher
    {
        /// <summary>
        /// Encrypt a string.
        /// </summary>
        /// <param name="plainText">String to be encrypted</param>
        /// <param name="password">Password</param>
        public static string Encrypt(string plainText, string password)
        {
            if (plainText == null)
            {
                return null;
            }

            if (password == null)
            {
                password = String.Empty;
            }

            // Get the bytes of the string
            var bytesToBeEncrypted = Encoding.UTF8.GetBytes(plainText);
            var passwordBytes = Encoding.UTF8.GetBytes(password);

            // Hash the password with SHA256
            passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

            var bytesEncrypted = Cipher.Encrypt(bytesToBeEncrypted, passwordBytes);

            return Convert.ToBase64String(bytesEncrypted);
        }

        /// <summary>
        /// Decrypt a string.
        /// </summary>
        /// <param name="encryptedText">String to be decrypted</param>
        /// <param name="password">Password used during encryption</param>
        /// <exception cref="FormatException"></exception>
        public static string Decrypt(string encryptedText, string password)
        {
            if (encryptedText == null)
            {
                return null;
            }

            if (password == null)
            {
                password = String.Empty;
            }

            // Get the bytes of the string
            var bytesToBeDecrypted = Convert.FromBase64String(encryptedText);
            var passwordBytes = Encoding.UTF8.GetBytes(password);

            passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

            var bytesDecrypted = Cipher.Decrypt(bytesToBeDecrypted, passwordBytes);

            return Encoding.UTF8.GetString(bytesDecrypted);
        }

        private static byte[] Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
        {
            byte[] encryptedBytes = null;

            // Set your salt here, change it to meet your flavor:
            // The salt bytes must be at least 8 bytes.
            var saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);

                    AES.KeySize = 256;
                    AES.BlockSize = 128;
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);

                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                        cs.Close();
                    }

                    encryptedBytes = ms.ToArray();
                }
            }

            return encryptedBytes;
        }

        private static byte[] Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
        {
            byte[] decryptedBytes = null;

            // Set your salt here, change it to meet your flavor:
            // The salt bytes must be at least 8 bytes.
            var saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

            using (MemoryStream ms = new MemoryStream())
            {
                using (RijndaelManaged AES = new RijndaelManaged())
                {
                    var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);

                    AES.KeySize = 256;
                    AES.BlockSize = 128;
                    AES.Key = key.GetBytes(AES.KeySize / 8);
                    AES.IV = key.GetBytes(AES.BlockSize / 8);
                    AES.Mode = CipherMode.CBC;

                    using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                        cs.Close();
                    }

                    decryptedBytes = ms.ToArray();
                }
            }

            return decryptedBytes;
        }
    }
}
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#
Sayfa 1 2

Kategoriler

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

Etiketler

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

İngilizce / Türkçe

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