mirror of
https://github.com/gonum/gonum.git
synced 2025-10-09 00:50:16 +08:00
graph: use int64 for node retrieval
This commit is contained in:
@@ -62,7 +62,7 @@ func init() {
|
|||||||
friends = simple.NewWeightedUndirectedGraph(0, 0)
|
friends = simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range middleEast.friends {
|
for u, e := range middleEast.friends {
|
||||||
// Ensure unconnected nodes are included.
|
// Ensure unconnected nodes are included.
|
||||||
if !friends.Has(simple.Node(u)) {
|
if !friends.Has(int64(u)) {
|
||||||
friends.AddNode(simple.Node(u))
|
friends.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -72,7 +72,7 @@ func init() {
|
|||||||
enemies = simple.NewWeightedUndirectedGraph(0, 0)
|
enemies = simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range middleEast.enemies {
|
for u, e := range middleEast.enemies {
|
||||||
// Ensure unconnected nodes are included.
|
// Ensure unconnected nodes are included.
|
||||||
if !enemies.Has(simple.Node(u)) {
|
if !enemies.Has(int64(u)) {
|
||||||
enemies.AddNode(simple.Node(u))
|
enemies.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -127,7 +127,7 @@ func TestProfileUndirected(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -144,7 +144,7 @@ func TestProfileWeightedUndirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -186,7 +186,7 @@ func TestProfileDirected(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -203,7 +203,7 @@ func TestProfileWeightedDirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -111,7 +111,7 @@ func TestKCliqueCommunities(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -359,10 +359,10 @@ const (
|
|||||||
// positiveWeightFuncFor returns a constructed weight function for the
|
// positiveWeightFuncFor returns a constructed weight function for the
|
||||||
// positively weighted g. Unweighted graphs have unit weight for existing
|
// positively weighted g. Unweighted graphs have unit weight for existing
|
||||||
// edges.
|
// edges.
|
||||||
func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
func positiveWeightFuncFor(g graph.Graph) func(xid, yid int64) float64 {
|
||||||
if wg, ok := g.(graph.Weighted); ok {
|
if wg, ok := g.(graph.Weighted); ok {
|
||||||
return func(x, y graph.Node) float64 {
|
return func(xid, yid int64) float64 {
|
||||||
w, ok := wg.Weight(x, y)
|
w, ok := wg.Weight(xid, yid)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -372,8 +372,8 @@ func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
|||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return func(x, y graph.Node) float64 {
|
return func(xid, yid int64) float64 {
|
||||||
e := g.Edge(x, y)
|
e := g.Edge(xid, yid)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -384,10 +384,10 @@ func positiveWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
|||||||
// negativeWeightFuncFor returns a constructed weight function for the
|
// negativeWeightFuncFor returns a constructed weight function for the
|
||||||
// negatively weighted g. Unweighted graphs have unit weight for existing
|
// negatively weighted g. Unweighted graphs have unit weight for existing
|
||||||
// edges.
|
// edges.
|
||||||
func negativeWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
func negativeWeightFuncFor(g graph.Graph) func(xid, yid int64) float64 {
|
||||||
if wg, ok := g.(graph.Weighted); ok {
|
if wg, ok := g.(graph.Weighted); ok {
|
||||||
return func(x, y graph.Node) float64 {
|
return func(xid, yid int64) float64 {
|
||||||
w, ok := wg.Weight(x, y)
|
w, ok := wg.Weight(xid, yid)
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -397,8 +397,8 @@ func negativeWeightFuncFor(g graph.Graph) func(x, y graph.Node) float64 {
|
|||||||
return -w
|
return -w
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return func(x, y graph.Node) float64 {
|
return func(xid, yid int64) float64 {
|
||||||
e := g.Edge(x, y)
|
e := g.Edge(xid, yid)
|
||||||
if e == nil {
|
if e == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@@ -34,24 +34,28 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
|
|||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
var wOut float64
|
var wOut float64
|
||||||
u := n
|
u := n
|
||||||
for _, v := range g.From(u) {
|
uid := u.ID()
|
||||||
wOut += weight(u, v)
|
for _, v := range g.From(uid) {
|
||||||
|
wOut += weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
var wIn float64
|
var wIn float64
|
||||||
v := n
|
v := n
|
||||||
for _, u := range g.To(v) {
|
vid := v.ID()
|
||||||
wIn += weight(u, v)
|
for _, u := range g.To(vid) {
|
||||||
|
wIn += weight(u.ID(), vid)
|
||||||
}
|
}
|
||||||
w := weight(n, n)
|
id := n.ID()
|
||||||
|
w := weight(id, id)
|
||||||
m += w + wOut // We only need to count edges once.
|
m += w + wOut // We only need to count edges once.
|
||||||
k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
k[id] = directedWeights{out: w + wOut, in: w + wIn}
|
||||||
}
|
}
|
||||||
|
|
||||||
if communities == nil {
|
if communities == nil {
|
||||||
var q float64
|
var q float64
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
kU := k[u.ID()]
|
uid := u.ID()
|
||||||
q += weight(u, u) - resolution*kU.out*kU.in/m
|
kU := k[uid]
|
||||||
|
q += weight(uid, uid) - resolution*kU.out*kU.in/m
|
||||||
}
|
}
|
||||||
return q / m
|
return q / m
|
||||||
}
|
}
|
||||||
@@ -59,10 +63,12 @@ func qDirected(g graph.Directed, communities [][]graph.Node, resolution float64)
|
|||||||
var q float64
|
var q float64
|
||||||
for _, c := range communities {
|
for _, c := range communities {
|
||||||
for _, u := range c {
|
for _, u := range c {
|
||||||
kU := k[u.ID()]
|
uid := u.ID()
|
||||||
|
kU := k[uid]
|
||||||
for _, v := range c {
|
for _, v := range c {
|
||||||
kV := k[v.ID()]
|
vid := v.ID()
|
||||||
q += weight(u, v) - resolution*kU.out*kV.in/m
|
kV := k[vid]
|
||||||
|
q += weight(uid, vid) - resolution*kU.out*kV.in/m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,23 +209,27 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
|||||||
|
|
||||||
var out []int
|
var out []int
|
||||||
u := n
|
u := n
|
||||||
for _, v := range g.From(u) {
|
uid := u.ID()
|
||||||
vid := communityOf[v.ID()]
|
for _, v := range g.From(uid) {
|
||||||
if vid != id {
|
vid := v.ID()
|
||||||
out = append(out, vid)
|
vcid := communityOf[vid]
|
||||||
|
if vcid != id {
|
||||||
|
out = append(out, vcid)
|
||||||
}
|
}
|
||||||
r.weights[[2]int{id, vid}] = weight(u, v)
|
r.weights[[2]int{id, vcid}] = weight(uid, vid)
|
||||||
}
|
}
|
||||||
r.edgesFrom[id] = out
|
r.edgesFrom[id] = out
|
||||||
|
|
||||||
var in []int
|
var in []int
|
||||||
v := n
|
v := n
|
||||||
for _, u := range g.To(v) {
|
vid := v.ID()
|
||||||
uid := communityOf[u.ID()]
|
for _, u := range g.To(vid) {
|
||||||
if uid != id {
|
uid := u.ID()
|
||||||
in = append(in, uid)
|
ucid := communityOf[uid]
|
||||||
|
if ucid != id {
|
||||||
|
in = append(in, ucid)
|
||||||
}
|
}
|
||||||
r.weights[[2]int{uid, id}] = weight(u, v)
|
r.weights[[2]int{ucid, id}] = weight(uid, vid)
|
||||||
}
|
}
|
||||||
r.edgesTo[id] = in
|
r.edgesTo[id] = in
|
||||||
}
|
}
|
||||||
@@ -270,43 +280,47 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
|||||||
var out, in []int
|
var out, in []int
|
||||||
for _, n := range comm {
|
for _, n := range comm {
|
||||||
u := n
|
u := n
|
||||||
|
uid := u.ID()
|
||||||
for _, v := range comm {
|
for _, v := range comm {
|
||||||
r.nodes[id].weight += weight(u, v)
|
r.nodes[id].weight += weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range g.From(u) {
|
for _, v := range g.From(uid) {
|
||||||
vid := communityOf[v.ID()]
|
vid := v.ID()
|
||||||
|
vcid := communityOf[vid]
|
||||||
found := false
|
found := false
|
||||||
for _, e := range out {
|
for _, e := range out {
|
||||||
if e == vid {
|
if e == vcid {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found && vid != id {
|
if !found && vcid != id {
|
||||||
out = append(out, vid)
|
out = append(out, vcid)
|
||||||
}
|
}
|
||||||
// Add half weights because the other
|
// Add half weights because the other
|
||||||
// ends of edges are also counted.
|
// ends of edges are also counted.
|
||||||
r.weights[[2]int{id, vid}] += weight(u, v) / 2
|
r.weights[[2]int{id, vcid}] += weight(uid, vid) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
v := n
|
v := n
|
||||||
for _, u := range g.To(v) {
|
vid := v.ID()
|
||||||
uid := communityOf[u.ID()]
|
for _, u := range g.To(vid) {
|
||||||
|
uid := u.ID()
|
||||||
|
ucid := communityOf[uid]
|
||||||
found := false
|
found := false
|
||||||
for _, e := range in {
|
for _, e := range in {
|
||||||
if e == uid {
|
if e == ucid {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found && uid != id {
|
if !found && ucid != id {
|
||||||
in = append(in, uid)
|
in = append(in, ucid)
|
||||||
}
|
}
|
||||||
// Add half weights because the other
|
// Add half weights because the other
|
||||||
// ends of edges are also counted.
|
// ends of edges are also counted.
|
||||||
r.weights[[2]int{uid, id}] += weight(u, v) / 2
|
r.weights[[2]int{ucid, id}] += weight(uid, vid) / 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.edgesFrom[id] = out
|
r.edgesFrom[id] = out
|
||||||
@@ -316,8 +330,7 @@ func reduceDirected(g graph.Directed, communities [][]graph.Node) *ReducedDirect
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *ReducedDirected) Has(n graph.Node) bool {
|
func (g *ReducedDirected) Has(id int64) bool {
|
||||||
id := n.ID()
|
|
||||||
return 0 <= id && id < int64(len(g.nodes))
|
return 0 <= id && id < int64(len(g.nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,8 +344,8 @@ func (g *ReducedDirected) Nodes() []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from u.
|
// From returns all nodes in g that can be reached directly from u.
|
||||||
func (g *ReducedDirected) From(u graph.Node) []graph.Node {
|
func (g *ReducedDirected) From(uid int64) []graph.Node {
|
||||||
out := g.edgesFrom[u.ID()]
|
out := g.edgesFrom[uid]
|
||||||
nodes := make([]graph.Node, len(out))
|
nodes := make([]graph.Node, len(out))
|
||||||
for i, vid := range out {
|
for i, vid := range out {
|
||||||
nodes[i] = g.nodes[vid]
|
nodes[i] = g.nodes[vid]
|
||||||
@@ -341,8 +354,8 @@ func (g *ReducedDirected) From(u graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// To returns all nodes in g that can reach directly to v.
|
// To returns all nodes in g that can reach directly to v.
|
||||||
func (g *ReducedDirected) To(v graph.Node) []graph.Node {
|
func (g *ReducedDirected) To(vid int64) []graph.Node {
|
||||||
in := g.edgesTo[v.ID()]
|
in := g.edgesTo[vid]
|
||||||
nodes := make([]graph.Node, len(in))
|
nodes := make([]graph.Node, len(in))
|
||||||
for i, uid := range in {
|
for i, uid := range in {
|
||||||
nodes[i] = g.nodes[uid]
|
nodes[i] = g.nodes[uid]
|
||||||
@@ -351,9 +364,7 @@ func (g *ReducedDirected) To(v graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g *ReducedDirected) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *ReducedDirected) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -366,9 +377,7 @@ func (g *ReducedDirected) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists from node u to v.
|
// HasEdgeFromTo returns whether an edge exists from node u to v.
|
||||||
func (g *ReducedDirected) HasEdgeFromTo(u, v graph.Node) bool {
|
func (g *ReducedDirected) HasEdgeFromTo(uid, vid int64) bool {
|
||||||
uid := u.ID()
|
|
||||||
vid := v.ID()
|
|
||||||
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -378,15 +387,13 @@ func (g *ReducedDirected) HasEdgeFromTo(u, v graph.Node) bool {
|
|||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *ReducedDirected) Edge(u, v graph.Node) graph.Edge {
|
func (g *ReducedDirected) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdge(u, v)
|
return g.WeightedEdge(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *ReducedDirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *ReducedDirected) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
uid := u.ID()
|
|
||||||
vid := v.ID()
|
|
||||||
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -401,9 +408,7 @@ func (g *ReducedDirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
|||||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g *ReducedDirected) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g *ReducedDirected) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if !isValidID(xid) || !isValidID(yid) {
|
if !isValidID(xid) || !isValidID(yid) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@@ -433,7 +438,7 @@ type directedLocalMover struct {
|
|||||||
// that returns the Weight value
|
// that returns the Weight value
|
||||||
// of the non-nil edge between x
|
// of the non-nil edge between x
|
||||||
// and y.
|
// and y.
|
||||||
weight func(x, y graph.Node) float64
|
weight func(xid, yid int64) float64
|
||||||
|
|
||||||
// communities is the current
|
// communities is the current
|
||||||
// division of g.
|
// division of g.
|
||||||
@@ -484,18 +489,21 @@ func newDirectedLocalMover(g *ReducedDirected, communities [][]graph.Node, resol
|
|||||||
for _, n := range l.nodes {
|
for _, n := range l.nodes {
|
||||||
u := n
|
u := n
|
||||||
var wOut float64
|
var wOut float64
|
||||||
for _, v := range g.From(u) {
|
uid := u.ID()
|
||||||
wOut += l.weight(u, v)
|
for _, v := range g.From(uid) {
|
||||||
|
wOut += l.weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
v := n
|
v := n
|
||||||
var wIn float64
|
var wIn float64
|
||||||
for _, u := range g.To(v) {
|
vid := v.ID()
|
||||||
wIn += l.weight(u, v)
|
for _, u := range g.To(vid) {
|
||||||
|
wIn += l.weight(u.ID(), vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
w := l.weight(n, n)
|
id := n.ID()
|
||||||
l.edgeWeightsOf[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
w := l.weight(id, id)
|
||||||
|
l.edgeWeightsOf[id] = directedWeights{out: w + wOut, in: w + wIn}
|
||||||
l.m += w + wOut
|
l.m += w + wOut
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,7 +570,7 @@ func (l *directedLocalMover) move(dst int, src commIdx) {
|
|||||||
func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
|
func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
|
||||||
id := n.ID()
|
id := n.ID()
|
||||||
|
|
||||||
a_aa := l.weight(n, n)
|
a_aa := l.weight(id, id)
|
||||||
k_a := l.edgeWeightsOf[id]
|
k_a := l.edgeWeightsOf[id]
|
||||||
m := l.m
|
m := l.m
|
||||||
gamma := l.resolution
|
gamma := l.resolution
|
||||||
@@ -613,8 +621,8 @@ func (l *directedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src
|
|||||||
removal = true
|
removal = true
|
||||||
}
|
}
|
||||||
|
|
||||||
k_aC.in += l.weight(u, n)
|
k_aC.in += l.weight(uid, id)
|
||||||
k_aC.out += l.weight(n, u)
|
k_aC.out += l.weight(id, uid)
|
||||||
// sigma_totC could be kept for each community
|
// sigma_totC could be kept for each community
|
||||||
// and updated for moves, changing the calculation
|
// and updated for moves, changing the calculation
|
||||||
// of sigma_totC here from O(n_c) to O(1), but
|
// of sigma_totC here from O(n_c) to O(1), but
|
||||||
|
@@ -63,7 +63,7 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
|||||||
layerResolution = resolutions[l]
|
layerResolution = resolutions[l]
|
||||||
}
|
}
|
||||||
|
|
||||||
var weight func(x, y graph.Node) float64
|
var weight func(xid, yid int64) float64
|
||||||
if layerWeight < 0 {
|
if layerWeight < 0 {
|
||||||
weight = negativeWeightFuncFor(layer)
|
weight = negativeWeightFuncFor(layer)
|
||||||
} else {
|
} else {
|
||||||
@@ -77,15 +77,18 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
|||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
var wOut float64
|
var wOut float64
|
||||||
u := n
|
u := n
|
||||||
for _, v := range layer.From(u) {
|
uid := u.ID()
|
||||||
wOut += weight(u, v)
|
for _, v := range layer.From(uid) {
|
||||||
|
wOut += weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
var wIn float64
|
var wIn float64
|
||||||
v := n
|
v := n
|
||||||
for _, u := range layer.To(v) {
|
vid := v.ID()
|
||||||
wIn += weight(u, v)
|
for _, u := range layer.To(vid) {
|
||||||
|
wIn += weight(u.ID(), vid)
|
||||||
}
|
}
|
||||||
w := weight(n, n)
|
id := n.ID()
|
||||||
|
w := weight(id, id)
|
||||||
m += w + wOut // We only need to count edges once.
|
m += w + wOut // We only need to count edges once.
|
||||||
k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
k[n.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
||||||
}
|
}
|
||||||
@@ -93,8 +96,9 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
|||||||
if communities == nil {
|
if communities == nil {
|
||||||
var qLayer float64
|
var qLayer float64
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
kU := k[u.ID()]
|
uid := u.ID()
|
||||||
qLayer += weight(u, u) - layerResolution*kU.out*kU.in/m
|
kU := k[uid]
|
||||||
|
qLayer += weight(uid, uid) - layerResolution*kU.out*kU.in/m
|
||||||
}
|
}
|
||||||
q[l] = layerWeight * qLayer
|
q[l] = layerWeight * qLayer
|
||||||
continue
|
continue
|
||||||
@@ -103,10 +107,12 @@ func qDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, weights
|
|||||||
var qLayer float64
|
var qLayer float64
|
||||||
for _, c := range communities {
|
for _, c := range communities {
|
||||||
for _, u := range c {
|
for _, u := range c {
|
||||||
kU := k[u.ID()]
|
uid := u.ID()
|
||||||
|
kU := k[uid]
|
||||||
for _, v := range c {
|
for _, v := range c {
|
||||||
kV := k[v.ID()]
|
vid := v.ID()
|
||||||
qLayer += weight(u, v) - layerResolution*kU.out*kV.in/m
|
kV := k[vid]
|
||||||
|
qLayer += weight(uid, vid) - layerResolution*kU.out*kV.in/m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,7 +327,7 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var sign float64
|
var sign float64
|
||||||
var weight func(x, y graph.Node) float64
|
var weight func(xid, yid int64) float64
|
||||||
if w < 0 {
|
if w < 0 {
|
||||||
sign, weight = -1, negativeWeightFuncFor(layer)
|
sign, weight = -1, negativeWeightFuncFor(layer)
|
||||||
} else {
|
} else {
|
||||||
@@ -332,23 +338,27 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
|||||||
|
|
||||||
var out []int
|
var out []int
|
||||||
u := n
|
u := n
|
||||||
for _, v := range layer.From(u) {
|
uid := u.ID()
|
||||||
vid := communityOf[v.ID()]
|
for _, v := range layer.From(uid) {
|
||||||
if vid != id {
|
vid := v.ID()
|
||||||
out = append(out, vid)
|
vcid := communityOf[vid]
|
||||||
|
if vcid != id {
|
||||||
|
out = append(out, vcid)
|
||||||
}
|
}
|
||||||
r.layers[l].weights[[2]int{id, vid}] = sign * weight(u, v)
|
r.layers[l].weights[[2]int{id, vcid}] = sign * weight(uid, vid)
|
||||||
}
|
}
|
||||||
r.layers[l].edgesFrom[id] = out
|
r.layers[l].edgesFrom[id] = out
|
||||||
|
|
||||||
var in []int
|
var in []int
|
||||||
v := n
|
v := n
|
||||||
for _, u := range layer.To(v) {
|
vid := v.ID()
|
||||||
uid := communityOf[u.ID()]
|
for _, u := range layer.To(vid) {
|
||||||
if uid != id {
|
uid := u.ID()
|
||||||
in = append(in, uid)
|
ucid := communityOf[uid]
|
||||||
|
if ucid != id {
|
||||||
|
in = append(in, ucid)
|
||||||
}
|
}
|
||||||
r.layers[l].weights[[2]int{uid, id}] = sign * weight(u, v)
|
r.layers[l].weights[[2]int{ucid, id}] = sign * weight(uid, vid)
|
||||||
}
|
}
|
||||||
r.layers[l].edgesTo[id] = in
|
r.layers[l].edgesTo[id] = in
|
||||||
}
|
}
|
||||||
@@ -408,7 +418,7 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var sign float64
|
var sign float64
|
||||||
var weight func(x, y graph.Node) float64
|
var weight func(xid, yid int64) float64
|
||||||
if w < 0 {
|
if w < 0 {
|
||||||
sign, weight = -1, negativeWeightFuncFor(layer)
|
sign, weight = -1, negativeWeightFuncFor(layer)
|
||||||
} else {
|
} else {
|
||||||
@@ -418,43 +428,47 @@ func reduceDirectedMultiplex(g DirectedMultiplex, communities [][]graph.Node, we
|
|||||||
var out, in []int
|
var out, in []int
|
||||||
for _, n := range comm {
|
for _, n := range comm {
|
||||||
u := n
|
u := n
|
||||||
|
uid := u.ID()
|
||||||
for _, v := range comm {
|
for _, v := range comm {
|
||||||
r.nodes[id].weights[l] += sign * weight(u, v)
|
r.nodes[id].weights[l] += sign * weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range layer.From(u) {
|
for _, v := range layer.From(uid) {
|
||||||
vid := communityOf[v.ID()]
|
vid := v.ID()
|
||||||
|
vcid := communityOf[vid]
|
||||||
found := false
|
found := false
|
||||||
for _, e := range out {
|
for _, e := range out {
|
||||||
if e == vid {
|
if e == vcid {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found && vid != id {
|
if !found && vcid != id {
|
||||||
out = append(out, vid)
|
out = append(out, vcid)
|
||||||
}
|
}
|
||||||
// Add half weights because the other
|
// Add half weights because the other
|
||||||
// ends of edges are also counted.
|
// ends of edges are also counted.
|
||||||
r.layers[l].weights[[2]int{id, vid}] += sign * weight(u, v) / 2
|
r.layers[l].weights[[2]int{id, vcid}] += sign * weight(uid, vid) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
v := n
|
v := n
|
||||||
for _, u := range layer.To(v) {
|
vid := v.ID()
|
||||||
uid := communityOf[u.ID()]
|
for _, u := range layer.To(vid) {
|
||||||
|
uid := u.ID()
|
||||||
|
ucid := communityOf[uid]
|
||||||
found := false
|
found := false
|
||||||
for _, e := range in {
|
for _, e := range in {
|
||||||
if e == uid {
|
if e == ucid {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found && uid != id {
|
if !found && ucid != id {
|
||||||
in = append(in, uid)
|
in = append(in, ucid)
|
||||||
}
|
}
|
||||||
// Add half weights because the other
|
// Add half weights because the other
|
||||||
// ends of edges are also counted.
|
// ends of edges are also counted.
|
||||||
r.layers[l].weights[[2]int{uid, id}] += sign * weight(u, v) / 2
|
r.layers[l].weights[[2]int{ucid, id}] += sign * weight(uid, vid) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -478,8 +492,7 @@ type directedLayerHandle struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g directedLayerHandle) Has(n graph.Node) bool {
|
func (g directedLayerHandle) Has(id int64) bool {
|
||||||
id := n.ID()
|
|
||||||
return 0 <= id && id < int64(len(g.multiplex.nodes))
|
return 0 <= id && id < int64(len(g.multiplex.nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,8 +506,8 @@ func (g directedLayerHandle) Nodes() []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from u.
|
// From returns all nodes in g that can be reached directly from u.
|
||||||
func (g directedLayerHandle) From(u graph.Node) []graph.Node {
|
func (g directedLayerHandle) From(uid int64) []graph.Node {
|
||||||
out := g.multiplex.layers[g.layer].edgesFrom[u.ID()]
|
out := g.multiplex.layers[g.layer].edgesFrom[uid]
|
||||||
nodes := make([]graph.Node, len(out))
|
nodes := make([]graph.Node, len(out))
|
||||||
for i, vid := range out {
|
for i, vid := range out {
|
||||||
nodes[i] = g.multiplex.nodes[vid]
|
nodes[i] = g.multiplex.nodes[vid]
|
||||||
@@ -503,8 +516,8 @@ func (g directedLayerHandle) From(u graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// To returns all nodes in g that can reach directly to v.
|
// To returns all nodes in g that can reach directly to v.
|
||||||
func (g directedLayerHandle) To(v graph.Node) []graph.Node {
|
func (g directedLayerHandle) To(vid int64) []graph.Node {
|
||||||
in := g.multiplex.layers[g.layer].edgesTo[v.ID()]
|
in := g.multiplex.layers[g.layer].edgesTo[vid]
|
||||||
nodes := make([]graph.Node, len(in))
|
nodes := make([]graph.Node, len(in))
|
||||||
for i, uid := range in {
|
for i, uid := range in {
|
||||||
nodes[i] = g.multiplex.nodes[uid]
|
nodes[i] = g.multiplex.nodes[uid]
|
||||||
@@ -513,9 +526,7 @@ func (g directedLayerHandle) To(v graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g directedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
|
func (g directedLayerHandle) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid {
|
if xid == yid {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -531,9 +542,7 @@ func (g directedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists from node u to v.
|
// HasEdgeFromTo returns whether an edge exists from node u to v.
|
||||||
func (g directedLayerHandle) HasEdgeFromTo(u, v graph.Node) bool {
|
func (g directedLayerHandle) HasEdgeFromTo(uid, vid int64) bool {
|
||||||
uid := u.ID()
|
|
||||||
vid := v.ID()
|
|
||||||
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -543,15 +552,13 @@ func (g directedLayerHandle) HasEdgeFromTo(u, v graph.Node) bool {
|
|||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g directedLayerHandle) Edge(u, v graph.Node) graph.Edge {
|
func (g directedLayerHandle) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdge(u, v)
|
return g.WeightedEdge(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g directedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g directedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
uid := u.ID()
|
|
||||||
vid := v.ID()
|
|
||||||
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
if uid == vid || !isValidID(uid) || !isValidID(vid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -559,16 +566,14 @@ func (g directedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return multiplexEdge{from: g.multiplex.nodes[u.ID()], to: g.multiplex.nodes[v.ID()], weight: w}
|
return multiplexEdge{from: g.multiplex.nodes[uid], to: g.multiplex.nodes[vid], weight: w}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
||||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g directedLayerHandle) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g directedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if !isValidID(xid) || !isValidID(yid) {
|
if !isValidID(xid) || !isValidID(yid) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@@ -598,7 +603,7 @@ type directedMultiplexLocalMover struct {
|
|||||||
// that returns the Weight value
|
// that returns the Weight value
|
||||||
// of the non-nil edge between x
|
// of the non-nil edge between x
|
||||||
// and y.
|
// and y.
|
||||||
weight []func(x, y graph.Node) float64
|
weight []func(xid, yid int64) float64
|
||||||
|
|
||||||
// communities is the current
|
// communities is the current
|
||||||
// division of g.
|
// division of g.
|
||||||
@@ -648,7 +653,7 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
|
|||||||
memberships: make([]int, len(nodes)),
|
memberships: make([]int, len(nodes)),
|
||||||
resolutions: resolutions,
|
resolutions: resolutions,
|
||||||
weights: weights,
|
weights: weights,
|
||||||
weight: make([]func(x, y graph.Node) float64, g.Depth()),
|
weight: make([]func(xid, yid int64) float64, g.Depth()),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the total edge weight of the graph
|
// Calculate the total edge weight of the graph
|
||||||
@@ -656,7 +661,7 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
|
|||||||
var zero int
|
var zero int
|
||||||
for i := 0; i < g.Depth(); i++ {
|
for i := 0; i < g.Depth(); i++ {
|
||||||
l.edgeWeightsOf[i] = make([]directedWeights, len(nodes))
|
l.edgeWeightsOf[i] = make([]directedWeights, len(nodes))
|
||||||
var weight func(x, y graph.Node) float64
|
var weight func(xid, yid int64) float64
|
||||||
|
|
||||||
if weights != nil {
|
if weights != nil {
|
||||||
if weights[i] == 0 {
|
if weights[i] == 0 {
|
||||||
@@ -677,19 +682,22 @@ func newDirectedMultiplexLocalMover(g *ReducedDirectedMultiplex, communities [][
|
|||||||
layer := g.Layer(i)
|
layer := g.Layer(i)
|
||||||
for _, n := range l.nodes {
|
for _, n := range l.nodes {
|
||||||
u := n
|
u := n
|
||||||
|
uid := u.ID()
|
||||||
var wOut float64
|
var wOut float64
|
||||||
for _, v := range layer.From(u) {
|
for _, v := range layer.From(uid) {
|
||||||
wOut += weight(u, v)
|
wOut += weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
v := n
|
v := n
|
||||||
|
vid := v.ID()
|
||||||
var wIn float64
|
var wIn float64
|
||||||
for _, u := range layer.To(v) {
|
for _, u := range layer.To(vid) {
|
||||||
wIn += weight(u, v)
|
wIn += weight(u.ID(), vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
w := weight(n, n)
|
id := n.ID()
|
||||||
l.edgeWeightsOf[i][u.ID()] = directedWeights{out: w + wOut, in: w + wIn}
|
w := weight(id, id)
|
||||||
|
l.edgeWeightsOf[i][uid] = directedWeights{out: w + wOut, in: w + wIn}
|
||||||
l.m[i] += w + wOut
|
l.m[i] += w + wOut
|
||||||
}
|
}
|
||||||
if l.m[i] == 0 {
|
if l.m[i] == 0 {
|
||||||
@@ -836,8 +844,8 @@ func (l *directedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst
|
|||||||
removal = true
|
removal = true
|
||||||
}
|
}
|
||||||
|
|
||||||
k_aC.in += l.weight[layer](n, u)
|
k_aC.in += l.weight[layer](id, uid)
|
||||||
k_aC.out += l.weight[layer](u, n)
|
k_aC.out += l.weight[layer](uid, id)
|
||||||
// sigma_totC could be kept for each community
|
// sigma_totC could be kept for each community
|
||||||
// and updated for moves, changing the calculation
|
// and updated for moves, changing the calculation
|
||||||
// of sigma_totC here from O(n_c) to O(1), but
|
// of sigma_totC here from O(n_c) to O(1), but
|
||||||
@@ -849,7 +857,7 @@ func (l *directedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst
|
|||||||
sigma_totC.out += w.out
|
sigma_totC.out += w.out
|
||||||
}
|
}
|
||||||
|
|
||||||
a_aa := l.weight[layer](n, n)
|
a_aa := l.weight[layer](id, id)
|
||||||
k_a := l.edgeWeightsOf[layer][id]
|
k_a := l.edgeWeightsOf[layer][id]
|
||||||
gamma := 1.0
|
gamma := 1.0
|
||||||
if l.resolutions != nil {
|
if l.resolutions != nil {
|
||||||
|
@@ -390,7 +390,7 @@ tests:
|
|||||||
}
|
}
|
||||||
layer := g.Layer(l)
|
layer := g.Layer(l)
|
||||||
for n := range c {
|
for n := range c {
|
||||||
if layer.HasEdgeBetween(simple.Node(n), target) {
|
if layer.HasEdgeBetween(int64(n), target.ID()) {
|
||||||
connected = true
|
connected = true
|
||||||
break search
|
break search
|
||||||
}
|
}
|
||||||
@@ -701,7 +701,7 @@ func directedMultiplexFrom(raw []layer) (DirectedLayers, []float64, error) {
|
|||||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||||
for u, e := range l.g {
|
for u, e := range l.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -204,7 +204,7 @@ func TestCommunityQDirected(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -221,7 +221,7 @@ func TestCommunityQWeightedDirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -257,7 +257,7 @@ func TestCommunityDeltaQDirected(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -274,7 +274,7 @@ func TestCommunityDeltaQWeightedDirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -338,7 +338,7 @@ func testCommunityDeltaQDirected(t *testing.T, test communityDirectedQTest, g gr
|
|||||||
}
|
}
|
||||||
connected := false
|
connected := false
|
||||||
for n := range c {
|
for n := range c {
|
||||||
if g.HasEdgeBetween(simple.Node(n), target) {
|
if g.HasEdgeBetween(int64(n), target.ID()) {
|
||||||
connected = true
|
connected = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -382,7 +382,7 @@ func TestReduceQConsistencyDirected(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -399,7 +399,7 @@ func TestReduceQConsistencyWeightedDirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -500,7 +500,7 @@ func TestMoveLocalDirected(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -517,7 +517,7 @@ func TestMoveLocalWeightedDirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -562,7 +562,7 @@ func TestModularizeDirected(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -579,7 +579,7 @@ func TestModularizeWeightedDirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedDirectedGraph(0, 0)
|
g := simple.NewWeightedDirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -34,19 +34,21 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
|
|||||||
var m2 float64
|
var m2 float64
|
||||||
k := make(map[int64]float64, len(nodes))
|
k := make(map[int64]float64, len(nodes))
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
w := weight(u, u)
|
uid := u.ID()
|
||||||
for _, v := range g.From(u) {
|
w := weight(uid, uid)
|
||||||
w += weight(u, v)
|
for _, v := range g.From(uid) {
|
||||||
|
w += weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
m2 += w
|
m2 += w
|
||||||
k[u.ID()] = w
|
k[uid] = w
|
||||||
}
|
}
|
||||||
|
|
||||||
if communities == nil {
|
if communities == nil {
|
||||||
var q float64
|
var q float64
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
kU := k[u.ID()]
|
uid := u.ID()
|
||||||
q += weight(u, u) - resolution*kU*kU/m2
|
kU := k[uid]
|
||||||
|
q += weight(uid, uid) - resolution*kU*kU/m2
|
||||||
}
|
}
|
||||||
return q / m2
|
return q / m2
|
||||||
}
|
}
|
||||||
@@ -57,10 +59,12 @@ func qUndirected(g graph.Undirected, communities [][]graph.Node, resolution floa
|
|||||||
var q float64
|
var q float64
|
||||||
for _, c := range communities {
|
for _, c := range communities {
|
||||||
for i, u := range c {
|
for i, u := range c {
|
||||||
kU := k[u.ID()]
|
uid := u.ID()
|
||||||
q += weight(u, u) - resolution*kU*kU/m2
|
kU := k[uid]
|
||||||
|
q += weight(uid, uid) - resolution*kU*kU/m2
|
||||||
for _, v := range c[i+1:] {
|
for _, v := range c[i+1:] {
|
||||||
q += 2 * (weight(u, v) - resolution*kU*k[v.ID()]/m2)
|
vid := v.ID()
|
||||||
|
q += 2 * (weight(uid, vid) - resolution*kU*k[vid]/m2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,19 +202,21 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
|
|||||||
communityOf[n.ID()] = i
|
communityOf[n.ID()] = i
|
||||||
}
|
}
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
|
ucid := communityOf[uid]
|
||||||
var out []int
|
var out []int
|
||||||
uid := communityOf[u.ID()]
|
for _, v := range g.From(uid) {
|
||||||
for _, v := range g.From(u) {
|
vid := v.ID()
|
||||||
vid := communityOf[v.ID()]
|
vcid := communityOf[vid]
|
||||||
if vid != uid {
|
if vcid != ucid {
|
||||||
out = append(out, vid)
|
out = append(out, vcid)
|
||||||
}
|
}
|
||||||
if uid < vid {
|
if ucid < vcid {
|
||||||
// Only store the weight once.
|
// Only store the weight once.
|
||||||
r.weights[[2]int{uid, vid}] = weight(u, v)
|
r.weights[[2]int{ucid, vcid}] = weight(uid, vid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.edges[uid] = out
|
r.edges[ucid] = out
|
||||||
}
|
}
|
||||||
return &r
|
return &r
|
||||||
}
|
}
|
||||||
@@ -254,39 +260,40 @@ func reduceUndirected(g graph.Undirected, communities [][]graph.Node) *ReducedUn
|
|||||||
communityOf[n.ID()] = i
|
communityOf[n.ID()] = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for uid, comm := range communities {
|
for ucid, comm := range communities {
|
||||||
var out []int
|
var out []int
|
||||||
for i, u := range comm {
|
for i, u := range comm {
|
||||||
r.nodes[uid].weight += weight(u, u)
|
uid := u.ID()
|
||||||
|
r.nodes[ucid].weight += weight(uid, uid)
|
||||||
for _, v := range comm[i+1:] {
|
for _, v := range comm[i+1:] {
|
||||||
r.nodes[uid].weight += 2 * weight(u, v)
|
r.nodes[ucid].weight += 2 * weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
for _, v := range g.From(u) {
|
for _, v := range g.From(uid) {
|
||||||
vid := communityOf[v.ID()]
|
vid := v.ID()
|
||||||
|
vcid := communityOf[vid]
|
||||||
found := false
|
found := false
|
||||||
for _, e := range out {
|
for _, e := range out {
|
||||||
if e == vid {
|
if e == vcid {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found && vid != uid {
|
if !found && vcid != ucid {
|
||||||
out = append(out, vid)
|
out = append(out, vcid)
|
||||||
}
|
}
|
||||||
if uid < vid {
|
if ucid < vcid {
|
||||||
// Only store the weight once.
|
// Only store the weight once.
|
||||||
r.weights[[2]int{uid, vid}] += weight(u, v)
|
r.weights[[2]int{ucid, vcid}] += weight(uid, vid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.edges[uid] = out
|
r.edges[ucid] = out
|
||||||
}
|
}
|
||||||
return &r
|
return &r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *ReducedUndirected) Has(n graph.Node) bool {
|
func (g *ReducedUndirected) Has(id int64) bool {
|
||||||
id := n.ID()
|
|
||||||
return 0 <= id || id < int64(len(g.nodes))
|
return 0 <= id || id < int64(len(g.nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,8 +307,8 @@ func (g *ReducedUndirected) Nodes() []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from u.
|
// From returns all nodes in g that can be reached directly from u.
|
||||||
func (g *ReducedUndirected) From(u graph.Node) []graph.Node {
|
func (g *ReducedUndirected) From(uid int64) []graph.Node {
|
||||||
out := g.edges[u.ID()]
|
out := g.edges[uid]
|
||||||
nodes := make([]graph.Node, len(out))
|
nodes := make([]graph.Node, len(out))
|
||||||
for i, vid := range out {
|
for i, vid := range out {
|
||||||
nodes[i] = g.nodes[vid]
|
nodes[i] = g.nodes[vid]
|
||||||
@@ -310,9 +317,7 @@ func (g *ReducedUndirected) From(u graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g *ReducedUndirected) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *ReducedUndirected) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -325,25 +330,23 @@ func (g *ReducedUndirected) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *ReducedUndirected) Edge(u, v graph.Node) graph.Edge {
|
func (g *ReducedUndirected) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *ReducedUndirected) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *ReducedUndirected) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y.
|
// EdgeBetween returns the edge between nodes x and y.
|
||||||
func (g *ReducedUndirected) EdgeBetween(x, y graph.Node) graph.Edge {
|
func (g *ReducedUndirected) EdgeBetween(xid, yid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(x, y)
|
return g.WeightedEdgeBetween(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||||
func (g *ReducedUndirected) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
|
func (g *ReducedUndirected) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -354,16 +357,14 @@ func (g *ReducedUndirected) WeightedEdgeBetween(x, y graph.Node) graph.WeightedE
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return edge{from: g.nodes[x.ID()], to: g.nodes[y.ID()], weight: w}
|
return edge{from: g.nodes[xid], to: g.nodes[yid], weight: w}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
||||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g *ReducedUndirected) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g *ReducedUndirected) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if !isValidID(xid) || !isValidID(yid) {
|
if !isValidID(xid) || !isValidID(yid) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@@ -396,7 +397,7 @@ type undirectedLocalMover struct {
|
|||||||
// that returns the Weight value
|
// that returns the Weight value
|
||||||
// of the non-nil edge between x
|
// of the non-nil edge between x
|
||||||
// and y.
|
// and y.
|
||||||
weight func(x, y graph.Node) float64
|
weight func(xid, yid int64) float64
|
||||||
|
|
||||||
// communities is the current
|
// communities is the current
|
||||||
// division of g.
|
// division of g.
|
||||||
@@ -440,11 +441,12 @@ func newUndirectedLocalMover(g *ReducedUndirected, communities [][]graph.Node, r
|
|||||||
// Calculate the total edge weight of the graph
|
// Calculate the total edge weight of the graph
|
||||||
// and degree weights for each node.
|
// and degree weights for each node.
|
||||||
for _, u := range l.nodes {
|
for _, u := range l.nodes {
|
||||||
w := l.weight(u, u)
|
uid := u.ID()
|
||||||
for _, v := range g.From(u) {
|
w := l.weight(uid, uid)
|
||||||
w += l.weight(u, v)
|
for _, v := range g.From(uid) {
|
||||||
|
w += l.weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
l.edgeWeightOf[u.ID()] = w
|
l.edgeWeightOf[uid] = w
|
||||||
l.m2 += w
|
l.m2 += w
|
||||||
}
|
}
|
||||||
if l.m2 == 0 {
|
if l.m2 == 0 {
|
||||||
@@ -514,7 +516,7 @@ func (l *undirectedLocalMover) move(dst int, src commIdx) {
|
|||||||
// is in communities.
|
// is in communities.
|
||||||
func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
|
func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, src commIdx) {
|
||||||
id := n.ID()
|
id := n.ID()
|
||||||
a_aa := l.weight(n, n)
|
a_aa := l.weight(id, id)
|
||||||
k_a := l.edgeWeightOf[id]
|
k_a := l.edgeWeightOf[id]
|
||||||
m2 := l.m2
|
m2 := l.m2
|
||||||
gamma := l.resolution
|
gamma := l.resolution
|
||||||
@@ -559,7 +561,7 @@ func (l *undirectedLocalMover) deltaQ(n graph.Node) (deltaQ float64, dst int, sr
|
|||||||
removal = true
|
removal = true
|
||||||
}
|
}
|
||||||
|
|
||||||
k_aC += l.weight(n, u)
|
k_aC += l.weight(id, uid)
|
||||||
// sigma_totC could be kept for each community
|
// sigma_totC could be kept for each community
|
||||||
// and updated for moves, changing the calculation
|
// and updated for moves, changing the calculation
|
||||||
// of sigma_totC here from O(n_c) to O(1), but
|
// of sigma_totC here from O(n_c) to O(1), but
|
||||||
|
@@ -66,7 +66,7 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
|
|||||||
layerResolution = resolutions[l]
|
layerResolution = resolutions[l]
|
||||||
}
|
}
|
||||||
|
|
||||||
var weight func(x, y graph.Node) float64
|
var weight func(xid, yid int64) float64
|
||||||
if layerWeight < 0 {
|
if layerWeight < 0 {
|
||||||
weight = negativeWeightFuncFor(layer)
|
weight = negativeWeightFuncFor(layer)
|
||||||
} else {
|
} else {
|
||||||
@@ -78,19 +78,21 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
|
|||||||
var m2 float64
|
var m2 float64
|
||||||
k := make(map[int64]float64, len(nodes))
|
k := make(map[int64]float64, len(nodes))
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
w := weight(u, u)
|
uid := u.ID()
|
||||||
for _, v := range layer.From(u) {
|
w := weight(uid, uid)
|
||||||
w += weight(u, v)
|
for _, v := range layer.From(uid) {
|
||||||
|
w += weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
m2 += w
|
m2 += w
|
||||||
k[u.ID()] = w
|
k[uid] = w
|
||||||
}
|
}
|
||||||
|
|
||||||
if communities == nil {
|
if communities == nil {
|
||||||
var qLayer float64
|
var qLayer float64
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
kU := k[u.ID()]
|
uid := u.ID()
|
||||||
qLayer += weight(u, u) - layerResolution*kU*kU/m2
|
kU := k[uid]
|
||||||
|
qLayer += weight(uid, uid) - layerResolution*kU*kU/m2
|
||||||
}
|
}
|
||||||
q[l] = layerWeight * qLayer
|
q[l] = layerWeight * qLayer
|
||||||
continue
|
continue
|
||||||
@@ -102,10 +104,12 @@ func qUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node, wei
|
|||||||
var qLayer float64
|
var qLayer float64
|
||||||
for _, c := range communities {
|
for _, c := range communities {
|
||||||
for i, u := range c {
|
for i, u := range c {
|
||||||
kU := k[u.ID()]
|
uid := u.ID()
|
||||||
qLayer += weight(u, u) - layerResolution*kU*kU/m2
|
kU := k[uid]
|
||||||
|
qLayer += weight(uid, uid) - layerResolution*kU*kU/m2
|
||||||
for _, v := range c[i+1:] {
|
for _, v := range c[i+1:] {
|
||||||
qLayer += 2 * (weight(u, v) - layerResolution*kU*k[v.ID()]/m2)
|
vid := v.ID()
|
||||||
|
qLayer += 2 * (weight(uid, vid) - layerResolution*kU*k[vid]/m2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -319,7 +323,7 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var sign float64
|
var sign float64
|
||||||
var weight func(x, y graph.Node) float64
|
var weight func(xid, yid int64) float64
|
||||||
if w < 0 {
|
if w < 0 {
|
||||||
sign, weight = -1, negativeWeightFuncFor(layer)
|
sign, weight = -1, negativeWeightFuncFor(layer)
|
||||||
} else {
|
} else {
|
||||||
@@ -327,18 +331,20 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
|||||||
}
|
}
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
var out []int
|
var out []int
|
||||||
uid := communityOf[u.ID()]
|
uid := u.ID()
|
||||||
for _, v := range layer.From(u) {
|
ucid := communityOf[uid]
|
||||||
vid := communityOf[v.ID()]
|
for _, v := range layer.From(uid) {
|
||||||
if vid != uid {
|
vid := v.ID()
|
||||||
out = append(out, vid)
|
vcid := communityOf[vid]
|
||||||
|
if vcid != ucid {
|
||||||
|
out = append(out, vcid)
|
||||||
}
|
}
|
||||||
if uid < vid {
|
if ucid < vcid {
|
||||||
// Only store the weight once.
|
// Only store the weight once.
|
||||||
r.layers[l].weights[[2]int{uid, vid}] = sign * weight(u, v)
|
r.layers[l].weights[[2]int{ucid, vcid}] = sign * weight(uid, vid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.layers[l].edges[uid] = out
|
r.layers[l].edges[ucid] = out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &r
|
return &r
|
||||||
@@ -395,38 +401,40 @@ func reduceUndirectedMultiplex(g UndirectedMultiplex, communities [][]graph.Node
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var sign float64
|
var sign float64
|
||||||
var weight func(x, y graph.Node) float64
|
var weight func(xid, yid int64) float64
|
||||||
if w < 0 {
|
if w < 0 {
|
||||||
sign, weight = -1, negativeWeightFuncFor(layer)
|
sign, weight = -1, negativeWeightFuncFor(layer)
|
||||||
} else {
|
} else {
|
||||||
sign, weight = 1, positiveWeightFuncFor(layer)
|
sign, weight = 1, positiveWeightFuncFor(layer)
|
||||||
}
|
}
|
||||||
for uid, comm := range communities {
|
for ucid, comm := range communities {
|
||||||
var out []int
|
var out []int
|
||||||
for i, u := range comm {
|
for i, u := range comm {
|
||||||
r.nodes[uid].weights[l] += sign * weight(u, u)
|
uid := u.ID()
|
||||||
|
r.nodes[ucid].weights[l] += sign * weight(uid, uid)
|
||||||
for _, v := range comm[i+1:] {
|
for _, v := range comm[i+1:] {
|
||||||
r.nodes[uid].weights[l] += 2 * sign * weight(u, v)
|
r.nodes[ucid].weights[l] += 2 * sign * weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
for _, v := range layer.From(u) {
|
for _, v := range layer.From(uid) {
|
||||||
vid := communityOf[v.ID()]
|
vid := v.ID()
|
||||||
|
vcid := communityOf[vid]
|
||||||
found := false
|
found := false
|
||||||
for _, e := range out {
|
for _, e := range out {
|
||||||
if e == vid {
|
if e == vcid {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found && vid != uid {
|
if !found && vcid != ucid {
|
||||||
out = append(out, vid)
|
out = append(out, vcid)
|
||||||
}
|
}
|
||||||
if uid < vid {
|
if ucid < vcid {
|
||||||
// Only store the weight once.
|
// Only store the weight once.
|
||||||
r.layers[l].weights[[2]int{uid, vid}] += sign * weight(u, v)
|
r.layers[l].weights[[2]int{ucid, vcid}] += sign * weight(uid, vid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
r.layers[l].edges[uid] = out
|
r.layers[l].edges[ucid] = out
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &r
|
return &r
|
||||||
@@ -445,8 +453,7 @@ type undirectedLayerHandle struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g undirectedLayerHandle) Has(n graph.Node) bool {
|
func (g undirectedLayerHandle) Has(id int64) bool {
|
||||||
id := n.ID()
|
|
||||||
return 0 <= id && id < int64(len(g.multiplex.nodes))
|
return 0 <= id && id < int64(len(g.multiplex.nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,8 +467,8 @@ func (g undirectedLayerHandle) Nodes() []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from u.
|
// From returns all nodes in g that can be reached directly from u.
|
||||||
func (g undirectedLayerHandle) From(u graph.Node) []graph.Node {
|
func (g undirectedLayerHandle) From(uid int64) []graph.Node {
|
||||||
out := g.multiplex.layers[g.layer].edges[u.ID()]
|
out := g.multiplex.layers[g.layer].edges[uid]
|
||||||
nodes := make([]graph.Node, len(out))
|
nodes := make([]graph.Node, len(out))
|
||||||
for i, vid := range out {
|
for i, vid := range out {
|
||||||
nodes[i] = g.multiplex.nodes[vid]
|
nodes[i] = g.multiplex.nodes[vid]
|
||||||
@@ -470,9 +477,7 @@ func (g undirectedLayerHandle) From(u graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g undirectedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
|
func (g undirectedLayerHandle) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -485,25 +490,23 @@ func (g undirectedLayerHandle) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g undirectedLayerHandle) Edge(u, v graph.Node) graph.Edge {
|
func (g undirectedLayerHandle) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g undirectedLayerHandle) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g undirectedLayerHandle) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y.
|
// EdgeBetween returns the edge between nodes x and y.
|
||||||
func (g undirectedLayerHandle) EdgeBetween(x, y graph.Node) graph.Edge {
|
func (g undirectedLayerHandle) EdgeBetween(xid, yid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(x, y)
|
return g.WeightedEdgeBetween(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||||
func (g undirectedLayerHandle) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
|
func (g undirectedLayerHandle) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
if xid == yid || !isValidID(xid) || !isValidID(yid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -514,16 +517,14 @@ func (g undirectedLayerHandle) WeightedEdgeBetween(x, y graph.Node) graph.Weight
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return multiplexEdge{from: g.multiplex.nodes[x.ID()], to: g.multiplex.nodes[y.ID()], weight: w}
|
return multiplexEdge{from: g.multiplex.nodes[xid], to: g.multiplex.nodes[yid], weight: w}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
||||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g undirectedLayerHandle) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g undirectedLayerHandle) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if !isValidID(xid) || !isValidID(yid) {
|
if !isValidID(xid) || !isValidID(yid) {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@@ -556,7 +557,7 @@ type undirectedMultiplexLocalMover struct {
|
|||||||
// that returns the Weight value
|
// that returns the Weight value
|
||||||
// of the non-nil edge between x
|
// of the non-nil edge between x
|
||||||
// and y.
|
// and y.
|
||||||
weight []func(x, y graph.Node) float64
|
weight []func(xid, yid int64) float64
|
||||||
|
|
||||||
// communities is the current
|
// communities is the current
|
||||||
// division of g.
|
// division of g.
|
||||||
@@ -606,7 +607,7 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
|
|||||||
memberships: make([]int, len(nodes)),
|
memberships: make([]int, len(nodes)),
|
||||||
resolutions: resolutions,
|
resolutions: resolutions,
|
||||||
weights: weights,
|
weights: weights,
|
||||||
weight: make([]func(x, y graph.Node) float64, g.Depth()),
|
weight: make([]func(xid, yid int64) float64, g.Depth()),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the total edge weight of the graph
|
// Calculate the total edge weight of the graph
|
||||||
@@ -614,7 +615,7 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
|
|||||||
var zero int
|
var zero int
|
||||||
for i := 0; i < g.Depth(); i++ {
|
for i := 0; i < g.Depth(); i++ {
|
||||||
l.edgeWeightOf[i] = make([]float64, len(nodes))
|
l.edgeWeightOf[i] = make([]float64, len(nodes))
|
||||||
var weight func(x, y graph.Node) float64
|
var weight func(xid, yid int64) float64
|
||||||
|
|
||||||
if weights != nil {
|
if weights != nil {
|
||||||
if weights[i] == 0 {
|
if weights[i] == 0 {
|
||||||
@@ -634,11 +635,12 @@ func newUndirectedMultiplexLocalMover(g *ReducedUndirectedMultiplex, communities
|
|||||||
l.weight[i] = weight
|
l.weight[i] = weight
|
||||||
layer := g.Layer(i)
|
layer := g.Layer(i)
|
||||||
for _, u := range l.nodes {
|
for _, u := range l.nodes {
|
||||||
w := weight(u, u)
|
uid := u.ID()
|
||||||
for _, v := range layer.From(u) {
|
w := weight(uid, uid)
|
||||||
w += weight(u, v)
|
for _, v := range layer.From(uid) {
|
||||||
|
w += weight(uid, v.ID())
|
||||||
}
|
}
|
||||||
l.edgeWeightOf[i][u.ID()] = w
|
l.edgeWeightOf[i][uid] = w
|
||||||
l.m2[i] += w
|
l.m2[i] += w
|
||||||
}
|
}
|
||||||
if l.m2[i] == 0 {
|
if l.m2[i] == 0 {
|
||||||
@@ -779,7 +781,7 @@ func (l *undirectedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, ds
|
|||||||
removal = true
|
removal = true
|
||||||
}
|
}
|
||||||
|
|
||||||
k_aC += l.weight[layer](n, u)
|
k_aC += l.weight[layer](id, uid)
|
||||||
// sigma_totC could be kept for each community
|
// sigma_totC could be kept for each community
|
||||||
// and updated for moves, changing the calculation
|
// and updated for moves, changing the calculation
|
||||||
// of sigma_totC here from O(n_c) to O(1), but
|
// of sigma_totC here from O(n_c) to O(1), but
|
||||||
@@ -789,7 +791,7 @@ func (l *undirectedMultiplexLocalMover) deltaQ(n graph.Node) (deltaQ float64, ds
|
|||||||
sigma_totC += l.edgeWeightOf[layer][uid]
|
sigma_totC += l.edgeWeightOf[layer][uid]
|
||||||
}
|
}
|
||||||
|
|
||||||
a_aa := l.weight[layer](n, n)
|
a_aa := l.weight[layer](id, id)
|
||||||
k_a := l.edgeWeightOf[layer][id]
|
k_a := l.edgeWeightOf[layer][id]
|
||||||
gamma := 1.0
|
gamma := 1.0
|
||||||
if l.resolutions != nil {
|
if l.resolutions != nil {
|
||||||
|
@@ -359,7 +359,7 @@ tests:
|
|||||||
}
|
}
|
||||||
layer := g.Layer(l)
|
layer := g.Layer(l)
|
||||||
for n := range c {
|
for n := range c {
|
||||||
if layer.HasEdgeBetween(simple.Node(n), target) {
|
if layer.HasEdgeBetween(int64(n), target.ID()) {
|
||||||
connected = true
|
connected = true
|
||||||
break search
|
break search
|
||||||
}
|
}
|
||||||
@@ -670,7 +670,7 @@ func undirectedMultiplexFrom(raw []layer) (UndirectedLayers, []float64, error) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range l.g {
|
for u, e := range l.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -267,7 +267,7 @@ func TestCommunityQUndirected(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -284,7 +284,7 @@ func TestCommunityQWeightedUndirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -320,7 +320,7 @@ func TestCommunityDeltaQUndirected(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -337,7 +337,7 @@ func TestCommunityDeltaQWeightedUndirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -401,7 +401,7 @@ func testCommunityDeltaQUndirected(t *testing.T, test communityUndirectedQTest,
|
|||||||
}
|
}
|
||||||
connected := false
|
connected := false
|
||||||
for n := range c {
|
for n := range c {
|
||||||
if g.HasEdgeBetween(simple.Node(n), target) {
|
if g.HasEdgeBetween(int64(n), target.ID()) {
|
||||||
connected = true
|
connected = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -445,7 +445,7 @@ func TestReduceQConsistencyUndirected(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -462,7 +462,7 @@ func TestReduceQConsistencyWeightedUndirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -563,7 +563,7 @@ func TestMoveLocalUndirected(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -580,7 +580,7 @@ func TestMoveLocalWeightedUndirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -625,7 +625,7 @@ func TestModularizeUndirected(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -642,7 +642,7 @@ func TestModularizeWeightedUndirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, 0)
|
g := simple.NewWeightedUndirectedGraph(0, 0)
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -151,7 +151,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
|||||||
if s, ok := n.(Subgrapher); ok {
|
if s, ok := n.(Subgrapher); ok {
|
||||||
// If the node is not linked to any other node
|
// If the node is not linked to any other node
|
||||||
// the graph needs to be written now.
|
// the graph needs to be written now.
|
||||||
if len(g.From(n)) == 0 {
|
if len(g.From(n.ID())) == 0 {
|
||||||
g := s.Subgraph()
|
g := s.Subgraph()
|
||||||
_, subIsDirected := g.(graph.Directed)
|
_, subIsDirected := g.(graph.Directed)
|
||||||
if subIsDirected != isDirected {
|
if subIsDirected != isDirected {
|
||||||
@@ -182,20 +182,22 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
|||||||
|
|
||||||
havePrintedEdgeHeader := false
|
havePrintedEdgeHeader := false
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
to := g.From(n)
|
nid := n.ID()
|
||||||
|
to := g.From(nid)
|
||||||
sort.Sort(ordered.ByID(to))
|
sort.Sort(ordered.ByID(to))
|
||||||
for _, t := range to {
|
for _, t := range to {
|
||||||
|
tid := t.ID()
|
||||||
if isDirected {
|
if isDirected {
|
||||||
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
|
if p.visited[edge{inGraph: name, from: nid, to: tid}] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
|
p.visited[edge{inGraph: name, from: nid, to: tid}] = true
|
||||||
} else {
|
} else {
|
||||||
if p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] {
|
if p.visited[edge{inGraph: name, from: nid, to: tid}] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.visited[edge{inGraph: name, from: n.ID(), to: t.ID()}] = true
|
p.visited[edge{inGraph: name, from: nid, to: tid}] = true
|
||||||
p.visited[edge{inGraph: name, from: t.ID(), to: n.ID()}] = true
|
p.visited[edge{inGraph: name, from: tid, to: n.ID()}] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !havePrintedEdgeHeader {
|
if !havePrintedEdgeHeader {
|
||||||
@@ -217,7 +219,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
|||||||
} else {
|
} else {
|
||||||
p.writeNode(n)
|
p.writeNode(n)
|
||||||
}
|
}
|
||||||
e, edgeIsPorter := g.Edge(n, t).(Porter)
|
e, edgeIsPorter := g.Edge(nid, tid).(Porter)
|
||||||
if edgeIsPorter {
|
if edgeIsPorter {
|
||||||
p.writePorts(e.FromPort())
|
p.writePorts(e.FromPort())
|
||||||
}
|
}
|
||||||
@@ -242,7 +244,7 @@ func (p *printer) print(g graph.Graph, name string, needsIndent, isSubgraph bool
|
|||||||
p.writePorts(e.ToPort())
|
p.writePorts(e.ToPort())
|
||||||
}
|
}
|
||||||
|
|
||||||
if a, ok := g.Edge(n, t).(encoding.Attributer); ok {
|
if a, ok := g.Edge(nid, tid).(encoding.Attributer); ok {
|
||||||
p.writeAttributeList(a)
|
p.writeAttributeList(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,29 +11,29 @@ type GraphNode struct {
|
|||||||
roots []*GraphNode
|
roots []*GraphNode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GraphNode) Has(n graph.Node) bool {
|
func (g *GraphNode) Has(id int64) bool {
|
||||||
if n.ID() == g.id {
|
if id == g.id {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
visited := map[int64]struct{}{g.id: {}}
|
visited := map[int64]struct{}{g.id: {}}
|
||||||
for _, root := range g.roots {
|
for _, root := range g.roots {
|
||||||
if root.ID() == n.ID() {
|
if root.ID() == id {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if root.has(n, visited) {
|
if root.has(id, visited) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, neigh := range g.neighbors {
|
for _, neigh := range g.neighbors {
|
||||||
if neigh.ID() == n.ID() {
|
if neigh.ID() == id {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if gn, ok := neigh.(*GraphNode); ok {
|
if gn, ok := neigh.(*GraphNode); ok {
|
||||||
if gn.has(n, visited) {
|
if gn.has(id, visited) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,18 +42,18 @@ func (g *GraphNode) Has(n graph.Node) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GraphNode) has(n graph.Node, visited map[int64]struct{}) bool {
|
func (g *GraphNode) has(id int64, visited map[int64]struct{}) bool {
|
||||||
for _, root := range g.roots {
|
for _, root := range g.roots {
|
||||||
if _, ok := visited[root.ID()]; ok {
|
if _, ok := visited[root.ID()]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
visited[root.ID()] = struct{}{}
|
visited[root.ID()] = struct{}{}
|
||||||
if root.ID() == n.ID() {
|
if root.ID() == id {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if root.has(n, visited) {
|
if root.has(id, visited) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,16 +65,15 @@ func (g *GraphNode) has(n graph.Node, visited map[int64]struct{}) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visited[neigh.ID()] = struct{}{}
|
visited[neigh.ID()] = struct{}{}
|
||||||
if neigh.ID() == n.ID() {
|
if neigh.ID() == id {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if gn, ok := neigh.(*GraphNode); ok {
|
if gn, ok := neigh.(*GraphNode); ok {
|
||||||
if gn.has(n, visited) {
|
if gn.has(id, visited) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
@@ -128,8 +127,8 @@ func (g *GraphNode) nodes(list []graph.Node, visited map[int64]struct{}) []graph
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GraphNode) From(n graph.Node) []graph.Node {
|
func (g *GraphNode) From(id int64) []graph.Node {
|
||||||
if n.ID() == g.ID() {
|
if id == g.ID() {
|
||||||
return g.neighbors
|
return g.neighbors
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +136,7 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
|
|||||||
for _, root := range g.roots {
|
for _, root := range g.roots {
|
||||||
visited[root.ID()] = struct{}{}
|
visited[root.ID()] = struct{}{}
|
||||||
|
|
||||||
if result := root.findNeighbors(n, visited); result != nil {
|
if result := root.findNeighbors(id, visited); result != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +145,7 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
|
|||||||
visited[neigh.ID()] = struct{}{}
|
visited[neigh.ID()] = struct{}{}
|
||||||
|
|
||||||
if gn, ok := neigh.(*GraphNode); ok {
|
if gn, ok := neigh.(*GraphNode); ok {
|
||||||
if result := gn.findNeighbors(n, visited); result != nil {
|
if result := gn.findNeighbors(id, visited); result != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,8 +154,8 @@ func (g *GraphNode) From(n graph.Node) []graph.Node {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []graph.Node {
|
func (g *GraphNode) findNeighbors(id int64, visited map[int64]struct{}) []graph.Node {
|
||||||
if n.ID() == g.ID() {
|
if id == g.ID() {
|
||||||
return g.neighbors
|
return g.neighbors
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +165,7 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
|
|||||||
}
|
}
|
||||||
visited[root.ID()] = struct{}{}
|
visited[root.ID()] = struct{}{}
|
||||||
|
|
||||||
if result := root.findNeighbors(n, visited); result != nil {
|
if result := root.findNeighbors(id, visited); result != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +177,7 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
|
|||||||
visited[neigh.ID()] = struct{}{}
|
visited[neigh.ID()] = struct{}{}
|
||||||
|
|
||||||
if gn, ok := neigh.(*GraphNode); ok {
|
if gn, ok := neigh.(*GraphNode); ok {
|
||||||
if result := gn.findNeighbors(n, visited); result != nil {
|
if result := gn.findNeighbors(id, visited); result != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,18 +186,18 @@ func (g *GraphNode) findNeighbors(n graph.Node, visited map[int64]struct{}) []gr
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GraphNode) HasEdgeBetween(u, v graph.Node) bool {
|
func (g *GraphNode) HasEdgeBetween(uid, vid int64) bool {
|
||||||
return g.EdgeBetween(u, v) != nil
|
return g.EdgeBetween(uid, vid) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GraphNode) Edge(u, v graph.Node) graph.Edge {
|
func (g *GraphNode) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.EdgeBetween(u, v)
|
return g.EdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
|
func (g *GraphNode) EdgeBetween(uid, vid int64) graph.Edge {
|
||||||
if u.ID() == g.id || v.ID() == g.id {
|
if uid == g.id || vid == g.id {
|
||||||
for _, neigh := range g.neighbors {
|
for _, neigh := range g.neighbors {
|
||||||
if neigh.ID() == u.ID() || neigh.ID() == v.ID() {
|
if neigh.ID() == uid || neigh.ID() == vid {
|
||||||
return simple.Edge{F: g, T: neigh}
|
return simple.Edge{F: g, T: neigh}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -208,7 +207,7 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
|
|||||||
visited := map[int64]struct{}{g.id: {}}
|
visited := map[int64]struct{}{g.id: {}}
|
||||||
for _, root := range g.roots {
|
for _, root := range g.roots {
|
||||||
visited[root.ID()] = struct{}{}
|
visited[root.ID()] = struct{}{}
|
||||||
if result := root.edgeBetween(u, v, visited); result != nil {
|
if result := root.edgeBetween(uid, vid, visited); result != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,7 +215,7 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
|
|||||||
for _, neigh := range g.neighbors {
|
for _, neigh := range g.neighbors {
|
||||||
visited[neigh.ID()] = struct{}{}
|
visited[neigh.ID()] = struct{}{}
|
||||||
if gn, ok := neigh.(*GraphNode); ok {
|
if gn, ok := neigh.(*GraphNode); ok {
|
||||||
if result := gn.edgeBetween(u, v, visited); result != nil {
|
if result := gn.edgeBetween(uid, vid, visited); result != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,10 +224,10 @@ func (g *GraphNode) EdgeBetween(u, v graph.Node) graph.Edge {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) graph.Edge {
|
func (g *GraphNode) edgeBetween(uid, vid int64, visited map[int64]struct{}) graph.Edge {
|
||||||
if u.ID() == g.id || v.ID() == g.id {
|
if uid == g.id || vid == g.id {
|
||||||
for _, neigh := range g.neighbors {
|
for _, neigh := range g.neighbors {
|
||||||
if neigh.ID() == u.ID() || neigh.ID() == v.ID() {
|
if neigh.ID() == uid || neigh.ID() == vid {
|
||||||
return simple.Edge{F: g, T: neigh}
|
return simple.Edge{F: g, T: neigh}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,7 +239,7 @@ func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) gra
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
visited[root.ID()] = struct{}{}
|
visited[root.ID()] = struct{}{}
|
||||||
if result := root.edgeBetween(u, v, visited); result != nil {
|
if result := root.edgeBetween(uid, vid, visited); result != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +251,7 @@ func (g *GraphNode) edgeBetween(u, v graph.Node, visited map[int64]struct{}) gra
|
|||||||
|
|
||||||
visited[neigh.ID()] = struct{}{}
|
visited[neigh.ID()] = struct{}{}
|
||||||
if gn, ok := neigh.(*GraphNode); ok {
|
if gn, ok := neigh.(*GraphNode); ok {
|
||||||
if result := gn.edgeBetween(u, v, visited); result != nil {
|
if result := gn.edgeBetween(uid, vid, visited); result != nil {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,53 +27,57 @@ type WeightedEdge interface {
|
|||||||
|
|
||||||
// Graph is a generalized graph.
|
// Graph is a generalized graph.
|
||||||
type Graph interface {
|
type Graph interface {
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether a node with the given ID exists
|
||||||
Has(Node) bool
|
// within the graph.
|
||||||
|
Has(id int64) bool
|
||||||
|
|
||||||
// Nodes returns all the nodes in the graph.
|
// Nodes returns all the nodes in the graph.
|
||||||
Nodes() []Node
|
Nodes() []Node
|
||||||
|
|
||||||
// From returns all nodes that can be reached directly
|
// From returns all nodes that can be reached directly
|
||||||
// from the given node.
|
// from the node with the given ID.
|
||||||
From(Node) []Node
|
From(id int64) []Node
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between
|
// HasEdgeBetween returns whether an edge exists between
|
||||||
// nodes x and y without considering direction.
|
// nodes with IDs xid and yid without considering direction.
|
||||||
HasEdgeBetween(x, y Node) bool
|
HasEdgeBetween(xid, yid int64) bool
|
||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge
|
// Edge returns the edge from u to v, with IDs uid and vid,
|
||||||
// exists and nil otherwise. The node v must be directly
|
// if such an edge exists and nil otherwise. The node v
|
||||||
// reachable from u as defined by the From method.
|
// must be directly reachable from u as defined by the
|
||||||
Edge(u, v Node) Edge
|
// From method.
|
||||||
|
Edge(uid, vid int64) Edge
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weighted is a weighted graph.
|
// Weighted is a weighted graph.
|
||||||
type Weighted interface {
|
type Weighted interface {
|
||||||
Graph
|
Graph
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if
|
// WeightedEdge returns the weighted edge from u to v
|
||||||
// such an edge exists and nil otherwise. The node v must
|
// with IDs uid and vid if such an edge exists and
|
||||||
// be directly reachable from u as defined by the
|
// nil otherwise. The node v must be directly
|
||||||
// From method.
|
// reachable from u as defined by the From method.
|
||||||
WeightedEdge(u, v Node) WeightedEdge
|
WeightedEdge(uid, vid int64) WeightedEdge
|
||||||
|
|
||||||
// Weight returns the weight for the edge between
|
// Weight returns the weight for the edge between
|
||||||
// x and y if Edge(x, y) returns a non-nil Edge.
|
// x and y with IDs xid and yid if Edge(xid, yid)
|
||||||
|
// returns a non-nil Edge.
|
||||||
// If x and y are the same node or there is no
|
// If x and y are the same node or there is no
|
||||||
// joining edge between the two nodes the weight
|
// joining edge between the two nodes the weight
|
||||||
// value returned is implementation dependent.
|
// value returned is implementation dependent.
|
||||||
// Weight returns true if an edge exists between
|
// Weight returns true if an edge exists between
|
||||||
// x and y or if x and y have the same ID, false
|
// x and y or if x and y have the same ID, false
|
||||||
// otherwise.
|
// otherwise.
|
||||||
Weight(x, y Node) (w float64, ok bool)
|
Weight(xid, yid int64) (w float64, ok bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undirected is an undirected graph.
|
// Undirected is an undirected graph.
|
||||||
type Undirected interface {
|
type Undirected interface {
|
||||||
Graph
|
Graph
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y.
|
// EdgeBetween returns the edge between nodes x and y
|
||||||
EdgeBetween(x, y Node) Edge
|
// with IDs xid and yid.
|
||||||
|
EdgeBetween(xid, yid int64) Edge
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedUndirected is a weighted undirected graph.
|
// WeightedUndirected is a weighted undirected graph.
|
||||||
@@ -81,8 +85,8 @@ type WeightedUndirected interface {
|
|||||||
Weighted
|
Weighted
|
||||||
|
|
||||||
// WeightedEdgeBetween returns the edge between nodes
|
// WeightedEdgeBetween returns the edge between nodes
|
||||||
// x and y.
|
// x and y with IDs xid and yid.
|
||||||
WeightedEdgeBetween(x, y Node) WeightedEdge
|
WeightedEdgeBetween(xid, yid int64) WeightedEdge
|
||||||
}
|
}
|
||||||
|
|
||||||
// Directed is a directed graph.
|
// Directed is a directed graph.
|
||||||
@@ -90,12 +94,12 @@ type Directed interface {
|
|||||||
Graph
|
Graph
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists
|
// HasEdgeFromTo returns whether an edge exists
|
||||||
// in the graph from u to v.
|
// in the graph from u to v with IDs uid and vid.
|
||||||
HasEdgeFromTo(u, v Node) bool
|
HasEdgeFromTo(uid, vid int64) bool
|
||||||
|
|
||||||
// To returns all nodes that can reach directly
|
// To returns all nodes that can reach directly
|
||||||
// to the given node.
|
// to the node with the given ID.
|
||||||
To(Node) []Node
|
To(id int64) []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedDirected is a weighted directed graph.
|
// WeightedDirected is a weighted directed graph.
|
||||||
@@ -103,12 +107,13 @@ type WeightedDirected interface {
|
|||||||
Weighted
|
Weighted
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists
|
// HasEdgeFromTo returns whether an edge exists
|
||||||
// in the graph from u to v.
|
// in the graph from u to v with the IDs uid and
|
||||||
HasEdgeFromTo(u, v Node) bool
|
// vid.
|
||||||
|
HasEdgeFromTo(uid, vid int64) bool
|
||||||
|
|
||||||
// To returns all nodes that can reach directly
|
// To returns all nodes that can reach directly
|
||||||
// to the given node.
|
// to the node with the given ID.
|
||||||
To(Node) []Node
|
To(id int64) []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeAdder is an interface for adding arbitrary nodes to a graph.
|
// NodeAdder is an interface for adding arbitrary nodes to a graph.
|
||||||
@@ -217,7 +222,7 @@ func Copy(dst Builder, src Graph) {
|
|||||||
dst.AddNode(n)
|
dst.AddNode(n)
|
||||||
}
|
}
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
for _, v := range src.From(u) {
|
for _, v := range src.From(u.ID()) {
|
||||||
dst.SetEdge(dst.NewEdge(u, v))
|
dst.SetEdge(dst.NewEdge(u, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -240,8 +245,8 @@ func CopyWeighted(dst WeightedBuilder, src Weighted) {
|
|||||||
dst.AddNode(n)
|
dst.AddNode(n)
|
||||||
}
|
}
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
for _, v := range src.From(u) {
|
for _, v := range src.From(u.ID()) {
|
||||||
dst.SetWeightedEdge(dst.NewWeightedEdge(u, v, src.WeightedEdge(u, v).Weight()))
|
dst.SetWeightedEdge(dst.NewWeightedEdge(u, v, src.WeightedEdge(u.ID(), v.ID()).Weight()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -273,8 +273,8 @@ func same(a, b graph.Graph) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, u := range a.Nodes() {
|
for _, u := range a.Nodes() {
|
||||||
aFromU := a.From(u)
|
aFromU := a.From(u.ID())
|
||||||
bFromU := b.From(u)
|
bFromU := b.From(u.ID())
|
||||||
if len(aFromU) != len(bFromU) {
|
if len(aFromU) != len(bFromU) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -288,7 +288,7 @@ func same(a, b graph.Graph) bool {
|
|||||||
aW, aWok := a.(graph.Weighted)
|
aW, aWok := a.(graph.Weighted)
|
||||||
bW, bWok := b.(graph.Weighted)
|
bW, bWok := b.(graph.Weighted)
|
||||||
if aWok && bWok {
|
if aWok && bWok {
|
||||||
if aW.WeightedEdge(u, va).Weight() != bW.WeightedEdge(u, vb).Weight() {
|
if aW.WeightedEdge(u.ID(), va.ID()).Weight() != bW.WeightedEdge(u.ID(), vb.ID()).Weight() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,7 @@ func Gnp(dst GraphBuilder, n int, p float64, src *rand.Rand) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
if !dst.Has(simple.Node(i)) {
|
if !dst.Has(int64(i)) {
|
||||||
dst.AddNode(simple.Node(i))
|
dst.AddNode(simple.Node(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
if !dst.Has(simple.Node(i)) {
|
if !dst.Has(int64(i)) {
|
||||||
dst.AddNode(simple.Node(i))
|
dst.AddNode(simple.Node(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
|
|||||||
for {
|
for {
|
||||||
v, w := edgeNodesFor(rnd(nChoose2))
|
v, w := edgeNodesFor(rnd(nChoose2))
|
||||||
e := simple.Edge{F: w, T: v}
|
e := simple.Edge{F: w, T: v}
|
||||||
if !hasEdge(e.F, e.T) {
|
if !hasEdge(e.F.ID(), e.T.ID()) {
|
||||||
dst.SetEdge(e)
|
dst.SetEdge(e)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ func Gnm(dst GraphBuilder, n, m int, src *rand.Rand) error {
|
|||||||
for {
|
for {
|
||||||
v, w := edgeNodesFor(rnd(nChoose2))
|
v, w := edgeNodesFor(rnd(nChoose2))
|
||||||
e := simple.Edge{F: v, T: w}
|
e := simple.Edge{F: v, T: w}
|
||||||
if !hasEdge(e.F, e.T) {
|
if !hasEdge(e.F.ID(), e.T.ID()) {
|
||||||
dst.SetEdge(e)
|
dst.SetEdge(e)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
if !dst.Has(simple.Node(i)) {
|
if !dst.Has(int64(i)) {
|
||||||
dst.AddNode(simple.Node(i))
|
dst.AddNode(simple.Node(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,14 +201,14 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
|||||||
j := v*(v-1)/2 + (v+i)%n
|
j := v*(v-1)/2 + (v+i)%n
|
||||||
var ej simple.Edge
|
var ej simple.Edge
|
||||||
ej.T, ej.F = edgeNodesFor(j)
|
ej.T, ej.F = edgeNodesFor(j)
|
||||||
if !hasEdge(ej.From(), ej.To()) {
|
if !hasEdge(ej.From().ID(), ej.To().ID()) {
|
||||||
dst.SetEdge(ej)
|
dst.SetEdge(ej)
|
||||||
}
|
}
|
||||||
k--
|
k--
|
||||||
m++
|
m++
|
||||||
var em simple.Edge
|
var em simple.Edge
|
||||||
em.T, em.F = edgeNodesFor(m)
|
em.T, em.F = edgeNodesFor(m)
|
||||||
if !hasEdge(em.From(), em.To()) {
|
if !hasEdge(em.From().ID(), em.To().ID()) {
|
||||||
replace[j] = m
|
replace[j] = m
|
||||||
} else {
|
} else {
|
||||||
replace[j] = replace[m]
|
replace[j] = replace[m]
|
||||||
@@ -222,17 +222,17 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
|||||||
r := rndN(nChoose2-i) + i
|
r := rndN(nChoose2-i) + i
|
||||||
var er simple.Edge
|
var er simple.Edge
|
||||||
er.T, er.F = edgeNodesFor(r)
|
er.T, er.F = edgeNodesFor(r)
|
||||||
if !hasEdge(er.From(), er.To()) {
|
if !hasEdge(er.From().ID(), er.To().ID()) {
|
||||||
dst.SetEdge(er)
|
dst.SetEdge(er)
|
||||||
} else {
|
} else {
|
||||||
er.T, er.F = edgeNodesFor(replace[r])
|
er.T, er.F = edgeNodesFor(replace[r])
|
||||||
if !hasEdge(er.From(), er.To()) {
|
if !hasEdge(er.From().ID(), er.To().ID()) {
|
||||||
dst.SetEdge(er)
|
dst.SetEdge(er)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var ei simple.Edge
|
var ei simple.Edge
|
||||||
ei.T, ei.F = edgeNodesFor(i)
|
ei.T, ei.F = edgeNodesFor(i)
|
||||||
if !hasEdge(ei.From(), ei.To()) {
|
if !hasEdge(ei.From().ID(), ei.To().ID()) {
|
||||||
replace[r] = i
|
replace[r] = i
|
||||||
} else {
|
} else {
|
||||||
replace[r] = replace[i]
|
replace[r] = replace[i]
|
||||||
@@ -252,12 +252,12 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
|||||||
j := v*(v-1)/2 + (v+i)%n
|
j := v*(v-1)/2 + (v+i)%n
|
||||||
var ej simple.Edge
|
var ej simple.Edge
|
||||||
ej.F, ej.T = edgeNodesFor(j)
|
ej.F, ej.T = edgeNodesFor(j)
|
||||||
if !hasEdge(ej.From(), ej.To()) {
|
if !hasEdge(ej.From().ID(), ej.To().ID()) {
|
||||||
dst.SetEdge(ej)
|
dst.SetEdge(ej)
|
||||||
}
|
}
|
||||||
k--
|
k--
|
||||||
m++
|
m++
|
||||||
if !hasEdge(edgeNodesFor(m)) {
|
if u, v := edgeNodesFor(m); !hasEdge(u.ID(), v.ID()) {
|
||||||
replace[j] = m
|
replace[j] = m
|
||||||
} else {
|
} else {
|
||||||
replace[j] = replace[m]
|
replace[j] = replace[m]
|
||||||
@@ -271,15 +271,15 @@ func SmallWorldsBB(dst GraphBuilder, n, d int, p float64, src *rand.Rand) error
|
|||||||
r := rndN(nChoose2-i) + i
|
r := rndN(nChoose2-i) + i
|
||||||
var er simple.Edge
|
var er simple.Edge
|
||||||
er.F, er.T = edgeNodesFor(r)
|
er.F, er.T = edgeNodesFor(r)
|
||||||
if !hasEdge(er.From(), er.To()) {
|
if !hasEdge(er.From().ID(), er.To().ID()) {
|
||||||
dst.SetEdge(er)
|
dst.SetEdge(er)
|
||||||
} else {
|
} else {
|
||||||
er.F, er.T = edgeNodesFor(replace[r])
|
er.F, er.T = edgeNodesFor(replace[r])
|
||||||
if !hasEdge(er.From(), er.To()) {
|
if !hasEdge(er.From().ID(), er.To().ID()) {
|
||||||
dst.SetEdge(er)
|
dst.SetEdge(er)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !hasEdge(edgeNodesFor(i)) {
|
if u, v := edgeNodesFor(i); !hasEdge(u.ID(), v.ID()) {
|
||||||
replace[r] = i
|
replace[r] = i
|
||||||
} else {
|
} else {
|
||||||
replace[r] = replace[i]
|
replace[r] = replace[i]
|
||||||
|
@@ -27,7 +27,7 @@ func (g *gnUndirected) SetEdge(e graph.Edge) {
|
|||||||
return
|
return
|
||||||
case e.From().ID() > e.To().ID():
|
case e.From().ID() > e.To().ID():
|
||||||
g.addBackwards = true
|
g.addBackwards = true
|
||||||
case g.UndirectedBuilder.HasEdgeBetween(e.From(), e.To()):
|
case g.UndirectedBuilder.HasEdgeBetween(e.From().ID(), e.To().ID()):
|
||||||
g.addMultipleEdge = true
|
g.addMultipleEdge = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ func (g *gnDirected) SetEdge(e graph.Edge) {
|
|||||||
case e.From().ID() == e.To().ID():
|
case e.From().ID() == e.To().ID():
|
||||||
g.addSelfLoop = true
|
g.addSelfLoop = true
|
||||||
return
|
return
|
||||||
case g.DirectedBuilder.HasEdgeFromTo(e.From(), e.To()):
|
case g.DirectedBuilder.HasEdgeFromTo(e.From().ID(), e.To().ID()):
|
||||||
g.addMultipleEdge = true
|
g.addMultipleEdge = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,9 +190,10 @@ func TestPowerLawUndirected(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
var lines int
|
var lines int
|
||||||
for _, v := range g.From(u) {
|
for _, v := range g.From(uid) {
|
||||||
lines += len(g.Lines(u, v))
|
lines += len(g.Lines(uid, v.ID()))
|
||||||
}
|
}
|
||||||
if lines < d {
|
if lines < d {
|
||||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||||
@@ -218,9 +219,10 @@ func TestPowerLawDirected(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
var lines int
|
var lines int
|
||||||
for _, v := range g.From(u) {
|
for _, v := range g.From(uid) {
|
||||||
lines += len(g.Lines(u, v))
|
lines += len(g.Lines(uid, v.ID()))
|
||||||
}
|
}
|
||||||
if lines < d {
|
if lines < d {
|
||||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||||
@@ -265,9 +267,10 @@ func TestBipartitePowerLawUndirected(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
var lines int
|
var lines int
|
||||||
for _, v := range g.From(u) {
|
for _, v := range g.From(uid) {
|
||||||
lines += len(g.Lines(u, v))
|
lines += len(g.Lines(uid, v.ID()))
|
||||||
}
|
}
|
||||||
if lines < d {
|
if lines < d {
|
||||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||||
@@ -312,9 +315,10 @@ func TestBipartitePowerLawDirected(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
var lines int
|
var lines int
|
||||||
for _, v := range g.From(u) {
|
for _, v := range g.From(uid) {
|
||||||
lines += len(g.Lines(u, v))
|
lines += len(g.Lines(uid, v.ID()))
|
||||||
}
|
}
|
||||||
if lines < d {
|
if lines < d {
|
||||||
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
t.Errorf("unexpected degree below d: n=%d, d=%d: got:%d", n, d, lines)
|
||||||
|
@@ -66,6 +66,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
|||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
u := nodes[rndN(len(nodes))]
|
u := nodes[rndN(len(nodes))]
|
||||||
d := dst.NewNode()
|
d := dst.NewNode()
|
||||||
|
did := d.ID()
|
||||||
|
|
||||||
// Add the duplicate node.
|
// Add the duplicate node.
|
||||||
dst.AddNode(d)
|
dst.AddNode(d)
|
||||||
@@ -74,13 +75,14 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
|||||||
// into the rest of the graph.
|
// into the rest of the graph.
|
||||||
for {
|
for {
|
||||||
// Add edges to parent's neighbours.
|
// Add edges to parent's neighbours.
|
||||||
to := dst.From(u)
|
to := dst.From(u.ID())
|
||||||
sort.Sort(ordered.ByID(to))
|
sort.Sort(ordered.ByID(to))
|
||||||
for _, v := range to {
|
for _, v := range to {
|
||||||
if rnd() < delta || dst.HasEdgeBetween(v, d) {
|
vid := v.ID()
|
||||||
|
if rnd() < delta || dst.HasEdgeBetween(vid, did) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if v.ID() < d.ID() {
|
if vid < did {
|
||||||
dst.SetEdge(dst.NewEdge(v, d))
|
dst.SetEdge(dst.NewEdge(v, d))
|
||||||
} else {
|
} else {
|
||||||
dst.SetEdge(dst.NewEdge(d, v))
|
dst.SetEdge(dst.NewEdge(d, v))
|
||||||
@@ -90,11 +92,13 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
|||||||
// Add edges to old nodes.
|
// Add edges to old nodes.
|
||||||
scaledAlpha := alpha / float64(len(nodes))
|
scaledAlpha := alpha / float64(len(nodes))
|
||||||
for _, v := range nodes {
|
for _, v := range nodes {
|
||||||
switch v.ID() {
|
uid := u.ID()
|
||||||
case u.ID():
|
vid := v.ID()
|
||||||
|
switch vid {
|
||||||
|
case uid:
|
||||||
if !math.IsNaN(sigma) {
|
if !math.IsNaN(sigma) {
|
||||||
if i == 0 || rnd() < sigma {
|
if i == 0 || rnd() < sigma {
|
||||||
if v.ID() < d.ID() {
|
if vid < did {
|
||||||
dst.SetEdge(dst.NewEdge(v, d))
|
dst.SetEdge(dst.NewEdge(v, d))
|
||||||
} else {
|
} else {
|
||||||
dst.SetEdge(dst.NewEdge(d, v))
|
dst.SetEdge(dst.NewEdge(d, v))
|
||||||
@@ -104,8 +108,8 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
|||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
default:
|
default:
|
||||||
if rnd() < scaledAlpha && !dst.HasEdgeBetween(v, d) {
|
if rnd() < scaledAlpha && !dst.HasEdgeBetween(vid, did) {
|
||||||
if v.ID() < d.ID() {
|
if vid < did {
|
||||||
dst.SetEdge(dst.NewEdge(v, d))
|
dst.SetEdge(dst.NewEdge(v, d))
|
||||||
} else {
|
} else {
|
||||||
dst.SetEdge(dst.NewEdge(d, v))
|
dst.SetEdge(dst.NewEdge(d, v))
|
||||||
@@ -114,7 +118,7 @@ func Duplication(dst UndirectedMutator, n int, delta, alpha, sigma float64, src
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(dst.From(d)) != 0 {
|
if len(dst.From(did)) != 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ func (g *duplication) SetEdge(e graph.Edge) {
|
|||||||
return
|
return
|
||||||
case e.From().ID() > e.To().ID():
|
case e.From().ID() > e.To().ID():
|
||||||
g.addBackwards = true
|
g.addBackwards = true
|
||||||
case g.UndirectedMutator.HasEdgeBetween(e.From(), e.To()):
|
case g.UndirectedMutator.HasEdgeBetween(e.From().ID(), e.To().ID()):
|
||||||
g.addMultipleEdge = true
|
g.addMultipleEdge = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,8 +8,8 @@ import "gonum.org/v1/gonum/graph"
|
|||||||
|
|
||||||
// GraphBuilder is a graph that can have nodes and edges added.
|
// GraphBuilder is a graph that can have nodes and edges added.
|
||||||
type GraphBuilder interface {
|
type GraphBuilder interface {
|
||||||
Has(graph.Node) bool
|
Has(id int64) bool
|
||||||
HasEdgeBetween(x, y graph.Node) bool
|
HasEdgeBetween(xid, yid int64) bool
|
||||||
graph.Builder
|
graph.Builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -47,7 +47,7 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
|
|||||||
// Initial condition.
|
// Initial condition.
|
||||||
wt := make([]float64, n)
|
wt := make([]float64, n)
|
||||||
for u := 0; u < m; u++ {
|
for u := 0; u < m; u++ {
|
||||||
if !dst.Has(simple.Node(u)) {
|
if !dst.Has(int64(0)) {
|
||||||
dst.AddNode(simple.Node(u))
|
dst.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
// We need to give equal probability for
|
// We need to give equal probability for
|
||||||
@@ -68,9 +68,9 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
|
|||||||
for i := 0; i < m; i++ {
|
for i := 0; i < m; i++ {
|
||||||
// Triad formation.
|
// Triad formation.
|
||||||
if i != 0 && rnd() < p {
|
if i != 0 && rnd() < p {
|
||||||
for _, w := range permute(dst.From(simple.Node(u)), rndN) {
|
for _, w := range permute(dst.From(int64(u)), rndN) {
|
||||||
wid := w.ID()
|
wid := w.ID()
|
||||||
if wid == int64(v) || dst.HasEdgeBetween(w, simple.Node(v)) {
|
if wid == int64(v) || dst.HasEdgeBetween(wid, int64(v)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dst.SetEdge(simple.Edge{F: w, T: simple.Node(v)})
|
dst.SetEdge(simple.Edge{F: w, T: simple.Node(v)})
|
||||||
@@ -87,7 +87,7 @@ func TunableClusteringScaleFree(dst graph.UndirectedBuilder, n, m int, p float64
|
|||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("gen: depleted distribution")
|
return errors.New("gen: depleted distribution")
|
||||||
}
|
}
|
||||||
if u == v || dst.HasEdgeBetween(simple.Node(u), simple.Node(v)) {
|
if u == v || dst.HasEdgeBetween(int64(u), int64(v)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dst.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
dst.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||||
@@ -128,7 +128,7 @@ func PreferentialAttachment(dst graph.UndirectedBuilder, n, m int, src *rand.Ran
|
|||||||
// Initial condition.
|
// Initial condition.
|
||||||
wt := make([]float64, n)
|
wt := make([]float64, n)
|
||||||
for u := 0; u < m; u++ {
|
for u := 0; u < m; u++ {
|
||||||
if !dst.Has(simple.Node(u)) {
|
if !dst.Has(int64(u)) {
|
||||||
dst.AddNode(simple.Node(u))
|
dst.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
// We need to give equal probability for
|
// We need to give equal probability for
|
||||||
|
@@ -40,7 +40,7 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
|
|||||||
n *= d
|
n *= d
|
||||||
}
|
}
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
if !dst.Has(simple.Node(i)) {
|
if !dst.Has(int64(i)) {
|
||||||
dst.AddNode(simple.Node(i))
|
dst.AddNode(simple.Node(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,14 +67,14 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
|
|||||||
if uid > vid {
|
if uid > vid {
|
||||||
e.F, e.T = e.T, e.F
|
e.F, e.T = e.T, e.F
|
||||||
}
|
}
|
||||||
if !hasEdge(e.From(), e.To()) {
|
if !hasEdge(e.From().ID(), e.To().ID()) {
|
||||||
dst.SetEdge(e)
|
dst.SetEdge(e)
|
||||||
}
|
}
|
||||||
if !isDirected {
|
if !isDirected {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
e.F, e.T = e.T, e.F
|
e.F, e.T = e.T, e.F
|
||||||
if !hasEdge(e.From(), e.To()) {
|
if !hasEdge(e.From().ID(), e.To().ID()) {
|
||||||
dst.SetEdge(e)
|
dst.SetEdge(e)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -110,7 +110,7 @@ func NavigableSmallWorld(dst GraphBuilder, dims []int, p, q int, r float64, src
|
|||||||
if !isDirected && uid > vid {
|
if !isDirected && uid > vid {
|
||||||
e.F, e.T = e.T, e.F
|
e.F, e.T = e.T, e.F
|
||||||
}
|
}
|
||||||
if !hasEdge(e.From(), e.To()) {
|
if !hasEdge(e.From().ID(), e.To().ID()) {
|
||||||
dst.SetEdge(e)
|
dst.SetEdge(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -103,13 +103,13 @@ func (g *DirectedGraph) SetLine(l graph.Line) {
|
|||||||
lid = l.ID()
|
lid = l.ID()
|
||||||
)
|
)
|
||||||
|
|
||||||
if !g.Has(from) {
|
if !g.Has(fid) {
|
||||||
g.AddNode(from)
|
g.AddNode(from)
|
||||||
}
|
}
|
||||||
if g.from[fid][tid] == nil {
|
if g.from[fid][tid] == nil {
|
||||||
g.from[fid][tid] = make(map[int64]graph.Line)
|
g.from[fid][tid] = make(map[int64]graph.Line)
|
||||||
}
|
}
|
||||||
if !g.Has(to) {
|
if !g.Has(tid) {
|
||||||
g.AddNode(to)
|
g.AddNode(to)
|
||||||
}
|
}
|
||||||
if g.to[tid][fid] == nil {
|
if g.to[tid][fid] == nil {
|
||||||
@@ -149,8 +149,8 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *DirectedGraph) Has(n graph.Node) bool {
|
func (g *DirectedGraph) Has(id int64) bool {
|
||||||
_, ok := g.nodes[n.ID()]
|
_, ok := g.nodes[id]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,30 +187,30 @@ func (g *DirectedGraph) Edges() []graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *DirectedGraph) From(n graph.Node) []graph.Node {
|
func (g *DirectedGraph) From(id int64) []graph.Node {
|
||||||
if _, ok := g.from[n.ID()]; !ok {
|
if _, ok := g.from[id]; !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
from := make([]graph.Node, len(g.from[n.ID()]))
|
from := make([]graph.Node, len(g.from[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for id := range g.from[n.ID()] {
|
for vid := range g.from[id] {
|
||||||
from[i] = g.nodes[id]
|
from[i] = g.nodes[vid]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return from
|
return from
|
||||||
}
|
}
|
||||||
|
|
||||||
// To returns all nodes in g that can reach directly to n.
|
// To returns all nodes in g that can reach directly to n.
|
||||||
func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
func (g *DirectedGraph) To(id int64) []graph.Node {
|
||||||
if _, ok := g.from[n.ID()]; !ok {
|
if _, ok := g.from[id]; !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
to := make([]graph.Node, len(g.to[n.ID()]))
|
to := make([]graph.Node, len(g.to[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for id := range g.to[n.ID()] {
|
for uid := range g.to[id] {
|
||||||
to[i] = g.nodes[id]
|
to[i] = g.nodes[uid]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return to
|
return to
|
||||||
@@ -218,9 +218,7 @@ func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
|||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||||
// considering direction.
|
// considering direction.
|
||||||
func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if _, ok := g.from[xid][yid]; ok {
|
if _, ok := g.from[xid][yid]; ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -231,8 +229,8 @@ func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// The returned graph.Edge is a multi.Edge if an edge exists.
|
// The returned graph.Edge is a multi.Edge if an edge exists.
|
||||||
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||||
lines := g.Lines(u, v)
|
lines := g.Lines(uid, vid)
|
||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -241,8 +239,8 @@ func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
|||||||
|
|
||||||
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
|
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *DirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
func (g *DirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||||
edge := g.from[u.ID()][v.ID()]
|
edge := g.from[uid][vid]
|
||||||
if len(edge) == 0 {
|
if len(edge) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -254,21 +252,21 @@ func (g *DirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||||
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||||
_, ok := g.from[u.ID()][v.ID()]
|
_, ok := g.from[uid][vid]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the in+out degree of n in g.
|
// Degree returns the in+out degree of n in g.
|
||||||
func (g *DirectedGraph) Degree(n graph.Node) int {
|
func (g *DirectedGraph) Degree(id int64) int {
|
||||||
if _, ok := g.nodes[n.ID()]; !ok {
|
if _, ok := g.nodes[id]; !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
var deg int
|
var deg int
|
||||||
for _, e := range g.from[n.ID()] {
|
for _, e := range g.from[id] {
|
||||||
deg += len(e)
|
deg += len(e)
|
||||||
}
|
}
|
||||||
for _, e := range g.to[n.ID()] {
|
for _, e := range g.to[id] {
|
||||||
deg += len(e)
|
deg += len(e)
|
||||||
}
|
}
|
||||||
return deg
|
return deg
|
||||||
|
@@ -21,7 +21,7 @@ var (
|
|||||||
func TestEdgeOvercounting(t *testing.T) {
|
func TestEdgeOvercounting(t *testing.T) {
|
||||||
g := generateDummyGraph()
|
g := generateDummyGraph()
|
||||||
|
|
||||||
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
|
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -95,13 +95,13 @@ func (g *UndirectedGraph) SetLine(l graph.Line) {
|
|||||||
lid = l.ID()
|
lid = l.ID()
|
||||||
)
|
)
|
||||||
|
|
||||||
if !g.Has(from) {
|
if !g.Has(fid) {
|
||||||
g.AddNode(from)
|
g.AddNode(from)
|
||||||
}
|
}
|
||||||
if g.lines[fid][tid] == nil {
|
if g.lines[fid][tid] == nil {
|
||||||
g.lines[fid][tid] = make(map[int64]graph.Line)
|
g.lines[fid][tid] = make(map[int64]graph.Line)
|
||||||
}
|
}
|
||||||
if !g.Has(to) {
|
if !g.Has(tid) {
|
||||||
g.AddNode(to)
|
g.AddNode(to)
|
||||||
}
|
}
|
||||||
if g.lines[tid][fid] == nil {
|
if g.lines[tid][fid] == nil {
|
||||||
@@ -138,8 +138,8 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *UndirectedGraph) Has(n graph.Node) bool {
|
func (g *UndirectedGraph) Has(id int64) bool {
|
||||||
_, ok := g.nodes[n.ID()]
|
_, ok := g.nodes[id]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,14 +185,14 @@ func (g *UndirectedGraph) Edges() []graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
|
func (g *UndirectedGraph) From(id int64) []graph.Node {
|
||||||
if !g.Has(n) {
|
if !g.Has(id) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes := make([]graph.Node, len(g.lines[n.ID()]))
|
nodes := make([]graph.Node, len(g.lines[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for from := range g.lines[n.ID()] {
|
for from := range g.lines[id] {
|
||||||
nodes[i] = g.nodes[from]
|
nodes[i] = g.nodes[from]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@@ -200,21 +200,21 @@ func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g *UndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||||
_, ok := g.lines[x.ID()][y.ID()]
|
_, ok := g.lines[xid][yid]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y.
|
// EdgeBetween returns the edge between nodes x and y.
|
||||||
func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||||
return g.Edge(x, y)
|
return g.Edge(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// The returned graph.Edge is a multi.Edge if an edge exists.
|
// The returned graph.Edge is a multi.Edge if an edge exists.
|
||||||
func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||||
lines := g.LinesBetween(u, v)
|
lines := g.LinesBetween(uid, vid)
|
||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -223,26 +223,26 @@ func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
|||||||
|
|
||||||
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
|
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *UndirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
func (g *UndirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||||
return g.LinesBetween(u, v)
|
return g.LinesBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinesBetween returns the lines between nodes x and y.
|
// LinesBetween returns the lines between nodes x and y.
|
||||||
func (g *UndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
|
func (g *UndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
|
||||||
var lines []graph.Line
|
var lines []graph.Line
|
||||||
for _, l := range g.lines[x.ID()][y.ID()] {
|
for _, l := range g.lines[xid][yid] {
|
||||||
lines = append(lines, l)
|
lines = append(lines, l)
|
||||||
}
|
}
|
||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the degree of n in g.
|
// Degree returns the degree of n in g.
|
||||||
func (g *UndirectedGraph) Degree(n graph.Node) int {
|
func (g *UndirectedGraph) Degree(id int64) int {
|
||||||
if _, ok := g.nodes[n.ID()]; !ok {
|
if _, ok := g.nodes[id]; !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
var deg int
|
var deg int
|
||||||
for _, e := range g.lines[n.ID()] {
|
for _, e := range g.lines[id] {
|
||||||
deg += len(e)
|
deg += len(e)
|
||||||
}
|
}
|
||||||
return deg
|
return deg
|
||||||
|
@@ -30,7 +30,7 @@ func TestMaxID(t *testing.T) {
|
|||||||
delete(nodes, Node(2))
|
delete(nodes, Node(2))
|
||||||
n := g.NewNode()
|
n := g.NewNode()
|
||||||
g.AddNode(n)
|
g.AddNode(n)
|
||||||
if !g.Has(n) {
|
if !g.Has(n.ID()) {
|
||||||
t.Error("added node does not exist in graph")
|
t.Error("added node does not exist in graph")
|
||||||
}
|
}
|
||||||
if _, exists := nodes[n]; exists {
|
if _, exists := nodes[n]; exists {
|
||||||
|
@@ -107,13 +107,13 @@ func (g *WeightedDirectedGraph) SetWeightedLine(l graph.WeightedLine) {
|
|||||||
lid = l.ID()
|
lid = l.ID()
|
||||||
)
|
)
|
||||||
|
|
||||||
if !g.Has(from) {
|
if !g.Has(fid) {
|
||||||
g.AddNode(from)
|
g.AddNode(from)
|
||||||
}
|
}
|
||||||
if g.from[fid][tid] == nil {
|
if g.from[fid][tid] == nil {
|
||||||
g.from[fid][tid] = make(map[int64]graph.WeightedLine)
|
g.from[fid][tid] = make(map[int64]graph.WeightedLine)
|
||||||
}
|
}
|
||||||
if !g.Has(to) {
|
if !g.Has(tid) {
|
||||||
g.AddNode(to)
|
g.AddNode(to)
|
||||||
}
|
}
|
||||||
if g.to[tid][fid] == nil {
|
if g.to[tid][fid] == nil {
|
||||||
@@ -153,8 +153,8 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *WeightedDirectedGraph) Has(n graph.Node) bool {
|
func (g *WeightedDirectedGraph) Has(id int64) bool {
|
||||||
_, ok := g.nodes[n.ID()]
|
_, ok := g.nodes[id]
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
@@ -213,30 +213,30 @@ func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *WeightedDirectedGraph) From(n graph.Node) []graph.Node {
|
func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
|
||||||
if _, ok := g.from[n.ID()]; !ok {
|
if _, ok := g.from[id]; !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
from := make([]graph.Node, len(g.from[n.ID()]))
|
from := make([]graph.Node, len(g.from[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for id := range g.from[n.ID()] {
|
for vid := range g.from[id] {
|
||||||
from[i] = g.nodes[id]
|
from[i] = g.nodes[vid]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return from
|
return from
|
||||||
}
|
}
|
||||||
|
|
||||||
// To returns all nodes in g that can reach directly to n.
|
// To returns all nodes in g that can reach directly to n.
|
||||||
func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
|
func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
|
||||||
if _, ok := g.from[n.ID()]; !ok {
|
if _, ok := g.from[id]; !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
to := make([]graph.Node, len(g.to[n.ID()]))
|
to := make([]graph.Node, len(g.to[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for id := range g.to[n.ID()] {
|
for uid := range g.to[id] {
|
||||||
to[i] = g.nodes[id]
|
to[i] = g.nodes[uid]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return to
|
return to
|
||||||
@@ -244,9 +244,7 @@ func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
|
|||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||||
// considering direction.
|
// considering direction.
|
||||||
func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if _, ok := g.from[xid][yid]; ok {
|
if _, ok := g.from[xid][yid]; ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -255,8 +253,8 @@ func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||||
func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||||
if _, ok := g.from[u.ID()][v.ID()]; !ok {
|
if _, ok := g.from[uid][vid]; !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -265,15 +263,15 @@ func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
|||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// The returned graph.Edge is a multi.WeightedEdge if an edge exists.
|
// The returned graph.Edge is a multi.WeightedEdge if an edge exists.
|
||||||
func (g *WeightedDirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdge(u, v)
|
return g.WeightedEdge(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
|
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
|
||||||
func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
lines := g.WeightedLines(u, v)
|
lines := g.WeightedLines(uid, vid)
|
||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -282,8 +280,8 @@ func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge
|
|||||||
|
|
||||||
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
|
// Lines returns the lines from u to v if such any such lines exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *WeightedDirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
func (g *WeightedDirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||||
edge := g.from[u.ID()][v.ID()]
|
edge := g.from[uid][vid]
|
||||||
if len(edge) == 0 {
|
if len(edge) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -296,8 +294,8 @@ func (g *WeightedDirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
|||||||
|
|
||||||
// WeightedLines returns the weighted lines from u to v if such any such lines exists
|
// WeightedLines returns the weighted lines from u to v if such any such lines exists
|
||||||
// and nil otherwise. The node v must be directly reachable from u as defined by the From method.
|
// and nil otherwise. The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *WeightedDirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedLine {
|
func (g *WeightedDirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
|
||||||
edge := g.from[u.ID()][v.ID()]
|
edge := g.from[uid][vid]
|
||||||
if len(edge) == 0 {
|
if len(edge) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -310,21 +308,21 @@ func (g *WeightedDirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedL
|
|||||||
|
|
||||||
// Weight returns the weight for the lines between x and y summarised by the receiver's
|
// Weight returns the weight for the lines between x and y summarised by the receiver's
|
||||||
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
|
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
|
||||||
func (g *WeightedDirectedGraph) Weight(u, v graph.Node) (w float64, ok bool) {
|
func (g *WeightedDirectedGraph) Weight(uid, vid int64) (w float64, ok bool) {
|
||||||
lines := g.WeightedLines(u, v)
|
lines := g.WeightedLines(uid, vid)
|
||||||
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
|
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the in+out degree of n in g.
|
// Degree returns the in+out degree of n in g.
|
||||||
func (g *WeightedDirectedGraph) Degree(n graph.Node) int {
|
func (g *WeightedDirectedGraph) Degree(id int64) int {
|
||||||
if _, ok := g.nodes[n.ID()]; !ok {
|
if _, ok := g.nodes[id]; !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
var deg int
|
var deg int
|
||||||
for _, e := range g.from[n.ID()] {
|
for _, e := range g.from[id] {
|
||||||
deg += len(e)
|
deg += len(e)
|
||||||
}
|
}
|
||||||
for _, e := range g.to[n.ID()] {
|
for _, e := range g.to[id] {
|
||||||
deg += len(e)
|
deg += len(e)
|
||||||
}
|
}
|
||||||
return deg
|
return deg
|
||||||
|
@@ -22,7 +22,7 @@ var (
|
|||||||
func TestWeightedEdgeOvercounting(t *testing.T) {
|
func TestWeightedEdgeOvercounting(t *testing.T) {
|
||||||
g := generateDummyWeightedGraph()
|
g := generateDummyWeightedGraph()
|
||||||
|
|
||||||
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
|
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -99,13 +99,13 @@ func (g *WeightedUndirectedGraph) SetWeighted(l graph.WeightedLine) {
|
|||||||
lid = l.ID()
|
lid = l.ID()
|
||||||
)
|
)
|
||||||
|
|
||||||
if !g.Has(from) {
|
if !g.Has(fid) {
|
||||||
g.AddNode(from)
|
g.AddNode(from)
|
||||||
}
|
}
|
||||||
if g.lines[fid][tid] == nil {
|
if g.lines[fid][tid] == nil {
|
||||||
g.lines[fid][tid] = make(map[int64]graph.WeightedLine)
|
g.lines[fid][tid] = make(map[int64]graph.WeightedLine)
|
||||||
}
|
}
|
||||||
if !g.Has(to) {
|
if !g.Has(tid) {
|
||||||
g.AddNode(to)
|
g.AddNode(to)
|
||||||
}
|
}
|
||||||
if g.lines[tid][fid] == nil {
|
if g.lines[tid][fid] == nil {
|
||||||
@@ -142,8 +142,8 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *WeightedUndirectedGraph) Has(n graph.Node) bool {
|
func (g *WeightedUndirectedGraph) Has(id int64) bool {
|
||||||
_, ok := g.nodes[n.ID()]
|
_, ok := g.nodes[id]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,14 +189,14 @@ func (g *WeightedUndirectedGraph) Edges() []graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
|
func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
|
||||||
if !g.Has(n) {
|
if !g.Has(id) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes := make([]graph.Node, len(g.lines[n.ID()]))
|
nodes := make([]graph.Node, len(g.lines[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for from := range g.lines[n.ID()] {
|
for from := range g.lines[id] {
|
||||||
nodes[i] = g.nodes[from]
|
nodes[i] = g.nodes[from]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@@ -204,20 +204,20 @@ func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g *WeightedUndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||||
_, ok := g.lines[x.ID()][y.ID()]
|
_, ok := g.lines[xid][yid]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
|
// Lines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *WeightedUndirectedGraph) Lines(u, v graph.Node) []graph.Line {
|
func (g *WeightedUndirectedGraph) Lines(uid, vid int64) []graph.Line {
|
||||||
return g.LinesBetween(u, v)
|
return g.LinesBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinesBetween returns the lines between nodes x and y.
|
// LinesBetween returns the lines between nodes x and y.
|
||||||
func (g *WeightedUndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
|
func (g *WeightedUndirectedGraph) LinesBetween(xid, yid int64) []graph.Line {
|
||||||
edge := g.lines[x.ID()][y.ID()]
|
edge := g.lines[xid][yid]
|
||||||
if len(edge) == 0 {
|
if len(edge) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -237,20 +237,20 @@ func (g *WeightedUndirectedGraph) LinesBetween(x, y graph.Node) []graph.Line {
|
|||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// The returned graph.Edge is a multi.WeightedEdge if an edge exists.
|
// The returned graph.Edge is a multi.WeightedEdge if an edge exists.
|
||||||
func (g *WeightedUndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdge(u, v)
|
return g.WeightedEdge(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y.
|
// EdgeBetween returns the edge between nodes x and y.
|
||||||
func (g *WeightedUndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||||
return g.WeightedEdge(x, y)
|
return g.WeightedEdge(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
|
// The returned graph.WeightedEdge is a multi.WeightedEdge if an edge exists.
|
||||||
func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
lines := g.WeightedLines(u, v)
|
lines := g.WeightedLines(uid, vid)
|
||||||
if len(lines) == 0 {
|
if len(lines) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -258,19 +258,19 @@ func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEd
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||||
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
|
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
|
||||||
return g.WeightedEdge(x, y)
|
return g.WeightedEdge(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedLines returns the lines from u to v if such an edge exists and nil otherwise.
|
// WeightedLines returns the lines from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *WeightedUndirectedGraph) WeightedLines(u, v graph.Node) []graph.WeightedLine {
|
func (g *WeightedUndirectedGraph) WeightedLines(uid, vid int64) []graph.WeightedLine {
|
||||||
return g.WeightedLinesBetween(u, v)
|
return g.WeightedLinesBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedLinesBetween returns the lines between nodes x and y.
|
// WeightedLinesBetween returns the lines between nodes x and y.
|
||||||
func (g *WeightedUndirectedGraph) WeightedLinesBetween(x, y graph.Node) []graph.WeightedLine {
|
func (g *WeightedUndirectedGraph) WeightedLinesBetween(xid, yid int64) []graph.WeightedLine {
|
||||||
edge := g.lines[x.ID()][y.ID()]
|
edge := g.lines[xid][yid]
|
||||||
if len(edge) == 0 {
|
if len(edge) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -289,18 +289,18 @@ func (g *WeightedUndirectedGraph) WeightedLinesBetween(x, y graph.Node) []graph.
|
|||||||
|
|
||||||
// Weight returns the weight for the lines between x and y summarised by the receiver's
|
// Weight returns the weight for the lines between x and y summarised by the receiver's
|
||||||
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
|
// EdgeWeightFunc. Weight returns true if an edge exists between x and y, false otherwise.
|
||||||
func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
lines := g.WeightedLines(x, y)
|
lines := g.WeightedLines(xid, yid)
|
||||||
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
|
return WeightedEdge{Lines: lines, WeightFunc: g.EdgeWeightFunc}.Weight(), len(lines) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the degree of n in g.
|
// Degree returns the degree of n in g.
|
||||||
func (g *WeightedUndirectedGraph) Degree(n graph.Node) int {
|
func (g *WeightedUndirectedGraph) Degree(id int64) int {
|
||||||
if _, ok := g.nodes[n.ID()]; !ok {
|
if _, ok := g.nodes[id]; !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
var deg int
|
var deg int
|
||||||
for _, e := range g.lines[n.ID()] {
|
for _, e := range g.lines[id] {
|
||||||
deg += len(e)
|
deg += len(e)
|
||||||
}
|
}
|
||||||
return deg
|
return deg
|
||||||
|
@@ -23,7 +23,7 @@ func TestWeightedMaxID(t *testing.T) {
|
|||||||
delete(nodes, Node(2))
|
delete(nodes, Node(2))
|
||||||
n := g.NewNode()
|
n := g.NewNode()
|
||||||
g.AddNode(n)
|
g.AddNode(n)
|
||||||
if !g.Has(n) {
|
if !g.Has(n.ID()) {
|
||||||
t.Error("added node does not exist in graph")
|
t.Error("added node does not exist in graph")
|
||||||
}
|
}
|
||||||
if _, exists := nodes[n]; exists {
|
if _, exists := nodes[n]; exists {
|
||||||
|
@@ -19,43 +19,46 @@ type WeightedLine interface {
|
|||||||
|
|
||||||
// Multigraph is a generalized multigraph.
|
// Multigraph is a generalized multigraph.
|
||||||
type Multigraph interface {
|
type Multigraph interface {
|
||||||
// Has returns whether the node exists within the multigraph.
|
// Has returns whether the node with the given ID exists
|
||||||
Has(Node) bool
|
// within the multigraph.
|
||||||
|
Has(id int64) bool
|
||||||
|
|
||||||
// Nodes returns all the nodes in the multigraph.
|
// Nodes returns all the nodes in the multigraph.
|
||||||
Nodes() []Node
|
Nodes() []Node
|
||||||
|
|
||||||
// From returns all nodes that can be reached directly
|
// From returns all nodes that can be reached directly
|
||||||
// from the given node.
|
// from the node with the given ID.
|
||||||
From(Node) []Node
|
From(id int64) []Node
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between
|
// HasEdgeBetween returns whether an edge exists between
|
||||||
// nodes x and y without considering direction.
|
// nodes with IDs xid and yid without considering direction.
|
||||||
HasEdgeBetween(x, y Node) bool
|
HasEdgeBetween(xid, yid int64) bool
|
||||||
|
|
||||||
// Lines returns the lines from u to v if any such lines
|
// Lines returns the lines from u to v, with IDs uid and
|
||||||
// exist and nil otherwise. The node v must be directly
|
// vid, if any such lines exist and nil otherwise. The
|
||||||
// reachable from u as defined by the From method.
|
// node v must be directly reachable from u as defined by
|
||||||
Lines(u, v Node) []Line
|
// the From method.
|
||||||
|
Lines(uid, vid int64) []Line
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedMultigraph is a weighted multigraph.
|
// WeightedMultigraph is a weighted multigraph.
|
||||||
type WeightedMultigraph interface {
|
type WeightedMultigraph interface {
|
||||||
Multigraph
|
Multigraph
|
||||||
|
|
||||||
// WeightedLines returns the weighted lines from u to v if
|
// WeightedLines returns the weighted lines from u to v
|
||||||
// any such lines exist and nil otherwise. The node v must
|
// with IDs uid and vid if any such lines exist and nil
|
||||||
// be directly reachable from u as defined by the
|
// otherwise. The node v must be directly reachable
|
||||||
// From method.
|
// from u as defined by the From method.
|
||||||
WeightedLines(u, v Node) []WeightedLine
|
WeightedLines(uid, vid int64) []WeightedLine
|
||||||
}
|
}
|
||||||
|
|
||||||
// UndirectedMultigraph is an undirected multigraph.
|
// UndirectedMultigraph is an undirected multigraph.
|
||||||
type UndirectedMultigraph interface {
|
type UndirectedMultigraph interface {
|
||||||
Multigraph
|
Multigraph
|
||||||
|
|
||||||
// LinesBetween returns the lines between nodes x and y.
|
// LinesBetween returns the lines between nodes x and y
|
||||||
LinesBetween(x, y Node) []Line
|
// with IDs xid and yid.
|
||||||
|
LinesBetween(xid, yid int64) []Line
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedUndirectedMultigraph is a weighted undirected multigraph.
|
// WeightedUndirectedMultigraph is a weighted undirected multigraph.
|
||||||
@@ -63,8 +66,8 @@ type WeightedUndirectedMultigraph interface {
|
|||||||
WeightedMultigraph
|
WeightedMultigraph
|
||||||
|
|
||||||
// WeightedLinesBetween returns the lines between nodes
|
// WeightedLinesBetween returns the lines between nodes
|
||||||
// x and y.
|
// x and y with IDs xid and yid.
|
||||||
WeightedLinesBetween(x, y Node) []WeightedLine
|
WeightedLinesBetween(xid, yid int64) []WeightedLine
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirectedMultigraph is a directed multigraph.
|
// DirectedMultigraph is a directed multigraph.
|
||||||
@@ -72,12 +75,13 @@ type DirectedMultigraph interface {
|
|||||||
Multigraph
|
Multigraph
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists
|
// HasEdgeFromTo returns whether an edge exists
|
||||||
// in the multigraph from u to v.
|
// in the multigraph from u to v with IDs uid
|
||||||
HasEdgeFromTo(u, v Node) bool
|
// and vid.
|
||||||
|
HasEdgeFromTo(uid, vid int64) bool
|
||||||
|
|
||||||
// To returns all nodes that can reach directly
|
// To returns all nodes that can reach directly
|
||||||
// to the given node.
|
// to the node with the given ID.
|
||||||
To(Node) []Node
|
To(id int64) []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedDirectedMultigraph is a weighted directed multigraph.
|
// WeightedDirectedMultigraph is a weighted directed multigraph.
|
||||||
@@ -85,12 +89,13 @@ type WeightedDirectedMultigraph interface {
|
|||||||
WeightedMultigraph
|
WeightedMultigraph
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists
|
// HasEdgeFromTo returns whether an edge exists
|
||||||
// in the multigraph from u to v.
|
// in the multigraph from u to v with IDs uid
|
||||||
HasEdgeFromTo(u, v Node) bool
|
// and vid.
|
||||||
|
HasEdgeFromTo(uid, vid int64) bool
|
||||||
|
|
||||||
// To returns all nodes that can reach directly
|
// To returns all nodes that can reach directly
|
||||||
// to the given node.
|
// to the node with the given ID.
|
||||||
To(Node) []Node
|
To(id int64) []Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// LineAdder is an interface for adding lines to a multigraph.
|
// LineAdder is an interface for adding lines to a multigraph.
|
||||||
|
@@ -115,17 +115,19 @@ func brandes(g graph.Graph, accumulate func(s graph.Node, stack linear.NodeStack
|
|||||||
queue.Enqueue(s)
|
queue.Enqueue(s)
|
||||||
for queue.Len() != 0 {
|
for queue.Len() != 0 {
|
||||||
v := queue.Dequeue()
|
v := queue.Dequeue()
|
||||||
|
vid := v.ID()
|
||||||
stack.Push(v)
|
stack.Push(v)
|
||||||
for _, w := range g.From(v) {
|
for _, w := range g.From(vid) {
|
||||||
|
wid := w.ID()
|
||||||
// w found for the first time?
|
// w found for the first time?
|
||||||
if d[w.ID()] < 0 {
|
if d[wid] < 0 {
|
||||||
queue.Enqueue(w)
|
queue.Enqueue(w)
|
||||||
d[w.ID()] = d[v.ID()] + 1
|
d[wid] = d[vid] + 1
|
||||||
}
|
}
|
||||||
// shortest path to w via v?
|
// shortest path to w via v?
|
||||||
if d[w.ID()] == d[v.ID()]+1 {
|
if d[wid] == d[vid]+1 {
|
||||||
sigma[w.ID()] += sigma[v.ID()]
|
sigma[wid] += sigma[vid]
|
||||||
p[w.ID()] = append(p[w.ID()], v)
|
p[wid] = append(p[wid], v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,18 +153,20 @@ func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64
|
|||||||
|
|
||||||
nodes := g.Nodes()
|
nodes := g.Nodes()
|
||||||
for i, s := range nodes {
|
for i, s := range nodes {
|
||||||
|
sid := s.ID()
|
||||||
for j, t := range nodes {
|
for j, t := range nodes {
|
||||||
if i == j {
|
if i == j {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
d := p.Weight(s, t)
|
tid := t.ID()
|
||||||
|
d := p.Weight(sid, tid)
|
||||||
if math.IsInf(d, 0) {
|
if math.IsInf(d, 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a unique path, don't do the
|
// If we have a unique path, don't do the
|
||||||
// extra work needed to get all paths.
|
// extra work needed to get all paths.
|
||||||
path, _, unique := p.Between(s, t)
|
path, _, unique := p.Between(sid, tid)
|
||||||
if unique {
|
if unique {
|
||||||
for _, v := range path[1 : len(path)-1] {
|
for _, v := range path[1 : len(path)-1] {
|
||||||
// For undirected graphs we double count
|
// For undirected graphs we double count
|
||||||
@@ -174,7 +178,7 @@ func BetweennessWeighted(g graph.Weighted, p path.AllShortest) map[int64]float64
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise iterate over all paths.
|
// Otherwise iterate over all paths.
|
||||||
paths, _ := p.AllBetween(s, t)
|
paths, _ := p.AllBetween(sid, tid)
|
||||||
stFrac := 1 / float64(len(paths))
|
stFrac := 1 / float64(len(paths))
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
for _, v := range path[1 : len(path)-1] {
|
for _, v := range path[1 : len(path)-1] {
|
||||||
@@ -203,18 +207,20 @@ func EdgeBetweennessWeighted(g graph.Weighted, p path.AllShortest) map[[2]int64]
|
|||||||
_, isUndirected := g.(graph.Undirected)
|
_, isUndirected := g.(graph.Undirected)
|
||||||
nodes := g.Nodes()
|
nodes := g.Nodes()
|
||||||
for i, s := range nodes {
|
for i, s := range nodes {
|
||||||
|
sid := s.ID()
|
||||||
for j, t := range nodes {
|
for j, t := range nodes {
|
||||||
if i == j {
|
if i == j {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
d := p.Weight(s, t)
|
tid := t.ID()
|
||||||
|
d := p.Weight(sid, tid)
|
||||||
if math.IsInf(d, 0) {
|
if math.IsInf(d, 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a unique path, don't do the
|
// If we have a unique path, don't do the
|
||||||
// extra work needed to get all paths.
|
// extra work needed to get all paths.
|
||||||
path, _, unique := p.Between(s, t)
|
path, _, unique := p.Between(sid, tid)
|
||||||
if unique {
|
if unique {
|
||||||
for k, v := range path[1:] {
|
for k, v := range path[1:] {
|
||||||
// For undirected graphs we double count
|
// For undirected graphs we double count
|
||||||
@@ -231,7 +237,7 @@ func EdgeBetweennessWeighted(g graph.Weighted, p path.AllShortest) map[[2]int64]
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise iterate over all paths.
|
// Otherwise iterate over all paths.
|
||||||
paths, _ := p.AllBetween(s, t)
|
paths, _ := p.AllBetween(sid, tid)
|
||||||
stFrac := 1 / float64(len(paths))
|
stFrac := 1 / float64(len(paths))
|
||||||
for _, path := range paths {
|
for _, path := range paths {
|
||||||
for k, v := range path[1:] {
|
for k, v := range path[1:] {
|
||||||
|
@@ -179,7 +179,7 @@ func TestBetweenness(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -208,7 +208,7 @@ func TestEdgeBetweenness(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -240,7 +240,7 @@ func TestBetweennessWeighted(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -276,7 +276,7 @@ func TestEdgeBetweennessWeighted(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -122,9 +122,9 @@ func NewLaplacian(g graph.Undirected) Laplacian {
|
|||||||
|
|
||||||
l := mat.NewSymDense(len(nodes), nil)
|
l := mat.NewSymDense(len(nodes), nil)
|
||||||
for j, u := range nodes {
|
for j, u := range nodes {
|
||||||
to := g.From(u)
|
|
||||||
l.SetSym(j, j, float64(len(to)))
|
|
||||||
uid := u.ID()
|
uid := u.ID()
|
||||||
|
to := g.From(uid)
|
||||||
|
l.SetSym(j, j, float64(len(to)))
|
||||||
for _, v := range to {
|
for _, v := range to {
|
||||||
vid := v.ID()
|
vid := v.ID()
|
||||||
if uid == vid {
|
if uid == vid {
|
||||||
@@ -155,12 +155,12 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
|
|||||||
|
|
||||||
l := mat.NewSymDense(len(nodes), nil)
|
l := mat.NewSymDense(len(nodes), nil)
|
||||||
for j, u := range nodes {
|
for j, u := range nodes {
|
||||||
to := g.From(u)
|
uid := u.ID()
|
||||||
|
to := g.From(uid)
|
||||||
if len(to) == 0 {
|
if len(to) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
l.SetSym(j, j, 1)
|
l.SetSym(j, j, 1)
|
||||||
uid := u.ID()
|
|
||||||
squdeg := math.Sqrt(float64(len(to)))
|
squdeg := math.Sqrt(float64(len(to)))
|
||||||
for _, v := range to {
|
for _, v := range to {
|
||||||
vid := v.ID()
|
vid := v.ID()
|
||||||
@@ -168,7 +168,7 @@ func NewSymNormLaplacian(g graph.Undirected) Laplacian {
|
|||||||
panic("network: self edge in graph")
|
panic("network: self edge in graph")
|
||||||
}
|
}
|
||||||
if uid < vid {
|
if uid < vid {
|
||||||
l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(len(g.From(v))))))
|
l.SetSym(indexOf[vid], j, -1/(squdeg*math.Sqrt(float64(len(g.From(vid))))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,7 +193,7 @@ func NewRandomWalkLaplacian(g graph.Graph, damp float64) Laplacian {
|
|||||||
l := mat.NewDense(len(nodes), len(nodes), nil)
|
l := mat.NewDense(len(nodes), len(nodes), nil)
|
||||||
for j, u := range nodes {
|
for j, u := range nodes {
|
||||||
uid := u.ID()
|
uid := u.ID()
|
||||||
to := g.From(u)
|
to := g.From(uid)
|
||||||
if len(to) == 0 {
|
if len(to) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@@ -152,7 +152,7 @@ func TestDiffuse(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -278,7 +278,7 @@ func TestRandomWalkLaplacian(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -466,7 +466,7 @@ func TestDiffuseToEquilibrium(t *testing.T) {
|
|||||||
g := test.builder
|
g := test.builder
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -22,12 +22,14 @@ func Closeness(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
|||||||
nodes := g.Nodes()
|
nodes := g.Nodes()
|
||||||
c := make(map[int64]float64, len(nodes))
|
c := make(map[int64]float64, len(nodes))
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
var sum float64
|
var sum float64
|
||||||
for _, v := range nodes {
|
for _, v := range nodes {
|
||||||
|
vid := v.ID()
|
||||||
// The ordering here is not relevant for
|
// The ordering here is not relevant for
|
||||||
// undirected graphs, but we make sure we
|
// undirected graphs, but we make sure we
|
||||||
// are counting incoming paths.
|
// are counting incoming paths.
|
||||||
d := p.Weight(v, u)
|
d := p.Weight(vid, uid)
|
||||||
if math.IsInf(d, 0) {
|
if math.IsInf(d, 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -49,12 +51,14 @@ func Farness(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
|||||||
nodes := g.Nodes()
|
nodes := g.Nodes()
|
||||||
f := make(map[int64]float64, len(nodes))
|
f := make(map[int64]float64, len(nodes))
|
||||||
for _, u := range nodes {
|
for _, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
var sum float64
|
var sum float64
|
||||||
for _, v := range nodes {
|
for _, v := range nodes {
|
||||||
|
vid := v.ID()
|
||||||
// The ordering here is not relevant for
|
// The ordering here is not relevant for
|
||||||
// undirected graphs, but we make sure we
|
// undirected graphs, but we make sure we
|
||||||
// are counting incoming paths.
|
// are counting incoming paths.
|
||||||
d := p.Weight(v, u)
|
d := p.Weight(vid, uid)
|
||||||
if math.IsInf(d, 0) {
|
if math.IsInf(d, 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -76,12 +80,14 @@ func Harmonic(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
|||||||
nodes := g.Nodes()
|
nodes := g.Nodes()
|
||||||
h := make(map[int64]float64, len(nodes))
|
h := make(map[int64]float64, len(nodes))
|
||||||
for i, u := range nodes {
|
for i, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
var sum float64
|
var sum float64
|
||||||
for j, v := range nodes {
|
for j, v := range nodes {
|
||||||
|
vid := v.ID()
|
||||||
// The ordering here is not relevant for
|
// The ordering here is not relevant for
|
||||||
// undirected graphs, but we make sure we
|
// undirected graphs, but we make sure we
|
||||||
// are counting incoming paths.
|
// are counting incoming paths.
|
||||||
d := p.Weight(v, u)
|
d := p.Weight(vid, uid)
|
||||||
if math.IsInf(d, 0) {
|
if math.IsInf(d, 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -105,12 +111,14 @@ func Residual(g graph.Graph, p path.AllShortest) map[int64]float64 {
|
|||||||
nodes := g.Nodes()
|
nodes := g.Nodes()
|
||||||
r := make(map[int64]float64, len(nodes))
|
r := make(map[int64]float64, len(nodes))
|
||||||
for i, u := range nodes {
|
for i, u := range nodes {
|
||||||
|
uid := u.ID()
|
||||||
var sum float64
|
var sum float64
|
||||||
for j, v := range nodes {
|
for j, v := range nodes {
|
||||||
|
vid := v.ID()
|
||||||
// The ordering here is not relevant for
|
// The ordering here is not relevant for
|
||||||
// undirected graphs, but we make sure we
|
// undirected graphs, but we make sure we
|
||||||
// are counting incoming paths.
|
// are counting incoming paths.
|
||||||
d := p.Weight(v, u)
|
d := p.Weight(vid, uid)
|
||||||
if math.IsInf(d, 0) {
|
if math.IsInf(d, 0) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@@ -146,7 +146,7 @@ func TestDistanceCentralityUndirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
g := simple.NewWeightedUndirectedGraph(0, math.Inf(1))
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -336,7 +336,7 @@ func TestDistanceCentralityDirected(t *testing.T) {
|
|||||||
g := simple.NewWeightedDirectedGraph(0, math.Inf(1))
|
g := simple.NewWeightedDirectedGraph(0, math.Inf(1))
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -32,10 +32,11 @@ func HITS(g graph.Directed, tol float64) map[int64]HubAuthority {
|
|||||||
nodesLinkingTo := make([][]int, len(nodes))
|
nodesLinkingTo := make([][]int, len(nodes))
|
||||||
nodesLinkedFrom := make([][]int, len(nodes))
|
nodesLinkedFrom := make([][]int, len(nodes))
|
||||||
for i, n := range nodes {
|
for i, n := range nodes {
|
||||||
for _, u := range g.To(n) {
|
id := n.ID()
|
||||||
|
for _, u := range g.To(id) {
|
||||||
nodesLinkingTo[i] = append(nodesLinkingTo[i], indexOf[u.ID()])
|
nodesLinkingTo[i] = append(nodesLinkingTo[i], indexOf[u.ID()])
|
||||||
}
|
}
|
||||||
for _, v := range g.From(n) {
|
for _, v := range g.From(id) {
|
||||||
nodesLinkedFrom[i] = append(nodesLinkedFrom[i], indexOf[v.ID()])
|
nodesLinkedFrom[i] = append(nodesLinkedFrom[i], indexOf[v.ID()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -46,7 +46,7 @@ func TestHITS(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -35,7 +35,7 @@ func PageRank(g graph.Directed, damp, tol float64) map[int64]float64 {
|
|||||||
m := mat.NewDense(len(nodes), len(nodes), nil)
|
m := mat.NewDense(len(nodes), len(nodes), nil)
|
||||||
dangling := damp / float64(len(nodes))
|
dangling := damp / float64(len(nodes))
|
||||||
for j, u := range nodes {
|
for j, u := range nodes {
|
||||||
to := g.From(u)
|
to := g.From(u.ID())
|
||||||
f := damp / float64(len(to))
|
f := damp / float64(len(to))
|
||||||
for _, v := range to {
|
for _, v := range to {
|
||||||
m.Set(indexOf[v.ID()], j, f)
|
m.Set(indexOf[v.ID()], j, f)
|
||||||
@@ -109,7 +109,7 @@ func PageRankSparse(g graph.Directed, damp, tol float64) map[int64]float64 {
|
|||||||
var dangling compressedRow
|
var dangling compressedRow
|
||||||
df := damp / float64(len(nodes))
|
df := damp / float64(len(nodes))
|
||||||
for j, u := range nodes {
|
for j, u := range nodes {
|
||||||
to := g.From(u)
|
to := g.From(u.ID())
|
||||||
f := damp / float64(len(to))
|
f := damp / float64(len(to))
|
||||||
for _, v := range to {
|
for _, v := range to {
|
||||||
m.addTo(indexOf[v.ID()], j, f)
|
m.addTo(indexOf[v.ID()], j, f)
|
||||||
|
@@ -84,7 +84,7 @@ func TestPageRank(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -108,7 +108,7 @@ func TestPageRankSparse(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -24,7 +24,7 @@ import (
|
|||||||
// falling back to NullHeuristic otherwise. If the graph does not implement graph.Weighter,
|
// falling back to NullHeuristic otherwise. If the graph does not implement graph.Weighter,
|
||||||
// UniformCost is used. AStar will panic if g has an A*-reachable negative edge weight.
|
// UniformCost is used. AStar will panic if g has an A*-reachable negative edge weight.
|
||||||
func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded int) {
|
func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded int) {
|
||||||
if !g.Has(s) || !g.Has(t) {
|
if !g.Has(s.ID()) || !g.Has(t.ID()) {
|
||||||
return Shortest{from: s}, 0
|
return Shortest{from: s}, 0
|
||||||
}
|
}
|
||||||
var weight Weighting
|
var weight Weighting
|
||||||
@@ -59,14 +59,14 @@ func AStar(s, t graph.Node, g graph.Graph, h Heuristic) (path Shortest, expanded
|
|||||||
}
|
}
|
||||||
|
|
||||||
visited.Add(uid)
|
visited.Add(uid)
|
||||||
for _, v := range g.From(u.node) {
|
for _, v := range g.From(u.node.ID()) {
|
||||||
vid := v.ID()
|
vid := v.ID()
|
||||||
if visited.Has(vid) {
|
if visited.Has(vid) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
j := path.indexOf[vid]
|
j := path.indexOf[vid]
|
||||||
|
|
||||||
w, ok := weight(u.node, v)
|
w, ok := weight(u.node.ID(), vid)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("A*: unexpected invalid weight")
|
panic("A*: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
|
@@ -129,7 +129,7 @@ func TestAStar(t *testing.T) {
|
|||||||
for _, test := range aStarTests {
|
for _, test := range aStarTests {
|
||||||
pt, _ := AStar(simple.Node(test.s), simple.Node(test.t), test.g, test.heuristic)
|
pt, _ := AStar(simple.Node(test.s), simple.Node(test.t), test.g, test.heuristic)
|
||||||
|
|
||||||
p, cost := pt.To(simple.Node(test.t))
|
p, cost := pt.To(test.t)
|
||||||
|
|
||||||
if !topo.IsPathIn(test.g, p) {
|
if !topo.IsPathIn(test.g, p) {
|
||||||
t.Errorf("got path that is not path in input graph for %q", test.name)
|
t.Errorf("got path that is not path in input graph for %q", test.name)
|
||||||
@@ -139,7 +139,7 @@ func TestAStar(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("unexpected negative cycle in %q", test.name)
|
t.Fatalf("unexpected negative cycle in %q", test.name)
|
||||||
}
|
}
|
||||||
if want := bfp.WeightTo(simple.Node(test.t)); cost != want {
|
if want := bfp.WeightTo(test.t); cost != want {
|
||||||
t.Errorf("unexpected cost for %q: got:%v want:%v", test.name, cost, want)
|
t.Errorf("unexpected cost for %q: got:%v want:%v", test.name, cost, want)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,8 +196,8 @@ func TestExhaustiveAStar(t *testing.T) {
|
|||||||
for _, start := range g.Nodes() {
|
for _, start := range g.Nodes() {
|
||||||
for _, goal := range g.Nodes() {
|
for _, goal := range g.Nodes() {
|
||||||
pt, _ := AStar(start, goal, g, heuristic)
|
pt, _ := AStar(start, goal, g, heuristic)
|
||||||
gotPath, gotWeight := pt.To(goal)
|
gotPath, gotWeight := pt.To(goal.ID())
|
||||||
wantPath, wantWeight, _ := ps.Between(start, goal)
|
wantPath, wantWeight, _ := ps.Between(start.ID(), goal.ID())
|
||||||
if gotWeight != wantWeight {
|
if gotWeight != wantWeight {
|
||||||
t.Errorf("unexpected path weight from %v to %v result: got:%f want:%f",
|
t.Errorf("unexpected path weight from %v to %v result: got:%f want:%f",
|
||||||
start, goal, gotWeight, wantWeight)
|
start, goal, gotWeight, wantWeight)
|
||||||
@@ -231,7 +231,7 @@ func isMonotonic(g UndirectedWeightLister, h Heuristic) (ok bool, at graph.Edge,
|
|||||||
for _, edge := range g.WeightedEdges() {
|
for _, edge := range g.WeightedEdges() {
|
||||||
from := edge.From()
|
from := edge.From()
|
||||||
to := edge.To()
|
to := edge.To()
|
||||||
w, ok := g.Weight(from, to)
|
w, ok := g.Weight(from.ID(), to.ID())
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("A*: unexpected invalid weight")
|
panic("A*: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
@@ -275,12 +275,12 @@ func TestAStarNullHeuristic(t *testing.T) {
|
|||||||
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
p, weight := pt.To(test.Query.To())
|
p, weight := pt.To(test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
|
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
@@ -301,7 +301,7 @@ func TestAStarNullHeuristic(t *testing.T) {
|
|||||||
test.Name, p, test.WantPaths)
|
test.Name, p, test.WantPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
np, weight := pt.To(test.NoPathFor.To())
|
np, weight := pt.To(test.NoPathFor.To().ID())
|
||||||
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
||||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||||
test.Name, np, weight)
|
test.Name, np, weight)
|
||||||
|
@@ -12,7 +12,7 @@ import "gonum.org/v1/gonum/graph"
|
|||||||
//
|
//
|
||||||
// The time complexity of BellmanFordFrom is O(|V|.|E|).
|
// The time complexity of BellmanFordFrom is O(|V|.|E|).
|
||||||
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
||||||
if !g.Has(u) {
|
if !g.Has(u.ID()) {
|
||||||
return Shortest{from: u}, true
|
return Shortest{from: u}, true
|
||||||
}
|
}
|
||||||
var weight Weighting
|
var weight Weighting
|
||||||
@@ -32,9 +32,11 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
|||||||
for i := 1; i < len(nodes); i++ {
|
for i := 1; i < len(nodes); i++ {
|
||||||
changed := false
|
changed := false
|
||||||
for j, u := range nodes {
|
for j, u := range nodes {
|
||||||
for _, v := range g.From(u) {
|
uid := u.ID()
|
||||||
k := path.indexOf[v.ID()]
|
for _, v := range g.From(uid) {
|
||||||
w, ok := weight(u, v)
|
vid := v.ID()
|
||||||
|
k := path.indexOf[vid]
|
||||||
|
w, ok := weight(uid, vid)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("bellman-ford: unexpected invalid weight")
|
panic("bellman-ford: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
@@ -51,9 +53,11 @@ func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for j, u := range nodes {
|
for j, u := range nodes {
|
||||||
for _, v := range g.From(u) {
|
uid := u.ID()
|
||||||
k := path.indexOf[v.ID()]
|
for _, v := range g.From(uid) {
|
||||||
w, ok := weight(u, v)
|
vid := v.ID()
|
||||||
|
k := path.indexOf[vid]
|
||||||
|
w, ok := weight(uid, vid)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("bellman-ford: unexpected invalid weight")
|
panic("bellman-ford: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
|
@@ -35,12 +35,12 @@ func TestBellmanFordFrom(t *testing.T) {
|
|||||||
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
p, weight := pt.To(test.Query.To())
|
p, weight := pt.To(test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
|
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
@@ -61,7 +61,7 @@ func TestBellmanFordFrom(t *testing.T) {
|
|||||||
test.Name, p, test.WantPaths)
|
test.Name, p, test.WantPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
np, weight := pt.To(test.NoPathFor.To())
|
np, weight := pt.To(test.NoPathFor.To().ID())
|
||||||
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
||||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||||
test.Name, np, weight)
|
test.Name, np, weight)
|
||||||
|
@@ -201,7 +201,7 @@ func BenchmarkRandomGraphDominators(b *testing.B) {
|
|||||||
if v == nil {
|
if v == nil {
|
||||||
v = unordered[ui][rnd.Intn(len(unordered[ui]))]
|
v = unordered[ui][rnd.Intn(len(unordered[ui]))]
|
||||||
}
|
}
|
||||||
if !g.HasEdgeFromTo(u, v) {
|
if !g.HasEdgeFromTo(u.ID(), v.ID()) {
|
||||||
g.SetEdge(g.NewEdge(u, v))
|
g.SetEdge(g.NewEdge(u, v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -253,16 +253,16 @@ type undirected struct {
|
|||||||
*simple.DirectedGraph
|
*simple.DirectedGraph
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g undirected) From(n graph.Node) []graph.Node {
|
func (g undirected) From(id int64) []graph.Node {
|
||||||
return append(g.DirectedGraph.From(n), g.DirectedGraph.To(n)...)
|
return append(g.DirectedGraph.From(id), g.DirectedGraph.To(id)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g undirected) HasEdgeBetween(x, y graph.Node) bool {
|
func (g undirected) HasEdgeBetween(xid, yid int64) bool {
|
||||||
return g.DirectedGraph.HasEdgeFromTo(x, y)
|
return g.DirectedGraph.HasEdgeFromTo(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g undirected) EdgeBetween(x, y graph.Node) graph.Edge {
|
func (g undirected) EdgeBetween(xid, yid int64) graph.Edge {
|
||||||
return g.DirectedGraph.Edge(x, y)
|
return g.DirectedGraph.Edge(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g undirected) SetEdge(e graph.Edge) {
|
func (g undirected) SetEdge(e graph.Edge) {
|
||||||
|
@@ -140,7 +140,7 @@ func (lt *lengauerTarjan) dfs(g graph.Directed, v graph.Node) {
|
|||||||
ltv.label = ltv
|
ltv.label = ltv
|
||||||
lt.nodes = append(lt.nodes, ltv)
|
lt.nodes = append(lt.nodes, ltv)
|
||||||
|
|
||||||
for _, w := range g.From(v) {
|
for _, w := range g.From(v.ID()) {
|
||||||
wid := w.ID()
|
wid := w.ID()
|
||||||
|
|
||||||
idx, ok := lt.indexOf[wid]
|
idx, ok := lt.indexOf[wid]
|
||||||
|
@@ -162,7 +162,7 @@ func (lt *sLengauerTarjan) dfs(g graph.Directed, v graph.Node) {
|
|||||||
ltv.label = ltv
|
ltv.label = ltv
|
||||||
lt.nodes = append(lt.nodes, ltv)
|
lt.nodes = append(lt.nodes, ltv)
|
||||||
|
|
||||||
for _, w := range g.From(v) {
|
for _, w := range g.From(v.ID()) {
|
||||||
wid := w.ID()
|
wid := w.ID()
|
||||||
|
|
||||||
idx, ok := lt.indexOf[wid]
|
idx, ok := lt.indexOf[wid]
|
||||||
|
@@ -16,7 +16,7 @@ import (
|
|||||||
//
|
//
|
||||||
// The time complexity of DijkstrFrom is O(|E|.log|V|).
|
// The time complexity of DijkstrFrom is O(|E|.log|V|).
|
||||||
func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
|
func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
|
||||||
if !g.Has(u) {
|
if !g.Has(u.ID()) {
|
||||||
return Shortest{from: u}
|
return Shortest{from: u}
|
||||||
}
|
}
|
||||||
var weight Weighting
|
var weight Weighting
|
||||||
@@ -46,9 +46,11 @@ func DijkstraFrom(u graph.Node, g graph.Graph) Shortest {
|
|||||||
if mid.dist > path.dist[k] {
|
if mid.dist > path.dist[k] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, v := range g.From(mid.node) {
|
mnid := mid.node.ID()
|
||||||
j := path.indexOf[v.ID()]
|
for _, v := range g.From(mnid) {
|
||||||
w, ok := weight(mid.node, v)
|
vid := v.ID()
|
||||||
|
j := path.indexOf[vid]
|
||||||
|
w, ok := weight(mnid, vid)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("dijkstra: unexpected invalid weight")
|
panic("dijkstra: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
@@ -106,9 +108,11 @@ func dijkstraAllPaths(g graph.Graph, paths AllShortest) {
|
|||||||
if mid.dist < paths.dist.At(i, k) {
|
if mid.dist < paths.dist.At(i, k) {
|
||||||
paths.dist.Set(i, k, mid.dist)
|
paths.dist.Set(i, k, mid.dist)
|
||||||
}
|
}
|
||||||
for _, v := range g.From(mid.node) {
|
mnid := mid.node.ID()
|
||||||
j := paths.indexOf[v.ID()]
|
for _, v := range g.From(mnid) {
|
||||||
w, ok := weight(mid.node, v)
|
vid := v.ID()
|
||||||
|
j := paths.indexOf[vid]
|
||||||
|
w, ok := weight(mnid, vid)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("dijkstra: unexpected invalid weight")
|
panic("dijkstra: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
|
@@ -47,12 +47,12 @@ func TestDijkstraFrom(t *testing.T) {
|
|||||||
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
t.Fatalf("%q: unexpected from node ID: got:%d want:%d", test.Name, pt.From().ID(), test.Query.From().ID())
|
||||||
}
|
}
|
||||||
|
|
||||||
p, weight := pt.To(test.Query.To())
|
p, weight := pt.To(test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
if weight := pt.WeightTo(test.Query.To()); weight != test.Weight {
|
if weight := pt.WeightTo(test.Query.To().ID()); weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ func TestDijkstraFrom(t *testing.T) {
|
|||||||
test.Name, p, test.WantPaths)
|
test.Name, p, test.WantPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
np, weight := pt.To(test.NoPathFor.To())
|
np, weight := pt.To(test.NoPathFor.To().ID())
|
||||||
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
if pt.From().ID() == test.NoPathFor.From().ID() && (np != nil || !math.IsInf(weight, 1)) {
|
||||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||||
test.Name, np, weight)
|
test.Name, np, weight)
|
||||||
@@ -111,12 +111,12 @@ func TestDijkstraAllPaths(t *testing.T) {
|
|||||||
|
|
||||||
// Check all random paths returned are OK.
|
// Check all random paths returned are OK.
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
|
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
|
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
@@ -142,13 +142,13 @@ func TestDijkstraAllPaths(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
|
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||||
if np != nil || !math.IsInf(weight, 1) || unique {
|
if np != nil || !math.IsInf(weight, 1) || unique {
|
||||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
||||||
test.Name, np, weight, unique)
|
test.Name, np, weight, unique)
|
||||||
}
|
}
|
||||||
|
|
||||||
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
|
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
@@ -169,7 +169,7 @@ func TestDijkstraAllPaths(t *testing.T) {
|
|||||||
test.Name, got, test.WantPaths)
|
test.Name, got, test.WantPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
|
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||||
if nps != nil || !math.IsInf(weight, 1) {
|
if nps != nil || !math.IsInf(weight, 1) {
|
||||||
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||||
test.Name, nps, weight)
|
test.Name, nps, weight)
|
||||||
|
@@ -99,12 +99,14 @@ func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, u := range d.model.Nodes() {
|
for _, u := range d.model.Nodes() {
|
||||||
for _, v := range g.From(u) {
|
uid := u.ID()
|
||||||
w := edgeWeight(d.weight, u, v)
|
for _, v := range g.From(uid) {
|
||||||
|
vid := v.ID()
|
||||||
|
w := edgeWeight(d.weight, uid, vid)
|
||||||
if w < 0 {
|
if w < 0 {
|
||||||
panic("D* Lite: negative edge weight")
|
panic("D* Lite: negative edge weight")
|
||||||
}
|
}
|
||||||
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: d.model.Node(v.ID()), W: w})
|
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: d.model.Node(vid), W: w})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,8 +122,8 @@ func NewDStarLite(s, t graph.Node, g graph.Graph, h path.Heuristic, m WorldModel
|
|||||||
// edgeWeight is a helper function that returns the weight of the edge between
|
// edgeWeight is a helper function that returns the weight of the edge between
|
||||||
// two connected nodes, u and v, using the provided weight function. It panics
|
// two connected nodes, u and v, using the provided weight function. It panics
|
||||||
// if there is no edge between u and v.
|
// if there is no edge between u and v.
|
||||||
func edgeWeight(weight path.Weighting, u, v graph.Node) float64 {
|
func edgeWeight(weight path.Weighting, uid, vid int64) float64 {
|
||||||
w, ok := weight(u, v)
|
w, ok := weight(uid, vid)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("D* Lite: unexpected invalid weight")
|
panic("D* Lite: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
@@ -187,29 +189,33 @@ func (d *DStarLite) findShortestPath() {
|
|||||||
if !u.key.less(d.keyFor(d.s)) && d.s.rhs <= d.s.g {
|
if !u.key.less(d.keyFor(d.s)) && d.s.rhs <= d.s.g {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
uid := u.ID()
|
||||||
switch kNew := d.keyFor(u); {
|
switch kNew := d.keyFor(u); {
|
||||||
case u.key.less(kNew):
|
case u.key.less(kNew):
|
||||||
d.queue.update(u, kNew)
|
d.queue.update(u, kNew)
|
||||||
case u.g > u.rhs:
|
case u.g > u.rhs:
|
||||||
u.g = u.rhs
|
u.g = u.rhs
|
||||||
d.queue.remove(u)
|
d.queue.remove(u)
|
||||||
for _, _s := range d.model.To(u) {
|
for _, _s := range d.model.To(uid) {
|
||||||
s := _s.(*dStarLiteNode)
|
s := _s.(*dStarLiteNode)
|
||||||
if s.ID() != d.t.ID() {
|
sid := s.ID()
|
||||||
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, s, u)+u.g)
|
if sid != d.t.ID() {
|
||||||
|
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, uid)+u.g)
|
||||||
}
|
}
|
||||||
d.update(s)
|
d.update(s)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
gOld := u.g
|
gOld := u.g
|
||||||
u.g = math.Inf(1)
|
u.g = math.Inf(1)
|
||||||
for _, _s := range append(d.model.To(u), u) {
|
for _, _s := range append(d.model.To(uid), u) {
|
||||||
s := _s.(*dStarLiteNode)
|
s := _s.(*dStarLiteNode)
|
||||||
if s.rhs == edgeWeight(d.model.Weight, s, u)+gOld {
|
sid := s.ID()
|
||||||
|
if s.rhs == edgeWeight(d.model.Weight, sid, uid)+gOld {
|
||||||
if s.ID() != d.t.ID() {
|
if s.ID() != d.t.ID() {
|
||||||
s.rhs = math.Inf(1)
|
s.rhs = math.Inf(1)
|
||||||
for _, t := range d.model.From(s) {
|
for _, t := range d.model.From(sid) {
|
||||||
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, s, t)+t.(*dStarLiteNode).g)
|
tid := t.ID()
|
||||||
|
s.rhs = math.Min(s.rhs, edgeWeight(d.model.Weight, sid, tid)+t.(*dStarLiteNode).g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,9 +249,10 @@ func (d *DStarLite) Step() bool {
|
|||||||
min := math.Inf(1)
|
min := math.Inf(1)
|
||||||
|
|
||||||
var next *dStarLiteNode
|
var next *dStarLiteNode
|
||||||
for _, _s := range d.model.From(d.s) {
|
dsid := d.s.ID()
|
||||||
|
for _, _s := range d.model.From(dsid) {
|
||||||
s := _s.(*dStarLiteNode)
|
s := _s.(*dStarLiteNode)
|
||||||
w := edgeWeight(d.model.Weight, d.s, s) + s.g
|
w := edgeWeight(d.model.Weight, dsid, s.ID()) + s.g
|
||||||
if w < min || (w == min && s.rhs < rhs) {
|
if w < min || (w == min && s.rhs < rhs) {
|
||||||
next = s
|
next = s
|
||||||
min = w
|
min = w
|
||||||
@@ -294,24 +301,27 @@ func (d *DStarLite) UpdateWorld(changes []graph.Edge) {
|
|||||||
d.last = d.s
|
d.last = d.s
|
||||||
for _, e := range changes {
|
for _, e := range changes {
|
||||||
from := e.From()
|
from := e.From()
|
||||||
|
fid := from.ID()
|
||||||
to := e.To()
|
to := e.To()
|
||||||
c, _ := d.weight(from, to)
|
tid := to.ID()
|
||||||
|
c, _ := d.weight(fid, tid)
|
||||||
if c < 0 {
|
if c < 0 {
|
||||||
panic("D* Lite: negative edge weight")
|
panic("D* Lite: negative edge weight")
|
||||||
}
|
}
|
||||||
cOld, _ := d.model.Weight(from, to)
|
cOld, _ := d.model.Weight(fid, tid)
|
||||||
u := d.worldNodeFor(from)
|
u := d.worldNodeFor(from)
|
||||||
v := d.worldNodeFor(to)
|
v := d.worldNodeFor(to)
|
||||||
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: v, W: c})
|
d.model.SetWeightedEdge(simple.WeightedEdge{F: u, T: v, W: c})
|
||||||
|
uid := u.ID()
|
||||||
if cOld > c {
|
if cOld > c {
|
||||||
if u.ID() != d.t.ID() {
|
if uid != d.t.ID() {
|
||||||
u.rhs = math.Min(u.rhs, c+v.g)
|
u.rhs = math.Min(u.rhs, c+v.g)
|
||||||
}
|
}
|
||||||
} else if u.rhs == cOld+v.g {
|
} else if u.rhs == cOld+v.g {
|
||||||
if u.ID() != d.t.ID() {
|
if uid != d.t.ID() {
|
||||||
u.rhs = math.Inf(1)
|
u.rhs = math.Inf(1)
|
||||||
for _, t := range d.model.From(u) {
|
for _, t := range d.model.From(uid) {
|
||||||
u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, u, t)+t.(*dStarLiteNode).g)
|
u.rhs = math.Min(u.rhs, edgeWeight(d.model.Weight, uid, t.ID())+t.(*dStarLiteNode).g)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -354,9 +364,11 @@ func (d *DStarLite) Path() (p []graph.Node, weight float64) {
|
|||||||
next *dStarLiteNode
|
next *dStarLiteNode
|
||||||
cost float64
|
cost float64
|
||||||
)
|
)
|
||||||
for _, _v := range d.model.From(u) {
|
uid := u.ID()
|
||||||
|
for _, _v := range d.model.From(uid) {
|
||||||
v := _v.(*dStarLiteNode)
|
v := _v.(*dStarLiteNode)
|
||||||
w := edgeWeight(d.model.Weight, u, v)
|
vid := v.ID()
|
||||||
|
w := edgeWeight(d.model.Weight, uid, vid)
|
||||||
if rhs := w + v.g; rhs < min || (rhs == min && v.rhs < rhsMin) {
|
if rhs := w + v.g; rhs < min || (rhs == min && v.rhs < rhsMin) {
|
||||||
next = v
|
next = v
|
||||||
min = rhs
|
min = rhs
|
||||||
|
@@ -389,7 +389,8 @@ var dynamicDStarLiteTests = []struct {
|
|||||||
all := l.Grid.AllVisible
|
all := l.Grid.AllVisible
|
||||||
l.Grid.AllVisible = false
|
l.Grid.AllVisible = false
|
||||||
for _, n := range l.Nodes() {
|
for _, n := range l.Nodes() {
|
||||||
l.Known[n.ID()] = !l.Grid.Has(n)
|
id := n.ID()
|
||||||
|
l.Known[id] = !l.Grid.Has(id)
|
||||||
}
|
}
|
||||||
l.Grid.AllVisible = all
|
l.Grid.AllVisible = all
|
||||||
|
|
||||||
@@ -401,19 +402,21 @@ var dynamicDStarLiteTests = []struct {
|
|||||||
|
|
||||||
// Check we have a correctly modified representation.
|
// Check we have a correctly modified representation.
|
||||||
for _, u := range l.Nodes() {
|
for _, u := range l.Nodes() {
|
||||||
|
uid := u.ID()
|
||||||
for _, v := range l.Nodes() {
|
for _, v := range l.Nodes() {
|
||||||
if l.HasEdgeBetween(u, v) != l.Grid.HasEdgeBetween(u, v) {
|
vid := v.ID()
|
||||||
ur, uc := l.RowCol(u.ID())
|
if l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) {
|
||||||
vr, vc := l.RowCol(v.ID())
|
ur, uc := l.RowCol(uid)
|
||||||
|
vr, vc := l.RowCol(vid)
|
||||||
if (ur == wallRow && uc == wallCol) || (vr == wallRow && vc == wallCol) {
|
if (ur == wallRow && uc == wallCol) || (vr == wallRow && vc == wallCol) {
|
||||||
if !l.HasEdgeBetween(u, v) {
|
if !l.HasEdgeBetween(uid, vid) {
|
||||||
panic(fmt.Sprintf("expected to believe edge between %v (%d,%d) and %v (%d,%d) is passable",
|
panic(fmt.Sprintf("expected to believe edge between %v (%d,%d) and %v (%d,%d) is passable",
|
||||||
u, v, ur, uc, vr, vc))
|
u, v, ur, uc, vr, vc))
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("disagreement about edge between %v (%d,%d) and %v (%d,%d): got:%t want:%t",
|
panic(fmt.Sprintf("disagreement about edge between %v (%d,%d) and %v (%d,%d): got:%t want:%t",
|
||||||
u, v, ur, uc, vr, vc, l.HasEdgeBetween(u, v), l.Grid.HasEdgeBetween(u, v)))
|
u, v, ur, uc, vr, vc, l.HasEdgeBetween(uid, vid), l.Grid.HasEdgeBetween(uid, vid)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -574,8 +577,8 @@ func TestDStarLiteDynamic(t *testing.T) {
|
|||||||
l.MoveTo(test.s)
|
l.MoveTo(test.s)
|
||||||
|
|
||||||
heuristic := func(a, b graph.Node) float64 {
|
heuristic := func(a, b graph.Node) float64 {
|
||||||
ax, ay := l.XY(a)
|
ax, ay := l.XY(a.ID())
|
||||||
bx, by := l.XY(b)
|
bx, by := l.XY(b.ID())
|
||||||
return test.heuristic(ax-bx, ay-by)
|
return test.heuristic(ax-bx, ay-by)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -657,7 +660,7 @@ func weightOf(path []graph.Node, g graph.Weighted) float64 {
|
|||||||
var w float64
|
var w float64
|
||||||
if len(path) > 1 {
|
if len(path) > 1 {
|
||||||
for p, n := range path[1:] {
|
for p, n := range path[1:] {
|
||||||
ew, ok := g.Weight(path[p], n)
|
ew, ok := g.Weight(path[p].ID(), n.ID())
|
||||||
if !ok {
|
if !ok {
|
||||||
return math.Inf(1)
|
return math.Inf(1)
|
||||||
}
|
}
|
||||||
@@ -673,7 +676,7 @@ func simpleWeightedEdgesOf(g graph.Weighted, edges []graph.Edge) []simple.Weight
|
|||||||
for i, e := range edges {
|
for i, e := range edges {
|
||||||
w[i].F = e.From()
|
w[i].F = e.From()
|
||||||
w[i].T = e.To()
|
w[i].T = e.To()
|
||||||
ew, _ := g.Weight(e.From(), e.To())
|
ew, _ := g.Weight(e.From().ID(), e.To().ID())
|
||||||
w[i].W = ew
|
w[i].W = ew
|
||||||
}
|
}
|
||||||
return w
|
return w
|
||||||
|
@@ -61,7 +61,7 @@ func (d *dumper) dump(withpath bool) {
|
|||||||
switch ln {
|
switch ln {
|
||||||
case 0:
|
case 0:
|
||||||
if n.ID() == d.grid.Location.ID() {
|
if n.ID() == d.grid.Location.ID() {
|
||||||
if d.grid.Grid.HasOpen(n) {
|
if d.grid.Grid.HasOpen(n.ID()) {
|
||||||
fmt.Fprintf(w, "id:%2d >@<", n.ID())
|
fmt.Fprintf(w, "id:%2d >@<", n.ID())
|
||||||
} else {
|
} else {
|
||||||
// Mark location as illegal.
|
// Mark location as illegal.
|
||||||
@@ -70,19 +70,19 @@ func (d *dumper) dump(withpath bool) {
|
|||||||
} else if n.ID() == d.dStarLite.t.ID() {
|
} else if n.ID() == d.dStarLite.t.ID() {
|
||||||
fmt.Fprintf(w, "id:%2d G", n.ID())
|
fmt.Fprintf(w, "id:%2d G", n.ID())
|
||||||
// Mark goal cell as illegal.
|
// Mark goal cell as illegal.
|
||||||
if !d.grid.Grid.HasOpen(n) {
|
if !d.grid.Grid.HasOpen(n.ID()) {
|
||||||
fmt.Fprint(w, "!")
|
fmt.Fprint(w, "!")
|
||||||
}
|
}
|
||||||
} else if pathStep[n.ID()] > 0 {
|
} else if pathStep[n.ID()] > 0 {
|
||||||
fmt.Fprintf(w, "id:%2d %2d", n.ID(), pathStep[n.ID()])
|
fmt.Fprintf(w, "id:%2d %2d", n.ID(), pathStep[n.ID()])
|
||||||
// Mark path cells with an obstruction.
|
// Mark path cells with an obstruction.
|
||||||
if !d.grid.Grid.HasOpen(n) {
|
if !d.grid.Grid.HasOpen(n.ID()) {
|
||||||
fmt.Fprint(w, "!")
|
fmt.Fprint(w, "!")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(w, "id:%2d", n.ID())
|
fmt.Fprintf(w, "id:%2d", n.ID())
|
||||||
// Mark cells with an obstruction.
|
// Mark cells with an obstruction.
|
||||||
if !d.grid.Grid.HasOpen(n) {
|
if !d.grid.Grid.HasOpen(n.ID()) {
|
||||||
fmt.Fprint(w, " *")
|
fmt.Fprint(w, " *")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,9 +23,11 @@ func FloydWarshall(g graph.Graph) (paths AllShortest, ok bool) {
|
|||||||
paths = newAllShortest(nodes, true)
|
paths = newAllShortest(nodes, true)
|
||||||
for i, u := range nodes {
|
for i, u := range nodes {
|
||||||
paths.dist.Set(i, i, 0)
|
paths.dist.Set(i, i, 0)
|
||||||
for _, v := range g.From(u) {
|
uid := u.ID()
|
||||||
j := paths.indexOf[v.ID()]
|
for _, v := range g.From(uid) {
|
||||||
w, ok := weight(u, v)
|
vid := v.ID()
|
||||||
|
j := paths.indexOf[vid]
|
||||||
|
w, ok := weight(uid, vid)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("floyd-warshall: unexpected invalid weight")
|
panic("floyd-warshall: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
|
@@ -35,12 +35,12 @@ func TestFloydWarshall(t *testing.T) {
|
|||||||
|
|
||||||
// Check all random paths returned are OK.
|
// Check all random paths returned are OK.
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
|
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
|
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
@@ -66,13 +66,13 @@ func TestFloydWarshall(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
|
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||||
if np != nil || !math.IsInf(weight, 1) || unique {
|
if np != nil || !math.IsInf(weight, 1) || unique {
|
||||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
||||||
test.Name, np, weight, unique)
|
test.Name, np, weight, unique)
|
||||||
}
|
}
|
||||||
|
|
||||||
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
|
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
@@ -93,7 +93,7 @@ func TestFloydWarshall(t *testing.T) {
|
|||||||
test.Name, got, test.WantPaths)
|
test.Name, got, test.WantPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
|
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||||
if nps != nil || !math.IsInf(weight, 1) {
|
if nps != nil || !math.IsInf(weight, 1) {
|
||||||
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||||
test.Name, nps, weight)
|
test.Name, nps, weight)
|
||||||
|
@@ -104,17 +104,12 @@ func (g *Grid) Nodes() []graph.Node {
|
|||||||
// Has returns whether n is a node in the grid. The state of
|
// Has returns whether n is a node in the grid. The state of
|
||||||
// the AllVisible field determines whether a non-open node is
|
// the AllVisible field determines whether a non-open node is
|
||||||
// present.
|
// present.
|
||||||
func (g *Grid) Has(n graph.Node) bool {
|
func (g *Grid) Has(id int64) bool {
|
||||||
return g.has(n.ID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Grid) has(id int64) bool {
|
|
||||||
return 0 <= id && id < int64(len(g.open)) && (g.AllVisible || g.open[id])
|
return 0 <= id && id < int64(len(g.open)) && (g.AllVisible || g.open[id])
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasOpen returns whether n is an open node in the grid.
|
// HasOpen returns whether n is an open node in the grid.
|
||||||
func (g *Grid) HasOpen(n graph.Node) bool {
|
func (g *Grid) HasOpen(id int64) bool {
|
||||||
id := n.ID()
|
|
||||||
return 0 <= id && id < int64(len(g.open)) && g.open[id]
|
return 0 <= id && id < int64(len(g.open)) && g.open[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,11 +140,11 @@ func (g *Grid) RowCol(id int64) (r, c int) {
|
|||||||
|
|
||||||
// XY returns the cartesian coordinates of n. If n is not a node
|
// XY returns the cartesian coordinates of n. If n is not a node
|
||||||
// in the grid, (NaN, NaN) is returned.
|
// in the grid, (NaN, NaN) is returned.
|
||||||
func (g *Grid) XY(n graph.Node) (x, y float64) {
|
func (g *Grid) XY(id int64) (x, y float64) {
|
||||||
if !g.Has(n) {
|
if !g.Has(id) {
|
||||||
return math.NaN(), math.NaN()
|
return math.NaN(), math.NaN()
|
||||||
}
|
}
|
||||||
r, c := g.RowCol(n.ID())
|
r, c := g.RowCol(id)
|
||||||
return float64(c), float64(r)
|
return float64(c), float64(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,15 +158,15 @@ func (g *Grid) NodeAt(r, c int) graph.Node {
|
|||||||
|
|
||||||
// From returns all the nodes reachable from u. Reachabilty requires that both
|
// From returns all the nodes reachable from u. Reachabilty requires that both
|
||||||
// ends of an edge must be open.
|
// ends of an edge must be open.
|
||||||
func (g *Grid) From(u graph.Node) []graph.Node {
|
func (g *Grid) From(uid int64) []graph.Node {
|
||||||
if !g.HasOpen(u) {
|
if !g.HasOpen(uid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
nr, nc := g.RowCol(u.ID())
|
nr, nc := g.RowCol(uid)
|
||||||
var to []graph.Node
|
var to []graph.Node
|
||||||
for r := nr - 1; r <= nr+1; r++ {
|
for r := nr - 1; r <= nr+1; r++ {
|
||||||
for c := nc - 1; c <= nc+1; c++ {
|
for c := nc - 1; c <= nc+1; c++ {
|
||||||
if v := g.NodeAt(r, c); v != nil && g.HasEdgeBetween(u, v) {
|
if v := g.NodeAt(r, c); v != nil && g.HasEdgeBetween(uid, v.ID()) {
|
||||||
to = append(to, v)
|
to = append(to, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,12 +175,12 @@ func (g *Grid) From(u graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether there is an edge between u and v.
|
// HasEdgeBetween returns whether there is an edge between u and v.
|
||||||
func (g *Grid) HasEdgeBetween(u, v graph.Node) bool {
|
func (g *Grid) HasEdgeBetween(uid, vid int64) bool {
|
||||||
if !g.HasOpen(u) || !g.HasOpen(v) || u.ID() == v.ID() {
|
if !g.HasOpen(uid) || !g.HasOpen(vid) || uid == vid {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
ur, uc := g.RowCol(u.ID())
|
ur, uc := g.RowCol(uid)
|
||||||
vr, vc := g.RowCol(v.ID())
|
vr, vc := g.RowCol(vid)
|
||||||
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -200,47 +195,47 @@ func abs(i int) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Edge returns the edge between u and v.
|
// Edge returns the edge between u and v.
|
||||||
func (g *Grid) Edge(u, v graph.Node) graph.Edge {
|
func (g *Grid) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge between u and v.
|
// WeightedEdge returns the weighted edge between u and v.
|
||||||
func (g *Grid) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *Grid) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between u and v.
|
// EdgeBetween returns the edge between u and v.
|
||||||
func (g *Grid) EdgeBetween(u, v graph.Node) graph.Edge {
|
func (g *Grid) EdgeBetween(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween returns the weighted edge between u and v.
|
// WeightedEdgeBetween returns the weighted edge between u and v.
|
||||||
func (g *Grid) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
|
func (g *Grid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
|
||||||
if g.HasEdgeBetween(u, v) {
|
if g.HasEdgeBetween(uid, vid) {
|
||||||
if !g.AllowDiagonal || g.UnitEdgeWeight {
|
if !g.AllowDiagonal || g.UnitEdgeWeight {
|
||||||
return simple.WeightedEdge{F: u, T: v, W: 1}
|
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: 1}
|
||||||
}
|
}
|
||||||
ux, uy := g.XY(u)
|
ux, uy := g.XY(uid)
|
||||||
vx, vy := g.XY(v)
|
vx, vy := g.XY(vid)
|
||||||
return simple.WeightedEdge{F: u, T: v, W: math.Hypot(ux-vx, uy-vy)}
|
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weight returns the weight of the given edge.
|
// Weight returns the weight of the given edge.
|
||||||
func (g *Grid) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g *Grid) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
if x.ID() == y.ID() {
|
if xid == yid {
|
||||||
return 0, true
|
return 0, true
|
||||||
}
|
}
|
||||||
if !g.HasEdgeBetween(x, y) {
|
if !g.HasEdgeBetween(xid, yid) {
|
||||||
return math.Inf(1), false
|
return math.Inf(1), false
|
||||||
}
|
}
|
||||||
if e := g.EdgeBetween(x, y); e != nil {
|
if e := g.EdgeBetween(xid, yid); e != nil {
|
||||||
if !g.AllowDiagonal || g.UnitEdgeWeight {
|
if !g.AllowDiagonal || g.UnitEdgeWeight {
|
||||||
return 1, true
|
return 1, true
|
||||||
}
|
}
|
||||||
ux, uy := g.XY(e.From())
|
ux, uy := g.XY(e.From().ID())
|
||||||
vx, vy := g.XY(e.To())
|
vx, vy := g.XY(e.To().ID())
|
||||||
return math.Hypot(ux-vx, uy-vy), true
|
return math.Hypot(ux-vx, uy-vy), true
|
||||||
}
|
}
|
||||||
return math.Inf(1), true
|
return math.Inf(1), true
|
||||||
@@ -274,15 +269,15 @@ func (g *Grid) Render(path []graph.Node) ([]byte, error) {
|
|||||||
// We don't use topo.IsPathIn at the outset because we
|
// We don't use topo.IsPathIn at the outset because we
|
||||||
// want to draw as much as possible before failing.
|
// want to draw as much as possible before failing.
|
||||||
for i, n := range path {
|
for i, n := range path {
|
||||||
if !g.Has(n) || (i != 0 && !g.HasEdgeBetween(path[i-1], n)) {
|
id := n.ID()
|
||||||
id := n.ID()
|
if !g.Has(id) || (i != 0 && !g.HasEdgeBetween(path[i-1].ID(), id)) {
|
||||||
if 0 <= id && id < int64(len(g.open)) {
|
if 0 <= id && id < int64(len(g.open)) {
|
||||||
r, c := g.RowCol(n.ID())
|
r, c := g.RowCol(id)
|
||||||
b[r*(g.c+1)+c] = '!'
|
b[r*(g.c+1)+c] = '!'
|
||||||
}
|
}
|
||||||
return b, errors.New("grid: not a path in graph")
|
return b, errors.New("grid: not a path in graph")
|
||||||
}
|
}
|
||||||
r, c := g.RowCol(n.ID())
|
r, c := g.RowCol(id)
|
||||||
switch i {
|
switch i {
|
||||||
case len(path) - 1:
|
case len(path) - 1:
|
||||||
b[r*(g.c+1)+c] = 'G'
|
b[r*(g.c+1)+c] = 'G'
|
||||||
|
@@ -249,7 +249,7 @@ func TestGrid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, test := range reach {
|
for _, test := range reach {
|
||||||
g.AllowDiagonal = test.diagonal
|
g.AllowDiagonal = test.diagonal
|
||||||
got := g.From(test.from)
|
got := g.From(test.from.ID())
|
||||||
if !reflect.DeepEqual(got, test.to) {
|
if !reflect.DeepEqual(got, test.to) {
|
||||||
t.Fatalf("unexpected nodes from %d with allow diagonal=%t:\ngot: %v\nwant:%v",
|
t.Fatalf("unexpected nodes from %d with allow diagonal=%t:\ngot: %v\nwant:%v",
|
||||||
test.from, test.diagonal, got, test.to)
|
test.from, test.diagonal, got, test.to)
|
||||||
|
@@ -47,23 +47,25 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
|
|||||||
if u == nil {
|
if u == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ux, uy := l.XY(u)
|
uid := u.ID()
|
||||||
|
ux, uy := l.XY(uid)
|
||||||
if math.Hypot(x-ux, y-uy) > l.VisionRadius {
|
if math.Hypot(x-ux, y-uy) > l.VisionRadius {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, v := range l.allPossibleFrom(u) {
|
for _, v := range l.allPossibleFrom(uid) {
|
||||||
if seen[[2]int64{u.ID(), v.ID()}] {
|
vid := v.ID()
|
||||||
|
if seen[[2]int64{uid, vid}] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seen[[2]int64{u.ID(), v.ID()}] = true
|
seen[[2]int64{uid, vid}] = true
|
||||||
|
|
||||||
vx, vy := l.XY(v)
|
vx, vy := l.XY(vid)
|
||||||
if !l.Known[v.ID()] && math.Hypot(x-vx, y-vy) > l.VisionRadius {
|
if !l.Known[vid] && math.Hypot(x-vx, y-vy) > l.VisionRadius {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
e := simple.Edge{F: u, T: v}
|
e := simple.Edge{F: u, T: v}
|
||||||
if !l.Known[u.ID()] || !l.Known[v.ID()] {
|
if !l.Known[uid] || !l.Known[vid] {
|
||||||
new = append(new, e)
|
new = append(new, e)
|
||||||
} else {
|
} else {
|
||||||
old = append(old, e)
|
old = append(old, e)
|
||||||
@@ -79,18 +81,20 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
|
|||||||
if u == nil {
|
if u == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ux, uy := l.XY(u)
|
uid := u.ID()
|
||||||
|
ux, uy := l.XY(uid)
|
||||||
if math.Hypot(x-ux, y-uy) > l.VisionRadius {
|
if math.Hypot(x-ux, y-uy) > l.VisionRadius {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, v := range l.allPossibleFrom(u) {
|
for _, v := range l.allPossibleFrom(uid) {
|
||||||
vx, vy := l.XY(v)
|
vid := v.ID()
|
||||||
|
vx, vy := l.XY(vid)
|
||||||
if math.Hypot(x-vx, y-vy) > l.VisionRadius {
|
if math.Hypot(x-vx, y-vy) > l.VisionRadius {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
l.Known[v.ID()] = true
|
l.Known[vid] = true
|
||||||
}
|
}
|
||||||
l.Known[u.ID()] = true
|
l.Known[uid] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,19 +104,19 @@ func (l *LimitedVisionGrid) MoveTo(n graph.Node) (new, old []graph.Edge) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// allPossibleFrom returns all the nodes possibly reachable from u.
|
// allPossibleFrom returns all the nodes possibly reachable from u.
|
||||||
func (l *LimitedVisionGrid) allPossibleFrom(u graph.Node) []graph.Node {
|
func (l *LimitedVisionGrid) allPossibleFrom(uid int64) []graph.Node {
|
||||||
if !l.Has(u) {
|
if !l.Has(uid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
nr, nc := l.RowCol(u.ID())
|
nr, nc := l.RowCol(uid)
|
||||||
var to []graph.Node
|
var to []graph.Node
|
||||||
for r := nr - 1; r <= nr+1; r++ {
|
for r := nr - 1; r <= nr+1; r++ {
|
||||||
for c := nc - 1; c <= nc+1; c++ {
|
for c := nc - 1; c <= nc+1; c++ {
|
||||||
v := l.NodeAt(r, c)
|
v := l.NodeAt(r, c)
|
||||||
if v == nil || u.ID() == v.ID() {
|
if v == nil || uid == v.ID() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ur, uc := l.RowCol(u.ID())
|
ur, uc := l.RowCol(uid)
|
||||||
vr, vc := l.RowCol(v.ID())
|
vr, vc := l.RowCol(v.ID())
|
||||||
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
||||||
continue
|
continue
|
||||||
@@ -134,11 +138,11 @@ func (l *LimitedVisionGrid) RowCol(id int64) (r, c int) {
|
|||||||
|
|
||||||
// XY returns the cartesian coordinates of n. If n is not a node
|
// XY returns the cartesian coordinates of n. If n is not a node
|
||||||
// in the grid, (NaN, NaN) is returned.
|
// in the grid, (NaN, NaN) is returned.
|
||||||
func (l *LimitedVisionGrid) XY(n graph.Node) (x, y float64) {
|
func (l *LimitedVisionGrid) XY(id int64) (x, y float64) {
|
||||||
if !l.Has(n) {
|
if !l.Has(id) {
|
||||||
return math.NaN(), math.NaN()
|
return math.NaN(), math.NaN()
|
||||||
}
|
}
|
||||||
r, c := l.RowCol(n.ID())
|
r, c := l.RowCol(id)
|
||||||
return float64(c), float64(r)
|
return float64(c), float64(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,25 +161,21 @@ func (l *LimitedVisionGrid) NodeAt(r, c int) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether n is a node in the grid.
|
// Has returns whether n is a node in the grid.
|
||||||
func (l *LimitedVisionGrid) Has(n graph.Node) bool {
|
func (l *LimitedVisionGrid) Has(id int64) bool {
|
||||||
return l.has(n.ID())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *LimitedVisionGrid) has(id int64) bool {
|
|
||||||
return 0 <= id && id < int64(len(l.Grid.open))
|
return 0 <= id && id < int64(len(l.Grid.open))
|
||||||
}
|
}
|
||||||
|
|
||||||
// From returns nodes that are optimistically reachable from u.
|
// From returns nodes that are optimistically reachable from u.
|
||||||
func (l *LimitedVisionGrid) From(u graph.Node) []graph.Node {
|
func (l *LimitedVisionGrid) From(uid int64) []graph.Node {
|
||||||
if !l.Has(u) {
|
if !l.Has(uid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
nr, nc := l.RowCol(u.ID())
|
nr, nc := l.RowCol(uid)
|
||||||
var to []graph.Node
|
var to []graph.Node
|
||||||
for r := nr - 1; r <= nr+1; r++ {
|
for r := nr - 1; r <= nr+1; r++ {
|
||||||
for c := nc - 1; c <= nc+1; c++ {
|
for c := nc - 1; c <= nc+1; c++ {
|
||||||
if v := l.NodeAt(r, c); v != nil && l.HasEdgeBetween(u, v) {
|
if v := l.NodeAt(r, c); v != nil && l.HasEdgeBetween(uid, v.ID()) {
|
||||||
to = append(to, v)
|
to = append(to, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,12 +184,12 @@ func (l *LimitedVisionGrid) From(u graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween optimistically returns whether an edge is exists between u and v.
|
// HasEdgeBetween optimistically returns whether an edge is exists between u and v.
|
||||||
func (l *LimitedVisionGrid) HasEdgeBetween(u, v graph.Node) bool {
|
func (l *LimitedVisionGrid) HasEdgeBetween(uid, vid int64) bool {
|
||||||
if u.ID() == v.ID() {
|
if uid == vid {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
ur, uc := l.RowCol(u.ID())
|
ur, uc := l.RowCol(uid)
|
||||||
vr, vc := l.RowCol(v.ID())
|
vr, vc := l.RowCol(vid)
|
||||||
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -197,66 +197,66 @@ func (l *LimitedVisionGrid) HasEdgeBetween(u, v graph.Node) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
x, y := l.XY(l.Location)
|
x, y := l.XY(l.Location.ID())
|
||||||
ux, uy := l.XY(u)
|
ux, uy := l.XY(uid)
|
||||||
vx, vy := l.XY(v)
|
vx, vy := l.XY(vid)
|
||||||
uKnown := l.Known[u.ID()] || math.Hypot(x-ux, y-uy) <= l.VisionRadius
|
uKnown := l.Known[uid] || math.Hypot(x-ux, y-uy) <= l.VisionRadius
|
||||||
vKnown := l.Known[v.ID()] || math.Hypot(x-vx, y-vy) <= l.VisionRadius
|
vKnown := l.Known[vid] || math.Hypot(x-vx, y-vy) <= l.VisionRadius
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case uKnown && vKnown:
|
case uKnown && vKnown:
|
||||||
return l.Grid.HasEdgeBetween(u, v)
|
return l.Grid.HasEdgeBetween(uid, vid)
|
||||||
case uKnown:
|
case uKnown:
|
||||||
return l.Grid.HasOpen(u)
|
return l.Grid.HasOpen(uid)
|
||||||
case vKnown:
|
case vKnown:
|
||||||
return l.Grid.HasOpen(v)
|
return l.Grid.HasOpen(vid)
|
||||||
default:
|
default:
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edge optimistically returns the edge from u to v.
|
// Edge optimistically returns the edge from u to v.
|
||||||
func (l *LimitedVisionGrid) Edge(u, v graph.Node) graph.Edge {
|
func (l *LimitedVisionGrid) Edge(uid, vid int64) graph.Edge {
|
||||||
return l.WeightedEdgeBetween(u, v)
|
return l.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edge optimistically returns the weighted edge from u to v.
|
// Edge optimistically returns the weighted edge from u to v.
|
||||||
func (l *LimitedVisionGrid) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (l *LimitedVisionGrid) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
return l.WeightedEdgeBetween(u, v)
|
return l.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween optimistically returns the edge between u and v.
|
// WeightedEdgeBetween optimistically returns the edge between u and v.
|
||||||
func (l *LimitedVisionGrid) EdgeBetween(u, v graph.Node) graph.Edge {
|
func (l *LimitedVisionGrid) EdgeBetween(uid, vid int64) graph.Edge {
|
||||||
return l.WeightedEdgeBetween(u, v)
|
return l.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween optimistically returns the weighted edge between u and v.
|
// WeightedEdgeBetween optimistically returns the weighted edge between u and v.
|
||||||
func (l *LimitedVisionGrid) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
|
func (l *LimitedVisionGrid) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
|
||||||
if l.HasEdgeBetween(u, v) {
|
if l.HasEdgeBetween(uid, vid) {
|
||||||
if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight {
|
if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight {
|
||||||
return simple.WeightedEdge{F: u, T: v, W: 1}
|
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: 1}
|
||||||
}
|
}
|
||||||
ux, uy := l.XY(u)
|
ux, uy := l.XY(uid)
|
||||||
vx, vy := l.XY(v)
|
vx, vy := l.XY(vid)
|
||||||
return simple.WeightedEdge{F: u, T: v, W: math.Hypot(ux-vx, uy-vy)}
|
return simple.WeightedEdge{F: simple.Node(uid), T: simple.Node(vid), W: math.Hypot(ux-vx, uy-vy)}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Weight returns the weight of the given edge.
|
// Weight returns the weight of the given edge.
|
||||||
func (l *LimitedVisionGrid) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (l *LimitedVisionGrid) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
if x.ID() == y.ID() {
|
if xid == yid {
|
||||||
return 0, true
|
return 0, true
|
||||||
}
|
}
|
||||||
if !l.HasEdgeBetween(x, y) {
|
if !l.HasEdgeBetween(xid, yid) {
|
||||||
return math.Inf(1), false
|
return math.Inf(1), false
|
||||||
}
|
}
|
||||||
if e := l.EdgeBetween(x, y); e != nil {
|
if e := l.EdgeBetween(xid, yid); e != nil {
|
||||||
if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight {
|
if !l.Grid.AllowDiagonal || l.Grid.UnitEdgeWeight {
|
||||||
return 1, true
|
return 1, true
|
||||||
}
|
}
|
||||||
ux, uy := l.XY(e.From())
|
ux, uy := l.XY(e.From().ID())
|
||||||
vx, vy := l.XY(e.To())
|
vx, vy := l.XY(e.To().ID())
|
||||||
return math.Hypot(ux-vx, uy-vy), true
|
return math.Hypot(ux-vx, uy-vy), true
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -294,15 +294,15 @@ func (l *LimitedVisionGrid) Render(path []graph.Node) ([]byte, error) {
|
|||||||
// We don't use topo.IsPathIn at the outset because we
|
// We don't use topo.IsPathIn at the outset because we
|
||||||
// want to draw as much as possible before failing.
|
// want to draw as much as possible before failing.
|
||||||
for i, n := range path {
|
for i, n := range path {
|
||||||
if !l.Has(n) || (i != 0 && !l.HasEdgeBetween(path[i-1], n)) {
|
id := n.ID()
|
||||||
id := n.ID()
|
if !l.Has(id) || (i != 0 && !l.HasEdgeBetween(path[i-1].ID(), id)) {
|
||||||
if 0 <= id && id < int64(len(l.Grid.open)) {
|
if 0 <= id && id < int64(len(l.Grid.open)) {
|
||||||
r, c := l.RowCol(n.ID())
|
r, c := l.RowCol(id)
|
||||||
b[r*(cols+1)+c] = '!'
|
b[r*(cols+1)+c] = '!'
|
||||||
}
|
}
|
||||||
return b, errors.New("grid: not a path in graph")
|
return b, errors.New("grid: not a path in graph")
|
||||||
}
|
}
|
||||||
r, c := l.RowCol(n.ID())
|
r, c := l.RowCol(id)
|
||||||
switch i {
|
switch i {
|
||||||
case len(path) - 1:
|
case len(path) - 1:
|
||||||
b[r*(cols+1)+c] = 'G'
|
b[r*(cols+1)+c] = 'G'
|
||||||
|
@@ -1165,23 +1165,25 @@ func TestLimitedVisionGrid(t *testing.T) {
|
|||||||
}
|
}
|
||||||
l.Grid.AllowDiagonal = test.diag
|
l.Grid.AllowDiagonal = test.diag
|
||||||
|
|
||||||
x, y := l.XY(test.path[0])
|
x, y := l.XY(test.path[0].ID())
|
||||||
for _, u := range l.Nodes() {
|
for _, u := range l.Nodes() {
|
||||||
ux, uy := l.XY(u)
|
uid := u.ID()
|
||||||
|
ux, uy := l.XY(uid)
|
||||||
uNear := math.Hypot(x-ux, y-uy) <= test.radius
|
uNear := math.Hypot(x-ux, y-uy) <= test.radius
|
||||||
for _, v := range l.Nodes() {
|
for _, v := range l.Nodes() {
|
||||||
vx, vy := l.XY(v)
|
vid := v.ID()
|
||||||
|
vx, vy := l.XY(vid)
|
||||||
vNear := math.Hypot(x-vx, y-vy) <= test.radius
|
vNear := math.Hypot(x-vx, y-vy) <= test.radius
|
||||||
if u.ID() == v.ID() && l.HasEdgeBetween(u, v) {
|
if u.ID() == v.ID() && l.HasEdgeBetween(uid, vid) {
|
||||||
t.Errorf("unexpected self edge: %v -- %v", u, v)
|
t.Errorf("unexpected self edge: %v -- %v", u, v)
|
||||||
}
|
}
|
||||||
if !uNear && !vNear && !l.HasEdgeBetween(u, v) && couldConnectIn(l, u, v) {
|
if !uNear && !vNear && !l.HasEdgeBetween(uid, vid) && couldConnectIn(l, uid, vid) {
|
||||||
t.Errorf("unexpected pessimism: no hope in distant edge between %v and %v for test %d",
|
t.Errorf("unexpected pessimism: no hope in distant edge between %v and %v for test %d",
|
||||||
u, v, i)
|
u, v, i)
|
||||||
}
|
}
|
||||||
if (uNear && vNear) && l.HasEdgeBetween(u, v) != l.Grid.HasEdgeBetween(u, v) {
|
if (uNear && vNear) && l.HasEdgeBetween(uid, vid) != l.Grid.HasEdgeBetween(uid, vid) {
|
||||||
t.Errorf("unrealistic optimism: disagreement about edge between %v and %v for test %d: got:%t want:%t",
|
t.Errorf("unrealistic optimism: disagreement about edge between %v and %v for test %d: got:%t want:%t",
|
||||||
u, v, i, l.HasEdgeBetween(u, v), l.Grid.HasEdgeBetween(u, v))
|
u, v, i, l.HasEdgeBetween(uid, vid), l.Grid.HasEdgeBetween(uid, vid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1205,7 +1207,7 @@ func asConcreteEdges(changes []graph.Edge, in graph.Weighted) []simple.WeightedE
|
|||||||
for i, e := range changes {
|
for i, e := range changes {
|
||||||
we[i].F = e.From()
|
we[i].F = e.From()
|
||||||
we[i].T = e.To()
|
we[i].T = e.To()
|
||||||
w, ok := in.Weight(e.From(), e.To())
|
w, ok := in.Weight(e.From().ID(), e.To().ID())
|
||||||
if !ok && !math.IsInf(w, 1) {
|
if !ok && !math.IsInf(w, 1) {
|
||||||
panic("unexpected invalid finite weight")
|
panic("unexpected invalid finite weight")
|
||||||
}
|
}
|
||||||
@@ -1214,13 +1216,13 @@ func asConcreteEdges(changes []graph.Edge, in graph.Weighted) []simple.WeightedE
|
|||||||
return we
|
return we
|
||||||
}
|
}
|
||||||
|
|
||||||
func couldConnectIn(l *LimitedVisionGrid, u, v graph.Node) bool {
|
func couldConnectIn(l *LimitedVisionGrid, uid, vid int64) bool {
|
||||||
if u.ID() == v.ID() {
|
if uid == vid {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
ur, uc := l.RowCol(u.ID())
|
ur, uc := l.RowCol(uid)
|
||||||
vr, vc := l.RowCol(v.ID())
|
vr, vc := l.RowCol(vid)
|
||||||
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
if abs(ur-vr) > 1 || abs(uc-vc) > 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -1228,13 +1230,13 @@ func couldConnectIn(l *LimitedVisionGrid, u, v graph.Node) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if !l.Known[u.ID()] && !l.Known[v.ID()] {
|
if !l.Known[uid] && !l.Known[vid] {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if l.Known[u.ID()] && !l.Grid.HasOpen(u) {
|
if l.Known[uid] && !l.Grid.HasOpen(uid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if l.Known[v.ID()] && !l.Grid.HasOpen(v) {
|
if l.Known[vid] && !l.Grid.HasOpen(vid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -52,12 +52,12 @@ func JohnsonAllPaths(g graph.Graph) (paths AllShortest, ok bool) {
|
|||||||
dijkstraAllPaths(jg, paths)
|
dijkstraAllPaths(jg, paths)
|
||||||
|
|
||||||
for i, u := range paths.nodes {
|
for i, u := range paths.nodes {
|
||||||
hu := jg.adjustBy.WeightTo(u)
|
hu := jg.adjustBy.WeightTo(u.ID())
|
||||||
for j, v := range paths.nodes {
|
for j, v := range paths.nodes {
|
||||||
if i == j {
|
if i == j {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
hv := jg.adjustBy.WeightTo(v)
|
hv := jg.adjustBy.WeightTo(v.ID())
|
||||||
paths.dist.Set(i, j, paths.dist.At(i, j)-hu+hv)
|
paths.dist.Set(i, j, paths.dist.At(i, j)-hu+hv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -69,8 +69,8 @@ type johnsonWeightAdjuster struct {
|
|||||||
q int64
|
q int64
|
||||||
g graph.Graph
|
g graph.Graph
|
||||||
|
|
||||||
from func(graph.Node) []graph.Node
|
from func(id int64) []graph.Node
|
||||||
edgeTo func(graph.Node, graph.Node) graph.Edge
|
edgeTo func(uid, vid int64) graph.Edge
|
||||||
weight Weighting
|
weight Weighting
|
||||||
|
|
||||||
bellmanFord bool
|
bellmanFord bool
|
||||||
@@ -86,11 +86,11 @@ var (
|
|||||||
_ graph.Weighted = johnsonWeightAdjuster{}
|
_ graph.Weighted = johnsonWeightAdjuster{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func (g johnsonWeightAdjuster) Has(n graph.Node) bool {
|
func (g johnsonWeightAdjuster) Has(id int64) bool {
|
||||||
if g.bellmanFord && n.ID() == g.q {
|
if g.bellmanFord && id == g.q {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return g.g.Has(n)
|
return g.g.Has(id)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,40 +101,40 @@ func (g johnsonWeightAdjuster) Nodes() []graph.Node {
|
|||||||
return g.g.Nodes()
|
return g.g.Nodes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g johnsonWeightAdjuster) From(n graph.Node) []graph.Node {
|
func (g johnsonWeightAdjuster) From(id int64) []graph.Node {
|
||||||
if g.bellmanFord && n.ID() == g.q {
|
if g.bellmanFord && id == g.q {
|
||||||
return g.g.Nodes()
|
return g.g.Nodes()
|
||||||
}
|
}
|
||||||
return g.from(n)
|
return g.from(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g johnsonWeightAdjuster) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g johnsonWeightAdjuster) WeightedEdge(_, _ int64) graph.WeightedEdge {
|
||||||
panic("path: unintended use of johnsonWeightAdjuster")
|
panic("path: unintended use of johnsonWeightAdjuster")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g johnsonWeightAdjuster) Edge(u, v graph.Node) graph.Edge {
|
func (g johnsonWeightAdjuster) Edge(uid, vid int64) graph.Edge {
|
||||||
if g.bellmanFord && u.ID() == g.q && g.g.Has(v) {
|
if g.bellmanFord && uid == g.q && g.g.Has(vid) {
|
||||||
return simple.Edge{F: johnsonGraphNode(g.q), T: v}
|
return simple.Edge{F: johnsonGraphNode(g.q), T: simple.Node(vid)}
|
||||||
}
|
}
|
||||||
return g.edgeTo(u, v)
|
return g.edgeTo(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g johnsonWeightAdjuster) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g johnsonWeightAdjuster) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
if g.bellmanFord {
|
if g.bellmanFord {
|
||||||
switch g.q {
|
switch g.q {
|
||||||
case x.ID():
|
case xid:
|
||||||
return 0, true
|
return 0, true
|
||||||
case y.ID():
|
case yid:
|
||||||
return math.Inf(1), false
|
return math.Inf(1), false
|
||||||
default:
|
default:
|
||||||
return g.weight(x, y)
|
return g.weight(xid, yid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w, ok = g.weight(x, y)
|
w, ok = g.weight(xid, yid)
|
||||||
return w + g.adjustBy.WeightTo(x) - g.adjustBy.WeightTo(y), ok
|
return w + g.adjustBy.WeightTo(xid) - g.adjustBy.WeightTo(yid), ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (johnsonWeightAdjuster) HasEdgeBetween(_, _ graph.Node) bool {
|
func (johnsonWeightAdjuster) HasEdgeBetween(_, _ int64) bool {
|
||||||
panic("path: unintended use of johnsonWeightAdjuster")
|
panic("path: unintended use of johnsonWeightAdjuster")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -35,12 +35,12 @@ func TestJohnsonAllPaths(t *testing.T) {
|
|||||||
|
|
||||||
// Check all random paths returned are OK.
|
// Check all random paths returned are OK.
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
p, weight, unique := pt.Between(test.Query.From(), test.Query.To())
|
p, weight, unique := pt.Between(test.Query.From().ID(), test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
if weight := pt.Weight(test.Query.From(), test.Query.To()); weight != test.Weight {
|
if weight := pt.Weight(test.Query.From().ID(), test.Query.To().ID()); weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Weight: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
}
|
}
|
||||||
@@ -66,13 +66,13 @@ func TestJohnsonAllPaths(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
np, weight, unique := pt.Between(test.NoPathFor.From(), test.NoPathFor.To())
|
np, weight, unique := pt.Between(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||||
if np != nil || !math.IsInf(weight, 1) || unique {
|
if np != nil || !math.IsInf(weight, 1) || unique {
|
||||||
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
t.Errorf("%q: unexpected path:\ngot: path=%v weight=%f unique=%t\nwant:path=<nil> weight=+Inf unique=false",
|
||||||
test.Name, np, weight, unique)
|
test.Name, np, weight, unique)
|
||||||
}
|
}
|
||||||
|
|
||||||
paths, weight := pt.AllBetween(test.Query.From(), test.Query.To())
|
paths, weight := pt.AllBetween(test.Query.From().ID(), test.Query.To().ID())
|
||||||
if weight != test.Weight {
|
if weight != test.Weight {
|
||||||
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
t.Errorf("%q: unexpected weight from Between: got:%f want:%f",
|
||||||
test.Name, weight, test.Weight)
|
test.Name, weight, test.Weight)
|
||||||
@@ -93,7 +93,7 @@ func TestJohnsonAllPaths(t *testing.T) {
|
|||||||
test.Name, got, test.WantPaths)
|
test.Name, got, test.WantPaths)
|
||||||
}
|
}
|
||||||
|
|
||||||
nps, weight := pt.AllBetween(test.NoPathFor.From(), test.NoPathFor.To())
|
nps, weight := pt.AllBetween(test.NoPathFor.From().ID(), test.NoPathFor.To().ID())
|
||||||
if nps != nil || !math.IsInf(weight, 1) {
|
if nps != nil || !math.IsInf(weight, 1) {
|
||||||
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
t.Errorf("%q: unexpected path:\ngot: paths=%v weight=%f\nwant:path=<nil> weight=+Inf",
|
||||||
test.Name, nps, weight)
|
test.Name, nps, weight)
|
||||||
|
@@ -47,7 +47,7 @@ func ExampleBellmanFordFrom_negativecycles() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, n := range []simple.Node{'a', 'b', 'c', 'd', 'e', 'f'} {
|
for _, n := range []simple.Node{'a', 'b', 'c', 'd', 'e', 'f'} {
|
||||||
p, w := pt.To(n)
|
p, w := pt.To(n.ID())
|
||||||
if math.IsNaN(w) {
|
if math.IsNaN(w) {
|
||||||
fmt.Printf("negative cycle in path to %c path:%c\n", n, p)
|
fmt.Printf("negative cycle in path to %c path:%c\n", n, p)
|
||||||
}
|
}
|
||||||
|
@@ -93,8 +93,8 @@ func (p Shortest) From() graph.Node { return p.from }
|
|||||||
|
|
||||||
// WeightTo returns the weight of the minimum path to v. If the path to v includes
|
// WeightTo returns the weight of the minimum path to v. If the path to v includes
|
||||||
// a negative cycle, the returned weight will not reflect the true path weight.
|
// a negative cycle, the returned weight will not reflect the true path weight.
|
||||||
func (p Shortest) WeightTo(v graph.Node) float64 {
|
func (p Shortest) WeightTo(vid int64) float64 {
|
||||||
to, toOK := p.indexOf[v.ID()]
|
to, toOK := p.indexOf[vid]
|
||||||
if !toOK {
|
if !toOK {
|
||||||
return math.Inf(1)
|
return math.Inf(1)
|
||||||
}
|
}
|
||||||
@@ -104,8 +104,8 @@ func (p Shortest) WeightTo(v graph.Node) float64 {
|
|||||||
// To returns a shortest path to v and the weight of the path. If the path
|
// To returns a shortest path to v and the weight of the path. If the path
|
||||||
// to v includes a negative cycle, one pass through the cycle will be included
|
// to v includes a negative cycle, one pass through the cycle will be included
|
||||||
// in path and weight will be returned as NaN.
|
// in path and weight will be returned as NaN.
|
||||||
func (p Shortest) To(v graph.Node) (path []graph.Node, weight float64) {
|
func (p Shortest) To(vid int64) (path []graph.Node, weight float64) {
|
||||||
to, toOK := p.indexOf[v.ID()]
|
to, toOK := p.indexOf[vid]
|
||||||
if !toOK || math.IsInf(p.dist[to], 1) {
|
if !toOK || math.IsInf(p.dist[to], 1) {
|
||||||
return nil, math.Inf(1)
|
return nil, math.Inf(1)
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ func (p Shortest) To(v graph.Node) (path []graph.Node, weight float64) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ordered.Reverse(path)
|
ordered.Reverse(path)
|
||||||
return path, math.Min(weight, p.dist[p.indexOf[v.ID()]])
|
return path, math.Min(weight, p.dist[p.indexOf[vid]])
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllShortest is a shortest-path tree created by the DijkstraAllPaths, FloydWarshall
|
// AllShortest is a shortest-path tree created by the DijkstraAllPaths, FloydWarshall
|
||||||
@@ -221,9 +221,9 @@ loop: // These are likely to be rare, so just loop over collisions.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Weight returns the weight of the minimum path between u and v.
|
// Weight returns the weight of the minimum path between u and v.
|
||||||
func (p AllShortest) Weight(u, v graph.Node) float64 {
|
func (p AllShortest) Weight(uid, vid int64) float64 {
|
||||||
from, fromOK := p.indexOf[u.ID()]
|
from, fromOK := p.indexOf[uid]
|
||||||
to, toOK := p.indexOf[v.ID()]
|
to, toOK := p.indexOf[vid]
|
||||||
if !fromOK || !toOK {
|
if !fromOK || !toOK {
|
||||||
return math.Inf(1)
|
return math.Inf(1)
|
||||||
}
|
}
|
||||||
@@ -234,11 +234,11 @@ func (p AllShortest) Weight(u, v graph.Node) float64 {
|
|||||||
// one shortest path exists between u and v, a randomly chosen path will be returned and
|
// one shortest path exists between u and v, a randomly chosen path will be returned and
|
||||||
// unique is returned false. If a cycle with zero weight exists in the path, it will not
|
// unique is returned false. If a cycle with zero weight exists in the path, it will not
|
||||||
// be included, but unique will be returned false.
|
// be included, but unique will be returned false.
|
||||||
func (p AllShortest) Between(u, v graph.Node) (path []graph.Node, weight float64, unique bool) {
|
func (p AllShortest) Between(uid, vid int64) (path []graph.Node, weight float64, unique bool) {
|
||||||
from, fromOK := p.indexOf[u.ID()]
|
from, fromOK := p.indexOf[uid]
|
||||||
to, toOK := p.indexOf[v.ID()]
|
to, toOK := p.indexOf[vid]
|
||||||
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
|
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
|
||||||
if u.ID() == v.ID() {
|
if uid == vid {
|
||||||
return []graph.Node{p.nodes[from]}, 0, true
|
return []graph.Node{p.nodes[from]}, 0, true
|
||||||
}
|
}
|
||||||
return nil, math.Inf(1), false
|
return nil, math.Inf(1), false
|
||||||
@@ -290,11 +290,11 @@ func (p AllShortest) Between(u, v graph.Node) (path []graph.Node, weight float64
|
|||||||
|
|
||||||
// AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
|
// AllBetween returns all shortest paths from u to v and the weight of the paths. Paths
|
||||||
// containing zero-weight cycles are not returned.
|
// containing zero-weight cycles are not returned.
|
||||||
func (p AllShortest) AllBetween(u, v graph.Node) (paths [][]graph.Node, weight float64) {
|
func (p AllShortest) AllBetween(uid, vid int64) (paths [][]graph.Node, weight float64) {
|
||||||
from, fromOK := p.indexOf[u.ID()]
|
from, fromOK := p.indexOf[uid]
|
||||||
to, toOK := p.indexOf[v.ID()]
|
to, toOK := p.indexOf[vid]
|
||||||
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
|
if !fromOK || !toOK || len(p.at(from, to)) == 0 {
|
||||||
if u.ID() == v.ID() {
|
if uid == vid {
|
||||||
return [][]graph.Node{{p.nodes[from]}}, 0
|
return [][]graph.Node{{p.nodes[from]}}, 0
|
||||||
}
|
}
|
||||||
return nil, math.Inf(1)
|
return nil, math.Inf(1)
|
||||||
@@ -302,9 +302,9 @@ func (p AllShortest) AllBetween(u, v graph.Node) (paths [][]graph.Node, weight f
|
|||||||
|
|
||||||
var n graph.Node
|
var n graph.Node
|
||||||
if p.forward {
|
if p.forward {
|
||||||
n = u
|
n = p.nodes[from]
|
||||||
} else {
|
} else {
|
||||||
n = v
|
n = p.nodes[to]
|
||||||
}
|
}
|
||||||
seen := make([]bool, len(p.nodes))
|
seen := make([]bool, len(p.nodes))
|
||||||
paths = p.allBetween(from, to, seen, []graph.Node{n}, nil)
|
paths = p.allBetween(from, to, seen, []graph.Node{n}, nil)
|
||||||
|
@@ -48,8 +48,9 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u := nodes[0]
|
u := nodes[0]
|
||||||
for _, v := range g.From(u) {
|
uid := u.ID()
|
||||||
w, ok := g.Weight(u, v)
|
for _, v := range g.From(uid) {
|
||||||
|
w, ok := g.Weight(uid, v.ID())
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("prim: unexpected invalid weight")
|
panic("prim: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
@@ -59,15 +60,16 @@ func Prim(dst WeightedBuilder, g graph.WeightedUndirected) float64 {
|
|||||||
var w float64
|
var w float64
|
||||||
for q.Len() > 0 {
|
for q.Len() > 0 {
|
||||||
e := heap.Pop(q).(simple.WeightedEdge)
|
e := heap.Pop(q).(simple.WeightedEdge)
|
||||||
if e.To() != nil && g.HasEdgeBetween(e.From(), e.To()) {
|
if e.To() != nil && g.HasEdgeBetween(e.From().ID(), e.To().ID()) {
|
||||||
dst.SetWeightedEdge(g.WeightedEdge(e.From(), e.To()))
|
dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID()))
|
||||||
w += e.Weight()
|
w += e.Weight()
|
||||||
}
|
}
|
||||||
|
|
||||||
u = e.From()
|
u = e.From()
|
||||||
for _, n := range g.From(u) {
|
uid := u.ID()
|
||||||
|
for _, n := range g.From(uid) {
|
||||||
if key, ok := q.key(n); ok {
|
if key, ok := q.key(n); ok {
|
||||||
w, ok := g.Weight(u, n)
|
w, ok := g.Weight(uid, n.ID())
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("prim: unexpected invalid weight")
|
panic("prim: unexpected invalid weight")
|
||||||
}
|
}
|
||||||
@@ -173,7 +175,7 @@ func Kruskal(dst WeightedBuilder, g UndirectedWeightLister) float64 {
|
|||||||
for _, e := range edges {
|
for _, e := range edges {
|
||||||
if s1, s2 := ds.find(e.From().ID()), ds.find(e.To().ID()); s1 != s2 {
|
if s1, s2 := ds.find(e.From().ID()), ds.find(e.To().ID()); s1 != s2 {
|
||||||
ds.union(s1, s2)
|
ds.union(s1, s2)
|
||||||
dst.SetWeightedEdge(g.WeightedEdge(e.From(), e.To()))
|
dst.SetWeightedEdge(g.WeightedEdge(e.From().ID(), e.To().ID()))
|
||||||
w += e.Weight()
|
w += e.Weight()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -268,7 +268,7 @@ func testMinumumSpanning(mst func(dst WeightedBuilder, g spanningGraph) float64,
|
|||||||
test.name, len(gotEdges), len(test.treeEdges))
|
test.name, len(gotEdges), len(test.treeEdges))
|
||||||
}
|
}
|
||||||
for _, e := range test.treeEdges {
|
for _, e := range test.treeEdges {
|
||||||
w, ok := dst.Weight(e.From(), e.To())
|
w, ok := dst.Weight(e.From().ID(), e.To().ID())
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Errorf("spanning tree edge not found in graph for %q: %+v",
|
t.Errorf("spanning tree edge not found in graph for %q: %+v",
|
||||||
test.name, e)
|
test.name, e)
|
||||||
|
@@ -12,18 +12,16 @@ import (
|
|||||||
|
|
||||||
// Weighting is a mapping between a pair of nodes and a weight. It follows the
|
// Weighting is a mapping between a pair of nodes and a weight. It follows the
|
||||||
// semantics of the Weighter interface.
|
// semantics of the Weighter interface.
|
||||||
type Weighting func(x, y graph.Node) (w float64, ok bool)
|
type Weighting func(xid, yid int64) (w float64, ok bool)
|
||||||
|
|
||||||
// UniformCost returns a Weighting that returns an edge cost of 1 for existing
|
// UniformCost returns a Weighting that returns an edge cost of 1 for existing
|
||||||
// edges, zero for node identity and Inf for otherwise absent edges.
|
// edges, zero for node identity and Inf for otherwise absent edges.
|
||||||
func UniformCost(g graph.Graph) Weighting {
|
func UniformCost(g graph.Graph) Weighting {
|
||||||
return func(x, y graph.Node) (w float64, ok bool) {
|
return func(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid {
|
if xid == yid {
|
||||||
return 0, true
|
return 0, true
|
||||||
}
|
}
|
||||||
if e := g.Edge(x, y); e != nil {
|
if e := g.Edge(xid, yid); e != nil {
|
||||||
return 1, true
|
return 1, true
|
||||||
}
|
}
|
||||||
return math.Inf(1), false
|
return math.Inf(1), false
|
||||||
|
@@ -75,8 +75,8 @@ func (g *DirectedMatrix) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *DirectedMatrix) Has(n graph.Node) bool {
|
func (g *DirectedMatrix) Has(id int64) bool {
|
||||||
return g.has(n.ID())
|
return g.has(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *DirectedMatrix) has(id int64) bool {
|
func (g *DirectedMatrix) has(id int64) bool {
|
||||||
@@ -117,8 +117,7 @@ func (g *DirectedMatrix) Edges() []graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *DirectedMatrix) From(n graph.Node) []graph.Node {
|
func (g *DirectedMatrix) From(id int64) []graph.Node {
|
||||||
id := n.ID()
|
|
||||||
if !g.has(id) {
|
if !g.has(id) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -137,8 +136,7 @@ func (g *DirectedMatrix) From(n graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// To returns all nodes in g that can reach directly to n.
|
// To returns all nodes in g that can reach directly to n.
|
||||||
func (g *DirectedMatrix) To(n graph.Node) []graph.Node {
|
func (g *DirectedMatrix) To(id int64) []graph.Node {
|
||||||
id := n.ID()
|
|
||||||
if !g.has(id) {
|
if !g.has(id) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -158,12 +156,10 @@ func (g *DirectedMatrix) To(n graph.Node) []graph.Node {
|
|||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||||
// considering direction.
|
// considering direction.
|
||||||
func (g *DirectedMatrix) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *DirectedMatrix) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
if !g.has(xid) {
|
if !g.has(xid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
yid := y.ID()
|
|
||||||
if !g.has(yid) {
|
if !g.has(yid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -173,27 +169,25 @@ func (g *DirectedMatrix) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *DirectedMatrix) Edge(u, v graph.Node) graph.Edge {
|
func (g *DirectedMatrix) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdge(u, v)
|
return g.WeightedEdge(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *DirectedMatrix) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *DirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
if g.HasEdgeFromTo(u, v) {
|
if g.HasEdgeFromTo(uid, vid) {
|
||||||
// x.ID() and y.ID() are not greater than maximum int by this point.
|
// xid and yid are not greater than maximum int by this point.
|
||||||
return WeightedEdge{F: g.Node(u.ID()), T: g.Node(v.ID()), W: g.mat.At(int(u.ID()), int(v.ID()))}
|
return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||||
func (g *DirectedMatrix) HasEdgeFromTo(u, v graph.Node) bool {
|
func (g *DirectedMatrix) HasEdgeFromTo(uid, vid int64) bool {
|
||||||
uid := u.ID()
|
|
||||||
if !g.has(uid) {
|
if !g.has(uid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
vid := v.ID()
|
|
||||||
if !g.has(vid) {
|
if !g.has(vid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -205,9 +199,7 @@ func (g *DirectedMatrix) HasEdgeFromTo(u, v graph.Node) bool {
|
|||||||
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
||||||
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g *DirectedMatrix) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g *DirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid {
|
if xid == yid {
|
||||||
return g.self, true
|
return g.self, true
|
||||||
}
|
}
|
||||||
@@ -262,8 +254,7 @@ func (g *DirectedMatrix) RemoveEdge(e graph.Edge) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the in+out degree of n in g.
|
// Degree returns the in+out degree of n in g.
|
||||||
func (g *DirectedMatrix) Degree(n graph.Node) int {
|
func (g *DirectedMatrix) Degree(id int64) int {
|
||||||
id := n.ID()
|
|
||||||
if !g.has(id) {
|
if !g.has(id) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@@ -75,8 +75,8 @@ func (g *UndirectedMatrix) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *UndirectedMatrix) Has(n graph.Node) bool {
|
func (g *UndirectedMatrix) Has(id int64) bool {
|
||||||
return g.has(n.ID())
|
return g.has(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *UndirectedMatrix) has(id int64) bool {
|
func (g *UndirectedMatrix) has(id int64) bool {
|
||||||
@@ -114,8 +114,7 @@ func (g *UndirectedMatrix) Edges() []graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *UndirectedMatrix) From(n graph.Node) []graph.Node {
|
func (g *UndirectedMatrix) From(id int64) []graph.Node {
|
||||||
id := n.ID()
|
|
||||||
if !g.has(id) {
|
if !g.has(id) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -134,12 +133,10 @@ func (g *UndirectedMatrix) From(n graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g *UndirectedMatrix) HasEdgeBetween(u, v graph.Node) bool {
|
func (g *UndirectedMatrix) HasEdgeBetween(uid, vid int64) bool {
|
||||||
uid := u.ID()
|
|
||||||
if !g.has(uid) {
|
if !g.has(uid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
vid := v.ID()
|
|
||||||
if !g.has(vid) {
|
if !g.has(vid) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -149,26 +146,26 @@ func (g *UndirectedMatrix) HasEdgeBetween(u, v graph.Node) bool {
|
|||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *UndirectedMatrix) Edge(u, v graph.Node) graph.Edge {
|
func (g *UndirectedMatrix) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *UndirectedMatrix) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *UndirectedMatrix) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y.
|
// EdgeBetween returns the edge between nodes x and y.
|
||||||
func (g *UndirectedMatrix) EdgeBetween(u, v graph.Node) graph.Edge {
|
func (g *UndirectedMatrix) EdgeBetween(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||||
func (g *UndirectedMatrix) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEdge {
|
func (g *UndirectedMatrix) WeightedEdgeBetween(uid, vid int64) graph.WeightedEdge {
|
||||||
if g.HasEdgeBetween(u, v) {
|
if g.HasEdgeBetween(uid, vid) {
|
||||||
// u.ID() and v.ID() are not greater than maximum int by this point.
|
// uid and vid are not greater than maximum int by this point.
|
||||||
return WeightedEdge{F: g.Node(u.ID()), T: g.Node(v.ID()), W: g.mat.At(int(u.ID()), int(v.ID()))}
|
return WeightedEdge{F: g.Node(uid), T: g.Node(vid), W: g.mat.At(int(uid), int(vid))}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -177,9 +174,7 @@ func (g *UndirectedMatrix) WeightedEdgeBetween(u, v graph.Node) graph.WeightedEd
|
|||||||
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
||||||
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g *UndirectedMatrix) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g *UndirectedMatrix) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid {
|
if xid == yid {
|
||||||
return g.self, true
|
return g.self, true
|
||||||
}
|
}
|
||||||
@@ -234,8 +229,7 @@ func (g *UndirectedMatrix) RemoveEdge(e graph.Edge) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the degree of n in g.
|
// Degree returns the degree of n in g.
|
||||||
func (g *UndirectedMatrix) Degree(n graph.Node) int {
|
func (g *UndirectedMatrix) Degree(id int64) int {
|
||||||
id := n.ID()
|
|
||||||
if !g.has(id) {
|
if !g.has(id) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@@ -34,17 +34,17 @@ func TestBasicDenseImpassable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
if !dg.Has(Node(i)) {
|
if !dg.Has(int64(i)) {
|
||||||
t.Errorf("Node that should exist doesn't: %d", i)
|
t.Errorf("Node that should exist doesn't: %d", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
if degree := dg.Degree(Node(i)); degree != 0 {
|
if degree := dg.Degree(int64(i)); degree != 0 {
|
||||||
t.Errorf("Node in impassable graph has a neighbor. Node: %d Degree: %d", i, degree)
|
t.Errorf("Node in impassable graph has a neighbor. Node: %d Degree: %d", i, degree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 5; i < 10; i++ {
|
for i := 5; i < 10; i++ {
|
||||||
if dg.Has(Node(i)) {
|
if dg.Has(int64(i)) {
|
||||||
t.Errorf("Node exists that shouldn't: %d", i)
|
t.Errorf("Node exists that shouldn't: %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,17 +57,17 @@ func TestBasicDensePassable(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
if !dg.Has(Node(i)) {
|
if !dg.Has(int64(i)) {
|
||||||
t.Errorf("Node that should exist doesn't: %d", i)
|
t.Errorf("Node that should exist doesn't: %d", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
if degree := dg.Degree(Node(i)); degree != 4 {
|
if degree := dg.Degree(int64(i)); degree != 4 {
|
||||||
t.Errorf("Node in passable graph missing neighbors. Node: %d Degree: %d", i, degree)
|
t.Errorf("Node in passable graph missing neighbors. Node: %d Degree: %d", i, degree)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 5; i < 10; i++ {
|
for i := 5; i < 10; i++ {
|
||||||
if dg.Has(Node(i)) {
|
if dg.Has(int64(i)) {
|
||||||
t.Errorf("Node exists that shouldn't: %d", i)
|
t.Errorf("Node exists that shouldn't: %d", i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,29 +77,29 @@ func TestDirectedDenseAddRemove(t *testing.T) {
|
|||||||
dg := NewDirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
|
dg := NewDirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
|
||||||
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 1})
|
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 1})
|
||||||
|
|
||||||
if neighbors := dg.From(Node(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||||
dg.Edge(Node(0), Node(2)) == nil {
|
dg.Edge(int64(0), int64(2)) == nil {
|
||||||
t.Errorf("Adding edge didn't create successor")
|
t.Errorf("Adding edge didn't create successor")
|
||||||
}
|
}
|
||||||
|
|
||||||
dg.RemoveEdge(Edge{F: Node(0), T: Node(2)})
|
dg.RemoveEdge(Edge{F: Node(0), T: Node(2)})
|
||||||
|
|
||||||
if neighbors := dg.From(Node(0)); len(neighbors) != 0 || dg.Edge(Node(0), Node(2)) != nil {
|
if neighbors := dg.From(int64(0)); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
|
||||||
t.Errorf("Removing edge didn't properly remove successor")
|
t.Errorf("Removing edge didn't properly remove successor")
|
||||||
}
|
}
|
||||||
|
|
||||||
if neighbors := dg.To(Node(2)); len(neighbors) != 0 || dg.Edge(Node(0), Node(2)) != nil {
|
if neighbors := dg.To(int64(2)); len(neighbors) != 0 || dg.Edge(int64(0), int64(2)) != nil {
|
||||||
t.Errorf("Removing directed edge wrongly kept predecessor")
|
t.Errorf("Removing directed edge wrongly kept predecessor")
|
||||||
}
|
}
|
||||||
|
|
||||||
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 2})
|
dg.SetWeightedEdge(WeightedEdge{F: Node(0), T: Node(2), W: 2})
|
||||||
// I figure we've torture tested From/To at this point
|
// I figure we've torture tested From/To at this point
|
||||||
// so we'll just use the bool functions now
|
// so we'll just use the bool functions now
|
||||||
if dg.Edge(Node(0), Node(2)) == nil {
|
if dg.Edge(int64(0), int64(2)) == nil {
|
||||||
t.Fatal("Adding directed edge didn't change successor back")
|
t.Fatal("Adding directed edge didn't change successor back")
|
||||||
}
|
}
|
||||||
c1, _ := dg.Weight(Node(2), Node(0))
|
c1, _ := dg.Weight(int64(2), int64(0))
|
||||||
c2, _ := dg.Weight(Node(0), Node(2))
|
c2, _ := dg.Weight(int64(0), int64(2))
|
||||||
if c1 == c2 {
|
if c1 == c2 {
|
||||||
t.Error("Adding directed edge affected cost in undirected manner")
|
t.Error("Adding directed edge affected cost in undirected manner")
|
||||||
}
|
}
|
||||||
@@ -109,13 +109,13 @@ func TestUndirectedDenseAddRemove(t *testing.T) {
|
|||||||
dg := NewUndirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
|
dg := NewUndirectedMatrix(10, math.Inf(1), 0, math.Inf(1))
|
||||||
dg.SetEdge(Edge{F: Node(0), T: Node(2)})
|
dg.SetEdge(Edge{F: Node(0), T: Node(2)})
|
||||||
|
|
||||||
if neighbors := dg.From(Node(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
if neighbors := dg.From(int64(0)); len(neighbors) != 1 || neighbors[0].ID() != 2 ||
|
||||||
dg.EdgeBetween(Node(0), Node(2)) == nil {
|
dg.EdgeBetween(int64(0), int64(2)) == nil {
|
||||||
t.Errorf("Couldn't add neighbor")
|
t.Errorf("Couldn't add neighbor")
|
||||||
}
|
}
|
||||||
|
|
||||||
if neighbors := dg.From(Node(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
|
if neighbors := dg.From(int64(2)); len(neighbors) != 1 || neighbors[0].ID() != 0 ||
|
||||||
dg.EdgeBetween(Node(2), Node(0)) == nil {
|
dg.EdgeBetween(int64(2), int64(0)) == nil {
|
||||||
t.Errorf("Adding an undirected neighbor didn't add it reciprocally")
|
t.Errorf("Adding an undirected neighbor didn't add it reciprocally")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -94,10 +94,10 @@ func (g *DirectedGraph) SetEdge(e graph.Edge) {
|
|||||||
panic("simple: adding self edge")
|
panic("simple: adding self edge")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !g.Has(from) {
|
if !g.Has(fid) {
|
||||||
g.AddNode(from)
|
g.AddNode(from)
|
||||||
}
|
}
|
||||||
if !g.Has(to) {
|
if !g.Has(tid) {
|
||||||
g.AddNode(to)
|
g.AddNode(to)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,8 +126,8 @@ func (g *DirectedGraph) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *DirectedGraph) Has(n graph.Node) bool {
|
func (g *DirectedGraph) Has(id int64) bool {
|
||||||
_, ok := g.nodes[n.ID()]
|
_, ok := g.nodes[id]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,30 +157,30 @@ func (g *DirectedGraph) Edges() []graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *DirectedGraph) From(n graph.Node) []graph.Node {
|
func (g *DirectedGraph) From(id int64) []graph.Node {
|
||||||
if _, ok := g.from[n.ID()]; !ok {
|
if _, ok := g.from[id]; !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
from := make([]graph.Node, len(g.from[n.ID()]))
|
from := make([]graph.Node, len(g.from[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for id := range g.from[n.ID()] {
|
for vid := range g.from[id] {
|
||||||
from[i] = g.nodes[id]
|
from[i] = g.nodes[vid]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return from
|
return from
|
||||||
}
|
}
|
||||||
|
|
||||||
// To returns all nodes in g that can reach directly to n.
|
// To returns all nodes in g that can reach directly to n.
|
||||||
func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
func (g *DirectedGraph) To(id int64) []graph.Node {
|
||||||
if _, ok := g.from[n.ID()]; !ok {
|
if _, ok := g.from[id]; !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
to := make([]graph.Node, len(g.to[n.ID()]))
|
to := make([]graph.Node, len(g.to[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for id := range g.to[n.ID()] {
|
for uid := range g.to[id] {
|
||||||
to[i] = g.nodes[id]
|
to[i] = g.nodes[uid]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return to
|
return to
|
||||||
@@ -188,9 +188,7 @@ func (g *DirectedGraph) To(n graph.Node) []graph.Node {
|
|||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||||
// considering direction.
|
// considering direction.
|
||||||
func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *DirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if _, ok := g.from[xid][yid]; ok {
|
if _, ok := g.from[xid][yid]; ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -200,8 +198,8 @@ func (g *DirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
func (g *DirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||||
edge, ok := g.from[u.ID()][v.ID()]
|
edge, ok := g.from[uid][vid]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -209,17 +207,17 @@ func (g *DirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||||
func (g *DirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
func (g *DirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||||
if _, ok := g.from[u.ID()][v.ID()]; !ok {
|
if _, ok := g.from[uid][vid]; !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the in+out degree of n in g.
|
// Degree returns the in+out degree of n in g.
|
||||||
func (g *DirectedGraph) Degree(n graph.Node) int {
|
func (g *DirectedGraph) Degree(id int64) int {
|
||||||
if _, ok := g.nodes[n.ID()]; !ok {
|
if _, ok := g.nodes[id]; !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return len(g.from[n.ID()]) + len(g.to[n.ID()])
|
return len(g.from[id]) + len(g.to[id])
|
||||||
}
|
}
|
||||||
|
@@ -21,7 +21,7 @@ var (
|
|||||||
func TestEdgeOvercounting(t *testing.T) {
|
func TestEdgeOvercounting(t *testing.T) {
|
||||||
g := generateDummyGraph()
|
g := generateDummyGraph()
|
||||||
|
|
||||||
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
|
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -86,10 +86,10 @@ func (g *UndirectedGraph) SetEdge(e graph.Edge) {
|
|||||||
panic("simple: adding self edge")
|
panic("simple: adding self edge")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !g.Has(from) {
|
if !g.Has(fid) {
|
||||||
g.AddNode(from)
|
g.AddNode(from)
|
||||||
}
|
}
|
||||||
if !g.Has(to) {
|
if !g.Has(tid) {
|
||||||
g.AddNode(to)
|
g.AddNode(to)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,8 +118,8 @@ func (g *UndirectedGraph) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *UndirectedGraph) Has(n graph.Node) bool {
|
func (g *UndirectedGraph) Has(id int64) bool {
|
||||||
_, ok := g.nodes[n.ID()]
|
_, ok := g.nodes[id]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,14 +160,14 @@ func (g *UndirectedGraph) Edges() []graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
|
func (g *UndirectedGraph) From(id int64) []graph.Node {
|
||||||
if !g.Has(n) {
|
if !g.Has(id) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes := make([]graph.Node, len(g.edges[n.ID()]))
|
nodes := make([]graph.Node, len(g.edges[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for from := range g.edges[n.ID()] {
|
for from := range g.edges[id] {
|
||||||
nodes[i] = g.nodes[from]
|
nodes[i] = g.nodes[from]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@@ -175,20 +175,20 @@ func (g *UndirectedGraph) From(n graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g *UndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *UndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||||
_, ok := g.edges[x.ID()][y.ID()]
|
_, ok := g.edges[xid][yid]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *UndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
func (g *UndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.EdgeBetween(u, v)
|
return g.EdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y.
|
// EdgeBetween returns the edge between nodes x and y.
|
||||||
func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
func (g *UndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||||
edge, ok := g.edges[x.ID()][y.ID()]
|
edge, ok := g.edges[xid][yid]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -196,9 +196,9 @@ func (g *UndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the degree of n in g.
|
// Degree returns the degree of n in g.
|
||||||
func (g *UndirectedGraph) Degree(n graph.Node) int {
|
func (g *UndirectedGraph) Degree(id int64) int {
|
||||||
if _, ok := g.nodes[n.ID()]; !ok {
|
if _, ok := g.nodes[id]; !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return len(g.edges[n.ID()])
|
return len(g.edges[id])
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,7 @@ func TestMaxID(t *testing.T) {
|
|||||||
delete(nodes, Node(2))
|
delete(nodes, Node(2))
|
||||||
n := g.NewNode()
|
n := g.NewNode()
|
||||||
g.AddNode(n)
|
g.AddNode(n)
|
||||||
if !g.Has(n) {
|
if !g.Has(n.ID()) {
|
||||||
t.Error("added node does not exist in graph")
|
t.Error("added node does not exist in graph")
|
||||||
}
|
}
|
||||||
if _, exists := nodes[n]; exists {
|
if _, exists := nodes[n]; exists {
|
||||||
|
@@ -100,10 +100,10 @@ func (g *WeightedDirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
|
|||||||
panic("simple: adding self edge")
|
panic("simple: adding self edge")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !g.Has(from) {
|
if !g.Has(fid) {
|
||||||
g.AddNode(from)
|
g.AddNode(from)
|
||||||
}
|
}
|
||||||
if !g.Has(to) {
|
if !g.Has(tid) {
|
||||||
g.AddNode(to)
|
g.AddNode(to)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,8 +132,8 @@ func (g *WeightedDirectedGraph) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *WeightedDirectedGraph) Has(n graph.Node) bool {
|
func (g *WeightedDirectedGraph) Has(id int64) bool {
|
||||||
_, ok := g.nodes[n.ID()]
|
_, ok := g.nodes[id]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,30 +174,30 @@ func (g *WeightedDirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *WeightedDirectedGraph) From(n graph.Node) []graph.Node {
|
func (g *WeightedDirectedGraph) From(id int64) []graph.Node {
|
||||||
if _, ok := g.from[n.ID()]; !ok {
|
if _, ok := g.from[id]; !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
from := make([]graph.Node, len(g.from[n.ID()]))
|
from := make([]graph.Node, len(g.from[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for id := range g.from[n.ID()] {
|
for vid := range g.from[id] {
|
||||||
from[i] = g.nodes[id]
|
from[i] = g.nodes[vid]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return from
|
return from
|
||||||
}
|
}
|
||||||
|
|
||||||
// To returns all nodes in g that can reach directly to n.
|
// To returns all nodes in g that can reach directly to n.
|
||||||
func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
|
func (g *WeightedDirectedGraph) To(id int64) []graph.Node {
|
||||||
if _, ok := g.from[n.ID()]; !ok {
|
if _, ok := g.from[id]; !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
to := make([]graph.Node, len(g.to[n.ID()]))
|
to := make([]graph.Node, len(g.to[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for id := range g.to[n.ID()] {
|
for uid := range g.to[id] {
|
||||||
to[i] = g.nodes[id]
|
to[i] = g.nodes[uid]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return to
|
return to
|
||||||
@@ -205,9 +205,7 @@ func (g *WeightedDirectedGraph) To(n graph.Node) []graph.Node {
|
|||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
// HasEdgeBetween returns whether an edge exists between nodes x and y without
|
||||||
// considering direction.
|
// considering direction.
|
||||||
func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *WeightedDirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if _, ok := g.from[xid][yid]; ok {
|
if _, ok := g.from[xid][yid]; ok {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -217,14 +215,14 @@ func (g *WeightedDirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
|||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *WeightedDirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
func (g *WeightedDirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdge(u, v)
|
return g.WeightedEdge(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *WeightedDirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
edge, ok := g.from[u.ID()][v.ID()]
|
edge, ok := g.from[uid][vid]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -232,8 +230,8 @@ func (g *WeightedDirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
// HasEdgeFromTo returns whether an edge exists in the graph from u to v.
|
||||||
func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
func (g *WeightedDirectedGraph) HasEdgeFromTo(uid, vid int64) bool {
|
||||||
if _, ok := g.from[u.ID()][v.ID()]; !ok {
|
if _, ok := g.from[uid][vid]; !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -243,9 +241,7 @@ func (g *WeightedDirectedGraph) HasEdgeFromTo(u, v graph.Node) bool {
|
|||||||
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
||||||
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g *WeightedDirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g *WeightedDirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid {
|
if xid == yid {
|
||||||
return g.self, true
|
return g.self, true
|
||||||
}
|
}
|
||||||
@@ -258,9 +254,9 @@ func (g *WeightedDirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the in+out degree of n in g.
|
// Degree returns the in+out degree of n in g.
|
||||||
func (g *WeightedDirectedGraph) Degree(n graph.Node) int {
|
func (g *WeightedDirectedGraph) Degree(id int64) int {
|
||||||
if _, ok := g.nodes[n.ID()]; !ok {
|
if _, ok := g.nodes[id]; !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return len(g.from[n.ID()]) + len(g.to[n.ID()])
|
return len(g.from[id]) + len(g.to[id])
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ var (
|
|||||||
func TestWeightedEdgeOvercounting(t *testing.T) {
|
func TestWeightedEdgeOvercounting(t *testing.T) {
|
||||||
g := generateDummyGraph()
|
g := generateDummyGraph()
|
||||||
|
|
||||||
if neigh := g.From(Node(Node(2))); len(neigh) != 2 {
|
if neigh := g.From(int64(2)); len(neigh) != 2 {
|
||||||
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
t.Errorf("Node 2 has incorrect number of neighbors got neighbors %v (count %d), expected 2 neighbors {0,1}", neigh, len(neigh))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -92,10 +92,10 @@ func (g *WeightedUndirectedGraph) SetWeightedEdge(e graph.WeightedEdge) {
|
|||||||
panic("simple: adding self edge")
|
panic("simple: adding self edge")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !g.Has(from) {
|
if !g.Has(fid) {
|
||||||
g.AddNode(from)
|
g.AddNode(from)
|
||||||
}
|
}
|
||||||
if !g.Has(to) {
|
if !g.Has(tid) {
|
||||||
g.AddNode(to)
|
g.AddNode(to)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,8 +124,8 @@ func (g *WeightedUndirectedGraph) Node(id int64) graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g *WeightedUndirectedGraph) Has(n graph.Node) bool {
|
func (g *WeightedUndirectedGraph) Has(id int64) bool {
|
||||||
_, ok := g.nodes[n.ID()]
|
_, ok := g.nodes[id]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,14 +185,14 @@ func (g *WeightedUndirectedGraph) WeightedEdges() []graph.WeightedEdge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from n.
|
// From returns all nodes in g that can be reached directly from n.
|
||||||
func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
|
func (g *WeightedUndirectedGraph) From(id int64) []graph.Node {
|
||||||
if !g.Has(n) {
|
if !g.Has(id) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
nodes := make([]graph.Node, len(g.edges[n.ID()]))
|
nodes := make([]graph.Node, len(g.edges[id]))
|
||||||
i := 0
|
i := 0
|
||||||
for from := range g.edges[n.ID()] {
|
for from := range g.edges[id] {
|
||||||
nodes[i] = g.nodes[from]
|
nodes[i] = g.nodes[from]
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
@@ -200,31 +200,31 @@ func (g *WeightedUndirectedGraph) From(n graph.Node) []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g *WeightedUndirectedGraph) HasEdgeBetween(x, y graph.Node) bool {
|
func (g *WeightedUndirectedGraph) HasEdgeBetween(xid, yid int64) bool {
|
||||||
_, ok := g.edges[x.ID()][y.ID()]
|
_, ok := g.edges[xid][yid]
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *WeightedUndirectedGraph) Edge(u, v graph.Node) graph.Edge {
|
func (g *WeightedUndirectedGraph) Edge(uid, vid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
func (g *WeightedUndirectedGraph) WeightedEdge(u, v graph.Node) graph.WeightedEdge {
|
func (g *WeightedUndirectedGraph) WeightedEdge(uid, vid int64) graph.WeightedEdge {
|
||||||
return g.WeightedEdgeBetween(u, v)
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y.
|
// EdgeBetween returns the edge between nodes x and y.
|
||||||
func (g *WeightedUndirectedGraph) EdgeBetween(x, y graph.Node) graph.Edge {
|
func (g *WeightedUndirectedGraph) EdgeBetween(xid, yid int64) graph.Edge {
|
||||||
return g.WeightedEdgeBetween(x, y)
|
return g.WeightedEdgeBetween(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
// WeightedEdgeBetween returns the weighted edge between nodes x and y.
|
||||||
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.WeightedEdge {
|
func (g *WeightedUndirectedGraph) WeightedEdgeBetween(xid, yid int64) graph.WeightedEdge {
|
||||||
edge, ok := g.edges[x.ID()][y.ID()]
|
edge, ok := g.edges[xid][yid]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -235,9 +235,7 @@ func (g *WeightedUndirectedGraph) WeightedEdgeBetween(x, y graph.Node) graph.Wei
|
|||||||
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
// If x and y are the same node or there is no joining edge between the two nodes the weight
|
||||||
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
// value returned is either the graph's absent or self value. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
func (g *WeightedUndirectedGraph) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
xid := x.ID()
|
|
||||||
yid := y.ID()
|
|
||||||
if xid == yid {
|
if xid == yid {
|
||||||
return g.self, true
|
return g.self, true
|
||||||
}
|
}
|
||||||
@@ -250,9 +248,9 @@ func (g *WeightedUndirectedGraph) Weight(x, y graph.Node) (w float64, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Degree returns the degree of n in g.
|
// Degree returns the degree of n in g.
|
||||||
func (g *WeightedUndirectedGraph) Degree(n graph.Node) int {
|
func (g *WeightedUndirectedGraph) Degree(id int64) int {
|
||||||
if _, ok := g.nodes[n.ID()]; !ok {
|
if _, ok := g.nodes[id]; !ok {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return len(g.edges[n.ID()])
|
return len(g.edges[id])
|
||||||
}
|
}
|
||||||
|
@@ -39,7 +39,7 @@ func TestWeightedMaxID(t *testing.T) {
|
|||||||
delete(nodes, Node(2))
|
delete(nodes, Node(2))
|
||||||
n := g.NewNode()
|
n := g.NewNode()
|
||||||
g.AddNode(n)
|
g.AddNode(n)
|
||||||
if !g.Has(n) {
|
if !g.Has(n.ID()) {
|
||||||
t.Error("added node does not exist in graph")
|
t.Error("added node does not exist in graph")
|
||||||
}
|
}
|
||||||
if _, exists := nodes[n]; exists {
|
if _, exists := nodes[n]; exists {
|
||||||
|
@@ -123,7 +123,7 @@ func twoSat(r io.Reader) (state map[string]bool, ok bool) {
|
|||||||
// Check for tautology.
|
// Check for tautology.
|
||||||
if variables[0].negated().ID() == variables[1].ID() {
|
if variables[0].negated().ID() == variables[1].ID() {
|
||||||
for _, v := range variables {
|
for _, v := range variables {
|
||||||
if !g.Has(v) {
|
if !g.Has(v.ID()) {
|
||||||
g.AddNode(v)
|
g.AddNode(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -60,9 +60,10 @@ func degeneracyOrdering(g graph.Undirected) (l []graph.Node, s []int) {
|
|||||||
neighbours = make(map[int64][]graph.Node)
|
neighbours = make(map[int64][]graph.Node)
|
||||||
)
|
)
|
||||||
for _, n := range nodes {
|
for _, n := range nodes {
|
||||||
adj := g.From(n)
|
id := n.ID()
|
||||||
neighbours[n.ID()] = adj
|
adj := g.From(id)
|
||||||
dv[n.ID()] = len(adj)
|
neighbours[id] = adj
|
||||||
|
dv[id] = len(adj)
|
||||||
if len(adj) > maxDegree {
|
if len(adj) > maxDegree {
|
||||||
maxDegree = len(adj)
|
maxDegree = len(adj)
|
||||||
}
|
}
|
||||||
@@ -146,7 +147,7 @@ func BronKerbosch(g graph.Undirected) [][]graph.Node {
|
|||||||
order, _ := degeneracyOrdering(g)
|
order, _ := degeneracyOrdering(g)
|
||||||
ordered.Reverse(order)
|
ordered.Reverse(order)
|
||||||
for _, v := range order {
|
for _, v := range order {
|
||||||
neighbours := g.From(v)
|
neighbours := g.From(v.ID())
|
||||||
nv := make(set.Nodes, len(neighbours))
|
nv := make(set.Nodes, len(neighbours))
|
||||||
for _, n := range neighbours {
|
for _, n := range neighbours {
|
||||||
nv.Add(n)
|
nv.Add(n)
|
||||||
@@ -175,7 +176,8 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
|
|||||||
if nu.Has(v) {
|
if nu.Has(v) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
neighbours := g.From(v)
|
vid := v.ID()
|
||||||
|
neighbours := g.From(vid)
|
||||||
nv := make(set.Nodes, len(neighbours))
|
nv := make(set.Nodes, len(neighbours))
|
||||||
for _, n := range neighbours {
|
for _, n := range neighbours {
|
||||||
nv.Add(n)
|
nv.Add(n)
|
||||||
@@ -183,7 +185,7 @@ func (bk *bronKerbosch) maximalCliquePivot(g graph.Undirected, r []graph.Node, p
|
|||||||
|
|
||||||
var found bool
|
var found bool
|
||||||
for _, n := range r {
|
for _, n := range r {
|
||||||
if n.ID() == v.ID() {
|
if n.ID() == vid {
|
||||||
found = true
|
found = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -205,10 +207,10 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
|
|||||||
// compile time option.
|
// compile time option.
|
||||||
if !tomitaTanakaTakahashi {
|
if !tomitaTanakaTakahashi {
|
||||||
for _, n := range p {
|
for _, n := range p {
|
||||||
return g.From(n)
|
return g.From(n.ID())
|
||||||
}
|
}
|
||||||
for _, n := range x {
|
for _, n := range x {
|
||||||
return g.From(n)
|
return g.From(n.ID())
|
||||||
}
|
}
|
||||||
panic("bronKerbosch: empty set")
|
panic("bronKerbosch: empty set")
|
||||||
}
|
}
|
||||||
@@ -220,7 +222,7 @@ func (*bronKerbosch) choosePivotFrom(g graph.Undirected, p, x set.Nodes) (neighb
|
|||||||
maxNeighbors := func(s set.Nodes) {
|
maxNeighbors := func(s set.Nodes) {
|
||||||
outer:
|
outer:
|
||||||
for _, u := range s {
|
for _, u := range s {
|
||||||
nb := g.From(u)
|
nb := g.From(u.ID())
|
||||||
c := len(nb)
|
c := len(nb)
|
||||||
if c <= max {
|
if c <= max {
|
||||||
continue
|
continue
|
||||||
|
@@ -53,7 +53,7 @@ func TestDegeneracyOrdering(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -93,7 +93,7 @@ func TestKCore(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -175,7 +175,7 @@ func TestBronKerbosch(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -92,7 +92,7 @@ func TestCliqueGraph(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -142,14 +142,15 @@ func johnsonGraphFrom(g graph.Directed) johnsonGraph {
|
|||||||
succ: make(map[int64]set.Int64s),
|
succ: make(map[int64]set.Int64s),
|
||||||
}
|
}
|
||||||
for i, u := range nodes {
|
for i, u := range nodes {
|
||||||
c.index[u.ID()] = i
|
uid := u.ID()
|
||||||
for _, v := range g.From(u) {
|
c.index[uid] = i
|
||||||
if c.succ[u.ID()] == nil {
|
for _, v := range g.From(uid) {
|
||||||
c.succ[u.ID()] = make(set.Int64s)
|
if c.succ[uid] == nil {
|
||||||
c.nodes.Add(u.ID())
|
c.succ[uid] = make(set.Int64s)
|
||||||
|
c.nodes.Add(uid)
|
||||||
}
|
}
|
||||||
c.nodes.Add(v.ID())
|
c.nodes.Add(v.ID())
|
||||||
c.succ[u.ID()].Add(v.ID())
|
c.succ[uid].Add(v.ID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c
|
return c
|
||||||
@@ -247,31 +248,31 @@ func (g johnsonGraph) Nodes() []graph.Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Successors is required to satisfy Tarjan.
|
// Successors is required to satisfy Tarjan.
|
||||||
func (g johnsonGraph) From(n graph.Node) []graph.Node {
|
func (g johnsonGraph) From(id int64) []graph.Node {
|
||||||
adj := g.succ[n.ID()]
|
adj := g.succ[id]
|
||||||
if len(adj) == 0 {
|
if len(adj) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
succ := make([]graph.Node, 0, len(adj))
|
succ := make([]graph.Node, 0, len(adj))
|
||||||
for n := range adj {
|
for id := range adj {
|
||||||
succ = append(succ, johnsonGraphNode(n))
|
succ = append(succ, johnsonGraphNode(id))
|
||||||
}
|
}
|
||||||
return succ
|
return succ
|
||||||
}
|
}
|
||||||
|
|
||||||
func (johnsonGraph) Has(graph.Node) bool {
|
func (johnsonGraph) Has(int64) bool {
|
||||||
panic("topo: unintended use of johnsonGraph")
|
panic("topo: unintended use of johnsonGraph")
|
||||||
}
|
}
|
||||||
func (johnsonGraph) HasEdgeBetween(_, _ graph.Node) bool {
|
func (johnsonGraph) HasEdgeBetween(_, _ int64) bool {
|
||||||
panic("topo: unintended use of johnsonGraph")
|
panic("topo: unintended use of johnsonGraph")
|
||||||
}
|
}
|
||||||
func (johnsonGraph) Edge(_, _ graph.Node) graph.Edge {
|
func (johnsonGraph) Edge(_, _ int64) graph.Edge {
|
||||||
panic("topo: unintended use of johnsonGraph")
|
panic("topo: unintended use of johnsonGraph")
|
||||||
}
|
}
|
||||||
func (johnsonGraph) HasEdgeFromTo(_, _ graph.Node) bool {
|
func (johnsonGraph) HasEdgeFromTo(_, _ int64) bool {
|
||||||
panic("topo: unintended use of johnsonGraph")
|
panic("topo: unintended use of johnsonGraph")
|
||||||
}
|
}
|
||||||
func (johnsonGraph) To(graph.Node) []graph.Node {
|
func (johnsonGraph) To(int64) []graph.Node {
|
||||||
panic("topo: unintended use of johnsonGraph")
|
panic("topo: unintended use of johnsonGraph")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -88,7 +88,7 @@ func TestDirectedCyclesIn(t *testing.T) {
|
|||||||
g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
|
g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -35,7 +35,7 @@ func UndirectedCyclesIn(g graph.Undirected) [][]graph.Node {
|
|||||||
u := tree.Pop()
|
u := tree.Pop()
|
||||||
uid := u.ID()
|
uid := u.ID()
|
||||||
adj := from[uid]
|
adj := from[uid]
|
||||||
for _, v := range g.From(u) {
|
for _, v := range g.From(uid) {
|
||||||
vid := v.ID()
|
vid := v.ID()
|
||||||
switch {
|
switch {
|
||||||
case uid == vid:
|
case uid == vid:
|
||||||
|
@@ -77,7 +77,7 @@ func TestUndirectedCyclesIn(t *testing.T) {
|
|||||||
g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
|
g.AddNode(simple.Node(-10)) // Make sure we test graphs with sparse IDs.
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -95,15 +95,15 @@ func TarjanSCC(g graph.Directed) [][]graph.Node {
|
|||||||
|
|
||||||
func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
|
func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.Node {
|
||||||
nodes := g.Nodes()
|
nodes := g.Nodes()
|
||||||
var succ func(graph.Node) []graph.Node
|
var succ func(id int64) []graph.Node
|
||||||
if order == nil {
|
if order == nil {
|
||||||
succ = g.From
|
succ = g.From
|
||||||
} else {
|
} else {
|
||||||
order(nodes)
|
order(nodes)
|
||||||
ordered.Reverse(nodes)
|
ordered.Reverse(nodes)
|
||||||
|
|
||||||
succ = func(n graph.Node) []graph.Node {
|
succ = func(id int64) []graph.Node {
|
||||||
to := g.From(n)
|
to := g.From(id)
|
||||||
order(to)
|
order(to)
|
||||||
ordered.Reverse(to)
|
ordered.Reverse(to)
|
||||||
return to
|
return to
|
||||||
@@ -131,7 +131,7 @@ func tarjanSCCstabilized(g graph.Directed, order func([]graph.Node)) [][]graph.N
|
|||||||
// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644
|
// http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm?oldid=642744644
|
||||||
//
|
//
|
||||||
type tarjan struct {
|
type tarjan struct {
|
||||||
succ func(graph.Node) []graph.Node
|
succ func(id int64) []graph.Node
|
||||||
|
|
||||||
index int
|
index int
|
||||||
indexTable map[int64]int
|
indexTable map[int64]int
|
||||||
@@ -156,7 +156,7 @@ func (t *tarjan) strongconnect(v graph.Node) {
|
|||||||
t.onStack.Add(vID)
|
t.onStack.Add(vID)
|
||||||
|
|
||||||
// Consider successors of v.
|
// Consider successors of v.
|
||||||
for _, w := range t.succ(v) {
|
for _, w := range t.succ(vID) {
|
||||||
wID := w.ID()
|
wID := w.ID()
|
||||||
if t.indexTable[wID] == 0 {
|
if t.indexTable[wID] == 0 {
|
||||||
// Successor w has not yet been visited; recur on it.
|
// Successor w has not yet been visited; recur on it.
|
||||||
|
@@ -132,7 +132,7 @@ func TestSort(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -163,7 +163,7 @@ func TestTarjanSCC(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -290,7 +290,7 @@ func TestSortStabilized(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
|
@@ -18,9 +18,9 @@ func IsPathIn(g graph.Graph, path []graph.Node) bool {
|
|||||||
case 0:
|
case 0:
|
||||||
return true
|
return true
|
||||||
case 1:
|
case 1:
|
||||||
return g.Has(path[0])
|
return g.Has(path[0].ID())
|
||||||
default:
|
default:
|
||||||
var canReach func(u, v graph.Node) bool
|
var canReach func(uid, vid int64) bool
|
||||||
switch g := g.(type) {
|
switch g := g.(type) {
|
||||||
case graph.Directed:
|
case graph.Directed:
|
||||||
canReach = g.HasEdgeFromTo
|
canReach = g.HasEdgeFromTo
|
||||||
@@ -29,7 +29,7 @@ func IsPathIn(g graph.Graph, path []graph.Node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, u := range path[:len(path)-1] {
|
for i, u := range path[:len(path)-1] {
|
||||||
if !canReach(u, path[i+1]) {
|
if !canReach(u.ID(), path[i+1].ID()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -71,11 +71,11 @@ func TestPathExistsInUndirected(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
|
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
if !g.Has(simple.Node(v)) {
|
if !g.Has(int64(v)) {
|
||||||
g.AddNode(simple.Node(v))
|
g.AddNode(simple.Node(v))
|
||||||
}
|
}
|
||||||
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||||
@@ -110,11 +110,11 @@ func TestPathExistsInDirected(t *testing.T) {
|
|||||||
g := simple.NewDirectedGraph()
|
g := simple.NewDirectedGraph()
|
||||||
|
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
if !g.Has(simple.Node(v)) {
|
if !g.Has(int64(v)) {
|
||||||
g.AddNode(simple.Node(v))
|
g.AddNode(simple.Node(v))
|
||||||
}
|
}
|
||||||
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||||
@@ -147,11 +147,11 @@ func TestConnectedComponents(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
|
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
if !g.Has(simple.Node(v)) {
|
if !g.Has(int64(v)) {
|
||||||
g.AddNode(simple.Node(v))
|
g.AddNode(simple.Node(v))
|
||||||
}
|
}
|
||||||
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||||
|
@@ -40,17 +40,19 @@ func (b *BreadthFirst) Walk(g graph.Graph, from graph.Node, until func(n graph.N
|
|||||||
if until != nil && until(t, depth) {
|
if until != nil && until(t, depth) {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
for _, n := range g.From(t) {
|
tid := t.ID()
|
||||||
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(t, n)) {
|
for _, n := range g.From(tid) {
|
||||||
|
nid := n.ID()
|
||||||
|
if b.EdgeFilter != nil && !b.EdgeFilter(g.Edge(tid, nid)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if b.visited.Has(n.ID()) {
|
if b.visited.Has(nid) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if b.Visit != nil {
|
if b.Visit != nil {
|
||||||
b.Visit(t, n)
|
b.Visit(t, n)
|
||||||
}
|
}
|
||||||
b.visited.Add(n.ID())
|
b.visited.Add(nid)
|
||||||
children++
|
children++
|
||||||
b.queue.Enqueue(n)
|
b.queue.Enqueue(n)
|
||||||
}
|
}
|
||||||
@@ -125,17 +127,19 @@ func (d *DepthFirst) Walk(g graph.Graph, from graph.Node, until func(graph.Node)
|
|||||||
if until != nil && until(t) {
|
if until != nil && until(t) {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
for _, n := range g.From(t) {
|
tid := t.ID()
|
||||||
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(t, n)) {
|
for _, n := range g.From(tid) {
|
||||||
|
nid := n.ID()
|
||||||
|
if d.EdgeFilter != nil && !d.EdgeFilter(g.Edge(tid, nid)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if d.visited.Has(n.ID()) {
|
if d.visited.Has(nid) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if d.Visit != nil {
|
if d.Visit != nil {
|
||||||
d.Visit(t, n)
|
d.Visit(t, n)
|
||||||
}
|
}
|
||||||
d.visited.Add(n.ID())
|
d.visited.Add(nid)
|
||||||
d.stack.Push(n)
|
d.stack.Push(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -136,7 +136,7 @@ func TestBreadthFirst(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -224,7 +224,7 @@ func TestDepthFirst(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
// Add nodes that are not defined by an edge.
|
// Add nodes that are not defined by an edge.
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
@@ -285,11 +285,11 @@ func TestWalkAll(t *testing.T) {
|
|||||||
g := simple.NewUndirectedGraph()
|
g := simple.NewUndirectedGraph()
|
||||||
|
|
||||||
for u, e := range test.g {
|
for u, e := range test.g {
|
||||||
if !g.Has(simple.Node(u)) {
|
if !g.Has(int64(u)) {
|
||||||
g.AddNode(simple.Node(u))
|
g.AddNode(simple.Node(u))
|
||||||
}
|
}
|
||||||
for v := range e {
|
for v := range e {
|
||||||
if !g.Has(simple.Node(v)) {
|
if !g.Has(int64(v)) {
|
||||||
g.AddNode(simple.Node(v))
|
g.AddNode(simple.Node(v))
|
||||||
}
|
}
|
||||||
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
g.SetEdge(simple.Edge{F: simple.Node(u), T: simple.Node(v)})
|
||||||
|
@@ -12,20 +12,20 @@ type Undirect struct {
|
|||||||
var _ Undirected = Undirect{}
|
var _ Undirected = Undirect{}
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g Undirect) Has(n Node) bool { return g.G.Has(n) }
|
func (g Undirect) Has(id int64) bool { return g.G.Has(id) }
|
||||||
|
|
||||||
// Nodes returns all the nodes in the graph.
|
// Nodes returns all the nodes in the graph.
|
||||||
func (g Undirect) Nodes() []Node { return g.G.Nodes() }
|
func (g Undirect) Nodes() []Node { return g.G.Nodes() }
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from u.
|
// From returns all nodes in g that can be reached directly from u.
|
||||||
func (g Undirect) From(u Node) []Node {
|
func (g Undirect) From(uid int64) []Node {
|
||||||
var nodes []Node
|
var nodes []Node
|
||||||
seen := make(map[int64]struct{})
|
seen := make(map[int64]struct{})
|
||||||
for _, n := range g.G.From(u) {
|
for _, n := range g.G.From(uid) {
|
||||||
seen[n.ID()] = struct{}{}
|
seen[n.ID()] = struct{}{}
|
||||||
nodes = append(nodes, n)
|
nodes = append(nodes, n)
|
||||||
}
|
}
|
||||||
for _, n := range g.G.To(u) {
|
for _, n := range g.G.To(uid) {
|
||||||
id := n.ID()
|
id := n.ID()
|
||||||
if _, ok := seen[id]; ok {
|
if _, ok := seen[id]; ok {
|
||||||
continue
|
continue
|
||||||
@@ -37,21 +37,21 @@ func (g Undirect) From(u Node) []Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g Undirect) HasEdgeBetween(x, y Node) bool { return g.G.HasEdgeBetween(x, y) }
|
func (g Undirect) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
|
||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
||||||
// the edge is determined by applying the Merge func to the weights of the
|
// the edge is determined by applying the Merge func to the weights of the
|
||||||
// edges between u and v.
|
// edges between u and v.
|
||||||
func (g Undirect) Edge(u, v Node) Edge { return g.EdgeBetween(u, v) }
|
func (g Undirect) Edge(uid, vid int64) Edge { return g.EdgeBetween(uid, vid) }
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
|
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
|
||||||
// Edge returned is an EdgePair. The weight of the edge is determined by
|
// Edge returned is an EdgePair. The weight of the edge is determined by
|
||||||
// applying the Merge func to the weights of edges between x and y.
|
// applying the Merge func to the weights of edges between x and y.
|
||||||
func (g Undirect) EdgeBetween(x, y Node) Edge {
|
func (g Undirect) EdgeBetween(xid, yid int64) Edge {
|
||||||
fe := g.G.Edge(x, y)
|
fe := g.G.Edge(xid, yid)
|
||||||
re := g.G.Edge(y, x)
|
re := g.G.Edge(yid, xid)
|
||||||
if fe == nil && re == nil {
|
if fe == nil && re == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -91,20 +91,20 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Has returns whether the node exists within the graph.
|
// Has returns whether the node exists within the graph.
|
||||||
func (g UndirectWeighted) Has(n Node) bool { return g.G.Has(n) }
|
func (g UndirectWeighted) Has(id int64) bool { return g.G.Has(id) }
|
||||||
|
|
||||||
// Nodes returns all the nodes in the graph.
|
// Nodes returns all the nodes in the graph.
|
||||||
func (g UndirectWeighted) Nodes() []Node { return g.G.Nodes() }
|
func (g UndirectWeighted) Nodes() []Node { return g.G.Nodes() }
|
||||||
|
|
||||||
// From returns all nodes in g that can be reached directly from u.
|
// From returns all nodes in g that can be reached directly from u.
|
||||||
func (g UndirectWeighted) From(u Node) []Node {
|
func (g UndirectWeighted) From(uid int64) []Node {
|
||||||
var nodes []Node
|
var nodes []Node
|
||||||
seen := make(map[int64]struct{})
|
seen := make(map[int64]struct{})
|
||||||
for _, n := range g.G.From(u) {
|
for _, n := range g.G.From(uid) {
|
||||||
seen[n.ID()] = struct{}{}
|
seen[n.ID()] = struct{}{}
|
||||||
nodes = append(nodes, n)
|
nodes = append(nodes, n)
|
||||||
}
|
}
|
||||||
for _, n := range g.G.To(u) {
|
for _, n := range g.G.To(uid) {
|
||||||
id := n.ID()
|
id := n.ID()
|
||||||
if _, ok := seen[id]; ok {
|
if _, ok := seen[id]; ok {
|
||||||
continue
|
continue
|
||||||
@@ -116,44 +116,46 @@ func (g UndirectWeighted) From(u Node) []Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
||||||
func (g UndirectWeighted) HasEdgeBetween(x, y Node) bool { return g.G.HasEdgeBetween(x, y) }
|
func (g UndirectWeighted) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
|
||||||
|
|
||||||
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
// Edge returns the edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
||||||
// the edge is determined by applying the Merge func to the weights of the
|
// the edge is determined by applying the Merge func to the weights of the
|
||||||
// edges between u and v.
|
// edges between u and v.
|
||||||
func (g UndirectWeighted) Edge(u, v Node) Edge { return g.WeightedEdgeBetween(u, v) }
|
func (g UndirectWeighted) Edge(uid, vid int64) Edge { return g.WeightedEdgeBetween(uid, vid) }
|
||||||
|
|
||||||
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
// WeightedEdge returns the weighted edge from u to v if such an edge exists and nil otherwise.
|
||||||
// The node v must be directly reachable from u as defined by the From method.
|
// The node v must be directly reachable from u as defined by the From method.
|
||||||
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
||||||
// the edge is determined by applying the Merge func to the weights of the
|
// the edge is determined by applying the Merge func to the weights of the
|
||||||
// edges between u and v.
|
// edges between u and v.
|
||||||
func (g UndirectWeighted) WeightedEdge(u, v Node) WeightedEdge { return g.WeightedEdgeBetween(u, v) }
|
func (g UndirectWeighted) WeightedEdge(uid, vid int64) WeightedEdge {
|
||||||
|
return g.WeightedEdgeBetween(uid, vid)
|
||||||
|
}
|
||||||
|
|
||||||
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
|
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
|
||||||
// Edge returned is an EdgePair. The weight of the edge is determined by
|
// Edge returned is an EdgePair. The weight of the edge is determined by
|
||||||
// applying the Merge func to the weights of edges between x and y.
|
// applying the Merge func to the weights of edges between x and y.
|
||||||
func (g UndirectWeighted) EdgeBetween(x, y Node) Edge {
|
func (g UndirectWeighted) EdgeBetween(xid, yid int64) Edge {
|
||||||
return g.WeightedEdgeBetween(x, y)
|
return g.WeightedEdgeBetween(xid, yid)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WeightedEdgeBetween returns the weighted edge between nodes x and y. If an edge exists, the
|
// WeightedEdgeBetween returns the weighted edge between nodes x and y. If an edge exists, the
|
||||||
// Edge returned is an EdgePair. The weight of the edge is determined by
|
// Edge returned is an EdgePair. The weight of the edge is determined by
|
||||||
// applying the Merge func to the weights of edges between x and y.
|
// applying the Merge func to the weights of edges between x and y.
|
||||||
func (g UndirectWeighted) WeightedEdgeBetween(x, y Node) WeightedEdge {
|
func (g UndirectWeighted) WeightedEdgeBetween(xid, yid int64) WeightedEdge {
|
||||||
fe := g.G.Edge(x, y)
|
fe := g.G.Edge(xid, yid)
|
||||||
re := g.G.Edge(y, x)
|
re := g.G.Edge(yid, xid)
|
||||||
if fe == nil && re == nil {
|
if fe == nil && re == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
f, ok := g.G.Weight(x, y)
|
f, ok := g.G.Weight(xid, yid)
|
||||||
if !ok {
|
if !ok {
|
||||||
f = g.Absent
|
f = g.Absent
|
||||||
}
|
}
|
||||||
r, ok := g.G.Weight(y, x)
|
r, ok := g.G.Weight(yid, xid)
|
||||||
if !ok {
|
if !ok {
|
||||||
r = g.Absent
|
r = g.Absent
|
||||||
}
|
}
|
||||||
@@ -171,15 +173,15 @@ func (g UndirectWeighted) WeightedEdgeBetween(x, y Node) WeightedEdge {
|
|||||||
// If x and y are the same node the internal node weight is returned. If there is no joining
|
// If x and y are the same node the internal node weight is returned. If there is no joining
|
||||||
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
||||||
// exists between x and y or if x and y have the same ID, false otherwise.
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
||||||
func (g UndirectWeighted) Weight(x, y Node) (w float64, ok bool) {
|
func (g UndirectWeighted) Weight(xid, yid int64) (w float64, ok bool) {
|
||||||
fe := g.G.Edge(x, y)
|
fe := g.G.Edge(xid, yid)
|
||||||
re := g.G.Edge(y, x)
|
re := g.G.Edge(yid, xid)
|
||||||
|
|
||||||
f, fOk := g.G.Weight(x, y)
|
f, fOk := g.G.Weight(xid, yid)
|
||||||
if !fOk {
|
if !fOk {
|
||||||
f = g.Absent
|
f = g.Absent
|
||||||
}
|
}
|
||||||
r, rOK := g.G.Weight(y, x)
|
r, rOK := g.G.Weight(yid, xid)
|
||||||
if !rOK {
|
if !rOK {
|
||||||
r = g.Absent
|
r = g.Absent
|
||||||
}
|
}
|
||||||
|
@@ -123,8 +123,8 @@ func TestUndirect(t *testing.T) {
|
|||||||
src := graph.Undirect{G: g}
|
src := graph.Undirect{G: g}
|
||||||
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
|
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
|
||||||
for _, u := range src.Nodes() {
|
for _, u := range src.Nodes() {
|
||||||
for _, v := range src.From(u) {
|
for _, v := range src.From(u.ID()) {
|
||||||
dst.SetEdge(src.Edge(u, v))
|
dst.SetEdge(src.Edge(u.ID(), v.ID()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,8 +148,8 @@ func TestUndirectWeighted(t *testing.T) {
|
|||||||
src := graph.UndirectWeighted{G: g, Absent: test.absent, Merge: test.merge}
|
src := graph.UndirectWeighted{G: g, Absent: test.absent, Merge: test.merge}
|
||||||
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
|
dst := simple.NewUndirectedMatrixFrom(src.Nodes(), 0, 0, 0)
|
||||||
for _, u := range src.Nodes() {
|
for _, u := range src.Nodes() {
|
||||||
for _, v := range src.From(u) {
|
for _, v := range src.From(u.ID()) {
|
||||||
dst.SetWeightedEdge(src.WeightedEdge(u, v))
|
dst.SetWeightedEdge(src.WeightedEdge(u.ID(), v.ID()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user