:::spoiler 目錄 [toc] ::: # 04.22 ## 討論內容:決策模型思維 1. 決策者:醫院 2. 涵蓋的時間範圍:一天 3. 決策變數:發車時間班表、哪部車、要載誰、路徑(? 4. 不能夠控制(給定決策環境、條件):有哪些患者搭車(多少患者幾點已經到院區)、看診與領藥時間(依科別)、加入等待線的時間 5. 操作性限制(決策者訂下之政策、規定):等待時間上限、某個時段內一定要發車、一天最少發幾次車、車一定要多滿、班距多少以內 6. 資源性限制:車隊大小、車子容量 ## 流程圖 ![pic1](https://hackmd.io/_uploads/S1iqtwIfA.png) ## 集合、參變數 ### Sets * $N:\ 所有病患的集合$ * $V:\ 所有車輛的集合$ * $G_i:\ 地理群集\ i\ 中的病患 \to G_i \subseteq N$ * $D:\ 所有科別的集合$ ### Parameters #### 病患資料 * $t_i:\ 病患\ i\ 到醫院的報到時間$ * $d_i:\ 病患\ i\ 所看的科別$ * $m_i:\ 病患\ i\ 所看的醫師$ * $h_i:\ 病患\ i\ 的家$(回程目的地) #### 醫院參數 * $s_{d,m}:\ 科別\ d\ 醫師\ m\ 的看診時間$(服務率) #### 加入等待線時間 * $a_i:\ 病患\ i\ 加入等待清待的時間$(拿藥時間(?) #### 車隊 * $flt:\ 車隊規模$ * $cap:\ 一台車子的容量$ * $oil:\ 一台車子的平均油耗$ ### Variables * $\tau_{i,n}:\ i\ 車第\ n\ 次發車的時間$ * $\phi_i^{j, n}\in\{0, 1\}:\ 病患\ i\ 搭上\ j\ 車\ n\ 車次為\ 1$ ### Dependent Variables * $w_i:\ 病患\ i\ 的累積等待時間 = \sum_{n = 0}^{5}\phi_i^{j, n}\tau_{j, n} - a_i\,,\ \ \tau_{i, n-1}<a_i<\tau_{i, n+1}$ ## 模型 ### Objective function * $\min \sum_{i=0}^{n}C_i$ (每車次成本總和) ### Constraints 1. $最大等待時間限制:\ w_i \le 60\,,\ \forall \ i\in N$ 2. $平均等待時間限制$ 3. $於系統內時間限制$ 4. $於系統內最大時間限制$ 5. $車容量限制$ 6. $繞行距離限制$ 7. $繞行時間限制$ 8. $容量利用率限制$ 9. $一位患者只能搭乘一次$ 10. $車必從醫院出發$ 11. $車必須回到醫院$ 12. $前一車次回到醫院後下一車次才可出發$ ## 問題 1. 一個患者可能看超過一科 $\to$ 不討論 2. 車次不知道要怎麼設定 3. 決定路線要怎麼加在裡面 4. 要 routing 嗎 5. 不知道歷史資料真正的用途 $\to$ 服從某種隨機變數分配 --- # 05.07 ## 討論內容 ### PART I * 模擬情境 * 給定資料(先以亂數產生):回程目的地$\ h_i(x, y)$、看診科別$\ d_i$、報到時間$\ t_i$ * 以歷史資料推估之資料:預估看診結束時間、預估領藥時間、預估加入等待線時間$\ a_i$ * 以函數表示 * $a_i=t_i+f(·)$ * 決策資料:每位病患被指派的車次 * 預設車次時間 * 得到初始解 * 績效資料:預估繞行時間 * 以此再去求更好的解 ### PART II * 思考答案結構 * 先給訂班次數 * 求發車時間點 * 搭車人數超過就發車 * 問題特性選擇 * 車輛路線分區:影響繞行時間 * 分區 or 不分區 or 不同路線合併? * 處理 Queue 的法則:影響排隊者心理 * FIFO or ...? * 二階段求解 * heuristic 的方式模擬,e.g. 路線過長就 cut 1. 用不同的法則去建立地理集群、依據集群去排班表 2. solution approach: 計算 KPI、模擬 * 班車準點率、服務水準、容量利用率等 * 給定 KPI、限制 $\to$ 加權平均得到整合評估值 :::info * **決策情境不會用寫數學模式來解決** * **勿將決策情境與求解混在一起** ::: --- # 08.03 ## Pseudo Code ### system - `addPatient` ```pseudo= Initialization: for each patient to be added to the system do: Create a new Patient object with the following parameters: - ID: unique identifier for the patient - dept: department the patient is associated with - doc: doctor assigned to the patient - dest: destination as a pair of coordinates (x, y) - arrival: patient's arrival time Call the predictAddedTime method on the patient object to: - Predict when the patient will be added to the system queue Call the setRegion method on the patient object to: - Determine the region of the patient based on destination or other criteria Add the patient object to the patients priority queue end for ``` - `addVehicle` ```pseudo= Initialization: for each vehicle to be added to the system do: Create a new Vehicle object with the following parameter: - ID: unique identifier for the vehicle Add the vehicle object to the vehicles list end for ``` - `generateSchedule` ```pseudo= Initialization: Create a predefined schedule of departure times for each vehicle: schedule = [ {660, 960, 1140}, {840, 1080, 1260}, {900, 1140, 1200}, {720, 1140, 1020} ] for each vehicle i in vehicles do: Assign the ideal departure times from the schedule to the vehicle's idealDeptTime Set the vehicle's first predicted departure time: vehicle.predDeptTime.push_back(vehicle.idealDeptTime.front()) end for Call the planReturnTrips method to: - Schedule and manage the return trips based on the current schedule ``` - `planReturnTrips` ```pseudo= Initialization: Set the simulation clock to start from the beginning of the operating time while the clock is less than or equal to 1320 do: while there are patients in the queue do: Get the top patient from the patients priority queue if the patient's addedTime is less than or equal to the current clock time then: Add the patient to the waiting line based on their region: waitingLine[patient.region].push_back(patient) Remove the patient from the patients priority queue else: Break out of the inner loop end if end while for each vehicle in vehicles do: Get the vehicle's ideal and predicted departure times Calculate nth_dept as the size of vehicle.predDeptTime minus 1 if nth_dept is greater than or equal to vehicle.numberOfTrip then: Continue to the next iteration end if Calculate the actual departure time deptTime as: deptTime = max(ideal[nth_dept], pred[nth_dept]) if the clock matches deptTime then: Print the current time and vehicle ID while the vehicle's waiting line is not empty and it has capacity do: Get the first patient from the waiting line Set the patient's getOnVehicleTime to the current clock time Add the patient to the vehicle's list of patients Add the patient to the returnedPatients list Remove the patient from the waiting line Print the patient's ID as they get on the vehicle end while Call predictRoutingTime on the vehicle to: - Calculate routing and clear the vehicle's patients Clear the vehicle's patient list end if end for Increment the clock by 1 minute end while ``` - `displayPlan` ```pseudo= Initialization: Print the system result header for each vehicle in vehicles do: Print the vehicle's ID for each departure time in vehicle.predDeptTime except the last one do: Calculate the actual departure time as: deptTime = max(vehicle.idealDeptTime[i], vehicle.predDeptTime[i]) Print the actual departure time end for Print a newline for better readability end for Print a newline for better readability ``` - `calculatePerformance` ```pseudo= Initialization: Set idleTime to 0 for each vehicle in vehicles do: for each departure time i in vehicle.predDeptTime do: Add to idleTime the difference between ideal and predicted times if positive: idleTime += max(0, vehicle.idealDeptTime[i] - vehicle.predDeptTime[i]) end for end for Set totalWaitingTime to 0 for each patient in returnedPatients do: Calculate the waiting time as the difference between getOnVehicleTime and addedTime: totalWaitingTime += patient.getOnVehicleTime - patient.addedTime end for Calculate avgWaitingTime as totalWaitingTime divided by the number of returned patients: avgWaitingTime = totalWaitingTime / returnedPatients.size() if there are no returned patients then: Set avgWaitingTime to 0 end if Calculate missedPatients as the total size of all waiting lines: missedPatients = sum(size of each waitingLine) Set totalReturnTime to 0 for each waiting line do: for each patient in the waiting line do: Calculate total return time by adding the absolute values of the patient's destination coordinates: totalReturnTime += abs(patient.destination.x) + abs(patient.destination.y) end for end for Calculate totalPerformance as: totalPerformance = 2000 - (idleTime + 1.5 * avgWaitingTime + 0.1 * totalReturnTime) Print the performance metrics: - Idle time in hours and minutes - Average waiting time in hours and minutes - Number of missed patients - Total return time of missed patients in hours and minutes - Total performance score ``` ### vehicle - `predictRoutingTime` ```pseudo= Initialization: Set lastDept to the index of the last element in predDeptTime Set lastDeptTime to the maximum value between idealDeptTime[lastDept] and predDeptTime[lastDept] Print the actual departure time in hours and minutes Set nextDeptTime to lastDeptTime Set currNode to the coordinates (0, 0) Create an empty list called distances for each patient in patients do: Get the patient's destination coordinates (x, y) Calculate the distance from the hospital as the sum of the absolute values of x and y Add the distance and patient to the distances list end for Sort the distances list by the distance value for each (distance, patient) in distances do: Get the current node coordinates (currX, currY) Get the patient's destination coordinates (nextX, nextY) Add the travel time to nextDeptTime as the sum of the absolute differences between nextX and currX, and nextY and currY Update currNode to the coordinates (nextX, nextY) end for Print the predicted return time in hours and minutes Add nextDeptTime to predDeptTime ``` ### patient - `predictAddedTime` ```pseudo= Set onCallTime to 35 (time for on call) Set shape to 7.400846 and scale to 1.0 / 0.441871 (parameters for preparing drug, 9-10 o'clock) Create a random number generator Create a gamma distribution with the given shape and scale Generate a random value using the gamma distribution and convert it to an integer, assigning it to prepDrugTime Calculate addedTime as the sum of arrivalTime, onCallTime, and prepDrugTime ``` | 路線編號 | 路線名稱 | 路線距離 (km) | 總人數 | 占比 (%) | 各站人數 (人) | 各站占比 (%) | |----------|------------------------------------|---------------|--------|----------|----------------------------------|--------------------------------------------------| | 1 | 斗六 - 林內 - 竹山 | 22 | 80 | 14.08 | 52, 20, 8 | 65%, 25%, 10% | | 2 | 斗六 - 虎尾 - 土庫 - 褒忠 - 東勢 - 台西 - 四湖 | 38 | 109 | 19.19 | 52, 33, 13, 4, 1, 5, 1 | 47.71%, 30.27%, 11.92%, 3.67%, 0.92%, 4.59%, 0.92% | | 3 | 斗六 - 斗南 - 大埤 - 元長 - 北港 - 水林 - 口湖 | 53 | 139 | 24.47 | 52, 69, 14, 3, 0, 1, 0 | 37.41%, 49.64%, 10.07%, 2.15%, 0%, 0.72%, 0% | | 4 | 斗六 - 古坑 - 梅山 | 20 | 110 | 19.37 | 52, 50, 8 | 47.27%, 45.45%, 7.27% | | 5 | 斗六 - 莿桐 - 西螺 - 二崙 - 崙背 - 麥寮 | 40 | 130 | 22.89 | 52, 44, 18, 6, 2, 8 | 40%, 33.85%, 13.85%, 4.62%, 1.54%, 6.15% | | **總計** | | | **568** | **100** | | |