Path: blob/main/latex-templates/templates/biology/evolutionary_dynamics.tex
51 views
unlisted
% Evolutionary Dynamics Template1% Topics: Fitness landscapes, natural selection, genetic drift, mutation-selection balance2% Style: Textbook chapter with theoretical foundations34\documentclass[a4paper, 11pt]{article}5\usepackage[utf8]{inputenc}6\usepackage[T1]{fontenc}7\usepackage{amsmath, amssymb}8\usepackage{graphicx}9\usepackage{siunitx}10\usepackage{booktabs}11\usepackage{subcaption}12\usepackage[makestderr]{pythontex}1314% Theorem environments15\newtheorem{definition}{Definition}[section]16\newtheorem{theorem}{Theorem}[section]17\newtheorem{example}{Example}[section]18\newtheorem{remark}{Remark}[section]1920\title{Evolutionary Dynamics: Selection, Drift, and Fitness Landscapes}21\author{Theoretical Population Genetics}22\date{\today}2324\begin{document}25\maketitle2627\begin{abstract}28This chapter explores the fundamental forces driving evolutionary change in populations.29We analyze natural selection under various fitness schemes, examine the stochastic effects30of genetic drift in finite populations, and investigate the interplay between mutation31and selection. Computational simulations illustrate fitness landscapes, fixation32probabilities, and the dynamics of allele frequency change under different evolutionary33scenarios.34\end{abstract}3536\section{Introduction}3738Evolution operates through the interplay of deterministic forces (selection, mutation) and39stochastic processes (genetic drift). Understanding these dynamics requires both analytical40theory and computational simulation.4142\begin{definition}[Fitness]43The fitness $w$ of a genotype is its relative reproductive success. For a diploid organism44with alleles $A$ and $a$, genotype fitnesses are denoted $w_{AA}$, $w_{Aa}$, and $w_{aa}$.45\end{definition}4647\section{Theoretical Framework}4849\subsection{Natural Selection}5051\begin{theorem}[Change in Allele Frequency Under Selection]52For a population with allele frequency $p$ (for allele $A$) and genotype fitnesses53$w_{AA}$, $w_{Aa}$, $w_{aa}$, the change in one generation is:54\begin{equation}55\Delta p = \frac{p q [p(w_{AA} - w_{Aa}) + q(w_{Aa} - w_{aa})]}{\bar{w}}56\end{equation}57where $q = 1 - p$ and $\bar{w} = p^2 w_{AA} + 2pq w_{Aa} + q^2 w_{aa}$ is the mean fitness.58\end{theorem}5960\subsection{Selection Schemes}6162\begin{definition}[Types of Selection]63Different selection regimes produce distinct dynamics:64\begin{itemize}65\item \textbf{Directional}: One homozygote has highest fitness; allele goes to fixation66\item \textbf{Overdominance}: Heterozygote advantage; stable polymorphism67\item \textbf{Underdominance}: Heterozygote disadvantage; unstable equilibrium68\item \textbf{Frequency-dependent}: Fitness depends on allele frequency69\end{itemize}70\end{definition}7172\subsection{Genetic Drift}7374\begin{theorem}[Wright-Fisher Model]75In a finite population of size $N$, allele frequencies change stochastically. The76variance in allele frequency change per generation is:77\begin{equation}78\text{Var}(\Delta p) = \frac{p(1-p)}{2N}79\end{equation}80The probability of eventual fixation for a neutral allele at initial frequency $p_0$ is $p_0$.81\end{theorem}8283\begin{remark}[Effective Population Size]84Real populations often have $N_e < N$ due to variance in reproductive success, unequal85sex ratios, and population fluctuations.86\end{remark}8788\subsection{Mutation-Selection Balance}8990\begin{theorem}[Equilibrium Frequency]91For a deleterious recessive allele with mutation rate $\mu$ and selection coefficient $s$:92\begin{equation}93\hat{q} \approx \sqrt{\frac{\mu}{s}}94\end{equation}95For a deleterious dominant allele: $\hat{q} \approx \mu/s$.96\end{theorem}9798\section{Computational Analysis}99100\begin{pycode}101import numpy as np102import matplotlib.pyplot as plt103from scipy.integrate import odeint104105np.random.seed(42)106107def selection_dynamics(p, t, w_AA, w_Aa, w_aa):108"""Continuous-time selection dynamics."""109if p <= 0 or p >= 1:110return 0111q = 1 - p112w_bar = p**2 * w_AA + 2*p*q * w_Aa + q**2 * w_aa113dp = p * q * (p*(w_AA - w_Aa) + q*(w_Aa - w_aa)) / w_bar114return dp115116def wright_fisher(p0, N, generations):117"""Wright-Fisher genetic drift simulation."""118p = np.zeros(generations)119p[0] = p0120for i in range(1, generations):121if p[i-1] <= 0 or p[i-1] >= 1:122p[i] = p[i-1]123else:124n_A = np.random.binomial(2*N, p[i-1])125p[i] = n_A / (2*N)126return p127128def fixation_probability_simulation(p0, N, s, n_sims=1000):129"""Estimate fixation probability by simulation."""130fixed = 0131for _ in range(n_sims):132p = p0133while 0 < p < 1:134# Selection135w_bar = (1 + s) * p**2 + p*(1-p) + (1-p)**2136p_sel = ((1 + s) * p**2 + p*(1-p)) / w_bar137# Drift138n_A = np.random.binomial(2*N, p_sel)139p = n_A / (2*N)140if p >= 1:141fixed += 1142return fixed / n_sims143144# Parameters145generations = 200146t = np.linspace(0, generations, 1000)147148# Selection scenarios149# Directional selection150p_dir = odeint(selection_dynamics, 0.1, t, args=(1.0, 0.95, 0.8))151# Overdominance152p_over = odeint(selection_dynamics, 0.1, t, args=(0.8, 1.0, 0.9))153# Underdominance (two initial conditions)154p_under1 = odeint(selection_dynamics, 0.4, t, args=(1.0, 0.8, 1.0))155p_under2 = odeint(selection_dynamics, 0.6, t, args=(1.0, 0.8, 1.0))156# Frequency-dependent (simplified)157p_freq = odeint(selection_dynamics, 0.3, t, args=(0.9, 1.0, 0.9))158159# Genetic drift simulations160N_values = [20, 100, 500]161n_reps = 20162drift_results = {}163for N in N_values:164drift_results[N] = [wright_fisher(0.5, N, generations) for _ in range(n_reps)]165166# Fitness landscape167p_range = np.linspace(0.001, 0.999, 200)168w_bar_dir = p_range**2 * 1.0 + 2*p_range*(1-p_range) * 0.95 + (1-p_range)**2 * 0.8169w_bar_over = p_range**2 * 0.8 + 2*p_range*(1-p_range) * 1.0 + (1-p_range)**2 * 0.9170w_bar_under = p_range**2 * 1.0 + 2*p_range*(1-p_range) * 0.8 + (1-p_range)**2 * 1.0171172# Mutation-selection balance173mu = 1e-5174s_values = np.logspace(-4, -1, 50)175q_eq_recessive = np.sqrt(mu / s_values)176q_eq_dominant = mu / s_values177178# Fixation probability (theoretical)179N_fix = 100180s_fix = np.linspace(-0.1, 0.1, 50)181# Kimura's formula: P_fix = (1 - exp(-4Ns*p0)) / (1 - exp(-4Ns))182p0_fix = 1 / (2 * N_fix) # New mutation183P_fix_theory = np.zeros_like(s_fix)184for i, s in enumerate(s_fix):185if abs(s) < 1e-6:186P_fix_theory[i] = p0_fix187else:188P_fix_theory[i] = (1 - np.exp(-4*N_fix*s*p0_fix)) / (1 - np.exp(-4*N_fix*s))189190# Create figure191fig = plt.figure(figsize=(14, 12))192193# Plot 1: Selection dynamics194ax1 = fig.add_subplot(3, 3, 1)195ax1.plot(t, p_dir, 'b-', linewidth=2, label='Directional')196ax1.plot(t, p_over, 'g-', linewidth=2, label='Overdominance')197ax1.plot(t, p_under1, 'r-', linewidth=1.5, label='Underdominance')198ax1.plot(t, p_under2, 'r--', linewidth=1.5)199ax1.set_xlabel('Generation')200ax1.set_ylabel('Allele frequency $p$')201ax1.set_title('Selection Dynamics')202ax1.legend(fontsize=8)203ax1.set_ylim([0, 1])204205# Plot 2: Fitness landscape206ax2 = fig.add_subplot(3, 3, 2)207ax2.plot(p_range, w_bar_dir, 'b-', linewidth=2, label='Directional')208ax2.plot(p_range, w_bar_over, 'g-', linewidth=2, label='Overdominance')209ax2.plot(p_range, w_bar_under, 'r-', linewidth=2, label='Underdominance')210ax2.set_xlabel('Allele frequency $p$')211ax2.set_ylabel('Mean fitness $\\bar{w}$')212ax2.set_title('Fitness Landscape')213ax2.legend(fontsize=8)214215# Plot 3: Genetic drift (small N)216ax3 = fig.add_subplot(3, 3, 3)217gen = np.arange(generations)218for traj in drift_results[20]:219ax3.plot(gen, traj, linewidth=0.8, alpha=0.5)220ax3.set_xlabel('Generation')221ax3.set_ylabel('Allele frequency $p$')222ax3.set_title(f'Genetic Drift (N = 20)')223ax3.set_ylim([0, 1])224225# Plot 4: Genetic drift (medium N)226ax4 = fig.add_subplot(3, 3, 4)227for traj in drift_results[100]:228ax4.plot(gen, traj, linewidth=0.8, alpha=0.5)229ax4.set_xlabel('Generation')230ax4.set_ylabel('Allele frequency $p$')231ax4.set_title(f'Genetic Drift (N = 100)')232ax4.set_ylim([0, 1])233234# Plot 5: Genetic drift (large N)235ax5 = fig.add_subplot(3, 3, 5)236for traj in drift_results[500]:237ax5.plot(gen, traj, linewidth=0.8, alpha=0.5)238ax5.set_xlabel('Generation')239ax5.set_ylabel('Allele frequency $p$')240ax5.set_title(f'Genetic Drift (N = 500)')241ax5.set_ylim([0, 1])242243# Plot 6: Mutation-selection balance244ax6 = fig.add_subplot(3, 3, 6)245ax6.loglog(s_values, q_eq_recessive, 'b-', linewidth=2, label='Recessive')246ax6.loglog(s_values, q_eq_dominant, 'r-', linewidth=2, label='Dominant')247ax6.set_xlabel('Selection coefficient $s$')248ax6.set_ylabel('Equilibrium frequency $\\hat{q}$')249ax6.set_title(f'Mutation-Selection Balance ($\\mu = {mu}$)')250ax6.legend()251252# Plot 7: Fixation probability253ax7 = fig.add_subplot(3, 3, 7)254ax7.plot(s_fix, P_fix_theory, 'b-', linewidth=2)255ax7.axhline(y=p0_fix, color='gray', linestyle='--', alpha=0.7, label='Neutral')256ax7.axvline(x=0, color='gray', linestyle=':', alpha=0.5)257ax7.set_xlabel('Selection coefficient $s$')258ax7.set_ylabel('Fixation probability')259ax7.set_title(f'Fixation Probability (N = {N_fix})')260ax7.legend(fontsize=8)261262# Plot 8: Hardy-Weinberg frequencies263ax8 = fig.add_subplot(3, 3, 8)264ax8.plot(p_range, p_range**2, 'b-', linewidth=2, label='$p^2$ (AA)')265ax8.plot(p_range, 2*p_range*(1-p_range), 'g-', linewidth=2, label='$2pq$ (Aa)')266ax8.plot(p_range, (1-p_range)**2, 'r-', linewidth=2, label='$q^2$ (aa)')267ax8.set_xlabel('Allele frequency $p$')268ax8.set_ylabel('Genotype frequency')269ax8.set_title('Hardy-Weinberg Equilibrium')270ax8.legend(fontsize=8)271272# Plot 9: Variance in allele frequency273ax9 = fig.add_subplot(3, 3, 9)274N_range = np.logspace(1, 4, 100)275p_test = 0.5276var_deltap = p_test * (1 - p_test) / (2 * N_range)277ax9.loglog(N_range, var_deltap, 'b-', linewidth=2)278ax9.set_xlabel('Population size $N$')279ax9.set_ylabel('Var($\\Delta p$)')280ax9.set_title('Drift Variance vs Population Size')281282plt.tight_layout()283plt.savefig('evolutionary_dynamics_analysis.pdf', dpi=150, bbox_inches='tight')284plt.close()285286# Calculate equilibrium for overdominance287p_eq_over = (1.0 - 0.9) / (2*1.0 - 0.8 - 0.9)288\end{pycode}289290\begin{figure}[htbp]291\centering292\includegraphics[width=\textwidth]{evolutionary_dynamics_analysis.pdf}293\caption{Evolutionary dynamics analysis: (a) Selection dynamics under different fitness294schemes; (b) Fitness landscapes showing mean fitness as function of allele frequency;295(c-e) Genetic drift in populations of different sizes; (f) Mutation-selection balance;296(g) Fixation probability as function of selection coefficient; (h) Hardy-Weinberg297genotype frequencies; (i) Drift variance versus population size.}298\label{fig:evolution}299\end{figure}300301\section{Results}302303\subsection{Selection Equilibria}304305\begin{pycode}306print(r"\begin{table}[htbp]")307print(r"\centering")308print(r"\caption{Selection Equilibria for Different Fitness Schemes}")309print(r"\begin{tabular}{lcccc}")310print(r"\toprule")311print(r"Selection Type & $w_{AA}$ & $w_{Aa}$ & $w_{aa}$ & Equilibrium $\hat{p}$ \\")312print(r"\midrule")313print(r"Directional & 1.00 & 0.95 & 0.80 & 1.00 (fixation) \\")314print(f"Overdominance & 0.80 & 1.00 & 0.90 & {p_eq_over:.2f} \\\\")315print(r"Underdominance & 1.00 & 0.80 & 1.00 & 0.00 or 1.00 \\")316print(r"\bottomrule")317print(r"\end{tabular}")318print(r"\label{tab:equilibria}")319print(r"\end{table}")320\end{pycode}321322\subsection{Drift Statistics}323324\begin{pycode}325print(r"\begin{table}[htbp]")326print(r"\centering")327print(r"\caption{Genetic Drift Statistics After " + str(generations) + r" Generations}")328print(r"\begin{tabular}{cccc}")329print(r"\toprule")330print(r"$N$ & Fixed & Lost & Polymorphic \\")331print(r"\midrule")332333for N in N_values:334fixed = sum(1 for traj in drift_results[N] if traj[-1] >= 0.99)335lost = sum(1 for traj in drift_results[N] if traj[-1] <= 0.01)336poly = n_reps - fixed - lost337print(f"{N} & {fixed} & {lost} & {poly} \\\\")338339print(r"\bottomrule")340print(r"\end{tabular}")341print(r"\label{tab:drift}")342print(r"\end{table}")343\end{pycode}344345\section{Discussion}346347\begin{example}[Overdominance and Stable Polymorphism]348Heterozygote advantage (overdominance) maintains genetic variation in populations.349The equilibrium allele frequency for our example is:350\begin{equation}351\hat{p} = \frac{w_{Aa} - w_{aa}}{2w_{Aa} - w_{AA} - w_{aa}} = \frac{1.0 - 0.9}{2(1.0) - 0.8 - 0.9} = \py{f"{p_eq_over:.2f}"}352\end{equation}353Classic examples include sickle-cell anemia and MHC diversity.354\end{example}355356\begin{remark}[Effective Population Size]357The variance in allele frequency change is $\text{Var}(\Delta p) = pq/(2N_e)$. Factors358reducing $N_e$ below census size include:359\begin{itemize}360\item Unequal sex ratios361\item Variance in reproductive success362\item Population bottlenecks363\item Overlapping generations364\end{itemize}365\end{remark}366367\section{Conclusions}368369This analysis demonstrates the fundamental forces of evolutionary change:370\begin{enumerate}371\item Selection drives systematic allele frequency change toward fitness peaks372\item Overdominance equilibrium at $\hat{p} = \py{f"{p_eq_over:.2f}"}$ maintains polymorphism373\item Genetic drift is stronger in small populations, with variance $\propto 1/N$374\item Mutation-selection balance maintains deleterious alleles at low frequencies375\item Fixation probability depends on both selection and population size376\end{enumerate}377378\section*{Further Reading}379380\begin{itemize}381\item Hartl, D.L. \& Clark, A.G. \textit{Principles of Population Genetics}, 4th ed. Sinauer, 2007.382\item Gillespie, J.H. \textit{Population Genetics: A Concise Guide}, 2nd ed. Johns Hopkins, 2004.383\item Nowak, M.A. \textit{Evolutionary Dynamics}. Harvard University Press, 2006.384\end{itemize}385386\end{document}387388389