The most important, what I failed to understand, is that isCovered is in the function of houses. I was thinking about the grid that one antenna can cover, but I should think about which houses antenna(s) can cover instead.
Here is the model:
using JuMP, Cbc, XLSX
mat = XLSX.readdata("data/input.xlsx", "sheet1", "A1:J10")
M = size(mat, 1)
N = size(mat, 2)
ratio = 0.7
houses = []
for i = 1 : M
for j = 1 : N
if mat[i,j] == 1
push!(houses, (i,j))
end
end
end
model = Model(Cbc.Optimizer)
@variable(model,
isCovered[houses],
Bin)
@variable(model,
isAntenna[1:M, 1:N],
Bin)
@objective(
model,
Min,
sum(isAntenna)
)
@constraint(
model,
sum(isCovered) >= length(houses) * ratio
)
@constraint(
model,
[h in houses],
isCovered[h] <=
sum(
isAntenna[r, c]
for r in h[1]-1:h[1]+1, c in h[2]-1:h[2]+1
if 1 <= r <= M && 1 <= c <= N
)
)
optimize!(model)
res = primal_status(model)
if res == MOI.FEASIBLE_POINT
val = value.(isAntenna)
open("out/result.txt","w") do io
for i in 1:M
for j in 1:N
print(io, floor(Int, val[i,j]))
print(io, '\t')
end
print(io, "\n")
end
end
end