main.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-"
  3. """
  4. Collatz - 2017/2020 - by psy (epsylon@riseup.net)
  5. You should have received a copy of the GNU General Public License along
  6. with Collatz; if not, write to the Free Software Foundation, Inc., 51
  7. Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  8. """
  9. import os, sys
  10. import matplotlib.pyplot as plt
  11. from mpl_toolkits.mplot3d import Axes3D
  12. plt.rcParams.update({'figure.max_open_warning': 0})
  13. class Collatz(object):
  14. def __init__(self):
  15. self.m=False
  16. def banner(self):
  17. print(" ____ _ _ _ ")
  18. print(" / ___|___ | | | __ _| |_ ____ ")
  19. print("| | / _ \| | |/ _` | __|_ / ")
  20. print("| |__| (_) | | | (_| | |_ / / ")
  21. print(" \____\___/|_|_|\__,_|\__/___| ")
  22. print(" 'Natural integers always becomes 1?' ")
  23. print("\n", 75*"=")
  24. print(" - RULE 1: if n is 'even' then n = n/2")
  25. print(" - RULE 2: if n is 'odd' then n = 3n+1")
  26. print(75*"=","\n")
  27. def generate_graph(self):
  28. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  29. print("[Info] Generating 'plots' for number:", self.root)
  30. if not os.path.exists("graphs/"):
  31. os.mkdir("graphs/")
  32. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  33. print("\n + Thread(s):", len(self.tree))
  34. print(' - Tree =', self.tree)
  35. plt.figure()
  36. fig = plt.figure(1)
  37. ax = plt.gca(projection="3d")
  38. xs = []
  39. ys = []
  40. zs = []
  41. for t in self.tree:
  42. z = float(t)
  43. y = z
  44. x = y
  45. xs.append(x)
  46. ys.append(y)
  47. zs.append(z)
  48. ax.scatter(xs,ys,zs, c='red',s=100)
  49. ax.plot(xs,ys,zs, color='green')
  50. header = '"Tree" for number '+str(self.root)+' to becomes 1'
  51. plt.title(header)
  52. plt.ylabel('Number(s)')
  53. plt.xlabel('Thread(s)')
  54. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  55. plt.show()
  56. g = "graphs/"+self.root
  57. if not os.path.exists(g):
  58. os.mkdir(g)
  59. f = open(g+"/"+self.root+"-collatz_tree.txt", 'wb')
  60. fig.savefig(g+"/"+self.root+"-collatz_graph.png")
  61. for t in self.tree:
  62. f.write(str(t).encode('utf-8'))
  63. f.close
  64. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  65. print("\n[Info] Generated 'tree' secuence at folder: "+g+"/\n")
  66. else:
  67. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  68. print("\n[Info] You have this 'tree' secuence previously saved. Exiting...\n")
  69. ax.clear()
  70. plt.clf()
  71. def generate_forest(self, rng):
  72. srng = rng.split('-')
  73. try:
  74. x=int(srng[0])
  75. y=int(srng[1])
  76. except:
  77. print("\n[Error] Numbers on range should be integers (ex: 427-8981318). Aborting...\n")
  78. sys.exit(2)
  79. print("[Info] Generating 'forest' for range:", rng, "\n")
  80. if x < y:
  81. for i in range(x,y+1):
  82. n = i
  83. self.root = str(n)
  84. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  85. print("[Info] Generating 'tree' for number:", self.root)
  86. self.generate_tree(n)
  87. else:
  88. for i in range(y,x+1):
  89. n = i
  90. self.root = str(n)
  91. print("[Info] Generating 'tree' for number:", self.root)
  92. self.generate_tree(n)
  93. def generate_tree(self, n):
  94. t=0 # threads counter
  95. o=0 # odds counter
  96. e=0 # evens counter
  97. w=False # warning flag
  98. self.tree = []
  99. while True:
  100. t=t+1
  101. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  102. print("")
  103. try:
  104. if int(n) != 1:
  105. if int(n) <= 0:
  106. self.m=True
  107. print("[Error] First number should be always > 0. Aborting...\n")
  108. sys.exit(2)
  109. else:
  110. self.m=False
  111. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  112. print(" + Thread:", t)
  113. self.tree.append(int(n))
  114. if int(n) & 1:
  115. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  116. print(' - Root =', n, "[odd]")
  117. r=3*int(n)+1
  118. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  119. print(' - New =', r, '[3*'+str(n)+'+1='+str(r)+"]")
  120. o=o+1
  121. else:
  122. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  123. print(' - Root =', n, "[even]")
  124. r=int(n)/2
  125. if int(r) == 1:
  126. w=True
  127. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  128. print(' - New =', r, "["+str(n)+'/2='+str(r)+"]")
  129. e=e+1
  130. n = r
  131. else:
  132. if w is False:
  133. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  134. print(" + Thread:", t)
  135. self.tree.append(int(n))
  136. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  137. print(' - Root =', n, "[odd]")
  138. r=3*int(n)+1
  139. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  140. print(' - New =', r, '[3*'+str(n)+'+1='+str(r)+"]")
  141. o=o+1
  142. w = True
  143. n = r
  144. else:
  145. break
  146. except:
  147. import random # generate pseudo-random number
  148. n=(random.randint(1,9999))
  149. print("[Error] First number should be an integer (ex: "+str(n)+"). Aborting...\n")
  150. m = True
  151. sys.exit(2)
  152. if self.m is False:
  153. print(100*"-")
  154. print("[Info] Number "+self.root+ " takes "+str(int(t)-1)+" threads using "+str(o)+" odds and "+str(e)+" evens to becomes 1")
  155. print(100*"-","\n")
  156. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  157. graph=input("Wanna generate a 'graph'? (Y/n)")
  158. if graph == "n" or graph == "N":
  159. print("")
  160. sys.exit(2)
  161. else:
  162. self.generate_graph()
  163. else:
  164. self.generate_graph()
  165. def run(self, opts=None):
  166. self.banner()
  167. self.mode=input("Set mode: single random (default), manual, learning (S/m/l): ")
  168. print(40*"-")
  169. if self.mode == "m" or self.mode == "M" or self.mode == "Manual" or self.mode == "manual": #mode manual
  170. n=input("Set a number: ")
  171. elif self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn": #mode learning
  172. rng=input("Set range (ex: 1-100 or 345-890 (PRESS ENTER = 1-100) (STOP = CTRL+z): ")
  173. if not rng:
  174. rng="1-100"
  175. else: # mode single random
  176. r=input("Set a max range (ex: 9999999) (PRESS ENTER = 9): ")
  177. if not r:
  178. r=9
  179. import random # generate pseudo-random number
  180. n=(random.randint(1,int(r)))
  181. if not self.mode == "l" or self.mode == "L" or self.mode == "Learn" or self.mode == "learn":
  182. self.root = str(n)
  183. print(" + Generating 'tree' for number:", self.root)
  184. self.generate_tree(n)
  185. else:
  186. print(75*"=")
  187. self.generate_forest(rng)
  188. print("[Info] 'Forest' correctly generated. Exiting...\n")
  189. if __name__ == "__main__":
  190. app = Collatz()
  191. app.run()