I’ll have detailed look at your suggestion (thanks a lot for proposing code!).
In the meantime, here is where I am currently at:
# Load the JuMP library
using Cbc
using JuMP
using MathProgBase
textProblem = """
6
13 + A1 A2 B1 B2
180 * C1 D1 D2 E1
9 + F1 F2 F3
2 = C2
20 * E2 E3
15 + A3 A4 A5
6 * B3 C3
11 + C4 D3 D4
3 = B4
9 + D5 E4 E5 F4
2 / B5 C5
18 + D6 E6 F5 F6
8 + A6 B6 C6
"""
problemList = split(textProblem, "\n")
problemsize = parse(problemList[1])
# Create a model
m = Model()
# Create the binary variables
@variable(m, x[1:problemsize, 1:problemsize, 1:problemsize], Bin)
# For each cell, calculate the value in that cell
@variable(m, v[1:problemsize, 1:problemsize], Int)
for i = 1:problemsize
for j = 1:problemsize
@constraint(m, v[i, j] == sum( (x[i, j, k] * k) for k=1:problemsize))
end
end
for i = 1:problemsize, j = 1:problemsize
@constraint(m, sum(x[i,j,k] for k=1:problemsize) == 1)
end
for row_or_col = 1:problemsize # Each row, OR each column
for digit = 1:problemsize # Each digit
# Sum across columns (j) - row constraint
@constraint(m, sum(x[row_or_col, j, digit] for j=1:problemsize ) == 1)
# Sum across rows (i) - column constraint
@constraint(m, sum(x[i, row_or_col, digit] for i=1:problemsize) == 1)
end
end
function A1_to_index(a1::String)
c = string(a1[1] - 'A' + 1)
r = a1[2]
return "v[" * c * "," * r * "]"
end
# Looping through all the constraints
counterBinary = 0
counterMult = 0
listExprs = []
for i = 2:length(problemList)-1
# The current constraint is parsed into total of the operation and the operation
constraintText = split(problemList[i])
constraintValue = constraintText[1]
constraintOp = constraintText[2]
constraintCells = map(x -> A1_to_index(convert(String, x)), constraintText[3:length(constraintText)])
cc = ""
if (constraintOp == "+") || (constraintOp == "=")
cc = join(constraintCells, " + ") * " == " * string(constraintValue)
push!(listExprs, "@constraint(m, " * cc * ")")
elseif constraintOp == "*"
counterMult += 1
multVariable1 = "mult" * string(counterMult)
push!(listExprs,
"@variable(m, " * multVariable1 * ", Int)")
cc = constraintCells[1] * " * " * constraintCells[2] * " - " *
multVariable1 * " == 0"
push!(listExprs, "@constraint(m, " * cc * ")")
println(cc)
if length(constraintCells) > 2
for j = 3:length(constraintCells)
counterMult += 1
multVariable2 = "mult" * string(counterMult)
push!(listExprs,
"@variable(m, " * multVariable2 * ", Int)")
cc = multVariable1 * " * " * constraintCells[j] * " - " *
multVariable2 * " == 0"
push!(listExprs, "@constraint(m, " * cc * ")")
multVariable1 = multVariable2
println(cc)
end
end
elseif constraintOp == "-"
cc = constraintCells[1] * " * " * constraintCells[1] * " - " *
"2 * " * constraintCells[1] * " * " * constraintCells[2] * " + " *
constraintCells[2] * " * " * constraintCells[2] * " == " * string(constraintValue)
push!(listExprs, "@constraint(m, " * cc * ")")
elseif constraintOp == "/"
counterBinary += 1
binvariable1 = "bin" * string(counterBinary)
push!(listExprs,
"@variable(m, " * binvariable1 * ", Bin)")
counterBinary += 1
binvariable2 = "bin" * string(counterBinary)
push!(listExprs,
"@variable(m, " * binvariable2 * ", Bin)")
cc = binvariable1 * " + " * binvariable2 * " == 1 "
push!(listExprs, "@constraint(m, " * cc * ")")
println(cc)
cc = binvariable1 * " * " * constraintCells[1] * " - " *
string(constraintValue) * " * " * constraintCells[2] * " == 0"
push!(listExprs, "@constraint(m, " * cc * ")")
println(cc)
cc = binvariable2 * " * " * constraintCells[2] * " - " *
string(constraintValue) * " * " * constraintCells[1] * " == 0"
push!(listExprs, "@constraint(m, " * cc * ")")
end
println(cc)
end
println("")
map( x -> eval(parse(x)), listExprs)
# We are now ready to solve the problem
# For this to work, you must have an integer programming
# solver installed. If you don't, you can install one with
# Pkg.add("GLPKMathProgInterface")
# or
# Pkg.add("Cbc")
solve(m)
# Extract the values of x
x_val = getvalue(x)
# Create a matrix to store the solution
sol = zeros(Int,9,9) # 9x9 matrix of integers
for i in 1:problemsize, j in 1:problemsize, k in 1:problemsize
# Integer programs are solved as a series of linear programs
# so the values might not be precisely 0 and 1. We can just
# round them to the nearest integer to make it easier
if round(Int, x_val[i,j,k]) == 1
sol[i,j] = k
end
end
# Display the solution
println(sol)