@objective in a (specific) model give "MethodError: no method matching iterate(::Nothing)"
Here is a model that works without @objective but adding an @objective throws MethodError: no method matching iterate(::Nothing). I don't know is this is a bug in my model or somewhere else. (It use a decomposition of cumulative and that might very well be the culprit.)
And sorry about the largish model. I haven't had any similar problems with @objective before this.
function cumulative(model, start, duration, resource, limit)
tasks = [i for i in 1:length(start) if resource[i] > 0 && duration[i] > 0]
num_tasks = length(tasks)
times_min_a = round.(Int,[JuMP.lower_bound(start[i]) for i in tasks])
times_min = minimum(times_min_a)
times_max_a = round.(Int,[JuMP.upper_bound(start[i])+duration[i] for i in tasks])
times_max = maximum(times_max_a)
for t in times_min:times_max
bs = @variable(model, [1:num_tasks], Bin)
bt = @variable(model, [1:num_tasks], Bin)
b = @variable(model, [1:num_tasks], Bin)
for i in tasks
# is this task active during this time t?
@constraint(model, bs[i] := {start[i] <= t})
@constraint(model, bt[i] := {t <= start[i]+duration[i]-1}) # (should be '<')
@constraint(model, b[i] := { bs[i] + bt[i] == 2})
end
# Check that there's no conflicts in time t
@constraint(model,sum([b[i]*resource[i] for i in tasks]) <= limit)
end
end
function furniture_moving1(print_solutions=true,all_solutions=false)
cbc_optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
glpk_optimizer = optimizer_with_attributes(GLPK.Optimizer)
ipopt_optimizer = optimizer_with_attributes(Ipopt.Optimizer)
model = Model(optimizer_with_attributes(CS.Optimizer,
"logging"=>[],
"traverse_strategy"=>:BFS,
"branch_split"=>:InHalf, # <-
"time_limit"=>6,
# "lp_optimizer" => cbc_optimizer,
"lp_optimizer" => glpk_optimizer,
# "lp_optimizer" => ipopt_optimizer,
))
# Furniture moving problem
n = 4
# [piano, chair, bed, table]
durations = [30,10,15,15]
resources = [3,1,3,2] # people needed per task
@variable(model, 0 <= start_times[1:n] <= 60, Int)
@variable(model, 0 <= end_times[1:n] <= 60, Int)
@variable(model, 1 <= limit <= 3, Int)
for i in 1:n
@constraint(model,end_times[i] == start_times[i] + durations[i])
end
cumulative(model, start_times, durations, resources, limit)
# This throws: MethodError: no method matching iterate(::Nothing)
# @objective(model,Min,limit)
optimize!(model)
status = JuMP.termination_status(model)
if status == MOI.OPTIMAL
num_sols = MOI.get(model, MOI.ResultCount())
println("num_sols:$num_sols\n")
if print_solutions
for sol in 1:num_sols
println("solution #$sol")
start_timesx = convert.(Integer,JuMP.value.(start_times; result=sol))
end_timesx = convert.(Integer,JuMP.value.(end_times; result=sol))
max_timex = convert.(Integer,JuMP.value.(max_time; result=sol))
limitx = convert.(Integer,JuMP.value.(limit; result=sol))
println("start_times:$start_timesx")
println("durations :$durations")
println("end_times :$end_timesx")
println("resources :$resources")
println("limit :$limitx")
end
end
end
end
@time furniture_moving1()
Sorry that is a small error on my side. Good catch. A fix is on its way. Unfortunately my solver has quite some troubles solving it at the moment.Not sure why yet but I see that I need more testing with reified constraints for objective functions.
Thanks again for the issue and the testing of my solver. It's a long way to go to make it really usable as it's a massive project but I enjoy the journey.
The optimal solution is limit = 3, right? I'm a bit confused why it takes so long when optimizing. When setting limit to <= 2 it's immediately infeasible for obvious reasons but the bound computed is always 1.0 when optimizing. I'll check this out in the next days but most likely not today.
I found out why this is very slow in general:
- The reified constraint doesn't anti prune see #222
- It's not immediately obvious that the sum over the b for each task needs to be the duration, so I would add that constraint
- My branching strategy fails miserably in this case as it tries out various variations of the binary variables but not of
start_timesandend_times. I'm working on activity based branch (see #181) but that also seems to fail here as the activity for the binary variables is much higher. I think it would be valuable to have a strategy which counts the activity as how many values can be removed by this change instead.
Nevertheless in general a scheduling constraint needs to be implemented :smile:
Thanks for looking into this, Ole.
And I agree that there should be a dedicated scheduling constraint. :-)
However, I don't understand your comment: "It's not immediately obvious that the sum over the b for each task needs to be the duration, so I would add that constraint.". Would you mind explain a little more what you mean?
(The approach for this implementation is to - for each time step - check that the the total number of active resources cannot exceed limit. "active" is here the complete duration of a task, from start to start + duration -1. )
For clarification:
The b basically encodes whether it's active in the given time.
We want that every task is completed until our maximum end time. This means that when we have a vector of b for each task the sum of it over t has to equal the duration.
This is given by your definition but it's not as easy for my solver to see. I would therefore add that constraint as a user.
@Wikunia Yes, you have a good point and I will test this as well. (My formulation is one of the most used decompositions in the CP folk lore.)
Unfortunately because of the other problems I have identified this will still take a minute to solve. Even with #222 because of the branching strategy. I'll do more research on that.