Jump to content

User:Simpsons contributor/periodicity checking

From Wikipedia, the free encyclopedia

Highly optimized Mandelbrot set processor which includes main cardioid and period-2 bulb check and periodicity checking. The documentation for period checking optimization is lousy on Wikipedia and across the Internet, so I hope this is of some use. Written in Java by Zom-B, ported to C# by Simpsons contributor.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Mandelbrot2
{
    public struct MandelbrotData
    {
        private double px;
        private double py;

        private double zx;
        private double zy;

        private long iteration;
        private bool inSet;
        private HowFound found;

        public MandelbrotData(double px, double py)
        {
            this.px = px;
            this.py = py;
            this.zx = 0.0;
            this.zy = 0.0;
            this.iteration = 0L;
            this.inSet = false;
            this.found = HowFound.Not;
        }

        public MandelbrotData(double px, double py,
                              double zx, double zy,
                              long iteration,
                              bool inSet,
                              HowFound found)
        {
            this.px = px;
            this.py = py;
            this.zx = zx;
            this.zy = zy;
            this.iteration = iteration;
            this.inSet = inSet;
            this.found = found;
        }

        public double PX
        {
            get { return this.px; }
        }

        public double PY
        {
            get { return this.py; }
        }

        public double ZX
        {
            get { return this.zx; }
        }

        public double ZY
        {
            get { return this.zy; }
        }

        public long Iteration
        {
            get { return this.iteration; }
        }

        public bool InSet
        {
            get { return this.inSet; }
        }

        public HowFound Found
        {
            get { return this.found; }
        }
    }

    public enum HowFound { Max, Period, Cardioid, Bulb, Not }

    class MandelbrotProcess
    {
        private long maxIteration;
        private double bailout;

        public MandelbrotProcess(long maxIteration, double bailout)
        {
            this.maxIteration = maxIteration;
            this.bailout = bailout;
        }

        public MandelbrotData Process(MandelbrotData data)
        {
            double zx;
            double zy;
            double xx;
            double yy;

            double px = data.PX;
            double py = data.PY;
            yy = py * py;

            #region Cardioid check

            //Cardioid
            double temp = px - 0.25;
            double q = temp * temp + yy;
            double a = q * (q + temp);
            double b = 0.25 * yy;
            if (a < b)
                return new MandelbrotData(px, py, px, py, this.maxIteration, true, HowFound.Cardioid);

            #endregion

            #region Period-2 bulb check

            //Period-2 bulb
            temp = px + 1.0;
            temp = temp * temp + yy;
            if (temp < 0.0625)
                return new MandelbrotData(px, py, px, py, this.maxIteration, true, HowFound.Bulb);

            #endregion

            zx = px;
            zy = py;

            int check = 3;
            int checkCounter = 0;

            int update = 10;
            int updateCounter = 0;

            double hx = 0.0;
            double hy = 0.0;

            for (long i = 1; i <= this.maxIteration; i++)
            {
                //Calculate squares
                xx = zx * zx;
                yy = zy * zy;

                #region Bailout check

                //Check bailout
                if (xx + yy > this.bailout)
                    return new MandelbrotData(px, py, zx, zy, i, false, HowFound.Not);

                #endregion

                //Iterate
                zy = 2.0 * zx * zy + py;
                zx = xx - yy + px;

                #region Periodicity check

                //Check for period
                double xDiff = Math.Abs(zx - hx);
                if (xDiff < this.ZERO)
                {
                    double yDiff = Math.Abs(zy - hy);
                    if (yDiff < this.ZERO)
                        return new MandelbrotData(px, py, zx, zy, i, true, HowFound.Period);
                } //End of on zero tests

                //Update history
                if (check == checkCounter)
                {
                    checkCounter = 0;

                    //Double the value of check
                    if (update == updateCounter)
                    {
                        updateCounter = 0;
                        check *= 2;
                    }
                    updateCounter++;

                    hx = zx;
                    hy = zy;
                } //End of update history
                checkCounter++;

                #endregion
            } //End of iterate for

            #region Max iteration

            return new MandelbrotData(px, py, zx, zy, this.maxIteration, true, HowFound.Max);

            #endregion
        }

        private double ZERO = 1e-17;
    }
}