Randomize a List problem
|
09-14-2020, 04:38 PM
(This post was last modified: 09-14-2020 04:52 PM by Hlib.)
Post: #1
|
|||
|
|||
Randomize a List problem
Over the weekend, I did a little research using a calculator. This is a program called "Randomize a List", taken from the wonderful manual <One-Minute Marvels> (a collection of short HP48/49 programs, page 8) by Wlodek Mier-Jedrzejowicz and Richard Nelson.
`RANL` Code:
For example, we will never get permutations {1 2 3} and {2 1 3 } after {3 2 1} `RANL` The number of all possible options we can get for a list of N elements in this program when it is run once: #2 {2 1} – 2 options out of 2!=2 possible. #3 {3 2 1} – 4 options out of 3!=6 possible. #4 {4 3 2 1} – 10 out of 4!=24. #5 {5 4 3 2 1} – 28 / out of 5!=120. #6 {6 5 4 3 2 1} – 80 / out of 6!=720. #7 {7 6 5 4 3 2 1} – 274 / out of 7!=5040. #8 {8 7 6 5 4 3 2 1} – 898 / out of 8!=40320 and so on. To fix this, you need to replace one letter in the text: ... FOR n t RAND × ... . But I`m interested in a more complex problem: how to use the formula to express the number of possible combinations in the first (not corrected) version of the program, also describing the ROLLD function in the loop. I calculated this using an algorithm on a calculator, and my knowledge of mathematics is clearly not enough for an analytical solution. |
|||
09-14-2020, 06:08 PM
Post: #2
|
|||
|
|||
RE: Randomize a List problem
Here is a good Wikipedia article describing the algorithm behind the RANL program. If you read farther down, it says that a simple programming mistake can accidentally implement Sattolo's algorithm which returns only cyclic permutations.
If that was exactly what was going on, you should be getting (n-1)! permutations, which you are not. I am not sure that the corrected version of the program does produce all permutations, nor whether the incorrect version is in fact the mistake noted in the linked article. I suspect the problem is more complex. By the way, I searched http://oeis.org/ with the numbers you listed but no result was returned. Are you sure you have found all the possible permutations that the incorrect version can produce? |
|||
09-14-2020, 07:32 PM
(This post was last modified: 09-15-2020 01:56 AM by Albert Chan.)
Post: #3
|
|||
|
|||
RE: Randomize a List problem
Random shuffling must produce all permutations with equal probabilities.
We pick a random element from the list, and moved out of the way Do this repeatedly, like this. (we can skip the 1 element list case) Code: function shuffle(lst) 1st loop, random element is swapped to lst[n], and never touched again. 2nd loop, random element is swapped to lst[n-1] ... lua> pat = setmetatable({}, {__index = function(a,i) return 0 end}) lua> for i=1,120000 do : lst = {'1','2','3'} : shuffle(lst) : x = table.concat(lst,'') : pat[x] = pat[x] + 1 : end lua> table.foreach(pat, print) 321 20104 312 19844 132 20026 123 20096 231 19890 213 20040 |
|||
09-14-2020, 08:51 PM
(This post was last modified: 09-14-2020 09:08 PM by Hlib.)
Post: #4
|
|||
|
|||
RE: Randomize a List problem
Quote: John Keith wrote:For simple cases you can check this manually: #3: 321 312 231 132 #4: 4321 4312 4231 4213 4132 4123 2431 2413 1432 1423 No matter how many times we run program << { 3. 2. 1 } LIST➝ ➝ t << 1. t FOR n n RAND × CEIL ROLLD NEXT t ➝LIST >> >> or << { 4. 3. 2. 1 } LIST➝ ➝ t << 1. t FOR n n RAND × CEIL ROLLD NEXT t ➝LIST >> >> we won`t get any other results. But if ... FOR n t RAND ... then after many clicks we may get all set of lists (6 for #3 and 24 for #4). Assuming that RAND can take any value from the interval [0,1] and taking into account the specifics of the ROLLD command, I calculated all possible options for the shown results for both versions of the program using the full search method. There is no error here. But let`s say we can`t be sure. So we need to get the formula. Quote: Albert Chan wrote:Thank you, but that`s not exactly what I meant. It is easy to randomize the list in different ways, for example, in CASIO-BASIC: Code: (Shuffling the List 2) |
|||
09-14-2020, 11:41 PM
(This post was last modified: 09-15-2020 08:49 AM by Albert Chan.)
Post: #5
|
|||
|
|||
RE: Randomize a List problem
Confession time. I have never program in HP-50g.
This is my first program, after skimming the online manual To move random element out of the way, I do it in 2 steps. ROLL it to top-of-stack, then ROLLD it to bottom-of-stack. ≪ { 3. 2. 1 } LIST➝ ➝ t ≪ t 2. FOR n n RAND × CEIL ROLL t ROLLD -1 STEP t ➝LIST ≫ ≫ We can also replace "t ROLLD" to "n ROLLD", possibly run faster ? P.S. possibly non-issue. "n RAND × CEIL" might return an index of 0 But, on the emulator 0 ROLL ≡ 1 ROLL ≡ do nothing. |
|||
09-15-2020, 01:00 AM
Post: #6
|
|||
|
|||
RE: Randomize a List problem
(09-14-2020 08:51 PM)Hlib Wrote: FOR n t RAND ... then after many clicks we may get all set of lists (6 for #3 and 24 for #4). For a list of 3 items, we have 3! = 6 permutations. But, your suggested shuffling can have 3*3*3 = 27 ways. By the pigeonhole principles, some will appear more often, some less (*) Starting from {3,2,1}, and gone thru all 27 possible ROLLD shuffling, we have: {3,2,1} × 5 {2,3,1} × 4 {3,1,2} × 5 {1,3,2} × 5 {2,1,3} × 4 {1,2,3} × 4 Shuffling will not be fair. I did a simulation, and confirmed this. (*) even if one divides the other, there is still a possibility of unfair shuffling, depending on shuffling details. |
|||
09-15-2020, 04:10 AM
Post: #7
|
|||
|
|||
RE: Randomize a List problem
(09-15-2020 01:00 AM)Albert Chan Wrote: For a list of 3 items, we have 3! = 6 permutations. I was just about to point out the same thing, implying that the probabilities are not all equal. Just for fun, here's my attempt at randomizing a list with equal probabilities. << { } 1. PICK3 SIZE START RAND + NEXT SWAP 2. ->LIST TRAN SORT TRAN 2. GET >> |
|||
09-15-2020, 06:41 AM
Post: #8
|
|||
|
|||
RE: Randomize a List problem
(09-14-2020 11:41 PM)Albert Chan Wrote: possibly non-issue. "n RAND × CEIL" might return an index of 0 Long ago, it has been confirmed by Those Who Know that RAND will never return 0. or 1., so 1. <= n RAND * CEIL <= n Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
09-15-2020, 09:47 AM
Post: #9
|
|||
|
|||
RE: Randomize a List problem
(09-14-2020 11:41 PM)Albert Chan Wrote: ≪ t 2. FOR n n RAND × CEIL ROLL t ROLLD -1 STEP t ➝LIST ≫ or, the other way round: ≪ 1. t FOR n t ROLL n RAND × CEIL ROLLD NEXT t ➝LIST ≫ Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
09-15-2020, 01:42 PM
Post: #10
|
|||
|
|||
RE: Randomize a List problem
(09-14-2020 08:51 PM)Hlib Wrote: For simple cases you can check this manually: Well, I checked and not all of the permutations you listed are cyclic permutations so we can scratch that idea. Also we can note that the number of permutations returned by the erroneous program grows much more slowly than (n-1)! As to the formula that explains the program behavior, I have no idea. |
|||
09-15-2020, 03:57 PM
(This post was last modified: 09-15-2020 04:01 PM by Hlib.)
Post: #11
|
|||
|
|||
RE: Randomize a List problem
Thanks everyone!
In our examples, can we estimate the number of different combinations for lists of any size? There may be unexpected results. I inserted a fragment into the source program, which swaps 1-st and random n-th elements on stack: Code: << { } LIST➝ ➝ t #2 {2 1} – 2 options out of 2!=2 possible. #3 {3 2 1} – 6 options out of 3!=6 possible. #4 {4 3 2 1} – 24 / out of 4!=24. #5 {5 4 3 2 1} – 107=5!–13 / out of 5!=120. #6 {6 5 4 3 2 1} – 685=6!–35 / out of 6!=720. For many practical problems we don`t need to have equal probabilities for each permutation, and we don`t always need the maximum number of possible combinations. But in these short programs before using them I would like to estimate at least the range of results that we get using the stack process. |
|||
09-15-2020, 04:36 PM
Post: #12
|
|||
|
|||
RE: Randomize a List problem
(09-15-2020 09:47 AM)Werner Wrote: or, the other way round: This may be easier to understand (and, probably more efficient): Note: I use lua definition of random(n) = 1 .. n, all equally likely. ≪ 1. t FOR n n ROLL n RAND × CEIL ROLLD NEXT t ➝LIST ≫ With k-1 items shuffled, k-th loop ROLL stack(k) to stack(1), then ROLLD to stack(random(k)). In the meantime, stack(k+1), stack(k+2), ..., had never been touched. (09-14-2020 11:41 PM)Albert Chan Wrote: ≪ t 2. FOR n n RAND × CEIL ROLL t ROLLD -1 STEP t ➝LIST ≫ My version give me an idea ... Say, we changed "t 2." to "t 1." (equivalent to "t ROLLD" before convert back to list). Now, imagine you know the next sequence of generated random numbers. If random(n) = 1, 1, 1 ..., shuffled list = original list (1st permutation) If random(n) = n, n, n ..., shuffled list = reversed list (t! permutation) We can reverse the process, and get the k-th lexigraphically ordered pattern. In other words, we can shuffle with k = random(n!), then reconstruct the permutation. Example: What is 100-th lexigraphically ordered list, [1, 2, 3, 4, 5] ? Code: 100 - 1 = 99 -- we do calculations, 0-based Reconstruct 100-th permutation of [1,2,3,4,5] on Emu-48: 5 4 3 2 1 5 ROLL 5 ROLLD → 5 4 3 2 1 1 ROLL 5 ROLLD → 1 5 4 3 2 2 ROLL 5 ROLLD → 3 1 5 4 2 2 ROLL 5 ROLLD → 4 3 1 5 2 5 ROLLD → 2 4 3 1 5 100-th permutation = [5,1,3,4,2]. Confirmed with actual counting. >>> from itertools import permutations >>> for i,x in enumerate(permutations([1,2,3,4,5]),1): ... if i==100: print(i, x); break ... (100, (5, 1, 3, 4, 2)) |
|||
09-15-2020, 06:39 PM
Post: #13
|
|||
|
|||
RE: Randomize a List problem
(09-15-2020 09:47 AM)Werner Wrote:(09-14-2020 11:41 PM)Albert Chan Wrote: ≪ t 2. FOR n n RAND × CEIL ROLL t ROLLD -1 STEP t ➝LIST ≫ Those two are the classic Fisher-Yates shuffle algorithm, with the ROLL and ROLLD exchanging two items at specified stack positions. Is there a more efficient way to swap stack elements? — Ian Abbott |
|||
09-15-2020, 07:53 PM
Post: #14
|
|||
|
|||
RE: Randomize a List problem
(09-15-2020 03:57 PM)Hlib Wrote: I inserted a fragment into the source program, which swaps 1-st and random n-th elements on stack ... Do not use this code ! This is much worse than "random(t) ROLLD" Code: Starting pattern = 123, shuffled pattern has 3^3 = 27 ways Uneven probabilities problem get worse with more items in the list. This is not just pigeonhole issues anymore. I would recommend not cutting corners here, and use good shuffling code. Code: Starting pattern = 1234, shuffled pattern has 4^4 = 256 ways |
|||
09-15-2020, 08:56 PM
Post: #15
|
|||
|
|||
RE: Randomize a List problem
(09-15-2020 06:39 PM)ijabbott Wrote: Those two are the classic Fisher-Yates shuffle algorithm, with the ROLL and ROLLD exchanging two items at specified stack positions. Is there a more efficient way to swap stack elements? In UserRPL I can't think of a faster way. Stack operations are generally faster than list operations. There are two ListExt commands that are germane to the current discussion: LSHUF implements the modern Fisher-Yates algorithm and is many times faster than any user implementation. DOPERM lists all permutations of a list taken n items at a time (see documentation). For instance, Albert's example of the 100th permutation of { 1 2 3 4 5 } would be { 1 2 3 4 5 } 5 << >> DOPERM 100 GET |
|||
09-15-2020, 09:34 PM
Post: #16
|
|||
|
|||
RE: Randomize a List problem
(09-15-2020 08:56 PM)John Keith Wrote: In UserRPL I can't think of a faster way. Stack operations are generally faster than list operations. Hi, John Keith Can you show what a list-operated shuffling code look like ? With both input and output a list, I would have guessed list-operated shuffle faster. |
|||
09-16-2020, 06:43 AM
Post: #17
|
|||
|
|||
RE: Randomize a List problem
(09-15-2020 09:34 PM)Albert Chan Wrote: Can you show what a list-operated shuffling code look like ? To swap two positions in a list: In: L i j Out: L, positions i and j swapped Code: \<< Stack operations are orders of magnitude faster, because the stack contains only pointers. The above code rebuilds the whole list twice (with each PUT). And yes, for the 49 and up it can be made 1 instruction shorter still (replace ROT SWAP with UNROT - purists will notice that that is not the same, but it is here). There is no way (short of machine language) to swap two objects in a list in-place. BTW the original 'randomize list' can be written in a much more compact way: Code: \<< Cheers, Werner 41CV†,42S,48GX,49G,DM42,DM41X,17BII,15CE,DM15L,12C,16CE |
|||
09-16-2020, 11:51 AM
Post: #18
|
|||
|
|||
RE: Randomize a List problem | |||
09-16-2020, 11:00 PM
(This post was last modified: 09-17-2020 05:07 PM by David Hayden.)
Post: #19
|
|||
|
|||
RE: Randomize a List problem
[ Edit: fixed some typos that Albert Chan pointed out in a private message. Thanks Albert! ]
You can swap level 1 with level N with Code: N PICK SWAP N UNPICK Code: N PICK SWAP N UNPICK @ swap level n and level 1 Code: IF N M < THEN @ EDIT: < should be ≠ With that, you can efficiently sort a list with [ EDIT: "sort" should be "shuffle" ] Code: « |
|||
09-17-2020, 09:36 AM
Post: #20
|
|||
|
|||
RE: Randomize a List problem
Quote:David Hayden wroteYes, this method is also quite good, although not elegant enough. Quite by chance, I found out about the existence of a very important application called "Extended List Commands Library". Thanks to John Keith for this link: Quote:John Keith wroteNow, to swap two objects in a stack or list, it is much easier to use the m n SWPXY and m n LSWAP commands from the library. |
|||
« Next Oldest | Next Newest »
|
User(s) browsing this thread: 4 Guest(s)