aegis_sim.submodels.reproduction.recombination
1import numpy as np 2from numba import njit 3from aegis_sim import variables 4from aegis_sim.utilities.funcs import profile_time 5 6 7def recombination(genomes, RECOMBINATION_RATE): 8 """Return recombined chromatids.""" 9 10 if RECOMBINATION_RATE == 0: 11 return genomes 12 13 # Recombine two chromatids but pass only one; 14 # thus double the number of chromatids, recobine, 15 # then return only one chromatid from each chromatid pair 16 genomes = genomes[np.repeat(np.arange(len(genomes)), 2)] 17 18 # Flatten loci and bits 19 flat_genomes = genomes.reshape(len(genomes), 2, -1) 20 21 # Get chromatids 22 chromatid1 = flat_genomes[:, 0] 23 chromatid2 = flat_genomes[:, 1] 24 25 # Make choice array: when to take recombined and when to take original loci 26 # -1 means synapse; +1 means clear 27 rr = RECOMBINATION_RATE / 2 # / 2 because you are generating two random vectors (fwd and bkd) 28 reco_fwd = (variables.rng.random(chromatid1.shape) < rr) * -2 + 1 29 reco_bkd = (variables.rng.random(chromatid2.shape) < rr) * -2 + 1 30 31 # Propagate synapse 32 reco_fwd_cum = np.cumprod(reco_fwd, axis=1) 33 reco_bkd_cum = np.cumprod(reco_bkd[:, ::-1], axis=1)[:, ::-1] 34 35 # Recombine if both sites recombining 36 reco_final = (reco_fwd_cum + reco_bkd_cum) == -2 37 38 # Choose bits from first or second chromatid 39 # recombined = np.empty(flat_genomes.shape, bool) 40 recombined = np.empty(flat_genomes.shape, dtype=np.bool_) 41 recombined[:, 0] = np.where(reco_final, chromatid2, chromatid1) 42 recombined[:, 1] = np.where(reco_final, chromatid1, chromatid2) 43 44 recombined = recombined.reshape(genomes.shape) 45 recombined = recombined[::2] # Look at first comment in the function 46 47 return recombined 48 49 50# # Loop version of the vectorized function above 51# def recombination_via_pairs(genomes, RECOMBINATION_RATE): 52 53# if RECOMBINATION_RATE == 0: 54# return genomes 55 56# flat_genomes = genomes.reshape(len(genomes), 2, -1) 57 58# n_sites = flat_genomes.shape[-1] 59 60# n_recombination_sites = np.random.binomial( 61# n=n_sites, 62# p=RECOMBINATION_RATE, 63# size=len(flat_genomes), 64# ) 65 66# # Produce all random numbers immediately 67# chiasmata_list = variables.rng.integers( 68# low=1, 69# high=n_sites, 70# size=(len(n_recombination_sites), max(n_recombination_sites)), 71# dtype=np.int32, 72# ) # [low, high) 73 74# for i, (chiasmata, n) in enumerate(zip(chiasmata_list, n_recombination_sites)): 75# for chiasma in chiasmata[:n]: 76# flat_genomes[i, 0, :chiasma], flat_genomes[i, 1, :chiasma] = ( 77# flat_genomes[i, 1, :chiasma], 78# flat_genomes[i, 0, :chiasma], 79# ) 80 81# unflattened_genomes = flat_genomes.reshape(genomes.shape) 82 83# return unflattened_genomes 84 85 86@njit 87def recombination_via_pairs_numba(flat_genomes, n_recombination_sites, chiasmata_list): 88 for i in range(len(flat_genomes)): 89 for j in range(n_recombination_sites[i]): 90 chiasma = chiasmata_list[i, j] 91 flat_genomes[i, 0, :chiasma], flat_genomes[i, 1, :chiasma] = ( 92 flat_genomes[i, 1, :chiasma].copy(), 93 flat_genomes[i, 0, :chiasma].copy(), 94 ) 95 return flat_genomes 96 97 98def recombination_via_pairs(genomes, RECOMBINATION_RATE): 99 if RECOMBINATION_RATE == 0: 100 return genomes 101 102 flat_genomes = genomes.reshape(len(genomes), 2, -1).copy() 103 n_sites = flat_genomes.shape[-1] 104 n_recombination_sites = np.random.binomial(n=n_sites, p=RECOMBINATION_RATE, size=len(flat_genomes)) 105 106 max_n = max(n_recombination_sites) 107 chiasmata_list = variables.rng.integers(low=1, high=n_sites, size=(len(flat_genomes), max_n), dtype=np.int32) 108 109 flat_genomes = recombination_via_pairs_numba(flat_genomes, n_recombination_sites, chiasmata_list) 110 111 return flat_genomes.reshape(genomes.shape)
def
recombination(genomes, RECOMBINATION_RATE):
8def recombination(genomes, RECOMBINATION_RATE): 9 """Return recombined chromatids.""" 10 11 if RECOMBINATION_RATE == 0: 12 return genomes 13 14 # Recombine two chromatids but pass only one; 15 # thus double the number of chromatids, recobine, 16 # then return only one chromatid from each chromatid pair 17 genomes = genomes[np.repeat(np.arange(len(genomes)), 2)] 18 19 # Flatten loci and bits 20 flat_genomes = genomes.reshape(len(genomes), 2, -1) 21 22 # Get chromatids 23 chromatid1 = flat_genomes[:, 0] 24 chromatid2 = flat_genomes[:, 1] 25 26 # Make choice array: when to take recombined and when to take original loci 27 # -1 means synapse; +1 means clear 28 rr = RECOMBINATION_RATE / 2 # / 2 because you are generating two random vectors (fwd and bkd) 29 reco_fwd = (variables.rng.random(chromatid1.shape) < rr) * -2 + 1 30 reco_bkd = (variables.rng.random(chromatid2.shape) < rr) * -2 + 1 31 32 # Propagate synapse 33 reco_fwd_cum = np.cumprod(reco_fwd, axis=1) 34 reco_bkd_cum = np.cumprod(reco_bkd[:, ::-1], axis=1)[:, ::-1] 35 36 # Recombine if both sites recombining 37 reco_final = (reco_fwd_cum + reco_bkd_cum) == -2 38 39 # Choose bits from first or second chromatid 40 # recombined = np.empty(flat_genomes.shape, bool) 41 recombined = np.empty(flat_genomes.shape, dtype=np.bool_) 42 recombined[:, 0] = np.where(reco_final, chromatid2, chromatid1) 43 recombined[:, 1] = np.where(reco_final, chromatid1, chromatid2) 44 45 recombined = recombined.reshape(genomes.shape) 46 recombined = recombined[::2] # Look at first comment in the function 47 48 return recombined
Return recombined chromatids.
@njit
def
recombination_via_pairs_numba(flat_genomes, n_recombination_sites, chiasmata_list):
87@njit 88def recombination_via_pairs_numba(flat_genomes, n_recombination_sites, chiasmata_list): 89 for i in range(len(flat_genomes)): 90 for j in range(n_recombination_sites[i]): 91 chiasma = chiasmata_list[i, j] 92 flat_genomes[i, 0, :chiasma], flat_genomes[i, 1, :chiasma] = ( 93 flat_genomes[i, 1, :chiasma].copy(), 94 flat_genomes[i, 0, :chiasma].copy(), 95 ) 96 return flat_genomes
def
recombination_via_pairs(genomes, RECOMBINATION_RATE):
99def recombination_via_pairs(genomes, RECOMBINATION_RATE): 100 if RECOMBINATION_RATE == 0: 101 return genomes 102 103 flat_genomes = genomes.reshape(len(genomes), 2, -1).copy() 104 n_sites = flat_genomes.shape[-1] 105 n_recombination_sites = np.random.binomial(n=n_sites, p=RECOMBINATION_RATE, size=len(flat_genomes)) 106 107 max_n = max(n_recombination_sites) 108 chiasmata_list = variables.rng.integers(low=1, high=n_sites, size=(len(flat_genomes), max_n), dtype=np.int32) 109 110 flat_genomes = recombination_via_pairs_numba(flat_genomes, n_recombination_sites, chiasmata_list) 111 112 return flat_genomes.reshape(genomes.shape)