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

View File

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

View File

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

View File

@@ -34,24 +34,28 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
for _, n := range nodes { for _, n := range nodes {
var wOut float64 var wOut float64
u := n u := n
for _, v := range g.From(u) { uid := u.ID()
wOut += weight(u, v) for _, v := range g.From(uid) {
wOut += weight(uid, v.ID())
} }
var wIn float64 var wIn float64
v := n v := n
for _, u := range g.To(v) { vid := v.ID()
wIn += weight(u, v) 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. 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 { if communities == nil {
var q float64 var q float64
for _, u := range nodes { for _, u := range nodes {
kU := k[u.ID()] uid := u.ID()
q += weight(u, u) - resolution*kU.out*kU.in/m kU := k[uid]
q += weight(uid, uid) - resolution*kU.out*kU.in/m
} }
return q / m return q / m
} }
@@ -59,10 +63,12 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
var q float64 var q float64
for _, c := range communities { for _, c := range communities {
for _, u := range c { for _, u := range c {
kU := k[u.ID()] uid := u.ID()
kU := k[uid]
for _, v := range c { for _, v := range c {
kV := k[v.ID()] vid := v.ID()
q += weight(u, v) - resolution*kU.out*kV.in/m 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 var out []int
u := n u := n
for _, v := range g.From(u) { uid := u.ID()
vid := communityOf[v.ID()] for _, v := range g.From(uid) {
if vid != id { vid := v.ID()
out = append(out, vid) 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 r.edgesFrom[id] = out
var in []int var in []int
v := n v := n
for _, u := range g.To(v) { vid := v.ID()
uid := communityOf[u.ID()] for _, u := range g.To(vid) {
if uid != id { uid := u.ID()
in = append(in, uid) 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 r.edgesTo[id] = in
} }
@@ -270,43 +280,47 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
var out, in []int var out, in []int
for _, n := range comm { for _, n := range comm {
u := n u := n
uid := u.ID()
for _, v := range comm { 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) { for _, v := range g.From(uid) {
vid := communityOf[v.ID()] vid := v.ID()
vcid := communityOf[vid]
found := false found := false
for _, e := range out { for _, e := range out {
if e == vid { if e == vcid {
found = true found = true
break break
} }
} }
if !found && vid != id { if !found && vcid != id {
out = append(out, vid) out = append(out, vcid)
} }
// Add half weights because the other // Add half weights because the other
// ends of edges are also counted. // 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 v := n
for _, u := range g.To(v) { vid := v.ID()
uid := communityOf[u.ID()] for _, u := range g.To(vid) {
uid := u.ID()
ucid := communityOf[uid]
found := false found := false
for _, e := range in { for _, e := range in {
if e == uid { if e == ucid {
found = true found = true
break break
} }
} }
if !found && uid != id { if !found && ucid != id {
in = append(in, uid) in = append(in, ucid)
} }
// Add half weights because the other // Add half weights because the other
// ends of edges are also counted. // 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 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. // Has returns whether the node exists within the graph.
func (g *ReducedDirected) Has(n graph.Node) bool { func (g *ReducedDirected) Has(id int64) bool {
id := n.ID()
return 0 <= id && id < int64(len(g.nodes)) 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. // From returns all nodes in g that can be reached directly from u.
func (g *ReducedDirected) From(u graph.Node) []graph.Node { func (g *ReducedDirected) From(uid int64) []graph.Node {
out := g.edgesFrom[u.ID()] out := g.edgesFrom[uid]
nodes := make([]graph.Node, len(out)) nodes := make([]graph.Node, len(out))
for i, vid := range out { for i, vid := range out {
nodes[i] = g.nodes[vid] 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. // To returns all nodes in g that can reach directly to v.
func (g *ReducedDirected) To(v graph.Node) []graph.Node { func (g *ReducedDirected) To(vid int64) []graph.Node {
in := g.edgesTo[v.ID()] in := g.edgesTo[vid]
nodes := make([]graph.Node, len(in)) nodes := make([]graph.Node, len(in))
for i, uid := range in { for i, uid := range in {
nodes[i] = g.nodes[uid] 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *ReducedDirected) HasEdgeBetween(x, y graph.Node) bool { func (g *ReducedDirected) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
yid := y.ID()
if xid == yid || !isValidID(xid) || !isValidID(yid) { if xid == yid || !isValidID(xid) || !isValidID(yid) {
return false 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. // HasEdgeFromTo returns whether an edge exists from node u to v.
func (g *ReducedDirected) HasEdgeFromTo(u, v graph.Node) bool { func (g *ReducedDirected) HasEdgeFromTo(uid, vid int64) bool {
uid := u.ID()
vid := v.ID()
if uid == vid || !isValidID(uid) || !isValidID(vid) { if uid == vid || !isValidID(uid) || !isValidID(vid) {
return false 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. // 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 node v must be directly reachable from u as defined by the From method.
func (g *ReducedDirected) Edge(u, v graph.Node) graph.Edge { func (g *ReducedDirected) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(u, v) return g.WeightedEdge(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g *ReducedDirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *ReducedDirected) WeightedEdge(uid, vid int64) graph.WeightedEdge {
uid := u.ID()
vid := v.ID()
if uid == vid || !isValidID(uid) || !isValidID(vid) { if uid == vid || !isValidID(uid) || !isValidID(vid) {
return nil 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 // 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 // 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. // 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) { func (g *ReducedDirected) Weight(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if !isValidID(xid) || !isValidID(yid) { if !isValidID(xid) || !isValidID(yid) {
return 0, false return 0, false
} }
@@ -433,7 +438,7 @@ type directedLocalMover struct {
// that returns the Weight value // that returns the Weight value
// of the non-nil edge between x // of the non-nil edge between x
// and y. // and y.
weight func(x, y graph.Node) float64 weight func(xid, yid int64) float64
// communities is the current // communities is the current
// division of g. // division of g.
@@ -484,18 +489,21 @@ func newDirectedLocalMover(g *ReducedDirected, communities [][]graph.Node, resol
for _, n := range l.nodes { for _, n := range l.nodes {
u := n u := n
var wOut float64 var wOut float64
for _, v := range g.From(u) { uid := u.ID()
wOut += l.weight(u, v) for _, v := range g.From(uid) {
wOut += l.weight(uid, v.ID())
} }
v := n v := n
var wIn float64 var wIn float64
for _, u := range g.To(v) { vid := v.ID()
wIn += l.weight(u, v) for _, u := range g.To(vid) {
wIn += l.weight(u.ID(), vid)
} }
w := l.weight(n, n) id := n.ID()
l.edgeWeightsOf[n.ID()] = directedWeights{out: w + wOut, in: w + wIn} w := l.weight(id, id)
l.edgeWeightsOf[id] = directedWeights{out: w + wOut, in: w + wIn}
l.m += w + wOut 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) { func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
id := n.ID() id := n.ID()
a_aa := l.weight(n, n) a_aa := l.weight(id, id)
k_a := l.edgeWeightsOf[id] k_a := l.edgeWeightsOf[id]
m := l.m m := l.m
gamma := l.resolution gamma := l.resolution
@@ -613,8 +621,8 @@ func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src
removal = true removal = true
} }
k_aC.in += l.weight(u, n) k_aC.in += l.weight(uid, id)
k_aC.out += l.weight(n, u) k_aC.out += l.weight(id, uid)
// sigma_totC could be kept for each community // sigma_totC could be kept for each community
// and updated for moves, changing the calculation // and updated for moves, changing the calculation
// of sigma_totC here from O(n_c) to O(1), but // 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] layerResolution = resolutions[l]
} }
var weight func(x, y graph.Node) float64 var weight func(xid, yid int64) float64
if layerWeight < 0 { if layerWeight < 0 {
weight = negativeWeightFuncFor(layer) weight = negativeWeightFuncFor(layer)
} else { } else {
@@ -77,15 +77,18 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
for _, n := range nodes { for _, n := range nodes {
var wOut float64 var wOut float64
u := n u := n
for _, v := range layer.From(u) { uid := u.ID()
wOut += weight(u, v) for _, v := range layer.From(uid) {
wOut += weight(uid, v.ID())
} }
var wIn float64 var wIn float64
v := n v := n
for _, u := range layer.To(v) { vid := v.ID()
wIn += weight(u, v) 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. m += w + wOut // We only need to count edges once.
k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn} 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 { if communities == nil {
var qLayer float64 var qLayer float64
for _, u := range nodes { for _, u := range nodes {
kU := k[u.ID()] uid := u.ID()
qLayer += weight(u, u) - layerResolution*kU.out*kU.in/m kU := k[uid]
qLayer += weight(uid, uid) - layerResolution*kU.out*kU.in/m
} }
q[l] = layerWeight * qLayer q[l] = layerWeight * qLayer
continue continue
@@ -103,10 +107,12 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
var qLayer float64 var qLayer float64
for _, c := range communities { for _, c := range communities {
for _, u := range c { for _, u := range c {
kU := k[u.ID()] uid := u.ID()
kU := k[uid]
for _, v := range c { for _, v := range c {
kV := k[v.ID()] vid := v.ID()
qLayer += weight(u, v) - layerResolution*kU.out*kV.in/m 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 continue
} }
var sign float64 var sign float64
var weight func(x, y graph.Node) float64 var weight func(xid, yid int64) float64
if w < 0 { if w < 0 {
sign, weight = -1, negativeWeightFuncFor(layer) sign, weight = -1, negativeWeightFuncFor(layer)
} else { } else {
@@ -332,23 +338,27 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
var out []int var out []int
u := n u := n
for _, v := range layer.From(u) { uid := u.ID()
vid := communityOf[v.ID()] for _, v := range layer.From(uid) {
if vid != id { vid := v.ID()
out = append(out, vid) 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 r.layers[l].edgesFrom[id] = out
var in []int var in []int
v := n v := n
for _, u := range layer.To(v) { vid := v.ID()
uid := communityOf[u.ID()] for _, u := range layer.To(vid) {
if uid != id { uid := u.ID()
in = append(in, uid) 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 r.layers[l].edgesTo[id] = in
} }
@@ -408,7 +418,7 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
continue continue
} }
var sign float64 var sign float64
var weight func(x, y graph.Node) float64 var weight func(xid, yid int64) float64
if w < 0 { if w < 0 {
sign, weight = -1, negativeWeightFuncFor(layer) sign, weight = -1, negativeWeightFuncFor(layer)
} else { } else {
@@ -418,43 +428,47 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
var out, in []int var out, in []int
for _, n := range comm { for _, n := range comm {
u := n u := n
uid := u.ID()
for _, v := range comm { 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) { for _, v := range layer.From(uid) {
vid := communityOf[v.ID()] vid := v.ID()
vcid := communityOf[vid]
found := false found := false
for _, e := range out { for _, e := range out {
if e == vid { if e == vcid {
found = true found = true
break break
} }
} }
if !found && vid != id { if !found && vcid != id {
out = append(out, vid) out = append(out, vcid)
} }
// Add half weights because the other // Add half weights because the other
// ends of edges are also counted. // 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 v := n
for _, u := range layer.To(v) { vid := v.ID()
uid := communityOf[u.ID()] for _, u := range layer.To(vid) {
uid := u.ID()
ucid := communityOf[uid]
found := false found := false
for _, e := range in { for _, e := range in {
if e == uid { if e == ucid {
found = true found = true
break break
} }
} }
if !found && uid != id { if !found && ucid != id {
in = append(in, uid) in = append(in, ucid)
} }
// Add half weights because the other // Add half weights because the other
// ends of edges are also counted. // 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. // Has returns whether the node exists within the graph.
func (g directedLayerHandle) Has(n graph.Node) bool { func (g directedLayerHandle) Has(id int64) bool {
id := n.ID()
return 0 <= id && id < int64(len(g.multiplex.nodes)) 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. // From returns all nodes in g that can be reached directly from u.
func (g directedLayerHandle) From(u graph.Node) []graph.Node { func (g directedLayerHandle) From(uid int64) []graph.Node {
out := g.multiplex.layers[g.layer].edgesFrom[u.ID()] out := g.multiplex.layers[g.layer].edgesFrom[uid]
nodes := make([]graph.Node, len(out)) nodes := make([]graph.Node, len(out))
for i, vid := range out { for i, vid := range out {
nodes[i] = g.multiplex.nodes[vid] 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. // To returns all nodes in g that can reach directly to v.
func (g directedLayerHandle) To(v graph.Node) []graph.Node { func (g directedLayerHandle) To(vid int64) []graph.Node {
in := g.multiplex.layers[g.layer].edgesTo[v.ID()] in := g.multiplex.layers[g.layer].edgesTo[vid]
nodes := make([]graph.Node, len(in)) nodes := make([]graph.Node, len(in))
for i, uid := range in { for i, uid := range in {
nodes[i] = g.multiplex.nodes[uid] 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g directedLayerHandle) HasEdgeBetween(x, y graph.Node) bool { func (g directedLayerHandle) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
yid := y.ID()
if xid == yid { if xid == yid {
return false 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. // HasEdgeFromTo returns whether an edge exists from node u to v.
func (g directedLayerHandle) HasEdgeFromTo(u, v graph.Node) bool { func (g directedLayerHandle) HasEdgeFromTo(uid, vid int64) bool {
uid := u.ID()
vid := v.ID()
if uid == vid || !isValidID(uid) || !isValidID(vid) { if uid == vid || !isValidID(uid) || !isValidID(vid) {
return false 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. // 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 node v must be directly reachable from u as defined by the From method.
func (g directedLayerHandle) Edge(u, v graph.Node) graph.Edge { func (g directedLayerHandle) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(u, v) return g.WeightedEdge(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g directedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g directedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge {
uid := u.ID()
vid := v.ID()
if uid == vid || !isValidID(uid) || !isValidID(vid) { if uid == vid || !isValidID(uid) || !isValidID(vid) {
return nil return nil
} }
@@ -559,16 +566,14 @@ func (g directedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
if !ok { if !ok {
return nil 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. // 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 // 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 // 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. // 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) { func (g directedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if !isValidID(xid) || !isValidID(yid) { if !isValidID(xid) || !isValidID(yid) {
return 0, false return 0, false
} }
@@ -598,7 +603,7 @@ type directedMultiplexLocalMover struct {
// that returns the Weight value // that returns the Weight value
// of the non-nil edge between x // of the non-nil edge between x
// and y. // and y.
weight []func(x, y graph.Node) float64 weight []func(xid, yid int64) float64
// communities is the current // communities is the current
// division of g. // division of g.
@@ -648,7 +653,7 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
memberships: make([]int, len(nodes)), memberships: make([]int, len(nodes)),
resolutions: resolutions, resolutions: resolutions,
weights: weights, 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 // Calculate the total edge weight of the graph
@@ -656,7 +661,7 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
var zero int var zero int
for i := 0; i < g.Depth(); i++ { for i := 0; i < g.Depth(); i++ {
l.edgeWeightsOf[i] = make([]directedWeights, len(nodes)) 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 != nil {
if weights[i] == 0 { if weights[i] == 0 {
@@ -677,19 +682,22 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
layer := g.Layer(i) layer := g.Layer(i)
for _, n := range l.nodes { for _, n := range l.nodes {
u := n u := n
uid := u.ID()
var wOut float64 var wOut float64
for _, v := range layer.From(u) { for _, v := range layer.From(uid) {
wOut += weight(u, v) wOut += weight(uid, v.ID())
} }
v := n v := n
vid := v.ID()
var wIn float64 var wIn float64
for _, u := range layer.To(v) { for _, u := range layer.To(vid) {
wIn += weight(u, v) wIn += weight(u.ID(), vid)
} }
w := weight(n, n) id := n.ID()
l.edgeWeightsOf[i][u.ID()] = directedWeights{out: w + wOut, in: w + wIn} w := weight(id, id)
l.edgeWeightsOf[i][uid] = directedWeights{out: w + wOut, in: w + wIn}
l.m[i] += w + wOut l.m[i] += w + wOut
} }
if l.m[i] == 0 { if l.m[i] == 0 {
@@ -836,8 +844,8 @@ func (l *directedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst
removal = true removal = true
} }
k_aC.in += l.weight[layer](n, u) k_aC.in += l.weight[layer](id, uid)
k_aC.out += l.weight[layer](u, n) k_aC.out += l.weight[layer](uid, id)
// sigma_totC could be kept for each community // sigma_totC could be kept for each community
// and updated for moves, changing the calculation // and updated for moves, changing the calculation
// of sigma_totC here from O(n_c) to O(1), but // 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 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] k_a := l.edgeWeightsOf[layer][id]
gamma := 1.0 gamma := 1.0
if l.resolutions != nil { if l.resolutions != nil {

View File

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

View File

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

View File

@@ -34,19 +34,21 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
var m2 float64 var m2 float64
k := make(map[int64]float64, len(nodes)) k := make(map[int64]float64, len(nodes))
for _, u := range nodes { for _, u := range nodes {
w := weight(u, u) uid := u.ID()
for _, v := range g.From(u) { w := weight(uid, uid)
w += weight(u, v) for _, v := range g.From(uid) {
w += weight(uid, v.ID())
} }
m2 += w m2 += w
k[u.ID()] = w k[uid] = w
} }
if communities == nil { if communities == nil {
var q float64 var q float64
for _, u := range nodes { for _, u := range nodes {
kU := k[u.ID()] uid := u.ID()
q += weight(u, u) - resolution*kU*kU/m2 kU := k[uid]
q += weight(uid, uid) - resolution*kU*kU/m2
} }
return q / m2 return q / m2
} }
@@ -57,10 +59,12 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
var q float64 var q float64
for _, c := range communities { for _, c := range communities {
for i, u := range c { for i, u := range c {
kU := k[u.ID()] uid := u.ID()
q += weight(u, u) - resolution*kU*kU/m2 kU := k[uid]
q += weight(uid, uid) - resolution*kU*kU/m2
for _, v := range c[i+1:] { 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 communityOf[n.ID()] = i
} }
for _, u := range nodes { for _, u := range nodes {
uid := u.ID()
ucid := communityOf[uid]
var out []int var out []int
uid := communityOf[u.ID()] for _, v := range g.From(uid) {
for _, v := range g.From(u) { vid := v.ID()
vid := communityOf[v.ID()] vcid := communityOf[vid]
if vid != uid { if vcid != ucid {
out = append(out, vid) out = append(out, vcid)
} }
if uid < vid { if ucid < vcid {
// Only store the weight once. // 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 return &r
} }
@@ -254,39 +260,40 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
communityOf[n.ID()] = i communityOf[n.ID()] = i
} }
} }
for uid, comm := range communities { for ucid, comm := range communities {
var out []int var out []int
for i, u := range comm { 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:] { 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) { for _, v := range g.From(uid) {
vid := communityOf[v.ID()] vid := v.ID()
vcid := communityOf[vid]
found := false found := false
for _, e := range out { for _, e := range out {
if e == vid { if e == vcid {
found = true found = true
break break
} }
} }
if !found && vid != uid { if !found && vcid != ucid {
out = append(out, vid) out = append(out, vcid)
} }
if uid < vid { if ucid < vcid {
// Only store the weight once. // 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 return &r
} }
// Has returns whether the node exists within the graph. // Has returns whether the node exists within the graph.
func (g *ReducedUndirected) Has(n graph.Node) bool { func (g *ReducedUndirected) Has(id int64) bool {
id := n.ID()
return 0 <= id || id < int64(len(g.nodes)) 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. // From returns all nodes in g that can be reached directly from u.
func (g *ReducedUndirected) From(u graph.Node) []graph.Node { func (g *ReducedUndirected) From(uid int64) []graph.Node {
out := g.edges[u.ID()] out := g.edges[uid]
nodes := make([]graph.Node, len(out)) nodes := make([]graph.Node, len(out))
for i, vid := range out { for i, vid := range out {
nodes[i] = g.nodes[vid] 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *ReducedUndirected) HasEdgeBetween(x, y graph.Node) bool { func (g *ReducedUndirected) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
yid := y.ID()
if xid == yid || !isValidID(xid) || !isValidID(yid) { if xid == yid || !isValidID(xid) || !isValidID(yid) {
return false 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. // 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 node v must be directly reachable from u as defined by the From method.
func (g *ReducedUndirected) Edge(u, v graph.Node) graph.Edge { func (g *ReducedUndirected) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g *ReducedUndirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *ReducedUndirected) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// EdgeBetween returns the edge between nodes x and y. // EdgeBetween returns the edge between nodes x and y.
func (g *ReducedUndirected) EdgeBetween(x, y graph.Node) graph.Edge { func (g *ReducedUndirected) EdgeBetween(xid, yid int64) graph.Edge {
return g.WeightedEdgeBetween(x, y) return g.WeightedEdgeBetween(xid, yid)
} }
// WeightedEdgeBetween returns the weighted edge between nodes x and y. // WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *ReducedUndirected) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge { func (g *ReducedUndirected) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
xid := x.ID()
yid := y.ID()
if xid == yid || !isValidID(xid) || !isValidID(yid) { if xid == yid || !isValidID(xid) || !isValidID(yid) {
return nil return nil
} }
@@ -354,16 +357,14 @@ func (g *ReducedUndirected) WeightedEdgeBetween(x, y graph.Node) graph.WeightedE
if !ok { if !ok {
return nil 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. // 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 // 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 // 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. // 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) { func (g *ReducedUndirected) Weight(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if !isValidID(xid) || !isValidID(yid) { if !isValidID(xid) || !isValidID(yid) {
return 0, false return 0, false
} }
@@ -396,7 +397,7 @@ type undirectedLocalMover struct {
// that returns the Weight value // that returns the Weight value
// of the non-nil edge between x // of the non-nil edge between x
// and y. // and y.
weight func(x, y graph.Node) float64 weight func(xid, yid int64) float64
// communities is the current // communities is the current
// division of g. // division of g.
@@ -440,11 +441,12 @@ func newUndirectedLocalMover(g *ReducedUndirected, communities [][]graph.Node, r
// Calculate the total edge weight of the graph // Calculate the total edge weight of the graph
// and degree weights for each node. // and degree weights for each node.
for _, u := range l.nodes { for _, u := range l.nodes {
w := l.weight(u, u) uid := u.ID()
for _, v := range g.From(u) { w := l.weight(uid, uid)
w += l.weight(u, v) for _, v := range g.From(uid) {
w += l.weight(uid, v.ID())
} }
l.edgeWeightOf[u.ID()] = w l.edgeWeightOf[uid] = w
l.m2 += w l.m2 += w
} }
if l.m2 == 0 { if l.m2 == 0 {
@@ -514,7 +516,7 @@ func (l *undirectedLocalMover) move(dst int, src commIdx) {
// is in communities. // is in communities.
func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) { func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
id := n.ID() id := n.ID()
a_aa := l.weight(n, n) a_aa := l.weight(id, id)
k_a := l.edgeWeightOf[id] k_a := l.edgeWeightOf[id]
m2 := l.m2 m2 := l.m2
gamma := l.resolution gamma := l.resolution
@@ -559,7 +561,7 @@ func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, sr
removal = true removal = true
} }
k_aC += l.weight(n, u) k_aC += l.weight(id, uid)
// sigma_totC could be kept for each community // sigma_totC could be kept for each community
// and updated for moves, changing the calculation // and updated for moves, changing the calculation
// of sigma_totC here from O(n_c) to O(1), but // 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] layerResolution = resolutions[l]
} }
var weight func(x, y graph.Node) float64 var weight func(xid, yid int64) float64
if layerWeight < 0 { if layerWeight < 0 {
weight = negativeWeightFuncFor(layer) weight = negativeWeightFuncFor(layer)
} else { } else {
@@ -78,19 +78,21 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
var m2 float64 var m2 float64
k := make(map[int64]float64, len(nodes)) k := make(map[int64]float64, len(nodes))
for _, u := range nodes { for _, u := range nodes {
w := weight(u, u) uid := u.ID()
for _, v := range layer.From(u) { w := weight(uid, uid)
w += weight(u, v) for _, v := range layer.From(uid) {
w += weight(uid, v.ID())
} }
m2 += w m2 += w
k[u.ID()] = w k[uid] = w
} }
if communities == nil { if communities == nil {
var qLayer float64 var qLayer float64
for _, u := range nodes { for _, u := range nodes {
kU := k[u.ID()] uid := u.ID()
qLayer += weight(u, u) - layerResolution*kU*kU/m2 kU := k[uid]
qLayer += weight(uid, uid) - layerResolution*kU*kU/m2
} }
q[l] = layerWeight * qLayer q[l] = layerWeight * qLayer
continue continue
@@ -102,10 +104,12 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
var qLayer float64 var qLayer float64
for _, c := range communities { for _, c := range communities {
for i, u := range c { for i, u := range c {
kU := k[u.ID()] uid := u.ID()
qLayer += weight(u, u) - layerResolution*kU*kU/m2 kU := k[uid]
qLayer += weight(uid, uid) - layerResolution*kU*kU/m2
for _, v := range c[i+1:] { 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 continue
} }
var sign float64 var sign float64
var weight func(x, y graph.Node) float64 var weight func(xid, yid int64) float64
if w < 0 { if w < 0 {
sign, weight = -1, negativeWeightFuncFor(layer) sign, weight = -1, negativeWeightFuncFor(layer)
} else { } else {
@@ -327,18 +331,20 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
} }
for _, u := range nodes { for _, u := range nodes {
var out []int var out []int
uid := communityOf[u.ID()] uid := u.ID()
for _, v := range layer.From(u) { ucid := communityOf[uid]
vid := communityOf[v.ID()] for _, v := range layer.From(uid) {
if vid != uid { vid := v.ID()
out = append(out, vid) vcid := communityOf[vid]
if vcid != ucid {
out = append(out, vcid)
} }
if uid < vid { if ucid < vcid {
// Only store the weight once. // 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 return &r
@@ -395,38 +401,40 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
continue continue
} }
var sign float64 var sign float64
var weight func(x, y graph.Node) float64 var weight func(xid, yid int64) float64
if w < 0 { if w < 0 {
sign, weight = -1, negativeWeightFuncFor(layer) sign, weight = -1, negativeWeightFuncFor(layer)
} else { } else {
sign, weight = 1, positiveWeightFuncFor(layer) sign, weight = 1, positiveWeightFuncFor(layer)
} }
for uid, comm := range communities { for ucid, comm := range communities {
var out []int var out []int
for i, u := range comm { 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:] { 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) { for _, v := range layer.From(uid) {
vid := communityOf[v.ID()] vid := v.ID()
vcid := communityOf[vid]
found := false found := false
for _, e := range out { for _, e := range out {
if e == vid { if e == vcid {
found = true found = true
break break
} }
} }
if !found && vid != uid { if !found && vcid != ucid {
out = append(out, vid) out = append(out, vcid)
} }
if uid < vid { if ucid < vcid {
// Only store the weight once. // 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 return &r
@@ -445,8 +453,7 @@ type undirectedLayerHandle struct {
} }
// Has returns whether the node exists within the graph. // Has returns whether the node exists within the graph.
func (g undirectedLayerHandle) Has(n graph.Node) bool { func (g undirectedLayerHandle) Has(id int64) bool {
id := n.ID()
return 0 <= id && id < int64(len(g.multiplex.nodes)) 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. // From returns all nodes in g that can be reached directly from u.
func (g undirectedLayerHandle) From(u graph.Node) []graph.Node { func (g undirectedLayerHandle) From(uid int64) []graph.Node {
out := g.multiplex.layers[g.layer].edges[u.ID()] out := g.multiplex.layers[g.layer].edges[uid]
nodes := make([]graph.Node, len(out)) nodes := make([]graph.Node, len(out))
for i, vid := range out { for i, vid := range out {
nodes[i] = g.multiplex.nodes[vid] 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g undirectedLayerHandle) HasEdgeBetween(x, y graph.Node) bool { func (g undirectedLayerHandle) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
yid := y.ID()
if xid == yid || !isValidID(xid) || !isValidID(yid) { if xid == yid || !isValidID(xid) || !isValidID(yid) {
return false 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. // 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 node v must be directly reachable from u as defined by the From method.
func (g undirectedLayerHandle) Edge(u, v graph.Node) graph.Edge { func (g undirectedLayerHandle) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g undirectedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g undirectedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// EdgeBetween returns the edge between nodes x and y. // EdgeBetween returns the edge between nodes x and y.
func (g undirectedLayerHandle) EdgeBetween(x, y graph.Node) graph.Edge { func (g undirectedLayerHandle) EdgeBetween(xid, yid int64) graph.Edge {
return g.WeightedEdgeBetween(x, y) return g.WeightedEdgeBetween(xid, yid)
} }
// WeightedEdgeBetween returns the weighted edge between nodes x and y. // WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g undirectedLayerHandle) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge { func (g undirectedLayerHandle) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
xid := x.ID()
yid := y.ID()
if xid == yid || !isValidID(xid) || !isValidID(yid) { if xid == yid || !isValidID(xid) || !isValidID(yid) {
return nil return nil
} }
@@ -514,16 +517,14 @@ func (g undirectedLayerHandle) WeightedEdgeBetween(x, y graph.Node) graph.Weight
if !ok { if !ok {
return nil 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. // 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 // 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 // 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. // 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) { func (g undirectedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if !isValidID(xid) || !isValidID(yid) { if !isValidID(xid) || !isValidID(yid) {
return 0, false return 0, false
} }
@@ -556,7 +557,7 @@ type undirectedMultiplexLocalMover struct {
// that returns the Weight value // that returns the Weight value
// of the non-nil edge between x // of the non-nil edge between x
// and y. // and y.
weight []func(x, y graph.Node) float64 weight []func(xid, yid int64) float64
// communities is the current // communities is the current
// division of g. // division of g.
@@ -606,7 +607,7 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
memberships: make([]int, len(nodes)), memberships: make([]int, len(nodes)),
resolutions: resolutions, resolutions: resolutions,
weights: weights, 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 // Calculate the total edge weight of the graph
@@ -614,7 +615,7 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
var zero int var zero int
for i := 0; i < g.Depth(); i++ { for i := 0; i < g.Depth(); i++ {
l.edgeWeightOf[i] = make([]float64, len(nodes)) 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 != nil {
if weights[i] == 0 { if weights[i] == 0 {
@@ -634,11 +635,12 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
l.weight[i] = weight l.weight[i] = weight
layer := g.Layer(i) layer := g.Layer(i)
for _, u := range l.nodes { for _, u := range l.nodes {
w := weight(u, u) uid := u.ID()
for _, v := range layer.From(u) { w := weight(uid, uid)
w += weight(u, v) 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 l.m2[i] += w
} }
if l.m2[i] == 0 { if l.m2[i] == 0 {
@@ -779,7 +781,7 @@ func (l *undirectedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, ds
removal = true removal = true
} }
k_aC += l.weight[layer](n, u) k_aC += l.weight[layer](id, uid)
// sigma_totC could be kept for each community // sigma_totC could be kept for each community
// and updated for moves, changing the calculation // and updated for moves, changing the calculation
// of sigma_totC here from O(n_c) to O(1), but // 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] 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] k_a := l.edgeWeightOf[layer][id]
gamma := 1.0 gamma := 1.0
if l.resolutions != nil { if l.resolutions != nil {

View File

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

View File

@@ -267,7 +267,7 @@ func TestCommunityQUndirected(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -284,7 +284,7 @@ func TestCommunityQWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0) g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -320,7 +320,7 @@ func TestCommunityDeltaQUndirected(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -337,7 +337,7 @@ func TestCommunityDeltaQWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0) g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -401,7 +401,7 @@ func testCommunityDeltaQUndirected(t *testing.T, test communityUndirectedQTest,
} }
connected := false connected := false
for n := range c { for n := range c {
if g.HasEdgeBetween(simple.Node(n), target) { if g.HasEdgeBetween(int64(n), target.ID()) {
connected = true connected = true
break break
} }
@@ -445,7 +445,7 @@ func TestReduceQConsistencyUndirected(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -462,7 +462,7 @@ func TestReduceQConsistencyWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0) g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -563,7 +563,7 @@ func TestMoveLocalUndirected(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -580,7 +580,7 @@ func TestMoveLocalWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0) g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -625,7 +625,7 @@ func TestModularizeUndirected(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -642,7 +642,7 @@ func TestModularizeWeightedUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, 0) g := simple.NewWeightedUndirectedGraph(0, 0)
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { 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 s, ok := n.(Subgrapher); ok {
// If the node is not linked to any other node // If the node is not linked to any other node
// the graph needs to be written now. // the graph needs to be written now.
if len(g.From(n)) == 0 { if len(g.From(n.ID())) == 0 {
g := s.Subgraph() g := s.Subgraph()
_, subIsDirected := g.(graph.Directed) _, subIsDirected := g.(graph.Directed)
if subIsDirected != isDirected { if subIsDirected != isDirected {
@@ -182,20 +182,22 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
havePrintedEdgeHeader := false havePrintedEdgeHeader := false
for _, n := range nodes { for _, n := range nodes {
to := g.From(n) nid := n.ID()
to := g.From(nid)
sort.Sort(ordered.ByID(to)) sort.Sort(ordered.ByID(to))
for _, t := range to { for _, t := range to {
tid := t.ID()
if isDirected { 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 continue
} }
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true p.visited[edge{inGraph: name, from: nid, to: tid}] = true
} else { } else {
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] { if p.visited[edge{inGraph: name, from: nid, to: tid}] {
continue continue
} }
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true p.visited[edge{inGraph: name, from: nid, to: tid}] = true
p.visited[edge{inGraph: name, from: t.ID(), to: n.ID()}] = true p.visited[edge{inGraph: name, from: tid, to: n.ID()}] = true
} }
if !havePrintedEdgeHeader { if !havePrintedEdgeHeader {
@@ -217,7 +219,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
} else { } else {
p.writeNode(n) p.writeNode(n)
} }
e, edgeIsPorter := g.Edge(n, t).(Porter) e, edgeIsPorter := g.Edge(nid, tid).(Porter)
if edgeIsPorter { if edgeIsPorter {
p.writePorts(e.FromPort()) p.writePorts(e.FromPort())
} }
@@ -242,7 +244,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
p.writePorts(e.ToPort()) 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) p.writeAttributeList(a)
} }

View File

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

View File

@@ -27,53 +27,57 @@ type WeightedEdge interface {
// Graph is a generalized graph. // Graph is a generalized graph.
type Graph interface { type Graph interface {
// Has returns whether the node exists within the graph. // Has returns whether a node with the given ID exists
Has(Node) bool // within the graph.
Has(id int64) bool
// Nodes returns all the nodes in the graph. // Nodes returns all the nodes in the graph.
Nodes() []Node Nodes() []Node
// From returns all nodes that can be reached directly // From returns all nodes that can be reached directly
// from the given node. // from the node with the given ID.
From(Node) []Node From(id int64) []Node
// HasEdgeBetween returns whether an edge exists between // HasEdgeBetween returns whether an edge exists between
// nodes x and y without considering direction. // nodes with IDs xid and yid without considering direction.
HasEdgeBetween(x, y Node) bool HasEdgeBetween(xid, yid int64) bool
// Edge returns the edge from u to v if such an edge // Edge returns the edge from u to v, with IDs uid and vid,
// exists and nil otherwise. The node v must be directly // if such an edge exists and nil otherwise. The node v
// reachable from u as defined by the From method. // must be directly reachable from u as defined by the
Edge(u, v Node) Edge // From method.
Edge(uid, vid int64) Edge
} }
// Weighted is a weighted graph. // Weighted is a weighted graph.
type Weighted interface { type Weighted interface {
Graph Graph
// WeightedEdge returns the weighted edge from u to v if // WeightedEdge returns the weighted edge from u to v
// such an edge exists and nil otherwise. The node v must // with IDs uid and vid if such an edge exists and
// be directly reachable from u as defined by the // nil otherwise. The node v must be directly
// From method. // reachable from u as defined by the From method.
WeightedEdge(u, v Node) WeightedEdge WeightedEdge(uid, vid int64) WeightedEdge
// Weight returns the weight for the edge between // 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 // If x and y are the same node or there is no
// joining edge between the two nodes the weight // joining edge between the two nodes the weight
// value returned is implementation dependent. // value returned is implementation dependent.
// Weight returns true if an edge exists between // Weight returns true if an edge exists between
// x and y or if x and y have the same ID, false // x and y or if x and y have the same ID, false
// otherwise. // otherwise.
Weight(x, y Node) (w float64, ok bool) Weight(xid, yid int64) (w float64, ok bool)
} }
// Undirected is an undirected graph. // Undirected is an undirected graph.
type Undirected interface { type Undirected interface {
Graph Graph
// EdgeBetween returns the edge between nodes x and y. // EdgeBetween returns the edge between nodes x and y
EdgeBetween(x, y Node) Edge // with IDs xid and yid.
EdgeBetween(xid, yid int64) Edge
} }
// WeightedUndirected is a weighted undirected graph. // WeightedUndirected is a weighted undirected graph.
@@ -81,8 +85,8 @@ type WeightedUndirected interface {
Weighted Weighted
// WeightedEdgeBetween returns the edge between nodes // WeightedEdgeBetween returns the edge between nodes
// x and y. // x and y with IDs xid and yid.
WeightedEdgeBetween(x, y Node) WeightedEdge WeightedEdgeBetween(xid, yid int64) WeightedEdge
} }
// Directed is a directed graph. // Directed is a directed graph.
@@ -90,12 +94,12 @@ type Directed interface {
Graph Graph
// HasEdgeFromTo returns whether an edge exists // HasEdgeFromTo returns whether an edge exists
// in the graph from u to v. // in the graph from u to v with IDs uid and vid.
HasEdgeFromTo(u, v Node) bool HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly // To returns all nodes that can reach directly
// to the given node. // to the node with the given ID.
To(Node) []Node To(id int64) []Node
} }
// WeightedDirected is a weighted directed graph. // WeightedDirected is a weighted directed graph.
@@ -103,12 +107,13 @@ type WeightedDirected interface {
Weighted Weighted
// HasEdgeFromTo returns whether an edge exists // HasEdgeFromTo returns whether an edge exists
// in the graph from u to v. // in the graph from u to v with the IDs uid and
HasEdgeFromTo(u, v Node) bool // vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly // To returns all nodes that can reach directly
// to the given node. // to the node with the given ID.
To(Node) []Node To(id int64) []Node
} }
// NodeAdder is an interface for adding arbitrary nodes to a graph. // NodeAdder is an interface for adding arbitrary nodes to a graph.
@@ -217,7 +222,7 @@ func Copy(dst Builder, src Graph) {
dst.AddNode(n) dst.AddNode(n)
} }
for _, u := range nodes { for _, u := range nodes {
for _, v := range src.From(u) { for _, v := range src.From(u.ID()) {
dst.SetEdge(dst.NewEdge(u, v)) dst.SetEdge(dst.NewEdge(u, v))
} }
} }
@@ -240,8 +245,8 @@ func CopyWeighted(dst WeightedBuilder, src Weighted) {
dst.AddNode(n) dst.AddNode(n)
} }
for _, u := range nodes { for _, u := range nodes {
for _, v := range src.From(u) { for _, v := range src.From(u.ID()) {
dst.SetWeightedEdge(dst.NewWeightedEdge(u, v, src.WeightedEdge(u, v).Weight())) 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() { for _, u := range a.Nodes() {
aFromU := a.From(u) aFromU := a.From(u.ID())
bFromU := b.From(u) bFromU := b.From(u.ID())
if len(aFromU) != len(bFromU) { if len(aFromU) != len(bFromU) {
return false return false
} }
@@ -288,7 +288,7 @@ func same(a, b graph.Graph) bool {
aW, aWok := a.(graph.Weighted) aW, aWok := a.(graph.Weighted)
bW, bWok := b.(graph.Weighted) bW, bWok := b.(graph.Weighted)
if aWok && bWok { 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 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++ { for i := 0; i < n; i++ {
if !dst.Has(simple.Node(i)) { if !dst.Has(int64(i)) {
dst.AddNode(simple.Node(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++ { for i := 0; i < n; i++ {
if !dst.Has(simple.Node(i)) { if !dst.Has(int64(i)) {
dst.AddNode(simple.Node(i)) dst.AddNode(simple.Node(i))
} }
} }
@@ -122,7 +122,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
for { for {
v, w := edgeNodesFor(rnd(nChoose2)) v, w := edgeNodesFor(rnd(nChoose2))
e := simple.Edge{F: w, T: v} e := simple.Edge{F: w, T: v}
if !hasEdge(e.F, e.T) { if !hasEdge(e.F.ID(), e.T.ID()) {
dst.SetEdge(e) dst.SetEdge(e)
break break
} }
@@ -137,7 +137,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
for { for {
v, w := edgeNodesFor(rnd(nChoose2)) v, w := edgeNodesFor(rnd(nChoose2))
e := simple.Edge{F: v, T: w} e := simple.Edge{F: v, T: w}
if !hasEdge(e.F, e.T) { if !hasEdge(e.F.ID(), e.T.ID()) {
dst.SetEdge(e) dst.SetEdge(e)
break break
} }
@@ -182,7 +182,7 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
if !dst.Has(simple.Node(i)) { if !dst.Has(int64(i)) {
dst.AddNode(simple.Node(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 j := v*(v-1)/2 + (v+i)%n
var ej simple.Edge var ej simple.Edge
ej.T, ej.F = edgeNodesFor(j) ej.T, ej.F = edgeNodesFor(j)
if !hasEdge(ej.From(), ej.To()) { if !hasEdge(ej.From().ID(), ej.To().ID()) {
dst.SetEdge(ej) dst.SetEdge(ej)
} }
k-- k--
m++ m++
var em simple.Edge var em simple.Edge
em.T, em.F = edgeNodesFor(m) em.T, em.F = edgeNodesFor(m)
if !hasEdge(em.From(), em.To()) { if !hasEdge(em.From().ID(), em.To().ID()) {
replace[j] = m replace[j] = m
} else { } else {
replace[j] = replace[m] 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 r := rndN(nChoose2-i) + i
var er simple.Edge var er simple.Edge
er.T, er.F = edgeNodesFor(r) er.T, er.F = edgeNodesFor(r)
if !hasEdge(er.From(), er.To()) { if !hasEdge(er.From().ID(), er.To().ID()) {
dst.SetEdge(er) dst.SetEdge(er)
} else { } else {
er.T, er.F = edgeNodesFor(replace[r]) er.T, er.F = edgeNodesFor(replace[r])
if !hasEdge(er.From(), er.To()) { if !hasEdge(er.From().ID(), er.To().ID()) {
dst.SetEdge(er) dst.SetEdge(er)
} }
} }
var ei simple.Edge var ei simple.Edge
ei.T, ei.F = edgeNodesFor(i) ei.T, ei.F = edgeNodesFor(i)
if !hasEdge(ei.From(), ei.To()) { if !hasEdge(ei.From().ID(), ei.To().ID()) {
replace[r] = i replace[r] = i
} else { } else {
replace[r] = replace[i] 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 j := v*(v-1)/2 + (v+i)%n
var ej simple.Edge var ej simple.Edge
ej.F, ej.T = edgeNodesFor(j) ej.F, ej.T = edgeNodesFor(j)
if !hasEdge(ej.From(), ej.To()) { if !hasEdge(ej.From().ID(), ej.To().ID()) {
dst.SetEdge(ej) dst.SetEdge(ej)
} }
k-- k--
m++ m++
if !hasEdge(edgeNodesFor(m)) { if u, v := edgeNodesFor(m); !hasEdge(u.ID(), v.ID()) {
replace[j] = m replace[j] = m
} else { } else {
replace[j] = replace[m] 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 r := rndN(nChoose2-i) + i
var er simple.Edge var er simple.Edge
er.F, er.T = edgeNodesFor(r) er.F, er.T = edgeNodesFor(r)
if !hasEdge(er.From(), er.To()) { if !hasEdge(er.From().ID(), er.To().ID()) {
dst.SetEdge(er) dst.SetEdge(er)
} else { } else {
er.F, er.T = edgeNodesFor(replace[r]) er.F, er.T = edgeNodesFor(replace[r])
if !hasEdge(er.From(), er.To()) { if !hasEdge(er.From().ID(), er.To().ID()) {
dst.SetEdge(er) dst.SetEdge(er)
} }
} }
if !hasEdge(edgeNodesFor(i)) { if u, v := edgeNodesFor(i); !hasEdge(u.ID(), v.ID()) {
replace[r] = i replace[r] = i
} else { } else {
replace[r] = replace[i] replace[r] = replace[i]

View File

@@ -27,7 +27,7 @@ func (g *gnUndirected) SetEdge(e graph.Edge) {
return return
case e.From().ID() > e.To().ID(): case e.From().ID() > e.To().ID():
g.addBackwards = true g.addBackwards = true
case g.UndirectedBuilder.HasEdgeBetween(e.From(), e.To()): case g.UndirectedBuilder.HasEdgeBetween(e.From().ID(), e.To().ID()):
g.addMultipleEdge = true g.addMultipleEdge = true
} }
@@ -45,7 +45,7 @@ func (g *gnDirected) SetEdge(e graph.Edge) {
case e.From().ID() == e.To().ID(): case e.From().ID() == e.To().ID():
g.addSelfLoop = true g.addSelfLoop = true
return return
case g.DirectedBuilder.HasEdgeFromTo(e.From(), e.To()): case g.DirectedBuilder.HasEdgeFromTo(e.From().ID(), e.To().ID()):
g.addMultipleEdge = true g.addMultipleEdge = true
} }
@@ -190,9 +190,10 @@ func TestPowerLawUndirected(t *testing.T) {
} }
for _, u := range nodes { for _, u := range nodes {
uid := u.ID()
var lines int var lines int
for _, v := range g.From(u) { for _, v := range g.From(uid) {
lines += len(g.Lines(u, v)) lines += len(g.Lines(uid, v.ID()))
} }
if lines < d { if lines < d {
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines) 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 { for _, u := range nodes {
uid := u.ID()
var lines int var lines int
for _, v := range g.From(u) { for _, v := range g.From(uid) {
lines += len(g.Lines(u, v)) lines += len(g.Lines(uid, v.ID()))
} }
if lines < d { if lines < d {
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines) 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 { for _, u := range nodes {
uid := u.ID()
var lines int var lines int
for _, v := range g.From(u) { for _, v := range g.From(uid) {
lines += len(g.Lines(u, v)) lines += len(g.Lines(uid, v.ID()))
} }
if lines < d { if lines < d {
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines) 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 { for _, u := range nodes {
uid := u.ID()
var lines int var lines int
for _, v := range g.From(u) { for _, v := range g.From(uid) {
lines += len(g.Lines(u, v)) lines += len(g.Lines(uid, v.ID()))
} }
if lines < d { if lines < d {
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines) 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++ { for i := 0; i < n; i++ {
u := nodes[rndN(len(nodes))] u := nodes[rndN(len(nodes))]
d := dst.NewNode() d := dst.NewNode()
did := d.ID()
// Add the duplicate node. // Add the duplicate node.
dst.AddNode(d) dst.AddNode(d)
@@ -74,13 +75,14 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
// into the rest of the graph. // into the rest of the graph.
for { for {
// Add edges to parent's neighbours. // Add edges to parent's neighbours.
to := dst.From(u) to := dst.From(u.ID())
sort.Sort(ordered.ByID(to)) sort.Sort(ordered.ByID(to))
for _, v := range to { for _, v := range to {
if rnd() < delta || dst.HasEdgeBetween(v, d) { vid := v.ID()
if rnd() < delta || dst.HasEdgeBetween(vid, did) {
continue continue
} }
if v.ID() < d.ID() { if vid < did {
dst.SetEdge(dst.NewEdge(v, d)) dst.SetEdge(dst.NewEdge(v, d))
} else { } else {
dst.SetEdge(dst.NewEdge(d, v)) 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. // Add edges to old nodes.
scaledAlpha := alpha / float64(len(nodes)) scaledAlpha := alpha / float64(len(nodes))
for _, v := range nodes { for _, v := range nodes {
switch v.ID() { uid := u.ID()
case u.ID(): vid := v.ID()
switch vid {
case uid:
if !math.IsNaN(sigma) { if !math.IsNaN(sigma) {
if i == 0 || rnd() < sigma { if i == 0 || rnd() < sigma {
if v.ID() < d.ID() { if vid < did {
dst.SetEdge(dst.NewEdge(v, d)) dst.SetEdge(dst.NewEdge(v, d))
} else { } else {
dst.SetEdge(dst.NewEdge(d, v)) dst.SetEdge(dst.NewEdge(d, v))
@@ -104,8 +108,8 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
} }
fallthrough fallthrough
default: default:
if rnd() < scaledAlpha && !dst.HasEdgeBetween(v, d) { if rnd() < scaledAlpha && !dst.HasEdgeBetween(vid, did) {
if v.ID() < d.ID() { if vid < did {
dst.SetEdge(dst.NewEdge(v, d)) dst.SetEdge(dst.NewEdge(v, d))
} else { } else {
dst.SetEdge(dst.NewEdge(d, v)) 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 break
} }
} }

View File

@@ -25,7 +25,7 @@ func (g *duplication) SetEdge(e graph.Edge) {
return return
case e.From().ID() > e.To().ID(): case e.From().ID() > e.To().ID():
g.addBackwards = true g.addBackwards = true
case g.UndirectedMutator.HasEdgeBetween(e.From(), e.To()): case g.UndirectedMutator.HasEdgeBetween(e.From().ID(), e.To().ID()):
g.addMultipleEdge = true 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. // GraphBuilder is a graph that can have nodes and edges added.
type GraphBuilder interface { type GraphBuilder interface {
Has(graph.Node) bool Has(id int64) bool
HasEdgeBetween(x, y graph.Node) bool HasEdgeBetween(xid, yid int64) bool
graph.Builder graph.Builder
} }

View File

@@ -47,7 +47,7 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
// Initial condition. // Initial condition.
wt := make([]float64, n) wt := make([]float64, n)
for u := 0; u < m; u++ { for u := 0; u < m; u++ {
if !dst.Has(simple.Node(u)) { if !dst.Has(int64(0)) {
dst.AddNode(simple.Node(u)) dst.AddNode(simple.Node(u))
} }
// We need to give equal probability for // 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++ { for i := 0; i < m; i++ {
// Triad formation. // Triad formation.
if i != 0 && rnd() < p { 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() wid := w.ID()
if wid == int64(v) || dst.HasEdgeBetween(w, simple.Node(v)) { if wid == int64(v) || dst.HasEdgeBetween(wid, int64(v)) {
continue continue
} }
dst.SetEdge(simple.Edge{F: w, T: simple.Node(v)}) 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 { if !ok {
return errors.New("gen: depleted distribution") 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 continue
} }
dst.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)}) 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. // Initial condition.
wt := make([]float64, n) wt := make([]float64, n)
for u := 0; u < m; u++ { for u := 0; u < m; u++ {
if !dst.Has(simple.Node(u)) { if !dst.Has(int64(u)) {
dst.AddNode(simple.Node(u)) dst.AddNode(simple.Node(u))
} }
// We need to give equal probability for // 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 n *= d
} }
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
if !dst.Has(simple.Node(i)) { if !dst.Has(int64(i)) {
dst.AddNode(simple.Node(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 { if uid > vid {
e.F, e.T = e.T, e.F 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) dst.SetEdge(e)
} }
if !isDirected { if !isDirected {
return return
} }
e.F, e.T = e.T, e.F 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) dst.SetEdge(e)
} }
}) })
@@ -110,7 +110,7 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
if !isDirected && uid > vid { if !isDirected && uid > vid {
e.F, e.T = e.T, e.F 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) dst.SetEdge(e)
} }
} }

View File

@@ -103,13 +103,13 @@ func (g *DirectedGraph) SetLine(l graph.Line) {
lid = l.ID() lid = l.ID()
) )
if !g.Has(from) { if !g.Has(fid) {
g.AddNode(from) g.AddNode(from)
} }
if g.from[fid][tid] == nil { if g.from[fid][tid] == nil {
g.from[fid][tid] = make(map[int64]graph.Line) g.from[fid][tid] = make(map[int64]graph.Line)
} }
if !g.Has(to) { if !g.Has(tid) {
g.AddNode(to) g.AddNode(to)
} }
if g.to[tid][fid] == nil { 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. // Has returns whether the node exists within the graph.
func (g *DirectedGraph) Has(n graph.Node) bool { func (g *DirectedGraph) Has(id int64) bool {
_, ok := g.nodes[n.ID()] _, ok := g.nodes[id]
return ok 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. // From returns all nodes in g that can be reached directly from n.
func (g *DirectedGraph) From(n graph.Node) []graph.Node { func (g *DirectedGraph) From(id int64) []graph.Node {
if _, ok := g.from[n.ID()]; !ok { if _, ok := g.from[id]; !ok {
return nil return nil
} }
from := make([]graph.Node, len(g.from[n.ID()])) from := make([]graph.Node, len(g.from[id]))
i := 0 i := 0
for id := range g.from[n.ID()] { for vid := range g.from[id] {
from[i] = g.nodes[id] from[i] = g.nodes[vid]
i++ i++
} }
return from return from
} }
// To returns all nodes in g that can reach directly to n. // To returns all nodes in g that can reach directly to n.
func (g *DirectedGraph) To(n graph.Node) []graph.Node { func (g *DirectedGraph) To(id int64) []graph.Node {
if _, ok := g.from[n.ID()]; !ok { if _, ok := g.from[id]; !ok {
return nil return nil
} }
to := make([]graph.Node, len(g.to[n.ID()])) to := make([]graph.Node, len(g.to[id]))
i := 0 i := 0
for id := range g.to[n.ID()] { for uid := range g.to[id] {
to[i] = g.nodes[id] to[i] = g.nodes[uid]
i++ i++
} }
return to 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 // HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction. // considering direction.
func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool { func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
yid := y.ID()
if _, ok := g.from[xid][yid]; ok { if _, ok := g.from[xid][yid]; ok {
return true 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. // 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 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. // The returned graph.Edge is a multi.Edge if an edge exists.
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge { func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
lines := g.Lines(u, v) lines := g.Lines(uid, vid)
if len(lines) == 0 { if len(lines) == 0 {
return nil 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. // 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. // 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 { func (g *DirectedGraph) Lines(uid, vid int64) []graph.Line {
edge := g.from[u.ID()][v.ID()] edge := g.from[uid][vid]
if len(edge) == 0 { if len(edge) == 0 {
return nil 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. // HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool { func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
_, ok := g.from[u.ID()][v.ID()] _, ok := g.from[uid][vid]
return ok return ok
} }
// Degree returns the in+out degree of n in g. // Degree returns the in+out degree of n in g.
func (g *DirectedGraph) Degree(n graph.Node) int { func (g *DirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[n.ID()]; !ok { if _, ok := g.nodes[id]; !ok {
return 0 return 0
} }
var deg int var deg int
for _, e := range g.from[n.ID()] { for _, e := range g.from[id] {
deg += len(e) deg += len(e)
} }
for _, e := range g.to[n.ID()] { for _, e := range g.to[id] {
deg += len(e) deg += len(e)
} }
return deg return deg

View File

@@ -21,7 +21,7 @@ var (
func TestEdgeOvercounting(t *testing.T) { func TestEdgeOvercounting(t *testing.T) {
g := generateDummyGraph() 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)) 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() lid = l.ID()
) )
if !g.Has(from) { if !g.Has(fid) {
g.AddNode(from) g.AddNode(from)
} }
if g.lines[fid][tid] == nil { if g.lines[fid][tid] == nil {
g.lines[fid][tid] = make(map[int64]graph.Line) g.lines[fid][tid] = make(map[int64]graph.Line)
} }
if !g.Has(to) { if !g.Has(tid) {
g.AddNode(to) g.AddNode(to)
} }
if g.lines[tid][fid] == nil { 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. // Has returns whether the node exists within the graph.
func (g *UndirectedGraph) Has(n graph.Node) bool { func (g *UndirectedGraph) Has(id int64) bool {
_, ok := g.nodes[n.ID()] _, ok := g.nodes[id]
return ok 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. // From returns all nodes in g that can be reached directly from n.
func (g *UndirectedGraph) From(n graph.Node) []graph.Node { func (g *UndirectedGraph) From(id int64) []graph.Node {
if !g.Has(n) { if !g.Has(id) {
return nil return nil
} }
nodes := make([]graph.Node, len(g.lines[n.ID()])) nodes := make([]graph.Node, len(g.lines[id]))
i := 0 i := 0
for from := range g.lines[n.ID()] { for from := range g.lines[id] {
nodes[i] = g.nodes[from] nodes[i] = g.nodes[from]
i++ 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *UndirectedGraph) HasEdgeBetween(x, y graph.Node) bool { func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
_, ok := g.lines[x.ID()][y.ID()] _, ok := g.lines[xid][yid]
return ok return ok
} }
// EdgeBetween returns the edge between nodes x and y. // EdgeBetween returns the edge between nodes x and y.
func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge { func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
return g.Edge(x, y) return g.Edge(xid, yid)
} }
// Edge returns the edge from u to v if such an edge exists and nil otherwise. // 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 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. // The returned graph.Edge is a multi.Edge if an edge exists.
func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge { func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
lines := g.LinesBetween(u, v) lines := g.LinesBetween(uid, vid)
if len(lines) == 0 { if len(lines) == 0 {
return nil 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. // 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. // 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 { func (g *UndirectedGraph) Lines(uid, vid int64) []graph.Line {
return g.LinesBetween(u, v) return g.LinesBetween(uid, vid)
} }
// LinesBetween returns the lines between nodes x and y. // 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 var lines []graph.Line
for _, l := range g.lines[x.ID()][y.ID()] { for _, l := range g.lines[xid][yid] {
lines = append(lines, l) lines = append(lines, l)
} }
return lines return lines
} }
// Degree returns the degree of n in g. // Degree returns the degree of n in g.
func (g *UndirectedGraph) Degree(n graph.Node) int { func (g *UndirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[n.ID()]; !ok { if _, ok := g.nodes[id]; !ok {
return 0 return 0
} }
var deg int var deg int
for _, e := range g.lines[n.ID()] { for _, e := range g.lines[id] {
deg += len(e) deg += len(e)
} }
return deg return deg

View File

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

View File

@@ -107,13 +107,13 @@ func (g *WeightedDirectedGraph) SetWeightedLine(l graph.WeightedLine) {
lid = l.ID() lid = l.ID()
) )
if !g.Has(from) { if !g.Has(fid) {
g.AddNode(from) g.AddNode(from)
} }
if g.from[fid][tid] == nil { if g.from[fid][tid] == nil {
g.from[fid][tid] = make(map[int64]graph.WeightedLine) g.from[fid][tid] = make(map[int64]graph.WeightedLine)
} }
if !g.Has(to) { if !g.Has(tid) {
g.AddNode(to) g.AddNode(to)
} }
if g.to[tid][fid] == nil { 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. // Has returns whether the node exists within the graph.
func (g *WeightedDirectedGraph) Has(n graph.Node) bool { func (g *WeightedDirectedGraph) Has(id int64) bool {
_, ok := g.nodes[n.ID()] _, ok := g.nodes[id]
return ok 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. // From returns all nodes in g that can be reached directly from n.
func (g *WeightedDirectedGraph) From(n graph.Node) []graph.Node { func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
if _, ok := g.from[n.ID()]; !ok { if _, ok := g.from[id]; !ok {
return nil return nil
} }
from := make([]graph.Node, len(g.from[n.ID()])) from := make([]graph.Node, len(g.from[id]))
i := 0 i := 0
for id := range g.from[n.ID()] { for vid := range g.from[id] {
from[i] = g.nodes[id] from[i] = g.nodes[vid]
i++ i++
} }
return from return from
} }
// To returns all nodes in g that can reach directly to n. // To returns all nodes in g that can reach directly to n.
func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node { func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
if _, ok := g.from[n.ID()]; !ok { if _, ok := g.from[id]; !ok {
return nil return nil
} }
to := make([]graph.Node, len(g.to[n.ID()])) to := make([]graph.Node, len(g.to[id]))
i := 0 i := 0
for id := range g.to[n.ID()] { for uid := range g.to[id] {
to[i] = g.nodes[id] to[i] = g.nodes[uid]
i++ i++
} }
return to 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 // HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction. // considering direction.
func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool { func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
yid := y.ID()
if _, ok := g.from[xid][yid]; ok { if _, ok := g.from[xid][yid]; ok {
return true 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. // HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool { func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
if _, ok := g.from[u.ID()][v.ID()]; !ok { if _, ok := g.from[uid][vid]; !ok {
return false return false
} }
return true 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. // 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 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. // The returned graph.Edge is a multi.WeightedEdge if an edge exists.
func (g *WeightedDirectedGraph) Edge(u, v graph.Node) graph.Edge { func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(u, v) return g.WeightedEdge(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 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. // The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
lines := g.WeightedLines(u, v) lines := g.WeightedLines(uid, vid)
if len(lines) == 0 { if len(lines) == 0 {
return nil 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. // 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. // 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 { func (g *WeightedDirectedGraph) Lines(uid, vid int64) []graph.Line {
edge := g.from[u.ID()][v.ID()] edge := g.from[uid][vid]
if len(edge) == 0 { if len(edge) == 0 {
return nil 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 // 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. // 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 { func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
edge := g.from[u.ID()][v.ID()] edge := g.from[uid][vid]
if len(edge) == 0 { if len(edge) == 0 {
return nil 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 // 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. // 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) { func (g *WeightedDirectedGraph) Weight(uid, vid int64) (w float64, ok bool) {
lines := g.WeightedLines(u, v) lines := g.WeightedLines(uid, vid)
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0 return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
} }
// Degree returns the in+out degree of n in g. // Degree returns the in+out degree of n in g.
func (g *WeightedDirectedGraph) Degree(n graph.Node) int { func (g *WeightedDirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[n.ID()]; !ok { if _, ok := g.nodes[id]; !ok {
return 0 return 0
} }
var deg int var deg int
for _, e := range g.from[n.ID()] { for _, e := range g.from[id] {
deg += len(e) deg += len(e)
} }
for _, e := range g.to[n.ID()] { for _, e := range g.to[id] {
deg += len(e) deg += len(e)
} }
return deg return deg

View File

@@ -22,7 +22,7 @@ var (
func TestWeightedEdgeOvercounting(t *testing.T) { func TestWeightedEdgeOvercounting(t *testing.T) {
g := generateDummyWeightedGraph() 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)) 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() lid = l.ID()
) )
if !g.Has(from) { if !g.Has(fid) {
g.AddNode(from) g.AddNode(from)
} }
if g.lines[fid][tid] == nil { if g.lines[fid][tid] == nil {
g.lines[fid][tid] = make(map[int64]graph.WeightedLine) g.lines[fid][tid] = make(map[int64]graph.WeightedLine)
} }
if !g.Has(to) { if !g.Has(tid) {
g.AddNode(to) g.AddNode(to)
} }
if g.lines[tid][fid] == nil { 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. // Has returns whether the node exists within the graph.
func (g *WeightedUndirectedGraph) Has(n graph.Node) bool { func (g *WeightedUndirectedGraph) Has(id int64) bool {
_, ok := g.nodes[n.ID()] _, ok := g.nodes[id]
return ok 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. // From returns all nodes in g that can be reached directly from n.
func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node { func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
if !g.Has(n) { if !g.Has(id) {
return nil return nil
} }
nodes := make([]graph.Node, len(g.lines[n.ID()])) nodes := make([]graph.Node, len(g.lines[id]))
i := 0 i := 0
for from := range g.lines[n.ID()] { for from := range g.lines[id] {
nodes[i] = g.nodes[from] nodes[i] = g.nodes[from]
i++ 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *WeightedUndirectedGraph) HasEdgeBetween(x, y graph.Node) bool { func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
_, ok := g.lines[x.ID()][y.ID()] _, ok := g.lines[xid][yid]
return ok return ok
} }
// Lines returns the lines from u to v if such an edge exists and nil otherwise. // 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. // 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 { func (g *WeightedUndirectedGraph) Lines(uid, vid int64) []graph.Line {
return g.LinesBetween(u, v) return g.LinesBetween(uid, vid)
} }
// LinesBetween returns the lines between nodes x and y. // LinesBetween returns the lines between nodes x and y.
func (g *WeightedUndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line { func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
edge := g.lines[x.ID()][y.ID()] edge := g.lines[xid][yid]
if len(edge) == 0 { if len(edge) == 0 {
return nil 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. // 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 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. // The returned graph.Edge is a multi.WeightedEdge if an edge exists.
func (g *WeightedUndirectedGraph) Edge(u, v graph.Node) graph.Edge { func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(u, v) return g.WeightedEdge(uid, vid)
} }
// EdgeBetween returns the edge between nodes x and y. // EdgeBetween returns the edge between nodes x and y.
func (g *WeightedUndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge { func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
return g.WeightedEdge(x, y) return g.WeightedEdge(xid, yid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 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. // The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
lines := g.WeightedLines(u, v) lines := g.WeightedLines(uid, vid)
if len(lines) == 0 { if len(lines) == 0 {
return nil 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. // WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge { func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
return g.WeightedEdge(x, y) return g.WeightedEdge(xid, yid)
} }
// WeightedLines returns the lines from u to v if such an edge exists and nil otherwise. // 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. // 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 { func (g *WeightedUndirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
return g.WeightedLinesBetween(u, v) return g.WeightedLinesBetween(uid, vid)
} }
// WeightedLinesBetween returns the lines between nodes x and y. // WeightedLinesBetween returns the lines between nodes x and y.
func (g *WeightedUndirectedGraph) WeightedLinesBetween(x, y graph.Node) []graph.WeightedLine { func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) []graph.WeightedLine {
edge := g.lines[x.ID()][y.ID()] edge := g.lines[xid][yid]
if len(edge) == 0 { if len(edge) == 0 {
return nil 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 // 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. // 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) { func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
lines := g.WeightedLines(x, y) lines := g.WeightedLines(xid, yid)
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0 return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
} }
// Degree returns the degree of n in g. // Degree returns the degree of n in g.
func (g *WeightedUndirectedGraph) Degree(n graph.Node) int { func (g *WeightedUndirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[n.ID()]; !ok { if _, ok := g.nodes[id]; !ok {
return 0 return 0
} }
var deg int var deg int
for _, e := range g.lines[n.ID()] { for _, e := range g.lines[id] {
deg += len(e) deg += len(e)
} }
return deg return deg

View File

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

View File

@@ -19,43 +19,46 @@ type WeightedLine interface {
// Multigraph is a generalized multigraph. // Multigraph is a generalized multigraph.
type Multigraph interface { type Multigraph interface {
// Has returns whether the node exists within the multigraph. // Has returns whether the node with the given ID exists
Has(Node) bool // within the multigraph.
Has(id int64) bool
// Nodes returns all the nodes in the multigraph. // Nodes returns all the nodes in the multigraph.
Nodes() []Node Nodes() []Node
// From returns all nodes that can be reached directly // From returns all nodes that can be reached directly
// from the given node. // from the node with the given ID.
From(Node) []Node From(id int64) []Node
// HasEdgeBetween returns whether an edge exists between // HasEdgeBetween returns whether an edge exists between
// nodes x and y without considering direction. // nodes with IDs xid and yid without considering direction.
HasEdgeBetween(x, y Node) bool HasEdgeBetween(xid, yid int64) bool
// Lines returns the lines from u to v if any such lines // Lines returns the lines from u to v, with IDs uid and
// exist and nil otherwise. The node v must be directly // vid, if any such lines exist and nil otherwise. The
// reachable from u as defined by the From method. // node v must be directly reachable from u as defined by
Lines(u, v Node) []Line // the From method.
Lines(uid, vid int64) []Line
} }
// WeightedMultigraph is a weighted multigraph. // WeightedMultigraph is a weighted multigraph.
type WeightedMultigraph interface { type WeightedMultigraph interface {
Multigraph Multigraph
// WeightedLines returns the weighted lines from u to v if // WeightedLines returns the weighted lines from u to v
// any such lines exist and nil otherwise. The node v must // with IDs uid and vid if any such lines exist and nil
// be directly reachable from u as defined by the // otherwise. The node v must be directly reachable
// From method. // from u as defined by the From method.
WeightedLines(u, v Node) []WeightedLine WeightedLines(uid, vid int64) []WeightedLine
} }
// UndirectedMultigraph is an undirected multigraph. // UndirectedMultigraph is an undirected multigraph.
type UndirectedMultigraph interface { type UndirectedMultigraph interface {
Multigraph Multigraph
// LinesBetween returns the lines between nodes x and y. // LinesBetween returns the lines between nodes x and y
LinesBetween(x, y Node) []Line // with IDs xid and yid.
LinesBetween(xid, yid int64) []Line
} }
// WeightedUndirectedMultigraph is a weighted undirected multigraph. // WeightedUndirectedMultigraph is a weighted undirected multigraph.
@@ -63,8 +66,8 @@ type WeightedUndirectedMultigraph interface {
WeightedMultigraph WeightedMultigraph
// WeightedLinesBetween returns the lines between nodes // WeightedLinesBetween returns the lines between nodes
// x and y. // x and y with IDs xid and yid.
WeightedLinesBetween(x, y Node) []WeightedLine WeightedLinesBetween(xid, yid int64) []WeightedLine
} }
// DirectedMultigraph is a directed multigraph. // DirectedMultigraph is a directed multigraph.
@@ -72,12 +75,13 @@ type DirectedMultigraph interface {
Multigraph Multigraph
// HasEdgeFromTo returns whether an edge exists // HasEdgeFromTo returns whether an edge exists
// in the multigraph from u to v. // in the multigraph from u to v with IDs uid
HasEdgeFromTo(u, v Node) bool // and vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly // To returns all nodes that can reach directly
// to the given node. // to the node with the given ID.
To(Node) []Node To(id int64) []Node
} }
// WeightedDirectedMultigraph is a weighted directed multigraph. // WeightedDirectedMultigraph is a weighted directed multigraph.
@@ -85,12 +89,13 @@ type WeightedDirectedMultigraph interface {
WeightedMultigraph WeightedMultigraph
// HasEdgeFromTo returns whether an edge exists // HasEdgeFromTo returns whether an edge exists
// in the multigraph from u to v. // in the multigraph from u to v with IDs uid
HasEdgeFromTo(u, v Node) bool // and vid.
HasEdgeFromTo(uid, vid int64) bool
// To returns all nodes that can reach directly // To returns all nodes that can reach directly
// to the given node. // to the node with the given ID.
To(Node) []Node To(id int64) []Node
} }
// LineAdder is an interface for adding lines to a multigraph. // 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) queue.Enqueue(s)
for queue.Len() != 0 { for queue.Len() != 0 {
v := queue.Dequeue() v := queue.Dequeue()
vid := v.ID()
stack.Push(v) stack.Push(v)
for _, w := range g.From(v) { for _, w := range g.From(vid) {
wid := w.ID()
// w found for the first time? // w found for the first time?
if d[w.ID()] < 0 { if d[wid] < 0 {
queue.Enqueue(w) queue.Enqueue(w)
d[w.ID()] = d[v.ID()] + 1 d[wid] = d[vid] + 1
} }
// shortest path to w via v? // shortest path to w via v?
if d[w.ID()] == d[v.ID()]+1 { if d[wid] == d[vid]+1 {
sigma[w.ID()] += sigma[v.ID()] sigma[wid] += sigma[vid]
p[w.ID()] = append(p[w.ID()], v) p[wid] = append(p[wid], v)
} }
} }
} }
@@ -151,18 +153,20 @@ func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64
nodes := g.Nodes() nodes := g.Nodes()
for i, s := range nodes { for i, s := range nodes {
sid := s.ID()
for j, t := range nodes { for j, t := range nodes {
if i == j { if i == j {
continue continue
} }
d := p.Weight(s, t) tid := t.ID()
d := p.Weight(sid, tid)
if math.IsInf(d, 0) { if math.IsInf(d, 0) {
continue continue
} }
// If we have a unique path, don't do the // If we have a unique path, don't do the
// extra work needed to get all paths. // extra work needed to get all paths.
path, _, unique := p.Between(s, t) path, _, unique := p.Between(sid, tid)
if unique { if unique {
for _, v := range path[1 : len(path)-1] { for _, v := range path[1 : len(path)-1] {
// For undirected graphs we double count // 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. // Otherwise iterate over all paths.
paths, _ := p.AllBetween(s, t) paths, _ := p.AllBetween(sid, tid)
stFrac := 1 / float64(len(paths)) stFrac := 1 / float64(len(paths))
for _, path := range paths { for _, path := range paths {
for _, v := range path[1 : len(path)-1] { 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) _, isUndirected := g.(graph.Undirected)
nodes := g.Nodes() nodes := g.Nodes()
for i, s := range nodes { for i, s := range nodes {
sid := s.ID()
for j, t := range nodes { for j, t := range nodes {
if i == j { if i == j {
continue continue
} }
d := p.Weight(s, t) tid := t.ID()
d := p.Weight(sid, tid)
if math.IsInf(d, 0) { if math.IsInf(d, 0) {
continue continue
} }
// If we have a unique path, don't do the // If we have a unique path, don't do the
// extra work needed to get all paths. // extra work needed to get all paths.
path, _, unique := p.Between(s, t) path, _, unique := p.Between(sid, tid)
if unique { if unique {
for k, v := range path[1:] { for k, v := range path[1:] {
// For undirected graphs we double count // 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. // Otherwise iterate over all paths.
paths, _ := p.AllBetween(s, t) paths, _ := p.AllBetween(sid, tid)
stFrac := 1 / float64(len(paths)) stFrac := 1 / float64(len(paths))
for _, path := range paths { for _, path := range paths {
for k, v := range path[1:] { for k, v := range path[1:] {

View File

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

View File

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

View File

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

View File

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

View File

@@ -146,7 +146,7 @@ func TestDistanceCentralityUndirected(t *testing.T) {
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1)) g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -336,7 +336,7 @@ func TestDistanceCentralityDirected(t *testing.T) {
g := simple.NewWeightedDirectedGraph(0, math.Inf(1)) g := simple.NewWeightedDirectedGraph(0, math.Inf(1))
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { 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)) nodesLinkingTo := make([][]int, len(nodes))
nodesLinkedFrom := make([][]int, len(nodes)) nodesLinkedFrom := make([][]int, len(nodes))
for i, n := range 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()]) 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()]) nodesLinkedFrom[i] = append(nodesLinkedFrom[i], indexOf[v.ID()])
} }
} }

View File

@@ -46,7 +46,7 @@ func TestHITS(t *testing.T) {
g := simple.NewDirectedGraph() g := simple.NewDirectedGraph()
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { 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) m := mat.NewDense(len(nodes), len(nodes), nil)
dangling := damp / float64(len(nodes)) dangling := damp / float64(len(nodes))
for j, u := range nodes { for j, u := range nodes {
to := g.From(u) to := g.From(u.ID())
f := damp / float64(len(to)) f := damp / float64(len(to))
for _, v := range to { for _, v := range to {
m.Set(indexOf[v.ID()], j, f) 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 var dangling compressedRow
df := damp / float64(len(nodes)) df := damp / float64(len(nodes))
for j, u := range nodes { for j, u := range nodes {
to := g.From(u) to := g.From(u.ID())
f := damp / float64(len(to)) f := damp / float64(len(to))
for _, v := range to { for _, v := range to {
m.addTo(indexOf[v.ID()], j, f) m.addTo(indexOf[v.ID()], j, f)

View File

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

View File

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

View File

@@ -129,7 +129,7 @@ func TestAStar(t *testing.T) {
for _, test := range aStarTests { for _, test := range aStarTests {
pt, _ := AStar(simple.Node(test.s), simple.Node(test.t), test.g, test.heuristic) 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) { if !topo.IsPathIn(test.g, p) {
t.Errorf("got path that is not path in input graph for %q", test.name) 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 { if !ok {
t.Fatalf("unexpected negative cycle in %q", test.name) 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) 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 _, start := range g.Nodes() {
for _, goal := range g.Nodes() { for _, goal := range g.Nodes() {
pt, _ := AStar(start, goal, g, heuristic) pt, _ := AStar(start, goal, g, heuristic)
gotPath, gotWeight := pt.To(goal) gotPath, gotWeight := pt.To(goal.ID())
wantPath, wantWeight, _ := ps.Between(start, goal) wantPath, wantWeight, _ := ps.Between(start.ID(), goal.ID())
if gotWeight != wantWeight { if gotWeight != wantWeight {
t.Errorf("unexpected path weight from %v to %v result: got:%f want:%f", t.Errorf("unexpected path weight from %v to %v result: got:%f want:%f",
start, goal, gotWeight, wantWeight) start, goal, gotWeight, wantWeight)
@@ -231,7 +231,7 @@ func isMonotonic(g UndirectedWeightLister, h Heuristic) (ok bool, at graph.Edge,
for _, edge := range g.WeightedEdges() { for _, edge := range g.WeightedEdges() {
from := edge.From() from := edge.From()
to := edge.To() to := edge.To()
w, ok := g.Weight(from, to) w, ok := g.Weight(from.ID(), to.ID())
if !ok { if !ok {
panic("A*: unexpected invalid weight") 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()) 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 { if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f", t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight) 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", t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight) test.Name, weight, test.Weight)
} }
@@ -301,7 +301,7 @@ func TestAStarNullHeuristic(t *testing.T) {
test.Name, p, test.WantPaths) 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)) { 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", t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, np, weight) 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|). // The time complexity of BellmanFordFrom is O(|V|.|E|).
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) { 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 return Shortest{from: u}, true
} }
var weight Weighting 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++ { for i := 1; i < len(nodes); i++ {
changed := false changed := false
for j, u := range nodes { for j, u := range nodes {
for _, v := range g.From(u) { uid := u.ID()
k := path.indexOf[v.ID()] for _, v := range g.From(uid) {
w, ok := weight(u, v) vid := v.ID()
k := path.indexOf[vid]
w, ok := weight(uid, vid)
if !ok { if !ok {
panic("bellman-ford: unexpected invalid weight") 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 j, u := range nodes {
for _, v := range g.From(u) { uid := u.ID()
k := path.indexOf[v.ID()] for _, v := range g.From(uid) {
w, ok := weight(u, v) vid := v.ID()
k := path.indexOf[vid]
w, ok := weight(uid, vid)
if !ok { if !ok {
panic("bellman-ford: unexpected invalid weight") 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()) 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 { if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f", t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight) 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", t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight) test.Name, weight, test.Weight)
} }
@@ -61,7 +61,7 @@ func TestBellmanFordFrom(t *testing.T) {
test.Name, p, test.WantPaths) 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)) { 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", t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, np, weight) test.Name, np, weight)

View File

@@ -201,7 +201,7 @@ func BenchmarkRandomGraphDominators(b *testing.B) {
if v == nil { if v == nil {
v = unordered[ui][rnd.Intn(len(unordered[ui]))] 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)) g.SetEdge(g.NewEdge(u, v))
} }
} }
@@ -253,16 +253,16 @@ type undirected struct {
*simple.DirectedGraph *simple.DirectedGraph
} }
func (g undirected) From(n graph.Node) []graph.Node { func (g undirected) From(id int64) []graph.Node {
return append(g.DirectedGraph.From(n), g.DirectedGraph.To(n)...) return append(g.DirectedGraph.From(id), g.DirectedGraph.To(id)...)
} }
func (g undirected) HasEdgeBetween(x, y graph.Node) bool { func (g undirected) HasEdgeBetween(xid, yid int64) bool {
return g.DirectedGraph.HasEdgeFromTo(x, y) return g.DirectedGraph.HasEdgeFromTo(xid, yid)
} }
func (g undirected) EdgeBetween(x, y graph.Node) graph.Edge { func (g undirected) EdgeBetween(xid, yid int64) graph.Edge {
return g.DirectedGraph.Edge(x, y) return g.DirectedGraph.Edge(xid, yid)
} }
func (g undirected) SetEdge(e graph.Edge) { 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 ltv.label = ltv
lt.nodes = append(lt.nodes, ltv) lt.nodes = append(lt.nodes, ltv)
for _, w := range g.From(v) { for _, w := range g.From(v.ID()) {
wid := w.ID() wid := w.ID()
idx, ok := lt.indexOf[wid] idx, ok := lt.indexOf[wid]

View File

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

View File

@@ -16,7 +16,7 @@ import (
// //
// The time complexity of DijkstrFrom is O(|E|.log|V|). // The time complexity of DijkstrFrom is O(|E|.log|V|).
func DijkstraFrom(u graph.Node, g graph.Graph) Shortest { func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
if !g.Has(u) { if !g.Has(u.ID()) {
return Shortest{from: u} return Shortest{from: u}
} }
var weight Weighting var weight Weighting
@@ -46,9 +46,11 @@ func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
if mid.dist > path.dist[k] { if mid.dist > path.dist[k] {
continue continue
} }
for _, v := range g.From(mid.node) { mnid := mid.node.ID()
j := path.indexOf[v.ID()] for _, v := range g.From(mnid) {
w, ok := weight(mid.node, v) vid := v.ID()
j := path.indexOf[vid]
w, ok := weight(mnid, vid)
if !ok { if !ok {
panic("dijkstra: unexpected invalid weight") panic("dijkstra: unexpected invalid weight")
} }
@@ -106,9 +108,11 @@ func dijkstraAllPaths(g graph.Graph, paths AllShortest) {
if mid.dist < paths.dist.At(i, k) { if mid.dist < paths.dist.At(i, k) {
paths.dist.Set(i, k, mid.dist) paths.dist.Set(i, k, mid.dist)
} }
for _, v := range g.From(mid.node) { mnid := mid.node.ID()
j := paths.indexOf[v.ID()] for _, v := range g.From(mnid) {
w, ok := weight(mid.node, v) vid := v.ID()
j := paths.indexOf[vid]
w, ok := weight(mnid, vid)
if !ok { if !ok {
panic("dijkstra: unexpected invalid weight") 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()) 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 { if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f", t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight) 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", t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight) test.Name, weight, test.Weight)
} }
@@ -73,7 +73,7 @@ func TestDijkstraFrom(t *testing.T) {
test.Name, p, test.WantPaths) 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)) { 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", t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, np, weight) test.Name, np, weight)
@@ -111,12 +111,12 @@ func TestDijkstraAllPaths(t *testing.T) {
// Check all random paths returned are OK. // Check all random paths returned are OK.
for i := 0; i < 10; i++ { 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 { if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f", t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight) 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", t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight) 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 { 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", t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
test.Name, np, weight, unique) 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 { if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f", t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight) test.Name, weight, test.Weight)
@@ -169,7 +169,7 @@ func TestDijkstraAllPaths(t *testing.T) {
test.Name, got, test.WantPaths) 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) { if nps != nil || !math.IsInf(weight, 1) {
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf", t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, nps, weight) 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 _, u := range d.model.Nodes() {
for _, v := range g.From(u) { uid := u.ID()
w := edgeWeight(d.weight, u, v) for _, v := range g.From(uid) {
vid := v.ID()
w := edgeWeight(d.weight, uid, vid)
if w < 0 { if w < 0 {
panic("D* Lite: negative edge weight") 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 // 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 // two connected nodes, u and v, using the provided weight function. It panics
// if there is no edge between u and v. // if there is no edge between u and v.
func edgeWeight(weight path.Weighting, u, v graph.Node) float64 { func edgeWeight(weight path.Weighting, uid, vid int64) float64 {
w, ok := weight(u, v) w, ok := weight(uid, vid)
if !ok { if !ok {
panic("D* Lite: unexpected invalid weight") 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 { if !u.key.less(d.keyFor(d.s)) && d.s.rhs <= d.s.g {
break break
} }
uid := u.ID()
switch kNew := d.keyFor(u); { switch kNew := d.keyFor(u); {
case u.key.less(kNew): case u.key.less(kNew):
d.queue.update(u, kNew) d.queue.update(u, kNew)
case u.g > u.rhs: case u.g > u.rhs:
u.g = u.rhs u.g = u.rhs
d.queue.remove(u) d.queue.remove(u)
for _, _s := range d.model.To(u) { for _, _s := range d.model.To(uid) {
s := _s.(*dStarLiteNode) s := _s.(*dStarLiteNode)
if s.ID() != d.t.ID() { sid := s.ID()
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, s, u)+u.g) if sid != d.t.ID() {
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, uid)+u.g)
} }
d.update(s) d.update(s)
} }
default: default:
gOld := u.g gOld := u.g
u.g = math.Inf(1) 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) 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() { if s.ID() != d.t.ID() {
s.rhs = math.Inf(1) s.rhs = math.Inf(1)
for _, t := range d.model.From(s) { for _, t := range d.model.From(sid) {
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, s, t)+t.(*dStarLiteNode).g) 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) min := math.Inf(1)
var next *dStarLiteNode 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) 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) { if w < min || (w == min && s.rhs < rhs) {
next = s next = s
min = w min = w
@@ -294,24 +301,27 @@ func (d *DStarLite) UpdateWorld(changes []graph.Edge) {
d.last = d.s d.last = d.s
for _, e := range changes { for _, e := range changes {
from := e.From() from := e.From()
fid := from.ID()
to := e.To() to := e.To()
c, _ := d.weight(from, to) tid := to.ID()
c, _ := d.weight(fid, tid)
if c < 0 { if c < 0 {
panic("D* Lite: negative edge weight") panic("D* Lite: negative edge weight")
} }
cOld, _ := d.model.Weight(from, to) cOld, _ := d.model.Weight(fid, tid)
u := d.worldNodeFor(from) u := d.worldNodeFor(from)
v := d.worldNodeFor(to) v := d.worldNodeFor(to)
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: v, W: c}) d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: v, W: c})
uid := u.ID()
if cOld > c { if cOld > c {
if u.ID() != d.t.ID() { if uid != d.t.ID() {
u.rhs = math.Min(u.rhs, c+v.g) u.rhs = math.Min(u.rhs, c+v.g)
} }
} else if u.rhs == cOld+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) u.rhs = math.Inf(1)
for _, t := range d.model.From(u) { for _, t := range d.model.From(uid) {
u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, u, t)+t.(*dStarLiteNode).g) 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 next *dStarLiteNode
cost float64 cost float64
) )
for _, _v := range d.model.From(u) { uid := u.ID()
for _, _v := range d.model.From(uid) {
v := _v.(*dStarLiteNode) 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) { if rhs := w + v.g; rhs < min || (rhs == min && v.rhs < rhsMin) {
next = v next = v
min = rhs min = rhs

View File

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

View File

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

View File

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

View File

@@ -35,12 +35,12 @@ func TestFloydWarshall(t *testing.T) {
// Check all random paths returned are OK. // Check all random paths returned are OK.
for i := 0; i < 10; i++ { 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 { if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f", t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight) 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", t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
test.Name, weight, test.Weight) 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 { 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", t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
test.Name, np, weight, unique) 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 { if weight != test.Weight {
t.Errorf("%q: unexpected weight from Between: got:%f want:%f", t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
test.Name, weight, test.Weight) test.Name, weight, test.Weight)
@@ -93,7 +93,7 @@ func TestFloydWarshall(t *testing.T) {
test.Name, got, test.WantPaths) 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) { if nps != nil || !math.IsInf(weight, 1) {
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf", t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
test.Name, nps, weight) 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 // Has returns whether n is a node in the grid. The state of
// the AllVisible field determines whether a non-open node is // the AllVisible field determines whether a non-open node is
// present. // present.
func (g *Grid) Has(n graph.Node) bool { func (g *Grid) Has(id int64) bool {
return g.has(n.ID())
}
func (g *Grid) has(id int64) bool {
return 0 <= id && id < int64(len(g.open)) && (g.AllVisible || g.open[id]) return 0 <= id && id < int64(len(g.open)) && (g.AllVisible || g.open[id])
} }
// HasOpen returns whether n is an open node in the grid. // HasOpen returns whether n is an open node in the grid.
func (g *Grid) HasOpen(n graph.Node) bool { func (g *Grid) HasOpen(id int64) bool {
id := n.ID()
return 0 <= id && id < int64(len(g.open)) && g.open[id] 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 // XY returns the cartesian coordinates of n. If n is not a node
// in the grid, (NaN, NaN) is returned. // in the grid, (NaN, NaN) is returned.
func (g *Grid) XY(n graph.Node) (x, y float64) { func (g *Grid) XY(id int64) (x, y float64) {
if !g.Has(n) { if !g.Has(id) {
return math.NaN(), math.NaN() return math.NaN(), math.NaN()
} }
r, c := g.RowCol(n.ID()) r, c := g.RowCol(id)
return float64(c), float64(r) 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 // From returns all the nodes reachable from u. Reachabilty requires that both
// ends of an edge must be open. // ends of an edge must be open.
func (g *Grid) From(u graph.Node) []graph.Node { func (g *Grid) From(uid int64) []graph.Node {
if !g.HasOpen(u) { if !g.HasOpen(uid) {
return nil return nil
} }
nr, nc := g.RowCol(u.ID()) nr, nc := g.RowCol(uid)
var to []graph.Node var to []graph.Node
for r := nr - 1; r <= nr+1; r++ { for r := nr - 1; r <= nr+1; r++ {
for c := nc - 1; c <= nc+1; c++ { 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) 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. // HasEdgeBetween returns whether there is an edge between u and v.
func (g *Grid) HasEdgeBetween(u, v graph.Node) bool { func (g *Grid) HasEdgeBetween(uid, vid int64) bool {
if !g.HasOpen(u) || !g.HasOpen(v) || u.ID() == v.ID() { if !g.HasOpen(uid) || !g.HasOpen(vid) || uid == vid {
return false return false
} }
ur, uc := g.RowCol(u.ID()) ur, uc := g.RowCol(uid)
vr, vc := g.RowCol(v.ID()) vr, vc := g.RowCol(vid)
if abs(ur-vr) > 1 || abs(uc-vc) > 1 { if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
return false return false
} }
@@ -200,47 +195,47 @@ func abs(i int) int {
} }
// Edge returns the edge between u and v. // Edge returns the edge between u and v.
func (g *Grid) Edge(u, v graph.Node) graph.Edge { func (g *Grid) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// WeightedEdge returns the weighted edge between u and v. // WeightedEdge returns the weighted edge between u and v.
func (g *Grid) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *Grid) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// EdgeBetween returns the edge between u and v. // EdgeBetween returns the edge between u and v.
func (g *Grid) EdgeBetween(u, v graph.Node) graph.Edge { func (g *Grid) EdgeBetween(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// WeightedEdgeBetween returns the weighted edge between u and v. // WeightedEdgeBetween returns the weighted edge between u and v.
func (g *Grid) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge { func (g *Grid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
if g.HasEdgeBetween(u, v) { if g.HasEdgeBetween(uid, vid) {
if !g.AllowDiagonal || g.UnitEdgeWeight { 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) ux, uy := g.XY(uid)
vx, vy := g.XY(v) vx, vy := g.XY(vid)
return simple.WeightedEdge{F: u, T: v, W: math.Hypot(ux-vx, uy-vy)} return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)}
} }
return nil return nil
} }
// Weight returns the weight of the given edge. // Weight returns the weight of the given edge.
func (g *Grid) Weight(x, y graph.Node) (w float64, ok bool) { func (g *Grid) Weight(xid, yid int64) (w float64, ok bool) {
if x.ID() == y.ID() { if xid == yid {
return 0, true return 0, true
} }
if !g.HasEdgeBetween(x, y) { if !g.HasEdgeBetween(xid, yid) {
return math.Inf(1), false 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 { if !g.AllowDiagonal || g.UnitEdgeWeight {
return 1, true return 1, true
} }
ux, uy := g.XY(e.From()) ux, uy := g.XY(e.From().ID())
vx, vy := g.XY(e.To()) vx, vy := g.XY(e.To().ID())
return math.Hypot(ux-vx, uy-vy), true return math.Hypot(ux-vx, uy-vy), true
} }
return math.Inf(1), 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 // We don't use topo.IsPathIn at the outset because we
// want to draw as much as possible before failing. // want to draw as much as possible before failing.
for i, n := range path { 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)) { 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] = '!' b[r*(g.c+1)+c] = '!'
} }
return b, errors.New("grid: not a path in graph") return b, errors.New("grid: not a path in graph")
} }
r, c := g.RowCol(n.ID()) r, c := g.RowCol(id)
switch i { switch i {
case len(path) - 1: case len(path) - 1:
b[r*(g.c+1)+c] = 'G' b[r*(g.c+1)+c] = 'G'

View File

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

View File

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

View File

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

View File

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

View File

@@ -47,7 +47,7 @@ func ExampleBellmanFordFrom_negativecycles() {
return return
} }
for _, n := range []simple.Node{'a', 'b', 'c', 'd', 'e', 'f'} { 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) { if math.IsNaN(w) {
fmt.Printf("negative cycle in path to %c path:%c\n", n, p) 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 // 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. // a negative cycle, the returned weight will not reflect the true path weight.
func (p Shortest) WeightTo(v graph.Node) float64 { func (p Shortest) WeightTo(vid int64) float64 {
to, toOK := p.indexOf[v.ID()] to, toOK := p.indexOf[vid]
if !toOK { if !toOK {
return math.Inf(1) 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 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 // to v includes a negative cycle, one pass through the cycle will be included
// in path and weight will be returned as NaN. // in path and weight will be returned as NaN.
func (p Shortest) To(v graph.Node) (path []graph.Node, weight float64) { func (p Shortest) To(vid int64) (path []graph.Node, weight float64) {
to, toOK := p.indexOf[v.ID()] to, toOK := p.indexOf[vid]
if !toOK || math.IsInf(p.dist[to], 1) { if !toOK || math.IsInf(p.dist[to], 1) {
return nil, math.Inf(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) 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 // 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. // Weight returns the weight of the minimum path between u and v.
func (p AllShortest) Weight(u, v graph.Node) float64 { func (p AllShortest) Weight(uid, vid int64) float64 {
from, fromOK := p.indexOf[u.ID()] from, fromOK := p.indexOf[uid]
to, toOK := p.indexOf[v.ID()] to, toOK := p.indexOf[vid]
if !fromOK || !toOK { if !fromOK || !toOK {
return math.Inf(1) 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 // 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 // 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. // be included, but unique will be returned false.
func (p AllShortest) Between(u, v graph.Node) (path []graph.Node, weight float64, unique bool) { func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) {
from, fromOK := p.indexOf[u.ID()] from, fromOK := p.indexOf[uid]
to, toOK := p.indexOf[v.ID()] to, toOK := p.indexOf[vid]
if !fromOK || !toOK || len(p.at(from, to)) == 0 { 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 []graph.Node{p.nodes[from]}, 0, true
} }
return nil, math.Inf(1), false 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 // AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
// containing zero-weight cycles are not returned. // containing zero-weight cycles are not returned.
func (p AllShortest) AllBetween(u, v graph.Node) (paths [][]graph.Node, weight float64) { func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) {
from, fromOK := p.indexOf[u.ID()] from, fromOK := p.indexOf[uid]
to, toOK := p.indexOf[v.ID()] to, toOK := p.indexOf[vid]
if !fromOK || !toOK || len(p.at(from, to)) == 0 { 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 [][]graph.Node{{p.nodes[from]}}, 0
} }
return nil, math.Inf(1) 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 var n graph.Node
if p.forward { if p.forward {
n = u n = p.nodes[from]
} else { } else {
n = v n = p.nodes[to]
} }
seen := make([]bool, len(p.nodes)) seen := make([]bool, len(p.nodes))
paths = p.allBetween(from, to, seen, []graph.Node{n}, nil) 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] u := nodes[0]
for _, v := range g.From(u) { uid := u.ID()
w, ok := g.Weight(u, v) for _, v := range g.From(uid) {
w, ok := g.Weight(uid, v.ID())
if !ok { if !ok {
panic("prim: unexpected invalid weight") panic("prim: unexpected invalid weight")
} }
@@ -59,15 +60,16 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
var w float64 var w float64
for q.Len() > 0 { for q.Len() > 0 {
e := heap.Pop(q).(simple.WeightedEdge) e := heap.Pop(q).(simple.WeightedEdge)
if e.To() != nil && g.HasEdgeBetween(e.From(), e.To()) { if e.To() != nil && g.HasEdgeBetween(e.From().ID(), e.To().ID()) {
dst.SetWeightedEdge(g.WeightedEdge(e.From(), e.To())) dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID()))
w += e.Weight() w += e.Weight()
} }
u = e.From() 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 { if key, ok := q.key(n); ok {
w, ok := g.Weight(u, n) w, ok := g.Weight(uid, n.ID())
if !ok { if !ok {
panic("prim: unexpected invalid weight") panic("prim: unexpected invalid weight")
} }
@@ -173,7 +175,7 @@ func Kruskal(dst WeightedBuilder, g UndirectedWeightLister) float64 {
for _, e := range edges { for _, e := range edges {
if s1, s2 := ds.find(e.From().ID()), ds.find(e.To().ID()); s1 != s2 { if s1, s2 := ds.find(e.From().ID()), ds.find(e.To().ID()); s1 != s2 {
ds.union(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() 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)) test.name, len(gotEdges), len(test.treeEdges))
} }
for _, e := range 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 { if !ok {
t.Errorf("spanning tree edge not found in graph for %q: %+v", t.Errorf("spanning tree edge not found in graph for %q: %+v",
test.name, e) 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 // Weighting is a mapping between a pair of nodes and a weight. It follows the
// semantics of the Weighter interface. // 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 // UniformCost returns a Weighting that returns an edge cost of 1 for existing
// edges, zero for node identity and Inf for otherwise absent edges. // edges, zero for node identity and Inf for otherwise absent edges.
func UniformCost(g graph.Graph) Weighting { func UniformCost(g graph.Graph) Weighting {
return func(x, y graph.Node) (w float64, ok bool) { return func(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if xid == yid { if xid == yid {
return 0, true return 0, true
} }
if e := g.Edge(x, y); e != nil { if e := g.Edge(xid, yid); e != nil {
return 1, true return 1, true
} }
return math.Inf(1), false 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. // Has returns whether the node exists within the graph.
func (g *DirectedMatrix) Has(n graph.Node) bool { func (g *DirectedMatrix) Has(id int64) bool {
return g.has(n.ID()) return g.has(id)
} }
func (g *DirectedMatrix) has(id int64) bool { 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. // From returns all nodes in g that can be reached directly from n.
func (g *DirectedMatrix) From(n graph.Node) []graph.Node { func (g *DirectedMatrix) From(id int64) []graph.Node {
id := n.ID()
if !g.has(id) { if !g.has(id) {
return nil 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. // To returns all nodes in g that can reach directly to n.
func (g *DirectedMatrix) To(n graph.Node) []graph.Node { func (g *DirectedMatrix) To(id int64) []graph.Node {
id := n.ID()
if !g.has(id) { if !g.has(id) {
return nil 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 // HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction. // considering direction.
func (g *DirectedMatrix) HasEdgeBetween(x, y graph.Node) bool { func (g *DirectedMatrix) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
if !g.has(xid) { if !g.has(xid) {
return false return false
} }
yid := y.ID()
if !g.has(yid) { if !g.has(yid) {
return false 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. // 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 node v must be directly reachable from u as defined by the From method.
func (g *DirectedMatrix) Edge(u, v graph.Node) graph.Edge { func (g *DirectedMatrix) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(u, v) return g.WeightedEdge(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g *DirectedMatrix) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *DirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
if g.HasEdgeFromTo(u, v) { if g.HasEdgeFromTo(uid, vid) {
// x.ID() and y.ID() are not greater than maximum int by this point. // xid and yid 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()))} return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
} }
return nil return nil
} }
// HasEdgeFromTo returns whether an edge exists in the graph from u to v. // HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *DirectedMatrix) HasEdgeFromTo(u, v graph.Node) bool { func (g *DirectedMatrix) HasEdgeFromTo(uid, vid int64) bool {
uid := u.ID()
if !g.has(uid) { if !g.has(uid) {
return false return false
} }
vid := v.ID()
if !g.has(vid) { if !g.has(vid) {
return false 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 // 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 // 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. // 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) { func (g *DirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if xid == yid { if xid == yid {
return g.self, true 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. // Degree returns the in+out degree of n in g.
func (g *DirectedMatrix) Degree(n graph.Node) int { func (g *DirectedMatrix) Degree(id int64) int {
id := n.ID()
if !g.has(id) { if !g.has(id) {
return 0 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. // Has returns whether the node exists within the graph.
func (g *UndirectedMatrix) Has(n graph.Node) bool { func (g *UndirectedMatrix) Has(id int64) bool {
return g.has(n.ID()) return g.has(id)
} }
func (g *UndirectedMatrix) has(id int64) bool { 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. // From returns all nodes in g that can be reached directly from n.
func (g *UndirectedMatrix) From(n graph.Node) []graph.Node { func (g *UndirectedMatrix) From(id int64) []graph.Node {
id := n.ID()
if !g.has(id) { if !g.has(id) {
return nil 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *UndirectedMatrix) HasEdgeBetween(u, v graph.Node) bool { func (g *UndirectedMatrix) HasEdgeBetween(uid, vid int64) bool {
uid := u.ID()
if !g.has(uid) { if !g.has(uid) {
return false return false
} }
vid := v.ID()
if !g.has(vid) { if !g.has(vid) {
return false 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. // 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 node v must be directly reachable from u as defined by the From method.
func (g *UndirectedMatrix) Edge(u, v graph.Node) graph.Edge { func (g *UndirectedMatrix) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g *UndirectedMatrix) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *UndirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// EdgeBetween returns the edge between nodes x and y. // EdgeBetween returns the edge between nodes x and y.
func (g *UndirectedMatrix) EdgeBetween(u, v graph.Node) graph.Edge { func (g *UndirectedMatrix) EdgeBetween(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// WeightedEdgeBetween returns the weighted edge between nodes x and y. // WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *UndirectedMatrix) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge { func (g *UndirectedMatrix) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
if g.HasEdgeBetween(u, v) { if g.HasEdgeBetween(uid, vid) {
// u.ID() and v.ID() are not greater than maximum int by this point. // uid and vid 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()))} return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
} }
return nil 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 // 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 // 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. // 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) { func (g *UndirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if xid == yid { if xid == yid {
return g.self, true return g.self, true
} }
@@ -234,8 +229,7 @@ func (g *UndirectedMatrix) RemoveEdge(e graph.Edge) {
} }
// Degree returns the degree of n in g. // Degree returns the degree of n in g.
func (g *UndirectedMatrix) Degree(n graph.Node) int { func (g *UndirectedMatrix) Degree(id int64) int {
id := n.ID()
if !g.has(id) { if !g.has(id) {
return 0 return 0
} }

View File

@@ -34,17 +34,17 @@ func TestBasicDenseImpassable(t *testing.T) {
} }
for i := 0; i < 5; i++ { 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) 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) t.Errorf("Node in impassable graph has a neighbor. Node: %d Degree: %d", i, degree)
} }
} }
for i := 5; i < 10; i++ { 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) t.Errorf("Node exists that shouldn't: %d", i)
} }
} }
@@ -57,17 +57,17 @@ func TestBasicDensePassable(t *testing.T) {
} }
for i := 0; i < 5; i++ { 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) 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) t.Errorf("Node in passable graph missing neighbors. Node: %d Degree: %d", i, degree)
} }
} }
for i := 5; i < 10; i++ { 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) 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 := NewDirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 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 || if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
dg.Edge(Node(0), Node(2)) == nil { dg.Edge(int64(0), int64(2)) == nil {
t.Errorf("Adding edge didn't create successor") t.Errorf("Adding edge didn't create successor")
} }
dg.RemoveEdge(Edge{F: Node(0), T: Node(2)}) 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") 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") t.Errorf("Removing directed edge wrongly kept predecessor")
} }
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 2}) dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 2})
// I figure we've torture tested From/To at this point // I figure we've torture tested From/To at this point
// so we'll just use the bool functions now // 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") t.Fatal("Adding directed edge didn't change successor back")
} }
c1, _ := dg.Weight(Node(2), Node(0)) c1, _ := dg.Weight(int64(2), int64(0))
c2, _ := dg.Weight(Node(0), Node(2)) c2, _ := dg.Weight(int64(0), int64(2))
if c1 == c2 { if c1 == c2 {
t.Error("Adding directed edge affected cost in undirected manner") 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 := NewUndirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
dg.SetEdge(Edge{F: Node(0), T: Node(2)}) dg.SetEdge(Edge{F: Node(0), T: Node(2)})
if neighbors := dg.From(Node(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 || if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
dg.EdgeBetween(Node(0), Node(2)) == nil { dg.EdgeBetween(int64(0), int64(2)) == nil {
t.Errorf("Couldn't add neighbor") t.Errorf("Couldn't add neighbor")
} }
if neighbors := dg.From(Node(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 || if neighbors := dg.From(int64(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
dg.EdgeBetween(Node(2), Node(0)) == nil { dg.EdgeBetween(int64(2), int64(0)) == nil {
t.Errorf("Adding an undirected neighbor didn't add it reciprocally") 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") panic("simple: adding self edge")
} }
if !g.Has(from) { if !g.Has(fid) {
g.AddNode(from) g.AddNode(from)
} }
if !g.Has(to) { if !g.Has(tid) {
g.AddNode(to) g.AddNode(to)
} }
@@ -126,8 +126,8 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
} }
// Has returns whether the node exists within the graph. // Has returns whether the node exists within the graph.
func (g *DirectedGraph) Has(n graph.Node) bool { func (g *DirectedGraph) Has(id int64) bool {
_, ok := g.nodes[n.ID()] _, ok := g.nodes[id]
return ok 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. // From returns all nodes in g that can be reached directly from n.
func (g *DirectedGraph) From(n graph.Node) []graph.Node { func (g *DirectedGraph) From(id int64) []graph.Node {
if _, ok := g.from[n.ID()]; !ok { if _, ok := g.from[id]; !ok {
return nil return nil
} }
from := make([]graph.Node, len(g.from[n.ID()])) from := make([]graph.Node, len(g.from[id]))
i := 0 i := 0
for id := range g.from[n.ID()] { for vid := range g.from[id] {
from[i] = g.nodes[id] from[i] = g.nodes[vid]
i++ i++
} }
return from return from
} }
// To returns all nodes in g that can reach directly to n. // To returns all nodes in g that can reach directly to n.
func (g *DirectedGraph) To(n graph.Node) []graph.Node { func (g *DirectedGraph) To(id int64) []graph.Node {
if _, ok := g.from[n.ID()]; !ok { if _, ok := g.from[id]; !ok {
return nil return nil
} }
to := make([]graph.Node, len(g.to[n.ID()])) to := make([]graph.Node, len(g.to[id]))
i := 0 i := 0
for id := range g.to[n.ID()] { for uid := range g.to[id] {
to[i] = g.nodes[id] to[i] = g.nodes[uid]
i++ i++
} }
return to 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 // HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction. // considering direction.
func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool { func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
yid := y.ID()
if _, ok := g.from[xid][yid]; ok { if _, ok := g.from[xid][yid]; ok {
return true 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. // 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 node v must be directly reachable from u as defined by the From method.
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge { func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
edge, ok := g.from[u.ID()][v.ID()] edge, ok := g.from[uid][vid]
if !ok { if !ok {
return nil 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. // HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool { func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
if _, ok := g.from[u.ID()][v.ID()]; !ok { if _, ok := g.from[uid][vid]; !ok {
return false return false
} }
return true return true
} }
// Degree returns the in+out degree of n in g. // Degree returns the in+out degree of n in g.
func (g *DirectedGraph) Degree(n graph.Node) int { func (g *DirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[n.ID()]; !ok { if _, ok := g.nodes[id]; !ok {
return 0 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) { func TestEdgeOvercounting(t *testing.T) {
g := generateDummyGraph() 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)) 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") panic("simple: adding self edge")
} }
if !g.Has(from) { if !g.Has(fid) {
g.AddNode(from) g.AddNode(from)
} }
if !g.Has(to) { if !g.Has(tid) {
g.AddNode(to) g.AddNode(to)
} }
@@ -118,8 +118,8 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
} }
// Has returns whether the node exists within the graph. // Has returns whether the node exists within the graph.
func (g *UndirectedGraph) Has(n graph.Node) bool { func (g *UndirectedGraph) Has(id int64) bool {
_, ok := g.nodes[n.ID()] _, ok := g.nodes[id]
return ok 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. // From returns all nodes in g that can be reached directly from n.
func (g *UndirectedGraph) From(n graph.Node) []graph.Node { func (g *UndirectedGraph) From(id int64) []graph.Node {
if !g.Has(n) { if !g.Has(id) {
return nil return nil
} }
nodes := make([]graph.Node, len(g.edges[n.ID()])) nodes := make([]graph.Node, len(g.edges[id]))
i := 0 i := 0
for from := range g.edges[n.ID()] { for from := range g.edges[id] {
nodes[i] = g.nodes[from] nodes[i] = g.nodes[from]
i++ 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *UndirectedGraph) HasEdgeBetween(x, y graph.Node) bool { func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
_, ok := g.edges[x.ID()][y.ID()] _, ok := g.edges[xid][yid]
return ok return ok
} }
// Edge returns the edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge { func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.EdgeBetween(u, v) return g.EdgeBetween(uid, vid)
} }
// EdgeBetween returns the edge between nodes x and y. // EdgeBetween returns the edge between nodes x and y.
func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge { func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
edge, ok := g.edges[x.ID()][y.ID()] edge, ok := g.edges[xid][yid]
if !ok { if !ok {
return nil return nil
} }
@@ -196,9 +196,9 @@ func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
} }
// Degree returns the degree of n in g. // Degree returns the degree of n in g.
func (g *UndirectedGraph) Degree(n graph.Node) int { func (g *UndirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[n.ID()]; !ok { if _, ok := g.nodes[id]; !ok {
return 0 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)) delete(nodes, Node(2))
n := g.NewNode() n := g.NewNode()
g.AddNode(n) g.AddNode(n)
if !g.Has(n) { if !g.Has(n.ID()) {
t.Error("added node does not exist in graph") t.Error("added node does not exist in graph")
} }
if _, exists := nodes[n]; exists { if _, exists := nodes[n]; exists {

View File

@@ -100,10 +100,10 @@ func (g *WeightedDirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
panic("simple: adding self edge") panic("simple: adding self edge")
} }
if !g.Has(from) { if !g.Has(fid) {
g.AddNode(from) g.AddNode(from)
} }
if !g.Has(to) { if !g.Has(tid) {
g.AddNode(to) g.AddNode(to)
} }
@@ -132,8 +132,8 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
} }
// Has returns whether the node exists within the graph. // Has returns whether the node exists within the graph.
func (g *WeightedDirectedGraph) Has(n graph.Node) bool { func (g *WeightedDirectedGraph) Has(id int64) bool {
_, ok := g.nodes[n.ID()] _, ok := g.nodes[id]
return ok 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. // From returns all nodes in g that can be reached directly from n.
func (g *WeightedDirectedGraph) From(n graph.Node) []graph.Node { func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
if _, ok := g.from[n.ID()]; !ok { if _, ok := g.from[id]; !ok {
return nil return nil
} }
from := make([]graph.Node, len(g.from[n.ID()])) from := make([]graph.Node, len(g.from[id]))
i := 0 i := 0
for id := range g.from[n.ID()] { for vid := range g.from[id] {
from[i] = g.nodes[id] from[i] = g.nodes[vid]
i++ i++
} }
return from return from
} }
// To returns all nodes in g that can reach directly to n. // To returns all nodes in g that can reach directly to n.
func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node { func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
if _, ok := g.from[n.ID()]; !ok { if _, ok := g.from[id]; !ok {
return nil return nil
} }
to := make([]graph.Node, len(g.to[n.ID()])) to := make([]graph.Node, len(g.to[id]))
i := 0 i := 0
for id := range g.to[n.ID()] { for uid := range g.to[id] {
to[i] = g.nodes[id] to[i] = g.nodes[uid]
i++ i++
} }
return to 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 // HasEdgeBetween returns whether an edge exists between nodes x and y without
// considering direction. // considering direction.
func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool { func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
xid := x.ID()
yid := y.ID()
if _, ok := g.from[xid][yid]; ok { if _, ok := g.from[xid][yid]; ok {
return true 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. // 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 node v must be directly reachable from u as defined by the From method.
func (g *WeightedDirectedGraph) Edge(u, v graph.Node) graph.Edge { func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdge(u, v) return g.WeightedEdge(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
edge, ok := g.from[u.ID()][v.ID()] edge, ok := g.from[uid][vid]
if !ok { if !ok {
return nil 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. // HasEdgeFromTo returns whether an edge exists in the graph from u to v.
func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool { func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
if _, ok := g.from[u.ID()][v.ID()]; !ok { if _, ok := g.from[uid][vid]; !ok {
return false return false
} }
return true 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 // 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 // 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. // 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) { func (g *WeightedDirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if xid == yid { if xid == yid {
return g.self, true 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. // Degree returns the in+out degree of n in g.
func (g *WeightedDirectedGraph) Degree(n graph.Node) int { func (g *WeightedDirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[n.ID()]; !ok { if _, ok := g.nodes[id]; !ok {
return 0 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) { func TestWeightedEdgeOvercounting(t *testing.T) {
g := generateDummyGraph() 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)) 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") panic("simple: adding self edge")
} }
if !g.Has(from) { if !g.Has(fid) {
g.AddNode(from) g.AddNode(from)
} }
if !g.Has(to) { if !g.Has(tid) {
g.AddNode(to) g.AddNode(to)
} }
@@ -124,8 +124,8 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
} }
// Has returns whether the node exists within the graph. // Has returns whether the node exists within the graph.
func (g *WeightedUndirectedGraph) Has(n graph.Node) bool { func (g *WeightedUndirectedGraph) Has(id int64) bool {
_, ok := g.nodes[n.ID()] _, ok := g.nodes[id]
return ok 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. // From returns all nodes in g that can be reached directly from n.
func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node { func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
if !g.Has(n) { if !g.Has(id) {
return nil return nil
} }
nodes := make([]graph.Node, len(g.edges[n.ID()])) nodes := make([]graph.Node, len(g.edges[id]))
i := 0 i := 0
for from := range g.edges[n.ID()] { for from := range g.edges[id] {
nodes[i] = g.nodes[from] nodes[i] = g.nodes[from]
i++ 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. // HasEdgeBetween returns whether an edge exists between nodes x and y.
func (g *WeightedUndirectedGraph) HasEdgeBetween(x, y graph.Node) bool { func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
_, ok := g.edges[x.ID()][y.ID()] _, ok := g.edges[xid][yid]
return ok return ok
} }
// Edge returns the edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g *WeightedUndirectedGraph) Edge(u, v graph.Node) graph.Edge { func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise. // 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 node v must be directly reachable from u as defined by the From method.
func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge { func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
return g.WeightedEdgeBetween(u, v) return g.WeightedEdgeBetween(uid, vid)
} }
// EdgeBetween returns the edge between nodes x and y. // EdgeBetween returns the edge between nodes x and y.
func (g *WeightedUndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge { func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
return g.WeightedEdgeBetween(x, y) return g.WeightedEdgeBetween(xid, yid)
} }
// WeightedEdgeBetween returns the weighted edge between nodes x and y. // WeightedEdgeBetween returns the weighted edge between nodes x and y.
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge { func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
edge, ok := g.edges[x.ID()][y.ID()] edge, ok := g.edges[xid][yid]
if !ok { if !ok {
return nil 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 // 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 // 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. // 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) { func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
xid := x.ID()
yid := y.ID()
if xid == yid { if xid == yid {
return g.self, true 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. // Degree returns the degree of n in g.
func (g *WeightedUndirectedGraph) Degree(n graph.Node) int { func (g *WeightedUndirectedGraph) Degree(id int64) int {
if _, ok := g.nodes[n.ID()]; !ok { if _, ok := g.nodes[id]; !ok {
return 0 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)) delete(nodes, Node(2))
n := g.NewNode() n := g.NewNode()
g.AddNode(n) g.AddNode(n)
if !g.Has(n) { if !g.Has(n.ID()) {
t.Error("added node does not exist in graph") t.Error("added node does not exist in graph")
} }
if _, exists := nodes[n]; exists { 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. // Check for tautology.
if variables[0].negated().ID() == variables[1].ID() { if variables[0].negated().ID() == variables[1].ID() {
for _, v := range variables { for _, v := range variables {
if !g.Has(v) { if !g.Has(v.ID()) {
g.AddNode(v) 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) neighbours = make(map[int64][]graph.Node)
) )
for _, n := range nodes { for _, n := range nodes {
adj := g.From(n) id := n.ID()
neighbours[n.ID()] = adj adj := g.From(id)
dv[n.ID()] = len(adj) neighbours[id] = adj
dv[id] = len(adj)
if len(adj) > maxDegree { if len(adj) > maxDegree {
maxDegree = len(adj) maxDegree = len(adj)
} }
@@ -146,7 +147,7 @@ func BronKerbosch(g graph.Undirected) [][]graph.Node {
order, _ := degeneracyOrdering(g) order, _ := degeneracyOrdering(g)
ordered.Reverse(order) ordered.Reverse(order)
for _, v := range order { for _, v := range order {
neighbours := g.From(v) neighbours := g.From(v.ID())
nv := make(set.Nodes, len(neighbours)) nv := make(set.Nodes, len(neighbours))
for _, n := range neighbours { for _, n := range neighbours {
nv.Add(n) nv.Add(n)
@@ -175,7 +176,8 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
if nu.Has(v) { if nu.Has(v) {
continue continue
} }
neighbours := g.From(v) vid := v.ID()
neighbours := g.From(vid)
nv := make(set.Nodes, len(neighbours)) nv := make(set.Nodes, len(neighbours))
for _, n := range neighbours { for _, n := range neighbours {
nv.Add(n) nv.Add(n)
@@ -183,7 +185,7 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
var found bool var found bool
for _, n := range r { for _, n := range r {
if n.ID() == v.ID() { if n.ID() == vid {
found = true found = true
break break
} }
@@ -205,10 +207,10 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
// compile time option. // compile time option.
if !tomitaTanakaTakahashi { if !tomitaTanakaTakahashi {
for _, n := range p { for _, n := range p {
return g.From(n) return g.From(n.ID())
} }
for _, n := range x { for _, n := range x {
return g.From(n) return g.From(n.ID())
} }
panic("bronKerbosch: empty set") panic("bronKerbosch: empty set")
} }
@@ -220,7 +222,7 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
maxNeighbors := func(s set.Nodes) { maxNeighbors := func(s set.Nodes) {
outer: outer:
for _, u := range s { for _, u := range s {
nb := g.From(u) nb := g.From(u.ID())
c := len(nb) c := len(nb)
if c <= max { if c <= max {
continue continue

View File

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

View File

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

View File

@@ -142,14 +142,15 @@ func johnsonGraphFrom(g graph.Directed) johnsonGraph {
succ: make(map[int64]set.Int64s), succ: make(map[int64]set.Int64s),
} }
for i, u := range nodes { for i, u := range nodes {
c.index[u.ID()] = i uid := u.ID()
for _, v := range g.From(u) { c.index[uid] = i
if c.succ[u.ID()] == nil { for _, v := range g.From(uid) {
c.succ[u.ID()] = make(set.Int64s) if c.succ[uid] == nil {
c.nodes.Add(u.ID()) c.succ[uid] = make(set.Int64s)
c.nodes.Add(uid)
} }
c.nodes.Add(v.ID()) c.nodes.Add(v.ID())
c.succ[u.ID()].Add(v.ID()) c.succ[uid].Add(v.ID())
} }
} }
return c return c
@@ -247,31 +248,31 @@ func (g johnsonGraph) Nodes() []graph.Node {
} }
// Successors is required to satisfy Tarjan. // Successors is required to satisfy Tarjan.
func (g johnsonGraph) From(n graph.Node) []graph.Node { func (g johnsonGraph) From(id int64) []graph.Node {
adj := g.succ[n.ID()] adj := g.succ[id]
if len(adj) == 0 { if len(adj) == 0 {
return nil return nil
} }
succ := make([]graph.Node, 0, len(adj)) succ := make([]graph.Node, 0, len(adj))
for n := range adj { for id := range adj {
succ = append(succ, johnsonGraphNode(n)) succ = append(succ, johnsonGraphNode(id))
} }
return succ return succ
} }
func (johnsonGraph) Has(graph.Node) bool { func (johnsonGraph) Has(int64) bool {
panic("topo: unintended use of johnsonGraph") panic("topo: unintended use of johnsonGraph")
} }
func (johnsonGraph) HasEdgeBetween(_, _ graph.Node) bool { func (johnsonGraph) HasEdgeBetween(_, _ int64) bool {
panic("topo: unintended use of johnsonGraph") 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") panic("topo: unintended use of johnsonGraph")
} }
func (johnsonGraph) HasEdgeFromTo(_, _ graph.Node) bool { func (johnsonGraph) HasEdgeFromTo(_, _ int64) bool {
panic("topo: unintended use of johnsonGraph") 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") 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. g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {

View File

@@ -35,7 +35,7 @@ func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
u := tree.Pop() u := tree.Pop()
uid := u.ID() uid := u.ID()
adj := from[uid] adj := from[uid]
for _, v := range g.From(u) { for _, v := range g.From(uid) {
vid := v.ID() vid := v.ID()
switch { switch {
case uid == vid: 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. g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { 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 { func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
nodes := g.Nodes() nodes := g.Nodes()
var succ func(graph.Node) []graph.Node var succ func(id int64) []graph.Node
if order == nil { if order == nil {
succ = g.From succ = g.From
} else { } else {
order(nodes) order(nodes)
ordered.Reverse(nodes) ordered.Reverse(nodes)
succ = func(n graph.Node) []graph.Node { succ = func(id int64) []graph.Node {
to := g.From(n) to := g.From(id)
order(to) order(to)
ordered.Reverse(to) ordered.Reverse(to)
return 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 // http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644
// //
type tarjan struct { type tarjan struct {
succ func(graph.Node) []graph.Node succ func(id int64) []graph.Node
index int index int
indexTable map[int64]int indexTable map[int64]int
@@ -156,7 +156,7 @@ func (t *tarjan) strongconnect(v graph.Node) {
t.onStack.Add(vID) t.onStack.Add(vID)
// Consider successors of v. // Consider successors of v.
for _, w := range t.succ(v) { for _, w := range t.succ(vID) {
wID := w.ID() wID := w.ID()
if t.indexTable[wID] == 0 { if t.indexTable[wID] == 0 {
// Successor w has not yet been visited; recur on it. // Successor w has not yet been visited; recur on it.

View File

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

View File

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

View File

@@ -71,11 +71,11 @@ func TestPathExistsInUndirected(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
if !g.Has(simple.Node(u)) { if !g.Has(int64(u)) {
g.AddNode(simple.Node(u)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
if !g.Has(simple.Node(v)) { if !g.Has(int64(v)) {
g.AddNode(simple.Node(v)) g.AddNode(simple.Node(v))
} }
g.SetEdge(simple.Edge{F: simple.Node(u), T: 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() g := simple.NewDirectedGraph()
for u, e := range test.g { for u, e := range test.g {
if !g.Has(simple.Node(u)) { if !g.Has(int64(u)) {
g.AddNode(simple.Node(u)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
if !g.Has(simple.Node(v)) { if !g.Has(int64(v)) {
g.AddNode(simple.Node(v)) g.AddNode(simple.Node(v))
} }
g.SetEdge(simple.Edge{F: simple.Node(u), T: 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() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
if !g.Has(simple.Node(u)) { if !g.Has(int64(u)) {
g.AddNode(simple.Node(u)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
if !g.Has(simple.Node(v)) { if !g.Has(int64(v)) {
g.AddNode(simple.Node(v)) g.AddNode(simple.Node(v))
} }
g.SetEdge(simple.Edge{F: simple.Node(u), T: 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) { if until != nil && until(t, depth) {
return t return t
} }
for _, n := range g.From(t) { tid := t.ID()
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(t, n)) { for _, n := range g.From(tid) {
nid := n.ID()
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(tid, nid)) {
continue continue
} }
if b.visited.Has(n.ID()) { if b.visited.Has(nid) {
continue continue
} }
if b.Visit != nil { if b.Visit != nil {
b.Visit(t, n) b.Visit(t, n)
} }
b.visited.Add(n.ID()) b.visited.Add(nid)
children++ children++
b.queue.Enqueue(n) 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) { if until != nil && until(t) {
return t return t
} }
for _, n := range g.From(t) { tid := t.ID()
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) { for _, n := range g.From(tid) {
nid := n.ID()
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(tid, nid)) {
continue continue
} }
if d.visited.Has(n.ID()) { if d.visited.Has(nid) {
continue continue
} }
if d.Visit != nil { if d.Visit != nil {
d.Visit(t, n) d.Visit(t, n)
} }
d.visited.Add(n.ID()) d.visited.Add(nid)
d.stack.Push(n) d.stack.Push(n)
} }
} }

View File

@@ -136,7 +136,7 @@ func TestBreadthFirst(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -224,7 +224,7 @@ func TestDepthFirst(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
// Add nodes that are not defined by an edge. // 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)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
@@ -285,11 +285,11 @@ func TestWalkAll(t *testing.T) {
g := simple.NewUndirectedGraph() g := simple.NewUndirectedGraph()
for u, e := range test.g { for u, e := range test.g {
if !g.Has(simple.Node(u)) { if !g.Has(int64(u)) {
g.AddNode(simple.Node(u)) g.AddNode(simple.Node(u))
} }
for v := range e { for v := range e {
if !g.Has(simple.Node(v)) { if !g.Has(int64(v)) {
g.AddNode(simple.Node(v)) g.AddNode(simple.Node(v))
} }
g.SetEdge(simple.Edge{F: simple.Node(u), T: 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{} var _ Undirected = Undirect{}
// Has returns whether the node exists within the graph. // 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. // Nodes returns all the nodes in the graph.
func (g Undirect) Nodes() []Node { return g.G.Nodes() } func (g Undirect) Nodes() []Node { return g.G.Nodes() }
// From returns all nodes in g that can be reached directly from u. // 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 var nodes []Node
seen := make(map[int64]struct{}) seen := make(map[int64]struct{})
for _, n := range g.G.From(u) { for _, n := range g.G.From(uid) {
seen[n.ID()] = struct{}{} seen[n.ID()] = struct{}{}
nodes = append(nodes, n) nodes = append(nodes, n)
} }
for _, n := range g.G.To(u) { for _, n := range g.G.To(uid) {
id := n.ID() id := n.ID()
if _, ok := seen[id]; ok { if _, ok := seen[id]; ok {
continue continue
@@ -37,21 +37,21 @@ func (g Undirect) From(u Node) []Node {
} }
// HasEdgeBetween returns whether an edge exists between nodes x and y. // 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. // 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 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 // 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 // the edge is determined by applying the Merge func to the weights of the
// edges between u and v. // 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 // 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 // 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. // applying the Merge func to the weights of edges between x and y.
func (g Undirect) EdgeBetween(x, y Node) Edge { func (g Undirect) EdgeBetween(xid, yid int64) Edge {
fe := g.G.Edge(x, y) fe := g.G.Edge(xid, yid)
re := g.G.Edge(y, x) re := g.G.Edge(yid, xid)
if fe == nil && re == nil { if fe == nil && re == nil {
return nil return nil
} }
@@ -91,20 +91,20 @@ var (
) )
// Has returns whether the node exists within the graph. // 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. // Nodes returns all the nodes in the graph.
func (g UndirectWeighted) Nodes() []Node { return g.G.Nodes() } func (g UndirectWeighted) Nodes() []Node { return g.G.Nodes() }
// From returns all nodes in g that can be reached directly from u. // 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 var nodes []Node
seen := make(map[int64]struct{}) seen := make(map[int64]struct{})
for _, n := range g.G.From(u) { for _, n := range g.G.From(uid) {
seen[n.ID()] = struct{}{} seen[n.ID()] = struct{}{}
nodes = append(nodes, n) nodes = append(nodes, n)
} }
for _, n := range g.G.To(u) { for _, n := range g.G.To(uid) {
id := n.ID() id := n.ID()
if _, ok := seen[id]; ok { if _, ok := seen[id]; ok {
continue continue
@@ -116,44 +116,46 @@ func (g UndirectWeighted) From(u Node) []Node {
} }
// HasEdgeBetween returns whether an edge exists between nodes x and y. // 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. // 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 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 // 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 // the edge is determined by applying the Merge func to the weights of the
// edges between u and v. // 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. // 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 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 // 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 // the edge is determined by applying the Merge func to the weights of the
// edges between u and v. // 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 // 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 // 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. // applying the Merge func to the weights of edges between x and y.
func (g UndirectWeighted) EdgeBetween(x, y Node) Edge { func (g UndirectWeighted) EdgeBetween(xid, yid int64) Edge {
return g.WeightedEdgeBetween(x, y) return g.WeightedEdgeBetween(xid, yid)
} }
// WeightedEdgeBetween returns the weighted edge between nodes x and y. If an edge exists, the // 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 // 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. // applying the Merge func to the weights of edges between x and y.
func (g UndirectWeighted) WeightedEdgeBetween(x, y Node) WeightedEdge { func (g UndirectWeighted) WeightedEdgeBetween(xid, yid int64) WeightedEdge {
fe := g.G.Edge(x, y) fe := g.G.Edge(xid, yid)
re := g.G.Edge(y, x) re := g.G.Edge(yid, xid)
if fe == nil && re == nil { if fe == nil && re == nil {
return nil return nil
} }
f, ok := g.G.Weight(x, y) f, ok := g.G.Weight(xid, yid)
if !ok { if !ok {
f = g.Absent f = g.Absent
} }
r, ok := g.G.Weight(y, x) r, ok := g.G.Weight(yid, xid)
if !ok { if !ok {
r = g.Absent 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 // 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 // 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. // 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) { func (g UndirectWeighted) Weight(xid, yid int64) (w float64, ok bool) {
fe := g.G.Edge(x, y) fe := g.G.Edge(xid, yid)
re := g.G.Edge(y, x) re := g.G.Edge(yid, xid)
f, fOk := g.G.Weight(x, y) f, fOk := g.G.Weight(xid, yid)
if !fOk { if !fOk {
f = g.Absent f = g.Absent
} }
r, rOK := g.G.Weight(y, x) r, rOK := g.G.Weight(yid, xid)
if !rOK { if !rOK {
r = g.Absent r = g.Absent
} }

View File

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