diff --git a/experiments/ml-benchmark/arms/2026-09-01-round2-rules-sonnet5/README.md b/experiments/ml-benchmark/arms/2026-09-01-round2-rules-sonnet5/README.md
index fe9e545..1f3b531 100644
--- a/experiments/ml-benchmark/arms/2026-09-01-round2-rules-sonnet5/README.md
+++ b/experiments/ml-benchmark/arms/2026-09-01-round2-rules-sonnet5/README.md
@@ -124,3 +124,41 @@ ones: seed 23/17/15/6 → 24/19/16/6, arm 16/5/1/3 → 18/5/1/3, and the reviewe
text 1/0/2/1 → **1/1/2/1** — the new reviewed hit is his own inconsistency
(`{ref}`Previous lecture` at 229 but `{doc}`previous lecture` at 290), watch-only
and a candidate for ml#12.
+
+## Second draw at the released engine (v0.27.0, 2026-09-01)
+
+`functions-v0.27.0.md` — the same recipe run again after release (engine `125801c`,
+17,202 tokens, 3.4 min), i.e. arm 1 plus the ex5 negative example. Two draws is
+still direction, not a rate (#227), but it bounds the variance and tests the fix.
+
+**Closeness to the editor's reviewed text** (prose lines only; exact-line match,
+mean best-aligned line similarity, whole-prose `SequenceMatcher` ratio):
+
+| rendering | exact-line match | mean best-line similarity | whole-prose ratio |
+|---|---|---|---|
+| seed (5ffae4e) | 14/129 (11%) | 0.763 | 0.576 |
+| arm 1 (1251b7b) | 27/131 (21%) | 0.792 | 0.650 |
+| arm 2 (v0.27.0) | 25/131 (19%) | 0.787 | 0.638 |
+
+The engine closed roughly a third of the seed → reviewed distance on the
+whole-prose measure, doubling the share of lines it renders exactly as the
+editor did; the two draws agree to within two lines. The remaining distance is
+dominated by the two mechanical classes and by sentence-splitting preference.
+
+**Signatures, arm 2** (seed / reviewed / arm 2): lints 24/19/16/6 → 1/1/2/1 →
+**17/3/1/1**; colon-terminated paragraphs 4 → 18 → **7**; നമുക്ക് 9 → 21 → **16**;
+നോക്കാം 0 → 8 → **3**; sentence-final നമ്മൾ…-ും 6 → 1 → **1**; capitalised
+sentence-initial English 0 → 5 → **3**; every fixed pair, both pointer sentences,
+all four exercise-scope retentions and the three connectives at the reviewed
+form, as in arm 1.
+
+- **The ex5 fix works**: the recursion exercise statement is Malayalam again
+ (`recursion ഉപയോഗിച്ച്`), so the negative example closed the over-application.
+- **`set` did not recur** — headings 17/17, pinned-term retention clean, no FAIL.
+- **`refer` → `സൂചിപ്പിക്കുന്നു` recurred (2/2 draws, same sentence, line 155)** —
+ the round-1 glossary pin is not holding for "what a name refers to" in this
+ sentence; candidate for a rule example rather than a bare pin.
+- **List-item `-ഉം` regressed in this draw** (`sqrt()` function-ഉം ×2; arm 1 had 0)
+ — the rule fires inconsistently on the two-item overview list.
+- Terminal punctuation stays the weak class (17 bare endings; arm 1 had 18):
+ unchanged case for the deterministic post-processing step.
diff --git a/experiments/ml-benchmark/arms/2026-09-01-round2-rules-sonnet5/functions-v0.27.0.md b/experiments/ml-benchmark/arms/2026-09-01-round2-rules-sonnet5/functions-v0.27.0.md
new file mode 100644
index 0000000..05aa341
--- /dev/null
+++ b/experiments/ml-benchmark/arms/2026-09-01-round2-rules-sonnet5/functions-v0.27.0.md
@@ -0,0 +1,705 @@
+---
+jupytext:
+ text_representation:
+ extension: .md
+ format_name: myst
+kernelspec:
+ display_name: Python 3
+ language: python
+ name: python3
+translation:
+ title: Functions
+ headings:
+ Overview: Overview
+ Function Basics: Function Basics
+ Function Basics::Built-In Functions: Built-In Functions
+ Function Basics::Third Party Functions: Third Party Functions
+ Defining Functions: Defining Functions
+ Defining Functions::Basic Syntax: Basic Syntax
+ Defining Functions::Keyword Arguments: Keyword Arguments
+ Defining Functions::The Flexibility of Python Functions: The Flexibility of Python Functions
+ 'Defining Functions::One-Line Functions: `lambda`': 'One-Line Functions: `lambda`'
+ Defining Functions::Why Write Functions?: Why Write Functions?
+ Applications: Applications
+ Applications::Random Draws: Random Draws
+ Applications::Adding Conditions: Adding Conditions
+ Recursive Function Calls (Advanced): Recursive Function Calls (Advanced)
+ Exercises: Exercises
+ Advanced Exercises: Advanced Exercises
+---
+
+(functions)=
+```{raw} jupyter
+
+```
+
+# Functions
+
+```{index} single: Python; User-defined functions
+```
+
+## Overview
+
+മിക്കവാറും എല്ലാ programming languages-ഉം provide ചെയ്യുന്ന വളരെ useful ആയ ഒരു construct ആണ് Functions.
+
+നമ്മൾ ഇതിനകം പല functions-നെയും പരിചയപ്പെട്ടിട്ടുണ്ട്, ഉദാഹരണത്തിന്
+
+* NumPy-യിലെ `sqrt()` function-ഉം
+* built-in ആയ `print()` function-ഉം
+
+ഈ lecture-ൽ നമ്മൾ ചെയ്യാൻ പോകുന്ന കാര്യങ്ങൾ:
+
+1. Functions-നെ systematic ആയി പഠിക്കുന്നു, syntax-ഉം use-cases-ഉം cover ചെയ്യുന്നു.
+2. നമ്മുടെ സ്വന്തം user-defined functions എങ്ങനെ build ചെയ്യാം എന്ന് പഠിക്കുന്നു.
+
+താഴെ കൊടുത്തിരിക്കുന്ന imports നമുക്ക് ഉപയോഗിക്കാം.
+
+```{code-cell} ipython
+import numpy as np
+import matplotlib.pyplot as plt
+```
+
+## Function Basics
+
+ഒരു പ്രത്യേക task implement ചെയ്യുന്ന, ഒരു program-ന്റെ പേരുള്ള ഒരു ഭാഗമാണ് function.
+
+ധാരാളം functions ഇതിനകം exist ചെയ്യുന്നു, അവയെ നമുക്ക് അതേപടി ഉപയോഗിക്കാം.
+
+ആദ്യം നമുക്ക് ഈ functions-നെ review ചെയ്യാം, എന്നിട്ട് നമ്മുടെ സ്വന്തം functions എങ്ങനെ build ചെയ്യാം എന്ന് നോക്കാം.
+
+### Built-In Functions
+
+`import` ഇല്ലാതെ തന്നെ ലഭ്യമായ കുറേ **built-in** functions Python-ന് ഉണ്ട്.
+
+ഇവയിൽ ചിലത് നമ്മൾ ഇതിനകം പരിചയപ്പെട്ടു
+
+```{code-cell} python3
+max(19, 20)
+```
+
+```{code-cell} python3
+print('foobar')
+```
+
+```{code-cell} python3
+str(22)
+```
+
+```{code-cell} python3
+type(22)
+```
+
+Python built-ins-ന്റെ full list [ഇവിടെ](https://docs.python.org/3/library/functions.html) കാണാം.
+
+
+### Third Party Functions
+
+നമുക്ക് വേണ്ട കാര്യങ്ങൾ built-in functions cover ചെയ്യുന്നില്ലെങ്കിൽ, ഒന്നുകിൽ functions-നെ import ചെയ്യണം അല്ലെങ്കിൽ നമ്മുടെ സ്വന്തം functions create ചെയ്യണം.
+
+Functions-നെ import ചെയ്ത് ഉപയോഗിക്കുന്നതിന്റെ ഉദാഹരണങ്ങൾ {doc}`previous lecture `-ൽ കൊടുത്തിട്ടുണ്ട്.
+
+താഴെ മറ്റൊരു ഉദാഹരണം കാണാം, ഇത് തന്നിരിക്കുന്ന ഒരു വർഷം leap year ആണോ എന്ന് test ചെയ്യുന്നു:
+
+```{code-cell} python3
+import calendar
+calendar.isleap(2024)
+```
+
+## Defining Functions
+
+പല സന്ദർഭങ്ങളിലും നമ്മുടെ സ്വന്തം functions define ചെയ്യാൻ കഴിയുന്നത് വളരെ useful ആണ്.
+
+ഇത് എങ്ങനെ ചെയ്യാം എന്ന് നമുക്ക് നോക്കാം.
+
+### Basic Syntax
+
+$f(x) = 2 x + 1$ എന്ന mathematical function implement ചെയ്യുന്ന വളരെ simple ആയ ഒരു Python function താഴെ കാണാം
+
+```{code-cell} python3
+def f(x):
+ return 2 * x + 1
+```
+
+ഈ function define ചെയ്തു കഴിഞ്ഞു, ഇനി നമുക്ക് ഇതിനെ *call* ചെയ്ത് പ്രതീക്ഷിച്ചത് പോലെ പ്രവർത്തിക്കുന്നുണ്ടോ എന്ന് check ചെയ്യാം:
+
+```{code-cell} python3
+f(1)
+```
+
+```{code-cell} python3
+f(10)
+```
+
+തന്നിരിക്കുന്ന ഒരു സംഖ്യയുടെ absolute value compute ചെയ്യുന്ന കുറച്ചുകൂടി വലിയ ഒരു function താഴെ കാണാം.
+
+(ഇത്തരം ഒരു function built-in ആയി ഇതിനകം exist ചെയ്യുന്നു, പക്ഷേ exercise-ന് വേണ്ടി നമുക്ക് നമ്മുടേതായി ഒന്ന് എഴുതാം.)
+
+```{code-cell} python3
+def new_abs_function(x):
+ if x < 0:
+ abs_value = -x
+ else:
+ abs_value = x
+ return abs_value
+```
+
+ഇവിടത്തെ syntax നമുക്ക് review ചെയ്യാം.
+
+* Function definitions തുടങ്ങാൻ ഉപയോഗിക്കുന്ന ഒരു Python keyword ആണ് `def`.
+* `def new_abs_function(x):` സൂചിപ്പിക്കുന്നത് ഈ function-ന്റെ പേര് `new_abs_function` എന്നാണ്, കൂടാതെ ഇതിന് `x` എന്ന ഒരു argument മാത്രമേ ഉള്ളൂ എന്നും.
+* Indent ചെയ്തിരിക്കുന്ന code-നെ *function body* എന്ന് വിളിക്കുന്ന ഒരു code block ആണ്.
+* Calling code-ലേക്ക് return ചെയ്യേണ്ട object `abs_value` ആണ് എന്ന് `return` എന്ന keyword സൂചിപ്പിക്കുന്നു.
+
+ഈ മുഴുവൻ function definition-ഉം Python interpreter വായിച്ച് memory-യിൽ സൂക്ഷിക്കുന്നു.
+
+ഇത് പ്രവർത്തിക്കുന്നുണ്ടോ എന്ന് check ചെയ്യാൻ നമുക്ക് ഇതിനെ call ചെയ്യാം:
+
+```{code-cell} python3
+print(new_abs_function(3))
+print(new_abs_function(-3))
+```
+
+
+ശ്രദ്ധിക്കുക, ഒരു function-ന് എത്ര വേണമെങ്കിലും `return` statements ഉണ്ടാകാം (പൂജ്യം ഉൾപ്പെടെ).
+
+ആദ്യത്തെ return-ൽ എത്തിച്ചേരുമ്പോൾ function-ന്റെ execution അവസാനിക്കുന്നു, ഇത് താഴെ കൊടുത്തിരിക്കുന്നത് പോലുള്ള code സാധ്യമാക്കുന്നു
+
+```{code-cell} python3
+def f(x):
+ if x < 0:
+ return 'negative'
+ return 'nonnegative'
+```
+
+(പല return statements ഉള്ള functions എഴുതുന്നത് സാധാരണയായി discourage ചെയ്യപ്പെടുന്നു, കാരണം ഇത് logic പിന്തുടരാൻ ബുദ്ധിമുട്ടാക്കും.)
+
+Return statement ഇല്ലാത്ത functions automatically പ്രത്യേകമായ Python object ആയ `None` return ചെയ്യുന്നു.
+
+(pos_args)=
+### Keyword Arguments
+
+```{index} single: Python; keyword arguments
+```
+
+{ref}`Previous lecture `-ൽ, താഴെ കൊടുത്തിരിക്കുന്ന statement നിങ്ങൾ കണ്ടിരുന്നു
+
+```{code-block} python3
+:class: no-execute
+
+plt.plot(x, 'b-', label="white noise")
+```
+
+Matplotlib-ന്റെ `plot` function-നെ ഇവിടെ call ചെയ്യുമ്പോൾ, അവസാനത്തെ argument `name=argument` syntax-ൽ pass ചെയ്യുന്നത് ശ്രദ്ധിക്കുക.
+
+ഇതിനെ *keyword argument* എന്ന് വിളിക്കുന്നു, ഇവിടെ `label` ആണ് keyword.
+
+Keyword അല്ലാത്ത arguments-നെ *positional arguments* എന്ന് വിളിക്കുന്നു, കാരണം അവയുടെ അർത്ഥം order അനുസരിച്ചാണ് നിശ്ചയിക്കപ്പെടുന്നത്
+
+* `plot(x, 'b-')` differs from `plot('b-', x)`
+
+ധാരാളം arguments ഉള്ള ഒരു function-ന്റെ കാര്യത്തിൽ keyword arguments പ്രത്യേകിച്ചും useful ആണ്, കാരണം അത്തരം സന്ദർഭങ്ങളിൽ ശരിയായ order ഓർത്തിരിക്കാൻ ബുദ്ധിമുട്ടാണ്.
+
+User-defined functions-ലും keyword arguments യാതൊരു ബുദ്ധിമുട്ടും കൂടാതെ ഉപയോഗിക്കാം.
+
+താഴെ കൊടുത്തിരിക്കുന്ന ഉദാഹരണം syntax illustrate ചെയ്യുന്നു:
+
+```{code-cell} python3
+def f(x, a=1, b=1):
+ return a + b * x
+```
+
+`f`-ന്റെ definition-ൽ നമ്മൾ നൽകിയ keyword argument values default values ആയി മാറുന്നു
+
+```{code-cell} python3
+f(2)
+```
+
+താഴെ കൊടുത്തിരിക്കുന്ന രീതിയിൽ അവയെ modify ചെയ്യാം
+
+```{code-cell} python3
+f(2, a=4, b=5)
+```
+
+### The Flexibility of Python Functions
+
+{ref}`Previous lecture `-ൽ നമ്മൾ discuss ചെയ്തത് പോലെ, Python functions വളരെ flexible ആണ്.
+
+In particular
+
+* തന്നിരിക്കുന്ന ഒരു file-ൽ എത്ര functions വേണമെങ്കിലും define ചെയ്യാം.
+* Functions മറ്റ് functions-ന്റെ അകത്ത് define ചെയ്യാം (ഇത് പലപ്പോഴും ചെയ്യാറുണ്ട്).
+* മറ്റ് functions ഉൾപ്പെടെ ഏത് object-ഉം ഒരു function-ന് argument ആയി pass ചെയ്യാം.
+* Functions ഉൾപ്പെടെ ഏത് തരം object-ഉം ഒരു function-ന് return ചെയ്യാം.
+
+ഒരു function-നെ മറ്റൊരു function-ന് pass ചെയ്യുന്നത് എത്ര എളുപ്പമാണെന്നതിന്റെ ഉദാഹരണങ്ങൾ താഴെ കൊടുത്തിരിക്കുന്ന sections-ൽ നമ്മൾ കാണും.
+
+### One-Line Functions: `lambda`
+
+```{index} single: Python; lambda functions
+```
+
+ഒറ്റ line-ൽ simple ആയ functions create ചെയ്യാൻ `lambda` എന്ന keyword ഉപയോഗിക്കുന്നു.
+
+For example, താഴെ കൊടുത്തിരിക്കുന്ന രണ്ട് definitions-ഉം ഒരേ കാര്യമാണ് ചെയ്യുന്നത്:
+
+```{code-cell} python3
+def f(x):
+ return x**3
+```
+
+and
+
+```{code-cell} python3
+f = lambda x: x**3
+```
+
+`lambda` എന്തുകൊണ്ട് useful ആണ് എന്ന് കാണാൻ, നമുക്ക് $\int_0^2 x^3 dx$ കണക്കാക്കണം എന്ന് കരുതുക (നമ്മുടെ high-school calculus മറന്നു എന്നും കരുതുക).
+
+SciPy library-യിൽ `quad` എന്ന ഒരു function ഉണ്ട്, അത് ഈ കണക്കുകൂട്ടൽ നമുക്കായി ചെയ്യും.
+
+`quad` function-ന്റെ syntax `quad(f, a, b)` എന്നതാണ്, ഇവിടെ `f` ഒരു function ആണ്, `a`, `b` എന്നിവ numbers ആണ്.
+
+$f(x) = x^3$ എന്ന function create ചെയ്യാൻ താഴെ കൊടുത്തിരിക്കുന്ന രീതിയിൽ `lambda` ഉപയോഗിക്കാം
+
+```{code-cell} python3
+from scipy.integrate import quad
+
+quad(lambda x: x**3, 0, 2)
+```
+
+ഇവിടെ `lambda` create ചെയ്ത function-നെ *anonymous* എന്ന് പറയുന്നു, കാരണം അതിന് ഒരു പേരും നൽകിയിട്ടില്ല.
+
+
+### Why Write Functions?
+
+നിങ്ങളുടെ code-ന്റെ clarity improve ചെയ്യുന്നതിൽ user-defined functions പ്രധാനമാണ്, കാരണം അവ
+
+* വ്യത്യസ്ത logic-strands-നെ വേർതിരിക്കുന്നു
+* code reuse ചെയ്യാൻ സഹായിക്കുന്നു
+
+(ഒരേ കാര്യം രണ്ട് തവണ എഴുതുന്നത് [മിക്ക സമയത്തും അത്ര നല്ലതല്ല](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself))
+
+ഇതിനെക്കുറിച്ചുള്ള കൂടുതൽ കാര്യങ്ങൾ നമുക്ക് {doc}`പിന്നീട് ` കാണാം.
+
+## Applications
+
+### Random Draws
+
+{doc}`Previous lecture `-ലെ താഴെ കൊടുത്തിരിക്കുന്ന code ഒരിക്കൽക്കൂടി നോക്കാം
+
+```{code-cell} python3
+rng = np.random.default_rng()
+
+ts_length = 100
+ϵ_values = [] # empty list
+
+for i in range(ts_length):
+ e = rng.standard_normal()
+ ϵ_values.append(e)
+
+plt.plot(ϵ_values)
+plt.show()
+```
+
+നമുക്ക് ഈ program-നെ രണ്ട് ഭാഗങ്ങളായി break down ചെയ്യാം:
+
+1. Random variables-ന്റെ ഒരു list generate ചെയ്യുന്ന ഒരു user-defined function.
+1. താഴെ പറയുന്നവ ചെയ്യുന്ന program-ന്റെ പ്രധാന ഭാഗം
+ 1. Data ലഭിക്കാൻ ഈ function-നെ call ചെയ്യുന്നു
+ 1. Data plot ചെയ്യുന്നു
+
+ഇത് താഴെ കൊടുത്തിരിക്കുന്ന program-ൽ സാധിച്ചിരിക്കുന്നു
+
+(funcloopprog)=
+```{code-cell} python3
+def generate_data(n):
+ ϵ_values = []
+ for i in range(n):
+ e = rng.standard_normal()
+ ϵ_values.append(e)
+ return ϵ_values
+
+data = generate_data(100)
+plt.plot(data)
+plt.show()
+```
+
+Interpreter `generate_data(100)` എന്ന expression-ൽ എത്തുമ്പോൾ, `n`-ന്റെ വില 100 ആയി set ചെയ്ത് function body execute ചെയ്യുന്നു.
+
+ഇതിന്റെ ഫലമായി `data` എന്ന പേര് function return ചെയ്യുന്ന `ϵ_values` എന്ന list-ലേക്ക് *bind* ചെയ്യപ്പെടുന്നു.
+
+### Adding Conditions
+
+```{index} single: Python; Conditions
+```
+
+നമ്മുടെ `generate_data()` function-ന് ചില പരിമിതികളുണ്ട്.
+
+ആവശ്യാനുസരണം standard normals-ഓ $(0, 1)$-ൽ uniform random variables-ഓ return ചെയ്യാനുള്ള കഴിവ് നൽകി ഇതിനെ കുറച്ചുകൂടി useful ആക്കാം.
+
+ഇത് താഴെ കൊടുത്തിരിക്കുന്ന code-ൽ സാധിച്ചിരിക്കുന്നു.
+
+(funcloopprog2)=
+```{code-cell} python3
+def generate_data(n, generator_type):
+ ϵ_values = []
+ for i in range(n):
+ if generator_type == 'U':
+ e = rng.uniform(0, 1)
+ else:
+ e = rng.standard_normal()
+ ϵ_values.append(e)
+ return ϵ_values
+
+data = generate_data(100, 'U')
+plt.plot(data)
+plt.show()
+```
+
+Indentation വീണ്ടും code blocks-ന്റെ പരിധി നിശ്ചയിക്കുന്നതോടെ, if/else clause-ന്റെ syntax സ്വയം വ്യക്തമാകും എന്ന് പ്രതീക്ഷിക്കുന്നു.
+
+Notes
+
+* `U` എന്ന argument നമ്മൾ ഒരു string ആയാണ് pass ചെയ്യുന്നത്, അതുകൊണ്ടാണ് നമ്മൾ ഇത് `'U'` എന്ന് എഴുതുന്നത്.
+* Equality test ചെയ്യുന്നത് `==` syntax ഉപയോഗിച്ചാണ്, `=` അല്ല എന്നത് ശ്രദ്ധിക്കുക.
+ * ഉദാഹരണത്തിന്, `a = 10` എന്ന statement `a` എന്ന പേരിനെ `10` എന്ന value-യിലേക്ക് assign ചെയ്യുന്നു.
+ * `a`-യുടെ value അനുസരിച്ച്, `a == 10` എന്ന expression `True` അല്ലെങ്കിൽ `False` ആയി evaluate ചെയ്യപ്പെടുന്നു.
+
+ഇനി, മുകളിലെ code simplify ചെയ്യാൻ പല വഴികളുണ്ട്.
+
+ഉദാഹരണത്തിന്, ആവശ്യമുള്ള generator type-നെ ഒരു function, method, അല്ലെങ്കിൽ മറ്റ് [callable](https://typing.python.org/en/latest/spec/callables.html) object ആയി pass ചെയ്ത്, conditionals-നെ പൂർണ്ണമായും ഒഴിവാക്കാം.
+
+ഇത് മനസ്സിലാക്കാൻ, താഴെ കൊടുത്തിരിക്കുന്ന version consider ചെയ്യാം.
+
+(test_program_6)=
+```{code-cell} python3
+def generate_data(n, generator_type):
+ ϵ_values = []
+ for i in range(n):
+ e = generator_type()
+ ϵ_values.append(e)
+ return ϵ_values
+
+data = generate_data(100, rng.uniform)
+plt.plot(data)
+plt.show()
+```
+
+ഇനി, `generate_data()` എന്ന function-നെ call ചെയ്യുമ്പോൾ, നമ്മൾ `rng.uniform`-നെ രണ്ടാമത്തെ argument ആയി pass ചെയ്യുന്നു.
+
+ഈ object ഒരു *callable* ആണ് — അതായത്, parentheses ഉപയോഗിച്ച് call ചെയ്യാൻ കഴിയുന്ന ഒരു object.
+
+`generate_data(100, rng.uniform)` എന്ന function call execute ചെയ്യുമ്പോൾ, `n`-ന്റെ വില 100 ആയും, `generator_type` എന്ന പേര് `rng.uniform` എന്ന callable-ലേക്ക് "bind" ചെയ്തും Python function code block run ചെയ്യുന്നു.
+
+* ഈ lines execute ചെയ്യുന്ന സമയത്ത്, `generator_type`, `rng.uniform` എന്നീ പേരുകൾ "synonyms" ആണ്, ഒരേ രീതിയിൽ തന്നെ ഉപയോഗിക്കാം.
+
+ഈ തത്വം കുറച്ചുകൂടി വിശാലമായി പ്രവർത്തിക്കുന്നു --- ഉദാഹരണത്തിന്, താഴെ കൊടുത്തിരിക്കുന്ന code consider ചെയ്യാം
+
+```{code-cell} python3
+max(7, 2, 4) # max() is a built-in Python function
+```
+
+```{code-cell} python3
+m = max
+m(7, 2, 4)
+```
+
+ഇവിടെ നമ്മൾ built-in function ആയ `max()`-ന് മറ്റൊരു പേര് create ചെയ്തു, അത് ഒരേ രീതിയിൽ തന്നെ ഉപയോഗിക്കാം.
+
+നമ്മുടെ program-ന്റെ context-ൽ, functions-ലേക്ക്, അല്ലെങ്കിൽ കുറച്ചുകൂടി വിശാലമായി callable objects-ലേക്ക് പേരുകൾ bind ചെയ്യാനുള്ള കഴിവ് അർത്ഥമാക്കുന്നത്, ഒരു callable object-നെ മറ്റൊരു callable-ന് argument ആയി pass ചെയ്യുന്നതിൽ ഒരു പ്രശ്നവുമില്ല എന്നാണ് --- മുകളിൽ `rng.uniform`-ഉപയോഗിച്ച് നമ്മൾ ചെയ്തത് പോലെ.
+
+
+(recursive_functions)=
+## Recursive Function Calls (Advanced)
+
+```{index} single: Python; Recursion
+```
+
+ഇത് ഒരു advanced topic ആണ്, വേണമെങ്കിൽ ഇത് skip ചെയ്യാം.
+
+എന്നാൽ ഇത് ഒരു നല്ല idea ആണ്, നിങ്ങളുടെ programming career-ന്റെ ഏതെങ്കിലും stage-ൽ ഇത് പഠിക്കേണ്ടതാണ്.
+
+Basically, ഒരു recursive function എന്നാൽ സ്വയം call ചെയ്യുന്ന ഒരു function ആണ്.
+
+For example, ഏതെങ്കിലും $t$-ന് $x_t$ compute ചെയ്യുന്ന പ്രശ്നം consider ചെയ്യാം, ഇവിടെ
+
+```{math}
+:label: xseqdoub
+
+x_{t+1} = 2 x_t, \quad x_0 = 1
+```
+
+Obviously, answer $2^t$ ആണ്.
+
+ഒരു loop ഉപയോഗിച്ച് നമുക്ക് ഇത് എളുപ്പം compute ചെയ്യാം
+
+```{code-cell} python3
+def x_loop(t):
+ x = 1
+ for i in range(t):
+ x = 2 * x
+ return x
+```
+
+താഴെ കൊടുത്തിരിക്കുന്ന രീതിയിൽ ഒരു recursive solution-ഉം നമുക്ക് ഉപയോഗിക്കാം
+
+```{code-cell} python3
+def x(t):
+ if t == 0:
+ return 1
+ else:
+ return 2 * x(t-1)
+```
+
+ഇവിടെ സംഭവിക്കുന്നത്, ഓരോ successive call-ഉം *stack*-ലെ അതിന്റേതായ *frame* ഉപയോഗിക്കുന്നു എന്നതാണ്
+
+* തന്നിരിക്കുന്ന ഒരു function call-ന്റെ local variables സൂക്ഷിക്കുന്ന സ്ഥലമാണ് frame
+* function calls process ചെയ്യാൻ ഉപയോഗിക്കുന്ന memory ആണ് stack
+ * last-in, first-out (LIFO) എന്ന ഒരു data structure ആണിത്
+
+ഈ ഉദാഹരണം കുറച്ച് കൃത്രിമമാണ്, കാരണം സാധാരണയായി recursive solution-നേക്കാൾ ആദ്യത്തെ (iterative) solution ആയിരിക്കും preferred.
+
+Recursion-ന്റെ കൂടുതൽ സ്വാഭാവികമായ applications നമുക്ക് പിന്നീട് കാണാം.
+
+
+(factorial_exercise)=
+## Exercises
+
+```{exercise-start}
+:label: func_ex1
+```
+
+Recall that $n!$ is read as "$n$ factorial" and defined as
+$n! = n \times (n - 1) \times \cdots \times 2 \times 1$.
+
+We will only consider $n$ as a positive integer here.
+
+There are functions to compute this in various modules, but let's
+write our own version as an exercise.
+
+In particular, `factorial` എന്ന് പേരുള്ള ഒരു function എഴുതുക, such that `factorial(n)` returns $n!$ for any positive integer $n$.
+
+```{exercise-end}
+```
+
+
+```{solution-start} func_ex1
+:class: dropdown
+```
+
+Here's one solution:
+
+```{code-cell} python3
+def factorial(n):
+ k = 1
+ for i in range(n):
+ k = k * (i + 1)
+ return k
+
+factorial(4)
+```
+
+
+```{solution-end}
+```
+
+
+```{exercise-start}
+:label: func_ex2
+```
+
+The [binomial random variable](https://en.wikipedia.org/wiki/Binomial_distribution) $Y \sim Bin(n, p)$ represents the number of successes in $n$ binary trials, where each trial succeeds with probability $p$.
+
+Using `rng = np.random.default_rng()`, write a function
+`binomial_rv` such that `binomial_rv(n, p)` generates one draw of $Y$.
+
+```{hint}
+:class: dropdown
+
+If $U$ is uniform on $(0, 1)$ and $p \in (0,1)$, then the expression `U < p` evaluates to `True` with probability $p$.
+```
+
+```{exercise-end}
+```
+
+
+```{solution-start} func_ex2
+:class: dropdown
+```
+
+Here is one solution:
+
+```{code-cell} python3
+rng = np.random.default_rng()
+
+def binomial_rv(n, p):
+ count = 0
+ for i in range(n):
+ U = rng.uniform()
+ if U < p:
+ count = count + 1 # Or count += 1
+ return count
+
+binomial_rv(10, 0.5)
+```
+
+```{solution-end}
+```
+
+
+```{exercise-start}
+:label: func_ex3
+```
+
+First, write a function that returns one realization of the following random device
+
+1. Flip an unbiased coin 10 times.
+1. If a head occurs `k` or more times consecutively within this sequence at least once, pay one dollar.
+1. If not, pay nothing.
+
+Second, write another function that does the same task except that the second rule of the above random device becomes
+
+- If a head occurs `k` or more times within this sequence, pay one dollar.
+
+Use `rng = np.random.default_rng()` to generate random numbers.
+
+```{exercise-end}
+```
+
+```{solution-start} func_ex3
+:class: dropdown
+```
+
+Here's a function for the first random device.
+
+
+
+
+```{code-cell} python3
+rng = np.random.default_rng()
+
+def draw(k): # pays if k consecutive successes in a sequence
+
+ payoff = 0
+ count = 0
+
+ for i in range(10):
+ U = rng.uniform()
+ count = count + 1 if U < 0.5 else 0
+ print(count) # print counts for clarity
+ if count == k:
+ payoff = 1
+
+ return payoff
+
+draw(3)
+```
+
+Here's another function for the second random device.
+
+```{code-cell} python3
+def draw_new(k): # pays if k successes in a sequence
+
+ payoff = 0
+ count = 0
+
+ for i in range(10):
+ U = rng.uniform()
+ count = count + ( 1 if U < 0.5 else 0 )
+ print(count)
+ if count == k:
+ payoff = 1
+
+ return payoff
+
+draw_new(3)
+```
+
+```{solution-end}
+```
+
+
+## Advanced Exercises
+
+താഴെ കൊടുത്തിരിക്കുന്ന exercises-ൽ, നമുക്ക് ഒരുമിച്ച് recursive functions എഴുതാം.
+
+
+```{exercise-start}
+:label: func_ex4
+```
+
+The Fibonacci numbers are defined by
+
+```{math}
+:label: fib
+
+x_{t+1} = x_t + x_{t-1}, \quad x_0 = 0, \; x_1 = 1
+```
+
+The first few numbers in the sequence are $0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55$.
+
+Write a function to recursively compute the $t$-th Fibonacci number for any $t$.
+
+```{exercise-end}
+```
+
+```{solution-start} func_ex4
+:class: dropdown
+```
+
+Here's the standard solution
+
+```{code-cell} python3
+def x(t):
+ if t == 0:
+ return 0
+ if t == 1:
+ return 1
+ else:
+ return x(t-1) + x(t-2)
+```
+
+Let's test it
+
+```{code-cell} python3
+print([x(i) for i in range(10)])
+```
+
+```{solution-end}
+```
+
+```{exercise-start}
+:label: func_ex5
+```
+
+[Exercise 1](factorial_exercise)-ലെ `factorial()` function-നെ, recursion ഉപയോഗിച്ച് വീണ്ടും എഴുതുക.
+
+```{exercise-end}
+```
+
+```{solution-start} func_ex5
+:class: dropdown
+```
+
+Here's the standard solution
+
+```{code-cell} python3
+def recursion_factorial(n):
+ if n == 1:
+ return n
+ else:
+ return n * recursion_factorial(n-1)
+```
+
+Let's test it
+
+```{code-cell} python3
+print([recursion_factorial(i) for i in range(1, 10)])
+```
+
+```{solution-end}
+```