private double[] getRates(int na, int na2, int nb, int nb2, oState state, int c, double k)
        {
            double[] rates =
            {
                k,                      //pA 0
                k,                      //pB 1
                k *c *na2,              //cA 2
                k *c *nb2,              //cB 3
                0,                      //uC 4
                k *((double)na) * 0.25, //mA 5
                k *((double)nb) * 0.25, //mB 6
                k *(na / 2),            //pA2 7
                k *(nb / 2),            //pB2 8
                k *((double)na2) * 5,   //mA2 9
                k *((double)nb2) * 5,   //mB2 10
                0                       // total rate - calculated later 11
            };
            switch (state)
            {
            case oState.A:
                rates[1] = 0;
                rates[2] = 0;
                rates[3] = 0;
                rates[4] = k;
                break;

            case oState.B:
                rates[0] = 0;
                rates[2] = 0;
                rates[3] = 0;
                rates[4] = k;
                break;
            }
            if (na == 1)
            {
                rates[7] = 0;
            }
            if (nb == 1)
            {
                rates[8] = 0;
            }
            rates[11] = rates.Sum();
            return(rates);
        }
        private void geneticSwitch2(int c, double k, int N, double starttime, bool detailedpath, bool verydetail)
        {
            rwplot = rwplot ?? new RandomWalkPlot(window.Plot1, "Kinetic Monte Carlo", "Genetic switch k=" + k + "; c=" + c + "; " + N + " Steps" + (N > 1 ? "ies" : "y") + "; warmup time = " + starttime);
            int    nA = 0, nB = 0, nA2 = 0, nB2 = 0;
            bool   logging = false;
            double time    = 0;
            oState state   = oState.e;

            rwplot.SetAxisTitles("λ", "p(λ)");

            int[] lambda = new int[N];
            int   s      = 0;

            while (s < N)
            {
                var    rates    = getRates(nA, nA2, nB, nB2, state, c, k);
                double rand     = rng.NextDouble() * rates[11];
                int    actindex = 0;
                double comp     = rates[0];
                while (rand > comp)
                {
                    actindex++;
                    comp += rates[actindex];
                }
                double dt = expverteilung(rates[11]);

                oAction todo = actions[actindex];
                if (state == oState.e && todo == oAction.uC)
                {
                    Console.WriteLine("LOLWTF");
                }
                if (state == oState.A && todo == oAction.pB)
                {
                    Console.WriteLine("LOLWTF");
                }
                if (state == oState.B && todo == oAction.pA)
                {
                    Console.WriteLine("LOLWTF");
                }
                if (state != oState.e && (todo == oAction.cB || todo == oAction.cA))
                {
                    Console.WriteLine("LOLWTF");
                }
                if (nA == 0 && (todo == oAction.mA || todo == oAction.pA2))
                {
                    Console.WriteLine("LOLWTF");
                }
                if (nB == 0 && (todo == oAction.mB || todo == oAction.pB2))
                {
                    Console.WriteLine("LOLWTF");
                }
                if (nA2 == 0 && (todo == oAction.mA2 || todo == oAction.cA))
                {
                    Console.WriteLine("LOLWTF");
                }
                if (nB2 == 0 && (todo == oAction.mB2 || todo == oAction.cB))
                {
                    Console.WriteLine("LOLWTF");
                }

                time += dt;
                switch (actions[actindex])
                {
                case oAction.pA: nA++; break;

                case oAction.pB: nB++; break;

                case oAction.cA: state = oState.A; nA2 -= 1; break;

                case oAction.cB: state = oState.B; nB2 -= 1; break;

                case oAction.uC:
                    if (state == oState.A)
                    {
                        nA2 += 1;
                    }
                    else
                    {
                        nB2 += 1;
                    }
                    state = oState.e;
                    break;

                case oAction.mA: nA--; break;

                case oAction.mB: nB--; break;

                case oAction.pA2: nA2++; nA -= 2; break;

                case oAction.pB2: nB2++; nB -= 2; break;

                case oAction.mA2: nA2--; nA += 2; break;

                case oAction.mB2: nB2--; nB += 2; break;
                }
                if (!logging && time > starttime)
                {
                    logging = true;
                }
                if (logging)
                {
                    lambda[s++] = (nA + 2 * nA2) - (nB + 2 * nB2);
                }
                if (s % 1000000 == 0)
                {
                    Console.WriteLine(s * 0.000001);
                }
                if (nA < 0 || nB < 0)
                {
                    Console.WriteLine("LOLWTF");
                }
            }
            LineSeries pLambda = rwplot.AddLineM("λ, c = " + c, OxyColors.Automatic);

            Array.Sort(lambda);
            for (int i = 0; i < N - 2;)
            {
                int j = 0;
                while (i + j + 1 < N && lambda[i] == lambda[i + j + 1])
                {
                    j++;
                }
                double n = j;
                pLambda.Points.Add(new DataPoint(lambda[i], n / N));
                i = i + j + 1;
            }
        }
        private void geneticSwitch(int c, double k, int N, double endtime, bool detailedpath, bool verydetail)
        {
            rwplot = rwplot ?? new RandomWalkPlot(window.Plot1, "Kinetic Monte Carlo", "Genetic switch k=" + k + "; c=" + c + "; " + N + " trajector" + (N > 1 ? "ies" : "y") + "; maxTime = " + endtime);
            int[]  nA   = new int[N], nB = new int[N], nA2 = new int[N], nB2 = new int[N];
            bool[] cont = Enumerable.Repeat <bool>(true, N).ToArray();
            var    time = new double[N];

            oState[] state = new oState[N];
            rwplot.SetAxisTitles("λ", "p(λ)");


            LineSeries pnA  = null;
            LineSeries pnB  = null;
            LineSeries pnA2 = null;
            LineSeries pnB2 = null;
            LineSeries pL   = null;

            if (detailedpath)
            {
                rwplot.SetAxisTitles("Time", "Amount");
                if (verydetail)
                {
                    pnA  = rwplot.AddLineM("A, c = " + c, OxyColors.Automatic);
                    pnB  = rwplot.AddLineM("B, c = " + c, OxyColors.Automatic);
                    pnA2 = rwplot.AddLineM("A2, c = " + c, OxyColors.Automatic);
                    pnB2 = rwplot.AddLineM("B2, c = " + c, OxyColors.Automatic);
                }
                else
                {
                    pL = rwplot.AddLineM("λ, c = " + c, OxyColors.Automatic);
                }
            }
            double[] lambda   = new double[N];
            int      finished = 0;

            while (finished != N)
            {
                for (int s = 0; s < N; s++)
                {
                    if (cont[s])
                    {
                        var    rates    = getRates(nA[s], nA2[s], nB[s], nB2[s], state[s], c, k);
                        double rand     = rng.NextDouble() * rates[11];
                        int    actindex = 0;
                        double comp     = rates[0];
                        while (rand > comp)
                        {
                            actindex++;
                            comp += rates[actindex];
                        }
                        double dt = expverteilung(rates[11]);

                        oAction todo = actions[actindex];
                        if (state[s] == oState.e && todo == oAction.uC)
                        {
                            Console.WriteLine("LOLWTF");
                        }
                        if (state[s] == oState.A && todo == oAction.pB)
                        {
                            Console.WriteLine("LOLWTF");
                        }
                        if (state[s] == oState.B && todo == oAction.pA)
                        {
                            Console.WriteLine("LOLWTF");
                        }
                        if (state[s] != oState.e && (todo == oAction.cB || todo == oAction.cA))
                        {
                            Console.WriteLine("LOLWTF");
                        }
                        if (nA[s] == 0 && (todo == oAction.mA || todo == oAction.pA2))
                        {
                            Console.WriteLine("LOLWTF");
                        }
                        if (nB[s] == 0 && (todo == oAction.mB || todo == oAction.pB2))
                        {
                            Console.WriteLine("LOLWTF");
                        }
                        if (nA2[s] == 0 && (todo == oAction.mA2 || todo == oAction.cA))
                        {
                            Console.WriteLine("LOLWTF");
                        }
                        if (nB2[s] == 0 && (todo == oAction.mB2 || todo == oAction.cB))
                        {
                            Console.WriteLine("LOLWTF");
                        }

                        time[s] += dt;
                        if (time[s] > endtime && cont[s])
                        {
                            cont[s] = false;
                            finished++;
                            continue;
                        }
                        switch (actions[actindex])
                        {
                        case oAction.pA: nA[s]++; break;

                        case oAction.pB: nB[s]++; break;

                        case oAction.cA: state[s] = oState.A; nA2[s] -= 1; break;

                        case oAction.cB: state[s] = oState.B; nB2[s] -= 1; break;

                        case oAction.uC:
                            if (state[s] == oState.A)
                            {
                                nA2[s] += 1;
                            }
                            else
                            {
                                nB2[s] += 1;
                            }
                            state[s] = oState.e;
                            break;

                        case oAction.mA: nA[s]--; break;

                        case oAction.mB: nB[s]--; break;

                        case oAction.pA2: nA2[s]++; nA[s] -= 2; break;

                        case oAction.pB2: nB2[s]++; nB[s] -= 2; break;

                        case oAction.mA2: nA2[s]--; nA[s] += 2; break;

                        case oAction.mB2: nB2[s]--; nB[s] += 2; break;
                        }
                        lambda[s] = (nA[s] + 2 * nA2[s]) - (nB[s] + 2 * nB2[s]);
                        if (detailedpath)
                        {
                            if (verydetail)
                            {
                                pnA.Points.Add(new DataPoint(time[s], nA[s]));
                                pnB.Points.Add(new DataPoint(time[s], nB[s]));
                                pnA2.Points.Add(new DataPoint(time[s], nA2[s]));
                                pnB2.Points.Add(new DataPoint(time[s], nB2[s]));
                            }
                            else
                            {
                                pL.Points.Add(new DataPoint(time[s], lambda[s]));
                            }
                        }
                        if (nA[s] < 0 || nB[s] < 0)
                        {
                            Console.WriteLine("LOLWTF");
                        }
                    }
                }
            }
            if (!detailedpath)
            {
                LineSeries pLambda = rwplot.AddLineM("λ, c = " + c, OxyColors.Automatic);
                double     lp      = lambda.Max();
                double     lm      = lambda.Min();
                int        classes = 50;
                double     di      = 2 * lp / classes;
                di = 1;
                for (double i = lm; i < lp; i += di)
                {
                    double n = 0;
                    foreach (var y in lambda)
                    {
                        if (i == y)
                        {
                            n++;
                        }
                    }
                    pLambda.Points.Add(new DataPoint(i, n / N));
                }
            }
        }