@@ -405,8 +405,7 @@ the generator's range:
405405 bytes /1 , bytes_s /2 ,
406406 jump /0 , jump /1 ,
407407 normal /0 , normal /2 , normal_s /1 , normal_s /3 ,
408- shuffle1 /1 , shuffle1_s /2 , shuffle2 /1 , shuffle2_s /2 ,
409- shuffle3 /1 , shuffle3_s /2 , shuffle4 /1 , shuffle4_s /2
408+ shuffle /1 , shuffle_s /2
410409 ]).
411410
412411% % Utilities
@@ -1317,16 +1316,15 @@ normal_s(Mean, Variance, State0) when 0 =< Variance ->
13171316 {X , State } = normal_s (State0 ),
13181317 {Mean + (math :sqrt (Variance ) * X ), State }.
13191318
1320- % % -------
13211319
1322- -spec shuffle1 (list ()) -> list ().
1323- shuffle1 (List ) ->
1324- {ShuffledList , State } = shuffle1_s (List , seed_get ()),
1320+ -spec shuffle (list ()) -> list ().
1321+ shuffle (List ) ->
1322+ {ShuffledList , State } = shuffle_s (List , seed_get ()),
13251323 _ = seed_put (State ),
13261324 ShuffledList .
13271325
1328- -spec shuffle1_s (list (), state ()) -> {list (), state ()}.
1329- shuffle1_s (List , {#{bits := _ , next := Next } = AlgHandler , R0 } = State )
1326+ -spec shuffle_s (list (), state ()) -> {list (), state ()}.
1327+ shuffle_s (List , {#{bits := _ , next := Next } = AlgHandler , R0 } = State )
13301328 when is_list (List ) ->
13311329 case List of
13321330 [] ->
@@ -1335,10 +1333,10 @@ shuffle1_s(List, {#{bits:=_, next:=Next} = AlgHandler, R0} = State)
13351333 {List , State };
13361334 _ ->
13371335 WeakLowBits = maps :get (weak_low_bits , AlgHandler , 0 ),
1338- {ShuffledList , R1 } = shuffle1_r (List , Next , R0 , WeakLowBits , []),
1336+ {ShuffledList , R1 } = shuffle_r (List , Next , R0 , WeakLowBits , []),
13391337 {ShuffledList , {AlgHandler , R1 }}
13401338 end ;
1341- shuffle1_s (List , {#{max := Mask , next := Next } = AlgHandler , R0 } = State )
1339+ shuffle_s (List , {#{max := Mask , next := Next } = AlgHandler , R0 } = State )
13421340 when is_list (List ), ? MASK (58 ) =< Mask ->
13431341 case List of
13441342 [] ->
@@ -1348,7 +1346,7 @@ shuffle1_s(List, {#{max:=Mask, next:=Next} = AlgHandler, R0} = State)
13481346 _ ->
13491347 % % Old spec - assume 2 weak low bits
13501348 WeakLowBits = 2 ,
1351- {ShuffledList , R1 } = shuffle1_r (List , Next , R0 , WeakLowBits , []),
1349+ {ShuffledList , R1 } = shuffle_r (List , Next , R0 , WeakLowBits , []),
13521350 {ShuffledList , {AlgHandler , R1 }}
13531351 end .
13541352
@@ -1360,204 +1358,42 @@ shuffle1_s(List, {#{max:=Mask, next:=Next} = AlgHandler, R0} = State)
13601358% % produces a bias free shuffle.
13611359
13621360% % Recursion entry point
1363- shuffle1_r ([X , Y ], Next , R0 , _WeakLowBits , Acc ) ->
1361+ shuffle_r ([X , Y ], Next , R0 , _WeakLowBits , Acc ) ->
13641362 % % Optimization for 2 elements; the most common case for duplicates
13651363 {V , R1 } = Next (R0 ),
13661364 if
13671365 % % Bit 7 should not be weak in any of the generators
13681366 V band 128 =:= 0 -> {[Y , X | Acc ], R1 };
13691367 true -> {[X , Y | Acc ], R1 }
13701368 end ;
1371- shuffle1_r (L , Next , R0 , WeakLowBits , Acc ) ->
1372- shuffle1_tag (L , Next , R0 , WeakLowBits , Acc , []).
1369+ shuffle_r (L , Next , R0 , WeakLowBits , Acc ) ->
1370+ shuffle_tag (L , Next , R0 , WeakLowBits , Acc , []).
13731371
13741372% % Tag elements with random integers
1375- shuffle1_tag ([], Next , R , WeakLowBits , Acc , TL ) ->
1376- % % Shuffle1 ; sort by random tag
1377- shuffle1_untag (lists :keysort (1 , TL ), Next , R , WeakLowBits , Acc );
1378- shuffle1_tag ([X | L ], Next , R0 , WeakLowBits , Acc , TL ) ->
1373+ shuffle_tag ([], Next , R , WeakLowBits , Acc , TL ) ->
1374+ % % Shuffle ; sort by random tag
1375+ shuffle_untag (lists :keysort (1 , TL ), Next , R , WeakLowBits , Acc );
1376+ shuffle_tag ([X | L ], Next , R0 , WeakLowBits , Acc , TL ) ->
13791377 {V , R1 } = Next (R0 ),
13801378 T = V bsr WeakLowBits ,
1381- shuffle1_tag (L , Next , R1 , WeakLowBits , Acc , [{T ,X } | TL ]).
1379+ shuffle_tag (L , Next , R1 , WeakLowBits , Acc , [{T ,X } | TL ]).
13821380
13831381% % Strip the tag integers
1384- shuffle1_untag ([{T ,X }, {T ,Y } | TL ], Next , R , WeakLowBits , Acc ) ->
1382+ shuffle_untag ([{T ,X }, {T ,Y } | TL ], Next , R , WeakLowBits , Acc ) ->
13851383 % % Random number duplicate
1386- shuffle1_untag (TL , Next , R , WeakLowBits , Acc , [Y , X ], T );
1387- shuffle1_untag ([{_ ,X } | TL ], Next , R , WeakLowBits , Acc ) ->
1388- shuffle1_untag (TL , Next , R , WeakLowBits , [X | Acc ]);
1389- shuffle1_untag ([], _Next , R , _WeakLowBits , Acc ) ->
1384+ shuffle_untag (TL , Next , R , WeakLowBits , Acc , [Y , X ], T );
1385+ shuffle_untag ([{_ ,X } | TL ], Next , R , WeakLowBits , Acc ) ->
1386+ shuffle_untag (TL , Next , R , WeakLowBits , [X | Acc ]);
1387+ shuffle_untag ([], _Next , R , _WeakLowBits , Acc ) ->
13901388 {Acc , R }.
13911389% %
13921390% % Collect duplicates
1393- shuffle1_untag ([{T ,X } | TL ], Next , R , WeakLowBits , Acc , Dups , T ) ->
1394- shuffle1_untag (TL , Next , R , WeakLowBits , Acc , [X | Dups ], T );
1395- shuffle1_untag (TL , Next , R0 , WeakLowBits , Acc0 , Dups , _T ) ->
1396- % % Shuffle1 the duplicates onto the result
1397- {Acc1 , R1 } = shuffle1_r (Dups , Next , R0 , WeakLowBits , Acc0 ),
1398- shuffle1_untag (TL , Next , R1 , WeakLowBits , Acc1 ).
1399-
1400- % % -------
1401-
1402- -spec shuffle2 (list ()) -> list ().
1403- shuffle2 (List ) ->
1404- {ShuffledList , State } = shuffle2_s (List , seed_get ()),
1405- _ = seed_put (State ),
1406- ShuffledList .
1407-
1408- -spec shuffle2_s (list (), state ()) -> {list (), state ()}.
1409- shuffle2_s (List , State )
1410- when is_list (List ) ->
1411- case List of
1412- [] ->
1413- {List , State };
1414- [_ ] ->
1415- {List , State };
1416- _ ->
1417- M = maps :from_list (lists :enumerate (List )),
1418- N = maps :size (M ),
1419- shuffle2_s (M , State , N , [])
1420- end .
1421-
1422- % % Classical Fisher-Yates shuffle, a.k.a Knuth shuffle.
1423- % % See the Wikipedia article "Fisher-Yates shuffle".
1424- % %
1425- % % This variant uses a map with integer keys as array
1426- % % and is optimized in that it minimizes map updates
1427- % % since the high index is never used again, so an overwrite
1428- % % can be used instead of an exchange.
1429-
1430- shuffle2_s (M0 , State0 , N , Acc )
1431- when is_map (M0 ), is_integer (N ) ->
1432- if
1433- N =:= 0 -> {Acc , State0 };
1434- true ->
1435- X = maps :get (N , M0 ),
1436- case uniform_s (N , State0 ) of
1437- {N , State1 } ->
1438- shuffle2_s (M0 , State1 , N - 1 , [X | Acc ]);
1439- {K , State1 } when is_integer (K ) ->
1440- Y = maps :get (K , M0 ),
1441- M1 = maps :update (K , X , M0 ),
1442- shuffle2_s (M1 , State1 , N - 1 , [Y | Acc ])
1443- end
1444- end .
1445-
1446- % % -------
1447-
1448- -spec shuffle3 (list ()) -> list ().
1449- shuffle3 (List ) ->
1450- {ShuffledList , State } = shuffle3_s (List , seed_get ()),
1451- _ = seed_put (State ),
1452- ShuffledList .
1453-
1454- -spec shuffle3_s (list (), state ()) -> {list (), state ()}.
1455- shuffle3_s (List , {#{bits := _ , next := Next } = AlgHandler , R0 } = State )
1456- when is_list (List ) ->
1457- case List of
1458- [] ->
1459- {List , State };
1460- [_ ] ->
1461- {List , State };
1462- _ ->
1463- WeakLowBits = maps :get (weak_low_bits , AlgHandler , 0 ),
1464- T = gb_trees :empty (),
1465- {ShuffledList , R1 } = shuffle3_r (List , Next , R0 , WeakLowBits , T ),
1466- {ShuffledList , {AlgHandler , R1 }}
1467- end ;
1468- shuffle3_s (List , {#{max := Mask , next := Next } = AlgHandler , R0 } = State )
1469- when is_list (List ), ? MASK (58 ) =< Mask ->
1470- case List of
1471- [] ->
1472- {List , State };
1473- [_ ] ->
1474- {List , State };
1475- _ ->
1476- % % Old spec - assume 2 weak low bits
1477- WeakLowBits = 2 ,
1478- T = gb_trees :empty (),
1479- {ShuffledList , R1 } = shuffle3_r (List , Next , R0 , WeakLowBits , T ),
1480- {ShuffledList , {AlgHandler , R1 }}
1481- end .
1482-
1483- % % See the Wikipedia article "Fisher-Yates shuffle", section "Sorting".
1484- % %
1485- % % To avoid bias due to duplicate random numbers, a gb_tree
1486- % % is used to check if a random number has already been used,
1487- % % and if so generate a new random number.
1488- % %
1489- % % Because a gb_tree is sorted no sorting needs to be done,
1490- % % it is enough to extract the values of the gb_tree that are
1491- % % ordered in key sort order.
1492-
1493- shuffle3_r ([], _Next , R , _WeakLowBits , T ) ->
1494- {gb_trees :values (T ), R };
1495- shuffle3_r ([X | L ] , Next , R0 , WeakLowBits , T ) ->
1496- {V , R1 } = Next (R0 ),
1497- K = V bsr WeakLowBits ,
1498- case gb_trees :is_defined (K , T ) of
1499- false ->
1500- shuffle3_r (L , Next , R1 , WeakLowBits , gb_trees :insert (K , X , T ));
1501- true ->
1502- shuffle3_r ([X | L ], Next , R1 , WeakLowBits , T )
1503- end .
1504-
1505- % % -------
1506-
1507- -spec shuffle4 (list ()) -> list ().
1508- shuffle4 (List ) ->
1509- {ShuffledList , State } = shuffle4_s (List , seed_get ()),
1510- _ = seed_put (State ),
1511- ShuffledList .
1512-
1513- -spec shuffle4_s (list (), state ()) -> {list (), state ()}.
1514- shuffle4_s (List , {#{bits := _ , next := Next } = AlgHandler , R0 } = State )
1515- when is_list (List ) ->
1516- case List of
1517- [] ->
1518- {List , State };
1519- [_ ] ->
1520- {List , State };
1521- _ ->
1522- WeakLowBits = maps :get (weak_low_bits , AlgHandler , 0 ),
1523- {ShuffledList , R1 } = shuffle4_r (List , Next , R0 , WeakLowBits , #{}),
1524- {ShuffledList , {AlgHandler , R1 }}
1525- end ;
1526- shuffle4_s (List , {#{max := Mask , next := Next } = AlgHandler , R0 } = State )
1527- when is_list (List ), ? MASK (58 ) =< Mask ->
1528- case List of
1529- [] ->
1530- {List , State };
1531- [_ ] ->
1532- {List , State };
1533- _ ->
1534- % % Old spec - assume 2 weak low bits
1535- WeakLowBits = 2 ,
1536- {ShuffledList , R1 } = shuffle4_r (List , Next , R0 , WeakLowBits , #{}),
1537- {ShuffledList , {AlgHandler , R1 }}
1538- end .
1539-
1540- % % See the Wikipedia article "Fisher-Yates shuffle", section "Sorting".
1541- % %
1542- % % To avoid bias due to duplicate random numbers, a map
1543- % % is used to check if a random number has already been used,
1544- % % and if so generate a new random number.
1545- % %
1546- % % Actual sorting doesn't is not needed. A map is ordered by key
1547- % % and therefore it is enough to extract the values of the map.
1548- % % The internal map key order will do just fine.
1549-
1550- shuffle4_r ([], _Next , R , _WeakLowBits , M ) ->
1551- {maps :values (M ), R };
1552- shuffle4_r ([X | L ] , Next , R0 , WeakLowBits , M ) ->
1553- {V , R1 } = Next (R0 ),
1554- K = V bsr WeakLowBits ,
1555- case maps :is_key (K , M ) of
1556- true ->
1557- shuffle4_r ([X | L ], Next , R1 , WeakLowBits , M );
1558- false ->
1559- shuffle4_r (L , Next , R1 , WeakLowBits , maps :put (K , X , M ))
1560- end .
1391+ shuffle_untag ([{T ,X } | TL ], Next , R , WeakLowBits , Acc , Dups , T ) ->
1392+ shuffle_untag (TL , Next , R , WeakLowBits , Acc , [X | Dups ], T );
1393+ shuffle_untag (TL , Next , R0 , WeakLowBits , Acc0 , Dups , _T ) ->
1394+ % % Shuffle the duplicates onto the result
1395+ {Acc1 , R1 } = shuffle_r (Dups , Next , R0 , WeakLowBits , Acc0 ),
1396+ shuffle_untag (TL , Next , R1 , WeakLowBits , Acc1 ).
15611397
15621398% % =====================================================================
15631399% % Internal functions
0 commit comments