# Price and Markdown Optimization for Multiple Time Intervals

This model optimizes prices for N consecutive time periods 
each of which has its own demand function. It is assumed that 
the stock level of the product is limited and the goal
is to sell out the stock in time maximizing the revenue.

### Detailed Description
See [Introduction to Algorithmic Marketing](https://algorithmicweb.wordpress.com/ ) book.

### Data
We use a simulator. No external datasets are used.

### Papers
Ferreira2017 (see [papers](https://github.com/ikatsov/tensor-house/blob/master/resources/papers.md))


```python
%matplotlib inline
import sympy as sy
import numpy as np
from tabulate import tabulate
import matplotlib.pyplot as plt
from scipy.optimize import linprog

def tabprint(msg, A):
    print(msg)
    print(tabulate(A, tablefmt="fancy_grid", floatfmt=".2f"))
```


```python
plevels = [89, 79, 69, 59, 49] # allowed price levels
C = 700                        # stock level

price = sy.symbols("price")

def rectified(f):
    return sy.Piecewise( (0, f < 0), (f, True))

# Demand functions estimated for each week of the sale
demands = [rectified(1500 - 10*price), # week 1
           rectified(1300 - 15*price), # week 2
           rectified(1200 - 15*price), # week 3
           rectified(1100 - 18*price)] # week 4
```


```python
# Evaluate values of demand functions for each price level
D = np.array([[q.subs(price, p) for p in plevels] for q in demands])
tabprint("D =", D)

# Evaluate revenue for each demand function and each price level
R = np.array([[p*q.subs(price, p) for p in plevels] for q in demands])
tabprint("R =", R)
```

    D =
    ╒════════╤════════╤════════╤════════╤═════════╕
    │ 610.00 │ 710.00 │ 810.00 │ 910.00 │ 1010.00 │
    ├────────┼────────┼────────┼────────┼─────────┤
    │   0.00 │ 115.00 │ 265.00 │ 415.00 │  565.00 │
    ├────────┼────────┼────────┼────────┼─────────┤
    │   0.00 │  15.00 │ 165.00 │ 315.00 │  465.00 │
    ├────────┼────────┼────────┼────────┼─────────┤
    │   0.00 │   0.00 │   0.00 │  38.00 │  218.00 │
    ╘════════╧════════╧════════╧════════╧═════════╛
    R =
    ╒══════════╤══════════╤══════════╤══════════╤══════════╕
    │ 54290.00 │ 56090.00 │ 55890.00 │ 53690.00 │ 49490.00 │
    ├──────────┼──────────┼──────────┼──────────┼──────────┤
    │     0.00 │  9085.00 │ 18285.00 │ 24485.00 │ 27685.00 │
    ├──────────┼──────────┼──────────┼──────────┼──────────┤
    │     0.00 │  1185.00 │ 11385.00 │ 18585.00 │ 22785.00 │
    ├──────────┼──────────┼──────────┼──────────┼──────────┤
    │     0.00 │     0.00 │     0.00 │  2242.00 │ 10682.00 │
    ╘══════════╧══════════╧══════════╧══════════╧══════════╛



```python
# Now we solve the following optimization problem:
# (q is demand, P is price, T is the number of time periods, and K is the number of price levels)
```

$\text{max} \quad \sum_{t=1}^{T} \sum_{i=1}^{K} z_{it} \cdot P_{i} \cdot q\left(P_{i},t\right)$ 

$\text{subject to}$

$\quad \sum_{t=1}^{T} \sum_{i=1}^{K} z_{it} \cdot q\left(P_{i},t\right) \le C $

$\quad \sum_{i=1}^{K} z_{it} = 1, \quad \text{for}\ t=1,\ldots,T $

$\quad z_{it}\ge 0 $


```python
L = len(demands)*len(plevels)

# First, we generate a binary mask to ensure that all z's 
# in one time interval sum up to 1.0, that is z.M = B
M = np.array([[
    1 if i >= len(plevels)*j and i < len(plevels)*(j+1) else 0
    for i in range(L)
] for j in range(len(demands))])

tabprint("M = ", M)

B = [1 for i in range(len(demands))]

# Second, we ensure that the sum of all demands is less than the availbale stock level,
# that is z.Df <= C
Df = np.array(D).reshape(1, L)

res = linprog(-np.array(R).flatten(), 
              A_eq=M, 
              b_eq=B, 
              A_ub=Df, 
              b_ub=np.array([C]), 
              bounds=(0, None))

print("Revenue value: $", -res.fun)

# Each column of the solution matrix corresponds to a time period (one week).  
# Each row corresponds to z value that can be interpreted as the percentage 
# of time z't price level should be used in the corresponding time period. 
tabprint("Price schedule:", np.array(res.x).reshape(len(demands), len(plevels)).T)
```

    M = 
    ╒══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╤══════╕
    │ 1.00 │ 1.00 │ 1.00 │ 1.00 │ 1.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │
    ├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
    │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 1.00 │ 1.00 │ 1.00 │ 1.00 │ 1.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │
    ├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
    │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 1.00 │ 1.00 │ 1.00 │ 1.00 │ 1.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │
    ├──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┼──────┤
    │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 0.00 │ 1.00 │ 1.00 │ 1.00 │ 1.00 │ 1.00 │
    ╘══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╧══════╛
    Revenue value: $ 61400.000000123204
    Price schedule:
    ╒══════╤══════╤══════╤══════╕
    │ 1.00 │ 0.29 │ 0.47 │ 0.33 │
    ├──────┼──────┼──────┼──────┤
    │ 0.00 │ 0.71 │ 0.53 │ 0.33 │
    ├──────┼──────┼──────┼──────┤
    │ 0.00 │ 0.00 │ 0.00 │ 0.33 │
    ├──────┼──────┼──────┼──────┤
    │ 0.00 │ 0.00 │ 0.00 │ 0.00 │
    ├──────┼──────┼──────┼──────┤
    │ 0.00 │ 0.00 │ 0.00 │ 0.00 │
    ╘══════╧══════╧══════╧══════╛



```python

```

af9b38b6d900176a1d549556f5c9aff319fc4a4b
ipynb
Jupyter Notebook
pricing/price-optimization-multiple-time-intervals.ipynb
naga6674/Tensor-House
01950fda7ecfaa7f3fc7d827a14c5c37788a7bf3
Apache-2.0
2020-02-24T05:11:07.000Z
2022-03-31T01:18:56.000Z
pricing/price-optimization-multiple-time-intervals.ipynb
pponnada/tensor-house
01950fda7ecfaa7f3fc7d827a14c5c37788a7bf3
Apache-2.0
2020-04-21T16:39:55.000Z
2021-06-15T15:49:40.000Z
pricing/price-optimization-multiple-time-intervals.ipynb
pponnada/tensor-house
01950fda7ecfaa7f3fc7d827a14c5c37788a7bf3
Apache-2.0
2020-02-27T12:21:42.000Z
2022-03-31T11:15:09.000Z
Qwen/Qwen-72B
1. YES
2. YES