diff --git a/src/MIP/SupportFunctions.jl b/src/MIP/SupportFunctions.jl index d34132e..5c24513 100644 --- a/src/MIP/SupportFunctions.jl +++ b/src/MIP/SupportFunctions.jl @@ -5,13 +5,12 @@ function buildJd(timeslots,subcal) timeslots |> @filter(_.dayID in keys(subcal))|>@groupby(_.resourceID) |>@map((d = key(_),j = unique(map(x->x.dayID,_)))) |> NDSparse end function buildI(timeslots) - timeslots |> @groupby((_.resourceID,_.dayID)) |> @map({d=key(_)[1],j=key(_)[2],i=map(x->x.timeslotID,_)})|> NDSparse + timeslots|> @filter(!_.booked) |> @groupby((_.resourceID,_.dayID)) |> @map({d=key(_)[1],j=key(_)[2],i=map(x->x.timeslotID,_)})|> NDSparse end function getTlowerbound(timeslots,resourceID,dayID) - println("$resourceID - $dayID") - bookedslots = timeslots |> @filter(_.resourceID == resourceID && _.dayID == dayID && _.status )|> @orderby(_.endTime) |> @take(1) |>@map(_.endTime) |> collect + bookedslots = timeslots |> @filter(_.resourceID == resourceID && _.dayID == dayID && _.booked )|> @orderby(_.endTime) |> @take(1) |>@map(_.endTime) |> collect if length(bookedslots) == 1 value = Dates.value(first(bookedslots))/60000000000 else @@ -56,7 +55,7 @@ end "Produces a IndexedTable of patient groups based on the function patientgroup()" function buildPg(patients,visits,Vp) - table(patients |> @groupby(patientgroup(visits,Vp,_.intID))|> @map((group1=key(_)[1],group2=key(_)[2],group3=key(_)[3],patients= map(x->x.intID,_))) |> collect) + table(patients |> @groupby(patientgroup(visits,Vp,_.intID))|> @map((types=key(_)[1],startmonth=key(_)[2],endmonths=key(_)[3],patients= map(x->x.intID,_))) |> collect) end diff --git a/src/MIP/masterproblem.jl b/src/MIP/masterproblem.jl index f370133..1475e18 100644 --- a/src/MIP/masterproblem.jl +++ b/src/MIP/masterproblem.jl @@ -8,7 +8,7 @@ function setupmaster(subproblems,patients,resources,timeslots,subMastercalendar, K = length(patients) Pg = sets.Pg - Gp = keys(Pg) ##TODO virker nok ikke men nu smutter jeg hjem + Gp = [i for i in 1:length(Pg)] D = JuliaDB.select(resources,:intID) J = keys(subMastercalendar) Jd = sets.Jd @@ -27,10 +27,10 @@ function setupmaster(subproblems,patients,resources,timeslots,subMastercalendar, @constraint(master,consref_offtime[d in D, j in Jd[d]], sum(lambda[m]*1000 for m in 1:K) <= closingtime[d,j]) #TODO Only for consultations @constraint(master,convexitycons[g in Gp], - sum(lambda[m] for m in 1:K if m in Pg[g].patients) == length(P_g[g].patients) ) + sum(lambda[m] for m in 1:K if m in Pg[g].patients) == length(Pg[g].patients) ) - @constraint(master,consref_onepatient[ d in D, j in Jd[d], i in I[d,j]], + @constraint(master,consref_onepatient[ d in D, j in Jd[d].j, i in I[d,j].i], 0 <=1 ) diff --git a/src/MIP/model_column.jl b/src/MIP/model_column.jl index ad8a0e0..53581ce 100644 --- a/src/MIP/model_column.jl +++ b/src/MIP/model_column.jl @@ -2,7 +2,8 @@ EPSVALUE = 0.1 -function columngeneration(patients, visits, resources, timeslots, mastercalendar, timeDelta, setuponly = false) +function columngeneration(patients, visits, resources, timeslots, mastercalendar, timeDelta; setuponly = false, multithreading = false) + println("Building sets") timeslotsNDSparse = ndsparse(timeslots) subproblems = Subproblems() sets = Sets() @@ -13,9 +14,9 @@ function columngeneration(patients, visits, resources, timeslots, mastercalendar sets.Jd = buildJd(timeslots,mastercalendar) sets.I = buildI(timeslots) sets.Pg = buildPg(patients,visits,sets.Vp) - + println("Setting up sub-problems") setup_sub!(subproblems,patients,visits,resources,timeslotsNDSparse,mastercalendar,timeDelta,sets,1) - + println("Setting up master") mp = setupmaster(subproblems,patients,resources,timeslots,mastercalendar,sets) #generateInitialColumns(mp,subproblems) if setuponly @@ -26,6 +27,7 @@ function columngeneration(patients, visits, resources, timeslots, mastercalendar while !done iteration +=1 println(iteration) + println("Solving master") optimize!(mp.model) println("Master objective value = $(JuMP.objective_value(mp.model))") println.(getPositiveVariables(mp.lambda)) @@ -39,24 +41,31 @@ function columngeneration(patients, visits, resources, timeslots, mastercalendar θ = dual.(mp.consref_onepatient) κ = dual.(mp.convexitycons) - subthreads = [] + println("Solving subproblems") + if multithreading + subthreads = [] + for sub in values(subproblems.pricingproblems) + push!(subthreads,Threads.@spawn solveSub!(sub,sets,ϕ,θ,κ)) + end + #end + for thread in subthreads + wait(thread) #TODO remove multithreading, fix at turn MT back on + end + else + for sub in values(subproblems.pricingproblems) + solveSub!(sub,sets,ϕ,θ,κ) + # solveSub!(sub,ϕ,θ,κ) + # done2 = addcolumntomaster!(mp,sub,iteration,EPSVALUE) #TODO add patient info + # done &= done2 + # count = 0 + # while !done2 && count < 0#length(sub.patients) + # count += 1 + # solveSub!(sub,getIndexofPositiveVariables(sub.xvars)) #TODO time this + # done2 = addcolumntomaster!(mp,sub,iteration,EPSVALUE) + # end + end + #end - for sub in values(subproblems.pricingproblems) - - push!(subthreads,Threads.@spawn solveSub!(sub,ϕ,θ,κ)) - # solveSub!(sub,ϕ,θ,κ) - # done2 = addcolumntomaster!(mp,sub,iteration,EPSVALUE) #TODO add patient info - # done &= done2 - # count = 0 - # while !done2 && count < 0#length(sub.patients) - # count += 1 - # solveSub!(sub,getIndexofPositiveVariables(sub.xvars)) #TODO time this - # done2 = addcolumntomaster!(mp,sub,iteration,EPSVALUE) - # end - end - #end - for thread in subthreads - wait(thread) end done = addcolumntomaster!(mp,subproblems,iteration,EPSVALUE) diff --git a/src/MIP/subproblem.jl b/src/MIP/subproblem.jl index 633d7d6..192c45f 100644 --- a/src/MIP/subproblem.jl +++ b/src/MIP/subproblem.jl @@ -8,12 +8,12 @@ function setup_sub!(subproblems,patients::IndexedTable,visits,resources::IndexedTable,timeslots,mastercalendar::Dict{Int,Date},TimeDelta,sets,months) - for patient in rows(patients) + for patientgroup in [i for i in 1:length(sets.Pg)] #TODO length of min treatment time should be calculated and used. - setup_sub!(subproblems,patient,visits,resources,timeslots,mastercalendar,TimeDelta,sets,months) + setup_sub!(subproblems,patientgroup,visits,resources,timeslots,mastercalendar,TimeDelta,sets,months) end end startofyear(date::Date) = Date(Year(date)) @@ -31,12 +31,12 @@ function getTimeDelta(timeDelta,visits,v1,v2) end -function setup_sub!(subproblems,patient::NamedTuple,visits,resources::IndexedTable,timeslots,mastercalendar::Dict{Int,Date},timeDelta,sets,months) +function setup_sub!(subproblems,p::Int64,visits,resources::IndexedTable,timeslots,mastercalendar::Dict{Int,Date},timeDelta,sets,months) M1 = 10 M2 = 1000 Td(v1,v2) = getTimeDelta(timeDelta,visits,v1,v2) - p = patient.intID + V = sets.Vp[p].v; Dv = sets.Dv; D = sets.Dp[p].d; J = sets.J ;Jd = sets.Jd; I = sets.I Ts(d,j,i) = Dates.value(timeslots[d,j,i].startTime)/60000000000 Te(d,j,i) = Dates.value(timeslots[d,j,i].endTime)/60000000000 @@ -46,11 +46,6 @@ function setup_sub!(subproblems,patient::NamedTuple,visits,resources::IndexedTab enddate = startdate + Month(months)-Day(1) subMastercalendar = MasterCalendar(mastercalendar,startdate,enddate) - - -# TODO tilføj gruppering igen - #TODO input all the . notificatons - sub = Model(with_optimizer(Gurobi.Optimizer,OutputFlag=0)) @variable(sub,xvars[v in V,d in Dv[v].d,j in Jd[d].j,i in I[d,j].i],Bin) @variable(sub,yvars[j = J],Bin) @@ -115,7 +110,7 @@ function solveSub!(sub,ϕ,θ,κ) optimize!(sub.model) status = termination_status(sub.model) if status != MOI.TerminationStatusCode(1) - println("$(minimum(sub.J)) - $(maximum(sub.J))") + throw("Error: Non optimal sub-problem for subproblem $(sub.intID)") #TODO Throw warning and extend search area