Solving a Combination Lock Puzzle with JuMP and Julia
iaindunning.com
iaindunning.com
[(a,b,c,d,e,f) | a <- [39, 90, 75, 15, 57], b <- [9, 2, 58, 68, 48, 64], c <- [91, 29, 55, 16, 67, 8], d <- [22, 32, 25, 40, 54, 66], e <- [41, 14, 30, 49, 01, 17], f <- [44, 63, 10, 83, 46, 03], a+b+c+d+e+f == 419 ]Do you have to write another program?
julia> function brute_force(P,t)
for x1=P[1,:], x2=P[2,:], x3=P[3,:], x4=P[4,:], x5=P[5,:], x6=P[6,:]
x1 + x2 + x3 + x4 + x5 + x6 == t || continue
println("solution: $x1 $x2 $x3 $x4 $x5 $x6")
end
end
brute_force (generic function with 1 method)
julia> brute_force(P,419)
solution: 90 68 91 66 41 63
solution: 90 48 91 66 41 83
solution: 90 64 67 66 49 83
solution: 88 68 91 40 49 83
The interesting thing about Iain's linear programming approach is that you can write the problem down the way it is defined and get a solution efficiently.The way in which the problem is framed suggests there is a unique solution. The model is presented as a square matrix subject to linear constraints. There are 36 unknowns, being x[1][1] through to x[36][36], each of which is 0 or 1. There is the constraint that the sum of the unknowns is 419. And there are two constraints to ensure that only one number is chosen from each row and each column, which together give rise to 36 constraint equations.
If any one of the latter constraints is replaced by the sum constraint, there is a linear system of 36 equations in 36 unknowns. Is it possible for that system to be constructed and solved directly through matrix inversion?
(For those trying the exercise at home, the number at P[1,2] appears as 90 but from the full problem statement I think it should be 6.)
One heuristic is to solve an IP is to relax the integer constraint to inequality constraints, solve the LP, and round the results. However, this can do arbitrarily poorly on most problems.
array<array<int, 6>, 6> tumblers
= {{{39, 90, 75, 88, 15, 57}, {9, 2, 58, 68, 48, 64},
{29, 55, 16, 67, 8, 91}, {40, 54, 66, 22, 32, 25},
{49, 1, 17, 41, 14, 30}, {44, 63, 10, 83, 46, 3}}};
template <typename It> bool
solve (It tumbler, It end, int const sum) {
if (tumbler == end)
return (sum == 0);
for (auto const pin: *tumbler) {
if (solve (next(tumbler), end, sum - pin)) {
std::cout << pin << std::endl;
return true;
}
}
return false;
}
int main() {
solve (tumblers.rbegin(), tumblers.rend(), 419);
} m = {{39, 90, 75, 88, 15, 57},
{9, 2, 58, 68, 48, 64},
{29, 55, 16, 67, 8, 91},
{40, 54, 66, 22, 32, 25},
{49, 1, 17, 41, 14, 30},
{44, 63, 10, 83, 46, 3}};
Select[
Extract[m, #] & /@ Transpose[{Range[6], #}] & /@ Tuples[Range[6], 6],
Total[#] == 419 &]