How to resolve the algorithm Recaman's sequence step by step in the Python programming language
How to resolve the algorithm Recaman's sequence step by step in the Python programming language
Table of Contents
Problem Statement
The Recamán's sequence generates Natural numbers. Starting from a(0)=0, the n'th term a(n), where n>0, is the previous term minus n i.e a(n) = a(n-1) - n but only if this is both positive and has not been previousely generated. If the conditions don't hold then a(n) = a(n-1) + n.
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Recaman's sequence step by step in the Python programming language
1. Recamán's Sequence Class (Recamans
):
- This class represents a generator for Recamán's sequence and keeps track of the sequence's history (
a
andn
) as it generates terms.
2. Generator (Recamans.__call__
):
- It yields the next term in Recamán's sequence.
- It initializes with
0
, stores the sequence ina
(set), and incrementsn
(term count). - It calculates the next term (
nxt
) based on the current term (an1
) andn
. - If
nxt
is negative or already ina
, it calculates a newnxt
. - It adds
nxt
toa
and returns it.
3. Main Execution (if __name__ == '__main__'
):
-
Creating a Recamán's sequence object:
recamans = Recamans()
creates an instance that generates Recamán's sequence.
-
Printing the first 15 terms:
print("First fifteen members of Recamans sequence:", list(islice(recamans(), 15)))
prints the first 15 terms using theislice
function.
-
Finding the first duplicate term:
- An empty set
so_far
is used to track seen terms. - The generator is iterated over until a term (
term
) seen inso_far
is found. print(f"First duplicate number in series is: a({recamans.n}) = {term}")
prints the first duplicate term and its positiona(n)
.
- An empty set
-
Checking if a specified range is covered:
- A set of integers
setn
is created for the range0 .. n
. - The generator is iterated over until the set
setn
is a subset of the sequence setrecamans.a
. print(f"Range 0 ..{n} is covered by terms up to a({recamans.n})")
prints the number of terms needed to cover the range.
- A set of integers
4. Recaman's Sequence as a Function (recamanUntil
):
recamanUntil
is a function that takes a predicatep
and returns the terms of the Recamán sequence until the predicate holds.
5. Recaman's Sequence Successor (recamanSucc
):
recamanSucc
calculates the successor term in Recamán's sequence based on the previous termr
, the current term countn
, and the set of seen termsseen
.
6. Test Cases (main
Function):
- Prints the first 15 Recaman terms.
- Finds the first duplicated Recaman term.
- Calculates the number of Recaman terms needed to generate all integers within a given range
0 .. 1000
.
7. Generic Functions:
enumFromTo
: Generates a range of integers fromm
ton
.iterate
: Iterates a functionf
over a valuex
.snd
: Gets the second component of a tuple.take
: Gets the firstn
elements from a list or iterator.until
: Applies a functionf
until a predicatep
holds, returning the final result.
8. Iterative Recamán's Sequence (main
Function):
- Creates an infinite iterator for Recamán's sequence as tuples
(n, r, blnNew)
. - Uses the
recamanTupleSucc
function to calculate the next tuple. - Prints the first 15 Recaman terms, the first duplicate term, and the number of terms needed to cover the range
0 .. 1000
.
Source code in the python programming language
from itertools import islice
class Recamans():
"Recamán's sequence generator callable class"
def __init__(self):
self.a = None # Set of results so far
self.n = None # n'th term (counting from zero)
def __call__(self):
"Recamán's sequence generator"
nxt = 0
a, n = {nxt}, 0
self.a = a
self.n = n
yield nxt
while True:
an1, n = nxt, n + 1
nxt = an1 - n
if nxt < 0 or nxt in a:
nxt = an1 + n
a.add(nxt)
self.n = n
yield nxt
if __name__ == '__main__':
recamans = Recamans()
print("First fifteen members of Recamans sequence:",
list(islice(recamans(), 15)))
so_far = set()
for term in recamans():
if term in so_far:
print(f"First duplicate number in series is: a({recamans.n}) = {term}")
break
so_far.add(term)
n = 1_000
setn = set(range(n + 1)) # The target set of numbers to be covered
for _ in recamans():
if setn.issubset(recamans.a):
print(f"Range 0 ..{n} is covered by terms up to a({recamans.n})")
break
'''Recaman sequence'''
# recamanUntil :: (Int -> Set Int > [Int] -> Bool) -> [Int]
def recamanUntil(p):
'''All terms of the Recaman series before the
first term for which the predicate p holds.'''
n = 1
r = 0 # First term of series
rs = [r]
seen = set(rs)
blnNew = True
while not p(seen, n, r, blnNew):
r = recamanSucc(seen, n, r)
blnNew = r not in seen
seen.add(r)
rs.append(r)
n = 1 + n
return rs
# recamanSucc :: Set Int -> Int -> Int
def recamanSucc(seen, n, r):
'''The successor for a given Recaman term,
given the set of Recaman terms seen so far.'''
back = r - n
return n + r if 0 > back or (back in seen) else back
# ------------------------- TEST -------------------------
# main :: IO ()
def main():
'''Test'''
print(
'First 15 Recaman:\r',
recamanUntil(
lambda seen, n, r, _: 15 == n
)
)
print(
'First duplicated Recaman:\r',
recamanUntil(
lambda seen, n, r, blnNew: not blnNew
)[-1]
)
setK = set(enumFromTo(0)(1000))
print(
'Number of Recaman terms needed to generate',
'all integers from [0..1000]:\r',
len(recamanUntil(
lambda seen, n, r, blnNew: (
blnNew and 1001 > r and setK.issubset(seen)
)
)) - 1
)
# ----------------------- GENERIC ------------------------
# enumFromTo :: (Int, Int) -> [Int]
def enumFromTo(m):
'''Integer enumeration from m to n.'''
return lambda n: range(m, 1 + n)
if __name__ == '__main__':
main()
'''Recaman by iteration of a function over a tuple.'''
from itertools import (islice)
# recamanTupleSucc :: Set Int -> (Int, Int, Bool) -> (Int, Int, Bool)
def recamanTupleSucc(seen):
'''The Nth in a series of Recaman tuples,
(N, previous term, boolPreviouslySeen?)
given the set of all terms seen so far.'''
def go(n, r, _):
back = r - n
nxt = n + r if 0 > back or (back in seen) else back
bln = nxt in seen
seen.add(nxt)
return (1 + n, nxt, bln)
return lambda tpl: go(*tpl)
# ------------------------- TEST -------------------------
# main :: IO()
def main():
'''First 15, and first duplicated Recaman.'''
f = recamanTupleSucc(set([0]))
print(
'First 15 Recaman:\n',
list(map(
snd,
take(15)(iterate(f)((1, 0, False)))
))
)
f = recamanTupleSucc(set([0]))
print(
'First duplicated Recaman:\n',
until(lambda x: x[2])(f)(
(1, 0, False)
)[1]
)
sk = set(enumFromTo(0)(1000))
sr = set([0])
f = recamanTupleSucc(sr)
print(
'Number of Recaman terms needed to generate',
'all integers from [0..1000]:\n',
until(
lambda x: not x[2] and 1001 > x[1] and sk.issubset(sr)
)(f)(
(1, 0, False)
)[0] - 1
)
# ----------------- GENERIC ABSTRACTIONS -----------------
# enumFromTo :: (Int, Int) -> [Int]
def enumFromTo(m):
'''Integer enumeration from m to n.'''
return lambda n: range(m, 1 + n)
# iterate :: (a -> a) -> a -> Gen [a]
def iterate(f):
'''An infinite list of repeated
applications of f to x.
'''
def go(x):
v = x
while True:
yield v
v = f(v)
return go
# snd :: (a, b) -> b
def snd(tpl):
'''Second component of a tuple.'''
return tpl[1]
# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
'''The prefix of xs of length n,
or xs itself if n > length xs.'''
return lambda xs: (
xs[0:n]
if isinstance(xs, list)
else islice(xs, n)
)
# until :: (a -> Bool) -> (a -> a) -> a -> a
def until(p):
'''The result of repeatedly applying f until p holds.
The initial seed value is x.
'''
def go(f):
def g(x):
v = x
while not p(v):
v = f(v)
return v
return g
return go
# MAIN ---
if __name__ == '__main__':
main()
You may also check:How to resolve the algorithm Gotchas step by step in the MIPS Assembly programming language
You may also check:How to resolve the algorithm Inconsummate numbers in base 10 step by step in the APL programming language
You may also check:How to resolve the algorithm Binary search step by step in the Eiffel programming language
You may also check:How to resolve the algorithm Sum and product puzzle step by step in the Ruby programming language
You may also check:How to resolve the algorithm Rosetta Code/Find bare lang tags step by step in the Mathematica/Wolfram Language programming language