1// Copyright 2014 Sonia Keys 2// License MIT: http://opensource.org/licenses/MIT 3 4package graph 5 6import "github.com/soniakeys/bits" 7 8// FromList represents a rooted tree (or forest) where each node is associated 9// with a half arc identifying an arc "from" another node. 10// 11// Other terms for this data structure include "parent list", 12// "predecessor list", "in-tree", "inverse arborescence", and 13// "spaghetti stack." 14// 15// The Paths member represents the tree structure. Leaves and MaxLen are 16// not always needed. Where Leaves is used it serves as a bitmap where 17// Leaves.Bit(n) == 1 for each leaf n of the tree. Where MaxLen is used it is 18// provided primarily as a convenience for functions that might want to 19// anticipate the maximum path length that would be encountered traversing 20// the tree. 21// 22// Various graph search methods use a FromList to returns search results. 23// For a start node of a search, From will be -1 and Len will be 1. For other 24// nodes reached by the search, From represents a half arc in a path back to 25// start and Len represents the number of nodes in the path. For nodes not 26// reached by the search, From will be -1 and Len will be 0. 27// 28// A single FromList can also represent a forest. In this case paths from 29// all leaves do not return to a single root node, but multiple root nodes. 30// 31// While a FromList generally encodes a tree or forest, it is technically 32// possible to encode a cyclic graph. A number of FromList methods require 33// the receiver to be acyclic. Graph methods documented to return a tree or 34// forest will never return a cyclic FromList. In other cases however, 35// where a FromList is not known to by cyclic, the Cyclic method can be 36// useful to validate the acyclic property. 37type FromList struct { 38 Paths []PathEnd // tree representation 39 Leaves bits.Bits // leaves of tree 40 MaxLen int // length of longest path, max of all PathEnd.Len values 41} 42 43// PathEnd associates a half arc and a path length. 44// 45// A PathEnd list is an element type of FromList. 46type PathEnd struct { 47 From NI // a "from" half arc, the node the arc comes from 48 Len int // number of nodes in path from start 49} 50 51/* NewFromList could be confusing now with bits also needing allocation. 52maybe best to not have this function. Maybe a more useful new would be 53one that took a PathEnd slice and intitialized everything including roots 54and max len. Maybe its time for a separate []PathEnd type when that's 55all that's needed. (and reconsider the name PathEnd) 56*/ 57 58// NewFromList creates a FromList object of given order. 59// 60// The Paths member is allocated to the specified order n but other members 61// are left as zero values. 62func NewFromList(n int) FromList { 63 return FromList{Paths: make([]PathEnd, n)} 64} 65 66// BoundsOk validates the "from" values in the list. 67// 68// Negative values are allowed as they indicate root nodes. 69// 70// BoundsOk returns true when all from values are less than len(t). 71// Otherwise it returns false and a node with a from value >= len(t). 72func (f FromList) BoundsOk() (ok bool, n NI) { 73 for n, e := range f.Paths { 74 if int(e.From) >= len(f.Paths) { 75 return false, NI(n) 76 } 77 } 78 return true, -1 79} 80 81// CommonStart returns the common start node of minimal paths to a and b. 82// 83// It returns -1 if a and b cannot be traced back to a common node. 84// 85// The method relies on populated PathEnd.Len members. Use RecalcLen if 86// the Len members are not known to be present and correct. 87func (f FromList) CommonStart(a, b NI) NI { 88 p := f.Paths 89 if p[a].Len < p[b].Len { 90 a, b = b, a 91 } 92 for bl := p[b].Len; p[a].Len > bl; { 93 a = p[a].From 94 if a < 0 { 95 return -1 96 } 97 } 98 for a != b { 99 a = p[a].From 100 if a < 0 { 101 return -1 102 } 103 b = p[b].From 104 } 105 return a 106} 107 108// Cyclic determines if f contains a cycle, a non-empty path from a node 109// back to itself. 110// 111// Cyclic returns true if g contains at least one cycle. It also returns 112// an example of a node involved in a cycle. 113// 114// Cyclic returns (false, -1) in the normal case where f is acyclic. 115// Note that the bool is not an "ok" return. A cyclic FromList is usually 116// not okay. 117func (f FromList) Cyclic() (cyclic bool, n NI) { 118 p := f.Paths 119 vis := bits.New(len(p)) 120 for i := range p { 121 path := bits.New(len(p)) 122 for n := i; vis.Bit(n) == 0; { 123 vis.SetBit(n, 1) 124 path.SetBit(n, 1) 125 if n = int(p[n].From); n < 0 { 126 break 127 } 128 if path.Bit(n) == 1 { 129 return true, NI(n) 130 } 131 } 132 } 133 return false, -1 134} 135 136// IsolatedNodeBits returns a bitmap of isolated nodes in receiver graph f. 137// 138// An isolated node is one with no arcs going to or from it. 139func (f FromList) IsolatedNodes() (iso bits.Bits) { 140 p := f.Paths 141 iso = bits.New(len(p)) 142 iso.SetAll() 143 for n, e := range p { 144 if e.From >= 0 { 145 iso.SetBit(n, 0) 146 iso.SetBit(int(e.From), 0) 147 } 148 } 149 return 150} 151 152// PathTo decodes a FromList, recovering a single path. 153// 154// The path is returned as a list of nodes where the first element will be 155// a root node and the last element will be the specified end node. 156// 157// Only the Paths member of the receiver is used. Other members of the 158// FromList do not need to be valid, however the MaxLen member can be useful 159// for allocating argument p. 160// 161// Argument p can provide the result slice. If p has capacity for the result 162// it will be used, otherwise a new slice is created for the result. 163// 164// See also function PathTo. 165func (f FromList) PathTo(end NI, p []NI) []NI { 166 return PathTo(f.Paths, end, p) 167} 168 169// PathTo decodes a single path from a PathEnd list. 170// 171// A PathEnd list is the main data representation in a FromList. See FromList. 172// 173// PathTo returns a list of nodes where the first element will be 174// a root node and the last element will be the specified end node. 175// 176// Argument p can provide the result slice. If p has capacity for the result 177// it will be used, otherwise a new slice is created for the result. 178// 179// See also method FromList.PathTo. 180func PathTo(paths []PathEnd, end NI, p []NI) []NI { 181 n := paths[end].Len 182 if n == 0 { 183 return p[:0] 184 } 185 if cap(p) >= n { 186 p = p[:n] 187 } else { 188 p = make([]NI, n) 189 } 190 for { 191 n-- 192 p[n] = end 193 if n == 0 { 194 return p 195 } 196 end = paths[end].From 197 } 198} 199 200// PathToLabeled decodes a FromList, recovering a single path. 201// 202// The start of the returned path will be a root node of the FromList. 203// 204// Only the Paths member of the receiver is used. Other members of the 205// FromList do not need to be valid, however the MaxLen member can be useful 206// for allocating argument p. 207// 208// Argument p can provide the result slice. If p has capacity for the result 209// it will be used, otherwise a new slice is created for the result. 210// 211// See also function PathTo. 212func (f FromList) PathToLabeled(end NI, labels []LI, p []Half) LabeledPath { 213 n := f.Paths[end].Len - 1 214 if n <= 0 { 215 return LabeledPath{end, p[:0]} 216 } 217 if cap(p) >= n { 218 p = p[:n] 219 } else { 220 p = make([]Half, n) 221 } 222 for { 223 n-- 224 p[n] = Half{To: end, Label: labels[end]} 225 end = f.Paths[end].From 226 if n == 0 { 227 return LabeledPath{end, p} 228 } 229 } 230} 231 232// Preorder traverses a FromList in preorder. 233// 234// Nodes are visited in order such that for any node n with from node fr, 235// fr is visited before n. Where f represents a tree, the visit ordering 236// corresponds to a preordering, or depth first traversal of the tree. 237// Where f represents a forest, the preorderings of the trees can be 238// intermingled. 239// 240// Leaves must be set correctly first. Use RecalcLeaves if leaves are not 241// known to be set correctly. FromList f cannot be cyclic. 242// 243// Traversal continues while visitor function v returns true. It terminates 244// if v returns false. Preorder returns true if it completes without v 245// returning false. Preorder returns false if traversal is terminated by v 246// returning false. 247func (f FromList) Preorder(v func(NI) bool) bool { 248 p := f.Paths 249 done := bits.New(len(p)) 250 var df func(NI) bool 251 df = func(n NI) bool { 252 done.SetBit(int(n), 1) 253 if fr := p[n].From; fr >= 0 && done.Bit(int(fr)) == 0 { 254 df(fr) 255 } 256 return v(n) 257 } 258 for n := range f.Paths { 259 p[n].Len = 0 260 } 261 return f.Leaves.IterateOnes(func(n int) bool { 262 return df(NI(n)) 263 }) 264} 265 266// RecalcLeaves recomputes the Leaves member of f. 267func (f *FromList) RecalcLeaves() { 268 p := f.Paths 269 lv := &f.Leaves 270 if lv.Num != len(p) { 271 *lv = bits.New(len(p)) 272 } 273 lv.SetAll() 274 for n := range f.Paths { 275 if fr := p[n].From; fr >= 0 { 276 lv.SetBit(int(fr), 0) 277 } 278 } 279} 280 281// RecalcLen recomputes Len for each path end, and recomputes MaxLen. 282// 283// RecalcLen relies on the Leaves member being valid. If it is not known 284// to be valid, call RecalcLeaves before calling RecalcLen. 285// 286// RecalcLen will panic if the FromList is cyclic. Use the Cyclic method 287// if needed to verify that the FromList is acyclic. 288func (f *FromList) RecalcLen() { 289 p := f.Paths 290 var setLen func(NI) int 291 setLen = func(n NI) int { 292 switch { 293 case p[n].Len > 0: 294 return p[n].Len 295 case p[n].From < 0: 296 p[n].Len = 1 297 return 1 298 } 299 l := 1 + setLen(p[n].From) 300 p[n].Len = l 301 return l 302 } 303 for n := range f.Paths { 304 p[n].Len = 0 305 } 306 f.MaxLen = 0 307 f.Leaves.IterateOnes(func(n int) bool { 308 if l := setLen(NI(n)); l > f.MaxLen { 309 f.MaxLen = l 310 } 311 return true 312 }) 313} 314 315// ReRoot reorients the tree containing n to make n the root node. 316// 317// It keeps the tree connected by "reversing" the path from n to the old root. 318// 319// After ReRoot, the Leaves and Len members are invalid. 320// Call RecalcLeaves or RecalcLen as needed. 321func (f *FromList) ReRoot(n NI) { 322 p := f.Paths 323 fr := p[n].From 324 if fr < 0 { 325 return 326 } 327 p[n].From = -1 328 for { 329 ff := p[fr].From 330 p[fr].From = n 331 if ff < 0 { 332 return 333 } 334 n = fr 335 fr = ff 336 } 337} 338 339// Root finds the root of a node in a FromList. 340func (f FromList) Root(n NI) NI { 341 for p := f.Paths; ; { 342 fr := p[n].From 343 if fr < 0 { 344 return n 345 } 346 n = fr 347 } 348} 349 350// Transpose constructs the directed graph corresponding to FromList f 351// but with arcs in the opposite direction. That is, from roots toward leaves. 352// 353// If non-nil argrument roots is passed, Transpose populates it as roots of 354// the resulting forest and returns nRoots as a count of the roots. 355// 356// The method relies only on the From member of f.Paths. Other members of 357// the FromList are not used. 358func (f FromList) Transpose(roots *bits.Bits) (forest Directed, nRoots int) { 359 p := f.Paths 360 g := make(AdjacencyList, len(p)) 361 if roots != nil { 362 nRoots = len(p) 363 if roots.Num != nRoots { 364 *roots = bits.New(nRoots) 365 } 366 roots.SetAll() 367 } 368 for i, e := range p { 369 if e.From == -1 { 370 continue 371 } 372 g[e.From] = append(g[e.From], NI(i)) 373 if roots != nil && roots.Bit(i) == 1 { 374 roots.SetBit(i, 0) 375 nRoots-- 376 } 377 } 378 return Directed{g}, nRoots 379} 380 381// TransposeLabeled constructs the labeled directed graph corresponding 382// to FromList f but with arcs in the opposite direction. That is, from 383// roots toward leaves. 384// 385// The argument labels can be nil. In this case labels are generated matching 386// the path indexes. This corresponds to the "to", or child node. 387// 388// If labels is non-nil, it must be the same length as t.Paths and is used 389// to look up label numbers by the path index. 390// 391// If non-nil argrument roots is passed, Transpose populates it as roots of 392// the resulting forest and returns nRoots as a count of the roots. 393// 394// The method relies only on the From member of f.Paths. Other members of 395// the FromList are not used. 396func (f FromList) TransposeLabeled(labels []LI, roots *bits.Bits) (forest LabeledDirected, nRoots int) { 397 p := f.Paths 398 g := make(LabeledAdjacencyList, len(p)) 399 if roots != nil { 400 nRoots = len(p) 401 if roots.Num != nRoots { 402 *roots = bits.New(nRoots) 403 } 404 roots.SetAll() 405 } 406 for i, p := range f.Paths { 407 if p.From == -1 { 408 continue 409 } 410 l := LI(i) 411 if labels != nil { 412 l = labels[i] 413 } 414 g[p.From] = append(g[p.From], Half{NI(i), l}) 415 if roots != nil && roots.Bit(i) == 1 { 416 roots.SetBit(i, 0) 417 nRoots-- 418 } 419 } 420 return LabeledDirected{g}, nRoots 421} 422 423// Undirected constructs the undirected graph corresponding to FromList f. 424// 425// The resulting graph will be a tree or forest. 426// 427// If non-nil argrument roots is passed, Transpose populates it as roots of 428// the resulting forest and returns nRoots as a count of the roots. 429// 430// The method relies only on the From member of f.Paths. Other members of 431// the FromList are not used. 432func (f FromList) Undirected(roots *bits.Bits) (forest Undirected, nRoots int) { 433 p := f.Paths 434 g := make(AdjacencyList, len(p)) 435 if roots != nil { 436 nRoots = len(p) 437 if roots.Num != nRoots { 438 *roots = bits.New(nRoots) 439 } 440 roots.SetAll() 441 } 442 for i, e := range p { 443 if e.From == -1 { 444 continue 445 } 446 g[i] = append(g[i], e.From) 447 g[e.From] = append(g[e.From], NI(i)) 448 if roots != nil && roots.Bit(i) == 1 { 449 roots.SetBit(i, 0) 450 nRoots-- 451 } 452 } 453 return Undirected{g}, nRoots 454} 455 456// LabeledUndirected constructs the labeled undirected graph corresponding 457// to FromList f. 458// 459// The resulting graph will be a tree or forest. 460// 461// The argument labels can be nil. In this case labels are generated matching 462// the path indexes. This corresponds to the "to", or child node. 463// 464// If labels is non-nil, it must be the same length as t.Paths and is used 465// to look up label numbers by the path index. 466// 467// If non-nil argrument roots is passed, LabeledUndirected populates it as 468// roots of the resulting forest and returns nRoots as a count of the roots. 469// 470// The method relies only on the From member of f.Paths. Other members of 471// the FromList are not used. 472func (f FromList) LabeledUndirected(labels []LI, roots *bits.Bits) (forest LabeledUndirected, nRoots int) { 473 p := f.Paths 474 g := make(LabeledAdjacencyList, len(p)) 475 if roots != nil { 476 nRoots = len(p) 477 if roots.Num != nRoots { 478 *roots = bits.New(nRoots) 479 } 480 roots.SetAll() 481 } 482 for i, p := range f.Paths { 483 if p.From == -1 { 484 continue 485 } 486 l := LI(i) 487 if labels != nil { 488 l = labels[i] 489 } 490 g[i] = append(g[i], Half{p.From, l}) 491 g[p.From] = append(g[p.From], Half{NI(i), l}) 492 if roots != nil && roots.Bit(i) == 1 { 493 roots.SetBit(i, 0) 494 nRoots-- 495 } 496 } 497 return LabeledUndirected{g}, nRoots 498} 499