knitr::opts_chunk$set(echo = TRUE, message = FALSE, warning = FALSE)
set.seed(123)   # Seed global untuk replikasi

#persiapan paket

# Tambahkan package "tibble" agar fungsi tibble() tersedia
need_pkg <- c("simmer", "simmer.plot", "ggplot2", "dplyr", "tibble")
for (p in need_pkg) {
  if (!requireNamespace(p, quietly = TRUE)) {
    install.packages(p, dependencies = TRUE)
  }
  library(p, character.only = TRUE)
}

1 Soal 1 – Estimasi \(E[X^2]\) untuk \(X \sim U(0,1)\)

Teori menyatakan \(E[X^2] = \frac{1}{3} \approx 0{,}3333\). Kita mendekatinya dengan 10 000 bilangan acak.

X <- runif(10000)
estimasi_ex2 <- mean(X^2)
estimasi_ex2
## [1] 0.3297405

2 Soal 2 – Simulasi \(N(100,15^2)\) dengan \(n=100,1000,10000\)

Untuk setiap \(n\) kita hitung rata‑rata, simpangan baku, serta histogram.

ns <- c(100, 1000, 10000)
for (n in ns) {
  samp <- rnorm(n, mean = 100, sd = 15)
  cat(sprintf("n = %5d | mean = %.2f | sd = %.2f\n", n, mean(samp), sd(samp)))
  hist(samp,
       main = paste0("Histogram N(100, 15^2) – n=", n),
       xlab = "Nilai",
       col  = "lightblue")
}
## n =   100 | mean = 101.02 | sd = 13.34

## n =  1000 | mean = 100.49 | sd = 14.92

## n = 10000 | mean = 99.97 | sd = 15.05


3 Soal 3 – Simulasi \(\operatorname{Bin}(30,0.25)\) sebanyak 5000 kali

Estimasi \(P(X\ge 15)\) berdasarkan simulasi.

B <- rbinom(5000, size = 30, prob = 0.25)
p_ge15 <- mean(B >= 15)
p_ge15
## [1] 0.0014

4 Soal 4 – Fungsi Rumus \(s\)

Rumus: \[s = \sqrt{\dfrac{\sum x^2 - \dfrac{(\sum x)^2}{n}}{n-1}}\]

calc_s_custom <- function(x) {
  n <- length(x)
  sqrt((sum(x^2) - (sum(x)^2) / n) / (n - 1))
}

Contoh penggunaan dengan data \(\mathcal N(89,10^2)\) ukuran 1000.

data_norm <- rnorm(1000, mean = 89, sd = 10)
list(
  s_custom = calc_s_custom(data_norm),
  sd_builtin = sd(data_norm)
)
## $s_custom
## [1] 10.29769
## 
## $sd_builtin
## [1] 10.29769

5 Soal 5 – Simulasi Antrian Bank (2 vs 3 Teller)

Bank buka 6 jam per hari, 20 hari kerja.

# Parameter umum
hari       <- 20
jam_hari   <- 6
lama_menit <- hari * jam_hari * 60  # total durasi simulasi (menit)

interarrival <- function() rexp(1, 1/12)  # λ = 5 nasabah/jam = 1/12 per mnt
service_time <- function() rexp(1, 1/8)   # rata2 pelayanan 8 mnt

traj <- trajectory("Nasabah") %>%
  seize("teller", 1) %>%
  timeout(service_time) %>%
  release("teller", 1)

sim_bank <- function(n_teller) {
  interarrival <- function() rexp(1, 1/12)
  service_time <- function() rexp(1, 1/8)

  traj <- trajectory("Nasabah") %>%
    seize("teller", 1) %>%
    timeout(service_time) %>%
    release("teller", 1)

  env <- simmer(paste0("Bank_", n_teller, "T")) %>%
    add_resource("teller", n_teller) %>%
    add_generator("Nasabah", traj, distribution = interarrival) %>%
    run(until = lama_menit)

  list(
    arrivals  = get_mon_arrivals(env),
    resources = get_mon_resources(env)
  )
}

5.1 Hasil 2 Teller

res2 <- sim_bank(2)
if (nrow(res2$arrivals) == 0 || nrow(res2$resources) == 0) {
  cat("Simulasi tidak menghasilkan data. Coba jalankan ulang.\n")
} else {
  wait2 <- mean(res2$arrivals$waiting_time)
  util2 <- mean(res2$resources$utilization[res2$resources$resource == "teller"]) * 100
  cat(sprintf("Rata2 tunggu = %.2f mnt | Utilisasi = %.2f%%\n", wait2, util2))
}
## Rata2 tunggu = NA mnt | Utilisasi = NA%

5.2 Hasil 3 Teller

res3 <- sim_bank(3)
if (nrow(res3$arrivals) == 0 || nrow(res3$resources) == 0) {
  cat("Simulasi tidak menghasilkan data. Coba jalankan ulang.\n")
} else {
  wait3 <- mean(res3$arrivals$waiting_time)
  util3 <- mean(res3$resources$utilization[res3$resources$resource == "teller"]) * 100
  cat(sprintf("Rata2 tunggu = %.2f mnt | Utilisasi = %.2f%%\n", wait3, util3))
}
## Rata2 tunggu = NA mnt | Utilisasi = NA%

5.3 Grafik Panjang Antrian (2 Teller)

plot(res2$resources, metric = "usage", resource = "teller",
     main = "Panjang Antrian Teller – 2 Teller")


6 Soal 6 – Simulasi Inventory Toko Kelontong Bu Sari (Extended 60 Hari)

6.1 6.1  Fungsi Simulasi

sim_inventory <- function(days = 60, stok_init = 100, order_qty = 50, order_freq = 5,
                          harga_jual = 0, lost_profit_per = 50000,
                          demand_fun = function() sample(8:15, 1)) {
  stok <- stok_init
  stok_vec <- numeric(days)
  lost_profit <- 0
  stockout_events <- 0

  for (t in 1:days) {
    # Pemesanan terjadwal
    if (t %% order_freq == 0) stok <- stok + order_qty

    # Permintaan harian
    demand <- demand_fun()
    if (demand > stok) {
      lost_profit <- lost_profit + (demand - stok) * lost_profit_per
      stockout_events <- stockout_events + 1
      stok <- 0
    } else {
      stok <- stok - demand
    }

    stok_vec[t] <- stok
  }
  list(stok = stok_vec,
       lost_profit = lost_profit,
       stockouts = stockout_events)
}

6.2 6.2  Simulasi Dasar (Pesan 50 karung / 5 hari)

baseline <- sim_inventory()
cat("Kehabisan stok", baseline$stockouts, "kali | Rugi ↓ Rp",
    format(baseline$lost_profit, big.mark = ","), "\n")
## Kehabisan stok 7 kali | Rugi ↓ Rp 3,300,000

6.3 6.3  Strategi (a) – Variasi Jumlah Pesan (40, 50, 60) tiap 5 hari

qty_vec <- c(40, 50, 60)
var_qty <- lapply(qty_vec, function(q) sim_inventory(order_qty = q))
qty_tbl <- tibble(qty = qty_vec,
                  stockouts = sapply(var_qty, `[[`, "stockouts"),
                  lost_profit = sapply(var_qty, `[[`, "lost_profit"))
qty_tbl
## # A tibble: 3 × 3
##     qty stockouts lost_profit
##   <dbl>     <dbl>       <dbl>
## 1    40        15     7750000
## 2    50         2      300000
## 3    60         0           0

6.4 6.4  Strategi (b) – Variasi Frekuensi Pesan (3, 5, 7 hari) 50 karung

freq_vec <- c(3, 5, 7)
var_freq <- lapply(freq_vec, function(f) sim_inventory(order_freq = f))
freq_tbl <- tibble(freq = freq_vec,
                   stockouts = sapply(var_freq, `[[`, "stockouts"),
                   lost_profit = sapply(var_freq, `[[`, "lost_profit"))
freq_tbl
## # A tibble: 3 × 3
##    freq stockouts lost_profit
##   <dbl>     <dbl>       <dbl>
## 1     3         0           0
## 2     5         4     1450000
## 3     7        18     8800000

6.5 6.5  Grafik Pergerakan Stok (Baseline)

library(ggplot2)
tibble(day = 1:60, stok = baseline$stok) %>%
  ggplot(aes(day, stok)) + geom_line() + geom_point() +
  labs(title = "Pergerakan Stok Beras – Strategi Dasar (50 karung / 5 hari)",
       x = "Hari", y = "Sisa Stok") + theme_minimal()

6.6 6.6  Rekomendasi

# Pilih strategi dengan lost_profit minimum, jika seri pakai stockouts minimum
best_qty <- qty_tbl %>% arrange(lost_profit, stockouts) %>% slice(1)
best_freq <- freq_tbl %>% arrange(lost_profit, stockouts) %>% slice(1)

cat("▶ Jumlah pesan optimal (tiap 5 hari):", best_qty$qty, "karung\n")
## ▶ Jumlah pesan optimal (tiap 5 hari): 60 karung
cat("   — kehabisan", best_qty$stockouts, "kali | rugi Rp",
    format(best_qty$lost_profit, big.mark = ","), "\n\n")
##    — kehabisan 0 kali | rugi Rp 0
cat("▶ Frekuensi pesan optimal (50 karung per pemesanan): setiap", best_freq$freq, "hari\n")
## ▶ Frekuensi pesan optimal (50 karung per pemesanan): setiap 3 hari
cat("   — kehabisan", best_freq$stockouts, "kali | rugi Rp",
    format(best_freq$lost_profit, big.mark = ","), "\n")
##    — kehabisan 0 kali | rugi Rp 0

7 Kesimpulan Singkat

Strategi stok terbaik berdasarkan simulasi 60 hari adalah:

🔹 Jumlah pemesanan optimal: 60 karung setiap 5 hari

🔹 Frekuensi pemesanan optimal: setiap 3 hari dengan jumlah 50 karung

🔹 Kedua strategi ini menghasilkan jumlah kehabisan stok dan kerugian terkecil selama periode simulasi.

📊 Bu Sari disarankan memilih kombinasi strategi tersebut untuk meminimalkan risiko kehilangan penjualan dan menjaga ketersediaan stok secara optimal.