Skip to content

Commit 82b9a95

Browse files
committed
Implement greedy, probabilistic algorithm for finding the best swaps
1 parent fab85b4 commit 82b9a95

File tree

1 file changed

+51
-16
lines changed

1 file changed

+51
-16
lines changed

day24/src/day24.cr

+51-16
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,21 @@ def swap(i : Int, j : Int, circuit : Circuit) : Circuit
6464
new_circuit
6565
end
6666

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)
6882
output_vars = solve(translate_to_z3(vars, circuit))
6983
x = extract_int("x", output_vars)
7084
y = extract_int("y", output_vars)
@@ -73,20 +87,35 @@ def find_best_swap(vars : Vars, circuit : Circuit) : Tuple(Int32, Int32)
7387
smallest_i = -1
7488
smallest_j = -1
7589
(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
7896
.each do |pair|
7997
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
86116
smallest_i = i
87117
smallest_j = j
88118
end
89-
d
90119
end
91120
{smallest_i, smallest_j}
92121
end
@@ -123,17 +152,23 @@ else
123152
part1 = extract_int("z", solve(translate_to_z3(vars, circuit)))
124153
puts "Part 1: #{part1}"
125154

155+
# For part 2 we use a probabilistic algorithm that tries to find the best
156+
# swaps for randomized inputs.
157+
126158
swapped = [] of String
159+
visited = Set(String).new
160+
127161
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+
131169
circuit = swap(i, j, circuit)
132170

133171
puts "#{i}, #{j}"
134-
135-
# Change up the circuit's inputs a bit
136-
vars[n] = {vars[n][0], 1_i64 - vars[n][1]}
137172
end
138173
swapped.sort!
139174
puts "Part 2: #{swapped.join(",")}"

0 commit comments

Comments
 (0)