/* LIBDGL -- a Directed Graph Library implementation * Copyright (C) 2002 Roberto Micarelli * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * best view with tabstop=4 */ /* * Add edge can be performed on TREE state graph. If the state is FLAT * return BadOnFlatGraph error. */ int DGL_ADD_EDGE_FUNC ( dglGraph_s * pgraph , dglInt32_t nHead, dglInt32_t nTail, dglInt32_t nCost, dglInt32_t nEdge, void * pvHeadAttr , void * pvTailAttr , void * pvEdgeAttr , dglInt32_t nFlags ) { dglInt32_t * pHead; dglInt32_t * pTail; dglInt32_t * pEdgeset; dglInt32_t * pEdge; DGL_T_NODEITEM_TYPE * pHeadNodeItem; DGL_T_NODEITEM_TYPE * pTailNodeItem; #if defined(_DGL_V2) dglInt32_t * pinEdgeset; dglTreeEdge_s * pEdgeItem; dglTreeEdge_s findEdge; #endif if ( pgraph->Flags & DGL_GS_FLAT ) { pgraph->iErrno = DGL_ERR_BadOnFlatGraph; return -pgraph->iErrno; } #ifdef DGL_STATS { clock_t clk = clock(); #endif if ( (pHeadNodeItem = DGL_T_NODEITEM_Add( pgraph->pNodeTree , nHead )) == NULL || (pTailNodeItem = DGL_T_NODEITEM_Add( pgraph->pNodeTree , nTail )) == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } #ifdef DGL_STATS pgraph->clkNodeTree += clock() - clk; pgraph->cNodeTree ++; pgraph->cNodeTree ++; } #endif if ( DGL_T_NODEITEM_NodePTR(pHeadNodeItem) == NULL ) { if ( (pHead = DGL_NODE_ALLOC( pgraph->NodeAttrSize )) == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -1; } DGL_NODE_STATUS(pHead) = 0; DGL_T_NODEITEM_Set_NodePTR(pHeadNodeItem,pHead); pgraph->cNode ++; pgraph->cHead ++; } else { pHead = DGL_T_NODEITEM_NodePTR(pHeadNodeItem); if ( !(DGL_NODE_STATUS(pHead) & DGL_NS_HEAD) ) pgraph->cHead++; } if ( DGL_T_NODEITEM_NodePTR(pTailNodeItem) == NULL ) { if ( (pTail = DGL_NODE_ALLOC( pgraph->NodeAttrSize )) == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } DGL_NODE_STATUS(pTail) = 0; DGL_T_NODEITEM_Set_NodePTR(pTailNodeItem,pTail); pgraph->cNode ++; pgraph->cTail ++; } else { pTail = DGL_T_NODEITEM_NodePTR(pTailNodeItem); if ( !(DGL_NODE_STATUS(pTail) & DGL_NS_TAIL) ) pgraph->cTail++; } DGL_NODE_STATUS(pHead) |= DGL_NS_HEAD; DGL_NODE_STATUS(pTail) |= DGL_NS_TAIL; if ( DGL_NODE_STATUS(pHead) & DGL_NS_ALONE ) { DGL_NODE_STATUS(pHead) &= ~DGL_NS_ALONE; pgraph->cAlone --; } if ( DGL_NODE_STATUS(pTail ) & DGL_NS_ALONE ) { DGL_NODE_STATUS(pTail ) &= ~DGL_NS_ALONE; pgraph->cAlone --; } DGL_NODE_ID(pHead) = nHead; DGL_NODE_ID(pTail) = nTail; DGL_NODE_EDGESET_OFFSET(pHead) = -1; DGL_NODE_EDGESET_OFFSET(pTail) = -1; if ( pvHeadAttr && pgraph->NodeAttrSize ) { memcpy( DGL_NODE_ATTR_PTR(pHead), pvHeadAttr, pgraph->NodeAttrSize ); } if ( pvTailAttr && pgraph->NodeAttrSize ) { memcpy( DGL_NODE_ATTR_PTR(pTail), pvTailAttr, pgraph->NodeAttrSize ); } /* if ( DGL_T_NODEITEM_OutEdgesetPTR(pTailNodeItem) == NULL ) { pEdgeset = DGL_EDGESET_ALLOC( 0 , pgraph->EdgeAttrSize ); if ( pEdgeset == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } DGL_EDGESET_EDGECOUNT(pEdgeset) = 0; DGL_T_NODEITEM_Set_OutEdgesetPTR(pTailNodeItem,pEdgeset); } */ if ( (pEdgeset=DGL_T_NODEITEM_OutEdgesetPTR(pHeadNodeItem)) == NULL ) { pEdgeset = DGL_EDGESET_ALLOC( 1 , pgraph->EdgeAttrSize ); if ( pEdgeset == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } DGL_EDGESET_EDGECOUNT(pEdgeset) = 0; DGL_T_NODEITEM_Set_OutEdgesetPTR(pHeadNodeItem,pEdgeset); } else { pEdgeset = DGL_EDGESET_REALLOC( pEdgeset , DGL_EDGESET_EDGECOUNT(pEdgeset) + 1 , pgraph->EdgeAttrSize ); if ( pEdgeset == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } DGL_T_NODEITEM_Set_OutEdgesetPTR(pHeadNodeItem,pEdgeset); } #if defined(_DGL_V2) /* if ( DGL_T_NODEITEM_InEdgesetPTR(pHeadNodeItem) == NULL ) { pinEdgeset = DGL_EDGESET_ALLOC( 0 , pgraph->EdgeAttrSize ); if ( pinEdgeset == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } DGL_EDGESET_EDGECOUNT(pinEdgeset) = 0; DGL_T_NODEITEM_Set_InEdgesetPTR(pHeadNodeItem,pinEdgeset); } */ if ( (pinEdgeset=DGL_T_NODEITEM_InEdgesetPTR(pTailNodeItem)) == NULL ) { pinEdgeset = DGL_EDGESET_ALLOC( 1 , pgraph->EdgeAttrSize ); if ( pinEdgeset == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } DGL_EDGESET_EDGECOUNT(pinEdgeset) = 0; DGL_T_NODEITEM_Set_InEdgesetPTR(pTailNodeItem,pinEdgeset); } else { pinEdgeset = DGL_EDGESET_REALLOC( pinEdgeset , DGL_EDGESET_EDGECOUNT(pinEdgeset) + 1 , pgraph->EdgeAttrSize ); if ( pinEdgeset == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } DGL_T_NODEITEM_Set_InEdgesetPTR(pTailNodeItem,pinEdgeset); } /* * Set the edge-tree */ findEdge.nKey = nEdge; if ( (pEdgeItem = dglTreeEdgeAdd(pgraph->pEdgeTree, nEdge)) == NULL) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } if ( pEdgeItem->pv ) { pgraph->iErrno = DGL_ERR_EdgeAlreadyExist; return -pgraph->iErrno; } if ( (pEdgeItem->pv = DGL_EDGE_ALLOC(pgraph->EdgeAttrSize)) == NULL ) { pgraph->iErrno = DGL_ERR_MemoryExhausted; return -pgraph->iErrno; } /* * assign edge id */ pEdgeset[DGL_EDGESET_EDGECOUNT(pEdgeset)+1] = nEdge; pinEdgeset[DGL_EDGESET_EDGECOUNT(pinEdgeset)+1] = nEdge; ++DGL_EDGESET_EDGECOUNT(pEdgeset); ++DGL_EDGESET_EDGECOUNT(pinEdgeset); /* printf( "add edge: node %ld(%ld,%ld) -> %ld(%ld,%ld)\n", DGL_NODE_ID(pHead), DGL_EDGESET_EDGECOUNT(pEdgeset),0, DGL_NODE_ID(pTail), 0,DGL_EDGESET_EDGECOUNT(pinEdgeset)); */ pEdge = pEdgeItem->pv; #endif #if defined(_DGL_V1) pEdge = DGL_EDGESET_EDGE_PTR(pEdgeset, DGL_EDGESET_EDGECOUNT(pEdgeset), pgraph->EdgeAttrSize); DGL_EDGESET_EDGECOUNT(pEdgeset) ++; #endif DGL_EDGE_HEADNODE_OFFSET(pEdge) = nHead; /* will be an offset after flattening */ DGL_EDGE_TAILNODE_OFFSET(pEdge) = nTail; /* will be an offset after flattening */ DGL_EDGE_COST(pEdge) = nCost; DGL_EDGE_ID(pEdge) = nEdge; #if !defined(_DGL_V1) if (nFlags & DGL_ES_DIRECTED) DGL_EDGE_STATUS(pEdge) = DGL_ES_DIRECTED; else DGL_EDGE_STATUS(pEdge) = 0; #endif pgraph->cEdge ++; pgraph->nnCost += (dglInt64_t)nCost; if ( pvEdgeAttr && pgraph->EdgeAttrSize ) { memcpy( DGL_EDGE_ATTR_PTR(pEdge), pvEdgeAttr, pgraph->EdgeAttrSize ); } /* * If requested add a cost-weighted entry into the edge prioritizer */ #if !defined(_DGL_V1) if ( pgraph->nOptions & DGL_GO_EdgePrioritize_COST ) { if (dgl_edge_prioritizer_add(pgraph,DGL_EDGE_ID(pEdge), DGL_EDGE_COST(pEdge)) < 0) { return -pgraph->iErrno; } } #endif if ( nFlags & DGL_STRONGCONNECT ) { return DGL_ADD_EDGE_FUNC(pgraph,nTail,nHead,nCost,nEdge,pvHeadAttr,pvTailAttr,pvEdgeAttr,nFlags & ~DGL_STRONGCONNECT); } return 0; } int DGL_DEL_EDGE_FUNC( dglGraph_s * pgraph, dglInt32_t nEdge ) { #if defined(_DGL_V1) pgraph->iErrno = DGL_ERR_NotSupported; return -pgraph->iErrno; #else dglTreeEdge_s * pEdgeItem , findEdgeItem; dglInt32_t * pEdge; if ( pgraph->Flags & DGL_GS_FLAT ) { pgraph->iErrno = DGL_ERR_BadOnFlatGraph; return -pgraph->iErrno; } if ( pgraph->pEdgeTree == NULL ) { pgraph->iErrno = DGL_ERR_UnexpectedNullPointer; return -pgraph->iErrno; } findEdgeItem.nKey = nEdge; if ( (pEdgeItem = avl_find( pgraph->pEdgeTree, &findEdgeItem )) == NULL) { pgraph->iErrno = DGL_ERR_EdgeNotFound; return -pgraph->iErrno; } pEdge = pEdgeItem->pv; if ( DGL_DEL_NODE_INEDGE_FUNC(pgraph, DGL_EDGE_TAILNODE_OFFSET(pEdge), DGL_EDGE_ID(pEdge)) < 0 ) { return -pgraph->iErrno; } if ( DGL_DEL_NODE_OUTEDGE_FUNC(pgraph, DGL_EDGE_HEADNODE_OFFSET(pEdge), DGL_EDGE_ID(pEdge)) < 0 ) { return -pgraph->iErrno; } /* prioritizer sync */ if (pgraph->nOptions & DGL_GO_EdgePrioritize_COST) { if ( dgl_edge_prioritizer_del(pgraph,DGL_EDGE_ID(pEdge),DGL_EDGE_COST(pEdge)) < 0) { return -pgraph->iErrno; } } /* */ pgraph->cEdge--; pgraph->nnCost -= (dglInt64_t)DGL_EDGE_COST(pEdge); avl_delete(pgraph->pEdgeTree, pEdgeItem); dglTreeEdgeCancel(pEdgeItem,NULL); return 0; #endif } dglInt32_t * DGL_GET_EDGE_FUNC( dglGraph_s * pgraph , dglInt32_t nEdge ) { #if defined(_DGL_V1) pgraph->iErrno = DGL_ERR_NotSupported; return NULL; #else register dglInt32_t top; /* top of table */ register dglInt32_t pos; /* current position to compare */ register dglInt32_t bot; /* bottom of table */ register dglInt32_t * pref; register int cwords; /* size of a edge in words of 32 bit */ register dglTreeEdge_s * ptreeEdge; dglTreeEdge_s findEdge; dglInt32_t id; pgraph->iErrno = 0; if ( pgraph->Flags & DGL_GS_FLAT ) { cwords = DGL_EDGE_WSIZE(pgraph->EdgeAttrSize); /*bot = pgraph->iEdgeBuffer / DGL_EDGE_SIZEOF(pgraph->EdgeAttrSize);*/ bot = pgraph->cEdge; top = 0; pos = 0; pref = (dglInt32_t*)pgraph->pEdgeBuffer; /* perform a binary search */ while( top != bot ) { pos = top + (bot - top) / 2; id = DGL_EDGE_ID(& pref[pos * cwords]); if ( id == nEdge ) { break; } else if ( nEdge < id ) { bot = pos; } else if ( nEdge > id ) { top = pos + 1; } } if ( top == bot ) { return NULL; } return & pref[ pos * cwords ]; } else { findEdge.nKey = nEdge; ptreeEdge = avl_find( pgraph->pEdgeTree , &findEdge ); if ( ptreeEdge && ptreeEdge->pv ) { return ptreeEdge->pv; } return NULL; } #endif }