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  }