algorithmfunctiondetectioncyclefloyd-cycle-finding

Cycle Detection Algorithm


Say I have a function f:

f(0) = 0
f(i) = (i - 1) % 4

f(0..12):

0 0 1 2 3 0 1 2 3 0 1 2 3

I want to find the cycle start and the cycle length, which are 1 and 4, respectively. The tortoise and hare algorithm works with iterated functions, but I don't have an iterated function. Are there other algorithms that work with non-iterated functions or can the tortoise and hare algorithm be modified for this?

Edit:

Using Jason S's answer, I managed to come up with this, which seems to be working:

public static Tuple<int, int> ModifiedTortoiseHare(Func<int, int> f, int x0 = 0, int checks = 4)
{
    for (; ; x0++)
    {
        int lam = 0, tortoise, hare;

        do
        {
            lam++;
            tortoise = f(x0 + lam);
            hare = f(x0 + 2 * lam);
        } while (tortoise != hare);

        int mu = -1;

        do
        {
            mu++;
            tortoise = f(x0 + mu);
            hare = f(x0 + mu + lam);
        } while (tortoise != hare);

        if (mu != 0) continue;

        bool correct = true;
        int lamCheckMax = lam * checks;

        for (int x = 0; x < lamCheckMax; x++)
        {
            if (f(x0 + x + mu) != f(x0 + x + mu + lam))
            {
                correct = false;
                if (mu != 0) x0 += mu - 1;
                break;
            }
        }

        if (correct) return Tuple.Create(x0 + mu, lam);
    }
}

Solution

  • If the function is a "black box", and you have the ability to find f(x) for any individual x (whether valid for real numbers or only integers), but you don't know anything else, there is no general way to find a cycle start and length. For example, consider the function

    f(k) = (k - 1) % 4 + g(k)
    g(k) = max(0, k-1000000)
    

    then f(k) looks like it repeats every 4 integers, but then when you get to k = 1000000, then the pattern stops.


    If the function has a finite range, and you can test for all integers, the tortoise/hare algorithm (= Floyd's cycle-finding algorithm) can be used to help.

    Instead of iterating function evaluation, calculate f(k0 + k) and f(k0 + 2*k) until they match, at which point the suspected period is k, and you just need to repeat through all values to verify that the cycle continues.

    Your question appears to be an equivalent problem as "How should I find repeated word sequences?" which has a number of answers.