mirror of
https://github.com/gonum/gonum.git
synced 2025-10-08 16:40:06 +08:00
graph: use int64 for node retrieval
This commit is contained in:
@@ -62,7 +62,7 @@ func init() {
|
||||
friends = simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range middleEast.friends {
|
||||
// Ensure unconnected nodes are included.
|
||||
if !friends.Has(simple.Node(u)) {
|
||||
if !friends.Has(int64(u)) {
|
||||
friends.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -72,7 +72,7 @@ func init() {
|
||||
enemies = simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range middleEast.enemies {
|
||||
// Ensure unconnected nodes are included.
|
||||
if !enemies.Has(simple.Node(u)) {
|
||||
if !enemies.Has(int64(u)) {
|
||||
enemies.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -127,7 +127,7 @@ func TestProfileUndirected(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -144,7 +144,7 @@ func TestProfileWeightedUndirected(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -186,7 +186,7 @@ func TestProfileDirected(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -203,7 +203,7 @@ func TestProfileWeightedDirected(t *testing.T) {
|
||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -111,7 +111,7 @@ func TestKCliqueCommunities(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -359,10 +359,10 @@ const (
|
||||
// positiveWeightFuncFor returns a constructed weight function for the
|
||||
// positively weighted g. Unweighted graphs have unit weight for existing
|
||||
// edges.
|
||||
func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
||||
func positiveWeightFuncFor(g graph.Graph) func(xid, yid int64) float64 {
|
||||
if wg, ok := g.(graph.Weighted); ok {
|
||||
return func(x, y graph.Node) float64 {
|
||||
w, ok := wg.Weight(x, y)
|
||||
return func(xid, yid int64) float64 {
|
||||
w, ok := wg.Weight(xid, yid)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
@@ -372,8 +372,8 @@ func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
||||
return w
|
||||
}
|
||||
}
|
||||
return func(x, y graph.Node) float64 {
|
||||
e := g.Edge(x, y)
|
||||
return func(xid, yid int64) float64 {
|
||||
e := g.Edge(xid, yid)
|
||||
if e == nil {
|
||||
return 0
|
||||
}
|
||||
@@ -384,10 +384,10 @@ func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
||||
// negativeWeightFuncFor returns a constructed weight function for the
|
||||
// negatively weighted g. Unweighted graphs have unit weight for existing
|
||||
// edges.
|
||||
func negativeWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
||||
func negativeWeightFuncFor(g graph.Graph) func(xid, yid int64) float64 {
|
||||
if wg, ok := g.(graph.Weighted); ok {
|
||||
return func(x, y graph.Node) float64 {
|
||||
w, ok := wg.Weight(x, y)
|
||||
return func(xid, yid int64) float64 {
|
||||
w, ok := wg.Weight(xid, yid)
|
||||
if !ok {
|
||||
return 0
|
||||
}
|
||||
@@ -397,8 +397,8 @@ func negativeWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
||||
return -w
|
||||
}
|
||||
}
|
||||
return func(x, y graph.Node) float64 {
|
||||
e := g.Edge(x, y)
|
||||
return func(xid, yid int64) float64 {
|
||||
e := g.Edge(xid, yid)
|
||||
if e == nil {
|
||||
return 0
|
||||
}
|
||||
|
@@ -34,24 +34,28 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
|
||||
for _, n := range nodes {
|
||||
var wOut float64
|
||||
u := n
|
||||
for _, v := range g.From(u) {
|
||||
wOut += weight(u, v)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
wOut += weight(uid, v.ID())
|
||||
}
|
||||
var wIn float64
|
||||
v := n
|
||||
for _, u := range g.To(v) {
|
||||
wIn += weight(u, v)
|
||||
vid := v.ID()
|
||||
for _, u := range g.To(vid) {
|
||||
wIn += weight(u.ID(), vid)
|
||||
}
|
||||
w := weight(n, n)
|
||||
id := n.ID()
|
||||
w := weight(id, id)
|
||||
m += w + wOut // We only need to count edges once.
|
||||
k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
||||
k[id] = directedWeights{out: w + wOut, in: w + wIn}
|
||||
}
|
||||
|
||||
if communities == nil {
|
||||
var q float64
|
||||
for _, u := range nodes {
|
||||
kU := k[u.ID()]
|
||||
q += weight(u, u) - resolution*kU.out*kU.in/m
|
||||
uid := u.ID()
|
||||
kU := k[uid]
|
||||
q += weight(uid, uid) - resolution*kU.out*kU.in/m
|
||||
}
|
||||
return q / m
|
||||
}
|
||||
@@ -59,10 +63,12 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
|
||||
var q float64
|
||||
for _, c := range communities {
|
||||
for _, u := range c {
|
||||
kU := k[u.ID()]
|
||||
uid := u.ID()
|
||||
kU := k[uid]
|
||||
for _, v := range c {
|
||||
kV := k[v.ID()]
|
||||
q += weight(u, v) - resolution*kU.out*kV.in/m
|
||||
vid := v.ID()
|
||||
kV := k[vid]
|
||||
q += weight(uid, vid) - resolution*kU.out*kV.in/m
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,23 +209,27 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
||||
|
||||
var out []int
|
||||
u := n
|
||||
for _, v := range g.From(u) {
|
||||
vid := communityOf[v.ID()]
|
||||
if vid != id {
|
||||
out = append(out, vid)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
vcid := communityOf[vid]
|
||||
if vcid != id {
|
||||
out = append(out, vcid)
|
||||
}
|
||||
r.weights[[2]int{id, vid}] = weight(u, v)
|
||||
r.weights[[2]int{id, vcid}] = weight(uid, vid)
|
||||
}
|
||||
r.edgesFrom[id] = out
|
||||
|
||||
var in []int
|
||||
v := n
|
||||
for _, u := range g.To(v) {
|
||||
uid := communityOf[u.ID()]
|
||||
if uid != id {
|
||||
in = append(in, uid)
|
||||
vid := v.ID()
|
||||
for _, u := range g.To(vid) {
|
||||
uid := u.ID()
|
||||
ucid := communityOf[uid]
|
||||
if ucid != id {
|
||||
in = append(in, ucid)
|
||||
}
|
||||
r.weights[[2]int{uid, id}] = weight(u, v)
|
||||
r.weights[[2]int{ucid, id}] = weight(uid, vid)
|
||||
}
|
||||
r.edgesTo[id] = in
|
||||
}
|
||||
@@ -270,43 +280,47 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
||||
var out, in []int
|
||||
for _, n := range comm {
|
||||
u := n
|
||||
uid := u.ID()
|
||||
for _, v := range comm {
|
||||
r.nodes[id].weight += weight(u, v)
|
||||
r.nodes[id].weight += weight(uid, v.ID())
|
||||
}
|
||||
|
||||
for _, v := range g.From(u) {
|
||||
vid := communityOf[v.ID()]
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
vcid := communityOf[vid]
|
||||
found := false
|
||||
for _, e := range out {
|
||||
if e == vid {
|
||||
if e == vcid {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found && vid != id {
|
||||
out = append(out, vid)
|
||||
if !found && vcid != id {
|
||||
out = append(out, vcid)
|
||||
}
|
||||
// Add half weights because the other
|
||||
// ends of edges are also counted.
|
||||
r.weights[[2]int{id, vid}] += weight(u, v) / 2
|
||||
r.weights[[2]int{id, vcid}] += weight(uid, vid) / 2
|
||||
}
|
||||
|
||||
v := n
|
||||
for _, u := range g.To(v) {
|
||||
uid := communityOf[u.ID()]
|
||||
vid := v.ID()
|
||||
for _, u := range g.To(vid) {
|
||||
uid := u.ID()
|
||||
ucid := communityOf[uid]
|
||||
found := false
|
||||
for _, e := range in {
|
||||
if e == uid {
|
||||
if e == ucid {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found && uid != id {
|
||||
in = append(in, uid)
|
||||
if !found && ucid != id {
|
||||
in = append(in, ucid)
|
||||
}
|
||||
// Add half weights because the other
|
||||
// ends of edges are also counted.
|
||||
r.weights[[2]int{uid, id}] += weight(u, v) / 2
|
||||
r.weights[[2]int{ucid, id}] += weight(uid, vid) / 2
|
||||
}
|
||||
}
|
||||
r.edgesFrom[id] = out
|
||||
@@ -316,8 +330,7 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *ReducedDirected) Has(n graph.Node) bool {
|
||||
id := n.ID()
|
||||
func (g *ReducedDirected) Has(id int64) bool {
|
||||
return 0 <= id && id < int64(len(g.nodes))
|
||||
}
|
||||
|
||||
@@ -331,8 +344,8 @@ func (g *ReducedDirected) Nodes() []graph.Node {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g *ReducedDirected) From(u graph.Node) []graph.Node {
|
||||
out := g.edgesFrom[u.ID()]
|
||||
func (g *ReducedDirected) From(uid int64) []graph.Node {
|
||||
out := g.edgesFrom[uid]
|
||||
nodes := make([]graph.Node, len(out))
|
||||
for i, vid := range out {
|
||||
nodes[i] = g.nodes[vid]
|
||||
@@ -341,8 +354,8 @@ func (g *ReducedDirected) From(u graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to v.
|
||||
func (g *ReducedDirected) To(v graph.Node) []graph.Node {
|
||||
in := g.edgesTo[v.ID()]
|
||||
func (g *ReducedDirected) To(vid int64) []graph.Node {
|
||||
in := g.edgesTo[vid]
|
||||
nodes := make([]graph.Node, len(in))
|
||||
for i, uid := range in {
|
||||
nodes[i] = g.nodes[uid]
|
||||
@@ -351,9 +364,7 @@ func (g *ReducedDirected) To(v graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g *ReducedDirected) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *ReducedDirected) HasEdgeBetween(xid, yid int64) bool {
|
||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||
return false
|
||||
}
|
||||
@@ -366,9 +377,7 @@ func (g *ReducedDirected) HasEdgeBetween(x, y graph.Node) bool {
|
||||
}
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists from node u to v.
|
||||
func (g *ReducedDirected) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
uid := u.ID()
|
||||
vid := v.ID()
|
||||
func (g *ReducedDirected) HasEdgeFromTo(uid, vid int64) bool {
|
||||
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
||||
return false
|
||||
}
|
||||
@@ -378,15 +387,13 @@ func (g *ReducedDirected) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *ReducedDirected) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdge(u, v)
|
||||
func (g *ReducedDirected) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdge(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *ReducedDirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
uid := u.ID()
|
||||
vid := v.ID()
|
||||
func (g *ReducedDirected) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
||||
return nil
|
||||
}
|
||||
@@ -401,9 +408,7 @@ func (g *ReducedDirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g *ReducedDirected) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *ReducedDirected) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if !isValidID(xid) || !isValidID(yid) {
|
||||
return 0, false
|
||||
}
|
||||
@@ -433,7 +438,7 @@ type directedLocalMover struct {
|
||||
// that returns the Weight value
|
||||
// of the non-nil edge between x
|
||||
// and y.
|
||||
weight func(x, y graph.Node) float64
|
||||
weight func(xid, yid int64) float64
|
||||
|
||||
// communities is the current
|
||||
// division of g.
|
||||
@@ -484,18 +489,21 @@ func newDirectedLocalMover(g *ReducedDirected, communities [][]graph.Node, resol
|
||||
for _, n := range l.nodes {
|
||||
u := n
|
||||
var wOut float64
|
||||
for _, v := range g.From(u) {
|
||||
wOut += l.weight(u, v)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
wOut += l.weight(uid, v.ID())
|
||||
}
|
||||
|
||||
v := n
|
||||
var wIn float64
|
||||
for _, u := range g.To(v) {
|
||||
wIn += l.weight(u, v)
|
||||
vid := v.ID()
|
||||
for _, u := range g.To(vid) {
|
||||
wIn += l.weight(u.ID(), vid)
|
||||
}
|
||||
|
||||
w := l.weight(n, n)
|
||||
l.edgeWeightsOf[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
||||
id := n.ID()
|
||||
w := l.weight(id, id)
|
||||
l.edgeWeightsOf[id] = directedWeights{out: w + wOut, in: w + wIn}
|
||||
l.m += w + wOut
|
||||
}
|
||||
|
||||
@@ -562,7 +570,7 @@ func (l *directedLocalMover) move(dst int, src commIdx) {
|
||||
func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
|
||||
id := n.ID()
|
||||
|
||||
a_aa := l.weight(n, n)
|
||||
a_aa := l.weight(id, id)
|
||||
k_a := l.edgeWeightsOf[id]
|
||||
m := l.m
|
||||
gamma := l.resolution
|
||||
@@ -613,8 +621,8 @@ func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src
|
||||
removal = true
|
||||
}
|
||||
|
||||
k_aC.in += l.weight(u, n)
|
||||
k_aC.out += l.weight(n, u)
|
||||
k_aC.in += l.weight(uid, id)
|
||||
k_aC.out += l.weight(id, uid)
|
||||
// sigma_totC could be kept for each community
|
||||
// and updated for moves, changing the calculation
|
||||
// of sigma_totC here from O(n_c) to O(1), but
|
||||
|
@@ -63,7 +63,7 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
||||
layerResolution = resolutions[l]
|
||||
}
|
||||
|
||||
var weight func(x, y graph.Node) float64
|
||||
var weight func(xid, yid int64) float64
|
||||
if layerWeight < 0 {
|
||||
weight = negativeWeightFuncFor(layer)
|
||||
} else {
|
||||
@@ -77,15 +77,18 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
||||
for _, n := range nodes {
|
||||
var wOut float64
|
||||
u := n
|
||||
for _, v := range layer.From(u) {
|
||||
wOut += weight(u, v)
|
||||
uid := u.ID()
|
||||
for _, v := range layer.From(uid) {
|
||||
wOut += weight(uid, v.ID())
|
||||
}
|
||||
var wIn float64
|
||||
v := n
|
||||
for _, u := range layer.To(v) {
|
||||
wIn += weight(u, v)
|
||||
vid := v.ID()
|
||||
for _, u := range layer.To(vid) {
|
||||
wIn += weight(u.ID(), vid)
|
||||
}
|
||||
w := weight(n, n)
|
||||
id := n.ID()
|
||||
w := weight(id, id)
|
||||
m += w + wOut // We only need to count edges once.
|
||||
k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
||||
}
|
||||
@@ -93,8 +96,9 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
||||
if communities == nil {
|
||||
var qLayer float64
|
||||
for _, u := range nodes {
|
||||
kU := k[u.ID()]
|
||||
qLayer += weight(u, u) - layerResolution*kU.out*kU.in/m
|
||||
uid := u.ID()
|
||||
kU := k[uid]
|
||||
qLayer += weight(uid, uid) - layerResolution*kU.out*kU.in/m
|
||||
}
|
||||
q[l] = layerWeight * qLayer
|
||||
continue
|
||||
@@ -103,10 +107,12 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
||||
var qLayer float64
|
||||
for _, c := range communities {
|
||||
for _, u := range c {
|
||||
kU := k[u.ID()]
|
||||
uid := u.ID()
|
||||
kU := k[uid]
|
||||
for _, v := range c {
|
||||
kV := k[v.ID()]
|
||||
qLayer += weight(u, v) - layerResolution*kU.out*kV.in/m
|
||||
vid := v.ID()
|
||||
kV := k[vid]
|
||||
qLayer += weight(uid, vid) - layerResolution*kU.out*kV.in/m
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,7 +327,7 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
continue
|
||||
}
|
||||
var sign float64
|
||||
var weight func(x, y graph.Node) float64
|
||||
var weight func(xid, yid int64) float64
|
||||
if w < 0 {
|
||||
sign, weight = -1, negativeWeightFuncFor(layer)
|
||||
} else {
|
||||
@@ -332,23 +338,27 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
|
||||
var out []int
|
||||
u := n
|
||||
for _, v := range layer.From(u) {
|
||||
vid := communityOf[v.ID()]
|
||||
if vid != id {
|
||||
out = append(out, vid)
|
||||
uid := u.ID()
|
||||
for _, v := range layer.From(uid) {
|
||||
vid := v.ID()
|
||||
vcid := communityOf[vid]
|
||||
if vcid != id {
|
||||
out = append(out, vcid)
|
||||
}
|
||||
r.layers[l].weights[[2]int{id, vid}] = sign * weight(u, v)
|
||||
r.layers[l].weights[[2]int{id, vcid}] = sign * weight(uid, vid)
|
||||
}
|
||||
r.layers[l].edgesFrom[id] = out
|
||||
|
||||
var in []int
|
||||
v := n
|
||||
for _, u := range layer.To(v) {
|
||||
uid := communityOf[u.ID()]
|
||||
if uid != id {
|
||||
in = append(in, uid)
|
||||
vid := v.ID()
|
||||
for _, u := range layer.To(vid) {
|
||||
uid := u.ID()
|
||||
ucid := communityOf[uid]
|
||||
if ucid != id {
|
||||
in = append(in, ucid)
|
||||
}
|
||||
r.layers[l].weights[[2]int{uid, id}] = sign * weight(u, v)
|
||||
r.layers[l].weights[[2]int{ucid, id}] = sign * weight(uid, vid)
|
||||
}
|
||||
r.layers[l].edgesTo[id] = in
|
||||
}
|
||||
@@ -408,7 +418,7 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
continue
|
||||
}
|
||||
var sign float64
|
||||
var weight func(x, y graph.Node) float64
|
||||
var weight func(xid, yid int64) float64
|
||||
if w < 0 {
|
||||
sign, weight = -1, negativeWeightFuncFor(layer)
|
||||
} else {
|
||||
@@ -418,43 +428,47 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
||||
var out, in []int
|
||||
for _, n := range comm {
|
||||
u := n
|
||||
uid := u.ID()
|
||||
for _, v := range comm {
|
||||
r.nodes[id].weights[l] += sign * weight(u, v)
|
||||
r.nodes[id].weights[l] += sign * weight(uid, v.ID())
|
||||
}
|
||||
|
||||
for _, v := range layer.From(u) {
|
||||
vid := communityOf[v.ID()]
|
||||
for _, v := range layer.From(uid) {
|
||||
vid := v.ID()
|
||||
vcid := communityOf[vid]
|
||||
found := false
|
||||
for _, e := range out {
|
||||
if e == vid {
|
||||
if e == vcid {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found && vid != id {
|
||||
out = append(out, vid)
|
||||
if !found && vcid != id {
|
||||
out = append(out, vcid)
|
||||
}
|
||||
// Add half weights because the other
|
||||
// ends of edges are also counted.
|
||||
r.layers[l].weights[[2]int{id, vid}] += sign * weight(u, v) / 2
|
||||
r.layers[l].weights[[2]int{id, vcid}] += sign * weight(uid, vid) / 2
|
||||
}
|
||||
|
||||
v := n
|
||||
for _, u := range layer.To(v) {
|
||||
uid := communityOf[u.ID()]
|
||||
vid := v.ID()
|
||||
for _, u := range layer.To(vid) {
|
||||
uid := u.ID()
|
||||
ucid := communityOf[uid]
|
||||
found := false
|
||||
for _, e := range in {
|
||||
if e == uid {
|
||||
if e == ucid {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found && uid != id {
|
||||
in = append(in, uid)
|
||||
if !found && ucid != id {
|
||||
in = append(in, ucid)
|
||||
}
|
||||
// Add half weights because the other
|
||||
// ends of edges are also counted.
|
||||
r.layers[l].weights[[2]int{uid, id}] += sign * weight(u, v) / 2
|
||||
r.layers[l].weights[[2]int{ucid, id}] += sign * weight(uid, vid) / 2
|
||||
}
|
||||
|
||||
}
|
||||
@@ -478,8 +492,7 @@ type directedLayerHandle struct {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g directedLayerHandle) Has(n graph.Node) bool {
|
||||
id := n.ID()
|
||||
func (g directedLayerHandle) Has(id int64) bool {
|
||||
return 0 <= id && id < int64(len(g.multiplex.nodes))
|
||||
}
|
||||
|
||||
@@ -493,8 +506,8 @@ func (g directedLayerHandle) Nodes() []graph.Node {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g directedLayerHandle) From(u graph.Node) []graph.Node {
|
||||
out := g.multiplex.layers[g.layer].edgesFrom[u.ID()]
|
||||
func (g directedLayerHandle) From(uid int64) []graph.Node {
|
||||
out := g.multiplex.layers[g.layer].edgesFrom[uid]
|
||||
nodes := make([]graph.Node, len(out))
|
||||
for i, vid := range out {
|
||||
nodes[i] = g.multiplex.nodes[vid]
|
||||
@@ -503,8 +516,8 @@ func (g directedLayerHandle) From(u graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to v.
|
||||
func (g directedLayerHandle) To(v graph.Node) []graph.Node {
|
||||
in := g.multiplex.layers[g.layer].edgesTo[v.ID()]
|
||||
func (g directedLayerHandle) To(vid int64) []graph.Node {
|
||||
in := g.multiplex.layers[g.layer].edgesTo[vid]
|
||||
nodes := make([]graph.Node, len(in))
|
||||
for i, uid := range in {
|
||||
nodes[i] = g.multiplex.nodes[uid]
|
||||
@@ -513,9 +526,7 @@ func (g directedLayerHandle) To(v graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g directedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g directedLayerHandle) HasEdgeBetween(xid, yid int64) bool {
|
||||
if xid == yid {
|
||||
return false
|
||||
}
|
||||
@@ -531,9 +542,7 @@ func (g directedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
|
||||
}
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists from node u to v.
|
||||
func (g directedLayerHandle) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
uid := u.ID()
|
||||
vid := v.ID()
|
||||
func (g directedLayerHandle) HasEdgeFromTo(uid, vid int64) bool {
|
||||
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
||||
return false
|
||||
}
|
||||
@@ -543,15 +552,13 @@ func (g directedLayerHandle) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g directedLayerHandle) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdge(u, v)
|
||||
func (g directedLayerHandle) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdge(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g directedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
uid := u.ID()
|
||||
vid := v.ID()
|
||||
func (g directedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
||||
return nil
|
||||
}
|
||||
@@ -559,16 +566,14 @@ func (g directedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return multiplexEdge{from: g.multiplex.nodes[u.ID()], to: g.multiplex.nodes[v.ID()], weight: w}
|
||||
return multiplexEdge{from: g.multiplex.nodes[uid], to: g.multiplex.nodes[vid], weight: w}
|
||||
}
|
||||
|
||||
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g directedLayerHandle) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g directedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if !isValidID(xid) || !isValidID(yid) {
|
||||
return 0, false
|
||||
}
|
||||
@@ -598,7 +603,7 @@ type directedMultiplexLocalMover struct {
|
||||
// that returns the Weight value
|
||||
// of the non-nil edge between x
|
||||
// and y.
|
||||
weight []func(x, y graph.Node) float64
|
||||
weight []func(xid, yid int64) float64
|
||||
|
||||
// communities is the current
|
||||
// division of g.
|
||||
@@ -648,7 +653,7 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
|
||||
memberships: make([]int, len(nodes)),
|
||||
resolutions: resolutions,
|
||||
weights: weights,
|
||||
weight: make([]func(x, y graph.Node) float64, g.Depth()),
|
||||
weight: make([]func(xid, yid int64) float64, g.Depth()),
|
||||
}
|
||||
|
||||
// Calculate the total edge weight of the graph
|
||||
@@ -656,7 +661,7 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
|
||||
var zero int
|
||||
for i := 0; i < g.Depth(); i++ {
|
||||
l.edgeWeightsOf[i] = make([]directedWeights, len(nodes))
|
||||
var weight func(x, y graph.Node) float64
|
||||
var weight func(xid, yid int64) float64
|
||||
|
||||
if weights != nil {
|
||||
if weights[i] == 0 {
|
||||
@@ -677,19 +682,22 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
|
||||
layer := g.Layer(i)
|
||||
for _, n := range l.nodes {
|
||||
u := n
|
||||
uid := u.ID()
|
||||
var wOut float64
|
||||
for _, v := range layer.From(u) {
|
||||
wOut += weight(u, v)
|
||||
for _, v := range layer.From(uid) {
|
||||
wOut += weight(uid, v.ID())
|
||||
}
|
||||
|
||||
v := n
|
||||
vid := v.ID()
|
||||
var wIn float64
|
||||
for _, u := range layer.To(v) {
|
||||
wIn += weight(u, v)
|
||||
for _, u := range layer.To(vid) {
|
||||
wIn += weight(u.ID(), vid)
|
||||
}
|
||||
|
||||
w := weight(n, n)
|
||||
l.edgeWeightsOf[i][u.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
||||
id := n.ID()
|
||||
w := weight(id, id)
|
||||
l.edgeWeightsOf[i][uid] = directedWeights{out: w + wOut, in: w + wIn}
|
||||
l.m[i] += w + wOut
|
||||
}
|
||||
if l.m[i] == 0 {
|
||||
@@ -836,8 +844,8 @@ func (l *directedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst
|
||||
removal = true
|
||||
}
|
||||
|
||||
k_aC.in += l.weight[layer](n, u)
|
||||
k_aC.out += l.weight[layer](u, n)
|
||||
k_aC.in += l.weight[layer](id, uid)
|
||||
k_aC.out += l.weight[layer](uid, id)
|
||||
// sigma_totC could be kept for each community
|
||||
// and updated for moves, changing the calculation
|
||||
// of sigma_totC here from O(n_c) to O(1), but
|
||||
@@ -849,7 +857,7 @@ func (l *directedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst
|
||||
sigma_totC.out += w.out
|
||||
}
|
||||
|
||||
a_aa := l.weight[layer](n, n)
|
||||
a_aa := l.weight[layer](id, id)
|
||||
k_a := l.edgeWeightsOf[layer][id]
|
||||
gamma := 1.0
|
||||
if l.resolutions != nil {
|
||||
|
@@ -390,7 +390,7 @@ tests:
|
||||
}
|
||||
layer := g.Layer(l)
|
||||
for n := range c {
|
||||
if layer.HasEdgeBetween(simple.Node(n), target) {
|
||||
if layer.HasEdgeBetween(int64(n), target.ID()) {
|
||||
connected = true
|
||||
break search
|
||||
}
|
||||
@@ -701,7 +701,7 @@ func directedMultiplexFrom(raw []layer) (DirectedLayers, []float64, error) {
|
||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||
for u, e := range l.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -204,7 +204,7 @@ func TestCommunityQDirected(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -221,7 +221,7 @@ func TestCommunityQWeightedDirected(t *testing.T) {
|
||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -257,7 +257,7 @@ func TestCommunityDeltaQDirected(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -274,7 +274,7 @@ func TestCommunityDeltaQWeightedDirected(t *testing.T) {
|
||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -338,7 +338,7 @@ func testCommunityDeltaQDirected(t *testing.T, test communityDirectedQTest, g gr
|
||||
}
|
||||
connected := false
|
||||
for n := range c {
|
||||
if g.HasEdgeBetween(simple.Node(n), target) {
|
||||
if g.HasEdgeBetween(int64(n), target.ID()) {
|
||||
connected = true
|
||||
break
|
||||
}
|
||||
@@ -382,7 +382,7 @@ func TestReduceQConsistencyDirected(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -399,7 +399,7 @@ func TestReduceQConsistencyWeightedDirected(t *testing.T) {
|
||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -500,7 +500,7 @@ func TestMoveLocalDirected(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -517,7 +517,7 @@ func TestMoveLocalWeightedDirected(t *testing.T) {
|
||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -562,7 +562,7 @@ func TestModularizeDirected(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -579,7 +579,7 @@ func TestModularizeWeightedDirected(t *testing.T) {
|
||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -34,19 +34,21 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
|
||||
var m2 float64
|
||||
k := make(map[int64]float64, len(nodes))
|
||||
for _, u := range nodes {
|
||||
w := weight(u, u)
|
||||
for _, v := range g.From(u) {
|
||||
w += weight(u, v)
|
||||
uid := u.ID()
|
||||
w := weight(uid, uid)
|
||||
for _, v := range g.From(uid) {
|
||||
w += weight(uid, v.ID())
|
||||
}
|
||||
m2 += w
|
||||
k[u.ID()] = w
|
||||
k[uid] = w
|
||||
}
|
||||
|
||||
if communities == nil {
|
||||
var q float64
|
||||
for _, u := range nodes {
|
||||
kU := k[u.ID()]
|
||||
q += weight(u, u) - resolution*kU*kU/m2
|
||||
uid := u.ID()
|
||||
kU := k[uid]
|
||||
q += weight(uid, uid) - resolution*kU*kU/m2
|
||||
}
|
||||
return q / m2
|
||||
}
|
||||
@@ -57,10 +59,12 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
|
||||
var q float64
|
||||
for _, c := range communities {
|
||||
for i, u := range c {
|
||||
kU := k[u.ID()]
|
||||
q += weight(u, u) - resolution*kU*kU/m2
|
||||
uid := u.ID()
|
||||
kU := k[uid]
|
||||
q += weight(uid, uid) - resolution*kU*kU/m2
|
||||
for _, v := range c[i+1:] {
|
||||
q += 2 * (weight(u, v) - resolution*kU*k[v.ID()]/m2)
|
||||
vid := v.ID()
|
||||
q += 2 * (weight(uid, vid) - resolution*kU*k[vid]/m2)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,19 +202,21 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
|
||||
communityOf[n.ID()] = i
|
||||
}
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
ucid := communityOf[uid]
|
||||
var out []int
|
||||
uid := communityOf[u.ID()]
|
||||
for _, v := range g.From(u) {
|
||||
vid := communityOf[v.ID()]
|
||||
if vid != uid {
|
||||
out = append(out, vid)
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
vcid := communityOf[vid]
|
||||
if vcid != ucid {
|
||||
out = append(out, vcid)
|
||||
}
|
||||
if uid < vid {
|
||||
if ucid < vcid {
|
||||
// Only store the weight once.
|
||||
r.weights[[2]int{uid, vid}] = weight(u, v)
|
||||
r.weights[[2]int{ucid, vcid}] = weight(uid, vid)
|
||||
}
|
||||
}
|
||||
r.edges[uid] = out
|
||||
r.edges[ucid] = out
|
||||
}
|
||||
return &r
|
||||
}
|
||||
@@ -254,39 +260,40 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
|
||||
communityOf[n.ID()] = i
|
||||
}
|
||||
}
|
||||
for uid, comm := range communities {
|
||||
for ucid, comm := range communities {
|
||||
var out []int
|
||||
for i, u := range comm {
|
||||
r.nodes[uid].weight += weight(u, u)
|
||||
uid := u.ID()
|
||||
r.nodes[ucid].weight += weight(uid, uid)
|
||||
for _, v := range comm[i+1:] {
|
||||
r.nodes[uid].weight += 2 * weight(u, v)
|
||||
r.nodes[ucid].weight += 2 * weight(uid, v.ID())
|
||||
}
|
||||
for _, v := range g.From(u) {
|
||||
vid := communityOf[v.ID()]
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
vcid := communityOf[vid]
|
||||
found := false
|
||||
for _, e := range out {
|
||||
if e == vid {
|
||||
if e == vcid {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found && vid != uid {
|
||||
out = append(out, vid)
|
||||
if !found && vcid != ucid {
|
||||
out = append(out, vcid)
|
||||
}
|
||||
if uid < vid {
|
||||
if ucid < vcid {
|
||||
// Only store the weight once.
|
||||
r.weights[[2]int{uid, vid}] += weight(u, v)
|
||||
r.weights[[2]int{ucid, vcid}] += weight(uid, vid)
|
||||
}
|
||||
}
|
||||
}
|
||||
r.edges[uid] = out
|
||||
r.edges[ucid] = out
|
||||
}
|
||||
return &r
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *ReducedUndirected) Has(n graph.Node) bool {
|
||||
id := n.ID()
|
||||
func (g *ReducedUndirected) Has(id int64) bool {
|
||||
return 0 <= id || id < int64(len(g.nodes))
|
||||
}
|
||||
|
||||
@@ -300,8 +307,8 @@ func (g *ReducedUndirected) Nodes() []graph.Node {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g *ReducedUndirected) From(u graph.Node) []graph.Node {
|
||||
out := g.edges[u.ID()]
|
||||
func (g *ReducedUndirected) From(uid int64) []graph.Node {
|
||||
out := g.edges[uid]
|
||||
nodes := make([]graph.Node, len(out))
|
||||
for i, vid := range out {
|
||||
nodes[i] = g.nodes[vid]
|
||||
@@ -310,9 +317,7 @@ func (g *ReducedUndirected) From(u graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g *ReducedUndirected) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *ReducedUndirected) HasEdgeBetween(xid, yid int64) bool {
|
||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||
return false
|
||||
}
|
||||
@@ -325,25 +330,23 @@ func (g *ReducedUndirected) HasEdgeBetween(x, y graph.Node) bool {
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *ReducedUndirected) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *ReducedUndirected) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *ReducedUndirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *ReducedUndirected) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
func (g *ReducedUndirected) EdgeBetween(x, y graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(x, y)
|
||||
func (g *ReducedUndirected) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(xid, yid)
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||
func (g *ReducedUndirected) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *ReducedUndirected) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
|
||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||
return nil
|
||||
}
|
||||
@@ -354,16 +357,14 @@ func (g *ReducedUndirected) WeightedEdgeBetween(x, y graph.Node) graph.WeightedE
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return edge{from: g.nodes[x.ID()], to: g.nodes[y.ID()], weight: w}
|
||||
return edge{from: g.nodes[xid], to: g.nodes[yid], weight: w}
|
||||
}
|
||||
|
||||
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g *ReducedUndirected) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *ReducedUndirected) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if !isValidID(xid) || !isValidID(yid) {
|
||||
return 0, false
|
||||
}
|
||||
@@ -396,7 +397,7 @@ type undirectedLocalMover struct {
|
||||
// that returns the Weight value
|
||||
// of the non-nil edge between x
|
||||
// and y.
|
||||
weight func(x, y graph.Node) float64
|
||||
weight func(xid, yid int64) float64
|
||||
|
||||
// communities is the current
|
||||
// division of g.
|
||||
@@ -440,11 +441,12 @@ func newUndirectedLocalMover(g *ReducedUndirected, communities [][]graph.Node, r
|
||||
// Calculate the total edge weight of the graph
|
||||
// and degree weights for each node.
|
||||
for _, u := range l.nodes {
|
||||
w := l.weight(u, u)
|
||||
for _, v := range g.From(u) {
|
||||
w += l.weight(u, v)
|
||||
uid := u.ID()
|
||||
w := l.weight(uid, uid)
|
||||
for _, v := range g.From(uid) {
|
||||
w += l.weight(uid, v.ID())
|
||||
}
|
||||
l.edgeWeightOf[u.ID()] = w
|
||||
l.edgeWeightOf[uid] = w
|
||||
l.m2 += w
|
||||
}
|
||||
if l.m2 == 0 {
|
||||
@@ -514,7 +516,7 @@ func (l *undirectedLocalMover) move(dst int, src commIdx) {
|
||||
// is in communities.
|
||||
func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
|
||||
id := n.ID()
|
||||
a_aa := l.weight(n, n)
|
||||
a_aa := l.weight(id, id)
|
||||
k_a := l.edgeWeightOf[id]
|
||||
m2 := l.m2
|
||||
gamma := l.resolution
|
||||
@@ -559,7 +561,7 @@ func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, sr
|
||||
removal = true
|
||||
}
|
||||
|
||||
k_aC += l.weight(n, u)
|
||||
k_aC += l.weight(id, uid)
|
||||
// sigma_totC could be kept for each community
|
||||
// and updated for moves, changing the calculation
|
||||
// of sigma_totC here from O(n_c) to O(1), but
|
||||
|
@@ -66,7 +66,7 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
|
||||
layerResolution = resolutions[l]
|
||||
}
|
||||
|
||||
var weight func(x, y graph.Node) float64
|
||||
var weight func(xid, yid int64) float64
|
||||
if layerWeight < 0 {
|
||||
weight = negativeWeightFuncFor(layer)
|
||||
} else {
|
||||
@@ -78,19 +78,21 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
|
||||
var m2 float64
|
||||
k := make(map[int64]float64, len(nodes))
|
||||
for _, u := range nodes {
|
||||
w := weight(u, u)
|
||||
for _, v := range layer.From(u) {
|
||||
w += weight(u, v)
|
||||
uid := u.ID()
|
||||
w := weight(uid, uid)
|
||||
for _, v := range layer.From(uid) {
|
||||
w += weight(uid, v.ID())
|
||||
}
|
||||
m2 += w
|
||||
k[u.ID()] = w
|
||||
k[uid] = w
|
||||
}
|
||||
|
||||
if communities == nil {
|
||||
var qLayer float64
|
||||
for _, u := range nodes {
|
||||
kU := k[u.ID()]
|
||||
qLayer += weight(u, u) - layerResolution*kU*kU/m2
|
||||
uid := u.ID()
|
||||
kU := k[uid]
|
||||
qLayer += weight(uid, uid) - layerResolution*kU*kU/m2
|
||||
}
|
||||
q[l] = layerWeight * qLayer
|
||||
continue
|
||||
@@ -102,10 +104,12 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
|
||||
var qLayer float64
|
||||
for _, c := range communities {
|
||||
for i, u := range c {
|
||||
kU := k[u.ID()]
|
||||
qLayer += weight(u, u) - layerResolution*kU*kU/m2
|
||||
uid := u.ID()
|
||||
kU := k[uid]
|
||||
qLayer += weight(uid, uid) - layerResolution*kU*kU/m2
|
||||
for _, v := range c[i+1:] {
|
||||
qLayer += 2 * (weight(u, v) - layerResolution*kU*k[v.ID()]/m2)
|
||||
vid := v.ID()
|
||||
qLayer += 2 * (weight(uid, vid) - layerResolution*kU*k[vid]/m2)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -319,7 +323,7 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
||||
continue
|
||||
}
|
||||
var sign float64
|
||||
var weight func(x, y graph.Node) float64
|
||||
var weight func(xid, yid int64) float64
|
||||
if w < 0 {
|
||||
sign, weight = -1, negativeWeightFuncFor(layer)
|
||||
} else {
|
||||
@@ -327,18 +331,20 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
||||
}
|
||||
for _, u := range nodes {
|
||||
var out []int
|
||||
uid := communityOf[u.ID()]
|
||||
for _, v := range layer.From(u) {
|
||||
vid := communityOf[v.ID()]
|
||||
if vid != uid {
|
||||
out = append(out, vid)
|
||||
uid := u.ID()
|
||||
ucid := communityOf[uid]
|
||||
for _, v := range layer.From(uid) {
|
||||
vid := v.ID()
|
||||
vcid := communityOf[vid]
|
||||
if vcid != ucid {
|
||||
out = append(out, vcid)
|
||||
}
|
||||
if uid < vid {
|
||||
if ucid < vcid {
|
||||
// Only store the weight once.
|
||||
r.layers[l].weights[[2]int{uid, vid}] = sign * weight(u, v)
|
||||
r.layers[l].weights[[2]int{ucid, vcid}] = sign * weight(uid, vid)
|
||||
}
|
||||
}
|
||||
r.layers[l].edges[uid] = out
|
||||
r.layers[l].edges[ucid] = out
|
||||
}
|
||||
}
|
||||
return &r
|
||||
@@ -395,38 +401,40 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
||||
continue
|
||||
}
|
||||
var sign float64
|
||||
var weight func(x, y graph.Node) float64
|
||||
var weight func(xid, yid int64) float64
|
||||
if w < 0 {
|
||||
sign, weight = -1, negativeWeightFuncFor(layer)
|
||||
} else {
|
||||
sign, weight = 1, positiveWeightFuncFor(layer)
|
||||
}
|
||||
for uid, comm := range communities {
|
||||
for ucid, comm := range communities {
|
||||
var out []int
|
||||
for i, u := range comm {
|
||||
r.nodes[uid].weights[l] += sign * weight(u, u)
|
||||
uid := u.ID()
|
||||
r.nodes[ucid].weights[l] += sign * weight(uid, uid)
|
||||
for _, v := range comm[i+1:] {
|
||||
r.nodes[uid].weights[l] += 2 * sign * weight(u, v)
|
||||
r.nodes[ucid].weights[l] += 2 * sign * weight(uid, v.ID())
|
||||
}
|
||||
for _, v := range layer.From(u) {
|
||||
vid := communityOf[v.ID()]
|
||||
for _, v := range layer.From(uid) {
|
||||
vid := v.ID()
|
||||
vcid := communityOf[vid]
|
||||
found := false
|
||||
for _, e := range out {
|
||||
if e == vid {
|
||||
if e == vcid {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found && vid != uid {
|
||||
out = append(out, vid)
|
||||
if !found && vcid != ucid {
|
||||
out = append(out, vcid)
|
||||
}
|
||||
if uid < vid {
|
||||
if ucid < vcid {
|
||||
// Only store the weight once.
|
||||
r.layers[l].weights[[2]int{uid, vid}] += sign * weight(u, v)
|
||||
r.layers[l].weights[[2]int{ucid, vcid}] += sign * weight(uid, vid)
|
||||
}
|
||||
}
|
||||
}
|
||||
r.layers[l].edges[uid] = out
|
||||
r.layers[l].edges[ucid] = out
|
||||
}
|
||||
}
|
||||
return &r
|
||||
@@ -445,8 +453,7 @@ type undirectedLayerHandle struct {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g undirectedLayerHandle) Has(n graph.Node) bool {
|
||||
id := n.ID()
|
||||
func (g undirectedLayerHandle) Has(id int64) bool {
|
||||
return 0 <= id && id < int64(len(g.multiplex.nodes))
|
||||
}
|
||||
|
||||
@@ -460,8 +467,8 @@ func (g undirectedLayerHandle) Nodes() []graph.Node {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g undirectedLayerHandle) From(u graph.Node) []graph.Node {
|
||||
out := g.multiplex.layers[g.layer].edges[u.ID()]
|
||||
func (g undirectedLayerHandle) From(uid int64) []graph.Node {
|
||||
out := g.multiplex.layers[g.layer].edges[uid]
|
||||
nodes := make([]graph.Node, len(out))
|
||||
for i, vid := range out {
|
||||
nodes[i] = g.multiplex.nodes[vid]
|
||||
@@ -470,9 +477,7 @@ func (g undirectedLayerHandle) From(u graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g undirectedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g undirectedLayerHandle) HasEdgeBetween(xid, yid int64) bool {
|
||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||
return false
|
||||
}
|
||||
@@ -485,25 +490,23 @@ func (g undirectedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g undirectedLayerHandle) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g undirectedLayerHandle) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g undirectedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g undirectedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
func (g undirectedLayerHandle) EdgeBetween(x, y graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(x, y)
|
||||
func (g undirectedLayerHandle) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(xid, yid)
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||
func (g undirectedLayerHandle) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g undirectedLayerHandle) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
|
||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||
return nil
|
||||
}
|
||||
@@ -514,16 +517,14 @@ func (g undirectedLayerHandle) WeightedEdgeBetween(x, y graph.Node) graph.Weight
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return multiplexEdge{from: g.multiplex.nodes[x.ID()], to: g.multiplex.nodes[y.ID()], weight: w}
|
||||
return multiplexEdge{from: g.multiplex.nodes[xid], to: g.multiplex.nodes[yid], weight: w}
|
||||
}
|
||||
|
||||
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g undirectedLayerHandle) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g undirectedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if !isValidID(xid) || !isValidID(yid) {
|
||||
return 0, false
|
||||
}
|
||||
@@ -556,7 +557,7 @@ type undirectedMultiplexLocalMover struct {
|
||||
// that returns the Weight value
|
||||
// of the non-nil edge between x
|
||||
// and y.
|
||||
weight []func(x, y graph.Node) float64
|
||||
weight []func(xid, yid int64) float64
|
||||
|
||||
// communities is the current
|
||||
// division of g.
|
||||
@@ -606,7 +607,7 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
|
||||
memberships: make([]int, len(nodes)),
|
||||
resolutions: resolutions,
|
||||
weights: weights,
|
||||
weight: make([]func(x, y graph.Node) float64, g.Depth()),
|
||||
weight: make([]func(xid, yid int64) float64, g.Depth()),
|
||||
}
|
||||
|
||||
// Calculate the total edge weight of the graph
|
||||
@@ -614,7 +615,7 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
|
||||
var zero int
|
||||
for i := 0; i < g.Depth(); i++ {
|
||||
l.edgeWeightOf[i] = make([]float64, len(nodes))
|
||||
var weight func(x, y graph.Node) float64
|
||||
var weight func(xid, yid int64) float64
|
||||
|
||||
if weights != nil {
|
||||
if weights[i] == 0 {
|
||||
@@ -634,11 +635,12 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
|
||||
l.weight[i] = weight
|
||||
layer := g.Layer(i)
|
||||
for _, u := range l.nodes {
|
||||
w := weight(u, u)
|
||||
for _, v := range layer.From(u) {
|
||||
w += weight(u, v)
|
||||
uid := u.ID()
|
||||
w := weight(uid, uid)
|
||||
for _, v := range layer.From(uid) {
|
||||
w += weight(uid, v.ID())
|
||||
}
|
||||
l.edgeWeightOf[i][u.ID()] = w
|
||||
l.edgeWeightOf[i][uid] = w
|
||||
l.m2[i] += w
|
||||
}
|
||||
if l.m2[i] == 0 {
|
||||
@@ -779,7 +781,7 @@ func (l *undirectedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, ds
|
||||
removal = true
|
||||
}
|
||||
|
||||
k_aC += l.weight[layer](n, u)
|
||||
k_aC += l.weight[layer](id, uid)
|
||||
// sigma_totC could be kept for each community
|
||||
// and updated for moves, changing the calculation
|
||||
// of sigma_totC here from O(n_c) to O(1), but
|
||||
@@ -789,7 +791,7 @@ func (l *undirectedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, ds
|
||||
sigma_totC += l.edgeWeightOf[layer][uid]
|
||||
}
|
||||
|
||||
a_aa := l.weight[layer](n, n)
|
||||
a_aa := l.weight[layer](id, id)
|
||||
k_a := l.edgeWeightOf[layer][id]
|
||||
gamma := 1.0
|
||||
if l.resolutions != nil {
|
||||
|
@@ -359,7 +359,7 @@ tests:
|
||||
}
|
||||
layer := g.Layer(l)
|
||||
for n := range c {
|
||||
if layer.HasEdgeBetween(simple.Node(n), target) {
|
||||
if layer.HasEdgeBetween(int64(n), target.ID()) {
|
||||
connected = true
|
||||
break search
|
||||
}
|
||||
@@ -670,7 +670,7 @@ func undirectedMultiplexFrom(raw []layer) (UndirectedLayers, []float64, error) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range l.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -267,7 +267,7 @@ func TestCommunityQUndirected(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -284,7 +284,7 @@ func TestCommunityQWeightedUndirected(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -320,7 +320,7 @@ func TestCommunityDeltaQUndirected(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -337,7 +337,7 @@ func TestCommunityDeltaQWeightedUndirected(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -401,7 +401,7 @@ func testCommunityDeltaQUndirected(t *testing.T, test communityUndirectedQTest,
|
||||
}
|
||||
connected := false
|
||||
for n := range c {
|
||||
if g.HasEdgeBetween(simple.Node(n), target) {
|
||||
if g.HasEdgeBetween(int64(n), target.ID()) {
|
||||
connected = true
|
||||
break
|
||||
}
|
||||
@@ -445,7 +445,7 @@ func TestReduceQConsistencyUndirected(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -462,7 +462,7 @@ func TestReduceQConsistencyWeightedUndirected(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -563,7 +563,7 @@ func TestMoveLocalUndirected(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -580,7 +580,7 @@ func TestMoveLocalWeightedUndirected(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -625,7 +625,7 @@ func TestModularizeUndirected(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -642,7 +642,7 @@ func TestModularizeWeightedUndirected(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -151,7 +151,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
||||
if s, ok := n.(Subgrapher); ok {
|
||||
// If the node is not linked to any other node
|
||||
// the graph needs to be written now.
|
||||
if len(g.From(n)) == 0 {
|
||||
if len(g.From(n.ID())) == 0 {
|
||||
g := s.Subgraph()
|
||||
_, subIsDirected := g.(graph.Directed)
|
||||
if subIsDirected != isDirected {
|
||||
@@ -182,20 +182,22 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
||||
|
||||
havePrintedEdgeHeader := false
|
||||
for _, n := range nodes {
|
||||
to := g.From(n)
|
||||
nid := n.ID()
|
||||
to := g.From(nid)
|
||||
sort.Sort(ordered.ByID(to))
|
||||
for _, t := range to {
|
||||
tid := t.ID()
|
||||
if isDirected {
|
||||
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
|
||||
if p.visited[edge{inGraph: name, from: nid, to: tid}] {
|
||||
continue
|
||||
}
|
||||
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
|
||||
p.visited[edge{inGraph: name, from: nid, to: tid}] = true
|
||||
} else {
|
||||
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
|
||||
if p.visited[edge{inGraph: name, from: nid, to: tid}] {
|
||||
continue
|
||||
}
|
||||
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
|
||||
p.visited[edge{inGraph: name, from: t.ID(), to: n.ID()}] = true
|
||||
p.visited[edge{inGraph: name, from: nid, to: tid}] = true
|
||||
p.visited[edge{inGraph: name, from: tid, to: n.ID()}] = true
|
||||
}
|
||||
|
||||
if !havePrintedEdgeHeader {
|
||||
@@ -217,7 +219,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
||||
} else {
|
||||
p.writeNode(n)
|
||||
}
|
||||
e, edgeIsPorter := g.Edge(n, t).(Porter)
|
||||
e, edgeIsPorter := g.Edge(nid, tid).(Porter)
|
||||
if edgeIsPorter {
|
||||
p.writePorts(e.FromPort())
|
||||
}
|
||||
@@ -242,7 +244,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
||||
p.writePorts(e.ToPort())
|
||||
}
|
||||
|
||||
if a, ok := g.Edge(n, t).(encoding.Attributer); ok {
|
||||
if a, ok := g.Edge(nid, tid).(encoding.Attributer); ok {
|
||||
p.writeAttributeList(a)
|
||||
}
|
||||
|
||||
|
@@ -11,29 +11,29 @@ type GraphNode struct {
|
||||
roots []*GraphNode
|
||||
}
|
||||
|
||||
func (g *GraphNode) Has(n graph.Node) bool {
|
||||
if n.ID() == g.id {
|
||||
func (g *GraphNode) Has(id int64) bool {
|
||||
if id == g.id {
|
||||
return true
|
||||
}
|
||||
|
||||
visited := map[int64]struct{}{g.id: {}}
|
||||
for _, root := range g.roots {
|
||||
if root.ID() == n.ID() {
|
||||
if root.ID() == id {
|
||||
return true
|
||||
}
|
||||
|
||||
if root.has(n, visited) {
|
||||
if root.has(id, visited) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
for _, neigh := range g.neighbors {
|
||||
if neigh.ID() == n.ID() {
|
||||
if neigh.ID() == id {
|
||||
return true
|
||||
}
|
||||
|
||||
if gn, ok := neigh.(*GraphNode); ok {
|
||||
if gn.has(n, visited) {
|
||||
if gn.has(id, visited) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -42,18 +42,18 @@ func (g *GraphNode) Has(n graph.Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *GraphNode) has(n graph.Node, visited map[int64]struct{}) bool {
|
||||
func (g *GraphNode) has(id int64, visited map[int64]struct{}) bool {
|
||||
for _, root := range g.roots {
|
||||
if _, ok := visited[root.ID()]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
visited[root.ID()] = struct{}{}
|
||||
if root.ID() == n.ID() {
|
||||
if root.ID() == id {
|
||||
return true
|
||||
}
|
||||
|
||||
if root.has(n, visited) {
|
||||
if root.has(id, visited) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -65,16 +65,15 @@ func (g *GraphNode) has(n graph.Node, visited map[int64]struct{}) bool {
|
||||
}
|
||||
|
||||
visited[neigh.ID()] = struct{}{}
|
||||
if neigh.ID() == n.ID() {
|
||||
if neigh.ID() == id {
|
||||
return true
|
||||
}
|
||||
|
||||
if gn, ok := neigh.(*GraphNode); ok {
|
||||
if gn.has(n, visited) {
|
||||
if gn.has(id, visited) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
@@ -128,8 +127,8 @@ func (g *GraphNode) nodes(list []graph.Node, visited map[int64]struct{}) []graph
|
||||
return list
|
||||
}
|
||||
|
||||
func (g *GraphNode) From(n graph.Node) []graph.Node {
|
||||
if n.ID() == g.ID() {
|
||||
func (g *GraphNode) From(id int64) []graph.Node {
|
||||
if id == g.ID() {
|
||||
return g.neighbors
|
||||
}
|
||||
|
||||
@@ -137,7 +136,7 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
|
||||
for _, root := range g.roots {
|
||||
visited[root.ID()] = struct{}{}
|
||||
|
||||
if result := root.findNeighbors(n, visited); result != nil {
|
||||
if result := root.findNeighbors(id, visited); result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -146,7 +145,7 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
|
||||
visited[neigh.ID()] = struct{}{}
|
||||
|
||||
if gn, ok := neigh.(*GraphNode); ok {
|
||||
if result := gn.findNeighbors(n, visited); result != nil {
|
||||
if result := gn.findNeighbors(id, visited); result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -155,8 +154,8 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []graph.Node {
|
||||
if n.ID() == g.ID() {
|
||||
func (g *GraphNode) findNeighbors(id int64, visited map[int64]struct{}) []graph.Node {
|
||||
if id == g.ID() {
|
||||
return g.neighbors
|
||||
}
|
||||
|
||||
@@ -166,7 +165,7 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
|
||||
}
|
||||
visited[root.ID()] = struct{}{}
|
||||
|
||||
if result := root.findNeighbors(n, visited); result != nil {
|
||||
if result := root.findNeighbors(id, visited); result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -178,7 +177,7 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
|
||||
visited[neigh.ID()] = struct{}{}
|
||||
|
||||
if gn, ok := neigh.(*GraphNode); ok {
|
||||
if result := gn.findNeighbors(n, visited); result != nil {
|
||||
if result := gn.findNeighbors(id, visited); result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -187,18 +186,18 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GraphNode) HasEdgeBetween(u, v graph.Node) bool {
|
||||
return g.EdgeBetween(u, v) != nil
|
||||
func (g *GraphNode) HasEdgeBetween(uid, vid int64) bool {
|
||||
return g.EdgeBetween(uid, vid) != nil
|
||||
}
|
||||
|
||||
func (g *GraphNode) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.EdgeBetween(u, v)
|
||||
func (g *GraphNode) Edge(uid, vid int64) graph.Edge {
|
||||
return g.EdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
if u.ID() == g.id || v.ID() == g.id {
|
||||
func (g *GraphNode) EdgeBetween(uid, vid int64) graph.Edge {
|
||||
if uid == g.id || vid == g.id {
|
||||
for _, neigh := range g.neighbors {
|
||||
if neigh.ID() == u.ID() || neigh.ID() == v.ID() {
|
||||
if neigh.ID() == uid || neigh.ID() == vid {
|
||||
return simple.Edge{F: g, T: neigh}
|
||||
}
|
||||
}
|
||||
@@ -208,7 +207,7 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
visited := map[int64]struct{}{g.id: {}}
|
||||
for _, root := range g.roots {
|
||||
visited[root.ID()] = struct{}{}
|
||||
if result := root.edgeBetween(u, v, visited); result != nil {
|
||||
if result := root.edgeBetween(uid, vid, visited); result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -216,7 +215,7 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
for _, neigh := range g.neighbors {
|
||||
visited[neigh.ID()] = struct{}{}
|
||||
if gn, ok := neigh.(*GraphNode); ok {
|
||||
if result := gn.edgeBetween(u, v, visited); result != nil {
|
||||
if result := gn.edgeBetween(uid, vid, visited); result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -225,10 +224,10 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) graph.Edge {
|
||||
if u.ID() == g.id || v.ID() == g.id {
|
||||
func (g *GraphNode) edgeBetween(uid, vid int64, visited map[int64]struct{}) graph.Edge {
|
||||
if uid == g.id || vid == g.id {
|
||||
for _, neigh := range g.neighbors {
|
||||
if neigh.ID() == u.ID() || neigh.ID() == v.ID() {
|
||||
if neigh.ID() == uid || neigh.ID() == vid {
|
||||
return simple.Edge{F: g, T: neigh}
|
||||
}
|
||||
}
|
||||
@@ -240,7 +239,7 @@ func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) gra
|
||||
continue
|
||||
}
|
||||
visited[root.ID()] = struct{}{}
|
||||
if result := root.edgeBetween(u, v, visited); result != nil {
|
||||
if result := root.edgeBetween(uid, vid, visited); result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -252,7 +251,7 @@ func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) gra
|
||||
|
||||
visited[neigh.ID()] = struct{}{}
|
||||
if gn, ok := neigh.(*GraphNode); ok {
|
||||
if result := gn.edgeBetween(u, v, visited); result != nil {
|
||||
if result := gn.edgeBetween(uid, vid, visited); result != nil {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@@ -27,53 +27,57 @@ type WeightedEdge interface {
|
||||
|
||||
// Graph is a generalized graph.
|
||||
type Graph interface {
|
||||
// Has returns whether the node exists within the graph.
|
||||
Has(Node) bool
|
||||
// Has returns whether a node with the given ID exists
|
||||
// within the graph.
|
||||
Has(id int64) bool
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
Nodes() []Node
|
||||
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the given node.
|
||||
From(Node) []Node
|
||||
// from the node with the given ID.
|
||||
From(id int64) []Node
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between
|
||||
// nodes x and y without considering direction.
|
||||
HasEdgeBetween(x, y Node) bool
|
||||
// nodes with IDs xid and yid without considering direction.
|
||||
HasEdgeBetween(xid, yid int64) bool
|
||||
|
||||
// Edge returns the edge from u to v if such an edge
|
||||
// exists and nil otherwise. The node v must be directly
|
||||
// reachable from u as defined by the From method.
|
||||
Edge(u, v Node) Edge
|
||||
// Edge returns the edge from u to v, with IDs uid and vid,
|
||||
// if such an edge exists and nil otherwise. The node v
|
||||
// must be directly reachable from u as defined by the
|
||||
// From method.
|
||||
Edge(uid, vid int64) Edge
|
||||
}
|
||||
|
||||
// Weighted is a weighted graph.
|
||||
type Weighted interface {
|
||||
Graph
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if
|
||||
// such an edge exists and nil otherwise. The node v must
|
||||
// be directly reachable from u as defined by the
|
||||
// From method.
|
||||
WeightedEdge(u, v Node) WeightedEdge
|
||||
// WeightedEdge returns the weighted edge from u to v
|
||||
// with IDs uid and vid if such an edge exists and
|
||||
// nil otherwise. The node v must be directly
|
||||
// reachable from u as defined by the From method.
|
||||
WeightedEdge(uid, vid int64) WeightedEdge
|
||||
|
||||
// Weight returns the weight for the edge between
|
||||
// x and y if Edge(x, y) returns a non-nil Edge.
|
||||
// x and y with IDs xid and yid if Edge(xid, yid)
|
||||
// returns a non-nil Edge.
|
||||
// If x and y are the same node or there is no
|
||||
// joining edge between the two nodes the weight
|
||||
// value returned is implementation dependent.
|
||||
// Weight returns true if an edge exists between
|
||||
// x and y or if x and y have the same ID, false
|
||||
// otherwise.
|
||||
Weight(x, y Node) (w float64, ok bool)
|
||||
Weight(xid, yid int64) (w float64, ok bool)
|
||||
}
|
||||
|
||||
// Undirected is an undirected graph.
|
||||
type Undirected interface {
|
||||
Graph
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
EdgeBetween(x, y Node) Edge
|
||||
// EdgeBetween returns the edge between nodes x and y
|
||||
// with IDs xid and yid.
|
||||
EdgeBetween(xid, yid int64) Edge
|
||||
}
|
||||
|
||||
// WeightedUndirected is a weighted undirected graph.
|
||||
@@ -81,8 +85,8 @@ type WeightedUndirected interface {
|
||||
Weighted
|
||||
|
||||
// WeightedEdgeBetween returns the edge between nodes
|
||||
// x and y.
|
||||
WeightedEdgeBetween(x, y Node) WeightedEdge
|
||||
// x and y with IDs xid and yid.
|
||||
WeightedEdgeBetween(xid, yid int64) WeightedEdge
|
||||
}
|
||||
|
||||
// Directed is a directed graph.
|
||||
@@ -90,12 +94,12 @@ type Directed interface {
|
||||
Graph
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists
|
||||
// in the graph from u to v.
|
||||
HasEdgeFromTo(u, v Node) bool
|
||||
// in the graph from u to v with IDs uid and vid.
|
||||
HasEdgeFromTo(uid, vid int64) bool
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the given node.
|
||||
To(Node) []Node
|
||||
// to the node with the given ID.
|
||||
To(id int64) []Node
|
||||
}
|
||||
|
||||
// WeightedDirected is a weighted directed graph.
|
||||
@@ -103,12 +107,13 @@ type WeightedDirected interface {
|
||||
Weighted
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists
|
||||
// in the graph from u to v.
|
||||
HasEdgeFromTo(u, v Node) bool
|
||||
// in the graph from u to v with the IDs uid and
|
||||
// vid.
|
||||
HasEdgeFromTo(uid, vid int64) bool
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the given node.
|
||||
To(Node) []Node
|
||||
// to the node with the given ID.
|
||||
To(id int64) []Node
|
||||
}
|
||||
|
||||
// NodeAdder is an interface for adding arbitrary nodes to a graph.
|
||||
@@ -217,7 +222,7 @@ func Copy(dst Builder, src Graph) {
|
||||
dst.AddNode(n)
|
||||
}
|
||||
for _, u := range nodes {
|
||||
for _, v := range src.From(u) {
|
||||
for _, v := range src.From(u.ID()) {
|
||||
dst.SetEdge(dst.NewEdge(u, v))
|
||||
}
|
||||
}
|
||||
@@ -240,8 +245,8 @@ func CopyWeighted(dst WeightedBuilder, src Weighted) {
|
||||
dst.AddNode(n)
|
||||
}
|
||||
for _, u := range nodes {
|
||||
for _, v := range src.From(u) {
|
||||
dst.SetWeightedEdge(dst.NewWeightedEdge(u, v, src.WeightedEdge(u, v).Weight()))
|
||||
for _, v := range src.From(u.ID()) {
|
||||
dst.SetWeightedEdge(dst.NewWeightedEdge(u, v, src.WeightedEdge(u.ID(), v.ID()).Weight()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -273,8 +273,8 @@ func same(a, b graph.Graph) bool {
|
||||
}
|
||||
}
|
||||
for _, u := range a.Nodes() {
|
||||
aFromU := a.From(u)
|
||||
bFromU := b.From(u)
|
||||
aFromU := a.From(u.ID())
|
||||
bFromU := b.From(u.ID())
|
||||
if len(aFromU) != len(bFromU) {
|
||||
return false
|
||||
}
|
||||
@@ -288,7 +288,7 @@ func same(a, b graph.Graph) bool {
|
||||
aW, aWok := a.(graph.Weighted)
|
||||
bW, bWok := b.(graph.Weighted)
|
||||
if aWok && bWok {
|
||||
if aW.WeightedEdge(u, va).Weight() != bW.WeightedEdge(u, vb).Weight() {
|
||||
if aW.WeightedEdge(u.ID(), va.ID()).Weight() != bW.WeightedEdge(u.ID(), vb.ID()).Weight() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ func Gnp(dst GraphBuilder, n int, p float64, src *rand.Rand) error {
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if !dst.Has(simple.Node(i)) {
|
||||
if !dst.Has(int64(i)) {
|
||||
dst.AddNode(simple.Node(i))
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if !dst.Has(simple.Node(i)) {
|
||||
if !dst.Has(int64(i)) {
|
||||
dst.AddNode(simple.Node(i))
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
|
||||
for {
|
||||
v, w := edgeNodesFor(rnd(nChoose2))
|
||||
e := simple.Edge{F: w, T: v}
|
||||
if !hasEdge(e.F, e.T) {
|
||||
if !hasEdge(e.F.ID(), e.T.ID()) {
|
||||
dst.SetEdge(e)
|
||||
break
|
||||
}
|
||||
@@ -137,7 +137,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
|
||||
for {
|
||||
v, w := edgeNodesFor(rnd(nChoose2))
|
||||
e := simple.Edge{F: v, T: w}
|
||||
if !hasEdge(e.F, e.T) {
|
||||
if !hasEdge(e.F.ID(), e.T.ID()) {
|
||||
dst.SetEdge(e)
|
||||
break
|
||||
}
|
||||
@@ -182,7 +182,7 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
if !dst.Has(simple.Node(i)) {
|
||||
if !dst.Has(int64(i)) {
|
||||
dst.AddNode(simple.Node(i))
|
||||
}
|
||||
}
|
||||
@@ -201,14 +201,14 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
||||
j := v*(v-1)/2 + (v+i)%n
|
||||
var ej simple.Edge
|
||||
ej.T, ej.F = edgeNodesFor(j)
|
||||
if !hasEdge(ej.From(), ej.To()) {
|
||||
if !hasEdge(ej.From().ID(), ej.To().ID()) {
|
||||
dst.SetEdge(ej)
|
||||
}
|
||||
k--
|
||||
m++
|
||||
var em simple.Edge
|
||||
em.T, em.F = edgeNodesFor(m)
|
||||
if !hasEdge(em.From(), em.To()) {
|
||||
if !hasEdge(em.From().ID(), em.To().ID()) {
|
||||
replace[j] = m
|
||||
} else {
|
||||
replace[j] = replace[m]
|
||||
@@ -222,17 +222,17 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
||||
r := rndN(nChoose2-i) + i
|
||||
var er simple.Edge
|
||||
er.T, er.F = edgeNodesFor(r)
|
||||
if !hasEdge(er.From(), er.To()) {
|
||||
if !hasEdge(er.From().ID(), er.To().ID()) {
|
||||
dst.SetEdge(er)
|
||||
} else {
|
||||
er.T, er.F = edgeNodesFor(replace[r])
|
||||
if !hasEdge(er.From(), er.To()) {
|
||||
if !hasEdge(er.From().ID(), er.To().ID()) {
|
||||
dst.SetEdge(er)
|
||||
}
|
||||
}
|
||||
var ei simple.Edge
|
||||
ei.T, ei.F = edgeNodesFor(i)
|
||||
if !hasEdge(ei.From(), ei.To()) {
|
||||
if !hasEdge(ei.From().ID(), ei.To().ID()) {
|
||||
replace[r] = i
|
||||
} else {
|
||||
replace[r] = replace[i]
|
||||
@@ -252,12 +252,12 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
||||
j := v*(v-1)/2 + (v+i)%n
|
||||
var ej simple.Edge
|
||||
ej.F, ej.T = edgeNodesFor(j)
|
||||
if !hasEdge(ej.From(), ej.To()) {
|
||||
if !hasEdge(ej.From().ID(), ej.To().ID()) {
|
||||
dst.SetEdge(ej)
|
||||
}
|
||||
k--
|
||||
m++
|
||||
if !hasEdge(edgeNodesFor(m)) {
|
||||
if u, v := edgeNodesFor(m); !hasEdge(u.ID(), v.ID()) {
|
||||
replace[j] = m
|
||||
} else {
|
||||
replace[j] = replace[m]
|
||||
@@ -271,15 +271,15 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
||||
r := rndN(nChoose2-i) + i
|
||||
var er simple.Edge
|
||||
er.F, er.T = edgeNodesFor(r)
|
||||
if !hasEdge(er.From(), er.To()) {
|
||||
if !hasEdge(er.From().ID(), er.To().ID()) {
|
||||
dst.SetEdge(er)
|
||||
} else {
|
||||
er.F, er.T = edgeNodesFor(replace[r])
|
||||
if !hasEdge(er.From(), er.To()) {
|
||||
if !hasEdge(er.From().ID(), er.To().ID()) {
|
||||
dst.SetEdge(er)
|
||||
}
|
||||
}
|
||||
if !hasEdge(edgeNodesFor(i)) {
|
||||
if u, v := edgeNodesFor(i); !hasEdge(u.ID(), v.ID()) {
|
||||
replace[r] = i
|
||||
} else {
|
||||
replace[r] = replace[i]
|
||||
|
@@ -27,7 +27,7 @@ func (g *gnUndirected) SetEdge(e graph.Edge) {
|
||||
return
|
||||
case e.From().ID() > e.To().ID():
|
||||
g.addBackwards = true
|
||||
case g.UndirectedBuilder.HasEdgeBetween(e.From(), e.To()):
|
||||
case g.UndirectedBuilder.HasEdgeBetween(e.From().ID(), e.To().ID()):
|
||||
g.addMultipleEdge = true
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ func (g *gnDirected) SetEdge(e graph.Edge) {
|
||||
case e.From().ID() == e.To().ID():
|
||||
g.addSelfLoop = true
|
||||
return
|
||||
case g.DirectedBuilder.HasEdgeFromTo(e.From(), e.To()):
|
||||
case g.DirectedBuilder.HasEdgeFromTo(e.From().ID(), e.To().ID()):
|
||||
g.addMultipleEdge = true
|
||||
}
|
||||
|
||||
@@ -190,9 +190,10 @@ func TestPowerLawUndirected(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
var lines int
|
||||
for _, v := range g.From(u) {
|
||||
lines += len(g.Lines(u, v))
|
||||
for _, v := range g.From(uid) {
|
||||
lines += len(g.Lines(uid, v.ID()))
|
||||
}
|
||||
if lines < d {
|
||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||
@@ -218,9 +219,10 @@ func TestPowerLawDirected(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
var lines int
|
||||
for _, v := range g.From(u) {
|
||||
lines += len(g.Lines(u, v))
|
||||
for _, v := range g.From(uid) {
|
||||
lines += len(g.Lines(uid, v.ID()))
|
||||
}
|
||||
if lines < d {
|
||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||
@@ -265,9 +267,10 @@ func TestBipartitePowerLawUndirected(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
var lines int
|
||||
for _, v := range g.From(u) {
|
||||
lines += len(g.Lines(u, v))
|
||||
for _, v := range g.From(uid) {
|
||||
lines += len(g.Lines(uid, v.ID()))
|
||||
}
|
||||
if lines < d {
|
||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||
@@ -312,9 +315,10 @@ func TestBipartitePowerLawDirected(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
var lines int
|
||||
for _, v := range g.From(u) {
|
||||
lines += len(g.Lines(u, v))
|
||||
for _, v := range g.From(uid) {
|
||||
lines += len(g.Lines(uid, v.ID()))
|
||||
}
|
||||
if lines < d {
|
||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||
|
@@ -66,6 +66,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
||||
for i := 0; i < n; i++ {
|
||||
u := nodes[rndN(len(nodes))]
|
||||
d := dst.NewNode()
|
||||
did := d.ID()
|
||||
|
||||
// Add the duplicate node.
|
||||
dst.AddNode(d)
|
||||
@@ -74,13 +75,14 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
||||
// into the rest of the graph.
|
||||
for {
|
||||
// Add edges to parent's neighbours.
|
||||
to := dst.From(u)
|
||||
to := dst.From(u.ID())
|
||||
sort.Sort(ordered.ByID(to))
|
||||
for _, v := range to {
|
||||
if rnd() < delta || dst.HasEdgeBetween(v, d) {
|
||||
vid := v.ID()
|
||||
if rnd() < delta || dst.HasEdgeBetween(vid, did) {
|
||||
continue
|
||||
}
|
||||
if v.ID() < d.ID() {
|
||||
if vid < did {
|
||||
dst.SetEdge(dst.NewEdge(v, d))
|
||||
} else {
|
||||
dst.SetEdge(dst.NewEdge(d, v))
|
||||
@@ -90,11 +92,13 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
||||
// Add edges to old nodes.
|
||||
scaledAlpha := alpha / float64(len(nodes))
|
||||
for _, v := range nodes {
|
||||
switch v.ID() {
|
||||
case u.ID():
|
||||
uid := u.ID()
|
||||
vid := v.ID()
|
||||
switch vid {
|
||||
case uid:
|
||||
if !math.IsNaN(sigma) {
|
||||
if i == 0 || rnd() < sigma {
|
||||
if v.ID() < d.ID() {
|
||||
if vid < did {
|
||||
dst.SetEdge(dst.NewEdge(v, d))
|
||||
} else {
|
||||
dst.SetEdge(dst.NewEdge(d, v))
|
||||
@@ -104,8 +108,8 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
if rnd() < scaledAlpha && !dst.HasEdgeBetween(v, d) {
|
||||
if v.ID() < d.ID() {
|
||||
if rnd() < scaledAlpha && !dst.HasEdgeBetween(vid, did) {
|
||||
if vid < did {
|
||||
dst.SetEdge(dst.NewEdge(v, d))
|
||||
} else {
|
||||
dst.SetEdge(dst.NewEdge(d, v))
|
||||
@@ -114,7 +118,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
||||
}
|
||||
}
|
||||
|
||||
if len(dst.From(d)) != 0 {
|
||||
if len(dst.From(did)) != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@@ -25,7 +25,7 @@ func (g *duplication) SetEdge(e graph.Edge) {
|
||||
return
|
||||
case e.From().ID() > e.To().ID():
|
||||
g.addBackwards = true
|
||||
case g.UndirectedMutator.HasEdgeBetween(e.From(), e.To()):
|
||||
case g.UndirectedMutator.HasEdgeBetween(e.From().ID(), e.To().ID()):
|
||||
g.addMultipleEdge = true
|
||||
}
|
||||
|
||||
|
@@ -8,8 +8,8 @@ import "gonum.org/v1/gonum/graph"
|
||||
|
||||
// GraphBuilder is a graph that can have nodes and edges added.
|
||||
type GraphBuilder interface {
|
||||
Has(graph.Node) bool
|
||||
HasEdgeBetween(x, y graph.Node) bool
|
||||
Has(id int64) bool
|
||||
HasEdgeBetween(xid, yid int64) bool
|
||||
graph.Builder
|
||||
}
|
||||
|
||||
|
@@ -47,7 +47,7 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
|
||||
// Initial condition.
|
||||
wt := make([]float64, n)
|
||||
for u := 0; u < m; u++ {
|
||||
if !dst.Has(simple.Node(u)) {
|
||||
if !dst.Has(int64(0)) {
|
||||
dst.AddNode(simple.Node(u))
|
||||
}
|
||||
// We need to give equal probability for
|
||||
@@ -68,9 +68,9 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
|
||||
for i := 0; i < m; i++ {
|
||||
// Triad formation.
|
||||
if i != 0 && rnd() < p {
|
||||
for _, w := range permute(dst.From(simple.Node(u)), rndN) {
|
||||
for _, w := range permute(dst.From(int64(u)), rndN) {
|
||||
wid := w.ID()
|
||||
if wid == int64(v) || dst.HasEdgeBetween(w, simple.Node(v)) {
|
||||
if wid == int64(v) || dst.HasEdgeBetween(wid, int64(v)) {
|
||||
continue
|
||||
}
|
||||
dst.SetEdge(simple.Edge{F: w, T: simple.Node(v)})
|
||||
@@ -87,7 +87,7 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
|
||||
if !ok {
|
||||
return errors.New("gen: depleted distribution")
|
||||
}
|
||||
if u == v || dst.HasEdgeBetween(simple.Node(u), simple.Node(v)) {
|
||||
if u == v || dst.HasEdgeBetween(int64(u), int64(v)) {
|
||||
continue
|
||||
}
|
||||
dst.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||
@@ -128,7 +128,7 @@ func PreferentialAttachment(dst graph.UndirectedBuilder, n, m int, src *rand.Ran
|
||||
// Initial condition.
|
||||
wt := make([]float64, n)
|
||||
for u := 0; u < m; u++ {
|
||||
if !dst.Has(simple.Node(u)) {
|
||||
if !dst.Has(int64(u)) {
|
||||
dst.AddNode(simple.Node(u))
|
||||
}
|
||||
// We need to give equal probability for
|
||||
|
@@ -40,7 +40,7 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
|
||||
n *= d
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
if !dst.Has(simple.Node(i)) {
|
||||
if !dst.Has(int64(i)) {
|
||||
dst.AddNode(simple.Node(i))
|
||||
}
|
||||
}
|
||||
@@ -67,14 +67,14 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
|
||||
if uid > vid {
|
||||
e.F, e.T = e.T, e.F
|
||||
}
|
||||
if !hasEdge(e.From(), e.To()) {
|
||||
if !hasEdge(e.From().ID(), e.To().ID()) {
|
||||
dst.SetEdge(e)
|
||||
}
|
||||
if !isDirected {
|
||||
return
|
||||
}
|
||||
e.F, e.T = e.T, e.F
|
||||
if !hasEdge(e.From(), e.To()) {
|
||||
if !hasEdge(e.From().ID(), e.To().ID()) {
|
||||
dst.SetEdge(e)
|
||||
}
|
||||
})
|
||||
@@ -110,7 +110,7 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
|
||||
if !isDirected && uid > vid {
|
||||
e.F, e.T = e.T, e.F
|
||||
}
|
||||
if !hasEdge(e.From(), e.To()) {
|
||||
if !hasEdge(e.From().ID(), e.To().ID()) {
|
||||
dst.SetEdge(e)
|
||||
}
|
||||
}
|
||||
|
@@ -103,13 +103,13 @@ func (g *DirectedGraph) SetLine(l graph.Line) {
|
||||
lid = l.ID()
|
||||
)
|
||||
|
||||
if !g.Has(from) {
|
||||
if !g.Has(fid) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
if g.from[fid][tid] == nil {
|
||||
g.from[fid][tid] = make(map[int64]graph.Line)
|
||||
}
|
||||
if !g.Has(to) {
|
||||
if !g.Has(tid) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
if g.to[tid][fid] == nil {
|
||||
@@ -149,8 +149,8 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *DirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodes[n.ID()]
|
||||
func (g *DirectedGraph) Has(id int64) bool {
|
||||
_, ok := g.nodes[id]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -187,30 +187,30 @@ func (g *DirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if _, ok := g.from[n.ID()]; !ok {
|
||||
func (g *DirectedGraph) From(id int64) []graph.Node {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
from := make([]graph.Node, len(g.from[n.ID()]))
|
||||
from := make([]graph.Node, len(g.from[id]))
|
||||
i := 0
|
||||
for id := range g.from[n.ID()] {
|
||||
from[i] = g.nodes[id]
|
||||
for vid := range g.from[id] {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
return from
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
||||
if _, ok := g.from[n.ID()]; !ok {
|
||||
func (g *DirectedGraph) To(id int64) []graph.Node {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
to := make([]graph.Node, len(g.to[n.ID()]))
|
||||
to := make([]graph.Node, len(g.to[id]))
|
||||
i := 0
|
||||
for id := range g.to[n.ID()] {
|
||||
to[i] = g.nodes[id]
|
||||
for uid := range g.to[id] {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
return to
|
||||
@@ -218,9 +218,7 @@ func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
// considering direction.
|
||||
func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
if _, ok := g.from[xid][yid]; ok {
|
||||
return true
|
||||
}
|
||||
@@ -231,8 +229,8 @@ func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.Edge is a multi.Edge if an edge exists.
|
||||
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
lines := g.Lines(u, v)
|
||||
func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
lines := g.Lines(uid, vid)
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -241,8 +239,8 @@ func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
|
||||
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *DirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
||||
edge := g.from[u.ID()][v.ID()]
|
||||
func (g *DirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -254,21 +252,21 @@ func (g *DirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
||||
}
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
_, ok := g.from[u.ID()][v.ID()]
|
||||
func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||
_, ok := g.from[uid][vid]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *DirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodes[n.ID()]; !ok {
|
||||
func (g *DirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
for _, e := range g.from[n.ID()] {
|
||||
for _, e := range g.from[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
for _, e := range g.to[n.ID()] {
|
||||
for _, e := range g.to[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
return deg
|
||||
|
@@ -21,7 +21,7 @@ var (
|
||||
func TestEdgeOvercounting(t *testing.T) {
|
||||
g := generateDummyGraph()
|
||||
|
||||
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
|
||||
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||
}
|
||||
}
|
||||
|
@@ -95,13 +95,13 @@ func (g *UndirectedGraph) SetLine(l graph.Line) {
|
||||
lid = l.ID()
|
||||
)
|
||||
|
||||
if !g.Has(from) {
|
||||
if !g.Has(fid) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
if g.lines[fid][tid] == nil {
|
||||
g.lines[fid][tid] = make(map[int64]graph.Line)
|
||||
}
|
||||
if !g.Has(to) {
|
||||
if !g.Has(tid) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
if g.lines[tid][fid] == nil {
|
||||
@@ -138,8 +138,8 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *UndirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodes[n.ID()]
|
||||
func (g *UndirectedGraph) Has(id int64) bool {
|
||||
_, ok := g.nodes[id]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -185,14 +185,14 @@ func (g *UndirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if !g.Has(n) {
|
||||
func (g *UndirectedGraph) From(id int64) []graph.Node {
|
||||
if !g.Has(id) {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodes := make([]graph.Node, len(g.lines[n.ID()]))
|
||||
nodes := make([]graph.Node, len(g.lines[id]))
|
||||
i := 0
|
||||
for from := range g.lines[n.ID()] {
|
||||
for from := range g.lines[id] {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
@@ -200,21 +200,21 @@ func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g *UndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
_, ok := g.lines[x.ID()][y.ID()]
|
||||
func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
_, ok := g.lines[xid][yid]
|
||||
return ok
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
||||
return g.Edge(x, y)
|
||||
func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
return g.Edge(xid, yid)
|
||||
}
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.Edge is a multi.Edge if an edge exists.
|
||||
func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
lines := g.LinesBetween(u, v)
|
||||
func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
lines := g.LinesBetween(uid, vid)
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -223,26 +223,26 @@ func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
|
||||
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *UndirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
||||
return g.LinesBetween(u, v)
|
||||
func (g *UndirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
return g.LinesBetween(uid, vid)
|
||||
}
|
||||
|
||||
// LinesBetween returns the lines between nodes x and y.
|
||||
func (g *UndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
|
||||
func (g *UndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
|
||||
var lines []graph.Line
|
||||
for _, l := range g.lines[x.ID()][y.ID()] {
|
||||
for _, l := range g.lines[xid][yid] {
|
||||
lines = append(lines, l)
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *UndirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodes[n.ID()]; !ok {
|
||||
func (g *UndirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
for _, e := range g.lines[n.ID()] {
|
||||
for _, e := range g.lines[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
return deg
|
||||
|
@@ -30,7 +30,7 @@ func TestMaxID(t *testing.T) {
|
||||
delete(nodes, Node(2))
|
||||
n := g.NewNode()
|
||||
g.AddNode(n)
|
||||
if !g.Has(n) {
|
||||
if !g.Has(n.ID()) {
|
||||
t.Error("added node does not exist in graph")
|
||||
}
|
||||
if _, exists := nodes[n]; exists {
|
||||
|
@@ -107,13 +107,13 @@ func (g *WeightedDirectedGraph) SetWeightedLine(l graph.WeightedLine) {
|
||||
lid = l.ID()
|
||||
)
|
||||
|
||||
if !g.Has(from) {
|
||||
if !g.Has(fid) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
if g.from[fid][tid] == nil {
|
||||
g.from[fid][tid] = make(map[int64]graph.WeightedLine)
|
||||
}
|
||||
if !g.Has(to) {
|
||||
if !g.Has(tid) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
if g.to[tid][fid] == nil {
|
||||
@@ -153,8 +153,8 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *WeightedDirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodes[n.ID()]
|
||||
func (g *WeightedDirectedGraph) Has(id int64) bool {
|
||||
_, ok := g.nodes[id]
|
||||
|
||||
return ok
|
||||
}
|
||||
@@ -213,30 +213,30 @@ func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedDirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if _, ok := g.from[n.ID()]; !ok {
|
||||
func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
from := make([]graph.Node, len(g.from[n.ID()]))
|
||||
from := make([]graph.Node, len(g.from[id]))
|
||||
i := 0
|
||||
for id := range g.from[n.ID()] {
|
||||
from[i] = g.nodes[id]
|
||||
for vid := range g.from[id] {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
return from
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
|
||||
if _, ok := g.from[n.ID()]; !ok {
|
||||
func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
to := make([]graph.Node, len(g.to[n.ID()]))
|
||||
to := make([]graph.Node, len(g.to[id]))
|
||||
i := 0
|
||||
for id := range g.to[n.ID()] {
|
||||
to[i] = g.nodes[id]
|
||||
for uid := range g.to[id] {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
return to
|
||||
@@ -244,9 +244,7 @@ func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
// considering direction.
|
||||
func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
if _, ok := g.from[xid][yid]; ok {
|
||||
return true
|
||||
}
|
||||
@@ -255,8 +253,8 @@ func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
}
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||
func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
if _, ok := g.from[u.ID()][v.ID()]; !ok {
|
||||
func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||
if _, ok := g.from[uid][vid]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -265,15 +263,15 @@ func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.Edge is a multi.WeightedEdge if an edge exists.
|
||||
func (g *WeightedDirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdge(u, v)
|
||||
func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdge(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
|
||||
func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
lines := g.WeightedLines(u, v)
|
||||
func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
lines := g.WeightedLines(uid, vid)
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -282,8 +280,8 @@ func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge
|
||||
|
||||
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedDirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
||||
edge := g.from[u.ID()][v.ID()]
|
||||
func (g *WeightedDirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -296,8 +294,8 @@ func (g *WeightedDirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
||||
|
||||
// WeightedLines returns the weighted lines from u to v if such any such lines exists
|
||||
// and nil otherwise. The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedDirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedLine {
|
||||
edge := g.from[u.ID()][v.ID()]
|
||||
func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
|
||||
edge := g.from[uid][vid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -310,21 +308,21 @@ func (g *WeightedDirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedL
|
||||
|
||||
// Weight returns the weight for the lines between x and y summarised by the receiver's
|
||||
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
|
||||
func (g *WeightedDirectedGraph) Weight(u, v graph.Node) (w float64, ok bool) {
|
||||
lines := g.WeightedLines(u, v)
|
||||
func (g *WeightedDirectedGraph) Weight(uid, vid int64) (w float64, ok bool) {
|
||||
lines := g.WeightedLines(uid, vid)
|
||||
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *WeightedDirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodes[n.ID()]; !ok {
|
||||
func (g *WeightedDirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
for _, e := range g.from[n.ID()] {
|
||||
for _, e := range g.from[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
for _, e := range g.to[n.ID()] {
|
||||
for _, e := range g.to[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
return deg
|
||||
|
@@ -22,7 +22,7 @@ var (
|
||||
func TestWeightedEdgeOvercounting(t *testing.T) {
|
||||
g := generateDummyWeightedGraph()
|
||||
|
||||
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
|
||||
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||
}
|
||||
}
|
||||
|
@@ -99,13 +99,13 @@ func (g *WeightedUndirectedGraph) SetWeighted(l graph.WeightedLine) {
|
||||
lid = l.ID()
|
||||
)
|
||||
|
||||
if !g.Has(from) {
|
||||
if !g.Has(fid) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
if g.lines[fid][tid] == nil {
|
||||
g.lines[fid][tid] = make(map[int64]graph.WeightedLine)
|
||||
}
|
||||
if !g.Has(to) {
|
||||
if !g.Has(tid) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
if g.lines[tid][fid] == nil {
|
||||
@@ -142,8 +142,8 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *WeightedUndirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodes[n.ID()]
|
||||
func (g *WeightedUndirectedGraph) Has(id int64) bool {
|
||||
_, ok := g.nodes[id]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -189,14 +189,14 @@ func (g *WeightedUndirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if !g.Has(n) {
|
||||
func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
|
||||
if !g.Has(id) {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodes := make([]graph.Node, len(g.lines[n.ID()]))
|
||||
nodes := make([]graph.Node, len(g.lines[id]))
|
||||
i := 0
|
||||
for from := range g.lines[n.ID()] {
|
||||
for from := range g.lines[id] {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
@@ -204,20 +204,20 @@ func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
_, ok := g.lines[x.ID()][y.ID()]
|
||||
func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
_, ok := g.lines[xid][yid]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedUndirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
||||
return g.LinesBetween(u, v)
|
||||
func (g *WeightedUndirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||
return g.LinesBetween(uid, vid)
|
||||
}
|
||||
|
||||
// LinesBetween returns the lines between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
|
||||
edge := g.lines[x.ID()][y.ID()]
|
||||
func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
|
||||
edge := g.lines[xid][yid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -237,20 +237,20 @@ func (g *WeightedUndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.Edge is a multi.WeightedEdge if an edge exists.
|
||||
func (g *WeightedUndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdge(u, v)
|
||||
func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdge(uid, vid)
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
||||
return g.WeightedEdge(x, y)
|
||||
func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
return g.WeightedEdge(xid, yid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
|
||||
func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
lines := g.WeightedLines(u, v)
|
||||
func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
lines := g.WeightedLines(uid, vid)
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -258,19 +258,19 @@ func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEd
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
|
||||
return g.WeightedEdge(x, y)
|
||||
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
|
||||
return g.WeightedEdge(xid, yid)
|
||||
}
|
||||
|
||||
// WeightedLines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedUndirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedLine {
|
||||
return g.WeightedLinesBetween(u, v)
|
||||
func (g *WeightedUndirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
|
||||
return g.WeightedLinesBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedLinesBetween returns the lines between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) WeightedLinesBetween(x, y graph.Node) []graph.WeightedLine {
|
||||
edge := g.lines[x.ID()][y.ID()]
|
||||
func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) []graph.WeightedLine {
|
||||
edge := g.lines[xid][yid]
|
||||
if len(edge) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -289,18 +289,18 @@ func (g *WeightedUndirectedGraph) WeightedLinesBetween(x, y graph.Node) []graph.
|
||||
|
||||
// Weight returns the weight for the lines between x and y summarised by the receiver's
|
||||
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
|
||||
func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
lines := g.WeightedLines(x, y)
|
||||
func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
lines := g.WeightedLines(xid, yid)
|
||||
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *WeightedUndirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodes[n.ID()]; !ok {
|
||||
func (g *WeightedUndirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
var deg int
|
||||
for _, e := range g.lines[n.ID()] {
|
||||
for _, e := range g.lines[id] {
|
||||
deg += len(e)
|
||||
}
|
||||
return deg
|
||||
|
@@ -23,7 +23,7 @@ func TestWeightedMaxID(t *testing.T) {
|
||||
delete(nodes, Node(2))
|
||||
n := g.NewNode()
|
||||
g.AddNode(n)
|
||||
if !g.Has(n) {
|
||||
if !g.Has(n.ID()) {
|
||||
t.Error("added node does not exist in graph")
|
||||
}
|
||||
if _, exists := nodes[n]; exists {
|
||||
|
@@ -19,43 +19,46 @@ type WeightedLine interface {
|
||||
|
||||
// Multigraph is a generalized multigraph.
|
||||
type Multigraph interface {
|
||||
// Has returns whether the node exists within the multigraph.
|
||||
Has(Node) bool
|
||||
// Has returns whether the node with the given ID exists
|
||||
// within the multigraph.
|
||||
Has(id int64) bool
|
||||
|
||||
// Nodes returns all the nodes in the multigraph.
|
||||
Nodes() []Node
|
||||
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the given node.
|
||||
From(Node) []Node
|
||||
// from the node with the given ID.
|
||||
From(id int64) []Node
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between
|
||||
// nodes x and y without considering direction.
|
||||
HasEdgeBetween(x, y Node) bool
|
||||
// nodes with IDs xid and yid without considering direction.
|
||||
HasEdgeBetween(xid, yid int64) bool
|
||||
|
||||
// Lines returns the lines from u to v if any such lines
|
||||
// exist and nil otherwise. The node v must be directly
|
||||
// reachable from u as defined by the From method.
|
||||
Lines(u, v Node) []Line
|
||||
// Lines returns the lines from u to v, with IDs uid and
|
||||
// vid, if any such lines exist and nil otherwise. The
|
||||
// node v must be directly reachable from u as defined by
|
||||
// the From method.
|
||||
Lines(uid, vid int64) []Line
|
||||
}
|
||||
|
||||
// WeightedMultigraph is a weighted multigraph.
|
||||
type WeightedMultigraph interface {
|
||||
Multigraph
|
||||
|
||||
// WeightedLines returns the weighted lines from u to v if
|
||||
// any such lines exist and nil otherwise. The node v must
|
||||
// be directly reachable from u as defined by the
|
||||
// From method.
|
||||
WeightedLines(u, v Node) []WeightedLine
|
||||
// WeightedLines returns the weighted lines from u to v
|
||||
// with IDs uid and vid if any such lines exist and nil
|
||||
// otherwise. The node v must be directly reachable
|
||||
// from u as defined by the From method.
|
||||
WeightedLines(uid, vid int64) []WeightedLine
|
||||
}
|
||||
|
||||
// UndirectedMultigraph is an undirected multigraph.
|
||||
type UndirectedMultigraph interface {
|
||||
Multigraph
|
||||
|
||||
// LinesBetween returns the lines between nodes x and y.
|
||||
LinesBetween(x, y Node) []Line
|
||||
// LinesBetween returns the lines between nodes x and y
|
||||
// with IDs xid and yid.
|
||||
LinesBetween(xid, yid int64) []Line
|
||||
}
|
||||
|
||||
// WeightedUndirectedMultigraph is a weighted undirected multigraph.
|
||||
@@ -63,8 +66,8 @@ type WeightedUndirectedMultigraph interface {
|
||||
WeightedMultigraph
|
||||
|
||||
// WeightedLinesBetween returns the lines between nodes
|
||||
// x and y.
|
||||
WeightedLinesBetween(x, y Node) []WeightedLine
|
||||
// x and y with IDs xid and yid.
|
||||
WeightedLinesBetween(xid, yid int64) []WeightedLine
|
||||
}
|
||||
|
||||
// DirectedMultigraph is a directed multigraph.
|
||||
@@ -72,12 +75,13 @@ type DirectedMultigraph interface {
|
||||
Multigraph
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists
|
||||
// in the multigraph from u to v.
|
||||
HasEdgeFromTo(u, v Node) bool
|
||||
// in the multigraph from u to v with IDs uid
|
||||
// and vid.
|
||||
HasEdgeFromTo(uid, vid int64) bool
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the given node.
|
||||
To(Node) []Node
|
||||
// to the node with the given ID.
|
||||
To(id int64) []Node
|
||||
}
|
||||
|
||||
// WeightedDirectedMultigraph is a weighted directed multigraph.
|
||||
@@ -85,12 +89,13 @@ type WeightedDirectedMultigraph interface {
|
||||
WeightedMultigraph
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists
|
||||
// in the multigraph from u to v.
|
||||
HasEdgeFromTo(u, v Node) bool
|
||||
// in the multigraph from u to v with IDs uid
|
||||
// and vid.
|
||||
HasEdgeFromTo(uid, vid int64) bool
|
||||
|
||||
// To returns all nodes that can reach directly
|
||||
// to the given node.
|
||||
To(Node) []Node
|
||||
// to the node with the given ID.
|
||||
To(id int64) []Node
|
||||
}
|
||||
|
||||
// LineAdder is an interface for adding lines to a multigraph.
|
||||
|
@@ -115,17 +115,19 @@ func brandes(g graph.Graph, accumulate func(s graph.Node, stack linear.NodeStack
|
||||
queue.Enqueue(s)
|
||||
for queue.Len() != 0 {
|
||||
v := queue.Dequeue()
|
||||
vid := v.ID()
|
||||
stack.Push(v)
|
||||
for _, w := range g.From(v) {
|
||||
for _, w := range g.From(vid) {
|
||||
wid := w.ID()
|
||||
// w found for the first time?
|
||||
if d[w.ID()] < 0 {
|
||||
if d[wid] < 0 {
|
||||
queue.Enqueue(w)
|
||||
d[w.ID()] = d[v.ID()] + 1
|
||||
d[wid] = d[vid] + 1
|
||||
}
|
||||
// shortest path to w via v?
|
||||
if d[w.ID()] == d[v.ID()]+1 {
|
||||
sigma[w.ID()] += sigma[v.ID()]
|
||||
p[w.ID()] = append(p[w.ID()], v)
|
||||
if d[wid] == d[vid]+1 {
|
||||
sigma[wid] += sigma[vid]
|
||||
p[wid] = append(p[wid], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,18 +153,20 @@ func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64
|
||||
|
||||
nodes := g.Nodes()
|
||||
for i, s := range nodes {
|
||||
sid := s.ID()
|
||||
for j, t := range nodes {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
d := p.Weight(s, t)
|
||||
tid := t.ID()
|
||||
d := p.Weight(sid, tid)
|
||||
if math.IsInf(d, 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If we have a unique path, don't do the
|
||||
// extra work needed to get all paths.
|
||||
path, _, unique := p.Between(s, t)
|
||||
path, _, unique := p.Between(sid, tid)
|
||||
if unique {
|
||||
for _, v := range path[1 : len(path)-1] {
|
||||
// For undirected graphs we double count
|
||||
@@ -174,7 +178,7 @@ func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64
|
||||
}
|
||||
|
||||
// Otherwise iterate over all paths.
|
||||
paths, _ := p.AllBetween(s, t)
|
||||
paths, _ := p.AllBetween(sid, tid)
|
||||
stFrac := 1 / float64(len(paths))
|
||||
for _, path := range paths {
|
||||
for _, v := range path[1 : len(path)-1] {
|
||||
@@ -203,18 +207,20 @@ func EdgeBetweennessWeighted(g graph.Weighted, p path.AllShortest) map[[2]int64]
|
||||
_, isUndirected := g.(graph.Undirected)
|
||||
nodes := g.Nodes()
|
||||
for i, s := range nodes {
|
||||
sid := s.ID()
|
||||
for j, t := range nodes {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
d := p.Weight(s, t)
|
||||
tid := t.ID()
|
||||
d := p.Weight(sid, tid)
|
||||
if math.IsInf(d, 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
// If we have a unique path, don't do the
|
||||
// extra work needed to get all paths.
|
||||
path, _, unique := p.Between(s, t)
|
||||
path, _, unique := p.Between(sid, tid)
|
||||
if unique {
|
||||
for k, v := range path[1:] {
|
||||
// For undirected graphs we double count
|
||||
@@ -231,7 +237,7 @@ func EdgeBetweennessWeighted(g graph.Weighted, p path.AllShortest) map[[2]int64]
|
||||
}
|
||||
|
||||
// Otherwise iterate over all paths.
|
||||
paths, _ := p.AllBetween(s, t)
|
||||
paths, _ := p.AllBetween(sid, tid)
|
||||
stFrac := 1 / float64(len(paths))
|
||||
for _, path := range paths {
|
||||
for k, v := range path[1:] {
|
||||
|
@@ -179,7 +179,7 @@ func TestBetweenness(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -208,7 +208,7 @@ func TestEdgeBetweenness(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -240,7 +240,7 @@ func TestBetweennessWeighted(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -276,7 +276,7 @@ func TestEdgeBetweennessWeighted(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -122,9 +122,9 @@ func NewLaplacian(g graph.Undirected) Laplacian {
|
||||
|
||||
l := mat.NewSymDense(len(nodes), nil)
|
||||
for j, u := range nodes {
|
||||
to := g.From(u)
|
||||
l.SetSym(j, j, float64(len(to)))
|
||||
uid := u.ID()
|
||||
to := g.From(uid)
|
||||
l.SetSym(j, j, float64(len(to)))
|
||||
for _, v := range to {
|
||||
vid := v.ID()
|
||||
if uid == vid {
|
||||
@@ -155,12 +155,12 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
|
||||
|
||||
l := mat.NewSymDense(len(nodes), nil)
|
||||
for j, u := range nodes {
|
||||
to := g.From(u)
|
||||
uid := u.ID()
|
||||
to := g.From(uid)
|
||||
if len(to) == 0 {
|
||||
continue
|
||||
}
|
||||
l.SetSym(j, j, 1)
|
||||
uid := u.ID()
|
||||
squdeg := math.Sqrt(float64(len(to)))
|
||||
for _, v := range to {
|
||||
vid := v.ID()
|
||||
@@ -168,7 +168,7 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
|
||||
panic("network: self edge in graph")
|
||||
}
|
||||
if uid < vid {
|
||||
l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(len(g.From(v))))))
|
||||
l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(len(g.From(vid))))))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,7 +193,7 @@ func NewRandomWalkLaplacian(g graph.Graph, damp float64) Laplacian {
|
||||
l := mat.NewDense(len(nodes), len(nodes), nil)
|
||||
for j, u := range nodes {
|
||||
uid := u.ID()
|
||||
to := g.From(u)
|
||||
to := g.From(uid)
|
||||
if len(to) == 0 {
|
||||
continue
|
||||
}
|
||||
|
@@ -152,7 +152,7 @@ func TestDiffuse(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -278,7 +278,7 @@ func TestRandomWalkLaplacian(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -466,7 +466,7 @@ func TestDiffuseToEquilibrium(t *testing.T) {
|
||||
g := test.builder
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -22,12 +22,14 @@ func Closeness(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
nodes := g.Nodes()
|
||||
c := make(map[int64]float64, len(nodes))
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
var sum float64
|
||||
for _, v := range nodes {
|
||||
vid := v.ID()
|
||||
// The ordering here is not relevant for
|
||||
// undirected graphs, but we make sure we
|
||||
// are counting incoming paths.
|
||||
d := p.Weight(v, u)
|
||||
d := p.Weight(vid, uid)
|
||||
if math.IsInf(d, 0) {
|
||||
continue
|
||||
}
|
||||
@@ -49,12 +51,14 @@ func Farness(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
nodes := g.Nodes()
|
||||
f := make(map[int64]float64, len(nodes))
|
||||
for _, u := range nodes {
|
||||
uid := u.ID()
|
||||
var sum float64
|
||||
for _, v := range nodes {
|
||||
vid := v.ID()
|
||||
// The ordering here is not relevant for
|
||||
// undirected graphs, but we make sure we
|
||||
// are counting incoming paths.
|
||||
d := p.Weight(v, u)
|
||||
d := p.Weight(vid, uid)
|
||||
if math.IsInf(d, 0) {
|
||||
continue
|
||||
}
|
||||
@@ -76,12 +80,14 @@ func Harmonic(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
nodes := g.Nodes()
|
||||
h := make(map[int64]float64, len(nodes))
|
||||
for i, u := range nodes {
|
||||
uid := u.ID()
|
||||
var sum float64
|
||||
for j, v := range nodes {
|
||||
vid := v.ID()
|
||||
// The ordering here is not relevant for
|
||||
// undirected graphs, but we make sure we
|
||||
// are counting incoming paths.
|
||||
d := p.Weight(v, u)
|
||||
d := p.Weight(vid, uid)
|
||||
if math.IsInf(d, 0) {
|
||||
continue
|
||||
}
|
||||
@@ -105,12 +111,14 @@ func Residual(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
||||
nodes := g.Nodes()
|
||||
r := make(map[int64]float64, len(nodes))
|
||||
for i, u := range nodes {
|
||||
uid := u.ID()
|
||||
var sum float64
|
||||
for j, v := range nodes {
|
||||
vid := v.ID()
|
||||
// The ordering here is not relevant for
|
||||
// undirected graphs, but we make sure we
|
||||
// are counting incoming paths.
|
||||
d := p.Weight(v, u)
|
||||
d := p.Weight(vid, uid)
|
||||
if math.IsInf(d, 0) {
|
||||
continue
|
||||
}
|
||||
|
@@ -146,7 +146,7 @@ func TestDistanceCentralityUndirected(t *testing.T) {
|
||||
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -336,7 +336,7 @@ func TestDistanceCentralityDirected(t *testing.T) {
|
||||
g := simple.NewWeightedDirectedGraph(0, math.Inf(1))
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -32,10 +32,11 @@ func HITS(g graph.Directed, tol float64) map[int64]HubAuthority {
|
||||
nodesLinkingTo := make([][]int, len(nodes))
|
||||
nodesLinkedFrom := make([][]int, len(nodes))
|
||||
for i, n := range nodes {
|
||||
for _, u := range g.To(n) {
|
||||
id := n.ID()
|
||||
for _, u := range g.To(id) {
|
||||
nodesLinkingTo[i] = append(nodesLinkingTo[i], indexOf[u.ID()])
|
||||
}
|
||||
for _, v := range g.From(n) {
|
||||
for _, v := range g.From(id) {
|
||||
nodesLinkedFrom[i] = append(nodesLinkedFrom[i], indexOf[v.ID()])
|
||||
}
|
||||
}
|
||||
|
@@ -46,7 +46,7 @@ func TestHITS(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -35,7 +35,7 @@ func PageRank(g graph.Directed, damp, tol float64) map[int64]float64 {
|
||||
m := mat.NewDense(len(nodes), len(nodes), nil)
|
||||
dangling := damp / float64(len(nodes))
|
||||
for j, u := range nodes {
|
||||
to := g.From(u)
|
||||
to := g.From(u.ID())
|
||||
f := damp / float64(len(to))
|
||||
for _, v := range to {
|
||||
m.Set(indexOf[v.ID()], j, f)
|
||||
@@ -109,7 +109,7 @@ func PageRankSparse(g graph.Directed, damp, tol float64) map[int64]float64 {
|
||||
var dangling compressedRow
|
||||
df := damp / float64(len(nodes))
|
||||
for j, u := range nodes {
|
||||
to := g.From(u)
|
||||
to := g.From(u.ID())
|
||||
f := damp / float64(len(to))
|
||||
for _, v := range to {
|
||||
m.addTo(indexOf[v.ID()], j, f)
|
||||
|
@@ -84,7 +84,7 @@ func TestPageRank(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -108,7 +108,7 @@ func TestPageRankSparse(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -24,7 +24,7 @@ import (
|
||||
// falling back to NullHeuristic otherwise. If the graph does not implement graph.Weighter,
|
||||
// UniformCost is used. AStar will panic if g has an A*-reachable negative edge weight.
|
||||
func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded int) {
|
||||
if !g.Has(s) || !g.Has(t) {
|
||||
if !g.Has(s.ID()) || !g.Has(t.ID()) {
|
||||
return Shortest{from: s}, 0
|
||||
}
|
||||
var weight Weighting
|
||||
@@ -59,14 +59,14 @@ func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded
|
||||
}
|
||||
|
||||
visited.Add(uid)
|
||||
for _, v := range g.From(u.node) {
|
||||
for _, v := range g.From(u.node.ID()) {
|
||||
vid := v.ID()
|
||||
if visited.Has(vid) {
|
||||
continue
|
||||
}
|
||||
j := path.indexOf[vid]
|
||||
|
||||
w, ok := weight(u.node, v)
|
||||
w, ok := weight(u.node.ID(), vid)
|
||||
if !ok {
|
||||
panic("A*: unexpected invalid weight")
|
||||
}
|
||||
|
@@ -129,7 +129,7 @@ func TestAStar(t *testing.T) {
|
||||
for _, test := range aStarTests {
|
||||
pt, _ := AStar(simple.Node(test.s), simple.Node(test.t), test.g, test.heuristic)
|
||||
|
||||
p, cost := pt.To(simple.Node(test.t))
|
||||
p, cost := pt.To(test.t)
|
||||
|
||||
if !topo.IsPathIn(test.g, p) {
|
||||
t.Errorf("got path that is not path in input graph for %q", test.name)
|
||||
@@ -139,7 +139,7 @@ func TestAStar(t *testing.T) {
|
||||
if !ok {
|
||||
t.Fatalf("unexpected negative cycle in %q", test.name)
|
||||
}
|
||||
if want := bfp.WeightTo(simple.Node(test.t)); cost != want {
|
||||
if want := bfp.WeightTo(test.t); cost != want {
|
||||
t.Errorf("unexpected cost for %q: got:%v want:%v", test.name, cost, want)
|
||||
}
|
||||
|
||||
@@ -196,8 +196,8 @@ func TestExhaustiveAStar(t *testing.T) {
|
||||
for _, start := range g.Nodes() {
|
||||
for _, goal := range g.Nodes() {
|
||||
pt, _ := AStar(start, goal, g, heuristic)
|
||||
gotPath, gotWeight := pt.To(goal)
|
||||
wantPath, wantWeight, _ := ps.Between(start, goal)
|
||||
gotPath, gotWeight := pt.To(goal.ID())
|
||||
wantPath, wantWeight, _ := ps.Between(start.ID(), goal.ID())
|
||||
if gotWeight != wantWeight {
|
||||
t.Errorf("unexpected path weight from %v to %v result: got:%f want:%f",
|
||||
start, goal, gotWeight, wantWeight)
|
||||
@@ -231,7 +231,7 @@ func isMonotonic(g UndirectedWeightLister, h Heuristic) (ok bool, at graph.Edge,
|
||||
for _, edge := range g.WeightedEdges() {
|
||||
from := edge.From()
|
||||
to := edge.To()
|
||||
w, ok := g.Weight(from, to)
|
||||
w, ok := g.Weight(from.ID(), to.ID())
|
||||
if !ok {
|
||||
panic("A*: unexpected invalid weight")
|
||||
}
|
||||
@@ -275,12 +275,12 @@ func TestAStarNullHeuristic(t *testing.T) {
|
||||
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
||||
}
|
||||
|
||||
p, weight := pt.To(test.Query.To())
|
||||
p, weight := pt.To(test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
|
||||
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
@@ -301,7 +301,7 @@ func TestAStarNullHeuristic(t *testing.T) {
|
||||
test.Name, p, test.WantPaths)
|
||||
}
|
||||
|
||||
np, weight := pt.To(test.NoPathFor.To())
|
||||
np, weight := pt.To(test.NoPathFor.To().ID())
|
||||
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||
test.Name, np, weight)
|
||||
|
@@ -12,7 +12,7 @@ import "gonum.org/v1/gonum/graph"
|
||||
//
|
||||
// The time complexity of BellmanFordFrom is O(|V|.|E|).
|
||||
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
||||
if !g.Has(u) {
|
||||
if !g.Has(u.ID()) {
|
||||
return Shortest{from: u}, true
|
||||
}
|
||||
var weight Weighting
|
||||
@@ -32,9 +32,11 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
||||
for i := 1; i < len(nodes); i++ {
|
||||
changed := false
|
||||
for j, u := range nodes {
|
||||
for _, v := range g.From(u) {
|
||||
k := path.indexOf[v.ID()]
|
||||
w, ok := weight(u, v)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
k := path.indexOf[vid]
|
||||
w, ok := weight(uid, vid)
|
||||
if !ok {
|
||||
panic("bellman-ford: unexpected invalid weight")
|
||||
}
|
||||
@@ -51,9 +53,11 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
||||
}
|
||||
|
||||
for j, u := range nodes {
|
||||
for _, v := range g.From(u) {
|
||||
k := path.indexOf[v.ID()]
|
||||
w, ok := weight(u, v)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
k := path.indexOf[vid]
|
||||
w, ok := weight(uid, vid)
|
||||
if !ok {
|
||||
panic("bellman-ford: unexpected invalid weight")
|
||||
}
|
||||
|
@@ -35,12 +35,12 @@ func TestBellmanFordFrom(t *testing.T) {
|
||||
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
||||
}
|
||||
|
||||
p, weight := pt.To(test.Query.To())
|
||||
p, weight := pt.To(test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
|
||||
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
@@ -61,7 +61,7 @@ func TestBellmanFordFrom(t *testing.T) {
|
||||
test.Name, p, test.WantPaths)
|
||||
}
|
||||
|
||||
np, weight := pt.To(test.NoPathFor.To())
|
||||
np, weight := pt.To(test.NoPathFor.To().ID())
|
||||
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||
test.Name, np, weight)
|
||||
|
@@ -201,7 +201,7 @@ func BenchmarkRandomGraphDominators(b *testing.B) {
|
||||
if v == nil {
|
||||
v = unordered[ui][rnd.Intn(len(unordered[ui]))]
|
||||
}
|
||||
if !g.HasEdgeFromTo(u, v) {
|
||||
if !g.HasEdgeFromTo(u.ID(), v.ID()) {
|
||||
g.SetEdge(g.NewEdge(u, v))
|
||||
}
|
||||
}
|
||||
@@ -253,16 +253,16 @@ type undirected struct {
|
||||
*simple.DirectedGraph
|
||||
}
|
||||
|
||||
func (g undirected) From(n graph.Node) []graph.Node {
|
||||
return append(g.DirectedGraph.From(n), g.DirectedGraph.To(n)...)
|
||||
func (g undirected) From(id int64) []graph.Node {
|
||||
return append(g.DirectedGraph.From(id), g.DirectedGraph.To(id)...)
|
||||
}
|
||||
|
||||
func (g undirected) HasEdgeBetween(x, y graph.Node) bool {
|
||||
return g.DirectedGraph.HasEdgeFromTo(x, y)
|
||||
func (g undirected) HasEdgeBetween(xid, yid int64) bool {
|
||||
return g.DirectedGraph.HasEdgeFromTo(xid, yid)
|
||||
}
|
||||
|
||||
func (g undirected) EdgeBetween(x, y graph.Node) graph.Edge {
|
||||
return g.DirectedGraph.Edge(x, y)
|
||||
func (g undirected) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
return g.DirectedGraph.Edge(xid, yid)
|
||||
}
|
||||
|
||||
func (g undirected) SetEdge(e graph.Edge) {
|
||||
|
@@ -140,7 +140,7 @@ func (lt *lengauerTarjan) dfs(g graph.Directed, v graph.Node) {
|
||||
ltv.label = ltv
|
||||
lt.nodes = append(lt.nodes, ltv)
|
||||
|
||||
for _, w := range g.From(v) {
|
||||
for _, w := range g.From(v.ID()) {
|
||||
wid := w.ID()
|
||||
|
||||
idx, ok := lt.indexOf[wid]
|
||||
|
@@ -162,7 +162,7 @@ func (lt *sLengauerTarjan) dfs(g graph.Directed, v graph.Node) {
|
||||
ltv.label = ltv
|
||||
lt.nodes = append(lt.nodes, ltv)
|
||||
|
||||
for _, w := range g.From(v) {
|
||||
for _, w := range g.From(v.ID()) {
|
||||
wid := w.ID()
|
||||
|
||||
idx, ok := lt.indexOf[wid]
|
||||
|
@@ -16,7 +16,7 @@ import (
|
||||
//
|
||||
// The time complexity of DijkstrFrom is O(|E|.log|V|).
|
||||
func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
|
||||
if !g.Has(u) {
|
||||
if !g.Has(u.ID()) {
|
||||
return Shortest{from: u}
|
||||
}
|
||||
var weight Weighting
|
||||
@@ -46,9 +46,11 @@ func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
|
||||
if mid.dist > path.dist[k] {
|
||||
continue
|
||||
}
|
||||
for _, v := range g.From(mid.node) {
|
||||
j := path.indexOf[v.ID()]
|
||||
w, ok := weight(mid.node, v)
|
||||
mnid := mid.node.ID()
|
||||
for _, v := range g.From(mnid) {
|
||||
vid := v.ID()
|
||||
j := path.indexOf[vid]
|
||||
w, ok := weight(mnid, vid)
|
||||
if !ok {
|
||||
panic("dijkstra: unexpected invalid weight")
|
||||
}
|
||||
@@ -106,9 +108,11 @@ func dijkstraAllPaths(g graph.Graph, paths AllShortest) {
|
||||
if mid.dist < paths.dist.At(i, k) {
|
||||
paths.dist.Set(i, k, mid.dist)
|
||||
}
|
||||
for _, v := range g.From(mid.node) {
|
||||
j := paths.indexOf[v.ID()]
|
||||
w, ok := weight(mid.node, v)
|
||||
mnid := mid.node.ID()
|
||||
for _, v := range g.From(mnid) {
|
||||
vid := v.ID()
|
||||
j := paths.indexOf[vid]
|
||||
w, ok := weight(mnid, vid)
|
||||
if !ok {
|
||||
panic("dijkstra: unexpected invalid weight")
|
||||
}
|
||||
|
@@ -47,12 +47,12 @@ func TestDijkstraFrom(t *testing.T) {
|
||||
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
||||
}
|
||||
|
||||
p, weight := pt.To(test.Query.To())
|
||||
p, weight := pt.To(test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
|
||||
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func TestDijkstraFrom(t *testing.T) {
|
||||
test.Name, p, test.WantPaths)
|
||||
}
|
||||
|
||||
np, weight := pt.To(test.NoPathFor.To())
|
||||
np, weight := pt.To(test.NoPathFor.To().ID())
|
||||
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||
test.Name, np, weight)
|
||||
@@ -111,12 +111,12 @@ func TestDijkstraAllPaths(t *testing.T) {
|
||||
|
||||
// Check all random paths returned are OK.
|
||||
for i := 0; i < 10; i++ {
|
||||
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
|
||||
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
|
||||
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
@@ -142,13 +142,13 @@ func TestDijkstraAllPaths(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
|
||||
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||
if np != nil || !math.IsInf(weight, 1) || unique {
|
||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
||||
test.Name, np, weight, unique)
|
||||
}
|
||||
|
||||
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
|
||||
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
@@ -169,7 +169,7 @@ func TestDijkstraAllPaths(t *testing.T) {
|
||||
test.Name, got, test.WantPaths)
|
||||
}
|
||||
|
||||
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
|
||||
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||
if nps != nil || !math.IsInf(weight, 1) {
|
||||
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||
test.Name, nps, weight)
|
||||
|
@@ -99,12 +99,14 @@ func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel
|
||||
}
|
||||
}
|
||||
for _, u := range d.model.Nodes() {
|
||||
for _, v := range g.From(u) {
|
||||
w := edgeWeight(d.weight, u, v)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
w := edgeWeight(d.weight, uid, vid)
|
||||
if w < 0 {
|
||||
panic("D* Lite: negative edge weight")
|
||||
}
|
||||
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: d.model.Node(v.ID()), W: w})
|
||||
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: d.model.Node(vid), W: w})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,8 +122,8 @@ func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel
|
||||
// edgeWeight is a helper function that returns the weight of the edge between
|
||||
// two connected nodes, u and v, using the provided weight function. It panics
|
||||
// if there is no edge between u and v.
|
||||
func edgeWeight(weight path.Weighting, u, v graph.Node) float64 {
|
||||
w, ok := weight(u, v)
|
||||
func edgeWeight(weight path.Weighting, uid, vid int64) float64 {
|
||||
w, ok := weight(uid, vid)
|
||||
if !ok {
|
||||
panic("D* Lite: unexpected invalid weight")
|
||||
}
|
||||
@@ -187,29 +189,33 @@ func (d *DStarLite) findShortestPath() {
|
||||
if !u.key.less(d.keyFor(d.s)) && d.s.rhs <= d.s.g {
|
||||
break
|
||||
}
|
||||
uid := u.ID()
|
||||
switch kNew := d.keyFor(u); {
|
||||
case u.key.less(kNew):
|
||||
d.queue.update(u, kNew)
|
||||
case u.g > u.rhs:
|
||||
u.g = u.rhs
|
||||
d.queue.remove(u)
|
||||
for _, _s := range d.model.To(u) {
|
||||
for _, _s := range d.model.To(uid) {
|
||||
s := _s.(*dStarLiteNode)
|
||||
if s.ID() != d.t.ID() {
|
||||
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, s, u)+u.g)
|
||||
sid := s.ID()
|
||||
if sid != d.t.ID() {
|
||||
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, uid)+u.g)
|
||||
}
|
||||
d.update(s)
|
||||
}
|
||||
default:
|
||||
gOld := u.g
|
||||
u.g = math.Inf(1)
|
||||
for _, _s := range append(d.model.To(u), u) {
|
||||
for _, _s := range append(d.model.To(uid), u) {
|
||||
s := _s.(*dStarLiteNode)
|
||||
if s.rhs == edgeWeight(d.model.Weight, s, u)+gOld {
|
||||
sid := s.ID()
|
||||
if s.rhs == edgeWeight(d.model.Weight, sid, uid)+gOld {
|
||||
if s.ID() != d.t.ID() {
|
||||
s.rhs = math.Inf(1)
|
||||
for _, t := range d.model.From(s) {
|
||||
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, s, t)+t.(*dStarLiteNode).g)
|
||||
for _, t := range d.model.From(sid) {
|
||||
tid := t.ID()
|
||||
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, tid)+t.(*dStarLiteNode).g)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -243,9 +249,10 @@ func (d *DStarLite) Step() bool {
|
||||
min := math.Inf(1)
|
||||
|
||||
var next *dStarLiteNode
|
||||
for _, _s := range d.model.From(d.s) {
|
||||
dsid := d.s.ID()
|
||||
for _, _s := range d.model.From(dsid) {
|
||||
s := _s.(*dStarLiteNode)
|
||||
w := edgeWeight(d.model.Weight, d.s, s) + s.g
|
||||
w := edgeWeight(d.model.Weight, dsid, s.ID()) + s.g
|
||||
if w < min || (w == min && s.rhs < rhs) {
|
||||
next = s
|
||||
min = w
|
||||
@@ -294,24 +301,27 @@ func (d *DStarLite) UpdateWorld(changes []graph.Edge) {
|
||||
d.last = d.s
|
||||
for _, e := range changes {
|
||||
from := e.From()
|
||||
fid := from.ID()
|
||||
to := e.To()
|
||||
c, _ := d.weight(from, to)
|
||||
tid := to.ID()
|
||||
c, _ := d.weight(fid, tid)
|
||||
if c < 0 {
|
||||
panic("D* Lite: negative edge weight")
|
||||
}
|
||||
cOld, _ := d.model.Weight(from, to)
|
||||
cOld, _ := d.model.Weight(fid, tid)
|
||||
u := d.worldNodeFor(from)
|
||||
v := d.worldNodeFor(to)
|
||||
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: v, W: c})
|
||||
uid := u.ID()
|
||||
if cOld > c {
|
||||
if u.ID() != d.t.ID() {
|
||||
if uid != d.t.ID() {
|
||||
u.rhs = math.Min(u.rhs, c+v.g)
|
||||
}
|
||||
} else if u.rhs == cOld+v.g {
|
||||
if u.ID() != d.t.ID() {
|
||||
if uid != d.t.ID() {
|
||||
u.rhs = math.Inf(1)
|
||||
for _, t := range d.model.From(u) {
|
||||
u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, u, t)+t.(*dStarLiteNode).g)
|
||||
for _, t := range d.model.From(uid) {
|
||||
u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, uid, t.ID())+t.(*dStarLiteNode).g)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -354,9 +364,11 @@ func (d *DStarLite) Path() (p []graph.Node, weight float64) {
|
||||
next *dStarLiteNode
|
||||
cost float64
|
||||
)
|
||||
for _, _v := range d.model.From(u) {
|
||||
uid := u.ID()
|
||||
for _, _v := range d.model.From(uid) {
|
||||
v := _v.(*dStarLiteNode)
|
||||
w := edgeWeight(d.model.Weight, u, v)
|
||||
vid := v.ID()
|
||||
w := edgeWeight(d.model.Weight, uid, vid)
|
||||
if rhs := w + v.g; rhs < min || (rhs == min && v.rhs < rhsMin) {
|
||||
next = v
|
||||
min = rhs
|
||||
|
@@ -389,7 +389,8 @@ var dynamicDStarLiteTests = []struct {
|
||||
all := l.Grid.AllVisible
|
||||
l.Grid.AllVisible = false
|
||||
for _, n := range l.Nodes() {
|
||||
l.Known[n.ID()] = !l.Grid.Has(n)
|
||||
id := n.ID()
|
||||
l.Known[id] = !l.Grid.Has(id)
|
||||
}
|
||||
l.Grid.AllVisible = all
|
||||
|
||||
@@ -401,19 +402,21 @@ var dynamicDStarLiteTests = []struct {
|
||||
|
||||
// Check we have a correctly modified representation.
|
||||
for _, u := range l.Nodes() {
|
||||
uid := u.ID()
|
||||
for _, v := range l.Nodes() {
|
||||
if l.HasEdgeBetween(u, v) != l.Grid.HasEdgeBetween(u, v) {
|
||||
ur, uc := l.RowCol(u.ID())
|
||||
vr, vc := l.RowCol(v.ID())
|
||||
vid := v.ID()
|
||||
if l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) {
|
||||
ur, uc := l.RowCol(uid)
|
||||
vr, vc := l.RowCol(vid)
|
||||
if (ur == wallRow && uc == wallCol) || (vr == wallRow && vc == wallCol) {
|
||||
if !l.HasEdgeBetween(u, v) {
|
||||
if !l.HasEdgeBetween(uid, vid) {
|
||||
panic(fmt.Sprintf("expected to believe edge between %v (%d,%d) and %v (%d,%d) is passable",
|
||||
u, v, ur, uc, vr, vc))
|
||||
}
|
||||
continue
|
||||
}
|
||||
panic(fmt.Sprintf("disagreement about edge between %v (%d,%d) and %v (%d,%d): got:%t want:%t",
|
||||
u, v, ur, uc, vr, vc, l.HasEdgeBetween(u, v), l.Grid.HasEdgeBetween(u, v)))
|
||||
u, v, ur, uc, vr, vc, l.HasEdgeBetween(uid, vid), l.Grid.HasEdgeBetween(uid, vid)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -574,8 +577,8 @@ func TestDStarLiteDynamic(t *testing.T) {
|
||||
l.MoveTo(test.s)
|
||||
|
||||
heuristic := func(a, b graph.Node) float64 {
|
||||
ax, ay := l.XY(a)
|
||||
bx, by := l.XY(b)
|
||||
ax, ay := l.XY(a.ID())
|
||||
bx, by := l.XY(b.ID())
|
||||
return test.heuristic(ax-bx, ay-by)
|
||||
}
|
||||
|
||||
@@ -657,7 +660,7 @@ func weightOf(path []graph.Node, g graph.Weighted) float64 {
|
||||
var w float64
|
||||
if len(path) > 1 {
|
||||
for p, n := range path[1:] {
|
||||
ew, ok := g.Weight(path[p], n)
|
||||
ew, ok := g.Weight(path[p].ID(), n.ID())
|
||||
if !ok {
|
||||
return math.Inf(1)
|
||||
}
|
||||
@@ -673,7 +676,7 @@ func simpleWeightedEdgesOf(g graph.Weighted, edges []graph.Edge) []simple.Weight
|
||||
for i, e := range edges {
|
||||
w[i].F = e.From()
|
||||
w[i].T = e.To()
|
||||
ew, _ := g.Weight(e.From(), e.To())
|
||||
ew, _ := g.Weight(e.From().ID(), e.To().ID())
|
||||
w[i].W = ew
|
||||
}
|
||||
return w
|
||||
|
@@ -61,7 +61,7 @@ func (d *dumper) dump(withpath bool) {
|
||||
switch ln {
|
||||
case 0:
|
||||
if n.ID() == d.grid.Location.ID() {
|
||||
if d.grid.Grid.HasOpen(n) {
|
||||
if d.grid.Grid.HasOpen(n.ID()) {
|
||||
fmt.Fprintf(w, "id:%2d >@<", n.ID())
|
||||
} else {
|
||||
// Mark location as illegal.
|
||||
@@ -70,19 +70,19 @@ func (d *dumper) dump(withpath bool) {
|
||||
} else if n.ID() == d.dStarLite.t.ID() {
|
||||
fmt.Fprintf(w, "id:%2d G", n.ID())
|
||||
// Mark goal cell as illegal.
|
||||
if !d.grid.Grid.HasOpen(n) {
|
||||
if !d.grid.Grid.HasOpen(n.ID()) {
|
||||
fmt.Fprint(w, "!")
|
||||
}
|
||||
} else if pathStep[n.ID()] > 0 {
|
||||
fmt.Fprintf(w, "id:%2d %2d", n.ID(), pathStep[n.ID()])
|
||||
// Mark path cells with an obstruction.
|
||||
if !d.grid.Grid.HasOpen(n) {
|
||||
if !d.grid.Grid.HasOpen(n.ID()) {
|
||||
fmt.Fprint(w, "!")
|
||||
}
|
||||
} else {
|
||||
fmt.Fprintf(w, "id:%2d", n.ID())
|
||||
// Mark cells with an obstruction.
|
||||
if !d.grid.Grid.HasOpen(n) {
|
||||
if !d.grid.Grid.HasOpen(n.ID()) {
|
||||
fmt.Fprint(w, " *")
|
||||
}
|
||||
}
|
||||
|
@@ -23,9 +23,11 @@ func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
|
||||
paths = newAllShortest(nodes, true)
|
||||
for i, u := range nodes {
|
||||
paths.dist.Set(i, i, 0)
|
||||
for _, v := range g.From(u) {
|
||||
j := paths.indexOf[v.ID()]
|
||||
w, ok := weight(u, v)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
j := paths.indexOf[vid]
|
||||
w, ok := weight(uid, vid)
|
||||
if !ok {
|
||||
panic("floyd-warshall: unexpected invalid weight")
|
||||
}
|
||||
|
@@ -35,12 +35,12 @@ func TestFloydWarshall(t *testing.T) {
|
||||
|
||||
// Check all random paths returned are OK.
|
||||
for i := 0; i < 10; i++ {
|
||||
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
|
||||
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
|
||||
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
@@ -66,13 +66,13 @@ func TestFloydWarshall(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
|
||||
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||
if np != nil || !math.IsInf(weight, 1) || unique {
|
||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
||||
test.Name, np, weight, unique)
|
||||
}
|
||||
|
||||
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
|
||||
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
@@ -93,7 +93,7 @@ func TestFloydWarshall(t *testing.T) {
|
||||
test.Name, got, test.WantPaths)
|
||||
}
|
||||
|
||||
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
|
||||
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||
if nps != nil || !math.IsInf(weight, 1) {
|
||||
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||
test.Name, nps, weight)
|
||||
|
@@ -104,17 +104,12 @@ func (g *Grid) Nodes() []graph.Node {
|
||||
// Has returns whether n is a node in the grid. The state of
|
||||
// the AllVisible field determines whether a non-open node is
|
||||
// present.
|
||||
func (g *Grid) Has(n graph.Node) bool {
|
||||
return g.has(n.ID())
|
||||
}
|
||||
|
||||
func (g *Grid) has(id int64) bool {
|
||||
func (g *Grid) Has(id int64) bool {
|
||||
return 0 <= id && id < int64(len(g.open)) && (g.AllVisible || g.open[id])
|
||||
}
|
||||
|
||||
// HasOpen returns whether n is an open node in the grid.
|
||||
func (g *Grid) HasOpen(n graph.Node) bool {
|
||||
id := n.ID()
|
||||
func (g *Grid) HasOpen(id int64) bool {
|
||||
return 0 <= id && id < int64(len(g.open)) && g.open[id]
|
||||
}
|
||||
|
||||
@@ -145,11 +140,11 @@ func (g *Grid) RowCol(id int64) (r, c int) {
|
||||
|
||||
// XY returns the cartesian coordinates of n. If n is not a node
|
||||
// in the grid, (NaN, NaN) is returned.
|
||||
func (g *Grid) XY(n graph.Node) (x, y float64) {
|
||||
if !g.Has(n) {
|
||||
func (g *Grid) XY(id int64) (x, y float64) {
|
||||
if !g.Has(id) {
|
||||
return math.NaN(), math.NaN()
|
||||
}
|
||||
r, c := g.RowCol(n.ID())
|
||||
r, c := g.RowCol(id)
|
||||
return float64(c), float64(r)
|
||||
}
|
||||
|
||||
@@ -163,15 +158,15 @@ func (g *Grid) NodeAt(r, c int) graph.Node {
|
||||
|
||||
// From returns all the nodes reachable from u. Reachabilty requires that both
|
||||
// ends of an edge must be open.
|
||||
func (g *Grid) From(u graph.Node) []graph.Node {
|
||||
if !g.HasOpen(u) {
|
||||
func (g *Grid) From(uid int64) []graph.Node {
|
||||
if !g.HasOpen(uid) {
|
||||
return nil
|
||||
}
|
||||
nr, nc := g.RowCol(u.ID())
|
||||
nr, nc := g.RowCol(uid)
|
||||
var to []graph.Node
|
||||
for r := nr - 1; r <= nr+1; r++ {
|
||||
for c := nc - 1; c <= nc+1; c++ {
|
||||
if v := g.NodeAt(r, c); v != nil && g.HasEdgeBetween(u, v) {
|
||||
if v := g.NodeAt(r, c); v != nil && g.HasEdgeBetween(uid, v.ID()) {
|
||||
to = append(to, v)
|
||||
}
|
||||
}
|
||||
@@ -180,12 +175,12 @@ func (g *Grid) From(u graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether there is an edge between u and v.
|
||||
func (g *Grid) HasEdgeBetween(u, v graph.Node) bool {
|
||||
if !g.HasOpen(u) || !g.HasOpen(v) || u.ID() == v.ID() {
|
||||
func (g *Grid) HasEdgeBetween(uid, vid int64) bool {
|
||||
if !g.HasOpen(uid) || !g.HasOpen(vid) || uid == vid {
|
||||
return false
|
||||
}
|
||||
ur, uc := g.RowCol(u.ID())
|
||||
vr, vc := g.RowCol(v.ID())
|
||||
ur, uc := g.RowCol(uid)
|
||||
vr, vc := g.RowCol(vid)
|
||||
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
||||
return false
|
||||
}
|
||||
@@ -200,47 +195,47 @@ func abs(i int) int {
|
||||
}
|
||||
|
||||
// Edge returns the edge between u and v.
|
||||
func (g *Grid) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *Grid) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge between u and v.
|
||||
func (g *Grid) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *Grid) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between u and v.
|
||||
func (g *Grid) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *Grid) EdgeBetween(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween returns the weighted edge between u and v.
|
||||
func (g *Grid) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
|
||||
if g.HasEdgeBetween(u, v) {
|
||||
func (g *Grid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
|
||||
if g.HasEdgeBetween(uid, vid) {
|
||||
if !g.AllowDiagonal || g.UnitEdgeWeight {
|
||||
return simple.WeightedEdge{F: u, T: v, W: 1}
|
||||
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: 1}
|
||||
}
|
||||
ux, uy := g.XY(u)
|
||||
vx, vy := g.XY(v)
|
||||
return simple.WeightedEdge{F: u, T: v, W: math.Hypot(ux-vx, uy-vy)}
|
||||
ux, uy := g.XY(uid)
|
||||
vx, vy := g.XY(vid)
|
||||
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Weight returns the weight of the given edge.
|
||||
func (g *Grid) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
if x.ID() == y.ID() {
|
||||
func (g *Grid) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if xid == yid {
|
||||
return 0, true
|
||||
}
|
||||
if !g.HasEdgeBetween(x, y) {
|
||||
if !g.HasEdgeBetween(xid, yid) {
|
||||
return math.Inf(1), false
|
||||
}
|
||||
if e := g.EdgeBetween(x, y); e != nil {
|
||||
if e := g.EdgeBetween(xid, yid); e != nil {
|
||||
if !g.AllowDiagonal || g.UnitEdgeWeight {
|
||||
return 1, true
|
||||
}
|
||||
ux, uy := g.XY(e.From())
|
||||
vx, vy := g.XY(e.To())
|
||||
ux, uy := g.XY(e.From().ID())
|
||||
vx, vy := g.XY(e.To().ID())
|
||||
return math.Hypot(ux-vx, uy-vy), true
|
||||
}
|
||||
return math.Inf(1), true
|
||||
@@ -274,15 +269,15 @@ func (g *Grid) Render(path []graph.Node) ([]byte, error) {
|
||||
// We don't use topo.IsPathIn at the outset because we
|
||||
// want to draw as much as possible before failing.
|
||||
for i, n := range path {
|
||||
if !g.Has(n) || (i != 0 && !g.HasEdgeBetween(path[i-1], n)) {
|
||||
id := n.ID()
|
||||
id := n.ID()
|
||||
if !g.Has(id) || (i != 0 && !g.HasEdgeBetween(path[i-1].ID(), id)) {
|
||||
if 0 <= id && id < int64(len(g.open)) {
|
||||
r, c := g.RowCol(n.ID())
|
||||
r, c := g.RowCol(id)
|
||||
b[r*(g.c+1)+c] = '!'
|
||||
}
|
||||
return b, errors.New("grid: not a path in graph")
|
||||
}
|
||||
r, c := g.RowCol(n.ID())
|
||||
r, c := g.RowCol(id)
|
||||
switch i {
|
||||
case len(path) - 1:
|
||||
b[r*(g.c+1)+c] = 'G'
|
||||
|
@@ -249,7 +249,7 @@ func TestGrid(t *testing.T) {
|
||||
}
|
||||
for _, test := range reach {
|
||||
g.AllowDiagonal = test.diagonal
|
||||
got := g.From(test.from)
|
||||
got := g.From(test.from.ID())
|
||||
if !reflect.DeepEqual(got, test.to) {
|
||||
t.Fatalf("unexpected nodes from %d with allow diagonal=%t:\ngot: %v\nwant:%v",
|
||||
test.from, test.diagonal, got, test.to)
|
||||
|
@@ -47,23 +47,25 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
|
||||
if u == nil {
|
||||
continue
|
||||
}
|
||||
ux, uy := l.XY(u)
|
||||
uid := u.ID()
|
||||
ux, uy := l.XY(uid)
|
||||
if math.Hypot(x-ux, y-uy) > l.VisionRadius {
|
||||
continue
|
||||
}
|
||||
for _, v := range l.allPossibleFrom(u) {
|
||||
if seen[[2]int64{u.ID(), v.ID()}] {
|
||||
for _, v := range l.allPossibleFrom(uid) {
|
||||
vid := v.ID()
|
||||
if seen[[2]int64{uid, vid}] {
|
||||
continue
|
||||
}
|
||||
seen[[2]int64{u.ID(), v.ID()}] = true
|
||||
seen[[2]int64{uid, vid}] = true
|
||||
|
||||
vx, vy := l.XY(v)
|
||||
if !l.Known[v.ID()] && math.Hypot(x-vx, y-vy) > l.VisionRadius {
|
||||
vx, vy := l.XY(vid)
|
||||
if !l.Known[vid] && math.Hypot(x-vx, y-vy) > l.VisionRadius {
|
||||
continue
|
||||
}
|
||||
|
||||
e := simple.Edge{F: u, T: v}
|
||||
if !l.Known[u.ID()] || !l.Known[v.ID()] {
|
||||
if !l.Known[uid] || !l.Known[vid] {
|
||||
new = append(new, e)
|
||||
} else {
|
||||
old = append(old, e)
|
||||
@@ -79,18 +81,20 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
|
||||
if u == nil {
|
||||
continue
|
||||
}
|
||||
ux, uy := l.XY(u)
|
||||
uid := u.ID()
|
||||
ux, uy := l.XY(uid)
|
||||
if math.Hypot(x-ux, y-uy) > l.VisionRadius {
|
||||
continue
|
||||
}
|
||||
for _, v := range l.allPossibleFrom(u) {
|
||||
vx, vy := l.XY(v)
|
||||
for _, v := range l.allPossibleFrom(uid) {
|
||||
vid := v.ID()
|
||||
vx, vy := l.XY(vid)
|
||||
if math.Hypot(x-vx, y-vy) > l.VisionRadius {
|
||||
continue
|
||||
}
|
||||
l.Known[v.ID()] = true
|
||||
l.Known[vid] = true
|
||||
}
|
||||
l.Known[u.ID()] = true
|
||||
l.Known[uid] = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,19 +104,19 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
|
||||
}
|
||||
|
||||
// allPossibleFrom returns all the nodes possibly reachable from u.
|
||||
func (l *LimitedVisionGrid) allPossibleFrom(u graph.Node) []graph.Node {
|
||||
if !l.Has(u) {
|
||||
func (l *LimitedVisionGrid) allPossibleFrom(uid int64) []graph.Node {
|
||||
if !l.Has(uid) {
|
||||
return nil
|
||||
}
|
||||
nr, nc := l.RowCol(u.ID())
|
||||
nr, nc := l.RowCol(uid)
|
||||
var to []graph.Node
|
||||
for r := nr - 1; r <= nr+1; r++ {
|
||||
for c := nc - 1; c <= nc+1; c++ {
|
||||
v := l.NodeAt(r, c)
|
||||
if v == nil || u.ID() == v.ID() {
|
||||
if v == nil || uid == v.ID() {
|
||||
continue
|
||||
}
|
||||
ur, uc := l.RowCol(u.ID())
|
||||
ur, uc := l.RowCol(uid)
|
||||
vr, vc := l.RowCol(v.ID())
|
||||
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
||||
continue
|
||||
@@ -134,11 +138,11 @@ func (l *LimitedVisionGrid) RowCol(id int64) (r, c int) {
|
||||
|
||||
// XY returns the cartesian coordinates of n. If n is not a node
|
||||
// in the grid, (NaN, NaN) is returned.
|
||||
func (l *LimitedVisionGrid) XY(n graph.Node) (x, y float64) {
|
||||
if !l.Has(n) {
|
||||
func (l *LimitedVisionGrid) XY(id int64) (x, y float64) {
|
||||
if !l.Has(id) {
|
||||
return math.NaN(), math.NaN()
|
||||
}
|
||||
r, c := l.RowCol(n.ID())
|
||||
r, c := l.RowCol(id)
|
||||
return float64(c), float64(r)
|
||||
}
|
||||
|
||||
@@ -157,25 +161,21 @@ func (l *LimitedVisionGrid) NodeAt(r, c int) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether n is a node in the grid.
|
||||
func (l *LimitedVisionGrid) Has(n graph.Node) bool {
|
||||
return l.has(n.ID())
|
||||
}
|
||||
|
||||
func (l *LimitedVisionGrid) has(id int64) bool {
|
||||
func (l *LimitedVisionGrid) Has(id int64) bool {
|
||||
return 0 <= id && id < int64(len(l.Grid.open))
|
||||
}
|
||||
|
||||
// From returns nodes that are optimistically reachable from u.
|
||||
func (l *LimitedVisionGrid) From(u graph.Node) []graph.Node {
|
||||
if !l.Has(u) {
|
||||
func (l *LimitedVisionGrid) From(uid int64) []graph.Node {
|
||||
if !l.Has(uid) {
|
||||
return nil
|
||||
}
|
||||
|
||||
nr, nc := l.RowCol(u.ID())
|
||||
nr, nc := l.RowCol(uid)
|
||||
var to []graph.Node
|
||||
for r := nr - 1; r <= nr+1; r++ {
|
||||
for c := nc - 1; c <= nc+1; c++ {
|
||||
if v := l.NodeAt(r, c); v != nil && l.HasEdgeBetween(u, v) {
|
||||
if v := l.NodeAt(r, c); v != nil && l.HasEdgeBetween(uid, v.ID()) {
|
||||
to = append(to, v)
|
||||
}
|
||||
}
|
||||
@@ -184,12 +184,12 @@ func (l *LimitedVisionGrid) From(u graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween optimistically returns whether an edge is exists between u and v.
|
||||
func (l *LimitedVisionGrid) HasEdgeBetween(u, v graph.Node) bool {
|
||||
if u.ID() == v.ID() {
|
||||
func (l *LimitedVisionGrid) HasEdgeBetween(uid, vid int64) bool {
|
||||
if uid == vid {
|
||||
return false
|
||||
}
|
||||
ur, uc := l.RowCol(u.ID())
|
||||
vr, vc := l.RowCol(v.ID())
|
||||
ur, uc := l.RowCol(uid)
|
||||
vr, vc := l.RowCol(vid)
|
||||
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
||||
return false
|
||||
}
|
||||
@@ -197,66 +197,66 @@ func (l *LimitedVisionGrid) HasEdgeBetween(u, v graph.Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
x, y := l.XY(l.Location)
|
||||
ux, uy := l.XY(u)
|
||||
vx, vy := l.XY(v)
|
||||
uKnown := l.Known[u.ID()] || math.Hypot(x-ux, y-uy) <= l.VisionRadius
|
||||
vKnown := l.Known[v.ID()] || math.Hypot(x-vx, y-vy) <= l.VisionRadius
|
||||
x, y := l.XY(l.Location.ID())
|
||||
ux, uy := l.XY(uid)
|
||||
vx, vy := l.XY(vid)
|
||||
uKnown := l.Known[uid] || math.Hypot(x-ux, y-uy) <= l.VisionRadius
|
||||
vKnown := l.Known[vid] || math.Hypot(x-vx, y-vy) <= l.VisionRadius
|
||||
|
||||
switch {
|
||||
case uKnown && vKnown:
|
||||
return l.Grid.HasEdgeBetween(u, v)
|
||||
return l.Grid.HasEdgeBetween(uid, vid)
|
||||
case uKnown:
|
||||
return l.Grid.HasOpen(u)
|
||||
return l.Grid.HasOpen(uid)
|
||||
case vKnown:
|
||||
return l.Grid.HasOpen(v)
|
||||
return l.Grid.HasOpen(vid)
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Edge optimistically returns the edge from u to v.
|
||||
func (l *LimitedVisionGrid) Edge(u, v graph.Node) graph.Edge {
|
||||
return l.WeightedEdgeBetween(u, v)
|
||||
func (l *LimitedVisionGrid) Edge(uid, vid int64) graph.Edge {
|
||||
return l.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// Edge optimistically returns the weighted edge from u to v.
|
||||
func (l *LimitedVisionGrid) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
return l.WeightedEdgeBetween(u, v)
|
||||
func (l *LimitedVisionGrid) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
return l.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween optimistically returns the edge between u and v.
|
||||
func (l *LimitedVisionGrid) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
return l.WeightedEdgeBetween(u, v)
|
||||
func (l *LimitedVisionGrid) EdgeBetween(uid, vid int64) graph.Edge {
|
||||
return l.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween optimistically returns the weighted edge between u and v.
|
||||
func (l *LimitedVisionGrid) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
|
||||
if l.HasEdgeBetween(u, v) {
|
||||
func (l *LimitedVisionGrid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
|
||||
if l.HasEdgeBetween(uid, vid) {
|
||||
if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight {
|
||||
return simple.WeightedEdge{F: u, T: v, W: 1}
|
||||
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: 1}
|
||||
}
|
||||
ux, uy := l.XY(u)
|
||||
vx, vy := l.XY(v)
|
||||
return simple.WeightedEdge{F: u, T: v, W: math.Hypot(ux-vx, uy-vy)}
|
||||
ux, uy := l.XY(uid)
|
||||
vx, vy := l.XY(vid)
|
||||
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Weight returns the weight of the given edge.
|
||||
func (l *LimitedVisionGrid) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
if x.ID() == y.ID() {
|
||||
func (l *LimitedVisionGrid) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if xid == yid {
|
||||
return 0, true
|
||||
}
|
||||
if !l.HasEdgeBetween(x, y) {
|
||||
if !l.HasEdgeBetween(xid, yid) {
|
||||
return math.Inf(1), false
|
||||
}
|
||||
if e := l.EdgeBetween(x, y); e != nil {
|
||||
if e := l.EdgeBetween(xid, yid); e != nil {
|
||||
if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight {
|
||||
return 1, true
|
||||
}
|
||||
ux, uy := l.XY(e.From())
|
||||
vx, vy := l.XY(e.To())
|
||||
ux, uy := l.XY(e.From().ID())
|
||||
vx, vy := l.XY(e.To().ID())
|
||||
return math.Hypot(ux-vx, uy-vy), true
|
||||
|
||||
}
|
||||
@@ -294,15 +294,15 @@ func (l *LimitedVisionGrid) Render(path []graph.Node) ([]byte, error) {
|
||||
// We don't use topo.IsPathIn at the outset because we
|
||||
// want to draw as much as possible before failing.
|
||||
for i, n := range path {
|
||||
if !l.Has(n) || (i != 0 && !l.HasEdgeBetween(path[i-1], n)) {
|
||||
id := n.ID()
|
||||
id := n.ID()
|
||||
if !l.Has(id) || (i != 0 && !l.HasEdgeBetween(path[i-1].ID(), id)) {
|
||||
if 0 <= id && id < int64(len(l.Grid.open)) {
|
||||
r, c := l.RowCol(n.ID())
|
||||
r, c := l.RowCol(id)
|
||||
b[r*(cols+1)+c] = '!'
|
||||
}
|
||||
return b, errors.New("grid: not a path in graph")
|
||||
}
|
||||
r, c := l.RowCol(n.ID())
|
||||
r, c := l.RowCol(id)
|
||||
switch i {
|
||||
case len(path) - 1:
|
||||
b[r*(cols+1)+c] = 'G'
|
||||
|
@@ -1165,23 +1165,25 @@ func TestLimitedVisionGrid(t *testing.T) {
|
||||
}
|
||||
l.Grid.AllowDiagonal = test.diag
|
||||
|
||||
x, y := l.XY(test.path[0])
|
||||
x, y := l.XY(test.path[0].ID())
|
||||
for _, u := range l.Nodes() {
|
||||
ux, uy := l.XY(u)
|
||||
uid := u.ID()
|
||||
ux, uy := l.XY(uid)
|
||||
uNear := math.Hypot(x-ux, y-uy) <= test.radius
|
||||
for _, v := range l.Nodes() {
|
||||
vx, vy := l.XY(v)
|
||||
vid := v.ID()
|
||||
vx, vy := l.XY(vid)
|
||||
vNear := math.Hypot(x-vx, y-vy) <= test.radius
|
||||
if u.ID() == v.ID() && l.HasEdgeBetween(u, v) {
|
||||
if u.ID() == v.ID() && l.HasEdgeBetween(uid, vid) {
|
||||
t.Errorf("unexpected self edge: %v -- %v", u, v)
|
||||
}
|
||||
if !uNear && !vNear && !l.HasEdgeBetween(u, v) && couldConnectIn(l, u, v) {
|
||||
if !uNear && !vNear && !l.HasEdgeBetween(uid, vid) && couldConnectIn(l, uid, vid) {
|
||||
t.Errorf("unexpected pessimism: no hope in distant edge between %v and %v for test %d",
|
||||
u, v, i)
|
||||
}
|
||||
if (uNear && vNear) && l.HasEdgeBetween(u, v) != l.Grid.HasEdgeBetween(u, v) {
|
||||
if (uNear && vNear) && l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) {
|
||||
t.Errorf("unrealistic optimism: disagreement about edge between %v and %v for test %d: got:%t want:%t",
|
||||
u, v, i, l.HasEdgeBetween(u, v), l.Grid.HasEdgeBetween(u, v))
|
||||
u, v, i, l.HasEdgeBetween(uid, vid), l.Grid.HasEdgeBetween(uid, vid))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1205,7 +1207,7 @@ func asConcreteEdges(changes []graph.Edge, in graph.Weighted) []simple.WeightedE
|
||||
for i, e := range changes {
|
||||
we[i].F = e.From()
|
||||
we[i].T = e.To()
|
||||
w, ok := in.Weight(e.From(), e.To())
|
||||
w, ok := in.Weight(e.From().ID(), e.To().ID())
|
||||
if !ok && !math.IsInf(w, 1) {
|
||||
panic("unexpected invalid finite weight")
|
||||
}
|
||||
@@ -1214,13 +1216,13 @@ func asConcreteEdges(changes []graph.Edge, in graph.Weighted) []simple.WeightedE
|
||||
return we
|
||||
}
|
||||
|
||||
func couldConnectIn(l *LimitedVisionGrid, u, v graph.Node) bool {
|
||||
if u.ID() == v.ID() {
|
||||
func couldConnectIn(l *LimitedVisionGrid, uid, vid int64) bool {
|
||||
if uid == vid {
|
||||
return false
|
||||
}
|
||||
|
||||
ur, uc := l.RowCol(u.ID())
|
||||
vr, vc := l.RowCol(v.ID())
|
||||
ur, uc := l.RowCol(uid)
|
||||
vr, vc := l.RowCol(vid)
|
||||
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
||||
return false
|
||||
}
|
||||
@@ -1228,13 +1230,13 @@ func couldConnectIn(l *LimitedVisionGrid, u, v graph.Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if !l.Known[u.ID()] && !l.Known[v.ID()] {
|
||||
if !l.Known[uid] && !l.Known[vid] {
|
||||
return true
|
||||
}
|
||||
if l.Known[u.ID()] && !l.Grid.HasOpen(u) {
|
||||
if l.Known[uid] && !l.Grid.HasOpen(uid) {
|
||||
return false
|
||||
}
|
||||
if l.Known[v.ID()] && !l.Grid.HasOpen(v) {
|
||||
if l.Known[vid] && !l.Grid.HasOpen(vid) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@@ -52,12 +52,12 @@ func JohnsonAllPaths(g graph.Graph) (paths AllShortest, ok bool) {
|
||||
dijkstraAllPaths(jg, paths)
|
||||
|
||||
for i, u := range paths.nodes {
|
||||
hu := jg.adjustBy.WeightTo(u)
|
||||
hu := jg.adjustBy.WeightTo(u.ID())
|
||||
for j, v := range paths.nodes {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
hv := jg.adjustBy.WeightTo(v)
|
||||
hv := jg.adjustBy.WeightTo(v.ID())
|
||||
paths.dist.Set(i, j, paths.dist.At(i, j)-hu+hv)
|
||||
}
|
||||
}
|
||||
@@ -69,8 +69,8 @@ type johnsonWeightAdjuster struct {
|
||||
q int64
|
||||
g graph.Graph
|
||||
|
||||
from func(graph.Node) []graph.Node
|
||||
edgeTo func(graph.Node, graph.Node) graph.Edge
|
||||
from func(id int64) []graph.Node
|
||||
edgeTo func(uid, vid int64) graph.Edge
|
||||
weight Weighting
|
||||
|
||||
bellmanFord bool
|
||||
@@ -86,11 +86,11 @@ var (
|
||||
_ graph.Weighted = johnsonWeightAdjuster{}
|
||||
)
|
||||
|
||||
func (g johnsonWeightAdjuster) Has(n graph.Node) bool {
|
||||
if g.bellmanFord && n.ID() == g.q {
|
||||
func (g johnsonWeightAdjuster) Has(id int64) bool {
|
||||
if g.bellmanFord && id == g.q {
|
||||
return true
|
||||
}
|
||||
return g.g.Has(n)
|
||||
return g.g.Has(id)
|
||||
|
||||
}
|
||||
|
||||
@@ -101,40 +101,40 @@ func (g johnsonWeightAdjuster) Nodes() []graph.Node {
|
||||
return g.g.Nodes()
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) From(n graph.Node) []graph.Node {
|
||||
if g.bellmanFord && n.ID() == g.q {
|
||||
func (g johnsonWeightAdjuster) From(id int64) []graph.Node {
|
||||
if g.bellmanFord && id == g.q {
|
||||
return g.g.Nodes()
|
||||
}
|
||||
return g.from(n)
|
||||
return g.from(id)
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
func (g johnsonWeightAdjuster) WeightedEdge(_, _ int64) graph.WeightedEdge {
|
||||
panic("path: unintended use of johnsonWeightAdjuster")
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) Edge(u, v graph.Node) graph.Edge {
|
||||
if g.bellmanFord && u.ID() == g.q && g.g.Has(v) {
|
||||
return simple.Edge{F: johnsonGraphNode(g.q), T: v}
|
||||
func (g johnsonWeightAdjuster) Edge(uid, vid int64) graph.Edge {
|
||||
if g.bellmanFord && uid == g.q && g.g.Has(vid) {
|
||||
return simple.Edge{F: johnsonGraphNode(g.q), T: simple.Node(vid)}
|
||||
}
|
||||
return g.edgeTo(u, v)
|
||||
return g.edgeTo(uid, vid)
|
||||
}
|
||||
|
||||
func (g johnsonWeightAdjuster) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
func (g johnsonWeightAdjuster) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if g.bellmanFord {
|
||||
switch g.q {
|
||||
case x.ID():
|
||||
case xid:
|
||||
return 0, true
|
||||
case y.ID():
|
||||
case yid:
|
||||
return math.Inf(1), false
|
||||
default:
|
||||
return g.weight(x, y)
|
||||
return g.weight(xid, yid)
|
||||
}
|
||||
}
|
||||
w, ok = g.weight(x, y)
|
||||
return w + g.adjustBy.WeightTo(x) - g.adjustBy.WeightTo(y), ok
|
||||
w, ok = g.weight(xid, yid)
|
||||
return w + g.adjustBy.WeightTo(xid) - g.adjustBy.WeightTo(yid), ok
|
||||
}
|
||||
|
||||
func (johnsonWeightAdjuster) HasEdgeBetween(_, _ graph.Node) bool {
|
||||
func (johnsonWeightAdjuster) HasEdgeBetween(_, _ int64) bool {
|
||||
panic("path: unintended use of johnsonWeightAdjuster")
|
||||
}
|
||||
|
||||
|
@@ -35,12 +35,12 @@ func TestJohnsonAllPaths(t *testing.T) {
|
||||
|
||||
// Check all random paths returned are OK.
|
||||
for i := 0; i < 10; i++ {
|
||||
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
|
||||
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
|
||||
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
}
|
||||
@@ -66,13 +66,13 @@ func TestJohnsonAllPaths(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
|
||||
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||
if np != nil || !math.IsInf(weight, 1) || unique {
|
||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
||||
test.Name, np, weight, unique)
|
||||
}
|
||||
|
||||
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
|
||||
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
|
||||
if weight != test.Weight {
|
||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||
test.Name, weight, test.Weight)
|
||||
@@ -93,7 +93,7 @@ func TestJohnsonAllPaths(t *testing.T) {
|
||||
test.Name, got, test.WantPaths)
|
||||
}
|
||||
|
||||
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
|
||||
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||
if nps != nil || !math.IsInf(weight, 1) {
|
||||
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||
test.Name, nps, weight)
|
||||
|
@@ -47,7 +47,7 @@ func ExampleBellmanFordFrom_negativecycles() {
|
||||
return
|
||||
}
|
||||
for _, n := range []simple.Node{'a', 'b', 'c', 'd', 'e', 'f'} {
|
||||
p, w := pt.To(n)
|
||||
p, w := pt.To(n.ID())
|
||||
if math.IsNaN(w) {
|
||||
fmt.Printf("negative cycle in path to %c path:%c\n", n, p)
|
||||
}
|
||||
|
@@ -93,8 +93,8 @@ func (p Shortest) From() graph.Node { return p.from }
|
||||
|
||||
// WeightTo returns the weight of the minimum path to v. If the path to v includes
|
||||
// a negative cycle, the returned weight will not reflect the true path weight.
|
||||
func (p Shortest) WeightTo(v graph.Node) float64 {
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
func (p Shortest) WeightTo(vid int64) float64 {
|
||||
to, toOK := p.indexOf[vid]
|
||||
if !toOK {
|
||||
return math.Inf(1)
|
||||
}
|
||||
@@ -104,8 +104,8 @@ func (p Shortest) WeightTo(v graph.Node) float64 {
|
||||
// To returns a shortest path to v and the weight of the path. If the path
|
||||
// to v includes a negative cycle, one pass through the cycle will be included
|
||||
// in path and weight will be returned as NaN.
|
||||
func (p Shortest) To(v graph.Node) (path []graph.Node, weight float64) {
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
func (p Shortest) To(vid int64) (path []graph.Node, weight float64) {
|
||||
to, toOK := p.indexOf[vid]
|
||||
if !toOK || math.IsInf(p.dist[to], 1) {
|
||||
return nil, math.Inf(1)
|
||||
}
|
||||
@@ -136,7 +136,7 @@ func (p Shortest) To(v graph.Node) (path []graph.Node, weight float64) {
|
||||
}
|
||||
}
|
||||
ordered.Reverse(path)
|
||||
return path, math.Min(weight, p.dist[p.indexOf[v.ID()]])
|
||||
return path, math.Min(weight, p.dist[p.indexOf[vid]])
|
||||
}
|
||||
|
||||
// AllShortest is a shortest-path tree created by the DijkstraAllPaths, FloydWarshall
|
||||
@@ -221,9 +221,9 @@ loop: // These are likely to be rare, so just loop over collisions.
|
||||
}
|
||||
|
||||
// Weight returns the weight of the minimum path between u and v.
|
||||
func (p AllShortest) Weight(u, v graph.Node) float64 {
|
||||
from, fromOK := p.indexOf[u.ID()]
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
func (p AllShortest) Weight(uid, vid int64) float64 {
|
||||
from, fromOK := p.indexOf[uid]
|
||||
to, toOK := p.indexOf[vid]
|
||||
if !fromOK || !toOK {
|
||||
return math.Inf(1)
|
||||
}
|
||||
@@ -234,11 +234,11 @@ func (p AllShortest) Weight(u, v graph.Node) float64 {
|
||||
// one shortest path exists between u and v, a randomly chosen path will be returned and
|
||||
// unique is returned false. If a cycle with zero weight exists in the path, it will not
|
||||
// be included, but unique will be returned false.
|
||||
func (p AllShortest) Between(u, v graph.Node) (path []graph.Node, weight float64, unique bool) {
|
||||
from, fromOK := p.indexOf[u.ID()]
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) {
|
||||
from, fromOK := p.indexOf[uid]
|
||||
to, toOK := p.indexOf[vid]
|
||||
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
|
||||
if u.ID() == v.ID() {
|
||||
if uid == vid {
|
||||
return []graph.Node{p.nodes[from]}, 0, true
|
||||
}
|
||||
return nil, math.Inf(1), false
|
||||
@@ -290,11 +290,11 @@ func (p AllShortest) Between(u, v graph.Node) (path []graph.Node, weight float64
|
||||
|
||||
// AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
|
||||
// containing zero-weight cycles are not returned.
|
||||
func (p AllShortest) AllBetween(u, v graph.Node) (paths [][]graph.Node, weight float64) {
|
||||
from, fromOK := p.indexOf[u.ID()]
|
||||
to, toOK := p.indexOf[v.ID()]
|
||||
func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) {
|
||||
from, fromOK := p.indexOf[uid]
|
||||
to, toOK := p.indexOf[vid]
|
||||
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
|
||||
if u.ID() == v.ID() {
|
||||
if uid == vid {
|
||||
return [][]graph.Node{{p.nodes[from]}}, 0
|
||||
}
|
||||
return nil, math.Inf(1)
|
||||
@@ -302,9 +302,9 @@ func (p AllShortest) AllBetween(u, v graph.Node) (paths [][]graph.Node, weight f
|
||||
|
||||
var n graph.Node
|
||||
if p.forward {
|
||||
n = u
|
||||
n = p.nodes[from]
|
||||
} else {
|
||||
n = v
|
||||
n = p.nodes[to]
|
||||
}
|
||||
seen := make([]bool, len(p.nodes))
|
||||
paths = p.allBetween(from, to, seen, []graph.Node{n}, nil)
|
||||
|
@@ -48,8 +48,9 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
|
||||
}
|
||||
|
||||
u := nodes[0]
|
||||
for _, v := range g.From(u) {
|
||||
w, ok := g.Weight(u, v)
|
||||
uid := u.ID()
|
||||
for _, v := range g.From(uid) {
|
||||
w, ok := g.Weight(uid, v.ID())
|
||||
if !ok {
|
||||
panic("prim: unexpected invalid weight")
|
||||
}
|
||||
@@ -59,15 +60,16 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
|
||||
var w float64
|
||||
for q.Len() > 0 {
|
||||
e := heap.Pop(q).(simple.WeightedEdge)
|
||||
if e.To() != nil && g.HasEdgeBetween(e.From(), e.To()) {
|
||||
dst.SetWeightedEdge(g.WeightedEdge(e.From(), e.To()))
|
||||
if e.To() != nil && g.HasEdgeBetween(e.From().ID(), e.To().ID()) {
|
||||
dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID()))
|
||||
w += e.Weight()
|
||||
}
|
||||
|
||||
u = e.From()
|
||||
for _, n := range g.From(u) {
|
||||
uid := u.ID()
|
||||
for _, n := range g.From(uid) {
|
||||
if key, ok := q.key(n); ok {
|
||||
w, ok := g.Weight(u, n)
|
||||
w, ok := g.Weight(uid, n.ID())
|
||||
if !ok {
|
||||
panic("prim: unexpected invalid weight")
|
||||
}
|
||||
@@ -173,7 +175,7 @@ func Kruskal(dst WeightedBuilder, g UndirectedWeightLister) float64 {
|
||||
for _, e := range edges {
|
||||
if s1, s2 := ds.find(e.From().ID()), ds.find(e.To().ID()); s1 != s2 {
|
||||
ds.union(s1, s2)
|
||||
dst.SetWeightedEdge(g.WeightedEdge(e.From(), e.To()))
|
||||
dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID()))
|
||||
w += e.Weight()
|
||||
}
|
||||
}
|
||||
|
@@ -268,7 +268,7 @@ func testMinumumSpanning(mst func(dst WeightedBuilder, g spanningGraph) float64,
|
||||
test.name, len(gotEdges), len(test.treeEdges))
|
||||
}
|
||||
for _, e := range test.treeEdges {
|
||||
w, ok := dst.Weight(e.From(), e.To())
|
||||
w, ok := dst.Weight(e.From().ID(), e.To().ID())
|
||||
if !ok {
|
||||
t.Errorf("spanning tree edge not found in graph for %q: %+v",
|
||||
test.name, e)
|
||||
|
@@ -12,18 +12,16 @@ import (
|
||||
|
||||
// Weighting is a mapping between a pair of nodes and a weight. It follows the
|
||||
// semantics of the Weighter interface.
|
||||
type Weighting func(x, y graph.Node) (w float64, ok bool)
|
||||
type Weighting func(xid, yid int64) (w float64, ok bool)
|
||||
|
||||
// UniformCost returns a Weighting that returns an edge cost of 1 for existing
|
||||
// edges, zero for node identity and Inf for otherwise absent edges.
|
||||
func UniformCost(g graph.Graph) Weighting {
|
||||
return func(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
return func(xid, yid int64) (w float64, ok bool) {
|
||||
if xid == yid {
|
||||
return 0, true
|
||||
}
|
||||
if e := g.Edge(x, y); e != nil {
|
||||
if e := g.Edge(xid, yid); e != nil {
|
||||
return 1, true
|
||||
}
|
||||
return math.Inf(1), false
|
||||
|
@@ -75,8 +75,8 @@ func (g *DirectedMatrix) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *DirectedMatrix) Has(n graph.Node) bool {
|
||||
return g.has(n.ID())
|
||||
func (g *DirectedMatrix) Has(id int64) bool {
|
||||
return g.has(id)
|
||||
}
|
||||
|
||||
func (g *DirectedMatrix) has(id int64) bool {
|
||||
@@ -117,8 +117,7 @@ func (g *DirectedMatrix) Edges() []graph.Edge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedMatrix) From(n graph.Node) []graph.Node {
|
||||
id := n.ID()
|
||||
func (g *DirectedMatrix) From(id int64) []graph.Node {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
}
|
||||
@@ -137,8 +136,7 @@ func (g *DirectedMatrix) From(n graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedMatrix) To(n graph.Node) []graph.Node {
|
||||
id := n.ID()
|
||||
func (g *DirectedMatrix) To(id int64) []graph.Node {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
}
|
||||
@@ -158,12 +156,10 @@ func (g *DirectedMatrix) To(n graph.Node) []graph.Node {
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
// considering direction.
|
||||
func (g *DirectedMatrix) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
func (g *DirectedMatrix) HasEdgeBetween(xid, yid int64) bool {
|
||||
if !g.has(xid) {
|
||||
return false
|
||||
}
|
||||
yid := y.ID()
|
||||
if !g.has(yid) {
|
||||
return false
|
||||
}
|
||||
@@ -173,27 +169,25 @@ func (g *DirectedMatrix) HasEdgeBetween(x, y graph.Node) bool {
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *DirectedMatrix) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdge(u, v)
|
||||
func (g *DirectedMatrix) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdge(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *DirectedMatrix) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
if g.HasEdgeFromTo(u, v) {
|
||||
// x.ID() and y.ID() are not greater than maximum int by this point.
|
||||
return WeightedEdge{F: g.Node(u.ID()), T: g.Node(v.ID()), W: g.mat.At(int(u.ID()), int(v.ID()))}
|
||||
func (g *DirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
if g.HasEdgeFromTo(uid, vid) {
|
||||
// xid and yid are not greater than maximum int by this point.
|
||||
return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||
func (g *DirectedMatrix) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
uid := u.ID()
|
||||
func (g *DirectedMatrix) HasEdgeFromTo(uid, vid int64) bool {
|
||||
if !g.has(uid) {
|
||||
return false
|
||||
}
|
||||
vid := v.ID()
|
||||
if !g.has(vid) {
|
||||
return false
|
||||
}
|
||||
@@ -205,9 +199,7 @@ func (g *DirectedMatrix) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
||||
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g *DirectedMatrix) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *DirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if xid == yid {
|
||||
return g.self, true
|
||||
}
|
||||
@@ -262,8 +254,7 @@ func (g *DirectedMatrix) RemoveEdge(e graph.Edge) {
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *DirectedMatrix) Degree(n graph.Node) int {
|
||||
id := n.ID()
|
||||
func (g *DirectedMatrix) Degree(id int64) int {
|
||||
if !g.has(id) {
|
||||
return 0
|
||||
}
|
||||
|
@@ -75,8 +75,8 @@ func (g *UndirectedMatrix) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *UndirectedMatrix) Has(n graph.Node) bool {
|
||||
return g.has(n.ID())
|
||||
func (g *UndirectedMatrix) Has(id int64) bool {
|
||||
return g.has(id)
|
||||
}
|
||||
|
||||
func (g *UndirectedMatrix) has(id int64) bool {
|
||||
@@ -114,8 +114,7 @@ func (g *UndirectedMatrix) Edges() []graph.Edge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedMatrix) From(n graph.Node) []graph.Node {
|
||||
id := n.ID()
|
||||
func (g *UndirectedMatrix) From(id int64) []graph.Node {
|
||||
if !g.has(id) {
|
||||
return nil
|
||||
}
|
||||
@@ -134,12 +133,10 @@ func (g *UndirectedMatrix) From(n graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g *UndirectedMatrix) HasEdgeBetween(u, v graph.Node) bool {
|
||||
uid := u.ID()
|
||||
func (g *UndirectedMatrix) HasEdgeBetween(uid, vid int64) bool {
|
||||
if !g.has(uid) {
|
||||
return false
|
||||
}
|
||||
vid := v.ID()
|
||||
if !g.has(vid) {
|
||||
return false
|
||||
}
|
||||
@@ -149,26 +146,26 @@ func (g *UndirectedMatrix) HasEdgeBetween(u, v graph.Node) bool {
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *UndirectedMatrix) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *UndirectedMatrix) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *UndirectedMatrix) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *UndirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
func (g *UndirectedMatrix) EdgeBetween(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *UndirectedMatrix) EdgeBetween(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||
func (g *UndirectedMatrix) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
|
||||
if g.HasEdgeBetween(u, v) {
|
||||
// u.ID() and v.ID() are not greater than maximum int by this point.
|
||||
return WeightedEdge{F: g.Node(u.ID()), T: g.Node(v.ID()), W: g.mat.At(int(u.ID()), int(v.ID()))}
|
||||
func (g *UndirectedMatrix) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
|
||||
if g.HasEdgeBetween(uid, vid) {
|
||||
// uid and vid are not greater than maximum int by this point.
|
||||
return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -177,9 +174,7 @@ func (g *UndirectedMatrix) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEd
|
||||
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
||||
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g *UndirectedMatrix) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *UndirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if xid == yid {
|
||||
return g.self, true
|
||||
}
|
||||
@@ -234,8 +229,7 @@ func (g *UndirectedMatrix) RemoveEdge(e graph.Edge) {
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *UndirectedMatrix) Degree(n graph.Node) int {
|
||||
id := n.ID()
|
||||
func (g *UndirectedMatrix) Degree(id int64) int {
|
||||
if !g.has(id) {
|
||||
return 0
|
||||
}
|
||||
|
@@ -34,17 +34,17 @@ func TestBasicDenseImpassable(t *testing.T) {
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
if !dg.Has(Node(i)) {
|
||||
if !dg.Has(int64(i)) {
|
||||
t.Errorf("Node that should exist doesn't: %d", i)
|
||||
}
|
||||
|
||||
if degree := dg.Degree(Node(i)); degree != 0 {
|
||||
if degree := dg.Degree(int64(i)); degree != 0 {
|
||||
t.Errorf("Node in impassable graph has a neighbor. Node: %d Degree: %d", i, degree)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 5; i < 10; i++ {
|
||||
if dg.Has(Node(i)) {
|
||||
if dg.Has(int64(i)) {
|
||||
t.Errorf("Node exists that shouldn't: %d", i)
|
||||
}
|
||||
}
|
||||
@@ -57,17 +57,17 @@ func TestBasicDensePassable(t *testing.T) {
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
if !dg.Has(Node(i)) {
|
||||
if !dg.Has(int64(i)) {
|
||||
t.Errorf("Node that should exist doesn't: %d", i)
|
||||
}
|
||||
|
||||
if degree := dg.Degree(Node(i)); degree != 4 {
|
||||
if degree := dg.Degree(int64(i)); degree != 4 {
|
||||
t.Errorf("Node in passable graph missing neighbors. Node: %d Degree: %d", i, degree)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 5; i < 10; i++ {
|
||||
if dg.Has(Node(i)) {
|
||||
if dg.Has(int64(i)) {
|
||||
t.Errorf("Node exists that shouldn't: %d", i)
|
||||
}
|
||||
}
|
||||
@@ -77,29 +77,29 @@ func TestDirectedDenseAddRemove(t *testing.T) {
|
||||
dg := NewDirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
|
||||
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 1})
|
||||
|
||||
if neighbors := dg.From(Node(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||
dg.Edge(Node(0), Node(2)) == nil {
|
||||
if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||
dg.Edge(int64(0), int64(2)) == nil {
|
||||
t.Errorf("Adding edge didn't create successor")
|
||||
}
|
||||
|
||||
dg.RemoveEdge(Edge{F: Node(0), T: Node(2)})
|
||||
|
||||
if neighbors := dg.From(Node(0)); len(neighbors) != 0 || dg.Edge(Node(0), Node(2)) != nil {
|
||||
if neighbors := dg.From(int64(0)); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
|
||||
t.Errorf("Removing edge didn't properly remove successor")
|
||||
}
|
||||
|
||||
if neighbors := dg.To(Node(2)); len(neighbors) != 0 || dg.Edge(Node(0), Node(2)) != nil {
|
||||
if neighbors := dg.To(int64(2)); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
|
||||
t.Errorf("Removing directed edge wrongly kept predecessor")
|
||||
}
|
||||
|
||||
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 2})
|
||||
// I figure we've torture tested From/To at this point
|
||||
// so we'll just use the bool functions now
|
||||
if dg.Edge(Node(0), Node(2)) == nil {
|
||||
if dg.Edge(int64(0), int64(2)) == nil {
|
||||
t.Fatal("Adding directed edge didn't change successor back")
|
||||
}
|
||||
c1, _ := dg.Weight(Node(2), Node(0))
|
||||
c2, _ := dg.Weight(Node(0), Node(2))
|
||||
c1, _ := dg.Weight(int64(2), int64(0))
|
||||
c2, _ := dg.Weight(int64(0), int64(2))
|
||||
if c1 == c2 {
|
||||
t.Error("Adding directed edge affected cost in undirected manner")
|
||||
}
|
||||
@@ -109,13 +109,13 @@ func TestUndirectedDenseAddRemove(t *testing.T) {
|
||||
dg := NewUndirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
|
||||
dg.SetEdge(Edge{F: Node(0), T: Node(2)})
|
||||
|
||||
if neighbors := dg.From(Node(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||
dg.EdgeBetween(Node(0), Node(2)) == nil {
|
||||
if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||
dg.EdgeBetween(int64(0), int64(2)) == nil {
|
||||
t.Errorf("Couldn't add neighbor")
|
||||
}
|
||||
|
||||
if neighbors := dg.From(Node(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
|
||||
dg.EdgeBetween(Node(2), Node(0)) == nil {
|
||||
if neighbors := dg.From(int64(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
|
||||
dg.EdgeBetween(int64(2), int64(0)) == nil {
|
||||
t.Errorf("Adding an undirected neighbor didn't add it reciprocally")
|
||||
}
|
||||
}
|
||||
|
@@ -94,10 +94,10 @@ func (g *DirectedGraph) SetEdge(e graph.Edge) {
|
||||
panic("simple: adding self edge")
|
||||
}
|
||||
|
||||
if !g.Has(from) {
|
||||
if !g.Has(fid) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
if !g.Has(to) {
|
||||
if !g.Has(tid) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
|
||||
@@ -126,8 +126,8 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *DirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodes[n.ID()]
|
||||
func (g *DirectedGraph) Has(id int64) bool {
|
||||
_, ok := g.nodes[id]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -157,30 +157,30 @@ func (g *DirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *DirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if _, ok := g.from[n.ID()]; !ok {
|
||||
func (g *DirectedGraph) From(id int64) []graph.Node {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
from := make([]graph.Node, len(g.from[n.ID()]))
|
||||
from := make([]graph.Node, len(g.from[id]))
|
||||
i := 0
|
||||
for id := range g.from[n.ID()] {
|
||||
from[i] = g.nodes[id]
|
||||
for vid := range g.from[id] {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
return from
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
||||
if _, ok := g.from[n.ID()]; !ok {
|
||||
func (g *DirectedGraph) To(id int64) []graph.Node {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
to := make([]graph.Node, len(g.to[n.ID()]))
|
||||
to := make([]graph.Node, len(g.to[id]))
|
||||
i := 0
|
||||
for id := range g.to[n.ID()] {
|
||||
to[i] = g.nodes[id]
|
||||
for uid := range g.to[id] {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
return to
|
||||
@@ -188,9 +188,7 @@ func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
// considering direction.
|
||||
func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
if _, ok := g.from[xid][yid]; ok {
|
||||
return true
|
||||
}
|
||||
@@ -200,8 +198,8 @@ func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
edge, ok := g.from[u.ID()][v.ID()]
|
||||
func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
edge, ok := g.from[uid][vid]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -209,17 +207,17 @@ func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
}
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
if _, ok := g.from[u.ID()][v.ID()]; !ok {
|
||||
func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||
if _, ok := g.from[uid][vid]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *DirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodes[n.ID()]; !ok {
|
||||
func (g *DirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
return len(g.from[n.ID()]) + len(g.to[n.ID()])
|
||||
return len(g.from[id]) + len(g.to[id])
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ var (
|
||||
func TestEdgeOvercounting(t *testing.T) {
|
||||
g := generateDummyGraph()
|
||||
|
||||
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
|
||||
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||
}
|
||||
}
|
||||
|
@@ -86,10 +86,10 @@ func (g *UndirectedGraph) SetEdge(e graph.Edge) {
|
||||
panic("simple: adding self edge")
|
||||
}
|
||||
|
||||
if !g.Has(from) {
|
||||
if !g.Has(fid) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
if !g.Has(to) {
|
||||
if !g.Has(tid) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
|
||||
@@ -118,8 +118,8 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *UndirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodes[n.ID()]
|
||||
func (g *UndirectedGraph) Has(id int64) bool {
|
||||
_, ok := g.nodes[id]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -160,14 +160,14 @@ func (g *UndirectedGraph) Edges() []graph.Edge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if !g.Has(n) {
|
||||
func (g *UndirectedGraph) From(id int64) []graph.Node {
|
||||
if !g.Has(id) {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodes := make([]graph.Node, len(g.edges[n.ID()]))
|
||||
nodes := make([]graph.Node, len(g.edges[id]))
|
||||
i := 0
|
||||
for from := range g.edges[n.ID()] {
|
||||
for from := range g.edges[id] {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
@@ -175,20 +175,20 @@ func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g *UndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
_, ok := g.edges[x.ID()][y.ID()]
|
||||
func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
_, ok := g.edges[xid][yid]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.EdgeBetween(u, v)
|
||||
func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
return g.EdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
||||
edge, ok := g.edges[x.ID()][y.ID()]
|
||||
func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
edge, ok := g.edges[xid][yid]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -196,9 +196,9 @@ func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *UndirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodes[n.ID()]; !ok {
|
||||
func (g *UndirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
return len(g.edges[n.ID()])
|
||||
return len(g.edges[id])
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ func TestMaxID(t *testing.T) {
|
||||
delete(nodes, Node(2))
|
||||
n := g.NewNode()
|
||||
g.AddNode(n)
|
||||
if !g.Has(n) {
|
||||
if !g.Has(n.ID()) {
|
||||
t.Error("added node does not exist in graph")
|
||||
}
|
||||
if _, exists := nodes[n]; exists {
|
||||
|
@@ -100,10 +100,10 @@ func (g *WeightedDirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
|
||||
panic("simple: adding self edge")
|
||||
}
|
||||
|
||||
if !g.Has(from) {
|
||||
if !g.Has(fid) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
if !g.Has(to) {
|
||||
if !g.Has(tid) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
|
||||
@@ -132,8 +132,8 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *WeightedDirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodes[n.ID()]
|
||||
func (g *WeightedDirectedGraph) Has(id int64) bool {
|
||||
_, ok := g.nodes[id]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -174,30 +174,30 @@ func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedDirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if _, ok := g.from[n.ID()]; !ok {
|
||||
func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
from := make([]graph.Node, len(g.from[n.ID()]))
|
||||
from := make([]graph.Node, len(g.from[id]))
|
||||
i := 0
|
||||
for id := range g.from[n.ID()] {
|
||||
from[i] = g.nodes[id]
|
||||
for vid := range g.from[id] {
|
||||
from[i] = g.nodes[vid]
|
||||
i++
|
||||
}
|
||||
return from
|
||||
}
|
||||
|
||||
// To returns all nodes in g that can reach directly to n.
|
||||
func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
|
||||
if _, ok := g.from[n.ID()]; !ok {
|
||||
func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
|
||||
if _, ok := g.from[id]; !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
to := make([]graph.Node, len(g.to[n.ID()]))
|
||||
to := make([]graph.Node, len(g.to[id]))
|
||||
i := 0
|
||||
for id := range g.to[n.ID()] {
|
||||
to[i] = g.nodes[id]
|
||||
for uid := range g.to[id] {
|
||||
to[i] = g.nodes[uid]
|
||||
i++
|
||||
}
|
||||
return to
|
||||
@@ -205,9 +205,7 @@ func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||
// considering direction.
|
||||
func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
if _, ok := g.from[xid][yid]; ok {
|
||||
return true
|
||||
}
|
||||
@@ -217,14 +215,14 @@ func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedDirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdge(u, v)
|
||||
func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdge(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
edge, ok := g.from[u.ID()][v.ID()]
|
||||
func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
edge, ok := g.from[uid][vid]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -232,8 +230,8 @@ func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge
|
||||
}
|
||||
|
||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||
func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
if _, ok := g.from[u.ID()][v.ID()]; !ok {
|
||||
func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||
if _, ok := g.from[uid][vid]; !ok {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -243,9 +241,7 @@ func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
||||
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
||||
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g *WeightedDirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *WeightedDirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if xid == yid {
|
||||
return g.self, true
|
||||
}
|
||||
@@ -258,9 +254,9 @@ func (g *WeightedDirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
}
|
||||
|
||||
// Degree returns the in+out degree of n in g.
|
||||
func (g *WeightedDirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodes[n.ID()]; !ok {
|
||||
func (g *WeightedDirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
return len(g.from[n.ID()]) + len(g.to[n.ID()])
|
||||
return len(g.from[id]) + len(g.to[id])
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ var (
|
||||
func TestWeightedEdgeOvercounting(t *testing.T) {
|
||||
g := generateDummyGraph()
|
||||
|
||||
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
|
||||
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||
}
|
||||
}
|
||||
|
@@ -92,10 +92,10 @@ func (g *WeightedUndirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
|
||||
panic("simple: adding self edge")
|
||||
}
|
||||
|
||||
if !g.Has(from) {
|
||||
if !g.Has(fid) {
|
||||
g.AddNode(from)
|
||||
}
|
||||
if !g.Has(to) {
|
||||
if !g.Has(tid) {
|
||||
g.AddNode(to)
|
||||
}
|
||||
|
||||
@@ -124,8 +124,8 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
|
||||
}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g *WeightedUndirectedGraph) Has(n graph.Node) bool {
|
||||
_, ok := g.nodes[n.ID()]
|
||||
func (g *WeightedUndirectedGraph) Has(id int64) bool {
|
||||
_, ok := g.nodes[id]
|
||||
return ok
|
||||
}
|
||||
|
||||
@@ -185,14 +185,14 @@ func (g *WeightedUndirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
||||
}
|
||||
|
||||
// From returns all nodes in g that can be reached directly from n.
|
||||
func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
|
||||
if !g.Has(n) {
|
||||
func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
|
||||
if !g.Has(id) {
|
||||
return nil
|
||||
}
|
||||
|
||||
nodes := make([]graph.Node, len(g.edges[n.ID()]))
|
||||
nodes := make([]graph.Node, len(g.edges[id]))
|
||||
i := 0
|
||||
for from := range g.edges[n.ID()] {
|
||||
for from := range g.edges[id] {
|
||||
nodes[i] = g.nodes[from]
|
||||
i++
|
||||
}
|
||||
@@ -200,31 +200,31 @@ func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
||||
_, ok := g.edges[x.ID()][y.ID()]
|
||||
func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||
_, ok := g.edges[xid][yid]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedUndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(u, v)
|
||||
func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
||||
return g.WeightedEdgeBetween(x, y)
|
||||
func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||
return g.WeightedEdgeBetween(xid, yid)
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
|
||||
edge, ok := g.edges[x.ID()][y.ID()]
|
||||
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
|
||||
edge, ok := g.edges[xid][yid]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
@@ -235,9 +235,7 @@ func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.Wei
|
||||
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
||||
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
xid := x.ID()
|
||||
yid := y.ID()
|
||||
func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
if xid == yid {
|
||||
return g.self, true
|
||||
}
|
||||
@@ -250,9 +248,9 @@ func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
||||
}
|
||||
|
||||
// Degree returns the degree of n in g.
|
||||
func (g *WeightedUndirectedGraph) Degree(n graph.Node) int {
|
||||
if _, ok := g.nodes[n.ID()]; !ok {
|
||||
func (g *WeightedUndirectedGraph) Degree(id int64) int {
|
||||
if _, ok := g.nodes[id]; !ok {
|
||||
return 0
|
||||
}
|
||||
return len(g.edges[n.ID()])
|
||||
return len(g.edges[id])
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ func TestWeightedMaxID(t *testing.T) {
|
||||
delete(nodes, Node(2))
|
||||
n := g.NewNode()
|
||||
g.AddNode(n)
|
||||
if !g.Has(n) {
|
||||
if !g.Has(n.ID()) {
|
||||
t.Error("added node does not exist in graph")
|
||||
}
|
||||
if _, exists := nodes[n]; exists {
|
||||
|
@@ -123,7 +123,7 @@ func twoSat(r io.Reader) (state map[string]bool, ok bool) {
|
||||
// Check for tautology.
|
||||
if variables[0].negated().ID() == variables[1].ID() {
|
||||
for _, v := range variables {
|
||||
if !g.Has(v) {
|
||||
if !g.Has(v.ID()) {
|
||||
g.AddNode(v)
|
||||
}
|
||||
}
|
||||
|
@@ -60,9 +60,10 @@ func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) {
|
||||
neighbours = make(map[int64][]graph.Node)
|
||||
)
|
||||
for _, n := range nodes {
|
||||
adj := g.From(n)
|
||||
neighbours[n.ID()] = adj
|
||||
dv[n.ID()] = len(adj)
|
||||
id := n.ID()
|
||||
adj := g.From(id)
|
||||
neighbours[id] = adj
|
||||
dv[id] = len(adj)
|
||||
if len(adj) > maxDegree {
|
||||
maxDegree = len(adj)
|
||||
}
|
||||
@@ -146,7 +147,7 @@ func BronKerbosch(g graph.Undirected) [][]graph.Node {
|
||||
order, _ := degeneracyOrdering(g)
|
||||
ordered.Reverse(order)
|
||||
for _, v := range order {
|
||||
neighbours := g.From(v)
|
||||
neighbours := g.From(v.ID())
|
||||
nv := make(set.Nodes, len(neighbours))
|
||||
for _, n := range neighbours {
|
||||
nv.Add(n)
|
||||
@@ -175,7 +176,8 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
|
||||
if nu.Has(v) {
|
||||
continue
|
||||
}
|
||||
neighbours := g.From(v)
|
||||
vid := v.ID()
|
||||
neighbours := g.From(vid)
|
||||
nv := make(set.Nodes, len(neighbours))
|
||||
for _, n := range neighbours {
|
||||
nv.Add(n)
|
||||
@@ -183,7 +185,7 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
|
||||
|
||||
var found bool
|
||||
for _, n := range r {
|
||||
if n.ID() == v.ID() {
|
||||
if n.ID() == vid {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
@@ -205,10 +207,10 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
|
||||
// compile time option.
|
||||
if !tomitaTanakaTakahashi {
|
||||
for _, n := range p {
|
||||
return g.From(n)
|
||||
return g.From(n.ID())
|
||||
}
|
||||
for _, n := range x {
|
||||
return g.From(n)
|
||||
return g.From(n.ID())
|
||||
}
|
||||
panic("bronKerbosch: empty set")
|
||||
}
|
||||
@@ -220,7 +222,7 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
|
||||
maxNeighbors := func(s set.Nodes) {
|
||||
outer:
|
||||
for _, u := range s {
|
||||
nb := g.From(u)
|
||||
nb := g.From(u.ID())
|
||||
c := len(nb)
|
||||
if c <= max {
|
||||
continue
|
||||
|
@@ -53,7 +53,7 @@ func TestDegeneracyOrdering(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -93,7 +93,7 @@ func TestKCore(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -175,7 +175,7 @@ func TestBronKerbosch(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -92,7 +92,7 @@ func TestCliqueGraph(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -142,14 +142,15 @@ func johnsonGraphFrom(g graph.Directed) johnsonGraph {
|
||||
succ: make(map[int64]set.Int64s),
|
||||
}
|
||||
for i, u := range nodes {
|
||||
c.index[u.ID()] = i
|
||||
for _, v := range g.From(u) {
|
||||
if c.succ[u.ID()] == nil {
|
||||
c.succ[u.ID()] = make(set.Int64s)
|
||||
c.nodes.Add(u.ID())
|
||||
uid := u.ID()
|
||||
c.index[uid] = i
|
||||
for _, v := range g.From(uid) {
|
||||
if c.succ[uid] == nil {
|
||||
c.succ[uid] = make(set.Int64s)
|
||||
c.nodes.Add(uid)
|
||||
}
|
||||
c.nodes.Add(v.ID())
|
||||
c.succ[u.ID()].Add(v.ID())
|
||||
c.succ[uid].Add(v.ID())
|
||||
}
|
||||
}
|
||||
return c
|
||||
@@ -247,31 +248,31 @@ func (g johnsonGraph) Nodes() []graph.Node {
|
||||
}
|
||||
|
||||
// Successors is required to satisfy Tarjan.
|
||||
func (g johnsonGraph) From(n graph.Node) []graph.Node {
|
||||
adj := g.succ[n.ID()]
|
||||
func (g johnsonGraph) From(id int64) []graph.Node {
|
||||
adj := g.succ[id]
|
||||
if len(adj) == 0 {
|
||||
return nil
|
||||
}
|
||||
succ := make([]graph.Node, 0, len(adj))
|
||||
for n := range adj {
|
||||
succ = append(succ, johnsonGraphNode(n))
|
||||
for id := range adj {
|
||||
succ = append(succ, johnsonGraphNode(id))
|
||||
}
|
||||
return succ
|
||||
}
|
||||
|
||||
func (johnsonGraph) Has(graph.Node) bool {
|
||||
func (johnsonGraph) Has(int64) bool {
|
||||
panic("topo: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) HasEdgeBetween(_, _ graph.Node) bool {
|
||||
func (johnsonGraph) HasEdgeBetween(_, _ int64) bool {
|
||||
panic("topo: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) Edge(_, _ graph.Node) graph.Edge {
|
||||
func (johnsonGraph) Edge(_, _ int64) graph.Edge {
|
||||
panic("topo: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) HasEdgeFromTo(_, _ graph.Node) bool {
|
||||
func (johnsonGraph) HasEdgeFromTo(_, _ int64) bool {
|
||||
panic("topo: unintended use of johnsonGraph")
|
||||
}
|
||||
func (johnsonGraph) To(graph.Node) []graph.Node {
|
||||
func (johnsonGraph) To(int64) []graph.Node {
|
||||
panic("topo: unintended use of johnsonGraph")
|
||||
}
|
||||
|
||||
|
@@ -88,7 +88,7 @@ func TestDirectedCyclesIn(t *testing.T) {
|
||||
g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -35,7 +35,7 @@ func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
|
||||
u := tree.Pop()
|
||||
uid := u.ID()
|
||||
adj := from[uid]
|
||||
for _, v := range g.From(u) {
|
||||
for _, v := range g.From(uid) {
|
||||
vid := v.ID()
|
||||
switch {
|
||||
case uid == vid:
|
||||
|
@@ -77,7 +77,7 @@ func TestUndirectedCyclesIn(t *testing.T) {
|
||||
g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -95,15 +95,15 @@ func TarjanSCC(g graph.Directed) [][]graph.Node {
|
||||
|
||||
func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
|
||||
nodes := g.Nodes()
|
||||
var succ func(graph.Node) []graph.Node
|
||||
var succ func(id int64) []graph.Node
|
||||
if order == nil {
|
||||
succ = g.From
|
||||
} else {
|
||||
order(nodes)
|
||||
ordered.Reverse(nodes)
|
||||
|
||||
succ = func(n graph.Node) []graph.Node {
|
||||
to := g.From(n)
|
||||
succ = func(id int64) []graph.Node {
|
||||
to := g.From(id)
|
||||
order(to)
|
||||
ordered.Reverse(to)
|
||||
return to
|
||||
@@ -131,7 +131,7 @@ func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.N
|
||||
// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644
|
||||
//
|
||||
type tarjan struct {
|
||||
succ func(graph.Node) []graph.Node
|
||||
succ func(id int64) []graph.Node
|
||||
|
||||
index int
|
||||
indexTable map[int64]int
|
||||
@@ -156,7 +156,7 @@ func (t *tarjan) strongconnect(v graph.Node) {
|
||||
t.onStack.Add(vID)
|
||||
|
||||
// Consider successors of v.
|
||||
for _, w := range t.succ(v) {
|
||||
for _, w := range t.succ(vID) {
|
||||
wID := w.ID()
|
||||
if t.indexTable[wID] == 0 {
|
||||
// Successor w has not yet been visited; recur on it.
|
||||
|
@@ -132,7 +132,7 @@ func TestSort(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -163,7 +163,7 @@ func TestTarjanSCC(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -290,7 +290,7 @@ func TestSortStabilized(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
|
@@ -18,9 +18,9 @@ func IsPathIn(g graph.Graph, path []graph.Node) bool {
|
||||
case 0:
|
||||
return true
|
||||
case 1:
|
||||
return g.Has(path[0])
|
||||
return g.Has(path[0].ID())
|
||||
default:
|
||||
var canReach func(u, v graph.Node) bool
|
||||
var canReach func(uid, vid int64) bool
|
||||
switch g := g.(type) {
|
||||
case graph.Directed:
|
||||
canReach = g.HasEdgeFromTo
|
||||
@@ -29,7 +29,7 @@ func IsPathIn(g graph.Graph, path []graph.Node) bool {
|
||||
}
|
||||
|
||||
for i, u := range path[:len(path)-1] {
|
||||
if !canReach(u, path[i+1]) {
|
||||
if !canReach(u.ID(), path[i+1].ID()) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@@ -71,11 +71,11 @@ func TestPathExistsInUndirected(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
|
||||
for u, e := range test.g {
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
if !g.Has(simple.Node(v)) {
|
||||
if !g.Has(int64(v)) {
|
||||
g.AddNode(simple.Node(v))
|
||||
}
|
||||
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||
@@ -110,11 +110,11 @@ func TestPathExistsInDirected(t *testing.T) {
|
||||
g := simple.NewDirectedGraph()
|
||||
|
||||
for u, e := range test.g {
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
if !g.Has(simple.Node(v)) {
|
||||
if !g.Has(int64(v)) {
|
||||
g.AddNode(simple.Node(v))
|
||||
}
|
||||
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||
@@ -147,11 +147,11 @@ func TestConnectedComponents(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
|
||||
for u, e := range test.g {
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
if !g.Has(simple.Node(v)) {
|
||||
if !g.Has(int64(v)) {
|
||||
g.AddNode(simple.Node(v))
|
||||
}
|
||||
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||
|
@@ -40,17 +40,19 @@ func (b *BreadthFirst) Walk(g graph.Graph, from graph.Node, until func(n graph.N
|
||||
if until != nil && until(t, depth) {
|
||||
return t
|
||||
}
|
||||
for _, n := range g.From(t) {
|
||||
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(t, n)) {
|
||||
tid := t.ID()
|
||||
for _, n := range g.From(tid) {
|
||||
nid := n.ID()
|
||||
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(tid, nid)) {
|
||||
continue
|
||||
}
|
||||
if b.visited.Has(n.ID()) {
|
||||
if b.visited.Has(nid) {
|
||||
continue
|
||||
}
|
||||
if b.Visit != nil {
|
||||
b.Visit(t, n)
|
||||
}
|
||||
b.visited.Add(n.ID())
|
||||
b.visited.Add(nid)
|
||||
children++
|
||||
b.queue.Enqueue(n)
|
||||
}
|
||||
@@ -125,17 +127,19 @@ func (d *DepthFirst) Walk(g graph.Graph, from graph.Node, until func(graph.Node)
|
||||
if until != nil && until(t) {
|
||||
return t
|
||||
}
|
||||
for _, n := range g.From(t) {
|
||||
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) {
|
||||
tid := t.ID()
|
||||
for _, n := range g.From(tid) {
|
||||
nid := n.ID()
|
||||
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(tid, nid)) {
|
||||
continue
|
||||
}
|
||||
if d.visited.Has(n.ID()) {
|
||||
if d.visited.Has(nid) {
|
||||
continue
|
||||
}
|
||||
if d.Visit != nil {
|
||||
d.Visit(t, n)
|
||||
}
|
||||
d.visited.Add(n.ID())
|
||||
d.visited.Add(nid)
|
||||
d.stack.Push(n)
|
||||
}
|
||||
}
|
||||
|
@@ -136,7 +136,7 @@ func TestBreadthFirst(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -224,7 +224,7 @@ func TestDepthFirst(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
for u, e := range test.g {
|
||||
// Add nodes that are not defined by an edge.
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
@@ -285,11 +285,11 @@ func TestWalkAll(t *testing.T) {
|
||||
g := simple.NewUndirectedGraph()
|
||||
|
||||
for u, e := range test.g {
|
||||
if !g.Has(simple.Node(u)) {
|
||||
if !g.Has(int64(u)) {
|
||||
g.AddNode(simple.Node(u))
|
||||
}
|
||||
for v := range e {
|
||||
if !g.Has(simple.Node(v)) {
|
||||
if !g.Has(int64(v)) {
|
||||
g.AddNode(simple.Node(v))
|
||||
}
|
||||
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||
|
@@ -12,20 +12,20 @@ type Undirect struct {
|
||||
var _ Undirected = Undirect{}
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g Undirect) Has(n Node) bool { return g.G.Has(n) }
|
||||
func (g Undirect) Has(id int64) bool { return g.G.Has(id) }
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g Undirect) Nodes() []Node { return g.G.Nodes() }
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g Undirect) From(u Node) []Node {
|
||||
func (g Undirect) From(uid int64) []Node {
|
||||
var nodes []Node
|
||||
seen := make(map[int64]struct{})
|
||||
for _, n := range g.G.From(u) {
|
||||
for _, n := range g.G.From(uid) {
|
||||
seen[n.ID()] = struct{}{}
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
for _, n := range g.G.To(u) {
|
||||
for _, n := range g.G.To(uid) {
|
||||
id := n.ID()
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
@@ -37,21 +37,21 @@ func (g Undirect) From(u Node) []Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g Undirect) HasEdgeBetween(x, y Node) bool { return g.G.HasEdgeBetween(x, y) }
|
||||
func (g Undirect) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
||||
// the edge is determined by applying the Merge func to the weights of the
|
||||
// edges between u and v.
|
||||
func (g Undirect) Edge(u, v Node) Edge { return g.EdgeBetween(u, v) }
|
||||
func (g Undirect) Edge(uid, vid int64) Edge { return g.EdgeBetween(uid, vid) }
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
|
||||
// Edge returned is an EdgePair. The weight of the edge is determined by
|
||||
// applying the Merge func to the weights of edges between x and y.
|
||||
func (g Undirect) EdgeBetween(x, y Node) Edge {
|
||||
fe := g.G.Edge(x, y)
|
||||
re := g.G.Edge(y, x)
|
||||
func (g Undirect) EdgeBetween(xid, yid int64) Edge {
|
||||
fe := g.G.Edge(xid, yid)
|
||||
re := g.G.Edge(yid, xid)
|
||||
if fe == nil && re == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -91,20 +91,20 @@ var (
|
||||
)
|
||||
|
||||
// Has returns whether the node exists within the graph.
|
||||
func (g UndirectWeighted) Has(n Node) bool { return g.G.Has(n) }
|
||||
func (g UndirectWeighted) Has(id int64) bool { return g.G.Has(id) }
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g UndirectWeighted) Nodes() []Node { return g.G.Nodes() }
|
||||
|
||||
// From returns all nodes in g that can be reached directly from u.
|
||||
func (g UndirectWeighted) From(u Node) []Node {
|
||||
func (g UndirectWeighted) From(uid int64) []Node {
|
||||
var nodes []Node
|
||||
seen := make(map[int64]struct{})
|
||||
for _, n := range g.G.From(u) {
|
||||
for _, n := range g.G.From(uid) {
|
||||
seen[n.ID()] = struct{}{}
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
for _, n := range g.G.To(u) {
|
||||
for _, n := range g.G.To(uid) {
|
||||
id := n.ID()
|
||||
if _, ok := seen[id]; ok {
|
||||
continue
|
||||
@@ -116,44 +116,46 @@ func (g UndirectWeighted) From(u Node) []Node {
|
||||
}
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||
func (g UndirectWeighted) HasEdgeBetween(x, y Node) bool { return g.G.HasEdgeBetween(x, y) }
|
||||
func (g UndirectWeighted) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
|
||||
|
||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
||||
// the edge is determined by applying the Merge func to the weights of the
|
||||
// edges between u and v.
|
||||
func (g UndirectWeighted) Edge(u, v Node) Edge { return g.WeightedEdgeBetween(u, v) }
|
||||
func (g UndirectWeighted) Edge(uid, vid int64) Edge { return g.WeightedEdgeBetween(uid, vid) }
|
||||
|
||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||
// The node v must be directly reachable from u as defined by the From method.
|
||||
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
||||
// the edge is determined by applying the Merge func to the weights of the
|
||||
// edges between u and v.
|
||||
func (g UndirectWeighted) WeightedEdge(u, v Node) WeightedEdge { return g.WeightedEdgeBetween(u, v) }
|
||||
func (g UndirectWeighted) WeightedEdge(uid, vid int64) WeightedEdge {
|
||||
return g.WeightedEdgeBetween(uid, vid)
|
||||
}
|
||||
|
||||
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
|
||||
// Edge returned is an EdgePair. The weight of the edge is determined by
|
||||
// applying the Merge func to the weights of edges between x and y.
|
||||
func (g UndirectWeighted) EdgeBetween(x, y Node) Edge {
|
||||
return g.WeightedEdgeBetween(x, y)
|
||||
func (g UndirectWeighted) EdgeBetween(xid, yid int64) Edge {
|
||||
return g.WeightedEdgeBetween(xid, yid)
|
||||
}
|
||||
|
||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y. If an edge exists, the
|
||||
// Edge returned is an EdgePair. The weight of the edge is determined by
|
||||
// applying the Merge func to the weights of edges between x and y.
|
||||
func (g UndirectWeighted) WeightedEdgeBetween(x, y Node) WeightedEdge {
|
||||
fe := g.G.Edge(x, y)
|
||||
re := g.G.Edge(y, x)
|
||||
func (g UndirectWeighted) WeightedEdgeBetween(xid, yid int64) WeightedEdge {
|
||||
fe := g.G.Edge(xid, yid)
|
||||
re := g.G.Edge(yid, xid)
|
||||
if fe == nil && re == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
f, ok := g.G.Weight(x, y)
|
||||
f, ok := g.G.Weight(xid, yid)
|
||||
if !ok {
|
||||
f = g.Absent
|
||||
}
|
||||
r, ok := g.G.Weight(y, x)
|
||||
r, ok := g.G.Weight(yid, xid)
|
||||
if !ok {
|
||||
r = g.Absent
|
||||
}
|
||||
@@ -171,15 +173,15 @@ func (g UndirectWeighted) WeightedEdgeBetween(x, y Node) WeightedEdge {
|
||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||
func (g UndirectWeighted) Weight(x, y Node) (w float64, ok bool) {
|
||||
fe := g.G.Edge(x, y)
|
||||
re := g.G.Edge(y, x)
|
||||
func (g UndirectWeighted) Weight(xid, yid int64) (w float64, ok bool) {
|
||||
fe := g.G.Edge(xid, yid)
|
||||
re := g.G.Edge(yid, xid)
|
||||
|
||||
f, fOk := g.G.Weight(x, y)
|
||||
f, fOk := g.G.Weight(xid, yid)
|
||||
if !fOk {
|
||||
f = g.Absent
|
||||
}
|
||||
r, rOK := g.G.Weight(y, x)
|
||||
r, rOK := g.G.Weight(yid, xid)
|
||||
if !rOK {
|
||||
r = g.Absent
|
||||
}
|
||||
|
@@ -123,8 +123,8 @@ func TestUndirect(t *testing.T) {
|
||||
src := graph.Undirect{G: g}
|
||||
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
|
||||
for _, u := range src.Nodes() {
|
||||
for _, v := range src.From(u) {
|
||||
dst.SetEdge(src.Edge(u, v))
|
||||
for _, v := range src.From(u.ID()) {
|
||||
dst.SetEdge(src.Edge(u.ID(), v.ID()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,8 +148,8 @@ func TestUndirectWeighted(t *testing.T) {
|
||||
src := graph.UndirectWeighted{G: g, Absent: test.absent, Merge: test.merge}
|
||||
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
|
||||
for _, u := range src.Nodes() {
|
||||
for _, v := range src.From(u) {
|
||||
dst.SetWeightedEdge(src.WeightedEdge(u, v))
|
||||
for _, v := range src.From(u.ID()) {
|
||||
dst.SetWeightedEdge(src.WeightedEdge(u.ID(), v.ID()))
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user