def getAction(self, signal):
		#using signal[-1] covers the len1/2 case uniformly
		theAct = util.weighted_choice(zip(self.actions, self.strategy[signal[-1]]))
                #theAct = np.random.choice(self.actions, p=util.normalize(self.strategy[signal[-1]]))
		if len(signal) == 1:
			self._choiceHistory.append((signal, theAct))
			return theAct
		else:
                        theFunc = util.weighted_choice(zip(range(self._numFuncs), self._funcWeights))
                        finalAct = self._funcs[theFunc][theAct]
			self._choiceHistory.append((signal, (theFunc, finalAct)))
			return finalAct
Esempio n. 2
0
 def action_given_state(self, state):
     if type(state) == list:
         state = tuple(state)
     normed = self.q_values_normalised_for_pick(state)
     action = u.weighted_choice(normed)
     print "CHOOSE\t based on state", state, "q_values", self.q_table[state], "(normed to", normed, ") => action", action
     return action
Esempio n. 3
0
    def breed_pop(self):
        """Breed the current population, a better score rank means probably more children."""
        pop_size = len(self.goombas)
        num_clones = ceil(pop_size * World.CLONE_BEST_FRACTION)
        num_bred = ceil(pop_size * World.BREED_FRACTION)
        num_rand = ceil(pop_size * World.NEW_RANDOM_FRACTION)

        # Order the population by final score
        ordered_pop = sorted([gmba for gmba in self.goombas], key=lambda g: g.score(), reverse=True)

        # The top few will be cloned into the next generation unchanged
        top_dogs = ordered_pop[:num_clones]
        new_goombas = [Goomba.from_sequences(dog.genome.sequences()) for dog in top_dogs]

        # The bottom fraction is thrown out entirely
        breeders = ordered_pop[:num_bred]

        # The remaining goombas breed, with a higher likelihood as they rank higher
        breed_weighted = dict(zip(breeders, linspace(World.REPRO_SUCCESS_RAMP, 1, len(breeders))))
        breeding_pairs = weighted_choice(breed_weighted, 2 * (pop_size - (num_clones + num_rand)))
        for i in range(0, len(breeding_pairs), 2):
            new_goombas.append(breed(breeding_pairs[i], breeding_pairs[i + 1]))

        for i in range(num_rand):
            new_goombas.append(Goomba(Genome.random_coding(self.seed_meta, randrange(*self.gen_len_range))))

        starts = self.start_locations(len(new_goombas))
        for gmba, pos in zip(new_goombas, starts):
            gmba.pos = pos

        self.goombas = new_goombas
	def getAction(self, signal):
		theAct = util.weighted_choice(zip(self.actions, self.strategy[sum(signal)]))
                #np.random.choice requires the weights to be probabilities; is normalizing then using this slower than weighted_choice?
                #theAct = np.random.choice(self.actions, p=util.normalize(self.strategy[sum(signal)]))
		if self._recordChoices:
			self._choiceHistory.append((signal, theAct))
		return theAct
Esempio n. 5
0
 def action_given_state(self, state):
     state = flatten(state)
     q_values = self.sess.run(self.core_q_values, feed_dict={self.core_state: state})
     normed = u.normalised(u.raised(q_values[0], self.state_normalisation_squash))
     action = u.weighted_choice(normed)
     print "CHOOSE\t based on state", state, "q_values", q_values, "(normed to", normed, ") => action", action
     return action
Esempio n. 6
0
 def action_given_state(self, state):
     state = flatten(state)
     q_values = self.sess.run(self.core_q_values, feed_dict={self.core_state: state})
     normed = u.normalised(u.raised(q_values[0], self.state_normalisation_squash))
     action = u.weighted_choice(normed)
     if random.random() < 0.1:
         print ">action_given_state  state %s q_values %s normed %s action %s" % (state, q_values, normed, action)
     return action
Esempio n. 7
0
def generate_age(classification):
    # age distribution at last tab "17.Population by Age-Group"
    # http://rural.nic.in/sites/downloads/IRDR/1.%20Demographic%20Profile.xls
    # does this need to go to database? or shall we use the average
    # but this needs to have the total number: pop ***!!!
    # my current idea idea is to simulate age dist and bootstrap
    age_range = util.weighted_choice(age_ranges, age_weights[classification])
    return random.randint(age_range[0], age_range[1])
Esempio n. 8
0
 def action_given_state(self, state):
     state = flatten(state)
     q_values = self.sess.run(self.core_q_values, feed_dict={self.core_state: state})
     normed = u.normalised(u.raised(q_values[0], self.state_normalisation_squash))
     action = u.weighted_choice(normed)
     if random.random() <= 0.05:
         q_values_str = " ".join(map(str, ["%0.2f" % v for v in q_values[0]]))
         normed_str = " ".join(map(str, ["%0.2f" % v for v in normed]))
         print ">action_given_state  state %s q_values %s normed %s action %s" % (state, q_values_str, normed_str, action)
     return action
	def getAction(self, signal):
		#using signal[-1] covers the len1/2 case uniformly
		theAct = util.weighted_choice(zip(self.actions, self.strategy[signal[-1]]))
                #theAct = np.random.choice(self.actions, p=util.normalize(self.strategy[signal[-1]]))
		if len(signal) == 1:
			self._choiceHistory.append((signal, theAct))
			return theAct
		else:
			self._choiceHistory.append((signal, self._func[theAct]))
			return self._func[theAct]
Esempio n. 10
0
    def random(cls, gen_len, const_bounds, leaf_weights, parent=None):
        ref_type = weighted_choice(leaf_weights)

        if ref_type == RefType.Pure_Offset_Call or ref_type == RefType.Impure_Offset_Call:
            val = random.randrange(gen_len) * random.choice([-1, 1])
        elif ref_type == RefType.Poll_Sensor:
            val = random.randrange(len(goomba.Sensor))
        else:
            val = (random.random() * (const_bounds[1]-const_bounds[0])) + const_bounds[0]
        return cls(None, ref_type, val, parent)
Esempio n. 11
0
def mutated_intenum(curr, enum_type, mute_prob, enum_rel):
    if random.random() > mute_prob:
        return curr

    mute = weighted_choice(enum_rel)
    if mute == EnumMutes.Increment:
        return enum_type((curr + 1) % len(enum_type))
    elif mute == EnumMutes.Decrement:
        return enum_type((curr - 1) % len(enum_type))
    else:
        return random.choice(list(enum_type))
Esempio n. 12
0
def mutated_int_in_range(val, mute_prob, rand_bounds, enum_rel):
    if random.random() > mute_prob:
        return val

    mute = weighted_choice(enum_rel)
    if mute == EnumMutes.Increment:
        return val + 1
    elif mute == EnumMutes.Decrement:
        return val - 1
    else:
        return random.randint(*rand_bounds)
Esempio n. 13
0
 def charge_problem_fee(self, problem, person):
     if problem.name == 'cataracts': 
         fee_options = [problem.cost_full, problem.cost_subsidized, 0]
         fee = util.weighted_choice(fee_options, 
                 Hospital.surgery_fee_proportions_by_state[self.state_name])
     elif problem.name == 'glasses':
         #FROM DATA
         fee = 120
     else:
         print 'Warning: unrecognized problem', problem.name
     person.money -= fee
 def will_make_order(self, client, product, timestamp):
     # type: (pd.Series, pd.Series, long) -> int
     """
     Ritorna 1 se il cliente effettuarà un ordine del prodotto il giorno stabilito.
     :param client: (np.Series) array che rappresenta un cliente
     :param product: (np.Series) array che rappresenta un prodotto
     :param timestamp: (long) timestamp del giorno dell'ordine
     :return: (float) probabilità dell'ordine
     """
     p = self.probability(client, product, timestamp)
     choices = [(1, p), (0, 1 - p)]
     return weighted_choice(choices)
Esempio n. 15
0
 def action_given_state(self, state):
     state = flatten(state)
     q_values = self.sess.run(self.core_q_values,
                              feed_dict={self.core_state: state})
     normed = u.normalised(
         u.raised(q_values[0], self.state_normalisation_squash))
     action = u.weighted_choice(normed)
     if random.random() <= 0.05:
         q_values_str = " ".join(
             map(str, ["%0.2f" % v for v in q_values[0]]))
         normed_str = " ".join(map(str, ["%0.2f" % v for v in normed]))
         print ">action_given_state  state %s q_values %s normed %s action %s" % (
             state, q_values_str, normed_str, action)
     return action
Esempio n. 16
0
File: rect.py Progetto: ZSwaff/bar
def distance_strategy():
    rects = []
    for i in range(N_RECTS):
        while True:
            weights = [
                sum(((x - e.cx) ** 2 + (y - e.cy) ** 2) ** .5 for e in rects) + 1
                for x, y in grid
            ]
            cx, cy = weighted_choice(grid, weights)
            radius = random.randint(MIN_RECT_RADIUS, MAX_RECT_RADIUS)
            rect = Rect(cx, cy, radius)
            if any(rect.collides_with(e) for e in rects):
                continue
            rects.append(rect)
            break
    return rects
Esempio n. 17
0
def mutated_num(num, mute_prob, genome, clamps):
    if random.random() > mute_prob:
        return num

    mute = weighted_choice(genome.mute_rates["const_rel"])
    if mute == ConstMutes.Increment:
        num += random.random() * genome.incr_range
    elif mute == ConstMutes.Decrement:
        num -= random.random() * genome.incr_range
    elif mute == ConstMutes.Incremult:  # Assumes mult_range >= 1
        num *= (random.random() * (genome.mult_range - 1)) + 1
    elif mute == ConstMutes.Decremult:
        num /= (random.random() * (genome.mult_range - 1)) + 1

    if clamps[0] is not None:
        num = max(clamps[0], num)
    if clamps[1] is not None:
        num = min(clamps[1], num)

    return num
Esempio n. 18
0
def mutated_num(num, mute_prob, genome, clamps):
    if random.random() > mute_prob:
        return num

    mute = weighted_choice(genome.mute_rates["const_rel"])
    if mute == ConstMutes.Increment:
        num += random.random() * genome.incr_range
    elif mute == ConstMutes.Decrement:
        num -= random.random() * genome.incr_range
    elif mute == ConstMutes.Incremult: # Assumes mult_range >= 1
        num *= (random.random() * (genome.mult_range-1)) + 1
    elif mute == ConstMutes.Decremult:
        num /= (random.random() * (genome.mult_range-1)) + 1

    if clamps[0] is not None:
        num = max(clamps[0], num)
    if clamps[1] is not None:
        num = min(clamps[1], num)

    return num
Esempio n. 19
0
    def mutate(self):
        # 1. Iterate through genome, checking each item for mutation
        i = 0
        while i < len(self):

            # 2. Check if the gene mutates.
            rand = random.random()
            mutation = None
            if rand < self.mute_rates["genome"]:
                mutation = weighted_choice(self.mute_rates["genome_rel"])

            # 3. Apply appropriate mutations, if any.
            if mutation is not None:
                fuzz = -1
                if mutation == GenomeMutes.Insert:
                    new_gene = Gene.random(round(self.fun_gen_depth),
                                           len(self), self.const_bounds,
                                           self.mute_rates["leaf_rel"])
                    self.genes.insert(i, new_gene)
                    fuzz = i
                    i += 1
                elif mutation == GenomeMutes.Dupe:
                    self.genes.insert(i, self.genes[i].copy())
                    fuzz = i
                    i += 1
                elif mutation == GenomeMutes.Delete:
                    del self.genes[i]
                    i -= 1
                elif mutation == GenomeMutes.Invert:
                    swapindex = (i + 1) % len(self)
                    tmp = self.genes[i]
                    self.genes[i] = self.genes[swapindex]
                    self.genes[swapindex] = tmp
                elif mutation == GenomeMutes.MuteGene:
                    self.genes[i].mutate(self)
                    fuzz = i

                if fuzz != -1:
                    self.fuzzify(self.genes[fuzz].function)

                # Mutate the colours when a functional mutation occurs, for a visual
                # indication of genetic distance.
                self.mutate_colors()

            i += 1

        # 4. Reset genome consistency
        self.link()

        # 5. Mutate the metagenome
        # fuzz [0.0, inf)
        self.fuzziness = mutated_num(self.fuzziness, self.mute_rates["genome"],
                                     self, [0.001, None])

        # const bounds (-inf, inf), but small smaller than large
        self.const_bounds[0] = mutated_num(self.const_bounds[0],
                                           self.mute_rates["genome"], self,
                                           [None, None])
        self.const_bounds[1] = mutated_num(self.const_bounds[1],
                                           self.mute_rates["genome"], self,
                                           [None, None])
        if self.const_bounds[0] > self.const_bounds[1]:
            self.const_bounds = self.const_bounds[::-1]

        # fun gen depth [0.0, 5.0]
        self.fun_gen_depth = mutated_by_factor(self.fun_gen_depth, 1.7,
                                               self.mute_rates["genome"],
                                               [0.001, 5.0])

        # incr_range [0.0, inf)
        self.incr_range = mutated_num(self.incr_range,
                                      self.mute_rates["genome"], self,
                                      [0.001, None])
        # mult_range [1.0, inf)
        self.mult_range = mutated_num(self.mult_range,
                                      self.mute_rates["genome"], self,
                                      [1.0, None])

        # Colours used to be mutated here.

        # mute_rates "mute", "genome" [0.0, 1.0]
        self.mute_rates["mute"] = mutated_by_const(self.mute_rates["mute"],
                                                   0.04,
                                                   self.mute_rates["genome"],
                                                   [0.001, 1.0])
        self.mute_rates["genome"] = mutated_by_const(self.mute_rates["genome"],
                                                     0.04,
                                                     self.mute_rates["mute"],
                                                     [0.001, 1.0])

        # other mute_rates [0.0, inf)
        rel_lists = [
            self.mute_rates["genome_rel"], self.mute_rates["const_rel"],
            self.mute_rates["leaf_rel"]
        ]

        for rel_list in rel_lists:
            for k in rel_list:
                rel_list[k] = mutated_num(rel_list[k], self.mute_rates["mute"],
                                          self, [0.001, None])
Esempio n. 20
0
    def mutate(self, genome):
        if random.random() < genome.mute_rates["gene_action"]:
            # Mutate this gene's action
            self.action = mutated_intenum(self.action, goomba.Action, 1.0,
                                          genome.mute_rates["enum_rel"])

        elif random.random() < genome.mute_rates["struct_mod"]:
            # Structure-modifying function mutations.

            # Select a random node and mutation
            node = random.choice(self.function.as_list())
            mute = weighted_choice(genome.mute_rates["struct_rel"])

            if mute == StructMutes.SubTree:
                new_node = FTreeNode.random(round(genome.fun_gen_depth),
                                            len(genome), genome.const_bounds,
                                            genome.mute_rates["leaf_rel"],
                                            node.parent)
                if node.parent is None:
                    self.function = new_node
                elif node.parent.left == node:
                    node.parent.left = new_node
                else:
                    node.parent.right = new_node

            elif mute == StructMutes.OpAbove:
                new_node = FTreeNode(random.choice(list(Op)), None, None,
                                     node.parent)

                if node.parent is None:
                    self.function = new_node
                elif node.parent.left == node:
                    node.parent.left = new_node
                else:
                    node.parent.right = new_node

                new_child = FTreeNode.random(round(genome.fun_gen_depth),
                                             len(genome), genome.const_bounds,
                                             genome.mute_rates["leaf_rel"],
                                             new_node)

                if random.random() < 0.5:
                    new_node.left = node
                    new_node.right = new_child
                else:
                    new_node.left = new_child
                    new_node.right = node

            elif mute == StructMutes.Swap:
                if isinstance(node, FTreeLeaf):
                    if node.parent is not None:
                        node = node.parent
                    else:
                        return
            # swap operands
                tmp = node.left
                node.left = node.right
                node.right = tmp

        else:
            # Non-strucure-modifying function mutation

            # Select a random node
            node = random.choice(self.function.as_list())

            if isinstance(node, FTreeNode):
                # mutate operator
                node.operator = mutated_intenum(node.operator, Op, 1.0,
                                                genome.mute_rates["enum_rel"])
            else:
                if random.random() < genome.mute_rates["leaf_type"]:
                    # mutate the leaf type

                    new_type = node.ref_type
                    # Keep trying to mutate until the value actually changes
                    while new_type == node.ref_type:
                        new_type = mutated_intenum(
                            node.ref_type, RefType, 1.0,
                            genome.mute_rates["leaf_rel"])
                    if node.ref_type == RefType.Constant:
                        node.val = round(
                            node.val)  # In case mutating from float to int
                    node.ref_type = new_type

                else:
                    # mutate the leaf value
                    if node.ref_type == RefType.Constant:
                        node.val = mutated_num(node.val, 1.0, genome,
                                               [None, None])
                    elif node.ref_type in [
                            RefType.Pure_Offset_Call,
                            RefType.Impure_Offset_Call
                    ]:
                        node.val = mutated_int_in_range(
                            node.val, 1.0,
                            [-len(genome), len(genome)],
                            genome.mute_rates["enum_rel"])
                    elif node.ref_type == RefType.Poll_Sensor:
                        node.val = mutated_int_in_range(
                            node.val, 1.0, [0, len(goomba.Sensor) - 1],
                            genome.mute_rates["enum_rel"])
Esempio n. 21
0
    def mutate(self, genome):
        if random.random() < genome.mute_rates["gene_action"]:
            # Mutate this gene's action
            self.action = mutated_intenum(self.action, goomba.Action,
                                          1.0, genome.mute_rates["enum_rel"])

        elif random.random() < genome.mute_rates["struct_mod"]:
            # Structure-modifying function mutations.

            # Select a random node and mutation
            node = random.choice(self.function.as_list())
            mute = weighted_choice(genome.mute_rates["struct_rel"])

            if mute == StructMutes.SubTree:
                new_node = FTreeNode.random(round(genome.fun_gen_depth),
                                            len(genome),
                                            genome.const_bounds,
                                            genome.mute_rates["leaf_rel"],
                                            node.parent)
                if node.parent is None:
                    self.function = new_node
                elif node.parent.left == node:
                    node.parent.left = new_node
                else:
                    node.parent.right = new_node

            elif mute == StructMutes.OpAbove:
                new_node = FTreeNode(random.choice(list(Op)), None, None, node.parent)
                
                if node.parent is None:
                    self.function = new_node
                elif node.parent.left == node:
                    node.parent.left = new_node
                else:
                    node.parent.right = new_node
                
                new_child = FTreeNode.random(round(genome.fun_gen_depth),
                                             len(genome),
                                             genome.const_bounds,
                                             genome.mute_rates["leaf_rel"],
                                             new_node)

                if random.random() < 0.5:
                    new_node.left = node
                    new_node.right = new_child
                else:
                    new_node.left = new_child
                    new_node.right = node
                    
            elif mute == StructMutes.Swap:
                if isinstance(node, FTreeLeaf):
                    if node.parent is not None:
                        node = node.parent
                    else:
                        return
            # swap operands
                tmp = node.left
                node.left = node.right
                node.right = tmp

        else:
            # Non-strucure-modifying function mutation
            
            # Select a random node
            node = random.choice(self.function.as_list())

            if isinstance(node, FTreeNode):
                # mutate operator
                node.operator = mutated_intenum(node.operator, Op, 
                                                1.0, genome.mute_rates["enum_rel"])
            else:
                if random.random() < genome.mute_rates["leaf_type"]:
                    # mutate the leaf type

                    new_type = node.ref_type
                    # Keep trying to mutate until the value actually changes
                    while new_type == node.ref_type:
                        new_type = mutated_intenum(node.ref_type, RefType,
                                                   1.0, genome.mute_rates["leaf_rel"])
                    if node.ref_type == RefType.Constant:
                        node.val = round(node.val)  # In case mutating from float to int
                    node.ref_type = new_type
                    
                else:
                    # mutate the leaf value
                    if node.ref_type == RefType.Constant:
                        node.val = mutated_num(node.val, 1.0,
                                               genome, [None, None])
                    elif node.ref_type in [RefType.Pure_Offset_Call, RefType.Impure_Offset_Call]:
                        node.val = mutated_int_in_range(node.val, 1.0,
                                                        [-len(genome), len(genome)],
                                                        genome.mute_rates["enum_rel"])
                    elif node.ref_type == RefType.Poll_Sensor:
                        node.val = mutated_int_in_range(node.val, 1.0,
                                                        [0, len(goomba.Sensor) - 1],
                                                        genome.mute_rates["enum_rel"])
Esempio n. 22
0
    def mutate(self):
        # 1. Iterate through genome, checking each item for mutation
        i = 0
        while i < len(self):

            # 2. Check if the gene mutates.
            rand = random.random()
            mutation = None
            if rand < self.mute_rates["genome"]:
                mutation = weighted_choice(self.mute_rates["genome_rel"])

              # 3. Apply appropriate mutations, if any.
            if mutation is not None:
                fuzz = -1
                if mutation == GenomeMutes.Insert:
                    new_gene = Gene.random(round(self.fun_gen_depth),
                                           len(self), self.const_bounds,
                                           self.mute_rates["leaf_rel"])
                    self.genes.insert(i, new_gene)
                    fuzz = i
                    i += 1
                elif mutation == GenomeMutes.Dupe:
                    self.genes.insert(i, self.genes[i].copy())
                    fuzz = i
                    i += 1
                elif mutation == GenomeMutes.Delete:
                    del self.genes[i]
                    i -= 1
                elif mutation == GenomeMutes.Invert:
                    swapindex = (i + 1)%len(self)
                    tmp = self.genes[i]
                    self.genes[i] = self.genes[swapindex]
                    self.genes[swapindex] = tmp
                elif mutation == GenomeMutes.MuteGene:
                    self.genes[i].mutate(self)
                    fuzz = i

                if fuzz != -1:
                    self.fuzzify(self.genes[fuzz].function)
                
                # Mutate the colours when a functional mutation occurs, for a visual
                # indication of genetic distance.
                self.mutate_colors()

            i += 1

        # 4. Reset genome consistency
        self.link()

        # 5. Mutate the metagenome
        # fuzz [0.0, inf)
        self.fuzziness = mutated_num(self.fuzziness, 
                                     self.mute_rates["genome"], 
                                     self,
                                     [0.001, None])

        # const bounds (-inf, inf), but small smaller than large
        self.const_bounds[0] = mutated_num(self.const_bounds[0],
                                           self.mute_rates["genome"],
                                           self,
                                           [None, None])
        self.const_bounds[1] = mutated_num(self.const_bounds[1],
                                           self.mute_rates["genome"], 
                                           self,
                                           [None, None])
        if self.const_bounds[0] > self.const_bounds[1]:
            self.const_bounds = self.const_bounds[::-1]

        # fun gen depth [0.0, 5.0]
        self.fun_gen_depth = mutated_by_factor(self.fun_gen_depth,
                                               1.7, self.mute_rates["genome"], [0.001, 5.0])

        # incr_range [0.0, inf)
        self.incr_range = mutated_num(self.incr_range,
                                      self.mute_rates["genome"], 
                                      self, 
                                      [0.001, None])
        # mult_range [1.0, inf)
        self.mult_range = mutated_num(self.mult_range, 
                                      self.mute_rates["genome"],
                                      self,
                                      [1.0, None])

        # Colours used to be mutated here.

        # mute_rates "mute", "genome" [0.0, 1.0]
        self.mute_rates["mute"] = mutated_by_const(self.mute_rates["mute"],
                                                   0.04, self.mute_rates["genome"], [0.001, 1.0])
        self.mute_rates["genome"] = mutated_by_const(self.mute_rates["genome"],
                                                     0.04, self.mute_rates["mute"], [0.001, 1.0])

        # other mute_rates [0.0, inf)
        rel_lists = [self.mute_rates["genome_rel"],
                     self.mute_rates["const_rel"],
                     self.mute_rates["leaf_rel"]]

        for rel_list in rel_lists:
            for k in rel_list:
                rel_list[k] = mutated_num(rel_list[k],
                                          self.mute_rates["mute"],
                                          self,
                                          [0.001, None])
Esempio n. 23
0
    words = line.split()
    grams += [tuple(words[i:i + N]) for i in xrange(len(words) - N + 1)]

gprob = u.to_prob(grams)

gram = dd(lambda: dd(lambda: 0))
gram_prob = dd(lambda: dd(lambda: 0))

for key, prob in gprob.items():
    gram[key[:-1]][key[-1]] = prob

for gram1, gram1_dict in gram.items():
    for gram2, p in gram1_dict.items():
        gram_prob[gram1][gram2] = u.softmax(p, gram1_dict.values())

start = random.choice(gprob.keys())
output = " ".join(start)
last = start[1:]
for i in range(T):
    gen = u.weighted_choice(gram_prob[last].items())
    if gen: output += gen + " "
    last = last[1:] + tuple([gen])

line = output.split("|")

phonemes = []
for word in line:
    phonemes.append(tuple(word.split()))

print to_words([phonemes], text)
Esempio n. 24
0
def generate_age(classification):
    # age distribution at last tab "17.Population by Age-Group"
    # http://rural.nic.in/sites/downloads/IRDR/1.%20Demographic%20Profile.xls
    age_range = util.weighted_choice(age_ranges, age_weights[classification])
    return random.randint(age_range[0], age_range[1])