4 Counterfactual Simulation

4.1 Welfare Calculation

Using our demand estimates, we evaluate the impact that the monitoring program has on consumer welfare and on firm profits in the status quo. To do this, we simulate a counterfactual scenario in which monitoring is not available, and compare it to the status quo baseline with monitoring.

  1. For each driver \(i\), simulate random coefficients (private risk) \(L \in \mathbb{N}^{+}\) times
  2. For each draw \(l \in \{ 1, ..., L \}\), calculate ex-ante utility directly and the corresponding certainty equivalent. First-period choice probabilities are also calculated, which gives us the monitoring share. Expected cost of the first semester can be calculated directly. But we also need to form an expectation of the second-period cost (and prices) in order to calculate total surplus (and profit):
  3. Simulate \(K \in \mathbb{N}^{+}\) draws of first-period claim occurrence and monitoring score based on private risk . Each draw pins down the renewal price change that driver \(i\) would face in the second period. All other prices remain constant. For each first-period choice \(d\), we can then calculate the second period choice probability and the corresponding expected cost
  • To do this, we need to generate choice sequence. First we calculate choice probability in \(t = 0\) for each draw of \(\lambda\)
i d t Prior Price \(\lambda_{1}\) \(\lambda_{L}\) \(\Pr_{1}\) \(\Pr_{L}\)
1 1 0 3 100 0.04 0.02 0.25 0.20
1 2 0 1 110 0.05 0.03 0.05 0.10
1 3 0 2 90 0.05 0.03 0.35 0.40
1 4 0 2 95 0.05 0.03 0.35 0.30
2 1 0 1 130 0.02 0.01 0.15 0.20
# Number of Draws
L <- 100
K <- 50

## df for t = 0, 1
df_t0 <- df %>% 
  dplyr::filter(t == 0)

df_t1 <- df %>% 
  dplyr::filter(t == 1)

## Simulate Private Risk Lambda
sim_lambda <- gen_lambda(df, cost_par, L) %>% 
  dplyr::select(starts_with("lambda"))

sim_lambda_expand <- df %>% 
  dplyr::bind_cols(sim_lambda)

for(k in 1:(K - 1)){
  sim_lambda_expand <- dplyr::bind_cols(sim_lambda_expand, sim_lambda)
}

column_order_lambda <- sim_lambda_expand %>% 
  dplyr::select(starts_with("lambda")) %>% 
  names() %>% 
  sort()

sim_lambda_expand <- sim_lambda_expand %>% 
  dplyr::select("i", "d", "t", "m", "f",
                "x_1", "x_2", "x_3", "x_4", 
                "price", "prior_firm", "choice",
                "claims", "score", "R_s", "R_C",
                all_of(column_order_lambda))

colnames(sim_lambda_expand) <- c("i", "d", "t", "m", "f",
                                 "x_1", "x_2", "x_3", "x_4", 
                                 "price", "prior_firm", "choice",
                                 "claims", "score", "R_s", "R_C",
                                 paste(rep("lambda", L * K), 
                                       rep(1:L, K, each = K), 
                                       rep(1:K, L),
                                       sep = "_"))


## Lambda with L columns
sim_lambda_t0 <- df %>% 
  dplyr::bind_cols(sim_lambda) %>% 
  dplyr::filter(t == 0)
sim_lambda_t1 <- df %>% 
  dplyr::bind_cols(sim_lambda) %>% 
  dplyr::filter(t == 1)

## Lambda with L * K columns

sim_lambda_expand_t0 <- sim_lambda_expand %>% 
  dplyr::filter(t == 0)
sim_lambda_expand_t1 <- sim_lambda_expand %>% 
  dplyr::filter(t == 1)

## Calculate Choice Probability in t = 0
sim_choice_probability_t0 <- function(df, theta, cost_par, lambda, Col){
 # Parameters
  eta_f <- theta[1:4]
  xi <- theta[5:6]
  alpha_m0 <- theta[7:9]
  alpha_m1 <- theta[10:13]
  beta <- theta[14]
  risk_aversion <- theta[15]
  
  # Cost Parameters
  theta_score <- cost_par[8:11]
  sigma_score <- cost_par[12]
  l0 <- cost_par[13]
  a_l <- cost_par[14]
  
  # Price
  price <- df$price * matrix(rep(1, dim(df)[1] * Col), nrow = dim(df)[1])
  colnames(price) <- c(paste("price", 1:Col, sep = "_"))
  
  price <- data.frame(price) %>% 
    tibble::as_tibble()  
  
  # Generate Demand Friction
  demand_friction <- lambda %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(ifelse(f == prior_firm, 
                                 0,  
                                 eta_f[1] + eta_f[2]*x_1 + eta_f[3]*x_2 + eta_f[4]*x_3) 
                          + ifelse(d == 1 & t == 0, 
                                   xi[1] + xi[2]*log(.), 
                                   0))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "demand_friction"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("demand_friction"))
  
  # Generate E_score
  E_score <- lambda %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(ifelse(t == 0 & m == 1,
                                 exp(theta_score[1] + theta_score[2]*log(.)
                                     + theta_score[3]*x_1 + theta_score[4]*x_2
                                     + sigma_score^2 / 2),
                                 0))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_score"), 
                       starts_with("lambda"))
  
  # Generate E_oop
  E_oop <- lambda %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(.*exp(-.)*(l0^(a_l)/(a_l - 1))*policy_limit^(-a_l + 1))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_oop"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("E_oop"))
  
  # Generate E_oop_sq
  E_oop_sq <- lambda %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(.*exp(-.)*((2 * l0^(a_l)) / ((a_l - 1) * (a_l - 1))) * policy_limit^(-a_l + 2))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_oop_sq"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("E_oop_sq"))

  # Generate E_R_s
  E_R_s <- E_score %>% 
    dplyr::mutate_at(vars(starts_with("E_score")),
                     funs(ifelse(t == 0 & m == 1,
                                 (alpha_m1[1] + alpha_m1[2]*x_1 + alpha_m1[3]*x_2 + alpha_m1[4]*.) / beta,
                                 (alpha_m0[1] + alpha_m0[2]*x_1 + alpha_m0[3]*x_2) / beta))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "E_score", "E_R_s"), 
                       starts_with("E_score")) %>% 
    dplyr::select(matches("E_R_s"))

  # Generate E_R_s_sq
  E_R_s_sq <- E_score %>% 
    dplyr::mutate_at(vars(starts_with("E_score")),
                     funs(ifelse(t == 0 & m == 1,
                                 (alpha_m1[1] + alpha_m1[2]*x_1 + alpha_m1[3]*x_2 + alpha_m1[4]*.) / beta^2,
                                 (alpha_m0[1] + alpha_m0[2]*x_1 + alpha_m0[3]*x_2) / beta^2))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "E_score", "E_R_s_sq"), 
                       starts_with("E_score")) %>% 
    dplyr::select(matches("E_R_s_sq"))  
  
  # Generate E_R_C
  E_R_C <- lambda %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(0.98 * exp(-.) + 1.2 * (1 - exp(-.)))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_R_C"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("E_R_C"))

  # Generate E_R_C_sq
  E_R_C_sq <- lambda %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(0.98^2 * exp(-.) + 1.2^2 * (1 - exp(-.)))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_R_C_sq"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("E_R_C_sq"))
  
  # Calculate E_h
  E_h <- - price - demand_friction - E_oop - E_R_s * E_R_C * price
  E_h <- E_h %>% 
    dplyr::rename_with(\(x) str_replace(x, "price", "E_h"), 
                       starts_with("price"))
  
  # Calculate E_h_sq
  E_h_sq <- price^2 + demand_friction^2 + E_oop_sq + E_R_s_sq*E_R_C_sq*price^2
  + 2*price*demand_friction + 2*price*E_oop + 2*price*(E_R_s*E_R_C*price)
  + 2*demand_friction*E_oop + 2*demand_friction*(E_R_s*E_R_C*price)
  + 2*E_oop*(E_R_s*E_R_C*price)
    
  E_h_sq <- E_h_sq %>% 
    dplyr::rename_with(\(x) str_replace(x, "price", "E_h_sq"), 
                       starts_with("price"))
  
  # Calculate v
  v <- (E_h - (risk_aversion / 2) * E_h_sq) %>% 
    dplyr::rename_with(\(x) str_replace(x, "E_h", "v"), 
                       starts_with("E_h"))
  
  ## Calculate Choice Probability
  output <- df %>% 
    dplyr::bind_cols(v) %>% 
    dplyr::group_by(i, t) %>% 
    dplyr::mutate_at(vars(starts_with("v")),
                     funs(exp(.) / sum(exp(.)))) %>% 
    dplyr::ungroup() %>% 
    dplyr::rename_with(\(x) str_replace(x, "v", "choice_probability"), 
                       starts_with("v"))
  
  return(output)
}

sim_choice_probability_t0(df_t0, theta, cost_par, sim_lambda_t0, L)
  • Next, we simulate \(K \in \mathbb{N}^{+}\) draws of first-period claim occurrence and monitoring score based on private risk for each \(\lambda\) (thus we simulate \(L \times K\) claims and monitoiring score in total)
i d t \(\lambda_{1}\) \(\lambda_{L}\) \(Claim_{11}\) \(Claim_{LK}\) \(Score_{11}\) \(Score_{LK}\)
1 1 0 0.05 0.03 0 1 -3.0 -1.0
1 2 0 0.05 0.03 0 0 0.0 0.0
1 3 0 0.05 0.03 1 0 0.0 0.0
1 4 0 0.05 0.03 0 0 0.0 0.0
2 1 0 0.02 0.01 2 0 -2.5 -1.2
  • Based on each claim and monitoring score, renewal price multiplier \(R_{0}\) is calculated
i d t \(R_{C, 11}\) \(R_{C, LK}\) \(R_{s, 11}\) \(R_{s, LK}\) \(R_{0, 11}\) \(R_{0, LK}\)
1 1 0 0.98 1.20 0.99 0.95 0.97 1.15
1 2 0 0.98 0.98 1.02 0.98 1.00 0.96
1 3 0 1.20 0.98 1.02 0.98 1.22 0.96
1 4 0 0.98 0.98 1.02 0.98 1.00 0.96
2 1 0 1.20 0.98 0.87 0.90 1.07 0.88
sim_renewal_price_multiplier <- function(df, theta, cost_par, lambda, Col){
  ## Generate Claims
  lambda_mat <- lambda %>% 
    dplyr::select(starts_with("lambda")) %>% 
    as.matrix()
  
  claims <- matrix(rpois(dim(df)[1]*Col, lambda = lambda_mat), nrow = dim(df)[1])
  colnames(claims) <- paste("claims", 1:Col, sep = "_")
  
  claims <- data.frame(claims) %>% 
    tibble::as_tibble()  
  
  ## Generate Monitoring Score
  theta_score <- cost_par[8:11]
  sigma_score <- cost_par[12]

  mu_score <- lambda %>%
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(theta_score[1] + theta_score[2]*log(.)
                          + theta_score[3]*x_1 + theta_score[4]*x_2)) %>%
    dplyr::rename_with(\(x) str_replace(x, "lambda", "mu_score"),
                       starts_with("lambda")) %>%
    dplyr::select(starts_with("mu_score")) %>%
    as.matrix()
  
  score <- matrix(rlnorm(dim(df)[1]*Col, mu_score, sigma_score), nrow = dim(df)[1])
  colnames(score) <- paste("score", 1:Col, sep = "_")

  score <- data.frame(score) %>%
    tibble::as_tibble()
  
  ## Calculate Claim Surcharge R_C
  R_C <- claims %>% 
    dplyr::mutate_at(vars(starts_with("claims")),
                     funs(ifelse(. == 0, 0.98, 1.2))) %>%
    dplyr::rename_with(\(x) str_replace(x, "claims", "R_C"),
                       starts_with("claims"))

  ## Calculate Base R_s
  ### Note that, for simplicity, assume that R0 is deterministic conditional on s. 
  ### In reality, the spread of baseline R0 without monitoring may have subtle 
  ### nonlinear effects on consumer choice, which we assume away
  alpha_m0 <- theta[7:9]
  alpha_m1 <- theta[10:13]
  beta <- theta[14]
  
  R_s <- df %>% 
    dplyr::select(m, x_1, x_2) %>% 
    dplyr::bind_cols(score) %>% 
    dplyr::mutate_at(vars(starts_with("score")),
                     funs(ifelse(m == 0,
                                 (alpha_m0[1] + alpha_m0[2]*x_1 + alpha_m0[3]*x_2) / beta,
                                 (alpha_m1[1] + alpha_m1[2]*x_1 + alpha_m1[3]*x_2 + alpha_m1[4]*.) / beta))) %>%
    dplyr::rename_with(\(x) str_replace(x, "score", "R_s"),
                       starts_with("score")) %>% 
    dplyr::select(-c(m, x_1, x_2))
  
  # ## Calculate Base Renewal Price
  # price <- df$price * matrix(rep(1, dim(df)[1] * L * K), nrow = dim(df)[1])
  # colnames(price) <- c(paste("price", 1:(L * K), sep = "_"))
  # 
  # price <- data.frame(price) %>% 
  #   tibble::as_tibble()
  
  R_0 <- (R_C * R_s) %>%
    dplyr::rename_with(\(x) str_replace(x, "R_C", "R_0"),
                       starts_with("R_C"))
  
  output <- df %>% 
    dplyr::bind_cols(R_0) %>% 
    dplyr::select(c("i", "d", matches("R_0")))

  return(output)
}


sim_renewal_price_multiplier(df_t0, theta, cost_par, sim_lambda_expand_t0, L*K)
  • Renewal price itself is expanded to the following table:
i d t Prior Prior_Price \(R_{0, 11}\) \(R_{0, LK}\) \(Price_{11}\) \(Price_{LK}\)
1 1 1 1 100 0.97 1.15 97 115
1 2 1 1 90 0.97 1.15 87 105
1 3 1 1 95 0.97 1.15 92 105
1 1 1 2 110 1.00 0.96 110 105
1 2 1 2 90 1.00 0.96 90 85
1 3 1 2 95 1.00 0.96 95 90
1 1 1 3 110 1.22 0.96 130 105
1 2 1 3 90 1.22 0.96 110 85
1 3 1 3 95 1.22 0.96 115 90
1 1 1 4 110 1.00 0.96 110 105
1 2 1 4 90 1.00 0.96 90 85
1 3 1 4 95 1.00 0.96 95 90
2 1 1 1 130 1.07 0.88 137 105
prior_price <- df_t0 %>% 
  dplyr::select(i, d, price) %>% 
  dplyr::rename(prior_price = price)

renewal_price_multiplier <- sim_renewal_price_multiplier(df_t0, theta, cost_par, sim_lambda_expand_t0, L*K)

renewal_price <- expand.grid(i = 1:N, d = 1:3, t = 1, prior_choice = 1:4) %>% 
  tibble::as_tibble() %>% 
  dplyr::arrange(i, prior_choice) %>% 
  dplyr::mutate(key = ifelse(d == 1 & prior_choice == 1, 1, d + 1)) %>% 
  dplyr::left_join(prior_price, by = c("i", "key" = "d")) %>% 
  dplyr::left_join(renewal_price_multiplier, by = c("i", "prior_choice" = "d"))
  • Finally we calculate choice probability in \(t = 1\) based on each renewal price and \(\lambda\) in \(t = 1\). Note that \(\lambda\) in \(t = 1\) is different from that of \(t = 0\), and hence we need to draw again
i d t Prior \(Price_{11}\) \(Price_{LK}\) \(\lambda_{1}\) \(\lambda_{L}\) \(\Pr_{11}\) \(\Pr_{LK}\)
1 1 1 1 97 115 0.06 0.04 0.45 0.40
1 2 1 1 87 105 0.06 0.04 0.25 0.30
1 3 1 1 92 105 0.06 0.04 0.30 0.30
1 1 1 2 110 105 0.06 0.04 0.25 0.20
1 2 1 2 90 85 0.06 0.04 0.25 0.40
1 3 1 2 95 90 0.06 0.04 0.50 0.40
1 1 1 3 130 105 0.06 0.04 0.20 0.10
1 2 1 3 110 85 0.06 0.04 0.35 0.50
1 3 1 3 115 90 0.06 0.04 0.45 0.40
1 1 1 4 110 105 0.06 0.04 0.55 0.30
1 2 1 4 90 85 0.06 0.04 0.15 0.30
1 3 1 4 95 90 0.06 0.04 0.35 0.40
2 1 1 1 137 105 0.03 0.07 0.25 0.20
  • Thus, while choice probability in \(t = 0\) has \((4N \times L)\) matrix form, choice probability in \(t = 1\) is \((12N \times LK)\) matrix, due to \(K\) times draw of claims and monitoring score as well as path dependence of choice
## Calculate Certainty Equivalent for Each Draw
### theta_estを入れるのが正しいが挙動確認のためthetaを入れている
cal_certainty_equivalent <- function(df, theta, cost_par, R, lambda){
  ## Risk Aversion
  risk_aversion <- theta[15]
  
  ## Calculate CE
  ### We apply `cal_v` to obtain v
  output <- cal_v(df, theta, cost_par, R, lambda) %>% 
    dplyr::mutate_at(vars(starts_with("v")),
                     funs(1 / risk_aversion - sqrt((1 / risk_aversion^2) - 2*. / risk_aversion))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "v", "certatinty_equivalent"), 
                       starts_with("v"))

  return(output)
}



#tmp_price <- sim_renewal_price(df_t0, theta, cost_par, R, sim_lambda_expand)

# Calculate Choice Probability in t = 1
cal_v_modified <- function(df, theta, cost_par, R, lambda_t0, lambda_t1){
 # Parameters
  eta_f <- theta[1:4]
  xi <- theta[5:6]
  alpha_m0 <- theta[7:9]
  alpha_m1 <- theta[10:13]
  beta <- theta[14]
  risk_aversion <- theta[15]
  
  # Cost Parameters
  theta_score <- cost_par[8:11]
  sigma_score <- cost_par[12]
  l0 <- cost_par[13]
  a_l <- cost_par[14]
  
  # Price
  price <- sim_renewal_price(df, theta, cost_par, R, lambda_t0)
  
  # Generate Demand Friction
  demand_friction <- df %>% 
    dplyr::left_join(lambda_t1, by = c("i", "f")) %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(~ifelse(f == prior_firm, 
                                 0,  
                                 eta_f[1] + eta_f[2]*x_1 + eta_f[3]*x_2 + eta_f[4]*x_3) 
                          + ifelse(d == 1 & t == 0, 
                                   xi[1] + xi[2]*log(.), 
                                   0))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "demand_friction"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("demand_friction"))
  
  # Generate E_score
  E_score <- df %>% 
    dplyr::left_join(lambda_t1, by = c("i", "f")) %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(ifelse(t == 0 & m == 1,
                                 exp(theta_score[1] + theta_score[2]*log(.)
                                     + theta_score[3]*x_1 + theta_score[4]*x_2
                                     + sigma_score^2 / 2),
                                 0))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_score"), 
                       starts_with("lambda"))
  
  # Generate E_oop
  E_oop <- df %>% 
    dplyr::left_join(lambda_t1, by = c("i", "f")) %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(.*exp(-.)*(l0^(a_l)/(a_l - 1))*policy_limit^(-a_l + 1))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_oop"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("E_oop"))
  
  # Generate E_oop_sq
  E_oop_sq <- df %>% 
    dplyr::left_join(lambda_t1, by = c("i", "f")) %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(.*exp(-.)*((2 * l0^(a_l)) / ((a_l - 1) * (a_l - 1))) * policy_limit^(-a_l + 2))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_oop_sq"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("E_oop_sq"))

  # Generate E_R_s
  E_R_s <- E_score %>% 
    dplyr::mutate_at(vars(starts_with("E_score")),
                     funs(ifelse(t == 0 & m == 1,
                                 (alpha_m1[1] + alpha_m1[2]*x_1 + alpha_m1[3]*x_2 + alpha_m1[4]*.) / beta,
                                 (alpha_m0[1] + alpha_m0[2]*x_1 + alpha_m0[3]*x_2) / beta))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "E_score", "E_R_s"), 
                       starts_with("E_score")) %>% 
    dplyr::select(matches("E_R_s"))

  # Generate E_R_s_sq
  E_R_s_sq <- E_score %>% 
    dplyr::mutate_at(vars(starts_with("E_score")),
                     funs(ifelse(t == 0 & m == 1,
                                 (alpha_m1[1] + alpha_m1[2]*x_1 + alpha_m1[3]*x_2 + alpha_m1[4]*.) / beta^2,
                                 (alpha_m0[1] + alpha_m0[2]*x_1 + alpha_m0[3]*x_2) / beta^2))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "E_score", "E_R_s_sq"), 
                       starts_with("E_score")) %>% 
    dplyr::select(matches("E_R_s_sq"))  
  
  # Generate E_R_C
  E_R_C <- df %>% 
    dplyr::left_join(lambda_t1, by = c("i", "f")) %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(0.98 * exp(-.) + 1.2 * (1 - exp(-.)))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_R_C"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("E_R_C"))

  # Generate E_R_C_sq
  E_R_C_sq <- df %>% 
    dplyr::left_join(lambda_t1, by = c("i", "f")) %>% 
    dplyr::mutate_at(vars(starts_with("lambda")),
                     funs(0.98^2 * exp(-.) + 1.2^2 * (1 - exp(-.)))) %>% 
    dplyr::rename_with(\(x) str_replace(x, "lambda", "E_R_C_sq"), 
                       starts_with("lambda")) %>% 
    dplyr::select(matches("E_R_C_sq"))
  
  # Calculate E_h
  E_h <- - price - demand_friction - E_oop - E_R_s * E_R_C * price
  E_h <- E_h %>% 
    dplyr::rename_with(\(x) str_replace(x, "price", "E_h"), 
                       starts_with("price"))
  
  # Calculate E_h_sq
  E_h_sq <- price^2 + demand_friction^2 + E_oop_sq + E_R_s_sq*E_R_C_sq*price^2
  + 2*price*demand_friction + 2*price*E_oop + 2*price*(E_R_s*E_R_C*price)
  + 2*demand_friction*E_oop + 2*demand_friction*(E_R_s*E_R_C*price)
  + 2*E_oop*(E_R_s*E_R_C*price)
    
  E_h_sq <- E_h_sq %>% 
    dplyr::rename_with(\(x) str_replace(x, "price", "E_h_sq"), 
                       starts_with("price"))
  
  # Calculate v
  v <- (E_h - (risk_aversion / 2) * E_h_sq) %>% 
    dplyr::rename_with(\(x) str_replace(x, "E_h", "v"), 
                       starts_with("E_h"))
  
  output <- df %>% 
    dplyr::bind_cols(v)
  
  return(output)
}

cal_choice_probability_modified <- function(df, theta, cost_par, R, lambda_t0, lambda_t1){
  ## Calculate v
  v <- cal_v_modified(df, theta, cost_par, R, lambda_t0, lambda_t1)
  
  ## Calculate Choice Probability
  output <- v %>% 
    dplyr::group_by(i, t) %>% 
    dplyr::mutate_at(vars(starts_with("v")),
                     funs(exp(.) / sum(exp(.)))) %>% 
    dplyr::ungroup() %>% 
    dplyr::rename_with(\(x) str_replace(x, "v", "choice_probability"), 
                       starts_with("v")) 
}

tmp_choice_prob <- cal_choice_probability_modified(df_t0, theta, cost_par, R, sim_lambda_expand_t0, sim_lambda_expand_t1)