Guest User

Untitled

a guest
May 27th, 2024
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.97 KB | None | 0 0
  1. from z3 import *
  2. import networkx as nx
  3.  
  4. # solver for Jane Street's bug byte, see:
  5. # https://www.janestreet.com/bug-byte/
  6.  
  7. white_17, white_3, green_31, green_19_23, top_star, green_8 = [vertex for vertex in range(0, 6)]
  8. green_6_9_16, white_54, white_49, white_60, white_79, white_75 = [vertex for vertex in range(6, 12)]
  9. empty_left, white_29, empty_right, white_39, white_25, bot_star = [vertex for vertex in range(12, 18)]
  10.  
  11. vertex_names = dict([
  12.     (white_17, "white_17"),
  13.     (white_3, "white_3"),
  14.     (green_31, "green_31"),
  15.     (green_19_23, "green_19_23"),
  16.     (top_star, "top_star"),
  17.     (green_8, "green_8"),
  18.     (green_6_9_16, "green_6_9_16"),
  19.     (white_54, "white_54"),
  20.     (white_49, "white_49"),
  21.     (white_60, "white_60"),
  22.     (white_79, "white_79"),
  23.     (white_75, "white_75"),
  24.     (empty_left, "empty_left"),
  25.     (white_29, "white_29"),
  26.     (empty_right, "empty_right"),
  27.     (white_39, "white_39"),
  28.     (white_25, "white_25"),
  29.     (bot_star, "bot_star")
  30. ])
  31.  
  32. solver = Solver()
  33. graph = nx.Graph()
  34.  
  35. graph.add_edge(white_17, green_19_23, weight=Int("(white_17, green_19_23)"))
  36. graph.add_edge(white_17, white_3, weight=Int("(white_17, white_3)"))
  37. graph.add_edge(white_3, top_star, weight=Int("(white_3, top_star)"))
  38. graph.add_edge(green_31, white_54, weight=Int("(green_31, white_54)"))
  39. graph.add_edge(green_19_23, white_54, weight=Int("(green_19_23, white_54)"))
  40. graph.add_edge(green_19_23, top_star, weight=12)
  41. graph.add_edge(top_star, white_49, weight=Int("top_star, white_49"))
  42. graph.add_edge(green_8, white_49, weight=Int("(green_8, white_49)"))
  43. graph.add_edge(green_6_9_16, white_60, weight=Int("(green_6_9_16, white_60)"))
  44. graph.add_edge(white_54, white_79, weight=Int("(white_54, white_79)"))
  45. graph.add_edge(white_54, white_60, weight=Int("(white_54, white_60)"))
  46. graph.add_edge(white_49, white_60, weight=Int("(white_49, white_60)"))
  47. graph.add_edge(white_49, white_75, weight=20)
  48. graph.add_edge(white_60, white_79, weight=24)
  49. graph.add_edge(white_60, white_75, weight=Int("(white_60, white_75)"))
  50. graph.add_edge(white_79, empty_left, weight=Int("(white_79, empty_left)"))
  51. graph.add_edge(white_79, white_39, weight=7)
  52. graph.add_edge(white_79, white_29, weight=Int("(white_79, white_29)"))
  53. graph.add_edge(white_75, white_25, weight=Int("(white_75, white_25)"))
  54. graph.add_edge(white_75, empty_right, weight=Int("(white_75, empty_right)"))
  55. graph.add_edge(white_29, white_25, weight=Int("(white_29, white_25)"))
  56. graph.add_edge(white_29, white_39, weight=Int("white_29, white_39"))
  57. graph.add_edge(white_39, bot_star, weight=Int("(white_39, bot_star)"))
  58. graph.add_edge(white_25, bot_star, weight=Int("(white_25, bot_star)"))
  59.  
  60. vertices = list(graph.nodes)
  61. weights = [weight for weight in map(lambda uvw: uvw[2], graph.edges.data("weight"))]
  62.  
  63. # all weights must be unique
  64. solver.add(Distinct(weights))
  65.  
  66. # all weights fall in [1, 24]
  67. for weight in weights:
  68.     solver.add(And(weight >= 1, weight <= 24))
  69.  
  70. vertices_to_sums = [
  71.     (white_17, 17), (white_3, 3), (white_54, 54), (white_49, 49), (white_60, 60),
  72.     (white_79, 79), (white_75, 75), (white_29, 29), (white_39, 39), (white_25, 25)
  73. ]
  74.  
  75. # adjacent edge weight sum constraints for white vertices
  76. for (vertex, sum) in vertices_to_sums:
  77.     neighbour_edge_weights = [graph.adj[vertex][neighbour]["weight"] for neighbour in graph[vertex]]
  78.     solver.add(Sum(neighbour_edge_weights) == sum)
  79.  
  80. vertices_to_path_sums = [
  81.     (green_19_23, [19, 23]),
  82.     (green_31, [31]),
  83.     (green_6_9_16, [6, 9, 16]),
  84.     (green_8, [8])
  85. ]
  86.  
  87. # existence of paths with particular weight sums for green vertices
  88. for (vertex, path_sums) in vertices_to_path_sums:
  89.     for path_sum in path_sums:
  90.         constraints = []
  91.  
  92.         for destination in (set(vertices) - set([vertex])):
  93.             for path in nx.all_simple_paths(graph, vertex, destination):
  94.                 constraints.append(nx.path_weight(graph, path, weight="weight") == path_sum)
  95.  
  96.         solver.add(Or(constraints))
  97.  
  98. # exhausts all possible solutions
  99. while solver.check() == sat:
  100.     model = solver.model()
  101.  
  102.     for vertex, neighbour in graph.edges():
  103.         variable = graph.adj[vertex][neighbour]["weight"]
  104.  
  105.         if isinstance(variable, int):
  106.             continue
  107.        
  108.         plugged_in = model.evaluate(variable).as_long()
  109.         graph.adj[vertex][neighbour]["weight"] = plugged_in
  110.  
  111.     answer_vertices = list(nx.shortest_path(graph, top_star, bot_star, weight="weight"))
  112.     answer_vertex_names = [vertex_names[vertex] for vertex in answer_vertices]
  113.     print("the shortest path is: %s" % answer_vertex_names)
  114.  
  115.     answer_weights = [graph.adj[answer_vertices[index]][answer_vertices[index + 1]]["weight"] for index in range(0, len(answer_vertices) - 1)]
  116.     chars = [c for c in map(lambda weight: chr(weight + 97 - 1), answer_weights)]
  117.     answer = ""
  118.  
  119.     for char in chars:
  120.         answer += char
  121.  
  122.     print("the answer is: \"%s\"" % answer)
  123.  
  124.     solver.add(Or([sym() != model[sym] for sym in model.decls()]))
  125.  
  126. print("no more solution found")
  127.  
Advertisement
Add Comment
Please, Sign In to add comment