00001 ## 00002 # 00003 # This module contains functions to do sampling with and without 00004 # replacement and random shuffling. The algorithms are from 00005 # Knuth, vol. 2, section 3.4.2. 00006 # 00007 # Copyright (C) 2002 GDS Software 00008 # 00009 # This program is free software; you can redistribute it and/or 00010 # modify it under the terms of the GNU General Public License as 00011 # published by the Free Software Foundation; either version 2 of 00012 # the License, or (at your option) any later version. 00013 # 00014 # This program is distributed in the hope that it will be useful, 00015 # but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 # GNU General Public License for more details. 00018 # 00019 # You should have received a copy of the GNU General Public 00020 # License along with this program; if not, write to the Free 00021 # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, 00022 # MA 02111-1307 USA 00023 # 00024 # See http://www.gnu.org/licenses/licenses.html for more details. 00025 # 00026 00027 import whrandom 00028 __version__ = "$Id: sample.py,v 1.4 2002/08/21 12:41:49 donp Exp $" 00029 00030 # Note: it's important to make the generator global. If you put it into 00031 # one of the functions and call that function rapidly, the generator will 00032 # be initialized using the clock. If the calls are fast enough, you'll 00033 # see distinctly nonrandom behavior. 00034 00035 rand_num_generatorG = whrandom.whrandom() 00036 00037 ## 00038 # Sample without replacement from a set of integers from 1 to 00039 # population_size. It returns a tuple of sample_size integers 00040 # that were selected. The sampling distribution is 00041 # hypergeometric. 00042 # 00043 def sample_wor(population_size, sample_size): 00044 assert type(population_size) == type(0) and type(sample_size) == type(0) and population_size > 0 and sample_size > 0 and sample_size <= population_size 00045 global rand_num_generatorG 00046 m = 0 # number of records selected so far 00047 t = 1 # Candidate integer to select if frac is right 00048 list = [] 00049 while m < sample_size: 00050 unif_rand = rand_num_generatorG.random() 00051 frac = 1.0 * (sample_size - m) / (population_size - (t-1)) 00052 if unif_rand < frac: 00053 list.append(t) 00054 m = m + 1 00055 t = t + 1 00056 return tuple(list) 00057 00058 ## 00059 # Sample with replacement from a set of integers from 1 to 00060 # population_size. It returns a tuple of sample_size integers 00061 # that were selected. The sampling distribution is binomial. 00062 # 00063 def sample_wr(population_size, sample_size): 00064 assert type(population_size) == type(0) and type(sample_size) == type(0) and population_size > 0 and sample_size > 0 00065 global rand_num_generatorG 00066 list = [] 00067 for ix in xrange(sample_size): 00068 list.append(rand_num_generatorG.randint(1, population_size)) 00069 return tuple(list) 00070 00071 ## 00072 # Moses and Oakford algorithm. See Knuth, vol 2, section 3.4.2. 00073 # Returns a tuple of a random permutation of the integers from 1 to 00074 # sample_size. 00075 # 00076 def shuffle(sample_size): 00077 assert type(sample_size) == type(0) and sample_size > 0 00078 global rand_num_generatorG 00079 list = range(1, sample_size + 1) 00080 for ix in xrange(sample_size - 1, 0, -1): 00081 rand_int = rand_num_generatorG.randint(0, ix) 00082 if rand_int == ix: 00083 continue 00084 tmp = list[ix] 00085 list[ix] = list[rand_int] 00086 list[rand_int] = tmp 00087 return tuple(list) 00088 00089 ## 00090 # Returns a tuple of the sequence set that has been randomly 00091 # shuffled. Works with lists and tuples. 00092 # 00093 def shuffle_set(set): 00094 shuffled_set = [] 00095 if type(set) != type([]) and type(set) != type(()): 00096 raise "Bad data", "must be list or tuple" 00097 numlist = shuffle(len(set)) 00098 for jx in numlist: 00099 ix = jx - 1 00100 shuffled_set.append(set[ix]) 00101 return tuple(shuffled_set) 00102 00103 ## 00104 # Returns a dictionary of dealt hands from the integers 1 to 00105 # deck_size. Each dictionary element (indexed by 1, 2, ..., 00106 # num_hands) is a list of num_per_hand integers. The element 00107 # indexed by 0 is the remaining integers that were not selected 00108 # for one of the hands. 00109 # 00110 def deal(deck_size, num_hands, num_per_hand): 00111 assert deck_size and deck_size >= num_hands * num_per_hand and num_hands > 0 and type(num_hands) == type(0) and num_per_hand > 0 and type(num_per_hand) == type(0) 00112 dict = {} 00113 # Generate the integers that will be in the hands 00114 sample = shuffle_set(range(1, deck_size + 1)) 00115 for ix in range(num_hands): # Partition into the dictionary 00116 start = ix * num_per_hand 00117 stop = start + num_per_hand 00118 dict[ix+1] = sample[start : stop] 00119 dict[0] = sample[stop:] 00120 return dict 00121 00122 ## 00123 # Returns a dictionary of a dealt card hand. The deal() function 00124 # is used, but the routine also maps the integers to a string that 00125 # contains the card identifications. For example, 1 -> 2S, 2 -> 3S, 00126 # ..., 13 -> AS, 14 -> 2C, etc. 00127 # 00128 def deal_deck(num_hands, num_per_hand): 00129 cards = deal(52, num_hands, num_per_hand) 00130 # Now go through and put identifier on the cards (and change them 00131 # from type integer to type string). 00132 suit_name = "SCHD" # Spades, clubs, hearts, diamonds 00133 card_name = "A234567890JQK" # Note 10 will need special handling... 00134 for hand in cards.keys(): 00135 new_hand = [] 00136 for card_num in cards[hand]: 00137 # We subtract 1 from card_num because cards are numbered 1 to 52 00138 suit_index, card_index = divmod(card_num-1, 13) 00139 #print "suit_index =", suit_index, " card_index =", card_index, " card_num =", card_num 00140 suit = suit_name[suit_index] 00141 card = ("1" * (card_index == 9)) + card_name[card_index] 00142 new_hand.append(card + suit) 00143 cards[hand] = new_hand 00144 return cards 00145 00146
© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."
Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.
122,241 lines of code and growing...