@@ -424,10 +424,63 @@ means that there is no problem *passing a function as an argument to another
424424function*---as we did above.
425425426426427+(recursive_functions)=
428+## Recursive Function Calls (Advanced)
429+430+```{index} single: Python; Recursion
431+```
432+433+This is not something that you will use every day, but it is still useful --- you should learn it at some stage.
434+435+Basically, a recursive function is a function that calls itself.
436+437+For example, consider the problem of computing $x_t$ for some t when
438+439+```{math}
440+:label: xseqdoub
441+442+x_{t+1} = 2 x_t, \quad x_0 = 1
443+```
444+445+Obviously the answer is $2^t$.
446+447+We can compute this easily enough with a loop
448+449+```{code-cell} python3
450+def x_loop(t):
451+ x = 1
452+ for i in range(t):
453+ x = 2 * x
454+ return x
455+```
456+457+We can also use a recursive solution, as follows
458+459+```{code-cell} python3
460+def x(t):
461+ if t == 0:
462+ return 1
463+ else:
464+ return 2 * x(t-1)
465+```
466+467+What happens here is that each successive call uses it's own *frame* in the *stack*
468+469+* a frame is where the local variables of a given function call are held
470+* stack is memory used to process function calls
471+* a First In Last Out (FILO) queue
472+473+This example is somewhat contrived, since the first (iterative) solution would usually be preferred to the recursive solution.
474+475+We'll meet less contrived applications of recursion later on.
476+477+478+(factorial_exercise)=
427479## Exercises
428480429-```{exercise}
430-:label: exercise_1
481+```{exercise-start}
482+:label: func_ex1
483+```
431484432485Recall that $n!$ is read as "$n$ factorial" and defined as
433486$n! = n \times (n - 1) \times \cdots \times 2 \times 1$.
@@ -452,10 +505,11 @@ For example
452505453506Try to use lambda expressions to define the function `f`.
454507508+```{exercise-end}
455509```
456510457-```{solution-start} exercise_1
458-:label: solution_1
511+512+```{solution-start} func_ex1
459513:class: dropdown
460514```
461515@@ -498,19 +552,21 @@ factorial(2, f) # even (equivalent to factorial(5))
498552```
499553500554501-```{exercise}
502-:label: exercise_2
555+```{exercise-start}
556+:label: func_ex2
557+```
503558504559The [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$.
505560506561Without any import besides `from numpy.random import uniform`, write a function
507562`binomial_rv` such that `binomial_rv(n, p)` generates one draw of $Y$.
508563509564Hint: If $U$ is uniform on $(0, 1)$ and $p \in (0,1)$, then the expression `U < p` evaluates to `True` with probability $p$.
565+```{exercise-end}
510566```
511567512-```{solution-start} exercise_2
513-:label: solution_2
568+569+```{solution-start} func_ex2
514570:class: dropdown
515571````
516572@@ -532,8 +588,9 @@ binomial_rv(10, 0.5)
532588```
533589534590535-```{exercise}
536-:label: exercise_3
591+```{exercise-start}
592+:label: func_ex3
593+```
537594538595First, write a function that returns one realization of the following random device
539596@@ -546,14 +603,18 @@ Second, write another function that does the same task except that the second ru
546603- If a head occurs `k` or more times within this sequence, pay one dollar.
547604548605Use no import besides `from numpy.random import uniform`.
606+607+```{exercise-end}
549608```
550609551-```{solution-start} exercise_3
552-:label: solution_3
610+```{solution-start} func_ex3
553611:class: dropdown
612+```
554613555614Here's a function for the first random device.
556-```
615+616+617+557618558619```{code-cell} python3
559620from numpy.random import uniform
@@ -597,3 +658,100 @@ draw_new(3)
597658598659```{solution-end}
599660```
661+662+663+## Advanced Exercises
664+665+In the following exercises, we will write recursive functions together.
666+667+We will use more advanced syntaxes such as {any}`list comprehensions <list_comprehensions>` to test our solutions against a list of inputs.
668+669+If you are not familiar with these concepts, feel free to come back later.
670+671+672+```{exercise-start}
673+:label: func_ex4
674+```
675+676+The Fibonacci numbers are defined by
677+678+```{math}
679+:label: fib
680+681+x_{t+1} = x_t + x_{t-1}, \quad x_0 = 0, \; x_1 = 1
682+```
683+684+The first few numbers in the sequence are $0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55$.
685+686+Write a function to recursively compute the $t$-th Fibonacci number for any $t$.
687+688+```{exercise-end}
689+```
690+691+```{solution-start} func_ex4
692+:class: dropdown
693+```
694+695+Here's the standard solution
696+697+```{code-cell} python3
698+def x(t):
699+ if t == 0:
700+ return 0
701+ if t == 1:
702+ return 1
703+ else:
704+ return x(t-1) + x(t-2)
705+```
706+707+Let's test it
708+709+```{code-cell} python3
710+print([x(i) for i in range(10)])
711+```
712+713+```{solution-end}
714+```
715+716+```{exercise-start}
717+:label: func_ex5
718+```
719+720+For this exercise, rewrite the function `factorial(n)` in **[exercise 1](factorial_exercise)** using recursion.
721+722+```{exercise-end}
723+```
724+725+```{solution-start} func_ex5
726+:class: dropdown
727+```
728+729+Here's the standard solution
730+731+```{code-cell} python3
732+def recursion_factorial(n):
733+ if n == 1:
734+ return n
735+ else:
736+ return n * recursion_factorial(n-1)
737+```
738+Here's a simplified solution
739+740+```{code-cell} python3
741+def recursion_factorial_simplified(n):
742+ return n * recursion_factorial(n-1) if n != 1 else n
743+```
744+745+Let's test them
746+747+```{code-cell} python3
748+print([recursion_factorial(i) for i in range(1, 10)])
749+```
750+751+```{code-cell} python3
752+print([recursion_factorial_simplified(i) for i in range(1, 10)])
753+```
754+755+756+```{solution-end}
757+```