Skip to content

Commit

Permalink
add makespan() for calculating elapsed time in Johnson's Rule
Browse files Browse the repository at this point in the history
  • Loading branch information
jbytecode committed May 21, 2024
1 parent 58f4349 commit 6d3705b
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 27 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### 0.2.1 (Upcoming Release)

- Typed Inf used instead of Inf64 in Johnson's rule.
- Implement makespan for Johnson's rule.


### 0.2.1
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,15 @@ julia> result.path

```


## Johnson's Rule for Job Scheduling (Ordering) Problems

Function `johnson()` implements 2-machine, 3-machine, and $n$-machine versions of the Johnson's Rule.
If possible, the problem with higher number of machines can be transformed into 2-machine problems.
`makespan()` function calculates the total time elapsed in the production. Please see the documentation
for details.


## Simplex with iterations

Suppose the problem is
Expand Down
5 changes: 5 additions & 0 deletions docs/src/algorithms.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,8 @@ OperationsResearchModels.solve(p::KnapsackProblem)
```@docs
OperationsResearchModels.johnsons
```

### Makespan
```@docs
OperationsResearchModels.makespan
```
4 changes: 2 additions & 2 deletions src/OperationsResearchModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ import .CPM: CpmActivity, earliestfinishtime, longestactivity, CpmProblem, CpmRe
import .CPM: PertActivity, PertProblem, PertResult
import .Knapsack: KnapsackResult, KnapsackProblem
import .Latex: latex
import .Johnsons: JohnsonResult, johnsons, JohnsonException
import .Johnsons: JohnsonResult, johnsons, JohnsonException, makespan

export TransportationProblem, TransportationResult, balance, isbalanced, northwestcorner
export Connection, ShortestPathResult, MaximumFlowResult, nodes
Expand All @@ -65,7 +65,7 @@ export KnapsackResult, KnapsackProblem
export Simplex
export Utility
export latex
export JohnsonResult, johnsons, JohnsonException
export JohnsonResult, johnsons, JohnsonException, makespan

export JuMP, HiGHS

Expand Down
75 changes: 74 additions & 1 deletion src/johnsons.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
module Johnsons

export JohnsonResult, JohnsonException, johnsons
export JohnsonResult
export JohnsonException
export johnsons
export makespan


# TODO: Add makespan calculation

Expand All @@ -14,6 +18,13 @@ struct JohnsonResult
# makespan::Float64
end

struct Process
start
duration
finish
end




"""
Expand Down Expand Up @@ -127,4 +138,66 @@ function johnsons_nmachines(times::Matrix)::JohnsonResult
return johnsons_2machines([G H])
end




"""
makespan(times::Matrix, permutation::Vector{Int})
Given a matrix of times and a permutation of the jobs, returns the makespan of the jobs.
# Arguments
- `times::Matrix`: a matrix of times
- `permutation::Vector{Int}`: a permutation of the jobs
# Returns
- `Float64`: the makespan of the jobs
# Example
```julia
julia> times = Float64[
3 3 5;
8 4 8;
7 2 10;
5 1 7;
2 5 6
]
julia> result = makespan(times, [1, 4, 5, 3, 2])
```
"""
function makespan(times::Matrix, permutation::Vector{Int})::Float64

n, m = size(times)

timetable = Array{Process,2}(undef, m, n)

for machine_id in 1:m
for task_id in 1:n
current_task = permutation[task_id]
if machine_id == 1
if task_id == 1
start = 0
else
start = timetable[machine_id, task_id-1].finish
end
else
if task_id == 1
start = timetable[machine_id-1, task_id].finish
else
start = max(timetable[machine_id, task_id-1].finish, timetable[machine_id-1, task_id].finish)
end
end
duration = times[current_task, machine_id]
finish = start + duration
timetable[machine_id, task_id] = Process(start, duration, finish)
end
end

return timetable[end, end].finish
end

end # end of module Johnsons
103 changes: 79 additions & 24 deletions test/testjohnsons.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
end


@testset "Example 2 with 2-machines" begin
@testset "Example 2 with 2-machines" begin
times = Float64[
4 7;
8 3;
Expand All @@ -29,80 +29,135 @@

result = johnsons(times)

time_elapsed = makespan(times, result.permutation)

@test result.permutation == [1, 3, 5, 6, 4, 2]
end

@test time_elapsed == 41
end
end


@testset "Three machines" verbose = true begin
@testset "Three machines" verbose = true begin

@testset "Example 1 for 3-machines" begin
@testset "Example 1 for 3-machines" begin

times = Float64[
3 3 5;
8 4 8;
7 2 10;
5 1 7;
2 5 6
2 5 6
]

result = johnsons(times)

time_elapsed = makespan(times, result.permutation)

@test result.permutation == [1, 4, 5, 3, 2]
end
end

@test time_elapsed == 42
end
end


@testset "Five machines" verbose = true begin
@testset "Five machines" verbose = true begin

@testset "Example 1 for 5-machines" begin
@testset "Example 1 for 5-machines" begin

times = Float64[
7 5 2 3 9;
6 6 4 5 10;
5 4 5 6 8;
8 3 3 2 6
8 3 3 2 6
]

result = johnsons(times)

time_elapsed = makespan(times, result.permutation)

@test result.permutation == [1, 3, 2, 4]
end

@test time_elapsed == 51
end
end


@testset "Cannot reduce to 2-machines" begin
@testset "Cannot reduce to 2-machines" begin

times = Float64[
3 3 5 2;
8 4 8 3;
7 2 10 4;
5 1 7 5;
2 5 6 6
]
times = Float64[
3 3 5 2;
8 4 8 3;
7 2 10 4;
5 1 7 5;
2 5 6 6
]

@test_throws JohnsonException johnsons(times)
@test_throws JohnsonException johnsons(times)

end

@testset "Other types of matrices (Int)" begin
@testset "Other types of matrices (Int)" begin

mat = rand(1:10, 10, 2)

result = johnsons(mat)

# expect no error
@test true
end
end

@testset "Other types of matrices (UInt8)" begin
@testset "Other types of matrices (UInt8)" begin

mat = convert(Array{UInt8, 2}, rand(1:10, 10, 2))
mat = convert(Array{UInt8,2}, rand(1:10, 10, 2))

result = johnsons(mat)

# expect no error
@test true
end



@testset "makespan" begin

best_permutation = [1, 4, 5, 3, 2]
best_makespan = 42


times = Float64[
3 3 5;
8 4 8;
7 2 10;
5 1 7;
2 5 6
]


ms = Float64[
makespan(times, [1, 2, 3, 4, 5]),
makespan(times, [1, 2, 3, 5, 4]),
makespan(times, [1, 2, 4, 3, 5]),
makespan(times, [1, 2, 4, 5, 3]),
makespan(times, [1, 2, 5, 3, 4]),
makespan(times, [1, 2, 5, 4, 3]),
makespan(times, [1, 3, 2, 4, 5]),
makespan(times, [1, 3, 2, 5, 4]),
makespan(times, [1, 3, 4, 2, 5]),
makespan(times, [1, 3, 4, 5, 2]),
makespan(times, [1, 3, 5, 2, 4]),
makespan(times, [1, 3, 5, 4, 2]),
makespan(times, [1, 4, 2, 3, 5]),
makespan(times, [1, 4, 2, 5, 3]),
makespan(times, [1, 4, 3, 2, 5]),
makespan(times, [1, 4, 3, 5, 2]),
makespan(times, [1, 4, 5, 2, 3]),
makespan(times, [1, 4, 5, 3, 2])
]

@test minimum(ms) == best_makespan
end



end

0 comments on commit 6d3705b

Please sign in to comment.