main.py 8.4 KB

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