/** * Random Numbers and Testing. */ #include #include #include #include /** * Much of the next bit follows * http://www.stat.uiowa.edu/~luke/R/references/weakfinex.html * * This is not well documented in Luke's web page, but I've put the * stream pointer in as the "key" of the weak pointer list, and the * NeticaCaseStream object as the "value". This allows me to set the * pointer to NULL when I'm closing all open streams, say on detatch. */ /** * Finalizer: calling this multiple times should be harmless. */ SEXP RNGFree (SEXP rngptr) { randgen_ns *rng_handle; if (rngptr == NULL || isNull(rngptr)) { //Already closed, nothing to do } else { if (TYPEOF(rngptr) != EXTPTRSXP || R_ExternalPtrTag(rngptr) != rngatt) { warning("Trying to free a non-rng pointer"); } else { rng_handle = (randgen_ns*) R_ExternalPtrAddr(rngptr); if (rng_handle != NULL) { DeleteRandomGen_ns(rng_handle); R_ClearExternalPtr(rngptr); } } } return R_NilValue; } void AddRNGRef(SEXP ref) { SEXP r, rngs, next=NULL, last=NULL; rngs = CDR(RngList); for (r = rngs; r != R_NilValue; r = next) { SEXP rr = CAR(r); SEXP key = R_WeakRefKey(rr); next = CDR(r); if (key == R_NilValue || R_ExternalPtrAddr(key)==NULL) { if (last == NULL) rngs = next; else SETCDR(last,next); } else { last = r; } } SETCDR(CaseStreamList, CONS(ref,rngs)); } void FreeRNGs () { SEXP r, rngs, next=NULL, last=NULL; rngs = CDR(RngList); for (r = rngs; r != R_NilValue; r = next) { SEXP rr = CAR(r); SEXP key = R_WeakRefKey(rr); SEXP rng = R_WeakRefValue(rr); next = CDR(r); if (key != R_NilValue) { RNGFree(key); if (rng && rng != R_NilValue) { setAttrib(rng,rngatt,R_NilValue); } } } } SEXP RN_isRNGActive(SEXP rng) { SEXP rngPtr, result; PROTECT(result=allocVector(LGLSXP,1)); LOGICAL(result)[0]=FALSE; PROTECT(rngPtr = getAttrib(rng,rngatt)); if (!isNull(rngPtr) && R_ExternalPtrAddr(rngPtr)) { LOGICAL(result)[0] = TRUE; } UNPROTECT(2); return result; } SEXP RN_NewRandomGenerator (SEXP seed) { const char* seedstring=CHAR(STRING_ELT(seed,0)); randgen_ns* rng = NewRandomGenerator_ns (seedstring,RN_netica_env, NULL); if (rng == NULL ) return R_NilValue; else { SEXP rngsexp, rngPtr, ref; //Allocate new rng object PROTECT(rngsexp = allocVector(STRSXP,1)); SET_STRING_ELT(rngsexp,0,mkChar(seedstring)); SET_CLASS(rngsexp,rngclass); PROTECT(rngPtr = R_MakeExternalPtr(rng,rngatt, R_NilValue)); setAttrib(rngsexp,rngatt,rngPtr); PROTECT(ref = R_MakeWeakRefC(rngPtr,rngsexp, (R_CFinalizer_t) &RNGFree, TRUE)); AddRNGRef(ref); UNPROTECT(3); return rngsexp; } } /** * Tests whether or not an object is a Netica RNG. */ int isNeticaRNG(SEXP obj) { SEXP klass; int result = FALSE; PROTECT(klass = getAttrib(obj,R_ClassSymbol)); R_len_t k, kk=length(klass); for (k=0; k