1. Gunakan Simulasi untuk menghitung nilai pendekatan dari E[X²] untuk variabel random berdistribusi Uniform jika X ~ U(0,1). Gunakan 10.000 angka Random

set.seed(123)
x <- runif(10000, 0, 1)
ekspektasi_x2 <- mean(x^2)
ekspektasi_x2
## [1] 0.3297405

2. Menghitung rata rata, simpangan baku dan plot histogram.

# Set seed untuk hasil tetap
set.seed(123)

# Fungsi untuk simulasi dan analisis
simulasi_normal <- function(n) {
  data <- rnorm(n, mean = 100, sd = 15)
  
  rata2 <- mean(data)
  simpangan_baku <- sd(data)
  
  cat("Jumlah data:", n, "\n")
  cat("Rata-rata:", round(rata2, 2), "\n")
  cat("Simpangan baku:", round(simpangan_baku, 2), "\n\n")
  
  hist(data,
       breaks = 30,
       col = "darkblue",
       main = paste("Histogram N(100, 15^2) dengan n =", n),
       xlab = "Nilai",
       border = "white")
  
  invisible(data)
}

# Jalankan untuk n = 100
data_100 <- simulasi_normal(100)
## Jumlah data: 100 
## Rata-rata: 101.36 
## Simpangan baku: 13.69

# Jalankan untuk n = 1000
data_1000 <- simulasi_normal(1000)
## Jumlah data: 1000 
## Rata-rata: 100.29 
## Simpangan baku: 15.07

# Jalankan untuk n = 10000
data_10000 <- simulasi_normal(10000)
## Jumlah data: 10000 
## Rata-rata: 99.96 
## Simpangan baku: 14.98

## 3. menentukan nilai estimasi dari P(X lebih besar sama dengan 15)

set.seed(123)
simulasi_binomial <- rbinom(5000, size = 30, prob = 0.25)
peluang_x_15_lebih <- mean(simulasi_binomial >= 15)
peluang_x_15_lebih
## [1] 0.0024

4. Menghitung nilai s dengan membangkitkan data berdistribusi normal sebanyak data 1000, rata rata 89, dan standar deviasi 10

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

# Coba fungsi dengan 1000 data dari distribusi normal
set.seed(123)
data_normal <- rnorm(1000, mean = 89, sd = 10)
s_manual(data_normal)
## [1] 9.91695
sd(data_normal)  # untuk membandingkan
## [1] 9.91695

5.a.) Simulasi antrian di bank selama 20 hari kerja

set.seed(123)

# Parameter dasar
jumlah_hari <- 20
jam_per_hari <- 6
total_menit <- jumlah_hari * jam_per_hari * 60  # Total simulasi dalam menit

# Rata-rata kedatangan: 5 orang per jam → 1 orang setiap 12 menit → rate = 1/12
rata_kedatangan <- 5 / 60  # per menit
rata_layanan <- 1 / 8      # rata-rata pelayanan 8 menit

# Simulasi waktu kedatangan nasabah
waktu_antar_kedatangan <- rexp(10000, rate = rata_kedatangan)
waktu_kedatangan <- cumsum(waktu_antar_kedatangan)
waktu_kedatangan <- waktu_kedatangan[waktu_kedatangan <= total_menit]

# Jumlah nasabah
n_nasabah <- length(waktu_kedatangan)

# Simulasi waktu pelayanan (eksponensial, mean = 8 menit)
lama_pelayanan <- rexp(n_nasabah, rate = rata_layanan)

# Simulasi antrian dengan 2 teller
mulai_pelayanan <- selesai_pelayanan <- numeric(n_nasabah)
teller_selesai <- c(0, 0)  # dua teller, inisialisasi waktu selesai mereka

for (i in 1:n_nasabah) {
  teller_tersedia <- which.min(teller_selesai)
  mulai_pelayanan[i] <- max(waktu_kedatangan[i], teller_selesai[teller_tersedia])
  selesai_pelayanan[i] <- mulai_pelayanan[i] + lama_pelayanan[i]
  teller_selesai[teller_tersedia] <- selesai_pelayanan[i]
}

# Output hasil simulasi
hasil_antrian <- data.frame(
  Nasabah = 1:n_nasabah,
  Datang = round(waktu_kedatangan, 2),
  Mulai = round(mulai_pelayanan, 2),
  Selesai = round(selesai_pelayanan, 2),
  Tunggu = round(mulai_pelayanan - waktu_kedatangan, 2),
  Durasi = round(lama_pelayanan, 2)
)

# Tampilkan 20 hari kerja
head(hasil_antrian, 20)
##    Nasabah Datang  Mulai Selesai Tunggu Durasi
## 1        1  10.12  10.12   11.66   0.00   1.54
## 2        2  17.04  17.04   20.95   0.00   3.91
## 3        3  32.99  32.99   38.94   0.00   5.95
## 4        4  33.37  33.37   42.00   0.00   8.63
## 5        5  34.04  38.94   47.07   4.89   8.14
## 6        6  37.84  42.00   61.63   4.15  19.63
## 7        7  41.61  47.07   50.72   5.46   3.64
## 8        8  43.35  50.72   66.61   7.36  15.90
## 9        9  76.07  76.07   76.45   0.00   0.38
## 10      10  76.42  76.42   92.62   0.00  16.20
## 11      11  88.48  88.48   91.50   0.00   3.02
## 12      12  94.24  94.24   95.05   0.00   0.81
## 13      13  97.61  97.61  100.26   0.00   2.65
## 14      14 102.14 102.14  116.05   0.00  13.92
## 15      15 104.40 104.40  115.40   0.00  11.00
## 16      16 114.59 115.40  150.96   0.81  35.56
## 17      17 133.35 133.35  134.83   0.00   1.48
## 18      18 139.10 139.10  142.40   0.00   3.30
## 19      19 146.19 146.19  149.43   0.00   3.24
## 20      20 194.68 194.68  195.24   0.00   0.56

5. b.) lama rata rata nasabah menunggu (dalam Jam)

# Hitung rata-rata waktu tunggu
rata_rata_tunggu <- mean(hasil_antrian$Tunggu)

# Tampilkan hasil
cat("Rata-rata waktu tunggu nasabah:", round(rata_rata_tunggu, 2), "menit\n")
## Rata-rata waktu tunggu nasabah: 1.24 menit

5.c.) hitung berapa persen waktu teller sibuk kerja

jumlah_teller <- 2
# Total waktu kerja per teller (dalam menit)
total_waktu_kerja_per_teller <- jumlah_hari * jam_per_hari * 60

# Total waktu sibuk masing-masing teller
waktu_sibuk_teller <- numeric(2)

# Kita hitung total durasi pelayanan masing-masing teller
# Caranya: kita ulangi proses simulasi & lacak teller mana yang melayani siapa

# Inisialisasi ulang
teller_selesai <- c(0, 0)
teller_log <- numeric(n_nasabah)

for (i in 1:n_nasabah) {
  teller_tersedia <- which.min(teller_selesai)
  mulai <- max(waktu_kedatangan[i], teller_selesai[teller_tersedia])
  selesai <- mulai + lama_pelayanan[i]
  teller_selesai[teller_tersedia] <- selesai
  waktu_sibuk_teller[teller_tersedia] <- waktu_sibuk_teller[teller_tersedia] + lama_pelayanan[i]
  teller_log[i] <- teller_tersedia
}

# Total waktu sibuk semua teller
total_sibuk <- sum(waktu_sibuk_teller)
total_kerja <- jumlah_teller * total_waktu_kerja_per_teller

# Hitung persentase waktu sibuk
persen_sibuk <- 100 * total_sibuk / total_kerja

# Tampilkan hasil
cat("Total waktu sibuk:", round(total_sibuk, 2), "menit\n")
## Total waktu sibuk: 4920.02 menit
cat("Persentase waktu teller sibuk:", round(persen_sibuk, 2), "%\n")
## Persentase waktu teller sibuk: 34.17 %

5.d.) Bandingkan jika bank menambah 1 teller lagi, apakah lebih efisien?

set.seed(123)

# Parameter dasar tetap
jumlah_teller <- 3
total_menit <- jumlah_hari * jam_per_hari * 60

# Simulasi kedatangan tetap sama
# waktu_kedatangan dan lama_pelayanan masih bisa kita gunakan

# Inisialisasi ulang
mulai_pelayanan_3 <- selesai_pelayanan_3 <- numeric(n_nasabah)
teller_selesai_3 <- rep(0, jumlah_teller)
teller_log_3 <- numeric(n_nasabah)
waktu_sibuk_teller_3 <- numeric(jumlah_teller)

for (i in 1:n_nasabah) {
  teller_tersedia <- which.min(teller_selesai_3)
  mulai_pelayanan_3[i] <- max(waktu_kedatangan[i], teller_selesai_3[teller_tersedia])
  selesai_pelayanan_3[i] <- mulai_pelayanan_3[i] + lama_pelayanan[i]
  teller_selesai_3[teller_tersedia] <- selesai_pelayanan_3[i]
  waktu_sibuk_teller_3[teller_tersedia] <- waktu_sibuk_teller_3[teller_tersedia] + lama_pelayanan[i]
  teller_log_3[i] <- teller_tersedia
}

# Buat data.frame untuk hasil
hasil_3_teller <- data.frame(
  Nasabah = 1:n_nasabah,
  Datang = round(waktu_kedatangan, 2),
  Mulai = round(mulai_pelayanan_3, 2),
  Selesai = round(selesai_pelayanan_3, 2),
  Tunggu = round(mulai_pelayanan_3 - waktu_kedatangan, 2),
  Durasi = round(lama_pelayanan, 2)
)

# Hitung metrik
rata2_tunggu_3 <- mean(hasil_3_teller$Tunggu)
total_sibuk_3 <- sum(waktu_sibuk_teller_3)
total_kerja_3 <- jumlah_teller * total_menit
persen_sibuk_3 <- 100 * total_sibuk_3 / total_kerja_3

# Tampilkan hasil
cat("=== HASIL DENGAN 3 TELLER ===\n")
## === HASIL DENGAN 3 TELLER ===
cat("Rata-rata waktu tunggu:", round(rata2_tunggu_3, 2), "menit\n")
## Rata-rata waktu tunggu: 0.15 menit
cat("Persentase waktu teller sibuk:", round(persen_sibuk_3, 2), "%\n")
## Persentase waktu teller sibuk: 22.78 %

5.e.) buat grafik yang menunjukkan panjang antrian sepanjang hari

# Simulasikan ulang dengan 2 teller (seperti awal)
jumlah_teller <- 2
teller_selesai_e <- rep(0, jumlah_teller)
mulai_e <- selesai_e <- numeric(n_nasabah)
antrian_harian <- numeric(jumlah_hari)

for (i in 1:n_nasabah) {
  hari_ke <- ceiling(waktu_kedatangan[i] / (jam_per_hari * 60))

  teller_tersedia <- which.min(teller_selesai_e)
  mulai_e[i] <- max(waktu_kedatangan[i], teller_selesai_e[teller_tersedia])
  selesai_e[i] <- mulai_e[i] + lama_pelayanan[i]
  teller_selesai_e[teller_tersedia] <- selesai_e[i]

  # Hitung panjang antrian saat nasabah datang (teller belum selesai)
  antrian_aktif <- sum(mulai_e[1:(i - 1)] > waktu_kedatangan[i])
  
  # Simpan panjang antrian maksimum per hari
  if (antrian_aktif > antrian_harian[hari_ke]) {
    antrian_harian[hari_ke] <- antrian_aktif
  }
}

# Buat data frame untuk plot
df_antrian <- data.frame(
  Hari = 1:jumlah_hari,
  Maks_Antrian = antrian_harian
)

# Plot grafik
library(ggplot2)
## Warning: package 'ggplot2' was built under R version 4.3.3
ggplot(df_antrian, aes(x = Hari, y = Maks_Antrian)) +
  geom_col(fill = "darkblue") +
  labs(
    title = "Grafik Panjang Antrian Maksimum per Hari",
    x = "Hari ke-",
    y = "Panjang Antrian Maksimum"
  ) +
  theme_minimal()

library(ggplot2)

# Data sebelumnya: df_antrian (untuk 2 teller)
ggplot(df_antrian, aes(x = factor(Hari), y = Maks_Antrian)) +
  geom_col(fill = "#F8766D", width = 0.6) +
  geom_text(aes(label = Maks_Antrian), vjust = -0.3, size = 3.5) +
  labs(
    title = "Panjang Antrian Maksimum per Hari (2 Teller)",
    x = "Hari ke-",
    y = "Panjang Antrian Maksimum"
  ) +
  theme_minimal(base_size = 13) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5, size = 14),
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.y = element_line(color = "gray85"),
    panel.grid.minor = element_blank()
  ) +
  ylim(0, max(df_antrian$Maks_Antrian) + 2)

6.a simulasikan stok beras selama 60 hari

# Parameter dasar
hari <- 60
stok_awal <- 100
jumlah_pesan <- 50
jadwal_pesan <- 5

# Inisialisasi vektor
stok <- numeric(hari)
penjualan <- numeric(hari)
pesan_ulang <- rep(FALSE, hari)
kehabisan <- rep(FALSE, hari)

# Set stok awal
stok[1] <- stok_awal

# Simulasi per hari
for (i in 1:hari) {
  # Penjualan hari ke-i
  penjualan[i] <- sample(8:15, 1)
  
  # Kurangi stok
  if (i == 1) {
    stok[i] <- stok_awal - penjualan[i]
  } else {
    stok[i] <- stok[i-1] - penjualan[i]
  }
  
  # Kalau stok habis atau negatif
  if (stok[i] < 0) {
    kehabisan[i] <- TRUE
    stok[i] <- 0
  }
  
  # Pesan ulang setiap 5 hari
  if (i %% jadwal_pesan == 0) {
    stok[i] <- stok[i] + jumlah_pesan
    pesan_ulang[i] <- TRUE
  }
}

cat("Stok akhir:", stok[hari], "\n")
## Stok akhir: 50
cat("Total kehabisan hari:", sum(kehabisan), "\n")
## Total kehabisan hari: 3
head(data.frame(Hari = 1:hari, Penjualan = penjualan, Stok = stok, PesanUlang = pesan_ulang, Kehabisan = kehabisan), 10)
##    Hari Penjualan Stok PesanUlang Kehabisan
## 1     1        14   86      FALSE     FALSE
## 2     2        14   72      FALSE     FALSE
## 3     3        10   62      FALSE     FALSE
## 4     4        13   49      FALSE     FALSE
## 5     5        10   89       TRUE     FALSE
## 6     6         9   80      FALSE     FALSE
## 7     7         9   71      FALSE     FALSE
## 8     8        13   58      FALSE     FALSE
## 9     9        10   48      FALSE     FALSE
## 10   10        12   86       TRUE     FALSE

6.b.) hitung berapa kali toko kehabisan stok

jumlah_kehabisan <- sum(kehabisan)
cat("Toko kehabisan stok sebanyak", jumlah_kehabisan, "hari dari total", hari, "hari.\n")
## Toko kehabisan stok sebanyak 3 hari dari total 60 hari.

6.c.) coba berbagai strategi; pesan 40,50, atau 60 karung. manakah yang terbaik

# Fungsi untuk mengevaluasi strategi jumlah pemesanan
evaluasi_strategi_pesan <- function(jumlah_pesan) {
  stok <- stok_awal
  kehabisan <- 0
  
  for (i in 1:hari) {
    jual <- sample(8:15, 1)
    stok <- stok - jual
    
    if (stok < 0) {
      kehabisan <- kehabisan + 1
      stok <- 0
    }
    
    if (i %% jadwal_pesan == 0) {
      stok <- stok + jumlah_pesan
    }
  }
  
  return(kehabisan)
}

# Coba 3 strategi pemesanan
opsi_jumlah_pesan <- c(40, 50, 60)
hasil_6c <- sapply(opsi_jumlah_pesan, evaluasi_strategi_pesan)

# Tampilkan hasil dalam data frame
hasil_df_6c <- data.frame(
  Jumlah_Pesan = opsi_jumlah_pesan,
  Hari_Kehabisan = hasil_6c,
  Kerugian = hasil_6c * 50000
)

hasil_df_6c
##   Jumlah_Pesan Hari_Kehabisan Kerugian
## 1           40             17   850000
## 2           50              9   450000
## 3           60              0        0

Strategi terbaik secara kerugian murni adalah memesan 60 karung Tapi kalau Bu Sari ingin menyeimbangkan antara kerugian dan stok berlebih, maka 50 karung bisa menjadi pilihan efisien.

6.d.) coba ubah frekuensi pesan: setiap 3,5, atau 7 hari. manakah yang optimal?

# Fungsi untuk uji frekuensi pemesanan (jumlah pesan tetap 50)
evaluasi_frekuensi_pesan <- function(frekuensi) {
  stok <- stok_awal
  kehabisan <- 0
  
  for (i in 1:hari) {
    jual <- sample(8:15, 1)
    stok <- stok - jual
    
    if (stok < 0) {
      kehabisan <- kehabisan + 1
      stok <- 0
    }
    
    if (i %% frekuensi == 0) {
      stok <- stok + 50
    }
  }
  
  return(kehabisan)
}

# Uji untuk frekuensi 3, 5, 7 hari
opsi_frekuensi <- c(3, 5, 7)
hasil_6d <- sapply(opsi_frekuensi, evaluasi_frekuensi_pesan)

# Tampilkan hasil dalam data frame
hasil_df_6d <- data.frame(
  Frekuensi_Pesan = opsi_frekuensi,
  Hari_Kehabisan = hasil_6d,
  Kerugian = hasil_6d * 50000
)

hasil_df_6d
##   Frekuensi_Pesan Hari_Kehabisan Kerugian
## 1               3              0        0
## 2               5              2   100000
## 3               7             17   850000

simulasi strategi pemesanan ulang beras untuk Bu Sari, dilakukan perbandingan terhadap tiga frekuensi pemesanan yang berbeda, yaitu setiap 3 hari, 5 hari, dan 7 hari, dengan jumlah pemesanan tetap sebanyak 50 karung. Hasil simulasi menunjukkan bahwa semakin sering pemesanan dilakukan, maka risiko kehabisan stok semakin kecil. Ketika Bu Sari melakukan pemesanan setiap 3 hari sekali, tidak pernah terjadi kehabisan stok selama periode 60 hari. Hal ini membuat kerugian akibat kehilangan penjualan menjadi nol. Sebaliknya, saat pemesanan dilakukan setiap 5 hari, toko mengalami kehabisan stok sebanyak 5 kali, yang setara dengan kerugian sebesar Rp250.000. Meskipun terdapat sedikit kerugian, strategi ini masih tergolong efisien karena tidak terlalu sering memesan dan kerugian tetap dalam batas wajar. Namun, ketika frekuensi pemesanan dikurangi menjadi setiap 7 hari, jumlah hari tanpa stok meningkat drastis menjadi 21 hari. Kerugian yang ditimbulkan pun mencapai Rp1.050.000, yang merupakan jumlah terbesar di antara ketiga strategi.

6.e.)

# Pastikan semua library tersedia
library(ggplot2)

# Parameter dasar
set.seed(123)  # Supaya hasil acak konsisten
hari <- 60
stok_awal <- 100
jumlah_pesan <- 50
jadwal_pesan <- 5

# Inisialisasi
stok <- numeric(hari)
penjualan <- numeric(hari)
pesan_ulang <- logical(hari)
kehabisan <- logical(hari)

# Simulasi
for (i in 1:hari) {
  penjualan[i] <- sample(8:15, 1)

  if (i == 1) {
    stok[i] <- stok_awal - penjualan[i]
  } else {
    stok[i] <- stok[i - 1] - penjualan[i]
  }

  # Cek kehabisan (stok nol atau kurang setelah penjualan)
  if (stok[i] <= 0) {
    kehabisan[i] <- TRUE
    stok[i] <- 0
  }

  # Pemesanan ulang tiap 5 hari
  if (i %% jadwal_pesan == 0) {
    stok[i] <- stok[i] + jumlah_pesan
    pesan_ulang[i] <- TRUE
  }
}

# Buat data frame untuk grafik
df_stok <- data.frame(
  Hari = 1:hari,
  Stok = stok,
  Pemesanan = pesan_ulang,
  Kehabisan = kehabisan
)

# Cek dulu jumlah hari kehabisan
print(paste("Total hari kehabisan stok:", sum(df_stok$Kehabisan)))
## [1] "Total hari kehabisan stok: 3"
# Plot grafik stok
ggplot(df_stok, aes(x = Hari, y = Stok)) +
  geom_line(color = "yellow", linewidth = 1.2) +
  geom_point(data = subset(df_stok, Pemesanan), aes(x = Hari, y = Stok), color = "blue", size = 3) +
  geom_point(data = subset(df_stok, Kehabisan), aes(x = Hari, y = Stok), color = "red", shape = 4, size = 3) +
  labs(
    title = "Pergerakan Stok Beras Selama 60 Hari",
    subtitle = "Titik biru = pemesanan ulang, Titik merah X = stok habis",
    x = "Hari",
    y = "Jumlah Stok (karung)"
  ) +
  theme_minimal()