#SOAL NO 1

Disimulasikan 1.000 data dari distribusi normal dengan rata-rata μ=75 dan simpangan baku σ=10. Kemudian dihitung rata-ratanya sebagai estimasi parameter populasi.

Gunakan simulasi untuk menghitung nilai pendekatan dari:

\[\mathbb{E}[X^2] = \int_0^1 x^2 \, dx = \frac{1}{3}, \text{ dengan } X \sim U(0,1)\]

Gunakan 10.000 angka random.

# Jumlah data simulasi
n <- 10000
# Simulasi bilangan acak dari distribusi Uniform(0,1)
x <- runif(n, min = 0, max = 1)
# Hitung nilai E[X^2] secara empiris
ex2 <- mean(x^2)
# Tampilkan hasil simulasi dan nilai teoritis
cat("Pendekatan E[X^2] dari simulasi =", ex2, "\n")
## Pendekatan E[X^2] dari simulasi = 0.3298796
cat("Nilai teoritis E[X^2] =", 1/3, "\n")
## Nilai teoritis E[X^2] = 0.3333333

Dengan demikian, hasil simulasi sangat mendekati nilai teoretis. Hal ini menunjukkan bahwa pendekatan Monte Carlo dengan menggunakan 10.000 angka random dari distribusi seragam \(U(0,1)\)memberikan estimasi yang cukup akurat terhadap nilai harapan \(\mathbb{E}[X^2]\)

#NO 2

Buat data random dari distribusi normal \(X \sim N(100, 15^2)\) untuk:

Hitung:

Lalu:

# Set seed untuk reproduktibilitas
set.seed(123)

# Parameter distribusi normal
mean_val <- 100
sd_val <- 15

# Ukuran sampel
n1 <- 100
n2 <- 1000
n3 <- 10000
# Simulasi data
data1 <- rnorm(n1, mean = mean_val, sd = sd_val)
data2 <- rnorm(n2, mean = mean_val, sd = sd_val)
data3 <- rnorm(n3, mean = mean_val, sd = sd_val)
# Hitung rata-rata dan simpangan baku
cat("n1 = 100 | Mean =", mean(data1), "| SD =", sd(data1), "\n")
## n1 = 100 | Mean = 101.3561 | SD = 13.69224
cat("n2 = 1000 | Mean =", mean(data2), "| SD =", sd(data2), "\n")
## n2 = 1000 | Mean = 100.2862 | SD = 15.06891
cat("n3 = 10000 | Mean =", mean(data3), "| SD =", sd(data3), "\n")
## n3 = 10000 | Mean = 99.96336 | SD = 14.98314
# Plot histogram
par(mfrow = c(1, 1)) # Membuat layout 1 baris 3 kolom
hist(data1, main = "Histogram n = 100", col = "skyblue", xlab = "Nilai", breaks = 20)

hist(data2, main = "Histogram n = 1.000", col = "salmon", xlab = "Nilai", breaks = 30)

hist(data3, main = "Histogram n = 10.000", col = "lightgreen", xlab = "Nilai", breaks = 40)

Lakukan simulasi dari distribusi binomial:

Sebanyak 5.000 kali percobaan (simulasi), kemudian:

Tentukan estimasi dari:

Penjelasan Hasil Secara umum, hasil dari simulasi ini menunjukkan:

Untuk Histogram terlihat agak kasar dan tidak terlalu menyerupai bentuk lonceng (normal), karena ukuran sampel yang kecil membuat distribusi empiris lebih rentan terhadap fluktuasi acak.

Untuk $𝑛= 1.000 $ Bentuk histogram mulai menyerupai kurva normal. Rata-rata dan simpangan baku mendekati nilai teoritis yaitu \(𝜇= 100 μ=100,𝜎= 15 σ=15.\)

Untuk \(𝑛= 10.000\) Distribusi semakin halus dan sangat menyerupai distribusi normal. Estimasi nilai rata-rata dan simpangan baku menjadi sangat dekat dengan nilai sebenarnya.

Soal no 3

# Set seed untuk reprodusibilitas
set.seed(123)

# Parameter distribusi
n <- 30
p <- 0.25
simulasi <- 5000
# Simulasi data dari distribusi binomial
data_binom <- rbinom(simulasi, size = n, prob = p)
# Hitung estimasi peluang P(X ≥ 15)
estimasi_prob <- mean(data_binom >= 15)
# Tampilkan hasil
cat("Estimasi P(X ≥ 15) =", estimasi_prob, "\n")
## Estimasi P(X ≥ 15) = 0.0024
# Nilai teoretis
1 - pbinom(14, size = 30, prob = 0.25)
## [1] 0.002749534

Soal No 4

untuk menghitung simpangan baku (standar deviasi sampel) berdasarkan rumus berikut:

# Fungsi simpangan baku menggunakan rumus manual
simpangan_baku_manual <- function(x) {
  n <- length(x)
  jumlah_x <- sum(x)
  jumlah_x2 <- sum(x^2)
  s <- sqrt((jumlah_x2 - (jumlah_x^2 / n)) / (n - 1))
  return(s)
}
# Set seed untuk reprodusibilitas
set.seed(123)

# Bangkitkan 1.000 data dari distribusi normal N(89, 10^2)
data_normal <- rnorm(1000, mean = 89, sd = 10)
# Hitung simpangan baku menggunakan fungsi manual
s_manual <- simpangan_baku_manual(data_normal)
# Bandingkan dengan fungsi sd() bawaan R
s_builtin <- sd(data_normal)
# Tampilkan hasil
cat("Simpangan baku (manual):", s_manual, "\n")
## Simpangan baku (manual): 9.91695
cat("Simpangan baku (builtin):", s_builtin, "\n")
## Simpangan baku (builtin): 9.91695

\(s = \sqrt{\frac{n \sum x^2 - (\sum x)^2}{n(n - 1)}}\)

SOAL NO 5

Spesifikasi Sistem:

library(simmer)
library(ggplot2)

# Parameter
set.seed(123)
lama_buka_jam <- 6
waktu_pelayanan <- 8  # menit
kedatangan_per_jam <- 5
hari_kerja <- 20
total_menit <- lama_buka_jam * 60 * hari_kerja

# Trajektori nasabah
nasabah_traj <- trajectory("nasabah") %>%
  seize("teller", 1) %>%
  timeout(function() rexp(1, 1/waktu_pelayanan)) %>%
  release("teller", 1)

# Fungsi simulasi
simulasi_antrian <- function(jumlah_teller) {
  env <- simmer("bank_simulasi")
  env %>%
    add_resource("teller", capacity = jumlah_teller) %>%
    add_generator("nasabah", nasabah_traj, function() rexp(1, kedatangan_per_jam / 60)) %>%
    run(until = total_menit)
  return(env)
}
  1. Simulasi Antrian Selama 20 Hari Kerja
jumlah_hari <- 20  # jumlah hari simulasi
waktu_buka <- 8 * 60  # 8 jam kerja dikonversi ke menit
rata_kedatangan_per_menit <- 1/5  # misalnya 1 nasabah setiap 5 menit
total_kedatangan <- c()  # inisialisasi vektor kosong

simulasi_2_teller <- simulasi_antrian(2)

for (hari in 1:jumlah_hari) {
  waktu <- 0
  kedatangan <- c()
  while (waktu < waktu_buka) {
    antar_kedatangan <- rexp(1, rate = rata_kedatangan_per_menit)
    waktu <- waktu + antar_kedatangan
    if (waktu < waktu_buka) {
      kedatangan <- c(kedatangan, waktu)
    }
  }
  total_kedatangan <- c(total_kedatangan, kedatangan)
}

cat("Total nasabah datang selama", jumlah_hari, "hari:", length(total_kedatangan), "orang\n")
## Total nasabah datang selama 20 hari: 1897 orang
  1. rata- rata waktu tunggu nasabah
# b. Rata-rata waktu tunggu nasabah
arrivals_2 <- get_mon_arrivals(simulasi_2_teller)
arrivals_2$waktu_tunggu <- arrivals_2$end_time - arrivals_2$start_time - arrivals_2$activity_time
rata2_tunggu_2 <- mean(arrivals_2$waktu_tunggu)
cat("Rata-rata waktu tunggu (2 teller):", round(rata2_tunggu_2, 2), "menit\n")
## Rata-rata waktu tunggu (2 teller): 0.94 menit
  1. presentase waktu teller sibuk

\(\bar{Q} = \frac{1}{n} \sum_{i=1}^{n} Q_i\)

# c. Persentase waktu teller sibuk
resource_2 <- get_mon_resources(simulasi_2_teller)
total_busy_2 <- tail(subset(resource_2, resource == "teller")$server, 1)
persen_sibuk_2 <- total_busy_2 / (2 * total_menit) * 100
cat("Persentase waktu teller sibuk (2 teller):", round(persen_sibuk_2, 2), "%\n")
## Persentase waktu teller sibuk (2 teller): 0.01 %

d. Bandingkan dengan 3 Teller

# d. Simulasi ulang dengan 3 teller
simulasi_3_teller <- simulasi_antrian(3)
arrivals_3 <- get_mon_arrivals(simulasi_3_teller)
arrivals_3$waktu_tunggu <- arrivals_3$end_time - arrivals_3$start_time - arrivals_3$activity_time
rata2_tunggu_3 <- mean(arrivals_3$waktu_tunggu)
cat("Rata-rata waktu tunggu (3 teller):", round(rata2_tunggu_3, 2), "menit\n")
## Rata-rata waktu tunggu (3 teller): 0.04 menit
resource_3 <- get_mon_resources(simulasi_3_teller)
total_busy_3 <- tail(subset(resource_3, resource == "teller")$server, 1)
persen_sibuk_3 <- total_busy_3 / (3 * total_menit) * 100
cat("Persentase waktu teller sibuk (3 teller):", round(persen_sibuk_3, 2), "%\n")
## Persentase waktu teller sibuk (3 teller): 0 %

e. Grafik Panjang Antrian

library(simmer)
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
library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:simmer':
## 
##     now, rollback
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
library(scales)

set.seed(42)
sim_time <- 360  # 6 jam (9:00–15:00)

# Jam awal operasional: pukul 9:00
start_time <- as.POSIXct("2025-06-20 09:00:00")

# Fungsi simulasi
create_bank <- function(n_teller, label) {
  env <- simmer(paste0("bank_", label))

  customer <- trajectory("nasabah") %>%
    seize("teller", 1) %>%
    timeout(function() rexp(1, rate = 1/8)) %>%  # waktu pelayanan rata-rata 8 menit
    release("teller", 1)

  env %>%
    add_resource("teller", capacity = n_teller) %>%
    add_generator("customer", customer, function() rexp(1, rate = 5/60)) %>%  # 5 orang per jam
    run(until = sim_time)

  # Ambil data queue dan ubah menit ke waktu jam
  get_mon_resources(env) %>%
    filter(resource == "teller") %>%
    mutate(
      label = paste(n_teller, "Teller"),
      real_time = start_time + dseconds(time * 60)
    ) %>%
    select(real_time, queue, label)
}

# Simulasi
data_2 <- create_bank(2, "2")
data_3 <- create_bank(3, "3")

# Gabungkan
combined <- bind_rows(data_2, data_3)

# Visualisasi
ggplot(combined, aes(x = real_time, y = queue, color = label, fill = label)) +
  geom_area(alpha = 0.3, position = "identity") +
  geom_line(size = 1) +
  facet_wrap(~label, ncol = 1, scales = "free_y") +
  scale_x_datetime(
    breaks = date_breaks("1 hour"),
    labels = date_format("%H:%M")
  ) +
  scale_color_manual(values = c("2 Teller" = "darkgreen", "3 Teller" = "steelblue")) +
  scale_fill_manual(values = c("2 Teller" = "lightgreen", "3 Teller" = "lightblue")) +
  labs(
    title = "📊 Perbandingan Panjang Antrian Teller (Simulasi Jam 09:00–15:00)",
    subtitle = "2 vs 3 Teller dalam 1 Hari Operasional (6 Jam)",
    x = "Waktu (Jam)",
    y = "Jumlah Nasabah dalam Antrian",
    color = "Jumlah Teller",
    fill = "Jumlah Teller"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", color = "#003366", size = 16),
    plot.subtitle = element_text(color = "#004080", face = "italic"),
    legend.position = "top",
    strip.text = element_text(face = "bold", size = 14)
  )
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

No 6

set.seed(123)

simulate_stock <- function(days = 60, order_qty = 50, order_freq = 5) {
  stock <- numeric(days)
  stock[1] <- 100  # stok awal
  for (day in 2:days) {
    demand <- sample(8:15, 1)  # permintaan acak
    stock[day] <- stock[day - 1] - demand
    if (day %% order_freq == 0) {
      stock[day] <- stock[day] + order_qty
    }
    if (stock[day] < 0) stock[day] <- 0
  }
  return(stock)
}

# Simulasi untuk soal a
stock_a <- simulate_stock()
print(stock_a)
##  [1] 100  86  72  62  99  89  80  71  58  98  86  75  62  49  91  82  72  57  45
## [20]  85  75  67  56  48  90  78  68  53  44  80  71  63  50  40  79  66  58  48
## [39]  34  72  61  47  32  23  61  47  39  31  22  58  48  37  25  11  49  39  24
## [58]  11   3  44

Interpretasi:

Pada bagian ini kita mensimulasikan stok harian selama 60 hari, dengan:

  • Penjualan acak 8–15 karung per hari (distribusi seragam).

  • Pengisian ulang setiap 5 hari sebanyak 50 karung.

  • Stok awal 100 karung.

Hasil simulasi menunjukkan fluktuasi stok yang menurun akibat permintaan harian dan kemudian meningkat kembali saat restock setiap 5 hari. Kita bisa melihat adanya potensi stok turun ke titik nol, meskipun tidak setiap hari.

No 6b — Hitung Berapa Kali Toko Kehabisan Stok

simulate_stock_loss <- function(days = 60, order_qty = 50, order_freq = 5) {
  stock <- 100
  out_of_stock_days <- 0
  loss <- 0
  
  for (day in 1:days) {
    demand <- sample(8:15, 1)
    if (stock < demand) {
      loss <- loss + (demand - stock) * 50000
      out_of_stock_days <- out_of_stock_days + 1
      stock <- 0
    } else {
      stock <- stock - demand
    }
    if (day %% order_freq == 0) stock <- stock + order_qty
  }
  return(list(out_of_stock_days = out_of_stock_days, loss = loss))
}

# Simulasi untuk soal b
result_b <- simulate_stock_loss()
print(result_b)
## $out_of_stock_days
## [1] 6
## 
## $loss
## [1] 2800000

Interpretasi:

  • Hari kehabisan stok menunjukkan seberapa sering toko tidak bisa memenuhi permintaan pelanggan karena stok habis.

    Kerugian dihitung berdasarkan hilangnya potensi keuntungan sebesar Rp50.000 per karung yang tidak terpenuhi.

Contoh hasil:

Toko kehabisan stok sebanyak 6 hari dalam 60 hari dan mengalami kerugian sekitar Rp700.000.

Ini menunjukkan perlunya manajemen stok yang lebih hati-hati agar tidak kehilangan keuntungan.

No 6c — Strategi Jumlah Pemesanan: 40, 50, 60 Karung

results_c <- sapply(c(40, 50, 60), function(qty) {
  result <- simulate_stock_loss(order_qty = qty)
  return(c(qty, result$out_of_stock_days, result$loss))
})

colnames(results_c) <- c("40 Karung", "50 Karung", "60 Karung")
rownames(results_c) <- c("Jumlah Pesan", "Hari Kehabisan", "Kerugian (Rp)")
print(results_c)
##                40 Karung 50 Karung 60 Karung
## Jumlah Pesan          40        50        60
## Hari Kehabisan        19         8         0
## Kerugian (Rp)    9450000   2550000         0

Semakin banyak karung yang dipesan, semakin kecil kemungkinan kehabisan stok dan kerugian. Namun, perlu dicatat bahwa biaya penyimpanan yang tidak dihitung di sini bisa meningkat jika stok terlalu banyak. Strategi 50–60 karung adalah yang paling seimbang.

No 6d — Strategi Frekuensi Pemesanan: Tiap 3, 5, 7 Hari

results_d <- sapply(c(3, 5, 7), function(freq) {
  result <- simulate_stock_loss(order_freq = freq)
  return(c(freq, result$out_of_stock_days, result$loss))
})

colnames(results_d) <- c("Setiap 3 Hari", "Setiap 5 Hari", "Setiap 7 Hari")
rownames(results_d) <- c("Frekuensi", "Hari Kehabisan", "Kerugian (Rp)")
print(results_d)
##                Setiap 3 Hari Setiap 5 Hari Setiap 7 Hari
## Frekuensi                  3         5e+00             7
## Hari Kehabisan             0         3e+00            19
## Kerugian (Rp)              0         1e+06       8650000

No 6e — Grafik Pergerakan Stok

library(ggplot2)

# Ambil strategi terbaik (misal: pesan 50 tiap 5 hari)
best_stock_e <- simulate_stock(order_qty = 50, order_freq = 5)

stock_df <- data.frame(
  Hari = 1:60,
  Stok = best_stock_e
)

ggplot(stock_df, aes(x = Hari, y = Stok)) +
  geom_line(color = "steelblue", size = 1.2) +
  geom_point(color = "darkblue") +
  labs(
    title = "📦 Grafik Pergerakan Stok Beras Bu Sari",
    x = "Hari ke-",
    y = "Jumlah Karung"
  ) +
  theme_minimal(base_size = 14)

Interpretasi:

Grafik menunjukkan fluktuasi stok dari hari ke hari. Polanya:

  • Stok menurun tajam selama 4 hari karena permintaan harian.

  • Lalu naik kembali saat pesanan datang setiap 5 hari.

  • Grafik ini membantu Bu Sari memantau tren kehabisan stok, dan menjadi dasar keputusan strategi pemesanan di masa depan.

Jika grafik sering menyentuh angka nol, maka itu alarm penting bahwa strategi saat ini tidak memadai.

Kesimpulan Umum:

Strategi terbaik (dalam hal meminimalkan kerugian karena kehabisan stok):

Namun, jika ingin strategi seimbang antara efisiensi dan biaya operasional, maka: