// do coalescent func (w *WFPopulation) coalescent() int { // randomly choose two nodes a := w.history.CurrentPool[randist.UniformRandomInt(w.rng, len(w.history.CurrentPool))] b := w.history.CurrentPool[randist.UniformRandomInt(w.rng, len(w.history.CurrentPool))] for a == b { b = w.history.CurrentPool[randist.UniformRandomInt(w.rng, len(w.history.CurrentPool))] } aTreeNode := w.history.Tree[a] bTreeNode := w.history.Tree[b] // create their ancestor tree node and add it into the tree genome := Merge(aTreeNode.Genome, bTreeNode.Genome) children := []int{a, b} w.history.Tree = append(w.history.Tree, TreeNode{Genome: genome, Children: children}) // update the current pool pool := []int{} for _, pos := range w.history.CurrentPool { if pos != a && pos != b { pool = append(pool, pos) } } ancestorID := len(w.history.Tree) - 1 pool = append(pool, ancestorID) w.history.CurrentPool = pool return ancestorID }
// mutation operator // parameters: g is genome idx. func (pop *SeqPop) mutate() { g := randist.UniformRandomInt(pop.rng, pop.Size) // randomly choose a genome l := randist.UniformRandomInt(pop.rng, pop.Length) // randomly determine a position s := randist.UniformRandomInt(pop.rng, pop.states) // randomly find a idx of the mutated character in pop.states for byte(s) == pop.Genomes[g][l] { s = randist.UniformRandomInt(pop.rng, pop.states) } // update the character. pop.Genomes[g][l] = byte(s) }
// do transfer func (w *WFPopulation) transfer() (parents []int) { // randomly choose a node c := w.history.CurrentPool[randist.UniformRandomInt(w.rng, len(w.history.CurrentPool))] // tranferring fragment begin := randist.UniformRandomInt(w.rng, w.GenomeLength) end := begin + w.TransferLength if end < w.GenomeLength { amA, amB := Split(w.history.Tree[c].Genome, begin, end) if len(amA) != 0 { genome := amA children := []int{c} w.history.Tree = append(w.history.Tree, TreeNode{Genome: genome, Children: children}) parents = append(parents, len(w.history.Tree)-1) } if len(amB) != 0 { genome := amB children := []int{c} w.history.Tree = append(w.history.Tree, TreeNode{Genome: genome, Children: children}) parents = append(parents, len(w.history.Tree)-1) } } else { amB, amA := Split(w.history.Tree[c].Genome, end-w.GenomeLength+1, begin-1) if len(amA) != 0 { genome := amA children := []int{c} w.history.Tree = append(w.history.Tree, TreeNode{Genome: genome, Children: children}) parents = append(parents, len(w.history.Tree)-1) } if len(amB) != 0 { genome := amB children := []int{c} w.history.Tree = append(w.history.Tree, TreeNode{Genome: genome, Children: children}) parents = append(parents, len(w.history.Tree)-1) } } // update the current pool pool := []int{} for _, pos := range w.history.CurrentPool { if pos != c { pool = append(pool, pos) } } for _, pos := range parents { pool = append(pool, pos) } w.history.CurrentPool = pool return }
func mutateAll(seqMap map[int][]byte, lambda float64, l int, rng *randist.RNG) { for _, seq := range seqMap { count := randist.PoissonRandomInt(rng, lambda) for i := 0; i < count; i++ { idx := randist.UniformRandomInt(rng, l) a := NucleicAcids[randist.UniformRandomInt(rng, len(NucleicAcids))] for a == seq[idx] { a = NucleicAcids[randist.UniformRandomInt(rng, len(NucleicAcids))] } seq[idx] = a } } }
func randomGenerateSequence(length int, rng *randist.RNG) (seq []byte) { seq = make([]byte, length) for i, _ := range seq { seq[i] = NucleicAcids[randist.UniformRandomInt(rng, len(NucleicAcids))] } return }
// transfer operator // parameter: g is genome idx. func (pop *SeqPop) transfer() { g := randist.UniformRandomInt(pop.rng, pop.Size) // randomly choose a receiver d := randist.UniformRandomInt(pop.rng, pop.Size) // randomly choose a donor for g == d { d = randist.UniformRandomInt(pop.rng, pop.Size) } l := randist.UniformRandomInt(pop.rng, pop.Length) // randomly choose a left index r := l + pop.Fragment // fragment right index if r < pop.Length { copy(pop.Genomes[g][l:r], pop.Genomes[d][l:r]) } else { copy(pop.Genomes[g][l:pop.Length], pop.Genomes[d][l:pop.Length]) copy(pop.Genomes[g][0:r-pop.Length], pop.Genomes[d][0:r-pop.Length]) } }
// Wright-Fisher generation func (pop *SeqPop) reproduce() { newGenomes := make([]Sequence, pop.Size) used := make([]bool, pop.Size) // records used genomes for n := 0; n < pop.Size; n++ { o := randist.UniformRandomInt(pop.rng, pop.Size) // randomly select a parent if used[o] { // do hard copy newGenomes[n] = make(Sequence, pop.Length) copy(newGenomes[n], pop.Genomes[o]) } else { // just pass the pointer of the genome newGenomes[n] = pop.Genomes[o] used[o] = true } } // update genomes pop.Genomes = newGenomes }
// NewSeqPop returns a population with full sequence genomes func NewSeqPop(size, length int, mutation, transfer float64, fragment int) *SeqPop { // verify population size and genome length if size <= 0 || length <= 0 { log.Panic("Population size or genome length should be positive!") } // verify transfer rate and transferred fragment if transfer > 0 && fragment <= 0 { log.Panic("Transferred fragment should be positive when transfer rate > 0!") } // construct a population with parameters pop := SeqPop{ Size: size, Length: length, Mutation: mutation, Transfer: transfer, Fragment: fragment, } // create random sources pop.rng = randist.NewRNG(randist.MT19937) // create genomes // randomly create a parent sequence pop.states = 4 // typical nucleotides, "ATGC" refseq := make(Sequence, pop.Length) for i := 0; i < len(refseq); i++ { refseq[i] = byte(randist.UniformRandomInt(pop.rng, pop.states)) // randomly assign a character } // copy the parent sequence to every genomes pop.Genomes = make([]Sequence, pop.Size) for i := 0; i < len(pop.Genomes); i++ { pop.Genomes[i] = make(Sequence, pop.Length) copy(pop.Genomes[i], refseq) } return &pop }