88# Copyright 2008-2025 Statnet Commons
99# ###############################################################################
1010
11- .call_N <- function (term , nw , arglist , ... , env = baseenv()){
11+ .call_N <- function (term , nw , arglist , ... , env = baseenv(),
12+ ownargs = list (varnames = " formula" , vartypes = " formula" , defaultvalues = list (NULL ), required = TRUE )) {
1213 a <- check.ErgmTerm(nw , arglist ,
13- varnames = c(" formula " , " lm" , " subset" , " weights" , " contrasts" , " offset" , " label" ),
14- vartypes = c(" formula " , " formula" , " formula,logical,numeric,expression,call" , " formula,logical,numeric,expression,call" , " list" , " formula,logical,numeric,expression,call" , " character" ),
15- defaultvalues = list ( NULL , ~ 1 , TRUE , 1 , NULL , NULL , NULL ),
16- required = c(TRUE , FALSE , FALSE , FALSE , FALSE , FALSE , FALSE ))
14+ varnames = c(ownargs $ varnames , " lm" , " subset" , " weights" , " contrasts" , " offset" , " label" ),
15+ vartypes = c(ownargs $ vartypes , " formula" , " formula,logical,numeric,expression,call" , " formula,logical,numeric,expression,call" , " list" , " formula,logical,numeric,expression,call" , " character" ),
16+ defaultvalues = c( ownargs $ defaultvalues , list ( ~ 1 , TRUE , 1 , NULL , NULL , NULL ) ),
17+ required = c(ownargs $ required , FALSE , FALSE , FALSE , FALSE , FALSE , FALSE ))
1718
1819 f <- a $ formula
19- ult(f ) <- call(paste0(term ," 1" ), as.formula(call(" ~" ,ult(f )), env = env )) # e.g., a~b -> a~term1(~b)
20+ # e.g., a~b -> a~term1(~b)
21+ ult(f ) <- as.call(c(list (paste0(term ," 1" ),
22+ as.formula(call(" ~" ,ult(f )), env = env )),
23+ a [setdiff(ownargs $ varnames , " formula" )]))
2024 environment(f ) <- environment(a $ formula )
2125 a $ formula <- f
2226
3337# ' @template ergmTerm-rdname
3438# ' @usage NULL
3539# ' @template ergmTerm-N-arguments
40+ # ' @concept temporal
3641InitErgmTerm.Form <- function (nw , arglist , ... ){
3742 if (! is(nw , " tergm_NetSeries" )) `InitErgmTerm.Form (dynamic)`(nw = nw , arglist = arglist , ... )
3843 else .call_N(" Form" , nw , arglist , ... )
@@ -62,6 +67,7 @@ InitErgmTerm.Form1 <- function(nw, arglist, ...){
6267# ' @template ergmTerm-rdname
6368# ' @usage NULL
6469# ' @template ergmTerm-N-arguments
70+ # ' @concept temporal
6571InitErgmTerm.Persist <- function (nw , arglist , ... ) {
6672 if (! is(nw , " tergm_NetSeries" )) `InitErgmTerm.Persist (dynamic)`(nw = nw , arglist = arglist ,... )
6773 else .call_N(" Persist" , nw , arglist , ... )
@@ -113,6 +119,7 @@ InitErgmTerm.Diss1 <- function(nw, arglist, ..., env){
113119# ' @template ergmTerm-rdname
114120# ' @usage NULL
115121# ' @template ergmTerm-N-arguments
122+ # ' @concept temporal
116123InitErgmTerm.Change <- function (nw , arglist , ... ) {
117124 if (! is(nw , " tergm_NetSeries" )) `InitErgmTerm.Change (dynamic)`(nw = nw , arglist = arglist , ... )
118125 else .call_N(" Change" , nw , arglist , ... )
@@ -165,6 +172,7 @@ InitErgmTerm.Change1 <- function(nw, arglist, ...){
165172# ' @rawNamespace import(ergm.multi, except=c("snctrl"))
166173# '
167174# ' @concept operator
175+ # ' @concept temporal
168176# ' @concept durational
169177InitErgmTerm.Cross <- function (nw , arglist , ... , env = baseenv()) {
170178 if (! is(nw , " tergm_NetSeries" )) `InitErgmTerm.Cross (dynamic)`(nw = nw , arglist = arglist , ... )
@@ -181,3 +189,104 @@ InitErgmTerm.Cross1 <- function(nw, arglist, ...){
181189
182190 ergm_model(a $ formula , nw , ... , terms.only = TRUE )
183191}
192+
193+
194+ # ' @templateVar name Lag
195+ # ' @title An edge covariate on the previous network's statistics
196+ # ' @description This term takes an ERGM formula that is evaluated on a
197+ # ' previous time step's network; the change statistics (optionally
198+ # ' transformed) are used as an edge covariate for the current
199+ # ' network. That is, a statistic of the form \eqn{\sum_{i,j}
200+ # ' y^{t}_{i,j} \Delta_{i,j} g(y^{t-1})} or a transformed variant
201+ # ' \eqn{\sum_{i,j} y^{t}_{i,j} f(\Delta_{i,j} g(y^{t-1}),
202+ # ' y^{t-1}_{i,j})}, where \eqn{Delta_{i,j} g(y) = g(y+(i,j)) -
203+ # ' g(y-(i,j))}.
204+ # '
205+ # ' @usage
206+ # ' # binary: Lag(
207+ # ' # formula,
208+ # ' # lag = 1,
209+ # ' # transform = NULL,
210+ # ' # lm = ~1,
211+ # ' # subset = TRUE,
212+ # ' # weights = 1,
213+ # ' # contrasts = NULL,
214+ # ' # offset = 0,
215+ # ' # label = NULL
216+ # ' # )
217+ # ' @template ergmTerm-formula
218+ # ' @param lag how many time steps to look back; at this time, only 1
219+ # ' is implemented.
220+ # ' @param transform a `function(x, y)` given an array of covariates
221+ # ' and the sociomatrix of the *previous* network to optionally
222+ # ' transform `x`, `NULL` to leave unchanged, or a character string
223+ # ' indicating a preset; current presets include \describe{
224+ # '
225+ # ' \item{`"signed"`}{multiplies each change statistic by \eqn{(2
226+ # ' y^{t-1}_{i,j} - 1)}}
227+ # '
228+ # ' \item{`"nonzero"`, "`positive`", "`negative`"}{indicator of whether
229+ # ' the change statistic has the respective value}
230+ # '
231+ # ' }
232+ # ' @template ergmTerm-N-arguments
233+ # '
234+ # ' @template ergmTerm-general
235+ # '
236+ # ' @references
237+ # '
238+ # ' Almquist, Z. W. and Butts, C. T. (2014). Logistic Network
239+ # ' Regression for Scalable Analysis of Networks with Joint Edge/Vertex
240+ # ' Dynamics. *Sociological Methodology*, 44(1),
241+ # ' 273-321. \doi{10.1177/0081175013520159}
242+ # '
243+ # ' @concept operator
244+ # ' @concept temporal
245+ # ' @concept dyad-independent
246+ InitErgmTerm.Lag <- function (nw , arglist , ... , env = baseenv()) {
247+ if (! is(nw , " tergm_NetSeries" )) ergm_Init_stop(" This term does not support non-netseries input at this time." )
248+ ownargs <- list (varnames = c(" formula" , " lag" , " transform" ),
249+ vartypes = c(" formula" , " numeric" , " function,character" ),
250+ defaultvalues = list (NULL , 1 , function (x , ... ) x ),
251+ required = c(TRUE , FALSE , FALSE ))
252+ .call_N(" Lag" , nw , arglist , ownargs = ownargs , ... , env = env )
253+ }
254+
255+ InitErgmTerm.Lag1 <- function (nw , arglist , ... ) {
256+ a <- check.ErgmTerm(nw , arglist ,
257+ varnames = c(" formula" , " lag" , " transform" ),
258+ vartypes = c(" formula" , " numeric" , " function,formula,character" ),
259+ defaultvalues = list (NULL , 1 , NULL ),
260+ required = c(TRUE , FALSE , FALSE ))
261+
262+ NVL(a $ transform ) <- function (x , ... ) x
263+
264+ if (is.character(a $ transform )) {
265+ presets <- c(" signed" , " nonzero" , " positive" )
266+ a $ transform <- switch (match.arg(a $ transform , presets ),
267+ signed = function (x , y , ... ) c(2 * y - 1 )* x ,
268+ nonzero = function (x , ... ) x != 0 ,
269+ positive = function (x , ... ) x > 0 ,
270+ negative = function (x , ... ) x < 0 ,
271+ ergm_Init_stop(sQuote(a $ transform ), " is not a valid preset; currently valid presets include " , paste.and(sQuote(presets )), " ." ))
272+ }
273+
274+ if (a $ lag != 1 ) ergm_Init_stop(" Lags other than 1 are not currently implemented." )
275+
276+ mple <- ergmMPLE(a $ formula , basis = (nw %n %" .PrevNets" )[[1 ]],
277+ expand.bipartite = TRUE , output = " array" )
278+ y <- mple $ response
279+ x <- mple $ predictor
280+
281+ pred <- a $ transform(x = x , y = y )
282+ if (ncol(pred ) == 0 ) ergm_Init_stop(" Formula produced 0 statistics." )
283+
284+ terms <- imap(dimnames(pred )[[3 ]],
285+ function (nm , i ) term_list(call(" edgecov" , x = pred [, , i ], attrname = nm ), env = environment(a $ formula ))) | >
286+ do.call(c , args = _)
287+
288+ m <- ergm_model(terms , nw , ... , terms.only = TRUE )
289+ param_names(m ) <- map(list (param_names(m , canonical = FALSE ), param_names(m , canonical = TRUE )),
290+ substring , 9 , 10000 )
291+ m
292+ }
0 commit comments