1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
|
"""
Digraphs from Integer-valued Iterated Functions
===============================================
Sums of cubes on 3N
-------------------
The number 153 has a curious property.
Let 3N={3,6,9,12,...} be the set of positive multiples of 3. Define an
iterative process f:3N->3N as follows: for a given n, take each digit
of n (in base 10), cube it and then sum the cubes to obtain f(n).
When this process is repeated, the resulting series n, f(n), f(f(n)),...
terminate in 153 after a finite number of iterations (the process ends
because 153 = 1**3 + 5**3 + 3**3).
In the language of discrete dynamical systems, 153 is the global
attractor for the iterated map f restricted to the set 3N.
For example: take the number 108
f(108) = 1**3 + 0**3 + 8**3 = 513
and
f(513) = 5**3 + 1**3 + 3**3 = 153
So, starting at 108 we reach 153 in two iterations,
represented as:
108->513->153
Computing all orbits of 3N up to 10**5 reveals that the attractor
153 is reached in a maximum of 14 iterations. In this code we
show that 13 cycles is the maximum required for all integers (in 3N)
less than 10,000.
The smallest number that requires 13 iterations to reach 153, is 177, i.e.,
177->687->1071->345->216->225->141->66->432->99->1458->702->351->153
The resulting large digraphs are useful for testing network software.
The general problem
-------------------
Given numbers n, a power p and base b, define F(n; p, b) as the sum of
the digits of n (in base b) raised to the power p. The above example
corresponds to f(n)=F(n; 3,10), and below F(n; p, b) is implemented as
the function powersum(n,p,b). The iterative dynamical system defined by
the mapping n:->f(n) above (over 3N) converges to a single fixed point;
153. Applying the map to all positive integers N, leads to a discrete
dynamical process with 5 fixed points: 1, 153, 370, 371, 407. Modulo 3
those numbers are 1, 0, 1, 2, 2. The function f above has the added
property that it maps a multiple of 3 to another multiple of 3; i.e. it
is invariant on the subset 3N.
The squaring of digits (in base 10) result in cycles and the
single fixed point 1. I.e., from a certain point on, the process
starts repeating itself.
keywords: "Recurring Digital Invariant", "Narcissistic Number",
"Happy Number"
The 3n+1 problem
----------------
There is a rich history of mathematical recreations
associated with discrete dynamical systems. The most famous
is the Collatz 3n+1 problem. See the function
collatz_problem_digraph below. The Collatz conjecture
--- that every orbit returrns to the fixed point 1 in finite time
--- is still unproven. Even the great Paul Erdos said "Mathematics
is not yet ready for such problems", and offered $500
for its solution.
keywords: "3n+1", "3x+1", "Collatz problem", "Thwaite's conjecture"
"""
from networkx import *
from math import *
nmax=10000
p=3
mach_eps=0.00000000001
def digitsrep(n,b=10):
"""Return list of digits comprising n represented in base b.
n must be a nonnegative integer"""
# very inefficient if you only work with base 10
dlist=[]
if n<=0:
return [0]
maxpow=int(floor( log(n)/log(b) + mach_eps ))
pow=maxpow
while pow>=0:
x=int(floor(n // b**pow))
dlist.append(x)
n=n-x*b**pow
pow=pow-1
return dlist
def powersum(n,p,b=10):
"""Return sum of digits of n (in base b) raised to the power p."""
dlist=digitsrep(n,b)
sum=0
for k in dlist:
sum+=k**p
return sum
def attractor153_graph(n,p,multiple=3,b=10):
"""Return digraph of iterations of powersum(n,3,10)."""
G=DiGraph()
for k in range(1,n+1):
if k%multiple==0 and k not in G:
k1=k
knext=powersum(k1,p,b)
while k1!=knext:
G.add_edge(k1,knext)
k1=knext
knext=powersum(k1,p,b)
return G
def squaring_cycle_graph_old(n,b=10):
"""Return digraph of iterations of powersum(n,2,10)."""
G=DiGraph()
for k in range(1,n+1):
k1=k
G.add_node(k1) # case k1==knext, at least add node
knext=powersum(k1,2,b)
G.add_edge(k1,knext)
while k1!=knext: # stop if fixed point
k1=knext
knext=powersum(k1,2,b)
G.add_edge(k1,knext)
if G.out_degree(knext) >=1:
# knext has already been iterated in and out
break
return G
def sum_of_digits_graph(nmax,b=10):
def f(n): return powersum(n,1,b)
return discrete_dynamics_digraph(nmax,f)
def squaring_cycle_digraph(nmax,b=10):
def f(n): return powersum(n,2,b)
return discrete_dynamics_digraph(nmax,f)
def cubing_153_digraph(nmax):
def f(n): return powersum(n,3,10)
return discrete_dynamics_digraph(nmax,f)
def discrete_dynamics_digraph(nmax,f,itermax=50000):
G=DiGraph()
for k in range(1,nmax+1):
kold=k
G.add_node(kold)
knew=f(kold)
G.add_edge(kold,knew)
while kold!=knew and kold<<itermax:
# iterate until fixed point reached or itermax is exceeded
kold=knew
knew=f(kold)
G.add_edge(kold,knew)
if G.out_degree(knew) >=1:
# knew has already been iterated in and out
break
return G
def collatz_problem_digraph(nmax):
def f(n):
if n%2==0:
return n // 2
else:
return 3*n+1
return discrete_dynamics_digraph(nmax,f)
def fixed_points(G):
"""Return a list of fixed points for the discrete dynamical
system represented by the digraph G.
"""
return [n for n in G if G.out_degree(n)==0]
if __name__ == "__main__":
nmax=10000
print("Building cubing_153_digraph(%d)"% nmax)
G=cubing_153_digraph(nmax)
print("Resulting digraph has", len(G), "nodes and",
G.size()," edges")
print("Shortest path from 177 to 153 is:")
print(shortest_path(G,177,153))
print("fixed points are %s" % fixed_points(G))
|