@@ -64,7 +64,21 @@ def swap(i : Int, j : Int, circuit : Circuit) : Circuit
64
64
new_circuit
65
65
end
66
66
67
- def find_best_swap (vars : Vars , circuit : Circuit ) : Tuple (Int32 , Int32 )
67
+ def flip !(i : Int , vars : Vars )
68
+ vars[i] = {vars[i][0 ], 1 _i64 - vars[i][1 ]}
69
+ end
70
+
71
+ RNG = Random .new
72
+
73
+ def randomize !(vars : Vars )
74
+ (0 ...vars.size).each do |i |
75
+ if RNG .next_bool
76
+ flip!(i, vars)
77
+ end
78
+ end
79
+ end
80
+
81
+ def find_best_swap (vars : Vars , circuit : Circuit , visited : Set (String )) : Tuple (Int32 , Int32 )
68
82
output_vars = solve(translate_to_z3(vars, circuit))
69
83
x = extract_int(" x" , output_vars)
70
84
y = extract_int(" y" , output_vars)
@@ -73,20 +87,35 @@ def find_best_swap(vars : Vars, circuit : Circuit) : Tuple(Int32, Int32)
73
87
smallest_i = -1
74
88
smallest_j = -1
75
89
(0 ...circuit.size)
76
- # Baed on manual analysis of the GraphViz plot, the swaps seem to be relatively local
77
- .flat_map { |i | ({i - 4 , 0 }.max..{i + 4 , circuit.size - 1 }.min).select { |j | i != j }.map { |j | {i, j} } }
90
+ .flat_map do |i |
91
+ # Baed on manual analysis of the GraphViz plot, the swaps seem to be relatively local
92
+ ({i + 1 , circuit.size - 1 }.min..{i + 5 , circuit.size - 1 }.min)
93
+ .select { |j | i != j && ! visited.includes?(circuit[i][1 ]) && ! visited.includes?(circuit[j][1 ]) }
94
+ .map { |j | {i, j} }
95
+ end
78
96
.each do |pair |
79
97
i, j = pair
80
- output_vars = solve(translate_to_z3(vars, swap(i, j, circuit)))
81
- z = extract_int(" z" , output_vars)
82
- d = hamming_dist(x + y, z)
83
- if d < smallest
84
- puts " #{ i } , #{ j } -> #{ d } (#{ x.to_s(16 ) } vs #{ y.to_s(16 ) } -> #{ z.to_s(16 ) } )"
85
- smallest = d
98
+ max_d = 0
99
+ max_d_z = 0
100
+ vars = [* vars]
101
+ 4 .times do
102
+ randomize!(vars)
103
+ output_vars = solve(translate_to_z3(vars, swap(i, j, circuit)))
104
+ x = extract_int(" x" , output_vars)
105
+ y = extract_int(" y" , output_vars)
106
+ z = extract_int(" z" , output_vars)
107
+ d = hamming_dist(x + y, z)
108
+ if d > max_d
109
+ max_d = d
110
+ max_d_z = z
111
+ end
112
+ end
113
+ if max_d < smallest
114
+ puts " #{ i } , #{ j } -> #{ max_d } "
115
+ smallest = max_d
86
116
smallest_i = i
87
117
smallest_j = j
88
118
end
89
- d
90
119
end
91
120
{smallest_i, smallest_j}
92
121
end
@@ -123,17 +152,23 @@ else
123
152
part1 = extract_int(" z" , solve(translate_to_z3(vars, circuit)))
124
153
puts " Part 1: #{ part1 } "
125
154
155
+ # For part 2 we use a probabilistic algorithm that tries to find the best
156
+ # swaps for randomized inputs.
157
+
126
158
swapped = [] of String
159
+ visited = Set (String ).new
160
+
127
161
4 .times do |n |
128
- i, j = find_best_swap(vars, circuit)
129
- swapped << circuit[i][1 ]
130
- swapped << circuit[j][1 ]
162
+ i, j = find_best_swap(vars, circuit, visited)
163
+
164
+ [circuit[i][1 ], circuit[j][1 ]].each do |v |
165
+ swapped << v
166
+ visited << v
167
+ end
168
+
131
169
circuit = swap(i, j, circuit)
132
170
133
171
puts " #{ i } , #{ j } "
134
-
135
- # Change up the circuit's inputs a bit
136
- vars[n] = {vars[n][0 ], 1 _i64 - vars[n][1 ]}
137
172
end
138
173
swapped.sort!
139
174
puts " Part 2: #{ swapped.join(" ," ) } "
0 commit comments