Skip to content

Commit

Permalink
feat: pert calculation
Browse files Browse the repository at this point in the history
  • Loading branch information
moul committed Jun 30, 2019
1 parent ec34c79 commit 42d41a1
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 20 deletions.
10 changes: 9 additions & 1 deletion attr.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,18 @@ func (a Attrs) SetTitle(title string) Attrs {
}

func (a Attrs) SetPert(opt, real, pess float64) Attrs {
a["pert"] = PertAttrs{
a["pert"] = &PertAttrs{
Optimistic: opt,
Realistic: real,
Pessimistic: pess,
}
return a
}

func (a Attrs) GetPert() *PertAttrs {
pa, found := a["pert"]
if !found {
return nil
}
return pa.(*PertAttrs)
}
2 changes: 2 additions & 0 deletions edge.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ func newEdge(src, dst *Vertex, attrs ...Attrs) *Edge {
var a Attrs
if len(attrs) > 0 {
a = attrs[0]
} else {
a = make(map[string]interface{})
}
return &Edge{
src: src,
Expand Down
40 changes: 40 additions & 0 deletions pert.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package graphman

import (
"fmt"
"math"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -47,3 +48,42 @@ func prettyFloat(f float64) string {
out = strings.TrimRight(out, ".")
return out
}

type PertResult struct {
CriticalPathVariance float64
CriticalPathStandardDeviation float64
}

func (pr PertResult) String() string {
return fmt.Sprintf(
"Tσe=%s,TVe=%s",
prettyFloat(pr.CriticalPathStandardDeviation),
prettyFloat(pr.CriticalPathVariance),
)
}

func ComputePert(g *Graph) PertResult {
result := PertResult{}

// apply pert defaults before computing
for _, edge := range g.edges {
pa := edge.GetPert()
if pa == nil {
if edge.Attrs == nil {
edge.Attrs = make(map[string]interface{})
}
edge.SetPert(1, 1, 1)
pa = edge.GetPert()
}
if pa.Realistic == 0 {
pa.Realistic = 1
}
if pa.Pessimistic == 0 && pa.Optimistic == 0 {
pa.Pessimistic = pa.Realistic
pa.Optimistic = pa.Realistic
}
result.CriticalPathVariance += pa.Variance()
}
result.CriticalPathStandardDeviation = math.Sqrt(result.CriticalPathVariance)
return result
}
68 changes: 49 additions & 19 deletions pert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,58 @@ import (
"fmt"
)

func Example_pert() {
func ExamplePertResult_withValue() {
graph := New()
graph.AddEdge("1", "2", Attrs{}.SetTitle("a").SetPert(3, 6, 15))
graph.AddEdge("1", "3", Attrs{}.SetTitle("b").SetPert(2, 5, 14))
graph.AddEdge("1", "4", Attrs{}.SetTitle("c").SetPert(6, 12, 30))
graph.AddEdge("2", "5", Attrs{}.SetTitle("d").SetPert(2, 5, 8))
graph.AddEdge("2", "6", Attrs{}.SetTitle("e").SetPert(5, 11, 17))
graph.AddEdge("3", "6", Attrs{}.SetTitle("f").SetPert(3, 6, 15))
graph.AddEdge("4", "7", Attrs{}.SetTitle("g").SetPert(3, 9, 27))
graph.AddEdge("5", "7", Attrs{}.SetTitle("h").SetPert(1, 4, 7))
graph.AddEdge("6", "7", Attrs{}.SetTitle("i").SetPert(4, 19, 28))
graph.AddEdge("1", "2", Attrs{}.SetPert(3, 6, 15))
graph.AddEdge("1", "3", Attrs{}.SetPert(2, 5, 14))
graph.AddEdge("1", "4", Attrs{}.SetPert(6, 12, 30))
graph.AddEdge("2", "5", Attrs{}.SetPert(2, 5, 8))
graph.AddEdge("2", "6", Attrs{}.SetPert(5, 11, 17))
graph.AddEdge("3", "6", Attrs{}.SetPert(3, 6, 15))
graph.AddEdge("4", "7", Attrs{}.SetPert(3, 9, 27))
graph.AddEdge("5", "7", Attrs{}.SetPert(1, 4, 7))
graph.AddEdge("6", "7", Attrs{}.SetPert(4, 19, 28))

fmt.Println("graph before computing:")
for _, e := range graph.Edges() {
fmt.Println("*", e)
}
fmt.Println()

result := ComputePert(graph)
fmt.Println("graph after computing:")
for _, e := range graph.Edges() {
fmt.Println("*", e)
}
fmt.Println("result:", result)

// Output:
}

func ExamplePertResult_withoutValue() {
graph := New()
graph.AddEdge("1", "2")
graph.AddEdge("1", "3")
graph.AddEdge("1", "4")
graph.AddEdge("2", "5")
graph.AddEdge("2", "6")
graph.AddEdge("3", "6")
graph.AddEdge("4", "7")
graph.AddEdge("5", "7")
graph.AddEdge("6", "7")

fmt.Println("graph before computing:")
for _, e := range graph.Edges() {
fmt.Println("*", e)
}
fmt.Println()

result := ComputePert(graph)
fmt.Println("graph after computing:")
fmt.Println(result)
for _, e := range graph.Edges() {
fmt.Println("*", e)
}

// Output:
// * (1,2)[[pert:To=3,Tm=6,Tp=15,Te=7,σe=2,Ve=4,title:a]]
// * (1,3)[[pert:To=2,Tm=5,Tp=14,Te=6,σe=2,Ve=4,title:b]]
// * (1,4)[[pert:To=6,Tm=12,Tp=30,Te=14,σe=4,Ve=16,title:c]]
// * (2,5)[[pert:To=2,Tm=5,Tp=8,Te=5,σe=1,Ve=1,title:d]]
// * (2,6)[[pert:To=5,Tm=11,Tp=17,Te=11,σe=2,Ve=4,title:e]]
// * (3,6)[[pert:To=3,Tm=6,Tp=15,Te=7,σe=2,Ve=4,title:f]]
// * (4,7)[[pert:To=3,Tm=9,Tp=27,Te=11,σe=4,Ve=16,title:g]]
// * (5,7)[[pert:To=1,Tm=4,Tp=7,Te=4,σe=1,Ve=1,title:h]]
// * (6,7)[[pert:To=4,Tm=19,Tp=28,Te=18,σe=4,Ve=16,title:i]]
}
2 changes: 2 additions & 0 deletions vertex.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ func newVertex(id string, attrs ...Attrs) *Vertex {
var a Attrs
if len(attrs) > 0 {
a = attrs[0]
} else {
a = make(map[string]interface{})
}
return &Vertex{
id: id,
Expand Down

0 comments on commit 42d41a1

Please sign in to comment.