github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/common/graph/choose.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 "math/big" 10 11 type orderedSet struct { 12 elements []interface{} 13 } 14 15 func (s *orderedSet) add(o interface{}) { 16 s.elements = append(s.elements, o) 17 } 18 19 type indiceSet struct { 20 indices []int 21 } 22 23 type indiceSets []*indiceSet 24 25 // CombinationsExceed computes the number of combinations 26 // of choosing K elements from N elements, and returns 27 // whether the number of combinations exceeds a given threshold. 28 // If n < k then it returns false. 29 func CombinationsExceed(n, k, threshold int) bool { 30 if n < k { 31 return false 32 } 33 combinations := &big.Int{} 34 combinations = combinations.Binomial(int64(n), int64(k)) 35 t := &big.Int{} 36 t.SetInt64(int64(threshold)) 37 return combinations.Cmp(t) > 0 38 } 39 40 func chooseKoutOfN(n, k int) indiceSets { 41 var res indiceSets 42 subGroups := &orderedSet{} 43 choose(n, k, 0, nil, subGroups) 44 for _, el := range subGroups.elements { 45 res = append(res, el.(*indiceSet)) 46 } 47 return res 48 } 49 50 func choose(n int, targetAmount int, i int, currentSubGroup []int, subGroups *orderedSet) { 51 // Check if we have enough elements in our current subgroup 52 if len(currentSubGroup) == targetAmount { 53 subGroups.add(&indiceSet{indices: currentSubGroup}) 54 return 55 } 56 // Return early if not enough remaining candidates to pick from 57 itemsLeftToPick := n - i 58 if targetAmount-len(currentSubGroup) > itemsLeftToPick { 59 return 60 } 61 // We either pick the current element 62 choose(n, targetAmount, i+1, append(currentSubGroup, i), subGroups) 63 // Or don't pick it 64 choose(n, targetAmount, i+1, currentSubGroup, subGroups) 65 }