---
title: "Loss Functions"
author: "Your Name"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Loss Functions}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
library(TKApprox)
```

## Introduction

TKApprox supports multiple Bayesian loss functions for parameter estimation. This vignette explains each loss function, its properties, and when to use it.

## Squared Error Loss (SEL)

Squared Error Loss is the most common loss function, leading to the posterior mean as the Bayes estimator.

**Loss function:** $L(\theta, \hat{\theta}) = (\theta - \hat{\theta})^2$

**Bayes estimator:** $\hat{\theta} = E[\theta | x]$ (posterior mean)

**Properties:**
- Symmetric: overestimation and underestimation are penalized equally
- Unbiased under regularity conditions
- Most commonly used loss function

```{r}
# Define exponential distribution
pdf_exp <- function(x, param) dexp(x, rate = param)
cdf_exp <- function(x, param) pexp(x, rate = param)

prior_spec <- list(rate = list(family = "gamma", hyperparameters = list(shape = 2, rate = 1)))

set.seed(123)
data <- rexp(20, rate = 1.5)

# Fit with SEL (default)
fit_sel <- tk_fit(
  data = data,
  censoring_scheme = "complete",
  pdf = pdf_exp,
  cdf = cdf_exp,
  prior_spec = prior_spec,
  initial_values = c(rate = 1),
  loss_function = "sel"
)

coef(fit_sel)
```

## LINEX Loss

LINEX (Linear-Exponential) Loss is an asymmetric loss function useful when overestimation and underestimation have different consequences.

**Loss function:** $L(\theta, \hat{\theta}) = [\exp(c(\hat{\theta} - \theta)) - c(\hat{\theta} - \theta) - 1]$

**Bayes estimator:** $\hat{\theta} = -\frac{1}{c} \log E[\exp(-c\theta) | x]$

**Properties:**
- Asymmetric: $c > 0$ penalizes overestimation more, $c < 0$ penalizes underestimation more
- Approaches SEL as $c \to 0$
- Useful in reliability and risk assessment

```{r}
# Fit with LINEX loss (c = 0.5, penalizes overestimation)
fit_linex_pos <- tk_fit(
  data = data,
  censoring_scheme = "complete",
  pdf = pdf_exp,
  cdf = cdf_exp,
  prior_spec = prior_spec,
  initial_values = c(rate = 1),
  loss_function = "linex",
  loss_params = list(c = 0.5)
)

# Fit with LINEX loss (c = -0.5, penalizes underestimation)
fit_linex_neg <- tk_fit(
  data = data,
  censoring_scheme = "complete",
  pdf = pdf_exp,
  cdf = cdf_exp,
  prior_spec = prior_spec,
  initial_values = c(rate = 1),
  loss_function = "linex",
  loss_params = list(c = -0.5)
)

# Compare estimates
data.frame(
  SEL = coef(fit_sel),
  LINEX_c_0.5 = coef(fit_linex_pos),
  LINEX_c_neg0.5 = coef(fit_linex_neg)
)
```

### LINEX Sensitivity Analysis

```{r}
# Examine sensitivity to LINEX parameter c
c_values <- c(-2, -1, -0.5, -0.1, 0.1, 0.5, 1, 2)
linex_estimates <- sapply(c_values, function(c) {
  fit <- tk_fit(
    data = data,
    censoring_scheme = "complete",
    pdf = pdf_exp,
    cdf = cdf_exp,
    prior_spec = prior_spec,
    initial_values = c(rate = 1),
    loss_function = "linex",
    loss_params = list(c = c)
  )
  coef(fit)
})

plot(c_values, linex_estimates, type = "b", pch = 19,
     xlab = "LINEX parameter c", ylab = "Estimate",
     main = "LINEX Estimates vs c")
abline(h = coef(fit_sel), col = "red", lty = 2)
legend("topright", legend = c("LINEX", "SEL"), col = c("black", "red"),
       pch = c(19, NA), lty = c(1, 2))
```

## General Entropy Loss (GEL)

General Entropy Loss is another asymmetric loss function useful for scale parameters.

**Loss function:** $L(\theta, \hat{\theta}) = (\hat{\theta}/\theta)^q / q - \log(\hat{\theta}/\theta) - 1/q$

**Bayes estimator:** $\hat{\theta} = [E(\theta^{-q} | x)]^{-1/q}$

**Properties:**
- Asymmetric: $q > 0$ penalizes overestimation, $q < 0$ penalizes underestimation
- Scale-invariant
- Useful for positive parameters (rates, scales)

```{r}
# Fit with GEL (q = 0.5)
fit_gel_pos <- tk_fit(
  data = data,
  censoring_scheme = "complete",
  pdf = pdf_exp,
  cdf = cdf_exp,
  prior_spec = prior_spec,
  initial_values = c(rate = 1),
  loss_function = "gel",
  loss_params = list(q = 0.5)
)

# Fit with GEL (q = -0.5)
fit_gel_neg <- tk_fit(
  data = data,
  censoring_scheme = "complete",
  pdf = pdf_exp,
  cdf = cdf_exp,
  prior_spec = prior_spec,
  initial_values = c(rate = 1),
  loss_function = "gel",
  loss_params = list(q = -0.5)
)

# Compare estimates
data.frame(
  SEL = coef(fit_sel),
  GEL_q_0.5 = coef(fit_gel_pos),
  GEL_q_neg0.5 = coef(fit_gel_neg)
)
```

## Precautionary Loss

Precautionary Loss is useful when we want to be conservative in estimation.

**Loss function:** $L(\theta, \hat{\theta}) = \hat{\theta}^2/\theta - 2\hat{\theta} + \theta$

**Bayes estimator:** $\hat{\theta} = \sqrt{E(\theta^2 | x)}$

**Properties:**
- Conservative: tends to produce larger estimates
- Useful for safety-critical applications
- Only appropriate for positive parameters

```{r}
# Fit with precautionary loss
fit_precautionary <- tk_fit(
  data = data,
  censoring_scheme = "complete",
  pdf = pdf_exp,
  cdf = cdf_exp,
  prior_spec = prior_spec,
  initial_values = c(rate = 1),
  loss_function = "precautionary"
)

# Compare with SEL
data.frame(
  SEL = coef(fit_sel),
  Precautionary = coef(fit_precautionary)
)
```

## Weighted Squared Error Loss

Weighted SEL uses inverse-variance weighting, useful when parameters have different scales.

**Loss function:** $L(\theta, \hat{\theta}) = (\theta - \hat{\theta})^2 / \theta^2$

**Bayes estimator:** $\hat{\theta} = 1 / E(\theta^{-1} | x)$

**Properties:**
- Scale-invariant
- Useful for parameters with large variability
- Emphasizes relative error

```{r}
# Fit with weighted SEL
fit_weighted <- tk_fit(
  data = data,
  censoring_scheme = "complete",
  pdf = pdf_exp,
  cdf = cdf_exp,
  prior_spec = prior_spec,
  initial_values = c(rate = 1),
  loss_function = "weighted-sel"
)

# Compare with SEL
data.frame(
  SEL = coef(fit_sel),
  Weighted_SEL = coef(fit_weighted)
)
```

## Custom Loss Functions

You can also specify custom loss functions by providing the g(θ) function directly.

```{r}
# Example: Estimate the median of the posterior
# For exponential distribution, median = log(2)/rate
# We want to estimate log(rate) instead of rate directly
custom_g <- function(param) log(param[1])

fit_custom <- tk_fit(
  data = data,
  censoring_scheme = "complete",
  pdf = pdf_exp,
  cdf = cdf_exp,
  prior_spec = prior_spec,
  initial_values = c(rate = 1),
  loss_function = "custom",
  custom_g = custom_g
)

# The estimate is E[log(rate) | x]
# Transform back to rate scale
rate_estimate <- exp(coef(fit_custom))

data.frame(
  SEL_rate = coef(fit_sel),
  Custom_log_rate = rate_estimate
)
```

## Comparing All Loss Functions

```{r}
# Fit with all loss functions
fit_sel <- tk_fit(data, "complete", pdf_exp, cdf_exp, prior_spec,
                  initial_values = c(rate = 1), loss_function = "sel")

fit_linex <- tk_fit(data, "complete", pdf_exp, cdf_exp, prior_spec,
                    initial_values = c(rate = 1), loss_function = "linex", loss_params = list(c = 0.5))

fit_gel <- tk_fit(data, "complete", pdf_exp, cdf_exp, prior_spec,
                  initial_values = c(rate = 1), loss_function = "gel", loss_params = list(q = 0.5))

fit_precautionary <- tk_fit(data, "complete", pdf_exp, cdf_exp, prior_spec,
                            initial_values = c(rate = 1), loss_function = "precautionary")

fit_weighted <- tk_fit(data, "complete", pdf_exp, cdf_exp, prior_spec,
                       initial_values = c(rate = 1), loss_function = "weighted-sel")

# Compare all estimates
comparison <- data.frame(
  Loss_Function = c("SEL", "LINEX (c=0.5)", "GEL (q=0.5)", "Precautionary", "Weighted SEL"),
  Estimate = c(coef(fit_sel), coef(fit_linex), coef(fit_gel),
               coef(fit_precautionary), coef(fit_weighted))
)

print(comparison)

# Visual comparison
barplot(comparison$Estimate, names.arg = comparison$Loss_Function,
        main = "Bayes Estimates Under Different Loss Functions",
        ylab = "Rate Estimate", col = "steelblue")
abline(h = 1.5, col = "red", lty = 2)  # True value
legend("topright", legend = "True value", col = "red", lty = 2)
```

## Choosing a Loss Function

The choice of loss function depends on your application:

- **SEL**: Use when errors are symmetric and you want unbiased estimates
- **LINEX**: Use when overestimation and underestimation have different costs
  - $c > 0$: Overestimation is more costly (e.g., safety margins)
  - $c < 0$: Underestimation is more costly (e.g., resource allocation)
- **GEL**: Use for scale parameters where relative error matters
- **Precautionary**: Use when you want conservative estimates
- **Weighted SEL**: Use when parameters have different scales or variability

## Multi-Parameter Models

For multi-parameter models, each parameter can be estimated under a different loss function:

```{r}
# Two-parameter Weibull example
pdf_weibull <- function(x, param) dweibull(x, shape = param[1], scale = param[2])
cdf_weibull <- function(x, param) pweibull(x, shape = param[1], scale = param[2])

prior_spec <- list(
  shape = list(family = "gamma", hyperparameters = list(shape = 2, rate = 1)),
  scale = list(family = "gamma", hyperparameters = list(shape = 2, rate = 1))
)

set.seed(123)
data_weibull <- rweibull(20, shape = 2, scale = 1)

# Fit with SEL (applies to both parameters)
fit_weibull <- tk_fit(
  data = data_weibull,
  censoring_scheme = "complete",
  pdf = pdf_weibull,
  cdf = cdf_weibull,
  prior_spec = prior_spec,
  initial_values = c(shape = 1.5, scale = 1),
  loss_function = "sel"
)

coef(fit_weibull)
```

## Next Steps

- See "Prior Specification" for information on choosing priors
- See "Simulation Studies" for comparing loss functions in simulation
