Guest User

Untitled

a guest
Jan 22nd, 2019
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.03 KB | None | 0 0
  1. #
  2. # Exploring how to maximize the conversations at a dinner table with one reseating.
  3. # Inspired by a team dinner at a long straight table.
  4. #
  5. # Brute force search so far. I haven't come up with a better algorithm. Brute force
  6. # at 12 people takes ~2 hours on my laptop, so I've reach the realistic limit of
  7. # this approach.
  8. #
  9. # Maybe
  10. # - Performance
  11. # - Using Python sets for the union function - may be able to make this much faster with a
  12. # less general data structure.
  13. # - Using strings where integers or characters might be faster.
  14. # - Remembers only the first solution for each improved value. If it remembered (and
  15. # printed) all it might be easier to find a pattern.
  16. # - I'm interested in exploring a "distance" metric and using that to find the "minimal"
  17. # change that still maxmizes the number of conversations. Could potentially be "number
  18. # of seats that change" or sum of the distances of changes.
  19. # - Convert to Python 3. Might already be compatible?
  20. #
  21. # Notes
  22. # - Much non-idiomatic Python here.
  23. # - Put everything in a function and use the __main()__ trick to make testing easier
  24. # - Perhaps some of this should be converted to classes - e.g. class SeatingConfiguration
  25. #
  26.  
  27. import itertools
  28. import time
  29. import sys
  30.  
  31.  
  32. # FIXME There has to be a less duplicative way to do this...
  33. people4 = ["A", "B", "C", "D"]
  34. people6 = ["A", "B", "C", "D", "E", "F"]
  35. people8 = ["A", "B", "C", "D", "E", "F", "G", "H"]
  36. people10 = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
  37. people12 = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]
  38.  
  39. # This makes it easy to change which problem size we are using
  40. people = people8
  41.  
  42.  
  43. #
  44. # A six person table is numbered thusly
  45. # 0 1 2 A B C
  46. # 5 4 3 F E D
  47. #
  48. # An eight person table is numbered thusly
  49. # 0 1 2 3 A B C D
  50. # 7 6 5 4 H G F E
  51. #
  52. # A ten person table is numbered thusly
  53. # 0 1 2 3 4 A B C D E
  54. # 9 8 7 6 5 J I H G F
  55. #
  56. # Computing the index of the seat opposite:
  57. # The sum of the indices of opposite seats = length-1.
  58. # So the index of the seat opposite seat i is ((length-1)-i
  59. #
  60.  
  61. # Downstream code assumes each conversation pair has [0] < [1]
  62. def add_pair(result, a, b):
  63. if (a < b):
  64. result.add((a, b))
  65. else:
  66. result.add((b, a))
  67.  
  68.  
  69. # Given a set of people p, return the set of conversations.
  70. # p must be even and >= 4.
  71. # We only add tuples with the first value < second value.
  72. def conversations(p):
  73. result = set()
  74. n = len(p)
  75.  
  76. # First corner: seat 0 can talk to 1, len-2 and len-1
  77. add_pair(result, p[0], p[1])
  78. add_pair(result, p[0], p[n - 2])
  79. add_pair(result, p[0], p[n - 1])
  80. # print "After first corner: %r" % sorted(list(result))
  81.  
  82. # Second corner: seat ((n/2)-1) can talk to the seat one smaller,
  83. # one greater, and two greater
  84. temp = (n / 2) - 1
  85. add_pair(result, p[temp], p[temp + 1])
  86. add_pair(result, p[temp], p[temp + 2])
  87. # print "After second corner: %r" % sorted(list(result))
  88.  
  89. # Third corner: seat n/2 can talk to two smaller, one smaller
  90. # and one greater
  91. add_pair(result, p[n / 2], p[(n / 2) + 1])
  92. # print "After third corner: %r" % sorted(list(result))
  93.  
  94. # Fourth corner: seat n-1 can only talk to seats < n-1, so nothing to do.
  95. # print "After fourth corner: %r" % sorted(list(result))
  96.  
  97. # "top" side of the table. There are five neighbors, but the one to the
  98. # left is smaller.
  99. for i in range(1, (n / 2) - 1):
  100. opposite = (n - 1) - i
  101. add_pair(result, p[i], p[i + 1])
  102. add_pair(result, p[i], p[opposite - 1])
  103. add_pair(result, p[i], p[opposite])
  104. add_pair(result, p[i], p[opposite + 1])
  105. # print "After 'top' side: count=%d %r" % (len(result), sorted(list(result)))
  106.  
  107.  
  108. # "bottom" side of the table. There are five neighbors. But all of those one the
  109. # "top" side of the table, and the one to the right, have already been added.
  110. for i in range((n / 2) + 1, n - 1):
  111. add_pair(result, p[i], p[i + 1])
  112. # print "After 'bottom' side: count=%d %r" % (len(result), sorted(list(result)))
  113.  
  114. # print "conversations: p=%r count=%d result=%r" % (
  115. # str(p).replace(" ", ""), len(result), str(sorted(list(result))).replace(" ", ""))
  116.  
  117. return result
  118.  
  119.  
  120. # Utility function to produce a compact string from a permutation
  121. def permutation_to_string(p):
  122. result = ""
  123. for x in p:
  124. result = result + str(x)
  125. return result
  126.  
  127.  
  128. # Utility function to produce a compact string from a set of conversations, represented
  129. # as a set of two-valued tuples.
  130. def conversations_to_string(conv):
  131. conv_list = sorted(list(conv))
  132.  
  133. t = {}
  134.  
  135. # intialize the dictionary with the first character as key and
  136. # an empty value. Dupes don't matter.
  137. for x in conv_list:
  138. t[x[0]] = x[0] + ":"
  139.  
  140. # For each first chaacter, accumulate a string of 2nd characters
  141. for x in conv_list:
  142. t[x[0]] = t[x[0]] + x[1]
  143.  
  144. result = "<<n=%d" % len(conv)
  145. for k, v in sorted(t.items()):
  146. result = result + " " + v
  147. result = result + ">>"
  148.  
  149. return result
  150.  
  151.  
  152. # Utility function to print conversations and
  153. # a permutation (presumably that generated those conversations)
  154. def print_conversations_and_permutations(leading_string, conv, permutation):
  155. print "%sperm=%s conv=%s" % (leading_string, permutation_to_string(permutation), conversations_to_string(conv))
  156.  
  157.  
  158. # The conversations created by the initial seating
  159. starting_conversations = conversations(people)
  160.  
  161. # Keep track of the best so far. Constants are just convenience keys into the dictionary.
  162. best_so_far = {}
  163. PERMUTATION = 0
  164. CONVERSATIONS = 1
  165. COUNT = 2
  166.  
  167. best_so_far[PERMUTATION] = people
  168. best_so_far[CONVERSATIONS] = starting_conversations
  169. best_so_far[COUNT] = len(starting_conversations)
  170.  
  171. print_conversations_and_permutations("INITIAL: ", best_so_far[CONVERSATIONS], best_so_far[PERMUTATION])
  172.  
  173. people_permutations = itertools.permutations(people)
  174. i = 0
  175. count_of_best = 0
  176. start_time = time.time()
  177. for perm in people_permutations:
  178. second_conversations = conversations(perm)
  179. unique_conversations = starting_conversations | second_conversations
  180. if (len(unique_conversations) > best_so_far[COUNT]):
  181. best_so_far[PERMUTATION] = perm
  182. best_so_far[CONVERSATIONS] = unique_conversations
  183. best_so_far[COUNT] = len(unique_conversations)
  184. count_of_best = 1
  185. print "IMPROVE(1): unique_conversations: %s additional_conversations: %s" % (
  186. conversations_to_string(unique_conversations),
  187. conversations_to_string(unique_conversations - starting_conversations))
  188. print_conversations_and_permutations("IMPROVE(2): ", best_so_far[CONVERSATIONS], best_so_far[PERMUTATION])
  189. elif (len(unique_conversations) == best_so_far[COUNT]):
  190. count_of_best = count_of_best + 1
  191. print "FOUND ANOTHER WITH SAME i=%d %d count_of_best=%d" % (i, best_so_far[COUNT], count_of_best)
  192.  
  193. i = i + 1
  194. if ((i % 1000) == 0):
  195. print "i=%d t=%d t_per_thousand=%f" % (i, (time.time()-start_time), ((time.time()-start_time))/i)
  196.  
  197. print ""
  198. print_conversations_and_permutations("BEST: ", best_so_far[CONVERSATIONS], best_so_far[PERMUTATION])
Add Comment
Please, Sign In to add comment