Simulasi Antrian yang Efisien Secara Komputasi melalui Paket R queuecomputer

Penulis: Anthony Ebert, Paul Wu, Kerrie Mengersen, Fabrizio Ruggeri

Sumber: https://stat.paperswithcode.com/paper/computationally-efficient-simulation-of

Abstrak

Jaringan besar dari sistem antrian digunakan untuk memodelkan berbagai sistem dunia nyata yang penting seperti klaster MapReduce, server web, rumah sakit, pusat panggilan (call center), dan terminal penumpang bandara. Untuk memodelkan sistem-sistem ini secara akurat, kita perlu mengestimasi parameter antrian berdasarkan data. Sayangnya, untuk banyak jaringan antrian, belum ada cara yang jelas untuk melakukan inferensi parameter dari data. Approximate Bayesian Computation (Perhitungan Bayesian Mendekati) dapat menjadi pendekatan yang mudah untuk mengestimasi parameter jaringan semacam ini—jika saja kita dapat mensimulasikan data dengan cukup cepat.

Kami memperkenalkan metode simulasi yang efisien secara komputasi untuk berbagai jenis jaringan antrian umum dengan menggunakan paket R queuecomputer. Percepatan kinerja yang luar biasa, lebih dari dua orde magnitudo, diamati jika dibandingkan dengan paket discrete event simulation (DES) populer seperti simmer dan simpy. Kami mereplikasi keluaran dari paket-paket tersebut untuk memvalidasi queuecomputer.

Paket ini bersifat modular dan terintegrasi dengan baik bersama paket R populer dplyr. Jaringan antrian yang kompleks dengan topologi tandem, paralel, dan fork/join dapat dengan mudah dibangun dengan menggabungkan kedua paket tersebut. Kami menunjukkan penggunaan paket ini melalui dua contoh: pusat panggilan dan terminal bandara.

Kata kunci: antrian, teori antrian, simulasi kejadian diskrit, riset operasi, approximate Bayesian computation, R

1. Pendahuluan

Antrian yang kita temui dalam kehidupan sehari-hari—di mana pelanggan menunggu dalam antrean untuk dilayani oleh pelayan—merupakan analogi yang berguna untuk banyak proses lainnya. Disebut analogi karena istilah pelanggan dalam konteks ini bisa merujuk pada: pekerjaan MapReduce (Lin et al., 2013); pasien di rumah sakit (Takagi et al., 2016); barang dalam sistem manufaktur (Dallery & Gershwin, 1992); panggilan masuk ke pusat layanan (Gans et al., 2003); kontainer pengiriman di pelabuhan (Kozan, 1997); bahkan tugas kognitif (Cao, 2013). Demikian pula, istilah pelayan bisa merujuk pada: klaster komputasi, tenaga medis, mesin produksi, atau petugas layanan pelanggan.

Sistem antrian juga bisa dihubungkan satu sama lain membentuk jaringan antrian. Jaringan ini bisa digunakan untuk membangun model proses-proses seperti: penyediaan layanan internet (Sutton & Jordan, 2011), fasilitasi penumpang di bandara internasional (Wu & Mengersen, 2013), serta evakuasi darurat (Van Woensel & Vandaele, 2007). Jelas bahwa sistem dan jaringan antrian sangat berguna dalam memahami berbagai sistem nyata yang penting.

Untuk mengukur performa dari suatu sistem antrian, sering kali diperlukan simulasi. Biasanya, antrian disimulasikan menggunakan pendekatan Simulasi Kejadian Diskrit (Discrete Event Simulation/DES) (Rios Insua et al., 2012). Dalam DES, perubahan keadaan bersifat tidak kontinu dan dipicu oleh sejumlah peristiwa (events) pada waktu-waktu tertentu. Bila kejadian terjadi hanya bergantung pada waktu simulasi, maka peristiwa tersebut determined; jika tidak, disebut contingent (Nance, 1981).

Beberapa perangkat lunak populer untuk DES tersedia dalam berbagai bahasa pemrograman, termasuk: simmer untuk R (Ucar & Smeets, 2016), simpy untuk Python (Lunsdorf & Scherfke, 2013), JMT untuk Java (Bertoli et al., 2009).

Bahkan, beberapa paket DES begitu ekspresif sehingga dianggap sebagai bahasa pemrograman tersendiri; contohnya, bahasa Simula (Dahl & Nygaard, 1966) adalah contoh literal dari hal ini.

Paket queuecomputer (Ebert, 2016) mengimplementasikan suatu algoritma yang dapat diterapkan secara luas pada berbagai sistem dan jaringan antrian. Pendekatan ini jauh lebih efisien secara komputasi dibandingkan pendekatan DES konvensional. Algoritma ini disebut sebagai Queue Departure Computation (QDC). Efisiensi komputasi menjadi sangat penting, karena jika kita dapat menyimulasikan sistem antrian dengan cepat, maka simulasi tersebut dapat disisipkan dalam algoritma Approximate Bayesian Computation (ABC) (Sunnåker et al., 2013), sehingga memungkinkan estimasi parameter dari model antrian yang kompleks secara lebih mudah.

Struktur artikel ini adalah sebagai berikut:

Bagian 2: Tinjauan pustaka tentang teori antrian dan notasi yang digunakan;

Bagian 3: Presentasi algoritma QDC dan perbandingannya dengan DES;

Bagian 4: Demonstrasi penggunaan paket queuecomputer;

Bagian 5: Penjelasan detail implementasi dan penggunaannya;

Bagian 6: Validasi paket dengan mereplikasi hasil dari simpy dan simmer;

Bagian 7: Benchmark performa paket dibandingkan dengan dua paket lainnya;

Bagian 8: Studi kasus simulasi pusat panggilan (call centre) dan terminal bandara.

2. Teori Antrian

Teori antrian adalah studi tentang sistem antrian dan berasal dari karya Agner Krarup Erlang pada tahun 1909 untuk merencanakan kebutuhan infrastruktur sistem telepon di Denmark (Thomopoulos 2012, hlm. 2).

Sebuah sistem antrian didefinisikan sebagai berikut.
Setiap pelanggan \(i = 1, 2, \dots\) memiliki waktu kedatangan \(a_i\) (atau secara ekuivalen waktu antar-kedatangan \(\delta_i = a_i - a_{i-1}\), dengan \(a_0 = 0\)), serta sejumlah waktu yang mereka butuhkan bersama pelayan, yang disebut waktu pelayanan \(s_i\).

Secara umum, seorang pelayan hanya dapat melayani satu pelanggan dalam satu waktu.
Pelayan yang sedang melayani pelanggan lain dikatakan tidak tersedia, sedangkan pelayan yang tidak sedang melayani siapa pun disebut tersedia.
Jika semua pelayan tidak tersedia saat seorang pelanggan datang, maka pelanggan harus menunggu dalam antrian sampai pelayan tersedia.

Pengantar mendalam tentang sistem antrian dapat ditemukan dalam buku-buku standar seperti Bhat (2015).

Karakteristik dari suatu sistem antrian dinyatakan dengan notasi Kendall (1953).
Notasi ini telah diperluas menjadi enam karakteristik:

  • \(f_\delta\): distribusi antar-kedatangan
  • \(f_s\): distribusi waktu pelayanan
  • \(K \in \mathbb{N}\): jumlah pelayan
  • \(C \in \mathbb{N}\): kapasitas sistem
  • \(n \in \mathbb{N}\): populasi pelanggan
  • \(R\): disiplin pelayanan$$

Pilihan umum untuk distribusi antar-kedatangan dan pelayanan adalah:
- “M” untuk distribusi eksponensial dan independen
- “GI” untuk distribusi umum dan independen
- “G” untuk distribusi umum tanpa asumsi independensi

Kapasitas sistem \(C\) mengacu pada jumlah maksimum pelanggan dalam sistem pada suatu waktu.
Pelanggan berada di dalam sistem jika mereka sedang dilayani atau menunggu dalam antrian.
Populasi pelanggan \(n\) adalah jumlah total pelanggan, termasuk yang belum datang atau sudah pergi.
Disiplin pelayanan \(R\) mendefinisikan bagaimana pelanggan dalam antrian dialokasikan ke pelayan yang tersedia.
Disiplin pelayanan yang paling umum adalah first come first serve (FCFS).

Untuk menentukan suatu sistem antrian, keenam karakteristik tersebut dituliskan secara berurutan dan dipisahkan dengan garis miring “/”.

Sistem antrian paling sederhana adalah sistem dengan distribusi eksponensial untuk waktu antar-kedatangan dan waktu pelayanan, yaitu:

  • \(\delta_i \overset{iid}{\sim} \text{Exp}(\lambda)\) untuk semua \(i \in 1{:}n\)
  • \(s_i \overset{iid}{\sim} \text{Exp}(\mu)\) untuk semua \(i \in 1{:}n\)

dengan \(\lambda\) dan \(\mu\) sebagai parameter laju eksponensial.
Selain itu, \(K\) diset menjadi 1, \(C\) dan \(n\) tak hingga (\(\infty\)), dan \(R\) adalah FCFS.

Sistem ini dinyatakan dengan:

\[ \text{M}/\text{M}/1/\infty/\infty/\text{FCFS} \]

yang biasanya disingkat menjadi:

\[ \text{M}/\text{M}/1 \]

Inferensi parameter untuk sistem ini pertama kali dibahas oleh Clarke (1957), di mana estimator diturunkan dari fungsi likelihood.
Likelihood ini kemudian digunakan oleh Muddapur (1972) untuk menurunkan distribusi posterior bersama.
Inferensi Bayesian untuk sistem antrian dirangkum secara lengkap oleh Rios Insua et al. (2012).

Manajer dan perencana biasanya kurang tertarik pada inferensi parameter, dan lebih tertarik pada ukuran performa seperti:

  • \(N(t)\): jumlah pelanggan dalam sistem pada waktu \(t\)
  • \(\bar{B}\): rata-rata jumlah pelayan yang sibuk
  • \(\rho\): utilisasi sumber daya
  • \(\bar{w}\): rata-rata waktu tunggu pelanggan

Jika \(\lambda < K\mu\), maka sistem antrian pada akhirnya akan mencapai keadaan keseimbangan dan distribusi dari ukuran performa menjadi tidak tergantung waktu.

Dalam kasus sistem \(\text{M}/\text{M}/K\), distribusi keseimbangan dari ukuran performa dapat diturunkan secara analitik, dan dapat ditemukan dalam buku teks teori antrian standar seperti Lipsky (2008) dan Thomopoulos (2012).

Sebagai contoh, probabilitas limit terdapatnya \(N\) pelanggan dalam sistem, \(P(N)\), adalah:

Probabilitas sistem kosong adalah:

\[ P(0) = \left[ \frac{(K\rho)^K}{K!(1 - \rho)} + 1 + \sum_{i = 1}^{K - 1} \frac{(K\rho)^i}{i!} \right]^{-1} \tag{1} \]

Probabilitas terdapat \(N\) pelanggan dalam sistem:

\[ P(N) = \begin{cases} P(0) \cdot \frac{(K\rho)^N}{N!}, & \text{jika } N \leq K \\ P(0) \cdot \frac{(K\rho)^N}{K! \cdot K^{N-K}}, & \text{jika tidak} \end{cases} \tag{2} \]

di mana \(\rho\), yaitu utilisasi sumber daya, didefinisikan sebagai:

\[ \rho = \frac{\lambda}{K\mu} \]

Untuk sistem \(\text{M}/\text{M}/K\), ini sama dengan jumlah harapan pelayan sibuk dibagi dengan jumlah total pelayan \(\frac{\mathbb{E}(B)}{K}\) (Cassandras dan Lafortune, 2009, hlm. 451). Jumlah harapan pelanggan dalam sistem menurut Bhat (2015) adalah:

\[ \mathbb{E}(N) = K\rho + \frac{\rho (K\rho)^K P(0)}{K!(1 - \rho)^2} \tag{3} \]

dan waktu tunggu harapan adalah:

\[ \mathbb{E}(w) = \frac{(K\rho)^K P(0)}{K!K\mu(1 - \rho)^2} \tag{4} \]

Jika parameter dari \(f_\delta\) dan \(f_s\) tidak pasti, maka kita harus menggunakan distribusi prediktif untuk memperkirakan ukuran performa. Distribusi prediktif dari ukuran performa menggunakan distribusi posterior Bayesian diturunkan oleh Armero (1994); Armero dan Bayarri (1999).

Jackson (1957) adalah salah satu yang pertama mempertimbangkan jaringan sistem antrian. Dalam jaringan Jackson terdapat himpunan sistem antrian sebanyak \(J\). Setelah pelanggan dilayani oleh sistem antrian ke-\(j\), mereka akan menuju sistem antrian lain dengan probabilitas tetap \(p_{j,k}\). Pelanggan akan meninggalkan sistem dengan probabilitas \(1 - \sum_{k=1}^{J} p_{j,k}\).

Contoh lain dari topologi jaringan antrian meliputi: - Tandem (Glynn dan Whitt, 1991) - Parallel (Hunt dan Foote, 1995) - Fork/Join (Kim dan Agrawala, 1989)

Dalam jaringan antrian tandem, pelanggan melewati serangkaian antrian secara berurutan sebelum keluar dari sistem. Contoh dunia nyata dari sistem ini termasuk terminal bandara, layanan internet, dan sistem manufaktur.

Dalam jaringan parallel, pelanggan dibagi ke dalam sistem antrian terpisah berdasarkan pasangan \((a, s)\).

Dalam jaringan fork/join, satu tugas (atau pelanggan) dibagi menjadi sejumlah sub-tugas yang harus diselesaikan oleh pelayan paralel yang berbeda. Perbedaan utama dari jaringan paralel biasa adalah bahwa tugas hanya dapat keluar dari sistem setelah semua sub-tugas mencapai titik join.

Sebagian besar model sistem antrian mengasumsikan bahwa proses antar-kedatangan dan pelayanan bersifat tidak berubah terhadap waktu (time-invariant). Namun dalam praktiknya, banyak sistem antrian di dunia nyata memiliki proses antar-kedatangan yang sangat tergantung waktu, contohnya:

  • Call center (Weinberg, Brown, dan Stroud 2007; Brown, Gans, Mandelbaum, Sakov, Shen, Zeltyn, dan Zhao 2005)
  • Landasan bandara (Koopman 1972)
  • Rumah sakit (Brahimi dan Worthington 1991)

Dalam kasus sistem \(\text{M}/\text{M}/1\), kita dapat menyesuaikan notasinya menjadi:

\[ \text{M}(t)/\text{M}(t)/1 \]

untuk merepresentasikan proses eksponensial di mana parameter \(\lambda(t)\) dan \(\mu(t)\) berubah terhadap waktu. Sistem antrian seperti ini disebut sebagai sistem antrian dinamis (dynamic queueing systems). Secara umum, solusi analitik tidak tersedia untuk sistem antrian dinamis (dynamic queueing systems) (Malone, 1995; Worthington, 2009).

Green, Kolesar, dan Svoronos (1991) menunjukkan bahwa menggunakan model sistem antrian stasioner untuk memodelkan sistem antrian dinamis akan menghasilkan kesalahan serius, bahkan ketika penyimpangan dari kondisi stasioner sangat kecil. Masalah ini menjadi semakin rumit ketika kita mempertimbangkan jaringan antrian (queueing networks).
Pemahaman tentang perilaku jangka panjang dan transien dari sistem antrian semacam itu hanya dapat dicapai melalui metode pendekatan (approximation methods) atau simulasi.

Pada bagian selanjutnya, kita akan menguraikan algoritma QDC (Queue Departure Computation), yaitu sebuah metode simulasi sistem antrian yang efisien secara komputasi.

3. Perhitungan Waktu Keluar Antrian (Queue Departure Computation)

3.1. Jumlah Pelayan Tetap (Fixed number of servers)

QDC (Queue Departure Computation) dapat dianggap sebagai ekstensi multiserver dari algoritma yang diperkenalkan oleh Lindley (1952).
Untuk sistem antrian dengan satu pelayan, waktu keluarnya pelanggan ke-\(i\) dirumuskan sebagai:

\[ d_i = \max(a_i, d_{i-1}) + s_i \]

karena pelanggan harus menunggu pelayan atau pelayan menunggu pelanggan.

Yang mengejutkan, algoritma ini (bukan makalahnya) tidak diperluas ke sistem multi-pelayan hingga Krivulin (1994).
Namun, untuk setiap pelanggan baru \(i\), algoritma harus mencari dalam vektor sepanjang \(i + 1\).
Akibatnya, algoritma ini tidak berskala baik, dengan kompleksitas komputasi sebesar \(\mathcal{O}(n^2)\), di mana \(n\) adalah jumlah pelanggan.

Kin dan Chan (2010) mengadaptasi algoritma asli dari Kiefer dan Wolfowitz (1955) menjadi algoritma dengan kompleksitas \(\mathcal{O}(nK)\) untuk antrian tandem multi-pelayan dengan pemblokiran, yaitu sistem antrian G/G/K/C di mana \(C\) adalah kapasitas maksimum pelanggan dalam sistem antrian.

QDC juga dapat dilihat sebagai solusi komputasi yang efisien untuk himpunan persamaan yang disajikan oleh Sutton dan Jordan (2011, hlm. 259) untuk sistem antrian FCFS.
Dalam sistem ini terdapat satu antrian yang dilayani oleh \(K\) pelayan tetap.
Pelanggan ke-\(i\) mengamati serangkaian waktu:

\[ b_i = \{b_{ik} \mid k \in 1{:}K\} \]

yang merepresentasikan waktu berikutnya setiap pelayan akan tersedia.
Pelanggan ke-\(i\) memilih pelayan paling awal tersedia:

\[ p_i = \arg\min(b_i) \]

Maka waktu keluarnya pelanggan ke-\(i\) adalah:

\[ d_i = \max(a_i, b_{p_i}) + s_i \]

karena pelayan menunggu pelanggan atau pelanggan menunggu pelayan.

Algoritma QDC untuk jumlah pelayan tetap (Algorithm 1) melakukan pra-urutkan (pre-sort) terhadap waktu kedatangan.
Alih-alih menetapkan sebuah \(b_i\) untuk setiap pelanggan \(i\) dan membentuk matriks \(b \in \mathbb{M}^{n \times K}\), QDC memperlakukan \(b\) sebagai vektor berdimensi \(K\) yang diperbarui terus-menerus, mewakili keadaan sistem.

Algoritma ini sederhana dan efisien secara komputasi.
Pada setiap iterasi, kita hanya perlu mencari nilai minimum dari vektor \(b\) berdimensi \(K\) pada baris kode ke-8.
Dalam bahasa Discrete Event Simulation (DES), vektor \(b\) mewakili state dari sistem dan \(a\) (waktu kedatangan) adalah daftar kejadian (event list) yang sudah ditentukan.

Ini berbeda dari pendekatan DES konvensional untuk pemodelan sistem antrian, di mana panjang antrian dianggap sebagai state, dan baik \(a\) maupun \(d\) dianggap sebagai event list—di mana kejadian \(a\) bersifat deterministik dan kejadian \(d\) diperbarui terus-menerus (kontingen).

Algoritma 1 dapat mensimulasikan sistem antrian dengan bentuk:

\[ G(t)/G(t)/K/\infty/n/FCFS \]

di mana \(K\) dan \(n\) dapat dibuat sebesar apapun.
Selain itu, distribusi antar-kedatangan dan pelayanan dapat berbentuk umum dan arbitrer, bahkan memiliki struktur ketergantungan (dependency structure).

Karena waktu kedatangan dan pelayanan diberikan oleh pengguna, bukan di-sampling langsung dalam algoritma, maka QDC memisahkan proses pengambilan sampel statistik dari proses simulasi antrian.
Dengan cara ini, pengguna bebas mensimulasikan sistem antrian dengan bentuk distribusi \(f_{\delta}, f_{s}\) yang sekompleks apapun, selama nilai \(K\) tetap.

Algoritma 1: QDC untuk \(K\) tetap

1:  function QDC(a ∈ ℝⁿ₊, s ∈ ℝⁿ₊, K ∈ ℕ)

2:      Urutkan (a, s) berdasarkan a (menaik)

3:      Buat vektor p ∈ ℕⁿ

4:      Buat vektor b ∈ ℝ₊^K

5:      Buat vektor d ∈ ℝⁿ₊

6:      Setiap elemen b_k ← 0 untuk semua k ∈ 1:K

7:      for i ∈ 1:n do

8:          pᵢ ← arg min(b)   # indeks pelayan paling cepat tersedia

9:          bₚᵢ ← max(aᵢ, bₚᵢ) + sᵢ

10:         dᵢ ← bₚᵢ

11:     end for

12:     Kembalikan (a, d, p) ke urutan asli input a

13:     return (d, p)

14: end function

3.2. Perubahan Jumlah Pelayan

Kasus Kondisional (Conditional Case)

Misalkan jumlah pelayan yang tersedia untuk digunakan oleh pelanggan berubah sepanjang hari.
Hal ini mencerminkan situasi nyata, seperti ketika lebih banyak pelayan dijadwalkan bertugas saat jam sibuk.
Kita nyatakan bahwa pada waktu \(t\) tertentu, pelanggan memiliki pilihan sebanyak \(K(t)\) pelayan yang aktif dari total \(K\).
Artinya, terdapat \(K(t)\) pelayan yang dijadwalkan aktif pada waktu \(t\). Kita mendefinisikan istilah tertutup (closed) sebagai kebalikan dari terbuka (open).

Kita representasikan jumlah pelayan terbuka sepanjang hari sebagai sebuah fungsi langkah (step function).
Waktu diasumsikan sebagai bilangan real positif, dan dibagi oleh \(L\) simpul (knot) \(x = (x_1, \cdots, x_L) \in \mathbb{R}^L_+\) ke dalam \(L + 1\) epoch:

\[(0, x_1], (x_1, x_2], \cdots, (x_L, \infty)\]

Jumlah pelayan terbuka di tiap epoch direpresentasikan oleh vektor berdimensi \(L + 1\):

\[ y = (y_1, \cdots, y_{L+1}) \in \mathbb{N}_0^{L+1} \]

Jika kita mengasumsikan bahwa tidak ada waktu pelayanan \(s_i\) yang melintasi lebih dari satu epoch, maka secara formal:

\[ \forall i, \quad s_i < \min(x_{l+1} - x_l \mid l \in 1{:}L) \tag{5} \]

maka kita hanya perlu mempertimbangkan perubahan status pada maksimal satu simpul (knot).
Fungsi langkah ini ditentukan oleh pengguna sebagai masukan (input) sebelum simulasi dilakukan, tidak dapat berubah selama simulasi berlangsung, sama seperti waktu kedatangan \(a\) dan waktu pelayanan \(s\).

Untuk menutup pelayan ke-\(k\), kita set nilai \(b_k = \infty\) agar tidak ada pelanggan yang dapat memilih pelayan tersebut.
Jika pelayan perlu dibuka kembali pada waktu \(t\), kita set nilai \(b_k = t\) agar pelayan tersebut dapat digunakan.
Karena \(x\) sekarang merepresentasikan perubahan pada vektor \(b\), maka simpul-simpul \(x\) merupakan bagian dari daftar kejadian (event list) bersama dengan waktu kedatangan \(a\).
Seluruh daftar kejadian ini bersifat ditentukan sebelumnya (pre-determined) dan tidak perlu diperbarui selama simulasi berlangsung.

Algoritma ini dapat mensimulasikan sistem antrian dengan bentuk:

\[ G(t)/G(t)/K(t)/\infty/n/FCFS \]

di mana \(K(t)\) adalah jumlah pelayan terbuka yang berubah terhadap waktu.

Seperti telah disebutkan sebelumnya, algoritma ini bergantung pada Kondisi (5), namun kondisi ini tidak terlalu membatasi jika kita mempertimbangkan sistem nyata yang hanya mengalami sedikit perubahan pada \(K\) sepanjang waktu.

Perlu dicatat bahwa hasil alokasi pelayan yang direkam dalam vektor:

\[ p = (p_1, \cdots, p_n) \]

mungkin tidak mencerminkan sistem sebenarnya, karena Algoritma 2 tidak memungkinkan pengguna untuk menentukan pelayan mana yang digunakan secara spesifik.

Algoritma 2: QDC untuk \(K(t)\) (Kasus Kondisional)

1:  function QDC_server_stepfun(a ∈ ℝⁿ₊, s ∈ ℝⁿ₊, x ∈ ℝ^L₊, y ∈ ℕ₀^{L+1})

2:      Urutkan (a, s) berdasarkan a (menaik)

3:      Tambahkan simpul terakhir: x_{L+1} ← ∞

4:        Tambahkan y_{L+2} ← 1

5:      K ← maksimum nilai dari vektor y

6:      Buat vektor b ∈ ℝ₊^K

7:      Setiap elemen b_k ← ∞ untuk semua k ∈ 1:K  # semua pelayan awalnya ditutup

8:      Setiap elemen b_k ← 0 untuk semua k ∈ 1:y₀  # buka y₀ pelayan pertama

9:      Buat vektor p ∈ ℕⁿ  # pelayan yang dipilih tiap pelanggan

10:     Buat vektor d ∈ ℝⁿ₊  # waktu keluar tiap pelanggan

11:     l ← 1  # indeks epoch

12:     p₁ ← 1

13:     for i ∈ 1:n do
14:
15:         # Penyesuaian jika terjadi perubahan epoch

16:         if ∀k ∈ 1:K [b_k ≥ x_{l+1}] OR a_i ≥ x_{l+1} then

17:             if y_{l+1} − y_l > 0 then

18:                 for k ∈ (y_l + 1 : y_{l+1}) do

19:                     b_k ← x_{l+1}  # buka pelayan di epoch baru

20:                 end for

21:             end if

22:             if y_{l+1} − y_l < 0 then

23:                 for k ∈ (y_{l+1} + 1 : y_l) do

24:                     b_k ← ∞  # tutup pelayan

25:                 end for

26:             end if

27:             l ← l + 1  # lanjut ke epoch berikutnya

28:         end if
29:
30:         # Pilih pelayan paling cepat tersedia

31:         p_i ← arg min(b)

32:         b_{p_i} ← max(a_i, b_{p_i}) + s_i

33:         d_i ← b_{p_i}
34:
35:         # Ulangi jika pada epoch saat ini tidak ada pelayan terbuka
36:         if y_l = 0 then

37:             i ← i − 1  # proses pelanggan di epoch selanjutnya

38:         end if
39:
40:     end for

41:     Kembalikan (a, d, p) ke urutan asli input a

42:     return (d, p)

43: end function

Kasus Tak Bersyarat (Unconditional Case)

Dalam pendekatan sebelumnya, hanya jumlah server yang terbuka atau tertutup dalam setiap epoch yang diketahui, tanpa menentukan server mana saja yang berada dalam kondisi tersebut. Jika keluaran seperti ini dibutuhkan, atau jika Kondisi 5 tidak terpenuhi, maka kita harus menggunakan algoritma yang lebih umum namun kurang efisien secara komputasi, yaitu algoritma tak bersyarat (unconditional algorithm), yang dijelaskan dalam Algoritma 4.

Jika Kondisi 5 tidak terpenuhi, atau jika kita ingin mengontrol secara tepat waktu kapan masing-masing server dibuka, maka kita perlu menggunakan algoritma yang kurang efisien ini.

Setiap server \(k\) memiliki pembagian sendiri dari \(L_k\) simpul waktu (knot locations), yang ditulis sebagai:

\[ x_k = (x_{k,1}, x_{k,2}, \ldots, x_{k,L_k}) \in \mathbb{R}_{+}^{L_k} \]

dan setiap simpul tersebut memiliki status terbuka atau tertutup yang dinyatakan dengan:

\[ y_k = (y_{k,1}, y_{k,2}, \ldots, y_{k,L_k+1}) \]

yaitu urutan nilai 0 dan 1 sepanjang \(L_k + 1\), yang menunjukkan apakah server dalam keadaan terbuka (1) atau tertutup (0) untuk setiap epoch terkait.

Algoritma 3: Fungsi next_fun

Misalkan:

  • \(y_k = (y_{k,1}, \dots, y_{k,L_k+1})\) adalah urutan bolak-balik antara 0 dan 1 sepanjang \(L_k\),
    yang menunjukkan apakah pelayan (server) dalam keadaan terbuka (1) atau tertutup (0)
    pada setiap epoch terkait.

  • Vektor \(c\) digunakan dengan cara yang sedikit berbeda dibandingkan pada Sutton dan Jordan (2011).
    Di sini, \(c\) merepresentasikan waktu berikutnya pelayan tersedia untuk pelanggan ke-\(i\),
    berdasarkan keadaan sistem saat ini (\(b\)).

  • Nilai \(c\) ini diperoleh dari fungsi bantu next_fun.

Algorithm 3: Fungsi next_fun

function next_fun(t, x ∈ ℝ^L₊, y)

Temukan l sehingga x_l < t ≤ x_{l+1}

if y_{l+1} == 0 then

  return x_{l+1}  # jika pelayan ditutup, kembali ke waktu buka berikutnya
else

  return t        # jika pelayan tetap terbuka, kembali waktu saat ini
    
end if

end function

Algoritma 4: QDC untuk \(K(t)\) (Kasus Tak Bersyarat)

Fungsi ini digunakan jika kita ingin mengatur server mana saja yang aktif atau tidak aktif secara eksplisit, tanpa mengandalkan kondisi global.
Berikut ini adalah pseudokode dan penjelasan algoritma:

Algoritma 4: QDC untuk K(t) - Tanpa Syarat

function QDC_server.list(a ∈ ℝⁿ₊, s ∈ ℝⁿ₊, 

                     x = (x₁, x₂, ..., x_K), 
                     
                     y = (y₁, y₂, ..., y_K))

Sort (a, s) berdasarkan a (naik)

# Tambahkan simpul tak hingga untuk akhir tiap server

∀k ∈ 1 : K  → xₖ,Lₖ₊₁ ← ∞

∀k ∈ 1 : K  → yₖ,Lₖ₊₂ ← 1

K ← panjang dari x (jumlah server)

Buat vektor c ∈ ℝ⁺ᴷ   # waktu server aktif berikutnya

Buat vektor b ∈ ℝ⁺ᴷ   # status server saat ini

Set bk ← 0 ∀k ∈ 1 : K

Buat vektor p ∈ ℕⁿ     # alokasi server per pelanggan

Buat vektor d ∈ ℝ⁺ⁿ    # waktu keluar pelanggan

for i ∈ 1 : n do

    for k ∈ 1 : K do
    
        cₖ ← next_fun(max(bₖ, aᵢ), xₖ, yₖ)
        
    end for

    pᵢ ← argmin(c)              # pilih server dengan waktu tercepat
    
    b_{pᵢ} ← c_{pᵢ} + sᵢ        # perbarui waktu keluar server tersebut
    
    dᵢ ← b_{pᵢ}                # simpan waktu keluar pelanggan
    
end for

Kembalikan urutan (a, d, p) ke urutan awal input a

return (d, p)

end function

Algoritma ini dapat digunakan untuk mensimulasikan sistem antrian dengan bentuk \(G(t)/G(t)/K(t)/\infty/n/FCFS\), di mana \(K(t)\) merepresentasikan jumlah server yang aktif yang dapat berubah seiring waktu. Selain itu, kita juga dapat menentukan server tertentu yang aktif pada waktu tertentu, bukan hanya jumlahnya saja, dan kita tidak terikat oleh Kondisi 5.

Sekali lagi perlu dicatat bahwa vektor \(b\) dapat dianggap sebagai representasi dari kondisi sistem saat ini (system state), dan daftar kejadian (event list) dibentuk oleh waktu kedatangan (\(a\)) dan simpul waktu (\(x\)).

Fungsi ini bisa dijalankan dengan fungsi queue_step() dalam paket queuecomputer di R, dengan memberikan objek server.list ke argumen servers.

3.3. Diskusi

Dengan algoritma-algoritma yang telah disajikan sejauh ini, kita dapat melakukan simulasi dari sekumpulan sistem antrian yang sangat umum yaitu:

\[ G(t)/G(t)/K(t)/\infty/n/FCFS \]

dengan cara yang efisien secara komputasi (computationally efficient).

Berbeda dengan algoritma dari Kin dan Chan (2010), dalam QDC vektor status \(b\) ditulisi ulang pada setiap iterasi.
Oleh karena itu, penggunaan memori untuk QDC berskala sebagai \(\mathcal{O}(n)\) dibandingkan dengan \(\mathcal{O}(nK)\) pada algoritma sebelumnya.

Jaringan antrian tandem (tandem queueing networks) dapat disimulasikan dengan menggunakan keluaran dari satu sistem antrian sebagai masukan bagi sistem antrian berikutnya.
Kami mendemonstrasikan pendekatan ini pada contoh simulasi bandara (Airport Simulation) di Bagian 8.2.

Sementara itu, jaringan antrian fork/join akan dibahas pada bagian selanjutnya, di mana kami menjelaskan rincian implementasi dari paket queuecomputer sehubungan dengan algoritma QDC.

4. Penggunaan Paket queuecomputer

Tujuan utama dari paket queuecomputer adalah untuk menghitung output dari sistem antrian secara deterministik, dengan memberikan waktu kedatangan dan waktu pelayanan dari semua pelanggan.

Fungsi yang paling penting adalah queue_step(). Fungsi ini memiliki tiga argumen utama:

  1. Vector waktu kedatangan pelanggan (arrivals)
  2. Vector waktu pelayanan masing-masing pelanggan (service)
  3. Jumlah server atau objek server tertentu yang tersedia (servers)

Contoh Penggunaan

Kita akan mensimulasikan sistem antrian dengan 100 pelanggan dan 2 server. Berikut adalah langkah-langkahnya:

# Memuat paket queuecomputer
library("queuecomputer")

# Membuat data waktu kedatangan (arrival) sebanyak 100 pelanggan
arrivals <- cumsum(rexp(100))  # waktu antar kedatangan eksponensial
head(arrivals)
## [1] 1.939816 3.329269 3.410338 3.551769 5.744942 6.833120
#Contoh Dasar: Simulasi Queue Sederhana
service <-rexp(100)
departures <- queue_step(arrivals, service = service, servers = 2)
departures
## $departures
##   [1]   4.234026   3.803542   4.685955   4.709399   6.046283  10.735276
##   [7]   8.937169   9.698598   9.758510  12.723962  17.206939  16.665389
##  [13]  17.428498  19.587427  18.814935  20.855473  21.359282  21.244272
##  [19]  21.321117  21.879114  21.489703  22.047452  24.018391  22.166933
##  [25]  22.855299  25.871338  24.400491  28.760298  27.331333  27.633126
##  [31]  28.415590  28.435419  28.606895  29.315124  29.991385  30.174557
##  [37]  32.682886  31.770106  33.061685  33.353945  33.490430  37.827825
##  [43]  36.262689  38.485274  37.970623  38.820077  40.061914  40.990822
##  [49]  43.450010  41.346024  41.702979  42.468652  43.107421  44.090491
##  [55]  45.750312  46.983952  48.552913  50.570923  51.167824  51.124480
##  [61]  51.848192  52.520343  57.324796  56.536881  60.871165  59.847537
##  [67]  60.526069  61.652309  69.205572  71.046431  69.339193  69.371069
##  [73]  70.389037  72.612367  74.385872  76.867629  78.632418  80.035531
##  [79]  79.996758  80.687793  83.973044  83.654381  84.900115  85.908104
##  [85]  86.537048  86.705547  87.547104  90.076149  90.090749  92.054227
##  [91]  90.451409  94.838885  96.944200 100.997834 101.467455 102.049077
##  [97] 101.851202 103.010745 102.259315 103.398549
## 
## $server
##   [1] 1 2 2 1 2 1 2 2 2 2 1 2 2 1 2 2 1 2 2 2 1 1 2 1 1 1 2 2 1 1 1 1 1 1 2 1 2
##  [38] 1 1 2 1 2 1 1 2 2 1 2 1 2 2 2 2 2 1 2 1 2 1 2 2 1 2 1 1 2 2 2 1 2 1 1 1 1
##  [75] 2 1 2 1 2 2 1 2 2 1 2 1 2 1 2 1 2 2 1 2 1 2 1 1 2 2
## 
## $departures_df
## # A tibble: 100 × 6
##    arrivals service departures  waiting system_time server
##       <dbl>   <dbl>      <dbl>    <dbl>       <dbl>  <int>
##  1     1.94  2.29         4.23 0              2.29       1
##  2     3.33  0.474        3.80 1.67e-16       0.474      2
##  3     3.41  0.882        4.69 3.93e- 1       1.28       2
##  4     3.55  0.475        4.71 6.82e- 1       1.16       1
##  5     5.74  0.301        6.05 0              0.301      2
##  6     6.83  3.90        10.7  0              3.90       1
##  7     7.02  1.92         8.94 0              1.92       2
##  8     7.34  0.761        9.70 1.60e+ 0       2.36       2
##  9     7.76  0.0599       9.76 1.94e+ 0       2.00       2
## 10    12.3   0.449       12.7  0              0.449      2
## # ℹ 90 more rows
## 
## $queuelength_df
##          times queuelength
## 1     0.000000           0
## 2     1.939816           1
## 3     1.939816           0
## 4     3.329269           1
## 5     3.329269           0
## 6     3.410338           1
## 7     3.551769           2
## 8     3.803542           1
## 9     4.234026           0
## 10    5.744942           1
## 11    5.744942           0
## 12    6.833120           1
## 13    6.833120           0
## 14    7.019520           1
## 15    7.019520           0
## 16    7.337512           1
## 17    7.757812           2
## 18    8.937169           1
## 19    9.698598           0
## 20   12.275006           1
## 21   12.275006           0
## 22   15.286441           1
## 23   15.286441           0
## 24   15.790852           1
## 25   15.790852           0
## 26   16.279805           1
## 27   16.446281           2
## 28   16.665389           1
## 29   16.845372           2
## 30   17.206939           1
## 31   17.428498           0
## 32   17.509171           1
## 33   17.734703           2
## 34   18.025341           3
## 35   18.213452           4
## 36   18.611648           5
## 37   18.685197           6
## 38   18.814935           5
## 39   19.263353           6
## 40   19.513265           7
## 41   19.587427           6
## 42   20.855473           5
## 43   21.244272           4
## 44   21.321117           3
## 45   21.359282           2
## 46   21.489703           1
## 47   21.543057           2
## 48   21.571897           3
## 49   21.879114           2
## 50   22.047452           1
## 51   22.166933           0
## 52   23.448385           1
## 53   23.448385           0
## 54   23.692617           1
## 55   24.018391           0
## 56   25.190822           1
## 57   25.190822           0
## 58   25.340545           1
## 59   25.536022           2
## 60   25.871338           1
## 61   26.065520           2
## 62   26.831113           3
## 63   27.061170           4
## 64   27.331333           3
## 65   27.633126           2
## 66   28.415590           1
## 67   28.435419           0
## 68   28.807416           1
## 69   28.807416           0
## 70   29.249020           1
## 71   29.249020           0
## 72   29.956167           1
## 73   29.956167           0
## 74   30.190540           1
## 75   30.190540           0
## 76   30.370870           1
## 77   30.370870           0
## 78   32.865171           1
## 79   32.865171           0
## 80   33.019653           1
## 81   33.019653           0
## 82   33.294503           1
## 83   33.294503           0
## 84   35.958092           1
## 85   35.958092           0
## 86   36.190063           1
## 87   36.190063           0
## 88   37.250795           1
## 89   37.250795           0
## 90   37.751649           1
## 91   37.827825           0
## 92   38.647400           1
## 93   38.647400           0
## 94   39.583848           1
## 95   39.583848           0
## 96   39.795739           1
## 97   39.795739           0
## 98   40.525734           1
## 99   40.525734           0
## 100  40.577817           1
## 101  40.990822           0
## 102  41.336541           1
## 103  41.346024           0
## 104  41.972494           1
## 105  41.972494           0
## 106  42.296708           1
## 107  42.468652           0
## 108  42.974228           1
## 109  43.107421           0
## 110  44.774941           1
## 111  44.774941           0
## 112  46.520197           1
## 113  46.520197           0
## 114  47.731222           1
## 115  47.731222           0
## 116  49.283231           1
## 117  49.283231           0
## 118  49.923808           1
## 119  49.923808           0
## 120  50.481586           1
## 121  50.570923           0
## 122  51.224949           1
## 123  51.224949           0
## 124  52.238063           1
## 125  52.238063           0
## 126  54.194700           1
## 127  54.194700           0
## 128  55.091958           1
## 129  55.091958           0
## 130  59.365842           1
## 131  59.365842           0
## 132  59.555924           1
## 133  59.555924           0
## 134  59.567034           1
## 135  59.847537           0
## 136  60.890439           1
## 137  60.890439           0
## 138  66.451773           1
## 139  66.451773           0
## 140  66.704726           1
## 141  66.704726           0
## 142  67.005259           1
## 143  68.477497           2
## 144  69.205572           1
## 145  69.339193           0
## 146  70.306576           1
## 147  70.306576           0
## 148  72.510249           1
## 149  72.510249           0
## 150  72.927377           1
## 151  72.927377           0
## 152  75.681242           1
## 153  75.681242           0
## 154  77.130847           1
## 155  77.130847           0
## 156  79.927714           1
## 157  79.927714           0
## 158  79.944131           1
## 159  79.944131           0
## 160  80.666220           1
## 161  80.666220           0
## 162  80.873426           1
## 163  80.873426           0
## 164  83.515027           1
## 165  83.515027           0
## 166  84.609394           1
## 167  84.609394           0
## 168  85.800510           1
## 169  85.800510           0
## 170  85.843323           1
## 171  85.843323           0
## 172  86.089132           1
## 173  86.089132           0
## 174  86.799425           1
## 175  86.799425           0
## 176  89.681339           1
## 177  89.681339           0
## 178  89.848693           1
## 179  89.848693           0
## 180  89.878493           1
## 181  89.906807           2
## 182  90.076149           1
## 183  90.090749           0
## 184  94.808806           1
## 185  94.808806           0
## 186  95.977347           1
## 187  95.977347           0
## 188  98.561529           1
## 189  98.561529           0
## 190  99.548938           1
## 191  99.548938           0
## 192 100.122008           1
## 193 100.387175           2
## 194 100.964702           3
## 195 100.997834           2
## 196 101.165768           3
## 197 101.467455           2
## 198 101.851202           1
## 199 102.049077           0
## 200 103.027239           1
## 201 103.027239           0
## 
## $systemlength_df
##          times queuelength
## 1     0.000000           0
## 2     1.939816           1
## 3     3.329269           2
## 4     3.410338           3
## 5     3.551769           4
## 6     3.803542           3
## 7     4.234026           2
## 8     4.685955           1
## 9     4.709399           0
## 10    5.744942           1
## 11    6.046283           0
## 12    6.833120           1
## 13    7.019520           2
## 14    7.337512           3
## 15    7.757812           4
## 16    8.937169           3
## 17    9.698598           2
## 18    9.758510           1
## 19   10.735276           0
## 20   12.275006           1
## 21   12.723962           0
## 22   15.286441           1
## 23   15.790852           2
## 24   16.279805           3
## 25   16.446281           4
## 26   16.665389           3
## 27   16.845372           4
## 28   17.206939           3
## 29   17.428498           2
## 30   17.509171           3
## 31   17.734703           4
## 32   18.025341           5
## 33   18.213452           6
## 34   18.611648           7
## 35   18.685197           8
## 36   18.814935           7
## 37   19.263353           8
## 38   19.513265           9
## 39   19.587427           8
## 40   20.855473           7
## 41   21.244272           6
## 42   21.321117           5
## 43   21.359282           4
## 44   21.489703           3
## 45   21.543057           4
## 46   21.571897           5
## 47   21.879114           4
## 48   22.047452           3
## 49   22.166933           2
## 50   22.855299           1
## 51   23.448385           2
## 52   23.692617           3
## 53   24.018391           2
## 54   24.400491           1
## 55   25.190822           2
## 56   25.340545           3
## 57   25.536022           4
## 58   25.871338           3
## 59   26.065520           4
## 60   26.831113           5
## 61   27.061170           6
## 62   27.331333           5
## 63   27.633126           4
## 64   28.415590           3
## 65   28.435419           2
## 66   28.606895           1
## 67   28.760298           0
## 68   28.807416           1
## 69   29.249020           2
## 70   29.315124           1
## 71   29.956167           2
## 72   29.991385           1
## 73   30.174557           0
## 74   30.190540           1
## 75   30.370870           2
## 76   31.770106           1
## 77   32.682886           0
## 78   32.865171           1
## 79   33.019653           2
## 80   33.061685           1
## 81   33.294503           2
## 82   33.353945           1
## 83   33.490430           0
## 84   35.958092           1
## 85   36.190063           2
## 86   36.262689           1
## 87   37.250795           2
## 88   37.751649           3
## 89   37.827825           2
## 90   37.970623           1
## 91   38.485274           0
## 92   38.647400           1
## 93   38.820077           0
## 94   39.583848           1
## 95   39.795739           2
## 96   40.061914           1
## 97   40.525734           2
## 98   40.577817           3
## 99   40.990822           2
## 100  41.336541           3
## 101  41.346024           2
## 102  41.702979           1
## 103  41.972494           2
## 104  42.296708           3
## 105  42.468652           2
## 106  42.974228           3
## 107  43.107421           2
## 108  43.450010           1
## 109  44.090491           0
## 110  44.774941           1
## 111  45.750312           0
## 112  46.520197           1
## 113  46.983952           0
## 114  47.731222           1
## 115  48.552913           0
## 116  49.283231           1
## 117  49.923808           2
## 118  50.481586           3
## 119  50.570923           2
## 120  51.124480           1
## 121  51.167824           0
## 122  51.224949           1
## 123  51.848192           0
## 124  52.238063           1
## 125  52.520343           0
## 126  54.194700           1
## 127  55.091958           2
## 128  56.536881           1
## 129  57.324796           0
## 130  59.365842           1
## 131  59.555924           2
## 132  59.567034           3
## 133  59.847537           2
## 134  60.526069           1
## 135  60.871165           0
## 136  60.890439           1
## 137  61.652309           0
## 138  66.451773           1
## 139  66.704726           2
## 140  67.005259           3
## 141  68.477497           4
## 142  69.205572           3
## 143  69.339193           2
## 144  69.371069           1
## 145  70.306576           2
## 146  70.389037           1
## 147  71.046431           0
## 148  72.510249           1
## 149  72.612367           0
## 150  72.927377           1
## 151  74.385872           0
## 152  75.681242           1
## 153  76.867629           0
## 154  77.130847           1
## 155  78.632418           0
## 156  79.927714           1
## 157  79.944131           2
## 158  79.996758           1
## 159  80.035531           0
## 160  80.666220           1
## 161  80.687793           0
## 162  80.873426           1
## 163  83.515027           2
## 164  83.654381           1
## 165  83.973044           0
## 166  84.609394           1
## 167  84.900115           0
## 168  85.800510           1
## 169  85.843323           2
## 170  85.908104           1
## 171  86.089132           2
## 172  86.537048           1
## 173  86.705547           0
## 174  86.799425           1
## 175  87.547104           0
## 176  89.681339           1
## 177  89.848693           2
## 178  89.878493           3
## 179  89.906807           4
## 180  90.076149           3
## 181  90.090749           2
## 182  90.451409           1
## 183  92.054227           0
## 184  94.808806           1
## 185  94.838885           0
## 186  95.977347           1
## 187  96.944200           0
## 188  98.561529           1
## 189  99.548938           2
## 190 100.122008           3
## 191 100.387175           4
## 192 100.964702           5
## 193 100.997834           4
## 194 101.165768           5
## 195 101.467455           4
## 196 101.851202           3
## 197 102.049077           2
## 198 102.259315           1
## 199 103.010745           0
## 200 103.027239           1
## 201 103.398549           0
## 
## $servers_input
## [1] 2
## 
## $state
## [1] 103.0107 103.3985
## 
## attr(,"class")
## [1] "queue_list" "list"

Hasil Output dari queue_step()

Fungsi queue_step() menghasilkan objek bertipe queue_list, yaitu objek yang berisi hasil simulasi sistem antrian seperti waktu kedatangan, pelayanan, waktu tunggu, waktu keluar dari sistem, dan alokasi server.

Untuk memudahkan analisis hasil, penulis paket juga membuat sebuah fungsi summary() khusus yang dapat digunakan pada objek hasil queue_step. Fungsi ini akan menampilkan rangkuman statistik dari proses antrian yang disimulasikan.

Contoh penggunaan:

summary(departures)
## Total customers:
##  100
## Missed customers:
##  0
## Mean waiting time:
##  0.42
## Mean response time:
##  1.38
## Utilization factor:
##  0.466483447643133
## Mean queue length:
##  0.407
## Mean number of customers in system:
##  1.34

Missed Customers:
1. Jika pada akhir vektor \(y\), nilai nya nol, artinya server dalam keadaan tertutup, sehingga ada pelanggan yang tidak pernah mendapatkan layanan. Hasil ini akan dilaporkan sebagai “Missed customers”.

  1. Performance Measures:
    • Mean Waiting Time (\(\bar{w}\)): Rata-rata waktu yang dihabiskan pelanggan dalam antrean sebelum dilayani.
    • Mean Response Time (\(\bar{r}\)): Rata-rata waktu total yang dibutuhkan dari saat pelanggan datang sampai selesai dilayani, yaitu selisih antara waktu pelayanan selesai (\(d\)) dan waktu kedatangan (\(a\)).
    • Utilization Factor (\(\overline{B}/K\)): Rasio antara rata-rata jumlah server yang aktif (sibuk) dengan total server, yang diperhitungkan secara dinamis ketika jumlah server yang tersedia berubah seiring waktu (\(K(t)\)).
    • Mean Queue Length dan Mean Number of Customers in System: Ukuran lain yang menunjukkan seberapa banyak pelanggan yang berada di antrian dan dalam sistem secara keseluruhan, secara rata-rata.
  2. Implementasi:
    Penulis selanjutnya menjelaskan detail bagaimana paket mengimplementasikan simulasi antrian beserta perhitungan ukuran-ukuran performa tersebut, agar pengguna dapat mengaplikasikan dan memahami algoritma tersebut dengan lebih baik.

5. Implementasi

Perulangan (loop) utama dalam Algoritma 1 dan 2 ditulis menggunakan bahasa C++ dengan bantuan pustaka Armadillo untuk aljabar linier (Sanderson dan Curtin, 2016). Perulangan C++ ini kemudian dipanggil dari R menggunakan paket Rcpp (Eddelbuettel dkk., 2011) dan RcppArmadillo (Eddelbuettel dan Sanderson, 2014).

Fungsi utama dalam paket ini adalah queue_step, yang bertindak sebagai wrapper untuk fungsi queue. Fungsi queue ini merupakan metode S3 di R yang akan memilih dan menjalankan algoritma sesuai dengan kelas (class) dari objek yang diberikan pada argumen servers:

  • Jika server bertipe numeric, maka dijalankan Algoritma 1 (jumlah server tetap).
  • Jika server bertipe server.stepfun, maka dijalankan Algoritma 2 (jumlah server berubah dalam bentuk fungsi langkah).
  • Jika server bertipe server.list, maka dijalankan Algoritma 4 (pengaturan server yang lebih kompleks dan fleksibel).

Fungsi queue akan menghitung waktu keluar (departure time) d dan alokasi server p. Sementara itu, fungsi queue_step menambahkan beberapa output tambahan seperti:

  • Waktu tunggu (waiting time): waktu antara kedatangan dan saat mulai dilayani.
  • Waktu dalam sistem (system time): waktu antara kedatangan dan kepergian.
  • Panjang antrian dan statistik performa lainnya.

Semua informasi ini digunakan dalam fungsi-fungsi summary dan plot untuk menganalisis kinerja sistem antrian yang disimulasikan.

Simulasi Jaringan Fork/Join

Untuk mensimulasikan jaringan antrian bertipe fork/join, paket queuecomputer menyediakan fungsi wait_step. Fungsi ini adalah pembungkus (wrapper) dari fungsi dasar pmax.int, yang digunakan untuk mengambil nilai maksimum dari beberapa waktu keberangkatan subpekerjaan (subtasks). Artinya, sebuah tugas (job) dianggap selesai ketika seluruh subtugas-nya telah selesai.

Pemisahan antara Sampling dan Perhitungan

Berbeda dengan paket simmer dan simpy yang meminta pengguna memasukkan parameter distribusi (seperti laju kedatangan dan layanan), dalam queuecomputer, pengguna langsung memasukkan waktu kedatangan dan waktu layanan yang sudah disampling sebelumnya.

Keuntungan pendekatan ini adalah:

  • Bisa digunakan untuk distribusi yang sangat kompleks, termasuk yang saling bergantung.
  • Hasil simulasi dapat direplikasi secara tepat karena tidak bergantung pada proses pengacakan internal.
  • Pendekatan ini sangat cocok digunakan dalam algoritma Approximate Bayesian Computation (ABC), karena simulasi dapat dilakukan secara deterministik berdasarkan input dari posterior sampling.

Dengan demikian, queuecomputer memisahkan antara proses sampling statistik dan perhitungan sistem antrian, yang memberi fleksibilitas dan efisiensi tinggi.

Berikut adalah terjemahan isi Bab 6: Validation dari buku “Computationally Efficient Simulation of Queues: The R Package queuecomputer”:


6. Validasi

6.1 Perbandingan dengan simmer

Untuk menunjukkan validitas algoritma QDC (Queue Departure Computation), penulis melakukan simulasi sistem antrian M/M/2/∞/1000/FCFS. Jika QDC valid untuk sistem antrian jenis ini, maka diasumsikan valid pula untuk sistem G(t)/G(t)/K/∞/n/FCFS, karena data input berupa pasangan \((a, s)\) (waktu kedatangan dan layanan) bisa saja berasal dari distribusi eksponensial meskipun peluang pengamatannya kecil.

Langkah-langkah validasi:

  1. Generate waktu kedatangan dan waktu layanan

    • Menggunakan distribusi eksponensial untuk \(\lambda = 1\) (kedatangan) dan \(\mu = 0{,}9\) (layanan).
    • Sebanyak 10.000 pelanggan disimulasikan.
set.seed(1)
n_customers <- 10^4
lambda_a <- 1/1
lambda_s <- 1/0.9
interarrivals <- rexp(n_customers, lambda_a)
arrivals <- cumsum(interarrivals)
service <- rexp(n_customers, lambda_s)
  1. Jalankan kedua paket:

    • queuecomputer langsung menerima input waktu kedatangan dan layanan.
    • simmer perlu dimodifikasi agar bisa menerima input tersebut (karena default-nya menerima parameter distribusi, bukan nilai acak mentah).
    • Hasil simulasi dari ketiganya dibandingkan.
## Menggunakan queuecomputer
library(queuecomputer)
queuecomputer_output <- queue_step(arrivals = arrivals, service = service, servers = 2)
head(sort(depart(queuecomputer_output)))
## [1] 1.340151 2.288112 2.639976 2.796572 3.249794 5.714967
## Menggunakan Simmmer
library(simmer)

simmer_step <- function(arrivals, service, servers = 1) {
  n <- length(arrivals)
  env <- simmer("DES Simulation")
  
  # Gunakan indeks global untuk mengakses service[i]
  idx <- 0
  
  # trajectory menetapkan waktu layanan berdasarkan urutan pelanggan
  traj <- trajectory("customer path") %>%
    set_attribute("service_time", function() {
      idx <<- idx + 1
      service[idx]
    }) %>%
    seize("server", 1) %>%
    timeout_from_attribute("service_time") %>%
    release("server", 1)
  
  # Tambah server
  env %>% add_resource("server", capacity = servers)
  
  # Tambahkan seluruh arrival
  env %>% add_generator(
    name_prefix = "cust",
    trajectory = traj,
    distribution = at(arrivals),
    mon = 2
  )
    env %>% run()
  return(get_mon_arrivals(env)$end_time)
}
simmer_output <- simmer_step(arrivals = arrivals, service = service, servers = 2)
head(simmer_output)
## [1] 1.340151 2.288112 2.639976 2.796572 3.249794 5.714967
  1. Hasil:

    • Semua hasil waktu keberangkatan dari ketiga paket identik hingga 5 digit signifikan.
    • Ini menunjukkan bahwa queuecomputer memberikan hasil yang setara secara fungsional dengan simulasi berbasis Discrete Event Simulation (DES) seperti simmer dan simpy.

6.2 Replikasi Hasil Teoretis untuk M/M/3

Simulasi juga dilakukan untuk sistem M/M/3/∞/5.000.000/FCFS menggunakan queuecomputer, dengan tujuan membandingkan metrik performa hasil simulasi dengan rumus analitik teori antrian:

  • Parameter:

    • \(\lambda = 2\)
    • \(\mu = 1\)
    • Jadi, \(\rho = \frac{\lambda}{K\mu} = \frac{2}{3} \approx 0{,}666\)
  • Hasil teoretis:

    • Waktu tunggu rata-rata: \(E(w) \approx 0{,}444\)
    • Jumlah pelanggan dalam sistem: \(E(N) \approx 2{,}889\)
    • Probabilitas jumlah pelanggan \(P(N)\) dihitung hingga \(N = 20\)
  • Hasil simulasi:

set.seed(1)
n_customers <- 5e6
lambda <- 2
mu <- 1
interarrivals <- rexp(n_customers, lambda)
arrivals <- cumsum(interarrivals)
service <- rexp(n_customers, mu)
K = 3

MM3 <- queue_step(arrivals = arrivals, service = service, servers = K)
summary(MM3)
## Total customers:
##  5000000
## Missed customers:
##  0
## Mean waiting time:
##  0.445
## Mean response time:
##  1.44
## Utilization factor:
##  0.666140156160826
## Mean queue length:
##  0.889
## Mean number of customers in system:
##  2.89

7. Tolok Ukur (Benchmark)

7.1 Metode

Untuk mengukur efisiensi komputasi dari berbagai paket simulasi antrian, penulis melakukan eksperimen sebagai berikut:

  • Sistem antrian yang disimulasikan: M/M/2/∞/n/FCFS (dengan dua server dan kapasitas tak terbatas).

  • Parameter yang digunakan:

    • Laju kedatangan: \(\lambda = 1\)
    • Laju layanan: \(\mu = \frac{1}{0{,}9} \approx 1{,}11\)
  • Tujuan: menghitung waktu keberangkatan pelanggan dengan jumlah pelanggan \(n\) yang bervariasi:

    • \(n = 10^2\), \(10^3\), \(10^5\), \(10^6\)
    • Untuk queuecomputer bahkan dicoba sampai \(n = 10^7\)
  • Setiap percobaan diulang 100 kali untuk mendapatkan waktu komputasi rata-rata.

  • Alat ukur waktu:

    • Fungsi microbenchmark dari paket R microbenchmark digunakan untuk queuecomputer dan simmer.
  • Lingkungan uji:

    • CPU: Intel Core i7-6700 @ 3.40GHz

    • OS: Debian GNU/Linux

    • Versi perangkat lunak:

      • R: 3.3.3
      • Python: 3.4.2
      • simmer: 3.6.1
      • simpy: 3.6.1
      • queuecomputer: 0.8.1

7.2 Hasil dan Diskusi

Hasil benchmark menunjukkan bahwa:

  • queuecomputer jauh lebih cepat dibandingkan dua paket lainnya.

  • Keuntungan kecepatan:

    • Dibandingkan simpy:

      • Kecepatan meningkat 50x (untuk 100 pelanggan) hingga 600x (untuk 1 juta pelanggan).
    • Dibandingkan simmer:

      • Kecepatan meningkat 170x (untuk 100 pelanggan) hingga 3100x (untuk 1 juta pelanggan).
  • Bahkan untuk 10 juta pelanggan, queuecomputer hanya membutuhkan kurang dari 1 detik untuk menyelesaikan simulasi.

  • Efisiensi tinggi ini didapatkan karena:

    • QDC (Queue Departure Computation) tidak menggunakan pemodelan event dinamis seperti dalam DES (Discrete Event Simulation) konvensional.
    • QDC hanya melakukan perhitungan deterministik atas input yang sudah disediakan (kedatangan dan layanan).
    • Ini menjadikannya sangat ringan dan cepat secara komputasi.
  • Grafik (Gambar 2) dalam buku menunjukkan waktu eksekusi dalam milidetik terhadap jumlah pelanggan pada skala log. Kurva queuecomputer secara konsisten berada jauh di bawah simmer dan simpy.

Kesimpulan

QDC dan implementasinya dalam queuecomputer merupakan cara yang sangat efisien secara komputasi untuk mensimulasikan sistem antrian tipe G(t)/G(t)/K/∞/n/FCFS dibandingkan metode simulasi DES konvensional yang digunakan di simpy dan simmer.

Bab 8: Contoh

Bab ini memperlihatkan beragam contoh simulasi sistem antrian menggunakan paket queuecomputer di R, mulai dari simulasi dasar, validasi model M/M/K, hingga aplikasi pada skenario bandara dan visualisasi hasilnya.

8.1 Studi casus Call center (Simulasi Antrian Dasar)

library(queuecomputer)
library(randomNames)
library(ggplot2)
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:simmer':
## 
##     select
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union

Pertama, kita memuat pustaka yang diperlukan: queuecomputer untuk simulasi antrian, randomNames untuk menghasilkan nama acak, ggplot2 untuk visualisasi, dan dplyr untuk manipulasi data.

arrivals <- cumsum(rexp(100))
head(arrivals)
## [1] 0.03191802 1.56707421 1.63300775 2.03311017 2.25897130 3.40425011

Waktu kedatangan pelanggan dihasilkan dari distribusi eksponensial, dan dikonversi menjadi waktu kedatangan kumulatif.

service <-rexp(100)
departures <- queue_step(arrivals, service = service, servers = 2)
head(departures)
## $departures
##   [1]  7.020874  2.874659  4.994353  5.046308  5.821050  8.491635  8.001266
##   [8]  8.198585  9.881190 12.793183 11.506491 12.739232 16.346705 17.820301
##  [15] 18.896116 19.881708 21.169453 25.923729 25.616642 26.035712 26.798894
##  [22] 26.225767 28.063023 27.974980 31.326364 29.158032 29.797688 30.449111
##  [29] 31.198705 31.935463 31.399457 31.807203 33.594346 34.743897 36.495513
##  [36] 36.627119 38.667802 38.766714 40.051650 40.142113 41.390960 41.628946
##  [43] 41.636018 41.994260 45.977332 48.337258 48.071360 49.313280 48.825331
##  [50] 49.051880 49.098984 50.607190 51.076834 53.563876 51.374360 54.479363
##  [57] 54.737201 55.405674 56.328476 58.052968 56.479337 59.791775 58.588751
##  [64] 59.262005 59.749795 60.760553 66.109363 66.109778 66.633358 68.903158
##  [71] 70.299787 69.060521 71.736641 71.222161 71.591935 72.182959 72.249669
##  [78] 76.230362 74.708306 76.612613 81.997902 81.781715 81.828348 82.369901
##  [85] 84.582392 85.205845 86.562365 86.451264 88.681585 91.058305 91.814324
##  [92] 91.746218 91.865389 92.487097 95.307024 93.072876 96.648826 96.369517
##  [99] 96.771675 98.199363
## 
## $server
##   [1] 1 2 2 2 2 2 1 1 1 2 1 1 1 2 1 2 1 2 1 1 2 1 1 2 2 1 1 1 1 1 2 2 2 1 2 1 2
##  [38] 1 2 1 2 1 2 1 2 1 2 2 1 1 1 1 2 1 2 2 1 2 1 2 1 1 2 2 2 2 1 2 1 2 1 2 2 1
##  [75] 1 1 2 1 2 2 1 2 2 2 1 2 1 2 2 1 2 1 1 2 1 2 2 1 1 2
## 
## $departures_df
## # A tibble: 100 × 6
##    arrivals service departures  waiting system_time server
##       <dbl>   <dbl>      <dbl>    <dbl>       <dbl>  <int>
##  1   0.0319  6.99         7.02 0              6.99       1
##  2   1.57    1.31         2.87 0              1.31       2
##  3   1.63    2.12         4.99 1.24e+ 0       3.36       2
##  4   2.03    0.0520       5.05 2.96e+ 0       3.01       2
##  5   2.26    0.775        5.82 2.79e+ 0       3.56       2
##  6   3.40    2.67         8.49 2.42e+ 0       5.09       2
##  7   6.12    0.980        8.00 9.05e- 1       1.89       1
##  8   6.75    0.197        8.20 1.25e+ 0       1.45       1
##  9   9.30    0.580        9.88 0              0.580      1
## 10  10.2     2.59        12.8  4.44e-16       2.59       2
## # ℹ 90 more rows
## 
## $queuelength_df
##           times queuelength
## 1    0.00000000           0
## 2    0.03191802           1
## 3    0.03191802           0
## 4    1.56707421           1
## 5    1.56707421           0
## 6    1.63300775           1
## 7    2.03311017           2
## 8    2.25897130           3
## 9    2.87465898           2
## 10   3.40425011           3
## 11   4.99435298           2
## 12   5.04630759           1
## 13   5.82104977           0
## 14   6.11599085           1
## 15   6.74926606           2
## 16   7.02087397           1
## 17   8.00126648           0
## 18   9.30164777           1
## 19   9.30164777           0
## 20  10.20339610           1
## 21  10.20339610           0
## 22  10.51514738           1
## 23  10.51514738           0
## 24  11.92875114           1
## 25  11.92875114           0
## 26  16.26120012           1
## 27  16.26120012           0
## 28  16.49568059           1
## 29  16.49568059           0
## 30  18.60862166           1
## 31  18.60862166           0
## 32  19.51715468           1
## 33  19.51715468           0
## 34  20.95733092           1
## 35  20.95733092           0
## 36  21.17445657           1
## 37  21.17445657           0
## 38  21.31161680           1
## 39  21.31161680           0
## 40  23.25486967           1
## 41  23.84703013           2
## 42  25.61664225           1
## 43  25.71095748           2
## 44  25.92372947           1
## 45  26.03158955           2
## 46  26.03571188           1
## 47  26.22576731           0
## 48  26.92867876           1
## 49  26.92867876           0
## 50  27.18630888           1
## 51  27.97342778           2
## 52  27.97498019           1
## 53  28.06302313           0
## 54  28.57387587           1
## 55  28.67073020           2
## 56  29.15803176           1
## 57  29.56657528           2
## 58  29.72866244           3
## 59  29.79768793           2
## 60  30.34845110           3
## 61  30.39509502           4
## 62  30.44911106           3
## 63  31.19870549           2
## 64  31.32636412           1
## 65  31.39945725           0
## 66  33.35901534           1
## 67  33.35901534           0
## 68  33.85187805           1
## 69  33.85187805           0
## 70  35.92813719           1
## 71  35.92813719           0
## 72  36.59218135           1
## 73  36.59218135           0
## 74  37.17496841           1
## 75  37.17496841           0
## 76  38.46633771           1
## 77  38.46633771           0
## 78  39.35264010           1
## 79  39.35264010           0
## 80  39.44679710           1
## 81  39.44679710           0
## 82  39.76660212           1
## 83  40.05164985           0
## 84  40.54621139           1
## 85  40.54621139           0
## 86  41.06844940           1
## 87  41.39096018           0
## 88  41.83742713           1
## 89  41.83742713           0
## 90  44.58272071           1
## 91  44.58272071           0
## 92  45.15391394           1
## 93  45.15391394           0
## 94  46.07286168           1
## 95  46.07286168           0
## 96  46.35868255           1
## 97  47.02470897           2
## 98  47.35608785           3
## 99  47.38685874           4
## 100 48.07136046           3
## 101 48.33725810           2
## 102 48.41204417           3
## 103 48.82533145           2
## 104 49.05187987           1
## 105 49.09898371           0
## 106 49.84859646           1
## 107 49.84859646           0
## 108 50.06382036           1
## 109 50.60718962           0
## 110 51.02429570           1
## 111 51.07683402           0
## 112 54.38609740           1
## 113 54.38609740           0
## 114 54.51871687           1
## 115 54.51871687           0
## 116 55.15587873           1
## 117 55.15587873           0
## 118 55.32030863           1
## 119 55.32030864           0
## 120 55.75872310           1
## 121 55.75872310           0
## 122 55.81811854           1
## 123 56.32847554           0
## 124 57.15750551           1
## 125 57.15750551           0
## 126 57.60731874           1
## 127 58.05296767           0
## 128 58.21422119           1
## 129 58.58875148           0
## 130 59.35269424           1
## 131 59.35269425           0
## 132 59.92461086           1
## 133 59.92461086           0
## 134 64.87574572           1
## 135 64.87574572           0
## 136 66.09106412           1
## 137 66.09106412           0
## 138 66.20605680           1
## 139 66.20605680           0
## 140 67.64218892           1
## 141 67.64218892           0
## 142 67.65909717           1
## 143 67.65909717           0
## 144 68.50909833           1
## 145 68.90315792           0
## 146 70.59011750           1
## 147 70.59011750           0
## 148 70.83973399           1
## 149 70.83973399           0
## 150 71.42987913           1
## 151 71.42987913           0
## 152 71.43758517           1
## 153 71.47975462           2
## 154 71.59193492           1
## 155 71.73664150           0
## 156 73.62660416           1
## 157 73.62660416           0
## 158 73.69621302           1
## 159 73.69621302           0
## 160 76.15160999           1
## 161 76.15160999           0
## 162 81.35209627           1
## 163 81.35209627           0
## 164 81.54448970           1
## 165 81.54448970           0
## 166 81.59896172           1
## 167 81.78171489           0
## 168 82.02927648           1
## 169 82.02927648           0
## 170 83.46305169           1
## 171 83.46305169           0
## 172 84.79021620           1
## 173 84.79021620           0
## 174 84.97319933           1
## 175 84.97319933           0
## 176 85.44385001           1
## 177 85.44385001           0
## 178 88.37676210           1
## 179 88.37676210           0
## 180 90.41871042           1
## 181 90.41871042           0
## 182 91.17416971           1
## 183 91.17416971           0
## 184 91.37165292           1
## 185 91.37165292           0
## 186 91.84942917           1
## 187 91.84942917           0
## 188 92.30096161           1
## 189 92.30096161           0
## 190 92.30223706           1
## 191 92.30223706           0
## 192 92.38702003           1
## 193 92.48709653           0
## 194 93.21611884           1
## 195 93.21611884           0
## 196 96.13026393           1
## 197 96.13026393           0
## 198 96.49223633           1
## 199 96.49223633           0
## 200 98.10466732           1
## 201 98.10466732           0
## 
## $systemlength_df
##           times queuelength
## 1    0.00000000           0
## 2    0.03191802           1
## 3    1.56707421           2
## 4    1.63300775           3
## 5    2.03311017           4
## 6    2.25897130           5
## 7    2.87465898           4
## 8    3.40425011           5
## 9    4.99435298           4
## 10   5.04630759           3
## 11   5.82104977           2
## 12   6.11599085           3
## 13   6.74926606           4
## 14   7.02087397           3
## 15   8.00126648           2
## 16   8.19858505           1
## 17   8.49163452           0
## 18   9.30164777           1
## 19   9.88119024           0
## 20  10.20339610           1
## 21  10.51514738           2
## 22  11.50649097           1
## 23  11.92875114           2
## 24  12.73923157           1
## 25  12.79318275           0
## 26  16.26120012           1
## 27  16.34670494           0
## 28  16.49568059           1
## 29  17.82030064           0
## 30  18.60862166           1
## 31  18.89611597           0
## 32  19.51715468           1
## 33  19.88170787           0
## 34  20.95733092           1
## 35  21.16945349           0
## 36  21.17445657           1
## 37  21.31161680           2
## 38  23.25486967           3
## 39  23.84703013           4
## 40  25.61664225           3
## 41  25.71095748           4
## 42  25.92372947           3
## 43  26.03158955           4
## 44  26.03571188           3
## 45  26.22576731           2
## 46  26.79889395           1
## 47  26.92867876           2
## 48  27.18630888           3
## 49  27.97342778           4
## 50  27.97498019           3
## 51  28.06302313           2
## 52  28.57387587           3
## 53  28.67073020           4
## 54  29.15803176           3
## 55  29.56657528           4
## 56  29.72866244           5
## 57  29.79768793           4
## 58  30.34845110           5
## 59  30.39509502           6
## 60  30.44911106           5
## 61  31.19870549           4
## 62  31.32636412           3
## 63  31.39945725           2
## 64  31.80720295           1
## 65  31.93546312           0
## 66  33.35901534           1
## 67  33.59434588           0
## 68  33.85187805           1
## 69  34.74389727           0
## 70  35.92813719           1
## 71  36.49551251           0
## 72  36.59218135           1
## 73  36.62711940           0
## 74  37.17496841           1
## 75  38.46633771           2
## 76  38.66780170           1
## 77  38.76671363           0
## 78  39.35264010           1
## 79  39.44679710           2
## 80  39.76660212           3
## 81  40.05164985           2
## 82  40.14211257           1
## 83  40.54621139           2
## 84  41.06844940           3
## 85  41.39096018           2
## 86  41.62894585           1
## 87  41.63601778           0
## 88  41.83742713           1
## 89  41.99426029           0
## 90  44.58272071           1
## 91  45.15391394           2
## 92  45.97733188           1
## 93  46.07286168           2
## 94  46.35868255           3
## 95  47.02470897           4
## 96  47.35608785           5
## 97  47.38685874           6
## 98  48.07136046           5
## 99  48.33725810           4
## 100 48.41204417           5
## 101 48.82533145           4
## 102 49.05187987           3
## 103 49.09898371           2
## 104 49.31327995           1
## 105 49.84859646           2
## 106 50.06382036           3
## 107 50.60718962           2
## 108 51.02429570           3
## 109 51.07683402           2
## 110 51.37436030           1
## 111 53.56387650           0
## 112 54.38609740           1
## 113 54.47936342           0
## 114 54.51871687           1
## 115 54.73720149           0
## 116 55.15587873           1
## 117 55.32030863           2
## 118 55.40567448           1
## 119 55.75872310           2
## 120 55.81811854           3
## 121 56.32847554           2
## 122 56.47933663           1
## 123 57.15750551           2
## 124 57.60731874           3
## 125 58.05296767           2
## 126 58.21422119           3
## 127 58.58875148           2
## 128 59.26200492           1
## 129 59.35269424           2
## 130 59.74979469           1
## 131 59.79177524           0
## 132 59.92461086           1
## 133 60.76055278           0
## 134 64.87574572           1
## 135 66.09106412           2
## 136 66.10936265           1
## 137 66.10977834           0
## 138 66.20605680           1
## 139 66.63335838           0
## 140 67.64218892           1
## 141 67.65909717           2
## 142 68.50909833           3
## 143 68.90315792           2
## 144 69.06052146           1
## 145 70.29978742           0
## 146 70.59011750           1
## 147 70.83973399           2
## 148 71.22216134           1
## 149 71.42987913           2
## 150 71.43758517           3
## 151 71.47975462           4
## 152 71.59193492           3
## 153 71.73664150           2
## 154 72.18295910           1
## 155 72.24966940           0
## 156 73.62660416           1
## 157 73.69621302           2
## 158 74.70830630           1
## 159 76.15160999           2
## 160 76.23036160           1
## 161 76.61261297           0
## 162 81.35209627           1
## 163 81.54448970           2
## 164 81.59896172           3
## 165 81.78171489           2
## 166 81.82834796           1
## 167 81.99790155           0
## 168 82.02927648           1
## 169 82.36990105           0
## 170 83.46305169           1
## 171 84.58239168           0
## 172 84.79021620           1
## 173 84.97319933           2
## 174 85.20584517           1
## 175 85.44385001           2
## 176 86.45126390           1
## 177 86.56236478           0
## 178 88.37676210           1
## 179 88.68158536           0
## 180 90.41871042           1
## 181 91.05830452           0
## 182 91.17416971           1
## 183 91.37165292           2
## 184 91.74621791           1
## 185 91.81432420           0
## 186 91.84942917           1
## 187 91.86538885           0
## 188 92.30096161           1
## 189 92.30223706           2
## 190 92.38702003           3
## 191 92.48709653           2
## 192 93.07287600           1
## 193 93.21611884           2
## 194 95.30702356           1
## 195 96.13026393           2
## 196 96.36951695           1
## 197 96.49223633           2
## 198 96.64882595           1
## 199 96.77167502           0
## 200 98.10466732           1
## 201 98.19936282           0
## 
## $servers_input
## [1] 2

Simulasi dilakukan dengan 2 server. Fungsi queue_step() akan menghitung waktu keluar berdasarkan urutan kedatangan dan durasi layanan.

Validasi Model M/M/2

#Validasi dengan M/M/2 Queue (λ = 1, μ = 0.9)
set.seed(1)
n_customers <-10^4
lambda_a <- 1/1
lambda_s <- 1/0.9
interarrivals <- rexp(n_customers, lambda_a)
arrivals <- cumsum(interarrivals)
service <- rexp(n_customers, lambda_s)
queue_output <- queue_step(arrivals = arrivals, service = service, servers = 2)
head(sort(depart(queue_output)))
## [1] 1.340151 2.288112 2.639976 2.796572 3.249794 5.714967

Simulasi sistem antrian M/M/2 (dua server, kedatangan dan layanan eksponensial) dilakukan dengan 10.000 pelanggan. Ini digunakan untuk memverifikasi apakah queuecomputer menghasilkan output yang sesuai dengan teori.

Replikasi Hasil Teori untuk M/M/3

#Replikasi Teori M/M/3 Queue (λ = 2, μ = 1)
set.seed(1)
n_customers <- 5e6
lambda <- 2
mu <- 1
interarrivals <- rexp(n_customers, lambda)
arrivals <- cumsum(interarrivals)
service <- rexp(n_customers, mu)
K = 3
MM3 <- queue_step(arrivals = arrivals, service = service, servers = K)
summary(MM3)
## Total customers:
##  5000000
## Missed customers:
##  0
## Mean waiting time:
##  0.445
## Mean response time:
##  1.44
## Utilization factor:
##  0.666140156160826
## Mean queue length:
##  0.889
## Mean number of customers in system:
##  2.89

Dalam contoh ini, kita meniru sistem M/M/3 dengan 5 juta pelanggan. Ringkasan output (summary) menunjukkan waktu tunggu rata-rata, utilisasi server, dan panjang antrian rata-rata, yang mendekati hasil teori untuk sistem M/M/3.

Simulasi Antrian dengan Nama Pelanggan

set.seed(1)
interarrivals <- rexp(20, 1)
arrivals <- cumsum(interarrivals)
customers <- randomNames(20, name.order = "first.last")
service <- rexp(20, 0.5)
head(service)
## [1] 0.8979956 0.7591994 2.4975352 5.3868231 0.3926436 4.5996743

Kita membuat daftar nama pelanggan secara acak. Lalu kita simulasikan antrian untuk 20 pelanggan:

queue_obj <-queue_step(arrivals, service, servers = 2, labels = customers)
head(queue_obj$departures_df)
## # A tibble: 6 × 7
##   labels            arrivals service departures  waiting system_time server
##   <chr>                <dbl>   <dbl>      <dbl>    <dbl>       <dbl>  <int>
## 1 Saadiq, el-Molla     0.755   0.898       1.65 1.11e-16       0.898      1
## 2 Jelicha, Kim         1.94    0.759       2.70 0              0.759      2
## 3 Briana, Lesley       2.08    2.50        4.58 0              2.50       1
## 4 Daeun, Her           2.22    5.39        8.08 4.74e- 1       5.86       2
## 5 Ruwaida, al-Bahri    2.66    0.393       4.97 1.92e+ 0       2.31       1
## 6 Fawzi, al-Jamail     5.55    4.60       10.2  0              4.60       1

Nama pelanggan ditambahkan sebagai label, dan hasil queue_obj dapat diperiksa untuk melihat siapa dilayani oleh server mana dan kapan mereka selesai.

firstcustomers <- arrivals[1:2] + service [1:2]
firstcustomers[2] + service[3]
## [1] 5.193559
depart(queue_obj)[1:3] - arrivals[1:3] - service[1:3]
## [1]  1.110223e-16 -1.110223e-16  0.000000e+00

Baris di atas menghitung waktu tunggu untuk tiga pelanggan pertama.

Analisis Statistik dan Visualisasi

summary(queue_obj)
## Total customers:
##  20
## Missed customers:
##  0
## Mean waiting time:
##  0.893
## Mean response time:
##  2.52
## Utilization factor:
##  0.700476008415974
## Mean queue length:
##  0.82
## Mean number of customers in system:
##  2.17
plot(queue_obj, which = c(2, 4, 5, 6))
## [[1]]

## 
## [[2]]

## 
## [[3]]

## 
## [[4]]

Fungsi summary() memberikan ringkasan performa sistem, dan plot() memvisualisasikan panjang antrian, waktu layanan, dan distribusi kedatangan serta keberangkatan.

8.2 Studi Kasus Bandara (Simulasi Fork/Join)

Kita bangun data simulasi 20 penumpang dengan rute imigrasi acak dan waktu layanan yang berbeda:

# Simulasi data 20 penumpang dengan rute imigrasi acak
set.seed(123)
n <- 20
Passenger_df <- tibble(
  ID = paste0("P", 1:n),
  route_imm = sample(c("smart gate", "manual"), n, replace = TRUE),
  arrive_imm = sort(runif(n, 500, 800)),  # waktu tiba di imigrasi
  service_imm = rexp(n, rate = 1/3),      # waktu layanan imigrasi
  bag_time = runif(n, 550, 900)           # waktu bagasi tiba
)

Definisi server per rute:

# Definisikan jumlah server per rute
server_df <- data.frame(route_imm = c("smart gate", "manual"))
server_df$servers <- list(
  5,  # smart gate: 5 server tetap
  as.server.stepfun(x = c(600, 780), y = c(10, 12, 8))  # manual: server dinamis
)
  • Smart gate: 5 server tetap.
  • Manual gate: jumlah server berubah seiring waktu (fungsi langkah).

Kita gabungkan konfigurasi server ke dalam data penumpang:

# Gabungkan informasi server ke data penumpang
Passenger_df <- left_join(Passenger_df, server_df, by = "route_imm")

Kemudian kita jalankan simulasi per grup (berdasarkan rute), dan hitung waktu keluarnya dari imigrasi dan dari area bagasi (fork/join):

Passenger_df <- Passenger_df %>%
  group_by(route_imm) %>%
  mutate(departures_imm = queue(arrive_imm, service_imm, servers = servers[[1]])) %>%
  ungroup() %>%
  mutate(departures_bc = pmax.int(departures_imm, bag_time))  # proses fork-join

Ringkasan waktu tunggu rata-rata:

Passenger_df %>%
  group_by(route_imm) %>%
  summarise(
    waiting_imm = mean(departures_imm - service_imm - arrive_imm),
    waiting_bc = mean(departures_bc - departures_imm)
  )
## # A tibble: 2 × 3
##   route_imm  waiting_imm waiting_bc
##   <chr>            <dbl>      <dbl>
## 1 manual               0       49.3
## 2 smart gate           0       76.3

Visualisasi Sistem Bandara

# Simulasi ulang untuk mendapatkan queue_list object
queue_obj <- queue_step(
  arrivals = Passenger_df$arrive_imm,
  service = Passenger_df$service_imm,
  servers = 5
)

# Plot queue length dan lainnya
plot(queue_obj, which = c(2, 4, 5, 6))
## [[1]]

## 
## [[2]]

## 
## [[3]]

## 
## [[4]]

Grafik yang dihasilkan menampilkan:

  • Panjang antrian
  • Distribusi waktu tunggu
  • Alokasi layanan oleh server
  • Perbandingan antara waktu kedatangan dan keberangkatan

Visualisasi Tambahan: Boxplot Waktu Tunggu

dummy_data <- data.frame(
  route_imm = rep(c("A", "B", "C"), each = 30),
  waiting_imm = c(rnorm(30, 15, 5), rnorm(30, 30, 10), rnorm(30, 5, 2))
)

ggplot(dummy_data, aes(x = route_imm, y = waiting_imm, fill = route_imm)) +
  geom_boxplot() +
  labs(title = "Boxplot Waktu Tunggu (Contoh Data Dummy)")

Visualisasi ini memperlihatkan perbandingan waktu tunggu antar rute imigrasi menggunakan data dummy — menggambarkan bagaimana distribusi waktu tunggu bisa sangat berbeda tergantung beban layanan dan jumlah server.

Kesimpulan

Contoh-contoh ini menunjukkan bahwa:

  • queuecomputer mudah digunakan bahkan untuk simulasi kompleks.
  • Simulasi dapat dilakukan dalam skala kecil hingga besar.
  • Dukungan terhadap struktur topologi antrian fork/join dan dinamis membuatnya fleksibel untuk kebutuhan nyata seperti di bandara atau pusat layanan pelanggan.
  • Integrasi dengan dplyr dan ggplot2 memungkinkan analisis dan visualisasi yang interaktif dan informatif.

Jika Anda ingin, saya dapat menyusun ini menjadi file .Rmd atau .pdf sebagai bagian dari laporan tugas atau publikasi.

9. Kesimpulan

Paket R queuecomputer mengimplementasikan algoritma Queue Departure Computation (QDC), yang dapat digunakan untuk mensimulasikan sistem antrian atau jaringan antrian berantai (tandem) dengan bentuk umum:

\[ G(t)/G(t)/K(t)/\infty/n/\text{FCFS} \]

Beberapa algoritma cepat untuk sistem antrian multiserver sebenarnya telah diusulkan sebelumnya (misalnya oleh Krivulin, 1994; Sutton dan Jordan, 2010; Kin dan Chan, 2010), tetapi kurang mendapat perhatian, bahkan ketika efisiensinya telah dibuktikan (seperti pada Kin dan Chan, 2010).

Keunggulan dari QDC:

  • Lebih sederhana secara konsep
  • Lebih hemat memori
  • Modular mudah dikombinasikan dengan sistem atau fungsi lain

Validasi

Algoritma QDC telah divalidasi dengan dua pendekatan:

  1. Replikasi hasil teoritis dari teori antrian (misalnya untuk sistem M/M/K).
  2. Perbandingan dengan paket DES (Discrete Event Simulation) seperti simmer dan simpy.

Hasilnya menunjukkan bahwa QDC mampu menghasilkan output yang sama akuratnya, tetapi dengan kecepatan komputasi yang jauh lebih tinggi mencapai percepatan hingga 1000 kali lipat.

Fitur Unggulan

  • Cepat cocok untuk simulasi skala besar.
  • Deterministik hasil simulasi konsisten karena tidak bergantung pada generator angka acak internal.
  • Decoupled sampling & computation pengguna bebas menghasilkan data waktu kedatangan dan layanan menggunakan metode/statistik apa pun.
  • Terintegrasi dengan baik sangat cocok digunakan bersama paket dplyr untuk manipulasi data dan ggplot2 untuk visualisasi.
  • Mendukung topologi kompleks dapat menangani jaringan antrian paralel, seri (tandem), dan fork/join.

Aplikasi Lanjutan

Kecepatan queuecomputer memungkinkan simulasi antrian untuk disisipkan dalam algoritma Approximate Bayesian Computation (ABC), yang akan dibahas lebih lanjut dalam penelitian selanjutnya.

Studi Kasus dan Pengembangan dari**Simulasi Antrian yang Efisien Secara Komputasi melalui Paket R queuecomputer*

Studi Kasus 1

# Panggil library
library(queuecomputer)
library(ggplot2)
library(dplyr)

Studi Kasus: Antrian Pasien di Rumah Sakit Dalam studi kasus ini, dilakukan simulasi antrian pasien di sebuah rumah sakit dengan jumlah pasien sebanyak 100 orang. Waktu antar kedatangan pasien mengikuti distribusi eksponensial dengan rata-rata 1 pasien per menit, sedangkan waktu pelayanan setiap pasien rata-rata adalah 3 menit per pasien, juga mengikuti distribusi eksponensial.

Konfigurasi jumlah petugas (server) disesuaikan dengan kondisi waktu operasional, yaitu:

Pada 0–30 menit (jam sepi), tersedia 1 petugas,

Pada 30–60 menit (jam ramai), tersedia 2 petugas,

Setelah 60 menit (jam sepi kembali), jumlah petugas dikurangi menjadi 1 petugas.

Simulasi ini bertujuan untuk mengevaluasi performa sistem antrian, termasuk analisis waktu tunggu pasien, waktu pelayanan, jumlah pasien dalam sistem dari waktu ke waktu, serta visualisasi antrian secara menyeluruh.

#Langkah pertama Simulasi Data Pasien
# Jumlah pasien
set.seed(123)
n <- 100

# Waktu antar kedatangan ~ Exponential(1) → rata-rata 1 menit
arrivals <- cumsum(rexp(n, rate = 1))

# Waktu pelayanan ~ Exponential(1/3) → rata-rata 3 menit
service <- rexp(n, rate = 1/3)

# Tambahkan label pasien
labels_pasien <- paste0("Pasien-", 1:n)

Langkah Pertama: Simulasi Data Pasien Pada langkah ini, dilakukan proses simulasi data untuk 100 pasien yang akan dilayani oleh rumah sakit. Langkah-langkahnya dijelaskan sebagai berikut: set.seed(123) Digunakan untuk menetapkan seed angka acak agar hasil simulasi dapat direproduksi. Artinya, setiap kali kode dijalankan, hasil acaknya akan tetap sama. n <- 100 Menyatakan bahwa jumlah pasien yang akan disimulasikan sebanyak 100 orang. arrivals <- cumsum(rexp(n, rate = 1)) Menghasilkan waktu kedatangan pasien secara berurutan. Setiap pasien datang secara acak mengikuti distribusi eksponensial dengan rata-rata 1 menit. Fungsi cumsum() digunakan untuk mengakumulasi waktu antar kedatangan, sehingga menghasilkan waktu kedatangan kumulatif untuk setiap pasien. service <- rexp(n, rate = 1/3) Menghasilkan waktu pelayanan bagi masing-masing pasien yang juga bersifat acak dan mengikuti distribusi eksponensial, dengan rata-rata waktu pelayanan 3 menit per pasien. labels_pasien <- paste0(“Pasien-”, 1:n) Memberikan label atau nama identitas unik untuk masing-masing pasien, dari “Pasien-1” hingga “Pasien-100”. Label ini akan digunakan dalam visualisasi untuk mempermudah identifikasi setiap pasien dalam antrian.

# Langkah kedua mengonfigurasi Server yang Berubah
# Jadwal server:
# 0–30 menit: 1 dokter (sepi)
# 30–60 menit: 2 dokter (ramai)
# >60 menit: kembali 1 dokter

server_shift <- as.server.stepfun(
  x = c(30, 60),
  y = c(1, 2, 1)
)

Langkah Kedua: Mengonfigurasi Server yang Berubah Pada bagian ini, dilakukan konfigurasi terhadap jumlah petugas (dalam hal ini dokter) yang melayani pasien di rumah sakit, dengan memperhatikan perubahan jumlah server berdasarkan rentang waktu tertentu. server_shift <- as.server.stepfun(…) Mendefinisikan fungsi tangga (step function) untuk menggambarkan perubahan jumlah server seiring waktu. Fungsi ini menghasilkan objek server_shift yang dapat digunakan dalam simulasi antrian dinamis menggunakan queuecomputer. x = c(30, 60) Titik waktu di mana perubahan jumlah server terjadi. Artinya: Perubahan pertama terjadi pada menit ke-30 Perubahan kedua terjadi pada menit ke-60 y = c(1, 2, 1) Jumlah server (dokter) yang aktif pada setiap interval waktu: Dari waktu 0 hingga <30 menit, tersedia 1 dokter (kondisi sepi) Dari waktu 30 hingga <60 menit, tersedia 2 dokter (kondisi ramai) Dari waktu 60 menit ke atas, kembali tersedia 1 dokter (kondisi sepi) Konfigurasi ini memungkinkan simulasi untuk menangani skenario realistik di mana jumlah tenaga medis dapat disesuaikan berdasarkan kondisi waktu operasional, seperti jam ramai dan jam sepi.

#langkah ke tiga Simulasi Antrian dengan queue_step()
queue_obj <- queue_step(
  arrivals = arrivals,
  service = service,
  servers = server_shift,
  labels = labels_pasien
)

Langkah Ketiga: Simulasi Antrian Pasien Langkah ini merupakan inti dari proses simulasi, yaitu menjalankan sistem antrian berdasarkan data kedatangan, waktu pelayanan, jumlah server, dan identitas pasien.

#Ringkasan Performa Antrian
summary(queue_obj)
## Total customers:
##  100
## Missed customers:
##  0
## Mean waiting time:
##  59.8
## Mean response time:
##  62.7
## Utilization factor:
##  1.00480969299063
## Mean queue length:
##  23.3
## Mean number of customers in system:
##  24.2

Simulasi menunjukkan bahwa rumah sakit mengalami beban antrian yang tinggi, dengan waktu tunggu rata-rata hampir 1 jam dan utilisasi melebihi kapasitas normal. Hal ini mengindikasikan bahwa konfigurasi jumlah server (dokter) yang tersedia masih belum optimal dalam menangani jumlah kedatangan pasien yang tinggi, terutama di jam-jam sibuk.

#Visualisasi Queue Length dan Sistem
plot(queue_obj, which = c(2, 4, 5, 6))  # default visualisasi bawaan
## [[1]]

## 
## [[2]]

## 
## [[3]]

## 
## [[4]]

#Data Frame Untuk Analisis
queue_df <- queue_obj$departures_df %>%
  mutate(
    waiting_time = departures - arrivals - service,
    start_time = departures - service,
    label = factor(labels, levels = labels)  # agar urutan benar
  )
#Boxplot Waktu Tunggu Pasien
ggplot(queue_df, aes(y = waiting_time)) +
  geom_boxplot(fill = "steelblue") +
  labs(
    title = "Boxplot Waktu Tunggu Pasien",
    y = "Waktu Tunggu (menit)",
    x = NULL
  ) +
  theme_minimal()

#Gantt Chart Pelayanan per Pasien
ggplot(queue_df, aes(y = label)) +
  geom_segment(
    aes(x = start_time, xend = departures, yend = label),
    linewidth = 4, color = "darkgreen"
  ) +
  labs(
    title = "Gantt Chart Pelayanan Pasien",
    x = "Waktu (menit)",
    y = "Pasien"
  ) +
  theme_minimal()

Studi Kasus 2

# 1. Install dan panggil library
library(queuecomputer)
library(ggplot2)
library(dplyr)

Baris diatas digunakan untuk memasang dan memanggil library yang dibutuhkan. queuecomputer → untuk simulasi antrian. ggplot2 dan dplyr → untuk visualisasi dan manipulasi data.

# 2. Simulasi Data Drive-Thru
set.seed(2025)
n_pelanggan <- 120
kedatangan <- cumsum(rexp(n_pelanggan, rate = 1/3))  # ~1 mobil tiap 3 menit
pelayanan <- rexp(n_pelanggan, rate = 1/5)           # ~5 menit waktu pelayanan
labels <- paste("Mobil", 1:n_pelanggan)

set.seed() menjamin hasil simulasi konsisten (reproducible). Simulasi diatas membuat 120 pelanggan (mobil) yang datang dalam satu hari. kedatangan dihitung dengan distribusi eksponensial → merepresentasikan kedatangan acak setiap ±3 menit. pelayanan juga eksponensial → waktu cuci mobil bervariasi, rata-rata 5 menit. labels digunakan untuk memberi nama identitas tiap mobil (Mobil 1, Mobil 2, dst)

# 3. Simulasi Antrian dengan 3 Jalur Drive-Thru
dt_queue <- queue_step(arrivals = kedatangan,
                       service = pelayanan,
                       servers = 3,
                       labels = labels)

Fungsi queue_step() menjalankan simulasi antrian drive-thru. Parameter: arrivals: waktu kedatangan tiap mobil, service: waktu pelayanan tiap mobil, servers = 3: sistem memiliki 3 jalur pelayanan paralel, labels: nama mobil (untuk pelacakan). Hasilnya adalah objek simulasi yang menyimpan waktu tunggu, waktu selesai pelayanan, dll.

# 4. Ringkasan Statistik Sistem Antrian
summary(dt_queue)
## Total customers:
##  120
## Missed customers:
##  0
## Mean waiting time:
##  0.688
## Mean response time:
##  5.77
## Utilization factor:
##  0.583258277850833
## Mean queue length:
##  0.242
## Mean number of customers in system:
##  1.99

Menampilkan statistik kinerja sistem antrian, seperti: Mean waiting time → rata-rata waktu pelanggan menunggu giliran, Mean response time → total waktu dalam sistem (tunggu + pelayanan), Utilization factor → seberapa sibuk server (jalur drive-thru), Missed customers → pelanggan yang tidak dilayani (dalam simulasi ini = 0).

# 5. Dataframe hasil simulasi
df_dt <- dt_queue$departures_df

Mengambil hasil simulasi dalam bentuk dataframe, berisi: Nama mobil,Waktu kedatangan,Waktu mulai dan selesai pelayanan,Server yang melayani.

# 6. Tambahkan kolom waktu_tunggu dan jam kedatangan
df_dt <- df_dt %>%
  mutate(waktu_tunggu = departures - arrivals - service,
         jam = floor(arrivals / 60))  # jam sejak simulasi dimulai

Menambahkan 2 kolom baru: waktu_tunggu: total waktu mobil menunggu sebelum dilayani. jam: untuk melihat jam ke berapa pelanggan datang (dibagi per 60 menit).

# 7. Plot 1: Histogram Waktu Tunggu
ggplot(df_dt, aes(x = waktu_tunggu)) +
  geom_histogram(binwidth = 0.5, fill = "steelblue", color = "red") +
  labs(title = "Distribusi Waktu Tunggu Pelanggan Drive-Thru",
       x = "Waktu Tunggu (menit)", y = "Jumlah Pelanggan")

Menampilkan distribusi jumlah pelanggan berdasarkan waktu tunggu.Digunakan untuk mengetahui apakah mayoritas pelanggan harus menunggu lama atau tidak.

# 8. Plot 2: Boxplot Waktu Tunggu
ggplot(df_dt, aes(y = waktu_tunggu)) +
  geom_boxplot(fill = "tomato", alpha = 0.7) +
  labs(title = "Boxplot Waktu Tunggu Pelanggan", y = "Waktu Tunggu (menit)")

Memberikan gambaran statistik waktu tunggu:Median, kuartil, dan outlier.Sangat berguna untuk melihat sebaran dan ekstrem dari waktu tunggu pelanggan.

# 9.Plot 3: Rata-rata Waktu Tunggu Tiap Jam
df_dt %>%
  group_by(jam) %>%
  summarise(rata_waktu_tunggu = mean(waktu_tunggu)) %>%
  ggplot(aes(x = jam, y = rata_waktu_tunggu)) +
  geom_line(color = "darkgreen", linewidth = 1.2) +
  geom_point(size = 2) +
  labs(title = "Rata-rata Waktu Tunggu Pelanggan per Jam",
       x = "Jam ke-", y = "Rata-rata Waktu Tunggu (menit)")

Mengelompokkan pelanggan berdasarkan jam kedatangan.Menunjukkan jam-jam sibuk dengan waktu tunggu paling tinggi.

# 10. 📊 Plot 4: Timeline Waktu Tiba vs Waktu Selesai
ggplot(df_dt, aes(x = arrivals, xend = departures, y = labels, yend = labels)) +
  geom_segment(color = "purple") +
  labs(title = "Timeline Kedatangan dan Selesai Pelayanan per Mobil",
       x = "Waktu (menit)", y = "Mobil") +
  theme(axis.text.y = element_blank())

Visualisasi timeline setiap mobil: kapan mereka datang dan kapan selesai dilayani.Sangat informatif untuk melihat tumpang tindih layanan dan durasi pelayanan tiap mobil.

Kesimpulan keduanya

Kedua studi kasus ini mengembangkan dan memperkuat klaim dari paper bahwa: