Guest User

Untitled

a guest
May 22nd, 2018
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.62 KB | None | 0 0
  1. # ex: set ts=2:
  2. #
  3. # Copyright Ryan Flynn <parseerror@gmail.com>
  4. # Released under Public Domain. Use it! Credit would be nice.
  5. #
  6. # IdealHumanRandomIterator - select "random" members of a population, favoring
  7. # those least-recently selected, to appease silly humans who hate repeats
  8. #
  9. # Abstract:
  10. # given a decently-sized set of items (say, 100 famous quotes), an
  11. # average persons's idea of N "random" entries is not actually random.
  12. # people don't want items to appear twice in a row, or too frequently
  13. # (even though true randomness means this is just as likely as any other order).
  14. #
  15. # instead, design a scheme whereby LRU items are weighted more heavily,
  16. # to "encourage" subsequent selections to not repeat.
  17. #
  18. class IdealHumanRandomIterator
  19. @items = []
  20.  
  21. def initialize(list)
  22. @items = list
  23. end
  24.  
  25. # Given length L, generate a random number in the range [0,len-1), heavily
  26. # weighted towards the low end.
  27. def self.nexti(len)
  28. len += 1 if len % 2 == 1
  29. index = len > 2 ? rand(len/2) : 0
  30. return index
  31. end
  32.  
  33. # return a psuedo-random member of items. subsequent calls should never
  34. # return the same item.
  35. def next()
  36. index = IdealHumanRandomIterator.nexti(@items.length)
  37. @items.push @items.delete_at(index)
  38. return @items.last
  39. end
  40. end
  41.  
  42. if $0 == __FILE__
  43. puts "Unit tests..."
  44. N = 10
  45. p (0..N-1).map{|n| IdealHumanRandomIterator.nexti(N) }.sort.reverse
  46. puts "Range..."
  47. raise "nexti(0) must be 0" unless 0 == IdealHumanRandomIterator.nexti(0)
  48. raise "nexti(1) must be 0" unless 0 == IdealHumanRandomIterator.nexti(1)
  49. [0,1,2,4,8,16,32].each do |n|
  50. acc=[0]*10
  51. 500.times{ i=IdealHumanRandomIterator.nexti(1 << n);acc[i]=acc[i]+1 if i < acc.size }
  52. printf "2**%2u %3u [%s]\n", n, eval(acc.join("+")), acc.map{|x|sprintf "%3u", x}.join(" ")
  53. end
  54. puts "Complexity..."
  55. Pool = "0123456789".split(//)
  56. printf "%2s %3s %5s %s\n", "#", "Rep", "Cmplx", "String"
  57.  
  58. for i in (0..Pool.length-1)
  59. pool = Pool[0..i]
  60. ideal = IdealHumanRandomIterator.new(pool)
  61. n = (1..70).map{|_| ideal.next() }
  62. # for any pool of > 1 items we should have zero repeats
  63. repeats = n.length - n.to_s.gsub(/(.)\1+/, '\1').length
  64. complexity = n.to_s.gsub(/(.+?)\1+/, '\1')
  65. printf "%2u %3u %5d %s\n", i, repeats, complexity.length, n.to_s
  66. if i > 0
  67. #raise "No item should ever repeat" if repeats > 0
  68. if i > 2
  69. # for sets of more than 2 items check that the resulting string
  70. # is not a mere concatenation of a few duplicated substrings
  71. if complexity.length < n.length / 2
  72. puts complexity
  73. raise "Too non-random"
  74. end
  75. end
  76. end
  77. end
  78. puts "OK."
  79. end
Add Comment
Please, Sign In to add comment