Skip to content

Commit

Permalink
Merge branch 'master' into triadic-proposal
Browse files Browse the repository at this point in the history
  • Loading branch information
krivit committed May 16, 2024
2 parents 35ae128 + cf9d2ae commit 0e5b2ca
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 203 deletions.
2 changes: 1 addition & 1 deletion inst/include/ergm_changestats_auxnet.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
#include "ergm_changestat_auxnet.h"
#include "ergm_dyad_hashmap.h"

typedef struct{StoreDyadSet *nwp; int *ref_el;} StoreDyadSetAndRefEL;
typedef struct{StoreStrictDyadSet *nwp; int *ref_el;} StoreStrictDyadSetAndRefEL;

#define map_toggle_maxtoggles__discord_net_Network 1
MAP_TOGGLE_FN(map_toggle__discord_net_Network){
Expand Down
123 changes: 80 additions & 43 deletions inst/include/ergm_dyad_hashmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ typedef struct TailHead_s{

/* Helper macros to construct TailHeads with the correct ordering. */
#define TH(T,H) ((TailHead){.tail=(T),.head=(H)})
#define UTH(tail, head) tail < head ? TH(tail, head) : TH(head, tail)

/* Hash and comparison functions designed for tail-head pairs. */
// The of macro-ing this due to Bob Jenkins.
Expand All @@ -45,62 +46,98 @@ static inline unsigned int kh_scramble_int(unsigned int a){
#define kh_vertexvertex_hash_func(key) (khint32_t) (((key).tail<(key).head || h->directed) ? ((key).tail + (key).head*0xd7d4eb2du) : ((key).head + (key).tail*0xd7d4eb2du))
#define kh_vertexvertex_hash_equal(a,b) ((a.tail==b.tail && a.head==b.head) || (!h->directed && a.tail==b.head && a.head==b.tail))

#define kh_vertexvertex_strict_hash_func(key) (khint32_t) ((key).tail + (key).head*0xd7d4eb2du)
#define kh_vertexvertex_strict_hash_equal(a,b) (a.tail==b.tail && a.head==b.head)

/* Accessors, modifiers, and incrementors. */
#define AccessorTemplate(fname, type, valtype, th_impl) \
static inline valtype GET ## fname (Vertex tail, Vertex head, Store ## type *hashmap){ \
return kh_getval(type, hashmap, th_impl, 0); \
} \
static inline void SET ## fname (Vertex tail, Vertex head, valtype v, Store ## type *hashmap){ \
if(v == (valtype)0){ \
kh_unset(type, hashmap, th_impl); \
}else{ \
kh_set(type, hashmap, th_impl, v); \
} \
} \
static inline valtype HAS ## fname (Vertex tail, Vertex head, Store ## type *hashmap){ \
return kh_get(type, hashmap, th_impl) != kh_none; \
} \
static inline void DEL ## fname (Vertex tail, Vertex head, Store ## type *hashmap){ \
kh_unset(type, hashmap, th_impl); \
} \
static inline void SET ## fname ## 0 (Vertex tail, Vertex head, valtype v, Store ## type *hashmap){ \
kh_set(type, hashmap, th_impl, v); \
}

#define IncDyadMapTemplate(fname, type, valtype, th_impl) \
static inline void fname(Vertex tail, Vertex head, int inc, Store ## type *h){ \
TailHead th = th_impl; \
if(inc!=0){ \
khiter_t pos = kh_get(type, h, th); \
valtype val = pos==kh_none ? 0 : kh_value(h, pos); \
val += inc; \
if(val==0){ \
kh_del(type, h, pos); \
}else{ \
if(pos==kh_none) \
pos = kh_put(type, h, th, NULL); \
kh_val(h, pos) = val; \
} \
} \
}


/* Predefined khash type for mapping dyads onto unsigned ints. */
KHASH_INIT(DyadMapUInt, TailHead, unsigned int, TRUE, kh_vertexvertex_hash_func, kh_vertexvertex_hash_equal, Rboolean directed;)
typedef khash_t(DyadMapUInt) StoreDyadMapUInt;
AccessorTemplate(DMUI, DyadMapUInt, unsigned int, TH(tail,head))
IncDyadMapTemplate(IncDyadMapUInt, DyadMapUInt, unsigned int, TH(tail, head))

/* Accessors, modifiers, and incrementors. */
#define GETDMUI(tail, head, hashmap)(kh_getval(DyadMapUInt, hashmap, TH(tail,head), 0))
#define SETDMUI(tail, head, v, hashmap) {if(v==0) kh_unset(DyadMapUInt, hashmap, TH(tail,head)); else kh_set(DyadMapUInt, hashmap, TH(tail,head), v)}
#define HASDMUI(tail, head, hashmap)(kh_get(DyadMapUInt, hashmap, TH(tail,head))!=kh_none)
#define DELDMUI(tail, head, hashmap)(kh_unset(DyadMapUInt, hashmap, TH(tail,head)))
#define SETDMUI0(tail, head, v, hashmap) {kh_set(DyadMapUInt, hashmap, TH(tail,head), v)}

static inline void IncDyadMapUInt(Vertex tail, Vertex head, int inc, StoreDyadMapUInt *h){
TailHead th = TH(tail, head);
if(inc!=0){
khiter_t pos = kh_get(DyadMapUInt, h, th);
unsigned int val = pos==kh_none ? 0 : kh_value(h, pos);
val += inc;
if(val==0){
kh_del(DyadMapUInt, h, pos);
}else{
if(pos==kh_none)
pos = kh_put(DyadMapUInt, h, th, NULL);
kh_val(h, pos) = val;
}
}
}
KHASH_INIT(StrictDyadMapUInt, TailHead, unsigned int, TRUE, kh_vertexvertex_strict_hash_func, kh_vertexvertex_strict_hash_equal,)
typedef khash_t(StrictDyadMapUInt) StoreStrictDyadMapUInt;
AccessorTemplate(DDMUI, StrictDyadMapUInt, unsigned int, TH(tail,head))
AccessorTemplate(UDMUI, StrictDyadMapUInt, unsigned int, UTH(tail, head))
IncDyadMapTemplate(IncDDyadMapUInt, StrictDyadMapUInt, unsigned int, TH(tail, head))
IncDyadMapTemplate(IncUDyadMapUInt, StrictDyadMapUInt, unsigned int, UTH(tail, head))

/* Predefined khash type for mapping dyads onto signed ints. */
KHASH_INIT(DyadMapInt, TailHead, int, TRUE, kh_vertexvertex_hash_func, kh_vertexvertex_hash_equal, Rboolean directed;)
typedef khash_t(DyadMapInt) StoreDyadMapInt;
AccessorTemplate(DMI, DyadMapInt, int, TH(tail,head))
IncDyadMapTemplate(IncDyadMapInt, DyadMapInt, int, TH(tail, head))

/* Accessors, modifiers, and incrementors. */
#define GETDMI(tail, head, hashmap)(kh_getval(DyadMapInt, hashmap, TH(tail,head), 0))
#define SETDMI(tail, head, v, hashmap) {if(v==0) kh_unset(DyadMapInt, hashmap, TH(tail,head)); else kh_set(DyadMapInt, hashmap, TH(tail,head), v)}
#define HASDMI(tail, head, hashmap)(kh_get(DyadMapInt, hashmap, TH(tail,head))!=kh_none)
#define DELDMI(tail, head, hashmap)(kh_unset(DyadMapInt, hashmap, TH(tail,head)))
#define SETDMI0(tail, head, v, hashmap) {kh_set(DyadMapInt, hashmap, TH(tail,head), v)}
KHASH_INIT(StrictDyadMapInt, TailHead, int, TRUE, kh_vertexvertex_strict_hash_func, kh_vertexvertex_strict_hash_equal,)
typedef khash_t(StrictDyadMapInt) StoreStrictDyadMapInt;
AccessorTemplate(DDMI, StrictDyadMapInt, int, TH(tail,head))
AccessorTemplate(UDMI, StrictDyadMapInt, int, UTH(tail, head))
IncDyadMapTemplate(IncDDyadMapInt, StrictDyadMapInt, int, TH(tail, head))
IncDyadMapTemplate(IncUDyadMapInt, StrictDyadMapInt, int, UTH(tail, head))

/* Predefined khash type for dyad sets. This may or may not be faster than edgetree. */
KHASH_INIT(DyadSet, TailHead, char, FALSE, kh_vertexvertex_hash_func, kh_vertexvertex_hash_equal, Rboolean directed;)
typedef khash_t(DyadSet) StoreDyadSet;

// Toggle an element of a DyadSet.
static inline Rboolean DyadSetToggle(Vertex tail, Vertex head, StoreDyadSet *h){
TailHead th = TH(tail, head);
kh_put_code ret;
// Attempt insertion
khiter_t i = kh_put(DyadSet, h, th, &ret);
if(ret==0){
// Already present: delete
kh_del(DyadSet, h, i);
return FALSE;
}else{
// Inserted by kh_put above
return TRUE;
#define DyadSetToggleTemplate(fname, type, th_impl) \
static inline Rboolean fname(Vertex tail, Vertex head, Store ## type *h){ \
TailHead th = th_impl; \
kh_put_code ret; \
khiter_t i = kh_put(type, h, th, &ret); \
if(ret==0){ \
kh_del(type, h, i); \
return FALSE; \
}else{ \
return TRUE; \
} \
}
}

KHASH_INIT(DyadSet, TailHead, char, FALSE, kh_vertexvertex_hash_func, kh_vertexvertex_hash_equal, Rboolean directed;)
typedef khash_t(DyadSet) StoreDyadSet;
DyadSetToggleTemplate(DyadSetToggle, DyadSet, TH(tail, head))

KHASH_INIT(StrictDyadSet, TailHead, char, FALSE, kh_vertexvertex_strict_hash_func, kh_vertexvertex_strict_hash_equal,)
typedef khash_t(StrictDyadSet) StoreStrictDyadSet;
DyadSetToggleTemplate(DDyadSetToggle, StrictDyadSet, TH(tail, head))
DyadSetToggleTemplate(UDyadSetToggle, StrictDyadSet, UTH(tail, head))

#endif // _ERGM_DYAD_HASHMAP_H_
3 changes: 3 additions & 0 deletions inst/include/ergm_dyad_hashmap_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@

/* Utility function declarations. */
void PrintDyadMapUInt(StoreDyadMapUInt *h);
void PrintStrictDyadMapUInt(StoreStrictDyadMapUInt *h);
void PrintDyadSet(StoreDyadSet *h);
void PrintStrictDyadSet(StoreStrictDyadSet *h);
StoreDyadSet *NetworkToDyadSet(Network *nwp);
StoreStrictDyadSet *NetworkToStrictDyadSet(Network *nwp);

#endif // _ERGM_DYAD_HASHMAP_H_
29 changes: 14 additions & 15 deletions inst/include/ergm_hash_edgelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,43 +22,42 @@

typedef struct {
UnsrtEL *list;
StoreDyadMapUInt *hash;
StoreStrictDyadMapUInt *hash;
} HashEL;

/* Embed an existing UnsrtEL into a HashEL. */
static inline HashEL *UnsrtELIntoHashEL(UnsrtEL *el, Rboolean directed) {
static inline HashEL *UnsrtELIntoHashEL(UnsrtEL *el) {
HashEL *hash = Calloc(1, HashEL);

hash->list = el;

hash->hash = kh_init(DyadMapUInt);
hash->hash->directed = directed;
hash->hash = kh_init(StrictDyadMapUInt);

if(el->nedges > 0) {
kh_resize(DyadMapUInt, hash->hash, 2*(el->nedges + 1));
kh_resize(StrictDyadMapUInt, hash->hash, 2*(el->nedges + 1));

for(unsigned int i = 1; i <= el->nedges; i++) {
kh_set(DyadMapUInt, hash->hash, TH(el->tails[i], el->heads[i]), i);
kh_set(StrictDyadMapUInt, hash->hash, TH(el->tails[i], el->heads[i]), i);
}
}

return hash;
}

static inline HashEL *HashELInitialize(unsigned int nedges, Vertex *tails, Vertex *heads, Rboolean copy, Rboolean directed) {
static inline HashEL *HashELInitialize(unsigned int nedges, Vertex *tails, Vertex *heads, Rboolean copy) {
UnsrtEL *el = UnsrtELInitialize(nedges, tails, heads, copy);
return UnsrtELIntoHashEL(el, directed);
return UnsrtELIntoHashEL(el);
}

static inline void HashELDestroy(HashEL *hash) {
kh_destroy(DyadMapUInt, hash->hash);
kh_destroy(StrictDyadMapUInt, hash->hash);
UnsrtELDestroy(hash->list);
Free(hash);
}

static inline void HashELClear(HashEL *hash) {
UnsrtELClear(hash->list);
kh_clear(DyadMapUInt, hash->hash);
kh_clear(StrictDyadMapUInt, hash->hash);
}

static inline void HashELGetRand(Vertex *tail, Vertex *head, HashEL *hash) {
Expand All @@ -67,20 +66,20 @@ static inline void HashELGetRand(Vertex *tail, Vertex *head, HashEL *hash) {

static inline void HashELInsert(Vertex tail, Vertex head, HashEL *hash) {
kh_put_code r;
khiter_t pos = kh_put(DyadMapUInt, hash->hash, TH(tail, head), &r);
khiter_t pos = kh_put(StrictDyadMapUInt, hash->hash, TH(tail, head), &r);
if(r == kh_put_present) return; // Already in the list.

UnsrtELInsert(tail, head, hash->list);
kh_val(hash->hash, pos) = hash->list->nedges;
}

static inline void HashELDelete(Vertex tail, Vertex head, HashEL *hash) {
khint_t i = kh_get(DyadMapUInt, hash->hash, TH(tail, head));
khint_t i = kh_get(StrictDyadMapUInt, hash->hash, TH(tail, head));
unsigned int index = kh_value(hash->hash, i);
kh_del(DyadMapUInt, hash->hash, i);
kh_del(StrictDyadMapUInt, hash->hash, i);

if(index < hash->list->nedges) {
kh_set(DyadMapUInt,
kh_set(StrictDyadMapUInt,
hash->hash,
TH(hash->list->tails[hash->list->nedges],
hash->list->heads[hash->list->nedges]),
Expand All @@ -99,7 +98,7 @@ static inline void HashELToggleKnown(Vertex tail, Vertex head, HashEL *hash, int
}

static inline unsigned int HashELSearch(Vertex tail, Vertex head, HashEL *hash) {
return kh_getval(DyadMapUInt, hash->hash, TH(tail, head), 0);
return kh_getval(StrictDyadMapUInt, hash->hash, TH(tail, head), 0);
}

#endif // _ERGM_HASH_EDGELIST_H_
2 changes: 1 addition & 1 deletion src/MHproposals.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ MH_I_FN(Mi_BDStratTNT) {
sto->hash[i] = HashELInitialize(els[i]->nedges,
els[i]->tails ? els[i]->tails + 1 : els[i]->tails,
els[i]->heads ? els[i]->heads + 1 : els[i]->heads,
FALSE, DIRECTED);
FALSE);
Free(els[i]);
}
Free(els);
Expand Down
4 changes: 2 additions & 2 deletions src/MHproposals_triadic.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ MH_I_FN(Mi_SPDyad){

MH_P_FN(Mp_SPDyad){
MH_GET_STORAGE(StoreDyadGenAndDegreeBound, storage);
MH_GET_AUX_STORAGE(StoreDyadMapUInt, spcache);
MH_GET_AUX_STORAGE(StoreStrictDyadMapUInt, spcache);

// With probability 1-MH_INPUTS[0], or if no dyad has any shared
// partners, just fall back to TNT. This is OK to do because it is
Expand Down Expand Up @@ -117,7 +117,7 @@ MH_P_FN(Mp_SPDyad){

// The following is setting up to use macros developed for the *sp
// terms.
Rboolean edgeflag = IS_UNDIRECTED_EDGE(*Mtail, *Mhead);
Rboolean edgeflag = IS_OUTEDGE(*Mtail, *Mhead);
int echange = edgeflag ? -1 : +1;
Vertex tail = *Mtail, head = *Mhead;

Expand Down
Loading

0 comments on commit 0e5b2ca

Please sign in to comment.