Short description.
I have a sequence of numbers [0, 1, 4, 0, 0, 1, 1, 2, 3, 7, 0, 0, 1, 1, 2, 3, 7, 0, 0, 1, 1, 2, 3, 7, 0, 0, 1, 1, 2, 3, 7] . As you can see, from the 3rd value, the sequence is periodic with the period [0, 0, 1, 1, 2, 3, 7] .
I am trying to automatically extract this period from this sequence. The problem is that I do not know the length of the period and do not know from what position the sequence becomes periodic.
Full explanation (some math may be required)
I study combinatorial game theory, and the cornerstone of this theory is to calculate the Grundy values ββof a game chart. This leads to an infinite sequence, which in many cases becomes ultimately periodic .
I found a way to efficiently calculate grundy values ββ(it returns me the sequence). I would like to automatically extract the offset and period of this sequence. I know that when you see part of the sequence [1, 2, 3, 1, 2, 3] , you cannot be sure that [1, 2, 3] is a period (who knows, maybe the next number is 4 , which violates the assumption), but I'm not interested in such subtleties (I assume that the sequence is enough to find the real period). Also the problem is that the sequence may stop in the middle of the period: [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, ...] (the period is still 1, 2, 3 ).
I also need to find the smallest offset and period. For example, for the original sequence, the offset can be [0, 1, 4, 0, 0] and the period [1, 1, 2, 3, 7, 0, 0] , but the smallest is [0, 1, 4] and [0, 0, 1, 1, 2, 3, 7] .
My ineffective approach is to try all possible offsets and all possible periods. Build a sequence using this data and check if it matches the original. I did not do any normal analysis, but it looks like it is at least quadratic in terms of time complexity.
Here is my quick python code (did not check it correctly):
def getPeriod(arr): min_offset, min_period, n = len(arr), len(arr), len(arr) best_offset, best_period = [], [] for offset in xrange(n): start = arr[:offset] for period_len in xrange(1, (n - offset) / 2): period = arr[offset: offset+period_len] attempt = (start + period * (n / period_len + 1))[:n] if attempt == arr: if period_len < min_period: best_offset, best_period = start[::], period[::] min_offset, min_period = len(start), period_len elif period_len == min_period and len(start) < min_offset: best_offset, best_period = start[::], period[::] min_offset, min_period = len(start), period_len return best_offset, best_period
Which returns me what I want for my original sequence:
offset [0, 1, 4] period [0, 0, 1, 1, 2, 3, 7]
Is there something more effective?