/** * Node.c --- This file contains functions for creating, * destroying, and modifying states of nodes. */ #include #include #include #include //#define DEBUGNODES /*************************************************************************** * Low Level Node Utilities ***************************************************************************/ node_bn* GetNodePtr (SEXP nodeobj) { node_bn* node_ptr = NULL; SEXP exPTR; PROTECT(exPTR=GET_FIELD(nodeobj,nodeatt)); if (exPTR) { node_ptr = (node_bn*) R_ExternalPtrAddr(exPTR); } UNPROTECT(1); return node_ptr; } void SetNodePtr (SEXP nodeobj, node_bn* node_ptr) { SEXP exPTR; PROTECT(exPTR=GET_FIELD(nodeobj,nodeatt)); if (exPTR) { R_SetExternalPtrAddr(exPTR,node_ptr); } else { UNPROTECT(1); PROTECT(exPTR = R_MakeExternalPtr(node_ptr,nodeatt,R_NilValue)); } SET_FIELD(nodeobj,nodeatt,exPTR); UNPROTECT(1); return; } /** * This is a small utility function meant to be used from within * toString to determine if the pointer is live or not. */ SEXP RN_isNodeActive(SEXP node) { SEXP nodePtr, result; PROTECT(result=allocVector(LGLSXP,1)); LOGICAL(result)[0]=FALSE; PROTECT(nodePtr = GET_FIELD(node,nodeatt)); if (nodePtr && nodePtr != R_NilValue && R_ExternalPtrAddr(nodePtr)) { LOGICAL(result)[0] = TRUE; } UNPROTECT(2); return result; } extern SEXP RN_DeactivateNode(SEXP node) { SEXP exPTR; PROTECT(exPTR=GET_FIELD(node,nodeatt)); if (exPTR) { R_ClearExternalPtr(exPTR); } SET_FIELD(node,nodeatt,exPTR); UNPROTECT(1); return node; } /** * Tests whether or not an object is a Netica Node. */ int isNeticaNode(SEXP obj) { return inherits(obj,NodeClass); } SEXP MakeNode(node_bn* node, SEXP bn) { SEXP sname, callme, isDiscrete, nd; PROTECT(sname= allocVector(STRSXP,1)); SET_STRING_ELT(sname,0,mkChar(GetNodeName_bn(node))); if (GetNodeType_bn(node) == DISCRETE_TYPE) { isDiscrete=TRUEV; } else { isDiscrete=FALSEV; } PROTECT(callme=lang4(nodeconstructor,sname,bn,isDiscrete)); SET_TAG(CDR(callme),namefield); SET_TAG(CDDR(callme),netfield); SET_TAG(CDDDR(callme),nodediscatt); PROTECT(nd=eval(callme,R_GlobalEnv)); SetNodePtr(nd,node); RN_RegisterNode(bn,GetNodeName_bn(node),nd); UNPROTECT(3); return nd; } /** * This function allocates a back pointer R object * for a newly created node. */ SEXP MakeNode_RRef(node_bn* node, const char* name, SEXP netobj) { node_bn* old_ptr; SEXP nd, ndhandle; #ifdef DEBUGNODES Rprintf("Searching R net for node named %s.\n",name); #endif PROTECT(nd=RN_FindNodeStr(netobj,name)); if (isNull(nd) || RX_isUnbound(nd)) { /* Didn't find one, need to make a new one. */ #ifdef DEBUGNODES Rprintf("Making a new node named %s.\n",name); #endif UNPROTECT(1); PROTECT(nd=MakeNode(node,netobj)); } old_ptr = GetNodePtr(nd); if (old_ptr && old_ptr != node) { /* Pointer is not null and not equal to the current node: something is wrong. */ error("RNetica Internal error: pointer mismatch for node %s\n",name); } // I think this might be redundant, but too lazy to prove it. #ifdef DEBUGNODES Rprintf("Setting fields for node named %s.\n",name); #endif SetNodePtr(nd,node); SET_FIELD(nd,netfield,netobj); RN_RegisterNode(netobj,name,nd); if (GetNodeType_bn(node) == DISCRETE_TYPE) { SET_FIELD(nd,nodediscatt,TRUEV); } else { SET_FIELD(nd,nodediscatt,FALSEV); } UNPROTECT(1); return nd; } /** * This function allows for the lazy creation of node objects * associated with a network. */ SEXP GetNode_RRef(node_bn *node, SEXP netobj) { const char *name = GetNodeName_bn(node); return MakeNode_RRef(node,name,netobj); } /** * This function removes the R handles from a node so it can be safely * deleted. */ /* No longer needed */ /* void RN_Free_Node(node_bn* node_handle, SEXP bn) { */ /* SEXP node, nodehandle; */ /* if (!node_handle) return; //Void pointer, nothing to do. */ /* node = GetNodeUserData_bn(node_handle,0); */ /* if (!node) return; //No R object, created nothing to do. */ /* PROTECT(node); */ /* PROTECT(nodehandle = getAttrib(node,nodeatt)); */ /* /\* Clear the handle *\/ */ /* if (nodehandle && nodehandle != R_NilValue) { */ /* R_ClearExternalPtr(nodehandle); */ /* } */ /* setAttrib(node,nodeatt,R_NilValue); //Probably not needed. */ /* R_ReleaseObject(node); //Let R garbage collect it when all */ /* //references are gone. */ /* SetNode_RRef(node_handle,NULL); */ /* UNPROTECT(2); */ /* return; */ /* } */ /* void RN_Free_Nodes(const nodelist_bn* nodelist, SEXP net) { */ /* int k, kk=LengthNodeList_bn(nodelist); */ /* for (k=0; k nn) { //Too long, remove states for (ni=n; ni > nn; ) { RemoveNodeState_bn(node_handle,--ni); } } SetNodeStateNames_bn(node_handle,value); } else { warning("Could not find node %s.",NODE_NAME(nd)); } return(nd); } SEXP RN_GetNodeStateTitles(SEXP nd) { R_len_t n, nn; const char *value, *statename; node_bn* node_handle; SEXP result, statenames; node_handle = GetNodeHandle(nd); if (!node_handle) { error("Could not find node %s.",NODE_NAME(nd)); PROTECT(result=allocVector(STRSXP,1)); SET_STRING_ELT(result,0,NA_STRING); } else { //Count number of fields. nn = GetNodeNumberStates_bn(node_handle); PROTECT(result = allocVector(STRSXP,nn)); PROTECT(statenames = allocVector(STRSXP,nn)); for (n=0; n < nn; n++) { statename = GetNodeStateName_bn(node_handle, n); value = GetNodeStateTitle_bn(node_handle, n); SET_STRING_ELT(statenames,n,mkChar(statename)); SET_STRING_ELT(result,n,mkChar(value)); } namesgets(result,statenames); UNPROTECT(1); } UNPROTECT(1); return(result); } SEXP RN_SetNodeStateTitles(SEXP nd, SEXP newvals) { R_len_t n, nn; const char *value; node_bn* node_handle; node_handle = GetNodeHandle(nd); if (!node_handle) { error("Could not find node %s.",NODE_NAME(nd)); return (R_NilValue); } else { //Count number of fields. nn = GetNodeNumberStates_bn(node_handle); for (n=0; n < nn; n++) { value = CHAR(STRING_ELT(newvals,n)); SetNodeStateTitle_bn(node_handle, n, value); } } return(nd); } SEXP RN_GetNodeStateComments(SEXP nd) { R_len_t n, nn; const char *value, *statename; node_bn* node_handle; SEXP result, statenames; node_handle = GetNodeHandle(nd); if (!node_handle) { error("Could not find node %s.",NODE_NAME(nd)); PROTECT(result=allocVector(STRSXP,1)); SET_STRING_ELT(result,0,NA_STRING); } else { //Count number of fields. nn = GetNodeNumberStates_bn(node_handle); PROTECT(result = allocVector(STRSXP,nn)); PROTECT(statenames = allocVector(STRSXP,nn)); for (n=0; n < nn; n++) { statename = GetNodeStateName_bn(node_handle, n); value = GetNodeStateComment_bn(node_handle, n); SET_STRING_ELT(statenames,n,mkChar(statename)); SET_STRING_ELT(result,n,mkChar(value)); } namesgets(result,statenames); UNPROTECT(1); } UNPROTECT(1); return(result); } SEXP RN_SetNodeStateComments(SEXP nd, SEXP newvals) { R_len_t n, nn; const char *value; node_bn* node_handle; node_handle = GetNodeHandle(nd); if (!node_handle) { error("Could not find node %s.",NODE_NAME(nd)); return (R_NilValue); } else { //Count number of fields. nn = GetNodeNumberStates_bn(node_handle); for (n=0; n < nn; n++) { value = CHAR(STRING_ELT(newvals,n)); SetNodeStateComment_bn(node_handle, n, value); } } return(nd); } //R code switches between continuous and discrete versions. SEXP RN_GetNodeLevelsDiscrete(SEXP nd) { R_len_t n, nn; const char *statename; node_bn* node_handle; const level_bn* levels; SEXP result, statenames; node_handle = GetNodeHandle(nd); if (!node_handle) { error("Could not find node %s.",NODE_NAME(nd)); PROTECT(result=ScalarReal(R_NaReal)); } else { //Count number of fields. nn = GetNodeNumberStates_bn(node_handle); PROTECT(result = allocVector(REALSXP,nn)); PROTECT(statenames = allocVector(STRSXP,nn)); levels = GetNodeLevels_bn(node_handle); for (n=0; n < nn; n++) { statename = GetNodeStateName_bn(node_handle, n); SET_STRING_ELT(statenames,n,mkChar(statename)); if (levels == NULL) { REAL(result)[n] = R_NaReal; } else { REAL(result)[n] = RN_NnumToRnum(levels[n]); } } namesgets(result,statenames); UNPROTECT(1); } UNPROTECT(1); return(result); } //Switching between discrete and continuous is done at R level. SEXP RN_GetNodeLevelsContinuous(SEXP nd) { node_bn* node_handle; const level_bn* levels; SEXP result; R_len_t n, nn; node_handle = GetNodeHandle(nd); if (!node_handle) { error("Could not find node %s.",NODE_NAME(nd)); PROTECT(result=ScalarReal(R_NaReal)); } else { //Count number of fields. levels = GetNodeLevels_bn(node_handle); if (levels == NULL) { nn = 0; } else { nn = GetNodeNumberStates_bn(node_handle)+1; } PROTECT(result = allocVector(REALSXP,nn)); for (n=0; n < nn; n++) { REAL(result)[n] = RN_NnumToRnum(levels[n]); } } UNPROTECT(1); return(result); } //Different error checking, but setting routine is similar. SEXP RN_SetNodeLevels(SEXP nd, SEXP newvals) { R_len_t n, nn = length(newvals); node_bn* node_handle; level_bn* levels; node_handle = GetNodeHandle(nd); if (!node_handle) { error("Could not find node %s.",NODE_NAME(nd)); } else { //Count number of fields. if (nn == 0 ) { levels = NULL; } else { levels = (level_bn *) R_alloc(nn,sizeof(level_bn)); for (n=0; n < nn; n++) { levels[n] = RN_RnumToNnum(REAL(newvals)[n]); } } //Continuous have number of states equal to length(newvals)-1 if (GetNodeType_bn(node_handle) == CONTINUOUS_TYPE && nn > 0) nn--; SetNodeLevels_bn(node_handle, nn, levels); } return(nd); } ////////////////////////////////////////////////////////////////// // Node Sets SEXP RN_ParseNodeSetString(net_bn *nt, bool_ns incSystem) { const char*rawsets=GetAllNodesets_bn(nt,incSystem,NULL); if (rawsets==NULL || strlen(rawsets)==0) { // Trap for zero length return (allocVector(STRSXP,0)); } char *sets = R_alloc(strlen(rawsets),sizeof(char)); sets = strcpy(sets,rawsets); SEXP result; int i, nsets = 1; for (i=0; i