Skip to content

Commit

Permalink
feat: initial version of pert simplifier
Browse files Browse the repository at this point in the history
  • Loading branch information
moul committed Jul 18, 2019
1 parent 614a84b commit 67255b5
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 18 deletions.
1 change: 1 addition & 0 deletions cmd/pertify/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8 h1:Ggy3mWN4l3PUFPfSG0YB3n5fVYggzysUmiUQ89SnX6Y=
gopkg.in/urfave/cli.v2 v2.0.0-20180128182452-d3ae77c26ac8/go.mod h1:cKXr3E0k4aosgycml1b5z33BVV6hai1Kh7uDgFOkbcs=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20190705120443-117fdf03f45f h1:nqBZgl3FUZD7Xe4yitNx/0mqkydzbl4Y89WSTjG6/ok=
gopkg.in/yaml.v3 v3.0.0-20190705120443-117fdf03f45f/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
4 changes: 4 additions & 0 deletions cmd/pertify/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ func main() {
&cli.BoolFlag{Name: "dot", Usage: "print 'dot' compatible output"},
&cli.BoolFlag{Name: "vertical", Usage: "displaying steps from top to bottom"},
&cli.BoolFlag{Name: "with-details", Usage: "Show pert numbers"},
&cli.BoolFlag{Name: "no-simplify", Usage: "Don't simplify the graph"},
&cli.BoolFlag{Name: "debug", Aliases: []string{"D"}, Usage: "verbose mode"},
},
Action: graph,
Expand All @@ -41,6 +42,9 @@ func graph(c *cli.Context) error {
return errors.Wrap(err, "failed to parse yaml file")
}

if c.Bool("no-simplify") {
config.Opts.NoSimplify = true
}
graph := graphman.FromPertConfig(config)
if c.Bool("debug") {
log.Println(graph)
Expand Down
12 changes: 11 additions & 1 deletion graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,16 @@ func (g *Graph) RemoveVertex(id string) bool {
return false
}

func (g *Graph) RemoveEdge(src, dst string) bool {
for k, v := range g.edges {
if v.src.id == src && v.dst.id == dst {
g.edges = append(g.edges[:k], g.edges[k+1:]...)
return true
}
}
return false
}

func (g Graph) GetVertex(id string) *Vertex {
for _, v := range g.vertices {
if v.id == id {
Expand All @@ -235,7 +245,7 @@ func (g *Graph) AddEdge(srcID, dstID string, attrs ...Attrs) *Edge {
dst := g.AddVertex(dstID)
edge := newEdge(src, dst, a)
src.successors = append(src.successors, edge)
dst.predecessors = append(src.predecessors, edge)
dst.predecessors = append(dst.predecessors, edge)
g.edges = append(g.edges, edge)
return edge
}
Expand Down
101 changes: 87 additions & 14 deletions pert_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,18 @@ type PertAction struct {
DependsOn []string `yaml:"depends_on"`
}

type PertState struct {
ID string `yaml:"id"`
Title string `yaml:"title"`
DependsOn []string `yaml:"depends_on"`
}

type PertConfig struct {
Actions []PertAction `yaml:"actions"`
States []PertState `yaml:"states"`
Opts struct {
NoSimplify bool `yaml:"simplify"`
} `yaml:"opts"`
}

const (
Expand All @@ -27,6 +37,21 @@ func FromPertConfig(config PertConfig) *Graph {
graph.AddVertex(pertStartVertex)
graph.AddVertex(pertFinishVertex)

for _, state := range config.States {
attrs := Attrs{}
if state.Title != "" {
attrs.SetTitle(state.Title)
}
graph.AddVertex(state.ID, attrs)
for _, dependency := range state.DependsOn {
graph.AddEdge(
pertPostID(dependency),
state.ID,
Attrs{}.SetPertZeroTimeActivity(),
)
}
}

for _, action := range config.Actions {
attrs := Attrs{}
if action.Title != "" {
Expand All @@ -46,27 +71,30 @@ func FromPertConfig(config PertConfig) *Graph {
}

// relationships
postCurrent := fmt.Sprintf("post_%s", action.ID)
switch len(action.DependsOn) {
case 0: // no dependency, linking with Start
graph.AddEdge(pertStartVertex, postCurrent, attrs)
graph.AddEdge(
pertStartVertex,
pertPostID(action.ID),
attrs,
)
case 1: // only one dependency
dependency := action.DependsOn[0]
graph.AddEdge(
fmt.Sprintf("post_%s", dependency),
postCurrent,
pertPostID(dependency),
pertPreID(action.ID),
attrs,
)
default:
graph.AddEdge(
fmt.Sprintf("pre_%s", action.ID),
postCurrent,
pertPreID(action.ID),
pertPostID(action.ID),
attrs,
)
for _, dependency := range action.DependsOn {
graph.AddEdge(
fmt.Sprintf("post_%s", dependency),
fmt.Sprintf("pre_%s", action.ID),
pertPostID(dependency),
pertPreID(action.ID),
Attrs{}.SetPertZeroTimeActivity(),
)
}
Expand All @@ -75,28 +103,73 @@ func FromPertConfig(config PertConfig) *Graph {

// link ending vertices with finish
for _, vertex := range graph.SinkVertices() {
if vertex.ID() == pertFinishVertex {
if vertex.id == pertFinishVertex {
continue
}
graph.AddEdge(
vertex.ID(),
vertex.id,
pertFinishVertex,
Attrs{}.SetPertZeroTimeActivity(),
)
}

// optimize
// FIXME: TODO

// nice names
for _, vertex := range graph.Vertices() {
if vertex.ID() == pertStartVertex || vertex.ID() == pertFinishVertex {
if vertex.id == pertStartVertex || vertex.id == pertFinishVertex {
continue
}
if vertex.Attrs.GetTitle() == "" {
vertex.Attrs.SetPertUntitledState()
}
}

for _, vertex := range graph.Vertices() {
if vertex.Attrs.GetTitle() == "" {
vertex.Attrs.SetTitle(vertex.id)
}
}
if !config.Opts.NoSimplify { // simplify the graph
verticesToDelete := map[string]bool{} // creating a map so we can iterate over vertices while deleting some entries
for _, vertex := range graph.Vertices() {
if pertIsUntitledState(vertex) || true {
if vertex.OutDegree() == 1 { // remove dummy states with only one dummy successor
successor := vertex.SuccessorEdges()[0]
if pertIsZeroTimeActivity(successor) {
for _, predecessor := range vertex.PredecessorEdges() {
predecessor.dst = successor.dst
}
graph.RemoveEdge(vertex.id, successor.dst.id)
verticesToDelete[vertex.id] = true
}
}
}
}
for id := range verticesToDelete {
graph.RemoveVertex(id)
}
}

return graph
}

func pertPreID(id string) string { return fmt.Sprintf("pre_%s", id) }
func pertPostID(id string) string { return fmt.Sprintf("post_%s", id) }

func pertIsZeroTimeActivity(edge *Edge) bool {
pert := edge.GetPert()
return pert != nil && pert.IsZeroTimeActivity
}

func pertIsUntitledState(vertex *Vertex) bool {
pert := vertex.GetPert()
return pert != nil && pert.IsUntitledState
}

func isMarkedAsDeleted(attrs Attrs) bool {
val, found := attrs["__deleted"].(bool)
return found && val
}

func markAsDeleted(attrs Attrs) {
attrs["__deleted"] = true
}
7 changes: 4 additions & 3 deletions viz/graphviz.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ func ToGraphviz(g *graphman.Graph, opts *Opts) (string, error) {
for _, vertex := range g.Vertices() {
if err := gv.AddNode(
"G",
vertex.ID(),
escape(vertex.ID()),
attrsFromVertex(vertex, opts),
); err != nil {
return "", err
}
}
for _, edge := range g.Edges() {
if err := gv.AddEdge(
edge.Src().ID(),
edge.Dst().ID(),
escape(edge.Src().ID()),
escape(edge.Dst().ID()),
true,
attrsFromEdge(edge, opts),
); err != nil {
Expand All @@ -65,6 +65,7 @@ func attrsFromVertex(vertex *graphman.Vertex, opts *Opts) map[string]string {
if pert.IsUntitledState {
attrs[string(graphviz.Label)] = " "
attrs[string(graphviz.Shape)] = "circle"
// attrs[string(graphviz.Style)] = "dashed"
}
}
attrsGeneric(vertex.Attrs, attrs, opts)
Expand Down

0 comments on commit 67255b5

Please sign in to comment.