main.py 8.3 KB

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