---
title: "MASC Parameters and Reward Rate"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{MASC Parameters and Reward Rate}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(ggplot2)
library(dplyr)
library(tibble)
library(purrr)
library(patchwork)
library(broom)
library(masc)
```

Search Sensitivity and Reward Rate: The relationship between MASC parameters and different behavioral outcome measures.

Higher levels of sampling noise lead to lower reward rates, while higher values of threshold
change and the search sensitivity parameter lead to higher reward rates (note that if \alpha = 0, search
is random).


```{r}
# masc_attr_weights_sampling_noise.R - Creates Figure 8 reproduction from
# Gluth, S., Deakin, J., & Rieskamp, J. (2026). A theory of multiattribute search and choice. Psychological Review.

simulate_parameter_effects <- function(n_trials = 2000) {
  # Parameter ranges
  sigmas <- seq(0.1, 3, length.out = 5)
  deltas <- seq(0.01, 0.1, length.out = 5)
  alphas <- seq(0, 10, length.out = 5)

  # Generate fixed weights for consistency
  set.seed(2025)
  w <- rbeta(3, 3/4, 3/4)
  w <- w/sum(w)

  # 1. Effect of Sampling Noise (sigma)
  cat("Processing Sampling Noise (sigma)...\n")
  sigma_trial_data <- list()
  sigma_binned_data <- list()

  for(i in seq_along(sigmas)) {
    s <- sigmas[i]
    cat(sprintf("  Processing sigma = %.2f (%d/%d)\n", s, i, length(sigmas)))

    # Run model
    result <- rMASC(n = n_trials/10, sigma = s, w = w)

    # Extract trial data
    trial_data <- map_dfr(result$raw, function(trial) {
      tibble(
        sigma = s,
        correct = trial$correct,
        rt = trial$rt,
        reward_rate = as.numeric(trial$correct)/trial$rt
      )
    })

    sigma_trial_data[[i]] <- trial_data

    # Calculate binned data
    n_trials_actual <- nrow(trial_data)
    sigma_binned_data[[i]] <- tibble(
      sigma = s,
      mean_correct = mean(as.numeric(trial_data$correct)),
      mean_rt = mean(trial_data$rt),
      mean_reward_rate = mean(trial_data$reward_rate),
      se_correct = sd(as.numeric(trial_data$correct))/sqrt(n_trials_actual),
      se_rt = sd(trial_data$rt)/sqrt(n_trials_actual),
      se_reward_rate = sd(trial_data$reward_rate)/sqrt(n_trials_actual)
    )
  }

  # 2. Effect of Threshold Change (delta)
  cat("\nProcessing Threshold Change (delta)...\n")
  delta_trial_data <- list()
  delta_binned_data <- list()

  for(i in seq_along(deltas)) {
    d <- deltas[i]
    cat(sprintf("  Processing delta = %.2f (%d/%d)\n", d, i, length(deltas)))

    # Run model
    result <- rMASC(n = n_trials/10, delta = d, w = w)

    # Extract trial data
    trial_data <- map_dfr(result$raw, function(trial) {
      tibble(
        delta = d,
        correct = trial$correct,
        rt = trial$rt,
        reward_rate = as.numeric(trial$correct)/trial$rt
      )
    })

    delta_trial_data[[i]] <- trial_data

    # Calculate binned data
    n_trials_actual <- nrow(trial_data)
    delta_binned_data[[i]] <- tibble(
      delta = d,
      mean_correct = mean(as.numeric(trial_data$correct)),
      mean_rt = mean(trial_data$rt),
      mean_reward_rate = mean(trial_data$reward_rate),
      se_correct = sd(as.numeric(trial_data$correct))/sqrt(n_trials_actual),
      se_rt = sd(trial_data$rt)/sqrt(n_trials_actual),
      se_reward_rate = sd(trial_data$reward_rate)/sqrt(n_trials_actual)
    )
  }

  # 3. Effect of Search Sensitivity (alpha)
  cat("\nProcessing Search Sensitivity (alpha)...\n")
  alpha_trial_data <- list()
  alpha_binned_data <- list()

  for(i in seq_along(alphas)) {
    a <- alphas[i]
    cat(sprintf("  Processing alpha = %.2f (%d/%d)\n", a, i, length(alphas)))

    # Run model
    result <- rMASC(n = n_trials/10, alpha = a, w = w)

    # Extract trial data
    trial_data <- map_dfr(result$raw, function(trial) {
      tibble(
        alpha = a,
        correct = trial$correct,
        rt = trial$rt,
        reward_rate = as.numeric(trial$correct)/trial$rt
      )
    })

    alpha_trial_data[[i]] <- trial_data

    # Calculate binned data
    n_trials_actual <- nrow(trial_data)
    alpha_binned_data[[i]] <- tibble(
      alpha = a,
      mean_correct = mean(as.numeric(trial_data$correct)),
      mean_rt = mean(trial_data$rt),
      mean_reward_rate = mean(trial_data$reward_rate),
      se_correct = sd(as.numeric(trial_data$correct))/sqrt(n_trials_actual),
      se_rt = sd(trial_data$rt)/sqrt(n_trials_actual),
      se_reward_rate = sd(trial_data$reward_rate)/sqrt(n_trials_actual)
    )
  }

  # Combine data
  sigma_trial <- bind_rows(sigma_trial_data)
  sigma_binned <- bind_rows(sigma_binned_data)

  delta_trial <- bind_rows(delta_trial_data)
  delta_binned <- bind_rows(delta_binned_data)

  alpha_trial <- bind_rows(alpha_trial_data)
  alpha_binned <- bind_rows(alpha_binned_data)

  # Return all data
  list(
    sigma_trial = sigma_trial,
    sigma_binned = sigma_binned,
    delta_trial = delta_trial,
    delta_binned = delta_binned,
    alpha_trial = alpha_trial,
    alpha_binned = alpha_binned
  )
}

plot_parameter_effects <- function(results) {
  theme_param <- theme_classic() +
    theme(
      text = element_text(size = 12),
      plot.title = element_text(size = 14, face = "bold"),
      panel.grid.minor = element_blank(),
      strip.text = element_text(face = "bold")
    )

  # 1. For sampling noise
  # Linear model for binned data
  sigma_correct_lm <- lm(mean_correct ~ sigma, data = results$sigma_binned)
  sigma_rt_lm <- lm(mean_rt ~ sigma, data = results$sigma_binned)
  sigma_rr_lm <- lm(mean_reward_rate ~ sigma, data = results$sigma_binned)

  # Create plots
  sigma_correct_plot <- ggplot() +
    geom_jitter(data = results$sigma_trial,
                aes(x = sigma, y = as.numeric(correct)),
                alpha = 0.01, width = 0.05, height = 0) +
    geom_point(data = results$sigma_binned,
               aes(x = sigma, y = mean_correct),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$sigma_binned,
                  aes(x = sigma,
                      ymin = mean_correct - se_correct,
                      ymax = mean_correct + se_correct),
                  width = 0.1, color = "darkgreen") +
    geom_smooth(data = results$sigma_binned,
                aes(x = sigma, y = mean_correct),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Sampling Noise σs",
         y = "Choice Consistency",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(sigma_correct_lm)[2],
                            summary(sigma_correct_lm)$coefficients[2,4])) +
    theme_param

  sigma_rt_plot <- ggplot() +
    geom_jitter(data = results$sigma_trial,
                aes(x = sigma, y = rt),
                alpha = 0.01, width = 0.05, height = 0) +
    geom_point(data = results$sigma_binned,
               aes(x = sigma, y = mean_rt),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$sigma_binned,
                  aes(x = sigma,
                      ymin = mean_rt - se_rt,
                      ymax = mean_rt + se_rt),
                  width = 0.1, color = "darkgreen") +
    geom_smooth(data = results$sigma_binned,
                aes(x = sigma, y = mean_rt),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Sampling Noise σs",
         y = "Number of Fixations",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(sigma_rt_lm)[2],
                            summary(sigma_rt_lm)$coefficients[2,4])) +
    theme_param

  sigma_rr_plot <- ggplot() +
    geom_jitter(data = results$sigma_trial,
                aes(x = sigma, y = reward_rate),
                alpha = 0.01, width = 0.05, height = 0) +
    geom_point(data = results$sigma_binned,
               aes(x = sigma, y = mean_reward_rate),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$sigma_binned,
                  aes(x = sigma,
                      ymin = mean_reward_rate - se_reward_rate,
                      ymax = mean_reward_rate + se_reward_rate),
                  width = 0.1, color = "darkgreen") +
    geom_smooth(data = results$sigma_binned,
                aes(x = sigma, y = mean_reward_rate),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Sampling Noise σs",
         y = "Reward Rate",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(sigma_rr_lm)[2],
                            summary(sigma_rr_lm)$coefficients[2,4])) +
    theme_param

  # 2. For threshold change (delta)
  # Linear model for binned data
  delta_correct_lm <- lm(mean_correct ~ delta, data = results$delta_binned)
  delta_rt_lm <- lm(mean_rt ~ delta, data = results$delta_binned)
  delta_rr_lm <- lm(mean_reward_rate ~ delta, data = results$delta_binned)

  # Create plots
  delta_correct_plot <- ggplot() +
    geom_jitter(data = results$delta_trial,
                aes(x = delta, y = as.numeric(correct)),
                alpha = 0.01, width = 0.001, height = 0) +
    geom_point(data = results$delta_binned,
               aes(x = delta, y = mean_correct),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$delta_binned,
                  aes(x = delta,
                      ymin = mean_correct - se_correct,
                      ymax = mean_correct + se_correct),
                  width = 0.002, color = "darkgreen") +
    geom_smooth(data = results$delta_binned,
                aes(x = delta, y = mean_correct),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Threshold Change θΔ",
         y = "Choice Consistency",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(delta_correct_lm)[2],
                            summary(delta_correct_lm)$coefficients[2,4])) +
    theme_param

  delta_rt_plot <- ggplot() +
    geom_jitter(data = results$delta_trial,
                aes(x = delta, y = rt),
                alpha = 0.01, width = 0.001, height = 0) +
    geom_point(data = results$delta_binned,
               aes(x = delta, y = mean_rt),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$delta_binned,
                  aes(x = delta,
                      ymin = mean_rt - se_rt,
                      ymax = mean_rt + se_rt),
                  width = 0.002, color = "darkgreen") +
    geom_smooth(data = results$delta_binned,
                aes(x = delta, y = mean_rt),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Threshold Change θΔ",
         y = "Number of Fixations",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(delta_rt_lm)[2],
                            summary(delta_rt_lm)$coefficients[2,4])) +
    theme_param

  delta_rr_plot <- ggplot() +
    geom_jitter(data = results$delta_trial,
                aes(x = delta, y = reward_rate),
                alpha = 0.01, width = 0.001, height = 0) +
    geom_point(data = results$delta_binned,
               aes(x = delta, y = mean_reward_rate),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$delta_binned,
                  aes(x = delta,
                      ymin = mean_reward_rate - se_reward_rate,
                      ymax = mean_reward_rate + se_reward_rate),
                  width = 0.002, color = "darkgreen") +
    geom_smooth(data = results$delta_binned,
                aes(x = delta, y = mean_reward_rate),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Threshold Change θΔ",
         y = "Reward Rate",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(delta_rr_lm)[2],
                            summary(delta_rr_lm)$coefficients[2,4])) +
    theme_param

  # 3. For search sensitivity (alpha)
  # Linear model for binned data
  alpha_correct_lm <- lm(mean_correct ~ alpha, data = results$alpha_binned)
  alpha_rt_lm <- lm(mean_rt ~ alpha, data = results$alpha_binned)
  alpha_rr_lm <- lm(mean_reward_rate ~ alpha, data = results$alpha_binned)

  # Create plots
  alpha_correct_plot <- ggplot() +
    geom_jitter(data = results$alpha_trial,
                aes(x = alpha, y = as.numeric(correct)),
                alpha = 0.01, width = 0.1, height = 0) +
    geom_point(data = results$alpha_binned,
               aes(x = alpha, y = mean_correct),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$alpha_binned,
                  aes(x = alpha,
                      ymin = mean_correct - se_correct,
                      ymax = mean_correct + se_correct),
                  width = 0.2, color = "darkgreen") +
    geom_smooth(data = results$alpha_binned,
                aes(x = alpha, y = mean_correct),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Search Sensitivity α",
         y = "Choice Consistency",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(alpha_correct_lm)[2],
                            summary(alpha_correct_lm)$coefficients[2,4])) +
    theme_param

  alpha_rt_plot <- ggplot() +
    geom_jitter(data = results$alpha_trial,
                aes(x = alpha, y = rt),
                alpha = 0.01, width = 0.1, height = 0) +
    geom_point(data = results$alpha_binned,
               aes(x = alpha, y = mean_rt),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$alpha_binned,
                  aes(x = alpha,
                      ymin = mean_rt - se_rt,
                      ymax = mean_rt + se_rt),
                  width = 0.2, color = "darkgreen") +
    geom_smooth(data = results$alpha_binned,
                aes(x = alpha, y = mean_rt),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Search Sensitivity α",
         y = "Number of Fixations",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(alpha_rt_lm)[2],
                            summary(alpha_rt_lm)$coefficients[2,4])) +
    theme_param

  alpha_rr_plot <- ggplot() +
    geom_jitter(data = results$alpha_trial,
                aes(x = alpha, y = reward_rate),
                alpha = 0.01, width = 0.1, height = 0) +
    geom_point(data = results$alpha_binned,
               aes(x = alpha, y = mean_reward_rate),
               size = 3, color = "darkgreen") +
    geom_errorbar(data = results$alpha_binned,
                  aes(x = alpha,
                      ymin = mean_reward_rate - se_reward_rate,
                      ymax = mean_reward_rate + se_reward_rate),
                  width = 0.2, color = "darkgreen") +
    geom_smooth(data = results$alpha_binned,
                aes(x = alpha, y = mean_reward_rate),
                method = "lm", formula = y ~ x, color = "green", se = FALSE) +
    labs(x = "Search Sensitivity α",
         y = "Reward Rate",
         subtitle = sprintf("β = %.3f, p = %.3e",
                            coef(alpha_rr_lm)[2],
                            summary(alpha_rr_lm)$coefficients[2,4])) +
    theme_param

  # Combine plots
  combined_plot <- wrap_plots(
    sigma_correct_plot, sigma_rt_plot, sigma_rr_plot,
    delta_correct_plot, delta_rt_plot, delta_rr_plot,
    alpha_correct_plot, alpha_rt_plot, alpha_rr_plot,
    ncol = 3
  ) +
    plot_annotation(
      title = "MASC Model Parameter Effects",
      theme = theme(plot.title = element_text(size = 16, face = "bold"))
    )

  # Print summary statistics
  cat("\nParameter Effects Summary:\n\n")

  cat("\nSampling Noise (σs):\n")
  cat("  Choice Consistency: β =", round(coef(sigma_correct_lm)[2], 3),
      ", p =", format.pval(summary(sigma_correct_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(sigma_correct_lm)$r.squared, 3), "\n")
  cat("  Number of Fixations: β =", round(coef(sigma_rt_lm)[2], 3),
      ", p =", format.pval(summary(sigma_rt_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(sigma_rt_lm)$r.squared, 3), "\n")
  cat("  Reward Rate: β =", round(coef(sigma_rr_lm)[2], 3),
      ", p =", format.pval(summary(sigma_rr_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(sigma_rr_lm)$r.squared, 3), "\n")

  cat("\nThreshold Change (θΔ):\n")
  cat("  Choice Consistency: β =", round(coef(delta_correct_lm)[2], 3),
      ", p =", format.pval(summary(delta_correct_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(delta_correct_lm)$r.squared, 3), "\n")
  cat("  Number of Fixations: β =", round(coef(delta_rt_lm)[2], 3),
      ", p =", format.pval(summary(delta_rt_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(delta_rt_lm)$r.squared, 3), "\n")
  cat("  Reward Rate: β =", round(coef(delta_rr_lm)[2], 3),
      ", p =", format.pval(summary(delta_rr_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(delta_rr_lm)$r.squared, 3), "\n")

  cat("\nSearch Sensitivity (α):\n")
  cat("  Choice Consistency: β =", round(coef(alpha_correct_lm)[2], 3),
      ", p =", format.pval(summary(alpha_correct_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(alpha_correct_lm)$r.squared, 3), "\n")
  cat("  Number of Fixations: β =", round(coef(alpha_rt_lm)[2], 3),
      ", p =", format.pval(summary(alpha_rt_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(alpha_rt_lm)$r.squared, 3), "\n")
  cat("  Reward Rate: β =", round(coef(alpha_rr_lm)[2], 3),
      ", p =", format.pval(summary(alpha_rr_lm)$coefficients[2,4], digits = 3),
      ", R² =", round(summary(alpha_rr_lm)$r.squared, 3), "\n")

  return(combined_plot)
}
```

```{r}
# Run simulation (this will take some time)
set.seed(2025)
n_trials <- 300
results <- simulate_parameter_effects(n_trials)
```

```{r, fig.width=14, fig.height=10, out.width="100%"}
# Plot results
plots <- plot_parameter_effects(results)

# Display plots
print(plots)
```

