samba shadow copy cannot match - snapshot

The test machine is running Ubuntu server 20.04 LTS, I'm tring to expose zfs snapshots to samba share as shadow copies but failed.
Here is the smb.conf share block:
[Storage]
comment = NAS Storage
path = /storage/smb
browseable = yes
read only = no
guest ok = no
create mask = 0755
directory mask = 0755
vfs objects = shadow_copy2
shadow:format = "CST-%Y.%m.%d-%H.%M.%S"
shadow:localtime = yes
shadow:snapdir = .zfs/snapshot
;shadow:basedir = /storage/smb
And these are zfs snapshots:
root#samba-1:/var/log/samba# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
storage/smb#CST-2022.03.08-23.25.35 16K - 26K -
storage/smb#CST-2022.03.08-23.39.39 16K - 26K -
storage/smb#CST-2022.03.09-00.01.17 56.5K - 66.5K -
And I found these in logs:
[2022/03/09 12:53:40.750713, 10, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/smbd/files.c:824(file
_name_hash)
file_name_hash: /storage/smb//storage/smb/.zfs/snapshot hash 0xb6dc192a
[2022/03/09 12:53:40.750846, 10, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_co
py2.c:1870(shadow_copy2_snapshot_to_gmt)
shadow_copy2_snapshot_to_gmt: no match "CST-%Y.%m.%d-%H.%M.%S": .
[2022/03/09 12:53:40.750872, 6, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:2064(shadow_copy2_get_shadow_copy_data)
shadow_copy2_get_shadow_copy_data: ignoring .
[2022/03/09 12:53:40.750892, 10, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:1870(shadow_copy2_snapshot_to_gmt)
shadow_copy2_snapshot_to_gmt: no match "CST-%Y.%m.%d-%H.%M.%S": ..
[2022/03/09 12:53:40.750910, 6, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:2064(shadow_copy2_get_shadow_copy_data)
shadow_copy2_get_shadow_copy_data: ignoring ..
[2022/03/09 12:53:40.750928, 10, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:1870(shadow_copy2_snapshot_to_gmt)
shadow_copy2_snapshot_to_gmt: no match "CST-%Y.%m.%d-%H.%M.%S": CST-2022.03.09-00.01.17
[2022/03/09 12:53:40.750947, 6, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:2064(shadow_copy2_get_shadow_copy_data)
shadow_copy2_get_shadow_copy_data: ignoring CST-2022.03.09-00.01.17
[2022/03/09 12:53:40.750973, 10, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:1870(shadow_copy2_snapshot_to_gmt)
shadow_copy2_snapshot_to_gmt: no match "CST-%Y.%m.%d-%H.%M.%S": CST-2022.03.08-23.39.39
[2022/03/09 12:53:40.751003, 6, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:2064(shadow_copy2_get_shadow_copy_data)
shadow_copy2_get_shadow_copy_data: ignoring CST-2022.03.08-23.39.39
[2022/03/09 12:53:40.751030, 10, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:1870(shadow_copy2_snapshot_to_gmt)
shadow_copy2_snapshot_to_gmt: no match "CST-%Y.%m.%d-%H.%M.%S": CST-2022.03.08-23.25.35
[2022/03/09 12:53:40.751053, 6, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/modules/vfs_shadow_copy2.c:2064(shadow_copy2_get_shadow_copy_data)
shadow_copy2_get_shadow_copy_data: ignoring CST-2022.03.08-23.25.35
[2022/03/09 12:53:40.751112, 5, pid=3211, effective(101105, 100513), real(101105, 0)] ../../source3/smbd/files.c:636(file_free)
freed files structure 0 (4 used)
[2022/03/09 12:53:40.751137, 10, pid=3211, effective(101105, 100513), real(101105, 0), class=vfs] ../../source3/modules/vfs_default.c:1482(vfswrap_fsctl)
FSCTL_GET_SHADOW_COPY_DATA: 0 volumes for path[.].
why the compare is no match? I generate the snapshot name using date +%Y.%m.%d-%H.%M.%S

My system is a Raspberry Pi 4 with Raspberry Pi OS lite 64bits and Samba Version 4.13.13-Debian and I'm having the same problems, but found a strange solution:
You have to set this
shadow:localtime = no
The following e-mail on the Samba mailing list gave me a clue.

Related

How to prove this josephus problem variation is a np-complete problem?

I have a problem that is a Josephus problem variation. It is described below:
There are m cards with number from 1 to m,and each of them has a unique number. The cards are dispatched to n person who sit in a circle. Note that m >= n.
Then we choose the person "A" who sits at the position "p" to out of the circle, just like the Josephus problem does. Next step we skip "k" person at the right of p while k is the number of the card toked by the person "A", and we do the same thing until only one person left in the circle.
Question is given n person and m cards, can we choose n cards and allocate them to the n person, to make that whether start at which position(exclude the first position), the person survival at the end is always the first person in the circle.
For example, m = n = 5, the only solution is (4, 1, 5, 3, 2).
I think this problem is a np-complete problem, but I can't prove it. Anybody has a good idea to find a polynomial time solution or prove it's np-hard?
--- example solutions ---
2: [ 1, 2]
2: [ 2, 1]
3: [ 1, 3, 2]
3: [ 3, 1, 2]
4: [ 4, 1, 3, 2]
5: [ 4, 1, 5, 3, 2]
7: [ 5, 7, 3, 1, 6, 4, 2]
9: [ 2, 7, 3, 9, 1, 6, 8, 5, 4]
9: [ 3, 1, 2, 7, 6, 5, 9, 4, 8]
9: [ 3, 5, 1, 8, 9, 6, 7, 4, 2]
9: [ 3, 9, 2, 7, 6, 1, 5, 4, 8]
9: [ 6, 1, 8, 3, 7, 9, 4, 5, 2]
10: [ 3, 5, 6, 10, 1, 9, 8, 7, 4, 2]
10: [ 4, 5, 2, 8, 7, 10, 6, 1, 9, 3]
10: [ 5, 1, 9, 2, 10, 3, 7, 6, 8, 4]
10: [ 6, 3, 1, 10, 9, 8, 7, 4, 5, 2]
10: [ 8, 5, 9, 10, 1, 7, 2, 6, 4, 3]
10: [10, 5, 2, 1, 8, 7, 6, 9, 3, 4]
11: [ 2, 1, 10, 11, 9, 3, 7, 5, 6, 8, 4]
11: [ 3, 7, 11, 10, 9, 8, 1, 6, 5, 4, 2]
11: [ 3, 11, 10, 9, 8, 1, 7, 2, 4, 5, 6]
11: [ 4, 1, 10, 2, 9, 8, 7, 5, 11, 3, 6]
11: [ 4, 2, 7, 11, 5, 1, 10, 9, 6, 3, 8]
11: [ 4, 7, 2, 3, 1, 10, 9, 6, 11, 5, 8]
11: [ 4, 7, 3, 9, 11, 10, 1, 8, 6, 5, 2]
11: [ 4, 11, 7, 2, 1, 10, 9, 6, 5, 3, 8]
11: [ 5, 11, 3, 9, 8, 7, 6, 1, 10, 4, 2]
11: [ 6, 1, 10, 2, 9, 8, 7, 5, 11, 3, 4]
11: [ 6, 2, 7, 11, 5, 1, 10, 9, 4, 3, 8]
11: [ 6, 11, 1, 3, 10, 2, 7, 5, 4, 9, 8]
11: [ 9, 5, 3, 1, 10, 2, 8, 7, 11, 6, 4]
12: [ 1, 7, 11, 10, 4, 9, 2, 12, 6, 5, 8, 3]
12: [ 3, 7, 12, 2, 11, 10, 9, 1, 6, 5, 4, 8]
12: [ 3, 8, 11, 2, 12, 9, 1, 7, 5, 10, 4, 6]
12: [ 4, 2, 5, 1, 11, 10, 9, 8, 12, 7, 3, 6]
12: [ 4, 3, 7, 6, 1, 11, 10, 9, 8, 12, 5, 2]
12: [ 5, 1, 6, 11, 9, 2, 10, 7, 12, 8, 3, 4]
12: [ 5, 2, 3, 12, 9, 10, 7, 6, 1, 11, 4, 8]
12: [ 5, 7, 12, 2, 10, 9, 8, 11, 1, 4, 6, 3]
12: [ 7, 1, 2, 3, 5, 9, 10, 8, 11, 6, 12, 4]
12: [ 8, 7, 1, 11, 9, 3, 5, 10, 6, 4, 12, 2]
12: [ 8, 7, 11, 10, 12, 3, 1, 9, 6, 5, 4, 2]
12: [12, 3, 11, 5, 1, 10, 8, 7, 6, 4, 9, 2]
12: [12, 7, 11, 1, 9, 3, 2, 10, 6, 5, 4, 8]
13: [ 2, 1, 4, 7, 11, 6, 3, 10, 13, 5, 8, 12, 9]
13: [ 2, 5, 13, 12, 4, 11, 3, 1, 9, 7, 8, 6, 10]
13: [ 2, 13, 12, 11, 3, 1, 9, 4, 8, 7, 10, 5, 6]
13: [ 3, 5, 2, 1, 12, 9, 11, 10, 7, 6, 13, 4, 8]
13: [ 3, 5, 13, 1, 11, 2, 9, 8, 7, 12, 6, 4, 10]
13: [ 4, 13, 3, 1, 12, 11, 10, 9, 7, 2, 5, 6, 8]
13: [ 6, 4, 3, 1, 10, 11, 13, 5, 9, 12, 7, 8, 2]
13: [ 6, 4, 13, 7, 5, 1, 12, 11, 10, 9, 8, 3, 2]
13: [ 6, 7, 3, 13, 12, 11, 10, 2, 1, 9, 5, 4, 8]
13: [ 6, 7, 13, 11, 2, 10, 9, 1, 8, 12, 5, 3, 4]
13: [ 6, 11, 7, 13, 1, 10, 2, 12, 9, 8, 5, 4, 3]
13: [ 7, 3, 2, 1, 11, 10, 9, 8, 13, 5, 12, 4, 6]
13: [ 7, 5, 13, 3, 10, 11, 2, 9, 1, 6, 8, 4, 12]
13: [ 7, 5, 13, 3, 11, 2, 9, 8, 1, 6, 12, 4, 10]
13: [ 7, 5, 13, 3, 11, 12, 2, 1, 9, 8, 6, 4, 10]
13: [ 7, 9, 1, 11, 3, 13, 2, 10, 12, 6, 5, 4, 8]
13: [ 8, 3, 5, 11, 13, 9, 10, 7, 1, 6, 4, 12, 2]
13: [ 8, 3, 13, 1, 5, 11, 10, 9, 12, 7, 6, 4, 2]
13: [ 9, 3, 13, 2, 10, 4, 1, 7, 6, 5, 12, 11, 8]
13: [ 9, 4, 7, 5, 1, 11, 13, 10, 12, 8, 6, 3, 2]
13: [ 9, 5, 4, 13, 2, 11, 8, 10, 1, 7, 12, 3, 6]
13: [ 9, 5, 13, 4, 11, 1, 8, 3, 7, 12, 6, 10, 2]
13: [10, 4, 3, 5, 13, 1, 9, 11, 7, 6, 8, 12, 2]
13: [11, 2, 7, 3, 12, 1, 10, 9, 6, 5, 13, 4, 8]
13: [11, 13, 5, 2, 10, 9, 8, 7, 1, 6, 4, 3, 12]
13: [11, 13, 7, 1, 12, 9, 2, 3, 10, 5, 4, 6, 8]
13: [12, 1, 3, 5, 11, 13, 4, 10, 9, 8, 7, 6, 2]
13: [12, 7, 13, 3, 11, 1, 9, 8, 6, 5, 10, 4, 2]
13: [12, 13, 7, 11, 2, 5, 1, 9, 10, 6, 4, 3, 8]
13: [13, 3, 1, 12, 11, 2, 9, 10, 7, 6, 4, 5, 8]
13: [13, 3, 7, 1, 5, 12, 4, 10, 9, 8, 11, 6, 2]
14: [ 3, 5, 13, 14, 1, 12, 11, 10, 9, 8, 7, 6, 4, 2]
14: [ 3, 9, 1, 13, 11, 10, 2, 4, 7, 14, 6, 8, 5, 12]
14: [ 3, 14, 4, 12, 11, 1, 9, 8, 2, 13, 7, 5, 10, 6]
14: [ 4, 11, 1, 13, 7, 10, 12, 2, 14, 9, 8, 5, 6, 3]
14: [ 4, 14, 2, 5, 13, 1, 12, 11, 7, 6, 10, 9, 3, 8]
14: [ 5, 7, 1, 13, 12, 11, 10, 2, 9, 8, 14, 6, 4, 3]
14: [ 6, 3, 14, 5, 11, 13, 2, 12, 9, 1, 7, 4, 8, 10]
14: [ 6, 14, 1, 12, 5, 13, 2, 11, 9, 7, 8, 4, 3, 10]
14: [ 7, 5, 13, 12, 1, 11, 4, 10, 2, 14, 9, 8, 6, 3]
14: [ 7, 11, 5, 13, 1, 3, 2, 4, 10, 9, 14, 6, 8, 12]
14: [ 7, 14, 1, 13, 2, 5, 11, 12, 10, 9, 8, 4, 3, 6]
14: [ 8, 7, 5, 13, 2, 11, 3, 9, 10, 12, 1, 14, 4, 6]
14: [11, 2, 10, 5, 8, 7, 9, 1, 13, 14, 12, 4, 3, 6]
14: [11, 3, 14, 2, 13, 1, 10, 8, 9, 7, 5, 12, 4, 6]
14: [11, 5, 3, 14, 2, 1, 13, 10, 8, 7, 6, 12, 4, 9]
14: [11, 14, 5, 3, 13, 1, 10, 2, 9, 4, 7, 8, 12, 6]
14: [12, 1, 14, 3, 13, 4, 10, 9, 2, 7, 6, 5, 11, 8]
14: [12, 11, 7, 5, 13, 3, 2, 14, 1, 9, 8, 4, 6, 10]
14: [12, 14, 7, 13, 6, 5, 11, 1, 10, 9, 8, 4, 3, 2]
14: [13, 1, 7, 2, 11, 3, 9, 14, 8, 6, 5, 10, 4, 12]
14: [13, 11, 3, 1, 4, 2, 7, 10, 9, 6, 14, 12, 5, 8]
14: [14, 1, 13, 3, 11, 5, 10, 9, 2, 6, 8, 7, 4, 12]
14: [14, 5, 1, 13, 12, 2, 11, 3, 7, 9, 6, 8, 4, 10]
--- possibly helpful for a mathematical solution ---
I noticed that starting with length 9, at least one solution for every length has a longish sequence of integers that decrement by 1.
9: [3, 1, 2, 7, 6, 5, 9, 4, 8]
10: [6, 3, 1, 10, 9, 8, 7, 4, 5, 2]
11: [3, 7, 11, 10, 9, 8, 1, 6, 5, 4, 2]
11: [3, 11, 10, 9, 8, 1, 7, 2, 4, 5, 6]
11: [5, 11, 3, 9, 8, 7, 6, 1, 10, 4, 2]
12: [4, 2, 5, 1, 11, 10, 9, 8, 12, 7, 3, 6]
12: [4, 3, 7, 6, 1, 11, 10, 9, 8, 12, 5, 2]
13: [6, 4, 13, 7, 5, 1, 12, 11, 10, 9, 8, 3, 2]
14: [3, 5, 13, 14, 1, 12, 11, 10, 9, 8, 7, 6, 4, 2]
I noticed that for every length I tested except the very small, at least one solution contains a relatively long run of descending
numbers. So far this answer only considers m = n. Here are a few examples; note that excess is n - run_len:
n = 3, run_len = 2, excess = 1: [1] + [3-2] + []
n = 4, run_len = 2, excess = 2: [4, 1] + [3-2] + []
n = 5, run_len = 2, excess = 3: [4, 1, 5] + [3-2] + []
n = 6, no solution
n = 7, run_len = 1, excess = 6: [5] + [7-7] + [3, 1, 6, 4, 2]
n = 8, no solution
n = 9, run_len = 3, excess = 6: [3, 1, 2] + [7-5] + [9, 4, 8]
n = 10, run_len = 4, excess = 6: [6, 3, 1] + [10-7] + [4, 5, 2]
n = 11, run_len = 4, excess = 7: [3, 7] + [11-8] + [1, 6, 5, 4, 2]
n = 12, run_len = 4, excess = 8: [4, 2, 5, 1] + [11-8] + [12, 7, 3, 6]
n = 13, run_len = 5, excess = 8: [6, 4, 13, 7, 5, 1] + [12-8] + [3, 2]
n = 14, run_len = 7, excess = 7: [3, 5, 13, 14, 1] + [12-6] + [4, 2]
n = 15, run_len = 8, excess = 7: [3, 15, 2] + [13-6] + [1, 5, 4, 14]
n = 16, run_len = 6, excess = 10: [6, 3, 1, 10] + [16-11] + [2, 9, 7, 4, 5, 8]
n = 17, run_len = 8, excess = 9: [2, 5, 17, 15, 14, 1] + [13-6] + [4, 3, 16]
n = 18, run_len = 10, excess = 8: [6, 3, 17, 18, 1] + [16-7] + [5, 4, 2]
n = 19, run_len = 10, excess = 9: [4, 19, 3, 17, 18, 1] + [16-7] + [5, 6, 2]
n = 20, no solution found with run_length >= 10
n = 21, run_len = 14, excess = 7: [3, 21, 2] + [19-6] + [1, 5, 4, 20]
n = 22, run_len = 14, excess = 8: [22, 3, 2, 1] + [20-7] + [5, 21, 4, 6]
n = 23, run_len = 14, excess = 9: [7, 1, 23, 3] + [21-8] + [6, 5, 22, 4, 2]
n = 24, run_len = 16, excess = 8: [6, 5, 24, 2] + [22-7] + [3, 1, 23, 4]
n = 25, run_len = 17, excess = 8: [25, 3, 2, 1] + [23-7] + [5, 24, 4, 6]
n = 26, run_len = 17, excess = 9: [26, 3, 25, 2, 1] + [23-7] + [5, 24, 4, 6]
n = 27, run_len = 20, excess = 7: [3, 27, 2] + [25-6] + [1, 5, 4, 26]
n = 28, run_len = 18, excess = 10: [28, 1, 27, 2, 3] + [25-8] + [6, 5, 7, 4, 26]
n = 29, run_len = 20, excess = 9: [2, 5, 29, 27, 26, 1] + [25-6] + [4, 3, 28]
n = 30, run_len = 23, excess = 7: [30, 5, 2, 1] + [28-6] + [29, 3, 4]
n = 31, run_len = 24, excess = 7: [5, 31, 3] + [29-6] + [1, 30, 4, 2]
n = 32, run_len = 23, excess = 9: [7, 32, 31, 2, 1] + [30-8] + [5, 4, 3, 6]
n = 33, run_len = 26, excess = 7: [3, 33, 2] + [31-6] + [1, 5, 4, 32]
n = 34, run_len = 27, excess = 7: [3, 5, 33, 34, 1] + [32-6] + [4, 2]
n = 35, run_len = 27, excess = 8: [5, 35, 3, 33, 34, 1] + [32-6] + [4, 2]
n = 36, run_len = 26, excess = 10: [35, 7, 3, 1, 36, 2] + [34-9] + [6, 5, 4, 8]
n = 37, run_len = 29, excess = 8: [6, 5, 2, 1] + [35-7] + [36, 37, 3, 4]
n = 38, run_len = 29, excess = 9: [3, 7, 37, 38, 1] + [36-8] + [6, 4, 5, 2]
n = 39, run_len = 32, excess = 7: [3, 39, 2] + [37-6] + [1, 5, 4, 38]
n = 40, run_len = 31, excess = 9: [5, 2, 1] + [38-8] + [3, 7, 40, 4, 6, 39]
n = 41, run_len = 33, excess = 8: [3, 5, 1, 40, 2] + [38-6] + [41, 39, 4]
n = 42, run_len = 33, excess = 9: [42, 3, 41, 2, 1] + [39-7] + [5, 4, 40, 6]
n = 43, run_len = 34, excess = 9: [6, 5, 7, 43, 1] + [41-8] + [42, 4, 3, 2]
n = 44, run_len = 35, excess = 9: [5, 3, 2, 1] + [42-8] + [43, 7, 4, 44, 6]
n = 45, run_len = 38, excess = 7: [3, 45, 2] + [43-6] + [1, 5, 4, 44]
n = 50, run_len = 43, excess = 7: [50, 5, 2, 1] + [48-6] + [49, 3, 4]
n = 100, run_len = 91, excess = 9: [5, 2, 1] + [98-8] + [3, 7, 100, 4, 6, 99]
n = 201, run_len = 194, excess = 7: [3, 201, 2] + [199-6] + [1, 5, 4, 200]
20 is missing from the above table because the run length is at most 10, and is taking a long time to compute. No larger value that I've tested has such a small max run length relative to n.
I found these by checking run lengths from n-1 descending, with all possible starting values and permutations of the run & surrounding elements. This reduces the search space immensely.
For a given n, if the max run in any solution to n is length n-k, then this will find it in O(k! * n). While this looks grim, if k has a constant upper bound (e.g. k <= some threshold for all sufficiently large n) then this is effectively O(n). 'Excess' is what I'm calling k in the examples above. I haven't found any greater than 10, but I don't have a solution yet to n = 20. If it has a solution then its excess will exceed 10.
UPDATE: There are a lot of patterns here.
If n mod 6 is 3 and n >= 9, then [3, n, 2, [n-2, n-3, ..., 6], 1, 5, 4, n-1] is valid.
If n mod 12 is 5 and n >= 17 then [2, 5, n, n-2, n-3, 1, [n-4, n-5, ..., 6], 4, 3, n-1] is valid.
If n mod 20 is 10, then [n, 5, 2, 1, [n-2, n-3, ..., 6], n-1, 3, 4] is valid.
If n mod 60 is 7, 11, 31, or 47, then [5, n, 3, [n-2, n-3, ..., 6], 1, n-1, 4, 2] is valid.
If n mod 60 is 6 or 18 and n >= 18 then [6, 3, n-1, n, 1, [n-2, n-3, ..., 7], 5, 4, 2] is valid.
If n mod 60 is 1, 22, 25 or 52 and n >= 22 then [n, 3, 2, 1], [n-2, n-3, ..., 7], 5, n-1, 4, 6] is valid.
If n mod 60 is 23 then [7, 1, n, 3, [n-2, n-3, ..., 8], 6, 5, n-1, 4, 2] is valid.
If n mod 60 is 14 or 34 then [3, 5, n-1, n, 1, [n-2, n-3, ..., 6], 4, 2] is valid.
If n mod 60 is 24 then [6, 5, n, 2, [n-2, n-1, ..., 7], 3, 1, n-1, 4] is valid
If n mod 60 is 2, 6, 26, 42 and n >= 26 then [n, 3, n-1, 2, 1, [n-3, n-4, ..., 7], 5, n-2, 4, 6] is valid.
If n mod 60 is 16 or 28 then [n, 1, n-1, 2, 3, [n-3, n-4, ..., 8], 6, 5, 7, 4, n-2] is valid.
If n mod 60 is 32 then [7, n, n-1, 2, 1, [n-2, n-3, ..., 8], 5, 4, 3, 6] is valid.
If n mod 60 is 35 or 47 then [5, n, 3, n-2, n-1, 1, [n-3, n-4, ..., 6], 4, 2] is valid.
If n mod 60 is 37 then [6, 5, 2, 1, [n-2, n-1, ..., 7], n-1, n, 3, 4]
If n mod 60 is 38 then [3, 7, n-1, n, 1] + [n-2, n-3, ..., 8] + [6, 4, 5, 2]
If n mod 60 is 40 then [5, 2, 1, [n-2, n-3, ..., 8], 3, 7, n, 4, 6, n-1] is valid
If n mod 60 is 0 and n >= 60 then [3, 5, n, 2, [n-2, n-3, ..., 7], 1, 6, n-1, 4] is valid
If n mod 60 is 7, 19, or 31 and n >= 19 then [4, n, 3, n-2, n-1, 1, [n-3, n-4, ..., 7], 5, 6, 2] is valid
If n mod 60 is 23, 38, or 43 then [7, 3, n, 1, [n-2, n-3, ..., 8], 6, 5, n-1, 4, 2] is a valid solution
If n mod 60 is 14 or 44 and n >= 74 then [3, 5, n-1, n, 1, [n-3, n-4, ..., 6], n-2, 4, 2] is valid.
If n mod 60 is 1 or 49 and n >= 49 then [3, 5, n, 1, [n-2, n-3, ..., 7], 2, n-1, 4, 6] is valid.
If n mod 60 is 6, 18, 30, 42, or 54 and n >= 18 then [n, 3, n-1, 2, 1, [n-3, n-4, ..., 7], 5, 4, n-2, 6] is valid.
If n mod 60 is 10, 18, 38 or 58 and n >= 18 then [n-1, 7, 5, n, 1, [n-2, n-3, ..., 8], 2, 6, 4, 3] is valid.
Currently solved for n mod 60 is any of the following values:
0, 1, 2, 3, 5, 6, 7, 9,
10, 11, 14, 15, 16, 17, 18, 19,
21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 37, 38, 39,
40, 41, 42, 43, 44, 45, 47, 49,
50, 51, 52, 53, 54, 57, 58
Also,
If n mod 42 is 31 then [n, 3, 2, 1, [n-2, n-3, ..., 8], n-1, 5, 4, 7, 6] is valid.
If n mod 420 is 36 or 396 then [n-1, 7, 3, 1, n, 2, [n-2, n-3, ..., 9], 6, 5, 4, 8] is valid.
--- Example for n=21, using the first pattern listed above, and all starting indices.
1: [21, 2, 18, 19, 16, 17, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 5, 4, 20, 1]
2: [ 2, 18, 21, 16, 19, 14, 17, 12, 15, 10, 13, 8, 11, 6, 9, 5, 1, 4, 20, 7]
3: [19, 21, 18, 2, 16, 17, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 5, 4, 20, 1]
4: [18, 21, 19, 17, 2, 15, 16, 13, 14, 11, 12, 9, 10, 7, 8, 1, 5, 4, 20, 6]
5: [17, 21, 19, 18, 16, 2, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 5, 4, 20, 1]
6: [16, 21, 19, 18, 17, 15, 2, 13, 14, 11, 12, 9, 10, 7, 8, 1, 5, 4, 20, 6]
7: [15, 21, 19, 18, 17, 16, 14, 2, 12, 13, 10, 11, 8, 9, 6, 7, 5, 4, 20, 1]
8: [14, 21, 19, 18, 17, 16, 15, 13, 2, 11, 12, 9, 10, 7, 8, 1, 5, 4, 20, 6]
9: [13, 21, 19, 18, 17, 16, 15, 14, 12, 2, 10, 11, 8, 9, 6, 7, 5, 4, 20, 1]
10: [12, 21, 19, 18, 17, 16, 15, 14, 13, 11, 2, 9, 10, 7, 8, 1, 5, 4, 20, 6]
11: [11, 21, 19, 18, 17, 16, 15, 14, 13, 12, 10, 2, 8, 9, 6, 7, 5, 4, 20, 1]
12: [10, 21, 19, 18, 17, 16, 15, 14, 13, 12, 11, 9, 2, 7, 8, 1, 5, 4, 20, 6]
13: [ 9, 21, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 8, 2, 6, 7, 5, 4, 20, 1]
14: [ 8, 21, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 7, 2, 1, 5, 4, 20, 6]
15: [ 7, 21, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 6, 2, 5, 4, 20, 1]
16: [ 6, 21, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 1, 5, 4, 20, 2]
17: [ 1, 5, 2, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 4, 19, 20, 21]
18: [ 5, 2, 18, 19, 16, 17, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 1, 20, 21]
19: [ 4, 2, 18, 19, 16, 17, 14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 5, 20, 21, 1]
20: [20, 4, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 1, 5, 21, 2]
You can observe the same relationship between elements from the decrementing run and other elements for all values of n that the pattern applies to. This isn't a proof, but you can turn this into a proof, though I think the work would need to be done for each pattern separately and it's beyond the scope of what I'm going to spend time on for an S/O question.
--- We can fill in the blanks by using m > n. ---
The pattern [n-1, n, 1, [n-2, n-3, ..., 3], n+5] is valid for n mod 4 is 1 and n >= 9.
The pattern [n, 2, 1, [n-2, n-3, ..., 3], n+4] is valid for n mod 2 is 0 and n >= 6.
With these two, plus what we already found, we get nearly everything. I found these by checking a single replacement value in a limited range.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 56, 57, 58
If n mod 30 is 29, then [3, n, 2, [n-2, n-3, ..., 4], n-1, n+15) is valid, giving us n mod 60 is 59. We're left with just one unknown: n mod 60 is 55.
...And finally! If n mod 12 is 7 (i.e. n mod 60 is 7, 19, 31, 43, or 55) then [n-1, n, 1, [n-2, n-3, ..., 6], 2, 5, 3, n+4] is valid for all n >= 19.
We now have solutions for all n mod 60, using m=n in most cases, and m=n+15 in the worst case.

tarantool pairs fetch not all tuples

box.space.test.index.secondary:select({1,'RU', 2})
---
- - [47, 6, 1, 'RU', 2, 11, 6]
- [44, 3, 1, 'RU', 2, 101, 6]
- [42, 1, 1, 'RU', 2, 189, 6]
- [34, 3, 1, 'RU', 2, 260, 5]
- [49, 8, 1, 'RU', 2, 290, 6]
- [41, 0, 1, 'RU', 2, 303, 6]
- [37, 6, 1, 'RU', 2, 494, 5]
- [35, 4, 1, 'RU', 2, 633, 5]
- [45, 4, 1, 'RU', 2, 694, 6]
- [43, 2, 1, 'RU', 2, 780, 6]
- [46, 5, 1, 'RU', 2, 833, 6]
- [40, 9, 1, 'RU', 2, 870, 5]
- [48, 7, 1, 'RU', 2, 927, 6]
- [50, 9, 1, 'RU', 2, 930, 6]
...
box.space.test.index.secondary
---
- unique: false
parts:
- type: NUM
fieldno: 3
- type: STR
fieldno: 4
- type: NUM
fieldno: 5
- type: NUM
fieldno: 6
id: 2
space_id: 512
name: secondary
type: TREE
...
local r='' for k,tuple in box.space.test.index.secondary:pairs({1, 'RU', 2}) do r=r..', found ('..tuple[1]..')' if (tuple[7]<6) then r = r .. ', delete(' ..tuple[1] .. ')' box.space.test:delete(tuple[1]) end end return r
---
- ', found (47), found (44), found (42), found (34), delete(34), found (41), found(37), delete(37), found (45), found (43), found (46), found (40), delete(40), found(50)'
...
box.space.test.index.secondary:select({1,'RU', 2})
---
- - [47, 6, 1, 'RU', 2, 11, 6]
- [44, 3, 1, 'RU', 2, 101, 6]
- [42, 1, 1, 'RU', 2, 189, 6]
- [49, 8, 1, 'RU', 2, 290, 6]
- [41, 0, 1, 'RU', 2, 303, 6]
- [35, 4, 1, 'RU', 2, 633, 5]
- [45, 4, 1, 'RU', 2, 694, 6]
- [43, 2, 1, 'RU', 2, 780, 6]
- [46, 5, 1, 'RU', 2, 833, 6]
- [48, 7, 1, 'RU', 2, 927, 6]
- [50, 9, 1, 'RU', 2, 930, 6]
...
local r='' for k,tuple in box.space.test.index.secondary:pairs({1, 'RU', 2}) do r=r..', found ('..tuple[1]..')' if (tuple[7]<6) then r = r .. ', delete(' ..tuple[1] .. ')' box.space.test:delete(tuple[1]) end end return r
---
- ', found (47), found (44), found (42), found (49), found (41), found (35), delete(35), found (43), found (46), found (48), found (50)'
...
box.space.test.index.secondary:select({1,'RU', 2})
---
- - [47, 6, 1, 'RU', 2, 11, 6]
- [44, 3, 1, 'RU', 2, 101, 6]
- [42, 1, 1, 'RU', 2, 189, 6]
- [49, 8, 1, 'RU', 2, 290, 6]
- [41, 0, 1, 'RU', 2, 303, 6]
- [45, 4, 1, 'RU', 2, 694, 6]
- [43, 2, 1, 'RU', 2, 780, 6]
- [46, 5, 1, 'RU', 2, 833, 6]
- [48, 7, 1, 'RU', 2, 927, 6]
- [50, 9, 1, 'RU', 2, 930, 6]
...
As I see :pairs don't see 35 tuple in first run, and see it only on second execution. Why?
p.s.: sorry for long explanation...

Reformat text file using awk or sed

I have a text data file that looks like below:
Day-Hour, 08188, 0, 08188, 1, (indicating the time is year 2008, julian day 188, between hour0 and hour1)
Receptor, A, (actual data begins)
1, 2, 3, 4,
5, 6, 7, 8,
Receptor, B,
1, 2, 3, 4,
5, 6, 7, 8,
... (continue data for a total of 22 receptors, each receptor has 8 data values)
Day-Hour, 08188, 1, 08188, 2,
Receptor, A,
1, 2, 3, 4,
5, 6, 7, 8,
Receptor, B,
1, 2, 3, 4,
5, 6, 7, 8,
... (continue data for a total of 22 receptors, each receptor has 8 data values, but this is for hours 1 to 2)
...... (continue the same previous pattern for a total of 24 times)
I'd like to reformat it to be like this:
day, time, receptor, data1, data2, data3, ....data8 (header)
08188, 0, A, 1, 2, 3, 4, 5, 6, 7, 8
08188, 0, B, 1, 2, 3, 4, 5, 6, 7, 8
... (repeat the same hour for all 22 receptor sites)
08188, 1, A, 1, 2, 3, 4, 5, 6, 7, 8
08188, 1, B, 1, 2, 3, 4, 5, 6, 7, 8
...(repeat the same hour for all 22 receptor sites)
...
...(repeat the same order 24 times)
I've managed to achieve the format I want through a couple of steps using combinations of awk and sed with something like below, but I feel it's kind of dumb to go through so many steps, and am hoping for experts' help to approach this in a much simpler step. Your inputs are greatly appreciated!
(example steps:)
step1: $ grep -v "Day-Hour" infile.txt > temp1.txt # remove all Day-Hour lines,
# as I know the order of the data
step2: $ sed '/^$/d' temp1.txt > temp2.txt # remove empty lines
step3: $ awk 'ORS=NR%3" ":"\n"' temp2.txt > temp3.txt #concatenate every 3 lines
step4: $ (create a file, e.g. daytime.txt, with 2 fields (day and hour) with following content)
08188, 0,
(repeat 22 times)
08188, 1,
(repeat 22 times)
.... (continue through hour 23)
step5: $ paste daytime.txt temp3.txt > final.txt
This may do the job:
cat file
Day-Hour, 08188, 0, 08188, 1
Receptor, A,
1, 2, 3, 4,
5, 6, 7, 8,
Receptor, B,
11, 12, 13, 14,
15, 16, 17, 18,
Receptor, C,
21, 22, 23, 24,
25, 26, 27, 28,
Day-Hour, 08188, 1, 08188, 2
Receptor, A,
1, 2, 3, 4,
5, 6, 7, 8,
Receptor, B,
1, 2, 3, 4,
5, 6, 7, 8,
awk -v RS= -v OFS=", " -F", *|\n" 'BEGIN {print "day, time, receptor, data1, data2, data3,....data8"} {for (i=7;i<=NF;i+=13) print $2,$3,$i,$(i+2),$(i+3),$(i+4),$(i+5),$(i+7),$(i+8),$(i+9),$(i+10)}' file
day, time, receptor, data1, data2, data3,....data8
08188, 0, A, 1, 2, 3, 4, 5, 6, 7, 8
08188, 0, B, 11, 12, 13, 14, 15, 16, 17, 18
08188, 0, C, 21, 22, 23, 24, 25, 26, 27, 28
08188, 1, A, 1, 2, 3, 4, 5, 6, 7, 8
08188, 1, B, 1, 2, 3, 4, 5, 6, 7, 8
This will print all Receptor, if its 1 or 22.
This will join them up:
sed 's/$/,/;N;N;N;N;N;N;N; s/\n/ /g' foo.txt
into this:
Day-Hour, 08188, 0, 08188, 1, Receptor, A, 1, 2, 3, 4, 5, 6, 7, 8,
Receptor, B, 1, 2, 3, 4, 5, 6, 7, 8, Day-Hour, 08188, 1, 08188, 2,
Receptor, A, 1, 2, 3, 4, 5, 6, 7, 8, Receptor, B, 1, 2, 3, 4, 5, 6, 7,
8,
Then I got lazy in the repackaging:
... | awk '{ $1 = ""; $4 = ""; $5 = ""; print }' | sed -e 's/ \(.*\) Receptor, \(A,.*\)Receptor, \(B, .*\)/\1\2\n\1\3/'
Which producd the desired output on my system.

index inside for loop in python 3.1

I can't understand a behavior .index method inside for loop
(Python 3.3.1 (v3.3.1:d9893d13c628, Apr 6 2013, 20:30:21) [MSC v.1600 64 bit (AMD64)] on win32)
L = [e for e in range(11)]
print(L)
for e in L[:]:
print(e, L.index(e))
L[L.index(e)] *= e
print(L)
output:
>>>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
0 0
1 1
2 2
3 3
4 2
5 5
6 6
7 7
8 8
9 3
10 10
[0, 1, 16, 81, 4, 25, 36, 49, 64, 9, 100]
>>>
I expected the final list [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
By the time you hit 4, your list is [0, 1, 4, 9, 4, 5, 6, 7, 8, 9, 10], having replaced the first 3 elements. .index() finds the first occurence of 4, at index 2, not 5, as you appear to be expecting. The same goes for 9; you already replaced 3 with 9 earlier in the loop and L.index(9) returns 3 instead of 10.
Don't use list.index() on a changing list; use enumerate() instead:
L = [e for e in range(11)]
print(L)
for i, e in enumerate(L[:]):
print(e, i)
L[i] *= e
print(L)
which then results in:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
You can replace [e for e in range(11)] with a simple list(range(11)). And you can replace your whole script with:
[e * e for e in range(11)]

Algorithm to distribute according to weights, with unknown total of items, guaranteeing good distribution?

I want to distribute tokens into 3 slots.
Each slot has some weight: maybe 50% of tokens should go into the first slot, 30% should go into the second slot, 20% into the third slot.
I don't know the total number of tokens – they keep on coming. I may get 1000 tokens to distribute at noon, I get another 300 at 1 p.m. and so on, unpredictably. At any point in time, the tokens I have received so far should be distributed as well as possible according to the weights.
One solution is to distribute by probabilities. I roll a 100-sided die for each token. If the result is 1–50, the token goes in slot 1. A result of 51–80 mean slot 2, a result of 81–100 mean slot 3.
But this means that it's not impossible (only improbable) that every single token ends up in slot 3, for example.
I want to guarantee that when I've received a total of 100 tokens, then exactly 50 of them will be in slot 1. When I've received 1000 tokens, exactly 500 should be in slot 1.
What is a good algorithm for this?
Calculate the error in each slot according to what the ideal distribution is. Always insert a token into the slot with the most error. If two or more slots are tied, insert into a random one among them.
The error is the difference between the expected number of tokens (tokens added * ratio) and the actual number of tokens.
This way you will always minimize error, and there will be no error if the tokens are able to be distributed exactly.
Demonstration code (this inserts into the first slot if there is equal amount of error instead of distributing randomly):
import random
tokens_in_slots = [0, 0, 0]
slot_distributions = [0.5, 0.3, 0.2]
def add_token():
num_tokens = sum(tokens_in_slots)
if not num_tokens:
#first token can go anywhere
tokens_in_slots[random.randint(0,2)] += 1
return
expected_tokens = [num_tokens*distr for distr in slot_distributions]
errors = [expected - actual
for expected, actual in zip(expected_tokens, tokens_in_slots)]
most_error = max(enumerate(errors), key=lambda (i,e): e)
tokens_in_slots[most_error[0]] += 1
def add_and_print(n):
for i in xrange(n):
add_token()
print sum(tokens_in_slots), tokens_in_slots
Result:
>>> add_and_print(100)
1 [0, 0, 1]
2 [1, 0, 1]
3 [1, 1, 1]
4 [2, 1, 1]
5 [2, 2, 1]
6 [3, 2, 1]
7 [3, 2, 2]
8 [4, 2, 2]
9 [4, 3, 2]
10 [5, 3, 2]
11 [6, 3, 2]
12 [6, 4, 2]
13 [6, 4, 3]
14 [7, 4, 3]
15 [7, 5, 3]
16 [8, 5, 3]
17 [8, 5, 4]
18 [9, 5, 4]
19 [9, 6, 4]
20 [10, 6, 4]
21 [11, 6, 4]
22 [11, 7, 4]
23 [11, 7, 5]
24 [12, 7, 5]
25 [12, 8, 5]
26 [13, 8, 5]
27 [13, 8, 6]
28 [14, 8, 6]
29 [14, 9, 6]
30 [15, 9, 6]
31 [16, 9, 6]
32 [16, 10, 6]
33 [16, 10, 7]
34 [17, 10, 7]
35 [17, 11, 7]
36 [18, 11, 7]
37 [18, 11, 8]
38 [19, 11, 8]
39 [19, 12, 8]
40 [20, 12, 8]
41 [21, 12, 8]
42 [21, 13, 8]
43 [21, 13, 9]
44 [22, 13, 9]
45 [22, 14, 9]
46 [23, 14, 9]
47 [23, 14, 10]
48 [24, 14, 10]
49 [24, 15, 10]
50 [25, 15, 10]
51 [26, 15, 10]
52 [26, 16, 10]
53 [26, 16, 11]
54 [27, 16, 11]
55 [27, 17, 11]
56 [28, 17, 11]
57 [28, 17, 12]
58 [29, 17, 12]
59 [29, 18, 12]
60 [30, 18, 12]
61 [31, 18, 12]
62 [31, 19, 12]
63 [31, 19, 13]
64 [32, 19, 13]
65 [32, 20, 13]
66 [33, 20, 13]
67 [33, 20, 14]
68 [34, 20, 14]
69 [34, 21, 14]
70 [35, 21, 14]
71 [36, 21, 14]
72 [36, 22, 14]
73 [36, 22, 15]
74 [37, 22, 15]
75 [37, 23, 15]
76 [38, 23, 15]
77 [38, 23, 16]
78 [39, 23, 16]
79 [39, 24, 16]
80 [40, 24, 16]
81 [41, 24, 16]
82 [41, 25, 16]
83 [41, 25, 17]
84 [42, 25, 17]
85 [42, 26, 17]
86 [43, 26, 17]
87 [43, 26, 18]
88 [44, 26, 18]
89 [44, 27, 18]
90 [45, 27, 18]
91 [46, 27, 18]
92 [46, 28, 18]
93 [46, 28, 19]
94 [47, 28, 19]
95 [47, 29, 19]
96 [48, 29, 19]
97 [48, 29, 20]
98 [49, 29, 20]
99 [49, 30, 20]
100 [50, 30, 20]
Results for
tokens_in_slots = [0, 0, 0, 0]
slot_distributions = [0.8, 0.1, 0.05, 0.05]
:
>>> add_and_print(100)
1 [0, 0, 1, 0]
2 [1, 0, 1, 0]
3 [2, 0, 1, 0]
4 [3, 0, 1, 0]
5 [3, 1, 1, 0]
6 [4, 1, 1, 0]
7 [5, 1, 1, 0]
8 [6, 1, 1, 0]
9 [7, 1, 1, 0]
10 [7, 1, 1, 1]
11 [8, 1, 1, 1]
12 [9, 1, 1, 1]
13 [10, 1, 1, 1]
14 [11, 1, 1, 1]
15 [11, 2, 1, 1]
16 [12, 2, 1, 1]
17 [13, 2, 1, 1]
18 [14, 2, 1, 1]
19 [15, 2, 1, 1]
20 [16, 2, 1, 1]
21 [17, 2, 1, 1]
22 [17, 3, 1, 1]
23 [18, 3, 1, 1]
24 [19, 3, 1, 1]
25 [20, 3, 1, 1]
26 [20, 3, 2, 1]
27 [21, 3, 2, 1]
28 [22, 3, 2, 1]
29 [23, 3, 2, 1]
30 [23, 3, 2, 2]
31 [24, 3, 2, 2]
32 [25, 3, 2, 2]
33 [26, 3, 2, 2]
34 [27, 3, 2, 2]
35 [27, 4, 2, 2]
36 [28, 4, 2, 2]
37 [29, 4, 2, 2]
38 [30, 4, 2, 2]
39 [31, 4, 2, 2]
40 [32, 4, 2, 2]
41 [33, 4, 2, 2]
42 [33, 5, 2, 2]
43 [34, 5, 2, 2]
44 [35, 5, 2, 2]
45 [36, 5, 2, 2]
46 [36, 5, 3, 2]
47 [37, 5, 3, 2]
48 [38, 5, 3, 2]
49 [39, 5, 3, 2]
50 [39, 5, 3, 3]
51 [40, 5, 3, 3]
52 [41, 5, 3, 3]
53 [42, 5, 3, 3]
54 [43, 5, 3, 3]
55 [43, 6, 3, 3]
56 [44, 6, 3, 3]
57 [45, 6, 3, 3]
58 [46, 6, 3, 3]
59 [47, 6, 3, 3]
60 [48, 6, 3, 3]
61 [49, 6, 3, 3]
62 [49, 7, 3, 3]
63 [50, 7, 3, 3]
64 [51, 7, 3, 3]
65 [52, 7, 3, 3]
66 [52, 7, 4, 3]
67 [53, 7, 4, 3]
68 [54, 7, 4, 3]
69 [55, 7, 4, 3]
70 [55, 7, 4, 4]
71 [56, 7, 4, 4]
72 [57, 7, 4, 4]
73 [58, 7, 4, 4]
74 [59, 7, 4, 4]
75 [59, 8, 4, 4]
76 [60, 8, 4, 4]
77 [61, 8, 4, 4]
78 [62, 8, 4, 4]
79 [63, 8, 4, 4]
80 [64, 8, 4, 4]
81 [65, 8, 4, 4]
82 [65, 9, 4, 4]
83 [66, 9, 4, 4]
84 [67, 9, 4, 4]
85 [68, 9, 4, 4]
86 [68, 9, 5, 4]
87 [69, 9, 5, 4]
88 [70, 9, 5, 4]
89 [71, 9, 5, 4]
90 [71, 9, 5, 5]
91 [72, 9, 5, 5]
92 [73, 9, 5, 5]
93 [74, 9, 5, 5]
94 [75, 9, 5, 5]
95 [75, 10, 5, 5]
96 [76, 10, 5, 5]
97 [77, 10, 5, 5]
98 [78, 10, 5, 5]
99 [79, 10, 5, 5]
100 [80, 10, 5, 5]
The solution that springs to my mind:
Give every slot a computed score. Put the token in the slot with the highest score. If more than one share that score, I don't care whether we pick the first one or a random one.
The computed score would be calculated something like the following Ruby/pseudo-code:
# Example values
# Floats to avoid integer division
slot_1_weight = 50.0
total_weight = 100.0
slot_1_tokens = 2.0
total_tokens = 3.0
if total_tokens == 0 || total_weight == 0 || slot_1_tokens
# Avoid division by zero.
slot_1_score = slot_1_weight
else
expected_distribution = slot_1_weight/total_weight
actual_distribution = slot_1_tokens/total_tokens
slot_1_score = slot_1_weight * (expected_distribution/actual_distribution)
end
So when expected and actual match, the score is the original weight. If expected is too high, the weight is scaled down. If expected is too low, the weight is scaled up.

Resources