//my stupid expectation formula requires iterating over all sequences in {0,...,n-1}^k. //the following two functions let us do that by iterating instead over {0,...,n^k -1}, //which is significantly easier. //this takes a number a between 0 and base^power - 1 (inclusive) and converts it into //the corresponding natural sequence embedded in {0,...,base}^power. int[int] to_sequence(int a, int base, int power){ int[int] seq; int leftovers = a; //doesn't matter for our purposes whether we preserve orientation, so we might not. for i from 1 to (power){ seq[power-i] = leftovers/(base**(power - i)); //debugging. //print((base**(power - i))+" goes into "+leftovers+" this many times: "+seq[power-i]); leftovers -= seq[power-i]* (base**(power - i)); } return seq; } //turns those sequences into sets for cleaner use in foreach loops. boolean[int] to_set(int[int] seq){ boolean[int] set; foreach i in seq{ set[seq[i]] = true; } return set; } //for any appropriate number X, "foreach i in X.to_sequence(base,power).to_set()" iterates //i over precisely the unique digits found in the sequence corresponding to X. //if you don't discard the multiplicity here, the iteration becomes quite a bit messier. //Coding natural morphisms is tricky, huh? //the formula includes the multiplicity function, so we write that here. //this'll return the number of times a digit j appears in the sequence seq. int mult(int[int] seq, int j){ int count; foreach i in seq{ if(seq[i] == j){ count++; } } return count; } //phi is the underlying probability distribution. I guess we'll normalize it in this function //for ease of use (so any proportional distribution could be input). //r will be the rejection rate array with positions corresponding to entries in phi. //k will be queue length, since this can't be deduced from r and phi. float expectation(float[int] phi, float[int] r, int k){ //deduce size of outcome set from input rather than requiring that input. int n = count(phi); //normalize phi. float phisum = 0.0; foreach i in phi{ phisum += phi[i]; } foreach i in phi{ phi[i] /= phisum; } //so now phi is a probability distribution unless some sick fart put negative/complex values in. //so now we have to do this. https://i.imgur.com/DsYTyrd.png //the top and bottom are nearly identical, so we'll be computing these simultaneously //while leaving out that factor of #a from the summands on the bottom. float top_outer_sum = 0.0; float bottom_outer_sum = 0.0; float inner_sum; float indexed_product; int[int] index_seq; boolean[int] index_set; for index from 0 to ((n**k) -1){ clear(index_seq); clear(index_set); inner_sum = 0.0; indexed_product = 1.0; index_seq = to_sequence(index,n,k); index_set = to_set(index_seq); //make the inner sum. foreach j in index_set{ inner_sum += phi[j]*r[j]; } //do the 1- thing. inner_sum = 1 - inner_sum; //now make the indexed product. foreach j in index_set{ indexed_product *= ( ( phi[j]*(1-r[j]) ) ** mult(index_seq,j) ) / ( 1 - r[j] ); } //now we increment the bottom by those two things multiplied together. bottom_outer_sum += inner_sum * indexed_product ; //and increment the top by the same thing but with a factor of #a. top_outer_sum += inner_sum * indexed_product * count(index_set); } //smush the top and bottom together and return it. return (top_outer_sum / bottom_outer_sum ); } /* //check that this works by looking at dice. float[int] fee = {1,1,1,1,1,1}; float[int] arrr = {0,0,0,0,0,0}; float[int] herman_cain = {0.999,0.999,0.999,0.999,0.999,0.999}; print(expectation(fee , arrr ,1)); //the above should print the average number of unique die roll outcomes occurring //in the last 1 die rolls. If it's not 1.0, we're very sad. //dear lord it returns exactly 1.0. debugging stuff print("let\'s write "+122+" in base 5 with 4 digits"); int[int] boop = 122.to_sequence(5,4); foreach i in boop{ print(i+": "+boop[i]); } print("let\'s write "+69+" in base 3 with 11 digits"); boop = 69.to_sequence(3,11); foreach i in boop{ print(i+": "+boop[i]); } */ //let's make data for some very pretty graphs. float[float] data; float[int] fee = {1,1,1,1,1}; float[int] arrr = {0,0,0,0,0}; //graphing how much rejection rate matters to steady state frequency. for i from 1 to 8{ arrr[4] = 0.0; for j from 0 to 999{ arrr[4] += 0.001; data[arrr[4]] = expectation(fee,arrr,i)/(i.to_float()); } //when i is 1, this should generate a text file with a column of 1000 1.0's. //only letting script do that for debugging. map_to_file(data,"plot of normalized expected variety in uniform phi with rejection on one outcome for n=5 k="+i+".txt"); clear(data); print("done with making graph number "+i); }