From e832353c2f65cc6b888d2f8960bd503d725c67fc Mon Sep 17 00:00:00 2001 From: "mhsatman@gmail.com" Date: Mon, 6 May 2024 20:50:49 +0300 Subject: [PATCH] make cpm and pert `solve()` compatible. --- CHANGELOG.md | 2 +- docs/src/algorithms.md | 10 ++++- src/OperationsResearchModels.jl | 8 ++-- src/cpm.jl | 72 ++++++++++++++++++++++++++++----- test/testcpm.jl | 11 ++++- test/testpert.jl | 13 ++++-- 6 files changed, 94 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 508bd72..b373083 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ - Iterations for single `solve()` method for many problems to provide a uniform way, e.g., `solve(p)` and `solve(r)` should work at the same time where `p` and `r` would be `TransportationProblem`, `AssignmentProblem`, `ShortestPathProblem`, `MaximumFlowProblem`, `MstProblem`, `KnapsackProblem`, etc. - In the release iterations, some of the methods will be removed so this release is planned to be a breaking one. - +- Make `cpm` and `pert` solvable using `solve(::CpmProblem)` and `solve(::PertProblem)`. ### 0.1.8 diff --git a/docs/src/algorithms.md b/docs/src/algorithms.md index 3a8457a..baa56f8 100644 --- a/docs/src/algorithms.md +++ b/docs/src/algorithms.md @@ -37,12 +37,18 @@ OperationsResearchModels.pmedian_with_distances ## CPM (Critical Path Method) ```@docs -OperationsResearchModels.cpm +OperationsResearchModels.solve(problem::CpmProblem) ``` +### CPM Activity +```@docs +OperationsResearchModels.CpmActivity +``` + + ## PERT (Project Evalutation and Review Technique) ```@docs -OperationsResearchModels.pert +OperationsResearchModels.solve(problem::PertProblem) ``` ## Knapsack diff --git a/src/OperationsResearchModels.jl b/src/OperationsResearchModels.jl index 8005f3b..932262b 100644 --- a/src/OperationsResearchModels.jl +++ b/src/OperationsResearchModels.jl @@ -48,8 +48,8 @@ import .Assignment: AssignmentProblem, AssignmentResult import .Game: game, GameResult import .MinimumSpanningTree: hasloop, MstResult, MstProblem import .PMedian: pmedian, pmedian_with_distances, PMedianResult -import .CPM: cpm, CpmActivity, earliestfinishtime, longestactivity, CpmResult -import .CPM: pert, PertActivity, PertResult +import .CPM: CpmActivity, earliestfinishtime, longestactivity, CpmProblem, CpmResult +import .CPM: PertActivity, PertProblem, PertResult import .Knapsack: KnapsackResult, KnapsackProblem import .Latex: latex @@ -60,8 +60,8 @@ export AssignmentProblem, AssignmentResult export game, GameResult export hasloop, MstResult, MstProblem export pmedian, pmedian_with_distances, PMedianResult -export cpm, CpmActivity, earliestfinishtime, longestactivity, CpmResult -export pert, PertActivity, PertResult +export CpmActivity, earliestfinishtime, longestactivity, CpmProblem, CpmResult +export PertActivity, PertProblem, PertResult export KnapsackResult, KnapsackProblem export Simplex export Utility diff --git a/src/cpm.jl b/src/cpm.jl index 46cbede..1d8def8 100644 --- a/src/cpm.jl +++ b/src/cpm.jl @@ -1,20 +1,46 @@ module CPM -export cpm +import ..OperationsResearchModels: solve + export CpmActivity +export CpmProblem export CpmResult export earliestfinishtime export longestactivity export PertActivity +export PertProblem export PertResult -export pert + +""" + CpmActivity(name::String, time::Float64, dependencies) + +# Description + +The object that represents an activity in CPM (Critical Path Method). + +# Arguments +- `name::String`: The name of the activity. +- `time::Float64`: The time of the activity. +- `dependencies`: The dependencies of the activity in type of `Vector{CpmActivity}`. + +# Example + +```julia +julia> A = CpmActivity("A", 2, []); +julia> B = CpmActivity("B", 3, []); +julia> C = CpmActivity("C", 2, [A, B]); +""" struct CpmActivity name::String time::Float64 dependencies::Vector{CpmActivity} end +struct CpmProblem + activities::Vector{CpmActivity} +end + struct CpmResult pathstr::Vector{String} path::Vector{CpmActivity} @@ -28,6 +54,10 @@ struct PertActivity dependencies::Vector{PertActivity} end +struct PertProblem + activities::Vector{PertActivity} +end + struct PertResult path::Vector{PertActivity} mean::Float64 @@ -86,18 +116,22 @@ function pathtostring(activities::Vector{CpmActivity})::Vector{String} end """ - cpm(activities) + solve(problem) # Arguments -- `activities::Vector{CpmActivity}` + +- `problem::CpmProblem`: The problem in type of CpmProblem. # Output + - `::CpmResult`: The object holds the results # Description + Calculates CPM (Critical Path Method) and reports the critical path for a given set of activities. # Example + ```julia julia> A = CpmActivity("A", 2); julia> B = CpmActivity("B", 3); @@ -112,7 +146,9 @@ julia> J = CpmActivity("J", 2, [C, D]); julia> activities = [A, B, C, D, E, F, G, H, I, J]; -julia> result = cpm(activities); +julia> problem = CpmProblem(activities); + +julia> result = solve(problem); julia> result.pathstr 4-element Vector{String}: @@ -125,7 +161,10 @@ julia> result.pathstr true ``` """ -function cpm(activities::Vector{CpmActivity})::CpmResult +function solve(problem::CpmProblem)::CpmResult + + activities = problem.activities + path = CpmActivity[] while true @@ -178,12 +217,13 @@ end """ - pert(activities) + solve(problem::PertProblem)::PertResult # Arguments -- `activities::Vector{PertActivity}`: Vector of Pert Activities. +- `problem::PertProblem`: The problem in type of PertProblem. # Example + ```julia julia> A = PertActivity("A", 1, 2, 3) PertActivity("A", 1.0, 2.0, 3.0, PertActivity[]) @@ -200,6 +240,8 @@ julia> activities = [A, B, C] PertActivity("B", 3.0, 3.0, 3.0, PertActivity[]) PertActivity("C", 5.0, 5.0, 5.0, PertActivity[PertActivity("A", 1.0, 2.0, 3.0, PertActivity[]), PertActivity("B", 3.0, 3.0, 3.0, PertActivity[])]) +julia> problem = PertProblem(activities); + julia> result = pert(activities) PertResult(PertActivity[PertActivity("B", 3.0, 3.0, 3.0, PertActivity[]), PertActivity("C", 5.0, 5.0, 5.0, PertActivity[PertActivity("A", 1.0, 2.0, 3.0, PertActivity[]), PertActivity("B", 3.0, 3.0, 3.0, PertActivity[])])], 8.0, 0.0) @@ -210,19 +252,29 @@ julia> result.stddev 0.0 ``` """ -function pert(activities::Vector{PertActivity}) +function solve(problem::PertProblem)::PertResult + + activities = problem.activities + L = length(activities) + cpmactivities = Array{CpmActivity,1}(undef, L) + for i = 1:L current::PertActivity = activities[i] cpmactivity = CpmActivity(current.name, mean(current), perttocpm.(current.dependencies)) cpmactivities[i] = cpmactivity end - cpmresult = cpm(cpmactivities) + + cpmresult = solve(CpmProblem(cpmactivities)) + pertpath = cpmresult.path + pertactivities = findpertactivities(pertpath, activities) + pertmean = sum(pertpath) + stddev = sqrt(var(pertactivities)) return PertResult(pertactivities, pertmean, stddev) diff --git a/test/testcpm.jl b/test/testcpm.jl index 6c248c8..5fe0951 100644 --- a/test/testcpm.jl +++ b/test/testcpm.jl @@ -30,7 +30,11 @@ activities = CpmActivity[A, B, C, D, E, F] - result = cpm(activities) + + problem = CpmProblem(activities) + + + result = solve(problem) @test result isa CpmResult @@ -52,7 +56,10 @@ J = CpmActivity("J", 2, [C, D]) activities = [A, B, C, D, E, F, G, H, I, J] - result = cpm(activities) + + problem = CpmProblem(activities) + + result = solve(problem) @test result.pathstr == ["B", "E", "G", "I"] @test result.path == [B, E, G, I] diff --git a/test/testpert.jl b/test/testpert.jl index 6a8a4b8..ea99067 100644 --- a/test/testpert.jl +++ b/test/testpert.jl @@ -6,7 +6,9 @@ activities = [A, B, C] - result::PertResult = pert(activities) + problem = PertProblem(activities) + + result::PertResult = solve(problem) @test result.mean == 8.0 @test result.stddev == 0.0 @@ -23,7 +25,9 @@ activities = [A, B, C] - result::PertResult = pert(activities) + problem = PertProblem(activities) + + result::PertResult = solve(problem) @test result.mean == 10.0 @test isapprox(result.stddev, 0.4714045207910317, atol = epsilon) @@ -49,7 +53,10 @@ activities = [A, B, C, D, E, F, G, H, I, J, K, L] - result = pert(activities) + + problem = PertProblem(activities) + + result = solve(problem) @test result isa PertResult @test result.mean == 22.5