@@ -57,79 +57,40 @@ def solve(z3_src : String) : Array(Tuple(String, Int64))
57
57
output_vars
58
58
end
59
59
60
- def swap (i : Int , j : Int , circuit : Circuit ) : Circuit
61
- new_circuit = [* circuit]
62
- new_circuit[i] = {circuit[i][0 ], circuit[j][1 ]}
63
- new_circuit[j] = {circuit[j][0 ], circuit[i][1 ]}
64
- new_circuit
60
+ def extract_int (prefix : String , values : Array (Tuple (String , Int64 ))) : Int
61
+ values
62
+ .select { |v | v[0 ].starts_with?(prefix) }
63
+ .map { |v | v[1 ] }
64
+ .reverse
65
+ .reduce(0 _i64 ) { |acc , b | (acc << 1 ) | b }
65
66
end
66
67
67
- def flip !(i : Int , vars : Vars )
68
- vars[i] = {vars[i][ 0 ], 1 _ i64 - vars[i][ 1 ]}
68
+ def is_x (s : String ) : Bool
69
+ s.starts_with?( " x " )
69
70
end
70
71
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
72
+ def is_y (s : String ) : Bool
73
+ s.starts_with?(" y" )
79
74
end
80
75
81
- def find_best_swap (vars : Vars , circuit : Circuit , visited : Set (String )) : Tuple (Int32 , Int32 )
82
- output_vars = solve(translate_to_z3(vars, circuit))
83
- x = extract_int(" x" , output_vars)
84
- y = extract_int(" y" , output_vars)
85
-
86
- smallest = 1000000
87
- smallest_i = -1
88
- smallest_j = -1
89
- (0 ...circuit.size)
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
96
- .each do |pair |
97
- i, j = pair
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
116
- smallest_i = i
117
- smallest_j = j
118
- end
119
- end
120
- {smallest_i, smallest_j}
76
+ def is_z (s : String ) : Bool
77
+ s.starts_with?(" z" )
121
78
end
122
79
123
- def hamming_dist (n : Int64 , m : Int64 ) : Int64
124
- (n ^ m).popcount
80
+ def is_coord (s : String ) : Bool
81
+ is_x(s) || is_y(s) || is_z(s)
125
82
end
126
83
127
- def extract_int (prefix : String , values : Array (Tuple (String , Int64 ))) : Int
128
- values
129
- .select { |v | v[0 ].starts_with?(prefix) }
130
- .map { |v | v[1 ] }
131
- .reverse
132
- .reduce(0 _i64 ) { |acc , b | (acc << 1 ) | b }
84
+ def is_wrong (expr : Array (String ), res : String ) : Bool
85
+ lhs, op, rhs = expr
86
+ xor_gate = op == " XOR"
87
+ or_gate = op == " OR"
88
+ and_gate = op == " AND"
89
+
90
+ [
91
+ xor_gate && ! is_coord(lhs) && ! is_coord(rhs) && ! is_coord(res),
92
+ ! xor_gate && is_z(res) && res != " z45" ,
93
+ ].any?
133
94
end
134
95
135
96
if ARGV .size == 0
@@ -152,24 +113,9 @@ else
152
113
part1 = extract_int(" z" , solve(translate_to_z3(vars, circuit)))
153
114
puts " Part 1: #{ part1 } "
154
115
155
- # For part 2 we use a probabilistic algorithm that tries to find the best
156
- # swaps for randomized inputs.
157
-
158
- swapped = [] of String
159
- visited = Set (String ).new
160
-
161
- 4 .times do |n |
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
-
169
- circuit = swap(i, j, circuit)
170
-
171
- puts " #{ i } , #{ j } "
172
- end
173
- swapped.sort!
174
- puts " Part 2: #{ swapped.join(" ," ) } "
116
+ part2 = circuit
117
+ .select { |c | is_wrong(c[0 ], c[1 ]) }
118
+ .map { |c | c[1 ] }
119
+ .join(" ," )
120
+ puts " Part 2: #{ part2 } "
175
121
end
0 commit comments