Skip to content

Instantly share code, notes, and snippets.

@palladin
Last active September 25, 2021 17:51
Show Gist options
  • Save palladin/8046053 to your computer and use it in GitHub Desktop.
Save palladin/8046053 to your computer and use it in GitHub Desktop.
Mandelbrot set with LINQ
// http://msmvps.com/blogs/jon_skeet/archive/2008/02/26/visualising-the-mandelbrot-set-with-linq-yet-again.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;
using LinqOptimizer.CSharp;
namespace LinqMandelbrot
{
public static class Program
{
const int ImageWidth = 1000;
const int ImageHeight = (int)(SampleHeight * ImageWidth / SampleWidth);
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var query = from row in heightArray.AsParallelQueryExpr()
from col in widthArray
// Work out the initial complex value from the row and column
let c = new Complex((col * SampleWidth) / ImageWidth + OffsetX,
(row * SampleHeight) / ImageHeight + OffsetY)
// Work out the number of iterations
let count = EnumerableEx.Generate(c, x => x.SquareLength < 4, x => x * x + c, x => x)
.Take(MaxIterations)
.Count()
// Map that to an appropriate byte value
select (byte)(count == MaxIterations ? 0 : (count % 255) + 1);
var resultTuple = Measure(() => query.ToArray().Run());
DisplayImage(resultTuple.Item1, resultTuple.Item2.ToString());
}
#region Details
const int MaxIterations = 200;
const double SampleWidth = 3.2;
const double SampleHeight = 2.5;
const double OffsetX = -2.1;
const double OffsetY = -1.25;
public static int[] heightArray = Enumerable.Range(0, ImageHeight).ToArray();
public static int[] widthArray = Enumerable.Range(0, ImageWidth).ToArray();
public static class EnumerableEx
{
public static IEnumerable<R> Generate<T, R>(T start, Func<T, bool> cond, Func<T, T> step, Func<T, R> resultSelector)
{
T value = start;
while (cond(value))
{
yield return resultSelector(value);
value = step(value);
}
}
}
static void DisplayImage(byte[] data, string text)
{
unsafe
{
fixed (byte* ptr = data)
{
IntPtr scan0 = new IntPtr(ptr);
Bitmap bitmap = new Bitmap(ImageWidth, ImageHeight, ImageWidth, PixelFormat.Format8bppIndexed, scan0);
ColorPalette palette = bitmap.Palette;
palette.Entries[0] = Color.Black;
for (int i = 1; i < 256; i++)
{
palette.Entries[i] = Color.FromArgb((i * 7) % 256, (i * 7) % 256, 255);
}
bitmap.Palette = palette;
PictureBox pb = new PictureBox();
pb.SizeMode = PictureBoxSizeMode.AutoSize;
pb.Image = bitmap;
Panel panel = new Panel();
panel.Controls.Add(pb);
panel.AutoScroll = true;
panel.Dock = DockStyle.Fill;
Form form = new Form();
form.FormBorderStyle = FormBorderStyle.Fixed3D;
form.Controls.Add(panel);
form.ClientSize = bitmap.Size;
form.Text = text;
Application.Run(form);
}
}
}
static Tuple<T, TimeSpan> Measure<T>(Func<T> func)
{
var watch = new Stopwatch();
watch.Start();
T result = func();
return Tuple.Create(result, watch.Elapsed);
}
public struct Complex
{
readonly double real;
readonly double imaginary;
public Complex(double real, double imaginary)
{
this.real = real;
this.imaginary = imaginary;
}
public static Complex operator +(Complex c1, Complex c2)
{
return new Complex(c1.real + c2.real, c1.imaginary + c2.imaginary);
}
public static Complex operator *(Complex c1, Complex c2)
{
return new Complex(c1.real * c2.real - c1.imaginary * c2.imaginary,
c1.real * c2.imaginary + c2.real * c1.imaginary);
}
public double SquareLength
{
get { return real * real + imaginary * imaginary; }
}
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment