graph: use int64 for node retrieval

This commit is contained in:
Dan Kortschak
2018-03-24 09:21:44 +10:30
committed by GitHub
parent f0b07f8621
commit 6b03bc22e1
93 changed files with 1174 additions and 1116 deletions

View File

@@ -62,7 +62,7 @@ func init() {
friends = simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range middleEast.friends {
// Ensure unconnected nodes are included.
if !friends.Has(simple.Node(u)) {
if !friends.Has(int64(u)) {
friends.AddNode(simple.Node(u))
}
for v := range e {
@@ -72,7 +72,7 @@ func init() {
enemies = simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range middleEast.enemies {
// Ensure unconnected nodes are included.
if !enemies.Has(simple.Node(u)) {
if !enemies.Has(int64(u)) {
enemies.AddNode(simple.Node(u))
}
for v := range e {
@@ -127,7 +127,7 @@ func TestProfileUndirected(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -144,7 +144,7 @@ func TestProfileWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -186,7 +186,7 @@ func TestProfileDirected(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -203,7 +203,7 @@ func TestProfileWeightedDirected(t *testing.T) {
g := simple.NewWeightedDirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -111,7 +111,7 @@ func TestKCliqueCommunities(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -359,10 +359,10 @@ const (
// positiveWeightFuncFor returns a constructed weight function for the
// positively weighted g. Unweighted graphs have unit weight for existing
// edges.
func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
func positiveWeightFuncFor(g graph.Graph) func(xid, yid int64) float64 {
if wg, ok := g.(graph.Weighted); ok {
return func(x, y graph.Node) float64 {
w, ok := wg.Weight(x, y)
return func(xid, yid int64) float64 {
w, ok := wg.Weight(xid, yid)
if !ok {
return 0
}
@@ -372,8 +372,8 @@ func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
return w
}
}
return func(x, y graph.Node) float64 {
e := g.Edge(x, y)
return func(xid, yid int64) float64 {
e := g.Edge(xid, yid)
if e == nil {
return 0
}
@@ -384,10 +384,10 @@ func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
// negativeWeightFuncFor returns a constructed weight function for the
// negatively weighted g. Unweighted graphs have unit weight for existing
// edges.
func negativeWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
func negativeWeightFuncFor(g graph.Graph) func(xid, yid int64) float64 {
if wg, ok := g.(graph.Weighted); ok {
return func(x, y graph.Node) float64 {
w, ok := wg.Weight(x, y)
return func(xid, yid int64) float64 {
w, ok := wg.Weight(xid, yid)
if !ok {
return 0
}
@@ -397,8 +397,8 @@ func negativeWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
return -w
}
}
return func(x, y graph.Node) float64 {
e := g.Edge(x, y)
return func(xid, yid int64) float64 {
e := g.Edge(xid, yid)
if e == nil {
return 0
}

View File

@@ -34,24 +34,28 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
for _, n := range nodes {
var wOut float64
u := n
for _, v := range g.From(u) {
wOut += weight(u, v)
uid := u.ID()
for _, v := range g.From(uid) {
wOut += weight(uid, v.ID())
}
var wIn float64
v := n
for _, u := range g.To(v) {
wIn += weight(u, v)
vid := v.ID()
for _, u := range g.To(vid) {
wIn += weight(u.ID(), vid)
}
w := weight(n, n)
id := n.ID()
w := weight(id, id)
m += w + wOut // We only need to count edges once.
k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
k[id] = directedWeights{out: w + wOut, in: w + wIn}
}
if communities == nil {
var q float64
for _, u := range nodes {
kU := k[u.ID()]
q += weight(u, u) - resolution*kU.out*kU.in/m
uid := u.ID()
kU := k[uid]
q += weight(uid, uid) - resolution*kU.out*kU.in/m
}
return q / m
}
@@ -59,10 +63,12 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
var q float64
for _, c := range communities {
for _, u := range c {
kU := k[u.ID()]
uid := u.ID()
kU := k[uid]
for _, v := range c {
kV := k[v.ID()]
q += weight(u, v) - resolution*kU.out*kV.in/m
vid := v.ID()
kV := k[vid]
q += weight(uid, vid) - resolution*kU.out*kV.in/m
}
}
}
@@ -203,23 +209,27 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
var out []int
u := n
for _, v := range g.From(u) {
vid := communityOf[v.ID()]
if vid != id {
out = append(out, vid)
uid := u.ID()
for _, v := range g.From(uid) {
vid := v.ID()
vcid := communityOf[vid]
if vcid != id {
out = append(out, vcid)
}
r.weights[[2]int{id, vid}] = weight(u, v)
r.weights[[2]int{id, vcid}] = weight(uid, vid)
}
r.edgesFrom[id] = out
var in []int
v := n
for _, u := range g.To(v) {
uid := communityOf[u.ID()]
if uid != id {
in = append(in, uid)
vid := v.ID()
for _, u := range g.To(vid) {
uid := u.ID()
ucid := communityOf[uid]
if ucid != id {
in = append(in, ucid)
}
r.weights[[2]int{uid, id}] = weight(u, v)
r.weights[[2]int{ucid, id}] = weight(uid, vid)
}
r.edgesTo[id] = in
}
@@ -270,43 +280,47 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
var out, in []int
for _, n := range comm {
u := n
uid := u.ID()
for _, v := range comm {
r.nodes[id].weight += weight(u, v)
r.nodes[id].weight += weight(uid, v.ID())
}
for _, v := range g.From(u) {
vid := communityOf[v.ID()]
for _, v := range g.From(uid) {
vid := v.ID()
vcid := communityOf[vid]
found := false
for _, e := range out {
if e == vid {
if e == vcid {
found = true
break
}
}
if !found && vid != id {
out = append(out, vid)
if !found && vcid != id {
out = append(out, vcid)
}
// Add half weights because the other
// ends of edges are also counted.
r.weights[[2]int{id, vid}] += weight(u, v) / 2
r.weights[[2]int{id, vcid}] += weight(uid, vid) / 2
}
v := n
for _, u := range g.To(v) {
uid := communityOf[u.ID()]
vid := v.ID()
for _, u := range g.To(vid) {
uid := u.ID()
ucid := communityOf[uid]
found := false
for _, e := range in {
if e == uid {
if e == ucid {
found = true
break
}
}
if !found && uid != id {
in = append(in, uid)
if !found && ucid != id {
in = append(in, ucid)
}
// Add half weights because the other
// ends of edges are also counted.
r.weights[[2]int{uid, id}] += weight(u, v) / 2
r.weights[[2]int{ucid, id}] += weight(uid, vid) / 2
}
}
r.edgesFrom[id] = out
@@ -316,8 +330,7 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
}
// Has returns whether the node exists within the graph.
func (g *ReducedDirected) Has(n graph.Node) bool {
id := n.ID()
func (g *ReducedDirected) Has(id int64) bool {
return 0 <= id && id < int64(len(g.nodes))
}
@@ -331,8 +344,8 @@ func (g *ReducedDirected) Nodes() []graph.Node {
}
// From returns all nodes in g that can be reached directly from u.
func (g *ReducedDirected) From(u graph.Node) []graph.Node {
out := g.edgesFrom[u.ID()]
func (g *ReducedDirected) From(uid int64) []graph.Node {
out := g.edgesFrom[uid]
nodes := make([]graph.Node, len(out))
for i, vid := range out {
nodes[i] = g.nodes[vid]
@@ -341,8 +354,8 @@ func (g *ReducedDirected) From(u graph.Node) []graph.Node {
}
// To returns all nodes in g that can reach directly to v.
func (g *ReducedDirected) To(v graph.Node) []graph.Node {
in := g.edgesTo[v.ID()]
func (g *ReducedDirected) To(vid int64) []graph.Node {
in := g.edgesTo[vid]
nodes := make([]graph.Node, len(in))
for i, uid := range in {
nodes[i] = g.nodes[uid]
@@ -351,9 +364,7 @@ func (g *ReducedDirected) To(v graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *ReducedDirected) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
yid := y.ID()
func (g *ReducedDirected) HasEdgeBetween(xid, yid int64) bool {
if xid == yid || !isValidID(xid) || !isValidID(yid) {
return false
}
@@ -366,9 +377,7 @@ func (g *ReducedDirected) HasEdgeBetween(x, y graph.Node) bool {
}
// HasEdgeFromTo returns whether an edge exists from node u to v.
func (g *ReducedDirected) HasEdgeFromTo(u, v graph.Node) bool {
uid := u.ID()
vid := v.ID()
func (g *ReducedDirected) HasEdgeFromTo(uid, vid int64) bool {
if uid == vid || !isValidID(uid) || !isValidID(vid) {
return false
}
@@ -378,15 +387,13 @@ func (g *ReducedDirected) HasEdgeFromTo(u, v graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *ReducedDirected) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdge(u, v)
func (g *ReducedDirected) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *ReducedDirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
uid := u.ID()
vid := v.ID()
func (g *ReducedDirected) WeightedEdge(uid, vid int64) graph.WeightedEdge {
if uid == vid || !isValidID(uid) || !isValidID(vid) {
return nil
}
@@ -401,9 +408,7 @@ func (g *ReducedDirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
// If x and y are the same node the internal node weight is returned. If there is no joining
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g *ReducedDirected) Weight(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
func (g *ReducedDirected) Weight(xid, yid int64) (w float64, ok bool) {
if !isValidID(xid) || !isValidID(yid) {
return 0, false
}
@@ -433,7 +438,7 @@ type directedLocalMover struct {
// that returns the Weight value
// of the non-nil edge between x
// and y.
weight func(x, y graph.Node) float64
weight func(xid, yid int64) float64
// communities is the current
// division of g.
@@ -484,18 +489,21 @@ func newDirectedLocalMover(g *ReducedDirected, communities [][]graph.Node, resol
for _, n := range l.nodes {
u := n
var wOut float64
for _, v := range g.From(u) {
wOut += l.weight(u, v)
uid := u.ID()
for _, v := range g.From(uid) {
wOut += l.weight(uid, v.ID())
}
v := n
var wIn float64
for _, u := range g.To(v) {
wIn += l.weight(u, v)
vid := v.ID()
for _, u := range g.To(vid) {
wIn += l.weight(u.ID(), vid)
}
w := l.weight(n, n)
l.edgeWeightsOf[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
id := n.ID()
w := l.weight(id, id)
l.edgeWeightsOf[id] = directedWeights{out: w + wOut, in: w + wIn}
l.m += w + wOut
}
@@ -562,7 +570,7 @@ func (l *directedLocalMover) move(dst int, src commIdx) {
func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
id := n.ID()
a_aa := l.weight(n, n)
a_aa := l.weight(id, id)
k_a := l.edgeWeightsOf[id]
m := l.m
gamma := l.resolution
@@ -613,8 +621,8 @@ func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src
removal = true
}
k_aC.in += l.weight(u, n)
k_aC.out += l.weight(n, u)
k_aC.in += l.weight(uid, id)
k_aC.out += l.weight(id, uid)
// sigma_totC could be kept for each community
// and updated for moves, changing the calculation
// of sigma_totC here from O(n_c) to O(1), but

View File

@@ -63,7 +63,7 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
layerResolution = resolutions[l]
}
var weight func(x, y graph.Node) float64
var weight func(xid, yid int64) float64
if layerWeight < 0 {
weight = negativeWeightFuncFor(layer)
} else {
@@ -77,15 +77,18 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
for _, n := range nodes {
var wOut float64
u := n
for _, v := range layer.From(u) {
wOut += weight(u, v)
uid := u.ID()
for _, v := range layer.From(uid) {
wOut += weight(uid, v.ID())
}
var wIn float64
v := n
for _, u := range layer.To(v) {
wIn += weight(u, v)
vid := v.ID()
for _, u := range layer.To(vid) {
wIn += weight(u.ID(), vid)
}
w := weight(n, n)
id := n.ID()
w := weight(id, id)
m += w + wOut // We only need to count edges once.
k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
}
@@ -93,8 +96,9 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
if communities == nil {
var qLayer float64
for _, u := range nodes {
kU := k[u.ID()]
qLayer += weight(u, u) - layerResolution*kU.out*kU.in/m
uid := u.ID()
kU := k[uid]
qLayer += weight(uid, uid) - layerResolution*kU.out*kU.in/m
}
q[l] = layerWeight * qLayer
continue
@@ -103,10 +107,12 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
var qLayer float64
for _, c := range communities {
for _, u := range c {
kU := k[u.ID()]
uid := u.ID()
kU := k[uid]
for _, v := range c {
kV := k[v.ID()]
qLayer += weight(u, v) - layerResolution*kU.out*kV.in/m
vid := v.ID()
kV := k[vid]
qLayer += weight(uid, vid) - layerResolution*kU.out*kV.in/m
}
}
}
@@ -321,7 +327,7 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
continue
}
var sign float64
var weight func(x, y graph.Node) float64
var weight func(xid, yid int64) float64
if w < 0 {
sign, weight = -1, negativeWeightFuncFor(layer)
} else {
@@ -332,23 +338,27 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
var out []int
u := n
for _, v := range layer.From(u) {
vid := communityOf[v.ID()]
if vid != id {
out = append(out, vid)
uid := u.ID()
for _, v := range layer.From(uid) {
vid := v.ID()
vcid := communityOf[vid]
if vcid != id {
out = append(out, vcid)
}
r.layers[l].weights[[2]int{id, vid}] = sign * weight(u, v)
r.layers[l].weights[[2]int{id, vcid}] = sign * weight(uid, vid)
}
r.layers[l].edgesFrom[id] = out
var in []int
v := n
for _, u := range layer.To(v) {
uid := communityOf[u.ID()]
if uid != id {
in = append(in, uid)
vid := v.ID()
for _, u := range layer.To(vid) {
uid := u.ID()
ucid := communityOf[uid]
if ucid != id {
in = append(in, ucid)
}
r.layers[l].weights[[2]int{uid, id}] = sign * weight(u, v)
r.layers[l].weights[[2]int{ucid, id}] = sign * weight(uid, vid)
}
r.layers[l].edgesTo[id] = in
}
@@ -408,7 +418,7 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
continue
}
var sign float64
var weight func(x, y graph.Node) float64
var weight func(xid, yid int64) float64
if w < 0 {
sign, weight = -1, negativeWeightFuncFor(layer)
} else {
@@ -418,43 +428,47 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
var out, in []int
for _, n := range comm {
u := n
uid := u.ID()
for _, v := range comm {
r.nodes[id].weights[l] += sign * weight(u, v)
r.nodes[id].weights[l] += sign * weight(uid, v.ID())
}
for _, v := range layer.From(u) {
vid := communityOf[v.ID()]
for _, v := range layer.From(uid) {
vid := v.ID()
vcid := communityOf[vid]
found := false
for _, e := range out {
if e == vid {
if e == vcid {
found = true
break
}
}
if !found && vid != id {
out = append(out, vid)
if !found && vcid != id {
out = append(out, vcid)
}
// Add half weights because the other
// ends of edges are also counted.
r.layers[l].weights[[2]int{id, vid}] += sign * weight(u, v) / 2
r.layers[l].weights[[2]int{id, vcid}] += sign * weight(uid, vid) / 2
}
v := n
for _, u := range layer.To(v) {
uid := communityOf[u.ID()]
vid := v.ID()
for _, u := range layer.To(vid) {
uid := u.ID()
ucid := communityOf[uid]
found := false
for _, e := range in {
if e == uid {
if e == ucid {
found = true
break
}
}
if !found && uid != id {
in = append(in, uid)
if !found && ucid != id {
in = append(in, ucid)
}
// Add half weights because the other
// ends of edges are also counted.
r.layers[l].weights[[2]int{uid, id}] += sign * weight(u, v) / 2
r.layers[l].weights[[2]int{ucid, id}] += sign * weight(uid, vid) / 2
}
}
@@ -478,8 +492,7 @@ type directedLayerHandle struct {
}
// Has returns whether the node exists within the graph.
func (g directedLayerHandle) Has(n graph.Node) bool {
id := n.ID()
func (g directedLayerHandle) Has(id int64) bool {
return 0 <= id && id < int64(len(g.multiplex.nodes))
}
@@ -493,8 +506,8 @@ func (g directedLayerHandle) Nodes() []graph.Node {
}
// From returns all nodes in g that can be reached directly from u.
func (g directedLayerHandle) From(u graph.Node) []graph.Node {
out := g.multiplex.layers[g.layer].edgesFrom[u.ID()]
func (g directedLayerHandle) From(uid int64) []graph.Node {
out := g.multiplex.layers[g.layer].edgesFrom[uid]
nodes := make([]graph.Node, len(out))
for i, vid := range out {
nodes[i] = g.multiplex.nodes[vid]
@@ -503,8 +516,8 @@ func (g directedLayerHandle) From(u graph.Node) []graph.Node {
}
// To returns all nodes in g that can reach directly to v.
func (g directedLayerHandle) To(v graph.Node) []graph.Node {
in := g.multiplex.layers[g.layer].edgesTo[v.ID()]
func (g directedLayerHandle) To(vid int64) []graph.Node {
in := g.multiplex.layers[g.layer].edgesTo[vid]
nodes := make([]graph.Node, len(in))
for i, uid := range in {
nodes[i] = g.multiplex.nodes[uid]
@@ -513,9 +526,7 @@ func (g directedLayerHandle) To(v graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g directedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
yid := y.ID()
func (g directedLayerHandle) HasEdgeBetween(xid, yid int64) bool {
if xid == yid {
return false
}
@@ -531,9 +542,7 @@ func (g directedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
}
// HasEdgeFromTo returns whether an edge exists from node u to v.
func (g directedLayerHandle) HasEdgeFromTo(u, v graph.Node) bool {
uid := u.ID()
vid := v.ID()
func (g directedLayerHandle) HasEdgeFromTo(uid, vid int64) bool {
if uid == vid || !isValidID(uid) || !isValidID(vid) {
return false
}
@@ -543,15 +552,13 @@ func (g directedLayerHandle) HasEdgeFromTo(u, v graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g directedLayerHandle) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdge(u, v)
func (g directedLayerHandle) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g directedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
uid := u.ID()
vid := v.ID()
func (g directedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge {
if uid == vid || !isValidID(uid) || !isValidID(vid) {
return nil
}
@@ -559,16 +566,14 @@ func (g directedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
if !ok {
return nil
}
return multiplexEdge{from: g.multiplex.nodes[u.ID()], to: g.multiplex.nodes[v.ID()], weight: w}
return multiplexEdge{from: g.multiplex.nodes[uid], to: g.multiplex.nodes[vid], weight: w}
}
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
// If x and y are the same node the internal node weight is returned. If there is no joining
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g directedLayerHandle) Weight(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
func (g directedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) {
if !isValidID(xid) || !isValidID(yid) {
return 0, false
}
@@ -598,7 +603,7 @@ type directedMultiplexLocalMover struct {
// that returns the Weight value
// of the non-nil edge between x
// and y.
weight []func(x, y graph.Node) float64
weight []func(xid, yid int64) float64
// communities is the current
// division of g.
@@ -648,7 +653,7 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
memberships: make([]int, len(nodes)),
resolutions: resolutions,
weights: weights,
weight: make([]func(x, y graph.Node) float64, g.Depth()),
weight: make([]func(xid, yid int64) float64, g.Depth()),
}
// Calculate the total edge weight of the graph
@@ -656,7 +661,7 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
var zero int
for i := 0; i < g.Depth(); i++ {
l.edgeWeightsOf[i] = make([]directedWeights, len(nodes))
var weight func(x, y graph.Node) float64
var weight func(xid, yid int64) float64
if weights != nil {
if weights[i] == 0 {
@@ -677,19 +682,22 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
layer := g.Layer(i)
for _, n := range l.nodes {
u := n
uid := u.ID()
var wOut float64
for _, v := range layer.From(u) {
wOut += weight(u, v)
for _, v := range layer.From(uid) {
wOut += weight(uid, v.ID())
}
v := n
vid := v.ID()
var wIn float64
for _, u := range layer.To(v) {
wIn += weight(u, v)
for _, u := range layer.To(vid) {
wIn += weight(u.ID(), vid)
}
w := weight(n, n)
l.edgeWeightsOf[i][u.ID()] = directedWeights{out: w + wOut, in: w + wIn}
id := n.ID()
w := weight(id, id)
l.edgeWeightsOf[i][uid] = directedWeights{out: w + wOut, in: w + wIn}
l.m[i] += w + wOut
}
if l.m[i] == 0 {
@@ -836,8 +844,8 @@ func (l *directedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst
removal = true
}
k_aC.in += l.weight[layer](n, u)
k_aC.out += l.weight[layer](u, n)
k_aC.in += l.weight[layer](id, uid)
k_aC.out += l.weight[layer](uid, id)
// sigma_totC could be kept for each community
// and updated for moves, changing the calculation
// of sigma_totC here from O(n_c) to O(1), but
@@ -849,7 +857,7 @@ func (l *directedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst
sigma_totC.out += w.out
}
a_aa := l.weight[layer](n, n)
a_aa := l.weight[layer](id, id)
k_a := l.edgeWeightsOf[layer][id]
gamma := 1.0
if l.resolutions != nil {

View File

@@ -390,7 +390,7 @@ tests:
}
layer := g.Layer(l)
for n := range c {
if layer.HasEdgeBetween(simple.Node(n), target) {
if layer.HasEdgeBetween(int64(n), target.ID()) {
connected = true
break search
}
@@ -701,7 +701,7 @@ func directedMultiplexFrom(raw []layer) (DirectedLayers, []float64, error) {
g := simple.NewWeightedDirectedGraph(0, 0)
for u, e := range l.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -204,7 +204,7 @@ func TestCommunityQDirected(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -221,7 +221,7 @@ func TestCommunityQWeightedDirected(t *testing.T) {
g := simple.NewWeightedDirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -257,7 +257,7 @@ func TestCommunityDeltaQDirected(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -274,7 +274,7 @@ func TestCommunityDeltaQWeightedDirected(t *testing.T) {
g := simple.NewWeightedDirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -338,7 +338,7 @@ func testCommunityDeltaQDirected(t *testing.T, test communityDirectedQTest, g gr
}
connected := false
for n := range c {
if g.HasEdgeBetween(simple.Node(n), target) {
if g.HasEdgeBetween(int64(n), target.ID()) {
connected = true
break
}
@@ -382,7 +382,7 @@ func TestReduceQConsistencyDirected(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -399,7 +399,7 @@ func TestReduceQConsistencyWeightedDirected(t *testing.T) {
g := simple.NewWeightedDirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -500,7 +500,7 @@ func TestMoveLocalDirected(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -517,7 +517,7 @@ func TestMoveLocalWeightedDirected(t *testing.T) {
g := simple.NewWeightedDirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -562,7 +562,7 @@ func TestModularizeDirected(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -579,7 +579,7 @@ func TestModularizeWeightedDirected(t *testing.T) {
g := simple.NewWeightedDirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -34,19 +34,21 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
var m2 float64
k := make(map[int64]float64, len(nodes))
for _, u := range nodes {
w := weight(u, u)
for _, v := range g.From(u) {
w += weight(u, v)
uid := u.ID()
w := weight(uid, uid)
for _, v := range g.From(uid) {
w += weight(uid, v.ID())
}
m2 += w
k[u.ID()] = w
k[uid] = w
}
if communities == nil {
var q float64
for _, u := range nodes {
kU := k[u.ID()]
q += weight(u, u) - resolution*kU*kU/m2
uid := u.ID()
kU := k[uid]
q += weight(uid, uid) - resolution*kU*kU/m2
}
return q / m2
}
@@ -57,10 +59,12 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
var q float64
for _, c := range communities {
for i, u := range c {
kU := k[u.ID()]
q += weight(u, u) - resolution*kU*kU/m2
uid := u.ID()
kU := k[uid]
q += weight(uid, uid) - resolution*kU*kU/m2
for _, v := range c[i+1:] {
q += 2 * (weight(u, v) - resolution*kU*k[v.ID()]/m2)
vid := v.ID()
q += 2 * (weight(uid, vid) - resolution*kU*k[vid]/m2)
}
}
}
@@ -198,19 +202,21 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
communityOf[n.ID()] = i
}
for _, u := range nodes {
uid := u.ID()
ucid := communityOf[uid]
var out []int
uid := communityOf[u.ID()]
for _, v := range g.From(u) {
vid := communityOf[v.ID()]
if vid != uid {
out = append(out, vid)
for _, v := range g.From(uid) {
vid := v.ID()
vcid := communityOf[vid]
if vcid != ucid {
out = append(out, vcid)
}
if uid < vid {
if ucid < vcid {
// Only store the weight once.
r.weights[[2]int{uid, vid}] = weight(u, v)
r.weights[[2]int{ucid, vcid}] = weight(uid, vid)
}
}
r.edges[uid] = out
r.edges[ucid] = out
}
return &r
}
@@ -254,39 +260,40 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
communityOf[n.ID()] = i
}
}
for uid, comm := range communities {
for ucid, comm := range communities {
var out []int
for i, u := range comm {
r.nodes[uid].weight += weight(u, u)
uid := u.ID()
r.nodes[ucid].weight += weight(uid, uid)
for _, v := range comm[i+1:] {
r.nodes[uid].weight += 2 * weight(u, v)
r.nodes[ucid].weight += 2 * weight(uid, v.ID())
}
for _, v := range g.From(u) {
vid := communityOf[v.ID()]
for _, v := range g.From(uid) {
vid := v.ID()
vcid := communityOf[vid]
found := false
for _, e := range out {
if e == vid {
if e == vcid {
found = true
break
}
}
if !found && vid != uid {
out = append(out, vid)
if !found && vcid != ucid {
out = append(out, vcid)
}
if uid < vid {
if ucid < vcid {
// Only store the weight once.
r.weights[[2]int{uid, vid}] += weight(u, v)
r.weights[[2]int{ucid, vcid}] += weight(uid, vid)
}
}
}
r.edges[uid] = out
r.edges[ucid] = out
}
return &r
}
// Has returns whether the node exists within the graph.
func (g *ReducedUndirected) Has(n graph.Node) bool {
id := n.ID()
func (g *ReducedUndirected) Has(id int64) bool {
return 0 <= id || id < int64(len(g.nodes))
}
@@ -300,8 +307,8 @@ func (g *ReducedUndirected) Nodes() []graph.Node {
}
// From returns all nodes in g that can be reached directly from u.
func (g *ReducedUndirected) From(u graph.Node) []graph.Node {
out := g.edges[u.ID()]
func (g *ReducedUndirected) From(uid int64) []graph.Node {
out := g.edges[uid]
nodes := make([]graph.Node, len(out))
for i, vid := range out {
nodes[i] = g.nodes[vid]
@@ -310,9 +317,7 @@ func (g *ReducedUndirected) From(u graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *ReducedUndirected) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
yid := y.ID()
func (g *ReducedUndirected) HasEdgeBetween(xid, yid int64) bool {
if xid == yid || !isValidID(xid) || !isValidID(yid) {
return false
}
@@ -325,25 +330,23 @@ func (g *ReducedUndirected) HasEdgeBetween(x, y graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *ReducedUndirected) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdgeBetween(u, v)
func (g *ReducedUndirected) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *ReducedUndirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v)
func (g *ReducedUndirected) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(uid, vid)
}
// EdgeBetween returns the edge between nodes x and y.
func (g *ReducedUndirected) EdgeBetween(x, y graph.Node) graph.Edge {
return g.WeightedEdgeBetween(x, y)
func (g *ReducedUndirected) EdgeBetween(xid, yid int64) graph.Edge {
return g.WeightedEdgeBetween(xid, yid)
}
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *ReducedUndirected) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
xid := x.ID()
yid := y.ID()
func (g *ReducedUndirected) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
if xid == yid || !isValidID(xid) || !isValidID(yid) {
return nil
}
@@ -354,16 +357,14 @@ func (g *ReducedUndirected) WeightedEdgeBetween(x, y graph.Node) graph.WeightedE
if !ok {
return nil
}
return edge{from: g.nodes[x.ID()], to: g.nodes[y.ID()], weight: w}
return edge{from: g.nodes[xid], to: g.nodes[yid], weight: w}
}
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
// If x and y are the same node the internal node weight is returned. If there is no joining
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g *ReducedUndirected) Weight(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
func (g *ReducedUndirected) Weight(xid, yid int64) (w float64, ok bool) {
if !isValidID(xid) || !isValidID(yid) {
return 0, false
}
@@ -396,7 +397,7 @@ type undirectedLocalMover struct {
// that returns the Weight value
// of the non-nil edge between x
// and y.
weight func(x, y graph.Node) float64
weight func(xid, yid int64) float64
// communities is the current
// division of g.
@@ -440,11 +441,12 @@ func newUndirectedLocalMover(g *ReducedUndirected, communities [][]graph.Node, r
// Calculate the total edge weight of the graph
// and degree weights for each node.
for _, u := range l.nodes {
w := l.weight(u, u)
for _, v := range g.From(u) {
w += l.weight(u, v)
uid := u.ID()
w := l.weight(uid, uid)
for _, v := range g.From(uid) {
w += l.weight(uid, v.ID())
}
l.edgeWeightOf[u.ID()] = w
l.edgeWeightOf[uid] = w
l.m2 += w
}
if l.m2 == 0 {
@@ -514,7 +516,7 @@ func (l *undirectedLocalMover) move(dst int, src commIdx) {
// is in communities.
func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
id := n.ID()
a_aa := l.weight(n, n)
a_aa := l.weight(id, id)
k_a := l.edgeWeightOf[id]
m2 := l.m2
gamma := l.resolution
@@ -559,7 +561,7 @@ func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, sr
removal = true
}
k_aC += l.weight(n, u)
k_aC += l.weight(id, uid)
// sigma_totC could be kept for each community
// and updated for moves, changing the calculation
// of sigma_totC here from O(n_c) to O(1), but

View File

@@ -66,7 +66,7 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
layerResolution = resolutions[l]
}
var weight func(x, y graph.Node) float64
var weight func(xid, yid int64) float64
if layerWeight < 0 {
weight = negativeWeightFuncFor(layer)
} else {
@@ -78,19 +78,21 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
var m2 float64
k := make(map[int64]float64, len(nodes))
for _, u := range nodes {
w := weight(u, u)
for _, v := range layer.From(u) {
w += weight(u, v)
uid := u.ID()
w := weight(uid, uid)
for _, v := range layer.From(uid) {
w += weight(uid, v.ID())
}
m2 += w
k[u.ID()] = w
k[uid] = w
}
if communities == nil {
var qLayer float64
for _, u := range nodes {
kU := k[u.ID()]
qLayer += weight(u, u) - layerResolution*kU*kU/m2
uid := u.ID()
kU := k[uid]
qLayer += weight(uid, uid) - layerResolution*kU*kU/m2
}
q[l] = layerWeight * qLayer
continue
@@ -102,10 +104,12 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
var qLayer float64
for _, c := range communities {
for i, u := range c {
kU := k[u.ID()]
qLayer += weight(u, u) - layerResolution*kU*kU/m2
uid := u.ID()
kU := k[uid]
qLayer += weight(uid, uid) - layerResolution*kU*kU/m2
for _, v := range c[i+1:] {
qLayer += 2 * (weight(u, v) - layerResolution*kU*k[v.ID()]/m2)
vid := v.ID()
qLayer += 2 * (weight(uid, vid) - layerResolution*kU*k[vid]/m2)
}
}
}
@@ -319,7 +323,7 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
continue
}
var sign float64
var weight func(x, y graph.Node) float64
var weight func(xid, yid int64) float64
if w < 0 {
sign, weight = -1, negativeWeightFuncFor(layer)
} else {
@@ -327,18 +331,20 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
}
for _, u := range nodes {
var out []int
uid := communityOf[u.ID()]
for _, v := range layer.From(u) {
vid := communityOf[v.ID()]
if vid != uid {
out = append(out, vid)
uid := u.ID()
ucid := communityOf[uid]
for _, v := range layer.From(uid) {
vid := v.ID()
vcid := communityOf[vid]
if vcid != ucid {
out = append(out, vcid)
}
if uid < vid {
if ucid < vcid {
// Only store the weight once.
r.layers[l].weights[[2]int{uid, vid}] = sign * weight(u, v)
r.layers[l].weights[[2]int{ucid, vcid}] = sign * weight(uid, vid)
}
}
r.layers[l].edges[uid] = out
r.layers[l].edges[ucid] = out
}
}
return &r
@@ -395,38 +401,40 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
continue
}
var sign float64
var weight func(x, y graph.Node) float64
var weight func(xid, yid int64) float64
if w < 0 {
sign, weight = -1, negativeWeightFuncFor(layer)
} else {
sign, weight = 1, positiveWeightFuncFor(layer)
}
for uid, comm := range communities {
for ucid, comm := range communities {
var out []int
for i, u := range comm {
r.nodes[uid].weights[l] += sign * weight(u, u)
uid := u.ID()
r.nodes[ucid].weights[l] += sign * weight(uid, uid)
for _, v := range comm[i+1:] {
r.nodes[uid].weights[l] += 2 * sign * weight(u, v)
r.nodes[ucid].weights[l] += 2 * sign * weight(uid, v.ID())
}
for _, v := range layer.From(u) {
vid := communityOf[v.ID()]
for _, v := range layer.From(uid) {
vid := v.ID()
vcid := communityOf[vid]
found := false
for _, e := range out {
if e == vid {
if e == vcid {
found = true
break
}
}
if !found && vid != uid {
out = append(out, vid)
if !found && vcid != ucid {
out = append(out, vcid)
}
if uid < vid {
if ucid < vcid {
// Only store the weight once.
r.layers[l].weights[[2]int{uid, vid}] += sign * weight(u, v)
r.layers[l].weights[[2]int{ucid, vcid}] += sign * weight(uid, vid)
}
}
}
r.layers[l].edges[uid] = out
r.layers[l].edges[ucid] = out
}
}
return &r
@@ -445,8 +453,7 @@ type undirectedLayerHandle struct {
}
// Has returns whether the node exists within the graph.
func (g undirectedLayerHandle) Has(n graph.Node) bool {
id := n.ID()
func (g undirectedLayerHandle) Has(id int64) bool {
return 0 <= id && id < int64(len(g.multiplex.nodes))
}
@@ -460,8 +467,8 @@ func (g undirectedLayerHandle) Nodes() []graph.Node {
}
// From returns all nodes in g that can be reached directly from u.
func (g undirectedLayerHandle) From(u graph.Node) []graph.Node {
out := g.multiplex.layers[g.layer].edges[u.ID()]
func (g undirectedLayerHandle) From(uid int64) []graph.Node {
out := g.multiplex.layers[g.layer].edges[uid]
nodes := make([]graph.Node, len(out))
for i, vid := range out {
nodes[i] = g.multiplex.nodes[vid]
@@ -470,9 +477,7 @@ func (g undirectedLayerHandle) From(u graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g undirectedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
yid := y.ID()
func (g undirectedLayerHandle) HasEdgeBetween(xid, yid int64) bool {
if xid == yid || !isValidID(xid) || !isValidID(yid) {
return false
}
@@ -485,25 +490,23 @@ func (g undirectedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g undirectedLayerHandle) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdgeBetween(u, v)
func (g undirectedLayerHandle) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g undirectedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v)
func (g undirectedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(uid, vid)
}
// EdgeBetween returns the edge between nodes x and y.
func (g undirectedLayerHandle) EdgeBetween(x, y graph.Node) graph.Edge {
return g.WeightedEdgeBetween(x, y)
func (g undirectedLayerHandle) EdgeBetween(xid, yid int64) graph.Edge {
return g.WeightedEdgeBetween(xid, yid)
}
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g undirectedLayerHandle) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
xid := x.ID()
yid := y.ID()
func (g undirectedLayerHandle) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
if xid == yid || !isValidID(xid) || !isValidID(yid) {
return nil
}
@@ -514,16 +517,14 @@ func (g undirectedLayerHandle) WeightedEdgeBetween(x, y graph.Node) graph.Weight
if !ok {
return nil
}
return multiplexEdge{from: g.multiplex.nodes[x.ID()], to: g.multiplex.nodes[y.ID()], weight: w}
return multiplexEdge{from: g.multiplex.nodes[xid], to: g.multiplex.nodes[yid], weight: w}
}
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
// If x and y are the same node the internal node weight is returned. If there is no joining
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g undirectedLayerHandle) Weight(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
func (g undirectedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) {
if !isValidID(xid) || !isValidID(yid) {
return 0, false
}
@@ -556,7 +557,7 @@ type undirectedMultiplexLocalMover struct {
// that returns the Weight value
// of the non-nil edge between x
// and y.
weight []func(x, y graph.Node) float64
weight []func(xid, yid int64) float64
// communities is the current
// division of g.
@@ -606,7 +607,7 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
memberships: make([]int, len(nodes)),
resolutions: resolutions,
weights: weights,
weight: make([]func(x, y graph.Node) float64, g.Depth()),
weight: make([]func(xid, yid int64) float64, g.Depth()),
}
// Calculate the total edge weight of the graph
@@ -614,7 +615,7 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
var zero int
for i := 0; i < g.Depth(); i++ {
l.edgeWeightOf[i] = make([]float64, len(nodes))
var weight func(x, y graph.Node) float64
var weight func(xid, yid int64) float64
if weights != nil {
if weights[i] == 0 {
@@ -634,11 +635,12 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
l.weight[i] = weight
layer := g.Layer(i)
for _, u := range l.nodes {
w := weight(u, u)
for _, v := range layer.From(u) {
w += weight(u, v)
uid := u.ID()
w := weight(uid, uid)
for _, v := range layer.From(uid) {
w += weight(uid, v.ID())
}
l.edgeWeightOf[i][u.ID()] = w
l.edgeWeightOf[i][uid] = w
l.m2[i] += w
}
if l.m2[i] == 0 {
@@ -779,7 +781,7 @@ func (l *undirectedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, ds
removal = true
}
k_aC += l.weight[layer](n, u)
k_aC += l.weight[layer](id, uid)
// sigma_totC could be kept for each community
// and updated for moves, changing the calculation
// of sigma_totC here from O(n_c) to O(1), but
@@ -789,7 +791,7 @@ func (l *undirectedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, ds
sigma_totC += l.edgeWeightOf[layer][uid]
}
a_aa := l.weight[layer](n, n)
a_aa := l.weight[layer](id, id)
k_a := l.edgeWeightOf[layer][id]
gamma := 1.0
if l.resolutions != nil {

View File

@@ -359,7 +359,7 @@ tests:
}
layer := g.Layer(l)
for n := range c {
if layer.HasEdgeBetween(simple.Node(n), target) {
if layer.HasEdgeBetween(int64(n), target.ID()) {
connected = true
break search
}
@@ -670,7 +670,7 @@ func undirectedMultiplexFrom(raw []layer) (UndirectedLayers, []float64, error) {
g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range l.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -267,7 +267,7 @@ func TestCommunityQUndirected(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -284,7 +284,7 @@ func TestCommunityQWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -320,7 +320,7 @@ func TestCommunityDeltaQUndirected(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -337,7 +337,7 @@ func TestCommunityDeltaQWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -401,7 +401,7 @@ func testCommunityDeltaQUndirected(t *testing.T, test communityUndirectedQTest,
}
connected := false
for n := range c {
if g.HasEdgeBetween(simple.Node(n), target) {
if g.HasEdgeBetween(int64(n), target.ID()) {
connected = true
break
}
@@ -445,7 +445,7 @@ func TestReduceQConsistencyUndirected(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -462,7 +462,7 @@ func TestReduceQConsistencyWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -563,7 +563,7 @@ func TestMoveLocalUndirected(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -580,7 +580,7 @@ func TestMoveLocalWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -625,7 +625,7 @@ func TestModularizeUndirected(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -642,7 +642,7 @@ func TestModularizeWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -151,7 +151,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
if s, ok := n.(Subgrapher); ok {
// If the node is not linked to any other node
// the graph needs to be written now.
if len(g.From(n)) == 0 {
if len(g.From(n.ID())) == 0 {
g := s.Subgraph()
_, subIsDirected := g.(graph.Directed)
if subIsDirected != isDirected {
@@ -182,20 +182,22 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
havePrintedEdgeHeader := false
for _, n := range nodes {
to := g.From(n)
nid := n.ID()
to := g.From(nid)
sort.Sort(ordered.ByID(to))
for _, t := range to {
tid := t.ID()
if isDirected {
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
if p.visited[edge{inGraph: name, from: nid, to: tid}] {
continue
}
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
p.visited[edge{inGraph: name, from: nid, to: tid}] = true
} else {
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
if p.visited[edge{inGraph: name, from: nid, to: tid}] {
continue
}
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
p.visited[edge{inGraph: name, from: t.ID(), to: n.ID()}] = true
p.visited[edge{inGraph: name, from: nid, to: tid}] = true
p.visited[edge{inGraph: name, from: tid, to: n.ID()}] = true
}
if !havePrintedEdgeHeader {
@@ -217,7 +219,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
} else {
p.writeNode(n)
}
e, edgeIsPorter := g.Edge(n, t).(Porter)
e, edgeIsPorter := g.Edge(nid, tid).(Porter)
if edgeIsPorter {
p.writePorts(e.FromPort())
}
@@ -242,7 +244,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
p.writePorts(e.ToPort())
}
if a, ok := g.Edge(n, t).(encoding.Attributer); ok {
if a, ok := g.Edge(nid, tid).(encoding.Attributer); ok {
p.writeAttributeList(a)
}

View File

@@ -11,29 +11,29 @@ type GraphNode struct {
roots []*GraphNode
}
func (g *GraphNode) Has(n graph.Node) bool {
if n.ID() == g.id {
func (g *GraphNode) Has(id int64) bool {
if id == g.id {
return true
}
visited := map[int64]struct{}{g.id: {}}
for _, root := range g.roots {
if root.ID() == n.ID() {
if root.ID() == id {
return true
}
if root.has(n, visited) {
if root.has(id, visited) {
return true
}
}
for _, neigh := range g.neighbors {
if neigh.ID() == n.ID() {
if neigh.ID() == id {
return true
}
if gn, ok := neigh.(*GraphNode); ok {
if gn.has(n, visited) {
if gn.has(id, visited) {
return true
}
}
@@ -42,18 +42,18 @@ func (g *GraphNode) Has(n graph.Node) bool {
return false
}
func (g *GraphNode) has(n graph.Node, visited map[int64]struct{}) bool {
func (g *GraphNode) has(id int64, visited map[int64]struct{}) bool {
for _, root := range g.roots {
if _, ok := visited[root.ID()]; ok {
continue
}
visited[root.ID()] = struct{}{}
if root.ID() == n.ID() {
if root.ID() == id {
return true
}
if root.has(n, visited) {
if root.has(id, visited) {
return true
}
@@ -65,16 +65,15 @@ func (g *GraphNode) has(n graph.Node, visited map[int64]struct{}) bool {
}
visited[neigh.ID()] = struct{}{}
if neigh.ID() == n.ID() {
if neigh.ID() == id {
return true
}
if gn, ok := neigh.(*GraphNode); ok {
if gn.has(n, visited) {
if gn.has(id, visited) {
return true
}
}
}
return false
@@ -128,8 +127,8 @@ func (g *GraphNode) nodes(list []graph.Node, visited map[int64]struct{}) []graph
return list
}
func (g *GraphNode) From(n graph.Node) []graph.Node {
if n.ID() == g.ID() {
func (g *GraphNode) From(id int64) []graph.Node {
if id == g.ID() {
return g.neighbors
}
@@ -137,7 +136,7 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
for _, root := range g.roots {
visited[root.ID()] = struct{}{}
if result := root.findNeighbors(n, visited); result != nil {
if result := root.findNeighbors(id, visited); result != nil {
return result
}
}
@@ -146,7 +145,7 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
visited[neigh.ID()] = struct{}{}
if gn, ok := neigh.(*GraphNode); ok {
if result := gn.findNeighbors(n, visited); result != nil {
if result := gn.findNeighbors(id, visited); result != nil {
return result
}
}
@@ -155,8 +154,8 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
return nil
}
func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []graph.Node {
if n.ID() == g.ID() {
func (g *GraphNode) findNeighbors(id int64, visited map[int64]struct{}) []graph.Node {
if id == g.ID() {
return g.neighbors
}
@@ -166,7 +165,7 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
}
visited[root.ID()] = struct{}{}
if result := root.findNeighbors(n, visited); result != nil {
if result := root.findNeighbors(id, visited); result != nil {
return result
}
}
@@ -178,7 +177,7 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
visited[neigh.ID()] = struct{}{}
if gn, ok := neigh.(*GraphNode); ok {
if result := gn.findNeighbors(n, visited); result != nil {
if result := gn.findNeighbors(id, visited); result != nil {
return result
}
}
@@ -187,18 +186,18 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
return nil
}
func (g *GraphNode) HasEdgeBetween(u, v graph.Node) bool {
return g.EdgeBetween(u, v) != nil
func (g *GraphNode) HasEdgeBetween(uid, vid int64) bool {
return g.EdgeBetween(uid, vid) != nil
}
func (g *GraphNode) Edge(u, v graph.Node) graph.Edge {
return g.EdgeBetween(u, v)
func (g *GraphNode) Edge(uid, vid int64) graph.Edge {
return g.EdgeBetween(uid, vid)
}
func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
if u.ID() == g.id || v.ID() == g.id {
func (g *GraphNode) EdgeBetween(uid, vid int64) graph.Edge {
if uid == g.id || vid == g.id {
for _, neigh := range g.neighbors {
if neigh.ID() == u.ID() || neigh.ID() == v.ID() {
if neigh.ID() == uid || neigh.ID() == vid {
return simple.Edge{F: g, T: neigh}
}
}
@@ -208,7 +207,7 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
visited := map[int64]struct{}{g.id: {}}
for _, root := range g.roots {
visited[root.ID()] = struct{}{}
if result := root.edgeBetween(u, v, visited); result != nil {
if result := root.edgeBetween(uid, vid, visited); result != nil {
return result
}
}
@@ -216,7 +215,7 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
for _, neigh := range g.neighbors {
visited[neigh.ID()] = struct{}{}
if gn, ok := neigh.(*GraphNode); ok {
if result := gn.edgeBetween(u, v, visited); result != nil {
if result := gn.edgeBetween(uid, vid, visited); result != nil {
return result
}
}
@@ -225,10 +224,10 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
return nil
}
func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) graph.Edge {
if u.ID() == g.id || v.ID() == g.id {
func (g *GraphNode) edgeBetween(uid, vid int64, visited map[int64]struct{}) graph.Edge {
if uid == g.id || vid == g.id {
for _, neigh := range g.neighbors {
if neigh.ID() == u.ID() || neigh.ID() == v.ID() {
if neigh.ID() == uid || neigh.ID() == vid {
return simple.Edge{F: g, T: neigh}
}
}
@@ -240,7 +239,7 @@ func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) gra
continue
}
visited[root.ID()] = struct{}{}
if result := root.edgeBetween(u, v, visited); result != nil {
if result := root.edgeBetween(uid, vid, visited); result != nil {
return result
}
}
@@ -252,7 +251,7 @@ func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) gra
visited[neigh.ID()] = struct{}{}
if gn, ok := neigh.(*GraphNode); ok {
if result := gn.edgeBetween(u, v, visited); result != nil {
if result := gn.edgeBetween(uid, vid, visited); result != nil {
return result
}
}

View File

@@ -27,53 +27,57 @@ type WeightedEdge interface {
// Graph is a generalized graph.
type Graph interface {
// Has returns whether the node exists within the graph.
Has(Node) bool
// Has returns whether a node with the given ID exists
// within the graph.
Has(id int64) bool
// Nodes returns all the nodes in the graph.
Nodes() []Node
// From returns all nodes that can be reached directly
// from the given node.
From(Node) []Node
// from the node with the given ID.
From(id int64) []Node
// HasEdgeBetween returns whether an edge exists between
// nodes x and y without considering direction.
HasEdgeBetween(x, y Node) bool
// nodes with IDs xid and yid without considering direction.
HasEdgeBetween(xid, yid int64) bool
// Edge returns the edge from u to v if such an edge
// exists and nil otherwise. The node v must be directly
// reachable from u as defined by the From method.
Edge(u, v Node) Edge
// Edge returns the edge from u to v, with IDs uid and vid,
// if such an edge exists and nil otherwise. The node v
// must be directly reachable from u as defined by the
// From method.
Edge(uid, vid int64) Edge
}
// Weighted is a weighted graph.
type Weighted interface {
Graph
// WeightedEdge returns the weighted edge from u to v if
// such an edge exists and nil otherwise. The node v must
// be directly reachable from u as defined by the
// From method.
WeightedEdge(u, v Node) WeightedEdge
// WeightedEdge returns the weighted edge from u to v
// with IDs uid and vid if such an edge exists and
// nil otherwise. The node v must be directly
// reachable from u as defined by the From method.
WeightedEdge(uid, vid int64) WeightedEdge
// Weight returns the weight for the edge between
// x and y if Edge(x, y) returns a non-nil Edge.
// x and y with IDs xid and yid if Edge(xid, yid)
// returns a non-nil Edge.
// If x and y are the same node or there is no
// joining edge between the two nodes the weight
// value returned is implementation dependent.
// Weight returns true if an edge exists between
// x and y or if x and y have the same ID, false
// otherwise.
Weight(x, y Node) (w float64, ok bool)
Weight(xid, yid int64) (w float64, ok bool)
}
// Undirected is an undirected graph.
type Undirected interface {
Graph
// EdgeBetween returns the edge between nodes x and y.
EdgeBetween(x, y Node) Edge
// EdgeBetween returns the edge between nodes x and y
// with IDs xid and yid.
EdgeBetween(xid, yid int64) Edge
}
// WeightedUndirected is a weighted undirected graph.
@@ -81,8 +85,8 @@ type WeightedUndirected interface {
Weighted
// WeightedEdgeBetween returns the edge between nodes
// x and y.
WeightedEdgeBetween(x, y Node) WeightedEdge
// x and y with IDs xid and yid.
WeightedEdgeBetween(xid, yid int64) WeightedEdge
}
// Directed is a directed graph.
@@ -90,12 +94,12 @@ type Directed interface {
Graph
// HasEdgeFromTo returns whether an edge exists
// in the graph from u to v.
HasEdgeFromTo(u, v Node) bool
// in the graph from u to v with IDs uid and vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly
// to the given node.
To(Node) []Node
// to the node with the given ID.
To(id int64) []Node
}
// WeightedDirected is a weighted directed graph.
@@ -103,12 +107,13 @@ type WeightedDirected interface {
Weighted
// HasEdgeFromTo returns whether an edge exists
// in the graph from u to v.
HasEdgeFromTo(u, v Node) bool
// in the graph from u to v with the IDs uid and
// vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly
// to the given node.
To(Node) []Node
// to the node with the given ID.
To(id int64) []Node
}
// NodeAdder is an interface for adding arbitrary nodes to a graph.
@@ -217,7 +222,7 @@ func Copy(dst Builder, src Graph) {
dst.AddNode(n)
}
for _, u := range nodes {
for _, v := range src.From(u) {
for _, v := range src.From(u.ID()) {
dst.SetEdge(dst.NewEdge(u, v))
}
}
@@ -240,8 +245,8 @@ func CopyWeighted(dst WeightedBuilder, src Weighted) {
dst.AddNode(n)
}
for _, u := range nodes {
for _, v := range src.From(u) {
dst.SetWeightedEdge(dst.NewWeightedEdge(u, v, src.WeightedEdge(u, v).Weight()))
for _, v := range src.From(u.ID()) {
dst.SetWeightedEdge(dst.NewWeightedEdge(u, v, src.WeightedEdge(u.ID(), v.ID()).Weight()))
}
}
}

View File

@@ -273,8 +273,8 @@ func same(a, b graph.Graph) bool {
}
}
for _, u := range a.Nodes() {
aFromU := a.From(u)
bFromU := b.From(u)
aFromU := a.From(u.ID())
bFromU := b.From(u.ID())
if len(aFromU) != len(bFromU) {
return false
}
@@ -288,7 +288,7 @@ func same(a, b graph.Graph) bool {
aW, aWok := a.(graph.Weighted)
bW, bWok := b.(graph.Weighted)
if aWok && bWok {
if aW.WeightedEdge(u, va).Weight() != bW.WeightedEdge(u, vb).Weight() {
if aW.WeightedEdge(u.ID(), va.ID()).Weight() != bW.WeightedEdge(u.ID(), vb.ID()).Weight() {
return false
}
}

View File

@@ -36,7 +36,7 @@ func Gnp(dst GraphBuilder, n int, p float64, src *rand.Rand) error {
}
for i := 0; i < n; i++ {
if !dst.Has(simple.Node(i)) {
if !dst.Has(int64(i)) {
dst.AddNode(simple.Node(i))
}
}
@@ -112,7 +112,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
}
for i := 0; i < n; i++ {
if !dst.Has(simple.Node(i)) {
if !dst.Has(int64(i)) {
dst.AddNode(simple.Node(i))
}
}
@@ -122,7 +122,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
for {
v, w := edgeNodesFor(rnd(nChoose2))
e := simple.Edge{F: w, T: v}
if !hasEdge(e.F, e.T) {
if !hasEdge(e.F.ID(), e.T.ID()) {
dst.SetEdge(e)
break
}
@@ -137,7 +137,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
for {
v, w := edgeNodesFor(rnd(nChoose2))
e := simple.Edge{F: v, T: w}
if !hasEdge(e.F, e.T) {
if !hasEdge(e.F.ID(), e.T.ID()) {
dst.SetEdge(e)
break
}
@@ -182,7 +182,7 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
}
for i := 0; i < n; i++ {
if !dst.Has(simple.Node(i)) {
if !dst.Has(int64(i)) {
dst.AddNode(simple.Node(i))
}
}
@@ -201,14 +201,14 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
j := v*(v-1)/2 + (v+i)%n
var ej simple.Edge
ej.T, ej.F = edgeNodesFor(j)
if !hasEdge(ej.From(), ej.To()) {
if !hasEdge(ej.From().ID(), ej.To().ID()) {
dst.SetEdge(ej)
}
k--
m++
var em simple.Edge
em.T, em.F = edgeNodesFor(m)
if !hasEdge(em.From(), em.To()) {
if !hasEdge(em.From().ID(), em.To().ID()) {
replace[j] = m
} else {
replace[j] = replace[m]
@@ -222,17 +222,17 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
r := rndN(nChoose2-i) + i
var er simple.Edge
er.T, er.F = edgeNodesFor(r)
if !hasEdge(er.From(), er.To()) {
if !hasEdge(er.From().ID(), er.To().ID()) {
dst.SetEdge(er)
} else {
er.T, er.F = edgeNodesFor(replace[r])
if !hasEdge(er.From(), er.To()) {
if !hasEdge(er.From().ID(), er.To().ID()) {
dst.SetEdge(er)
}
}
var ei simple.Edge
ei.T, ei.F = edgeNodesFor(i)
if !hasEdge(ei.From(), ei.To()) {
if !hasEdge(ei.From().ID(), ei.To().ID()) {
replace[r] = i
} else {
replace[r] = replace[i]
@@ -252,12 +252,12 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
j := v*(v-1)/2 + (v+i)%n
var ej simple.Edge
ej.F, ej.T = edgeNodesFor(j)
if !hasEdge(ej.From(), ej.To()) {
if !hasEdge(ej.From().ID(), ej.To().ID()) {
dst.SetEdge(ej)
}
k--
m++
if !hasEdge(edgeNodesFor(m)) {
if u, v := edgeNodesFor(m); !hasEdge(u.ID(), v.ID()) {
replace[j] = m
} else {
replace[j] = replace[m]
@@ -271,15 +271,15 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
r := rndN(nChoose2-i) + i
var er simple.Edge
er.F, er.T = edgeNodesFor(r)
if !hasEdge(er.From(), er.To()) {
if !hasEdge(er.From().ID(), er.To().ID()) {
dst.SetEdge(er)
} else {
er.F, er.T = edgeNodesFor(replace[r])
if !hasEdge(er.From(), er.To()) {
if !hasEdge(er.From().ID(), er.To().ID()) {
dst.SetEdge(er)
}
}
if !hasEdge(edgeNodesFor(i)) {
if u, v := edgeNodesFor(i); !hasEdge(u.ID(), v.ID()) {
replace[r] = i
} else {
replace[r] = replace[i]

View File

@@ -27,7 +27,7 @@ func (g *gnUndirected) SetEdge(e graph.Edge) {
return
case e.From().ID() > e.To().ID():
g.addBackwards = true
case g.UndirectedBuilder.HasEdgeBetween(e.From(), e.To()):
case g.UndirectedBuilder.HasEdgeBetween(e.From().ID(), e.To().ID()):
g.addMultipleEdge = true
}
@@ -45,7 +45,7 @@ func (g *gnDirected) SetEdge(e graph.Edge) {
case e.From().ID() == e.To().ID():
g.addSelfLoop = true
return
case g.DirectedBuilder.HasEdgeFromTo(e.From(), e.To()):
case g.DirectedBuilder.HasEdgeFromTo(e.From().ID(), e.To().ID()):
g.addMultipleEdge = true
}
@@ -190,9 +190,10 @@ func TestPowerLawUndirected(t *testing.T) {
}
for _, u := range nodes {
uid := u.ID()
var lines int
for _, v := range g.From(u) {
lines += len(g.Lines(u, v))
for _, v := range g.From(uid) {
lines += len(g.Lines(uid, v.ID()))
}
if lines < d {
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
@@ -218,9 +219,10 @@ func TestPowerLawDirected(t *testing.T) {
}
for _, u := range nodes {
uid := u.ID()
var lines int
for _, v := range g.From(u) {
lines += len(g.Lines(u, v))
for _, v := range g.From(uid) {
lines += len(g.Lines(uid, v.ID()))
}
if lines < d {
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
@@ -265,9 +267,10 @@ func TestBipartitePowerLawUndirected(t *testing.T) {
}
for _, u := range nodes {
uid := u.ID()
var lines int
for _, v := range g.From(u) {
lines += len(g.Lines(u, v))
for _, v := range g.From(uid) {
lines += len(g.Lines(uid, v.ID()))
}
if lines < d {
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
@@ -312,9 +315,10 @@ func TestBipartitePowerLawDirected(t *testing.T) {
}
for _, u := range nodes {
uid := u.ID()
var lines int
for _, v := range g.From(u) {
lines += len(g.Lines(u, v))
for _, v := range g.From(uid) {
lines += len(g.Lines(uid, v.ID()))
}
if lines < d {
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)

View File

@@ -66,6 +66,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
for i := 0; i < n; i++ {
u := nodes[rndN(len(nodes))]
d := dst.NewNode()
did := d.ID()
// Add the duplicate node.
dst.AddNode(d)
@@ -74,13 +75,14 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
// into the rest of the graph.
for {
// Add edges to parent's neighbours.
to := dst.From(u)
to := dst.From(u.ID())
sort.Sort(ordered.ByID(to))
for _, v := range to {
if rnd() < delta || dst.HasEdgeBetween(v, d) {
vid := v.ID()
if rnd() < delta || dst.HasEdgeBetween(vid, did) {
continue
}
if v.ID() < d.ID() {
if vid < did {
dst.SetEdge(dst.NewEdge(v, d))
} else {
dst.SetEdge(dst.NewEdge(d, v))
@@ -90,11 +92,13 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
// Add edges to old nodes.
scaledAlpha := alpha / float64(len(nodes))
for _, v := range nodes {
switch v.ID() {
case u.ID():
uid := u.ID()
vid := v.ID()
switch vid {
case uid:
if !math.IsNaN(sigma) {
if i == 0 || rnd() < sigma {
if v.ID() < d.ID() {
if vid < did {
dst.SetEdge(dst.NewEdge(v, d))
} else {
dst.SetEdge(dst.NewEdge(d, v))
@@ -104,8 +108,8 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
}
fallthrough
default:
if rnd() < scaledAlpha && !dst.HasEdgeBetween(v, d) {
if v.ID() < d.ID() {
if rnd() < scaledAlpha && !dst.HasEdgeBetween(vid, did) {
if vid < did {
dst.SetEdge(dst.NewEdge(v, d))
} else {
dst.SetEdge(dst.NewEdge(d, v))
@@ -114,7 +118,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
}
}
if len(dst.From(d)) != 0 {
if len(dst.From(did)) != 0 {
break
}
}

View File

@@ -25,7 +25,7 @@ func (g *duplication) SetEdge(e graph.Edge) {
return
case e.From().ID() > e.To().ID():
g.addBackwards = true
case g.UndirectedMutator.HasEdgeBetween(e.From(), e.To()):
case g.UndirectedMutator.HasEdgeBetween(e.From().ID(), e.To().ID()):
g.addMultipleEdge = true
}

View File

@@ -8,8 +8,8 @@ import "gonum.org/v1/gonum/graph"
// GraphBuilder is a graph that can have nodes and edges added.
type GraphBuilder interface {
Has(graph.Node) bool
HasEdgeBetween(x, y graph.Node) bool
Has(id int64) bool
HasEdgeBetween(xid, yid int64) bool
graph.Builder
}

View File

@@ -47,7 +47,7 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
// Initial condition.
wt := make([]float64, n)
for u := 0; u < m; u++ {
if !dst.Has(simple.Node(u)) {
if !dst.Has(int64(0)) {
dst.AddNode(simple.Node(u))
}
// We need to give equal probability for
@@ -68,9 +68,9 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
for i := 0; i < m; i++ {
// Triad formation.
if i != 0 && rnd() < p {
for _, w := range permute(dst.From(simple.Node(u)), rndN) {
for _, w := range permute(dst.From(int64(u)), rndN) {
wid := w.ID()
if wid == int64(v) || dst.HasEdgeBetween(w, simple.Node(v)) {
if wid == int64(v) || dst.HasEdgeBetween(wid, int64(v)) {
continue
}
dst.SetEdge(simple.Edge{F: w, T: simple.Node(v)})
@@ -87,7 +87,7 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
if !ok {
return errors.New("gen: depleted distribution")
}
if u == v || dst.HasEdgeBetween(simple.Node(u), simple.Node(v)) {
if u == v || dst.HasEdgeBetween(int64(u), int64(v)) {
continue
}
dst.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
@@ -128,7 +128,7 @@ func PreferentialAttachment(dst graph.UndirectedBuilder, n, m int, src *rand.Ran
// Initial condition.
wt := make([]float64, n)
for u := 0; u < m; u++ {
if !dst.Has(simple.Node(u)) {
if !dst.Has(int64(u)) {
dst.AddNode(simple.Node(u))
}
// We need to give equal probability for

View File

@@ -40,7 +40,7 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
n *= d
}
for i := 0; i < n; i++ {
if !dst.Has(simple.Node(i)) {
if !dst.Has(int64(i)) {
dst.AddNode(simple.Node(i))
}
}
@@ -67,14 +67,14 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
if uid > vid {
e.F, e.T = e.T, e.F
}
if !hasEdge(e.From(), e.To()) {
if !hasEdge(e.From().ID(), e.To().ID()) {
dst.SetEdge(e)
}
if !isDirected {
return
}
e.F, e.T = e.T, e.F
if !hasEdge(e.From(), e.To()) {
if !hasEdge(e.From().ID(), e.To().ID()) {
dst.SetEdge(e)
}
})
@@ -110,7 +110,7 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
if !isDirected && uid > vid {
e.F, e.T = e.T, e.F
}
if !hasEdge(e.From(), e.To()) {
if !hasEdge(e.From().ID(), e.To().ID()) {
dst.SetEdge(e)
}
}

View File

@@ -103,13 +103,13 @@ func (g *DirectedGraph) SetLine(l graph.Line) {
lid = l.ID()
)
if !g.Has(from) {
if !g.Has(fid) {
g.AddNode(from)
}
if g.from[fid][tid] == nil {
g.from[fid][tid] = make(map[int64]graph.Line)
}
if !g.Has(to) {
if !g.Has(tid) {
g.AddNode(to)
}
if g.to[tid][fid] == nil {
@@ -149,8 +149,8 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *DirectedGraph) Has(n graph.Node) bool {
_, ok := g.nodes[n.ID()]
func (g *DirectedGraph) Has(id int64) bool {
_, ok := g.nodes[id]
return ok
}
@@ -187,30 +187,30 @@ func (g *DirectedGraph) Edges() []graph.Edge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *DirectedGraph) From(n graph.Node) []graph.Node {
if _, ok := g.from[n.ID()]; !ok {
func (g *DirectedGraph) From(id int64) []graph.Node {
if _, ok := g.from[id]; !ok {
return nil
}
from := make([]graph.Node, len(g.from[n.ID()]))
from := make([]graph.Node, len(g.from[id]))
i := 0
for id := range g.from[n.ID()] {
from[i] = g.nodes[id]
for vid := range g.from[id] {
from[i] = g.nodes[vid]
i++
}
return from
}
// To returns all nodes in g that can reach directly to n.
func (g *DirectedGraph) To(n graph.Node) []graph.Node {
if _, ok := g.from[n.ID()]; !ok {
func (g *DirectedGraph) To(id int64) []graph.Node {
if _, ok := g.from[id]; !ok {
return nil
}
to := make([]graph.Node, len(g.to[n.ID()]))
to := make([]graph.Node, len(g.to[id]))
i := 0
for id := range g.to[n.ID()] {
to[i] = g.nodes[id]
for uid := range g.to[id] {
to[i] = g.nodes[uid]
i++
}
return to
@@ -218,9 +218,7 @@ func (g *DirectedGraph) To(n graph.Node) []graph.Node {
// HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction.
func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
yid := y.ID()
func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
if _, ok := g.from[xid][yid]; ok {
return true
}
@@ -231,8 +229,8 @@ func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// The returned graph.Edge is a multi.Edge if an edge exists.
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
lines := g.Lines(u, v)
func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
lines := g.Lines(uid, vid)
if len(lines) == 0 {
return nil
}
@@ -241,8 +239,8 @@ func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *DirectedGraph) Lines(u, v graph.Node) []graph.Line {
edge := g.from[u.ID()][v.ID()]
func (g *DirectedGraph) Lines(uid, vid int64) []graph.Line {
edge := g.from[uid][vid]
if len(edge) == 0 {
return nil
}
@@ -254,21 +252,21 @@ func (g *DirectedGraph) Lines(u, v graph.Node) []graph.Line {
}
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
_, ok := g.from[u.ID()][v.ID()]
func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
_, ok := g.from[uid][vid]
return ok
}
// Degree returns the in+out degree of n in g.
func (g *DirectedGraph) Degree(n graph.Node) int {
if _, ok := g.nodes[n.ID()]; !ok {
func (g *DirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[id]; !ok {
return 0
}
var deg int
for _, e := range g.from[n.ID()] {
for _, e := range g.from[id] {
deg += len(e)
}
for _, e := range g.to[n.ID()] {
for _, e := range g.to[id] {
deg += len(e)
}
return deg

View File

@@ -21,7 +21,7 @@ var (
func TestEdgeOvercounting(t *testing.T) {
g := generateDummyGraph()
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
if neigh := g.From(int64(2)); len(neigh) != 2 {
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
}
}

View File

@@ -95,13 +95,13 @@ func (g *UndirectedGraph) SetLine(l graph.Line) {
lid = l.ID()
)
if !g.Has(from) {
if !g.Has(fid) {
g.AddNode(from)
}
if g.lines[fid][tid] == nil {
g.lines[fid][tid] = make(map[int64]graph.Line)
}
if !g.Has(to) {
if !g.Has(tid) {
g.AddNode(to)
}
if g.lines[tid][fid] == nil {
@@ -138,8 +138,8 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *UndirectedGraph) Has(n graph.Node) bool {
_, ok := g.nodes[n.ID()]
func (g *UndirectedGraph) Has(id int64) bool {
_, ok := g.nodes[id]
return ok
}
@@ -185,14 +185,14 @@ func (g *UndirectedGraph) Edges() []graph.Edge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
if !g.Has(n) {
func (g *UndirectedGraph) From(id int64) []graph.Node {
if !g.Has(id) {
return nil
}
nodes := make([]graph.Node, len(g.lines[n.ID()]))
nodes := make([]graph.Node, len(g.lines[id]))
i := 0
for from := range g.lines[n.ID()] {
for from := range g.lines[id] {
nodes[i] = g.nodes[from]
i++
}
@@ -200,21 +200,21 @@ func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *UndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
_, ok := g.lines[x.ID()][y.ID()]
func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
_, ok := g.lines[xid][yid]
return ok
}
// EdgeBetween returns the edge between nodes x and y.
func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
return g.Edge(x, y)
func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
return g.Edge(xid, yid)
}
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// The returned graph.Edge is a multi.Edge if an edge exists.
func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
lines := g.LinesBetween(u, v)
func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
lines := g.LinesBetween(uid, vid)
if len(lines) == 0 {
return nil
}
@@ -223,26 +223,26 @@ func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *UndirectedGraph) Lines(u, v graph.Node) []graph.Line {
return g.LinesBetween(u, v)
func (g *UndirectedGraph) Lines(uid, vid int64) []graph.Line {
return g.LinesBetween(uid, vid)
}
// LinesBetween returns the lines between nodes x and y.
func (g *UndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
func (g *UndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
var lines []graph.Line
for _, l := range g.lines[x.ID()][y.ID()] {
for _, l := range g.lines[xid][yid] {
lines = append(lines, l)
}
return lines
}
// Degree returns the degree of n in g.
func (g *UndirectedGraph) Degree(n graph.Node) int {
if _, ok := g.nodes[n.ID()]; !ok {
func (g *UndirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[id]; !ok {
return 0
}
var deg int
for _, e := range g.lines[n.ID()] {
for _, e := range g.lines[id] {
deg += len(e)
}
return deg

View File

@@ -30,7 +30,7 @@ func TestMaxID(t *testing.T) {
delete(nodes, Node(2))
n := g.NewNode()
g.AddNode(n)
if !g.Has(n) {
if !g.Has(n.ID()) {
t.Error("added node does not exist in graph")
}
if _, exists := nodes[n]; exists {

View File

@@ -107,13 +107,13 @@ func (g *WeightedDirectedGraph) SetWeightedLine(l graph.WeightedLine) {
lid = l.ID()
)
if !g.Has(from) {
if !g.Has(fid) {
g.AddNode(from)
}
if g.from[fid][tid] == nil {
g.from[fid][tid] = make(map[int64]graph.WeightedLine)
}
if !g.Has(to) {
if !g.Has(tid) {
g.AddNode(to)
}
if g.to[tid][fid] == nil {
@@ -153,8 +153,8 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *WeightedDirectedGraph) Has(n graph.Node) bool {
_, ok := g.nodes[n.ID()]
func (g *WeightedDirectedGraph) Has(id int64) bool {
_, ok := g.nodes[id]
return ok
}
@@ -213,30 +213,30 @@ func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *WeightedDirectedGraph) From(n graph.Node) []graph.Node {
if _, ok := g.from[n.ID()]; !ok {
func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
if _, ok := g.from[id]; !ok {
return nil
}
from := make([]graph.Node, len(g.from[n.ID()]))
from := make([]graph.Node, len(g.from[id]))
i := 0
for id := range g.from[n.ID()] {
from[i] = g.nodes[id]
for vid := range g.from[id] {
from[i] = g.nodes[vid]
i++
}
return from
}
// To returns all nodes in g that can reach directly to n.
func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
if _, ok := g.from[n.ID()]; !ok {
func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
if _, ok := g.from[id]; !ok {
return nil
}
to := make([]graph.Node, len(g.to[n.ID()]))
to := make([]graph.Node, len(g.to[id]))
i := 0
for id := range g.to[n.ID()] {
to[i] = g.nodes[id]
for uid := range g.to[id] {
to[i] = g.nodes[uid]
i++
}
return to
@@ -244,9 +244,7 @@ func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
// HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction.
func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
yid := y.ID()
func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
if _, ok := g.from[xid][yid]; ok {
return true
}
@@ -255,8 +253,8 @@ func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
}
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
if _, ok := g.from[u.ID()][v.ID()]; !ok {
func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
if _, ok := g.from[uid][vid]; !ok {
return false
}
return true
@@ -265,15 +263,15 @@ func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// The returned graph.Edge is a multi.WeightedEdge if an edge exists.
func (g *WeightedDirectedGraph) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdge(u, v)
func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
lines := g.WeightedLines(u, v)
func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
lines := g.WeightedLines(uid, vid)
if len(lines) == 0 {
return nil
}
@@ -282,8 +280,8 @@ func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *WeightedDirectedGraph) Lines(u, v graph.Node) []graph.Line {
edge := g.from[u.ID()][v.ID()]
func (g *WeightedDirectedGraph) Lines(uid, vid int64) []graph.Line {
edge := g.from[uid][vid]
if len(edge) == 0 {
return nil
}
@@ -296,8 +294,8 @@ func (g *WeightedDirectedGraph) Lines(u, v graph.Node) []graph.Line {
// WeightedLines returns the weighted lines from u to v if such any such lines exists
// and nil otherwise. The node v must be directly reachable from u as defined by the From method.
func (g *WeightedDirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedLine {
edge := g.from[u.ID()][v.ID()]
func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
edge := g.from[uid][vid]
if len(edge) == 0 {
return nil
}
@@ -310,21 +308,21 @@ func (g *WeightedDirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedL
// Weight returns the weight for the lines between x and y summarised by the receiver's
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
func (g *WeightedDirectedGraph) Weight(u, v graph.Node) (w float64, ok bool) {
lines := g.WeightedLines(u, v)
func (g *WeightedDirectedGraph) Weight(uid, vid int64) (w float64, ok bool) {
lines := g.WeightedLines(uid, vid)
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
}
// Degree returns the in+out degree of n in g.
func (g *WeightedDirectedGraph) Degree(n graph.Node) int {
if _, ok := g.nodes[n.ID()]; !ok {
func (g *WeightedDirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[id]; !ok {
return 0
}
var deg int
for _, e := range g.from[n.ID()] {
for _, e := range g.from[id] {
deg += len(e)
}
for _, e := range g.to[n.ID()] {
for _, e := range g.to[id] {
deg += len(e)
}
return deg

View File

@@ -22,7 +22,7 @@ var (
func TestWeightedEdgeOvercounting(t *testing.T) {
g := generateDummyWeightedGraph()
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
if neigh := g.From(int64(2)); len(neigh) != 2 {
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
}
}

View File

@@ -99,13 +99,13 @@ func (g *WeightedUndirectedGraph) SetWeighted(l graph.WeightedLine) {
lid = l.ID()
)
if !g.Has(from) {
if !g.Has(fid) {
g.AddNode(from)
}
if g.lines[fid][tid] == nil {
g.lines[fid][tid] = make(map[int64]graph.WeightedLine)
}
if !g.Has(to) {
if !g.Has(tid) {
g.AddNode(to)
}
if g.lines[tid][fid] == nil {
@@ -142,8 +142,8 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *WeightedUndirectedGraph) Has(n graph.Node) bool {
_, ok := g.nodes[n.ID()]
func (g *WeightedUndirectedGraph) Has(id int64) bool {
_, ok := g.nodes[id]
return ok
}
@@ -189,14 +189,14 @@ func (g *WeightedUndirectedGraph) Edges() []graph.Edge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
if !g.Has(n) {
func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
if !g.Has(id) {
return nil
}
nodes := make([]graph.Node, len(g.lines[n.ID()]))
nodes := make([]graph.Node, len(g.lines[id]))
i := 0
for from := range g.lines[n.ID()] {
for from := range g.lines[id] {
nodes[i] = g.nodes[from]
i++
}
@@ -204,20 +204,20 @@ func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *WeightedUndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
_, ok := g.lines[x.ID()][y.ID()]
func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
_, ok := g.lines[xid][yid]
return ok
}
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *WeightedUndirectedGraph) Lines(u, v graph.Node) []graph.Line {
return g.LinesBetween(u, v)
func (g *WeightedUndirectedGraph) Lines(uid, vid int64) []graph.Line {
return g.LinesBetween(uid, vid)
}
// LinesBetween returns the lines between nodes x and y.
func (g *WeightedUndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
edge := g.lines[x.ID()][y.ID()]
func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
edge := g.lines[xid][yid]
if len(edge) == 0 {
return nil
}
@@ -237,20 +237,20 @@ func (g *WeightedUndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// The returned graph.Edge is a multi.WeightedEdge if an edge exists.
func (g *WeightedUndirectedGraph) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdge(u, v)
func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(uid, vid)
}
// EdgeBetween returns the edge between nodes x and y.
func (g *WeightedUndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
return g.WeightedEdge(x, y)
func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
return g.WeightedEdge(xid, yid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
lines := g.WeightedLines(u, v)
func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
lines := g.WeightedLines(uid, vid)
if len(lines) == 0 {
return nil
}
@@ -258,19 +258,19 @@ func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEd
}
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
return g.WeightedEdge(x, y)
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
return g.WeightedEdge(xid, yid)
}
// WeightedLines returns the lines from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *WeightedUndirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedLine {
return g.WeightedLinesBetween(u, v)
func (g *WeightedUndirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
return g.WeightedLinesBetween(uid, vid)
}
// WeightedLinesBetween returns the lines between nodes x and y.
func (g *WeightedUndirectedGraph) WeightedLinesBetween(x, y graph.Node) []graph.WeightedLine {
edge := g.lines[x.ID()][y.ID()]
func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) []graph.WeightedLine {
edge := g.lines[xid][yid]
if len(edge) == 0 {
return nil
}
@@ -289,18 +289,18 @@ func (g *WeightedUndirectedGraph) WeightedLinesBetween(x, y graph.Node) []graph.
// Weight returns the weight for the lines between x and y summarised by the receiver's
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
lines := g.WeightedLines(x, y)
func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
lines := g.WeightedLines(xid, yid)
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
}
// Degree returns the degree of n in g.
func (g *WeightedUndirectedGraph) Degree(n graph.Node) int {
if _, ok := g.nodes[n.ID()]; !ok {
func (g *WeightedUndirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[id]; !ok {
return 0
}
var deg int
for _, e := range g.lines[n.ID()] {
for _, e := range g.lines[id] {
deg += len(e)
}
return deg

View File

@@ -23,7 +23,7 @@ func TestWeightedMaxID(t *testing.T) {
delete(nodes, Node(2))
n := g.NewNode()
g.AddNode(n)
if !g.Has(n) {
if !g.Has(n.ID()) {
t.Error("added node does not exist in graph")
}
if _, exists := nodes[n]; exists {

View File

@@ -19,43 +19,46 @@ type WeightedLine interface {
// Multigraph is a generalized multigraph.
type Multigraph interface {
// Has returns whether the node exists within the multigraph.
Has(Node) bool
// Has returns whether the node with the given ID exists
// within the multigraph.
Has(id int64) bool
// Nodes returns all the nodes in the multigraph.
Nodes() []Node
// From returns all nodes that can be reached directly
// from the given node.
From(Node) []Node
// from the node with the given ID.
From(id int64) []Node
// HasEdgeBetween returns whether an edge exists between
// nodes x and y without considering direction.
HasEdgeBetween(x, y Node) bool
// nodes with IDs xid and yid without considering direction.
HasEdgeBetween(xid, yid int64) bool
// Lines returns the lines from u to v if any such lines
// exist and nil otherwise. The node v must be directly
// reachable from u as defined by the From method.
Lines(u, v Node) []Line
// Lines returns the lines from u to v, with IDs uid and
// vid, if any such lines exist and nil otherwise. The
// node v must be directly reachable from u as defined by
// the From method.
Lines(uid, vid int64) []Line
}
// WeightedMultigraph is a weighted multigraph.
type WeightedMultigraph interface {
Multigraph
// WeightedLines returns the weighted lines from u to v if
// any such lines exist and nil otherwise. The node v must
// be directly reachable from u as defined by the
// From method.
WeightedLines(u, v Node) []WeightedLine
// WeightedLines returns the weighted lines from u to v
// with IDs uid and vid if any such lines exist and nil
// otherwise. The node v must be directly reachable
// from u as defined by the From method.
WeightedLines(uid, vid int64) []WeightedLine
}
// UndirectedMultigraph is an undirected multigraph.
type UndirectedMultigraph interface {
Multigraph
// LinesBetween returns the lines between nodes x and y.
LinesBetween(x, y Node) []Line
// LinesBetween returns the lines between nodes x and y
// with IDs xid and yid.
LinesBetween(xid, yid int64) []Line
}
// WeightedUndirectedMultigraph is a weighted undirected multigraph.
@@ -63,8 +66,8 @@ type WeightedUndirectedMultigraph interface {
WeightedMultigraph
// WeightedLinesBetween returns the lines between nodes
// x and y.
WeightedLinesBetween(x, y Node) []WeightedLine
// x and y with IDs xid and yid.
WeightedLinesBetween(xid, yid int64) []WeightedLine
}
// DirectedMultigraph is a directed multigraph.
@@ -72,12 +75,13 @@ type DirectedMultigraph interface {
Multigraph
// HasEdgeFromTo returns whether an edge exists
// in the multigraph from u to v.
HasEdgeFromTo(u, v Node) bool
// in the multigraph from u to v with IDs uid
// and vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly
// to the given node.
To(Node) []Node
// to the node with the given ID.
To(id int64) []Node
}
// WeightedDirectedMultigraph is a weighted directed multigraph.
@@ -85,12 +89,13 @@ type WeightedDirectedMultigraph interface {
WeightedMultigraph
// HasEdgeFromTo returns whether an edge exists
// in the multigraph from u to v.
HasEdgeFromTo(u, v Node) bool
// in the multigraph from u to v with IDs uid
// and vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly
// to the given node.
To(Node) []Node
// to the node with the given ID.
To(id int64) []Node
}
// LineAdder is an interface for adding lines to a multigraph.

View File

@@ -115,17 +115,19 @@ func brandes(g graph.Graph, accumulate func(s graph.Node, stack linear.NodeStack
queue.Enqueue(s)
for queue.Len() != 0 {
v := queue.Dequeue()
vid := v.ID()
stack.Push(v)
for _, w := range g.From(v) {
for _, w := range g.From(vid) {
wid := w.ID()
// w found for the first time?
if d[w.ID()] < 0 {
if d[wid] < 0 {
queue.Enqueue(w)
d[w.ID()] = d[v.ID()] + 1
d[wid] = d[vid] + 1
}
// shortest path to w via v?
if d[w.ID()] == d[v.ID()]+1 {
sigma[w.ID()] += sigma[v.ID()]
p[w.ID()] = append(p[w.ID()], v)
if d[wid] == d[vid]+1 {
sigma[wid] += sigma[vid]
p[wid] = append(p[wid], v)
}
}
}
@@ -151,18 +153,20 @@ func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64
nodes := g.Nodes()
for i, s := range nodes {
sid := s.ID()
for j, t := range nodes {
if i == j {
continue
}
d := p.Weight(s, t)
tid := t.ID()
d := p.Weight(sid, tid)
if math.IsInf(d, 0) {
continue
}
// If we have a unique path, don't do the
// extra work needed to get all paths.
path, _, unique := p.Between(s, t)
path, _, unique := p.Between(sid, tid)
if unique {
for _, v := range path[1 : len(path)-1] {
// For undirected graphs we double count
@@ -174,7 +178,7 @@ func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64
}
// Otherwise iterate over all paths.
paths, _ := p.AllBetween(s, t)
paths, _ := p.AllBetween(sid, tid)
stFrac := 1 / float64(len(paths))
for _, path := range paths {
for _, v := range path[1 : len(path)-1] {
@@ -203,18 +207,20 @@ func EdgeBetweennessWeighted(g graph.Weighted, p path.AllShortest) map[[2]int64]
_, isUndirected := g.(graph.Undirected)
nodes := g.Nodes()
for i, s := range nodes {
sid := s.ID()
for j, t := range nodes {
if i == j {
continue
}
d := p.Weight(s, t)
tid := t.ID()
d := p.Weight(sid, tid)
if math.IsInf(d, 0) {
continue
}
// If we have a unique path, don't do the
// extra work needed to get all paths.
path, _, unique := p.Between(s, t)
path, _, unique := p.Between(sid, tid)
if unique {
for k, v := range path[1:] {
// For undirected graphs we double count
@@ -231,7 +237,7 @@ func EdgeBetweennessWeighted(g graph.Weighted, p path.AllShortest) map[[2]int64]
}
// Otherwise iterate over all paths.
paths, _ := p.AllBetween(s, t)
paths, _ := p.AllBetween(sid, tid)
stFrac := 1 / float64(len(paths))
for _, path := range paths {
for k, v := range path[1:] {

View File

@@ -179,7 +179,7 @@ func TestBetweenness(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -208,7 +208,7 @@ func TestEdgeBetweenness(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -240,7 +240,7 @@ func TestBetweennessWeighted(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -276,7 +276,7 @@ func TestEdgeBetweennessWeighted(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -122,9 +122,9 @@ func NewLaplacian(g graph.Undirected) Laplacian {
l := mat.NewSymDense(len(nodes), nil)
for j, u := range nodes {
to := g.From(u)
l.SetSym(j, j, float64(len(to)))
uid := u.ID()
to := g.From(uid)
l.SetSym(j, j, float64(len(to)))
for _, v := range to {
vid := v.ID()
if uid == vid {
@@ -155,12 +155,12 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
l := mat.NewSymDense(len(nodes), nil)
for j, u := range nodes {
to := g.From(u)
uid := u.ID()
to := g.From(uid)
if len(to) == 0 {
continue
}
l.SetSym(j, j, 1)
uid := u.ID()
squdeg := math.Sqrt(float64(len(to)))
for _, v := range to {
vid := v.ID()
@@ -168,7 +168,7 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
panic("network: self edge in graph")
}
if uid < vid {
l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(len(g.From(v))))))
l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(len(g.From(vid))))))
}
}
}
@@ -193,7 +193,7 @@ func NewRandomWalkLaplacian(g graph.Graph, damp float64) Laplacian {
l := mat.NewDense(len(nodes), len(nodes), nil)
for j, u := range nodes {
uid := u.ID()
to := g.From(u)
to := g.From(uid)
if len(to) == 0 {
continue
}

View File

@@ -152,7 +152,7 @@ func TestDiffuse(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -278,7 +278,7 @@ func TestRandomWalkLaplacian(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -466,7 +466,7 @@ func TestDiffuseToEquilibrium(t *testing.T) {
g := test.builder
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -22,12 +22,14 @@ func Closeness(g graph.Graph, p path.AllShortest) map[int64]float64 {
nodes := g.Nodes()
c := make(map[int64]float64, len(nodes))
for _, u := range nodes {
uid := u.ID()
var sum float64
for _, v := range nodes {
vid := v.ID()
// The ordering here is not relevant for
// undirected graphs, but we make sure we
// are counting incoming paths.
d := p.Weight(v, u)
d := p.Weight(vid, uid)
if math.IsInf(d, 0) {
continue
}
@@ -49,12 +51,14 @@ func Farness(g graph.Graph, p path.AllShortest) map[int64]float64 {
nodes := g.Nodes()
f := make(map[int64]float64, len(nodes))
for _, u := range nodes {
uid := u.ID()
var sum float64
for _, v := range nodes {
vid := v.ID()
// The ordering here is not relevant for
// undirected graphs, but we make sure we
// are counting incoming paths.
d := p.Weight(v, u)
d := p.Weight(vid, uid)
if math.IsInf(d, 0) {
continue
}
@@ -76,12 +80,14 @@ func Harmonic(g graph.Graph, p path.AllShortest) map[int64]float64 {
nodes := g.Nodes()
h := make(map[int64]float64, len(nodes))
for i, u := range nodes {
uid := u.ID()
var sum float64
for j, v := range nodes {
vid := v.ID()
// The ordering here is not relevant for
// undirected graphs, but we make sure we
// are counting incoming paths.
d := p.Weight(v, u)
d := p.Weight(vid, uid)
if math.IsInf(d, 0) {
continue
}
@@ -105,12 +111,14 @@ func Residual(g graph.Graph, p path.AllShortest) map[int64]float64 {
nodes := g.Nodes()
r := make(map[int64]float64, len(nodes))
for i, u := range nodes {
uid := u.ID()
var sum float64
for j, v := range nodes {
vid := v.ID()
// The ordering here is not relevant for
// undirected graphs, but we make sure we
// are counting incoming paths.
d := p.Weight(v, u)
d := p.Weight(vid, uid)
if math.IsInf(d, 0) {
continue
}

View File

@@ -146,7 +146,7 @@ func TestDistanceCentralityUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -336,7 +336,7 @@ func TestDistanceCentralityDirected(t *testing.T) {
g := simple.NewWeightedDirectedGraph(0, math.Inf(1))
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -32,10 +32,11 @@ func HITS(g graph.Directed, tol float64) map[int64]HubAuthority {
nodesLinkingTo := make([][]int, len(nodes))
nodesLinkedFrom := make([][]int, len(nodes))
for i, n := range nodes {
for _, u := range g.To(n) {
id := n.ID()
for _, u := range g.To(id) {
nodesLinkingTo[i] = append(nodesLinkingTo[i], indexOf[u.ID()])
}
for _, v := range g.From(n) {
for _, v := range g.From(id) {
nodesLinkedFrom[i] = append(nodesLinkedFrom[i], indexOf[v.ID()])
}
}

View File

@@ -46,7 +46,7 @@ func TestHITS(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -35,7 +35,7 @@ func PageRank(g graph.Directed, damp, tol float64) map[int64]float64 {
m := mat.NewDense(len(nodes), len(nodes), nil)
dangling := damp / float64(len(nodes))
for j, u := range nodes {
to := g.From(u)
to := g.From(u.ID())
f := damp / float64(len(to))
for _, v := range to {
m.Set(indexOf[v.ID()], j, f)
@@ -109,7 +109,7 @@ func PageRankSparse(g graph.Directed, damp, tol float64) map[int64]float64 {
var dangling compressedRow
df := damp / float64(len(nodes))
for j, u := range nodes {
to := g.From(u)
to := g.From(u.ID())
f := damp / float64(len(to))
for _, v := range to {
m.addTo(indexOf[v.ID()], j, f)

View File

@@ -84,7 +84,7 @@ func TestPageRank(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -108,7 +108,7 @@ func TestPageRankSparse(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -24,7 +24,7 @@ import (
// falling back to NullHeuristic otherwise. If the graph does not implement graph.Weighter,
// UniformCost is used. AStar will panic if g has an A*-reachable negative edge weight.
func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded int) {
if !g.Has(s) || !g.Has(t) {
if !g.Has(s.ID()) || !g.Has(t.ID()) {
return Shortest{from: s}, 0
}
var weight Weighting
@@ -59,14 +59,14 @@ func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded
}
visited.Add(uid)
for _, v := range g.From(u.node) {
for _, v := range g.From(u.node.ID()) {
vid := v.ID()
if visited.Has(vid) {
continue
}
j := path.indexOf[vid]
w, ok := weight(u.node, v)
w, ok := weight(u.node.ID(), vid)
if !ok {
panic("A*: unexpected invalid weight")
}

View File

@@ -129,7 +129,7 @@ func TestAStar(t *testing.T) {
for _, test := range aStarTests {
pt, _ := AStar(simple.Node(test.s), simple.Node(test.t), test.g, test.heuristic)
p, cost := pt.To(simple.Node(test.t))
p, cost := pt.To(test.t)
if !topo.IsPathIn(test.g, p) {
t.Errorf("got path that is not path in input graph for %q", test.name)
@@ -139,7 +139,7 @@ func TestAStar(t *testing.T) {
if !ok {
t.Fatalf("unexpected negative cycle in %q", test.name)
}
if want := bfp.WeightTo(simple.Node(test.t)); cost != want {
if want := bfp.WeightTo(test.t); cost != want {
t.Errorf("unexpected cost for %q: got:%v want:%v", test.name, cost, want)
}
@@ -196,8 +196,8 @@ func TestExhaustiveAStar(t *testing.T) {
for _, start := range g.Nodes() {
for _, goal := range g.Nodes() {
pt, _ := AStar(start, goal, g, heuristic)
gotPath, gotWeight := pt.To(goal)
wantPath, wantWeight, _ := ps.Between(start, goal)
gotPath, gotWeight := pt.To(goal.ID())
wantPath, wantWeight, _ := ps.Between(start.ID(), goal.ID())
if gotWeight != wantWeight {
t.Errorf("unexpected path weight from %v to %v result: got:%f want:%f",
start, goal, gotWeight, wantWeight)
@@ -231,7 +231,7 @@ func isMonotonic(g UndirectedWeightLister, h Heuristic) (ok bool, at graph.Edge,
for _, edge := range g.WeightedEdges() {
from := edge.From()
to := edge.To()
w, ok := g.Weight(from, to)
w, ok := g.Weight(from.ID(), to.ID())
if !ok {
panic("A*: unexpected invalid weight")
}
@@ -275,12 +275,12 @@ func TestAStarNullHeuristic(t *testing.T) {
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
}
p, weight := pt.To(test.Query.To())
p, weight := pt.To(test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
}
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight)
}
@@ -301,7 +301,7 @@ func TestAStarNullHeuristic(t *testing.T) {
test.Name, p, test.WantPaths)
}
np, weight := pt.To(test.NoPathFor.To())
np, weight := pt.To(test.NoPathFor.To().ID())
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, np, weight)

View File

@@ -12,7 +12,7 @@ import "gonum.org/v1/gonum/graph"
//
// The time complexity of BellmanFordFrom is O(|V|.|E|).
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
if !g.Has(u) {
if !g.Has(u.ID()) {
return Shortest{from: u}, true
}
var weight Weighting
@@ -32,9 +32,11 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
for i := 1; i < len(nodes); i++ {
changed := false
for j, u := range nodes {
for _, v := range g.From(u) {
k := path.indexOf[v.ID()]
w, ok := weight(u, v)
uid := u.ID()
for _, v := range g.From(uid) {
vid := v.ID()
k := path.indexOf[vid]
w, ok := weight(uid, vid)
if !ok {
panic("bellman-ford: unexpected invalid weight")
}
@@ -51,9 +53,11 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
}
for j, u := range nodes {
for _, v := range g.From(u) {
k := path.indexOf[v.ID()]
w, ok := weight(u, v)
uid := u.ID()
for _, v := range g.From(uid) {
vid := v.ID()
k := path.indexOf[vid]
w, ok := weight(uid, vid)
if !ok {
panic("bellman-ford: unexpected invalid weight")
}

View File

@@ -35,12 +35,12 @@ func TestBellmanFordFrom(t *testing.T) {
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
}
p, weight := pt.To(test.Query.To())
p, weight := pt.To(test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
}
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight)
}
@@ -61,7 +61,7 @@ func TestBellmanFordFrom(t *testing.T) {
test.Name, p, test.WantPaths)
}
np, weight := pt.To(test.NoPathFor.To())
np, weight := pt.To(test.NoPathFor.To().ID())
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, np, weight)

View File

@@ -201,7 +201,7 @@ func BenchmarkRandomGraphDominators(b *testing.B) {
if v == nil {
v = unordered[ui][rnd.Intn(len(unordered[ui]))]
}
if !g.HasEdgeFromTo(u, v) {
if !g.HasEdgeFromTo(u.ID(), v.ID()) {
g.SetEdge(g.NewEdge(u, v))
}
}
@@ -253,16 +253,16 @@ type undirected struct {
*simple.DirectedGraph
}
func (g undirected) From(n graph.Node) []graph.Node {
return append(g.DirectedGraph.From(n), g.DirectedGraph.To(n)...)
func (g undirected) From(id int64) []graph.Node {
return append(g.DirectedGraph.From(id), g.DirectedGraph.To(id)...)
}
func (g undirected) HasEdgeBetween(x, y graph.Node) bool {
return g.DirectedGraph.HasEdgeFromTo(x, y)
func (g undirected) HasEdgeBetween(xid, yid int64) bool {
return g.DirectedGraph.HasEdgeFromTo(xid, yid)
}
func (g undirected) EdgeBetween(x, y graph.Node) graph.Edge {
return g.DirectedGraph.Edge(x, y)
func (g undirected) EdgeBetween(xid, yid int64) graph.Edge {
return g.DirectedGraph.Edge(xid, yid)
}
func (g undirected) SetEdge(e graph.Edge) {

View File

@@ -140,7 +140,7 @@ func (lt *lengauerTarjan) dfs(g graph.Directed, v graph.Node) {
ltv.label = ltv
lt.nodes = append(lt.nodes, ltv)
for _, w := range g.From(v) {
for _, w := range g.From(v.ID()) {
wid := w.ID()
idx, ok := lt.indexOf[wid]

View File

@@ -162,7 +162,7 @@ func (lt *sLengauerTarjan) dfs(g graph.Directed, v graph.Node) {
ltv.label = ltv
lt.nodes = append(lt.nodes, ltv)
for _, w := range g.From(v) {
for _, w := range g.From(v.ID()) {
wid := w.ID()
idx, ok := lt.indexOf[wid]

View File

@@ -16,7 +16,7 @@ import (
//
// The time complexity of DijkstrFrom is O(|E|.log|V|).
func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
if !g.Has(u) {
if !g.Has(u.ID()) {
return Shortest{from: u}
}
var weight Weighting
@@ -46,9 +46,11 @@ func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
if mid.dist > path.dist[k] {
continue
}
for _, v := range g.From(mid.node) {
j := path.indexOf[v.ID()]
w, ok := weight(mid.node, v)
mnid := mid.node.ID()
for _, v := range g.From(mnid) {
vid := v.ID()
j := path.indexOf[vid]
w, ok := weight(mnid, vid)
if !ok {
panic("dijkstra: unexpected invalid weight")
}
@@ -106,9 +108,11 @@ func dijkstraAllPaths(g graph.Graph, paths AllShortest) {
if mid.dist < paths.dist.At(i, k) {
paths.dist.Set(i, k, mid.dist)
}
for _, v := range g.From(mid.node) {
j := paths.indexOf[v.ID()]
w, ok := weight(mid.node, v)
mnid := mid.node.ID()
for _, v := range g.From(mnid) {
vid := v.ID()
j := paths.indexOf[vid]
w, ok := weight(mnid, vid)
if !ok {
panic("dijkstra: unexpected invalid weight")
}

View File

@@ -47,12 +47,12 @@ func TestDijkstraFrom(t *testing.T) {
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
}
p, weight := pt.To(test.Query.To())
p, weight := pt.To(test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
}
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight)
}
@@ -73,7 +73,7 @@ func TestDijkstraFrom(t *testing.T) {
test.Name, p, test.WantPaths)
}
np, weight := pt.To(test.NoPathFor.To())
np, weight := pt.To(test.NoPathFor.To().ID())
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, np, weight)
@@ -111,12 +111,12 @@ func TestDijkstraAllPaths(t *testing.T) {
// Check all random paths returned are OK.
for i := 0; i < 10; i++ {
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
}
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight)
}
@@ -142,13 +142,13 @@ func TestDijkstraAllPaths(t *testing.T) {
}
}
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
if np != nil || !math.IsInf(weight, 1) || unique {
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
test.Name, np, weight, unique)
}
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
@@ -169,7 +169,7 @@ func TestDijkstraAllPaths(t *testing.T) {
test.Name, got, test.WantPaths)
}
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
if nps != nil || !math.IsInf(weight, 1) {
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, nps, weight)

View File

@@ -99,12 +99,14 @@ func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel
}
}
for _, u := range d.model.Nodes() {
for _, v := range g.From(u) {
w := edgeWeight(d.weight, u, v)
uid := u.ID()
for _, v := range g.From(uid) {
vid := v.ID()
w := edgeWeight(d.weight, uid, vid)
if w < 0 {
panic("D* Lite: negative edge weight")
}
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: d.model.Node(v.ID()), W: w})
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: d.model.Node(vid), W: w})
}
}
@@ -120,8 +122,8 @@ func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel
// edgeWeight is a helper function that returns the weight of the edge between
// two connected nodes, u and v, using the provided weight function. It panics
// if there is no edge between u and v.
func edgeWeight(weight path.Weighting, u, v graph.Node) float64 {
w, ok := weight(u, v)
func edgeWeight(weight path.Weighting, uid, vid int64) float64 {
w, ok := weight(uid, vid)
if !ok {
panic("D* Lite: unexpected invalid weight")
}
@@ -187,29 +189,33 @@ func (d *DStarLite) findShortestPath() {
if !u.key.less(d.keyFor(d.s)) && d.s.rhs <= d.s.g {
break
}
uid := u.ID()
switch kNew := d.keyFor(u); {
case u.key.less(kNew):
d.queue.update(u, kNew)
case u.g > u.rhs:
u.g = u.rhs
d.queue.remove(u)
for _, _s := range d.model.To(u) {
for _, _s := range d.model.To(uid) {
s := _s.(*dStarLiteNode)
if s.ID() != d.t.ID() {
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, s, u)+u.g)
sid := s.ID()
if sid != d.t.ID() {
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, uid)+u.g)
}
d.update(s)
}
default:
gOld := u.g
u.g = math.Inf(1)
for _, _s := range append(d.model.To(u), u) {
for _, _s := range append(d.model.To(uid), u) {
s := _s.(*dStarLiteNode)
if s.rhs == edgeWeight(d.model.Weight, s, u)+gOld {
sid := s.ID()
if s.rhs == edgeWeight(d.model.Weight, sid, uid)+gOld {
if s.ID() != d.t.ID() {
s.rhs = math.Inf(1)
for _, t := range d.model.From(s) {
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, s, t)+t.(*dStarLiteNode).g)
for _, t := range d.model.From(sid) {
tid := t.ID()
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, tid)+t.(*dStarLiteNode).g)
}
}
}
@@ -243,9 +249,10 @@ func (d *DStarLite) Step() bool {
min := math.Inf(1)
var next *dStarLiteNode
for _, _s := range d.model.From(d.s) {
dsid := d.s.ID()
for _, _s := range d.model.From(dsid) {
s := _s.(*dStarLiteNode)
w := edgeWeight(d.model.Weight, d.s, s) + s.g
w := edgeWeight(d.model.Weight, dsid, s.ID()) + s.g
if w < min || (w == min && s.rhs < rhs) {
next = s
min = w
@@ -294,24 +301,27 @@ func (d *DStarLite) UpdateWorld(changes []graph.Edge) {
d.last = d.s
for _, e := range changes {
from := e.From()
fid := from.ID()
to := e.To()
c, _ := d.weight(from, to)
tid := to.ID()
c, _ := d.weight(fid, tid)
if c < 0 {
panic("D* Lite: negative edge weight")
}
cOld, _ := d.model.Weight(from, to)
cOld, _ := d.model.Weight(fid, tid)
u := d.worldNodeFor(from)
v := d.worldNodeFor(to)
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: v, W: c})
uid := u.ID()
if cOld > c {
if u.ID() != d.t.ID() {
if uid != d.t.ID() {
u.rhs = math.Min(u.rhs, c+v.g)
}
} else if u.rhs == cOld+v.g {
if u.ID() != d.t.ID() {
if uid != d.t.ID() {
u.rhs = math.Inf(1)
for _, t := range d.model.From(u) {
u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, u, t)+t.(*dStarLiteNode).g)
for _, t := range d.model.From(uid) {
u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, uid, t.ID())+t.(*dStarLiteNode).g)
}
}
}
@@ -354,9 +364,11 @@ func (d *DStarLite) Path() (p []graph.Node, weight float64) {
next *dStarLiteNode
cost float64
)
for _, _v := range d.model.From(u) {
uid := u.ID()
for _, _v := range d.model.From(uid) {
v := _v.(*dStarLiteNode)
w := edgeWeight(d.model.Weight, u, v)
vid := v.ID()
w := edgeWeight(d.model.Weight, uid, vid)
if rhs := w + v.g; rhs < min || (rhs == min && v.rhs < rhsMin) {
next = v
min = rhs

View File

@@ -389,7 +389,8 @@ var dynamicDStarLiteTests = []struct {
all := l.Grid.AllVisible
l.Grid.AllVisible = false
for _, n := range l.Nodes() {
l.Known[n.ID()] = !l.Grid.Has(n)
id := n.ID()
l.Known[id] = !l.Grid.Has(id)
}
l.Grid.AllVisible = all
@@ -401,19 +402,21 @@ var dynamicDStarLiteTests = []struct {
// Check we have a correctly modified representation.
for _, u := range l.Nodes() {
uid := u.ID()
for _, v := range l.Nodes() {
if l.HasEdgeBetween(u, v) != l.Grid.HasEdgeBetween(u, v) {
ur, uc := l.RowCol(u.ID())
vr, vc := l.RowCol(v.ID())
vid := v.ID()
if l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) {
ur, uc := l.RowCol(uid)
vr, vc := l.RowCol(vid)
if (ur == wallRow && uc == wallCol) || (vr == wallRow && vc == wallCol) {
if !l.HasEdgeBetween(u, v) {
if !l.HasEdgeBetween(uid, vid) {
panic(fmt.Sprintf("expected to believe edge between %v (%d,%d) and %v (%d,%d) is passable",
u, v, ur, uc, vr, vc))
}
continue
}
panic(fmt.Sprintf("disagreement about edge between %v (%d,%d) and %v (%d,%d): got:%t want:%t",
u, v, ur, uc, vr, vc, l.HasEdgeBetween(u, v), l.Grid.HasEdgeBetween(u, v)))
u, v, ur, uc, vr, vc, l.HasEdgeBetween(uid, vid), l.Grid.HasEdgeBetween(uid, vid)))
}
}
}
@@ -574,8 +577,8 @@ func TestDStarLiteDynamic(t *testing.T) {
l.MoveTo(test.s)
heuristic := func(a, b graph.Node) float64 {
ax, ay := l.XY(a)
bx, by := l.XY(b)
ax, ay := l.XY(a.ID())
bx, by := l.XY(b.ID())
return test.heuristic(ax-bx, ay-by)
}
@@ -657,7 +660,7 @@ func weightOf(path []graph.Node, g graph.Weighted) float64 {
var w float64
if len(path) > 1 {
for p, n := range path[1:] {
ew, ok := g.Weight(path[p], n)
ew, ok := g.Weight(path[p].ID(), n.ID())
if !ok {
return math.Inf(1)
}
@@ -673,7 +676,7 @@ func simpleWeightedEdgesOf(g graph.Weighted, edges []graph.Edge) []simple.Weight
for i, e := range edges {
w[i].F = e.From()
w[i].T = e.To()
ew, _ := g.Weight(e.From(), e.To())
ew, _ := g.Weight(e.From().ID(), e.To().ID())
w[i].W = ew
}
return w

View File

@@ -61,7 +61,7 @@ func (d *dumper) dump(withpath bool) {
switch ln {
case 0:
if n.ID() == d.grid.Location.ID() {
if d.grid.Grid.HasOpen(n) {
if d.grid.Grid.HasOpen(n.ID()) {
fmt.Fprintf(w, "id:%2d >@<", n.ID())
} else {
// Mark location as illegal.
@@ -70,19 +70,19 @@ func (d *dumper) dump(withpath bool) {
} else if n.ID() == d.dStarLite.t.ID() {
fmt.Fprintf(w, "id:%2d G", n.ID())
// Mark goal cell as illegal.
if !d.grid.Grid.HasOpen(n) {
if !d.grid.Grid.HasOpen(n.ID()) {
fmt.Fprint(w, "!")
}
} else if pathStep[n.ID()] > 0 {
fmt.Fprintf(w, "id:%2d %2d", n.ID(), pathStep[n.ID()])
// Mark path cells with an obstruction.
if !d.grid.Grid.HasOpen(n) {
if !d.grid.Grid.HasOpen(n.ID()) {
fmt.Fprint(w, "!")
}
} else {
fmt.Fprintf(w, "id:%2d", n.ID())
// Mark cells with an obstruction.
if !d.grid.Grid.HasOpen(n) {
if !d.grid.Grid.HasOpen(n.ID()) {
fmt.Fprint(w, " *")
}
}

View File

@@ -23,9 +23,11 @@ func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
paths = newAllShortest(nodes, true)
for i, u := range nodes {
paths.dist.Set(i, i, 0)
for _, v := range g.From(u) {
j := paths.indexOf[v.ID()]
w, ok := weight(u, v)
uid := u.ID()
for _, v := range g.From(uid) {
vid := v.ID()
j := paths.indexOf[vid]
w, ok := weight(uid, vid)
if !ok {
panic("floyd-warshall: unexpected invalid weight")
}

View File

@@ -35,12 +35,12 @@ func TestFloydWarshall(t *testing.T) {
// Check all random paths returned are OK.
for i := 0; i < 10; i++ {
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
}
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight)
}
@@ -66,13 +66,13 @@ func TestFloydWarshall(t *testing.T) {
}
}
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
if np != nil || !math.IsInf(weight, 1) || unique {
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
test.Name, np, weight, unique)
}
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
@@ -93,7 +93,7 @@ func TestFloydWarshall(t *testing.T) {
test.Name, got, test.WantPaths)
}
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
if nps != nil || !math.IsInf(weight, 1) {
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, nps, weight)

View File

@@ -104,17 +104,12 @@ func (g *Grid) Nodes() []graph.Node {
// Has returns whether n is a node in the grid. The state of
// the AllVisible field determines whether a non-open node is
// present.
func (g *Grid) Has(n graph.Node) bool {
return g.has(n.ID())
}
func (g *Grid) has(id int64) bool {
func (g *Grid) Has(id int64) bool {
return 0 <= id && id < int64(len(g.open)) && (g.AllVisible || g.open[id])
}
// HasOpen returns whether n is an open node in the grid.
func (g *Grid) HasOpen(n graph.Node) bool {
id := n.ID()
func (g *Grid) HasOpen(id int64) bool {
return 0 <= id && id < int64(len(g.open)) && g.open[id]
}
@@ -145,11 +140,11 @@ func (g *Grid) RowCol(id int64) (r, c int) {
// XY returns the cartesian coordinates of n. If n is not a node
// in the grid, (NaN, NaN) is returned.
func (g *Grid) XY(n graph.Node) (x, y float64) {
if !g.Has(n) {
func (g *Grid) XY(id int64) (x, y float64) {
if !g.Has(id) {
return math.NaN(), math.NaN()
}
r, c := g.RowCol(n.ID())
r, c := g.RowCol(id)
return float64(c), float64(r)
}
@@ -163,15 +158,15 @@ func (g *Grid) NodeAt(r, c int) graph.Node {
// From returns all the nodes reachable from u. Reachabilty requires that both
// ends of an edge must be open.
func (g *Grid) From(u graph.Node) []graph.Node {
if !g.HasOpen(u) {
func (g *Grid) From(uid int64) []graph.Node {
if !g.HasOpen(uid) {
return nil
}
nr, nc := g.RowCol(u.ID())
nr, nc := g.RowCol(uid)
var to []graph.Node
for r := nr - 1; r <= nr+1; r++ {
for c := nc - 1; c <= nc+1; c++ {
if v := g.NodeAt(r, c); v != nil && g.HasEdgeBetween(u, v) {
if v := g.NodeAt(r, c); v != nil && g.HasEdgeBetween(uid, v.ID()) {
to = append(to, v)
}
}
@@ -180,12 +175,12 @@ func (g *Grid) From(u graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether there is an edge between u and v.
func (g *Grid) HasEdgeBetween(u, v graph.Node) bool {
if !g.HasOpen(u) || !g.HasOpen(v) || u.ID() == v.ID() {
func (g *Grid) HasEdgeBetween(uid, vid int64) bool {
if !g.HasOpen(uid) || !g.HasOpen(vid) || uid == vid {
return false
}
ur, uc := g.RowCol(u.ID())
vr, vc := g.RowCol(v.ID())
ur, uc := g.RowCol(uid)
vr, vc := g.RowCol(vid)
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
return false
}
@@ -200,47 +195,47 @@ func abs(i int) int {
}
// Edge returns the edge between u and v.
func (g *Grid) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdgeBetween(u, v)
func (g *Grid) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// WeightedEdge returns the weighted edge between u and v.
func (g *Grid) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v)
func (g *Grid) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(uid, vid)
}
// EdgeBetween returns the edge between u and v.
func (g *Grid) EdgeBetween(u, v graph.Node) graph.Edge {
return g.WeightedEdgeBetween(u, v)
func (g *Grid) EdgeBetween(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// WeightedEdgeBetween returns the weighted edge between u and v.
func (g *Grid) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
if g.HasEdgeBetween(u, v) {
func (g *Grid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
if g.HasEdgeBetween(uid, vid) {
if !g.AllowDiagonal || g.UnitEdgeWeight {
return simple.WeightedEdge{F: u, T: v, W: 1}
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: 1}
}
ux, uy := g.XY(u)
vx, vy := g.XY(v)
return simple.WeightedEdge{F: u, T: v, W: math.Hypot(ux-vx, uy-vy)}
ux, uy := g.XY(uid)
vx, vy := g.XY(vid)
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)}
}
return nil
}
// Weight returns the weight of the given edge.
func (g *Grid) Weight(x, y graph.Node) (w float64, ok bool) {
if x.ID() == y.ID() {
func (g *Grid) Weight(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return 0, true
}
if !g.HasEdgeBetween(x, y) {
if !g.HasEdgeBetween(xid, yid) {
return math.Inf(1), false
}
if e := g.EdgeBetween(x, y); e != nil {
if e := g.EdgeBetween(xid, yid); e != nil {
if !g.AllowDiagonal || g.UnitEdgeWeight {
return 1, true
}
ux, uy := g.XY(e.From())
vx, vy := g.XY(e.To())
ux, uy := g.XY(e.From().ID())
vx, vy := g.XY(e.To().ID())
return math.Hypot(ux-vx, uy-vy), true
}
return math.Inf(1), true
@@ -274,15 +269,15 @@ func (g *Grid) Render(path []graph.Node) ([]byte, error) {
// We don't use topo.IsPathIn at the outset because we
// want to draw as much as possible before failing.
for i, n := range path {
if !g.Has(n) || (i != 0 && !g.HasEdgeBetween(path[i-1], n)) {
id := n.ID()
id := n.ID()
if !g.Has(id) || (i != 0 && !g.HasEdgeBetween(path[i-1].ID(), id)) {
if 0 <= id && id < int64(len(g.open)) {
r, c := g.RowCol(n.ID())
r, c := g.RowCol(id)
b[r*(g.c+1)+c] = '!'
}
return b, errors.New("grid: not a path in graph")
}
r, c := g.RowCol(n.ID())
r, c := g.RowCol(id)
switch i {
case len(path) - 1:
b[r*(g.c+1)+c] = 'G'

View File

@@ -249,7 +249,7 @@ func TestGrid(t *testing.T) {
}
for _, test := range reach {
g.AllowDiagonal = test.diagonal
got := g.From(test.from)
got := g.From(test.from.ID())
if !reflect.DeepEqual(got, test.to) {
t.Fatalf("unexpected nodes from %d with allow diagonal=%t:\ngot: %v\nwant:%v",
test.from, test.diagonal, got, test.to)

View File

@@ -47,23 +47,25 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
if u == nil {
continue
}
ux, uy := l.XY(u)
uid := u.ID()
ux, uy := l.XY(uid)
if math.Hypot(x-ux, y-uy) > l.VisionRadius {
continue
}
for _, v := range l.allPossibleFrom(u) {
if seen[[2]int64{u.ID(), v.ID()}] {
for _, v := range l.allPossibleFrom(uid) {
vid := v.ID()
if seen[[2]int64{uid, vid}] {
continue
}
seen[[2]int64{u.ID(), v.ID()}] = true
seen[[2]int64{uid, vid}] = true
vx, vy := l.XY(v)
if !l.Known[v.ID()] && math.Hypot(x-vx, y-vy) > l.VisionRadius {
vx, vy := l.XY(vid)
if !l.Known[vid] && math.Hypot(x-vx, y-vy) > l.VisionRadius {
continue
}
e := simple.Edge{F: u, T: v}
if !l.Known[u.ID()] || !l.Known[v.ID()] {
if !l.Known[uid] || !l.Known[vid] {
new = append(new, e)
} else {
old = append(old, e)
@@ -79,18 +81,20 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
if u == nil {
continue
}
ux, uy := l.XY(u)
uid := u.ID()
ux, uy := l.XY(uid)
if math.Hypot(x-ux, y-uy) > l.VisionRadius {
continue
}
for _, v := range l.allPossibleFrom(u) {
vx, vy := l.XY(v)
for _, v := range l.allPossibleFrom(uid) {
vid := v.ID()
vx, vy := l.XY(vid)
if math.Hypot(x-vx, y-vy) > l.VisionRadius {
continue
}
l.Known[v.ID()] = true
l.Known[vid] = true
}
l.Known[u.ID()] = true
l.Known[uid] = true
}
}
@@ -100,19 +104,19 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
}
// allPossibleFrom returns all the nodes possibly reachable from u.
func (l *LimitedVisionGrid) allPossibleFrom(u graph.Node) []graph.Node {
if !l.Has(u) {
func (l *LimitedVisionGrid) allPossibleFrom(uid int64) []graph.Node {
if !l.Has(uid) {
return nil
}
nr, nc := l.RowCol(u.ID())
nr, nc := l.RowCol(uid)
var to []graph.Node
for r := nr - 1; r <= nr+1; r++ {
for c := nc - 1; c <= nc+1; c++ {
v := l.NodeAt(r, c)
if v == nil || u.ID() == v.ID() {
if v == nil || uid == v.ID() {
continue
}
ur, uc := l.RowCol(u.ID())
ur, uc := l.RowCol(uid)
vr, vc := l.RowCol(v.ID())
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
continue
@@ -134,11 +138,11 @@ func (l *LimitedVisionGrid) RowCol(id int64) (r, c int) {
// XY returns the cartesian coordinates of n. If n is not a node
// in the grid, (NaN, NaN) is returned.
func (l *LimitedVisionGrid) XY(n graph.Node) (x, y float64) {
if !l.Has(n) {
func (l *LimitedVisionGrid) XY(id int64) (x, y float64) {
if !l.Has(id) {
return math.NaN(), math.NaN()
}
r, c := l.RowCol(n.ID())
r, c := l.RowCol(id)
return float64(c), float64(r)
}
@@ -157,25 +161,21 @@ func (l *LimitedVisionGrid) NodeAt(r, c int) graph.Node {
}
// Has returns whether n is a node in the grid.
func (l *LimitedVisionGrid) Has(n graph.Node) bool {
return l.has(n.ID())
}
func (l *LimitedVisionGrid) has(id int64) bool {
func (l *LimitedVisionGrid) Has(id int64) bool {
return 0 <= id && id < int64(len(l.Grid.open))
}
// From returns nodes that are optimistically reachable from u.
func (l *LimitedVisionGrid) From(u graph.Node) []graph.Node {
if !l.Has(u) {
func (l *LimitedVisionGrid) From(uid int64) []graph.Node {
if !l.Has(uid) {
return nil
}
nr, nc := l.RowCol(u.ID())
nr, nc := l.RowCol(uid)
var to []graph.Node
for r := nr - 1; r <= nr+1; r++ {
for c := nc - 1; c <= nc+1; c++ {
if v := l.NodeAt(r, c); v != nil && l.HasEdgeBetween(u, v) {
if v := l.NodeAt(r, c); v != nil && l.HasEdgeBetween(uid, v.ID()) {
to = append(to, v)
}
}
@@ -184,12 +184,12 @@ func (l *LimitedVisionGrid) From(u graph.Node) []graph.Node {
}
// HasEdgeBetween optimistically returns whether an edge is exists between u and v.
func (l *LimitedVisionGrid) HasEdgeBetween(u, v graph.Node) bool {
if u.ID() == v.ID() {
func (l *LimitedVisionGrid) HasEdgeBetween(uid, vid int64) bool {
if uid == vid {
return false
}
ur, uc := l.RowCol(u.ID())
vr, vc := l.RowCol(v.ID())
ur, uc := l.RowCol(uid)
vr, vc := l.RowCol(vid)
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
return false
}
@@ -197,66 +197,66 @@ func (l *LimitedVisionGrid) HasEdgeBetween(u, v graph.Node) bool {
return false
}
x, y := l.XY(l.Location)
ux, uy := l.XY(u)
vx, vy := l.XY(v)
uKnown := l.Known[u.ID()] || math.Hypot(x-ux, y-uy) <= l.VisionRadius
vKnown := l.Known[v.ID()] || math.Hypot(x-vx, y-vy) <= l.VisionRadius
x, y := l.XY(l.Location.ID())
ux, uy := l.XY(uid)
vx, vy := l.XY(vid)
uKnown := l.Known[uid] || math.Hypot(x-ux, y-uy) <= l.VisionRadius
vKnown := l.Known[vid] || math.Hypot(x-vx, y-vy) <= l.VisionRadius
switch {
case uKnown && vKnown:
return l.Grid.HasEdgeBetween(u, v)
return l.Grid.HasEdgeBetween(uid, vid)
case uKnown:
return l.Grid.HasOpen(u)
return l.Grid.HasOpen(uid)
case vKnown:
return l.Grid.HasOpen(v)
return l.Grid.HasOpen(vid)
default:
return true
}
}
// Edge optimistically returns the edge from u to v.
func (l *LimitedVisionGrid) Edge(u, v graph.Node) graph.Edge {
return l.WeightedEdgeBetween(u, v)
func (l *LimitedVisionGrid) Edge(uid, vid int64) graph.Edge {
return l.WeightedEdgeBetween(uid, vid)
}
// Edge optimistically returns the weighted edge from u to v.
func (l *LimitedVisionGrid) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
return l.WeightedEdgeBetween(u, v)
func (l *LimitedVisionGrid) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return l.WeightedEdgeBetween(uid, vid)
}
// WeightedEdgeBetween optimistically returns the edge between u and v.
func (l *LimitedVisionGrid) EdgeBetween(u, v graph.Node) graph.Edge {
return l.WeightedEdgeBetween(u, v)
func (l *LimitedVisionGrid) EdgeBetween(uid, vid int64) graph.Edge {
return l.WeightedEdgeBetween(uid, vid)
}
// WeightedEdgeBetween optimistically returns the weighted edge between u and v.
func (l *LimitedVisionGrid) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
if l.HasEdgeBetween(u, v) {
func (l *LimitedVisionGrid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
if l.HasEdgeBetween(uid, vid) {
if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight {
return simple.WeightedEdge{F: u, T: v, W: 1}
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: 1}
}
ux, uy := l.XY(u)
vx, vy := l.XY(v)
return simple.WeightedEdge{F: u, T: v, W: math.Hypot(ux-vx, uy-vy)}
ux, uy := l.XY(uid)
vx, vy := l.XY(vid)
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)}
}
return nil
}
// Weight returns the weight of the given edge.
func (l *LimitedVisionGrid) Weight(x, y graph.Node) (w float64, ok bool) {
if x.ID() == y.ID() {
func (l *LimitedVisionGrid) Weight(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return 0, true
}
if !l.HasEdgeBetween(x, y) {
if !l.HasEdgeBetween(xid, yid) {
return math.Inf(1), false
}
if e := l.EdgeBetween(x, y); e != nil {
if e := l.EdgeBetween(xid, yid); e != nil {
if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight {
return 1, true
}
ux, uy := l.XY(e.From())
vx, vy := l.XY(e.To())
ux, uy := l.XY(e.From().ID())
vx, vy := l.XY(e.To().ID())
return math.Hypot(ux-vx, uy-vy), true
}
@@ -294,15 +294,15 @@ func (l *LimitedVisionGrid) Render(path []graph.Node) ([]byte, error) {
// We don't use topo.IsPathIn at the outset because we
// want to draw as much as possible before failing.
for i, n := range path {
if !l.Has(n) || (i != 0 && !l.HasEdgeBetween(path[i-1], n)) {
id := n.ID()
id := n.ID()
if !l.Has(id) || (i != 0 && !l.HasEdgeBetween(path[i-1].ID(), id)) {
if 0 <= id && id < int64(len(l.Grid.open)) {
r, c := l.RowCol(n.ID())
r, c := l.RowCol(id)
b[r*(cols+1)+c] = '!'
}
return b, errors.New("grid: not a path in graph")
}
r, c := l.RowCol(n.ID())
r, c := l.RowCol(id)
switch i {
case len(path) - 1:
b[r*(cols+1)+c] = 'G'

View File

@@ -1165,23 +1165,25 @@ func TestLimitedVisionGrid(t *testing.T) {
}
l.Grid.AllowDiagonal = test.diag
x, y := l.XY(test.path[0])
x, y := l.XY(test.path[0].ID())
for _, u := range l.Nodes() {
ux, uy := l.XY(u)
uid := u.ID()
ux, uy := l.XY(uid)
uNear := math.Hypot(x-ux, y-uy) <= test.radius
for _, v := range l.Nodes() {
vx, vy := l.XY(v)
vid := v.ID()
vx, vy := l.XY(vid)
vNear := math.Hypot(x-vx, y-vy) <= test.radius
if u.ID() == v.ID() && l.HasEdgeBetween(u, v) {
if u.ID() == v.ID() && l.HasEdgeBetween(uid, vid) {
t.Errorf("unexpected self edge: %v -- %v", u, v)
}
if !uNear && !vNear && !l.HasEdgeBetween(u, v) && couldConnectIn(l, u, v) {
if !uNear && !vNear && !l.HasEdgeBetween(uid, vid) && couldConnectIn(l, uid, vid) {
t.Errorf("unexpected pessimism: no hope in distant edge between %v and %v for test %d",
u, v, i)
}
if (uNear && vNear) && l.HasEdgeBetween(u, v) != l.Grid.HasEdgeBetween(u, v) {
if (uNear && vNear) && l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) {
t.Errorf("unrealistic optimism: disagreement about edge between %v and %v for test %d: got:%t want:%t",
u, v, i, l.HasEdgeBetween(u, v), l.Grid.HasEdgeBetween(u, v))
u, v, i, l.HasEdgeBetween(uid, vid), l.Grid.HasEdgeBetween(uid, vid))
}
}
}
@@ -1205,7 +1207,7 @@ func asConcreteEdges(changes []graph.Edge, in graph.Weighted) []simple.WeightedE
for i, e := range changes {
we[i].F = e.From()
we[i].T = e.To()
w, ok := in.Weight(e.From(), e.To())
w, ok := in.Weight(e.From().ID(), e.To().ID())
if !ok && !math.IsInf(w, 1) {
panic("unexpected invalid finite weight")
}
@@ -1214,13 +1216,13 @@ func asConcreteEdges(changes []graph.Edge, in graph.Weighted) []simple.WeightedE
return we
}
func couldConnectIn(l *LimitedVisionGrid, u, v graph.Node) bool {
if u.ID() == v.ID() {
func couldConnectIn(l *LimitedVisionGrid, uid, vid int64) bool {
if uid == vid {
return false
}
ur, uc := l.RowCol(u.ID())
vr, vc := l.RowCol(v.ID())
ur, uc := l.RowCol(uid)
vr, vc := l.RowCol(vid)
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
return false
}
@@ -1228,13 +1230,13 @@ func couldConnectIn(l *LimitedVisionGrid, u, v graph.Node) bool {
return false
}
if !l.Known[u.ID()] && !l.Known[v.ID()] {
if !l.Known[uid] && !l.Known[vid] {
return true
}
if l.Known[u.ID()] && !l.Grid.HasOpen(u) {
if l.Known[uid] && !l.Grid.HasOpen(uid) {
return false
}
if l.Known[v.ID()] && !l.Grid.HasOpen(v) {
if l.Known[vid] && !l.Grid.HasOpen(vid) {
return false
}

View File

@@ -52,12 +52,12 @@ func JohnsonAllPaths(g graph.Graph) (paths AllShortest, ok bool) {
dijkstraAllPaths(jg, paths)
for i, u := range paths.nodes {
hu := jg.adjustBy.WeightTo(u)
hu := jg.adjustBy.WeightTo(u.ID())
for j, v := range paths.nodes {
if i == j {
continue
}
hv := jg.adjustBy.WeightTo(v)
hv := jg.adjustBy.WeightTo(v.ID())
paths.dist.Set(i, j, paths.dist.At(i, j)-hu+hv)
}
}
@@ -69,8 +69,8 @@ type johnsonWeightAdjuster struct {
q int64
g graph.Graph
from func(graph.Node) []graph.Node
edgeTo func(graph.Node, graph.Node) graph.Edge
from func(id int64) []graph.Node
edgeTo func(uid, vid int64) graph.Edge
weight Weighting
bellmanFord bool
@@ -86,11 +86,11 @@ var (
_ graph.Weighted = johnsonWeightAdjuster{}
)
func (g johnsonWeightAdjuster) Has(n graph.Node) bool {
if g.bellmanFord && n.ID() == g.q {
func (g johnsonWeightAdjuster) Has(id int64) bool {
if g.bellmanFord && id == g.q {
return true
}
return g.g.Has(n)
return g.g.Has(id)
}
@@ -101,40 +101,40 @@ func (g johnsonWeightAdjuster) Nodes() []graph.Node {
return g.g.Nodes()
}
func (g johnsonWeightAdjuster) From(n graph.Node) []graph.Node {
if g.bellmanFord && n.ID() == g.q {
func (g johnsonWeightAdjuster) From(id int64) []graph.Node {
if g.bellmanFord && id == g.q {
return g.g.Nodes()
}
return g.from(n)
return g.from(id)
}
func (g johnsonWeightAdjuster) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
func (g johnsonWeightAdjuster) WeightedEdge(_, _ int64) graph.WeightedEdge {
panic("path: unintended use of johnsonWeightAdjuster")
}
func (g johnsonWeightAdjuster) Edge(u, v graph.Node) graph.Edge {
if g.bellmanFord && u.ID() == g.q && g.g.Has(v) {
return simple.Edge{F: johnsonGraphNode(g.q), T: v}
func (g johnsonWeightAdjuster) Edge(uid, vid int64) graph.Edge {
if g.bellmanFord && uid == g.q && g.g.Has(vid) {
return simple.Edge{F: johnsonGraphNode(g.q), T: simple.Node(vid)}
}
return g.edgeTo(u, v)
return g.edgeTo(uid, vid)
}
func (g johnsonWeightAdjuster) Weight(x, y graph.Node) (w float64, ok bool) {
func (g johnsonWeightAdjuster) Weight(xid, yid int64) (w float64, ok bool) {
if g.bellmanFord {
switch g.q {
case x.ID():
case xid:
return 0, true
case y.ID():
case yid:
return math.Inf(1), false
default:
return g.weight(x, y)
return g.weight(xid, yid)
}
}
w, ok = g.weight(x, y)
return w + g.adjustBy.WeightTo(x) - g.adjustBy.WeightTo(y), ok
w, ok = g.weight(xid, yid)
return w + g.adjustBy.WeightTo(xid) - g.adjustBy.WeightTo(yid), ok
}
func (johnsonWeightAdjuster) HasEdgeBetween(_, _ graph.Node) bool {
func (johnsonWeightAdjuster) HasEdgeBetween(_, _ int64) bool {
panic("path: unintended use of johnsonWeightAdjuster")
}

View File

@@ -35,12 +35,12 @@ func TestJohnsonAllPaths(t *testing.T) {
// Check all random paths returned are OK.
for i := 0; i < 10; i++ {
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
}
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight)
}
@@ -66,13 +66,13 @@ func TestJohnsonAllPaths(t *testing.T) {
}
}
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
if np != nil || !math.IsInf(weight, 1) || unique {
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
test.Name, np, weight, unique)
}
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight)
@@ -93,7 +93,7 @@ func TestJohnsonAllPaths(t *testing.T) {
test.Name, got, test.WantPaths)
}
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
if nps != nil || !math.IsInf(weight, 1) {
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, nps, weight)

View File

@@ -47,7 +47,7 @@ func ExampleBellmanFordFrom_negativecycles() {
return
}
for _, n := range []simple.Node{'a', 'b', 'c', 'd', 'e', 'f'} {
p, w := pt.To(n)
p, w := pt.To(n.ID())
if math.IsNaN(w) {
fmt.Printf("negative cycle in path to %c path:%c\n", n, p)
}

View File

@@ -93,8 +93,8 @@ func (p Shortest) From() graph.Node { return p.from }
// WeightTo returns the weight of the minimum path to v. If the path to v includes
// a negative cycle, the returned weight will not reflect the true path weight.
func (p Shortest) WeightTo(v graph.Node) float64 {
to, toOK := p.indexOf[v.ID()]
func (p Shortest) WeightTo(vid int64) float64 {
to, toOK := p.indexOf[vid]
if !toOK {
return math.Inf(1)
}
@@ -104,8 +104,8 @@ func (p Shortest) WeightTo(v graph.Node) float64 {
// To returns a shortest path to v and the weight of the path. If the path
// to v includes a negative cycle, one pass through the cycle will be included
// in path and weight will be returned as NaN.
func (p Shortest) To(v graph.Node) (path []graph.Node, weight float64) {
to, toOK := p.indexOf[v.ID()]
func (p Shortest) To(vid int64) (path []graph.Node, weight float64) {
to, toOK := p.indexOf[vid]
if !toOK || math.IsInf(p.dist[to], 1) {
return nil, math.Inf(1)
}
@@ -136,7 +136,7 @@ func (p Shortest) To(v graph.Node) (path []graph.Node, weight float64) {
}
}
ordered.Reverse(path)
return path, math.Min(weight, p.dist[p.indexOf[v.ID()]])
return path, math.Min(weight, p.dist[p.indexOf[vid]])
}
// AllShortest is a shortest-path tree created by the DijkstraAllPaths, FloydWarshall
@@ -221,9 +221,9 @@ loop: // These are likely to be rare, so just loop over collisions.
}
// Weight returns the weight of the minimum path between u and v.
func (p AllShortest) Weight(u, v graph.Node) float64 {
from, fromOK := p.indexOf[u.ID()]
to, toOK := p.indexOf[v.ID()]
func (p AllShortest) Weight(uid, vid int64) float64 {
from, fromOK := p.indexOf[uid]
to, toOK := p.indexOf[vid]
if !fromOK || !toOK {
return math.Inf(1)
}
@@ -234,11 +234,11 @@ func (p AllShortest) Weight(u, v graph.Node) float64 {
// one shortest path exists between u and v, a randomly chosen path will be returned and
// unique is returned false. If a cycle with zero weight exists in the path, it will not
// be included, but unique will be returned false.
func (p AllShortest) Between(u, v graph.Node) (path []graph.Node, weight float64, unique bool) {
from, fromOK := p.indexOf[u.ID()]
to, toOK := p.indexOf[v.ID()]
func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) {
from, fromOK := p.indexOf[uid]
to, toOK := p.indexOf[vid]
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
if u.ID() == v.ID() {
if uid == vid {
return []graph.Node{p.nodes[from]}, 0, true
}
return nil, math.Inf(1), false
@@ -290,11 +290,11 @@ func (p AllShortest) Between(u, v graph.Node) (path []graph.Node, weight float64
// AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
// containing zero-weight cycles are not returned.
func (p AllShortest) AllBetween(u, v graph.Node) (paths [][]graph.Node, weight float64) {
from, fromOK := p.indexOf[u.ID()]
to, toOK := p.indexOf[v.ID()]
func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) {
from, fromOK := p.indexOf[uid]
to, toOK := p.indexOf[vid]
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
if u.ID() == v.ID() {
if uid == vid {
return [][]graph.Node{{p.nodes[from]}}, 0
}
return nil, math.Inf(1)
@@ -302,9 +302,9 @@ func (p AllShortest) AllBetween(u, v graph.Node) (paths [][]graph.Node, weight f
var n graph.Node
if p.forward {
n = u
n = p.nodes[from]
} else {
n = v
n = p.nodes[to]
}
seen := make([]bool, len(p.nodes))
paths = p.allBetween(from, to, seen, []graph.Node{n}, nil)

View File

@@ -48,8 +48,9 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
}
u := nodes[0]
for _, v := range g.From(u) {
w, ok := g.Weight(u, v)
uid := u.ID()
for _, v := range g.From(uid) {
w, ok := g.Weight(uid, v.ID())
if !ok {
panic("prim: unexpected invalid weight")
}
@@ -59,15 +60,16 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
var w float64
for q.Len() > 0 {
e := heap.Pop(q).(simple.WeightedEdge)
if e.To() != nil && g.HasEdgeBetween(e.From(), e.To()) {
dst.SetWeightedEdge(g.WeightedEdge(e.From(), e.To()))
if e.To() != nil && g.HasEdgeBetween(e.From().ID(), e.To().ID()) {
dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID()))
w += e.Weight()
}
u = e.From()
for _, n := range g.From(u) {
uid := u.ID()
for _, n := range g.From(uid) {
if key, ok := q.key(n); ok {
w, ok := g.Weight(u, n)
w, ok := g.Weight(uid, n.ID())
if !ok {
panic("prim: unexpected invalid weight")
}
@@ -173,7 +175,7 @@ func Kruskal(dst WeightedBuilder, g UndirectedWeightLister) float64 {
for _, e := range edges {
if s1, s2 := ds.find(e.From().ID()), ds.find(e.To().ID()); s1 != s2 {
ds.union(s1, s2)
dst.SetWeightedEdge(g.WeightedEdge(e.From(), e.To()))
dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID()))
w += e.Weight()
}
}

View File

@@ -268,7 +268,7 @@ func testMinumumSpanning(mst func(dst WeightedBuilder, g spanningGraph) float64,
test.name, len(gotEdges), len(test.treeEdges))
}
for _, e := range test.treeEdges {
w, ok := dst.Weight(e.From(), e.To())
w, ok := dst.Weight(e.From().ID(), e.To().ID())
if !ok {
t.Errorf("spanning tree edge not found in graph for %q: %+v",
test.name, e)

View File

@@ -12,18 +12,16 @@ import (
// Weighting is a mapping between a pair of nodes and a weight. It follows the
// semantics of the Weighter interface.
type Weighting func(x, y graph.Node) (w float64, ok bool)
type Weighting func(xid, yid int64) (w float64, ok bool)
// UniformCost returns a Weighting that returns an edge cost of 1 for existing
// edges, zero for node identity and Inf for otherwise absent edges.
func UniformCost(g graph.Graph) Weighting {
return func(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
return func(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return 0, true
}
if e := g.Edge(x, y); e != nil {
if e := g.Edge(xid, yid); e != nil {
return 1, true
}
return math.Inf(1), false

View File

@@ -75,8 +75,8 @@ func (g *DirectedMatrix) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *DirectedMatrix) Has(n graph.Node) bool {
return g.has(n.ID())
func (g *DirectedMatrix) Has(id int64) bool {
return g.has(id)
}
func (g *DirectedMatrix) has(id int64) bool {
@@ -117,8 +117,7 @@ func (g *DirectedMatrix) Edges() []graph.Edge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *DirectedMatrix) From(n graph.Node) []graph.Node {
id := n.ID()
func (g *DirectedMatrix) From(id int64) []graph.Node {
if !g.has(id) {
return nil
}
@@ -137,8 +136,7 @@ func (g *DirectedMatrix) From(n graph.Node) []graph.Node {
}
// To returns all nodes in g that can reach directly to n.
func (g *DirectedMatrix) To(n graph.Node) []graph.Node {
id := n.ID()
func (g *DirectedMatrix) To(id int64) []graph.Node {
if !g.has(id) {
return nil
}
@@ -158,12 +156,10 @@ func (g *DirectedMatrix) To(n graph.Node) []graph.Node {
// HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction.
func (g *DirectedMatrix) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
func (g *DirectedMatrix) HasEdgeBetween(xid, yid int64) bool {
if !g.has(xid) {
return false
}
yid := y.ID()
if !g.has(yid) {
return false
}
@@ -173,27 +169,25 @@ func (g *DirectedMatrix) HasEdgeBetween(x, y graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *DirectedMatrix) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdge(u, v)
func (g *DirectedMatrix) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *DirectedMatrix) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
if g.HasEdgeFromTo(u, v) {
// x.ID() and y.ID() are not greater than maximum int by this point.
return WeightedEdge{F: g.Node(u.ID()), T: g.Node(v.ID()), W: g.mat.At(int(u.ID()), int(v.ID()))}
func (g *DirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
if g.HasEdgeFromTo(uid, vid) {
// xid and yid are not greater than maximum int by this point.
return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
}
return nil
}
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *DirectedMatrix) HasEdgeFromTo(u, v graph.Node) bool {
uid := u.ID()
func (g *DirectedMatrix) HasEdgeFromTo(uid, vid int64) bool {
if !g.has(uid) {
return false
}
vid := v.ID()
if !g.has(vid) {
return false
}
@@ -205,9 +199,7 @@ func (g *DirectedMatrix) HasEdgeFromTo(u, v graph.Node) bool {
// If x and y are the same node or there is no joining edge between the two nodes the weight
// value returned is either the graph's absent or self value. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g *DirectedMatrix) Weight(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
func (g *DirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return g.self, true
}
@@ -262,8 +254,7 @@ func (g *DirectedMatrix) RemoveEdge(e graph.Edge) {
}
// Degree returns the in+out degree of n in g.
func (g *DirectedMatrix) Degree(n graph.Node) int {
id := n.ID()
func (g *DirectedMatrix) Degree(id int64) int {
if !g.has(id) {
return 0
}

View File

@@ -75,8 +75,8 @@ func (g *UndirectedMatrix) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *UndirectedMatrix) Has(n graph.Node) bool {
return g.has(n.ID())
func (g *UndirectedMatrix) Has(id int64) bool {
return g.has(id)
}
func (g *UndirectedMatrix) has(id int64) bool {
@@ -114,8 +114,7 @@ func (g *UndirectedMatrix) Edges() []graph.Edge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *UndirectedMatrix) From(n graph.Node) []graph.Node {
id := n.ID()
func (g *UndirectedMatrix) From(id int64) []graph.Node {
if !g.has(id) {
return nil
}
@@ -134,12 +133,10 @@ func (g *UndirectedMatrix) From(n graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *UndirectedMatrix) HasEdgeBetween(u, v graph.Node) bool {
uid := u.ID()
func (g *UndirectedMatrix) HasEdgeBetween(uid, vid int64) bool {
if !g.has(uid) {
return false
}
vid := v.ID()
if !g.has(vid) {
return false
}
@@ -149,26 +146,26 @@ func (g *UndirectedMatrix) HasEdgeBetween(u, v graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *UndirectedMatrix) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdgeBetween(u, v)
func (g *UndirectedMatrix) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *UndirectedMatrix) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v)
func (g *UndirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(uid, vid)
}
// EdgeBetween returns the edge between nodes x and y.
func (g *UndirectedMatrix) EdgeBetween(u, v graph.Node) graph.Edge {
return g.WeightedEdgeBetween(u, v)
func (g *UndirectedMatrix) EdgeBetween(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *UndirectedMatrix) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
if g.HasEdgeBetween(u, v) {
// u.ID() and v.ID() are not greater than maximum int by this point.
return WeightedEdge{F: g.Node(u.ID()), T: g.Node(v.ID()), W: g.mat.At(int(u.ID()), int(v.ID()))}
func (g *UndirectedMatrix) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
if g.HasEdgeBetween(uid, vid) {
// uid and vid are not greater than maximum int by this point.
return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
}
return nil
}
@@ -177,9 +174,7 @@ func (g *UndirectedMatrix) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEd
// If x and y are the same node or there is no joining edge between the two nodes the weight
// value returned is either the graph's absent or self value. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g *UndirectedMatrix) Weight(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
func (g *UndirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return g.self, true
}
@@ -234,8 +229,7 @@ func (g *UndirectedMatrix) RemoveEdge(e graph.Edge) {
}
// Degree returns the degree of n in g.
func (g *UndirectedMatrix) Degree(n graph.Node) int {
id := n.ID()
func (g *UndirectedMatrix) Degree(id int64) int {
if !g.has(id) {
return 0
}

View File

@@ -34,17 +34,17 @@ func TestBasicDenseImpassable(t *testing.T) {
}
for i := 0; i < 5; i++ {
if !dg.Has(Node(i)) {
if !dg.Has(int64(i)) {
t.Errorf("Node that should exist doesn't: %d", i)
}
if degree := dg.Degree(Node(i)); degree != 0 {
if degree := dg.Degree(int64(i)); degree != 0 {
t.Errorf("Node in impassable graph has a neighbor. Node: %d Degree: %d", i, degree)
}
}
for i := 5; i < 10; i++ {
if dg.Has(Node(i)) {
if dg.Has(int64(i)) {
t.Errorf("Node exists that shouldn't: %d", i)
}
}
@@ -57,17 +57,17 @@ func TestBasicDensePassable(t *testing.T) {
}
for i := 0; i < 5; i++ {
if !dg.Has(Node(i)) {
if !dg.Has(int64(i)) {
t.Errorf("Node that should exist doesn't: %d", i)
}
if degree := dg.Degree(Node(i)); degree != 4 {
if degree := dg.Degree(int64(i)); degree != 4 {
t.Errorf("Node in passable graph missing neighbors. Node: %d Degree: %d", i, degree)
}
}
for i := 5; i < 10; i++ {
if dg.Has(Node(i)) {
if dg.Has(int64(i)) {
t.Errorf("Node exists that shouldn't: %d", i)
}
}
@@ -77,29 +77,29 @@ func TestDirectedDenseAddRemove(t *testing.T) {
dg := NewDirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 1})
if neighbors := dg.From(Node(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
dg.Edge(Node(0), Node(2)) == nil {
if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
dg.Edge(int64(0), int64(2)) == nil {
t.Errorf("Adding edge didn't create successor")
}
dg.RemoveEdge(Edge{F: Node(0), T: Node(2)})
if neighbors := dg.From(Node(0)); len(neighbors) != 0 || dg.Edge(Node(0), Node(2)) != nil {
if neighbors := dg.From(int64(0)); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
t.Errorf("Removing edge didn't properly remove successor")
}
if neighbors := dg.To(Node(2)); len(neighbors) != 0 || dg.Edge(Node(0), Node(2)) != nil {
if neighbors := dg.To(int64(2)); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
t.Errorf("Removing directed edge wrongly kept predecessor")
}
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 2})
// I figure we've torture tested From/To at this point
// so we'll just use the bool functions now
if dg.Edge(Node(0), Node(2)) == nil {
if dg.Edge(int64(0), int64(2)) == nil {
t.Fatal("Adding directed edge didn't change successor back")
}
c1, _ := dg.Weight(Node(2), Node(0))
c2, _ := dg.Weight(Node(0), Node(2))
c1, _ := dg.Weight(int64(2), int64(0))
c2, _ := dg.Weight(int64(0), int64(2))
if c1 == c2 {
t.Error("Adding directed edge affected cost in undirected manner")
}
@@ -109,13 +109,13 @@ func TestUndirectedDenseAddRemove(t *testing.T) {
dg := NewUndirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
dg.SetEdge(Edge{F: Node(0), T: Node(2)})
if neighbors := dg.From(Node(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
dg.EdgeBetween(Node(0), Node(2)) == nil {
if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
dg.EdgeBetween(int64(0), int64(2)) == nil {
t.Errorf("Couldn't add neighbor")
}
if neighbors := dg.From(Node(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
dg.EdgeBetween(Node(2), Node(0)) == nil {
if neighbors := dg.From(int64(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
dg.EdgeBetween(int64(2), int64(0)) == nil {
t.Errorf("Adding an undirected neighbor didn't add it reciprocally")
}
}

View File

@@ -94,10 +94,10 @@ func (g *DirectedGraph) SetEdge(e graph.Edge) {
panic("simple: adding self edge")
}
if !g.Has(from) {
if !g.Has(fid) {
g.AddNode(from)
}
if !g.Has(to) {
if !g.Has(tid) {
g.AddNode(to)
}
@@ -126,8 +126,8 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *DirectedGraph) Has(n graph.Node) bool {
_, ok := g.nodes[n.ID()]
func (g *DirectedGraph) Has(id int64) bool {
_, ok := g.nodes[id]
return ok
}
@@ -157,30 +157,30 @@ func (g *DirectedGraph) Edges() []graph.Edge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *DirectedGraph) From(n graph.Node) []graph.Node {
if _, ok := g.from[n.ID()]; !ok {
func (g *DirectedGraph) From(id int64) []graph.Node {
if _, ok := g.from[id]; !ok {
return nil
}
from := make([]graph.Node, len(g.from[n.ID()]))
from := make([]graph.Node, len(g.from[id]))
i := 0
for id := range g.from[n.ID()] {
from[i] = g.nodes[id]
for vid := range g.from[id] {
from[i] = g.nodes[vid]
i++
}
return from
}
// To returns all nodes in g that can reach directly to n.
func (g *DirectedGraph) To(n graph.Node) []graph.Node {
if _, ok := g.from[n.ID()]; !ok {
func (g *DirectedGraph) To(id int64) []graph.Node {
if _, ok := g.from[id]; !ok {
return nil
}
to := make([]graph.Node, len(g.to[n.ID()]))
to := make([]graph.Node, len(g.to[id]))
i := 0
for id := range g.to[n.ID()] {
to[i] = g.nodes[id]
for uid := range g.to[id] {
to[i] = g.nodes[uid]
i++
}
return to
@@ -188,9 +188,7 @@ func (g *DirectedGraph) To(n graph.Node) []graph.Node {
// HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction.
func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
yid := y.ID()
func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
if _, ok := g.from[xid][yid]; ok {
return true
}
@@ -200,8 +198,8 @@ func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
edge, ok := g.from[u.ID()][v.ID()]
func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
edge, ok := g.from[uid][vid]
if !ok {
return nil
}
@@ -209,17 +207,17 @@ func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
}
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
if _, ok := g.from[u.ID()][v.ID()]; !ok {
func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
if _, ok := g.from[uid][vid]; !ok {
return false
}
return true
}
// Degree returns the in+out degree of n in g.
func (g *DirectedGraph) Degree(n graph.Node) int {
if _, ok := g.nodes[n.ID()]; !ok {
func (g *DirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[id]; !ok {
return 0
}
return len(g.from[n.ID()]) + len(g.to[n.ID()])
return len(g.from[id]) + len(g.to[id])
}

View File

@@ -21,7 +21,7 @@ var (
func TestEdgeOvercounting(t *testing.T) {
g := generateDummyGraph()
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
if neigh := g.From(int64(2)); len(neigh) != 2 {
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
}
}

View File

@@ -86,10 +86,10 @@ func (g *UndirectedGraph) SetEdge(e graph.Edge) {
panic("simple: adding self edge")
}
if !g.Has(from) {
if !g.Has(fid) {
g.AddNode(from)
}
if !g.Has(to) {
if !g.Has(tid) {
g.AddNode(to)
}
@@ -118,8 +118,8 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *UndirectedGraph) Has(n graph.Node) bool {
_, ok := g.nodes[n.ID()]
func (g *UndirectedGraph) Has(id int64) bool {
_, ok := g.nodes[id]
return ok
}
@@ -160,14 +160,14 @@ func (g *UndirectedGraph) Edges() []graph.Edge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
if !g.Has(n) {
func (g *UndirectedGraph) From(id int64) []graph.Node {
if !g.Has(id) {
return nil
}
nodes := make([]graph.Node, len(g.edges[n.ID()]))
nodes := make([]graph.Node, len(g.edges[id]))
i := 0
for from := range g.edges[n.ID()] {
for from := range g.edges[id] {
nodes[i] = g.nodes[from]
i++
}
@@ -175,20 +175,20 @@ func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *UndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
_, ok := g.edges[x.ID()][y.ID()]
func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
_, ok := g.edges[xid][yid]
return ok
}
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
return g.EdgeBetween(u, v)
func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.EdgeBetween(uid, vid)
}
// EdgeBetween returns the edge between nodes x and y.
func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
edge, ok := g.edges[x.ID()][y.ID()]
func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
edge, ok := g.edges[xid][yid]
if !ok {
return nil
}
@@ -196,9 +196,9 @@ func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
}
// Degree returns the degree of n in g.
func (g *UndirectedGraph) Degree(n graph.Node) int {
if _, ok := g.nodes[n.ID()]; !ok {
func (g *UndirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[id]; !ok {
return 0
}
return len(g.edges[n.ID()])
return len(g.edges[id])
}

View File

@@ -37,7 +37,7 @@ func TestMaxID(t *testing.T) {
delete(nodes, Node(2))
n := g.NewNode()
g.AddNode(n)
if !g.Has(n) {
if !g.Has(n.ID()) {
t.Error("added node does not exist in graph")
}
if _, exists := nodes[n]; exists {

View File

@@ -100,10 +100,10 @@ func (g *WeightedDirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
panic("simple: adding self edge")
}
if !g.Has(from) {
if !g.Has(fid) {
g.AddNode(from)
}
if !g.Has(to) {
if !g.Has(tid) {
g.AddNode(to)
}
@@ -132,8 +132,8 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *WeightedDirectedGraph) Has(n graph.Node) bool {
_, ok := g.nodes[n.ID()]
func (g *WeightedDirectedGraph) Has(id int64) bool {
_, ok := g.nodes[id]
return ok
}
@@ -174,30 +174,30 @@ func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *WeightedDirectedGraph) From(n graph.Node) []graph.Node {
if _, ok := g.from[n.ID()]; !ok {
func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
if _, ok := g.from[id]; !ok {
return nil
}
from := make([]graph.Node, len(g.from[n.ID()]))
from := make([]graph.Node, len(g.from[id]))
i := 0
for id := range g.from[n.ID()] {
from[i] = g.nodes[id]
for vid := range g.from[id] {
from[i] = g.nodes[vid]
i++
}
return from
}
// To returns all nodes in g that can reach directly to n.
func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
if _, ok := g.from[n.ID()]; !ok {
func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
if _, ok := g.from[id]; !ok {
return nil
}
to := make([]graph.Node, len(g.to[n.ID()]))
to := make([]graph.Node, len(g.to[id]))
i := 0
for id := range g.to[n.ID()] {
to[i] = g.nodes[id]
for uid := range g.to[id] {
to[i] = g.nodes[uid]
i++
}
return to
@@ -205,9 +205,7 @@ func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
// HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction.
func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
xid := x.ID()
yid := y.ID()
func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
if _, ok := g.from[xid][yid]; ok {
return true
}
@@ -217,14 +215,14 @@ func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *WeightedDirectedGraph) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdge(u, v)
func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
edge, ok := g.from[u.ID()][v.ID()]
func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
edge, ok := g.from[uid][vid]
if !ok {
return nil
}
@@ -232,8 +230,8 @@ func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge
}
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
if _, ok := g.from[u.ID()][v.ID()]; !ok {
func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
if _, ok := g.from[uid][vid]; !ok {
return false
}
return true
@@ -243,9 +241,7 @@ func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
// If x and y are the same node or there is no joining edge between the two nodes the weight
// value returned is either the graph's absent or self value. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g *WeightedDirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
func (g *WeightedDirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return g.self, true
}
@@ -258,9 +254,9 @@ func (g *WeightedDirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
}
// Degree returns the in+out degree of n in g.
func (g *WeightedDirectedGraph) Degree(n graph.Node) int {
if _, ok := g.nodes[n.ID()]; !ok {
func (g *WeightedDirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[id]; !ok {
return 0
}
return len(g.from[n.ID()]) + len(g.to[n.ID()])
return len(g.from[id]) + len(g.to[id])
}

View File

@@ -23,7 +23,7 @@ var (
func TestWeightedEdgeOvercounting(t *testing.T) {
g := generateDummyGraph()
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
if neigh := g.From(int64(2)); len(neigh) != 2 {
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
}
}

View File

@@ -92,10 +92,10 @@ func (g *WeightedUndirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
panic("simple: adding self edge")
}
if !g.Has(from) {
if !g.Has(fid) {
g.AddNode(from)
}
if !g.Has(to) {
if !g.Has(tid) {
g.AddNode(to)
}
@@ -124,8 +124,8 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
}
// Has returns whether the node exists within the graph.
func (g *WeightedUndirectedGraph) Has(n graph.Node) bool {
_, ok := g.nodes[n.ID()]
func (g *WeightedUndirectedGraph) Has(id int64) bool {
_, ok := g.nodes[id]
return ok
}
@@ -185,14 +185,14 @@ func (g *WeightedUndirectedGraph) WeightedEdges() []graph.WeightedEdge {
}
// From returns all nodes in g that can be reached directly from n.
func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
if !g.Has(n) {
func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
if !g.Has(id) {
return nil
}
nodes := make([]graph.Node, len(g.edges[n.ID()]))
nodes := make([]graph.Node, len(g.edges[id]))
i := 0
for from := range g.edges[n.ID()] {
for from := range g.edges[id] {
nodes[i] = g.nodes[from]
i++
}
@@ -200,31 +200,31 @@ func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *WeightedUndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
_, ok := g.edges[x.ID()][y.ID()]
func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
_, ok := g.edges[xid][yid]
return ok
}
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *WeightedUndirectedGraph) Edge(u, v graph.Node) graph.Edge {
return g.WeightedEdgeBetween(u, v)
func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(uid, vid)
}
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v)
func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(uid, vid)
}
// EdgeBetween returns the edge between nodes x and y.
func (g *WeightedUndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
return g.WeightedEdgeBetween(x, y)
func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
return g.WeightedEdgeBetween(xid, yid)
}
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
edge, ok := g.edges[x.ID()][y.ID()]
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
edge, ok := g.edges[xid][yid]
if !ok {
return nil
}
@@ -235,9 +235,7 @@ func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.Wei
// If x and y are the same node or there is no joining edge between the two nodes the weight
// value returned is either the graph's absent or self value. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
if xid == yid {
return g.self, true
}
@@ -250,9 +248,9 @@ func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
}
// Degree returns the degree of n in g.
func (g *WeightedUndirectedGraph) Degree(n graph.Node) int {
if _, ok := g.nodes[n.ID()]; !ok {
func (g *WeightedUndirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[id]; !ok {
return 0
}
return len(g.edges[n.ID()])
return len(g.edges[id])
}

View File

@@ -39,7 +39,7 @@ func TestWeightedMaxID(t *testing.T) {
delete(nodes, Node(2))
n := g.NewNode()
g.AddNode(n)
if !g.Has(n) {
if !g.Has(n.ID()) {
t.Error("added node does not exist in graph")
}
if _, exists := nodes[n]; exists {

View File

@@ -123,7 +123,7 @@ func twoSat(r io.Reader) (state map[string]bool, ok bool) {
// Check for tautology.
if variables[0].negated().ID() == variables[1].ID() {
for _, v := range variables {
if !g.Has(v) {
if !g.Has(v.ID()) {
g.AddNode(v)
}
}

View File

@@ -60,9 +60,10 @@ func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) {
neighbours = make(map[int64][]graph.Node)
)
for _, n := range nodes {
adj := g.From(n)
neighbours[n.ID()] = adj
dv[n.ID()] = len(adj)
id := n.ID()
adj := g.From(id)
neighbours[id] = adj
dv[id] = len(adj)
if len(adj) > maxDegree {
maxDegree = len(adj)
}
@@ -146,7 +147,7 @@ func BronKerbosch(g graph.Undirected) [][]graph.Node {
order, _ := degeneracyOrdering(g)
ordered.Reverse(order)
for _, v := range order {
neighbours := g.From(v)
neighbours := g.From(v.ID())
nv := make(set.Nodes, len(neighbours))
for _, n := range neighbours {
nv.Add(n)
@@ -175,7 +176,8 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
if nu.Has(v) {
continue
}
neighbours := g.From(v)
vid := v.ID()
neighbours := g.From(vid)
nv := make(set.Nodes, len(neighbours))
for _, n := range neighbours {
nv.Add(n)
@@ -183,7 +185,7 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
var found bool
for _, n := range r {
if n.ID() == v.ID() {
if n.ID() == vid {
found = true
break
}
@@ -205,10 +207,10 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
// compile time option.
if !tomitaTanakaTakahashi {
for _, n := range p {
return g.From(n)
return g.From(n.ID())
}
for _, n := range x {
return g.From(n)
return g.From(n.ID())
}
panic("bronKerbosch: empty set")
}
@@ -220,7 +222,7 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
maxNeighbors := func(s set.Nodes) {
outer:
for _, u := range s {
nb := g.From(u)
nb := g.From(u.ID())
c := len(nb)
if c <= max {
continue

View File

@@ -53,7 +53,7 @@ func TestDegeneracyOrdering(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -93,7 +93,7 @@ func TestKCore(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -175,7 +175,7 @@ func TestBronKerbosch(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -92,7 +92,7 @@ func TestCliqueGraph(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -142,14 +142,15 @@ func johnsonGraphFrom(g graph.Directed) johnsonGraph {
succ: make(map[int64]set.Int64s),
}
for i, u := range nodes {
c.index[u.ID()] = i
for _, v := range g.From(u) {
if c.succ[u.ID()] == nil {
c.succ[u.ID()] = make(set.Int64s)
c.nodes.Add(u.ID())
uid := u.ID()
c.index[uid] = i
for _, v := range g.From(uid) {
if c.succ[uid] == nil {
c.succ[uid] = make(set.Int64s)
c.nodes.Add(uid)
}
c.nodes.Add(v.ID())
c.succ[u.ID()].Add(v.ID())
c.succ[uid].Add(v.ID())
}
}
return c
@@ -247,31 +248,31 @@ func (g johnsonGraph) Nodes() []graph.Node {
}
// Successors is required to satisfy Tarjan.
func (g johnsonGraph) From(n graph.Node) []graph.Node {
adj := g.succ[n.ID()]
func (g johnsonGraph) From(id int64) []graph.Node {
adj := g.succ[id]
if len(adj) == 0 {
return nil
}
succ := make([]graph.Node, 0, len(adj))
for n := range adj {
succ = append(succ, johnsonGraphNode(n))
for id := range adj {
succ = append(succ, johnsonGraphNode(id))
}
return succ
}
func (johnsonGraph) Has(graph.Node) bool {
func (johnsonGraph) Has(int64) bool {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) HasEdgeBetween(_, _ graph.Node) bool {
func (johnsonGraph) HasEdgeBetween(_, _ int64) bool {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) Edge(_, _ graph.Node) graph.Edge {
func (johnsonGraph) Edge(_, _ int64) graph.Edge {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) HasEdgeFromTo(_, _ graph.Node) bool {
func (johnsonGraph) HasEdgeFromTo(_, _ int64) bool {
panic("topo: unintended use of johnsonGraph")
}
func (johnsonGraph) To(graph.Node) []graph.Node {
func (johnsonGraph) To(int64) []graph.Node {
panic("topo: unintended use of johnsonGraph")
}

View File

@@ -88,7 +88,7 @@ func TestDirectedCyclesIn(t *testing.T) {
g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -35,7 +35,7 @@ func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
u := tree.Pop()
uid := u.ID()
adj := from[uid]
for _, v := range g.From(u) {
for _, v := range g.From(uid) {
vid := v.ID()
switch {
case uid == vid:

View File

@@ -77,7 +77,7 @@ func TestUndirectedCyclesIn(t *testing.T) {
g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -95,15 +95,15 @@ func TarjanSCC(g graph.Directed) [][]graph.Node {
func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
nodes := g.Nodes()
var succ func(graph.Node) []graph.Node
var succ func(id int64) []graph.Node
if order == nil {
succ = g.From
} else {
order(nodes)
ordered.Reverse(nodes)
succ = func(n graph.Node) []graph.Node {
to := g.From(n)
succ = func(id int64) []graph.Node {
to := g.From(id)
order(to)
ordered.Reverse(to)
return to
@@ -131,7 +131,7 @@ func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.N
// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644
//
type tarjan struct {
succ func(graph.Node) []graph.Node
succ func(id int64) []graph.Node
index int
indexTable map[int64]int
@@ -156,7 +156,7 @@ func (t *tarjan) strongconnect(v graph.Node) {
t.onStack.Add(vID)
// Consider successors of v.
for _, w := range t.succ(v) {
for _, w := range t.succ(vID) {
wID := w.ID()
if t.indexTable[wID] == 0 {
// Successor w has not yet been visited; recur on it.

View File

@@ -132,7 +132,7 @@ func TestSort(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -163,7 +163,7 @@ func TestTarjanSCC(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -290,7 +290,7 @@ func TestSortStabilized(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {

View File

@@ -18,9 +18,9 @@ func IsPathIn(g graph.Graph, path []graph.Node) bool {
case 0:
return true
case 1:
return g.Has(path[0])
return g.Has(path[0].ID())
default:
var canReach func(u, v graph.Node) bool
var canReach func(uid, vid int64) bool
switch g := g.(type) {
case graph.Directed:
canReach = g.HasEdgeFromTo
@@ -29,7 +29,7 @@ func IsPathIn(g graph.Graph, path []graph.Node) bool {
}
for i, u := range path[:len(path)-1] {
if !canReach(u, path[i+1]) {
if !canReach(u.ID(), path[i+1].ID()) {
return false
}
}

View File

@@ -71,11 +71,11 @@ func TestPathExistsInUndirected(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
if !g.Has(simple.Node(v)) {
if !g.Has(int64(v)) {
g.AddNode(simple.Node(v))
}
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
@@ -110,11 +110,11 @@ func TestPathExistsInDirected(t *testing.T) {
g := simple.NewDirectedGraph()
for u, e := range test.g {
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
if !g.Has(simple.Node(v)) {
if !g.Has(int64(v)) {
g.AddNode(simple.Node(v))
}
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
@@ -147,11 +147,11 @@ func TestConnectedComponents(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
if !g.Has(simple.Node(v)) {
if !g.Has(int64(v)) {
g.AddNode(simple.Node(v))
}
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})

View File

@@ -40,17 +40,19 @@ func (b *BreadthFirst) Walk(g graph.Graph, from graph.Node, until func(n graph.N
if until != nil && until(t, depth) {
return t
}
for _, n := range g.From(t) {
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(t, n)) {
tid := t.ID()
for _, n := range g.From(tid) {
nid := n.ID()
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(tid, nid)) {
continue
}
if b.visited.Has(n.ID()) {
if b.visited.Has(nid) {
continue
}
if b.Visit != nil {
b.Visit(t, n)
}
b.visited.Add(n.ID())
b.visited.Add(nid)
children++
b.queue.Enqueue(n)
}
@@ -125,17 +127,19 @@ func (d *DepthFirst) Walk(g graph.Graph, from graph.Node, until func(graph.Node)
if until != nil && until(t) {
return t
}
for _, n := range g.From(t) {
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) {
tid := t.ID()
for _, n := range g.From(tid) {
nid := n.ID()
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(tid, nid)) {
continue
}
if d.visited.Has(n.ID()) {
if d.visited.Has(nid) {
continue
}
if d.Visit != nil {
d.Visit(t, n)
}
d.visited.Add(n.ID())
d.visited.Add(nid)
d.stack.Push(n)
}
}

View File

@@ -136,7 +136,7 @@ func TestBreadthFirst(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -224,7 +224,7 @@ func TestDepthFirst(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
// Add nodes that are not defined by an edge.
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
@@ -285,11 +285,11 @@ func TestWalkAll(t *testing.T) {
g := simple.NewUndirectedGraph()
for u, e := range test.g {
if !g.Has(simple.Node(u)) {
if !g.Has(int64(u)) {
g.AddNode(simple.Node(u))
}
for v := range e {
if !g.Has(simple.Node(v)) {
if !g.Has(int64(v)) {
g.AddNode(simple.Node(v))
}
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})

View File

@@ -12,20 +12,20 @@ type Undirect struct {
var _ Undirected = Undirect{}
// Has returns whether the node exists within the graph.
func (g Undirect) Has(n Node) bool { return g.G.Has(n) }
func (g Undirect) Has(id int64) bool { return g.G.Has(id) }
// Nodes returns all the nodes in the graph.
func (g Undirect) Nodes() []Node { return g.G.Nodes() }
// From returns all nodes in g that can be reached directly from u.
func (g Undirect) From(u Node) []Node {
func (g Undirect) From(uid int64) []Node {
var nodes []Node
seen := make(map[int64]struct{})
for _, n := range g.G.From(u) {
for _, n := range g.G.From(uid) {
seen[n.ID()] = struct{}{}
nodes = append(nodes, n)
}
for _, n := range g.G.To(u) {
for _, n := range g.G.To(uid) {
id := n.ID()
if _, ok := seen[id]; ok {
continue
@@ -37,21 +37,21 @@ func (g Undirect) From(u Node) []Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g Undirect) HasEdgeBetween(x, y Node) bool { return g.G.HasEdgeBetween(x, y) }
func (g Undirect) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// If an edge exists, the Edge returned is an EdgePair. The weight of
// the edge is determined by applying the Merge func to the weights of the
// edges between u and v.
func (g Undirect) Edge(u, v Node) Edge { return g.EdgeBetween(u, v) }
func (g Undirect) Edge(uid, vid int64) Edge { return g.EdgeBetween(uid, vid) }
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
// Edge returned is an EdgePair. The weight of the edge is determined by
// applying the Merge func to the weights of edges between x and y.
func (g Undirect) EdgeBetween(x, y Node) Edge {
fe := g.G.Edge(x, y)
re := g.G.Edge(y, x)
func (g Undirect) EdgeBetween(xid, yid int64) Edge {
fe := g.G.Edge(xid, yid)
re := g.G.Edge(yid, xid)
if fe == nil && re == nil {
return nil
}
@@ -91,20 +91,20 @@ var (
)
// Has returns whether the node exists within the graph.
func (g UndirectWeighted) Has(n Node) bool { return g.G.Has(n) }
func (g UndirectWeighted) Has(id int64) bool { return g.G.Has(id) }
// Nodes returns all the nodes in the graph.
func (g UndirectWeighted) Nodes() []Node { return g.G.Nodes() }
// From returns all nodes in g that can be reached directly from u.
func (g UndirectWeighted) From(u Node) []Node {
func (g UndirectWeighted) From(uid int64) []Node {
var nodes []Node
seen := make(map[int64]struct{})
for _, n := range g.G.From(u) {
for _, n := range g.G.From(uid) {
seen[n.ID()] = struct{}{}
nodes = append(nodes, n)
}
for _, n := range g.G.To(u) {
for _, n := range g.G.To(uid) {
id := n.ID()
if _, ok := seen[id]; ok {
continue
@@ -116,44 +116,46 @@ func (g UndirectWeighted) From(u Node) []Node {
}
// HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g UndirectWeighted) HasEdgeBetween(x, y Node) bool { return g.G.HasEdgeBetween(x, y) }
func (g UndirectWeighted) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// If an edge exists, the Edge returned is an EdgePair. The weight of
// the edge is determined by applying the Merge func to the weights of the
// edges between u and v.
func (g UndirectWeighted) Edge(u, v Node) Edge { return g.WeightedEdgeBetween(u, v) }
func (g UndirectWeighted) Edge(uid, vid int64) Edge { return g.WeightedEdgeBetween(uid, vid) }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
// The node v must be directly reachable from u as defined by the From method.
// If an edge exists, the Edge returned is an EdgePair. The weight of
// the edge is determined by applying the Merge func to the weights of the
// edges between u and v.
func (g UndirectWeighted) WeightedEdge(u, v Node) WeightedEdge { return g.WeightedEdgeBetween(u, v) }
func (g UndirectWeighted) WeightedEdge(uid, vid int64) WeightedEdge {
return g.WeightedEdgeBetween(uid, vid)
}
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
// Edge returned is an EdgePair. The weight of the edge is determined by
// applying the Merge func to the weights of edges between x and y.
func (g UndirectWeighted) EdgeBetween(x, y Node) Edge {
return g.WeightedEdgeBetween(x, y)
func (g UndirectWeighted) EdgeBetween(xid, yid int64) Edge {
return g.WeightedEdgeBetween(xid, yid)
}
// WeightedEdgeBetween returns the weighted edge between nodes x and y. If an edge exists, the
// Edge returned is an EdgePair. The weight of the edge is determined by
// applying the Merge func to the weights of edges between x and y.
func (g UndirectWeighted) WeightedEdgeBetween(x, y Node) WeightedEdge {
fe := g.G.Edge(x, y)
re := g.G.Edge(y, x)
func (g UndirectWeighted) WeightedEdgeBetween(xid, yid int64) WeightedEdge {
fe := g.G.Edge(xid, yid)
re := g.G.Edge(yid, xid)
if fe == nil && re == nil {
return nil
}
f, ok := g.G.Weight(x, y)
f, ok := g.G.Weight(xid, yid)
if !ok {
f = g.Absent
}
r, ok := g.G.Weight(y, x)
r, ok := g.G.Weight(yid, xid)
if !ok {
r = g.Absent
}
@@ -171,15 +173,15 @@ func (g UndirectWeighted) WeightedEdgeBetween(x, y Node) WeightedEdge {
// If x and y are the same node the internal node weight is returned. If there is no joining
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
// exists between x and y or if x and y have the same ID, false otherwise.
func (g UndirectWeighted) Weight(x, y Node) (w float64, ok bool) {
fe := g.G.Edge(x, y)
re := g.G.Edge(y, x)
func (g UndirectWeighted) Weight(xid, yid int64) (w float64, ok bool) {
fe := g.G.Edge(xid, yid)
re := g.G.Edge(yid, xid)
f, fOk := g.G.Weight(x, y)
f, fOk := g.G.Weight(xid, yid)
if !fOk {
f = g.Absent
}
r, rOK := g.G.Weight(y, x)
r, rOK := g.G.Weight(yid, xid)
if !rOK {
r = g.Absent
}

View File

@@ -123,8 +123,8 @@ func TestUndirect(t *testing.T) {
src := graph.Undirect{G: g}
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
for _, u := range src.Nodes() {
for _, v := range src.From(u) {
dst.SetEdge(src.Edge(u, v))
for _, v := range src.From(u.ID()) {
dst.SetEdge(src.Edge(u.ID(), v.ID()))
}
}
@@ -148,8 +148,8 @@ func TestUndirectWeighted(t *testing.T) {
src := graph.UndirectWeighted{G: g, Absent: test.absent, Merge: test.merge}
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
for _, u := range src.Nodes() {
for _, v := range src.From(u) {
dst.SetWeightedEdge(src.WeightedEdge(u, v))
for _, v := range src.From(u.ID()) {
dst.SetWeightedEdge(src.WeightedEdge(u.ID(), v.ID()))
}
}