---
title: "Input formats for build_htna()"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Input formats for build_htna()}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(
  collapse  = TRUE,
  comment   = "#>",
  message   = FALSE,
  warning   = FALSE,
  fig.width = 10,
  fig.height = 7,
  dpi = 90
)
```

`build_htna()` accepts data in **three
interchangeable shapes**: 
1. a named list of per-actor-type nodes
2. a single combined frame with an actor-type column
3. a single combined frame with a node-to-actor-type dictionary. 

This vignette walks through each form, shows that all three produce 
the same network, and then covers two extra parameters that compose 
with any input form: `disambiguate` (for code-label collisions) and 
`group` (for per-cohort networks).

To keep the examples concrete, `htna` ships four bundled objects
covering every shape the vignette needs:

* `human_simplified` and `ai_simplified`: per-actor long datasets, one
  per actor type. These feed **Form 1** directly.
* `human_ai`: the same data row-bound into one long frame with an
  `actor_type` column (and a pre-computed `phase` cohort tag for the
  grouped example at the end). This feeds **Form 2** and **Form 3**.
* `human_ai_codebook` — a tidy two-column code → actor-type lookup,
  ready to pass to **Form 3**.

## Setup

```{r}
library(htna)
data(human_ai)
data(human_simplified)
data(ai_simplified)
data(human_ai_codebook)
```

All three long frames share the canonical schema `htna` expects:
`actor`/`session_id`, `code`, `order_in_session`. Within each session,
`order_in_session` is a **shared** time index across both actors.

## Form 1 — Named list of per-actor frames

The most direct form. Each entry is one actor's long frame; the list
name becomes the actor-type label on the network. The bundled
`human_simplified` and `ai_simplified` frames already have this
shape — one per actor type, sharing the canonical schema.

```{r}
net_list <- build_htna(list(Human = human_simplified, AI = ai_simplified), 
                       actor = "session_id")
summary(net_list)
```

```{r, fig.height = 7}
plot_htna(net_list)
```

Use this form when each actor's data lives in a separate frame (the
typical case when the two streams were prepared independently).

## Form 2 — Single combined frame with `actor_type`

When the data already comes as one long table, tag each row with the
actor-type and pass the column name to `actor_type =`.

```{r}
net_actor_type <- build_htna(human_ai, 
                             actor_type = "actor_type", 
                             actor = "session_id", 
                             order = "order_in_session")
```

The actor-type order on the resulting network follows the factor levels
(or, for character vectors, the order of first appearance), which is
how the actor groups will be ordered in legends and plots.

## Form 3 — Single combined frame with `node_groups`

When the combined frame has **no** actor-type column, declare the
node-to-actor partition directly via `node_groups`. `node_groups` accepts
two interchangeable shapes:

### 3a. Named list of code vectors

Extract the per-actor code sets from the bundled per-actor frames and
pass them as a named list. The list names become the actor-type
labels on the network.

```{r}
human_codes <- c("Specify", "Request", "Frustrate", "Check", "Inquire", "Refine")
ai_codes    <- c("Delegate", "Plan", "Execute", "Ask", "Repair", "Report")

net_node_groups <- build_htna(
  human_ai,
  actor = "session_id",
  node_groups = list(Human = human_codes, AI = ai_codes)
)
net_node_groups
```

### 3b. Two-column data frame (codebook)

The same partition expressed as a tidy codebook — one row per code, one
column for the action and one for the actor type. The action column must
match the `action` parameter (default `"code"`); the other column is
treated as the actor-type tag. Column order is irrelevant.

The bundled `human_ai_codebook` already has this shape, so it can be
passed straight through:

```{r}
head(human_ai_codebook)

net_node_groups_df <- build_htna(
  human_ai,
  session = "session_id",
  node_groups = human_ai_codebook
)
```

The actor-type ordering follows the column's factor levels (if a
factor) or the order of first appearance (if a character vector). Use
this form when your code/actor mapping already lives in a tidy lookup
table.

## All forms produce the same network

`build_htna()` resolves every input shape to the same combined sequence
and forwards to `Nestimate::build_network()`. The four networks below
are drawn side by side — the layout, colours, and edges are
indistinguishable:

```{r, fig.height = 9}
forms <- list(
  list_form        = net_list,
  actor_type_form  = net_actor_type,
  node_groups_list = net_node_groups,
  node_groups_df   = net_node_groups_df
)

op <- par(mfrow = c(2, 2), mar = c(1, 1, 3, 1))
for (nm in names(forms)) plot_htna(forms[[nm]], title = nm)
par(op)
```


 
## Handling code-label collisions with `disambiguate =`

If both actor types share a code label (e.g. both Human and AI have a
code called `Ask` and another code called `Reply`),
`build_htna()` errors by default — keeping such
states distinct is usually what you want. Pass `disambiguate = TRUE`
to prefix every code with its actor-type label so the two `Ask` nodes
become `Human:Ask` and `AI:Ask`.

```{r}
overlap <- data.frame(
  session_id        = rep(paste0("s", 1:3), each = 6),
  code              = rep(c("Ask", "Reply", "Ask", "Reply", "Ask", "Reply"), 3),
  actor_type        = rep(c("Human", "Human", "AI", "AI", "Human", "AI"), 3),
  order_in_session  = rep(1:6, 3),
  stringsAsFactors  = FALSE
)

# Without disambiguate=, this errors:
try(build_htna(overlap, actor_type = "actor_type"))

# With disambiguate=, the two `Ask`s become distinct nodes:
net_dis <- build_htna(overlap, actor_type = "actor_type",
                      disambiguate = TRUE)
net_dis$nodes$label
plot(net_dis)
```

## Splitting into cohorts with `group =`

Any of the three input forms can additionally be split into per-cohort
networks by passing `group =` — the result is an `htna_group`, one
`htna` network per level of the grouping column. `human_ai` already
ships with a `phase` column tagging each session as `Early` or `Late`
(a chronological split: first-half of sessions = early, rest = late),
so the cohort build is a one-liner:

```{r}
grp <- build_htna(human_ai, actor_type = "actor_type", group = "phase")
class(grp)
names(grp)
```

```{r, fig.height = 7}
plot_htna(grp)
```

## Cheat sheet

| Form | When to use |
|---|---|
| `list(Actor1 = a1, Actor2 = a2)` | Each actor's data is in its own frame |
| `df, actor_type = "actor_type"` | One combined frame, actor identity in a row-level column |
| `df, node_groups = list(Actor1 = ..., Actor2 = ...)` | One combined frame; partition declared as a named list of codes |
| `df, node_groups = data.frame(code = ..., actor_type = ...)` | One combined frame; partition declared as a tidy codebook |
| `Nestimate::build_clusters(htna, ...)` | Distance-based sequence clusters; returns one HTNA network per cluster |
| `Nestimate::cluster_mmm(htna, ...)` | Already-fitted latent Markov clusters; preserves fitted weights and posterior diagnostics |
| `tna::cluster_sequences(...), node_groups = ...` | Legacy sequence-clustering result; builds one HTNA network per cluster |
| `+ actor = "user_id"` | Identify the individual actor that performed each event (forwarded to `Nestimate::build_network()`) |
| `+ disambiguate = TRUE` | Same code label appears in more than one actor type |
| `+ group = "phase"` | Build one network per cohort/phase |

The row/list forms build one network directly. Clustering forms build or
preserve an outer `htna_group`, while every child keeps the same actor
partition.
