---
title: "Dyadic Score Model (DSM)"
author: "Pascal Küng"
bibliography: references.bib
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Dyadic Score Model (DSM)}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

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

diagram_helper <- if (file.exists("diagram-helpers.Rinc")) {
  "diagram-helpers.Rinc"
} else {
  file.path("vignettes", "diagram-helpers.Rinc")
}
sys.source(diagram_helper, envir = knitr::knit_global())

diagram_device <- .vignette_diagram_device()
knitr::opts_chunk$set(dev = diagram_device, fig.ext = diagram_device)
```

```{r setup}
library(dyadMLM)
has_glmmTMB <- requireNamespace("glmmTMB", quietly = TRUE)
dsm_fitted_alt <- "Fitted DSM diagram unavailable."
```

This vignette focuses on the Dyadic Score Model (DSM) for distinguishable
dyads and its relationship to the distinguishable Actor-Partner
Interdependence Model (APIM). The DSM expresses associations in terms of the
dyad's shared level and the directional difference between partners
[@iidaModelsInterdependentIndividuals2018].

For the broader package workflow and an overview of the available
model-specific vignettes, including the
[Actor-Partner Interdependence Model](apim.html) and
[Dyad-Individual Model](dim.html), see the
[online package overview](https://pascal-kueng.github.io/dyadMLM/).

## Preparing DSM Data

A DSM requires an explicitly declared direction. This direction should be
substantively meaningful when the directional coefficients are interpreted.
Here, `c("female", "male")` defines every difference as female minus male.

```{r prepare-cross-dsm}
cross_dsm_data <- dyadMLM::prepare_dyad_data(
  dyads_cross,
  dyad = coupleID,
  member = personID,
  role = gender,
  predictors = provided_support,
  model_types = "dsm",
  # All three observed compositions in `dyads_cross` are detected and retained by
  # default. This example focuses on `female-male` dyads, so we restrict the
  # analysis here.
  keep_compositions = "female-male",
  dsm_role_order = c("female", "male")
)

print(cross_dsm_data, n = 4)
```

For predictor values $X_{\mathrm{female}}$ and $X_{\mathrm{male}}$, `dyadMLM`
then creates:

- `.dy_provided_support_dyad_mean_gmc` $=
  \frac{X_{\mathrm{female}} + X_{\mathrm{male}}}{2} - \mu_X$ (with $\mu_X$ representing the sample grand
  mean of the dyad-level predictor means)
  
- `.dy_provided_support_within_dyad_diff` $= X_{\mathrm{female}} - X_{\mathrm{male}}$

- `.dy_dsm_role_contrast` $= +0.5$ for female and $-0.5$ for male.

The dyad mean and signed difference are repeated on both member rows. The
outcome remains unchanged and no transformation is needed.

## Cross-Sectional Gaussian DSM

For a cross-sectional Gaussian DSM, a correlated dyad random intercept and
role-contrast slope represent unexplained outcome-level and outcome-difference
variation. 

```{r conceptual-dsm-diagram, echo=FALSE, fig.width=9, fig.height=4.8, out.width="100%", fig.cap="Conceptual cross-sectional DSM. Predictor mean and predictor difference each predict both outcome scores.", fig.alt="Path diagram for a cross-sectional dyadic score model. The centered female-male predictor mean and female-minus-male predictor difference each predict the female-male outcome mean and female-minus-male outcome difference. Paths are labelled a11, a12, a21, and a22, and outcome intercepts are labelled a10 and a20."}
draw_dsm_diagram()
```

The same model can be displayed in the individual-member rows used by the
long-format multilevel model.

```{r conceptual-dsm-member-diagram, echo=FALSE, fig.width=9, fig.height=5.6, out.width="100%", fig.cap="Individual-level representation of the cross-sectional DSM used for the long-format multilevel model. The centered predictor mean and female-minus-male predictor difference appear on both member rows. For the female outcome, the intercept and slopes add one-half of the corresponding outcome-difference parameters. For the male outcome, they subtract one-half. The female and male residuals may have different variances and covary.", fig.alt="Two-panel path diagram for a female-minus-male dyadic score model. Both panels contain the centered predictor mean and female-minus-male predictor difference. For the female outcome, the intercept is a10 plus half a20, the predictor-mean coefficient is a11 plus half a21, and the predictor-difference coefficient is a12 plus half a22. For the male outcome, the same combinations use minus signs. The two member residuals covary."}
draw_dsm_member_diagram()
```

The path labels correspond directly to the terms in the model below:

```{r fit-cross-dsm, eval=has_glmmTMB}
dsm_model <- glmmTMB::glmmTMB(
  closeness ~

    # Outcome-level intercept
    1 +

    # Predictor level -> outcome level (a11)
    .dy_provided_support_dyad_mean_gmc +

    # Predictor difference -> outcome level (a12)
    .dy_provided_support_within_dyad_diff +

    # Outcome-difference intercept (a20)
    .dy_dsm_role_contrast +

    # Predictor level -> outcome difference (a21)
    .dy_provided_support_dyad_mean_gmc:.dy_dsm_role_contrast +

    # Predictor difference -> outcome difference (a22)
    .dy_provided_support_within_dyad_diff:.dy_dsm_role_contrast +

    # Outcome-level and outcome-difference residual variances and their covariance
    us(1 + .dy_dsm_role_contrast | coupleID),
  dispformula = ~ 0,
  family = gaussian(),
  data = cross_dsm_data
)

summary(dsm_model)
```

### Interpreting the DSM paths

For the outcomes given the predictors, the long-format model estimates the same
paths as the conventional score-based DSM
[@iidaModelsInterdependentIndividuals2018].

In the conventional score-based representation, the **predictors** are
decomposed in the same way:

$$
X_{\mathrm{mean}}
= \frac{X_{\mathrm{female}} + X_{\mathrm{male}}}{2} - \mu_X,
\qquad
X_{\mathrm{diff}} = X_{\mathrm{female}} - X_{\mathrm{male}},
$$

where $\mu_X$ is the sample grand mean of the dyad-level predictor means.

The **outcomes** are also decomposed:

$$
Y_{\mathrm{mean}} = \frac{Y_{\mathrm{female}} + Y_{\mathrm{male}}}{2},
\qquad
Y_{\mathrm{diff}} = Y_{\mathrm{female}} - Y_{\mathrm{male}}.
$$

The long-format model fitted here does not create $Y_{\mathrm{mean}}$ and
$Y_{\mathrm{diff}}$ as observed variables. Instead, it uses the member-level
outcome directly. With complete outcome pairs, this is an equivalent
parameterization of the same conditional outcome regressions.

Consider the conceptual SEM formulas:

$$
\widehat{Y_{\mathrm{mean}}}
= a_{10} + a_{11}X_{\mathrm{mean}} + a_{12}X_{\mathrm{diff}},
$$

$$
\widehat{Y_{\mathrm{diff}}}
= a_{20} + a_{21}X_{\mathrm{mean}} + a_{22}X_{\mathrm{diff}}.
$$

The fitted paths for this example are:

```{r prepare-fitted-dsm-diagram, include=FALSE, eval=has_glmmTMB}
dsm_diagram_values <- .extract_dsm_diagram_values(dsm_model)
dsm_diagram_estimates <- dsm_diagram_values$estimates
dsm_diagram_residuals <- dsm_diagram_values$residuals

dsm_fitted_alt <- sprintf(
  paste(
    "Fitted DSM. Intercepts a10 %.2f and a20 %.2f; paths a11 %.2f, a12 %.2f,",
    "a21 %.2f, and a22 %.2f; residual SDs %.2f and %.2f, with correlation %.2f."
  ),
  dsm_diagram_estimates[["a10"]],
  dsm_diagram_estimates[["a20"]],
  dsm_diagram_estimates[["a11"]],
  dsm_diagram_estimates[["a12"]],
  dsm_diagram_estimates[["a21"]],
  dsm_diagram_estimates[["a22"]],
  dsm_diagram_residuals[["sd_mean"]],
  dsm_diagram_residuals[["sd_difference"]],
  dsm_diagram_residuals[["correlation"]]
)
```

```{r fitted-dsm-diagram, echo=FALSE, eval=has_glmmTMB, fig.width=9, fig.height=4.8, out.width="100%", fig.cap="Fitted cross-sectional DSM for the example data. The nodes identify the mean and difference scores; edge and intercept labels show the estimated DSM coefficients, and the residual labels show the estimated score-component standard deviations and correlation.", fig.alt=dsm_fitted_alt}
draw_dsm_diagram(
  model = dsm_model,
  labels = c(predictor = "provided support", outcome = "closeness")
)
```

The fixed effects from our MLM model map directly to these paths as such:

| Long-format fixed effect | DSM SEM path and interpretation |
|---|---|
| Intercept | $a_{10}$: expected dyad-average closeness at the sample-average provided-support level and no female-male support difference |
| Provided-support dyad mean | $a_{11}$: predictor level $\rightarrow$ outcome level |
| Provided-support difference | $a_{12}$: predictor difference $\rightarrow$ outcome level |
| DSM role contrast | $a_{20}$: expected female-minus-male outcome difference at the predictor reference values |
| Dyad mean $\times$ role contrast | $a_{21}$: predictor level $\rightarrow$ outcome difference |
| Provided-support difference $\times$ role contrast | $a_{22}$: predictor difference $\rightarrow$ outcome difference |

Thus, for example, $a_{12}$ is the change in dyad-average closeness
associated with a one-unit larger female-minus-male provided-support difference,
holding support level constant. In contrast, $a_{22}$ is the change in
the female-minus-male closeness difference associated with that same
one-unit larger support difference, holding support level
constant. The $a_{12}$ and $a_{21}$ coefficients are the DSM cross-paths. They
are omitted from the reduced DSM but are needed for the full model.

The random intercept variance is unexplained variation in outcome level, and
the random role-contrast slope variance is unexplained variation in the full
directional outcome difference. Their covariance indicates whether unexplained
outcome level and unexplained outcome difference are associated.

The curved arrow $\rho_{r_m r_d}$ is the scale-free correlation between the
outcome-mean residual and the outcome-difference residual. It is **not** the
female-male residual correlation $\rho_{\epsilon_F\epsilon_M}$ from the APIM.

The DSM uses the full female-minus-male difference:

$$
e_{\mathrm{F}} = r_{\mathrm{m}} + \frac{1}{2}r_{\mathrm{d}},
\qquad
e_{\mathrm{M}} = r_{\mathrm{m}} - \frac{1}{2}r_{\mathrm{d}}.
$$

Therefore, this relationship applies:

$$
\operatorname{Cov}(r_{\mathrm{m}},r_{\mathrm{d}})
=
\frac{\operatorname{Var}(e_{\mathrm{F}})-\operatorname{Var}(e_{\mathrm{M}})}{2}.
$$

For this reason, a nonzero $\rho_{r_m r_d}$ indicates that the two roles have different
residual variances. The remaining covariance between the partners' residuals is

$$
\operatorname{Cov}(e_{\mathrm{F}},e_{\mathrm{M}})
=
\operatorname{Var}(r_{\mathrm{m}})-\frac{1}{4}\operatorname{Var}(r_{\mathrm{d}}).
$$

### Reversing the coding

Instead of computing $X_{\mathrm{female}} - X_{\mathrm{male}}$, we can reverse
the direction and compute $X_{\mathrm{male}} - X_{\mathrm{female}}$. This
changes the direction of the differences, but not the substantive model.

```{r prepare-cross-dsm-inverted}
cross_dsm_data_inverted <- dyadMLM::prepare_dyad_data(
  dyads_cross,
  dyad = coupleID,
  member = personID,
  role = gender,
  predictors = provided_support,
  # Request APIM columns too for comparison below.
  model_types = c("dsm", "apim"),
  keep_compositions = "female-male",
  dsm_role_order = c("male", "female")
)
```

```{r fit-cross-dsm-inverted, eval=has_glmmTMB}
dsm_model_inverted <- glmmTMB::glmmTMB(
  closeness ~
    .dy_provided_support_dyad_mean_gmc +
    .dy_provided_support_within_dyad_diff +
    .dy_dsm_role_contrast +
    .dy_provided_support_dyad_mean_gmc:.dy_dsm_role_contrast +
    .dy_provided_support_within_dyad_diff:.dy_dsm_role_contrast +
    us(1 + .dy_dsm_role_contrast | coupleID),
  dispformula = ~ 0,
  family = gaussian(),
  data = cross_dsm_data_inverted
)

female_minus_male <- glmmTMB::fixef(dsm_model)$cond
male_minus_female <- glmmTMB::fixef(dsm_model_inverted)$cond

knitr::kable(
  data.frame(
    `model term` = names(female_minus_male),
    `female - male` = unname(female_minus_male),
    `male - female` = unname(male_minus_female),
    check.names = FALSE
  ),
  digits = 3,
  align = c("l", "r", "r")
)
```

The two models have identical fitted values and model fit: 

- `.dy_provided_support_within_dyad_diff` reverses because the predictor difference
  reverses.

- `.dy_dsm_role_contrast` reverses because the represented outcome difference
  reverses.

- `.dy_provided_support_dyad_mean_gmc:.dy_dsm_role_contrast` reverses because only
  the outcome difference reverses.

- `.dy_provided_support_within_dyad_diff:.dy_dsm_role_contrast` remains unchanged
  because both differences reverse.

The intercept and `.dy_provided_support_dyad_mean_gmc` also remain unchanged. For
the random effects, the variances of `(Intercept)` and
`.dy_dsm_role_contrast` remain unchanged, whereas their covariance reverses
sign.

## Relationship to the APIM and DIM

For distinguishable dyads, the full DSM and an unconstrained distinguishable
APIM are alternative parameterizations of the same fixed associations
[@iidaModelsInterdependentIndividuals2018].

Let's fit the equivalent distinguishable APIM:

```{r fit-cross-apim, eval=has_glmmTMB}
apim_model <- glmmTMB::glmmTMB(
  closeness ~
    # Role-specific intercepts
    0 +
    .dy_is_female_x_male_female +
    .dy_is_female_x_male_male +

    # Role-specific actor effects
    .dy_is_female_x_male_female:.dy_provided_support_actor +
    .dy_is_female_x_male_male:.dy_provided_support_actor +

    # Role-specific partner effects
    .dy_is_female_x_male_female:.dy_provided_support_partner +
    .dy_is_female_x_male_male:.dy_provided_support_partner +

    # Role-specific Gaussian residual covariance structure
    us(0 +
         .dy_is_female_x_male_female +
         .dy_is_female_x_male_male
       | coupleID),
  dispformula = ~ 0,
  family = gaussian(),
  data = cross_dsm_data_inverted
)
```

The two DSM directions and the APIM have identical fit statistics:

```{r compare-cross-fit, eval=has_glmmTMB}
data.frame(
  model = c("DSM: female - male", "DSM: male - female", "APIM"),
  AIC = round(c(AIC(dsm_model), AIC(dsm_model_inverted), AIC(apim_model)), 3),
  BIC = round(c(BIC(dsm_model), BIC(dsm_model_inverted), BIC(apim_model)), 3),
  logLik = round(c(
    as.numeric(logLik(dsm_model)),
    as.numeric(logLik(dsm_model_inverted)),
    as.numeric(logLik(apim_model))
  ), 3)
)
```

### Fixed-effect transformation

Let $b_{\mathrm{actor},\mathrm{female}}$ and
$b_{\mathrm{actor},\mathrm{male}}$ denote the actor effects on the female and
male outcomes. The corresponding partner effects are
$b_{\mathrm{partner},\mathrm{female}}$ and
$b_{\mathrm{partner},\mathrm{male}}$, and the APIM intercepts are
$b_{0,\mathrm{female}}$ and $b_{0,\mathrm{male}}$. Fixed APIM coefficients use
$b$ and write out their effect and outcome role. The numbered paths $a_{10}$
through $a_{22}$ retain the published DSM notation.

The slope transformation can be understood in two steps. First, for each
outcome role $r \in \{\mathrm{female},\mathrm{male}\}$, form the actor-plus-partner
and actor-minus-partner combinations:

$$
\begin{aligned}
b_{\mathrm{sum},r}
&= b_{\mathrm{actor},r} + b_{\mathrm{partner},r}, \\
b_{\mathrm{difference},r}
&= b_{\mathrm{actor},r} - b_{\mathrm{partner},r}.
\end{aligned}
$$

The DSM slopes then follow by combining the female- and male-outcome effects:

$$
\begin{aligned}
a_{11}
&= \frac{b_{\mathrm{sum},\mathrm{female}}
        + b_{\mathrm{sum},\mathrm{male}}}{2},
&
a_{21}
&= b_{\mathrm{sum},\mathrm{female}}
   - b_{\mathrm{sum},\mathrm{male}}, \\
a_{12}
&= \frac{b_{\mathrm{difference},\mathrm{female}}
        - b_{\mathrm{difference},\mathrm{male}}}{4},
&
a_{22}
&= \frac{b_{\mathrm{difference},\mathrm{female}}
        + b_{\mathrm{difference},\mathrm{male}}}{2}.
\end{aligned}
$$

The APIM predictors retain their original scale, whereas the DSM predictor
level is grand-mean centered. Keeping the raw APIM predictors on their original
scale preserves their reference values; the centering difference is handled
explicitly in the intercept transformation. If $\mu_X$ is the grand mean
subtracted from the DSM predictor level, the intercepts transform as

$$
a_{10}
= \frac{b_{0,\mathrm{female}} + b_{0,\mathrm{male}}}{2} + \mu_X a_{11},
\qquad
a_{20} = b_{0,\mathrm{female}} - b_{0,\mathrm{male}} + \mu_X a_{21}.
$$

For the reverse slope transformation, first recover the role-specific
actor-plus-partner and actor-minus-partner combinations:

$$
\begin{aligned}
b_{\mathrm{sum},\mathrm{female}}
&= a_{11} + \frac{a_{21}}{2},
&
b_{\mathrm{sum},\mathrm{male}}
&= a_{11} - \frac{a_{21}}{2}, \\
b_{\mathrm{difference},\mathrm{female}}
&= a_{22} + 2a_{12},
&
b_{\mathrm{difference},\mathrm{male}}
&= a_{22} - 2a_{12}.
\end{aligned}
$$

Then, for each outcome role $r$,

$$
b_{\mathrm{actor},r}
= \frac{b_{\mathrm{sum},r} + b_{\mathrm{difference},r}}{2},
\qquad
b_{\mathrm{partner},r}
= \frac{b_{\mathrm{sum},r} - b_{\mathrm{difference},r}}{2}.
$$

The intercepts transform back as

$$
b_{0,\mathrm{female}} = a_{10} + \frac{a_{20}}{2}
- \mu_X\left(a_{11} + \frac{a_{21}}{2}\right),
$$

$$
b_{0,\mathrm{male}} = a_{10} - \frac{a_{20}}{2}
- \mu_X\left(a_{11} - \frac{a_{21}}{2}\right).
$$

The following comparison applies the APIM-to-DSM transformation to all six
fixed effects:

```{r compare-cross-coefficients, eval=has_glmmTMB, echo=FALSE}
apim_coef <- glmmTMB::fixef(apim_model)$cond
dsm_coef <- glmmTMB::fixef(dsm_model)$cond

b0_female <- apim_coef[[".dy_is_female_x_male_female"]]
b0_male <- apim_coef[[".dy_is_female_x_male_male"]]
b_actor_female <- apim_coef[[
  ".dy_is_female_x_male_female:.dy_provided_support_actor"
]]
b_actor_male <- apim_coef[[
  ".dy_is_female_x_male_male:.dy_provided_support_actor"
]]
b_partner_female <- apim_coef[[
  ".dy_is_female_x_male_female:.dy_provided_support_partner"
]]
b_partner_male <- apim_coef[[
  ".dy_is_female_x_male_male:.dy_provided_support_partner"
]]

mu_X <- mean(
  (cross_dsm_data_inverted$.dy_provided_support_actor +
     cross_dsm_data_inverted$.dy_provided_support_partner) / 2 -
    cross_dsm_data_inverted$.dy_provided_support_dyad_mean_gmc,
  na.rm = TRUE
)

b_sum_female <- b_actor_female + b_partner_female
b_sum_male <- b_actor_male + b_partner_male
b_difference_female <- b_actor_female - b_partner_female
b_difference_male <- b_actor_male - b_partner_male

a11_from_apim <- (b_sum_female + b_sum_male) / 2
a21_from_apim <- b_sum_female - b_sum_male
a12_from_apim <- (b_difference_female - b_difference_male) / 4
a22_from_apim <- (b_difference_female + b_difference_male) / 2

apim_to_dsm <- c(
  a10 = (b0_female + b0_male) / 2 + mu_X * a11_from_apim,
  a11 = a11_from_apim,
  a12 = a12_from_apim,
  a20 = b0_female - b0_male + mu_X * a21_from_apim,
  a21 = a21_from_apim,
  a22 = a22_from_apim
)

a10_dsm <- dsm_coef[["(Intercept)"]]
a11_dsm <- dsm_coef[[".dy_provided_support_dyad_mean_gmc"]]
a12_dsm <- dsm_coef[[".dy_provided_support_within_dyad_diff"]]
a20_dsm <- dsm_coef[[".dy_dsm_role_contrast"]]
a21_dsm <- dsm_coef[[
  ".dy_provided_support_dyad_mean_gmc:.dy_dsm_role_contrast"
]]
a22_dsm <- dsm_coef[[
  ".dy_provided_support_within_dyad_diff:.dy_dsm_role_contrast"
]]

knitr::kable(
  data.frame(
    `DSM path` = names(apim_to_dsm),
    `From APIM transformation` = round(unname(apim_to_dsm), 3),
    `From DSM model` = round(c(
      a10_dsm,
      a11_dsm,
      a12_dsm,
      a20_dsm,
      a21_dsm,
      a22_dsm
    ), 3),
    check.names = FALSE
  ),
  align = c("l", "r", "r"),
  caption = paste0(
    "APIM-to-DSM fixed-effect transformation (centering constant = ",
    round(mu_X, 3),
    ")."
  )
)
```

### Random-effect transformation

Let $u_{\mathrm{female}}$ and $u_{\mathrm{male}}$ be the APIM random effects
for the female and male outcomes. The DSM outcome-level and outcome-difference
residuals are the same random effects expressed in different coordinates:

$$
\begin{pmatrix} r_{Y,\mathrm{mean}} \\ r_{Y,\mathrm{diff}} \end{pmatrix}
=
\begin{pmatrix} 1/2 & 1/2 \\ 1 & -1 \end{pmatrix}
\begin{pmatrix} u_{\mathrm{female}} \\ u_{\mathrm{male}} \end{pmatrix}.
$$

Applying this rotation to the APIM covariance matrix reproduces the DSM random
intercept variance, intercept-slope covariance, and role-slope variance:

```{r compare-cross-random-effects, eval=has_glmmTMB}
apim_vcov <- as.matrix(glmmTMB::VarCorr(apim_model)$cond$coupleID)
dsm_vcov <- as.matrix(glmmTMB::VarCorr(dsm_model)$cond$coupleID)

rotation <- rbind(
  outcome_level = c(0.5, 0.5),
  outcome_difference = c(1, -1)
)
apim_to_dsm_vcov <- rotation %*% apim_vcov %*% t(rotation)

data.frame(
  parameter = c(
    "Var(outcome mean)",
    "Cov(outcome mean, outcome diff)",
    "Var(outcome diff)"
  ),
  from_DSM = round(c(
    dsm_vcov[1, 1],
    dsm_vcov[1, 2],
    dsm_vcov[2, 2]
  ), 3),
  from_APIM_transformation = round(c(
    apim_to_dsm_vcov[1, 1],
    apim_to_dsm_vcov[1, 2],
    apim_to_dsm_vcov[2, 2]
  ), 3)
)
```

For exchangeable dyads, the direction of a member difference is arbitrary.
The directional intercept, both cross-paths, and the covariance between outcome
level and outcome difference must then be zero. The remaining reduced,
label-invariant DSM is algebraically the Gaussian Dyad-Individual Model (DIM).
In `dyadMLM`, use `model_types = "dim"` for this exchangeable model and reserve
`model_types = "dsm"` for distinguishable dyads.

Because the Gaussian DIM is the exchangeability-constrained version of the full
DSM, exchangeability can also be tested by comparing these nested models. This
is equivalent to the comparison shown in [Testing distinguishability in the APIM vignette](apim.html#testing-distinguishability).

## Intensive longitudinal DSM

The intensive longitudinal DSM extends the cross-sectional DSM using the same
temporal decomposition and multilevel workflow shown for the
[intensive longitudinal DIM](dim.html#intensive-longitudinal-dim). The DSM
retains the directional mean-and-difference parameterization described above.
For more detail on centering decisions and mean-and-deviation interpretation,
refer to the [DIM vignette](dim.html#intensive-longitudinal-dim). For dynamic
models and their cautions, see the
[dynamic ILD APIM example](apim.html#dynamic-models).

Brief example of ILD DSM:

```{r prepare-ild-dsm}
ild_dsm_data <- dyadMLM::prepare_dyad_data(
  dyads_ild,
  dyad = coupleID,
  member = personID,
  role = gender,
  time = diaryday,
  predictors = provided_support,
  model_types = "dsm",
  keep_compositions = "female-male",
  dsm_role_order = c("female", "male")
)

print(ild_dsm_data, n = 4)
```

The example below estimates same-day associations between support and closeness
and includes `diaryday` to allow separate linear trends for the outcome level
and the female-minus-male outcome difference.

```{r fit-ild-dsm, eval = has_glmmTMB}

dsm_ILD <- glmmTMB::glmmTMB(
  closeness ~

    # Outcome-level intercept and linear time trend
    1 +
    diaryday +

    # Within-person predictor level -> outcome level
    .dy_provided_support_cwp_dyad_mean +

    # Within-person predictor difference -> outcome level
    .dy_provided_support_cwp_within_dyad_diff +

    # Between-person predictor level -> outcome level
    .dy_provided_support_cbp_dyad_mean +

    # Between-person predictor difference -> outcome level
    .dy_provided_support_cbp_within_dyad_diff +

    # Outcome-difference intercept and linear time trend
    .dy_dsm_role_contrast +
    diaryday:.dy_dsm_role_contrast +

    # Within-person predictor level and difference -> outcome difference
    .dy_provided_support_cwp_dyad_mean:.dy_dsm_role_contrast +
    .dy_provided_support_cwp_within_dyad_diff:.dy_dsm_role_contrast +

    # Between-person predictor level and difference -> outcome difference
    .dy_provided_support_cbp_dyad_mean:.dy_dsm_role_contrast +
    .dy_provided_support_cbp_within_dyad_diff:.dy_dsm_role_contrast +

    # Stable outcome-level and outcome-difference covariance
    us(1 + .dy_dsm_role_contrast | coupleID) +

    # Same-day outcome-level and outcome-difference covariance
    us(1 + .dy_dsm_role_contrast | coupleID:diaryday),
  dispformula = ~ 0,
  family = gaussian(),
  data = ild_dsm_data
)

summary(dsm_ILD)

```

The cross-sectional path interpretation therefore applies separately at the
within-person and between-person levels. At each level, the predictor dyad mean
and directional difference predict both the outcome level and the directional
outcome difference.

---

Return to the [Actor-Partner Interdependence Model vignette](apim.html), see
the [Dyad-Individual Model vignette](dim.html) for a related model
specification, or return to the
[online package overview](https://pascal-kueng.github.io/dyadMLM/).

## References

::: {#refs}
:::
