github.com/hyperledger-labs/bdls@v2.1.1+incompatible/common/graph/tree.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package graph
     8  
     9  // Iterator defines an iterator that can be used to traverse vertices
    10  // of a graph
    11  type Iterator interface {
    12  	// Next returns the next element in the iteration order,
    13  	// or nil if there is no such an element
    14  	Next() *TreeVertex
    15  }
    16  
    17  // TreeVertex defines a vertex of a tree
    18  type TreeVertex struct {
    19  	Id          string        // id identifies uniquely the TreeVertex in the Tree
    20  	Data        interface{}   // data holds arbitrary data, to be used by the user of the package
    21  	Descendants []*TreeVertex // descendants are the vertices that this TreeVertex is their parent in the tree
    22  	Threshold   int           // threshold symbols the count of sub-trees / leaves to pick when creating tree permutations
    23  }
    24  
    25  // NewTreeVertex creates a new vertex with a given unique id and a given arbitrary data
    26  func NewTreeVertex(id string, data interface{}, descendants ...*TreeVertex) *TreeVertex {
    27  	return &TreeVertex{
    28  		Id:          id,
    29  		Data:        data,
    30  		Descendants: descendants,
    31  	}
    32  }
    33  
    34  // IsLeaf returns whether the given vertex is a leaf
    35  func (v *TreeVertex) IsLeaf() bool {
    36  	return len(v.Descendants) == 0
    37  }
    38  
    39  // AddDescendant creates a new vertex who's parent is the invoker vertex,
    40  // with a given id and data. Returns the new vertex
    41  func (v *TreeVertex) AddDescendant(u *TreeVertex) *TreeVertex {
    42  	v.Descendants = append(v.Descendants, u)
    43  	return u
    44  }
    45  
    46  // ToTree creates a Tree who's root vertex is the current vertex
    47  func (v *TreeVertex) ToTree() *Tree {
    48  	return &Tree{
    49  		Root: v,
    50  	}
    51  }
    52  
    53  // Find searches for a vertex who's id is the given id.
    54  // Returns the first vertex it finds with such an Id, or nil if not found
    55  func (v *TreeVertex) Find(id string) *TreeVertex {
    56  	if v.Id == id {
    57  		return v
    58  	}
    59  	for _, u := range v.Descendants {
    60  		if r := u.Find(id); r != nil {
    61  			return r
    62  		}
    63  	}
    64  	return nil
    65  }
    66  
    67  // Exists searches for a vertex who's id is the given id,
    68  // and returns whether such a vertex was found or not.
    69  func (v *TreeVertex) Exists(id string) bool {
    70  	return v.Find(id) != nil
    71  }
    72  
    73  // Clone clones the tree who's root vertex is the current vertex.
    74  func (v *TreeVertex) Clone() *TreeVertex {
    75  	var descendants []*TreeVertex
    76  	for _, u := range v.Descendants {
    77  		descendants = append(descendants, u.Clone())
    78  	}
    79  	copy := &TreeVertex{
    80  		Id:          v.Id,
    81  		Descendants: descendants,
    82  		Data:        v.Data,
    83  	}
    84  	return copy
    85  }
    86  
    87  // replace replaces the sub-tree of the vertex who's id is the given id
    88  // with a sub-tree who's root vertex is r.
    89  func (v *TreeVertex) replace(id string, r *TreeVertex) {
    90  	if v.Id == id {
    91  		v.Descendants = r.Descendants
    92  		return
    93  	}
    94  	for _, u := range v.Descendants {
    95  		u.replace(id, r)
    96  	}
    97  }
    98  
    99  // Tree defines a Tree of vertices of type TreeVertex
   100  type Tree struct {
   101  	Root *TreeVertex
   102  }
   103  
   104  // Permute returns Trees that their vertices and edges all exist in the original tree.
   105  // The permutations are calculated according to the thresholds of all vertices.
   106  // The combinationUpperBound is an upper bound of possible combinations of direct descendants
   107  // of a vertex. If the vertex has a threshold and descendants that result a number of combinations
   108  // that exceeds the given combinationUpperBound, the descendants are pruned until the number of
   109  // combinations is lower than the combinationUpperBound.
   110  // This is done in order to cap the memory usage of the computed result.
   111  func (t *Tree) Permute(combinationUpperBound int) []*Tree {
   112  	return newTreePermutation(t.Root, combinationUpperBound).permute()
   113  }
   114  
   115  // BFS returns an iterator that iterates the vertices
   116  // in a Breadth-First-Search order
   117  func (t *Tree) BFS() Iterator {
   118  	return newBFSIterator(t.Root)
   119  }
   120  
   121  type bfsIterator struct {
   122  	*queue
   123  }
   124  
   125  func newBFSIterator(v *TreeVertex) *bfsIterator {
   126  	return &bfsIterator{
   127  		queue: &queue{
   128  			arr: []*TreeVertex{v},
   129  		},
   130  	}
   131  }
   132  
   133  // Next returns the next element in the iteration order,
   134  // or nil if there is no such an element
   135  func (bfs *bfsIterator) Next() *TreeVertex {
   136  	if len(bfs.arr) == 0 {
   137  		return nil
   138  	}
   139  	v := bfs.dequeue()
   140  	for _, u := range v.Descendants {
   141  		bfs.enqueue(u)
   142  	}
   143  	return v
   144  }
   145  
   146  // a primitive implementation of a queue backed by a slice
   147  type queue struct {
   148  	arr []*TreeVertex
   149  }
   150  
   151  func (q *queue) enqueue(v *TreeVertex) {
   152  	q.arr = append(q.arr, v)
   153  }
   154  
   155  func (q *queue) dequeue() *TreeVertex {
   156  	v := q.arr[0]
   157  	q.arr = q.arr[1:]
   158  	return v
   159  }