#ifndef lint static char *rcsid = "$Header: /tmp_mnt/vida/disks/disk5/Users/terry/r/gassy/RCS/alleles.c,v 1.3 1992/10/09 06:43:50 terry Exp terry $"; #endif #include "types.h" #if defined(APP_INDIVIDUALS_HAVE_CONSTANT_SIZE) && defined(APP_INDIVIDUALS_ARE_STRINGS) VOID create_initial_alleles(context) CONTEXT *context; { /* * Fill the context->alleles variable. This is an array of LOCUS * which each contain an allele value and a probability that * that allele is chosen at random when the initial population * is filled at random. If the probabilities are going to be the * same for each allele value, the LOCUS structure also contains * a count of the number of alleles - this makes things a touch * faster later on for mutation. * * The way this is done is complicated by the various combinations * of constant sized individuals, string type individuals, * binary individuals, and equal allele frequency individuals etc. * * If we do not have constant sized individuals and string type * individuals, then we get the application to create the individuals * for us (and we don't use alleles). Otherwise, we try to be * of as much help as possible in creating alleles. * * The snarl of #if's below treats four cases (in this order): * * (1) Constant length binary strings with equal probabilities. * (2) Constant length binary strings with unequal probabilities. * (3) Constant length non binary strings with equal probabilities. * (4) Constant length non binary strings with unequal probabilities. * */ register INT i; #if defined(APP_INDIVIDUALS_ARE_BINARY) for (i = 0; i < context->genome_size; i++){ context->alleles[i].probabilities = (PROBABILITY *) Malloc(2 * sizeof(PROBABILITY)); } #if defined(APP_INDIVIDUALS_HAVE_EQUAL_PROB_ALLELES) /* (1) Constant length binary strings with equal probabilities. */ for (i = 0; i < context->genome_size; i++){ context->alleles[i].possible_alleles = "01"; context->alleles[i].nalleles = 2; context->alleles[i].probabilities[0] = (PROBABILITY) 0.5; context->alleles[i].probabilities[1] = (PROBABILITY) 0.5; } #else /* (2) Constant length binary strings with unequal probabilities. */ for (i = 0; i < context->genome_size; i++){ context->alleles[i].possible_alleles = "01"; } /* Get the application to fill in the probabilities. */ app_allele_probabilities(context->alleles); #endif /* INDIVIDUALS_HAVE_EQUAL_PROB_ALLELES */ #else /* Non binary. */ #if defined(APP_INDIVIDUALS_HAVE_EQUAL_PROB_ALLELES) /* (3) Constant length non binary strings with equal probabilities. */ /* Get the application to fill in the allele possibilities. */ app_allele_possibilities(context->alleles); /* Now we fill in the probabilities. */ for (i = 0; i < context->genome_size; i++){ register INT pos; PROBABILITY probability; if (context->alleles[i].possible_alleles == (STRING) 0){ error("the application did give allele possibilities at locus %d.", i); } context->alleles[i].nalleles = strlen(context->alleles[i].possible_alleles);; context->alleles[i].probabilities = (PROBABILITY *) Malloc(context->alleles[i].nalleles * sizeof(PROBABILITY)); probability = (PROBABILITY) 1.0 / (PROBABILITY) context->alleles[i].nalleles ; for (pos = 0; pos < context->alleles[i].nalleles ; pos++){ context->alleles[i].probabilities[pos] = probability; } } #else /* (4) Constant length non binary strings with unequal probabilities. We can't help. */ app_initial_population_alleles(context->alleles); #endif /* INDIVIDUALS_HAVE_EQUAL_PROB_ALLELES */ #endif /* INDIVIDUALS_ARE_BINARY */ #if defined(APP_ONE_ALLELE_LOCI_ALLOWED) && defined(APP_HAS_CONSTANT_NUM_OF_ONE_ALLELE_LOCI) /* Now the alleles are created, figure out how many one allele loci there are. */ context->num_one_allele_loci = count_single_allele_loci(context); #endif /* * Now, if the alleles are not going to change, figure out how * many mutatable loci there are. If they are going to change, * this will get taken care of in create_mutation_alleles(). */ #if ! defined(APP_ALLELE_PROBS_CHANGE) #if defined(APP_INDIVIDUALS_HAVE_CONSTANT_SIZE) && defined(APP_INDIVIDUALS_ARE_STRINGS) #if defined(APP_ONE_ALLELE_LOCI_ALLOWED) && defined(APP_HAS_CONSTANT_NUM_OF_ONE_ALLELE_LOCI) context->num_mutatable_loci_on_genome = context->genome_length - count_one_allele_loci(context); context->num_mutatable_loci_in_population = context->population_size * (context->genome_length - context->num_one_allele_loci); #else context->num_mutatable_loci_in_population = context->population_size * context->genome_size; #endif #endif #endif return; } #if defined(APP_ALLELE_PROBS_CHANGE) VOID create_mutation_alleles(context) CONTEXT *context; { /* * Fill in the allele values that will be used in mutation. * These may not be the same as those in the initial population. */ #if defined(APP_ALLELE_PROBS_CHANGE_TO_EQUAL) register INT i; #if defined(APP_INDIVIDUALS_ARE_BINARY) for (i = 0; i < context->genome_size; i++){ context->alleles[i].nalleles = 2; context->alleles[i].probabilities[0] = (PROBABILITY) 0.5; context->alleles[i].probabilities[1] = (PROBABILITY) 0.5; } #else for (i = 0; i < context->genome_size; i++){ register INT num_possibilities; register INT pos; PROBABILITY probability; context->alleles[i].nalleles = strlen(context->alleles[i].possible_alleles); probability = (PROBABILITY) 1.0 / (PROBABILITY) context->alleles[i].nalleles; for (pos = 0; pos < context->alleles[i].nalleles; pos++){ context->alleles[i].probabilities[pos] = probability; } } #endif #else /* They change, but not to equal probabilities. Ask the application for the probabilities. */ app_mutation_allele_probabilities(context->alleles); #endif #if defined(APP_INDIVIDUALS_HAVE_CONSTANT_SIZE) && defined(APP_INDIVIDUALS_ARE_STRINGS) #if defined(APP_ONE_ALLELE_LOCI_ALLOWED) && defined(APP_HAS_CONSTANT_NUM_OF_ONE_ALLELE_LOCI) context->num_mutatable_loci_on_genome = context->genome_length - count_one_allele_loci(context); context->num_mutatable_loci_in_population = context->population_size * (context->genome_length - context->num_one_allele_loci); #else context->num_mutatable_loci_in_population = context->population_size * context->genome_size; #endif #endif return; } #endif VOID create_individual_from_alleles(individual, context) INDIVIDUAL *individual; CONTEXT *context; { register INT i; for (i = 0; i < context->genome_size; i++){ register INT allele = (INT) 0; DOUBLE d = knuth_random(); while(1){ if (context->alleles[i].probabilities[allele] > d){ individual->genome[i] = context->alleles[i].possible_alleles[allele]; break; } else { d -= context->alleles[i].probabilities[allele]; } allele++; } } return; } #define FUDGE 0.00000001 VOID check_alleles(context) CONTEXT *context; { register INT i; /* Check that the allele values are sensible. */ for (i = 0; i < context->genome_size; i++){ register INT num_possibilities; register INT pos; PROBABILITY total_probability = (PROBABILITY) 0.0; if (context->alleles[i].possible_alleles == (STRING) 0){ error("the application did not give allele possibilities at locus %d.", i); } num_possibilities = strlen(context->alleles[i].possible_alleles); if (num_possibilities == (INT) 0){ error("the application did not specify any allele possibilities at locus %d.", i); } #if ! defined(APP_ONE_ALLELE_LOCI_ALLOWED) if (num_possibilities == (INT) 1){ error("the application only specified one allele possibility (%c) at locus %d.", context->alleles[i].possible_alleles[0], i); } #endif for (pos = 0; pos < num_possibilities; pos++){ if (context->alleles[i].probabilities[pos] < (PROBABILITY) 0.0){ error("the application specified an allele probability less than zero at locus %d.", i); } if (context->alleles[i].probabilities[pos] > (PROBABILITY) 1.0){ /* Invert the value. This makes it easy to specify fractional probs like 1/3. */ context->alleles[i].probabilities[pos] = 1.0 / context->alleles[i].probabilities[pos]; } /* We now allow this. It is quite possible. * if (context->alleles[i].probabilities[pos] == (PROBABILITY) 0.0){ * error("the application specified an allele probability of zero at locus %d.", i); * } */ total_probability += context->alleles[i].probabilities[pos]; } if (total_probability < (PROBABILITY) (1.0 - FUDGE)){ error("the application allele probabilities do not sum to 1.0 at locus %d.", i); } } return; } #undef FUDGE #if defined(APP_ONE_ALLELE_LOCI_ALLOWED) && defined(APP_HAS_CONSTANT_NUM_OF_ONE_ALLELE_LOCI) INT count_one_allele_loci(context) CONTEXT *context; { /* * Return the number of alleles on the genome that have a single possible allele. * The second test is written that way to avoid calling strlen. */ register INT i; register INT count = (INT) 0; for (i = 0; i < context->genome_size; i++){ #if defined(APP_INDIVIDUALS_HAVE_EQUAL_PROB_ALLELES) || (defined(APP_ALLELE_PROBS_CHANGE) && defined(APP_ALLELE_PROBS_CHANGE_TO_EQUAL)) if (context->alleles[i].nalleles == 1){ #else if (context->alleles[i].possible_alleles[0] != '\0' && context->alleles[i].possible_alleles[1] == '\0'){ #endif count++; } } return count; } #endif #endif