---
title: Conversions for `tergm` version 4.0
output: rmarkdown::html_vignette
vignette: >
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
  %\VignetteIndexEntry{Conversions for tergm version 4.0}
---

```{r, echo=FALSE, cache=FALSE, eval=TRUE}
library(knitr)
library(rmarkdown)
options(rmarkdown.html_vignette.check_title = FALSE)
opts_chunk$set(echo=TRUE)
options(width=80)
```

# Introduction #

Version 4.0 of the `tergm` package introduces new user interfaces for 
specifying `tergm` models.  While an effort has been made to maintain a high
degree of backwards compatibility, there are some points of backwards 
incompatibility, and some users may wish to convert their code to use the new 
interfaces anyway, so this document describes how to go about doing that.  The 
examples given here are somewhat artificial so as to better illustrate the 
range of possible changes needed; they may not be typical or even plausible in 
every detail, but are intended to exhibit the types of updates that users may 
need to make.

# Estimation #

Estimation calls in `tergm` 3.x might look something like

```
data(samplk)
samp <- list(samplk1, samplk2, samplk3)
samp.fit <- stergm(samp,
                   formation = ~edges+mutual+cyclicalties+transitiveties,
                   dissolution = ~edges+mutual+cyclicalties+transitiveties,
                   estimate = "CMLE",
                   times = 1:3,
                   control = control.stergm(CMLE.control.form = control.ergm(init = c(-3.5,2,0,NA)),
                                            CMLE.control.diss = control.ergm(init = c(0,1,0,1/2))))
```

for CMLE, and

```
data(florentine)
stergm.fit.1 <- stergm(flobusiness,
                       formation = ~edges+gwesp(0,fixed=T),
                       dissolution = ~offset(edges),
                       targets = "formation",
                       offset.coef.diss = log(9),
                       estimate = "EGMME",
                       control = control.stergm(SA.plot.progress=TRUE))
```

for EGMME.

To convert these to the new 4.0 user interface, we make the following changes.

- Replace the function name `stergm` with `tergm` (in 4.0, the tergms need not 
  be separable, hence we drop the s).

- Combine the network (or network list), formation, and dissolution formulas 
  into a single formula, schematically of the form 

  ```
  network ~ Form(formation formula) + 
            Persist(dissolution formula)
  ```

  where `Form` and `Persist` are operator terms defined in `tergm` 4.0.
  
  For the CMLE example, this results in the formula 
  
  ```
  samp ~ Form(~edges+mutual+cyclicalties+transitiveties) + 
         Persist(~edges+mutual+cyclicalties+transitiveties)
  ```
  
  and for the EGMME example, it results in the formula 
  
  ```
  flobusiness ~ Form(~edges+gwesp(0,fixed=T)) + 
                Persist(~offset(edges))
  ```
  
  These formulas will be our first arguments to the `tergm` function.

- The control argument (if present), previously of class `control.stergm`, 
  should be replaced by one of class `control.tergm`.  This can be accomplished 
  by replacing `control.stergm()` with `control.tergm()`, `snctrl()`, or 
  `list()`, and updating arguments as follows.  Arguments to `control.stergm()` 
  occurring in pairs with `.form` and `.diss` in their names have been 
  collapsed to single, correspondingly named arguments to `control.tergm()` 
  without `.form` or `.diss`.  Additionally, the arguments `CMLE.control.form` and
  `CMLE.control.diss` to `control.stergm()` correspond to the `CMLE.ergm` 
  argument to `control.tergm()` (and have been renamed as the `CMLE.form.ergm`
  and `CMLE.diss.ergm` control arguments to `control.stergm()`).
  Furthermore, the arguments `MCMC.init.maxedges` 
  and `MCMC.init.maxchanges` to `control.stergm()` have been replaced by the 
  `MCMC.maxedges` and `MCMC.maxchanges` arguments to `control.tergm()`; these
  arguments have also been replaced in `control.stergm()`, so code continuing
  to use the old interface will still need to change from using 
  `MCMC.init.maxedges` and `MCMC.init.maxchanges` to using `MCMC.maxedges` and 
  `MCMC.maxchanges`.  
  
  Our discussion of initial coefficient values below will also include the 
  necessary control argument changes for our examples above.

- The initial coefficient specifications for the formation and dissolution
  models, if passed, should be combined into a specification of initial
  coefficients for the combined model.  This can be done through the `tergm`
  function's `offset.coef`, `control$init`, and/or `control$CMLE.ergm$init`
  arguments (the final one applying only to the CMLE case).  If `offset.coef`
  is passed, it should have length equal to the number of offset thetas in the
  combined model, and if `control$init` or `control$CMLE.ergm$init` is passed, 
  it should have length equal to the total number of thetas in the combined 
  model.  (`NA`s may be used in `control$init` or `control$CMLE.ergm$init` to 
  indicate that initial values for those (non-offset) thetas are not being 
  passed.)  Here `control` refers to the `control.tergm` class control 
  discussed in the previous bullet point.

  In our examples, the CMLE call specifies initial coefficient values through
  `control$CMLE.control.*$init`.  We can combine these into 
  `control$CMLE.ergm$init` as
  
  ```
  control = control.tergm(CMLE.ergm = control.ergm(init = c(-3.5,2,0,NA,0,1,0,1/2)))
  ```  
  
  noting that we also replaced `control.stergm()` with `control.tergm()`.  We 
  can simplify this further by exploiting new control list flattening 
  features, writing 
  
  ```
  control = snctrl(init = c(-3.5,2,0,NA,0,1,0,1/2))
  ```  

  instead.  
  
  The EGMME call specifies only a single dissolution offset, which we can 
  specify through `offset.coef` as 
  
  ```
  offset.coef = log(9)
  ```

Overall, this produces the new-style calls

```
data(samplk)
samp <- list(samplk1, samplk2, samplk3)
samp.fit <- tergm(samp ~ Form(~edges+mutual+cyclicalties+transitiveties) + 
                         Persist(~edges+mutual+cyclicalties+transitiveties),
                  estimate = "CMLE",
                  times = 1:3,
                  control = snctrl(init = c(-3.5,2,0,NA,0,1,0,1/2)))
```

for CMLE, and

```
data(florentine)
tergm.fit.1 <- tergm(flobusiness ~ Form(~edges+gwesp(0,fixed=T)) + 
                                   Persist(~offset(edges)),
                     targets = "formation",
                     offset.coef = log(9),
                     estimate = "EGMME",
                     control = control.tergm(SA.plot.progress=TRUE))
```

for EGMME.

# Simulation #

## From a fitted `tergm` object ##

A call in `tergm` 3.x for simulating from a fitted `stergm` might look 
something like

```
stergm.sim.1 <- simulate(stergm.fit.1, 
                         stats.form = TRUE,
                         nsim = 1,
                         time.slices = 1000,
                         control = control.simulate.stergm(MCMC.init.maxchanges = 10000))
```

There is no `simulate.stergm` function in `tergm` 4.0, only a `simulate.tergm` 
function, so the changes described in this section are generally mandatory, 
with the exception of the control list class, which can be left as 
`control.simulate.stergm` if desired (although this is not recommended).
Even if one calls the old `stergm()` function to estimate the model, calling
`simulate` on the returned object will dispatch to the `simulate.tergm` 
function described here.

To convert from simulating a fitted `stergm` in `tergm` 3.x to simulating a 
fitted `tergm` in `tergm` 4.0, we make the following changes.

- Replace the `coef.form` and `coef.diss` arguments (which will default to the 
  coefficients of the fitted `stergm`) with the `coef` argument (which will 
  default to the coefficients of the fitted `tergm`), which is schematically of 
  the form `coef = c(coef.form, coef.diss)`, assuming the combined formula used 
  when estimating the `tergm` was of the form described in the Estimation 
  section (with `Form(formation formula)` preceding 
  `Persist(dissolution formula)`).
  
  These arguments are not passed in the example 
  above, so no corresponding changes are needed in that example.

- Replace the `stats.form` and `stats.diss` arguments (if passed) with the 
  `stats` argument, which will give all generative model statistics if set to
  `TRUE`.
  
  In the example above, we pass `stats.form = TRUE`, so in
  the 4.0 version of the call, we will set `stats = TRUE`.

- The control argument (if passed), previously of class 
  `control.simulate.stergm`, should be replaced by one of class 
  `control.simulate.tergm`.  This can be accomplished by replacing 
  `control.simulate.stergm()` with `control.simulate.tergm()`, `snctrl()`, or 
  `list()`, and updating arguments as follows.  Arguments to 
  `control.simulate.stergm()` occurring in pairs with `.form` and `.diss` in 
  their names have been collapsed to single, correspondingly named arguments to 
  `control.simulate.tergm()` without `.form` or `.diss`.  Additionally, the 
  arguments `MCMC.init.maxedges` and `MCMC.init.maxchanges` to 
  `control.simulate.stergm()` have been replaced by the `MCMC.maxedges` and 
  `MCMC.maxchanges` arguments to `control.simulate.tergm()`; these arguments
  have also been replaced in `control.simulate.stergm()`, so code continuing 
  to use `control.simulate.stergm()` will still need to change from using 
  `MCMC.init.maxedges` and `MCMC.init.maxchanges` to using `MCMC.maxedges` and 
  `MCMC.maxchanges`.
  
  In the example above, we passed `MCMC.init.maxchanges = 10000`; since this is
  enough to accomodate all expected changes throughout the entire simulation, 
  we will pass
  
  ```
  control = snctrl(MCMC.maxchanges = 10000)
  ```
  
  in the 4.0 version of the call.

Thus, dropping the s from the object names for consistency, we obtain the 4.0
style call

```
tergm.sim.1 <- simulate(tergm.fit.1, 
                        stats = TRUE,
                        nsim = 1,
                        time.slices = 1000,
                        control = snctrl(MCMC.maxchanges = 10000))
```

## From a network (or networkDynamic) ##

A call in `tergm` 3.x for simulating based on a starting network (or 
networkDynamic), along with specified formation and dissolution formulas and 
coefficients, might look something like

```
stergm.sim.2 <- simulate(flobusiness, 
                         formation = ~edges+gwesp(0,fixed=T),
                         dissolution = ~edges, 
                         monitor = "formation",
                         coef.form = c(-7.981749, 1.575780), 
                         coef.diss = log(99),
                         time.slices = 50000)
```

To convert from simulating based on a starting network in `tergm` 3.x to 
simulating based on a starting network in `tergm` 4.0, we make the following 
changes.

- Combine the network, formation, and dissolution formulas into a single 
  formula, schematically of the form 

  ```
  network ~ Form(formation formula) + 
            Persist(dissolution formula)
  ```
  
  as for estimation.

- Combine the `coef.form` and `coef.diss` arguments into a single `coef` 
  argument, schematically of the form `coef = c(coef.form, coef.diss)`, 
  assuming the combined formula is specified as in the previous bullet point
  (with `Form(formation formula)` preceding `Persist(dissolution formula)`).

- The control argument (if passed), previously of class 
  `control.simulate.network`, should be replaced by one of class 
  `control.simulate.formula.tergm`.  This can be accomplished by replacing 
  `control.simulate.network()` with `control.simulate.formula.tergm()`, 
  `snctrl()`, or `list()`, and updating arguments as when simulating from a 
  fitted `tergm`.

- Combine the `stats.form` and `stats.diss` arguments (if passed) into a 
  single `stats` argument.

- Pass `dynamic = TRUE` to indicate that you want dynamic `tergm` simulation.

Thus, we obtain the 4.0 simulation call

```
tergm.sim.2 <- simulate(flobusiness ~ Form(~edges+gwesp(0,fixed=T)) +
                                      Persist(~edges),
                        monitor = "formation",
                        coef = c(-7.981749, 1.575780, log(99)), 
                        time.slices = 50000,
                        dynamic = TRUE)
```

<!-- # Some Technical Points # -->
<!-- perhaps to be added later -->