github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/common/graph/perm.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 import ( 10 "math/rand" 11 "time" 12 ) 13 14 func init() { 15 rand.Seed(time.Now().UnixNano()) 16 } 17 18 // treePermutations represents possible permutations 19 // of a tree 20 type treePermutations struct { 21 combinationUpperBound int // The upper bound of combinations of direct descendants. 22 originalRoot *TreeVertex // The root vertex of all sub-trees 23 permutations []*TreeVertex // The accumulated permutations 24 descendantPermutations map[*TreeVertex][][]*TreeVertex // Defines the combinations of sub-trees based on the threshold of the current vertex 25 } 26 27 // newTreePermutation creates a new treePermutations object with a given root vertex 28 func newTreePermutation(root *TreeVertex, combinationUpperBound int) *treePermutations { 29 return &treePermutations{ 30 combinationUpperBound: combinationUpperBound, 31 descendantPermutations: make(map[*TreeVertex][][]*TreeVertex), 32 originalRoot: root, 33 permutations: []*TreeVertex{root}, 34 } 35 } 36 37 // permute returns Trees that their vertices and edges all exist in the original tree who's vertex 38 // is the 'originalRoot' field of the treePermutations 39 func (tp *treePermutations) permute() []*Tree { 40 tp.computeDescendantPermutations() 41 42 it := newBFSIterator(tp.originalRoot) 43 for { 44 v := it.Next() 45 if v == nil { 46 break 47 } 48 49 if len(v.Descendants) == 0 { 50 continue 51 } 52 53 // Iterate over all permutations where v exists 54 // and separate them to 2 sets: a indiceSet where it exists and a indiceSet where it doesn't 55 var permutationsWhereVexists []*TreeVertex 56 var permutationsWhereVdoesntExist []*TreeVertex 57 for _, perm := range tp.permutations { 58 if perm.Exists(v.Id) { 59 permutationsWhereVexists = append(permutationsWhereVexists, perm) 60 } else { 61 permutationsWhereVdoesntExist = append(permutationsWhereVdoesntExist, perm) 62 } 63 } 64 65 // Remove the permutations where v exists from the permutations 66 tp.permutations = permutationsWhereVdoesntExist 67 68 // Next, we replace each occurrence of a permutation where v exists, 69 // with multiple occurrences of its descendants permutations 70 for _, perm := range permutationsWhereVexists { 71 // For each permutation of v's descendants, clone the graph 72 // and create a new graph with v replaced with the permutated graph 73 // of v connected to the descendant permutation 74 for _, permutation := range tp.descendantPermutations[v] { 75 subGraph := &TreeVertex{ 76 Id: v.Id, 77 Data: v.Data, 78 Descendants: permutation, 79 } 80 newTree := perm.Clone() 81 newTree.replace(v.Id, subGraph) 82 // Add the new option to the permutations 83 tp.permutations = append(tp.permutations, newTree) 84 } 85 } 86 } 87 88 res := make([]*Tree, len(tp.permutations)) 89 for i, perm := range tp.permutations { 90 res[i] = perm.ToTree() 91 } 92 return res 93 } 94 95 // computeDescendantPermutations computes all possible combinations of sub-trees 96 // for all vertices, based on the thresholds. 97 func (tp *treePermutations) computeDescendantPermutations() { 98 it := newBFSIterator(tp.originalRoot) 99 for { 100 v := it.Next() 101 if v == nil { 102 return 103 } 104 105 // Skip leaves 106 if len(v.Descendants) == 0 { 107 continue 108 } 109 110 // Ensure we don't have too much combinations of descendants 111 for CombinationsExceed(len(v.Descendants), v.Threshold, tp.combinationUpperBound) { 112 // Randomly pick a descendant, and remove it 113 victim := rand.Intn(len(v.Descendants)) 114 v.Descendants = append(v.Descendants[:victim], v.Descendants[victim+1:]...) 115 } 116 117 // Iterate over all options of selecting the threshold out of the descendants 118 for _, el := range chooseKoutOfN(len(v.Descendants), v.Threshold) { 119 // And for each such option, append it to the current TreeVertex 120 tp.descendantPermutations[v] = append(tp.descendantPermutations[v], v.selectDescendants(el.indices)) 121 } 122 } 123 } 124 125 // selectDescendants returns a subset of descendants according to given indices 126 func (v *TreeVertex) selectDescendants(indices []int) []*TreeVertex { 127 r := make([]*TreeVertex, len(indices)) 128 i := 0 129 for _, index := range indices { 130 r[i] = v.Descendants[index] 131 i++ 132 } 133 return r 134 }