We model firms as having two characteristics:
An AI tool with effectiveness \(\omega \in (0, 1)\) reduces labor demand to:
\[ \text{Effective headcount} = n(1 - \omega v) \]
The value (cost savings) for the firm is:
\[ \text{Value} = c \cdot n \cdot \omega v \]
The cost (price paid) to the vendor is:
\[ \text{Price paid} = p \cdot n \cdot (1 - \omega v) \]
The vendor also incurs a support cost:
\[ \text{Cost to vendor} = w \cdot n \cdot (1 - \omega v) \]
A firm adopts the AI tool if:
\[ c n \omega v > p n (1 - \omega v) \quad \Rightarrow \quad v > \frac{1}{\omega} \frac{p}{c + p} \]
Let \(v^* = \frac{1}{\omega} \frac{p}{c + p}\) denote the threshold above which firms adopt.
Given \((n, v)\), if \(v > v^*\), the total payment by the firm is:
\[ \text{Payment}(n,v) = p \cdot n \cdot (1 - \omega v) \]
The vendor’s profit from an \((n,v)\) adopter firm is \((p-w) n (1-\omega v)\). Total profit across all adopter firms (\(v > v^\ast)\) of given size \(n\) is \(\int_{v^\ast}^{1} (p-w) n (1-\omega v) dv\) = \((p-w) n \int_{v^\ast}^{1} (v - \omega \frac{v^2}{2}) \vert_{v^\ast}^{1} dv\) = \((p-w) n \left(1 - \frac{\omega}{2} - v^* + \frac{\omega}{2}(v^*)^2 \right)\).
Further, looking at this across all firm sizes involves a second integral over \(n\); that integral resolves differently depending on whether \(n\) follows a uniform or Beta distribution. For the Beta distribution, the integral \(\int_{Beta(n)} n dn\) resolves to the expected value of the Beta distribution, i.e., \(\frac{\alpha}{\alpha+\beta}\).
Firms vary by size \(n \in [0,1] \sim ext{Beta}(\alpha, \beta)\) and ability to benefit \(v \in [0,1]\). The AI tool reduces workforce to \(n(1 - \omega v)\). Vendor charges \(p\) per supported seat and incurs cost \(w\).
# omega <- 0.15
c <- 1000
w <- 0.3
alpha <- 5
beta <- 5
v_star <- function(p, omega, c) p / (omega*(c + p))
v_integral <- function(p, omega, c) {
v_cut <- v_star(p, omega, c)
1 - omega/2 - v_cut + (omega/2) * v_cut^2
}
profit_beta_cost <- function(p, omega, c, w, alpha, beta) {
E_n <- alpha / (alpha + beta)
E_n * (p - w) * v_integral(p, omega, c)
}
p_vals <- seq(1, 1000, by = 1)
profits <- function(omega) {sapply(p_vals, profit_beta_cost, omega = omega, c = c, w = w, alpha = alpha, beta = beta)}
# Define your vector of omega values
omega_values <- c(0.4, 0.6, 0.8) # Modify these values as needed
# Create data for all omega values
price_profit_data <- do.call(rbind, lapply(omega_values, function(omega) {
data.frame(
p = p_vals,
profit = profits(omega),
omega = omega
)
}))
# Create the plot with multiple curves
ggplot(price_profit_data, aes(x = p, y = profit, color = factor(omega))) +
geom_line(size = 1) +
labs(
title = "Profit vs Price (Beta Distribution) for Different Omega Values",
x = "Price (p)",
y = "Profit",
color = "Omega"
) +
theme_minimal() +
scale_color_brewer(type = "qual", palette = "Set1")
## 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.
# Lets compute p* given an omega value, and other parameters
opt_result <- function(omega) {
optimize(function(p) -profit_beta_cost(p, omega, c, w, alpha, beta),
interval = c(1, 5000), maximum = FALSE)
}
p_star <- function(omega) {opt_result(omega)$minimum}
profit_star <- function(omega) {-opt_result(omega)$objective}
v_cut_star <- function(omega) {v_star(p_star(omega), omega, c)}
# cat("Optimal p:", round(p_star, 2), "\n")
# cat("Optimal profit:", round(profit_star, 2), "\n")
# cat("Cutoff v*:", round(v_cut_star, 4), "\n")
v_vals <- seq(from = 1, to = 0, by = -0.01) # should be to v_cut_star(omega) - see filter below
v_vals <- rev(v_vals)
n_vals <- seq(0.1, 1, by=0.01)
param_grid <- expand.grid(n = n_vals, v = v_vals)
# payment_grid$payment <- with(payment_grid, p_star * n * (1 - omega * v))
payment_grid <- function(omega) {
param_grid %>% filter(v >= v_cut_star(omega)) %>%
mutate(nv = n*v, payment = p_star(omega) * n * (1 - omega * v)) %>% arrange(nv)
}
kable(payment_grid[sample(nrow(payment_grid), 10), ] %>% arrange(nv), digits = 4, caption = "Sample Buyer Payments (n, v > v*)")
# ggplot(payment_grid) + geom_point(aes(x=nv, y=payment))
# Plot
ggplot(payment_grid, aes(x = nv, y = payment)) +
geom_line(color = "blue", size = 1) +
geom_point(color = "darkblue") +
labs(title = "Average Payment vs. nv",
x = "n × v (nv)",
y = "Average Payment") +
theme_minimal()
# ggplot(payment_grid) + geom_point(aes(x=nv, y=payment))
# Compute average payment by nv
payment_summary <- payment_grid %>% mutate(nv = round(nv,1)) %>%
group_by(nv) %>%
summarise(avg_payment = mean(payment, na.rm = TRUE)) %>%
arrange(nv)
# Plot
ggplot(payment_summary, aes(x = nv, y = avg_payment)) +
geom_line(color = "blue", size = 1) +
geom_point(color = "darkblue") +
labs(title = "Average Payment vs. nv",
x = "n × v (nv)",
y = "Average Payment") +
theme_minimal()
# Define omega values
omega_values <- seq(0.1, 0.9, 0.1)
# Create payment summaries for all omega values
payment_summary_all <- do.call(rbind, lapply(omega_values, function(omega) {
payment_summary <- payment_grid(omega) %>%
mutate(nv = round(nv, 1)) %>%
group_by(nv) %>%
summarise(avg_payment = mean(payment, na.rm = TRUE), .groups = 'drop') %>%
arrange(nv) %>%
mutate(omega = omega)
return(payment_summary)
}))
# Create the plot with multiple curves
ggplot(payment_summary_all, aes(x = nv, y = avg_payment, color = factor(omega))) +
geom_line(size = 1) +
geom_point() +
labs(
title = "Average Payment vs. nv for Different Omega Values",
x = "n × v (nv)",
y = "Average Payment",
color = "Omega"
) +
theme_minimal() +
scale_color_brewer(type = "qual", palette = "Set1")
# Define sequences for n and v
c <- 1000
w <- 0.3
alpha <- 12
beta <- 2
omegaValues <- seq(0.09,0.99,0.1)
nValues <- seq(0,1,0.01)
vValues <- seq(0,1,0.01)
# Create a data frame with all combinations of n and v
df <- expand.grid(omega = omegaValues, n = nValues, v = vValues)
# Define the payment function
payment <- function(p, omega, n, v) {
p * omega * n * (1 - omega*v)
}
value <- function(emp_cost, n, v) { # n employees --> n*(1-v) employees
emp_cost * n * v
}
# df <- df %>% filter()
# Compute nv and payment
df <- df %>%
mutate(
nv = n * v,
payment = payment(omega, n, v)
)
kable(df[sample(dim(df)[1] ,8), ], caption = "sample values in df")
ggplot(df, aes(x = nv, y = payment)) +
geom_point(aes(color = as.factor(n)), shape = 21, alpha = 0.7) +
facet_wrap(~ omega, ncol = 4, scales="free") +
# ggplot(df, aes(x = nv, y = payment, color = as.factor(round(n)))) +
# geom_point(alpha = 0.5, size = 0.7) +
labs(
title = "Scatterplot of Payment vs n × v",
x = "n × v",
y = "Payment",
shape = "Rounded v",
color = "Rounded n"
) +
theme_minimal()