Skip to content

Add edist term for spatial network models - #659

Closed
smjenness wants to merge 1 commit into
masterfrom
edist-term
Closed

Add edist term for spatial network models#659
smjenness wants to merge 1 commit into
masterfrom
edist-term

Conversation

@smjenness

Copy link
Copy Markdown
Member

Adds an edist ERGM term. For each edge it contributes the Euclidean distance between the two incident nodes in a space defined by two or more numeric nodal coordinates (e.g., edist(c("lat", "long"))), optionally raised to one or more powers.

What it does

For an edge between nodes i and j with numeric coordinate attributes, edist contributes d_ij = sqrt(sum_k (x_ik - x_jk)^2), optionally raised to each requested power.

~edges + edist(c("lat", "long"))                 # Euclidean distance
~edges + edist(c("lat", "long"), pow = 2)        # squared Euclidean distance
~edges + edist(c("lat", "long"), pow = c(1, 2))  # polynomial in distance

The pow argument controls whether the log-odds of a tie are linear or non-linear in distance. pow = 1 (default) is linear in Euclidean distance, pow = 2 gives a Gaussian-type decay in tie probability, larger powers decline more sharply, and a vector of powers adds one statistic per power so a single term fits a polynomial in distance.

Why a dedicated term

edgecov with a precomputed distance matrix can do the same thing but costs O(n^2) memory. The Sum/Prod operators reach squared Euclidean distance but not true Euclidean distance, because they compose statistics already summed over edges, so a square root there gives sqrt(sum_edges d^2) rather than sum_edges d. The square root has to be applied per dyad, inside the change statistic, before summing. edist computes the distance on the fly from the length-n coordinate vectors, so memory is O(n).

Implementation

  • src/changestats.c: c_edist, a dyad-independent change statistic that reads the coordinate matrix and the pow vector from the term inputs and emits one statistic per power.
  • R/InitErgmTerm.R: InitErgmTerm.edist, using ergm_get_vattr(..., multiple = "matrix") to gather the coordinate columns. Requires two or more dimensions and errors otherwise, pointing single-dimension users to absdiff.
  • Works for both directed and undirected networks.
  • roxygen term documentation and an inst/NEWS.Rd item.

Testing

tests/testthat/test-term-edist.R covers:

  • summary statistics for pow = 1, pow = 2, pow = 1.5, and vector pow, including coefficient names.
  • change statistics under interleaved add/remove toggles via ergm.godfather.
  • the two-dimension minimum error.
  • three-dimensional coordinates.
  • directed networks.
  • estimation with ergm() and simulation.

All pass locally, and the existing term tests are unaffected.

Ported from EpiModel/EpiModel#1052, which adds the same term as an EpiModel user term. That PR stays open until this one lands; the term is a better fit here as a general spatial ERGM term.

Adds an edist term that contributes, per edge, the Euclidean distance
between the two incident nodes in a space defined by two or more numeric
nodal coordinates (e.g., edist(c("lat", "long"))), optionally raised to
one or more powers.

The pow argument sets the functional form of distance dependence in the
log-odds of a tie: pow = 1 (default) is linear in Euclidean distance,
pow = 2 is squared Euclidean distance (Gaussian-type decay), and a vector
such as pow = c(1, 2) fits a polynomial in distance. Distances are
computed on the fly from the length-n coordinate vectors, so memory use
is linear rather than quadratic in network size, unlike an equivalent
edgecov distance matrix.

The statistic is dyad-independent and works for both directed and
undirected networks. Implementation is a c_edist change statistic in
changestats.c and an InitErgmTerm.edist definition in InitErgmTerm.R,
with distances read on the fly from a coordinate matrix passed through
the term inputs. Includes unit tests covering summary and change
statistics across scalar and vector powers, the two-dimension minimum,
and three-dimensional coordinates.
@CarterButts

CarterButts commented Jul 26, 2026 via email

Copy link
Copy Markdown

@CarterButts

Copy link
Copy Markdown

I'm going to go ahead and put in a fork with the fancier term and will submit a pull request for that; this should be more straightforward than having folks use an add-on package.

@smjenness

Copy link
Copy Markdown
Member Author

Closing as this better addressed in #660

@smjenness smjenness closed this Jul 28, 2026
@smjenness
smjenness deleted the edist-term branch July 28, 2026 17:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants