---
title: "Dyadic Score Model (DSM)"
author: "Pascal Küng"
description: >
  Construction and interpretation of DSM predictor scores and contrasts,
  including their relationship to APIM effects for distinguishable dyads.
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,
  dev.args = list(bg = "transparent")
)
```

```{r setup}
library(dyadMLM)
```

```{r internal-setup, include=FALSE}
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.

Here $X_{\mathrm{female}}$ and $X_{\mathrm{male}}$ denote provided support
centered with the pooled mean from complete predictor pairs.
`prepare_dyad_data()` creates the corresponding DSM dyad-mean column; using the
original zero requires shifting it manually.

```{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)
```

With this notation, `dyadMLM` creates the equivalent coordinates:

- `.provided_support_dyad_mean_gmc` $=
  \frac{X_{\mathrm{female}} + X_{\mathrm{male}}}{2}$
  
- `.provided_support_within_dyad_diff` $= X_{\mathrm{female}} - X_{\mathrm{male}}$

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

The common centering shift cancels from the signed difference. Both predictor
scores are repeated on the member rows; the outcome remains unchanged. APIM GMC
uses all retained non-missing values, whereas DSM uses complete pairs, so their
constants may differ with one-sided missingness.

## 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
variance. 

```{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)
    .provided_support_dyad_mean_gmc +

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

    # Outcome-difference intercept (a20)
    .dsm_role_contrast +

    # Predictor level -> outcome difference (a21)
    .provided_support_dyad_mean_gmc:.dsm_role_contrast +

    # Predictor difference -> outcome difference (a22)
    .provided_support_within_dyad_diff:.dsm_role_contrast +

    # Outcome-level and outcome-difference residual variances and their covariance
    us(1 + .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},
\qquad
X_{\mathrm{diff}} = X_{\mathrm{female}} - X_{\mathrm{male}}.
$$

Here the two member predictors already share the pooled grand-mean reference,
so $X_{\mathrm{mean}}$ is grand-mean centered and the common shift cancels from
$X_{\mathrm{diff}}$.

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 variance in outcome level, and
the random role-contrast slope variance is unexplained variance 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"),
  add_apim_gmc_predictors = TRUE,
  keep_compositions = "female-male",
  dsm_role_order = c("male", "female")
)
```

```{r fit-cross-dsm-inverted, eval=has_glmmTMB}
dsm_model_inverted <- glmmTMB::glmmTMB(
  closeness ~
    .provided_support_dyad_mean_gmc +
    .provided_support_within_dyad_diff +
    .dsm_role_contrast +
    .provided_support_dyad_mean_gmc:.dsm_role_contrast +
    .provided_support_within_dyad_diff:.dsm_role_contrast +
    us(1 + .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: 

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

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

- `.provided_support_dyad_mean_gmc:.dsm_role_contrast` reverses because only
  the outcome difference reverses.

- `.provided_support_within_dyad_diff:.dsm_role_contrast` remains unchanged
  because both differences reverse.

The intercept and `.provided_support_dyad_mean_gmc` also remain unchanged. For
the random effects, the variances of `(Intercept)` and
`.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 +
    .is_female +
    .is_male +

    # Role-specific actor effects
    .is_female:.provided_support_gmc_actor +
    .is_male:.provided_support_gmc_actor +

    # Role-specific partner effects
    .is_female:.provided_support_gmc_partner +
    .is_male:.provided_support_gmc_partner +

    # Role-specific Gaussian residual covariance structure
    us(0 +
         .is_female +
         .is_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}
$$

With complete pairs, the GMC APIM and DSM share a zero point, so the intercepts
transform as

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

Raw APIM predictors leave the slope transformations unchanged but require
intercept recentering.

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},
$$

$$
b_{0,\mathrm{male}} = a_{10} - \frac{a_{20}}{2}.
$$

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[[".is_female"]]
b0_male <- apim_coef[[".is_male"]]
b_actor_female <- apim_coef[[
  ".is_female:.provided_support_gmc_actor"
]]
b_actor_male <- apim_coef[[
  ".is_male:.provided_support_gmc_actor"
]]
b_partner_female <- apim_coef[[
  ".is_female:.provided_support_gmc_partner"
]]
b_partner_male <- apim_coef[[
  ".is_male:.provided_support_gmc_partner"
]]

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,
  a11 = a11_from_apim,
  a12 = a12_from_apim,
  a20 = b0_female - b0_male,
  a21 = a21_from_apim,
  a22 = a22_from_apim
)

a10_dsm <- dsm_coef[["(Intercept)"]]
a11_dsm <- dsm_coef[[".provided_support_dyad_mean_gmc"]]
a12_dsm <- dsm_coef[[".provided_support_within_dyad_diff"]]
a20_dsm <- dsm_coef[[".dsm_role_contrast"]]
a21_dsm <- dsm_coef[[
  ".provided_support_dyad_mean_gmc:.dsm_role_contrast"
]]
a22_dsm <- dsm_coef[[
  ".provided_support_within_dyad_diff:.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 = paste(
    "APIM-to-DSM fixed-effect transformation with pooled",
    "grand-mean-centered actor and partner predictors."
  )
)
```

### 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).

## Checking partner dependence

We can check whether the fitted DSM reproduces each role's response variance and
the partner correlation by comparing observed and simulated data.

::: {.no-invert-dark-mode}

```{r check-cross-dsm, dev.args = list(bg = "white"), eval = has_glmmTMB, fig.width = 10, fig.height = 6.5, out.width = "100%", fig.alt = "Six predictive-check histograms for the DSM. Member SDs and partner correlation are in the top row; dyad-average and half-difference summaries are in the bottom row. Red lines mark observed values."}
dsm_simulations <- dyadMLM::simulate_dyad_responses(dsm_model, seed = 123)
dyadMLM::check_partner_dependence(
  dsm_simulations,
  dyad = coupleID,
  role = gender,
  # Supply the fitting data because gender is not in the model formula.
  data = cross_dsm_data
)
```

:::

The top row shows role-specific SDs and partner correlation. The bottom
row shows the same information using dyad averages and half the differences
between partners. Histograms show simulated values and red lines mark observed
values. A red line far from most simulations suggests a mismatch.

By default, the check subtracts the model's fixed-effect predictions from
observed and simulated responses. Good agreement is often expected for variances
and correlations estimated from the same data. See the
[function help](https://pascal-kueng.github.io/dyadMLM/reference/check_partner_dependence.html)
for details and interpretation. Simulation studies show how often the check
detects [omitted partner dependence](https://pascal-kueng.github.io/dyadMLM/articles/partner-dependence-simulation.html)
and [incorrect covariance pooling](https://pascal-kueng.github.io/dyadMLM/articles/covariance-pooling.html),
and how often it raises false alarms. For intensive longitudinal data, also supply
`member` and `time`. A [separate study](https://pascal-kueng.github.io/dyadMLM/articles/ild-partner-dependence.html) covers this case.

The same `dsm_simulations` can be checked with
[`check_dyad_residuals()`](https://pascal-kueng.github.io/dyadMLM/reference/check_dyad_residuals.html)
and [`check_dyad_outcomes()`](https://pascal-kueng.github.io/dyadMLM/reference/check_dyad_outcomes.html),
as shown in the [APIM vignette](apim.html#checking-residuals-and-outcomes).

## 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 specification below estimates same-day associations between support and
closeness and allows separate linear trends for the outcome level and the
female-minus-male outcome difference. It also includes the role-specific AR(1)
components specified and interpreted in the APIM vignette.

```{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
    .provided_support_cwp_dyad_mean +

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

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

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

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

    # Within-person predictor level and difference -> outcome difference
    .provided_support_cwp_dyad_mean:.dsm_role_contrast +
    .provided_support_cwp_within_dyad_diff:.dsm_role_contrast +

    # Between-person predictor level and difference -> outcome difference
    .provided_support_cbp_dyad_mean:.dsm_role_contrast +
    .provided_support_cbp_within_dyad_diff:.dsm_role_contrast +

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

    # Same-day outcome-level and outcome-difference covariance
    us(1 + .dsm_role_contrast | coupleID:diaryday) +

    # Role-specific residual persistence
    ar1(0 + .is_female:factor(diaryday) | coupleID) +
    ar1(0 + .is_male:factor(diaryday) | coupleID),
  dispformula = ~ 0,
  family = gaussian(),
  data = ild_dsm_data,
  # Non-default settings help this example converge.
  control = glmmTMB::glmmTMBControl(
    profile = TRUE,
    optimizer = stats::optim,
    optArgs = list(method = "BFGS")
  )
)

glmmTMB::VarCorr(dsm_ILD)

```

This AR-adjusted, fixed-slope DSM omits the actor random slopes present in the
simulation. See the
[distinguishable APIM AR(1) section](apim.html#distinguishable-residual-ar1) for
the corresponding specification and interpretation.

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}
:::
