---
# System prepended metadata

title: 'Lesson 5: Recursion, Dynamic Programming'
tags: [Matlab Workshop]

---

---
tags: Matlab Workshop
---

# Lesson 5: Recursion, Dynamic Programming

## 1. Recursion
Recursion (遞迴) occurs when the definition of a concept or process depends on a simpler or previous version of itself [wikipedia-recursion](https://en.wikipedia.org/wiki/Recursion).

:::info
Factorial is defined as 

```
n! = 1 x 2 x ... x (n-1) x n
```

Or, we could use a recursive definition
![](https://i.imgur.com/CSgVobE.png)
```
factorial(n) = n * factorial(n-1)
```
:::

We can use functions to define a recursion. The function would call itself within its definition.
```matlab
function result = factorial(n)
   if n <= 1
       result = 1;
   else
       result = n * factorial(n-1);
   end
end
disp(factorial(5)) % 120
```

### Fibonacci sequence
1, 1, 2, 3, 5, 8, 13, 21, ...

`n` is the length of the sequence. `i` is the index of the sequence element.
- `i` $\in\{1, 2\}$ $\rightarrow$ `Fibonacci(i)` $= 1$
- `i` $>2$ $\rightarrow$ `Fibonacci(i)` $=$ `Fibonacci(i-1)` $+$ `Fibonacci(i-2)`

:::warning
Please implement the above calculation.
```matlab
function result = fibonacci(i)
    if ...
      % some equation you want to put
    else
        % equation for getting the fibonacci sequence
    end
end
disp(fibonacci(8)) % >>> 21
disp(fibonacci(21)) % >>> 10946
```
Put your code [here](https://hackmd.io/k4ni6ad7TRKt85VCPVQmeg).
:::

## 2. Dynamic programming (DP)

In the previous example when calculating Fibonacci sequence, we can break down the overall recursion steps. For example when calculating fib(5),

![](https://i.imgur.com/kP0Gcs1.png)

We can see a lot of repeated work is done. 

Three points of dynamic programming:
1. **Avoiding redundant calculations**
   We use the recursion idea. 
2. **Bottom-up approach**
   Starting from a simple case (`fib(0)`) up to complex cases (`fib(N)`)
3. **Memorization**
   Recording the previous answers instead of calculate them everytime. We can store previous ```fib(n)``` results.

 
```matlab
function r = memo_fib(n)
    % Handle base cases directly
    if n == 1 || n == 2
        r = 1;
        return;
    end
    
    % Initialize memo array for iterative approach
    memo = zeros(1, n);
    memo(1) = 1;
    memo(2) = 1;
    
    % Fill the memo array iteratively
    for i = 3:n
        memo(i) = memo(i-1) + memo(i-2);
    end
    
    % Result is the nth Fibonacci number
    r = memo(n);
end

disp(memo_fib(8)) % 120
disp(memo_fib(21)) % 720

```

"Memorization" and "Dynamic Programming" are often used interchangeably.

Now, let's see the execution speed of both recursion and dynamic programming.

:::info
### Let's try! Why one runs faster?
```matlab
Using the fibonacci example using recursion:
tic; disp(fibonacci(30)); toc 


Using the fibonacci example using dynamic programming
tic; disp(memo_fib(30)); toc 
```

`tic` and `toc` are functions to check the execution speed of the code.
:::

### Sample Outline for Homework 1
```
%input
input sequence 1 (dealing with characters)
input sequence 2 (dealing with characters)

%scores
match_score (dealing with integer)
mismatch_penalty (dealing with integer)
gap_penalty (dealing with integer)

%creating the initial matrix with zeroes as values
%use the sequence length as the row (sequence 2) and column (sequence 1)

matrix dimension(seq_1_length, seq_2_length)
Hint: using the function: zeros(n,m)

%fill in the initial matrix with scores
%calculate for the match or mismatch score for each base 

for i = 1:seq_2_length+1
    for j = 1:seq_1_length+1
        %checking the top, left, and diagonal cells
        %get the max score among these three
    end
end


%Traceback part
1.You need to store aligned sequences

2.You need to start from the very bottom cell which is (sequence_1_length, sequence_2_length)

3.Evaluate the scores to know the direction of tracing back
Hint:
    a) Use while loop to have loop until you go back to the leftmost cell
    b) Use if-else condition to know whether to put a gap or proceed to the next nucleotide
    
4.Reverse the aligned sequence you stored from the end of the sequence or bottom-most right cell of the score matrix

```

## Knapsack problems

### 0-1 knapsack problem

Now, we look at the 0-1 knapscak problem. "0-1" means that an item can be either taken or not taken (no available item). We can solve the problem using the naive searching approach (brute force approach), but it would get very slow when there is a lot of items.

Goal: To find the number of items that will give us the highest price given a maximum capacity (weights) you can buy.

Combination count:
```
2 ^ #items
```

We can use DP on this problem.


```matlab
values = [6, 4, 10, 12];
weights = [1, 4, 2, 3];
capacity = 5;
```

We construct a 2D array of [N_items][capacity]

|   | cap: 0 | cap: 1 | cap: 2 | cap: 3 | cap: 4 | cap: 5 |
|---|---|---|---|---|---|---|
| # of item available: 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| # of item available: 1 | 0 |   |   |   |   |   |
| # of item available: 2 | 0 |   |   |   |   |   |
| # of item available: 3 | 0 |   |   |   |   |   |
| # of item available: 4 | 0 |   |   |   |   |   |

x: capacity
y: item count
val: highest price

```matlab
prices = [6, 4, 10, 12];
weights = [1, 4, 2, 3];
capacity = 5;

n = length(prices);
table = zeros(n+1, capacity+1);

for i = 1:n+1
    for j = 1:capacity+1
        if i==1 || j==1 % boundary condition
            table(i, j) = 0;
        else                       
            new_item_idx = i-1;
            cap_limit = j-1;
            new_item_weight = weights(new_item_idx);
            new_item_price = prices(new_item_idx);

            if new_item_weight <= cap_limit
                % we could either take it or not take it
                take_price = new_item_price + table(i-1, j-new_item_weight);
                not_take_price = table(i-1, j); % as if this item is not available
                table(i, j) = max(take_price, not_take_price);
                
            else % this item is too heavy, as if this item is not avialable
               table(i, j) = table(i-1, j); 
            end
        end
    end
end
```

:::info
### Exercise

We have a rod of length n and rods with different length have different price. We want find the optimal way to cut the rod to obtain the highest profit.

![](https://i.imgur.com/CYsaGm2.png)

Hint:

When n = 1, optimal profit is 1, we say f(1) = prices[1]

When n = 2, we can choose to cut or not cut, so the optimal profit is max(f(1)+prices[1], prices[2])

When n = 3, optimal profit would be max(f(2)+prices[1], f(1)+prices[2], prices[3])

```matlab
prices = [1, 5, 8, 9, 10, 17, 17, 20];
optimal_profits = zeros(1, 8);

a = length(prices)
for i = 1:a
    if i == 1 % boundary condition
        optimal_profits(i) = prices(1);
    else
        % recursive definition here!
        
    end
end
```
:::

## Take Home Exercise

### 1. 2D Maze

There's a 2D maze with some rocks on the way and you cannot walk across rocks. Calculate how many different but meaningful routes a person can take from the starting point to the ending point.

![](https://i.imgur.com/NX0v2M5.png)
