fork download
  1. # Utility functions
  2. def intersect(line0, line1)
  3. def aux(line0,line1)
  4. a,b = line0[0]
  5. c,d = line0[1]
  6. e,f = b-d,c-a
  7. p0x,p0y = line1[0][0]-a, line1[0][1]-b
  8. p1x,p1y = line1[1][0]-a, line1[1][1]-b
  9.  
  10. (e*p0x+f*p0y)*(e*p1x+f*p1y) < 0.0
  11. end
  12.  
  13. aux(line0,line1) && aux(line1,line0)
  14. end
  15.  
  16. def i2r_x(i)
  17. @bounds[0][0] + i*@grid_width + @delta
  18. end
  19.  
  20. def i2r_y(i)
  21. @bounds[1][0] + i*@grid_width + @delta
  22. end
  23.  
  24. def grid_to_cartesian(p)
  25. [i2r_x(p[0]), i2r_y(p[1])]
  26. end
  27.  
  28. def reducible?(p0,p1)
  29. line = [grid_to_cartesian(p0), grid_to_cartesian(p1)]
  30. @boards.each do |board|
  31. return false if intersect(line, board)
  32. end
  33.  
  34. true
  35. end
  36.  
  37. def reduce(src)
  38. r = []
  39. loop do
  40. if src.length < 3
  41. r << src[0]
  42. r << src[1]
  43. break
  44. else
  45. if reducible?(src[0],src[2])
  46. src.delete_at(1)
  47. else
  48. r << src.shift
  49. end
  50. end
  51. end
  52.  
  53. r
  54. end
  55.  
  56. def make_taboo(grid_n)
  57. def template(grid_n, type, r)
  58. (grid_n-type).times do |j|
  59. (grid_n-(1-type)).times do |i|
  60. p0,p1 = type == 0 ? [[i,j],[i+1,j]] : [[i,j],[i,j+1]]
  61. line0 = [grid_to_cartesian(p0),grid_to_cartesian(p1)]
  62. @boards.each do |line1|
  63. if intersect(line0, line1)
  64. r[p0] ||= []
  65. r[p1] ||= []
  66. r[p0] << p1
  67. r[p1] << p0
  68. end
  69. end
  70. end
  71. end
  72. end
  73. r = {}
  74. template(grid_n, 0, r)
  75. template(grid_n, 1, r)
  76.  
  77. r
  78. end
  79.  
  80. def make_taboo_fast(grid_n)
  81. def w2g_x(r)
  82. (r - @bounds[0][0] - @delta) / @grid_width
  83. end
  84. def w2g_y(r)
  85. (r - @bounds[1][0] - @delta) / @grid_width
  86. end
  87. def cartesian_to_grid(p0)
  88. [w2g_x(p0[0]), w2g_y(p0[1])]
  89. end
  90. def line_to_coverrange(line)
  91. x0,y0 = cartesian_to_grid(line[0])
  92. x1,y1 = cartesian_to_grid(line[1])
  93. x_min,x_max = [x0,x1].minmax
  94. y_min,y_max = [y0,y1].minmax
  95. [[x_min.floor, x_max.ceil],[y_min.floor, y_max.ceil]]
  96. end
  97. def add(r,p0,p1)
  98. r[p0] ||= []
  99. r[p1] ||= []
  100. r[p0] << p1
  101. r[p1] << p0
  102. end
  103. r = {}
  104. @boards.each do |b|
  105. line = [cartesian_to_grid(b[0]), cartesian_to_grid(b[1])]
  106. x_range,y_range = line_to_coverrange(b)
  107. xd = line[1][0]-line[0][0]
  108. yd = line[1][1]-line[0][1]
  109.  
  110. if xd != 0.0
  111. i = x_range[0] + 1
  112. i = 0 if i < 0
  113. while i < x_range[1]
  114. y_f = yd * (i.to_f-line[0][0]) / xd + line[0][1]
  115. y = y_f.floor
  116. add(r,[i,y],[i,y+1])
  117. i += 1
  118. end
  119. end
  120.  
  121. if yd != 0.0
  122. i = y_range[0] + 1
  123. i = 0 if i < 0
  124. while i < y_range[1]
  125. x_f = xd * (i.to_f-line[0][1]) / yd + line[0][0]
  126. x = x_f.floor
  127. add(r,[x,i],[x+1,i])
  128. i += 1
  129. end
  130. end
  131. end
  132.  
  133. r
  134. end
  135.  
  136. # Search on Grid (Beam Search) Definition
  137. class Search
  138. def initialize(grid_n, taboo, start_pos, target_pos)
  139. @grid_n = grid_n
  140. @taboo = taboo
  141. @start_pos, @target_pos = start_pos, target_pos
  142. @has_answer = false
  143. @answer = nil
  144. end
  145. def h(pos)
  146. # Manhattan distance
  147. (@target_pos[0]-pos[0]).abs+(@target_pos[1]-pos[1]).abs
  148. end
  149. def successors(pos)
  150. r = []
  151. [[1,0],[0,1],[-1,0],[0,-1]].each do |d|
  152. i,j = pos[0]+d[0], pos[1]+d[1]
  153. next unless 0 <= i && i < @grid_n && 0 <= j && j < @grid_n
  154. succ = [i,j]
  155. r << succ unless @taboo[pos] && @taboo[pos].include?(succ)
  156. end
  157.  
  158. r
  159. end
  160. def calc(beamwidth)
  161. states = [@start_pos]
  162. history = {}
  163. tmp = []
  164. loop do
  165. break unless 0 < states.length
  166.  
  167. states.each do |cur_pos|
  168. succs = []
  169. successors(cur_pos).each do |succ|
  170. if succ == @target_pos
  171. result = [@target_pos, cur_pos]
  172. pos = cur_pos
  173. while prev_pos = history[pos]
  174. result << prev_pos
  175. break if prev_pos == @start_pos
  176. pos = prev_pos
  177. end
  178. return [true, result.reverse]
  179. end
  180. unless history[succ]
  181. history[succ] = cur_pos
  182. succs << [h(succ), succ]
  183. end
  184. end
  185. tmp.concat(succs)
  186. end
  187.  
  188. tmp.sort!
  189. states.clear
  190.  
  191. n = [tmp.length, beamwidth].min
  192. n.times do |i|
  193. states << tmp[i][1]
  194. end
  195.  
  196. tmp.clear
  197. end
  198.  
  199. [false, nil]
  200. end
  201. end
  202.  
  203. # Simulated Anealing Definition
  204. class SimulatedAnealing
  205. def initialize(energy_func, neighbour_func, temparature_func, probablity_func)
  206. @energy = energy_func # state -> float(energy)
  207. @neighbour = neighbour_func # state -> state
  208. @temparature = temparature_func # float(progress degree) -> float(temparature)
  209. @probability = probablity_func # float(energy_src) -> float(energy_dst) -> temparature -> float(probablity)
  210. end
  211. def calc(start_state, max_iter, goal_energy)
  212. state = start_state
  213. e = @energy.call(state)
  214. best_state = state
  215. best_e = e
  216. max_iter.times do |iter|
  217. next_state = @neighbour.call(state)
  218. next_e = @energy.call(next_state)
  219. if next_e <= best_e
  220. best_state = next_state
  221. best_e = next_e
  222. if best_e <= goal_energy
  223. return best_state
  224. end
  225. end
  226.  
  227. t = @temparature.call(iter.to_f / max_iter)
  228. prob = @probability.call(e, next_e, t)
  229. if Random.rand <= prob
  230. state = next_state
  231. e = next_e
  232. end
  233. end
  234.  
  235. best_state
  236. end
  237. end
  238.  
  239. # Setting functions
  240. def set_boards(n) # parallel zigzag pattern
  241. dy = (@bounds[1][1] - @bounds[1][0]) / (n+1)
  242.  
  243. n.times do |i|
  244. y0 = @bounds[1][0]
  245. yval = y0+dy*(i+1)
  246. board =
  247. if i%2 == 0
  248. [[0.0, yval], [0.66, yval]]
  249. else
  250. [[0.33, yval], [1.0, yval]]
  251. end
  252. @boards << board
  253. end
  254. end
  255.  
  256. def set_boards2(n) # diagonal zigzag pattern
  257. def add(delta,width,x,y)
  258. p0 = [x*width-delta, y*width+delta]
  259. p1 = [(x+1)*width+delta, (y-1)*width-delta]
  260. @boards << [p0, p1]
  261. end
  262. delta = 0.00001
  263. width = 1.0 / (n-1)
  264.  
  265. (2..(2*(n-2))).each do |k|
  266. iter_num = k < n ? k : (2*(n-1)-k)
  267. pass_index0 = Random.rand(iter_num)
  268. pass_index1 = Random.rand(iter_num)
  269. iter_num.times do |i|
  270. next if i == pass_index0 || i == pass_index1
  271. x,y = k < n ? [i,k-i] : [k-n+1+i,n-1-i]
  272. add(delta,width,x,y)
  273. end
  274. end
  275. end
  276.  
  277. def set_boards3(k)
  278. def add(d,w,sx,sy,x0,y0,x1,y1)
  279. if y0 == y1
  280. #horizontal
  281. x0,x1,y0,y1 = x1,x0,y1,y0 if x1 < x0
  282. else
  283. #vertical
  284. x0,x1,y0,y1 = x1,x0,y1,y0 if y1 < y0
  285. end
  286. p0 = [sx+x0*w-d, sy+y0*w-d]
  287. p1 = [sx+x1*w+d, sy+y1*w+d]
  288. p2 = [sx+x0*w-d, sy+y0*w+d]
  289. p3 = [sx+x1*w+d, sy+y1*w-d]
  290. @boards << [p0, p1]
  291. @boards << [p2, p3]
  292. end
  293. def sub(delta, max_width, sx, sy, n)
  294. width = max_width / (n-1)
  295.  
  296. (n-2).times do |j|
  297. (n-2).times do |i|
  298. dir_i = Random.rand(j == 0 ? 4 : 3)
  299. dx,dy = [[-1,0],[0,1],[1,0],[0,-1]][dir_i]
  300. x0,y0 = i+1,j+1
  301. x1,y1 = x0+dx,y0+dy
  302. add(delta,width,sx,sy,x0,y0,x1,y1)
  303. end
  304. end
  305. end
  306. delta = 0.00001
  307. sub(delta, 1.0, 0.0, 0.0, k)
  308. end
  309.  
  310. # Main functions
  311. def grid_search(grid_n, taboo, beam_width)
  312. n = grid_n
  313. start_pos = [0,0]
  314. end_pos = [n-1,n-1]
  315.  
  316. Search.new(n, taboo, start_pos, end_pos).calc(beam_width)
  317. end
  318.  
  319. def make_sa_params
  320. grid_n = @grid_n
  321. e_func = lambda{|state|
  322. state.length.to_f
  323. }
  324. n_func = lambda{|state|
  325. return state if state.length < 3
  326. i = 1 + Random.rand(state.length-2)
  327. np = state[i]
  328. x,y = np
  329.  
  330. 100.times do
  331. nx,ny = Random.rand(grid_n), Random.rand(grid_n)
  332. if 0 <= nx && nx < grid_n && 0 <= ny && ny < grid_n
  333. tp = [nx,ny]
  334. if reducible?(state[i-1], tp) && reducible?(tp, state[i+1])
  335. np = tp
  336. break
  337. end
  338. end
  339. end
  340.  
  341. new_state = state.dup
  342. new_state[i] = np
  343.  
  344. if 0 <= i-2 && reducible?(new_state[i-2], np)
  345. new_state.delete_at(i-1)
  346. i -= 1
  347. end
  348. if i+2 < new_state.length && reducible?(np, new_state[i+2])
  349. new_state.delete_at(i+1)
  350. end
  351.  
  352. new_state
  353. }
  354. t_func = lambda{|progress|
  355. a = 0.3
  356. Math.exp(progress*Math.log(a))
  357. }
  358. p_func = lambda{|e0,e1,t|
  359. if e0 >= e1
  360. 1.0
  361. else
  362. k = 1.0
  363. Math.exp((e0-e1) / (k*t))
  364. end
  365. }
  366. max_iter = 1000
  367. goal_e = 0.0
  368.  
  369. [e_func, n_func, t_func, p_func, max_iter, goal_e]
  370. end
  371.  
  372. def reduce_by_sa(init_state)
  373. energy,neighbour,temparature,probability,max_iter,goal_e = make_sa_params
  374. sa = SimulatedAnealing.new(energy, neighbour, temparature, probability)
  375.  
  376. sa.calc(init_state, max_iter, goal_e)
  377. end
  378.  
  379. def display_answer(answer)
  380. puts answer.length
  381. puts answer.map{|e| "%.3f %.3f" % e}
  382. end
  383.  
  384. def output_json(seed, prof, boards, intermediate, answer)
  385. require 'json'
  386. puts JSON.pretty_generate({"seed" => seed}.merge(prof.merge({"answer" => answer, "intermediate" => intermediate, "boards" => boards})))
  387. end
  388.  
  389. def prof_exec(result, id_name, &f)
  390. start_time = Time.now
  391. f.call
  392. t = Time.now - start_time
  393. result[id_name] = t
  394. end
  395.  
  396. # Run
  397. @bounds = [[0.0,1.0],[0.0,1.0]]
  398. @boards = []
  399. @delta = 0.0001
  400. @grid_n = 132
  401. @grid_width = (1.0-@delta*2)/(@grid_n-1)
  402.  
  403. seed = Random.rand(1000)
  404. seed = 13
  405. prof = {}
  406. taboo,found,route,reduced,final_state = nil,nil,nil,nil,nil
  407.  
  408. srand(seed)
  409.  
  410. prof_exec(prof, "set_boards") do
  411. set_boards2(6)
  412. set_boards3(31)
  413. end
  414.  
  415. prof_exec(prof, "make_taboo") do
  416. taboo = make_taboo_fast(@grid_n)
  417. end
  418.  
  419. prof_exec(prof, "grid_search") do
  420. found, route = grid_search(@grid_n, taboo, 1000)
  421. end
  422.  
  423. unless found
  424. output_json(seed,prof,@boards,[],[])
  425. exit
  426. end
  427.  
  428. prof_exec(prof, "reduce_greedy") do
  429. reduced = reduce(route)
  430. end
  431.  
  432. prof_exec(prof, "reduce_by_sa") do
  433. final_state = []
  434. final_state = reduce_by_sa(reduced)
  435. end
  436.  
  437. output_json(seed,
  438. prof,
  439. @boards,
  440. reduced.map{|e| grid_to_cartesian(e)},
  441. final_state.map{|e| grid_to_cartesian(e)})
  442. #display_answer(final_state.map{|e| grid_to_cartesian(e)})
Time limit exceeded #stdin #stdout 5s 13680KB
stdin
Standard input is empty
stdout
Standard output is empty