void dijkstra1( long int n, long int s, double *D1, double *P1, double *Gpr, mwIndex *Gir, mwIndex *Gjc) { int finished; long int i, startInd, endInd, whichNeigh, nDone, closest; double closestD, arcLength, INF, SMALL, oldDist; HeapNode *A, *hnMin, hnTmp; FibHeap *heap; INF=mxGetInf(); SMALL=mxGetEps(); // setup heap if ((heap = new FibHeap) == NULL || (A = new HeapNode[n+1]) == NULL ) mexErrMsgTxt( "Memory allocation failed-- ABORTING.\n" ); heap->ClearHeapOwnership(); // initialize for (i=0; i<n; i++) { if (i!=s) A[ i ] = (double) INF; else A[ i ] = (double) SMALL; if (i!=s) D1[ i ] = (double) INF; else D1[ i ] = (double) SMALL; P1[ i ] = -1; heap->Insert( &A[i] ); A[ i ].SetIndexValue( (long int) i ); } // Insert 0 then extract it, which will balance heap heap->Insert(&hnTmp); heap->ExtractMin(); // loop over nonreached nodes finished = nDone = 0; while ((finished==0) && (nDone < n)) { hnMin = (HeapNode *) heap->ExtractMin(); closest = hnMin->GetIndexValue(); closestD = hnMin->GetKeyValue(); if ((closest<0) || (closest>=n)) mexErrMsgTxt( "Minimum Index out of bound..." ); D1[ closest ] = closestD; if (closestD == INF) finished=1; else { // relax all nodes adjacent to closest nDone++; startInd = Gjc[ closest ]; endInd = Gjc[ closest+1 ] - 1; if( startInd!=endInd+1 ) for( i=startInd; i<=endInd; i++ ) { whichNeigh = Gir[ i ]; arcLength = Gpr[ i ]; oldDist = D1[ whichNeigh ]; if ( oldDist > ( closestD + arcLength )) { D1[ whichNeigh ] = closestD + arcLength; // c++ index P1[ whichNeigh ] = closest; hnTmp = A[ whichNeigh ]; hnTmp.SetKeyValue( closestD + arcLength ); heap->DecreaseKey( &A[ whichNeigh ], hnTmp ); } } } } // cleanup delete heap; delete[] A; }
void test_sequential_random_Insert_DeleteMin(){ FibHeap fib; priority_queue<int> ref_q; int NUM_NODES = 100000; for (int i = 0; i < NUM_NODES; i++){ int curr = rand(); fib.insertNode(curr); ref_q.push(-curr); } for (int i = 0; i < NUM_NODES; i++){ int val= fib.deleteMin(); int ref = -ref_q.top(); ref_q.pop(); if (val != ref){ cout << "\n Our value: " << val << " Ref Value: " << ref; return; } } cout << "\n Sequential Insert then Delete Succeeded"; for (int i = 0; i < NUM_NODES; i++){ int curr = rand(); fib.insertNode(curr); ref_q.push(-curr); if (i%50 == 0){ int num_deletes = rand() % fib.getSize()+1; for (int j = 0; j < num_deletes; j++){ int val= fib.deleteMin(); int ref = -ref_q.top(); ref_q.pop(); if (val != ref){ cout << "\n Random : Our value: " << val << " Ref Value: " << ref; return; } } } } cout << "\n Random Insert and Delete Succeeded"; }
/* * Adaptive Randomized Sampling Algorithm for Weighted graphs. The cut-off on the number of samples is n/20. */ void Adaptive_Sampling_Weighted(f64 ACB[], NETWORK *network, f64 c_thr, f64 sup, f64 &time_dif) { ui64 i, j, u, v, numSample, randvx; ui64 nvertices = (ui64) network->nvertices; // The number of vertices in the network ui64 count = 0; f64 u_distance, v_distance, edgeWeight; // Variables to store distance estimates or edge weights time_t start, end; // Time variables vector<ui64> sigma; // sigma is the number of shortest paths vector<f64> delta; // A vector storing dependency of the source vertex on all other vertices vector< vector <ui64> > PredList; // A list of predecessors of all vertices vector<ui64> SampleVertex; vector<ui64>::iterator it; // An iterator of vector elements vector<bool> Flag; stack <ui64> S; // A stack containing vertices in the order found by Dijkstra's Algorithm FibHeap PQueue; // A priority queue storing vertices FibHeapNode nodeTemp; // A particular node stored in the priority queue FibHeapNode *nodePtr; // Pointer to a vertex element stored in the priority queue vector<FibHeapNode *> nodeVector; // A vector of all priority queue elements // Set the start time of Randomized Brandes' Algorithm time(&start); nodeVector.assign ( nvertices, NULL ); for (i=0; i < nvertices; i++) { nodeVector[i] = new FibHeapNode(); nodeVector[i]->Set_vertexPosition(i); //Set all Nodes distance to unsigned long max ULONG_MAX that is assumed to be infinity nodeVector[i]->Set_key(ULONG_MAX); } // Generate random seed srand((unsigned)time(NULL)); numSample = (ui64) (nvertices/sup); if (numSample < 1) numSample = nvertices; SampleVertex.resize(numSample); Flag.assign(nvertices, false); for (i=0; i < numSample; i++) { // Generate a random vertex randvx = (ui64) ((((f64) rand())/((f64) RAND_MAX + 1.0))*nvertices); // Insert the randomly sampled vertex SampleVertex.push_back(randvx); } // Compute Randomized Betweenness Centrality using sampled vertices for (it= SampleVertex.begin(); it < SampleVertex.end(); it++) { count += 1; i = *it; /* Initialize */ PredList.assign(nvertices, vector <ui64> (0, 0)); sigma.assign(nvertices, 0); sigma[i] = 1; delta.assign(nvertices, 0); nodeVector[i]->Set_key(0); PQueue.Insert(nodeVector[i]); // While the priority queue is nonempty while (PQueue.GetNumNodes() != 0) { // Get the element in the priority queue with the minimum key nodePtr = PQueue.ExtractMin(); // Get the vertex corresponding to the queue element with the minimum key u = nodePtr->Get_vertexPosition(); // Push u onto the stack S. Needed later for betweenness computation S.push(u); // Shortest path distance from source i to vertex u u_distance = nodeVector[u]->Get_key(); // Iterate over all the neighbors of u for (j=0; j < (ui64) network->vertex[u].degree; j++) { // Get the neighbor v of vertex u v = (ui64) network->vertex[u].edge[j].target; // Get the weight of the edge (u,v) edgeWeight = (f64) network->vertex[u].edge[j].weight; // If v's shortest path distance estimate has not been set yet, then // set the distance estimate of v and store v in the priority queue if (nodeVector[v]->Get_key() == ULONG_MAX) { nodeVector[v]->Set_key(u_distance + edgeWeight); PQueue.Insert(nodeVector[v]); } // Get the current shortest path distance estimate of v v_distance = nodeVector[v]->Get_key(); /* Relax and Count */ if (v_distance == u_distance + edgeWeight) { sigma[v] += sigma[u]; PredList[v].push_back(u); } if (v_distance > u_distance + edgeWeight) { sigma[v] = sigma[u]; PredList[v].clear(); PredList[v].push_back(u); nodeTemp.Set_vertexPosition(v); nodeTemp.Set_key(u_distance + edgeWeight); if (PQueue.DecreaseKey(nodeVector[v], nodeTemp) != 0) cout << "Error decreasing the node key" << endl; } } // End For } // End While /* Accumulation */ while (!S.empty()) { u = S.top(); S.pop(); for (j=0; j < PredList[u].size(); j++) { delta[PredList[u][j]] += ((f64) sigma[PredList[u][j]]/sigma[u]) * (1+delta[u]); } if ((u != i) && (!Flag[u])) { ACB[u] += delta[u]; if (ACB[u] > c_thr * nvertices) { ACB[u] = nvertices * (ACB[u]/count); Flag[u] = true; } } // End If } // End While // Clear data for the next run PredList.clear(); sigma.clear(); delta.clear(); for (j=0; j < nvertices; j++) nodeVector[j]->Set_key(ULONG_MAX); } // End For for (i=0; i < nvertices; i++) { if (!Flag[i]) { ACB[i] = nvertices * (ACB[i]/numSample); } } // End time after Brandes' algorithm and the time difference time(&end); time_dif = difftime(end, start); cout << "It took " << time_dif << " seconds to calculate Adaptive Sampling Based Approximate Centrality Values in a weighted graph" << endl; // Deallocate memory for (i=0; i < nvertices; i++) delete nodeVector[i]; return; } // End of Adaptive_Sampling_Weighted
/* * Brandes Algorithm for weighted graphs */ void BrandesAlgorithm_Weighted(f64 CB[], NETWORK *network, f64 &time_dif) { ui64 i, j, u, v; ui64 nvertices = (ui64) network->nvertices; // The number of vertices in the network f64 u_distance, v_distance, edgeWeight; // Variables to store distance estimates or edge weights time_t start, end; // Time variables vector<ui64> sigma; // sigma is the number of shortest paths vector<f64> delta; // A vector storing dependency of the source vertex on all other vertices vector< vector <ui64> > PredList; // A list of predecessors of all vertices stack <ui64> S; // A stack containing vertices in the order found by Dijkstra's Algorithm FibHeap PQueue; // A priority queue storing vertices FibHeapNode nodeTemp; // A particular node stored in the priority queue FibHeapNode *nodePtr; // Pointer to a vertex element stored in the priority queue vector<FibHeapNode *> nodeVector; // A vector of all priority queue elements // Set the start time of Brandes' Algorithm time(&start); nodeVector.assign ( nvertices, NULL ); for (i=0; i < nvertices; i++) { nodeVector[i] = new FibHeapNode(); nodeVector[i]->Set_vertexPosition(i); //Set all Nodes distance to unsigned long max ULONG_MAX that is assumed to be infinity nodeVector[i]->Set_key(ULONG_MAX); } // Compute Betweenness Centrality for every vertex i for (i=0; i < nvertices; i++) { /* Initialize */ PredList.assign(nvertices, vector <ui64> (0, 0)); sigma.assign(nvertices, 0); sigma[i] = 1; delta.assign(nvertices, 0); nodeVector[i]->Set_key(0); PQueue.Insert(nodeVector[i]); // While the priority queue is nonempty while (PQueue.GetNumNodes() != 0) { // Get the element in the priority queue with the minimum key nodePtr = PQueue.ExtractMin(); // Get the vertex corresponding to the queue element with the minimum key u = nodePtr->Get_vertexPosition(); // Push u onto the stack S. Needed later for betweenness computation S.push(u); // Shortest path distance from source i to vertex u u_distance = nodeVector[u]->Get_key(); // Iterate over all the neighbors of u for (j=0; j < (ui64) network->vertex[u].degree; j++) { // Get the neighbor v of vertex u v = (ui64) network->vertex[u].edge[j].target; // Get the weight of the edge (u,v) edgeWeight = (f64) network->vertex[u].edge[j].weight; // If v's shortest path distance estimate has not been set yet, then // set the distance estimate of v and store v in the priority queue if (nodeVector[v]->Get_key() == ULONG_MAX) { nodeVector[v]->Set_key(u_distance + edgeWeight); PQueue.Insert(nodeVector[v]); } // Get the current shortest path distance estimate of v v_distance = nodeVector[v]->Get_key(); /* Relax and Count */ if (v_distance == u_distance + edgeWeight) { sigma[v] += sigma[u]; PredList[v].push_back(u); } if (v_distance > u_distance + edgeWeight) { sigma[v] = sigma[u]; PredList[v].clear(); PredList[v].push_back(u); nodeTemp.Set_vertexPosition(v); nodeTemp.Set_key(u_distance + edgeWeight); if (PQueue.DecreaseKey(nodeVector[v], nodeTemp) != 0) cout << "Error decreasing the node key" << endl; } } // End For } // End While /* Accumulation */ while (!S.empty()) { u = S.top(); S.pop(); for (j=0; j < PredList[u].size(); j++) { delta[PredList[u][j]] += ((f64) sigma[PredList[u][j]]/sigma[u]) * (1+delta[u]); } if (u != i) CB[u] += delta[u]; } // Clear data for the next run PredList.clear(); sigma.clear(); delta.clear(); for (j=0; j < nvertices; j++) nodeVector[j]->Set_key(ULONG_MAX); } // End For // End time after Brandes' algorithm and the time difference time(&end); time_dif = difftime(end, start); cout << "It took " << time_dif << " seconds to calculate Betweenness Centrality in an weighted graph" << endl; // Deallocate memory for (i=0; i < nvertices; i++) delete nodeVector[i]; return; } // End of BrandesAlgorithm_Weighted
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) { double *sr,*D,*P,*SS,*Dsmall,*Psmall; int *irs,*jcs; long int M,N,S,MS,NS,i,j,in; HeapNode *A = NULL; FibHeap *theHeap = NULL; if (nrhs != 2) { mexErrMsgTxt( "Only 2 input arguments allowed." ); } else if (nlhs != 1) { mexErrMsgTxt( "Only 1 output argument allowed." ); } M = mxGetM( prhs[0] ); N = mxGetN( prhs[0] ); if (M != N) mexErrMsgTxt( "Input matrix needs to be square." ); SS = mxGetPr(prhs[1]); MS = mxGetM( prhs[1] ); NS = mxGetN( prhs[1] ); if ((MS==0) || (NS==0) || ((MS>1) && (NS>1))) mexErrMsgTxt( "Source nodes are specified in one dimensional matrix only" ); if (NS>MS) MS=NS; plhs[0] = mxCreateDoubleMatrix( MS,M, mxREAL); D = mxGetPr(plhs[0]); Dsmall = (double *) mxCalloc( M , sizeof( double )); if (mxIsSparse( prhs[ 0 ] ) == 1) { /* dealing with sparse array */ sr = mxGetPr(prhs[0]); irs = mxGetIr(prhs[0]); jcs = mxGetJc(prhs[0]); // Setup for the Fibonacci heap for (i=0; i<MS; i++) { if ((theHeap = new FibHeap) == NULL || (A = new HeapNode[M+1]) == NULL ) { mexErrMsgTxt( "Memory allocation failed-- ABORTING.\n" ); } theHeap->ClearHeapOwnership(); S = (long int) *( SS + i ); S--; if ((S < 0) || (S > M-1)) mexErrMsgTxt( "Source node(s) out of bound" ); /* ------------------------------------------------------------------------------------------------- run the dijkstra code ------------------------------------------------------------------------------------------------- */ //mexPrintf( "Working on i=%d\n" , i ); dodijk_sparse( M,N,S,Dsmall,sr,irs,jcs,A,theHeap ); for (j=0; j<M; j++) { *( D + j*MS + i ) = *( Dsmall + j ); //mexPrintf( "Distance i=%d to j=%d =%f\n" , S+1 , j , *( Dsmall + j ) ); } /* ------------------------------------------------------------------------------------------------- end of the dijkstra code ------------------------------------------------------------------------------------------------- */ delete theHeap; delete[] A; } } else mexErrMsgTxt( "Function not implemented for full arrays" ); }
//============================================================================================ // Dijkstra::_run // // Input: // fromId: The id of the starting city. // toId: The id of the ending city // cities: A vector of City objectrs representing all the cities in the graph. // forward: A boolean value indicating whether or not the algorithm should be run by following // edges leading to a Node or edges leading away from that Node. // // Output: // A DijkstraResult object. // // Run Dijkstra's Algorithm from the City identified by the fromId parameter to the city identified by the // toId parameter. //============================================================================================ DijkstraResult *Dijkstra::_run(unsigned long fromId, unsigned long toId, std::map<unsigned long, City *> cities, bool forward){ std::map<unsigned long, City*> previous; std::map<unsigned long, Node*> cityNodes; std::map<unsigned long, unsigned long> distances; FibHeap* heap = new FibHeap(); Node *temp; for(auto it = cities.begin(); it != cities.end(); it++){ it->second->visited = false; if (it->second->key == fromId) { it->second->distance = 0; } else{ it->second->distance = ULONG_MAX; } temp = new Node(it->second); FibHeap::insert(temp, heap); cityNodes[it->second->key] = temp; } City *minCity, *neighbor; Road *road; std::vector<Road *> roads; while(heap->min != nullptr) { minCity = heap->deleteMin(heap); if(forward){ roads = minCity->fromRoads; } else{ roads = minCity->toRoads; } for (auto it = roads.begin(); it != roads.end(); it++) { road = *it; if(forward){ neighbor = cities[road->to]; }else{ neighbor = cities[road->from]; } if (neighbor->visited == false) { unsigned long altDistance = minCity->distance + road->length; if (altDistance < neighbor->distance) { if(minCity->distance != ULONG_MAX){ unsigned long sub = neighbor->distance - altDistance; previous[neighbor->key] = minCity; distances[neighbor->key] = altDistance; FibHeap::decreaseKey(sub, cityNodes[neighbor->key], heap); } } } } minCity->visited = true; } distances[toId] = cities[toId]->distance; return new DijkstraResult(previous, distances); }
void test_decrease_key(){ FibHeap fib; int NUM_NODES = 100; boost_heap pq; map<int, boost_heap::handle_type> index; vector<int> keys; set<int> keyset; // Used for getting logarithmic random generation and duplicate detection for (int i = 0; i < NUM_NODES; i++){ unsigned int curr = rand(); if (present(keyset, curr)) continue; fib.insertNode(curr); index[curr]=pq.push(curr); keys.push_back(curr); keyset.insert(curr); if (i % 25 == 0){ //Do some random decrease keys for (int j = 0; j < 20; j++){ //Pick a key to change unsigned int to_change_index = rand() % keys.size(); unsigned int to_change_val = keys[to_change_index]; if (to_change_val == 0) continue; //Find a smaller value to change to which doesnt already exist // Or try for a bit unsigned int new_val = rand() % to_change_val; for (int k = 0; k < 100; k++){ if (present(keyset, new_val)) new_val = rand() % to_change_val; else break; } if (present(keyset,new_val)) continue; //replace the old value with new one keys[to_change_index] = new_val; keyset.erase(to_change_val); keyset.insert(new_val); //perform operation on heaps pq.decrease(index[to_change_val],new_val); index[new_val] = index[to_change_val]; index.erase(to_change_val); fib.decreaseKey(to_change_val, new_val); } } if (i%50 == 0){ int num_deletes = rand() % fib.getSize()+1; for (int j = 0; j < num_deletes; j++){ unsigned int val= fib.deleteMin(); unsigned int ref = pq.top(); pq.pop(); if (val != ref){ cout << "\n Random : Our value: " << val << " Ref Value: " << ref; return; } keyset.erase(val); std::vector<int>::iterator position = std::find(keys.begin(), keys.end(), val); if (position != keys.end()) // == vector.end() means the element was not found keys.erase(position); else cout << "Should never get here, keys messed up"; index.erase(val); } } } cout <<"Test completed"; }