###### tags: `Python筆記`
# 【Python】決策科學作業4
## 第一題
```python
%pip install scipy --upgrade
import math
import matplotlib.pyplot as plt
import scipy.stats as stats
import scipy.optimize as opt
import numpy as np
import pandas as pd
%pip install statsmodels --upgrade
import statsmodels.api as sm
%pip install pymoo
import pymoo as pymoo
```
```python
#homework demand function:
arrD = [0,1,2,3,4,5,6,7,8,9,10]
def Demand(T):
d = np.random.choice(arrD , T , p=[0.01,0.02,0.04,0.06,0.09,0.14,0.18,0.22,0.16,0.06,0.02] )
return d
#Holding cost per item per day
h_val=0.6
unit_price=400
unit_cost=250
#Profit margin per TV sold
unit_profit=unit_price-unit_cost
#Cost per delivery from supplier to the dealer
shipping_cost=500
def InvModelsS(x):
#Set the seed for reproducibility
np.random.seed(5566)
#you have two decision variables
s=x[0]
S=x[1]
#The number of simulation runs
M=5000
#The number of days
T=360
#The experiment will be repeated for
#m in 1:M repetitions & t in 1:T duration
#Vector initialization
#SL: service level
SL=np.empty(M)
daily_profit=np.empty(M)
for m in range(M):
inv_onhand=np.empty(T+1)
inv_onhand[0]=S
sales=np.zeros(T)
orderQ=np.zeros(T)
#Keep track of inventory on-order but not arrived yet
inv_onorder=np.array([])
inv_onorder_stamp=np.array([])
#The number of deliveries from the supplier
delivery=0
#The total amount of lost sales
loss=0
#The number of stockouts in a repetition
stockout=0
#Simulate Poisson demand for T periods
# d=np.random.poisson(lambda_est,T)
d = Demand(T)
arrival=0
for t in range(T):
if t==0:
#Selling process
sales[t]=min(inv_onhand[t],d[t])
#Check stockout
if (d[t]>sales[t]):
stockout=stockout+1
loss=loss+(d[t]-sales[t])
#Compute inventory position
inv_position=inv_onhand[0]
#Ordering mechanism of (s, S)
if inv_position<=s:
#Compute order quantity
#This hw need to order the fixed quantity of Q
Q=S
#Update inventory on-order
inv_onorder=np.append(inv_onorder,Q)
#Simulate stochastic lead time
#change the lead time prob in homework
time_to_arrive=t+np.random.choice([3,4,5],size=1,p=[0.2,0.6,0.2])+1
#Update time stamp for invenory on-order
inv_onorder_stamp=np.append(inv_onorder_stamp,time_to_arrive)
#Record order quantity
orderQ[t]=Q
#Update inventory on-hand in the end of each day
inv_onhand[t+1]=inv_onhand[t]-sales[t]
###End t==0
if t>0:
#Check if any inventory on-order should arrive
if np.any(inv_onorder_stamp==t):
#Update the number of deliveries
delivery=delivery+1
#Compute the total of arrived inventories
index=np.where(inv_onorder_stamp==t)
arrival=np.sum(inv_onorder[index])
#Update inventory on-hand before starting the day
inv_onhand[t]=inv_onhand[t]+arrival
#Removed those just arrived from inventory on-order
inv_onorder=np.delete(inv_onorder,index)
inv_onorder_stamp=np.delete(inv_onorder_stamp,index)
#Record sales
sales[t]=min(inv_onhand[t],d[t])
#Check if any stockout takes place
if d[t]>sales[t]:
stockout=stockout+1
loss=loss+d[t]-sales[t]
#End if
#Update inventory position
inv_position=inv_onhand[t]+np.sum(inv_onorder)
#Ordering mechanism of (s, S) inventory policy
if (inv_position<=s):
#This hw need to order the fixed quantity of Q
Q=S
inv_onorder=np.append(inv_onorder,Q)
time_to_arrive=t+np.random.choice([3,4,5],size=1,p=[0.2,0.6,0.2])+1
inv_onorder_stamp=np.append(inv_onorder_stamp,time_to_arrive)
orderQ[t]=Q
#Update inventory on-hand in the end of the day
inv_onhand[t+1]=inv_onhand[t]-sales[t]
###End t>0
#print("t=",t,"d=",d[t],"arrival=",arrival,"; inv_onhand=",inv_onhand[t],"; order(t)=",orderQ[t])
###End t loop
#Calculate the service level (i.e., in-stock probability)
SL[m]=(T-stockout)/t
#Calculate the average daily profit
daily_profit[m]=(unit_profit*np.sum(sales)-np.sum(h_val*inv_onhand)-shipping_cost*delivery-unit_profit*loss)/T
#Print simulation progrss
#if (np.remainder(m,100)==0):
# print("m=",m)
return -1*np.mean(daily_profit)
```
```python
##Use Pymoo for numerical optimization
##Define the optimization problem first
from pymoo.problems.functional import FunctionalProblem
problemInv=FunctionalProblem(n_var=2,objs=InvModelsS,
xl=np.array([20,100]),xu=np.array([90,200]))
```
```python
##Hooke-Jeeves Search
from pymoo.algorithms.soo.nonconvex.pattern import PatternSearch
from pymoo.optimize import minimize
resHK=minimize(problemInv,algorithm=PatternSearch(),verbose=True)
print("Best solution found: \nX = %s\nF = %s" % (resHK.X, resHK.F))
```
```
=================================================
n_gen | n_eval | f_avg | f_min
=================================================
1 | 20 | -7.987321E+02 | -8.268439E+02
2 | 24 | -8.269384E+02 | -8.270328E+02
3 | 29 | -8.270328E+02 | -8.270328E+02
4 | 33 | -8.270328E+02 | -8.270328E+02
5 | 37 | -8.270452E+02 | -8.270576E+02
6 | 42 | -8.270576E+02 | -8.270576E+02
7 | 46 | -8.270638E+02 | -8.270700E+02
8 | 51 | -8.271015E+02 | -8.271330E+02
9 | 56 | -8.271330E+02 | -8.271330E+02
10 | 60 | -8.271330E+02 | -8.271330E+02
11 | 64 | -8.271330E+02 | -8.271330E+02
12 | 68 | -8.271330E+02 | -8.271330E+02
13 | 72 | -8.271330E+02 | -8.271330E+02
14 | 76 | -8.271330E+02 | -8.271330E+02
15 | 80 | -8.271330E+02 | -8.271330E+02
16 | 84 | -8.271330E+02 | -8.271330E+02
17 | 88 | -8.271330E+02 | -8.271330E+02
18 | 92 | -8.271330E+02 | -8.271330E+02
```
**Best solution found:**
X = [ 45.23958658 100. ]
F = [-827.13301022]
```python
##Nelder-Mead Search
from pymoo.algorithms.soo.nonconvex.nelder import NelderMead
resNM=minimize(problemInv,algorithm=NelderMead(),verbose=True)
print("Best solution found: \nX = %s\nF = %s" % (resNM.X, resNM.F))
```
```
=================================================
n_gen | n_eval | f_avg | f_min
=================================================
1 | 20 | -7.971971E+02 | -8.210567E+02
2 | 22 | -8.202593E+02 | -8.210567E+02
3 | 23 | -8.198597E+02 | -8.210567E+02
4 | 25 | -8.210112E+02 | -8.224950E+02
5 | 27 | -8.232974E+02 | -8.263406E+02
6 | 29 | -8.252921E+02 | -8.270408E+02
7 | 31 | -8.261500E+02 | -8.270408E+02
8 | 33 | -8.267295E+02 | -8.270408E+02
9 | 35 | -8.268829E+02 | -8.270408E+02
10 | 37 | -8.269563E+02 | -8.270408E+02
11 | 41 | -8.269082E+02 | -8.270408E+02
12 | 43 | -8.269913E+02 | -8.270568E+02
13 | 45 | -8.270613E+02 | -8.270862E+02
14 | 47 | -8.270701E+02 | -8.270862E+02
15 | 51 | -8.270680E+02 | -8.270944E+02
16 | 53 | -8.270919E+02 | -8.270952E+02
17 | 55 | -8.271026E+02 | -8.271181E+02
18 | 57 | -8.271237E+02 | -8.271579E+02
19 | 61 | -8.271493E+02 | -8.271579E+02
20 | 65 | -8.270960E+02 | -8.271740E+02
21 | 67 | -8.271198E+02 | -8.271740E+02
22 | 69 | -8.271329E+02 | -8.271740E+02
23 | 71 | -8.271613E+02 | -8.271740E+02
24 | 73 | -8.271632E+02 | -8.271740E+02
25 | 75 | -8.271643E+02 | -8.271740E+02
26 | 77 | -8.271770E+02 | -8.271961E+02
27 | 81 | -8.271831E+02 | -8.271961E+02
28 | 83 | -8.271894E+02 | -8.271961E+02
29 | 85 | -8.271956E+02 | -8.271961E+02
30 | 87 | -8.271970E+02 | -8.271987E+02
31 | 89 | -8.271979E+02 | -8.271988E+02
32 | 91 | -8.271983E+02 | -8.271988E+02
33 | 93 | -8.271992E+02 | -8.272000E+02
34 | 95 | -8.271993E+02 | -8.272000E+02
35 | 97 | -8.272000E+02 | -8.272010E+02
36 | 99 | -8.272010E+02 | -8.272020E+02
37 | 101 | -8.272025E+02 | -8.272045E+02
38 | 103 | -8.272039E+02 | -8.272054E+02
39 | 105 | -8.272059E+02 | -8.272079E+02
40 | 107 | -8.272074E+02 | -8.272088E+02
41 | 109 | -8.272079E+02 | -8.272088E+02
42 | 111 | -8.272081E+02 | -8.272088E+02
43 | 113 | -8.272086E+02 | -8.272091E+02
44 | 115 | -8.272093E+02 | -8.272100E+02
45 | 117 | -8.272095E+02 | -8.272100E+02
46 | 119 | -8.272095E+02 | -8.272100E+02
47 | 121 | -8.272096E+02 | -8.272100E+02
48 | 123 | -8.272097E+02 | -8.272100E+02
49 | 125 | -8.272099E+02 | -8.272101E+02
50 | 127 | -8.272100E+02 | -8.272101E+02
51 | 129 | -8.272100E+02 | -8.272101E+02
52 | 131 | -8.272101E+02 | -8.272102E+02
53 | 133 | -8.272102E+02 | -8.272102E+02
54 | 135 | -8.272102E+02 | -8.272103E+02
55 | 137 | -8.272102E+02 | -8.272103E+02
56 | 139 | -8.272103E+02 | -8.272103E+02
57 | 141 | -8.272103E+02 | -8.272103E+02
58 | 143 | -8.272103E+02 | -8.272103E+02
59 | 145 | -8.272103E+02 | -8.272103E+02
60 | 147 | -8.272103E+02 | -8.272103E+02
61 | 149 | -8.272103E+02 | -8.272103E+02
62 | 151 | -8.272103E+02 | -8.272103E+02
63 | 153 | -8.272103E+02 | -8.272103E+02
64 | 155 | -8.272103E+02 | -8.272103E+02
65 | 157 | -8.272103E+02 | -8.272103E+02
66 | 159 | -8.272103E+02 | -8.272103E+02
67 | 161 | -8.272103E+02 | -8.272103E+02
68 | 163 | -8.272103E+02 | -8.272103E+02
69 | 165 | -8.272103E+02 | -8.272103E+02
70 | 167 | -8.272103E+02 | -8.272103E+02
71 | 169 | -8.272103E+02 | -8.272103E+02
72 | 171 | -8.272103E+02 | -8.272103E+02
73 | 173 | -8.272103E+02 | -8.272103E+02
74 | 175 | -8.272103E+02 | -8.272103E+02
75 | 177 | -8.272103E+02 | -8.272103E+02
76 | 179 | -8.272103E+02 | -8.272103E+02
77 | 181 | -8.272103E+02 | -8.272103E+02
78 | 183 | -8.272103E+02 | -8.272103E+02
79 | 185 | -8.272103E+02 | -8.272103E+02
80 | 187 | -8.272103E+02 | -8.272103E+02
81 | 189 | -8.272103E+02 | -8.272103E+02
82 | 191 | -8.272103E+02 | -8.272103E+02
83 | 193 | -8.272103E+02 | -8.272103E+02
84 | 195 | -8.272103E+02 | -8.272103E+02
85 | 197 | -8.272103E+02 | -8.272103E+02
86 | 199 | -8.272103E+02 | -8.272103E+02
87 | 201 | -8.272103E+02 | -8.272103E+02
88 | 203 | -8.272103E+02 | -8.272103E+02
89 | 205 | -8.272103E+02 | -8.272103E+02
90 | 207 | -8.272103E+02 | -8.272103E+02
91 | 209 | -8.272103E+02 | -8.272103E+02
92 | 211 | -8.272103E+02 | -8.272103E+02
```
**Best solution found:**
X = [ 45.44456331 103.77779118]
F = [-827.21033316]