Advertisement
Guest User

Untitled

a guest
Jan 17th, 2017
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.88 KB | None | 0 0
  1. import numpy as np
  2. from PIL import Image, ImageDraw, ImageOps
  3. import random
  4. import operator
  5.  
  6. #etat initial test, sinon importer d'un fichier
  7. map_size = [512, 512]
  8.  
  9. n_walls = 5
  10. walls = []
  11. walls.append(((0, 0), (0, 511)))
  12. walls.append(((0, 511), (511, 511)))
  13. walls.append(((511, 511), (511, 0)))
  14. walls.append(((511, 0), (0, 0)))
  15.  
  16. walls.append(((0, 425), (140, 390)))
  17. walls.append(((140, 390), (140, 125)))
  18. walls.append(((140, 390), (315, 420)))
  19. walls.append(((0, 320), (50, 280)))
  20. walls.append(((140, 200), (360, 115)))
  21. walls.append(((300, 220), (511, 140)))
  22. walls.append(((185, 0), (260, 50)))
  23.  
  24. goal = (130, 440)
  25. #robot = [(50, 50), (80, 80), (80, 45), (100, 70)] #test trajectoire
  26. #i_robot = len(robot)-1 #indice de la position actuelle
  27. robot = [(50, 50)] #trajectoire du robot
  28. candidates = []
  29. """TODO: lecture de la mape, positions robot et but d'un fichier"""
  30. """TODO: sortie des methodes: nombre d'iterations, convergence"""
  31.  
  32. #---------------------------------------------------------------------------------------------------------
  33. #fonctions de calcul
  34.  
  35. def perp(a):
  36. b = np.empty_like(a)
  37. b[0] = - a[1]
  38. b[1] = a[0]
  39. return b
  40.  
  41. #donne le point d'intersection de deux segments ou False si ils ne se coupent pas
  42. def seg_intersect(c1, c2, d1, d2):
  43. a1 = np.array([float(c1[0]), float(c1[1])])
  44. a2 = np.array([float(c2[0]), float(c2[1])])
  45. b1 = np.array([float(d1[0]), float(d1[1])])
  46. b2 = np.array([float(d2[0]), float(d2[1])])
  47. da = a2 - a1
  48. db = b2 - b1
  49. dp = a1 - b1
  50. dap = perp(da)
  51. denom = np.dot(dap, db)
  52. if denom == 0:
  53. return False
  54. num = np.dot(dap, dp)
  55. p = (num / denom.astype(float)) * db + b1
  56. intersection = (int(round(p[0])), int(round(p[1])))
  57. if c1[0] < c2[0]:
  58. if intersection[0] < c1[0] or intersection[0] > c2[0]:
  59. return False
  60. elif c1[0] > c2[0]:
  61. if intersection[0] < c2[0] or intersection[0] > c1[0]:
  62. return False
  63. if d1[0] < d2[0]:
  64. if intersection[0] < d1[0] or intersection[0] > d2[0]:
  65. return False
  66. elif d1[0] > d2[0]:
  67. if intersection[0] < d2[0] or intersection[0] > d1[0]:
  68. return False
  69. if c1[1] < c2[1]:
  70. if intersection[1] < c1[1] or intersection[1] > c2[1]:
  71. return False
  72. elif c1[1] > c2[1]:
  73. if intersection[1] < c2[1] or intersection[1] > c1[1]:
  74. return False
  75. if d1[1] < d2[1]:
  76. if intersection[1] < d1[1] or intersection[1] > d2[1]:
  77. return False
  78. elif d1[1] > d2[1]:
  79. if intersection[1] < d2[1] or intersection[1] > d1[1]:
  80. return False
  81. return intersection
  82.  
  83. #calcule la distance euclidienne entre deux points
  84. def dist_eucl(a, b):
  85. return np.linalg.norm(np.array(a) - np.array(b))
  86.  
  87. #verifie si le but est atteint
  88. def goal_reached():
  89. i_robot = len(robot)-1
  90. if dist_eucl(robot[i_robot], goal) <= 10:
  91. print 'but atteint'
  92. return True
  93. goal_seg0 = ((goal[0] - 5, goal[1] - 5), (goal[0] + 5, goal[1] + 5))
  94. goal_seg1 = ((goal[0] - 5, goal[1] + 5), (goal[0] + 5, goal[1] - 5))
  95. if i_robot > 1:
  96. for i in range(i_robot):
  97. if (seg_intersect(robot[i], robot[i+1], goal_seg0[0], goal_seg0[1]) != False or seg_intersect(robot[i], robot[i+1], goal_seg1[0], goal_seg1[1]) != False):
  98. print 'but atteint'
  99. return True
  100. return False
  101.  
  102. #---------------------------------------------------------------------------------------------------------
  103. #generation de candidats
  104.  
  105. #verifie qu'il n'y ait pas de mur entre le robot et une position candidate
  106. def viable_candidate(p, i_robot):
  107. for w in walls[4:]:
  108. intersect_wall = seg_intersect(robot[i_robot], p, w[0], w[1])
  109. if intersect_wall != False:
  110. return False
  111. return True
  112.  
  113. #genere des positions candidates pour cette iteration, c-a-d des positions qui peuvent etre atteintes (a partir de la position actuelle du robot) en ligne droite sans passer par un mur
  114. def generate_candidates(n_candidates):
  115. i_robot = len(robot)-1
  116. candidates = []
  117. candidates.append(robot[i_robot])
  118. for i in range(1, n_candidates):
  119. p_viable = False
  120. while p_viable == False:
  121. p = (random.randint(1, map_size[0]-1), random.randint(1, map_size[1]-1))
  122. p_viable = viable_candidate(p, i_robot) and p not in candidates
  123. candidates.append(p)
  124. return candidates
  125. """TODO: faire la generation de maniere plus intelligente qu'avec les random"""
  126.  
  127. #---------------------------------------------------------------------------------------------------------
  128. #fitness
  129.  
  130. #calcule la fitness des positions candidats
  131. def calculate_fitness(candidates):
  132. fitness = []
  133. for c in candidates:
  134. fitness.append(- dist_eucl(c, goal))
  135. return fitness
  136.  
  137. #methode fitness; nombre d'iterations limite car la methode risque de ne pas converger (c'est le cas adns l'exemple de l'article)
  138. def fitness_search(n_candidates, max_iter):
  139. iter_count = 0
  140. while not goal_reached():
  141. candidates = generate_candidates(n_candidates)
  142. fitness = calculate_fitness(candidates)
  143. i_fit_max, fit_max = max(enumerate(fitness), key = operator.itemgetter(1))
  144. robot.append(candidates[i_fit_max])
  145. iter_count += 1
  146. if iter_count >= max_iter:
  147. print 'fitness search n\'a pas converge en ' + str(max_iter) + ' iterations'
  148. return iter_count
  149. print iter_count, fitness
  150.  
  151. #---------------------------------------------------------------------------------------------------------
  152. #novelty
  153.  
  154. #calcule la nouveaute d'une position
  155. def calculate_novelty(p, archive, population, k):
  156. n = len(archive) + len(population)
  157. if k > n:
  158. k = n
  159. distances = []
  160. for a in archive:
  161. distances.append(dist_eucl(p, a))
  162. for ind in population:
  163. distances.append(dist_eucl(p, ind))
  164. distances.sort()
  165. nov = 1.0 / k * sum([distances[i] for i in range(k)])
  166. return nov
  167.  
  168. #methode novelty
  169. def novelty_search(n_candidates, k, min_nov, max_iter):
  170. archive = []
  171. iter_count = 0
  172. iter_no_add_count = 0
  173. while not goal_reached() and iter_count < max_iter:
  174. if iter_no_add_count > 2500:
  175. min_nov *= 0.95
  176. iter_count += 1
  177. iter_no_add_count += 1
  178. add_count = 0
  179. population = generate_candidates(n_candidates)
  180. novelties = []
  181. for i in range(n_candidates):
  182. novelties.append(calculate_novelty(population[i], archive, population, k))
  183. if novelties[i] >= min_nov:
  184. archive.append(population[i])
  185. add_count += 1
  186. iter_no_add_count = 0
  187. if add_count > 4:
  188. min_nov *= 1.05
  189. i_nov_max, nov_max = max(enumerate(novelties), key = operator.itemgetter(1))
  190. robot.append(population[i_nov_max])
  191. print iter_count
  192. return iter_count
  193.  
  194. #methode novelty sans archive
  195. def novelty_search_no_archive(n_candidates, k, min_nov, max_iter):
  196. iter_count = 0
  197. iter_no_add_count = 0
  198. while not goal_reached() and iter_count < max_iter:
  199. if iter_no_add_count > 2500:
  200. min_nov *= 0.95
  201. iter_count += 1
  202. iter_no_add_count += 1
  203. add_count = 0
  204. population = generate_candidates(n_candidates)
  205. novelties = []
  206. for i in range(n_candidates):
  207. novelties.append(calculate_novelty(population[i], [], population, k))
  208. if novelties[i] >= min_nov:
  209. add_count += 1
  210. iter_no_add_count = 0
  211. if add_count > 4:
  212. min_nov *= 1.05
  213. i_nov_max, nov_max = max(enumerate(novelties), key = operator.itemgetter(1))
  214. robot.append(population[i_nov_max])
  215. print iter_count
  216. return iter_count
  217.  
  218. #methode novelty avec uniquement l'archive
  219. def novelty_search_archive_only(n_candidates, k, min_nov, max_iter):
  220. archive = robot
  221. iter_count = 0
  222. iter_no_add_count = 0
  223. while not goal_reached() and iter_count < max_iter:
  224. if iter_no_add_count > 2500:
  225. min_nov *= 0.95
  226. iter_count += 1
  227. iter_no_add_count += 1
  228. add_count = 0
  229. population = generate_candidates(n_candidates)
  230. novelties = []
  231. for i in range(n_candidates):
  232. novelties.append(calculate_novelty(population[i], archive, [], k))
  233. if novelties[i] >= min_nov:
  234. archive.append(population[i])
  235. add_count += 1
  236. iter_no_add_count = 0
  237. if add_count > 4:
  238. min_nov *= 1.05
  239. i_nov_max, nov_max = max(enumerate(novelties), key = operator.itemgetter(1))
  240. robot.append(population[i_nov_max])
  241. print iter_count
  242. return iter_count
  243.  
  244. #---------------------------------------------------------------------------------------------------------
  245. #MOEA
  246.  
  247. #construction du front de pareto en fonction des fitness et nouveaute de la population
  248. def convert_to_pareto_front(pop_fit_nov):
  249. n = len(pop_fit_nov[0])
  250. i = 0
  251. while i < n-1:
  252. j = i + 1
  253. while j < n:
  254. #print i, j, n
  255. if pop_fit_nov[1][i] >= pop_fit_nov[1][j] and pop_fit_nov[2][i] >= pop_fit_nov[2][j]:
  256. del pop_fit_nov[0][j]
  257. del pop_fit_nov[1][j]
  258. del pop_fit_nov[2][j]
  259. n = len(pop_fit_nov[0])
  260. elif pop_fit_nov[1][i] <= pop_fit_nov[1][j] and pop_fit_nov[2][i] <= pop_fit_nov[2][j]:
  261. del pop_fit_nov[0][i]
  262. del pop_fit_nov[1][i]
  263. del pop_fit_nov[2][i]
  264. n = len(pop_fit_nov[0])
  265. j += 1
  266. i += 1
  267. return pop_fit_nov
  268.  
  269. #calcul de score sur les deux objectifs (fitness et nouveaute) en ponderant le rapport de chacun sur sa moyenne par un poids donne
  270. def calculate_mo_score(pop_fit_nov, weight_obj0):
  271. weight_obj1 = 1 - weight_obj0
  272. n = len(pop_fit_nov[0])
  273. mo_scores = []
  274. mean_fit = 1.0 / n * sum(pop_fit_nov[1])
  275. mean_nov = 1.0 / n * sum(pop_fit_nov[2])
  276. for i in range(n):
  277. mo_scores.append(weight_obj0 * pop_fit_nov[1][i] / mean_fit + weight_obj1 * pop_fit_nov[2][i] / mean_nov)
  278. return mo_scores
  279.  
  280. #methode MOEA
  281. def fit_nov_MOEA(n_candidates, k, min_nov, max_iter, weight_obj0):
  282. archive = []
  283. iter_count = 0
  284. iter_no_add_count = 0
  285. while not goal_reached() and iter_count < max_iter:
  286. if iter_no_add_count > 2500:
  287. min_nov *= 0.95
  288. iter_count += 1
  289. iter_no_add_count += 1
  290. add_count = 0
  291. pop_fit_nov = [[], [], []]
  292. pop_fit_nov[0] = generate_candidates(n_candidates)
  293. pop_fit_nov[1] = calculate_fitness(pop_fit_nov[0])
  294. pop_fit_nov[2] = []
  295. for i in range(n_candidates):
  296. pop_fit_nov[2].append(calculate_novelty(pop_fit_nov[0][i], archive, pop_fit_nov[0], k))
  297. if pop_fit_nov[2][i] >= min_nov:
  298. archive.append(pop_fit_nov[0][i])
  299. add_count += 1
  300. iter_no_add_count = 0
  301. if add_count > 4:
  302. min_nov *= 1.05
  303. #for i in range(len(pop_fit_nov[0])):
  304. # print (pop_fit_nov[0][i], pop_fit_nov[1][i], pop_fit_nov[2][i])
  305. pop_fit_nov = convert_to_pareto_front(pop_fit_nov)
  306. mo_scores = calculate_mo_score(pop_fit_nov, weight_obj0)
  307. i_score_max, score_max = max(enumerate(mo_scores), key = operator.itemgetter(1))
  308. robot.append(pop_fit_nov[0][i_score_max])
  309. print iter_count
  310. return iter_count
  311.  
  312.  
  313. #---------------------------------------------------------------------------------------------------------
  314. #tests
  315.  
  316. random.seed()
  317. n_candidates = 100
  318. #iter_count, fitness = fitness_search(n_candidates, 50)
  319. #iter_count = novelty_search(n_candidates, 5, 5, 50)
  320. #iter_count = novelty_search_no_archive(n_candidates, 5, 5, 50)
  321. #iter_count = novelty_search_archive_only(n_candidates, 5, 5, 50)
  322. iter_count = fit_nov_MOEA(n_candidates, 5, 5, 500, 0.75)
  323. #candidates = generate_candidates(n_candidates)
  324. #print robot
  325.  
  326. #---------------------------------------------------------------------------------------------------------
  327. #representation graphique
  328.  
  329. i_robot = len(robot)-1
  330. im = Image.open('blank.png')
  331. draw = ImageDraw.Draw(im)
  332.  
  333. for w in walls:
  334. draw.line(w, fill = 'black', width = 3)
  335. draw.ellipse(((goal[0]-9, goal[1]-9), (goal[0]+9, goal[1]+9)), fill = 'black', outline = 'black') #but
  336. for c in candidates:
  337. draw.ellipse(((c[0]-3, c[1]-3), (c[0]+3, c[1]+3)), fill = 'lightgray', outline = 'gray') #candidats
  338. for i in range(len(robot)-1):
  339. draw.line((robot[i], robot[i+1]), fill = 'red') #trajectoire
  340. draw.ellipse(((robot[0][0]-6, robot[0][1]-6), (robot[0][0]+6, robot[0][1]+6)), fill = 'white', outline = 'red') #position initiale du robot (debut de la trajectoire)
  341. draw.ellipse(((robot[i_robot][0]-6, robot[i_robot][1]-6), (robot[i_robot][0]+6, robot[i_robot][1]+6)), fill = 'red', outline = 'black') #position actualle du robot (fin de la trajectoire)
  342.  
  343. del draw
  344. im = ImageOps.flip(im)
  345. im.save('test.png', 'PNG')
  346. im.show()
  347. #---------------------------------------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement