Compare commits

..

6 commits

5 changed files with 87 additions and 0 deletions

View file

@ -4,10 +4,13 @@ authors = ["Dimitri Lozeve <dimitri@lozeve.com>"]
version = "0.1.0" version = "0.1.0"
[deps] [deps]
CPLEX = "a076750e-1247-5638-91d2-ce28b192dca0"
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"

View file

@ -17,6 +17,7 @@ export update!, fillgardenrandomly!, gardenevolution!, outputgarden
include("classification.jl") include("classification.jl")
include("loaddata.jl") include("loaddata.jl")
include("mcmc.jl") include("mcmc.jl")
include("optim.jl")
"Save the garden to a CSV file." "Save the garden to a CSV file."
function outputgarden(garden::Matrix{Int}, plants::Vector{Symbol}) function outputgarden(garden::Matrix{Int}, plants::Vector{Symbol})

67
src/optim.jl Normal file
View file

@ -0,0 +1,67 @@
using JuMP
using CPLEX
function neighbourindices(mask::Matrix, idx::Int)::Vector{Int}
if mask[idx] == 0
return []
end
m, n = size(mask)
i, j = Tuple(CartesianIndices(mask)[idx])
indices = [(i, j-1), (i, j+1), (i-1, j), (i+1, j)]
# cells filled with 0 are not part of the garden
cartesianindices = [
CartesianIndex(k, l) for (k, l) in indices
if 0 < k <= m && 0 < l <= n && mask[k, l] != 0
]
# convert to linear indices
LinearIndices(mask)[cartesianindices]
end
function neighbourmatrix(mask::Matrix)::Matrix{Bool}
N = length(mask)
d = zeros(N, N)
for i in 1:N
for j in neighbourindices(mask, i)
d[i, j] = 1
end
end
d
end
function definemodel(plantcounts::Vector, garden::Matrix, mask::Matrix, costs::Matrix)
N = length(mask)
Q = size(costs, 1)
optimizer = optimizer_with_attributes(
CPLEX.Optimizer, "CPX_PARAM_OPTIMALITYTARGET" => 2, "CPX_PARAM_EPINT" => 1e-8)
model = Model(optimizer)
@variable(model, x[1:N, 1:Q], Bin)
@objective(
model,
Min,
sum(
costs[q, r] * x[i, q] * x[j, r]
for i = 1:N, q = 1:Q, r = 1:Q for j = neighbourindices(mask, i)
)
)
for i = 1:N
@constraint(model, sum(x[i, q] for q = 1:Q) <= 1)
if mask[i] == 0
for q = 1:Q
@constraint(model, x[i, q] == 0)
end
end
if garden[i] != 0
@constraint(model, x[i, garden[i]] == 1)
end
end
for q = 1:Q
@constraint(model, sum(x[i, q] for i = 1:N) >= plantcounts[q])
end
model
end

15
test/optim.jl Normal file
View file

@ -0,0 +1,15 @@
using GardenOptim
using LinearAlgebra
using Test
@testset "optim" begin
mask = zeros(Bool, 5, 7)
mask[[1, 2, 6, 7]] .= 1
@test GardenOptim.neighbourindices(mask, 1) == [6, 2]
@test GardenOptim.neighbourindices(mask, 2) == [7, 1]
@test GardenOptim.neighbourindices(mask, 3) == []
neighbourcount = sum([length(GardenOptim.neighbourindices(mask, i)) for i = 1:length(mask)])
@test sum(GardenOptim.neighbourmatrix(mask)) == neighbourcount
@test issymmetric(GardenOptim.neighbourmatrix(mask))
end

View file

@ -3,4 +3,5 @@ using Test
@testset "GardenOptim.jl" begin @testset "GardenOptim.jl" begin
include("classification.jl") include("classification.jl")
include("mcmc.jl") include("mcmc.jl")
include("optim.jl")
end end