Skip to content

Commit

Permalink
Merge pull request #30 from nulab/dev-29/upgrade-go-1.23
Browse files Browse the repository at this point in the history
Dev 29/upgrade go 1.23
  • Loading branch information
vibridi authored Oct 1, 2024
2 parents d470725 + 928dd13 commit 30f1943
Show file tree
Hide file tree
Showing 23 changed files with 194 additions and 252 deletions.
8 changes: 1 addition & 7 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
module github.com/nulab/autog

go 1.22.4

toolchain go1.22.7
go 1.23.1

require github.com/stretchr/testify v1.8.4

replace github.com/vibridi/graphify => ../../vibridi/graphify

require (
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/vibridi/graphify v0.0.0-20240926092405-5791dfe773cb // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
31 changes: 0 additions & 31 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,41 +1,10 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/vibridi/graphify v0.0.0-20240926092405-5791dfe773cb h1:vJaelmTCdGCWuUUmERFznS6843ewGv4MGKv8nOETyt4=
github.com/vibridi/graphify v0.0.0-20240926092405-5791dfe773cb/go.mod h1:ClQsJC5L+MO0eABQoEJBx8EXSxi++0VrUuIYXcYeViY=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
3 changes: 0 additions & 3 deletions internal/geom/spline.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,6 @@ func FitSpline(path []P, tanv1, tanv2 P, barriers []Segment) []ctrlp {
upperps := FitSpline(path[:k+1], tanv1, tanw, barriers)
lowerps := FitSpline(path[k:], tanw, tanv2, barriers)

// if upperps != nil && lowerps != nil {
// return append(upperps, lowerps...)
// }
return append(upperps, lowerps...)
}

Expand Down
35 changes: 19 additions & 16 deletions internal/graph/dgraph.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package graph

import (
"iter"
"strings"
)

type DGraph struct {
Nodes []*Node
Edges EdgeList
Layers Layers
Layers []*Layer
}

func (g *DGraph) Populate(*DGraph) {
Expand All @@ -25,28 +26,30 @@ func (g *DGraph) GetEdges() []*Edge {
return nil
}

// todo: sources and sinks don't yet account for isolated nodes with a self-loop

// Sources returns a list of nodes with no incoming edges
func (g *DGraph) Sources() []*Node {
var sources []*Node
for _, n := range g.Nodes {
if len(n.In) == 0 {
sources = append(sources, n)
// Sources returns a sequence of nodes with no incoming edges
func (g *DGraph) Sources() iter.Seq[*Node] {
return func(yield func(*Node) bool) {
for _, n := range g.Nodes {
if n.Indeg() == 0 {
if !yield(n) {
return
}
}
}
}
return sources
}

// Sinks returns a list of nodes with no outgoing edges
func (g *DGraph) Sinks() []*Node {
var sinks []*Node
for _, n := range g.Nodes {
if len(n.Out) == 0 {
sinks = append(sinks, n)
func (g *DGraph) Sinks() iter.Seq[*Node] {
return func(yield func(*Node) bool) {
for _, n := range g.Nodes {
if n.Outdeg() == 0 {
if !yield(n) {
return
}
}
}
}
return sinks
}

func (g *DGraph) String() string {
Expand Down
38 changes: 23 additions & 15 deletions internal/graph/edge.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,30 @@ func (e *Edge) Crosses(f *Edge) bool {
(etop.LayerPos > ftop.LayerPos && ebtm.LayerPos < fbtm.LayerPos)
}

// Type returns the edge type as follows:
// - 0: both of e's adjacent nodes are concrete nodes
// - 1: exactly one of e's adjacent nodes is virtual
// - 2: both of e's adjacent nodes are virtual
func (e *Edge) Type() int {
// todo: might return an enum instead
if !e.From.IsVirtual && !e.To.IsVirtual {
return 0
}
if e.From.IsVirtual != e.To.IsVirtual {
return 1
}
if e.From.IsVirtual && e.To.IsVirtual {
return 2
// EdgeType encodes information about the nodes adjacent to an edge,
type EdgeType uint8

const (
// EdgeTypeConcrete indicates a type 0 edge whose adjacent nodes are both non-virtual.
EdgeTypeConcrete EdgeType = iota
// EdgeTypeHybrid indicates a type 1 edge whose adjacent nodes are one virtual and one non-virtual.
EdgeTypeHybrid
// EdgeTypeVirtual indicates a type 2 edge whose adjacent nodes are both virtual.
EdgeTypeVirtual
)

// Type returns the edge's EdgeType
func (e *Edge) Type() EdgeType {
switch {
case !e.From.IsVirtual && !e.To.IsVirtual:
return EdgeTypeConcrete
case e.From.IsVirtual != e.To.IsVirtual:
return EdgeTypeHybrid
case e.From.IsVirtual && e.To.IsVirtual:
return EdgeTypeVirtual
default:
panic("edge type cases aren't exhaustive")
}
panic("edge type cases aren't exhaustive")
}

func (e *Edge) String() string {
Expand Down
2 changes: 0 additions & 2 deletions internal/graph/maps.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ type NodeSet = hashmap[*Node, bool]

type EdgeSet = hashmap[*Edge, bool]

type Layers = hashmap[int, *Layer]

func (m hashmap[K, V]) Clone() hashmap[K, V] {
return maps.Clone(m)
}
Expand Down
32 changes: 15 additions & 17 deletions internal/graph/node_iter.go
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
package graph

import "iter"

func (n *Node) VisitEdges(visit func(*Edge)) {
fn, next := n.allEdges()
for next {
next = fn(visit)
for e := range n.allEdges() {
visit(e)
}
}

func (n *Node) allEdges() (visitor func(func(*Edge)) bool, next bool) {
i := 0
visitor = func(yield func(*Edge)) bool {
if i >= len(n.In)+len(n.Out) {
return false
}
if i < len(n.In) {
yield(n.In[i])
} else {
yield(n.Out[i-len(n.In)])
func (n *Node) allEdges() iter.Seq[*Edge] {
return func(yield func(*Edge) bool) {
for i, b := 0, true; i < n.Deg(); i++ {
if i < n.Indeg() {
b = yield(n.In[i])
} else {
b = yield(n.Out[i-n.Indeg()])
}
if !b {
return
}
}
i++
return true
}
next = true
return
}
27 changes: 16 additions & 11 deletions internal/graph/node_iter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,27 @@ import (
)

func TestVisitEdges(t *testing.T) {
t.Skip()
ids := strings.Split("abcde", "")
es := []*Edge{}
for i := range ids {
es = append(es, &Edge{edge: edge{Delta: i}})
n := &Node{ID: "N"}
n.In = []*Edge{
{edge: edge{From: &Node{ID: "A1"}, To: n}},
{edge: edge{From: &Node{ID: "A2"}, To: n}},
{edge: edge{From: &Node{ID: "A3"}, To: n}},
}

n := &Node{
In: es[:3],
Out: es[3:],
n.Out = []*Edge{
{edge: edge{From: n, To: &Node{ID: "B1"}}},
{edge: edge{From: n, To: &Node{ID: "B2"}}},
{edge: edge{From: n, To: &Node{ID: "B3"}}},
{edge: edge{From: n, To: &Node{ID: "B4"}}},
}

i := 0
n.VisitEdges(func(e *Edge) {
assert.Equal(t, ids[i], i)
if i < 3 {
assert.True(t, strings.HasPrefix(e.From.ID, "A"))
} else {
assert.True(t, strings.HasPrefix(e.To.ID, "B"))
}
i++
})
assert.Equal(t, 5, i)
assert.Equal(t, 7, i)
}
11 changes: 3 additions & 8 deletions internal/phase1/dfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,19 @@ func execDepthFirst(g *graph.DGraph) {
active: make(graph.NodeSet),
}

// get list of source nodes (nodes with no incoming edge)
sources := g.Sources()

for _, node := range sources {
// process nodes with no incoming edge first
for node := range g.Sources() {
p.visit(node)
}

nodeCount := len(g.Nodes)
for i := 0; i < nodeCount; i++ {
node := g.Nodes[i]
for _, node := range g.Nodes {
if !p.visited[node] {
p.visit(node)
}
}

for _, e := range p.reversable {
e.Reverse()
// g.IsCyclic = true
}
}

Expand Down
5 changes: 3 additions & 2 deletions internal/phase1/greedy.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package phase1
import (
"math"
"math/rand"
"slices"
"time"

"github.com/nulab/autog/internal/graph"
Expand Down Expand Up @@ -37,8 +38,8 @@ func execGreedy(g *graph.DGraph, params graph.Params) {

nodeCount := len(g.Nodes)

sources := g.Sources()
sinks := g.Sinks()
sources := slices.Collect(g.Sources())
sinks := slices.Collect(g.Sinks())

// here ELK accounts for edge priority: particular edges that the user doesn't want to reverse
// can be assigned a non-zero priority; this will artificially increase the node's in-/out-degrees.
Expand Down
35 changes: 18 additions & 17 deletions internal/phase2/alg_process.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,27 +24,28 @@ func (alg Alg) Process(g *graph.DGraph, params graph.Params) {
}

initLayers:
m := map[int]*graph.Layer{}
size := 0
for _, n := range g.Nodes {
layer := m[n.Layer]
if layer == nil {
layer = &graph.Layer{Index: n.Layer}
}
layer.Nodes = append(layer.Nodes, n)
m[n.Layer] = layer
size = max(size, n.Layer)
}
g.Layers = m
fillLayers(g)
}
size += 1 // the highest layer index must fit in the slice too

ls := make([]*graph.Layer, size)

func fillLayers(g *graph.DGraph) {
highest := 0
for i := range g.Layers {
highest = max(highest, i)
for _, n := range g.Nodes {
l := ls[n.Layer]
if l == nil {
l = &graph.Layer{Index: n.Layer}
}
l.Nodes = append(l.Nodes, n)
ls[n.Layer] = l
}
for i := 0; i < highest; i++ {
_, ok := g.Layers[i]
if !ok {
g.Layers = ls

// fill layers
for i := range size {
l := g.Layers[i]
if l == nil {
g.Layers[i] = &graph.Layer{Index: i}
}
}
Expand Down
5 changes: 2 additions & 3 deletions internal/phase2/network_simplex.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package phase2

import (
"math"
"slices"

"github.com/nulab/autog/internal/graph"
)
Expand All @@ -11,8 +12,6 @@ type networkSimplexProcessor struct {
low graph.NodeIntMap // Gansner et al.: lowest postorder traversal number among nodes reachable from the input node
}

// todo: exec alg on single connected components?

// this implements a graph node layering algorithm, based on:
// - "Emden R. Gansner, Eleftherios Koutsofios, Stephen C. North, Kiem-Phong Vo, A technique for
// drawing directed graphs. Software Engineering 19(3), pp. 214-230, 1993."
Expand Down Expand Up @@ -129,7 +128,7 @@ func (p *networkSimplexProcessor) initLayers(g *graph.DGraph) {
}

// sources have layer 0
sources := g.Sources()
sources := slices.Collect(g.Sources())

for len(sources) > 0 {
n := sources[0]
Expand Down
Loading

0 comments on commit 30f1943

Please sign in to comment.