\n",
"\n",
"The bird doesn't do a calculus problem to decide how large its foraging radius should be, or how many eggs it should lay. \n",
"\n",
"The cells don't solve math problems when arranging themselves to form arteries, in order to minimize the total vascular resistance. \n",
"\n",
"So what's actually behind all this? \n",
"
\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"\n",
"\n",
"**Evolution!**\n",
"\n",
"More precisely, natural selection: survival of the ***fittest***. \n",
"
\n",
".update at 0x7f01cfc610d0> with 2 widgets\n",
" l: Tran…"
]
},
"execution_count": 10,
"metadata": {
},
"output_type": "execute_result"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "110416b561bd488883930f017a37aa74",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"FigureWidget({\n",
" 'data': [{'line': {'color': '#35b779', 'shape': 'spline', 'smoothing': 1.30000000000000},\n",
" …"
]
},
"execution_count": 10,
"metadata": {
},
"output_type": "execute_result"
}
],
"source": [
"def fitness_interactive():\n",
" fitness(x) = 0.79 / (1 + ((x - 60)/30)^2) * (1 + (x - 60)/100)\n",
"\n",
" figure = FigureWidget(subplots=[{}, {}])\n",
" figure.axes_ranges((0, 100), (0, 60), scale=(1,1))\n",
" figure.axes_labels(\"Body length (cm)\", \"\")\n",
" figure.layout.margin.r = 100\n",
" figure.layout.xaxis1.zeroline = False\n",
" figure.layout.yaxis1.visible = False\n",
" figure.layout.xaxis2.range = [0, 100]\n",
" figure.layout.yaxis2.range = [0, 1]\n",
" figure.layout.xaxis2.title.text = \"Body length (cm)\"\n",
" figure.layout.yaxis2.title.text = \"Fitness\"\n",
" figure.layout.showlegend = False\n",
" figure.add(plotly_text(\"Fitness graph\", (0.78,0.95), font_size=18, paper=True, xanchor=\"center\"))\n",
" figure.add_layout_image(source=\"images/FishImage.png\", x=0, y=0, \n",
" xref=\"x\", yref=\"y\", xanchor=\"left\", yanchor=\"bottom\")\n",
" fish = figure.layout.images[0]\n",
" color1 = plotly.colors.sequential.Viridis[6]\n",
" color2 = plotly.colors.sequential.Viridis[0]\n",
" figure.add(plotly_function(fitness, (x, 5, 100), color=color1), subplot=2)\n",
" point_on_graph = figure.add(plotly_points([(0, 0)]), subplot=2)\n",
" maximum = find_root(fitness.derivative(), 10, 100)\n",
" maxline = plotly_lines([(maximum, -0.1), (maximum, 0.9)], color=color2, line_dash=\"dash\")\n",
" maxline = figure.add(maxline, subplot=2)\n",
" maxlabel = plotly_text(fr\"{round(maximum, 1)} cm\", \n",
" (maximum - 0.5, 0.4), font_size=14, xanchor=\"right\", xref=\"x2\", yref=\"y2\")\n",
" maxlabel = figure.add(maxlabel)\n",
"\n",
" @interact(l=slider(5, 100, 1, default=20, label=\"Body length\"), \n",
" show_max=checkbox(False, label=\"Show maximum\"))\n",
" def update(l, show_max):\n",
" with figure.batch_update():\n",
" fish.update(sizex=l, sizey=l)\n",
" point_on_graph.update(x=[float(l)], y=[float(fitness(l))])\n",
" maxline.visible = show_max\n",
" maxlabel.visible = show_max\n",
"\n",
" return figure\n",
"\n",
"fitness_interactive()"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Fitness is a function of genotype\n",
"\n",
"\n",
"(or phenotype)\n",
"\n",
"**Definition:** The ***fitness*** of a particular genotype is the *average number* (expected value) of offspring that an individual with that exact genotype will have. \n",
"\n",
"In other words, for any combination of genes, fitness measures how much an individual with those genes is likely to contribute to the gene pool of the next generation. \n",
"
\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Example 4: Darwin's finches\n",
"\n",
"
\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
],
"source": [
"finches = {\n",
" (0.85, 0.15): \"images/DarwinsFinches1.png\", \n",
" (0.40, 0.25): \"images/DarwinsFinches2.png\", \n",
" (0.15, 0.65): \"images/DarwinsFinches3.png\", \n",
" (0.50, 0.85): \"images/DarwinsFinches4.png\", \n",
"}\n",
"var(\"x, y\")\n",
"bump(x0, y0, h) = h^2/(h^2 + (x - x0)^2 + (y - y0)^2)\n",
"fitness(x, y) = 0\n",
"genotypes = np.array(list(finches.keys()), dtype=float)\n",
"for (x0, y0), a in zip(genotypes, (0.7, 0.3, 0.35, 0.6)):\n",
" fitness += a * bump(x0, y0, 0.15 + 0.08*random())\n",
"gradient = fitness.gradient()\n",
"hessian = jacobian(gradient, (x, y))\n",
"crit_points = find_zeros(gradient, (x, 0, 1), (y, 0, 1))\n",
"crit_points = [pt for pt in crit_points if all(l < 0 for l in hessian(*pt).eigenvalues())]\n",
"closest = lambda pt: np.linalg.norm(genotypes - pt, axis=1).argmin()\n",
"crit_points.sort(key=closest)\n",
"for oldpt, newpt in zip(genotypes, crit_points):\n",
" finches[tuple(newpt)] = finches.pop(tuple(oldpt))"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "f4bc597c6c3f4554bc4245821792a41e",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(SelectionSlider(description='Finches', options=('None', 1, 2, 3, 4, 'All'), value='None'…"
]
},
"execution_count": 15,
"metadata": {
},
"output_type": "execute_result"
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "095b0f792fa64b6c8ba8cf267627051f",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"FigureWidget({\n",
" 'data': [{'colorscale': [[0.0, 'lightblue'], [1.0, 'lightblue']],\n",
" 'opacity': …"
]
},
"execution_count": 15,
"metadata": {
},
"output_type": "execute_result"
}
],
"source": [
"def finches_interactive():\n",
" figure = FigureWidget(subplots=[{}, {\"type\": \"scene\"}])\n",
" figure.layout.yaxis.domain = [0, 0.95]\n",
" figure.layout.scene.domain.y = [0, 0.95]\n",
" figure.axes_ranges((0, 1), (0, 1), scale=(1,1))\n",
" figure.axes_labels(\"Beak length\", \"Beak pointiness\")\n",
" figure.axes_ranges((0, 1), (0, 1), (0, 1), scale=(1,1,1))\n",
" figure.axes_labels(\"Beak length\", \"Beak pointiness\", \"Fitness\")\n",
" figure.layout.showlegend = False\n",
" figure.add(plotly_text(\"Genotype space\", (0.22,0.95), font_size=18, \n",
" paper=True, xanchor=\"center\"))\n",
" title = figure.add(plotly_text(\"Fitness landscape\", (0.78,0.95), font_size=18, \n",
" paper=True, xanchor=\"center\"))\n",
" for (x0, y0), source in finches.items():\n",
" figure.add_layout_image(source=source, x=x0, y=y0, sizex=0.2, sizey=0.2, \n",
" xref=\"x\", yref=\"y\", xanchor=\"center\", yanchor=\"middle\")\n",
" figure.add_layout_image(source=source, x=0.5, y=0.5, sizex=0.5, sizey=1, \n",
" xref=\"paper\", yref=\"paper\", xanchor=\"left\", yanchor=\"middle\")\n",
" fitness_landscape = figure.add(plotly_function3d(fitness, (x, 0, 1), (y, 0, 1), opacity=0.8))\n",
" maxima = [(x0, y0, fitness(x0, y0)) for x0, y0 in finches]\n",
" maxima = figure.add(plotly_points3d(maxima, size=1.5, color=\"darkgreen\"))\n",
"\n",
" @interact(finch=slider([\"None\", 1, 2, 3, 4, \"All\"], label=\"Finches\"), \n",
" show_graph=checkbox(False, label=\"Show fitness landscape\"), \n",
" show_maxima=checkbox(False, label=\"Show species\"))\n",
" def update(finch, show_graph, show_maxima):\n",
" finchnum = -1 if finch == \"None\" else 99 if finch == \"All\" else finch - 1\n",
" with figure.batch_update():\n",
" for i in range(4):\n",
" figure.layout.images[2*i].visible = (i < finchnum)\n",
" figure.layout.images[2*i + 1].visible = (i == finchnum)\n",
" title.visible = show_graph\n",
" fitness_landscape.visible = show_graph\n",
" maxima.visible = show_maxima\n",
"\n",
" return figure\n",
"\n",
"finches_interactive()"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Local maxima and local minima\n",
"\n",
"\n",
"**Definition:** \n",
"- A function has a ***local maximum*** at a point $x$ if there is some region around $x$ such that, *within that region,* the maximum value of the function occurs at $x$. \n",
"- A function has a ***local minimum*** at a point $x$ if there is some region around $x$ such that, *within that region,* the minimum value of the function occurs at $x$. \n",
"\n",
"Also, maxima and minima collectively are called *extrema*, as in the *extreme values* of a function. \n",
"
\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": "\n\n\n \n\n"
},
"execution_count": 16,
"metadata": {
},
"output_type": "execute_result"
}
],
"source": [
"f(x) = (16*(x-3)^4 - 10*(x-3)^2 + 3*(x-3) + 4) * exp(-(x-3)^2)\n",
"df = f.derivative()\n",
"d2f = df.derivative()\n",
"critpts = find_zeros1d(df, (x, 0, 6))\n",
"colors = []\n",
"for x0 in critpts:\n",
" evalue = d2f(x0)\n",
" colors.append(\"darkgreen\" if evalue < 0 else \"darkred\")\n",
"critpts = [(x0, f(x0)) for x0 in critpts]\n",
"\n",
"figure = Figure()\n",
"figure.axes_ranges((0, 6), (0, 8))\n",
"figure.axes_labels(\"$x$\", \"$f(x)$\")\n",
"figure.layout.margin.b = 80\n",
"figure.layout.margin.r = 200\n",
"figure.add(plotly_function(f, (x, 0, 6), name=\"Graph of function\", plotpoints=161))\n",
"figure.add(plotly_points(critpts, color=colors, name=\"Extrema\", visible=\"legendonly\"))\n",
"figure"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Conclusions: \n",
"\n",
"\n",
"1. Many many features (anatomical, behavioral, even biochemical) in biology seem to be the result of an optimization process. Any time one can say a species is “adapted to do ... very well”, that's probably describing such a result. \n",
"\n",
"2. The biological mechanism underlying all of these optimizations is **evolution**, or more specifically, natural selection: survival of the *fittest*. The ***fitness*** of a certain genotype (or phenotype) is defined roughly as the average number of offspring an individual with that genotype will produce. \n",
"\n",
"3. A function has a ***local maximum*** at a point $x$ if there is some region around $x$ such that, within that region, the maximum value of the function occurs at $x$. A ***local minimum*** is defined similarly. \n",
"\n",
"4. One mathematical model for *speciation* is that species can form at any one of the local maxima of the fitness function, or ***fitness landscape***. \n",
"
\n",
"
\n"
]
},
{
"cell_type": "code",
"execution_count": 0,
"metadata": {
"collapsed": false,
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
],
"source": [
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"hide_input": false,
"kernelspec": {
"argv": [
"sage-9.8",
"--python",
"-m",
"sage.repl.ipython_kernel",
"--matplotlib=inline",
"-f",
"{connection_file}"
],
"display_name": "SageMath 9.8",
"env": {
},
"language": "sagemath",
"metadata": {
"cocalc": {
"description": "Open-source mathematical software system",
"priority": 1,
"url": "https://www.sagemath.org/"
}
},
"name": "sage-9.8",
"resource_dir": "/ext/jupyter/kernels/sage-9.8"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2"
}
},
"nbformat": 4,
"nbformat_minor": 4
}