GitHub

@@ -424,10 +424,63 @@ means that there is no problem *passing a function as an argument to another

424424

function*---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+

```

431484432485

Recall 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

452505453506

Try 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+

```

503558504559

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$.

505560506561

Without 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$.

508563509564

Hint: 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+

```

537594538595

First, 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.

547604548605

Use 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+

```

554613555614

Here's a function for the first random device.

556-

```

615+616+617+557618558619

```{code-cell} python3

559620

from 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+

```

Read the original on github.com ↗