June 2018 Update
This commit is contained in:
parent
ba8067c3b7
commit
22f33d4004
5278 changed files with 84726 additions and 14379 deletions
|
|
@ -1,23 +1,29 @@
|
|||
This is a method of randomly sampling n items from a set of M items, with equal probability; where M >= n and M, the number of items is unknown until the end.
|
||||
This means that the equal probability sampling should be maintained for all successive items > n as they become available (although the content of successive samples can change).
|
||||
|
||||
|
||||
;The algorithm:
|
||||
# Select the first n items as the sample as they become available;
|
||||
# For the i-th item where i > n, have a random chance of n/i of keeping it. If failing this chance, the sample remains the same. If not, have it randomly (1/n) replace one of the previously selected n items of the sample.
|
||||
# Repeat #2 for any subsequent items.
|
||||
:* Select the first n items as the sample as they become available;
|
||||
:* For the i-th item where i > n, have a random chance of n/i of keeping it. If failing this chance, the sample remains the same. If not, have it randomly (1/n) replace one of the previously selected n items of the sample.
|
||||
:* Repeat 2<sup>nd</sup> step for any subsequent items.
|
||||
|
||||
|
||||
;The Task:
|
||||
# Create a function <code>s_of_n_creator</code> that given <math>n</math> the maximum sample size, returns a function <code>s_of_n</code> that takes one parameter, <code>item</code>.
|
||||
# Function <code>s_of_n</code> when called with successive items returns an equi-weighted random sample of up to n of its items so far, each time it is called, calculated using Knuths Algorithm S.
|
||||
# Test your functions by printing and showing the frequency of occurrences of the selected digits from 100,000 repetitions of:
|
||||
:# Use the s_of_n_creator with n == 3 to generate an s_of_n.
|
||||
:# call s_of_n with each of the digits 0 to 9 in order, keeping the returned three digits of its random sampling from its last call with argument item=9.
|
||||
:* Create a function <code>s_of_n_creator</code> that given <math>n</math> the maximum sample size, returns a function <code>s_of_n</code> that takes one parameter, <code>item</code>.
|
||||
:* Function <code>s_of_n</code> when called with successive items returns an equi-weighted random sample of up to n of its items so far, each time it is called, calculated using Knuths Algorithm S.
|
||||
:* Test your functions by printing and showing the frequency of occurrences of the selected digits from 100,000 repetitions of:
|
||||
:::# Use the s_of_n_creator with n == 3 to generate an s_of_n.
|
||||
:::# call s_of_n with each of the digits 0 to 9 in order, keeping the returned three digits of its random sampling from its last call with argument item=9.
|
||||
|
||||
|
||||
Note: A class taking n and generating a callable instance/function might also be used.
|
||||
|
||||
|
||||
;Reference:
|
||||
* The Art of Computer Programming, Vol 2, 3.4.2 p.142
|
||||
|
||||
;Cf.
|
||||
|
||||
;Related tasks:
|
||||
* [[One of n lines in a file]]
|
||||
* [[Accumulator factory]]
|
||||
<br><br>
|
||||
|
|
|
|||
|
|
@ -1,35 +1,26 @@
|
|||
function makesofn(n::Int)
|
||||
buf = Any[]
|
||||
function makesofn(n::Integer)
|
||||
buf = Vector{typeof(n)}(0)
|
||||
i = 0
|
||||
function sofn(item)
|
||||
return function sofn(item)
|
||||
i += 1
|
||||
if i <= n
|
||||
if i ≤ n
|
||||
push!(buf, item)
|
||||
else
|
||||
j = rand(1:i)
|
||||
if j <= n
|
||||
buf[j] = item
|
||||
end
|
||||
if j ≤ n buf[j] = item end
|
||||
end
|
||||
return buf
|
||||
end
|
||||
return sofn
|
||||
end
|
||||
|
||||
|
||||
nhist = zeros(Int, 10)
|
||||
|
||||
for i in 1:10^5
|
||||
for _ in 1:10^5
|
||||
kas = makesofn(3)
|
||||
for j in 0:8
|
||||
kas(j)
|
||||
end
|
||||
for k in kas(9)
|
||||
nhist[k+1] += 1
|
||||
end
|
||||
for j in 0:8 kas(j) end
|
||||
for k in kas(9) nhist[k+1] += 1 end
|
||||
end
|
||||
|
||||
println("Simulating sof3(0:9) 100000 times:")
|
||||
for (i, c) in enumerate(nhist)
|
||||
println(@sprintf " %2d => %5d" i-1 c)
|
||||
@printf("%5d → %5d\n", i-1, c)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,40 +1,39 @@
|
|||
/*REXX program using Knuth's algorithm S (a random sampling N of M items).*/
|
||||
parse arg trials size . /*obtain optional arguments from the CL*/
|
||||
if trials=='' then trials=100000 /*Not specified? Then use the default.*/
|
||||
if size=='' then size= 3 /* " " " " " " */
|
||||
#.=0 /*initialize frequency counter array. */
|
||||
do trials /*OK, now let's light this candle. */
|
||||
call s_of_n_creator size /*create an initial list of N items. */
|
||||
/*REXX program using Knuth's algorithm S (a random sampling N of M items). */
|
||||
parse arg trials size . /*obtain optional arguments from the CL*/
|
||||
if trials=='' | trials=="," then trials=100000 /*Not specified? Then use the default.*/
|
||||
if size=='' | size=="," then size= 3 /* " " " " " " */
|
||||
#.=0 /*initialize frequency counter array. */
|
||||
do trials /*OK, now let's light this candle. */
|
||||
call s_of_n_creator size /*create an initial list of N items. */
|
||||
|
||||
do gener=0 for 10
|
||||
call s_of_n gener /*call s_of_n with a single decimal dig*/
|
||||
end /*gener*/
|
||||
do gener=0 for 10
|
||||
call s_of_n gener /*call s_of_n with a single decimal dig*/
|
||||
end /*gener*/
|
||||
|
||||
do count=1 for size /*let's examine what SofN generated. */
|
||||
_=!.count /*get a decimal digit from the Nth */
|
||||
#._=#._+1 /* ··· item, and count it, of course.*/
|
||||
end /*count*/
|
||||
end /*trials*/
|
||||
@='trials, and with size='
|
||||
say "Using Knuth's algorithm S for" commas(trials) @ || commas(size)":"
|
||||
say
|
||||
do dig=0 to 9 /* [↓] display the frequency of a dig.*/
|
||||
say left('',20) "frequency of the" dig 'digit is:' commas(#.dig)
|
||||
end /*dig*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
commas: procedure; parse arg _; n=_'.9'; #=123456789; b=verify(n,#,"M")
|
||||
e=verify(n, #'0', , verify(n, #"0.", 'M')) - 4
|
||||
do j=e to b by -3; _=insert(',',_,j); end /*j*/; return _
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
s_of_n: parse arg item; items=items+1 /*get "item", bump the items counter.*/
|
||||
c=random(1, items) /* [↓] should replace a previous item?*/
|
||||
if c>size then return /*probability isn't good, so skip it. */
|
||||
_=random(1, size); !._=item /*now, figure out which previous ··· */
|
||||
return /* ··· item to replace with ITEM.*/
|
||||
/*────────────────────────────────────────────────────────────────────────────*/
|
||||
s_of_n_creator: parse arg item 1 items /*generate ITEM number of items. */
|
||||
do k=1 for item /*traipse through the first N items. */
|
||||
!.k=random(0, 9) /*set the Kth item with random digit.*/
|
||||
end /*k*/
|
||||
return /*the piddly stuff is done (for now). */
|
||||
/* [↓] examine what SofN generated. */
|
||||
do count=1 for size; _= !.count /*get a dec. digit from the Nth item. */
|
||||
#._=#._ + 1 /*bump counter for the decimal digit. */
|
||||
end /*count*/
|
||||
end /*trials*/
|
||||
@= ' trials, and with a size of '
|
||||
hdr=" Using Knuth's algorithm S for " commas(trials) @ || commas(size)": "
|
||||
say hdr; say copies("═", length(hdr) ) /*display the header and its separator.*/
|
||||
|
||||
do dig=0 to 9 /* [↓] display the frequency of a dig.*/
|
||||
say left('', 20) "frequency of the" dig 'digit is: ' commas(#.dig)
|
||||
end /*dig*/
|
||||
exit /*stick a fork in it, we're all done. */
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
commas: parse arg _; do jc=length(_)-3 to 1 by -3; _=insert(',', _, jc); end; return _
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
s_of_n: parse arg item; items=items + 1 /*get "item", bump the items counter.*/
|
||||
c=random(1, items) /* [↓] should replace a previous item?*/
|
||||
if c>size then return /*probability isn't good, so skip it. */
|
||||
_=random(1, size); !._=item /*now, figure out which previous ··· */
|
||||
return /* ··· item to replace with ITEM.*/
|
||||
/*──────────────────────────────────────────────────────────────────────────────────────*/
|
||||
s_of_n_creator: parse arg item 1 items /*generate ITEM number of items. */
|
||||
do k=1 for item /*traipse through the first N items. */
|
||||
!.k=random(0, 9) /*set the Kth item with random digit.*/
|
||||
end /*k*/
|
||||
return /*the piddly stuff is done (for now). */
|
||||
|
|
|
|||
46
Task/Knuths-algorithm-S/Rust/knuths-algorithm-s.rust
Normal file
46
Task/Knuths-algorithm-S/Rust/knuths-algorithm-s.rust
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
use rand::{Rng,weak_rng};
|
||||
|
||||
struct SofN<R: Rng+Sized, T> {
|
||||
rng: R,
|
||||
sample: Vec<T>,
|
||||
i: usize,
|
||||
n: usize,
|
||||
}
|
||||
|
||||
impl<R: Rng, T> SofN<R, T> {
|
||||
fn new(rng: R, n: usize) -> Self {
|
||||
SofN{rng, sample: Vec::new(), i: 0, n}
|
||||
}
|
||||
|
||||
fn add(&mut self, item: T) {
|
||||
self.i += 1;
|
||||
if self.i <= self.n {
|
||||
self.sample.push(item);
|
||||
} else if self.rng.gen_range(0, self.i) < self.n {
|
||||
self.sample[self.rng.gen_range(0, self.n)] = item;
|
||||
}
|
||||
}
|
||||
|
||||
fn sample(&self) -> &Vec<T> {
|
||||
&self.sample
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn main() {
|
||||
const MAX: usize = 10;
|
||||
let mut bin: [i32; MAX] = Default::default();
|
||||
for _ in 0..100000 {
|
||||
let mut s_of_n = SofN::new(weak_rng(), 3);
|
||||
|
||||
for i in 0..MAX { s_of_n.add(i); }
|
||||
|
||||
for s in s_of_n.sample() {
|
||||
bin[*s] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (i, x) in bin.iter().enumerate() {
|
||||
println!("frequency of {}: {}", i, x);
|
||||
}
|
||||
}
|
||||
21
Task/Knuths-algorithm-S/Scala/knuths-algorithm-s.scala
Normal file
21
Task/Knuths-algorithm-S/Scala/knuths-algorithm-s.scala
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import java.util
|
||||
import scala.util.Random
|
||||
|
||||
object KnuthsAlgorithmS extends App {
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
|
||||
val (n, rand, bin) = (3, Random, new Array[Int](10))
|
||||
|
||||
for (_ <- 0 until 100000) {
|
||||
val sample = new util.ArrayList[Int](n)
|
||||
for (item <- 0 until 10) {
|
||||
if (item < n) sample.add(item)
|
||||
else if (rand.nextInt(item + 1) < n)
|
||||
sample.asScala(rand.nextInt(n)) = item
|
||||
}
|
||||
for (s <- sample.asScala.toList) bin(s) += 1
|
||||
}
|
||||
|
||||
println(bin.mkString("[", ", ", "]"))
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue