gonum.org/v1/gonum@v0.14.0/stat/combin/combin_test.go (about) 1 // Copyright ©2016 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package combin 6 7 import ( 8 "math/big" 9 "reflect" 10 "strconv" 11 "testing" 12 "unsafe" 13 14 "gonum.org/v1/gonum/floats/scalar" 15 ) 16 17 // intSosMatch returns true if the two slices of slices are equal. 18 func intSosMatch(a, b [][]int) bool { 19 if len(a) != len(b) { 20 return false 21 } 22 for i, s := range a { 23 if len(s) != len(b[i]) { 24 return false 25 } 26 for j, v := range s { 27 if v != b[i][j] { 28 return false 29 } 30 } 31 } 32 return true 33 } 34 35 var binomialTests = []struct { 36 n, k, ans int 37 }{ 38 {0, 0, 1}, 39 {5, 0, 1}, 40 {5, 1, 5}, 41 {5, 2, 10}, 42 {5, 3, 10}, 43 {5, 4, 5}, 44 {5, 5, 1}, 45 46 {6, 0, 1}, 47 {6, 1, 6}, 48 {6, 2, 15}, 49 {6, 3, 20}, 50 {6, 4, 15}, 51 {6, 5, 6}, 52 {6, 6, 1}, 53 54 {20, 0, 1}, 55 {20, 1, 20}, 56 {20, 2, 190}, 57 {20, 3, 1140}, 58 {20, 4, 4845}, 59 {20, 5, 15504}, 60 {20, 6, 38760}, 61 {20, 7, 77520}, 62 {20, 8, 125970}, 63 {20, 9, 167960}, 64 {20, 10, 184756}, 65 {20, 11, 167960}, 66 {20, 12, 125970}, 67 {20, 13, 77520}, 68 {20, 14, 38760}, 69 {20, 15, 15504}, 70 {20, 16, 4845}, 71 {20, 17, 1140}, 72 {20, 18, 190}, 73 {20, 19, 20}, 74 {20, 20, 1}, 75 } 76 77 func TestBinomial(t *testing.T) { 78 for cas, test := range binomialTests { 79 ans := Binomial(test.n, test.k) 80 if ans != test.ans { 81 t.Errorf("Case %v: Binomial mismatch. Got %v, want %v.", cas, ans, test.ans) 82 } 83 } 84 var ( 85 // Ensure that we have enough space to represent results. 86 // TODO(kortschak): Replace the unsafe.Sizeof(int(0)) expression with 87 // sizeof.Int if https://github.com/golang/go/issues/29982 is 88 // implemented. See also https://github.com/golang/go/issues/40168. 89 n = int(unsafe.Sizeof(int(0))*8 - 3) 90 91 want big.Int 92 got big.Int 93 ) 94 for k := 0; k <= n; k++ { 95 want.Binomial(int64(n), int64(k)) 96 got.SetInt64(int64(Binomial(n, k))) 97 if want.Cmp(&got) != 0 { 98 t.Errorf("Case n=%v,k=%v: Binomial mismatch for large n. Got %v, want %v.", n, k, got, want) 99 } 100 } 101 } 102 103 func TestGeneralizedBinomial(t *testing.T) { 104 for cas, test := range binomialTests { 105 ans := GeneralizedBinomial(float64(test.n), float64(test.k)) 106 if !scalar.EqualWithinAbsOrRel(ans, float64(test.ans), 1e-14, 1e-14) { 107 t.Errorf("Case %v: Binomial mismatch. Got %v, want %v.", cas, ans, test.ans) 108 } 109 } 110 } 111 112 func TestCombinations(t *testing.T) { 113 for cas, test := range []struct { 114 n, k int 115 data [][]int 116 }{ 117 { 118 n: 1, 119 k: 1, 120 data: [][]int{{0}}, 121 }, 122 { 123 n: 2, 124 k: 1, 125 data: [][]int{{0}, {1}}, 126 }, 127 { 128 n: 2, 129 k: 2, 130 data: [][]int{{0, 1}}, 131 }, 132 { 133 n: 3, 134 k: 1, 135 data: [][]int{{0}, {1}, {2}}, 136 }, 137 { 138 n: 3, 139 k: 2, 140 data: [][]int{{0, 1}, {0, 2}, {1, 2}}, 141 }, 142 { 143 n: 3, 144 k: 3, 145 data: [][]int{{0, 1, 2}}, 146 }, 147 { 148 n: 4, 149 k: 1, 150 data: [][]int{{0}, {1}, {2}, {3}}, 151 }, 152 { 153 n: 4, 154 k: 2, 155 data: [][]int{{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}}, 156 }, 157 { 158 n: 4, 159 k: 3, 160 data: [][]int{{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}}, 161 }, 162 { 163 n: 4, 164 k: 4, 165 data: [][]int{{0, 1, 2, 3}}, 166 }, 167 } { 168 data := Combinations(test.n, test.k) 169 if !intSosMatch(data, test.data) { 170 t.Errorf("Cas %v: Generated combinations mismatch. Got %v, want %v.", cas, data, test.data) 171 } 172 } 173 } 174 175 func TestCombinationGenerator(t *testing.T) { 176 for n := 0; n <= 10; n++ { 177 for k := 1; k <= n; k++ { 178 combinations := Combinations(n, k) 179 cg := NewCombinationGenerator(n, k) 180 genCombs := make([][]int, 0, len(combinations)) 181 for cg.Next() { 182 genCombs = append(genCombs, cg.Combination(nil)) 183 } 184 if !intSosMatch(combinations, genCombs) { 185 t.Errorf("Combinations and generated combinations do not match. n = %v, k = %v", n, k) 186 } 187 } 188 } 189 } 190 191 func TestCombinationIndex(t *testing.T) { 192 for cas, s := range []struct { 193 n, k int 194 }{ 195 {6, 3}, 196 {4, 4}, 197 {10, 1}, 198 {8, 2}, 199 } { 200 n := s.n 201 k := s.k 202 combs := make(map[string]struct{}) 203 for i := 0; i < Binomial(n, k); i++ { 204 comb := IndexToCombination(nil, i, n, k) 205 idx := CombinationIndex(comb, n, k) 206 if idx != i { 207 t.Errorf("Cas %d: combination mismatch. Want %d, got %d", cas, i, idx) 208 } 209 combs[intSliceToKey(comb)] = struct{}{} 210 } 211 if len(combs) != Binomial(n, k) { 212 t.Errorf("Case %d: not all generated combinations were unique", cas) 213 } 214 } 215 } 216 217 func intSliceToKey(s []int) string { 218 var str string 219 for _, v := range s { 220 str += strconv.Itoa(v) + "_" 221 } 222 return str 223 } 224 225 // TestCombinationOrder tests that the different Combinations methods 226 // agree on the iteration order. 227 func TestCombinationOrder(t *testing.T) { 228 n := 7 229 k := 3 230 list := Combinations(n, k) 231 for i, v := range list { 232 idx := CombinationIndex(v, n, k) 233 if idx != i { 234 t.Errorf("Combinations and CombinationIndex mismatch") 235 break 236 } 237 } 238 } 239 240 func TestIdxSubFor(t *testing.T) { 241 for cas, dims := range [][]int{ 242 {2, 2}, 243 {3, 1, 6}, 244 {2, 4, 6, 7}, 245 } { 246 // Loop over all of the indexes. Confirm that the subscripts make sense 247 // and that IdxFor is the converse of SubFor. 248 maxIdx := 1 249 for _, v := range dims { 250 maxIdx *= v 251 } 252 into := make([]int, len(dims)) 253 for idx := 0; idx < maxIdx; idx++ { 254 sub := SubFor(nil, idx, dims) 255 for i := range sub { 256 if sub[i] < 0 || sub[i] >= dims[i] { 257 t.Errorf("cas %v: bad subscript. dims: %v, sub: %v", cas, dims, sub) 258 } 259 } 260 SubFor(into, idx, dims) 261 if !reflect.DeepEqual(sub, into) { 262 t.Errorf("cas %v: subscript mismatch with supplied slice. Got %v, want %v", cas, into, sub) 263 } 264 idxOut := IdxFor(sub, dims) 265 if idxOut != idx { 266 t.Errorf("cas %v: returned index mismatch. Got %v, want %v", cas, idxOut, idx) 267 } 268 } 269 } 270 } 271 272 func TestCartesian(t *testing.T) { 273 // First, test with a known return. 274 lens := []int{2, 3, 4} 275 want := [][]int{ 276 {0, 0, 0}, 277 {0, 0, 1}, 278 {0, 0, 2}, 279 {0, 0, 3}, 280 {0, 1, 0}, 281 {0, 1, 1}, 282 {0, 1, 2}, 283 {0, 1, 3}, 284 {0, 2, 0}, 285 {0, 2, 1}, 286 {0, 2, 2}, 287 {0, 2, 3}, 288 {1, 0, 0}, 289 {1, 0, 1}, 290 {1, 0, 2}, 291 {1, 0, 3}, 292 {1, 1, 0}, 293 {1, 1, 1}, 294 {1, 1, 2}, 295 {1, 1, 3}, 296 {1, 2, 0}, 297 {1, 2, 1}, 298 {1, 2, 2}, 299 {1, 2, 3}, 300 } 301 got := Cartesian(lens) 302 if !intSosMatch(want, got) { 303 t.Errorf("Cartesian data mismatch.\nwant:\n%v\ngot:\n%v", want, got) 304 } 305 } 306 307 func TestNumCartesianProducts(t *testing.T) { 308 want := 6 309 got := Card([]int{1, 2, 3}) 310 if want != got { 311 t.Errorf("number of Cartesian products mismatch.\nwant:\n%v\ngot:\n%v", want, got) 312 } 313 } 314 315 func TestCartesianGenerator(t *testing.T) { 316 want := [][]int{ 317 {0, 0, 0}, 318 {0, 0, 1}, 319 {0, 0, 2}, 320 {0, 1, 0}, 321 {0, 1, 1}, 322 {0, 1, 2}, 323 } 324 gen := NewCartesianGenerator([]int{1, 2, 3}) 325 iterations := 0 326 for gen.Next() { 327 got := gen.Product(nil) 328 if !reflect.DeepEqual(got, want[iterations]) { 329 t.Errorf("Cartesian product does not match. want: %v got: %v", want[iterations], got) 330 } 331 iterations++ 332 } 333 334 if iterations != len(want) { 335 t.Errorf("Number of products does not match. want: %v got: %v", len(want), iterations) 336 } 337 } 338 339 func TestPermutationIndex(t *testing.T) { 340 for cas, s := range []struct { 341 n, k int 342 }{ 343 {6, 3}, 344 {4, 4}, 345 {10, 1}, 346 {8, 2}, 347 } { 348 n := s.n 349 k := s.k 350 perms := make(map[string]struct{}) 351 for i := 0; i < NumPermutations(n, k); i++ { 352 perm := IndexToPermutation(nil, i, n, k) 353 idx := PermutationIndex(perm, n, k) 354 if idx != i { 355 t.Errorf("Cas %d: permutation mismatch. Want %d, got %d", cas, i, idx) 356 } 357 perms[intSliceToKey(perm)] = struct{}{} 358 } 359 if len(perms) != NumPermutations(n, k) { 360 t.Errorf("Case %d: not all generated combinations were unique", cas) 361 } 362 } 363 } 364 365 func TestPermutationGenerator(t *testing.T) { 366 for n := 0; n <= 7; n++ { 367 for k := 1; k <= n; k++ { 368 permutations := Permutations(n, k) 369 pg := NewPermutationGenerator(n, k) 370 genPerms := make([][]int, 0, len(permutations)) 371 for pg.Next() { 372 genPerms = append(genPerms, pg.Permutation(nil)) 373 } 374 if !intSosMatch(permutations, genPerms) { 375 t.Errorf("Permutations and generated permutations do not match. n = %v, k = %v", n, k) 376 } 377 } 378 } 379 }