pop

package
v1.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 9, 2020 License: GPL-3.0 Imports: 14 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyFullTruncationNoise

func ApplyFullTruncationNoise(p *Population, envNoise float64, uniformRandom *rand.Rand)

ApplyTruncationNoise only adds environmental noise (no selection noise)

func ApplyPartialTruncationNoise

func ApplyPartialTruncationNoise(p *Population, envNoise float64, uniformRandom *rand.Rand)

ApplyPartialTruncationNoise adds environmental noise and partial truncation selection noise

func ApplyProportProbNoise

func ApplyProportProbNoise(p *Population, envNoise float64, uniformRandom *rand.Rand)

ApplyProportProbNoise adds environmental noise and strict proportionality probability selection noise

func ApplyUnrestrictProbNoise

func ApplyUnrestrictProbNoise(p *Population, envNoise float64, uniformRandom *rand.Rand)

ApplyUnrestrictProbNoise adds environmental noise and unrestricted probability selection noise

func CalcFitnessNumOffspring

func CalcFitnessNumOffspring(ind *Individual, uniformRandom *rand.Rand) uint32

Randomly choose a number of offspring that is, on average, proportional to the individual's fitness

func CalcPoissonNumMutations

func CalcPoissonNumMutations(uniformRandom *rand.Rand) uint32

Use a poisson distribution to choose a number of mutations, with the mean of number of mutations for all individuals being Mutn_rate

func CalcSemiFixedNumMutations

func CalcSemiFixedNumMutations(uniformRandom *rand.Rand) uint32

Randomly round Mutn_rate to the uint32 below or above, proportional to how close it is to each (so the resulting average should be Mutn_rate)

func CalcSemiFixedNumOffspring

func CalcSemiFixedNumOffspring(ind *Individual, uniformRandom *rand.Rand) uint32

Randomly rounds the desired number of offspring to the integer below or above, proportional to how close it is to each (so the resulting average should be (Num_offspring*2) )

func CalcUniformNumOffspring

func CalcUniformNumOffspring(ind *Individual, uniformRandom *rand.Rand) uint32

A uniform algorithm for calculating the number of offspring that gives an even distribution between 1 and 2*(Num_offspring*2)-1

func CapacityPopulationGrowth

func CapacityPopulationGrowth(prevPop *Population, _ uint32) uint32

CapacityPopulationGrowth uses an equation in which the pop size approaches the carrying capacity

func ExponentialPopulationGrowth

func ExponentialPopulationGrowth(prevPop *Population, _ uint32) uint32

ExponentialPopulationGrowth returns the previous pop size times the growth rate

func FoundersPopulationGrowth

func FoundersPopulationGrowth(prevPop *Population, genNum uint32) uint32

FoundersPopulationGrowth increases the pop size exponentially until it reaches the carrying capacity, and supports bottlenecks

func GenerateAllUniqueInitialAlleles

func GenerateAllUniqueInitialAlleles(p *Population, uniformRandom *rand.Rand)

GenerateAllUniqueInitialAlleles creates unique initial contrasting allele pairs (if specified by the config file) on indivs in the population

func GenerateVariableFreqInitialAlleles

func GenerateVariableFreqInitialAlleles(p *Population, uniformRandom *rand.Rand)

GenerateVariableFreqInitialAlleles creates initial contrasting allele pairs according to the frequencies specified in Initial_alleles_frequencies

func MultIndivFitness

func MultIndivFitness(_ *Individual) (fitness float64)

Note implemented yet. MultIndivFitness aggregates the fitness factors of all of the mutations using a combination of additive and mutliplicative, based on config.Cfg.Mutations.Multiplicative_weighting

func MultiBottleneckPopulationGrowth

func MultiBottleneckPopulationGrowth(prevPop *Population, genNum uint32) uint32

MultiBottleneckPopulationGrowth is like founders, except supports an arbitrary number of bottlenecks

func NoPopulationGrowth

func NoPopulationGrowth(prevPop *Population, _ uint32) uint32

NoPopulationGrowth returns the same pop size as the previous generation

func SetModels

func SetModels(c *config.Config)

SetModels is called by main.initialize() to set the function ptrs for the various algorithms chosen by the input file.

func SumIndivFitness

func SumIndivFitness(ind *Individual) (fitness float64)

SumIndivFitness adds together the fitness factors of all of the mutations. An individual's fitness starts at 1 and then deleterious mutations subtract from that and favorable mutations add to it. A total fitness of 0 means the individual is dead.

Types

type ApplySelectionNoiseType

type ApplySelectionNoiseType func(p *Population, envNoise float64, uniformRandom *rand.Rand)

ApplySelectionNoiseType functions add environmental noise and selection noise to the GenoFitness to set the PhenoFitness of all of the individuals of the population

type Bottleneck

type Bottleneck struct {
	GrowthRate        float64 // the pop growth rate before this bottleneck, 1.0 means no growth
	MaxPop            uint32  // the max pop size before this bottleneck, 0 means no max
	BottleneckStart   uint32  // the starting gen num, 0 means no more bottlenecks
	BottleneckPopSize uint32  // the pop size during the bottleneck time period
	BottleneckGens    uint32  // the num gens the bottleneck will last, then we move on to the next Bottleneck element
}

type Bottlenecks

type Bottlenecks struct {
	Bottlenecks  []Bottleneck
	CurrentIndex uint32
}

func ParseMultipleBottlenecks

func ParseMultipleBottlenecks(bottlenecksStr string) *Bottlenecks

ParseMultipleBottlenecks parses the config value that is comma-separated 5-tuples growth-rate:max-pop:bottle-start:bottle-size:bottle-gens It returns the Bottlenecks iterable

func (*Bottlenecks) CurrentBottleneck

func (pb *Bottlenecks) CurrentBottleneck() Bottleneck

CurrentBottleneck returns the current Bottleneck element.

func (*Bottlenecks) NextBottleneck

func (pb *Bottlenecks) NextBottleneck() Bottleneck

NextBottleneck returns the next Bottleneck element.

type Buckets

type Buckets struct {
	Generation        uint32   `json:"generation"`
	Bins              []uint32 `json:"bins"`
	Deleterious       []uint32 `json:"deleterious"`
	Neutral           []uint32 `json:"neutral"`
	Favorable         []uint32 `json:"favorable"`
	DelInitialAlleles []uint32 `json:"delInitialAlleles"`
	FavInitialAlleles []uint32 `json:"favInitialAlleles"`
}

type ByFitness

type ByFitness []IndivRef

func (ByFitness) Len

func (a ByFitness) Len() int

func (ByFitness) Less

func (a ByFitness) Less(i, j int) bool

func (ByFitness) Swap

func (a ByFitness) Swap(i, j int)

type CalcIndivFitnessType

type CalcIndivFitnessType func(ind *Individual) float64

Algorithms for aggregating all of the individual's mutation fitness factors into a single geno fitness value

type CalcNumMutationsType

type CalcNumMutationsType func(uniformRandom *rand.Rand) uint32

Algorithms for determining the number of additional mutations a specific offspring should be given

type CalcNumOffspringType

type CalcNumOffspringType func(ind *Individual, uniformRandom *rand.Rand) uint32

Various algorithms for determining the random number of offspring for a mating pair of individuals

type DistributionBuckets

type DistributionBuckets struct {
	Generation         uint32    `json:"generation"`
	BinMidpointFitness []float64 `json:"binmidpointfitness"`
	Recessive          []float64 `json:"recessive"`
	Dominant           []float64 `json:"dominant"`
}

type FractionFrequency

type FractionFrequency struct {
	// contains filtered or unexported fields
}

func ParseInitialAllelesFrequencies

func ParseInitialAllelesFrequencies(frequencies string) (freqList []FractionFrequency)

type GenerateInitialAllelesType

type GenerateInitialAllelesType func(p *Population, uniformRandom *rand.Rand)

These are the different algorithms for generating initial alleles

type IndivRef

type IndivRef struct {
	Indiv *Individual
}

Used as the elements for the Sort routine used for selection, and as indirection to point to individuals in PopulationPart objects

type Individual

type Individual struct {
	GenoFitness  float64 // fitness due to genomic mutations
	PhenoFitness float64 // fitness due to GenoFitness plus environmental noise and selection noise
	Dead         bool    // if true, selection has identified it for elimination
	NumMutations uint32  // keep a running total of the mutations. This is both mutations and initial alleles.

	// Note: we currently don't really need to cache these, because p.GetMutationStats caches its values, and the only other function that currently uses these is ind.Report() which only gets called for small populations.
	//		But it would only save 0.56 MB for 10,000 population, so let's wait and see if we need them cached for more stats in the future.
	NumDeleterious, NumNeutral, NumFavorable uint32 // cache some of the stats we usually gather
	NumDelAllele, NumFavAllele               uint32 // cache some of the stats we usually gather about initial alleles

	ChromosomesFromDad []dna.Chromosome
	ChromosomesFromMom []dna.Chromosome
	// contains filtered or unexported fields
}

Individual represents 1 organism in the population, tracking its mutations and alleles.

func IndividualFactory

func IndividualFactory(popPart *PopulationPart, _ bool) *Individual

func (*Individual) AddInitialAllelePair

func (ind *Individual) AddInitialAllelePair(chromoIndex, lbIndexOnChr int, favMutn, delMutn dna.Mutation)

AddInitialAllelePair adds 1 pair of contrasting alleles to this individual

func (*Individual) AddInitialContrastingAlleles

func (ind *Individual) AddInitialContrastingAlleles(numAlleles uint32, uniformRandom *rand.Rand) (uint32, uint32)

AddInitialContrastingAlleles adds numAlleles pairs of contrasting alleles to this individual

func (*Individual) AddMutations

func (child *Individual) AddMutations(lBsPerChromosome uint32, uniformRandom *rand.Rand)

AddMutations adds new mutations to this child right after mating.

func (*Individual) CountAlleles

func (ind *Individual) CountAlleles(alleles *dna.AlleleCount)

CountAlleles counts all of this individual's alleles (both mutations and initial alleles) and adds them to the given struct

func (*Individual) GetInitialAlleleStats

func (ind *Individual) GetInitialAlleleStats() (uint32, uint32)

GetInitialAlleleStats returns the number of deleterious, neutral, favorable initial alleles, and the average fitness factor of deleterious and favorable

func (*Individual) GetMutationStats

func (ind *Individual) GetMutationStats() (uint32, uint32, uint32)

GetMutationStats returns the number of deleterious, neutral, favorable mutations

func (*Individual) GetNumChromosomes

func (ind *Individual) GetNumChromosomes() uint32

GetNumChromosomes returns the number of chromosomes from each parent (we assume they always have the same number from each parent)

func (*Individual) Mate

func (ind *Individual) Mate(otherInd *Individual, newPopPart *PopulationPart, uniformRandom *rand.Rand)

Mate combines this person with the specified person to create a list of offspring. The offspring are added to newPopPart

func (*Individual) OneOffspring

func (dad *Individual) OneOffspring(mom *Individual, newPopPart *PopulationPart, uniformRandom *rand.Rand) *Individual

Offspring returns 1 offspring of this person (dad) and the specified person (mom).

func (*Individual) Reinitialize

func (ind *Individual) Reinitialize() *Individual

Not currently used, but kept here in case we want to reuse populations - Reinitialize gets an existing/old individual ready for reuse. In addition to their member vars, Individual objects have an array of Chromosomes ptrs. We will end up overwriting the contents of those Chromosome objects (including their LB array), but we want to reuse the memory allocation of those arrays.

func (*Individual) Report

func (ind *Individual) Report(_ bool)

Report prints out statistics of this individual. If final==true it could print more details.

type InitialAlleleModelType

type InitialAlleleModelType string
const (
	ALLUNIQUE_INITIAL_ALLELES     InitialAlleleModelType = "allunique"
	VARIABLE_FREQ_INITIAL_ALLELES InitialAlleleModelType = "variablefreq"
)

type Models

type Models struct {
	CalcNumOffspring       CalcNumOffspringType
	CalcIndivFitness       CalcIndivFitnessType
	CalcNumMutations       CalcNumMutationsType
	ApplySelectionNoise    ApplySelectionNoiseType
	PopulationGrowth       PopulationGrowthType
	GenerateInitialAlleles GenerateInitialAllelesType
}

Models holds pointers to functions that implement the various algorithms chosen by the input file.

var Mdl *Models

Mdl is the singleton instance of Models that can be accessed throughout the dna package. It gets set in SetModels().

type MutationRateModelType

type MutationRateModelType string
const (
	FIXED_MUTN_RATE   MutationRateModelType = "fixed"
	POISSON_MUTN_RATE MutationRateModelType = "poisson"
)

type NormalizedBuckets

type NormalizedBuckets struct {
	Generation uint32 `json:"generation"`
	//Bins []float64 `json:"bins"`
	Bins              []uint32  `json:"bins"`
	Deleterious       []float64 `json:"deleterious"`
	Neutral           []float64 `json:"neutral"`
	Favorable         []float64 `json:"favorable"`
	DelInitialAlleles []float64 `json:"delInitialAlleles"`
	FavInitialAlleles []float64 `json:"favInitialAlleles"`
}

type NumOffSpringModelType

type NumOffSpringModelType string
const (
	UNIFORM_NUM_OFFSPRING NumOffSpringModelType = "uniform"
	FIXED_NUM_OFFSPRING   NumOffSpringModelType = "fixed"
	//FORTRAN_NUM_OFFSPRING NumOffSpringModelType = "fortran" // this ended up giving the same results as FIXED_NUM_OFFSPRING
	FITNESS_NUM_OFFSPRING NumOffSpringModelType = "fitness"
)

type Population

type Population struct {
	TribeNum  uint32            // the tribe number
	Parts     []*PopulationPart // Subsets of the pop that are mated in parallel. This contains the backing array for IndexRefs.
	IndivRefs []IndivRef        // References to individuals in the indivs array. This level of indirection allows us to sort this list, truncate it after selection, and refer to indivs in PopulationParts, all w/o copying Individual objects.

	TargetSize       uint32       // the target size of this population after selection
	Done             bool         // true if went extinct or hit its pop max
	BottleNecks      *Bottlenecks // the bottlenecks this pop should go thru
	Num_offspring    float64      // Average number of offspring each individual should have (so need to multiple by 2 to get it for the mating pair). Calculated from config values Fraction_random_death and Reproductive_rate.
	LBsPerChromosome uint32       // How many linkage blocks in each chromosome. For now the total number of LBs must be an exact multiple of the number of chromosomes

	// Stats
	ActualAvgOffspring        float64 // The average number of offspring each individual from last generation actually had in this generation
	PreSelGenoFitnessMean     float64 // The average fitness of all of the individuals (before selection) due to their genomic mutations
	PreSelGenoFitnessVariance float64 //
	PreSelGenoFitnessStDev    float64 // The standard deviation from the GenoFitnessMean
	EnvironNoise              float64 // randomness applied to geno fitness calculated from PreSelGenoFitnessVariance, heritability, and non_scaling_noise

	MeanFitness, MinFitness, MaxFitness float64 // cache summary info about the individuals
	TotalNumMutations                   uint64
	MeanNumMutations                    float64

	MeanNumDeleterious, MeanNumNeutral, MeanNumFavorable float64 // cache some of the stats we usually gather

	MeanNumDelAllele, MeanNumFavAllele float64 // cache some of the stats we usually gather
}

Population tracks the tribes and global info about the population. It also handles population-wide actions like mating and selection.

func PopulationFactory

func PopulationFactory(prevPop *Population, genNum, tribeNum, partsPerPop uint32) *Population

PopulationFactory creates a new population. If genNum==0 it creates the special genesis population.

func (*Population) CountAlleles

func (p *Population) CountAlleles(genNum uint32, lastGen bool)

func (*Population) FreeParentRefs

func (p *Population) FreeParentRefs(dadIndex int, momIndex int)

FreeParentRefs eliminates the reference to these 2 parents so gc can reclaim them because we don't need them any more. This is called by populationpart.Mate() after mating these 2 parents.

func (*Population) GetCurrentSize

func (p *Population) GetCurrentSize() uint32

Size returns the current number of individuals in this population

func (*Population) GetFitnessStats

func (p *Population) GetFitnessStats() (float64, float64, float64, uint64, float64)

GetFitnessStats returns the average of all the individuals fitness levels, as well as the min and max, and total and mean mutations. Note: this function should only get stats that the individuals already have, because it is called in a minimal verbose level that is meant to be fast.

func (*Population) GetInitialAlleleStats

func (p *Population) GetInitialAlleleStats() (float64, float64)

GetInitialAlleleStats returns the average number of deleterious and favorable initial alleles

func (*Population) GetMutationStats

func (p *Population) GetMutationStats() (float64, float64, float64)

GetMutationStats returns the average number of deleterious, neutral, favorable mutations

func (*Population) IsDone

func (p *Population) IsDone(doLog bool) bool

Returns true if this pop has gone extinct or reached its pop max

func (*Population) Mate

func (p *Population) Mate(newP *Population, uniformRandom *rand.Rand)

Mate mates all the pairs of the population, choosing the linkage block at each linkage block position randomly from the mom or dad according to the crossover model (as in meiosis), and fills in the new/resulting population. The mating process is: - randomly choose 2 parents - determine number of offspring - for each offspring:

  • for each LB section, choose 1 LB from dad (from either his dad or mom) and 1 LB from mom (from either her dad or mom)
  • add new mutations to random LBs
  • add offspring to new population

func (*Population) PreSelectFitnessStats

func (p *Population) PreSelectFitnessStats() (genoFitnessMean, genoFitnessVariance, genoFitnessStDev float64)

PreSelectFitnessStats returns the mean geno fitness and std deviation

func (*Population) Reinitialize

func (p *Population) Reinitialize(prevPop *Population, genNum uint32) *Population

Not currently used, but kept here in case we want to reuse populations - Reinitialize recycles a population object for another generation. This saves freeing and reallocating a lot of objects

func (*Population) ReportDeadStats

func (p *Population) ReportDeadStats()

ReportDeadStats reports means of all the individuals that are being eliminated by selection

func (*Population) ReportEachGen

func (p *Population) ReportEachGen(genNum uint32, lastGen bool, totalInterimTime, genTime float64, memUsed float32)

Report prints out statistics of this population

func (*Population) ReportInitial

func (p *Population) ReportInitial()

ReportInitial prints out stuff at the beginning, usually headers for data files, or a summary of the run we are about to do

func (*Population) Select

func (p *Population) Select(uniformRandom *rand.Rand)

Select removes the least fit individuals in the population

type PopulationGrowthModelType

type PopulationGrowthModelType string
const (
	NO_POPULATON_GROWTH               PopulationGrowthModelType = "none"
	EXPONENTIAL_POPULATON_GROWTH      PopulationGrowthModelType = "exponential"
	CAPACITY_POPULATON_GROWTH         PopulationGrowthModelType = "capacity"
	FOUNDERS_POPULATON_GROWTH         PopulationGrowthModelType = "founders"
	MULTI_BOTTLENECK_POPULATON_GROWTH PopulationGrowthModelType = "multi-bottleneck"
)

type PopulationGrowthType

type PopulationGrowthType func(prevPop *Population, genNum uint32) uint32

PopulationGrowthType takes in the current population and generation number and returns the target pop size for the next gen

type PopulationPart

type PopulationPart struct {
	Indivs         []*Individual    // the offspring of this part of the population
	NextIndivIndex int              // supports reusing the Individual objects in a repurposed part
	Pop            *Population      // a reference back to the whole population, but that object should only be read
	MyUniqueInt    *utils.UniqueInt // this part gets its own range for mutation id's that can be manipulated concurrently with the gloabl one. This is set in Mate().

}

PopulationPart is a construct used to partition the population for the purpose mating parts of the population in parallel go routines in a thread-safe way. Each go routine is assigned 1 instance of PopulationPart and only writes to that object. (We could instead use mutexes to coordinate writing to shared objects, but that reduces performance, and in the mating operation performance is key because it is by far the most time consuming operation.

func PopulationPartFactory

func PopulationPartFactory(numIndivs uint32, pop *Population) *PopulationPart

PopulationPartFactory returns an instance of PopulationPart

func (*PopulationPart) FreeIndivs

func (p *PopulationPart) FreeIndivs()

FreeIndivs drops references to the Indivs

func (*PopulationPart) GetCurrentSize

func (p *PopulationPart) GetCurrentSize() uint32

Size returns the current number of individuals in this part of the population

func (*PopulationPart) GetIndividual

func (p *PopulationPart) GetIndividual() (ind *Individual)

GetIndividual returns the next available Individual to reuse, or creates one if necessary. Note: this has to use the member vars of the part (instead of having our own) so it is thread safe.

func (*PopulationPart) Mate

func (p *PopulationPart) Mate(parentPop *Population, parentIndices []int, uniqueInt *utils.UniqueInt, uniformRandom *rand.Rand, waitGroup *sync.WaitGroup)

Mate mates the parents passed in (which is a slice of the individuals in the parent population) and adds the children to this PopulationPart object. This function is called in a go routine so it must be thread-safe. Note: since parentIndices is a slice (not the actual array), passing it as a param does not copy all of the elements, which is good.

func (*PopulationPart) Reinitialize

func (p *PopulationPart) Reinitialize()

Not currently used, but kept here in case we want to reuse populations - Reinitialize repurposes a part for another generation. This is never called for gen 0.

func (*PopulationPart) SetEstimatedNumIndivs

func (p *PopulationPart) SetEstimatedNumIndivs(estimatedNumIndivs uint32)

SetEstimatedNumIndivs allocates the array of ptrs to Individuals once to an approx size, instead of appending multiple times. Note: this has to use the member vars of the part (instead of having our own) so it is thread safe.

type RecombinationType

type RecombinationType uint8
const (
	//CLONAL RecombinationType = 1   <-- have not needed these yet, uncomment when we do
	//SUPPRESSED RecombinationType = 2
	FULL_SEXUAL RecombinationType = 3
)

type SelectionNoiseModelType

type SelectionNoiseModelType string
const (
	FULL_TRUNC_SELECTION      SelectionNoiseModelType = "fulltrunc"
	UNRESTRICT_PROB_SELECTION SelectionNoiseModelType = "ups"
	PROPORT_PROB_SELECTION    SelectionNoiseModelType = "spps"
	PARTIAL_TRUNC_SELECTION   SelectionNoiseModelType = "partialtrunc"
)

type Species

type Species struct {
	Populations []*Population // the tribes that make up this species
	PartsPerPop uint32        // the number of population parts (threads) each population should have
}

Species tracks all of the populations (tribes) and holds attributes common to the whole species.

func SpeciesFactory

func SpeciesFactory() *Species

func (*Species) AllPopsDone

func (s *Species) AllPopsDone() bool

Go thru all pops and see if they all have gone extinct or reached their pop max

func (*Species) GetAverageFitness

func (s *Species) GetAverageFitness() (averageFitness float64)

GetAverageFitness gets the overall fitness of the species to determine if it has gone extinct

func (*Species) GetCurrentSize

func (s *Species) GetCurrentSize() (size uint32)

GetCurrentSize returns the sum of all of the pop sizes

func (*Species) GetFitnessStats

func (s *Species) GetFitnessStats() (meanFitness float64, minFitness float64, maxFitness float64, totalNumMutations uint64, meanNumMutations float64, speciesSize uint64)

GetFitnessStats returns the average of all the individuals fitness levels across the pops, as well as the min and max, and total and mean mutations.

func (*Species) GetMutationStats

func (s *Species) GetMutationStats() (meanNumDeleterious float64, meanNumNeutral float64, meanNumFavorable float64)

func (*Species) GetNextGeneration

func (parentS *Species) GetNextGeneration(gen uint32) (childrenS *Species)

GetNextGeneration prepares all of the populations for the next gen and returns them in a new Species object

func (*Species) GetNumPopulations

func (s *Species) GetNumPopulations() uint32

GetNumPopulations returns the number of populations in this species

func (*Species) Initialize

func (s *Species) Initialize(maxGenNum uint32, uniformRandom *rand.Rand) *Species

Initialize inits the populations for gen 0

func (*Species) MarkDonePops

func (s *Species) MarkDonePops()

Go thru all pops and mark as done any that have gone extinct or reached its pop max

func (*Species) Mate

func (parentS *Species) Mate(childrenS *Species, uniformRandom *rand.Rand)

Mate mates all of the populations

func (*Species) ReportEachGen

func (s *Species) ReportEachGen(genNum uint32, lastGen bool, totalInterimTime, genTime float64)

ReportEachGen reports stats on each population

func (*Species) ReportInitial

func (s *Species) ReportInitial()

ReportInitial prints out stuff at the beginning, usually headers for data files, or a summary of the run we are about to do

func (*Species) Select

func (s *Species) Select(uniformRandom *rand.Rand)

Select does selection on all of the populations

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL