---
title: "Cookbook: Ordinal Outcome, End to End"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Cookbook: Ordinal Outcome, End to End}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

One complete, runnable script for an **ordinal** outcome — ordered
categories such as a 4-point severity scale or a Likert response. Same
four steps as every cookbook (see `vignette("cookbook-continuous")`).
Responses are recorded as integer levels `1, 2, …, K`; the default
estimand is the treatment coefficient of a proportional-odds (cumulative
logit) model, and the `InferenceOrdinal*` family also offers adjacent-
category, continuation-ratio, probit, cauchit and cloglog links plus
matched-design (KK) variants.

## Setup

EDI is not on CRAN yet, so `install.packages("EDI")` fails — install from
R-universe (fallback: GitHub, `subdir = "R/EDI"`). Not evaluated here.

```{r install, eval = FALSE, purl = FALSE}
install.packages("EDI", repos = c("https://kapelner.r-universe.dev", "https://cloud.r-project.org"))
# or: remotes::install_github("kapelner/EDI", subdir = "R/EDI")
```

```{r setup}
library(EDI)
set.seed(20260916)

n = 100
X = data.frame(
  baseline_score = round(rnorm(n, 5, 1.5), 1),
  female         = rbinom(n, 1, 0.5)
)
true_effect = 0.8   # shift on the latent logistic scale
```

## Fixed design, proportional odds

Outcomes are drawn from a latent-variable model: a linear predictor plus
logistic noise, cut at three thresholds into four ordered levels.

```{r fixed}
des = DesignFixedBernoulli$new(n = n, response_type = "ordinal", verbose = FALSE)
des$add_all_subjects_to_experiment(X)
des$assign_w_to_all_subjects()
w = des$get_w()

eta = true_effect * w + 0.3 * (X$baseline_score - 5) - 0.2 * X$female
u   = runif(n)
y   = ifelse(u <= plogis(-1.0 - eta), 1L,
      ifelse(u <= plogis( 0.2 - eta), 2L,
      ifelse(u <= plogis( 1.1 - eta), 3L, 4L)))
des$add_all_subject_responses(y)
table(level = y, treatment = w)

inf = InferenceOrdinalPropOddsRegr$new(des, verbose = FALSE)
inf$num_cores = 1L
inf$compute_estimate()                         # treatment log-odds shift
inf$compute_asymp_confidence_interval(alpha = 0.05)
inf$compute_asymp_two_sided_pval()
```

```{r fixed-resampling}
inf$set_seed(1)
inf$compute_rand_two_sided_pval(r = 200, show_progress = FALSE)
inf$set_seed(1)
inf$compute_bootstrap_confidence_interval(alpha = 0.05, B = 200, show_progress = FALSE)
```

## Everything at once

```{r suite}
suite = InferenceSuite$new(des)
res = suite$run_all_inference(screen = TRUE, plots = FALSE, num_cores = 1L,
                              methods = c("wald", "score", "lik_ratio"), max_secs_per_class = 15)
```

## Sequential design

```{r seq}
des_seq = DesignSeqOneByOneKK14$new(n = n, response_type = "ordinal", verbose = FALSE)
for (i in seq_len(n)) {
  w_i   = des_seq$add_one_subject_to_experiment_and_assign(X[i, , drop = FALSE])
  eta_i = true_effect * w_i + 0.3 * (X$baseline_score[i] - 5) - 0.2 * X$female[i]
  u_i   = runif(1)
  y_i   = if (u_i <= plogis(-1.0 - eta_i)) 1L else if (u_i <= plogis(0.2 - eta_i)) 2L else
          if (u_i <= plogis(1.1 - eta_i)) 3L else 4L
  des_seq$add_one_subject_response(i, y_i)
}

inf_seq = InferenceOrdinalPropOddsRegr$new(des_seq, verbose = FALSE)
inf_seq$num_cores = 1L
inf_seq$compute_estimate()
inf_seq$set_seed(1)
inf_seq$compute_rand_two_sided_pval(r = 200, show_progress = FALSE)
```

## Where to go next

- Other links on the same design: `InferenceOrdinalAdjCatLogitRegr`,
  `InferenceOrdinalContRatioRegr`, `InferenceOrdinalOrderedProbitRegr`,
  `InferenceOrdinalCauchitRegr`, `InferenceOrdinalCloglogRegr`.
- A distribution-free alternative when the proportional-odds assumption
  is doubtful: the Wilcoxon-family classes `InferenceSuite` includes for
  ordinal data.
- `vignette("validation-evidence")`: checked against `ordinal::clm`,
  `VGAM::vglm`, `MASS::polr`.
