0

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);
    }
}
nhahtdh
  • 55,989
  • 15
  • 126
  • 162
SuprDewd
  • 269
  • 6
  • 12
  • possible duplicate of [How should I find repeated word sequences](http://stackoverflow.com/questions/4413764/how-should-i-find-repeated-word-sequences) – Jason S Jun 18 '11 at 16:43
  • @SuprDewd: are you looking for the cycle which repeats at least twice with the longest length, or the cycle which repeats with the longest total length? (e.g. `01010101010123401234' as shorthand for f(0) = 0, f(1) = 1, f(2) = 0, f(3) = 1, etc., which has 6 cycles of 0 1 with total length 12, and 2 cycles of 0 1 2 3 4 with total length 10) Or something else? – Jason S Jun 18 '11 at 20:50
  • ...or do you know that f(x) always follows some particular form? (e.g. `f(x) = (x-x0) % m` for all x > some x1) – Jason S Jun 18 '11 at 20:52
  • I'm looking for the longest cycle. My code above will return start 0 and length 2, but I'm pretty sure this is hard to avoid. – SuprDewd Jun 18 '11 at 20:57
  • For example the sequence: 123123123123123123...*5 billion times 123*...123456123456123456123456... Sequences like this are very hard to account for. – SuprDewd Jun 18 '11 at 20:59
  • A better algorithm is of course well appreciated. – SuprDewd Jun 18 '11 at 21:37
  • @Jason S: I updated the algorithm to work with sequences like `01010101010123401234'. Now it validates the cycle some specified amount of times towards the end. I'm pretty happy with it now. – SuprDewd Jun 20 '11 at 00:11

2 Answers2

7

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.

Community
  • 1
  • 1
Jason S
  • 184,598
  • 164
  • 608
  • 970
  • But what do you mean by "and you just need to repeat through all values to verify that the cycle continues"? There may be infinitely many values left, and I cannot check them all... – SuprDewd Jun 18 '11 at 22:09
  • 1
    I said "If the function has a finite range" -- you didn't say in your problem statement whether the function was over a finite or infinite range. If finite, check them all. If infinite, you need another criteria for success/failure, because you can't check them all. – Jason S Jun 18 '11 at 23:51
0

for the fn you have given since its dividing by 4 the length is four and since there is no value added to it 0 is actually the start of the cycle and not 1.you can actually observe this if you do implement it using a graph as has been pointed out. Since these are fn values you could use a linked list instead, and on every value the fn returns, add it to the list if its not already there, else u can have a cycle.assuming that there is only 1 cycle..

jemmanuel
  • 466
  • 4
  • 13