This vignette documents the C++ convenience wrappers for developing ERGM terms and proposals using modern C++ while interfacing with ergm's core C data structures.
The API partially wraps the Terms and Proposals APIs and focuses on lightweight wrappers (no ownership) around existing C structs to provide: range-based iteration, safer array handling, and access to ->R list elements/attributes.
WARNING: This API is experimental and is subject to change in response to evolving needs and user feedback, but some effort will be made to maintain backwards compatibility. In particular, see the item about namespace versioning below.
inst/include/cpp/ and complement the C headers in inst/include/.src/, typically via #include "cpp/ergm_network.h", #include "cpp/ergm_changestat.h", etc.ergm namespace (e.g., ergm::ErgmCppNetwork); either qualify their names or add using declarations in your translation units.ergm::v1 (currently defaulted); pin explicitly with ergm::v1::ErgmCppNetwork if you need to avoid future breaking changes.mt.stat, mt.dinput, mt.iinput, mt.dattrib, mt.iattrib and, for proposals, p.dinput, p.iinput. Treat these as array-like: use [] for access and .size() for length.nw.nodes(), nw.out_neighbors(i), nw.in_neighbors(i), nw.neighbors(i), and nw.edges() with range-based for loops; for weighted networks, neighbor/edge values include weights.mt.storage / p.storage let you keep a user-defined pointer across calls; mt.aux_storage[i] / p.aux_storage[i] access auxiliaries at position i. (Cast to your type before use.)Init*Ergm*() function can be accessed as mt.R["name"], its attributes as mt.R.attr["name"], and analogously for mt.ext_state. They return SEXP values; use the standard R API to handle them as needed.ErgmCppNetwork and ErgmCppWtNetworkHeaders: #include "cpp/ergm_network.h", #include "cpp/ergm_wtnetwork.h"
These wrap Network (unweighted) and WtNetwork (weighted) to provide edge queries, degree access, and simple iteration.
ErgmCppNetwork nw(nwp); and ErgmCppWtNetwork nw(nwp);nw(tail, head) returns presence (Rboolean) or double weight (0 for no edge).nw.nodes(), bipartite halves: nw.b1(), nw.b2().nw.out_neighbors(i), nw.in_neighbors(i), nw.neighbors(i).nw.out_degree(i), nw.in_degree(i), nw.degree(i).for (auto e : nw.edges()) yields (tail, head).in_ and out_ automatically fall back to the undirected network if nw is undirected.(neighbor, weight); edges() yields (tail, head, weight).Example:
// You can also use nw.edges(), though for an undirected network, the following // code will visit each edge twice, once from each end. ErgmCppNetwork nw(nwp); for(Vertex i : nw.nodes()) { for(Vertex j : nw.out_neighbors(i)) { // process edge i->j } }
ErgmCppWtNetwork nw(nwp); for(auto [j, w] : nw.neighbors(i)) { // weighted edge i->j of weight w } for(auto [i, j, w] : nw.edges()) { // weighted edge i->j of weight w }
ErgmCppModelTerm and ErgmCppWtModelTermHeaders: #include "cpp/ergm_changestat.h", #include "cpp/ergm_wtchangestat.h"
ModelTerm* (or WtModelTerm*)..size() to get lengths):stat: writable stats (double); length via mt.stat.size().dinput, iinput: numeric and integer inputs; lengths via mt.dinput.size() / mt.iinput.size().dattrib, iattrib: attribute slices of inputs if present; lengths via .size().storage: user-defined pointer you manage across calls (mt.storage).aux_storage: access auxiliary storage by index, e.g., auto* my_aux = static_cast<MyType*>(mt.aux_storage[0]).R and ext_state: access term and extended state via mt.R["name"] / mt.ext_state["name"], their attributes via mt.R.attr["name"] and mt.ext_state.attr["name"]ErgmCppProposal and ErgmCppWtProposalHeaders: #include "cpp/ergm_proposal.h", #include "cpp/ergm_wtproposal.h"
MHProposal*.size (Edge&): number of toggles (ntoggles).tail, head (Vertex*), weight (double*, for valued networks): toggle arrays.logratio (double&).dinput, iinput are array-like; use .size() for lengths.storage: user-managed pointer reference (p.storage).aux_storage: access by index if present, e.g., p.aux_storage[0].R: access proposal list elements if needed.The following macros define the C entry point and construct network and model term handles named nw and mt for use in impl:
C_CHANGESTAT_CPP(name, StorageType, impl)S_CHANGESTAT_CPP(name, StorageType, impl)D_CHANGESTAT_CPP(name, StorageType, impl)I_CHANGESTAT_CPP(name, StorageType, impl)U_CHANGESTAT_CPP(name, StorageType, impl)F_CHANGESTAT_CPP(name, StorageType, impl)W_CHANGESTAT_CPP(name, StorageType, impl) (returns SEXP)X_CHANGESTAT_CPP(name, StorageType, impl)Z_CHANGESTAT_CPP(name, StorageType, impl)StorageType can be omitted (i.e., passing only 2 arguments) if no private storage is used.
Weighted counterparts in ergm_wtchangestat.h are prefixed with Wt (e.g., WtC_CHANGESTAT_CPP).
Binary terms: triangle and cycle counts in src/cpp_changestats.cpp.
Valued terms: transitive weights in src/cpp_wtchangestats.cpp.
Proposal: src/MHproposals_triadic.cpp.
FixedArray::size() to avoid out-of-bounds when iterating inputs and stats.aux_storage elements to the correct type before use.Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.